Skip to content

Commit 4edc3cd

Browse files
midnightveilnspin
authored andcommitted
domains: support units for schedule duration
This is an implementation of the equivalent change to the C/Haskell capDL initialiser with the commit name 'Support domain schedule units (us & ticks)'. For justification of the algorithm within, its correctness, and discussion of why we want it, please see that PR. Signed-off-by: Julia Vassiliki <julia.vassiliki@unsw.edu.au>
1 parent 2c1fa13 commit 4edc3cd

2 files changed

Lines changed: 97 additions & 5 deletions

File tree

crates/sel4-capdl-initializer/src/initialize.rs

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,82 @@ impl<'a> Initializer<'a> {
10531053
Ok(())
10541054
}
10551055

1056+
#[sel4::sel4_cfg(KERNEL_MCS)]
1057+
fn us_to_ticks(&self, duration_us: u64) -> Result<sel4::Time> {
1058+
sel4::sel4_cfg_if! {
1059+
if #[sel4_cfg(any(ARCH_ARM, ARCH_RISCV))] {
1060+
const US_IN_SECOND: u64 = 1000 * 1000;
1061+
1062+
// On 32-bit platforms, Word is 32-bits, but on 64-bit platforms
1063+
// it is also a u64 and deemed "unnecessary".
1064+
#[allow(clippy::useless_conversion)]
1065+
let f: u64 = sel4::sel4_cfg_word!(TIMER_FREQUENCY).into();
1066+
1067+
// TODO: Formal correctness of this implementation
1068+
// https://github.com/seL4/capdl/issues/98
1069+
// See also the corresponding implementation in capDL.
1070+
1071+
if (duration_us / US_IN_SECOND) >= (1u64 << 56) / f {
1072+
panic!(
1073+
"Input us {duration_us} would overflow 64-bits of \
1074+
exceed 56-bit output tick maximum @ freq {f} Hz"
1075+
);
1076+
}
1077+
1078+
let s: u64 = duration_us / US_IN_SECOND;
1079+
let us: u64 = duration_us % US_IN_SECOND;
1080+
1081+
// The '+ US_IN_S / 2' implements round-to-nearest behaviour
1082+
let ticks = s * f + ((us * f + US_IN_SECOND / 2) / US_IN_SECOND);
1083+
1084+
Ok(ticks)
1085+
} else if #[sel4_cfg(any(ARCH_X86, ARCH_X86_64))] {
1086+
let tsc_freq_bi = self
1087+
.bootinfo
1088+
.extra()
1089+
.find(|bi| bi.id == sel4::BootInfoExtraId::X86TscFreq)
1090+
.expect("Unable to determine timer frequency as \
1091+
no TSC frequency provided in bootinfo");
1092+
1093+
// For x86 platforms, the timer frequency is provided in MHz by the bootinfo
1094+
let tsc_freq_mhz = u32::from_le_bytes(tsc_freq_bi.content().try_into().unwrap());
1095+
1096+
let ticks = duration_us
1097+
.checked_mul(tsc_freq_mhz.into())
1098+
.expect(format!(
1099+
"Output would overflow when computing ticks for duration \
1100+
{duration_us} us @ freq {tsc_freq_mhz} MHz"));
1101+
1102+
Ok(ticks)
1103+
} else {
1104+
compile_error!("unsupported architecture");
1105+
}
1106+
}
1107+
}
1108+
1109+
#[sel4::sel4_cfg(not(KERNEL_MCS))]
1110+
fn us_to_ticks(&self, duration_us: u64) -> Result<sel4::Time> {
1111+
// On non-MCS, 1 tick is equivalent to 1 TIMER_TICK_MS, or an integer multiple
1112+
// of 1 millisecond.
1113+
1114+
// On 32-bit platforms, Word is 32-bits, but on 64-bit platforms it is
1115+
// also a u64 and deemed "unnecessary".
1116+
#[allow(clippy::unnecessary_cast)]
1117+
const TIMER_TICK_MS: u64 = sel4::sel4_cfg_word!(TIMER_TICK_MS) as u64;
1118+
let period_us: u64 = 1000 * TIMER_TICK_MS;
1119+
let ticks: u64 = duration_us / period_us;
1120+
let remainder: u64 = duration_us % period_us;
1121+
1122+
if remainder != 0 {
1123+
panic!(
1124+
"domain schedule duration {duration_us} is not an \
1125+
integer multiple of TIMER_TICK_MS ({TIMER_TICK_MS} ms)"
1126+
);
1127+
}
1128+
1129+
Ok(ticks)
1130+
}
1131+
10561132
fn init_domain_schedule(&self) -> Result<()> {
10571133
if let ArchivedOption::Some(domain_schedule) = &self.spec.domain_schedule {
10581134
debug!("Initializing domain schedule");
@@ -1066,11 +1142,17 @@ impl<'a> Initializer<'a> {
10661142

10671143
// sched_index is used as a shift, and not an invariant for the loop.
10681144
#[allow(clippy::explicit_counter_loop)]
1069-
for ArchivedDomainSchedEntry { id, time } in domain_schedule.iter() {
1070-
let domain_time = *time;
1145+
for ArchivedDomainSchedEntry { domain, duration } in domain_schedule.iter() {
1146+
let duration_ticks: u64 = match *duration {
1147+
ArchivedDomainSchedDuration::Ticks(ticks) => ticks.get(),
1148+
ArchivedDomainSchedDuration::Us(us) => self.us_to_ticks(us.get())?,
1149+
ArchivedDomainSchedDuration::EndMarker => 0,
1150+
};
1151+
10711152
init_thread::slot::DOMAIN_SET
10721153
.cap()
1073-
.domain_set_schedule_configure(sched_index, *id, domain_time.to_native())?;
1154+
.domain_set_schedule_configure(sched_index, *domain, duration_ticks)?;
1155+
10741156
sched_index += 1;
10751157
}
10761158
}

crates/sel4-capdl-initializer/types/src/spec.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use alloc::boxed::Box;
88
use alloc::string::String;
99
use alloc::vec::Vec;
10+
use core::num::NonZero;
1011
use core::ops::Range;
1112

1213
use rkyv::Archive;
@@ -143,12 +144,21 @@ pub struct IrqEntry {
143144
pub handler: ObjectId,
144145
}
145146

147+
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
148+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
149+
#[derive(rkyv::Archive, rkyv::Serialize)]
150+
pub enum DomainSchedDuration {
151+
Ticks(NonZero<u64>),
152+
Us(NonZero<u64>),
153+
EndMarker,
154+
}
155+
146156
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
147157
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
148158
#[derive(rkyv::Archive, rkyv::Serialize)]
149159
pub struct DomainSchedEntry {
150-
pub id: u8,
151-
pub time: u64,
160+
pub domain: u8,
161+
pub duration: DomainSchedDuration,
152162
}
153163

154164
pub type AsidSlotEntry = ObjectId;

0 commit comments

Comments
 (0)