Reading sectors under UEFI: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
m (→‎Loading Raw Sectors: fixed example)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(One intermediate revision by the same user not shown)
Line 4: Line 4:


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.
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.
<source lang="c">
<syntaxhighlight lang="c">
EFI_GUID bioGuid = BLOCK_IO_PROTOCOL;
EFI_GUID bioGuid = BLOCK_IO_PROTOCOL;
EFI_BLOCK_IO *bio;
EFI_BLOCK_IO *bio;
Line 24: Line 24:
/* second round, locate the protocol with big enough buffer */
/* second round, locate the protocol with big enough buffer */
status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &bioGuid, NULL, &handle_size, handles);
status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &bioGuid, NULL, &handle_size, handles);
</syntaxhighlight>
</source>
Now "handles" is an array that has a handle for each and every block device in the system.
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.
We should iterate on that array, and use ith handle to get the block IO interface for a device.
<source lang="c">
<syntaxhighlight lang="c">
for (i = 0; i < handle_size / sizeof(EFI_HANDLE); i++) {
for (i = 0; i < handle_size / sizeof(EFI_HANDLE); i++) {
status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], &bioGuid, (void **) &bio);
status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], &bioGuid, (void **) &bio);
Line 36: Line 36:
/* TODO: do something with that device. */
/* TODO: do something with that device. */
}
}
</syntaxhighlight>
</source>


== Loading Raw Sectors ==
== 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:
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:
<source lang="c">
<syntaxhighlight lang="c">
UINT8 mbr[512];
UINT8 mbr[512];


Line 48: Line 48:
/* AUCH, error reading sector */
/* AUCH, error reading sector */
}
}
</syntaxhighlight>
</source>


== See also ==
== See also ==

Latest revision as of 05:43, 9 June 2024

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