/* * Copyright (c) 2022, Able * * SPDX-License-Identifier: MPL-2.0 */ use crate::arch::drivers::sysinfo::master; use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2}; use crate::devices::pci::ide::{Channel, Drive}; use crate::devices::pci::{PciDevice, PCI_DEVICES}; use crate::filesystem; use crate::filesystem::vfs::VFS; use crate::systeminfo::{KERNEL_VERSION, RELEASE_TYPE}; use crate::time::fetch_time; use crate::{ arch::shutdown, rhai_shell::KEYBUFF, vterm::VTerm, wasm_jumploader::run_program, KERNEL_STATE, }; use acpi::{AcpiTables, PlatformInfo}; use cpuio::{inb, outb}; use kernel::allocator::ALLOCATOR; use spin::Lazy; use x86_64::instructions::interrupts::{disable, enable}; pub const BANNER_WIDTH: &str = "================================================================================"; // TODO: move to a better place #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct AcpiStruct {} impl acpi::AcpiHandler for AcpiStruct { unsafe fn map_physical_region( &self, physical_address: usize, size: usize, ) -> acpi::PhysicalMapping { info!("PHYS ADDR: {:?}", physical_address); info!("Size: {:?}", size); todo!("map_physical_region"); } fn unmap_physical_region(_region: &acpi::PhysicalMapping) { todo!("unmap_physical_region"); } } pub static TERM: Lazy> = Lazy::new(|| spin::Mutex::new(VTerm::new())); #[derive(Debug)] pub struct Path { pub path: Vec, } impl Path { pub fn new(path: String) -> Self { let mut path_vec_string = vec![]; for part in path.split(&['\\', '/'][..]) { path_vec_string.push(part.to_string()); } Path { path: path_vec_string, } } } /// Experimental scratchpad for testing. pub fn scratchpad() { // bruh(); // panic!(":>"); // for c in 0..144_697 { // trace!("{:?}", char::from_u32(c)); // } // bruh(); disable(); let tick_time = fetch_time(); let hostname = KERNEL_STATE.lock().hostname.clone(); let allocator = ALLOCATOR.lock(); let size = allocator.size(); let used = allocator.used(); drop(allocator); enable(); println!( "{} ,-------. OS: \u{001A}BLUE\u{001A}AbleOS\u{001A}RESET\u{001A} ,'\\ _ _`. Host: \u{001A}PINK\u{001A}{}\u{001A}RESET\u{001A} / \\)_)-)_)-\\ Kernel: \u{001A}RED\u{001A}AKern-{}-v{}\u{001A}RESET\u{001A} : : Uptime: \u{001A}GREEN\u{001A}{}\u{001A}RESET\u{001A} \\ / Packages: None \\ / Shell: BuiltinShell `. ,' Resolution: 640x480 `. ,' Terminal: VGABuffer `.,' CPU: {} /\\`. ,-._ GPU: VGA Compatible `-' Memory: {}/{} {}", // include_str!("../assets/balloon.txt"), // kstate.hostname, BANNER_WIDTH, hostname, RELEASE_TYPE, KERNEL_VERSION, tick_time, master().unwrap().brand_string().unwrap(), // "", // mem used, size, BANNER_WIDTH ); let pci_ide_device = { let pci_devices = PCI_DEVICES.lock(); pci_devices .iter() .find_map(|device_ref| { let device = device_ref.lock(); if let PciDevice::Ide(dev) = &*device { println!("IDE Device found: {}", dev.device_info()); Some(device_ref.clone()) } else { None } }) .unwrap() }; { let mut pci_ide_device = pci_ide_device.lock(); if let PciDevice::Ide(device) = &mut *pci_ide_device { let mut first_sector = Vec::with_capacity(512); device .read(Channel::Primary, Drive::Master, 0, 1, &mut first_sector) .unwrap(); // trace!("IDE Primary/Master sector 0: {first_sector:?}"); } } real_shell(); } pub fn acpi() { let acpi_handler = AcpiStruct {}; let _table; unsafe { _table = AcpiTables::search_for_rsdp_bios(acpi_handler); } match _table.unwrap().platform_info().unwrap() { PlatformInfo { power_profile, interrupt_model, .. } => { info!("{:?}", power_profile); info!("{:?}", interrupt_model); // info!("{:?}", processor_info.unwrap()); // info!("{:?}", pm_timer.unwrap()); } } } pub fn real_shell() { let prompt = "-> "; let _current_dir = "/".to_string(); let current_user = "able".to_string(); let mut buf = String::new(); print!("{}", prompt); // panic!(":<"); loop { match x86_64::instructions::interrupts::without_interrupts(|| KEYBUFF.lock().pop()) { Some('\n') => { // panic!(); println!(); // match engine.eval_with_scope::(&mut scope, &buf) { // Ok(o) => println!("{o}"), // Err(e) => println!("Eval error: {e}"), // }; if !buf.is_empty() { command_parser(current_user.clone(), buf.clone()); } buf.clear(); print!("{}", prompt); } Some('\u{8}') => { print!("\u{8}"); buf.pop(); } Some('\u{0009}') => { buf.push(' '); buf.push(' '); buf.push(' '); buf.push(' '); } Some(chr) => { buf.push(chr); print!("{}", chr); } None => { // trace!("{}", buf); } } } } pub fn command_parser(user: String, command: String) { let mut iter = command.split_whitespace(); let current_path = Path::new("/home/able".to_string()); trace!("Current path: {:?}", current_path); let current_path = "/home/able/"; let bin_name = iter.next().unwrap(); let mut strin = String::new(); for stri in iter.clone() { trace!("{}", stri); strin.push_str(stri); } let conf_args; match clparse::Arguments::parse_from_string(strin) { Ok(ok) => conf_args = ok, Err(err) => { println!("ERROR: {}", err); error!("{}", err); return; } }; match bin_name { // note: able asked for rhaish to stay in the repo but will be removed // in the future so just comment it out for now // "rhai" => { // shell(); // } "list" | "ls" => { let mut vfs = VFS.lock(); let handle = vfs.resolve(current_path).unwrap(); let dir = vfs.fs_node(handle).unwrap(); drop(vfs); for dir_entry in dir.directory().unwrap() { println!("{}", dir_entry.name()); } } "echo" => match conf_args.1.arguments.get("p") { Some(path) => echo_file(path.to_string()), None => println!("No path provided"), }, "test" => {} "quit" => shutdown(), "tree" => filesystem::tree("/").unwrap(), _ => { let file = { let mut vfs = VFS.lock(); let path = format!("/home/{user}/bins/{bin_name}.wasm"); let handle = if let Ok(file) = vfs.resolve(path) { file } else { let path = format!("/shared/bins/{bin_name}.wasm"); if let Ok(file) = vfs.resolve(path) { file } else { let path = format!("/system/bins/{bin_name}.wasm"); match vfs.resolve(path) { Ok(file) => file, Err(error) => { trace!("{:?}", error); println!("No such binary: {}", bin_name); error!("No such binary: {}", bin_name); return; } } } }; vfs.fs_node(handle).unwrap() }; let mut binary = vec![]; file.read(0, file.size(), &mut binary).unwrap(); let args = iter.collect::>(); println!("{:?}", args); run_program(&binary); } } } pub fn sound(n_frequency: u32) { let div: u32; let tmp: u8; div = 1193180 / n_frequency; unsafe { outb(0xb6, 0x43); set_pit_2(div); // And play the sound using the PC speaker tmp = inb(0x61); if tmp != (tmp | 3) { outb(tmp | 3, 0x61); } } } pub fn sound_off() { unsafe { let tmp = inb(0x61) & 0xFC; outb(tmp, 0x61) }; reset_pit_for_cpu(); } pub fn echo_file(path: String) { println!("{}", path); let mut current_path = String::from(""); current_path.push_str(&path); debug!("Aquiring lock"); let mut vfs = VFS.lock(); debug!("Resolving path"); let maybe_handle = vfs.resolve(¤t_path); match maybe_handle { Ok(handle) => { debug!("Loading file"); let maybe_file = vfs.fs_node(handle); match maybe_file { Some(file) => { trace!("checking is directory"); if file.is_dir() { println!( "\u{001A}RED\u{001A}ERROR\u{001A}RESET\u{001A} {} is a directory", path ); error!("{} is a directory", path); } else { trace!("allocating buffer for file contents"); let mut file_contents = Vec::new(); trace!("Reading file {} into buffer", path); file.read(0, file.size(), &mut file_contents).unwrap(); trace!("Converting file bytes into string"); let file_contents_str = String::from_utf8_lossy(&file_contents); println!("{}", file_contents_str); } } None => { error!("File {} doesn't exist", path); println!( "\u{001A}RED\u{001A}ERROR\u{001A}RESET\u{001A}: File {} doesn't exist", path ); } } } Err(err) => { println!( "\u{001A}RED\u{001A}ERROR\u{001A}RESET\u{001A}: path {} Error {}", path, err ); error!("path {} Error {}", path, err); } } }