kernel/arm: implement memory attributes
Set AP[2:0] and XN flags based on page attributes. PXN is not implemented as it seems to be available only in L1 descriptors on ARMv7. Set TEX, B, C flags based on memoryType: * B_MTR_UC is mapped to Strongly Ordered (TEX=0, B=0, C=0) * B_MTR_WC is mapped to Shareable Device Memory (TEX=0, B=1, C=0) * B_MTR_WT is mapped to Outer and Inner Write-Through, no Write-Allocate (TEX=0, B=0, C=1) * B_MTR_WB is mapped to Outer and Inner Write-Back, no Write-Allocate (TEx=0, B=1, C=1) * B_MTR_WP has no direct equivalent on the ARM so it's mapped as B_MTR_WB * default is Write-Back Implement ARMPagingMethod32Bit::AttributesToPageTableEntryFlags() for mapping from page attributes to AP[2:0] and XN flags. Implement ARMPagingMethod32Bit::PageTableEntryFlagsToAttributes() for the reverse mapping used in Query() and QueryInterrupt() i.e. recover page attributes from AP[2:0] and XN flags. Implement ARMPagingMethod32Bit::MemoryTypeToPageTableEntryFlags() fr mapping from memoryType to TEX, B, C flags. Implement ARMVMTranslationMap32Bit::Protect() which used to be commented out. Accessed and modified flags are not implemented yet, so no such flags are returned from Query() and QueryInterrupt(). Also because of this, we just invalidate TLB on any call to Protect() without checking whether the page has been accessed. Change-Id: I027af5c02bd6218d9f92a58044aeb26373e1956b Reviewed-on: https://review.haiku-os.org/c/haiku/+/5236 Reviewed-by: Adrien Destugues <[email protected]> Reviewed-by: Fredrik Holmqvist <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
d0c94afe0c
commit
745a40d78a
@@ -96,4 +96,7 @@
|
||||
#define ARM_PTE_ADDRESS_MASK 0xfffff000
|
||||
#define ARM_PTE_TYPE_MASK 0x00000003
|
||||
|
||||
#define ARM_PTE_PROTECTION_MASK 0x00000231 // AP[2:0], XN
|
||||
#define ARM_PTE_MEMORY_TYPE_MASK 0x000001cc // TEX, B, C
|
||||
|
||||
#endif /* _ARCH_ARM_ARM_MMU_H */
|
||||
|
||||
@@ -511,22 +511,10 @@ ARMPagingMethod32Bit::PutPageTableEntryInTable(page_table_entry* entry,
|
||||
{
|
||||
page_table_entry page = (physicalAddress & ARM_PTE_ADDRESS_MASK)
|
||||
| ARM_MMU_L2_TYPE_SMALLNEW
|
||||
| ARM_MMU_L2_FLAG_B | ARM_MMU_L2_FLAG_C
|
||||
| ARM_MMU_L2_FLAG_AP_RW;
|
||||
#if 0 //IRA
|
||||
| X86_PTE_PRESENT | (globalPage ? X86_PTE_GLOBAL : 0)
|
||||
| MemoryTypeToPageTableEntryFlags(memoryType);
|
||||
| MemoryTypeToPageTableEntryFlags(memoryType)
|
||||
| AttributesToPageTableEntryFlags(attributes)
|
||||
| (globalPage ? 0 : ARM_MMU_L2_FLAG_NG);
|
||||
|
||||
// if the page is user accessible, it's automatically
|
||||
// accessible in kernel space, too (but with the same
|
||||
// protection)
|
||||
if ((attributes & B_USER_PROTECTION) != 0) {
|
||||
page |= X86_PTE_USER;
|
||||
if ((attributes & B_WRITE_AREA) != 0)
|
||||
page |= X86_PTE_WRITABLE;
|
||||
} else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
|
||||
page |= X86_PTE_WRITABLE;
|
||||
#endif
|
||||
// put it in the page table
|
||||
*(volatile page_table_entry*)entry = page;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,10 @@ public:
|
||||
static page_table_entry ClearPageTableEntryFlags(
|
||||
page_table_entry* entry, uint32 flags);
|
||||
|
||||
static uint32 AttributesToPageTableEntryFlags(
|
||||
uint32 attributes);
|
||||
static uint32 PageTableEntryFlagsToAttributes(
|
||||
uint32 pageTableEntry);
|
||||
static uint32 MemoryTypeToPageTableEntryFlags(
|
||||
uint32 memoryType);
|
||||
|
||||
@@ -139,37 +143,95 @@ ARMPagingMethod32Bit::ClearPageTableEntryFlags(page_table_entry* entry, uint32 f
|
||||
}
|
||||
|
||||
|
||||
/*static*/ inline uint32
|
||||
ARMPagingMethod32Bit::AttributesToPageTableEntryFlags(uint32 attributes)
|
||||
{
|
||||
int apFlags = 0;
|
||||
|
||||
if ((attributes & B_WRITE_AREA) != 0) {
|
||||
// kernel rw user rw
|
||||
apFlags = ARM_MMU_L2_FLAG_AP1 | ARM_MMU_L2_FLAG_AP0;
|
||||
} else if ((attributes & B_READ_AREA) != 0) {
|
||||
if ((attributes & B_KERNEL_WRITE_AREA) != 0) {
|
||||
// kernel rw user ro
|
||||
apFlags = ARM_MMU_L2_FLAG_AP1;
|
||||
} else {
|
||||
// kernel ro user ro
|
||||
apFlags = ARM_MMU_L2_FLAG_AP2 | ARM_MMU_L2_FLAG_AP1;
|
||||
}
|
||||
} else if ((attributes & B_KERNEL_WRITE_AREA) != 0) {
|
||||
// kernel rw
|
||||
apFlags = ARM_MMU_L2_FLAG_AP0;
|
||||
} else {
|
||||
// kernel ro
|
||||
apFlags = ARM_MMU_L2_FLAG_AP2 | ARM_MMU_L2_FLAG_AP0;
|
||||
}
|
||||
|
||||
if (((attributes & B_KERNEL_EXECUTE_AREA) == 0) &&
|
||||
((attributes & B_EXECUTE_AREA) == 0)) {
|
||||
apFlags |= ARM_MMU_L2_FLAG_XN;
|
||||
}
|
||||
|
||||
return apFlags;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ inline uint32
|
||||
ARMPagingMethod32Bit::PageTableEntryFlagsToAttributes(uint32 pageTableEntry)
|
||||
{
|
||||
uint32 attributes;
|
||||
|
||||
if ((pageTableEntry & ARM_MMU_L2_FLAG_AP2) == 0) {
|
||||
if ((pageTableEntry & ARM_MMU_L2_FLAG_AP1) != 0) {
|
||||
if ((pageTableEntry & ARM_MMU_L2_FLAG_AP0) != 0)
|
||||
attributes = B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA;
|
||||
else
|
||||
attributes = B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA;
|
||||
} else {
|
||||
if ((pageTableEntry & ARM_MMU_L2_FLAG_AP0) != 0)
|
||||
attributes = B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA;
|
||||
else
|
||||
attributes = 0;
|
||||
}
|
||||
} else {
|
||||
if ((pageTableEntry & ARM_MMU_L2_FLAG_AP1) != 0)
|
||||
attributes = B_KERNEL_READ_AREA | B_READ_AREA;
|
||||
else if ((pageTableEntry & ARM_MMU_L2_FLAG_AP0) != 0)
|
||||
attributes = B_KERNEL_READ_AREA;
|
||||
else
|
||||
attributes = 0;
|
||||
}
|
||||
|
||||
if ((pageTableEntry & ARM_MMU_L2_FLAG_XN) == 0) {
|
||||
if ((attributes & B_KERNEL_READ_AREA) != 0)
|
||||
attributes |= B_KERNEL_EXECUTE_AREA;
|
||||
if ((attributes & B_READ_AREA) != 0)
|
||||
attributes |= B_EXECUTE_AREA;
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ inline uint32
|
||||
ARMPagingMethod32Bit::MemoryTypeToPageTableEntryFlags(uint32 memoryType)
|
||||
{
|
||||
#if 0 //IRA
|
||||
// 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 | X86_PTE_WRITE_THROUGH;
|
||||
|
||||
case B_MTR_WC:
|
||||
// ARM_PTE_WRITE_THROUGH would be closer, but the combination with
|
||||
// MTRR WC is "implementation defined" for Pentium Pro/II.
|
||||
// Strongly Ordered
|
||||
return 0;
|
||||
|
||||
case B_MTR_WC:
|
||||
// Shareable Device Memory
|
||||
return ARM_MMU_L2_FLAG_B;
|
||||
case B_MTR_WT:
|
||||
return X86_PTE_WRITE_THROUGH;
|
||||
|
||||
// Outer and Inner Write-Through, no Write-Allocate
|
||||
return ARM_MMU_L2_FLAG_C;
|
||||
case B_MTR_WP:
|
||||
case B_MTR_WB:
|
||||
default:
|
||||
return 0;
|
||||
// Outer and Inner Write-Back, no Write-Allocate
|
||||
return ARM_MMU_L2_FLAG_B | ARM_MMU_L2_FLAG_C;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -638,23 +638,11 @@ ARMVMTranslationMap32Bit::Query(addr_t va, phys_addr_t *_physical,
|
||||
if ((entry & ARM_PTE_TYPE_MASK) != 0)
|
||||
*_physical = (entry & ARM_PTE_ADDRESS_MASK);
|
||||
|
||||
#if 0 //IRA
|
||||
// read in the page state flags
|
||||
if ((entry & X86_PTE_USER) != 0) {
|
||||
*_flags |= ((entry & X86_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0)
|
||||
| B_READ_AREA;
|
||||
}
|
||||
|
||||
*_flags |= ((entry & X86_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0)
|
||||
| B_KERNEL_READ_AREA
|
||||
| ((entry & ARM_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
|
||||
| ((entry & ARM_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
|
||||
| ((entry & ARM_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
|
||||
#else
|
||||
*_flags = B_KERNEL_WRITE_AREA | B_KERNEL_READ_AREA;
|
||||
//TODO: read in the page state flags
|
||||
*_flags = ARMPagingMethod32Bit::PageTableEntryFlagsToAttributes(entry);
|
||||
if (*_physical != 0)
|
||||
*_flags |= PAGE_PRESENT;
|
||||
#endif
|
||||
|
||||
pinner.Unlock();
|
||||
|
||||
TRACE("query_tmap: returning pa 0x%lx for va 0x%lx\n", *_physical, va);
|
||||
@@ -686,23 +674,11 @@ ARMVMTranslationMap32Bit::QueryInterrupt(addr_t va, phys_addr_t *_physical,
|
||||
if ((entry & ARM_PTE_TYPE_MASK) != 0)
|
||||
*_physical = (entry & ARM_PTE_ADDRESS_MASK);
|
||||
|
||||
#if 0
|
||||
// read in the page state flags
|
||||
if ((entry & X86_PTE_USER) != 0) {
|
||||
*_flags |= ((entry & X86_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0)
|
||||
| B_READ_AREA;
|
||||
}
|
||||
|
||||
*_flags |= ((entry & X86_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0)
|
||||
| B_KERNEL_READ_AREA
|
||||
| ((entry & X86_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
|
||||
| ((entry & X86_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
|
||||
| ((entry & X86_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
|
||||
#else
|
||||
*_flags = B_KERNEL_WRITE_AREA | B_KERNEL_READ_AREA;
|
||||
//TODO: read in the page state flags
|
||||
*_flags = ARMPagingMethod32Bit::PageTableEntryFlagsToAttributes(entry);
|
||||
if (*_physical != 0)
|
||||
*_flags |= PAGE_PRESENT;
|
||||
#endif
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -717,15 +693,9 @@ ARMVMTranslationMap32Bit::Protect(addr_t start, addr_t end, uint32 attributes,
|
||||
|
||||
TRACE("protect_tmap: pages 0x%lx to 0x%lx, attributes %lx\n", start, end,
|
||||
attributes);
|
||||
#if 0 //IRA
|
||||
// compute protection flags
|
||||
uint32 newProtectionFlags = 0;
|
||||
if ((attributes & B_USER_PROTECTION) != 0) {
|
||||
newProtectionFlags = ARM_PTE_USER;
|
||||
if ((attributes & B_WRITE_AREA) != 0)
|
||||
newProtectionFlags |= ARM_PTE_WRITABLE;
|
||||
} else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
|
||||
newProtectionFlags = ARM_PTE_WRITABLE;
|
||||
|
||||
uint32 newProtectionFlags = ARMPagingMethod32Bit::AttributesToPageTableEntryFlags(attributes);
|
||||
uint32 newMemoryTypeFlags = ARMPagingMethod32Bit::MemoryTypeToPageTableEntryFlags(memoryType);
|
||||
|
||||
page_directory_entry *pd = fPagingStructures->pgdir_virt;
|
||||
|
||||
@@ -747,7 +717,7 @@ ARMVMTranslationMap32Bit::Protect(addr_t start, addr_t end, uint32 attributes,
|
||||
for (index = VADDR_TO_PTENT(start); index < 256 && start < end;
|
||||
index++, start += B_PAGE_SIZE) {
|
||||
page_table_entry entry = pt[index];
|
||||
if ((entry & ARM_PTE_PRESENT) == 0) {
|
||||
if ((entry & ARM_PTE_TYPE_MASK) == 0) {
|
||||
// page mapping not valid
|
||||
continue;
|
||||
}
|
||||
@@ -762,24 +732,18 @@ ARMVMTranslationMap32Bit::Protect(addr_t start, addr_t end, uint32 attributes,
|
||||
&pt[index],
|
||||
(entry & ~(ARM_PTE_PROTECTION_MASK
|
||||
| ARM_PTE_MEMORY_TYPE_MASK))
|
||||
| newProtectionFlags
|
||||
| ARMPagingMethod32Bit::MemoryTypeToPageTableEntryFlags(
|
||||
memoryType),
|
||||
| newProtectionFlags | newMemoryTypeFlags,
|
||||
entry);
|
||||
if (oldEntry == entry)
|
||||
break;
|
||||
entry = oldEntry;
|
||||
}
|
||||
|
||||
if ((oldEntry & ARM_PTE_ACCESSED) != 0) {
|
||||
// Note, that we only need to invalidate the address, if the
|
||||
// accessed flag was set, since only then the entry could have
|
||||
// been in any TLB.
|
||||
InvalidatePage(start);
|
||||
}
|
||||
//TODO: invalidate only if the Accessed flag is set
|
||||
InvalidatePage(start);
|
||||
}
|
||||
} while (start != 0 && start < end);
|
||||
#endif
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user