1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-21 23:56:18 +04:00

Added virtual memory support for aarch64 and x86_64.

1. Memory mapping at KSEG2_START(0xffff_fe80_0000_0000) will now be visible to all processes.
   This feature is required by Loadable Kernel Module when mapping kernel module into memory.
2. Wrapping PageTableImpl::active() into ManuallyDrop, so that no extra "mem::forget" is required.
3. Added PageTableImpl::kernel_table(). This function is the same as active() on x86_64, but not the same on aarch64.
This commit is contained in:
gjz010 2019-06-07 15:57:18 +08:00
parent 8e5e798d78
commit da028c1f10
7 changed files with 51 additions and 10 deletions

3
.gitignore vendored
View File

@ -20,3 +20,6 @@ Cargo.lock
# for vim
*.swp
# for idea
.idea

View File

@ -5,3 +5,4 @@ pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024;
pub const USER_STACK_OFFSET: usize = 0x0000_8000_0000_0000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 1 * 1024 * 1024;
pub const KSEG2_START: usize = 0xffff_fe80_0000_0000;

View File

@ -10,6 +10,7 @@ use aarch64::paging::{
FrameAllocator, FrameDeallocator, Page as PageAllSizes, Size4KiB,
};
use aarch64::{PhysAddr, VirtAddr};
use core::mem::ManuallyDrop;
use log::*;
use rcore_memory::paging::*;
@ -205,15 +206,26 @@ impl PageEntry {
impl PageTableImpl {
/// Unsafely get the current active page table.
/// WARN: You MUST call `core::mem::forget` for it after use!
pub unsafe fn active() -> Self {
/// Using ManuallyDrop to wrap the page table: this is how `core::mem::forget` is implemented now.
pub unsafe fn active() -> ManuallyDrop<Self> {
let frame = Frame::of_addr(PageTableImpl::active_token() as u64);
let table = &mut *frame_to_page_table(frame);
PageTableImpl {
ManuallyDrop::new(PageTableImpl {
page_table: MappedPageTable::new(table, frame_to_page_table),
root_frame: frame,
entry: core::mem::MaybeUninit::uninitialized().into_initialized(),
}
})
}
/// The method for getting the kernel page table.
/// In aarch64 case kernel page table and user page table are two different tables.
pub unsafe fn kernel_table() -> ManuallyDrop<Self> {
let frame = Frame::of_addr(ttbr_el1_read(1).start_address().as_u64());
let table = &mut *frame_to_page_table(frame);
ManuallyDrop::new(PageTableImpl {
page_table: MappedPageTable::new(table, frame_to_page_table),
root_frame: frame,
entry: core::mem::MaybeUninit::uninitialized().into_initialized(),
})
}
}

View File

@ -5,3 +5,4 @@ pub const PHYSICAL_MEMORY_OFFSET: usize = 0xfffffc00_00000000;
pub const USER_STACK_OFFSET: usize = 0x00008000_00000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 8 * 1024 * 1024; // 8 MB, the default config of Linux
pub const KSEG2_START: usize = 0xffff_fe80_0000_0000;

View File

@ -1,8 +1,8 @@
use super::paging::PageTableImpl;
use super::{BootInfo, MemoryRegionType};
use crate::memory::{init_heap, FRAME_ALLOCATOR};
use bitmap_allocator::BitAlloc;
use rcore_memory::paging::*;
pub fn init(boot_info: &BootInfo) {
init_frame_allocator(boot_info);
init_heap();
@ -20,3 +20,17 @@ fn init_frame_allocator(boot_info: &BootInfo) {
}
}
}
/// The method for initializing kernel virtual memory space, a memory space of 512 GiB.
/// The memory space is resided at the 509th item of the first-level page table.
/// After the initialization, mapping on this space will be "broadcast" to all page tables.
pub fn init_kernel_kseg2_map() {
let mut page_table = unsafe { PageTableImpl::kernel_table() };
// Dirty hack here:
// We do not really need the mapping. Indeed, we only need the second-level page table.
// Second-level page table item can then be copied to all page tables safely.
// This hack requires the page table not to recycle the second level page table on unmap.
page_table.map(0xfffffe8000000000, 0x0).update();
page_table.unmap(0xfffffe8000000000);
}

View File

@ -52,6 +52,8 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! {
// Init GDT
gdt::init();
// Init virtual space
memory::init_kernel_kseg2_map();
//get local apic id of cpu
cpu::init();
// Use IOAPIC instead of PIC, use APIC Timer instead of PIT, init serial&keyboard in x86_64

View File

@ -1,4 +1,5 @@
use crate::memory::{alloc_frame, dealloc_frame, phys_to_virt};
use core::mem::ManuallyDrop;
use core::sync::atomic::Ordering;
use log::*;
use rcore_memory::paging::*;
@ -196,15 +197,20 @@ impl PageEntry {
impl PageTableImpl {
/// Unsafely get the current active page table.
/// WARN: You MUST call `core::mem::forget` for it after use!
pub unsafe fn active() -> Self {
/// Using ManuallyDrop to wrap the page table: this is how `core::mem::forget` is implemented now.
pub unsafe fn active() -> ManuallyDrop<Self> {
let frame = Cr3::read().0;
let table = &mut *frame_to_page_table(frame);
PageTableImpl(
ManuallyDrop::new(PageTableImpl(
MappedPageTable::new(table, frame_to_page_table),
core::mem::MaybeUninit::uninitialized().into_initialized(),
frame,
)
))
}
/// The method for getting the kernel page table.
/// In x86_64 case kernel page table and user page table are the same table. However you have to do the initialization.
pub unsafe fn kernel_table() -> ManuallyDrop<Self> {
Self::active()
}
}
@ -227,14 +233,16 @@ impl PageTableExt for PageTableImpl {
let table = unsafe { &mut *frame_to_page_table(Cr3::read().0) };
// Kernel at 0xffff_ff00_0000_0000
// Kernel stack at 0x0000_57ac_0000_0000 (defined in bootloader crate)
// Kseg2 at 0xffff_fe80_0000_0000
let ekernel = table[510].clone();
let ephysical = table[0x1f8].clone();
let estack = table[175].clone();
let ekseg2 = table[509].clone();
let table = unsafe { &mut *frame_to_page_table(self.2) };
table[510].set_addr(ekernel.addr(), ekernel.flags() | EF::GLOBAL);
table[0x1f8].set_addr(ephysical.addr(), ephysical.flags() | EF::GLOBAL);
table[175].set_addr(estack.addr(), estack.flags() | EF::GLOBAL);
table[509].set_addr(ekseg2.addr(), ekseg2.flags() | EF::GLOBAL);
}
fn token(&self) -> usize {