Skip to content

Commit f48f443

Browse files
committed
WIP
1 parent b7cb4d3 commit f48f443

File tree

15 files changed

+231
-210
lines changed

15 files changed

+231
-210
lines changed

src/arch/aarch64/kernel/interrupts.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use memory_addresses::arch::aarch64::PhysAddr;
1717
use crate::arch::aarch64::kernel::core_local::increment_irq_counter;
1818
use crate::arch::aarch64::kernel::scheduler::State;
1919
use crate::arch::aarch64::mm::paging::{self, BasePageSize, PageSize, PageTableEntryFlags};
20+
use crate::arch::timer_interrupts;
2021
#[cfg(not(feature = "pci"))]
2122
use crate::drivers::mmio::get_interrupt_handlers;
2223
#[cfg(feature = "pci")]
@@ -93,10 +94,7 @@ pub(crate) fn install_handlers() {
9394

9495
fn timer_handler() {
9596
debug!("Handle timer interrupt");
96-
97-
// disable timer
98-
CNTP_CVAL_EL0.set(0);
99-
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::CLEAR);
97+
timer_interrupts::clear_active_and_set_next();
10098
}
10199

102100
for (key, value) in get_interrupt_handlers().into_iter() {

src/arch/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Architecture-specific architecture abstraction.
22
3+
pub(crate) mod timer_interrupts;
4+
35
cfg_if::cfg_if! {
46
if #[cfg(target_arch = "aarch64")] {
57
pub(crate) mod aarch64;

src/arch/riscv64/kernel/scheduler.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@ use free_list::{PageLayout, PageRange};
55
use memory_addresses::{PhysAddr, VirtAddr};
66

77
use crate::arch::riscv64::kernel::core_local::core_scheduler;
8-
use crate::arch::riscv64::kernel::processor::set_oneshot_timer;
98
use crate::arch::riscv64::mm::paging::{BasePageSize, PageSize, PageTableEntryFlags};
109
use crate::mm::{FrameAlloc, PageAlloc, PageRangeAllocator};
1110
use crate::scheduler::task::{Task, TaskFrame};
12-
use crate::{DEFAULT_STACK_SIZE, KERNEL_STACK_SIZE};
11+
use crate::{DEFAULT_STACK_SIZE, KERNEL_STACK_SIZE, timer_interrupts};
1312

1413
#[repr(C, packed)]
1514
#[derive(Clone, Copy, Debug)]
@@ -360,9 +359,9 @@ unsafe extern "C" fn task_start(func: extern "C" fn(usize), arg: usize, user_sta
360359
}
361360

362361
pub fn timer_handler() {
363-
//increment_irq_counter(apic::TIMER_INTERRUPT_NUMBER.into());
362+
debug!("Handle timer interrupt");
363+
timer_interrupts::clear_active_and_set_next();
364364
core_scheduler().handle_waiting_tasks();
365-
set_oneshot_timer(None);
366365
core_scheduler().scheduler();
367366
}
368367

src/arch/timer_interrupts.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
use core::ops::{Deref, DerefMut};
2+
3+
use crate::core_local::core_scheduler;
4+
#[cfg(feature = "net")]
5+
use crate::executor::network::NETWORK_WAKER;
6+
use crate::set_oneshot_timer;
7+
8+
/// A possible timer interrupt source (i.e. reason the timer interrupt was set
9+
/// up).
10+
#[derive(Debug, PartialEq, Eq)]
11+
pub enum Source {
12+
Network,
13+
Scheduler,
14+
}
15+
16+
/// A slot in the timer list. Each source is represented once. This is so that
17+
/// we can have multiple timers at the same time with only one hardware timer.
18+
#[derive(Debug)]
19+
pub struct Slot {
20+
/// Timer source.
21+
source: Source,
22+
/// Point in time at which to wake up (in microsecond precision).
23+
/// A value of [`u64::MAX`] means the timer is not set.
24+
wakeup_time: u64,
25+
}
26+
27+
// List of timers with one entry for every possible source.
28+
#[derive(Debug)]
29+
pub struct TimerList([Slot; 2]);
30+
31+
impl TimerList {
32+
pub fn new() -> Self {
33+
Self([
34+
Slot {
35+
source: Source::Network,
36+
wakeup_time: u64::MAX,
37+
},
38+
Slot {
39+
source: Source::Scheduler,
40+
wakeup_time: u64::MAX,
41+
},
42+
])
43+
}
44+
}
45+
46+
impl Deref for TimerList {
47+
type Target = [Slot; 2];
48+
49+
fn deref(&self) -> &Self::Target {
50+
&self.0
51+
}
52+
}
53+
54+
impl DerefMut for TimerList {
55+
fn deref_mut(&mut self) -> &mut Self::Target {
56+
&mut self.0
57+
}
58+
}
59+
60+
/// Create a new timer, overriding any previous timer for the source.
61+
#[cfg(feature = "net")]
62+
#[inline]
63+
pub fn create_timer(source: Source, wakeup_micros: u64) {
64+
create_timer_abs(
65+
source,
66+
crate::arch::processor::get_timer_ticks() + wakeup_micros,
67+
);
68+
}
69+
70+
/// Crete a new timer, but with an absolute wakeup time.
71+
pub fn create_timer_abs(source: Source, wakeup_time: u64) {
72+
let timers = &mut core_scheduler().timers;
73+
74+
// SAFETY: Our timer list has an entry for every possible source
75+
let previous_entry = timers
76+
.iter_mut()
77+
.find(|slot| slot.source == source)
78+
.unwrap();
79+
80+
// Overwrite the wakeup time
81+
previous_entry.wakeup_time = previous_entry.wakeup_time.min(wakeup_time);
82+
83+
// If this timer is the one closest in the future, set the real timer to it
84+
// SAFETY: There's more than 1 slot
85+
if timers.iter().map(|slot| slot.wakeup_time).min().unwrap() == wakeup_time {
86+
set_oneshot_timer(Some(wakeup_time));
87+
}
88+
}
89+
90+
/// Clears the timer slot for the currently active timer and sets the next timer or disables it if no timer is pending.
91+
pub fn clear_active_and_set_next() {
92+
let timers = &mut core_scheduler().timers;
93+
94+
// SAFETY: There's more than 1 slot
95+
let lowest_timer = timers
96+
.iter_mut()
97+
.min_by(|a, b| a.wakeup_time.cmp(&b.wakeup_time))
98+
.unwrap();
99+
100+
assert!(lowest_timer.wakeup_time != u64::MAX);
101+
102+
// TODO: Do we really want to do this here?
103+
match lowest_timer.source {
104+
#[cfg(feature = "net")]
105+
Source::Network => NETWORK_WAKER.lock().wake(),
106+
_ => {} // no-op, we always poll after a timer interrupt
107+
}
108+
109+
trace!("Cleared active timer {lowest_timer:?}");
110+
111+
lowest_timer.wakeup_time = u64::MAX;
112+
113+
// We may receive a timer interrupt earlier than expected
114+
// This appears to only be the case in QEMU, it seems like timer ticks
115+
// do not advance linearly there?
116+
// Either way, this means that QEMU *thinks* the time has passed, so it
117+
// probably has and knows better than we do.
118+
// We can cheat a bit and adjust all timers slightly based on this
119+
if lowest_timer.wakeup_time > crate::arch::processor::get_timer_ticks() {
120+
let offset = lowest_timer.wakeup_time - crate::arch::processor::get_timer_ticks();
121+
122+
for timer in timers.iter_mut() {
123+
if timer.wakeup_time != u64::MAX {
124+
timer.wakeup_time -= offset;
125+
}
126+
}
127+
}
128+
129+
// SAFETY: There's more than 1 slot
130+
let new_lowest_timer = timers.iter().map(|slot| slot.wakeup_time).min().unwrap();
131+
132+
if new_lowest_timer == u64::MAX {
133+
set_oneshot_timer(None);
134+
} else {
135+
set_oneshot_timer(Some(new_lowest_timer));
136+
}
137+
}

src/arch/x86_64/kernel/scheduler.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ use crate::arch::x86_64::mm::paging::{
1414
BasePageSize, PageSize, PageTableEntryFlags, PageTableEntryFlagsExt,
1515
};
1616
use crate::config::*;
17-
use crate::env;
1817
use crate::mm::{FrameAlloc, PageAlloc, PageRangeAllocator};
1918
use crate::scheduler::PerCoreSchedulerExt;
2019
use crate::scheduler::task::{Task, TaskFrame};
20+
use crate::{env, timer_interrupts};
2121

2222
#[repr(C, packed)]
2323
struct State {
@@ -318,6 +318,10 @@ impl TaskFrame for Task {
318318

319319
extern "x86-interrupt" fn timer_handler(_stack_frame: interrupts::ExceptionStackFrame) {
320320
increment_irq_counter(apic::TIMER_INTERRUPT_NUMBER);
321+
322+
debug!("Handle timer interrupt");
323+
timer_interrupts::clear_active_and_set_next();
324+
321325
core_scheduler().handle_waiting_tasks();
322326
apic::eoi();
323327
core_scheduler().reschedule();

src/drivers/net/gem.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use crate::drivers::net::{NetworkDriver, mtu};
3232
#[cfg(feature = "pci")]
3333
use crate::drivers::pci as hardware;
3434
use crate::drivers::{Driver, InterruptLine};
35+
use crate::executor::network::NETWORK_WAKER;
3536
use crate::mm::device_alloc::DeviceAlloc;
3637
use crate::{BasePageSize, PageSize};
3738

@@ -276,6 +277,9 @@ impl NetworkDriver for GEMDriver {
276277

277278
fn handle_interrupt(&mut self) {
278279
self.tx_fields.handle_interrupt();
280+
281+
trace!("Waking network waker");
282+
NETWORK_WAKER.lock().wake();
279283
}
280284
}
281285

src/drivers/net/loopback.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use smoltcp::time::Instant;
88

99
use crate::drivers::net::NetworkDriver;
1010
use crate::drivers::{Driver, InterruptLine};
11+
use crate::executor::network::NETWORK_WAKER;
1112
use crate::mm::device_alloc::DeviceAlloc;
1213

1314
pub(crate) struct LoopbackDriver {
@@ -122,7 +123,8 @@ impl NetworkDriver for LoopbackDriver {
122123
}
123124

124125
fn handle_interrupt(&mut self) {
125-
// no-op
126+
trace!("Waking network waker");
127+
NETWORK_WAKER.lock().wake();
126128
}
127129
}
128130

src/drivers/net/rtl8139.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::drivers::Driver;
2121
use crate::drivers::error::DriverError;
2222
use crate::drivers::net::{NetworkDriver, mtu};
2323
use crate::drivers::pci::PciDevice;
24+
use crate::executor::network::NETWORK_WAKER;
2425
use crate::mm::device_alloc::DeviceAlloc;
2526

2627
/// size of the receive buffer
@@ -687,6 +688,9 @@ impl NetworkDriver for RTL8139Driver {
687688
self.regs.as_mut_ptr().isr().write(le16::from(
688689
isr_contents & (ISR_RXOVW | ISR_TER | ISR_RER | ISR_TOK | ISR_ROK),
689690
));
691+
692+
trace!("Waking network waker");
693+
NETWORK_WAKER.lock().wake();
690694
}
691695
}
692696

src/drivers/net/virtio/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use crate::drivers::virtio::virtqueue::{
4242
AvailBufferToken, BufferElem, BufferType, UsedBufferToken, VirtQueue, Virtq,
4343
};
4444
use crate::drivers::{Driver, InterruptLine};
45+
use crate::executor::network::NETWORK_WAKER;
4546
use crate::mm::device_alloc::DeviceAlloc;
4647

4748
/// A wrapper struct for the raw configuration structure.
@@ -417,6 +418,9 @@ impl NetworkDriver for VirtioNetDriver<Init> {
417418
}
418419

419420
self.isr_stat.acknowledge();
421+
422+
trace!("Waking network waker");
423+
NETWORK_WAKER.lock().wake();
420424
}
421425
}
422426

0 commit comments

Comments
 (0)