/src/apps/shell.rs
use core::{num::ParseIntError, slice};
use crate::stdlib;
enum CommandError {
BadCommand,
BadAddress,
NeedArgument,
}
impl From<ParseIntError> for CommandError {
fn from(_value: ParseIntError) -> Self {
CommandError::BadAddress
}
}
fn readline(buf: &mut [u8]) -> Option<&str> {
let mut inbuf = [0u8; 100];
let mut i = 0;
loop {
let n_read = stdlib::read(buf);
for b in &buf[..n_read] {
match *b {
b'\r' | b'\n' => {
stdlib::print("\r\n");
// TODO: don't dump the rest of the buffer
buf.copy_from_slice(&inbuf);
let s = core::str::from_utf8(&buf[..i]).unwrap();
return Some(s);
}
0x08 => {
if i > 0 {
stdlib::print("\x08 \x08");
i -= 1;
}
}
0x03 => {
stdlib::print("\r\n");
return None;
}
b => {
inbuf[i] = b;
stdlib::write(&inbuf[i..i + 1]);
i += 1;
}
}
}
}
}
fn format_hex_u32(buf: &mut [u8], mut n: u32) {
let mut i: i32 = 7;
while i >= 0 {
let d = n & 0xF;
buf[i as usize] = match d {
0..=9 => (0x30 + d) as u8,
_ => (0x41 - 10 + d) as u8,
};
i -= 1;
n >>= 4;
}
}
fn print_hex_u32(n: u32) {
let mut hexbuf = [0u8; 8];
format_hex_u32(&mut hexbuf, n);
stdlib::write(&hexbuf);
}
fn read_addr(a: u32) -> u32 {
unsafe {
let ptr = a as *const u32;
*ptr
}
}
fn parse_cmdline(cmdline: &str) -> Result<(), CommandError> {
let mut parts = cmdline.split_ascii_whitespace();
let cmd = parts.next().ok_or(CommandError::BadCommand)?;
match cmd {
"r" => {
let astr = parts.next().ok_or(CommandError::NeedArgument)?;
let mut aparts = astr.split('.');
let from = aparts
.next()
.map(|s| u32::from_str_radix(s, 16))
.ok_or(CommandError::BadAddress)??;
print_hex_u32(from);
stdlib::print(": ");
match aparts.next() {
Some(to) => {
let to = u32::from_str_radix(to, 16)?;
let mut line_c = 0;
for addr in (from..to).step_by(4) {
if line_c == 4 {
stdlib::print("\r\n");
print_hex_u32(addr);
stdlib::print(": ");
line_c = 0;
}
print_hex_u32(read_addr(addr));
stdlib::print(" ");
line_c += 1;
}
}
None => {
print_hex_u32(read_addr(from));
}
};
stdlib::print("\r\n");
Ok(())
}
"q" => {
stdlib::exit();
}
"dog" | "cat" => {
let tid = stdlib::spawn(if cmd == "cat" { cat } else { dog });
if tid == 0xFFFFFFFF {
stdlib::print("Failed to launch ");
stdlib::print(cmd);
stdlib::print("\r\n");
} else {
stdlib::print("spawned ");
stdlib::print(cmd);
stdlib::print(" at tid ");
print_hex_u32(tid);
stdlib::print("\r\n");
}
Ok(())
}
"ps" => {
stdlib::ps();
Ok(())
}
"unaligned" => unsafe {
let p = 2 as *const u32;
print_hex_u32(*p);
Ok(())
}
"instr" => unsafe {
let b: &[u16; 2] = &[0xf7f0, 0xa000]; // Should be an undefined instruction
let fp: fn() = core::mem::transmute(b);
fp();
Ok(())
}
"panic" => {
panic!("Test panic");
}
"kernelpanic" => {
stdlib::kernel_panic();
Ok(())
}
"k" => {
let mut keybits = [0u32; 3];
let mut db = [0u8; 1];
stdlib::kb_read_matrix(&mut keybits);
stdlib::print(" c1 c2 c3 c4 c5 c6 c7 c8 c9\r\n");
for r in 0..9 {
stdlib::print("r");
db[0] = 0x30 + r + 1;
stdlib::write(&db);
for c in 0..9 {
let i = (r * 9 + c) as usize;
if keybits[i / 32] & 1 << (i % 32) != 0 {
db[0] = 0x31;
} else {
db[0] = 0x30;
}
stdlib::print(" ");
stdlib::write(&db);
}
stdlib::print("\r\n");
}
Ok(())
}
_ => Err(CommandError::BadCommand),
}
}
pub fn shell(base: u32, _size: u32) -> ! {
let mut input_buffer = unsafe { slice::from_raw_parts_mut(base as *mut u8, 100) };
stdlib::sleep(1000);
stdlib::print("\r\nShell 0.1\r\n");
loop {
stdlib::print("> ");
if let Some(cmdline) = readline(&mut input_buffer) {
match parse_cmdline(cmdline) {
Ok(_) => (),
Err(CommandError::BadCommand) => stdlib::print("Bad command\r\n"),
Err(CommandError::BadAddress) => stdlib::print("Bad address\r\n"),
Err(CommandError::NeedArgument) => stdlib::print("Need argument\r\n"),
}
}
}
}
fn cat(_base: u32, _size: u32) -> ! {
stdlib::sleep(1000);
unsafe {
// Try to read kernel memory
let p = 0x20040000 as *const u32;
let b = *p;
stdlib::sleep(b);
}
stdlib::exit();
}
fn dog(_base: u32, _size: u32) -> ! {
for _ in 0..10 {
stdlib::print("woof\r\n");
stdlib::sleep(1500);
}
stdlib::exit();
}