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