[BOOTMGFW]:

- Add very early EFI Firmware and x86 Context Management Support.

svn path=/trunk/; revision=69041
This commit is contained in:
Alex Ionescu 2015-09-05 20:31:14 +00:00
parent 38f02bb9e7
commit c378dbf128
6 changed files with 606 additions and 12 deletions

View file

@ -11,14 +11,15 @@ list(APPEND BOOTLIB_SOURCE
app/bootmgr/bootmgr.h
lib/bootlib.c
lib/misc/bcd.c
lib/misc/util.c)
lib/misc/util.c
lib/firmware/efi/firmware.c)
if(ARCH STREQUAL "i386")
list(APPEND BOOTLIB_ASM_SOURCE
#lib/arch/i386/foo.asm
)
list(APPEND BOOTLIB_SOURCE
#lib/arch/i386/foo.c
lib/arch/i386/arch.c
)
elseif(ARCH STREQUAL "amd64")
list(APPEND BOOTLIB_ASM_SOURCE

View file

@ -677,7 +677,7 @@ EfiInitpCreateApplicationEntry (
/* Zero out the header, and write down the signature */
RtlZeroMemory(Entry, sizeof(BL_APPLICATION_ENTRY));
RtlCopyMemory(Entry->Signature, "BTAPENT", 7);
RtlCopyMemory(Entry->Signature, BL_APP_ENTRY_SIGNATURE, 7);
/* Check if a BCD object was passed on the command-line */
ObjectString = wcsstr(CommandLine, L"BCDOBJECT=");

View file

@ -19,6 +19,9 @@
/* NT Base Headers */
#include <ntifs.h>
/* NDK Headers */
#include <ntndk.h>
/* UEFI Headers */
#include <Uefi.h>
#include <DevicePath.h>
@ -28,6 +31,8 @@
#define BL_APPLICATION_FLAG_CONVERTED_FROM_EFI 0x01
#define BL_APP_ENTRY_SIGNATURE "BTAPENT"
#define BOOT_APPLICATION_SIGNATURE_1 'TOOB'
#define BOOT_APPLICATION_SIGNATURE_2 ' PPA'
@ -41,8 +46,25 @@
#define BL_APPLICATION_ENTRY_FLAG_NO_GUID 0x01
#define BL_CONTEXT_PAGING_ON 1
#define BL_CONTEXT_INTERRUPTS_ON 2
/* ENUMERATIONS **************************************************************/
typedef enum _BL_TRANSLATION_TYPE
{
BlNone,
BlVirtual,
BlPae,
BlMax
} BL_TRANSLATION_TYPE;
typedef enum _BL_ARCH_MODE
{
BlProtectedMode,
BlRealMode
} BL_ARCH_MODE;
//
// Boot Device Types
//
@ -325,6 +347,13 @@ typedef struct _BL_WINDOWS_LOAD_OPTIONS
WCHAR LoadOptions[ANYSIZE_ARRAY];
} BL_WINDOWS_LOAD_OPTIONS, *PBL_WINDOWS_LOAD_OPTIONS;
typedef struct _BL_ARCH_CONTEXT
{
BL_ARCH_MODE Mode;
BL_TRANSLATION_TYPE TranslationType;
ULONG ContextFlags;
} BL_ARCH_CONTEXT, *PBL_ARCH_CONTEXT;
/* INITIALIZATION ROUTINES ***************************************************/
NTSTATUS
@ -333,6 +362,17 @@ BlInitializeLibrary(
_In_ PBL_LIBRARY_PARAMETERS LibraryParameters
);
NTSTATUS
BlpArchInitialize (
_In_ ULONG Phase
);
NTSTATUS
BlpFwInitialize (
_In_ ULONG Phase,
_In_ PBL_FIRMWARE_DESCRIPTOR FirmwareParameters
);
/* UTILITY ROUTINES **********************************************************/
EFI_STATUS
@ -340,6 +380,11 @@ EfiGetEfiStatusCode(
_In_ NTSTATUS Status
);
NTSTATUS
EfiGetNtStatusCode (
_In_ EFI_STATUS EfiStatus
);
/* BCD ROUTINES **************************************************************/
ULONG
@ -347,4 +392,16 @@ BlGetBootOptionSize (
_In_ PBL_BCD_OPTION BcdOption
);
/* CONTEXT ROUTINES **********************************************************/
VOID
BlpArchSwitchContext (
_In_ BL_ARCH_MODE NewMode
);
extern ULONG BlpApplicationFlags;
extern BL_LIBRARY_PARAMETERS BlpLibraryParameters;
extern BL_TRANSLATION_TYPE MmTranslationType;
extern PBL_ARCH_CONTEXT CurrentExecutionContext;
#endif

View file

@ -0,0 +1,250 @@
/*
* 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(naked) fixme: gcc
ArchTrapNoProcess (
VOID
)
{
/* Do nothing, this is an unsupported debugging interrupt */
// _asm { iret } FIXME: GCC
}
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 != BlProtectedMode) Context = &ApplicationExecutionContext;
/* Are we in a different mode? */
if (CurrentExecutionContext->Mode != NewMode)
{
/* Switch to the new one */
ArchSwitchContext(Context, CurrentExecutionContext);
CurrentExecutionContext = Context;
}
}
/*++
* @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 */
// _asm { mov CodeSegment, cs } FIXME: GCC
CodeSegment = 8; // fix fix
/* 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 */
// __asm { fninit } FIXME: GCC
}
else
{
/* Reset TSC if needed */
if ((__readmsr(0x10) >> 32) & 0xFFC00000)
{
__writemsr(0x10, 0);
}
/* Initialize all the contexts */
Status = ArchInitializeContexts();
}
/* Return initialization state */
return Status;
}

