arm64: Fixes to the page fault handler.
* Improve atomicity of PTE updates. * Centralize a few constants. Change-Id: Iaeeb82e9dc7f7ca97d13ba816fb72c6475754310 Reviewed-on: https://review.haiku-os.org/c/haiku/+/8171 Reviewed-by: waddlesplash <[email protected]> Reviewed-by: Fredrik Holmqvist <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
a64e78a34e
commit
50bb52021c
@@ -5,6 +5,10 @@
|
|||||||
#ifndef _KERNEL_ARCH_ARM64_ARCH_VM_TRANSLATION_MAP_H_
|
#ifndef _KERNEL_ARCH_ARM64_ARCH_VM_TRANSLATION_MAP_H_
|
||||||
#define _KERNEL_ARCH_ARM64_ARCH_VM_TRANSLATION_MAP_H_
|
#define _KERNEL_ARCH_ARM64_ARCH_VM_TRANSLATION_MAP_H_
|
||||||
|
|
||||||
|
// The base address of TTBR*_EL1 is in bits [47:1] of the register, and the
|
||||||
|
// low bit is implicitly zero.
|
||||||
|
static constexpr uint64_t kTtbrBasePhysAddrMask = (((1UL << 47) - 1) << 1);
|
||||||
|
|
||||||
void arch_vm_install_empty_table_ttbr0(void);
|
void arch_vm_install_empty_table_ttbr0(void);
|
||||||
|
|
||||||
#endif /* _KERNEL_ARCH_ARM64_ARCH_VM_TRANSLATION_MAP_H_ */
|
#endif /* _KERNEL_ARCH_ARM64_ARCH_VM_TRANSLATION_MAP_H_ */
|
||||||
|
|||||||
@@ -10,29 +10,6 @@
|
|||||||
#include <vm/vm_page.h>
|
#include <vm/vm_page.h>
|
||||||
#include <vm/vm_priv.h>
|
#include <vm/vm_priv.h>
|
||||||
|
|
||||||
|
|
||||||
static constexpr uint64_t kPteAddrMask = (((1UL << 36) - 1) << 12);
|
|
||||||
static constexpr uint64_t kPteAttrMask = ~(kPteAddrMask | 0x3);
|
|
||||||
static constexpr uint64_t kPteTLBCompatMask = (kPteAddrMask | (0x3 << 2) | (0x3 << 8));
|
|
||||||
|
|
||||||
static constexpr uint64_t kPteValidMask = 0x1;
|
|
||||||
static constexpr uint64_t kPteTypeMask = 0x3;
|
|
||||||
static constexpr uint64_t kPteTypeL012Table = 0x3;
|
|
||||||
static constexpr uint64_t kPteTypeL12Block = 0x1;
|
|
||||||
static constexpr uint64_t kPteTypeL3Page = 0x3;
|
|
||||||
|
|
||||||
static constexpr uint64_t kAttrSWDBM = (1UL << 55);
|
|
||||||
static constexpr uint64_t kAttrUXN = (1UL << 54);
|
|
||||||
static constexpr uint64_t kAttrPXN = (1UL << 53);
|
|
||||||
static constexpr uint64_t kAttrDBM = (1UL << 51);
|
|
||||||
static constexpr uint64_t kAttrNG = (1UL << 11);
|
|
||||||
static constexpr uint64_t kAttrAF = (1UL << 10);
|
|
||||||
static constexpr uint64_t kAttrSHInnerShareable = (3UL << 8);
|
|
||||||
static constexpr uint64_t kAttrAPReadOnly = (1UL << 7);
|
|
||||||
static constexpr uint64_t kAttrAPUserAccess = (1UL << 6);
|
|
||||||
|
|
||||||
static constexpr uint64_t kTLBIMask = ((1UL << 44) - 1);
|
|
||||||
|
|
||||||
uint32_t VMSAv8TranslationMap::fHwFeature;
|
uint32_t VMSAv8TranslationMap::fHwFeature;
|
||||||
uint64_t VMSAv8TranslationMap::fMair;
|
uint64_t VMSAv8TranslationMap::fMair;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,29 @@
|
|||||||
#include <vm/VMTranslationMap.h>
|
#include <vm/VMTranslationMap.h>
|
||||||
|
|
||||||
|
|
||||||
|
static constexpr uint64_t kPteAddrMask = (((1UL << 36) - 1) << 12);
|
||||||
|
static constexpr uint64_t kPteAttrMask = ~(kPteAddrMask | 0x3);
|
||||||
|
static constexpr uint64_t kPteTLBCompatMask = (kPteAddrMask | (0x3 << 2) | (0x3 << 8));
|
||||||
|
|
||||||
|
static constexpr uint64_t kPteValidMask = 0x1;
|
||||||
|
static constexpr uint64_t kPteTypeMask = 0x3;
|
||||||
|
static constexpr uint64_t kPteTypeL012Table = 0x3;
|
||||||
|
static constexpr uint64_t kPteTypeL12Block = 0x1;
|
||||||
|
static constexpr uint64_t kPteTypeL3Page = 0x3;
|
||||||
|
|
||||||
|
static constexpr uint64_t kAttrSWDBM = (1UL << 55);
|
||||||
|
static constexpr uint64_t kAttrUXN = (1UL << 54);
|
||||||
|
static constexpr uint64_t kAttrPXN = (1UL << 53);
|
||||||
|
static constexpr uint64_t kAttrDBM = (1UL << 51);
|
||||||
|
static constexpr uint64_t kAttrNG = (1UL << 11);
|
||||||
|
static constexpr uint64_t kAttrAF = (1UL << 10);
|
||||||
|
static constexpr uint64_t kAttrSHInnerShareable = (3UL << 8);
|
||||||
|
static constexpr uint64_t kAttrAPReadOnly = (1UL << 7);
|
||||||
|
static constexpr uint64_t kAttrAPUserAccess = (1UL << 6);
|
||||||
|
|
||||||
|
static constexpr uint64_t kTLBIMask = ((1UL << 44) - 1);
|
||||||
|
|
||||||
|
|
||||||
struct VMSAv8TranslationMap : public VMTranslationMap {
|
struct VMSAv8TranslationMap : public VMTranslationMap {
|
||||||
public:
|
public:
|
||||||
VMSAv8TranslationMap(
|
VMSAv8TranslationMap(
|
||||||
|
|||||||
@@ -127,13 +127,6 @@ arch_int_init_post_device_manager(struct kernel_args *args)
|
|||||||
|
|
||||||
static int page_bits = 12;
|
static int page_bits = 12;
|
||||||
|
|
||||||
static constexpr uint64_t kPteAddrMask = (((1UL << 36) - 1) << 12);
|
|
||||||
static constexpr uint64_t kPteAttrMask = ~(kPteAddrMask | 0x3);
|
|
||||||
static constexpr uint64_t kAttrSWDBM = (1UL << 55);
|
|
||||||
static constexpr uint64_t kAttrAF = (1UL << 10);
|
|
||||||
static constexpr uint64_t kAttrAP2 = (1UL << 7);
|
|
||||||
|
|
||||||
|
|
||||||
static uint64_t*
|
static uint64_t*
|
||||||
TableFromPa(phys_addr_t pa)
|
TableFromPa(phys_addr_t pa)
|
||||||
{
|
{
|
||||||
@@ -154,21 +147,31 @@ fixup_entry(phys_addr_t ptPa, int level, addr_t va, bool wr)
|
|||||||
int index = (va >> shift) & tableMask;
|
int index = (va >> shift) & tableMask;
|
||||||
|
|
||||||
uint64_t *pte = &TableFromPa(ptPa)[index];
|
uint64_t *pte = &TableFromPa(ptPa)[index];
|
||||||
|
uint64_t oldPte = atomic_get64((int64*)pte);
|
||||||
|
|
||||||
int type = *pte & 0x3;
|
int type = oldPte & kPteTypeMask;
|
||||||
uint64_t addr = *pte & kPteAddrMask;
|
uint64_t addr = oldPte & kPteAddrMask;
|
||||||
|
|
||||||
if ((level == 3 && type == 0x3) || (level < 3 && type == 0x1)) {
|
if ((level == 3 && type == kPteTypeL3Page) || (level < 3 && type == kPteTypeL12Block)) {
|
||||||
if (!wr && (*pte & kAttrAF) == 0) {
|
if (!wr && (oldPte & kAttrAF) == 0) {
|
||||||
atomic_or64((int64*)pte, kAttrAF);
|
uint64_t newPte = oldPte | kAttrAF;
|
||||||
|
if ((uint64_t)atomic_test_and_set64((int64*)pte, newPte, oldPte) != oldPte)
|
||||||
|
return true; // If something changed, handle it by taking another fault
|
||||||
|
asm("dsb ishst");
|
||||||
|
asm("isb");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (wr && (*pte & kAttrSWDBM) != 0 && (*pte & kAttrAP2) != 0) {
|
if (wr && (oldPte & kAttrSWDBM) != 0 && (oldPte & kAttrAPReadOnly) != 0) {
|
||||||
atomic_and64((int64*)pte, ~kAttrAP2);
|
uint64_t newPte = oldPte & ~kAttrAPReadOnly;
|
||||||
asm("tlbi vaae1is, %0 \n dsb ish"::"r"(va >> page_bits));
|
if ((uint64_t)atomic_test_and_set64((int64*)pte, newPte, oldPte) != oldPte)
|
||||||
|
return true;
|
||||||
|
asm("dsb ishst");
|
||||||
|
asm("tlbi vaae1is, %0" :: "r" ((va >> 12) & kTLBIMask));
|
||||||
|
asm("dsb ish");
|
||||||
|
asm("isb");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (level < 3 && type == 0x3) {
|
} else if (level < 3 && type == kPteTypeL012Table) {
|
||||||
return fixup_entry(addr, level + 1, va, wr);
|
return fixup_entry(addr, level + 1, va, wr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,6 +254,7 @@ do_sync_handler(iframe * frame)
|
|||||||
ptPa = READ_SPECIALREG(TTBR1_EL1);
|
ptPa = READ_SPECIALREG(TTBR1_EL1);
|
||||||
else
|
else
|
||||||
ptPa = READ_SPECIALREG(TTBR0_EL1);
|
ptPa = READ_SPECIALREG(TTBR0_EL1);
|
||||||
|
ptPa &= kTtbrBasePhysAddrMask;
|
||||||
|
|
||||||
switch (frame->esr & ISS_DATA_DFSC_MASK) {
|
switch (frame->esr & ISS_DATA_DFSC_MASK) {
|
||||||
case ISS_DATA_DFSC_TF_L0:
|
case ISS_DATA_DFSC_TF_L0:
|
||||||
|
|||||||
@@ -15,10 +15,6 @@
|
|||||||
|
|
||||||
static char sPhysicalPageMapperData[sizeof(PMAPPhysicalPageMapper)];
|
static char sPhysicalPageMapperData[sizeof(PMAPPhysicalPageMapper)];
|
||||||
|
|
||||||
// The base address of TTBR*_EL1 is in bits [47:1] of the register, and the
|
|
||||||
// low bit is implicitly zero.
|
|
||||||
static constexpr uint64_t kTtbrBasePhysAddrMask = (((1UL << 47) - 1) << 1);
|
|
||||||
|
|
||||||
// Physical pointer to an empty page table, which is used for break-before-make
|
// Physical pointer to an empty page table, which is used for break-before-make
|
||||||
// when updating TTBR0_EL1.
|
// when updating TTBR0_EL1.
|
||||||
static phys_addr_t sEmptyTable;
|
static phys_addr_t sEmptyTable;
|
||||||
@@ -145,9 +141,6 @@ arch_vm_translation_map_init_post_area(kernel_args* args)
|
|||||||
|
|
||||||
// TODO: reuse some bits from VMSAv8TranslationMap
|
// TODO: reuse some bits from VMSAv8TranslationMap
|
||||||
|
|
||||||
static constexpr uint64_t kPteAddrMask = (((1UL << 36) - 1) << 12);
|
|
||||||
static constexpr uint64_t kPteAttrMask = ~(kPteAddrMask | 0x3);
|
|
||||||
|
|
||||||
static uint64_t page_bits = 12;
|
static uint64_t page_bits = 12;
|
||||||
static uint64_t tsz = 16;
|
static uint64_t tsz = 16;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user