aboutsummaryrefslogtreecommitdiff
path: root/Application/Loader
diff options
context:
space:
mode:
Diffstat (limited to 'Application/Loader')
-rw-r--r--Application/Loader/Loader.c653
-rw-r--r--Application/Loader/Loader.inf64
-rw-r--r--Application/Loader/Loader.vcxproj40
-rw-r--r--Application/Loader/Loader.vcxproj.filters26
4 files changed, 783 insertions, 0 deletions
diff --git a/Application/Loader/Loader.c b/Application/Loader/Loader.c
new file mode 100644
index 0000000..4d94ec6
--- /dev/null
+++ b/Application/Loader/Loader.c
@@ -0,0 +1,653 @@
+#include <Uefi.h>
+#include <Pi/PiDxeCis.h>
+
+#include <Protocol/EfiGuard.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/LoadedImage.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+
+//
+// Define whether the loader should prompt for driver configuration or not.
+// If this is 0, the defaults are used and Windows will be booted with no user interaction.
+// This can be overridden on the command line with -D CONFIGURE_DRIVER=[0|1]
+//
+#ifndef CONFIGURE_DRIVER
+#define CONFIGURE_DRIVER 0
+#endif
+
+
+//
+// Paths to the driver to try
+//
+#define EFIGUARD_DRIVER_FILENAME L"EfiGuardDxe.efi"
+STATIC CHAR16* mDriverPaths[] = {
+ L"\\EFI\\Boot\\" EFIGUARD_DRIVER_FILENAME,
+ L"\\EFI\\" EFIGUARD_DRIVER_FILENAME,
+ L"\\" EFIGUARD_DRIVER_FILENAME
+};
+
+
+STATIC
+BOOLEAN
+EFIAPI
+WaitForKey(
+ )
+{
+ EFI_INPUT_KEY Key = { 0, 0 };
+ UINTN Index = 0;
+ gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index);
+ gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
+
+ return (BOOLEAN)(Key.ScanCode != SCAN_ESC);
+}
+
+#if CONFIGURE_DRIVER
+
+STATIC
+UINT16
+EFIAPI
+PromptInput(
+ IN CONST UINT16* AcceptedChars,
+ IN UINTN NumAcceptedChars,
+ IN UINT16 DefaultSelection
+ )
+{
+ UINT16 SelectedChar;
+
+ while (TRUE)
+ {
+ SelectedChar = CHAR_NULL;
+
+ EFI_INPUT_KEY Key = { 0, 0 };
+ UINTN Index = 0;
+ gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index);
+ gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
+
+ if (Key.UnicodeChar == CHAR_LINEFEED || Key.UnicodeChar == CHAR_CARRIAGE_RETURN)
+ {
+ SelectedChar = DefaultSelection;
+ break;
+ }
+
+ for (UINTN i = 0; i < NumAcceptedChars; ++i)
+ {
+ if (Key.UnicodeChar == AcceptedChars[i])
+ {
+ SelectedChar = Key.UnicodeChar;
+ break;
+ }
+ }
+
+ if (SelectedChar != CHAR_NULL)
+ break;
+ }
+
+ Print(L"%c\n\n", SelectedChar);
+ return SelectedChar;
+}
+
+#endif
+
+
+//
+// Try to find a file by browsing each device
+//
+STATIC
+EFI_STATUS
+LocateFile(
+ IN CHAR16* ImagePath,
+ OUT EFI_DEVICE_PATH** DevicePath
+ )
+{
+ *DevicePath = NULL;
+
+ UINTN NumHandles;
+ EFI_HANDLE* Handles;
+ EFI_STATUS Status = gBS->LocateHandleBuffer(ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumHandles,
+ &Handles);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ DEBUG((DEBUG_INFO, "[LOADER] Number of UEFI Filesystem Devices: %llu\r\n", NumHandles));
+
+ for (UINTN i = 0; i < NumHandles; i++)
+ {
+ EFI_FILE_IO_INTERFACE *IoDevice;
+ Status = gBS->OpenProtocol(Handles[i],
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID**)&IoDevice,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (Status != EFI_SUCCESS)
+ continue;
+
+ EFI_FILE_HANDLE VolumeHandle;
+ Status = IoDevice->OpenVolume(IoDevice, &VolumeHandle);
+ if (EFI_ERROR(Status))
+ continue;
+
+ EFI_FILE_HANDLE FileHandle;
+ Status = VolumeHandle->Open(VolumeHandle,
+ &FileHandle,
+ ImagePath,
+ EFI_FILE_MODE_READ,
+ EFI_FILE_READ_ONLY);
+ if (!EFI_ERROR(Status))
+ {
+ VolumeHandle->Close(FileHandle);
+ *DevicePath = FileDevicePath(Handles[i], ImagePath);
+ CHAR16 *PathString = ConvertDevicePathToText(*DevicePath, TRUE, TRUE);
+ DEBUG((DEBUG_INFO, "[LOADER] Found file at %S.\r\n", PathString));
+ if (PathString != NULL)
+ FreePool(PathString);
+ break;
+ }
+ }
+
+ FreePool(Handles);
+
+ return Status;
+}
+
+//
+// Find the optimal available console output mode and set it if it's not already the current mode
+//
+STATIC
+EFI_STATUS
+EFIAPI
+SetHighestAvailableMode(
+ VOID
+ )
+{
+ INT32 MaxModeNum = 0;
+ UINTN Cols, Rows, MaxColsXRows = 0;
+
+ for (INT32 ModeNum = 0; ModeNum < gST->ConOut->Mode->MaxMode; ModeNum++)
+ {
+ CONST EFI_STATUS Status = gST->ConOut->QueryMode(gST->ConOut, ModeNum, &Cols, &Rows);
+ if (EFI_ERROR(Status))
+ continue;
+
+ // Accept only modes where the total of (Rows * Columns) >= the previous known best
+ if ((Cols * Rows) >= MaxColsXRows)
+ {
+ MaxColsXRows = Cols * Rows;
+ MaxModeNum = ModeNum;
+ }
+ }
+
+ if (gST->ConOut->Mode->Mode == MaxModeNum)
+ {
+ // We're already at the correct mode
+ return EFI_SUCCESS;
+ }
+
+ return gST->ConOut->SetMode(gST->ConOut, MaxModeNum);
+}
+
+//
+// Connects all current system handles recursively.
+//
+STATIC
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllEfi(
+ VOID
+ )
+{
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ CONST EFI_STATUS Status = gBS->LocateHandleBuffer(AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ for (UINTN Index = 0; Index < HandleCount; ++Index)
+ {
+ gBS->ConnectController(HandleBuffer[Index],
+ NULL,
+ NULL,
+ TRUE);
+ }
+
+ if (HandleBuffer != NULL)
+ FreePool(HandleBuffer);
+
+ return EFI_SUCCESS;
+}
+
+//
+// Connects all drivers to all controllers.
+//
+STATIC
+VOID
+EFIAPI
+BdsLibConnectAllDriversToAllControllers(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ do
+ {
+ //
+ // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
+ //
+ BdsLibConnectAllEfi();
+
+ //
+ // Check to see if it's possible to dispatch an more DXE drivers.
+ // The BdsLibConnectAllEfi () may have made new DXE drivers show up.
+ // If anything is Dispatched Status == EFI_SUCCESS and we will try
+ // the connect again.
+ //
+ Status = gDS->Dispatch();
+
+ } while (!EFI_ERROR(Status));
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+StartAndConfigureDriver(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE* SystemTable
+ )
+{
+ EFIGUARD_DRIVER_PROTOCOL* EfiGuardDriverProtocol;
+ EFI_DEVICE_PATH *DriverDevicePath = NULL;
+
+ //
+ // Check if the driver is loaded
+ //
+ EFI_STATUS Status = gBS->LocateProtocol(&gEfiGuardDriverProtocolGuid,
+ NULL,
+ (VOID**)&EfiGuardDriverProtocol);
+ ASSERT((!EFI_ERROR(Status) || Status == EFI_NOT_FOUND));
+ if (Status == EFI_NOT_FOUND)
+ {
+ Print(L"[LOADER] Locating and loading driver file %S...\r\n", EFIGUARD_DRIVER_FILENAME);
+ for (UINT32 i = 0; i < ARRAY_SIZE(mDriverPaths); ++i)
+ {
+ Status = LocateFile(mDriverPaths[i], &DriverDevicePath);
+ if (!EFI_ERROR(Status))
+ break;
+ }
+ if (EFI_ERROR(Status))
+ {
+ Print(L"[LOADER] Failed to find driver file %S.\r\n", EFIGUARD_DRIVER_FILENAME);
+ goto Exit;
+ }
+
+ EFI_HANDLE DriverHandle = NULL;
+ Status = gBS->LoadImage(FALSE, // Request is not from boot manager
+ ImageHandle,
+ DriverDevicePath,
+ NULL,
+ 0,
+ &DriverHandle);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"[LOADER] LoadImage failed: %llx (%r).\r\n", Status, Status);
+ goto Exit;
+ }
+
+ Status = gBS->StartImage(DriverHandle, NULL, NULL);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"[LOADER] StartImage failed: %llx (%r).\r\n", Status, Status);
+ goto Exit;
+ }
+
+ Status = gBS->LocateProtocol(&gEfiGuardDriverProtocolGuid,
+ NULL,
+ (VOID**)&EfiGuardDriverProtocol);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"[LOADER] LocateProtocol failed: %llx (%r).\r\n", Status, Status);
+ goto Exit;
+ }
+ }
+ else
+ {
+ Print(L"[LOADER] The driver is already loaded.\r\n");
+ Status = EFI_ALREADY_STARTED;
+ goto Exit;
+ }
+
+#if CONFIGURE_DRIVER
+ //
+ // Interactive driver configuration
+ //
+ Print(L"\r\nChoose the type of DSE bypass to use, or press ENTER for default:\r\n"
+ L" [1] No DSE bypass\r\n [2] Boot time DSE bypass\r\n [3] Runtime SetVariable hook (default)\r\n ");
+ CONST UINT16 AcceptedDseBypasses[] = { L'1', L'2', L'3' };
+ CONST UINT16 SelectedDseBypass = PromptInput(AcceptedDseBypasses,
+ sizeof(AcceptedDseBypasses) / sizeof(UINT16),
+ L'3');
+
+ Print(L"Wait for a keypress to continue after each patch stage? (for debugging)\n"
+ L" [1] Yes\r\n [2] No (default)\r\n ");
+ CONST UINT16 YesNo[] = { L'1', L'2' };
+ CONST UINT16 SelectedWaitForKeyPress = PromptInput(YesNo,
+ sizeof(YesNo) / sizeof(UINT16),
+ L'2');
+
+ EFIGUARD_CONFIGURATION_DATA ConfigData;
+ if (SelectedDseBypass == L'1')
+ ConfigData.DseBypassMethod = DSE_DISABLE_NONE;
+ else if (SelectedDseBypass == L'2')
+ ConfigData.DseBypassMethod = DSE_DISABLE_AT_BOOT;
+ else
+ ConfigData.DseBypassMethod = DSE_DISABLE_SETVARIABLE_HOOK;
+ ConfigData.WaitForKeyPress = (BOOLEAN)(SelectedWaitForKeyPress == L'1');
+
+ //
+ // Send the configuration data to the driver
+ //
+ Status = EfiGuardDriverProtocol->Configure(&ConfigData);
+
+ if (EFI_ERROR(Status))
+ Print(L"[LOADER] Driver Configure() returned error %llx (%r).\r\n", Status, Status);
+#endif
+
+Exit:
+ if (DriverDevicePath != NULL)
+ FreePool(DriverDevicePath);
+
+ return Status;
+}
+
+//
+// Attempt to boot each Windows boot option in the BootOptions array.
+// This function is a combined and simplified version of BootBootOptions (BdsDxe) and EfiBootManagerBoot (UefiBootManagerLib),
+// except for the fact that we are of course not in the BDS phase and also not a driver or the platform boot manager.
+// The Windows boot manager doesn't have to know about all this, that would only confuse it
+//
+STATIC
+BOOLEAN
+TryBootOptionsInOrder(
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
+ IN UINTN BootOptionCount,
+ IN UINT16 CurrentBootOptionIndex,
+ IN BOOLEAN OnlyBootWindows
+ )
+{
+ //
+ // Iterate over the boot options 'in BootOrder order'
+ //
+ EFI_DEVICE_PATH_PROTOCOL* FullPath;
+ for (UINTN Index = 0; Index < BootOptionCount; ++Index)
+ {
+ //
+ // This is us
+ //
+ if (Index == CurrentBootOptionIndex)
+ continue;
+
+ //
+ // No LOAD_OPTION_ACTIVE, no load
+ //
+ if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)
+ continue;
+
+ //
+ // Ignore LOAD_OPTION_CATEGORY_APP entries
+ //
+ if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT)
+ continue;
+
+ //
+ // Filter out non-Windows boot entries.
+ // Apply some heuristics based on the device path, which must end in "bootmgfw.efi" or "bootx64.efi".
+ // In the latter case we may get false positives, but for some types of boots (WinPE, Windows To Go,
+ // and that VM product from Larry Ellison that still can't emulate NVRAM properly), the name will
+ // always be bootx64.efi, so this can't be avoided.
+ //
+ // For the common case, a simpler way would have been to check if the description is "Windows Boot Manager",
+ // but it turns out that we need the full path anyway to LoadImage the file with BootPolicy = TRUE.
+ //
+ BOOLEAN MaybeWindows = FALSE;
+ UINTN FileSize;
+ VOID* FileBuffer = EfiBootManagerGetLoadOptionBuffer(BootOptions[Index].FilePath, &FullPath, &FileSize);
+ if (FileBuffer != NULL)
+ FreePool(FileBuffer);
+
+ // EDK2's EfiBootManagerGetLoadOptionBuffer will sometimes give a NULL "full path"
+ // from an originally non-NULL file path. If so, swap it back (and don't free it).
+ if (FullPath == NULL)
+ FullPath = BootOptions[Index].FilePath;
+
+ // Get the text representation of the device path and check it for our suspects
+ CHAR16* ConvertedPath = ConvertDevicePathToText(FullPath, FALSE, FALSE);
+ if (ConvertedPath != NULL &&
+ (StrStr(ConvertedPath, L"bootmgfw.efi") != NULL || StrStr(ConvertedPath, L"BOOTMGFW.EFI") != NULL ||
+ StrStr(ConvertedPath, L"bootx64.efi") != NULL || StrStr(ConvertedPath, L"BOOTX64.EFI") != NULL))
+ {
+ MaybeWindows = TRUE;
+ }
+
+ if (ConvertedPath != NULL)
+ FreePool(ConvertedPath);
+
+ if (OnlyBootWindows && !MaybeWindows)
+ {
+ if (FullPath != BootOptions[Index].FilePath)
+ FreePool(FullPath);
+
+ // Not Windows; skip this entry
+ continue;
+ }
+
+ //
+ // Boot this image.
+ //
+ // DO NOT: call EfiBootManagerBoot(BootOption) to 'simplify' this process.
+ // The driver will not work in this case due to EfiBootManagerBoot calling BmSetMemoryTypeInformationVariable(),
+ // which performs a warm reset of the system if, for example, the category of the current boot option changed
+ // from 'app' to 'boot'. Which is precisely what we are doing...
+ //
+ // Change the BootCurrent variable to the option number for our boot selection
+ UINT16 OptionNumber = (UINT16)BootOptions[Index].OptionNumber;
+ EFI_STATUS Status = gRT->SetVariable(EFI_BOOT_CURRENT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(UINT16),
+ &OptionNumber);
+ ASSERT_EFI_ERROR(Status);
+
+ // Signal the EVT_SIGNAL_READY_TO_BOOT event
+ EfiSignalEventReadyToBoot();
+
+ // So again, DO NOT call this abortion:
+ //BmSetMemoryTypeInformationVariable((BOOLEAN)((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT));
+
+ // Ensure the image path is connected end-to-end by Dispatch()ing any required drivers through DXE services
+ EfiBootManagerConnectDevicePath(BootOptions[Index].FilePath, NULL);
+
+ // Instead of creating a ramdisk and reading the file into it (¿que?), just pass the path we saved earlier.
+ // This is the point where the driver kicks in via its LoadImage hook.
+ EFI_HANDLE ImageHandle = NULL;
+ Status = gBS->LoadImage(TRUE,
+ gImageHandle,
+ FullPath,
+ NULL,
+ 0,
+ &ImageHandle);
+
+ if (FullPath != BootOptions[Index].FilePath)
+ FreePool(FullPath);
+
+ if (EFI_ERROR(Status))
+ {
+ Print(L"LoadImage error %llx (%r)\r\n", Status, Status);
+ continue;
+ }
+
+ // Get loaded image info
+ EFI_LOADED_IMAGE_PROTOCOL* ImageInfo;
+ Status = gBS->OpenProtocol(ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID**)&ImageInfo,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ ASSERT_EFI_ERROR(Status);
+
+ // Set image load options from the boot option
+ ImageInfo->LoadOptionsSize = BootOptions[Index].OptionalDataSize;
+ ImageInfo->LoadOptions = BootOptions[Index].OptionalData;
+
+ // "Clean to NULL because the image is loaded directly from the firmware's boot manager." (EDK2) Good call, I agree
+ ImageInfo->ParentHandle = NULL;
+
+ // Enable the Watchdog Timer for 5 minutes before calling the image
+ gBS->SetWatchdogTimer(5 * 60, 0x0000, 0x00, NULL);
+
+ // Start the image and set the return code in the boot option status
+ Status = gBS->StartImage(ImageHandle,
+ &BootOptions[Index].ExitDataSize,
+ &BootOptions[Index].ExitData);
+ BootOptions[Index].Status = Status;
+ if (EFI_ERROR(Status))
+ {
+ Print(L"StartImage error %llx (%r)\r\n", Status, Status);
+ continue;
+ }
+
+ //
+ // Success. Code below is never executed
+ //
+
+ // Clear the watchdog timer after the image returns
+ gBS->SetWatchdogTimer(0x0000, 0x0000, 0x0000, NULL);
+
+ // Clear the BootCurrent variable
+ gRT->SetVariable(L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL);
+
+ if (BootOptions[Index].Status == EFI_SUCCESS)
+ return TRUE;
+ }
+
+ // All boot attempts failed, or no suitable entries were found
+ return FALSE;
+}
+
+EFI_STATUS
+EFIAPI
+UefiMain(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE* SystemTable
+ )
+{
+ //
+ // Connect all drivers to all controllers
+ //
+ BdsLibConnectAllDriversToAllControllers();
+
+ //
+ // Set the highest available console mode and clear the screen
+ //
+ SetHighestAvailableMode();
+ gST->ConOut->ClearScreen(gST->ConOut);
+
+ //
+ // Turn off the watchdog timer
+ //
+ gBS->SetWatchdogTimer(0, 0, 0, NULL);
+
+ //
+ // Enable cursor
+ //
+ gST->ConOut->EnableCursor(gST->ConOut, TRUE);
+
+ //
+ // Locate, load, start and configure the driver
+ //
+ CONST EFI_STATUS DriverStatus = StartAndConfigureDriver(ImageHandle, SystemTable);
+ if (DriverStatus == EFI_ALREADY_STARTED)
+ return EFI_SUCCESS;
+
+ if (EFI_ERROR(DriverStatus))
+ {
+ Print(L"\r\nERROR: driver load failed with status %llx (%r).\r\n"
+ L"Press any key to continue, or press ESC to return to the firmware or shell.\r\n",
+ DriverStatus, DriverStatus);
+ if (!WaitForKey())
+ {
+ return DriverStatus;
+ }
+ }
+
+ //
+ // Start the "boot through" procedure to boot Windows.
+ //
+ // First obtain our own boot option number, since we don't want to boot ourselves again
+ UINT16 CurrentBootOptionIndex;
+ UINT32 Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+ UINTN Size = sizeof(CurrentBootOptionIndex);
+ CONST EFI_STATUS Status = gRT->GetVariable(EFI_BOOT_CURRENT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ &Attributes,
+ &Size,
+ &CurrentBootOptionIndex);
+ if (EFI_ERROR(Status))
+ {
+ CurrentBootOptionIndex = 0xFFFF;
+ Print(L"WARNING: failed to query the current boot option index variable.\r\n"
+ L"This could lead to the current device being booted recursively.\r\n"
+ L"If you booted from a removable device, it is recommended that you remove it now.\r\n"
+ L"\r\nPress any key to continue...\r\n");
+ WaitForKey();
+ }
+
+ // Query all boot options, and try each following the order set in the "BootOrder" variable, except
+ // (1) Do not boot ourselves again, and
+ // (2) The description or filename must indicate the boot option is some form of Windows.
+ UINTN BootOptionCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION* BootOptions = EfiBootManagerGetLoadOptions(&BootOptionCount, LoadOptionTypeBoot);
+ BOOLEAN BootSuccess = TryBootOptionsInOrder(BootOptions,
+ BootOptionCount,
+ CurrentBootOptionIndex,
+ TRUE);
+ if (!BootSuccess)
+ {
+ // We did not find any Windows boot entry; retry without the "must be Windows" restriction.
+ BootSuccess = TryBootOptionsInOrder(BootOptions,
+ BootOptionCount,
+ CurrentBootOptionIndex,
+ FALSE);
+ }
+ EfiBootManagerFreeLoadOptions(BootOptions, BootOptionCount);
+
+ if (BootSuccess)
+ return EFI_SUCCESS;
+
+ // We should never reach this unless something is seriously wrong (no boot device / partition table corrupted / catastrophic boot manager failure...)
+ Print(L"Failed to boot anything. This is super bad!\r\n"
+ L"Press any key to return to the firmware or shell,\r\nwhich will surely fix this and not make things worse.\r\n");
+ WaitForKey();
+
+ gBS->Exit(gImageHandle, EFI_SUCCESS, 0, NULL);
+
+ return EFI_SUCCESS;
+}
diff --git a/Application/Loader/Loader.inf b/Application/Loader/Loader.inf
new file mode 100644
index 0000000..1e8e902
--- /dev/null
+++ b/Application/Loader/Loader.inf
@@ -0,0 +1,64 @@
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = Loader
+ FILE_GUID = FADCFFF6-E60C-4684-A241-B203D6E6686D
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ Loader.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EfiGuardPkg/EfiGuardPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ UefiLib
+ DevicePathLib
+ PrintLib
+ UefiBootManagerLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" (The boot option of current boot)
+ gEfiGlobalVariableGuid
+ gEfiEventReadyToBootGuid ## SOMETIMES_PRODUCES
+ gEfiHobListGuid ## CONSUMES
+ gEfiDxeServicesTableGuid ## CONSUMES
+ gEfiFileInfoGuid ## CONSUMES
+
+[Protocols]
+ gEfiGuardDriverProtocolGuid ## CONSUMES
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiDevicePathToTextProtocolGuid ## CONSUMES
+ gEfiDevicePathUtilitiesProtocolGuid ## CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## CONSUMES
+ gEfiLoadFileProtocolGuid ## CONSUMES
+ gEfiBlockIoProtocolGuid ## CONSUMES
+ gEfiRamDiskProtocolGuid ## CONSUMES
+ gEfiHiiStringProtocolGuid ## CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiFontProtocolGuid ## CONSUMES
+ gEfiHiiImageProtocolGuid ## CONSUMES
+ gEfiPciIoProtocolGuid ## CONSUMES
+ gEfiUsbIoProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
+ gEfiSimpleTextInProtocolGuid ## CONSUMES
+ gEfiSimpleTextOutProtocolGuid ## CONSUMES
+
+[BuildOptions.Common]
+ *:DEBUG_*_*_PP_FLAGS = -D EFI_DEBUG
+ *:DEBUG_*_*_CC_FLAGS = -D EFI_DEBUG
+
+ *:RELEASE_*_*_CC_FLAGS = -D MDEPKG_NDEBUG
+
+[BuildOptions.common.UEFI_APPLICATION]
+ MSFT:*_*_*_DLINK_FLAGS = /SUBSYSTEM:EFI_APPLICATION,1.0
+ INTEL:*_*_*_DLINK_FLAGS = /SUBSYSTEM:EFI_APPLICATION,1.0
diff --git a/Application/Loader/Loader.vcxproj b/Application/Loader/Loader.vcxproj
new file mode 100644
index 0000000..9b8c441
--- /dev/null
+++ b/Application/Loader/Loader.vcxproj
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <Keyword>Win32Proj</Keyword>
+ <ProjectGuid>{0E4BAB8F-E6E0-47A8-8E99-8D451839967E}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(SolutionDir)\EfiGuard.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CONFIGURE_DRIVER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)Include</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>UefiApplicationEntryPoint.lib;BaseMemoryLib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>EFI Application</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\Include\Protocol\EfiGuard.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Loader.c" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Application/Loader/Loader.vcxproj.filters b/Application/Loader/Loader.vcxproj.filters
new file mode 100644
index 0000000..9498c8d
--- /dev/null
+++ b/Application/Loader/Loader.vcxproj.filters
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{2C3B8C5F-45D8-45DC-89D3-F9FB7889C9DA}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{548AA1C9-5601-4F15-B01D-53DC20744039}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Header Files\Protocol">
+ <UniqueIdentifier>{7817a5d9-dbec-4278-8dcb-4458096bdbbf}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\Include\Protocol\EfiGuard.h">
+ <Filter>Header Files\Protocol</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Loader.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file