microblaze: Fix MSR flags when returning from exception
authorMichal Simek <michal.simek@xilinx.com>
Wed, 24 Feb 2016 10:30:04 +0000 (11:30 +0100)
committerMichal Simek <michal.simek@xilinx.com>
Thu, 22 Jun 2017 13:37:00 +0000 (15:37 +0200)
The issue was that the service routine was sometimes
returning with the wrong flags set in the MSR.

In this case, EIP bit was set while returning to User Mode
which is an illegal combination since exceptions are always
handled in privileged mode.

In order for MicroBlaze to take an interrupt, the MSR must have IE=1,
BIP=0 and EIP=0.

Signed-off-by: Stefan Asserhall <stefana@xilinx.com>
Signed-off-by: Goran Bilski <goran@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
arch/microblaze/kernel/entry.S

index 285e8880e274df8ecfd209bf101cff1cbc5ff1f7..4e1b567becd6a86e6edfa7dc1c8d7bf6d82a4b18 100644 (file)
@@ -245,6 +245,13 @@ syscall_debug_table:
        mts     rmsr , r11;                                             \
        RESTORE_REGS_GP
 
+#define RESTORE_REGS_RTBD \
+       lwi     r11, r1, PT_MSR;                                        \
+       andni   r11, r11, MSR_EIP;          /* clear EIP */             \
+       ori     r11, r11, MSR_EE | MSR_BIP; /* set EE and BIP */        \
+       mts     rmsr , r11;                                             \
+       RESTORE_REGS_GP
+
 #define SAVE_STATE     \
        swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */     \
        /* See if already in kernel mode.*/                             \
@@ -430,7 +437,7 @@ C_ENTRY(ret_from_trap):
        swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
        VM_OFF;
        tophys(r1,r1);
-       RESTORE_REGS;
+       RESTORE_REGS_RTBD;
        addik   r1, r1, PT_SIZE         /* Clean up stack space.  */
        lwi     r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
        bri     6f;
@@ -439,7 +446,7 @@ C_ENTRY(ret_from_trap):
 2:     set_bip;                        /*  Ints masked for state restore */
        VM_OFF;
        tophys(r1,r1);
-       RESTORE_REGS;
+       RESTORE_REGS_RTBD;
        addik   r1, r1, PT_SIZE         /* Clean up stack space.  */
        tovirt(r1,r1);
 6:
@@ -615,7 +622,7 @@ C_ENTRY(ret_from_exc):
        VM_OFF;
        tophys(r1,r1);
 
-       RESTORE_REGS;
+       RESTORE_REGS_RTBD;
        addik   r1, r1, PT_SIZE         /* Clean up stack space.  */
 
        lwi     r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
@@ -624,7 +631,7 @@ C_ENTRY(ret_from_exc):
 2:     set_bip;                        /* Ints masked for state restore */
        VM_OFF;
        tophys(r1,r1);
-       RESTORE_REGS;
+       RESTORE_REGS_RTBD;
        addik   r1, r1, PT_SIZE         /* Clean up stack space.  */
 
        tovirt(r1,r1);
@@ -850,7 +857,7 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
        VM_OFF;
        tophys(r1,r1);
        /* MS: Restore all regs */
-       RESTORE_REGS
+       RESTORE_REGS_RTBD
        addik   r1, r1, PT_SIZE  /* Clean up stack space */
        lwi     r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
 DBTRAP_return_user: /* MS: Make global symbol for debugging */
@@ -861,7 +868,7 @@ DBTRAP_return_user: /* MS: Make global symbol for debugging */
 2:     VM_OFF;
        tophys(r1,r1);
        /* MS: Restore all regs */
-       RESTORE_REGS
+       RESTORE_REGS_RTBD
        lwi     r14, r1, PT_R14;
        lwi     r16, r1, PT_PC;
        addik   r1, r1, PT_SIZE; /* MS: Clean up stack space */