rustubs/arch/x86_64/interrupt/
pit.rs1use crate::machine::device_io::IOPort;
5use crate::machine::time;
6use crate::proc::sched::SET_NEED_RESCHEDULE;
7use crate::proc::sync::bellringer::BellRinger;
8use crate::proc::sync::IRQHandlerEpilogue;
9use crate::proc::task::Task;
10pub struct PIT {}
12
13impl PIT {
14 const CTRL_PORT: IOPort = IOPort::new(0x43);
15 const DATA_PORT: IOPort = IOPort::new(0x40);
16 const PIT_BASE_NS: u64 = 838;
18 pub fn set_interval(us: u64) -> u64 {
20 let mut divider =
21 (us * 1000 + Self::PIT_BASE_NS / 2) / Self::PIT_BASE_NS;
22 if divider == 0 {
23 panic!("how on earth can you make a zero divider?")
24 }
25 if divider >= 65535 {
26 divider = 65535;
27 }
28 Self::CTRL_PORT.outb(0x34);
30 Self::DATA_PORT.outb((divider & 0xff) as u8);
31 Self::DATA_PORT.outb(((divider & 0xff00) >> 8) as u8);
32 divider * Self::PIT_BASE_NS
33 }
34}
35
36impl IRQHandlerEpilogue for PIT {
37 unsafe fn do_prologue() {
38 time::tick();
42 let _task = Task::current();
43 if _task.is_none() {
44 return;
45 }
46 let _ = SET_NEED_RESCHEDULE();
47 }
48 unsafe fn do_epilogue() { BellRinger::check_all(); }
49}