diff --git a/README.md b/README.md index 8430d8d..d1dd868 100644 --- a/README.md +++ b/README.md @@ -5,28 +5,26 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. This README will guide you through the process of building and running CappuccinOS. ## Features -- [X] Serial output -- [X] Hardware interrupts -- [X] Heap allocation + +- [x] Serial output +- [x] Hardware interrupts +- [x] Heap allocation - [ ] Externalized kernel modules - - [X] Initramfs - - [X] Squashfs driver - - [X] Programmatic reads - - [X] Decompression + - [x] Initramfs + - [x] Squashfs driver + - [x] Programmatic reads + - [x] Decompression - [ ] PS/2 Keyboard support - [ ] ANSI color codes in console - [ ] SMP - - [ ] Use APIC instead of PIC + - [x] Use APIC instead of PIC - [ ] Pre-emptive multitasking - - [ ] Scheduling -- [ ] Roll my own bootloader - - [ ] x86 CPU support - - [ ] armv8 CPU support + - [ ] Scheduling - [ ] File system - - [X] FAT file system (read-only rn) - - [ ] Ext2 file system + - [x] FAT file system (read-only rn) + - [ ] Ext2 file system - [ ] Block Device support - - [X] IDE device support + - [x] IDE device support - [ ] SATA device support - [ ] MMC/Nand device support - [ ] M.2 NVME device support @@ -34,17 +32,18 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi - [ ] Basic I/O - [ ] Executing Programs from disk - [ ] Lua interpreter -- [ ] Memory management +- [x] Memory management - [ ] Network support - [ ] GUI - [ ] Device drivers - - [ ] Native intel graphics + - [ ] Native intel graphics - [ ] User authentication - [ ] Power management - [ ] Paging - [ ] RTC Clock ## Setup + Before building CappuccinOS, make sure you have the following installed on your machine: - rust @@ -55,23 +54,27 @@ Before building CappuccinOS, make sure you have the following installed on your - qemu (optional) Clone the repo: + ```BASH git clone https://github.com/juls0730/CappuccinOS.git cd CappuccinOS ``` Install rust, if you haven't already: + ```BASH curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none ``` Install the dependencies: +
Arch sudo pacman -S gptfdisk mtools squashfs-tools python # Optionally sudo pacman -S qemu-system-x86 +
@@ -81,15 +84,19 @@ Install the dependencies: sudo apt install gdisk mtools squashfs-tools # Optionally sudo apt install qemu +
## Usage + Run CappuccinOS with QEMU: + ```BASH make run ``` If you would like to just build CappuccinOS but not run it: + ```BASH make build ``` @@ -97,26 +104,32 @@ make build If you would like to target another architecture other than x86_64, set the `ARCH` variable to the a supported architecture. CappuccinOS is also built in release mode by default, if you would like to build CappuccinOS in debug mode, set the `MODE` variable to `debug`. Run on a bare metal machine by flashing to a USB stick or hard drive: + ``` sudo dd if=bin/CappuccinOS.iso of=/dev/sdX bs=1M && sync ``` + **Be careful not to overwrite your hard drive when using `dd`!** ## Supported Architectures + - x86_64 -- ~~aarch64~~ not in scope __might__ not build -- ~~RISC-V64~~ not in scope __might__ not build +- ~~aarch64~~ not in scope **might** not build +- ~~RISC-V64~~ not in scope **might** not build ## 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). Some Resources I used over the creation of CappuccinOS: + - [OSDev wiki](https://wiki.osdev.org) - Wikipedia on various random things - [Squashfs Binary Format](https://dr-emann.github.io/squashfs/squashfs.html) - [GRUB](https://www.gnu.org/software/grub/grub-download.html) Mainly for Squashfs things, even though I later learned it does things incorrectly And mostly for examples of how people did stuff I used these (projects made by people who might actually have a clue what they're doing): + - This is missing some entries somehow - [MOROS](https://github.com/vinc/moros) - [Felix](https://github.com/mrgian/felix) @@ -125,4 +138,5 @@ And mostly for examples of how people did stuff I used these (projects made by p - [Lyre](https://github.com/Lyre-OS/klyre) ## License -CappuccinOS is license under the MIT License. Feel free to modify and distribute in accordance with the license. \ No newline at end of file + +CappuccinOS is license under the MIT License. Feel free to modify and distribute in accordance with the license. diff --git a/src/drivers/fs/fat.rs b/src/drivers/fs/fat.rs index 66a7d7d..daa3145 100755 --- a/src/drivers/fs/fat.rs +++ b/src/drivers/fs/fat.rs @@ -432,6 +432,10 @@ impl FatFs { } fn cluster_to_sector(&self, cluster: usize) -> usize { + crate::println!("bytes per sector: {}", unsafe { + core::ptr::read_unaligned(core::ptr::addr_of!(self.bpb.bytes_per_sector)) + }); + let fat_size = self.sectors_per_fat; let root_dir_sectors = ((self.bpb.root_directory_count * 32) + (self.bpb.bytes_per_sector - 1)) @@ -539,7 +543,6 @@ impl FsOps for FatFs { ref_count: 0, shared_lock_count: 0, exclusive_lock_count: 0, - vfs_mounted_here: None, ops: Box::new(file), node_data: None, parent: vfsp, @@ -668,7 +671,6 @@ impl<'a> VNodeOperations for File { ref_count: 0, shared_lock_count: 0, exclusive_lock_count: 0, - vfs_mounted_here: None, ops: Box::new(file), node_data: None, parent: (*vp).parent, diff --git a/src/drivers/fs/initramfs/mod.rs b/src/drivers/fs/initramfs/mod.rs index 1f6e9c0..a26d89a 100755 --- a/src/drivers/fs/initramfs/mod.rs +++ b/src/drivers/fs/initramfs/mod.rs @@ -364,7 +364,6 @@ impl<'a> FsOps for Squashfs<'a> { ref_count: 0, shared_lock_count: 0, exclusive_lock_count: 0, - vfs_mounted_here: None, ops: Box::new(root_dir), node_data: None, parent: vfsp, @@ -572,7 +571,6 @@ impl VNodeOperations for Inode { ref_count: 0, shared_lock_count: 0, exclusive_lock_count: 0, - vfs_mounted_here: None, ops: Box::new(inode), node_data: None, parent: (*vp).parent, diff --git a/src/drivers/fs/vfs.rs b/src/drivers/fs/vfs.rs index c421df7..26ee4d4 100755 --- a/src/drivers/fs/vfs.rs +++ b/src/drivers/fs/vfs.rs @@ -1,27 +1,23 @@ use core::fmt::Debug; use alloc::{ - alloc::{alloc, dealloc}, + // alloc::{alloc, dealloc}, boxed::Box, + string::{String, ToString}, sync::Arc, vec::Vec, }; -use crate::{ - log_info, log_ok, - mem::{ - // ALLOCATOR, - PHYSICAL_MEMORY_MANAGER, - }, -}; +use crate::{log_info, log_ok, mem::PHYSICAL_MEMORY_MANAGER}; static mut ROOT_VFS: Vfs = Vfs::null(); #[allow(unused)] pub struct Vfs { + mount_point: Option, next: Option<*mut Vfs>, ops: Option>, - vnode_covered: Option<*const VNode>, + // vnode_covered: Option<*const VNode>, flags: u32, block_size: u32, pub data: *mut u8, @@ -32,9 +28,10 @@ unsafe impl Sync for Vfs {} impl Vfs { const fn null() -> Self { return Vfs { + mount_point: None, next: None, ops: None, - vnode_covered: None, + // vnode_covered: None, flags: 0, block_size: 0, data: core::ptr::null_mut(), @@ -100,7 +97,6 @@ pub struct VNode { pub ref_count: u16, pub shared_lock_count: u16, pub exclusive_lock_count: u16, - pub vfs_mounted_here: Option<*mut Vfs>, pub ops: Box, pub node_data: Option, pub parent: *const Vfs, @@ -226,19 +222,56 @@ pub struct VAttr { used_blocks: u32, } -pub fn add_vfs(mount_point: &str, fs_ops: Box) -> Result<(), ()> { - let layout = alloc::alloc::Layout::new::(); - let vfs_ptr = unsafe { alloc(layout).cast::() }; +unsafe fn find_mount_point(file_path: &str) -> Option<*mut Vfs> { + // TODO: refactor + let mut mount_point = ROOT_VFS.next; + let mut current = ROOT_VFS.next; + + while let Some(node) = current { + let mount_point_str = node + .as_ref() + .unwrap() + .mount_point + .as_ref() + .expect("Null mount point"); + if file_path.starts_with(mount_point_str) + && mount_point_str.len() + > (mount_point.unwrap().as_ref().unwrap()) + .mount_point + .as_ref() + .unwrap() + .len() + { + mount_point = Some(node); + } + current = unsafe { (*node).next }; + } + + mount_point +} + +pub fn add_vfs(mut mount_point: &str, fs_ops: Box) -> Result<(), ()> { + if mount_point != "/" { + mount_point = mount_point.trim_end_matches('/'); + } + + // let layout = alloc::alloc::Layout::new::(); + // TODO: its fucking broken again + let vfs_ptr = PHYSICAL_MEMORY_MANAGER.alloc(1).cast::(); let vfs = unsafe { &mut *vfs_ptr }; (*vfs) = Vfs::null(); (*vfs).ops = Some(fs_ops); + (*vfs).mount_point = Some(mount_point.to_string()); - log_info!("Adding vfs at {mount_point}"); + log_info!("Adding vfs at {mount_point} {vfs_ptr:p}"); + // TODO: dont give / special treatment if mount_point == "/" { if unsafe { ROOT_VFS.next.is_some() } { + // unsafe { dealloc(vfs_ptr.cast::(), layout) }; + PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::(), 1); return Err(()); } @@ -254,37 +287,35 @@ pub fn add_vfs(mount_point: &str, fs_ops: Box) -> Result<(), ()> { unsafe { ROOT_VFS.next = Some(vfs.as_mut_ptr()) }; } else { + // TODO: technically this allows you to mount file systems at nonexistent mount point if unsafe { ROOT_VFS.next.is_none() } { - unsafe { dealloc(vfs_ptr.cast::(), layout) }; + // unsafe { dealloc(vfs_ptr.cast::(), layout) }; + PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::(), 1); return Err(()); } - let target_vfs = unsafe { ROOT_VFS.next.unwrap() }; + // let target_vfs = unsafe { ROOT_VFS.next.unwrap() }; - let mut cur_vnode = unsafe { (*target_vfs).ops.as_mut().unwrap().root(target_vfs) }; + let mut next_vfs = unsafe { ROOT_VFS.next }; - let parts = mount_point.split('/').collect::>(); - - for part in parts { - if part.is_empty() { - continue; - } - - // TODO: dont just lookup everything as the root user - if let Ok(vnode) = - cur_vnode - .ops - .lookup(part, UserCred { uid: 0, gid: 0 }, cur_vnode.as_ptr()) + while let Some(target_vfs) = next_vfs { + if unsafe { target_vfs.as_ref().unwrap().mount_point.as_ref().unwrap() == mount_point } { - cur_vnode = vnode; - } else { - unsafe { dealloc(vfs_ptr.cast::(), layout) }; + // unsafe { dealloc(vfs_ptr.cast::(), layout) }; + PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::(), 1); return Err(()); } + + if unsafe { (*target_vfs).next }.is_none() { + break; + } + + next_vfs = unsafe { (*target_vfs).next }; } - if cur_vnode.vfs_mounted_here.is_some() { - unsafe { dealloc(vfs_ptr.cast::(), layout) }; + if next_vfs.is_none() { + // unsafe { dealloc(vfs_ptr.cast::(), layout) }; + PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::(), 1); return Err(()); } @@ -298,7 +329,41 @@ pub fn add_vfs(mount_point: &str, fs_ops: Box) -> Result<(), ()> { .mount(mount_point, &mut vfs.data, vfsp); } - cur_vnode.vfs_mounted_here = Some(vfs.as_mut_ptr()); + unsafe { (*(next_vfs.unwrap())).next = Some(vfs) }; + + // let mut cur_vnode = unsafe { (*target_vfs).ops.as_mut().unwrap().root(target_vfs) }; + + // let parts = mount_point.split('/').collect::>(); + + // for part in parts { + // if part.is_empty() { + // continue; + // } + + // // TODO: dont just lookup everything as the root user + // if let Ok(vnode) = + // cur_vnode + // .ops + // .lookup(part, UserCred { uid: 0, gid: 0 }, cur_vnode.as_ptr()) + // { + // cur_vnode = vnode; + // } else { + // unsafe { dealloc(vfs_ptr.cast::(), layout) }; + // return Err(()); + // } + // } + + // if cur_vnode.vfs_mounted_here.is_some() { + // unsafe { dealloc(vfs_ptr.cast::(), layout) }; + // return Err(()); + // } + + // { + // let vfsp = vfs.as_ptr(); + + // } + + // cur_vnode.vfs_mounted_here = Some(vfs.as_mut_ptr()); } log_ok!("Added vfs at {mount_point}"); @@ -311,9 +376,23 @@ pub fn vfs_open(path: &str) -> Result { return Err(()); } + let root_vfs = unsafe { find_mount_point(path) }; + + if root_vfs.is_none() { + return Err(()); + } + + let mut cur_vnode = unsafe { + (*root_vfs.unwrap()) + .ops + .as_mut() + .unwrap() + .root(root_vfs.unwrap()) + }; + + let path = &path[unsafe { (*root_vfs.unwrap()).mount_point.as_ref().unwrap() }.len()..]; + let parts = path.split('/').collect::>(); - let target_vfs = unsafe { ROOT_VFS.next.unwrap() }; - let mut cur_vnode = unsafe { (*target_vfs).ops.as_mut().unwrap().root(target_vfs) }; for part in parts { if part.is_empty() { @@ -325,11 +404,7 @@ pub fn vfs_open(path: &str) -> Result { .ops .lookup(part, UserCred { uid: 0, gid: 0 }, cur_vnode.as_ptr()) { - if let Some(vfs) = vnode.vfs_mounted_here { - cur_vnode = unsafe { (*vfs).ops.as_mut().unwrap().root(vfs) } - } else { - cur_vnode = vnode; - } + cur_vnode = vnode; } else { return Err(()); } diff --git a/src/drivers/storage/ide.rs b/src/drivers/storage/ide.rs index 454eb79..f420dcf 100755 --- a/src/drivers/storage/ide.rs +++ b/src/drivers/storage/ide.rs @@ -691,7 +691,7 @@ fn ide_initialize(bar0: u32, bar1: u32, _bar2: u32, _bar3: u32, _bar4: u32) { let fat_fs = fat_fs.unwrap(); // TODO - let _ = add_vfs("/", Box::new(fat_fs)); + let _ = add_vfs("/mnt", Box::new(fat_fs)); // let vfs = crate::drivers::fs::vfs::Vfs::new( // Box::new(fat_fs), diff --git a/src/main.rs b/src/main.rs index b0075b7..eb2fceb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,20 +45,20 @@ pub fn kmain() -> ! { let mut file = vfs_open("/firstdir/seconddirbutlonger/yeah.txt").unwrap(); - // drivers::storage::ide::init(); + drivers::storage::ide::init(); - // let nested_file = vfs_open("/boot/limine/limine.cfg").unwrap(); + let mut nested_file = vfs_open("/mnt/boot/limine/limine.cfg").unwrap(); - // crate::println!( - // "{:X?}", - // nested_file - // .ops - // .open(0, UserCred { uid: 0, gid: 0 }, nested_file.as_ptr()) - // ); + crate::println!( + "LIMINE BOOT: {:X?}", + nested_file + .ops + .open(0, UserCred { uid: 0, gid: 0 }, nested_file.as_ptr()) + ); // let file = vfs_open("/example.txt").unwrap(); crate::println!( - "{:X?}", + "YEAH.TXT: {:X?}", &file .ops .open(0, UserCred { uid: 0, gid: 0 }, file.as_ptr()) diff --git a/src/mem/mod.rs b/src/mem/mod.rs index 08487dd..b1cf709 100755 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -15,7 +15,7 @@ pub fn align_up(addr: usize, align: usize) -> usize { addr + offset } -const HEAP_PAGES: usize = 1024; // 4 MiB heap +const HEAP_PAGES: usize = 4096; // 8 MiB heap #[global_allocator] pub static ALLOCATOR: Mutex = Mutex::new(LinkedListAllocator::new());