pub mod chars;
mod guid;
#[macro_use]
mod opaque;
#[cfg(feature = "alloc")]
mod owned_strs;
mod strs;
mod unaligned_slice;
pub use chars::{Char8, Char16};
pub use guid::{Guid, Identify};
#[cfg(feature = "alloc")]
pub use owned_strs::{CString16, FromStrError};
pub use strs::{
CStr8, CStr16, EqStrUntilNul, FromSliceWithNulError, FromStrWithBufError, PoolString,
UnalignedCStr16Error,
};
#[doc(hidden)]
pub use strs::{str_num_latin1_chars, str_to_latin1};
pub use uefi_raw::{PhysicalAddress, VirtualAddress};
pub use unaligned_slice::UnalignedSlice;
use crate::Result;
use crate::boot::{self, OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol};
use crate::proto::device_path::DevicePath;
use crate::proto::driver::ComponentName2;
use core::ffi::c_void;
use core::ptr::{self, NonNull};
#[cfg(doc)]
use uefi_raw::Status;
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
#[repr(transparent)]
pub struct Handle(NonNull<c_void>);
impl Handle {
#[must_use]
pub const unsafe fn new(ptr: NonNull<c_void>) -> Self {
Self(ptr)
}
pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
NonNull::new(ptr).map(Self)
}
#[must_use]
pub const fn as_ptr(&self) -> *mut c_void {
self.0.as_ptr()
}
pub(crate) fn opt_to_ptr(handle: Option<Self>) -> *mut c_void {
handle.map(|h| h.0.as_ptr()).unwrap_or(ptr::null_mut())
}
pub fn component_name(&self) -> Result<ScopedProtocol<ComponentName2>> {
unsafe {
boot::open_protocol::<ComponentName2>(
OpenProtocolParams {
handle: *self,
agent: boot::image_handle(),
controller: None,
},
OpenProtocolAttributes::GetProtocol,
)
}
}
pub fn device_path(&self) -> Result<ScopedProtocol<DevicePath>> {
unsafe {
boot::open_protocol::<DevicePath>(
OpenProtocolParams {
handle: *self,
agent: boot::image_handle(),
controller: None,
},
OpenProtocolAttributes::GetProtocol,
)
}
}
}
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
#[repr(transparent)]
pub struct Event(NonNull<c_void>);
impl Event {
#[must_use]
pub const unsafe fn unsafe_clone(&self) -> Self {
Self(self.0)
}
pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
NonNull::new(ptr).map(Self)
}
#[must_use]
pub const fn as_ptr(&self) -> *mut c_void {
self.0.as_ptr()
}
}
pub trait Align {
fn alignment() -> usize;
#[must_use]
fn offset_up_to_alignment(val: usize) -> usize {
assert_ne!(Self::alignment(), 0);
let r = val % Self::alignment();
if r == 0 { 0 } else { Self::alignment() - r }
}
#[must_use]
fn round_up_to_alignment(val: usize) -> usize {
val + Self::offset_up_to_alignment(val)
}
fn align_buf(buf: &mut [u8]) -> Option<&mut [u8]> {
let offset = buf.as_ptr().align_offset(Self::alignment());
buf.get_mut(offset..)
}
fn assert_aligned(storage: &mut [u8]) {
if !storage.is_empty() {
assert_eq!(
storage.as_ptr().align_offset(Self::alignment()),
0,
"The provided storage is not correctly aligned for this type"
)
}
}
}
impl Align for [u8] {
fn alignment() -> usize {
1
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_alignment() {
struct X {}
impl Align for X {
fn alignment() -> usize {
4
}
}
assert_eq!(X::offset_up_to_alignment(0), 0);
assert_eq!(X::offset_up_to_alignment(1), 3);
assert_eq!(X::offset_up_to_alignment(2), 2);
assert_eq!(X::offset_up_to_alignment(3), 1);
assert_eq!(X::offset_up_to_alignment(4), 0);
assert_eq!(X::offset_up_to_alignment(5), 3);
assert_eq!(X::offset_up_to_alignment(6), 2);
assert_eq!(X::offset_up_to_alignment(7), 1);
assert_eq!(X::offset_up_to_alignment(8), 0);
assert_eq!(X::round_up_to_alignment(0), 0);
assert_eq!(X::round_up_to_alignment(1), 4);
assert_eq!(X::round_up_to_alignment(2), 4);
assert_eq!(X::round_up_to_alignment(3), 4);
assert_eq!(X::round_up_to_alignment(4), 4);
assert_eq!(X::round_up_to_alignment(5), 8);
assert_eq!(X::round_up_to_alignment(6), 8);
assert_eq!(X::round_up_to_alignment(7), 8);
assert_eq!(X::round_up_to_alignment(8), 8);
let mut buffer = [0u8; 16];
let mut buffer = &mut buffer[..];
if (buffer.as_ptr() as usize) % X::alignment() == 0 {
buffer = &mut buffer[1..];
}
let buffer = X::align_buf(buffer).unwrap();
X::assert_aligned(buffer);
}
}