#![allow(dead_code)]
use alloc::vec::Vec;
use core::ops::Range;
use align_ext::AlignExt;
use log::info;
use spin::Once;
use super::{
nr_subpage_per_huge,
page::{
meta::{mapping, KernelMeta, MetaPageMeta},
Page,
},
page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags},
page_table::{KernelMode, PageTable},
Paddr, PagingConstsTrait, Vaddr, PAGE_SIZE,
};
use crate::{
arch::mm::{PageTableEntry, PagingConsts},
boot::memory_region::MemoryRegionType,
};
const ADDR_WIDTH_SHIFT: isize = PagingConsts::ADDRESS_WIDTH as isize - 48;
pub const KERNEL_BASE_VADDR: Vaddr = 0xffff_8000_0000_0000 << ADDR_WIDTH_SHIFT;
pub const KERNEL_END_VADDR: Vaddr = 0xffff_ffff_ffff_0000 << ADDR_WIDTH_SHIFT;
pub fn kernel_loaded_offset() -> usize {
KERNEL_CODE_BASE_VADDR
}
#[cfg(target_arch = "x86_64")]
const KERNEL_CODE_BASE_VADDR: usize = 0xffff_ffff_8000_0000 << ADDR_WIDTH_SHIFT;
#[cfg(target_arch = "riscv64")]
const KERNEL_CODE_BASE_VADDR: usize = 0xffff_ffff_0000_0000 << ADDR_WIDTH_SHIFT;
const FRAME_METADATA_CAP_VADDR: Vaddr = 0xffff_ff00_0000_0000 << ADDR_WIDTH_SHIFT;
const FRAME_METADATA_BASE_VADDR: Vaddr = 0xffff_fe00_0000_0000 << ADDR_WIDTH_SHIFT;
pub(in crate::mm) const FRAME_METADATA_RANGE: Range<Vaddr> =
FRAME_METADATA_BASE_VADDR..FRAME_METADATA_CAP_VADDR;
const VMALLOC_BASE_VADDR: Vaddr = 0xffff_fd00_0000_0000 << ADDR_WIDTH_SHIFT;
pub const VMALLOC_VADDR_RANGE: Range<Vaddr> = VMALLOC_BASE_VADDR..FRAME_METADATA_BASE_VADDR;
pub const LINEAR_MAPPING_BASE_VADDR: Vaddr = 0xffff_8000_0000_0000 << ADDR_WIDTH_SHIFT;
pub const LINEAR_MAPPING_VADDR_RANGE: Range<Vaddr> = LINEAR_MAPPING_BASE_VADDR..VMALLOC_BASE_VADDR;
pub fn paddr_to_vaddr(pa: Paddr) -> usize {
debug_assert!(pa < VMALLOC_BASE_VADDR - LINEAR_MAPPING_BASE_VADDR);
pa + LINEAR_MAPPING_BASE_VADDR
}
pub(crate) fn should_map_as_tracked(addr: Vaddr) -> bool {
!LINEAR_MAPPING_VADDR_RANGE.contains(&addr)
}
pub static KERNEL_PAGE_TABLE: Once<PageTable<KernelMode, PageTableEntry, PagingConsts>> =
Once::new();
pub fn init_kernel_page_table(meta_pages: Vec<Page<MetaPageMeta>>) {
info!("Initializing the kernel page table");
let regions = crate::boot::memory_regions();
let phys_mem_cap = regions.iter().map(|r| r.base() + r.len()).max().unwrap();
let kpt = PageTable::<KernelMode>::empty();
{
let pte_index_max = nr_subpage_per_huge::<PagingConsts>();
kpt.make_shared_tables(pte_index_max / 2..pte_index_max);
}
{
let from = LINEAR_MAPPING_BASE_VADDR..LINEAR_MAPPING_BASE_VADDR + phys_mem_cap;
let to = 0..phys_mem_cap;
let prop = PageProperty {
flags: PageFlags::RW,
cache: CachePolicy::Writeback,
priv_flags: PrivilegedPageFlags::GLOBAL,
};
unsafe {
kpt.map(&from, &to, prop).unwrap();
}
}
{
let start_va = mapping::page_to_meta::<PagingConsts>(0);
let from = start_va..start_va + meta_pages.len() * PAGE_SIZE;
let prop = PageProperty {
flags: PageFlags::RW,
cache: CachePolicy::Writeback,
priv_flags: PrivilegedPageFlags::GLOBAL,
};
let mut cursor = kpt.cursor_mut(&from).unwrap();
for meta_page in meta_pages {
unsafe {
let _old = cursor.map(meta_page.into(), prop);
}
}
}
{
let to = 0x8_0000_0000..0x9_0000_0000;
let from = LINEAR_MAPPING_BASE_VADDR + to.start..LINEAR_MAPPING_BASE_VADDR + to.end;
let prop = PageProperty {
flags: PageFlags::RW,
cache: CachePolicy::Uncacheable,
priv_flags: PrivilegedPageFlags::GLOBAL,
};
unsafe {
kpt.map(&from, &to, prop).unwrap();
}
}
{
let region = regions
.iter()
.find(|r| r.typ() == MemoryRegionType::Kernel)
.unwrap();
let offset = kernel_loaded_offset();
let to =
region.base().align_down(PAGE_SIZE)..(region.base() + region.len()).align_up(PAGE_SIZE);
let from = to.start + offset..to.end + offset;
let prop = PageProperty {
flags: PageFlags::RWX,
cache: CachePolicy::Writeback,
priv_flags: PrivilegedPageFlags::GLOBAL,
};
let mut cursor = kpt.cursor_mut(&from).unwrap();
for frame_paddr in to.step_by(PAGE_SIZE) {
let page = Page::<KernelMeta>::from_unused(frame_paddr, KernelMeta::default());
unsafe {
let _old = cursor.map(page.into(), prop);
}
}
}
KERNEL_PAGE_TABLE.call_once(|| kpt);
}
pub unsafe fn activate_kernel_page_table() {
let kpt = KERNEL_PAGE_TABLE
.get()
.expect("The kernel page table is not initialized yet");
unsafe {
kpt.first_activate_unchecked();
crate::arch::mm::tlb_flush_all_including_global();
}
unsafe {
crate::mm::page_table::boot_pt::dismiss();
}
}