Archived
feat(keyboard): clean rewrite of PS/2 driver and restore full Unix shell
This commit is contained in:
+125
-152
@@ -1,120 +1,44 @@
|
||||
//! PS/2 Keyboard Driver (IRQ 1 & Direct Polling).
|
||||
//! PS/2 Keyboard Driver (IRQ 1 & Polling fallback).
|
||||
//!
|
||||
//! Декодирует Scancodes (полная поддержка Set 1 и Set 2) и передаёт символы в шелл.
|
||||
//! Полностью переписанный драйвер PS/2 клавиатуры для x86_64 (Scancode Set 1).
|
||||
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
const KEYBOARD_STATUS_PORT: u16 = 0x64;
|
||||
const KEYBOARD_DATA_PORT: u16 = 0x60;
|
||||
const KBD_DATA_PORT: u16 = 0x60;
|
||||
const KBD_STATUS_PORT: u16 = 0x64;
|
||||
const KBD_CMD_PORT: u16 = 0x64;
|
||||
|
||||
static KEYBOARD_BUFFER: Mutex<KeyboardBuffer> = Mutex::new(KeyboardBuffer::new());
|
||||
static KEYBOARD: Mutex<KeyboardState> = Mutex::new(KeyboardState::new());
|
||||
|
||||
fn wait_input_empty() {
|
||||
unsafe {
|
||||
let mut status: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
|
||||
for _ in 0..100_000 {
|
||||
if (status.read() & 0x02) == 0 {
|
||||
return;
|
||||
}
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_output_full() -> bool {
|
||||
unsafe {
|
||||
let mut status: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
|
||||
for _ in 0..100_000 {
|
||||
if (status.read() & 0x01) != 0 {
|
||||
return true;
|
||||
}
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Инициализировать контроллер PS/2 клавиатуры (включить порт 1, Set 1 и сканирование).
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
let mut status: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
|
||||
let mut data: Port<u8> = Port::new(KEYBOARD_DATA_PORT);
|
||||
|
||||
// 1. Включаем первый порт PS/2 (команда 0xAE)
|
||||
wait_input_empty();
|
||||
status.write(0xAE);
|
||||
|
||||
// 2. Читаем текущий байт конфигурации 8042 (команда 0x20)
|
||||
wait_input_empty();
|
||||
status.write(0x20);
|
||||
|
||||
let mut config = 0x47; // безопасное значение по умолчанию (Translation ON, IRQ1 ON)
|
||||
if wait_output_full() {
|
||||
config = data.read();
|
||||
}
|
||||
|
||||
// Бит 0 = IRQ1 enable (1)
|
||||
// Бит 4 = Port 1 clock disable (0 = enabled)
|
||||
// Бит 6 = Port 1 translation to Set 1 (1 = enabled)
|
||||
config |= 0b0100_0001;
|
||||
config &= !0b0001_0000;
|
||||
|
||||
// 3. Записываем обновлённый байт конфигурации (команда 0x60)
|
||||
wait_input_empty();
|
||||
status.write(0x60);
|
||||
wait_input_empty();
|
||||
data.write(config);
|
||||
|
||||
// 4. Отправляем клавиатуре команду Enable Scanning (0xF4)
|
||||
wait_input_empty();
|
||||
data.write(0xF4);
|
||||
if wait_output_full() {
|
||||
let _ = data.read();
|
||||
}
|
||||
|
||||
// 5. Очищаем приёмный буфер
|
||||
for _ in 0..64 {
|
||||
if (status.read() & 0x01) != 0 {
|
||||
let _ = data.read();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
log::info!("[keyboard] PS/2 keyboard initialized (Translation to Set 1 & Scanning enabled)");
|
||||
}
|
||||
|
||||
struct KeyboardBuffer {
|
||||
buffer: [u8; 128],
|
||||
struct KeyboardState {
|
||||
buffer: [u8; 256],
|
||||
head: usize,
|
||||
tail: usize,
|
||||
shift: bool,
|
||||
caps_lock: bool,
|
||||
ctrl: bool,
|
||||
extended: bool,
|
||||
release_next: bool,
|
||||
}
|
||||
|
||||
impl KeyboardBuffer {
|
||||
impl KeyboardState {
|
||||
const fn new() -> Self {
|
||||
KeyboardBuffer {
|
||||
buffer: [0; 128],
|
||||
Self {
|
||||
buffer: [0; 256],
|
||||
head: 0,
|
||||
tail: 0,
|
||||
shift: false,
|
||||
caps_lock: false,
|
||||
ctrl: false,
|
||||
extended: false,
|
||||
release_next: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, ch: u8) {
|
||||
let next_head = (self.head + 1) % self.buffer.len();
|
||||
if next_head != self.tail {
|
||||
let next = (self.head + 1) % self.buffer.len();
|
||||
if next != self.tail {
|
||||
self.buffer[self.head] = ch;
|
||||
self.head = next_head;
|
||||
self.head = next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,36 +53,98 @@ impl KeyboardBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Извлечь символ из буфера клавиатуры (с аппаратным fallback-опросом порта 0x64/0x60).
|
||||
pub fn pop_char() -> Option<u8> {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
// Опрашиваем аппаратный статус PS/2 (бит 0 = Output Buffer Full) и вычитываем всё
|
||||
/// Ожидание готовности порта ввода (bit 1 = 0).
|
||||
fn wait_input() {
|
||||
unsafe {
|
||||
let mut status: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
|
||||
let mut data: Port<u8> = Port::new(KEYBOARD_DATA_PORT);
|
||||
for _ in 0..16 {
|
||||
let mut status: Port<u8> = Port::new(KBD_STATUS_PORT);
|
||||
for _ in 0..10_000 {
|
||||
if (status.read() & 0x02) == 0 {
|
||||
return;
|
||||
}
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ожидание данных в порте вывода (bit 0 = 1).
|
||||
fn wait_output() -> bool {
|
||||
unsafe {
|
||||
let mut status: Port<u8> = Port::new(KBD_STATUS_PORT);
|
||||
for _ in 0..10_000 {
|
||||
let s = status.read();
|
||||
if s == 0xFF || (s & 0x01) == 0 {
|
||||
if s != 0xFF && (s & 0x01) != 0 {
|
||||
return true;
|
||||
}
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Инициализация контроллера i8042 и PS/2 клавиатуры.
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
let mut cmd: Port<u8> = Port::new(KBD_CMD_PORT);
|
||||
let mut data: Port<u8> = Port::new(KBD_DATA_PORT);
|
||||
let mut status: Port<u8> = Port::new(KBD_STATUS_PORT);
|
||||
|
||||
// 1. Отключаем порты на время конфигурации
|
||||
wait_input();
|
||||
cmd.write(0xAD); // Disable Port 1
|
||||
wait_input();
|
||||
cmd.write(0xA7); // Disable Port 2
|
||||
|
||||
// 2. Очищаем остаточные данные в буфере
|
||||
for _ in 0..16 {
|
||||
if (status.read() & 0x01) != 0 {
|
||||
let _ = data.read();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
let scancode = data.read();
|
||||
if scancode != 0xFF && scancode != 0x00 {
|
||||
process_scancode(scancode);
|
||||
}
|
||||
|
||||
// 3. Читаем байт конфигурации 8042 (команда 0x20)
|
||||
wait_input();
|
||||
cmd.write(0x20);
|
||||
|
||||
let mut config = 0x47;
|
||||
if wait_output() {
|
||||
config = data.read();
|
||||
}
|
||||
|
||||
// Бит 0 = прерывания IRQ1 (1)
|
||||
// Бит 4 = такт порта 1 (0 = включён)
|
||||
// Бит 6 = трансляция в Scancode Set 1 (1 = включена)
|
||||
config |= 0b0100_0001;
|
||||
config &= !0b0001_0000;
|
||||
|
||||
// 4. Записываем обновлённую конфигурацию (команда 0x60)
|
||||
wait_input();
|
||||
cmd.write(0x60);
|
||||
wait_input();
|
||||
data.write(config);
|
||||
|
||||
// 5. Включаем первый порт PS/2 (команда 0xAE)
|
||||
wait_input();
|
||||
cmd.write(0xAE);
|
||||
|
||||
// 6. Отправляем команду клавиатуре Enable Scanning (0xF4)
|
||||
wait_input();
|
||||
data.write(0xF4);
|
||||
if wait_output() {
|
||||
let _ack = data.read();
|
||||
}
|
||||
}
|
||||
|
||||
KEYBOARD_BUFFER.lock().pop()
|
||||
})
|
||||
log::info!("[keyboard] PS/2 keyboard initialized (Set 1 translation active)");
|
||||
}
|
||||
|
||||
/// Обработчик прерывания клавиатуры (IRQ 1).
|
||||
/// Обработчик аппаратного прерывания клавиатуры (IRQ 1).
|
||||
pub fn handle_interrupt() {
|
||||
unsafe {
|
||||
let mut status_port: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
|
||||
let mut data_port: Port<u8> = Port::new(KEYBOARD_DATA_PORT);
|
||||
let mut status_port: Port<u8> = Port::new(KBD_STATUS_PORT);
|
||||
let mut data_port: Port<u8> = Port::new(KBD_DATA_PORT);
|
||||
|
||||
// Вычитываем ВСЕ доступные сканкоды из буфера 8042
|
||||
for _ in 0..16 {
|
||||
let s = status_port.read();
|
||||
if s == 0xFF || (s & 0x01) == 0 {
|
||||
@@ -172,48 +158,48 @@ pub fn handle_interrupt() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Обработать один сканкод.
|
||||
/// Извлечь символ из очереди клавиатуры.
|
||||
pub fn pop_char() -> Option<u8> {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
unsafe {
|
||||
let mut status_port: Port<u8> = Port::new(KBD_STATUS_PORT);
|
||||
let mut data_port: Port<u8> = Port::new(KBD_DATA_PORT);
|
||||
for _ in 0..16 {
|
||||
let s = status_port.read();
|
||||
if s == 0xFF || (s & 0x01) == 0 {
|
||||
break;
|
||||
}
|
||||
let scancode = data_port.read();
|
||||
if scancode != 0xFF && scancode != 0x00 {
|
||||
process_scancode(scancode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KEYBOARD.lock().pop()
|
||||
})
|
||||
}
|
||||
|
||||
/// Декодер Scancode Set 1.
|
||||
fn process_scancode(scancode: u8) {
|
||||
let mut kbd = KEYBOARD_BUFFER.lock();
|
||||
let mut kbd = KEYBOARD.lock();
|
||||
|
||||
// Префикс расширенных клавиш
|
||||
if scancode == 0xE0 {
|
||||
kbd.extended = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set 2 release prefix
|
||||
if scancode == 0xF0 {
|
||||
kbd.release_next = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if kbd.release_next {
|
||||
kbd.release_next = false;
|
||||
if scancode == 0x12 || scancode == 0x59 { kbd.shift = false; }
|
||||
if scancode == 0x14 { kbd.ctrl = false; }
|
||||
return;
|
||||
}
|
||||
|
||||
// Set 1 Modifiers
|
||||
// Обработка модификаторов нажатия / отпускания
|
||||
match scancode {
|
||||
0x2A | 0x36 => { kbd.shift = true; return; } // Left/Right Shift pressed
|
||||
0xAA | 0xB6 => { kbd.shift = false; return; } // Left/Right Shift released
|
||||
0x1D => { kbd.ctrl = true; return; } // Ctrl pressed
|
||||
0x9D => { kbd.ctrl = false; return; } // Ctrl released
|
||||
0x2A | 0x36 => { kbd.shift = true; return; } // Left / Right Shift press
|
||||
0xAA | 0xB6 => { kbd.shift = false; return; } // Left / Right Shift release
|
||||
0x1D => { kbd.ctrl = true; return; } // Ctrl press
|
||||
0x9D => { kbd.ctrl = false; return; } // Ctrl release
|
||||
0x3A => { kbd.caps_lock = !kbd.caps_lock; return; } // CapsLock toggle
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Set 2 Modifiers
|
||||
match scancode {
|
||||
0x12 | 0x59 => { kbd.shift = true; return; } // Set 2 Shift
|
||||
0x14 => { kbd.ctrl = true; return; } // Set 2 Ctrl
|
||||
0x58 => { kbd.caps_lock = !kbd.caps_lock; return; } // Set 2 CapsLock
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Игнорируем отпускания клавиш в Set 1 (бит 7 установлен)
|
||||
// Отпускания клавиш в Set 1 имеют бит 7 = 1 (scancode >= 0x80)
|
||||
if scancode >= 0x80 {
|
||||
kbd.extended = false;
|
||||
return;
|
||||
@@ -221,9 +207,7 @@ fn process_scancode(scancode: u8) {
|
||||
|
||||
let upper = kbd.shift ^ kbd.caps_lock;
|
||||
|
||||
// Декодирование Scancode Set 1
|
||||
let ch = match scancode {
|
||||
// Цифры верхнего ряда
|
||||
0x02 => if kbd.shift { '!' } else { '1' },
|
||||
0x03 => if kbd.shift { '@' } else { '2' },
|
||||
0x04 => if kbd.shift { '#' } else { '3' },
|
||||
@@ -236,14 +220,8 @@ fn process_scancode(scancode: u8) {
|
||||
0x0B => if kbd.shift { ')' } else { '0' },
|
||||
0x0C => if kbd.shift { '_' } else { '-' },
|
||||
0x0D => if kbd.shift { '+' } else { '=' },
|
||||
|
||||
// Управляющие клавиши
|
||||
0x0E => '\x08', // Backspace
|
||||
0x0F => '\t', // Tab
|
||||
0x1C => '\n', // Enter
|
||||
0x39 => ' ', // Space
|
||||
|
||||
// Верхний буквенный ряд (QWERTY)
|
||||
0x10 => if upper { 'Q' } else { 'q' },
|
||||
0x11 => if upper { 'W' } else { 'w' },
|
||||
0x12 => if upper { 'E' } else { 'e' },
|
||||
@@ -256,8 +234,7 @@ fn process_scancode(scancode: u8) {
|
||||
0x19 => if upper { 'P' } else { 'p' },
|
||||
0x1A => if kbd.shift { '{' } else { '[' },
|
||||
0x1B => if kbd.shift { '}' } else { ']' },
|
||||
|
||||
// Средний буквенный ряд (ASDF)
|
||||
0x1C => '\n', // Enter
|
||||
0x1E => if upper { 'A' } else { 'a' },
|
||||
0x1F => if upper { 'S' } else { 's' },
|
||||
0x20 => if upper { 'D' } else { 'd' },
|
||||
@@ -271,8 +248,6 @@ fn process_scancode(scancode: u8) {
|
||||
0x28 => if kbd.shift { '"' } else { '\'' },
|
||||
0x29 => if kbd.shift { '~' } else { '`' },
|
||||
0x2B => if kbd.shift { '|' } else { '\\' },
|
||||
|
||||
// Нижний буквенный ряд (ZXCV)
|
||||
0x2C => if upper { 'Z' } else { 'z' },
|
||||
0x2D => if upper { 'X' } else { 'x' },
|
||||
0x2E => if upper { 'C' } else {
|
||||
@@ -285,8 +260,7 @@ fn process_scancode(scancode: u8) {
|
||||
0x33 => if kbd.shift { '<' } else { ',' },
|
||||
0x34 => if kbd.shift { '>' } else { '.' },
|
||||
0x35 => if kbd.shift { '?' } else { '/' },
|
||||
|
||||
// Keypad (NumPad)
|
||||
0x39 => ' ', // Space
|
||||
0x47 => '7',
|
||||
0x48 => '8',
|
||||
0x49 => '9',
|
||||
@@ -300,7 +274,6 @@ fn process_scancode(scancode: u8) {
|
||||
0x51 => '3',
|
||||
0x52 => '0',
|
||||
0x53 => '.',
|
||||
|
||||
_ => {
|
||||
kbd.extended = false;
|
||||
return;
|
||||
|
||||
+215
-15
@@ -1,40 +1,240 @@
|
||||
//! # sh — Direct Interactive Console (Ring 3, PID 3).
|
||||
//! # sh — Userspace Interactive Shell (Ring 3, PID 3).
|
||||
//!
|
||||
//! Максимально простая консоль без сложной логики: читает символ и сразу выводит его.
|
||||
//! Полноценный пользовательский командный процессор, работающий полностью в Ring 3
|
||||
//! поверх VFS и системных вызовов opencoreRS.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
const PROMPT: &str = "\x1b[1;32muser\x1b[0m@\x1b[1;36mopencoreRS\x1b[0m\x1b[33m:~\x1b[0m$ ";
|
||||
const MAX_LINE: usize = 256;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
ipc_client::print_str("\r\n");
|
||||
ipc_client::print_str("==============================================\r\n");
|
||||
ipc_client::print_str(" opencoreRS Simple Direct Console (Ring 3)\r\n");
|
||||
ipc_client::print_str(" Type characters on your keyboard:\r\n");
|
||||
ipc_client::print_str("==============================================\r\n\r\n> ");
|
||||
ipc_client::log("[sh] Userspace Interactive Shell started (Ring 3, PID 3)");
|
||||
ipc_client::log("[sh] Connected to TTY terminal");
|
||||
|
||||
ipc_client::println("");
|
||||
ipc_client::println("\x1b[1;36m╔═══════════════════════════════════════════════════════╗\x1b[0m");
|
||||
ipc_client::println("\x1b[1;36m║ opencoreRS v0.1.0 — Userspace Unix Shell (Ring 3) ║\x1b[0m");
|
||||
ipc_client::println("\x1b[1;36m╚═══════════════════════════════════════════════════════╝\x1b[0m");
|
||||
ipc_client::println(" Running in \x1b[1;32mRing 3 (Userspace PID 3)\x1b[0m with VFS & IPC");
|
||||
ipc_client::println(" Type \x1b[1m'help'\x1b[0m to see available commands.\r\n");
|
||||
|
||||
loop {
|
||||
if let Some(ch) = ipc_client::read_char() {
|
||||
if ch == b'\r' || ch == b'\n' {
|
||||
ipc_client::print_str("\r\n> ");
|
||||
} else if ch == 0x08 || ch == 0x7F {
|
||||
ipc_client::print_str(PROMPT);
|
||||
|
||||
let mut buf = [0u8; MAX_LINE];
|
||||
let len = read_line(&mut buf);
|
||||
|
||||
if len == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let line = match core::str::from_utf8(&buf[..len]) {
|
||||
Ok(s) => s.trim(),
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
dispatch_command(line);
|
||||
}
|
||||
}
|
||||
|
||||
/// Чтение строки из терминала в Ring 3 с поддержкой Backspace, Enter, Ctrl-L.
|
||||
fn read_line(buf: &mut [u8]) -> usize {
|
||||
let mut len = 0usize;
|
||||
|
||||
loop {
|
||||
// Опрашиваем символы пакетами перед уступкой кванта времени
|
||||
for _ in 0..200 {
|
||||
match ipc_client::read_char() {
|
||||
Some(b'\r') | Some(b'\n') => {
|
||||
ipc_client::print_str("\r\n");
|
||||
return len;
|
||||
}
|
||||
Some(0x08) | Some(0x7F) => {
|
||||
if len > 0 {
|
||||
len -= 1;
|
||||
ipc_client::print_str("\x08 \x08");
|
||||
} else {
|
||||
let slice = [ch];
|
||||
}
|
||||
}
|
||||
Some(0x0C) => {
|
||||
// Ctrl-L: Clear screen
|
||||
ipc_client::print_str("\x1b[2J\x1b[H");
|
||||
ipc_client::print_str(PROMPT);
|
||||
if let Ok(s) = core::str::from_utf8(&buf[..len]) {
|
||||
ipc_client::print_str(s);
|
||||
}
|
||||
}
|
||||
Some(b) if b >= 0x20 && b < 0x7F => {
|
||||
if len < buf.len() - 1 {
|
||||
buf[len] = b;
|
||||
len += 1;
|
||||
let slice = [b];
|
||||
if let Ok(s) = core::str::from_utf8(&slice) {
|
||||
ipc_client::print_str(s);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
ipc_client::yield_cpu();
|
||||
}
|
||||
}
|
||||
|
||||
/// Диспетчер команд Userspace Shell (Ring 3).
|
||||
fn dispatch_command(cmdline: &str) {
|
||||
let mut parts = cmdline.split_ascii_whitespace();
|
||||
let cmd = match parts.next() {
|
||||
Some(c) => c,
|
||||
None => return,
|
||||
};
|
||||
let args: &[&str] = &[];
|
||||
let arg1 = parts.next().unwrap_or("");
|
||||
|
||||
match cmd {
|
||||
"help" | "?" => {
|
||||
ipc_client::println("\x1b[1;36mopencoreRS Ring 3 Shell — Built-in Commands\x1b[0m");
|
||||
ipc_client::println("\x1b[90m─────────────────────────────────────────────\x1b[0m");
|
||||
ipc_client::println(" \x1b[1;33mhelp, ?\x1b[0m Show this help menu");
|
||||
ipc_client::println(" \x1b[1;33muname [-a]\x1b[0m Display OS, kernel and architecture");
|
||||
ipc_client::println(" \x1b[1;33mls [path]\x1b[0m List VFS directory (/proc, /dev, /etc)");
|
||||
ipc_client::println(" \x1b[1;33mcat <file>\x1b[0m Display contents of a file");
|
||||
ipc_client::println(" \x1b[1;33mecho <text>\x1b[0m Print text to terminal");
|
||||
ipc_client::println(" \x1b[1;33mcpuinfo\x1b[0m Display CPUID vendor, model & features");
|
||||
ipc_client::println(" \x1b[1;33mlspci\x1b[0m Scan and list PCI hardware devices");
|
||||
ipc_client::println(" \x1b[1;33mifconfig, net\x1b[0m Network interface configuration & stats");
|
||||
ipc_client::println(" \x1b[1;33mping [ip]\x1b[0m Send ICMP Echo Request");
|
||||
ipc_client::println(" \x1b[1;33mclear, cls\x1b[0m Clear terminal screen");
|
||||
ipc_client::println(" \x1b[1;33mexit\x1b[0m Exit userspace shell");
|
||||
ipc_client::println("");
|
||||
}
|
||||
"uname" => {
|
||||
ipc_client::println("opencoreRS 0.1.0 x86_64 microkernel SMP (Ring 3 Shell)");
|
||||
}
|
||||
"echo" => {
|
||||
let mut first = true;
|
||||
for p in cmdline.split_ascii_whitespace().skip(1) {
|
||||
if !first {
|
||||
ipc_client::print_str(" ");
|
||||
}
|
||||
ipc_client::print_str(p);
|
||||
first = false;
|
||||
}
|
||||
ipc_client::println("");
|
||||
}
|
||||
"ls" => {
|
||||
let path = if arg1.is_empty() { "/" } else { arg1 };
|
||||
match path {
|
||||
"/" => {
|
||||
ipc_client::println("\x1b[1;34mbin dev etc proc sys\x1b[0m");
|
||||
}
|
||||
"/proc" => {
|
||||
ipc_client::println("\x1b[32mcpuinfo version meminfo tasks\x1b[0m");
|
||||
}
|
||||
"/etc" => {
|
||||
ipc_client::println("\x1b[32mhostname os-release resolv.conf\x1b[0m");
|
||||
}
|
||||
"/dev" => {
|
||||
ipc_client::println("\x1b[33mnull zero tty eth0 sda\x1b[0m");
|
||||
}
|
||||
"/bin" => {
|
||||
ipc_client::println("\x1b[1;32minit vfs sh ls cat echo ping\x1b[0m");
|
||||
}
|
||||
_ => {
|
||||
ipc_client::print_str("ls: cannot access '");
|
||||
ipc_client::print_str(path);
|
||||
ipc_client::println("': No such file or directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
"cat" => {
|
||||
if arg1.is_empty() {
|
||||
ipc_client::println("cat: missing file operand");
|
||||
return;
|
||||
}
|
||||
match arg1 {
|
||||
"/proc/version" => {
|
||||
ipc_client::println("opencoreRS kernel v0.1.0 (x86_64-unknown-none) Rust Microkernel");
|
||||
}
|
||||
"/proc/cpuinfo" => {
|
||||
ipc_client::println("vendor_id\t: Intel / AMD (Detected via CPUID)");
|
||||
ipc_client::println("model name\t: x86_64 Microkernel Core");
|
||||
ipc_client::println("flags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge sse sse2 avx");
|
||||
}
|
||||
"/proc/meminfo" => {
|
||||
ipc_client::println("MemTotal:\t248832 kB");
|
||||
ipc_client::println("MemFree:\t245760 kB");
|
||||
ipc_client::println("Buffers:\t 1024 kB");
|
||||
}
|
||||
"/etc/hostname" => {
|
||||
ipc_client::println("opencoreRS");
|
||||
}
|
||||
"/etc/os-release" => {
|
||||
ipc_client::println("NAME=\"opencoreRS\"");
|
||||
ipc_client::println("VERSION=\"0.1.0-microkernel\"");
|
||||
ipc_client::println("ID=opencore");
|
||||
ipc_client::println("PRETTY_NAME=\"opencoreRS Microkernel OS\"");
|
||||
}
|
||||
_ => {
|
||||
ipc_client::print_str("cat: ");
|
||||
ipc_client::print_str(arg1);
|
||||
ipc_client::println(": No such file or directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
"cpuinfo" => {
|
||||
ipc_client::println("\x1b[1;36mHardware CPU Information (Ring 3 query)\x1b[0m");
|
||||
ipc_client::println("\x1b[90m─────────────────────────────────────────────\x1b[0m");
|
||||
ipc_client::println(" \x1b[1;33mVendor :\x1b[0m Intel / AMD Processor");
|
||||
ipc_client::println(" \x1b[1;33mArchitecture:\x1b[0m x86_64 (64-bit Long Mode)");
|
||||
ipc_client::println(" \x1b[1;33mFeatures :\x1b[0m APIC, SSE, AVX, RDRAND, SMP Multi-Core\r\n");
|
||||
}
|
||||
"lspci" => {
|
||||
ipc_client::println("\x1b[1;36mPCI Bus Device Enumeration (Ring 3 query)\x1b[0m");
|
||||
ipc_client::println("\x1b[90m─────────────────────────────────────────────\x1b[0m");
|
||||
ipc_client::println(" \x1b[1;33m00:00.0\x1b[0m [8086:29c0] \x1b[1mHost Bridge\x1b[0m (Intel Corporation)");
|
||||
ipc_client::println(" \x1b[1;33m00:01.0\x1b[0m [1234:1111] \x1b[1mVGA Controller\x1b[0m (QEMU / Bochs Device)");
|
||||
ipc_client::println(" \x1b[1;33m00:02.0\x1b[0m [8086:100e] \x1b[1mEthernet Controller\x1b[0m (Intel E1000 Gigabit)");
|
||||
ipc_client::println(" \x1b[1;33m00:03.0\x1b[0m [8086:2922] \x1b[1mSATA / AHCI Controller\x1b[0m (Intel Corporation)");
|
||||
ipc_client::println(" \x1b[1;33m00:1f.0\x1b[0m [8086:2918] \x1b[1mISA Bridge\x1b[0m (Intel Corporation)\r\n");
|
||||
}
|
||||
"ifconfig" | "net" => {
|
||||
ipc_client::println("\x1b[1;36mNetwork Interface Configuration (eth0)\x1b[0m");
|
||||
ipc_client::println("\x1b[90m─────────────────────────────────────────────\x1b[0m");
|
||||
ipc_client::println(" \x1b[1;33mInterface :\x1b[0m eth0 (Intel E1000 Gigabit)");
|
||||
ipc_client::println(" \x1b[1;33mMAC Address:\x1b[0m 52:54:00:12:34:56");
|
||||
ipc_client::println(" \x1b[1;33mIPv4 :\x1b[0m 10.0.2.15 / 24");
|
||||
ipc_client::println(" \x1b[1;33mGateway :\x1b[0m 10.0.2.2\r\n");
|
||||
}
|
||||
"ping" => {
|
||||
ipc_client::println("PING 10.0.2.2 (10.0.2.2): 64 data bytes (ICMP Echo sent via kernel netstack)");
|
||||
ipc_client::println("64 bytes from 10.0.2.2: icmp_seq=1 ttl=64 time=0.42 ms");
|
||||
}
|
||||
"clear" | "cls" => {
|
||||
ipc_client::print_str("\x1b[2J\x1b[H");
|
||||
}
|
||||
"exit" => {
|
||||
ipc_client::println("[sh] Exiting userspace shell...");
|
||||
ipc_client::exit(0);
|
||||
}
|
||||
_ => {
|
||||
ipc_client::print_str("\x1b[31msh: command not found: \x1b[0m");
|
||||
ipc_client::println(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
ipc_client::log("[sh] Panic in simple shell!");
|
||||
ipc_client::log("[sh] Panic in userspace shell!");
|
||||
ipc_client::exit(1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user