]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BaseLib/Ia32/Thunk16.S
MdePkg: First instruction after clearing CR0.PE must be a far jmp.
[mirror_edk2.git] / MdePkg / Library / BaseLib / Ia32 / Thunk16.S
1 #------------------------------------------------------------------------------
2 #
3 # Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
4 # 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 # Thunk16.S
15 #
16 # Abstract:
17 #
18 # Real mode thunk
19 #
20 #------------------------------------------------------------------------------
21
22 #include <Library/BaseLib.h>
23
24 ASM_GLOBAL ASM_PFX(m16Start), ASM_PFX(m16Size), ASM_PFX(mThunk16Attr), ASM_PFX(m16Gdt), ASM_PFX(m16GdtrBase), ASM_PFX(mTransition)
25 ASM_GLOBAL ASM_PFX(InternalAsmThunk16)
26
27 # define the structure of IA32_REGS
28 .set _EDI, 0 #size 4
29 .set _ESI, 4 #size 4
30 .set _EBP, 8 #size 4
31 .set _ESP, 12 #size 4
32 .set _EBX, 16 #size 4
33 .set _EDX, 20 #size 4
34 .set _ECX, 24 #size 4
35 .set _EAX, 28 #size 4
36 .set _DS, 32 #size 2
37 .set _ES, 34 #size 2
38 .set _FS, 36 #size 2
39 .set _GS, 38 #size 2
40 .set _EFLAGS, 40 #size 4
41 .set _EIP, 44 #size 4
42 .set _CS, 48 #size 2
43 .set _SS, 50 #size 2
44 .set IA32_REGS_SIZE, 52
45
46 .text
47 .code16
48
49 ASM_PFX(m16Start):
50
51 SavedGdt: .space 6
52
53 ASM_PFX(BackFromUserCode):
54 push %ss
55 push %cs
56
57 calll L_Base1 # push eip
58 L_Base1:
59 pushfl
60 cli # disable interrupts
61 push %gs
62 push %fs
63 push %es
64 push %ds
65 pushal
66 .byte 0x66, 0xba # mov edx, imm32
67 ASM_PFX(ThunkAttr): .space 4
68 testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15, %dl
69 jz 1f
70 movw $0x2401, %ax
71 int $0x15
72 cli # disable interrupts
73 jnc 2f
74 1:
75 testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL, %dl
76 jz 2f
77 inb $0x92, %al
78 orb $2, %al
79 outb %al, $0x92 # deactivate A20M#
80 2:
81 xorl %eax, %eax
82 movw %ss, %ax
83 leal IA32_REGS_SIZE(%esp), %ebp
84 mov %ebp, (_ESP - IA32_REGS_SIZE)(%bp)
85 mov (_EIP - IA32_REGS_SIZE)(%bp), %bx
86 shll $4, %eax
87 addl %eax, %ebp
88 .byte 0x66, 0xb8 # mov eax, imm32
89 SavedCr4: .space 4
90 movl %eax, %cr4
91 lgdtl %cs:(SavedGdt - L_Base1)(%bx)
92 .byte 0x66, 0xb8 # mov eax, imm32
93 SavedCr0: .space 4
94 movl %eax, %cr0
95 .byte 0xb8 # mov ax, imm16
96 SavedSs: .space 2
97 movl %eax, %ss
98 .byte 0x66, 0xbc # mov esp, imm32
99 SavedEsp: .space 4
100 lretl # return to protected mode
101
102 _EntryPoint: .long ASM_PFX(ToUserCode) - ASM_PFX(m16Start)
103 .word 0x8
104 _16Idtr: .word 0x3ff
105 .long 0
106 _16Gdtr: .word GdtEnd - _NullSegDesc - 1
107 _16GdtrBase: .long _NullSegDesc
108
109 ASM_PFX(ToUserCode):
110 movw %ss, %dx
111 movw %cx, %ss # set new segment selectors
112 movw %cx, %ds
113 movw %cx, %es
114 movw %cx, %fs
115 movw %cx, %gs
116 movl %eax, %cr0 # real mode starts at next instruction
117 # which (per SDM) *must* be a far JMP.
118 ljmpw $0,$0 # will be filled in by InternalAsmThunk16
119 L_Base: # to point here.
120 movl %ebp, %cr4
121 movw %si, %ss # set up 16-bit stack segment
122 xchgl %ebx, %esp # set up 16-bit stack pointer
123
124 movw IA32_REGS_SIZE(%esp), %bp # get BackToUserCode address from stack
125 mov %dx, %cs:(SavedSs - ASM_PFX(BackFromUserCode))(%bp)
126 mov %ebx, %cs:(SavedEsp - ASM_PFX(BackFromUserCode))(%bp)
127 lidtl %cs:(_16Idtr - ASM_PFX(BackFromUserCode))(%bp)
128 popal
129 pop %ds
130 pop %es
131 pop %fs
132 pop %gs
133 popfl
134 lretl # transfer control to user code
135
136 _NullSegDesc: .quad 0
137 _16CsDesc:
138 .word -1
139 .word 0
140 .byte 0
141 .byte 0x9b
142 .byte 0x8f # 16-bit segment, 4GB limit
143 .byte 0
144 _16DsDesc:
145 .word -1
146 .word 0
147 .byte 0
148 .byte 0x93
149 .byte 0x8f # 16-bit segment, 4GB limit
150 .byte 0
151 GdtEnd:
152
153 .code32
154 #
155 # @param RegSet The pointer to a IA32_DWORD_REGS structure
156 # @param Transition The pointer to the transition code
157 # @return The address of the 16-bit stack after returning from user code
158 #
159 ASM_PFX(InternalAsmThunk16):
160 push %ebp
161 push %ebx
162 push %esi
163 push %edi
164 push %ds
165 push %es
166 push %fs
167 push %gs
168 movl 36(%esp), %esi # esi <- RegSet
169 movzwl _SS(%esi), %edx
170 mov _ESP(%esi), %edi
171 add $(-(IA32_REGS_SIZE + 4)), %edi
172 movl %edi, %ebx # ebx <- stack offset
173 imul $0x10, %edx, %eax
174 push $(IA32_REGS_SIZE / 4)
175 addl %eax, %edi # edi <- linear address of 16-bit stack
176 pop %ecx
177 rep
178 movsl # copy RegSet
179 movl 40(%esp), %eax # eax <- address of transition code
180 movl %edx, %esi # esi <- 16-bit stack segment
181 lea (SavedCr0 - ASM_PFX(m16Start))(%eax), %edx
182 movl %eax, %ecx
183 andl $0xf, %ecx
184 shll $12, %eax
185 lea (ASM_PFX(BackFromUserCode) - ASM_PFX(m16Start))(%ecx), %ecx
186 movw %cx, %ax
187 stosl # [edi] <- return address of user code
188 addl $(L_Base - ASM_PFX(BackFromUserCode)), %eax
189 movl %eax, (L_Base - SavedCr0 - 4)(%edx)
190 sgdtl (SavedGdt - SavedCr0)(%edx)
191 sidtl 0x24(%esp)
192 movl %cr0, %eax
193 movl %eax, (%edx) # save CR0 in SavedCr0
194 andl $0x7ffffffe, %eax # clear PE, PG bits
195 movl %cr4, %ebp
196 mov %ebp, (SavedCr4 - SavedCr0)(%edx)
197 andl $0xffffffcf, %ebp # clear PAE, PSE bits
198 pushl $0x10
199 pop %ecx # ecx <- selector for data segments
200 lgdtl (_16Gdtr - SavedCr0)(%edx)
201 pushfl
202 lcall *(_EntryPoint - SavedCr0)(%edx)
203 popfl
204 lidtl 0x24(%esp)
205 lea -IA32_REGS_SIZE(%ebp), %eax
206 pop %gs
207 pop %fs
208 pop %es
209 pop %ds
210 pop %edi
211 pop %esi
212 pop %ebx
213 pop %ebp
214 ret
215
216 .const:
217
218 ASM_PFX(m16Size): .word ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start)
219 ASM_PFX(mThunk16Attr): .word ASM_PFX(ThunkAttr) - ASM_PFX(m16Start)
220 ASM_PFX(m16Gdt): .word _NullSegDesc - ASM_PFX(m16Start)
221 ASM_PFX(m16GdtrBase): .word _16GdtrBase - ASM_PFX(m16Start)
222 ASM_PFX(mTransition): .word _EntryPoint - ASM_PFX(m16Start)