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

View File

@@ -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)]

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)]
#[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 {

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 {
if self.bit_index == 8 {
self.input_buf.remove(0);

View File

@@ -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::<DirectoryTableHeader>();
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::<DirectoryTableHeader>();
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,21 +469,20 @@ impl<'a> BasicFileInode<'a> {
frag_idx,
block_offset,
file_size,
block_sizes,
};
}
}
impl<'a> VfsFile for BasicFileInode<'a> {
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?
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,
(
false,
@@ -494,10 +497,74 @@ impl<'a> VfsFile for BasicFileInode<'a> {
),
);
block_data.extend(
&data_table[self.block_offset as usize..(self.block_offset + self.file_size) as usize],
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));
}
}

View File

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

View File

@@ -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<u8> = 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)
{
// # Safety
//
// We know that buffer is the exact size of count, so it will never panic:tm:
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);
}
}
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::<u16>(),
);
},
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(());

View File

@@ -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,

View File

@@ -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"))]
{