working acpi table parsing
This commit is contained in:
43
Makefile
43
Makefile
@@ -4,9 +4,12 @@ ISO_PARTITION_TYPE ?= GPT
|
|||||||
MODE ?= release
|
MODE ?= release
|
||||||
ARCH ?= x86_64
|
ARCH ?= x86_64
|
||||||
MEMORY ?= 512M
|
MEMORY ?= 512M
|
||||||
|
# In MB
|
||||||
|
ISO_SIZE ?= 256
|
||||||
QEMU_OPTS ?=
|
QEMU_OPTS ?=
|
||||||
MKSQUASHFS_OPTS ?=
|
MKSQUASHFS_OPTS ?=
|
||||||
GDB ?=
|
GDB ?=
|
||||||
|
ESP_BITS ?= 16
|
||||||
|
|
||||||
ISO_PATH = ${ARTIFACTS_PATH}/iso_root
|
ISO_PATH = ${ARTIFACTS_PATH}/iso_root
|
||||||
INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs
|
INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs
|
||||||
@@ -62,6 +65,7 @@ prepare-bin-files:
|
|||||||
mkdir -p ${ARTIFACTS_PATH}
|
mkdir -p ${ARTIFACTS_PATH}
|
||||||
mkdir -p ${ISO_PATH}
|
mkdir -p ${ISO_PATH}
|
||||||
mkdir -p ${INITRAMFS_PATH}
|
mkdir -p ${INITRAMFS_PATH}
|
||||||
|
mkdir -p ${ARTIFACTS_PATH}/mnt
|
||||||
|
|
||||||
copy-initramfs-files:
|
copy-initramfs-files:
|
||||||
echo "Hello World from Initramfs" > ${INITRAMFS_PATH}/example.txt
|
echo "Hello World from Initramfs" > ${INITRAMFS_PATH}/example.txt
|
||||||
@@ -87,6 +91,8 @@ run-scripts:
|
|||||||
python scripts/font.py
|
python scripts/font.py
|
||||||
mv scripts/font.psf ${INITRAMFS_PATH}/
|
mv scripts/font.psf ${INITRAMFS_PATH}/
|
||||||
|
|
||||||
|
# python scripts/initramfs-test.py 1000 ${INITRAMFS_PATH}/
|
||||||
|
|
||||||
copy-iso-files:
|
copy-iso-files:
|
||||||
# Limine files
|
# Limine files
|
||||||
mkdir -p ${ISO_PATH}/boot/limine
|
mkdir -p ${ISO_PATH}/boot/limine
|
||||||
@@ -109,35 +115,40 @@ copy-iso-files:
|
|||||||
|
|
||||||
partition-iso: copy-iso-files
|
partition-iso: copy-iso-files
|
||||||
# Make empty ISO of 64M in size
|
# 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)
|
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
|
parted -s ${IMAGE_PATH} mklabel gpt
|
||||||
# Then a second partition spanning the rest of the disk
|
parted -s ${IMAGE_PATH} mkpart ESP fat${ESP_BITS} 2048s 34815s
|
||||||
sgdisk ${IMAGE_PATH} -n 1:2048:+32768 -t 1:ef00 -n 2
|
|
||||||
else
|
else
|
||||||
# Make ISO a MBR disk with 1 partition starting at sector 2048 that is 32768 sectors, or 16MiB, in size
|
parted -s ${IMAGE_PATH} mklabel msdos
|
||||||
# Then a second partition spanning the rest of the disk
|
parted -s ${IMAGE_PATH} mkpart primary fat${ESP_BITS} 2048s 34815s
|
||||||
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
|
|
||||||
endif
|
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
|
build-iso: partition-iso copy-initramfs-files
|
||||||
ifeq (${ARCH},x86_64)
|
ifeq (${ARCH},x86_64)
|
||||||
# Install the Limine bootloader for bios installs
|
# Install the Limine bootloader for bios installs
|
||||||
./limine/limine bios-install ${IMAGE_PATH}
|
./limine/limine bios-install ${IMAGE_PATH}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Make a FAT32 FS and copy files in /bin/iso_root into the ISO starting at 1M or exactly 2048 sectors
|
sudo losetup -Pf --show ${IMAGE_PATH} > loopback_dev
|
||||||
mformat -F -i ${IMAGE_PATH}@@1M
|
sudo mkfs.fat -F ${ESP_BITS} `cat loopback_dev`p1
|
||||||
mmd -i ${IMAGE_PATH}@@1M ::/EFI ::/EFI/BOOT
|
sudo mount `cat loopback_dev`p1 ${ARTIFACTS_PATH}/mnt
|
||||||
mcopy -i ${IMAGE_PATH}@@1M -s ${ISO_PATH}/* ::/
|
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:
|
compile-bootloader:
|
||||||
@if [ ! -d "limine" ]; then \
|
@if [ ! -d "limine" ]; then \
|
||||||
echo "Cloning Limine into limine/..."; \
|
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 \
|
else \
|
||||||
echo "Folder limine already exists. Skipping clone."; \
|
echo "Folder limine already exists. Skipping clone."; \
|
||||||
fi
|
fi
|
||||||
@@ -182,5 +193,5 @@ line-count:
|
|||||||
cloc --quiet --exclude-dir=bin --csv src/ | tail -n 1 | awk -F, '{print $$5}'
|
cloc --quiet --exclude-dir=bin --csv src/ | tail -n 1 | awk -F, '{print $$5}'
|
||||||
clean:
|
clean:
|
||||||
cargo clean
|
cargo clean
|
||||||
rm -rf bin
|
rm -rf ${ARTIFACTS_PATH}
|
||||||
make clean -C limine
|
make clean -C limine
|
||||||
15
README.md
15
README.md
@@ -23,11 +23,13 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
|
|||||||
- [ ] x86 CPU support
|
- [ ] x86 CPU support
|
||||||
- [ ] armv8 CPU support
|
- [ ] armv8 CPU support
|
||||||
- [ ] File system
|
- [ ] File system
|
||||||
- [ ] Block Device support
|
- [X] FAT file system (read-only rn)
|
||||||
- [X] IDE device support
|
- [ ] Ext2 file system
|
||||||
- [ ] SATA device support
|
- [ ] Block Device support
|
||||||
- [ ] MMC/Nand device support
|
- [X] IDE device support
|
||||||
- [ ] M.2 NVME device support
|
- [ ] SATA device support
|
||||||
|
- [ ] MMC/Nand device support
|
||||||
|
- [ ] M.2 NVME device support
|
||||||
- [ ] Basic shell
|
- [ ] Basic shell
|
||||||
- [X] Basic I/O
|
- [X] Basic I/O
|
||||||
- [ ] Executing Programs from disk
|
- [ ] Executing Programs from disk
|
||||||
@@ -112,10 +114,11 @@ Some Resources I used over the creation of CappuccinOS:
|
|||||||
- Wikipedia on various random things
|
- Wikipedia on various random things
|
||||||
- [Squashfs Binary Format](https://dr-emann.github.io/squashfs/squashfs.html)
|
- [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)
|
- [MOROS](https://github.com/vinc/moros)
|
||||||
- [Felix](https://github.com/mrgian/felix)
|
- [Felix](https://github.com/mrgian/felix)
|
||||||
- [mOS](https://github.com/Moldytzu/mOS)
|
- [mOS](https://github.com/Moldytzu/mOS)
|
||||||
|
- [rust_os](https://github.com/thepowersgang/rust_os/tree/master)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
CappuccinOS is license under the MIT License. Feel free to modify and distribute in accordance with the license.
|
CappuccinOS is license under the MIT License. Feel free to modify and distribute in accordance with the license.
|
||||||
@@ -2,4 +2,10 @@
|
|||||||
This folder is responsible for holding all the scripts that are necessary for building CappuccinOS
|
This folder is responsible for holding all the scripts that are necessary for building CappuccinOS
|
||||||
|
|
||||||
- **demangle-symbols.py**<br/>
|
- **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).
|
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
|
||||||
259
scripts/font.py
259
scripts/font.py
File diff suppressed because one or more lines are too long
37
scripts/initramfs-test.py
Normal file
37
scripts/initramfs-test.py
Normal 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)
|
||||||
@@ -17,8 +17,8 @@ pub fn push_gprs() {
|
|||||||
pub fn pop_gprs() {
|
pub fn pop_gprs() {
|
||||||
unsafe {
|
unsafe {
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
"pop rax", "pop rbx", "pop rcx", "pop rdx", "pop rsi", "pop rdi", "pop rbp", "pop r8",
|
"pop r15", "pop r14", "pop r13", "pop r12", "pop r11", "pop r10", "pop r9", "pop r8",
|
||||||
"pop r9", "pop r10", "pop r11", "pop r12", "pop r13", "pop r14", "pop r15",
|
"pop rbp", "pop rdi", "pop rsi", "pop rdx", "pop rcx", "pop rbx", "pop rax"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ pub fn print_stack_trace(max_frames: usize, rbp: u64) {
|
|||||||
|
|
||||||
let instruction_pointer = unsafe { (*stackframe).rip };
|
let instruction_pointer = unsafe { (*stackframe).rip };
|
||||||
|
|
||||||
|
crate::print!(" {:#X} ", instruction_pointer);
|
||||||
|
|
||||||
let instrcution_info = get_function_name(instruction_pointer);
|
let instrcution_info = get_function_name(instruction_pointer);
|
||||||
|
|
||||||
if let Ok((function_name, function_offset)) = instrcution_info {
|
if let Ok((function_name, function_offset)) = instrcution_info {
|
||||||
|
|||||||
@@ -1,260 +1,264 @@
|
|||||||
use crate::{
|
// TODO: reduce the need to derive(Clone, Copy) everything
|
||||||
libs::{lazy::Lazy, mutex::Mutex},
|
|
||||||
log_error, log_info, log_ok,
|
|
||||||
};
|
|
||||||
use alloc::{sync::Arc, vec::Vec};
|
|
||||||
use limine::RsdpRequest;
|
|
||||||
|
|
||||||
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)]
|
#[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],
|
signature: [u8; 8],
|
||||||
checksum: u8,
|
checksum: u8,
|
||||||
oem_id: [u8; 6],
|
oem_id: [u8; 6],
|
||||||
revision: u8,
|
revision: u8,
|
||||||
rsdt_address: u32,
|
rsdt_addr: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
struct Xsdp {
|
struct XSDP {
|
||||||
|
rsdp: RSDP,
|
||||||
|
|
||||||
length: u32,
|
length: u32,
|
||||||
xsdt_address: u64,
|
xsdt_addr: u64,
|
||||||
extended_checksum: u8,
|
ext_checksum: u8,
|
||||||
reserved: [u8; 3],
|
_reserved: [u8; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Acpi {
|
#[repr(C, packed)]
|
||||||
tables: Arc<[*const u8]>,
|
#[derive(Clone, Copy, Debug)]
|
||||||
entries: usize,
|
struct RSDT {
|
||||||
v2: bool,
|
pointers: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Acpi {
|
#[repr(C, packed)]
|
||||||
fn has_signature(&self, table_index: usize, signature: &str) -> bool {
|
#[derive(Clone, Copy, Debug)]
|
||||||
unsafe {
|
struct XSDT {
|
||||||
let sdt_header: &SdtHeader = &*(self.tables[table_index] as *const SdtHeader);
|
pointers: u64,
|
||||||
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,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[repr(C)]
|
enum RootSDT {
|
||||||
struct SdtHeader {
|
RSDT(SDT<RSDT>),
|
||||||
signature: [u8; 4],
|
XSDT(SDT<XSDT>),
|
||||||
length: u32,
|
|
||||||
revision: u8,
|
|
||||||
checksum: u8,
|
|
||||||
oem_id: [u8; 6],
|
|
||||||
oem_table_id: [u8; 8],
|
|
||||||
oem_revision: u32,
|
|
||||||
creator_id: u32,
|
|
||||||
creator_revision: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_rsdt_checksum(table_header: *const SdtHeader) -> bool {
|
impl RootSDT {
|
||||||
let mut sum: u8 = 0;
|
fn header(&self) -> SDTHeader {
|
||||||
|
return match self {
|
||||||
for i in 0..unsafe { (*table_header).length } {
|
&RootSDT::RSDT(RSDT) => RSDT.header,
|
||||||
sum += unsafe { *((table_header as *const u8).add(i as usize)) };
|
&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)]
|
#[repr(C, packed)]
|
||||||
struct RSDT {
|
#[derive(Clone, Copy, Debug)]
|
||||||
h: SdtHeader,
|
struct GenericAddressStructure {
|
||||||
pointer_to_other_sdt: *const u8,
|
address_space: u8,
|
||||||
|
bit_width: u8,
|
||||||
|
bit_offset: u8,
|
||||||
|
access_size: u8,
|
||||||
|
address: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_fadt(root_sdt: *const RSDT) -> Option<SdtHeader> {
|
#[repr(C, packed)]
|
||||||
// unsafe {
|
#[derive(Clone, Copy, Debug)]
|
||||||
// let rsdt = root_sdt.as_ref()?;
|
struct FADT {
|
||||||
// let entries = (rsdt.h.length - core::mem::size_of::<AcpiSdtHeader>() as u32) / 4;
|
firmware_ctrl: u32,
|
||||||
|
dsdt: u32,
|
||||||
|
|
||||||
// let pointer_to_other_sdt =
|
_reserved: u8,
|
||||||
|
|
||||||
// for i in 0..entries {
|
preferred_power_management_profile: u8,
|
||||||
// crate::println!("{i}");
|
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;
|
boot_architecture_flags: u16,
|
||||||
// let h = h_ptr.as_ref()?;
|
|
||||||
// let slice = core::slice::from_raw_parts(h.signature.as_ptr(), 4);
|
|
||||||
|
|
||||||
// let signature = core::str::from_utf8(slice).ok()?;
|
_reserved2: u8,
|
||||||
|
flags: u32,
|
||||||
|
|
||||||
// if signature == "FACP" {
|
reset_reg: GenericAddressStructure,
|
||||||
// return Some(*h_ptr);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // No FACP found
|
reset_value: u8,
|
||||||
// return None;
|
_reserved3: [u8; 3],
|
||||||
// }
|
|
||||||
None
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::drivers::storage::drive::{BlockDevice, GPTPartitionEntry};
|
use crate::drivers::storage::{BlockDevice, GPTPartitionEntry};
|
||||||
|
|
||||||
use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem};
|
use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem};
|
||||||
|
|
||||||
@@ -15,19 +15,23 @@ use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem};
|
|||||||
//
|
//
|
||||||
// Fat Clusters are either one of these types:
|
// Fat Clusters are either one of these types:
|
||||||
//
|
//
|
||||||
// 0x0FFFFFF8 : End Of cluster Chain
|
// | fat12 | fat16 | fat32 | Description |
|
||||||
// 0x0FFFFFF7 : Bad Cluster
|
// |---------------|-----------------|-------------------------|-------------------------------|
|
||||||
// 0x00000001 - 0x0FFFFFEF : In use Cluster
|
// | 0xFF8-0xFFF | 0xFFF8-0xFFFF | 0x0FFFFFF8-0x0FFFFFFF | End Of cluster Chain |
|
||||||
// 0x00000000 : Free Cluster
|
// | 0xFF7 | 0xFFF7 | 0x0FFFFFF7 | Bad Cluster |
|
||||||
|
// | 0x002-0xFEF | 0x0002-0xFFEF | 0x00000002-0x0FFFFFEF | In use Cluster |
|
||||||
|
// | 0x000 | 0x0000 | 0x00000000 | Free Cluster |
|
||||||
|
|
||||||
// End Of Chain
|
// 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)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
enum FatType {
|
enum FatType {
|
||||||
Fat12,
|
Fat12(Fat16EBPB),
|
||||||
Fat16,
|
Fat16(Fat16EBPB),
|
||||||
Fat32,
|
Fat32(Fat32EBPB),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
@@ -47,10 +51,24 @@ pub struct BIOSParameterBlock {
|
|||||||
pub head_count: u16, // 10 00 (16)
|
pub head_count: u16, // 10 00 (16)
|
||||||
pub hidden_sectors: u32, // 00 00 00 00
|
pub hidden_sectors: u32, // 00 00 00 00
|
||||||
pub large_sector_count: u32, // 00 F8 01 00 (129024)
|
pub large_sector_count: u32, // 00 F8 01 00 (129024)
|
||||||
// pub ebpb: [u8; 54],
|
pub ebpb_bytes: [u8; 54],
|
||||||
// ---------------------------------
|
}
|
||||||
// - Extended BIOS Parameter Block -
|
|
||||||
// ---------------------------------
|
// 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 sectors_per_fat_ext: u32, // E1 03 00 00 (993, wtf)
|
||||||
pub flags: [u8; 2], // 00 00
|
pub flags: [u8; 2], // 00 00
|
||||||
pub fat_version: u16, // 00 00
|
pub fat_version: u16, // 00 00
|
||||||
@@ -64,15 +82,12 @@ pub struct BIOSParameterBlock {
|
|||||||
pub volume_id: u32, // Varies
|
pub volume_id: u32, // Varies
|
||||||
pub volume_label: [u8; 11], // "NO NAME "
|
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)
|
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)]
|
#[repr(C, packed)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FSInfo {
|
pub struct FSInfo {
|
||||||
pub lead_signature: u32,
|
pub lead_signature: u32,
|
||||||
_reserved: [u8; 480],
|
|
||||||
pub mid_signature: u32,
|
pub mid_signature: u32,
|
||||||
pub last_known_free_cluster: u32,
|
pub last_known_free_cluster: u32,
|
||||||
pub look_for_free_clusters: u32,
|
pub look_for_free_clusters: u32,
|
||||||
@@ -83,7 +98,6 @@ pub struct FSInfo {
|
|||||||
impl FSInfo {
|
impl FSInfo {
|
||||||
pub fn from_bytes(bytes: Arc<[u8]>) -> Self {
|
pub fn from_bytes(bytes: Arc<[u8]>) -> Self {
|
||||||
let lead_signature = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
|
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 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 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());
|
let look_for_free_clusters = u32::from_le_bytes(bytes[492..496].try_into().unwrap());
|
||||||
@@ -92,7 +106,6 @@ impl FSInfo {
|
|||||||
|
|
||||||
return Self {
|
return Self {
|
||||||
lead_signature,
|
lead_signature,
|
||||||
_reserved,
|
|
||||||
mid_signature,
|
mid_signature,
|
||||||
last_known_free_cluster,
|
last_known_free_cluster,
|
||||||
look_for_free_clusters,
|
look_for_free_clusters,
|
||||||
@@ -150,7 +163,7 @@ pub struct FatFs<'a> {
|
|||||||
drive: &'a dyn BlockDevice,
|
drive: &'a dyn BlockDevice,
|
||||||
partition: GPTPartitionEntry,
|
partition: GPTPartitionEntry,
|
||||||
// FAT info
|
// FAT info
|
||||||
fs_info: FSInfo,
|
fs_info: Option<FSInfo>,
|
||||||
fat: Option<Arc<[u32]>>,
|
fat: Option<Arc<[u32]>>,
|
||||||
bpb: BIOSParameterBlock,
|
bpb: BIOSParameterBlock,
|
||||||
fat_start: u64,
|
fat_start: u64,
|
||||||
@@ -165,56 +178,12 @@ impl<'a> FatFs<'a> {
|
|||||||
.read(partition.start_sector, 1)
|
.read(partition.start_sector, 1)
|
||||||
.expect("Failed to read FAT32 BIOS Parameter Block!");
|
.expect("Failed to read FAT32 BIOS Parameter Block!");
|
||||||
|
|
||||||
let bpb = unsafe { *(bpb_bytes.clone().as_ptr() as *const BIOSParameterBlock) };
|
let bpb = unsafe { *(bpb_bytes.as_ptr().cast::<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 (total_sectors, fat_size) = if bpb.total_sectors == 0 {
|
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 {
|
} else {
|
||||||
(bpb.total_sectors as u32, bpb.sectors_per_fat as u32)
|
(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 total_clusters = total_data_sectors / bpb.sectors_per_cluster as u32;
|
||||||
|
|
||||||
let fat_type = if total_clusters < 4085 {
|
let fat_type = if total_clusters < 4085 {
|
||||||
FatType::Fat12
|
FatType::Fat12(unsafe { *bpb.ebpb_bytes.as_ptr().cast::<Fat16EBPB>() })
|
||||||
} else if total_clusters < 65525 {
|
} else if total_clusters < 65525 {
|
||||||
FatType::Fat16
|
FatType::Fat16(unsafe { *bpb.ebpb_bytes.as_ptr().cast::<Fat16EBPB>() })
|
||||||
} else {
|
} 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 {
|
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,
|
_ => 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;
|
let cluster_size = bpb.sectors_per_cluster as usize * 512;
|
||||||
|
|
||||||
return Ok(Self {
|
return Ok(Self {
|
||||||
@@ -379,45 +432,66 @@ impl<'a> FatFs<'a> {
|
|||||||
+ (self.bpb.fat_count as usize * fat_size)
|
+ (self.bpb.fat_count as usize * fat_size)
|
||||||
+ root_dir_sectors as usize;
|
+ root_dir_sectors as usize;
|
||||||
|
|
||||||
return ((cluster - 2) as isize * self.bpb.sectors_per_cluster as isize) as usize
|
return ((((cluster.wrapping_sub(2)) as isize)
|
||||||
+ first_data_sector;
|
.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 {
|
fn get_next_cluster(&self, cluster: usize) -> u32 {
|
||||||
if crate::KERNEL_FEATURES.fat_in_mem {
|
if crate::KERNEL_FEATURES.fat_in_mem {
|
||||||
return match self.fat_type {
|
return match self.fat_type {
|
||||||
FatType::Fat12 => {
|
FatType::Fat12(_) => self.fat.as_ref().unwrap()[cluster] & 0x0FFF,
|
||||||
todo!();
|
FatType::Fat16(_) => self.fat.as_ref().unwrap()[cluster] & 0xFFFF,
|
||||||
}
|
FatType::Fat32(_) => self.fat.as_ref().unwrap()[cluster] & 0x0FFFFFFF,
|
||||||
FatType::Fat16 => {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
FatType::Fat32 => self.fat.as_ref().unwrap()[cluster] & 0x0FFFFFFF,
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
let fat_entry_size = match self.fat_type {
|
let fat_entry_size = match self.fat_type {
|
||||||
FatType::Fat12 => 1, // 12 bits per entry
|
FatType::Fat12(_) => 2, // 12 bits per entry
|
||||||
FatType::Fat16 => 2, // 16 bits per entry
|
FatType::Fat16(_) => 2, // 16 bits per entry
|
||||||
FatType::Fat32 => 4, // "32" bits per entry
|
FatType::Fat32(_) => 4, // 28S bits per entry
|
||||||
};
|
};
|
||||||
let entry_offset = cluster * fat_entry_size;
|
let entry_offset = cluster * fat_entry_size;
|
||||||
let entry_offset_in_sector = entry_offset % 512;
|
let entry_offset_in_sector = entry_offset % 512;
|
||||||
|
|
||||||
|
// needs two incase we "straddle a sector"
|
||||||
let sector_data = self
|
let sector_data = self
|
||||||
.drive
|
.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!");
|
.expect("Failed to read from FAT!");
|
||||||
|
|
||||||
match self.fat_type {
|
match self.fat_type {
|
||||||
FatType::Fat12 => {
|
FatType::Fat12(_) => {
|
||||||
todo!();
|
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 => {
|
FatType::Fat16(_) => {
|
||||||
todo!();
|
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
|
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()
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
return u32::from_le_bytes(cluster_entry_bytes) & 0x0FFFFFFF;
|
return u32::from_le_bytes(cluster_entry_bytes) & 0x0FFFFFFF;
|
||||||
@@ -430,7 +504,13 @@ impl<'a> FatFs<'a> {
|
|||||||
impl<'a> VfsFileSystem for FatFs<'a> {
|
impl<'a> VfsFileSystem for FatFs<'a> {
|
||||||
fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> {
|
fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> {
|
||||||
let path_componenets: Vec<&str> = path.trim_start_matches('/').split('/').collect();
|
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 {
|
for path in path_componenets {
|
||||||
let file_entry: FileEntry = self.find_entry_in_directory(current_cluster, path)?;
|
let file_entry: FileEntry = self.find_entry_in_directory(current_cluster, path)?;
|
||||||
@@ -497,8 +577,22 @@ impl<'a> VfsFile for FatFile<'a> {
|
|||||||
|
|
||||||
cluster = self.fat_fs.get_next_cluster(cluster as usize);
|
cluster = self.fat_fs.get_next_cluster(cluster as usize);
|
||||||
|
|
||||||
if cluster >= EOC {
|
match self.fat_fs.fat_type {
|
||||||
break;
|
FatType::Fat12(_) => {
|
||||||
|
if cluster >= EOC_12 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FatType::Fat16(_) => {
|
||||||
|
if cluster >= EOC_16 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FatType::Fat32(_) => {
|
||||||
|
if cluster >= EOC_32 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -238,12 +238,13 @@ impl InflateContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.ring.data[self.ring.pointer] = byte;
|
self.ring.data[self.ring.pointer] = byte;
|
||||||
self.output_buf.push(byte);
|
|
||||||
self.ring.pointer += 1;
|
self.ring.pointer += 1;
|
||||||
|
self.output_buf.push(byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek(&mut self, offset: usize) -> u8 {
|
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<(), ()> {
|
fn uncompressed(&mut self) -> Result<(), ()> {
|
||||||
|
|||||||
@@ -211,9 +211,7 @@ impl Squashfs<'_> {
|
|||||||
&inode_table[inode_offset..],
|
&inode_table[inode_offset..],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => panic!("Unsupported or unknown inode file type {inode_file_type:?}!"),
|
||||||
panic!("Unsupported or unknown inode file type {inode_file_type:?}!")
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,12 +6,12 @@ use crate::{
|
|||||||
arch::io::{inb, insw, inw, outb, outsw},
|
arch::io::{inb, insw, inw, outb, outsw},
|
||||||
drivers::{
|
drivers::{
|
||||||
fs::fat,
|
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;
|
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
|
(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 {
|
let mbr_partitions = mbr_sector.partitions();
|
||||||
panic!("First sector is not MBR");
|
|
||||||
|
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");
|
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];
|
let mut array = [0u8; 512];
|
||||||
array.copy_from_slice(&gpt_sector[..512]);
|
array.copy_from_slice(&gpt_sector[..512]);
|
||||||
|
|
||||||
let mut signature = [0u8; 8];
|
let gpt = GPTHeader::new(&array);
|
||||||
signature.copy_from_slice(&gpt_sector[0..8]);
|
|
||||||
|
|
||||||
if &signature != b"EFI PART" {
|
|
||||||
panic!("MBR Disk is unsupported!")
|
|
||||||
}
|
|
||||||
|
|
||||||
let gpt = GPTBlock::new(&array);
|
|
||||||
|
|
||||||
let mut partitions: Vec<GPTPartitionEntry> =
|
let mut partitions: Vec<GPTPartitionEntry> =
|
||||||
Vec::with_capacity(gpt.partition_entry_count as usize);
|
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 {
|
for i in 0..gpt.partition_entry_count {
|
||||||
let entry_offset = (i * gpt.partition_entry_size) as usize;
|
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()
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut is_zero = true;
|
let partition_type_guid = Uuid::from(partition_type_guid_bytes);
|
||||||
|
|
||||||
for &j in partition_type_guid.iter() {
|
if partition_type_guid == "00000000-0000-0000-0000-000000000000 " {
|
||||||
if j != 0 {
|
|
||||||
is_zero = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_zero {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let unique_partition_guid: [u8; 16] = partition_sector
|
let unique_partition_guid_bytes: [u8; 16] = partition_sector
|
||||||
[entry_offset + 16..entry_offset + 32]
|
[entry_offset + 16..entry_offset + 32]
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let unique_partition_guid = Uuid::from(unique_partition_guid_bytes);
|
||||||
|
|
||||||
let start_sector = u64::from_le_bytes(
|
let start_sector = u64::from_le_bytes(
|
||||||
partition_sector[entry_offset + 32..entry_offset + 40]
|
partition_sector[entry_offset + 32..entry_offset + 40]
|
||||||
.try_into()
|
.try_into()
|
||||||
@@ -661,6 +655,10 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for &partition in partitions.iter() {
|
for &partition in partitions.iter() {
|
||||||
|
if partition.partition_type_guid != "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let fat_fs = fat::FatFs::new(drive, partition);
|
let fat_fs = fat::FatFs::new(drive, partition);
|
||||||
|
|
||||||
if fat_fs.is_err() {
|
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(
|
let vfs = crate::drivers::fs::vfs::Vfs::new(
|
||||||
Box::new(fat_fs),
|
Box::new(fat_fs),
|
||||||
&format!("{:?}", partition.partition_type_guid),
|
&format!("{}", partition.partition_type_guid),
|
||||||
);
|
);
|
||||||
|
|
||||||
crate::drivers::fs::vfs::VFS_INSTANCES
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,152 @@
|
|||||||
pub mod drive;
|
|
||||||
pub mod ide;
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use alloc::vec::Vec;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
drivers::fs::{initramfs::INITRAMFS, vfs::VfsFileSystem},
|
drivers::fs::{initramfs::INITRAMFS, vfs::VfsFileSystem},
|
||||||
libs::lazy::Lazy,
|
libs::{lazy::Lazy, mutex::Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
15
src/libs/elf.rs
Normal file
15
src/libs/elf.rs
Normal 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);
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
|
pub mod elf;
|
||||||
pub mod lazy;
|
pub mod lazy;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
|
pub mod oncecell;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
pub mod uuid;
|
||||||
|
|||||||
70
src/libs/oncecell.rs
Normal file
70
src/libs/oncecell.rs
Normal 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
100
src/libs/uuid.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ pub extern "C" fn _start() -> ! {
|
|||||||
|
|
||||||
mem::log_info();
|
mem::log_info();
|
||||||
|
|
||||||
// drivers::acpi::init_acpi();
|
drivers::acpi::init_acpi();
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
drivers::pci::enumerate_pci_bus();
|
drivers::pci::enumerate_pci_bus();
|
||||||
@@ -117,12 +117,14 @@ fn parse_kernel_cmdline() -> KernelFeatures {
|
|||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
let message = format!("{}", info);
|
let message = format!("{}\n", info);
|
||||||
|
|
||||||
for ch in message.chars() {
|
for ch in message.chars() {
|
||||||
write_serial(ch);
|
write_serial(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_error!("{}", info);
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
{
|
{
|
||||||
let rbp: u64;
|
let rbp: u64;
|
||||||
|
|||||||
@@ -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() {
|
pub fn log_info() {
|
||||||
crate::log_info!(
|
crate::log_info!(
|
||||||
"Initialized heap with {} of memory at {:#X}",
|
"Initialized heap with {} of memory at {:#X}",
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ use alloc::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
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,
|
mem::LabelBytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -781,7 +782,28 @@ pub fn exec(command: &str) {
|
|||||||
return;
|
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>) {
|
fn parse_input(input: &str) -> (String, Vec<String>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user