ppc64: handle exception 0x1500 (soft patch)

This change adds a hypervisor trap handler for exception 0x1500 (soft patch),
normalizing all VSX registers and returning.
This avoids a kernel panic due to unknown exception.

Change made with the collaboration of leonardo.bianconi_eldorado.org.br,
that found out that this is a hypervisor exception and not a supervisor one,
and fixed this in the code.

Reviewed by:	jhibbits, sbruno
Differential Revision:	https://reviews.freebsd.org/D17806
This commit is contained in:
Leandro Lupori 2018-12-10 14:54:28 +00:00
parent 457e6311ad
commit be2bd024de
4 changed files with 61 additions and 0 deletions

View File

@ -366,6 +366,7 @@ aim_cpu_init(vm_offset_t toc)
bcopy(&hypertrapcode, (void *)(EXC_HEA + trap_offset), trapsize);
bcopy(&hypertrapcode, (void *)(EXC_HMI + trap_offset), trapsize);
bcopy(&hypertrapcode, (void *)(EXC_HVI + trap_offset), trapsize);
bcopy(&hypertrapcode, (void *)(EXC_SOFT_PATCH + trap_offset), trapsize);
#endif
bcopy(&rstcode, (void *)(EXC_RST + trap_offset), (size_t)&rstcodeend -

View File

@ -103,6 +103,9 @@
#define EXC_SPFPD 0x2f30 /* SPE Floating-point Data */
#define EXC_SPFPR 0x2f40 /* SPE Floating-point Round */
/* POWER8 */
#define EXC_SOFT_PATCH 0x1500 /* POWER8 Soft Patch Exception */
#define EXC_LAST 0x2f00 /* Last possible exception vector */
#define EXC_AST 0x3000 /* Fake AST vector */

View File

@ -255,6 +255,7 @@ db_backtrace(struct thread *td, db_addr_t fp, int count)
case EXC_DECR: trapstr = "DECR"; break;
case EXC_PERF: trapstr = "PERF"; break;
case EXC_VSX: trapstr = "VSX"; break;
case EXC_SOFT_PATCH: trapstr = "SOFT_PATCH"; break;
default: trapstr = NULL; break;
}
if (trapstr != NULL) {

View File

@ -95,6 +95,7 @@ static void syscall(struct trapframe *frame);
void handle_kernel_slb_spill(int, register_t, register_t);
static int handle_user_slb_spill(pmap_t pm, vm_offset_t addr);
extern int n_slbs;
static void normalize_inputs(void);
#endif
extern vm_offset_t __startkernel;
@ -147,6 +148,7 @@ static struct powerpc_exception powerpc_exceptions[] = {
{ EXC_VECAST_G4, "altivec assist" },
{ EXC_THRM, "thermal management" },
{ EXC_RUNMODETRC, "run mode/trace" },
{ EXC_SOFT_PATCH, "soft patch exception" },
{ EXC_LAST, NULL }
};
@ -382,6 +384,17 @@ trap(struct trapframe *frame)
ucode = BUS_OBJERR;
break;
#if defined(__powerpc64__) && defined(AIM)
case EXC_SOFT_PATCH:
/*
* Point to the instruction that generated the exception to execute it again,
* and normalize the register values.
*/
frame->srr0 -= 4;
normalize_inputs();
break;
#endif
default:
trap_fatal(frame);
}
@ -909,6 +922,49 @@ fix_unaligned(struct thread *td, struct trapframe *frame)
return (-1);
}
#if defined(__powerpc64__) && defined(AIM)
#define MSKNSHL(x, m, n) "(((" #x ") & " #m ") << " #n ")"
#define MSKNSHR(x, m, n) "(((" #x ") & " #m ") >> " #n ")"
/* xvcpsgndp instruction, built in opcode format.
* This can be changed to use mnemonic after a toolchain update.
*/
#define XVCPSGNDP(xt, xa, xb) \
__asm __volatile(".long (" \
MSKNSHL(60, 0x3f, 26) " | " \
MSKNSHL(xt, 0x1f, 21) " | " \
MSKNSHL(xa, 0x1f, 16) " | " \
MSKNSHL(xb, 0x1f, 11) " | " \
MSKNSHL(240, 0xff, 3) " | " \
MSKNSHR(xa, 0x20, 3) " | " \
MSKNSHR(xa, 0x20, 4) " | " \
MSKNSHR(xa, 0x20, 5) ")")
/* Macros to normalize 1 or 10 VSX registers */
#define NORM(x) XVCPSGNDP(x, x, x)
#define NORM10(x) \
NORM(x ## 0); NORM(x ## 1); NORM(x ## 2); NORM(x ## 3); NORM(x ## 4); \
NORM(x ## 5); NORM(x ## 6); NORM(x ## 7); NORM(x ## 8); NORM(x ## 9)
static void
normalize_inputs(void)
{
unsigned long msr;
/* enable VSX */
msr = mfmsr();
mtmsr(msr | PSL_VSX);
NORM(0); NORM(1); NORM(2); NORM(3); NORM(4);
NORM(5); NORM(6); NORM(7); NORM(8); NORM(9);
NORM10(1); NORM10(2); NORM10(3); NORM10(4); NORM10(5);
NORM(60); NORM(61); NORM(62); NORM(63);
/* restore MSR */
mtmsr(msr);
}
#endif
#ifdef KDB
int
db_trap_glue(struct trapframe *frame)