EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) { EFI_STATUS Status; EFI_BLOCK_IO *BlockIo; EFI_DISK_IO *DiskIo; FSW_VOLUME_DATA *Volume; VBoxLogFlowFuncEnter(); // open consumed protocols Status = BS->OpenProtocol(ControllerHandle, &PROTO_NAME(BlockIoProtocol), (VOID **) &BlockIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); // NOTE: we only want to look at the MediaId if (EFI_ERROR(Status)) { VBoxLogFlowFuncLeaveRC(Status); return Status; } Status = BS->OpenProtocol(ControllerHandle, &PROTO_NAME(DiskIoProtocol), (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR(Status)) { VBoxLogFlowFuncLeaveRC(Status); return Status; } // allocate volume structure Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA)); Status = fsw_efi_ReMount(Volume, ControllerHandle, DiskIo, BlockIo); // on errors, close the opened protocols if (EFI_ERROR(Status)) { if (Volume->vol != NULL) fsw_unmount(Volume->vol); FreePool(Volume); #if 0 if (Status == EFI_MEDIA_CHANGED) Status = fsw_efi_ReMount(Volume, ControllerHandle, DiskIo, BlockIo); else #endif BS->CloseProtocol(ControllerHandle, &PROTO_NAME(DiskIoProtocol), This->DriverBindingHandle, ControllerHandle); } VBoxLogFlowFuncLeaveRC(Status); return Status; }
static EFI_STATUS fsw_efi_ReMount(IN FSW_VOLUME_DATA *pVolume, IN EFI_HANDLE ControllerHandle, EFI_DISK_IO *pDiskIo, EFI_BLOCK_IO *pBlockIo) { EFI_STATUS Status; VBoxLogFlowFuncEnter(); pVolume->Signature = FSW_VOLUME_DATA_SIGNATURE; pVolume->Handle = ControllerHandle; pVolume->DiskIo = pDiskIo; pVolume->MediaId = pBlockIo->Media->MediaId; pVolume->LastIOStatus = EFI_SUCCESS; // mount the filesystem Status = fsw_efi_map_status(fsw_mount(pVolume, &fsw_efi_host_table, &FSW_FSTYPE_TABLE_NAME(FSTYPE), &pVolume->vol), pVolume); VBoxLogFlowFuncMarkRC(Status); if (!EFI_ERROR(Status)) { // register the SimpleFileSystem protocol pVolume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION; pVolume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume; Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle, &PROTO_NAME(SimpleFileSystemProtocol), &pVolume->FileSystem, NULL); if (EFI_ERROR(Status)) Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status); } VBoxLogFlowFuncLeaveRC(Status); return Status; }
EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) { EFI_STATUS Status; EFI_DISK_IO *DiskIo; // we check for both DiskIO and BlockIO protocols // first, open DiskIO VBoxLogFlowFuncEnter(); VBoxLogFlowFuncMarkDP(RemainingDevicePath); Status = BS->OpenProtocol(ControllerHandle, &PROTO_NAME(DiskIoProtocol), (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) { VBoxLogFlowFuncLeaveRC(Status); return Status; } // we were just checking, close it again BS->CloseProtocol(ControllerHandle, &PROTO_NAME(DiskIoProtocol), This->DriverBindingHandle, ControllerHandle); // next, check BlockIO without actually opening it Status = BS->OpenProtocol(ControllerHandle, &PROTO_NAME(BlockIoProtocol), NULL, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); VBoxLogFlowFuncLeaveRC(Status); return Status; }
/** Test to see if this driver supports ControllerHandle. Any ControllerHandle than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be supported. @param[in] This Protocol instance pointer. @param[in] ControllerHandle Handle of device to test. @param[in] RemainingDevicePath Optional parameter use to pick a specific child device to start. @retval EFI_SUCCESS This driver supports this device @retval EFI_ALREADY_STARTED This driver is already running on this device @retval other This driver does not support this device **/ EFI_STATUS EFIAPI PartitionDriverBindingSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; EFI_DISK_IO_PROTOCOL *DiskIo; EFI_DEV_PATH *Node; VBoxLogFlowFuncEnter(); // // Check RemainingDevicePath validation // if (RemainingDevicePath != NULL) { // // Check if RemainingDevicePath is the End of Device Path Node, // if yes, go on checking other conditions // VBoxLogFlowFuncMarkDP(RemainingDevicePath); if (!IsDevicePathEnd (RemainingDevicePath)) { // // If RemainingDevicePath isn't the End of Device Path Node, // check its validation // Node = (EFI_DEV_PATH *) RemainingDevicePath; if ( Node->DevPath.Type != MEDIA_DEVICE_PATH || Node->DevPath.SubType != MEDIA_HARDDRIVE_DP || DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH) || Node->DevPath.Type != MESSAGING_DEVICE_PATH || Node->DevPath.SubType != MSG_SATA_DP) { VBoxLogFlowFuncLeaveRC(EFI_UNSUPPORTED); return EFI_UNSUPPORTED; } } } // // Open the IO Abstraction(s) needed to perform the supported test // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (Status == EFI_ALREADY_STARTED) { VBoxLogFlowFuncLeaveRC(EFI_SUCCESS); return EFI_SUCCESS; } if (EFI_ERROR (Status)) { VBoxLogFlowFuncLeaveRC(Status); return Status; } // // Close the I/O Abstraction(s) used to perform the supported test // gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle ); // // Open the EFI Device Path protocol needed to perform the supported test // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **) &ParentDevicePath, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); VBoxLogFlowFuncMarkDP(ParentDevicePath); if (Status == EFI_ALREADY_STARTED) { VBoxLogFlowFuncLeaveRC(EFI_SUCCESS); return EFI_SUCCESS; } if (EFI_ERROR (Status)) { VBoxLogFlowFuncLeaveRC(Status); return Status; } // // Close protocol, don't use device path protocol in the Support() function // gBS->CloseProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle ); // // Open the IO Abstraction(s) needed to perform the supported test // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiBlockIoProtocolGuid, NULL, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL ); if (EFI_ERROR (Status)) { VBoxLogFlowFuncLeaveRC(Status); return Status; } VBoxLogFlowFuncLeaveRC(EFI_SUCCESS); return EFI_SUCCESS; }
/** Start this driver on ControllerHandle by opening a Block IO or a Block IO2 or both, and Disk IO protocol, reading Device Path, and creating a child handle with a Disk IO and device path protocol. @param[in] This Protocol instance pointer. @param[in] ControllerHandle Handle of device to bind driver to @param[in] RemainingDevicePath Optional parameter use to pick a specific child device to start. @retval EFI_SUCCESS This driver is added to ControllerHandle @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle @retval other This driver does not support this device **/ EFI_STATUS EFIAPI PartitionDriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; EFI_STATUS OpenStatus; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO2_PROTOCOL *BlockIo2; EFI_DISK_IO_PROTOCOL *DiskIo; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; PARTITION_DETECT_ROUTINE *Routine; BOOLEAN MediaPresent; EFI_TPL OldTpl; int idxRoutine = 0; VBoxLogFlowFuncEnter(); BlockIo2 = NULL; OldTpl = gBS->RaiseTPL (TPL_CALLBACK); // // Check RemainingDevicePath validation // if (RemainingDevicePath != NULL) { // // Check if RemainingDevicePath is the End of Device Path Node, // if yes, return EFI_SUCCESS // if (IsDevicePathEnd (RemainingDevicePath)) { Status = EFI_SUCCESS; goto Exit; } } // // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue, // otherwise, return error. // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { VBoxLogFlowFuncMarkRC(Status); goto Exit; } Status = gBS->OpenProtocol ( ControllerHandle, &gEfiBlockIo2ProtocolGuid, (VOID **) &BlockIo2, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); // // Get the Device Path Protocol on ControllerHandle's handle. // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **) &ParentDevicePath, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { VBoxLogFlowFuncMarkRC(Status); goto Exit; } Status = gBS->OpenProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { gBS->CloseProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle ); VBoxLogFlowFuncMarkRC(Status); goto Exit; } OpenStatus = Status; // // Try to read blocks when there's media or it is removable physical partition. // Status = EFI_UNSUPPORTED; MediaPresent = BlockIo->Media->MediaPresent; if (BlockIo->Media->MediaPresent || (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) { // // Try for GPT, then El Torito, and then legacy MBR partition types. If the // media supports a given partition type install child handles to represent // the partitions described by the media. // Routine = &mPartitionDetectRoutineTable[0]; while (*Routine != NULL) { Status = (*Routine) ( This, ControllerHandle, DiskIo, BlockIo, BlockIo2, ParentDevicePath ); VBoxLogFlowFuncMarkRC(Status); if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) { VBoxLogFlowFuncMarkVar(idxRoutine, "%d"); break; } Routine++; idxRoutine++; } } // // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED), // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the // driver. So don't try to close them. Otherwise, we will break the dependency // between the controller and the driver set up before. // // In the case that when the media changes on a device it will Reinstall the // BlockIo interaface. This will cause a call to our Stop(), and a subsequent // reentrant call to our Start() successfully. We should leave the device open // when this happen. The "media change" case includes either the status is // EFI_MEDIA_CHANGED or it is a "media" to "no media" change. // if (EFI_ERROR (Status) && !EFI_ERROR (OpenStatus) && Status != EFI_MEDIA_CHANGED && !(MediaPresent && Status == EFI_NO_MEDIA)) { gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle ); // // Close Parent BlockIO2 if has. // gBS->CloseProtocol ( ControllerHandle, &gEfiBlockIo2ProtocolGuid, This->DriverBindingHandle, ControllerHandle ); gBS->CloseProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle ); } Exit: gBS->RestoreTPL (OldTpl); VBoxLogFlowFuncLeaveRC(Status); return Status; }
STATIC EFI_STATUS PciRomLoadEfiDriversFromRomImage ( IN EFI_PHYSICAL_ADDRESS Rom, IN UINTN RomSize ) { CHAR16 *FileName; EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; PCI_DATA_STRUCTURE *Pcir; UINTN ImageIndex; UINTN RomOffset; UINT32 ImageSize; UINT16 ImageOffset; EFI_HANDLE ImageHandle; EFI_STATUS Status; EFI_STATUS retStatus; EFI_DEVICE_PATH_PROTOCOL *FilePath; BOOLEAN SkipImage; UINT32 DestinationSize; UINT32 ScratchSize; UINT8 *Scratch; VOID *ImageBuffer; VOID *DecompressedImageBuffer; UINT32 ImageLength; EFI_DECOMPRESS_PROTOCOL *Decompress; UINT32 InitializationSize; VBoxLogFlowFuncEnter(); FileName = L"PciRomInMemory"; //FileName = L"PciRom Addr=0000000000000000"; //HexToString (&FileName[12], Rom, 16); ImageIndex = 0; retStatus = EFI_NOT_FOUND; RomOffset = (UINTN) Rom; do { EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomOffset; if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { return retStatus; } // // If the pointer to the PCI Data Structure is invalid, no further images can be located. // The PCI Data Structure must be DWORD aligned. // if (EfiRomHeader->PcirOffset == 0 || (EfiRomHeader->PcirOffset & 3) != 0 || RomOffset - (UINTN)Rom + EfiRomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > RomSize) { break; } Pcir = (PCI_DATA_STRUCTURE *) (UINTN) (RomOffset + EfiRomHeader->PcirOffset); // // If a valid signature is not present in the PCI Data Structure, no further images can be located. // if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { break; } ImageSize = Pcir->ImageLength * 512; if (RomOffset - (UINTN)Rom + ImageSize > RomSize) { break; } if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) && ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) { ImageOffset = EfiRomHeader->EfiImageHeaderOffset; InitializationSize = EfiRomHeader->InitializationSize * 512; if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) { ImageBuffer = (VOID *) (UINTN) (RomOffset + ImageOffset); ImageLength = InitializationSize - ImageOffset; DecompressedImageBuffer = NULL; // // decompress here if needed // SkipImage = FALSE; if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { SkipImage = TRUE; } if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress); if (EFI_ERROR (Status)) { SkipImage = TRUE; } else { SkipImage = TRUE; Status = Decompress->GetInfo ( Decompress, ImageBuffer, ImageLength, &DestinationSize, &ScratchSize ); if (!EFI_ERROR (Status)) { DecompressedImageBuffer = NULL; DecompressedImageBuffer = AllocatePool (DestinationSize); if (DecompressedImageBuffer != NULL) { Scratch = AllocatePool (ScratchSize); if (Scratch != NULL) { Status = Decompress->Decompress ( Decompress, ImageBuffer, ImageLength, DecompressedImageBuffer, DestinationSize, Scratch, ScratchSize ); if (!EFI_ERROR (Status)) { ImageBuffer = DecompressedImageBuffer; ImageLength = DestinationSize; SkipImage = FALSE; } gBS->FreePool (Scratch); } } } } } if (!SkipImage) { // // load image and start image // FilePath = FileDevicePath (NULL, FileName); Status = gBS->LoadImage ( FALSE, gImageHandle, FilePath, ImageBuffer, ImageLength, &ImageHandle ); if (!EFI_ERROR (Status)) { Status = gBS->StartImage (ImageHandle, NULL, NULL); if (!EFI_ERROR (Status)) { retStatus = Status; } } if (FilePath != NULL) { gBS->FreePool (FilePath); } } if (DecompressedImageBuffer != NULL) { gBS->FreePool (DecompressedImageBuffer); } } } RomOffset = RomOffset + ImageSize; ImageIndex++; } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomOffset - (UINTN) Rom) < RomSize)); VBoxLogFlowFuncLeaveRC(retStatus); return retStatus; }