Reading sectors under UEFI: Difference between revisions
[unchecked revision] | [unchecked revision] |
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. |
||
< |
<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. |
||
< |
<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: |
||
< |
<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 */
}