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