[U-Boot] Trying to understand ARM926EJS/start.S

Hello,
I am not (yet) good at ARM assembler syntax and instructions, so trying to understand the start.S code is not very easy for me. However I think I saw some places there that need clarification. All what I see as suspiscious I have marked with $$$ and just comments with %%% in the next line.
... .globl _bss_start_ofs _bss_start_ofs: .word __bss_start - _start
.globl _bss_end_ofs _bss_end_ofs: .word _end - _start %%% both yield constants that are in TEXT and can be accessed %%% PC relative, right? ... reset: /* * set the cpu to SVC32 mode */ mrs r0,cpsr bic r0,r0,#0x1f orr r0,r0,#0xd3 msr cpsr,r0 %%% just style: the rest uses spaces after the comma. /* * we do sys-critical inits only at reboot, * not when booting from ram! */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif
/* Set stackpointer in internal RAM to call board_init_f */ call_board_init_f: ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) ldr r0,=0x00000000 %%% style bl board_init_f
/*------------------------------------------------------------------------------*/
/* * void relocate_code (addr_sp, gd, addr_moni) * * This "function" does not return, instead it continues in RAM * after relocating the monitor code. * */ .globl relocate_code relocate_code: mov r4, r0 /* save addr_sp */ mov r5, r1 /* save addr of gd */ mov r6, r2 /* save addr of destination */ mov r7, r2 /* save addr of destination */
/* Set up the stack */ stack_setup: mov sp, r4
adr r0, _start %%% adr reg, label sets reg to the address of label? %%% ldr reg, label sets reg to the content of mem at label? ldr r2, _TEXT_BASE $$$ r2 is overwritten two lines below, right? ldr r3, _bss_start_ofs add r2, r0, r3 /* r2 <- source end address */ cmp r0, r6 beq clear_bss
copy_loop: ldmia r0!, {r9-r10} /* copy from source address [r0] */ stmia r6!, {r9-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end address [r2] */ blo copy_loop
#ifndef CONFIG_PRELOADER /* * fix .rel.dyn relocations */ ldr r0, _TEXT_BASE /* r0 <- Text base */ %%% why are we using _TEXT_BASE here and not _start? sub r9, r7, r0 /* r9 <- relocation offset */ ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */ add r10, r10, r0 /* r10 <- sym table in FLASH */ ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */ add r2, r2, r0 /* r2 <- rel dyn start in FLASH */ ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */ add r3, r3, r0 /* r3 <- rel dyn end in FLASH */ fixloop: ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */ add r0, r0, r9 /* r0 <- location to fix up in RAM */ ldr r1, [r2, #4] and r8, r1, #0xff cmp r8, #23 /* relative fixup? */ beq fixrel cmp r8, #2 /* absolute fixup? */ beq fixabs /* ignore unknown type of fixup */ b fixnext fixabs: /* absolute fix: set location to (offset) symbol value */ mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */ add r1, r10, r1 /* r1 <- address of symbol in table */ ldr r1, [r1, #4] /* r1 <- symbol value */ add r1, r9 /* r1 <- relocated sym addr */ b fixnext fixrel: /* relative fix: increase location by offset */ ldr r1, [r0] add r1, r1, r9 fixnext: str r1, [r0] add r2, r2, #8 /* each rel.dyn entry is 8 bytes */ cmp r2, r3 blo fixloop #endif
clear_bss: #ifndef CONFIG_PRELOADER ldr r0, _bss_start_ofs %%% r0 = __bss_start - _start ldr r1, _bss_end_ofs %%% r1 = _end - _start ldr r3, _TEXT_BASE /* Text base */ $$$ r3 is not used below this mov r4, r7 /* reloc addr */ %%% why move it to r4? could we not add r7 in the next 2 lines? add r0, r0, r4 %%% ok, this yields r0 = __bss_start - _start + "relocated address" add r1, r1, r4 %%% ok, this yields r1 = _end - _start + "relocated address" mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */ add r0, r0, #4 cmp r0, r1 bne clbss_l %%% this should better be blo, just in case _end is not aligned?
%%% I cannot see anything here that would prevent BSS being cleared. bl coloured_LED_init bl red_LED_on #endif
/* * We are done. Do not return, instead branch to second part of board * initialization, now running from RAM. */ #ifdef CONFIG_NAND_SPL ldr r0, _nand_boot_ofs mov pc, r0
_nand_boot_ofs: .word nand_boot #else ldr r0, _board_init_r_ofs adr r1, _start add lr, r0, r1 add lr, lr, r9 /* setup parameters for board_init_r */ mov r0, r5 /* gd_t */ mov r1, r7 /* dest_addr */ /* jump to it ... */ mov pc, lr ...
Best Regards, Reinhard

Le 30/10/2010 20:09, Reinhard Meyer a écrit :
%%% both yield constants that are in TEXT and can be accessed %%% PC relative, right?
Constants, yes; in .text, yes; can be accessed pc-relative, yes, as any other location in .text actually. But you probably meant "expected to be accessed PC relative", in which case: yes.
%%% adr reg, label sets reg to the address of label? %%% ldr reg, label sets reg to the content of mem at label?
Correct.
ldr r2, _TEXT_BASE $$$ r2 is overwritten two lines below, right? ldr r3, _bss_start_ofs add r2, r0, r3 /* r2<- source end address */
Correct.
ldr r0, _TEXT_BASE /* r0<- Text base */ %%% why are we using _TEXT_BASE here and not _start?
Because we're accessing the relocation tables in the FLASH (or freshly NAND-loaded) "source" copy of u-boot, not in the RAM "target" copy (in which the relocation tables won't exist).
ldr r3, _TEXT_BASE /* Text base */ $$$ r3 is not used below this
If it is useless then it can be removed (but would not cause any issue). Note that it may be used implicitly as the 3rd argument to a C function call... But I don't think it is, no function called below uses 3 arguments I think.
mov r4, r7 /* reloc addr */ %%% why move it to r4? could we not add r7 in the next 2 lines?
We could indeed -- actually, we could probably otimize register usage in other places too.
bne clbss_l %%% this should better be blo, just in case _end is not aligned?
Correct. I thinought I'd sent a patch to fix all these... Seems I missed some.
%%% I cannot see anything here that would prevent BSS being cleared.
Neither do I -- if you think of Alexander's issue, I think it is not related to BSS initialization.
Best Regards, Reinhard
Amicalement,

