feat: ARCH 2.4-7

This commit is contained in:
Faynot
2026-07-08 23:18:47 +03:00
parent e754bac5e8
commit 1fc622c5da
4 changed files with 109 additions and 30 deletions

View File

@@ -10,6 +10,7 @@ pub use descriptor::*;
pub struct CNodeSlot { pub struct CNodeSlot {
pub cap: Capability, pub cap: Capability,
pub parent_idx: Option<usize>, pub parent_idx: Option<usize>,
pub children: Vec<usize>,
} }
pub struct CNode { pub struct CNode {
@@ -23,6 +24,7 @@ impl CNode {
slots.push(Locked::new(CNodeSlot { slots.push(Locked::new(CNodeSlot {
cap: Capability::empty(), cap: Capability::empty(),
parent_idx: None, parent_idx: None,
children: Vec::new(),
})); }));
} }
Self { slots } Self { slots }
@@ -42,12 +44,10 @@ impl CNode {
return Err("Index out of bounds"); return Err("Index out of bounds");
} }
// Защита от дедлока: если src == dest, операция не имеет смысла
if src == dest { if src == dest {
return Err("Source and destination slots must be different"); return Err("Source and destination slots must be different");
} }
// Захватываем блокировки в строгом порядке индексов для предотвращения инверсии блокировок (Lock Ranking)
let mut _guard_low; let mut _guard_low;
let mut _guard_high; let mut _guard_high;
@@ -68,72 +68,72 @@ impl CNode {
return Err("Insufficient rights to mint (Missing GRANT flag)"); return Err("Insufficient rights to mint (Missing GRANT flag)");
} }
// Права дочернего дескриптора не могут превышать права родительского
let final_rights = src_slot.cap.rights & rights; let final_rights = src_slot.cap.rights & rights;
dest_slot.children.clear();
dest_slot.cap = src_slot.cap; dest_slot.cap = src_slot.cap;
dest_slot.cap.rights = final_rights; dest_slot.cap.rights = final_rights;
dest_slot.cap.relation = relation; dest_slot.cap.relation = relation;
dest_slot.parent_idx = Some(src); dest_slot.parent_idx = Some(src);
src_slot.children.push(dest);
Ok(()) Ok(())
} }
/// Публичный метод отзыва прав.
/// Каскадно аннулирует все дочерние дескрипторы и отправляет их токены в lock-free очередь VMM.
pub fn revoke(&self, slot_idx: usize) -> Result<(), &'static str> { pub fn revoke(&self, slot_idx: usize) -> Result<(), &'static str> {
if slot_idx >= self.slots.len() { if slot_idx >= self.slots.len() {
return Err("Index out of bounds"); return Err("Index out of bounds");
} }
// Запускаем рекурсивный отзыв
self.revoke_internal(slot_idx); self.revoke_internal(slot_idx);
Ok(()) Ok(())
} }
/// Внутренний метод каскадного удаления.
/// Вынесен отдельно, чтобы избежать удержания блокировок при переходе на следующий уровень рекурсии.
fn revoke_internal(&self, slot_idx: usize) { fn revoke_internal(&self, slot_idx: usize) {
// 1. Сначала рекурсивно ищем и уничтожаем всех потомков данного слота let children: Vec<usize> = {
for i in 0..self.slots.len() { let slot = self.slots[slot_idx].lock();
let is_child = { slot.children.clone()
let child = self.slots[i].lock();
child.parent_idx == Some(slot_idx)
}; };
if is_child { for child in children {
// Рекурсивный спуск. Блокировка с child[i] к этому моменту уже снята, дедлока нет. let is_valid_child = {
self.revoke_internal(i); let c = self.slots[child].lock();
c.parent_idx == Some(slot_idx) && c.cap.is_valid()
};
if is_valid_child {
self.revoke_internal(child);
} }
} }
// 2. Теперь уничтожаем сам дескриптор в текущем слоте и отправляем его токен на отзыв в MMU let (token_to_revoke, parent_idx) = {
let token_to_revoke = {
let mut slot = self.slots[slot_idx].lock(); let mut slot = self.slots[slot_idx].lock();
if slot.cap.is_valid() { let parent = slot.parent_idx;
let token = slot.cap.token_sig; let token = if slot.cap.is_valid() {
let t = slot.cap.token_sig;
// Перезаписываем пустой заглушкой (уничтожаем сильную ссылку ядра)
slot.cap = Capability::empty(); slot.cap = Capability::empty();
slot.parent_idx = None; slot.parent_idx = None;
slot.children.clear();
Some(token) Some(t)
} else { } else {
None None
} };
(token, parent)
}; };
// 3. Если слот содержал валидный токен, асинхронно уведомляем VMM актёра через lock-free кольцевой буфер
if let Some(token) = token_to_revoke { if let Some(token) = token_to_revoke {
// В Elyz 0xDEAD_BEEF используется для сырого Untyped, его в MMU слать бессмысленно
if token != 0 && token != 0xDEAD_BEEF { if token != 0 && token != 0xDEAD_BEEF {
if let Err(e) = MMU_REVOCATION_QUEUE.push(token) { if let Err(e) = MMU_REVOCATION_QUEUE.push(token) {
// Переполнение очереди отзыва — критический сбой планировщика ресурсов ядра
panic!("FATAL: Критическое переполнение очереди отзыва MMU: {}", e); panic!("FATAL: Критическое переполнение очереди отзыва MMU: {}", e);
} }
} }
} }
if let Some(parent) = parent_idx {
let mut parent_slot = self.slots[parent].lock();
parent_slot.children.retain(|&c| c != slot_idx);
}
} }
pub fn get_cap(&self, slot: usize) -> Option<Capability> { pub fn get_cap(&self, slot: usize) -> Option<Capability> {

View File

@@ -1,3 +1,4 @@
pub mod idt; pub mod idt;
pub mod interrupts; pub mod interrupts;
pub mod lapic; pub mod lapic;
pub mod smp;

61
kernel/src/cpu/smp.rs Normal file
View File

@@ -0,0 +1,61 @@
use core::sync::atomic::{AtomicU64, Ordering};
use limine::mp;
use crate::mem::vmm::ACTIVE_CPUS_MASK;
static KERNEL_PML4: AtomicU64 = AtomicU64::new(0);
pub fn set_kernel_pml4(phys: u64) {
KERNEL_PML4.store(phys, Ordering::Release);
}
pub fn start_aps(mp_res: &limine::response::MpResponse) {
let bsp_lapic = mp_res.bsp_lapic_id();
let mut ap_count = 0;
for cpu in mp_res.cpus() {
if cpu.lapic_id == bsp_lapic {
continue;
}
cpu.goto_address.write(ap_entry);
ap_count += 1;
}
if ap_count == 0 {
return;
}
let target_mask: u64 = mp_res.cpus().iter()
.filter(|cpu| cpu.lapic_id != bsp_lapic && (cpu.lapic_id as u64) < 64)
.fold(0, |mask, cpu| mask | (1u64 << cpu.lapic_id));
while ACTIVE_CPUS_MASK.load(Ordering::Acquire) & target_mask != target_mask {
core::hint::spin_loop();
}
}
extern "C" fn ap_entry(cpu: &mp::Cpu) -> ! {
let pml4 = KERNEL_PML4.load(Ordering::Acquire);
if pml4 != 0 {
unsafe {
core::arch::asm!("mov cr3, {0}", in(reg) pml4,
options(nostack, preserves_flags));
}
}
unsafe {
(*core::ptr::addr_of!(crate::cpu::interrupts::IDT)).load();
}
crate::cpu::lapic::init();
let lapic_id = cpu.lapic_id;
if (lapic_id as u64) < 64 {
ACTIVE_CPUS_MASK.fetch_or(1u64 << lapic_id, Ordering::AcqRel);
}
unsafe { core::arch::asm!("sti", options(nomem, nostack, preserves_flags)); }
loop {
unsafe { core::arch::asm!("hlt", options(nomem, nostack, preserves_flags)); }
}
}

View File

@@ -8,7 +8,7 @@ use core::fmt::{self, Write};
use alloc::vec::Vec; use alloc::vec::Vec;
use limine::BaseRevision; use limine::BaseRevision;
use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker, HhdmRequest, MemoryMapRequest, ExecutableAddressRequest}; use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker, HhdmRequest, MemoryMapRequest, ExecutableAddressRequest, MpRequest};
use crate::mem::paging::{PageTable, PageTableFlags}; use crate::mem::paging::{PageTable, PageTableFlags};
use crate::mem::address::{PhysAddr, VirtAddr}; use crate::mem::address::{PhysAddr, VirtAddr};
@@ -161,6 +161,9 @@ static BASE_REVISION: BaseRevision = BaseRevision::new();
#[used] #[unsafe(link_section = ".requests")] #[used] #[unsafe(link_section = ".requests")]
static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
#[used] #[unsafe(link_section = ".requests")]
static MP_REQUEST: MpRequest = MpRequest::new();
#[used] #[unsafe(link_section = ".requests_start_marker")] #[used] #[unsafe(link_section = ".requests_start_marker")]
static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new(); static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
@@ -224,6 +227,7 @@ unsafe extern "C" fn kmain() -> ! {
info!(console, "MMU", "Activating Kernel Page Tables..."); info!(console, "MMU", "Activating Kernel Page Tables...");
unsafe { p4.activate(p4_phys); } unsafe { p4.activate(p4_phys); }
cpu::smp::set_kernel_pml4(p4_phys.0);
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;
@@ -250,6 +254,19 @@ unsafe extern "C" fn kmain() -> ! {
unsafe { core::arch::asm!("sti", options(nomem, nostack, preserves_flags)); } unsafe { core::arch::asm!("sti", options(nomem, nostack, preserves_flags)); }
if let Some(mp_res) = MP_REQUEST.get_response() {
let cpu_ct = mp_res.cpus().len();
let bsp_id = mp_res.bsp_lapic_id();
info!(console, "SMP", "Detected {} CPU(s), BSP APIC ID: {}", cpu_ct, bsp_id);
if cpu_ct > 1 {
cpu::smp::start_aps(mp_res);
let active = crate::mem::vmm::ACTIVE_CPUS_MASK.load(core::sync::atomic::Ordering::Relaxed);
info!(console, "SMP", "All APs online. Active mask: {:#018x}", active);
}
} else {
info!(console, "SMP", "No MP response — running single-core");
}
let root_cnode = cap::CNode::new(256); let root_cnode = cap::CNode::new(256);
if let Some(frame) = mem::pmm::alloc_frame() { if let Some(frame) = mem::pmm::alloc_frame() {
let mem_cap = Capability { let mem_cap = Capability {