Cortex M7: Branch just after start

1

I'm using the ATSAMV71Q21B MCU which uses a cortex-M7 processor. In order to add redundancy, I would like to have multiple boot loader and enter to one of those boot loader just after starting the microcontroller. Atlough, the ARM processor begins executing at the reset vector location 0x00000000. I cannot choose where I want to start.

I was wondering if it was possible to branch to one of my boot loaders using in few instructions.

For the moment, all solutions that I tried to generate hundred instructions which is too much for me. I guess that I need to manually add branch instructions the vector location 0x00000000. Although, I'm not sure where I should branch and if it is OK to do this.

Indeed, I'm not sure if I really understand the beginning of the assembly code generated. Therefore, I'm not sure where to branch.

Here is an example of the beginning of the program:

0x00400000  70 0a 40 20 d9 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 00 00 00 00  p.@ Ù.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.....
0x00400020  00 00 00 00 00 00 00 00 00 00 00 00 d5 01 40 00 d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00  ............Õ.@.Õ.@.....Õ.@.Õ.@.
0x00400040  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400060  d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.....Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400080  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x004000A0  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x004000C0  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x004000E0  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400100  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 00 00 00 00 00 00 00 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.........
0x00400120  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400140  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400160  d5 01 40 00 d5 01 40 00 10 b5 05 4c 23 78 33 b9 04 4b 13 b1 04 48 af f3 00 80 01 23 23 70 10 bd  Õ.@.Õ.@..µ.L#x3..K.±.H¯ó.€.##p..
0x00400180  2c 04 40 20 00 00 00 00 28 04 40 00 0c 4b 43 b1 0c 48 0d 49 10 b5 af f3 00 80 0c 48 03 68 23 b9  ,.@ ....(.@..KC±.H.I.µ¯ó.€.H.h#.
0x004001A0  10 bd 0a 48 03 68 33 b9 70 47 09 4b 00 2b f7 d0 bd e8 10 40 18 47 06 4b 00 2b f5 d0 18 47 00 bf  ...H.h3.pG.K.+÷Ð.è.@.G.K.+õÐ.G.¿
0x004001C0  00 00 00 00 28 04 40 00 30 04 40 20 28 04 40 00 00 00 00 00 fe e7 00 bf 16 49 17 4a 91 42 08 b5  ....(.@.0.@ (.@.....þç.¿.I.J‘B.µ

If I understand correctly, this is a vector table and I should not branch here. Is that correct ?

c
assembly
bootloader
cortex-m
asked on Stack Overflow Oct 13, 2020 by Antoine Boré

1 Answer

2
0x00400000  70 0a 40 20 d9 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 00 00 00 00  p.@ Ù.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.....
0x00400020  00 00 00 00 00 00 00 00 00 00 00 00 d5 01 40 00 d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00  ............Õ.@.Õ.@.....Õ.@.Õ.@.
0x00400040  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400060  d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.....Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400080  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.

So these look fine the first one is the stack pointer load value

0x20400a70 

A strange number perhaps but this part has 0x80000 bytes of ram so it is valid. so probably a linker script generated value (stack setup in the linker script rather than just start with top of ram).

Reset vector is

0x004001d9 

which is properly formatted (lsbit is set) as to what it points to you have not provided.

many of the others are

0x004001d5

Also properly formatted is probably an infinite loop based on its proximity to the reset vector but who knows have to look at the code. It does not matter much for booting.

The chip/family doc indicates that user flash is at address 0x00400000 and is quite large for these parts, so both the address on the left of this dump and the reset vectors this all looks fine.

There is an indication that there is a sam-ba bootloader at some address 0x00800000 or 0x08000000 or I do not remember, you can look it up. Now I have used other Atmel parts that did not have the bootloader burned in the flash from Atmel but instead source to a sam-ba you could build and use yourself (why bother make your own much simpler less bulky), but I had issues with that approach how the flash did or didn't lock, how easy to unlock and erase, so what is the point? use SWD. This comment in the doc may indicate a burned in one in that case then you need to look at how to choose to boot that application instead of the user application, in either case since they indicate a specific address. If it is user changeable then that would be where you want to put your bootloader possibly or if fixed and not changeable then just use it as your bootloader.

As to where in general you put your bootloader that is all you, you choose your design, what you mean by bootloader, what features etc. Often misused but the term implies both booting the part but also having a way to load other applications in some way (run one in ram, reprogram the user/boot/application flash, etc). Something you need to look at is how the flash works on this device assuming you want to be able to re-write a portion of it with new firmware. Sometimes you can execute out of and flash at the same time but more likely to do that they use multiple flash banks so you can run in one and modify the other, which then leads into what is their boot scheme does it always only boot on one and never the other so you either have to keep the bootloader as-is forever or have a scheme, also have to have a scheme for choosing which of the images on which banks to be the default firmware after the bootloader boots.

These cores can run code in ram generally and no reason to expect not here (it's not the core, it's the chip vendor's implementation that matters) so doing a copy and jump of a portion of the bootloader to ram in order to not be running on flash allowing you to reprogram any of the flash but put yourself at risk if it fails or if power goes the part may be bricked.

If the chip vendor has not already done this with a factory bootloader and that factory loader being desirable for field use, it may use an I/O pin to determine which one boots, have to look at the docs. If you choose to do this yourself it is not unwise to have a gpio pin pick two boot paths, you can then have a very small, ideally bug free dozen or so lines of assembly that read the gpio pin and branch to a fixed point in flash that you choose Say 0x00500000 and 0x00600000 for example depending on how big you think your applications really will be. Then you can do a copy and jump into ram if the user desires loading the flash and then you can choose to load one or the other. The handful of lines of code could be a few dozen and do a checksum of some sort of the selected bank and the not selected if the selected is bad and did not complete. or a third bootloader that you provide in case the two do not checksum.

Tons of solutions, generally if you do not have separately banked flashes you need to branch to ram and have more freedom as to how to design your memory space (assuming the flash can be erased in pages). Otherwise you might want to just go with the banking solution from the chip vendor.

So all of this is documented in documents from arm and Atmel (microchip) that you should have had before starting work on this device. The only thing remotely related to arm in any of this is how the vector table works. All of the rest, the addresses, sizes, etc are all chip vendor implementation. So most of your reading is in the chip vendors docs, in this case they have the huge datasheet approach (rather than separate data sheet and reference manual approach).

You need to re-read what I found about sam-ba if you want to use that if it works for you, the nature of the flash implementation, is it in application programmable, etc. And then you design not only the functionality of your bootloader but the address space, whether it executes in flash or ram.

Edit

In case I did not understand the question.

The arm reset vector is at 0x00000004 not 0x00000000 (for the cortex-ms) and it is the address of the handler ORRED with one. Address 0x00000000 is the stack pointer initialization value, if you choose to init the stack pointer in code and not using this mechanism you can put whatever you want there.

If you want to change the reset handler address then you have to modify 0x00000004 which on some parts you can change without an erase (often flashes either work by erasing to all ones then you can write zeros, can't write ones but can changes ones to zeros on a per byte/word/chunk basis). So to change this you likely need to save it erase the block/page, change the bits you want and write back. You might for example be able to change it from 0x004001d9 to sah 0x004101d9 or to 0x004000d9, but not worth trying to do that. The value is the address of the handler ORRED with one.

It is not a branch as code is not executing at this point (normally/assumed) it is the logic reading that location and using that as the starting point, the first fetch not branch.

And as pointed out look at where the vector table is in the project and then modify that to point at your alternate reset handler. It might be code that looks like this

.word STACK_END
.word reset_handler
.word 

in this case some fill/dummy vector for many of the rest. Just replace the reset_handler or whatever you find with your handler, remember this is a bootloader and you need to bootstrap C if you plan to call any C functions, worse if C++ or other language.

answered on Stack Overflow Oct 13, 2020 by old_timer • edited May 14, 2021 by halfer

User contributions licensed under CC BY-SA 3.0