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