working acpi table parsing

This commit is contained in:
Zoe
2024-01-19 22:58:48 -06:00
parent 361cfc49fe
commit 7b5f42f76a
22 changed files with 1171 additions and 458 deletions

View File

@@ -4,9 +4,12 @@ ISO_PARTITION_TYPE ?= GPT
MODE ?= release
ARCH ?= x86_64
MEMORY ?= 512M
# In MB
ISO_SIZE ?= 256
QEMU_OPTS ?=
MKSQUASHFS_OPTS ?=
GDB ?=
ESP_BITS ?= 16
ISO_PATH = ${ARTIFACTS_PATH}/iso_root
INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs
@@ -62,6 +65,7 @@ prepare-bin-files:
mkdir -p ${ARTIFACTS_PATH}
mkdir -p ${ISO_PATH}
mkdir -p ${INITRAMFS_PATH}
mkdir -p ${ARTIFACTS_PATH}/mnt
copy-initramfs-files:
echo "Hello World from Initramfs" > ${INITRAMFS_PATH}/example.txt
@@ -87,6 +91,8 @@ run-scripts:
python scripts/font.py
mv scripts/font.psf ${INITRAMFS_PATH}/
# python scripts/initramfs-test.py 1000 ${INITRAMFS_PATH}/
copy-iso-files:
# Limine files
mkdir -p ${ISO_PATH}/boot/limine
@@ -109,35 +115,40 @@ copy-iso-files:
partition-iso: copy-iso-files
# Make empty ISO of 64M in size
dd if=/dev/zero of=${IMAGE_PATH} bs=1M count=0 seek=64
dd if=/dev/zero of=${IMAGE_PATH} bs=1M count=0 seek=${ISO_SIZE}
ifeq (${ISO_PARTITION_TYPE},GPT)
# Make ISO a GPT disk with 1 partition starting at sector 2048 that is 32768 sectors, or 16MiB, in size
# Then a second partition spanning the rest of the disk
sgdisk ${IMAGE_PATH} -n 1:2048:+32768 -t 1:ef00 -n 2
parted -s ${IMAGE_PATH} mklabel gpt
parted -s ${IMAGE_PATH} mkpart ESP fat${ESP_BITS} 2048s 34815s
else
# Make ISO a MBR disk with 1 partition starting at sector 2048 that is 32768 sectors, or 16MiB, in size
# Then a second partition spanning the rest of the disk
parted -a none ${IMAGE_PATH} mklabel msdos
parted -a none ${IMAGE_PATH} mkpart primary 2048s 34815s
parted -a none ${IMAGE_PATH} mkpart primary 34816s 100%
parted -a none ${IMAGE_PATH} set 1 boot on
parted -s ${IMAGE_PATH} mklabel msdos
parted -s ${IMAGE_PATH} mkpart primary fat${ESP_BITS} 2048s 34815s
endif
# Make ISO with 1 partition starting at sector 2048 that is 32768 sectors, or 16MiB, in size
# Then a second partition spanning the rest of the disk
parted -s ${IMAGE_PATH} mkpart primary 34816s 100%
parted -s ${IMAGE_PATH} set 1 esp on
build-iso: partition-iso copy-initramfs-files
ifeq (${ARCH},x86_64)
# Install the Limine bootloader for bios installs
./limine/limine bios-install ${IMAGE_PATH}
endif
# Make a FAT32 FS and copy files in /bin/iso_root into the ISO starting at 1M or exactly 2048 sectors
mformat -F -i ${IMAGE_PATH}@@1M
mmd -i ${IMAGE_PATH}@@1M ::/EFI ::/EFI/BOOT
mcopy -i ${IMAGE_PATH}@@1M -s ${ISO_PATH}/* ::/
sudo losetup -Pf --show ${IMAGE_PATH} > loopback_dev
sudo mkfs.fat -F ${ESP_BITS} `cat loopback_dev`p1
sudo mount `cat loopback_dev`p1 ${ARTIFACTS_PATH}/mnt
sudo cp -r ${ISO_PATH}/* ${ARTIFACTS_PATH}/mnt
sync
sudo umount ${ARTIFACTS_PATH}/mnt
sudo losetup -d `cat loopback_dev`
rm -rf loopback_dev
compile-bootloader:
@if [ ! -d "limine" ]; then \
echo "Cloning Limine into limine/..."; \
git clone https://github.com/limine-bootloader/limine.git --branch=v5.x-branch-binary --depth=1; \
git clone https://github.com/limine-bootloader/limine.git --branch=v6.x-branch-binary --depth=1; \
else \
echo "Folder limine already exists. Skipping clone."; \
fi
@@ -182,5 +193,5 @@ line-count:
cloc --quiet --exclude-dir=bin --csv src/ | tail -n 1 | awk -F, '{print $$5}'
clean:
cargo clean
rm -rf bin
rm -rf ${ARTIFACTS_PATH}
make clean -C limine

View File

@@ -23,6 +23,8 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
- [ ] x86 CPU support
- [ ] armv8 CPU support
- [ ] File system
- [X] FAT file system (read-only rn)
- [ ] Ext2 file system
- [ ] Block Device support
- [X] IDE device support
- [ ] SATA device support
@@ -112,10 +114,11 @@ Some Resources I used over the creation of CappuccinOS:
- Wikipedia on various random things
- [Squashfs Binary Format](https://dr-emann.github.io/squashfs/squashfs.html)
And mostly for examples of how people did stuff I used these (projects made by people who actually have a clue what they're doing):
And mostly for examples of how people did stuff I used these (projects made by people who might actually have a clue what they're doing):
- [MOROS](https://github.com/vinc/moros)
- [Felix](https://github.com/mrgian/felix)
- [mOS](https://github.com/Moldytzu/mOS)
- [rust_os](https://github.com/thepowersgang/rust_os/tree/master)
## License
CappuccinOS is license under the MIT License. Feel free to modify and distribute in accordance with the license.

View File

@@ -3,3 +3,9 @@ This folder is responsible for holding all the scripts that are necessary for bu
- **demangle-symbols.py**<br/>
This file takes in a symbols file generated by the `nm` program and outputs a symbol file with the symbol names demangled, it uses my library, [rustc_demangle.py](https://github.com/juls0730/rustc_demangle.py) which is a python port of the Rust symbol demangling library [rustc-demangle](https://github.com/rust-lang/rustc-demangle).
- **font.py**<br/>
This file takes an array of u8 numbers and exports a PC Screen Font file (2.0)
- **initramfs-test.py**
This file generates tons of files in the initramfs directory from huge to small files nested in directories, etc. It's intended to test the squashfs driver

File diff suppressed because one or more lines are too long

37
scripts/initramfs-test.py Normal file
View File

@@ -0,0 +1,37 @@
import os
import random
import string
import sys
def generate_random_string(length: int):
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
def generate_random_data(size: int):
return os.urandom(size)
def create_random_structure(output_dir: str, depth: int, max_depth: int):
if depth >= max_depth:
return
random_dir = generate_random_string(10)
os.makedirs(os.path.join(output_dir, random_dir))
random_file_name = generate_random_string(8)
random_file_path = os.path.join(output_dir, random_dir, random_file_name)
with open(random_file_path, 'wb') as file:
pass
create_random_structure(os.path.join(output_dir, random_dir), depth + 1, max_depth)
if __name__ == "__main__":
if len(sys.argv) < 2 or len(sys.argv) > 3:
print("Usage: initramfs-test.py <iteration num> [output_dir]")
exit(1)
iterations = int(sys.argv[1])
output_dir = sys.argv[2] if len(sys.argv) == 3 else "."
for i in range(iterations):
max_depth = random.randint(0, 3)
create_random_structure(output_dir, 0, max_depth)

View File

@@ -17,8 +17,8 @@ pub fn push_gprs() {
pub fn pop_gprs() {
unsafe {
core::arch::asm!(
"pop rax", "pop rbx", "pop rcx", "pop rdx", "pop rsi", "pop rdi", "pop rbp", "pop r8",
"pop r9", "pop r10", "pop r11", "pop r12", "pop r13", "pop r14", "pop r15",
"pop r15", "pop r14", "pop r13", "pop r12", "pop r11", "pop r10", "pop r9", "pop r8",
"pop rbp", "pop rdi", "pop rsi", "pop rdx", "pop rcx", "pop rbx", "pop rax"
);
}
}

View File

@@ -20,6 +20,8 @@ pub fn print_stack_trace(max_frames: usize, rbp: u64) {
let instruction_pointer = unsafe { (*stackframe).rip };
crate::print!(" {:#X} ", instruction_pointer);
let instrcution_info = get_function_name(instruction_pointer);
if let Ok((function_name, function_offset)) = instrcution_info {

View File

@@ -1,260 +1,264 @@
use crate::{
libs::{lazy::Lazy, mutex::Mutex},
log_error, log_info, log_ok,
};
use alloc::{sync::Arc, vec::Vec};
use limine::RsdpRequest;
// TODO: reduce the need to derive(Clone, Copy) everything
static RSDP_REQUEST: RsdpRequest = RsdpRequest::new(0);
use alloc::{sync::Arc, vec::Vec};
use crate::{
arch::io::{inw, outb},
libs::{lazy::Lazy, mutex::Mutex, oncecell::OnceCell},
log_info,
};
#[repr(C, packed)]
struct Rsdp {
#[derive(Clone, Copy, Debug)]
struct SDTHeader {
pub signature: [u8; 4],
pub length: u32,
pub revision: u8,
pub checksum: u8,
pub oemid: [u8; 6],
pub oem_table_id: [u8; 8],
pub oem_revision: u32,
pub creator_id: u32,
pub creator_revision: u32,
}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug)]
pub struct SDT<T> {
pub header: SDTHeader,
pub inner: T,
}
impl<T: Copy> SDT<T> {
unsafe fn new(pointer: *mut u8) -> Self {
let header = *(pointer.cast::<SDTHeader>());
let inner = *(pointer.add(core::mem::size_of::<SDTHeader>()).cast::<T>());
return Self { header, inner };
}
}
#[repr(C, packed)]
#[derive(Debug)]
struct RSDP {
signature: [u8; 8],
checksum: u8,
oem_id: [u8; 6],
revision: u8,
rsdt_address: u32,
rsdt_addr: u32,
}
#[repr(C, packed)]
struct Xsdp {
struct XSDP {
rsdp: RSDP,
length: u32,
xsdt_address: u64,
extended_checksum: u8,
reserved: [u8; 3],
xsdt_addr: u64,
ext_checksum: u8,
_reserved: [u8; 3],
}
pub struct Acpi {
tables: Arc<[*const u8]>,
entries: usize,
v2: bool,
#[repr(C, packed)]
#[derive(Clone, Copy, Debug)]
struct RSDT {
pointers: u32,
}
impl Acpi {
fn has_signature(&self, table_index: usize, signature: &str) -> bool {
unsafe {
let sdt_header: &SdtHeader = &*(self.tables[table_index] as *const SdtHeader);
let st = core::str::from_utf8_unchecked(&sdt_header.signature);
st == signature
}
}
pub fn list_tables(&self) {
unsafe {
for i in 0..self.entries {
let sdt_header: &SdtHeader = &*(self.tables[i] as *const SdtHeader);
let st = sdt_header.signature;
log_info!("entry {:02}: {:?}", i + 1, sdt_header);
}
}
}
pub fn get_table(&self, signature: &str) -> Option<*const u8> {
for i in 0..self.entries {
if self.has_signature(i, signature) {
return Some(self.tables[i]);
}
}
None
}
}
const RSDP_V1_LENGTH: usize = 20;
const RSDP_V2_EXT_LENGTH: usize = core::mem::size_of::<Rsdp>() - RSDP_V1_LENGTH;
const RSDP_SIG: [u8; 8] = *b"RSD PTR ";
impl Rsdp {
pub fn is_valid(&self) -> bool {
if self.signature != RSDP_SIG {
return false;
}
let bytes = unsafe { core::slice::from_raw_parts(self as *const Rsdp as *const u8, 20) };
let sum = bytes.iter().fold(0u8, |sum, &byte| sum.wrapping_add(byte));
if sum & 0xFF != 0 {
return false;
}
return true;
}
}
impl Xsdp {
pub fn is_valid(&self) -> bool {
let bytes = unsafe { core::slice::from_raw_parts(self as *const Xsdp as *const u8, 20) };
let sum = bytes.iter().fold(0u8, |sum, &byte| sum.wrapping_add(byte));
if sum & 0xFF != 0 {
return false;
}
return true;
}
}
static ACPI: Lazy<Mutex<Acpi>> = Lazy::new(|| {
let acpi = resolve_acpi();
if acpi.is_err() {
panic!("Failed to resolve ACPI!");
}
Mutex::new(acpi.unwrap())
});
pub fn init_acpi() {
let acpi_lock = ACPI.lock();
let acpi = acpi_lock.read();
log_ok!("Successfully initialized ACPI with {} tables", acpi.entries);
acpi.list_tables()
}
#[derive(Debug)]
enum AcpiRootTable {
Rsdp(u32),
Xsdp(u64),
}
impl AcpiRootTable {
pub fn get_from_bootloader() -> Result<Self, ()> {
let rsdp_response = RSDP_REQUEST.get_response().get();
if rsdp_response.is_none() {
log_error!("Failed to initialize ACPI: RSDP not found!");
return Err(());
}
let rsdp_address = &rsdp_response.unwrap().address;
let rsdp_table: &Rsdp = unsafe { &*(rsdp_address.as_ptr().unwrap() as *const Rsdp) };
if !rsdp_table.is_valid() {
log_error!("Failed to initialize ACPI: RSDP was not valid!");
return Err(());
}
if rsdp_table.revision == 2 {
let xsdp_table: &Xsdp = unsafe { &*(rsdp_address.as_ptr().unwrap() as *const Xsdp) };
if !xsdp_table.is_valid() {
log_error!("Failed to initalize ACPI: XSDP was not valid!");
return Err(());
}
return Ok(AcpiRootTable::Xsdp(xsdp_table.xsdt_address));
}
return Ok(AcpiRootTable::Rsdp(rsdp_table.rsdt_address));
}
}
fn resolve_acpi() -> Result<Acpi, ()> {
let root_table = AcpiRootTable::get_from_bootloader()?;
crate::println!("{:?}", root_table);
let (header_addr, ptr_size, ext_table) = match root_table {
AcpiRootTable::Rsdp(addr) => (addr as u64, core::mem::size_of::<u32>(), false),
AcpiRootTable::Xsdp(addr) => (addr, core::mem::size_of::<u64>(), true),
};
let root_header: &SdtHeader = unsafe { &*(header_addr as *const SdtHeader) };
unsafe {
if !ext_table {
if core::str::from_utf8_unchecked(&root_header.signature) != "RSDT" {
log_error!("Invalid root table header, expected RSDT.");
return Err(());
}
} else {
if core::str::from_utf8_unchecked(&root_header.signature) != "XSDT" {
log_error!("Invalid root table header, expected XSDT.");
return Err(());
}
}
}
let mut entries = (root_header.length as usize - core::mem::size_of::<SdtHeader>()) / ptr_size;
if entries > 48 {
log_error!("Expected at most 48 ACPI tables, got {entries}!");
entries = 48;
}
let mut acpi_tables: Vec<*const u8> = Vec::with_capacity(entries);
for i in 0..entries {
let address =
(header_addr + (core::mem::size_of::<SdtHeader>() + i * ptr_size) as u64) as *const u8;
acpi_tables.push(address);
}
crate::println!("{:?} {}", acpi_tables, entries);
return Ok(Acpi {
tables: Arc::from(acpi_tables),
entries,
v2: ext_table,
});
#[repr(C, packed)]
#[derive(Clone, Copy, Debug)]
struct XSDT {
pointers: u64,
}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
struct SdtHeader {
signature: [u8; 4],
length: u32,
revision: u8,
checksum: u8,
oem_id: [u8; 6],
oem_table_id: [u8; 8],
oem_revision: u32,
creator_id: u32,
creator_revision: u32,
enum RootSDT {
RSDT(SDT<RSDT>),
XSDT(SDT<XSDT>),
}
fn check_rsdt_checksum(table_header: *const SdtHeader) -> bool {
let mut sum: u8 = 0;
for i in 0..unsafe { (*table_header).length } {
sum += unsafe { *((table_header as *const u8).add(i as usize)) };
impl RootSDT {
fn header(&self) -> SDTHeader {
return match self {
&RootSDT::RSDT(RSDT) => RSDT.header,
&RootSDT::XSDT(XSDT) => XSDT.header,
};
}
return sum == 0;
fn len(&self) -> usize {
let ptr_size = match self {
&RootSDT::RSDT(_) => 4,
&RootSDT::XSDT(_) => 8,
};
return (self.header().length as usize - core::mem::size_of::<SDTHeader>()) / ptr_size;
}
unsafe fn get(&self, idx: usize) -> *const u8 {
let mut offset = 0;
let root_ptr = match self {
&RootSDT::RSDT(RSDT) => {
let ptrs = RSDT.inner.pointers as *const u8;
assert!(!ptrs.is_null());
ptrs.add(offset)
}
&RootSDT::XSDT(XSDT) => {
let ptrs = XSDT.inner.pointers as *const u8;
assert!(!ptrs.is_null());
ptrs.add(offset)
}
};
for _ in 0..idx {
let header = *root_ptr.add(offset).cast::<SDTHeader>();
offset += header.length as usize;
}
crate::println!("{offset:X?} {idx}");
return root_ptr.add(offset);
}
}
#[derive(Clone, Debug)]
struct ACPI {
root_sdt: RootSDT,
tables: Vec<[u8; 4]>,
}
static ACPI: OnceCell<ACPI> = OnceCell::new();
static RSDP_REQ: limine::RsdpRequest = limine::RsdpRequest::new(0);
fn resolve_acpi() {
let rsdp_ptr = RSDP_REQ.get_response().get();
if rsdp_ptr.is_none() {
panic!("RSDP not found!");
}
let rsdp = unsafe { &*rsdp_ptr.unwrap().address.as_ptr().unwrap().cast::<RSDP>() };
log_info!("RSDP: {rsdp:X?}");
// TODO: validate RSDT
let root_sdt = {
if rsdp.revision == 0 {
RootSDT::RSDT(unsafe { SDT::new(rsdp.rsdt_addr as *mut u8) })
} else {
let xsdt = unsafe { &*rsdp_ptr.unwrap().address.as_ptr().unwrap().cast::<XSDP>() };
RootSDT::XSDT(unsafe { SDT::new(xsdt.xsdt_addr as *mut u8) })
}
};
log_info!("{root_sdt:X?}");
let tables: Vec<[u8; 4]> = (0..root_sdt.len())
.map(|i| {
let sdt_ptr = unsafe { root_sdt.get(i) };
let signature = unsafe { core::slice::from_raw_parts(sdt_ptr, 4) };
let ret = signature.try_into().unwrap();
ret
})
.collect();
let acpi_table = ACPI { root_sdt, tables };
ACPI.set(acpi_table);
}
#[repr(C, packed)]
struct RSDT {
h: SdtHeader,
pointer_to_other_sdt: *const u8,
#[derive(Clone, Copy, Debug)]
struct GenericAddressStructure {
address_space: u8,
bit_width: u8,
bit_offset: u8,
access_size: u8,
address: u8,
}
fn find_fadt(root_sdt: *const RSDT) -> Option<SdtHeader> {
// unsafe {
// let rsdt = root_sdt.as_ref()?;
// let entries = (rsdt.h.length - core::mem::size_of::<AcpiSdtHeader>() as u32) / 4;
#[repr(C, packed)]
#[derive(Clone, Copy, Debug)]
struct FADT {
firmware_ctrl: u32,
dsdt: u32,
// let pointer_to_other_sdt =
_reserved: u8,
// for i in 0..entries {
// crate::println!("{i}");
preferred_power_management_profile: u8,
sci_interrupt: u16,
smi_cmd_port: u32,
acpi_enable: u8,
acpi_disable: u8,
s4biox_req: u8,
pstate_control: u8,
pm1a_event_block: u32,
pm1b_event_block: u32,
pm1a_control_block: u32,
pm1b_control_block: u32,
pm2_control_block: u32,
pm_timer_block: u32,
gpe0_block: u32,
gpe1_block: u32,
pm1_event_length: u8,
pm1_control_length: u8,
pm2_control_length: u8,
pm_timer_length: u8,
gpe0_length: u8,
gpe1_length: u8,
gpe1_base: u8,
c_state_control: u8,
worst_c2_latency: u16,
worst_c3_length: u16,
flush_size: u16,
flush_stride: u16,
duty_offset: u8,
duty_width: u8,
day_alarm: u8,
month_alarm: u8,
century: u8,
// let h_ptr = rsdt.pointer_to_other_sdt[i as usize] as *const AcpiSdtHeader;
// let h = h_ptr.as_ref()?;
// let slice = core::slice::from_raw_parts(h.signature.as_ptr(), 4);
boot_architecture_flags: u16,
// let signature = core::str::from_utf8(slice).ok()?;
_reserved2: u8,
flags: u32,
// if signature == "FACP" {
// return Some(*h_ptr);
// }
// }
reset_reg: GenericAddressStructure,
// // No FACP found
// return None;
// }
None
reset_value: u8,
_reserved3: [u8; 3],
x_firmware_control: u64,
x_dstd: u64,
x_pm1a_event_block: GenericAddressStructure,
x_pm1b_event_block: GenericAddressStructure,
x_pm1a_control_block: GenericAddressStructure,
x_pm1b_control_block: GenericAddressStructure,
x_pm2_control_block: GenericAddressStructure,
x_pm_timer_block: GenericAddressStructure,
x_gpe0_block: GenericAddressStructure,
x_gpe1_block: GenericAddressStructure,
}
pub fn init_acpi() {
resolve_acpi();
let fadt = find_table::<FADT>("FACP").expect("Failed to find FADT");
crate::println!("{fadt:X?}");
}
pub fn find_table<T: Copy>(table_name: &str) -> Option<SDT<T>> {
assert_eq!(table_name.len(), 4);
for (i, table) in ACPI.tables.iter().enumerate() {
if table == table_name.as_bytes() {
let ptr = unsafe { ACPI.root_sdt.get(i).cast::<SDT<T>>() };
crate::println!("Found {table_name} at index {i} {ptr:p}");
let table = unsafe { *ptr };
return Some(table);
}
}
return None;
}

View File

@@ -5,7 +5,7 @@ use alloc::{
vec::Vec,
};
use crate::drivers::storage::drive::{BlockDevice, GPTPartitionEntry};
use crate::drivers::storage::{BlockDevice, GPTPartitionEntry};
use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem};
@@ -15,19 +15,23 @@ use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem};
//
// Fat Clusters are either one of these types:
//
// 0x0FFFFFF8 : End Of cluster Chain
// 0x0FFFFFF7 : Bad Cluster
// 0x00000001 - 0x0FFFFFEF : In use Cluster
// 0x00000000 : Free Cluster
// | fat12 | fat16 | fat32 | Description |
// |---------------|-----------------|-------------------------|-------------------------------|
// | 0xFF8-0xFFF | 0xFFF8-0xFFFF | 0x0FFFFFF8-0x0FFFFFFF | End Of cluster Chain |
// | 0xFF7 | 0xFFF7 | 0x0FFFFFF7 | Bad Cluster |
// | 0x002-0xFEF | 0x0002-0xFFEF | 0x00000002-0x0FFFFFEF | In use Cluster |
// | 0x000 | 0x0000 | 0x00000000 | Free Cluster |
// End Of Chain
const EOC: u32 = 0x0FFFFFF8;
const EOC_12: u32 = 0x0FF8;
const EOC_16: u32 = 0xFFF8;
const EOC_32: u32 = 0x0FFFFFF8;
#[derive(Clone, Copy, Debug)]
enum FatType {
Fat12,
Fat16,
Fat32,
Fat12(Fat16EBPB),
Fat16(Fat16EBPB),
Fat32(Fat32EBPB),
}
#[repr(C, packed)]
@@ -47,10 +51,24 @@ pub struct BIOSParameterBlock {
pub head_count: u16, // 10 00 (16)
pub hidden_sectors: u32, // 00 00 00 00
pub large_sector_count: u32, // 00 F8 01 00 (129024)
// pub ebpb: [u8; 54],
// ---------------------------------
// - Extended BIOS Parameter Block -
// ---------------------------------
pub ebpb_bytes: [u8; 54],
}
// Fat 12 and Fat 16 EBPB
#[repr(C, packed)]
#[derive(Clone, Copy, Debug)]
pub struct Fat16EBPB {
pub drive_number: u8,
_reserved: u8,
pub signature: u8,
pub volume_id: u32,
pub volume_label: [u8; 11],
pub system_identifier_string: [u8; 8],
}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug)]
pub struct Fat32EBPB {
pub sectors_per_fat_ext: u32, // E1 03 00 00 (993, wtf)
pub flags: [u8; 2], // 00 00
pub fat_version: u16, // 00 00
@@ -64,15 +82,12 @@ pub struct BIOSParameterBlock {
pub volume_id: u32, // Varies
pub volume_label: [u8; 11], // "NO NAME "
pub system_identifier_string: [u8; 8], // Always "FAT32 " but never trust the contents of this string (for some reason)
_boot_code: [u8; 420], // ~~code~~
pub bootable_signature: u16, // 0xAA55
}
#[repr(C, packed)]
#[derive(Debug)]
pub struct FSInfo {
pub lead_signature: u32,
_reserved: [u8; 480],
pub mid_signature: u32,
pub last_known_free_cluster: u32,
pub look_for_free_clusters: u32,
@@ -83,7 +98,6 @@ pub struct FSInfo {
impl FSInfo {
pub fn from_bytes(bytes: Arc<[u8]>) -> Self {
let lead_signature = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
let _reserved = bytes[4..484].try_into().unwrap();
let mid_signature = u32::from_le_bytes(bytes[484..488].try_into().unwrap());
let last_known_free_cluster = u32::from_le_bytes(bytes[488..492].try_into().unwrap());
let look_for_free_clusters = u32::from_le_bytes(bytes[492..496].try_into().unwrap());
@@ -92,7 +106,6 @@ impl FSInfo {
return Self {
lead_signature,
_reserved,
mid_signature,
last_known_free_cluster,
look_for_free_clusters,
@@ -150,7 +163,7 @@ pub struct FatFs<'a> {
drive: &'a dyn BlockDevice,
partition: GPTPartitionEntry,
// FAT info
fs_info: FSInfo,
fs_info: Option<FSInfo>,
fat: Option<Arc<[u32]>>,
bpb: BIOSParameterBlock,
fat_start: u64,
@@ -165,56 +178,12 @@ impl<'a> FatFs<'a> {
.read(partition.start_sector, 1)
.expect("Failed to read FAT32 BIOS Parameter Block!");
let bpb = unsafe { *(bpb_bytes.clone().as_ptr() as *const BIOSParameterBlock) };
let system_identifier = core::str::from_utf8(&bpb.system_identifier_string);
if system_identifier.is_err() {
return Err(());
}
// We're trusting it
if let Ok(system_identifier_string) = system_identifier {
if !system_identifier_string.contains("FAT32") {
return Err(());
}
}
let fsinfo_bytes = drive
.read(partition.start_sector + bpb.fsinfo_sector as u64, 1)
.expect("Failed to read FSInfo sector!");
let fs_info = FSInfo::from_bytes(fsinfo_bytes);
let fat_start = partition.start_sector + bpb.reserved_sectors as u64;
let bytes_per_fat = 512 * bpb.sectors_per_fat_ext as usize;
let mut fat: Option<Arc<[u32]>> = None;
if crate::KERNEL_FEATURES.fat_in_mem {
let mut fat_vec: Vec<u32> = Vec::with_capacity(bytes_per_fat / 4);
for i in 0..(bpb.sectors_per_fat_ext as usize) {
let sector = drive
.read(fat_start + i as u64, 1)
.expect("Failed to read FAT");
for j in 0..(512 / 4) {
fat_vec.push(u32::from_le_bytes(
sector[j * 4..(j * 4 + 4)].try_into().unwrap(),
))
}
}
fat = Some(Arc::from(fat_vec));
} else {
crate::log_info!(
"\033[33mWARNING\033[0m: FAT is not being stored in memory, this feature is experimental and file reads are expected to be slower."
)
}
let bpb = unsafe { *(bpb_bytes.as_ptr().cast::<BIOSParameterBlock>()) };
let (total_sectors, fat_size) = if bpb.total_sectors == 0 {
(bpb.large_sector_count, bpb.sectors_per_fat_ext)
(bpb.large_sector_count, unsafe {
(*bpb.ebpb_bytes.as_ptr().cast::<Fat32EBPB>()).sectors_per_fat_ext
})
} else {
(bpb.total_sectors as u32, bpb.sectors_per_fat as u32)
};
@@ -229,20 +198,104 @@ impl<'a> FatFs<'a> {
let total_clusters = total_data_sectors / bpb.sectors_per_cluster as u32;
let fat_type = if total_clusters < 4085 {
FatType::Fat12
FatType::Fat12(unsafe { *bpb.ebpb_bytes.as_ptr().cast::<Fat16EBPB>() })
} else if total_clusters < 65525 {
FatType::Fat16
FatType::Fat16(unsafe { *bpb.ebpb_bytes.as_ptr().cast::<Fat16EBPB>() })
} else {
FatType::Fat32
FatType::Fat32(unsafe { *bpb.ebpb_bytes.as_ptr().cast::<Fat32EBPB>() })
};
crate::println!("Found {fat_type:?} FS");
let system_ident = match fat_type {
FatType::Fat12(ebpb) => ebpb.system_identifier_string,
FatType::Fat16(ebpb) => ebpb.system_identifier_string,
FatType::Fat32(ebpb) => ebpb.system_identifier_string,
};
let system_identifier = core::str::from_utf8(&system_ident);
if system_identifier.is_err() {
return Err(());
}
if let Ok(system_identifier_string) = system_identifier {
match fat_type {
FatType::Fat12(_) => {
if !system_identifier_string.contains("FAT12") {
return Err(());
}
}
FatType::Fat16(_) => {
if !system_identifier_string.contains("FAT16") {
return Err(());
}
}
FatType::Fat32(_) => {
if !system_identifier_string.contains("FAT32") {
return Err(());
}
}
}
}
let fs_info = match fat_type {
FatType::Fat32(ebpb) => {
let fsinfo_bytes = drive
.read(partition.start_sector + ebpb.fsinfo_sector as u64, 1)
.expect("Failed to read FSInfo sector!");
Some(FSInfo::from_bytes(fsinfo_bytes))
}
_ => None,
};
let fat_start = partition.start_sector + bpb.reserved_sectors as u64;
let sectors_per_fat = match fat_type {
FatType::Fat32 => bpb.sectors_per_fat_ext as usize,
FatType::Fat32(ebpb) => ebpb.sectors_per_fat_ext as usize,
_ => bpb.sectors_per_fat as usize,
};
let bytes_per_fat = 512 * sectors_per_fat;
let mut fat: Option<Arc<[u32]>> = None;
if crate::KERNEL_FEATURES.fat_in_mem {
let cluster_bytes = match fat_type {
FatType::Fat32(_) => 4,
_ => 2,
};
let mut fat_vec: Vec<u32> = Vec::with_capacity(bytes_per_fat / cluster_bytes);
for i in 0..sectors_per_fat {
let sector = drive
.read(fat_start + i as u64, 1)
.expect("Failed to read FAT");
for j in 0..(512 / cluster_bytes) {
match fat_type {
FatType::Fat32(_) => fat_vec.push(u32::from_le_bytes(
sector[j * cluster_bytes..(j * cluster_bytes + cluster_bytes)]
.try_into()
.unwrap(),
)),
_ => fat_vec.push(u16::from_le_bytes(
sector[j * cluster_bytes..(j * cluster_bytes + cluster_bytes)]
.try_into()
.unwrap(),
) as u32),
}
}
}
fat = Some(Arc::from(fat_vec));
} else {
crate::log_info!(
"\033[33mWARNING\033[0m: FAT is not being stored in memory, this feature is experimental and file reads are expected to be slower."
)
}
crate::println!("Found {fat_type:?} FS");
let cluster_size = bpb.sectors_per_cluster as usize * 512;
return Ok(Self {
@@ -379,45 +432,66 @@ impl<'a> FatFs<'a> {
+ (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;
return ((((cluster.wrapping_sub(2)) as isize)
.wrapping_mul(self.bpb.sectors_per_cluster as isize)) as usize)
.wrapping_add(first_data_sector);
}
fn sector_to_cluster(&self, sector: usize) -> usize {
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 usize
+ (self.bpb.fat_count as usize * fat_size)
+ root_dir_sectors as usize;
return (((sector).wrapping_sub(first_data_sector))
.wrapping_div(self.bpb.sectors_per_cluster as usize))
.wrapping_add(2);
}
fn get_next_cluster(&self, cluster: usize) -> u32 {
if crate::KERNEL_FEATURES.fat_in_mem {
return match self.fat_type {
FatType::Fat12 => {
todo!();
}
FatType::Fat16 => {
todo!();
}
FatType::Fat32 => self.fat.as_ref().unwrap()[cluster] & 0x0FFFFFFF,
FatType::Fat12(_) => self.fat.as_ref().unwrap()[cluster] & 0x0FFF,
FatType::Fat16(_) => self.fat.as_ref().unwrap()[cluster] & 0xFFFF,
FatType::Fat32(_) => self.fat.as_ref().unwrap()[cluster] & 0x0FFFFFFF,
};
} else {
let fat_entry_size = match self.fat_type {
FatType::Fat12 => 1, // 12 bits per entry
FatType::Fat16 => 2, // 16 bits per entry
FatType::Fat32 => 4, // "32" bits per entry
FatType::Fat12(_) => 2, // 12 bits per entry
FatType::Fat16(_) => 2, // 16 bits per entry
FatType::Fat32(_) => 4, // 28S bits per entry
};
let entry_offset = cluster * fat_entry_size;
let entry_offset_in_sector = entry_offset % 512;
// needs two incase we "straddle a sector"
let sector_data = self
.drive
.read(self.fat_start + entry_offset as u64 / 512, 1)
.read(self.fat_start + entry_offset as u64 / 512, 2)
.expect("Failed to read from FAT!");
match self.fat_type {
FatType::Fat12 => {
todo!();
FatType::Fat12(_) => {
let cluster_entry_bytes: [u8; 2] = sector_data
[entry_offset_in_sector..entry_offset_in_sector + 2]
.try_into()
.unwrap();
return (u16::from_le_bytes(cluster_entry_bytes) & 0x0FFF) as u32;
}
FatType::Fat16 => {
todo!();
FatType::Fat16(_) => {
let cluster_entry_bytes: [u8; 2] = sector_data
[entry_offset_in_sector..entry_offset_in_sector + 2]
.try_into()
.unwrap();
return (u16::from_le_bytes(cluster_entry_bytes) & 0xFFFF) as u32;
}
FatType::Fat32 => {
FatType::Fat32(_) => {
let cluster_entry_bytes: [u8; 4] = sector_data
[entry_offset_in_sector..=entry_offset_in_sector + 3]
[entry_offset_in_sector..entry_offset_in_sector + 4]
.try_into()
.unwrap();
return u32::from_le_bytes(cluster_entry_bytes) & 0x0FFFFFFF;
@@ -430,7 +504,13 @@ impl<'a> FatFs<'a> {
impl<'a> VfsFileSystem for FatFs<'a> {
fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> {
let path_componenets: Vec<&str> = path.trim_start_matches('/').split('/').collect();
let mut current_cluster = self.bpb.root_dir_cluster as usize;
let mut current_cluster = match self.fat_type {
FatType::Fat32(ebpb) => ebpb.root_dir_cluster as usize,
_ => self.sector_to_cluster(
self.bpb.reserved_sectors as usize
+ (self.bpb.fat_count as usize * self.sectors_per_fat),
),
};
for path in path_componenets {
let file_entry: FileEntry = self.find_entry_in_directory(current_cluster, path)?;
@@ -497,10 +577,24 @@ impl<'a> VfsFile for FatFile<'a> {
cluster = self.fat_fs.get_next_cluster(cluster as usize);
if cluster >= EOC {
match self.fat_fs.fat_type {
FatType::Fat12(_) => {
if cluster >= EOC_12 {
break;
}
}
FatType::Fat16(_) => {
if cluster >= EOC_16 {
break;
}
}
FatType::Fat32(_) => {
if cluster >= EOC_32 {
break;
}
}
}
}
return Ok(Arc::from(file));
}

View File

@@ -238,12 +238,13 @@ impl InflateContext {
}
self.ring.data[self.ring.pointer] = byte;
self.output_buf.push(byte);
self.ring.pointer += 1;
self.output_buf.push(byte);
}
fn peek(&mut self, offset: usize) -> u8 {
self.ring.data[(self.ring.pointer - offset) % 32768]
let index = (self.ring.pointer as usize).wrapping_sub(offset as usize) % 32768;
self.ring.data[index]
}
fn uncompressed(&mut self) -> Result<(), ()> {

View File

@@ -211,9 +211,7 @@ impl Squashfs<'_> {
&inode_table[inode_offset..],
));
}
_ => {
panic!("Unsupported or unknown inode file type {inode_file_type:?}!")
}
_ => panic!("Unsupported or unknown inode file type {inode_file_type:?}!"),
};
}

View File

@@ -1,74 +0,0 @@
use alloc::sync::Arc;
pub trait BlockDevice {
fn sector_count(&self) -> u64;
fn read(&self, sector: u64, sector_count: usize) -> Result<Arc<[u8]>, ()>;
fn write(&self, sector: u64, data: &[u8]) -> Result<(), ()>;
}
#[derive(Clone, Copy, Debug)]
pub struct GPTPartitionEntry {
pub partition_type_guid: [u8; 16],
pub unique_partition_guid: [u8; 16],
pub start_sector: u64,
pub end_sector: u64,
pub attributes: u64,
pub partition_name: [u8; 72],
}
#[derive(Debug)]
pub struct GPTBlock {
pub header: [u8; 8], // 0x45 0x46 0x49 0x20 0x50 0x41 0x52 0x54
pub revision: u32,
pub header_size: u32,
pub header_checksum: u32, // CRC32
_reserved: [u8; 4],
pub header_lba: u64,
pub header_lba_alt: u64,
pub first_usable_block: u64,
pub last_usable_block: u64,
pub guid: [u8; 16],
pub guid_lba: u64,
pub partition_entry_count: u32,
pub partition_entry_size: u32,
pub partition_table_crc: u32,
_reserved2: [u8; 512 - 0x5C],
}
impl GPTBlock {
pub fn new(data: &[u8; 512]) -> Self {
let header = data[0x00..0x08].try_into().unwrap();
let revision = u32::from_le_bytes(data[0x08..0x0C].try_into().unwrap());
let header_size = u32::from_le_bytes(data[0x0C..0x10].try_into().unwrap());
let header_checksum = u32::from_le_bytes(data[0x10..0x14].try_into().unwrap());
let _reserved = data[0x14..0x18].try_into().unwrap();
let header_lba = u64::from_le_bytes(data[0x18..0x20].try_into().unwrap());
let header_lba_alt = u64::from_le_bytes(data[0x20..0x28].try_into().unwrap());
let first_usable_block = u64::from_le_bytes(data[0x28..0x30].try_into().unwrap());
let last_usable_block = u64::from_le_bytes(data[0x30..0x38].try_into().unwrap());
let guid = data[0x38..0x48].try_into().unwrap();
let guid_lba = u64::from_le_bytes(data[0x48..0x50].try_into().unwrap());
let partition_entry_count = u32::from_le_bytes(data[0x50..0x54].try_into().unwrap());
let partition_entry_size = u32::from_le_bytes(data[0x54..0x58].try_into().unwrap());
let partition_table_crc = u32::from_le_bytes(data[0x58..0x5C].try_into().unwrap());
let _reserved2 = data[0x5C..512].try_into().unwrap();
GPTBlock {
header,
revision,
header_size,
header_checksum,
_reserved,
header_lba,
header_lba_alt,
first_usable_block,
last_usable_block,
guid,
guid_lba,
partition_entry_count,
partition_entry_size,
partition_table_crc,
_reserved2,
}
}
}

View File

@@ -6,12 +6,12 @@ use crate::{
arch::io::{inb, insw, inw, outb, outsw},
drivers::{
fs::fat,
storage::drive::{GPTBlock, GPTPartitionEntry},
storage::{GPTHeader, GPTPartitionEntry, MBR},
},
libs::mutex::Mutex,
libs::{mutex::Mutex, uuid::Uuid},
};
use super::drive::BlockDevice;
use super::BlockDevice;
const ATA_SECTOR_SIZE: usize = 512;
@@ -564,12 +564,16 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
(sectors * ATA_SECTOR_SIZE as u64) / 1024 / 1024
);
let mbr_sector = drive.read(0, 1).expect("Failed to read first sector");
let mbr_sector: MBR = (*drive.read(0, 1).expect("Failed to read first sector")).into();
let signature: [u8; 2] = mbr_sector[510..].try_into().unwrap();
if u16::from_le_bytes(mbr_sector.signature) != 0xAA55 {
panic!("MBR is corrupted!");
}
if u16::from_le_bytes(signature[0..2].try_into().unwrap()) != 0xAA55 {
panic!("First sector is not MBR");
let mbr_partitions = mbr_sector.partitions();
if mbr_partitions[0].partition_type != 0xEE {
panic!("MBR disks are unsupported")
}
let gpt_sector = drive.read(1, 1).expect("Failed to read sector 2");
@@ -577,14 +581,7 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
let mut array = [0u8; 512];
array.copy_from_slice(&gpt_sector[..512]);
let mut signature = [0u8; 8];
signature.copy_from_slice(&gpt_sector[0..8]);
if &signature != b"EFI PART" {
panic!("MBR Disk is unsupported!")
}
let gpt = GPTBlock::new(&array);
let gpt = GPTHeader::new(&array);
let mut partitions: Vec<GPTPartitionEntry> =
Vec::with_capacity(gpt.partition_entry_count as usize);
@@ -607,27 +604,24 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
for i in 0..gpt.partition_entry_count {
let entry_offset = (i * gpt.partition_entry_size) as usize;
let partition_type_guid: [u8; 16] = partition_sector[entry_offset..entry_offset + 16]
let partition_type_guid_bytes: [u8; 16] = partition_sector
[entry_offset..entry_offset + 16]
.try_into()
.unwrap();
let mut is_zero = true;
let partition_type_guid = Uuid::from(partition_type_guid_bytes);
for &j in partition_type_guid.iter() {
if j != 0 {
is_zero = false;
}
}
if is_zero {
if partition_type_guid == "00000000-0000-0000-0000-000000000000 " {
continue;
}
let unique_partition_guid: [u8; 16] = partition_sector
let unique_partition_guid_bytes: [u8; 16] = partition_sector
[entry_offset + 16..entry_offset + 32]
.try_into()
.unwrap();
let unique_partition_guid = Uuid::from(unique_partition_guid_bytes);
let start_sector = u64::from_le_bytes(
partition_sector[entry_offset + 32..entry_offset + 40]
.try_into()
@@ -661,6 +655,10 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
}
for &partition in partitions.iter() {
if partition.partition_type_guid != "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" {
continue;
}
let fat_fs = fat::FatFs::new(drive, partition);
if fat_fs.is_err() {
@@ -671,7 +669,7 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
let vfs = crate::drivers::fs::vfs::Vfs::new(
Box::new(fat_fs),
&format!("{:?}", partition.partition_type_guid),
&format!("{}", partition.partition_type_guid),
);
crate::drivers::fs::vfs::VFS_INSTANCES
@@ -692,6 +690,6 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
);
}
crate::println!("{:?}", partitions);
crate::println!("{:X?}", partitions);
}
}

View File

@@ -1,2 +1,152 @@
pub mod drive;
pub mod ide;
use alloc::{sync::Arc, vec::Vec};
use crate::libs::uuid::Uuid;
pub trait BlockDevice {
fn sector_count(&self) -> u64;
fn read(&self, sector: u64, sector_count: usize) -> Result<Arc<[u8]>, ()>;
fn write(&self, sector: u64, data: &[u8]) -> Result<(), ()>;
}
#[derive(Clone, Copy, Debug)]
pub struct MBR {
pub disk_id: [u8; 4],
_reserved: [u8; 2],
pub first_partition: [u8; 16],
pub second_partition: [u8; 16],
pub third_partition: [u8; 16],
pub fourth_partition: [u8; 16],
pub signature: [u8; 2],
}
impl From<&[u8]> for MBR {
fn from(value: &[u8]) -> Self {
let mut offset = 0;
if value.len() >= 512 {
offset = 440;
}
return Self {
disk_id: value[offset..offset + 4].try_into().unwrap(),
_reserved: value[offset + 4..offset + 6].try_into().unwrap(),
first_partition: value[offset + 6..offset + 22].try_into().unwrap(),
second_partition: value[offset + 22..offset + 38].try_into().unwrap(),
third_partition: value[offset + 38..offset + 54].try_into().unwrap(),
fourth_partition: value[offset + 54..offset + 70].try_into().unwrap(),
signature: value[offset + 70..offset + 72].try_into().unwrap(),
};
}
}
impl MBR {
pub fn partitions(&self) -> Arc<[MBRPartition]> {
let mut partitions = Vec::new();
let raw_partitions = [
self.first_partition,
self.second_partition,
self.third_partition,
self.fourth_partition,
];
for partition in raw_partitions.iter() {
// if partition bytes are empty
if partition.iter().filter(|&&x| x > 0).count() == 0 {
break;
}
let partition = MBRPartition {
boot_indicator: partition[0],
partition_start_chs: partition[1..4].try_into().unwrap(),
partition_type: partition[4],
partition_end_chs: partition[4..7].try_into().unwrap(),
partition_start_lba: u32::from_le_bytes(partition[8..12].try_into().unwrap()),
partition_sectors: u32::from_le_bytes(partition[12..16].try_into().unwrap()),
};
partitions.push(partition)
}
return Arc::from(partitions);
}
}
#[derive(Clone, Copy, Debug)]
pub struct MBRPartition {
pub boot_indicator: u8,
pub partition_start_chs: [u8; 3],
pub partition_type: u8,
pub partition_end_chs: [u8; 3],
pub partition_start_lba: u32,
pub partition_sectors: u32,
}
#[derive(Clone, Copy, Debug)]
pub struct GPTPartitionEntry {
pub partition_type_guid: Uuid,
pub unique_partition_guid: Uuid,
pub start_sector: u64,
pub end_sector: u64,
pub attributes: u64,
pub partition_name: [u8; 72],
}
#[derive(Debug)]
pub struct GPTHeader {
pub header: [u8; 8], // 0x45 0x46 0x49 0x20 0x50 0x41 0x52 0x54
pub revision: u32,
pub header_size: u32,
pub header_checksum: u32, // CRC32
_reserved: [u8; 4],
pub header_lba: u64,
pub header_lba_alt: u64,
pub first_usable_block: u64,
pub last_usable_block: u64,
pub guid: Uuid,
pub guid_lba: u64,
pub partition_entry_count: u32,
pub partition_entry_size: u32,
pub partition_table_crc: u32,
}
impl GPTHeader {
pub fn new(data: &[u8]) -> Self {
assert!(data.len() >= 0x5C);
let header = data[0x00..0x08].try_into().unwrap();
let revision = u32::from_le_bytes(data[0x08..0x0C].try_into().unwrap());
let header_size = u32::from_le_bytes(data[0x0C..0x10].try_into().unwrap());
let header_checksum = u32::from_le_bytes(data[0x10..0x14].try_into().unwrap());
let _reserved = data[0x14..0x18].try_into().unwrap();
let header_lba = u64::from_le_bytes(data[0x18..0x20].try_into().unwrap());
let header_lba_alt = u64::from_le_bytes(data[0x20..0x28].try_into().unwrap());
let first_usable_block = u64::from_le_bytes(data[0x28..0x30].try_into().unwrap());
let last_usable_block = u64::from_le_bytes(data[0x30..0x38].try_into().unwrap());
let guid_bytes: [u8; 16] = data[0x38..0x48].try_into().unwrap();
let guid = guid_bytes.try_into().unwrap();
let guid_lba = u64::from_le_bytes(data[0x48..0x50].try_into().unwrap());
let partition_entry_count = u32::from_le_bytes(data[0x50..0x54].try_into().unwrap());
let partition_entry_size = u32::from_le_bytes(data[0x54..0x58].try_into().unwrap());
let partition_table_crc = u32::from_le_bytes(data[0x58..0x5C].try_into().unwrap());
Self {
header,
revision,
header_size,
header_checksum,
_reserved,
header_lba,
header_lba_alt,
first_usable_block,
last_usable_block,
guid,
guid_lba,
partition_entry_count,
partition_entry_size,
partition_table_crc,
}
}
}

View File

@@ -2,7 +2,7 @@ use alloc::vec::Vec;
use crate::{
drivers::fs::{initramfs::INITRAMFS, vfs::VfsFileSystem},
libs::lazy::Lazy,
libs::{lazy::Lazy, mutex::Mutex},
};
#[derive(Debug)]

15
src/libs/elf.rs Normal file
View File

@@ -0,0 +1,15 @@
#[derive(Clone, Copy, Debug)]
pub struct Elf;
pub fn load_elf(bytes: &[u8]) -> Result<Elf, ()> {
if &bytes[0..4] != b"\x74ELF" {
return Err(());
}
if bytes[5] != 0x02 {
// Only support 64-bit ELF files for now
return Err(());
}
return Ok(Elf);
}

View File

@@ -1,5 +1,8 @@
pub mod elf;
pub mod lazy;
pub mod logging;
pub mod math;
pub mod mutex;
pub mod oncecell;
pub mod util;
pub mod uuid;

70
src/libs/oncecell.rs Normal file
View File

@@ -0,0 +1,70 @@
use core::{cell::UnsafeCell, ops::Deref, sync::atomic::AtomicU8};
pub struct OnceCell<T> {
state: AtomicU8,
data: UnsafeCell<Option<T>>,
}
unsafe impl<T> Sync for OnceCell<T> {}
#[repr(u8)]
enum State {
Uninitialized = 0,
Initializing,
Initialized,
}
impl From<u8> for State {
fn from(value: u8) -> Self {
match value {
0 => State::Uninitialized,
1 => State::Initializing,
2 => State::Initialized,
_ => panic!("Invalid state value"),
}
}
}
impl<T> OnceCell<T> {
pub const fn new() -> Self {
return OnceCell {
state: AtomicU8::new(State::Uninitialized as u8),
data: UnsafeCell::new(None),
};
}
pub fn set(&self, new_data: T) {
let current_state = self.state.load(core::sync::atomic::Ordering::SeqCst);
match State::from(current_state) {
State::Uninitialized => {
self.state.store(
State::Initializing as u8,
core::sync::atomic::Ordering::SeqCst,
);
unsafe { *self.data.get() = Some(new_data) };
self.state.store(
State::Initialized as u8,
core::sync::atomic::Ordering::SeqCst,
);
}
_ => panic!("Tried to initialize data that is alread initialized"),
}
}
}
impl<T> Deref for OnceCell<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
if self.state.load(core::sync::atomic::Ordering::SeqCst) == State::Initialized as u8 {
if let Some(value) = unsafe { &*self.data.get() } {
return value;
}
}
panic!("Attempted to access uninitialized data!")
}
}

100
src/libs/uuid.rs Normal file
View File

@@ -0,0 +1,100 @@
use core::fmt::Display;
use alloc::{string::String, vec::Vec};
#[derive(Clone, Copy, Debug)]
pub struct Uuid {
pub a: u32,
pub b: u16,
pub c: u16,
pub d: [u8; 8],
}
impl From<[u8; 16]> for Uuid {
fn from(value: [u8; 16]) -> Self {
let a = u32::from_le_bytes(value[0..4].try_into().unwrap());
let b = u16::from_le_bytes(value[4..6].try_into().unwrap());
let c = u16::from_le_bytes(value[6..8].try_into().unwrap());
let d = value[8..16].try_into().unwrap();
return Self { a, b, c, d };
}
}
impl PartialEq for Uuid {
fn eq(&self, other: &Self) -> bool {
return self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d;
}
}
impl PartialEq<&str> for Uuid {
fn eq(&self, other: &&str) -> bool {
let parts = other.split("-").collect::<Vec<&str>>();
if parts.len() != 5 {
return false;
}
let a = u32::from_str_radix(parts[0], 16);
let b = u16::from_str_radix(parts[1], 16);
let c = u16::from_str_radix(parts[2], 16);
if a.is_err() || b.is_err() || c.is_err() {
return false;
}
let d = {
let part = [parts[3], parts[4]].concat();
let mut d_vec = Vec::new();
let d_parts = part
.trim()
.chars()
.collect::<Vec<_>>()
.chunks(2)
.map(|chunk| chunk.iter().collect())
.collect::<Vec<String>>();
for d_part in d_parts {
let d_part = u8::from_str_radix(&d_part, 16);
if d_part.is_err() {
return false;
}
d_vec.push(d_part.unwrap());
}
d_vec
};
let d: &[u8] = &d;
let d: Result<[u8; 8], _> = d.try_into();
if d.is_err() {
return false;
}
let uuid = Uuid {
a: a.unwrap(),
b: b.unwrap(),
c: c.unwrap(),
d: d.unwrap(),
};
return self == &uuid;
}
}
impl Display for Uuid {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:X}-{:X}-{:X}-", self.a, self.b, self.c)?;
for &byte in &self.d {
write!(f, "{:02X}", byte)?;
}
Ok(())
}
}

View File

@@ -30,7 +30,7 @@ pub extern "C" fn _start() -> ! {
mem::log_info();
// drivers::acpi::init_acpi();
drivers::acpi::init_acpi();
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
drivers::pci::enumerate_pci_bus();
@@ -117,12 +117,14 @@ fn parse_kernel_cmdline() -> KernelFeatures {
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
let message = format!("{}", info);
let message = format!("{}\n", info);
for ch in message.chars() {
write_serial(ch);
}
log_error!("{}", info);
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
let rbp: u64;

View File

@@ -90,6 +90,20 @@ pub static ALLOCATOR: Allocator = Allocator {
}),
};
#[no_mangle]
pub extern "C" fn malloc(size: usize) -> *mut u8 {
let layout = core::alloc::Layout::from_size_align(size, 1).unwrap();
unsafe { ALLOCATOR.alloc(layout) }
}
#[no_mangle]
pub extern "C" fn free(ptr: *mut u8, size: usize) {
let layout = core::alloc::Layout::from_size_align(size, 1).unwrap();
unsafe {
ALLOCATOR.dealloc(ptr, layout);
}
}
pub fn log_info() {
crate::log_info!(
"Initialized heap with {} of memory at {:#X}",

View File

@@ -8,7 +8,8 @@ use alloc::{
};
use crate::{
libs::{lazy::Lazy, mutex::Mutex},
drivers::{fs::vfs::VFS_INSTANCES, serial::write_serial},
libs::{elf::load_elf, lazy::Lazy, mutex::Mutex},
mem::LabelBytes,
};
@@ -781,7 +782,28 @@ pub fn exec(command: &str) {
return;
}
println!("{:?} {:?}", command, args);
// TODO: check a path and not just /bin/
if let Ok(program) = VFS_INSTANCES.lock().read()[0].open(&format!("/bin/{}", command)) {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
let program_bytes = program.read().expect("Failed to read program!");
let program_elf = match load_elf(&program_bytes) {
Ok(elf) => elf,
Err(_) => {
println!("Command not found: {command} (err)");
return;
}
};
crate::arch::push_gprs();
// execute program
crate::println!("{program_elf:?}");
crate::arch::pop_gprs();
}
} else {
println!("Command not found: {command}");
}
}
fn parse_input(input: &str) -> (String, Vec<String>) {