mount within directories (its dumb I know)
This commit is contained in:
46
README.md
46
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
|
||||
- [ ] 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.
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(());
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
18
src/main.rs
18
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())
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user