[RFC,6/7] asm/head: provide asm support for interrupts to be returned from

Message ID 20180921080511.22026-7-npiggin@gmail.com
State New
Headers show
Series
  • virtual memory patches
Related show

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success master/apply_patch Successfully applied

Commit Message

Nicholas Piggin Sept. 21, 2018, 8:05 a.m.
This adds the redzone to the interrupt stack, and code to restore
registers.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 asm/asm-offsets.c |  6 ++++
 asm/head.S        | 83 +++++++++++++++++++++++++++++++++++------------
 core/exceptions.c |  5 ++-
 3 files changed, 73 insertions(+), 21 deletions(-)

Patch

diff --git a/asm/asm-offsets.c b/asm/asm-offsets.c
index 45f42436..85ead488 100644
--- a/asm/asm-offsets.c
+++ b/asm/asm-offsets.c
@@ -28,6 +28,11 @@ 
 #define OFFSET(sym, str, mem) \
 	DEFINE(sym, offsetof(struct str, mem))
 
+/*
+ * 64-bit BE ELF ABI specifies 288 byte redzone size.
+ */
+#define REDZONE_SIZE 288
+
 int main(void);
 
 int main(void)
@@ -95,6 +100,7 @@  int main(void)
 	OFFSET(STACK_HSRR1,	stack_frame, hsrr1);
 	OFFSET(STACK_DAR,	stack_frame, dar);
 	DEFINE(STACK_FRAMESIZE,	sizeof(struct stack_frame));
+	DEFINE(INT_FRAMESIZE,	(sizeof(struct stack_frame) + REDZONE_SIZE));
 
 	return 0;
 }
diff --git a/asm/head.S b/asm/head.S
index 7968bb69..9c2162c1 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -155,16 +155,32 @@  hdat_entry:
 
 	.= 0x1e00
 _exception:
-	stdu	%r1,-STACK_FRAMESIZE(%r1)
+	stdu	%r1,-INT_FRAMESIZE(%r1)
 	std	%r3,STACK_CFAR(%r1)
 	std	%r4,STACK_TYPE(%r1)
 	mfsprg0	%r3
 	mfsprg1 %r4
+	SAVE_GPR(3,%r1)
+	SAVE_GPR(4,%r1)
+	mfspr	%r3,SPR_SRR0
+	mfspr	%r4,SPR_SRR1
+	std	%r3,STACK_SRR0(%r1)
+	std	%r4,STACK_SRR1(%r1)
+	mfspr	%r3,SPR_DSISR
+	mfspr	%r4,SPR_DAR
+	stw	%r3,STACK_DSISR(%r1)
+	std	%r4,STACK_DAR(%r1)
+	mfmsr	%r3
+	ori	%r4,%r3,MSR_RI
+	mtmsrd	%r4,1
+	std	%r3,STACK_MSR(%r1)
+	mfspr	%r3,SPR_HSRR0
+	mfspr	%r4,SPR_HSRR1
+	std	%r3,STACK_HSRR0(%r1)
+	std	%r4,STACK_HSRR1(%r1)
 	SAVE_GPR(0,%r1)
 	SAVE_GPR(1,%r1)
 	SAVE_GPR(2,%r1)
-	SAVE_GPR(3,%r1)
-	SAVE_GPR(4,%r1)
 	SAVE_GPR(5,%r1)
 	SAVE_GPR(6,%r1)
 	SAVE_GPR(7,%r1)
@@ -200,29 +216,56 @@  _exception:
 	stw	%r4,STACK_XER(%r1)
 	std	%r5,STACK_CTR(%r1)
 	std	%r6,STACK_LR(%r1)
-	mfspr	%r3,SPR_SRR0
-	mfspr	%r4,SPR_SRR1
-	mfspr	%r5,SPR_HSRR0
-	mfspr	%r6,SPR_HSRR1
-	std	%r3,STACK_SRR0(%r1)
-	std	%r4,STACK_SRR1(%r1)
-	std	%r5,STACK_HSRR0(%r1)
-	std	%r6,STACK_HSRR1(%r1)
-	mfspr	%r3,SPR_DSISR
-	mfspr	%r4,SPR_DAR
-	mfmsr	%r5
-	stw	%r3,STACK_DSISR(%r1)
-	std	%r4,STACK_DAR(%r1)
-	std	%r5,STACK_MSR(%r1)
 	mr	%r3,%r1
 	LOAD_IMM64(%r4, SKIBOOT_BASE)
 	LOAD_IMM32(%r5, exception_entry_foo - __head)
 	add	%r4,%r4,%r5
 	mtctr	%r4
-	bctrl
-	b	.
+	bctr
 exception_entry_foo:
-	b	exception_entry
+	bl	exception_entry
+	lwz	%r3,STACK_CR(%r1)
+	lwz	%r4,STACK_XER(%r1)
+	ld	%r5,STACK_CTR(%r1)
+	ld	%r6,STACK_LR(%r1)
+	mtcr	%r3
+	mtxer	%r4
+	mtctr	%r5
+	mtlr	%r6
+	REST_GPR(0,%r1)
+	REST_GPR(2,%r1)
+	REST_GPR(3,%r1)
+	REST_GPR(4,%r1)
+	REST_GPR(5,%r1)
+	REST_GPR(6,%r1)
+	REST_GPR(7,%r1)
+	REST_GPR(8,%r1)
+	REST_GPR(9,%r1)
+	REST_GPR(10,%r1)
+	REST_GPR(11,%r1)
+	REST_GPR(12,%r1)
+	REST_GPR(13,%r1)
+	REST_GPR(14,%r1)
+	REST_GPR(15,%r1)
+	REST_GPR(16,%r1)
+	REST_GPR(17,%r1)
+	REST_GPR(18,%r1)
+	REST_GPR(19,%r1)
+	REST_GPR(20,%r1)
+	REST_GPR(21,%r1)
+	REST_GPR(22,%r1)
+	REST_GPR(23,%r1)
+	REST_GPR(24,%r1)
+	REST_GPR(25,%r1)
+	REST_GPR(26,%r1)
+	REST_GPR(27,%r1)
+	REST_GPR(28,%r1)
+	REST_GPR(29,%r1)
+	REST_GPR(30,%r1)
+	REST_GPR(31,%r1)
+	addi	%r1,%r1,INT_FRAMESIZE
+	hrfid
+	b	.
 
 	.= EXCEPTION_VECTORS_END
 	/* This is the OPAL branch table. It's populated at boot time
diff --git a/core/exceptions.c b/core/exceptions.c
index be701f0f..e205ac6e 100644
--- a/core/exceptions.c
+++ b/core/exceptions.c
@@ -40,7 +40,7 @@  static void dump_regs(struct stack_frame *stack)
 }
 
 /* Called from head.S, thus no prototype */
-void exception_entry(struct stack_frame *stack) __noreturn;
+void exception_entry(struct stack_frame *stack);
 
 void exception_entry(struct stack_frame *stack)
 {
@@ -66,6 +66,9 @@  void exception_entry(struct stack_frame *stack)
 	default:
 		nip = stack->srr0;
 		msr = stack->srr1;
+		/* Set up to allow hrfid return */
+		mtspr(SPR_HSRR0, nip);
+		mtspr(SPR_HSRR1, msr);
 		break;
 	}