[U-Boot] lib_arm global data pointer

Hi all, in libarm/board.c, in function start_armboot(void) I found lines like these:
/* Pointer is writable since we allocated a register for it */ gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory");
gd is defined as: register volatile gd_t *gd asm ("r8")
I have 3 questions: 1) Why is it necessary to allocate register? Don't we have stack at this point (we already allocated stack in start.S). 2) One C question - are we sure that compiler will listen to our which and really allocate register? 3) Why do we need this membar? To prevent compiler from touching our reg r8 or for some other reason?
Suppose that I allocated one register in start.S and put in it some data I want to have later on C side. From start.S we enter to start_armboot(void) function. Would this work :
void start_armboot (void) { init_fnc_t **init_fnc_ptr; char *s; #ifndef CFG_NO_FLASH ulong size; #endif #if defined(CONFIG_VFD) || defined(CONFIG_LCD) unsigned long addr; #endif *#ifdef DATA_FROM_ASM_IN_R10 register volatile unsigned long tmp asm ("r10"); #endif*
/* Pointer is writable since we allocated a register for it */ gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t)); gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); memset (gd->bd, 0, sizeof (bd_t));
*#ifdef DATA_FROM_ASM_IN_R10 /* data will be passed to C from assembly start-up in reg r10 */ gd->bd->bi_my_data = tmp; #endif*
monitor_flash_len = _bss_start - _armboot_start;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); } }
...
}
Would I from this point on really have on C stack what I had in r10 in start.S?
If not, does anybody have idea how I can do it?
Thanks and best regards, Drasko DRASKOVIC

