non-working squashfs driver updates, partial stack traces, and more

This commit is contained in:
Zoe
2023-11-24 03:58:30 -06:00
parent 1c865a6695
commit 525ae40054
24 changed files with 477 additions and 357 deletions

View File

@@ -6,4 +6,5 @@ build-std = [
] ]
[build] [build]
target = "./src/arch/x86_64/x86_64-unknown-none.json" target = "./src/arch/x86_64/x86_64-unknown-none.json"
rustflags = ["-Cforce-frame-pointers=yes"]

View File

@@ -88,6 +88,9 @@ else
endif endif
build-iso: partition-iso build-iso: partition-iso
nm target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf > scripts/symbols.table
python scripts/demangle-symbols.py
mv scripts/symbols.table ${ISO_PATH}/boot
# Install the Limine bootloader on the ISO # Install the Limine bootloader on the ISO
./limine/limine bios-install ${IMAGE_PATH} ./limine/limine bios-install ${IMAGE_PATH}

View File

@@ -44,6 +44,7 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
Before building CappuccinOS, make sure you have the following installed on your machine: Before building CappuccinOS, make sure you have the following installed on your machine:
- rust - rust
- python
- binutils - binutils
- sgdisk - sgdisk
- mtools - mtools
@@ -64,22 +65,19 @@ curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none
Install the dependencies: Install the dependencies:
<details> <details>
<summary>Arch</summary> <summary>Arch</summary>
```BASH sudo pacman -S binutils gptfdisk mtools squashfs-tools python
sudo pacman -S binutils gptfdisk mtools squashfs-tools
# Optionally # Optionally
sudo pacman -S qemu-system-x86 sudo pacman -S qemu-system-x86
```
</details> </details>
<details> <details>
<summary>Ubuntu</summary> <summary>Ubuntu</summary>
Python should be installed by default, and if it's not, make an issue or a PR and I'll fix it
```BASH
sudo apt install binutils gdisk mtools squashfs-tools sudo apt install binutils gdisk mtools squashfs-tools
# Optionally # Optionally
sudo apt install qemu sudo apt install qemu
```
</details> </details>
## Usage ## Usage

View File

@@ -1,4 +1,2 @@
# CappuccinOS/scripts # CappuccinOS/scripts
This folder is responsible for holding all the scripts that are necessary for building CappuccinOS, the list currently includes: This folder is responsible for holding all the scripts that are necessary for building CappuccinOS
- [initramfs.py](initramfs.py): This file is used for generating an initramfs file that holds critical drivers that the kernel needs to access other drivers that may be located on block storage.

View File

@@ -0,0 +1,20 @@
import rustc_demangle.rustc_demangle as rustc_demangle
def demangle_function_name(mangled_name):
return rustc_demangle.demangle(mangled_name).get_fn_name(False)
if __name__ == "__main__":
with open("scripts/symbols.table", 'r') as infile:
lines = infile.readlines()
sorted_lines = sorted(lines, key=lambda line: int(line.split()[0], 16) if len(line.split()) >= 1 else 0)
with open("scripts/symbols.table", 'w') as outfile:
for line in sorted_lines:
parts = line.split()
if len(parts) >= 3:
address = parts[0]
mangled_name = parts[2]
demangled_name = demangle_function_name(mangled_name)
new_line = f"{address} {demangled_name}\n"
outfile.write(new_line)

View File

@@ -1,25 +0,0 @@
import os
import gzip
import shutil
import sys
if __name__ == "__main__":
if len(sys.argv) != 3:
print(f"Usage: python scripts/initramfs.py /path/to/source/directory /path/to/output/directory/initramfs.gz")
sys.exit(1)
source_dir, output_file = sys.argv[1], sys.argv[2]
try:
with gzip.open(output_file, 'wb') as gz_file:
for foldername, subfolders, filenames in os.walk(source_dir):
for filename in filenames:
file_path = os.path.join(foldername, filename)
rel_path = os.path.relpath(file_path, source_dir)
gz_file.write(os.path.join(rel_path).encode())
with open(file_path, 'rb') as source_file:
shutil.copyfileobj(source_file, gz_file)
print(f"Compression completed. Output file: {output_file}")
except Exception as e:
print(f"Error compressing directory: {str(e)}")
sys.exit(1)

View File

@@ -30,6 +30,7 @@ pub extern "C" fn exception_handler(int: u64, eip: u64, cs: u64, eflags: u64) ->
log_error!("EXCEPTION!"); log_error!("EXCEPTION!");
} }
} }
log_info!( log_info!(
"INT: {:x} EIP: {:X}, CS: {:X}, EFLAGS: {:b}", "INT: {:x} EIP: {:X}, CS: {:X}, EFLAGS: {:b}",
int, int,
@@ -38,6 +39,12 @@ pub extern "C" fn exception_handler(int: u64, eip: u64, cs: u64, eflags: u64) ->
eflags eflags
); );
// unsafe {
// core::arch::asm!("cli");
// };
crate::arch::stack_trace::print_stack_trace(6);
hcf(); hcf();
} }

0
src/arch/x86_64/interrupts/mod.rs Normal file → Executable file
View File

View File

@@ -1,5 +1,6 @@
pub mod io; pub mod io;
pub mod pic; pub mod pic;
pub mod stack_trace;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)] #[inline(always)]

View File

@@ -0,0 +1,26 @@
#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct StackFrame {
back: *const StackFrame,
rip: u64,
}
pub fn print_stack_trace(max_frames: usize) {
let mut stackframe: *const StackFrame;
unsafe {
core::arch::asm!("mov {0:r}, rbp", out(reg) stackframe);
};
crate::println!("Stack Trace:");
for _frame in 0..max_frames {
if stackframe.is_null() || unsafe { (*stackframe).back.is_null() } {
break;
}
unsafe {
crate::println!(" {:#X}", (*stackframe).rip);
stackframe = (*stackframe).back;
};
}
}

