non-working squashfs driver updates, partial stack traces, and more
This commit is contained in:
@@ -7,3 +7,4 @@ 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"]
|
||||||
3
Makefile
3
Makefile
@@ -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}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -65,21 +66,18 @@ 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
|
||||||
|
|||||||
@@ -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.
|
|
||||||
|
|||||||
20
scripts/demangle-symbols.py
Normal file
20
scripts/demangle-symbols.py
Normal 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)
|
||||||
@@ -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)
|
|
||||||
@@ -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
0
src/arch/x86_64/interrupts/mod.rs
Normal file → Executable 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)]
|
||||||
|
|||||||
26
src/arch/x86_common/stack_trace.rs
Normal file
26
src/arch/x86_common/stack_trace.rs
Normal 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
23
src/drivers/fs/fat.rs
Normal file → Executable 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
408
src/drivers/fs/initramfs/mod.rs
Normal file → Executable 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
85
src/drivers/fs/vfs.rs
Normal file → Executable 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
0
src/drivers/keyboard.rs
Normal file → Executable file
29
src/drivers/pci.rs
Normal file → Executable file
29
src/drivers/pci.rs
Normal file → Executable 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
0
src/drivers/storage/ide.rs
Normal file → Executable file
8
src/drivers/video/font.rs
Normal file → Executable file
8
src/drivers/video/font.rs
Normal file → Executable 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
2
src/drivers/video/mod.rs
Normal file → Executable 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
15
src/libs/lazy.rs
Normal file → Executable 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
0
src/libs/mutex.rs
Normal file → Executable file
2
src/main.rs
Normal file → Executable file
2
src/main.rs
Normal file → Executable 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
86
src/mem/mod.rs
Normal file → Executable 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
42
src/usr/shell.rs
Normal file → Executable 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
33
src/usr/tty.rs
Normal file → Executable 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!");
|
||||||
|
|||||||
Reference in New Issue
Block a user