@@ -236,17 +236,21 @@ uint64_t setup_amd64_paging(vMemory& memory,
236236
237237 if (split_all_hugepages_during_loading)
238238 {
239+ // Stop at 1MB address, to prevent trampling user space
240+ uint64_t max = 512 * PD_PAGES;
241+ if (max > 512U * 1U )
242+ max = 512U * 1U ;
243+
239244 // Split all hugepages into 4k pages for the entire memory area
240- for (uint64_t i = base_2mb_page; i < 512 *PD_PAGES ; i++)
245+ for (uint64_t i = base_2mb_page+ 2 ; i < max ; i++)
241246 {
242247 if (pd[i] & PDE64_PS) {
243248 // Set default attributes + free PTE page
244- pd[i] = PDE64_PRESENT | PDE64_USER | PDE64_RW | free_page;
245- // Fill new page with default attributes
249+ pd[i] = PDE64_PRESENT | heap_flags | free_page;
250+ // Fill new page with default heap attributes
246251 auto * pagetable = (uint64_t *) memory.at (free_page);
247252 for (uint64_t j = 0 ; j < 512 ; j++) {
248- // Set writable 4k attributes
249- uint64_t addr4k = (base_giga_page << 30 ) | (i << 21 ) | (j << 12 );
253+ const uint64_t addr4k = (base_giga_page << 30 ) | (i << 21 ) | (j << 12 );
250254 pagetable[j] =
251255 PDE64_PRESENT | heap_flags | addr4k;
252256 }
@@ -937,4 +941,54 @@ void WritablePage::set_protections(int prot)
937941 }
938942}
939943
944+ size_t paging_merge_leaf_pages_into_hugepages (vMemory& memory)
945+ {
946+ unsigned merged_pages = 0 ;
947+ // Try to merge contiguous 4k pages with the same permissions,
948+ // ignoring accessed/dirty bits, into 2MB pages. We will not
949+ // try to optimize the page tables, rather just turn 2MB entry
950+ // pages directly into leaf 2MB pages.
951+ auto * pml4 = memory.page_at (memory.page_tables );
952+ for (size_t i = 0 ; i < 4 ; i++) { // 512GB entries
953+ if (pml4[i] & PDE64_PRESENT) {
954+ const auto [pdpt_base, pdpt_mem, pdpt_size] = pdpt_from_index (i, pml4);
955+ auto * pdpt = memory.page_at (pdpt_mem);
956+ for (uint64_t j = 0 ; j < 512 ; j++) { // 1GB entries
957+ if (pdpt[j] & PDE64_PRESENT) {
958+ const auto [pd_base, pd_mem, pd_size] = pd_from_index (j, pdpt_base, pdpt);
959+ auto * pd = memory.page_at (pd_mem);
960+ for (uint64_t k = 0 ; k < 512 ; k++) { // 2MB entries
961+ if (pd[k] & PDE64_PRESENT) {
962+ // Only consider page tables
963+ if (pd[k] & PDE64_PS)
964+ continue ;
965+ const auto [pt_base, pt_mem, pt_size] = pt_from_index (k, pd_base, pd);
966+ auto * pt = memory.page_at (pt_mem);
967+ // Check if we can merge 512 entries
968+ bool can_merge = true ;
969+ static constexpr uint64_t MERGE_MASK =
970+ PDE64_PRESENT | PDE64_RW | PDE64_USER | PDE64_NX | PDE64_CLONEABLE | PDE64_G;
971+ uint64_t first_entry = pt[0 ] & MERGE_MASK;
972+ for (size_t e = 1 ; e < 512 ; e++) {
973+ if ((pt[e] & MERGE_MASK) != first_entry) {
974+ can_merge = false ;
975+ break ;
976+ }
977+ }
978+ if (can_merge) {
979+ // Merge into 2MB page with same flags
980+ pd[k] = (pt[0 ] & PDE64_ADDR_MASK) | first_entry
981+ | PDE64_PS | PDE64_PRESENT;
982+ CLPRINT (" Merged 4k pages into 2MB page at PD index %lu\n " , k);
983+ merged_pages += 512 ;
984+ }
985+ } // pd present
986+ } // pd[k]
987+ } // pdpt present
988+ } // pdpt[j]
989+ } // pml4 present
990+ } // pml4[i]
991+ return merged_pages;
992+ } // paging_merge_leaf_pages_into_hugepages()
993+
940994} // tinykvm
0 commit comments