KVM: PPC: Add mtsrin PV code
This is the guest side of the mtsr acceleration. Using this a guest can now call mtsrin with almost no overhead as long as it ensures that it only uses it with (MSR_IR|MSR_DR) == 0. Linux does that, so we're good. Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
		
					parent
					
						
							
								df1bfa25d8
							
						
					
				
			
			
				commit
				
					
						cbe487fac7
					
				
			
		
					 4 changed files with 114 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -160,6 +160,9 @@ mtmsr	rX		b	<special mtmsr section>
 | 
			
		|||
 | 
			
		||||
mtmsrd	rX, 1		b	<special mtmsrd section>
 | 
			
		||||
 | 
			
		||||
[Book3S only]
 | 
			
		||||
mtsrin	rX, rY		b	<special mtsrin section>
 | 
			
		||||
 | 
			
		||||
[BookE only]
 | 
			
		||||
wrteei	[0|1]		b	<special wrteei section>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -478,6 +478,7 @@ int main(void)
 | 
			
		|||
	DEFINE(KVM_MAGIC_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
 | 
			
		||||
	DEFINE(KVM_MAGIC_CRITICAL, offsetof(struct kvm_vcpu_arch_shared,
 | 
			
		||||
					    critical));
 | 
			
		||||
	DEFINE(KVM_MAGIC_SR, offsetof(struct kvm_vcpu_arch_shared, sr));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_44x
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,6 +42,7 @@
 | 
			
		|||
#define KVM_INST_B_MAX		0x01ffffff
 | 
			
		||||
 | 
			
		||||
#define KVM_MASK_RT		0x03e00000
 | 
			
		||||
#define KVM_MASK_RB		0x0000f800
 | 
			
		||||
#define KVM_INST_MFMSR		0x7c0000a6
 | 
			
		||||
#define KVM_INST_MFSPR_SPRG0	0x7c1042a6
 | 
			
		||||
#define KVM_INST_MFSPR_SPRG1	0x7c1142a6
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +70,8 @@
 | 
			
		|||
#define KVM_INST_WRTEEI_0	0x7c000146
 | 
			
		||||
#define KVM_INST_WRTEEI_1	0x7c008146
 | 
			
		||||
 | 
			
		||||
#define KVM_INST_MTSRIN		0x7c0001e4
 | 
			
		||||
 | 
			
		||||
static bool kvm_patching_worked = true;
 | 
			
		||||
static char kvm_tmp[1024 * 1024];
 | 
			
		||||
static int kvm_tmp_index;
 | 
			
		||||
| 
						 | 
				
			
			@ -264,6 +267,51 @@ static void kvm_patch_ins_wrteei(u32 *inst)
 | 
			
		|||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PPC_BOOK3S_32
 | 
			
		||||
 | 
			
		||||
extern u32 kvm_emulate_mtsrin_branch_offs;
 | 
			
		||||
extern u32 kvm_emulate_mtsrin_reg1_offs;
 | 
			
		||||
extern u32 kvm_emulate_mtsrin_reg2_offs;
 | 
			
		||||
extern u32 kvm_emulate_mtsrin_orig_ins_offs;
 | 
			
		||||
extern u32 kvm_emulate_mtsrin_len;
 | 
			
		||||
extern u32 kvm_emulate_mtsrin[];
 | 
			
		||||
 | 
			
		||||
static void kvm_patch_ins_mtsrin(u32 *inst, u32 rt, u32 rb)
 | 
			
		||||
{
 | 
			
		||||
	u32 *p;
 | 
			
		||||
	int distance_start;
 | 
			
		||||
	int distance_end;
 | 
			
		||||
	ulong next_inst;
 | 
			
		||||
 | 
			
		||||
	p = kvm_alloc(kvm_emulate_mtsrin_len * 4);
 | 
			
		||||
	if (!p)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Find out where we are and put everything there */
 | 
			
		||||
	distance_start = (ulong)p - (ulong)inst;
 | 
			
		||||
	next_inst = ((ulong)inst + 4);
 | 
			
		||||
	distance_end = next_inst - (ulong)&p[kvm_emulate_mtsrin_branch_offs];
 | 
			
		||||
 | 
			
		||||
	/* Make sure we only write valid b instructions */
 | 
			
		||||
	if (distance_start > KVM_INST_B_MAX) {
 | 
			
		||||
		kvm_patching_worked = false;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Modify the chunk to fit the invocation */
 | 
			
		||||
	memcpy(p, kvm_emulate_mtsrin, kvm_emulate_mtsrin_len * 4);
 | 
			
		||||
	p[kvm_emulate_mtsrin_branch_offs] |= distance_end & KVM_INST_B_MASK;
 | 
			
		||||
	p[kvm_emulate_mtsrin_reg1_offs] |= (rb << 10);
 | 
			
		||||
	p[kvm_emulate_mtsrin_reg2_offs] |= rt;
 | 
			
		||||
	p[kvm_emulate_mtsrin_orig_ins_offs] = *inst;
 | 
			
		||||
	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtsrin_len * 4);
 | 
			
		||||
 | 
			
		||||
	/* Patch the invocation */
 | 
			
		||||
	kvm_patch_ins_b(inst, distance_start);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void kvm_map_magic_page(void *data)
 | 
			
		||||
{
 | 
			
		||||
	u32 *features = data;
 | 
			
		||||
| 
						 | 
				
			
			@ -360,6 +408,18 @@ static void kvm_check_ins(u32 *inst, u32 features)
 | 
			
		|||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (inst_no_rt & ~KVM_MASK_RB) {
 | 
			
		||||
#ifdef CONFIG_PPC_BOOK3S_32
 | 
			
		||||
	case KVM_INST_MTSRIN:
 | 
			
		||||
		if (features & KVM_MAGIC_FEAT_SR) {
 | 
			
		||||
			u32 inst_rb = _inst & KVM_MASK_RB;
 | 
			
		||||
			kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
		break;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (_inst) {
 | 
			
		||||
#ifdef CONFIG_BOOKE
 | 
			
		||||
	case KVM_INST_WRTEEI_0:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -245,3 +245,53 @@ kvm_emulate_wrteei_ee_offs:
 | 
			
		|||
.global kvm_emulate_wrteei_len
 | 
			
		||||
kvm_emulate_wrteei_len:
 | 
			
		||||
	.long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.global kvm_emulate_mtsrin
 | 
			
		||||
kvm_emulate_mtsrin:
 | 
			
		||||
 | 
			
		||||
	SCRATCH_SAVE
 | 
			
		||||
 | 
			
		||||
	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
 | 
			
		||||
	andi.	r31, r31, MSR_DR | MSR_IR
 | 
			
		||||
	beq	kvm_emulate_mtsrin_reg1
 | 
			
		||||
 | 
			
		||||
	SCRATCH_RESTORE
 | 
			
		||||
 | 
			
		||||
kvm_emulate_mtsrin_orig_ins:
 | 
			
		||||
	nop
 | 
			
		||||
	b	kvm_emulate_mtsrin_branch
 | 
			
		||||
 | 
			
		||||
kvm_emulate_mtsrin_reg1:
 | 
			
		||||
	/* rX >> 26 */
 | 
			
		||||
	rlwinm  r30,r0,6,26,29
 | 
			
		||||
 | 
			
		||||
kvm_emulate_mtsrin_reg2:
 | 
			
		||||
	stw	r0, (KVM_MAGIC_PAGE + KVM_MAGIC_SR)(r30)
 | 
			
		||||
 | 
			
		||||
	SCRATCH_RESTORE
 | 
			
		||||
 | 
			
		||||
	/* Go back to caller */
 | 
			
		||||
kvm_emulate_mtsrin_branch:
 | 
			
		||||
	b	.
 | 
			
		||||
kvm_emulate_mtsrin_end:
 | 
			
		||||
 | 
			
		||||
.global kvm_emulate_mtsrin_branch_offs
 | 
			
		||||
kvm_emulate_mtsrin_branch_offs:
 | 
			
		||||
	.long (kvm_emulate_mtsrin_branch - kvm_emulate_mtsrin) / 4
 | 
			
		||||
 | 
			
		||||
.global kvm_emulate_mtsrin_reg1_offs
 | 
			
		||||
kvm_emulate_mtsrin_reg1_offs:
 | 
			
		||||
	.long (kvm_emulate_mtsrin_reg1 - kvm_emulate_mtsrin) / 4
 | 
			
		||||
 | 
			
		||||
.global kvm_emulate_mtsrin_reg2_offs
 | 
			
		||||
kvm_emulate_mtsrin_reg2_offs:
 | 
			
		||||
	.long (kvm_emulate_mtsrin_reg2 - kvm_emulate_mtsrin) / 4
 | 
			
		||||
 | 
			
		||||
.global kvm_emulate_mtsrin_orig_ins_offs
 | 
			
		||||
kvm_emulate_mtsrin_orig_ins_offs:
 | 
			
		||||
	.long (kvm_emulate_mtsrin_orig_ins - kvm_emulate_mtsrin) / 4
 | 
			
		||||
 | 
			
		||||
.global kvm_emulate_mtsrin_len
 | 
			
		||||
kvm_emulate_mtsrin_len:
 | 
			
		||||
	.long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue