squashfs fragment support + bug fixes

This commit is contained in:
Zoe
2023-12-20 01:50:17 -06:00
parent f03d29d1fa
commit 361cfc49fe
9 changed files with 150 additions and 74 deletions

View File

@@ -6,6 +6,7 @@ ARCH ?= x86_64
MEMORY ?= 512M MEMORY ?= 512M
QEMU_OPTS ?= QEMU_OPTS ?=
MKSQUASHFS_OPTS ?= MKSQUASHFS_OPTS ?=
GDB ?=
ISO_PATH = ${ARTIFACTS_PATH}/iso_root ISO_PATH = ${ARTIFACTS_PATH}/iso_root
INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs
@@ -16,7 +17,9 @@ LIMINE_BOOT_VARIATION = X64
ifeq (${MODE},release) ifeq (${MODE},release)
CARGO_OPTS += --release CARGO_OPTS += --release
else endif
ifneq (${GDB},)
QEMU_OPTS += -s -S QEMU_OPTS += -s -S
endif endif

View File

@@ -37,7 +37,6 @@ pub fn outw(port: u16, value: u16) {
options(preserves_flags, nomem, nostack) options(preserves_flags, nomem, nostack)
); );
} }
return;
} }
#[inline(always)] #[inline(always)]
@@ -82,7 +81,7 @@ pub unsafe fn outsw(port: u16, buffer: *mut u16, count: usize) {
asm!("cld", asm!("cld",
"rep outsw", "rep outsw",
in("dx") port, in("dx") port,
inout("rdi") buffer => _, inout("rsi") buffer => _,
inout("rcx") count => _ inout("rcx") count => _
); );
} }
@@ -98,7 +97,6 @@ pub fn outl(port: u16, value: u32) {
options(preserves_flags, nomem, nostack) options(preserves_flags, nomem, nostack)
); );
} }
return;
} }
#[inline(always)] #[inline(always)]

View File

@@ -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)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@@ -20,8 +20,6 @@ pub fn print_stack_trace(max_frames: usize, rbp: u64) {
let instruction_pointer = unsafe { (*stackframe).rip }; let instruction_pointer = unsafe { (*stackframe).rip };
crate::print!(" {:#X} ", instruction_pointer);
let instrcution_info = get_function_name(instruction_pointer); let instrcution_info = get_function_name(instruction_pointer);
if let Ok((function_name, function_offset)) = instrcution_info { if let Ok((function_name, function_offset)) = instrcution_info {

View File

@@ -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 { pub fn get_bit(&mut self) -> bool {
if self.bit_index == 8 { if self.bit_index == 8 {
self.input_buf.remove(0); self.input_buf.remove(0);

View File

@@ -2,12 +2,12 @@ pub mod compressors;
use core::fmt::{self, Debug}; 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 limine::ModuleRequest;
use crate::{ use crate::libs::{
drivers::serial::write_serial, lazy::Lazy,
libs::{lazy::Lazy, math::ceil}, math::{ceil, floor},
}; };
use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem}; use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem};
@@ -62,6 +62,7 @@ fn init() -> Squashfs<'static> {
#[derive(Debug)] #[derive(Debug)]
pub struct Squashfs<'a> { pub struct Squashfs<'a> {
superblock: SquashfsSuperblock, superblock: SquashfsSuperblock,
start: *mut u8,
data_table: &'a [u8], data_table: &'a [u8],
inode_table: &'a [u8], inode_table: &'a [u8],
directory_table: &'a [u8], directory_table: &'a [u8],
@@ -163,6 +164,7 @@ impl Squashfs<'_> {
return Ok(Squashfs { return Ok(Squashfs {
superblock, superblock,
start: ptr,
data_table, data_table,
inode_table, inode_table,
directory_table, directory_table,
@@ -396,14 +398,14 @@ impl<'a> BasicDirectoryInode<'a> {
let mut offset = self.block_offset as usize + core::mem::size_of::<DirectoryTableHeader>(); let mut offset = self.block_offset as usize + core::mem::size_of::<DirectoryTableHeader>();
for _ in 0..directory_table_header.entry_count as usize { for _ in 0..directory_table_header.entry_count as usize {
let 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 let file_inode = self
.header .header
.squashfs .squashfs
.read_inode(directroy_table_entry.offset as u32); .read_inode(directory_table_entry.offset as u32);
entries.push(file_inode); entries.push(file_inode);
} }
@@ -424,15 +426,15 @@ impl<'a> BasicDirectoryInode<'a> {
let mut offset = self.block_offset as usize + core::mem::size_of::<DirectoryTableHeader>(); let mut offset = self.block_offset as usize + core::mem::size_of::<DirectoryTableHeader>();
for _ in 0..directory_table_header.entry_count as usize { for _ in 0..directory_table_header.entry_count as usize {
let 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( return Some(
self.header self.header
.squashfs .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 frag_idx: u32, // 8
block_offset: u32, // 12 block_offset: u32, // 12
file_size: u32, // 16 file_size: u32, // 16
block_sizes: *const u32,
} }
impl<'a> BasicFileInode<'a> { 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 frag_idx = u32::from_le_bytes(bytes[20..24].try_into().unwrap());
let block_offset = u32::from_le_bytes(bytes[24..28].try_into().unwrap()); let block_offset = u32::from_le_bytes(bytes[24..28].try_into().unwrap());
let file_size = u32::from_le_bytes(bytes[28..32].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 { return Self {
header, header,
@@ -465,21 +469,20 @@ impl<'a> BasicFileInode<'a> {
frag_idx, frag_idx,
block_offset, block_offset,
file_size, file_size,
block_sizes,
}; };
} }
} }
impl<'a> VfsFile for BasicFileInode<'a> { impl<'a> VfsFile for BasicFileInode<'a> {
fn read(&self) -> Result<Arc<[u8]>, ()> { fn read(&self) -> Result<Arc<[u8]>, ()> {
// TODO: 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? // TODO: is this really how you're supposed to do this?
let mut block_data: Vec<u8> = Vec::with_capacity(self.file_size as usize); let mut block_data: Vec<u8> = Vec::with_capacity(self.file_size as usize);
let data_table = self.header.squashfs.get_decompressed_table( 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, self.header.squashfs.data_table,
( (
false, false,
@@ -494,10 +497,74 @@ impl<'a> VfsFile for BasicFileInode<'a> {
), ),
); );
block_data.extend( self.block_offset as usize
&data_table[self.block_offset as usize..(self.block_offset + self.file_size) 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)); return Ok(Arc::from(block_data));
} }
} }

View File

@@ -55,6 +55,9 @@ fn is_transmit_empty() -> bool {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn write_serial(character: char) { pub fn write_serial(character: char) {
while is_transmit_empty() {} while is_transmit_empty() {}
if character == '\n' {
write_serial('\r');
}
outb(PORT, character as u8); outb(PORT, character as u8);
} }

View File

@@ -1,7 +1,9 @@
use core::mem::size_of;
use alloc::{boxed::Box, format, sync::Arc, vec::Vec}; use alloc::{boxed::Box, format, sync::Arc, vec::Vec};
use crate::{ use crate::{
arch::io::{inb, inw, outb, outw}, arch::io::{inb, insw, inw, outb, outsw},
drivers::{ drivers::{
fs::fat, fs::fat,
storage::drive::{GPTBlock, GPTPartitionEntry}, storage::drive::{GPTBlock, GPTPartitionEntry},
@@ -294,7 +296,7 @@ impl ATABus {
sector, sector,
sector_count, sector_count,
ATADriveDirection::Read, ATADriveDirection::Read,
(buffer.as_mut_ptr(), buffer.len()), &mut buffer,
)?; )?;
return Ok(Arc::from(buffer)); return Ok(Arc::from(buffer));
@@ -311,12 +313,14 @@ impl ATABus {
return Err(()); return Err(());
} }
let mut mut_buf: Vec<u8> = Vec::new();
mut_buf.extend(buffer);
self.ide_access( self.ide_access(
drive, drive,
sector, sector,
sector_count, sector_count,
ATADriveDirection::Write, ATADriveDirection::Write,
(buffer.as_ptr() as *mut u8, buffer.len()), &mut mut_buf,
)?; )?;
return Ok(()); return Ok(());
@@ -328,10 +332,8 @@ impl ATABus {
sector: u64, sector: u64,
sector_count: usize, sector_count: usize,
direction: ATADriveDirection, direction: ATADriveDirection,
buffer: (*mut u8, usize), buffer: &mut [u8],
) -> Result<(), ()> { ) -> Result<(), ()> {
let buffer = unsafe { core::slice::from_raw_parts_mut(buffer.0, buffer.1) };
self.await_busy(); self.await_busy();
let using_lba48 = sector >= (1 << 28) - 1; let using_lba48 = sector >= (1 << 28) - 1;
@@ -411,29 +413,32 @@ impl ATABus {
// Since this is an internal function, this should never fail // Since this is an internal function, this should never fail
assert!(buffer.len() >= array_size); assert!(buffer.len() >= array_size);
// Allocate memory for the array that stores the sector data
let mut buffer_offset = 0; let mut buffer_offset = 0;
for _ in 0..sector_count { for _ in 0..sector_count {
self.wait_for_drive_ready() self.wait_for_drive_ready()
.map_err(|_| crate::log_error!("Error reading IDE Device"))?; .map_err(|_| crate::log_error!("Error reading IDE Device"))?;
for chunk in // # Safety
buffer[buffer_offset..(buffer_offset + ATA_SECTOR_SIZE)].chunks_exact_mut(2) //
{ // We know that buffer is the exact size of count, so it will never panic:tm:
match direction { match direction {
ATADriveDirection::Read => { ATADriveDirection::Read => unsafe {
let word = insw(
inw(self.io_bar + ATADriveDataRegister::Data as u16).to_le_bytes(); self.io_bar + ATADriveDataRegister::Data as u16,
chunk.copy_from_slice(&word); (buffer.as_mut_ptr() as *mut u16).add(buffer_offset),
} ATA_SECTOR_SIZE / size_of::<u16>(),
ATADriveDirection::Write => { );
let word = u16::from_le_bytes(chunk.try_into().unwrap()); },
outw(self.io_bar + ATADriveDataRegister::Data as u16, word); 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::<u16>(),
)
},
} }
buffer_offset += ATA_SECTOR_SIZE; buffer_offset += ATA_SECTOR_SIZE / size_of::<u16>();
} }
return Ok(()); return Ok(());

View File

@@ -1,13 +1,11 @@
use alloc::{format, vec::Vec}; use alloc::vec::Vec;
use crate::{ use crate::{
drivers::{ drivers::fs::{initramfs::INITRAMFS, vfs::VfsFileSystem},
fs::{initramfs::INITRAMFS, vfs::VfsFileSystem},
serial::write_serial,
},
libs::lazy::Lazy, libs::lazy::Lazy,
}; };
#[derive(Debug)]
pub struct PSFFontHeader { pub struct PSFFontHeader {
pub magic: u32, pub magic: u32,
pub length: u32, pub length: u32,

View File

@@ -12,15 +12,12 @@ mod usr;
use core::ffi::CStr; use core::ffi::CStr;
use alloc::vec::Vec; use alloc::{format, vec::Vec};
use drivers::serial; use drivers::serial;
use libs::util::hcf; use libs::util::hcf;
use limine::KernelFileRequest; use limine::KernelFileRequest;
use crate::{ use crate::{drivers::serial::write_serial, mem::LabelBytes};
drivers::fs::{initramfs::INITRAMFS, vfs::VfsFileSystem},
mem::LabelBytes,
};
pub static KERNEL_REQUEST: KernelFileRequest = KernelFileRequest::new(0); pub static KERNEL_REQUEST: KernelFileRequest = KernelFileRequest::new(0);
@@ -120,7 +117,11 @@ fn parse_kernel_cmdline() -> KernelFeatures {
#[panic_handler] #[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! { 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"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{ {