@@ -23,8 +23,8 @@ limitations under the License.
2323
2424use crate :: vmem:: {
2525 BasicMapping , CowMapping , MapRequest , MapResponse , Mapping , MappingKind , SpaceAwareMapping ,
26- SpaceId , SpaceReferenceMapping , TableMovabilityBase , TableOps , TableReadOps , UpdateParent ,
27- UpdateParentNone , modify_ptes, write_entry_updating,
26+ SpaceId , TableMovabilityBase , TableOps , TableReadOps , UpdateParent , UpdateParentNone ,
27+ modify_ptes, write_entry_updating,
2828} ;
2929
3030pub const PAGE_SIZE : usize = 4096 ;
@@ -44,6 +44,40 @@ const PAGE_AVL_COW: u64 = 1 << 9;
4444
4545const VA_BITS : usize = 32 ;
4646
47+ /// The level of the page-table hierarchy at which sharing occurs.
48+ ///
49+ /// On i686 the only shareable level is the leaf page table: the table a PDE points at.
50+ #[ derive( Debug , Clone , Copy ) ]
51+ pub enum SharedTableLevel {
52+ /// A leaf page table
53+ Pt ,
54+ }
55+
56+ /// A reference from one address space to an intermediate page table
57+ /// that lives in a different space. Produced by [`walk_va_spaces`]
58+ /// when the walker encounters an intermediate table whose physical
59+ /// address was already seen via an earlier root.
60+ ///
61+ /// On i686 the only shareable level is [`SharedTableLevel::Pt`] (one
62+ /// level below the root PD).
63+ ///
64+ /// `our_va` and `their_va` may be any virtual address inside the
65+ /// aliased region but callers must not assume they are region-aligned.
66+ #[ derive( Debug , Clone , Copy ) ]
67+ pub struct SpaceReferenceMapping {
68+ /// The level at which the alias starts.
69+ pub level : SharedTableLevel ,
70+ /// The "owning" space is the first root that visited this
71+ /// intermediate PA during [`walk_va_spaces`].
72+ pub space : SpaceId ,
73+ /// Any VA inside the aliased sub-tree in OUR space.
74+ pub our_va : u64 ,
75+ /// Any VA inside the aliased sub-tree in the owning space.
76+ /// Usually equal to `our_va` (kernel mappings at the same VA
77+ /// across processes) but the design permits different VAs.
78+ pub their_va : u64 ,
79+ }
80+
4781pub trait TableMovability < Op : TableReadOps + ?Sized , TableMoveInfo > {
4882 type RootUpdateParent : UpdateParent < Op , TableMoveInfo = TableMoveInfo > ;
4983 fn root_update_parent ( ) -> Self :: RootUpdateParent ;
@@ -213,17 +247,16 @@ pub unsafe fn map<Op: TableOps>(op: &Op, mapping: Mapping) {
213247// Multi-space walk / link (shared intermediate tables)
214248//==================================================================================================
215249
216- /// i686 has two levels (PD -> PT). The only sharable thing is a PT,
217- /// at depth 1 (one level below the root PD).
218- const SHARED_TABLE_DEPTH : usize = 1 ;
219-
220250/// Walk multiple root PDs together, detecting PDEs that point at the
221251/// same PT PA across roots (i.e. aliased PTs — the standard
222252/// "kernel-half shared" trick on x86 without KPTI). The first root to
223253/// visit a given PT PA becomes the "owner"; later roots that alias it
224- /// receive `AnotherSpace(SpaceReferenceMapping { depth: 1 , .. })`
254+ /// receive `AnotherSpace(SpaceReferenceMapping { level: SharedTableLevel::Pt , .. })`
225255/// entries.
226256///
257+ /// i686 has two levels (PD -> PT). The only sharable thing is a PT,
258+ /// one level below the root PD ([`SharedTableLevel::Pt`]).
259+ ///
227260/// Generic over `TableAddr` so it works with both the in-guest
228261/// implementation (`TableAddr = u32`, backed by raw pointers) and the
229262/// host-side snapshot buffer (`TableAddr = u64`, byte offsets).
@@ -273,7 +306,7 @@ pub unsafe fn walk_va_spaces<Op: TableReadOps>(
273306 if let Some ( & ( owner, their_va) ) = seen_pts. get ( & pt_pa) {
274307 if owner != root_id {
275308 mappings. push ( SpaceAwareMapping :: AnotherSpace ( SpaceReferenceMapping {
276- depth : SHARED_TABLE_DEPTH ,
309+ level : SharedTableLevel :: Pt ,
277310 space : owner,
278311 our_va : r. vmin ,
279312 their_va,
@@ -335,24 +368,18 @@ pub unsafe fn walk_va_spaces<Op: TableReadOps>(
335368/// PDE slot, and write that PA into our root's PDE slot for
336369/// `our_va`. The owner's rebuilt root is found via `built_roots`.
337370///
338- /// On i686 `ref_map.depth` must be 1 (PT-level sharing). Other depths
339- /// are rejected defensively.
340- ///
341371/// # Safety
342372/// Same invariants as [`map`]: caller owns the concurrency story and
343373/// must invalidate the TLB if the page tables are live.
344374#[ allow( clippy:: missing_safety_doc) ]
345- pub unsafe fn space_aware_map < Op : TableOps > (
375+ pub ( super ) unsafe fn link_shared_table < Op : TableOps > (
346376 op : & Op ,
347377 ref_map : SpaceReferenceMapping ,
348378 built_roots : & :: alloc:: collections:: BTreeMap < SpaceId , Op :: TableAddr > ,
349379) {
350- assert ! (
351- ref_map. depth == SHARED_TABLE_DEPTH ,
352- "i686 only supports depth={} sharing; got depth={}" ,
353- SHARED_TABLE_DEPTH ,
354- ref_map. depth
355- ) ;
380+ match ref_map. level {
381+ SharedTableLevel :: Pt => { }
382+ }
356383
357384 // Their rebuilt root — must have been populated earlier in the
358385 // rebuild loop (walk_va_spaces guarantees topological order).
0 commit comments