1) Professional Embedded ARM Development, by Langbridge [1]
This one is more about ARM instructions than about bootloaders or embedded OSes, but it does cover bootloaders in detail with case studies of some relatively unknown embedded boards, of the well-known Raspberry Pi, and of modern bootloader software like u-boot.
2) Building Embedded Systems, by Gu [2]
This book is broader than the one above, covering all kinds of embedded systems. It's the better book to understand the big picture, and understand how all the components (bootloader, OS, SoC, hardware buses, storage) interact. It does cover bootloaders but not in depth and not with case studies.
[1]: https://www.amazon.com/Professional-Embedded-Development-Jam...
[2]: https://www.amazon.com/Building-Embedded-Systems-Programmabl...
https://github.com/SoloKeysSec/solo/blob/master/targets/efm3...
https://github.com/SoloKeysSec/solo/blob/master/targets/efm3...
Like what others mention, it really depends on documentation from the vendor for the chipset you're working with. I mainly copied and pasted code from a form post by the vendor.
And of course link to the security key product :)
Some of the critical tasks I would like my bootloader to cover are... 1) Initialize critical parts of the processor (oscillators, clock branches, peripheral enables, etc..) 2) Initialize a few peripherals like UART to provide some useful "readable" output during this process
Some additional "would be nice" features I would like to do are... 1) Load an application from a SD card 2) Parse over the application executable for validity purposes
Your request #1 is on the mark: you want to cold-boot the chip and get the various necessary registers in place to accomplish #2, which is set up some of the peripherals to begin working.
So you have two choices:
1) Start reading the TRM and writing assembly code to do this, then read the TRM again and understand the boot sequence to figure out how and where to load the code.
or...
2) Read existing code to learn from someone else's work, because they did the exact same thing at some earlier point in time.
Loading an app from an SD card is likely harder than you think: it needs to be compiled/assembled correctly, you need to define where it starts, how it's linked, etc.
"Parse over the app executable for validity" is super-broad, and could mean just about anything. If you're trying to validate compiled programs, this will be difficult. If you're trying to validate byte-code programs (or something similar) it's significantly easier (or even unnecessary).
It'd probably be helpful if you were able to define specifically what you're trying to accomplish, and why an existing system doesn't meet your needs. While writing a trivial execution environment is really easy, writing a general-purpose OS is significantly more difficult.
You usually can have quite a bit of help by looking at the generated code from your compiler that sets up a simple 'main(...){ while(1); }' program. Often it'll be in your toolchain as a .S file or similar.