summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2020-10-23 16:54:46 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2020-10-23 16:54:46 +0000
commit27c20f37a7ac49098c2855d9d3cae544b4981297 (patch)
tree6cb1299ff814631fc0fcf62c29c3b35e844af179 /sys/arch/sparc64
parent522833ae3ed17802c846dd1a722e8d14a378c216 (diff)
Refactor page fault/error functions, normalizing their operation relative
to other architectures. Kernel lock only the minimum (in preparation for further unlocking down the line) ok kettenis
Diffstat (limited to 'sys/arch/sparc64')
-rw-r--r--sys/arch/sparc64/sparc64/trap.c354
1 files changed, 154 insertions, 200 deletions
diff --git a/sys/arch/sparc64/sparc64/trap.c b/sys/arch/sparc64/sparc64/trap.c
index 7cc15c50792..2b9e05d0d2f 100644
--- a/sys/arch/sparc64/sparc64/trap.c
+++ b/sys/arch/sparc64/sparc64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.106 2020/10/21 17:54:33 deraadt Exp $ */
+/* $OpenBSD: trap.c,v 1.107 2020/10/23 16:54:35 deraadt Exp $ */
/* $NetBSD: trap.c,v 1.73 2001/08/09 01:03:01 eeh Exp $ */
/*
@@ -718,6 +718,21 @@ pmap_unuse_final(struct proc *p)
p->p_addr->u_pcb.pcb_nsaved = 0;
}
+static inline int
+accesstype(unsigned int type, u_long sfsr)
+{
+ /*
+ * If it was a FAST_DATA_ACCESS_MMU_MISS we have no idea what the
+ * access was since the SFSR is not set. But we should never get
+ * here from there.
+ */
+ if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0)
+ return PROT_READ;
+ else if (sfsr & SFSR_W)
+ return PROT_READ | PROT_WRITE;
+ return PROT_READ;
+}
+
/*
* This routine handles MMU generated faults. About half
* of them could be recoverable through uvm_fault.
@@ -726,40 +741,18 @@ void
data_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc,
vaddr_t addr, vaddr_t sfva, u_long sfsr)
{
- u_int64_t tstate;
- struct proc *p;
- struct vmspace *vm;
- vaddr_t va;
- int rv;
- vm_prot_t access_type;
+ struct proc *p = curproc;
+ vaddr_t va = trunc_page(addr);
+ vm_prot_t access_type = accesstype(type, sfsr);
vaddr_t onfault;
union sigval sv;
+ int signal, sicode, error;
uvmexp.traps++;
- if ((p = curproc) == NULL) /* safety check */
+ if (p == NULL) /* safety check */
p = &proc0;
- tstate = tf->tf_tstate;
-
- /* Find the faulting va to give to uvm_fault */
- va = trunc_page(addr);
-
- /*
- * Now munch on protections.
- *
- * If it was a FAST_DATA_ACCESS_MMU_MISS we have no idea what the
- * access was since the SFSR is not set. But we should never get
- * here from there.
- */
- if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0) {
- /* Punt */
- access_type = PROT_READ;
- } else {
- access_type = (sfsr & SFSR_W) ? PROT_READ | PROT_WRITE
- : PROT_READ;
- }
- if (tstate & TSTATE_PRIV) {
- KERNEL_LOCK();
+ if (tf->tf_tstate & TSTATE_PRIV) {
#ifdef DDB
extern char Lfsprobe[];
/*
@@ -779,11 +772,13 @@ data_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc,
goto kfault;
if (!(addr & TLB_TAG_ACCESS_CTX)) {
/* CTXT == NUCLEUS */
- rv = uvm_fault(kernel_map, va, 0, access_type);
- if (rv == 0) {
- KERNEL_UNLOCK();
+
+ KERNEL_LOCK();
+ error = uvm_fault(kernel_map, va, 0, access_type);
+ KERNEL_UNLOCK();
+
+ if (error == 0)
return;
- }
goto kfault;
}
} else {
@@ -793,15 +788,13 @@ data_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc,
"[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
goto out;
-
- KERNEL_LOCK();
}
- vm = p->p_vmspace;
- /* alas! must call the horrible vm code */
onfault = (vaddr_t)p->p_addr->u_pcb.pcb_onfault;
p->p_addr->u_pcb.pcb_onfault = NULL;
- rv = uvm_fault(&vm->vm_map, (vaddr_t)va, 0, access_type);
+ KERNEL_LOCK();
+ error = uvm_fault(&p->p_vmspace->vm_map, (vaddr_t)va, 0, access_type);
+ KERNEL_UNLOCK();
p->p_addr->u_pcb.pcb_onfault = (void *)onfault;
/*
@@ -811,58 +804,52 @@ data_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc,
* the current limit and we need to reflect that as an access
* error.
*/
- if (rv == 0)
+ if (error == 0) {
uvm_grow(p, va);
+ goto out;
+ }
- if (rv != 0) {
- /*
- * Pagein failed. If doing copyin/out, return to onfault
- * address. Any other page fault in kernel, die; if user
- * fault, deliver SIGSEGV.
- */
- int signal, sicode;
-
- if (tstate & TSTATE_PRIV) {
+ /*
+ * Pagein failed. If doing copyin/out, return to onfault
+ * address. Any other page fault in kernel, die; if user
+ * fault, deliver SIGSEGV.
+ */
+ if (tf->tf_tstate & TSTATE_PRIV) {
kfault:
- onfault = (long)p->p_addr->u_pcb.pcb_onfault;
- if (!onfault) {
- (void) splhigh();
- panic("kernel data fault: pc=%lx addr=%lx",
- pc, addr);
- /* NOTREACHED */
- }
- tf->tf_pc = onfault;
- tf->tf_npc = onfault + 4;
- KERNEL_UNLOCK();
- return;
- }
-
- if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0)
- sv.sival_ptr = (void *)va;
- else
- sv.sival_ptr = (void *)sfva;
-
- signal = SIGSEGV;
- sicode = SEGV_MAPERR;
- if (rv == ENOMEM) {
- printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
- p->p_p->ps_pid, p->p_p->ps_comm,
- p->p_ucred ? (int)p->p_ucred->cr_uid : -1);
- signal = SIGKILL;
- }
- if (rv == EACCES)
- sicode = SEGV_ACCERR;
- if (rv == EIO) {
- signal = SIGBUS;
- sicode = BUS_OBJERR;
+ onfault = (long)p->p_addr->u_pcb.pcb_onfault;
+ if (!onfault) {
+ (void) splhigh();
+ panic("kernel data fault: pc=%lx addr=%lx",
+ pc, addr);
+ /* NOTREACHED */
}
- trapsignal(p, signal, access_type, sicode, sv);
+ tf->tf_pc = onfault;
+ tf->tf_npc = onfault + 4;
+ return;
}
- KERNEL_UNLOCK();
+ if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0)
+ sv.sival_ptr = (void *)va;
+ else
+ sv.sival_ptr = (void *)sfva;
+
+ signal = SIGSEGV;
+ sicode = SEGV_MAPERR;
+ if (error == ENOMEM) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_p->ps_pid, p->p_p->ps_comm,
+ p->p_ucred ? (int)p->p_ucred->cr_uid : -1);
+ signal = SIGKILL;
+ } else if (error == EACCES)
+ sicode = SEGV_ACCERR;
+ else if (error == EIO) {
+ signal = SIGBUS;
+ sicode = BUS_OBJERR;
+ }
+ trapsignal(p, signal, access_type, sicode, sv);
out:
- if ((tstate & TSTATE_PRIV) == 0) {
+ if ((tf->tf_tstate & TSTATE_PRIV) == 0) {
userret(p);
share_fpu(p, tf);
}
@@ -879,18 +866,15 @@ void
data_access_error(struct trapframe64 *tf, unsigned type, vaddr_t afva,
u_long afsr, vaddr_t sfva, u_long sfsr)
{
+ struct proc *p = curproc;
u_long pc;
- u_int64_t tstate;
- struct proc *p;
vaddr_t onfault;
union sigval sv;
uvmexp.traps++;
- if ((p = curproc) == NULL) /* safety check */
+ if (p == NULL) /* safety check */
p = &proc0;
- tstate = tf->tf_tstate;
-
/*
* Catch PCI config space reads.
*/
@@ -901,19 +885,16 @@ data_access_error(struct trapframe64 *tf, unsigned type, vaddr_t afva,
pc = tf->tf_pc;
- sv.sival_ptr = (void *)pc;
-
onfault = (long)p->p_addr->u_pcb.pcb_onfault;
printf("data error type %x sfsr=%lx sfva=%lx afsr=%lx afva=%lx tf=%p\n",
- type, sfsr, sfva, afsr, afva, tf);
+ type, sfsr, sfva, afsr, afva, tf);
if (afsr == 0 && sfsr == 0) {
printf("data_access_error: no fault\n");
goto out; /* No fault. Why were we called? */
}
- if (tstate & TSTATE_PRIV) {
-
+ if (tf->tf_tstate & TSTATE_PRIV) {
if (!onfault) {
(void) splhigh();
panic("data fault: pc=%lx addr=%lx sfsr=%lb",
@@ -935,10 +916,11 @@ data_access_error(struct trapframe64 *tf, unsigned type, vaddr_t afva,
return;
}
+ sv.sival_ptr = (void *)pc;
trapsignal(p, SIGSEGV, PROT_READ | PROT_WRITE, SEGV_MAPERR, sv);
out:
- if ((tstate & TSTATE_PRIV) == 0) {
+ if ((tf->tf_tstate & TSTATE_PRIV) == 0) {
userret(p);
share_fpu(p, tf);
}
@@ -952,45 +934,34 @@ void
text_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc,
u_long sfsr)
{
- u_int64_t tstate;
- struct proc *p;
- struct vmspace *vm;
- vaddr_t va;
- int rv;
- vm_prot_t access_type;
+ struct proc *p = curproc;
+ vaddr_t va = trunc_page(pc);
+ vm_prot_t access_type = PROT_EXEC;
union sigval sv;
-
- sv.sival_ptr = (void *)pc;
+ int signal, sicode, error;
uvmexp.traps++;
- if ((p = curproc) == NULL) /* safety check */
+ if (p == NULL) /* safety check */
panic("text_access_fault: no curproc");
- tstate = tf->tf_tstate;
-
- va = trunc_page(pc);
-
- /* Now munch on protections... */
+ sv.sival_ptr = (void *)pc;
- access_type = PROT_EXEC;
- if (tstate & TSTATE_PRIV) {
+ if (tf->tf_tstate & TSTATE_PRIV) {
(void) splhigh();
panic("kernel text_access_fault: pc=%lx va=%lx", pc, va);
/* NOTREACHED */
- } else {
- p->p_md.md_tf = tf;
- refreshcreds(p);
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto out;
}
- KERNEL_LOCK();
+ p->p_md.md_tf = tf;
+ refreshcreds(p);
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
- vm = p->p_vmspace;
- /* alas! must call the horrible vm code */
- rv = uvm_fault(&vm->vm_map, va, 0, access_type);
+ KERNEL_LOCK();
+ error = uvm_fault(&p->p_vmspace->vm_map, va, 0, access_type);
+ KERNEL_UNLOCK();
/*
* If this was a stack access we keep track of the maximum
@@ -999,37 +970,33 @@ text_access_fault(struct trapframe64 *tf, unsigned type, vaddr_t pc,
* the current limit and we need to reflect that as an access
* error.
*/
- if (rv == 0)
+ if (error == 0) {
uvm_grow(p, va);
+ goto out;
+ }
- if (rv != 0) {
- /*
- * Pagein failed. Any other page fault in kernel, die; if user
- * fault, deliver SIGSEGV.
- */
- int signal, sicode;
-
- if (tstate & TSTATE_PRIV) {
- (void) splhigh();
- panic("kernel text fault: pc=%llx", (unsigned long long)pc);
- /* NOTREACHED */
- }
-
- signal = SIGSEGV;
- sicode = SEGV_MAPERR;
- if (rv == EACCES)
- sicode = SEGV_ACCERR;
- if (rv == EIO) {
- signal = SIGBUS;
- sicode = BUS_OBJERR;
- }
- trapsignal(p, signal, access_type, sicode, sv);
+ /*
+ * Pagein failed. Any other page fault in kernel, die; if user
+ * fault, deliver SIGSEGV.
+ */
+ if (tf->tf_tstate & TSTATE_PRIV) {
+ (void) splhigh();
+ panic("kernel text fault: pc=%llx", (unsigned long long)pc);
+ /* NOTREACHED */
}
- KERNEL_UNLOCK();
+ signal = SIGSEGV;
+ sicode = SEGV_MAPERR;
+ if (error == EACCES)
+ sicode = SEGV_ACCERR;
+ else if (error == EIO) {
+ signal = SIGBUS;
+ sicode = BUS_OBJERR;
+ }
+ trapsignal(p, signal, access_type, sicode, sv);
out:
- if ((tstate & TSTATE_PRIV) == 0) {
+ if ((tf->tf_tstate & TSTATE_PRIV) == 0) {
userret(p);
share_fpu(p, tf);
}
@@ -1047,27 +1014,24 @@ void
text_access_error(struct trapframe64 *tf, unsigned type, vaddr_t pc,
u_long sfsr, vaddr_t afva, u_long afsr)
{
- int64_t tstate;
- struct proc *p;
- struct vmspace *vm;
- vaddr_t va;
- int rv;
- vm_prot_t access_type;
+ struct proc *p = curproc;
+ vaddr_t va = trunc_page(pc);
+ vm_prot_t access_type = PROT_EXEC;
union sigval sv;
+ int signal, sicode, error;
- sv.sival_ptr = (void *)pc;
uvmexp.traps++;
- if ((p = curproc) == NULL) /* safety check */
+ if (p == NULL) /* safety check */
p = &proc0;
- tstate = tf->tf_tstate;
+ sv.sival_ptr = (void *)pc;
if ((afsr) != 0) {
printf("text_access_error: memory error...\n");
- printf("text memory error type %d sfsr=%lx sfva=%lx afsr=%lx afva=%lx tf=%p\n",
- type, sfsr, pc, afsr, afva, tf);
+ printf("type %d sfsr=%lx sfva=%lx afsr=%lx afva=%lx tf=%p\n",
+ type, sfsr, pc, afsr, afva, tf);
- if (tstate & TSTATE_PRIV)
+ if (tf->tf_tstate & TSTATE_PRIV)
panic("text_access_error: kernel memory error");
/* User fault -- Berr */
@@ -1077,29 +1041,23 @@ text_access_error(struct trapframe64 *tf, unsigned type, vaddr_t pc,
if ((sfsr & SFSR_FV) == 0 || (sfsr & SFSR_FT) == 0)
goto out; /* No fault. Why were we called? */
- va = trunc_page(pc);
-
- /* Now munch on protections... */
- access_type = PROT_EXEC;
- if (tstate & TSTATE_PRIV) {
+ if (tf->tf_tstate & TSTATE_PRIV) {
(void) splhigh();
panic("kernel text error: pc=%lx sfsr=%lb", pc,
sfsr, SFSR_BITS);
/* NOTREACHED */
- } else {
- p->p_md.md_tf = tf;
- refreshcreds(p);
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto out;
}
- KERNEL_LOCK();
+ p->p_md.md_tf = tf;
+ refreshcreds(p);
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
- vm = p->p_vmspace;
- /* alas! must call the horrible vm code */
- rv = uvm_fault(&vm->vm_map, va, 0, access_type);
+ KERNEL_LOCK();
+ error = uvm_fault(&p->p_vmspace->vm_map, va, 0, access_type);
+ KERNEL_UNLOCK();
/*
* If this was a stack access we keep track of the maximum
@@ -1108,39 +1066,35 @@ text_access_error(struct trapframe64 *tf, unsigned type, vaddr_t pc,
* the current limit and we need to reflect that as an access
* error.
*/
- if (rv == 0)
+ if (error == 0) {
uvm_grow(p, va);
+ goto out;
+ }
- if (rv != 0) {
- /*
- * Pagein failed. If doing copyin/out, return to onfault
- * address. Any other page fault in kernel, die; if user
- * fault, deliver SIGSEGV.
- */
- int signal, sicode;
-
- if (tstate & TSTATE_PRIV) {
- (void) splhigh();
- panic("kernel text error: pc=%lx sfsr=%lb", pc,
- sfsr, SFSR_BITS);
- /* NOTREACHED */
- }
-
- signal = SIGSEGV;
- sicode = SEGV_MAPERR;
- if (rv == EACCES)
- sicode = SEGV_ACCERR;
- if (rv == EIO) {
- signal = SIGBUS;
- sicode = BUS_OBJERR;
- }
- trapsignal(p, signal, access_type, sicode, sv);
+ /*
+ * Pagein failed. If doing copyin/out, return to onfault
+ * address. Any other page fault in kernel, die; if user
+ * fault, deliver SIGSEGV.
+ */
+ if (tf->tf_tstate & TSTATE_PRIV) {
+ (void) splhigh();
+ panic("kernel text error: pc=%lx sfsr=%lb", pc,
+ sfsr, SFSR_BITS);
+ /* NOTREACHED */
}
- KERNEL_UNLOCK();
+ signal = SIGSEGV;
+ sicode = SEGV_MAPERR;
+ if (error == EACCES)
+ sicode = SEGV_ACCERR;
+ else if (error == EIO) {
+ signal = SIGBUS;
+ sicode = BUS_OBJERR;
+ }
+ trapsignal(p, signal, access_type, sicode, sv);
out:
- if ((tstate & TSTATE_PRIV) == 0) {
+ if ((tf->tf_tstate & TSTATE_PRIV) == 0) {
userret(p);
share_fpu(p, tf);
}