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
25global ASM_PFX(m16Size)
26global ASM_PFX(mThunk16Attr)
27global ASM_PFX(m16Gdt)
28global ASM_PFX(m16GdtrBase)
29global ASM_PFX(mTransition)
30global ASM_PFX(m16Start)
31
32struc IA32_REGS
33
34  ._EDI:       resd      1
35  ._ESI:       resd      1
36  ._EBP:       resd      1
37  ._ESP:       resd      1
38  ._EBX:       resd      1
39  ._EDX:       resd      1
40  ._ECX:       resd      1
41  ._EAX:       resd      1
42  ._DS:        resw      1
43  ._ES:        resw      1
44  ._FS:        resw      1
45  ._GS:        resw      1
46  ._EFLAGS:    resd      1
47  ._EIP:       resd      1
48  ._CS:        resw      1
49  ._SS:        resw      1
50  .size:
51
52endstruc
53
54;; .const
55
56SECTION .data
57
58;
59; These are global constant to convey information to C code.
60;
61ASM_PFX(m16Size)         DW      ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start)
62ASM_PFX(mThunk16Attr)    DW      _BackFromUserCode.ThunkAttrEnd - 4 - ASM_PFX(m16Start)
63ASM_PFX(m16Gdt)          DW      _NullSegDesc - ASM_PFX(m16Start)
64ASM_PFX(m16GdtrBase)     DW      _16GdtrBase - ASM_PFX(m16Start)
65ASM_PFX(mTransition)     DW      _EntryPoint - ASM_PFX(m16Start)
66
67SECTION .text
68
69ASM_PFX(m16Start):
70
71SavedGdt:
72            dw  0
73            dd  0
74
75;------------------------------------------------------------------------------
76; _BackFromUserCode() takes control in real mode after 'retf' has been executed
77; by user code. It will be shadowed to somewhere in memory below 1MB.
78;------------------------------------------------------------------------------
79_BackFromUserCode:
80    ;
81    ; The order of saved registers on the stack matches the order they appears
82    ; in IA32_REGS structure. This facilitates wrapper function to extract them
83    ; into that structure.
84    ;
85BITS    16
86    push    ss
87    push    cs
88    ;
89    ; Note: We can't use o32 on the next instruction because of a bug
90    ; in NASM 2.09.04 through 2.10rc1.
91    ;
92    call    dword .Base                 ; push eip
93.Base:
94    pushfd
95    cli                                 ; disable interrupts
96    push    gs
97    push    fs
98    push    es
99    push    ds
100    pushad
101    mov     edx, strict dword 0
102.ThunkAttrEnd:
103    test    dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
104    jz      .1
105    mov     ax, 2401h
106    int     15h
107    cli                                 ; disable interrupts
108    jnc     .2
109.1:
110    test    dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
111    jz      .2
112    in      al, 92h
113    or      al, 2
114    out     92h, al                     ; deactivate A20M#
115.2:
116    xor     eax, eax
117    mov     ax, ss
118    lea     ebp, [esp + IA32_REGS.size]
119    mov     [bp - IA32_REGS.size + IA32_REGS._ESP], ebp
120    mov     bx, [bp - IA32_REGS.size + IA32_REGS._EIP]
121    shl     eax, 4                      ; shl eax, 4
122    add     ebp, eax                    ; add ebp, eax
123    mov     eax, strict dword 0
124.SavedCr4End:
125    mov     cr4, eax
126o32 lgdt [cs:bx + (SavedGdt - .Base)]
127    mov     eax, strict dword 0
128.SavedCr0End:
129    mov     cr0, eax
130    mov     ax, strict word 0
131.SavedSsEnd:
132    mov     ss, eax
133    mov     esp, strict dword 0
134.SavedEspEnd:
135o32 retf                                ; return to protected mode
136
137_EntryPoint:
138        DD      _ToUserCode - ASM_PFX(m16Start)
139        DW      8h
140_16Idtr:
141        DW      (1 << 10) - 1
142        DD      0
143_16Gdtr:
144        DW      GdtEnd - _NullSegDesc - 1
145_16GdtrBase:
146        DD      0
147
148;------------------------------------------------------------------------------
149; _ToUserCode() takes control in real mode before passing control to user code.
150; It will be shadowed to somewhere in memory below 1MB.
151;------------------------------------------------------------------------------
152_ToUserCode:
153BITS    16
154    mov     dx, ss
155    mov     ss, cx                      ; set new segment selectors
156    mov     ds, cx
157    mov     es, cx
158    mov     fs, cx
159    mov     gs, cx
160    mov     cr0, eax                    ; real mode starts at next instruction
161                                        ;  which (per SDM) *must* be a far JMP.
162    jmp     0:strict word 0
163.RealAddrEnd:
164    mov     cr4, ebp
165    mov     ss, si                      ; set up 16-bit stack segment
166    xchg    esp, ebx                    ; set up 16-bit stack pointer
167    mov     bp, [esp + IA32_REGS.size]
168    mov     [cs:bp + (_BackFromUserCode.SavedSsEnd - 2 - _BackFromUserCode)], dx
169    mov     [cs:bp + (_BackFromUserCode.SavedEspEnd - 4 - _BackFromUserCode)], ebx
170    lidt    [cs:bp + (_16Idtr - _BackFromUserCode)]
171
172    popad
173    pop     ds
174    pop     es
175    pop     fs
176    pop     gs
177    popfd
178
179o32 retf                                ; transfer control to user code
180
181ALIGN   16
182_NullSegDesc    DQ      0
183_16CsDesc:
184                DW      -1
185                DW      0
186                DB      0
187                DB      9bh
188                DB      8fh             ; 16-bit segment, 4GB limit
189                DB      0
190_16DsDesc:
191                DW      -1
192                DW      0
193                DB      0
194                DB      93h
195                DB      8fh             ; 16-bit segment, 4GB limit
196                DB      0
197GdtEnd:
198
199;------------------------------------------------------------------------------
200; IA32_REGISTER_SET *
201; EFIAPI
202; InternalAsmThunk16 (
203;   IN      IA32_REGISTER_SET         *RegisterSet,
204;   IN OUT  VOID                      *Transition
205;   );
206;------------------------------------------------------------------------------
207global ASM_PFX(InternalAsmThunk16)
208ASM_PFX(InternalAsmThunk16):
209BITS    32
210    push    ebp
211    push    ebx
212    push    esi
213    push    edi
214    push    ds
215    push    es
216    push    fs
217    push    gs
218    mov     esi, [esp + 36]             ; esi <- RegSet, the 1st parameter
219    movzx   edx, word [esi + IA32_REGS._SS]
220    mov     edi, [esi + IA32_REGS._ESP]
221    add     edi, - (IA32_REGS.size + 4) ; reserve stack space
222    mov     ebx, edi                    ; ebx <- stack offset
223    imul    eax, edx, 16                ; eax <- edx * 16
224    push    IA32_REGS.size / 4
225    add     edi, eax                    ; edi <- linear address of 16-bit stack
226    pop     ecx
227    rep     movsd                       ; copy RegSet
228    mov     eax, [esp + 40]             ; eax <- address of transition code
229    mov     esi, edx                    ; esi <- 16-bit stack segment
230    lea     edx, [eax + (_BackFromUserCode.SavedCr0End - ASM_PFX(m16Start))]
231    mov     ecx, eax
232    and     ecx, 0fh
233    shl     eax, 12
234    lea     ecx, [ecx + (_BackFromUserCode - ASM_PFX(m16Start))]
235    mov     ax, cx
236    stosd                               ; [edi] <- return address of user code
237    add     eax, _ToUserCode.RealAddrEnd - _BackFromUserCode
238    mov     [edx + (_ToUserCode.RealAddrEnd - 4 - _BackFromUserCode.SavedCr0End)], eax
239    sgdt    [edx + (SavedGdt - _BackFromUserCode.SavedCr0End)]
240    sidt    [esp + 36]        ; save IDT stack in argument space
241    mov     eax, cr0
242    mov     [edx - 4], eax                  ; save CR0 in _BackFromUserCode.SavedCr0End - 4
243    and     eax, 7ffffffeh              ; clear PE, PG bits
244    mov     ebp, cr4
245    mov     [edx + (_BackFromUserCode.SavedCr4End - 4 - _BackFromUserCode.SavedCr0End)], ebp
246    and     ebp, ~30h                ; clear PAE, PSE bits
247    push    10h
248    pop     ecx                         ; ecx <- selector for data segments
249    lgdt    [edx + (_16Gdtr - _BackFromUserCode.SavedCr0End)]
250    pushfd                              ; Save df/if indeed
251    call    dword far [edx + (_EntryPoint - _BackFromUserCode.SavedCr0End)]
252    popfd
253    lidt    [esp + 36]        ; restore protected mode IDTR
254    lea     eax, [ebp - IA32_REGS.size] ; eax <- the address of IA32_REGS
255    pop     gs
256    pop     fs
257    pop     es
258    pop     ds
259    pop     edi
260    pop     esi
261    pop     ebx
262    pop     ebp
263    ret
264