update v2
This commit is contained in:
27
kernel/src/boot.s
Normal file
27
kernel/src/boot.s
Normal file
@ -0,0 +1,27 @@
|
||||
# Multiboot header
|
||||
.section .multiboot
|
||||
.align 8
|
||||
multiboot_header:
|
||||
.long 0x1BADB002 # magic
|
||||
.long 0x00 # flags
|
||||
.long -(0x1BADB002 + 0x00) # checksum
|
||||
|
||||
# Entry point
|
||||
.section .text
|
||||
.global _start
|
||||
.code64
|
||||
_start:
|
||||
# Disable interrupts
|
||||
cli
|
||||
|
||||
# Load null descriptor into data segment registers
|
||||
xor %ax, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %ss
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
|
||||
# Halt
|
||||
hlt
|
||||
1: jmp 1b
|
34
kernel/src/boot32.s
Normal file
34
kernel/src/boot32.s
Normal file
@ -0,0 +1,34 @@
|
||||
.code32
|
||||
.section .multiboot, "ax"
|
||||
.align 4
|
||||
multiboot_header:
|
||||
.long 0x1BADB002 # magic
|
||||
.long 0x00 # flags
|
||||
.long -(0x1BADB002 + 0x00) # checksum
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
_start:
|
||||
# We start in 32-bit mode
|
||||
cli
|
||||
|
||||
# Set up a simple stack
|
||||
movl $stack_top, %esp
|
||||
|
||||
# Write 'OK' to VGA buffer
|
||||
movl $0xb8000, %edi
|
||||
movb $'O', (%edi)
|
||||
movb $0x0f, 1(%edi)
|
||||
movb $'K', 2(%edi)
|
||||
movb $0x0f, 3(%edi)
|
||||
|
||||
# Halt
|
||||
hang:
|
||||
hlt
|
||||
jmp hang
|
||||
|
||||
.section .bss
|
||||
.align 16
|
||||
stack_bottom:
|
||||
.space 4096
|
||||
stack_top:
|
130
kernel/src/console.rs
Normal file
130
kernel/src/console.rs
Normal file
@ -0,0 +1,130 @@
|
||||
//! Simple VGA console for AIOS v2
|
||||
//! No external crates, pure Rust implementation
|
||||
|
||||
use core::fmt::{self, Write};
|
||||
|
||||
const VGA_BUFFER: *mut u16 = 0xb8000 as *mut u16;
|
||||
const VGA_WIDTH: usize = 80;
|
||||
const VGA_HEIGHT: usize = 25;
|
||||
|
||||
static mut CONSOLE: Console = Console {
|
||||
col: 0,
|
||||
row: 0,
|
||||
color: 0x0f, // White on black
|
||||
};
|
||||
|
||||
struct Console {
|
||||
col: usize,
|
||||
row: usize,
|
||||
color: u8,
|
||||
}
|
||||
|
||||
impl Console {
|
||||
fn clear(&mut self) {
|
||||
for i in 0..(VGA_WIDTH * VGA_HEIGHT) {
|
||||
unsafe {
|
||||
VGA_BUFFER.add(i).write_volatile(0x0f00); // Clear with white on black
|
||||
}
|
||||
}
|
||||
self.col = 0;
|
||||
self.row = 0;
|
||||
}
|
||||
|
||||
fn write_byte(&mut self, byte: u8) {
|
||||
match byte {
|
||||
b'\n' => {
|
||||
self.col = 0;
|
||||
self.row += 1;
|
||||
if self.row >= VGA_HEIGHT {
|
||||
self.scroll_up();
|
||||
}
|
||||
}
|
||||
byte => {
|
||||
if self.col >= VGA_WIDTH {
|
||||
self.col = 0;
|
||||
self.row += 1;
|
||||
if self.row >= VGA_HEIGHT {
|
||||
self.scroll_up();
|
||||
}
|
||||
}
|
||||
|
||||
let pos = self.row * VGA_WIDTH + self.col;
|
||||
let entry = (self.color as u16) << 8 | byte as u16;
|
||||
|
||||
unsafe {
|
||||
VGA_BUFFER.add(pos).write_volatile(entry);
|
||||
}
|
||||
|
||||
self.col += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self) {
|
||||
// Move all lines up by one
|
||||
for row in 1..VGA_HEIGHT {
|
||||
for col in 0..VGA_WIDTH {
|
||||
let pos = row * VGA_WIDTH + col;
|
||||
let prev_pos = (row - 1) * VGA_WIDTH + col;
|
||||
unsafe {
|
||||
let entry = VGA_BUFFER.add(pos).read_volatile();
|
||||
VGA_BUFFER.add(prev_pos).write_volatile(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear last line
|
||||
for col in 0..VGA_WIDTH {
|
||||
let pos = (VGA_HEIGHT - 1) * VGA_WIDTH + col;
|
||||
unsafe {
|
||||
VGA_BUFFER.add(pos).write_volatile(0x0f00);
|
||||
}
|
||||
}
|
||||
|
||||
self.row = VGA_HEIGHT - 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Console {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for byte in s.bytes() {
|
||||
self.write_byte(byte);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
CONSOLE.clear();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print(s: &str) {
|
||||
unsafe {
|
||||
CONSOLE.write_str(s).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! kprint {
|
||||
($($arg:tt)*) => {
|
||||
$crate::console::_print(format_args!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! kprintln {
|
||||
() => ($crate::console::print("\n"));
|
||||
($($arg:tt)*) => ({
|
||||
$crate::console::_print(format_args!($($arg)*));
|
||||
$crate::console::print("\n");
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _print(args: fmt::Arguments) {
|
||||
unsafe {
|
||||
CONSOLE.write_fmt(args).unwrap();
|
||||
}
|
||||
}
|
67
kernel/src/keyboard.rs
Normal file
67
kernel/src/keyboard.rs
Normal file
@ -0,0 +1,67 @@
|
||||
//! PS/2 Keyboard Driver for AIOS v2
|
||||
|
||||
/// PS/2 keyboard data port
|
||||
const KEYBOARD_DATA_PORT: u16 = 0x60;
|
||||
|
||||
/// PS/2 keyboard status port
|
||||
const KEYBOARD_STATUS_PORT: u16 = 0x64;
|
||||
|
||||
/// Keyboard scan codes to ASCII mapping (US layout)
|
||||
static SCANCODE_TO_ASCII: [u8; 128] = [
|
||||
0, 27, b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'0', b'-', b'=', 8, // backspace
|
||||
b'\t', b'q', b'w', b'e', b'r', b't', b'y', b'u', b'i', b'o', b'p', b'[', b']', b'\n', // enter
|
||||
0, // left ctrl
|
||||
b'a', b's', b'd', b'f', b'g', b'h', b'j', b'k', b'l', b';', b'\'', b'`',
|
||||
0, // left shift
|
||||
b'\\', b'z', b'x', b'c', b'v', b'b', b'n', b'm', b',', b'.', b'/',
|
||||
0, // right shift
|
||||
b'*',
|
||||
0, // left alt
|
||||
b' ', // space
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F1-F10
|
||||
0, // num lock
|
||||
0, // scroll lock
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, // keypad
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
/// Read a byte from a port
|
||||
unsafe fn inb(port: u16) -> u8 {
|
||||
let result: u8;
|
||||
core::arch::asm!(
|
||||
"in al, dx",
|
||||
out("al") result,
|
||||
in("dx") port,
|
||||
options(nomem, nostack, preserves_flags)
|
||||
);
|
||||
result
|
||||
}
|
||||
|
||||
/// Check if keyboard has data available
|
||||
pub fn keyboard_ready() -> bool {
|
||||
unsafe {
|
||||
(inb(KEYBOARD_STATUS_PORT) & 0x01) != 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a key from the keyboard (non-blocking)
|
||||
pub fn read_key() -> Option<u8> {
|
||||
if !keyboard_ready() {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let scancode = inb(KEYBOARD_DATA_PORT);
|
||||
|
||||
// Only handle key press (bit 7 = 0), ignore key release
|
||||
if scancode & 0x80 == 0 {
|
||||
if let Some(&ascii) = SCANCODE_TO_ASCII.get(scancode as usize) {
|
||||
if ascii != 0 {
|
||||
return Some(ascii);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
62
kernel/src/keyboard_basic.rs
Normal file
62
kernel/src/keyboard_basic.rs
Normal file
@ -0,0 +1,62 @@
|
||||
//! Basic Keyboard Driver - Minimal approach
|
||||
|
||||
/// Check if there's data in keyboard buffer
|
||||
pub fn has_key() -> bool {
|
||||
unsafe {
|
||||
let status: u8;
|
||||
core::arch::asm!(
|
||||
"in al, 0x64",
|
||||
out("al") status,
|
||||
options(nomem, nostack, preserves_flags)
|
||||
);
|
||||
(status & 1) != 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Read raw scancode from keyboard
|
||||
pub fn read_scancode() -> u8 {
|
||||
unsafe {
|
||||
let scancode: u8;
|
||||
core::arch::asm!(
|
||||
"in al, 0x60",
|
||||
out("al") scancode,
|
||||
options(nomem, nostack, preserves_flags)
|
||||
);
|
||||
scancode
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert scancode to ASCII (basic mapping)
|
||||
pub fn scancode_to_char(scancode: u8) -> Option<char> {
|
||||
match scancode {
|
||||
0x1E => Some('a'),
|
||||
0x30 => Some('b'),
|
||||
0x2E => Some('c'),
|
||||
0x20 => Some('d'),
|
||||
0x12 => Some('e'),
|
||||
0x21 => Some('f'),
|
||||
0x22 => Some('g'),
|
||||
0x23 => Some('h'),
|
||||
0x17 => Some('i'),
|
||||
0x24 => Some('j'),
|
||||
0x25 => Some('k'),
|
||||
0x26 => Some('l'),
|
||||
0x32 => Some('m'),
|
||||
0x31 => Some('n'),
|
||||
0x18 => Some('o'),
|
||||
0x19 => Some('p'),
|
||||
0x10 => Some('q'),
|
||||
0x13 => Some('r'),
|
||||
0x1F => Some('s'),
|
||||
0x14 => Some('t'),
|
||||
0x16 => Some('u'),
|
||||
0x2F => Some('v'),
|
||||
0x11 => Some('w'),
|
||||
0x2D => Some('x'),
|
||||
0x15 => Some('y'),
|
||||
0x2C => Some('z'),
|
||||
0x39 => Some(' '),
|
||||
0x1C => Some('\n'),
|
||||
_ => None,
|
||||
}
|
||||
}
|
116
kernel/src/keyboard_safe.rs
Normal file
116
kernel/src/keyboard_safe.rs
Normal file
@ -0,0 +1,116 @@
|
||||
//! Safe Keyboard Driver for AIOS v2
|
||||
//! Uses polling without interrupts to avoid conflicts
|
||||
|
||||
/// PS/2 keyboard data port
|
||||
const KEYBOARD_DATA_PORT: u16 = 0x60;
|
||||
|
||||
/// PS/2 keyboard status port
|
||||
const KEYBOARD_STATUS_PORT: u16 = 0x64;
|
||||
|
||||
/// Simple scan code to ASCII mapping for common keys
|
||||
fn scancode_to_ascii(scancode: u8) -> Option<u8> {
|
||||
match scancode {
|
||||
0x02 => Some(b'1'),
|
||||
0x03 => Some(b'2'),
|
||||
0x04 => Some(b'3'),
|
||||
0x05 => Some(b'4'),
|
||||
0x06 => Some(b'5'),
|
||||
0x07 => Some(b'6'),
|
||||
0x08 => Some(b'7'),
|
||||
0x09 => Some(b'8'),
|
||||
0x0A => Some(b'9'),
|
||||
0x0B => Some(b'0'),
|
||||
|
||||
0x10 => Some(b'q'),
|
||||
0x11 => Some(b'w'),
|
||||
0x12 => Some(b'e'),
|
||||
0x13 => Some(b'r'),
|
||||
0x14 => Some(b't'),
|
||||
0x15 => Some(b'y'),
|
||||
0x16 => Some(b'u'),
|
||||
0x17 => Some(b'i'),
|
||||
0x18 => Some(b'o'),
|
||||
0x19 => Some(b'p'),
|
||||
|
||||
0x1E => Some(b'a'),
|
||||
0x1F => Some(b's'),
|
||||
0x20 => Some(b'd'),
|
||||
0x21 => Some(b'f'),
|
||||
0x22 => Some(b'g'),
|
||||
0x23 => Some(b'h'),
|
||||
0x24 => Some(b'j'),
|
||||
0x25 => Some(b'k'),
|
||||
0x26 => Some(b'l'),
|
||||
|
||||
0x2C => Some(b'z'),
|
||||
0x2D => Some(b'x'),
|
||||
0x2E => Some(b'c'),
|
||||
0x2F => Some(b'v'),
|
||||
0x30 => Some(b'b'),
|
||||
0x31 => Some(b'n'),
|
||||
0x32 => Some(b'm'),
|
||||
|
||||
0x39 => Some(b' '), // space
|
||||
0x1C => Some(b'\n'), // enter
|
||||
0x0E => Some(8), // backspace
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe port read with error handling
|
||||
unsafe fn try_inb(port: u16) -> Option<u8> {
|
||||
// Add a simple delay to avoid rapid polling
|
||||
for _ in 0..1000 {
|
||||
core::arch::asm!("nop");
|
||||
}
|
||||
|
||||
let result: u8;
|
||||
core::arch::asm!(
|
||||
"in al, dx",
|
||||
out("al") result,
|
||||
in("dx") port,
|
||||
options(nomem, nostack, preserves_flags)
|
||||
);
|
||||
Some(result)
|
||||
}
|
||||
|
||||
/// Check if keyboard has data available (safe version)
|
||||
pub fn keyboard_ready() -> bool {
|
||||
unsafe {
|
||||
if let Some(status) = try_inb(KEYBOARD_STATUS_PORT) {
|
||||
(status & 0x01) != 0
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a key from keyboard with safety checks
|
||||
pub fn read_key() -> Option<u8> {
|
||||
if !keyboard_ready() {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if let Some(scancode) = try_inb(KEYBOARD_DATA_PORT) {
|
||||
// Only handle key press (bit 7 = 0)
|
||||
if scancode & 0x80 == 0 {
|
||||
return scancode_to_ascii(scancode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Get raw scancode for debugging
|
||||
pub fn get_raw_scancode() -> Option<u8> {
|
||||
if !keyboard_ready() {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
try_inb(KEYBOARD_DATA_PORT)
|
||||
}
|
||||
}
|
208
kernel/src/main.rs
Normal file
208
kernel/src/main.rs
Normal file
@ -0,0 +1,208 @@
|
||||
//! Aios Kernel - Interactive Shell
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod keyboard_basic;
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
// Simple VGA buffer writer
|
||||
struct VgaBuffer {
|
||||
chars: [[u16; 80]; 25],
|
||||
}
|
||||
|
||||
static mut VGA_BUFFER: *mut VgaBuffer = 0xb8000 as *mut VgaBuffer;
|
||||
static mut CURSOR_ROW: usize = 12;
|
||||
static mut CURSOR_COL: usize = 6;
|
||||
|
||||
pub fn print_char(c: u8, x: usize, y: usize) {
|
||||
if x >= 80 || y >= 25 {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
let vga = &mut *VGA_BUFFER;
|
||||
vga.chars[y][x] = (0x0f << 8) | (c as u16);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_str(s: &str, x: usize, y: usize) {
|
||||
for (i, byte) in s.bytes().enumerate() {
|
||||
if x + i >= 80 {
|
||||
break;
|
||||
}
|
||||
print_char(byte, x + i, y);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_screen() {
|
||||
for y in 0..25 {
|
||||
for x in 0..80 {
|
||||
print_char(b' ', x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shell state
|
||||
static mut INPUT_BUFFER: [u8; 64] = [0; 64];
|
||||
static mut INPUT_POS: usize = 0;
|
||||
|
||||
fn print_prompt() {
|
||||
unsafe {
|
||||
print_str("aios> ", 0, CURSOR_ROW);
|
||||
CURSOR_COL = 6;
|
||||
}
|
||||
}
|
||||
|
||||
fn new_line() {
|
||||
unsafe {
|
||||
CURSOR_ROW += 1;
|
||||
CURSOR_COL = 0;
|
||||
if CURSOR_ROW >= 24 {
|
||||
CURSOR_ROW = 23;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_command() {
|
||||
unsafe {
|
||||
let cmd = core::str::from_utf8(&INPUT_BUFFER[..INPUT_POS]).unwrap_or("");
|
||||
|
||||
new_line();
|
||||
|
||||
match cmd {
|
||||
"help" => {
|
||||
print_str("Aios Commands:", 0, CURSOR_ROW);
|
||||
new_line();
|
||||
print_str(" help - Show this help", 0, CURSOR_ROW);
|
||||
new_line();
|
||||
print_str(" version - Show version", 0, CURSOR_ROW);
|
||||
new_line();
|
||||
print_str(" echo - Echo test", 0, CURSOR_ROW);
|
||||
new_line();
|
||||
print_str(" clear - Clear screen", 0, CURSOR_ROW);
|
||||
new_line();
|
||||
}
|
||||
"version" => {
|
||||
print_str("Aios 2.0 - AI Operating System", 0, CURSOR_ROW);
|
||||
new_line();
|
||||
print_str("Interactive Shell with Keyboard Support", 0, CURSOR_ROW);
|
||||
new_line();
|
||||
}
|
||||
"echo" => {
|
||||
print_str("Hello from Aios Interactive Shell!", 0, CURSOR_ROW);
|
||||
new_line();
|
||||
}
|
||||
"clear" => {
|
||||
clear_screen();
|
||||
CURSOR_ROW = 2;
|
||||
print_str("Aios - AI Operating System", 25, 0);
|
||||
print_str("Interactive Shell Ready", 27, 1);
|
||||
CURSOR_ROW = 3;
|
||||
}
|
||||
"" => {
|
||||
// Empty command
|
||||
}
|
||||
_ => {
|
||||
print_str("Unknown command: ", 0, CURSOR_ROW);
|
||||
print_str(cmd, 17, CURSOR_ROW);
|
||||
new_line();
|
||||
print_str("Type 'help' for available commands", 0, CURSOR_ROW);
|
||||
new_line();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear input buffer
|
||||
INPUT_BUFFER.fill(0);
|
||||
INPUT_POS = 0;
|
||||
|
||||
new_line();
|
||||
print_prompt();
|
||||
}
|
||||
}
|
||||
|
||||
fn process_char(ch: char) {
|
||||
unsafe {
|
||||
match ch {
|
||||
'\n' => {
|
||||
execute_command();
|
||||
}
|
||||
'\u{8}' => {
|
||||
// Backspace
|
||||
if INPUT_POS > 0 {
|
||||
INPUT_POS -= 1;
|
||||
INPUT_BUFFER[INPUT_POS] = 0;
|
||||
CURSOR_COL -= 1;
|
||||
print_char(b' ', CURSOR_COL, CURSOR_ROW);
|
||||
}
|
||||
}
|
||||
' '..='~' => {
|
||||
// Printable characters
|
||||
if INPUT_POS < INPUT_BUFFER.len() - 1 {
|
||||
INPUT_BUFFER[INPUT_POS] = ch as u8;
|
||||
print_char(ch as u8, CURSOR_COL, CURSOR_ROW);
|
||||
INPUT_POS += 1;
|
||||
CURSOR_COL += 1;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Ignore other characters
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Entry point
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
// Clear screen
|
||||
clear_screen();
|
||||
|
||||
// Print welcome message
|
||||
print_str("Aios - AI Operating System", 25, 0);
|
||||
print_str("Interactive Shell Ready", 27, 1);
|
||||
print_str("Type 'help' for commands", 27, 2);
|
||||
|
||||
// Initialize shell
|
||||
unsafe {
|
||||
CURSOR_ROW = 5;
|
||||
}
|
||||
print_prompt();
|
||||
|
||||
let mut last_scancode = 0u8;
|
||||
|
||||
loop {
|
||||
if keyboard_basic::has_key() {
|
||||
let scancode = keyboard_basic::read_scancode();
|
||||
|
||||
// Only process key press (not key release)
|
||||
if scancode != last_scancode && (scancode & 0x80) == 0 {
|
||||
last_scancode = scancode;
|
||||
|
||||
if let Some(ch) = keyboard_basic::scancode_to_char(scancode) {
|
||||
process_char(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Small delay to avoid excessive polling
|
||||
for _ in 0..1000 {
|
||||
unsafe {
|
||||
core::arch::asm!("nop");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Panic handler
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
clear_screen();
|
||||
print_str("!!! KERNEL PANIC !!!", 29, 12);
|
||||
print_str("System halted.", 33, 13);
|
||||
loop {
|
||||
unsafe {
|
||||
core::arch::asm!("hlt");
|
||||
}
|
||||
}
|
||||
}
|
7
kernel/src/memory.rs
Normal file
7
kernel/src/memory.rs
Normal file
@ -0,0 +1,7 @@
|
||||
//! Simple memory management for AIOS v2
|
||||
//! Minimal implementation for initial boot
|
||||
|
||||
pub fn init() {
|
||||
// TODO: Implement proper memory management
|
||||
// For now, just a placeholder to complete initialization sequence
|
||||
}
|
27
kernel/src/panic.rs
Normal file
27
kernel/src/panic.rs
Normal file
@ -0,0 +1,27 @@
|
||||
//! Panic handler for AIOS v2
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
use crate::console;
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
console::print("\n!!! KERNEL PANIC !!!\n");
|
||||
if let Some(location) = info.location() {
|
||||
console::print("Location: ");
|
||||
console::print(location.file());
|
||||
console::print(":");
|
||||
// TODO: Convert line number to string
|
||||
console::print("\n");
|
||||
}
|
||||
|
||||
console::print("Message: ");
|
||||
console::print("Kernel panic occurred\n");
|
||||
|
||||
console::print("System halted.\n");
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
core::arch::asm!("hlt");
|
||||
}
|
||||
}
|
||||
}
|
209
kernel/src/shell.rs
Normal file
209
kernel/src/shell.rs
Normal file
@ -0,0 +1,209 @@
|
||||
//! Simple Shell for AIOS v2
|
||||
|
||||
use crate::{print_char, print_str, clear_screen};
|
||||
|
||||
/// Maximum command line length
|
||||
const MAX_CMD_LEN: usize = 256;
|
||||
|
||||
/// Shell state
|
||||
pub struct Shell {
|
||||
input_buffer: [u8; MAX_CMD_LEN],
|
||||
cursor: usize,
|
||||
prompt: &'static str,
|
||||
}
|
||||
|
||||
impl Shell {
|
||||
/// Create a new shell instance
|
||||
pub fn new() -> Self {
|
||||
Shell {
|
||||
input_buffer: [0; MAX_CMD_LEN],
|
||||
cursor: 0,
|
||||
prompt: "aios> ",
|
||||
}
|
||||
}
|
||||
|
||||
/// Print the shell prompt
|
||||
pub fn print_prompt(&self) {
|
||||
print_str(self.prompt, 0, get_current_row());
|
||||
set_cursor_col(self.prompt.len());
|
||||
}
|
||||
|
||||
/// Process a single character input
|
||||
pub fn process_char(&mut self, c: u8) {
|
||||
match c {
|
||||
b'\n' => {
|
||||
// Enter pressed - execute command
|
||||
self.execute_command();
|
||||
self.clear_input();
|
||||
print_newline();
|
||||
self.print_prompt();
|
||||
}
|
||||
8 => {
|
||||
// Backspace
|
||||
if self.cursor > 0 {
|
||||
self.cursor -= 1;
|
||||
self.input_buffer[self.cursor] = 0;
|
||||
self.redraw_line();
|
||||
}
|
||||
}
|
||||
32..=126 => {
|
||||
// Printable characters
|
||||
if self.cursor < MAX_CMD_LEN - 1 {
|
||||
self.input_buffer[self.cursor] = c;
|
||||
self.cursor += 1;
|
||||
print_char(c, get_cursor_col(), get_current_row());
|
||||
inc_cursor_col();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Ignore other characters
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute the current command
|
||||
fn execute_command(&mut self) {
|
||||
let cmd = self.get_command_str();
|
||||
|
||||
print_newline();
|
||||
|
||||
match cmd {
|
||||
"help" => self.cmd_help(),
|
||||
"clear" => self.cmd_clear(),
|
||||
"echo" => self.cmd_echo(),
|
||||
"version" => self.cmd_version(),
|
||||
"reboot" => self.cmd_reboot(),
|
||||
"" => {
|
||||
// Empty command, do nothing
|
||||
}
|
||||
_ => {
|
||||
print_str("Unknown command: ", 0, get_current_row());
|
||||
print_str(cmd, 18, get_current_row());
|
||||
print_newline();
|
||||
print_str("Type 'help' for available commands.", 0, get_current_row());
|
||||
print_newline();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get command as string slice
|
||||
fn get_command_str(&self) -> &str {
|
||||
let bytes = &self.input_buffer[..self.cursor];
|
||||
core::str::from_utf8(bytes).unwrap_or("")
|
||||
}
|
||||
|
||||
/// Clear input buffer
|
||||
fn clear_input(&mut self) {
|
||||
self.input_buffer.fill(0);
|
||||
self.cursor = 0;
|
||||
}
|
||||
|
||||
/// Redraw the current line
|
||||
fn redraw_line(&self) {
|
||||
let row = get_current_row();
|
||||
let prompt_len = self.prompt.len();
|
||||
|
||||
// Clear the line after prompt
|
||||
for i in prompt_len..80 {
|
||||
print_char(b' ', i, row);
|
||||
}
|
||||
|
||||
// Redraw the command
|
||||
for (i, &c) in self.input_buffer[..self.cursor].iter().enumerate() {
|
||||
print_char(c, prompt_len + i, row);
|
||||
}
|
||||
|
||||
set_cursor_col(prompt_len + self.cursor);
|
||||
}
|
||||
|
||||
// Command implementations
|
||||
fn cmd_help(&self) {
|
||||
print_str("AIOS v2 Shell Commands:", 0, get_current_row());
|
||||
print_newline();
|
||||
print_str(" help - Show this help message", 0, get_current_row());
|
||||
print_newline();
|
||||
print_str(" clear - Clear the screen", 0, get_current_row());
|
||||
print_newline();
|
||||
print_str(" echo - Echo test message", 0, get_current_row());
|
||||
print_newline();
|
||||
print_str(" version - Show AIOS version", 0, get_current_row());
|
||||
print_newline();
|
||||
print_str(" reboot - Reboot the system", 0, get_current_row());
|
||||
print_newline();
|
||||
}
|
||||
|
||||
fn cmd_clear(&self) {
|
||||
clear_screen();
|
||||
reset_cursor();
|
||||
}
|
||||
|
||||
fn cmd_echo(&self) {
|
||||
print_str("Hello from AIOS v2 Shell!", 0, get_current_row());
|
||||
print_newline();
|
||||
}
|
||||
|
||||
fn cmd_version(&self) {
|
||||
print_str("AIOS v2.0 - AI Operating System", 0, get_current_row());
|
||||
print_newline();
|
||||
print_str("Built with Rust and powered by Claude", 0, get_current_row());
|
||||
print_newline();
|
||||
}
|
||||
|
||||
fn cmd_reboot(&self) {
|
||||
print_str("Rebooting system...", 0, get_current_row());
|
||||
print_newline();
|
||||
// Simple triple fault to reboot
|
||||
unsafe {
|
||||
core::arch::asm!("int3");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VGA buffer interface (temporary - will be moved to separate module)
|
||||
static mut CURSOR_ROW: usize = 0;
|
||||
static mut CURSOR_COL: usize = 0;
|
||||
|
||||
fn get_current_row() -> usize {
|
||||
unsafe { CURSOR_ROW }
|
||||
}
|
||||
|
||||
fn get_cursor_col() -> usize {
|
||||
unsafe { CURSOR_COL }
|
||||
}
|
||||
|
||||
fn set_cursor_col(col: usize) {
|
||||
unsafe { CURSOR_COL = col; }
|
||||
}
|
||||
|
||||
fn inc_cursor_col() {
|
||||
unsafe {
|
||||
CURSOR_COL += 1;
|
||||
if CURSOR_COL >= 80 {
|
||||
CURSOR_COL = 0;
|
||||
CURSOR_ROW += 1;
|
||||
if CURSOR_ROW >= 25 {
|
||||
CURSOR_ROW = 24;
|
||||
// TODO: Scroll screen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_newline() {
|
||||
unsafe {
|
||||
CURSOR_ROW += 1;
|
||||
CURSOR_COL = 0;
|
||||
if CURSOR_ROW >= 25 {
|
||||
CURSOR_ROW = 24;
|
||||
// TODO: Scroll screen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_cursor() {
|
||||
unsafe {
|
||||
CURSOR_ROW = 0;
|
||||
CURSOR_COL = 0;
|
||||
}
|
||||
}
|
||||
|
109
kernel/src/shell_simple.rs
Normal file
109
kernel/src/shell_simple.rs
Normal file
@ -0,0 +1,109 @@
|
||||
//! Simple Interactive Shell for AIOS v2
|
||||
|
||||
/// Shell buffer for command input
|
||||
static mut INPUT_BUFFER: [u8; 64] = [0; 64];
|
||||
static mut INPUT_POS: usize = 0;
|
||||
static mut SHELL_ROW: usize = 12;
|
||||
|
||||
/// Initialize shell
|
||||
pub fn init() {
|
||||
crate::print_str("aios> ", 0, unsafe { SHELL_ROW });
|
||||
}
|
||||
|
||||
/// Process a character input
|
||||
pub fn process_char(c: u8) {
|
||||
unsafe {
|
||||
match c {
|
||||
b'\n' => {
|
||||
// Execute command
|
||||
execute_command();
|
||||
new_prompt();
|
||||
}
|
||||
8 => {
|
||||
// Backspace
|
||||
if INPUT_POS > 0 {
|
||||
INPUT_POS -= 1;
|
||||
INPUT_BUFFER[INPUT_POS] = 0;
|
||||
redraw_line();
|
||||
}
|
||||
}
|
||||
32..=126 => {
|
||||
// Printable character
|
||||
if INPUT_POS < INPUT_BUFFER.len() - 1 {
|
||||
INPUT_BUFFER[INPUT_POS] = c;
|
||||
INPUT_POS += 1;
|
||||
crate::print_char(c, 6 + INPUT_POS - 1, SHELL_ROW);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute the current command
|
||||
fn execute_command() {
|
||||
unsafe {
|
||||
let cmd = core::str::from_utf8(&INPUT_BUFFER[..INPUT_POS]).unwrap_or("");
|
||||
|
||||
SHELL_ROW += 1;
|
||||
|
||||
match cmd {
|
||||
"help" => {
|
||||
crate::print_str("Commands: help, version, echo, clear", 0, SHELL_ROW);
|
||||
SHELL_ROW += 1;
|
||||
}
|
||||
"version" => {
|
||||
crate::print_str("AIOS v2.0 - Interactive Shell", 0, SHELL_ROW);
|
||||
SHELL_ROW += 1;
|
||||
}
|
||||
"echo" => {
|
||||
crate::print_str("Hello from interactive shell!", 0, SHELL_ROW);
|
||||
SHELL_ROW += 1;
|
||||
}
|
||||
"clear" => {
|
||||
crate::clear_screen();
|
||||
SHELL_ROW = 5;
|
||||
crate::print_str("AIOS v2 - AI Operating System", 25, 2);
|
||||
crate::print_str("Interactive Shell Active", 27, 3);
|
||||
}
|
||||
"" => {
|
||||
// Empty command, just new line
|
||||
}
|
||||
_ => {
|
||||
crate::print_str("Unknown command: ", 0, SHELL_ROW);
|
||||
crate::print_str(cmd, 18, SHELL_ROW);
|
||||
SHELL_ROW += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear input buffer
|
||||
INPUT_BUFFER.fill(0);
|
||||
INPUT_POS = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Start a new command prompt
|
||||
fn new_prompt() {
|
||||
unsafe {
|
||||
if SHELL_ROW >= 24 {
|
||||
SHELL_ROW = 23;
|
||||
}
|
||||
SHELL_ROW += 1;
|
||||
crate::print_str("aios> ", 0, SHELL_ROW);
|
||||
}
|
||||
}
|
||||
|
||||
/// Redraw current input line
|
||||
fn redraw_line() {
|
||||
unsafe {
|
||||
// Clear line after prompt
|
||||
for i in 6..80 {
|
||||
crate::print_char(b' ', i, SHELL_ROW);
|
||||
}
|
||||
|
||||
// Redraw input
|
||||
for (i, &c) in INPUT_BUFFER[..INPUT_POS].iter().enumerate() {
|
||||
crate::print_char(c, 6 + i, SHELL_ROW);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user