mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 22:37:49 +00:00
Make exit_qemu safe
This commit is contained in:
@@ -185,15 +185,17 @@ pub enum QemuExitCode {
|
||||
Failed = 0x11,
|
||||
}
|
||||
|
||||
pub unsafe fn exit_qemu(exit_code: QemuExitCode) {
|
||||
pub fn exit_qemu(exit_code: QemuExitCode) {
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
let mut port = Port::new(0xf4);
|
||||
port.write(exit_code as u32);
|
||||
unsafe {
|
||||
let mut port = Port::new(0xf4);
|
||||
port.write(exit_code as u32);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We mark the function as `unsafe` because it relies on the fact that a special QEMU device is attached to the I/O port with address `0xf4`. The function creates a new [`Port`] at `0xf4`, which is the `iobase` of the `isa-debug-exit` device. Then it writes the the passed exit code to the port. We use `u32` because we specified the `iosize` of the `isa-debug-exit` device as 4 bytes.
|
||||
The function creates a new [`Port`] at `0xf4`, which is the `iobase` of the `isa-debug-exit` device. Then it writes the the passed exit code to the port. We use `u32` because we specified the `iosize` of the `isa-debug-exit` device as 4 bytes. Both operations are unsafe, because writing to an I/O port can generally result in arbitrary behavior.
|
||||
|
||||
For specifying the exit status, we create a `QemuExitCode` enum. The idea is to exit with the success exit code if all tests succeeded and with the failure exit code otherwise. The enum is marked as `#[repr(u32)]` to represent each variant by an `u32` integer. We use exit code `0x10` for success and `0x11` for failure. The actual exit codes do not matter much, as long as they don't clash with the default exit codes of QEMU. For example, using exit code `0` for success is not a good idea because it becomes `(0 << 1) | 1 = 1` after the transformation, which is the default exit code when QEMU failed to run. So we could not differentiate a QEMU error from a successfull test run.
|
||||
|
||||
@@ -206,7 +208,7 @@ fn test_runner(tests: &[&dyn Fn()]) {
|
||||
test();
|
||||
}
|
||||
/// new
|
||||
unsafe { exit_qemu(QemuExitCode::Success) };
|
||||
exit_qemu(QemuExitCode::Success);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -294,7 +296,7 @@ lazy_static! {
|
||||
|
||||
Like with the [VGA text buffer][vga lazy-static], we use `lazy_static` and a spinlock to create a `static` writer instance. By using `lazy_static` we can ensure that the `init` method is called exactly once on its first use.
|
||||
|
||||
Like the `isa-debug-exit` device, the UART is programmed using port I/O. Since the UART is more complex, it uses multiple I/O ports for programming different device registers. The `SerialPort::new` function expects the address of the first I/O port of the UART as argument, from which it can calculate the addresses of all needed ports. We're passing the port address `0x3F8`, which is the standard port number for the first serial interface.
|
||||
Like the `isa-debug-exit` device, the UART is programmed using port I/O. Since the UART is more complex, it uses multiple I/O ports for programming different device registers. The unsafe `SerialPort::new` function expects the address of the first I/O port of the UART as argument, from which it can calculate the addresses of all needed ports. We're passing the port address `0x3F8`, which is the standard port number for the first serial interface.
|
||||
|
||||
[vga lazy-static]: ./second-edition/posts/03-vga-text-buffer/index.md#lazy-statics
|
||||
|
||||
@@ -408,7 +410,7 @@ fn panic(info: &PanicInfo) -> ! {
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
serial_println!("[failed]\n");
|
||||
serial_println!("Error: {}\n", info);
|
||||
unsafe { exit_qemu(QemuExitCode::Failed); }
|
||||
exit_qemu(QemuExitCode::Failed);
|
||||
loop {}
|
||||
}
|
||||
```
|
||||
@@ -594,15 +596,13 @@ pub fn test_runner(tests: &[&dyn Fn()]) {
|
||||
for test in tests {
|
||||
test();
|
||||
}
|
||||
unsafe { exit_qemu(QemuExitCode::Success) };
|
||||
exit_qemu(QemuExitCode::Success);
|
||||
}
|
||||
|
||||
pub fn test_panic_handler(info: &PanicInfo) -> ! {
|
||||
serial_println!("[failed]\n");
|
||||
serial_println!("Error: {}\n", info);
|
||||
unsafe {
|
||||
exit_qemu(QemuExitCode::Failed);
|
||||
}
|
||||
exit_qemu(QemuExitCode::Failed);
|
||||
loop {}
|
||||
}
|
||||
|
||||
@@ -639,11 +639,13 @@ pub enum QemuExitCode {
|
||||
Failed = 0x11,
|
||||
}
|
||||
|
||||
pub unsafe fn exit_qemu(exit_code: QemuExitCode) {
|
||||
pub fn exit_qemu(exit_code: QemuExitCode) {
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
let mut port = Port::new(0xf4);
|
||||
port.write(exit_code as u32);
|
||||
unsafe {
|
||||
let mut port = Port::new(0xf4);
|
||||
port.write(exit_code as u32);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user