1use core::fmt::Write;
6use core::ptr;
7use core::{arch::asm, panic::PanicInfo};
8
9use kernel::debug;
10
11use x86_q35::serial::{BlockingSerialPort, COM1_BASE};
12
13use crate::{CHIP, PROCESSES, PROCESS_PRINTER};
14
15fn exit_qemu() -> ! {
20    unsafe {
21        asm!(
22            "
23    mov dx, 0xf4
24    mov al, 0x01
25    out dx,al
26            "
27        );
28    }
29
30    let mut com1 = unsafe { BlockingSerialPort::new(COM1_BASE) };
34    let _ = com1.write_fmt(format_args!(
35        "BUG:  QEMU did not exit.\
36        \r\n      The isa-debug-exit device is missing or is at a wrong address.\
37        \r\n      Please make sure the QEMU command line uses\
38        \r\n      the `-device isa-debug-exit,iobase=0xf4,iosize=0x04` argument.\
39        \r\nHINT: Use `killall qemu-system-i386` or the Task Manager to stop.\
40        \r\n"
41    ));
42
43    loop {
46        unsafe { asm!("hlt") }
47    }
48}
49
50#[cfg(not(test))]
52#[panic_handler]
53unsafe fn panic_handler(pi: &PanicInfo) -> ! {
54    let mut com1 = BlockingSerialPort::new(COM1_BASE);
55
56    debug::panic_print(
57        &mut com1,
58        pi,
59        &x86::support::nop,
60        PROCESSES.unwrap().as_slice(),
61        &*ptr::addr_of!(CHIP),
62        &*ptr::addr_of!(PROCESS_PRINTER),
63    );
64
65    exit_qemu();
66}