summaryrefslogtreecommitdiff
path: root/sys/arch/mips64
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2017-08-26 15:21:49 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2017-08-26 15:21:49 +0000
commit457ce13dc17c7a6f9297ed6a2608838292128c4f (patch)
tree20088f2adce0afe854aacab85eefbbfe88923d5a /sys/arch/mips64
parent1df2b32a9e6308e38c72697b3eac01c533bbe4ab (diff)
Use copyin32() instead of a direct memory load when fetching a branch
instruction for branch emulation. This ensures the userspace memory access is properly guarded and that TLB faults are handled. In order not to complicate the interface of MipsEmulateBranch(), each caller now has to provide the branch instruction for the function. Feedback from miod@
Diffstat (limited to 'sys/arch/mips64')
-rw-r--r--sys/arch/mips64/mips64/db_machdep.c8
-rw-r--r--sys/arch/mips64/mips64/fp_emulate.c15
-rw-r--r--sys/arch/mips64/mips64/trap.c74
3 files changed, 73 insertions, 24 deletions
diff --git a/sys/arch/mips64/mips64/db_machdep.c b/sys/arch/mips64/mips64/db_machdep.c
index 41299aa5740..1c620160023 100644
--- a/sys/arch/mips64/mips64/db_machdep.c
+++ b/sys/arch/mips64/mips64/db_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: db_machdep.c,v 1.47 2016/09/19 17:59:19 jasper Exp $ */
+/* $OpenBSD: db_machdep.c,v 1.48 2017/08/26 15:21:48 visa Exp $ */
/*
* Copyright (c) 1998-2003 Opsycon AB (www.opsycon.se)
@@ -358,9 +358,11 @@ db_addr_t
next_instr_address(db_addr_t pc, boolean_t bd)
{
db_addr_t next;
+ uint32_t instr;
- next = MipsEmulateBranch(&ddb_regs, (vaddr_t)pc, 0, 0);
- return(next);
+ instr = kdbpeek(pc);
+ next = MipsEmulateBranch(&ddb_regs, (vaddr_t)pc, 0, instr);
+ return (next);
}
/*
diff --git a/sys/arch/mips64/mips64/fp_emulate.c b/sys/arch/mips64/mips64/fp_emulate.c
index 50251be956f..f6bee8e04c6 100644
--- a/sys/arch/mips64/mips64/fp_emulate.c
+++ b/sys/arch/mips64/mips64/fp_emulate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fp_emulate.c,v 1.15 2017/01/21 05:42:03 guenther Exp $ */
+/* $OpenBSD: fp_emulate.c,v 1.16 2017/08/26 15:21:48 visa Exp $ */
/*
* Copyright (c) 2010 Miodrag Vallat.
@@ -134,6 +134,7 @@ MipsFPTrap(struct trapframe *tf)
union sigval sv;
vaddr_t pc;
uint32_t fsr, excbits;
+ uint32_t branch = 0;
uint32_t insn;
InstFmt inst;
int sig = 0;
@@ -194,6 +195,15 @@ MipsFPTrap(struct trapframe *tf)
}
inst = *(InstFmt *)&insn;
+ if (tf->cause & CR_BR_DELAY) {
+ if (copyin32((const void *)tf->pc, &branch) != 0) {
+ sig = SIGBUS;
+ fault_type = BUS_OBJERR;
+ sv.sival_ptr = (void *)tf->pc;
+ goto deliver;
+ }
+ }
+
/*
* Emulate the instruction.
*/
@@ -366,7 +376,8 @@ deliver:
* only used to decide whether to branch or not
* if the faulting instruction was BC1[FT].
*/
- tf->pc = MipsEmulateBranch(tf, tf->pc, fsr, 0);
+ tf->pc = MipsEmulateBranch(tf, tf->pc, fsr,
+ branch);
} else
tf->pc += 4;
}
diff --git a/sys/arch/mips64/mips64/trap.c b/sys/arch/mips64/mips64/trap.c
index f01bff0c8a7..9e2980dd18b 100644
--- a/sys/arch/mips64/mips64/trap.c
+++ b/sys/arch/mips64/mips64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.127 2017/07/22 18:33:51 visa Exp $ */
+/* $OpenBSD: trap.c,v 1.128 2017/08/26 15:21:48 visa Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@@ -465,6 +465,7 @@ fault_common_no_miss:
struct sysent *callp;
unsigned int code;
register_t tpc;
+ uint32_t branch = 0;
int error, numarg, numsys;
struct args {
register_t i[8];
@@ -475,10 +476,17 @@ fault_common_no_miss:
/* compute next PC after syscall instruction */
tpc = trapframe->pc; /* Remember if restart */
- if (trapframe->cause & CR_BR_DELAY)
+ if (trapframe->cause & CR_BR_DELAY) {
+ /* Get the branch instruction. */
+ if (copyin32((const void *)locr0->pc, &branch) != 0) {
+ signal = SIGBUS;
+ sicode = BUS_OBJERR;
+ break;
+ }
+
locr0->pc = MipsEmulateBranch(locr0,
- trapframe->pc, 0, 0);
- else
+ trapframe->pc, 0, branch);
+ } else
locr0->pc += 4;
callp = p->p_p->ps_emul->e_sysent;
numsys = p->p_p->ps_emul->e_nsysent;
@@ -578,15 +586,25 @@ fault_common_no_miss:
case T_BREAK+T_USER:
{
- caddr_t va;
- u_int32_t instr;
struct trapframe *locr0 = p->p_md.md_regs;
+ caddr_t va;
+ uint32_t branch = 0;
+ uint32_t instr;
/* compute address of break instruction */
va = (caddr_t)trapframe->pc;
- if (trapframe->cause & CR_BR_DELAY)
+ if (trapframe->cause & CR_BR_DELAY) {
va += 4;
+ /* Read branch instruction. */
+ if (copyin32((const void *)trapframe->pc,
+ &branch) != 0) {
+ signal = SIGBUS;
+ sicode = BUS_OBJERR;
+ break;
+ }
+ }
+
/* read break instruction */
copyin(va, &instr, sizeof(int32_t));
@@ -597,7 +615,7 @@ fault_common_no_miss:
/* skip instruction */
if (trapframe->cause & CR_BR_DELAY)
locr0->pc = MipsEmulateBranch(locr0,
- trapframe->pc, 0, 0);
+ trapframe->pc, 0, branch);
else
locr0->pc += 4;
break;
@@ -607,7 +625,7 @@ fault_common_no_miss:
/* skip instruction */
if (trapframe->cause & CR_BR_DELAY)
locr0->pc = MipsEmulateBranch(locr0,
- trapframe->pc, 0, 0);
+ trapframe->pc, 0, branch);
else
locr0->pc += 4;
break;
@@ -685,20 +703,31 @@ fault_common_no_miss:
case T_TRAP+T_USER:
{
- caddr_t va;
- u_int32_t instr;
struct trapframe *locr0 = p->p_md.md_regs;
+ caddr_t va;
+ uint32_t branch = 0;
+ uint32_t instr;
/* compute address of trap instruction */
va = (caddr_t)trapframe->pc;
- if (trapframe->cause & CR_BR_DELAY)
+ if (trapframe->cause & CR_BR_DELAY) {
va += 4;
+
+ /* Read branch instruction. */
+ if (copyin32((const void *)trapframe->pc,
+ &branch) != 0) {
+ signal = SIGBUS;
+ sicode = BUS_OBJERR;
+ break;
+ }
+ }
+
/* read break instruction */
copyin(va, &instr, sizeof(int32_t));
if (trapframe->cause & CR_BR_DELAY)
locr0->pc = MipsEmulateBranch(locr0,
- trapframe->pc, 0, 0);
+ trapframe->pc, 0, branch);
else
locr0->pc += 4;
/*
@@ -721,13 +750,23 @@ fault_common_no_miss:
{
register_t *regs = (register_t *)trapframe;
caddr_t va;
+ uint32_t branch = 0;
InstFmt inst;
/* Compute the instruction's address. */
va = (caddr_t)trapframe->pc;
- if (trapframe->cause & CR_BR_DELAY)
+ if (trapframe->cause & CR_BR_DELAY) {
va += 4;
+ /* Get the branch instruction. */
+ if (copyin32((const void *)trapframe->pc,
+ &branch) != 0) {
+ signal = SIGBUS;
+ sicode = BUS_OBJERR;
+ break;
+ }
+ }
+
/* Get the faulting instruction. */
if (copyin32((void *)va, &inst.word) != 0) {
signal = SIGBUS;
@@ -746,7 +785,7 @@ fault_common_no_miss:
/* Figure out where to continue. */
if (trapframe->cause & CR_BR_DELAY)
trapframe->pc = MipsEmulateBranch(trapframe,
- trapframe->pc, 0, 0);
+ trapframe->pc, 0, branch);
else
trapframe->pc += 4;
return;
@@ -951,10 +990,7 @@ MipsEmulateBranch(struct trapframe *tf, vaddr_t instPC, uint32_t fsr,
#define GetBranchDest(InstPtr, inst) \
(InstPtr + 4 + ((short)inst.IType.imm << 2))
- if (curinst != 0)
- inst = *(InstFmt *)&curinst;
- else
- inst = *(InstFmt *)instPC;
+ inst.word = curinst;
regsPtr[ZERO] = 0; /* Make sure zero is 0x0 */