First instruction execution

Hello,
As an educational diversion, I'm trying to learn about linker scripts and how processors "know" what instruction to run first when they boot/get flashed. I read online that normal c/c++ programs include a reset vector that points to the first function or something. I also read that the cortex M-7 looks at the start of the CODE section, address 0x0.
I made a simple sketch and disassembled it, but it seems like the code starts at 0x60000000. This lines up with what the linker script says FLASH starts. I also noticed that inside the .text.code, .startup is first. I assume that this means any function slated to be in .startup would run first. The only three functions that are marked .startup are memory_copy, memory_clear, and ResetHandler.
Am I correct in stating that ResetHandler is the first function called on boot? It would make sense that code execution would start at the top of .text.code, but I couldn't find anything online saying that exactly.
Thanks,
Panda
 
The processor has a built-in ROM which is the very first code that gets executed on startup. It checks the built-in fuses and/or the current status of some of the GPIOs to decide how to attempt loading an executable image. In the case of the Teensy, the fuses are set to load from flash memory so that's what happens.
It doesn't start off running the image at address 0; the flash memory is mapped directly to 0x60000000 so it jumps into that range then copies itself into RAM.
 
Last edited:
The startup process is even more complicated. The boot ROM looks for a table of flash memory config at 0x60000000, and another IVT table at 0x60001000. The IVT has the address of a bootdata structure. That bootdata info gives it the address of the first executable instruction.

This boot stuff is all documented in the reference manual, which you can find on the Teensy 4.1 product page under "Technical Information" (scroll down to nearly the end). You might start reading at page 256 for relevant info, and try to ignore the extremely confusing Figure 9-14 on page 257.
 
It's technically possible to boot from any address rather than the ROM by changing the initial VTOR address in GPR16. But then you have to manually take care of all the startup stuff that the ROM usually does (and GPR16 will always revert to pointing at the ROM after initial power-up).
 
Ah that makes sense. I forgot to check the reference manual before asking my question.
The boot ROM looks for a table of flash memory config at 0x60000000, and another IVT table at 0x60001000. The IVT has the address of a bootdata structure.
This makes more sense as to why ResetHandler() has a starting address of 0x60001400 since the first main IVT starts at 0x60001000 and is 512 (0x400) bytes long.

The main thing that helped was me discovering bootdata.c and seeing the .text.headers layout of the linker script. That explains why ResetHandler starts at such a strange (no more) address.

Thank you so much, this has been quite fun to learn about!
 
Another small detail not really mentioned in most of the documentation is the minimum block size for BEE encryption. It's 1024 bytes. Before Lockable Teensy, we would start the code immediate after IVT and bootdata. But when encryption support was added, we had to move the actual code image to the next 1K boundary, which is why the executable image starts at 0x60001400. When the hex file is encrypted to ehex, the bootdata structure gets modified to point to a "startup shim" (placed in memory right after bootdata) which turns on BEE and then jumps to the actual start address which was in the original bootdata. So everything from 0x60000000 to 0x600013FF is accessed normally as plaintext and everything starting at 0x60001400 gets on-the-fly decrypted by BEE. Of course that's only on Lockable Teensy after your key has been written and it's able to run ehex. But we keep the same structure on standard Teensy (and Lockable Teensy when unlocked and programmed with regular hex), which is why there's a gap between IVT+bootdata and the actual code.
 
Is the unencrypted startup shim signed? If not, what stops someone overwriting it with their own code to dump the decrypted program?
 
Back
Top