123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- dispatch.c
- Abstract:
- This module implements the driver dispatcher.
- Author:
- Evan Green 12-Mar-2014
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "ueficore.h"
- #include "fwvolp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define EFI_CORE_DRIVER_ENTRY_MAGIC 0x76697244 // 'virD'
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef struct _EFI_KNOWN_HANDLE {
- LIST_ENTRY ListEntry;
- EFI_HANDLE Handle;
- EFI_GUID NameGuid;
- } EFI_KNOWN_HANDLE, *PEFI_KNOWN_HANDLE;
- typedef struct _EFI_CORE_DRIVER_ENTRY {
- UINTN Magic;
- LIST_ENTRY DriverListEntry;
- LIST_ENTRY SchedulerListEntry;
- EFI_HANDLE VolumeHandle;
- EFI_GUID FileName;
- EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Volume;
- EFI_HANDLE ImageHandle;
- BOOLEAN IsFirmwareVolumeImage;
- BOOLEAN Untrusted;
- BOOLEAN Initialized;
- BOOLEAN Scheduled;
- BOOLEAN Dependent;
- } EFI_CORE_DRIVER_ENTRY, *PEFI_CORE_DRIVER_ENTRY;
- typedef struct _EFI_FIRMWARE_VOLUME_FILE_DEVICE_PATH {
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;
- EFI_DEVICE_PATH_PROTOCOL End;
- } EFI_FIRMWARE_VOLUME_FILE_DEVICE_PATH, *PEFI_FIRMWARE_VOLUME_FILE_DEVICE_PATH;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- EFIAPI
- VOID
- EfipFirmwareVolumeEventProtocolNotify (
- EFI_EVENT Event,
- VOID *Context
- );
- BOOLEAN
- EfipFirmwareVolumeHasBeenProcessed (
- EFI_HANDLE Handle
- );
- PEFI_KNOWN_HANDLE
- EfipMarkFirmwareVolumeProcessed (
- EFI_HANDLE Handle
- );
- EFI_STATUS
- EfipCoreAddDriverToList (
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Volume,
- EFI_HANDLE VolumeHandle,
- EFI_GUID *DriverName,
- EFI_FV_FILETYPE Type
- );
- EFI_DEVICE_PATH_PROTOCOL *
- EfipCoreConvertFirmwareVolumeFileToDevicePath (
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Volume,
- EFI_HANDLE VolumeHandle,
- EFI_GUID *DriverName
- );
- VOID
- EfipCoreInsertOnScheduledQueue (
- PEFI_CORE_DRIVER_ENTRY DriverEntry
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store the list of known firmware volume handles.
- //
- LIST_ENTRY EfiFirmwareVolumeList;
- //
- // Define the variables used to register for firmware volume arrivals.
- //
- EFI_EVENT EfiFirmwareVolumeEvent;
- VOID *EfiFirmwareVolumeEventRegistration;
- //
- // Define the list of file types supported by the dispatcher.
- //
- EFI_FV_FILETYPE EfiDispatcherFileTypes[] = {
- EFI_FV_FILETYPE_DRIVER,
- EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
- };
- EFI_LOCK EfiDispatcherLock;
- LIST_ENTRY EfiDiscoveredList;
- LIST_ENTRY EfiScheduledQueue;
- BOOLEAN EfiDispatcherRunning;
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- EfiCoreInitializeDispatcher (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes the driver dispatcher.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- INITIALIZE_LIST_HEAD(&EfiFirmwareVolumeList);
- INITIALIZE_LIST_HEAD(&EfiDiscoveredList);
- INITIALIZE_LIST_HEAD(&EfiScheduledQueue);
- EfiCoreInitializeLock(&EfiDispatcherLock, TPL_HIGH_LEVEL);
- EfiFirmwareVolumeEvent = EfiCoreCreateProtocolNotifyEvent(
- &EfiFirmwareVolume2ProtocolGuid,
- TPL_CALLBACK,
- EfipFirmwareVolumeEventProtocolNotify,
- NULL,
- &EfiFirmwareVolumeEventRegistration);
- ASSERT(EfiFirmwareVolumeEvent != NULL);
- return;
- }
- EFIAPI
- EFI_STATUS
- EfiCoreDispatcher (
- VOID
- )
- /*++
- Routine Description:
- This routine runs the driver dispatcher. It drains the scheduled queue
- loading and starting drivers until there are no more drivers to run.
- Arguments:
- None.
- Return Value:
- EFI_SUCCESS if one or more drivers were loaded.
- EFI_NOT_FOUND if no drivers were loaded.
- EFI_ALREADY_STARTED if the dispatcher is already running.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PEFI_CORE_DRIVER_ENTRY DriverEntry;
- BOOLEAN ReadyToRun;
- EFI_STATUS ReturnStatus;
- EFI_STATUS Status;
- if (EfiDispatcherRunning != FALSE) {
- return EFI_ALREADY_STARTED;
- }
- EfiDispatcherRunning = TRUE;
- ReturnStatus = EFI_NOT_FOUND;
- do {
- //
- // Drain the scheduled queue.
- //
- while (LIST_EMPTY(&EfiScheduledQueue) == FALSE) {
- DriverEntry = LIST_VALUE(EfiScheduledQueue.Next,
- EFI_CORE_DRIVER_ENTRY,
- SchedulerListEntry);
- ASSERT(DriverEntry->Magic == EFI_CORE_DRIVER_ENTRY_MAGIC);
- //
- // Load the driver into memory if needed.
- //
- if ((DriverEntry->ImageHandle == NULL) &&
- (DriverEntry->IsFirmwareVolumeImage == FALSE)) {
- Status = EfiCoreLoadImage(FALSE,
- EfiFirmwareImageHandle,
- DriverEntry->FileDevicePath,
- NULL,
- 0,
- &(DriverEntry->ImageHandle));
- if (EFI_ERROR(Status)) {
- RtlDebugPrint("Warning: Driver failed load with status "
- "%x\n",
- Status);
- EfiCoreAcquireLock(&EfiDispatcherLock);
- if (Status == EFI_SECURITY_VIOLATION) {
- DriverEntry->Untrusted = TRUE;
- } else {
- DriverEntry->Initialized = TRUE;
- }
- DriverEntry->Scheduled = FALSE;
- LIST_REMOVE(&(DriverEntry->SchedulerListEntry));
- EfiCoreReleaseLock(&EfiDispatcherLock);
- //
- // Don't try to start this image, it failed to load.
- //
- continue;
- }
- }
- EfiCoreAcquireLock(&EfiDispatcherLock);
- DriverEntry->Scheduled = FALSE;
- DriverEntry->Initialized = TRUE;
- LIST_REMOVE(&(DriverEntry->SchedulerListEntry));
- EfiCoreReleaseLock(&EfiDispatcherLock);
- if (DriverEntry->IsFirmwareVolumeImage == FALSE) {
- ASSERT(DriverEntry->ImageHandle != NULL);
- Status = EfiCoreStartImage(DriverEntry->ImageHandle,
- NULL,
- NULL);
- if (EFI_ERROR(Status)) {
- RtlDebugPrint("Warning: Driver start failed with "
- "status %x\n",
- Status);
- }
- }
- ReturnStatus = EFI_SUCCESS;
- }
- //
- // Search the discovered list for items to place on the scheduled
- // queue.
- //
- ReadyToRun = FALSE;
- CurrentEntry = EfiDiscoveredList.Next;
- while (CurrentEntry != &EfiDiscoveredList) {
- DriverEntry = LIST_VALUE(CurrentEntry,
- EFI_CORE_DRIVER_ENTRY,
- DriverListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (DriverEntry->Dependent != FALSE) {
- EfipCoreInsertOnScheduledQueue(DriverEntry);
- ReadyToRun = TRUE;
- }
- }
- } while (ReadyToRun != FALSE);
- EfiDispatcherRunning = FALSE;
- return ReturnStatus;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- EFIAPI
- VOID
- EfipFirmwareVolumeEventProtocolNotify (
- EFI_EVENT Event,
- VOID *Context
- )
- /*++
- Routine Description:
- This routine is called when a new firmware volume protocol appears in the
- system.
- Arguments:
- Event - Supplies a pointer to the event that fired.
- Context - Supplies an unused context pointer.
- Return Value:
- None.
- --*/
- {
- EFI_FV_FILE_ATTRIBUTES Attributes;
- UINTN BufferSize;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- UINTN FileTypeCount;
- EFI_STATUS GetNextFileStatus;
- UINTN Index;
- UINTN Key;
- PEFI_KNOWN_HANDLE KnownHandle;
- EFI_GUID NameGuid;
- UINTN Size;
- EFI_STATUS Status;
- EFI_FV_FILETYPE Type;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Volume;
- EFI_HANDLE VolumeHandle;
- //
- // Loop through all the new firmware volumes.
- //
- while (TRUE) {
- BufferSize = sizeof(EFI_HANDLE);
- Status = EfiCoreLocateHandle(ByRegisterNotify,
- NULL,
- EfiFirmwareVolumeEventRegistration,
- &BufferSize,
- &VolumeHandle);
- if (EFI_ERROR(Status)) {
- break;
- }
- if (EfipFirmwareVolumeHasBeenProcessed(VolumeHandle) != FALSE) {
- continue;
- }
- KnownHandle = EfipMarkFirmwareVolumeProcessed(VolumeHandle);
- if (KnownHandle == NULL) {
- continue;
- }
- Status = EfiCoreHandleProtocol(VolumeHandle,
- &EfiFirmwareVolume2ProtocolGuid,
- (VOID **)&Volume);
- if ((EFI_ERROR(Status)) || (Volume == NULL)) {
- ASSERT(FALSE);
- continue;
- }
- Status = EfiCoreHandleProtocol(VolumeHandle,
- &EfiDevicePathProtocolGuid,
- (VOID **)&DevicePath);
- if (EFI_ERROR(Status)) {
- continue;
- }
- //
- // Discover drivers in the firmware volume and add them to the
- // discovered driver list.
- //
- FileTypeCount = sizeof(EfiDispatcherFileTypes) /
- sizeof(EfiDispatcherFileTypes[0]);
- for (Index = 0; Index < FileTypeCount; Index += 1) {
- Key = 0;
- while (TRUE) {
- Type = EfiDispatcherFileTypes[Index];
- GetNextFileStatus = Volume->GetNextFile(Volume,
- &Key,
- &Type,
- &NameGuid,
- &Attributes,
- &Size);
- if (EFI_ERROR(GetNextFileStatus)) {
- break;
- }
- EfipCoreAddDriverToList(Volume, VolumeHandle, &NameGuid, Type);
- }
- }
- }
- return;
- }
- BOOLEAN
- EfipFirmwareVolumeHasBeenProcessed (
- EFI_HANDLE Handle
- )
- /*++
- Routine Description:
- This routine determines if the given firmware volume has been processed.
- Arguments:
- Handle - Supplies the handle to the volume.
- Return Value:
- TRUE if the handle has been processed.
- FALSE if the handle has not been processed.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PEFI_KNOWN_HANDLE KnownHandle;
- CurrentEntry = EfiFirmwareVolumeList.Next;
- while (CurrentEntry != &EfiFirmwareVolumeList) {
- KnownHandle = LIST_VALUE(CurrentEntry, EFI_KNOWN_HANDLE, ListEntry);
- if (KnownHandle->Handle == Handle) {
- return TRUE;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- return FALSE;
- }
- PEFI_KNOWN_HANDLE
- EfipMarkFirmwareVolumeProcessed (
- EFI_HANDLE Handle
- )
- /*++
- Routine Description:
- This routine marks a firmware volume handle as having been processed. This
- function adds entries on the firmware volume list if the new entry is
- different from the one in the handle list by checking the firmware volume
- image GUID. Items are never removed/free from the firmware volume list.
- Arguments:
- Handle - Supplies the handle to the volume.
- Return Value:
- Returns a pointer to the new known handle structure.
- NULL if a firmware volume with the same GUID was already processed.
- --*/
- {
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BlockIo;
- EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
- PLIST_ENTRY CurrentEntry;
- UINT32 ExtHeaderOffset;
- UINTN Index;
- PEFI_KNOWN_HANDLE KnownHandle;
- EFI_LBA LbaIndex;
- UINTN LbaOffset;
- EFI_GUID NameGuid;
- BOOLEAN NameGuidFound;
- EFI_STATUS Status;
- EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader;
- NameGuidFound = FALSE;
- //
- // Get the firmware volume block protocol on the handle. Going rogue.
- //
- Status = EfiCoreHandleProtocol(Handle,
- &EfiFirmwareVolumeBlockProtocolGuid,
- (VOID **)&BlockIo);
- if (!EFI_ERROR(Status)) {
- //
- // Get the full volume header using the block I/O protocol.
- //
- ASSERT(BlockIo != NULL);
- Status = EfiFvGetVolumeHeader(BlockIo, &VolumeHeader);
- if (!EFI_ERROR(Status)) {
- ASSERT(VolumeHeader != NULL);
- if ((EfiFvVerifyHeaderChecksum(VolumeHeader) != FALSE) &&
- (VolumeHeader->ExtHeaderOffset != 0)) {
- ExtHeaderOffset = VolumeHeader->ExtHeaderOffset;
- BlockMap = VolumeHeader->BlockMap;
- LbaIndex = 0;
- LbaOffset = 0;
- //
- // Find the LBA index and offset for the volume extension
- // header using the block map.
- //
- while ((BlockMap->BlockCount != 0) ||
- (BlockMap->BlockLength != 0)) {
- for (Index = 0;
- Index < BlockMap->BlockCount;
- Index += 1) {
- if (ExtHeaderOffset < BlockMap->BlockLength) {
- break;
- }
- ExtHeaderOffset -= BlockMap->BlockLength;
- LbaIndex += 1;
- }
- if (Index < BlockMap->BlockCount) {
- LbaOffset = ExtHeaderOffset;
- break;
- }
- BlockMap += 1;
- }
- Status = EfiFvReadData(BlockIo,
- &LbaIndex,
- &LbaOffset,
- sizeof(NameGuid),
- (UINT8 *)&NameGuid);
- if (!EFI_ERROR(Status)) {
- NameGuidFound = TRUE;
- }
- }
- EfiCoreFreePool(VolumeHeader);
- }
- }
- //
- // If a name GUID for this volume was found, compare it with all the other
- // known volumes.
- //
- if (NameGuidFound != FALSE) {
- CurrentEntry = EfiFirmwareVolumeList.Next;
- while (CurrentEntry != &EfiFirmwareVolumeList) {
- KnownHandle = LIST_VALUE(CurrentEntry, EFI_KNOWN_HANDLE, ListEntry);
- if (EfiCoreCompareGuids(&NameGuid, &(KnownHandle->NameGuid)) !=
- FALSE) {
- RtlDebugPrint("Found two firmware volumes with the same GUID. "
- "Skipping one!\n");
- return NULL;
- }
- }
- }
- KnownHandle = EfiCoreAllocateBootPool(sizeof(EFI_KNOWN_HANDLE));
- if (KnownHandle == NULL) {
- ASSERT(FALSE);
- return NULL;
- }
- EfiCoreSetMemory(KnownHandle, sizeof(EFI_KNOWN_HANDLE), 0);
- KnownHandle->Handle = Handle;
- if (NameGuidFound != FALSE) {
- EfiCoreCopyMemory(&(KnownHandle->NameGuid),
- &NameGuid,
- sizeof(EFI_GUID));
- }
- INSERT_BEFORE(&(KnownHandle->ListEntry), &EfiFirmwareVolumeList);
- return KnownHandle;
- }
- EFI_STATUS
- EfipCoreAddDriverToList (
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Volume,
- EFI_HANDLE VolumeHandle,
- EFI_GUID *DriverName,
- EFI_FV_FILETYPE Type
- )
- /*++
- Routine Description:
- This routine adds a driver entry to the discovered list.
- Arguments:
- Volume - Supplies a pointer to the firmware volume.
- VolumeHandle - Supplies the firmware volume handle.
- DriverName - Supplies a pointer to the GUID of the driver's name.
- Type - Supplies the file type.
- Return Value:
- EFI_SUCCESS on success.
- EFI_ALREADY_STARTED if the driver has already been started.
- --*/
- {
- EFI_CORE_DRIVER_ENTRY *DriverEntry;
- DriverEntry = EfiCoreAllocateBootPool(sizeof(EFI_CORE_DRIVER_ENTRY));
- if (DriverEntry == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- EfiCoreSetMemory(DriverEntry, sizeof(EFI_CORE_DRIVER_ENTRY), 0);
- if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
- DriverEntry->IsFirmwareVolumeImage = TRUE;
- }
- DriverEntry->Magic = EFI_CORE_DRIVER_ENTRY_MAGIC;
- EfiCoreCopyMemory(&(DriverEntry->FileName), DriverName, sizeof(EFI_GUID));
- DriverEntry->VolumeHandle = VolumeHandle;
- DriverEntry->Volume = Volume;
- DriverEntry->FileDevicePath =
- EfipCoreConvertFirmwareVolumeFileToDevicePath(Volume,
- VolumeHandle,
- DriverName);
- DriverEntry->Dependent = TRUE;
- EfiCoreAcquireLock(&EfiDispatcherLock);
- INSERT_BEFORE(&(DriverEntry->DriverListEntry), &EfiDiscoveredList);
- EfiCoreReleaseLock(&EfiDispatcherLock);
- return EFI_SUCCESS;
- }
- EFI_DEVICE_PATH_PROTOCOL *
- EfipCoreConvertFirmwareVolumeFileToDevicePath (
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Volume,
- EFI_HANDLE VolumeHandle,
- EFI_GUID *DriverName
- )
- /*++
- Routine Description:
- This routine converts a firmware volume and driver name into an EFI
- device path.
- Arguments:
- Volume - Supplies a pointer to the firmware volume.
- VolumeHandle - Supplies the firmware volume handle.
- DriverName - Supplies a pointer to the GUID of the driver's name.
- Return Value:
- Returns a pointer to the file device path.
- --*/
- {
- EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
- EFI_FIRMWARE_VOLUME_FILE_DEVICE_PATH FileNameDevicePath;
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *VolumeDevicePath;
- Status = EfiCoreHandleProtocol(VolumeHandle,
- &EfiDevicePathProtocolGuid,
- (VOID **)&VolumeDevicePath);
- if (EFI_ERROR(Status)) {
- return NULL;
- }
- //
- // Build a device path to the file in the volume.
- //
- EfiCoreInitializeFirmwareVolumeDevicePathNode(&(FileNameDevicePath.File),
- DriverName);
- EfiCoreSetDevicePathEndNode(&(FileNameDevicePath.End));
- FileDevicePath = EfiCoreAppendDevicePath(
- VolumeDevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&FileNameDevicePath);
- return FileDevicePath;
- }
- VOID
- EfipCoreInsertOnScheduledQueue (
- PEFI_CORE_DRIVER_ENTRY DriverEntry
- )
- /*++
- Routine Description:
- This routine inserts a driver entry onto the scheduled queue.
- Arguments:
- DriverEntry - Supplies a pointer to the driver entry to schedule.
- Return Value:
- None.
- --*/
- {
- EfiCoreAcquireLock(&EfiDispatcherLock);
- DriverEntry->Dependent = FALSE;
- DriverEntry->Scheduled = TRUE;
- INSERT_BEFORE(&(DriverEntry->SchedulerListEntry), &EfiScheduledQueue);
- EfiCoreReleaseLock(&EfiDispatcherLock);
- return;
- }
|