On Wed Apr 1, 2026 at 6:20 AM JST, Joel Fernandes wrote: > Add unified Pte, Pde, and DualPde wrapper enums that abstract over > MMU v2 and v3 page table entry formats. These enums allow the page > table walker and VMM to work with both MMU versions. > > Each unified type: > - Takes MmuVersion parameter in constructors > - Wraps both ver2 and ver3 variants > - Delegates method calls to the appropriate variant > > This enables version-agnostic page table operations while keeping > version-specific implementation details encapsulated in the ver2 > and ver3 modules. > > Cc: Nikola Djukic <[email protected]> > Signed-off-by: Joel Fernandes <[email protected]> > --- > drivers/gpu/nova-core/mm/pagetable.rs | 330 ++++++++++++++++++++++++++ > 1 file changed, 330 insertions(+) > > diff --git a/drivers/gpu/nova-core/mm/pagetable.rs > b/drivers/gpu/nova-core/mm/pagetable.rs > index 6e01a1af5222..909df37c3ee8 100644 > --- a/drivers/gpu/nova-core/mm/pagetable.rs > +++ b/drivers/gpu/nova-core/mm/pagetable.rs > @@ -12,6 +12,13 @@ > pub(crate) mod ver3; > > use crate::gpu::Architecture; > +use crate::mm::{ > + pramin, > + Pfn, > + VirtualAddress, > + VramAddress, // > +}; > +use kernel::prelude::*; > > /// Extracts the page table index at a given level from a virtual address. > pub(crate) trait VaLevelIndex { > @@ -84,6 +91,96 @@ pub(crate) const fn as_index(&self) -> u64 { > } > } > > +impl MmuVersion { > + /// Get the `PDE` levels (excluding PTE level) for page table walking. > + pub(crate) fn pde_levels(&self) -> &'static [PageTableLevel] { > + match self { > + Self::V2 => ver2::PDE_LEVELS, > + Self::V3 => ver3::PDE_LEVELS, > + } > + } > + > + /// Get the PTE level for this MMU version. > + pub(crate) fn pte_level(&self) -> PageTableLevel { > + match self { > + Self::V2 => ver2::PTE_LEVEL, > + Self::V3 => ver3::PTE_LEVEL, > + } > + } > + > + /// Get the dual PDE level (128-bit entries) for this MMU version. > + pub(crate) fn dual_pde_level(&self) -> PageTableLevel { > + match self { > + Self::V2 => ver2::DUAL_PDE_LEVEL, > + Self::V3 => ver3::DUAL_PDE_LEVEL, > + } > + } > + > + /// Get the number of PDE levels for this MMU version. > + pub(crate) fn pde_level_count(&self) -> usize { > + self.pde_levels().len() > + } > + > + /// Get the entry size in bytes for a given level. > + pub(crate) fn entry_size(&self, level: PageTableLevel) -> usize { > + if level == self.dual_pde_level() { > + 16 // 128-bit dual PDE > + } else { > + 8 // 64-bit PDE/PTE > + } > + } > + > + /// Get the number of entries per page table page for a given level. > + pub(crate) fn entries_per_page(&self, level: PageTableLevel) -> usize { > + match self { > + Self::V2 => match level { > + // TODO: Calculate these values from the bitfield dynamically > + // instead of hardcoding them. > + PageTableLevel::Pdb => 4, // PD3 root: bits [48:47] = 2 bits > + PageTableLevel::L3 => 256, // PD0 dual: bits [28:21] = 8 bits > + _ => 512, // PD2, PD1, PT: 9 bits each > + }, > + Self::V3 => match level { > + PageTableLevel::Pdb => 2, // PDE4 root: bit [56] = 1 bit, 2 > entries > + PageTableLevel::L4 => 256, // PDE0 dual: bits [28:21] = 8 > bits > + _ => 512, // PDE3, PDE2, PDE1, PT: 9 bits > each > + }, > + } > + } > + > + /// Extract the page table index at `level` from `va` for this MMU > version. > + pub(crate) fn level_index(&self, va: VirtualAddress, level: u64) -> u64 { > + match self { > + Self::V2 => ver2::VirtualAddressV2::new(va).level_index(level), > + Self::V3 => ver3::VirtualAddressV3::new(va).level_index(level), > + } > + } > + > + /// Compute upper bound on page table pages needed for `num_virt_pages`. > + /// > + /// Walks from PTE level up through PDE levels, accumulating the tree. > + pub(crate) fn pt_pages_upper_bound(&self, num_virt_pages: usize) -> > usize { > + let mut total = 0; > + > + // PTE pages at the leaf level. > + let pte_epp = self.entries_per_page(self.pte_level()); > + let mut pages_at_level = num_virt_pages.div_ceil(pte_epp); > + total += pages_at_level; > + > + // Walk PDE levels bottom-up (reverse of pde_levels()). > + for &level in self.pde_levels().iter().rev() { > + let epp = self.entries_per_page(level); > + > + // How many pages at this level do we need to point to > + // the previous pages_at_level? > + pages_at_level = pages_at_level.div_ceil(epp); > + total += pages_at_level; > + } > + > + total > + } > +} > +
We have a lot of matches on the MMU version here (and below in Pte, Pde, DualPde). What about making MmuVersion into a trait (e.g. Mmu) with associated types for Pte, Pde, DualPde which can implement traits defining their common operations too? Then you can parameterise Vmm/PtWalk on this type.
