[RFC][PATCH] kernel relocation for KVM exceptions
Nicholas Piggin
npiggin at gmail.com
Thu Oct 13 14:08:24 AEDT 2016
Hi Paul,
I wonder what you think about this approach for applying relocation to KVM
exceptions? It's not yet tested and I haven't attempted PR, but I'll keep
at it if you think it's the right direction.
The relocation branch requires ctr, but we can get away without more scratch
storage by putting trap and cr in one register.
On the other hand, that's going to make the calling convention diverge even
more for 32-bit, so perhaps it's being overly complex and you'd rather add
another scratch save for CONFIG_RELOCATABLE? Other ideas?
Thanks,
Nick
---
arch/powerpc/include/asm/exception-64s.h | 63 ++++++++++++++++++++++++++------
arch/powerpc/kernel/exceptions-64s.S | 4 +-
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 18 +++++----
3 files changed, 65 insertions(+), 20 deletions(-)
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 84d49b1..466870f 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -97,6 +97,11 @@
ld reg,PACAKBASE(r13); \
ori reg,reg,(ABS_ADDR(label))@l;
+#define __LOAD_FAR_HANDLER(reg, label) \
+ ld reg,PACAKBASE(r13); \
+ ori reg,reg,(ABS_ADDR(label))@l; \
+ addis reg,reg,(ABS_ADDR(label))@h;
+
/* Exception register prefixes */
#define EXC_HV H
#define EXC_STD
@@ -218,12 +223,43 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
mtctr reg; \
bctr
+/*
+ * KVM requires a far (>64K) branch, and to set the exit number in r12
+ * when branching from an exception
+ */
+#define BRANCH_TO_KVM_EXIT(reg, label) \
+ mfctr reg; \
+ std reg,HSTATE_SCRATCH2(r13); \
+ __LOAD_FAR_HANDLER(reg, label); \
+ mtctr reg; \
+ bctr
+
+#define BRANCH_TO_KVM(reg, label) \
+ __LOAD_FAR_HANDLER(reg, label); \
+ mtctr reg; \
+ bctr
+
+#define BRANCH_LINK_TO_KVM(reg, label) \
+ __LOAD_FAR_HANDLER(reg, label); \
+ mtctr reg; \
+ bctrl
+
#else
#define BRANCH_TO_COMMON(reg, label) \
b label
+#define BRANCH_TO_KVM(reg, label) \
+ b label
+
+#define BRANCH_TO_KVM_EXIT(reg, label) \
+ b label
+
+#define BRANCH_LINK_TO_KVM(reg, label) \
+ b label
+
#endif
+
#define __KVM_HANDLER_PROLOG(area, n) \
BEGIN_FTR_SECTION_NESTED(947) \
ld r10,area+EX_CFAR(r13); \
@@ -234,30 +270,35 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
std r10,HSTATE_PPR(r13); \
END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,948); \
ld r10,area+EX_R10(r13); \
- stw r9,HSTATE_SCRATCH1(r13); \
- ld r9,area+EX_R9(r13); \
std r12,HSTATE_SCRATCH0(r13); \
+ li r12,(n); \
+ sldi r12,r12,32; \
+ ori r12,r12,r9; \
+ ld r9,area+EX_R9(r13); \
+ std r9,HSTATE_SCRATCH1(r13); \
#define __KVM_HANDLER(area, h, n) \
__KVM_HANDLER_PROLOG(area, n) \
- li r12,n; \
- b kvmppc_interrupt
+ BRANCH_TO_KVM_EXIT(r9, kvmppc_interrupt)
#define __KVM_HANDLER_SKIP(area, h, n) \
cmpwi r10,KVM_GUEST_MODE_SKIP; \
- ld r10,area+EX_R10(r13); \
beq 89f; \
- stw r9,HSTATE_SCRATCH1(r13); \
BEGIN_FTR_SECTION_NESTED(948) \
- ld r9,area+EX_PPR(r13); \
- std r9,HSTATE_PPR(r13); \
+ ld r10,area+EX_PPR(r13); \
+ std r0,HSTATE_PPR(r13); \
END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,948); \
- ld r9,area+EX_R9(r13); \
+ ld r10,area+EX_R10(r13); \
std r12,HSTATE_SCRATCH0(r13); \
- li r12,n; \
- b kvmppc_interrupt; \
+ li r12,(n); \
+ sldi r12,r12,32; \
+ ori r12,r12,r9; \
+ ld r9,area+EX_R9(r13); \
+ std r9,HSTATE_SCRATCH1(r13); \
+ BRANCH_TO_KVM_EXIT(r9, kvmppc_interrupt); \
89: mtocrf 0x80,r9; \
ld r9,area+EX_R9(r13); \
+ ld r10,area+EX_R10(r13); \
b kvmppc_skip_##h##interrupt
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index e680e84..81c3a63 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -137,7 +137,7 @@ EXC_COMMON_BEGIN(system_reset_idle_common)
lbz r0,HSTATE_HWTHREAD_REQ(r13)
cmpwi r0,0
beq 1f
- b kvm_start_guest
+ BRANCH_TO_KVM(r10, kvm_start_guest)
1:
#endif
@@ -974,7 +974,7 @@ TRAMP_REAL_BEGIN(hmi_exception_early)
EXCEPTION_PROLOG_COMMON_2(PACA_EXGEN)
EXCEPTION_PROLOG_COMMON_3(0xe60)
addi r3,r1,STACK_FRAME_OVERHEAD
- bl hmi_exception_realmode
+ BRANCH_LINK_TO_KVM(r4, hmi_exception_realmode)
/* Windup the stack. */
/* Move original HSRR0 and HSRR1 into the respective regs */
ld r9,_MSR(r1)
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index c3c1d1b..824e87a 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -1043,19 +1043,23 @@ hdec_soon:
kvmppc_interrupt_hv:
/*
* Register contents:
- * R12 = interrupt vector
+ * R12 = (interrupt vector << 32) | guest CR
* R13 = PACA
- * guest CR, R12 saved in shadow VCPU SCRATCH1/0
+ * guest R12, R9 saved in shadow VCPU SCRATCH0/1 respectively
+ * guest CTR saved in shadow VCPU SCRATCH2 if RELOCATABLE
* guest R13 saved in SPRN_SCRATCH0
*/
- std r9, HSTATE_SCRATCH2(r13)
+#ifdef CONFIG_RELOCATABLE
+ ld r9, HSTATE_SCRATCH2(r13)
+ mfctr r9
+#endif
lbz r9, HSTATE_IN_GUEST(r13)
cmpwi r9, KVM_GUEST_MODE_HOST_HV
beq kvmppc_bad_host_intr
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
cmpwi r9, KVM_GUEST_MODE_GUEST
- ld r9, HSTATE_SCRATCH2(r13)
+ ld r9, HSTATE_SCRATCH1(r13)
beq kvmppc_interrupt_pr
#endif
/* We're now back in the host but in guest MMU context */
@@ -1075,14 +1079,13 @@ kvmppc_interrupt_hv:
std r6, VCPU_GPR(R6)(r9)
std r7, VCPU_GPR(R7)(r9)
std r8, VCPU_GPR(R8)(r9)
- ld r0, HSTATE_SCRATCH2(r13)
+ ld r0, HSTATE_SCRATCH1(r13)
std r0, VCPU_GPR(R9)(r9)
std r10, VCPU_GPR(R10)(r9)
std r11, VCPU_GPR(R11)(r9)
ld r3, HSTATE_SCRATCH0(r13)
- lwz r4, HSTATE_SCRATCH1(r13)
std r3, VCPU_GPR(R12)(r9)
- stw r4, VCPU_CR(r9)
+ stw r12, VCPU_CR(r9) /* CR is in the low half of r12 */
BEGIN_FTR_SECTION
ld r3, HSTATE_CFAR(r13)
std r3, VCPU_CFAR(r9)
@@ -1100,6 +1103,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
mfspr r11, SPRN_SRR1
std r10, VCPU_SRR0(r9)
std r11, VCPU_SRR1(r9)
+ srdi r12, r12, 32 /* trap is in the high half of r12 */
andi. r0, r12, 2 /* need to read HSRR0/1? */
beq 1f
mfspr r10, SPRN_HSRR0
--
2.9.3
More information about the Linuxppc-dev
mailing list