summaryrefslogtreecommitdiff
path: root/EdkCompatibilityPkg/Foundation/Library/Thunk16/X64/Thunk16.asm
blob: 0638d5faa8de9a3a6067853c506387572faaad76 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
;*****************************************************************************
;*
;*   Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
;*   This program and the accompanying materials                          
;*   are licensed and made available under the terms and conditions of the BSD License         
;*   which accompanies this distribution.  The full text of the license may be found at        
;*   http://opensource.org/licenses/bsd-license.php                                            
;*                                                                                             
;*   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
;*   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
;*   
;*   Module Name:
;*
;*    Thunk.asm
;*  
;*   Abstract:
;*  
;*    Real mode thunk
;*  
;*****************************************************************************

EXTERNDEF   mCode16Size:QWORD

    .const

mCode16Size     DQ      _Code16End - _Code16Addr

    .data

NullSegSel      DQ      0
_16CsSegSel     LABEL   QWORD
                DW      -1
                DW      0
                DB      0
                DB      9bh
                DB      8fh             ; 16-bit segment
                DB      0
_16DsSegSel     LABEL   QWORD
                DW      -1
                DW      0
                DB      0
                DB      93h
                DB      8fh             ; 16-bit segment
                DB      0

_16Gdtr         LABEL   FWORD
                DW      $ - offset NullSegSel - 1
                DQ      offset NullSegSel

    .code

STACK_PARAM_SIZE  EQU  16

IA32_REGS   STRUC   4t
_EDI        DD      ?
_ESI        DD      ?
_EBP        DD      ?
_ESP        DD      ?
_EBX        DD      ?
_EDX        DD      ?
_ECX        DD      ?
_EAX        DD      ?
_DS         DW      ?
_ES         DW      ?
_FS         DW      ?
_GS         DW      ?
_RFLAGS     DQ      ?
_EIP        DD      ?
_CS         DW      ?
_SS         DW      ?
IA32_REGS   ENDS

_STK16      STRUC   1t
RetEip      DD      ?
RetCs       DW      ?
ThunkFlags  DW      ?
SavedGdtr   FWORD   ?
Resvd1      DW      ?
SavedCr0    DD      ?
SavedCr4    DD      ?
_STK16      ENDS

_Thunk16    PROC    USES    rbp rbx rsi rdi r12 r13 r14 r15

    push    fs
    push    gs

    mov     r12d, ds
    mov     r13d, es
    mov     r14d, ss
    mov     r15, rsp
    mov     rsi, rcx
    movzx   r10, (IA32_REGS ptr [rsi])._SS
    xor     rdi, rdi
    mov     edi, (IA32_REGS ptr [rsi])._ESP
    add     rdi, - sizeof (IA32_REGS) - sizeof (_STK16)
    push    rdi
    imul    rax, r10, 16
    add     rdi, rax
    push    sizeof (IA32_REGS) / 4
    pop     rcx
    rep     movsd

    ; copy eflags to stack frame
    mov     rax, (IA32_REGS ptr [rsi - sizeof(IA32_REGS)])._RFLAGS
    mov     [rdi - sizeof(IA32_REGS) - STACK_PARAM_SIZE - 8], rax

    pop     rbx                         ; rbx <- 16-bit stack offset
    lea     eax, @F                     ; return offset
    stosd
    mov     eax, cs                     ; return segment
    stosw
    mov     eax, edx                    ; THUNK Flags
    stosw
    sgdt    fword ptr [rsp + 58h]       ; save GDTR
    mov     rax, [rsp + 58h]
    stosq
    mov     rax, cr0                    ; save CR0
    mov     esi, eax                    ; esi <- CR0 to set
    stosd
    mov     rax, cr4                    ; save CR4
    stosd
    sidt    fword ptr [rsp + 58h]       ; save IDTR
    and     esi, 07ffffffeh             ; clear PE & PG bits
    mov     rdi, r10                    ; rdi <- 16-bit stack segment

    shl     r8, 16
    push    r8                          ; far jmp address
    lea     eax, @16Bit
    push    rax
    mov     word ptr [rsp + 4], 8
    lgdt    _16Gdtr
    retf
@16Bit:
    DB      66h
    mov     ecx, 0c0000080h
    mov     cr0, rsi                    ; disable PE & PG
    rdmsr
    and     ah, NOT 1
    wrmsr                               ; clear LME bit
    mov     rax, cr4
    and     al, NOT 30h                 ; clear PAE & PSE
    mov     cr4, rax
    retf
@@:
    xor     rax, rax
    mov     eax, ss
    shl     eax, 4
    add     eax, esp                    ; rax <- address of 16-bit stack
    mov     rsp, r15
    lidt    fword ptr [rsp + 58h]       ; restore IDTR
    mov     ds, r12d
    mov     es, r13d
    mov     ss, r14d
    pop     gs
    pop     fs
    ret
_Thunk16    ENDP

    ALIGN   10h

_Code16Addr PROC
_Code16Addr ENDP

RealMode    PROC
    mov     ss, edi
    mov     sp, bx                      ; set up 16-bit stack
    DB      2eh, 0fh, 1, 1eh
    DW      _16Idtr - _Code16Addr       ; lidt _16Idtr
    DB      66h, 61h                    ; popad
    DB      1fh                         ; pop ds
    DB      7                           ; pop es
    pop     fs
    pop     gs
    sub     esp, (sizeof(IA32_REGS) - 16) + STACK_PARAM_SIZE + 8

    DB      66h, 9Dh                    ; popfd
    add     esp, 4                      ; skip high part of RFLAGS
    DB      67h, 0f7h, 44h, 24h         ; test    (_STK16 ptr [esp + STACK_PARAM_SIZE + sizeof(IA32_REGS)]).ThunkFlags, 1
    DB      (STACK_PARAM_SIZE + sizeof(IA32_REGS) + 6)
    DB      1, 0
    jz      @F
    pushfq                              ; pushf, actually, when it's INT#
@@:
    DB      0eh                         ; push cs
    DB      68h                         ; push /iw
    DW      @FarCallRet - _Code16Addr
    jz      @F
    DB      66h
    jmp     fword ptr [esp + 6 + STACK_PARAM_SIZE + sizeof(IA32_REGS) - 8]
@@:
    DB      66h
    jmp     fword ptr [esp + 4 + STACK_PARAM_SIZE + sizeof(IA32_REGS) - 8]
@FarCallRet:
    add     esp, (sizeof(IA32_REGS) - 16) + STACK_PARAM_SIZE + 8
    DB      66h
    push    0                           ; push a dword of zero
    pushf                               ; pushfd, actually
    push    gs
    push    fs
    DB      6                           ; push es
    DB      1eh                         ; push ds
    DB      66h, 60h                    ; pushad
    cli

    DB      66h
    lgdt    (_STK16 ptr [esp + sizeof(IA32_REGS)]).SavedGdtr
    DB      66h
    mov     eax, (_STK16 ptr [esp + sizeof(IA32_REGS)]).SavedCr4
    mov     cr4, rax
    DB      66h
    mov     ecx, 0c0000080h
    rdmsr
    or      ah, 1
    wrmsr                               ; set LME
    DB      66h
    mov     eax, (_STK16 ptr [esp + sizeof(IA32_REGS)]).SavedCr0
    mov     cr0, rax
    DB      66h
    jmp     fword ptr (_STK16 ptr [esp + sizeof(IA32_REGS)]).RetEip

RealMode    ENDP

_16Idtr     FWORD   (1 SHL 10) - 1

_Code16End:

    END