Skip to content

Commit ea36c5d

Browse files
committed
dev
1 parent 1173413 commit ea36c5d

File tree

4 files changed

+380
-81
lines changed

4 files changed

+380
-81
lines changed

Cargo.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,20 @@ numeric-enum-macro = "0.2"
1515

1616
axerrno = "0.1.0"
1717
page_table_entry = "0.5"
18+
page_table_multiarch = "0.5"
1819
memory_addr = "0.3.1"
1920
crate_interface = "0.1"
20-
21+
iced-x86 = { version = "1.12.0", features = [
22+
"decoder",
23+
"no_std",
24+
"intel",
25+
"op_code_info",
26+
"encoder",
27+
"masm"
28+
], default-features = false }
2129
axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" }
2230
axvcpu = { git = "https://github.com/arceos-hypervisor/axvcpu.git" }
31+
axvisor_api = { git = "https://github.com/arceos-hypervisor/axvisor_api.git" }
2332

2433
[features]
2534
default = ["vmx"]

src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub(crate) mod regs;
1515
mod ept;
1616
mod frame;
1717
mod instruction_emulator;
18+
mod page_table;
1819

1920
cfg_if::cfg_if! {
2021
if #[cfg(feature = "vmx")] {
@@ -27,6 +28,14 @@ cfg_if::cfg_if! {
2728
}
2829
}
2930

31+
use axaddrspace::GuestPhysAddr;
3032
pub use ept::GuestPageWalkInfo;
33+
use memory_addr::PhysAddr;
3134
pub use regs::GeneralRegisters;
3235
pub use vender::has_hardware_support;
36+
37+
/// Legacy function for backward compatibility
38+
/// Use GuestMemoryAccess for new code
39+
pub fn translate_to_phys(addr: GuestPhysAddr) -> Option<PhysAddr> {
40+
axvisor_api::guest_memory::translate_to_phys(axvisor_api::vmm::current_vm_id(), axvisor_api::vmm::current_vcpu_id(), addr)
41+
}

