浏览代码

microblaze: Fix MSR flags when returning from exception

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>
Michal Simek 9 年之前
父节点
当前提交
14ef905bb2
共有 1 个文件被更改,包括 13 次插入6 次删除
  1. 13 6
      arch/microblaze/kernel/entry.S

+ 13 - 6
arch/microblaze/kernel/entry.S

@@ -245,6 +245,13 @@ syscall_debug_table:
 	mts	rmsr , r11;						\
 	mts	rmsr , r11;						\
 	RESTORE_REGS_GP
 	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	\
 #define SAVE_STATE	\
 	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */	\
 	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */	\
 	/* See if already in kernel mode.*/				\
 	/* 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 */
 	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	VM_OFF;
 	tophys(r1,r1);
 	tophys(r1,r1);
-	RESTORE_REGS;
+	RESTORE_REGS_RTBD;
 	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
 	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
 	lwi	r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
 	lwi	r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
 	bri	6f;
 	bri	6f;
@@ -439,7 +446,7 @@ C_ENTRY(ret_from_trap):
 2:	set_bip;			/*  Ints masked for state restore */
 2:	set_bip;			/*  Ints masked for state restore */
 	VM_OFF;
 	VM_OFF;
 	tophys(r1,r1);
 	tophys(r1,r1);
-	RESTORE_REGS;
+	RESTORE_REGS_RTBD;
 	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
 	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
 	tovirt(r1,r1);
 	tovirt(r1,r1);
 6:
 6:
@@ -615,7 +622,7 @@ C_ENTRY(ret_from_exc):
 	VM_OFF;
 	VM_OFF;
 	tophys(r1,r1);
 	tophys(r1,r1);
 
 
-	RESTORE_REGS;
+	RESTORE_REGS_RTBD;
 	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
 	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
 
 
 	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
 	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 */
 2:	set_bip;			/* Ints masked for state restore */
 	VM_OFF;
 	VM_OFF;
 	tophys(r1,r1);
 	tophys(r1,r1);
-	RESTORE_REGS;
+	RESTORE_REGS_RTBD;
 	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
 	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
 
 
 	tovirt(r1,r1);
 	tovirt(r1,r1);
@@ -850,7 +857,7 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
 	VM_OFF;
 	VM_OFF;
 	tophys(r1,r1);
 	tophys(r1,r1);
 	/* MS: Restore all regs */
 	/* MS: Restore all regs */
-	RESTORE_REGS
+	RESTORE_REGS_RTBD
 	addik	r1, r1, PT_SIZE	 /* Clean up stack space */
 	addik	r1, r1, PT_SIZE	 /* Clean up stack space */
 	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
 	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
 DBTRAP_return_user: /* MS: Make global symbol for debugging */
 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;
 2:	VM_OFF;
 	tophys(r1,r1);
 	tophys(r1,r1);
 	/* MS: Restore all regs */
 	/* MS: Restore all regs */
-	RESTORE_REGS
+	RESTORE_REGS_RTBD
 	lwi	r14, r1, PT_R14;
 	lwi	r14, r1, PT_R14;
 	lwi	r16, r1, PT_PC;
 	lwi	r16, r1, PT_PC;
 	addik	r1, r1, PT_SIZE; /* MS: Clean up stack space */
 	addik	r1, r1, PT_SIZE; /* MS: Clean up stack space */