Beispiel #1
0
/**
  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;
}
Beispiel #3
0
/**
  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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
/**
  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;
}
Beispiel #7
0
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);
}
Beispiel #8
0
/**
  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
  }

}
Beispiel #9
0
/** 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);
			}
		}
	}
}
Beispiel #10
0
/**
  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;
}
Beispiel #11
0
/**

  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;
}
Beispiel #12
0
/**
  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 ;
}
Beispiel #13
0
/**
  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;
}
Beispiel #14
0
/**
  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);

}
Beispiel #15
0
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;
}
Beispiel #16
0
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;
}
Beispiel #17
0
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 ;
}
Beispiel #18
0
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;
}
Beispiel #19
0
/**
 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;
}
Beispiel #20
0
/**
 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;
}
Beispiel #21
0
/**
  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);
}