diff --git a/Cargo.toml b/Cargo.toml index 15b45f3..4dc861a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,9 @@ authors = ["Philipp Oppermann "] [lib] crate-type = ["staticlib"] +[features] +qemu_auto_exit = [] + [dependencies] bit_field = "0.7.0" rlibc = "1.0" diff --git a/Makefile b/Makefile index 75bc6f8..d47c279 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,10 @@ grub_cfg := $(boot_src)/grub.cfg assembly_source_files := $(wildcard $(boot_src)/*.asm) assembly_object_files := $(patsubst $(boot_src)/%.asm, \ build/arch/$(arch)/boot/%.o, $(assembly_source_files)) +qemu_opts := -cdrom $(iso) \ + -smp 2 \ + -device isa-debug-exit # enable shutdown inside the qemu +features := qemu_auto_exit ifeq ($(shell uname), Linux) prefix := @@ -27,7 +31,7 @@ clean: @rm -r build run: $(iso) - @qemu-system-$(arch) -cdrom $(iso) -smp 2 + @qemu-system-$(arch) $(qemu_opts) iso: $(iso) @@ -43,7 +47,7 @@ $(kernel): kernel $(rust_os) $(assembly_object_files) $(linker_script) $(assembly_object_files) $(rust_os) kernel: - @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) + @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) --features $(features) # compile assembly files build/arch/$(arch)/boot/%.o: $(boot_src)/%.asm diff --git a/src/arch/x86_64/cpu.rs b/src/arch/x86_64/cpu.rs index 1cd9f47..08307a2 100644 --- a/src/arch/x86_64/cpu.rs +++ b/src/arch/x86_64/cpu.rs @@ -1,4 +1,4 @@ -// Enable 'No-Execute' bit in page entry +/// Enable 'No-Execute' bit in page entry pub fn enable_nxe_bit() { use x86_64::registers::msr::{IA32_EFER, rdmsr, wrmsr}; @@ -11,11 +11,22 @@ pub fn enable_nxe_bit() { } } -// Enable write protection in kernel mode +/// Enable write protection in kernel mode pub fn enable_write_protect_bit() { use x86_64::registers::control_regs::{cr0, cr0_write, Cr0}; // The CR0 register is only allowed in kernel mode // But we are in kernel mode. So it's safe. unsafe { cr0_write(cr0() | Cr0::WRITE_PROTECT) }; +} + +/// Exit qemu +/// See: https://wiki.osdev.org/Shutdown +/// Must run qemu with `-device isa-debug-exit` +/// The error code is `value written to 0x501` *2 +1, so it should be odd +pub unsafe fn exit_in_qemu(error_code: u8) -> ! { + use x86_64::instructions::port::outb; + assert!(error_code & 1 == 1); + outb(0x501, (error_code - 1) / 2); + unreachable!() } \ No newline at end of file diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index eaf8d38..a6322a3 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -1,5 +1,5 @@ pub mod driver; -mod cpu; +pub mod cpu; pub fn init() { cpu::enable_nxe_bit(); diff --git a/src/lang.rs b/src/lang.rs index 9dfff44..936dec2 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -1,6 +1,7 @@ // Rust language features implementions use core; +use arch::cpu; #[lang = "eh_personality"] extern fn eh_personality() { @@ -11,5 +12,9 @@ extern fn eh_personality() { pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32) -> ! { println!("\n\nPANIC in {} at line {}:", file, line); println!(" {}", fmt); - loop{} -} \ No newline at end of file + if cfg!(feature = "qemu_auto_exit") { + unsafe{ cpu::exit_in_qemu(1) } + } else { + loop { } + } +}