Commit d4bb2b8a authored by David Gibson's avatar David Gibson Committed by Linus Torvalds

[PATCH] ppc64: allow emulation of mfpvr on ppc64 kernel

Allow userspace programs on ppc64 to use the (privileged) mfpvr instruction
to determine the processor type.  At the moment it emulates the instruction
to provide the real PVR value, though it could be made to lie in future if
for some reason we wish to restrict what CPU features userspace uses.

If nothing else this means that some existing ppc32 applications will now
run on a 64-bit kernel (the 32-bit kernel has long supported this
emulation).  It will also be necessary for ppc64 perfctr support, where
userspace requires finer-grained cpu type information than the kernel in
order to correctly program the performance monitor control registers.
Signed-off-by: default avatarDavid Gibson <dwg@au1.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f49d1f28
......@@ -279,6 +279,9 @@ static void parse_fpe(struct pt_regs *regs)
* fault. Return zero on success.
*/
#define INST_MFSPR_PVR 0x7c1f42a6
#define INST_MFSPR_PVR_MASK 0xfc1fffff
#define INST_DCBA 0x7c0005ec
#define INST_DCBA_MASK 0x7c0007fe
......@@ -297,6 +300,15 @@ static int emulate_instruction(struct pt_regs *regs)
if (get_user(instword, (unsigned int __user *)(regs->nip)))
return -EFAULT;
/* Emulate the mfspr rD, PVR. */
if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
unsigned int rd;
rd = (instword >> 21) & 0x1f;
regs->gpr[rd] = mfspr(SPRN_PVR);
return 0;
}
/* Emulating the dcba insn is just a no-op. */
if ((instword & INST_DCBA_MASK) == INST_DCBA) {
static int warned;
......@@ -390,11 +402,6 @@ void program_check_exception(struct pt_regs *regs)
if (regs->msr & 0x100000) {
/* IEEE FP exception */
parse_fpe(regs);
} else if (regs->msr & 0x40000) {
/* Privileged instruction */
_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
} else if (regs->msr & 0x20000) {
/* trap exception */
......@@ -411,7 +418,7 @@ void program_check_exception(struct pt_regs *regs)
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
} else {
/* Illegal instruction; try to emulate it. */
/* Privileged or illegal instruction; try to emulate it. */
switch (emulate_instruction(regs)) {
case 0:
regs->nip += 4;
......@@ -423,7 +430,12 @@ void program_check_exception(struct pt_regs *regs)
break;
default:
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
if (regs->msr & 0x40000)
/* priveleged */
_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
else
/* illegal */
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
break;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment