Skip to main content

native_v86_core/cpu/
apic.rs

1// See Intel's System Programming Guide
2
3use crate::cpu::{cpu::js, global_pointers::acpi_enabled, ioapic};
4use std::sync::{Mutex, MutexGuard};
5
6const APIC_LOG_VERBOSE: bool = false;
7
8// should probably be kept in sync with TSC_RATE in cpu.rs
9const 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// keep in sync with cpu.js
38#[allow(dead_code)]
39const APIC_STRUCT_SIZE: usize = 4 * 46;
40
41// Note: JavaScript (cpu.get_state_apic) depens on this layout
42const _: () = 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            // version
131            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            // write-only (written by DSL)
144            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            // divider
231            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                // should only happen after restore_state
244                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            // version
295            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                    // Send eoi to all IO APICs
313                    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            // updated readable error register with real error
337            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                // no shorthand
365                route(
366                    apic,
367                    vector,
368                    delivery_mode,
369                    is_level,
370                    destination,
371                    destination_mode,
372                );
373            } else if destination_shorthand == 1 {
374                // self
375                deliver(apic, vector, IOAPIC_DELIVERY_FIXED, is_level);
376            } else if destination_shorthand == 2 {
377                // all including self
378                deliver(apic, vector, delivery_mode, is_level);
379            } else if destination_shorthand == 3 {
380                // all but self
381            } 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            // TODO: check if unmasking and if this should trigger an interrupt immediately
396            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        // should only happen after restore_state
478        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    // TODO
543    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        // TODO
553        return;
554    }
555
556    if mode == IOAPIC_DELIVERY_NMI {
557        // TODO
558        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
639// functions operating on 256-bit registers (for irr, isr, tmr)
640fn 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
666/// Restore the APIC state serialized by v86's `get_state_apic`.
667pub 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}