use super::Header;
use crate::table::boot::MemoryDescriptor;
use crate::{Result, Status};
use bitflags::bitflags;
use core::fmt;
use core::mem::MaybeUninit;
use core::ptr;
#[repr(C)]
pub struct RuntimeServices {
header: Header,
get_time:
unsafe extern "efiapi" fn(time: *mut Time, capabilities: *mut TimeCapabilities) -> Status,
set_time: unsafe extern "efiapi" fn(time: &Time) -> Status,
_pad: [usize; 2],
set_virtual_address_map: unsafe extern "efiapi" fn(
map_size: usize,
desc_size: usize,
desc_version: u32,
virtual_map: *mut MemoryDescriptor,
) -> Status,
_pad2: [usize; 5],
reset: unsafe extern "efiapi" fn(
rt: ResetType,
status: Status,
data_size: usize,
data: *const u8,
) -> !,
}
impl RuntimeServices {
pub fn get_time(&self) -> Result<Time> {
let mut time = MaybeUninit::<Time>::uninit();
unsafe { (self.get_time)(time.as_mut_ptr(), ptr::null_mut()) }
.into_with_val(|| unsafe { time.assume_init() })
}
pub fn get_time_and_caps(&self) -> Result<(Time, TimeCapabilities)> {
let mut time = MaybeUninit::<Time>::uninit();
let mut caps = MaybeUninit::<TimeCapabilities>::uninit();
unsafe { (self.get_time)(time.as_mut_ptr(), caps.as_mut_ptr()) }
.into_with_val(|| unsafe { (time.assume_init(), caps.assume_init()) })
}
pub unsafe fn set_time(&mut self, time: &Time) -> Result {
(self.set_time)(time).into()
}
pub unsafe fn set_virtual_address_map(&self, map: &mut [MemoryDescriptor]) -> Result {
let map_size = core::mem::size_of_val(map);
let entry_size = core::mem::size_of::<MemoryDescriptor>();
let entry_version = crate::table::boot::MEMORY_DESCRIPTOR_VERSION;
let map_ptr = map.as_mut_ptr();
(self.set_virtual_address_map)(map_size, entry_size, entry_version, map_ptr).into()
}
pub fn reset(&self, rt: ResetType, status: Status, data: Option<&[u8]>) -> ! {
let (size, data) = match data {
Some(data) => (data.len(), data.as_ptr()),
None => (0, ptr::null()),
};
unsafe { (self.reset)(rt, status, size, data) }
}
}
impl super::Table for RuntimeServices {
const SIGNATURE: u64 = 0x5652_4553_544e_5552;
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Time {
year: u16, month: u8, day: u8, hour: u8, minute: u8, second: u8, _pad1: u8,
nanosecond: u32, time_zone: i16, daylight: Daylight,
_pad2: u8,
}
bitflags! {
pub struct Daylight: u8 {
const ADJUST_DAYLIGHT = 0x01;
const IN_DAYLIGHT = 0x02;
}
}
impl Time {
#[allow(clippy::too_many_arguments)]
pub fn new(
year: u16,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
nanosecond: u32,
time_zone: i16,
daylight: Daylight,
) -> Self {
assert!((1900..=9999).contains(&year));
assert!((1..=12).contains(&month));
assert!((1..=31).contains(&day));
assert!(hour <= 23);
assert!(minute <= 59);
assert!(second <= 59);
assert!(nanosecond <= 999_999_999);
assert!((time_zone >= -1440 && time_zone <= 1440) || time_zone == 2047);
Self {
year,
month,
day,
hour,
minute,
second,
_pad1: 0,
nanosecond,
time_zone,
daylight,
_pad2: 0,
}
}
pub fn year(&self) -> u16 {
self.year
}
pub fn month(&self) -> u8 {
self.month
}
pub fn day(&self) -> u8 {
self.day
}
pub fn hour(&self) -> u8 {
self.hour
}
pub fn minute(&self) -> u8 {
self.minute
}
pub fn second(&self) -> u8 {
self.second
}
pub fn nanosecond(&self) -> u32 {
self.nanosecond
}
pub fn time_zone(&self) -> Option<i16> {
if self.time_zone == 2047 {
None
} else {
Some(self.time_zone)
}
}
pub fn daylight(&self) -> Daylight {
self.daylight
}
}
impl fmt::Debug for Time {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}-{}-{} ", self.year, self.month, self.day)?;
write!(
f,
"{}:{}:{}.{} ",
self.hour, self.minute, self.second, self.nanosecond
)?;
write!(f, "{} {:?}", self.time_zone, self.daylight)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct TimeCapabilities {
pub resolution: u32,
pub accuracy: u32,
pub sets_to_zero: bool,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u32)]
pub enum ResetType {
Cold = 0,
Warm,
Shutdown,
PlatformSpecific,
}