44//! Methods to construct page tables on x64. 
55
66use  crate :: IdentityMapSize ; 
7- use  crate :: PageTableBuffer ; 
87use  zerocopy:: FromBytes ; 
9- use  zerocopy:: FromZeros ; 
108use  zerocopy:: Immutable ; 
119use  zerocopy:: IntoBytes ; 
1210use  zerocopy:: KnownLayout ; 
@@ -18,6 +16,7 @@ const X64_PTE_DIRTY: u64 = 1 << 6;
1816const  X64_PTE_LARGE_PAGE :  u64  = 1  << 7 ; 
1917
2018const  PAGE_TABLE_ENTRY_COUNT :  usize  = 512 ; 
19+ const  PAGE_TABLE_ENTRY_SIZE :  usize  = 8 ; 
2120
2221const  X64_PAGE_SHIFT :  u64  = 12 ; 
2322const  X64_PTE_BITS :  u64  = 9 ; 
@@ -31,6 +30,14 @@ pub const X64_LARGE_PAGE_SIZE: u64 = 0x200000;
3130/// Number of bytes in a 1GB page for X64. 
3231pub  const  X64_1GB_PAGE_SIZE :  u64  = 0x40000000 ; 
3332
33+ /// Maximum number of page tables created for an x64 identity map 
34+ pub  const  PAGE_TABLE_MAX_COUNT :  usize  = 13 ; 
35+ 
36+ const  PAGE_TABLE_SIZE :  usize  = PAGE_TABLE_ENTRY_COUNT  *  PAGE_TABLE_ENTRY_SIZE ; 
37+ 
38+ /// Maximum number of bytes needed to store an x64 identity map 
39+ pub  const  PAGE_TABLE_MAX_BYTES :  usize  = PAGE_TABLE_MAX_COUNT  *  X64_PAGE_SIZE  as  usize ; 
40+ 
3441#[ derive( Copy ,  Clone ,  PartialEq ,  Eq ,  IntoBytes ,  Immutable ,  KnownLayout ,  FromBytes ) ]  
3542#[ repr( transparent) ]  
3643pub  struct  PageTableEntry  { 
@@ -341,11 +348,11 @@ impl PageTableBuilder {
341348    /// Build a set of X64 page tables identity mapping the given regions. `size` must be less than 512GB. 
342349     /// This creates up to 3+N page tables: 1 PML4E and up to 2 PDPTE tables, and N page tables counted at 1 per GB of size, 
343350     /// for 2MB mappings. 
344-      pub  fn  build < P ,   F > ( self ,   page_table :   & mut   P ,   flattened_page_table :   & mut   F ) 
345-     where 
346-         P :   PageTableBuffer < Element  =  PageTable > , 
347-         F :   PageTableBuffer < Element  =  u8 > , 
348-     { 
351+      pub  fn  build < ' a > ( 
352+          self , 
353+         page_table :   & mut   [ PageTable ] , 
354+         flattened_page_table :   & ' a   mut   [ u8 ] , 
355+     )  ->  & ' a   [ u8 ]   { 
349356        const  SIZE_512_GB :  u64  = 0x8000000000 ; 
350357
351358        if  self . size  == 0  { 
@@ -389,25 +396,24 @@ impl PageTableBuilder {
389396        } 
390397
391398        // Allocate single PML4E page table. 
392-         page_table. push ( PageTable :: new_zeroed ( ) ) ; 
393-         let  pml4_table_index = 0 ; 
399+         let  ( mut  page_table_index,  pml4_table_index)  = ( 0 ,  0 ) ; 
394400        let  confidential = self . confidential_bit . is_some ( ) ; 
395401
396402        let  mut  link_tables = |start_va :  u64 ,  end_va :  u64 ,  use_large_pages :  bool | { 
397403            let  mut  current_va = start_va; 
398404            while  current_va < end_va { 
399405                let  pdpte_table_index = { 
400-                     let  next_index = page_table. len ( ) ; 
401406                    let  pml4_entry = page_table[ pml4_table_index] . entry ( current_va,  3 ) ; 
402407                    if  !pml4_entry. is_present ( )  { 
408+                         page_table_index += 1 ; 
403409                        // Allocate and link PDPTE table. 
404-                         let  output_address = page_table_gpa + next_index as  u64  *  X64_PAGE_SIZE ; 
410+                         let  output_address =
411+                             page_table_gpa + page_table_index as  u64  *  X64_PAGE_SIZE ; 
405412                        let  mut  new_entry =
406413                            Self :: build_pte ( PageTableEntryType :: Pde ( output_address) ) ; 
407414                        self . set_pte_confidentiality ( & mut  new_entry,  confidential) ; 
408415                        * pml4_entry = new_entry; 
409-                         page_table. push ( PageTable :: new_zeroed ( ) ) ; 
410-                         next_index
416+                         page_table_index
411417                    }  else  { 
412418                        ( ( self . get_addr_from_pte ( pml4_entry)  - page_table_gpa)  / X64_PAGE_SIZE ) 
413419                            . try_into ( ) 
@@ -416,26 +422,25 @@ impl PageTableBuilder {
416422                } ; 
417423
418424                let  pde_table_index = { 
419-                     let  next_index = page_table. len ( ) ; 
420425                    let  pdpte_entry = page_table[ pdpte_table_index] . entry ( current_va,  2 ) ; 
421426                    if  !pdpte_entry. is_present ( )  { 
427+                         page_table_index += 1 ; 
422428                        // Allocate and link PDE table. 
423-                         let  output_address = page_table_gpa + next_index as  u64  *  X64_PAGE_SIZE ; 
429+                         let  output_address =
430+                             page_table_gpa + page_table_index as  u64  *  X64_PAGE_SIZE ; 
424431                        let  mut  new_entry =
425432                            Self :: build_pte ( PageTableEntryType :: Pde ( output_address) ) ; 
426433                        self . set_pte_confidentiality ( & mut  new_entry,  confidential) ; 
427434                        * pdpte_entry = new_entry; 
428-                         page_table. push ( PageTable :: new_zeroed ( ) ) ; 
429435
430-                         next_index 
436+                         page_table_index 
431437                    }  else  { 
432438                        ( ( self . get_addr_from_pte ( pdpte_entry)  - page_table_gpa)  / X64_PAGE_SIZE ) 
433439                            . try_into ( ) 
434440                            . expect ( "Valid page table index" ) 
435441                    } 
436442                } ; 
437443
438-                 let  next_index = page_table. len ( ) ; 
439444                let  pde_entry = page_table[ pde_table_index] . entry ( current_va,  1 ) ; 
440445                assert ! ( !pde_entry. is_present( ) ) ; 
441446
@@ -449,15 +454,16 @@ impl PageTableBuilder {
449454                    current_va += X64_LARGE_PAGE_SIZE ; 
450455                }  else  { 
451456                    let  pt_table_index = if  !pde_entry. is_present ( )  { 
457+                         page_table_index += 1 ; 
452458                        // Allocate and link page table. 
453-                         let  output_address = page_table_gpa + next_index as  u64  *  X64_PAGE_SIZE ; 
459+                         let  output_address =
460+                             page_table_gpa + page_table_index as  u64  *  X64_PAGE_SIZE ; 
454461                        let  mut  new_entry =
455462                            Self :: build_pte ( PageTableEntryType :: Pde ( output_address) ) ; 
456463                        self . set_pte_confidentiality ( & mut  new_entry,  confidential) ; 
457464                        * pde_entry = new_entry; 
458-                         page_table. push ( PageTable :: new_zeroed ( ) ) ; 
459465
460-                         next_index 
466+                         page_table_index 
461467                    }  else  { 
462468                        ( ( self . get_addr_from_pte ( pde_entry)  - page_table_gpa)  / X64_PAGE_SIZE ) 
463469                            . try_into ( ) 
@@ -487,7 +493,7 @@ impl PageTableBuilder {
487493        } 
488494
489495        // Flatten page table vec into u8 vec 
490-         flatten_page_table ( page_table,  flattened_page_table) ; 
496+         flatten_page_table ( page_table,  flattened_page_table,  page_table_index +  1 ) 
491497    } 
492498} 
493499
@@ -497,18 +503,15 @@ impl PageTableBuilder {
497503/// An optional PML4E entry may be linked, with arguments being (link_target_gpa, linkage_gpa). 
498504/// link_target_gpa represents the GPA of the PML4E to link into the built page table. 
499505/// linkage_gpa represents the GPA at which the linked PML4E should be linked. 
500- pub  fn  build_page_tables_64 < P ,   F > ( 
506+ pub  fn  build_page_tables_64 < ' a > ( 
501507    page_table_gpa :  u64 , 
502508    address_bias :  u64 , 
503509    identity_map_size :  IdentityMapSize , 
504510    pml4e_link :  Option < ( u64 ,  u64 ) > , 
505511    read_only :  bool , 
506-     page_table :  & mut  P , 
507-     flattened_page_table :  & mut  F , 
508- )  where 
509-     P :  PageTableBuffer < Element  = PageTable > , 
510-     F :  PageTableBuffer < Element  = u8 > , 
511- { 
512+     page_table :  & mut  [ PageTable ] , 
513+     flattened_page_table :  & ' a  mut  [ u8 ] , 
514+ )  -> & ' a  [ u8 ]  { 
512515    // Allocate page tables. There are up to 6 total page tables: 
513516    //      1 PML4E (Level 4) (omitted if the address bias is non-zero) 
514517    //      1 PDPTE (Level 3) 
@@ -519,9 +522,6 @@ pub fn build_page_tables_64<P, F>(
519522        IdentityMapSize :: Size8Gb  => 8 , 
520523    } ; 
521524    let  page_table_count = leaf_page_table_count + if  address_bias == 0  {  2  }  else  {  1  } ; 
522-     for  _ in  0 ..page_table_count { 
523-         page_table. push ( PageTable :: new_zeroed ( ) ) ; 
524-     } 
525525    let  mut  page_table_allocator = page_table. iter_mut ( ) . enumerate ( ) ; 
526526
527527    // Allocate single PDPTE table. 
@@ -586,11 +586,8 @@ pub fn build_page_tables_64<P, F>(
586586        } 
587587    } 
588588
589-     // All pagetables should be used, code bug if not. 
590-     assert ! ( page_table_allocator. next( ) . is_none( ) ) ; 
591- 
592589    // Flatten page table vec into u8 vec 
593-     flatten_page_table ( page_table,  flattened_page_table) 
590+     flatten_page_table ( page_table,  flattened_page_table,  page_table_count ) 
594591} 
595592
596593/// Align an address up to the start of the next page. 
@@ -607,14 +604,22 @@ pub fn align_up_to_large_page_size(address: u64) -> u64 {
607604pub  fn  align_up_to_1_gb_page_size ( address :  u64 )  -> u64  { 
608605    ( address + X64_1GB_PAGE_SIZE  - 1 )  &  !( X64_1GB_PAGE_SIZE  - 1 ) 
609606} 
610- fn  flatten_page_table < P ,  F > ( page_table :  & mut  P ,  flattened_page_table :  & mut  F ) 
611- where 
612-     P :  PageTableBuffer < Element  = PageTable > , 
613-     F :  PageTableBuffer < Element  = u8 > , 
614- { 
615-     for  table_index in  0 ..page_table. len ( )  { 
616-         flattened_page_table. extend ( page_table[ table_index] . as_bytes ( ) ) 
607+ 
608+ fn  flatten_page_table < ' a > ( 
609+     page_table :  & mut  [ PageTable ] , 
610+     flattened_page_table :  & ' a  mut  [ u8 ] , 
611+     page_table_count :  usize , 
612+ )  -> & ' a  [ u8 ]  { 
613+     for  ( page_table,  dst)  in  page_table
614+         . iter ( ) 
615+         . take ( page_table_count) 
616+         . zip ( flattened_page_table. chunks_mut ( PAGE_TABLE_SIZE ) ) 
617+     { 
618+         let  src = page_table. as_bytes ( ) ; 
619+         dst. copy_from_slice ( src) ; 
617620    } 
621+ 
622+     & flattened_page_table[ 0 ..PAGE_TABLE_SIZE  *  page_table_count] 
618623} 
619624
620625#[ cfg( test) ]  
0 commit comments