lspci, console refactor
This commit is contained in:
parent
85afa2b437
commit
c9ad4e9e58
10 changed files with 250 additions and 327 deletions
|
|
@ -126,17 +126,9 @@ impl Iterator for ACPISDTIter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_init() -> Result<(), &'static str> {
|
|
||||||
if unsafe { ACPI.valid } {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err("ACPI is not initialized")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initalized the ACPI module
|
/// Initalized the ACPI module
|
||||||
pub fn init() -> Result<(), &'static str> {
|
pub fn init() -> Result<(), &'static str> {
|
||||||
if let Ok(()) = is_init() {
|
if unsafe{ACPI.valid} {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
unsafe { ACPI.init() }
|
unsafe { ACPI.init() }
|
||||||
|
|
@ -144,7 +136,7 @@ pub fn init() -> Result<(), &'static str> {
|
||||||
|
|
||||||
/// Load the ACPI module, addr given is a ptr to RSDP
|
/// Load the ACPI module, addr given is a ptr to RSDP
|
||||||
pub fn load(rsdp_addr: u32) -> Result<(), &'static str> {
|
pub fn load(rsdp_addr: u32) -> Result<(), &'static str> {
|
||||||
if let Ok(()) = is_init() {
|
if unsafe{ACPI.valid} {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
unsafe { ACPI.load(rsdp_addr) }
|
unsafe { ACPI.load(rsdp_addr) }
|
||||||
|
|
@ -152,32 +144,30 @@ pub fn load(rsdp_addr: u32) -> Result<(), &'static str> {
|
||||||
|
|
||||||
/// Proceed to ACPI shutdown
|
/// Proceed to ACPI shutdown
|
||||||
/// This function doesn't work with Virtual Box yet
|
/// This function doesn't work with Virtual Box yet
|
||||||
pub fn shutdown() -> Result<(), &'static str> {
|
pub fn shutdown() {
|
||||||
is_init()?;
|
if unsafe{ACPI.valid} { return }
|
||||||
dsdt::shutdown(fadt::get_controlblock()?)
|
dsdt::shutdown(fadt::get_controlblock().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Proceed to ACPI reboot
|
/// Proceed to ACPI reboot
|
||||||
/// This function need ACPI in v2
|
/// This function need ACPI in v2
|
||||||
pub fn reboot() -> Result<(), &'static str> {
|
pub fn reboot() {
|
||||||
is_init()?;
|
if unsafe {!ACPI.valid} {
|
||||||
|
println!("ACPI not initialized");
|
||||||
|
}
|
||||||
if unsafe { ACPI.v2 } {
|
if unsafe { ACPI.v2 } {
|
||||||
fadt::reboot()
|
fadt::reboot().unwrap()
|
||||||
} else {
|
} else {
|
||||||
Err("ACPI reboot only available in ACPI v2+")
|
println!("ACPI reboot only available in ACPI v2+");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display state of ACPI
|
/// Display state of ACPI
|
||||||
pub fn info() -> Result<(), &'static str> {
|
pub fn info() {
|
||||||
is_init()?;
|
if unsafe { !ACPI.valid } { println!("ACPI not initialized"); return }
|
||||||
println!(
|
match fadt::is_enable() {
|
||||||
"ACPI STATE:\n {}",
|
Ok(True) => println!("ACPI is disabled"),
|
||||||
if fadt::is_enable()? {
|
Ok(False) => println!("ACPI is disabled"),
|
||||||
"ENABLED"
|
Err(msg) => println!("error while checking ACPI")
|
||||||
} else {
|
|
||||||
"DISABLED"
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,5 +23,5 @@ pub unsafe fn init(active_table: &mut ActivePageTable) {
|
||||||
|
|
||||||
#[alloc_error_handler]
|
#[alloc_error_handler]
|
||||||
fn foo(_: core::alloc::Layout) -> ! {
|
fn foo(_: core::alloc::Layout) -> ! {
|
||||||
panic!();
|
panic!("alloc_error_handler");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
extern crate raw_cpuid;
|
extern crate raw_cpuid;
|
||||||
|
|
||||||
use core::fmt::Result;
|
|
||||||
|
|
||||||
use self::raw_cpuid::CpuId;
|
use self::raw_cpuid::CpuId;
|
||||||
|
|
||||||
pub fn cpu_info() -> Result {
|
pub fn cpu_info() {
|
||||||
let cpuid = CpuId::new();
|
let cpuid = CpuId::new();
|
||||||
|
|
||||||
if let Some(info) = cpuid.get_vendor_info() {
|
if let Some(info) = cpuid.get_vendor_info() {
|
||||||
|
|
@ -285,6 +283,4 @@ pub fn cpu_info() -> Result {
|
||||||
};
|
};
|
||||||
println!("");
|
println!("");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,6 @@ pub unsafe extern "C" fn x86_rust_start(multiboot_info_addr: usize) {
|
||||||
// parse multiboot2 info
|
// parse multiboot2 info
|
||||||
let boot_info = multiboot2::load(multiboot_info_addr);
|
let boot_info = multiboot2::load(multiboot_info_addr);
|
||||||
|
|
||||||
// println!("{:?}", boot_info);
|
|
||||||
// flush!();
|
|
||||||
// asm!("hlt");
|
|
||||||
|
|
||||||
// ACPI must be intialized BEFORE paging is active
|
// ACPI must be intialized BEFORE paging is active
|
||||||
if let Some(rsdp) = boot_info.rsdp_v2_tag() {
|
if let Some(rsdp) = boot_info.rsdp_v2_tag() {
|
||||||
acpi::load(rsdp).expect("ACPI failed");
|
acpi::load(rsdp).expect("ACPI failed");
|
||||||
|
|
@ -116,3 +112,30 @@ pub unsafe fn usermode(ip: u32, sp: u32) -> ! {
|
||||||
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dump control registers
|
||||||
|
pub fn regs() {
|
||||||
|
use x86::registers::control::*;
|
||||||
|
use x86::instructions::tables::tr;
|
||||||
|
use x86::instructions::segmentation::*;
|
||||||
|
use x86::registers::flags::*;
|
||||||
|
use x86::structures::gdt;
|
||||||
|
println!("cr0 = {:?}", Cr0::read());
|
||||||
|
println!("cr3 = {:?}", Cr3::read());
|
||||||
|
println!("cr4 = {:?}", Cr4::read());
|
||||||
|
println!("flags= {:?}", flags());
|
||||||
|
println!("tr = {:?}", tr());
|
||||||
|
println!("ss = {:?}", ss());
|
||||||
|
println!("cs = {:?}", cs());
|
||||||
|
println!("ds = {:?}", ds());
|
||||||
|
println!("es = {:?}", es());
|
||||||
|
println!("fs = {:?}", fs());
|
||||||
|
println!("gs = {:?}", gs());
|
||||||
|
unsafe {
|
||||||
|
println!(
|
||||||
|
"tss = {:#?}",
|
||||||
|
gdt::Descriptor(::arch::x86::gdt::GDT.table[tr().index() as usize])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
flush!();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,49 @@
|
||||||
extern crate core;
|
extern crate core;
|
||||||
// extern crate multiboot2;
|
// extern crate multiboot2;
|
||||||
|
|
||||||
use acpi;
|
|
||||||
use time;
|
|
||||||
use keyboard::PS2;
|
|
||||||
use core::char;
|
|
||||||
use vga::*;
|
use vga::*;
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
|
||||||
pub static mut CONSOLE: Console = self::Console::new();
|
pub static mut CONSOLE: Console = self::Console::new();
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref COMMANDS: BTreeMap<&'static str, fn()> = {
|
||||||
|
let mut commands = BTreeMap::new();
|
||||||
|
commands.insert("help", self::help as fn());
|
||||||
|
|
||||||
|
// ACPI
|
||||||
|
commands.insert("acpi", ::acpi::info as fn());
|
||||||
|
commands.insert("reboot", ::acpi::reboot as fn());
|
||||||
|
commands.insert("shutdown", ::acpi::shutdown as fn());
|
||||||
|
|
||||||
|
// time
|
||||||
|
commands.insert("uptime", ::time::uptime as fn());
|
||||||
|
|
||||||
|
// cpu
|
||||||
|
use arch::x86;
|
||||||
|
commands.insert("cpu", x86::devices::cpu::cpu_info as fn());
|
||||||
|
commands.insert("regs", x86::regs as fn());
|
||||||
|
commands.insert("int3", ::x86::instructions::interrupts::int3 as fn());
|
||||||
|
|
||||||
|
//memory
|
||||||
|
commands.insert("stack", ::memory::print_stack as fn());
|
||||||
|
commands.insert("page_fault", ::memory::page_fault as fn());
|
||||||
|
commands.insert("overflow", ::memory::overflow as fn());
|
||||||
|
commands.insert("overflow", ::memory::overflow as fn());
|
||||||
|
|
||||||
|
//pci
|
||||||
|
commands.insert("lspci", ::pci::lspci as fn());
|
||||||
|
commands
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn help() {
|
||||||
|
println!("The following commands are available:");
|
||||||
|
for (key, val) in COMMANDS.iter() {
|
||||||
|
println!("{}", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Console {
|
pub struct Console {
|
||||||
command: [u8; 10],
|
command: [u8; 10],
|
||||||
command_len: usize,
|
command_len: usize,
|
||||||
|
|
@ -54,11 +89,7 @@ impl Console {
|
||||||
}
|
}
|
||||||
b'\n' => {
|
b'\n' => {
|
||||||
unsafe { VGA.write_byte(b'\n'); }
|
unsafe { VGA.write_byte(b'\n'); }
|
||||||
if let Err(msg) = self.exec() {
|
self.exec();
|
||||||
set_color!(Red);
|
|
||||||
println!("{}", msg);
|
|
||||||
set_color!();
|
|
||||||
}
|
|
||||||
self.command_len = 0;
|
self.command_len = 0;
|
||||||
self.prompt();
|
self.prompt();
|
||||||
}
|
}
|
||||||
|
|
@ -73,256 +104,27 @@ impl Console {
|
||||||
self.command_len += 1;
|
self.command_len += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flush!();
|
unsafe { VGA.flush(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_command(&self) -> Result<fn(), &'static str> {
|
||||||
fn get_command(&self) -> Result<&str, &'static str> {
|
|
||||||
match core::str::from_utf8(&self.command) {
|
match core::str::from_utf8(&self.command) {
|
||||||
Ok(y) => Ok(&y[..self.command_len]),
|
Ok(y) => {
|
||||||
|
if let Some(command) = COMMANDS.get(&y[..self.command_len]) {
|
||||||
|
Ok(*command)
|
||||||
|
} else {
|
||||||
|
Err("Command not found, try help")
|
||||||
|
}
|
||||||
|
},
|
||||||
Err(_) => Err("Command is not utf8"),
|
Err(_) => Err("Command is not utf8"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec(&self) -> core::result::Result<(), &'static str> {
|
pub fn exec(&self) {
|
||||||
let command = self.get_command();
|
let command = self.get_command();
|
||||||
if let Err(msg) = command {
|
match command {
|
||||||
return Err(msg)
|
|
||||||
}
|
|
||||||
match command.unwrap() {
|
|
||||||
"help" | "h" => self::help(),
|
|
||||||
|
|
||||||
// multiboot
|
|
||||||
// "memory" => self::mb2_memory(),
|
|
||||||
// "multiboot" => self::mb2_info(),
|
|
||||||
// "sections" => self::mb2_sections(),
|
|
||||||
|
|
||||||
// ACPI
|
|
||||||
"acpi" => self::acpi_info(),
|
|
||||||
"reboot" => self::reboot(),
|
|
||||||
"shutdown" | "halt" | "q" => self::shutdown(),
|
|
||||||
|
|
||||||
// x86 specific
|
|
||||||
"stack" => self::print_stack(),
|
|
||||||
"regs" => self::regs(),
|
|
||||||
"cpu" => self::cpu(),
|
|
||||||
"int3" => self::int3(),
|
|
||||||
"overflow" => self::overflow(),
|
|
||||||
"page_fault" => self::page_fault(),
|
|
||||||
|
|
||||||
// time
|
|
||||||
"uptime" => self::uptime(),
|
|
||||||
|
|
||||||
_ => Err("Command unknown. (try help)"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn help() -> Result<(), &'static str> {
|
|
||||||
println!("help | h => print this help");
|
|
||||||
// println!("memory => Print memory areas");
|
|
||||||
// println!("multiboot => Print multiboot information");
|
|
||||||
// println!("sections => Print elf sections");
|
|
||||||
println!("reboot => reboot");
|
|
||||||
println!("shutdown | halt | q => acpi shutdown");
|
|
||||||
println!("acpi => acpi state");
|
|
||||||
println!("stack => print kernel stack in a fancy way");
|
|
||||||
println!("regs => print controle register");
|
|
||||||
println!("cpu => print cpu information");
|
|
||||||
println!("overflow => triggers a stack overflow");
|
|
||||||
println!("page_fault => triggers a page fault on 0xdead");
|
|
||||||
flush!();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uptime() -> Result<(), &'static str> {
|
|
||||||
let mut offset = time::OFFSET.lock();
|
|
||||||
fprintln!("{}s", offset.0 + offset.1 / 1_000_000);
|
|
||||||
flush!();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
use x86::instructions::halt;
|
|
||||||
/// Reboot the kernel
|
|
||||||
///
|
|
||||||
/// If reboot failed, will loop on a halt cmd
|
|
||||||
///
|
|
||||||
fn reboot() -> ! {
|
|
||||||
match acpi::reboot() {
|
|
||||||
Err(msg) => println!("{}", msg),
|
Err(msg) => println!("{}", msg),
|
||||||
_ => println!("Unable to perform ACPI reboot."),
|
Ok(func) => (func)(),
|
||||||
}
|
}
|
||||||
flush!();
|
|
||||||
unsafe { PS2.ps2_8042_reset() }; // TODO unsafe
|
|
||||||
println!("Unable to perform 8042 reboot. Kernel will be halted");
|
|
||||||
flush!();
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shutdown the kernel
|
|
||||||
///
|
|
||||||
/// If shutdown is performed but failed, will loop on a halt cmd
|
|
||||||
/// If shutdown cannot be called, return a Err(&str)
|
|
||||||
///
|
|
||||||
fn shutdown() -> ! {
|
|
||||||
match acpi::shutdown() {
|
|
||||||
Err(msg) => println!("{}", msg),
|
|
||||||
_ => println!("Unable to perform ACPI shutdown. Kernel will be halted"),
|
|
||||||
}
|
}
|
||||||
flush!();
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hexdump(start: usize, end: usize) {
|
|
||||||
let mut address = 0;
|
|
||||||
let data = unsafe { core::slice::from_raw_parts_mut(start as *mut u8, end - start) };
|
|
||||||
while address <= data.len() {
|
|
||||||
let next_end = core::cmp::min(address + 16, data.len());
|
|
||||||
print_line(&data[address..next_end], address + start);
|
|
||||||
address = address + 16;
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_control(c: char) -> bool {
|
|
||||||
!(c >= ' ' && c <= '~')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_line(line: &[u8], address: usize) {
|
|
||||||
print!("\n{:#08x}: ", address);
|
|
||||||
for byte in line {
|
|
||||||
print!("{:02x} ", *byte);
|
|
||||||
}
|
|
||||||
let length: usize = 16 - line.len();
|
|
||||||
for _ in 0..length {
|
|
||||||
print!(" ");
|
|
||||||
}
|
|
||||||
print!("|");
|
|
||||||
for byte in line {
|
|
||||||
match is_control(*byte as char) {
|
|
||||||
true => print!("."),
|
|
||||||
false => print!("{}", *byte as char),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
print!("|");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print the kernel stack
|
|
||||||
pub fn print_stack() -> Result<(), &'static str> {
|
|
||||||
let esp: usize;
|
|
||||||
let ebp: usize;
|
|
||||||
unsafe { asm!("" : "={esp}"(esp), "={ebp}"(ebp):::) };
|
|
||||||
println!("esp = {:#x}", esp);
|
|
||||||
println!("ebp = {:#x}", ebp);
|
|
||||||
println!("size = {:#X} bytes", ebp - esp);
|
|
||||||
hexdump(esp, ebp);
|
|
||||||
flush!();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn mb2_memory() -> Result <(), &'static str> {
|
|
||||||
// let boot_info = ::multiboot2::boot_info();
|
|
||||||
|
|
||||||
// let memory_map_tag = boot_info.memory_map_tag()
|
|
||||||
// .expect("Memory map tag required");
|
|
||||||
|
|
||||||
// println!("memory areas:");
|
|
||||||
// for area in memory_map_tag.memory_areas() {
|
|
||||||
// println!(" start: 0x{:x}, length: 0x{:x}",
|
|
||||||
// area.start_address(), area.size());
|
|
||||||
// }
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn mb2_sections() -> Result <(), &'static str> {
|
|
||||||
// let boot_info = ::multiboot2::boot_info();
|
|
||||||
|
|
||||||
// let elf_sections_tag = boot_info.elf_sections_tag()
|
|
||||||
// .expect("Elf-sections tag required");
|
|
||||||
|
|
||||||
// println!("kernel sections:");
|
|
||||||
// for section in elf_sections_tag.sections() {
|
|
||||||
// println!(" {: <10} {:#x}, size: {:#x}, flags: {:#X}",
|
|
||||||
// section.name(), section.start_address(), section.size(), section.flags());
|
|
||||||
// }
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn mb2_info() -> Result <(), &'static str> {
|
|
||||||
// let boot_info = context::boot_info();
|
|
||||||
|
|
||||||
// let command_line_tag = boot_info.command_line_tag()
|
|
||||||
// .expect("Elf-sections tag required");
|
|
||||||
|
|
||||||
// let bootloader_tag = boot_info.boot_loader_name_tag()
|
|
||||||
// .expect("Elf-sections tag required");
|
|
||||||
|
|
||||||
// println!("bootloader: {}", bootloader_tag.name());
|
|
||||||
// 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(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dump control registers
|
|
||||||
pub fn regs() -> Result<(), &'static str> {
|
|
||||||
use x86::registers::control::*;
|
|
||||||
use x86::instructions::tables::tr;
|
|
||||||
use x86::instructions::segmentation::*;
|
|
||||||
use x86::registers::flags::*;
|
|
||||||
use x86::structures::gdt;
|
|
||||||
println!("cr0 = {:?}", Cr0::read());
|
|
||||||
println!("cr3 = {:?}", Cr3::read());
|
|
||||||
println!("cr4 = {:?}", Cr4::read());
|
|
||||||
println!("flags= {:?}", flags());
|
|
||||||
println!("tr = {:?}", tr());
|
|
||||||
println!("ss = {:?}", ss());
|
|
||||||
println!("cs = {:?}", cs());
|
|
||||||
println!("ds = {:?}", ds());
|
|
||||||
println!("es = {:?}", es());
|
|
||||||
println!("fs = {:?}", fs());
|
|
||||||
println!("gs = {:?}", gs());
|
|
||||||
unsafe {
|
|
||||||
println!(
|
|
||||||
"tss = {:#?}",
|
|
||||||
gdt::Descriptor(::arch::x86::gdt::GDT.table[tr().index() as usize])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
flush!();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dump cpu info, should add power management info
|
|
||||||
pub fn cpu() -> Result<(), &'static str> {
|
|
||||||
use arch::x86::devices::cpu;
|
|
||||||
cpu::cpu_info().expect("cpu info not available");
|
|
||||||
flush!();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn int3() -> Result<(), &'static str> {
|
|
||||||
use x86;
|
|
||||||
x86::instructions::interrupts::int3();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unconditional_recursion)]
|
|
||||||
pub fn overflow() -> Result<(), &'static str> {
|
|
||||||
fn stack_overflow() {
|
|
||||||
stack_overflow();
|
|
||||||
}
|
|
||||||
stack_overflow();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn page_fault() -> Result<(), &'static str> {
|
|
||||||
unsafe {
|
|
||||||
*(0xdead as *mut u32) = 42;
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,9 @@ pub fn kmain() -> ! {
|
||||||
// unsafe VGA
|
// unsafe VGA
|
||||||
unsafe { console::CONSOLE.init(); }
|
unsafe { console::CONSOLE.init(); }
|
||||||
|
|
||||||
pci::lspci();
|
if let Ok(slot) = pci::get_ide1() {
|
||||||
|
println!("found IDE at slot {}", slot);
|
||||||
|
}
|
||||||
// scheduler WIP
|
// scheduler WIP
|
||||||
// scheduling::schedule();
|
// scheduling::schedule();
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
|
|
||||||
|
|
@ -101,3 +101,63 @@ pub fn init_noncore() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// for console
|
||||||
|
#[allow(unconditional_recursion)]
|
||||||
|
pub fn overflow() {
|
||||||
|
overflow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// for console
|
||||||
|
pub fn page_fault() {
|
||||||
|
unsafe {
|
||||||
|
*(0xdead as *mut u32) = 42;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print the kernel stack
|
||||||
|
pub fn print_stack() {
|
||||||
|
fn hexdump(start: usize, end: usize) {
|
||||||
|
let mut address = 0;
|
||||||
|
let data = unsafe { core::slice::from_raw_parts_mut(start as *mut u8, end - start) };
|
||||||
|
while address <= data.len() {
|
||||||
|
let next_end = core::cmp::min(address + 16, data.len());
|
||||||
|
print_line(&data[address..next_end], address + start);
|
||||||
|
address = address + 16;
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_control(c: char) -> bool {
|
||||||
|
!(c >= ' ' && c <= '~')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_line(line: &[u8], address: usize) {
|
||||||
|
print!("\n{:#08x}: ", address);
|
||||||
|
for byte in line {
|
||||||
|
print!("{:02x} ", *byte);
|
||||||
|
}
|
||||||
|
let length: usize = 16 - line.len();
|
||||||
|
for _ in 0..length {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
print!("|");
|
||||||
|
for byte in line {
|
||||||
|
match is_control(*byte as char) {
|
||||||
|
true => print!("."),
|
||||||
|
false => print!("{}", *byte as char),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
print!("|");
|
||||||
|
}
|
||||||
|
|
||||||
|
let esp: usize;
|
||||||
|
let ebp: usize;
|
||||||
|
unsafe { asm!("" : "={esp}"(esp), "={ebp}"(ebp):::) };
|
||||||
|
println!("esp = {:#x}", esp);
|
||||||
|
println!("ebp = {:#x}", ebp);
|
||||||
|
println!("size = {:#X} bytes", ebp - esp);
|
||||||
|
hexdump(esp, ebp);
|
||||||
|
flush!();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,79 @@
|
||||||
// https://wiki.osdev.org/PCI
|
// https://wiki.osdev.org/PCI
|
||||||
|
|
||||||
use x86::devices::io::{Pio};
|
use x86::devices::io::{Pio, Io};
|
||||||
|
|
||||||
pub static mut PCI_CONFIG_ADDRESS: Pio<u8> = Pio::new(0xCF8);
|
pub static mut PCI_CONFIG_ADDRESS: Pio<u32> = Pio::new(0xCF8);
|
||||||
pub static mut PCI_CONFIG_DATA: Pio<u8> = Pio::new(0xCFC);
|
pub static mut PCI_CONFIG_DATA: Pio<u32> = Pio::new(0xCFC);
|
||||||
|
|
||||||
|
pub fn get_ide1() -> Result<u32, ()> {
|
||||||
|
let bus = 0;
|
||||||
|
|
||||||
|
for slot in 0..31 {
|
||||||
|
let vendor = pci_config_read_word(bus, slot, 0, 0);
|
||||||
|
if vendor == 0xffff {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let class = pci_config_read_byte(bus, slot, 0, 11);
|
||||||
|
let subclass = pci_config_read_byte(bus, slot, 0, 10);
|
||||||
|
if class == 0x01 && subclass == 0x01 {
|
||||||
|
return Ok(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lspci() {
|
pub fn lspci() {
|
||||||
pci_config_read_word(1, 1, 1, 2);
|
let bus = 0;
|
||||||
|
|
||||||
|
for slot in 0..31 {
|
||||||
|
let vendor = pci_config_read_word(bus, slot, 0, 0);
|
||||||
|
if vendor == 0xffff {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let header_type = pci_config_read_byte(bus, slot, 0, 14) ;
|
||||||
|
if header_type & 0x80 != 0 {
|
||||||
|
// device has multiple functions
|
||||||
|
for function in 0..0x7 {
|
||||||
|
let vendor = pci_config_read_word(bus, slot, function, 0);
|
||||||
|
if vendor != 0xffff {
|
||||||
|
pci_display(bus, slot, function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pci_display(bus, slot, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pci_config_read_word(bus: u32, slot: u32, func: u32, offset: u32) {
|
pub fn pci_display(bus: u32, slot: u32, function: u32) {
|
||||||
// let address: u64 = (bus as u32) << 16
|
let vendor = pci_config_read_word(bus, slot, function, 0);
|
||||||
// | (slot as u32) << 11
|
let device = pci_config_read_word(bus, slot, function, 2);
|
||||||
// | (func as u32) << 8
|
let class = pci_config_read_byte(bus, slot, function, 11);
|
||||||
// | (offset as u32) & 0xfc
|
let subclass = pci_config_read_byte(bus, slot, function, 10);
|
||||||
// | 0x80000000;
|
println!("{}:{}.{} {:#x},{:#x}: {:#x} {:#x}",
|
||||||
let address: u64 = 0x80000000;
|
bus, slot, function, class, subclass, vendor, device);
|
||||||
println!("{} {} {} {}", bus, slot, func, offset);
|
}
|
||||||
println!("{:#x}", address);
|
|
||||||
println!("{:#b}", address);
|
pub fn pci_access(bus: u32, slot: u32, func: u32, offset: u32) {
|
||||||
|
let address = (bus as u32) << 16
|
||||||
|
| (slot as u32) << 11
|
||||||
|
| (func as u32) << 8
|
||||||
|
| (offset as u32) & 0xfc
|
||||||
|
| 0x80000000;
|
||||||
|
unsafe { PCI_CONFIG_ADDRESS.write(address); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pci_config_read_doubleword(bus: u32, slot: u32, func: u32, offset: u32) -> u32 {
|
||||||
|
pci_access(bus, slot, func, offset);
|
||||||
|
unsafe { PCI_CONFIG_DATA.read() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pci_config_read_word(bus: u32, slot: u32, func: u32, offset: u32) -> u16 {
|
||||||
|
pci_access(bus, slot, func, offset);
|
||||||
|
unsafe { (PCI_CONFIG_DATA.read() >> ((offset & 2) * 8)) as u16 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pci_config_read_byte(bus: u32, slot: u32, func: u32, offset: u32) -> u8 {
|
||||||
|
pci_access(bus, slot, func, offset);
|
||||||
|
unsafe { (PCI_CONFIG_DATA.read() >> ((offset & 3) * 8)) as u8 }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,3 +15,8 @@ pub fn realtime() -> (u32, u32) {
|
||||||
let sum = start.1 + offset.1;
|
let sum = start.1 + offset.1;
|
||||||
(start.0 + offset.0 + sum / 1_000_000, sum % 1_000_000)
|
(start.0 + offset.0 + sum / 1_000_000, sum % 1_000_000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn uptime() {
|
||||||
|
let mut offset = self::OFFSET.lock();
|
||||||
|
println!("{}s", offset.0 + offset.1 / 1_000_000);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ pub mod cursor;
|
||||||
pub use self::color::{Color, ColorCode};
|
pub use self::color::{Color, ColorCode};
|
||||||
use self::cursor::CURSOR;
|
use self::cursor::CURSOR;
|
||||||
|
|
||||||
use console;
|
|
||||||
|
|
||||||
pub static mut VGA: Writer = self::Writer::new();
|
pub static mut VGA: Writer = self::Writer::new();
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -16,6 +14,7 @@ struct ScreenChar {
|
||||||
}
|
}
|
||||||
|
|
||||||
// print wrapper macro around vga
|
// print wrapper macro around vga
|
||||||
|
#[allow(unused_macros)]
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
($($arg:tt)*) => ({
|
($($arg:tt)*) => ({
|
||||||
$crate::vga::print(format_args!($($arg)*));
|
$crate::vga::print(format_args!($($arg)*));
|
||||||
|
|
@ -23,6 +22,7 @@ macro_rules! print {
|
||||||
}
|
}
|
||||||
|
|
||||||
// flushed print
|
// flushed print
|
||||||
|
#[allow(unused_macros)]
|
||||||
macro_rules! fprint {
|
macro_rules! fprint {
|
||||||
($($arg:tt)*) => ({
|
($($arg:tt)*) => ({
|
||||||
print!($($arg)*);
|
print!($($arg)*);
|
||||||
|
|
@ -31,12 +31,15 @@ macro_rules! fprint {
|
||||||
}
|
}
|
||||||
|
|
||||||
// print with a line feed
|
// print with a line feed
|
||||||
|
#[allow(unused_macros)]
|
||||||
macro_rules! println {
|
macro_rules! println {
|
||||||
|
() => ({print!("\n")});
|
||||||
($fmt:expr) => (print!(concat!($fmt, "\n")));
|
($fmt:expr) => (print!(concat!($fmt, "\n")));
|
||||||
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
||||||
}
|
}
|
||||||
|
|
||||||
// flushed println
|
// flushed println
|
||||||
|
#[allow(unused_macros)]
|
||||||
macro_rules! fprintln {
|
macro_rules! fprintln {
|
||||||
($($arg:tt)*) => ({
|
($($arg:tt)*) => ({
|
||||||
println!($($arg)*);
|
println!($($arg)*);
|
||||||
|
|
@ -73,8 +76,6 @@ pub struct Writer {
|
||||||
pub buffer_pos: usize,
|
pub buffer_pos: usize,
|
||||||
pub color_code: ColorCode,
|
pub color_code: ColorCode,
|
||||||
buffer: [u8; BUFFER_ROWS * BUFFER_COLS],
|
buffer: [u8; BUFFER_ROWS * BUFFER_COLS],
|
||||||
command: [u8; 10],
|
|
||||||
command_len: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Writer {
|
impl Writer {
|
||||||
|
|
@ -83,46 +84,36 @@ impl Writer {
|
||||||
buffer_pos: 0,
|
buffer_pos: 0,
|
||||||
color_code: ColorCode::new(Color::White, Color::Black),
|
color_code: ColorCode::new(Color::White, Color::Black),
|
||||||
buffer: [0; BUFFER_ROWS * BUFFER_COLS],
|
buffer: [0; BUFFER_ROWS * BUFFER_COLS],
|
||||||
command: [b'\0'; 10],
|
|
||||||
command_len: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 erase_byte(&mut self) {
|
pub fn erase_byte(&mut self) {
|
||||||
self.buffer_pos -= 2;
|
self.buffer_pos -= 2;
|
||||||
let i = self.buffer_pos;
|
let i = self.buffer_pos;
|
||||||
self.buffer[i] = b' ';
|
self.buffer[i] = b' ';
|
||||||
self.buffer[i + 1] = self.color_code.0;
|
self.buffer[i + 1] = self.color_code.0;
|
||||||
self.flush();
|
self.flush();
|
||||||
// flush!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_byte(&mut self, byte: u8) {
|
pub fn write_byte(&mut self, byte: u8) {
|
||||||
let i = self.buffer_pos;
|
|
||||||
|
|
||||||
match byte {
|
match byte {
|
||||||
b'\n' => {
|
b'\n' => {
|
||||||
let current_line = self.buffer_pos / (BUFFER_COLS);
|
let current_line = self.buffer_pos / (BUFFER_COLS);
|
||||||
self.buffer_pos = (current_line + 1) * BUFFER_COLS;
|
self.buffer_pos = (current_line + 1) * BUFFER_COLS;
|
||||||
}
|
}
|
||||||
byte => {
|
byte => {
|
||||||
self.buffer[i] = byte;
|
self.buffer[self.buffer_pos] = byte;
|
||||||
self.buffer[i + 1] = self.color_code.0;
|
self.buffer[self.buffer_pos + 1] = self.color_code.0;
|
||||||
self.buffer_pos += 2;
|
self.buffer_pos += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.buffer_pos >= self.buffer.len() {
|
if self.buffer_pos >= self.buffer.len() {
|
||||||
self.scroll();
|
self.scroll();
|
||||||
|
self.flush();
|
||||||
}
|
}
|
||||||
|
// flushing here is correct but slow
|
||||||
|
// self.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_str(&mut self, s: &str) {
|
pub fn write_str(&mut self, s: &str) {
|
||||||
|
|
@ -132,9 +123,7 @@ impl Writer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_cursor(&self) {
|
fn flush_cursor(&self) {
|
||||||
unsafe {
|
unsafe { CURSOR.flush(self.buffer_pos / 2); }
|
||||||
CURSOR.flush(self.buffer_pos / 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flush(&mut self) {
|
pub fn flush(&mut self) {
|
||||||
|
|
@ -157,7 +146,6 @@ impl Writer {
|
||||||
self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col + 1)] =
|
self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col + 1)] =
|
||||||
ColorCode::new(Color::White, Color::Black).0;
|
ColorCode::new(Color::White, Color::Black).0;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.buffer_pos = (BUFFER_ROWS - 1) * BUFFER_COLS;
|
self.buffer_pos = (BUFFER_ROWS - 1) * BUFFER_COLS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue