Reading sectors under UEFI

From OSDev Wiki
Jump to navigation Jump to search

Note that you don't necessarily need to access raw block devices, because UEFI provides files abstraction with EFI_SIMPLE_FILE_SYSTEM_PROTOCOL (typically limited to FAT-only partitions).

Iterating on Disks

If you already have a handle for a block device, then your job is easy. However more often you don't, which means first you must query the list of block devices in the system. Because you don't know in advance how many devices there are, you must locate the BLOCK_IO_PROTOCOL twice.

EFI_GUID bioGuid = BLOCK_IO_PROTOCOL;
EFI_BLOCK_IO *bio;
EFI_HANDLE *handles = NULL;
UINTN handle_size = 0;

/* first, locate the protocol with empty buffer */
status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &bioGuid, NULL, &handle_size, handles);
if (status != EFI_BUFFER_TOO_SMALL || handle_size == 0) {
    /* AUCH, error we don't have BLOCK_IO */
}

/* get a buffer for the handles now that we know the buffer size */
status = uefi_call_wrapper(BS->AllocatePages, 4, 0, 2, (handle_size + PAGESIZE-1) / PAGESIZE, (EFI_PHYSICAL_ADDRESS*)&handles);
if (EFI_ERROR(status) || handles == NULL) {
    /* AUCH, error memory allocation failed */
}

/* second round, locate the protocol with big enough buffer */
status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &bioGuid, NULL, &handle_size, handles);

Now "handles" is an array that has a handle for each and every block device in the system.

We should iterate on that array, and use ith handle to get the block IO interface for a device.

for (i = 0; i < handle_size / sizeof(EFI_HANDLE); i++) {
    status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], &bioGuid, (void **) &bio);
    /* if unsuccessful, skip and go over to the next device */
    if (EFI_ERROR(status) || bio == NULL || bio->Media->BlockSize==0)
        continue;
    /* TODO: do something with that device. */
}

Loading Raw Sectors

The "bio" interface inside the iteration above refers to one particular device. You can use that interface to load sectors from that device quite easily:

UINT8 mbr[512];

status = uefi_call_wrapper(bio->ReadBlocks, 5, bio, bio->Media->MediaId, 1, 512, &mbr);
if (EFI_ERROR(status)) {
    /* AUCH, error reading sector */
}

See also

Articles

External Links