Module Name: src
Committed By: ryo
Date: Sat Feb 29 21:34:37 UTC 2020
Modified Files:
src/sys/arch/aarch64/aarch64: fault.c pmap.c pmapboot.c
src/sys/arch/aarch64/include: pte.h
Log Message:
Fix pmap to work correctly with tagged addresses
- when fault, untag from address before passing to uvm/pmap functions
- pmap_extract() checks more strictly and consider the address tag
To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/aarch64/aarch64/fault.c
cvs rdiff -u -r1.65 -r1.66 src/sys/arch/aarch64/aarch64/pmap.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/aarch64/aarch64/pmapboot.c
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/aarch64/include/pte.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/aarch64/aarch64/fault.c
diff -u src/sys/arch/aarch64/aarch64/fault.c:1.11 src/sys/arch/aarch64/aarch64/fault.c:1.12
--- src/sys/arch/aarch64/aarch64/fault.c:1.11 Thu Jan 9 01:38:34 2020
+++ src/sys/arch/aarch64/aarch64/fault.c Sat Feb 29 21:34:37 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: fault.c,v 1.11 2020/01/09 01:38:34 ryo Exp $ */
+/* $NetBSD: fault.c,v 1.12 2020/02/29 21:34:37 ryo Exp $ */
/*
* Copyright (c) 2017 Ryo Shimizu <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.11 2020/01/09 01:38:34 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.12 2020/02/29 21:34:37 ryo Exp $");
#include "opt_compat_netbsd32.h"
#include "opt_ddb.h"
@@ -157,6 +157,9 @@ data_abort_handler(struct trapframe *tf,
p = l->l_proc;
va = trunc_page((vaddr_t)tf->tf_far);
+ /* eliminate addresss tag if ECR_EL1.TBI[01] is enabled */
+ va = aarch64_untag_address(va);
+
if ((VM_MIN_KERNEL_ADDRESS <= va) && (va < VM_MAX_KERNEL_ADDRESS)) {
map = kernel_map;
UVMHIST_LOG(pmaphist, "use kernel_map %p", map, 0, 0, 0);
@@ -200,8 +203,8 @@ data_abort_handler(struct trapframe *tf,
if (user)
uvm_grow(p, va);
- UVMHIST_LOG(pmaphist, "uvm_fault success: va=%016llx",
- tf->tf_far, 0, 0, 0);
+ UVMHIST_LOG(pmaphist, "uvm_fault success: far=%016lx, va=%016llx",
+ tf->tf_far, va, 0, 0);
return;
}
Index: src/sys/arch/aarch64/aarch64/pmap.c
diff -u src/sys/arch/aarch64/aarch64/pmap.c:1.65 src/sys/arch/aarch64/aarch64/pmap.c:1.66
--- src/sys/arch/aarch64/aarch64/pmap.c:1.65 Sat Feb 29 21:10:09 2020
+++ src/sys/arch/aarch64/aarch64/pmap.c Sat Feb 29 21:34:37 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.65 2020/02/29 21:10:09 ryo Exp $ */
+/* $NetBSD: pmap.c,v 1.66 2020/02/29 21:34:37 ryo Exp $ */
/*
* Copyright (c) 2017 Ryo Shimizu <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.65 2020/02/29 21:10:09 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.66 2020/02/29 21:34:37 ryo Exp $");
#include "opt_arm_debug.h"
#include "opt_ddb.h"
@@ -49,6 +49,7 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.6
#include <aarch64/pte.h>
#include <aarch64/armreg.h>
#include <aarch64/cpufunc.h>
+#include <aarch64/locore.h>
#include <aarch64/machdep.h>
#ifdef DDB
#include <aarch64/db_machdep.h>
@@ -281,15 +282,25 @@ phys_to_pp(paddr_t pa)
#define IN_KSEG_ADDR(va) \
IN_RANGE((va), AARCH64_KSEG_START, AARCH64_KSEG_END)
-#define KASSERT_PM_ADDR(pm, va) \
+#ifdef DIAGNOSTIC
+#define KASSERT_PM_ADDR(pm,va) \
do { \
+ int space = aarch64_addressspace(va); \
if ((pm) == pmap_kernel()) { \
+ KASSERTMSG(space == AARCH64_ADDRSPACE_UPPER, \
+ "%s: kernel pm %p: va=%016lx" \
+ " is out of upper address space\n", \
+ __func__, (pm), (va)); \
KASSERTMSG(IN_RANGE((va), VM_MIN_KERNEL_ADDRESS, \
VM_MAX_KERNEL_ADDRESS), \
"%s: kernel pm %p: va=%016lx" \
" is not kernel address\n", \
__func__, (pm), (va)); \
} else { \
+ KASSERTMSG(space == AARCH64_ADDRSPACE_LOWER, \
+ "%s: user pm %p: va=%016lx" \
+ " is out of lower address space\n", \
+ __func__, (pm), (va)); \
KASSERTMSG(IN_RANGE((va), \
VM_MIN_ADDRESS, VM_MAX_ADDRESS), \
"%s: user pm %p: va=%016lx" \
@@ -297,6 +308,9 @@ phys_to_pp(paddr_t pa)
__func__, (pm), (va)); \
} \
} while (0 /* CONSTCOND */)
+#else /* DIAGNOSTIC */
+#define KASSERT_PM_ADDR(pm,va)
+#endif /* DIAGNOSTIC */
static const struct pmap_devmap *pmap_devmap_table;
@@ -739,25 +753,56 @@ pmap_extract(struct pmap *pm, vaddr_t va
pt_entry_t *ptep, pte;
paddr_t pa;
vsize_t blocksize = 0;
+ int space;
extern char __kernel_text[];
extern char _end[];
- if (IN_RANGE(va, (vaddr_t)__kernel_text, (vaddr_t)_end)) {
- /* fast loookup */
- pa = KERN_VTOPHYS(va);
- } else if (IN_KSEG_ADDR(va)) {
- /* fast loookup. should be used only if actually mapped? */
- pa = AARCH64_KVA_TO_PA(va);
- } else {
- ptep = _pmap_pte_lookup_bs(pm, va, &blocksize);
- if (ptep == NULL)
+ space = aarch64_addressspace(va);
+ if (pm == pmap_kernel()) {
+ if (space != AARCH64_ADDRSPACE_UPPER)
return false;
- pte = *ptep;
- if (!lxpde_valid(pte))
+
+ if (IN_RANGE(va, (vaddr_t)__kernel_text, (vaddr_t)_end)) {
+ /* kernel text/data/bss are definitely linear mapped */
+ pa = KERN_VTOPHYS(va);
+ goto mapped;
+ } else if (IN_KSEG_ADDR(va)) {
+ /*
+ * also KSEG is linear mapped, but areas that have no
+ * physical memory haven't been mapped.
+ * fast lookup by using the S1E1R/PAR_EL1 registers.
+ */
+ register_t s = daif_disable(DAIF_I|DAIF_F);
+ reg_s1e1r_write(va);
+ __asm __volatile ("isb");
+ uint64_t par = reg_par_el1_read();
+ daif_enable(s);
+
+ if (par & PAR_F)
+ return false;
+ pa = (__SHIFTOUT(par, PAR_PA) << PAR_PA_SHIFT) +
+ (va & __BITS(PAR_PA_SHIFT - 1, 0));
+ goto mapped;
+ }
+ } else {
+ if (space != AARCH64_ADDRSPACE_LOWER)
return false;
- pa = lxpde_pa(pte) + (va & (blocksize - 1));
}
+ /*
+ * other areas, it isn't able to examined using the PAR_EL1 register,
+ * because the page may be in an access fault state due to
+ * reference bit emulation.
+ */
+ ptep = _pmap_pte_lookup_bs(pm, va, &blocksize);
+ if (ptep == NULL)
+ return false;
+ pte = *ptep;
+ if (!lxpde_valid(pte))
+ return false;
+ pa = lxpde_pa(pte) + (va & (blocksize - 1));
+
+ mapped:
if (pap != NULL)
*pap = pa;
return true;
@@ -769,7 +814,8 @@ vtophys(vaddr_t va)
struct pmap *pm;
paddr_t pa;
- if (va & TTBR_SEL_VA)
+ /* even if TBI is disabled, AARCH64_ADDRTOP_TAG means KVA */
+ if ((uint64_t)va & AARCH64_ADDRTOP_TAG)
pm = pmap_kernel();
else
pm = curlwp->l_proc->p_vmspace->vm_map.pmap;
@@ -791,13 +837,6 @@ _pmap_pte_lookup_bs(struct pmap *pm, vad
vsize_t blocksize;
unsigned int idx;
- if (((pm == pmap_kernel()) && ((va & TTBR_SEL_VA) == 0)) ||
- ((pm != pmap_kernel()) && ((va & TTBR_SEL_VA) != 0))) {
- blocksize = 0;
- ptep = NULL;
- goto done;
- }
-
/*
* traverse L0 -> L1 -> L2 -> L3
*/
@@ -856,6 +895,8 @@ pmap_icache_sync_range(pmap_t pm, vaddr_
vaddr_t va;
vsize_t blocksize = 0;
+ KASSERT_PM_ADDR(pm, sva);
+
pm_lock(pm);
for (va = sva; va < eva; va = (va + blocksize) & ~(blocksize - 1)) {
@@ -2553,12 +2594,18 @@ pmap_db_pteinfo(vaddr_t va, void (*pr)(c
paddr_t pa;
unsigned int idx;
- if (va & TTBR_SEL_VA) {
+ switch (aarch64_addressspace(va)) {
+ case AARCH64_ADDRSPACE_UPPER:
user = false;
ttbr = reg_ttbr1_el1_read();
- } else {
+ break;
+ case AARCH64_ADDRSPACE_LOWER:
user = true;
ttbr = reg_ttbr0_el1_read();
+ break;
+ default:
+ pr("illegal address space\n");
+ return;
}
pa = ttbr & TTBR_BADDR;
l0 = (pd_entry_t *)AARCH64_PA_TO_KVA(pa);
Index: src/sys/arch/aarch64/aarch64/pmapboot.c
diff -u src/sys/arch/aarch64/aarch64/pmapboot.c:1.5 src/sys/arch/aarch64/aarch64/pmapboot.c:1.6
--- src/sys/arch/aarch64/aarch64/pmapboot.c:1.5 Sat Feb 29 21:09:11 2020
+++ src/sys/arch/aarch64/aarch64/pmapboot.c Sat Feb 29 21:34:37 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: pmapboot.c,v 1.5 2020/02/29 21:09:11 ryo Exp $ */
+/* $NetBSD: pmapboot.c,v 1.6 2020/02/29 21:34:37 ryo Exp $ */
/*
* Copyright (c) 2018 Ryo Shimizu <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmapboot.c,v 1.5 2020/02/29 21:09:11 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmapboot.c,v 1.6 2020/02/29 21:34:37 ryo Exp $");
#include "opt_arm_debug.h"
#include "opt_ddb.h"
@@ -47,7 +47,6 @@ __KERNEL_RCSID(0, "$NetBSD: pmapboot.c,v
#define OPTIMIZE_TLB_CONTIG
-
static void
pmapboot_protect_entry(pt_entry_t *pte, vm_prot_t clrprot)
{
@@ -77,17 +76,21 @@ pmapboot_protect(vaddr_t sva, vaddr_t ev
paddr_t pa;
pd_entry_t *l0, *l1, *l2, *l3;
- for (va = sva; va < eva;) {
- /*
- * 0x0000xxxxxxxxxxxx -> l0 = (ttbr0_el1 & TTBR_BADDR)
- * 0xffffxxxxxxxxxxxx -> l0 = (ttbr1_el1 & TTBR_BADDR)
- */
- if (va & TTBR_SEL_VA)
- pa = (reg_ttbr1_el1_read() & TTBR_BADDR);
- else
- pa = (reg_ttbr0_el1_read() & TTBR_BADDR);
- l0 = (pd_entry_t *)AARCH64_PA_TO_KVA(pa);
+ switch (aarch64_addressspace(sva)) {
+ case AARCH64_ADDRSPACE_LOWER:
+ /* 0x0000xxxxxxxxxxxx */
+ pa = (reg_ttbr0_el1_read() & TTBR_BADDR);
+ break;
+ case AARCH64_ADDRSPACE_UPPER:
+ /* 0xFFFFxxxxxxxxxxxx */
+ pa = (reg_ttbr1_el1_read() & TTBR_BADDR);
+ break;
+ default:
+ return -1;
+ }
+ l0 = (pd_entry_t *)AARCH64_PA_TO_KVA(pa);
+ for (va = sva; va < eva;) {
idx = l0pde_index(va);
if (!l0pde_valid(l0[idx]))
return -1;
@@ -233,19 +236,22 @@ pmapboot_enter(vaddr_t va, paddr_t pa, p
attr |= LX_BLKPAG_OS_BOOT;
- while (va <= va_end) {
- /*
- * 0x0000xxxxxxxxxxxx -> l0 = (ttbr0_el1 & TTBR_BADDR)
- * 0xffffxxxxxxxxxxxx -> l0 = (ttbr1_el1 & TTBR_BADDR)
- */
- if (va & TTBR_SEL_VA) {
- l0 = (pd_entry_t *)(reg_ttbr1_el1_read() & TTBR_BADDR);
- ttbr = 1;
- } else {
- l0 = (pd_entry_t *)(reg_ttbr0_el1_read() & TTBR_BADDR);
- ttbr = 0;
- }
+ switch (aarch64_addressspace(va)) {
+ case AARCH64_ADDRSPACE_LOWER:
+ /* 0x0000xxxxxxxxxxxx */
+ l0 = (pd_entry_t *)(reg_ttbr0_el1_read() & TTBR_BADDR);
+ ttbr = 0;
+ break;
+ case AARCH64_ADDRSPACE_UPPER:
+ /* 0xFFFFxxxxxxxxxxxx */
+ l0 = (pd_entry_t *)(reg_ttbr1_el1_read() & TTBR_BADDR);
+ ttbr = 1;
+ break;
+ default:
+ return -1;
+ }
+ while (va <= va_end) {
#ifdef OPTIMIZE_TLB_CONTIG
ll = NULL;
llidx = -1;
Index: src/sys/arch/aarch64/include/pte.h
diff -u src/sys/arch/aarch64/include/pte.h:1.11 src/sys/arch/aarch64/include/pte.h:1.12
--- src/sys/arch/aarch64/include/pte.h:1.11 Fri Jan 31 09:23:58 2020
+++ src/sys/arch/aarch64/include/pte.h Sat Feb 29 21:34:37 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: pte.h,v 1.11 2020/01/31 09:23:58 maxv Exp $ */
+/* $NetBSD: pte.h,v 1.12 2020/02/29 21:34:37 ryo Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -135,8 +135,6 @@ typedef uint64_t pt_entry_t; /* L3(4k) t
#define Ln_ENTRIES (1 << Ln_ENTRIES_SHIFT)
#define Ln_TABLE_SIZE (8 << Ln_ENTRIES_SHIFT)
-#define TTBR_SEL_VA __BIT(63) /* which TTBR is selected */
-
#elif defined(__arm__)
#include <arm/pte.h>