• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Execute 32-bit code in Long Mode
3   Provide a thunk function to transition from long mode to compatibility mode to execute 32-bit code and then transit
4   back to long mode.
5 
6   Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
7   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 #include "ScriptSave.h"
17 
18 #pragma pack(1)
19 typedef union {
20   struct {
21     UINT32  LimitLow    : 16;
22     UINT32  BaseLow     : 16;
23     UINT32  BaseMid     : 8;
24     UINT32  Type        : 4;
25     UINT32  System      : 1;
26     UINT32  Dpl         : 2;
27     UINT32  Present     : 1;
28     UINT32  LimitHigh   : 4;
29     UINT32  Software    : 1;
30     UINT32  Reserved    : 1;
31     UINT32  DefaultSize : 1;
32     UINT32  Granularity : 1;
33     UINT32  BaseHigh    : 8;
34   } Bits;
35   UINT64  Uint64;
36 } IA32_GDT;
37 
38 ///
39 /// Byte packed structure for an IA-32 Interrupt Gate Descriptor.
40 ///
41 typedef union {
42   struct {
43     UINT32  OffsetLow:16;   ///< Offset bits 15..0.
44     UINT32  Selector:16;    ///< Selector.
45     UINT32  Reserved_0:8;   ///< Reserved.
46     UINT32  GateType:8;     ///< Gate Type.  See #defines above.
47     UINT32  OffsetHigh:16;  ///< Offset bits 31..16.
48   } Bits;
49   UINT64  Uint64;
50 } IA32_IDT_ENTRY;
51 #pragma pack()
52 
53 #define COMPATIBILITY_MODE_SELECTOR  8
54 
55 //
56 // Global Descriptor Table (GDT)
57 //
58 GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
59   {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}}, /* 0x0:  reserve */
60   {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  0, 1,  1,  0}}, /* 0x8:  compatibility mode */
61   {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  1, 0,  1,  0}}, /* 0x10: for long mode */
62   {{0xFFFF, 0,  0,  0x3,  1,  0,  1,  0xF,  0,  0, 1,  1,  0}}, /* 0x18: data */
63   {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}}, /* 0x20: reserve */
64 };
65 
66 //
67 // IA32 Gdt register
68 //
69 GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
70   sizeof (mGdtEntries) - 1,
71   (UINTN) mGdtEntries
72   };
73 /**
74   Assembly function to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
75   long mode.
76   @param  Function     The 32bit code entry to be executed.
77   @param  Param1       The first parameter to pass to 32bit code
78   @param  Param2       The second parameter to pass to 32bit code
79   @param  InternalGdtr The GDT and GDT descriptor used by this library
80 
81   @retval EFI_SUCCESS  Execute 32bit code successfully.
82   @retval other        Something wrong when execute the 32bit code
83 **/
84 EFI_STATUS
85 AsmExecute32BitCode (
86   IN UINT64           Function,
87   IN UINT64           Param1,
88   IN UINT64           Param2,
89   IN IA32_DESCRIPTOR  *InternalGdtr
90   );
91 
92 /**
93   Wrapper for a thunk  to transition from long mode to compatibility mode to execute 32-bit code and then transit back to
94   long mode.
95 
96   @param  Function     The 32bit code entry to be executed.
97   @param  Param1       The first parameter to pass to 32bit code
98   @param  Param2       The second parameter to pass to 32bit code
99   @retval EFI_SUCCESS  Execute 32bit code successfully.
100   @retval other        Something wrong when execute the 32bit code
101 
102 **/
103 EFI_STATUS
Execute32BitCode(IN UINT64 Function,IN UINT64 Param1,IN UINT64 Param2)104 Execute32BitCode (
105   IN UINT64      Function,
106   IN UINT64      Param1,
107   IN UINT64      Param2
108   )
109 {
110   EFI_STATUS                 Status;
111   IA32_DESCRIPTOR            *Ia32Idtr;
112   IA32_DESCRIPTOR            X64Idtr;
113   UINTN                      Ia32IdtEntryCount;
114   UINTN                      Index;
115   IA32_IDT_ENTRY             *Ia32IdtEntry;
116 
117   //
118   // Save x64 IDT Descriptor
119   //
120   AsmReadIdtr ((IA32_DESCRIPTOR *) &X64Idtr);
121 
122   //
123   // Get the IA32 IDT Descriptor saved in 16 bytes in front of X64 IDT table.
124   //
125   Ia32Idtr = (IA32_DESCRIPTOR *) (UINTN) (X64Idtr.Base - 16);
126   Ia32IdtEntryCount = (Ia32Idtr->Limit + 1) / sizeof (IA32_IDT_ENTRY);
127 
128   Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
129   for (Index = 0; Index < Ia32IdtEntryCount; Index ++ ) {
130     //
131     // Use the new Code Selector value
132     //
133     Ia32IdtEntry[Index].Bits.Selector = COMPATIBILITY_MODE_SELECTOR;
134   }
135 
136   //
137   // Setup IA32 IDT table for 32-bit framework Boot Script code
138   //
139   AsmWriteIdtr (Ia32Idtr);
140 
141   ASSERT (Function != 0);
142 
143   Status = AsmExecute32BitCode (
144              Function,
145              Param1,
146              Param2,
147              &mGdt
148              );
149 
150   //
151   // Restore X64 IDT table
152   //
153   AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr);
154 
155   return Status;
156 }
157 
158