feat: ARCH 2.4-7
This commit is contained in:
@@ -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> {
|
||||||
|
|||||||
@@ -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
61
kernel/src/cpu/smp.rs
Normal 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)); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user