diff --git a/Makefile b/Makefile index 3eb6bff..653577f 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ ARCH ?= x86_64 MEMORY ?= 512M QEMU_OPTS ?= MKSQUASHFS_OPTS ?= +GDB ?= ISO_PATH = ${ARTIFACTS_PATH}/iso_root INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs @@ -16,7 +17,9 @@ LIMINE_BOOT_VARIATION = X64 ifeq (${MODE},release) CARGO_OPTS += --release -else +endif + +ifneq (${GDB},) QEMU_OPTS += -s -S endif diff --git a/src/arch/x86_common/io.rs b/src/arch/x86_common/io.rs index fff91b3..0e12fdd 100644 --- a/src/arch/x86_common/io.rs +++ b/src/arch/x86_common/io.rs @@ -37,7 +37,6 @@ pub fn outw(port: u16, value: u16) { options(preserves_flags, nomem, nostack) ); } - return; } #[inline(always)] @@ -82,7 +81,7 @@ pub unsafe fn outsw(port: u16, buffer: *mut u16, count: usize) { asm!("cld", "rep outsw", in("dx") port, - inout("rdi") buffer => _, + inout("rsi") buffer => _, inout("rcx") count => _ ); } @@ -98,7 +97,6 @@ pub fn outl(port: u16, value: u32) { options(preserves_flags, nomem, nostack) ); } - return; } #[inline(always)] diff --git a/src/arch/x86_common/stack_trace.rs b/src/arch/x86_common/stack_trace.rs index af13fc4..f8caf33 100644 --- a/src/arch/x86_common/stack_trace.rs +++ b/src/arch/x86_common/stack_trace.rs @@ -1,6 +1,6 @@ -use alloc::{borrow::ToOwned, string::String, vec::Vec}; +use alloc::{borrow::ToOwned, format, string::String, vec::Vec}; -use crate::drivers::fs::vfs::VfsFileSystem; +use crate::drivers::{fs::vfs::VfsFileSystem, serial::write_serial}; #[repr(C)] #[derive(Clone, Copy, Debug)] @@ -20,8 +20,6 @@ pub fn print_stack_trace(max_frames: usize, rbp: u64) { let instruction_pointer = unsafe { (*stackframe).rip }; - crate::print!(" {:#X} ", instruction_pointer); - let instrcution_info = get_function_name(instruction_pointer); if let Ok((function_name, function_offset)) = instrcution_info { diff --git a/src/drivers/fs/initramfs/compressors/gzip.rs b/src/drivers/fs/initramfs/compressors/gzip.rs index 6991c6a..9f5c7ba 100644 --- a/src/drivers/fs/initramfs/compressors/gzip.rs +++ b/src/drivers/fs/initramfs/compressors/gzip.rs @@ -145,6 +145,9 @@ impl InflateContext { }; } + // read from right-to-left NOT, and I cannot stress this enough, left-to-right + // probably because it's way simpler computationally to get the right-most bit, + // but still, wasted weeks on this because I read it from left-to-right ;~; pub fn get_bit(&mut self) -> bool { if self.bit_index == 8 { self.input_buf.remove(0); diff --git a/src/drivers/fs/initramfs/mod.rs b/src/drivers/fs/initramfs/mod.rs index f205622..5beea59 100755 --- a/src/drivers/fs/initramfs/mod.rs +++ b/src/drivers/fs/initramfs/mod.rs @@ -2,12 +2,12 @@ pub mod compressors; use core::fmt::{self, Debug}; -use alloc::{boxed::Box, fmt::format, format, sync::Arc, vec::Vec}; +use alloc::{boxed::Box, sync::Arc, vec::Vec}; use limine::ModuleRequest; -use crate::{ - drivers::serial::write_serial, - libs::{lazy::Lazy, math::ceil}, +use crate::libs::{ + lazy::Lazy, + math::{ceil, floor}, }; use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem}; @@ -62,6 +62,7 @@ fn init() -> Squashfs<'static> { #[derive(Debug)] pub struct Squashfs<'a> { superblock: SquashfsSuperblock, + start: *mut u8, data_table: &'a [u8], inode_table: &'a [u8], directory_table: &'a [u8], @@ -163,6 +164,7 @@ impl Squashfs<'_> { return Ok(Squashfs { superblock, + start: ptr, data_table, inode_table, directory_table, @@ -396,14 +398,14 @@ impl<'a> BasicDirectoryInode<'a> { let mut offset = self.block_offset as usize + core::mem::size_of::(); for _ in 0..directory_table_header.entry_count as usize { - let directroy_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]); + let directory_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]); - offset += 8 + directroy_table_entry.name.len(); + offset += 8 + directory_table_entry.name.len(); let file_inode = self .header .squashfs - .read_inode(directroy_table_entry.offset as u32); + .read_inode(directory_table_entry.offset as u32); entries.push(file_inode); } @@ -424,15 +426,15 @@ impl<'a> BasicDirectoryInode<'a> { let mut offset = self.block_offset as usize + core::mem::size_of::(); for _ in 0..directory_table_header.entry_count as usize { - let directroy_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]); + let directory_table_entry = DirectoryTableEntry::from_bytes(&directory_table[offset..]); - offset += 8 + directroy_table_entry.name.len(); + offset += 8 + directory_table_entry.name.len(); - if directroy_table_entry.name == name { + if directory_table_entry.name == name { return Some( self.header .squashfs - .read_inode(directroy_table_entry.offset as u32), + .read_inode(directory_table_entry.offset as u32), ); } } @@ -449,6 +451,7 @@ struct BasicFileInode<'a> { frag_idx: u32, // 8 block_offset: u32, // 12 file_size: u32, // 16 + block_sizes: *const u32, } impl<'a> BasicFileInode<'a> { @@ -458,6 +461,7 @@ impl<'a> BasicFileInode<'a> { let frag_idx = u32::from_le_bytes(bytes[20..24].try_into().unwrap()); let block_offset = u32::from_le_bytes(bytes[24..28].try_into().unwrap()); let file_size = u32::from_le_bytes(bytes[28..32].try_into().unwrap()); + let block_sizes = bytes[32..].as_ptr() as *const u32; return Self { header, @@ -465,38 +469,101 @@ impl<'a> BasicFileInode<'a> { frag_idx, block_offset, file_size, + block_sizes, }; } } impl<'a> VfsFile for BasicFileInode<'a> { fn read(&self) -> Result, ()> { - // TODO: handle tail end packing (somehow?) - let block_count = - ceil(self.file_size as f64 / self.header.squashfs.superblock.block_size as f64) - as usize; - // TODO: is this really how you're supposed to do this? let mut block_data: Vec = Vec::with_capacity(self.file_size as usize); - let data_table = self.header.squashfs.get_decompressed_table( - self.header.squashfs.data_table, - ( - false, - Some( - !self - .header - .squashfs - .superblock - .features() - .uncompressed_data_blocks, - ), - ), - ); + let data_table: Vec; - block_data.extend( - &data_table[self.block_offset as usize..(self.block_offset + self.file_size) as usize], - ); + 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, + // ), + ), + ); + + 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; + + 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_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() + }; + + data_table = self + .header + .squashfs + .get_decompressed_table(&data_table_raw, (false, Some(fragment_compressed))); + + self.block_offset as usize + }; + + block_data.extend(&data_table[block_offset..(block_offset + self.file_size as usize)]); return Ok(Arc::from(block_data)); } diff --git a/src/drivers/serial.rs b/src/drivers/serial.rs index e3a69dd..ef07464 100644 --- a/src/drivers/serial.rs +++ b/src/drivers/serial.rs @@ -55,6 +55,9 @@ fn is_transmit_empty() -> bool { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn write_serial(character: char) { while is_transmit_empty() {} + if character == '\n' { + write_serial('\r'); + } outb(PORT, character as u8); } diff --git a/src/drivers/storage/ide.rs b/src/drivers/storage/ide.rs index 6cc5d39..b7ef3f7 100755 --- a/src/drivers/storage/ide.rs +++ b/src/drivers/storage/ide.rs @@ -1,7 +1,9 @@ +use core::mem::size_of; + use alloc::{boxed::Box, format, sync::Arc, vec::Vec}; use crate::{ - arch::io::{inb, inw, outb, outw}, + arch::io::{inb, insw, inw, outb, outsw}, drivers::{ fs::fat, storage::drive::{GPTBlock, GPTPartitionEntry}, @@ -294,7 +296,7 @@ impl ATABus { sector, sector_count, ATADriveDirection::Read, - (buffer.as_mut_ptr(), buffer.len()), + &mut buffer, )?; return Ok(Arc::from(buffer)); @@ -311,12 +313,14 @@ impl ATABus { return Err(()); } + let mut mut_buf: Vec = Vec::new(); + mut_buf.extend(buffer); self.ide_access( drive, sector, sector_count, ATADriveDirection::Write, - (buffer.as_ptr() as *mut u8, buffer.len()), + &mut mut_buf, )?; return Ok(()); @@ -328,10 +332,8 @@ impl ATABus { sector: u64, sector_count: usize, direction: ATADriveDirection, - buffer: (*mut u8, usize), + buffer: &mut [u8], ) -> Result<(), ()> { - let buffer = unsafe { core::slice::from_raw_parts_mut(buffer.0, buffer.1) }; - self.await_busy(); let using_lba48 = sector >= (1 << 28) - 1; @@ -411,29 +413,32 @@ impl ATABus { // Since this is an internal function, this should never fail assert!(buffer.len() >= array_size); - // Allocate memory for the array that stores the sector data let mut buffer_offset = 0; for _ in 0..sector_count { self.wait_for_drive_ready() .map_err(|_| crate::log_error!("Error reading IDE Device"))?; - for chunk in - buffer[buffer_offset..(buffer_offset + ATA_SECTOR_SIZE)].chunks_exact_mut(2) - { - match direction { - ATADriveDirection::Read => { - let word = - inw(self.io_bar + ATADriveDataRegister::Data as u16).to_le_bytes(); - chunk.copy_from_slice(&word); - } - ATADriveDirection::Write => { - let word = u16::from_le_bytes(chunk.try_into().unwrap()); - outw(self.io_bar + ATADriveDataRegister::Data as u16, word); - } - } + // # Safety + // + // We know that buffer is the exact size of count, so it will never panic:tm: + match direction { + ATADriveDirection::Read => unsafe { + insw( + self.io_bar + ATADriveDataRegister::Data as u16, + (buffer.as_mut_ptr() as *mut u16).add(buffer_offset), + ATA_SECTOR_SIZE / size_of::(), + ); + }, + ATADriveDirection::Write => unsafe { + outsw( + self.io_bar + ATADriveDataRegister::Data as u16, + (buffer.as_mut_ptr() as *mut u16).add(buffer_offset), + ATA_SECTOR_SIZE / size_of::(), + ) + }, } - buffer_offset += ATA_SECTOR_SIZE; + buffer_offset += ATA_SECTOR_SIZE / size_of::(); } return Ok(()); diff --git a/src/drivers/video/font.rs b/src/drivers/video/font.rs index bc43728..f2c834e 100755 --- a/src/drivers/video/font.rs +++ b/src/drivers/video/font.rs @@ -1,13 +1,11 @@ -use alloc::{format, vec::Vec}; +use alloc::vec::Vec; use crate::{ - drivers::{ - fs::{initramfs::INITRAMFS, vfs::VfsFileSystem}, - serial::write_serial, - }, + drivers::fs::{initramfs::INITRAMFS, vfs::VfsFileSystem}, libs::lazy::Lazy, }; +#[derive(Debug)] pub struct PSFFontHeader { pub magic: u32, pub length: u32, diff --git a/src/main.rs b/src/main.rs index bc46c62..333590a 100755 --- a/src/main.rs +++ b/src/main.rs @@ -12,15 +12,12 @@ mod usr; use core::ffi::CStr; -use alloc::vec::Vec; +use alloc::{format, vec::Vec}; use drivers::serial; use libs::util::hcf; use limine::KernelFileRequest; -use crate::{ - drivers::fs::{initramfs::INITRAMFS, vfs::VfsFileSystem}, - mem::LabelBytes, -}; +use crate::{drivers::serial::write_serial, mem::LabelBytes}; pub static KERNEL_REQUEST: KernelFileRequest = KernelFileRequest::new(0); @@ -120,7 +117,11 @@ fn parse_kernel_cmdline() -> KernelFeatures { #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { - crate::log_error!("{}", info); + let message = format!("{}", info); + + for ch in message.chars() { + write_serial(ch); + } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {