use {VirtualAddress, PhysicalAddress};
pub const BASE_PAGE_SIZE: u64 = 4096; pub const LARGE_PAGE_SIZE: u64 = 1024 * 1024 * 2; pub const HUGE_PAGE_SIZE: u64 = 1024 * 1024 * 1024; pub const CACHE_LINE_SIZE: usize = 64;
pub const MAXPHYADDR: u64 = 52;
const ADDRESS_MASK: u64 = ((1 << MAXPHYADDR) - 1) & !0xfff;
pub type PML4 = [PML4Entry; 512];
pub type PDPT = [PDPTEntry; 512];
pub type PD = [PDEntry; 512];
pub type PT = [PTEntry; 512];
pub fn pml4_index(addr: VirtualAddress) -> usize {
(addr.as_usize() >> 39) & 0b111111111
}
#[inline]
pub fn pdpt_index(addr: VirtualAddress) -> usize {
(addr.as_usize() >> 30) & 0b111111111
}
#[inline]
pub fn pd_index(addr: VirtualAddress) -> usize {
(addr.as_usize() >> 21) & 0b111111111
}
#[inline]
pub fn pt_index(addr: VirtualAddress) -> usize {
(addr.as_usize() >> 12) & 0b111111111
}
bitflags! {
pub flags PML4Entry: u64 {
const PML4_P = bit!(0),
const PML4_RW = bit!(1),
const PML4_US = bit!(2),
const PML4_PWT = bit!(3),
const PML4_PCD = bit!(4),
const PML4_A = bit!(5),
const PML4_XD = bit!(63),
}
}
impl PML4Entry {
pub fn new(pdpt: PhysicalAddress, flags: PML4Entry) -> PML4Entry {
let pdpt_val = pdpt.as_u64();
assert!(pdpt_val % BASE_PAGE_SIZE == 0);
PML4Entry { bits: pdpt_val | flags.bits }
}
pub fn get_address(self) -> PhysicalAddress {
PhysicalAddress::from(self.bits & ADDRESS_MASK)
}
check_flag!(doc = "Is page present?", is_present, PML4_P);
check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 512-GByte region, controlled by this entry (see Section 4.6)",
is_writeable, PML4_RW);
check_flag!(doc = "User/supervisor; if 0, user-mode accesses are not allowed to the 512-GByte region controlled by this entry.",
is_user_mode_allowed, PML4_US);
check_flag!(doc = "Page-level write-through; indirectly determines the memory type used to access the page-directory-pointer table referenced by this entry.",
is_page_write_through, PML4_PWT);
check_flag!(doc = "Page-level cache disable; indirectly determines the memory type used to access the page-directory-pointer table referenced by this entry.",
is_page_level_cache_disabled, PML4_PCD);
check_flag!(doc = "Accessed; indicates whether this entry has been used for linear-address translation.",
is_accessed, PML4_A);
check_flag!(doc = "If IA32_EFER.NXE = 1, execute-disable. If 1, instruction fetches are not allowed from the 512-GByte region.",
is_instruction_fetching_disabled, PML4_XD);
}
bitflags! {
pub flags PDPTEntry: u64 {
const PDPT_P = bit!(0),
const PDPT_RW = bit!(1),
const PDPT_US = bit!(2),
const PDPT_PWT = bit!(3),
const PDPT_PCD = bit!(4),
const PDPT_A = bit!(5),
const PDPT_D = bit!(6),
const PDPT_PS = bit!(7),
const PDPT_G = bit!(8),
const PDPT_PAT = bit!(12),
const PDPT_XD = bit!(63),
}
}
impl PDPTEntry {
pub fn new(pd: PhysicalAddress, flags: PDPTEntry) -> PDPTEntry {
let pd_val = pd.as_u64();
assert!(pd_val % BASE_PAGE_SIZE == 0);
PDPTEntry { bits: pd_val | flags.bits }
}
pub fn get_address(self) -> PhysicalAddress {
PhysicalAddress::from(self.bits & ADDRESS_MASK)
}
check_flag!(doc = "Is page present?", is_present, PDPT_P);
check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 1-GByte region controlled by this entry.",
is_writeable, PDPT_RW);
check_flag!(doc = "User/supervisor; user-mode accesses are not allowed to the 1-GByte region controlled by this entry.",
is_user_mode_allowed, PDPT_US);
check_flag!(doc = "Page-level write-through.",
is_page_write_through, PDPT_PWT);
check_flag!(doc = "Page-level cache disable.",
is_page_level_cache_disabled, PDPT_PCD);
check_flag!(doc = "Accessed; indicates whether this entry has been used for linear-address translation.",
is_accessed, PDPT_A);
check_flag!(doc = "Indirectly determines the memory type used to access the 1-GByte page referenced by this entry. if not PDPT_PS this is ignored.",
is_pat, PDPT_PAT);
check_flag!(doc = "If IA32_EFER.NXE = 1, execute-disable. If 1, instruction fetches are not allowed from the 512-GByte region.",
is_instruction_fetching_disabled, PDPT_XD);
}
bitflags! {
pub flags PDEntry: u64 {
const PD_P = bit!(0),
const PD_RW = bit!(1),
const PD_US = bit!(2),
const PD_PWT = bit!(3),
const PD_PCD = bit!(4),
const PD_A = bit!(5),
const PD_D = bit!(6),
const PD_PS = bit!(7),
const PD_G = bit!(8),
const PD_PAT = bit!(12),
const PD_XD = bit!(63),
}
}
impl PDEntry {
pub fn new(pt: PhysicalAddress, flags: PDEntry) -> PDEntry {
let pt_val = pt.as_u64();
assert!(pt_val % BASE_PAGE_SIZE == 0);
PDEntry { bits: pt_val | flags.bits }
}
pub fn get_address(self) -> PhysicalAddress {
PhysicalAddress::from(self.bits & ADDRESS_MASK)
}
check_flag!(doc = "Present; must be 1 to map a 2-MByte page or reference a page table.",
is_present, PD_P);
check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 2-MByte region controlled by this entry",
is_writeable, PD_RW);
check_flag!(doc = "User/supervisor; user-mode accesses are not allowed to the 2-MByte region controlled by this entry.",
is_user_mode_allowed, PD_US);
check_flag!(doc = "Page-level write-through.",
is_page_write_through, PD_PWT);
check_flag!(doc = "Page-level cache disable.",
is_page_level_cache_disabled, PD_PCD);
check_flag!(doc = "Accessed; if PD_PS set indicates whether software has accessed the 2-MByte page else indicates whether this entry has been used for linear-address translation.",
is_accessed, PD_A);
check_flag!(doc = "Dirty; if PD_PS set indicates whether software has written to the 2-MByte page referenced by this entry else ignored.",
is_dirty, PD_D);
check_flag!(doc = "Page size; if set this entry maps a 2-MByte page; otherwise, this entry references a page directory.",
is_page, PD_PS);
check_flag!(doc = "Global; if PD_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise if not PD_PS this is ignored.",
is_global, PD_G);
check_flag!(doc = "Indirectly determines the memory type used to access the 2-MByte page referenced by this entry. if not PD_PS this is ignored.",
is_pat, PD_PAT);
check_flag!(doc = "If IA32_EFER.NXE = 1, execute-disable. If 1, instruction fetches are not allowed from the 2-Mbyte region.",
is_instruction_fetching_disabled, PD_XD);
}
bitflags! {
pub flags PTEntry: u64 {
const PT_P = bit!(0),
const PT_RW = bit!(1),
const PT_US = bit!(2),
const PT_PWT = bit!(3),
const PT_PCD = bit!(4),
const PT_A = bit!(5),
const PT_D = bit!(6),
const PT_G = bit!(8),
const PT_XD = bit!(63),
}
}
impl PTEntry {
pub fn new(page: PhysicalAddress, flags: PTEntry) -> PTEntry {
let page_val = page.as_u64();
assert!(page_val % BASE_PAGE_SIZE == 0);
PTEntry { bits: page_val | flags.bits }
}
pub fn get_address(self) -> PhysicalAddress {
PhysicalAddress::from(self.bits & ADDRESS_MASK)
}
check_flag!(doc = "Present; must be 1 to map a 4-KByte page or reference a page table.",
is_present, PT_P);
check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 4-KByte region controlled by this entry",
is_writeable, PT_RW);
check_flag!(doc = "User/supervisor; user-mode accesses are not allowed to the 4-KByte region controlled by this entry.",
is_user_mode_allowed, PT_US);
check_flag!(doc = "Page-level write-through.",
is_page_write_through, PT_PWT);
check_flag!(doc = "Page-level cache disable.",
is_page_level_cache_disabled, PT_PCD);
check_flag!(doc = "Accessed; if PT_PS set indicates whether software has accessed the 4-KByte page else indicates whether this entry has been used for linear-address translation.",
is_accessed, PT_A);
check_flag!(doc = "Dirty; if PD_PS set indicates whether software has written to the 4-KByte page referenced by this entry else ignored.",
is_dirty, PT_D);
check_flag!(doc = "Global; if PT_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise if not PT_PS this is ignored.",
is_global, PT_G);
check_flag!(doc = "If IA32_EFER.NXE = 1, execute-disable. If 1, instruction fetches are not allowed from the 4-KByte region.",
is_instruction_fetching_disabled, PT_XD);
}