Skip to content

Commit 4b26795

Browse files
hawkwAnatol Ulrich
and
Anatol Ulrich
authored
all platforms: update Mycelium dependencies (#343)
This updates our dependencies on Mycelium crates to hawkw/mycelium@ba56bb4. This picks up the new `maitake` timer API, as well as the upstream change hawkw/mycelium#487 to allow raw access to the IDT in the Mycelium x86_64 HAL, which we need to do an async UART driver (see #337). While updating everything to use the new timer API, I also made some tweaks to our existing timer code, including implementing 32-bit timer rollover for the D1's TIMER0 (our current timestamp source on that platform). This was an ancient TODO item since basically forever. Fixes #337 --------- Co-authored-by: Anatol Ulrich <[email protected]>
1 parent 5f4bc9e commit 4b26795

File tree

22 files changed

+279
-158
lines changed

22 files changed

+279
-158
lines changed

Cargo.lock

+22-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+25-18
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,22 @@ default-members = [
6767
# this isn't actually a crate
6868
exclude = ["source/notes"]
6969

70+
### workspace dependencies ###
71+
7072
[workspace.package]
7173
edition = "2021"
7274
repository = "https://github.com/tosc-rs/mnemos"
7375
homepage = "https://mnemos.dev"
7476
license = "MIT OR Apache-2.0"
7577

7678
[workspace.dependencies]
79+
cordyceps = { version = "0.3", default-features = false }
80+
hal-core = { version = "0.1.0" }
81+
maitake = { version = "0.1.0", default-features = false }
7782
miette = "7.2"
83+
mycelium-alloc = { version = "0.1.0", features = ["buddy", "bump"] }
84+
mycelium-bitfield = { version = "0.1.5" }
85+
mycelium-util = { version = "0.1.0" }
7886

7987
### profile settings ###
8088

@@ -150,13 +158,12 @@ debug = "line-tables-only"
150158
### patches ###
151159

152160
[patch.crates-io.maitake]
153-
git = "https://github.com/hawkw/mycelium.git"
154-
rev = "13d0722429ef201f38e4ea47ea22d88f3f72c10e"
155-
156-
[patch.crates-io.mycelium-util]
157-
git = "https://github.com/hawkw/mycelium.git"
158-
rev = "13d0722429ef201f38e4ea47ea22d88f3f72c10e"
161+
git = "https://github.com/hawkw/mycelium"
162+
rev = "ba56bb4d02f46fb59754b7b88bddc2e8ca99c1f5"
159163

164+
[patch.crates-io.mycelium-alloc]
165+
git = "https://github.com/hawkw/mycelium"
166+
rev = "ba56bb4d02f46fb59754b7b88bddc2e8ca99c1f5"
160167
# Use the `mycelium-bitfield` crate from the Mycelium monorepo rather than
161168
# crates.io.
162169
# NOTE: this patch, unlike the patches for `maitake` and `mycelium-util`, (which
@@ -165,24 +172,24 @@ rev = "13d0722429ef201f38e4ea47ea22d88f3f72c10e"
165172
# since it's already in our dependency tree as a transitive dep of `maitake` ---
166173
# having both a Git dep and a crates.io dep seems unfortunate.
167174
[patch.crates-io.mycelium-bitfield]
168-
git = "https://github.com/hawkw/mycelium.git"
169-
rev = "13d0722429ef201f38e4ea47ea22d88f3f72c10e"
175+
git = "https://github.com/hawkw/mycelium"
176+
rev = "ba56bb4d02f46fb59754b7b88bddc2e8ca99c1f5"
177+
178+
[patch.crates-io.mycelium-util]
179+
git = "https://github.com/hawkw/mycelium"
180+
rev = "ba56bb4d02f46fb59754b7b88bddc2e8ca99c1f5"
170181

171182
[patch.crates-io.cordyceps]
172-
git = "https://github.com/hawkw/mycelium.git"
173-
rev = "13d0722429ef201f38e4ea47ea22d88f3f72c10e"
183+
git = "https://github.com/hawkw/mycelium"
184+
rev = "ba56bb4d02f46fb59754b7b88bddc2e8ca99c1f5"
174185

175186
[patch.crates-io.hal-core]
176-
git = "https://github.com/hawkw/mycelium.git"
177-
rev = "13d0722429ef201f38e4ea47ea22d88f3f72c10e"
187+
git = "https://github.com/hawkw/mycelium"
188+
rev = "ba56bb4d02f46fb59754b7b88bddc2e8ca99c1f5"
178189

179190
[patch.crates-io.hal-x86_64]
180-
git = "https://github.com/hawkw/mycelium.git"
181-
rev = "13d0722429ef201f38e4ea47ea22d88f3f72c10e"
182-
183-
[patch.crates-io.mycelium-alloc]
184-
git = "https://github.com/hawkw/mycelium.git"
185-
rev = "13d0722429ef201f38e4ea47ea22d88f3f72c10e"
191+
git = "https://github.com/hawkw/mycelium"
192+
rev = "ba56bb4d02f46fb59754b7b88bddc2e8ca99c1f5"
186193

187194
[patch.crates-io.bbq10kbd]
188195
git = "https://github.com/hawkw/bbq10kbd"

platforms/allwinner-d1/board-configs/lichee-rv.toml

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[kernel]
22
max_drivers = 16
3-
timer_granularity = { secs = 0, nanos = 333 }
43

54
[services.spawnulator]
65
enabled = true

platforms/allwinner-d1/d1-core/src/timer.rs

+79
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,92 @@
1+
use crate::plic::{Plic, Priority};
2+
use core::sync::atomic::{AtomicU32, Ordering};
13
pub use d1_pac::timer::tmr_ctrl::{
24
TMR_CLK_PRES_A as TimerPrescaler, TMR_CLK_SRC_A as TimerSource, TMR_MODE_A as TimerMode,
35
};
46
use d1_pac::TIMER;
7+
use kernel::maitake::time::Clock;
58

69
pub struct Timers {
710
pub timer0: Timer0,
811
pub timer1: Timer1,
912
}
1013

14+
static TIMER0_ROLLOVERS: AtomicU32 = AtomicU32::new(0);
15+
16+
impl Timer0 {
17+
const INITIAL_VALUE: u32 = u32::MAX;
18+
19+
pub fn into_maitake_clock(mut self, plic: &Plic) -> Clock {
20+
use d1_pac::Interrupt;
21+
self.set_prescaler(TimerPrescaler::P8); // 24M / 8: 3.00M ticks/s
22+
self.set_mode(TimerMode::PERIODIC);
23+
24+
// Clear any previous interrupt flag.
25+
let _ = self.get_and_clear_interrupt();
26+
27+
// Register the interrupt handler for when the timer rolls over.
28+
unsafe {
29+
plic.register(Interrupt::TIMER0, Self::maitake_timer_interrupt);
30+
plic.activate(Interrupt::TIMER0, Priority::P1).unwrap();
31+
}
32+
33+
// Start the timer counting down from u32::MAX;.
34+
self.reset();
35+
36+
Clock::new(core::time::Duration::from_nanos(333), || {
37+
let timer0 = unsafe {
38+
// Safety: we are just reading the current value and will not be
39+
// concurrently mutating the timer.
40+
Self::steal()
41+
};
42+
// Since timer 0 is counting *down*, we have to subtract its current
43+
// value from the intial value to get an i[ncreasing timestamp for
44+
// Maitake. As timer 0 is a 32-bit timer, this forms the lower half
45+
// of our 64-bit timestamp.
46+
let lo = (Self::INITIAL_VALUE - timer0.current_value()) as u64;
47+
// The higher half of the 64-bit timestamp is the current value of
48+
// the 32-bit timer rollover counter --- i.e. the number of times
49+
// that timer 0 has counted down to 0.
50+
let hi = TIMER0_ROLLOVERS.load(Ordering::Relaxed) as u64;
51+
// Combine the two halves to form the full 64-bit timestamp.
52+
(hi << 32) | lo
53+
})
54+
.named("CLOCK_D1_TIMER0")
55+
}
56+
57+
fn reset(&mut self) {
58+
self.start_counter(Self::INITIAL_VALUE);
59+
// N.B. that we probably don't *have* to reset the IRQ_EN bit every time
60+
// it fires, but let's make sure it's enabled just in case...
61+
self.set_interrupt_en(true);
62+
}
63+
64+
/// Handle a TIMER0 interrupt when TIMER0 is used as the maitake timer.
65+
fn maitake_timer_interrupt() {
66+
let mut timer0 = unsafe {
67+
// Safety: we need to do this to be an ISR lol
68+
Self::steal()
69+
};
70+
71+
// Clear the interrupt flag
72+
let _ = timer0.get_and_clear_interrupt();
73+
74+
// Increment the rollover counter
75+
TIMER0_ROLLOVERS.fetch_add(1, Ordering::Relaxed);
76+
77+
// Wait for the interrupt to clear to avoid repeat interrupts
78+
let timers = unsafe { &*TIMER::PTR };
79+
while timers.tmr_irq_sta.read().tmr0_irq_pend().bit_is_set() {}
80+
81+
// RESET THE CLOCK!
82+
timer0.reset();
83+
}
84+
85+
unsafe fn steal() -> Self {
86+
Self { _x: () }
87+
}
88+
}
89+
1190
mod sealed {
1291
use d1_pac::{
1392
generic::Reg,

platforms/allwinner-d1/src/lib.rs

+11-25
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ pub fn kernel_entry(config: mnemos_config::MnemosConfig<PlatformConfig>) -> ! {
163163

164164
pub struct D1 {
165165
pub kernel: &'static Kernel,
166-
pub timers: Timers,
166+
pub timer1: mnemos_d1_core::timer::Timer1,
167167
pub plic: Plic,
168168
pub dmac: Dmac,
169169
_uart: Uart,
@@ -192,10 +192,13 @@ impl D1 {
192192
kernel_settings: KernelSettings,
193193
service_settings: KernelServiceSettings,
194194
) -> Self {
195+
let timer0_clock = timers.timer0.into_maitake_clock(&plic);
195196
let k = unsafe {
196-
Box::into_raw(Kernel::new(kernel_settings).expect("cannot initialize kernel"))
197-
.as_ref()
198-
.unwrap()
197+
Box::into_raw(
198+
Kernel::new(kernel_settings, timer0_clock).expect("cannot initialize kernel"),
199+
)
200+
.as_ref()
201+
.unwrap()
199202
};
200203

201204
k.initialize_default_services(service_settings);
@@ -240,7 +243,7 @@ impl D1 {
240243
kernel: k,
241244
_uart: uart,
242245
_spim: spim,
243-
timers,
246+
timer1: timers.timer1,
244247
plic,
245248
dmac,
246249
i2c0_int,
@@ -293,7 +296,7 @@ impl D1 {
293296
pub fn run(self) -> ! {
294297
let Self {
295298
kernel: k,
296-
timers,
299+
mut timer1,
297300
plic,
298301
dmac: _,
299302
_uart,
@@ -308,19 +311,9 @@ impl D1 {
308311
//
309312
// In the future, we probably want to rework this to use the RTC timer for
310313
// both purposes, as this will likely play better with sleep power usage.
311-
let Timers {
312-
mut timer0,
313-
mut timer1,
314-
} = timers;
315314

316-
// NOTE: if you change the timer frequency, make sure you update
317-
// initialize_kernel() below to correct the kernel timer wheel
318-
// granularity setting!
319-
timer0.set_prescaler(TimerPrescaler::P8); // 24M / 8: 3.00M ticks/s
320315
timer1.set_prescaler(TimerPrescaler::P8);
321-
timer0.set_mode(TimerMode::PERIODIC);
322316
timer1.set_mode(TimerMode::SINGLE_COUNTING);
323-
let _ = timer0.get_and_clear_interrupt();
324317
let _ = timer1.get_and_clear_interrupt();
325318

326319
unsafe {
@@ -344,22 +337,16 @@ impl D1 {
344337
}
345338
}
346339

347-
timer0.start_counter(0xFFFF_FFFF);
348-
349340
loop {
350341
// Tick the scheduler
351-
let start = timer0.current_value();
352342
let tick = k.tick();
353343

354344
// Timer is downcounting
355-
let elapsed = start.wrapping_sub(timer0.current_value());
356-
let turn = k.timer().force_advance_ticks(elapsed.into());
345+
let turn = k.timer().turn();
357346

358347
// If there is nothing else scheduled, and we didn't just wake something up,
359348
// sleep for some amount of time
360349
if turn.expired == 0 && !tick.has_remaining {
361-
let wfi_start = timer0.current_value();
362-
363350
// TODO(AJM): Sometimes there is no "next" in the timer wheel, even though there should
364351
// be. Don't take lack of timer wheel presence as the ONLY heuristic of whether we
365352
// should just wait for SOME interrupt to occur. For now, force a max sleep of 100ms
@@ -384,8 +371,7 @@ impl D1 {
384371
timer1.stop();
385372

386373
// Account for time slept
387-
let elapsed = wfi_start.wrapping_sub(timer0.current_value());
388-
let _turn = k.timer().force_advance_ticks(elapsed.into());
374+
let _turn = k.timer().turn();
389375
}
390376
}
391377
}

0 commit comments

Comments
 (0)