summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2023-10-11 14:35:26 +0200
committerArd Biesheuvel <ardb@kernel.org>2023-10-11 16:13:53 +0200
commit6869e9c4c0032efd1618d4893292d37f660c8410 (patch)
tree35d04ae329d6d56b54c875f7e48e723db14a461d
parent3d56a46e280284cd656e58412391025962dee5aa (diff)
downloadefilite-6869e9c4c0032efd1618d4893292d37f660c8410.tar.gz
rtc stuff
-rw-r--r--src/efi/mod.rs13
-rw-r--r--src/efi/runtimeservices.rs31
-rw-r--r--src/main.rs7
-rw-r--r--src/pl031.rs82
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()));
+}