zlib driver & experimental riscv support
this commit adds the last piece to get the initramfs completely finished
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
/target
|
/target
|
||||||
/bin
|
/bin
|
||||||
|
/ovmf
|
||||||
|
|
||||||
# Bochs
|
# Bochs
|
||||||
bx_enh_dbg.ini
|
bx_enh_dbg.ini
|
||||||
|
|||||||
46
Makefile
46
Makefile
@@ -5,13 +5,14 @@ MODE ?= release
|
|||||||
ARCH ?= x86_64
|
ARCH ?= x86_64
|
||||||
MEMORY ?= 512M
|
MEMORY ?= 512M
|
||||||
QEMU_OPTS ?=
|
QEMU_OPTS ?=
|
||||||
MKSQUASHFS_OPTS ?= -no-compression
|
MKSQUASHFS_OPTS ?=
|
||||||
|
|
||||||
ISO_PATH = ${ARTIFACTS_PATH}/iso_root
|
ISO_PATH = ${ARTIFACTS_PATH}/iso_root
|
||||||
INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs
|
INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs
|
||||||
IMAGE_PATH = ${ARTIFACTS_PATH}/${IMAGE_NAME}
|
IMAGE_PATH = ${ARTIFACTS_PATH}/${IMAGE_NAME}
|
||||||
CARGO_OPTS = --target=src/arch/${ARCH}/${ARCH}-unknown-none.json
|
CARGO_OPTS = --target=src/arch/${ARCH}/${ARCH}-unknown-none.json
|
||||||
QEMU_OPTS += -m ${MEMORY} -drive format=raw,file=${IMAGE_PATH}
|
QEMU_OPTS += -m ${MEMORY} -drive id=hd0,format=raw,file=${IMAGE_PATH}
|
||||||
|
LIMINE_BOOT_VARIATION = X64
|
||||||
|
|
||||||
ifeq (${MODE},release)
|
ifeq (${MODE},release)
|
||||||
CARGO_OPTS += --release
|
CARGO_OPTS += --release
|
||||||
@@ -19,9 +20,18 @@ else
|
|||||||
QEMU_OPTS += -s -S
|
QEMU_OPTS += -s -S
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq (${ARCH},riscv64)
|
||||||
|
LIMINE_BOOT_VARIATION := RISCV64
|
||||||
|
UEFI := true
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (${UEFI},)
|
ifneq (${UEFI},)
|
||||||
RUN_OPTS := ovmf
|
RUN_OPTS := ovmf-${ARCH}
|
||||||
QEMU_OPTS += -bios bin/ovmf/OVMF.fd
|
ifeq (${ARCH},riscv64)
|
||||||
|
QEMU_OPTS += -drive if=pflash,unit=0,format=raw,file=bin/ovmf-riscv64/OVMF.fd -M virt
|
||||||
|
else
|
||||||
|
QEMU_OPTS += -bios ovmf/ovmf-${ARCH}/OVMF.fd
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: all check prepare-bin-files copy-initramfs-files compile-initramfs copy-iso-files build-iso compile-bootloader compile-binaries ovmf clean run build line-count
|
.PHONY: all check prepare-bin-files copy-initramfs-files compile-initramfs copy-iso-files build-iso compile-bootloader compile-binaries ovmf clean run build line-count
|
||||||
@@ -44,7 +54,6 @@ prepare-bin-files:
|
|||||||
mkdir -p ${INITRAMFS_PATH}
|
mkdir -p ${INITRAMFS_PATH}
|
||||||
|
|
||||||
copy-initramfs-files:
|
copy-initramfs-files:
|
||||||
# Stub for now ;)
|
|
||||||
echo "Hello World from Initramfs" > ${INITRAMFS_PATH}/example.txt
|
echo "Hello World from Initramfs" > ${INITRAMFS_PATH}/example.txt
|
||||||
echo "Second file for testing" > ${INITRAMFS_PATH}/example2.txt
|
echo "Second file for testing" > ${INITRAMFS_PATH}/example2.txt
|
||||||
mkdir -p ${INITRAMFS_PATH}/firstdir/seconddirbutlonger/
|
mkdir -p ${INITRAMFS_PATH}/firstdir/seconddirbutlonger/
|
||||||
@@ -60,7 +69,7 @@ copy-iso-files:
|
|||||||
mkdir -p ${ISO_PATH}/EFI/BOOT
|
mkdir -p ${ISO_PATH}/EFI/BOOT
|
||||||
|
|
||||||
cp -v limine.cfg limine/limine-bios.sys ${ISO_PATH}/boot/limine
|
cp -v limine.cfg limine/limine-bios.sys ${ISO_PATH}/boot/limine
|
||||||
cp -v limine/BOOTX64.EFI ${ISO_PATH}/EFI/BOOT/
|
cp -v limine/BOOT${LIMINE_BOOT_VARIATION}.EFI ${ISO_PATH}/EFI/BOOT/
|
||||||
|
|
||||||
# OS files
|
# OS files
|
||||||
cp -v target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf ${ISO_PATH}/boot
|
cp -v target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf ${ISO_PATH}/boot
|
||||||
@@ -100,8 +109,10 @@ build-iso: partition-iso
|
|||||||
fi
|
fi
|
||||||
python scripts/demangle-symbols.py
|
python scripts/demangle-symbols.py
|
||||||
mv scripts/symbols.table ${ISO_PATH}/boot
|
mv scripts/symbols.table ${ISO_PATH}/boot
|
||||||
# Install the Limine bootloader on the ISO
|
ifeq (${ARCH},x86_64)
|
||||||
|
# Install the Limine bootloader for bios installs
|
||||||
./limine/limine bios-install ${IMAGE_PATH}
|
./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
|
# 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
|
mformat -F -i ${IMAGE_PATH}@@1M
|
||||||
@@ -120,16 +131,29 @@ compile-bootloader:
|
|||||||
compile-binaries:
|
compile-binaries:
|
||||||
cargo build ${CARGO_OPTS}
|
cargo build ${CARGO_OPTS}
|
||||||
|
|
||||||
ovmf:
|
ovmf-x86_64: ovmf
|
||||||
mkdir -p bin/ovmf
|
mkdir -p ovmf/ovmf-x86_64
|
||||||
cd bin/ovmf && curl -Lo OVMF.fd https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd
|
@if [ ! -d "ovmf/ovmf-x86_64/OVMF.fd" ]; then \
|
||||||
|
cd ovmf/ovmf-x86_64 && curl -Lo OVMF.fd https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
ovmf-riscv64: ovmf
|
||||||
|
mkdir -p ovmf/ovmf-riscv64
|
||||||
|
@if [ ! -d "ovmf/ovmf-riscv64/OVMF.fd" ]; then \
|
||||||
|
cd ovmf/ovmf-riscv64 && curl -o OVMF.fd https://retrage.github.io/edk2-nightly/bin/RELEASERISCV64_VIRT_CODE.fd && dd if=/dev/zero of=OVMF.fd bs=1 count=0 seek=33554432; \
|
||||||
|
fi
|
||||||
|
|
||||||
# In debug mode, open a terminal and run this command:
|
# In debug mode, open a terminal and run this command:
|
||||||
# gdb target/x86_64-unknown-none/debug/CappuccinOS.elf -ex "target remote :1234"
|
# gdb target/x86_64-unknown-none/debug/CappuccinOS.elf -ex "target remote :1234"
|
||||||
|
|
||||||
run: build ${RUN_OPTS}
|
run: build ${RUN_OPTS} run-${ARCH}
|
||||||
|
|
||||||
|
run-x86_64:
|
||||||
qemu-system-x86_64 ${QEMU_OPTS}
|
qemu-system-x86_64 ${QEMU_OPTS}
|
||||||
|
|
||||||
|
run-riscv64:
|
||||||
|
qemu-system-riscv64 ${QEMU_OPTS} -M virt -cpu rv64 -device ramfb -device qemu-xhci -device usb-kbd -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd0
|
||||||
|
|
||||||
line-count:
|
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:
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -11,7 +11,10 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
|
|||||||
- [X] ANSI color codes in console
|
- [X] ANSI color codes in console
|
||||||
- [X] Heap allocation
|
- [X] Heap allocation
|
||||||
- [ ] Externalized kernel modules
|
- [ ] Externalized kernel modules
|
||||||
- [ ] Initramfs
|
- [X] Initramfs
|
||||||
|
- [X] Squashfs driver
|
||||||
|
- [X] Programmatic reads
|
||||||
|
- [X] Decompression
|
||||||
- [ ] SMP
|
- [ ] SMP
|
||||||
- [ ] Use APIC instead of PIC
|
- [ ] Use APIC instead of PIC
|
||||||
- [ ] Pre-emptive multitasking
|
- [ ] Pre-emptive multitasking
|
||||||
@@ -27,7 +30,7 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
|
|||||||
- [ ] M.2 NVME device support
|
- [ ] M.2 NVME device support
|
||||||
- [ ] Basic shell
|
- [ ] Basic shell
|
||||||
- [X] Basic I/O
|
- [X] Basic I/O
|
||||||
- [ ] Executing Programs
|
- [ ] Executing Programs from disk
|
||||||
- [ ] Lua interpreter
|
- [ ] Lua interpreter
|
||||||
- [ ] Memory management
|
- [ ] Memory management
|
||||||
- [ ] Network support
|
- [ ] Network support
|
||||||
@@ -37,7 +40,6 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
|
|||||||
- [ ] User authentication
|
- [ ] User authentication
|
||||||
- [ ] Power management
|
- [ ] Power management
|
||||||
- [ ] Paging
|
- [ ] Paging
|
||||||
- [ ] Hardware abstraction layer
|
|
||||||
- [ ] RTC Clock
|
- [ ] RTC Clock
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
@@ -45,7 +47,6 @@ Before building CappuccinOS, make sure you have the following installed on your
|
|||||||
|
|
||||||
- rust
|
- rust
|
||||||
- python
|
- python
|
||||||
- binutils
|
|
||||||
- sgdisk
|
- sgdisk
|
||||||
- mtools
|
- mtools
|
||||||
- squashfs-tools
|
- squashfs-tools
|
||||||
@@ -66,7 +67,7 @@ Install the dependencies:
|
|||||||
<details>
|
<details>
|
||||||
<summary>Arch</summary>
|
<summary>Arch</summary>
|
||||||
|
|
||||||
sudo pacman -S binutils gptfdisk mtools squashfs-tools python
|
sudo pacman -S gptfdisk mtools squashfs-tools python
|
||||||
# Optionally
|
# Optionally
|
||||||
sudo pacman -S qemu-system-x86
|
sudo pacman -S qemu-system-x86
|
||||||
</details>
|
</details>
|
||||||
@@ -75,7 +76,7 @@ Install the dependencies:
|
|||||||
<summary>Ubuntu</summary>
|
<summary>Ubuntu</summary>
|
||||||
Python should be installed by default, and if it's not, make an issue or a PR and I'll fix it
|
Python should be installed by default, and if it's not, make an issue or a PR and I'll fix it
|
||||||
|
|
||||||
sudo apt install binutils gdisk mtools squashfs-tools
|
sudo apt install gdisk mtools squashfs-tools
|
||||||
# Optionally
|
# Optionally
|
||||||
sudo apt install qemu
|
sudo apt install qemu
|
||||||
</details>
|
</details>
|
||||||
@@ -99,6 +100,10 @@ sudo dd if=bin/CappuccinOS.iso of=/dev/sdX bs=1M && sync
|
|||||||
```
|
```
|
||||||
**Be careful not to overwrite your hard drive when using `dd`!**
|
**Be careful not to overwrite your hard drive when using `dd`!**
|
||||||
|
|
||||||
|
## Supported Architectures
|
||||||
|
- x86_64
|
||||||
|
- RISC-V64 (experimental until I can get my hands on some RISC-V hardware)
|
||||||
|
|
||||||
## Credits an attributions
|
## Credits an attributions
|
||||||
Inspiration was mainly from [JDH's Tetris OS](https://www.youtube.com/watch?v=FaILnmUYS_U), mixed with a growing interest in low level in general and an interest in learning rust (yeah, I started this project with not that much rust experience, maybe a CLI app or two, and trust me it shows).
|
Inspiration was mainly from [JDH's Tetris OS](https://www.youtube.com/watch?v=FaILnmUYS_U), mixed with a growing interest in low level in general and an interest in learning rust (yeah, I started this project with not that much rust experience, maybe a CLI app or two, and trust me it shows).
|
||||||
|
|
||||||
|
|||||||
10
TODO.md
10
TODO.md
@@ -2,10 +2,12 @@
|
|||||||
not really meant to be looked at, just writing down my thoughts
|
not really meant to be looked at, just writing down my thoughts
|
||||||
|
|
||||||
- [ ] finish fat fs
|
- [ ] finish fat fs
|
||||||
- [ ] follow cluster chains
|
- [X] follow cluster chains
|
||||||
- [ ] Search for file in code
|
- [X] Search for file in code
|
||||||
- [ ] search into folders
|
- [X] search into folders
|
||||||
- [ ] Integrate with VFS
|
- [X] Integrate with VFS
|
||||||
|
- [ ] Writes
|
||||||
|
- [ ] Read directory contents
|
||||||
- [ ] Custom FS
|
- [ ] Custom FS
|
||||||
|
|
||||||
2 partitions, one that is the FAT fs that the system boot from, the directory structure looks like this:
|
2 partitions, one that is the FAT fs that the system boot from, the directory structure looks like this:
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ TIMEOUT=3
|
|||||||
PROTOCOL=limine
|
PROTOCOL=limine
|
||||||
|
|
||||||
KERNEL_PATH=boot:///boot/CappuccinOS.elf
|
KERNEL_PATH=boot:///boot/CappuccinOS.elf
|
||||||
KERNEL_CMDLINE=fat_in_mem=true big_fat_phony
|
KERNEL_CMDLINE=fat_in_mem=false big_fat_phony
|
||||||
|
|
||||||
MODULE_PATH=boot:///boot/initramfs.img
|
MODULE_PATH=boot:///boot/initramfs.img
|
||||||
@@ -9,3 +9,9 @@ mod x86_64;
|
|||||||
|
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
mod x86_common;
|
mod x86_common;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
mod riscv64;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use self::riscv64::*;
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
"features": "-mmx,-sse,+soft-float",
|
"features": "-mmx,-sse,+soft-float",
|
||||||
"os": "CappuccinOS",
|
"os": "CappuccinOS",
|
||||||
"arch": "x86_64",
|
"arch": "x86_64",
|
||||||
"linker-flavor": "ld",
|
"linker": "rust-lld",
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
"pre-link-args": {
|
"pre-link-args": {
|
||||||
"ld": [
|
"ld.lld": [
|
||||||
"-melf_x86_64",
|
"-melf_x86_64",
|
||||||
"--script=./src/arch/x86_64/linker.ld"
|
"--script=./src/arch/x86_64/linker.ld"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// use alloc::format;
|
// use alloc::format;
|
||||||
|
|
||||||
// // piggyback off of the CappuccinOS allocator
|
// // piggyback off of the CappuccinOS allocator
|
||||||
// // TODO: make a syscall for memory operations
|
// // TODO: make a malloc lib for memory operations
|
||||||
// #[allow(unused_imports)]
|
// #[allow(unused_imports)]
|
||||||
// use CappuccinOS;
|
// use CappuccinOS;
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ pub fn _start(_args: &[&str]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print(message: &str) {
|
fn print(message: &str) {
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
unsafe {
|
unsafe {
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
"mov rdi, 0x01", // write syscall
|
"mov rdi, 0x01", // write syscall
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use super::vfs::{VfsDirectory, VfsFile, VfsFileSystem};
|
|||||||
// End Of Chain
|
// End Of Chain
|
||||||
const EOC: u32 = 0x0FFFFFF8;
|
const EOC: u32 = 0x0FFFFFF8;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
enum FatType {
|
enum FatType {
|
||||||
Fat12,
|
Fat12,
|
||||||
Fat16,
|
Fat16,
|
||||||
@@ -47,6 +47,7 @@ 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],
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
// - Extended BIOS Parameter Block -
|
// - Extended BIOS Parameter Block -
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
@@ -193,19 +194,15 @@ impl<'a> FatFs<'a> {
|
|||||||
|
|
||||||
if crate::KERNEL_FEATURES.fat_in_mem {
|
if crate::KERNEL_FEATURES.fat_in_mem {
|
||||||
let mut fat_vec: Vec<u32> = Vec::with_capacity(bytes_per_fat / 4);
|
let mut fat_vec: Vec<u32> = Vec::with_capacity(bytes_per_fat / 4);
|
||||||
unsafe { fat_vec.set_len(fat_vec.capacity()) };
|
|
||||||
|
|
||||||
for i in 0..(bpb.sectors_per_fat_ext as usize) {
|
for i in 0..(bpb.sectors_per_fat_ext as usize) {
|
||||||
let sector = drive
|
let sector = drive
|
||||||
.read(fat_start + i as u64, 1)
|
.read(fat_start + i as u64, 1)
|
||||||
.expect("Failed to read FAT");
|
.expect("Failed to read FAT");
|
||||||
for j in 0..(512 / 4) {
|
for j in 0..(512 / 4) {
|
||||||
fat_vec[i * (512 / 4) + j] = u32::from_le_bytes([
|
fat_vec.push(u32::from_le_bytes(
|
||||||
sector[j * 4],
|
sector[j * 4..(j * 4 + 4)].try_into().unwrap(),
|
||||||
sector[(j * 4) + 1],
|
))
|
||||||
sector[(j * 4) + 2],
|
|
||||||
sector[(j * 4) + 3],
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +285,7 @@ impl<'a> FatFs<'a> {
|
|||||||
continue; // Directory is unused, ignore it
|
continue; // Directory is unused, ignore it
|
||||||
} else if bytes[11] == FileEntryAttributes::LongFileName as u8 {
|
} else if bytes[11] == FileEntryAttributes::LongFileName as u8 {
|
||||||
// Entry is LFN (step 3)
|
// Entry is LFN (step 3)
|
||||||
// read long filename somehow (step 4)
|
// read long filename (step 4)
|
||||||
let long_filename_part: LongFileName;
|
let long_filename_part: LongFileName;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
|
|
||||||
|
use crate::libs::mutex::Mutex;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
enum ZlibCompressionLevel {
|
enum ZlibCompressionLevel {
|
||||||
@@ -21,15 +25,14 @@ impl From<u8> for ZlibCompressionLevel {
|
|||||||
|
|
||||||
// RFC 1950: "ZLIB Compressed Data Format Specification"
|
// RFC 1950: "ZLIB Compressed Data Format Specification"
|
||||||
// RFC 1951: "DEFLATE Compressed Data Format Specification"
|
// RFC 1951: "DEFLATE Compressed Data Format Specification"
|
||||||
pub fn uncompress_data(bytes: &[u8]) -> &[u8] {
|
pub fn uncompress_data(bytes: &[u8]) -> Result<Arc<[u8]>, ()> {
|
||||||
assert!(bytes.len() > 2);
|
assert!(bytes.len() > 2);
|
||||||
|
|
||||||
// Compression Method and flags
|
// Compression Method and flags
|
||||||
let cmf = bytes[0];
|
let cmf = bytes[0];
|
||||||
let flags = bytes[1];
|
|
||||||
|
|
||||||
if cmf & 0x0F != 0x08 {
|
if (cmf & 0x0F) != 0x08 {
|
||||||
panic!("Compression method is not GZIP!",);
|
panic!("Compression method is not deflate!");
|
||||||
}
|
}
|
||||||
|
|
||||||
let window_log2 = cmf >> 4 & 0x0F;
|
let window_log2 = cmf >> 4 & 0x0F;
|
||||||
@@ -38,10 +41,378 @@ pub fn uncompress_data(bytes: &[u8]) -> &[u8] {
|
|||||||
panic!("Unsupported window size {window_log2:X}!");
|
panic!("Unsupported window size {window_log2:X}!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let flags = bytes[1];
|
||||||
|
if (cmf as u32 * 256 + flags as u32) % 31 != 0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Check if FCheck is valid
|
// TODO: Check if FCheck is valid
|
||||||
|
|
||||||
let present_dictionary = flags >> 5 & 0x01 != 0;
|
let present_dictionary = flags >> 5 & 0x01 != 0;
|
||||||
let compression_level: ZlibCompressionLevel = (flags >> 6 & 0x03).into();
|
let _compression_level: ZlibCompressionLevel = (flags >> 6 & 0x03).into();
|
||||||
|
|
||||||
todo!("Uncompress data");
|
if present_dictionary {
|
||||||
|
// cry
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut inflate_context = InflateContext::new(&bytes[2..bytes.len() - 4]);
|
||||||
|
|
||||||
|
let data = inflate_context.decompress()?;
|
||||||
|
|
||||||
|
// last 4 bytes
|
||||||
|
let checksum = u32::from_le_bytes(bytes[bytes.len() - 4..].try_into().unwrap());
|
||||||
|
|
||||||
|
if adler32(&data) != checksum {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(data.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adler32(bytes: &[u8]) -> u32 {
|
||||||
|
let mut a = 1_u32;
|
||||||
|
let mut b = 0_u32;
|
||||||
|
|
||||||
|
for &byte in bytes {
|
||||||
|
a = (a + byte as u32) % 65521;
|
||||||
|
b = (b + a) % 65521;
|
||||||
|
}
|
||||||
|
|
||||||
|
return u32::from_be((b << 16) | a);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Huff {
|
||||||
|
counts: [u16; 16],
|
||||||
|
symbols: [u16; 288],
|
||||||
|
}
|
||||||
|
|
||||||
|
static FIXED_LENGTHS: Mutex<Huff> = Mutex::new(Huff {
|
||||||
|
counts: [0_u16; 16],
|
||||||
|
symbols: [0_u16; 288],
|
||||||
|
});
|
||||||
|
static FIXED_DISTS: Mutex<Huff> = Mutex::new(Huff {
|
||||||
|
counts: [0_u16; 16],
|
||||||
|
symbols: [0_u16; 288],
|
||||||
|
});
|
||||||
|
|
||||||
|
struct HuffRing {
|
||||||
|
pointer: usize,
|
||||||
|
data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HuffRing {
|
||||||
|
fn new() -> Self {
|
||||||
|
let mut data = Vec::with_capacity(32 * 1024);
|
||||||
|
unsafe {
|
||||||
|
data.set_len(32 * 1024);
|
||||||
|
};
|
||||||
|
|
||||||
|
return Self { pointer: 0, data };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InflateContext {
|
||||||
|
input_buf: Vec<u8>,
|
||||||
|
bit_index: usize,
|
||||||
|
output_buf: alloc::vec::Vec<u8>,
|
||||||
|
ring: HuffRing,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InflateContext {
|
||||||
|
fn new(bytes: &[u8]) -> Self {
|
||||||
|
return Self {
|
||||||
|
input_buf: bytes.to_vec(),
|
||||||
|
bit_index: 0,
|
||||||
|
output_buf: Vec::new(),
|
||||||
|
ring: HuffRing::new(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bit(&mut self) -> bool {
|
||||||
|
if self.bit_index == 8 {
|
||||||
|
self.input_buf.remove(0);
|
||||||
|
if self.input_buf.len() == 0 {
|
||||||
|
panic!("Not enough data! {:X?}", self.output_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.bit_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let byte = self.input_buf[0] & (1 << self.bit_index) != 0;
|
||||||
|
self.bit_index += 1;
|
||||||
|
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bits(&mut self, num_bits: usize) -> u32 {
|
||||||
|
let mut byte = 0_u32;
|
||||||
|
|
||||||
|
for bit in 0..num_bits {
|
||||||
|
byte |= (self.get_bit() as u32) << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bits_base(&mut self, num: usize, base: usize) -> u32 {
|
||||||
|
return (base + if num != 0 { self.get_bits(num) } else { 0 } as usize) as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decompress(&mut self) -> Result<Arc<[u8]>, ()> {
|
||||||
|
build_fixed();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let is_final = self.get_bit();
|
||||||
|
let block_type = self.get_bits(2);
|
||||||
|
|
||||||
|
match block_type {
|
||||||
|
0x00 => {
|
||||||
|
self.uncompressed()?;
|
||||||
|
}
|
||||||
|
0x01 => {
|
||||||
|
self.inflate(FIXED_LENGTHS.lock().write(), FIXED_DISTS.lock().write())?;
|
||||||
|
}
|
||||||
|
0x02 => {
|
||||||
|
self.decode_huffman()?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_final {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(Arc::from(self.output_buf.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(&mut self, huff: &mut Huff) -> u32 {
|
||||||
|
let mut base: i32 = 0;
|
||||||
|
let mut offs: i32 = 0;
|
||||||
|
|
||||||
|
let mut i = 1;
|
||||||
|
loop {
|
||||||
|
offs = 2 * offs + self.get_bit() as i32;
|
||||||
|
|
||||||
|
assert!(i <= 15);
|
||||||
|
|
||||||
|
if offs < huff.counts[i] as i32 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
base += huff.counts[i] as i32;
|
||||||
|
offs -= huff.counts[i] as i32;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(base + offs >= 0 && base + offs < 288);
|
||||||
|
|
||||||
|
return huff.symbols[(base + offs) as usize] as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit(&mut self, byte: u8) {
|
||||||
|
if self.ring.pointer == 32768 {
|
||||||
|
self.ring.pointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ring.data[self.ring.pointer] = byte;
|
||||||
|
self.output_buf.push(byte);
|
||||||
|
self.ring.pointer += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek(&mut self, offset: usize) -> u8 {
|
||||||
|
self.ring.data[(self.ring.pointer - offset) % 32768]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uncompressed(&mut self) -> Result<(), ()> {
|
||||||
|
let len = u16::from_le(self.get_bits(16).try_into().unwrap());
|
||||||
|
let nlen = u16::from_le(self.get_bits(16).try_into().unwrap());
|
||||||
|
|
||||||
|
if nlen != !len {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..len {
|
||||||
|
// TODO: is this right?
|
||||||
|
let byte = self.get_bits(8) as u8;
|
||||||
|
self.emit(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inflate(&mut self, huff_len: &mut Huff, huff_dist: &mut Huff) -> Result<(), ()> {
|
||||||
|
let length_bits = [
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,
|
||||||
|
127,
|
||||||
|
];
|
||||||
|
let length_base = [
|
||||||
|
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99,
|
||||||
|
115, 131, 163, 195, 227, 258, 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
let dist_bits = [
|
||||||
|
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
|
||||||
|
12, 13, 13,
|
||||||
|
];
|
||||||
|
let dist_base = [
|
||||||
|
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025,
|
||||||
|
1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577,
|
||||||
|
];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut symbol = self.decode(huff_len);
|
||||||
|
|
||||||
|
if symbol < 256 {
|
||||||
|
self.emit(symbol as u8);
|
||||||
|
} else {
|
||||||
|
if symbol == 256 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol -= 257;
|
||||||
|
|
||||||
|
let length =
|
||||||
|
self.get_bits_base(length_bits[symbol as usize], length_base[symbol as usize]);
|
||||||
|
let distance = self.decode(huff_dist);
|
||||||
|
let offset =
|
||||||
|
self.get_bits_base(dist_bits[distance as usize], dist_base[distance as usize]);
|
||||||
|
|
||||||
|
for _ in 0..length {
|
||||||
|
let b = self.peek(offset as usize);
|
||||||
|
self.emit(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_huffman(&mut self) -> Result<(), ()> {
|
||||||
|
let clens = [
|
||||||
|
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut lengths = [0_u8; 320];
|
||||||
|
|
||||||
|
let literals = self.get_bits_base(5, 257);
|
||||||
|
let distances = self.get_bits_base(5, 1);
|
||||||
|
let clengths = self.get_bits_base(4, 4);
|
||||||
|
|
||||||
|
for i in 0..clengths {
|
||||||
|
lengths[clens[i as usize] as usize] = self.get_bits(3) as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut codes = Huff {
|
||||||
|
counts: [0_u16; 16],
|
||||||
|
symbols: [0_u16; 288],
|
||||||
|
};
|
||||||
|
build_huffman(&lengths, 19, &mut codes);
|
||||||
|
|
||||||
|
let mut count = 0_u32;
|
||||||
|
while count < literals + distances {
|
||||||
|
let symbol = self.decode(&mut codes);
|
||||||
|
|
||||||
|
if symbol < 16 {
|
||||||
|
lengths[count as usize] = symbol as u8;
|
||||||
|
count += 1;
|
||||||
|
} else if symbol < 19 {
|
||||||
|
let mut rep = 0_u32;
|
||||||
|
let mut length;
|
||||||
|
|
||||||
|
if symbol == 16 {
|
||||||
|
rep = lengths[count as usize - 1] as u32;
|
||||||
|
length = self.get_bits_base(2, 3);
|
||||||
|
} else if symbol == 17 {
|
||||||
|
length = self.get_bits_base(3, 3);
|
||||||
|
} else {
|
||||||
|
length = self.get_bits_base(7, 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
while length != 0 {
|
||||||
|
lengths[count as usize] = rep as u8;
|
||||||
|
count += 1;
|
||||||
|
length -= 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut huff_len = Huff {
|
||||||
|
counts: [0_u16; 16],
|
||||||
|
symbols: [0_u16; 288],
|
||||||
|
};
|
||||||
|
build_huffman(&lengths, literals as usize, &mut huff_len);
|
||||||
|
let mut huff_dist = Huff {
|
||||||
|
counts: [0_u16; 16],
|
||||||
|
symbols: [0_u16; 288],
|
||||||
|
};
|
||||||
|
build_huffman(
|
||||||
|
&lengths[literals as usize..],
|
||||||
|
distances as usize,
|
||||||
|
&mut huff_dist,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.inflate(&mut huff_len, &mut huff_dist)?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_huffman(lengths: &[u8], size: usize, out: &mut Huff) {
|
||||||
|
let mut offsets = [0_u32; 16];
|
||||||
|
let mut count: u32 = 0;
|
||||||
|
|
||||||
|
assert!(size <= 288);
|
||||||
|
|
||||||
|
for i in 0..16 {
|
||||||
|
out.counts[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..size {
|
||||||
|
assert!(lengths[i] <= 15);
|
||||||
|
|
||||||
|
out.counts[lengths[i] as usize] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.counts[0] = 0;
|
||||||
|
|
||||||
|
for i in 0..16 {
|
||||||
|
offsets[i] = count;
|
||||||
|
count += out.counts[i] as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..size {
|
||||||
|
if lengths[i] != 0 {
|
||||||
|
out.symbols[offsets[lengths[i] as usize] as usize] = i.try_into().unwrap();
|
||||||
|
offsets[lengths[i] as usize] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_fixed() {
|
||||||
|
let mut lengths = [0_u8; 288];
|
||||||
|
for i in 0..144 {
|
||||||
|
lengths[i] = 8;
|
||||||
|
}
|
||||||
|
for i in 144..256 {
|
||||||
|
lengths[i] = 9;
|
||||||
|
}
|
||||||
|
for i in 256..280 {
|
||||||
|
lengths[i] = 7;
|
||||||
|
}
|
||||||
|
for i in 280..288 {
|
||||||
|
lengths[i] = 8;
|
||||||
|
}
|
||||||
|
build_huffman(&lengths, 288, FIXED_LENGTHS.lock().write());
|
||||||
|
|
||||||
|
for i in 0..30 {
|
||||||
|
lengths[i] = 5;
|
||||||
|
}
|
||||||
|
build_huffman(&lengths, 30, FIXED_DISTS.lock().write());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,15 +43,6 @@ pub fn init() {
|
|||||||
}
|
}
|
||||||
let initramfs = initramfs.unwrap();
|
let initramfs = initramfs.unwrap();
|
||||||
|
|
||||||
crate::println!("Initramfs is located at: {:#018X?}", unsafe {
|
|
||||||
initramfs.base.as_ptr().unwrap()
|
|
||||||
..initramfs
|
|
||||||
.base
|
|
||||||
.as_ptr()
|
|
||||||
.unwrap()
|
|
||||||
.add(initramfs.length as usize)
|
|
||||||
});
|
|
||||||
|
|
||||||
let squashfs = Squashfs::new(initramfs.base.as_ptr().unwrap());
|
let squashfs = Squashfs::new(initramfs.base.as_ptr().unwrap());
|
||||||
|
|
||||||
if squashfs.is_err() {
|
if squashfs.is_err() {
|
||||||
@@ -61,15 +52,15 @@ pub fn init() {
|
|||||||
|
|
||||||
let squashfs = squashfs.unwrap();
|
let squashfs = squashfs.unwrap();
|
||||||
|
|
||||||
crate::println!("{:X?}", squashfs);
|
|
||||||
crate::println!("{:?}", squashfs.superblock.features());
|
|
||||||
|
|
||||||
crate::println!(
|
crate::println!(
|
||||||
"{:X?}",
|
"\033[92m{:?}",
|
||||||
squashfs
|
core::str::from_utf8(
|
||||||
|
&squashfs
|
||||||
.open("/firstdir/seconddirbutlonger/yeah.txt")
|
.open("/firstdir/seconddirbutlonger/yeah.txt")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.read()
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,9 +79,9 @@ struct Squashfs<'a> {
|
|||||||
|
|
||||||
impl Squashfs<'_> {
|
impl Squashfs<'_> {
|
||||||
fn new(ptr: *mut u8) -> Result<Squashfs<'static>, ()> {
|
fn new(ptr: *mut u8) -> Result<Squashfs<'static>, ()> {
|
||||||
crate::println!("Parsing initramfs fs at {:p}", ptr);
|
crate::log_info!("Parsing initramfs at {:p}", ptr);
|
||||||
|
|
||||||
// bytes used from superblock
|
// 40 is the offset for bytes used by the archive in the superblock
|
||||||
let length = unsafe { u64::from_le(*(ptr.add(40) as *const u64)) as usize };
|
let length = unsafe { u64::from_le(*(ptr.add(40) as *const u64)) as usize };
|
||||||
|
|
||||||
let squashfs_data: &[u8] = unsafe { core::slice::from_raw_parts(ptr, length) };
|
let squashfs_data: &[u8] = unsafe { core::slice::from_raw_parts(ptr, length) };
|
||||||
@@ -100,36 +91,81 @@ impl Squashfs<'_> {
|
|||||||
let data_table = &squashfs_data
|
let data_table = &squashfs_data
|
||||||
[core::mem::size_of::<SquashfsSuperblock>()..superblock.inode_table as usize];
|
[core::mem::size_of::<SquashfsSuperblock>()..superblock.inode_table as usize];
|
||||||
|
|
||||||
let inode_table =
|
macro_rules! get_metadata_table {
|
||||||
&squashfs_data[superblock.inode_table as usize..superblock.dir_table as usize];
|
($table_type:ident) => {{
|
||||||
|
// get table size minus the top bit (indicates compression) plus 2, because
|
||||||
|
// The table size is minus the size of the size header (two bytes)
|
||||||
|
let table_size = (u16::from_le_bytes(
|
||||||
|
squashfs_data
|
||||||
|
[superblock.$table_type as usize..superblock.$table_type as usize + 2]
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
) & 0x7FFF)
|
||||||
|
+ 2;
|
||||||
|
|
||||||
let directory_table =
|
&squashfs_data[superblock.$table_type as usize
|
||||||
&squashfs_data[superblock.dir_table as usize..superblock.frag_table as usize];
|
..superblock.$table_type as usize + table_size as usize]
|
||||||
|
}};
|
||||||
let mut fragment_table: Option<&[u8]> = None;
|
|
||||||
|
|
||||||
if superblock.frag_table != u64::MAX {
|
|
||||||
fragment_table = Some(
|
|
||||||
&squashfs_data[superblock.frag_table as usize..superblock.export_table as usize],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut export_table: Option<&[u8]> = None;
|
let inode_table = get_metadata_table!(inode_table);
|
||||||
|
|
||||||
|
let directory_table = get_metadata_table!(dir_table);
|
||||||
|
|
||||||
|
let fragment_table: Option<&[u8]> = {
|
||||||
|
if superblock.frag_table == u64::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
if superblock.export_table != u64::MAX {
|
if superblock.export_table != u64::MAX {
|
||||||
export_table = Some(
|
Some(
|
||||||
&squashfs_data[superblock.export_table as usize..superblock.id_table as usize],
|
&squashfs_data
|
||||||
);
|
[superblock.frag_table as usize..superblock.export_table as usize],
|
||||||
|
)
|
||||||
|
} else if superblock.xattr_table != u64::MAX {
|
||||||
|
Some(
|
||||||
|
&squashfs_data
|
||||||
|
[superblock.frag_table as usize..superblock.xattr_table as usize],
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
|
&squashfs_data
|
||||||
|
[superblock.frag_table as usize..superblock.id_table as usize],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut id_table: &[u8] = &squashfs_data[superblock.id_table as usize..];
|
let export_table: Option<&[u8]> = {
|
||||||
let mut xattr_table: Option<&[u8]> = None;
|
if superblock.export_table == u64::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
if superblock.xattr_table != u64::MAX {
|
if superblock.xattr_table != u64::MAX {
|
||||||
id_table =
|
Some(
|
||||||
&squashfs_data[superblock.id_table as usize..superblock.xattr_table as usize];
|
&squashfs_data
|
||||||
xattr_table = Some(&squashfs_data[superblock.xattr_table as usize..]);
|
[superblock.export_table as usize..superblock.xattr_table as usize],
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
|
&squashfs_data
|
||||||
|
[superblock.export_table as usize..superblock.id_table as usize],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let id_table: &[u8] = if superblock.xattr_table != u64::MAX {
|
||||||
|
&squashfs_data[superblock.id_table as usize..superblock.xattr_table as usize]
|
||||||
|
} else {
|
||||||
|
&squashfs_data[superblock.id_table as usize..]
|
||||||
|
};
|
||||||
|
|
||||||
|
let xattr_table: Option<&[u8]> = {
|
||||||
|
if superblock.xattr_table == u64::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(&squashfs_data[superblock.xattr_table as usize..])
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return Ok(Squashfs {
|
return Ok(Squashfs {
|
||||||
superblock,
|
superblock,
|
||||||
@@ -212,7 +248,7 @@ impl Squashfs<'_> {
|
|||||||
|
|
||||||
match self.superblock.compressor {
|
match self.superblock.compressor {
|
||||||
SquashfsCompressionType::Gzip => {
|
SquashfsCompressionType::Gzip => {
|
||||||
buffer.extend_from_slice(compressors::gzip::uncompress_data(bytes));
|
buffer.extend_from_slice(&compressors::gzip::uncompress_data(bytes).unwrap());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
crate::println!("Unsupported compression type")
|
crate::println!("Unsupported compression type")
|
||||||
@@ -239,13 +275,7 @@ impl<'a> VfsFileSystem for Squashfs<'a> {
|
|||||||
let path_components: Vec<&str> = path.trim_start_matches('/').split('/').collect();
|
let path_components: Vec<&str> = path.trim_start_matches('/').split('/').collect();
|
||||||
let mut current_dir = self.read_root_dir();
|
let mut current_dir = self.read_root_dir();
|
||||||
|
|
||||||
crate::println!("\033[94m{}\033[0m", "-".repeat(40));
|
|
||||||
for (i, &part) in path_components.iter().enumerate() {
|
for (i, &part) in path_components.iter().enumerate() {
|
||||||
crate::println!(
|
|
||||||
"{}\ncur: {current_dir:?}\n{part}\n{path}\n{0}",
|
|
||||||
"-".repeat(20)
|
|
||||||
);
|
|
||||||
|
|
||||||
let file = current_dir.find(part).ok_or(())?;
|
let file = current_dir.find(part).ok_or(())?;
|
||||||
|
|
||||||
match file {
|
match file {
|
||||||
@@ -261,7 +291,6 @@ impl<'a> VfsFileSystem for Squashfs<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crate::println!("\033[94m{}\033[0m", "-".repeat(40));
|
|
||||||
|
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@@ -370,20 +399,10 @@ impl<'a> BasicDirectoryInode<'a> {
|
|||||||
fn entries(&self) -> Arc<[Inode]> {
|
fn entries(&self) -> Arc<[Inode]> {
|
||||||
let mut entries: Vec<Inode> = Vec::new();
|
let mut entries: Vec<Inode> = Vec::new();
|
||||||
|
|
||||||
let directory_table = &self.header.squashfs.get_decompressed_table(
|
let directory_table = &self
|
||||||
self.header.squashfs.directory_table,
|
|
||||||
(
|
|
||||||
false,
|
|
||||||
Some(
|
|
||||||
!self
|
|
||||||
.header
|
.header
|
||||||
.squashfs
|
.squashfs
|
||||||
.superblock
|
.get_decompressed_table(self.header.squashfs.directory_table, (true, None));
|
||||||
.features()
|
|
||||||
.uncompressed_data_blocks,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
let directory_table_header =
|
let directory_table_header =
|
||||||
DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]);
|
DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]);
|
||||||
@@ -408,22 +427,10 @@ impl<'a> BasicDirectoryInode<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn find(&self, name: &str) -> Option<Inode<'a>> {
|
fn find(&self, name: &str) -> Option<Inode<'a>> {
|
||||||
crate::println!("Searching for file {name} in directory");
|
let directory_table = &self
|
||||||
|
|
||||||
let directory_table = &self.header.squashfs.get_decompressed_table(
|
|
||||||
self.header.squashfs.directory_table,
|
|
||||||
(
|
|
||||||
false,
|
|
||||||
Some(
|
|
||||||
!self
|
|
||||||
.header
|
.header
|
||||||
.squashfs
|
.squashfs
|
||||||
.superblock
|
.get_decompressed_table(self.header.squashfs.directory_table, (true, None));
|
||||||
.features()
|
|
||||||
.uncompressed_data_blocks,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
let directory_table_header =
|
let directory_table_header =
|
||||||
DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]);
|
DirectoryTableHeader::from_bytes(&directory_table[self.block_offset as usize..]);
|
||||||
@@ -436,8 +443,6 @@ impl<'a> BasicDirectoryInode<'a> {
|
|||||||
|
|
||||||
offset += 8 + directroy_table_entry.name.len();
|
offset += 8 + directroy_table_entry.name.len();
|
||||||
|
|
||||||
crate::println!("{}", directroy_table_entry.name);
|
|
||||||
|
|
||||||
if directroy_table_entry.name == name {
|
if directroy_table_entry.name == name {
|
||||||
return Some(
|
return Some(
|
||||||
self.header
|
self.header
|
||||||
@@ -490,12 +495,23 @@ impl<'a> VfsFile for BasicFileInode<'a> {
|
|||||||
let mut block_data: Vec<u8> = Vec::with_capacity(8192 * block_count);
|
let mut block_data: Vec<u8> = Vec::with_capacity(8192 * block_count);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
core::ptr::copy_nonoverlapping(
|
let data_table = self.header.squashfs.get_decompressed_table(
|
||||||
self.header
|
self.header.squashfs.data_table,
|
||||||
|
(
|
||||||
|
false,
|
||||||
|
Some(
|
||||||
|
!self
|
||||||
|
.header
|
||||||
.squashfs
|
.squashfs
|
||||||
.data_table
|
.superblock
|
||||||
.as_ptr()
|
.features()
|
||||||
.add(self.block_offset as usize),
|
.uncompressed_data_blocks,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
core::ptr::copy_nonoverlapping(
|
||||||
|
data_table.as_ptr().add(self.block_offset as usize),
|
||||||
block_data.as_mut_ptr(),
|
block_data.as_mut_ptr(),
|
||||||
self.file_size as usize,
|
self.file_size as usize,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
use alloc::{
|
||||||
|
boxed::Box,
|
||||||
|
string::{String, ToString},
|
||||||
|
sync::Arc,
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::libs::mutex::Mutex;
|
use crate::libs::mutex::Mutex;
|
||||||
|
|
||||||
@@ -18,12 +23,16 @@ pub trait VfsDirectory {
|
|||||||
pub static VFS_INSTANCES: Mutex<Vec<Vfs>> = Mutex::new(Vec::new());
|
pub static VFS_INSTANCES: Mutex<Vec<Vfs>> = Mutex::new(Vec::new());
|
||||||
|
|
||||||
pub struct Vfs {
|
pub struct Vfs {
|
||||||
|
identifier: String,
|
||||||
file_system: Box<dyn VfsFileSystem>,
|
file_system: Box<dyn VfsFileSystem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vfs {
|
impl Vfs {
|
||||||
pub fn new(file_system: Box<dyn VfsFileSystem>) -> Self {
|
pub fn new(file_system: Box<dyn VfsFileSystem>, identifier: &str) -> Self {
|
||||||
return Self { file_system };
|
return Self {
|
||||||
|
identifier: identifier.to_string(),
|
||||||
|
file_system,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> {
|
pub fn open(&self, path: &str) -> Result<Box<dyn VfsFile + '_>, ()> {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
use crate::arch::interrupts::{idt_set_gate, InterruptIndex};
|
use crate::arch::interrupts::{idt_set_gate, InterruptIndex};
|
||||||
// Shitty keyboard driver
|
// Shitty keyboard driver
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
@@ -39,6 +40,7 @@ pub enum KBDError {
|
|||||||
TestFailed,
|
TestFailed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
pub fn init() -> Result<(), KBDError> {
|
pub fn init() -> Result<(), KBDError> {
|
||||||
// flush output buffer
|
// flush output buffer
|
||||||
while (inb(KBD_COMMAND_AND_STATUS_PORT) & 1) != 0 {
|
while (inb(KBD_COMMAND_AND_STATUS_PORT) & 1) != 0 {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
pub mod acpi;
|
pub mod acpi;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
pub mod pci;
|
pub mod pci;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::arch::io::{inb, outb};
|
|||||||
|
|
||||||
// COM1
|
// COM1
|
||||||
pub static PORT: u16 = 0x3f8;
|
pub static PORT: u16 = 0x3f8;
|
||||||
|
pub const UART: *mut char = 0x10000000 as *mut char;
|
||||||
|
|
||||||
pub static POISONED: AtomicBool = AtomicBool::new(false);
|
pub static POISONED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
@@ -56,3 +57,17 @@ pub fn write_serial(character: char) {
|
|||||||
while is_transmit_empty() {}
|
while is_transmit_empty() {}
|
||||||
outb(PORT, character as u8);
|
outb(PORT, character as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
|
pub fn is_transmit_empty() -> bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
|
pub fn write_serial(character: char) {
|
||||||
|
unsafe {
|
||||||
|
*UART = character;
|
||||||
|
};
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,14 +3,17 @@ use alloc::sync::Arc;
|
|||||||
pub trait BlockDevice {
|
pub trait BlockDevice {
|
||||||
fn sector_count(&self) -> u64;
|
fn sector_count(&self) -> u64;
|
||||||
fn read(&self, sector: u64, sector_count: usize) -> Result<Arc<[u8]>, ()>;
|
fn read(&self, sector: u64, sector_count: usize) -> Result<Arc<[u8]>, ()>;
|
||||||
fn write(&self, sector: u64, data: &mut [u8]) -> Result<(), ()>;
|
fn write(&self, sector: u64, data: &[u8]) -> Result<(), ()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct GPTPartitionEntry {
|
pub struct GPTPartitionEntry {
|
||||||
pub partition_type_guid: [u8; 16],
|
pub partition_type_guid: [u8; 16],
|
||||||
|
pub unique_partition_guid: [u8; 16],
|
||||||
pub start_sector: u64,
|
pub start_sector: u64,
|
||||||
pub end_sector: u64,
|
pub end_sector: u64,
|
||||||
|
pub attributes: u64,
|
||||||
|
pub partition_name: [u8; 72],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
use core::mem::size_of;
|
use alloc::{boxed::Box, format, sync::Arc, vec::Vec};
|
||||||
|
|
||||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::io::{inb, insw, inw, outb, outsw, outw},
|
arch::io::{inb, inw, outb, outw},
|
||||||
drivers::{
|
drivers::{
|
||||||
fs::fat,
|
fs::fat,
|
||||||
storage::drive::{GPTBlock, GPTPartitionEntry},
|
storage::drive::{GPTBlock, GPTPartitionEntry},
|
||||||
@@ -296,7 +294,7 @@ impl ATABus {
|
|||||||
sector,
|
sector,
|
||||||
sector_count,
|
sector_count,
|
||||||
ATADriveDirection::Read,
|
ATADriveDirection::Read,
|
||||||
buffer.as_mut_slice(),
|
(buffer.as_mut_ptr(), buffer.len()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
return Ok(Arc::from(buffer));
|
return Ok(Arc::from(buffer));
|
||||||
@@ -307,7 +305,7 @@ impl ATABus {
|
|||||||
drive: ATADriveType,
|
drive: ATADriveType,
|
||||||
sector: u64,
|
sector: u64,
|
||||||
sector_count: usize,
|
sector_count: usize,
|
||||||
buffer: &mut [u8],
|
buffer: &[u8],
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
if buffer.len() < ATA_SECTOR_SIZE * sector_count {
|
if buffer.len() < ATA_SECTOR_SIZE * sector_count {
|
||||||
return Err(());
|
return Err(());
|
||||||
@@ -318,7 +316,7 @@ impl ATABus {
|
|||||||
sector,
|
sector,
|
||||||
sector_count,
|
sector_count,
|
||||||
ATADriveDirection::Write,
|
ATADriveDirection::Write,
|
||||||
buffer,
|
(buffer.as_ptr() as *mut u8, buffer.len()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -330,8 +328,10 @@ impl ATABus {
|
|||||||
sector: u64,
|
sector: u64,
|
||||||
sector_count: usize,
|
sector_count: usize,
|
||||||
direction: ATADriveDirection,
|
direction: ATADriveDirection,
|
||||||
buffer: &mut [u8],
|
buffer: (*mut u8, usize),
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
|
let buffer = unsafe { core::slice::from_raw_parts_mut(buffer.0, buffer.1) };
|
||||||
|
|
||||||
self.await_busy();
|
self.await_busy();
|
||||||
|
|
||||||
let using_lba48 = sector >= (1 << 28) - 1;
|
let using_lba48 = sector >= (1 << 28) - 1;
|
||||||
@@ -413,30 +413,10 @@ impl ATABus {
|
|||||||
|
|
||||||
// Allocate memory for the array that stores the sector data
|
// Allocate memory for the array that stores the sector data
|
||||||
let mut buffer_offset = 0;
|
let mut buffer_offset = 0;
|
||||||
for i in 0..sector_count {
|
for _ in 0..sector_count {
|
||||||
self.wait_for_drive_ready()
|
self.wait_for_drive_ready()
|
||||||
.map_err(|_| crate::log_error!("Error reading IDE Device"))?;
|
.map_err(|_| crate::log_error!("Error reading IDE Device"))?;
|
||||||
|
|
||||||
// # Safety
|
|
||||||
//
|
|
||||||
// We know that buffer is at least sector_count * ATA_SECTOR_SIZE, so it will never panic:tm:
|
|
||||||
// unsafe {
|
|
||||||
// match direction {
|
|
||||||
// ATADriveDirection::Read => insw(
|
|
||||||
// self.io_bar + ATADriveDataRegister::Data as u16,
|
|
||||||
// (buffer.as_mut_ptr() as *mut u16)
|
|
||||||
// .add((i * ATA_SECTOR_SIZE) / size_of::<u16>()),
|
|
||||||
// ATA_SECTOR_SIZE / size_of::<u16>(),
|
|
||||||
// ),
|
|
||||||
// ATADriveDirection::Write => outsw(
|
|
||||||
// self.io_bar + ATADriveDataRegister::Data as u16,
|
|
||||||
// (buffer.as_mut_ptr() as *mut u16)
|
|
||||||
// .add((i * ATA_SECTOR_SIZE) / size_of::<u16>()),
|
|
||||||
// ATA_SECTOR_SIZE / size_of::<u16>(),
|
|
||||||
// ),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
for chunk in
|
for chunk in
|
||||||
buffer[buffer_offset..(buffer_offset + ATA_SECTOR_SIZE)].chunks_exact_mut(2)
|
buffer[buffer_offset..(buffer_offset + ATA_SECTOR_SIZE)].chunks_exact_mut(2)
|
||||||
{
|
{
|
||||||
@@ -525,7 +505,7 @@ impl BlockDevice for ATADrive {
|
|||||||
return unsafe { *(sectors as *const u32) } as u64;
|
return unsafe { *(sectors as *const u32) } as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self, sector: u64, buffer: &mut [u8]) -> Result<(), ()> {
|
fn write(&self, sector: u64, buffer: &[u8]) -> Result<(), ()> {
|
||||||
let sector_count = buffer.len() / 512;
|
let sector_count = buffer.len() / 512;
|
||||||
|
|
||||||
self.bus.software_reset();
|
self.bus.software_reset();
|
||||||
@@ -612,10 +592,11 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
|
|||||||
.expect("Failed to read partition table");
|
.expect("Failed to read partition table");
|
||||||
|
|
||||||
crate::println!(
|
crate::println!(
|
||||||
"{}, {}, {}",
|
"{}, {}, {}, {:X?}",
|
||||||
(gpt.partition_entry_count * gpt.partition_entry_size) as usize / ATA_SECTOR_SIZE,
|
(gpt.partition_entry_count * gpt.partition_entry_size) as usize / ATA_SECTOR_SIZE,
|
||||||
gpt.partition_entry_count,
|
gpt.partition_entry_count,
|
||||||
gpt.partition_entry_size
|
gpt.partition_entry_size,
|
||||||
|
gpt.guid
|
||||||
);
|
);
|
||||||
|
|
||||||
for i in 0..gpt.partition_entry_count {
|
for i in 0..gpt.partition_entry_count {
|
||||||
@@ -637,6 +618,11 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let unique_partition_guid: [u8; 16] = partition_sector
|
||||||
|
[entry_offset + 16..entry_offset + 32]
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
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()
|
||||||
@@ -648,11 +634,24 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let attributes = u64::from_le_bytes(
|
||||||
|
partition_sector[entry_offset + 48..entry_offset + 56]
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let partition_name = partition_sector[entry_offset + 56..entry_offset + 128]
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Store the parsed information in the partition_entries array
|
// Store the parsed information in the partition_entries array
|
||||||
partitions.push(GPTPartitionEntry {
|
partitions.push(GPTPartitionEntry {
|
||||||
partition_type_guid,
|
partition_type_guid,
|
||||||
|
unique_partition_guid,
|
||||||
start_sector,
|
start_sector,
|
||||||
end_sector,
|
end_sector,
|
||||||
|
attributes,
|
||||||
|
partition_name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,7 +664,10 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
|
|||||||
|
|
||||||
let fat_fs = fat_fs.unwrap();
|
let fat_fs = fat_fs.unwrap();
|
||||||
|
|
||||||
let vfs = crate::drivers::fs::vfs::Vfs::new(Box::new(fat_fs));
|
let vfs = crate::drivers::fs::vfs::Vfs::new(
|
||||||
|
Box::new(fat_fs),
|
||||||
|
&format!("{:?}", partition.partition_type_guid),
|
||||||
|
);
|
||||||
|
|
||||||
crate::drivers::fs::vfs::VFS_INSTANCES
|
crate::drivers::fs::vfs::VFS_INSTANCES
|
||||||
.lock()
|
.lock()
|
||||||
@@ -685,16 +687,6 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buffer = Vec::with_capacity(4096);
|
|
||||||
unsafe { buffer.set_len(buffer.capacity()) };
|
|
||||||
buffer.fill(0x69_u8);
|
|
||||||
|
|
||||||
let _ = drive.write(0, &mut buffer);
|
|
||||||
|
|
||||||
let data = drive.read(0, 1);
|
|
||||||
|
|
||||||
crate::println!("{:X?}", data);
|
|
||||||
|
|
||||||
crate::println!("{:?}", partitions);
|
crate::println!("{:?}", partitions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
mod font;
|
mod font;
|
||||||
|
|
||||||
use crate::libs::mutex::Mutex;
|
use crate::libs::mutex::Mutex;
|
||||||
|
use alloc::vec;
|
||||||
use limine::FramebufferRequest;
|
use limine::FramebufferRequest;
|
||||||
|
|
||||||
pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(0);
|
pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(0);
|
||||||
@@ -35,6 +36,8 @@ pub fn put_char(
|
|||||||
mirror_buffer: Option<Framebuffer>,
|
mirror_buffer: Option<Framebuffer>,
|
||||||
) {
|
) {
|
||||||
let font = font::G_8X16_FONT;
|
let font = font::G_8X16_FONT;
|
||||||
|
let font_width = 8;
|
||||||
|
let font_height = 16;
|
||||||
|
|
||||||
if character as usize > u8::MAX as usize {
|
if character as usize > u8::MAX as usize {
|
||||||
character = '\x00'; // rounded question mark
|
character = '\x00'; // rounded question mark
|
||||||
@@ -46,13 +49,13 @@ pub fn put_char(
|
|||||||
let framebuffer =
|
let framebuffer =
|
||||||
get_framebuffer().expect("Tried to use framebuffer, but framebuffer was not found");
|
get_framebuffer().expect("Tried to use framebuffer, but framebuffer was not found");
|
||||||
|
|
||||||
let start_x = cx * 8;
|
let start_x = cx * font_width as u16;
|
||||||
let start_y = cy * 16;
|
let start_y = cy * font_height as u16;
|
||||||
|
|
||||||
for (row_idx, &character_byte) in character_array.iter().enumerate() {
|
for (row_idx, &character_byte) in character_array.iter().enumerate() {
|
||||||
let mut byte = [bg; 8];
|
let mut byte = vec![bg; font_width];
|
||||||
for (i, bit) in byte.iter_mut().enumerate() {
|
for (i, bit) in byte.iter_mut().enumerate() {
|
||||||
*bit = [bg, fg][((character_byte >> (7 - i)) & 0b00000001) as usize]
|
*bit = [bg, fg][((character_byte >> ((font_width - 1) - i)) & 0b00000001) as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
let row_start_offset = (start_y as usize + row_idx) * framebuffer.pitch
|
let row_start_offset = (start_y as usize + row_idx) * framebuffer.pitch
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
pub unsafe fn memset32(dst: *mut u32, val: u32, count: usize) {
|
pub unsafe fn memset32(dst: *mut u32, val: u32, count: usize) {
|
||||||
if cfg!(not(any(target_arch = "x86", target_arch = "x86_64"))) {
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
|
{
|
||||||
let mut buf = dst;
|
let mut buf = dst;
|
||||||
unsafe {
|
unsafe {
|
||||||
while buf < dst.add(count) {
|
while buf < dst.add(count) {
|
||||||
@@ -11,12 +11,15 @@ pub unsafe fn memset32(dst: *mut u32, val: u32, count: usize) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
|
{
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
"rep stosd",
|
"rep stosd",
|
||||||
inout("ecx") count => _,
|
inout("ecx") count => _,
|
||||||
inout("edi") dst => _,
|
inout("edi") dst => _,
|
||||||
inout("eax") val => _
|
inout("eax") val => _
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hcf() -> ! {
|
pub fn hcf() -> ! {
|
||||||
@@ -25,7 +28,7 @@ pub fn hcf() -> ! {
|
|||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
core::arch::asm!("hlt");
|
core::arch::asm!("hlt");
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||||
core::arch::asm!("wfi");
|
core::arch::asm!("wfi");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/main.rs
12
src/main.rs
@@ -1,5 +1,4 @@
|
|||||||
#![feature(abi_x86_interrupt)]
|
#![feature(abi_x86_interrupt, naked_functions)]
|
||||||
#![feature(naked_functions)]
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
@@ -35,10 +34,15 @@ pub extern "C" fn _start() -> ! {
|
|||||||
|
|
||||||
// drivers::acpi::init_acpi();
|
// drivers::acpi::init_acpi();
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
drivers::pci::enumerate_pci_bus();
|
drivers::pci::enumerate_pci_bus();
|
||||||
|
|
||||||
drivers::fs::vfs::init();
|
drivers::fs::vfs::init();
|
||||||
|
|
||||||
|
if let Some(kernel) = KERNEL_REQUEST.get_response().get() {
|
||||||
|
crate::println!("{:X?}", kernel.kernel_file.get().unwrap().gpt_disk_uuid);
|
||||||
|
}
|
||||||
|
|
||||||
crate::println!(
|
crate::println!(
|
||||||
"Total memory: {}",
|
"Total memory: {}",
|
||||||
crate::mem::PHYSICAL_MEMORY_MANAGER
|
crate::mem::PHYSICAL_MEMORY_MANAGER
|
||||||
@@ -58,6 +62,7 @@ pub struct KernelFeatures {
|
|||||||
|
|
||||||
impl KernelFeatures {
|
impl KernelFeatures {
|
||||||
fn update_option(&mut self, option: &str, value: &str) {
|
fn update_option(&mut self, option: &str, value: &str) {
|
||||||
|
#[allow(clippy::single_match)]
|
||||||
match option {
|
match option {
|
||||||
"fat_in_mem" => self.fat_in_mem = value == "true",
|
"fat_in_mem" => self.fat_in_mem = value == "true",
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -113,11 +118,14 @@ fn parse_kernel_cmdline() -> KernelFeatures {
|
|||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
crate::log_error!("{}", info);
|
crate::log_error!("{}", info);
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
|
{
|
||||||
let rbp: u64;
|
let rbp: u64;
|
||||||
unsafe {
|
unsafe {
|
||||||
core::arch::asm!("mov {0:r}, rbp", out(reg) rbp);
|
core::arch::asm!("mov {0:r}, rbp", out(reg) rbp);
|
||||||
};
|
};
|
||||||
crate::arch::stack_trace::print_stack_trace(6, rbp);
|
crate::arch::stack_trace::print_stack_trace(6, rbp);
|
||||||
|
}
|
||||||
|
|
||||||
hcf();
|
hcf();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,11 +110,13 @@ pub fn init_shell() {
|
|||||||
prompt();
|
prompt();
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
|
{
|
||||||
let kbd_result = crate::drivers::keyboard::init();
|
let kbd_result = crate::drivers::keyboard::init();
|
||||||
|
|
||||||
if kbd_result.is_err() {
|
if kbd_result.is_err() {
|
||||||
crate::log_error!("Unable to initialize keyboard! {:?}", kbd_result);
|
crate::log_error!("Unable to initialize keyboard! {:?}", kbd_result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
// crate::drivers::keyboard::consume_scancode();
|
// crate::drivers::keyboard::consume_scancode();
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ pub struct Console {
|
|||||||
pub cursor: Cursor,
|
pub cursor: Cursor,
|
||||||
feature_bits: AtomicU8,
|
feature_bits: AtomicU8,
|
||||||
pub second_buffer: Mutex<Option<crate::drivers::video::Framebuffer>>,
|
pub second_buffer: Mutex<Option<crate::drivers::video::Framebuffer>>,
|
||||||
|
// pub lines: Mutex<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConsoleFeatures {
|
pub struct ConsoleFeatures {
|
||||||
@@ -43,6 +44,7 @@ impl Console {
|
|||||||
cursor: Cursor::new(),
|
cursor: Cursor::new(),
|
||||||
feature_bits: AtomicU8::new(0b00000000),
|
feature_bits: AtomicU8::new(0b00000000),
|
||||||
second_buffer: Mutex::new(None),
|
second_buffer: Mutex::new(None),
|
||||||
|
// lines: Mutex::new(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +100,13 @@ impl Console {
|
|||||||
let rows = framebuffer.height / 16;
|
let rows = framebuffer.height / 16;
|
||||||
self.columns.store(columns as u16, Ordering::SeqCst);
|
self.columns.store(columns as u16, Ordering::SeqCst);
|
||||||
self.rows.store(rows as u16, Ordering::SeqCst);
|
self.rows.store(rows as u16, Ordering::SeqCst);
|
||||||
|
|
||||||
|
// let mut lines_lock = self.lines.lock();
|
||||||
|
// lines_lock.write().reserve_exact(rows);
|
||||||
|
// for _ in 0..rows {
|
||||||
|
// let string = String::with_capacity(columns);
|
||||||
|
// lines_lock.write().push(string);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_features(&self) -> ConsoleFeatures {
|
pub fn get_features(&self) -> ConsoleFeatures {
|
||||||
@@ -115,6 +124,54 @@ impl Console {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn puts(&self, string: &str) {
|
||||||
|
// let mut lines = Vec::new();
|
||||||
|
|
||||||
|
// // let mut text_lock = self.text.lock();
|
||||||
|
// // let text = text_lock.write();
|
||||||
|
|
||||||
|
// let mut col_idx = 0_usize;
|
||||||
|
// let mut line_string = String::new();
|
||||||
|
// for ch in string.chars() {
|
||||||
|
// if col_idx > self.columns.load(Ordering::SeqCst) as usize - 1 {
|
||||||
|
// col_idx = 0;
|
||||||
|
// lines.push(line_string.clone());
|
||||||
|
// line_string.clear();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if ch == '\n' {
|
||||||
|
// col_idx = 0;
|
||||||
|
// lines.push(line_string.clone());
|
||||||
|
// line_string.clear();
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// line_string.push(ch);
|
||||||
|
// col_idx += 1;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let mut new_lines = [self.lines.lock().read().as_slice(), lines.as_slice()].concat();
|
||||||
|
// if new_lines.len() > self.rows.load(Ordering::SeqCst) as usize {
|
||||||
|
// new_lines.reverse();
|
||||||
|
// new_lines.resize(self.rows.load(Ordering::SeqCst) as usize - 1, String::new());
|
||||||
|
// new_lines.reverse();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// (*self.lines.lock().write()) = new_lines;
|
||||||
|
|
||||||
|
// crate::drivers::video::fill_screen(0x000000, *self.second_buffer.lock().read());
|
||||||
|
// self.cursor.set_pos(0, 0);
|
||||||
|
// for line in self.lines.lock().read() {
|
||||||
|
// self._puts(line);
|
||||||
|
// self.cursor
|
||||||
|
// .set_pos(0, self.cursor.cy.load(Ordering::SeqCst) + 1);
|
||||||
|
// crate::drivers::serial::write_serial('\r');
|
||||||
|
// crate::drivers::serial::write_serial('\n')
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // self._puts(string);
|
||||||
|
// }
|
||||||
|
|
||||||
// Uses a stripped down version of ANSI color codes:
|
// Uses a stripped down version of ANSI color codes:
|
||||||
// \033[FG;BGm
|
// \033[FG;BGm
|
||||||
pub fn puts(&self, string: &str) {
|
pub fn puts(&self, string: &str) {
|
||||||
@@ -191,6 +248,7 @@ impl Console {
|
|||||||
self.cursor.bg.load(Ordering::SeqCst),
|
self.cursor.bg.load(Ordering::SeqCst),
|
||||||
*self.second_buffer.lock().read(),
|
*self.second_buffer.lock().read(),
|
||||||
);
|
);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,6 +285,15 @@ impl Console {
|
|||||||
self.cursor.set_color(0xbababa, 0x000000);
|
self.cursor.set_color(0xbababa, 0x000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn reblit(&self) {
|
||||||
|
// self.cursor.set_pos(0, 0);
|
||||||
|
// self.reblit.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
// self.puts(&self.text.lock().read().trim_end_matches('\n'));
|
||||||
|
|
||||||
|
// self.reblit.store(false, Ordering::SeqCst);
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn scroll_console(&self) {
|
pub fn scroll_console(&self) {
|
||||||
let framebuffer_attributes = crate::drivers::video::get_framebuffer()
|
let framebuffer_attributes = crate::drivers::video::get_framebuffer()
|
||||||
.expect("Tried to scroll console but we have no framebuffer.");
|
.expect("Tried to scroll console but we have no framebuffer.");
|
||||||
@@ -695,6 +762,8 @@ pub fn exec(command: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if command == "test" {
|
if command == "test" {
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
|
{
|
||||||
let message = "Hello from syscall!\n";
|
let message = "Hello from syscall!\n";
|
||||||
unsafe {
|
unsafe {
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
@@ -707,6 +776,7 @@ pub fn exec(command: &str) {
|
|||||||
in(reg) message.len()
|
in(reg) message.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
43
test.log
43
test.log
@@ -1,43 +0,0 @@
|
|||||||
[ * ] Serial Driver successfully initialized
|
|
||||||
[ ? ] Initialized heap with 4MiB of memory at 0x4E8000
|
|
||||||
[ ? ] Initialized framebuffer mirroring with 3MiB at 0x100000
|
|
||||||
====== MEMORY MAP ======
|
|
||||||
[ 0x0000000000001000..0x0000000000052000 ] Type: BootloaderReclaimable Size: 324KiB
|
|
||||||
[ 0x0000000000053000..0x000000000009F000 ] Type: Usable Size: 304KiB
|
|
||||||
[ 0x000000000009FC00..0x00000000000A0000 ] Type: Reserved Size: 1KiB
|
|
||||||
[ 0x00000000000F0000..0x0000000000100000 ] Type: Reserved Size: 64KiB
|
|
||||||
[ 0x0000000000100000..0x0000000007AC3000 ] Type: Usable Size: 121MiB
|
|
||||||
[ 0x0000000007AC3000..0x0000000007AC4000 ] Type: KernelAndModules Size: 4KiB
|
|
||||||
[ 0x0000000007AC4000..0x0000000007AC5000 ] Type: BootloaderReclaimable Size: 4KiB
|
|
||||||
[ 0x0000000007AC5000..0x0000000007AC8000 ] Type: Usable Size: 12KiB
|
|
||||||
[ 0x0000000007AC8000..0x0000000007AD0000 ] Type: BootloaderReclaimable Size: 32KiB
|
|
||||||
[ 0x0000000007AD0000..0x0000000007AFE000 ] Type: KernelAndModules Size: 184KiB
|
|
||||||
[ 0x0000000007AFE000..0x0000000007B3C000 ] Type: BootloaderReclaimable Size: 248KiB
|
|
||||||
[ 0x0000000007B3C000..0x0000000007F26000 ] Type: Usable Size: 3MiB
|
|
||||||
[ 0x0000000007F26000..0x0000000007FE0000 ] Type: BootloaderReclaimable Size: 744KiB
|
|
||||||
[ 0x0000000007FE0000..0x0000000008000000 ] Type: Reserved Size: 128KiB
|
|
||||||
[ 0x00000000FD000000..0x00000000FD3E8000 ] Type: Framebuffer Size: 3MiB
|
|
||||||
[ 0x00000000FFFC0000..0x0000000100000000 ] Type: Reserved Size: 256KiB
|
|
||||||
[ 0x000000FD00000000..0x0000010000000000 ] Type: Reserved Size: 12GiB
|
|
||||||
Initramfs is located at: 0xffff800007ac3000..0xffff800007ac4000
|
|
||||||
Parsing initramfs fs at 0xffff800007ac3000
|
|
||||||
Squashfs { ptr: 0xffff800007ac3060, superblock: SquashfsSuperblock { magic: 73717368, inode_count: 2, mod_time: 6566B6A1, block_size: 20000, frag_count: 1, compressor: GZIP, block_log: 11, flags: 1CB, id_count: 1, ver_major: 4, ver_minor: 0, root_inode_offset: 20, root_inode_block: 0, _reserved: 0, bytes_used: 120, id_table: 118, xattr_table: FFFFFFFFFFFFFFFF, inode_table: 7B, dir_table: BD, frag_table: F0, export_table: 10A }, data_table: [48, 65, 6C, 6C, 6F, 20, 57, 6F, 72, 6C, 64, 20, 66, 72, 6F, 6D, 20, 49, 6E, 69, 74, 72, 61, 6D, 66, 73, A], inode_table: [40, 80, 2, 0, A4, 1, 0, 0, 0, 0, A1, B6, 66, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1B, 0, 0, 0, 1, 0, ED, 1, 0, 0, 0, 0, A1, B6, 66, 65, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 22, 0, 0, 0, 3, 0, 0, 0], directory_table: [1F, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, A, 0, 65, 78, 61, 6D, 70, 6C, 65, 2E, 74, 78, 74, 10, 80, 60, 0, 0, 0, 0, 0, 0, 0, 1B, 0, 0, 1, 0, 0, 0, 0], fragment_table: Some([DE, 0, 0, 0, 0, 0, 0, 0, 10, 80, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0]), export_table: Some([F8, 0, 0, 0, 0, 0, 0, 0, 4, 80, E8, 3, 0, 0]), id_table: [12, 1, 0, 0, 0, 0, 0, 0], xattr_table: None }
|
|
||||||
SquashfsFeatures { uncompressed_inodes: true, uncompressed_data_blocks: true, _reserved: false, uncompressed_fragments: true, unused_fragments: false, fragments_always_present: false, deduplicated_data: true, nfs_table_present: true, uncompressed_xattrs: true, no_xattrs: false, compressor_options_present: false, uncompressed_id_table: false }
|
|
||||||
[1, 0, ED, 1, 0, 0, 0, 0, A1, B6, 66, 65, 2, 0, 0, 0]
|
|
||||||
InodeHeader { file_type: BasicDirectory, _reserved: [0, 0, 0], mtime: 6566B6A1, inode_num: 2 }
|
|
||||||
root_inode: DirectoryInode { block_index: 0, link_count: 2, file_size: 22, block_offset: 0, parent_inode: 3 }
|
|
||||||
====== PCI DEVICES ======
|
|
||||||
Entry 0: Bus: 0 Device: 0 Function: 0 VendorID: 0x8086 DeviceID: 0x1237 ClassCode: 0x06 SubclassCode: 0x00 ProgIF: 0x00
|
|
||||||
Entry 1: Bus: 0 Device: 1 Function: 0 VendorID: 0x8086 DeviceID: 0x7000 ClassCode: 0x06 SubclassCode: 0x01 ProgIF: 0x00
|
|
||||||
Entry 2: Bus: 0 Device: 1 Function: 1 VendorID: 0x8086 DeviceID: 0x7010 ClassCode: 0x01 SubclassCode: 0x01 ProgIF: 0x80
|
|
||||||
Entry 3: Bus: 0 Device: 1 Function: 3 VendorID: 0x8086 DeviceID: 0x7113 ClassCode: 0x06 SubclassCode: 0x80 ProgIF: 0x00
|
|
||||||
Entry 4: Bus: 0 Device: 2 Function: 0 VendorID: 0x1234 DeviceID: 0x1111 ClassCode: 0x03 SubclassCode: 0x00 ProgIF: 0x00
|
|
||||||
Entry 5: Bus: 0 Device: 3 Function: 0 VendorID: 0x8086 DeviceID: 0x100E ClassCode: 0x02 SubclassCode: 0x00 ProgIF: 0x00
|
|
||||||
[ ? ] ATA: Detected 1 drive
|
|
||||||
[ ? ] ATA: Drive 0 has 131072 sectors (64 MB)
|
|
||||||
11, 44, 128
|
|
||||||
[ ? ] WARNING: FAT is not being stored in memory, this feature is experimental and file reads are expected to be slower.
|
|
||||||
Found Fat32 FS
|
|
||||||
[GPTPartitionEntry { partition_type_guid: [40, 115, 42, 193, 31, 248, 210, 17, 186, 75, 0, 160, 201, 62, 201, 59], start_sector: 2048, end_sector: 34815 }, GPTPartitionEntry { partition_type_guid: [175, 61, 198, 15, 131, 132, 114, 71, 142, 121, 61, 105, 216, 71, 125, 228], start_sector: 34816, end_sector: 131038 }]
|
|
||||||
Total memory: 125MiB
|
|
||||||
>
|
|
||||||
Reference in New Issue
Block a user