mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 12:26:32 +00:00
306 lines
7.9 KiB
C
306 lines
7.9 KiB
C
/*
|
|
* COPYRIGHT: See COPYING.ARM in the top level directory
|
|
* PROJECT: ReactOS UEFI Boot Library
|
|
* FILE: boot/environ/lib/arch/i386/arch.c
|
|
* PURPOSE: Boot Library Architectural Initialization for i386
|
|
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include "bl.h"
|
|
|
|
/* DATA VARIABLES ************************************************************/
|
|
|
|
BL_ARCH_CONTEXT FirmwareExecutionContext;
|
|
BL_ARCH_CONTEXT ApplicationExecutionContext;
|
|
PBL_ARCH_CONTEXT CurrentExecutionContext;
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
VOID
|
|
DECLSPEC_NORETURN
|
|
ArchTrapNoProcess (
|
|
VOID
|
|
)
|
|
{
|
|
/* Do nothing, this is an unsupported debugging interrupt */
|
|
#if defined(__GNUC__)
|
|
__asm__ __volatile__ ("iret");
|
|
#elif defined (_MSC_VER)
|
|
_asm { iret };
|
|
#else
|
|
#error wtf are you using
|
|
#endif
|
|
__assume(0);
|
|
}
|
|
|
|
VOID
|
|
ArchSwitchContext (
|
|
_In_ PBL_ARCH_CONTEXT NewContext,
|
|
_In_ PBL_ARCH_CONTEXT OldContext
|
|
)
|
|
{
|
|
/* Are we switching to real mode? */
|
|
if (NewContext->Mode == BlRealMode)
|
|
{
|
|
/* Disable paging */
|
|
__writecr0(__readcr0() & ~CR0_PG);
|
|
|
|
/* Are we coming from PAE mode? */
|
|
if ((OldContext != NULL) && (OldContext->TranslationType == BlPae))
|
|
{
|
|
/* Turn off PAE */
|
|
__writecr4(__readcr4() & ~CR4_PAE);
|
|
}
|
|
|
|
/* Enable interrupts */
|
|
_enable();
|
|
}
|
|
else
|
|
{
|
|
/* Switching to protected mode -- disable interrupts if needed */
|
|
if (!(NewContext->ContextFlags & BL_CONTEXT_INTERRUPTS_ON))
|
|
{
|
|
_disable();
|
|
}
|
|
|
|
/* Are we enabling paging for the first time? */
|
|
if (NewContext->ContextFlags & BL_CONTEXT_PAGING_ON)
|
|
{
|
|
/* In PAE mode? */
|
|
if (NewContext->TranslationType == BlPae)
|
|
{
|
|
/* Turn on PAE */
|
|
__writecr4(__readcr4() | CR4_PAE);
|
|
}
|
|
|
|
/* Turn on paging */
|
|
__writecr0(__readcr0() | CR0_PG);
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
ArchInitializeContext (
|
|
_In_ PBL_ARCH_CONTEXT Context
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
/* Are we initializing real mode? */
|
|
if (Context->Mode == BlRealMode)
|
|
{
|
|
/* Disable paging, enable interrupts */
|
|
Context->ContextFlags &= ~BL_CONTEXT_PAGING_ON;
|
|
Context->ContextFlags |= BL_CONTEXT_INTERRUPTS_ON;
|
|
}
|
|
else if (!(BlpApplicationFlags & BL_APPLICATION_FLAG_CONVERTED_FROM_EFI) ||
|
|
(BlpLibraryParameters.TranslationType != BlNone))
|
|
{
|
|
/* Read the current translation type */
|
|
Context->TranslationType = BlpLibraryParameters.TranslationType;
|
|
|
|
/* Disable paging (it's already on), enable interrupts */
|
|
Context->ContextFlags &= ~BL_CONTEXT_PAGING_ON;
|
|
Context->ContextFlags |= BL_CONTEXT_INTERRUPTS_ON;
|
|
|
|
/* Enable FXSR support in the FPU */
|
|
__writecr4(__readcr4() | CR4_FXSR);
|
|
}
|
|
else
|
|
{
|
|
/* Invalid context */
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
/* Return context status */
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ArchInitializeContexts (
|
|
VOID
|
|
)
|
|
{
|
|
PBL_ARCH_CONTEXT Context = NULL;
|
|
NTSTATUS EfiStatus, AppStatus;
|
|
|
|
/* No current context */
|
|
CurrentExecutionContext = NULL;
|
|
|
|
/* Setup the EFI and Application modes respectively */
|
|
FirmwareExecutionContext.Mode = BlRealMode;
|
|
ApplicationExecutionContext.Mode = BlProtectedMode;
|
|
|
|
/* Initialize application mode */
|
|
AppStatus = ArchInitializeContext(&ApplicationExecutionContext);
|
|
if (NT_SUCCESS(AppStatus))
|
|
{
|
|
/* Set it as current if it worked */
|
|
Context = &ApplicationExecutionContext;
|
|
CurrentExecutionContext = &ApplicationExecutionContext;
|
|
}
|
|
|
|
/* Initialize EFI mode */
|
|
EfiStatus = ArchInitializeContext(&FirmwareExecutionContext);
|
|
if (NT_SUCCESS(EfiStatus))
|
|
{
|
|
/* Set it as current if application context failed */
|
|
if (!NT_SUCCESS(AppStatus))
|
|
{
|
|
Context = &FirmwareExecutionContext;
|
|
CurrentExecutionContext = &FirmwareExecutionContext;
|
|
}
|
|
|
|
/* Switch to application mode, or EFI if that one failed */
|
|
ArchSwitchContext(Context, NULL);
|
|
EfiStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Return initialization state */
|
|
return EfiStatus;
|
|
}
|
|
|
|
VOID
|
|
BlpArchSwitchContext (
|
|
_In_ BL_ARCH_MODE NewMode
|
|
)
|
|
{
|
|
PBL_ARCH_CONTEXT Context;
|
|
|
|
/* In real mode, use EFI, otherwise, use the application mode */
|
|
Context = &FirmwareExecutionContext;
|
|
if (NewMode != BlRealMode)
|
|
{
|
|
Context = &ApplicationExecutionContext;
|
|
}
|
|
|
|
/* Are we in a different mode? */
|
|
if (CurrentExecutionContext->Mode != NewMode)
|
|
{
|
|
/* Switch to the new one */
|
|
ArchSwitchContext(Context, CurrentExecutionContext);
|
|
CurrentExecutionContext = Context;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
BlpArchEnableTranslation (
|
|
VOID
|
|
)
|
|
{
|
|
PBL_ARCH_CONTEXT Context;
|
|
|
|
/* Does the current execution context already have paging enabled? */
|
|
Context = CurrentExecutionContext;
|
|
if (!(Context->ContextFlags & BL_CONTEXT_PAGING_ON))
|
|
{
|
|
/* No -- does it have interrupts enabled? */
|
|
if (Context->ContextFlags & BL_CONTEXT_INTERRUPTS_ON)
|
|
{
|
|
/* Disable them */
|
|
_disable();
|
|
Context->ContextFlags &= ~BL_CONTEXT_INTERRUPTS_ON;
|
|
}
|
|
|
|
/* Are we enabling PAE? */
|
|
if (Context->TranslationType == BlPae)
|
|
{
|
|
/* Make sure CR4 reflects this */
|
|
__writecr4(__readcr4() | CR4_PAE);
|
|
}
|
|
|
|
/* Enable paging in the CPU */
|
|
__writecr0(__readcr0() | CR0_PG);
|
|
|
|
/* Reflect that paging is enabled */
|
|
Context->ContextFlags |= BL_CONTEXT_PAGING_ON;
|
|
}
|
|
}
|
|
|
|
/*++
|
|
* @name BlpArchInitialize
|
|
*
|
|
* The BlpArchInitialize function initializes the Boot Library.
|
|
*
|
|
* @param Phase
|
|
* Pointer to the Boot Application Parameter Block.
|
|
*
|
|
* @return NT_SUCCESS if the boot library was loaded correctly, relevant error
|
|
* otherwise.
|
|
*
|
|
*--*/
|
|
NTSTATUS
|
|
BlpArchInitialize (
|
|
_In_ ULONG Phase
|
|
)
|
|
{
|
|
KDESCRIPTOR Idtr;
|
|
USHORT CodeSegment;
|
|
NTSTATUS Status;
|
|
PKIDTENTRY IdtBase;
|
|
|
|
/* Assume success */
|
|
Status = STATUS_SUCCESS;
|
|
|
|
/* Is this phase 1? */
|
|
if (Phase != 0)
|
|
{
|
|
/* Get the IDT */
|
|
__sidt(&Idtr);
|
|
IdtBase = (PKIDTENTRY)Idtr.Base;
|
|
|
|
/* Get the Code Segment */
|
|
#if defined(__GNUC__)
|
|
__asm__ __volatile__ ("mov %%cs,%0\n\t" :"=r" (CodeSegment));
|
|
#elif defined (_MSC_VER)
|
|
_asm { mov CodeSegment, cs };
|
|
#else
|
|
#error wtf are you using
|
|
#endif
|
|
|
|
/* Set up INT 3, ASSERT, and SECURITY_ASSERT to be no-op (for Rtl) */
|
|
IdtBase[3].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
|
|
IdtBase[3].Selector = CodeSegment;
|
|
IdtBase[3].Access = 0x8E00u;
|
|
IdtBase[3].ExtendedOffset = (ULONG_PTR)ArchTrapNoProcess >> 16;
|
|
IdtBase[0x2C].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
|
|
IdtBase[0x2C].Selector = CodeSegment;
|
|
IdtBase[0x2C].Access = 0x8E00u;
|
|
IdtBase[0x2C].ExtendedOffset = (ULONG_PTR)ArchTrapNoProcess >> 16;
|
|
IdtBase[0x2D].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
|
|
IdtBase[0x2D].Selector = CodeSegment;
|
|
IdtBase[0x2D].Access = 0x8E00u;
|
|
IdtBase[0x2D].ExtendedOffset = (ULONG_PTR)ArchTrapNoProcess >> 16;
|
|
|
|
/* Write the IDT back */
|
|
Idtr.Base = (ULONG)IdtBase;
|
|
__lidt(&Idtr);
|
|
|
|
/* Reset FPU state */
|
|
#if defined(__GNUC__)
|
|
__asm__ __volatile__ ("fninit");
|
|
#elif defined (_MSC_VER)
|
|
_asm { fninit };
|
|
#else
|
|
#error wtf are you using
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
/* Reset TSC if needed */
|
|
if ((__readmsr(0x10) >> 32) & 0xFFC00000)
|
|
{
|
|
__writemsr(0x10, 0);
|
|
}
|
|
|
|
/* Initialize all the contexts */
|
|
Status = ArchInitializeContexts();
|
|
}
|
|
|
|
/* Return initialization state */
|
|
return Status;
|
|
}
|
|
|