[coreboot] Disassembly of coreboot binaries
Aaron Durbin
adurbin at google.com
Mon Dec 19 19:10:19 CET 2016
On Mon, Dec 19, 2016 at 11:18 AM, Chauhan, Himanshu
<hschauhan at nulltrace.org> wrote:
> On Mon, Dec 19, 2016 at 10:03 PM, Aaron Durbin <adurbin at google.com> wrote:
>> On Mon, Dec 19, 2016 at 9:55 AM, Chauhan, Himanshu
>> <hschauhan at nulltrace.org> wrote:
>>> On Mon, Dec 19, 2016 at 9:09 PM, Aaron Durbin <adurbin at google.com> wrote:
>>>> On Sun, Dec 18, 2016 at 11:04 PM, Chauhan, Himanshu
>>>> <hschauhan at nulltrace.org> wrote:
>>>>> On Mon, Dec 19, 2016 at 12:40 AM, Aaron Durbin <adurbin at google.com> wrote:
>>>>>> On Sun, Dec 18, 2016 at 9:37 AM, Chauhan, Himanshu
>>>>>> <hschauhan at nulltrace.org> wrote:
>>>>>>> Hi Aaron,
>>>>>>>
>>>>>>> I figured out the crash. It wan't because wrong load of the ROM image
>>>>>>> (thanks to the nifty post_code which I could trap on IO). I see that
>>>>>>> the page fault I am getting is in following code:
>>>>>>> (gdb) list *(((0xfff81e41 - 0xfff80000)-200)+0x2000000)
>>>>>>
>>>>>> I'm curious about the 200 and 16MiB offset being applied.
>>>>>
>>>>> 0x2000000 is the new address where romstage is linked. Earlier
>>>>> (atleast in 2014) the linked address used to be 0xfff80000. This is
>>>>> the same address (guest physical) where I map the ROM code. In the
>>>>> above calculation I am taking the offset from 0xfff80000 and adding to
>>>>> the link address of romstage (0x2000000). The 0x200 is the difference
>>>>> I see to map the addresses correctly. This calculation seems fine to
>>>>> me because with this I am able to pin point all the earlier faults and
>>>>> the post_code trap rIP.
>>>>>
>>>>
>>>> If you provide 'cbfstool print -k' output, I could most likely provide
>>>> the exact offset mapping. Alternatively you could extract the
>>>> romstage.elf from the image using 'cbfstool extract -m x86', but it
>>>> won't have debug info. But it'd provide the information to compare
>>>> against the pre-relocated image for the correct mapping.
>>>>
>>> How exactly to run it? It says unknown option -k (cbfstool in build directory).
>>
>>
>> ./coreboot-builds/sharedutils/cbfstool/cbfstool
>> coreboot-builds/GOOGLE_REEF/coreboot.rom print -k
>>
>
> hchauhan at panini:build$ ./cbfstool coreboot.rom print -k
>
> Performing operation on 'COREBOOT' region...
>
> Name Offset Type Metadata Size Data Size Total Size
>
> cbfs master header 0x0 cbfs header 0x38 0x20 0x58
>
> fallback/romstage 0x80 stage 0x64 0x320c 0x3270
>
> fallback/ramstage 0x3300 stage 0x38 0x99d7 0x9a0f
>
> config 0xcd40 raw 0x38 0x238 0x270
>
> revision 0xcfc0 raw 0x38 0x239 0x271
>
> cmos_layout.bin 0xd240 cmos_layout 0x38 0x304 0x33c
>
> fallback/dsdt.aml 0xd580 raw 0x48 0xfb5 0xffd
>
> fallback/payload 0xe580 payload 0x38 0x6b85 0x6bbd
>
> (empty) 0x15140 null 0x28 0x6a998 0x6a9c0
>
> bootblock 0x7fb00 bootblock 0x40 0x3c0 0x400
What is CONFIG_ROM_SIZE? When I build qemu-i440fx my ROM_SIZE is 4MiB.
It seems like you are changing it from the default.
$ ./coreboot-builds/sharedutils/cbfstool/cbfstool
./coreboot-builds/EMULATION_QEMU_X86_I440FX/coreboot.rom extract -m
x86 -n fallback/romstage -f extracted_romstage.elf
$ diff -up <(readelf -h
./coreboot-builds/EMULATION_QEMU_X86_I440FX/cbfs/fallback/romstage.elf)
<(readelf -h extracted_romstage.elf )
--- /dev/fd/63 2016-12-19 11:42:16.459336682 -0600
+++ /dev/fd/62 2016-12-19 11:42:16.459336682 -0600
@@ -8,13 +8,13 @@ ELF Header:
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
- Entry point address: 0x2000020
- Start of program headers: 52 (bytes into file)
- Start of section headers: 21496 (bytes into file)
+ Entry point address: 0xfffc0220
+ Start of program headers: 252 (bytes into file)
+ Start of section headers: 52 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
- Number of section headers: 8
- Section header string table index: 5
+ Number of section headers: 5
+ Section header string table index: 1
You can perform the translation based on the difference of the entry
point offsets.
After doing that does the faulting RIP still point to imd_recover()? A
high RIP like that would indicate we're still in rosmtage. I still
don't see how we'd ever be calling into that function given Having
serial console would be extremely helpful in being able to track down
where things are falling over.
>
>
>> That's an example after me building reef with abuild. How old is your
>> coreboot checkout?
>>
> Pulled just a few days back.
>
>>>
>>>>>>
>>>>>>> 0x2001d79 is in imd_recover (src/lib/imd.c:139).
>>>>>>> 134
>>>>>>> 135 static void imdr_init(struct imdr *ir, void *upper_limit)
>>>>>>> 136 {
>>>>>>> 137 uintptr_t limit = (uintptr_t)upper_limit;
>>>>>>> 138 /* Upper limit is aligned down to 4KiB */
>>>>>>> 139 ir->limit = ALIGN_DOWN(limit, LIMIT_ALIGN);
>>>>>>> 140 ir->r = NULL;
>>>>>>> 141 }
>>>>>>> 142
>>>>>>> 143 static int imdr_create_empty(struct imdr *imdr, size_t root_size,
>>>>>>>
>>>>>>> I see that this function is being called multiple times (I added some
>>>>>>> more post_code and see them being trapped). I get a series of page
>>>>>>> faults which I am able to honour all but last.
>>>>>>
>>>>>> I don't see how imdr_init would be faulting. That's just assigning
>>>>>> fields of a struct sitting on the stack. What's your stack pointer
>>>>>> value at the time of the faults?
>>>>>
>>>>> "ir" should be on stack or on top of the RAM. Right now it looks like
>>>>> its on top of the RAM. That area is not mapped initially. On a page
>>>>> fault, I map a 4K page. For the reference, the following is the
>>>>> register dump of coreboot. RSP is 0x9fe54.
>>>>>
>>>>
>>>> The values should not be striding. That object is always on the stack.
>>>> Where the stack is located could be in low or high memory. I still
>>>> need to know what platform you are targeting for the image to provide
>>>> details. However, it would not be striding.
>>>
>>> I am building this for qemu i440-fx.
>>
>> OK. What is your cmos emulation returning at addresses 0x34, 0x35,
>> 0x5d, 0x5c and 0x5b?
This question above would be helpful.
>>
>> I also don't understand why we're adding 16MiB to
>> qemu_get_memory_size() unconditionally.
>>
>>>
>>>>
>>>>> GUEST guest0/vcpu0 dump state:
>>>>>
>>>>> RAX: 0x9fe80 RBX: 0xfffff8 RCX: 0x1b RDX: 0x53a11439
>>>>> R08: 0x0 R09: 0x0 R10: 0x0 R11: 0x0
>>>>> R12: 0x0 R13: 0x0 R14: 0x0 R15: 0x0
>>>>> RSP: 0x9fe54 RBP: 0xa0000 RDI: 0xfff801e4 RSI: 0x9fe80
>>>>> RIP: 0xfff81e41
>>>>>
>>>>> CR0: 0xe0000011 CR2: 0x0 CR3: 0xa23000 CR4: 0x0
>>>>> CS : Sel: 0x00000008 Limit: 0xffffffff Base: 0x00000000 (G: 1 DB:
>>>>> 1 L: 0 AVL: 0 P: 1 DPL: 0 S: 1 Type: 11)
>>>>> DS : Sel: 0x00000010 Limit: 0xffffffff Base: 0x00000000 (G: 1 DB:
>>>>> 1 L: 0 AVL: 0 P: 1 DPL: 0 S: 1 Type: 3)
>>>>> ES : Sel: 0x00000010 Limit: 0xffffffff Base: 0x00000000 (G: 1 DB:
>>>>> 1 L: 0 AVL: 0 P: 1 DPL: 0 S: 1 Type: 3)
>>>>> SS : Sel: 0x00000010 Limit: 0xffffffff Base: 0x00000000 (G: 1 DB:
>>>>> 1 L: 0 AVL: 0 P: 1 DPL: 0 S: 1 Type: 3)
>>>>> FS : Sel: 0x00000010 Limit: 0xffffffff Base: 0x00000000 (G: 1 DB:
>>>>> 1 L: 0 AVL: 0 P: 1 DPL: 0 S: 1 Type: 3)
>>>>> GS : Sel: 0x00000010 Limit: 0xffffffff Base: 0x00000000 (G: 1 DB:
>>>>> 1 L: 0 AVL: 0 P: 1 DPL: 0 S: 1 Type: 3)
>>>>> GDT : Sel: 0x00000000 Limit: 0x0000001f Base: 0xfff80200 (G: 0 DB:
>>>>> 0 L: 0 AVL: 0 P: 0 DPL: 0 S: 0 Type: 0)
>>>>> LDT : Sel: 0x00000000 Limit: 0x0000ffff Base: 0x00000000 (G: 0 DB:
>>>>> 0 L: 0 AVL: 0 P: 0 DPL: 0 S: 0 Type: 0)
>>>>> IDT : Sel: 0x00000000 Limit: 0x00000000 Base: 0x00000000 (G: 0 DB:
>>>>> 0 L: 0 AVL: 0 P: 0 DPL: 0 S: 0 Type: 0)
>>>>> TR : Sel: 0x00000000 Limit: 0x0000ffff Base: 0x00000000 (G: 1 DB:
>>>>> 0 L: 1 AVL: 1 P: 0 DPL: 0 S: 0 Type: 0)
>>>>> RFLAGS: 0xa [ ]
>>>>>
>>>>>
>>>>>>>
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f7fffc (rIP: 00000000FFF81E41)
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f7effc (rIP: 00000000FFF81E41)
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f7dffc (rIP: 00000000FFF81E41)
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f7cffc (rIP: 00000000FFF81E41)
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f7bffc (rIP: 00000000FFF81E41)
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f7affc (rIP: 00000000FFF81E41)
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f79ffc (rIP: 00000000FFF81E41)
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f78ffc (rIP: 00000000FFF81E41)
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f77ffc (rIP: 00000000FFF81E41)
>>>>>>> (__handle_vm_exception:543) Guest fault: 0x7f76ffc (rIP: 00000000FFF81E41)
>>>>>>> <snip>
What's the full sequence of faults?
>>>>>>
>>>>>> Are those non-rIP addresses the page fault address?
>>>>>
>>>>> Guest fault: 0x7f7fffc is the address which I think is pointing to
>>>>> "ir". If you look all the faulting addresses are 4K apart which is my
>>>>> default page size for mapping all the guest pages. It also means that
>>>>> multiple times "imdr_init" is being called it faults for different
>>>>> addresses hence the same rIP.
>>>>
>>>> I just don't see how we're using that much stack. That doesn't seem
>>>> right at all.
>>>>
>>>
>>> Yes. Something is terribly wrong. I had this working back in 2014.
>>> Please take a look at this video that I created at that time.
>>> https://www.youtube.com/watch?v=jPAzzLQ0NgU
>>
>> i see you do have serial port. It'd be interesting to get full logs
>> when the thing is booting to see where it goes off the rails.
>>>
>>> I couldn't work on it for quite some time and meantime core boot
>>> changed a lot. I have one question. In earlier core boot images,
>>> romstage was linked to 0xfff80000 and now its 0x2000000. Any reason?
>>
>> It's just linked at CONFIG_ROMSTAGE_ADDR to avoid a double link step.
>> It's linked once and cbfstool relocates the image when placing it into
>> CBFS. It previously was linked at a specific address then the xip
>> address was calculated by performing a pseudo CBFS add operation. Then
>> romstage was re-linked and added to CBFS.
>>
>> The offset for address translation is the entry point differences
>> between the 2 elf files. You can extract the one in coreboot.rom to
>> get a the entry point of the romstage being ran.
>>
>>>
>>>>>
>>>>>>
>>>>>>>
>>>>>>> handle_guest_realmode_page_fault: offset: 0x3ffc fault: 0x1003ffc reg: 0x1000000
>>>>>>> handle_guest_realmode_page_fault: offset: 0x2ffc fault: 0x1002ffc reg: 0x1000000
>>>>>>> handle_guest_realmode_page_fault: offset: 0x1ffc fault: 0x1001ffc reg: 0x1000000
>>>>>>> handle_guest_realmode_page_fault: offset: 0xffc fault: 0x1000ffc reg: 0x1000000
>>>>>>
>>>>>> What is the above detailing? I'm not sure what the 'fault' value means.
>>>>>
>>>>> These are same as Guest fault above. You can disregard them.
>>>>>
>>>>>>
>>>>>>>
>>>>>>> (__handle_vm_exception:561) ERROR: No region mapped to guest physical: 0xfffffc
>>>>>>>
>>>>>>>
>>>>>>> I want to understand why imd_recover gets called multiple times
>>>>>>> starting from top of memory (128MB is what I have assigned to the
>>>>>>> guest) to 16MB last (after which I can't honour). There is something
>>>>>>> amiss in my understanding of core boot memory map.
>>>>>>>
>>>>>>> Could you please help?
>>>>>>
>>>>>> The imd library contains the implementation of cbmem. See
>>>>>> include/cbmem.h for more details, but how it works is that the
>>>>>> platform needs to supply the implementation of cbmem_top() which
>>>>>> defines the exclusive upper boundary to start growing entries downward
>>>>>> from. There is a large and small object size with large blocks being
>>>>>> 4KiB in size and small blocks being 32 byes. I don't understand why
>>>>>> the faulting addresses are offset from 128MiB by 512KiB with a 4KiB
>>>>>> stride.
>>>>>>
>>>>>> What platform are you targeting for your coreboot build? Are you
>>>>>> restarting the instruction that faults? I'm really curious about the
>>>>>> current fault patterns. It looks like things are faulting around
>>>>>> accessing the imd_root_pointer root_offset field. Are these faults
>>>>>> reads or writes? However, that's assuming cbmem_top() is returning
>>>>>> 128MiB-512KiB. However, it doesn't explain the successive strides. Do
>>>>>> you have serial port emulation to get the console messages out?
>>>>>>
>>>>>> So in your platform code ensure 2 things are happening:
>>>>>>
>>>>>> 1. cbmem_top() returns a highest address in 'ram' of the guest once
>>>>>> it's online. 128MiB if that's your expectation. The value cbmem_top()
>>>>>> returns should never change from successive calls aside from NULL
>>>>>> being returned when ram is not yet available.
>
> It will always return 0x6f8. This is decided when the guest is created.
>
That doesn't seem right. You mean that's what gets returned from cmos
before adding a 16MiB?
More information about the coreboot
mailing list