squashfs fragment support + bug fixes
This commit is contained in:
5
Makefile
5
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
|
||||
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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(());
|
||||
|
||||
@@ -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,
|
||||
|
||||
13
src/main.rs
13
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"))]
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user