On 12/04/13 06:46, Laszlo Ersek wrote:

>>> OVMF S3 resume [...] The place where it unexpectedly reboots now is the
>>> following sequence (from
>>> MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S):
>>>
>>> ASM_GLOBAL ASM_PFX(AsmTransferControl)
>>> ASM_PFX(AsmTransferControl):
>>>     # rcx S3WakingVector    :DWORD
>>>     # rdx AcpiLowMemoryBase :DWORD
>>>     lea   _AsmTransferControl_al_0000(%rip), %eax
>>>     movq  $0x2800000000, %r8
>>>     orq   %r8, %rax
>>>     pushq %rax
>>>     shrd  $20, %ecx, %ebx
>>>     andl  $0x0f, %ecx
>>>     movw  %cx, %bx
>>>     movl  %ebx, jmp_addr(%rip)
>>>     lret                         <-------------- here
>>> _AsmTransferControl_al_0000:
>>>     .byte    0x0b8, 0x30, 0      # mov ax, 30h as selector
>>>     movl  %eax, %ds
>>>     movl  %eax, %es
>>>     movl  %eax, %fs
>>>     movl  %eax, %gs
>>>     movl  %eax, %ss
>>>     movq  %cr0, %rax
>>>     movq  %cr4, %rbx
>>>     .byte    0x66
>>>     andl  $0x7ffffffe, %eax
>>>     andb  $0xdf, %bl
>>>     movq  %rax, %cr0
>>>     .byte    0x66
>>>     movl  $0x0c0000080, %ecx
>>>     rdmsr
>>>     andb  $0xfe, %ah
>>>     wrmsr
>>>     movq  %rbx, %cr4
>>>     .byte    0x0ea              # jmp far jmp_addr
>>> jmp_addr:
>>>     .long    0
>>>
>>> The idea is to simply follow through AsmTransferControl_al_0000, but
>>> flip CS to 0x28 at that point.

[...]

>>> The GDT entry at/for 0x28 is
>>>
>>>   UINT32  LimitLow    : 16  == 0xFFFF
>>>   UINT32  BaseLow     : 16  == 0
>>>   UINT32  BaseMid     : 8   == 0
>>>   UINT32  Type        : 4   == 0xB /* = Code, Execute/Read, accessed */
>>>   UINT32  System      : 1   == 1   /* = code or data */
>>>   UINT32  Dpl         : 2   == 0
>>>   UINT32  Present     : 1   == 1
>>>   UINT32  LimitHigh   : 4   == 0xF
>>>   UINT32  Software    : 1   == 0   /* this bit is freely usable */
>>>   UINT32  Reserved    : 1   == 0   /* = exec'd in compat (32bit) mode */
>>>   UINT32  DefaultSize : 1   == 0   /* = 16-bit def. addr & op size */
>>>   UINT32  Granularity : 1   == 1   /* = limit in 4KB units */
>>>   UINT32  BaseHigh    : 8   == 0
> 
> (note: the GDT entries are in
> "UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c")

The problem is the DefaultSize flag (== 0 in the above descriptor). The
descriptor at 0x10 only differs in the DefaultSize bit (== 1 in there),
and the lret instruction works with that as expected.

When the lret is executed, the processor is still in IA-32e mode and
apparently doesn't accept a code segment where the default address and
operand size is 16-bit. We probably need to clear only the L flag at
first (64-bit code segment, called "Reserved" above), by selecting the
0x10 descriptor. Then, in 32-bit code, bring the CPU out of IA-32e (the
assembly in the rest of AsmTransferControl seems to aim at that), and
then we can probably select the 0x28 descriptor, changing the default
operand/address size to 16 bits. I guess.

Laszlo

------------------------------------------------------------------------------
Sponsored by Intel(R) XDK 
Develop, test and display web and hybrid apps with a single code base.
Download it for free now!
http://pubads.g.doubleclick.net/gampad/clk?id=111408631&iu=/4140/ostg.clktrk
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to