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

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

View File

@@ -88,6 +88,9 @@ else
endif
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
./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:
- rust
- python
- binutils
- sgdisk
- mtools
@@ -65,21 +66,18 @@ Install the dependencies:
<details>
<summary>Arch</summary>
```BASH
sudo pacman -S binutils gptfdisk mtools squashfs-tools
sudo pacman -S binutils gptfdisk mtools squashfs-tools python
# Optionally
sudo pacman -S qemu-system-x86
```
</details>
<details>
<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
# Optionally
sudo apt install qemu
```
</details>
## Usage

View File

@@ -1,4 +1,2 @@
# CappuccinOS/scripts
This folder is responsible for holding all the scripts that are necessary for building CappuccinOS, the list currently includes:
- [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.
This folder is responsible for holding all the scripts that are necessary for building CappuccinOS

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_info!(
"INT: {:x} EIP: {:X}, CS: {:X}, EFLAGS: {:b}",
int,
@@ -38,6 +39,12 @@ pub extern "C" fn exception_handler(int: u64, eip: u64, cs: u64, eflags: u64) ->
eflags
);
// unsafe {
// core::arch::asm!("cli");
// };
crate::arch::stack_trace::print_stack_trace(6);
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 pic;
pub mod stack_trace;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[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,
string::{String, ToString},
sync::Arc,
vec::{self, Vec},
vec::Vec,
};
use crate::drivers::storage::drive::{BlockDevice, GPTPartitionEntry};
@@ -23,6 +23,7 @@ use super::vfs::{VFSDirectory, VFSFile, VFSFileSystem};
// End Of Chain
const EOC: u32 = 0x0FFFFFF8;
#[derive(Debug)]
enum FatType {
Fat12,
Fat16,
@@ -154,6 +155,7 @@ pub struct FATFS<'a> {
fat_start: u64,
fat_type: FatType,
cluster_size: usize,
sectors_per_fat: usize,
}
impl<'a> FATFS<'a> {
@@ -219,6 +221,7 @@ impl<'a> FATFS<'a> {
} else {
(bpb.total_sectors as u32, bpb.sectors_per_fat as u32)
};
let root_dir_sectors =
((bpb.root_directory_count * 32) + (bpb.bytes_per_sector - 1)) / bpb.bytes_per_sector;
let total_data_sectors = total_sectors
@@ -236,6 +239,13 @@ impl<'a> FATFS<'a> {
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;
return Ok(Self {
@@ -247,6 +257,7 @@ impl<'a> FATFS<'a> {
fat_start,
fat_type,
cluster_size,
sectors_per_fat,
});
}
@@ -364,17 +375,17 @@ impl<'a> FATFS<'a> {
}
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)
+ (self.bpb.bytes_per_sector - 1))
/ self.bpb.bytes_per_sector;
let first_data_sector = self.bpb.reserved_sectors as u32
+ (self.bpb.fat_count as u32 * fat_size)
+ root_dir_sectors as u32;
let first_data_sector = self.bpb.reserved_sectors as usize
+ (self.bpb.fat_count as usize * fat_size)
+ root_dir_sectors 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 {

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

@@ -1,11 +1,15 @@
pub mod compressors;
use alloc::vec::Vec;
use limine::ModuleRequest;
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() {
// TODO: Put this stuff in another file?
// TODO: Put the module request stuff in another file?
if MODULE_REQUEST.get_response().get().is_none() {
crate::log_error!("Module request in none!");
return;
@@ -28,6 +32,7 @@ pub fn init() {
initramfs = Some(module);
}
// End TODO
if initramfs.is_none() {
crate::log_error!("Initramfs was not found!");
@@ -44,11 +49,291 @@ pub fn init() {
.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)]
#[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 {
GZIP = 1,
LZMA = 2,
@@ -104,6 +389,7 @@ impl Into<SquashfsCompressionType> for u16 {
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct SquashfsSuperblock {
magic: u32, // 0x73717368
@@ -117,7 +403,9 @@ struct SquashfsSuperblock {
id_count: u16, // 0x01
ver_major: u16, // 0x04
ver_minor: u16, // 0x00
root_inode: u64, // 0x20
root_inode_offset: u16, //
root_inode_block: u32, //
_reserved: u16, // 0x20
bytes_used: u64, // 0x0103
id_table: u64, // 0x00FB
xattr_table: u64, // 0xFFFFFFFFFFFFFFFF
@@ -128,8 +416,8 @@ struct SquashfsSuperblock {
}
impl SquashfsSuperblock {
fn new(bytes: &[u8]) -> Self {
return Self {
fn new(bytes: &[u8]) -> Result<Self, ()> {
let superblock = Self {
magic: u32::from_le_bytes(bytes[0..4].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()),
@@ -141,7 +429,9 @@ impl SquashfsSuperblock {
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_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()),
id_table: u64::from_le_bytes(bytes[48..56].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()),
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 {
// 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_data_blocks =
(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
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 fn enumerate_pci_bus() {
let header_type = read_pci_header_type(0, 0, 0);
if (header_type & 0x80) == 0 {
// 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);
}
for bus in 0..=255 {
check_bus(bus);
}
crate::println!("====== PCI DEVICES ======");
@@ -153,7 +142,7 @@ fn check_bus(bus: 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);
@@ -165,15 +154,12 @@ fn check_device(bus: u8, device: u8) {
let header_type = read_pci_header_type(bus, device, func);
if header_type & 0x80 != 0 {
// It's a multi-function device
func += 1;
for func in 1..8 {
let vendor_id = read_pci_vendor_id(bus, device, func);
while func < 8 {
if read_pci_vendor_id(bus, device, func) != 0xFFFF {
if vendor_id != 0xFFFF {
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 {
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,
],
[

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;
if character as usize > u8::MAX as usize {
character = '?';
character = '\x00'; // rounded question mark
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> {
value: UnsafeCell<Option<T>>,
init_func: Option<F>,
init_func: F,
initialized: AtomicBool,
}
@@ -14,7 +14,7 @@ impl<T, F: Fn() -> T> Lazy<T, F> {
pub const fn new(init_func: F) -> Self {
Lazy {
value: UnsafeCell::new(None),
init_func: Some(init_func),
init_func: init_func,
initialized: AtomicBool::new(false),
}
}
@@ -25,13 +25,12 @@ impl<T, F: Fn() -> T> Deref for Lazy<T, F> {
fn deref(&self) -> &Self::Target {
if !self.initialized.load(Ordering::Acquire) {
if let Some(init_func) = &self.init_func {
let value = init_func();
unsafe {
*(self.value.get()) = Some(value);
}
self.initialized.store(true, Ordering::Release);
let value = (self.init_func)();
unsafe {
*(self.value.get()) = Some(value);
}
self.initialized.store(true, Ordering::Release);
}
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 drivers::serial;
use libs::util::hcf;
use limine::{KernelFileRequest, ModuleRequest};
use limine::KernelFileRequest;
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;
});
// 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> =
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"))]
use crate::drivers::keyboard::set_leds;
use crate::{drivers::keyboard::Key, libs::mutex::Mutex};
use crate::drivers::keyboard::Key;
struct ModStatus {
pub win: bool, // first bit
pub ctrl: bool, // second bit
pub alt: bool, // third bit
pub shift: bool, // forth bit
pub caps: bool, // fifth bit
pub num_lock: bool, // sixth bit
pub scr_lock: bool, // (possibly unnecessary) seventh bit
pub win: bool, // first bit (0000_0001)
pub ctrl: bool, // second bit (0000_0010)
pub alt: bool, // third bit (0000_0100)
pub shift: bool, // forth bit (0000_1000)
pub caps: bool, // fifth bit (0001_0000)
pub num_lock: bool, // sixth bit (0010_0000)
pub scr_lock: bool, // (possibly unnecessary) seventh bit (0100_0000)
}
impl ModStatus {
@@ -41,21 +43,21 @@ impl ModStatus {
}
struct ModStatusBits {
status: Mutex<u8>,
led_status: Mutex<u8>,
status: AtomicU8,
led_status: AtomicU8,
}
impl ModStatusBits {
#[inline]
const fn new() -> Self {
return Self {
status: Mutex::new(0u8),
led_status: Mutex::new(0u8),
status: AtomicU8::new(0u8),
led_status: AtomicU8::new(0u8),
};
}
fn get_status(&self) -> ModStatus {
let status = self.status.lock().read();
let status = self.status.load(Ordering::SeqCst);
return ModStatus {
win: ((status >> 0) & 1) != 0,
@@ -69,8 +71,7 @@ impl ModStatusBits {
}
fn set_modifier_key(&self, key: &str, status: bool) {
let mut led_status_lock = self.led_status.lock();
let led_status = led_status_lock.write();
let mut led_status = self.led_status.load(Ordering::SeqCst);
let mut mod_status = self.get_status();
match key {
@@ -79,15 +80,15 @@ impl ModStatusBits {
"alt" => mod_status.alt = status,
"shift" => mod_status.shift = status,
"caps" => {
*led_status ^= 0b00000100;
led_status ^= 0b00000100;
mod_status.caps = status
}
"num_lock" => {
*led_status ^= 0b00000010;
led_status ^= 0b00000010;
mod_status.num_lock = status
}
"scr_lock" => {
*led_status ^= 0b00000100;
led_status ^= 0b00000100;
mod_status.scr_lock = status
}
_ => return,
@@ -95,10 +96,11 @@ impl ModStatusBits {
// set Keyboard led (caps, num lock, scroll lock)
#[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();
*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::{
alloc::{alloc, dealloc},
@@ -23,7 +23,7 @@ pub struct Console {
columns: AtomicU16,
rows: AtomicU16,
pub cursor: Cursor,
feature_bits: Mutex<u8>,
feature_bits: AtomicU8,
pub second_buffer: Mutex<Option<crate::drivers::video::Framebuffer>>,
}
@@ -41,7 +41,7 @@ impl Console {
columns: AtomicU16::new(0),
rows: AtomicU16::new(0),
cursor: Cursor::new(),
feature_bits: Mutex::new(0b00000000),
feature_bits: AtomicU8::new(0b00000000),
second_buffer: Mutex::new(None),
}
}
@@ -52,18 +52,27 @@ impl Console {
// Enable serial if it initialized correctly
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
if framebuffer.is_some() {
*self.feature_bits.lock().write() |= 1;
self.feature_bits.store(
self.feature_bits.load(Ordering::SeqCst) | 1,
Ordering::SeqCst,
);
} else {
return;
}
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();
back_buffer.pointer = back_buffer_region.unwrap();
@@ -92,9 +101,11 @@ impl Console {
}
pub fn get_features(&self) -> ConsoleFeatures {
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 feature_bits = self.feature_bits.load(Ordering::SeqCst);
let graphical_output = (feature_bits & 0x01) != 0;
let serial_output = (feature_bits & 0x02) != 0;
let doubled_buffered = (feature_bits & 0x04) != 0;
return ConsoleFeatures {
_reserved: [0; 6],
@@ -677,7 +688,9 @@ pub fn exec(command: &str) {
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() {
println!("read: Unable to read file!");