add proper vfs

This commit is contained in:
Zoe
2024-03-03 17:57:41 -06:00
parent 00037311c6
commit 3a39441717
44 changed files with 1648 additions and 3097 deletions

View File

@@ -12,6 +12,7 @@ GDB ?=
CPUS ?= 1 CPUS ?= 1
# FAT type # FAT type
ESP_BITS ?= 32 ESP_BITS ?= 32
EXPORT_SYMBOLS = true
ISO_PATH = ${ARTIFACTS_PATH}/iso_root ISO_PATH = ${ARTIFACTS_PATH}/iso_root
INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs
@@ -84,6 +85,7 @@ compile-initramfs: copy-initramfs-files
mksquashfs ${INITRAMFS_PATH} ${ARTIFACTS_PATH}/initramfs.img ${MKSQUASHFS_OPTS} mksquashfs ${INITRAMFS_PATH} ${ARTIFACTS_PATH}/initramfs.img ${MKSQUASHFS_OPTS}
run-scripts: run-scripts:
ifeq (${EXPORT_SYMBOLS},true)
nm target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf > scripts/symbols.table nm target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf > scripts/symbols.table
@if [ ! -d "scripts/rustc_demangle" ]; then \ @if [ ! -d "scripts/rustc_demangle" ]; then \
echo "Cloning rustc_demangle.py into scripts/rustc_demangle/..."; \ echo "Cloning rustc_demangle.py into scripts/rustc_demangle/..."; \
@@ -93,6 +95,7 @@ run-scripts:
fi fi
python scripts/demangle-symbols.py python scripts/demangle-symbols.py
mv scripts/symbols.table ${INITRAMFS_PATH}/ mv scripts/symbols.table ${INITRAMFS_PATH}/
endif
python scripts/font.py python scripts/font.py
mv scripts/font.psf ${INITRAMFS_PATH}/ mv scripts/font.psf ${INITRAMFS_PATH}/

View File

@@ -104,7 +104,8 @@ sudo dd if=bin/CappuccinOS.iso of=/dev/sdX bs=1M && sync
## Supported Architectures ## Supported Architectures
- x86_64 - 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 ## 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). 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).

View File

@@ -28,6 +28,16 @@ pub unsafe fn insw(port: u16, buffer: *mut u16, count: usize) {
return; 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`. /// Outputs `count` 16-bit values from the specified `port` into the `buffer`.
/// ///
/// # Safety /// # Safety

View File

@@ -1,23 +1,17 @@
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub use self::x86_64::*; pub use x86_64::*;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use self::x86_common::*;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
mod x86_64; mod x86_64;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod x86_common;
#[cfg(target_arch = "riscv64")] #[cfg(target_arch = "riscv64")]
mod riscv64; mod riscv64;
#[cfg(target_arch = "riscv64")] #[cfg(target_arch = "riscv64")]
pub use self::riscv64::*; pub use riscv64::*;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
mod aarch64; mod aarch64;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub use self::aarch64::*; pub use aarch64::*;

View File

@@ -28,6 +28,16 @@ pub unsafe fn insw(port: u16, buffer: *mut u16, count: usize) {
return; 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`. /// Outputs `count` 16-bit values from the specified `port` into the `buffer`.
/// ///
/// # Safety /// # Safety

View File

@@ -1,5 +1,5 @@
use super::idt_set_gate; use super::idt_set_gate;
use crate::libs::util::hcf; use crate::hcf;
use crate::{log_error, log_info}; use crate::{log_error, log_info};
#[repr(C)] #[repr(C)]
@@ -77,40 +77,35 @@ extern "C" fn exception_handler(registers: u64) {
// *macro intensifies* // *macro intensifies*
macro_rules! exception_function { macro_rules! exception_function {
($code:expr, $handler:ident, $recoverable:literal) => { ($code:expr, $handler:ident) => {
#[inline(always)] #[inline(always)]
extern "C" fn $handler() { extern "C" fn $handler() {
crate::arch::push_gprs();
unsafe { unsafe {
core::arch::asm!( core::arch::asm!(
"pushfq",
"push {0:r}", "push {0:r}",
"mov rdi, rsp", "mov rdi, rsp",
"call {1}", "call {1}",
"pop {0:r}", "pop {0:r}",
"mov rsp, rdi", "mov rsp, rdi",
"popfq",
in(reg) $code, in(reg) $code,
sym exception_handler, sym exception_handler,
); );
}; };
if $recoverable {
crate::println!("TODO: Recover gracefully ;~;");
hcf(); hcf();
} else {
hcf();
}
} }
}; };
} }
exception_function!(0x00, div_error, true); exception_function!(0x00, div_error);
exception_function!(0x06, invalid_opcode, true); exception_function!(0x06, invalid_opcode);
exception_function!(0x08, double_fault, false); exception_function!(0x08, double_fault);
exception_function!(0x0D, general_protection_fault, true); exception_function!(0x0D, general_protection_fault);
// TODO: fix the page fault then gracefully return. // TODO: fix the page fault then gracefully return.
exception_function!(0x0E, page_fault, false); exception_function!(0x0E, page_fault);
exception_function!(0xFF, generic_handler, true); exception_function!(0xFF, generic_handler);
pub fn set_exceptions() { pub fn set_exceptions() {
for i in 0..32 { for i in 0..32 {

View File

@@ -1,8 +1,9 @@
pub mod apic;
mod exceptions; mod exceptions;
use crate::{ use crate::{
arch::{apic, x86_common::pic::ChainedPics}, // arch::{apic, x86_common::pic::ChainedPics},
libs::mutex::Mutex, libs::sync::Mutex,
}; };
#[repr(C, packed)] #[repr(C, packed)]
@@ -42,7 +43,7 @@ static IDT: Mutex<[IdtEntry; 256]> = Mutex::new([IdtEntry::new(); 256]);
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(u8)] #[repr(u8)]
pub enum InterruptIndex { pub enum InterruptIndex {
Timer = PIC_1_OFFSET, Timer = 32,
Keyboard, 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<ChainedPics> = Mutex::new(ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET));
static mut IDT_PTR: IdtPtr = IdtPtr { static mut IDT_PTR: IdtPtr = IdtPtr {
limit: (core::mem::size_of::<IdtEntry>() * 256) as u16 - 1, limit: (core::mem::size_of::<IdtEntry>() * 256) as u16 - 1,
base: 0, base: 0,
@@ -64,7 +60,7 @@ static mut IDT_PTR: IdtPtr = IdtPtr {
pub fn idt_set_gate(num: u8, function_ptr: usize) { pub fn idt_set_gate(num: u8, function_ptr: usize) {
let base = function_ptr; let base = function_ptr;
IDT.lock().write()[num as usize] = IdtEntry { IDT.lock()[num as usize] = IdtEntry {
base_lo: (base & 0xFFFF) as u16, base_lo: (base & 0xFFFF) as u16,
base_mid: ((base >> 16) & 0xFFFF) as u16, base_mid: ((base >> 16) & 0xFFFF) as u16,
base_hi: ((base >> 32) & 0xFFFFFFFF) as u32, 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 // 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 // We will need to tell the PIC that interrupt is over, this stops new interrupts
// From never firing because "it was never finished" // 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() { extern "x86-interrupt" fn null_interrupt_handler() {
crate::log_info!("Unhandled interrupt!"); crate::log_info!("Unhandled interrupt!");
if apic::APIC.lock().read().is_some() { signal_end_of_interrupt();
apic::APIC
.lock()
.read()
.as_ref()
.unwrap()
.end_of_interrupt();
}
} }
extern "x86-interrupt" fn timer_handler() { extern "x86-interrupt" fn timer_handler() {
// crate::usr::tty::puts("."); // crate::usr::tty::puts(".");
signal_end_of_interrupt(InterruptIndex::Timer.as_u8()); signal_end_of_interrupt();
} }
fn idt_init() { fn idt_init() {
unsafe { unsafe {
let idt_size = core::mem::size_of::<IdtEntry>() * 256; let idt_size = core::mem::size_of::<IdtEntry>() * 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( core::ptr::write_bytes(idt_lock.as_mut_ptr() as *mut core::ffi::c_void, 0, idt_size);
IDT.lock().write().as_mut_ptr() as *mut core::ffi::c_void, }
0,
idt_size,
);
// Set every interrupt to the "null" interrupt handler (it does nothing) // Set every interrupt to the "null" interrupt handler (it does nothing)
for num in 0..=255 { for num in 0..=255 {
@@ -120,22 +108,13 @@ fn idt_init() {
core::arch::asm!( core::arch::asm!(
"lidt [{}]", "lidt [{}]",
in(reg) &IDT_PTR in(reg) core::ptr::addr_of!(IDT_PTR)
); );
} }
} }
pub fn signal_end_of_interrupt(int: u8) { pub fn signal_end_of_interrupt() {
if apic::APIC.lock().read().is_some() { apic::APIC.end_of_interrupt();
apic::APIC
.lock()
.read()
.as_ref()
.unwrap()
.end_of_interrupt();
} else {
PICS.lock().write().notify_end_of_interrupt(int);
}
} }
#[naked] #[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 buf = rdx as *const u8; // Treat as pointer to u8 (byte array)
let count = rcx as usize; 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() { pub fn init() {
crate::drivers::acpi::init_acpi();
idt_init(); idt_init();
PICS.lock().write().initialize();
unsafe { unsafe {
core::arch::asm!("sti"); core::arch::asm!("sti");
} }

View File

@@ -1,24 +1,35 @@
pub mod interrupts; 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)] #[inline(always)]
pub fn push_gprs() { pub fn pause() {
unsafe { unsafe {
core::arch::asm!( core::arch::asm!("pause");
"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"
);
}
} }
// This inline is detremental to having readable stack traces #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)] #[inline(always)]
pub fn pop_gprs() { pub fn cpu_has_msr() -> bool {
unsafe { return unsafe { core::arch::x86_64::__cpuid_count(1, 0).edx } & 1 << 5 != 0;
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 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,
);
} }

View File

@@ -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::<u8>()
}
}
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<Self, ()> {
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::<MADT>("APIC");
if madt.is_none() {
return Err(());
}
let mut cpus: Vec<LAPIC> = 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::<LAPIC>() });
}
}
1 => unsafe {
io_apic = Some(IOAPIC {
ioapic_id: *ptr.add(2),
_reserved: *ptr.add(3),
ptr: (*ptr.add(4).cast::<u32>()) as *mut u8,
global_interrupt_base: *ptr.add(8).cast::<u32>(),
})
},
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::<u32>(),
flags: *ptr.add(8).cast::<u16>(),
})
},
5 => lapic_ptr = unsafe { *(ptr.add(4).cast::<u64>()) } 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::<u32>(), reg & 0xff);
return core::ptr::read_volatile(self.io_apic.ptr.cast::<u32>().add(4));
}
}
pub fn write_ioapic(&self, reg: u32, value: u32) {
unsafe {
core::ptr::write_volatile(self.io_apic.ptr.cast::<u32>(), reg & 0xff);
core::ptr::write_volatile(self.io_apic.ptr.cast::<u32>().add(4), value);
}
}
pub fn read_lapic(&self, reg: u32) -> u32 {
unsafe {
return *self.local_apic.add(reg as usize).cast::<u32>();
}
}
pub fn write_lapic(&self, reg: u32, value: u32) {
unsafe {
*self.local_apic.add(reg as usize).cast::<u32>() = value;
}
}
pub fn end_of_interrupt(&self) {
self.write_lapic(0xB0, 0x00);
}
}
pub static APIC: Mutex<Option<APIC>> = Mutex::new(None);

View File

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

View File

@@ -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,
);
}

