This module enhances the efficiency of application memory usage through dynamic memory allocation, allowing resources to be allocated and deallocated at runtime. This optimizes memory utilization and reduces waste.
Furthermore, the module introduces a virtual-to-physical address mapping mechanism using page tables, providing a uniform virtual address space layout for user programs. This allows applications to access memory transparently, simplifying memory management complexity.
The page table mechanism also provides strong memory isolation between applications, and between applications and the kernel. The independence of virtual address spaces ensures that processes do not interfere with each other's memory, enhancing system stability and security against malicious access or programming errors.
For security, SCore uses a multi-page-table structure, as shown in the memory layout below. The kernel has its own page table, and each user process has its own, creating separate address spaces for the kernel and user applications.

The SCore microkernel supports virtual memory, which involves two main responsibilities: virtual memory management and physical memory management. While traditional microkernels often delegate memory management entirely to user space to minimize kernel code size, this approach can introduce overhead for allocation and mapping, and requires developers to be aware of the physical memory layout. SCore adopts a more developer-friendly design by retaining basic memory management functions in the kernel, such as virtual-to-physical page mapping and physical frame allocation.
SCore uses the SV39 paging mode. Virtual memory management is built upon four key data structures: the address space (MemorySet), the virtual memory area (MapArea), the page table (PageTable), and the page table entry (PageTableEntry). As illustrated below, an application's virtual address space is composed of several MapAreas, each of which consists of multiple virtual pages.
!MemorySet Structure
This structure manages a multi-level page table and its associated memory areas.
pub struct MemorySet {
/// The multi-level page table for this address space.
page_table: PageTable,
/// A vector of all memory areas in this address space.
areas: Vec<MapArea>,
}token(): Returns the physical address of the page table's root node, which serves as a unique identifier for the address space.new_kernel(): Creates the kernel's address space.from_elf(elf_data: &[u8]): Parses an ELF file to create a new user address space, mapping its segments.insert_frames_area(...): Inserts a newMapAreainto the address space, mapping it to physical frames.
A MapArea represents a contiguous segment of virtual memory. All virtual pages within this area are mapped in the same way (e.g., to physical frames or on-demand) and share the same access permissions (read, write, execute).
pub struct MapArea {
/// A continuous range of virtual page numbers.
vpn_range: VPNRange,
/// A map from virtual page numbers to the physical frames they are mapped to.
data_frames: BTreeMap<VirtPageNum, FrameTracker>,
/// The mapping type for all pages in this area.
map_type: MapType,
/// The access permissions for this area.
map_perm: MapPermission,
}map(page_table: &mut PageTable): Adds the mappings for this memory area to the given page table.unmap(page_table: &mut PageTable): Removes the mappings for this memory area from the given page table.
The PageTable struct holds the root physical page number (root_ppn) as its unique identifier. The frames vector contains FrameTrackers for all physical frames used by the page table's nodes. The lifetime of these trackers is bound to the PageTable, ensuring that when a PageTable is dropped, all associated physical frames are automatically deallocated.
pub struct PageTable {
/// The physical page number of the root node.
root_ppn: PhysPageNum,
/// The physical frames that hold the page table's nodes.
frames: Vec<FrameTracker>,
}find_pte_create(vpn: VirtPageNum): Traverses the multi-level page table to find thePageTableEntryfor a given virtual page number. If intermediate nodes do not exist, they are created on-the-fly.map(vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags): Inserts a mapping from a virtual page to a physical page with the specified flags.unmap(vpn: VirtPageNum): Removes a mapping for a given virtual page.
!Page Table Entry Format
A page table entry is represented by a 64-bit usize. As shown above, bits [53:10] hold the 44-bit physical page number (PPN), and the lower 8 bits [7:0] are flags.
#[derive(Copy, Clone)]
pub struct PageTableEntry {
pub bits: usize,
}Flag Bits [7:0]:
bitflags! {
pub struct PTEFlags: u8 {
const V = 1 << 0; // Valid
const R = 1 << 1; // Read
const W = 1 << 2; // Write
const X = 1 << 3; // Execute
const U = 1 << 4; // User
const G = 1 << 5; // Global
const A = 1 << 6; // Accessed
const D = 1 << 7; // Dirty
}
}ppn(): Returns the physical page number from the entry.flags(): Returns the flags from the entry.
SCore uses a stack-based allocator to manage physical memory frames.
This allocator manages a pool of available physical page frames. It maintains a range of unallocated frames (current to end) and a stack (recycled) of frames that have been used and returned.
pub struct StackFrameAllocator {
/// The start of the unallocated physical page number range.
current: usize,
/// The end of the unallocated physical page number range.
end: usize,
/// A LIFO stack of recycled physical page numbers.
recycled: Vec<usize>,
}frame_alloc(): Allocates a physical frame. It first attempts to pop a frame from therecycledstack. If the stack is empty, it allocates a new frame from the[current, end)range.frame_dealloc(ppn: PhysPageNum): Deallocates a physical frame by pushing its page number onto therecycledstack.