diff options
author | Ard Biesheuvel <ardb@kernel.org> | 2023-10-11 14:35:26 +0200 |
---|---|---|
committer | Ard Biesheuvel <ardb@kernel.org> | 2023-10-11 16:13:53 +0200 |
commit | 6869e9c4c0032efd1618d4893292d37f660c8410 (patch) | |
tree | 35d04ae329d6d56b54c875f7e48e723db14a461d | |
parent | 3d56a46e280284cd656e58412391025962dee5aa (diff) | |
download | efilite-6869e9c4c0032efd1618d4893292d37f660c8410.tar.gz |
rtc stuff
-rw-r--r-- | src/efi/mod.rs | 13 | ||||
-rw-r--r-- | src/efi/runtimeservices.rs | 31 | ||||
-rw-r--r-- | src/main.rs | 7 | ||||
-rw-r--r-- | src/pl031.rs | 82 |
4 files changed, 113 insertions, 20 deletions
diff --git a/src/efi/mod.rs b/src/efi/mod.rs index b6bea0e..c4f4750 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -7,6 +7,7 @@ use crate::efi::configtable::ConfigurationTable; use crate::efi::loadedimage::EFI_LOADED_IMAGE_PROTOCOL_GUID; use crate::efi::memmap::*; use crate::efi::runtimeservices::RuntimeServices; +use crate::efi::runtimeservices::GetTime; use crate::efi::MemoryType::*; use crate::efi::{loadedimage::*, memorytype::*, systemtable::*}; use crate::PeImage; @@ -37,7 +38,7 @@ pub mod memmap; pub mod memorytype; pub mod peloader; pub mod rng; -mod runtimeservices; +pub mod runtimeservices; mod simpletext; pub mod status; mod systemtable; @@ -117,6 +118,7 @@ pub const EFI_MEMORY_ATTRIBUTES_TABLE_GUID: Guid = guid!( ); const EFI_RT_SUPPORTED_GET_TIME: u32 = 0x0001; +const EFI_RT_SUPPORTED_SET_TIME: u32 = 0x0002; const EFI_RT_SUPPORTED_GET_VARIABLE: u32 = 0x0010; const EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME: u32 = 0x0020; const EFI_RT_SUPPORTED_RESET_SYSTEM: u32 = 0x0400; @@ -132,6 +134,7 @@ static RT_PROPERTIES_TABLE: RtPropertiesTable = RtPropertiesTable { version: 1, length: core::mem::size_of::<RtPropertiesTable>() as _, supported_mask: EFI_RT_SUPPORTED_GET_TIME + | EFI_RT_SUPPORTED_SET_TIME | EFI_RT_SUPPORTED_GET_VARIABLE | EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME | EFI_RT_SUPPORTED_RESET_SYSTEM, @@ -201,7 +204,7 @@ pub struct EfiContext { configtable_db: Spinlock<BTreeMap<Guid, ConfigurationTable>>, _bs: Pin<Box<BootServices>>, - _rt: &'static RuntimeServices, + rt: Spinlock<&'static mut RuntimeServices>, sys_table: Spinlock<&'static mut SystemTable>, } @@ -232,7 +235,7 @@ pub fn init() -> Result<&'static EfiContext, ()> { rtsdata: h, configtable_db: Spinlock::new(BTreeMap::new()), _bs: bs, - _rt: rt, + rt: Spinlock::new(rt), sys_table: Spinlock::new(st), })) }); @@ -285,4 +288,8 @@ impl EfiContext { randomized, ) } + + pub fn set_rtc_override(&self, f: GetTime) { + self.rt.lock().get_time = f; + } } diff --git a/src/efi/runtimeservices.rs b/src/efi/runtimeservices.rs index 8aa438e..80294fa 100644 --- a/src/efi/runtimeservices.rs +++ b/src/efi/runtimeservices.rs @@ -7,23 +7,24 @@ use crate::efi::{memorytype::*, status::*, tableheader::*}; use crate::efi::{Bool, Char16, Guid, PhysicalAddress}; use crate::psci; +#[derive(Debug)] #[repr(C)] -struct Time { - year: u16, - month: u8, - date: u8, - hour: u8, - minute: u8, - second: u8, - pad1: u8, - nanosecond: u32, - timezone: u16, - daylight: u8, - pad2: u8, +pub struct Time { + pub year: u16, + pub month: u8, + pub day: u8, + pub hour: u8, + pub minute: u8, + pub second: u8, + pub pad1: u8, + pub nanosecond: u32, + pub timezone: u16, + pub daylight: u8, + pub pad2: u8, } #[repr(C)] -struct TimeCapabilities { +pub struct TimeCapabilities { resolution: u32, accuracy: u32, sets_to_zero: Bool, @@ -46,7 +47,7 @@ struct CapsuleHeader { capsule_image_size: u32, } -type GetTime = extern "C" fn(_time: *mut Time, _capabilities: *mut TimeCapabilities) -> Status; +pub(super) type GetTime = extern "C" fn(_time: *mut Time, _capabilities: *mut TimeCapabilities) -> Status; type SetTime = extern "C" fn(_time: *const Time) -> Status; @@ -118,7 +119,7 @@ type QueryVariableInfo = extern "C" fn( #[repr(C)] pub struct RuntimeServices { hdr: TableHeader, - get_time: GetTime, + pub get_time: GetTime, set_time: SetTime, get_wakeup_time: GetWakeupTime, set_wakeup_time: SetWakeupTime, diff --git a/src/main.rs b/src/main.rs index 9999166..12ff4b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ mod idmap; mod initrd; mod pagealloc; mod paging; +mod pl031; mod psci; mod rng; @@ -44,9 +45,9 @@ use crate::efi::FileLoader; use crate::efi::{guid, Guid}; use crate::paging::Attributes; use crate::MemoryType::EfiBootServicesData; +use crate::MemoryType::EfiMemoryMappedIO; use crate::MemoryType::EfiRuntimeServicesCode; use crate::MemoryType::EfiRuntimeServicesData; -use crate::MemoryType::EfiMemoryMappedIO; #[macro_use] extern crate bitflags; @@ -166,7 +167,9 @@ extern "C" fn efilite_main(base: *mut u8, mapped: usize, used: isize, avail: usi pl031_node.reg().map(|mut r| { let b = r.nth(0)?.starting_address; let s = unsafe { slice::from_raw_parts(b as *const u8, EFI_PAGE_MASK + 1) }; - efi::memmap::declare_runtime_region(s, EfiMemoryMappedIO).ok() + efi::memmap::declare_runtime_region(s, EfiMemoryMappedIO).ok(); + pl031::init(b as usize); + Some(efi.set_rtc_override(pl031::get_time)) }); } else { debug!("ACPI tables unavailable: {}\n", tbl.err().unwrap()); diff --git a/src/pl031.rs b/src/pl031.rs new file mode 100644 index 0000000..83429d2 --- /dev/null +++ b/src/pl031.rs @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2023 Google LLC +// Author: Ard Biesheuvel <ardb@google.com> + +use crate::efi::runtimeservices::{Time, TimeCapabilities}; +use crate::efi::status::Status; +use crate::efi::status::Status::EFI_SUCCESS; + +use core::mem::MaybeUninit; +use mmio::{Allow, VolBox}; + +//const EFI_TIME_ADJUST_DAYLIGHT: u8 = 0x1; +//const EFI_TIME_IN_DAYLIGHT: u8 = 0x2; + +const EFI_UNSPECIFIED_TIMEZONE: u16 = 0x07ff; + +#[link_section = ".rtrodata"] +static mut _RTC: MaybeUninit<VolBox<u32, Allow, Allow>> = MaybeUninit::uninit(); + +fn time_from_ts(ts: u32) -> Time { + let secs = ts % 86400; + + let h = secs / 3600; + let m = (secs / 60) % 60; + let s = secs % 60; + + /* algorithm taken from drivers/rtc/lib.c in Linux */ + let (century, day_of_century) = { + let d = ts / 86400 + 719468; + let t = 4 * d + 3; + + (t / 146097, t % 146097 / 4) + }; + + let (year_of_century, day_of_year) = { + let t = 2939745u64 * (4 * day_of_century as u64 + 3); + + (t >> 32, (t & u32::MAX as u64) as u32 / 2939745 / 4) + }; + + let (day, year, month) = { + let t = 2141 * day_of_year + 132377; + let y = 100 * century + year_of_century as u32; + let m = t >> 16; + let d = (t & u16::MAX as u32) / 2141; + if m > 12 { + (d + 1, y + 1, m - 11) + } else { + (d + 1, y, m + 1) + } + }; + + Time { + year: year as u16, + month: month as u8, + day: day as u8, + hour: h as u8, + minute: m as u8, + second: s as u8, + pad1: 0, + nanosecond: 0, + timezone: EFI_UNSPECIFIED_TIMEZONE, + daylight: 0, + pad2: 0, + } +} + +pub extern "C" fn get_time(time: *mut Time, _capabilities: *mut TimeCapabilities) -> Status { + let rtc = unsafe { _RTC.assume_init_ref() }; + let t = time_from_ts(rtc.read()); + + unsafe { + *time = t; + } + EFI_SUCCESS +} + +pub fn init(base: usize) { + let rtc = unsafe { _RTC.write(VolBox::<u32, Allow, Allow>::new(base as *mut u32)) }; + + log::trace!("{:?}\n", time_from_ts(rtc.read())); +} |