1 /*
2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/arch/i386/arch.c
5 * PURPOSE: Boot Library Architectural Initialization for i386
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12
13 /* DATA VARIABLES ************************************************************/
14
15 BL_ARCH_CONTEXT FirmwareExecutionContext;
16 BL_ARCH_CONTEXT ApplicationExecutionContext;
17 PBL_ARCH_CONTEXT CurrentExecutionContext;
18
19 /* FUNCTIONS *****************************************************************/
20
21 VOID
22 DECLSPEC_NORETURN
ArchTrapNoProcess(VOID)23 ArchTrapNoProcess (
24 VOID
25 )
26 {
27 /* Do nothing, this is an unsupported debugging interrupt */
28 #if defined(__GNUC__)
29 __asm__ __volatile__ ("iret");
30 #elif defined (_MSC_VER)
31 _asm { iret };
32 #else
33 #error wtf are you using
34 #endif
35 __assume(0);
36 }
37
38 VOID
ArchSwitchContext(_In_ PBL_ARCH_CONTEXT NewContext,_In_ PBL_ARCH_CONTEXT OldContext)39 ArchSwitchContext (
40 _In_ PBL_ARCH_CONTEXT NewContext,
41 _In_ PBL_ARCH_CONTEXT OldContext
42 )
43 {
44 /* Are we switching to real mode? */
45 if (NewContext->Mode == BlRealMode)
46 {
47 /* Disable paging */
48 __writecr0(__readcr0() & ~CR0_PG);
49
50 /* Are we coming from PAE mode? */
51 if ((OldContext != NULL) && (OldContext->TranslationType == BlPae))
52 {
53 /* Turn off PAE */
54 __writecr4(__readcr4() & ~CR4_PAE);
55 }
56
57 /* Enable interrupts */
58 _enable();
59 }
60 else
61 {
62 /* Switching to protected mode -- disable interrupts if needed */
63 if (!(NewContext->ContextFlags & BL_CONTEXT_INTERRUPTS_ON))
64 {
65 _disable();
66 }
67
68 /* Are we enabling paging for the first time? */
69 if (NewContext->ContextFlags & BL_CONTEXT_PAGING_ON)
70 {
71 /* In PAE mode? */
72 if (NewContext->TranslationType == BlPae)
73 {
74 /* Turn on PAE */
75 __writecr4(__readcr4() | CR4_PAE);
76 }
77
78 /* Turn on paging */
79 __writecr0(__readcr0() | CR0_PG);
80 }
81 }
82 }
83
84 NTSTATUS
ArchInitializeContext(_In_ PBL_ARCH_CONTEXT Context)85 ArchInitializeContext (
86 _In_ PBL_ARCH_CONTEXT Context
87 )
88 {
89 NTSTATUS Status = STATUS_SUCCESS;
90
91 /* Are we initializing real mode? */
92 if (Context->Mode == BlRealMode)
93 {
94 /* Disable paging, enable interrupts */
95 Context->ContextFlags &= ~BL_CONTEXT_PAGING_ON;
96 Context->ContextFlags |= BL_CONTEXT_INTERRUPTS_ON;
97 }
98 else if (!(BlpApplicationFlags & BL_APPLICATION_FLAG_CONVERTED_FROM_EFI) ||
99 (BlpLibraryParameters.TranslationType != BlNone))
100 {
101 /* Read the current translation type */
102 Context->TranslationType = BlpLibraryParameters.TranslationType;
103
104 /* Disable paging (it's already on), enable interrupts */
105 Context->ContextFlags &= ~BL_CONTEXT_PAGING_ON;
106 Context->ContextFlags |= BL_CONTEXT_INTERRUPTS_ON;
107
108 /* Enable FXSR support in the FPU */
109 __writecr4(__readcr4() | CR4_FXSR);
110 }
111 else
112 {
113 /* Invalid context */
114 Status = STATUS_NOT_SUPPORTED;
115 }
116
117 /* Return context status */
118 return Status;
119 }
120
121 NTSTATUS
ArchInitializeContexts(VOID)122 ArchInitializeContexts (
123 VOID
124 )
125 {
126 PBL_ARCH_CONTEXT Context = NULL;
127 NTSTATUS EfiStatus, AppStatus;
128
129 /* No current context */
130 CurrentExecutionContext = NULL;
131
132 /* Setup the EFI and Application modes respectively */
133 FirmwareExecutionContext.Mode = BlRealMode;
134 ApplicationExecutionContext.Mode = BlProtectedMode;
135
136 /* Initialize application mode */
137 AppStatus = ArchInitializeContext(&ApplicationExecutionContext);
138 if (NT_SUCCESS(AppStatus))
139 {
140 /* Set it as current if it worked */
141 Context = &ApplicationExecutionContext;
142 CurrentExecutionContext = &ApplicationExecutionContext;
143 }
144
145 /* Initialize EFI mode */
146 EfiStatus = ArchInitializeContext(&FirmwareExecutionContext);
147 if (NT_SUCCESS(EfiStatus))
148 {
149 /* Set it as current if application context failed */
150 if (!NT_SUCCESS(AppStatus))
151 {
152 Context = &FirmwareExecutionContext;
153 CurrentExecutionContext = &FirmwareExecutionContext;
154 }
155
156 /* Switch to application mode, or EFI if that one failed */
157 ArchSwitchContext(Context, NULL);
158 EfiStatus = STATUS_SUCCESS;
159 }
160
161 /* Return initialization state */
162 return EfiStatus;
163 }
164
165 VOID
BlpArchSwitchContext(_In_ BL_ARCH_MODE NewMode)166 BlpArchSwitchContext (
167 _In_ BL_ARCH_MODE NewMode
168 )
169 {
170 PBL_ARCH_CONTEXT Context;
171
172 /* In real mode, use EFI, otherwise, use the application mode */
173 Context = &FirmwareExecutionContext;
174 if (NewMode != BlRealMode)
175 {
176 Context = &ApplicationExecutionContext;
177 }
178
179 /* Are we in a different mode? */
180 if (CurrentExecutionContext->Mode != NewMode)
181 {
182 /* Switch to the new one */
183 ArchSwitchContext(Context, CurrentExecutionContext);
184 CurrentExecutionContext = Context;
185 }
186 }
187
188 VOID
BlpArchEnableTranslation(VOID)189 BlpArchEnableTranslation (
190 VOID
191 )
192 {
193 PBL_ARCH_CONTEXT Context;
194
195 /* Does the current execution context already have paging enabled? */
196 Context = CurrentExecutionContext;
197 if (!(Context->ContextFlags & BL_CONTEXT_PAGING_ON))
198 {
199 /* No -- does it have interrupts enabled? */
200 if (Context->ContextFlags & BL_CONTEXT_INTERRUPTS_ON)
201 {
202 /* Disable them */
203 _disable();
204 Context->ContextFlags &= ~BL_CONTEXT_INTERRUPTS_ON;
205 }
206
207 /* Are we enabling PAE? */
208 if (Context->TranslationType == BlPae)
209 {
210 /* Make sure CR4 reflects this */
211 __writecr4(__readcr4() | CR4_PAE);
212 }
213
214 /* Enable paging in the CPU */
215 __writecr0(__readcr0() | CR0_PG);
216
217 /* Reflect that paging is enabled */
218 Context->ContextFlags |= BL_CONTEXT_PAGING_ON;
219 }
220 }
221
222 /*++
223 * @name BlpArchInitialize
224 *
225 * The BlpArchInitialize function initializes the Boot Library.
226 *
227 * @param Phase
228 * Pointer to the Boot Application Parameter Block.
229 *
230 * @return NT_SUCCESS if the boot library was loaded correctly, relevant error
231 * otherwise.
232 *
233 *--*/
234 NTSTATUS
BlpArchInitialize(_In_ ULONG Phase)235 BlpArchInitialize (
236 _In_ ULONG Phase
237 )
238 {
239 KDESCRIPTOR Idtr;
240 USHORT CodeSegment;
241 NTSTATUS Status;
242 PKIDTENTRY IdtBase;
243
244 /* Assume success */
245 Status = STATUS_SUCCESS;
246
247 /* Is this phase 1? */
248 if (Phase != 0)
249 {
250 /* Get the IDT */
251 __sidt(&Idtr);
252 IdtBase = (PKIDTENTRY)Idtr.Base;
253
254 /* Get the Code Segment */
255 #if defined(__GNUC__)
256 __asm__ __volatile__ ("mov %%cs,%0\n\t" :"=r" (CodeSegment));
257 #elif defined (_MSC_VER)
258 _asm { mov CodeSegment, cs };
259 #else
260 #error wtf are you using
261 #endif
262
263 /* Set up INT 3, ASSERT, and SECURITY_ASSERT to be no-op (for Rtl) */
264 IdtBase[3].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
265 IdtBase[3].Selector = CodeSegment;
266 IdtBase[3].Access = 0x8E00u;
267 IdtBase[3].ExtendedOffset = (ULONG_PTR)ArchTrapNoProcess >> 16;
268 IdtBase[0x2C].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
269 IdtBase[0x2C].Selector = CodeSegment;
270 IdtBase[0x2C].Access = 0x8E00u;
271 IdtBase[0x2C].ExtendedOffset = (ULONG_PTR)ArchTrapNoProcess >> 16;
272 IdtBase[0x2D].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
273 IdtBase[0x2D].Selector = CodeSegment;
274 IdtBase[0x2D].Access = 0x8E00u;
275 IdtBase[0x2D].ExtendedOffset = (ULONG_PTR)ArchTrapNoProcess >> 16;
276
277 /* Write the IDT back */
278 Idtr.Base = (ULONG)IdtBase;
279 __lidt(&Idtr);
280
281 /* Reset FPU state */
282 #if defined(__GNUC__)
283 __asm__ __volatile__ ("fninit");
284 #elif defined (_MSC_VER)
285 _asm { fninit };
286 #else
287 #error wtf are you using
288 #endif
289 }
290 else
291 {
292 /* Reset TSC if needed */
293 if ((__readmsr(0x10) >> 32) & 0xFFC00000)
294 {
295 __writemsr(0x10, 0);
296 }
297
298 /* Initialize all the contexts */
299 Status = ArchInitializeContexts();
300 }
301
302 /* Return initialization state */
303 return Status;
304 }
305
306