| Address | Name | Description | |
|---|---|---|---|
| InternalAssert | |||
| _ModuleEntryPoint | |||
| DiskIoDxeInstallProtocols | |||
| DiskIoDriverBindingSupported | |||
| DiskIoDriverBindingStart | |||
| DiskIoDriverBindingStop | |||
| DiskIoReadDisk | |||
| DiskIoWriteDisk | |||
| DiskIo2ReadDiskEx | |||
| DiskIo2WriteDiskEx | |||
| DiskIo2FlushDiskEx | |||
| DiskIo2Cancel | |||
| DiskIoRequest | |||
| DiskIoCreateSubtasks | |||
| DiskIoSubtaskCallback | |||
| DiskIoCheckAllSubtasksCompleted | |||
| DiskIoComponentNameGetDriverName | |||
| DiskIoComponentNameGetControllerName | |||
| ProcessLibraryConstructorList | |||
| Module | globals (set by _ModuleEntryPoint at 0x390) | ||
| EFI_HANDLE | gImageHandle = NULL; | ||
| Debug | print error level protocol (lazily resolved) | ||
| qword_38E0 | in the binary | ||
| DEBUG_PRINT_ERROR_LEVEL_PROTOCOL | *gDebugPrintErrorLevelProtocol = NULL; | ||
| Driver | Binding Protocol instance | ||
| Installed | in DiskIoDxeInstallProtocols (sub_448) | ||
| EFI_DRIVER_BINDING_PROTOCOL | gDiskIoDriverBinding = { | ||
| Version | NULL, // ImageHandle - set during binding | ||
| DriverBindingHandle | - set by InstallMultipleProtocolInterfaces | ||
| Component | Name tables (at .rdata +0x3868 and +0x3880) | ||
| Stored | as: { GetDriverName, GetControllerName, DriverNameString } | ||
| where | GetDriverName = DiskIoComponentNameGetDriverName (0x1CEC) | ||
| GetControllerName | = DiskIoComponentNameGetControllerName (0x1E48) | ||
| DriverNameString | = "Generic Disk I/O Driver" (0x2EA0) for COMPONENT_NAME | ||
| DriverNameString | = "Disk I/O Driver" (0x2E94 "eng;en" table) for COMPONENT_NAME2 | ||
| EFI_COMPONENT_NAME_PROTOCOL | gDiskIoComponentName = { | ||
| Supported | Languages | ||
| Forward | declarations for library-internal helpers | ||
| Module | Entry Point | ||
| Process | library constructors (sub_26D0) | ||
| This | calls ProcessLibraryConstructorList to initialize HOB list, etc. | ||
| ProcessLibraryConstructorList | (); | ||
| Install | the driver binding and component name protocols (sub_448) | ||
| return | DiskIoDxeInstallProtocols (ImageHandle); | ||
| Protocol | Installation | ||
| Driver | Binding Protocol: Supported, Start, Stop | ||
| Allocate | a pool tag (8 bytes) for tracking | ||
| HandlePtr | = gBootServices->AllocatePool (EfiBootServicesData, sizeof (EFI_HANDLE)); | ||
| Open | Block I/O protocol BY_DRIVER | ||
| Status | = gBootServices->OpenProtocol ( | ||
| Optionally | open Block I/O 2 protocol BY_DRIVER | ||
| Allocate | and initialize the private data structure | ||
| Instance | = InternalAllocateCopyPool (BlockIo2, sizeof (DISK_IO_PRIVATE_DATA)); | ||
| Validate | BlockIo vs BlockIo2 alignment consistency | ||
| if | (BlockIo2 != NULL) { | ||
| Initialize | DiskIo protocol interface (at Instance + 0x08) | ||
| Initialize | DiskIo2 protocol interface (at Instance + 0x28) | ||
| Initialize | the task list | ||
| InitializeListHead | (&Instance->TaskList); | ||
| Initialize | the EFI lock (LockType=16, Tpl=4, EfiLockReleased=1) | ||
| EfiInitializeLock | (&Instance->TaskListLock, TPL_NOTIFY); | ||
| Allocate | an aligned media buffer for bouncing unaligned transfers | ||
| BlockSize | = BlockIo->Media->BlockSize; | ||
| Install | the Disk I/O protocols on the controller handle | ||
| On | failure, free the aligned buffer and instance | ||
| InternalFreeAlignedBuffer | ( | ||
| Open | the installed DiskIo protocol to get our private instance | ||
| CR | macro: DiskIo is at Instance + 0x08 (offset 8) | ||
| Instance | = CR (DiskIo, DISK_IO_PRIVATE_DATA, DiskIo, DISK_IO_PRIVATE_DATA_SIGNATURE); | ||
| Drain | all outstanding non-blocking I/O | ||
| do | { | ||
| Uninstall | protocols | ||
| if | (Instance->BlockIo2 != NULL) { | ||
| Free | the aligned media buffer | ||
| if | (Instance->MediaBuffer != NULL) { | ||
| Close | the underlying Block I/O protocols | ||
| Free | the instance | ||
| InternalFreePool | (Instance); | ||
| EFI_DISK_IO_PROTOCOL | Implementation | ||
| Synchronous | flush | ||
| return | Instance->BlockIo2->FlushBlocksEx (Instance->BlockIo2, NULL); | ||
| FlushTask | = InternalAllocatePool (EfiBootServicesData, sizeof (DISK_IO_FLUSH_TASK)); | ||
| Create | a notification event | ||
| Status | = gBootServices->CreateEvent ( | ||
| Submit | to BlockIo2 with our event | ||
| Status | = Instance->BlockIo2->FlushBlocksEx (Instance->BlockIo2, FlushTask->Event); | ||
| EfiAcquireLock | (&Instance->TaskListLock); | ||
| Entry | = GetFirstNode (&Instance->TaskList); | ||
| Cancel | this task: abort the user's token | ||
| if | (Task->Token != NULL) { | ||
| Free | the task (implicitly removes from list) | ||
| RemoveEntryList | (Entry); | ||
| Core | I/O Dispatcher: DiskIoRequest | ||
| IsBlocking | = FALSE; | ||
| Wait | for previous non-blocking requests to drain | ||
| while | (!DiskIoCheckAllSubtasksCompleted (Instance)) { | ||
| Spin | until all subtasks complete | ||
| Allocate | a DISK_IO_TASK (0x50 bytes) | ||
| Task | = InternalAllocatePool (EfiBootServicesData, sizeof (DISK_IO_TASK)); | ||
| Insert | the task into the instance's task list | ||
| InsertTailList | (&Instance->TaskList, &Task->Link); | ||
| Initialize | the subtask list for this task | ||
| InitializeListHead | (&Task->SubtaskList); | ||
| Create | the subtasks | ||
| Blocking | path (Token == NULL or Token->Event == NULL) | ||
| IsBlocking | = TRUE; | ||
| Use | local stack variable for the subtask list head | ||
| InitializeListHead | (&SubtaskList); | ||
| Blocking | Instance->MediaBuffer | ||
| If | no subtasks were created, clean up and return error | ||
| if | (IsListEmpty (SubtaskListPtr)) { | ||
| Execute | all subtasks | ||
| Status | = EFI_SUCCESS; | ||
| Validate | block alignment | ||
| if | ((Subtask->Length % BlockSize != 0) && (Subtask->Length >= BlockSize)) { | ||
| Choose | between BlockIo2 (non-blocking) and BlockIo (blocking) | ||
| if | (Subtask->IsWrite) { | ||
| Write | operation | ||
| if | (Subtask->WorkingBuffer != NULL) { | ||
| Copy | from user buffer to bounce buffer first | ||
| if | (Subtask->UseBlockIo2) { | ||
| Status | = BlockIo2->ReadBlocksEx ( | ||
| Blocking | read via BlockIo | ||
| Status | = BlockIo->ReadBlocks ( | ||
| For | blocking reads with bounce buffer: copy to user buffer | ||
| if | (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) { | ||
| Clean | up completed subtask | ||
| DiskIoFreeSubtask | (Instance, (DISK_IO_TASK *)Subtask); | ||
| If | blocking and error: stop processing further subtasks | ||
| if | (EFI_ERROR (Status) && !Subtask->UseBlockIo2) { | ||
| If | any blocking subtask failed, drain remaining subtask list | ||
| if | (EFI_ERROR (Status)) { | ||
| For | non-blocking tasks: cleanup and possibly signal completion | ||
| if | (!IsBlocking && Task != NULL) { | ||
| If | the non-blocking request was effectively blocking (all subtasks | ||
| completed | synchronously), signal the user's event directly | ||
| if | (!EFI_ERROR (Status) && (Task->Token != NULL)) { | ||
| Remove | the task from the instance's task list and free it | ||
| RemoveEntryList | (&Task->Link); | ||
| Subtask | Management | ||
| Calculate | starting LBA and offset within first block | ||
| DivU64x32Remainder | (Offset, (UINT32)BlockSize, &OffsetInBlock); | ||
| Subtask | = DiskIoCreateSubtask ( | ||
| UseBlockIo2 | for non-blocking | ||
| Head | fragment: start is not block-aligned | ||
| FragmentSize | = BlockSize - OffsetInBlock; | ||
| For | blocking: use MediaBuffer as the bounce buffer | ||
| For | non-blocking: reuse the subtask's own buffer | ||
| if | (!IsBlocking) { | ||
| Process | aligned remaining data | ||
| if | (Remaining > 0) { | ||
| If | the remaining data is perfectly block-aligned | ||
| do | it as one large aligned transfer (no bounce buffer needed) | ||
| if | (Remaining % BlockSize == 0) { | ||
| No | bounce buffer for aligned transfer | ||
| Process | aligned full blocks one at a time | ||
| while | (Remaining >= BlockSize) { | ||
| No | bounce buffer needed | ||
| Tail | unaligned fragment | ||
| Bounce | buffer for tail fragment | ||
| Allocate | the subtask (0x68 = 104 bytes) | ||
| Subtask | = InternalAllocatePool (EfiBootServicesData, sizeof (DISK_IO_SUBTASK)); | ||
| Zero | the structure | ||
| ZeroMem | (Subtask, sizeof (DISK_IO_SUBTASK)); | ||
| For | reads with bounce buffer: copy data to user buffer | ||
| if | (!Subtask->IsWrite && (Subtask->WorkingBuffer != NULL)) { | ||
| Close | the event | ||
| or | by the cleanup code in DiskIoRequest | ||
| Remove | from linked list | ||
| RemoveEntryList | (&Subtask->Link); | ||
| Close | event if non-blocking subtask | ||
| if | (Subtask->Token != NULL) { | ||
| This | is actually the subtask's Event field at offset 0x58 | ||
| Free | the allocation | ||
| InternalFreePool | (Subtask); | ||
| Task | completed, signal its token | ||
| Remove | and free the completed task | ||
| RemoveEntryList | (TaskEntry); | ||
| Component | Name Protocol | ||
| The | component name table at .rdata +0x3868 / +0x3880 contains: | ||
| For | COMPONENT_NAME: DriverNameString = "Generic Disk I/O Driver" (0x2EA0) | ||
| For | COMPONENT_NAME2: DriverNameString = "eng;en" string table -> "Disk I/O Driver" | ||
| The | actual implementation iterates over the language table checking | ||
| each | entry against the requested Language parameter. | ||
| if | **((Language == NULL) | (DriverName == NULL)) {** | |
| each | entry with string comparison. For English, returns the known string. | ||
| Library | Constructors | ||
| to | find the DebugPrintErrorLevelLib protocol and cache it. | ||
| At | qword_38E0 and qword_38E8, the debug print protocol pointer | ||
| is | lazily resolved on first use via DebugPrintErrorLevelLibGetDebug |
Generated by HR650X BIOS Decompilation Project