Initram is being set up as follows: 08048074 T spd_read_byte 080480e0 T main 08048145 T __i686.get_pc_thunk.bx 0804814c t helper_calc 08048199 T hcf 080481bd T banner 080481f6 t helper_spd 08048248 t auto_size_dimm 08048451 T sdram_set_spd_registers 08048a32 T sdram_set_registers 08048a89 T sdram_enable 08048c4c T system_preinit 08048c55 T geode_link_speed 08048c80 T pll_reset 08048d4c T pci_speed 08048d62 T cpu_speed 08048d8c T cpu_reg_init 08049000 r spdbytes 08049222 r num_col_addr 08049232 r CASDDR 0804923a r REFRESH_RATE 080492e0 r msr_table 08049320 r delay_control_table 080493c0 d _GLOBAL_OFFSET_TABLE_ 080493cc D post_code 080493d0 D printk 080493d4 A __bss_start 080493d4 A _edata 080493d4 A _end
note that spd_read_byte is first. And it's entered first and that's bad, as main is supposed to be entered. I tried the simple thing of reordering the functions in the file, and that did not do it.
So, why is spd_read_byte first in the file, and how do we fix it? Because the call from the rom code is going to spd_read_byte, not main, and I'm stuck :-)
but wow, it's close!
ron
On 26.11.2007 08:24, ron minnich wrote:
Initram is being set up as follows: 08048074 T spd_read_byte 080480e0 T main 08048145 T __i686.get_pc_thunk.bx [...]
note that spd_read_byte is first. And it's entered first and that's bad, as main is supposed to be entered. I tried the simple thing of reordering the functions in the file, and that did not do it.
Try this in combination with having main first in the file:
--- Rules.make (Revision 518) +++ Rules.make (Arbeitskopie) @@ -81,10 +81,11 @@ # # RAM initialization code can not be linked at a specific address, # hence it has to be executed in place position independently. +# -fno-toplevel-reorder is here to work around a linker bug. #
$(obj)/%_xip.o: $(src)/%.c $(Q)mkdir -p $(dir $@) $(Q)printf " CC $(subst $(shell pwd)/,,$(@)) (XIP)\n" - $(Q)$(CC) $(INITCFLAGS) -D_SHARED -fPIE -c $< -o $@ + $(Q)$(CC) $(INITCFLAGS) -fno-toplevel-reorder -save-temps -D_SHARED -fPIE -c $< -o $@
While the problem we see is not a gcc bug, this can help to workaround the bug partially.
So, why is spd_read_byte first in the file, and how do we fix it? Because the call from the rom code is going to spd_read_byte, not main, and I'm stuck :-)
Linking build/linuxbios.initram.o gives us code which is still correct and contains all necessary sections and has the right entry point. Then we invoke objcopy -O binary build/linuxbios.initram.o build/linuxbios.initram and that objcopy leaves us with a binary object. Where exactly in that binary object do we store the entry point? Exactly. Nowhere. So LAR has no place to get the entry point. However, lib/lar.c also does not care about the entry point for execution at all if you call run_file() or execute_in_place(), it simply starts execution at the beginning of the LAR member. That works as long as main() happens to be exactly at the start of the binary object. Badbadbad.
This patch should clarify what happens.
Index: lib/lar.c =================================================================== --- lib/lar.c (Revision 518) +++ lib/lar.c (Arbeitskopie) @@ -232,6 +232,8 @@ * Given a file name in the LAR , search for it, and load it into memory, * using the passed-in pointer as the address; jump to the file. * If the passed-in pointer is (void *)-1, then execute the file in place. + * BIG FAT WARNING: run_file uses the beginning of the file as entry point + * and does NOT care about the entry member of the LAR header! * @param archive A descriptor for current archive. * @param filename filename to find * @param where pointer to where to load the data @@ -265,7 +267,7 @@ } where = result.start; } - printk(BIOS_SPEW, "where is %p\n", where); + printk(BIOS_SPEW, "where is %p, not honoring entry point specified in archive\n", where); ret = run_address(where); printk(BIOS_SPEW, "run_file returns with %d\n", ret); return ret;
We now have two choices: * make sure main() is always at the start of the binary object both for initram and stage2 or * honor the entry point specified in the LAR header.
I vote for the second choice, but that means we can't feed the lar utility binary objects anymore without additional "entry" parameters.
Regards, Carl-Daniel
On 26.11.2007 15:24, Carl-Daniel Hailfinger wrote:
On 26.11.2007 08:24, ron minnich wrote:
Initram is being set up as follows: 08048074 T spd_read_byte 080480e0 T main 08048145 T __i686.get_pc_thunk.bx [...]
note that spd_read_byte is first. And it's entered first and that's bad, as main is supposed to be entered. I tried the simple thing of reordering the functions in the file, and that did not do it. [...]
So, why is spd_read_byte first in the file, and how do we fix it? Because the call from the rom code is going to spd_read_byte, not main, and I'm stuck :-)
Linking build/linuxbios.initram.o gives us code which is still correct and contains all necessary sections and has the right entry point. Then we invoke objcopy -O binary build/linuxbios.initram.o build/linuxbios.initram and that objcopy leaves us with a binary object. Where exactly in that binary object do we store the entry point? Exactly. Nowhere. So LAR has no place to get the entry point. However, lib/lar.c also does not care about the entry point for execution at all if you call run_file() or execute_in_place(), it simply starts execution at the beginning of the LAR member. That works as long as main() happens to be exactly at the start of the binary object. Badbadbad.
Try this patch for better debugging and try it with the qemu target:
--- LinuxBIOSv3-testnewshared/lib/lar.c (Revision 518) +++ LinuxBIOSv3-testnewshared/lib/lar.c (Arbeitskopie) @@ -232,6 +232,8 @@ * Given a file name in the LAR , search for it, and load it into memory, * using the passed-in pointer as the address; jump to the file. * If the passed-in pointer is (void *)-1, then execute the file in place. + * BIG FAT WARNING: run_file uses the beginning of the file as entry point + * and does NOT care about the entry member of the LAR header! * @param archive A descriptor for current archive. * @param filename filename to find * @param where pointer to where to load the data @@ -265,7 +267,7 @@ } where = result.start; } - printk(BIOS_SPEW, "where is %p\n", where); + printk(BIOS_SPEW, "where is %p, not honoring entry point specified in archive\n", where); ret = run_address(where); printk(BIOS_SPEW, "run_file returns with %d\n", ret); return ret; --- LinuxBIOSv3-testnewshared/mainboard/emulation/qemu-x86/initram.c (Revision 518) +++ LinuxBIOSv3-testnewshared/mainboard/emulation/qemu-x86/initram.c (Arbeitskopie) @@ -20,10 +20,24 @@ #define _MAINOBJECT #include <console.h>
+/* printktest1() is here to increase the likelihood of main() not ending up at + * the beginning of the file obtained with "objcopy -O binary". + * + */ +int printktest1(void) +{ + printk(BIOS_INFO, "printktest1: If the immediately preceding line does" + " not say "Nothing to do.", then execution did not start at" + " main()\n"); + + return 0; +} + int main(void) { printk(BIOS_INFO, "RAM init code started.\n"); printk(BIOS_INFO, "Nothing to do.\n"); + printktest1();
return 0; }
We now have two choices:
- make sure main() is always at the start of the binary object both for
initram and stage2 or
- honor the entry point specified in the LAR header.
I vote for the second choice, but that means we can't feed the lar utility binary objects anymore without additional "entry" parameters.
Here is a patch to calculate the entry offset for the qemu initram target:
--- LinuxBIOSv3-testnewshared/mainboard/emulation/qemu-x86/Makefile (Revision 518) +++ LinuxBIOSv3-testnewshared/mainboard/emulation/qemu-x86/Makefile (Arbeitskopie) @@ -44,12 +44,19 @@
$(obj)/linuxbios.initram $(obj)/linuxbios.initram.map: $(obj)/stage0.init $(obj)/stage0-prefixed.o $(patsubst %.o,%_xip.o,$(INITRAM_OBJ)) $(Q)# initram links against stage0 - $(Q)printf " LD $(subst $(shell pwd)/,,$(@))\n" + $(Q)printf " LD $(subst $(shell pwd)/,,$(@)).o\n" $(Q)$(LD) --entry main -N -R $(obj)/stage0-prefixed.o \ $(patsubst %.o,%_xip.o,$(INITRAM_OBJ)) -o $(obj)/linuxbios.initram.o + $(Q)# calculate the offset of the entry point + $(Q)printf " CALCUL $(subst $(shell pwd)/,,$(@)).entryoffset\n" + $(Q)echo -e "ibase=16\n"\ + `objdump -f $(obj)/linuxbios.initram.o|grep "start address"|sed "s/.*0x//"|tr "[[:lower:]]" "[[:upper:]]"`\ + -\ + `objdump -t $(obj)/linuxbios.initram.o|grep '.text.*.text$$'|cut -f 1 -d" "|tr "[[:lower:]]" "[[:upper:]]"`\ + |bc > $(obj)/linuxbios.initram.entryoffset $(Q)printf " OBJCOPY $(subst $(shell pwd)/,,$(@))\n" $(Q)$(OBJCOPY) -O binary $(obj)/linuxbios.initram.o \ $(obj)/linuxbios.initram - $(Q)printf " NM $(subst $(shell pwd)/,,$(@))\n" + $(Q)printf " NM $(subst $(shell pwd)/,,$(@)).o\n" $(Q)$(NM) $(obj)/linuxbios.initram.o | sort -u > $(obj)/linuxbios.initram.map
I suggest to populate the ->entry member of the lar header for XIP files with the entry offset from start of file, not with an absolute address because XIP code has relative jumps in the first place.
Regards, Carl-Daniel
Hi carl-daniel, please see my other messages. I would prefer to have lar parse the elf for the initram, as it is doing for the payload, and in fact i'd like to get rid of binary blobs altogether. can you look at my proposed modifications and see what you think? Unfortunately they do replace the mods you are proposing in this message.
"I vote for the second choice, but that means we can't feed the lar utility binary objects anymore without additional "entry" parameters."
Exactly. Let's get rid of binary objects.
I just read your second message on this subject, I am not really comfortable with this type of complexity in a makefile: `objdump -f $(obj)/linuxbios.initram.o|grep "start address"|sed "s/.*0x//"|tr "[[:lower:]]" "[[:upper:]]"`
Let's just do the right thing and parse the elf of initram.o. It works. I had to make *0* changes to the lar create -- just hand it the initram.o, and it all just worked! the first test of the change involved adding just a few characters in the makefile!
thanks
ron