morpheus_bootloader/uefi/
block_io_adapter.rsuse super::block_io::BlockIoProtocol;
use core::fmt;
use gpt_disk_io::BlockIo;
use gpt_disk_types::{BlockSize, Lba};
#[derive(Debug, Clone, Copy)]
pub struct UefiBlockIoError(pub usize);
impl fmt::Display for UefiBlockIoError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UEFI BlockIo error: {}", self.0)
}
}
pub struct UefiBlockIo {
protocol: *mut BlockIoProtocol,
block_size: BlockSize,
num_blocks: u64,
}
impl UefiBlockIo {
pub unsafe fn new(protocol: *mut BlockIoProtocol) -> Self {
let media = &*(*protocol).media;
let block_size = BlockSize::new(media.block_size).unwrap_or(BlockSize::BS_512);
let num_blocks = media.last_block + 1;
Self {
protocol,
block_size,
num_blocks,
}
}
pub fn protocol(&self) -> *mut BlockIoProtocol {
self.protocol
}
pub fn block_size_bytes(&self) -> u32 {
self.block_size.to_u32()
}
pub fn total_blocks(&self) -> u64 {
self.num_blocks
}
}
impl BlockIo for UefiBlockIo {
type Error = UefiBlockIoError;
fn block_size(&self) -> BlockSize {
self.block_size
}
fn num_blocks(&mut self) -> Result<u64, Self::Error> {
Ok(self.num_blocks)
}
fn read_blocks(&mut self, start_lba: Lba, buffer: &mut [u8]) -> Result<(), Self::Error> {
let block_size = self.block_size.to_u64();
let num_blocks = buffer.len() as u64 / block_size;
unsafe {
let protocol = &mut *self.protocol;
protocol
.read_sectors(start_lba.0, num_blocks, buffer)
.map_err(UefiBlockIoError)
}
}
fn write_blocks(&mut self, start_lba: Lba, buffer: &[u8]) -> Result<(), Self::Error> {
let block_size = self.block_size.to_u64();
let num_blocks = buffer.len() as u64 / block_size;
unsafe {
let protocol = &mut *self.protocol;
protocol
.write_sectors(start_lba.0, num_blocks, buffer)
.map_err(UefiBlockIoError)
}
}
fn flush(&mut self) -> Result<(), Self::Error> {
unsafe {
let protocol = &mut *self.protocol;
let status = ((*protocol).flush_blocks)(protocol);
if status == 0 {
Ok(())
} else {
Err(UefiBlockIoError(status))
}
}
}
}