mount within directories (its dumb I know)

This commit is contained in:
Zoe
2024-05-13 22:41:22 -05:00
parent 4611b89a1d
commit f9ae4ce5ba
7 changed files with 167 additions and 78 deletions

View File

@@ -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. 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 ## Features
- [X] Serial output
- [X] Hardware interrupts - [x] Serial output
- [X] Heap allocation - [x] Hardware interrupts
- [x] Heap allocation
- [ ] Externalized kernel modules - [ ] Externalized kernel modules
- [X] Initramfs - [x] Initramfs
- [X] Squashfs driver - [x] Squashfs driver
- [X] Programmatic reads - [x] Programmatic reads
- [X] Decompression - [x] Decompression
- [ ] PS/2 Keyboard support - [ ] PS/2 Keyboard support
- [ ] ANSI color codes in console - [ ] ANSI color codes in console
- [ ] SMP - [ ] SMP
- [ ] Use APIC instead of PIC - [x] Use APIC instead of PIC
- [ ] Pre-emptive multitasking - [ ] Pre-emptive multitasking
- [ ] Scheduling - [ ] Scheduling
- [ ] Roll my own bootloader
- [ ] x86 CPU support
- [ ] armv8 CPU support
- [ ] File system - [ ] File system
- [X] FAT file system (read-only rn) - [x] FAT file system (read-only rn)
- [ ] Ext2 file system - [ ] Ext2 file system
- [ ] Block Device support - [ ] Block Device support
- [X] IDE device support - [x] IDE device support
- [ ] SATA device support - [ ] SATA device support
- [ ] MMC/Nand device support - [ ] MMC/Nand device support
- [ ] M.2 NVME device support - [ ] M.2 NVME device support
@@ -34,7 +32,7 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
- [ ] Basic I/O - [ ] Basic I/O
- [ ] Executing Programs from disk - [ ] Executing Programs from disk
- [ ] Lua interpreter - [ ] Lua interpreter
- [ ] Memory management - [x] Memory management
- [ ] Network support - [ ] Network support
- [ ] GUI - [ ] GUI
- [ ] Device drivers - [ ] Device drivers
@@ -45,6 +43,7 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
- [ ] RTC Clock - [ ] RTC Clock
## Setup ## Setup
Before building CappuccinOS, make sure you have the following installed on your machine: Before building CappuccinOS, make sure you have the following installed on your machine:
- rust - rust
@@ -55,23 +54,27 @@ Before building CappuccinOS, make sure you have the following installed on your
- qemu (optional) - qemu (optional)
Clone the repo: Clone the repo:
```BASH ```BASH
git clone https://github.com/juls0730/CappuccinOS.git git clone https://github.com/juls0730/CappuccinOS.git
cd CappuccinOS cd CappuccinOS
``` ```
Install rust, if you haven't already: Install rust, if you haven't already:
```BASH ```BASH
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none
``` ```
Install the dependencies: Install the dependencies:
<details> <details>
<summary>Arch</summary> <summary>Arch</summary>
sudo pacman -S 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>
<details> <details>
@@ -81,15 +84,19 @@ Install the dependencies:
sudo apt install gdisk mtools squashfs-tools sudo apt install gdisk mtools squashfs-tools
# Optionally # Optionally
sudo apt install qemu sudo apt install qemu
</details> </details>
## Usage ## Usage
Run CappuccinOS with QEMU: Run CappuccinOS with QEMU:
```BASH ```BASH
make run make run
``` ```
If you would like to just build CappuccinOS but not run it: If you would like to just build CappuccinOS but not run it:
```BASH ```BASH
make build 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`. 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: 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 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 ## Supported Architectures
- x86_64 - x86_64
- ~~aarch64~~ not in scope __might__ not build - ~~aarch64~~ not in scope **might** not build
- ~~RISC-V64~~ not in scope __might__ not build - ~~RISC-V64~~ not in scope **might** not build
## 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).
Some Resources I used over the creation of CappuccinOS: Some Resources I used over the creation of CappuccinOS:
- [OSDev wiki](https://wiki.osdev.org) - [OSDev wiki](https://wiki.osdev.org)
- Wikipedia on various random things - Wikipedia on various random things
- [Squashfs Binary Format](https://dr-emann.github.io/squashfs/squashfs.html) - [Squashfs Binary Format](https://dr-emann.github.io/squashfs/squashfs.html)
- [GRUB](https://www.gnu.org/software/grub/grub-download.html) Mainly for Squashfs things, even though I later learned it does things incorrectly - [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): 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 - This is missing some entries somehow
- [MOROS](https://github.com/vinc/moros) - [MOROS](https://github.com/vinc/moros)
- [Felix](https://github.com/mrgian/felix) - [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) - [Lyre](https://github.com/Lyre-OS/klyre)
## License ## License
CappuccinOS is license under the MIT License. Feel free to modify and distribute in accordance with the license. CappuccinOS is license under the MIT License. Feel free to modify and distribute in accordance with the license.

View File

@@ -432,6 +432,10 @@ impl FatFs {
} }
fn cluster_to_sector(&self, cluster: usize) -> usize { 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 fat_size = self.sectors_per_fat;
let root_dir_sectors = ((self.bpb.root_directory_count * 32) let root_dir_sectors = ((self.bpb.root_directory_count * 32)
+ (self.bpb.bytes_per_sector - 1)) + (self.bpb.bytes_per_sector - 1))
@@ -539,7 +543,6 @@ impl FsOps for FatFs {
ref_count: 0, ref_count: 0,
shared_lock_count: 0, shared_lock_count: 0,
exclusive_lock_count: 0, exclusive_lock_count: 0,
vfs_mounted_here: None,
ops: Box::new(file), ops: Box::new(file),
node_data: None, node_data: None,
parent: vfsp, parent: vfsp,
@@ -668,7 +671,6 @@ impl<'a> VNodeOperations for File {
ref_count: 0, ref_count: 0,
shared_lock_count: 0, shared_lock_count: 0,
exclusive_lock_count: 0, exclusive_lock_count: 0,
vfs_mounted_here: None,
ops: Box::new(file), ops: Box::new(file),
node_data: None, node_data: None,
parent: (*vp).parent, parent: (*vp).parent,

View File

@@ -364,7 +364,6 @@ impl<'a> FsOps for Squashfs<'a> {
ref_count: 0, ref_count: 0,
shared_lock_count: 0, shared_lock_count: 0,
exclusive_lock_count: 0, exclusive_lock_count: 0,
vfs_mounted_here: None,
ops: Box::new(root_dir), ops: Box::new(root_dir),
node_data: None, node_data: None,
parent: vfsp, parent: vfsp,
@@ -572,7 +571,6 @@ impl VNodeOperations for Inode {
ref_count: 0, ref_count: 0,
shared_lock_count: 0, shared_lock_count: 0,
exclusive_lock_count: 0, exclusive_lock_count: 0,
vfs_mounted_here: None,
ops: Box::new(inode), ops: Box::new(inode),
node_data: None, node_data: None,
parent: (*vp).parent, parent: (*vp).parent,

View File

@@ -1,27 +1,23 @@
use core::fmt::Debug; use core::fmt::Debug;
use alloc::{ use alloc::{
alloc::{alloc, dealloc}, // alloc::{alloc, dealloc},
boxed::Box, boxed::Box,
string::{String, ToString},
sync::Arc, sync::Arc,
vec::Vec, vec::Vec,
}; };
use crate::{ use crate::{log_info, log_ok, mem::PHYSICAL_MEMORY_MANAGER};
log_info, log_ok,
mem::{
// ALLOCATOR,
PHYSICAL_MEMORY_MANAGER,
},
};
static mut ROOT_VFS: Vfs = Vfs::null(); static mut ROOT_VFS: Vfs = Vfs::null();
#[allow(unused)] #[allow(unused)]
pub struct Vfs { pub struct Vfs {
mount_point: Option<String>,
next: Option<*mut Vfs>, next: Option<*mut Vfs>,
ops: Option<Box<dyn FsOps>>, ops: Option<Box<dyn FsOps>>,
vnode_covered: Option<*const VNode>, // vnode_covered: Option<*const VNode>,
flags: u32, flags: u32,
block_size: u32, block_size: u32,
pub data: *mut u8, pub data: *mut u8,
@@ -32,9 +28,10 @@ unsafe impl Sync for Vfs {}
impl Vfs { impl Vfs {
const fn null() -> Self { const fn null() -> Self {
return Vfs { return Vfs {
mount_point: None,
next: None, next: None,
ops: None, ops: None,
vnode_covered: None, // vnode_covered: None,
flags: 0, flags: 0,
block_size: 0, block_size: 0,
data: core::ptr::null_mut(), data: core::ptr::null_mut(),
@@ -100,7 +97,6 @@ pub struct VNode {
pub ref_count: u16, pub ref_count: u16,
pub shared_lock_count: u16, pub shared_lock_count: u16,
pub exclusive_lock_count: u16, pub exclusive_lock_count: u16,
pub vfs_mounted_here: Option<*mut Vfs>,
pub ops: Box<dyn VNodeOperations>, pub ops: Box<dyn VNodeOperations>,
pub node_data: Option<NodeData>, pub node_data: Option<NodeData>,
pub parent: *const Vfs, pub parent: *const Vfs,
@@ -226,19 +222,56 @@ pub struct VAttr {
used_blocks: u32, used_blocks: u32,
} }
pub fn add_vfs(mount_point: &str, fs_ops: Box<dyn FsOps>) -> Result<(), ()> { unsafe fn find_mount_point(file_path: &str) -> Option<*mut Vfs> {
let layout = alloc::alloc::Layout::new::<Vfs>(); // TODO: refactor
let vfs_ptr = unsafe { alloc(layout).cast::<Vfs>() }; 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<dyn FsOps>) -> Result<(), ()> {
if mount_point != "/" {
mount_point = mount_point.trim_end_matches('/');
}
// let layout = alloc::alloc::Layout::new::<Vfs>();
// TODO: its fucking broken again
let vfs_ptr = PHYSICAL_MEMORY_MANAGER.alloc(1).cast::<Vfs>();
let vfs = unsafe { &mut *vfs_ptr }; let vfs = unsafe { &mut *vfs_ptr };
(*vfs) = Vfs::null(); (*vfs) = Vfs::null();
(*vfs).ops = Some(fs_ops); (*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 mount_point == "/" {
if unsafe { ROOT_VFS.next.is_some() } { if unsafe { ROOT_VFS.next.is_some() } {
// unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) };
PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::<u8>(), 1);
return Err(()); return Err(());
} }
@@ -254,37 +287,35 @@ pub fn add_vfs(mount_point: &str, fs_ops: Box<dyn FsOps>) -> Result<(), ()> {
unsafe { ROOT_VFS.next = Some(vfs.as_mut_ptr()) }; unsafe { ROOT_VFS.next = Some(vfs.as_mut_ptr()) };
} else { } else {
// TODO: technically this allows you to mount file systems at nonexistent mount point
if unsafe { ROOT_VFS.next.is_none() } { if unsafe { ROOT_VFS.next.is_none() } {
unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) }; // unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) };
PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::<u8>(), 1);
return Err(()); 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::<Vec<&str>>(); while let Some(target_vfs) = next_vfs {
if unsafe { target_vfs.as_ref().unwrap().mount_point.as_ref().unwrap() == mount_point }
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; // unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) };
} else { PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::<u8>(), 1);
unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) };
return Err(()); return Err(());
} }
if unsafe { (*target_vfs).next }.is_none() {
break;
} }
if cur_vnode.vfs_mounted_here.is_some() { next_vfs = unsafe { (*target_vfs).next };
unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) }; }
if next_vfs.is_none() {
// unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) };
PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::<u8>(), 1);
return Err(()); return Err(());
} }
@@ -298,7 +329,41 @@ pub fn add_vfs(mount_point: &str, fs_ops: Box<dyn FsOps>) -> Result<(), ()> {
.mount(mount_point, &mut vfs.data, vfsp); .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::<Vec<&str>>();
// 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::<u8>(), layout) };
// return Err(());
// }
// }
// if cur_vnode.vfs_mounted_here.is_some() {
// unsafe { dealloc(vfs_ptr.cast::<u8>(), 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}"); log_ok!("Added vfs at {mount_point}");
@@ -311,9 +376,23 @@ pub fn vfs_open(path: &str) -> Result<VNode, ()> {
return Err(()); 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::<Vec<&str>>(); let parts = path.split('/').collect::<Vec<&str>>();
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 { for part in parts {
if part.is_empty() { if part.is_empty() {
@@ -325,11 +404,7 @@ pub fn vfs_open(path: &str) -> Result<VNode, ()> {
.ops .ops
.lookup(part, UserCred { uid: 0, gid: 0 }, cur_vnode.as_ptr()) .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 { } else {
return Err(()); return Err(());
} }

View File

@@ -691,7 +691,7 @@ 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();
// TODO // TODO
let _ = add_vfs("/", Box::new(fat_fs)); let _ = add_vfs("/mnt", Box::new(fat_fs));
// let vfs = crate::drivers::fs::vfs::Vfs::new( // let vfs = crate::drivers::fs::vfs::Vfs::new(
// Box::new(fat_fs), // Box::new(fat_fs),

View File

@@ -45,20 +45,20 @@ pub fn kmain() -> ! {
let mut file = vfs_open("/firstdir/seconddirbutlonger/yeah.txt").unwrap(); 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!( crate::println!(
// "{:X?}", "LIMINE BOOT: {:X?}",
// nested_file nested_file
// .ops .ops
// .open(0, UserCred { uid: 0, gid: 0 }, nested_file.as_ptr()) .open(0, UserCred { uid: 0, gid: 0 }, nested_file.as_ptr())
// ); );
// let file = vfs_open("/example.txt").unwrap(); // let file = vfs_open("/example.txt").unwrap();
crate::println!( crate::println!(
"{:X?}", "YEAH.TXT: {:X?}",
&file &file
.ops .ops
.open(0, UserCred { uid: 0, gid: 0 }, file.as_ptr()) .open(0, UserCred { uid: 0, gid: 0 }, file.as_ptr())

View File

@@ -15,7 +15,7 @@ pub fn align_up(addr: usize, align: usize) -> usize {
addr + offset addr + offset
} }
const HEAP_PAGES: usize = 1024; // 4 MiB heap const HEAP_PAGES: usize = 4096; // 8 MiB heap
#[global_allocator] #[global_allocator]
pub static ALLOCATOR: Mutex<LinkedListAllocator> = Mutex::new(LinkedListAllocator::new()); pub static ALLOCATOR: Mutex<LinkedListAllocator> = Mutex::new(LinkedListAllocator::new());