1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2024.
45use core::fmt::Write;
6use core::ptr;
7use core::{arch::asm, panic::PanicInfo};
89use kernel::debug;
1011use x86_q35::serial::{BlockingSerialPort, COM1_BASE};
1213use crate::{CHIP, PROCESSES, PROCESS_PRINTER};
1415/// Exists QEMU
16///
17/// This function requires the `-device isa-debug-exit,iobase=0xf4,iosize=0x04`
18/// device enabled.
19fn exit_qemu() -> ! {
20unsafe {
21asm!(
22"
23 mov dx, 0xf4
24 mov al, 0x01
25 out dx,al
26 "
27);
28 }
2930// We prefer the infinite loop to the `options(noreturn)` for `asm!` as
31 // the required `isa-debug-exit` device might be missing in which case
32 // the execution does not stop and generates undefined behaviour.
33let mut com1 = unsafe { BlockingSerialPort::new(COM1_BASE) };
34let _ = 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));
4243// We use the `htl` instruction in the infinite loop to prevent high CPU usage
44 // if QEMU did not exit.
45loop {
46unsafe { asm!("hlt") }
47 }
48}
4950/// Panic handler.
51#[cfg(not(test))]
52#[panic_handler]
53unsafe fn panic_handler(pi: &PanicInfo) -> ! {
54let mut com1 = BlockingSerialPort::new(COM1_BASE);
5556 debug::panic_print(
57&mut com1,
58 pi,
59&x86::support::nop,
60&*ptr::addr_of!(PROCESSES),
61&*ptr::addr_of!(CHIP),
62&*ptr::addr_of!(PROCESS_PRINTER),
63 );
6465 exit_qemu();
66}