23
src/drivers/fs/fat.rs Normal file → Executable file
View File

@@ -2,7 +2,7 @@ use alloc::{
boxed::Box, boxed::Box,
string::{String, ToString}, string::{String, ToString},
sync::Arc, sync::Arc,
vec::{self, Vec}, vec::Vec,
}; };
use crate::drivers::storage::drive::{BlockDevice, GPTPartitionEntry}; use crate::drivers::storage::drive::{BlockDevice, GPTPartitionEntry};
@@ -23,6 +23,7 @@ use super::vfs::{VFSDirectory, VFSFile, VFSFileSystem};
// End Of Chain // End Of Chain
const EOC: u32 = 0x0FFFFFF8; const EOC: u32 = 0x0FFFFFF8;
#[derive(Debug)]
enum FatType { enum FatType {
Fat12, Fat12,
Fat16, Fat16,
@@ -154,6 +155,7 @@ pub struct FATFS<'a> {
fat_start: u64, fat_start: u64,
fat_type: FatType, fat_type: FatType,
cluster_size: usize, cluster_size: usize,
sectors_per_fat: usize,
} }
impl<'a> FATFS<'a> { impl<'a> FATFS<'a> {
@@ -219,6 +221,7 @@ impl<'a> FATFS<'a> {
} else { } else {
(bpb.total_sectors as u32, bpb.sectors_per_fat as u32) (bpb.total_sectors as u32, bpb.sectors_per_fat as u32)
}; };
let root_dir_sectors = let root_dir_sectors =
((bpb.root_directory_count * 32) + (bpb.bytes_per_sector - 1)) / bpb.bytes_per_sector; ((bpb.root_directory_count * 32) + (bpb.bytes_per_sector - 1)) / bpb.bytes_per_sector;
let total_data_sectors = total_sectors let total_data_sectors = total_sectors
@@ -236,6 +239,13 @@ impl<'a> FATFS<'a> {
FatType::Fat32 FatType::Fat32
}; };
crate::println!("Found {fat_type:?} FS");
let sectors_per_fat = match fat_type {
FatType::Fat32 => bpb.sectors_per_fat_ext as usize,
_ => bpb.sectors_per_fat as usize,
};
let cluster_size = bpb.sectors_per_cluster as usize * 512; let cluster_size = bpb.sectors_per_cluster as usize * 512;
return Ok(Self { return Ok(Self {
@@ -247,6 +257,7 @@ impl<'a> FATFS<'a> {
fat_start, fat_start,
fat_type, fat_type,
cluster_size, cluster_size,
sectors_per_fat,
}); });
} }
@@ -364,17 +375,17 @@ impl<'a> FATFS<'a> {
} }
fn cluster_to_sector(&self, cluster: usize) -> usize { fn cluster_to_sector(&self, cluster: usize) -> usize {
let fat_size = self.bpb.sectors_per_fat_ext; let fat_size = self.sectors_per_fat;
let root_dir_sectors = ((self.bpb.root_directory_count * 32) let root_dir_sectors = ((self.bpb.root_directory_count * 32)
+ (self.bpb.bytes_per_sector - 1)) + (self.bpb.bytes_per_sector - 1))
/ self.bpb.bytes_per_sector; / self.bpb.bytes_per_sector;
let first_data_sector = self.bpb.reserved_sectors as u32 let first_data_sector = self.bpb.reserved_sectors as usize
+ (self.bpb.fat_count as u32 * fat_size) + (self.bpb.fat_count as usize * fat_size)
+ root_dir_sectors as u32; + root_dir_sectors as usize;
return ((cluster - 2) as isize * self.bpb.sectors_per_cluster as isize) as usize return ((cluster - 2) as isize * self.bpb.sectors_per_cluster as isize) as usize
+ first_data_sector as usize; + first_data_sector;
} }
fn get_next_cluster(&self, cluster: usize) -> u32 { fn get_next_cluster(&self, cluster: usize) -> u32 {

408
src/drivers/fs/initramfs/mod.rs Normal file → Executable file
View File

@@ -1,11 +1,15 @@
pub mod compressors; pub mod compressors;
use alloc::vec::Vec;
use limine::ModuleRequest; use limine::ModuleRequest;
pub static MODULE_REQUEST: ModuleRequest = ModuleRequest::new(0); pub static MODULE_REQUEST: ModuleRequest = ModuleRequest::new(0);
const SQUASHFS_INODE_OFFSET: fn(a: u32) -> u32 = |a| a & 0xFFF;
const SQUASHFS_INODE_BLK: fn(a: u32) -> u32 = |a| a >> 16;
pub fn init() { pub fn init() {
// TODO: Put this stuff in another file? // TODO: Put the module request stuff in another file?
if MODULE_REQUEST.get_response().get().is_none() { if MODULE_REQUEST.get_response().get().is_none() {
crate::log_error!("Module request in none!"); crate::log_error!("Module request in none!");
return; return;
@@ -28,6 +32,7 @@ pub fn init() {
initramfs = Some(module); initramfs = Some(module);
} }
// End TODO
if initramfs.is_none() { if initramfs.is_none() {
crate::log_error!("Initramfs was not found!"); crate::log_error!("Initramfs was not found!");
@@ -44,11 +49,291 @@ pub fn init() {
.add(initramfs.length as usize) .add(initramfs.length as usize)
}); });
init_fs(initramfs.base.as_ptr().unwrap()); let squashfs = Squashfs::new(initramfs.base.as_ptr().unwrap());
if squashfs.is_err() {
crate::log_error!("Initramfs in corrupt!");
return;
}
let squashfs = squashfs.unwrap();
crate::println!("{:X?}", squashfs);
crate::println!("{:?}", squashfs.superblock.features());
squashfs.test();
}
#[derive(Debug)]
struct Squashfs<'a> {
ptr: *mut u8,
superblock: SquashfsSuperblock,
data_table: &'a [u8],
inode_table: &'a [u8],
directory_table: &'a [u8],
fragment_table: Option<&'a [u8]>,
export_table: Option<&'a [u8]>,
id_table: &'a [u8],
xattr_table: Option<&'a [u8]>,
}
impl Squashfs<'_> {
fn new(ptr: *mut u8) -> Result<Squashfs<'static>, ()> {
crate::println!("Parsing initramfs fs at {:p}", ptr);
// bytes used from superblock
let length = unsafe { u64::from_le(*(ptr.add(40) as *const u64)) as usize };
let squashfs_data: &[u8] = unsafe { core::slice::from_raw_parts(ptr, length) };
let superblock = SquashfsSuperblock::new(&squashfs_data)?;
let data_table = &squashfs_data
[core::mem::size_of::<SquashfsSuperblock>()..superblock.inode_table as usize];
let inode_table =
&squashfs_data[superblock.inode_table as usize..superblock.dir_table as usize];
let directory_table =
&squashfs_data[superblock.dir_table as usize..superblock.frag_table as usize];
let mut fragment_table: Option<&[u8]> = None;
if superblock.frag_table != u64::MAX {
fragment_table = Some(
&squashfs_data[superblock.frag_table as usize..superblock.export_table as usize],
);
}
let mut export_table: Option<&[u8]> = None;
if superblock.export_table != u64::MAX {
export_table = Some(
&squashfs_data[superblock.export_table as usize..superblock.id_table as usize],
);
}
let mut id_table: &[u8] = &squashfs_data[superblock.id_table as usize..];
let mut xattr_table: Option<&[u8]> = None;
if superblock.xattr_table != u64::MAX {
id_table =
&squashfs_data[superblock.id_table as usize..superblock.xattr_table as usize];
xattr_table = Some(&squashfs_data[superblock.xattr_table as usize..]);
}
return Ok(Squashfs {
ptr: unsafe { ptr.add(core::mem::size_of::<SquashfsSuperblock>()) },
superblock,
data_table,
inode_table,
directory_table,
fragment_table,
export_table,
id_table,
xattr_table,
});
}
// big function that does stuff hard coded-ly before I rip it all out
pub fn test(&self) {
// the bottom 15 bits, I think the last bit indicates whether the data is uncompressed
let inode_table_header = u16::from_le_bytes(self.inode_table[0..2].try_into().unwrap());
let inode_is_compressed = inode_table_header & 0x80 != 0;
let inode_table_size = inode_table_header & 0x7FFF;
if inode_table_size >= 8192 {
panic!("Inode block is not less than 8KiB!");
}
let mut buffer: Vec<u8> = Vec::with_capacity(8192);
if inode_is_compressed {
todo!("uncompress zlib data")
} else {
unsafe {
core::ptr::copy_nonoverlapping(
self.inode_table.as_ptr().add(2),
buffer.as_mut_ptr(),
inode_table_size as usize,
);
buffer.set_len(inode_table_size as usize);
}
}
let root_inode_block = self.superblock.root_inode_block as usize;
let root_inode_offset = self.superblock.root_inode_offset as usize;
let root_inode_header = self.read_inode(root_inode_offset as u32);
let root_inode_header = InodeHeader {
file_type: u16::from_le_bytes(
buffer[root_inode_offset..root_inode_offset + 2]
.try_into()
.unwrap(),
)
.into(),
_reserved: [
u16::from_le_bytes(
buffer[root_inode_offset + 2..root_inode_offset + 4]
.try_into()
.unwrap(),
),
u16::from_le_bytes(
buffer[root_inode_offset + 4..root_inode_offset + 6]
.try_into()
.unwrap(),
),
u16::from_le_bytes(
buffer[root_inode_offset + 6..root_inode_offset + 8]
.try_into()
.unwrap(),
),
],
mtime: u32::from_le_bytes(
buffer[root_inode_offset + 8..root_inode_offset + 12]
.try_into()
.unwrap(),
),
inode_num: u32::from_le_bytes(
buffer[root_inode_offset + 12..root_inode_offset + 16]
.try_into()
.unwrap(),
),
};
crate::println!("{:X?}", root_inode_header);
let root_inode = DirectoryInode {
block_index: u32::from_le_bytes(
buffer[root_inode_offset + 16..root_inode_offset + 20]
.try_into()
.unwrap(),
),
link_count: u32::from_le_bytes(
buffer[root_inode_offset + 20..root_inode_offset + 24]
.try_into()
.unwrap(),
),
file_size: u16::from_le_bytes(
buffer[root_inode_offset + 24..root_inode_offset + 26]
.try_into()
.unwrap(),
),
block_offset: u16::from_le_bytes(
buffer[root_inode_offset + 26..root_inode_offset + 28]
.try_into()
.unwrap(),
),
parent_inode: u32::from_le_bytes(
buffer[root_inode_offset + 28..root_inode_offset + 32]
.try_into()
.unwrap(),
),
};
crate::println!("{:?}", root_inode);
}
fn read_inode(&self, inode_num: u32) -> Option<InodeHeader> {
let inode_offset = inode_num as usize + 2;
if inode_offset + core::mem::size_of::<InodeHeader>() > self.inode_table.len() {
return None;
}
let inode_header_bytes = &self.inode_table[inode_offset..(inode_offset + 16)];
crate::println!("{:X?}", inode_header_bytes);
let inode_header = InodeHeader::from_bytes(inode_header_bytes)?;
Some(inode_header)
}
}
#[derive(Debug)]
struct InodeHeader {
file_type: InodeFileType,
_reserved: [u16; 3],
mtime: u32,
inode_num: u32,
}
impl InodeHeader {
fn from_bytes(bytes: &[u8]) -> Option<InodeHeader> {
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());
Some(InodeHeader {
file_type,
_reserved: [0; 3],
mtime,
inode_num,
})
}
}
#[derive(Debug)]
struct DirectoryInode {
block_index: u32,
link_count: u32,
file_size: u16,
block_offset: u16,
parent_inode: u32,
}
#[derive(Debug)]
struct FileInode {
block_start: u32,
frag_idx: u32,
block_offset: u32,
file_size: u32,
block_size: [u32; 0],
} }
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u16)] #[repr(u16)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum InodeFileType {
BasicDirectory = 1,
BasicFile = 2,
BasicSymlink = 3,
BasicBlockDevice = 4,
BasicCharDevice = 5,
BasicPipe = 6,
BasicSocked = 7,
ExtendedDirectory = 8,
ExtendedFile = 9,
ExtendedSymlink = 10,
ExtendedBlockDevice = 11,
ExtendedPipe = 12,
ExtendedSocked = 13,
}
impl Into<InodeFileType> for u16 {
fn into(self) -> InodeFileType {
match self {
1 => InodeFileType::BasicDirectory,
2 => InodeFileType::BasicFile,
3 => InodeFileType::BasicSymlink,
4 => InodeFileType::BasicBlockDevice,
5 => InodeFileType::BasicCharDevice,
6 => InodeFileType::BasicPipe,
7 => InodeFileType::BasicSocked,
8 => InodeFileType::ExtendedDirectory,
9 => InodeFileType::ExtendedFile,
10 => InodeFileType::ExtendedSymlink,
11 => InodeFileType::ExtendedBlockDevice,
12 => InodeFileType::ExtendedPipe,
13 => InodeFileType::ExtendedSocked,
_ => panic!("Unexpected Inode file type {self}!"),
}
}
}
#[repr(u16)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum SquashfsCompressionType { enum SquashfsCompressionType {
GZIP = 1, GZIP = 1,
LZMA = 2, LZMA = 2,
@@ -104,6 +389,7 @@ impl Into<SquashfsCompressionType> for u16 {
} }
} }
#[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
struct SquashfsSuperblock { struct SquashfsSuperblock {
magic: u32, // 0x73717368 magic: u32, // 0x73717368
@@ -117,7 +403,9 @@ struct SquashfsSuperblock {
id_count: u16, // 0x01 id_count: u16, // 0x01
ver_major: u16, // 0x04 ver_major: u16, // 0x04
ver_minor: u16, // 0x00 ver_minor: u16, // 0x00
root_inode: u64, // 0x20 root_inode_offset: u16, //
root_inode_block: u32, //
_reserved: u16, // 0x20
bytes_used: u64, // 0x0103 bytes_used: u64, // 0x0103
id_table: u64, // 0x00FB id_table: u64, // 0x00FB
xattr_table: u64, // 0xFFFFFFFFFFFFFFFF xattr_table: u64, // 0xFFFFFFFFFFFFFFFF
@@ -128,8 +416,8 @@ struct SquashfsSuperblock {
} }
impl SquashfsSuperblock { impl SquashfsSuperblock {
fn new(bytes: &[u8]) -> Self { fn new(bytes: &[u8]) -> Result<Self, ()> {
return Self { let superblock = Self {
magic: u32::from_le_bytes(bytes[0..4].try_into().unwrap()), magic: u32::from_le_bytes(bytes[0..4].try_into().unwrap()),
inode_count: u32::from_le_bytes(bytes[4..8].try_into().unwrap()), inode_count: u32::from_le_bytes(bytes[4..8].try_into().unwrap()),
mod_time: u32::from_le_bytes(bytes[8..12].try_into().unwrap()), mod_time: u32::from_le_bytes(bytes[8..12].try_into().unwrap()),
@@ -141,7 +429,9 @@ impl SquashfsSuperblock {
id_count: u16::from_le_bytes(bytes[26..28].try_into().unwrap()), id_count: u16::from_le_bytes(bytes[26..28].try_into().unwrap()),
ver_major: u16::from_le_bytes(bytes[28..30].try_into().unwrap()), ver_major: u16::from_le_bytes(bytes[28..30].try_into().unwrap()),
ver_minor: u16::from_le_bytes(bytes[30..32].try_into().unwrap()), ver_minor: u16::from_le_bytes(bytes[30..32].try_into().unwrap()),
root_inode: u64::from_le_bytes(bytes[32..40].try_into().unwrap()), root_inode_offset: u16::from_le_bytes(bytes[32..34].try_into().unwrap()),
root_inode_block: u32::from_le_bytes(bytes[34..38].try_into().unwrap()),
_reserved: u16::from_le_bytes(bytes[38..40].try_into().unwrap()),
bytes_used: u64::from_le_bytes(bytes[40..48].try_into().unwrap()), bytes_used: u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
id_table: u64::from_le_bytes(bytes[48..56].try_into().unwrap()), id_table: u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
xattr_table: u64::from_le_bytes(bytes[56..64].try_into().unwrap()), xattr_table: u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
@@ -150,12 +440,39 @@ impl SquashfsSuperblock {
frag_table: u64::from_le_bytes(bytes[80..88].try_into().unwrap()), frag_table: u64::from_le_bytes(bytes[80..88].try_into().unwrap()),
export_table: u64::from_le_bytes(bytes[88..96].try_into().unwrap()), export_table: u64::from_le_bytes(bytes[88..96].try_into().unwrap()),
}; };
if superblock.magic != 0x73717368 {
return Err(());
}
if superblock.ver_major != 4 || superblock.ver_minor != 0 {
return Err(());
}
if superblock.block_size > 1048576 {
return Err(());
}
if superblock.block_log > 20 {
return Err(());
}
if superblock.block_size != (1 << superblock.block_log) {
return Err(());
}
if superblock.block_size == 0 {
return Err(());
}
if ((superblock.block_size - 1) & superblock.block_size) != 0 {
return Err(());
}
return Ok(superblock);
} }
fn features(&self) -> SquashfsFeatures { fn features(&self) -> SquashfsFeatures {
// let graphical_output = ((*self.feature_bits.lock().read()) & 0x01) != 0;
// let serial_output = ((*self.feature_bits.lock().read()) & 0x02) != 0;
// let doubled_buffered = ((*self.feature_bits.lock().read()) & 0x04) != 0;
let uncompressed_inodes = (self.flags & SquashfsFlags::UncompressedInodes as u16) != 0; let uncompressed_inodes = (self.flags & SquashfsFlags::UncompressedInodes as u16) != 0;
let uncompressed_data_blocks = let uncompressed_data_blocks =
(self.flags & SquashfsFlags::UncompressedDataBlocks as u16) != 0; (self.flags & SquashfsFlags::UncompressedDataBlocks as u16) != 0;
@@ -189,74 +506,3 @@ impl SquashfsSuperblock {
}; };
} }
} }
#[derive(Debug)]
struct Squashfs<'a> {
ptr: *mut u8,
superblock: SquashfsSuperblock,
data_table: &'a [u8],
inode_table: &'a [u8],
directory_table: &'a [u8],
fragment_table: Option<&'a [u8]>,
export_table: Option<&'a [u8]>,
id_table: &'a [u8],
xattr_table: Option<&'a [u8]>,
}
fn init_fs(initramfs: *mut u8) {
crate::println!("Parsing initramfs fs at {:p}", initramfs);
// bytes used from superblock
let length = unsafe { u64::from_le(*(initramfs.add(40) as *const u64)) as usize };
let squashfs_data: &[u8] = unsafe { core::slice::from_raw_parts(initramfs, length) };
let superblock = SquashfsSuperblock::new(&squashfs_data);
let data_table =
&squashfs_data[core::mem::size_of::<SquashfsSuperblock>()..superblock.inode_table as usize];
let inode_table =
&squashfs_data[superblock.inode_table as usize..superblock.dir_table as usize];
let directory_table =
&squashfs_data[superblock.dir_table as usize..superblock.frag_table as usize];
let mut fragment_table: Option<&[u8]> = None;
if superblock.frag_table != u64::MAX {
fragment_table =
Some(&squashfs_data[superblock.frag_table as usize..superblock.export_table as usize]);
}
let mut export_table: Option<&[u8]> = None;
if superblock.export_table != u64::MAX {
export_table =
Some(&squashfs_data[superblock.export_table as usize..superblock.id_table as usize]);
}
let mut id_table: &[u8] = &squashfs_data[superblock.id_table as usize..];
let mut xattr_table: Option<&[u8]> = None;
if superblock.xattr_table != u64::MAX {
id_table = &squashfs_data[superblock.id_table as usize..superblock.xattr_table as usize];
xattr_table = Some(&squashfs_data[superblock.xattr_table as usize..]);
}
let squashfs = Squashfs {
ptr: initramfs,
superblock,
data_table,
inode_table,
directory_table,
fragment_table,
export_table,
id_table,
xattr_table,
};
crate::println!("{:#X?}", squashfs);
crate::println!("{:?}", squashfs.superblock.features());
}

85
src/drivers/fs/vfs.rs Normal file → Executable file
View File

@@ -40,88 +40,3 @@ pub fn init() {
// TODO: Deduce which storage medium(s) we're using // TODO: Deduce which storage medium(s) we're using
crate::drivers::storage::ide::init(); crate::drivers::storage::ide::init();
} }
// //? Please, shield your eyes and hide your children
// // This is... really bad to say the least, I think you can make it way better by using traits but I'm not sure
// use alloc::{sync::Arc, vec::Vec};
// use crate::libs::mutex::Mutex;
// pub struct VFSPartition {
// start_sector: usize,
// sectors: usize,
// }
// pub struct VFSDrive {
// sectors: usize,
// read: fn(sector: u64, sector_count: usize) -> Result<Arc<[u8]>, ()>,
// write: fn(sector: u64, data: &[u8]) -> Result<(), ()>,
// partitions: Arc<[VFSPartition]>,
// }
// pub struct VFSFileSystem<'a> {
// name: &'a str,
// mount_point: &'a str,
// open: Option<fn(VFSNode)>,
// read: Option<fn(VFSNode, usize, usize) -> Result<Arc<[u8]>, ()>>,
// write: Option<fn(VFSNode, Arc<[u8]>, usize, usize) -> Result<(), ()>>,
// }
// pub struct VFSNode<'a> {
// filesystem: *const VFSFileSystem<'a>,
// size: usize,
// id: usize,
// path: &'a str,
// next: Option<*const VFSNode<'a>>,
// }
// static ROOT_FS: VFSFileSystem = VFSFileSystem {
// name: "rootfs",
// mount_point: "/",
// open: None,
// read: None,
// write: None,
// };
// static ROOT_NODE: Mutex<VFSNode> = Mutex::new(VFSNode {
// filesystem: core::ptr::null(),
// size: 0,
// id: 0,
// path: "",
// next: None,
// });
// pub static VFS_INSTANCES: Mutex<VFS> = Mutex::new(VFS::new());
// pub struct VFS {
// drives: Vec<VFSDrive>,
// }
// impl VFS {
// pub const fn new() -> Self {
// return Self { drives: Vec::new() };
// }
// pub fn add_drive(&mut self, drive: VFSDrive) {
// self.drives.push(drive);
// let mut drive_node = VFSNode {
// filesystem: core::ptr::null(),
// size: 0,
// id: 0,
// path: "",
// next: None,
// };
// drive_node.filesystem = &ROOT_FS;
// }
// }
// pub fn init() {
// ROOT_NODE.lock().write().filesystem = &ROOT_FS;
// crate::println!("VFS: Registered VFS on {}", ROOT_FS.mount_point);
// }

0
src/drivers/keyboard.rs Normal file → Executable file
View File

29
src/drivers/pci.rs Normal file → Executable file
View File

@@ -125,19 +125,8 @@ impl core::fmt::Display for PciDevice {
pub static PCI_DEVICES: Mutex<Vec<PciDevice>> = Mutex::new(Vec::new()); pub static PCI_DEVICES: Mutex<Vec<PciDevice>> = Mutex::new(Vec::new());
pub fn enumerate_pci_bus() { pub fn enumerate_pci_bus() {
let header_type = read_pci_header_type(0, 0, 0); for bus in 0..=255 {
if (header_type & 0x80) == 0 { check_bus(bus);
// Single PCI host controller
check_bus(0);
} else {
// Multiple PCI host controllers
for function in 0..8 {
if read_pci_vendor_id(0, 0, function) != 0xFFFF {
break;
}
let bus = function;
check_bus(bus);
}
} }
crate::println!("====== PCI DEVICES ======"); crate::println!("====== PCI DEVICES ======");
@@ -153,7 +142,7 @@ fn check_bus(bus: u8) {
} }
fn check_device(bus: u8, device: u8) { fn check_device(bus: u8, device: u8) {
let mut func: u8 = 0; let func: u8 = 0;
let vendor_id = read_pci_vendor_id(bus, device, func); let vendor_id = read_pci_vendor_id(bus, device, func);
@@ -165,15 +154,12 @@ fn check_device(bus: u8, device: u8) {
let header_type = read_pci_header_type(bus, device, func); let header_type = read_pci_header_type(bus, device, func);
if header_type & 0x80 != 0 { if header_type & 0x80 != 0 {
// It's a multi-function device for func in 1..8 {
func += 1; let vendor_id = read_pci_vendor_id(bus, device, func);
while func < 8 { if vendor_id != 0xFFFF {
if read_pci_vendor_id(bus, device, func) != 0xFFFF {
check_function(bus, device, func); check_function(bus, device, func);
} }
func += 1;
} }
} }
} }
@@ -193,6 +179,7 @@ fn check_function(bus: u8, device: u8, func: u8) {
if class_code == 0x06 && subclass_code == 0x04 { if class_code == 0x06 && subclass_code == 0x04 {
secondary_bus = read_pci_to_pci_secondary_bus(bus, device, func); secondary_bus = read_pci_to_pci_secondary_bus(bus, device, func);
check_bus(secondary_bus); // TODO: This causes an infinite loop on baremetal
// check_bus(secondary_bus);
} }
} }

0
src/drivers/storage/ide.rs Normal file → Executable file
View File

8
src/drivers/video/font.rs Normal file → Executable file
View File

@@ -1,6 +1,10 @@
pub const G_8X16_FONT: [[u8; 16]; 256] = [ pub static G_8X16_FONT: [[u8; 16]; 256] = [
// [
// 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00,
// 0x00,
// ],
[ [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0x99, 0xA5, 0x85, 0x89, 0x89, 0x81, 0x89, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00,
], ],
[ [

2
src/drivers/video/mod.rs Normal file → Executable file
View File

@@ -41,7 +41,7 @@ pub fn put_char(
let font = font::G_8X16_FONT; let font = font::G_8X16_FONT;
if character as usize > u8::MAX as usize { if character as usize > u8::MAX as usize {
character = '?'; character = '\x00'; // rounded question mark
fg = 0xFF0000; fg = 0xFF0000;
} }

15
src/libs/lazy.rs Normal file → Executable file
View File

@@ -6,7 +6,7 @@ use core::{
pub struct Lazy<T, F = fn() -> T> { pub struct Lazy<T, F = fn() -> T> {
value: UnsafeCell<Option<T>>, value: UnsafeCell<Option<T>>,
init_func: Option<F>, init_func: F,
initialized: AtomicBool, initialized: AtomicBool,
} }
@@ -14,7 +14,7 @@ impl<T, F: Fn() -> T> Lazy<T, F> {
pub const fn new(init_func: F) -> Self { pub const fn new(init_func: F) -> Self {
Lazy { Lazy {
value: UnsafeCell::new(None), value: UnsafeCell::new(None),
init_func: Some(init_func), init_func: init_func,
initialized: AtomicBool::new(false), initialized: AtomicBool::new(false),
} }
} }
@@ -25,13 +25,12 @@ impl<T, F: Fn() -> T> Deref for Lazy<T, F> {
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
if !self.initialized.load(Ordering::Acquire) { if !self.initialized.load(Ordering::Acquire) {
if let Some(init_func) = &self.init_func { let value = (self.init_func)();
let value = init_func(); unsafe {
unsafe { *(self.value.get()) = Some(value);
*(self.value.get()) = Some(value);
}
self.initialized.store(true, Ordering::Release);
} }
self.initialized.store(true, Ordering::Release);
} }
unsafe { unsafe {

0
src/libs/mutex.rs Normal file → Executable file
View File

2
src/main.rs Normal file → Executable file
View File

@@ -16,7 +16,7 @@ use core::ffi::CStr;
use alloc::vec::Vec; use alloc::vec::Vec;
use drivers::serial; use drivers::serial;
use libs::util::hcf; use libs::util::hcf;
use limine::{KernelFileRequest, ModuleRequest}; use limine::KernelFileRequest;
use crate::mem::LabelBytes; use crate::mem::LabelBytes;

86
src/mem/mod.rs Normal file → Executable file
View File

@@ -33,61 +33,6 @@ pub static HHDM_OFFSET: Lazy<usize> = Lazy::new(|| {
return hhdm.offset as usize; return hhdm.offset as usize;
}); });
// fn stitch_memory_map(memmap: &mut [NonNullPtr<MemmapEntry>]) -> &mut [NonNullPtr<MemmapEntry>] {
// let mut null_index_ptr = 0;
//
// crate::println!("====== MEMORY MAP ======");
// for entry in memmap.iter() {
// crate::println!(
// "[ {:#018X?} ] Type: {:?} Size: {:?}",
// entry.base..entry.base + entry.len,
// entry.typ,
// entry.len as usize
// )
// }
//
// for i in 1..memmap.len() {
// let region = &memmap[i];
//
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
// if region.typ == limine::MemoryMapEntryType::Framebuffer {
// crate::arch::set_mtrr(
// region.base,
// region.len,
// crate::arch::MTRRMode::WriteCombining,
// );
// }
//
// if !memory_section_is_usable(&memmap[i]) {
// memmap[null_index_ptr].len = memmap[i].len;
// memmap[null_index_ptr].base = memmap[i].base;
// memmap[null_index_ptr].typ = memmap[i].typ;
//
// null_index_ptr += 1;
// continue;
// }
//
// if null_index_ptr > 0 && memory_section_is_usable(&memmap[null_index_ptr - 1]) {
// memmap[null_index_ptr - 1].len += memmap[i].len;
//
// continue;
// }
//
// if memory_section_is_usable(&memmap[i - 1]) {
// memmap[i - 1].len += memmap[i].len;
//
// memmap[null_index_ptr].len = memmap[i - 1].len;
// memmap[null_index_ptr].base = memmap[i - 1].base;
// memmap[null_index_ptr].typ = memmap[i - 1].typ;
//
// null_index_ptr += 1;
// continue;
// }
// }
//
// return &mut memmap[0..null_index_ptr];
// }
pub static PHYSICAL_MEMORY_MANAGER: Lazy<PhysicalMemoryManager> = pub static PHYSICAL_MEMORY_MANAGER: Lazy<PhysicalMemoryManager> =
Lazy::new(|| PhysicalMemoryManager::new()); Lazy::new(|| PhysicalMemoryManager::new());
@@ -214,34 +159,3 @@ impl LabelBytes for usize {
} }
} }
} }
pub fn test_page_frame_allocator(iterations: usize) {
crate::log_info!("Testing page allocator");
for i in 0..iterations {
let a = crate::mem::PHYSICAL_MEMORY_MANAGER.alloc(20);
let percent_complete = (i as f64 / iterations as f64) * 100.0;
crate::print!("[ ");
for j in 0..50 {
if (j * 2) < percent_complete as usize {
crate::print!("#");
} else {
crate::print!(".");
}
}
crate::print!(" ] {percent_complete:.1}%\r");
if a.is_err() {
crate::log_error!(
"Page frame allocator failed to allocate {iterations} pages on iteration {i}!"
);
break;
}
crate::mem::PHYSICAL_MEMORY_MANAGER.dealloc(a.unwrap(), 20);
}
crate::log_ok!("Page frame allocator successfully allocated {iterations} pages!");
}

42
src/usr/shell.rs Normal file → Executable file
View File

@@ -1,15 +1,17 @@
use core::sync::atomic::{AtomicU8, Ordering};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use crate::drivers::keyboard::set_leds; use crate::drivers::keyboard::set_leds;
use crate::{drivers::keyboard::Key, libs::mutex::Mutex}; use crate::drivers::keyboard::Key;
struct ModStatus { struct ModStatus {
pub win: bool, // first bit pub win: bool, // first bit (0000_0001)
pub ctrl: bool, // second bit pub ctrl: bool, // second bit (0000_0010)
pub alt: bool, // third bit pub alt: bool, // third bit (0000_0100)
pub shift: bool, // forth bit pub shift: bool, // forth bit (0000_1000)
pub caps: bool, // fifth bit pub caps: bool, // fifth bit (0001_0000)
pub num_lock: bool, // sixth bit pub num_lock: bool, // sixth bit (0010_0000)
pub scr_lock: bool, // (possibly unnecessary) seventh bit pub scr_lock: bool, // (possibly unnecessary) seventh bit (0100_0000)
} }
impl ModStatus { impl ModStatus {
@@ -41,21 +43,21 @@ impl ModStatus {
} }
struct ModStatusBits { struct ModStatusBits {
status: Mutex<u8>, status: AtomicU8,
led_status: Mutex<u8>, led_status: AtomicU8,
} }
impl ModStatusBits { impl ModStatusBits {
#[inline] #[inline]
const fn new() -> Self { const fn new() -> Self {
return Self { return Self {
status: Mutex::new(0u8), status: AtomicU8::new(0u8),
led_status: Mutex::new(0u8), led_status: AtomicU8::new(0u8),
}; };
} }
fn get_status(&self) -> ModStatus { fn get_status(&self) -> ModStatus {
let status = self.status.lock().read(); let status = self.status.load(Ordering::SeqCst);
return ModStatus { return ModStatus {
win: ((status >> 0) & 1) != 0, win: ((status >> 0) & 1) != 0,
@@ -69,8 +71,7 @@ impl ModStatusBits {
} }
fn set_modifier_key(&self, key: &str, status: bool) { fn set_modifier_key(&self, key: &str, status: bool) {
let mut led_status_lock = self.led_status.lock(); let mut led_status = self.led_status.load(Ordering::SeqCst);
let led_status = led_status_lock.write();
let mut mod_status = self.get_status(); let mut mod_status = self.get_status();
match key { match key {
@@ -79,15 +80,15 @@ impl ModStatusBits {
"alt" => mod_status.alt = status, "alt" => mod_status.alt = status,
"shift" => mod_status.shift = status, "shift" => mod_status.shift = status,
"caps" => { "caps" => {
*led_status ^= 0b00000100; led_status ^= 0b00000100;
mod_status.caps = status mod_status.caps = status
} }
"num_lock" => { "num_lock" => {
*led_status ^= 0b00000010; led_status ^= 0b00000010;
mod_status.num_lock = status mod_status.num_lock = status
} }
"scr_lock" => { "scr_lock" => {
*led_status ^= 0b00000100; led_status ^= 0b00000100;
mod_status.scr_lock = status mod_status.scr_lock = status
} }
_ => return, _ => return,
@@ -95,10 +96,11 @@ impl ModStatusBits {
// set Keyboard led (caps, num lock, scroll lock) // set Keyboard led (caps, num lock, scroll lock)
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
set_leds(*led_status); set_leds(led_status);
self.led_status.store(led_status, Ordering::SeqCst);
let new_value = mod_status.to_byte(); let new_value = mod_status.to_byte();
*self.status.lock().write() = new_value; self.status.store(new_value, Ordering::SeqCst);
} }
} }

33
src/usr/tty.rs Normal file → Executable file
View File

@@ -1,4 +1,4 @@
use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; use core::sync::atomic::{AtomicU16, AtomicU32, AtomicU8, Ordering};
use alloc::{ use alloc::{
alloc::{alloc, dealloc}, alloc::{alloc, dealloc},
@@ -23,7 +23,7 @@ pub struct Console {
columns: AtomicU16, columns: AtomicU16,
rows: AtomicU16, rows: AtomicU16,
pub cursor: Cursor, pub cursor: Cursor,
feature_bits: Mutex<u8>, feature_bits: AtomicU8,
pub second_buffer: Mutex<Option<crate::drivers::video::Framebuffer>>, pub second_buffer: Mutex<Option<crate::drivers::video::Framebuffer>>,
} }
@@ -41,7 +41,7 @@ impl Console {
columns: AtomicU16::new(0), columns: AtomicU16::new(0),
rows: AtomicU16::new(0), rows: AtomicU16::new(0),
cursor: Cursor::new(), cursor: Cursor::new(),
feature_bits: Mutex::new(0b00000000), feature_bits: AtomicU8::new(0b00000000),
second_buffer: Mutex::new(None), second_buffer: Mutex::new(None),
} }
} }
@@ -52,18 +52,27 @@ impl Console {
// Enable serial if it initialized correctly // Enable serial if it initialized correctly
if crate::drivers::serial::POISONED.load(Ordering::SeqCst) == false { if crate::drivers::serial::POISONED.load(Ordering::SeqCst) == false {
*self.feature_bits.lock().write() |= 1 << 1; self.feature_bits.store(
self.feature_bits.load(Ordering::SeqCst) | 1 << 1,
Ordering::SeqCst,
);
} }
// Enable graphical output // Enable graphical output
if framebuffer.is_some() { if framebuffer.is_some() {
*self.feature_bits.lock().write() |= 1; self.feature_bits.store(
self.feature_bits.load(Ordering::SeqCst) | 1,
Ordering::SeqCst,
);
} else { } else {
return; return;
} }
if back_buffer_region.is_some() { if back_buffer_region.is_some() {
*self.feature_bits.lock().write() |= 1 << 2; self.feature_bits.store(
self.feature_bits.load(Ordering::SeqCst) | 1 << 2,
Ordering::SeqCst,
);
let mut back_buffer = crate::drivers::video::get_framebuffer().unwrap(); let mut back_buffer = crate::drivers::video::get_framebuffer().unwrap();
back_buffer.pointer = back_buffer_region.unwrap(); back_buffer.pointer = back_buffer_region.unwrap();
@@ -92,9 +101,11 @@ impl Console {
} }
pub fn get_features(&self) -> ConsoleFeatures { pub fn get_features(&self) -> ConsoleFeatures {
let graphical_output = ((*self.feature_bits.lock().read()) & 0x01) != 0; let feature_bits = self.feature_bits.load(Ordering::SeqCst);
let serial_output = ((*self.feature_bits.lock().read()) & 0x02) != 0;
let doubled_buffered = ((*self.feature_bits.lock().read()) & 0x04) != 0; let graphical_output = (feature_bits & 0x01) != 0;
let serial_output = (feature_bits & 0x02) != 0;
let doubled_buffered = (feature_bits & 0x04) != 0;
return ConsoleFeatures { return ConsoleFeatures {
_reserved: [0; 6], _reserved: [0; 6],
@@ -677,7 +688,9 @@ pub fn exec(command: &str) {
return; return;
} }
let file = crate::drivers::fs::vfs::VFS_INSTANCES.lock().read()[0].open(&args[0]); let vfs_lock = crate::drivers::fs::vfs::VFS_INSTANCES.lock();
let file = vfs_lock.read()[0].open(&args[0]);
if file.is_err() { if file.is_err() {
println!("read: Unable to read file!"); println!("read: Unable to read file!");