Compare commits

..

5 Commits

Author SHA1 Message Date
805048459c Update README.md 2026-05-08 16:03:02 +03:00
259c2d4e85 Update README.md 2026-05-05 01:36:26 +03:00
Faynot
d542b5586d feat: implement capability-based memory management foundation 2026-05-05 01:30:16 +03:00
Faynot
a45587042b change logo 2026-04-19 22:33:41 +03:00
Faynot
745687b0fa feat: capability start 2026-04-19 22:33:12 +03:00
10 changed files with 280 additions and 68 deletions

View File

@@ -1,5 +1,5 @@
<h1 align="center"> <h1 align="center">
<img width="512" src="https://git.inotfail.com/ami-chuu/Elyz/raw/commit/3831cfd967afb60efe108a7579a767ec2309631b/logo.png" alt="Elyz"> <img width="512" src="./logo.png" alt="Elyz">
</h1> </h1>
<p align="center"> <p align="center">
@@ -121,8 +121,6 @@ make run KARCH=aarch64
## Development Plan (TODO) ## Development Plan (TODO)
### Detailed Task List
| # | Task | Subtasks | Priority | Dependencies | | # | Task | Subtasks | Priority | Dependencies |
|---|------|----------|----------|--------------| |---|------|----------|----------|--------------|
| 1 | **Descriptor memory model** | | High | PMM, VMM | | 1 | **Descriptor memory model** | | High | PMM, VMM |

View File

@@ -0,0 +1,49 @@
use crate::mem::address::PhysAddr;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Relation {
Strong,
Borrow,
Transfer,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CapObject {
Empty,
Memory { phys: PhysAddr, size_pages: usize },
CNode { phys: PhysAddr, slots: usize },
PMActor { id: u64 },
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CapRights: u8 {
const READ = 1 << 0;
const WRITE = 1 << 1;
const EXECUTE = 1 << 2;
const GRANT = 1 << 3;
}
}
#[derive(Debug, Clone, Copy)]
pub struct Capability {
pub object: CapObject,
pub rights: CapRights,
pub relation: Relation,
pub token_sig: u64,
}
impl Capability {
pub const fn empty() -> Self {
Self {
object: CapObject::Empty,
rights: CapRights::empty(),
relation: Relation::Borrow,
token_sig: 0,
}
}
pub fn is_valid(&self) -> bool {
!matches!(self.object, CapObject::Empty)
}
}

75
kernel/src/cap/mod.rs Normal file
View File

@@ -0,0 +1,75 @@
pub mod descriptor;
pub mod object;
use alloc::vec::Vec;
use crate::mem::allocator::Locked;
pub use descriptor::*;
pub struct CNodeSlot {
pub cap: Capability,
pub parent_idx: Option<usize>,
}
pub struct CNode {
pub slots: Vec<Locked<CNodeSlot>>,
}
impl CNode {
pub fn new(size: usize) -> Self {
let mut slots = Vec::with_capacity(size);
for _ in 0..size {
slots.push(Locked::new(CNodeSlot {
cap: Capability::empty(),
parent_idx: None,
}));
}
Self { slots }
}
pub fn insert(&self, slot: usize, cap: Capability) -> Result<(), &'static str> {
if slot >= self.slots.len() { return Err("Index out of bounds"); }
let mut s = self.slots[slot].lock();
s.cap = cap;
Ok(())
}
pub fn mint(&self, src: usize, dest: usize, relation: Relation, rights: CapRights) -> Result<(), &'static str> {
let mut slots = (self.slots[src].lock(), self.slots[dest].lock());
let (src_slot, mut dest_slot) = (&slots.0, &mut slots.1);
if !src_slot.cap.is_valid() { return Err("Source empty"); }
if !src_slot.cap.rights.contains(CapRights::GRANT) { return Err("Insufficient rights to mint"); }
let final_rights = src_slot.cap.rights & rights;
dest_slot.cap = src_slot.cap;
dest_slot.cap.rights = final_rights;
dest_slot.cap.relation = relation;
dest_slot.parent_idx = Some(src);
Ok(())
}
pub fn revoke(&self, slot_idx: usize) {
for i in 0..self.slots.len() {
let mut should_clear = false;
{
let child = self.slots[i].lock();
if child.parent_idx == Some(slot_idx) {
should_clear = true;
}
}
if should_clear {
self.revoke(i);
let mut child = self.slots[i].lock();
child.cap = Capability::empty();
child.parent_idx = None;
}
}
}
pub fn get_cap(&self, slot: usize) -> Option<Capability> {
self.slots.get(slot).map(|s| s.lock().cap)
}
}