On Fri, Jul 10, 2009 at 02:52:32PM +0200, Drasko DRASKOVIC wrote: [...]
Suppose that I allocated one register in start.S and put in it some data I want to have later on C side. From start.S we enter to start_armboot(void) function. Would this work :
void start_armboot (void) { init_fnc_t **init_fnc_ptr; char *s; #ifndef CFG_NO_FLASH ulong size; #endif #if defined(CONFIG_VFD) || defined(CONFIG_LCD) unsigned long addr; #endif *#ifdef DATA_FROM_ASM_IN_R10 register volatile unsigned long tmp asm ("r10"); #endif*
/* Pointer is writable since we allocated a register for it */ gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory"); memset ((void*)gd, 0, sizeof (gd_t)); gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); memset (gd->bd, 0, sizeof (bd_t));
*#ifdef DATA_FROM_ASM_IN_R10 /* data will be passed to C from assembly start-up in reg r10 */ gd->bd->bi_my_data = tmp; #endif*
[...]
Would I from this point on really have on C stack what I had in r10 in start.S?
If not, does anybody have idea how I can do it?
While the above may work, why you don't just follow the procedure call standard instead? Place the value in r0 instead of r10, and you'll have it as the first argument to the function.
Rabin

While the above may work, why you don't just follow the procedure call standard instead? Place the value in r0 instead of r10, and you'll have it as the first argument to the function.
there is a reason why I use r10 (and why somebody used r8, I suppose) - I search some address during start.S, and want to stock it in the place that will not be corrupted during continuation of the code in start.S. As you can see, start.S will heavily use r0, r1, probably other low-numbered regs.
Yes, I can put r10 to r0 just before the call of the function (and change signature of start(void) to start(int my_var), is that rght?) but what would this change. If the thisngs work with r10, even better...
And one thing I also noted that is strange a variable of "register volatile". I played around with arm gcc compiler - does this volatile stuff really have some effect? Compiler seems to produce asm code like it is not volatile (optimize by deleting conditions, assign values by add and not mov, etc...)
BR, Drasko
On Mon, Jul 13, 2009 at 3:38 PM, Rabin Vincent rabin@rab.in wrote:
On Fri, Jul 10, 2009 at 02:52:32PM +0200, Drasko DRASKOVIC wrote: [...]
Suppose that I allocated one register in start.S and put in it some data
I
want to have later on C side. From start.S we enter to
start_armboot(void)
function. Would this work :
void start_armboot (void) { init_fnc_t **init_fnc_ptr; char *s; #ifndef CFG_NO_FLASH ulong size; #endif #if defined(CONFIG_VFD) || defined(CONFIG_LCD) unsigned long addr; #endif *#ifdef DATA_FROM_ASM_IN_R10 register volatile unsigned long tmp asm ("r10"); #endif*
/* Pointer is writable since we allocated a register for it */ gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory"); memset ((void*)gd, 0, sizeof (gd_t)); gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); memset (gd->bd, 0, sizeof (bd_t));
*#ifdef DATA_FROM_ASM_IN_R10 /* data will be passed to C from assembly start-up in reg r10 */ gd->bd->bi_my_data = tmp; #endif*
[...]
Would I from this point on really have on C stack what I had in r10 in start.S?
If not, does anybody have idea how I can do it?
While the above may work, why you don't just follow the procedure call standard instead? Place the value in r0 instead of r10, and you'll have it as the first argument to the function.
Rabin

Dear Drasko DRASKOVIC,
In message 5ec3d7930907130700h24ab20c3t258e2c31e21bb71f@mail.gmail.com you wrote:
there is a reason why I use r10 (and why somebody used r8, I suppose) - I
Well, that's easy - as the code has to interface with GCC generated code, you have to stick with GCC's register usage conventions.
And one thing I also noted that is strange a variable of "register volatile". I played around with arm gcc compiler - does this volatile stuff really have some effect? Compiler seems to produce asm code like it is not volatile (optimize by deleting conditions, assign values by add and not mov, etc...)
"register volatile" makes sense only for the special case of global or local register variables. Whether or not it is implemented in a specific version of GCC for a specific architecture is another story; please ask this on the GCC mailing list.
Best regards,
Wolfgang Denk

Well, that's easy - as the code has to interface with GCC generated code, you have to stick with GCC's register usage conventions.
I think we were refering here to ATPCS (ARM-THUMB Procedure Call Standard, i.e. ARM ABI), which tells that first 4 args of the calee are passed by the caller via r0-r3, and if calee takes more args, the rest is passed via stack. IMHO, GCC conventions has not much to do with this. I used r10 because there is small probability that it will be clobbered in start.S.
"register volatile" makes sense only for the special case of global
or local register variables. Whether or not it is implemented in a specific version of GCC for a specific architecture is another story; please ask this on the GCC mailing list.
OK. But since it was implemented in U-Boot and for ARM, I thought that anybody who wrote this will be so kind to shread some light on this (I am guessing that that it has something to do with ISR, but in ISR we seem to preserve r8), and also on the membar two lines below, and spare me from subscribing to a huge volume gcc mailing lists for posting just one question. This rests for me one of the most obscure corners of U-Boot.
Best regards, Drasko DRASKOVIC

Dear Drasko DRASKOVIC,
In message 5ec3d7930907130900l7e043b11lcf37a0d3e161f511@mail.gmail.com you wrote:
Well, that's easy - as the code has to interface with GCC generated code, you have to stick with GCC's register usage conventions.
I think we were refering here to ATPCS (ARM-THUMB Procedure Call Standard, i.e. ARM ABI), which tells that first 4 args of the calee are passed by the caller via r0-r3, and if calee takes more args, the rest is passed via stack. IMHO, GCC conventions has not much to do with this. I used r10 because there is small probability that it will be clobbered in start.S.
When I wrote "GCC's register usage conventions" I usually mean exactly that and not some completely different thing.
You also might want to read the README. Search for "On ARM, the following registers are used"...
"register volatile" makes sense only for the special case of global
or local register variables. Whether or not it is implemented in a specific version of GCC for a specific architecture is another story; please ask this on the GCC mailing list.
OK. But since it was implemented in U-Boot and for ARM, I thought that anybody who wrote this will be so kind to shread some light on this (I am guessing that that it has something to do with ISR, but in ISR we seem to
This has nothing to do with ISRs at all. What makes you think so?
preserve r8), and also on the membar two lines below, and spare me from subscribing to a huge volume gcc mailing lists for posting just one question. This rests for me one of the most obscure corners of U-Boot.
The GCC mailing list is where GCC experts can answer your questions. I'm not a GCC expert - just a happy user since version 1.35 or so...
--00151748e7286f26c8046e986b49 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
And please don't post HTML.
Best regards,
Wolfgang Denk

Dear Wolfgang Denk.
On Mon, Jul 13, 2009 at 9:34 PM, Wolfgang Denk wd@denx.de wrote: When I wrote "GCC's register usage conventions" I usually mean exactly that and not some completely different thing.
You also might want to read the README. Search for "On ARM, the following registers are used"...
On a first glance README actually tells that U-Boot will respect ATCPS (whith exception of r8, which it will reserve). So, actually, it can be that we were talking about the same thing, just that I used term ATPCS to underline that it is ARM (and not U-Boot or GCC) specific. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0042c/index.h... (http://www.nabble.com/Register-Usage-td23279910.html)
In any case, my code is working fine with r10 choice, which comes from the reasons I elaborated before (although maybe r10 would not be the happiest choice, but some of the regs r4-r9, r8 excluded).
This has nothing to do with ISRs at all. What makes you think so?
This, for example: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=64... And this: http://www.nabble.com/bug-or-feature--CSE-optimizes-away-global,-fixed-regis...
This gave me a hint that people using "volatile register" vars mostly in these cases. And I was thinking myself: why claiming our local reg as volatile? Who can change it appart from us, if not some other thread (written in assembly most probably, because if it was a C call then GCC would introduce prologue and epilogue to preserve register that are guaranteed to be non clobbered by ATCPS). So what other thread do we have in non-multithreaded U-Boot? So, I grepped to see who the hell is touching r8, and all I could find was (in cpu/armXXX/start.S) : .macro irq_save_user_regs sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ Calling r0-r12 @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good. add r8, sp, #S_PC stmdb r8, {sp, lr}^ @ Calling SP, LR str lr, [r8, #0] @ Save calling PC mrs r6, spsr str r6, [r8, #4] @ Save CPSR str r0, [r8, #8] @ Save OLD_R0 mov r0, sp .endm chunk of code in ISR.
So, my suspicions comes from there.
The GCC mailing list is where GCC experts can answer your questions. I'm not a GCC expert - just a happy user since version 1.35 or so...
Thanks, I will investigate this interesting topic further and post on this thread if I come with reasonable solution. As I mentioned, my gcc was not working as I expected with "register volatile", as it was doing some optimization exibitions rather than plain register read/mov.
Some questions are also worth mentioning:
/* Pointer is writable since we allocated a register for it */ gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
Would not it be writable even if we did not allocated reg for it? We could have declared it as a global var without asm("r8") stuff and compiler would have put it on the stack - but I guess it would be writable.
And then: /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory");
Why is order of ams instructions important here? (I did not had time yet to recompile without this membar before posting this question, so I will try to do it and reproduce the problem).
Best regards, Drasko DRASKOVIC
participants (3)
-
Drasko DRASKOVIC
-
Rabin Vincent
-
Wolfgang Denk