/** Initialize CapsuleMax variables. **/ VOID InitCapsuleMaxVariable ( VOID ) { EFI_STATUS Status; UINTN Size; CHAR16 CapsuleMaxStr[sizeof("Capsule####")]; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; UnicodeSPrint( CapsuleMaxStr, sizeof(CapsuleMaxStr), L"Capsule%04x", PcdGet16(PcdCapsuleMax) ); Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator Status = gRT->SetVariable( L"CapsuleMax", &gEfiCapsuleReportGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, Size, CapsuleMaxStr ); if (!EFI_ERROR(Status)) { // Lock it per UEFI spec. Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock); if (!EFI_ERROR(Status)) { Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid); ASSERT_EFI_ERROR(Status); } } }
/** Allocate a block of memory that will contain performance data to OS. **/ VOID BdsAllocateMemoryForPerformanceData ( VOID ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; AcpiLowMemoryBase = 0x0FFFFFFFFULL; // // Allocate a block of memory that will contain performance data to OS. // Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH), &AcpiLowMemoryBase ); if (!EFI_ERROR (Status)) { // // Save the pointer to variable for use in S3 resume. // Status = BdsDxeSetVariableAndReportStatusCodeOnError ( L"PerfDataMemAddr", &gPerformanceProtocolGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof (EFI_PHYSICAL_ADDRESS), &AcpiLowMemoryBase ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase)); } // // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code. // Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); if (!EFI_ERROR (Status)) { Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid); ASSERT_EFI_ERROR (Status); } } }
/** Register callback function upon VariableLockProtocol to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it. @param[in] Event Event whose notification function is being invoked. @param[in] Context Pointer to the notification function's context. **/ VOID EFIAPI VariableLockAcpiGlobalVariable ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; // // Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists // Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); if (!EFI_ERROR (Status)) { Status = VariableLock->RequestToLock (VariableLock, ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid); ASSERT_EFI_ERROR (Status); } }
/** Locks all the UEFI Variables used by this module. @retval EFI_SUCCESS All UEFI variables are locked. @retval EFI_UNSUPPORTED Variable Lock Protocol not found. @retval Other One of the UEFI variables could not be locked. **/ EFI_STATUS LockAllFmpVariables ( VOID ) { EFI_STATUS Status; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; EFI_STATUS ReturnStatus; UINTN Index; VariableLock = NULL; Status = gBS->LocateProtocol ( &gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to locate Variable Lock Protocol (%r).\n", Status)); return EFI_UNSUPPORTED; } ReturnStatus = EFI_SUCCESS; for (Index = 0; Index < ARRAY_SIZE (mFmpVariableLockList); Index++) { Status = VariableLock->RequestToLock ( VariableLock, (CHAR16 *)mFmpVariableLockList[Index], &gEfiCallerIdGuid ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variable %g %s. Status = %r\n", &gEfiCallerIdGuid, mFmpVariableLockList[Index], Status )); if (!EFI_ERROR (ReturnStatus)) { ReturnStatus = Status; } } } return ReturnStatus; }
/** Initialize CapsuleLast variables. **/ VOID InitCapsuleLastVariable ( VOID ) { EFI_STATUS Status; EFI_BOOT_MODE BootMode; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; VOID *CapsuleResult; UINTN Size; CHAR16 CapsuleLastStr[sizeof("Capsule####")]; BootMode = GetBootModeHob(); if (BootMode == BOOT_ON_FLASH_UPDATE) { Status = gRT->SetVariable( L"CapsuleLast", &gEfiCapsuleReportGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL ); // Do not lock it because it will be updated later. } else { // // Check if OS/APP cleared L"Capsule####" // ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr)); Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator Status = gRT->GetVariable( L"CapsuleLast", &gEfiCapsuleReportGuid, NULL, &Size, CapsuleLastStr ); if (!EFI_ERROR(Status)) { // // L"CapsuleLast" is got, check if data is there. // Status = GetVariable2 ( CapsuleLastStr, &gEfiCapsuleReportGuid, (VOID **) &CapsuleResult, NULL ); if (EFI_ERROR(Status)) { // // If no data, delete L"CapsuleLast" // Status = gRT->SetVariable( L"CapsuleLast", &gEfiCapsuleReportGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL ); } } // Lock it in normal boot path per UEFI spec. Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock); if (!EFI_ERROR(Status)) { Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid); ASSERT_EFI_ERROR(Status); } } }
/** Check and execute the pending TPM request and Lock TPM. The TPM request may come from OS or BIOS. This API will display request information and wait for user confirmation if TPM request exists. The TPM request will be sent to TPM device after the TPM request is confirmed, and one or more reset may be required to make TPM request to take effect. At last, it will lock TPM to prevent TPM state change by malware. This API should be invoked after console in and console out are all ready as they are required to display request information and get user input to confirm the request. This API should also be invoked as early as possible as TPM is locked in this function. **/ VOID EFIAPI TcgPhysicalPresenceLibProcessRequest ( VOID ) { EFI_STATUS Status; BOOLEAN LifetimeLock; BOOLEAN CmdEnable; UINTN DataSize; EFI_PHYSICAL_PRESENCE TcgPpData; EFI_TCG_PROTOCOL *TcgProtocol; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol; UINT8 PpiFlags; Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol); if (EFI_ERROR (Status)) { return ; } // // Initialize physical presence flags. // DataSize = sizeof (UINT8); Status = gRT->GetVariable ( PHYSICAL_PRESENCE_FLAGS_VARIABLE, &gEfiPhysicalPresenceGuid, NULL, &DataSize, &PpiFlags ); if (EFI_ERROR (Status)) { PpiFlags = FLAG_NO_PPI_PROVISION; Status = gRT->SetVariable ( PHYSICAL_PRESENCE_FLAGS_VARIABLE, &gEfiPhysicalPresenceGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof (UINT8), &PpiFlags ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[TPM] Set physical presence flag failed, Status = %r\n", Status)); return ; } } DEBUG ((EFI_D_INFO, "[TPM] PpiFlags = %x\n", PpiFlags)); // // This flags variable controls whether physical presence is required for TPM command. // It should be protected from malicious software. We set it as read-only variable here. // Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol); if (!EFI_ERROR (Status)) { Status = VariableLockProtocol->RequestToLock ( VariableLockProtocol, PHYSICAL_PRESENCE_FLAGS_VARIABLE, &gEfiPhysicalPresenceGuid ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[TPM] Error when lock variable %s, Status = %r\n", PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status)); ASSERT_EFI_ERROR (Status); } } // // Initialize physical presence variable. // DataSize = sizeof (EFI_PHYSICAL_PRESENCE); Status = gRT->GetVariable ( PHYSICAL_PRESENCE_VARIABLE, &gEfiPhysicalPresenceGuid, NULL, &DataSize, &TcgPpData ); if (EFI_ERROR (Status)) { ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData)); DataSize = sizeof (EFI_PHYSICAL_PRESENCE); Status = gRT->SetVariable ( PHYSICAL_PRESENCE_VARIABLE, &gEfiPhysicalPresenceGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, DataSize, &TcgPpData ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "[TPM] Set physical presence variable failed, Status = %r\n", Status)); return; } } DEBUG ((EFI_D_INFO, "[TPM] Flags=%x, PPRequest=%x\n", PpiFlags, TcgPpData.PPRequest)); if (TcgPpData.PPRequest == PHYSICAL_PRESENCE_NO_ACTION) { // // No operation request // return; } Status = GetTpmCapability (TcgProtocol, &LifetimeLock, &CmdEnable); if (EFI_ERROR (Status)) { return ; } if (!CmdEnable) { if (LifetimeLock) { // // physicalPresenceCMDEnable is locked, can't execute physical presence command. // return ; } Status = TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_CMD_ENABLE); if (EFI_ERROR (Status)) { return ; } } // // Set operator physical presence flags // TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_PRESENT); // // Execute pending TPM request. // ExecutePendingTpmRequest (TcgProtocol, &TcgPpData, PpiFlags); DEBUG ((EFI_D_INFO, "[TPM] PPResponse = %x\n", TcgPpData.PPResponse)); // // Lock physical presence. // TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_NOTPRESENT | TPM_PHYSICAL_PRESENCE_LOCK); }
/** Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable from the load option. @param LoadOption Pointer to the load option. @retval EFI_SUCCESS The variable was created. @retval Others Error status returned by RT->SetVariable. **/ EFI_STATUS EFIAPI EfiBootManagerLoadOptionToVariable ( IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Option ) { EFI_STATUS Status; UINTN VariableSize; UINT8 *Variable; UINT8 *Ptr; CHAR16 OptionName[BM_OPTION_NAME_LEN]; CHAR16 *Description; CHAR16 NullChar; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; UINT32 VariableAttributes; if ((Option->OptionNumber == LoadOptionNumberUnassigned) || (Option->FilePath == NULL) || ((UINT32) Option->OptionType >= LoadOptionTypeMax) ) { return EFI_INVALID_PARAMETER; } // // Convert NULL description to empty description // NullChar = L'\0'; Description = Option->Description; if (Description == NULL) { Description = &NullChar; } /* UINT32 Attributes; UINT16 FilePathListLength; CHAR16 Description[]; EFI_DEVICE_PATH_PROTOCOL FilePathList[]; UINT8 OptionalData[]; TODO: FilePathList[] IS: A packed array of UEFI device paths. The first element of the array is a device path that describes the device and location of the Image for this load option. The FilePathList[0] is specific to the device type. Other device paths may optionally exist in the FilePathList, but their usage is OSV specific. Each element in the array is variable length, and ends at the device path end structure. */ VariableSize = sizeof (Option->Attributes) + sizeof (UINT16) + StrSize (Description) + GetDevicePathSize (Option->FilePath) + Option->OptionalDataSize; Variable = AllocatePool (VariableSize); ASSERT (Variable != NULL); Ptr = Variable; WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes); Ptr += sizeof (Option->Attributes); WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath)); Ptr += sizeof (UINT16); CopyMem (Ptr, Description, StrSize (Description)); Ptr += StrSize (Description); CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath)); Ptr += GetDevicePathSize (Option->FilePath); CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize); UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber); VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE; if (Option->OptionType == LoadOptionTypePlatformRecovery) { // // Lock the PlatformRecovery#### // Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); if (!EFI_ERROR (Status)) { Status = VariableLock->RequestToLock (VariableLock, OptionName, &gEfiGlobalVariableGuid); ASSERT_EFI_ERROR (Status); } VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; } Status = gRT->SetVariable ( OptionName, &gEfiGlobalVariableGuid, VariableAttributes, VariableSize, Variable ); FreePool (Variable); return Status; }
/** 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 ) { LIST_ENTRY DriverOptionList; LIST_ENTRY BootOptionList; UINTN BootNextSize; CHAR16 *FirmwareVendor; EFI_STATUS Status; UINT16 BootTimeOut; UINTN Index; EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; // // Insert the performance probe // PERF_END (NULL, "DXE", NULL, 0); PERF_START (NULL, "BDS", NULL, 0); // // Initialize the global system boot option and driver option // InitializeListHead (&DriverOptionList); InitializeListHead (&BootOptionList); // // Initialize hotkey service // InitializeHotkeyService (); // // 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 Tasble 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. // 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); } } // // Report Status Code to indicate connecting drivers will happen // REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS) ); InitializeHwErrRecSupport(); // // Initialize L"Timeout" EFI global variable. // BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut); if (BootTimeOut != 0xFFFF) { // // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification // define same behavior between no value or 0xFFFF value for L"Timeout". // BdsDxeSetVariableAndReportStatusCodeOnError ( L"Timeout", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, sizeof (UINT16), &BootTimeOut ); } // // bugbug: platform specific code // Initialize the platform specific string and language // InitializeStringSupport (); InitializeLanguage (TRUE); InitializeFrontPage (TRUE); // // Do the platform init, can be customized by OEM/IBV // PERF_START (NULL, "PlatformBds", "BDS", 0); PlatformBdsInit (); // // Set up the device list based on EFI 1.1 variables // process Driver#### and Load the driver's in the // driver option list // BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder"); if (!IsListEmpty (&DriverOptionList)) { BdsLibLoadDrivers (&DriverOptionList); } // // Check if we have the boot next option // mBootNext = BdsLibGetVariableAndSize ( L"BootNext", &gEfiGlobalVariableGuid, &BootNextSize ); // // Setup some platform policy here // PlatformBdsPolicyBehavior (&DriverOptionList, &BootOptionList, BdsProcessCapsules, BdsMemoryTest); PERF_END (NULL, "PlatformBds", "BDS", 0); // // BDS select the boot device to load OS // BdsBootDeviceSelect (); // // Only assert here since this is the right behavior, we should never // return back to DxeCore. // ASSERT (FALSE); return ; }