Short summary for Gleb and Paolo:
- qemu master + kvm_intel (3.10) run both OVMF/master and
OVMF/master+SeaBIOS/master CSM well, including booting a legacy OS
- qemu master + TCG spirals into an endless loop when trying to boot a
legacy OS with OVMF+CSM -- I'm not focusing on this right now,
- qemu master + kvm_amd (3.10) throws an emulation failure with pure
OVMF immediately at startup:
On 09/03/13 11:56, Laszlo Ersek wrote:
> On 09/03/13 01:05, Rod Smith wrote:
>> On 09/02/2013 05:32 PM, Laszlo Ersek wrote:
>
>>> Maybe -enable-kvm would make a difference...
>>
>> It causes it to crash with a new set of error messages:
>>
>> KVM internal error. Suberror: 1
>> emulation failure
>> EAX=c0000033 EBX=fffcc0e4 ECX=c0000080 EDX=00000000
>> ESI=fffcc2c4 EDI=00005042 EBP=fffcc000 ESP=00000000
>> EIP=ffffff26 EFL=00000082 [--S----] CPL=0 II=0 A20=1 SMM=0 HLT=0
>> ES =0008 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
>> CS =0010 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
>> SS =0008 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
>> DS =0008 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
>> FS =0008 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
>> GS =0008 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
>> LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
>> TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS64-busy
>> GDT= 00000000ffffff80 0000001f
>> IDT= 0000000000000000 0000ffff
>> CR0=c0000033 CR2=0000000000000000 CR3=00000000ffffe000 CR4=00000660
>> DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000
>> DR3=0000000000000000
>> DR6=00000000ffff0ff0 DR7=0000000000000400
>> EFER=0000000000000500
>> Code=00 c0 0f 32 0f ba e8 08 0f 30 0f 20 c0 0f ba e8 1f 0f 22 c0 <ea>
>> 2d ff ff ff 18 00 e9 93 00 00 00 fa bb 00 f0 8e db bb 6c ff 2e 66 0f
>> 01 17 66 b8 23 00
>> Connected to RFB server, using protocol version 3.8
>>
>> the kvm and kvm_amd modules are loaded on my system when this
>> happens.
In the qemu monitor:
(qemu) x /20i 0xffffffefd
0x0000000ffffffefd: mov $0xffffe000,%eax
0x0000000fffffff02: mov %eax,%cr3
0x0000000fffffff05: mov %cr4,%eax
0x0000000fffffff08: bts $0x5,%eax
0x0000000fffffff0c: mov %eax,%cr4
0x0000000fffffff0f: mov $0xc0000080,%ecx
0x0000000fffffff14: rdmsr
0x0000000fffffff16: bts $0x8,%eax
0x0000000fffffff1a: wrmsr
0x0000000fffffff1c: mov %cr0,%eax
0x0000000fffffff1f: bts $0x1f,%eax
0x0000000fffffff23: mov %eax,%cr0
0x0000000fffffff26: ljmp $0x18,$0xffffff2d <------ emul. failure here
0x0000000fffffff2d: jmp 0xffffffc5
This guest disassembly is part of the UEFI reset vector code under
UefiCpuPkg/ResetVector/Vtf0.
Main16 [Main.asm]
EarlyInit16 [Ia16/Init16.asm]
TransitionFromReal16To32BitFlat [Ia16/Real16ToFlat32.asm]
Flat32SearchForBfvBase [Ia32/SearchForBfvBase.asm]
Flat32SearchForSecEntryPoint [Ia32/SearchForSecEntry.asm]
Transition32FlatTo64Flat [Ia32/Flat32ToFlat64.asm]
The Transition32FlatTo64Flat "function" has the following source,
corresponding to the qemu disassembly:
> BITS 32
>
> ;
> ; Modified: EAX
> ;
> Transition32FlatTo64Flat:
>
> mov eax, ((ADDR_OF_START_OF_RESET_CODE & ~0xfff) - 0x1000)
> mov cr3, eax
0x0000000ffffffefd: mov $0xffffe000,%eax
0x0000000fffffff02: mov %eax,%cr3
>
> mov eax, cr4
> bts eax, 5 ; enable PAE
> mov cr4, eax
0x0000000fffffff05: mov %cr4,%eax
0x0000000fffffff08: bts $0x5,%eax
0x0000000fffffff0c: mov %eax,%cr4
>
> mov ecx, 0xc0000080
> rdmsr
> bts eax, 8 ; set LME
> wrmsr
0x0000000fffffff0f: mov $0xc0000080,%ecx
0x0000000fffffff14: rdmsr
0x0000000fffffff16: bts $0x8,%eax
0x0000000fffffff1a: wrmsr
>
> mov eax, cr0
> bts eax, 31 ; set PG
> mov cr0, eax ; enable paging
0x0000000fffffff1c: mov %cr0,%eax
0x0000000fffffff1f: bts $0x1f,%eax
0x0000000fffffff23: mov %eax,%cr0
>
> jmp LINEAR_CODE64_SEL:ADDR_OF(jumpTo64BitAndLandHere)
0x0000000fffffff26: ljmp $0x18,$0xffffff2d <------ emul. failure here
> BITS 64
> jumpTo64BitAndLandHere:
>
> debugShowPostCode POSTCODE_64BIT_MODE
>
> OneTimeCallRet Transition32FlatTo64Flat
0x0000000fffffff2d: jmp 0xffffffc5
"LINEAR_CODE64_SEL" is defined in "Ia16/Real16ToFlat32.asm" as:
> ;
> ; The Global Descriptor Table (GDT)
> ;
>
> GDT_BASE:
> ; null descriptor
> [...]
>
> ; linear data segment descriptor
> LINEAR_SEL equ $-GDT_BASE
> [...]
>
> ; linear code segment descriptor
> LINEAR_CODE_SEL equ $-GDT_BASE
> [...]
>
> %ifdef ARCH_X64
> ; linear code (64-bit) segment descriptor
> LINEAR_CODE64_SEL equ $-GDT_BASE
> DW 0xffff ; limit 15:0
> DW 0 ; base 15:0
> DB 0 ; base 23:16
> DB PRESENT_FLAG(1)|DPL(0)|SYSTEM_FLAG(1)|DESC_TYPE(CODE64_TYPE)
> DB
> GRANULARITY_FLAG(1)|DEFAULT_SIZE32(0)|CODE64_FLAG(1)|UPPER_LIMIT(0xf)
> DB 0 ; base 31:24
> %endif
>
> GDT_END:
>
I grepped the 3.10 kernel for KVM_INTERNAL_ERROR_EMULATION:
arch/x86/kvm/svm.c: svm->vcpu.run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
arch/x86/kvm/vmx.c: vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
arch/x86/kvm/vmx.c: vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
arch/x86/kvm/x86.c: vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
include/uapi/linux/kvm.h:#define KVM_INTERNAL_ERROR_EMULATION 1
"x86.c" would be my first guess (after x86_decode_insn() or
x86_emulate_insn() fails), but that's probably not it, considering that
the code runs fine on VMX and fails on SVM, and "x86.c" looks like a
shared file.
This is what trace-cmd has to say:
qemu-system-x86-29149 [002] 12270.789910: kvm_update_master_clock: masterclock
0 hostclock tsc offsetmatched 0
qemu-system-x86-29149 [002] 12270.789977: kvm_fpu: load
qemu-system-x86-29149 [002] 12270.789979: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.789987: kvm_exit: reason EXIT_NPF
rip 0xfff0 info 100000014 fffffff0
qemu-system-x86-29149 [002] 12270.789992: kvm_page_fault: address
fffffff0 error_code 14
qemu-system-x86-29149 [002] 12270.790022: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.790025: kvm_exit: reason
EXIT_WRITE_CR0 rip 0xff46 info 0 0
qemu-system-x86-29149 [002] 12270.790042: kvm_emulate_insn: ffff0000:ff46:
0f 22 c0
qemu-system-x86-29149 [002] 12270.790060: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.790063: kvm_exit: reason
EXIT_WRITE_CR4 rip 0xffffff56 info 0 0
qemu-system-x86-29149 [002] 12270.790065: kvm_emulate_insn: 0:ffffff56: 0f
22 e0
qemu-system-x86-29149 [002] 12270.790069: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.790076: kvm_exit: reason
EXIT_READ_CR4 rip 0xffffff05 info 0 0
qemu-system-x86-29149 [002] 12270.790079: kvm_emulate_insn: 0:ffffff05: 0f
20 e0
qemu-system-x86-29149 [002] 12270.790082: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.790084: kvm_exit: reason
EXIT_WRITE_CR4 rip 0xffffff0c info 0 0
qemu-system-x86-29149 [002] 12270.790086: kvm_emulate_insn: 0:ffffff0c: 0f
22 e0
qemu-system-x86-29149 [002] 12270.790092: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.790095: kvm_exit: reason EXIT_MSR
rip 0xffffff14 info 0 0
qemu-system-x86-29149 [002] 12270.790097: kvm_msr: msr_read
c0000080 = 0x0
qemu-system-x86-29149 [002] 12270.790098: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.790100: kvm_exit: reason EXIT_MSR
rip 0xffffff1a info 1 0
qemu-system-x86-29149 [002] 12270.790102: kvm_msr: msr_write
c0000080 = 0x100
qemu-system-x86-29149 [002] 12270.790103: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.790105: kvm_exit: reason
EXIT_READ_CR0 rip 0xffffff1c info 0 0
qemu-system-x86-29149 [002] 12270.790108: kvm_emulate_insn: 0:ffffff1c: 0f
20 c0
qemu-system-x86-29149 [002] 12270.790109: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.790112: kvm_exit: reason
EXIT_WRITE_CR0 rip 0xffffff23 info 0 0
qemu-system-x86-29149 [002] 12270.790113: kvm_emulate_insn: 0:ffffff23: 0f
22 c0
qemu-system-x86-29149 [002] 12270.790121: kvm_entry: vcpu 0
qemu-system-x86-29149 [002] 12270.790124: kvm_exit: reason EXIT_NPF
rip 0xffffff26 info 200000007 ffffe000
qemu-system-x86-29149 [002] 12270.790125: kvm_page_fault: address
ffffe000 error_code 7
qemu-system-x86-29149 [002] 12270.790129: kvm_emulate_insn: 0:ffffff26: 0f
22 c0
qemu-system-x86-29149 [002] 12270.790131: kvm_emulate_insn: 0:ffffff26: 0f
22 c0 FAIL
qemu-system-x86-29149 [002] 12270.790134: kvm_userspace_exit: reason
KVM_EXIT_INTERNAL_ERROR (17)
qemu-system-x86-29149 [002] 12270.790137: kvm_fpu: unload
After all this does implicate x86_decode_insn():
x86_emulate_instruction() [arch/x86/kvm/x86.c]
x86_decode_insn() [arch/x86/kvm/emulate.c]
trace_kvm_emulate_insn_start()
handle_emulation_failure() [arch/x86/kvm/x86.c]
trace_kvm_emulate_insn_failed
sets KVM_INTERNAL_ERROR_EMULATION
Interestingly, the trace lists "0f 22 c0", which corresponds to
mov %eax,%cr0
(see near "enable paging" above). So I'm not sure if the "ljmp" fails,
or the mov-to-cr0.
Volume 2 of the Intel SDM says under "MOV -- Move to/from Control
Registers" (we're in 32-bit mode, executing Transition32FlatTo64Flat):
Opcode Instruction Op/En 64-Bit Mode Compat/Leg Mode Description
-------- ------------ ----- ----------- --------------- -----------
0F 22 /r MOV CR0-CR7, A Not Valid Move r32 to
r32 Encodable control register
A reference is made to Volume 3, Chapter 22.4, "CHANGES TO INSTRUCTION
BEHAVIOR IN VMX NON-ROOT OPERATION"... which reads:
MOV to CR0. An execution of MOV to CR0 that does not cause a VM exit
(see Section 22.1.3) leaves unmodified any bit in CR0 corresponding to
a bit set in the CR0 guest/host mask. Treatment of attempts to modify
other bits in CR0 depends on the setting of the unrestricted guest
VM-execution control: ^1
- If the control is 0, MOV to CR0 causes a general-protection
exception if it attempts to set any bit in CR0 to a value not
supported in VMX operation (see Section 20.8).
- If the control is 1, MOV to CR0 causes a general-protection
exception if it attempts to set any bit in CR0 other than bit 0 (PE)
or bit 31 (PG) to a value not supported in VMX operation. It remains
the case, however, that MOV to CR0 causes a general-protection
exception if it would result in CR0.PE = 0 and CR0.PG = 1 or if it
would result in CR0.PG = 1, CR4.PAE = 0, and IA32_EFER.LME = 1.
Ugh, thanks anyway...
So, what's going on here? Perhaps, does this mov-to-cr0 *not* exit on
Intel, but unexpectedly exits on AMD, and the instruction emulator is
not prepared to handle it?
In x86_decode_insn():
/* Opcode byte(s). */
opcode = opcode_table[ctxt->b];
/* Two-byte opcode? */
if (ctxt->b == 0x0f) {
ctxt->twobyte = 1;
ctxt->b = insn_fetch(u8, ctxt);
opcode = twobyte_table[ctxt->b];
}
ctxt->d = opcode.flags;
twobyte_table[0x22] is
IIP(ModRM | SrcMem | Priv | Op3264, em_cr_write, cr_write,
check_cr_write),
which at least appears to match mov-to-cr0.
I guess Rod is the first user who tried OVMF on SVM...
Thanks
Laszlo
------------------------------------------------------------------------------
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel