diff --git a/Makefile b/Makefile index 4f9df2f..d32e509 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ GDB ?= CPUS ?= 1 # FAT type ESP_BITS ?= 32 +EXPORT_SYMBOLS = true ISO_PATH = ${ARTIFACTS_PATH}/iso_root INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs @@ -84,6 +85,7 @@ compile-initramfs: copy-initramfs-files mksquashfs ${INITRAMFS_PATH} ${ARTIFACTS_PATH}/initramfs.img ${MKSQUASHFS_OPTS} run-scripts: +ifeq (${EXPORT_SYMBOLS},true) nm target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf > scripts/symbols.table @if [ ! -d "scripts/rustc_demangle" ]; then \ echo "Cloning rustc_demangle.py into scripts/rustc_demangle/..."; \ @@ -93,6 +95,7 @@ run-scripts: fi python scripts/demangle-symbols.py mv scripts/symbols.table ${INITRAMFS_PATH}/ +endif python scripts/font.py mv scripts/font.psf ${INITRAMFS_PATH}/ diff --git a/README.md b/README.md index e2247be..aaa5d0f 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,8 @@ sudo dd if=bin/CappuccinOS.iso of=/dev/sdX bs=1M && sync ## Supported Architectures - x86_64 -- RISC-V64 (experimental until I can get my hands on some RISC-V hardware) +- ~~aarch64~~ not in scope __might__ not build +- ~~RISC-V64~~ not in scope __might__ not build ## Credits an attributions Inspiration was mainly from [JDH's Tetris OS](https://www.youtube.com/watch?v=FaILnmUYS_U), mixed with a growing interest in low level in general and an interest in learning rust (yeah, I started this project with not that much rust experience, maybe a CLI app or two, and trust me it shows). diff --git a/src/arch/aarch64/io.rs b/src/arch/aarch64/io.rs index 6af24ab..43bd597 100644 --- a/src/arch/aarch64/io.rs +++ b/src/arch/aarch64/io.rs @@ -28,6 +28,16 @@ pub unsafe fn insw(port: u16, buffer: *mut u16, count: usize) { return; } +/// Outputs `count` 8-bit values from the specified `port` into the `buffer`. +/// +/// # Safety +/// +/// This function panics if the supplied buffer's size is smaller than `count`. +#[inline(always)] +pub unsafe fn outsb(port: u16, buffer: *const u8, count: usize) { + return; +} + /// Outputs `count` 16-bit values from the specified `port` into the `buffer`. /// /// # Safety diff --git a/src/arch/mod.rs b/src/arch/mod.rs index 63a9bb0..924c98a 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -1,23 +1,17 @@ #[cfg(target_arch = "x86_64")] -pub use self::x86_64::*; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub use self::x86_common::*; +pub use x86_64::*; #[cfg(target_arch = "x86_64")] mod x86_64; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod x86_common; - #[cfg(target_arch = "riscv64")] mod riscv64; #[cfg(target_arch = "riscv64")] -pub use self::riscv64::*; +pub use riscv64::*; #[cfg(target_arch = "aarch64")] mod aarch64; #[cfg(target_arch = "aarch64")] -pub use self::aarch64::*; +pub use aarch64::*; diff --git a/src/arch/riscv64/io.rs b/src/arch/riscv64/io.rs index 6af24ab..43bd597 100644 --- a/src/arch/riscv64/io.rs +++ b/src/arch/riscv64/io.rs @@ -28,6 +28,16 @@ pub unsafe fn insw(port: u16, buffer: *mut u16, count: usize) { return; } +/// Outputs `count` 8-bit values from the specified `port` into the `buffer`. +/// +/// # Safety +/// +/// This function panics if the supplied buffer's size is smaller than `count`. +#[inline(always)] +pub unsafe fn outsb(port: u16, buffer: *const u8, count: usize) { + return; +} + /// Outputs `count` 16-bit values from the specified `port` into the `buffer`. /// /// # Safety diff --git a/src/arch/x86_64/interrupts/exceptions.rs b/src/arch/x86_64/interrupts/exceptions.rs index 85859cc..394c090 100644 --- a/src/arch/x86_64/interrupts/exceptions.rs +++ b/src/arch/x86_64/interrupts/exceptions.rs @@ -1,5 +1,5 @@ use super::idt_set_gate; -use crate::libs::util::hcf; +use crate::hcf; use crate::{log_error, log_info}; #[repr(C)] @@ -77,40 +77,35 @@ extern "C" fn exception_handler(registers: u64) { // *macro intensifies* macro_rules! exception_function { - ($code:expr, $handler:ident, $recoverable:literal) => { + ($code:expr, $handler:ident) => { #[inline(always)] extern "C" fn $handler() { - crate::arch::push_gprs(); - unsafe { core::arch::asm!( + "pushfq", "push {0:r}", "mov rdi, rsp", "call {1}", "pop {0:r}", "mov rsp, rdi", + "popfq", in(reg) $code, sym exception_handler, ); }; - if $recoverable { - crate::println!("TODO: Recover gracefully ;~;"); - hcf(); - } else { - hcf(); - } + hcf(); } }; } -exception_function!(0x00, div_error, true); -exception_function!(0x06, invalid_opcode, true); -exception_function!(0x08, double_fault, false); -exception_function!(0x0D, general_protection_fault, true); +exception_function!(0x00, div_error); +exception_function!(0x06, invalid_opcode); +exception_function!(0x08, double_fault); +exception_function!(0x0D, general_protection_fault); // TODO: fix the page fault then gracefully return. -exception_function!(0x0E, page_fault, false); -exception_function!(0xFF, generic_handler, true); +exception_function!(0x0E, page_fault); +exception_function!(0xFF, generic_handler); pub fn set_exceptions() { for i in 0..32 { diff --git a/src/arch/x86_64/interrupts/mod.rs b/src/arch/x86_64/interrupts/mod.rs index bd38b80..0ab15cf 100755 --- a/src/arch/x86_64/interrupts/mod.rs +++ b/src/arch/x86_64/interrupts/mod.rs @@ -1,8 +1,9 @@ +pub mod apic; mod exceptions; use crate::{ - arch::{apic, x86_common::pic::ChainedPics}, - libs::mutex::Mutex, + // arch::{apic, x86_common::pic::ChainedPics}, + libs::sync::Mutex, }; #[repr(C, packed)] @@ -42,7 +43,7 @@ static IDT: Mutex<[IdtEntry; 256]> = Mutex::new([IdtEntry::new(); 256]); #[derive(Clone, Copy)] #[repr(u8)] pub enum InterruptIndex { - Timer = PIC_1_OFFSET, + Timer = 32, Keyboard, } @@ -52,11 +53,6 @@ impl InterruptIndex { } } -pub const PIC_1_OFFSET: u8 = 32; -pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; - -pub static PICS: Mutex = Mutex::new(ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET)); - static mut IDT_PTR: IdtPtr = IdtPtr { limit: (core::mem::size_of::() * 256) as u16 - 1, base: 0, @@ -64,7 +60,7 @@ static mut IDT_PTR: IdtPtr = IdtPtr { pub fn idt_set_gate(num: u8, function_ptr: usize) { let base = function_ptr; - IDT.lock().write()[num as usize] = IdtEntry { + IDT.lock()[num as usize] = IdtEntry { base_lo: (base & 0xFFFF) as u16, base_mid: ((base >> 16) & 0xFFFF) as u16, base_hi: ((base >> 32) & 0xFFFFFFFF) as u32, @@ -77,36 +73,28 @@ pub fn idt_set_gate(num: u8, function_ptr: usize) { // If the interrupt with this number occurred with the "null" interrupt handler // We will need to tell the PIC that interrupt is over, this stops new interrupts // From never firing because "it was never finished" - signal_end_of_interrupt(num); + // signal_end_of_interrupt(num); } extern "x86-interrupt" fn null_interrupt_handler() { crate::log_info!("Unhandled interrupt!"); - if apic::APIC.lock().read().is_some() { - apic::APIC - .lock() - .read() - .as_ref() - .unwrap() - .end_of_interrupt(); - } + signal_end_of_interrupt(); } extern "x86-interrupt" fn timer_handler() { // crate::usr::tty::puts("."); - signal_end_of_interrupt(InterruptIndex::Timer.as_u8()); + signal_end_of_interrupt(); } fn idt_init() { unsafe { let idt_size = core::mem::size_of::() * 256; - IDT_PTR.base = IDT.lock().read().as_ptr() as u64; + { + let mut idt_lock = IDT.lock(); + IDT_PTR.base = idt_lock.as_ptr() as u64; - core::ptr::write_bytes( - IDT.lock().write().as_mut_ptr() as *mut core::ffi::c_void, - 0, - idt_size, - ); + core::ptr::write_bytes(idt_lock.as_mut_ptr() as *mut core::ffi::c_void, 0, idt_size); + } // Set every interrupt to the "null" interrupt handler (it does nothing) for num in 0..=255 { @@ -120,22 +108,13 @@ fn idt_init() { core::arch::asm!( "lidt [{}]", - in(reg) &IDT_PTR + in(reg) core::ptr::addr_of!(IDT_PTR) ); } } -pub fn signal_end_of_interrupt(int: u8) { - if apic::APIC.lock().read().is_some() { - apic::APIC - .lock() - .read() - .as_ref() - .unwrap() - .end_of_interrupt(); - } else { - PICS.lock().write().notify_end_of_interrupt(int); - } +pub fn signal_end_of_interrupt() { + apic::APIC.end_of_interrupt(); } #[naked] @@ -158,7 +137,7 @@ pub extern "C" fn syscall() { } } -pub extern "C" fn syscall_handler(rdi: u64, rsi: u64, rdx: u64, rcx: u64) { +pub extern "C" fn syscall_handler(_rdi: u64, _rsi: u64, rdx: u64, rcx: u64) { let buf = rdx as *const u8; // Treat as pointer to u8 (byte array) let count = rcx as usize; @@ -168,9 +147,10 @@ pub extern "C" fn syscall_handler(rdi: u64, rsi: u64, rdx: u64, rcx: u64) { } pub fn init() { + crate::drivers::acpi::init_acpi(); + idt_init(); - PICS.lock().write().initialize(); unsafe { core::arch::asm!("sti"); } diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 38f5c21..30aa24b 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -1,24 +1,35 @@ pub mod interrupts; +pub mod io; +pub mod stack_trace; -// This inline is detremental to having readable stack traces +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[inline(always)] -pub fn push_gprs() { +pub fn pause() { unsafe { - core::arch::asm!( - "push rax", "push rbx", "push rcx", "push rdx", "push rsi", "push rdi", "push rbp", - "push r8", "push r9", "push r10", "push r11", "push r12", "push r13", "push r14", - "push r15" - ); - } + core::arch::asm!("pause"); + }; } -// This inline is detremental to having readable stack traces +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[inline(always)] -pub fn pop_gprs() { - unsafe { - core::arch::asm!( - "pop r15", "pop r14", "pop r13", "pop r12", "pop r11", "pop r10", "pop r9", "pop r8", - "pop rbp", "pop rdi", "pop rsi", "pop rdx", "pop rcx", "pop rbx", "pop rax" - ); - } +pub fn cpu_has_msr() -> bool { + return unsafe { core::arch::x86_64::__cpuid_count(1, 0).edx } & 1 << 5 != 0; +} + +pub unsafe fn cpu_get_msr(msr: u32, lo: &mut u32, hi: &mut u32) { + core::arch::asm!( + "rdmsr", + in("ecx") msr, + inout("eax") *lo, + inout("edx") *hi, + ); +} + +pub unsafe fn cpu_set_msr(msr: u32, lo: &u32, hi: &u32) { + core::arch::asm!( + "wrmsr", + in("ecx") msr, + in("eax") *lo, + in("edx") *hi, + ); } diff --git a/src/arch/x86_common/apic.rs b/src/arch/x86_common/apic.rs deleted file mode 100644 index d21ac80..0000000 --- a/src/arch/x86_common/apic.rs +++ /dev/null @@ -1,211 +0,0 @@ -use core::sync::atomic::AtomicBool; - -use alloc::{boxed::Box, sync::Arc, vec::Vec}; - -use crate::{drivers::acpi::SDTHeader, libs::mutex::Mutex}; - -use super::{cpu_get_msr, cpu_set_msr, pic::ChainedPics}; - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -struct MADT { - pub local_apic_address: u32, - pub flags: u32, -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -struct MADTEntry {} - -impl MADT { - pub fn as_ptr(&self) -> *const u8 { - core::ptr::addr_of!(self).cast::() - } -} - -const IA32_APIC_BASE_MSR: u32 = 0x1B; -const IA32_APIC_BASE_MSR_ENABLE: usize = 0x800; - -pub fn has_apic() -> bool { - return unsafe { core::arch::x86_64::__cpuid_count(1, 0).edx } & 1 << 9 != 0; -} - -fn set_apic_base(apic: usize) { - let edx: u32 = 0; - let eax = (apic & 0xfffff0000) | IA32_APIC_BASE_MSR_ENABLE; - - unsafe { cpu_set_msr(IA32_APIC_BASE_MSR, &(eax as u32), &edx) }; -} - -fn get_apic_base() -> u32 { - let mut eax: u32 = 0; - let mut edx: u32 = 0; - unsafe { cpu_get_msr(IA32_APIC_BASE_MSR, &mut eax, &mut edx) }; - - return eax & 0xfffff000; -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct LAPIC { - pub acpi_processor_id: u8, - pub apic_id: u8, - pub flags: u32, -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct IOAPIC { - pub ioapic_id: u8, - _reserved: u8, - pub ptr: *mut u8, - pub global_interrupt_base: u32, -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct IOAPICSourceOverride { - bus_source: u8, - irq_source: u8, - global_system_interrupt: u32, - flags: u16, -} - -#[derive(Debug)] -pub struct APIC { - pub io_apic: IOAPIC, - local_apic: *mut u8, - pub cpus: Arc<[LAPIC]>, -} - -impl APIC { - pub fn new() -> Result { - if !has_apic() { - return Err(()); - } - - let apic_base = get_apic_base() as usize; - - set_apic_base(apic_base); - - let madt = crate::drivers::acpi::find_table::("APIC"); - - if madt.is_none() { - return Err(()); - } - - let mut cpus: Vec = Vec::new(); - - let madt = madt.unwrap(); - - crate::log_info!("MADT located at: {:p}", core::ptr::addr_of!(madt)); - - let mut lapic_ptr = madt.inner.local_apic_address as *mut u8; - let mut io_apic = None; - let mut io_apic_source_override = None; - - let mut ptr = madt.extra.unwrap().as_ptr(); - let ptr_end = unsafe { ptr.add(madt.header.length as usize - 44) }; - - while (ptr as usize) < (ptr_end as usize) { - match unsafe { *ptr } { - 0 => { - if unsafe { *(ptr.add(4)) } & 1 != 0 { - cpus.push(unsafe { *ptr.add(2).cast::() }); - } - } - 1 => unsafe { - io_apic = Some(IOAPIC { - ioapic_id: *ptr.add(2), - _reserved: *ptr.add(3), - ptr: (*ptr.add(4).cast::()) as *mut u8, - global_interrupt_base: *ptr.add(8).cast::(), - }) - }, - 2 => unsafe { - io_apic_source_override = Some(IOAPICSourceOverride { - bus_source: *ptr.add(2), - irq_source: *ptr.add(3), - global_system_interrupt: *ptr.add(4).cast::(), - flags: *ptr.add(8).cast::(), - }) - }, - 5 => lapic_ptr = unsafe { *(ptr.add(4).cast::()) } as *mut u8, - _ => {} - } - - ptr = unsafe { ptr.add((*ptr.add(1)) as usize) }; - } - - if io_apic.is_none() || io_apic_source_override.is_none() { - return Err(()); - } - - let io_apic_ptr = io_apic.unwrap().ptr; - - crate::println!( - "Found {} cores, IOAPIC {:p}, LAPIC {lapic_ptr:p}, Processor IDs:", - cpus.len(), - io_apic_ptr, - ); - - for apic in &cpus { - crate::println!(" {}", apic.acpi_processor_id); - } - - let apic = Self { - io_apic: io_apic.unwrap(), - local_apic: lapic_ptr, - cpus: cpus.into(), - }; - - apic.write_lapic(0xF0, apic.read_lapic(0xF0) | 0x100); - - let io_apic_ver = apic.read_ioapic(0x01); - - let number_of_inputs = ((io_apic_ver >> 16) & 0xFF) + 1; - - crate::println!("{number_of_inputs}"); - - // Take the keyboard vector table, then mask out the top most bit (interrupt mask), then, - // mask out the bottom 8 bits, and put the kbd int in it setting the interrupt vector - let keyboard_vt = ((apic.read_ioapic(0x12) & 0x7FFF) & 0xFF00) | 0x21; - - // enable keyboard interrupt - apic.write_ioapic(0x12, keyboard_vt); - - return Ok(apic); - } - - pub fn read_ioapic(&self, reg: u32) -> u32 { - unsafe { - core::ptr::write_volatile(self.io_apic.ptr.cast::(), reg & 0xff); - return core::ptr::read_volatile(self.io_apic.ptr.cast::().add(4)); - } - } - - pub fn write_ioapic(&self, reg: u32, value: u32) { - unsafe { - core::ptr::write_volatile(self.io_apic.ptr.cast::(), reg & 0xff); - core::ptr::write_volatile(self.io_apic.ptr.cast::().add(4), value); - } - } - - pub fn read_lapic(&self, reg: u32) -> u32 { - unsafe { - return *self.local_apic.add(reg as usize).cast::(); - } - } - - pub fn write_lapic(&self, reg: u32, value: u32) { - unsafe { - *self.local_apic.add(reg as usize).cast::() = value; - } - } - - pub fn end_of_interrupt(&self) { - self.write_lapic(0xB0, 0x00); - } -} - -pub static APIC: Mutex> = Mutex::new(None); diff --git a/src/arch/x86_common/io.rs b/src/arch/x86_common/io.rs deleted file mode 100644 index 0e12fdd..0000000 --- a/src/arch/x86_common/io.rs +++ /dev/null @@ -1,119 +0,0 @@ -use core::arch::asm; - -#[inline(always)] -pub fn outb(port: u16, value: u8) { - unsafe { - asm!( - "out dx, al", - in("dx") port, - in("al") value, - options(preserves_flags, nomem, nostack) - ); - } - return; -} - -#[inline(always)] -pub fn inb(port: u16) -> u8 { - let mut value: u8; - unsafe { - asm!( - "in al, dx", - out("al") value, - in("dx") port, - options(preserves_flags, nomem, nostack) - ); - } - return value; -} - -#[inline(always)] -pub fn outw(port: u16, value: u16) { - unsafe { - asm!( - "out dx, ax", - in("dx") port, - in("ax") value, - options(preserves_flags, nomem, nostack) - ); - } -} - -#[inline(always)] -pub fn inw(port: u16) -> u16 { - let mut value: u16; - unsafe { - asm!( - "in ax, dx", - out("ax") value, - in("dx") port, - options(preserves_flags, nomem, nostack) - ); - } - return value; -} - -/// Reads `count` 16-bit values from the specified `port` into the `buffer`. -/// -/// # Safety -/// -/// This function panics if the supplied buffer's size is smaller than `count`. -#[inline(always)] -pub unsafe fn insw(port: u16, buffer: *mut u16, count: usize) { - unsafe { - asm!("cld", - "rep insw", - in("dx") port, - inout("rdi") buffer => _, - inout("rcx") count => _ - ); - } -} - -/// Outputs `count` 16-bit values from the specified `port` into the `buffer`. -/// -/// # Safety -/// -/// This function panics if the supplied buffer's size is smaller than `count`. -#[inline(always)] -pub unsafe fn outsw(port: u16, buffer: *mut u16, count: usize) { - unsafe { - asm!("cld", - "rep outsw", - in("dx") port, - inout("rsi") buffer => _, - inout("rcx") count => _ - ); - } -} - -#[inline(always)] -pub fn outl(port: u16, value: u32) { - unsafe { - asm!( - "out dx, eax", - in("dx") port, - in("eax") value, - options(preserves_flags, nomem, nostack) - ); - } -} - -#[inline(always)] -pub fn inl(port: u16) -> u32 { - let mut value: u32; - unsafe { - asm!( - "in eax, dx", - out("eax") value, - in("dx") port, - options(preserves_flags, nomem, nostack) - ); - } - return value; -} - -#[inline(always)] -pub fn io_wait() { - outb(0x80, 0); -} diff --git a/src/arch/x86_common/mod.rs b/src/arch/x86_common/mod.rs deleted file mode 100644 index 654122e..0000000 --- a/src/arch/x86_common/mod.rs +++ /dev/null @@ -1,36 +0,0 @@ -pub mod apic; -pub mod io; -pub mod pic; -pub mod stack_trace; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[inline(always)] -pub fn pause() { - unsafe { - core::arch::asm!("pause"); - }; -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[inline(always)] -pub fn cpu_has_msr() -> bool { - return unsafe { core::arch::x86_64::__cpuid_count(1, 0).edx } & 1 << 5 != 0; -} - -pub unsafe fn cpu_get_msr(msr: u32, lo: &mut u32, hi: &mut u32) { - core::arch::asm!( - "rdmsr", - in("ecx") msr, - inout("eax") *lo, - inout("edx") *hi, - ); -} - -pub unsafe fn cpu_set_msr(msr: u32, lo: &u32, hi: &u32) { - core::arch::asm!( - "wrmsr", - in("ecx") msr, - in("eax") *lo, - in("edx") *hi, - ); -} diff --git a/src/arch/x86_common/pic.rs b/src/arch/x86_common/pic.rs deleted file mode 100644 index 5f9efb7..0000000 --- a/src/arch/x86_common/pic.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Originally from pic8259 (https://docs.rs/pic8259/0.10.1/pic8259/) -// But this one feeds my addiction of not adding unnecessary crates -// And I can read and learn about the PIC too ig -// Driver for the 8086 PIC, we will switch to the APIC later on. - -use super::io::{io_wait, outb}; - -// Command used to begin PIC initialization. -const CMD_INIT: u8 = 0x11; - -// Command used to acknowledge an interrupt. -const CMD_END_OF_INTERRUPT: u8 = 0x20; - -// The mode we want to run the PIC in. -const MODE_8086: u8 = 0x01; - -struct Pic { - // The base interrupt offset - offset: u8, - - // The I/O port we send commands to. - command: u8, - - // The I/O port we receive commands from - data: u8, -} - -impl Pic { - // Are we in charge of handling this interrupt? - fn handles_interrupt(&self, interrupt_id: u8) -> bool { - return self.offset <= interrupt_id && interrupt_id < self.offset + 8; - } - - // Notify us that an interrupt has been handled and we're ready - // for more - fn end_of_interrupt(&mut self) { - return outb(self.command as u16, CMD_END_OF_INTERRUPT); - } - - // Write the interrupt mask of this PIC - fn write_mask(&mut self, mask: u8) { - return outb(self.data as u16, mask); - } -} - -// A pair of chained Pic controllers. -pub struct ChainedPics { - pics: [Pic; 2], -} - -impl ChainedPics { - // Create a new interface for the chained pic controllers. - #[inline] - pub const fn new(offset1: u8, offset2: u8) -> ChainedPics { - ChainedPics { - pics: [ - Pic { - offset: offset1, - command: 0x20, - data: 0x21, - }, - Pic { - offset: offset2, - command: 0xA0, - data: 0xA1, - }, - ], - } - } - - // Initialize the chained pic controllers. - pub fn initialize(&mut self) { - // Tell each PIC we're going to initialize it. - outb(self.pics[0].command as u16, CMD_INIT); - io_wait(); - outb(self.pics[1].command as u16, CMD_INIT); - io_wait(); - - // Byte 1: Set up our base offsets. - outb(self.pics[0].data as u16, self.pics[0].offset); - io_wait(); - outb(self.pics[1].data as u16, self.pics[1].offset); - io_wait(); - - // Byte 2: Configure chaining - outb(self.pics[0].data as u16, 4); // Tell Master Pic that there is a slave Pic at IRQ2 - io_wait(); - outb(self.pics[1].data as u16, 2); // Tell Slave PIC it's cascade identity - io_wait(); - - // Byte 3: Set out mode. - outb(self.pics[0].data as u16, MODE_8086); - io_wait(); - outb(self.pics[1].data as u16, MODE_8086); - io_wait(); - } - - pub fn write_masks(&mut self, mask1: u8, mask2: u8) { - self.pics[0].write_mask(mask1); - self.pics[1].write_mask(mask2); - } - - // Keep for later if we want to use APIC later in the future - #[allow(dead_code)] - pub fn disable(&mut self) { - self.write_masks(0xFF, 0xFF); - } - - pub fn handles_interrupt(&self, interrupt_id: u8) -> bool { - return self - .pics - .iter() - .any(|pic| pic.handles_interrupt(interrupt_id)); - } - - pub fn notify_end_of_interrupt(&mut self, interrupt_id: u8) { - if self.handles_interrupt(interrupt_id) && self.pics[1].handles_interrupt(interrupt_id) { - self.pics[1].end_of_interrupt(); - } - - self.pics[0].end_of_interrupt(); - } -} diff --git a/src/arch/x86_common/stack_trace.rs b/src/arch/x86_common/stack_trace.rs deleted file mode 100644 index 757c77e..0000000 --- a/src/arch/x86_common/stack_trace.rs +++ /dev/null @@ -1,97 +0,0 @@ -use alloc::{borrow::ToOwned, string::String, vec::Vec}; - -use crate::drivers::fs::vfs::VfsFileSystem; - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -struct StackFrame { - back: *const StackFrame, - rip: u64, -} - -pub fn print_stack_trace(max_frames: usize, rbp: u64) { - let mut stackframe = rbp as *const StackFrame; - - crate::println!("Stack Trace:"); - for _frame in 0..max_frames { - if stackframe.is_null() || unsafe { (*stackframe).back.is_null() } { - break; - } - - let instruction_pointer = unsafe { (*stackframe).rip }; - - if instruction_pointer == 0x0 { - unsafe { - stackframe = (*stackframe).back; - }; - continue; - } - - crate::print!(" {:#X} ", instruction_pointer); - - let instrcution_info = get_function_name(instruction_pointer); - - if let Ok((function_name, function_offset)) = instrcution_info { - crate::println!("<{}+{:#X}>", function_name, function_offset); - } else { - crate::println!(); - } - - unsafe { - stackframe = (*stackframe).back; - }; - } -} - -fn get_function_name(function_address: u64) -> Result<(String, u64), ()> { - let symbols_fd = (*crate::drivers::fs::initramfs::INITRAMFS).open("/symbols.table")?; - - let symbols_table_bytes = symbols_fd.read()?; - let symbols_table = core::str::from_utf8(&symbols_table_bytes).ok().ok_or(())?; - - let mut previous_symbol: Option<(&str, u64)> = None; - - let symbols_table_lines: Vec<&str> = symbols_table.lines().collect(); - - for (i, line) in symbols_table_lines.iter().enumerate() { - let line_parts: Vec<&str> = line.splitn(2, ' ').collect(); - - if line_parts.len() < 2 { - continue; - } - - let (address, function_name) = ( - u64::from_str_radix(line_parts[0], 16).ok().ok_or(())?, - line_parts[1], - ); - - if address == function_address { - return Ok((function_name.to_owned(), 0)); - } - - if i == symbols_table_lines.len() - 1 { - return Ok((function_name.to_owned(), function_address - address)); - } - - if i == 0 { - if function_address < address { - return Err(()); - } - - previous_symbol = Some((function_name, address)); - continue; - } - - if function_address > previous_symbol.unwrap().1 && function_address < address { - // function is previous symbol - return Ok(( - previous_symbol.unwrap().0.to_owned(), - address - previous_symbol.unwrap().1, - )); - } - - previous_symbol = Some((function_name, address)); - } - - unreachable!(); -} diff --git a/src/bin/hello.rs b/src/bin/hello.rs index 95fb6fb..44613aa 100644 --- a/src/bin/hello.rs +++ b/src/bin/hello.rs @@ -1,12 +1,31 @@ #![no_std] #![no_main] -// use alloc::format; +// extern crate alloc; -// // piggyback off of the CappuccinOS allocator -// // TODO: make a malloc lib for memory operations -// #[allow(unused_imports)] -// use CappuccinOS; +// use core::alloc::GlobalAlloc; + +// use alloc::{borrow::ToOwned, format, string::String}; + +// struct Allocator; + +// unsafe impl GlobalAlloc for Allocator { +// unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { +// return malloc(layout.size()); +// } + +// unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { +// free(ptr, layout.size()); +// } +// } + +// #[global_allocator] +// static ALLOC: Allocator = Allocator; + +// extern "C" { +// fn malloc(size: usize) -> *mut u8; +// fn free(ptr: *mut u8, size: usize); +// } #[no_mangle] pub fn _start(_args: &[&str]) { diff --git a/src/drivers/acpi.rs b/src/drivers/acpi.rs index 39138d4..87a765c 100644 --- a/src/drivers/acpi.rs +++ b/src/drivers/acpi.rs @@ -1,10 +1,13 @@ use alloc::vec::Vec; +use limine::SmpRequest; use crate::{ arch::io::{inw, outb}, - libs::oncecell::OnceCell, + libs::cell::OnceCell, }; +pub static SMP_REQUEST: SmpRequest = SmpRequest::new(0); + #[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct SDTHeader { @@ -32,12 +35,14 @@ impl<'a, T> SDT<'a, T> { let length = core::ptr::read_unaligned(ptr.add(4).cast::()); let data = core::slice::from_raw_parts(ptr, length as usize); - crate::log_serial!("SDT at: {ptr:p}"); + crate::log_serial!("SDT at: {ptr:p}\n"); assert!(data.len() == length as usize); - let header: &SDTHeader = core::mem::transmute(data[0..].as_ptr()); - let inner: &T = core::mem::transmute(data[core::mem::size_of::()..].as_ptr()); + let header: &SDTHeader = &*data[0..].as_ptr().cast::(); + let inner: &T = &*data[core::mem::size_of::()..] + .as_ptr() + .cast::(); let mut extra = None; if length as usize > core::mem::size_of::() + core::mem::size_of::() { @@ -94,15 +99,15 @@ enum RootSDT<'a> { impl<'a> RootSDT<'a> { fn header(&self) -> SDTHeader { return match self { - RootSDT::RSDT(RSDT) => *RSDT.header, - RootSDT::XSDT(XSDT) => *XSDT.header, + RootSDT::RSDT(rsdt) => *rsdt.header, + RootSDT::XSDT(xsdt) => *xsdt.header, }; } fn len(&self) -> usize { let ptr_size = match self { - &RootSDT::RSDT(_) => 4, - &RootSDT::XSDT(_) => 8, + RootSDT::RSDT(_) => 4, + RootSDT::XSDT(_) => 8, }; return (self.header().length as usize - core::mem::size_of::()) / ptr_size; @@ -112,20 +117,20 @@ impl<'a> RootSDT<'a> { let mut offset = 0; let root_ptr = match self { - RootSDT::RSDT(RSDT) => { - let ptrs = RSDT.inner.pointers as *const u8; + RootSDT::RSDT(rsdt) => { + let ptrs = rsdt.inner.pointers as *const u8; assert!(!ptrs.is_null()); ptrs.add(offset) } - RootSDT::XSDT(XSDT) => { - let ptrs = XSDT.inner.pointers as *const u8; + RootSDT::XSDT(xsdt) => { + let ptrs = xsdt.inner.pointers as *const u8; assert!(!ptrs.is_null()); ptrs.add(offset) } }; for _ in 0..idx { - let header: &SDTHeader = core::mem::transmute(root_ptr.add(offset).cast::()); + let header: &SDTHeader = &*root_ptr.add(offset).cast::(); offset += header.length as usize; } @@ -165,8 +170,7 @@ fn resolve_acpi() { .map(|i| { let sdt_ptr = unsafe { root_sdt.get(i) }; let signature = unsafe { core::slice::from_raw_parts(sdt_ptr, 4) }; - let ret = signature.try_into().unwrap(); - ret + signature.try_into().unwrap() }) .collect(); @@ -254,9 +258,9 @@ pub fn init_acpi() { crate::log_ok!("Found {} ACPI Tables!", ACPI.tables.len()); - crate::log_serial!("Available serial tables:"); + crate::log_serial!("Available serial tables:\n"); for i in 0..ACPI.tables.len() { - crate::log_serial!(" {}", core::str::from_utf8(&ACPI.tables[i]).unwrap()) + crate::log_serial!(" {}\n", core::str::from_utf8(&ACPI.tables[i]).unwrap()); } let fadt = find_table::("FACP").expect("Failed to find FADT"); @@ -265,11 +269,9 @@ pub fn init_acpi() { while inw(fadt.inner.pm1a_control_block as u16) & 1 == 0 {} - crate::arch::interrupts::PICS.lock().write().disable(); - - *crate::arch::apic::APIC.lock().write() = - Some(crate::arch::apic::APIC::new().expect("Failed to enable APIC!")); - + #[cfg(target_arch = "x86_64")] + crate::arch::interrupts::apic::APIC + .set(crate::arch::interrupts::apic::APIC::new().expect("Failed to enable APIC!")); crate::log_ok!("APIC enabled!"); } diff --git a/src/drivers/fs/fat.rs b/src/drivers/fs/fat.rs index d19b4e0..86a8eea 100755 --- a/src/drivers/fs/fat.rs +++ b/src/drivers/fs/fat.rs @@ -5,9 +5,9 @@ use alloc::{ vec::Vec, }; -use crate::drivers::storage::{BlockDevice, GPTPartitionEntry}; +use crate::drivers::storage::Partition; -use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem}; +use super::vfs::{FsOps, VNode, VNodeOperations}; // The first Cluster (perhaps 0xF0FFFF0F) is the FAT ID // The second cluster stores the end-of-cluster-chain marker @@ -97,6 +97,8 @@ pub struct FSInfo { impl FSInfo { pub fn from_bytes(bytes: Arc<[u8]>) -> Self { + assert!(bytes.len() >= 512); + let lead_signature = u32::from_le_bytes(bytes[0..4].try_into().unwrap()); let mid_signature = u32::from_le_bytes(bytes[484..488].try_into().unwrap()); let last_known_free_cluster = u32::from_le_bytes(bytes[488..492].try_into().unwrap()); @@ -117,6 +119,7 @@ impl FSInfo { #[repr(u8)] #[derive(Debug, PartialEq)] +#[allow(dead_code)] enum FileEntryAttributes { ReadOnly = 0x01, Hidden = 0x02, @@ -127,7 +130,7 @@ enum FileEntryAttributes { LongFileName = 0x0F, } -#[repr(packed)] +#[repr(C, packed)] #[derive(Debug)] struct LongFileName { entry_order: u8, @@ -140,7 +143,7 @@ struct LongFileName { final_characters: [u16; 2], } -#[repr(packed)] +#[repr(C, packed)] #[derive(Debug)] pub struct FileEntry { file_name: [u8; 8], @@ -158,11 +161,18 @@ pub struct FileEntry { file_size: u32, } -pub struct FatFs<'a> { - // Block device Info - drive: &'a dyn BlockDevice, - partition: GPTPartitionEntry, +impl FileEntry { + pub fn cluster(&self) -> u32 { + let mut cluster = self.low_first_cluster_number as u32; + cluster |= (self.high_first_cluster_number as u32) << 16; + return cluster; + } +} + +pub struct FatFs { + partition: Partition, // FAT info + #[allow(dead_code)] fs_info: Option, fat: Option>, bpb: BIOSParameterBlock, @@ -172,10 +182,10 @@ pub struct FatFs<'a> { sectors_per_fat: usize, } -impl<'a> FatFs<'a> { - pub fn new(drive: &'a dyn BlockDevice, partition: GPTPartitionEntry) -> Result { - let bpb_bytes = drive - .read(partition.start_sector, 1) +impl FatFs { + pub fn new(partition: Partition) -> Result { + let bpb_bytes = partition + .read(0, 1) .expect("Failed to read FAT32 BIOS Parameter Block!"); let bpb = unsafe { *(bpb_bytes.as_ptr().cast::()) }; @@ -239,8 +249,8 @@ impl<'a> FatFs<'a> { let fs_info = match fat_type { FatType::Fat32(ebpb) => { - let fsinfo_bytes = drive - .read(partition.start_sector + ebpb.fsinfo_sector as u64, 1) + let fsinfo_bytes = partition + .read(ebpb.fsinfo_sector as u64, 1) .expect("Failed to read FSInfo sector!"); Some(FSInfo::from_bytes(fsinfo_bytes)) @@ -248,7 +258,7 @@ impl<'a> FatFs<'a> { _ => None, }; - let fat_start = partition.start_sector + bpb.reserved_sectors as u64; + let fat_start = bpb.reserved_sectors as u64; let sectors_per_fat = match fat_type { FatType::Fat32(ebpb) => ebpb.sectors_per_fat_ext as usize, @@ -268,7 +278,7 @@ impl<'a> FatFs<'a> { let mut fat_vec: Vec = Vec::with_capacity(bytes_per_fat / cluster_bytes); for i in 0..sectors_per_fat { - let sector = drive + let sector = partition .read(fat_start + i as u64, 1) .expect("Failed to read FAT"); for j in 0..(512 / cluster_bytes) { @@ -290,7 +300,7 @@ impl<'a> FatFs<'a> { fat = Some(Arc::from(fat_vec)); } else { crate::log_info!( - "\033[33mWARNING\033[0m: FAT is not being stored in memory, this feature is experimental and file reads are expected to be slower." + "\x1B[33mWARNING\x1B[0m: FAT is not being stored in memory, this feature is experimental and file reads are expected to be slower." ) } @@ -299,7 +309,6 @@ impl<'a> FatFs<'a> { let cluster_size = bpb.sectors_per_cluster as usize * 512; return Ok(Self { - drive, partition, fs_info, fat, @@ -416,8 +425,8 @@ impl<'a> FatFs<'a> { } pub fn read_cluster(&self, cluster: usize) -> Result, ()> { - return self.drive.read( - self.partition.start_sector + self.cluster_to_sector(cluster) as u64, + return self.partition.read( + self.cluster_to_sector(cluster) as u64, self.bpb.sectors_per_cluster as usize, ); } @@ -463,14 +472,14 @@ impl<'a> FatFs<'a> { let fat_entry_size = match self.fat_type { FatType::Fat12(_) => 2, // 12 bits per entry FatType::Fat16(_) => 2, // 16 bits per entry - FatType::Fat32(_) => 4, // 28S bits per entry + FatType::Fat32(_) => 4, // 28 bits per entry }; let entry_offset = cluster * fat_entry_size; let entry_offset_in_sector = entry_offset % 512; // needs two incase we "straddle a sector" let sector_data = self - .drive + .partition .read(self.fat_start + entry_offset as u64 / 512, 2) .expect("Failed to read from FAT!"); @@ -487,7 +496,7 @@ impl<'a> FatFs<'a> { [entry_offset_in_sector..entry_offset_in_sector + 2] .try_into() .unwrap(); - return (u16::from_le_bytes(cluster_entry_bytes) & 0xFFFF) as u32; + return (u16::from_le_bytes(cluster_entry_bytes)) as u32; } FatType::Fat32(_) => { let cluster_entry_bytes: [u8; 4] = sector_data @@ -501,10 +510,22 @@ impl<'a> FatFs<'a> { } } -impl<'a> VfsFileSystem for FatFs<'a> { - fn open(&self, path: &str) -> Result, ()> { - let path_componenets: Vec<&str> = path.trim_start_matches('/').split('/').collect(); - let mut current_cluster = match self.fat_type { +impl FsOps for FatFs { + fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const super::vfs::Vfs) { + // TODO: load the FAT into memory here + + *data = core::ptr::addr_of!(*self) as *mut u8; + + // *data = unsafe { alloc::alloc::alloc(alloc::alloc::Layout::new::>()) }; + // unsafe { *data.cast::>() = None }; + } + + fn unmount(&self, vfsp: *const super::vfs::Vfs) { + // TODO: unload the FAT form memory + } + + fn root(&self, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { + let mut root_cluster = match self.fat_type { FatType::Fat32(ebpb) => ebpb.root_dir_cluster as usize, _ => self.sector_to_cluster( self.bpb.reserved_sectors as usize @@ -512,101 +533,383 @@ impl<'a> VfsFileSystem for FatFs<'a> { ), }; - for path in path_componenets { - let file_entry: FileEntry = self.find_entry_in_directory(current_cluster, path)?; + let file = File::Dir(FatDirectory { + directory_cluster: root_cluster, + // fat_fs: self, + }); - if file_entry.attributes == FileEntryAttributes::Directory as u8 { - current_cluster = (((file_entry.high_first_cluster_number as u32) << 16) - | file_entry.low_first_cluster_number as u32) - as usize; - } else { - return Ok(Box::new(FatFile { - fat_fs: self, - file_entry, - })); - } - } - - return Err(()); + return super::vfs::VNode { + flags: 0, + ref_count: 0, + shared_lock_count: 0, + exclusive_lock_count: 0, + vfs_mounted_here: None, + ops: Box::new(file), + node_data: None, + parent: vfsp, + typ: super::vfs::VNodeType::Directory, + data: core::ptr::null_mut(), + }; } - fn read_dir(&self, path: &str) -> Result, ()> { - unimplemented!(); + fn fid(&self, path: &str, vfsp: *const super::vfs::Vfs) -> Option { + todo!("FAT FID"); + } + + fn statfs(&self, vfsp: *const super::vfs::Vfs) -> super::vfs::StatFs { + todo!("FAT STATFS"); + } + + fn sync(&self, vfsp: *const super::vfs::Vfs) { + todo!("FAT SYNC"); + } + + fn vget(&self, fid: super::vfs::FileId, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { + todo!("FAT VGET"); + } + + // fn open(&self, path: &str) -> Result, ()> { + // let path_componenets: Vec<&str> = path.trim_start_matches('/').split('/').collect(); + // let mut current_cluster = match self.fat_type { + // FatType::Fat32(ebpb) => ebpb.root_dir_cluster as usize, + // _ => self.sector_to_cluster( + // self.bpb.reserved_sectors as usize + // + (self.bpb.fat_count as usize * self.sectors_per_fat), + // ), + // }; + + // for path in path_componenets { + // let file_entry: FileEntry = self.find_entry_in_directory(current_cluster, path)?; + + // if file_entry.attributes == FileEntryAttributes::Directory as u8 { + // current_cluster = (((file_entry.high_first_cluster_number as u32) << 16) + // | file_entry.low_first_cluster_number as u32) + // as usize; + // } else { + // return Ok(Box::new(FatFile { + // fat_fs: self, + // file_entry, + // })); + // } + // } + + // return Err(()); + // } + + // fn read_dir(&self, _path: &str) -> Result, ()> { + // unimplemented!(); + // } +} + +enum File { + Archive(FatFile), + Dir(FatDirectory), +} + +impl<'a> VNodeOperations for File { + fn access(&self, m: u32, c: super::vfs::UserCred, vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn bmap(&self, block_number: u32, bnp: (), vp: *const VNode) -> super::vfs::VNode { + todo!("VNODE OPERATIONS"); + } + + fn bread(&self, block_number: u32, vp: *const VNode) -> Arc<[u8]> { + todo!("VNODE OPERATIONS"); + } + + fn close(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn create( + &self, + nm: &str, + va: super::vfs::VAttr, + e: u32, + m: u32, + c: super::vfs::UserCred, + vp: *const VNode, + ) -> Result { + todo!("VNODE OPERATIONS"); + } + + fn fsync(&self, c: super::vfs::UserCred, vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn getattr(&self, c: super::vfs::UserCred, vp: *const VNode) -> super::vfs::VAttr { + todo!("VNODE OPERATIONS"); + } + + fn inactive(&self, c: super::vfs::UserCred, vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn ioctl(&self, com: u32, d: *mut u8, f: u32, c: super::vfs::UserCred, vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn link( + &self, + target_dir: *mut super::vfs::VNode, + target_name: &str, + c: super::vfs::UserCred, + vp: *const VNode, + ) { + todo!("VNODE OPERATIONS"); + } + + fn lookup( + &self, + nm: &str, + c: super::vfs::UserCred, + vp: *const VNode, + ) -> Result { + let fat_fs = unsafe { (*(*vp).parent).data.cast::() }; + + match self { + File::Dir(directory) => unsafe { + let file_entry = + (*fat_fs).find_entry_in_directory(directory.directory_cluster, nm)?; + + let file_typ = if file_entry.attributes == FileEntryAttributes::Directory as u8 { + crate::drivers::fs::vfs::VNodeType::Directory + } else { + crate::drivers::fs::vfs::VNodeType::Regular + }; + + let file = if file_entry.attributes == FileEntryAttributes::Directory as u8 { + File::Dir(FatDirectory { + directory_cluster: file_entry.cluster() as usize, + }) + } else { + File::Archive(FatFile { file_entry }) + }; + + let vnode = VNode { + flags: 0, + ref_count: 0, + shared_lock_count: 0, + exclusive_lock_count: 0, + vfs_mounted_here: None, + ops: Box::new(file), + node_data: None, + parent: (*vp).parent, + typ: file_typ, + data: core::ptr::null_mut(), + }; + + Ok(vnode) + }, + _ => panic!("tried to lookup on a file"), + } + } + + fn mkdir( + &self, + nm: &str, + va: super::vfs::VAttr, + c: super::vfs::UserCred, + vp: *const VNode, + ) -> Result { + todo!("VNODE OPERATIONS"); + } + + fn open(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) -> Result, ()> { + match self { + File::Archive(archive) => { + let fat_fs = unsafe { (*(*vp).parent).data.cast::() }; + + let mut file: Vec = Vec::with_capacity(archive.file_entry.file_size as usize); + let mut file_ptr_index = 0; + + let mut cluster = ((archive.file_entry.high_first_cluster_number as u32) << 16) + | archive.file_entry.low_first_cluster_number as u32; + let cluster_size = unsafe { (*fat_fs).cluster_size }; + + let mut copied_bytes = 0; + + loop { + let cluster_data = unsafe { (*fat_fs).read_cluster(cluster as usize)? }; + + let remaining = archive.file_entry.file_size as usize - copied_bytes; + let to_copy = if remaining > cluster_size { + cluster_size + } else { + remaining + }; + + unsafe { + core::ptr::copy_nonoverlapping( + cluster_data.as_ptr(), + file.as_mut_ptr().add(file_ptr_index), + to_copy, + ); + + file.set_len(file.len() + to_copy); + } + + file_ptr_index += cluster_size; + + copied_bytes += to_copy; + + cluster = unsafe { (*fat_fs).get_next_cluster(cluster as usize) }; + + match unsafe { (*fat_fs).fat_type } { + FatType::Fat12(_) => { + if cluster >= EOC_12 { + break; + } + } + FatType::Fat16(_) => { + if cluster >= EOC_16 { + break; + } + } + FatType::Fat32(_) => { + if cluster >= EOC_32 { + break; + } + } + } + } + + return Ok(Arc::from(file)); + } + _ => panic!("Cannot open non archives"), + } + + todo!("VNODE OPERATIONS"); + } + + fn rdwr( + &self, + uiop: *const super::vfs::UIO, + direction: super::vfs::IODirection, + f: u32, + c: super::vfs::UserCred, + vp: *const VNode, + ) { + todo!("VNODE OPERATIONS"); + } + + fn readdir(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn readlink(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn rename( + &self, + nm: &str, + target_dir: *mut super::vfs::VNode, + target_name: &str, + c: super::vfs::UserCred, + vp: *const VNode, + ) { + todo!("VNODE OPERATIONS"); + } + + fn select(&self, w: super::vfs::IODirection, c: super::vfs::UserCred, vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn setattr(&self, va: super::vfs::VAttr, c: super::vfs::UserCred, vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn strategy(&self, bp: (), vp: *const VNode) { + todo!("VNODE OPERATIONS"); + } + + fn symlink( + &self, + link_name: &str, + va: super::vfs::VAttr, + target_name: &str, + c: super::vfs::UserCred, + vp: *const VNode, + ) { + todo!("VNODE OPERATIONS"); } } -struct FatFile<'a> { - fat_fs: &'a FatFs<'a>, +struct FatFile { + // fat_fs: &'a FatFs, file_entry: FileEntry, } -impl<'a> VfsFile for FatFile<'a> { - fn read(&self) -> Result, ()> { - let mut file: Vec = Vec::with_capacity(self.file_entry.file_size as usize); - let mut file_ptr_index = 0; +// impl<'a> VfsFile for FatFile<'a> { +// fn read(&self) -> Result, ()> { +// let mut file: Vec = Vec::with_capacity(self.file_entry.file_size as usize); +// let mut file_ptr_index = 0; - let mut cluster = ((self.file_entry.high_first_cluster_number as u32) << 16) - | self.file_entry.low_first_cluster_number as u32; - let cluster_size = self.fat_fs.cluster_size; +// let mut cluster = ((self.file_entry.high_first_cluster_number as u32) << 16) +// | self.file_entry.low_first_cluster_number as u32; +// let cluster_size = self.fat_fs.cluster_size; - let mut copied_bytes = 0; +// let mut copied_bytes = 0; - loop { - let cluster_data = self.fat_fs.read_cluster(cluster as usize)?; +// loop { +// let cluster_data = self.fat_fs.read_cluster(cluster as usize)?; - let remaining = self.file_entry.file_size as usize - copied_bytes; - let to_copy = if remaining > cluster_size { - cluster_size - } else { - remaining - }; +// let remaining = self.file_entry.file_size as usize - copied_bytes; +// let to_copy = if remaining > cluster_size { +// cluster_size +// } else { +// remaining +// }; - unsafe { - core::ptr::copy_nonoverlapping( - cluster_data.as_ptr(), - file.as_mut_ptr().add(file_ptr_index), - to_copy, - ); +// unsafe { +// core::ptr::copy_nonoverlapping( +// cluster_data.as_ptr(), +// file.as_mut_ptr().add(file_ptr_index), +// to_copy, +// ); - file.set_len(file.len() + to_copy); - } +// file.set_len(file.len() + to_copy); +// } - file_ptr_index += cluster_size; +// file_ptr_index += cluster_size; - copied_bytes += to_copy; +// copied_bytes += to_copy; - cluster = self.fat_fs.get_next_cluster(cluster as usize); +// cluster = self.fat_fs.get_next_cluster(cluster as usize); - match self.fat_fs.fat_type { - FatType::Fat12(_) => { - if cluster >= EOC_12 { - break; - } - } - FatType::Fat16(_) => { - if cluster >= EOC_16 { - break; - } - } - FatType::Fat32(_) => { - if cluster >= EOC_32 { - break; - } - } - } - } +// match self.fat_fs.fat_type { +// FatType::Fat12(_) => { +// if cluster >= EOC_12 { +// break; +// } +// } +// FatType::Fat16(_) => { +// if cluster >= EOC_16 { +// break; +// } +// } +// FatType::Fat32(_) => { +// if cluster >= EOC_32 { +// break; +// } +// } +// } +// } - return Ok(Arc::from(file)); - } -} +// return Ok(Arc::from(file)); +// } +// } -struct FatDirectory<'a> { - fat_fs: &'a FatFs<'a>, +struct FatDirectory { + // fat_fs: &'a FatFs, directory_cluster: usize, } -impl<'a> VfsDirectory for FatDirectory<'a> { - fn list_files(&self) -> Result]>, ()> { - unimplemented!(); - } -} +// impl<'a> VfsDirectory for FatDirectory<'a> { +// fn list_files(&self) -> Result]>, ()> { +// unimplemented!(); +// } +// } diff --git a/src/drivers/fs/initramfs/compressors/gzip.rs b/src/drivers/fs/initramfs/compressors/gzip.rs index 58b4e44..9a25909 100644 --- a/src/drivers/fs/initramfs/compressors/gzip.rs +++ b/src/drivers/fs/initramfs/compressors/gzip.rs @@ -1,6 +1,6 @@ use alloc::{sync::Arc, vec::Vec}; -use crate::libs::mutex::Mutex; +use crate::libs::sync::Mutex; #[derive(Debug)] #[repr(u8)] @@ -82,7 +82,7 @@ pub fn uncompress_data(bytes: &[u8]) -> Result, CompressionErrors> { return Err(CompressionErrors::FailedChecksum); } - return Ok(data.into()); + return Ok(data); } fn adler32(bytes: &[u8]) -> u32 { @@ -151,7 +151,7 @@ impl InflateContext { pub fn get_bit(&mut self) -> bool { if self.bit_index == 8 { self.input_buf.remove(0); - if self.input_buf.len() == 0 { + if self.input_buf.is_empty() { panic!("Not enough data! {:X?}", self.output_buf); } @@ -190,7 +190,7 @@ impl InflateContext { self.uncompressed()?; } 0x01 => { - self.inflate(FIXED_LENGTHS.lock().write(), FIXED_DISTS.lock().write())?; + self.inflate(&mut FIXED_LENGTHS.lock(), &mut FIXED_DISTS.lock())?; } 0x02 => { self.decode_huffman()?; @@ -243,7 +243,7 @@ impl InflateContext { } fn peek(&mut self, offset: usize) -> u8 { - let index = (self.ring.pointer as usize).wrapping_sub(offset as usize) % 32768; + let index = (self.ring.pointer).wrapping_sub(offset) % 32768; self.ring.data[index] } @@ -416,22 +416,15 @@ fn build_huffman(lengths: &[u8], size: usize, out: &mut Huff) { fn build_fixed() { let mut lengths = [0_u8; 288]; - for i in 0..144 { - lengths[i] = 8; - } - for i in 144..256 { - lengths[i] = 9; - } - for i in 256..280 { - lengths[i] = 7; - } - for i in 280..288 { - lengths[i] = 8; - } - build_huffman(&lengths, 288, FIXED_LENGTHS.lock().write()); - for i in 0..30 { - lengths[i] = 5; - } - build_huffman(&lengths, 30, FIXED_DISTS.lock().write()); + lengths[0..144].fill(8); + lengths[144..256].fill(9); + lengths[256..280].fill(7); + lengths[280..288].fill(8); + + build_huffman(&lengths, 288, &mut FIXED_LENGTHS.lock()); + + lengths[0..30].fill(5); + + build_huffman(&lengths, 30, &mut FIXED_DISTS.lock()); } diff --git a/src/drivers/fs/initramfs/mod.rs b/src/drivers/fs/initramfs/mod.rs index 8780c46..f87b2df 100755 --- a/src/drivers/fs/initramfs/mod.rs +++ b/src/drivers/fs/initramfs/mod.rs @@ -5,17 +5,14 @@ use core::fmt::{self, Debug}; use alloc::{boxed::Box, sync::Arc, vec::Vec}; use limine::ModuleRequest; -use crate::libs::{ - lazy::Lazy, - math::{ceil, floor}, -}; +use crate::libs::cell::LazyCell; -use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem}; +use super::vfs::{FsOps, VNode, VNodeOperations}; pub static MODULE_REQUEST: ModuleRequest = ModuleRequest::new(0); // TODO: do something better than this shite -pub static INITRAMFS: Lazy = Lazy::new(init); +pub static INITRAMFS: LazyCell = LazyCell::new(init); fn init() -> Squashfs<'static> { // TODO: Put the module request stuff in another file? @@ -110,41 +107,30 @@ impl Squashfs<'_> { let fragment_table: Option<&[u8]> = { if superblock.frag_table == u64::MAX { None + } else if superblock.export_table != u64::MAX { + Some( + &squashfs_data + [superblock.frag_table as usize..superblock.export_table as usize], + ) + } else if superblock.xattr_table != u64::MAX { + Some( + &squashfs_data[superblock.frag_table as usize..superblock.xattr_table as usize], + ) } else { - if superblock.export_table != u64::MAX { - Some( - &squashfs_data - [superblock.frag_table as usize..superblock.export_table as usize], - ) - } else if superblock.xattr_table != u64::MAX { - Some( - &squashfs_data - [superblock.frag_table as usize..superblock.xattr_table as usize], - ) - } else { - Some( - &squashfs_data - [superblock.frag_table as usize..superblock.id_table as usize], - ) - } + Some(&squashfs_data[superblock.frag_table as usize..superblock.id_table as usize]) } }; let export_table: Option<&[u8]> = { if superblock.export_table == u64::MAX { None + } else if superblock.xattr_table != u64::MAX { + Some( + &squashfs_data + [superblock.export_table as usize..superblock.xattr_table as usize], + ) } else { - if superblock.xattr_table != u64::MAX { - Some( - &squashfs_data - [superblock.export_table as usize..superblock.xattr_table as usize], - ) - } else { - Some( - &squashfs_data - [superblock.export_table as usize..superblock.id_table as usize], - ) - } + Some(&squashfs_data[superblock.export_table as usize..superblock.id_table as usize]) } }; @@ -201,15 +187,11 @@ impl Squashfs<'_> { match inode_file_type { InodeFileType::BasicDirectory => { return Inode::BasicDirectory(BasicDirectoryInode::from_bytes( - self, &inode_table[inode_offset..], )); } InodeFileType::BasicFile => { - return Inode::BasicFile(BasicFileInode::from_bytes( - self, - &inode_table[inode_offset..], - )); + return Inode::BasicFile(BasicFileInode::from_bytes(&inode_table[inode_offset..])); } _ => panic!("Unsupported or unknown inode file type {inode_file_type:?}!"), }; @@ -229,7 +211,7 @@ impl Squashfs<'_> { } else { header & 0x8000 == 0 }; - let table_size = header & 0x7FFF; + // let table_size = header & 0x7FFF; // if table.len() >= 8192 { // panic!("Inode block is not less than 8KiB!"); @@ -255,45 +237,220 @@ impl Squashfs<'_> { } } -impl<'a> VfsFileSystem for Squashfs<'a> { - fn open(&self, path: &str) -> Result, ()> { - let path_components: Vec<&str> = path.trim_start_matches('/').split('/').collect(); - let mut current_dir = self.read_root_dir(); - - for (i, &part) in path_components.iter().enumerate() { - let file = current_dir.find(part).ok_or(())?; - - match file { - Inode::BasicDirectory(dir) => { - current_dir = dir; - } - Inode::BasicFile(file) => { - if i < path_components.len() - 1 { - return Err(()); - } - - return Ok(Box::new(file)); - } - } - } - - return Err(()); +impl<'a> FsOps for Squashfs<'a> { + fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const super::vfs::Vfs) { + // STUB } - fn read_dir(&self, path: &str) -> Result, ()> { - unimplemented!() + fn unmount(&self, vfsp: *const super::vfs::Vfs) { + // STUB + } + + fn root(&self, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { + let root_dir = Inode::BasicDirectory(self.read_root_dir()); + + super::vfs::VNode { + flags: 0, + ref_count: 0, + shared_lock_count: 0, + exclusive_lock_count: 0, + vfs_mounted_here: None, + ops: Box::new(Inode::BasicDirectory(self.read_root_dir())), + node_data: None, + parent: vfsp, + typ: super::vfs::VNodeType::Directory, + data: core::ptr::null_mut(), + } + } + + fn fid(&self, path: &str, vfsp: *const super::vfs::Vfs) -> Option { + todo!(); + } + + fn statfs(&self, vfsp: *const super::vfs::Vfs) -> super::vfs::StatFs { + todo!(); + } + + fn sync(&self, vfsp: *const super::vfs::Vfs) { + todo!(); + } + + fn vget(&self, fid: super::vfs::FileId, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { + todo!(); } } +// impl<'a> VfsFileSystem for Squashfs<'a> { +// fn open(&self, path: &str) -> Result, ()> { +// let path_components: Vec<&str> = path.trim_start_matches('/').split('/').collect(); +// let mut current_dir = self.read_root_dir(); + +// for (i, &part) in path_components.iter().enumerate() { +// let file = current_dir.find(part).ok_or(())?; + +// match file { +// Inode::BasicDirectory(dir) => { +// current_dir = dir; +// } +// Inode::BasicFile(file) => { +// if i < path_components.len() - 1 { +// return Err(()); +// } + +// return Ok(Box::new(file)); +// } +// } +// } + +// return Err(()); +// } + +// fn read_dir(&self, _path: &str) -> Result, ()> { +// unimplemented!() +// } +// } + #[derive(Clone, Copy, Debug)] -enum Inode<'a> { - BasicFile(BasicFileInode<'a>), - BasicDirectory(BasicDirectoryInode<'a>), +enum Inode { + BasicFile(BasicFileInode), + BasicDirectory(BasicDirectoryInode), +} + +impl VNodeOperations for Inode { + fn open(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) -> Result, ()> { + todo!() + } + + fn close(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) { + todo!() + } + + fn rdwr( + &self, + uiop: *const super::vfs::UIO, + direction: super::vfs::IODirection, + f: u32, + c: super::vfs::UserCred, + vp: *const VNode, + ) { + todo!() + } + + fn ioctl(&self, com: u32, d: *mut u8, f: u32, c: super::vfs::UserCred, vp: *const VNode) { + todo!() + } + + fn select(&self, w: super::vfs::IODirection, c: super::vfs::UserCred, vp: *const VNode) { + todo!() + } + + fn getattr(&self, c: super::vfs::UserCred, vp: *const VNode) -> super::vfs::VAttr { + todo!() + } + + fn setattr(&self, va: super::vfs::VAttr, c: super::vfs::UserCred, vp: *const VNode) { + todo!() + } + + fn access(&self, m: u32, c: super::vfs::UserCred, vp: *const VNode) { + todo!() + } + + fn lookup( + &self, + nm: &str, + c: super::vfs::UserCred, + vp: *const VNode, + ) -> Result { + todo!() + } + + fn create( + &self, + nm: &str, + va: super::vfs::VAttr, + e: u32, + m: u32, + c: super::vfs::UserCred, + vp: *const VNode, + ) -> Result { + todo!() + } + + fn link( + &self, + target_dir: *mut super::vfs::VNode, + target_name: &str, + c: super::vfs::UserCred, + vp: *const VNode, + ) { + todo!() + } + + fn rename( + &self, + nm: &str, + target_dir: *mut super::vfs::VNode, + target_name: &str, + c: super::vfs::UserCred, + vp: *const VNode, + ) { + todo!() + } + + fn mkdir( + &self, + nm: &str, + va: super::vfs::VAttr, + c: super::vfs::UserCred, + vp: *const VNode, + ) -> Result { + todo!() + } + + fn readdir(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) { + todo!() + } + + fn symlink( + &self, + link_name: &str, + va: super::vfs::VAttr, + target_name: &str, + c: super::vfs::UserCred, + vp: *const VNode, + ) { + todo!() + } + + fn readlink(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) { + todo!() + } + + fn fsync(&self, c: super::vfs::UserCred, vp: *const VNode) { + todo!() + } + + fn inactive(&self, c: super::vfs::UserCred, vp: *const VNode) { + todo!() + } + + fn bmap(&self, block_number: u32, bnp: (), vp: *const VNode) -> super::vfs::VNode { + todo!() + } + + fn strategy(&self, bp: (), vp: *const VNode) { + todo!() + } + + fn bread(&self, block_number: u32, vp: *const VNode) -> Arc<[u8]> { + todo!() + } } macro_rules! inode_enum_try_into { ($inode_type:ty, $inode_name:ident) => { - impl<'a> TryInto<$inode_type> for Inode<'a> { + impl<'a> TryInto<$inode_type> for Inode { type Error = (); fn try_into(self) -> Result<$inode_type, Self::Error> { @@ -310,28 +467,28 @@ macro_rules! inode_enum_try_into { }; } -inode_enum_try_into!(BasicFileInode<'a>, BasicFile); -inode_enum_try_into!(BasicDirectoryInode<'a>, BasicDirectory); +inode_enum_try_into!(BasicFileInode, BasicFile); +inode_enum_try_into!(BasicDirectoryInode, BasicDirectory); // TODO: can we remove the dependence on squahsfs?? #[repr(C)] #[derive(Clone, Copy)] -struct InodeHeader<'a> { - squashfs: &'a Squashfs<'a>, +struct InodeHeader { + // squashfs: &'a Squashfs<'a>, file_type: InodeFileType, _reserved: [u16; 3], mtime: u32, inode_num: u32, } -impl<'a> InodeHeader<'a> { - fn from_bytes(squashfs: &'a Squashfs, bytes: &[u8]) -> Self { +impl InodeHeader { + fn from_bytes(bytes: &[u8]) -> Self { let file_type = u16::from_le_bytes(bytes[0..2].try_into().unwrap()).into(); let mtime = u32::from_le_bytes(bytes[8..12].try_into().unwrap()); let inode_num = u32::from_le_bytes(bytes[12..16].try_into().unwrap()); return Self { - squashfs, + // squashfs, file_type, _reserved: [0; 3], mtime, @@ -340,7 +497,7 @@ impl<'a> InodeHeader<'a> { } } -impl<'a> Debug for InodeHeader<'a> { +impl Debug for InodeHeader { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("InodeHeader") .field("file_type", &self.file_type) @@ -353,8 +510,8 @@ impl<'a> Debug for InodeHeader<'a> { #[repr(C)] #[derive(Clone, Copy, Debug)] -struct BasicDirectoryInode<'a> { - header: InodeHeader<'a>, +struct BasicDirectoryInode { + header: InodeHeader, block_index: u32, // 4 link_count: u32, // 8 file_size: u16, // 10 @@ -362,9 +519,9 @@ struct BasicDirectoryInode<'a> { parent_inode: u32, // 16 } -impl<'a> BasicDirectoryInode<'a> { - fn from_bytes(squashfs: &'a Squashfs, bytes: &[u8]) -> Self { - let header = InodeHeader::from_bytes(squashfs, bytes); +impl BasicDirectoryInode { + fn from_bytes(bytes: &[u8]) -> Self { + let header = InodeHeader::from_bytes(bytes); let block_index = u32::from_le_bytes(bytes[16..20].try_into().unwrap()); let link_count = u32::from_le_bytes(bytes[20..24].try_into().unwrap()); let file_size = u16::from_le_bytes(bytes[24..26].try_into().unwrap()); @@ -381,70 +538,71 @@ impl<'a> BasicDirectoryInode<'a> { }; } - fn entries(&self) -> Arc<[Inode]> { - let mut entries: Vec = Vec::new(); + // #[allow(dead_code)] + // fn entries(&self) -> Arc<[Inode]> { + // let mut entries: Vec = Vec::new(); - let directory_table = &self - .header - .squashfs - .get_decompressed_table(self.header.squashfs.directory_table, (true, None)); + // let directory_table = &self + // .header + // .squashfs + // .get_decompressed_table(self.header.squashfs.directory_table, (true, None)); - let directory_table_header = - DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]); + // let directory_table_header = + // DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]); - // TODO: cheap hack, fix it when I have more hours of sleep. - let mut offset = self.block_offset as usize + core::mem::size_of::(); + // // TODO: cheap hack, fix it when I have more hours of sleep. + // let mut offset = self.block_offset as usize + core::mem::size_of::(); - for _ in 0..directory_table_header.entry_count as usize { - let directory_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]); + // for _ in 0..directory_table_header.entry_count as usize { + // let directory_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]); - offset += 8 + directory_table_entry.name.len(); + // offset += 8 + directory_table_entry.name.len(); - let file_inode = self - .header - .squashfs - .read_inode(directory_table_entry.offset as u32); + // let file_inode = self + // .header + // .squashfs + // .read_inode(directory_table_entry.offset as u32); - entries.push(file_inode); - } + // entries.push(file_inode); + // } - return Arc::from(entries); - } + // return Arc::from(entries); + // } - fn find(&self, name: &str) -> Option> { - let directory_table = &self - .header - .squashfs - .get_decompressed_table(self.header.squashfs.directory_table, (true, None)); + // fn find(&self, name: &str) -> Option> { + // let directory_table = &self + // .header + // .squashfs + // .get_decompressed_table(self.header.squashfs.directory_table, (true, None)); - let directory_table_header = - DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]); + // let directory_table_header = + // DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]); - // TODO: cheap hack, fix it when I have more hours of sleep. - let mut offset = self.block_offset as usize + core::mem::size_of::(); + // // TODO: cheap hack, fix it when I have more hours of sleep. + // let mut offset = self.block_offset as usize + core::mem::size_of::(); + // InodeHeader + // for _ in 0..directory_table_header.entry_count as usize { + // let directory_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]); - for _ in 0..directory_table_header.entry_count as usize { - let directory_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]); + // offset += 8 + directory_table_entry.name.len(); - offset += 8 + directory_table_entry.name.len(); + // if directory_table_entry.name == name { + // return Some( + // self.header + // .squashfs + // .read_inode(directory_table_entry.offset as u32), + // ); + // } + // } - if directory_table_entry.name == name { - return Some( - self.header - .squashfs - .read_inode(directory_table_entry.offset as u32), - ); - } - } - - return None; - } + // return None; + // } } #[repr(C)] #[derive(Clone, Copy, Debug)] -struct BasicFileInode<'a> { - header: InodeHeader<'a>, +struct BasicFileInode { + header: InodeHeader, block_start: u32, // 4 frag_idx: u32, // 8 block_offset: u32, // 12 @@ -452,9 +610,9 @@ struct BasicFileInode<'a> { block_sizes: *const u32, } -impl<'a> BasicFileInode<'a> { - fn from_bytes(squashfs: &'a Squashfs, bytes: &[u8]) -> Self { - let header = InodeHeader::from_bytes(squashfs, bytes); +impl BasicFileInode { + fn from_bytes(bytes: &[u8]) -> Self { + let header = InodeHeader::from_bytes(bytes); let block_start = u32::from_le_bytes(bytes[16..20].try_into().unwrap()); let frag_idx = u32::from_le_bytes(bytes[20..24].try_into().unwrap()); let block_offset = u32::from_le_bytes(bytes[24..28].try_into().unwrap()); @@ -472,100 +630,100 @@ impl<'a> BasicFileInode<'a> { } } -impl<'a> VfsFile for BasicFileInode<'a> { - fn read(&self) -> Result, ()> { - // TODO: is this really how you're supposed to do this? - let mut block_data: Vec = Vec::with_capacity(self.file_size as usize); +// impl<'a> VfsFile for BasicFileInode<'a> { +// fn read(&self) -> Result, ()> { +// // TODO: is this really how you're supposed to do this? +// let mut block_data: Vec = Vec::with_capacity(self.file_size as usize); - let data_table: Vec; +// let data_table: Vec; - let block_offset = if self.frag_idx == u32::MAX { - data_table = self.header.squashfs.get_decompressed_table( - self.header.squashfs.data_table, - ( - false, - Some( - !self - .header - .squashfs - .superblock - .features() - .uncompressed_data_blocks, - ), - ), - ); +// let block_offset = if self.frag_idx == u32::MAX { +// data_table = self.header.squashfs.get_decompressed_table( +// self.header.squashfs.data_table, +// ( +// false, +// Some( +// !self +// .header +// .squashfs +// .superblock +// .features() +// .uncompressed_data_blocks, +// ), +// ), +// ); - self.block_offset as usize - } else { - // Tail end packing - let fragment_table = self.header.squashfs.get_decompressed_table( - self.header.squashfs.fragment_table.unwrap(), - ( - false, - Some(false), // Some( - // !self - // .header - // .squashfs - // .superblock - // .features() - // .uncompressed_fragments, - // ), - ), - ); +// self.block_offset as usize +// } else { +// // Tail end packing +// let fragment_table = self.header.squashfs.get_decompressed_table( +// self.header.squashfs.fragment_table.unwrap(), +// ( +// false, +// Some(false), // Some( +// // !self +// // .header +// // .squashfs +// // .superblock +// // .features() +// // .uncompressed_fragments, +// // ), +// ), +// ); - let fragment_pointer = (self.header.squashfs.start as u64 - + u64::from_le_bytes( - fragment_table[self.frag_idx as usize..(self.frag_idx + 8) as usize] - .try_into() - .unwrap(), - )) as *mut u8; +// let fragment_pointer = (self.header.squashfs.start as u64 +// + u64::from_le_bytes( +// fragment_table[self.frag_idx as usize..(self.frag_idx + 8) as usize] +// .try_into() +// .unwrap(), +// )) as *mut u8; - // build array since fragment_pointer is not guaranteed to be 0x02 aligned - // We add two since fragment_pointer points to the beginning of the fragment block, - // Which is a metadata block, and we get the size, but that excludes the two header bytes, - // And since we are building the array due to unaligned pointer shenanigans we need to - // include the header bytes otherwise we are short by two bytes - let fragment_block_size = unsafe { - u16::from_le(core::ptr::read_unaligned(fragment_pointer as *mut u16)) & 0x7FFF - } + 2; +// // build array since fragment_pointer is not guaranteed to be 0x02 aligned +// // We add two since fragment_pointer points to the beginning of the fragment block, +// // Which is a metadata block, and we get the size, but that excludes the two header bytes, +// // And since we are building the array due to unaligned pointer shenanigans we need to +// // include the header bytes otherwise we are short by two bytes +// let fragment_block_size = unsafe { +// u16::from_le(core::ptr::read_unaligned(fragment_pointer as *mut u16)) & 0x7FFF +// } + 2; - let mut fragment_block_raw = Vec::new(); - for i in 0..fragment_block_size as usize { - fragment_block_raw - .push(unsafe { core::ptr::read_unaligned(fragment_pointer.add(i)) }) - } +// let mut fragment_block_raw = Vec::new(); +// for i in 0..fragment_block_size as usize { +// fragment_block_raw +// .push(unsafe { core::ptr::read_unaligned(fragment_pointer.add(i)) }) +// } - let fragment_block = self - .header - .squashfs - .get_decompressed_table(&fragment_block_raw, (true, None)); +// let fragment_block = self +// .header +// .squashfs +// .get_decompressed_table(&fragment_block_raw, (true, None)); - let fragment_start = u64::from_le_bytes(fragment_block[0..8].try_into().unwrap()); - let fragment_size = u32::from_le_bytes(fragment_block[8..12].try_into().unwrap()); - let fragment_compressed = fragment_size & 1 << 24 == 0; - let fragment_size = fragment_size & 0xFEFFFFFF; +// let fragment_start = u64::from_le_bytes(fragment_block[0..8].try_into().unwrap()); +// let fragment_size = u32::from_le_bytes(fragment_block[8..12].try_into().unwrap()); +// let fragment_compressed = fragment_size & 1 << 24 == 0; +// let fragment_size = fragment_size & 0xFEFFFFFF; - let data_table_raw = unsafe { - core::slice::from_raw_parts( - (self.header.squashfs.start as u64 + fragment_start) as *mut u8, - fragment_size as usize, - ) - .to_vec() - }; +// let data_table_raw = unsafe { +// core::slice::from_raw_parts( +// (self.header.squashfs.start as u64 + fragment_start) as *mut u8, +// fragment_size as usize, +// ) +// .to_vec() +// }; - data_table = self - .header - .squashfs - .get_decompressed_table(&data_table_raw, (false, Some(fragment_compressed))); +// data_table = self +// .header +// .squashfs +// .get_decompressed_table(&data_table_raw, (false, Some(fragment_compressed))); - self.block_offset as usize - }; +// self.block_offset as usize +// }; - block_data.extend(&data_table[block_offset..(block_offset + self.file_size as usize)]); +// block_data.extend(&data_table[block_offset..(block_offset + self.file_size as usize)]); - return Ok(Arc::from(block_data)); - } -} +// return Ok(Arc::from(block_data)); +// } +// } #[repr(C)] #[derive(Debug)] diff --git a/src/drivers/fs/mod.rs b/src/drivers/fs/mod.rs index 56ed512..e3fd8f3 100644 --- a/src/drivers/fs/mod.rs +++ b/src/drivers/fs/mod.rs @@ -1,3 +1,4 @@ +pub mod devfs; pub mod fat; pub mod initramfs; pub mod vfs; diff --git a/src/drivers/fs/vfs.rs b/src/drivers/fs/vfs.rs index b3d65b4..c2d4b25 100755 --- a/src/drivers/fs/vfs.rs +++ b/src/drivers/fs/vfs.rs @@ -1,50 +1,357 @@ -use alloc::{ - boxed::Box, - string::{String, ToString}, - sync::Arc, - vec::Vec, -}; +// use alloc::{ +// boxed::Box, +// string::{String, ToString}, +// sync::Arc, +// vec::Vec, +// }; -use crate::libs::mutex::Mutex; +// use crate::{drivers::pci::PCI_DEVICES, libs::sync::Mutex}; -pub trait VfsFileSystem { - fn open(&self, path: &str) -> Result, ()>; - fn read_dir(&self, path: &str) -> Result, ()>; -} +// pub trait VfsFileSystem { +// fn open(&self, path: &str) -> Result, ()>; +// fn read_dir(&self, path: &str) -> Result, ()>; +// } -pub trait VfsFile { - fn read(&self) -> Result, ()>; -} +// pub trait VfsFile { +// fn read(&self) -> Result, ()>; +// } -pub trait VfsDirectory { - fn list_files(&self) -> Result]>, ()>; -} +// pub trait VfsDirectory { +// fn list_files(&self) -> Result]>, ()>; +// } -pub static VFS_INSTANCES: Mutex> = Mutex::new(Vec::new()); +// pub static VFS_INSTANCES: Mutex> = Mutex::new(Vec::new()); + +// pub struct Vfs { +// _identifier: String, +// file_system: Box, +// } + +// impl Vfs { +// pub fn new(file_system: Box, identifier: &str) -> Self { +// return Self { +// _identifier: identifier.to_string(), +// file_system, +// }; +// } + +// pub fn open(&self, path: &str) -> Result, ()> { +// return self.file_system.open(path); +// } + +// pub fn read_dir(&self, path: &str) -> Result, ()> { +// return self.file_system.read_dir(path); +// } +// } + +// pub fn init() { +// // TODO: Deduce which storage medium(s) we're using +// let pci_devices_lock = PCI_DEVICES.lock(); +// let mass_storage_devices = pci_devices_lock +// .iter() +// .filter(|&pci_device| pci_device.class_code == 0x01) +// .collect::>(); + +// for pci_device in mass_storage_devices { +// match pci_device.subclass_code { +// 0x01 => crate::drivers::storage::ide::init(), +// _ => {} +// } +// } +// } + +use core::fmt::Debug; + +use alloc::{alloc::handle_alloc_error, boxed::Box, sync::Arc, vec::Vec}; + +use crate::{log_info, mem::PHYSICAL_MEMORY_MANAGER}; + +static mut ROOT_VFS: Vfs = Vfs::null(); pub struct Vfs { - identifier: String, - file_system: Box, + next: Option<*mut Vfs>, + ops: Option>, + vnode_covered: Option>, + flags: u32, + block_size: u32, + pub data: *mut u8, } +unsafe impl Sync for Vfs {} + impl Vfs { - pub fn new(file_system: Box, identifier: &str) -> Self { - return Self { - identifier: identifier.to_string(), - file_system, + const fn null() -> Self { + return Vfs { + next: None, + ops: None, + vnode_covered: None, + flags: 0, + block_size: 0, + data: core::ptr::null_mut(), }; } - pub fn open(&self, path: &str) -> Result, ()> { - return self.file_system.open(path); + fn as_ptr(&self) -> *const Vfs { + core::ptr::addr_of!(*self) } - pub fn read_dir(&self, path: &str) -> Result, ()> { - return self.file_system.read_dir(path); + fn as_mut_ptr(&mut self) -> *mut Vfs { + core::ptr::addr_of_mut!(*self) } } -pub fn init() { - // TODO: Deduce which storage medium(s) we're using - crate::drivers::storage::ide::init(); +pub trait FsOps { + // yes, the vfsp was the best solution I could come up with + fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const Vfs); + fn unmount(&self, vfsp: *const Vfs); + fn root(&self, vfsp: *const Vfs) -> VNode; + fn statfs(&self, vfsp: *const Vfs) -> StatFs; + fn sync(&self, vfsp: *const Vfs); + fn fid(&self, path: &str, vfsp: *const Vfs) -> Option; + // idk how the fuck you're supposed to accomplish this + // good luck I guess. + fn vget(&self, fid: FileId, vfsp: *const Vfs) -> VNode; +} + +pub struct FileId { + len: u16, + data: u8, +} + +pub struct StatFs { + typ: u32, + block_size: u32, + total_blocks: u32, + free_blocks: u32, + available_blocks: u32, // non-protected blocks + files: u32, + free_nodes: u32, + fs_id: u32, + _reserved: [u8; 7], +} + +#[repr(u8)] +pub enum VNodeType { + // Jury is out on this one + NON = 0, + Regular, + Directory, + Block, + Character, + Link, + Socket, + Bad, +} + +pub struct VNode { + pub flags: u16, + pub ref_count: u16, + pub shared_lock_count: u16, + pub exclusive_lock_count: u16, + pub vfs_mounted_here: Option<*mut Vfs>, + pub ops: Box, + pub node_data: Option, + pub parent: *const Vfs, + pub typ: VNodeType, + pub data: *mut u8, +} + +impl VNode { + pub fn as_ptr(&self) -> *const VNode { + core::ptr::addr_of!(*self) + } +} + +impl Debug for VNode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("VNode")) + } +} + +#[repr(C)] +pub union NodeData { + socket: (), // Socket + stream_data: (), // Stream +} + +pub struct UserCred { + pub uid: u16, + pub gid: u16, +} + +pub enum IODirection { + Read, + Write, +} + +pub struct IoVec { + iov_base: *mut u8, + iov_len: usize, +} + +pub struct UIO { + iov: *mut IoVec, + iov_count: u32, + offset: usize, + seg_flag: u32, + file_mode: u32, + max_offset: usize, + residual_count: u32, +} + +pub trait VNodeOperations { + fn open(&self, f: u32, c: UserCred, vp: *const VNode) -> Result, ()>; + fn close(&self, f: u32, c: UserCred, vp: *const VNode); + fn rdwr(&self, uiop: *const UIO, direction: IODirection, f: u32, c: UserCred, vp: *const VNode); + fn ioctl(&self, com: u32, d: *mut u8, f: u32, c: UserCred, vp: *const VNode); + fn select(&self, w: IODirection, c: UserCred, vp: *const VNode); + fn getattr(&self, c: UserCred, vp: *const VNode) -> VAttr; + fn setattr(&self, va: VAttr, c: UserCred, vp: *const VNode); + fn access(&self, m: u32, c: UserCred, vp: *const VNode); + fn lookup(&self, nm: &str, c: UserCred, vp: *const VNode) -> Result; + fn create( + &self, + nm: &str, + va: VAttr, + e: u32, + m: u32, + c: UserCred, + vp: *const VNode, + ) -> Result; + fn link(&self, target_dir: *mut VNode, target_name: &str, c: UserCred, vp: *const VNode); + fn rename( + &self, + nm: &str, + target_dir: *mut VNode, + target_name: &str, + c: UserCred, + vp: *const VNode, + ); + fn mkdir(&self, nm: &str, va: VAttr, c: UserCred, vp: *const VNode) -> Result; + fn readdir(&self, uiop: *const UIO, c: UserCred, vp: *const VNode); + fn symlink(&self, link_name: &str, va: VAttr, target_name: &str, c: UserCred, vp: *const VNode); + fn readlink(&self, uiop: *const UIO, c: UserCred, vp: *const VNode); + fn fsync(&self, c: UserCred, vp: *const VNode); + fn inactive(&self, c: UserCred, vp: *const VNode); + fn bmap(&self, block_number: u32, bnp: (), vp: *const VNode) -> VNode; + fn strategy(&self, bp: (), vp: *const VNode); + fn bread(&self, block_number: u32, vp: *const VNode) -> Arc<[u8]>; +} + +pub struct VAttr { + typ: VNode, + mode: u16, + uid: u16, + gid: u16, + fs_id: u32, + node_id: u32, + link_count: u16, + size: u32, + block_size: u32, + last_access: u32, + last_modify: u32, + // got no clue + last_chg: u32, + // the device??? + rdev: (), + used_blocks: u32, +} + +pub fn add_vfs(mount_point: &str, fs_ops: Box) -> Result<(), ()> { + let layout = alloc::alloc::Layout::new::(); + let vfs = PHYSICAL_MEMORY_MANAGER.alloc(1).unwrap().cast::(); + + let vfs = unsafe { &mut *vfs }; + + (*vfs) = Vfs::null(); + (*vfs).ops = Some(fs_ops); + + log_info!("Adding vfs at {mount_point}"); + + if mount_point == "/" { + if unsafe { ROOT_VFS.next.is_some() } { + return Err(()); + } + + { + let vfsp = vfs.as_ptr(); + + (*vfs) + .ops + .as_ref() + .unwrap() + .mount(mount_point, &mut vfs.data, vfsp); + } + + unsafe { ROOT_VFS.next = Some(vfs.as_mut_ptr()) }; + + return Ok(()); + } + + if unsafe { ROOT_VFS.next.is_none() } { + return Err(()); + } + + let target_vfs = unsafe { ROOT_VFS.next.unwrap() }; + + let binding = unsafe { &(*target_vfs).ops }; + let mut cur_vnode = binding.as_ref().unwrap().root(target_vfs); + + let parts = mount_point.split('/').collect::>(); + + for part in parts { + // TODO: dont just lookup everything as the root user + if let Ok(vnode) = + cur_vnode + .ops + .lookup(part, UserCred { uid: 0, gid: 0 }, cur_vnode.as_ptr()) + { + cur_vnode = vnode; + } else { + return Err(()); + } + } + + if cur_vnode.vfs_mounted_here.is_some() { + return Err(()); + } + + { + let vfsp = vfs.as_ptr(); + + (*vfs) + .ops + .as_ref() + .unwrap() + .mount(mount_point, &mut vfs.data, vfsp); + } + + cur_vnode.vfs_mounted_here = Some(vfs.as_mut_ptr()); + + return Err(()); +} + +pub fn vfs_open(path: &str) -> Result { + let parts = path.split('/').collect::>(); + let target_vfs = unsafe { ROOT_VFS.next.unwrap() }; + let binding = unsafe { &(*target_vfs).ops }; + let mut cur_vnode = binding.as_ref().unwrap().root(target_vfs); + + for part in parts { + if part.is_empty() { + continue; + } + + if let Ok(vnode) = + cur_vnode + .ops + .lookup(part, UserCred { uid: 0, gid: 0 }, cur_vnode.as_ptr()) + { + cur_vnode = vnode; + } else { + return Err(()); + } + } + + return Ok(cur_vnode); } diff --git a/src/drivers/keyboard.rs b/src/drivers/keyboard.rs index fd79b72..06335b3 100755 --- a/src/drivers/keyboard.rs +++ b/src/drivers/keyboard.rs @@ -21,14 +21,17 @@ static EXTENDED_KEY: AtomicBool = AtomicBool::new(false); #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub extern "x86-interrupt" fn keyboard_interrupt_handler() { - interrupts::signal_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); + use crate::drivers::serial::write_serial; + + interrupts::signal_end_of_interrupt(); let scancode = inb(KBD_DATA_PORT); let key = parse_key(scancode); if let Some(key) = key { - crate::usr::shell::handle_key(key) + // crate::usr::shell::handle_key(key) + write_serial(key.character.unwrap() as u8); } } diff --git a/src/drivers/mod.rs b/src/drivers/mod.rs index 0a043b1..ff4e79c 100644 --- a/src/drivers/mod.rs +++ b/src/drivers/mod.rs @@ -1,8 +1,6 @@ -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub mod acpi; pub mod fs; pub mod keyboard; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub mod pci; pub mod serial; pub mod storage; diff --git a/src/drivers/pci.rs b/src/drivers/pci.rs index db1309f..834dd62 100755 --- a/src/drivers/pci.rs +++ b/src/drivers/pci.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use crate::{ arch::io::{inl, outl}, - libs::mutex::Mutex, + libs::sync::Mutex, }; const PCI_CONFIG_PORT: u16 = 0xCF8; // The base I/O port for PCI configuration access @@ -77,6 +77,7 @@ pub fn _get_pci_bar_addresses(bus: u8, device: u8, func: u8) -> (u32, u32, u32, (bar0, bar1, bar2, bar3, bar4, bar5) } +#[derive(Debug)] pub struct PciDevice { pub bus: u8, pub device: u8, @@ -130,7 +131,7 @@ pub fn enumerate_pci_bus() { } crate::println!("====== PCI DEVICES ======"); - for (i, pci_device) in PCI_DEVICES.lock().read().iter().enumerate() { + for (i, pci_device) in PCI_DEVICES.lock().iter().enumerate() { crate::println!("Entry {i:2}: {pci_device}") } } @@ -165,10 +166,7 @@ fn check_device(bus: u8, device: u8) { } fn check_function(bus: u8, device: u8, func: u8) { - PCI_DEVICES - .lock() - .write() - .push(PciDevice::new(bus, device, func)); + PCI_DEVICES.lock().push(PciDevice::new(bus, device, func)); let _secondary_bus: u8; diff --git a/src/drivers/serial.rs b/src/drivers/serial.rs index ebb88e6..5a1a615 100644 --- a/src/drivers/serial.rs +++ b/src/drivers/serial.rs @@ -1,11 +1,11 @@ use core::sync::atomic::AtomicBool; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use crate::arch::io::{inb, outb}; +#[cfg(target_arch = "x86_64")] +use crate::arch::io::{inb, outb, outsb}; // COM1 pub static PORT: u16 = 0x3f8; -pub const UART: *mut char = 0x10000000 as *mut char; +pub const UART: *mut u8 = 0x10000000 as *mut u8; pub static POISONED: AtomicBool = AtomicBool::new(false); @@ -17,7 +17,7 @@ pub static POISONED: AtomicBool = AtomicBool::new(false); // PORT + 2: Interrupt identification and FIFO control registers. // PORT + 3: Line control register, this sets DLAB to the most significant bit. // PORT + 4: Modem control register -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[cfg(target_arch = "x86_64")] pub fn init_serial() -> u8 { outb(PORT + 1, 0x00); outb(PORT + 3, 0x80); @@ -43,30 +43,49 @@ pub fn init_serial() -> u8 { } pub fn write_string(string: &str) { - for &ch in string.as_bytes() { - write_serial(ch as char); + #[cfg(target_arch = "x86_64")] + { + while is_transmit_empty() {} + + unsafe { outsb(PORT, string.as_ptr(), string.len()) } + } + #[cfg(not(target_arch = "x86_64"))] + { + for &ch in string.as_bytes() { + write_serial(ch as char); + } } - write_serial('\n'); - write_serial('\r'); } -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +#[cfg(not(target_arch = "x86_64"))] pub fn init_serial() -> u8 { return 0; } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn is_transmit_empty() -> bool { - return (inb(PORT + 5) & 0x20) != 0x20; + return inb((PORT + 5) & 0x20) == 0; } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub fn write_serial(character: char) { +pub fn write_serial(character: u8) { while is_transmit_empty() {} - if character == '\n' { - write_serial('\r'); + if character == b'\n' { + write_serial(b'\r'); } - outb(PORT, character as u8); + + outb(PORT, character); +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn serial_recieved() -> bool { + return (inb(PORT + 5) & 0x01) == 0; +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn read_serial() -> u8 { + while serial_recieved() {} + return inb(PORT); } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] @@ -75,8 +94,13 @@ pub fn is_transmit_empty() -> bool { } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -pub fn write_serial(character: char) { +pub fn write_serial(character: u8) { unsafe { *UART = character; }; } + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +pub fn read_serial() -> u8 { + return 0; +} diff --git a/src/drivers/storage/ide.rs b/src/drivers/storage/ide.rs index 859613e..e4be190 100755 --- a/src/drivers/storage/ide.rs +++ b/src/drivers/storage/ide.rs @@ -5,10 +5,10 @@ use alloc::{boxed::Box, format, sync::Arc, vec::Vec}; use crate::{ arch::io::{inb, insw, inw, outb, outsw}, drivers::{ - fs::fat, - storage::{GPTHeader, GPTPartitionEntry, MBR}, + fs::{devfs::DeviceOperations, fat, vfs::add_vfs}, + storage::{GPTHeader, GPTPartitionEntry, Partition, MBR}, }, - libs::{mutex::Mutex, uuid::Uuid}, + libs::{sync::Mutex, uuid::Uuid}, }; use super::BlockDevice; @@ -52,19 +52,20 @@ impl core::convert::From for ATADriveStatus { } } -#[repr(u8)] -enum ATADriveError { - AddressMarkNotFound = 0x01, - Track0NotFound = 0x02, - CommandAborted = 0x04, - MediaChangeReq = 0x08, - IDNotFound = 0x10, - MediaChanged = 0x20, - UncorrectableData = 0x40, - BadBlock = 0x80, -} +// #[repr(u8)] +// enum ATADriveError { +// AddressMarkNotFound = 0x01, +// Track0NotFound = 0x02, +// CommandAborted = 0x04, +// MediaChangeReq = 0x08, +// IDNotFound = 0x10, +// MediaChanged = 0x20, +// UncorrectableData = 0x40, +// BadBlock = 0x80, +// } #[repr(u8)] +#[allow(dead_code)] enum ATADriveCommand { ReadPIO = 0x20, ReadPIOExt = 0x24, @@ -81,20 +82,20 @@ enum ATADriveCommand { Identify = 0xEC, } -#[repr(u8)] -enum ATADriveIdentifyResponse { - DeviceType = 0x00, - Cylinders = 0x02, - Heads = 0x06, - Sectors = 0x0C, - Serial = 0x14, - Model = 0x36, - Capabilities = 0x62, - FieldValid = 0x6A, - MaxLBA = 0x78, - CommandSets = 0xA4, - MaxLBAExt = 0xC8, -} +// #[repr(u8)] +// enum ATADriveIdentifyResponse { +// DeviceType = 0x00, +// Cylinders = 0x02, +// Heads = 0x06, +// Sectors = 0x0C, +// Serial = 0x14, +// Model = 0x36, +// Capabilities = 0x62, +// FieldValid = 0x6A, +// MaxLBA = 0x78, +// CommandSets = 0xA4, +// MaxLBAExt = 0xC8, +// } #[repr(u16)] enum IDEDriveType { @@ -126,6 +127,7 @@ enum ATADriveType { } #[repr(u8)] +#[allow(dead_code)] enum ATADriveDataRegister { Data = 0x00, ErrorAndFeatures = 0x01, @@ -144,12 +146,14 @@ enum ATADriveDataRegister { } #[repr(u8)] +#[allow(dead_code)] enum ATADriveControlRegister { ControlAndAltStatus = 0x02, DeviceAddress = 0x03, } #[repr(u8)] +#[allow(dead_code)] enum ATADriveChannels { Primary = 0x00, Secondary = 0x01, @@ -494,6 +498,16 @@ impl ATADrive { drive_type: drive, }); } + + fn sector_count(&self) -> u64 { + let sectors = self.identify_data[120..].as_ptr(); + + return unsafe { *(sectors as *const u32) } as u64; + } + + pub fn as_ptr(&self) -> *const ATADrive { + return core::ptr::addr_of!(*self); + } } impl BlockDevice for ATADrive { @@ -530,6 +544,7 @@ static DRIVES: Mutex> = Mutex::new(Vec::new()); // This code could probably be made better and more device agnostic // But that's TODO obviously fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { + let mut drives_lock = DRIVES.lock(); let io_port_base = bar0 as u16; let control_port_base = bar1 as u16; @@ -545,20 +560,20 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { let drive = ATADrive::new(bus.clone(), drive_type); if let Ok(drive) = drive { - DRIVES.lock().write().push(drive); + drives_lock.push(drive); } } crate::log_info!( "ATA: Detected {} drive{}", - DRIVES.lock().read().len(), - match DRIVES.lock().read().len() { + drives_lock.len(), + match drives_lock.len() { 1 => "", _ => "s", } ); - for drive in DRIVES.lock().read().iter() { + for drive in drives_lock.iter() { let sectors = drive.sector_count(); crate::log_info!( @@ -586,8 +601,7 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { let gpt = GPTHeader::new(&array); - let mut partitions: Vec = - Vec::with_capacity(gpt.partition_entry_count as usize); + let mut partitions: Vec = Vec::with_capacity(gpt.partition_entry_count as usize); let partition_sector = drive .read( @@ -647,52 +661,60 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { .unwrap(); // Store the parsed information in the partition_entries array - partitions.push(GPTPartitionEntry { - partition_type_guid, - unique_partition_guid, - start_sector, - end_sector, - attributes, - partition_name, - }); + partitions.push(Partition::GPTPartition(( + GPTPartitionEntry { + partition_type_guid, + unique_partition_guid, + start_sector, + end_sector, + attributes, + partition_name, + }, + drive.as_ptr(), + ))); } for &partition in partitions.iter() { - if partition.partition_type_guid != "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" { - continue; + match partition { + Partition::GPTPartition(gpt_partition) => { + if gpt_partition.0.partition_type_guid != "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" + { + continue; + } + + let fat_fs = fat::FatFs::new(partition); + + if fat_fs.is_err() { + continue; + } + + let fat_fs = fat_fs.unwrap(); + + crate::println!("adding fat fs to / :scared:"); + + add_vfs("/", Box::new(fat_fs)); + + // let vfs = crate::drivers::fs::vfs::Vfs::new( + // Box::new(fat_fs), + // &format!("{}", gpt_partition.0.partition_type_guid), + // ); + + // crate::drivers::fs::vfs::VFS_INSTANCES.lock().push(vfs); + + // crate::println!( + // "{:?}", + // crate::drivers::fs::vfs::VFS_INSTANCES + // .lock() + // .read() + // .last() + // .unwrap() + // .open("/example.txt") + // .unwrap() + // .read() + // ); + } + _ => todo!("Handle MBR!"), } - - let fat_fs = fat::FatFs::new(drive, partition); - - if fat_fs.is_err() { - continue; - } - - let fat_fs = fat_fs.unwrap(); - - let vfs = crate::drivers::fs::vfs::Vfs::new( - Box::new(fat_fs), - &format!("{}", partition.partition_type_guid), - ); - - crate::drivers::fs::vfs::VFS_INSTANCES - .lock() - .write() - .push(vfs); - - crate::println!( - "{:?}", - crate::drivers::fs::vfs::VFS_INSTANCES - .lock() - .read() - .last() - .unwrap() - .open("/example.txt") - .unwrap() - .read() - ); } - - crate::println!("{:X?}", partitions); } } diff --git a/src/drivers/storage/mod.rs b/src/drivers/storage/mod.rs index 7edfc82..f6add2b 100644 --- a/src/drivers/storage/mod.rs +++ b/src/drivers/storage/mod.rs @@ -74,6 +74,44 @@ impl MBR { } } +#[derive(Clone, Copy, Debug)] +pub enum Partition { + MBRPartition((MBRPartition, *const dyn BlockDevice)), + GPTPartition((GPTPartitionEntry, *const dyn BlockDevice)), +} + +impl Partition { + pub fn read(&self, sector: u64, sector_count: usize) -> Result, ()> { + match self { + Partition::GPTPartition((partition, block_device)) => { + if partition.start_sector + sector + sector_count as u64 > partition.end_sector { + return Err(()); + } + + return unsafe { + (**block_device).read(partition.start_sector + sector, sector_count) + }; + } + Partition::MBRPartition((partition, block_device)) => { + if partition.partition_start_lba as u64 + sector + sector_count as u64 + > partition.partition_start_lba as u64 + partition.partition_sectors as u64 + { + return Err(()); + } + + return unsafe { + (**block_device) + .read(partition.partition_start_lba as u64 + sector, sector_count) + }; + } + } + } + + pub fn write(&self, _sector: u64, _data: &[u8]) -> Result<(), ()> { + todo!(); + } +} + #[derive(Clone, Copy, Debug)] pub struct MBRPartition { pub boot_indicator: u8, @@ -126,7 +164,7 @@ impl GPTHeader { let first_usable_block = u64::from_le_bytes(data[0x28..0x30].try_into().unwrap()); let last_usable_block = u64::from_le_bytes(data[0x30..0x38].try_into().unwrap()); let guid_bytes: [u8; 16] = data[0x38..0x48].try_into().unwrap(); - let guid = guid_bytes.try_into().unwrap(); + let guid = guid_bytes.into(); let guid_lba = u64::from_le_bytes(data[0x48..0x50].try_into().unwrap()); let partition_entry_count = u32::from_le_bytes(data[0x50..0x54].try_into().unwrap()); let partition_entry_size = u32::from_le_bytes(data[0x54..0x58].try_into().unwrap()); diff --git a/src/drivers/video/font.rs b/src/drivers/video/font.rs deleted file mode 100755 index cebffff..0000000 --- a/src/drivers/video/font.rs +++ /dev/null @@ -1,54 +0,0 @@ -use alloc::vec::Vec; - -use crate::{ - drivers::fs::{initramfs::INITRAMFS, vfs::VfsFileSystem}, - libs::{lazy::Lazy, mutex::Mutex}, -}; - -#[derive(Debug)] -pub struct PSFFontHeader { - pub magic: u32, - pub length: u32, - pub bytes_per_glyph: u32, - pub width: u32, - pub height: u32, -} - -pub struct PSFFont { - pub header: PSFFontHeader, - pub data: Vec>, -} - -impl PSFFont { - fn from_file_data(file_data: Vec) -> Result { - let header = PSFFontHeader { - magic: u32::from_be_bytes(file_data[0..4].try_into().unwrap()), - length: u32::from_le_bytes(file_data[16..20].try_into().unwrap()), - bytes_per_glyph: u32::from_le_bytes(file_data[20..24].try_into().unwrap()), - height: u32::from_le_bytes(file_data[24..28].try_into().unwrap()), - width: u32::from_le_bytes(file_data[28..32].try_into().unwrap()), - }; - - if header.magic != 0x72B54A86 { - return Err(()); - } - - let data: Vec<_> = file_data[32..] - .chunks_exact(header.bytes_per_glyph as usize) - .map(Vec::from) - .collect(); - - Ok(PSFFont { header, data }) - } -} - -pub static FONT: Lazy = Lazy::new(|| { - let file_data = INITRAMFS - .open("/font.psf") - .unwrap() - .read() - .unwrap() - .to_vec(); - - PSFFont::from_file_data(file_data).expect("Failed to create terminal font!") -}); diff --git a/src/drivers/video/mod.rs b/src/drivers/video/mod.rs deleted file mode 100755 index 26f2f1c..0000000 --- a/src/drivers/video/mod.rs +++ /dev/null @@ -1,222 +0,0 @@ -mod font; - -use crate::libs::mutex::Mutex; -use alloc::vec; -use limine::FramebufferRequest; - -pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(0); - -pub static FRAMEBUFFER: Mutex> = Mutex::new(None); - -// This is slow, but significantly faster than filling the framebuffer pixel-by-pixel with for loops. -// idk, fix it later ig. -pub fn fill_screen(color: u32, mirror_buffer: Option) { - let framebuffer = - get_framebuffer().expect("Tried to use framebuffer, but framebuffer was not found"); - - let framebuffer_ptr = framebuffer.pointer; - - let buffer_size = (framebuffer.pitch / (framebuffer.bpp / 8)) * framebuffer.height; - - unsafe { - if let Some(mirror_buffer) = mirror_buffer { - crate::libs::util::memset32(mirror_buffer.pointer as *mut u32, color, buffer_size); - } - - crate::libs::util::memset32(framebuffer_ptr as *mut u32, color, buffer_size); - } -} - -pub fn put_char( - mut character: char, - cx: u16, - cy: u16, - mut fg: u32, - bg: u32, - mirror_buffer: Option, -) { - let font = &font::FONT; - let font_width = font.header.width; - let font_height = font.header.height; - - if character as usize > u8::MAX as usize { - character = '\x00'; // rounded question mark - fg = 0xFF0000; - } - - let character_array = &font.data[character as usize]; - - let framebuffer = - get_framebuffer().expect("Tried to use framebuffer, but framebuffer was not found"); - - let start_x = cx * font_width as u16; - let start_y = cy * font_height as u16; - - for (row_idx, &character_byte) in character_array.iter().enumerate() { - let mut byte = vec![bg; font_width as usize]; - for (i, bit) in byte.iter_mut().enumerate() { - *bit = [bg, fg] - [((character_byte >> ((font_width as usize - 1) - i)) & 0b00000001) as usize] - } - - let row_start_offset = (start_y as usize + row_idx) * framebuffer.pitch - + (start_x as usize * framebuffer.bpp / 8); - - unsafe { - let src_ptr = byte.as_ptr() as *const u128; - - core::ptr::copy_nonoverlapping( - src_ptr, - framebuffer.pointer.add(row_start_offset) as *mut u128, - 2, - ); - - if let Some(mirror_framebuffer) = mirror_buffer { - core::ptr::copy_nonoverlapping( - src_ptr, - mirror_framebuffer.pointer.add(row_start_offset) as *mut u128, - 2, - ); - } - }; - } -} - -// pub static GLYPH_CACHE: Mutex>>> = Mutex::new(None); - -// pub fn put_char( -// character: char, -// cx: u16, -// cy: u16, -// fg: u32, -// bg: u32, -// mirror_buffer: Option, -// ) { -// let font = font::G_8X16_FONT; -// let character_array = font[character as usize]; - -// let framebuffer = -// get_framebuffer().expect("Tried to use framebuffer, but framebuffer was not found"); - -// let glyph_index = character as u8 as usize; - -// if GLYPH_CACHE.lock().read().is_none() { -// *GLYPH_CACHE.lock().write() = Some(alloc::vec![None; u8::MAX as usize]); -// } - -// // Lock once and reuse the lock result -// let mut glyph_cache_lock = GLYPH_CACHE.lock(); -// let glyph_cache = glyph_cache_lock.write().as_mut().unwrap(); - -// if glyph_cache[glyph_index].is_none() { -// let mut new_character_buf = [[bg; 8]; 16]; - -// for (i, &character_byte) in character_array.iter().enumerate() { -// let mut byte = [bg; 8]; -// for bit in 0..8 { -// byte[bit] = [bg, fg][((character_byte >> (7 - bit)) & 0b00000001) as usize]; -// } - -// new_character_buf[i] = byte; -// } - -// glyph_cache[glyph_index] = Some(new_character_buf); -// } - -// let start_x = cx * 8; -// let start_y = cy * 16; - -// let character_buf = glyph_cache[glyph_index].unwrap(); - -// for row_index in 0..character_buf.len() { -// let row_num = start_y as usize + row_index; -// let row_offset = (row_num as usize * framebuffer.pitch) as usize; -// let col_offset = (start_x as usize * framebuffer.bpp / 8) as usize; -// let row_start_offset = row_offset + col_offset; - -// unsafe { -// let src_ptr = character_buf[row_index].as_ptr() as *const u128; - -// core::ptr::copy_nonoverlapping( -// src_ptr, -// framebuffer.pointer.add(row_start_offset) as *mut u128, -// 2, -// ); - -// if let Some(mirror_framebuffer) = mirror_buffer { -// core::ptr::copy_nonoverlapping( -// src_ptr, -// mirror_framebuffer.pointer.add(row_start_offset) as *mut u128, -// 2, -// ); -// } -// }; -// } -// } - -pub fn put_pixel(x: u32, y: u32, color: u32) { - let framebuffer = - get_framebuffer().expect("Tried to use framebuffer, but framebuffer was not found"); - - let framebuffer_ptr = framebuffer.pointer; - - let pixel_offset = (y * framebuffer.pitch as u32 + (x * (framebuffer.bpp / 8) as u32)) as isize; - - unsafe { - *(framebuffer_ptr.offset(pixel_offset) as *mut u32) = color; - } -} - -#[derive(Clone, Copy, Debug)] -pub struct Framebuffer { - pub width: usize, - pub height: usize, - pub bpp: usize, - pub pitch: usize, - pub pointer: *mut u8, -} - -impl Framebuffer { - #[inline] - const fn new(bpp: usize, pitch: usize, ptr: *mut u8, width: usize, height: usize) -> Self { - return Self { - width, - height, - bpp, - pitch, - pointer: ptr, - }; - } -} - -pub fn get_framebuffer() -> Option { - let framebuffer_mutex_lock = FRAMEBUFFER.lock(); - - if framebuffer_mutex_lock.read().is_some() { - return Some(FRAMEBUFFER.lock().read().unwrap()); - } - - let framebuffer_response = crate::drivers::video::FRAMEBUFFER_REQUEST - .get_response() - .get()?; - - if framebuffer_response.framebuffer_count < 1 { - return None; - } - - let framebuffer_response = &framebuffer_response.framebuffers()[0]; - - let framebuffer = Framebuffer::new( - framebuffer_response.bpp as usize, - framebuffer_response.pitch as usize, - framebuffer_response.address.as_ptr().unwrap(), - framebuffer_response.width as usize, - framebuffer_response.height as usize, - ); - - let mut framebuffer_mutex_lock = FRAMEBUFFER.lock(); - - *(framebuffer_mutex_lock.write()) = Some(framebuffer); - - return Some(framebuffer); -} diff --git a/src/libs/elf.rs b/src/libs/elf.rs deleted file mode 100644 index ae65ddd..0000000 --- a/src/libs/elf.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[derive(Clone, Copy, Debug)] -pub struct Elf; - -pub fn load_elf(bytes: &[u8]) -> Result { - if &bytes[0..4] != b"\x74ELF" { - return Err(()); - } - - if bytes[5] != 0x02 { - // Only support 64-bit ELF files for now - return Err(()); - } - - return Ok(Elf); -} diff --git a/src/libs/lazy.rs b/src/libs/lazy.rs deleted file mode 100755 index fb20eda..0000000 --- a/src/libs/lazy.rs +++ /dev/null @@ -1,44 +0,0 @@ -use core::{ - cell::UnsafeCell, - ops::Deref, - sync::atomic::{AtomicBool, Ordering}, -}; - -pub struct Lazy T> { - value: UnsafeCell>, - init_func: F, - initialized: AtomicBool, -} - -impl T> Lazy { - pub const fn new(init_func: F) -> Self { - Lazy { - value: UnsafeCell::new(None), - init_func, - initialized: AtomicBool::new(false), - } - } -} - -impl T> Deref for Lazy { - type Target = T; - - fn deref(&self) -> &Self::Target { - if !self.initialized.load(Ordering::Acquire) { - let value = (self.init_func)(); - unsafe { - *(self.value.get()) = Some(value); - } - - self.initialized.store(true, Ordering::Release); - } - - unsafe { - (*self.value.get()) - .as_ref() - .expect("Lazy value is not initialized!") - } - } -} - -unsafe impl T + Send> Sync for Lazy {} diff --git a/src/libs/logging.rs b/src/libs/logging.rs deleted file mode 100644 index 4fa9d26..0000000 --- a/src/libs/logging.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[macro_export] -macro_rules! log_info { - ($($arg:tt)*) => ($crate::println!("\033[97m[ \033[90m? \033[97m]\033[0m {}", &alloc::format!($($arg)*))); -} - -#[macro_export] -macro_rules! log_serial { - ($($arg:tt)*) => ( - $crate::drivers::serial::write_string(&alloc::format!($($arg)*)) - ); -} - -#[macro_export] -macro_rules! log_error { - ($($arg:tt)*) => ($crate::println!("\033[97m[ \033[91m! \033[97m]\033[0m {}", &alloc::format!($($arg)*))); -} - -#[macro_export] -macro_rules! log_ok { - ($($arg:tt)*) => ($crate::println!("\033[97m[ \033[92m* \033[97m]\033[0;m {}", &alloc::format!($($arg)*))); -} diff --git a/src/libs/math.rs b/src/libs/math.rs deleted file mode 100644 index 717e494..0000000 --- a/src/libs/math.rs +++ /dev/null @@ -1,89 +0,0 @@ -pub fn abs(x: f64) -> f64 { - return f64::from_bits(x.to_bits() & (u64::MAX / 2)); -} - -const TOINT: f64 = 1. / f64::EPSILON; - -pub fn floor(x: f64) -> f64 { - #[cfg(all( - any(target_arch = "x86", target_arch = "x86_64"), - not(target_feature = "sse2") - ))] - { - if abs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated > x { - return truncated - 1.0; - } else { - return truncated; - } - } else { - return x; - } - } - - let ui = x.to_bits(); - let e = ((ui >> 52) & 0x7FF) as i32; - - if (e >= 0x3FF + 52) || (x == 0.) { - return x; - } - - let y = if (ui >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT + TOINT - x - }; - - if e < 0x3FF { - return if (ui >> 63) != 0 { -1. } else { 0. }; - } - - if y > 0. { - return x + y - 1.; - } else { - return x + y; - } -} - -pub fn ceil(x: f64) -> f64 { - #[cfg(all( - any(target_arch = "x86", target_arch = "x86_64"), - not(target_feature = "sse2") - ))] - { - if abs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated < x { - return truncated + 1.0; - } else { - return truncated; - } - } else { - return x; - } - } - - let u: u64 = x.to_bits(); - let e: i64 = (u >> 52 & 0x7ff) as i64; - - if e >= 0x3ff + 52 || x == 0. { - return x; - } - - let y = if (u >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT - TOINT - x - }; - - if e < 0x3ff { - return if (u >> 63) != 0 { -0. } else { 1. }; - } - - if y < 0. { - return x + y + 1.; - } else { - return x + y; - } -} diff --git a/src/libs/mod.rs b/src/libs/mod.rs index 763fec1..8e1965f 100644 --- a/src/libs/mod.rs +++ b/src/libs/mod.rs @@ -1,8 +1,3 @@ -pub mod elf; -pub mod lazy; -pub mod logging; -pub mod math; -pub mod mutex; -pub mod oncecell; -pub mod util; +pub mod cell; +pub mod sync; pub mod uuid; diff --git a/src/libs/mutex.rs b/src/libs/mutex.rs deleted file mode 100755 index b5e4090..0000000 --- a/src/libs/mutex.rs +++ /dev/null @@ -1,62 +0,0 @@ -use core::{ - cell::UnsafeCell, - sync::atomic::{AtomicBool, Ordering}, -}; - -// TODO: Rip the lock out of mutex and make it more generic to be able to use it outside of mutexes - -pub struct Mutex { - locked: AtomicBool, - data: UnsafeCell, -} - -unsafe impl Sync for Mutex {} - -impl Mutex { - #[inline] - pub const fn new(data: T) -> Self { - return Self { - locked: AtomicBool::new(false), - data: UnsafeCell::new(data), - }; - } - - pub fn lock(&self) -> MutexGuard<'_, T> { - while self.locked.swap(true, Ordering::Acquire) { - // spin lock - } - return MutexGuard { mutex: self }; - } -} - -impl core::fmt::Debug for Mutex { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let locked = self.locked.load(Ordering::SeqCst); - write!(f, "Mutex: {{ data: ",)?; - if locked { - write!(f, " }}") - } else { - write!(f, "{:?} }}", self.data) - } - } -} - -pub struct MutexGuard<'a, T: ?Sized> { - mutex: &'a Mutex, -} - -impl<'a, T: ?Sized> MutexGuard<'a, T> { - pub fn read(self) -> &'a T { - unsafe { &*self.mutex.data.get() } - } - - pub fn write(&mut self) -> &'a mut T { - unsafe { &mut *self.mutex.data.get() } - } -} - -impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { - fn drop(&mut self) { - self.mutex.locked.store(false, Ordering::Release); - } -} diff --git a/src/libs/oncecell.rs b/src/libs/oncecell.rs deleted file mode 100644 index f72b22e..0000000 --- a/src/libs/oncecell.rs +++ /dev/null @@ -1,70 +0,0 @@ -use core::{cell::UnsafeCell, ops::Deref, sync::atomic::AtomicU8}; - -pub struct OnceCell { - state: AtomicU8, - data: UnsafeCell>, -} - -unsafe impl Sync for OnceCell {} - -#[repr(u8)] -enum State { - Uninitialized = 0, - Initializing, - Initialized, -} - -impl From for State { - fn from(value: u8) -> Self { - match value { - 0 => State::Uninitialized, - 1 => State::Initializing, - 2 => State::Initialized, - _ => panic!("Invalid state value"), - } - } -} - -impl OnceCell { - pub const fn new() -> Self { - return OnceCell { - state: AtomicU8::new(State::Uninitialized as u8), - data: UnsafeCell::new(None), - }; - } - - pub fn set(&self, new_data: T) { - let current_state = self.state.load(core::sync::atomic::Ordering::SeqCst); - - match State::from(current_state) { - State::Uninitialized => { - self.state.store( - State::Initializing as u8, - core::sync::atomic::Ordering::SeqCst, - ); - - unsafe { *self.data.get() = Some(new_data) }; - - self.state.store( - State::Initialized as u8, - core::sync::atomic::Ordering::SeqCst, - ); - } - _ => panic!("Tried to initialize data that is alread initialized"), - } - } -} - -impl Deref for OnceCell { - type Target = T; - - fn deref(&self) -> &Self::Target { - if self.state.load(core::sync::atomic::Ordering::SeqCst) == State::Initialized as u8 { - if let Some(value) = unsafe { &*self.data.get() } { - return value; - } - } - - panic!("Attempted to access uninitialized data!") - } -} diff --git a/src/libs/util.rs b/src/libs/util.rs deleted file mode 100644 index 0778cd0..0000000 --- a/src/libs/util.rs +++ /dev/null @@ -1,35 +0,0 @@ -pub unsafe fn memset32(dst: *mut u32, val: u32, count: usize) { - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - { - let mut buf = dst; - unsafe { - while buf < dst.add(count) { - core::ptr::write_volatile(buf, val); - buf = buf.offset(1); - } - } - return; - } - - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - core::arch::asm!( - "rep stosd", - inout("ecx") count => _, - inout("edi") dst => _, - inout("eax") val => _ - ); - } -} - -pub fn hcf() -> ! { - loop { - unsafe { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - core::arch::asm!("hlt"); - - #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] - core::arch::asm!("wfi"); - } - } -} diff --git a/src/libs/uuid.rs b/src/libs/uuid.rs index 149a750..c2017f0 100644 --- a/src/libs/uuid.rs +++ b/src/libs/uuid.rs @@ -29,7 +29,7 @@ impl PartialEq for Uuid { impl PartialEq<&str> for Uuid { fn eq(&self, other: &&str) -> bool { - let parts = other.split("-").collect::>(); + let parts = other.split('-').collect::>(); if parts.len() != 5 { return false; diff --git a/src/main.rs b/src/main.rs old mode 100755 new mode 100644 index b5f07b4..156f437 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,25 @@ -#![feature(abi_x86_interrupt, allocator_api, naked_functions)] +#![feature(abi_x86_interrupt, naked_functions)] +// Unforunately, this doesnt actually work with rust-analyzer, so if you want the annoying +// Error about "unnecessary returns" to go away, see https://github.com/rust-lang/rust-analyzer/issues/16542 +// And if that issue ever gets closed, and you're reading this, feel free to remove this comment +#![allow(clippy::needless_return)] #![no_std] #![no_main] -extern crate alloc; - -mod arch; -mod drivers; -mod libs; -mod mem; -mod usr; - use core::ffi::CStr; use alloc::{format, vec::Vec}; -use drivers::serial; -use libs::util::hcf; +use drivers::serial::{read_serial, write_serial}; use limine::KernelFileRequest; -use crate::{drivers::serial::write_serial, mem::LabelBytes}; +use crate::drivers::fs::vfs::{vfs_open, UserCred}; + +extern crate alloc; + +pub mod arch; +pub mod drivers; +pub mod libs; +pub mod mem; pub static KERNEL_REQUEST: KernelFileRequest = KernelFileRequest::new(0); @@ -26,36 +28,100 @@ pub extern "C" fn _start() -> ! { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] arch::interrupts::init(); - serial::init_serial(); - - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - drivers::acpi::init_acpi(); - - mem::log_info(); + drivers::serial::init_serial(); #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] drivers::pci::enumerate_pci_bus(); - drivers::fs::vfs::init(); + drivers::storage::ide::init(); - // crate::println!("{:?}", INITRAMFS.open("/font.psf").unwrap().read()); - - if let Some(kernel) = KERNEL_REQUEST.get_response().get() { - crate::println!("{:X?}", kernel.kernel_file.get().unwrap().gpt_disk_uuid); - } + crate::println!("{:?}", vfs_open("/example.txt")); + let file = vfs_open("/example.txt").unwrap(); crate::println!( - "Total memory: {}", - crate::mem::PHYSICAL_MEMORY_MANAGER - .total_memory() - .label_bytes() + "{:X?}", + file.ops.open(0, UserCred { uid: 0, gid: 0 }, file.as_ptr()) ); - usr::shell::init_shell(); + let fb = drivers::video::get_framebuffer().unwrap(); + let length = (fb.height * fb.width) * (fb.bpp / 8); + let pages = length / crate::mem::pmm::PAGE_SIZE; + let buffer = unsafe { + core::slice::from_raw_parts_mut( + crate::mem::PHYSICAL_MEMORY_MANAGER + .alloc(pages) + .expect("Could not allocate color buffer") as *mut u32, + length, + ) + }; + + for y in 0..fb.height { + let r = ((y as f32) / ((fb.height - 1) as f32)) * 200.0; + for x in 0..fb.width { + let g = ((x as f32) / ((fb.width - 1) as f32)) * 200.0; + buffer[y * fb.width + x] = ((r as u32) << 16) | ((g as u32) << 8) | 175; + } + } + + fb.blit_screen(buffer, None); + + loop { + let ch = read_serial(); + + if ch == b'\x00' { + continue; + } + + if ch == b'\x08' { + write_serial(b'\x08'); + write_serial(b' '); + write_serial(b'\x08'); + } + + if ch > 0x20 && ch < 0x7F { + write_serial(ch); + } + } hcf(); } +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ($crate::print!("{}\n", &alloc::format!($($arg)*))); +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ( + + $crate::drivers::serial::write_string(&alloc::format!($($arg)*).replace('\n', "\n\r")) + ) +} + +#[macro_export] +macro_rules! log_info { + ($($arg:tt)*) => ($crate::println!("\x1B[97m[ \x1B[90m? \x1B[97m]\x1B[0m () {}", &alloc::format!($($arg)*))); +} + +#[macro_export] +macro_rules! log_serial { + ($($arg:tt)*) => ( + $crate::drivers::serial::write_string(&alloc::format!($($arg)*).replace('\n', "\n\r")) + ); +} + +#[macro_export] +macro_rules! log_error { + ($($arg:tt)*) => ($crate::println!("\x1B[97m[ \x1B[91m! \x1B[97m]\x1B[0m {}", &alloc::format!($($arg)*))); +} + +#[macro_export] +macro_rules! log_ok { + ($($arg:tt)*) => ($crate::println!("\x1B[97m[ \x1B[92m* \x1B[97m]\x1B[0;m {}", &alloc::format!($($arg)*))); +} + #[derive(Debug)] pub struct KernelFeatures { pub fat_in_mem: bool, @@ -71,8 +137,8 @@ impl KernelFeatures { } } -pub static KERNEL_FEATURES: libs::lazy::Lazy = - libs::lazy::Lazy::new(parse_kernel_cmdline); +pub static KERNEL_FEATURES: libs::cell::LazyCell = + libs::cell::LazyCell::new(parse_kernel_cmdline); fn parse_kernel_cmdline() -> KernelFeatures { let mut kernel_features: KernelFeatures = KernelFeatures { fat_in_mem: true }; @@ -118,13 +184,9 @@ fn parse_kernel_cmdline() -> KernelFeatures { #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { - let message = format!("{}\n", info); + let msg = &format!("{info}\n").replace('\n', "\n\r"); - for ch in message.chars() { - write_serial(ch); - } - - log_error!("{}", info); + drivers::serial::write_string(msg); #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { @@ -137,3 +199,15 @@ fn panic(info: &core::panic::PanicInfo) -> ! { hcf(); } + +pub fn hcf() -> ! { + loop { + unsafe { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + core::arch::asm!("hlt"); + + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + core::arch::asm!("wfi"); + } + } +} diff --git a/src/mem/allocator.rs b/src/mem/allocator.rs index 260d029..e97e67e 100644 --- a/src/mem/allocator.rs +++ b/src/mem/allocator.rs @@ -1,6 +1,6 @@ // Original code from: https://github.com/DrChat/buddyalloc/blob/master/src/heap.rs // But I made it ~~much worse~~ *better* by making it GlobalAlloc compatible -// By using A custom Mutex implementation (which also sucks) and dereferencing all the pointers, +// By using A custom Mutex implementation (which also sucks), // I was able to remove all the mut's In the original code. // TODO: Replace this with a slab allocator that can take advantage of the page frame allocator @@ -11,7 +11,7 @@ use core::ptr; use core::sync::atomic::Ordering::SeqCst; use core::sync::atomic::{AtomicPtr, AtomicU8, AtomicUsize}; -use crate::libs::mutex::Mutex; +use crate::libs::sync::Mutex; const fn log2(num: usize) -> u8 { let mut temp = num; @@ -107,33 +107,36 @@ impl BuddyAllocator { } fn free_list_pop(&self, order: usize) -> Option<*mut u8> { - let candidate = (*self.free_lists.lock().read())[order]; + let mut free_lists_lock = self.free_lists.lock(); + + let candidate = (*free_lists_lock)[order]; if candidate.is_null() { return None; } - if order != self.free_lists.lock().read().len() - 1 { - (*self.free_lists.lock().write())[order] = unsafe { (*candidate).next }; + if order != free_lists_lock.len() - 1 { + (*free_lists_lock)[order] = unsafe { (*candidate).next }; } else { - (*self.free_lists.lock().write())[order] = ptr::null_mut(); + (*free_lists_lock)[order] = ptr::null_mut(); } return Some(candidate as *mut u8); } fn free_list_insert(&self, order: usize, block: *mut u8) { + let mut free_lists_lock = self.free_lists.lock(); let free_block_ptr = block as *mut FreeBlock; - unsafe { *free_block_ptr = FreeBlock::new((*self.free_lists.lock().read())[order]) }; + unsafe { *free_block_ptr = FreeBlock::new((*free_lists_lock)[order]) }; - (*self.free_lists.lock().write())[order] = free_block_ptr; + (*free_lists_lock)[order] = free_block_ptr; } fn free_list_remove(&self, order: usize, block: *mut u8) -> bool { let block_ptr = block as *mut FreeBlock; - let mut checking: &mut *mut FreeBlock = &mut (*self.free_lists.lock().write())[order]; + let mut checking: &mut *mut FreeBlock = &mut (*self.free_lists.lock())[order]; unsafe { while !(*checking).is_null() { @@ -177,11 +180,12 @@ impl BuddyAllocator { } pub fn get_free_mem(&self) -> usize { + let free_lists_lock = self.free_lists.lock(); let mut free_mem = 0; unsafe { - for order in 0..self.free_lists.lock().read().len() { - let mut block = (*self.free_lists.lock().write())[order]; + for order in 0..free_lists_lock.len() { + let mut block = (*free_lists_lock)[order]; while !block.is_null() { free_mem += self.order_size(order); @@ -201,7 +205,9 @@ impl BuddyAllocator { unsafe impl GlobalAlloc for BuddyAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { if let Some(order_needed) = self.allocation_order(layout.size(), layout.align()) { - for order in order_needed..self.free_lists.lock().read().len() { + let free_lists_len = { self.free_lists.lock().len() }; + + for order in order_needed..free_lists_len { if let Some(block) = self.free_list_pop(order) { if order > order_needed { self.split_free_block(block, order, order_needed); @@ -221,7 +227,9 @@ unsafe impl GlobalAlloc for BuddyAllocator { .expect("Tried to dispose of invalid block"); let mut block = ptr; - for order in initial_order..self.free_lists.lock().read().len() { + let free_lists_len = { self.free_lists.lock().len() }; + + for order in initial_order..free_lists_len { if let Some(buddy) = self.buddy(order, block) { if self.free_list_remove(order, block) { block = min(block, buddy); @@ -234,3 +242,33 @@ unsafe impl GlobalAlloc for BuddyAllocator { } } } + +#[no_mangle] +pub extern "C" fn malloc(size: usize) -> *mut u8 { + let layout = alloc::alloc::Layout::from_size_align(size, 2); + + if layout.is_err() { + return core::ptr::null_mut(); + } + + unsafe { + return alloc::alloc::alloc(layout.unwrap()); + }; +} + +#[no_mangle] +pub extern "C" fn free(ptr: *mut u8, size: usize) { + if ptr.is_null() { + return; + } + + let layout = alloc::alloc::Layout::from_size_align(size, 2); + + if layout.is_err() { + return; + } + + unsafe { + alloc::alloc::dealloc(ptr, layout.unwrap()); + }; +} diff --git a/src/mem/mod.rs b/src/mem/mod.rs index b8e17b9..adbb516 100755 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -5,17 +5,14 @@ use core::alloc::GlobalAlloc; use limine::{MemmapEntry, NonNullPtr}; -use crate::{ - libs::{lazy::Lazy, mutex::Mutex}, - usr::tty::CONSOLE, -}; +use crate::libs::{cell::LazyCell, sync::Mutex}; use self::{allocator::BuddyAllocator, pmm::PhysicalMemoryManager}; static MEMMAP_REQUEST: limine::MemmapRequest = limine::MemmapRequest::new(0); static HHDM_REQUEST: limine::HhdmRequest = limine::HhdmRequest::new(0); -pub static MEMMAP: Lazy]>> = Lazy::new(|| { +pub static MEMMAP: LazyCell]>> = LazyCell::new(|| { let memmap_request = MEMMAP_REQUEST .get_response() .get_mut() @@ -24,7 +21,7 @@ pub static MEMMAP: Lazy]>> = Lazy::new(|| { return Mutex::new(memmap_request.memmap_mut()); }); -pub static HHDM_OFFSET: Lazy = Lazy::new(|| { +pub static HHDM_OFFSET: LazyCell = LazyCell::new(|| { let hhdm = HHDM_REQUEST .get_response() .get() @@ -33,37 +30,11 @@ pub static HHDM_OFFSET: Lazy = Lazy::new(|| { return hhdm.offset as usize; }); -pub static PHYSICAL_MEMORY_MANAGER: Lazy = - Lazy::new(PhysicalMemoryManager::new); +pub static PHYSICAL_MEMORY_MANAGER: LazyCell = + LazyCell::new(PhysicalMemoryManager::new); -pub struct PageAllocator; - -unsafe impl core::alloc::Allocator for PageAllocator { - fn allocate( - &self, - layout: core::alloc::Layout, - ) -> Result, core::alloc::AllocError> { - let pages = layout.size() / 4096 + 1; - let ptr = PHYSICAL_MEMORY_MANAGER.alloc(pages); - - if ptr.is_err() { - return Err(core::alloc::AllocError); - } - - let ptr = ptr.unwrap(); - let slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(ptr, pages) }; - - unsafe { Ok(core::ptr::NonNull::new_unchecked(slice)) } - } - - unsafe fn deallocate(&self, ptr: core::ptr::NonNull, layout: core::alloc::Layout) { - let pages = layout.size() / 4096 + 1; - - PHYSICAL_MEMORY_MANAGER.dealloc(ptr.as_ptr(), pages); - } -} pub struct Allocator { - pub inner: Lazy, + pub inner: LazyCell, } unsafe impl GlobalAlloc for Allocator { @@ -81,7 +52,7 @@ const HEAP_SIZE: usize = HEAP_PAGES * 1024; #[global_allocator] pub static ALLOCATOR: Allocator = Allocator { - inner: Lazy::new(|| { + inner: LazyCell::new(|| { let heap_start = PHYSICAL_MEMORY_MANAGER .alloc(HEAP_PAGES) .expect("Failed to allocate heap!"); @@ -90,45 +61,6 @@ pub static ALLOCATOR: Allocator = Allocator { }), }; -#[no_mangle] -pub extern "C" fn malloc(size: usize) -> *mut u8 { - let layout = core::alloc::Layout::from_size_align(size, 1).unwrap(); - unsafe { ALLOCATOR.alloc(layout) } -} - -#[no_mangle] -pub extern "C" fn free(ptr: *mut u8, size: usize) { - let layout = core::alloc::Layout::from_size_align(size, 1).unwrap(); - unsafe { - ALLOCATOR.dealloc(ptr, layout); - } -} - -pub fn log_info() { - crate::log_info!( - "Initialized heap with {} of memory at {:#X}", - HEAP_SIZE.label_bytes(), - ALLOCATOR - .inner - .heap_start - .load(core::sync::atomic::Ordering::SeqCst) as usize - ); - - if CONSOLE.get_features().doubled_buffered { - let row_size = CONSOLE.second_buffer.lock().read().unwrap().pitch - / (CONSOLE.second_buffer.lock().read().unwrap().bpp / 8); - - let screen_size = row_size * CONSOLE.second_buffer.lock().read().unwrap().height; - crate::log_info!( - "Initialized framebuffer mirroring with {} at {:#X}", - (screen_size * 4).label_bytes(), - CONSOLE.second_buffer.lock().read().unwrap().pointer as usize - ); - } - - log_memory_map(); -} - pub fn log_memory_map() { let memmap_request = MEMMAP_REQUEST.get_response().get_mut(); if memmap_request.is_none() { @@ -137,12 +69,12 @@ pub fn log_memory_map() { let memmap = memmap_request.unwrap().memmap(); - crate::log_serial!("====== MEMORY MAP ======"); + crate::log_serial!("====== MEMORY MAP ======\n"); for entry in memmap.iter() { let label = (entry.len as usize).label_bytes(); crate::log_serial!( - "[ {:#018X?} ] Type: {:?} Size: {}", + "[ {:#018X?} ] Type: {:?} Size: {}\n", entry.base..entry.base + entry.len, entry.typ, label @@ -195,3 +127,29 @@ impl LabelBytes for usize { } } } + +/// # Safety +/// This will produce undefined behavior if dst is not valid for count writes +pub unsafe fn memset32(dst: *mut u32, val: u32, count: usize) { + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + { + let mut buf = dst; + unsafe { + while buf < dst.add(count) { + core::ptr::write_volatile(buf, val); + buf = buf.offset(1); + } + } + return; + } + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + core::arch::asm!( + "rep stosd", + inout("ecx") count => _, + inout("edi") dst => _, + inout("eax") val => _ + ); + } +} diff --git a/src/mem/pmm.rs b/src/mem/pmm.rs index 867918d..202ef2e 100644 --- a/src/mem/pmm.rs +++ b/src/mem/pmm.rs @@ -27,7 +27,7 @@ impl PhysicalMemoryManager { let mut highest_addr: usize = 0; - for entry in super::MEMMAP.lock().read().iter() { + for entry in super::MEMMAP.lock().iter() { if entry.typ == limine::MemoryMapEntryType::Usable { pmm.usable_pages .fetch_add(entry.len as usize / PAGE_SIZE, Ordering::SeqCst); @@ -42,7 +42,7 @@ impl PhysicalMemoryManager { let bitmap_size = ((pmm.highest_page_idx.load(Ordering::SeqCst) / 8) + PAGE_SIZE - 1) & !(PAGE_SIZE - 1); - for entry in super::MEMMAP.lock().write().iter_mut() { + for entry in super::MEMMAP.lock().iter_mut() { if entry.typ != limine::MemoryMapEntryType::Usable { continue; } @@ -63,7 +63,7 @@ impl PhysicalMemoryManager { } } - for entry in super::MEMMAP.lock().read().iter() { + for entry in super::MEMMAP.lock().iter() { if entry.typ != limine::MemoryMapEntryType::Usable { continue; } diff --git a/src/usr/mod.rs b/src/usr/mod.rs deleted file mode 100644 index 145cb15..0000000 --- a/src/usr/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod shell; -#[macro_use] -pub mod tty; diff --git a/src/usr/shell.rs b/src/usr/shell.rs deleted file mode 100755 index cff1991..0000000 --- a/src/usr/shell.rs +++ /dev/null @@ -1,282 +0,0 @@ -use core::sync::atomic::{AtomicU8, Ordering}; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use crate::drivers::keyboard::set_leds; -use crate::drivers::keyboard::Key; - -struct ModStatus { - pub win: bool, // first bit (0000_0001) - pub ctrl: bool, // second bit (0000_0010) - pub alt: bool, // third bit (0000_0100) - pub shift: bool, // forth bit (0000_1000) - pub caps: bool, // fifth bit (0001_0000) - pub num_lock: bool, // sixth bit (0010_0000) - pub scr_lock: bool, // (possibly unnecessary) seventh bit (0100_0000) -} - -impl ModStatus { - fn to_byte(&self) -> u8 { - let mut value = 0u8; - if self.win { - value |= 0b0000_0001; - } - if self.ctrl { - value |= 0b0000_0010; - } - if self.alt { - value |= 0b0000_0100; - } - if self.shift { - value |= 0b0000_1000; - } - if self.caps { - value |= 0b0001_0000; - } - if self.num_lock { - value |= 0b0010_0000; - } - if self.scr_lock { - value |= 0b0100_0000; - } - return value; - } -} - -struct ModStatusBits { - status: AtomicU8, - led_status: AtomicU8, -} - -impl ModStatusBits { - #[inline] - const fn new() -> Self { - return Self { - status: AtomicU8::new(0u8), - led_status: AtomicU8::new(0u8), - }; - } - - fn get_status(&self) -> ModStatus { - let status = self.status.load(Ordering::SeqCst); - - return ModStatus { - win: (status & 1) != 0, - ctrl: ((status >> 1) & 1) != 0, - alt: ((status >> 2) & 1) != 0, - shift: ((status >> 3) & 1) != 0, - caps: ((status >> 4) & 1) != 0, - num_lock: ((status >> 5) & 1) != 0, - scr_lock: ((status >> 6) & 1) != 0, - }; - } - - fn set_modifier_key(&self, key: &str, status: bool) { - let mut led_status = self.led_status.load(Ordering::SeqCst); - let mut mod_status = self.get_status(); - - match key { - "win" => mod_status.win = status, - "ctrl" => mod_status.ctrl = status, - "alt" => mod_status.alt = status, - "shift" => mod_status.shift = status, - "caps" => { - led_status ^= 0b00000100; - mod_status.caps = status - } - "num_lock" => { - led_status ^= 0b00000010; - mod_status.num_lock = status - } - "scr_lock" => { - led_status ^= 0b00000100; - mod_status.scr_lock = status - } - _ => return, - } - - // set Keyboard led (caps, num lock, scroll lock) - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - set_leds(led_status); - - self.led_status.store(led_status, Ordering::SeqCst); - let new_value = mod_status.to_byte(); - self.status.store(new_value, Ordering::SeqCst); - } -} - -static MOD_STATUS: ModStatusBits = ModStatusBits::new(); - -pub fn init_shell() { - prompt(); - - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - let kbd_result = crate::drivers::keyboard::init(); - - if kbd_result.is_err() { - crate::log_error!("Unable to initialize keyboard! {:?}", kbd_result); - } - } - - // #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - // crate::drivers::keyboard::consume_scancode(); -} - -pub fn handle_key(mut key: Key) { - if key.name.len() > 1 && key.character.is_none() { - parse_mod_key(&key); - } - - if key.character.is_some() { - key = parse_key(key); - } - - super::tty::handle_key(key); -} - -pub fn prompt() { - super::tty::CONSOLE.puts("> "); -} - -fn parse_key(mut key: Key) -> Key { - let mod_status = MOD_STATUS.get_status(); - - if key.character.is_none() { - panic!("Key passed into parse_key is not a character key!"); - } - - if !mod_status.num_lock && key.name.starts_with("Keypad") { - key = parse_keypad_keys(key); - return key; - } - - if mod_status.ctrl { - key.character = Some(parse_unicode_keys(&key)); - return key; - } - - if key.character.unwrap().is_alphabetic() && (mod_status.shift ^ mod_status.caps) { - key.character = Some(key.character.unwrap().to_ascii_uppercase()); - return key; - } - - if mod_status.shift && !key.name.starts_with("Keypad") { - key.character = Some(capitalize_non_alphabetical(key.character.unwrap())); - return key; - } - - key.character = Some(key.character.unwrap()); - return key; -} - -fn capitalize_non_alphabetical(character: char) -> char { - match character { - '`' => '~', - '1' => '!', - '2' => '@', - '3' => '#', - '4' => '$', - '5' => '%', - '6' => '^', - '7' => '&', - '8' => '*', - '9' => '(', - '0' => ')', - '-' => '_', - '=' => '+', - '[' => '{', - ']' => '}', - '\\' => '|', - ';' => ':', - '\'' => '"', - ',' => '<', - '.' => '>', - '/' => '?', - _ => character, - } -} - -fn parse_mod_key(key: &Key) { - // Held mod keys - if key.name.ends_with("Ctrl") { - MOD_STATUS.set_modifier_key("ctrl", key.pressed); - return; - } - - if key.name.ends_with("Shift") { - MOD_STATUS.set_modifier_key("shift", key.pressed); - return; - } - - if key.name.ends_with("Alt") { - MOD_STATUS.set_modifier_key("alt", key.pressed); - return; - } - - // Toggled mod keys - if !key.pressed { - return; - } - - let mod_status = MOD_STATUS.get_status(); - - if key.name == "CapsLock" { - MOD_STATUS.set_modifier_key("caps", !mod_status.caps); - return; - } - - if key.name == "NumLock" { - MOD_STATUS.set_modifier_key("num_lock", !mod_status.num_lock); - return; - } -} - -fn parse_keypad_keys(mut key: Key) -> Key { - match key.character.unwrap() { - '7' => { - key.name = "Home"; - } - '8' => { - key.name = "CurUp"; - } - '9' => { - key.name = "PgUp"; - } - '4' => { - key.name = "CurLeft"; - } - // 5 has no special function - '6' => { - key.name = "CurRight"; - } - '1' => { - key.name = "End"; - } - '2' => { - key.name = "CurDown"; - } - '3' => { - key.name = "PgDown"; - } - '0' => { - key.name = "Insert"; - } - '.' => { - key.name = "Del"; - } - _ => {} - }; - - key.character = None; - return key; -} - -// bad name -fn parse_unicode_keys(key: &Key) -> char { - assert!(key.character.is_some()); - - match key.character.unwrap() { - 'c' => '\u{0003}', - _ => key.character.unwrap(), - } -} diff --git a/src/usr/tty.rs b/src/usr/tty.rs deleted file mode 100755 index ad1529d..0000000 --- a/src/usr/tty.rs +++ /dev/null @@ -1,901 +0,0 @@ -use core::sync::atomic::{AtomicU16, AtomicU32, AtomicU8, Ordering}; - -use alloc::{ - alloc::{alloc, dealloc}, - format, str, - string::String, - vec::Vec, -}; - -use crate::{ - drivers::{fs::vfs::VFS_INSTANCES, serial::write_serial}, - libs::{elf::load_elf, lazy::Lazy, mutex::Mutex}, - mem::LabelBytes, -}; - -pub struct Cursor { - cx: AtomicU16, - cy: AtomicU16, - fg: AtomicU32, - bg: AtomicU32, -} - -pub struct Console { - columns: AtomicU16, - rows: AtomicU16, - pub cursor: Cursor, - feature_bits: AtomicU8, - pub second_buffer: Mutex>, - // pub lines: Mutex>, -} - -pub struct ConsoleFeatures { - _reserved: [u8; 6], - pub serial_output: bool, - pub graphical_output: bool, - pub doubled_buffered: bool, -} - -impl Console { - #[inline] - const fn new() -> Self { - Self { - columns: AtomicU16::new(0), - rows: AtomicU16::new(0), - cursor: Cursor::new(), - feature_bits: AtomicU8::new(0b00000000), - second_buffer: Mutex::new(None), - // lines: Mutex::new(Vec::new()), - } - } - - #[inline] - pub fn reinit(&self, back_buffer_region: Option<*mut u8>) { - let framebuffer = crate::drivers::video::get_framebuffer(); - - // Enable serial if it initialized correctly - if !crate::drivers::serial::POISONED.load(Ordering::SeqCst) { - self.feature_bits.store( - self.feature_bits.load(Ordering::SeqCst) | 1 << 1, - Ordering::SeqCst, - ); - } - - // Enable graphical output - if framebuffer.is_some() { - self.feature_bits.store( - self.feature_bits.load(Ordering::SeqCst) | 1, - Ordering::SeqCst, - ); - } else { - return; - } - - if back_buffer_region.is_some() { - self.feature_bits.store( - self.feature_bits.load(Ordering::SeqCst) | 1 << 2, - Ordering::SeqCst, - ); - let mut back_buffer = crate::drivers::video::get_framebuffer().unwrap(); - - back_buffer.pointer = back_buffer_region.unwrap(); - - // let row_size = back_buffer.pitch / (back_buffer.bpp / 8); - - // let screen_size = row_size * back_buffer.height; - - // unsafe { - // core::ptr::write_bytes::( - // back_buffer.pointer as *mut u32, - // 0x000000, - // screen_size, - // ); - // } - - (*self.second_buffer.lock().write()) = Some(back_buffer); - } - - let framebuffer = framebuffer.unwrap(); - - let columns = framebuffer.width / 8; - let rows = framebuffer.height / 16; - self.columns.store(columns as u16, Ordering::SeqCst); - self.rows.store(rows as u16, Ordering::SeqCst); - - // let mut lines_lock = self.lines.lock(); - // lines_lock.write().reserve_exact(rows); - // for _ in 0..rows { - // let string = String::with_capacity(columns); - // lines_lock.write().push(string); - // } - } - - pub fn get_features(&self) -> ConsoleFeatures { - let feature_bits = self.feature_bits.load(Ordering::SeqCst); - - let graphical_output = (feature_bits & 0x01) != 0; - let serial_output = (feature_bits & 0x02) != 0; - let doubled_buffered = (feature_bits & 0x04) != 0; - - return ConsoleFeatures { - _reserved: [0; 6], - serial_output, - graphical_output, - doubled_buffered, - }; - } - - // pub fn puts(&self, string: &str) { - // let mut lines = Vec::new(); - - // // let mut text_lock = self.text.lock(); - // // let text = text_lock.write(); - - // let mut col_idx = 0_usize; - // let mut line_string = String::new(); - // for ch in string.chars() { - // if col_idx > self.columns.load(Ordering::SeqCst) as usize - 1 { - // col_idx = 0; - // lines.push(line_string.clone()); - // line_string.clear(); - // } - - // if ch == '\n' { - // col_idx = 0; - // lines.push(line_string.clone()); - // line_string.clear(); - // continue; - // } - - // line_string.push(ch); - // col_idx += 1; - // } - - // let mut new_lines = [self.lines.lock().read().as_slice(), lines.as_slice()].concat(); - // if new_lines.len() > self.rows.load(Ordering::SeqCst) as usize { - // new_lines.reverse(); - // new_lines.resize(self.rows.load(Ordering::SeqCst) as usize - 1, String::new()); - // new_lines.reverse(); - // } - - // (*self.lines.lock().write()) = new_lines; - - // crate::drivers::video::fill_screen(0x000000, *self.second_buffer.lock().read()); - // self.cursor.set_pos(0, 0); - // for line in self.lines.lock().read() { - // self._puts(line); - // self.cursor - // .set_pos(0, self.cursor.cy.load(Ordering::SeqCst) + 1); - // crate::drivers::serial::write_serial('\r'); - // crate::drivers::serial::write_serial('\n') - // } - - // // self._puts(string); - // } - - // Uses a stripped down version of ANSI color codes: - // \033[FG;BGm - pub fn puts(&self, string: &str) { - let mut in_escape_sequence = false; - let mut color_code_buffer = String::new(); - - for character in string.chars() { - if in_escape_sequence { - if character == 'm' { - in_escape_sequence = false; - - let codes: Vec = color_code_buffer - .split(';') - .filter_map(|code| code.parse().ok()) - .collect(); - - for code in codes { - match code { - 0 => { - self.cursor.set_fg(0xbababa); - self.cursor.set_bg(0x000000); - } - 30..=37 => self.cursor.set_fg(color_to_hex(code - 30)), - 40..=47 => self.cursor.set_bg(color_to_hex(code - 40)), - 90..=97 => self.cursor.set_fg(color_to_hex(code - 30)), - 100..=107 => self.cursor.set_bg(color_to_hex(code - 40)), - _ => {} - } - } - - color_code_buffer.clear(); - } else if character.is_ascii_digit() || character == ';' { - color_code_buffer.push(character); - } else { - if character == '[' { - // official start of the color sequence - color_code_buffer.clear(); - continue; - } - - in_escape_sequence = false; - color_code_buffer.clear(); - } - - continue; - } - - if character == '\0' { - in_escape_sequence = true; - continue; - } - - if CONSOLE.get_features().serial_output { - if character == '\n' { - crate::drivers::serial::write_serial('\r'); - } - crate::drivers::serial::write_serial(character); - } - - if !CONSOLE.get_features().graphical_output { - // No graphical output, so to avoid errors, continue after sending serial - continue; - } - - if character == '\u{0008}' { - CONSOLE.cursor.move_left(); - crate::drivers::serial::write_serial(' '); - crate::drivers::serial::write_serial(character); - crate::drivers::video::put_char( - ' ', - self.cursor.cx.load(Ordering::SeqCst), - self.cursor.cy.load(Ordering::SeqCst), - self.cursor.fg.load(Ordering::SeqCst), - self.cursor.bg.load(Ordering::SeqCst), - *self.second_buffer.lock().read(), - ); - - continue; - } - - if character == '\r' { - self.cursor - .set_pos(0, self.cursor.cy.load(Ordering::SeqCst)); - continue; - } - - if character == '\n' { - if (self.cursor.cy.load(Ordering::SeqCst) + 1) >= self.rows.load(Ordering::SeqCst) { - self.scroll_console(); - - self.cursor - .set_pos(0, self.cursor.cy.load(Ordering::SeqCst)); - } else { - self.cursor - .set_pos(0, self.cursor.cy.load(Ordering::SeqCst) + 1); - } - } else { - crate::drivers::video::put_char( - character, - self.cursor.cx.load(Ordering::SeqCst), - self.cursor.cy.load(Ordering::SeqCst), - self.cursor.fg.load(Ordering::SeqCst), - self.cursor.bg.load(Ordering::SeqCst), - *self.second_buffer.lock().read(), - ); - - self.cursor.move_right(); - } - } - - self.cursor.set_color(0xbababa, 0x000000); - } - - // pub fn reblit(&self) { - // self.cursor.set_pos(0, 0); - // self.reblit.store(true, Ordering::SeqCst); - - // self.puts(&self.text.lock().read().trim_end_matches('\n')); - - // self.reblit.store(false, Ordering::SeqCst); - // } - - pub fn scroll_console(&self) { - let framebuffer_attributes = crate::drivers::video::get_framebuffer() - .expect("Tried to scroll console but we have no framebuffer."); - - let lines_to_skip = 16; - - let framebuffer = framebuffer_attributes.pointer as *mut u32; - - let row_size = framebuffer_attributes.pitch / (framebuffer_attributes.bpp / 8); - - let screen_size = row_size * framebuffer_attributes.height; - - let skip = lines_to_skip * row_size; - - if self.get_features().doubled_buffered { - let second_buffer = self.second_buffer.lock().read().unwrap().pointer as *mut u32; - - unsafe { - core::ptr::copy_nonoverlapping( - second_buffer.add(skip), - second_buffer, - screen_size - skip, - ); - - crate::libs::util::memset32(second_buffer.add(screen_size - skip), 0x000000, skip); - - core::ptr::copy_nonoverlapping(second_buffer, framebuffer, screen_size); - } - } else { - unsafe { - core::ptr::copy_nonoverlapping( - framebuffer.add(skip), - framebuffer, - screen_size - skip, - ); - - crate::libs::util::memset32(framebuffer.add(screen_size - skip), 0x000000, skip); - } - } - } - - pub fn clear_screen(&self) { - self.cursor.set_pos(0, 0); - - crate::drivers::video::fill_screen( - self.cursor.bg.load(Ordering::SeqCst), - *self.second_buffer.lock().read(), - ); - } -} - -// pub static CONSOLE: Console = Console::new(); -pub static CONSOLE: Lazy = Lazy::new(|| { - let console = Console::new(); - - let mut framebuffer_region = None; - - for entry in crate::mem::MEMMAP.lock().read().iter() { - if entry.typ == limine::MemoryMapEntryType::Framebuffer { - framebuffer_region = Some(entry); - } - } - - let mut back_buffer_region = None; - - if let Some(framebuffer_region) = framebuffer_region { - back_buffer_region = crate::mem::PHYSICAL_MEMORY_MANAGER - .alloc(framebuffer_region.len as usize / crate::mem::pmm::PAGE_SIZE) - .ok(); - } - - console.reinit(back_buffer_region); - - return console; -}); - -impl Cursor { - #[inline] - const fn new() -> Self { - return Self { - cx: AtomicU16::new(0), - cy: AtomicU16::new(0), - fg: AtomicU32::new(0xbababa), - bg: AtomicU32::new(0x000000), - }; - } - - pub fn set_pos(&self, new_cx: u16, new_cy: u16) { - self.cx.store(new_cx, Ordering::SeqCst); - self.cy.store(new_cy, Ordering::SeqCst); - } - - fn move_right(&self) { - let framebuffer_response = crate::drivers::video::FRAMEBUFFER_REQUEST - .get_response() - .get(); - - if framebuffer_response.is_none() { - return; - } - - // eww, variable redeclaration - let framebuffer_response = framebuffer_response.unwrap(); - let framebuffer = &framebuffer_response.framebuffers()[0]; - - if self.cx.load(Ordering::SeqCst) == (framebuffer.width / 8) as u16 - 1 { - if self.cy.load(Ordering::SeqCst) == (framebuffer.height / 16) as u16 - 1 { - CONSOLE.scroll_console(); - - self.cy - .store(((framebuffer.height / 16) - 1) as u16, Ordering::SeqCst); - self.cx.store(0, Ordering::SeqCst); - } else { - self.cy.fetch_add(1, Ordering::SeqCst); - self.cx.store(0, Ordering::SeqCst); - } - } else { - self.cx.fetch_add(1, Ordering::SeqCst); - } - } - - fn move_left(&self) { - let framebuffer_response = crate::drivers::video::FRAMEBUFFER_REQUEST - .get_response() - .get(); - - if framebuffer_response.is_none() { - return; - } - - // eww, variable redeclaration - let framebuffer_response = framebuffer_response.unwrap(); - let framebuffer = &framebuffer_response.framebuffers()[0]; - - if self.cx.load(Ordering::SeqCst) == 0 { - self.cx - .store((framebuffer.width / 8) as u16 - 1, Ordering::SeqCst); - self.cy.fetch_sub(1, Ordering::SeqCst); - } else { - self.cx.fetch_sub(1, Ordering::SeqCst); - } - } - - pub fn set_fg(&self, new_fg: u32) { - self.fg.store(new_fg, Ordering::SeqCst); - } - - pub fn set_bg(&self, new_bg: u32) { - self.bg.store(new_bg, Ordering::SeqCst); - } - - pub fn set_color(&self, new_fg: u32, new_bg: u32) { - self.fg.store(new_fg, Ordering::SeqCst); - self.bg.store(new_bg, Ordering::SeqCst); - } -} - -fn color_to_hex(color: u8) -> u32 { - match color { - 0 => 0x000000, - 1 => 0xCD0000, - 2 => 0x00CD00, - 3 => 0xCDCD00, - 4 => 0x0000EE, - 5 => 0xCD00CD, - 6 => 0x00CDCD, - 7 => 0xBABABA, - 60 => 0x555555, - 61 => 0xFF0000, - 62 => 0x00FF00, - 63 => 0xFFFF00, - 64 => 0x5C5CFF, - 65 => 0xFF00FF, - 66 => 0x00FFFF, - 67 => 0xFFFFFF, - _ => 0x000000, - } -} - -#[macro_export] -macro_rules! println { - () => ($crate::print!("\n")); - ($($arg:tt)*) => ($crate::print!("{}\n", &alloc::format!($($arg)*))); -} - -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ( - $crate::usr::tty::CONSOLE.puts(&alloc::format!($($arg)*)) - ) -} - -pub struct InputBuffer { - pub buffer: Vec, -} - -impl InputBuffer { - pub fn clear(&mut self) { - self.buffer.clear(); - } - - pub fn push(&mut self, value: u8) { - self.buffer.push(value); - } - - pub fn pop(&mut self) { - if !self.buffer.is_empty() { - self.buffer.pop(); - } - } - - pub fn as_str(&self) -> &str { - // Convert the buffer to a string slice for convenience - str::from_utf8(&self.buffer).unwrap_or("") - } -} - -static INPUT_BUFFER: Mutex = Mutex::new(InputBuffer { buffer: Vec::new() }); - -pub fn handle_key(key: crate::drivers::keyboard::Key) { - let input_buffer = INPUT_BUFFER.lock().write(); - - if !key.pressed { - return; - } - - if key.character == Some('\n') { - CONSOLE.puts("\r\n"); - exec(input_buffer.as_str()); - input_buffer.clear(); - super::shell::prompt(); - return; - } - - if key.name.starts_with("Cur") { - if key.name.ends_with("Up") || key.name.ends_with("Down") { - return; - } - - if key.name.ends_with("Left") { - CONSOLE.cursor.move_left(); - return; - } else { - CONSOLE.cursor.move_right(); - return; - } - } - - if key.character.is_none() { - return; - } - - if key.character.unwrap() == '\u{0003}' { - CONSOLE.puts("^C\r\n"); - input_buffer.clear(); - super::shell::prompt(); - return; - } - - if key.character.unwrap() == '\u{0008}' { - if input_buffer.buffer.is_empty() { - return; - } - - input_buffer.pop(); - CONSOLE.puts("\u{0008}"); - return; - } - - let character = key.character.unwrap(); - input_buffer.push(character as u8); - - CONSOLE.puts(&format!("{}", key.character.unwrap())); -} - -pub fn exec(command: &str) { - let (command, args) = parse_input(command.trim()); - - if command.is_empty() { - return; - } - - if command == "memstat" { - let allocator = &crate::mem::ALLOCATOR; - - let used_mem = allocator.inner.get_used_mem().label_bytes(); - let free_mem = allocator.inner.get_free_mem().label_bytes(); - let total_mem = allocator.inner.get_total_mem().label_bytes(); - - println!( - "Allocated so far: {used_mem}\nFree memory: {free_mem}\nTotal Memory: {total_mem}", - ); - return; - } - - if command == "memalloc" { - if args.is_empty() { - println!("Allocation size is required. See --help for detailed instructions."); - return; - } - - if args[0].as_str() == "--help" || args[0].as_str() == "-h" { - // print help menu - println!("memalloc ALLOCATION_SIZE [OPTIONS]\n-d alias: --dealloc; Deallocates memory at the specified location with specified size."); - return; - } - - if args.len() == 1 { - // allocate - let size: Result = args[0].as_str().parse(); - - if size.is_err() { - println!( - "Provided argument is not a number. See --help for detailed instructions." - ); - return; - } - - let layout = core::alloc::Layout::from_size_align(size.unwrap(), 16).unwrap(); - - let mem = unsafe { alloc(layout) as *mut u16 }; - unsafe { *(mem) = 42 }; - println!("{mem:p} val: {}", unsafe { *(mem) }); - } else { - // deallocate - if args.len() < 3 { - println!("Malformed input. See --help for detailed instructions."); - return; - } - - let mut memory_address = 0; - let mut size = 0; - - for arg in args { - if arg.starts_with('-') { - continue; - } - - if arg.starts_with("0x") { - memory_address = parse_memory_address(arg.as_str()).unwrap(); - continue; - } - - let num_arg = arg.parse::(); - - if num_arg.is_err() { - println!( - "Provided argument is not a number. See --help for detailed instructions." - ); - return; - } - - size = num_arg.unwrap(); - } - - let layout = core::alloc::Layout::from_size_align(size, 16).unwrap(); - - let ptr = memory_address as *mut u8; - - unsafe { - dealloc(ptr, layout); - - println!("Deallocated memory at address: {:?}", ptr); - } - } - return; - } - - if command == "memtest" { - if args.is_empty() { - println!("Memory address to test is required."); - return; - } - - let arg = args[0].as_str(); - - if let Some(addr) = parse_memory_address(arg) { - let ptr: *const u32 = addr as *const u32; - - unsafe { - let val = *ptr; - - println!("Value at memory address: {val}"); - } - } else { - println!("Argument provided is not a memory address."); - } - - return; - } - - if command == "memfill" { - let allocator = &crate::mem::ALLOCATOR; - let free_mem = allocator.inner.get_free_mem(); - - unsafe { - let layout = core::alloc::Layout::from_size_align(free_mem, 16).unwrap(); - let ptr = alloc(layout); - dealloc(ptr, layout); - } - println!("Filled allocator with {free_mem} bytes"); - - return; - } - - if command == "echo" { - let mut input = ""; - - if !args.is_empty() { - input = args[0].as_str(); - } - - CONSOLE.puts(input); - CONSOLE.puts("\n"); - return; - } - - if command == "poke" { - if args.len() < 2 { - println!("poke: usage error: memory address & value required!"); - return; - } - - if let Some(addr) = parse_memory_address(args[0].as_str()) { - let value: Result = args[1].as_str().parse(); - - if value.is_err() { - println!("Second argument provided is not a number."); - } - - let ptr: *mut u32 = addr as *mut u32; - - unsafe { - *ptr = value.unwrap(); - - println!("Allocated {:?} at {:#x}", *ptr, addr); - } - } else { - println!("First argument provided is not a memory address."); - } - } - - if command == "clear" { - CONSOLE.clear_screen(); - return; - } - - if command == "read" { - if args.is_empty() { - println!("read: usage error: at least one argument is required!"); - return; - } - - let vfs_lock = crate::drivers::fs::vfs::VFS_INSTANCES.lock(); - - let file = vfs_lock.read()[0].open(&args[0]); - - if file.is_err() { - println!("read: Unable to read file!"); - return; - } - - println!("{:X?}", file.unwrap().read()); - - return; - } - - if command == "test" { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - let message = "Hello from syscall!\n"; - unsafe { - core::arch::asm!( - "mov rdi, 0x01", // write syscall - "mov rsi, 0x01", // stdio (but it doesnt matter) - "mov rdx, {0:r}", // pointer - "mov rcx, {1:r}", // count - "int 0x80", - in(reg) message.as_ptr(), - in(reg) message.len() - ); - } - } - - return; - } - - // TODO: check a path and not just /bin/ - if let Ok(program) = VFS_INSTANCES.lock().read()[0].open(&format!("/bin/{}", command)) { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - let program_bytes = program.read().expect("Failed to read program!"); - let program_elf = match load_elf(&program_bytes) { - Ok(elf) => elf, - Err(_) => { - println!("Command not found: {command} (err)"); - return; - } - }; - crate::arch::push_gprs(); - - // execute program - crate::println!("{program_elf:?}"); - - crate::arch::pop_gprs(); - } - } else { - println!("Command not found: {command}"); - } -} - -fn parse_input(input: &str) -> (String, Vec) { - let mut command = String::new(); - let mut args: Vec = Vec::new(); - let mut iter = input.trim().chars().peekable(); - - let mut i: usize = 0; - while let Some(char) = iter.next() { - let mut arg = String::new(); - - match char { - ' ' => continue, - '"' | '\'' => { - let mut escape_char = '"'; - if char == '\'' { - escape_char = '\''; - } - - while let Some(ch) = iter.next() { - match ch { - '\\' => { - if let Some(next_char) = iter.next() { - arg.push(parse_escaped_char(next_char)); - } - } - '"' | '\'' => { - if ch == escape_char { - break; - } - - arg.push(ch); - } - _ => arg.push(ch), - } - } - - if i == 0 { - command = arg; - } else { - args.push(arg); - } - } - _ => { - if char == '\\' { - if let Some(ch) = iter.next() { - arg.push(parse_escaped_char(ch)); - } - } else { - arg.push(char); - } - - while let Some(ch) = iter.peek() { - match ch { - &' ' | &'"' | &'\'' => break, - &'\\' => { - iter.next(); - if let Some(next_char) = iter.next() { - arg.push(parse_escaped_char(next_char)); - } - } - _ => arg.push(iter.next().unwrap()), - } - } - - if i == 0 { - command = arg; - } else { - args.push(arg); - } - } - } - i += 1; - } - - return (command, args); -} - -fn parse_escaped_char(next_char: char) -> char { - let escaped = match next_char { - 'n' => '\n', - 't' => '\t', - '0' => '\0', - _ => next_char, // You can add more escape sequences if needed - }; - return escaped; -} - -fn parse_memory_address(input: &str) -> Option { - if let Some(stripped) = input.strip_prefix("0x") { - return u64::from_str_radix(stripped, 16).ok(); - } else { - return None; - } -}