[SeaBIOS] Problems with Linux payload

Laszlo Ersek lersek at redhat.com
Thu Aug 28 01:12:48 CEST 2014


On 08/27/14 23:17, Curt Brune wrote:
> Hello Kevin -
> 
> On Mon Aug 18 14:56, Kevin O'Connor wrote:
>> Unfortunately, I don't see anything in the log that looks suspicious.
>> Since you are using qemu/kvm, you could try attaching a debugger (if
>> you are familiar with gdb).
>>
>> There's documentation online and in the SeaBIOS' README file.  In a
>> nutshell, run qemu with "-s -S" and then run "gdb" in another terminal
>> and send it "target remote localhost:1234" along with something like
>> "br *0x40000" to set a break point at the start of the payload.
>>
>> Another option would be to try with a known working payload and verify
>> if you can get SeaBIOS to launch it.
> 
> Thanks for your time and suggestions.
> 
> As a control I tried using the libpayload example
> (http://www.coreboot.org/Libpayload) as a SeaBIOS payload and that
> worked fine.  So SeaBIOS seems fine.
> 
> I went down the gdb route and found some interesting results, but
> still not sure what is wrong.  It has been educational :)
> 
> Using gdb I worked my way through coreboot and SeaBIOS loading and
> into cbfs_run_payload().  cbfs_run_payload() loads the payload OK and
> jumps to the trampoline @ 0x40000 fine.  The trampoline does various
> things and eventually jumps to the kernel code @ 0x1000000.  In gdb
> this looks like:
> 
>    => 0x1000000:   cld    
>       0x1000001:   test   BYTE PTR [esi+0x211],0x40
>       0x1000008:   jne    0x1000016
>       0x100000a:   cli    
>       0x100000b:   mov    eax,0x18
>       0x1000010:   mov    ds,eax
>       0x1000012:   mov    es,eax
>       0x1000014:   mov    ss,eax           <--- CPU resets executing this
>       0x1000016:   lea    esp,[esi+0x1e8]
>       0x100001c:   call   0x1000021
> 
> The source code for this location comes from the kernel file
> linux/arch/x86/boot/compressed/head_64.S
> 
> I found executing the "mov ss,eax" instruction @ 0x1000014 would cause
> the virtual machine to reboot.  I presume some kind of stack/memory
> exception happened and the exception handler resets the CPU.
> 
> Just before executing that instruction the CPU registers look like
> this (from the qemu monitor):
> 
>   (qemu) info registers
>   EAX=00000018 EBX=1ffd6610 ECX=00000000 EDX=00000000
>   ESI=00090000 EDI=00090334 EBP=00040070 ESP=00006fa4
>   EIP=01000014 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
>   ES =0018 000f0000 0000ffff 00009b00 DPL=0 CS16 [-RA]
>   CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
>   SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
>   DS =0018 000f0000 0000ffff 00009b00 DPL=0 CS16 [-RA]
>   FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
>   GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
>   LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
>   TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
>   GDT=     000f4b78 00000037
>   IDT=     000f4bb6 00000000
>   CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
>   DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
>   DR6=00000000ffff0ff0 DR7=0000000000000400
>   EFER=0000000000000000
>   FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
> 
> So setting SS from 0x10 to 0x18 caused the exception.  Of note the DS
> and ES registers were set from 0x10 to 0x18 without any problem.
> 
> Now armed with qemu/gdb knowledge I went through my working case,
> where my kernel is loaded directly by coreboot.  SeaBIOS is not used
> in this case.  My kernel boots fine in this case.
> 
> Just before executing the troublesome instruction @ 0x1000014 the CPU
> registers look like this (from the qemu monitor) in the working case:
> 
>   (qemu) info registers
>   EAX=00000018 EBX=1ffd6610 ECX=00000000 EDX=00000000
>   ESI=00090000 EDI=00090334 EBP=00127ff0 ESP=1ffd0f88
>   EIP=01000014 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
>   ES =0018 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
>   CS =0010 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
>   SS =0018 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
>   DS =0018 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
>   FS =0018 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
>   GS =0018 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
>   LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
>   TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
>   GDT=     1ffec000 00000047
>   IDT=     001218c4 0000009f
>   CR0=60000011 CR2=00000000 CR3=00000000 CR4=00000000
>   DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
>   DR6=00000000ffff0ff0 DR7=0000000000000400
>   EFER=0000000000000000
>   FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
> 
> Here the interesting thing is that DS, ES and SS *already* contained
> 0x18.  In the SeaBIOS case those registers contained 0x10 before the
> Linux kernel set them up.
> 
> That's all I got.  Any clues?

I'll probably make a clown out of myself, but I'll just blurt out that
the direct value of SS (0x18) is quite meaningless, it's just a segment
*selector* value. What is interesting is the contents of the GDT entry,
at byte offset 0x18 (which corresponds to the fourth GDT entry).

In your first register dump, you have

GDT=     000f4b78 00000037

in the 2nd register dump, you have

GDT=     1ffec000 00000047

The second value in each case means the maximum (inclusive) byte offset
in the GDT, so 0x18 itself should be okay in both cases.

Can you hex-dump the guest memory too, in both cases, starting from
0xf4b78+0x18, and from 0x1ffec000+0x18, respectively, for 0x8 bytes?
This would provide the segment descriptor in each case that the selector
value 0x18 references.

In the resetting case, the segment descriptor referenced by selector
value 0x18 is probably suitable for data segments, but inappropriate for
the stack segment.

Thanks
Laszlo
/ducks




More information about the SeaBIOS mailing list