29
kernel/src/cap/object.rs Normal file
View File

@@ -0,0 +1,29 @@
use crate::mem::address::PhysAddr;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug)]
pub enum ObjectType {
Untyped,
Frame,
CNode,
ThreadBlock,
PageTable,
}
pub struct KernelObject {
pub phys_addr: PhysAddr,
pub size_bits: u8,
pub obj_type: ObjectType,
pub ref_count: AtomicUsize,
pub owner_id: u64,
}
impl KernelObject {
pub fn add_ref(&self) {
self.ref_count.fetch_add(1, Ordering::Relaxed);
}
pub fn release(&self) -> bool {
self.ref_count.fetch_sub(1, Ordering::Release) == 1
}
}

View File

@@ -12,7 +12,9 @@ use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker
use crate::mem::paging::{PageTable, PageTableFlags}; use crate::mem::paging::{PageTable, PageTableFlags};
use crate::mem::address::{PhysAddr, VirtAddr}; use crate::mem::address::{PhysAddr, VirtAddr};
use crate::cap::{Relation, CapRights, Capability, CapObject};
pub mod cap;
mod mem; mod mem;
#[macro_use] #[macro_use]
pub mod debug; pub mod debug;
@@ -156,7 +158,6 @@ static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
#[used] #[unsafe(link_section = ".requests_end_marker")] #[used] #[unsafe(link_section = ".requests_end_marker")]
static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new(); static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
// Точка входа
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
unsafe extern "C" fn kmain() -> ! { unsafe extern "C" fn kmain() -> ! {
assert!(BASE_REVISION.is_supported()); assert!(BASE_REVISION.is_supported());
@@ -173,47 +174,33 @@ unsafe extern "C" fn kmain() -> ! {
info!(console, "BOOT", "RINA Kernel Starting..."); info!(console, "BOOT", "RINA Kernel Starting...");
// Initialize Physical Memory Manager
unsafe { mem::pmm::BitmapPMM::init(&mmap_res, hhdm_offset); } unsafe { mem::pmm::BitmapPMM::init(&mmap_res, hhdm_offset); }
info!(console, "MEM", "Physical Memory Manager initialized."); info!(console, "MEM", "Physical Memory Manager initialized.");
// Prepare Kernel Page Tables (P4) let p4_phys = mem::pmm::alloc_frame().expect("OOM: Failed to allocate P4 table");
let p4_phys = mem::pmm::alloc_page().expect("OOM: Failed to allocate P4 table");
let p4 = unsafe { &mut *p4_phys.to_virt(hhdm_offset).as_mut_ptr::<PageTable>() }; let p4 = unsafe { &mut *p4_phys.to_virt(hhdm_offset).as_mut_ptr::<PageTable>() };
unsafe { core::ptr::write_bytes(p4 as *mut _ as *mut u8, 0, 4096); } unsafe { core::ptr::write_bytes(p4 as *mut _ as *mut u8, 0, 4096); }
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
// Mapping Strategy: HHDM + Identity Mapping for active segments
for entry in mmap_res.entries() { for entry in mmap_res.entries() {
let phys = PhysAddr(entry.base); let phys = PhysAddr(entry.base);
let virt_hhdm = phys.to_virt(hhdm_offset); let virt_hhdm = phys.to_virt(hhdm_offset);
p4.map_region(virt_hhdm, phys, entry.length, flags, hhdm_offset); p4.map_region(virt_hhdm, phys, entry.length, flags, hhdm_offset);
if entry.entry_type != limine::memory_map::EntryType::RESERVED { if entry.entry_type != limine::memory_map::EntryType::RESERVED {
p4.map_region(VirtAddr(entry.base), phys, entry.length, flags, hhdm_offset); p4.map_region(VirtAddr(entry.base), phys, entry.length, flags, hhdm_offset);
} }
} }
// Map the kernel itself based on provided executable addresses p4.map_region(VirtAddr(kaddr_res.virtual_base()), PhysAddr(kaddr_res.physical_base()), 0x1000 * 1024, flags, hhdm_offset);
p4.map_region(
VirtAddr(kaddr_res.virtual_base()),
PhysAddr(kaddr_res.physical_base()),
0x1000 * 1024, // 4MB default
flags,
hhdm_offset
);
info!(console, "MMU", "Switching to Kernel Page Tables..."); info!(console, "MMU", "Switching to Kernel Page Tables...");
unsafe { p4.activate(p4_phys); } unsafe { p4.activate(p4_phys); }
// Initialize Global Heap
let heap_start = 0xFFFF_9000_0000_0000; let heap_start = 0xFFFF_9000_0000_0000;
let heap_size = 8 * 1024 * 1024; let heap_size = 8 * 1024 * 1024;
for i in (0..heap_size).step_by(4096) { for i in (0..heap_size).step_by(4096) {
let frame = mem::pmm::alloc_page().expect("OOM: Heap allocation failed"); let frame = mem::pmm::alloc_frame().expect("OOM: Heap allocation failed");
p4.map_page(VirtAddr(heap_start + i as u64), frame, flags, hhdm_offset); p4.map_page(VirtAddr(heap_start + i as u64), frame, flags, hhdm_offset);
} }
@@ -221,13 +208,55 @@ unsafe extern "C" fn kmain() -> ! {
let mut allocator = allocator::ALLOCATOR.lock(); let mut allocator = allocator::ALLOCATOR.lock();
allocator.init(heap_start as usize, heap_size); allocator.init(heap_start as usize, heap_size);
} }
info!(console, "HEAP", "Global Allocator is online."); info!(console, "HEAP", "Global Allocator is online.");
// Integrity Test
let mut test_vec = Vec::new(); let root_cnode = cap::CNode::new(256);
test_vec.push(42);
info!(console, "CORE", "Vec test passed. Pointer: {:?}", test_vec.as_ptr()); if let Some(frame) = mem::pmm::alloc_frame() {
let mem_cap = Capability {
object: CapObject::Memory { phys: frame, size_pages: 1 },
rights: CapRights::all(),
relation: Relation::Strong,
token_sig: 0x1,
};
root_cnode.insert(0, mem_cap).unwrap();
info!(console, "CAP", "Root capability created at slot 0");
}
root_cnode.mint(0, 10, Relation::Borrow, CapRights::READ | CapRights::WRITE).unwrap();
if let Some(c) = root_cnode.get_cap(10) {
info!(console, "CAP", "Slot 10 (Borrowed): {:?}", c.relation);
}
root_cnode.revoke(0);
if let Some(c) = root_cnode.get_cap(10) {
if !c.is_valid() {
info!(console, "CAP", "Slot 10 successfully revoked.");
}
}
let logo = r#"
###########
##################
###### ######
##### #####
#### ##### ####
#### ### ###### ####
#### #### #### ####
#### #### ### ####
#### ### ## ### ####
#### ######## #### ####
#### #### #### ####
#### ###### ### ####
#### ####### ####
##### #####
###### ######
##################
############
"#;
let _ = writeln!(console, "{}", logo);
hcf(); hcf();
} }

