/** @file This module produce main entry for BDS phase - BdsEntry. When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed which contains interface of BdsEntry. After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked to enter BDS phase. Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
(C) Copyright 2016-2019 Hewlett Packard Enterprise Development LP
(C) Copyright 2015 Hewlett-Packard Development Company, L.P.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Bds.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /// /// BDS arch protocol instance initial value. /// EFI_HANDLE gBdsHandle = NULL; EFI_BDS_ARCH_PROTOCOL gBds = { BdsEntry }; /// /// The read-only variables defined in UEFI Spec. /// CHAR16 *mReadOnlyVariables[] = { EFI_PLATFORM_LANG_CODES_VARIABLE_NAME EFI_LANG_CODES_VARIABLE_NAME, EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME, EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME }; /** Install Boot Device Selection Protocol @param ImageHandle The image handle. @param SystemTable The system table. @retval EFI_SUCEESS BDS has finished initializing. Return the dispatcher and recall BDS.Entry @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface **/ EFI_STATUS EFIAPI BdsInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; VOID *ReturnUnsupported; #ifdef MDE_CPU_X64 STATIC UINT8 mReturnUnsupported[] = { 0x48, 0xB8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC3 }; #else STATIC UINT8 mReturnUnsupported[] = { 0xB8, 0x03, 0x00, 0x00, 0x80, 0xC3 }; #endif // // Provide dummy functions // Status = gBS->AllocatePool (EfiRuntimeServicesCode, sizeof (mReturnUnsupported), (VOID **)&ReturnUnsupported); ASSERT_EFI_ERROR (Status); CopyMem (ReturnUnsupported, mReturnUnsupported, sizeof (mReturnUnsupported)); gRT->UpdateCapsule = (EFI_UPDATE_CAPSULE)ReturnUnsupported; gRT->QueryCapsuleCapabilities = (EFI_QUERY_CAPSULE_CAPABILITIES)ReturnUnsupported; // // Install protocol interface // Status = gBS->InstallMultipleProtocolInterfaces ( &gBdsHandle, &gEfiBdsArchProtocolGuid, &gBds, &gEfiCapsuleArchProtocolGuid, NULL, NULL ); ASSERT_EFI_ERROR (Status); return Status; } STATIC EFI_STATUS BdsCheckSignature ( IN EFI_HANDLE Handle ) { EFI_STATUS Status; volatile BOOT1_LOADER *SelfSignature; BOOT1_LOADER *DiskSignature; UINTN DiskSignatureSize; EFI_BLOCK_IO_PROTOCOL *BlockIo; UINTN Index; UINT8 NonZero; SelfSignature = (volatile BOOT1_LOADER *)(BOOT1_BASE); if (SelfSignature->Magic != BOOT1_MAGIC) { return EFI_UNSUPPORTED; } Status = gBS->HandleProtocol ( Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo ); if (EFI_ERROR (Status)) { return Status; } DiskSignatureSize = ALIGN_VALUE ( MAX (sizeof (*DiskSignature), BlockIo->Media->BlockSize), BlockIo->Media->BlockSize ); DiskSignature = AllocatePool (DiskSignatureSize); if (DiskSignature == NULL) { return EFI_OUT_OF_RESOURCES; } Status = BlockIo->ReadBlocks ( BlockIo, BlockIo->Media->MediaId, 0, DiskSignatureSize, DiskSignature ); if (!EFI_ERROR (Status) && (DiskSignature->Magic == SelfSignature->Magic)) { NonZero = 0; for (Index = 0; Index < sizeof (SelfSignature->Signature); ++Index) { if (SelfSignature->Signature[Index] != DiskSignature->Signature[Index]) { Status = EFI_NOT_FOUND; break; } NonZero |= SelfSignature->Signature[Index]; } if (NonZero == 0) { Status = EFI_NOT_FOUND; } } else { Status = EFI_UNSUPPORTED; } FreePool (DiskSignature); return Status; } /** This function attempts to boot for the boot order specified by platform policy. **/ STATIC VOID BdsBootDeviceSelect ( IN BOOLEAN RequireValidDisk ) { EFI_STATUS Status; UINTN Index; EFI_HANDLE *FileSystemHandles; UINTN NumberFileSystemHandles; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_HANDLE ImageHandle; // // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here. // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &NumberFileSystemHandles, &FileSystemHandles ); if (EFI_ERROR (Status)) { return; } for (Index = 0; Index < NumberFileSystemHandles; Index++) { // // Check matching volume DuetPkg was booted from. // if (RequireValidDisk) { Status = BdsCheckSignature (FileSystemHandles[Index]); if (EFI_ERROR (Status)) { continue; } } // // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI // machinename is ia32, ia64, x64, ... // DevicePath = FileDevicePath ( FileSystemHandles[Index], L"\\EFI\\OC\\OpenCore.efi" ); if (DevicePath == NULL) { continue; } ImageHandle = NULL; Status = gBS->LoadImage ( TRUE, gImageHandle, DevicePath, NULL, 0, &ImageHandle ); if (!EFI_ERROR (Status)) { gBS->StartImage ( ImageHandle, 0, NULL ); } FreePool (DevicePath); } if (NumberFileSystemHandles != 0) { FreePool (FileSystemHandles); } } /** Validate input console variable data. If found the device path is not a valid device path, remove the variable. @param VariableName Input console variable name. **/ STATIC VOID BdsFormalizeConsoleVariable ( IN CHAR16 *VariableName ) { EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINTN VariableSize; EFI_STATUS Status; GetEfiGlobalVariable2 (VariableName, (VOID **)&DevicePath, &VariableSize); if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { Status = gRT->SetVariable ( VariableName, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 0, NULL ); // // Deleting variable with current variable implementation shouldn't fail. // ASSERT_EFI_ERROR (Status); } if (DevicePath != NULL) { FreePool (DevicePath); } } /** Formalize Bds global variables. 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable. 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps 3. Delete OsIndications variable if it is not NV/BS/RT UINT64 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable. **/ STATIC VOID BdsFormalizeEfiGlobalVariable ( VOID ) { UINT64 OsIndicationSupport; // // Validate Console variable. // BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME); BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME); BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME); // // OS indicater support variable // OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI \ | EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED; gRT->SetVariable ( EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof (UINT64), &OsIndicationSupport ); } /** Set language related EFI Variables. **/ STATIC VOID InitializeLanguage ( VOID ) { CHAR8 *PlatformLangCodes; CHAR8 *PlatformLang; PlatformLangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes); PlatformLang = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLang); gRT->SetVariable ( L"PlatformLangCodes", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, AsciiStrSize (PlatformLangCodes), PlatformLangCodes ); gRT->SetVariable ( L"PlatformLang", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, AsciiStrSize (PlatformLang), PlatformLang ); } /** Service routine for BdsInstance->Entry(). Devices are connected, the consoles are initialized, and the boot options are tried. @param This Protocol Instance structure. **/ VOID EFIAPI BdsEntry ( IN EFI_BDS_ARCH_PROTOCOL *This ) { CHAR16 *FirmwareVendor; EFI_STATUS Status; UINT16 BootTimeOut; UINTN Index; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; // // Fill in FirmwareVendor and FirmwareRevision from PCDs // FirmwareVendor = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor); gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor); ASSERT (gST->FirmwareVendor != NULL); gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision); // // Fixup Table CRC after we updated Firmware Vendor and Revision // gST->Hdr.CRC32 = 0; gBS->CalculateCrc32 ((VOID *)gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32); // // Validate Variable. // TODO: Explore. // BdsFormalizeEfiGlobalVariable (); // // Mark the read-only variables if the Variable Lock protocol exists // Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock); DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status)); if (!EFI_ERROR (Status)) { for (Index = 0; Index < ARRAY_SIZE (mReadOnlyVariables); Index++) { Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid); ASSERT_EFI_ERROR (Status); } } // // Initialize L"Timeout" EFI global variable. // BootTimeOut = 0; gRT->SetVariable ( L"Timeout", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, sizeof (UINT16), &BootTimeOut ); // // Platform specific code // Initialize the platform specific string and language // InitializeLanguage (); // // Do the platform init, can be customized by OEM/IBV // PlatformBdsInit (); // // Signal EndOfDxe // EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid); // // Setup some platform policy here // PlatformBdsPolicyBehavior (); // // Signal the EVT_SIGNAL_READY_TO_BOOT event // EfiSignalEventReadyToBoot (); // // BDS select the boot device to load OS // BdsBootDeviceSelect (TRUE); // // Try to boot any volume // gST->ConOut->OutputString (gST->ConOut, L"BOOT MISMATCH!\r\n"); gBS->Stall (3000000); BdsBootDeviceSelect (FALSE); // // Abort with error. // gST->ConOut->OutputString (gST->ConOut, L"BOOT FAIL!\r\n"); gBS->Stall (3000000); CpuDeadLoop (); // // Only assert here since this is the right behavior, we should never // return back to DxeCore. // ASSERT (FALSE); }