Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 7 Jul 2010 12:04:57 +0000 (UTC)
From:      Juli Mallett <jmallett@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r209762 - user/jmallett/octeon/sys/mips/mips
Message-ID:  <201007071204.o67C4v6Q084114@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jmallett
Date: Wed Jul  7 12:04:56 2010
New Revision: 209762
URL: http://svn.freebsd.org/changeset/base/209762

Log:
  Simplify code some and correct a few bugs and omissions related to unaligned
  accesses.  There still seems to be something not quite right here, but this
  should fix problems related to useracc failing when the access could have been
  fixed up (due to always assuming word access width in useracc even for halfword
  unaligned accesses), as well as providing unaligned ld/sd fixup.

Modified:
  user/jmallett/octeon/sys/mips/mips/trap.c

Modified: user/jmallett/octeon/sys/mips/mips/trap.c
==============================================================================
--- user/jmallett/octeon/sys/mips/mips/trap.c	Wed Jul  7 12:00:11 2010	(r209761)
+++ user/jmallett/octeon/sys/mips/mips/trap.c	Wed Jul  7 12:04:56 2010	(r209762)
@@ -259,7 +259,7 @@ static int allow_unaligned_acc = 1;
 SYSCTL_INT(_vm, OID_AUTO, allow_unaligned_acc, CTLFLAG_RW,
     &allow_unaligned_acc, 0, "Allow unaligned accesses");
 
-static int emulate_unaligned_access(struct trapframe *frame);
+static int emulate_unaligned_access(struct trapframe *frame, int mode);
 
 extern void fswintrberr(void); /* XXX */
 
@@ -563,21 +563,9 @@ dofault:
 			else
 				mode = VM_PROT_WRITE;
 
-			/*
-			 * ADDR_ERR faults have higher priority than TLB
-			 * Miss faults.  Therefore, it is necessary to
-			 * verify that the faulting address is a valid
-			 * virtual address within the process' address space
-			 * before trying to emulate the unaligned access.
-			 */
-			if (useracc((caddr_t)
-			    (((vm_offset_t)trapframe->badvaddr) &
-			    ~(sizeof(int) - 1)), sizeof(int) * 2, mode)) {
-				access_type = emulate_unaligned_access(
-				    trapframe);
-				if (access_type != 0)
-					goto out;
-			}
+			access_type = emulate_unaligned_access(trapframe, mode);
+			if (access_type != 0)
+				goto out;
 		}
 		msg = "ADDRESS_ERR";
 
@@ -949,22 +937,9 @@ dofault:
 			else
 				mode = VM_PROT_WRITE;
 
-			/*
-			 * ADDR_ERR faults have higher priority than TLB
-			 * Miss faults.  Therefore, it is necessary to
-			 * verify that the faulting address is a valid
-			 * virtual address within the process' address space
-			 * before trying to emulate the unaligned access.
-			 */
-			if (useracc((caddr_t)
-			    (((vm_offset_t)trapframe->badvaddr) &
-			    ~(sizeof(int) - 1)), sizeof(int) * 2, mode)) {
-				access_type = emulate_unaligned_access(
-				    trapframe);
-				if (access_type != 0) {
-					return (trapframe->pc);
-				}
-			}
+			access_type = emulate_unaligned_access(trapframe, mode);
+			if (access_type != 0)
+				return (trapframe->pc);
 		}
 		/* FALLTHROUGH */
 
