[LinuxBIOS] v3: an interesting problem with initram
c-d.hailfinger.devel.2006 at gmx.net
Mon Nov 26 19:12:20 CET 2007
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);
--- LinuxBIOSv3-testnewshared/mainboard/emulation/qemu-x86/initram.c (Revision 518)
+++ LinuxBIOSv3-testnewshared/mainboard/emulation/qemu-x86/initram.c (Arbeitskopie)
@@ -20,10 +20,24 @@
+/* printktest1() is here to increase the likelihood of main() not ending up at
+ * the beginning of the file obtained with "objcopy -O binary".
+ 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;
printk(BIOS_INFO, "RAM init code started.\n");
printk(BIOS_INFO, "Nothing to do.\n");
> 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 \
- $(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.
More information about the coreboot