diff --git a/kernel-rs/Makefile b/kernel-rs/Makefile index b4f1aed8..6485e460 100644 --- a/kernel-rs/Makefile +++ b/kernel-rs/Makefile @@ -11,12 +11,13 @@ endif project := bluesnow arch ?= x86 NASM := nasm -f elf -LD := ld -m elf_i386 -n --gc-sections +LD := ld -m elf_i386 -L ./ -n --gc-sections # QEMU := qemu-system-x86_64 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -gdb tcp::$(PORTG) -enable-kvm -monitor telnet:127.0.0.1:$(PORT),server,nowait QEMU := qemu-system-x86_64 -gdb tcp::$(PORTG) -enable-kvm -monitor telnet:127.0.0.1:$(PORT),server,nowait -kernel := build/kernel-$(arch).bin -iso := build/os-$(arch).iso +kerName := BlueSnow +kernel := build/$(kerName) +iso := $(kernel).iso DIRISO := build/isofiles target ?= $(arch)-$(project) @@ -30,11 +31,11 @@ asm_object := $(patsubst src/arch/$(arch)/%.asm, build/arch/$(arch)/%.o, $(asm_ KERNEL_RUN := $(QEMU) -curses -cdrom $(iso) MONITOR := sleep 0.5;\ telnet 127.0.0.1 $(PORT);\ - kill \`ps -x | grep gdb | head -n 2 | tail -n 1 | cut -d \ -f 1 \`;\ - kill \`ps -x | grep gdb | head -n 2 | tail -n 1 | cut -d \ -f 2 \` + kill \`ps -x | grep \"[g]db\" | cut -d \ -f 1 \`;\ + kill \`ps -x | grep \"[g]db\" | cut -d \ -f 2 \` GDB := gdb -q\ -ex \"set arch i386:x86-64\"\ - -ex \"file build/kernel-x86.bin\"\ + -ex \"file $(kernel)\"\ -ex \"target remote localhost:$(PORTG)\" \ -ex \"continue\" @@ -46,18 +47,28 @@ build/arch/$(arch)/%.o: src/arch/$(arch)/%.asm Makefile @echo "Compiling (ASM) $@..." $(kernel): $(rust_os) $(asm_object) $(linker_script) Makefile - @$(LD) -o $(kernel) -T $(linker_script) $(asm_object) $(rust_os) + @$(LD) -o $@ -T $(linker_script) $(asm_object) $(rust_os) $(iso): $(kernel) $(grub.cfg) Makefile @mkdir -p $(DIRISO)/boot/grub @cp $(grub.cfg) $(DIRISO)/boot/grub - @cp $(kernel) $(DIRISO)/boot/kernel.bin - @grub-mkrescue -o $(iso) $(DIRISO) 2>/dev/null + @cp $(kernel) $(DIRISO)/boot/$(kerName) + @grub-mkrescue -o $@ $(DIRISO) 2>/dev/null + +# $(kernel).img: $(kernel) +# @cp .clean.img $@ +# @sudo mount -oloop=/dev/loop0,offset=32256 $@ /mnt +# @sudo cp $(kernel) /mnt/boot/. +# @sudo umount /mnt run: $(iso) Makefile @tmux info >&- || { echo -e "\033[38;5;16m ~~ NOT IN A VALID TMUX SESSION ~~\033[0m" ; exit 1; } @tmux new-window 'tmux split-window -h "$(MONITOR)"; tmux split-window -fv "$(GDB)"; tmux select-pane -t 1; tmux resize-pane -x 80 -y 25; $(KERNEL_RUN)' - @# @$(QEMU) -curses -cdrom $(iso) + +# Run without try to do a compile +R: + @tmux info >&- || { echo -e "\033[38;5;16m ~~ NOT IN A VALID TMUX SESSION ~~\033[0m" ; exit 1; } + @tmux new-window 'tmux split-window -h "$(MONITOR)"; tmux split-window -fv "$(GDB)"; tmux select-pane -t 1; tmux resize-pane -x 80 -y 25; $(KERNEL_RUN)' clean: @cargo clean @@ -69,4 +80,4 @@ $(rust_os): $(target).json Makefile kernel: $(rust_os) iso: $(iso) -.PHONY: run clean kernel iso $(rust_os) +.PHONY: R run clean kernel iso $(rust_os) diff --git a/kernel-rs/src/acpi/dsdt.rs b/kernel-rs/src/acpi/dsdt.rs new file mode 100644 index 00000000..5943e757 --- /dev/null +++ b/kernel-rs/src/acpi/dsdt.rs @@ -0,0 +1,84 @@ +use super::{check_signature,ACPISDTHeader}; +use core::mem; +use cpuio; + +static mut DSDT: DSDT = DSDT { + valid: false, + dsdt: None, + s5_ptr: 0, + slp_typ_a: 0, + slp_typ_b: 0 +}; + +struct DSDT { + valid: bool, + dsdt: Option<*const ACPISDTHeader>, + s5_ptr: u32, + slp_typ_a: u16, + slp_typ_b: u16 +} + +impl DSDT { + fn init(&mut self, addr: u32) -> Result <(), &'static str> { + self.dsdt = Some(addr as *const ACPISDTHeader); + self.s5_ptr = self.find_s5(addr)?; + self.parse_s5(); + self.valid = true; + Ok(()) + } + + fn find_s5(&self, addr: u32) -> Result { + let dsdt_start = addr + mem::size_of::() as u32; + let dsdt_end = dsdt_start + unsafe {(*self.dsdt.unwrap()).length}; + for addr in dsdt_start..dsdt_end { + if check_signature(addr, "_S5_") { + if (check_signature(addr - 1, "\x08") || check_signature(addr - 2, "\x08\\")) && check_signature(addr + 4, "\x12") { + return Ok(addr); + } + } + } + Err("Can not find S5 section in DSDT") + } + + fn parse_s5(&mut self) { + let ptr = self.s5_ptr + 5; + let ptr = ((unsafe{*(ptr as *const u8)} & 0xC0) >> 6) + 2; + let ptr = if unsafe{*(ptr as *const u8)} == 0x0A { ptr + 1 } else { ptr };// Skip bytePrefix + self.slp_typ_a = (unsafe {*(ptr as *const u8)} as u16) << 10; + let ptr = ptr + 1; + let ptr = if unsafe{*(ptr as *const u8)} == 0x0A { ptr + 1 } else { ptr };// Skip bytePrefix + self.slp_typ_b = (unsafe {*(ptr as *const u8)} as u16) << 10; + } +} +fn is_init() -> Result <(), &'static str> { + match unsafe {DSDT.valid} { + true => Ok(()), + false => match unsafe {DSDT.dsdt} { + Some(_) => Err("Differentiated System Description Pointer (DSDP) is not valid"), + None => Err("Differentiated System Description Pointer (DSDP) is not initialized") + } + } +} + +/// ## Initialize Differentiated System Description Table (DSDT) +/// input param addr is contain in FADT +pub fn init(addr: u32) -> Result <(), &'static str> { + if ACPISDTHeader::valid(addr, "DSDT") { + return unsafe {DSDT.init(addr)}; + } + return Err("Can not find Differentiated System Description Table (DSDT)."); +} + +/// NOT COMPATIBLE WITH VIRTUALBOX +/// Send shutdown signal +/// outw(PM1a_CNT_BLK, SLP_TYPx | SLP_EN) +pub fn shutdown(pm1_cnt: [u16; 2]) -> Result <(), &'static str> { + is_init()?; + let slp_typ = unsafe{ DSDT.slp_typ_a } | (1 << 13); + cpuio::outw(pm1_cnt[0], slp_typ); + if pm1_cnt[1] != 0 { + let slp_typ = unsafe{ DSDT.slp_typ_b } | (1 << 13); + cpuio::outw(pm1_cnt[1], slp_typ); + } + Ok(()) +} diff --git a/kernel-rs/src/acpi/fadt.rs b/kernel-rs/src/acpi/fadt.rs new file mode 100644 index 00000000..99686934 --- /dev/null +++ b/kernel-rs/src/acpi/fadt.rs @@ -0,0 +1,143 @@ +use super::{ACPISDTHeader,ACPISDTIter}; +use cpuio; + +#[repr(C)] +#[derive(Debug)] +struct GenericAddressStructure { + addressspace: u8, + bitwidth: u8, + bitoffset: u8, + accesssize: u8, + noused: u32, + address: u64 +} + +#[repr(C)] +#[derive(Debug)] +struct FADT +{ + header: ACPISDTHeader, + firmwarectrl: u32, + dsdt: u32, + + // field used in acpi 1.0; no longer in use, for compatibility only + reserved: u8, + + preferredpowermanagementprofile: u8, + sci_interrupt: u16, + smi_commandport: u32, + acpi_enable: u8, + acpidisable: u8, + s4bios_req: u8, //no use + pstate_control: u8, //no use + pm1aeventblock: u32, //no use + pm1beventblock: u32, //no use + pm1acontrolblock: u32, + pm1bcontrolblock: u32, + pm2controlblock: u32, //no use + pmtimerblock: u32, //no use + gpe0block: u32, //no use + gpe1block: u32, //no use + pm1eventlength: u8, //no use + pm1controllength: u8, + pm2controllength: u8, //no use + pmtimerlength: u8, //no use + gpe0length: u8, //no use + gpe1length: u8, //no use + gpe1base: u8, //no use + cstatecontrol: u8, //no use + worstc2latency: u16, //no use + worstc3latency: u16, //no use + flushsize: u16, //no use + flushstride: u16, //no use + dutyoffset: u8, //no use + dutywidth: u8, //no use + dayalarm: u8, //no use + monthalarm: u8, //no use + century: u8, //no use + + // reserved in acpi 1.0; used since acpi 2.0+ + bootarchitectureflags: u16, + + reserved2: u8, + flags: u32, + + // 12 byte structure; see below for details + resetreg: GenericAddressStructure, + + resetvalue: u8, + reserved3: [u8; 3], + + // 64bit pointers - Available on ACPI 2.0+ + x_firmwarecontrol: u64, + x_dsdt: u64, + + x_pm1aeventblock: GenericAddressStructure, + x_pm1beventblock: GenericAddressStructure, + x_pm1acontrolblock: GenericAddressStructure, + x_pm1bcontrolblock: GenericAddressStructure, + x_pm2controlblock: GenericAddressStructure, + x_pmtimerblock: GenericAddressStructure, + x_gpe0block: GenericAddressStructure, + x_gpe1block: GenericAddressStructure, + +} + +static mut FADT: Option<*const FADT> = None; + +/// ## Initialize Fixed ACPI Description Table (FADT) +/// input param addr is contain in other ptr of rsdt +pub fn init(sdt_iter: ACPISDTIter) -> Result <(), &'static str> { + for sdt_ptr in sdt_iter { + if ACPISDTHeader::valid(sdt_ptr, "FACP") { // Where is "FADT"? Shut up is magic + let ptr = sdt_ptr as *const FADT; + unsafe {FADT = Some(ptr)}; + if !is_enable()? { // TODO do i have to check if enabled before init ??? + let smi_cmd = unsafe {(*ptr).smi_commandport} as u16; // TODO WHY DO I NEED THIS FUCKING CAST + let acpi_enable = unsafe {(*ptr).acpi_enable}; + cpuio::outb(smi_cmd, acpi_enable); // send acpi enable command + } + return Ok(()); + } + } + return Err("Can not find Fixed ACPI Description Table (FADT)."); +} + +fn is_init() -> Result <*const FADT, &'static str> { + match unsafe {FADT} { + Some(ptr) => Ok(ptr), + None => Err("Fixed ACPI Description Table (FADT) is not initialized") + } +} + +/// Return Dsdt address +/// FADT must have been initialized first +pub fn dsdtaddr() -> Result { + let ptr = is_init()?; + return Ok(unsafe {(*ptr).dsdt}); +} + +fn get_cnt(ptr: *const FADT) -> [u16; 2] { + [unsafe {(*ptr).pm1acontrolblock} as u16, unsafe {(*ptr).pm1bcontrolblock} as u16] // TODO WHY DO I NEED THIS FUCKING CAST +} + +/// Return true/false depending of acpi is enable +pub fn is_enable() -> Result { + let ptr = is_init()?; + let pm1_cnt = get_cnt(ptr); + if pm1_cnt[1] == 0 { + Ok(cpuio::inw(pm1_cnt[0]) & 0x1 == 0x1) + } else { + Ok(cpuio::inw(pm1_cnt[0]) & 0x1 == 0x1 || cpuio::inw(pm1_cnt[1]) & 0x1 == 0x1) + } +} + +/// Return a array with [pm1a, pm1b] +/// FADT must have been initialized first +pub fn get_controlblock() -> Result <[u16; 2], &'static str> { + if !is_enable()? { + Err("ACPI is not enabled") + } else { + Ok(get_cnt(is_init()?)) // TODO redondant call to is_init + } +} diff --git a/kernel-rs/src/acpi/mod.rs b/kernel-rs/src/acpi/mod.rs new file mode 100644 index 00000000..702e6f9c --- /dev/null +++ b/kernel-rs/src/acpi/mod.rs @@ -0,0 +1,145 @@ +mod rsdp; +mod rsdt; +mod xsdt; +mod fadt; +mod dsdt; + +use core; +use core::mem; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +struct ACPISDTHeader { + signature: [u8; 4], + length: u32, + revision: u8, + checksum: u8, + oemid: [u8; 6], + oemtableid: [u8; 8], + oemrevision: u32, + creatorid: u32, + creatorrevision: u32, +} + +impl ACPISDTHeader { + pub fn valid(addr: u32, signature: &str) -> bool { + if check_signature(addr, signature) { + let ptr_tmp = addr as *const ACPISDTHeader; + if check_checksum(addr, unsafe {(*ptr_tmp).length} as usize) { + return true; + } + } + return false; + } +} + +static mut ACPI: Acpi = Acpi { + valid: false, + v2: false +}; + +struct Acpi { + valid: bool, + v2: bool +} + +impl Acpi { + fn init(&mut self) -> Result <(), &'static str> { + self.v2 = rsdp::init()?; + if self.v2 { + // Xsdt Address: + // 64-bit physical address of the XSDT table. If you detect ACPI Version 2.0 you should use this table instead of RSDT even on x86, casting the address to uint32_t. + xsdt::init(rsdp::xsdtaddr()?)?; + fadt::init(xsdt::iter()?)?; + } else { + rsdt::init(rsdp::rsdtaddr()?)?; + fadt::init(rsdt::iter()?)?; + } + dsdt::init(fadt::dsdtaddr()?)?; + self.valid = true; + Ok(()) + } +} + +fn check_signature(addr: u32, id: &str) -> bool { + let signature = match core::str::from_utf8(unsafe {core::slice::from_raw_parts_mut(addr as *mut u8, id.len())}) { + Ok(y) => y, + Err(_) => return false, + }; + return signature == id; +} + +fn check_checksum(addr: u32, len: usize) -> bool { + let byte_array = unsafe {core::slice::from_raw_parts_mut(addr as *mut u8, len)}; + let mut sum: u32 = 0; + for byte in byte_array { + sum += *byte as u32; + } + return sum as u8 == 0; +} + +pub struct ACPISDTIter { + pos: usize, + width: usize, + sdt: u32, + len: usize +} + +impl ACPISDTIter { + fn new(acpi_sdt: Option<*const ACPISDTHeader>, ptr_len: usize) -> Result { + match acpi_sdt { + None => Err("There is no ACPI System Description Table (ACPISDTHeader) to iter on."), + Some(ptr) => Ok(ACPISDTIter { + pos: 0, + width: ptr_len, + sdt: ptr as u32 + mem::size_of::() as u32, + len: (unsafe {(*ptr).length} as usize - mem::size_of::()) / ptr_len + }) + } + } +} + +impl Iterator for ACPISDTIter { + type Item = u32; + + fn next(&mut self) -> Option { + self.pos += 1; + if self.pos > self.len { + return None; + } + let ret = Some(unsafe {*(self.sdt as *const u32)}); + self.sdt += self.width as u32; + return ret; + } +} + +fn is_init() -> Result <(), &'static str> { + if unsafe {ACPI.valid} { + Ok(()) + } else { + Err("ACPI is not initialized") + } +} + + +/// Initalized the ACPI module +pub fn init() -> Result <(), &'static str> { + if let Ok(()) = is_init() { + return Ok(()); + } + unsafe {ACPI.init()} +} + +/// Proceed to ACPI shutdown +/// This function doesn't work with Virtual Box yet +pub fn shutdown() -> Result <(), &'static str> { + is_init()?; + dsdt::shutdown(fadt::get_controlblock()?) +} + +/// Display state of ACPI +pub fn info() -> Result <(), &'static str> { + is_init()?; + println!("ACPI STATE:\n {}", if fadt::is_enable()? {"ENABLED"} else {"DISABLED"}); + Ok(()) +} diff --git a/kernel-rs/src/acpi/rsdp.rs b/kernel-rs/src/acpi/rsdp.rs new file mode 100644 index 00000000..b5b6967b --- /dev/null +++ b/kernel-rs/src/acpi/rsdp.rs @@ -0,0 +1,89 @@ +use super::{check_signature,check_checksum}; +use core::mem; + +#[repr(C)] +struct RSDP { + signature: [u8; 8], + checksum: u8, + oemid: [u8; 6], + revision: u8, + rsdtaddr: u32, +} + +#[repr(C)] +pub struct RSDP20 { + rsdp: RSDP, + length: u32, + xsdtaddress: u64, + extendedchecksum: u8, + reserved: [u8; 3], +} + +static mut RSDPTR: Option<*const RSDP20> = None; + +/// RSDP load will check is RSDP is present at the addr sent. +/// Return a bool +/// true => RSDP is V2 +/// false => RSDP is V1 +pub fn load(addr: u32) -> Result { + if check_signature(addr, "RSD PTR ") { + let ptr_tmp = addr as *const RSDP20; + let revision = unsafe {(*ptr_tmp).rsdp.revision}; + if (revision == 0 && check_checksum(addr, mem::size_of::())) || (revision == 2 && check_checksum(addr, mem::size_of::())) { + unsafe {RSDPTR = Some(ptr_tmp)}; + return Ok(revision == 2); + } + } + Err("Not a valid RSD ptr") +} + +fn memory_finding(bound: u32) -> Result { + let mut i = 0; + while i < 0x1000000 { + i += bound; + if let Ok(result) = load(i) { + return Ok(result) + } + } + // HACK because RSDP is not always aligned on 16 bytes boundary with QEMU + if bound > 1 { + return memory_finding(bound / 2); + } + Err("Can not find Root System Description Pointer (RSDP).") +} + +fn is_init() -> Result <*const RSDP20, &'static str> { + match unsafe {RSDPTR} { + Some(ptr) => Ok(ptr), + None => Err("Root System Description Pointer (RSDP) is not initialized") + // if ptr == 0 as *const RSDP20 + // => Err("Root System Description Pointer (RSDP) is not initialized"), + // ptr + // => Ok(ptr) + } +} + +/// Return a ptr on xsdt +/// RSDP must have been initialized first +pub fn xsdtaddr() -> Result { + let ptr = is_init()?; + let revision = unsafe {(*ptr).rsdp.revision}; + if revision != 2 { + return Err("Wrong RSDP version asked"); + } + return Ok(unsafe {(*ptr).xsdtaddress}); +} + +/// Return a ptr on rsdt +/// RSDP must have been initialized first +pub fn rsdtaddr() -> Result { + let ptr = is_init()?; + return Ok(unsafe {(*ptr).rsdp.rsdtaddr}); +} + +/// RSDP init will iter on addr in [0x0 - 0x1000000] to find "RSDP PTR " +/// if you already know the location, you should prefer to use load function +/// return an Error if there is no RSDP in memory, or return the value of load function +pub fn init() -> Result { + memory_finding(16) +} diff --git a/kernel-rs/src/acpi/rsdt.rs b/kernel-rs/src/acpi/rsdt.rs new file mode 100644 index 00000000..61363973 --- /dev/null +++ b/kernel-rs/src/acpi/rsdt.rs @@ -0,0 +1,19 @@ +use super::{ACPISDTHeader,ACPISDTIter}; + +static mut RSDT: Option<*const ACPISDTHeader> = None; + +/// ## Initialize Root System Description Table (RSDT) +/// input param addr is contain in RSDP +pub fn init(addr: u32) -> Result <(), &'static str> { + if ACPISDTHeader::valid(addr, "RSDT") { + unsafe {RSDT = Some(addr as *const ACPISDTHeader)}; + return Ok(()); + } + return Err("Can not find Root System Description Table (RSDT)."); +} + +/// Return a iterable of ptr contained in RSDT +/// RSDT must have been initialized first +pub fn iter() -> Result { + ACPISDTIter::new(unsafe {RSDT}, 4) +} diff --git a/kernel-rs/src/acpi/xsdt.rs b/kernel-rs/src/acpi/xsdt.rs new file mode 100644 index 00000000..356be49d --- /dev/null +++ b/kernel-rs/src/acpi/xsdt.rs @@ -0,0 +1,21 @@ +use super::{ACPISDTHeader,ACPISDTIter}; + +static mut XSDT: Option<*const ACPISDTHeader> = None; + +/// ## Initialize Root System Description Table (XSDT) +/// input param addr is contain in RSDP +pub fn init(addr: u64) -> Result <(), &'static str> { + assert!((addr as u32) as u64 == addr); + let addr: u32 = addr as u32; + if ACPISDTHeader::valid(addr, "XSDT") { + unsafe {XSDT = Some(addr as *const ACPISDTHeader)}; + return Ok(()); + } + return Err("Can not find eXtended System Descriptor Table (XSDT)."); +} + +/// Return a iterable of ptr contained in XSDT +/// XSDT must have been initialized first +pub fn iter() -> Result { + ACPISDTIter::new(unsafe {XSDT}, 8) +} diff --git a/kernel-rs/src/arch/x86/grub.cfg b/kernel-rs/src/arch/x86/grub.cfg index 4e624c0f..4cbeea5c 100644 --- a/kernel-rs/src/arch/x86/grub.cfg +++ b/kernel-rs/src/arch/x86/grub.cfg @@ -2,6 +2,6 @@ set timeout=0 set default=0 menuentry "Blue Snow" { - multiboot2 /boot/kernel.bin + multiboot2 /boot/BlueSnow boot } diff --git a/kernel-rs/src/arch/x86/linker.ld b/kernel-rs/src/arch/x86/linker.ld index 2c96fb77..58b51fbc 100644 --- a/kernel-rs/src/arch/x86/linker.ld +++ b/kernel-rs/src/arch/x86/linker.ld @@ -11,8 +11,6 @@ SECTIONS { . += 80 * 25 * 2; . = 1M; - kernel_start = . ; - /* ensure that the multiboot header is at the beginning */ .multiboot_header : { KEEP(*(.multiboot_header)) } .text : { *(.text .text.*) } @@ -20,6 +18,4 @@ SECTIONS { .data : { *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) *(.data.*) } .debug : { *(.debug_*) } .bss : {*(.bss .bss.*)} - - /* kernel_end = . ; */ } diff --git a/kernel-rs/src/arch/x86/multiboot_header.asm b/kernel-rs/src/arch/x86/multiboot_header.asm index 9f87d3bb..584b3856 100644 --- a/kernel-rs/src/arch/x86/multiboot_header.asm +++ b/kernel-rs/src/arch/x86/multiboot_header.asm @@ -1,7 +1,8 @@ section .multiboot_header header_start: +align 4 dd 0xe85250d6 ; magic number (multiboot 2) - dd 0 ; architecture 0 (protected mode i386) + dd 0 ; TODO change it because architecture 0 means(protected mode i386) We could have problem here dd header_end - header_start ; header length dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)); checksum diff --git a/kernel-rs/src/console.rs b/kernel-rs/src/console.rs index c5f8a075..35960b2f 100644 --- a/kernel-rs/src/console.rs +++ b/kernel-rs/src/console.rs @@ -1,41 +1,44 @@ use cpuio; +use acpi; -//TODO implement ACPI to have such functionality /// Reboot the kernel /// /// If reboot failed, will loop on a halt cmd /// -pub fn reboot() { - //TODO disable interrupt here something like : asm volatile ("cli"); - +pub fn reboot() -> ! { + unsafe {asm!("cli")}; //TODO volatile ????? // I will now clear the keyboard buffer let mut buffer: u8 = 0x02; - while buffer == 0x02 { + while buffer & 0x02 != 0 { + cpuio::inb(0x60); buffer = cpuio::inb(0x64); } - cpuio::outb(0x64, 0xFE);//Send reset value to CPU //TODO doesn't work - println!("Reicv reboot command. System cannot reboot yet, he is now halt\n"); + cpuio::outb(0x64, 0xFE);//Send reset value to CPU //TODO doesn't work in QEMU ==> it seems that qemu cannot reboot + println!("Unable to perform reboot. Kernel will be halted"); cpuio::halt(); } /// Shutdown the kernel /// -/// # Pre-requist: -/// Seems that he have to use following line command : -/// `-device isa-debug-exit,iobase=0xf4,iosize=0x04` +/// If shutdown is performed but failed, will loop on a halt cmd +/// If shutdown cannot be called, return a Err(&str) /// -/// If shutdown failed, will loop on a halt cmd -/// -pub fn shutdown() -> ! { - cpuio::outb(0xf4, 0x00);//TODO doesn't work :( - println!("Reicv shutdown command. System cannot shutdown properly yet, he is now halt\n"); +pub fn shutdown() -> Result <(), &'static str> { + println!("RECV SHUTDOWN"); + acpi::shutdown()?; + println!("Unable to perform ACPI shutdown. Kernel will be halted"); cpuio::halt(); } /// Print the kernel stack /// -pub fn print_kernel_stack() { +pub fn print_kernel_stack() -> Result <(), &'static str> { println!("It's a stack print"); + Ok(()) } +pub fn acpi_info() -> Result <(), &'static str> { + acpi::info()?; + Ok(()) +} diff --git a/kernel-rs/src/cpuio.rs b/kernel-rs/src/cpuio.rs index 148ee020..ffd6ca9b 100644 --- a/kernel-rs/src/cpuio.rs +++ b/kernel-rs/src/cpuio.rs @@ -10,7 +10,7 @@ pub fn inb(port: u16) -> u8 { } /// Write a `u8`-sized `value` to `port`. -pub fn outb(value: u8, port: u16) { +pub fn outb(port: u16, value: u8) { unsafe {asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile")}; } @@ -22,7 +22,7 @@ pub fn inw(port: u16) -> u16 { } /// Write a `u8`-sized `value` to `port`. -pub fn outw(value: u16, port: u16) { +pub fn outw(port: u16, value: u16) { unsafe {asm!("outw %ax, %dx" :: "{dx}"(port), "{ax}"(value) :: "volatile")}; } @@ -34,11 +34,12 @@ pub fn inl(port: u16) -> u32 { } /// Write a `u32`-sized `value` to `port`. -pub fn outl(value: u32, port: u16) { +pub fn outl(port: u16, value: u32) { unsafe {asm!("outl %eax, %dx" :: "{dx}"(port), "{eax}"(value) :: "volatile")}; } pub fn halt() -> ! { + unsafe {asm!("cli")};//TODO sure here ? loop { unsafe {asm!("hlt")}; //TODO volatile ????? } diff --git a/kernel-rs/src/lib.rs b/kernel-rs/src/lib.rs index 2e42ab22..599d5c06 100644 --- a/kernel-rs/src/lib.rs +++ b/kernel-rs/src/lib.rs @@ -4,7 +4,7 @@ #![feature(lang_items)] #![feature(const_fn)] #![feature(ptr_internals)] -#![feature(asm)] //needed by cpuio for inline asm +#![feature(asm)] extern crate rlibc; extern crate multiboot2; @@ -19,29 +19,40 @@ pub mod keyboard; pub mod console; /// wrappers around the x86-family I/O instructions. pub mod cpuio; +/// ACPI self-content module +pub mod acpi; use context::CONTEXT; + +fn init_kernel() -> Result <(), &'static str> { + acpi::init()?; + Ok(()) +} use vga::{Color, ColorCode}; #[no_mangle] pub extern fn kmain(multiboot_information_address: usize) -> ! { - // unsafe { CONTEXT.current_term().color_code = ColorCode::new(Color::White, Color::Cyan); } - // print!("{}{}{}{}{}{}{}{}{}{}{}{}{}{}", - // format_args!("{: ^80}", r#" ,--, "#), - // format_args!("{: ^80}", r#" ,--.'| ,----, "#), - // format_args!("{: ^80}", r#" ,--, | : .' .' \ "#), - // format_args!("{: ^80}", r#",---.'| : ' ,----,' | "#), - // format_args!("{: ^80}", r#"; : | | ; | : . ; "#), - // format_args!("{: ^80}", r#"| | : _' | ; |.' / "#), - // format_args!("{: ^80}", r#": : |.' | `----'/ ; "#), - // format_args!("{: ^80}", r#"| ' ' ; : / ; / "#), - // format_args!("{: ^80}", r#"\ \ .'. | ; / /-, "#), - // format_args!("{: ^80}", r#" `---`: | ' / / /.`| "#), - // format_args!("{: ^80}", r#" ' ; |./__; : "#), - // format_args!("{: ^80}", r#" | : ;| : .' "#), - // format_args!("{: ^80}", r#" ' ,/ ; | .' "#), - // format_args!("{: ^80}", r#" '--' `---' "#)); - // unsafe { CONTEXT.current_term().color_code = ColorCode::new(Color::White, Color::Black); } + if let Err(msg) = init_kernel() { + println!("Kernel initialization has failed: {}", msg); + cpuio::halt(); + } + unsafe { CONTEXT.current_term().color_code = ColorCode::new(Color::White, Color::Cyan); } + print!("{}{}{}{}{}{}{}{}{}{}{}{}{}{}", + format_args!("{: ^80}", r#" ,--, "#), + format_args!("{: ^80}", r#" ,--.'| ,----, "#), + format_args!("{: ^80}", r#" ,--, | : .' .' \ "#), + format_args!("{: ^80}", r#",---.'| : ' ,----,' | "#), + format_args!("{: ^80}", r#"; : | | ; | : . ; "#), + format_args!("{: ^80}", r#"| | : _' | ; |.' / "#), + format_args!("{: ^80}", r#": : |.' | `----'/ ; "#), + format_args!("{: ^80}", r#"| ' ' ; : / ; / "#), + format_args!("{: ^80}", r#"\ \ .'. | ; / /-, "#), + format_args!("{: ^80}", r#" `---`: | ' / / /.`| "#), + format_args!("{: ^80}", r#" ' ; |./__; : "#), + format_args!("{: ^80}", r#" | : ;| : .' "#), + format_args!("{: ^80}", r#" ' ,/ ; | .' "#), + format_args!("{: ^80}", r#" '--' `---' "#)); + unsafe { CONTEXT.current_term().color_code = ColorCode::new(Color::White, Color::Black); } let boot_info = unsafe{ multiboot2::load(multiboot_information_address) }; let memory_map_tag = boot_info.memory_map_tag() .expect("Memory map tag required"); diff --git a/kernel-rs/src/vga/mod.rs b/kernel-rs/src/vga/mod.rs index 5c054a9b..c6266ebd 100644 --- a/kernel-rs/src/vga/mod.rs +++ b/kernel-rs/src/vga/mod.rs @@ -69,30 +69,48 @@ impl Writer { } } + fn execute_cmd(&self, command: &str) -> Result <(), &'static str> { + match command { + "shutdown" | "halt" | "q" => console::shutdown(), + "reboot" | "r" => console::reboot(), + "acpi" | "a" => console::acpi_info(), + "stack" => console::print_kernel_stack(), + _ if self.command_len > 0 => Err("Command unknown"), + _ => Ok(()), + } + } + + fn exec(&mut self) -> Result <(), &'static str> { + self.write_byte(b'\n'); + let command = match core::str::from_utf8(&self.command) { + Ok(y) => &y[..self.command_len], + Err(_) => return Err("Command is not utf8 char") + }; + if let Err(msg) = self.execute_cmd(command) { + let color_code_save = self.color_code; + self.color_code = ColorCode::new(Color::Red, Color::Black); + println!("`{}`: {}", command, msg); + self.color_code = color_code_save; + } + self.command_len = 0; + Ok(()) + } + pub fn keypress(&mut self, ascii: u8) { match ascii { b'\n' => { - self.write_byte(b'\n'); - { - let command: &str = &core::str::from_utf8(&self.command).unwrap()[..self.command_len]; - match command { - "shutdown" | "halt" => console::shutdown(), - "reboot" => console::reboot(), - "stack" => console::print_kernel_stack(), - _ => { - let color_code_save = self.color_code; - self.color_code = ColorCode::new(Color::Red, Color::Black); - println!("`{}': Command unknown ", command); - self.color_code = color_code_save; - } - } + if let Err(msg) = self.exec() { + let color_code_save = self.color_code; + self.color_code = ColorCode::new(Color::Red, Color::Black); + println!("Something wrong: {}", msg); + self.color_code = color_code_save; } - self.command_len = 0; self.prompt(); } + _ if self.command_len >= 10 => (), + byte if self.command_len == 0 && byte == b' ' => (), byte => { if self.command_len >= 10 { return }; - self.command[self.command_len] = byte; self.write_byte(byte); self.command_len += 1; @@ -136,15 +154,14 @@ impl Writer { } } - fn flush_cursor(&self) - { + fn flush_cursor(&self) { let cursor_position = self.buffer_pos / 2; // 14 awaits the rightmost 8bits - cpuio::outb(14, 0x3D4); - cpuio::outb((cursor_position >> 8) as u8, 0x3D5); + cpuio::outb(0x3D4, 14); + cpuio::outb(0x3D5, (cursor_position >> 8) as u8); // 15 awaits the leftmost 8bits - cpuio::outb(15, 0x3D4); - cpuio::outb((cursor_position >> 0) as u8 & 0x00ff, 0x3D5); + cpuio::outb(0x3D4, 15); + cpuio::outb(0x3D5, (cursor_position >> 0) as u8 & 0x00ff); } pub fn flush(&mut self) {