@@ -1429,76 +1404,120 @@ log_bad_page_fault(char *msg, struct tra
  * Unaligned load/store emulation
  */
 static int
-mips_unaligned_load_store(struct trapframe *frame, register_t addr, register_t pc)
+mips_unaligned_load_store(struct trapframe *frame, int mode, register_t addr, register_t pc)
 {
 	register_t *reg = (register_t *) frame;
 	u_int32_t inst = *((u_int32_t *)(intptr_t)pc);
-	u_int32_t value_msb, value;
-	int access_type = 0;
+	register_t value_msb, value;
+	unsigned size;
+
+	/*
+	 * ADDR_ERR faults have higher priority than TLB
+	 * Miss faults.  Therefore, it is necessary to
+	 * verify that the faulting address is a valid
+	 * virtual address within the process' address space
+	 * before trying to emulate the unaligned access.
+	 */
+	switch (MIPS_INST_OPCODE(inst)) {
+	case OP_LHU: case OP_LH:
+	case OP_SH:
+		size = 2;
+		break;
+	case OP_LWU: case OP_LW:
+	case OP_SW:
+		size = 4;
+		break;
+	case OP_LD:
+	case OP_SD:
+		size = 8;
+		break;
+	default:
+		printf("%s: unhandled opcode in address error: %#x\n", __func__, MIPS_INST_OPCODE(inst));
+		return (0);
+	}
 
+	if (!useracc((void *)((vm_offset_t)addr & ~(size - 1)), size * 2, mode))
+		return (0);
+
+	/*
+	 * XXX
+	 * Handle LL/SC LLD/SCD.
+	 */
 	switch (MIPS_INST_OPCODE(inst)) {
 	case OP_LHU:
+		KASSERT(mode == VM_PROT_READ, ("access mode must be read for load instruction."));
 		lbu_macro(value_msb, addr);
 		addr += 1;
 		lbu_macro(value, addr);
 		value |= value_msb << 8;
 		reg[MIPS_INST_RT(inst)] = value;
-		access_type = MIPS_LHU_ACCESS;
-		break;
+		return (MIPS_LHU_ACCESS);
 
 	case OP_LH:
+		KASSERT(mode == VM_PROT_READ, ("access mode must be read for load instruction."));
 		lb_macro(value_msb, addr);
 		addr += 1;
 		lbu_macro(value, addr);
 		value |= value_msb << 8;
 		reg[MIPS_INST_RT(inst)] = value;
-		access_type = MIPS_LH_ACCESS;
-		break;
+		return (MIPS_LH_ACCESS);
 
 	case OP_LWU:
+		KASSERT(mode == VM_PROT_READ, ("access mode must be read for load instruction."));
 		lwl_macro(value, addr);
 		addr += 3;
 		lwr_macro(value, addr);
 		value &= 0xffffffff;
 		reg[MIPS_INST_RT(inst)] = value;
-		access_type = MIPS_LWU_ACCESS;
-		break;
+		return (MIPS_LWU_ACCESS);
 
 	case OP_LW:
+		KASSERT(mode == VM_PROT_READ, ("access mode must be read for load instruction."));
 		lwl_macro(value, addr);
 		addr += 3;
 		lwr_macro(value, addr);
 		reg[MIPS_INST_RT(inst)] = value;
-		access_type = MIPS_LW_ACCESS;
-		break;
+		return (MIPS_LW_ACCESS);
+
+	case OP_LD:
+		KASSERT(mode == VM_PROT_READ, ("access mode must be read for load instruction."));
+		ldl_macro(value, addr);
+		addr += 7;
+		ldr_macro(value, addr);
+		reg[MIPS_INST_RT(inst)] = value;
+		return (MIPS_LD_ACCESS);
 
 	case OP_SH:
+		KASSERT(mode == VM_PROT_WRITE, ("access mode must be write for store instruction."));
 		value = reg[MIPS_INST_RT(inst)];
 		value_msb = value >> 8;
 		sb_macro(value_msb, addr);
 		addr += 1;
 		sb_macro(value, addr);
-		access_type = MIPS_SH_ACCESS;
-		break;
+		return (MIPS_SH_ACCESS);
 
 	case OP_SW:
+		KASSERT(mode == VM_PROT_WRITE, ("access mode must be write for store instruction."));
 		value = reg[MIPS_INST_RT(inst)];
 		swl_macro(value, addr);
 		addr += 3;
 		swr_macro(value, addr);
-		access_type = MIPS_SW_ACCESS;
-		break;
+		return (MIPS_SW_ACCESS);
 
-	default:
-		break;
+	case OP_SD:
+		KASSERT(mode == VM_PROT_WRITE, ("access mode must be write for store instruction."));
+		value = reg[MIPS_INST_RT(inst)];
+		sdl_macro(value, addr);
+		addr += 7;
+		sdr_macro(value, addr);
+		return (MIPS_SD_ACCESS);
 	}
-
-	return access_type;
+	panic("%s: should not be reached.", __func__);
 }
 
 
 static int
-emulate_unaligned_access(struct trapframe *frame)
+emulate_unaligned_access(struct trapframe *frame, int mode)
 {
 	register_t pc;
 	int access_type = 0;
@@ -1519,7 +1538,7 @@ emulate_unaligned_access(struct trapfram
 		 * Otherwise restore pc and fall through.
 		 */
 		access_type = mips_unaligned_load_store(frame,
-		    frame->badvaddr, pc);
+		    mode, frame->badvaddr, pc);
 
 		if (access_type) {
 			if (DELAYBRANCH(frame->cause))



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007071204.o67C4v6Q084114>