feat: change font and release greate tty output
This commit is contained in:
@@ -25,7 +25,7 @@ impl<A> Locked<A> {
|
||||
|
||||
pub fn lock(&self) -> LockedGuard<'_, A> {
|
||||
while self.lock.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() {
|
||||
core::hint::spin_loop(); // Уступка в spinlock для снижения нагрузки на шину
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
LockedGuard {
|
||||
lock: &self.lock,
|
||||
@@ -49,14 +49,12 @@ impl<A> DerefMut for LockedGuard<'_, A> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { self.data }
|
||||
}
|
||||
|
||||
/// Узел односвязного списка свободных блоков
|
||||
struct ListNode {
|
||||
next: Option<&'static mut ListNode>,
|
||||
}
|
||||
|
||||
const BLOCK_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048];
|
||||
|
||||
/// Slab аллокатор для гранулярного выделения памяти
|
||||
pub struct SlabAllocator {
|
||||
list_heads: [Option<&'static mut ListNode>; BLOCK_SIZES.len()],
|
||||
heap_start: usize,
|
||||
@@ -80,13 +78,11 @@ impl SlabAllocator {
|
||||
self.heap_end = start + size;
|
||||
}
|
||||
|
||||
/// Поиск индекса блока под требуемый размер
|
||||
fn list_index(layout: &Layout) -> Option<usize> {
|
||||
let required_block_size = layout.size().max(layout.align());
|
||||
BLOCK_SIZES.iter().position(|&s| s >= required_block_size)
|
||||
}
|
||||
|
||||
/// Резервный Bump-аллокатор для нарезки новых Slab-блоков
|
||||
fn fallback_alloc(&mut self, layout: Layout) -> *mut u8 {
|
||||
let alloc_start = (self.next_bump + layout.align() - 1) & !(layout.align() - 1);
|
||||
let alloc_end = alloc_start.checked_add(layout.size()).unwrap_or(self.heap_end + 1);
|
||||
@@ -143,8 +139,6 @@ unsafe impl GlobalAlloc for Locked<SlabAllocator> {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Крупные регионы освобождаются через вызовы дескрипторов VMM/PMM,
|
||||
// глобальный аллокатор ядра их не трекает.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,15 +37,12 @@
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// Constants & helpers
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Maximum allocation order.
|
||||
/// `2^11 × 4 096 bytes = 8 MiB` per single allocation.
|
||||
pub const MAX_ORDER: usize = 11;
|
||||
|
||||
/// ⌈log₂(n)⌉ — the minimum order whose block size covers `page_count` pages.
|
||||
/// ⌈log2(n)⌉ — the minimum order whose block size covers `page_count` pages.
|
||||
///
|
||||
/// ```text
|
||||
/// order_for(1) = 0 (2^0 = 1)
|
||||
@@ -63,10 +60,7 @@ pub fn order_for(page_count: usize) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// BuddyAllocator
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Buddy allocator over a contiguous, pre-committed range of physical pages.
|
||||
///
|
||||
/// All page indices stored in free lists are **relative to the start of the
|
||||
@@ -89,8 +83,7 @@ pub struct BuddyAllocator {
|
||||
}
|
||||
|
||||
impl BuddyAllocator {
|
||||
// ─── Construction ─────────────────────────────────────────────────────────
|
||||
|
||||
//Construction
|
||||
/// Create a new allocator over `total_pages` pages, **all initially free**.
|
||||
///
|
||||
/// Uses a greedy largest-first decomposition to build the initial free lists
|
||||
@@ -127,7 +120,7 @@ impl BuddyAllocator {
|
||||
|
||||
// Size constraint: 2^order ≤ remaining → order ≤ ⌊log₂(remaining)⌋.
|
||||
let size_order = (usize::BITS as usize - 1)
|
||||
- remaining.leading_zeros() as usize; // ⌊log₂(remaining)⌋
|
||||
- remaining.leading_zeros() as usize; // ⌊log2(remaining)⌋
|
||||
|
||||
let order = MAX_ORDER.min(align_order).min(size_order);
|
||||
let block_size = 1usize << order;
|
||||
@@ -140,8 +133,7 @@ impl BuddyAllocator {
|
||||
this
|
||||
}
|
||||
|
||||
// ─── Allocation ───────────────────────────────────────────────────────────
|
||||
|
||||
//Allocation
|
||||
/// Allocate a 2^`order`-page block.
|
||||
///
|
||||
/// Returns the **relative** page index of the block's first page, or `None`
|
||||
@@ -206,7 +198,7 @@ impl BuddyAllocator {
|
||||
self.alloc(order).map(|idx| (idx, order))
|
||||
}
|
||||
|
||||
// ─── Deallocation ─────────────────────────────────────────────────────────
|
||||
//Deallocation
|
||||
|
||||
/// Return a 2^`order`-page block at **relative** index `block_idx` to the
|
||||
/// free pool, coalescing with free buddies up the order chain.
|
||||
@@ -269,7 +261,7 @@ impl BuddyAllocator {
|
||||
self.free_lists[order].push(block_idx);
|
||||
}
|
||||
|
||||
// ─── Introspection ────────────────────────────────────────────────────────
|
||||
//Introspection
|
||||
|
||||
/// Number of pages currently available for allocation.
|
||||
#[inline]
|
||||
|
||||
@@ -29,7 +29,7 @@ pub struct PageTable {
|
||||
}
|
||||
|
||||
impl PageTable {
|
||||
// ── Bulk mapping ─────────────────────────────────────────────────────────
|
||||
//Bulk mapping
|
||||
|
||||
/// Map a contiguous physical range to a contiguous virtual range.
|
||||
/// Allocates intermediate page-table pages from the PMM as needed.
|
||||
@@ -48,7 +48,7 @@ impl PageTable {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Single-page operations ────────────────────────────────────────────────
|
||||
//Single-page operations
|
||||
|
||||
/// Map a single 4 KiB page.
|
||||
/// Allocates intermediate PT pages from the PMM if they do not exist.
|
||||
@@ -134,7 +134,7 @@ impl PageTable {
|
||||
Some(PhysAddr((p1e & PTE_ADDR_MASK) | (virt.0 & 0xFFF)))
|
||||
}
|
||||
|
||||
// ── CR3 ──────────────────────────────────────────────────────────────────
|
||||
// CR3
|
||||
|
||||
/// Load this page table into CR3 (full TLB flush, no PCID).
|
||||
///
|
||||
@@ -151,7 +151,7 @@ impl PageTable {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Private walk helpers ──────────────────────────────────────────────────────
|
||||
//Private walk helpers
|
||||
|
||||
impl PageTable {
|
||||
/// Walk (or create) the path P4 → P3 → P2 → P1, returning a mutable
|
||||
@@ -201,7 +201,7 @@ impl PageTable {
|
||||
}
|
||||
}
|
||||
|
||||
// ── PMM shim ─────────────────────────────────────────────────────────────────
|
||||
//PMM shim
|
||||
|
||||
/// Allocate a single physical frame for page-table use.
|
||||
/// This thin wrapper avoids a direct dependency cycle between paging ↔ pmm.
|
||||
|
||||
@@ -49,9 +49,7 @@ use crate::mem::pmm::PAGE_SIZE;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// Message packing constants
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const QUEUE_SIZE: usize = 1024; // power-of-two
|
||||
const QUEUE_MASK: usize = QUEUE_SIZE - 1;
|
||||
@@ -67,10 +65,7 @@ mod packing {
|
||||
pub const ARG_MASK: u64 = 0x000F_FFFF; // 20 bits
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// Request type
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Asynchronous request submitted to a `PMActor` inbox.
|
||||
///
|
||||
/// `channel_id` identifies where the response should be routed.
|
||||
@@ -163,9 +158,7 @@ impl PMRequest {
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// Response type
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Result returned by `PMActor::process_messages()` for each completed request.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -194,10 +187,7 @@ pub enum PMResult {
|
||||
Freed { pages_returned: usize },
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// Lock-free MPSC inbox
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// MPSC ring buffer for PMRequest values.
|
||||
///
|
||||
/// Producers (any core, any context) call `send`; the owning PMActor calls
|
||||
@@ -268,10 +258,7 @@ impl PMActorQueue {
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// PM Actor
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// An autonomous physical-memory actor.
|
||||
///
|
||||
/// Owns a `BuddyAllocator` over its capital range and a lock-free MPSC inbox.
|
||||
@@ -284,16 +271,12 @@ impl PMActorQueue {
|
||||
pub struct PMActor {
|
||||
/// Unique identity within the actor federation.
|
||||
pub actor_id: u64,
|
||||
|
||||
/// Root strong capability over the entire managed physical range.
|
||||
pub root_untyped: Capability,
|
||||
|
||||
/// `(inclusive_start, exclusive_end)` physical addresses.
|
||||
pub managed_range: (PhysAddr, PhysAddr),
|
||||
|
||||
/// Inbox — producers write here, actor reads here.
|
||||
queue: PMActorQueue,
|
||||
|
||||
/// Local buddy allocator. Only ever touched in `process_messages`.
|
||||
buddy: BuddyAllocator,
|
||||
}
|
||||
@@ -319,7 +302,7 @@ impl PMActor {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Producer API (callable from any context) ──────────────────────────
|
||||
//Producer API (callable from any context)
|
||||
|
||||
/// Submit a request to this actor's inbox.
|
||||
///
|
||||
@@ -329,7 +312,7 @@ impl PMActor {
|
||||
self.queue.send(req)
|
||||
}
|
||||
|
||||
// ─── Consumer API (actor's own scheduled context) ─────────────────────
|
||||
//Consumer API (actor's own scheduled context)
|
||||
|
||||
/// Drain the inbox and execute all pending requests.
|
||||
///
|
||||
@@ -370,7 +353,7 @@ impl PMActor {
|
||||
responses
|
||||
}
|
||||
|
||||
// ─── Introspection ────────────────────────────────────────────────────
|
||||
//Introspection
|
||||
|
||||
/// Free pages remaining in this actor's buddy pool.
|
||||
#[inline]
|
||||
@@ -385,7 +368,7 @@ impl PMActor {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Private handler implementations ──────────────────────────────────────────
|
||||
//Private handler implementations
|
||||
|
||||
impl PMActor {
|
||||
fn handle_allocate(
|
||||
|
||||
@@ -71,7 +71,7 @@ impl BitmapPMM {
|
||||
*PMM.lock() = Some(pmm);
|
||||
}
|
||||
|
||||
// ── Core operations ───────────────────────────────────────────────────────
|
||||
//Core operations
|
||||
|
||||
/// Mark a frame as free. Idempotent (double-free is a no-op, not UB).
|
||||
pub fn free_frame(&mut self, phys_addr: PhysAddr) {
|
||||
@@ -175,7 +175,7 @@ impl BitmapPMM {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Module-level convenience functions ───────────────────────────────────────
|
||||
//Module-level convenience functions
|
||||
|
||||
pub fn alloc_frame() -> Option<PhysAddr> {
|
||||
PMM.lock().as_mut()?.alloc_frame()
|
||||
|
||||
@@ -37,10 +37,7 @@ use crate::events::MMU_REVOCATION_QUEUE;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// Error type
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum VmError {
|
||||
/// PMM returned `None` — no physical frames available.
|
||||
@@ -80,9 +77,7 @@ impl core::fmt::Display for VmError {
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// VMA flags
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -113,9 +108,7 @@ impl VmaFlags {
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// VMA backing
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VmaBacking {
|
||||
@@ -159,9 +152,7 @@ impl VmaBacking {
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// VMA region
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VmaRegion {
|
||||
@@ -180,9 +171,7 @@ impl VmaRegion {
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// ASID / PCID allocator (bitmap-based, const-initializable, O(1) amortised)
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// x86-64 PCIDs: 0 (kernel, no PCID tagging) and 4095 (reserved by spec).
|
||||
/// Valid user ASIDs: 1 – 4094 inclusive.
|
||||
@@ -262,9 +251,7 @@ fn free_asid(asid: u16) {
|
||||
ASID_ALLOC.lock().free(asid);
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// CPU feature detection (call once during boot, before first activate())
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Set to `true` at boot if CPUID.07H:EBX[10] = 1 (INVPCID supported).
|
||||
static INVPCID_SUPPORTED: AtomicBool = AtomicBool::new(false);
|
||||
@@ -302,9 +289,7 @@ pub fn init_cpu_features() {
|
||||
INVPCID_SUPPORTED.store(supported, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// Address space
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
pub struct AddressSpace {
|
||||
/// Hardware PCID written to CR3 bits 11:0.
|
||||
@@ -317,8 +302,6 @@ pub struct AddressSpace {
|
||||
hhdm: u64,
|
||||
}
|
||||
|
||||
// ── Private helpers ───────────────────────────────────────────────────────────
|
||||
|
||||
impl AddressSpace {
|
||||
#[inline]
|
||||
unsafe fn pml4_raw(&self) -> *mut PageTable {
|
||||
@@ -392,11 +375,7 @@ impl AddressSpace {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Public API ────────────────────────────────────────────────────────────────
|
||||
|
||||
impl AddressSpace {
|
||||
// ─── Construction ──────────────────────────────────────────────────────
|
||||
|
||||
/// Allocate a fresh, empty address space with a zeroed PML4.
|
||||
pub fn new(hhdm: u64) -> Result<Self, VmError> {
|
||||
let pml4_phys = pmm::alloc_frame().ok_or(VmError::OutOfMemory)?;
|
||||
@@ -480,8 +459,6 @@ impl AddressSpace {
|
||||
Ok(virt)
|
||||
}
|
||||
|
||||
// ─── Zero-copy shared mapping (new) ───────────────────────────────────
|
||||
|
||||
/// Map `page_count` pages of physical memory owned by `owner_cap` into
|
||||
/// this address space at `virt`.
|
||||
///
|
||||
@@ -533,8 +510,6 @@ impl AddressSpace {
|
||||
Ok(virt)
|
||||
}
|
||||
|
||||
// ─── Demand paging ─────────────────────────────────────────────────────
|
||||
|
||||
/// Handle a hardware page fault at `fault_addr`.
|
||||
///
|
||||
/// Returns `Ok(())` if the fault was a valid lazy demand-page (caller should
|
||||
@@ -579,8 +554,6 @@ impl AddressSpace {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ─── Unmapping ─────────────────────────────────────────────────────────
|
||||
|
||||
/// Unmap the VMA containing `virt`, free its frames (if owned), flush TLB.
|
||||
pub fn unmap_region(&mut self, virt: VirtAddr) -> Result<(), VmError> {
|
||||
let idx = self.find_idx(virt).ok_or(VmError::RegionNotFound)?;
|
||||
@@ -591,8 +564,6 @@ impl AddressSpace {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ─── Capability revocation ─────────────────────────────────────────────
|
||||
|
||||
/// Atomically unmap all VMAs associated with `cap_token` (skip PINNED).
|
||||
///
|
||||
/// Hardware access is terminated before this function returns.
|
||||
@@ -618,14 +589,14 @@ impl AddressSpace {
|
||||
tlb_flush_asid(self.asid);
|
||||
}
|
||||
|
||||
// ─── Address translation ───────────────────────────────────────────────
|
||||
//Address translation
|
||||
|
||||
/// Walk the live page table to translate `virt` → physical address.
|
||||
pub fn translate(&self, virt: VirtAddr) -> Option<PhysAddr> {
|
||||
unsafe { (*self.pml4_raw()).translate(virt, self.hhdm) }
|
||||
}
|
||||
|
||||
// ─── Activation ────────────────────────────────────────────────────────
|
||||
//Activation
|
||||
|
||||
/// Load this address space into the CPU (context switch).
|
||||
///
|
||||
@@ -646,8 +617,6 @@ impl AddressSpace {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Introspection ─────────────────────────────────────────────────────
|
||||
|
||||
#[inline] pub fn regions(&self) -> &[VmaRegion] { &self.regions }
|
||||
#[inline] pub fn region_count(&self) -> usize { self.regions.len() }
|
||||
|
||||
@@ -670,10 +639,7 @@ impl Drop for AddressSpace {
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// TLB management
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Flush all TLB entries tagged with `asid` (PCID) on the current core.
|
||||
///
|
||||
/// Uses `INVPCID` type-1 (single-context flush) when available (Broadwell+,
|
||||
@@ -714,10 +680,7 @@ pub fn tlb_flush_all() {
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// Global kernel address space
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// The one kernel address space. Initialised once during boot.
|
||||
pub static KERNEL_SPACE: Locked<Option<AddressSpace>> = Locked::new(None);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user