[PATCH v3 3/6] arm: KVM: Invalidate BTB on guest exit for Cortex-A12/A17

Marc Zyngier marc.zyngier at arm.com
Wed Jan 31 04:11:57 PST 2018


Hi Robin,

On 26/01/18 17:12, Robin Murphy wrote:
> On 25/01/18 15:21, Marc Zyngier wrote:
>> In order to avoid aliasing attacks against the branch predictor,
>> let's invalidate the BTB on guest exit. This is made complicated
>> by the fact that we cannot take a branch before invalidating the
>> BTB.
>>
>> We only apply this to A12 and A17, which are the only two ARM
>> cores on which this useful.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
>> ---
>>   arch/arm/include/asm/kvm_asm.h |  2 --
>>   arch/arm/include/asm/kvm_mmu.h | 13 ++++++++-
>>   arch/arm/kvm/hyp/hyp-entry.S   | 62 ++++++++++++++++++++++++++++++++++++++++--
>>   3 files changed, 72 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
>> index 36dd2962a42d..df24ed48977d 100644
>> --- a/arch/arm/include/asm/kvm_asm.h
>> +++ b/arch/arm/include/asm/kvm_asm.h
>> @@ -61,8 +61,6 @@ struct kvm_vcpu;
>>   extern char __kvm_hyp_init[];
>>   extern char __kvm_hyp_init_end[];
>>   
>> -extern char __kvm_hyp_vector[];
>> -
>>   extern void __kvm_flush_vm_context(void);
>>   extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
>>   extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
>> diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
>> index eb46fc81a440..b47db5b9e407 100644
>> --- a/arch/arm/include/asm/kvm_mmu.h
>> +++ b/arch/arm/include/asm/kvm_mmu.h
>> @@ -37,6 +37,7 @@
>>   
>>   #include <linux/highmem.h>
>>   #include <asm/cacheflush.h>
>> +#include <asm/cputype.h>
>>   #include <asm/pgalloc.h>
>>   #include <asm/stage2_pgtable.h>
>>   
>> @@ -223,7 +224,17 @@ static inline unsigned int kvm_get_vmid_bits(void)
>>   
>>   static inline void *kvm_get_hyp_vector(void)
>>   {
>> -	return kvm_ksym_ref(__kvm_hyp_vector);
>> +	extern char __kvm_hyp_vector[];
>> +	extern char __kvm_hyp_vector_bp_inv[];
>> +
>> +	switch(read_cpuid_part()) {
>> +	case ARM_CPU_PART_CORTEX_A12:
>> +	case ARM_CPU_PART_CORTEX_A17:
>> +		return kvm_ksym_ref(__kvm_hyp_vector_bp_inv);
>> +
>> +	default:
>> +		return kvm_ksym_ref(__kvm_hyp_vector);
>> +	}
>>   }
>>   
>>   static inline int kvm_map_vectors(void)
>> diff --git a/arch/arm/kvm/hyp/hyp-entry.S b/arch/arm/kvm/hyp/hyp-entry.S
>> index 95a2faefc070..aab6b0c06a19 100644
>> --- a/arch/arm/kvm/hyp/hyp-entry.S
>> +++ b/arch/arm/kvm/hyp/hyp-entry.S
>> @@ -70,6 +70,57 @@ __kvm_hyp_vector:
>>   	W(b)	hyp_hvc
>>   	W(b)	hyp_irq
>>   	W(b)	hyp_fiq
>> +	
>> +	.align 5
>> +__kvm_hyp_vector_bp_inv:
>> +	.global __kvm_hyp_vector_bp_inv
>> +
>> +	/*
>> +	 * We encode the exception entry in the bottom 3 bits of
>> +	 * SP, and we have to guarantee to be 8 bytes aligned.
>> +	 */
>> +	W(add)	sp, sp, #1	/* Reset 	  7 */
>> +	W(add)	sp, sp, #1	/* Undef	  6 */
>> +	W(add)	sp, sp, #1	/* Syscall	  5 */
>> +	W(add)	sp, sp, #1	/* Prefetch abort 4 */
>> +	W(add)	sp, sp, #1	/* Data abort	  3 */
>> +	W(add)	sp, sp, #1	/* HVC		  2 */
>> +	W(add)	sp, sp, #1	/* IRQ		  1 */
>> +	W(nop)			/* FIQ		  0 */
>> +
>> +	mcr	p15, 0, r0, c7, c5, 6	/* BPIALL */
>> +	isb
>> +
> 
> The below is quite a bit of faff; might it be worth an
> 
> #ifdef CONFIG_THUMB2_KERNEL
> 
>> +	/*
>> +	 * Yet another silly hack: Use VPIDR as a temp register.
>> +	 * Thumb2 is really a pain, as SP cannot be used with most
>> +	 * of the bitwise instructions. The vect_br macro ensures
>> +	 * things gets cleaned-up.
>> +	 */
>> +	mcr	p15, 4, r0, c0, c0, 0	/* VPIDR */
>> +	mov	r0, sp
>> +	and	r0, r0, #7
>> +	sub	sp, sp, r0
>> +	push	{r1, r2}
>> +	mov	r1, r0
>> +	mrc	p15, 4, r0, c0, c0, 0	/* VPIDR */
>> +	mrc	p15, 0, r2, c0, c0, 0	/* MIDR  */
>> +	mcr	p15, 4, r2, c0, c0, 0	/* VPIDR */
> 
> #endif
> 
>> +
>> +.macro vect_br val, targ
> 
> ARM(cmp		sp, #val)

Doesn't quite work, as we still have all the top bits that contain the 
stack address. But I like the idea of making it baster for non-T2. How
about this instead?

diff --git a/arch/arm/kvm/hyp/hyp-entry.S b/arch/arm/kvm/hyp/hyp-entry.S
index 2377ed86e20b..23c954a9e441 100644
--- a/arch/arm/kvm/hyp/hyp-entry.S
+++ b/arch/arm/kvm/hyp/hyp-entry.S
@@ -114,6 +114,8 @@ __kvm_hyp_vector_bp_inv:
 	isb
 
 decode_vectors:
+
+#ifdef CONFIG_THUMB2_KERNEL
 	/*
 	 * Yet another silly hack: Use VPIDR as a temp register.
 	 * Thumb2 is really a pain, as SP cannot be used with most
@@ -129,10 +131,16 @@ decode_vectors:
 	mrc	p15, 4, r0, c0, c0, 0	/* VPIDR */
 	mrc	p15, 0, r2, c0, c0, 0	/* MIDR  */
 	mcr	p15, 4, r2, c0, c0, 0	/* VPIDR */
+#endif
 
 .macro vect_br val, targ
-	cmp	r1, #\val
-	popeq	{r1, r2}
+ARM(	eor	sp, sp, #\val	)
+ARM(	tst	sp, #7		)
+ARM(	eorne	sp, sp, #\val	)
+
+THUMB(	cmp	r1, #\val	)
+THUMB(	popeq	{r1, r2}	)
+
 	beq	\targ
 .endm
 


> THUMB(cmp	r1, #\val)
> THUMB(popeq	{r1, r2}
> 
>> +	beq	\targ
>> +.endm
> 
> ...to keep the "normal" path relatively streamlined?

I think the above achieves it... Thoughts?

	M.
-- 
Jazz is not dead. It just smells funny...



More information about the linux-arm-kernel mailing list