diff --git a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp index 9e846d47d6..48fdc325f5 100644 --- a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp +++ b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp @@ -151,12 +151,44 @@ early_query(addr_t va, addr_t *_physicalAddress) } +static inline uint32 +memory_type_to_pte_flags(uint32 memoryType) +{ + // ATM we only handle the uncacheable and write-through type explicitly. For + // all other types we rely on the MTRRs to be set up correctly. Since we set + // the default memory type to write-back and since the uncacheable type in + // the PTE overrides any MTRR attribute (though, as per the specs, that is + // not recommended for performance reasons), this reduces the work we + // actually *have* to do with the MTRRs to setting the remaining types + // (usually only write-combining for the frame buffer). + switch (memoryType) { + case B_MTR_UC: + return X86_PTE_CACHING_DISABLED; + + case B_MTR_WC: + // X86_PTE_WRITE_THROUGH would be closer, but the combination with + // MTRR WC is "implementation defined" for Pentium [Pro]. + return 0; + + case B_MTR_WT: + return X86_PTE_WRITE_THROUGH; + + case B_MTR_WP: + case B_MTR_WB: + default: + return 0; + } +} + + static void put_page_table_entry_in_pgtable(page_table_entry* entry, - addr_t physicalAddress, uint32 attributes, bool globalPage) + addr_t physicalAddress, uint32 attributes, uint32 memoryType, + bool globalPage) { page_table_entry page = (physicalAddress & X86_PTE_ADDRESS_MASK) - | X86_PTE_PRESENT | (globalPage ? X86_PTE_GLOBAL : 0); + | X86_PTE_PRESENT | (globalPage ? X86_PTE_GLOBAL : 0) + | memory_type_to_pte_flags(memoryType); // if the page is user accessible, it's automatically // accessible in kernel space, too (but with the same @@ -404,7 +436,6 @@ status_t X86VMTranslationMap::Map(addr_t va, addr_t pa, uint32 attributes, uint32 memoryType, vm_page_reservation* reservation) { -// TODO: Support memory types! TRACE("map_tmap: entry pa 0x%lx va 0x%lx\n", pa, va); /* @@ -458,7 +489,7 @@ X86VMTranslationMap::Map(addr_t va, addr_t pa, uint32 attributes, "virtual address: %#" B_PRIxADDR ", existing pte: %#" B_PRIx32, va, pt[index]); - put_page_table_entry_in_pgtable(&pt[index], pa, attributes, + put_page_table_entry_in_pgtable(&pt[index], pa, attributes, memoryType, IS_KERNEL_MAP(map)); pinner.Unlock(); @@ -975,7 +1006,6 @@ status_t X86VMTranslationMap::Protect(addr_t start, addr_t end, uint32 attributes, uint32 memoryType) { -// TODO: Support memory types! page_directory_entry *pd = fArchData->pgdir_virt; start = ROUNDDOWN(start, B_PAGE_SIZE); @@ -1026,8 +1056,8 @@ restart: page_table_entry oldEntry; while (true) { oldEntry = test_and_set_page_table_entry(&pt[index], - (entry & ~(X86_PTE_WRITABLE | X86_PTE_USER)) - | newProtectionFlags, + (entry & ~(X86_PTE_PROTECTION_MASK | X86_PTE_MEMORY_TYPE_MASK)) + | newProtectionFlags | memory_type_to_pte_flags(memoryType), entry); if (oldEntry == entry) break; @@ -1449,7 +1479,7 @@ arch_vm_translation_map_early_map(kernel_args *args, addr_t va, addr_t pa, // now, fill in the pentry put_page_table_entry_in_pgtable(sPageHole + va / B_PAGE_SIZE, pa, - attributes, IS_KERNEL_ADDRESS(va)); + attributes, 0, IS_KERNEL_ADDRESS(va)); return B_OK; } diff --git a/src/system/kernel/arch/x86/x86_paging.h b/src/system/kernel/arch/x86/x86_paging.h index c95273cf40..1fe796aafb 100644 --- a/src/system/kernel/arch/x86/x86_paging.h +++ b/src/system/kernel/arch/x86/x86_paging.h @@ -54,6 +54,9 @@ class TranslationMapPhysicalPageMapper; #define X86_PTE_IGNORED2 0x00000400 #define X86_PTE_IGNORED3 0x00000800 #define X86_PTE_ADDRESS_MASK 0xfffff000 +#define X86_PTE_PROTECTION_MASK (X86_PTE_WRITABLE | X86_PTE_USER) +#define X86_PTE_MEMORY_TYPE_MASK (X86_PTE_WRITE_THROUGH \ + | X86_PTE_CACHING_DISABLED) typedef uint32 page_table_entry;