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
- [ ] 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:
<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.
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;
}
next_vfs = unsafe { (*target_vfs).next };
}
if cur_vnode.vfs_mounted_here.is_some() {
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(());
}
@@ -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;
}
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());