lspci, console refactor

This commit is contained in:
Jack Halford 2019-01-20 22:11:14 +01:00
parent 85afa2b437
commit c9ad4e9e58
10 changed files with 250 additions and 327 deletions

View file

@ -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
pub fn init() -> Result<(), &'static str> {
if let Ok(()) = is_init() {
if unsafe{ACPI.valid} {
return Ok(());
}
unsafe { ACPI.init() }
@ -144,7 +136,7 @@ pub fn init() -> Result<(), &'static str> {
/// Load the ACPI module, addr given is a ptr to RSDP
pub fn load(rsdp_addr: u32) -> Result<(), &'static str> {
if let Ok(()) = is_init() {
if unsafe{ACPI.valid} {
return Ok(());
}
unsafe { ACPI.load(rsdp_addr) }
@ -152,32 +144,30 @@ pub fn load(rsdp_addr: u32) -> Result<(), &'static str> {
/// 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()?)
pub fn shutdown() {
if unsafe{ACPI.valid} { return }
dsdt::shutdown(fadt::get_controlblock().unwrap());
}
/// Proceed to ACPI reboot
/// This function need ACPI in v2
pub fn reboot() -> Result<(), &'static str> {
is_init()?;
pub fn reboot() {
if unsafe {!ACPI.valid} {
println!("ACPI not initialized");
}
if unsafe { ACPI.v2 } {
fadt::reboot()
fadt::reboot().unwrap()
} else {
Err("ACPI reboot only available in ACPI v2+")
println!("ACPI reboot only available in ACPI v2+");
}
}
/// Display state of ACPI
pub fn info() -> Result<(), &'static str> {
is_init()?;
println!(
"ACPI STATE:\n {}",
if fadt::is_enable()? {
"ENABLED"
} else {
"DISABLED"
}
);
Ok(())
pub fn info() {
if unsafe { !ACPI.valid } { println!("ACPI not initialized"); return }
match fadt::is_enable() {
Ok(True) => println!("ACPI is disabled"),
Ok(False) => println!("ACPI is disabled"),
Err(msg) => println!("error while checking ACPI")
}
}

View file

@ -23,5 +23,5 @@ pub unsafe fn init(active_table: &mut ActivePageTable) {
#[alloc_error_handler]
fn foo(_: core::alloc::Layout) -> ! {
panic!();
panic!("alloc_error_handler");
}

View file

@ -1,10 +1,8 @@
extern crate raw_cpuid;
use core::fmt::Result;
use self::raw_cpuid::CpuId;
pub fn cpu_info() -> Result {
pub fn cpu_info() {
let cpuid = CpuId::new();
if let Some(info) = cpuid.get_vendor_info() {
@ -285,6 +283,4 @@ pub fn cpu_info() -> Result {
};
println!("");
}
Ok(())
}

View file

@ -17,10 +17,6 @@ pub unsafe extern "C" fn x86_rust_start(multiboot_info_addr: usize) {
// parse multiboot2 info
let boot_info = multiboot2::load(multiboot_info_addr);
// println!("{:?}", boot_info);
// flush!();
// asm!("hlt");
// ACPI must be intialized BEFORE paging is active
if let Some(rsdp) = boot_info.rsdp_v2_tag() {
acpi::load(rsdp).expect("ACPI failed");
@ -116,3 +112,30 @@ pub unsafe fn usermode(ip: u32, sp: u32) -> ! {
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!();
}

View file

@ -1,14 +1,49 @@
extern crate core;
// extern crate multiboot2;
use acpi;
use time;
use keyboard::PS2;
use core::char;
use vga::*;
use alloc::collections::BTreeMap;
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 {
command: [u8; 10],
command_len: usize,
@ -54,11 +89,7 @@ impl Console {
}
b'\n' => {
unsafe { VGA.write_byte(b'\n'); }
if let Err(msg) = self.exec() {
set_color!(Red);
println!("{}", msg);
set_color!();
}
self.exec();
self.command_len = 0;
self.prompt();
}
@ -73,256 +104,27 @@ impl Console {
self.command_len += 1;
}
}
flush!();
unsafe { VGA.flush(); }
}
fn get_command(&self) -> Result<&str, &'static str> {
fn get_command(&self) -> Result<fn(), &'static str> {
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"),
}
}
pub fn exec(&self) -> core::result::Result<(), &'static str> {
pub fn exec(&self) {
let command = self.get_command();
if let Err(msg) = 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)"),
match command {
Err(msg) => println!("{}", msg),
Ok(func) => (func)(),
}
}
}
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),
_ => println!("Unable to perform ACPI reboot."),
}
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(())
}

