We all know that U-BOOT is divided into two stages.
The first stage is (~ /Cpu/arm920t/start. in seconds) run on FLASH (generally) to initialize the hardware, including the watchdog and cache interruption, in addition, it is responsible for moving the code to the SDRAM (checking whether the code is in the SDRAM during the migration), and then completing the establishment of the environment required for the C program to run, including the initialization of the stack, etc, finally, execute a jump command:
Ldr pc, _ start_armboot
_ Start_armboot:. word start_armboot,
Go to the void start_armboot (void) function in/lib_arm/board. c ). This is the second stage. This is described in many materials, so you do not need to say more.
There are several problems in the first stage. I have never understood it before. Since the code in FLASH copies itself to the SDRAM, in the memory address space of the S3C2410, there are two pieces of startup code, the first is in FLASH, and the second is in SDRAM.
Based on the Link script file (~ /Board/smdk2410/u-boot.lds)
OUTPUT_FORMAT ("elf32-littlearm", "elf32-littlearm", "elf32-littlearm ")
/* OUTPUT_FORMAT ("elf32-arm", "elf32-arm", "elf32-arm ")*/
OUTPUT_ARCH (arm)
ENTRY (_ start)
SECTIONS
{
. = 0x00000000;/* Postscript: the starting address of this link is actually updated by-ttest $ (test_base */
. = 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 = .;
. BSS: {* (. BSS )}
_ End = .;
}
The link command. = 0x00000000; indicates that the address counter starts counting from 0, and _ start is the entry of the program code segment, then *. all address numbers in text (cpu/arm920t/start. the value defined in S should start from 0, so the entry address of start_armboot (that is, void start_armboot (void) function) should be in FLASH, therefore, according to the above analysis,
Ldr pc, _ start_armboot
_ Start_armboot:. word start_armboot
This statement does not jump to void start_armboot (void) in SDRAM, but to void start_armboot (void) in FLASH.
So there is such a conflict. There is a piece of code in FLASH that copies itself to the SDRAM and generates two executable UBOOT command streams, however, it does not jump to the SDRAM to run the command to speed up command execution.
The above understandings are based on the following (which must be false ):
1.
* All address labels in. text are generated starting from 0.
In fact, when executing arm-linux-ld, the previously defined 0x0 address is updated to the address defined by TEXT_BASE.
2.
Relocate:/* relocate U-Boot to RAM */
Adr r0, _ start/* r0 <-current position of code */
Ldr r1, _ TEXT_BASE/* test if we run from flash or RAM */
Cmp r0, r1/* don't reloc during debug */
Beq stack_setup
Ldr r2, _ armboot_start
Ldr r3, _ bss_start
Sub r2, r3, r2/* r2 <-size of armboot */
Add R2, R0, R2/* R2 <-source end address */
If it is not due to the debugging phase, the R0 and R1 in the Code involved in this shift are definitely not equal. R0 = #0, R1 = # text_base: 0x33f80000 (in. /board/smdk2410/config. mk), so the Code itself is copied and moved.
Note:: In GNU:
ADR r0, _ start is used to obtain the address value of the actual operation of _ start, while LDR R1 and _ text_base are used to obtain the data stored in address _ text_base,
Here, ADR R0 and _ start are translated into add r0, (PC + # offset ),Offset is the offset from the _ start command to the _ start command of adr r0. It is determined at the link time that this offset is address-independent..
LDR R1, _ text_base commandLoad data in a relative offset of a programIs another form of index Offset Loading. It is equivalent to LDR R1, [PC + # offset], and offset is the offset from LDR R1, _ text_base to _ text_base.Note that this usage is not a pseudo-command. The features of the pseudo-command are:
Ldr r1, = expr/lable_expr. For LDR commands, the ads situations are somewhat different (slightly different). For details about the LDR commands, refer to duchunlei <ARM architecture and programming> 144.
Comparison:
Add r0, (PC + # offset): (PC + # offset) is the relative address, indicating that the offset of this command is traced back or down.Address load to r0;
LDR R1, [PC + # offset]: [PC + # offset] is also a relative address, indicating to offsetLoad the data on the address to r1;
Continue now:
The contradiction obtained by the analysis just now is definitely the deviation in understanding, after making the U-BOOT, from the two generated. Map Files (~ /U-boot.map and systen. map), all address labels start from 0x33f80000, that is, from the high address of the SDRAM, equal to the value of text_base, that is, the linker starts from 0x33f80000 to link the compiled target file, instead of starting from 0. After viewing, start_armboot = 0x33f80d9c, that is, void start_armboot (void) the function entry address is in SDRAM (determined by the linker ).
Ldr pc, _ start_armboot
_ Start_armboot:. Word start_armboot,
The PC pointer must point to the SDRAM. In other words, it is entered into the SDRAM. For ldr pc, _ start_armboot, it is still using the program relative offset in GNU to load data, the translation is ldr pc, [pc + pc to _ start_armboot offset value], and the result is to put the number of start_armboot in the _ start_armboot address into the pc to complete the jump, the value of start_armboot (function address) is determined at the link, relative to TEXT_BASE. Because all addressing in phase 1 of UBOOT is relative addressing (although the Code of Phase 1 is considered as starting from the address 0x3ff80000 ), the Code of Phase 1 can also be correctly run in FLASH at the beginning of 0. If the Reset vector of ARM is 0x00000001 (hypothesis ), if you burn the code to a place starting from 0x00000004, the code can run correctly during power-on (assuming that the Reset vector of ARM is in 0x00000004). Of course, the Reset vector of ARM is not here, this assumption is used to illustrate the above analysis of Phase 1.
Now the last contradiction is the link script (~ /Board/smdk2410/u-boot.lds) the link address is not the same as the actual link address, because according to the link script, all address labels should start counting from 0 address, but not. Find the Makefile file,
In the Makefile file at the top layer, link the link command in line 166:
$ (LD) $ (LDFLAGS) $ UNDEF_SYM $ (OBJS )/,
Row 145 of LDFLAGS defined in config. mk at the top layer: LDFLAGS + =-Bstatic-T $ (LDSCRIPT)-Ttext $ (TEXT_BASE) $ (PLATFORM_LDFLAGS ),
The most critical is the-Ttext $ (TEXT_BASE) command, which means that the starting address is in TEXT_BASE, while TEXT_BASE is in ~ TEXT_BASE = 0x3FF80000 in/board/smdk2410/config. mk;
Now we can figure out why the link started from 0x3ff80000. As for the link script, its main function is to specify each *. o file sequence, such as entry address label (_ start) and so on, and make the two address labels get the current address
_ U_boot_cmd_start = ..; *. Start address of the u_boot_cmd segment
. U_boot_cmd: {* (. u_boot_cmd )}
_ U_boot_cmd_end = ..; *. End address of the u_boot_cmd segment
For use by C Programs. _ U_boot_cmd_start and _ u_boot_cmd_end can be used as global constants.
.
Summary:
Because the-Ttext $ (TEXT_BASE) command is used, the linker connects UBOOT from the address 0x3ff80000. In the first stage, all target address addressing uses the method of adding or subtracting the offset from the current PC value. Therefore, writing UBOOT to FLASH starting from 0 does not affect the correct execution of the first phase.