add proper vfs
This commit is contained in:
3
Makefile
3
Makefile
@@ -12,6 +12,7 @@ GDB ?=
|
||||
CPUS ?= 1
|
||||
# FAT type
|
||||
ESP_BITS ?= 32
|
||||
EXPORT_SYMBOLS = true
|
||||
|
||||
ISO_PATH = ${ARTIFACTS_PATH}/iso_root
|
||||
INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs
|
||||
@@ -84,6 +85,7 @@ compile-initramfs: copy-initramfs-files
|
||||
mksquashfs ${INITRAMFS_PATH} ${ARTIFACTS_PATH}/initramfs.img ${MKSQUASHFS_OPTS}
|
||||
|
||||
run-scripts:
|
||||
ifeq (${EXPORT_SYMBOLS},true)
|
||||
nm target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf > scripts/symbols.table
|
||||
@if [ ! -d "scripts/rustc_demangle" ]; then \
|
||||
echo "Cloning rustc_demangle.py into scripts/rustc_demangle/..."; \
|
||||
@@ -93,6 +95,7 @@ run-scripts:
|
||||
fi
|
||||
python scripts/demangle-symbols.py
|
||||
mv scripts/symbols.table ${INITRAMFS_PATH}/
|
||||
endif
|
||||
|
||||
python scripts/font.py
|
||||
mv scripts/font.psf ${INITRAMFS_PATH}/
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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!();
|
||||
}
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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!");
|
||||
}
|
||||
|
||||
|
||||
@@ -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!();
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod devfs;
|
||||
pub mod fat;
|
||||
pub mod initramfs;
|
||||
pub mod vfs;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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!")
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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> {}
|
||||
@@ -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)*)));
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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!")
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
148
src/main.rs
Executable file → Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
};
|
||||
}
|
||||
|
||||
112
src/mem/mod.rs
112
src/mem/mod.rs
@@ -5,17 +5,14 @@ use core::alloc::GlobalAlloc;
|
||||
|
||||
use limine::{MemmapEntry, NonNullPtr};
|
||||
|
||||
use crate::{
|
||||
libs::{lazy::Lazy, mutex::Mutex},
|
||||
usr::tty::CONSOLE,
|
||||
};
|
||||
use crate::libs::{cell::LazyCell, sync::Mutex};
|
||||
|
||||
use self::{allocator::BuddyAllocator, pmm::PhysicalMemoryManager};
|
||||
|
||||
static MEMMAP_REQUEST: limine::MemmapRequest = limine::MemmapRequest::new(0);
|
||||
static HHDM_REQUEST: limine::HhdmRequest = limine::HhdmRequest::new(0);
|
||||
|
||||
pub static MEMMAP: Lazy<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 => _
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
pub mod shell;
|
||||
#[macro_use]
|
||||
pub mod tty;
|
||||
282
src/usr/shell.rs
282
src/usr/shell.rs
@@ -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(),
|
||||
}
|
||||
}
|
||||
901
src/usr/tty.rs
901
src/usr/tty.rs
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user