• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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