Skip to contentSkip to conversation

Patch "arm/arm64: KVM: set right LR register value for 32 bit guest when inject abort" has been added to the 4.9-stable tree

PATCH [email protected] 1 participant 1 message Nov 5, 2017

Subsystems (4)
lore
Share & tools
lore

[email protected]

author maintainer Applied
#0 lore raw

This is a note to let you know that I've just added the patch titled

arm/arm64: KVM: set right LR register value for 32 bit guest when inject abort

to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
arm-arm64-kvm-set-right-lr-register-value-for-32-bit-guest-when-inject-abort.patch
and it can be found in the queue-4.9 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.

Quoted 1 line

From fd6c8c206fc5d0717b0433b191de0715122f33bb Mon Sep 17 00:00:00 2001

From: Dongjiu Geng <[email protected]>
Date: Tue, 17 Oct 2017 22:23:49 +0800
Subject: arm/arm64: KVM: set right LR register value for 32 bit guest when inject abort

From: Dongjiu Geng <[email protected]>

commit fd6c8c206fc5d0717b0433b191de0715122f33bb upstream.

When a exception is trapped to EL2, hardware uses ELR_ELx to hold the current fault instruction address. If KVM wants to inject a abort to 32 bit guest, it needs to set the LR register for the guest to emulate this abort happened in the guest. Because ARM32 architecture is pipelined execution, so the LR value has an offset to the fault instruction address.

The offsets applied to Link value for exceptions as shown below, which should be added for the ARM32 link register(LR).

Table taken from ARMv8 ARM DDI0487B-B, table G1-10:
Exception Offset, for PE state of:

				A32 	  T32

Undefined Instruction +4 +2
Prefetch Abort +4 +4
Data Abort +8 +8
IRQ or FIQ +4 +4

[ Removed unused variables in inject_abt to avoid compile warnings.
-- Christoffer ]

---
 arch/arm/kvm/emulate.c        |    6 ++----
 arch/arm64/kvm/inject_fault.c |   16 +++++++++++++++-
 2 files changed, 17 insertions(+), 5 deletions(-)
arch/arm/kvm/emulate.c +2 -4
@@ -227,7 +227,7 @@ void kvm_inject_undefined(struct kvm_vcp
 	u32 return_offset = (is_thumb) ? 2 : 4;
 
 	kvm_update_psr(vcpu, UND_MODE);
-	*vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) - return_offset;
+	*vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
 
 	/* Branch to exception vector */
 	*vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset;
@@ -239,10 +239,8 @@ void kvm_inject_undefined(struct kvm_vcp
  */
 static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr)
 {
-	unsigned long cpsr = *vcpu_cpsr(vcpu);
-	bool is_thumb = (cpsr & PSR_T_BIT);
 	u32 vect_offset;
-	u32 return_offset = (is_thumb) ? 4 : 0;
+	u32 return_offset = (is_pabt) ? 4 : 8;
 	bool is_lpae;
 
 	kvm_update_psr(vcpu, ABT_MODE);
arch/arm64/kvm/inject_fault.c +15 -1
@@ -33,12 +33,26 @@
 #define LOWER_EL_AArch64_VECTOR		0x400
 #define LOWER_EL_AArch32_VECTOR		0x600
 
+/*
+ * Table taken from ARMv8 ARM DDI0487B-B, table G1-10.
+ */
+static const u8 return_offsets[8][2] = {
+	[0] = { 0, 0 },		/* Reset, unused */
+	[1] = { 4, 2 },		/* Undefined */
+	[2] = { 0, 0 },		/* SVC, unused */
+	[3] = { 4, 4 },		/* Prefetch abort */
+	[4] = { 8, 8 },		/* Data abort */
+	[5] = { 0, 0 },		/* HVC, unused */
+	[6] = { 4, 4 },		/* IRQ, unused */
+	[7] = { 4, 4 },		/* FIQ, unused */
+};
+
 static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
 {
 	unsigned long cpsr;
 	unsigned long new_spsr_value = *vcpu_cpsr(vcpu);
 	bool is_thumb = (new_spsr_value & COMPAT_PSR_T_BIT);
-	u32 return_offset = (is_thumb) ? 4 : 0;
+	u32 return_offset = return_offsets[vect_offset >> 2][is_thumb];
 	u32 sctlr = vcpu_cp15(vcpu, c1_SCTLR);
 
 	cpsr = mode | COMPAT_PSR_I_BIT;

Patches currently in stable-queue which might be from [email protected] are

queue-4.9/arm-arm64-kvm-set-right-lr-register-value-for-32-bit-guest-when-inject-abort.patch