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
|
||||
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)
|
||||
|
|
|
|||
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
|
||||
|
||||
menuentry "Blue Snow" {
|
||||
multiboot2 /boot/kernel.bin
|
||||
multiboot2 /boot/BlueSnow
|
||||
boot
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ SECTIONS {
|
|||
. += 80 * 25 * 2;
|
||||
|
||||
. = 1M;
|
||||
kernel_start = . ;
|
||||
|
||||
/* ensure that the multiboot header is at the beginning */
|
||||
.multiboot : { KEEP(*(.multiboot)) }
|
||||
.text : { *(.text .text.*) }
|
||||
|
|
@ -21,6 +19,4 @@ SECTIONS {
|
|||
.data : { *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) *(.data.*) }
|
||||
.debug : { *(.debug_*) }
|
||||
.bss : {*(.bss .bss.*)}
|
||||
|
||||
/* kernel_end = . ; */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
section .multiboot
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,56 +1,74 @@
|
|||
extern crate core;
|
||||
extern crate multiboot2;
|
||||
|
||||
use acpi;
|
||||
use cpuio;
|
||||
use core::char;
|
||||
use context::CONTEXT;
|
||||
use vga::*;
|
||||
|
||||
pub fn dispatch(command: &str) {
|
||||
fn dispatch(command: &str) -> Result <(), &'static str> {
|
||||
match command {
|
||||
"shutdown" | "halt" => self::shutdown(),
|
||||
"reboot" => self::reboot(),
|
||||
"stack" => self::print_stack(),
|
||||
"multiboot" => self::mb2_info(),
|
||||
"acpi" => self::acpi_info(),
|
||||
"help" | "h" => self::help(),
|
||||
"memory" => self::mb2_memory(),
|
||||
"multiboot" => self::mb2_info(),
|
||||
"reboot" => self::reboot(),
|
||||
"sections" => self::mb2_sections(),
|
||||
_ => {
|
||||
set_color!(Red);
|
||||
println!("`{}': Command unknown ", command);
|
||||
set_color!();
|
||||
}
|
||||
"shutdown" | "halt" | "q" => self::shutdown(),
|
||||
"stack" => self::print_stack(),
|
||||
_ => Err("Command unknown. (h|help for help)"),
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
///
|
||||
/// If reboot failed, will loop on a halt cmd
|
||||
///
|
||||
fn reboot() {
|
||||
//TODO disable interrupt here something like : asm volatile ("cli");
|
||||
|
||||
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
|
||||
///
|
||||
fn shutdown() -> ! {
|
||||
cpuio::outb(0xf4, 0x00);//TODO doesn't work :(
|
||||
println!("Reicv shutdown command. System cannot shutdown properly yet, he is now halt\n");
|
||||
fn shutdown() -> Result <(), &'static str> {
|
||||
acpi::shutdown()?;
|
||||
println!("Unable to perform ACPI shutdown. Kernel will be halted");
|
||||
cpuio::halt();
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +102,9 @@ fn print_line(line: &[u8], address: usize) {
|
|||
print!("|");
|
||||
}
|
||||
|
||||
fn print_stack() {
|
||||
/// Print the kernel stack
|
||||
///
|
||||
fn print_stack() -> Result <(), &'static str> {
|
||||
let esp: usize;
|
||||
let ebp: usize;
|
||||
unsafe { asm!("" : "={esp}"(esp), "={ebp}"(ebp):::) };
|
||||
|
|
@ -92,9 +112,10 @@ fn print_stack() {
|
|||
println!("ebp = {:#x}", ebp);
|
||||
println!("size = {:#X} bytes", ebp - esp);
|
||||
hexdump(esp, ebp);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mb2_memory() {
|
||||
fn mb2_memory() -> Result <(), &'static str> {
|
||||
let boot_info = unsafe { multiboot2::load(CONTEXT.boot_info_addr) };
|
||||
|
||||
let memory_map_tag = boot_info.memory_map_tag()
|
||||
|
|
@ -105,11 +126,11 @@ fn mb2_memory() {
|
|||
println!(" start: 0x{:x}, length: 0x{:x}",
|
||||
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 elf_sections_tag = boot_info.elf_sections_tag()
|
||||
.expect("Elf-sections tag required");
|
||||
|
||||
|
|
@ -118,9 +139,10 @@ fn mb2_sections() {
|
|||
println!(" {: <10} {:#x}, size: {:#x}, flags: {:#X}",
|
||||
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 command_line_tag = boot_info.command_line_tag()
|
||||
|
|
@ -133,4 +155,10 @@ fn mb2_info() {
|
|||
if command_line_tag.command_line().len() != 0 {
|
||||
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`.
|
||||
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 ?????
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; //slightly modified fork from official 0.3.2
|
||||
|
|
@ -19,12 +19,41 @@ 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(multiboot_information_address: usize) -> Result <(), &'static str> {
|
||||
unsafe { CONTEXT.boot_info_addr = multiboot_information_address };
|
||||
acpi::init()?;
|
||||
Ok(())
|
||||
}
|
||||
use vga::{Color, ColorCode};
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn kmain(multiboot_info_addr: usize) -> ! {
|
||||
unsafe { CONTEXT.boot_info_addr = multiboot_info_addr };
|
||||
pub extern fn kmain(multiboot_information_address: usize) -> ! {
|
||||
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.vga2.prompt(); }
|
||||
|
|
|
|||
|
|
@ -79,20 +79,37 @@ impl Writer {
|
|||
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) {
|
||||
match ascii {
|
||||
b'\n' if self.command_len == 0 => {
|
||||
self.write_byte(b'\n');
|
||||
self.prompt();
|
||||
}
|
||||
b'\n' => {
|
||||
self.write_byte(b'\n');
|
||||
{
|
||||
let command: &str = &core::str::from_utf8(&self.command).unwrap()[..self.command_len];
|
||||
console::dispatch(command);
|
||||
if let Err(msg) = console::exec(&self) {
|
||||
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;
|
||||
|
|
@ -137,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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue