xref: /reactos/boot/environ/lib/arch/i386/arch.c (revision c2c66aff)
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