1use crate::cpu::{cpu::js, global_pointers::acpi_enabled, ioapic};
4use std::sync::{Mutex, MutexGuard};
5
6const APIC_LOG_VERBOSE: bool = false;
7
8const APIC_TIMER_FREQ: f64 = 1.0 * 1000.0 * 1000.0;
10
11const APIC_TIMER_MODE_MASK: u32 = 3 << 17;
12
13const APIC_TIMER_MODE_ONE_SHOT: u32 = 0;
14const APIC_TIMER_MODE_PERIODIC: u32 = 1 << 17;
15
16const _APIC_TIMER_MODE_TSC: u32 = 2 << 17;
17
18const DELIVERY_MODES: [&str; 8] = [
19 "Fixed (0)",
20 "Lowest Prio (1)",
21 "SMI (2)",
22 "Reserved (3)",
23 "NMI (4)",
24 "INIT (5)",
25 "Reserved (6)",
26 "ExtINT (7)",
27];
28
29const DESTINATION_MODES: [&str; 2] = ["physical", "logical"];
30
31const IOAPIC_CONFIG_MASKED: u32 = 0x10000;
32
33const IOAPIC_DELIVERY_INIT: u8 = 5;
34const IOAPIC_DELIVERY_NMI: u8 = 4;
35const IOAPIC_DELIVERY_FIXED: u8 = 0;
36
37#[allow(dead_code)]
39const APIC_STRUCT_SIZE: usize = 4 * 46;
40
41const _: () = assert!(std::mem::offset_of!(Apic, timer_last_tick) == 6 * 4);
43const _: () = assert!(std::mem::offset_of!(Apic, lvt_timer) == 8 * 4);
44const _: () = assert!(std::mem::offset_of!(Apic, lvt_perf_counter) == 9 * 4);
45const _: () = assert!(std::mem::offset_of!(Apic, icr0) == 14 * 4);
46const _: () = assert!(std::mem::offset_of!(Apic, icr1) == 15 * 4);
47const _: () = assert!(std::mem::offset_of!(Apic, irr) == 16 * 4);
48const _: () = assert!(std::mem::offset_of!(Apic, isr) == 24 * 4);
49const _: () = assert!(std::mem::offset_of!(Apic, tmr) == 32 * 4);
50const _: () = assert!(std::mem::offset_of!(Apic, spurious_vector) == 40 * 4);
51const _: () = assert!(std::mem::offset_of!(Apic, lvt_thermal_sensor) == 45 * 4);
52const _: () = assert!(std::mem::size_of::<Apic>() == APIC_STRUCT_SIZE);
53#[repr(C)]
54pub struct Apic {
55 apic_id: u32,
56 timer_divider: u32,
57 timer_divider_shift: u32,
58 timer_initial_count: u32,
59 timer_current_count: u32,
60 timer_last_tick: f64,
61 lvt_timer: u32,
62 lvt_perf_counter: u32,
63 lvt_int0: u32,
64 lvt_int1: u32,
65 lvt_error: u32,
66 tpr: u32,
67 icr0: u32,
68 icr1: u32,
69 irr: [u32; 8],
70 isr: [u32; 8],
71 tmr: [u32; 8],
72 spurious_vector: u32,
73 destination_format: u32,
74 local_destination: u32,
75 error: u32,
76 read_error: u32,
77 lvt_thermal_sensor: u32,
78}
79
80static APIC: Mutex<Apic> = Mutex::new(Apic {
81 apic_id: 0,
82 timer_divider: 0,
83 timer_divider_shift: 1,
84 timer_initial_count: 0,
85 timer_current_count: 0,
86 timer_last_tick: 0.0,
87 lvt_timer: IOAPIC_CONFIG_MASKED,
88 lvt_thermal_sensor: IOAPIC_CONFIG_MASKED,
89 lvt_perf_counter: IOAPIC_CONFIG_MASKED,
90 lvt_int0: IOAPIC_CONFIG_MASKED,
91 lvt_int1: IOAPIC_CONFIG_MASKED,
92 lvt_error: IOAPIC_CONFIG_MASKED,
93 tpr: 0,
94 icr0: 0,
95 icr1: 0,
96 irr: [0; 8],
97 isr: [0; 8],
98 tmr: [0; 8],
99 spurious_vector: 0xFE,
100 destination_format: !0,
101 local_destination: 0,
102 error: 0,
103 read_error: 0,
104});
105
106pub fn get_apic() -> MutexGuard<'static, Apic> {
107 APIC.try_lock().unwrap()
108}
109
110#[no_mangle]
111pub fn get_apic_addr() -> u32 {
112 &raw mut *get_apic() as u32
113}
114
115pub fn read32(addr: u32) -> u32 {
116 if unsafe { !*acpi_enabled } {
117 return 0;
118 }
119 read32_internal(&mut get_apic(), addr)
120}
121
122fn read32_internal(apic: &mut Apic, addr: u32) -> u32 {
123 match addr {
124 0x20 => {
125 dbg_log!("APIC read id");
126 apic.apic_id
127 }
128
129 0x30 => {
130 dbg_log!("APIC read version");
132 0x50014
133 }
134
135 0x80 => {
136 if APIC_LOG_VERBOSE {
137 dbg_log!("APIC read tpr");
138 }
139 apic.tpr
140 }
141
142 0xB0 => {
143 if APIC_LOG_VERBOSE {
145 dbg_log!("APIC read eoi register");
146 }
147 0
148 }
149
150 0xD0 => {
151 dbg_log!("Read local destination");
152 apic.local_destination
153 }
154
155 0xE0 => {
156 dbg_log!("Read destination format");
157 apic.destination_format
158 }
159
160 0xF0 => apic.spurious_vector,
161
162 0x100 | 0x110 | 0x120 | 0x130 | 0x140 | 0x150 | 0x160 | 0x170 => {
163 let index = ((addr - 0x100) >> 4) as usize;
164 dbg_log!("Read isr {}: {:08x}", index, apic.isr[index] as u32);
165 apic.isr[index]
166 }
167
168 0x180 | 0x190 | 0x1A0 | 0x1B0 | 0x1C0 | 0x1D0 | 0x1E0 | 0x1F0 => {
169 let index = ((addr - 0x180) >> 4) as usize;
170 dbg_log!("Read tmr {}: {:08x}", index, apic.tmr[index] as u32);
171 apic.tmr[index]
172 }
173
174 0x200 | 0x210 | 0x220 | 0x230 | 0x240 | 0x250 | 0x260 | 0x270 => {
175 let index = ((addr - 0x200) >> 4) as usize;
176 dbg_log!("Read irr {}: {:08x}", index, apic.irr[index] as u32);
177 apic.irr[index]
178 }
179
180 0x280 => {
181 dbg_log!("Read error: {:08x}", apic.read_error);
182 apic.read_error
183 }
184
185 0x300 => {
186 if APIC_LOG_VERBOSE {
187 dbg_log!("APIC read icr0");
188 }
189 apic.icr0
190 }
191
192 0x310 => {
193 dbg_log!("APIC read icr1");
194 apic.icr1
195 }
196
197 0x320 => {
198 if APIC_LOG_VERBOSE {
199 dbg_log!("read timer lvt");
200 }
201 apic.lvt_timer
202 }
203
204 0x330 => {
205 dbg_log!("read lvt thermal sensor");
206 apic.lvt_thermal_sensor
207 }
208
209 0x340 => {
210 dbg_log!("read lvt perf counter");
211 apic.lvt_perf_counter
212 }
213
214 0x350 => {
215 dbg_log!("read lvt int0");
216 apic.lvt_int0
217 }
218
219 0x360 => {
220 dbg_log!("read lvt int1");
221 apic.lvt_int1
222 }
223
224 0x370 => {
225 dbg_log!("read lvt error");
226 apic.lvt_error
227 }
228
229 0x3E0 => {
230 dbg_log!("read timer divider");
232 apic.timer_divider
233 }
234
235 0x380 => {
236 dbg_log!("read timer initial count");
237 apic.timer_initial_count
238 }
239
240 0x390 => {
241 let now = unsafe { js::microtick() };
242 if apic.timer_last_tick > now {
243 dbg_log!("warning: APIC last_tick is in the future, resetting");
245 apic.timer_last_tick = now;
246 }
247 let diff = now - apic.timer_last_tick;
248 let diff_in_ticks = diff * APIC_TIMER_FREQ / (1 << apic.timer_divider_shift) as f64;
249 dbg_assert!(diff_in_ticks >= 0.0);
250 let diff_in_ticks = diff_in_ticks as u64;
251 let result = if diff_in_ticks < apic.timer_initial_count as u64 {
252 apic.timer_initial_count - diff_in_ticks as u32
253 } else {
254 let mode = apic.lvt_timer & APIC_TIMER_MODE_MASK;
255 if mode == APIC_TIMER_MODE_PERIODIC {
256 apic.timer_initial_count
257 - (diff_in_ticks % (apic.timer_initial_count as u64 + 1)) as u32
258 } else if mode == APIC_TIMER_MODE_ONE_SHOT {
259 0
260 } else {
261 dbg_assert!(false, "apic unimplemented timer mode: {:x}", mode);
262 0
263 }
264 };
265 if APIC_LOG_VERBOSE {
266 dbg_log!("read timer current count: {}", result);
267 }
268 result
269 }
270
271 _ => {
272 dbg_log!("APIC read {:x}", addr);
273 dbg_assert!(false);
274 0
275 }
276 }
277}
278
279pub fn write32(addr: u32, value: u32) {
280 if unsafe { !*acpi_enabled } {
281 return;
282 }
283 write32_internal(&mut get_apic(), addr, value)
284}
285
286fn write32_internal(apic: &mut Apic, addr: u32, value: u32) {
287 match addr {
288 0x20 => {
289 dbg_log!("APIC write id: {:08x}", value >> 8);
290 apic.apic_id = value;
291 }
292
293 0x30 => {
294 dbg_log!("APIC write version: {:08x}, ignored", value);
296 }
297
298 0x80 => {
299 if APIC_LOG_VERBOSE {
300 dbg_log!("Set tpr: {:02x}", value & 0xFF);
301 }
302 apic.tpr = value & 0xFF;
303 }
304
305 0xB0 => {
306 if let Some(highest_isr) = highest_isr(apic) {
307 if APIC_LOG_VERBOSE {
308 dbg_log!("eoi: {:08x} for vector {:x}", value, highest_isr);
309 }
310 register_clear_bit(&mut apic.isr, highest_isr);
311 if register_get_bit(&apic.tmr, highest_isr) {
312 ioapic::remote_eoi(apic, highest_isr);
314 }
315 } else {
316 dbg_log!("Bad eoi: No isr set");
317 }
318 }
319
320 0xD0 => {
321 dbg_log!("Set local destination: {:08x}", value);
322 apic.local_destination = value & 0xFF000000;
323 }
324
325 0xE0 => {
326 dbg_log!("Set destination format: {:08x}", value);
327 apic.destination_format = value | 0xFFFFFF;
328 }
329
330 0xF0 => {
331 dbg_log!("Set spurious vector: {:08x}", value);
332 apic.spurious_vector = value;
333 }
334
335 0x280 => {
336 dbg_log!("Write error: {:08x}", value);
338 apic.read_error = apic.error;
339 apic.error = 0;
340 }
341
342 0x300 => {
343 let vector = (value & 0xFF) as u8;
344 let delivery_mode = ((value >> 8) & 7) as u8;
345 let destination_mode = ((value >> 11) & 1) as u8;
346 let is_level = value & ioapic::IOAPIC_CONFIG_TRIGGER_MODE_LEVEL
347 == ioapic::IOAPIC_CONFIG_TRIGGER_MODE_LEVEL;
348 let destination_shorthand = (value >> 18) & 3;
349 let destination = (apic.icr1 >> 24) as u8;
350 dbg_log!(
351 "APIC write icr0: {:08x} vector={:02x} destination_mode={} delivery_mode={} destination_shorthand={}",
352 value,
353 vector,
354 DESTINATION_MODES[destination_mode as usize],
355 DELIVERY_MODES[delivery_mode as usize],
356 ["no", "self", "all with self", "all without self"][destination_shorthand as usize]
357 );
358
359 let mut value = value;
360 value &= !(1 << 12);
361 apic.icr0 = value;
362
363 if destination_shorthand == 0 {
364 route(
366 apic,
367 vector,
368 delivery_mode,
369 is_level,
370 destination,
371 destination_mode,
372 );
373 } else if destination_shorthand == 1 {
374 deliver(apic, vector, IOAPIC_DELIVERY_FIXED, is_level);
376 } else if destination_shorthand == 2 {
377 deliver(apic, vector, delivery_mode, is_level);
379 } else if destination_shorthand == 3 {
380 } else {
382 dbg_assert!(false);
383 }
384 }
385
386 0x310 => {
387 dbg_log!("APIC write icr1: {:08x}", value);
388 apic.icr1 = value;
389 }
390
391 0x320 => {
392 if APIC_LOG_VERBOSE {
393 dbg_log!("timer lvt: {:08x}", value);
394 }
395 apic.lvt_timer = value;
397 }
398
399 0x330 => {
400 dbg_log!("lvt thermal sensor: {:08x}", value);
401 apic.lvt_thermal_sensor = value;
402 }
403
404 0x340 => {
405 dbg_log!("lvt perf counter: {:08x}", value);
406 apic.lvt_perf_counter = value;
407 }
408
409 0x350 => {
410 dbg_log!("lvt int0: {:08x}", value);
411 apic.lvt_int0 = value;
412 }
413
414 0x360 => {
415 dbg_log!("lvt int1: {:08x}", value);
416 apic.lvt_int1 = value;
417 }
418
419 0x370 => {
420 dbg_log!("lvt error: {:08x}", value);
421 apic.lvt_error = value;
422 }
423
424 0x3E0 => {
425 apic.timer_divider = value;
426
427 let divide_shift = (value & 0b11) | ((value & 0b1000) >> 1);
428 apic.timer_divider_shift = if divide_shift == 0b111 {
429 0
430 } else {
431 divide_shift + 1
432 };
433 dbg_log!(
434 "APIC timer divider: {:08x} shift={} tick={:.6}ms",
435 apic.timer_divider,
436 apic.timer_divider_shift,
437 (1 << apic.timer_divider_shift) as f64 / APIC_TIMER_FREQ
438 );
439 }
440
441 0x380 => {
442 if APIC_LOG_VERBOSE {
443 dbg_log!(
444 "APIC timer initial: {} next_interrupt={:.2}ms",
445 value,
446 value as f64 * (1 << apic.timer_divider_shift) as f64 / APIC_TIMER_FREQ,
447 );
448 }
449 apic.timer_initial_count = value;
450 apic.timer_current_count = value;
451 apic.timer_last_tick = unsafe { js::microtick() };
452 }
453
454 0x390 => {
455 dbg_log!("write timer current: {:08x}", value);
456 dbg_assert!(false, "read-only register");
457 }
458
459 _ => {
460 dbg_log!("APIC write32 {:x} <- {:08x}", addr, value);
461 dbg_assert!(false);
462 }
463 }
464}
465
466#[no_mangle]
467pub fn apic_timer(now: f64) -> f64 {
468 timer(&mut get_apic(), now)
469}
470
471fn timer(apic: &mut Apic, now: f64) -> f64 {
472 if apic.timer_initial_count == 0 || apic.timer_current_count == 0 {
473 return 100.0;
474 }
475
476 if apic.timer_last_tick > now {
477 dbg_log!("warning: APIC last_tick is in the future, resetting");
479 apic.timer_last_tick = now;
480 }
481
482 let diff = now - apic.timer_last_tick;
483 let diff_in_ticks = diff * APIC_TIMER_FREQ / (1 << apic.timer_divider_shift) as f64;
484 dbg_assert!(diff_in_ticks >= 0.0);
485 let diff_in_ticks = diff_in_ticks as u64;
486
487 let time_per_interrupt =
488 apic.timer_initial_count as f64 * (1 << apic.timer_divider_shift) as f64 / APIC_TIMER_FREQ;
489
490 if diff_in_ticks >= apic.timer_initial_count as u64 {
491 let mode = apic.lvt_timer & APIC_TIMER_MODE_MASK;
492 if mode == APIC_TIMER_MODE_PERIODIC {
493 if APIC_LOG_VERBOSE {
494 dbg_log!("APIC timer periodic interrupt");
495 }
496
497 if diff_in_ticks >= 2 * apic.timer_initial_count as u64 {
498 dbg_log!(
499 "warning: APIC skipping {} interrupts initial={} ticks={} last_tick={:.1}ms now={:.1}ms d={:.1}ms",
500 diff_in_ticks / apic.timer_initial_count as u64 - 1,
501 apic.timer_initial_count,
502 diff_in_ticks,
503 apic.timer_last_tick,
504 now,
505 diff,
506 );
507 apic.timer_last_tick = now;
508 } else {
509 apic.timer_last_tick += time_per_interrupt;
510 dbg_assert!(apic.timer_last_tick <= now);
511 }
512 } else if mode == APIC_TIMER_MODE_ONE_SHOT {
513 if APIC_LOG_VERBOSE {
514 dbg_log!("APIC timer one shot end");
515 }
516 apic.timer_current_count = 0;
517 } else {
518 dbg_assert!(false, "apic unimplemented timer mode: {:x}", mode);
519 }
520
521 if apic.lvt_timer & IOAPIC_CONFIG_MASKED == 0 {
522 deliver(
523 apic,
524 (apic.lvt_timer & 0xFF) as u8,
525 IOAPIC_DELIVERY_FIXED,
526 false,
527 );
528 }
529 }
530
531 apic.timer_last_tick + time_per_interrupt - now
532}
533
534pub fn route(
535 apic: &mut Apic,
536 vector: u8,
537 mode: u8,
538 is_level: bool,
539 _destination: u8,
540 _destination_mode: u8,
541) {
542 deliver(apic, vector, mode, is_level);
544}
545
546fn deliver(apic: &mut Apic, vector: u8, mode: u8, is_level: bool) {
547 if APIC_LOG_VERBOSE {
548 dbg_log!("Deliver {:02x} mode={} level={}", vector, mode, is_level);
549 }
550
551 if mode == IOAPIC_DELIVERY_INIT {
552 return;
554 }
555
556 if mode == IOAPIC_DELIVERY_NMI {
557 return;
559 }
560
561 if vector < 0x10 || vector == 0xFF {
562 dbg_assert!(false, "TODO: Invalid vector: {:x}", vector);
563 }
564
565 if register_get_bit(&apic.irr, vector) {
566 dbg_log!("Not delivered: irr already set, vector={:02x}", vector);
567 return;
568 }
569
570 register_set_bit(&mut apic.irr, vector);
571
572 if is_level {
573 register_set_bit(&mut apic.tmr, vector);
574 } else {
575 register_clear_bit(&mut apic.tmr, vector);
576 }
577}
578
579fn highest_irr(apic: &mut Apic) -> Option<u8> {
580 let highest = register_get_highest_bit(&apic.irr);
581 if let Some(x) = highest {
582 dbg_assert!(x >= 0x10);
583 dbg_assert!(x != 0xFF);
584 }
585 highest
586}
587
588fn highest_isr(apic: &mut Apic) -> Option<u8> {
589 let highest = register_get_highest_bit(&apic.isr);
590 if let Some(x) = highest {
591 dbg_assert!(x >= 0x10);
592 dbg_assert!(x != 0xFF);
593 }
594 highest
595}
596
597pub fn acknowledge_irq() -> Option<u8> {
598 acknowledge_irq_internal(&mut get_apic())
599}
600
601fn acknowledge_irq_internal(apic: &mut Apic) -> Option<u8> {
602 let highest_irr = match highest_irr(apic) {
603 None => return None,
604 Some(x) => x,
605 };
606
607 if let Some(highest_isr) = highest_isr(apic) {
608 if highest_isr >= highest_irr {
609 if APIC_LOG_VERBOSE {
610 dbg_log!("Higher isr, isr={:x} irr={:x}", highest_isr, highest_irr);
611 }
612 return None;
613 }
614 }
615
616 if highest_irr & 0xF0 <= apic.tpr as u8 & 0xF0 {
617 if APIC_LOG_VERBOSE {
618 dbg_log!(
619 "Higher tpr, tpr={:x} irr={:x}",
620 apic.tpr & 0xF0,
621 highest_irr
622 );
623 }
624 return None;
625 }
626
627 register_clear_bit(&mut apic.irr, highest_irr);
628 register_set_bit(&mut apic.isr, highest_irr);
629
630 if APIC_LOG_VERBOSE {
631 dbg_log!("Calling vector {:x}", highest_irr);
632 }
633
634 dbg_assert!(acknowledge_irq_internal(apic).is_none());
635
636 Some(highest_irr)
637}
638
639fn register_get_bit(v: &[u32; 8], bit: u8) -> bool {
641 v[(bit >> 5) as usize] & 1 << (bit & 31) != 0
642}
643
644fn register_set_bit(v: &mut [u32; 8], bit: u8) {
645 v[(bit >> 5) as usize] |= 1 << (bit & 31);
646}
647
648fn register_clear_bit(v: &mut [u32; 8], bit: u8) {
649 v[(bit >> 5) as usize] &= !(1 << (bit & 31));
650}
651
652fn register_get_highest_bit(v: &[u32; 8]) -> Option<u8> {
653 dbg_assert!(v.as_ptr().addr() & std::mem::align_of::<u64>() - 1 == 0);
654 let v: &[u64; 4] = unsafe { std::mem::transmute(v) };
655 for i in (0..4).rev() {
656 let word = v[i];
657
658 if word != 0 {
659 return Some(word.ilog2() as u8 | (i as u8) << 6);
660 }
661 }
662
663 None
664}
665
666pub fn restore_state_bytes(bytes: &[u8]) -> Result<(), String> {
668 if bytes.len() != std::mem::size_of::<Apic>() {
669 return Err(format!(
670 "APIC state length {} != expected {}",
671 bytes.len(),
672 std::mem::size_of::<Apic>()
673 ));
674 }
675 if cfg!(target_endian = "big") {
676 return Err("native APIC restore requires a little-endian host".to_owned());
677 }
678 let mut apic = get_apic();
679 let target = unsafe {
680 std::slice::from_raw_parts_mut(
681 (&mut *apic as *mut Apic).cast::<u8>(),
682 std::mem::size_of::<Apic>(),
683 )
684 };
685 target.copy_from_slice(bytes);
686 Ok(())
687}