/** Initialize Global Descriptor Table. **/ VOID InitGlobalDescriptorTable ( VOID ) { GDT_ENTRIES *gdt; IA32_DESCRIPTOR gdtPtr; // // Allocate Runtime Data for the GDT // gdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8); ASSERT (gdt != NULL); gdt = ALIGN_POINTER (gdt, 8); // // Initialize all GDT entries // CopyMem (gdt, &GdtTemplate, sizeof (GdtTemplate)); // // Write GDT register // gdtPtr.Base = (UINT32)(UINTN)(VOID*) gdt; gdtPtr.Limit = (UINT16) (sizeof (GdtTemplate) - 1); AsmWriteGdtr (&gdtPtr); // // Update selector (segment) registers base on new GDT // SetCodeSelector ((UINT16)CPU_CODE_SEL); SetDataSelectors ((UINT16)CPU_DATA_SEL); }
/** Constructor routine for runtime crypt library instance. The constructor function pre-allocates space for runtime cryptographic operation. @param ImageHandle The firmware allocated handle for the EFI image. @param SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The construction succeeded. @retval EFI_OUT_OF_RESOURCE Failed to allocate memory. **/ EFI_STATUS EFIAPI RuntimeCryptLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; VOID *Buffer; // // Pre-allocates runtime space for possible cryptographic operations // Buffer = AllocateRuntimePool (MIN_REQUIRED_BLOCKS * 1024); Status = InitializeScratchMemory (Buffer, MIN_REQUIRED_BLOCKS * 1024); if (EFI_ERROR (Status)) { return Status; } // // Create address change event // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RuntimeCryptLibAddressChangeEvent, NULL, &gEfiEventVirtualAddressChangeGuid, &mVirtualAddressChangeEvent ); ASSERT_EFI_ERROR (Status); return Status; }
/** Initialize Global Descriptor Table. **/ VOID InitLinuxDescriptorTables ( VOID ) { // // Allocate Runtime Data for the GDT // mGdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8); ASSERT (mGdt != NULL); mGdt = ALIGN_POINTER (mGdt, 8); // // Initialize all GDT entries // CopyMem (mGdt, &GdtTemplate, sizeof (GdtTemplate)); }
/** Initialize runtime memory status code table as initialization for runtime memory status code worker @retval EFI_SUCCESS Runtime memory status code table successfully initialized. **/ EFI_STATUS RtMemoryStatusCodeInitializeWorker ( VOID ) { // // Allocate runtime memory status code pool. // mRtMemoryStatusCodeTable = AllocateRuntimePool ( sizeof (RUNTIME_MEMORY_STATUSCODE_HEADER) + PcdGet16 (PcdStatusCodeMemorySize) * 1024 ); ASSERT (mRtMemoryStatusCodeTable != NULL); mRtMemoryStatusCodeTable->RecordIndex = 0; mRtMemoryStatusCodeTable->NumberOfRecords = 0; mRtMemoryStatusCodeTable->MaxRecordsNumber = (PcdGet16 (PcdStatusCodeMemorySize) * 1024) / sizeof (MEMORY_STATUSCODE_RECORD); return EFI_SUCCESS; }
EFIAPI GuidStr(IN EFI_GUID *Guid) { UINTN i; CHAR16 *Str = NULL; if (GuidPrintBuffer == NULL) { GuidPrintBuffer = AllocateRuntimePool(GUID_PRINT_BUFFER_SIZE); } for(i = 1; EfiGuidStrMap[i].Guid != NULL; i++) { if (CompareGuid(EfiGuidStrMap[i].Guid, Guid)) { Str = EfiGuidStrMap[i].Str; break; } } if (Str == NULL) { UnicodeSPrint(GuidPrintBuffer, GUID_PRINT_BUFFER_SIZE, L"%g", Guid); Str = GuidPrintBuffer; } return Str; }
/** Initialize runtime memory status code table as initialization for runtime memory status code worker @retval EFI_SUCCESS Runtime memory status code table successfully initialized. @retval others Errors from gBS->InstallConfigurationTable(). **/ EFI_STATUS RtMemoryStatusCodeInitializeWorker ( VOID ) { EFI_STATUS Status; // // Allocate runtime memory status code pool. // mRtMemoryStatusCodeTable = AllocateRuntimePool ( sizeof (RUNTIME_MEMORY_STATUSCODE_HEADER) + PcdGet16 (PcdStatusCodeMemorySize) * 1024 ); ASSERT (mRtMemoryStatusCodeTable != NULL); mRtMemoryStatusCodeTable->RecordIndex = 0; mRtMemoryStatusCodeTable->NumberOfRecords = 0; mRtMemoryStatusCodeTable->MaxRecordsNumber = (PcdGet16 (PcdStatusCodeMemorySize) * 1024) / sizeof (MEMORY_STATUSCODE_RECORD); Status = gBS->InstallConfigurationTable (&gMemoryStatusCodeRecordGuid, mRtMemoryStatusCodeTable); return Status; }
VOID ReserveEmuVariableNvStore ( ) { EFI_PHYSICAL_ADDRESS VariableStore; // // Allocate storage for NV variables early on so it will be // at a consistent address. Since VM memory is preserved // across reboots, this allows the NV variable storage to survive // a VM reboot. // VariableStore = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocateRuntimePool ( 2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize) ); DEBUG ((EFI_D_INFO, "Reserved variable store memory: 0x%lX; size: %dkb\n", VariableStore, (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024 )); PcdSet64 (PcdEmuVariableNvStoreReserved, VariableStore); }
/** This function uses policy data from the platform to determine what operating system or system utility should be loaded and invoked. This function call also optionally make the use of user input to determine the operating system or system utility to be loaded and invoked. When the DXE Core has dispatched all the drivers on the dispatch queue, this function is called. This function will attempt to connect the boot devices required to load and invoke the selected operating system or system utility. During this process, additional firmware volumes may be discovered that may contain addition DXE drivers that can be dispatched by the DXE Core. If a boot device cannot be fully connected, this function calls the DXE Service Dispatch() to allow the DXE drivers from any newly discovered firmware volumes to be dispatched. Then the boot device connection can be attempted again. If the same boot device connection operation fails twice in a row, then that boot device has failed, and should be skipped. This function should never return. @param This The EFI_BDS_ARCH_PROTOCOL instance. @return None. **/ VOID EFIAPI BdsEntry ( IN EFI_BDS_ARCH_PROTOCOL *This ) { UINTN Size; EFI_STATUS Status; UINT16 *BootNext; UINTN BootNextSize; CHAR16 BootVariableName[9]; EFI_EVENT EndOfDxeEvent; VOID *NewBase; // // Signal EndOfDxe PI Event // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, EmptyCallbackFunction, NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent ); if (!EFI_ERROR (Status)) { gBS->SignalEvent (EndOfDxeEvent); } PERF_END (NULL, "DXE", NULL, 0); OemPostEndIndicator(); //?им1??и▓бф?иж?б└бзиви┤и║б└1?б└и╣бд?бу?бъ?ж╠б└ижи║??2G?и▓бф?и║б└бъ??и▓бф?2?1?ио?бъ??ик?ив??HOB?D //memory reserved идидDикимивижy?asystem memory идидDик NewBase = AllocatePages (EFI_SIZE_TO_PAGES(SIZE_2GB)); if (NULL == NewBase) { DEBUG ((EFI_D_ERROR, "There are not enough memory space..........\n")); } else { FreePages(NewBase,EFI_SIZE_TO_PAGES(SIZE_2GB)); } // // Declare the Firmware Vendor // if (FixedPcdGetPtr(PcdFirmwareVendor) != NULL) { Size = 0x100; gST->FirmwareVendor = AllocateRuntimePool (Size); ASSERT (gST->FirmwareVendor != NULL); UnicodeSPrint (gST->FirmwareVendor, Size, L"%a EFI %a %a", PcdGetPtr(PcdFirmwareVendor), __DATE__, __TIME__); } // // Fixup Table CRC after we updated Firmware Vendor // gST->Hdr.CRC32 = 0; Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { //for fortify } // If BootNext environment variable is defined then we just load it ! BootNextSize = sizeof(UINT16); Status = GetGlobalEnvironmentVariable (L"BootNext", NULL, &BootNextSize, (VOID**)&BootNext); if (!EFI_ERROR(Status)) { ASSERT(BootNextSize == sizeof(UINT16)); // Generate the requested Boot Entry variable name UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", *BootNext); // Set BootCurrent variable gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, BootNextSize, BootNext); FreePool (BootNext); // Start the requested Boot Entry Status = BdsStartBootOption (BootVariableName); if (Status != EFI_NOT_FOUND) { // BootNext has not been succeeded launched if (EFI_ERROR(Status)) { Print(L"Fail to start BootNext.\n"); } // Delete the BootNext environment variable gRT->SetVariable (L"BootNext", &gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL); } // Clear BootCurrent variable gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL); } // If Boot Order does not exist then create a default entry DefineDefaultBootEntries (); // Now we need to setup the EFI System Table with information about the console devices. InitializeConsole (); // // Update the CRC32 in the EFI System Table header // gST->Hdr.CRC32 = 0; Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { //for fortify } // Timer before initiating the default boot selection StartDefaultBootOnTimeout (); Status = VerifyBootLineEntry (); if(EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR,"Input Password Error, Boot failed!\n")); return; } // Start the Boot Menu Status = BootMenuMain (); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { //for fortify } }
/** Prints RT vars. */ VOID EFIAPI PrintRTVariables( IN EFI_RUNTIME_SERVICES *RT ) { EFI_STATUS Status; UINT32 Attributes; //UINT64 MaximumVariableStorageSize; //UINT64 RemainingVariableStorageSize; //UINT64 MaximumVariableSize; UINTN VariableNameSize; UINTN VariableNameBufferSize; UINTN VariableDataSize; EFI_GUID VendorGuid; BOOLEAN IsDataPrintDisabled; // // Print storage info // /* PRINT("Vars storage:\n"); PRINT(" Attrib: MaximumVariableStorageSize, RemainingVariableStorageSize, MaximumVariableSize\n"); // NV+BS PRINT(" NV+BS : "); Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS; Status = RT->QueryVariableInfo(Attributes, &MaximumVariableStorageSize, &RemainingVariableStorageSize, &MaximumVariableSize); if (EFI_ERROR(Status)) { PRINT("%r\n", Status); } else { PRINT("%ld, %ld, %ld\n", MaximumVariableStorageSize, RemainingVariableStorageSize, MaximumVariableSize); } // NV+BS+RT PRINT(" NV+BS+RT: "); Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; Status = RT->QueryVariableInfo(Attributes, &MaximumVariableStorageSize, &RemainingVariableStorageSize, &MaximumVariableSize); if (EFI_ERROR(Status)) { PRINT("%r\n", Status); } else { PRINT("%ld, %ld, %ld\n", MaximumVariableStorageSize, RemainingVariableStorageSize, MaximumVariableSize); } */ // // Print all vars // PRINT("Variables:\n"); VariableNameBufferSize = VARIABLE_NAME_BUFFER_SIZE; if (gVariableNameBuffer == NULL) { // init var name buffer // note: this must be called during boot services, // so if vars are going to be printed during runtime // they must be first printed during boot services // to init this buffer. if (InBootServices) { gVariableNameBuffer = AllocateRuntimePool(VariableNameBufferSize); } else { // error: buffer not inited during boot services PRINT("ERROR: gVariableNameBuffer not inited\n"); return; } } // first call to GetNextVariableName must be with empty string gVariableNameBuffer[0] = L'\0'; while (TRUE) { VariableNameSize = VariableNameBufferSize; Status = RT->GetNextVariableName(&VariableNameSize, gVariableNameBuffer, &VendorGuid); if (Status == EFI_BUFFER_TOO_SMALL) { // we will not handle this to avoid problems during calling in runtime PRINT("ERROR: gVariableNameBuffer too small\n"); return; } if (Status == EFI_NOT_FOUND) { // no more vars break; } if (EFI_ERROR (Status)) { // no more vars or error PRINT("ERROR: GetNextVariableName: %r\n", Status); return; } // prepare for var data if needed if (gVariableDataBuffer == NULL) { if (InBootServices) { gVariableDataBuffer = AllocateRuntimePool(VARIABLE_DATA_BUFFER_SIZE); } else { // error: buffer not inited during boot services PRINT("ERROR: gVariableDataBuffer not inited\n"); return; } } IsDataPrintDisabled = FALSE; #if PRINT_SHELL_VARS == 0 { BOOLEAN IsShellVar; IsShellVar = CompareGuid(&VendorGuid, &ShellInt) || CompareGuid(&VendorGuid, &SEnv) || CompareGuid(&VendorGuid, &ShellDevPathMap) || CompareGuid(&VendorGuid, &ShellProtId) || CompareGuid(&VendorGuid, &ShellAlias); IsDataPrintDisabled = IsShellVar; } #endif // get and print this var VariableDataSize = VARIABLE_DATA_BUFFER_SIZE; Status = RT->GetVariable(gVariableNameBuffer, &VendorGuid, &Attributes, &VariableDataSize, gVariableDataBuffer); if (EFI_ERROR(Status)) { PRINT(" %s:%s = %r\n", GuidStr(&VendorGuid), gVariableNameBuffer, Status); } else { PRINT("%08x ", Attributes); PRINT("%a", (Attributes & EFI_VARIABLE_NON_VOLATILE) ? "NV+" : " "); PRINT("%a", (Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) ? "BS+" : " "); PRINT("%a", (Attributes & EFI_VARIABLE_RUNTIME_ACCESS) ? "RT+" : " "); PRINT("%a", (Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) ? "HW+" : " "); PRINT(" %s:%s, DataSize = %x\n", GuidStr(&VendorGuid), gVariableNameBuffer, VariableDataSize); if (!IsDataPrintDisabled) { PrintBytes(gVariableDataBuffer, VariableDataSize); } } } }
/** Initializes for authenticated varibale service. @retval EFI_SUCCESS The function successfully executed. @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resources. **/ EFI_STATUS AutenticatedVariableServiceInitialize ( VOID ) { EFI_STATUS Status; VARIABLE_POINTER_TRACK Variable; UINT8 VarValue; UINT32 VarAttr; UINTN DataSize; UINTN CtxSize; VARIABLE_HEADER VariableHeader; BOOLEAN Valid; ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER)); mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid; mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical] = &gEfiCertRsa2048Sha256Guid; mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid; // // Initialize hash context. // CtxSize = Sha256GetContextSize (); mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize); ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL); // // Check "AuthVarKeyDatabase" variable's existence. // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. // Status = FindVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB], &gEfiAuthenticatedVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance ); if (Variable.CurrPtr == 0x0) { VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; VarValue = 0; mPubKeyNumber = 0; Status = UpdateVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB], &gEfiAuthenticatedVariableGuid, &VarValue, sizeof(UINT8), VarAttr, 0, 0, FALSE, mVariableModuleGlobal, &Variable ); if (EFI_ERROR (Status)) { return Status; } } else { // // Load database in global variable for cache. // Valid = IsValidVariableHeader ( Variable.CurrPtr, Variable.Volatile, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance, &VariableHeader ); ASSERT (Valid); DataSize = DataSizeOfVariable (&VariableHeader); ASSERT (DataSize <= MAX_KEYDB_SIZE); GetVariableDataPtr ( Variable.CurrPtr, Variable.Volatile, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance, (CHAR16 *) mVariableModuleGlobal->PubKeyStore ); mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE); } // // Check "SetupMode" variable's existence. // If it doesn't exist, check PK database's existence to determine the value. // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. // Status = FindVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE], &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance ); if (Variable.CurrPtr == 0x0) { Status = FindVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY], &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance ); if (Variable.CurrPtr == 0x0) { mPlatformMode = SETUP_MODE; } else { mPlatformMode = USER_MODE; } VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; Status = UpdateVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE], &gEfiGlobalVariableGuid, &mPlatformMode, sizeof(UINT8), VarAttr, 0, 0, FALSE, mVariableModuleGlobal, &Variable ); if (EFI_ERROR (Status)) { return Status; } } else { GetVariableDataPtr ( Variable.CurrPtr, Variable.Volatile, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance, (CHAR16 *) &mPlatformMode ); } // // Check "SignatureSupport" variable's existence. // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. // Status = FindVariable ( EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance ); if (Variable.CurrPtr == 0x0) { VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; Status = UpdateVariable ( EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, mSignatureSupport, SIGSUPPORT_NUM * sizeof(EFI_GUID), VarAttr, 0, 0, FALSE, mVariableModuleGlobal, &Variable ); } return Status; }
/** This routine is called to see if there are any capsules we need to process. If the boot mode is not UPDATE, then we do nothing. Otherwise find the capsule HOBS and produce firmware volumes for them via the DXE service. Then call the dispatcher to dispatch drivers from them. Finally, check the status of the updates. This function should be called by BDS in case we need to do some sort of processing even if there is no capsule to process. We need to do this if an earlier update went away and we need to clear the capsule variable so on the next reset PEI does not see it and think there is a capsule available. @param BootMode the current boot mode @retval EFI_INVALID_PARAMETER boot mode is not correct for an update @retval EFI_SUCCESS There is no error when processing capsule **/ EFI_STATUS EFIAPI BdsProcessCapsules ( EFI_BOOT_MODE BootMode ) { EFI_STATUS Status; EFI_PEI_HOB_POINTERS HobPointer; EFI_CAPSULE_HEADER *CapsuleHeader; UINT32 Size; UINT32 CapsuleNumber; UINT32 CapsuleTotalNumber; EFI_CAPSULE_TABLE *CapsuleTable; UINT32 Index; UINT32 CacheIndex; UINT32 CacheNumber; VOID **CapsulePtr; VOID **CapsulePtrCache; EFI_GUID *CapsuleGuidCache; BOOLEAN NeedReset; CapsuleNumber = 0; CapsuleTotalNumber = 0; CacheIndex = 0; CacheNumber = 0; CapsulePtr = NULL; CapsulePtrCache = NULL; CapsuleGuidCache = NULL; NeedReset = FALSE; // // We don't do anything else if the boot mode is not flash-update // if (BootMode != BOOT_ON_FLASH_UPDATE) { DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update.\n")); return EFI_INVALID_PARAMETER; } Status = EFI_SUCCESS; // // Find all capsule images from hob // HobPointer.Raw = GetHobList (); while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) { CapsuleTotalNumber ++; HobPointer.Raw = GET_NEXT_HOB (HobPointer); } if (CapsuleTotalNumber == 0) { // // We didn't find a hob, so had no errors. // DEBUG ((EFI_D_ERROR, "We can not find capsule data in capsule update boot mode.\n")); DEBUG ((EFI_D_ERROR, "Please check the followings are correct if unexpected capsule update error happens.\n")); DEBUG ((EFI_D_ERROR, "1. CapsuleX64 is built as X64 module when PEI is IA32 and DXE is X64\n")); DEBUG ((EFI_D_ERROR, "2. Capsule data should persist in memory across a system reset.\n")); PlatformBdsLockNonUpdatableFlash (); return EFI_SUCCESS; } // // Init temp Capsule Data table. // CapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber); ASSERT (CapsulePtr != NULL); CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber); ASSERT (CapsulePtrCache != NULL); CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber); ASSERT (CapsuleGuidCache != NULL); // // Find all capsule images from hob // HobPointer.Raw = GetHobList (); while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) { CapsulePtr [CapsuleNumber++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress; HobPointer.Raw = GET_NEXT_HOB (HobPointer); } // //Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install //capsuleTable to configure table with EFI_CAPSULE_GUID // // // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating // System to have information persist across a system reset. EFI System Table must // point to an array of capsules that contains the same CapsuleGuid value. And agents // searching for this type capsule will look in EFI System Table and search for the // capsule's Guid and associated pointer to retrieve the data. Two steps below describes // how to sorting the capsules by the unique guid and install the array to EFI System Table. // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an // array for later sorting capsules by CapsuleGuid. // for (Index = 0; Index < CapsuleTotalNumber; Index++) { CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) { // // For each capsule, we compare it with known CapsuleGuid in the CacheArray. // If already has the Guid, skip it. Whereas, record it in the CacheArray as // an additional one. // CacheIndex = 0; while (CacheIndex < CacheNumber) { if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) { break; } CacheIndex++; } if (CacheIndex == CacheNumber) { CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID)); } } } // // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules // whose guid is the same as it, and malloc memory for an array which preceding // with UINT32. The array fills with entry point of capsules that have the same // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install // this array into EFI System Table, so that agents searching for this type capsule // will look in EFI System Table and search for the capsule's Guid and associated // pointer to retrieve the data. // CacheIndex = 0; while (CacheIndex < CacheNumber) { CapsuleNumber = 0; for (Index = 0; Index < CapsuleTotalNumber; Index++) { CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) { if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) { // // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid. // CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader; } } } if (CapsuleNumber != 0) { Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*); CapsuleTable = AllocateRuntimePool (Size); ASSERT (CapsuleTable != NULL); CapsuleTable->CapsuleArrayNumber = CapsuleNumber; CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*)); Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable); ASSERT_EFI_ERROR (Status); } CacheIndex++; } // // Besides ones with CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag, all capsules left are // recognized by platform with CapsuleGuid. For general platform driver, UpdateFlash // type is commonly supported, so here only deal with encapsuled FVs capsule. Additional // type capsule transaction could be extended. It depends on platform policy. // for (Index = 0; Index < CapsuleTotalNumber; Index++) { CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index]; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) { // // Always reset system after all capsule processed if FMP capsule exist // if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) { NeedReset = TRUE; } // // Call capsule library to process capsule image. // ProcessCapsuleImage (CapsuleHeader); } } if (NeedReset) { Print(L"Capsule Request Cold Reboot.\n"); for (Index = 5; Index > 0; Index--) { Print(L"\rResetting system in %d seconds ...", Index); gBS->Stall (1000000); } gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); CpuDeadLoop (); } PlatformBdsLockNonUpdatableFlash (); // // Free the allocated temp memory space. // FreePool (CapsuleGuidCache); FreePool (CapsulePtrCache); FreePool (CapsulePtr); return Status; }
/** This function uses policy data from the platform to determine what operating system or system utility should be loaded and invoked. This function call also optionally make the use of user input to determine the operating system or system utility to be loaded and invoked. When the DXE Core has dispatched all the drivers on the dispatch queue, this function is called. This function will attempt to connect the boot devices required to load and invoke the selected operating system or system utility. During this process, additional firmware volumes may be discovered that may contain addition DXE drivers that can be dispatched by the DXE Core. If a boot device cannot be fully connected, this function calls the DXE Service Dispatch() to allow the DXE drivers from any newly discovered firmware volumes to be dispatched. Then the boot device connection can be attempted again. If the same boot device connection operation fails twice in a row, then that boot device has failed, and should be skipped. This function should never return. @param This The EFI_BDS_ARCH_PROTOCOL instance. @return None. **/ VOID EFIAPI BdsEntry ( IN EFI_BDS_ARCH_PROTOCOL *This ) { EFI_STATUS Status; UINTN NoHandles; EFI_HANDLE *Buffer; EFI_HANDLE FvHandle; EFI_HANDLE ImageHandle; EFI_HANDLE UsbDeviceHandle; EFI_GUID NameGuid; UINTN Size; UINTN HandleCount; UINTN OldHandleCount; EFI_HANDLE *HandleBuffer; UINTN Index; EFI_DEVICE_PATH_PROTOCOL *LoadImageDevicePath; EFI_DEVICE_PATH_PROTOCOL *FileSystemDevicePath; PERF_END (NULL, "DXE", NULL, 0); PERF_START (NULL, "BDS", NULL, 0); // // Now do the EFI stuff // Size = 0x100; gST->FirmwareVendor = AllocateRuntimePool (Size); ASSERT (gST->FirmwareVendor != NULL); UnicodeSPrint (gST->FirmwareVendor, Size, L"BeagleBoard EFI %a %a", __DATE__, __TIME__); // // Now we need to setup the EFI System Table with information about the console devices. // This code is normally in the console spliter driver on platforms that support multiple // consoles at the same time // Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &NoHandles, &Buffer); if (!EFI_ERROR (Status)) { // Use the first SimpleTextOut we find and update the EFI System Table gST->ConsoleOutHandle = Buffer[0]; gST->StandardErrorHandle = Buffer[0]; Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextOutProtocolGuid, (VOID **)&gST->ConOut); ASSERT_EFI_ERROR (Status); gST->StdErr = gST->ConOut; gST->ConOut->OutputString (gST->ConOut, L"BDS: Console Started!!!!\n\r"); FreePool (Buffer); gConsolePresent = TRUE; } Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInProtocolGuid, NULL, &NoHandles, &Buffer); if (!EFI_ERROR (Status)) { // Use the first SimpleTextIn we find and update the EFI System Table gST->ConsoleInHandle = Buffer[0]; Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextInProtocolGuid, (VOID **)&gST->ConIn); ASSERT_EFI_ERROR (Status); FreePool (Buffer); } // // We now have EFI Consoles up and running. Print () will work now. DEBUG () and ASSERT () worked // prior to this point as they were configured to use a more primative output scheme. // // //Perform Connect // HandleCount = 0; while (1) { OldHandleCount = HandleCount; Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { break; } if (HandleCount == OldHandleCount) { break; } for (Index = 0; Index < HandleCount; Index++) { gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); } } EfiSignalEventReadyToBoot (); //Locate handles for SimpleFileSystem protocol Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (!EFI_ERROR(Status)) { for (Index = 0; Index < HandleCount; Index++) { //Get the device path FileSystemDevicePath = DevicePathFromHandle(HandleBuffer[Index]); if (FileSystemDevicePath == NULL) { continue; } //Check if UsbIo is on any handles in the device path. Status = gBS->LocateDevicePath(&gEfiUsbIoProtocolGuid, &FileSystemDevicePath, &UsbDeviceHandle); if (EFI_ERROR(Status)) { continue; } //Check if Usb stick has a magic EBL file. LoadImageDevicePath = FileDevicePath(HandleBuffer[Index], L"Ebl.efi"); Status = gBS->LoadImage (TRUE, gImageHandle, LoadImageDevicePath, NULL, 0, &ImageHandle); if (EFI_ERROR(Status)) { continue; } //Boot to Shell on USB stick. Status = gBS->StartImage (ImageHandle, NULL, NULL); if (EFI_ERROR(Status)) { continue; } } } // // Normal UEFI behavior is to process Globally Defined Variables as defined in Chapter 3 // (Boot Manager) of the UEFI specification. For this embedded system we don't do this. // // // Search all the FVs for an application with a UI Section of Ebl. A .FDF file can be used // to control the names of UI sections in an FV. // Status = FindApplicationMatchingUiSection (L"Ebl", &FvHandle, &NameGuid); if (!EFI_ERROR (Status)) { //Boot to Shell. Status = LoadPeCoffSectionFromFv (FvHandle, &NameGuid); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "Boot from Shell failed. Status: %r\n", Status)); } } // // EFI does not define the behaviour if all boot attemps fail and the last one returns. // So we make a policy choice to reset the system since this BDS does not have a UI. // gRT->ResetSystem (EfiResetShutdown, Status, 0, NULL); return ; }
/** Initialization for authenticated varibale services. If this initialization returns error status, other APIs will not work and expect to be not called then. @param[in] AuthVarLibContextIn Pointer to input auth variable lib context. @param[out] AuthVarLibContextOut Pointer to output auth variable lib context. @retval EFI_SUCCESS Function successfully executed. @retval EFI_INVALID_PARAMETER If AuthVarLibContextIn == NULL or AuthVarLibContextOut == NULL. @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource. @retval EFI_UNSUPPORTED Unsupported to process authenticated variable. **/ EFI_STATUS EFIAPI AuthVariableLibInitialize ( IN AUTH_VAR_LIB_CONTEXT_IN *AuthVarLibContextIn, OUT AUTH_VAR_LIB_CONTEXT_OUT *AuthVarLibContextOut ) { EFI_STATUS Status; UINT8 VarValue; UINT32 VarAttr; UINT8 *Data; UINTN DataSize; UINTN CtxSize; UINT8 SecureBootMode; UINT8 SecureBootEnable; UINT8 CustomMode; UINT32 ListSize; if ((AuthVarLibContextIn == NULL) || (AuthVarLibContextOut == NULL)) { return EFI_INVALID_PARAMETER; } mAuthVarLibContextIn = AuthVarLibContextIn; // // Initialize hash context. // CtxSize = Sha256GetContextSize (); mHashCtx = AllocateRuntimePool (CtxSize); if (mHashCtx == NULL) { return EFI_OUT_OF_RESOURCES; } // // Reserve runtime buffer for public key database. The size excludes variable header and name size. // mMaxKeyDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (AUTHVAR_KEYDB_NAME)); mMaxKeyNumber = mMaxKeyDbSize / sizeof (AUTHVAR_KEY_DB_DATA); mPubKeyStore = AllocateRuntimePool (mMaxKeyDbSize); if (mPubKeyStore == NULL) { return EFI_OUT_OF_RESOURCES; } // // Reserve runtime buffer for certificate database. The size excludes variable header and name size. // Use EFI_CERT_DB_VOLATILE_NAME size since it is longer. // mMaxCertDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (EFI_CERT_DB_VOLATILE_NAME)); mCertDbStore = AllocateRuntimePool (mMaxCertDbSize); if (mCertDbStore == NULL) { return EFI_OUT_OF_RESOURCES; } // // Check "AuthVarKeyDatabase" variable's existence. // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. // Status = AuthServiceInternalFindVariable ( AUTHVAR_KEYDB_NAME, &gEfiAuthenticatedVariableGuid, (VOID **) &Data, &DataSize ); if (EFI_ERROR (Status)) { VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; VarValue = 0; mPubKeyNumber = 0; Status = AuthServiceInternalUpdateVariable ( AUTHVAR_KEYDB_NAME, &gEfiAuthenticatedVariableGuid, &VarValue, sizeof(UINT8), VarAttr ); if (EFI_ERROR (Status)) { return Status; } } else { // // Load database in global variable for cache. // ASSERT ((DataSize != 0) && (Data != NULL)); // // "AuthVarKeyDatabase" is an internal variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before) // Therefore, there is no memory overflow in underlying CopyMem. // CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize); mPubKeyNumber = (UINT32) (DataSize / sizeof (AUTHVAR_KEY_DB_DATA)); } Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME)); } else { DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME)); } // // Create "SetupMode" variable with BS+RT attribute set. // if (EFI_ERROR (Status)) { mPlatformMode = SETUP_MODE; } else { mPlatformMode = USER_MODE; } Status = AuthServiceInternalUpdateVariable ( EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, &mPlatformMode, sizeof(UINT8), EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS ); if (EFI_ERROR (Status)) { return Status; } // // Create "SignatureSupport" variable with BS+RT attribute set. // Status = AuthServiceInternalUpdateVariable ( EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, mSignatureSupport, sizeof(mSignatureSupport), EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS ); if (EFI_ERROR (Status)) { return Status; } // // If "SecureBootEnable" variable exists, then update "SecureBoot" variable. // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE. // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE. // SecureBootEnable = SECURE_BOOT_DISABLE; Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **) &Data, &DataSize); if (!EFI_ERROR (Status)) { if (mPlatformMode == USER_MODE){ SecureBootEnable = *(UINT8 *) Data; } } else if (mPlatformMode == USER_MODE) { // // "SecureBootEnable" not exist, initialize it in USER_MODE. // SecureBootEnable = SECURE_BOOT_ENABLE; Status = AuthServiceInternalUpdateVariable ( EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &SecureBootEnable, sizeof (UINT8), EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS ); if (EFI_ERROR (Status)) { return Status; } } // // Create "SecureBoot" variable with BS+RT attribute set. // if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) { SecureBootMode = SECURE_BOOT_MODE_ENABLE; } else { SecureBootMode = SECURE_BOOT_MODE_DISABLE; } Status = AuthServiceInternalUpdateVariable ( EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &SecureBootMode, sizeof (UINT8), EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS ); if (EFI_ERROR (Status)) { return Status; } DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode)); DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode)); DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable)); // // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state. // CustomMode = STANDARD_SECURE_BOOT_MODE; Status = AuthServiceInternalUpdateVariable ( EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &CustomMode, sizeof (UINT8), EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS ); if (EFI_ERROR (Status)) { return Status; } DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode)); // // Check "certdb" variable's existence. // If it doesn't exist, then create a new one with // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set. // Status = AuthServiceInternalFindVariable ( EFI_CERT_DB_NAME, &gEfiCertDbGuid, (VOID **) &Data, &DataSize ); if (EFI_ERROR (Status)) { VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; ListSize = sizeof (UINT32); Status = AuthServiceInternalUpdateVariable ( EFI_CERT_DB_NAME, &gEfiCertDbGuid, &ListSize, sizeof (UINT32), VarAttr ); if (EFI_ERROR (Status)) { return Status; } } else { // // Clean up Certs to make certDB & Time based auth variable consistent // Status = CleanCertsFromDb(); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Clean up CertDB fail! Status %x\n", Status)); return Status; } } // // Create "certdbv" variable with RT+BS+AT set. // VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; ListSize = sizeof (UINT32); Status = AuthServiceInternalUpdateVariable ( EFI_CERT_DB_VOLATILE_NAME, &gEfiCertDbGuid, &ListSize, sizeof (UINT32), VarAttr ); if (EFI_ERROR (Status)) { return Status; } // // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly. // Status = AuthServiceInternalFindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, (VOID **) &Data, &DataSize); if (!EFI_ERROR (Status)) { mVendorKeyState = *(UINT8 *)Data; } else { // // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state. // mVendorKeyState = VENDOR_KEYS_VALID; Status = AuthServiceInternalUpdateVariable ( EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, &mVendorKeyState, sizeof (UINT8), EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS ); if (EFI_ERROR (Status)) { return Status; } } // // Create "VendorKeys" variable with BS+RT attribute set. // Status = AuthServiceInternalUpdateVariable ( EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid, &mVendorKeyState, sizeof (UINT8), EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS ); if (EFI_ERROR (Status)) { return Status; } DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_VENDOR_KEYS_VARIABLE_NAME, mVendorKeyState)); AuthVarLibContextOut->StructVersion = AUTH_VAR_LIB_CONTEXT_OUT_STRUCT_VERSION; AuthVarLibContextOut->StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_OUT); AuthVarLibContextOut->AuthVarEntry = mAuthVarEntry; AuthVarLibContextOut->AuthVarEntryCount = sizeof (mAuthVarEntry) / sizeof (mAuthVarEntry[0]); mAuthVarAddressPointer[0] = (VOID **) &mPubKeyStore; mAuthVarAddressPointer[1] = (VOID **) &mCertDbStore; mAuthVarAddressPointer[2] = (VOID **) &mHashCtx; mAuthVarAddressPointer[3] = (VOID **) &mAuthVarLibContextIn; mAuthVarAddressPointer[4] = (VOID **) &(mAuthVarLibContextIn->FindVariable), mAuthVarAddressPointer[5] = (VOID **) &(mAuthVarLibContextIn->FindNextVariable), mAuthVarAddressPointer[6] = (VOID **) &(mAuthVarLibContextIn->UpdateVariable), mAuthVarAddressPointer[7] = (VOID **) &(mAuthVarLibContextIn->GetScratchBuffer), mAuthVarAddressPointer[8] = (VOID **) &(mAuthVarLibContextIn->CheckRemainingSpaceForConsistency), mAuthVarAddressPointer[9] = (VOID **) &(mAuthVarLibContextIn->AtRuntime), AuthVarLibContextOut->AddressPointer = mAuthVarAddressPointer; AuthVarLibContextOut->AddressPointerCount = sizeof (mAuthVarAddressPointer) / sizeof (mAuthVarAddressPointer[0]); // // Cache UserPhysicalPresent State. // Platform should report PhysicalPresent before this point // mUserPhysicalPresent = UserPhysicalPresent(); return Status; }
/** This function uses policy data from the platform to determine what operating system or system utility should be loaded and invoked. This function call also optionally make the use of user input to determine the operating system or system utility to be loaded and invoked. When the DXE Core has dispatched all the drivers on the dispatch queue, this function is called. This function will attempt to connect the boot devices required to load and invoke the selected operating system or system utility. During this process, additional firmware volumes may be discovered that may contain addition DXE drivers that can be dispatched by the DXE Core. If a boot device cannot be fully connected, this function calls the DXE Service Dispatch() to allow the DXE drivers from any newly discovered firmware volumes to be dispatched. Then the boot device connection can be attempted again. If the same boot device connection operation fails twice in a row, then that boot device has failed, and should be skipped. This function should never return. @param This The EFI_BDS_ARCH_PROTOCOL instance. @return None. **/ VOID EFIAPI BdsEntry ( IN EFI_BDS_ARCH_PROTOCOL *This ) { UINTN Size; EFI_STATUS Status; UINT16 *BootNext; UINTN BootNextSize; CHAR16 BootVariableName[9]; EFI_EVENT EndOfDxeEvent; // // Signal EndOfDxe PI Event // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, EmptyCallbackFunction, NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent ); if (!EFI_ERROR (Status)) { gBS->SignalEvent (EndOfDxeEvent); } PERF_END (NULL, "DXE", NULL, 0); // // Declare the Firmware Vendor // if (FixedPcdGetPtr(PcdFirmwareVendor) != NULL) { Size = 0x100; gST->FirmwareVendor = AllocateRuntimePool (Size); ASSERT (gST->FirmwareVendor != NULL); UnicodeSPrint (gST->FirmwareVendor, Size, L"%a EFI %a %a", PcdGetPtr(PcdFirmwareVendor), __DATE__, __TIME__); } // // Fixup Table CRC after we updated Firmware Vendor // gST->Hdr.CRC32 = 0; Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32); ASSERT_EFI_ERROR (Status); // If BootNext environment variable is defined then we just load it ! BootNextSize = sizeof(UINT16); Status = GetGlobalEnvironmentVariable (L"BootNext", NULL, &BootNextSize, (VOID**)&BootNext); if (!EFI_ERROR(Status)) { ASSERT(BootNextSize == sizeof(UINT16)); // Generate the requested Boot Entry variable name UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", *BootNext); // Set BootCurrent variable gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, BootNextSize, BootNext); FreePool (BootNext); // Start the requested Boot Entry Status = BdsStartBootOption (BootVariableName); if (Status != EFI_NOT_FOUND) { // BootNext has not been succeeded launched if (EFI_ERROR(Status)) { Print(L"Fail to start BootNext.\n"); } // Delete the BootNext environment variable gRT->SetVariable (L"BootNext", &gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL); } // Clear BootCurrent variable gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL); } // If Boot Order does not exist then create a default entry DefineDefaultBootEntries (); // Now we need to setup the EFI System Table with information about the console devices. InitializeConsole (); // // Update the CRC32 in the EFI System Table header // gST->Hdr.CRC32 = 0; Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32); ASSERT_EFI_ERROR (Status); // Timer before initiating the default boot selection StartDefaultBootOnTimeout (); // Start the Boot Menu Status = BootMenuMain (); ASSERT_EFI_ERROR (Status); }
EFI_STATUS NorFlashCreateInstance ( IN UINTN NorFlashDeviceBase, IN UINTN NorFlashRegionBase, IN UINTN NorFlashSize, IN UINT32 MediaId, IN UINT32 BlockSize, IN BOOLEAN SupportFvb, IN CONST GUID *NorFlashGuid, OUT NOR_FLASH_INSTANCE** NorFlashInstance ) { EFI_STATUS Status; NOR_FLASH_INSTANCE* Instance; ASSERT(NorFlashInstance != NULL); Instance = AllocateRuntimeCopyPool (sizeof(NOR_FLASH_INSTANCE),&mNorFlashInstanceTemplate); if (Instance == NULL) { return EFI_OUT_OF_RESOURCES; } Instance->DeviceBaseAddress = NorFlashDeviceBase; Instance->RegionBaseAddress = NorFlashRegionBase; Instance->Size = NorFlashSize; Instance->BlockIoProtocol.Media = &Instance->Media; Instance->Media.MediaId = MediaId; Instance->Media.BlockSize = BlockSize; Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1; CopyGuid (&Instance->DevicePath.Vendor.Guid, NorFlashGuid); Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);; if (Instance->ShadowBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } if (SupportFvb) { Instance->SupportFvb = TRUE; Instance->Initialize = NorFlashFvbInitialize; Status = gBS->InstallMultipleProtocolInterfaces ( &Instance->Handle, &gEfiDevicePathProtocolGuid, &Instance->DevicePath, &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol, &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol, NULL ); if (EFI_ERROR(Status)) { FreePool (Instance); return Status; } } else { Instance->Initialized = TRUE; Status = gBS->InstallMultipleProtocolInterfaces ( &Instance->Handle, &gEfiDevicePathProtocolGuid, &Instance->DevicePath, &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol, &gEfiDiskIoProtocolGuid, &Instance->DiskIoProtocol, NULL ); if (EFI_ERROR(Status)) { FreePool (Instance); return Status; } } *NorFlashInstance = Instance; return Status; }
EFI_STATUS EFIAPI NorFlashInitialise ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINT32 Index; NOR_FLASH_DESCRIPTION* NorFlashDevices; BOOLEAN ContainVariableStorage; Status = NorFlashPlatformInitialization (); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to initialize Nor Flash devices\n")); return Status; } Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to get Nor Flash devices\n")); return Status; } mNorFlashInstances = AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE*) * mNorFlashDeviceCount); for (Index = 0; Index < mNorFlashDeviceCount; Index++) { // Check if this NOR Flash device contain the variable storage region ContainVariableStorage = (NorFlashDevices[Index].RegionBaseAddress <= PcdGet32 (PcdFlashNvStorageVariableBase)) && (PcdGet32 (PcdFlashNvStorageVariableBase) + PcdGet32 (PcdFlashNvStorageVariableSize) <= NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size); Status = NorFlashCreateInstance ( NorFlashDevices[Index].DeviceBaseAddress, NorFlashDevices[Index].RegionBaseAddress, NorFlashDevices[Index].Size, Index, NorFlashDevices[Index].BlockSize, ContainVariableStorage, &NorFlashDevices[Index].Guid, &mNorFlashInstances[Index] ); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index)); } } // // Register for the virtual address change event // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, NorFlashVirtualNotifyEvent, NULL, &gEfiEventVirtualAddressChangeGuid, &mNorFlashVirtualAddrChangeEvent ); ASSERT_EFI_ERROR (Status); return Status; }
VOID EFIAPI PlatformBdsPolicyBehavior ( IN OUT LIST_ENTRY *DriverOptionList, IN OUT LIST_ENTRY *BootOptionList, IN PROCESS_CAPSULES ProcessCapsules, IN BASEM_MEMORY_TEST BaseMemoryTest ) /*++ Routine Description: The function will excute with as the platform policy, current policy is driven by boot mode. IBV/OEM can customize this code for their specific policy action. Arguments: DriverOptionList - The header of the driver option link list BootOptionList - The header of the boot option link list ProcessCapsules - A pointer to ProcessCapsules() BaseMemoryTest - A pointer to BaseMemoryTest() Returns: None. --*/ { EFI_STATUS Status; UINT16 Timeout; EFI_EVENT UserInputDurationTime; LIST_ENTRY *Link; BDS_COMMON_OPTION *BootOption; UINTN Index; EFI_INPUT_KEY Key; EFI_TPL OldTpl; EFI_BOOT_MODE BootMode; VBoxLogFlowFuncEnter(); ConnectRootBridge (); if (PcdGetBool (PcdOvmfFlashVariablesEnable)) { DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars " "from disk since flash variables appear to be supported.\n")); } else { // // Try to restore variables from the hard disk early so // they can be used for the other BDS connect operations. // PlatformBdsRestoreNvVarsFromHardDisk (); } // // Init the time out value // Timeout = PcdGet16 (PcdPlatformBootTimeOut); // // Load the driver option as the driver option list // PlatformBdsGetDriverOption (DriverOptionList); // // Get current Boot Mode // Status = BdsLibGetBootMode (&BootMode); DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode)); // // Go the different platform policy with different boot mode // Notes: this part code can be change with the table policy // ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION); // // Connect platform console // Status = PlatformBdsConnectConsole (gPlatformConsole); if (EFI_ERROR (Status)) { // // Here OEM/IBV can customize with defined action // PlatformBdsNoConsoleAction (); } // // Create a 300ms duration event to ensure user has enough input time to enter Setup // Status = gBS->CreateEvent ( EVT_TIMER, 0, NULL, NULL, &UserInputDurationTime ); ASSERT (Status == EFI_SUCCESS); Status = gBS->SetTimer (UserInputDurationTime, TimerRelative, 3000000); ASSERT (Status == EFI_SUCCESS); // // Memory test and Logo show // PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest); // // Perform some platform specific connect sequence // PlatformBdsConnectSequence (); // // Process QEMU's -kernel command line option // TryRunningQemuKernel (); // // Give one chance to enter the setup if we // have the time out // if (Timeout != 0) { //PlatformBdsEnterFrontPage (Timeout, FALSE); } DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n")); BdsLibConnectAll (); #ifdef VBOX { UINTN cFileSystem = 0; EFI_HANDLE *phFileSystem = NULL; BDS_COMMON_OPTION *BootOption0080 = NULL; EFI_STATUS rc = EFI_SUCCESS; DEBUG ((EFI_D_INFO, "------------------ VBox Platform Specific Initialization Start -----------------------\n")); BootOption0080 = BdsLibVariableToOption(BootOptionList, L"Boot0080"); if (!BootOption0080) { rc = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &cFileSystem, &phFileSystem); VBoxLogFlowFuncMarkRC(rc); VBoxLogFlowFuncMarkVar(cFileSystem, "%d"); if ( rc == EFI_SUCCESS && cFileSystem > 0) { EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFSVolume; EFI_FILE_HANDLE hFSRoot; EFI_FILE_HANDLE hBootEfiFile; UINTN iFileSystem = 0; /* Ok, we've found several simple file system handles * 1. we should find if '\\System\\Library\\CoreServices\\boot.efi' present * 2. Alter 'BootOrder' to include this file in boot sequence. */ for (iFileSystem = 0; iFileSystem < cFileSystem; ++iFileSystem) { EFI_DEVICE_PATH_PROTOCOL *pDevicePath = NULL; /* mount and look up the boot.efi */ rc = gBS->HandleProtocol (phFileSystem[iFileSystem], &gEfiSimpleFileSystemProtocolGuid, (VOID *) &pFSVolume); VBoxLogFlowFuncMarkVar(iFileSystem, "%d"); VBoxLogFlowFuncMarkRC(rc); if (EFI_ERROR(rc)) continue; rc = pFSVolume->OpenVolume(pFSVolume, &hFSRoot); VBoxLogFlowFuncMarkRC(rc); if (EFI_ERROR(rc)) continue; rc = hFSRoot->Open(hFSRoot, &hBootEfiFile, L"\\System\\Library\\CoreServices\\boot.efi", EFI_FILE_MODE_READ, 0); VBoxLogFlowFuncMarkRC(rc); if (EFI_ERROR(rc)) continue; /* nice file is found and we have to register it */ pDevicePath = FileDevicePath(phFileSystem[iFileSystem], L"\\System\\Library\\CoreServices\\boot.efi"); VBoxLogFlowFuncMarkVar(pDevicePath,"%p"); if (!pDevicePath) continue; rc = BdsLibRegisterNewOption (BootOptionList, pDevicePath, L"Mac Boot", L"BootOrder"); VBoxLogFlowFuncMarkRC(rc); } } } else { VBoxLogFlowFuncMarkVar(BootOption0080->LoadOptionsSize, "%d"); if (BootOption0080->LoadOptionsSize) VBoxLogFlowFuncMarkVar(BootOption0080->LoadOptions, "%s"); #if 0 /* Boot0080 option is found */ UINT16 *BootOrder; UINTN BootOrderSize; UINTN Index = 0; CHAR16 *BootOptionName; ASSERT(BootOption0080->Signature == BDS_LOAD_OPTION_SIGNATURE); BootOrder = BdsLibGetVariableAndSize ( L"BootOrder", &gEfiGlobalVariableGuid, &BootOrderSize); ASSERT(BootOrder); BootOptionName = AllocateRuntimePool(256 * sizeof(UINT16)); UnicodeSPrint(BootOptionName, 256 * sizeof(UINT16), L"Boot%04x", BootOrder[Index]); BootOption0080->OptionName = BootOptionName; rc = gRT->SetVariable(BootOptionName, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof(BDS_COMMON_OPTION), BootOption0080); LogFlowFuncMarkRC(rc); #if 0 rc = BdsLibRegisterNewOption (BootOptionList, BootOption0080->DevicePath, L"Mac Boot Temp", L"BootOrder"); #endif LogFlowFuncMarkRC(rc); #endif } DEBUG ((EFI_D_INFO, "------------------ VBox Platform Specific Initialization End -----------------------\n")); } #endif BdsLibEnumerateAllBootOption (BootOptionList); SetBootOrderFromQemu (BootOptionList); // // The BootOrder variable may have changed, reload the in-memory list with // it. // BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); // // To give the User a chance to enter Setup here, if user set TimeOut is 0. // BDS should still give user a chance to enter Setup // // Connect first boot option, and then check user input before exit // for (Link = BootOptionList->ForwardLink; Link != BootOptionList;Link = Link->ForwardLink) { BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) { // // skip the header of the link list, becuase it has no boot option // continue; } else { // // Make sure the boot option device path connected, but ignore the BBS device path // if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) { BdsLibConnectDevicePath (BootOption->DevicePath); } break; } } // // Check whether the user input after the duration time has expired // OldTpl = EfiGetCurrentTpl(); gBS->RestoreTPL (TPL_APPLICATION); gBS->WaitForEvent (1, &UserInputDurationTime, &Index); gBS->CloseEvent (UserInputDurationTime); Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); gBS->RaiseTPL (OldTpl); if (!EFI_ERROR (Status)) { // // Enter Setup if user input // Timeout = 0xffff; PlatformBdsEnterFrontPage (Timeout, FALSE); } VBoxLogFlowFuncLeave(); return ; }
EFI_STATUS EFIAPI FvbInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /*++ Routine Description: This function does common initialization for FVB services Arguments: Returns: --*/ { EFI_STATUS Status; EFI_FW_VOL_INSTANCE *FwhInstance; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_DXE_SERVICES *DxeServices; EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; UINT32 BufferSize; EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; EFI_HANDLE FwbHandle; EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface; UINT32 MaxLbaSize; EFI_PHYSICAL_ADDRESS BaseAddress; UINT64 Length; UINTN NumOfBlocks; EFI_PEI_HOB_POINTERS FvHob; // // Get the DXE services table // DxeServices = gDS; // // Allocate runtime services data for global variable, which contains // the private data of all firmware volume block instances // mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL)); ASSERT (mFvbModuleGlobal != NULL); // // Calculate the total size for all firmware volume block instances // BufferSize = 0; FvHob.Raw = GetHobList (); while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) { BaseAddress = FvHob.FirmwareVolume->BaseAddress; Length = FvHob.FirmwareVolume->Length; // // Check if it is a "real" flash // Status = DxeServices->GetMemorySpaceDescriptor ( BaseAddress, &Descriptor ); if (EFI_ERROR (Status)) { break; } if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) { FvHob.Raw = GET_NEXT_HOB (FvHob); continue; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; Status = ValidateFvHeader (FwVolHeader); if (EFI_ERROR (Status)) { // // Get FvbInfo // Status = GetFvbInfo (Length, &FwVolHeader); if (EFI_ERROR (Status)) { FvHob.Raw = GET_NEXT_HOB (FvHob); continue; } } BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER)); FvHob.Raw = GET_NEXT_HOB (FvHob); } // // Only need to allocate once. There is only one copy of physical memory for // the private data of each FV instance. But in virtual mode or in physical // mode, the address of the the physical memory may be different. // mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = AllocateRuntimePool (BufferSize); ASSERT (mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] != NULL); // // Make a virtual copy of the FvInstance pointer. // FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance; mFvbModuleGlobal->NumFv = 0; MaxLbaSize = 0; FvHob.Raw = GetHobList (); while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) { BaseAddress = FvHob.FirmwareVolume->BaseAddress; Length = FvHob.FirmwareVolume->Length; // // Check if it is a "real" flash // Status = DxeServices->GetMemorySpaceDescriptor ( BaseAddress, &Descriptor ); if (EFI_ERROR (Status)) { break; } if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) { FvHob.Raw = GET_NEXT_HOB (FvHob); continue; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; Status = ValidateFvHeader (FwVolHeader); if (EFI_ERROR (Status)) { // // Get FvbInfo to provide in FwhInstance. // Status = GetFvbInfo (Length, &FwVolHeader); if (EFI_ERROR (Status)) { FvHob.Raw = GET_NEXT_HOB (FvHob); continue; } // // Write healthy FV header back. // CopyMem ( (VOID *) (UINTN) BaseAddress, (VOID *) FwVolHeader, FwVolHeader->HeaderLength ); } FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress; FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress; CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength); FwVolHeader = &(FwhInstance->VolumeHeader); EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL); NumOfBlocks = 0; for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { // // Get the maximum size of a block. // if (MaxLbaSize < PtrBlockMapEntry->Length) { MaxLbaSize = PtrBlockMapEntry->Length; } NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks; } // // The total number of blocks in the FV. // FwhInstance->NumOfBlocks = NumOfBlocks; // // Add a FVB Protocol Instance // FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE)); ASSERT (FvbDevice != NULL); CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE)); FvbDevice->Instance = mFvbModuleGlobal->NumFv; mFvbModuleGlobal->NumFv++; // // Set up the devicepath // if (FwVolHeader->ExtHeaderOffset == 0) { // // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH // FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate); ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress; ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1; } else { FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate); CopyGuid ( &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName, (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset) ); } // // Find a handle with a matching device path that has supports FW Block protocol // Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &FvbDevice->DevicePath, &FwbHandle); if (EFI_ERROR (Status)) { // // LocateDevicePath fails so install a new interface and device path // FwbHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &FwbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDevice->FwVolBlockInstance, &gEfiDevicePathProtocolGuid, FvbDevice->DevicePath, NULL ); ASSERT_EFI_ERROR (Status); } else if (IsDevicePathEnd (FvbDevice->DevicePath)) { // // Device allready exists, so reinstall the FVB protocol // Status = gBS->HandleProtocol ( FwbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID**)&OldFwbInterface ); ASSERT_EFI_ERROR (Status); Status = gBS->ReinstallProtocolInterface ( FwbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, OldFwbInterface, &FvbDevice->FwVolBlockInstance ); ASSERT_EFI_ERROR (Status); } else { // // There was a FVB protocol on an End Device Path node // ASSERT (FALSE); } FwhInstance = (EFI_FW_VOL_INSTANCE *) ( (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) ); FvHob.Raw = GET_NEXT_HOB (FvHob); } return EFI_SUCCESS; }
/** Writes the specified number of bytes from the input buffer to the block. The Write() function writes the specified number of bytes from the provided buffer to the specified block and offset. If the firmware volume is sticky write, the caller must ensure that all the bits of the specified range to write are in the EFI_FVB_ERASE_POLARITY state before calling the Write() function, or else the result will be unpredictable. This unpredictability arises because, for a sticky-write firmware volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY state but cannot flip it back again. Before calling the Write() function, it is recommended for the caller to first call the EraseBlocks() function to erase the specified block to write. A block erase cycle will transition bits from the (NOT)EFI_FVB_ERASE_POLARITY state back to the EFI_FVB_ERASE_POLARITY state. Implementations should be mindful that the firmware volume might be in the WriteDisabled state. If it is in this state, the Write() function must return the status code EFI_ACCESS_DENIED without modifying the contents of the firmware volume. The Write() function must also prevent spanning block boundaries. If a write is requested that spans a block boundary, the write must store up to the boundary but not beyond. The output parameter NumBytes must be set to correctly indicate the number of bytes actually written. The caller must be aware that a write may be partially completed. All writes, partial or otherwise, must be fully flushed to the hardware before the Write() service returns. @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. @param Lba The starting logical block index to write to. @param Offset Offset into the block at which to begin writing. @param NumBytes The pointer to a UINTN. At entry, *NumBytes contains the total size of the buffer. At exit, *NumBytes contains the total number of bytes actually written. @param Buffer The pointer to a caller-allocated buffer that contains the source for the write. @retval EFI_SUCCESS The firmware volume was written successfully. @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary. On output, NumBytes contains the total number of bytes actually written. @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be written. **/ EFI_STATUS EFIAPI FvbWrite ( IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Offset, IN OUT UINTN *NumBytes, IN UINT8 *Buffer ) { EFI_STATUS Status; EFI_STATUS TempStatus; UINTN BlockSize; UINT8 *BlockBuffer; NOR_FLASH_INSTANCE *Instance; Instance = INSTANCE_FROM_FVB_THIS(This); if (!Instance->Initialized && Instance->Initialize) { Instance->Initialize(Instance); } DEBUG ((DEBUG_BLKIO, "FvbWrite(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Instance->StartLba + Lba, Offset, *NumBytes, Buffer)); Status = EFI_SUCCESS; TempStatus = Status; // Detect WriteDisabled state if (Instance->Media.ReadOnly == TRUE) { DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - Can not write: Device is in WriteDisabled state.\n")); // It is in WriteDisabled state, return an error right away return EFI_ACCESS_DENIED; } // Cache the block size to avoid de-referencing pointers all the time BlockSize = Instance->Media.BlockSize; // The write must not span block boundaries. // We need to check each variable individually because adding two large values together overflows. if ( ( Offset >= BlockSize ) || ( *NumBytes > BlockSize ) || ( (Offset + *NumBytes) > BlockSize ) ) { DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); return EFI_BAD_BUFFER_SIZE; } // We must have some bytes to write if (*NumBytes == 0) { DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); return EFI_BAD_BUFFER_SIZE; } // Allocate runtime memory to read in the NOR Flash data. // Since the intention is to use this with Variable Services and since these are runtime, // allocate the memory from the runtime pool. BlockBuffer = AllocateRuntimePool (BlockSize); // Check we did get some memory if( BlockBuffer == NULL ) { DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - Can not allocate BlockBuffer @ 0x%08x.\n", BlockBuffer)); return EFI_DEVICE_ERROR; } // Read NOR Flash data into shadow buffer TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, BlockSize, BlockBuffer); if (EFI_ERROR (TempStatus)) { // Return one of the pre-approved error statuses Status = EFI_DEVICE_ERROR; goto FREE_MEMORY; } // Put the data at the appropriate location inside the buffer area CopyMem((BlockBuffer + Offset), Buffer, *NumBytes); // Write the modified buffer back to the NorFlash Status = NorFlashWriteBlocks (Instance, Instance->StartLba + Lba, BlockSize, BlockBuffer); if (EFI_ERROR (TempStatus)) { // Return one of the pre-approved error statuses Status = EFI_DEVICE_ERROR; goto FREE_MEMORY; } FREE_MEMORY: FreePool(BlockBuffer); return Status; }
/** Reads the specified number of bytes into a buffer from the specified block. The Read() function reads the requested number of bytes from the requested block and stores them in the provided buffer. Implementations should be mindful that the firmware volume might be in the ReadDisabled state. If it is in this state, the Read() function must return the status code EFI_ACCESS_DENIED without modifying the contents of the buffer. The Read() function must also prevent spanning block boundaries. If a read is requested that would span a block boundary, the read must read up to the boundary but not beyond. The output parameter NumBytes must be set to correctly indicate the number of bytes actually read. The caller must be aware that a read may be partially completed. @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. @param Lba The starting logical block index from which to read. @param Offset Offset into the block at which to begin reading. @param NumBytes Pointer to a UINTN. At entry, *NumBytes contains the total size of the buffer. At exit, *NumBytes contains the total number of bytes read. @param Buffer Pointer to a caller-allocated buffer that will be used to hold the data that is read. @retval EFI_SUCCESS The firmware volume was read successfully, and contents are in Buffer. @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary. On output, NumBytes contains the total number of bytes returned in Buffer. @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be read. **/ EFI_STATUS EFIAPI FvbRead ( IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Offset, IN OUT UINTN *NumBytes, IN OUT UINT8 *Buffer ) { EFI_STATUS Status; EFI_STATUS TempStatus; UINTN BlockSize; UINT8 *BlockBuffer; NOR_FLASH_INSTANCE *Instance; Instance = INSTANCE_FROM_FVB_THIS(This); DEBUG ((DEBUG_BLKIO, "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Instance->StartLba + Lba, Offset, *NumBytes, Buffer)); if (!Instance->Initialized && Instance->Initialize) { Instance->Initialize(Instance); } Status = EFI_SUCCESS; TempStatus = Status; // Cache the block size to avoid de-referencing pointers all the time BlockSize = Instance->Media.BlockSize; DEBUG ((DEBUG_BLKIO, "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); // The read must not span block boundaries. // We need to check each variable individually because adding two large values together overflows. if ((Offset >= BlockSize) || (*NumBytes > BlockSize) || ((Offset + *NumBytes) > BlockSize)) { DEBUG ((EFI_D_ERROR, "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); return EFI_BAD_BUFFER_SIZE; } // We must have some bytes to read if (*NumBytes == 0) { return EFI_BAD_BUFFER_SIZE; } // FixMe: Allow an arbitrary number of bytes to be read out, not just a multiple of block size. // Allocate runtime memory to read in the NOR Flash data. Variable Services are runtime. BlockBuffer = AllocateRuntimePool (BlockSize); // Check if the memory allocation was successful if (BlockBuffer == NULL) { DEBUG ((EFI_D_ERROR, "FvbRead: ERROR - Could not allocate BlockBuffer @ 0x%08x.\n", BlockBuffer)); return EFI_DEVICE_ERROR; } // Read NOR Flash data into shadow buffer TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, BlockSize, BlockBuffer); if (EFI_ERROR (TempStatus)) { // Return one of the pre-approved error statuses Status = EFI_DEVICE_ERROR; goto FREE_MEMORY; } // Put the data at the appropriate location inside the buffer area DEBUG ((DEBUG_BLKIO, "FvbRead: CopyMem( Dst=0x%08x, Src=0x%08x, Size=0x%x ).\n", Buffer, BlockBuffer + Offset, *NumBytes)); CopyMem(Buffer, BlockBuffer + Offset, *NumBytes); FREE_MEMORY: FreePool(BlockBuffer); return Status; }
/** This function populates capsule in the configuration table. **/ VOID PopulateCapsuleInConfigurationTable ( VOID ) { VOID **CapsulePtrCache; EFI_GUID *CapsuleGuidCache; EFI_CAPSULE_HEADER *CapsuleHeader; EFI_CAPSULE_TABLE *CapsuleTable; UINT32 CacheIndex; UINT32 CacheNumber; UINT32 CapsuleNumber; UINTN Index; UINTN Size; EFI_STATUS Status; if (mCapsuleTotalNumber == 0) { return ; } CapsulePtrCache = NULL; CapsuleGuidCache = NULL; CacheIndex = 0; CacheNumber = 0; CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber); if (CapsulePtrCache == NULL) { DEBUG ((DEBUG_ERROR, "Allocate CapsulePtrCache fail!\n")); return ; } CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * mCapsuleTotalNumber); if (CapsuleGuidCache == NULL) { DEBUG ((DEBUG_ERROR, "Allocate CapsuleGuidCache fail!\n")); FreePool (CapsulePtrCache); return ; } // // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating // System to have information persist across a system reset. EFI System Table must // point to an array of capsules that contains the same CapsuleGuid value. And agents // searching for this type capsule will look in EFI System Table and search for the // capsule's Guid and associated pointer to retrieve the data. Two steps below describes // how to sorting the capsules by the unique guid and install the array to EFI System Table. // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an // array for later sorting capsules by CapsuleGuid. // for (Index = 0; Index < mCapsuleTotalNumber; Index++) { CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index]; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) { // // For each capsule, we compare it with known CapsuleGuid in the CacheArray. // If already has the Guid, skip it. Whereas, record it in the CacheArray as // an additional one. // CacheIndex = 0; while (CacheIndex < CacheNumber) { if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) { break; } CacheIndex++; } if (CacheIndex == CacheNumber) { CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID)); } } } // // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules // whose guid is the same as it, and malloc memory for an array which preceding // with UINT32. The array fills with entry point of capsules that have the same // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install // this array into EFI System Table, so that agents searching for this type capsule // will look in EFI System Table and search for the capsule's Guid and associated // pointer to retrieve the data. // for (CacheIndex = 0; CacheIndex < CacheNumber; CacheIndex++) { CapsuleNumber = 0; for (Index = 0; Index < mCapsuleTotalNumber; Index++) { CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index]; if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) { if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) { // // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid. // CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader; } } } if (CapsuleNumber != 0) { Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*); CapsuleTable = AllocateRuntimePool (Size); if (CapsuleTable == NULL) { DEBUG ((DEBUG_ERROR, "Allocate CapsuleTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex])); continue; } CapsuleTable->CapsuleArrayNumber = CapsuleNumber; CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*)); Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "InstallConfigurationTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex])); } } } FreePool(CapsuleGuidCache); FreePool(CapsulePtrCache); }