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