Dear Albert ARIBAUD,
In message 4CCC69E4.8090103@free.fr you wrote:
ldr r0, _TEXT_BASE /* r0<- Text base */ %%% why are we using _TEXT_BASE here and not _start?
Because we're accessing the relocation tables in the FLASH (or freshly NAND-loaded) "source" copy of u-boot, not in the RAM "target" copy (in which the relocation tables won't exist).
Sorry, but I don't understand this explanation.
With the linker script we make sure that the symbol _start gets linked to the absolute address CONFIG_SYS_TEXT_BASE, right? And _TEXT_BASE is a storage that holds exactly the value CONFIG_SYS_TEXT_BASE, which should be identical to the address of _start ?
Best regards,
Wolfgang Denk

Le 30/10/2010 21:21, Wolfgang Denk a écrit :
Dear Albert ARIBAUD,
In message4CCC69E4.8090103@free.fr you wrote:
ldr r0, _TEXT_BASE /* r0<- Text base */ %%% why are we using _TEXT_BASE here and not _start?
Because we're accessing the relocation tables in the FLASH (or freshly NAND-loaded) "source" copy of u-boot, not in the RAM "target" copy (in which the relocation tables won't exist).
Sorry, but I don't understand this explanation.
With the linker script we make sure that the symbol _start gets linked to the absolute address CONFIG_SYS_TEXT_BASE, right? And _TEXT_BASE is a storage that holds exactly the value CONFIG_SYS_TEXT_BASE, which should be identical to the address of _start ?
Somehow I thought the question was "why use the source location rather than the target".
Yes, if we're still running from the "source" address at that point, the value of _start and the content of _TEXT_BASE should be the same -- that does change once we start the fixup loop, though; after the loop is done, I think "adr r0, _start" will still give us the source start address but _TEXT_BASE will contain the target start address -- though at this time of the evening I'd want to be careful about that.
Tomorrow morning I'll run a step-by-step case on my ED Mini V2 and on my OpenRD and see if / where we can use "adr rX, _start".
Best regards,
Wolfgang Denk
Amicalement,

Le 30/10/2010 23:56, Albert ARIBAUD a écrit :
after the loop is done, I think "adr r0, _start" will still give us the source start address but _TEXT_BASE will contain the target start address -- though at this time of the evening I'd want to be careful about that.
Scratch that. After the loop, the _TEXT_BASE of the target location will contain the target _start, but the _TEXt_BASE of relocate_code() will keep on containing the source _start. Really time I went to sleep.
Apologies,

