WIP: Global page info structs.
This commit is contained in:
+17
-7
@@ -2,7 +2,7 @@ use core::{
|
||||
cmp,
|
||||
mem,
|
||||
slice,
|
||||
sync::atomic::{self, AtomicUsize, Ordering},
|
||||
sync::atomic::{self, AtomicUsize, Ordering}, cell::SyncUnsafeCell,
|
||||
};
|
||||
use rmm::{
|
||||
KILOBYTE,
|
||||
@@ -102,7 +102,7 @@ unsafe fn inner<A: Arch>(
|
||||
}
|
||||
}
|
||||
|
||||
// Map kernel at KERNEL_OFFSET and identity map too
|
||||
// Map kernel at KERNEL_OFFSET and map linearly too
|
||||
for i in 0..kernel_size_aligned / A::PAGE_SIZE {
|
||||
let phys = PhysicalAddress::new(kernel_base + i * A::PAGE_SIZE);
|
||||
let virt = VirtualAddress::new(crate::KERNEL_OFFSET + i * A::PAGE_SIZE);
|
||||
@@ -226,10 +226,18 @@ impl core::fmt::Debug for LockedAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
static mut AREAS: [MemoryArea; 512] = [MemoryArea {
|
||||
static AREAS: SyncUnsafeCell<[MemoryArea; 512]> = SyncUnsafeCell::new([MemoryArea {
|
||||
base: PhysicalAddress::new(0),
|
||||
size: 0,
|
||||
}; 512];
|
||||
}; 512]);
|
||||
static AREA_COUNT: SyncUnsafeCell<u16> = SyncUnsafeCell::new(0);
|
||||
|
||||
pub fn areas() -> &'static [MemoryArea] {
|
||||
// SAFETY: Both AREAS and AREA_COUNT are initialized once and then never changed.
|
||||
//
|
||||
// TODO: Memory hotplug?
|
||||
unsafe { &(&*AREAS.get())[..AREA_COUNT.get().read().into()] }
|
||||
}
|
||||
|
||||
pub static FRAME_ALLOCATOR: LockedAllocator = LockedAllocator;
|
||||
|
||||
@@ -420,13 +428,15 @@ pub unsafe fn init(
|
||||
continue;
|
||||
}
|
||||
|
||||
AREAS[area_i].base = PhysicalAddress::new(base);
|
||||
AREAS[area_i].size = size;
|
||||
let areas = &mut *AREAS.get();
|
||||
areas[area_i].base = PhysicalAddress::new(base);
|
||||
areas[area_i].size = size;
|
||||
area_i += 1;
|
||||
}
|
||||
AREA_COUNT.get().write(area_i as u16);
|
||||
|
||||
let allocator = inner::<A>(
|
||||
&AREAS,
|
||||
areas(),
|
||||
kernel_base, kernel_size_aligned,
|
||||
stack_base, stack_size_aligned,
|
||||
env_base, env_size_aligned,
|
||||
|
||||
@@ -7,7 +7,7 @@ use core::cell::Cell;
|
||||
use core::slice;
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
|
||||
use crate::allocator;
|
||||
use crate::{allocator, memory};
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::acpi;
|
||||
use crate::arch::pti;
|
||||
@@ -263,6 +263,8 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
// Initialize devices (for AP)
|
||||
device::init_ap();
|
||||
|
||||
memory::init_mm();
|
||||
|
||||
AP_READY.store(true, Ordering::SeqCst);
|
||||
|
||||
cpu_id
|
||||
|
||||
@@ -529,17 +529,11 @@ pub struct GrantInfo {
|
||||
pub(crate) provider: Provider,
|
||||
}
|
||||
|
||||
/// The arch-specific user page tables are throwaway, and this enum contains all required
|
||||
/// information to update lazy mappings in the event of page faults.
|
||||
#[derive(Debug)]
|
||||
pub enum Provider {
|
||||
/// The grant was initialized with (lazy) zeroed memory, and any changes will make it owned by
|
||||
/// the frame allocator.
|
||||
//
|
||||
// TODO: strong-count-only Arc?
|
||||
//
|
||||
// https://internals.rust-lang.org/t/pre-rfc-rc-and-arc-with-only-strong-count/5828
|
||||
Allocated { pages: Box<[Option<PageInfo>]> },
|
||||
Allocated,
|
||||
/// The grant is not owned, but borrowed from physical memory frames that do not belong to the
|
||||
/// frame allocator.
|
||||
PhysBorrowed { base: Frame },
|
||||
@@ -547,7 +541,7 @@ pub enum Provider {
|
||||
///
|
||||
/// All grants in the specified range must be of type Allocated.
|
||||
// TODO: Vec?
|
||||
External { address_space: Arc<RwLock<AddrSpace>>, src_base: Page, cow: bool, pages: Option<Box<[Option<PageInfo>]>> },
|
||||
External { address_space: Arc<RwLock<AddrSpace>>, src_base: Page, cow: bool },
|
||||
/// The memory is borrowed from another address space, but managed by a scheme via fmap.
|
||||
// TODO: This is probably a very heavy way to keep track of fmap'd files, perhaps move to the
|
||||
// ~~context~~ address space?
|
||||
|
||||
+94
-1
@@ -3,14 +3,23 @@
|
||||
|
||||
use core::cmp;
|
||||
use core::num::NonZeroUsize;
|
||||
use core::ops::Deref;
|
||||
use core::sync::atomic::AtomicUsize;
|
||||
|
||||
use crate::arch::rmm::LockedAllocator;
|
||||
use crate::common::try_box_slice_new;
|
||||
pub use crate::paging::{PAGE_SIZE, PhysicalAddress};
|
||||
use crate::rmm::areas;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use rmm::{
|
||||
FrameAllocator,
|
||||
FrameCount,
|
||||
};
|
||||
use spin::RwLock;
|
||||
use crate::syscall::flag::{PartialAllocStrategy, PhysallocFlags};
|
||||
use crate::syscall::error::{ENOMEM, Error};
|
||||
|
||||
@@ -112,11 +121,14 @@ impl Frame {
|
||||
pub fn range_inclusive(start: Frame, end: Frame) -> FrameIter {
|
||||
FrameIter { start, end }
|
||||
}
|
||||
pub fn next_by(&self, n: usize) -> Self {
|
||||
pub fn next_by(self, n: usize) -> Self {
|
||||
Self {
|
||||
number: self.number.get().checked_add(n).and_then(NonZeroUsize::new).expect("overflow in Frame::next_by"),
|
||||
}
|
||||
}
|
||||
pub fn offset_from(self, from: Self) -> usize {
|
||||
from.number.get().checked_sub(self.number.get()).expect("overflow in Frame::offset_from")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FrameIter {
|
||||
@@ -176,3 +188,84 @@ impl Drop for RaiiFrame {
|
||||
crate::memory::deallocate_frames(self.inner, 1);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PageInfo {
|
||||
refcount: AtomicUsize,
|
||||
cow_refcount: AtomicUsize,
|
||||
flags: FrameFlags,
|
||||
_padding: usize,
|
||||
}
|
||||
bitflags::bitflags! {
|
||||
struct FrameFlags: usize {
|
||||
const NONE = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Very read-heavy RwLock?
|
||||
pub static SECTIONS: RwLock<Box<[&'static Section]>> = RwLock::new(Box::new([]));
|
||||
|
||||
pub struct Section {
|
||||
base: Frame,
|
||||
frames: Box<[PageInfo]>,
|
||||
}
|
||||
|
||||
pub const MAX_SECTION_SIZE_BITS: u32 = 27;
|
||||
pub const MAX_SECTION_SIZE: usize = 1 << MAX_SECTION_SIZE_BITS;
|
||||
pub const MAX_SECTION_PAGE_COUNT: usize = MAX_SECTION_SIZE / PAGE_SIZE;
|
||||
|
||||
#[cold]
|
||||
pub fn init_mm() {
|
||||
let mut guard = SECTIONS.write();
|
||||
let mut sections = Vec::new();
|
||||
|
||||
for memory_map_area in areas().iter().filter(|area| area.size > 0) {
|
||||
let mut pages_left = memory_map_area.size.div_floor(PAGE_SIZE);
|
||||
let mut base = Frame::containing_address(memory_map_area.base);
|
||||
|
||||
while pages_left > 0 {
|
||||
let section_page_count = core::cmp::min(pages_left, MAX_SECTION_PAGE_COUNT);
|
||||
|
||||
sections.push(Box::leak(Box::new(Section {
|
||||
base,
|
||||
// TODO: zeroed?
|
||||
frames: try_box_slice_new(PageInfo::new, section_page_count).expect("failed to allocate pages array"),
|
||||
})) as &'static Section);
|
||||
|
||||
pages_left -= section_page_count;
|
||||
base = base.next_by(section_page_count);
|
||||
}
|
||||
}
|
||||
|
||||
sections.sort_unstable_by_key(|s| s.base);
|
||||
|
||||
*guard = sections.into_boxed_slice();
|
||||
}
|
||||
impl PageInfo {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
refcount: AtomicUsize::new(0),
|
||||
cow_refcount: AtomicUsize::new(0),
|
||||
flags: FrameFlags::NONE,
|
||||
_padding: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn get_page(frame: Frame) -> Option<&'static PageInfo> {
|
||||
let sections = SECTIONS.read();
|
||||
|
||||
let idx = sections
|
||||
.binary_search_by_key(&frame, |section| section.base)
|
||||
.unwrap_or_else(|e| e);
|
||||
|
||||
let section = sections.get(idx)?;
|
||||
|
||||
section.frames.get(frame.offset_from(section.base))
|
||||
|
||||
/*
|
||||
sections
|
||||
.range(..=frame)
|
||||
.next_back()
|
||||
.filter(|(base, section)| frame <= base.next_by(section.frames.len()))
|
||||
.map(|(base, section)| PageInfoHandle { section, idx: frame.offset_from(*base) })
|
||||
*/
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user