View File

@@ -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();
}
}

View File

@@ -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!();
}

View File

@@ -1,12 +1,31 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
// use alloc::format; // extern crate alloc;
// // piggyback off of the CappuccinOS allocator // use core::alloc::GlobalAlloc;
// // TODO: make a malloc lib for memory operations
// #[allow(unused_imports)] // use alloc::{borrow::ToOwned, format, string::String};
// use CappuccinOS;
// 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] #[no_mangle]
pub fn _start(_args: &[&str]) { pub fn _start(_args: &[&str]) {

View File

@@ -1,10 +1,13 @@
use alloc::vec::Vec; use alloc::vec::Vec;
use limine::SmpRequest;
use crate::{ use crate::{
arch::io::{inw, outb}, arch::io::{inw, outb},
libs::oncecell::OnceCell, libs::cell::OnceCell,
}; };
pub static SMP_REQUEST: SmpRequest = SmpRequest::new(0);
#[repr(C, packed)] #[repr(C, packed)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct SDTHeader { pub struct SDTHeader {
@@ -32,12 +35,14 @@ impl<'a, T> SDT<'a, T> {
let length = core::ptr::read_unaligned(ptr.add(4).cast::<u32>()); let length = core::ptr::read_unaligned(ptr.add(4).cast::<u32>());
let data = core::slice::from_raw_parts(ptr, length as usize); 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); assert!(data.len() == length as usize);
let header: &SDTHeader = core::mem::transmute(data[0..].as_ptr()); let header: &SDTHeader = &*data[0..].as_ptr().cast::<SDTHeader>();
let inner: &T = core::mem::transmute(data[core::mem::size_of::<SDTHeader>()..].as_ptr()); let inner: &T = &*data[core::mem::size_of::<SDTHeader>()..]
.as_ptr()
.cast::<T>();
let mut extra = None; let mut extra = None;
if length as usize > core::mem::size_of::<SDTHeader>() + core::mem::size_of::<T>() { if length as usize > core::mem::size_of::<SDTHeader>() + core::mem::size_of::<T>() {
@@ -94,15 +99,15 @@ enum RootSDT<'a> {
impl<'a> RootSDT<'a> { impl<'a> RootSDT<'a> {
fn header(&self) -> SDTHeader { fn header(&self) -> SDTHeader {
return match self { return match self {
RootSDT::RSDT(RSDT) => *RSDT.header, RootSDT::RSDT(rsdt) => *rsdt.header,
RootSDT::XSDT(XSDT) => *XSDT.header, RootSDT::XSDT(xsdt) => *xsdt.header,
}; };
} }
fn len(&self) -> usize { fn len(&self) -> usize {
let ptr_size = match self { let ptr_size = match self {
&RootSDT::RSDT(_) => 4, RootSDT::RSDT(_) => 4,
&RootSDT::XSDT(_) => 8, RootSDT::XSDT(_) => 8,
}; };
return (self.header().length as usize - core::mem::size_of::<SDTHeader>()) / ptr_size; return (self.header().length as usize - core::mem::size_of::<SDTHeader>()) / ptr_size;
@@ -112,20 +117,20 @@ impl<'a> RootSDT<'a> {
let mut offset = 0; let mut offset = 0;
let root_ptr = match self { let root_ptr = match self {
RootSDT::RSDT(RSDT) => { RootSDT::RSDT(rsdt) => {
let ptrs = RSDT.inner.pointers as *const u8; let ptrs = rsdt.inner.pointers as *const u8;
assert!(!ptrs.is_null()); assert!(!ptrs.is_null());
ptrs.add(offset) ptrs.add(offset)
} }
RootSDT::XSDT(XSDT) => { RootSDT::XSDT(xsdt) => {
let ptrs = XSDT.inner.pointers as *const u8; let ptrs = xsdt.inner.pointers as *const u8;
assert!(!ptrs.is_null()); assert!(!ptrs.is_null());
ptrs.add(offset) ptrs.add(offset)
} }
}; };
for _ in 0..idx { for _ in 0..idx {
let header: &SDTHeader = core::mem::transmute(root_ptr.add(offset).cast::<SDTHeader>()); let header: &SDTHeader = &*root_ptr.add(offset).cast::<SDTHeader>();
offset += header.length as usize; offset += header.length as usize;
} }
@@ -165,8 +170,7 @@ fn resolve_acpi() {
.map(|i| { .map(|i| {
let sdt_ptr = unsafe { root_sdt.get(i) }; let sdt_ptr = unsafe { root_sdt.get(i) };
let signature = unsafe { core::slice::from_raw_parts(sdt_ptr, 4) }; let signature = unsafe { core::slice::from_raw_parts(sdt_ptr, 4) };
let ret = signature.try_into().unwrap(); signature.try_into().unwrap()
ret
}) })
.collect(); .collect();
@@ -254,9 +258,9 @@ pub fn init_acpi() {
crate::log_ok!("Found {} ACPI Tables!", ACPI.tables.len()); 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() { 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::<FADT>("FACP").expect("Failed to find FADT"); let fadt = find_table::<FADT>("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 {} while inw(fadt.inner.pm1a_control_block as u16) & 1 == 0 {}
crate::arch::interrupts::PICS.lock().write().disable(); #[cfg(target_arch = "x86_64")]
crate::arch::interrupts::apic::APIC
*crate::arch::apic::APIC.lock().write() = .set(crate::arch::interrupts::apic::APIC::new().expect("Failed to enable APIC!"));
Some(crate::arch::apic::APIC::new().expect("Failed to enable APIC!"));
crate::log_ok!("APIC enabled!"); crate::log_ok!("APIC enabled!");
} }

View File

@@ -5,9 +5,9 @@ use alloc::{
vec::Vec, 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 first Cluster (perhaps 0xF0FFFF0F) is the FAT ID
// The second cluster stores the end-of-cluster-chain marker // The second cluster stores the end-of-cluster-chain marker
@@ -97,6 +97,8 @@ pub struct FSInfo {
impl FSInfo { impl FSInfo {
pub fn from_bytes(bytes: Arc<[u8]>) -> Self { 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 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 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()); let last_known_free_cluster = u32::from_le_bytes(bytes[488..492].try_into().unwrap());
@@ -117,6 +119,7 @@ impl FSInfo {
#[repr(u8)] #[repr(u8)]
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
#[allow(dead_code)]
enum FileEntryAttributes { enum FileEntryAttributes {
ReadOnly = 0x01, ReadOnly = 0x01,
Hidden = 0x02, Hidden = 0x02,
@@ -127,7 +130,7 @@ enum FileEntryAttributes {
LongFileName = 0x0F, LongFileName = 0x0F,
} }
#[repr(packed)] #[repr(C, packed)]
#[derive(Debug)] #[derive(Debug)]
struct LongFileName { struct LongFileName {
entry_order: u8, entry_order: u8,
@@ -140,7 +143,7 @@ struct LongFileName {
final_characters: [u16; 2], final_characters: [u16; 2],
} }
#[repr(packed)] #[repr(C, packed)]
#[derive(Debug)] #[derive(Debug)]
pub struct FileEntry { pub struct FileEntry {
file_name: [u8; 8], file_name: [u8; 8],
@@ -158,11 +161,18 @@ pub struct FileEntry {
file_size: u32, file_size: u32,
} }
pub struct FatFs<'a> { impl FileEntry {
// Block device Info pub fn cluster(&self) -> u32 {
drive: &'a dyn BlockDevice, let mut cluster = self.low_first_cluster_number as u32;
partition: GPTPartitionEntry, cluster |= (self.high_first_cluster_number as u32) << 16;
return cluster;
}
}
pub struct FatFs {
partition: Partition,
// FAT info // FAT info
#[allow(dead_code)]
fs_info: Option<FSInfo>, fs_info: Option<FSInfo>,
fat: Option<Arc<[u32]>>, fat: Option<Arc<[u32]>>,
bpb: BIOSParameterBlock, bpb: BIOSParameterBlock,
@@ -172,10 +182,10 @@ pub struct FatFs<'a> {
sectors_per_fat: usize, sectors_per_fat: usize,
} }
impl<'a> FatFs<'a> { impl FatFs {
pub fn new(drive: &'a dyn BlockDevice, partition: GPTPartitionEntry) -> Result<Self, ()> { pub fn new(partition: Partition) -> Result<Self, ()> {
let bpb_bytes = drive let bpb_bytes = partition
.read(partition.start_sector, 1) .read(0, 1)
.expect("Failed to read FAT32 BIOS Parameter Block!"); .expect("Failed to read FAT32 BIOS Parameter Block!");
let bpb = unsafe { *(bpb_bytes.as_ptr().cast::<BIOSParameterBlock>()) }; let bpb = unsafe { *(bpb_bytes.as_ptr().cast::<BIOSParameterBlock>()) };
@@ -239,8 +249,8 @@ impl<'a> FatFs<'a> {
let fs_info = match fat_type { let fs_info = match fat_type {
FatType::Fat32(ebpb) => { FatType::Fat32(ebpb) => {
let fsinfo_bytes = drive let fsinfo_bytes = partition
.read(partition.start_sector + ebpb.fsinfo_sector as u64, 1) .read(ebpb.fsinfo_sector as u64, 1)
.expect("Failed to read FSInfo sector!"); .expect("Failed to read FSInfo sector!");
Some(FSInfo::from_bytes(fsinfo_bytes)) Some(FSInfo::from_bytes(fsinfo_bytes))
@@ -248,7 +258,7 @@ impl<'a> FatFs<'a> {
_ => None, _ => 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 { let sectors_per_fat = match fat_type {
FatType::Fat32(ebpb) => ebpb.sectors_per_fat_ext as usize, FatType::Fat32(ebpb) => ebpb.sectors_per_fat_ext as usize,
@@ -268,7 +278,7 @@ impl<'a> FatFs<'a> {
let mut fat_vec: Vec<u32> = Vec::with_capacity(bytes_per_fat / cluster_bytes); let mut fat_vec: Vec<u32> = Vec::with_capacity(bytes_per_fat / cluster_bytes);
for i in 0..sectors_per_fat { for i in 0..sectors_per_fat {
let sector = drive let sector = partition
.read(fat_start + i as u64, 1) .read(fat_start + i as u64, 1)
.expect("Failed to read FAT"); .expect("Failed to read FAT");
for j in 0..(512 / cluster_bytes) { for j in 0..(512 / cluster_bytes) {
@@ -290,7 +300,7 @@ impl<'a> FatFs<'a> {
fat = Some(Arc::from(fat_vec)); fat = Some(Arc::from(fat_vec));
} else { } else {
crate::log_info!( 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; let cluster_size = bpb.sectors_per_cluster as usize * 512;
return Ok(Self { return Ok(Self {
drive,
partition, partition,
fs_info, fs_info,
fat, fat,
@@ -416,8 +425,8 @@ impl<'a> FatFs<'a> {
} }
pub fn read_cluster(&self, cluster: usize) -> Result<Arc<[u8]>, ()> { pub fn read_cluster(&self, cluster: usize) -> Result<Arc<[u8]>, ()> {
return self.drive.read( return self.partition.read(
self.partition.start_sector + self.cluster_to_sector(cluster) as u64, self.cluster_to_sector(cluster) as u64,
self.bpb.sectors_per_cluster as usize, self.bpb.sectors_per_cluster as usize,
); );
} }
@@ -463,14 +472,14 @@ impl<'a> FatFs<'a> {
let fat_entry_size = match self.fat_type { let fat_entry_size = match self.fat_type {
FatType::Fat12(_) => 2, // 12 bits per entry FatType::Fat12(_) => 2, // 12 bits per entry
FatType::Fat16(_) => 2, // 16 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 = cluster * fat_entry_size;
let entry_offset_in_sector = entry_offset % 512; let entry_offset_in_sector = entry_offset % 512;
// needs two incase we "straddle a sector" // needs two incase we "straddle a sector"
let sector_data = self let sector_data = self
.drive .partition
.read(self.fat_start + entry_offset as u64 / 512, 2) .read(self.fat_start + entry_offset as u64 / 512, 2)
.expect("Failed to read from FAT!"); .expect("Failed to read from FAT!");
@@ -487,7 +496,7 @@ impl<'a> FatFs<'a> {
[entry_offset_in_sector..entry_offset_in_sector + 2] [entry_offset_in_sector..entry_offset_in_sector + 2]
.try_into() .try_into()
.unwrap(); .unwrap();
return (u16::from_le_bytes(cluster_entry_bytes) & 0xFFFF) as u32; return (u16::from_le_bytes(cluster_entry_bytes)) as u32;
} }
FatType::Fat32(_) => { FatType::Fat32(_) => {
let cluster_entry_bytes: [u8; 4] = sector_data let cluster_entry_bytes: [u8; 4] = sector_data
@@ -501,10 +510,22 @@ impl<'a> FatFs<'a> {
} }
} }
impl<'a> VfsFileSystem for FatFs<'a> { impl FsOps for FatFs {
fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> { fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const super::vfs::Vfs) {
let path_componenets: Vec<&str> = path.trim_start_matches('/').split('/').collect(); // TODO: load the FAT into memory here
let mut current_cluster = match self.fat_type {
*data = core::ptr::addr_of!(*self) as *mut u8;
// *data = unsafe { alloc::alloc::alloc(alloc::alloc::Layout::new::<Option<VNode>>()) };
// unsafe { *data.cast::<Option<VNode>>() = 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, FatType::Fat32(ebpb) => ebpb.root_dir_cluster as usize,
_ => self.sector_to_cluster( _ => self.sector_to_cluster(
self.bpb.reserved_sectors as usize self.bpb.reserved_sectors as usize
@@ -512,49 +533,208 @@ impl<'a> VfsFileSystem for FatFs<'a> {
), ),
}; };
for path in path_componenets { let file = File::Dir(FatDirectory {
let file_entry: FileEntry = self.find_entry_in_directory(current_cluster, path)?; directory_cluster: root_cluster,
// fat_fs: self,
});
if file_entry.attributes == FileEntryAttributes::Directory as u8 { return super::vfs::VNode {
current_cluster = (((file_entry.high_first_cluster_number as u32) << 16) flags: 0,
| file_entry.low_first_cluster_number as u32) ref_count: 0,
as usize; 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 fid(&self, path: &str, vfsp: *const super::vfs::Vfs) -> Option<super::vfs::FileId> {
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<Box<dyn VfsFile + '_>, ()> {
// 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<Box<dyn VfsDirectory>, ()> {
// 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<super::vfs::VNode, ()> {
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<super::vfs::VNode, ()> {
let fat_fs = unsafe { (*(*vp).parent).data.cast::<FatFs>() };
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 { } else {
return Ok(Box::new(FatFile { crate::drivers::fs::vfs::VNodeType::Regular
fat_fs: self, };
file_entry,
})); 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"),
} }
} }
return Err(()); fn mkdir(
&self,
nm: &str,
va: super::vfs::VAttr,
c: super::vfs::UserCred,
vp: *const VNode,
) -> Result<super::vfs::VNode, ()> {
todo!("VNODE OPERATIONS");
} }
fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()> { fn open(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) -> Result<Arc<[u8]>, ()> {
unimplemented!(); match self {
} File::Archive(archive) => {
} let fat_fs = unsafe { (*(*vp).parent).data.cast::<FatFs>() };
struct FatFile<'a> { let mut file: Vec<u8> = Vec::with_capacity(archive.file_entry.file_size as usize);
fat_fs: &'a FatFs<'a>,
file_entry: FileEntry,
}
impl<'a> VfsFile for FatFile<'a> {
fn read(&self) -> Result<Arc<[u8]>, ()> {
let mut file: Vec<u8> = Vec::with_capacity(self.file_entry.file_size as usize);
let mut file_ptr_index = 0; let mut file_ptr_index = 0;
let mut cluster = ((self.file_entry.high_first_cluster_number as u32) << 16) let mut cluster = ((archive.file_entry.high_first_cluster_number as u32) << 16)
| self.file_entry.low_first_cluster_number as u32; | archive.file_entry.low_first_cluster_number as u32;
let cluster_size = self.fat_fs.cluster_size; let cluster_size = unsafe { (*fat_fs).cluster_size };
let mut copied_bytes = 0; let mut copied_bytes = 0;
loop { loop {
let cluster_data = self.fat_fs.read_cluster(cluster as usize)?; let cluster_data = unsafe { (*fat_fs).read_cluster(cluster as usize)? };
let remaining = self.file_entry.file_size as usize - copied_bytes; let remaining = archive.file_entry.file_size as usize - copied_bytes;
let to_copy = if remaining > cluster_size { let to_copy = if remaining > cluster_size {
cluster_size cluster_size
} else { } else {
@@ -575,9 +755,9 @@ impl<'a> VfsFile for FatFile<'a> {
copied_bytes += to_copy; copied_bytes += to_copy;
cluster = self.fat_fs.get_next_cluster(cluster as usize); cluster = unsafe { (*fat_fs).get_next_cluster(cluster as usize) };
match self.fat_fs.fat_type { match unsafe { (*fat_fs).fat_type } {
FatType::Fat12(_) => { FatType::Fat12(_) => {
if cluster >= EOC_12 { if cluster >= EOC_12 {
break; break;
@@ -598,15 +778,138 @@ impl<'a> VfsFile for FatFile<'a> {
return Ok(Arc::from(file)); 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 FatDirectory<'a> { struct FatFile {
fat_fs: &'a FatFs<'a>, // fat_fs: &'a FatFs,
file_entry: FileEntry,
}
// impl<'a> VfsFile for FatFile<'a> {
// fn read(&self) -> Result<Arc<[u8]>, ()> {
// let mut file: Vec<u8> = 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 copied_bytes = 0;
// 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
// };
// 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 = 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;
// }
// }
// }
// }
// return Ok(Arc::from(file));
// }
// }
struct FatDirectory {
// fat_fs: &'a FatFs,
directory_cluster: usize, directory_cluster: usize,
} }
impl<'a> VfsDirectory for FatDirectory<'a> { // impl<'a> VfsDirectory for FatDirectory<'a> {
fn list_files(&self) -> Result<Arc<[Box<dyn VfsFile>]>, ()> { // fn list_files(&self) -> Result<Arc<[Box<dyn VfsFile>]>, ()> {
unimplemented!(); // unimplemented!();
} // }
} // }

View File

@@ -1,6 +1,6 @@
use alloc::{sync::Arc, vec::Vec}; use alloc::{sync::Arc, vec::Vec};
use crate::libs::mutex::Mutex; use crate::libs::sync::Mutex;
#[derive(Debug)] #[derive(Debug)]
#[repr(u8)] #[repr(u8)]
@@ -82,7 +82,7 @@ pub fn uncompress_data(bytes: &[u8]) -> Result<Arc<[u8]>, CompressionErrors> {
return Err(CompressionErrors::FailedChecksum); return Err(CompressionErrors::FailedChecksum);
} }
return Ok(data.into()); return Ok(data);
} }
fn adler32(bytes: &[u8]) -> u32 { fn adler32(bytes: &[u8]) -> u32 {
@@ -151,7 +151,7 @@ impl InflateContext {
pub fn get_bit(&mut self) -> bool { pub fn get_bit(&mut self) -> bool {
if self.bit_index == 8 { if self.bit_index == 8 {
self.input_buf.remove(0); 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); panic!("Not enough data! {:X?}", self.output_buf);
} }
@@ -190,7 +190,7 @@ impl InflateContext {
self.uncompressed()?; self.uncompressed()?;
} }
0x01 => { 0x01 => {
self.inflate(FIXED_LENGTHS.lock().write(), FIXED_DISTS.lock().write())?; self.inflate(&mut FIXED_LENGTHS.lock(), &mut FIXED_DISTS.lock())?;
} }
0x02 => { 0x02 => {
self.decode_huffman()?; self.decode_huffman()?;
@@ -243,7 +243,7 @@ impl InflateContext {
} }
fn peek(&mut self, offset: usize) -> u8 { 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] self.ring.data[index]
} }
@@ -416,22 +416,15 @@ fn build_huffman(lengths: &[u8], size: usize, out: &mut Huff) {
fn build_fixed() { fn build_fixed() {
let mut lengths = [0_u8; 288]; 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[0..144].fill(8);
lengths[i] = 5; lengths[144..256].fill(9);
} lengths[256..280].fill(7);
build_huffman(&lengths, 30, FIXED_DISTS.lock().write()); 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());
} }

View File

@@ -5,17 +5,14 @@ use core::fmt::{self, Debug};
use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloc::{boxed::Box, sync::Arc, vec::Vec};
use limine::ModuleRequest; use limine::ModuleRequest;
use crate::libs::{ use crate::libs::cell::LazyCell;
lazy::Lazy,
math::{ceil, floor},
};
use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem}; use super::vfs::{FsOps, VNode, VNodeOperations};
pub static MODULE_REQUEST: ModuleRequest = ModuleRequest::new(0); pub static MODULE_REQUEST: ModuleRequest = ModuleRequest::new(0);
// TODO: do something better than this shite // TODO: do something better than this shite
pub static INITRAMFS: Lazy<Squashfs> = Lazy::new(init); pub static INITRAMFS: LazyCell<Squashfs> = LazyCell::new(init);
fn init() -> Squashfs<'static> { fn init() -> Squashfs<'static> {
// TODO: Put the module request stuff in another file? // TODO: Put the module request stuff in another file?
@@ -110,41 +107,30 @@ impl Squashfs<'_> {
let fragment_table: Option<&[u8]> = { let fragment_table: Option<&[u8]> = {
if superblock.frag_table == u64::MAX { if superblock.frag_table == u64::MAX {
None None
} else { } else if superblock.export_table != u64::MAX {
if superblock.export_table != u64::MAX {
Some( Some(
&squashfs_data &squashfs_data
[superblock.frag_table as usize..superblock.export_table as usize], [superblock.frag_table as usize..superblock.export_table as usize],
) )
} else if superblock.xattr_table != u64::MAX { } else if superblock.xattr_table != u64::MAX {
Some( Some(
&squashfs_data &squashfs_data[superblock.frag_table as usize..superblock.xattr_table as usize],
[superblock.frag_table as usize..superblock.xattr_table as usize],
) )
} else { } else {
Some( Some(&squashfs_data[superblock.frag_table as usize..superblock.id_table as usize])
&squashfs_data
[superblock.frag_table as usize..superblock.id_table as usize],
)
}
} }
}; };
let export_table: Option<&[u8]> = { let export_table: Option<&[u8]> = {
if superblock.export_table == u64::MAX { if superblock.export_table == u64::MAX {
None None
} else { } else if superblock.xattr_table != u64::MAX {
if superblock.xattr_table != u64::MAX {
Some( Some(
&squashfs_data &squashfs_data
[superblock.export_table as usize..superblock.xattr_table as usize], [superblock.export_table as usize..superblock.xattr_table as usize],
) )
} else { } else {
Some( Some(&squashfs_data[superblock.export_table as usize..superblock.id_table as usize])
&squashfs_data
[superblock.export_table as usize..superblock.id_table as usize],
)
}
} }
}; };
@@ -201,15 +187,11 @@ impl Squashfs<'_> {
match inode_file_type { match inode_file_type {
InodeFileType::BasicDirectory => { InodeFileType::BasicDirectory => {
return Inode::BasicDirectory(BasicDirectoryInode::from_bytes( return Inode::BasicDirectory(BasicDirectoryInode::from_bytes(
self,
&inode_table[inode_offset..], &inode_table[inode_offset..],
)); ));
} }
InodeFileType::BasicFile => { InodeFileType::BasicFile => {
return Inode::BasicFile(BasicFileInode::from_bytes( return Inode::BasicFile(BasicFileInode::from_bytes(&inode_table[inode_offset..]));
self,
&inode_table[inode_offset..],
));
} }
_ => panic!("Unsupported or unknown inode file type {inode_file_type:?}!"), _ => panic!("Unsupported or unknown inode file type {inode_file_type:?}!"),
}; };
@@ -229,7 +211,7 @@ impl Squashfs<'_> {
} else { } else {
header & 0x8000 == 0 header & 0x8000 == 0
}; };
let table_size = header & 0x7FFF; // let table_size = header & 0x7FFF;
// if table.len() >= 8192 { // if table.len() >= 8192 {
// panic!("Inode block is not less than 8KiB!"); // panic!("Inode block is not less than 8KiB!");
@@ -255,45 +237,220 @@ impl Squashfs<'_> {
} }
} }
impl<'a> VfsFileSystem for Squashfs<'a> { impl<'a> FsOps for Squashfs<'a> {
fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> { fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const super::vfs::Vfs) {
let path_components: Vec<&str> = path.trim_start_matches('/').split('/').collect(); // STUB
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)); 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(),
} }
} }
return Err(()); fn fid(&self, path: &str, vfsp: *const super::vfs::Vfs) -> Option<super::vfs::FileId> {
todo!();
} }
fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()> { fn statfs(&self, vfsp: *const super::vfs::Vfs) -> super::vfs::StatFs {
unimplemented!() 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<Box<dyn VfsFile + '_>, ()> {
// 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<Box<dyn VfsDirectory>, ()> {
// unimplemented!()
// }
// }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
enum Inode<'a> { enum Inode {
BasicFile(BasicFileInode<'a>), BasicFile(BasicFileInode),
BasicDirectory(BasicDirectoryInode<'a>), BasicDirectory(BasicDirectoryInode),
}
impl VNodeOperations for Inode {
fn open(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) -> Result<Arc<[u8]>, ()> {
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<super::vfs::VNode, ()> {
todo!()
}
fn create(
&self,
nm: &str,
va: super::vfs::VAttr,
e: u32,
m: u32,
c: super::vfs::UserCred,
vp: *const VNode,
) -> Result<super::vfs::VNode, ()> {
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<super::vfs::VNode, ()> {
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 { macro_rules! inode_enum_try_into {
($inode_type:ty, $inode_name:ident) => { ($inode_type:ty, $inode_name:ident) => {
impl<'a> TryInto<$inode_type> for Inode<'a> { impl<'a> TryInto<$inode_type> for Inode {
type Error = (); type Error = ();
fn try_into(self) -> Result<$inode_type, Self::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!(BasicFileInode, BasicFile);
inode_enum_try_into!(BasicDirectoryInode<'a>, BasicDirectory); inode_enum_try_into!(BasicDirectoryInode, BasicDirectory);
// TODO: can we remove the dependence on squahsfs?? // TODO: can we remove the dependence on squahsfs??
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct InodeHeader<'a> { struct InodeHeader {
squashfs: &'a Squashfs<'a>, // squashfs: &'a Squashfs<'a>,
file_type: InodeFileType, file_type: InodeFileType,
_reserved: [u16; 3], _reserved: [u16; 3],
mtime: u32, mtime: u32,
inode_num: u32, inode_num: u32,
} }
impl<'a> InodeHeader<'a> { impl InodeHeader {
fn from_bytes(squashfs: &'a Squashfs, bytes: &[u8]) -> Self { fn from_bytes(bytes: &[u8]) -> Self {
let file_type = u16::from_le_bytes(bytes[0..2].try_into().unwrap()).into(); 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 mtime = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
let inode_num = u32::from_le_bytes(bytes[12..16].try_into().unwrap()); let inode_num = u32::from_le_bytes(bytes[12..16].try_into().unwrap());
return Self { return Self {
squashfs, // squashfs,
file_type, file_type,
_reserved: [0; 3], _reserved: [0; 3],
mtime, 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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InodeHeader") f.debug_struct("InodeHeader")
.field("file_type", &self.file_type) .field("file_type", &self.file_type)
@@ -353,8 +510,8 @@ impl<'a> Debug for InodeHeader<'a> {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
struct BasicDirectoryInode<'a> { struct BasicDirectoryInode {
header: InodeHeader<'a>, header: InodeHeader,
block_index: u32, // 4 block_index: u32, // 4
link_count: u32, // 8 link_count: u32, // 8
file_size: u16, // 10 file_size: u16, // 10
@@ -362,9 +519,9 @@ struct BasicDirectoryInode<'a> {
parent_inode: u32, // 16 parent_inode: u32, // 16
} }
impl<'a> BasicDirectoryInode<'a> { impl BasicDirectoryInode {
fn from_bytes(squashfs: &'a Squashfs, bytes: &[u8]) -> Self { fn from_bytes(bytes: &[u8]) -> Self {
let header = InodeHeader::from_bytes(squashfs, bytes); let header = InodeHeader::from_bytes(bytes);
let block_index = u32::from_le_bytes(bytes[16..20].try_into().unwrap()); 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 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()); 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]> { // #[allow(dead_code)]
let mut entries: Vec<Inode> = Vec::new(); // fn entries(&self) -> Arc<[Inode]> {
// let mut entries: Vec<Inode> = Vec::new();
let directory_table = &self // let directory_table = &self
.header // .header
.squashfs // .squashfs
.get_decompressed_table(self.header.squashfs.directory_table, (true, None)); // .get_decompressed_table(self.header.squashfs.directory_table, (true, None));
let directory_table_header = // let directory_table_header =
DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]); // DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]);
// TODO: cheap hack, fix it when I have more hours of sleep. // // TODO: cheap hack, fix it when I have more hours of sleep.
let mut offset = self.block_offset as usize + core::mem::size_of::<DirectoryTableHeader>(); // let mut offset = self.block_offset as usize + core::mem::size_of::<DirectoryTableHeader>();
for _ in 0..directory_table_header.entry_count as usize { // for _ in 0..directory_table_header.entry_count as usize {
let directory_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]); // 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 // let file_inode = self
.header // .header
.squashfs // .squashfs
.read_inode(directory_table_entry.offset as u32); // .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<Inode<'a>> { // fn find(&self, name: &str) -> Option<Inode<'a>> {
let directory_table = &self // let directory_table = &self
.header // .header
.squashfs // .squashfs
.get_decompressed_table(self.header.squashfs.directory_table, (true, None)); // .get_decompressed_table(self.header.squashfs.directory_table, (true, None));
let directory_table_header = // let directory_table_header =
DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]); // DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]);
// TODO: cheap hack, fix it when I have more hours of sleep. // // TODO: cheap hack, fix it when I have more hours of sleep.
let mut offset = self.block_offset as usize + core::mem::size_of::<DirectoryTableHeader>(); // let mut offset = self.block_offset as usize + core::mem::size_of::<DirectoryTableHeader>();
// 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 { // offset += 8 + directory_table_entry.name.len();
let directory_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]);
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 None;
return Some( // }
self.header
.squashfs
.read_inode(directory_table_entry.offset as u32),
);
}
}
return None;
}
} }
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
struct BasicFileInode<'a> { struct BasicFileInode {
header: InodeHeader<'a>, header: InodeHeader,
block_start: u32, // 4 block_start: u32, // 4
frag_idx: u32, // 8 frag_idx: u32, // 8
block_offset: u32, // 12 block_offset: u32, // 12
@@ -452,9 +610,9 @@ struct BasicFileInode<'a> {
block_sizes: *const u32, block_sizes: *const u32,
} }
impl<'a> BasicFileInode<'a> { impl BasicFileInode {
fn from_bytes(squashfs: &'a Squashfs, bytes: &[u8]) -> Self { fn from_bytes(bytes: &[u8]) -> Self {
let header = InodeHeader::from_bytes(squashfs, bytes); let header = InodeHeader::from_bytes(bytes);
let block_start = u32::from_le_bytes(bytes[16..20].try_into().unwrap()); 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 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()); 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> { // impl<'a> VfsFile for BasicFileInode<'a> {
fn read(&self) -> Result<Arc<[u8]>, ()> { // fn read(&self) -> Result<Arc<[u8]>, ()> {
// TODO: is this really how you're supposed to do this? // // TODO: is this really how you're supposed to do this?
let mut block_data: Vec<u8> = Vec::with_capacity(self.file_size as usize); // let mut block_data: Vec<u8> = Vec::with_capacity(self.file_size as usize);
let data_table: Vec<u8>; // let data_table: Vec<u8>;
let block_offset = if self.frag_idx == u32::MAX { // let block_offset = if self.frag_idx == u32::MAX {
data_table = self.header.squashfs.get_decompressed_table( // data_table = self.header.squashfs.get_decompressed_table(
self.header.squashfs.data_table, // self.header.squashfs.data_table,
( // (
false, // false,
Some( // Some(
!self // !self
.header // .header
.squashfs // .squashfs
.superblock // .superblock
.features() // .features()
.uncompressed_data_blocks, // .uncompressed_data_blocks,
), // ),
), // ),
); // );
self.block_offset as usize // self.block_offset as usize
} else { // } else {
// Tail end packing // // Tail end packing
let fragment_table = self.header.squashfs.get_decompressed_table( // let fragment_table = self.header.squashfs.get_decompressed_table(
self.header.squashfs.fragment_table.unwrap(), // self.header.squashfs.fragment_table.unwrap(),
( // (
false, // false,
Some(false), // Some( // Some(false), // Some(
// !self // // !self
// .header // // .header
// .squashfs // // .squashfs
// .superblock // // .superblock
// .features() // // .features()
// .uncompressed_fragments, // // .uncompressed_fragments,
// ), // // ),
), // ),
); // );
let fragment_pointer = (self.header.squashfs.start as u64 // let fragment_pointer = (self.header.squashfs.start as u64
+ u64::from_le_bytes( // + u64::from_le_bytes(
fragment_table[self.frag_idx as usize..(self.frag_idx + 8) as usize] // fragment_table[self.frag_idx as usize..(self.frag_idx + 8) as usize]
.try_into() // .try_into()
.unwrap(), // .unwrap(),
)) as *mut u8; // )) as *mut u8;
// build array since fragment_pointer is not guaranteed to be 0x02 aligned // // 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, // // 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, // // 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 // // 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 // // include the header bytes otherwise we are short by two bytes
let fragment_block_size = unsafe { // let fragment_block_size = unsafe {
u16::from_le(core::ptr::read_unaligned(fragment_pointer as *mut u16)) & 0x7FFF // u16::from_le(core::ptr::read_unaligned(fragment_pointer as *mut u16)) & 0x7FFF
} + 2; // } + 2;
let mut fragment_block_raw = Vec::new(); // let mut fragment_block_raw = Vec::new();
for i in 0..fragment_block_size as usize { // for i in 0..fragment_block_size as usize {
fragment_block_raw // fragment_block_raw
.push(unsafe { core::ptr::read_unaligned(fragment_pointer.add(i)) }) // .push(unsafe { core::ptr::read_unaligned(fragment_pointer.add(i)) })
} // }
let fragment_block = self // let fragment_block = self
.header // .header
.squashfs // .squashfs
.get_decompressed_table(&fragment_block_raw, (true, None)); // .get_decompressed_table(&fragment_block_raw, (true, None));
let fragment_start = u64::from_le_bytes(fragment_block[0..8].try_into().unwrap()); // 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_size = u32::from_le_bytes(fragment_block[8..12].try_into().unwrap());
let fragment_compressed = fragment_size & 1 << 24 == 0; // let fragment_compressed = fragment_size & 1 << 24 == 0;
let fragment_size = fragment_size & 0xFEFFFFFF; // let fragment_size = fragment_size & 0xFEFFFFFF;
let data_table_raw = unsafe { // let data_table_raw = unsafe {
core::slice::from_raw_parts( // core::slice::from_raw_parts(
(self.header.squashfs.start as u64 + fragment_start) as *mut u8, // (self.header.squashfs.start as u64 + fragment_start) as *mut u8,
fragment_size as usize, // fragment_size as usize,
) // )
.to_vec() // .to_vec()
}; // };
data_table = self // data_table = self
.header // .header
.squashfs // .squashfs
.get_decompressed_table(&data_table_raw, (false, Some(fragment_compressed))); // .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)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]

View File

@@ -1,3 +1,4 @@
pub mod devfs;
pub mod fat; pub mod fat;
pub mod initramfs; pub mod initramfs;
pub mod vfs; pub mod vfs;

View File

@@ -1,50 +1,357 @@
use alloc::{ // use alloc::{
boxed::Box, // boxed::Box,
string::{String, ToString}, // string::{String, ToString},
sync::Arc, // sync::Arc,
vec::Vec, // vec::Vec,
}; // };
use crate::libs::mutex::Mutex; // use crate::{drivers::pci::PCI_DEVICES, libs::sync::Mutex};
pub trait VfsFileSystem { // pub trait VfsFileSystem {
fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()>; // fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()>;
fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()>; // fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()>;
} // }
pub trait VfsFile { // pub trait VfsFile {
fn read(&self) -> Result<Arc<[u8]>, ()>; // fn read(&self) -> Result<Arc<[u8]>, ()>;
} // }
pub trait VfsDirectory { // pub trait VfsDirectory {
fn list_files(&self) -> Result<Arc<[Box<dyn VfsFile>]>, ()>; // fn list_files(&self) -> Result<Arc<[Box<dyn VfsFile>]>, ()>;
} // }
pub static VFS_INSTANCES: Mutex<Vec<Vfs>> = Mutex::new(Vec::new()); // pub static VFS_INSTANCES: Mutex<Vec<Vfs>> = Mutex::new(Vec::new());
// pub struct Vfs {
// _identifier: String,
// file_system: Box<dyn VfsFileSystem>,
// }
// impl Vfs {
// pub fn new(file_system: Box<dyn VfsFileSystem>, identifier: &str) -> Self {
// return Self {
// _identifier: identifier.to_string(),
// file_system,
// };
// }
// pub fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> {
// return self.file_system.open(path);
// }
// pub fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()> {
// 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::<Vec<_>>();
// 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 { pub struct Vfs {
identifier: String, next: Option<*mut Vfs>,
file_system: Box<dyn VfsFileSystem>, ops: Option<Box<dyn FsOps>>,
vnode_covered: Option<Box<VNode>>,
flags: u32,
block_size: u32,
pub data: *mut u8,
} }
unsafe impl Sync for Vfs {}
impl Vfs { impl Vfs {
pub fn new(file_system: Box<dyn VfsFileSystem>, identifier: &str) -> Self { const fn null() -> Self {
return Self { return Vfs {
identifier: identifier.to_string(), next: None,
file_system, ops: None,
vnode_covered: None,
flags: 0,
block_size: 0,
data: core::ptr::null_mut(),
}; };
} }
pub fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> { fn as_ptr(&self) -> *const Vfs {
return self.file_system.open(path); core::ptr::addr_of!(*self)
} }
pub fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()> { fn as_mut_ptr(&mut self) -> *mut Vfs {
return self.file_system.read_dir(path); core::ptr::addr_of_mut!(*self)
} }
} }
pub fn init() { pub trait FsOps {
// TODO: Deduce which storage medium(s) we're using // yes, the vfsp was the best solution I could come up with
crate::drivers::storage::ide::init(); 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<FileId>;
// 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<dyn VNodeOperations>,
pub node_data: Option<NodeData>,
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<Arc<[u8]>, ()>;
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<VNode, ()>;
fn create(
&self,
nm: &str,
va: VAttr,
e: u32,
m: u32,
c: UserCred,
vp: *const VNode,
) -> Result<VNode, ()>;
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<VNode, ()>;
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<dyn FsOps>) -> Result<(), ()> {
let layout = alloc::alloc::Layout::new::<Vfs>();
let vfs = PHYSICAL_MEMORY_MANAGER.alloc(1).unwrap().cast::<Vfs>();
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::<Vec<&str>>();
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<VNode, ()> {
let parts = path.split('/').collect::<Vec<&str>>();
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);
} }

View File

@@ -21,14 +21,17 @@ static EXTENDED_KEY: AtomicBool = AtomicBool::new(false);
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub extern "x86-interrupt" fn keyboard_interrupt_handler() { 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 scancode = inb(KBD_DATA_PORT);
let key = parse_key(scancode); let key = parse_key(scancode);
if let Some(key) = key { if let Some(key) = key {
crate::usr::shell::handle_key(key) // crate::usr::shell::handle_key(key)
write_serial(key.character.unwrap() as u8);
} }
} }

View File

@@ -1,8 +1,6 @@
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub mod acpi; pub mod acpi;
pub mod fs; pub mod fs;
pub mod keyboard; pub mod keyboard;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub mod pci; pub mod pci;
pub mod serial; pub mod serial;
pub mod storage; pub mod storage;

View File

@@ -2,7 +2,7 @@ use alloc::vec::Vec;
use crate::{ use crate::{
arch::io::{inl, outl}, 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 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) (bar0, bar1, bar2, bar3, bar4, bar5)
} }
#[derive(Debug)]
pub struct PciDevice { pub struct PciDevice {
pub bus: u8, pub bus: u8,
pub device: u8, pub device: u8,
@@ -130,7 +131,7 @@ pub fn enumerate_pci_bus() {
} }
crate::println!("====== PCI DEVICES ======"); 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}") 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) { fn check_function(bus: u8, device: u8, func: u8) {
PCI_DEVICES PCI_DEVICES.lock().push(PciDevice::new(bus, device, func));
.lock()
.write()
.push(PciDevice::new(bus, device, func));
let _secondary_bus: u8; let _secondary_bus: u8;

View File

@@ -1,11 +1,11 @@
use core::sync::atomic::AtomicBool; use core::sync::atomic::AtomicBool;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(target_arch = "x86_64")]
use crate::arch::io::{inb, outb}; use crate::arch::io::{inb, outb, outsb};
// COM1 // COM1
pub static PORT: u16 = 0x3f8; 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); 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 + 2: Interrupt identification and FIFO control registers.
// PORT + 3: Line control register, this sets DLAB to the most significant bit. // PORT + 3: Line control register, this sets DLAB to the most significant bit.
// PORT + 4: Modem control register // PORT + 4: Modem control register
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(target_arch = "x86_64")]
pub fn init_serial() -> u8 { pub fn init_serial() -> u8 {
outb(PORT + 1, 0x00); outb(PORT + 1, 0x00);
outb(PORT + 3, 0x80); outb(PORT + 3, 0x80);
@@ -43,30 +43,49 @@ pub fn init_serial() -> u8 {
} }
pub fn write_string(string: &str) { pub fn write_string(string: &str) {
#[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() { for &ch in string.as_bytes() {
write_serial(ch as char); 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 { pub fn init_serial() -> u8 {
return 0; return 0;
} }
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn is_transmit_empty() -> bool { 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"))] #[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() {} while is_transmit_empty() {}
if character == '\n' { if character == b'\n' {
write_serial('\r'); 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")))] #[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")))] #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
pub fn write_serial(character: char) { pub fn write_serial(character: u8) {
unsafe { unsafe {
*UART = character; *UART = character;
}; };
} }
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
pub fn read_serial() -> u8 {
return 0;
}

View File

@@ -5,10 +5,10 @@ use alloc::{boxed::Box, format, sync::Arc, vec::Vec};
use crate::{ use crate::{
arch::io::{inb, insw, inw, outb, outsw}, arch::io::{inb, insw, inw, outb, outsw},
drivers::{ drivers::{
fs::fat, fs::{devfs::DeviceOperations, fat, vfs::add_vfs},
storage::{GPTHeader, GPTPartitionEntry, MBR}, storage::{GPTHeader, GPTPartitionEntry, Partition, MBR},
}, },
libs::{mutex::Mutex, uuid::Uuid}, libs::{sync::Mutex, uuid::Uuid},
}; };
use super::BlockDevice; use super::BlockDevice;
@@ -52,19 +52,20 @@ impl core::convert::From<u8> for ATADriveStatus {
} }
} }
#[repr(u8)] // #[repr(u8)]
enum ATADriveError { // enum ATADriveError {
AddressMarkNotFound = 0x01, // AddressMarkNotFound = 0x01,
Track0NotFound = 0x02, // Track0NotFound = 0x02,
CommandAborted = 0x04, // CommandAborted = 0x04,
MediaChangeReq = 0x08, // MediaChangeReq = 0x08,
IDNotFound = 0x10, // IDNotFound = 0x10,
MediaChanged = 0x20, // MediaChanged = 0x20,
UncorrectableData = 0x40, // UncorrectableData = 0x40,
BadBlock = 0x80, // BadBlock = 0x80,
} // }
#[repr(u8)] #[repr(u8)]
#[allow(dead_code)]
enum ATADriveCommand { enum ATADriveCommand {
ReadPIO = 0x20, ReadPIO = 0x20,
ReadPIOExt = 0x24, ReadPIOExt = 0x24,
@@ -81,20 +82,20 @@ enum ATADriveCommand {
Identify = 0xEC, Identify = 0xEC,
} }
#[repr(u8)] // #[repr(u8)]
enum ATADriveIdentifyResponse { // enum ATADriveIdentifyResponse {
DeviceType = 0x00, // DeviceType = 0x00,
Cylinders = 0x02, // Cylinders = 0x02,
Heads = 0x06, // Heads = 0x06,
Sectors = 0x0C, // Sectors = 0x0C,
Serial = 0x14, // Serial = 0x14,
Model = 0x36, // Model = 0x36,
Capabilities = 0x62, // Capabilities = 0x62,
FieldValid = 0x6A, // FieldValid = 0x6A,
MaxLBA = 0x78, // MaxLBA = 0x78,
CommandSets = 0xA4, // CommandSets = 0xA4,
MaxLBAExt = 0xC8, // MaxLBAExt = 0xC8,
} // }
#[repr(u16)] #[repr(u16)]
enum IDEDriveType { enum IDEDriveType {
@@ -126,6 +127,7 @@ enum ATADriveType {
} }
#[repr(u8)] #[repr(u8)]
#[allow(dead_code)]
enum ATADriveDataRegister { enum ATADriveDataRegister {
Data = 0x00, Data = 0x00,
ErrorAndFeatures = 0x01, ErrorAndFeatures = 0x01,
@@ -144,12 +146,14 @@ enum ATADriveDataRegister {
} }
#[repr(u8)] #[repr(u8)]
#[allow(dead_code)]
enum ATADriveControlRegister { enum ATADriveControlRegister {
ControlAndAltStatus = 0x02, ControlAndAltStatus = 0x02,
DeviceAddress = 0x03, DeviceAddress = 0x03,
} }
#[repr(u8)] #[repr(u8)]
#[allow(dead_code)]
enum ATADriveChannels { enum ATADriveChannels {
Primary = 0x00, Primary = 0x00,
Secondary = 0x01, Secondary = 0x01,
@@ -494,6 +498,16 @@ impl ATADrive {
drive_type: drive, 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 { impl BlockDevice for ATADrive {
@@ -530,6 +544,7 @@ static DRIVES: Mutex<Vec<ATADrive>> = Mutex::new(Vec::new());
// This code could probably be made better and more device agnostic // This code could probably be made better and more device agnostic
// But that's TODO obviously // But that's TODO obviously
fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { 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 io_port_base = bar0 as u16;
let control_port_base = bar1 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); let drive = ATADrive::new(bus.clone(), drive_type);
if let Ok(drive) = drive { if let Ok(drive) = drive {
DRIVES.lock().write().push(drive); drives_lock.push(drive);
} }
} }
crate::log_info!( crate::log_info!(
"ATA: Detected {} drive{}", "ATA: Detected {} drive{}",
DRIVES.lock().read().len(), drives_lock.len(),
match DRIVES.lock().read().len() { match drives_lock.len() {
1 => "", 1 => "",
_ => "s", _ => "s",
} }
); );
for drive in DRIVES.lock().read().iter() { for drive in drives_lock.iter() {
let sectors = drive.sector_count(); let sectors = drive.sector_count();
crate::log_info!( 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 gpt = GPTHeader::new(&array);
let mut partitions: Vec<GPTPartitionEntry> = let mut partitions: Vec<Partition> = Vec::with_capacity(gpt.partition_entry_count as usize);
Vec::with_capacity(gpt.partition_entry_count as usize);
let partition_sector = drive let partition_sector = drive
.read( .read(
@@ -647,22 +661,28 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
.unwrap(); .unwrap();
// Store the parsed information in the partition_entries array // Store the parsed information in the partition_entries array
partitions.push(GPTPartitionEntry { partitions.push(Partition::GPTPartition((
GPTPartitionEntry {
partition_type_guid, partition_type_guid,
unique_partition_guid, unique_partition_guid,
start_sector, start_sector,
end_sector, end_sector,
attributes, attributes,
partition_name, partition_name,
}); },
drive.as_ptr(),
)));
} }
for &partition in partitions.iter() { for &partition in partitions.iter() {
if partition.partition_type_guid != "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" { match partition {
Partition::GPTPartition(gpt_partition) => {
if gpt_partition.0.partition_type_guid != "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
{
continue; continue;
} }
let fat_fs = fat::FatFs::new(drive, partition); let fat_fs = fat::FatFs::new(partition);
if fat_fs.is_err() { if fat_fs.is_err() {
continue; continue;
@@ -670,29 +690,31 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
let fat_fs = fat_fs.unwrap(); let fat_fs = fat_fs.unwrap();
let vfs = crate::drivers::fs::vfs::Vfs::new( crate::println!("adding fat fs to / :scared:");
Box::new(fat_fs),
&format!("{}", partition.partition_type_guid),
);
crate::drivers::fs::vfs::VFS_INSTANCES add_vfs("/", Box::new(fat_fs));
.lock()
.write()
.push(vfs);
crate::println!( // let vfs = crate::drivers::fs::vfs::Vfs::new(
"{:?}", // Box::new(fat_fs),
crate::drivers::fs::vfs::VFS_INSTANCES // &format!("{}", gpt_partition.0.partition_type_guid),
.lock() // );
.read()
.last() // crate::drivers::fs::vfs::VFS_INSTANCES.lock().push(vfs);
.unwrap()
.open("/example.txt") // crate::println!(
.unwrap() // "{:?}",
.read() // crate::drivers::fs::vfs::VFS_INSTANCES
); // .lock()
// .read()
// .last()
// .unwrap()
// .open("/example.txt")
// .unwrap()
// .read()
// );
}
_ => todo!("Handle MBR!"),
}
} }
crate::println!("{:X?}", partitions);
} }
} }

View File

@@ -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<Arc<[u8]>, ()> {
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)] #[derive(Clone, Copy, Debug)]
pub struct MBRPartition { pub struct MBRPartition {
pub boot_indicator: u8, 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 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 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_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 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_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()); let partition_entry_size = u32::from_le_bytes(data[0x54..0x58].try_into().unwrap());

View File

@@ -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<Vec<u8>>,
}
impl PSFFont {
fn from_file_data(file_data: Vec<u8>) -> Result<PSFFont, ()> {
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<PSFFont> = 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!")
});

View File

@@ -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<Option<Framebuffer>> = 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<Framebuffer>) {
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<Framebuffer>,
) {
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<Option<alloc::vec::Vec<Option<[[u32; 8]; 16]>>>> = Mutex::new(None);
// pub fn put_char(
// character: char,
// cx: u16,
// cy: u16,
// fg: u32,
// bg: u32,
// mirror_buffer: Option<Framebuffer>,
// ) {
// 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<Framebuffer> {
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);
}

View File

@@ -1,15 +0,0 @@
#[derive(Clone, Copy, Debug)]
pub struct Elf;
pub fn load_elf(bytes: &[u8]) -> Result<Elf, ()> {
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);
}

View File

@@ -1,44 +0,0 @@
use core::{
cell::UnsafeCell,
ops::Deref,
sync::atomic::{AtomicBool, Ordering},
};
pub struct Lazy<T, F = fn() -> T> {
value: UnsafeCell<Option<T>>,
init_func: F,
initialized: AtomicBool,
}
impl<T, F: Fn() -> T> Lazy<T, F> {
pub const fn new(init_func: F) -> Self {
Lazy {
value: UnsafeCell::new(None),
init_func,
initialized: AtomicBool::new(false),
}
}
}
impl<T, F: Fn() -> T> Deref for Lazy<T, F> {
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, F: Fn() -> T + Send> Sync for Lazy<T, F> {}

View File

@@ -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)*)));
}

View File

@@ -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;
}
}

View File

@@ -1,8 +1,3 @@
pub mod elf; pub mod cell;
pub mod lazy; pub mod sync;
pub mod logging;
pub mod math;
pub mod mutex;
pub mod oncecell;
pub mod util;
pub mod uuid; pub mod uuid;

View File

@@ -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<T: ?Sized> {
locked: AtomicBool,
data: UnsafeCell<T>,
}
unsafe impl<T: ?Sized> Sync for Mutex<T> {}
impl<T> Mutex<T> {
#[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<T> core::fmt::Debug for Mutex<T> {
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, "<locked> }}")
} else {
write!(f, "{:?} }}", self.data)
}
}
}
pub struct MutexGuard<'a, T: ?Sized> {
mutex: &'a Mutex<T>,
}
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);
}
}

View File

@@ -1,70 +0,0 @@
use core::{cell::UnsafeCell, ops::Deref, sync::atomic::AtomicU8};
pub struct OnceCell<T> {
state: AtomicU8,
data: UnsafeCell<Option<T>>,
}
unsafe impl<T> Sync for OnceCell<T> {}
#[repr(u8)]
enum State {
Uninitialized = 0,
Initializing,
Initialized,
}
impl From<u8> for State {
fn from(value: u8) -> Self {
match value {
0 => State::Uninitialized,
1 => State::Initializing,
2 => State::Initialized,
_ => panic!("Invalid state value"),
}
}
}
impl<T> OnceCell<T> {
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<T> Deref for OnceCell<T> {
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!")
}
}

View File

@@ -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");
}
}
}

View File

@@ -29,7 +29,7 @@ impl PartialEq for Uuid {
impl PartialEq<&str> for Uuid { impl PartialEq<&str> for Uuid {
fn eq(&self, other: &&str) -> bool { fn eq(&self, other: &&str) -> bool {
let parts = other.split("-").collect::<Vec<&str>>(); let parts = other.split('-').collect::<Vec<&str>>();
if parts.len() != 5 { if parts.len() != 5 {
return false; return false;

148
src/main.rs Executable file → Normal file
View File

@@ -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_std]
#![no_main] #![no_main]
extern crate alloc;
mod arch;
mod drivers;
mod libs;
mod mem;
mod usr;
use core::ffi::CStr; use core::ffi::CStr;
use alloc::{format, vec::Vec}; use alloc::{format, vec::Vec};
use drivers::serial; use drivers::serial::{read_serial, write_serial};
use libs::util::hcf;
use limine::KernelFileRequest; 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); 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"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
arch::interrupts::init(); arch::interrupts::init();
serial::init_serial(); drivers::serial::init_serial();
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
drivers::acpi::init_acpi();
mem::log_info();
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
drivers::pci::enumerate_pci_bus(); drivers::pci::enumerate_pci_bus();
drivers::fs::vfs::init(); drivers::storage::ide::init();
// crate::println!("{:?}", INITRAMFS.open("/font.psf").unwrap().read()); crate::println!("{:?}", vfs_open("/example.txt"));
if let Some(kernel) = KERNEL_REQUEST.get_response().get() {
crate::println!("{:X?}", kernel.kernel_file.get().unwrap().gpt_disk_uuid);
}
let file = vfs_open("/example.txt").unwrap();
crate::println!( crate::println!(
"Total memory: {}", "{:X?}",
crate::mem::PHYSICAL_MEMORY_MANAGER file.ops.open(0, UserCred { uid: 0, gid: 0 }, file.as_ptr())
.total_memory()
.label_bytes()
); );
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(); 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)] #[derive(Debug)]
pub struct KernelFeatures { pub struct KernelFeatures {
pub fat_in_mem: bool, pub fat_in_mem: bool,
@@ -71,8 +137,8 @@ impl KernelFeatures {
} }
} }
pub static KERNEL_FEATURES: libs::lazy::Lazy<KernelFeatures> = pub static KERNEL_FEATURES: libs::cell::LazyCell<KernelFeatures> =
libs::lazy::Lazy::new(parse_kernel_cmdline); libs::cell::LazyCell::new(parse_kernel_cmdline);
fn parse_kernel_cmdline() -> KernelFeatures { fn parse_kernel_cmdline() -> KernelFeatures {
let mut kernel_features: KernelFeatures = KernelFeatures { fat_in_mem: true }; let mut kernel_features: KernelFeatures = KernelFeatures { fat_in_mem: true };
@@ -118,13 +184,9 @@ fn parse_kernel_cmdline() -> KernelFeatures {
#[panic_handler] #[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! { 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() { drivers::serial::write_string(msg);
write_serial(ch);
}
log_error!("{}", info);
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{ {
@@ -137,3 +199,15 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
hcf(); 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");
}
}
}

View File

@@ -1,6 +1,6 @@
// Original code from: https://github.com/DrChat/buddyalloc/blob/master/src/heap.rs // 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 // 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. // 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 // 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::Ordering::SeqCst;
use core::sync::atomic::{AtomicPtr, AtomicU8, AtomicUsize}; use core::sync::atomic::{AtomicPtr, AtomicU8, AtomicUsize};
use crate::libs::mutex::Mutex; use crate::libs::sync::Mutex;
const fn log2(num: usize) -> u8 { const fn log2(num: usize) -> u8 {
let mut temp = num; let mut temp = num;
@@ -107,33 +107,36 @@ impl BuddyAllocator {
} }
fn free_list_pop(&self, order: usize) -> Option<*mut u8> { 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() { if candidate.is_null() {
return None; return None;
} }
if order != self.free_lists.lock().read().len() - 1 { if order != free_lists_lock.len() - 1 {
(*self.free_lists.lock().write())[order] = unsafe { (*candidate).next }; (*free_lists_lock)[order] = unsafe { (*candidate).next };
} else { } else {
(*self.free_lists.lock().write())[order] = ptr::null_mut(); (*free_lists_lock)[order] = ptr::null_mut();
} }
return Some(candidate as *mut u8); return Some(candidate as *mut u8);
} }
fn free_list_insert(&self, order: usize, block: *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; 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 { fn free_list_remove(&self, order: usize, block: *mut u8) -> bool {
let block_ptr = block as *mut FreeBlock; 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 { unsafe {
while !(*checking).is_null() { while !(*checking).is_null() {
@@ -177,11 +180,12 @@ impl BuddyAllocator {
} }
pub fn get_free_mem(&self) -> usize { pub fn get_free_mem(&self) -> usize {
let free_lists_lock = self.free_lists.lock();
let mut free_mem = 0; let mut free_mem = 0;
unsafe { unsafe {
for order in 0..self.free_lists.lock().read().len() { for order in 0..free_lists_lock.len() {
let mut block = (*self.free_lists.lock().write())[order]; let mut block = (*free_lists_lock)[order];
while !block.is_null() { while !block.is_null() {
free_mem += self.order_size(order); free_mem += self.order_size(order);
@@ -201,7 +205,9 @@ impl BuddyAllocator {
unsafe impl GlobalAlloc for BuddyAllocator { unsafe impl GlobalAlloc for BuddyAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if let Some(order_needed) = self.allocation_order(layout.size(), layout.align()) { 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 let Some(block) = self.free_list_pop(order) {
if order > order_needed { if order > order_needed {
self.split_free_block(block, 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"); .expect("Tried to dispose of invalid block");
let mut block = ptr; 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 let Some(buddy) = self.buddy(order, block) {
if self.free_list_remove(order, block) { if self.free_list_remove(order, block) {
block = min(block, buddy); 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());
};
}

View File

@@ -5,17 +5,14 @@ use core::alloc::GlobalAlloc;
use limine::{MemmapEntry, NonNullPtr}; use limine::{MemmapEntry, NonNullPtr};
use crate::{ use crate::libs::{cell::LazyCell, sync::Mutex};
libs::{lazy::Lazy, mutex::Mutex},
usr::tty::CONSOLE,
};
use self::{allocator::BuddyAllocator, pmm::PhysicalMemoryManager}; use self::{allocator::BuddyAllocator, pmm::PhysicalMemoryManager};
static MEMMAP_REQUEST: limine::MemmapRequest = limine::MemmapRequest::new(0); static MEMMAP_REQUEST: limine::MemmapRequest = limine::MemmapRequest::new(0);
static HHDM_REQUEST: limine::HhdmRequest = limine::HhdmRequest::new(0); static HHDM_REQUEST: limine::HhdmRequest = limine::HhdmRequest::new(0);
pub static MEMMAP: Lazy<Mutex<&mut [NonNullPtr<MemmapEntry>]>> = Lazy::new(|| { pub static MEMMAP: LazyCell<Mutex<&mut [NonNullPtr<MemmapEntry>]>> = LazyCell::new(|| {
let memmap_request = MEMMAP_REQUEST let memmap_request = MEMMAP_REQUEST
.get_response() .get_response()
.get_mut() .get_mut()
@@ -24,7 +21,7 @@ pub static MEMMAP: Lazy<Mutex<&mut [NonNullPtr<MemmapEntry>]>> = Lazy::new(|| {
return Mutex::new(memmap_request.memmap_mut()); return Mutex::new(memmap_request.memmap_mut());
}); });
pub static HHDM_OFFSET: Lazy<usize> = Lazy::new(|| { pub static HHDM_OFFSET: LazyCell<usize> = LazyCell::new(|| {
let hhdm = HHDM_REQUEST let hhdm = HHDM_REQUEST
.get_response() .get_response()
.get() .get()
@@ -33,37 +30,11 @@ pub static HHDM_OFFSET: Lazy<usize> = Lazy::new(|| {
return hhdm.offset as usize; return hhdm.offset as usize;
}); });
pub static PHYSICAL_MEMORY_MANAGER: Lazy<PhysicalMemoryManager> = pub static PHYSICAL_MEMORY_MANAGER: LazyCell<PhysicalMemoryManager> =
Lazy::new(PhysicalMemoryManager::new); LazyCell::new(PhysicalMemoryManager::new);
pub struct PageAllocator;
unsafe impl core::alloc::Allocator for PageAllocator {
fn allocate(
&self,
layout: core::alloc::Layout,
) -> Result<core::ptr::NonNull<[u8]>, 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<u8>, layout: core::alloc::Layout) {
let pages = layout.size() / 4096 + 1;
PHYSICAL_MEMORY_MANAGER.dealloc(ptr.as_ptr(), pages);
}
}
pub struct Allocator { pub struct Allocator {
pub inner: Lazy<BuddyAllocator>, pub inner: LazyCell<BuddyAllocator>,
} }
unsafe impl GlobalAlloc for Allocator { unsafe impl GlobalAlloc for Allocator {
@@ -81,7 +52,7 @@ const HEAP_SIZE: usize = HEAP_PAGES * 1024;
#[global_allocator] #[global_allocator]
pub static ALLOCATOR: Allocator = Allocator { pub static ALLOCATOR: Allocator = Allocator {
inner: Lazy::new(|| { inner: LazyCell::new(|| {
let heap_start = PHYSICAL_MEMORY_MANAGER let heap_start = PHYSICAL_MEMORY_MANAGER
.alloc(HEAP_PAGES) .alloc(HEAP_PAGES)
.expect("Failed to allocate heap!"); .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() { pub fn log_memory_map() {
let memmap_request = MEMMAP_REQUEST.get_response().get_mut(); let memmap_request = MEMMAP_REQUEST.get_response().get_mut();
if memmap_request.is_none() { if memmap_request.is_none() {
@@ -137,12 +69,12 @@ pub fn log_memory_map() {
let memmap = memmap_request.unwrap().memmap(); let memmap = memmap_request.unwrap().memmap();
crate::log_serial!("====== MEMORY MAP ======"); crate::log_serial!("====== MEMORY MAP ======\n");
for entry in memmap.iter() { for entry in memmap.iter() {
let label = (entry.len as usize).label_bytes(); let label = (entry.len as usize).label_bytes();
crate::log_serial!( crate::log_serial!(
"[ {:#018X?} ] Type: {:?} Size: {}", "[ {:#018X?} ] Type: {:?} Size: {}\n",
entry.base..entry.base + entry.len, entry.base..entry.base + entry.len,
entry.typ, entry.typ,
label 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 => _
);
}
}

View File

@@ -27,7 +27,7 @@ impl PhysicalMemoryManager {
let mut highest_addr: usize = 0; 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 { if entry.typ == limine::MemoryMapEntryType::Usable {
pmm.usable_pages pmm.usable_pages
.fetch_add(entry.len as usize / PAGE_SIZE, Ordering::SeqCst); .fetch_add(entry.len as usize / PAGE_SIZE, Ordering::SeqCst);
@@ -42,7 +42,7 @@ impl PhysicalMemoryManager {
let bitmap_size = let bitmap_size =
((pmm.highest_page_idx.load(Ordering::SeqCst) / 8) + PAGE_SIZE - 1) & !(PAGE_SIZE - 1); ((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 { if entry.typ != limine::MemoryMapEntryType::Usable {
continue; 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 { if entry.typ != limine::MemoryMapEntryType::Usable {
continue; continue;
} }

View File

@@ -1,3 +0,0 @@
pub mod shell;
#[macro_use]
pub mod tty;

View File

@@ -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(),
}
}

View File

@@ -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<Option<crate::drivers::video::Framebuffer>>,
// pub lines: Mutex<Vec<String>>,
}
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::<u32>(
// 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<u8> = 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<Console> = 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<u8>,
}
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<InputBuffer> = 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<usize, core::num::ParseIntError> = 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::<usize>();
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<u32, core::num::ParseIntError> = 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<String>) {
let mut command = String::new();
let mut args: Vec<String> = 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<u64> {
if let Some(stripped) = input.strip_prefix("0x") {
return u64::from_str_radix(stripped, 16).ok();
} else {
return None;
}
}