Home | History | Annotate | Download | only in X64
      1 
      2 #include "BaseLibInternals.h"
      3 
      4 ;------------------------------------------------------------------------------
      5 ;
      6 ; Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
      7 ; This program and the accompanying materials
      8 ; are licensed and made available under the terms and conditions of the BSD License
      9 ; which accompanies this distribution.  The full text of the license may be found at
     10 ; http://opensource.org/licenses/bsd-license.php.
     11 ;
     12 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 ;
     15 ; Module Name:
     16 ;
     17 ;   Thunk.asm
     18 ;
     19 ; Abstract:
     20 ;
     21 ;   Real mode thunk
     22 ;
     23 ;------------------------------------------------------------------------------
     24 
     25 EXTERNDEF   m16Start:BYTE
     26 EXTERNDEF   m16Size:WORD
     27 EXTERNDEF   mThunk16Attr:WORD
     28 EXTERNDEF   m16Gdt:WORD
     29 EXTERNDEF   m16GdtrBase:WORD
     30 EXTERNDEF   mTransition:WORD
     31 
     32 IA32_REGS   STRUC   4t
     33 _EDI        DD      ?
     34 _ESI        DD      ?
     35 _EBP        DD      ?
     36 _ESP        DD      ?
     37 _EBX        DD      ?
     38 _EDX        DD      ?
     39 _ECX        DD      ?
     40 _EAX        DD      ?
     41 _DS         DW      ?
     42 _ES         DW      ?
     43 _FS         DW      ?
     44 _GS         DW      ?
     45 _EFLAGS     DQ      ?
     46 _EIP        DD      ?
     47 _CS         DW      ?
     48 _SS         DW      ?
     49 IA32_REGS   ENDS
     50 
     51     .const
     52 
     53 m16Size         DW      InternalAsmThunk16 - m16Start
     54 mThunk16Attr    DW      _ThunkAttr - m16Start
     55 m16Gdt          DW      _NullSeg - m16Start
     56 m16GdtrBase     DW      _16GdtrBase - m16Start
     57 mTransition     DW      _EntryPoint - m16Start
     58 
     59     .code
     60 
     61 m16Start    LABEL   BYTE
     62 
     63 SavedGdt    LABEL   FWORD
     64             DW      ?
     65             DQ      ?
     66 
     67 ;------------------------------------------------------------------------------
     68 ; _BackFromUserCode() takes control in real mode after 'retf' has been executed
     69 ; by user code. It will be shadowed to somewhere in memory below 1MB.
     70 ;------------------------------------------------------------------------------
     71 _BackFromUserCode   PROC
     72     ;
     73     ; The order of saved registers on the stack matches the order they appears
     74     ; in IA32_REGS structure. This facilitates wrapper function to extract them
     75     ; into that structure.
     76     ;
     77     ; Some instructions for manipulation of segment registers have to be written
     78     ; in opcode since 64-bit MASM prevents accesses to those registers.
     79     ;
     80     DB      16h                         ; push ss
     81     DB      0eh                         ; push cs
     82     DB      66h
     83     call    @Base                       ; push eip
     84 @Base:
     85     DB      66h
     86     push    0                           ; reserved high order 32 bits of EFlags
     87     pushf                               ; pushfd actually
     88     cli                                 ; disable interrupts
     89     push    gs
     90     push    fs
     91     DB      6                           ; push es
     92     DB      1eh                         ; push ds
     93     DB      66h, 60h                    ; pushad
     94     DB      66h, 0bah                   ; mov edx, imm32
     95 _ThunkAttr  DD      ?
     96     test    dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
     97     jz      @1
     98     mov     eax, 15cd2401h              ; mov ax, 2401h & int 15h
     99     cli                                 ; disable interrupts
    100     jnc     @2
    101 @1:
    102     test    dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
    103     jz      @2
    104     in      al, 92h
    105     or      al, 2
    106     out     92h, al                     ; deactivate A20M#
    107 @2:
    108     xor     ax, ax                      ; xor eax, eax
    109     mov     eax, ss                     ; mov ax, ss
    110     lea     bp, [esp + sizeof (IA32_REGS)]
    111     ;
    112     ; rsi in the following 2 instructions is indeed bp in 16-bit code
    113     ;
    114     mov     word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp
    115     DB      66h
    116     mov     ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP
    117     shl     ax, 4                       ; shl eax, 4
    118     add     bp, ax                      ; add ebp, eax
    119     mov     ax, cs
    120     shl     ax, 4
    121     lea     ax, [eax + ebx + (@64BitCode - @Base)]
    122     DB      66h, 2eh, 89h, 87h          ; mov cs:[bx + (@64Eip - @Base)], eax
    123     DW      @64Eip - @Base
    124     DB      66h, 0b8h                   ; mov eax, imm32
    125 SavedCr4    DD      ?
    126     mov     cr4, rax
    127     ;
    128     ; rdi in the instruction below is indeed bx in 16-bit code
    129     ;
    130     DB      66h, 2eh                    ; 2eh is "cs:" segment override
    131     lgdt    fword ptr [rdi + (SavedGdt - @Base)]
    132     DB      66h
    133     mov     ecx, 0c0000080h
    134     rdmsr
    135     or      ah, 1
    136     wrmsr
    137     DB      66h, 0b8h                   ; mov eax, imm32
    138 SavedCr0    DD      ?
    139     mov     cr0, rax
    140     DB      66h, 0eah                   ; jmp far cs:@64Bit
    141 @64Eip      DD      ?
    142 SavedCs     DW      ?
    143 @64BitCode:
    144     db      090h 
    145     db      048h, 0bch                 ; mov rsp, imm64
    146 SavedSp     DQ   ?                     ; restore stack
    147     nop
    148     ret
    149 _BackFromUserCode   ENDP
    150 
    151 _EntryPoint DD      _ToUserCode - m16Start
    152             DW      CODE16
    153 _16Gdtr     LABEL   FWORD
    154             DW      GDT_SIZE - 1
    155 _16GdtrBase DQ      _NullSeg
    156 _16Idtr     FWORD   (1 SHL 10) - 1
    157 
    158 ;------------------------------------------------------------------------------
    159 ; _ToUserCode() takes control in real mode before passing control to user code.
    160 ; It will be shadowed to somewhere in memory below 1MB.
    161 ;------------------------------------------------------------------------------
    162 _ToUserCode PROC
    163     mov     ss, edx                     ; set new segment selectors
    164     mov     ds, edx
    165     mov     es, edx
    166     mov     fs, edx
    167     mov     gs, edx
    168     DB      66h
    169     mov     ecx, 0c0000080h
    170     mov     cr0, rax                    ; real mode starts at next instruction
    171     rdmsr
    172     and     ah, NOT 1
    173     wrmsr
    174     mov     cr4, rbp
    175     mov     ss, esi                     ; set up 16-bit stack segment
    176     mov     sp, bx                      ; set up 16-bit stack pointer
    177     DB      66h                         ; make the following call 32-bit
    178     call    @Base                       ; push eip
    179 @Base:
    180     pop     bp                          ; ebp <- address of @Base
    181     push    [esp + sizeof (IA32_REGS) + 2]
    182     lea     eax, [rsi + (@RealMode - @Base)]    ; rsi is "bp" in 16-bit code
    183     push    rax
    184     retf                                ; execution begins at next instruction
    185 @RealMode:
    186     DB      66h, 2eh                    ; CS and operand size override
    187     lidt    fword ptr [rsi + (_16Idtr - @Base)]
    188     DB      66h, 61h                    ; popad
    189     DB      1fh                         ; pop ds
    190     DB      07h                         ; pop es
    191     pop     fs
    192     pop     gs
    193     popf                                ; popfd
    194     lea     sp, [esp + 4]               ; skip high order 32 bits of EFlags
    195     DB      66h                         ; make the following retf 32-bit
    196     retf                                ; transfer control to user code
    197 _ToUserCode ENDP
    198 
    199 CODE16  = _16Code - $
    200 DATA16  = _16Data - $
    201 DATA32  = _32Data - $
    202 
    203 _NullSeg    DQ      0
    204 _16Code     LABEL   QWORD
    205             DW      -1
    206             DW      0
    207             DB      0
    208             DB      9bh
    209             DB      8fh                 ; 16-bit segment, 4GB limit
    210             DB      0
    211 _16Data     LABEL   QWORD
    212             DW      -1
    213             DW      0
    214             DB      0
    215             DB      93h
    216             DB      8fh                 ; 16-bit segment, 4GB limit
    217             DB      0
    218 _32Data     LABEL   QWORD
    219             DW      -1
    220             DW      0
    221             DB      0
    222             DB      93h
    223             DB      0cfh                ; 16-bit segment, 4GB limit
    224             DB      0
    225 
    226 GDT_SIZE = $ - _NullSeg
    227 
    228 ;------------------------------------------------------------------------------
    229 ; IA32_REGISTER_SET *
    230 ; EFIAPI
    231 ; InternalAsmThunk16 (
    232 ;   IN      IA32_REGISTER_SET         *RegisterSet,
    233 ;   IN OUT  VOID                      *Transition
    234 ;   );
    235 ;------------------------------------------------------------------------------
    236 InternalAsmThunk16  PROC    USES    rbp rbx rsi rdi
    237     mov     rbx, ds
    238     push    rbx          ; Save ds segment register on the stack
    239     mov     rbx, es
    240     push    rbx          ; Save es segment register on the stack
    241     mov     rbx, ss
    242     push    rbx          ; Save ss segment register on the stack
    243     
    244     push    fs
    245     push    gs
    246     mov     rsi, rcx
    247     movzx   r8d, (IA32_REGS ptr [rsi])._SS
    248     mov     edi, (IA32_REGS ptr [rsi])._ESP
    249     lea     rdi, [edi - (sizeof (IA32_REGS) + 4)]
    250     imul    eax, r8d, 16                ; eax <- r8d(stack segment) * 16
    251     mov     ebx, edi                    ; ebx <- stack for 16-bit code
    252     push    sizeof (IA32_REGS) / 4
    253     add     edi, eax                    ; edi <- linear address of 16-bit stack
    254     pop     rcx
    255     rep     movsd                       ; copy RegSet
    256     lea     ecx, [rdx + (SavedCr4 - m16Start)]
    257     mov     eax, edx                    ; eax <- transition code address
    258     and     edx, 0fh
    259     shl     eax, 12                     ; segment address in high order 16 bits
    260     lea     ax, [rdx + (_BackFromUserCode - m16Start)]  ; offset address
    261     stosd                               ; [edi] <- return address of user code
    262   
    263     sgdt    fword ptr [rsp + 60h]       ; save GDT stack in argument space
    264     movzx   r10, word ptr [rsp + 60h]   ; r10 <- GDT limit 
    265     lea     r11, [rcx + (InternalAsmThunk16 - SavedCr4) + 0xf]
    266     and     r11, 0xfffffff0             ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer
    267     
    268     mov     word ptr [rcx + (SavedGdt - SavedCr4)], r10w      ; save the limit of shadowed GDT table
    269     mov     qword ptr [rcx + (SavedGdt - SavedCr4) + 2], r11  ; save the base address of shadowed GDT table
    270     
    271     mov     rsi, qword ptr [rsp + 62h]  ; rsi <- the original GDT base address
    272     xchg    rcx, r10                    ; save rcx to r10 and initialize rcx to be the limit of GDT table
    273     inc     rcx                         ; rcx <- the size of memory to copy
    274     xchg    rdi, r11                    ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table
    275     rep     movsb                       ; perform memory copy to shadow GDT table
    276     mov     rcx, r10                    ; restore the orignal rcx before memory copy
    277     mov     rdi, r11                    ; restore the original rdi before memory copy
    278     
    279     sidt    fword ptr [rsp + 50h]       ; save IDT stack in argument space
    280     mov     rax, cr0
    281     mov     [rcx + (SavedCr0 - SavedCr4)], eax
    282     and     eax, 7ffffffeh              ; clear PE, PG bits
    283     mov     rbp, cr4
    284     mov     [rcx], ebp                  ; save CR4 in SavedCr4
    285     and     ebp, NOT 30h                ; clear PAE, PSE bits
    286     mov     esi, r8d                    ; esi <- 16-bit stack segment
    287     DB      6ah, DATA32                 ; push DATA32
    288     pop     rdx                         ; rdx <- 32-bit data segment selector
    289     lgdt    fword ptr [rcx + (_16Gdtr - SavedCr4)]
    290     mov     ss, edx
    291     pushfq
    292     lea     edx, [rdx + DATA16 - DATA32]
    293     lea     r8, @RetFromRealMode
    294     push    r8
    295     mov     r8d, cs
    296     mov     [rcx + (SavedCs - SavedCr4)], r8w
    297     mov     [rcx + (SavedSp - SavedCr4)], rsp
    298     jmp     fword ptr [rcx + (_EntryPoint - SavedCr4)]
    299 @RetFromRealMode:
    300     popfq
    301     lgdt    fword ptr [rsp + 60h]       ; restore protected mode GDTR
    302     lidt    fword ptr [rsp + 50h]       ; restore protected mode IDTR
    303     lea     eax, [rbp - sizeof (IA32_REGS)]
    304     pop     gs
    305     pop     fs
    306     pop     rbx
    307     mov     ss, rbx
    308     pop     rbx
    309     mov     es, rbx
    310     pop     rbx
    311     mov     ds, rbx
    312     ret
    313 InternalAsmThunk16  ENDP
    314 
    315     END
    316