Merge branch 'ACPI' into KFS-2 + add help function
This commit is contained in:
commit
6e2456d2f8
14 changed files with 650 additions and 67 deletions
|
|
@ -11,12 +11,13 @@ endif
|
||||||
project := bluesnow
|
project := bluesnow
|
||||||
arch ?= x86
|
arch ?= x86
|
||||||
NASM := nasm -f elf
|
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 -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
|
QEMU := qemu-system-x86_64 -gdb tcp::$(PORTG) -enable-kvm -monitor telnet:127.0.0.1:$(PORT),server,nowait
|
||||||
|
|
||||||
kernel := build/kernel-$(arch).bin
|
kerName := BlueSnow
|
||||||
iso := build/os-$(arch).iso
|
kernel := build/$(kerName)
|
||||||
|
iso := $(kernel).iso
|
||||||
DIRISO := build/isofiles
|
DIRISO := build/isofiles
|
||||||
|
|
||||||
target ?= $(arch)-$(project)
|
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)
|
KERNEL_RUN := $(QEMU) -curses -cdrom $(iso)
|
||||||
MONITOR := sleep 0.5;\
|
MONITOR := sleep 0.5;\
|
||||||
telnet 127.0.0.1 $(PORT);\
|
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 \"[g]db\" | 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 2 \`
|
||||||
GDB := gdb -q\
|
GDB := gdb -q\
|
||||||
-ex \"set arch i386:x86-64\"\
|
-ex \"set arch i386:x86-64\"\
|
||||||
-ex \"file build/kernel-x86.bin\"\
|
-ex \"file $(kernel)\"\
|
||||||
-ex \"target remote localhost:$(PORTG)\" \
|
-ex \"target remote localhost:$(PORTG)\" \
|
||||||
-ex \"continue\"
|
-ex \"continue\"
|
||||||
|
|
||||||
|
|
@ -46,18 +47,28 @@ build/arch/$(arch)/%.o: src/arch/$(arch)/%.asm Makefile
|
||||||
@echo "Compiling (ASM) $@..."
|
@echo "Compiling (ASM) $@..."
|
||||||
|
|
||||||
$(kernel): $(rust_os) $(asm_object) $(linker_script) Makefile
|
$(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
|
$(iso): $(kernel) $(grub.cfg) Makefile
|
||||||
@mkdir -p $(DIRISO)/boot/grub
|
@mkdir -p $(DIRISO)/boot/grub
|
||||||
@cp $(grub.cfg) $(DIRISO)/boot/grub
|
@cp $(grub.cfg) $(DIRISO)/boot/grub
|
||||||
@cp $(kernel) $(DIRISO)/boot/kernel.bin
|
@cp $(kernel) $(DIRISO)/boot/$(kerName)
|
||||||
@grub-mkrescue -o $(iso) $(DIRISO) 2>/dev/null
|
@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
|
run: $(iso) Makefile
|
||||||
@tmux info >&- || { echo -e "\033[38;5;16m ~~ NOT IN A VALID TMUX SESSION ~~\033[0m" ; exit 1; }
|
@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)'
|
@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:
|
clean:
|
||||||
@cargo clean
|
@cargo clean
|
||||||
|
|
@ -69,4 +80,4 @@ $(rust_os): $(target).json Makefile
|
||||||
kernel: $(rust_os)
|
kernel: $(rust_os)
|
||||||
iso: $(iso)
|
iso: $(iso)
|
||||||
|
|
||||||
.PHONY: run clean kernel iso $(rust_os)
|
.PHONY: R run clean kernel iso $(rust_os)
|
||||||
|
|
|
||||||
84
kernel-rs/src/acpi/dsdt.rs
Normal file
84
kernel-rs/src/acpi/dsdt.rs
Normal 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
143
kernel-rs/src/acpi/fadt.rs
Normal 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
145
kernel-rs/src/acpi/mod.rs
Normal 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(())
|
||||||
|
}
|
||||||
89
kernel-rs/src/acpi/rsdp.rs
Normal file
89
kernel-rs/src/acpi/rsdp.rs
Normal 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)
|
||||||
|
}
|
||||||
19
kernel-rs/src/acpi/rsdt.rs
Normal file
19
kernel-rs/src/acpi/rsdt.rs
Normal 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)
|
||||||
|
}
|
||||||
21
kernel-rs/src/acpi/xsdt.rs
Normal file
21
kernel-rs/src/acpi/xsdt.rs
Normal 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)
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,6 @@ set timeout=0
|
||||||
set default=0
|
set default=0
|
||||||
|
|
||||||
menuentry "Blue Snow" {
|
menuentry "Blue Snow" {
|
||||||
multiboot2 /boot/kernel.bin
|
multiboot2 /boot/BlueSnow
|
||||||
boot
|
boot
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ SECTIONS {
|
||||||
. += 80 * 25 * 2;
|
. += 80 * 25 * 2;
|
||||||
|
|
||||||
. = 1M;
|
. = 1M;
|
||||||
kernel_start = . ;
|
|
||||||
|
|
||||||
/* ensure that the multiboot header is at the beginning */
|
/* ensure that the multiboot header is at the beginning */
|
||||||
.multiboot : { KEEP(*(.multiboot)) }
|
.multiboot : { KEEP(*(.multiboot)) }
|
||||||
.text : { *(.text .text.*) }
|
.text : { *(.text .text.*) }
|
||||||
|
|
@ -21,6 +19,4 @@ SECTIONS {
|
||||||
.data : { *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) *(.data.*) }
|
.data : { *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) *(.data.*) }
|
||||||
.debug : { *(.debug_*) }
|
.debug : { *(.debug_*) }
|
||||||
.bss : {*(.bss .bss.*)}
|
.bss : {*(.bss .bss.*)}
|
||||||
|
|
||||||
/* kernel_end = . ; */
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
section .multiboot
|
section .multiboot
|
||||||
header_start:
|
header_start:
|
||||||
|
align 4
|
||||||
dd 0xe85250d6 ; magic number (multiboot 2)
|
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 header_end - header_start ; header length
|
||||||
|
|
||||||
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)); checksum
|
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)); checksum
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,74 @@
|
||||||
extern crate core;
|
extern crate core;
|
||||||
extern crate multiboot2;
|
extern crate multiboot2;
|
||||||
|
|
||||||
|
use acpi;
|
||||||
use cpuio;
|
use cpuio;
|
||||||
use core::char;
|
use core::char;
|
||||||
use context::CONTEXT;
|
use context::CONTEXT;
|
||||||
use vga::*;
|
use vga::*;
|
||||||
|
|
||||||
pub fn dispatch(command: &str) {
|
fn dispatch(command: &str) -> Result <(), &'static str> {
|
||||||
match command {
|
match command {
|
||||||
"shutdown" | "halt" => self::shutdown(),
|
"acpi" => self::acpi_info(),
|
||||||
"reboot" => self::reboot(),
|
"help" | "h" => self::help(),
|
||||||
"stack" => self::print_stack(),
|
"memory" => self::mb2_memory(),
|
||||||
"multiboot" => self::mb2_info(),
|
"multiboot" => self::mb2_info(),
|
||||||
"memory" => self::mb2_memory(),
|
"reboot" => self::reboot(),
|
||||||
"sections" => self::mb2_sections(),
|
"sections" => self::mb2_sections(),
|
||||||
_ => {
|
"shutdown" | "halt" | "q" => self::shutdown(),
|
||||||
set_color!(Red);
|
"stack" => self::print_stack(),
|
||||||
println!("`{}': Command unknown ", command);
|
_ => Err("Command unknown. (h|help for help)"),
|
||||||
set_color!();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO implement ACPI to have such functionality
|
pub fn exec(cli: &Writer) -> Result <(), &'static str> {
|
||||||
|
let command = cli.get_command()?;
|
||||||
|
if let Err(msg) = self::dispatch(command) {
|
||||||
|
set_color!(Red);
|
||||||
|
println!("`{}`: {}", command, msg);
|
||||||
|
set_color!();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn help() -> Result <(), &'static str> {
|
||||||
|
print!("{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n",
|
||||||
|
"acpi => Return acpi state (ENABLED|DISABLE)",
|
||||||
|
"help | h => Print this help",
|
||||||
|
"memory => lolilol", // TODO
|
||||||
|
"multiboot => lolilol", // TODO
|
||||||
|
"reboot => reboot",
|
||||||
|
"sections => lolilol", // TODO
|
||||||
|
"shutdown | halt | q => Kill a kitten, then shutdown",
|
||||||
|
"stack => Print kernel stack in a fancy way");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Reboot the kernel
|
/// Reboot the kernel
|
||||||
///
|
///
|
||||||
/// If reboot failed, will loop on a halt cmd
|
/// If reboot failed, will loop on a halt cmd
|
||||||
///
|
///
|
||||||
fn reboot() {
|
fn reboot() -> ! {
|
||||||
//TODO disable interrupt here something like : asm volatile ("cli");
|
unsafe {asm!("cli")}; //TODO volatile ?????
|
||||||
|
|
||||||
// I will now clear the keyboard buffer
|
// I will now clear the keyboard buffer
|
||||||
let mut buffer: u8 = 0x02;
|
let mut buffer: u8 = 0x02;
|
||||||
while buffer == 0x02 {
|
while buffer & 0x02 != 0 {
|
||||||
|
cpuio::inb(0x60);
|
||||||
buffer = cpuio::inb(0x64);
|
buffer = cpuio::inb(0x64);
|
||||||
}
|
}
|
||||||
cpuio::outb(0x64, 0xFE);//Send reset value to CPU //TODO doesn't work
|
cpuio::outb(0x64, 0xFE);//Send reset value to CPU //TODO doesn't work in QEMU ==> it seems that qemu cannot reboot
|
||||||
println!("Reicv reboot command. System cannot reboot yet, he is now halt\n");
|
println!("Unable to perform reboot. Kernel will be halted");
|
||||||
cpuio::halt();
|
cpuio::halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shutdown the kernel
|
/// Shutdown the kernel
|
||||||
///
|
///
|
||||||
/// # Pre-requist:
|
/// If shutdown is performed but failed, will loop on a halt cmd
|
||||||
/// Seems that he have to use following line command :
|
/// If shutdown cannot be called, return a Err(&str)
|
||||||
/// `-device isa-debug-exit,iobase=0xf4,iosize=0x04`
|
|
||||||
///
|
///
|
||||||
/// If shutdown failed, will loop on a halt cmd
|
fn shutdown() -> Result <(), &'static str> {
|
||||||
///
|
acpi::shutdown()?;
|
||||||
fn shutdown() -> ! {
|
println!("Unable to perform ACPI shutdown. Kernel will be halted");
|
||||||
cpuio::outb(0xf4, 0x00);//TODO doesn't work :(
|
|
||||||
println!("Reicv shutdown command. System cannot shutdown properly yet, he is now halt\n");
|
|
||||||
cpuio::halt();
|
cpuio::halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,7 +102,9 @@ fn print_line(line: &[u8], address: usize) {
|
||||||
print!("|");
|
print!("|");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_stack() {
|
/// Print the kernel stack
|
||||||
|
///
|
||||||
|
fn print_stack() -> Result <(), &'static str> {
|
||||||
let esp: usize;
|
let esp: usize;
|
||||||
let ebp: usize;
|
let ebp: usize;
|
||||||
unsafe { asm!("" : "={esp}"(esp), "={ebp}"(ebp):::) };
|
unsafe { asm!("" : "={esp}"(esp), "={ebp}"(ebp):::) };
|
||||||
|
|
@ -92,9 +112,10 @@ fn print_stack() {
|
||||||
println!("ebp = {:#x}", ebp);
|
println!("ebp = {:#x}", ebp);
|
||||||
println!("size = {:#X} bytes", ebp - esp);
|
println!("size = {:#X} bytes", ebp - esp);
|
||||||
hexdump(esp, ebp);
|
hexdump(esp, ebp);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mb2_memory() {
|
fn mb2_memory() -> Result <(), &'static str> {
|
||||||
let boot_info = unsafe { multiboot2::load(CONTEXT.boot_info_addr) };
|
let boot_info = unsafe { multiboot2::load(CONTEXT.boot_info_addr) };
|
||||||
|
|
||||||
let memory_map_tag = boot_info.memory_map_tag()
|
let memory_map_tag = boot_info.memory_map_tag()
|
||||||
|
|
@ -105,22 +126,23 @@ fn mb2_memory() {
|
||||||
println!(" start: 0x{:x}, length: 0x{:x}",
|
println!(" start: 0x{:x}, length: 0x{:x}",
|
||||||
area.start_address(), area.size());
|
area.start_address(), area.size());
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mb2_sections() {
|
fn mb2_sections() -> Result <(), &'static str> {
|
||||||
let boot_info = unsafe { multiboot2::load(CONTEXT.boot_info_addr) };
|
let boot_info = unsafe { multiboot2::load(CONTEXT.boot_info_addr) };
|
||||||
|
|
||||||
let elf_sections_tag = boot_info.elf_sections_tag()
|
let elf_sections_tag = boot_info.elf_sections_tag()
|
||||||
.expect("Elf-sections tag required");
|
.expect("Elf-sections tag required");
|
||||||
|
|
||||||
println!("kernel sections:");
|
println!("kernel sections:");
|
||||||
for section in elf_sections_tag.sections() {
|
for section in elf_sections_tag.sections() {
|
||||||
println!(" {: <10} {:#x}, size: {:#x}, flags: {:#X}",
|
println!(" {: <10} {:#x}, size: {:#x}, flags: {:#X}",
|
||||||
section.name(), section.start_address(), section.size(), section.flags());
|
section.name(), section.start_address(), section.size(), section.flags());
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mb2_info() {
|
fn mb2_info() -> Result <(), &'static str> {
|
||||||
let boot_info = unsafe { multiboot2::load(CONTEXT.boot_info_addr) };
|
let boot_info = unsafe { multiboot2::load(CONTEXT.boot_info_addr) };
|
||||||
|
|
||||||
let command_line_tag = boot_info.command_line_tag()
|
let command_line_tag = boot_info.command_line_tag()
|
||||||
|
|
@ -133,4 +155,10 @@ fn mb2_info() {
|
||||||
if command_line_tag.command_line().len() != 0 {
|
if command_line_tag.command_line().len() != 0 {
|
||||||
println!("command line: {}", command_line_tag.command_line());
|
println!("command line: {}", command_line_tag.command_line());
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acpi_info() -> Result <(), &'static str> {
|
||||||
|
acpi::info()?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ pub fn inb(port: u16) -> u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a `u8`-sized `value` to `port`.
|
/// 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")};
|
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`.
|
/// 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")};
|
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`.
|
/// 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")};
|
unsafe {asm!("outl %eax, %dx" :: "{dx}"(port), "{eax}"(value) :: "volatile")};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn halt() -> ! {
|
pub fn halt() -> ! {
|
||||||
|
unsafe {asm!("cli")};//TODO sure here ?
|
||||||
loop {
|
loop {
|
||||||
unsafe {asm!("hlt")}; //TODO volatile ?????
|
unsafe {asm!("hlt")}; //TODO volatile ?????
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
#![feature(ptr_internals)]
|
#![feature(ptr_internals)]
|
||||||
#![feature(asm)] //needed by cpuio for inline asm
|
#![feature(asm)]
|
||||||
|
|
||||||
extern crate rlibc;
|
extern crate rlibc;
|
||||||
extern crate multiboot2; //slightly modified fork from official 0.3.2
|
extern crate multiboot2; //slightly modified fork from official 0.3.2
|
||||||
|
|
@ -19,12 +19,41 @@ pub mod keyboard;
|
||||||
pub mod console;
|
pub mod console;
|
||||||
/// wrappers around the x86-family I/O instructions.
|
/// wrappers around the x86-family I/O instructions.
|
||||||
pub mod cpuio;
|
pub mod cpuio;
|
||||||
|
/// ACPI self-content module
|
||||||
|
pub mod acpi;
|
||||||
|
|
||||||
use context::CONTEXT;
|
use context::CONTEXT;
|
||||||
|
|
||||||
|
fn init_kernel(multiboot_information_address: usize) -> Result <(), &'static str> {
|
||||||
|
unsafe { CONTEXT.boot_info_addr = multiboot_information_address };
|
||||||
|
acpi::init()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
use vga::{Color, ColorCode};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn kmain(multiboot_info_addr: usize) -> ! {
|
pub extern fn kmain(multiboot_information_address: usize) -> ! {
|
||||||
unsafe { CONTEXT.boot_info_addr = multiboot_info_addr };
|
if let Err(msg) = init_kernel(multiboot_information_address) {
|
||||||
|
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); }
|
||||||
|
|
||||||
unsafe { CONTEXT.vga1.prompt();CONTEXT.vga1.flush(); }
|
unsafe { CONTEXT.vga1.prompt();CONTEXT.vga1.flush(); }
|
||||||
unsafe { CONTEXT.vga2.prompt(); }
|
unsafe { CONTEXT.vga2.prompt(); }
|
||||||
|
|
|
||||||
|
|
@ -79,20 +79,37 @@ impl Writer {
|
||||||
self.erase_byte();
|
self.erase_byte();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_command(&self) -> Result <&str, &'static str> {
|
||||||
|
|
||||||
|
match core::str::from_utf8(&self.command) {
|
||||||
|
Ok(y) => Ok(&y[..self.command_len]),
|
||||||
|
Err(_) => Err("Command is not utf8 char")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub fn keypress(&mut self, ascii: u8) {
|
pub fn keypress(&mut self, ascii: u8) {
|
||||||
match ascii {
|
match ascii {
|
||||||
|
b'\n' if self.command_len == 0 => {
|
||||||
|
self.write_byte(b'\n');
|
||||||
|
self.prompt();
|
||||||
|
}
|
||||||
b'\n' => {
|
b'\n' => {
|
||||||
self.write_byte(b'\n');
|
self.write_byte(b'\n');
|
||||||
{
|
if let Err(msg) = console::exec(&self) {
|
||||||
let command: &str = &core::str::from_utf8(&self.command).unwrap()[..self.command_len];
|
let color_code_save = self.color_code;
|
||||||
console::dispatch(command);
|
self.color_code = ColorCode::new(Color::Red, Color::Black);
|
||||||
|
println!("Something wrong: {}", msg);
|
||||||
|
self.color_code = color_code_save;
|
||||||
}
|
}
|
||||||
self.command_len = 0;
|
self.command_len = 0;
|
||||||
self.prompt();
|
self.prompt();
|
||||||
}
|
}
|
||||||
|
_ if self.command_len >= 10 => (),
|
||||||
|
byte if self.command_len == 0 && byte == b' ' => (),
|
||||||
byte => {
|
byte => {
|
||||||
if self.command_len >= 10 { return };
|
if self.command_len >= 10 { return };
|
||||||
|
|
||||||
self.command[self.command_len] = byte;
|
self.command[self.command_len] = byte;
|
||||||
self.write_byte(byte);
|
self.write_byte(byte);
|
||||||
self.command_len += 1;
|
self.command_len += 1;
|
||||||
|
|
@ -137,15 +154,14 @@ impl Writer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_cursor(&self)
|
fn flush_cursor(&self) {
|
||||||
{
|
|
||||||
let cursor_position = self.buffer_pos / 2;
|
let cursor_position = self.buffer_pos / 2;
|
||||||
// 14 awaits the rightmost 8bits
|
// 14 awaits the rightmost 8bits
|
||||||
cpuio::outb(14, 0x3D4);
|
cpuio::outb(0x3D4, 14);
|
||||||
cpuio::outb((cursor_position >> 8) as u8, 0x3D5);
|
cpuio::outb(0x3D5, (cursor_position >> 8) as u8);
|
||||||
// 15 awaits the leftmost 8bits
|
// 15 awaits the leftmost 8bits
|
||||||
cpuio::outb(15, 0x3D4);
|
cpuio::outb(0x3D4, 15);
|
||||||
cpuio::outb((cursor_position >> 0) as u8 & 0x00ff, 0x3D5);
|
cpuio::outb(0x3D5, (cursor_position >> 0) as u8 & 0x00ff);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flush(&mut self) {
|
pub fn flush(&mut self) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue