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