After nearly two years of arm driver development, drivers of various commonly used devices have basically been touched. However, due to the Task Arrangement of boot (the company has been working with dedicated personnel), there has been no chance of contact, when I first got started with embedded systems, I had been trying to figure out how, Program But after reading the company's boot source code, I quickly gave up. At that time, I was full of fear about compilation. After more than a year of driving, looking at the compilation, I feel that it is no longer painful. Recently, I sorted out the boot data and read the core section of boot. Now I have made a mark. I have sorted out the difficulties that I think I was confused before. Maybe you can discuss them together, maybe new users like me can take less detours.
The core of boot is relocate. Currently, a typical embedded system, except for the processor, has at least Rom (norflash, nandflash) RAM (SDRAM ). Code Stored in norflash, and nandflash cannot be accessed randomly due to hardware reasons. It is generally used to store applications. after the system is powered on or reset, the CPU is usually scheduled by the CPU manufacturer to take the address command in advance. In the arm system, the first command is usually obtained from the 0x0 address, that is, Pc = 0.
I personally think that is closely related to boot.
1. Remap.
Remap is relatively simple. It is equivalent to MMU, except that the remap address is estimated to be 0x0, there is a post on the Internet called <arm REMAP and relocation excerpt> devoted to its understanding of REMAP. The role of REMAP is as follows: when the ARM processor is powered on or reset, processor from 0x0. Therefore, commands at 0x0 must be executed when the system is powered on. Therefore, when power-on, 0x0 address must be Rom or flash (NOR ). However, to speed up the startup, you can easily change the abnormal vector table to speed up the interrupt response, and usually map the abnormal vector table to a faster and wider (32bit/16bit) RAM. However, the starting address of the abnormal vector table is determined by the ARM architecture and must be at 0x0. Therefore, the RAM must be mapped to 0x0.
This article mentions three situations of ARM processor remap:
1) remap can be completed if the processor has a dedicated register. Then, the remap is completed through the corresponding bit set 1 of the remap register.
For example, Atmel at91xx
2) If the processor does not have a special register, but memory's bank control register can be used to configure the starting address of the bank, you only need to program the starting address of Ram to 0x0, you can also complete Remap. For example, Samsung.
3) if neither of the above mechanisms is available, REMAP will not be used. Because the implementation of the processor determines that the Bank address corresponding to the SDRAM cannot be changed. Such as Samsung S3C2410.
However, my opinion is a little different. If neither of the above two mechanisms is available, REMAP will not be used. A typical example is Samsung S3C2410, 2410 although the Bank address corresponding to SDRAM cannot be changed, but it has the MMU function, MMU can play the role of REMAP, the most common example should be Samsung B0, it has no MMU, there is no way to change the address of SDRAM. by the way, in addition to 4510, we can change the address of each bank, as well as the w90p740 (ARM7) of huabang. Oh, I am using this u, you can set the Bank address at will.
2. relocate.
Relocate (address relocation), I personally think this is the most troublesome and core part of boot. It was my nightmare when I first started to read the boot code, I don't know if the source code process for analyzing boot is like this. I may not be a computer in college, but I have never learned how to compile it. (I haven't seen it yet) I don't know anything about links and loading, two weeks of pain, that is, why do I write the link script in Boot. there are a lot of posts on uboot on the Internet, but I have never written any details about the link. I don't know if it's too basic. I am not willing to talk about it. Finally, I will find my own materials, I found that the root cause of all the pain is that the link and loading are not clear, but I personally feel that the boot is a handler except initialization. How can I handle it? Why do we need to know the address distribution of the hardware board in that case? These are determined by links, so it is not clear!
1. Why do we need relocate? Economically, (the prices of nandflash and norflash vary greatly from each megabits), and the boot code is placed in norflash (why not put it in nandflash, because nandflash requires driver support and norflash can be accessed directly ), boot is usually very small, it only needs to occupy dozens of K of space, so it only needs a small norflash chip, this is very cheap, and the application is usually very large, therefore, nandflash is used for storage at a low cost. In actual applications, the nandflash code and data are transferred to the memory for execution by executing the boot program. This way, the program can be directly stored in norflash. in addition, there are differences in the running speed. The execution speed of the program in norflash is much lower than the execution speed in SDRAM. In order to achieve higher speed, relocate is also required for the program to be executed in the SDRAM.
.
2. about loading a domain (VMA) and a running domain (LMA ), in his classic <ARM architecture and programming>, du chunlei specializes in loading and running domain inconsistencies, however, after I first came into contact with these loading and running domains, I checked the uboot's lDs. The uboot's LDs didn't set the LMA, but set the VMA, so I have been wondering for a long time. until the patience to read the linker and loader book suddenly understand (http://bbs.chinaunix.net/viewthread.php? Tid = 817770), the basic work of any linker and loader is very simple:
Bind a more abstract name to a lower-level name, so that programmers can use a more abstract name to write code. The linker is to parse the source file through symbols, bind the resolved symbols and addresses, and bind the global variables, functions, and labels to the addresses.
3. there is another important reason why boot can be correctly executed after power-on. It is necessary to ensure that the code initially executed after the boot system is powered on or reset is address-independent, (the Code executed before the code is moved is not related to the address.) the image file generated by the address-independent code can be run on any address in the memory. For address-independent code, addressing is based on the PC value. +/-an offset value on the PC value to obtain the running address, such as jump command B. after the code is executed, we need to jump to the address-related place for execution. That is, in our Ram, we usually jump to a label, then the address-related code starts to run ldr pc, _ start_armboot. this is because the _ start_armboot symbol has been bound to the actual address when the bin image is generated. When LDR is executed
PC, _ start_armboot will jump from execution in ROM to ram, but the premise is that we have moved the Code. If there is no code to move ldr pc, _ start_armboot, if there is no code program in Ram, it will fly away immediately. Before moving, we cannot address the absolute address. The code must be executed.
Take the u-boot-1.1.4 of smdk2410 for example, and smdk2410 Board closely related to the two folders \ board \ smdk2410 and \ CPU \ ARM920T, inside the core file on the u-boot.lds, config. MK, start. s.
Entry (_ start)
Sections
{
. = 0x00000000; // starts from 0
. = Align (4 );
. Text:
{
CPU/ARM920T/start. O (. Text)
* (. Text)
}
. = Align (4 );
. Rodata: {* (. rodata )}
. = Align (4 );
. Data: {* (. Data )}
. = Align (4 );
. Got: {* (. Got )}
. = .;
_ U_boot_1__start = .;
. U_boot_cmd: {* (. u_boot_cmd )}
_ U_boot_1__end = .;
. = Align (4 );
_ Bss_start =.; // The symbol provided for the handling code to indicate the BSS segment address for relocate convenience
. BSS: {* (. BSS )}
_ End =.; // defines the end address of the entire image.
}
U-boot.lds is the link script file, I was confused for a long time when I first read this link script file, I don't understand VMA = LMA in lDs (many of the link scripts in this document include the LDs scripts written by myself in our company's project. They set LMA through the AT command, so it seems that the address space allocation is clearer ), in addition, the VMA of the entire image uses the LDs base address as 0x0, while the 2410 chip cannot Remap. The 0x0 address is the ROM region, not the RAM address at runtime, in my understanding, the code segment address should point to the memory area of the hardware board and be set. TEXT = text_base instead. TEXT = 0x0. I was very depressed with this question. After thinking for a long time, I didn't want to figure out whether the link script such as U-boot can run boot, when I burned the compiled bin to norflash, uboot ran and found a problem,
The u-boot.map found. text is from config. MK defines text_base = 0x33f80000, instead of the 0x0 set by LDs, which surprised me. I don't know how it works. I have some information on porting uboot, however, the uboot link is not detailed enough to understand the config. the MK file is a ghost, but the MAKEFILE file has not been found several times. Why? (still not familiar with makefile !), Finally, the uboot compilation process is viewed as hidden.
Arm-Linux-LD-Tu-boot-1.1.4 \ board \ smdk2410 \ u-boot.lds-ttext 0x33f80000
Arm-Linux-objcopy -- gap-fill = 0xff-O binary uboot ubtoot. Bin
I don't know why the uboot designer should add a-ttext here instead of setting it in lDs? A lot of uboot porting materials are described in the LDs file, but this important detail seems to have been missed. I don't know if it is because it is too basic, so I didn't talk about it.
However, for the last bin generated, see arm-Linux-objcopy -- gap-fill = 0xff-O binary uboot ubtoot. bin does not relocate the ELF file generated by the link, so its run address is config. MK defines text_base as the base address, which is added in sequence according to the order of LDS. Therefore, the initial running process of uboot is as follows:
_ Start & #61664; reset & #61664; cpu_init_crit & #61664; relocate
This part is complete initialization. It is easy to set svc32, shut down the watchdog, shut down the clock, set the clock, and initialize the SDRAM (to prepare for code transfer to the SDRAM ).
Relocate:
ADR r0, _ start
LDR R1, _ text_base
CMP r0, r1
Beq stack_setup
LDR R2, _ armboot_start
LDR R3, _ bss_start
Sub R2, R3, r2
Add R2, R0, r2
Copy_loop:
Ldmia R0 !, {R3-r10}
Stmia R1 !, {R3-r10}
CMP r0, r2
Ble copy_loop
I read the post on the Internet and the ADR command. Many people on the Internet are depressed by this command. I think du chunlei's <ARM architecture and programming> p143 said, this command is based on a PC or register and is address-independent. It is generally replaced by sub r0, PC, # offset by the compiler, do not read the address that complies with the _ start symbol in the table (0x33f80000 ). when we start execution after power-on, the PC starts from 0, so the R0 value is 0 + offset, not equal to _ text_base (0x33f80000 ). next, we need to use the signed address identified during the link, _ armboot_start (0x33f80000 )., _ bss_start (0x33f97954) These can be seen in the u-boot.map,
Size of armboot = 0x33f97954-0x33f80000, SET _ start: 0x0 (norflsh. text ,. data Code: 0x33f80000. the SDRAM base address of S3C2410 is 0x3000_0000, because uboot supports this board SDRAM is 64 m, (0x3000_0000 --- 0x3400_0000), so the u-boot.bin to the high-end address of memory. then jump to the memory for execution to increase the speed.
Then relocate & #61664; stack_setup & #61664; clear_bss & #61664; ldr pc, _ start_armboot (ROM & #61664; Ram)
_ Start_armboot:. Word start_armboot (u-boot-1.1.4 \ lib_arm \ board. c)
Stack_setup and clear_bss set the stack clearing BSS segments to initialize the C language. After you link start_armboot and bind the function address to ram, label command, the program will start from the label binding address, so as to achieve the transformation from the address-independent program to the address-related, we do code migration is also to prepare for the jump, if not moved, direct access address-related, because Ram is a random value, a jump will immediately fly. when you enter the start_armboot C function, the rest will not be difficult. you can analyze the source code slowly. 2410 there is no remap register, so it is easier to relocate. remap the chips with remap registers during relocate makes the situation more complicated. however, the principles are similar.
Go to the board. after C, uboot also performs a code transfer as follows, for example, but there are two types: one is to upload the image uploaded by the PC to the memory through the serial port or network to start execution, or move the application from nandflash to the memory for execution, but the principle is similar.
The company gave us a board-Level Initialization training to sort out the key points of the hardware board initial process ,. compared with the boot initialization, we can find that the hardware board initialization process is similar. it is a headache or link to this part. I feel that there is too little information in this area. No one can give me some advice. It is very painful to read this part of information.
[CPU core initialization] & #61664; [watchdog initialization] & #61664; [gpio initialization] & #61664; [system clock initialization] & #61664; [memory initialization] & #61664; [Mode Initialization] & #61664; [interrupt vector initialization] & #61664; [MMU initialization] & #61664; [cache initialization] & #61664; [Bus initialization] & #61664; [language-related initialization] & #61664; [device-related initialization]
4. ELF format and bin format
Executable and linking format (ELF) Relocation, can participate in the program Link (create a program) and program execution (run a program), the main link, and execution, however, there is a lot of information about the ELF file. If you don't have time to take a closer look, you can debug the program in the ELF format because it contains the various symbols required for debugging, the bin format is used for solidification. It is an executable image and elf is converted to bin using objcopy. However, there is very little information about the bin format on the Internet, but we only know the bin program, as long as you set the PC as the bin image's entry address, it can be correctly executed. objcopy can convert elf to bin and then perform address relocation. However, we haven't seen such operations yet. For elf, and bin do not understand the system, and there are very few materials. At work, the Integrated Development Tool ide shields these settings. Is there a strong person who can write a document, just give a clear explanation of all these systems!
By the way, there are not many forums in Shanghai. Are you looking for a job online? A mm pulled me to Shanghai. Although I was very satisfied with my current job, mm is more important than work. I had to make a choice. I only went to Shanghai, but I submitted a resume on 51job, it is reasonable to say that two years is not short, at least a bubble will take place. Is there any advice from Shanghai? How did you find a job in Shanghai?
I added that I was looking for information and saw a post on the Internet. I felt like I wrote a very incisive explanation about the address. The webpage address was changed to a similar path, so I couldn't paste it out, paste the original text.
Keywords: Address independence
Terms
Address-independent: the compilation address is not equal to the running address.
Address: the compilation address is equal to the running address.
Common boot (for example, U-boot, Vivi) and the start of Linux kernel code are location-independent, meaning that the run address has nothing to do with the compile address. for example, the Kernel Compiling address is 0xc0008000, and the running address is 0x30008000.
Why?
Why are the compilation addresses and application addresses of the Code not equal? The main reasons are as follows: 1) for boot, the memory capacity used to store Boot Code is smaller than the amount of code. for example, the boot chip has 4 K, and the code usually has 50-60 K. in this way, boot will usually copy itself to ram in the first 4 K code and then run. here we need to make a choice, whether to make the previous Code relevant to the address, or to make the subsequent Code related to the address? Obviously, we will select the address irrelevant to the small amount of code in the previous section. 2) For Linux kernel, it runs in the virtual address space, such as 0xc0008000. However, before MMU is enabled, the address is usually
Does not exist. That is to say, before MMU is enabled, the kernel code must be address-independent.
What should I do?
For location-independent code, addressing is based on the PC value. +/-an offset value on the PC value to get the running address. taking arm as an example, ADR is used for addressing. ADR is actually a macro command. During code compilation, it will be replaced by the compiler with the PC ++/-operation.
Note that there is obviously an address range for PC +/-running, so it is wise to select an address with a small amount of code on it.
The access address-related code only needs to use other addressing commands. but before that, you must ensure that the Code is placed on the correct address. Therefore, there is usually a process of copying the code, and then jump to a label, and the address-related code starts to run.
This article is reproduced on the Internet. The author is unknown.