Add FULL ACPI support, change exec mode

This commit is contained in:
wescande 2018-03-02 15:48:06 +01:00
parent 0877ac2cc6
commit 614da57de3
14 changed files with 617 additions and 76 deletions

View file

@ -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)

View file

@ -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 <u32, &'static str> {
let dsdt_start = addr + mem::size_of::<ACPISDTHeader>() 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(())
}

143
kernel-rs/src/acpi/fadt.rs Normal file
View file

@ -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 <u32, &'static str> {
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 <bool, &'static str> {
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
}
}

145
kernel-rs/src/acpi/mod.rs Normal file
View file

@ -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 <ACPISDTIter, &'static str> {
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::<ACPISDTHeader>() as u32,
len: (unsafe {(*ptr).length} as usize - mem::size_of::<ACPISDTHeader>()) / ptr_len
})
}
}
}
impl Iterator for ACPISDTIter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
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(())
}

View file

@ -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 <bool, &'static str> {
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::<RSDP>())) || (revision == 2 && check_checksum(addr, mem::size_of::<RSDP20>())) {
unsafe {RSDPTR = Some(ptr_tmp)};
return Ok(revision == 2);
}
}
Err("Not a valid RSD ptr")
}
fn memory_finding(bound: u32) -> Result <bool, &'static str> {
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 <u64, &'static str> {
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 <u32, &'static str> {
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 <bool, &'static str> {
memory_finding(16)
}

View file

@ -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, &'static str> {
ACPISDTIter::new(unsafe {RSDT}, 4)
}

View file

@ -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, &'static str> {
ACPISDTIter::new(unsafe {XSDT}, 8)
}

View file

@ -2,6 +2,6 @@ set timeout=0
set default=0
menuentry "Blue Snow" {
multiboot2 /boot/kernel.bin
multiboot2 /boot/BlueSnow
boot
}

View file

@ -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 = . ; */
}

View file

@ -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

View file

@ -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(())
}

View file

@ -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 ?????
}

View file

@ -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");

View file

@ -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) {