summaryrefslogtreecommitdiff
path: root/EdkCompatibilityPkg/Foundation/Library/Thunk16/X64/Thunk16.S
blob: a8a94a4fa978fc5bf1f09f87ba6ccfc011df442b (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
229
230
231
232
233
234
235
236
#*****************************************************************************
#*
#*   Copyright (c) 2008, Intel Corporation                                                         
#*   All rights reserved. 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.S
#*  
#*   Abstract:
#*  
#*    Real mode thunk
#*  
#*****************************************************************************
#include <EfiBind.h>



    .data

.globl ASM_PFX(mCode16Size)

.data
mCode16Size:    .long   _Code16End - _Code16Addr


NullSegSel:     .quad   0
_16CsSegSel:    
                .word   -1
                .word   0
                .byte   0
                .byte   0x9b
                .byte   0x8f            #16-bit segment
                .byte   0
_16DsSegSel:
                .word   -1
                .word   0
                .byte   0
                .byte   0x93
                .byte   0x8f           #16-bit segment
                .byte   0

_16Gdtr:
                .word      _16Gdtr - NullSegSel - 1
                .long      NullSegSel
    .code: 

#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

ASM_PFX(Thunk16):
      push   %rbp
      push   %rbx
      push   %rsi
      push   %rdi
      push   %r12
      push   %r13
      push   %r14
      push   %r15
      pushq  %fs
      pushq  %gs
      movl   %ds,%r12d
      movl   %es,%r13d
      movl   %ss,%r14d
      mov    %rsp,%r15
      mov    %rcx,%rsi
      movzwq 0x36(%rsi),%r10            #movzx   r10, (IA32_REGS ptr [rsi])._SS
      xor    %rdi,%rdi
      mov    0xc(%rsi),%edi             #mov     edi, (IA32_REGS ptr [rsi])._ESP
      add    $0xffffffffffffffb0,%rdi   #add     rdi, - sizeof (IA32_REGS) - sizeof (_STK16)
      push   %rdi
      imul   $0x10,%r10,%rax
      add    %rax,%rdi
      pushq  $0xe                       #push    sizeof (IA32_REGS) / 4
      pop    %rcx
      rep movsl %ds:(%rsi),%es:(%rdi)
      pop    %rbx                       #rbx <- 16-bit stack offset
      lea    Label,%eax                 #42 <_Thunk16+0x42>
      stos   %eax,%es:(%rdi)
      movl   %cs,%eax                   #return segment
      stos   %ax,%es:(%rdi)
      mov    %edx,%eax                  #THUNK Flags
      stos   %ax,%es:(%rdi)
      sgdt  0x58(%rsp)                  #save GDTR
      mov    0x58(%rsp),%rax
      stos   %rax,%es:(%rdi)
      mov    %cr0,%rax                  #save CR0
      mov    %eax,%esi                  #esi <- CR0 to set
      stos   %eax,%es:(%rdi)
      mov    %cr4,%rax                  #save CR4
      stos   %eax,%es:(%rdi)
      sidt   0x58(%rsp)                 #save IDTR
      and    $0x7ffffffe,%esi           #clear PE & PG bits
      mov    %r10,%rdi                  #rdi <- 16-bit stack segment
      shl    $0x10,%r8
      push   %r8                        #far jmp address
      lea    Label_16Bit,%eax           
      push   %rax
      movw   $0x8,0x4(%rsp)
      lgdt   _16Gdtr                    #bugbug: may not match.
      lret   
Label_16Bit:
      .byte  0x66
      movl   $0xc0000080,%ecx
      mov    %rsi,%cr0                  #disable PE & PG        
      rdmsr  
      and    $0xfe,%ah
      wrmsr                             #clear LME bit
      mov    %cr4,%rax
      and    $0xcf,%al                  #clear PAE & PSE
      mov    %rax,%cr4
      lret   

Label:
      xor    %rax,%rax
      movl   %ss,%eax
      shl    $0x4,%eax
      add    %esp,%eax
      mov    %r15,%rsp
      lidt   0x58(%rsp)
      movl   %r12d,%ds
      movl   %r13d,%es
      movl   %r14d,%ss
      popq   %gs
      popq   %fs
      pop    %r15
      pop    %r14
      pop    %r13
      pop    %r12
      pop    %rdi
      pop    %rsi
      pop    %rbx
      pop    %rbp
      retq   


    .align 0x10

_Code16Addr:
ASM_PFX(RealMode):
    movl   %edi,%ss
    mov    %bx,%sp                     #set up 16-bit stack
   .byte   0x2e 
   .byte   0x0f 
   .byte   0x01
   .byte   0x1e
   .word   _16Idtr - _Code16Addr       #lidt _16Idtr
   .byte   0x66
   .byte   0x61                        #popad
   .byte   0x1f                        #pop ds
   .byte   0x07                        #pop es
    popq   %fs
    popq   %gs
    add    $0x8,%esp                   #skip RFLAGS
   .byte   0x67                        #test [esp + 0eh], 1
   .byte   0xf7    
   .byte   0x44
   .byte   0x24
   .byte   0x0e
   .byte   0x01
   .byte   0x00
    jz      1f
    pushfq                             #pushf, actually
1:
   .byte   0x0e                        #push cs
   .byte   0x68                        #push /iw
   .word   FarCallRet - _Code16Addr
    jz     2f
   .byte   0x66
    ljmp   *6(%esp)
2:    
   .byte   0x66
    ljmp   *4(%esp)
FarCallRet: 
   .byte   0x66
    push   $0x00                       #push a dword of zero
   .byte   0x66
    pushf                              #pushfd, actually
    pushq  %gs
    pushq  %fs
   .byte   0x06                        #push %es
   .byte   0x1e                        #push %ds
   .byte   0x66
   .byte   0x60
    cli
   .byte   0x66                        #sizeof (IA32_REGS) = 13 * 4 = 52
    lgdt   64(%esp)                    #lgdt    (_STK16 ptr [esp + sizeof (IA32_REGS)]).SavedGdtr
   .byte   0x66
    mov    76(%esp), %eax
    mov    %rax, %cr4
   .byte   0x66
    mov    $0xc0000080, %ecx
    rdmsr
    orb    $1, %ah
    wrmsr
   .byte   0x66
    mov    72(%esp), %eax
    mov    %rax, %cr0                   #restore CR0
   .byte   0x66
    ljmpl  *52(%esp)                    

_16Idtr:
   .word 0x3ff                          #FWORD   (1 SHL 10) - 1
   .byte 0x00