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 LogFlowFuncEnter(); LogFlowFuncMarkDP(RemainingDevicePath); Status = BS->OpenProtocol(ControllerHandle, &PROTO_NAME(DiskIoProtocol), (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) { LogFlowFuncLeaveRC(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); LogFlowFuncLeaveRC(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; LogFlowFuncEnter(); // // Check RemainingDevicePath validation // if (RemainingDevicePath != NULL) { // // Check if RemainingDevicePath is the End of Device Path Node, // if yes, go on checking other conditions // LogFlowFuncMarkDP(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) { LogFlowFuncLeaveRC(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) { LogFlowFuncLeaveRC(EFI_SUCCESS); return EFI_SUCCESS; } if (EFI_ERROR (Status)) { LogFlowFuncLeaveRC(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 ); LogFlowFuncMarkDP(ParentDevicePath); if (Status == EFI_ALREADY_STARTED) { LogFlowFuncLeaveRC(EFI_SUCCESS); return EFI_SUCCESS; } if (EFI_ERROR (Status)) { LogFlowFuncLeaveRC(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)) { LogFlowFuncLeaveRC(Status); return Status; } LogFlowFuncLeaveRC(EFI_SUCCESS); return EFI_SUCCESS; }
/** Install child handles if the Handle supports El Torito format. @param[in] This Calling context. @param[in] Handle Parent Handle. @param[in] DiskIo Parent DiskIo interface. @param[in] BlockIo Parent BlockIo interface. @param[in] BlockIo2 Parent BlockIo2 interface. @param[in] DevicePath Parent Device Path @retval EFI_SUCCESS Child handle(s) was added. @retval EFI_MEDIA_CHANGED Media changed Detected. @retval other no child handle was added. **/ EFI_STATUS PartitionInstallElToritoChildHandles ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Handle, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; UINT32 VolDescriptorLba; UINT32 Lba; EFI_BLOCK_IO_MEDIA *Media; CDROM_VOLUME_DESCRIPTOR *VolDescriptor; ELTORITO_CATALOG *Catalog; UINTN Check; UINTN Index; UINTN BootEntry; UINTN MaxIndex; UINT16 *CheckBuffer; CDROM_DEVICE_PATH CdDev; UINT32 SubBlockSize; UINT32 SectorCount; EFI_STATUS Found; UINT32 VolSpaceSize; LogFlowFuncMarkDP(DevicePath); Found = EFI_NOT_FOUND; Media = BlockIo->Media; VolSpaceSize = 0; // // CD_ROM has the fixed block size as 2048 bytes // if (Media->BlockSize != 2048) { return EFI_NOT_FOUND; } VolDescriptor = AllocatePool ((UINTN) Media->BlockSize); if (VolDescriptor == NULL) { return EFI_NOT_FOUND; } Catalog = (ELTORITO_CATALOG *) VolDescriptor; // // the ISO-9660 volume descriptor starts at 32k on the media // and CD_ROM has the fixed block size as 2048 bytes, so... // // // ((16*2048) / Media->BlockSize) - 1; // VolDescriptorLba = 15; // // Loop: handle one volume descriptor per time // while (TRUE) { VolDescriptorLba += 1; if (VolDescriptorLba > Media->LastBlock) { // // We are pointing past the end of the device so exit // break; } Status = DiskIo->ReadDisk ( DiskIo, Media->MediaId, MultU64x32 (VolDescriptorLba, Media->BlockSize), Media->BlockSize, VolDescriptor ); if (EFI_ERROR (Status)) { Found = Status; break; } // // Check for valid volume descriptor signature // if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END || CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0 ) { // // end of Volume descriptor list // break; } // // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte, // the 32-bit numerical values is stored in Both-byte orders // if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) { VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0]; } // // Is it an El Torito volume descriptor? // if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) { continue; } // // Read in the boot El Torito boot catalog // Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog); if (Lba > Media->LastBlock) { continue; } Status = DiskIo->ReadDisk ( DiskIo, Media->MediaId, MultU64x32 (Lba, Media->BlockSize), Media->BlockSize, Catalog ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status)); continue; } // // We don't care too much about the Catalog header's contents, but we do want // to make sure it looks like a Catalog header // if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) { DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n")); continue; } Check = 0; CheckBuffer = (UINT16 *) Catalog; for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) { Check += CheckBuffer[Index]; } if ((Check & 0xFFFF) != 0) { DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n")); continue; } MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG); for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) { // // Next entry // Catalog += 1; // // Check this entry // if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) { continue; } SubBlockSize = 512; SectorCount = Catalog->Boot.SectorCount; switch (Catalog->Boot.MediaType) { case ELTORITO_NO_EMULATION: SubBlockSize = Media->BlockSize; break; case ELTORITO_HARD_DISK: break; case ELTORITO_12_DISKETTE: SectorCount = 0x50 * 0x02 * 0x0F; break; case ELTORITO_14_DISKETTE: SectorCount = 0x50 * 0x02 * 0x12; break; case ELTORITO_28_DISKETTE: SectorCount = 0x50 * 0x02 * 0x24; break; default: DEBUG ((EFI_D_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType)); SectorCount = 0; SubBlockSize = Media->BlockSize; break; } // // Create child device handle // CdDev.Header.Type = MEDIA_DEVICE_PATH; CdDev.Header.SubType = MEDIA_CDROM_DP; SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev)); if (Index == 1) { // // This is the initial/default entry // BootEntry = 0; } CdDev.BootEntry = (UINT32) BootEntry; BootEntry++; CdDev.PartitionStart = Catalog->Boot.Lba; if (SectorCount < 2) { // // When the SectorCount < 2, set the Partition as the whole CD. // if (VolSpaceSize > (Media->LastBlock + 1)) { CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba + 1); } else { CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba); } } else { CdDev.PartitionSize = DivU64x32 ( MultU64x32 ( SectorCount, SubBlockSize ) + Media->BlockSize - 1, Media->BlockSize ); } Status = PartitionInstallChildHandle ( This, Handle, DiskIo, BlockIo, BlockIo2, DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &CdDev, Catalog->Boot.Lba, Catalog->Boot.Lba + CdDev.PartitionSize - 1, SubBlockSize, FALSE ); if (!EFI_ERROR (Status)) { Found = EFI_SUCCESS; } } } FreePool (VolDescriptor); return Found; }
/** Install child handles if the Handle supports GPT partition structure. @param[in] This Calling context. @param[in] Handle Parent Handle. @param[in] DiskIo Parent DiskIo interface. @param[in] BlockIo Parent BlockIo interface. @param[in] BlockIo2 Parent BlockIo2 interface. @param[in] DevicePath Parent Device Path. @retval EFI_SUCCESS Valid GPT disk. @retval EFI_MEDIA_CHANGED Media changed Detected. @retval other Not a valid GPT disk. **/ EFI_STATUS PartitionInstallGptChildHandles ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Handle, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; UINT32 BlockSize; EFI_LBA LastBlock; MASTER_BOOT_RECORD *ProtectiveMbr; EFI_PARTITION_TABLE_HEADER *PrimaryHeader; EFI_PARTITION_TABLE_HEADER *BackupHeader; EFI_PARTITION_ENTRY *PartEntry; EFI_PARTITION_ENTRY *Entry; EFI_PARTITION_ENTRY_STATUS *PEntryStatus; UINTN Index; EFI_STATUS GptValidStatus; HARDDRIVE_DEVICE_PATH HdDev; UINT32 MediaId; LogFlowFuncMarkDP(DevicePath); ProtectiveMbr = NULL; PrimaryHeader = NULL; BackupHeader = NULL; PartEntry = NULL; PEntryStatus = NULL; BlockSize = BlockIo->Media->BlockSize; LastBlock = BlockIo->Media->LastBlock; MediaId = BlockIo->Media->MediaId; DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize)); DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock)); GptValidStatus = EFI_NOT_FOUND; // // Allocate a buffer for the Protective MBR // ProtectiveMbr = AllocatePool (BlockSize); if (ProtectiveMbr == NULL) { return EFI_NOT_FOUND; } // // Read the Protective MBR from LBA #0 // Status = DiskIo->ReadDisk ( DiskIo, MediaId, 0, BlockSize, ProtectiveMbr ); if (EFI_ERROR (Status)) { GptValidStatus = Status; goto Done; } // // Verify that the Protective MBR is valid // for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) { if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 && ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION && UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1 ) { break; } } if (Index == MAX_MBR_PARTITIONS) { goto Done; } // // Allocate the GPT structures // PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER)); if (PrimaryHeader == NULL) { goto Done; } BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER)); if (BackupHeader == NULL) { goto Done; } // // Check primary and backup partition tables // if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) { DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n")); if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) { DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n")); goto Done; } else { DEBUG ((EFI_D_INFO, " Valid backup partition table\n")); DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n")); if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) { DEBUG ((EFI_D_INFO, " Restore primary partition table error\n")); } if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) { DEBUG ((EFI_D_INFO, " Restore backup partition table success\n")); } } } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) { DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n")); DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n")); if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) { DEBUG ((EFI_D_INFO, " Restore backup partition table error\n")); } if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) { DEBUG ((EFI_D_INFO, " Restore backup partition table success\n")); } } DEBUG ((EFI_D_INFO, " Valid primary and Valid backup partition table\n")); // // Read the EFI Partition Entries // PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); if (PartEntry == NULL) { DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); goto Done; } Status = DiskIo->ReadDisk ( DiskIo, MediaId, MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize), PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry), PartEntry ); if (EFI_ERROR (Status)) { GptValidStatus = Status; DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n")); goto Done; } DEBUG ((EFI_D_INFO, " Partition entries read block success\n")); DEBUG ((EFI_D_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries)); PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)); if (PEntryStatus == NULL) { DEBUG ((EFI_D_ERROR, "Allocate pool error\n")); goto Done; } // // Check the integrity of partition entries // PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus); // // If we got this far the GPT layout of the disk is valid and we should return true // GptValidStatus = EFI_SUCCESS; // // Create child device handles // for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) { Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry); if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) || PEntryStatus[Index].OutOfRange || PEntryStatus[Index].Overlap || PEntryStatus[Index].OsSpecific ) { // // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific // partition Entries // continue; } ZeroMem (&HdDev, sizeof (HdDev)); HdDev.Header.Type = MEDIA_DEVICE_PATH; HdDev.Header.SubType = MEDIA_HARDDRIVE_DP; SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev)); HdDev.PartitionNumber = (UINT32) Index + 1; HdDev.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER; HdDev.SignatureType = SIGNATURE_TYPE_GUID; HdDev.PartitionStart = Entry->StartingLBA; HdDev.PartitionSize = Entry->EndingLBA - Entry->StartingLBA + 1; CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID)); DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index)); DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart)); DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA)); DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize)); DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize))); DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize))); Status = PartitionInstallChildHandle ( This, Handle, DiskIo, BlockIo, BlockIo2, DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &HdDev, Entry->StartingLBA, Entry->EndingLBA, BlockSize, CompareGuid(&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid) ); } DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n")); Done: if (ProtectiveMbr != NULL) { FreePool (ProtectiveMbr); } if (PrimaryHeader != NULL) { FreePool (PrimaryHeader); } if (BackupHeader != NULL) { FreePool (BackupHeader); } if (PartEntry != NULL) { FreePool (PartEntry); } if (PEntryStatus != NULL) { FreePool (PEntryStatus); } return GptValidStatus; }