zlib driver & experimental riscv support

this commit adds the last piece to get the initramfs completely finished
This commit is contained in:
Zoe
2023-12-17 01:46:31 -06:00
parent 0a8ee7c58a
commit 7f216fdfdd
24 changed files with 744 additions and 255 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
/target /target
/bin /bin
/ovmf
# Bochs # Bochs
bx_enh_dbg.ini bx_enh_dbg.ini

View File

@@ -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:

View File

@@ -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
View File

@@ -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:

View File

@@ -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

View File

@@ -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::*;

View File

@@ -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"
] ]

View File

@@ -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

View File

@@ -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 {

View File

@@ -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());
} }

View File

@@ -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,
); );

View File

@@ -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 + '_>, ()> {

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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)]

View File

@@ -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);
} }
} }

View File

@@ -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

View File

@@ -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,6 +11,8 @@ 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 => _,
@@ -18,6 +20,7 @@ pub unsafe fn memset32(dst: *mut u32, val: u32, count: usize) {
inout("eax") val => _ inout("eax") val => _
); );
} }
}
pub fn hcf() -> ! { pub fn hcf() -> ! {
loop { loop {
@@ -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");
} }
} }

View File

@@ -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();
} }

View File

@@ -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();

View File

@@ -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;
} }

View File

@@ -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
>