Replacing MBR with custom bootloader

Hi,

I'm developing a custom MBR/bootloader for NRF52811 which is used as a second/radio MCU on the board. The MCU will need to run applications with and without the softdevice, based on current usecase (ble and non-BLE protocols). The official uart bootloader takes way too much flash (25k + 8k of config space), even after removing crypto (still 15k+config), leaving us with only few kB of Flash for application logic.

So the current approach is to write a custom MBR which would contain a simple UART protocol to rewrite the flash, nothing fancy, just writing to flash and getting CRC of the data written, a data blob with app or app+softdevice would be written from 0x1000.

So, my question is how the official MBR actually works. Is it enough to change VTOR to 0x1000, jump to reset handler in vector table at that address and stop worrying (assuming the softdevice, if present, handles forwarding all interrupts to app)? Is there anything else, except the interrupt vectors redirection needed to support the softdevice?

Thank you

  • Hi,

    thank you very much for the answer, but I still don't understand few points:

    - when I run reset vector at 2), the MBR won't be executed again until reset, right? I assume the reset  vector shall not return - therefore I'll never by able to run 3) to  6)
    - at 4), how do I get the application start address? It depends on softdevice version...
    - 6) so I have to modify the application to do the heavylifting instead of MBR? I thought this was to be done by the MBR, not the application
    - is there a way to detect the binary at 0x1000 is a softdevice?

  • Hi,

    I've added vector forwarding to vector table at 0x20000000. The application seems to be launched correctly though the softdevice, but it always fails starting the softdevice (the sd_softdevice_enable call returns 0x20005fd4 which doesn't make much sense to me, as it's some address in ram, not the actual error code). I'm using S112 7.2.0

  • Ok, I guess I've managed to make it work with help of some MBR binary disassembly, the error mentioned in the previous post was caused in bug in my code around SVCall processing.

    So, the official MBR seems to be doing:

    - After boot, the MBR does some magic at UICR->NRFFW pointed address (with fallback to some hardcoded address), it seems it has something to do with the MBR configuration storage that to my understanding contains data for DFU (e.g. which section is to be written with DFU data,...), so I can ignore this as I don't intend to use the official bootloader
    - Once reading configuration is done, bootloader jumps to application/softdevice at 0x1000 + 0x4 (if not set to different address in the configuration above), before jumping 0x20000000 is written with the vector table address (0x1000)
    - All interrupts except Reset and SVCall are redirected to vector table the 0x20000000 points to.
    - The SVCall interrupt check the argument in svcall instruction, if it's equal to 0x18, it's a bootloader call, else it's passed to softdevice/app in the same way as the other interrupts.

    That seems to be everything the MBR does when not requested otherwise. Implementing similar behavior seems to work for me with BLE uart example (modified as loopback) and S112.

    However I still don't understand, why the VTOR change I used initially doesn't work, what my MBR implementation does now is redirecting all IRQs to addresses at 0x1000 (softdevice vector table). The 0x20000000 doesn't seem to be changing during app/softdevice runtime, so the behavior shall be identical...

  • Hi,

    kajus said:
    That seems to be everything the MBR does when not requested otherwise. Implementing similar behavior seems to work for me with BLE uart example (modified as loopback) and S112.

    That sounds correct, yes.

    To elaborate on the redirection of interrupts and SVCalls, similar redirects are done also from SoftDevice to application, for the interrupts not used by the SoftDevice. In theory, if you redirect anything to the SoftDevice which the SoftDevice doesn't use, then the SoftDevice will redirect that back to the app, and you end up looping infinitely.

    Hence if VTOR is set to the application start, you need to redirect interrupts for certain peripherals to the SoftDevice, but only when the SoftDevice is enabled. Also, you must only redirect interrupts for the peripherals actually used by the SoftDevice. Failing to map this correctly could lead to either the SoftDevice not getting interrupts, or interrupts getting endlessly redirected back and forth between app and SoftDevice.

    kajus said:
    However I still don't understand, why the VTOR change I used initially doesn't work, what my MBR implementation does now is redirecting all IRQs to addresses at 0x1000 (softdevice vector table). The 0x20000000 doesn't seem to be changing during app/softdevice runtime, so the behavior shall be identical...

    The first couple of words in RAM are used for vector table coordination between MBR and SoftDevice. Hence the need to set 0x20000000 to 0x1000.

    Regards,
    Terje

Related