use crate::VirtAddr;
#[inline]
pub fn flush(addr: VirtAddr) {
#[cfg(feature = "inline_asm")]
unsafe {
asm!("invlpg [{}]", in(reg) addr.as_u64(), options(nostack))
};
#[cfg(not(feature = "inline_asm"))]
unsafe {
crate::asm::x86_64_asm_invlpg(addr.as_u64())
};
}
#[inline]
pub fn flush_all() {
use crate::registers::control::Cr3;
let (frame, flags) = Cr3::read();
unsafe { Cr3::write(frame, flags) }
}
#[derive(Debug)]
pub enum InvPicdCommand {
Address(VirtAddr, Pcid),
Single(Pcid),
All,
AllExceptGlobal,
}
#[repr(C)]
#[derive(Debug)]
struct InvpcidDescriptor {
address: u64,
pcid: u64,
}
#[repr(transparent)]
#[derive(Debug)]
pub struct Pcid(u16);
impl Pcid {
pub const fn new(pcid: u16) -> Result<Pcid, &'static str> {
if pcid >= 4096 {
Err("PCID should be < 4096.")
} else {
Ok(Pcid(pcid))
}
}
pub const fn value(&self) -> u16 {
self.0
}
}
#[inline]
pub unsafe fn flush_pcid(command: InvPicdCommand) {
let mut desc = InvpcidDescriptor {
address: 0,
pcid: 0,
};
let kind: u64;
match command {
InvPicdCommand::Address(addr, pcid) => {
kind = 0;
desc.pcid = pcid.value().into();
desc.address = addr.as_u64()
}
InvPicdCommand::Single(pcid) => {
kind = 1;
desc.pcid = pcid.0.into()
}
InvPicdCommand::All => kind = 2,
InvPicdCommand::AllExceptGlobal => kind = 3,
}
#[cfg(feature = "inline_asm")]
{
let desc_value = &desc as *const InvpcidDescriptor as u64;
asm!("invpcid {1}, [{0}]", in(reg) desc_value, in(reg) kind);
};
#[cfg(not(feature = "inline_asm"))]
{
crate::asm::x86_64_asm_invpcid(kind, &desc as *const InvpcidDescriptor as u64)
};
}