On 30.10.2010 20:54, Albert ARIBAUD wrote:
Le 30/10/2010 20:09, Reinhard Meyer a écrit :
%%% both yield constants that are in TEXT and can be accessed %%% PC relative, right?
Constants, yes; in .text, yes; can be accessed pc-relative, yes, as any other location in .text actually. But you probably meant "expected to be accessed PC relative", in which case: yes.
Yes, I meant the latter.
%%% adr reg, label sets reg to the address of label? %%% ldr reg, label sets reg to the content of mem at label?
Correct.
ldr r2, _TEXT_BASE $$$ r2 is overwritten two lines below, right?
So this line is some remnant of earlier code and can be removed
ldr r3, _bss_start_ofs add r2, r0, r3 /* r2<- source end address */
Correct.
ldr r0, _TEXT_BASE /* r0<- Text base */ %%% why are we using _TEXT_BASE here and not _start?
Because we're accessing the relocation tables in the FLASH (or freshly NAND-loaded) "source" copy of u-boot, not in the RAM "target" copy (in which the relocation tables won't exist).
Which, by definition, is at TEXT_BASE, so _start should be identical and adr r0, _start should have the same result?
ldr r3, _TEXT_BASE /* Text base */ $$$ r3 is not used below this
If it is useless then it can be removed (but would not cause any issue). Note that it may be used implicitly as the 3rd argument to a C function call... But I don't think it is, no function called below uses 3 arguments I think.
That would be bad style. Sure it is not used later.
mov r4, r7 /* reloc addr */ %%% why move it to r4? could we not add r7 in the next 2 lines?
We could indeed -- actually, we could probably otimize register usage in other places too.
bne clbss_l %%% this should better be blo, just in case _end is not aligned?
Correct. I thinought I'd sent a patch to fix all these... Seems I missed some.
I'm still thinking of the idea to move the general, non specific bits of relocation and bss clearing to a general file; or even better to do most of it in C. We should just need a small asm helper function to change stack and branch to the relocated code.
%%% I cannot see anything here that would prevent BSS being cleared.
Neither do I -- if you think of Alexander's issue, I think it is not related to BSS initialization.
No, since everything works fine here (though I cannot confirm BSS gets cleared, maybe none of the code active here assumes cleared BSS:) ), but I am sure ALL code and vars is really accessed at the final, high end RAM location. I filled all RAM upto 2MB below the end with garbage and nothing crashed and u-boot still behaved proper.
Alexander's issue cannot be related to a general u-boot problem, it must be SoC or board specific or handling specific. As to what we can only speculate.
I can only advise again to check for static vars that are used before relocation (which need not lead to a crash), but their values will be lost during relocation. This made timers fail here because clock frequencies calculated in timer init before relocation and stored in static vars were gone after relocation.
Oh, and u-boot did not work here when compiled with gcc 4.4.5 - I almost forgot about that... I think I even mentioned that in some message a while ago, but I can't find it right now.
Best Regards, Reinhard

Oh, and u-boot did not work here when compiled with gcc 4.4.5 - I almost forgot about that... I think I even mentioned that in some message a while ago, but I can't find it right now.
Aah, it was 4.3.5:
Re: [U-Boot] Followup: GCC-4.3.5 and U-Boot (arm, reloc) not working> at 11.10.2010
Best Regards, Reinhard

Dear Reinhard Meyer,
In message 4CCC709F.20306@emk-elektronik.de you wrote:
Neither do I -- if you think of Alexander's issue, I think it is not related to BSS initialization.
No, since everything works fine here (though I cannot confirm BSS gets cleared, maybe none of the code active here assumes cleared BSS:) ), but I am sure ALL code and vars is really accessed at the final, high end RAM location. I filled all RAM upto 2MB below the end with garbage and nothing crashed and u-boot still behaved proper.
Well, if you like then just make an experiment and replace the
mov r2, #0x00000000 /* clear */
by something like
mov r2, #0xA5A5A5A5 /* clear */
and watch your system go kaboom...
Alexander's issue cannot be related to a general u-boot problem, it must be SoC or board specific or handling specific. As to what we can only speculate.
I can only advise again to check for static vars that are used before relocation (which need not lead to a crash), but their values will be lost during relocation. This made timers fail here because clock frequencies calculated in timer init before relocation and stored in static vars were gone after relocation.
That would most likely be driver stuff, which is shared with other boards, so thse should show similar issues.
My bet is on errors in the initial RAM setup - like unaligned intial stack (which would also explain the bogus RAM sizes printed, with the hex numbers not even corresponding to the decimal decoding), and/or tool chain issues (I've seen way too many optimizer bugs in GCC >= 4.3 lately).
Oh, and u-boot did not work here when compiled with gcc 4.4.5 - I almost forgot about that... I think I even mentioned that in some message a while ago, but I can't find it right now.
I'm neither surprised nor amused.
Best regards,
Wolfgang Denk
participants (3)
-
Albert ARIBAUD
-
Reinhard Meyer
-
Wolfgang Denk