KVM: PPC: PV mtmsrd L=1
The PowerPC ISA has a special instruction for mtmsr that only changes the EE and RI bits, namely the L=1 form. Since that one is reasonably often occuring and simple to implement, let's go with this first. Writing EE=0 is always just a store. Doing EE=1 also requires us to check for pending interrupts and if necessary exit back to the hypervisor. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
92234722ed
commit
819a63dc79
|
@ -63,6 +63,7 @@
|
||||||
#define KVM_INST_MTSPR_DSISR 0x7c1203a6
|
#define KVM_INST_MTSPR_DSISR 0x7c1203a6
|
||||||
|
|
||||||
#define KVM_INST_TLBSYNC 0x7c00046c
|
#define KVM_INST_TLBSYNC 0x7c00046c
|
||||||
|
#define KVM_INST_MTMSRD_L1 0x7c010164
|
||||||
|
|
||||||
static bool kvm_patching_worked = true;
|
static bool kvm_patching_worked = true;
|
||||||
static char kvm_tmp[1024 * 1024];
|
static char kvm_tmp[1024 * 1024];
|
||||||
|
@ -138,6 +139,43 @@ static u32 *kvm_alloc(int len)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern u32 kvm_emulate_mtmsrd_branch_offs;
|
||||||
|
extern u32 kvm_emulate_mtmsrd_reg_offs;
|
||||||
|
extern u32 kvm_emulate_mtmsrd_len;
|
||||||
|
extern u32 kvm_emulate_mtmsrd[];
|
||||||
|
|
||||||
|
static void kvm_patch_ins_mtmsrd(u32 *inst, u32 rt)
|
||||||
|
{
|
||||||
|
u32 *p;
|
||||||
|
int distance_start;
|
||||||
|
int distance_end;
|
||||||
|
ulong next_inst;
|
||||||
|
|
||||||
|
p = kvm_alloc(kvm_emulate_mtmsrd_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_mtmsrd_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_mtmsrd, kvm_emulate_mtmsrd_len * 4);
|
||||||
|
p[kvm_emulate_mtmsrd_branch_offs] |= distance_end & KVM_INST_B_MASK;
|
||||||
|
p[kvm_emulate_mtmsrd_reg_offs] |= rt;
|
||||||
|
flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsrd_len * 4);
|
||||||
|
|
||||||
|
/* Patch the invocation */
|
||||||
|
kvm_patch_ins_b(inst, distance_start);
|
||||||
|
}
|
||||||
|
|
||||||
static void kvm_map_magic_page(void *data)
|
static void kvm_map_magic_page(void *data)
|
||||||
{
|
{
|
||||||
kvm_hypercall2(KVM_HC_PPC_MAP_MAGIC_PAGE,
|
kvm_hypercall2(KVM_HC_PPC_MAP_MAGIC_PAGE,
|
||||||
|
@ -211,6 +249,13 @@ static void kvm_check_ins(u32 *inst)
|
||||||
case KVM_INST_TLBSYNC:
|
case KVM_INST_TLBSYNC:
|
||||||
kvm_patch_ins_nop(inst);
|
kvm_patch_ins_nop(inst);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Rewrites */
|
||||||
|
case KVM_INST_MTMSRD_L1:
|
||||||
|
/* We use r30 and r31 during the hook */
|
||||||
|
if (get_rt(inst_rt) < 30)
|
||||||
|
kvm_patch_ins_mtmsrd(inst, inst_rt);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_inst) {
|
switch (_inst) {
|
||||||
|
|
|
@ -64,3 +64,59 @@ kvm_hypercall_start:
|
||||||
/* Disable critical section. We are critical if \
|
/* Disable critical section. We are critical if \
|
||||||
shared->critical == r1 and r2 is always != r1 */ \
|
shared->critical == r1 and r2 is always != r1 */ \
|
||||||
STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);
|
STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);
|
||||||
|
|
||||||
|
.global kvm_emulate_mtmsrd
|
||||||
|
kvm_emulate_mtmsrd:
|
||||||
|
|
||||||
|
SCRATCH_SAVE
|
||||||
|
|
||||||
|
/* Put MSR & ~(MSR_EE|MSR_RI) in r31 */
|
||||||
|
LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
|
||||||
|
lis r30, (~(MSR_EE | MSR_RI))@h
|
||||||
|
ori r30, r30, (~(MSR_EE | MSR_RI))@l
|
||||||
|
and r31, r31, r30
|
||||||
|
|
||||||
|
/* OR the register's (MSR_EE|MSR_RI) on MSR */
|
||||||
|
kvm_emulate_mtmsrd_reg:
|
||||||
|
andi. r30, r0, (MSR_EE|MSR_RI)
|
||||||
|
or r31, r31, r30
|
||||||
|
|
||||||
|
/* Put MSR back into magic page */
|
||||||
|
STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
|
||||||
|
|
||||||
|
/* Check if we have to fetch an interrupt */
|
||||||
|
lwz r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
|
||||||
|
cmpwi r31, 0
|
||||||
|
beq+ no_check
|
||||||
|
|
||||||
|
/* Check if we may trigger an interrupt */
|
||||||
|
andi. r30, r30, MSR_EE
|
||||||
|
beq no_check
|
||||||
|
|
||||||
|
SCRATCH_RESTORE
|
||||||
|
|
||||||
|
/* Nag hypervisor */
|
||||||
|
tlbsync
|
||||||
|
|
||||||
|
b kvm_emulate_mtmsrd_branch
|
||||||
|
|
||||||
|
no_check:
|
||||||
|
|
||||||
|
SCRATCH_RESTORE
|
||||||
|
|
||||||
|
/* Go back to caller */
|
||||||
|
kvm_emulate_mtmsrd_branch:
|
||||||
|
b .
|
||||||
|
kvm_emulate_mtmsrd_end:
|
||||||
|
|
||||||
|
.global kvm_emulate_mtmsrd_branch_offs
|
||||||
|
kvm_emulate_mtmsrd_branch_offs:
|
||||||
|
.long (kvm_emulate_mtmsrd_branch - kvm_emulate_mtmsrd) / 4
|
||||||
|
|
||||||
|
.global kvm_emulate_mtmsrd_reg_offs
|
||||||
|
kvm_emulate_mtmsrd_reg_offs:
|
||||||
|
.long (kvm_emulate_mtmsrd_reg - kvm_emulate_mtmsrd) / 4
|
||||||
|
|
||||||
|
.global kvm_emulate_mtmsrd_len
|
||||||
|
kvm_emulate_mtmsrd_len:
|
||||||
|
.long (kvm_emulate_mtmsrd_end - kvm_emulate_mtmsrd) / 4
|
||||||
|
|
Loading…
Reference in a new issue