123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 |
- /*++
- Copyright (c) 2014 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- bootman.c
- Abstract:
- This module loads the selected operating system loader into memory and
- jumps to it.
- Author:
- Evan Green 21-Feb-2014
- Environment:
- Boot
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include <minoca/lib/fat/fat.h>
- #include "firmware.h"
- #include "bootlib.h"
- #include <minoca/lib/basevid.h>
- #include "bootman.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define BOOT_MANAGER_BINARY_NAME_MAX_SIZE 16
- #define BOOT_MANAGER_MODULE_BUFFER_SIZE \
- (sizeof(DEBUG_MODULE) + sizeof(BOOT_MANAGER_BINARY_NAME_MAX_SIZE))
- #define BOOT_MANAGER_NAME "Minoca Boot Manager"
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- BmpLoadBootConfiguration (
- PVOID BootDevice,
- PBOOT_CONFIGURATION_CONTEXT Context,
- PBOOT_ENTRY *SelectedBootEntry
- );
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Set this to TRUE to enable debugging in the boot manager.
- //
- BOOL BmDebug = FALSE;
- DEBUG_MODULE BmModule;
- LIST_ENTRY BmLoadedImageList;
- //
- // Carve off memory to store the loader module, including its string.
- //
- UCHAR BmModuleBuffer[BOOT_MANAGER_MODULE_BUFFER_SIZE];
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- BmMain (
- PBOOT_INITIALIZATION_BLOCK Parameters
- )
- /*++
- Routine Description:
- This routine is the entry point for the boot manager program.
- Arguments:
- Parameters - Supplies a pointer to the application parameters.
- Return Value:
- On success, this function does not return.
- On failure, this function returns the step number on which it failed. This
- provides an indication as to where in the boot process it failed.
- --*/
- {
- PCSTR ApplicationName;
- INT ApplicationReturn;
- UINTN BaseDifference;
- BOOT_CONFIGURATION_CONTEXT BootConfigurationContext;
- PBOOT_VOLUME BootDevice;
- PBOOT_ENTRY BootEntry;
- PDEBUG_DEVICE_DESCRIPTION DebugDevice;
- PDEBUG_MODULE DebugModule;
- PLOADED_IMAGE LoaderImage;
- PCSTR LoaderName;
- UINTN LoaderNameSize;
- PBOOT_INITIALIZATION_BLOCK LoaderParameters;
- ULONG LoadFlags;
- ULONG ModuleNameLength;
- PBOOT_VOLUME OsDevice;
- KSTATUS Status;
- ULONG Step;
- BootDevice = NULL;
- DebugDevice = NULL;
- LoaderParameters = NULL;
- Step = 0;
- //
- // Perform just enough firmware initialization to get to the debugger. Not
- // much happens here, as this is all undebuggable.
- //
- Status = FwInitialize(0, Parameters);
- if (!KSUCCESS(Status)) {
- goto MainEnd;
- }
- //
- // Perform very basic processor initialization, preparing it to take
- // exceptions and use the serial port.
- //
- Step += 1;
- BoInitializeProcessor();
- Step += 1;
- BoHlBootInitialize(&DebugDevice, NULL);
- if (BoFirmwareDebugDevice != NULL) {
- DebugDevice = BoFirmwareDebugDevice;
- }
- Step += 1;
- DebugModule = (PDEBUG_MODULE)BmModuleBuffer;
- //
- // Initialize the debugging subsystem.
- //
- RtlZeroMemory(&BmModuleBuffer, sizeof(BmModuleBuffer));
- ApplicationName = (PVOID)(UINTN)(Parameters->ApplicationName);
- ModuleNameLength = RtlStringLength(ApplicationName) + 1;
- if (ModuleNameLength > BOOT_MANAGER_BINARY_NAME_MAX_SIZE) {
- ModuleNameLength = BOOT_MANAGER_BINARY_NAME_MAX_SIZE;
- }
- DebugModule->StructureSize = sizeof(DEBUG_MODULE) + ModuleNameLength -
- (ANYSIZE_ARRAY * sizeof(CHAR));
- RtlStringCopy(DebugModule->BinaryName, ApplicationName, ModuleNameLength);
- DebugModule->LowestAddress =
- (PVOID)(UINTN)(Parameters->ApplicationLowestAddress);
- DebugModule->Size = Parameters->ApplicationSize;
- BoProductName = BOOT_MANAGER_NAME;
- if (BmDebug != FALSE) {
- Status = KdInitialize(DebugDevice, DebugModule);
- if (!KSUCCESS(Status)) {
- goto MainEnd;
- }
- }
- //
- // Initialize the firmware layer.
- //
- Step += 1;
- Status = FwInitialize(1, Parameters);
- if (!KSUCCESS(Status)) {
- goto MainEnd;
- }
- //
- // Mount the boot device.
- //
- Step += 1;
- Status = BoOpenBootVolume(Parameters->DriveNumber,
- Parameters->PartitionOffset,
- NULL,
- &BootDevice);
- if (!KSUCCESS(Status)) {
- FwPrintString(0, 0, "Failed to open boot volume.");
- goto MainEnd;
- }
- //
- // Load the boot configuration information.
- //
- Step += 1;
- Status = BmpLoadBootConfiguration(BootDevice,
- &BootConfigurationContext,
- &BootEntry);
- if (!KSUCCESS(Status)) {
- FwPrintString(0, 0, "Failed to load Boot Configuration.");
- goto MainEnd;
- }
- //
- // Close the boot volume and open the OS volume. It is possible these are
- // the same.
- //
- Step += 1;
- Status = BoCloseVolume(BootDevice);
- BootDevice = NULL;
- if (!KSUCCESS(Status)) {
- goto MainEnd;
- }
- Step += 1;
- if (BootEntry == NULL) {
- FwPrintString(0, 0, "No boot entry selected.");
- Status = STATUS_NO_DATA_AVAILABLE;
- goto MainEnd;
- }
- Step += 1;
- Status = BoOpenVolume(BootEntry->PartitionId, &OsDevice);
- if (!KSUCCESS(Status)) {
- FwPrintString(0, 0, "Failed to open OS volume.");
- goto MainEnd;
- }
- //
- // Load the loader.
- //
- Step += 1;
- Status = BmpInitializeImageSupport(OsDevice, BootEntry);
- if (!KSUCCESS(Status)) {
- goto MainEnd;
- }
- LoaderName = BootEntry->LoaderPath;
- LoaderNameSize = RtlStringLength(BootEntry->LoaderPath);
- LoadFlags = IMAGE_LOAD_FLAG_IGNORE_INTERPRETER |
- IMAGE_LOAD_FLAG_PRIMARY_EXECUTABLE |
- IMAGE_LOAD_FLAG_NO_STATIC_CONSTRUCTORS |
- IMAGE_LOAD_FLAG_BIND_NOW;
- Status = ImLoad(&BmLoadedImageList,
- BootEntry->LoaderPath,
- NULL,
- NULL,
- NULL,
- LoadFlags,
- &LoaderImage,
- NULL);
- if (!KSUCCESS(Status)) {
- FwPrintString(0, 0, "Failed to load OS loader.");
- goto MainEnd;
- }
- //
- // Initialize the boot parameters.
- //
- Step += 1;
- LoaderParameters = BoAllocateMemory(sizeof(BOOT_INITIALIZATION_BLOCK));
- if (LoaderParameters == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto MainEnd;
- }
- Step += 1;
- RtlZeroMemory(LoaderParameters, sizeof(BOOT_INITIALIZATION_BLOCK));
- LoaderParameters->Version = BOOT_INITIALIZATION_BLOCK_VERSION;
- LoaderParameters->BootConfigurationFile =
- (UINTN)(BootConfigurationContext.FileData);
- LoaderParameters->BootConfigurationFileSize =
- BootConfigurationContext.FileDataSize;
- LoaderParameters->BootEntryId = BootEntry->Id;
- LoaderParameters->BootEntryFlags = BootEntry->Flags;
- LoaderParameters->StackTop = Parameters->StackTop;
- LoaderParameters->StackSize = Parameters->StackSize;
- LoaderParameters->Flags = Parameters->Flags |
- BOOT_INITIALIZATION_FLAG_SCREEN_CLEAR;
- if (LoaderImage->Format == ImageElf64) {
- LoaderParameters->Flags |= BOOT_INITIALIZATION_FLAG_64BIT;
- }
- BaseDifference = LoaderImage->BaseDifference;
- //
- // Set the file name and base address of the loader.
- //
- ApplicationName = RtlStringFindCharacterRight(LoaderName,
- '/',
- LoaderNameSize);
- if (ApplicationName == NULL) {
- ApplicationName = LoaderName;
- } else {
- ApplicationName += 1;
- }
- LoaderParameters->ApplicationName = (UINTN)ApplicationName;
- LoaderParameters->ApplicationLowestAddress =
- (UINTN)LoaderImage->PreferredLowestAddress + BaseDifference;
- LoaderParameters->ApplicationSize = LoaderImage->Size;
- LoaderParameters->ApplicationArguments = (UINTN)BootEntry->LoaderArguments;
- Status = BmpFwInitializeBootBlock(LoaderParameters, OsDevice);
- if (!KSUCCESS(Status)) {
- goto MainEnd;
- }
- Step += 1;
- Status = BoCloseVolume(OsDevice);
- if (!KSUCCESS(Status)) {
- goto MainEnd;
- }
- Step += 1;
- KdDisconnect();
- //
- // Launch the boot application. Hopefully this does not return.
- //
- Step += 1;
- ApplicationReturn = BmpFwTransferToBootApplication(LoaderParameters,
- LoaderImage->EntryPoint);
- Step += 1;
- //
- // The loader prints on the first two lines, so leave those alone.
- //
- FwPrintString(0, 3, "Boot Application returned ");
- FwPrintHexInteger(26, 3, ApplicationReturn);
- //
- // Unload the image.
- //
- ImImageReleaseReference(LoaderImage);
- LoaderImage = NULL;
- //
- // Destroy the initialization block.
- //
- if (LoaderParameters != NULL) {
- if (LoaderParameters->ReservedRegions != (UINTN)NULL) {
- BoFreeMemory((PVOID)(UINTN)(LoaderParameters->ReservedRegions));
- }
- BoFreeMemory(LoaderParameters);
- LoaderParameters = NULL;
- }
- Status = STATUS_SUCCESS;
- MainEnd:
- //
- // The loader prints on the first two lines, and the "application returned"
- // message occurs on the third, so start on the fourth.
- //
- FwPrintString(0, 4, "Boot Manager Failed: ");
- FwPrintHexInteger(21, 4, Status);
- FwPrintString(0, 5, "Step: ");
- FwPrintInteger(6, 5, Step);
- FwDestroy();
- return Step;
- }
- PVOID
- BoExpandHeap (
- PMEMORY_HEAP Heap,
- UINTN Size,
- UINTN Tag
- )
- /*++
- Routine Description:
- This routine is called when the heap wants to expand and get more space.
- Arguments:
- Heap - Supplies a pointer to the heap to allocate from.
- Size - Supplies the size of the allocation request, in bytes.
- Tag - Supplies a 32-bit tag to associate with this allocation for debugging
- purposes. These are usually four ASCII characters so as to stand out
- when a poor developer is looking at a raw memory dump. It could also be
- a return address.
- Return Value:
- Returns a pointer to the allocation if successful, or NULL if the
- allocation failed.
- --*/
- {
- ULONG AllocationSize;
- ULONG PageSize;
- PHYSICAL_ADDRESS PhysicalAddress;
- PVOID PhysicalPointer;
- KSTATUS Status;
- PhysicalPointer = NULL;
- if (Size == 0) {
- return NULL;
- }
- PageSize = MmPageSize();
- //
- // Attempt to allocate new pages to satisfy the allocation.
- //
- AllocationSize = ALIGN_RANGE_UP(Size, PageSize);
- Status = FwAllocatePages(&PhysicalAddress,
- AllocationSize,
- PageSize,
- MemoryTypeLoaderTemporary);
- if (!KSUCCESS(Status)) {
- goto ExpandHeapEnd;
- }
- ASSERT((UINTN)PhysicalAddress == PhysicalAddress);
- PhysicalPointer = (PVOID)(UINTN)PhysicalAddress;
- ExpandHeapEnd:
- return PhysicalPointer;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- BmpLoadBootConfiguration (
- PVOID BootDevice,
- PBOOT_CONFIGURATION_CONTEXT Context,
- PBOOT_ENTRY *SelectedBootEntry
- )
- /*++
- Routine Description:
- This routine loads and read the boot configuration information.
- Arguments:
- BootDevice - Supplies the open handle to the boot partition.
- Context - Supplies a pointer where the initialized boot configuration
- context will be returned.
- SelectedBootEntry - Supplies a pointer where a pointer to the selected
- boot entry will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- FILE_PROPERTIES DirectoryProperties;
- PVOID FileData;
- UINTN FileDataSize;
- ULONGLONG ModificationDate;
- KSTATUS Status;
- *SelectedBootEntry = NULL;
- FileData = NULL;
- Status = BoLookupPath(BootDevice,
- NULL,
- BOOT_CONFIGURATION_FILE_PATH,
- &DirectoryProperties);
- if (!KSUCCESS(Status)) {
- goto LoadBootConfigurationEnd;
- }
- Status = BoLoadFile(BootDevice,
- &(DirectoryProperties.FileId),
- BOOT_CONFIGURATION_FILE_NAME,
- &FileData,
- &FileDataSize,
- &ModificationDate);
- if (!KSUCCESS(Status)) {
- goto LoadBootConfigurationEnd;
- }
- //
- // Initialize the boot configuration context.
- //
- RtlZeroMemory(Context, sizeof(BOOT_CONFIGURATION_CONTEXT));
- Context->AllocateFunction = BoAllocateMemory;
- Context->FreeFunction = BoFreeMemory;
- Context->FileData = FileData;
- Context->FileDataSize = FileDataSize;
- Status = BcInitializeContext(Context);
- if (!KSUCCESS(Status)) {
- goto LoadBootConfigurationEnd;
- }
- //
- // Read and parse the boot configuration file data.
- //
- Status = BcReadBootConfigurationFile(Context);
- if (!KSUCCESS(Status)) {
- goto LoadBootConfigurationEnd;
- }
- //
- // If there's no boot once entry, then fill out the default and return.
- //
- *SelectedBootEntry = Context->GlobalConfiguration.DefaultBootEntry;
- if (Context->GlobalConfiguration.BootOnce == NULL) {
- Status = STATUS_SUCCESS;
- goto LoadBootConfigurationEnd;
- }
- //
- // There is a boot once entry. Save it as the selected boot entry, then
- // work to write out the boot configuration with the boot once field
- // cleared.
- //
- *SelectedBootEntry = Context->GlobalConfiguration.BootOnce;
- Context->GlobalConfiguration.BootOnce = NULL;
- Status = BcWriteBootConfigurationFile(Context);
- if (!KSUCCESS(Status)) {
- goto LoadBootConfigurationEnd;
- }
- Status = BoStoreFile(BootDevice,
- DirectoryProperties.FileId,
- BOOT_CONFIGURATION_FILE_NAME,
- sizeof(BOOT_CONFIGURATION_FILE_NAME),
- Context->FileData,
- Context->FileDataSize,
- ModificationDate);
- if (!KSUCCESS(Status)) {
- goto LoadBootConfigurationEnd;
- }
- Status = STATUS_SUCCESS;
- LoadBootConfigurationEnd:
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("Failed to load Boot Configuration: %d.\n", Status);
- if (FileData != NULL) {
- BoFreeMemory(FileData);
- }
- }
- return Status;
- }
|