View file

@ -1,10 +1,10 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/bootlib.c
* PURPOSE: Boot Library Initialization
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/bootlib.c
* PURPOSE: Boot Library Initialization
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
@ -13,6 +13,14 @@
/* DATA VARIABLES ************************************************************/
BL_LIBRARY_PARAMETERS BlpLibraryParameters;
PBL_DEVICE_DESCRIPTOR BlpBootDevice;
PWCHAR BlpApplicationBaseDirectory;
PBOOT_APPLICATION_PARAMETER_BLOCK BlpApplicationParameters;
BL_APPLICATION_ENTRY BlpApplicationEntry;
BOOLEAN BlpLibraryParametersInitialized;
/* temp */
BL_TRANSLATION_TYPE MmTranslationType;
/* FUNCTIONS *****************************************************************/
@ -37,10 +45,66 @@ InitializeLibrary (
_In_ PBL_LIBRARY_PARAMETERS LibraryParameters
)
{
DBG_UNREFERENCED_PARAMETER(BootAppParameters);
DBG_UNREFERENCED_PARAMETER(LibraryParameters);
NTSTATUS Status;
//PBL_MEMORY_DATA MemoryData;
PBL_APPLICATION_ENTRY AppEntry;
PBL_FIRMWARE_DESCRIPTOR FirmwareDescriptor;
ULONG_PTR ParamPointer = (ULONG_PTR)BootAppParameters;
return STATUS_NOT_IMPLEMENTED;
/* Validate correct Boot Application data */
if (!(BootAppParameters) ||
(BootAppParameters->Signature[0] != BOOT_APPLICATION_SIGNATURE_1) ||
(BootAppParameters->Signature[1] != BOOT_APPLICATION_SIGNATURE_2) ||
(BootAppParameters->Size < sizeof(*BootAppParameters)))
{
return STATUS_INVALID_PARAMETER;
}
/* Get sub-structures */
//MemoryData = (PBL_MEMORY_DATA)(ParamPointer + BootAppParameters->MemoryDataOffset);
FirmwareDescriptor = (PBL_FIRMWARE_DESCRIPTOR)(ParamPointer + BootAppParameters->FirmwareParametersOffset);
AppEntry = (PBL_APPLICATION_ENTRY)(ParamPointer + BootAppParameters->AppEntryOffset);
BlpBootDevice = (PBL_DEVICE_DESCRIPTOR)(ParamPointer + BootAppParameters->BootDeviceOffset);
BlpApplicationBaseDirectory = LibraryParameters->ApplicationBaseDirectory;
/* Initialize the firmware table */
Status = BlpFwInitialize(0, FirmwareDescriptor);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Find boot application entry */
if (strncmp(AppEntry->Signature, BL_APP_ENTRY_SIGNATURE, 7))
{
Status = STATUS_INVALID_PARAMETER_9;
}
/* Read parameters */
BlpApplicationParameters = BootAppParameters;
BlpLibraryParameters = *LibraryParameters;
/* Save the application entry */
if (AppEntry->Flags & 2)
{
AppEntry->Flags = (AppEntry->Flags & ~0x2) | 0x80;
}
BlpApplicationEntry = *AppEntry;
/* Everything has been captured */
BlpLibraryParametersInitialized = TRUE;
/* Initialize the architecture (PM or RM) switching */
Status = BlpArchInitialize(0);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
Status = STATUS_NOT_IMPLEMENTED;
Quickie:
return Status;
}
/*++

View file

@ -0,0 +1,222 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/firmware/efi/firmware.c
* PURPOSE: Boot Library Firmware Initialization for EFI
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
GUID EfiSimpleTextInputExProtocol = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
PBL_FIRMWARE_DESCRIPTOR EfiFirmwareParameters;
BL_FIRMWARE_DESCRIPTOR EfiFirmwareData;
EFI_HANDLE EfiImageHandle;
EFI_SYSTEM_TABLE* EfiSystemTable;
EFI_SYSTEM_TABLE *EfiST;
EFI_BOOT_SERVICES *EfiBS;
EFI_RUNTIME_SERVICES *EfiRT;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *EfiConOut;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *EfiConIn;
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *EfiConInEx;
/* FUNCTIONS *****************************************************************/
NTSTATUS
EfiOpenProtocol (
_In_ EFI_HANDLE Handle,
_In_ EFI_GUID *Protocol,
_Out_ PVOID* Interface
)
{
EFI_STATUS EfiStatus;
NTSTATUS Status;
BL_ARCH_MODE OldMode;
/* Are we using virtual memory/ */
if (MmTranslationType != BlNone)
{
/* We need complex tracking to make this work */
//Status = EfiVmOpenProtocol(Handle, Protocol, Interface);
Status = STATUS_NOT_SUPPORTED;
}
else
{
/* Are we in protected mode? */
OldMode = CurrentExecutionContext->Mode;
if (OldMode != BlRealMode)
{
/* FIXME: Not yet implemented */
return STATUS_NOT_IMPLEMENTED;
}
/* Are we on legacy 1.02? */
if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
{
/* Make the legacy call */
EfiStatus = EfiBS->HandleProtocol(Handle, Protocol, Interface);
}
else
{
/* Use the UEFI version */
EfiStatus = EfiBS->OpenProtocol(Handle,
Protocol,
Interface,
EfiImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
/* Switch back to protected mode if we came from there */
if (OldMode != BlRealMode)
{
BlpArchSwitchContext(OldMode);
}
}
/* Convert the error to an NTSTATUS */
Status = EfiGetNtStatusCode(EfiStatus);
}
/* Clear the interface on failure, and return the status */
if (!NT_SUCCESS(Status))
{
*Interface = NULL;
}
return Status;
}
NTSTATUS
EfiConInExSetState (
_In_ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *ConInEx,
_In_ EFI_KEY_TOGGLE_STATE* KeyToggleState
)
{
BL_ARCH_MODE OldMode;
EFI_STATUS EfiStatus;
/* Are we in protected mode? */
OldMode = CurrentExecutionContext->Mode;
if (OldMode != BlRealMode)
{
/* FIXME: Not yet implemented */
return STATUS_NOT_IMPLEMENTED;
}
/* Make the EFI call */
EfiStatus = ConInEx->SetState(ConInEx, KeyToggleState);
/* Switch back to protected mode if we came from there */
if (OldMode != BlRealMode)
{
BlpArchSwitchContext(OldMode);
}
/* Convert the error to an NTSTATUS */
return EfiGetNtStatusCode(EfiStatus);
}
NTSTATUS
EfiSetWatchdogTimer (
VOID
)
{
BL_ARCH_MODE OldMode;
EFI_STATUS EfiStatus;
/* Are we in protected mode? */
OldMode = CurrentExecutionContext->Mode;
if (OldMode != BlRealMode)
{
/* FIXME: Not yet implemented */
return STATUS_NOT_IMPLEMENTED;
}
/* Make the EFI call */
EfiStatus = EfiBS->SetWatchdogTimer(0, 0, 0, NULL);
/* Switch back to protected mode if we came from there */
if (OldMode != BlRealMode)
{
BlpArchSwitchContext(OldMode);
}
/* Convert the error to an NTSTATUS */
return EfiGetNtStatusCode(EfiStatus);
}
NTSTATUS
BlpFwInitialize (
_In_ ULONG Phase,
_In_ PBL_FIRMWARE_DESCRIPTOR FirmwareData
)
{
NTSTATUS Status = STATUS_SUCCESS;
EFI_KEY_TOGGLE_STATE KeyToggleState;
/* Check if we have vaild firmware data */
if (!(FirmwareData) || !(FirmwareData->Version))
{
return STATUS_INVALID_PARAMETER;
}
/* Check which boot phase we're in */
if (Phase != 0)
{
/* Memory manager is ready, open the extended input protocol */
Status = EfiOpenProtocol(EfiST->ConsoleInHandle,
&EfiSimpleTextInputExProtocol,
(PVOID*)&EfiConInEx);
if (NT_SUCCESS(Status))
{
/* Set the initial key toggle state */
KeyToggleState = EFI_TOGGLE_STATE_VALID | 40;
EfiConInExSetState(EfiST->ConsoleInHandle, &KeyToggleState);
}
/* Setup the watchdog timer */
EfiSetWatchdogTimer();
}
else
{
/* Make a copy of the parameters */
EfiFirmwareParameters = &EfiFirmwareData;
/* Check which version we received */
if (FirmwareData->Version == 1)
{
/* FIXME: Not supported */
Status = STATUS_NOT_SUPPORTED;
}
else if (FirmwareData->Version >= 2)
{
/* Version 2 -- save the data */
EfiFirmwareData = *FirmwareData;
EfiSystemTable = FirmwareData->SystemTable;
EfiImageHandle = FirmwareData->ImageHandle;
/* Set the EDK-II style variables as well */
EfiST = EfiSystemTable;
EfiBS = EfiSystemTable->BootServices;
EfiRT = EfiSystemTable->RuntimeServices;
EfiConOut = EfiSystemTable->ConOut;
EfiConIn = EfiSystemTable->ConIn;
EfiConInEx = NULL;
}
else
{
/* Unknown version */
Status = STATUS_NOT_SUPPORTED;
}
}
/* Return the initialization state */
return Status;
}