Open Mathis-Z opened 3 weeks ago
I just found out that reversing the list of handles allows me to open all of them exclusively. This code:
fn main() -> Status {
uefi::helpers::init().unwrap();
let _ = system::with_stdout(|stdout| stdout.clear());
let mut handles = boot::find_handles::<DiskIo>().unwrap();
handles.reverse();
for disk_handle in handles {
unsafe {
match boot::open_protocol::<BlockIO>(
OpenProtocolParams {
handle: disk_handle,
agent: boot::image_handle(),
controller: None,
},
boot::OpenProtocolAttributes::Exclusive,
) {
Ok(scoped_block_prot) => {
let block_io = scoped_block_prot.get().unwrap();
println!(
"{disk_handle:?} is logical partition: {}",
block_io.media().is_logical_partition()
)
}
Err(error) => {
println!("Could not open BlockIO protocol for {disk_handle:?} : {error}")
}
}
}
}
boot::stall(100_000_000);
Status::SUCCESS
}
Output:
Handle(0xxxx) is logical partition: true
Handle(0xxxx) is logical partition: true
Handle(0xxxx) is logical partition: true
Handle(0xxxx) is logical partition: false
Handle(0xxxx) is logical partition: true
Handle(0xxxx) is logical partition: false
Handle(0xxxx) is logical partition: false
This indicates to me that exclusively opening a protocol on the "root" handle of the disk (the one with logical partition: false) also locks the "children" handles but dropping the ScopedProtocol for the "root" handle does not release the locks on the children. This is why trying to exclusively open a protocol on a child handle fails afterwards. If we reverse the list of handles we open the children handles before opening the root handle and so we don't run into the problem. So this is probably a bug in uefi-rs.
The locking provided by OpenProtocolAttributes::Exclusive
is not implemented by uefi-rs, but rather is part of the firmware. See EXCLUSIVE
in https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-openprotocol
So while it is possible there's a bug in uefi-rs, I think more likely you are seeing firmware behavior.
For disk operations, I would actually recommend not opening in exclusive mode. I've observed on real hardware that this can be quite slow, taking almost one second for the firmware to finish doing whatever cleanup is necessary to provide exclusive access.
I am not sure if that is to be expected, an issue with uefi-rs or an issue with my setup but here is my problem:
I am writing a simple bootloader with uefi-rs (with the alloc feature) and I am testing it in QEMU with a .vdi (VirtualBox hard drive) mounted. I want to read ext4 partitions using an external crate and for this I need to access the partitions raw. I can list the handles supporting the BlockIO protocol but I can only open the protocol for handles that represent entire disks (rather than logical partitions). This is my minimal code example:
This produces output like:
I know the handles I cannot open are for logical partitions because it works when I change
boot::OpenProtocolAttributes::Exclusive
toboot::OpenProtocolAttributes::GetProtocol
. Then I get this output:Another observation I made is that after running my code above I cannot call
find_handles::<DiskIo>()
again because it will just block forever as if the handles are still occupied or something. This does not happen when I open the protocols usingboot::OpenProtocolAttributes::GetProtocol
.Finally, I can open the BlockIO protocol for my logical partitions using the following code:
Producing output like:
Combining this code with the code from above I can confirm that these are the very same handles that could not be opened previously.
Again, I am not sure if this is to be expected or potentially an issue but I hope I could give you enough info to tell.