235 lines
6.6 KiB
Rust
235 lines
6.6 KiB
Rust
extern crate core;
|
|
// extern crate multiboot2;
|
|
|
|
use acpi;
|
|
use keyboard::PS2;
|
|
use core::char;
|
|
use vga::*;
|
|
|
|
fn dispatch(command: &str) -> Result<(), &'static str> {
|
|
match command {
|
|
"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(),
|
|
|
|
_ => Err("Command unknown. (h|help for help)"),
|
|
}
|
|
}
|
|
|
|
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> {
|
|
println!("acpi => Return acpi state (ENABLED|DISABLE)");
|
|
println!("help | h => Print this help");
|
|
// println!("memory => Print memory areas");
|
|
// println!("multiboot => Print multiboot information");
|
|
println!("reboot => Reboot");
|
|
// println!("sections => Print elf sections");
|
|
println!("shutdown | halt | q => Kill a kitten, then shutdown");
|
|
println!("stack => Print kernel stack in a fancy way");
|
|
println!("regs => Print controle register");
|
|
println!("cpu => Print cpu information");
|
|
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::device::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(())
|
|
}
|