diff --git a/bootloader/rustsbi-qemu.bin b/bootloader/rustsbi-qemu.bin index ddbf336a..d74249e8 100755 Binary files a/bootloader/rustsbi-qemu.bin and b/bootloader/rustsbi-qemu.bin differ diff --git a/os/src/lang_items.rs b/os/src/lang_items.rs index db902c35..9a9a2f5c 100644 --- a/os/src/lang_items.rs +++ b/os/src/lang_items.rs @@ -1,6 +1,7 @@ //! The panic handler -use crate::sbi::shutdown; +//use crate::sbi::shutdown; +use crate::qemu_exit::{QEMUExit,QEMU_EXIT_HANDLE}; use core::panic::PanicInfo; #[panic_handler] @@ -15,5 +16,7 @@ fn panic(info: &PanicInfo) -> ! { } else { println!("[kernel] Panicked: {}", info.message().unwrap()); } - shutdown() + //shutdown() + // QEMU_EXIT_HANDLE.exit(13) + QEMU_EXIT_HANDLE.exit_success() } diff --git a/os/src/main.rs b/os/src/main.rs index fcb396cc..4451f83c 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -18,7 +18,9 @@ use core::arch::global_asm; #[macro_use] mod console; mod lang_items; +mod qemu_exit; mod sbi; +use crate::qemu_exit::{QEMUExit, QEMU_EXIT_HANDLE}; global_asm!(include_str!("entry.asm")); @@ -35,26 +37,29 @@ pub fn clear_bss() { #[no_mangle] pub fn rust_main() -> ! { extern "C" { - fn stext(); // begin addr of text segment - fn etext(); // end addr of text segment - fn srodata(); // start addr of Read-Only data segment - fn erodata(); // end addr of Read-Only data ssegment - fn sdata(); // start addr of data segment - fn edata(); // end addr of data segment - fn sbss(); // start addr of BSS segment - fn ebss(); // end addr of BSS segment - fn boot_stack(); // stack bottom - fn boot_stack_top(); // stack top + fn stext(); // begin addr of text segment + fn etext(); // end addr of text segment + fn srodata(); // start addr of Read-Only data segment + fn erodata(); // end addr of Read-Only data ssegment + fn sdata(); // start addr of data segment + fn edata(); // end addr of data segment + fn sbss(); // start addr of BSS segment + fn ebss(); // end addr of BSS segment + fn boot_stack(); // stack bottom + fn boot_stack_top(); // stack top } clear_bss(); println!("Hello, world!"); println!(".text [{:#x}, {:#x})", stext as usize, etext as usize); - println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize); + println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize); println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize); println!( - "boot_stack [{:#x}, {:#x})", - boot_stack as usize, boot_stack_top as usize - ); + "boot_stack [{:#x}, {:#x})", + boot_stack as usize, boot_stack_top as usize + ); println!(".bss [{:#x}, {:#x})", sbss as usize, ebss as usize); - panic!("Shutdown machine!"); + + QEMU_EXIT_HANDLE.exit_success(); //need successful qemu exit + //QEMU_EXIT_HANDLE.exit_failure(); //need failed qemu exit + //panic!("Shutdown machine!"); } diff --git a/os/src/qemu_exit.rs b/os/src/qemu_exit.rs new file mode 100644 index 00000000..94a2ecb8 --- /dev/null +++ b/os/src/qemu_exit.rs @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Esteban Blanc + +//! RISCV64. + +use core::arch::asm; + +const EXIT_SUCCESS: u32 = 0x5555; // Equals `exit(0)`. + +const EXIT_FAILURE_FLAG: u32 = 0x3333; +const EXIT_FAILURE: u32 = exit_code_encode(1); // Equals `exit(1)`. +const EXIT_RESET: u32 = 0x7777; + +pub trait QEMUExit { + /// Exit with specified return code. + /// + /// Note: For `X86`, code is binary-OR'ed with `0x1` inside QEMU. + fn exit(&self, code: u32) -> !; + + /// Exit QEMU using `EXIT_SUCCESS`, aka `0`, if possible. + /// + /// Note: Not possible for `X86`. + fn exit_success(&self) -> !; + + /// Exit QEMU using `EXIT_FAILURE`, aka `1`. + fn exit_failure(&self) -> !; +} + + +/// RISCV64 configuration +pub struct RISCV64 { + /// Address of the sifive_test mapped device. + addr: u64, +} + +/// Encode the exit code using EXIT_FAILURE_FLAG. +const fn exit_code_encode(code: u32) -> u32 { + (code << 16) | EXIT_FAILURE_FLAG +} + +impl RISCV64 { + /// Create an instance. + pub const fn new(addr: u64) -> Self { + RISCV64 { addr } + } +} + +impl QEMUExit for RISCV64 { + /// Exit qemu with specified exit code. + fn exit(&self, code: u32) -> ! { + // If code is not a special value, we need to encode it with EXIT_FAILURE_FLAG. + let code_new = match code { + EXIT_SUCCESS | EXIT_FAILURE | EXIT_RESET => code, + _ => exit_code_encode(code), + }; + + unsafe { + asm!( + "sw {0}, 0({1})", + in(reg)code_new, in(reg)self.addr + ); + + // For the case that the QEMU exit attempt did not work, transition into an infinite + // loop. Calling `panic!()` here is unfeasible, since there is a good chance + // this function here is the last expression in the `panic!()` handler + // itself. This prevents a possible infinite loop. + loop { + asm!("wfi", options(nomem, nostack)); + } + } + } + + fn exit_success(&self) -> ! { + self.exit(EXIT_SUCCESS); + } + + fn exit_failure(&self) -> ! { + self.exit(EXIT_FAILURE); + } +} + +pub const QEMU_EXIT_HANDLE: RISCV64 = RISCV64::new(0x100000); \ No newline at end of file