|
@@ -1377,6 +1377,7 @@ void facility_unavailable_exception(struct pt_regs *regs)
|
|
|
};
|
|
|
char *facility = "unknown";
|
|
|
u64 value;
|
|
|
+ u32 instword, rd;
|
|
|
u8 status;
|
|
|
bool hv;
|
|
|
|
|
@@ -1388,12 +1389,46 @@ void facility_unavailable_exception(struct pt_regs *regs)
|
|
|
|
|
|
status = value >> 56;
|
|
|
if (status == FSCR_DSCR_LG) {
|
|
|
- /* User is acessing the DSCR. Set the inherit bit and allow
|
|
|
- * the user to set it directly in future by setting via the
|
|
|
- * FSCR DSCR bit. We always leave HFSCR DSCR set.
|
|
|
+ /*
|
|
|
+ * User is accessing the DSCR register using the problem
|
|
|
+ * state only SPR number (0x03) either through a mfspr or
|
|
|
+ * a mtspr instruction. If it is a write attempt through
|
|
|
+ * a mtspr, then we set the inherit bit. This also allows
|
|
|
+ * the user to write or read the register directly in the
|
|
|
+ * future by setting via the FSCR DSCR bit. But in case it
|
|
|
+ * is a read DSCR attempt through a mfspr instruction, we
|
|
|
+ * just emulate the instruction instead. This code path will
|
|
|
+ * always emulate all the mfspr instructions till the user
|
|
|
+ * has attempted atleast one mtspr instruction. This way it
|
|
|
+ * preserves the same behaviour when the user is accessing
|
|
|
+ * the DSCR through privilege level only SPR number (0x11)
|
|
|
+ * which is emulated through illegal instruction exception.
|
|
|
+ * We always leave HFSCR DSCR set.
|
|
|
*/
|
|
|
- current->thread.dscr_inherit = 1;
|
|
|
- mtspr(SPRN_FSCR, value | FSCR_DSCR);
|
|
|
+ if (get_user(instword, (u32 __user *)(regs->nip))) {
|
|
|
+ pr_err("Failed to fetch the user instruction\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Write into DSCR (mtspr 0x03, RS) */
|
|
|
+ if ((instword & PPC_INST_MTSPR_DSCR_USER_MASK)
|
|
|
+ == PPC_INST_MTSPR_DSCR_USER) {
|
|
|
+ rd = (instword >> 21) & 0x1f;
|
|
|
+ current->thread.dscr = regs->gpr[rd];
|
|
|
+ current->thread.dscr_inherit = 1;
|
|
|
+ mtspr(SPRN_FSCR, value | FSCR_DSCR);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Read from DSCR (mfspr RT, 0x03) */
|
|
|
+ if ((instword & PPC_INST_MFSPR_DSCR_USER_MASK)
|
|
|
+ == PPC_INST_MFSPR_DSCR_USER) {
|
|
|
+ if (emulate_instruction(regs)) {
|
|
|
+ pr_err("DSCR based mfspr emulation failed\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ regs->nip += 4;
|
|
|
+ emulate_single_step(regs);
|
|
|
+ }
|
|
|
return;
|
|
|
}
|
|
|
|