src/page_table.rs

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
//! Used to query and manipulate the page tables of a guest.
2+
use core::marker::PhantomData;
3+
4+
use memory_addr::MemoryAddr;
5+
use page_table_entry::{GenericPTE, MappingFlags};
6+
use page_table_multiarch::{PageSize, PagingError, PagingHandler, PagingResult};
7+
8+
use axaddrspace::{EPTTranslator, GuestPhysAddr, GuestVirtAddr};
9+
10+
const fn p5_index(vaddr: usize) -> usize {
11+
(vaddr >> (12 + 36)) & (ENTRY_COUNT - 1)
12+
}
13+
14+
const fn p4_index(vaddr: usize) -> usize {
15+
(vaddr >> (12 + 27)) & (ENTRY_COUNT - 1)
16+
}
17+
18+
const fn p3_index(vaddr: usize) -> usize {
19+
(vaddr >> (12 + 18)) & (ENTRY_COUNT - 1)
20+
}
21+
22+
const fn p2_index(vaddr: usize) -> usize {
23+
(vaddr >> (12 + 9)) & (ENTRY_COUNT - 1)
24+
}
25+
26+
const fn p1_index(vaddr: usize) -> usize {
27+
(vaddr >> 12) & (ENTRY_COUNT - 1)
28+
}
29+
30+
#[derive(Debug)]
31+
/// The information of guest page walk.
32+
pub struct GuestPageWalkInfo {
33+
/// Guest VM cr3 value.
34+
pub cr3: usize,
35+
/// Guest page table level.
36+
pub level: usize,
37+
/// Guest page table width
38+
pub width: u32,
39+
/// Guest page table user mode
40+
pub is_user_mode_access: bool,
41+
/// Guest page table write access
42+
pub is_write_access: bool,
43+
/// Guest page table instruction fetch
44+
pub is_inst_fetch: bool,
45+
/// CR4.PSE for 32bit paging, true for PAE/4-level paging
46+
pub pse: bool,
47+
/// CR0.WP
48+
pub wp: bool, // CR0.WP
49+
/// MSR_IA32_EFER_NXE_BIT
50+
pub nxe: bool,
51+
52+
/// Guest page table Supervisor mode access prevention
53+
pub is_smap_on: bool,
54+
/// Guest page table Supervisor mode execution protection
55+
pub is_smep_on: bool,
56+
}
57+
58+
// /// Metadata of guest page tables.
59+
// pub struct GuestPageTableMetadata;
60+
61+
// impl PagingMetaData for GuestPageTableMetadata<EPT> {
62+
// const LEVELS: usize = 4;
63+
// const PA_MAX_BITS: usize = 52;
64+
// const VA_MAX_BITS: usize = 48;
65+
66+
// type VirtAddr = GuestVirtAddr;
67+
// type PhysAddr = GuestPhysAddr;
68+
69+
// fn to_actual_paddr(paddr: Self::PhysAddr) -> HostPhysAddr {
70+
// EPT::guest_phys_to_host_phys(paddr).unwrap()
71+
// }
72+
73+
// fn flush_tlb(_vaddr: Option<GuestVirtAddr>) {
74+
// warn!("flush_tlb is not implemented for guest page tables");
75+
// }
76+
// }
77+
78+
const ENTRY_COUNT: usize = 512;
79+
80+
// pub type GuestPageTable<EPT: EPTTranslator,H> = PageTable64<GuestPageTableMetadata<EPT>, X64PTE, H>;
81+
82+
/// A generic page table struct for 64-bit platform.
83+
///
84+
/// It also tracks all intermediate level tables. They will be deallocated
85+
/// When the [`GuestPageTable64`] itself is dropped.
86+
pub struct GuestPageTable64<PTE: GenericPTE, H: PagingHandler, EPT: EPTTranslator> {
87+
root_paddr: GuestPhysAddr,
88+
levels: usize,
89+
_phantom: PhantomData<(PTE, H, EPT)>,
90+
}
91+
92+
impl<PTE: GenericPTE, H: PagingHandler, EPT: EPTTranslator> GuestPageTable64<PTE, H, EPT> {
93+
/// Create a new page table.
94+
pub fn construct(guest_ptw_info: &GuestPageWalkInfo) -> Self {
95+
const PHYS_ADDR_MASK: usize = 0x000f_ffff_ffff_f000; // bits 12..52
96+
97+
Self {
98+
root_paddr: GuestPhysAddr::from(guest_ptw_info.cr3 & &PHYS_ADDR_MASK),
99+
levels: guest_ptw_info.level,
100+
_phantom: PhantomData,
101+
}
102+
}
103+
104+
/// Get the root page table physical address.
105+
pub fn root_paddr(&self) -> GuestPhysAddr {
106+
self.root_paddr
107+
}
108+
109+
/// Queries the result of the mapping starts with `vaddr`.
110+
///
111+
/// Returns the physical address of the target frame, mapping flags, and
112+
/// the page size.
113+
///
114+
/// Returns [`Err(PagingError::NotMapped)`](PagingError::NotMapped) if the
115+
/// mapping is not present.
116+
pub fn query(
117+
&self,
118+
vaddr: GuestVirtAddr,
119+
) -> PagingResult<(GuestPhysAddr, MappingFlags, PageSize)> {
120+
let (entry, size) = self.get_entry(vaddr)?;
121+
if entry.is_unused() {
122+
error!("GuestPT64 query {:?} Entry is unused", vaddr);
123+
return Err(PagingError::NotMapped);
124+
}
125+
let off = size.align_offset(vaddr.into());
126+
Ok((
127+
entry.paddr().add(off).as_usize().into(),
128+
entry.flags(),
129+
size,
130+
))
131+
}
132+
}
133+
134+
// private implements
135+
impl<PTE: GenericPTE, H: PagingHandler, EPT: EPTTranslator> GuestPageTable64<PTE, H, EPT> {
136+
fn table_of<'a>(&self, gpa: GuestPhysAddr) -> PagingResult<&'a [PTE]> {
137+
let hpa = EPT::guest_phys_to_host_phys(gpa)
138+
.map(|(hpa, _flags, _pgsize)| hpa)
139+
.ok_or_else(|| {
140+
warn!("Failed to translate GPA {:?}", gpa);
141+
PagingError::NotMapped
142+
})?;
143+
let ptr = H::phys_to_virt(hpa).as_ptr() as _;
144+
145+
Ok(unsafe { core::slice::from_raw_parts(ptr, ENTRY_COUNT) })
146+
}
147+
148+
fn next_table<'a>(&self, entry: &PTE) -> PagingResult<&'a [PTE]> {
149+
if !entry.is_present() {
150+
error!("GuestPT64 next_table {:?} Entry is not present", entry);
151+
Err(PagingError::NotMapped)
152+
} else if entry.is_huge() {
153+
error!("GuestPT64 next_table {:?} Entry is huge", entry);
154+
Err(PagingError::MappedToHugePage)
155+
} else {
156+
self.table_of(entry.paddr().as_usize().into())
157+
}
158+
}
159+
160+
fn get_entry(&self, gva: GuestVirtAddr) -> PagingResult<(&PTE, PageSize)> {
161+
let vaddr: usize = gva.into();
162+
163+
let p3 = if self.levels == 3 {
164+
self.table_of(self.root_paddr())?
165+
} else if self.levels == 4 {
166+
let p4 = self.table_of(self.root_paddr())?;
167+
let p4e = &p4[p4_index(vaddr)];
168+
self.next_table(p4e)?
169+
} else {
170+
// 5-level paging
171+
let p5 = self.table_of(self.root_paddr())?;
172+
let p5e = &p5[p5_index(vaddr)];
173+
if p5e.is_huge() {
174+
return Err(PagingError::MappedToHugePage);
175+
}
176+
let p4 = self.next_table(p5e)?;
177+
let p4e = &p4[p4_index(vaddr)];
178+
179+
if p4e.is_huge() {
180+
return Err(PagingError::MappedToHugePage);
181+
}
182+
183+
self.next_table(p4e)?
184+
};
185+
186+
let p3e = &p3[p3_index(vaddr)];
187+
if p3e.is_huge() {
188+
return Ok((p3e, PageSize::Size1G));
189+
}
190+
191+
let p2 = self.next_table(p3e)?;
192+
let p2e = &p2[p2_index(vaddr)];
193+
if p2e.is_huge() {
194+
return Ok((p2e, PageSize::Size2M));
195+
}
196+
197+
let p1 = self.next_table(p2e)?;
198+
let p1e = &p1[p1_index(vaddr)];
199+
Ok((p1e, PageSize::Size4K))
200+
}
201+
}

0 commit comments

Comments
 (0)