use num_traits;
use r_efi::efi;
use crate::error::EfiError;
pub mod guid;
#[cfg(any(test, feature = "alloc"))]
pub mod memory_map;
pub const UEFI_PAGE_SIZE: usize = 0x1000;
pub const UEFI_PAGE_MASK: usize = UEFI_PAGE_SIZE - 1;
pub const UEFI_PAGE_SHIFT: usize = 12;
pub const SIZE_1KB: usize = 0x400;
pub const SIZE_2KB: usize = 0x800;
pub const SIZE_4KB: usize = 0x1000;
pub const SIZE_8KB: usize = 0x2000;
pub const SIZE_16KB: usize = 0x4000;
pub const SIZE_32KB: usize = 0x8000;
pub const SIZE_64KB: usize = 0x10000;
pub const SIZE_128KB: usize = 0x20000;
pub const SIZE_256KB: usize = 0x40000;
pub const SIZE_512KB: usize = 0x80000;
pub const SIZE_1MB: usize = 0x100000;
pub const SIZE_2MB: usize = 0x200000;
pub const SIZE_4MB: usize = 0x400000;
pub const SIZE_8MB: usize = 0x800000;
pub const SIZE_16MB: usize = 0x1000000;
pub const SIZE_32MB: usize = 0x2000000;
pub const SIZE_64MB: usize = 0x4000000;
pub const SIZE_128MB: usize = 0x8000000;
pub const SIZE_256MB: usize = 0x10000000;
pub const SIZE_512MB: usize = 0x20000000;
pub const SIZE_1GB: usize = 0x40000000;
pub const SIZE_2GB: usize = 0x80000000;
pub const SIZE_4GB: usize = 0x100000000;
pub const SIZE_8GB: usize = 0x200000000;
pub const SIZE_16GB: usize = 0x400000000;
pub const SIZE_32GB: usize = 0x800000000;
pub const SIZE_64GB: usize = 0x1000000000;
pub const SIZE_128GB: usize = 0x2000000000;
pub const SIZE_256GB: usize = 0x4000000000;
pub const SIZE_512GB: usize = 0x8000000000;
pub const SIZE_1TB: usize = 0x10000000000;
pub const SIZE_2TB: usize = 0x20000000000;
pub const SIZE_4TB: usize = 0x40000000000;
pub const SIZE_8TB: usize = 0x80000000000;
pub const SIZE_16TB: usize = 0x100000000000;
pub const SIZE_32TB: usize = 0x200000000000;
pub const SIZE_64TB: usize = 0x400000000000;
pub const SIZE_128TB: usize = 0x800000000000;
pub const SIZE_256TB: usize = 0x1000000000000;
pub const DEFAULT_CACHE_ATTR: u64 = efi::MEMORY_WB;
#[macro_export]
macro_rules! bit {
($n:expr) => {
1 << $n
};
}
#[inline]
pub fn is_power_of_two<T>(x: T) -> bool
where
T: num_traits::PrimInt,
{
x > T::zero() && (x & (x - T::one())) == T::zero()
}
#[inline]
pub fn align_down<T>(addr: T, align: T) -> Result<T, EfiError>
where
T: num_traits::PrimInt,
{
if !is_power_of_two(align) {
return Err(EfiError::InvalidParameter);
}
Ok(addr & !(align - T::one()))
}
#[inline]
pub fn align_up<T>(addr: T, align: T) -> Result<T, EfiError>
where
T: num_traits::PrimInt,
{
if !is_power_of_two(align) {
return Err(EfiError::InvalidParameter);
}
let align_mask = align - T::one();
if addr & align_mask == T::zero() {
Ok(addr) } else {
(addr | align_mask).checked_add(&T::one()).ok_or(EfiError::InvalidParameter)
}
}
#[inline]
pub fn align_range<T>(base: T, length: T, align: T) -> Result<(T, T), EfiError>
where
T: num_traits::PrimInt,
{
if !is_power_of_two(align) {
return Err(EfiError::InvalidParameter);
}
let aligned_end = align_up(base + length, align)?;
let aligned_base = align_down(base, align)?;
let aligned_length = aligned_end - aligned_base;
Ok((aligned_base, aligned_length))
}
#[allow(unused_macros)]
#[macro_export]
macro_rules! signature {
($a:literal) => {
($a as u16)
};
($a:literal, $b:literal) => {
($a as u16) | (($b as u16) << 8)
};
($a:literal, $b:literal, $c:literal) => {
($a as u32) | (($b as u32) << 8) | (($c as u32) << 16)
};
($a:literal, $b:literal, $c:literal, $d:literal) => {
($a as u32) | (($b as u32) << 8) | (($c as u32) << 16) | (($d as u32) << 24)
};
($a:literal, $b:literal, $c:literal, $d:literal, $e:literal) => {
($a as u64) | (($b as u64) << 8) | (($c as u64) << 16) | (($d as u64) << 24) | (($e as u64) << 32)
};
($a:literal, $b:literal, $c:literal, $d:literal, $e:literal, $f:literal) => {
($a as u64)
| (($b as u64) << 8)
| (($c as u64) << 16)
| (($d as u64) << 24)
| (($e as u64) << 32)
| (($f as u64) << 40)
};
($a:literal, $b:literal, $c:literal, $d:literal, $e:literal, $f:literal, $g:literal) => {
($a as u64)
| (($b as u64) << 8)
| (($c as u64) << 16)
| (($d as u64) << 24)
| (($e as u64) << 32)
| (($f as u64) << 40)
| (($g as u64) << 48)
};
($a:literal, $b:literal, $c:literal, $d:literal, $e:literal, $f:literal, $g:literal, $h:literal) => {
($a as u64)
| (($b as u64) << 8)
| (($c as u64) << 16)
| (($d as u64) << 24)
| (($e as u64) << 32)
| (($f as u64) << 40)
| (($g as u64) << 48)
| (($h as u64) << 56)
};
}
#[cfg(test)]
#[coverage(off)]
mod tests {
use super::*;
#[test]
fn test_is_power_of_two() {
assert!(is_power_of_two(1u64));
assert!(is_power_of_two(2u64));
assert!(is_power_of_two(4u64));
assert!(is_power_of_two(1024u64));
assert!(!is_power_of_two(0u64));
assert!(!is_power_of_two(3u64));
assert!(!is_power_of_two(1023u64));
}
#[test]
fn test_align_down() {
assert_eq!(align_down(1023u64, 512u64).unwrap(), 512u64);
assert_eq!(align_down(1024u64, 512u64).unwrap(), 1024u64);
assert_eq!(align_down(0u64, 512u64).unwrap(), 0u64);
assert_eq!(align_down(513u64, 512u64).unwrap(), 512u64);
assert_eq!(align_down(0xFFFFu64, 0x1000u64).unwrap(), 0xF000u64);
assert_eq!(align_down(0x1000u64, 0x1000u64).unwrap(), 0x1000u64);
assert!(align_down(100u64, 3u64).is_err()); }
#[test]
fn test_align_up() {
assert_eq!(align_up(1025u64, 512u64).unwrap(), 1536u64);
assert_eq!(align_up(1024u64, 512u64).unwrap(), 1024u64);
assert_eq!(align_up(0u64, 512u64).unwrap(), 0u64);
assert_eq!(align_up(513u64, 512u64).unwrap(), 1024u64);
assert_eq!(align_up(0xFFFFu64, 0x1000u64).unwrap(), 0x10000u64);
assert_eq!(align_up(0x1000u64, 0x1000u64).unwrap(), 0x1000u64);
assert!(align_up(100u64, 3u64).is_err()); assert!(align_up(u64::MAX, 2u64).is_err());
}
#[test]
fn test_align_range() {
let (base, len) = align_range(1023u64, 2048u64, 512u64).unwrap();
assert_eq!(base, 512u64);
assert_eq!(len, 2560u64);
let (base, len) = align_range(0u64, 100u64, 64u64).unwrap();
assert_eq!(base, 0u64);
assert_eq!(len, 128u64);
let (base, len) = align_range(100u64, 100u64, 64u64).unwrap();
assert_eq!(base, 64u64);
assert_eq!(len, 192u64);
assert!(align_range(100u64, 100u64, 3u64).is_err()); }
#[test]
fn test_signature() {
const TEST0: u16 = signature!('A');
assert_eq!(TEST0, 0x0041);
const TEST1: u16 = signature!('A', '\0');
assert_eq!(TEST1, 0x0041);
const TEST2: u16 = signature!('A', 'B');
assert_eq!(TEST2, 0x4241);
const TEST3: u32 = signature!('A', 'B', 'C');
assert_eq!(TEST3, 0x00434241);
const TEST4: u32 = signature!('A', 'B', 'C', 'D');
assert_eq!(TEST4, 0x44434241);
const TEST5: u32 = signature!('\0', '\0', 'C', 'D');
assert_eq!(TEST5, 0x44430000);
const TEST6: u64 = signature!('A', 'B', 'C', 'D', 'E');
assert_eq!(TEST6, 0x0000004544434241);
const TEST7: u64 = signature!('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H');
assert_eq!(TEST7, 0x4847464544434241);
}
#[test]
fn test_bit_macro_simple() {
assert_eq!(bit!(0), 0b1);
assert_eq!(bit!(1), 0b10);
assert_eq!(bit!(2), 0b100);
assert_eq!(bit!(3), 0b1000);
assert_eq!(bit!(4), 0b1_0000);
assert_eq!(bit!(5), 0b10_0000);
assert_eq!(bit!(6), 0b100_0000);
assert_eq!(bit!(7), 0b1000_0000);
assert_eq!(bit!(8), 0b1_0000_0000);
assert_eq!(bit!(9), 0b10_0000_0000);
assert_eq!(bit!(10), 0b100_0000_0000);
assert_eq!(bit!(20), 0b1_0000_0000_0000_0000_0000);
assert_eq!(bit!(30), 0b100_0000_0000_0000_0000_0000_0000_0000u64);
assert_eq!(bit!(63), 0x8000_0000_0000_0000u64);
}
#[test]
fn test_bit_macro_or() {
let combined = bit!(1) | bit!(3) | bit!(5);
assert_eq!(combined, 0b101010);
let combined = bit!(0) | bit!(2) | bit!(4) | bit!(6) | bit!(8);
assert_eq!(combined, 0b101010101);
}
#[test]
fn test_bit_with_types_specified_works() {
let b1: u8 = bit!(3);
assert_eq!(b1, 0b0000_1000u8);
let b2: u16 = bit!(10);
assert_eq!(b2, 0b0000_0100_0000_0000u16);
let b3: u32 = bit!(20);
assert_eq!(b3, 0x0010_0000u32);
let b4: u64 = bit!(40);
assert_eq!(b4, 0x0100_0000_0000u64);
let b5: u128 = bit!(50);
assert_eq!(b5, 0x0004_0000_0000_0000u128);
}
}