View File

@@ -12,8 +12,5 @@ pub fn init(memmap: &limine::response::MemoryMapResponse, hhdm_offset: u64) {
#[allow(dead_code)] #[allow(dead_code)]
pub fn get_stats() -> (usize, usize) { pub fn get_stats() -> (usize, usize) {
unsafe { pmm::get_stats()
let pmm = pmm::get_pmm_unchecked();
(pmm.used_pages(), pmm.total_pages())
}
} }

View File

@@ -2,6 +2,7 @@ use crate::mem::address::{PhysAddr, VirtAddr};
use crate::mem::pmm; use crate::mem::pmm;
use core::arch::asm; use core::arch::asm;
use bitflags::bitflags; use bitflags::bitflags;
use crate::mem::pmm::PMM;
bitflags! { bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -65,8 +66,9 @@ impl PageTable {
fn get_or_create_next_table(&mut self, index: usize, hhdm: u64) -> &mut Self { fn get_or_create_next_table(&mut self, index: usize, hhdm: u64) -> &mut Self {
if self.entries[index] & PageTableFlags::PRESENT.bits() == 0 { if self.entries[index] & PageTableFlags::PRESENT.bits() == 0 {
let pt_phys = pmm::alloc_page().expect("VMM: Table allocation failed"); let pt_phys = pmm_alloc().expect("VMM: Out of memory for page tables");
let pt_virt = pt_phys.to_virt(hhdm); let pt_virt = pt_phys.to_virt(hhdm);
unsafe { core::ptr::write_bytes(pt_virt.as_mut_ptr::<u8>(), 0, 4096); } unsafe { core::ptr::write_bytes(pt_virt.as_mut_ptr::<u8>(), 0, 4096); }
self.entries[index] = pt_phys.0 | (PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER).bits(); self.entries[index] = pt_phys.0 | (PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER).bits();
@@ -75,3 +77,8 @@ impl PageTable {
unsafe { &mut *next_pt_phys.to_virt(hhdm).as_mut_ptr() } unsafe { &mut *next_pt_phys.to_virt(hhdm).as_mut_ptr() }
} }
} }
pub fn pmm_alloc() -> Option<PhysAddr> {
PMM.lock().as_mut()?.alloc_frame()
}

View File

@@ -0,0 +1,25 @@
use crate::cap::{Capability, CapObject, Relation, CapRights};
use crate::mem::address::PhysAddr;
pub struct PMActor {
pub root_untyped: Capability,
pub managed_range: (PhysAddr, PhysAddr),
}
impl PMActor {
pub fn carve_region(&self, offset: usize, size: usize) -> Capability {
if let CapObject::Memory { phys, .. } = self.root_untyped.object {
Capability {
object: CapObject::Memory {
phys: PhysAddr(phys.0 + offset as u64),
size_pages: size / 4096,
},
rights: CapRights::READ | CapRights::WRITE | CapRights::GRANT,
relation: Relation::Strong,
token_sig: 0xDEAD_BEEF,
}
} else {
panic!("PM: Root is not memory!");
}
}
}

View File

@@ -1,8 +1,8 @@
use crate::mem::address::{PhysAddr}; use crate::mem::address::PhysAddr;
use crate::mem::allocator::Locked;
pub const PAGE_SIZE: u64 = 4096; pub const PAGE_SIZE: u64 = 4096;
#[allow(dead_code)]
pub struct BitmapPMM { pub struct BitmapPMM {
bitmap: &'static mut [u8], bitmap: &'static mut [u8],
total_pages: usize, total_pages: usize,
@@ -10,7 +10,7 @@ pub struct BitmapPMM {
last_idx: usize, last_idx: usize,
} }
static mut PMM: Option<BitmapPMM> = None; pub static PMM: Locked<Option<BitmapPMM>> = Locked::new(None);
impl BitmapPMM { impl BitmapPMM {
#[allow(dead_code)] #[allow(dead_code)]
@@ -33,7 +33,6 @@ impl BitmapPMM {
.expect("PMM: Insufficient memory for bitmap"); .expect("PMM: Insufficient memory for bitmap");
let bitmap_virt_ptr = (bitmap_phys_addr + hhdm_offset) as *mut u8; let bitmap_virt_ptr = (bitmap_phys_addr + hhdm_offset) as *mut u8;
// Оборачиваем небезопасные операции
let bitmap_slice = unsafe { core::slice::from_raw_parts_mut(bitmap_virt_ptr, bitmap_size) }; let bitmap_slice = unsafe { core::slice::from_raw_parts_mut(bitmap_virt_ptr, bitmap_size) };
bitmap_slice.fill(0xFF); bitmap_slice.fill(0xFF);
@@ -58,9 +57,7 @@ impl BitmapPMM {
pmm.lock_frame(PhysAddr(0)); pmm.lock_frame(PhysAddr(0));
unsafe { *PMM.lock() = Some(pmm);
core::ptr::write(core::ptr::addr_of_mut!(PMM), Some(pmm));
}
} }
pub fn free_frame(&mut self, phys_addr: PhysAddr) { pub fn free_frame(&mut self, phys_addr: PhysAddr) {
@@ -88,41 +85,47 @@ impl BitmapPMM {
} }
pub fn alloc_frame(&mut self) -> Option<PhysAddr> { pub fn alloc_frame(&mut self) -> Option<PhysAddr> {
for i in self.last_idx..self.total_pages { let start_byte = self.last_idx / 8;
let byte_idx = i / 8; for i in start_byte..(self.bitmap.len()) {
if self.bitmap[byte_idx] == 0xFF { continue; } if self.bitmap[i] != 0xFF {
for bit in 0..8 {
let idx = i * 8 + bit;
if idx >= self.total_pages { return None; }
let bit_idx = i % 8; let addr = PhysAddr(idx as u64 * PAGE_SIZE);
if (self.bitmap[byte_idx] & (1 << bit_idx)) == 0 { if !self.is_locked(addr) {
let addr = PhysAddr(i as u64 * PAGE_SIZE);
self.lock_frame(addr); self.lock_frame(addr);
self.last_idx = i; self.last_idx = idx;
return Some(addr); return Some(addr);
} }
} }
}
}
None None
} }
}
#[allow(dead_code)] #[inline]
pub unsafe fn get_pmm_unchecked() -> &'static BitmapPMM { fn is_locked(&self, addr: PhysAddr) -> bool {
let pmm_ptr = core::ptr::addr_of!(PMM); let idx = (addr.0 / PAGE_SIZE) as usize;
unsafe { (*pmm_ptr).as_ref().expect("PMM: Not initialized") } (self.bitmap[idx / 8] & (1 << (idx % 8))) != 0
}
pub fn alloc_page() -> Option<PhysAddr> {
unsafe {
let pmm_ptr = core::ptr::addr_of_mut!(PMM);
(*pmm_ptr).as_mut()?.alloc_frame()
} }
} }
#[allow(dead_code)]
pub fn free_page(addr: PhysAddr) { pub fn alloc_frame() -> Option<PhysAddr> {
unsafe { PMM.lock().as_mut()?.alloc_frame()
let pmm_ptr = core::ptr::addr_of_mut!(PMM); }
if let Some(pmm) = (*pmm_ptr).as_mut() {
pub fn free_frame(addr: PhysAddr) {
if let Some(pmm) = PMM.lock().as_mut() {
pmm.free_frame(addr); pmm.free_frame(addr);
} }
} }
pub fn get_stats() -> (usize, usize) {
if let Some(pmm) = PMM.lock().as_ref() {
(pmm.used_pages(), pmm.total_pages())
} else {
(0, 0)
}
} }

BIN
logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 472 KiB