View file

@ -51,7 +51,9 @@ pub fn kmain() -> ! {
// unsafe VGA
unsafe { console::CONSOLE.init(); }
pci::lspci();
if let Ok(slot) = pci::get_ide1() {
println!("found IDE at slot {}", slot);
}
// scheduler WIP
// scheduling::schedule();
unreachable!();

View file

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

View file

@ -1,22 +1,79 @@
// 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_DATA: Pio<u8> = Pio::new(0xCFC);
pub static mut PCI_CONFIG_ADDRESS: Pio<u32> = Pio::new(0xCF8);
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() {
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) {
// let address: u64 = (bus as u32) << 16
// | (slot as u32) << 11
// | (func as u32) << 8
// | (offset as u32) & 0xfc
// | 0x80000000;
let address: u64 = 0x80000000;
println!("{} {} {} {}", bus, slot, func, offset);
println!("{:#x}", address);
println!("{:#b}", address);
pub fn pci_display(bus: u32, slot: u32, function: u32) {
let vendor = pci_config_read_word(bus, slot, function, 0);
let device = pci_config_read_word(bus, slot, function, 2);
let class = pci_config_read_byte(bus, slot, function, 11);
let subclass = pci_config_read_byte(bus, slot, function, 10);
println!("{}:{}.{} {:#x},{:#x}: {:#x} {:#x}",
bus, slot, function, class, subclass, vendor, device);
}
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 }
}

View file

@ -15,3 +15,8 @@ pub fn realtime() -> (u32, u32) {
let sum = start.1 + offset.1;
(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);
}

View file

@ -4,8 +4,6 @@ pub mod cursor;
pub use self::color::{Color, ColorCode};
use self::cursor::CURSOR;
use console;
pub static mut VGA: Writer = self::Writer::new();
#[derive(Debug, Clone, Copy)]
@ -16,6 +14,7 @@ struct ScreenChar {
}
// print wrapper macro around vga
#[allow(unused_macros)]
macro_rules! print {
($($arg:tt)*) => ({
$crate::vga::print(format_args!($($arg)*));
@ -23,6 +22,7 @@ macro_rules! print {
}
// flushed print
#[allow(unused_macros)]
macro_rules! fprint {
($($arg:tt)*) => ({
print!($($arg)*);
@ -31,12 +31,15 @@ macro_rules! fprint {
}
// print with a line feed
#[allow(unused_macros)]
macro_rules! println {
() => ({print!("\n")});
($fmt:expr) => (print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
// flushed println
#[allow(unused_macros)]
macro_rules! fprintln {
($($arg:tt)*) => ({
println!($($arg)*);
@ -73,8 +76,6 @@ pub struct Writer {
pub buffer_pos: usize,
pub color_code: ColorCode,
buffer: [u8; BUFFER_ROWS * BUFFER_COLS],
command: [u8; 10],
command_len: usize,
}
impl Writer {
@ -83,46 +84,36 @@ impl Writer {
buffer_pos: 0,
color_code: ColorCode::new(Color::White, Color::Black),
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) {
self.buffer_pos -= 2;
let i = self.buffer_pos;
self.buffer[i] = b' ';
self.buffer[i + 1] = self.color_code.0;
self.flush();
// flush!();
}
pub fn write_byte(&mut self, byte: u8) {
let i = self.buffer_pos;
match byte {
b'\n' => {
let current_line = self.buffer_pos / (BUFFER_COLS);
self.buffer_pos = (current_line + 1) * BUFFER_COLS;
}
byte => {
self.buffer[i] = byte;
self.buffer[i + 1] = self.color_code.0;
self.buffer[self.buffer_pos] = byte;
self.buffer[self.buffer_pos + 1] = self.color_code.0;
self.buffer_pos += 2;
}
}
if self.buffer_pos >= self.buffer.len() {
self.scroll();
self.flush();
}
// flushing here is correct but slow
// self.flush();
}
pub fn write_str(&mut self, s: &str) {
@ -132,9 +123,7 @@ impl Writer {
}
fn flush_cursor(&self) {
unsafe {
CURSOR.flush(self.buffer_pos / 2);
}
unsafe { CURSOR.flush(self.buffer_pos / 2); }
}
pub fn flush(&mut self) {
@ -157,7 +146,6 @@ impl Writer {
self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col + 1)] =
ColorCode::new(Color::White, Color::Black).0;
}
self.buffer_pos = (BUFFER_ROWS - 1) * BUFFER_COLS;
}
}