On 12/05/13 00:21, Yao, Jiewen wrote:
> Hi Laszlo
> Thanks for the investigation.
> 
> Maybe I am wrong, but I would like to point out this piece of code works fine 
> on IA real platform.

Thanks for confirming that! I was wondering if it was in active use.

> We also have other piece of code to jump from 64bit to 16bit directly, which 
> works fine also.
> 
> I just checked IA32 manual, for far return, detail below: (error handling are 
> removed)

Yes I've been staring at the far return documentation for days now :)

> Would you please help to check if the emulator follow IA32 manual to do the 
> mode switch?

I've already asked on an internal list and got a discussion started, but
I think I'll have to keep asking. The interesting thing is that this
lret instruction doesn't seem to trap to KVM at all (although KVM does
have a function to emulate this, em_ret_far()). I could have messed up
the tracing of course. Right now it seems to me that the reboot happens
internally to the guest, without a VMEXIT or so. (Not sure if what I'm
saying makes any sense, sorry...)

> ===================================
> (* IA-32e Mode *)
> IF (PE = 1 and VM = 0 and IA32_EFER.LMA = 1) and instruction = far return
>   GOTO IA-32E-MODE-RETURN-SAME-PRIVILEGE-LEVEL
> 
> IA-32E-MODE-RETURN-SAME-PRIVILEGE-LEVEL:
> IF OperandSize = 32
>   THEN
>     EIP <- Pop();
>     CS <- Pop(); (* 32-bit pop, high-order 16 bits discarded *)
>   ELSE
>     IF OperandSize = 16
>       THEN
>         EIP <- Pop();
>         EIP <- EIP AND 0000FFFFH;
>         CS <- Pop(); (* 16-bit pop *)
>       ELSE (* OperandSize = 64 *)
>         RIP <- Pop();
>         CS <- Pop(); (* 64-bit pop, high-order 48 bits discarded *)
>     FI;
> FI;
> IF instruction has immediate operand
>   THEN (* Release parameters from stack *)
>     IF StackAddressSize = 32
>       THEN
>         ESP <- ESP + SRC;
>       ELSE
>         IF StackAddressSize = 16
>           THEN
>             SP <- SP + SRC;
>           ELSE (* StackAddressSize = 64 *)
>             RSP <- RSP + SRC;
>         FI;
>     FI;
> FI;
> ===================================

I sought to check the error handling too, in the SDM and in the KVM
source, and I couldn't find anything that we'd hit.


Can you please help me understand the routine though?

>>>> 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

So the intent of the lret is mostly clear to me. What are we doing with
ecx and edx? On input rcx holds the S3WakingVector parameter, which is
0x9A1D0 in my case.

Any real mode vector will (I guess) occupy at most 20 bits (< 1MB). The
shrd seems to shift those bits from the least significant end of ecx
into the most significant end of ebx, right?

  ecx: 00000000 00001001 10100001 11010000 == 0x0009A1D0
  ebx: 10011010 00011101 0000???? ???????? == 0x9A1D0???

Then the andl masks out everything in ecx except the least significant
nibble:

  ecx: 00000000 00000000 00000000 00000000 == 0x00000000
  ebx: 10011010 00011101 0000???? ???????? == 0x9A1D0???

We copy the least significant 16 bits from ecx to ebx:

  ecx: 00000000 00000000 00000000 00000000 == 0x00000000
  ebx: 10011010 00011101 00000000 00000000 == 0x9A1D0000

and we write ebx to the .long at jmp_addr.

>>>> _AsmTransferControl_al_0000:
>>>>     .byte    0x0b8, 0x30, 0      # mov ax, 30h as selector

Why is it necessary to express this in raw binary? We could simply say
"movl $0, %eax", couldn't we?

>>>>     movl  %eax, %ds
>>>>     movl  %eax, %es
>>>>     movl  %eax, %fs
>>>>     movl  %eax, %gs
>>>>     movl  %eax, %ss
>>>>     movq  %cr0, %rax

OK so this surprises me (but as you can tell my assembly is quite weak).
The segment descriptor we selected with CS=0x28 at the top tells the CPU
that this code here should be executed in compatibility mode.

According to the SDM, "MOV—Move to/from Control Registers",

  MOV r64, CR0–CR7 # Move extended control register to r64.

is N.E. in compatibility/legacy mode.

Are we not in compat mode? If the processor is still in 64-bit mode,
what is the CS change good for?

>>>>     movq  %cr4, %rbx
>>>>     .byte    0x66
>>>>     andl  $0x7ffffffe, %eax

I guess the 0x66 prefix is justified because our CS change resulted in
the default address & operand width being 16 bits, and we need 32 bit
operands here. We mask off the MSB and LSB of eax, which seem to
correspond to Paging and Protection Enable, respectively. (This would
enable real mode when written back to cr0.)

>>>>     andb  $0xdf, %bl

Turns off bit 5 in cr4's value, which is Physical Address Extension (PAE).

>>>>     movq  %rax, %cr0

At this point we seem to reenter real mode (turning off Paging and
Protection Enable).

>>>>     .byte    0x66
>>>>     movl  $0x0c0000080, %ecx

Is a reference to "ecx" still valid in real mode?

>>>>     rdmsr
>>>>     andb  $0xfe, %ah
>>>>     wrmsr

This seems to clear bit 8 in IA32_EFER, which stands for "IA-32e Mode
Enable".

>>>>     movq  %rbx, %cr4

Turns off PAE.

We're surely not in 64-bit mode here though? And

    MOV CR0–CR7, r64 # Move r64 to extended control register.

is N.E. (not encodable) in compat/legacy mode.

>>>>     .byte    0x0ea              # jmp far jmp_addr
>>>> jmp_addr:
>>>>     .long    0

  EA cd  JMP ptr16:16  Jump far, absolute, address given in operand

The operand is 0x9A1D0000, meaning 9A1D:0, which seems to correspond to
the original 0x9A1D0 input param. And looking back at the ebx
calculation at the top, a nonzero offset (<= 0xf) would be stored
correctly as well.

Thank you,
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