reactos/boot/environ/lib/arch/i386/arch.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;
}