Why do all ARM bootloaders have build code?

Writing in assembler reduces code size and runtime. But suppose I have enough memory and enough time. Can I use only C code and boot the device? I mean, with the power turned on, directly run the C code. I am particularly interested in ARM processors.

+4
source share
4 answers

In fact, you can create C-only firmware for ARM Cortex-M3 microcontrollers . Since its vector table contains an entry for the stack pointer, its value will be initialized by the processor, and you can use the compiled code directly from reset. You still need to configure peripherals and initialize the C library environment, but you don't need to do this in assembler. Cortex-M3 also automatically saves volatile registers to interrupt handler records, so they can also be written directly to C.

However, most compiler vendors still provide run in assembly language because it provides the most control.

+6
source

As mentioned, cortex-m3 is special and would allow such a thing, well with one exception, you still need some asm or some other magic to build a vector table to invoke C code.

In general, the answer is no, some assembly is required. The processors are common, they usually do not know what address space you created for the program and the data and the stack, and such registers, in particular the stack pointer, are often initialized with some known value, such as zero. Usually, as you know, the processor has a boot sequence, either there is an address from which it starts to execute, or an address where it finds an address to start execution. This address table, one for reset, one for interrupts, etc., is located there by the programmer of the loading code, although it is possible to control it in C, it’s not worth the effort, it’s much easier to write several asm lines to build this vector table. (this is the case for bark-m)

So, at least you need to set the stack pointer, and then go to the C write code, and from there you can probably get away with running C. Now, if this is a hand and is not -m bark, then you have several stacks to configure (if you want to use interrupts, handle errors, etc.), and you must use special asm instructions to do this, so asm is required, real or inline.

If you have a habit of using .data or expect the .bss value to be zero, something needs to be done, some code should be zero bss and prepare .data. Typically, your system (even your desktop / laptop) will boot from flash, if you have .data, that .data will need to be in flash, but you will need to read / write, so you will need to copy this data from the flash to his house in the ram, well, you need to start and run first (see below).

Not in the good old days, but, of course, today with a drama that you cannot turn on and start using memory, there is a lot of code necessary to get it working and working. Yes, this code is in C and probably not asm (although for performance reasons, asm can be used to use certain instructions that you may not do for the C compiler for you).

Thus, you have different scenarios in general, not necessarily related to weapons. I will list some, but not every nuance

1) you have a system that uses sram or an internal ram that does not need to be initialized, you are not using .data, and your code does not assume that .bss has been reset. The minimum in the general case was to initialize the stack pointer and branch to your C entry point (main or any other that you call).

2) you have a system that uses sram or an internal ram that does not need to be initialized, you use the .data that you expect there before the start of the C code (quite typical for C programmers) and .bss to be zero before the start of the C code (also typical, but fortunately gcc starts complaining about code that does this). Since your C code in this case expects these things to be prepared before running the C code, then resetting .bss and copying .data from flash to ram happens in asm. This is your most common scenario, look at many of the crt0.s routines for different processors, this is a common topic, set the stack pointer, zero bss, copy the .data branch to the main one.

3) you have a system with an internal sram that does not need to be initialized, but the main memory that you expect to use is drum. These are two steps, your first bootloader should still set the stack pointer, optionally zero .bss and copy the .data depending on your preferences, and then go to the entry point for the first bootloader. This bootloader will raise the drama system. This bootloader can now optionally copy .data and zero.bss (now it can be in C), and then go to the main boot point / bootloader function, which expects and uses large main memory.

4) you have an x86 processor with micro-coding, you need to fix the micro-code at boot, I do not have personal knowledge of this, but I assume that you have a limited number of instructions that you should use, since you are changing the micro-coding for some, or, maybe you will copy some ram, and then flip it slightly, and it will magically switch to patches, and you will do it with the changes, you don’t know, but I'm sure assembly is required.

Keep in mind that C contains several calls to the C library. So, C is an assembly, esp on hand. Do you avoid all divisions, multiplications, modules, floating point, etc.? you never use string functions or copy functions. Do you use C library calls at all? There is probably an asm that you use and don't know. memcpy is often manually configured in asm, esp on the hand. And if you use structures in your code, the compiler may / will be thrown into memcpys depending on how and how you use them. divide and modulo specifically asm. multiply sometimes. floating point, often asm, even if there is fpu. Of course, you did not record this asm yourself, but there is probably asm there, and your bootloader would not exist without this asm (if you use these libraries).

The title issue, which only implies assembly for the bootloader, is false, bootloaders are mostly not assemblies. Almost always, although assembly is required.

Cortex-m is a unique beast because it was designed so that you did not have to wrap interrupts with special instructions or asm (or the compiler does this for you). not typical. however, Corex-m has a large and huge table of vectors. I’m curious how you are going to build this table in C. I have some ideas on how to do this, but it is much simpler with asm, although asm is actually not asm, these are assembly directives (.word this_handler, .word that_handler).

A traditional ARM console with a 32-bit ARM7-like instruction, you should configure the stacks and branch to C-code in asm at least if you are not playing compiler games, exception handlers also want a little asm, just a few lines.

I need to think about the root of this issue. Loaders are very closely related to the processor and perhipherals, programmers who write loaders should be comfortable with hardware registers, etc. This implies some level of comfort with a set of instructions for this processor. Eliminating all asm in the bootloader is troubling. Even with Corex, just because you can go directly from the vector table to the C code, you still need to verify that the compiler you use complies with the hardware calling convention, and not just some general hand calling conventions, to ensure that a certain range of registers is saved, and the correct instruction is used when returning, which means disassembling and manually / visually checking the code generated by the compiler at this level, although only read, is on par with the asm record.

+4
source

I also do not know the exact answer. I just suggest some of the reasons I can think of (minus memory and efficiency):
- The code is very specific for the device, there is no need to compile and run elsewhere
- Access to special instructions (?)
- The state at bootloader startup differs from the usual program (?) (Stack, heap)

Disclaimer: This answer may contain incorrect information. Do not take anything serious here.

+1
source

The bootloader is responsible for initializing the device when it starts. At the moment, there is nothing but assembler. Part of the assembler is often kept as small as possible and is responsible for initializing the system, so that parts of the operating system and, for example, the minimum C-runtime can be loaded into memory and executed, and after that moment other initialization tasks can be performed using, for example, FROM.

Some links that may be helpful:

Wikipedia bootloader entry

U-boot design principles

Hope this will be helpful.

+1
source

Source: https://habr.com/ru/post/1414071/


All Articles