feat: implement capability-based memory management foundation
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
// src/cap/descriptor.rs
|
||||
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 { frame: PhysAddr, size: usize },
|
||||
Thread { id: u64 },
|
||||
CNode { frame: PhysAddr, size: usize }, // Капа на таблицу других кап
|
||||
Endpoint { id: u64 }, // Для IPC
|
||||
Memory { phys: PhysAddr, size_pages: usize },
|
||||
CNode { phys: PhysAddr, slots: usize },
|
||||
PMActor { id: u64 },
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
@@ -16,7 +21,7 @@ bitflags::bitflags! {
|
||||
const READ = 1 << 0;
|
||||
const WRITE = 1 << 1;
|
||||
const EXECUTE = 1 << 2;
|
||||
const GRANT = 1 << 3; // Право передавать эту капу дальше
|
||||
const GRANT = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +29,8 @@ bitflags::bitflags! {
|
||||
pub struct Capability {
|
||||
pub object: CapObject,
|
||||
pub rights: CapRights,
|
||||
pub relation: Relation,
|
||||
pub token_sig: u64,
|
||||
}
|
||||
|
||||
impl Capability {
|
||||
@@ -31,6 +38,12 @@ impl Capability {
|
||||
Self {
|
||||
object: CapObject::Empty,
|
||||
rights: CapRights::empty(),
|
||||
relation: Relation::Borrow,
|
||||
token_sig: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_valid(&self) -> bool {
|
||||
!matches!(self.object, CapObject::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,75 @@
|
||||
// src/cap/mod.rs
|
||||
pub mod descriptor;
|
||||
pub mod object;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
pub use descriptor::{Capability, CapObject, CapRights};
|
||||
use crate::mem::allocator::Locked;
|
||||
pub use descriptor::*;
|
||||
|
||||
pub struct CNodeSlot {
|
||||
pub cap: Capability,
|
||||
pub parent_idx: Option<usize>,
|
||||
}
|
||||
|
||||
/// CNode — это таблица возможностей.
|
||||
/// Дескриптор (u64) — это просто индекс в этом векторе.
|
||||
pub struct CNode {
|
||||
caps: Vec<Capability>,
|
||||
pub slots: Vec<Locked<CNodeSlot>>,
|
||||
}
|
||||
|
||||
impl CNode {
|
||||
pub fn new(size: usize) -> Self {
|
||||
let mut caps = Vec::with_capacity(size);
|
||||
let mut slots = Vec::with_capacity(size);
|
||||
for _ in 0..size {
|
||||
caps.push(Capability::empty());
|
||||
slots.push(Locked::new(CNodeSlot {
|
||||
cap: Capability::empty(),
|
||||
parent_idx: None,
|
||||
}));
|
||||
}
|
||||
Self { caps }
|
||||
Self { slots }
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, slot: usize, cap: Capability) -> Result<(), &'static str> {
|
||||
if slot >= self.caps.len() { return Err("Index out of bounds"); }
|
||||
self.caps[slot] = cap;
|
||||
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 get(&self, slot: usize) -> Option<&Capability> {
|
||||
self.caps.get(slot)
|
||||
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
29
kernel/src/cap/object.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker
|
||||
|
||||
use crate::mem::paging::{PageTable, PageTableFlags};
|
||||
use crate::mem::address::{PhysAddr, VirtAddr};
|
||||
use crate::cap::{Relation, CapRights, Capability, CapObject};
|
||||
|
||||
pub mod cap;
|
||||
mod mem;
|
||||
@@ -157,7 +158,6 @@ static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
|
||||
#[used] #[unsafe(link_section = ".requests_end_marker")]
|
||||
static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
|
||||
|
||||
// Точка входа
|
||||
#[unsafe(no_mangle)]
|
||||
unsafe extern "C" fn kmain() -> ! {
|
||||
assert!(BASE_REVISION.is_supported());
|
||||
@@ -174,12 +174,10 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
|
||||
info!(console, "BOOT", "RINA Kernel Starting...");
|
||||
|
||||
// 1. Инициализация PMM
|
||||
unsafe { mem::pmm::BitmapPMM::init(&mmap_res, hhdm_offset); }
|
||||
info!(console, "MEM", "Physical Memory Manager initialized.");
|
||||
|
||||
// 2. Инициализация страничного управления
|
||||
let p4_phys = mem::pmm::alloc_page().expect("OOM: Failed to allocate P4 table");
|
||||
let p4_phys = mem::pmm::alloc_frame().expect("OOM: Failed to allocate P4 table");
|
||||
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); }
|
||||
|
||||
@@ -199,11 +197,10 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
info!(console, "MMU", "Switching to Kernel Page Tables...");
|
||||
unsafe { p4.activate(p4_phys); }
|
||||
|
||||
// 3. Инициализация Кучи
|
||||
let heap_start = 0xFFFF_9000_0000_0000;
|
||||
let heap_size = 8 * 1024 * 1024;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -213,28 +210,33 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
}
|
||||
info!(console, "HEAP", "Global Allocator is online.");
|
||||
|
||||
// --- Инициализация Модели Capabilities ---
|
||||
|
||||
// Создаем корневой CNode для ядра на 256 слотов
|
||||
let mut root_cnode = cap::CNode::new(256);
|
||||
let root_cnode = cap::CNode::new(256);
|
||||
|
||||
// Пример: Превращаем физическую страницу в Capability "Memory"
|
||||
if let Some(frame) = mem::pmm::alloc_page() {
|
||||
let mem_cap = cap::Capability {
|
||||
object: cap::CapObject::Memory { frame, size: 4096 },
|
||||
rights: cap::CapRights::READ | cap::CapRights::WRITE,
|
||||
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,
|
||||
};
|
||||
|
||||
// Помещаем в слот 0. Теперь "Дескриптор 0" — это право доступа к этой памяти.
|
||||
root_cnode.insert(0, mem_cap).unwrap();
|
||||
info!(console, "CAP", "Created memory capability at slot 0");
|
||||
info!(console, "CAP", "Root capability created at slot 0");
|
||||
}
|
||||
|
||||
// Проверка
|
||||
if let Some(c) = root_cnode.get(0) {
|
||||
info!(console, "CAP", "Slot 0 verification: {:?}", c.object);
|
||||
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#"
|
||||
###########
|
||||
##################
|
||||
|
||||
@@ -12,8 +12,5 @@ pub fn init(memmap: &limine::response::MemoryMapResponse, hhdm_offset: u64) {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_stats() -> (usize, usize) {
|
||||
unsafe {
|
||||
let pmm = pmm::get_pmm_unchecked();
|
||||
(pmm.used_pages(), pmm.total_pages())
|
||||
}
|
||||
pmm::get_stats()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::mem::address::{PhysAddr, VirtAddr};
|
||||
use crate::mem::pmm;
|
||||
use core::arch::asm;
|
||||
use bitflags::bitflags;
|
||||
use crate::mem::pmm::PMM;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -63,10 +64,11 @@ 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 {
|
||||
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);
|
||||
|
||||
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();
|
||||
@@ -75,3 +77,8 @@ impl PageTable {
|
||||
unsafe { &mut *next_pt_phys.to_virt(hhdm).as_mut_ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pmm_alloc() -> Option<PhysAddr> {
|
||||
PMM.lock().as_mut()?.alloc_frame()
|
||||
}
|
||||
|
||||
|
||||
25
kernel/src/mem/pm_manages.rs
Normal file
25
kernel/src/mem/pm_manages.rs
Normal 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct BitmapPMM {
|
||||
bitmap: &'static mut [u8],
|
||||
total_pages: usize,
|
||||
@@ -10,7 +10,7 @@ pub struct BitmapPMM {
|
||||
last_idx: usize,
|
||||
}
|
||||
|
||||
static mut PMM: Option<BitmapPMM> = None;
|
||||
pub static PMM: Locked<Option<BitmapPMM>> = Locked::new(None);
|
||||
|
||||
impl BitmapPMM {
|
||||
#[allow(dead_code)]
|
||||
@@ -33,7 +33,6 @@ impl BitmapPMM {
|
||||
.expect("PMM: Insufficient memory for bitmap");
|
||||
|
||||
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) };
|
||||
bitmap_slice.fill(0xFF);
|
||||
|
||||
@@ -58,9 +57,7 @@ impl BitmapPMM {
|
||||
|
||||
pmm.lock_frame(PhysAddr(0));
|
||||
|
||||
unsafe {
|
||||
core::ptr::write(core::ptr::addr_of_mut!(PMM), Some(pmm));
|
||||
}
|
||||
*PMM.lock() = Some(pmm);
|
||||
}
|
||||
|
||||
pub fn free_frame(&mut self, phys_addr: PhysAddr) {
|
||||
@@ -87,42 +84,48 @@ impl BitmapPMM {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_frame(&mut self) -> Option<PhysAddr> {
|
||||
for i in self.last_idx..self.total_pages {
|
||||
let byte_idx = i / 8;
|
||||
if self.bitmap[byte_idx] == 0xFF { continue; }
|
||||
|
||||
let bit_idx = i % 8;
|
||||
if (self.bitmap[byte_idx] & (1 << bit_idx)) == 0 {
|
||||
let addr = PhysAddr(i as u64 * PAGE_SIZE);
|
||||
self.lock_frame(addr);
|
||||
self.last_idx = i;
|
||||
return Some(addr);
|
||||
pub fn alloc_frame(&mut self) -> Option<PhysAddr> {
|
||||
let start_byte = self.last_idx / 8;
|
||||
for i in start_byte..(self.bitmap.len()) {
|
||||
if self.bitmap[i] != 0xFF {
|
||||
for bit in 0..8 {
|
||||
let idx = i * 8 + bit;
|
||||
if idx >= self.total_pages { return None; }
|
||||
|
||||
let addr = PhysAddr(idx as u64 * PAGE_SIZE);
|
||||
if !self.is_locked(addr) {
|
||||
self.lock_frame(addr);
|
||||
self.last_idx = idx;
|
||||
return Some(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn get_pmm_unchecked() -> &'static BitmapPMM {
|
||||
let pmm_ptr = core::ptr::addr_of!(PMM);
|
||||
unsafe { (*pmm_ptr).as_ref().expect("PMM: Not initialized") }
|
||||
}
|
||||
|
||||
pub fn alloc_page() -> Option<PhysAddr> {
|
||||
unsafe {
|
||||
let pmm_ptr = core::ptr::addr_of_mut!(PMM);
|
||||
(*pmm_ptr).as_mut()?.alloc_frame()
|
||||
#[inline]
|
||||
fn is_locked(&self, addr: PhysAddr) -> bool {
|
||||
let idx = (addr.0 / PAGE_SIZE) as usize;
|
||||
(self.bitmap[idx / 8] & (1 << (idx % 8))) != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn free_page(addr: PhysAddr) {
|
||||
unsafe {
|
||||
let pmm_ptr = core::ptr::addr_of_mut!(PMM);
|
||||
if let Some(pmm) = (*pmm_ptr).as_mut() {
|
||||
pmm.free_frame(addr);
|
||||
}
|
||||
|
||||
pub fn alloc_frame() -> Option<PhysAddr> {
|
||||
PMM.lock().as_mut()?.alloc_frame()
|
||||
}
|
||||
|
||||
pub fn free_frame(addr: PhysAddr) {
|
||||
if let Some(pmm) = PMM.lock().as_mut() {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user