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