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.
## 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
- [ ] File system
- [X] FAT file system (read-only rn)
- [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,7 +32,7 @@ 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
@@ -45,6 +43,7 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
- [ ] 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:
<details>
<summary>Arch</summary>
sudo pacman -S gptfdisk mtools squashfs-tools python
# Optionally
sudo pacman -S qemu-system-x86
</details>
<details>
@@ -81,15 +84,19 @@ Install the dependencies:
sudo apt install gdisk mtools squashfs-tools
# Optionally
sudo apt install qemu
</details>
## 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.

View File

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

View File

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

View File

@@ -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<String>,
next: Option<*mut Vfs>,
ops: Option<Box<dyn FsOps>>,
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<dyn VNodeOperations>,
pub node_data: Option<NodeData>,
pub parent: *const Vfs,
@@ -226,19 +222,56 @@ pub struct VAttr {
used_blocks: u32,
}
pub fn add_vfs(mount_point: &str, fs_ops: Box<dyn FsOps>) -> Result<(), ()> {
let layout = alloc::alloc::Layout::new::<Vfs>();
let vfs_ptr = unsafe { alloc(layout).cast::<Vfs>() };
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<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 };
(*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::<u8>(), layout) };
PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::<u8>(), 1);
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()) };
} 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::<u8>(), layout) };
// unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) };
PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::<u8>(), 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::<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())
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::<u8>(), layout) };
// unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) };
PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::<u8>(), 1);
return Err(());
}
if unsafe { (*target_vfs).next }.is_none() {
break;
}
if cur_vnode.vfs_mounted_here.is_some() {
unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) };
next_vfs = unsafe { (*target_vfs).next };
}
if next_vfs.is_none() {
// unsafe { dealloc(vfs_ptr.cast::<u8>(), layout) };
PHYSICAL_MEMORY_MANAGER.dealloc(vfs_ptr.cast::<u8>(), 1);
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);
}
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}");
@@ -311,9 +376,23 @@ pub fn vfs_open(path: &str) -> Result<VNode, ()> {
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 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<VNode, ()> {
.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;
}
} else {
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();
// 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),

View File

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

View File

@@ -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<LinkedListAllocator> = Mutex::new(LinkedListAllocator::new());