update v2

This commit is contained in:
2025-07-05 14:31:39 +09:00
parent 163ac1668d
commit 3a9e563ee0
40 changed files with 1929 additions and 2128 deletions

13
kernel/.cargo/config.toml Normal file
View File

@ -0,0 +1,13 @@
[build]
target = "x86_64-unknown-none"
[target.x86_64-unknown-none]
rustflags = [
"-C", "link-arg=-T/Users/syui/git/aios/kernel/kernel.ld",
"-C", "relocation-model=static",
"-C", "code-model=kernel"
]
[unstable]
build-std = ["core", "compiler_builtins"]
build-std-features = ["compiler-builtins-mem"]

14
kernel/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "aios-kernel"
version = "2.0.0"
edition = "2021"
[[bin]]
name = "aios-kernel"
path = "src/main.rs"
[dependencies]
bootloader = "0.9.23"
[package.metadata.bootimage]
test-args = ["-nographic"]

22
kernel/i686-aios.json Normal file
View File

@ -0,0 +1,22 @@
{
"llvm-target": "i686-unknown-none",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128",
"arch": "x86",
"os": "none",
"env": "",
"vendor": "unknown",
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "-mmx,-sse,-sse2",
"executables": true,
"relocation-model": "static",
"code-model": "small",
"pre-link-args": {
"ld.lld": ["-Tkernel.ld"]
}
}

35
kernel/kernel.ld Normal file
View File

@ -0,0 +1,35 @@
/* AIOS v2 Kernel Linker Script */
ENTRY(_start)
SECTIONS
{
. = 1M;
.multiboot :
{
/* Ensure the multiboot header is at the very beginning */
KEEP(*(.multiboot))
}
.text : ALIGN(0x1000)
{
*(.text .text.*)
}
.rodata : ALIGN(0x1000)
{
*(.rodata .rodata.*)
}
.data : ALIGN(0x1000)
{
*(.data .data.*)
}
.bss : ALIGN(0x1000)
{
*(COMMON)
*(.bss .bss.*)
}
}

27
kernel/src/boot.s Normal file
View 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
View 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
View 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
View 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
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}
}
}