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

View File

@@ -104,7 +104,8 @@ sudo dd if=bin/CappuccinOS.iso of=/dev/sdX bs=1M && sync
## Supported Architectures
- x86_64
- RISC-V64 (experimental until I can get my hands on some RISC-V hardware)
- ~~aarch64~~ not in scope __might__ not build
- ~~RISC-V64~~ not in scope __might__ not build
## Credits an attributions
Inspiration was mainly from [JDH's Tetris OS](https://www.youtube.com/watch?v=FaILnmUYS_U), mixed with a growing interest in low level in general and an interest in learning rust (yeah, I started this project with not that much rust experience, maybe a CLI app or two, and trust me it shows).

View File

@@ -28,6 +28,16 @@ pub unsafe fn insw(port: u16, buffer: *mut u16, count: usize) {
return;
}
/// Outputs `count` 8-bit values from the specified `port` into the `buffer`.
///
/// # Safety
///
/// This function panics if the supplied buffer's size is smaller than `count`.
#[inline(always)]
pub unsafe fn outsb(port: u16, buffer: *const u8, count: usize) {
return;
}
/// Outputs `count` 16-bit values from the specified `port` into the `buffer`.
///
/// # Safety

View File

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

View File

@@ -28,6 +28,16 @@ pub unsafe fn insw(port: u16, buffer: *mut u16, count: usize) {
return;
}
/// Outputs `count` 8-bit values from the specified `port` into the `buffer`.
///
/// # Safety
///
/// This function panics if the supplied buffer's size is smaller than `count`.
#[inline(always)]
pub unsafe fn outsb(port: u16, buffer: *const u8, count: usize) {
return;
}
/// Outputs `count` 16-bit values from the specified `port` into the `buffer`.
///
/// # Safety

View File

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

View File

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

View File

@@ -1,24 +1,35 @@
pub mod interrupts;
pub mod io;
pub mod stack_trace;
// This inline is detremental to having readable stack traces
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
pub fn push_gprs() {
pub fn pause() {
unsafe {
core::arch::asm!(
"push rax", "push rbx", "push rcx", "push rdx", "push rsi", "push rdi", "push rbp",
"push r8", "push r9", "push r10", "push r11", "push r12", "push r13", "push r14",
"push r15"
);
}
core::arch::asm!("pause");
};
}
// This inline is detremental to having readable stack traces
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
pub fn pop_gprs() {
unsafe {
core::arch::asm!(
"pop r15", "pop r14", "pop r13", "pop r12", "pop r11", "pop r10", "pop r9", "pop r8",
"pop rbp", "pop rdi", "pop rsi", "pop rdx", "pop rcx", "pop rbx", "pop rax"
);
}
pub fn cpu_has_msr() -> bool {
return unsafe { core::arch::x86_64::__cpuid_count(1, 0).edx } & 1 << 5 != 0;
}
pub unsafe fn cpu_get_msr(msr: u32, lo: &mut u32, hi: &mut u32) {
core::arch::asm!(
"rdmsr",
in("ecx") msr,
inout("eax") *lo,
inout("edx") *hi,
);
}
pub unsafe fn cpu_set_msr(msr: u32, lo: &u32, hi: &u32) {
core::arch::asm!(
"wrmsr",
in("ecx") msr,
in("eax") *lo,
in("edx") *hi,
);
}

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_main]
// use alloc::format;
// extern crate alloc;
// // piggyback off of the CappuccinOS allocator
// // TODO: make a malloc lib for memory operations
// #[allow(unused_imports)]
// use CappuccinOS;
// use core::alloc::GlobalAlloc;
// use alloc::{borrow::ToOwned, format, string::String};
// struct Allocator;
// unsafe impl GlobalAlloc for Allocator {
// unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
// return malloc(layout.size());
// }
// unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
// free(ptr, layout.size());
// }
// }
// #[global_allocator]
// static ALLOC: Allocator = Allocator;
// extern "C" {
// fn malloc(size: usize) -> *mut u8;
// fn free(ptr: *mut u8, size: usize);
// }
#[no_mangle]
pub fn _start(_args: &[&str]) {

View File

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

View File

@@ -5,9 +5,9 @@ use alloc::{
vec::Vec,
};
use crate::drivers::storage::{BlockDevice, GPTPartitionEntry};
use crate::drivers::storage::Partition;
use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem};
use super::vfs::{FsOps, VNode, VNodeOperations};
// The first Cluster (perhaps 0xF0FFFF0F) is the FAT ID
// The second cluster stores the end-of-cluster-chain marker
@@ -97,6 +97,8 @@ pub struct FSInfo {
impl FSInfo {
pub fn from_bytes(bytes: Arc<[u8]>) -> Self {
assert!(bytes.len() >= 512);
let lead_signature = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
let mid_signature = u32::from_le_bytes(bytes[484..488].try_into().unwrap());
let last_known_free_cluster = u32::from_le_bytes(bytes[488..492].try_into().unwrap());
@@ -117,6 +119,7 @@ impl FSInfo {
#[repr(u8)]
#[derive(Debug, PartialEq)]
#[allow(dead_code)]
enum FileEntryAttributes {
ReadOnly = 0x01,
Hidden = 0x02,
@@ -127,7 +130,7 @@ enum FileEntryAttributes {
LongFileName = 0x0F,
}
#[repr(packed)]
#[repr(C, packed)]
#[derive(Debug)]
struct LongFileName {
entry_order: u8,
@@ -140,7 +143,7 @@ struct LongFileName {
final_characters: [u16; 2],
}
#[repr(packed)]
#[repr(C, packed)]
#[derive(Debug)]
pub struct FileEntry {
file_name: [u8; 8],
@@ -158,11 +161,18 @@ pub struct FileEntry {
file_size: u32,
}
pub struct FatFs<'a> {
// Block device Info
drive: &'a dyn BlockDevice,
partition: GPTPartitionEntry,
impl FileEntry {
pub fn cluster(&self) -> u32 {
let mut cluster = self.low_first_cluster_number as u32;
cluster |= (self.high_first_cluster_number as u32) << 16;
return cluster;
}
}
pub struct FatFs {
partition: Partition,
// FAT info
#[allow(dead_code)]
fs_info: Option<FSInfo>,
fat: Option<Arc<[u32]>>,
bpb: BIOSParameterBlock,
@@ -172,10 +182,10 @@ pub struct FatFs<'a> {
sectors_per_fat: usize,
}
impl<'a> FatFs<'a> {
pub fn new(drive: &'a dyn BlockDevice, partition: GPTPartitionEntry) -> Result<Self, ()> {
let bpb_bytes = drive
.read(partition.start_sector, 1)
impl FatFs {
pub fn new(partition: Partition) -> Result<Self, ()> {
let bpb_bytes = partition
.read(0, 1)
.expect("Failed to read FAT32 BIOS Parameter Block!");
let bpb = unsafe { *(bpb_bytes.as_ptr().cast::<BIOSParameterBlock>()) };
@@ -239,8 +249,8 @@ impl<'a> FatFs<'a> {
let fs_info = match fat_type {
FatType::Fat32(ebpb) => {
let fsinfo_bytes = drive
.read(partition.start_sector + ebpb.fsinfo_sector as u64, 1)
let fsinfo_bytes = partition
.read(ebpb.fsinfo_sector as u64, 1)
.expect("Failed to read FSInfo sector!");
Some(FSInfo::from_bytes(fsinfo_bytes))
@@ -248,7 +258,7 @@ impl<'a> FatFs<'a> {
_ => None,
};
let fat_start = partition.start_sector + bpb.reserved_sectors as u64;
let fat_start = bpb.reserved_sectors as u64;
let sectors_per_fat = match fat_type {
FatType::Fat32(ebpb) => ebpb.sectors_per_fat_ext as usize,
@@ -268,7 +278,7 @@ impl<'a> FatFs<'a> {
let mut fat_vec: Vec<u32> = Vec::with_capacity(bytes_per_fat / cluster_bytes);
for i in 0..sectors_per_fat {
let sector = drive
let sector = partition
.read(fat_start + i as u64, 1)
.expect("Failed to read FAT");
for j in 0..(512 / cluster_bytes) {
@@ -290,7 +300,7 @@ impl<'a> FatFs<'a> {
fat = Some(Arc::from(fat_vec));
} else {
crate::log_info!(
"\033[33mWARNING\033[0m: FAT is not being stored in memory, this feature is experimental and file reads are expected to be slower."
"\x1B[33mWARNING\x1B[0m: FAT is not being stored in memory, this feature is experimental and file reads are expected to be slower."
)
}
@@ -299,7 +309,6 @@ impl<'a> FatFs<'a> {
let cluster_size = bpb.sectors_per_cluster as usize * 512;
return Ok(Self {
drive,
partition,
fs_info,
fat,
@@ -416,8 +425,8 @@ impl<'a> FatFs<'a> {
}
pub fn read_cluster(&self, cluster: usize) -> Result<Arc<[u8]>, ()> {
return self.drive.read(
self.partition.start_sector + self.cluster_to_sector(cluster) as u64,
return self.partition.read(
self.cluster_to_sector(cluster) as u64,
self.bpb.sectors_per_cluster as usize,
);
}
@@ -463,14 +472,14 @@ impl<'a> FatFs<'a> {
let fat_entry_size = match self.fat_type {
FatType::Fat12(_) => 2, // 12 bits per entry
FatType::Fat16(_) => 2, // 16 bits per entry
FatType::Fat32(_) => 4, // 28S bits per entry
FatType::Fat32(_) => 4, // 28 bits per entry
};
let entry_offset = cluster * fat_entry_size;
let entry_offset_in_sector = entry_offset % 512;
// needs two incase we "straddle a sector"
let sector_data = self
.drive
.partition
.read(self.fat_start + entry_offset as u64 / 512, 2)
.expect("Failed to read from FAT!");
@@ -487,7 +496,7 @@ impl<'a> FatFs<'a> {
[entry_offset_in_sector..entry_offset_in_sector + 2]
.try_into()
.unwrap();
return (u16::from_le_bytes(cluster_entry_bytes) & 0xFFFF) as u32;
return (u16::from_le_bytes(cluster_entry_bytes)) as u32;
}
FatType::Fat32(_) => {
let cluster_entry_bytes: [u8; 4] = sector_data
@@ -501,10 +510,22 @@ impl<'a> FatFs<'a> {
}
}
impl<'a> VfsFileSystem for FatFs<'a> {
fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> {
let path_componenets: Vec<&str> = path.trim_start_matches('/').split('/').collect();
let mut current_cluster = match self.fat_type {
impl FsOps for FatFs {
fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const super::vfs::Vfs) {
// TODO: load the FAT into memory here
*data = core::ptr::addr_of!(*self) as *mut u8;
// *data = unsafe { alloc::alloc::alloc(alloc::alloc::Layout::new::<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,
_ => self.sector_to_cluster(
self.bpb.reserved_sectors as usize
@@ -512,101 +533,383 @@ impl<'a> VfsFileSystem for FatFs<'a> {
),
};
for path in path_componenets {
let file_entry: FileEntry = self.find_entry_in_directory(current_cluster, path)?;
let file = File::Dir(FatDirectory {
directory_cluster: root_cluster,
// fat_fs: self,
});
if file_entry.attributes == FileEntryAttributes::Directory as u8 {
current_cluster = (((file_entry.high_first_cluster_number as u32) << 16)
| file_entry.low_first_cluster_number as u32)
as usize;
} else {
return Ok(Box::new(FatFile {
fat_fs: self,
file_entry,
}));
}
}
return Err(());
return super::vfs::VNode {
flags: 0,
ref_count: 0,
shared_lock_count: 0,
exclusive_lock_count: 0,
vfs_mounted_here: None,
ops: Box::new(file),
node_data: None,
parent: vfsp,
typ: super::vfs::VNodeType::Directory,
data: core::ptr::null_mut(),
};
}
fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()> {
unimplemented!();
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 {
crate::drivers::fs::vfs::VNodeType::Regular
};
let file = if file_entry.attributes == FileEntryAttributes::Directory as u8 {
File::Dir(FatDirectory {
directory_cluster: file_entry.cluster() as usize,
})
} else {
File::Archive(FatFile { file_entry })
};
let vnode = VNode {
flags: 0,
ref_count: 0,
shared_lock_count: 0,
exclusive_lock_count: 0,
vfs_mounted_here: None,
ops: Box::new(file),
node_data: None,
parent: (*vp).parent,
typ: file_typ,
data: core::ptr::null_mut(),
};
Ok(vnode)
},
_ => panic!("tried to lookup on a file"),
}
}
fn mkdir(
&self,
nm: &str,
va: super::vfs::VAttr,
c: super::vfs::UserCred,
vp: *const VNode,
) -> Result<super::vfs::VNode, ()> {
todo!("VNODE OPERATIONS");
}
fn open(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) -> Result<Arc<[u8]>, ()> {
match self {
File::Archive(archive) => {
let fat_fs = unsafe { (*(*vp).parent).data.cast::<FatFs>() };
let mut file: Vec<u8> = Vec::with_capacity(archive.file_entry.file_size as usize);
let mut file_ptr_index = 0;
let mut cluster = ((archive.file_entry.high_first_cluster_number as u32) << 16)
| archive.file_entry.low_first_cluster_number as u32;
let cluster_size = unsafe { (*fat_fs).cluster_size };
let mut copied_bytes = 0;
loop {
let cluster_data = unsafe { (*fat_fs).read_cluster(cluster as usize)? };
let remaining = archive.file_entry.file_size as usize - copied_bytes;
let to_copy = if remaining > cluster_size {
cluster_size
} else {
remaining
};
unsafe {
core::ptr::copy_nonoverlapping(
cluster_data.as_ptr(),
file.as_mut_ptr().add(file_ptr_index),
to_copy,
);
file.set_len(file.len() + to_copy);
}
file_ptr_index += cluster_size;
copied_bytes += to_copy;
cluster = unsafe { (*fat_fs).get_next_cluster(cluster as usize) };
match unsafe { (*fat_fs).fat_type } {
FatType::Fat12(_) => {
if cluster >= EOC_12 {
break;
}
}
FatType::Fat16(_) => {
if cluster >= EOC_16 {
break;
}
}
FatType::Fat32(_) => {
if cluster >= EOC_32 {
break;
}
}
}
}
return Ok(Arc::from(file));
}
_ => panic!("Cannot open non archives"),
}
todo!("VNODE OPERATIONS");
}
fn rdwr(
&self,
uiop: *const super::vfs::UIO,
direction: super::vfs::IODirection,
f: u32,
c: super::vfs::UserCred,
vp: *const VNode,
) {
todo!("VNODE OPERATIONS");
}
fn readdir(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) {
todo!("VNODE OPERATIONS");
}
fn readlink(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) {
todo!("VNODE OPERATIONS");
}
fn rename(
&self,
nm: &str,
target_dir: *mut super::vfs::VNode,
target_name: &str,
c: super::vfs::UserCred,
vp: *const VNode,
) {
todo!("VNODE OPERATIONS");
}
fn select(&self, w: super::vfs::IODirection, c: super::vfs::UserCred, vp: *const VNode) {
todo!("VNODE OPERATIONS");
}
fn setattr(&self, va: super::vfs::VAttr, c: super::vfs::UserCred, vp: *const VNode) {
todo!("VNODE OPERATIONS");
}
fn strategy(&self, bp: (), vp: *const VNode) {
todo!("VNODE OPERATIONS");
}
fn symlink(
&self,
link_name: &str,
va: super::vfs::VAttr,
target_name: &str,
c: super::vfs::UserCred,
vp: *const VNode,
) {
todo!("VNODE OPERATIONS");
}
}
struct FatFile<'a> {
fat_fs: &'a FatFs<'a>,
struct FatFile {
// fat_fs: &'a FatFs,
file_entry: FileEntry,
}
impl<'a> VfsFile for FatFile<'a> {
fn read(&self) -> Result<Arc<[u8]>, ()> {
let mut file: Vec<u8> = Vec::with_capacity(self.file_entry.file_size as usize);
let mut file_ptr_index = 0;
// impl<'a> VfsFile for FatFile<'a> {
// fn read(&self) -> Result<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 cluster = ((self.file_entry.high_first_cluster_number as u32) << 16)
// | self.file_entry.low_first_cluster_number as u32;
// let cluster_size = self.fat_fs.cluster_size;
let mut copied_bytes = 0;
// let mut copied_bytes = 0;
loop {
let cluster_data = self.fat_fs.read_cluster(cluster as usize)?;
// loop {
// let cluster_data = self.fat_fs.read_cluster(cluster as usize)?;
let remaining = self.file_entry.file_size as usize - copied_bytes;
let to_copy = if remaining > cluster_size {
cluster_size
} else {
remaining
};
// let remaining = self.file_entry.file_size as usize - copied_bytes;
// let to_copy = if remaining > cluster_size {
// cluster_size
// } else {
// remaining
// };
unsafe {
core::ptr::copy_nonoverlapping(
cluster_data.as_ptr(),
file.as_mut_ptr().add(file_ptr_index),
to_copy,
);
// unsafe {
// core::ptr::copy_nonoverlapping(
// cluster_data.as_ptr(),
// file.as_mut_ptr().add(file_ptr_index),
// to_copy,
// );
file.set_len(file.len() + to_copy);
}
// file.set_len(file.len() + to_copy);
// }
file_ptr_index += cluster_size;
// file_ptr_index += cluster_size;
copied_bytes += to_copy;
// copied_bytes += to_copy;
cluster = self.fat_fs.get_next_cluster(cluster as usize);
// cluster = self.fat_fs.get_next_cluster(cluster as usize);
match self.fat_fs.fat_type {
FatType::Fat12(_) => {
if cluster >= EOC_12 {
break;
}
}
FatType::Fat16(_) => {
if cluster >= EOC_16 {
break;
}
}
FatType::Fat32(_) => {
if cluster >= EOC_32 {
break;
}
}
}
}
// match self.fat_fs.fat_type {
// FatType::Fat12(_) => {
// if cluster >= EOC_12 {
// break;
// }
// }
// FatType::Fat16(_) => {
// if cluster >= EOC_16 {
// break;
// }
// }
// FatType::Fat32(_) => {
// if cluster >= EOC_32 {
// break;
// }
// }
// }
// }
return Ok(Arc::from(file));
}
}
// return Ok(Arc::from(file));
// }
// }
struct FatDirectory<'a> {
fat_fs: &'a FatFs<'a>,
struct FatDirectory {
// fat_fs: &'a FatFs,
directory_cluster: usize,
}
impl<'a> VfsDirectory for FatDirectory<'a> {
fn list_files(&self) -> Result<Arc<[Box<dyn VfsFile>]>, ()> {
unimplemented!();
}
}
// impl<'a> VfsDirectory for FatDirectory<'a> {
// fn list_files(&self) -> Result<Arc<[Box<dyn VfsFile>]>, ()> {
// unimplemented!();
// }
// }

View File

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

View File

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

View File

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

View File

@@ -1,50 +1,357 @@
use alloc::{
boxed::Box,
string::{String, ToString},
sync::Arc,
vec::Vec,
};
// use alloc::{
// boxed::Box,
// string::{String, ToString},
// sync::Arc,
// vec::Vec,
// };
use crate::libs::mutex::Mutex;
// use crate::{drivers::pci::PCI_DEVICES, libs::sync::Mutex};
pub trait VfsFileSystem {
fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()>;
fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()>;
}
// pub trait VfsFileSystem {
// fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()>;
// fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()>;
// }
pub trait VfsFile {
fn read(&self) -> Result<Arc<[u8]>, ()>;
}
// pub trait VfsFile {
// fn read(&self) -> Result<Arc<[u8]>, ()>;
// }
pub trait VfsDirectory {
fn list_files(&self) -> Result<Arc<[Box<dyn VfsFile>]>, ()>;
}
// pub trait VfsDirectory {
// 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 {
identifier: String,
file_system: Box<dyn VfsFileSystem>,
next: Option<*mut Vfs>,
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 {
pub fn new(file_system: Box<dyn VfsFileSystem>, identifier: &str) -> Self {
return Self {
identifier: identifier.to_string(),
file_system,
const fn null() -> Self {
return Vfs {
next: None,
ops: None,
vnode_covered: None,
flags: 0,
block_size: 0,
data: core::ptr::null_mut(),
};
}
pub fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> {
return self.file_system.open(path);
fn as_ptr(&self) -> *const Vfs {
core::ptr::addr_of!(*self)
}
pub fn read_dir(&self, path: &str) -> Result<Box<dyn VfsDirectory>, ()> {
return self.file_system.read_dir(path);
fn as_mut_ptr(&mut self) -> *mut Vfs {
core::ptr::addr_of_mut!(*self)
}
}
pub fn init() {
// TODO: Deduce which storage medium(s) we're using
crate::drivers::storage::ide::init();
pub trait FsOps {
// yes, the vfsp was the best solution I could come up with
fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const Vfs);
fn unmount(&self, vfsp: *const Vfs);
fn root(&self, vfsp: *const Vfs) -> VNode;
fn statfs(&self, vfsp: *const Vfs) -> StatFs;
fn sync(&self, vfsp: *const Vfs);
fn fid(&self, path: &str, vfsp: *const Vfs) -> Option<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"))]
pub extern "x86-interrupt" fn keyboard_interrupt_handler() {
interrupts::signal_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
use crate::drivers::serial::write_serial;
interrupts::signal_end_of_interrupt();
let scancode = inb(KBD_DATA_PORT);
let key = parse_key(scancode);
if let Some(key) = key {
crate::usr::shell::handle_key(key)
// crate::usr::shell::handle_key(key)
write_serial(key.character.unwrap() as u8);
}
}

View File

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

View File

@@ -2,7 +2,7 @@ use alloc::vec::Vec;
use crate::{
arch::io::{inl, outl},
libs::mutex::Mutex,
libs::sync::Mutex,
};
const PCI_CONFIG_PORT: u16 = 0xCF8; // The base I/O port for PCI configuration access
@@ -77,6 +77,7 @@ pub fn _get_pci_bar_addresses(bus: u8, device: u8, func: u8) -> (u32, u32, u32,
(bar0, bar1, bar2, bar3, bar4, bar5)
}
#[derive(Debug)]
pub struct PciDevice {
pub bus: u8,
pub device: u8,
@@ -130,7 +131,7 @@ pub fn enumerate_pci_bus() {
}
crate::println!("====== PCI DEVICES ======");
for (i, pci_device) in PCI_DEVICES.lock().read().iter().enumerate() {
for (i, pci_device) in PCI_DEVICES.lock().iter().enumerate() {
crate::println!("Entry {i:2}: {pci_device}")
}
}
@@ -165,10 +166,7 @@ fn check_device(bus: u8, device: u8) {
}
fn check_function(bus: u8, device: u8, func: u8) {
PCI_DEVICES
.lock()
.write()
.push(PciDevice::new(bus, device, func));
PCI_DEVICES.lock().push(PciDevice::new(bus, device, func));
let _secondary_bus: u8;

View File

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

View File

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

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)]
pub struct MBRPartition {
pub boot_indicator: u8,
@@ -126,7 +164,7 @@ impl GPTHeader {
let first_usable_block = u64::from_le_bytes(data[0x28..0x30].try_into().unwrap());
let last_usable_block = u64::from_le_bytes(data[0x30..0x38].try_into().unwrap());
let guid_bytes: [u8; 16] = data[0x38..0x48].try_into().unwrap();
let guid = guid_bytes.try_into().unwrap();
let guid = guid_bytes.into();
let guid_lba = u64::from_le_bytes(data[0x48..0x50].try_into().unwrap());
let partition_entry_count = u32::from_le_bytes(data[0x50..0x54].try_into().unwrap());
let partition_entry_size = u32::from_le_bytes(data[0x54..0x58].try_into().unwrap());

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 lazy;
pub mod logging;
pub mod math;
pub mod mutex;
pub mod oncecell;
pub mod util;
pub mod cell;
pub mod sync;
pub mod uuid;

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 {
fn eq(&self, other: &&str) -> bool {
let parts = other.split("-").collect::<Vec<&str>>();
let parts = other.split('-').collect::<Vec<&str>>();
if parts.len() != 5 {
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_main]
extern crate alloc;
mod arch;
mod drivers;
mod libs;
mod mem;
mod usr;
use core::ffi::CStr;
use alloc::{format, vec::Vec};
use drivers::serial;
use libs::util::hcf;
use drivers::serial::{read_serial, write_serial};
use limine::KernelFileRequest;
use crate::{drivers::serial::write_serial, mem::LabelBytes};
use crate::drivers::fs::vfs::{vfs_open, UserCred};
extern crate alloc;
pub mod arch;
pub mod drivers;
pub mod libs;
pub mod mem;
pub static KERNEL_REQUEST: KernelFileRequest = KernelFileRequest::new(0);
@@ -26,36 +28,100 @@ pub extern "C" fn _start() -> ! {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
arch::interrupts::init();
serial::init_serial();
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
drivers::acpi::init_acpi();
mem::log_info();
drivers::serial::init_serial();
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
drivers::pci::enumerate_pci_bus();
drivers::fs::vfs::init();
drivers::storage::ide::init();
// crate::println!("{:?}", INITRAMFS.open("/font.psf").unwrap().read());
if let Some(kernel) = KERNEL_REQUEST.get_response().get() {
crate::println!("{:X?}", kernel.kernel_file.get().unwrap().gpt_disk_uuid);
}
crate::println!("{:?}", vfs_open("/example.txt"));
let file = vfs_open("/example.txt").unwrap();
crate::println!(
"Total memory: {}",
crate::mem::PHYSICAL_MEMORY_MANAGER
.total_memory()
.label_bytes()
"{:X?}",
file.ops.open(0, UserCred { uid: 0, gid: 0 }, file.as_ptr())
);
usr::shell::init_shell();
let fb = drivers::video::get_framebuffer().unwrap();
let length = (fb.height * fb.width) * (fb.bpp / 8);
let pages = length / crate::mem::pmm::PAGE_SIZE;
let buffer = unsafe {
core::slice::from_raw_parts_mut(
crate::mem::PHYSICAL_MEMORY_MANAGER
.alloc(pages)
.expect("Could not allocate color buffer") as *mut u32,
length,
)
};
for y in 0..fb.height {
let r = ((y as f32) / ((fb.height - 1) as f32)) * 200.0;
for x in 0..fb.width {
let g = ((x as f32) / ((fb.width - 1) as f32)) * 200.0;
buffer[y * fb.width + x] = ((r as u32) << 16) | ((g as u32) << 8) | 175;
}
}
fb.blit_screen(buffer, None);
loop {
let ch = read_serial();
if ch == b'\x00' {
continue;
}
if ch == b'\x08' {
write_serial(b'\x08');
write_serial(b' ');
write_serial(b'\x08');
}
if ch > 0x20 && ch < 0x7F {
write_serial(ch);
}
}
hcf();
}
#[macro_export]
macro_rules! println {
() => ($crate::print!("\n"));
($($arg:tt)*) => ($crate::print!("{}\n", &alloc::format!($($arg)*)));
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => (
$crate::drivers::serial::write_string(&alloc::format!($($arg)*).replace('\n', "\n\r"))
)
}
#[macro_export]
macro_rules! log_info {
($($arg:tt)*) => ($crate::println!("\x1B[97m[ \x1B[90m? \x1B[97m]\x1B[0m () {}", &alloc::format!($($arg)*)));
}
#[macro_export]
macro_rules! log_serial {
($($arg:tt)*) => (
$crate::drivers::serial::write_string(&alloc::format!($($arg)*).replace('\n', "\n\r"))
);
}
#[macro_export]
macro_rules! log_error {
($($arg:tt)*) => ($crate::println!("\x1B[97m[ \x1B[91m! \x1B[97m]\x1B[0m {}", &alloc::format!($($arg)*)));
}
#[macro_export]
macro_rules! log_ok {
($($arg:tt)*) => ($crate::println!("\x1B[97m[ \x1B[92m* \x1B[97m]\x1B[0;m {}", &alloc::format!($($arg)*)));
}
#[derive(Debug)]
pub struct KernelFeatures {
pub fat_in_mem: bool,
@@ -71,8 +137,8 @@ impl KernelFeatures {
}
}
pub static KERNEL_FEATURES: libs::lazy::Lazy<KernelFeatures> =
libs::lazy::Lazy::new(parse_kernel_cmdline);
pub static KERNEL_FEATURES: libs::cell::LazyCell<KernelFeatures> =
libs::cell::LazyCell::new(parse_kernel_cmdline);
fn parse_kernel_cmdline() -> KernelFeatures {
let mut kernel_features: KernelFeatures = KernelFeatures { fat_in_mem: true };
@@ -118,13 +184,9 @@ fn parse_kernel_cmdline() -> KernelFeatures {
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
let message = format!("{}\n", info);
let msg = &format!("{info}\n").replace('\n', "\n\r");
for ch in message.chars() {
write_serial(ch);
}
log_error!("{}", info);
drivers::serial::write_string(msg);
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
@@ -137,3 +199,15 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
hcf();
}
pub fn hcf() -> ! {
loop {
unsafe {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
core::arch::asm!("hlt");
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
core::arch::asm!("wfi");
}
}
}

View File

@@ -1,6 +1,6 @@
// Original code from: https://github.com/DrChat/buddyalloc/blob/master/src/heap.rs
// But I made it ~~much worse~~ *better* by making it GlobalAlloc compatible
// By using A custom Mutex implementation (which also sucks) and dereferencing all the pointers,
// By using A custom Mutex implementation (which also sucks),
// I was able to remove all the mut's In the original code.
// TODO: Replace this with a slab allocator that can take advantage of the page frame allocator
@@ -11,7 +11,7 @@ use core::ptr;
use core::sync::atomic::Ordering::SeqCst;
use core::sync::atomic::{AtomicPtr, AtomicU8, AtomicUsize};
use crate::libs::mutex::Mutex;
use crate::libs::sync::Mutex;
const fn log2(num: usize) -> u8 {
let mut temp = num;
@@ -107,33 +107,36 @@ impl BuddyAllocator {
}
fn free_list_pop(&self, order: usize) -> Option<*mut u8> {
let candidate = (*self.free_lists.lock().read())[order];
let mut free_lists_lock = self.free_lists.lock();
let candidate = (*free_lists_lock)[order];
if candidate.is_null() {
return None;
}
if order != self.free_lists.lock().read().len() - 1 {
(*self.free_lists.lock().write())[order] = unsafe { (*candidate).next };
if order != free_lists_lock.len() - 1 {
(*free_lists_lock)[order] = unsafe { (*candidate).next };
} else {
(*self.free_lists.lock().write())[order] = ptr::null_mut();
(*free_lists_lock)[order] = ptr::null_mut();
}
return Some(candidate as *mut u8);
}
fn free_list_insert(&self, order: usize, block: *mut u8) {
let mut free_lists_lock = self.free_lists.lock();
let free_block_ptr = block as *mut FreeBlock;
unsafe { *free_block_ptr = FreeBlock::new((*self.free_lists.lock().read())[order]) };
unsafe { *free_block_ptr = FreeBlock::new((*free_lists_lock)[order]) };
(*self.free_lists.lock().write())[order] = free_block_ptr;
(*free_lists_lock)[order] = free_block_ptr;
}
fn free_list_remove(&self, order: usize, block: *mut u8) -> bool {
let block_ptr = block as *mut FreeBlock;
let mut checking: &mut *mut FreeBlock = &mut (*self.free_lists.lock().write())[order];
let mut checking: &mut *mut FreeBlock = &mut (*self.free_lists.lock())[order];
unsafe {
while !(*checking).is_null() {
@@ -177,11 +180,12 @@ impl BuddyAllocator {
}
pub fn get_free_mem(&self) -> usize {
let free_lists_lock = self.free_lists.lock();
let mut free_mem = 0;
unsafe {
for order in 0..self.free_lists.lock().read().len() {
let mut block = (*self.free_lists.lock().write())[order];
for order in 0..free_lists_lock.len() {
let mut block = (*free_lists_lock)[order];
while !block.is_null() {
free_mem += self.order_size(order);
@@ -201,7 +205,9 @@ impl BuddyAllocator {
unsafe impl GlobalAlloc for BuddyAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if let Some(order_needed) = self.allocation_order(layout.size(), layout.align()) {
for order in order_needed..self.free_lists.lock().read().len() {
let free_lists_len = { self.free_lists.lock().len() };
for order in order_needed..free_lists_len {
if let Some(block) = self.free_list_pop(order) {
if order > order_needed {
self.split_free_block(block, order, order_needed);
@@ -221,7 +227,9 @@ unsafe impl GlobalAlloc for BuddyAllocator {
.expect("Tried to dispose of invalid block");
let mut block = ptr;
for order in initial_order..self.free_lists.lock().read().len() {
let free_lists_len = { self.free_lists.lock().len() };
for order in initial_order..free_lists_len {
if let Some(buddy) = self.buddy(order, block) {
if self.free_list_remove(order, block) {
block = min(block, buddy);
@@ -234,3 +242,33 @@ unsafe impl GlobalAlloc for BuddyAllocator {
}
}
}
#[no_mangle]
pub extern "C" fn malloc(size: usize) -> *mut u8 {
let layout = alloc::alloc::Layout::from_size_align(size, 2);
if layout.is_err() {
return core::ptr::null_mut();
}
unsafe {
return alloc::alloc::alloc(layout.unwrap());
};
}
#[no_mangle]
pub extern "C" fn free(ptr: *mut u8, size: usize) {
if ptr.is_null() {
return;
}
let layout = alloc::alloc::Layout::from_size_align(size, 2);
if layout.is_err() {
return;
}
unsafe {
alloc::alloc::dealloc(ptr, layout.unwrap());
};
}

View File

@@ -5,17 +5,14 @@ use core::alloc::GlobalAlloc;
use limine::{MemmapEntry, NonNullPtr};
use crate::{
libs::{lazy::Lazy, mutex::Mutex},
usr::tty::CONSOLE,
};
use crate::libs::{cell::LazyCell, sync::Mutex};
use self::{allocator::BuddyAllocator, pmm::PhysicalMemoryManager};
static MEMMAP_REQUEST: limine::MemmapRequest = limine::MemmapRequest::new(0);
static HHDM_REQUEST: limine::HhdmRequest = limine::HhdmRequest::new(0);
pub static MEMMAP: Lazy<Mutex<&mut [NonNullPtr<MemmapEntry>]>> = Lazy::new(|| {
pub static MEMMAP: LazyCell<Mutex<&mut [NonNullPtr<MemmapEntry>]>> = LazyCell::new(|| {
let memmap_request = MEMMAP_REQUEST
.get_response()
.get_mut()
@@ -24,7 +21,7 @@ pub static MEMMAP: Lazy<Mutex<&mut [NonNullPtr<MemmapEntry>]>> = Lazy::new(|| {
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
.get_response()
.get()
@@ -33,37 +30,11 @@ pub static HHDM_OFFSET: Lazy<usize> = Lazy::new(|| {
return hhdm.offset as usize;
});
pub static PHYSICAL_MEMORY_MANAGER: Lazy<PhysicalMemoryManager> =
Lazy::new(PhysicalMemoryManager::new);
pub static PHYSICAL_MEMORY_MANAGER: LazyCell<PhysicalMemoryManager> =
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 inner: Lazy<BuddyAllocator>,
pub inner: LazyCell<BuddyAllocator>,
}
unsafe impl GlobalAlloc for Allocator {
@@ -81,7 +52,7 @@ const HEAP_SIZE: usize = HEAP_PAGES * 1024;
#[global_allocator]
pub static ALLOCATOR: Allocator = Allocator {
inner: Lazy::new(|| {
inner: LazyCell::new(|| {
let heap_start = PHYSICAL_MEMORY_MANAGER
.alloc(HEAP_PAGES)
.expect("Failed to allocate heap!");
@@ -90,45 +61,6 @@ pub static ALLOCATOR: Allocator = Allocator {
}),
};
#[no_mangle]
pub extern "C" fn malloc(size: usize) -> *mut u8 {
let layout = core::alloc::Layout::from_size_align(size, 1).unwrap();
unsafe { ALLOCATOR.alloc(layout) }
}
#[no_mangle]
pub extern "C" fn free(ptr: *mut u8, size: usize) {
let layout = core::alloc::Layout::from_size_align(size, 1).unwrap();
unsafe {
ALLOCATOR.dealloc(ptr, layout);
}
}
pub fn log_info() {
crate::log_info!(
"Initialized heap with {} of memory at {:#X}",
HEAP_SIZE.label_bytes(),
ALLOCATOR
.inner
.heap_start
.load(core::sync::atomic::Ordering::SeqCst) as usize
);
if CONSOLE.get_features().doubled_buffered {
let row_size = CONSOLE.second_buffer.lock().read().unwrap().pitch
/ (CONSOLE.second_buffer.lock().read().unwrap().bpp / 8);
let screen_size = row_size * CONSOLE.second_buffer.lock().read().unwrap().height;
crate::log_info!(
"Initialized framebuffer mirroring with {} at {:#X}",
(screen_size * 4).label_bytes(),
CONSOLE.second_buffer.lock().read().unwrap().pointer as usize
);
}
log_memory_map();
}
pub fn log_memory_map() {
let memmap_request = MEMMAP_REQUEST.get_response().get_mut();
if memmap_request.is_none() {
@@ -137,12 +69,12 @@ pub fn log_memory_map() {
let memmap = memmap_request.unwrap().memmap();
crate::log_serial!("====== MEMORY MAP ======");
crate::log_serial!("====== MEMORY MAP ======\n");
for entry in memmap.iter() {
let label = (entry.len as usize).label_bytes();
crate::log_serial!(
"[ {:#018X?} ] Type: {:?} Size: {}",
"[ {:#018X?} ] Type: {:?} Size: {}\n",
entry.base..entry.base + entry.len,
entry.typ,
label
@@ -195,3 +127,29 @@ impl LabelBytes for usize {
}
}
}
/// # Safety
/// This will produce undefined behavior if dst is not valid for count writes
pub unsafe fn memset32(dst: *mut u32, val: u32, count: usize) {
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
{
let mut buf = dst;
unsafe {
while buf < dst.add(count) {
core::ptr::write_volatile(buf, val);
buf = buf.offset(1);
}
}
return;
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
core::arch::asm!(
"rep stosd",
inout("ecx") count => _,
inout("edi") dst => _,
inout("eax") val => _
);
}
}

View File

@@ -27,7 +27,7 @@ impl PhysicalMemoryManager {
let mut highest_addr: usize = 0;
for entry in super::MEMMAP.lock().read().iter() {
for entry in super::MEMMAP.lock().iter() {
if entry.typ == limine::MemoryMapEntryType::Usable {
pmm.usable_pages
.fetch_add(entry.len as usize / PAGE_SIZE, Ordering::SeqCst);
@@ -42,7 +42,7 @@ impl PhysicalMemoryManager {
let bitmap_size =
((pmm.highest_page_idx.load(Ordering::SeqCst) / 8) + PAGE_SIZE - 1) & !(PAGE_SIZE - 1);
for entry in super::MEMMAP.lock().write().iter_mut() {
for entry in super::MEMMAP.lock().iter_mut() {
if entry.typ != limine::MemoryMapEntryType::Usable {
continue;
}
@@ -63,7 +63,7 @@ impl PhysicalMemoryManager {
}
}
for entry in super::MEMMAP.lock().read().iter() {
for entry in super::MEMMAP.lock().iter() {
if entry.typ != limine::MemoryMapEntryType::Usable {
continue;
}

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