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
25EXTERNDEF   m16Start:BYTE
26EXTERNDEF   m16Size:WORD
27EXTERNDEF   mThunk16Attr:WORD
28EXTERNDEF   m16Gdt:WORD
29EXTERNDEF   m16GdtrBase:WORD
30EXTERNDEF   mTransition:WORD
31
32IA32_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      ?
49IA32_REGS   ENDS
50
51    .const
52
53m16Size         DW      InternalAsmThunk16 - m16Start
54mThunk16Attr    DW      _ThunkAttr - m16Start
55m16Gdt          DW      _NullSeg - m16Start
56m16GdtrBase     DW      _16GdtrBase - m16Start
57mTransition     DW      _EntryPoint - m16Start
58
59    .code
60
61m16Start    LABEL   BYTE
62
63SavedGdt    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
125SavedCr4    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
138SavedCr0    DD      ?
139    mov     cr0, rax
140    DB      66h, 0eah                   ; jmp far cs:@64Bit
141@64Eip      DD      ?
142SavedCs     DW      ?
143@64BitCode:
144    db      090h 
145    db      048h, 0bch                 ; mov rsp, imm64
146SavedSp     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
199CODE16  = _16Code - $
200DATA16  = _16Data - $
201DATA32  = _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
226GDT_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;------------------------------------------------------------------------------
236InternalAsmThunk16  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
313InternalAsmThunk16  ENDP
314
315    END
316