]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Foundation/Library/Thunk16/X86Thunk.c
Maintainers.txt: Remove EdkCompatibilityPkg information
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / Thunk16 / X86Thunk.c
CommitLineData
3eb9473e 1/*++\r
2\r
515327a3 3Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
4ea9375a 4This program and the accompanying materials \r
3eb9473e 5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12\r
13Module Name:\r
14\r
15 x86Thunk.c\r
16\r
17Abstract:\r
18\r
19 Real Mode Thunk Functions\r
20\r
21--*/\r
22\r
23#include "Thunk16Lib.h"\r
24#include "EfiCommonLib.h"\r
25\r
3eb9473e 26extern CONST UINTN mCode16Size;\r
27\r
28extern\r
29IA32_REGISTER_SET *\r
4798ea5b 30EFIAPI\r
3eb9473e 31_Thunk16 (\r
32 IN OUT IA32_REGISTER_SET *RegisterSet,\r
33 IN UINT32 ThunkFlags,\r
34 IN UINT32 RealModeCs\r
35 );\r
36\r
37extern\r
38VOID\r
4798ea5b 39EFIAPI\r
3eb9473e 40_Code16Addr (\r
41 VOID\r
42 );\r
43\r
44VOID\r
4798ea5b 45EFIAPI\r
3eb9473e 46AsmFxRestore (\r
47 IN CONST IA32_FX_BUFFER *Buffer\r
48 );\r
49\r
50VOID\r
4798ea5b 51EFIAPI\r
3eb9473e 52AsmFxSave (\r
53 OUT IA32_FX_BUFFER *Buffer\r
54 );\r
55\r
3e99020d
LG
56UINTN\r
57EFIAPI\r
58AsmGetEflags (\r
59 VOID\r
60 );\r
61\r
62VOID\r
63EFIAPI\r
64AsmSetEflags (\r
65 IN UINTN Eflags\r
66 );\r
67\r
3eb9473e 68//\r
69// Implementation\r
70//\r
71STATIC\r
72IA32_REGISTER_SET *\r
73AsmThunk16 (\r
74 IN THUNK_CONTEXT *ThunkContext,\r
75 IN OUT IA32_REGISTER_SET *RegisterSet,\r
76 IN UINT32 ThunkFlags\r
77 )\r
78/*++\r
79\r
80Routine Description:\r
81\r
82 Do the 16-bit thunk code.\r
83\r
84 NOTE: This function must be called on TPL_HIGH_LEVEL or with interrupts\r
85 disabled because of GDTR and IDTR manipulations.\r
86 This function must be placed in identity mapped pages.\r
87\r
88Arguments:\r
89\r
90 ThunkContext - Thunk context to use.\r
91 RegisterSet - CPU registers would be set to the values contained in this\r
92 structure before making the far call. Then CPU registers are\r
93 copied back to this structure.\r
94 SS:ESP points to the real mode stack if THUNK_USER_STACK is\r
95 set on input, otherwise ignored.\r
96 EFlages is ignored on input.\r
97 On output, values of CS, EIP, SS and ESP should be ignored.\r
98 ThunkFlags - 2 flags have currently been defined, THUNK_SAVE_FP_STATE and\r
99 THUNK_USER_STACK.\r
100 THUNK_SAVE_FP_STATE - FPU state would be saved/restored\r
101 before/after calling real mode code.\r
102 THUNK_USER_STACK - The stack specified by SS:ESP would be\r
103 used instead of the default stack.\r
104\r
105Returns:\r
106\r
107 RegisterSet is returned.\r
108\r
109--*/\r
110{\r
111 IA32_FX_BUFFER *FpSavedState;\r
112 UINT8 FpBuffer[sizeof (*FpSavedState) + 0x10];\r
3e99020d 113 UINTN Eflags;\r
3eb9473e 114\r
115 FpSavedState = (IA32_FX_BUFFER*)(((UINTN)FpBuffer + 0xf) & ~0xf);\r
116\r
117 if (!(ThunkFlags & THUNK_USER_STACK)) {\r
118 RegisterSet->E.ESP = (UINT16)ThunkContext->DefaultStack;\r
119 RegisterSet->E.SS = (UINT16)((ThunkContext->DefaultStack >> 4) & 0xf000);\r
120 }\r
121\r
122 if (ThunkFlags & THUNK_SAVE_FP_STATE) {\r
123 AsmFxSave (FpSavedState);\r
124 }\r
125\r
3e99020d
LG
126 Eflags = AsmGetEflags ();\r
127\r
3eb9473e 128 EfiCommonLibCopyMem (\r
129 RegisterSet,\r
130 _Thunk16 (\r
131 RegisterSet,\r
132 (UINT16)(ThunkFlags >> 16),\r
133 ThunkContext->RealModeBuffer >> 4\r
134 ),\r
135 sizeof (*RegisterSet)\r
136 );\r
137\r
3e99020d
LG
138 AsmSetEflags (Eflags);\r
139\r
3eb9473e 140 if (ThunkFlags & THUNK_SAVE_FP_STATE) {\r
141 AsmFxRestore (FpSavedState);\r
142 }\r
143\r
144 return RegisterSet;\r
145}\r
146\r
147UINTN\r
148EFIAPI\r
149AsmThunk16GetProperties (\r
150 OUT UINTN *MinimumStackSize\r
151 )\r
152/*++\r
153\r
154Routine Description:\r
155\r
156 Returns the properties of this real mode thunk implementation. Currently\r
157 there are 2 properties has been defined, the minimum real mode buffer size\r
158 and the minimum stack size.\r
159\r
160Arguments:\r
161\r
162 MinimumStackSize - The minimum size required for a 16-bit stack.\r
163\r
164Returns:\r
165\r
166 The minimum size of the real mode buffer needed by this thunk implementation\r
167 is returned.\r
168\r
169--*/\r
170{\r
171 //\r
172 // This size should be large enough to hold the register set as well as saved\r
173 // CPU contexts including GDTR, CR0 and CR4\r
174 //\r
175 if (MinimumStackSize) {\r
176 *MinimumStackSize = sizeof (IA32_REGISTER_SET) + 0x200;\r
177 }\r
178\r
179 return mCode16Size;\r
180}\r
181\r
182THUNK_CONTEXT *\r
183EFIAPI\r
184AsmThunk16SetProperties (\r
185 OUT THUNK_CONTEXT *ThunkContext,\r
186 IN VOID *RealModeBuffer,\r
187 IN UINTN BufferSize\r
188 )\r
189/*++\r
190\r
191Routine Description:\r
192\r
193 Tell this real mode thunk implementation the address and size of the real\r
194 mode buffer needed.\r
195\r
196Arguments:\r
197\r
198 ThunkContext - The thunk context whose properties to set.\r
199 RealModeBuffer - The address of the buffer allocated by caller. It should be\r
200 aligned on a 16-byte boundary.\r
201 This buffer must be in identity mapped pages.\r
202 BufferSize - The size of RealModeBuffer. Must be larger than the minimum\r
203 size required as returned by AsmThunk16GetProperties().\r
204\r
205Returns:\r
206\r
207 None\r
208\r
209--*/\r
210{\r
211 BufferSize &= ~3;\r
212\r
213 ThunkContext->RealModeBuffer = (UINT32)(UINTN)RealModeBuffer;\r
214 ThunkContext->DefaultStack = (UINT32)(ThunkContext->RealModeBuffer + BufferSize);\r
215 EfiCommonLibCopyMem (RealModeBuffer, (VOID*)(UINTN)_Code16Addr, mCode16Size);\r
216\r
217 return ThunkContext;\r
218}\r
219\r
3e99020d
LG
220#pragma pack (1)\r
221\r
222typedef struct {\r
223 UINT32 EDI;\r
224 UINT32 ESI;\r
225 UINT32 EBP;\r
226 UINT32 ESP;\r
227 UINT32 EBX;\r
228 UINT32 EDX;\r
229 UINT32 ECX;\r
230 UINT32 EAX;\r
231 UINT16 DS;\r
232 UINT16 ES;\r
233 UINT16 FS;\r
234 UINT16 GS;\r
235 UINTN EFLAGS;\r
236 UINT32 EIP;\r
237 UINT16 CS;\r
238 UINT16 SS;\r
239} IA32_REGS;\r
240\r
241typedef struct {\r
242 UINT16 Limit;\r
243 UINT32 Base;\r
244} IA32_DESC;\r
245\r
246typedef struct {\r
247 UINT32 RetEip;\r
248 UINT16 RetCs;\r
249 UINT16 ThunkFlags;\r
250#ifdef EFI32\r
251 UINT32 SavedEsp;\r
252 UINT16 SavedSs;\r
253#endif\r
254 IA32_DESC SavedGdtr;\r
255#ifdef EFIX64\r
256 UINT16 Resvd1;\r
257#endif\r
258 UINT32 SavedCr0;\r
259 UINT32 SavedCr4;\r
260} _STK16;\r
261#pragma pack ()\r
262\r
263#define STACK_PARAM_SIZE 16\r
264\r
265BOOLEAN\r
266AsmThunk16SetUserStack (\r
267 IN THUNK_CONTEXT *ThunkContext,\r
268 IN VOID *Stack,\r
269 IN UINTN StackSize\r
270 )\r
271{\r
272 if (StackSize > STACK_PARAM_SIZE) {\r
273 return FALSE;\r
274 }\r
275\r
276 EfiCommonLibCopyMem ((VOID *)(UINTN)(ThunkContext->DefaultStack - sizeof(_STK16) - sizeof(IA32_REGS) - STACK_PARAM_SIZE), Stack, StackSize);\r
277\r
278 return TRUE;\r
279}\r
280\r
3eb9473e 281VOID\r
282EFIAPI\r
283AsmThunk16Destroy (\r
284 IN OUT THUNK_CONTEXT *ThunkContext\r
285 )\r
286/*++\r
287\r
288Routine Description:\r
289\r
290 Reset all internal states to their initial values. The caller should not\r
291 release the real mode buffer until after a call to this function.\r
292\r
293Arguments:\r
294\r
295 ThunkContext - The thunk context to destroy.\r
296\r
297Returns:\r
298\r
299 None\r
300\r
301--*/\r
302{\r
303 ThunkContext->RealModeBuffer = 0;\r
304}\r
305\r
306IA32_REGISTER_SET *\r
307EFIAPI\r
308AsmThunk16FarCall86 (\r
309 IN THUNK_CONTEXT *ThunkContext,\r
310 IN OUT IA32_REGISTER_SET *RegisterSet,\r
311 IN UINT32 Flags\r
312 )\r
313/*++\r
314\r
315Routine Description:\r
316\r
317 Make a far call to 16-bit code.\r
318\r
319 NOTE: This function must be called on TPL_HIGH_LEVEL or with interrupts\r
320 disabled because of GDTR and IDTR manipulations.\r
321 This function must be placed in identity mapped pages.\r
322\r
323Arguments:\r
324\r
325 ThunkContext - Thunk context to use.\r
326 RegisterSet - CPU registers would be set to the values contained in this\r
327 structure before making the far call. Then CPU registers are\r
328 copied back to this structure.\r
329 CS:EIP points to the real mode code being called on input.\r
330 SS:ESP points to the real mode stack if THUNK_USER_STACK is\r
331 set on input, otherwise ignored.\r
332 EFlages is ignored on input.\r
333 On output, values of CS, EIP, SS and ESP should be ignored.\r
3e99020d
LG
334 ThunkFlags - THUNK_USER_STACK: The stack specified by SS:ESP would be\r
335 used instead of the default stack.\r
3eb9473e 336\r
337Returns:\r
338\r
339 RegisterSet is returned.\r
340\r
341--*/\r
342{\r
343 return AsmThunk16 (ThunkContext, RegisterSet, Flags);\r
344}\r
345\r
346IA32_REGISTER_SET *\r
347EFIAPI\r
348AsmThunk16Int86 (\r
349 IN THUNK_CONTEXT *ThunkContext,\r
350 IN UINT8 IntNumber,\r
351 IN OUT IA32_REGISTER_SET *RegisterSet,\r
352 IN UINT32 Flags\r
353 )\r
354/*++\r
355\r
356Routine Description:\r
357\r
358 Invoke a 16-bit interrupt handler.\r
359\r
360 NOTE: This function must be called on TPL_HIGH_LEVEL or with interrupts\r
361 disabled because of GDTR and IDTR manipulations.\r
362 This function must be placed in identity mapped pages.\r
363\r
364Arguments:\r
365\r
366 ThunkContext - Thunk context to use.\r
367 IntNumber - The ordinal of the interrupt handler ranging from 0 to 255.\r
368 RegisterSet - CPU registers would be set to the values contained in this\r
369 structure before making the far call. Then CPU registers are\r
370 copied back to this structure.\r
371 SS:ESP points to the real mode stack if THUNK_USER_STACK is\r
372 set on input, otherwise ignored.\r
373 EFlages is ignored on input.\r
374 On output, values of CS, EIP, SS and ESP should be ignored.\r
3e99020d
LG
375 ThunkFlags - THUNK_USER_STACK: The stack specified by SS:ESP would be\r
376 used instead of the default stack.\r
3eb9473e 377\r
378Returns:\r
379\r
380 RegisterSet is returned.\r
381\r
382--*/\r
383{\r
515327a3 384 UINT32 *VectorBase;\r
385 \r
386 //\r
387 // The base address of legacy interrupt vector table is 0.\r
388 // We use this base address to get the legacy interrupt handler.\r
389 //\r
390 VectorBase = 0;\r
391 RegisterSet->E.EIP = (UINT16)(VectorBase)[IntNumber];\r
392 RegisterSet->E.CS = (UINT16)((VectorBase)[IntNumber] >> 16);\r
3eb9473e 393\r
394 return AsmThunk16 (ThunkContext, RegisterSet, Flags | THUNK_INTERRUPT);\r
395}\r