KVM: PPC: Improve split mode
When in split mode, instruction relocation and data relocation are not equal. So far we implemented this mode by reserving a special pseudo-VSID for the two cases and flushing all PTEs when going into split mode, which is slow. Unfortunately 32bit Linux and Mac OS X use split mode extensively. So to not slow down things too much, I came up with a different idea: Mark the split mode with a bit in the VSID and then treat it like any other segment. This means we can just flush the shadow segment cache, but keep the PTEs intact. I verified that this works with ppc32 Linux and Mac OS X 10.4 guests and does speed them up. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
7fdaec997c
commit
f7bc74e1c3
4 changed files with 52 additions and 45 deletions
|
@ -100,11 +100,10 @@ struct kvmppc_vcpu_book3s {
|
||||||
#define CONTEXT_GUEST 1
|
#define CONTEXT_GUEST 1
|
||||||
#define CONTEXT_GUEST_END 2
|
#define CONTEXT_GUEST_END 2
|
||||||
|
|
||||||
#define VSID_REAL_DR 0x7ffffffffff00000ULL
|
#define VSID_REAL 0x1fffffffffc00000ULL
|
||||||
#define VSID_REAL_IR 0x7fffffffffe00000ULL
|
#define VSID_BAT 0x1fffffffffb00000ULL
|
||||||
#define VSID_SPLIT_MASK 0x7fffffffffe00000ULL
|
#define VSID_REAL_DR 0x2000000000000000ULL
|
||||||
#define VSID_REAL 0x7fffffffffc00000ULL
|
#define VSID_REAL_IR 0x4000000000000000ULL
|
||||||
#define VSID_BAT 0x7fffffffffb00000ULL
|
|
||||||
#define VSID_PR 0x8000000000000000ULL
|
#define VSID_PR 0x8000000000000000ULL
|
||||||
|
|
||||||
extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong ea, ulong ea_mask);
|
extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong ea, ulong ea_mask);
|
||||||
|
|
|
@ -148,16 +148,8 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((vcpu->arch.msr & (MSR_IR|MSR_DR)) != (old_msr & (MSR_IR|MSR_DR))) ||
|
if ((vcpu->arch.msr & (MSR_PR|MSR_IR|MSR_DR)) !=
|
||||||
(vcpu->arch.msr & MSR_PR) != (old_msr & MSR_PR)) {
|
(old_msr & (MSR_PR|MSR_IR|MSR_DR))) {
|
||||||
bool dr = (vcpu->arch.msr & MSR_DR) ? true : false;
|
|
||||||
bool ir = (vcpu->arch.msr & MSR_IR) ? true : false;
|
|
||||||
|
|
||||||
/* Flush split mode PTEs */
|
|
||||||
if (dr != ir)
|
|
||||||
kvmppc_mmu_pte_vflush(vcpu, VSID_SPLIT_MASK,
|
|
||||||
VSID_SPLIT_MASK);
|
|
||||||
|
|
||||||
kvmppc_mmu_flush_segments(vcpu);
|
kvmppc_mmu_flush_segments(vcpu);
|
||||||
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
|
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
|
||||||
}
|
}
|
||||||
|
@ -535,6 +527,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||||
bool is_mmio = false;
|
bool is_mmio = false;
|
||||||
bool dr = (vcpu->arch.msr & MSR_DR) ? true : false;
|
bool dr = (vcpu->arch.msr & MSR_DR) ? true : false;
|
||||||
bool ir = (vcpu->arch.msr & MSR_IR) ? true : false;
|
bool ir = (vcpu->arch.msr & MSR_IR) ? true : false;
|
||||||
|
u64 vsid;
|
||||||
|
|
||||||
relocated = data ? dr : ir;
|
relocated = data ? dr : ir;
|
||||||
|
|
||||||
|
@ -552,13 +545,20 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||||
|
|
||||||
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||||
case 0:
|
case 0:
|
||||||
pte.vpage |= VSID_REAL;
|
pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12));
|
||||||
break;
|
break;
|
||||||
case MSR_DR:
|
case MSR_DR:
|
||||||
pte.vpage |= VSID_REAL_DR;
|
|
||||||
break;
|
|
||||||
case MSR_IR:
|
case MSR_IR:
|
||||||
pte.vpage |= VSID_REAL_IR;
|
vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid);
|
||||||
|
|
||||||
|
if ((vcpu->arch.msr & (MSR_DR|MSR_IR)) == MSR_DR)
|
||||||
|
pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12));
|
||||||
|
else
|
||||||
|
pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12));
|
||||||
|
pte.vpage |= vsid;
|
||||||
|
|
||||||
|
if (vsid == -1)
|
||||||
|
page_found = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -330,30 +330,35 @@ static void kvmppc_mmu_book3s_32_tlbie(struct kvm_vcpu *vcpu, ulong ea, bool lar
|
||||||
static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||||
u64 *vsid)
|
u64 *vsid)
|
||||||
{
|
{
|
||||||
|
ulong ea = esid << SID_SHIFT;
|
||||||
|
struct kvmppc_sr *sr;
|
||||||
|
u64 gvsid = esid;
|
||||||
|
|
||||||
|
if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||||
|
sr = find_sr(to_book3s(vcpu), ea);
|
||||||
|
if (sr->valid)
|
||||||
|
gvsid = sr->vsid;
|
||||||
|
}
|
||||||
|
|
||||||
/* In case we only have one of MSR_IR or MSR_DR set, let's put
|
/* In case we only have one of MSR_IR or MSR_DR set, let's put
|
||||||
that in the real-mode context (and hope RM doesn't access
|
that in the real-mode context (and hope RM doesn't access
|
||||||
high memory) */
|
high memory) */
|
||||||
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||||
case 0:
|
case 0:
|
||||||
*vsid = (VSID_REAL >> 16) | esid;
|
*vsid = VSID_REAL | esid;
|
||||||
break;
|
break;
|
||||||
case MSR_IR:
|
case MSR_IR:
|
||||||
*vsid = (VSID_REAL_IR >> 16) | esid;
|
*vsid = VSID_REAL_IR | gvsid;
|
||||||
break;
|
break;
|
||||||
case MSR_DR:
|
case MSR_DR:
|
||||||
*vsid = (VSID_REAL_DR >> 16) | esid;
|
*vsid = VSID_REAL_DR | gvsid;
|
||||||
break;
|
break;
|
||||||
case MSR_DR|MSR_IR:
|
case MSR_DR|MSR_IR:
|
||||||
{
|
|
||||||
ulong ea = esid << SID_SHIFT;
|
|
||||||
struct kvmppc_sr *sr = find_sr(to_book3s(vcpu), ea);
|
|
||||||
|
|
||||||
if (!sr->valid)
|
if (!sr->valid)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
*vsid = sr->vsid;
|
*vsid = sr->vsid;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
|
@ -442,29 +442,32 @@ static void kvmppc_mmu_book3s_64_tlbie(struct kvm_vcpu *vcpu, ulong va,
|
||||||
static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||||
u64 *vsid)
|
u64 *vsid)
|
||||||
{
|
{
|
||||||
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
ulong ea = esid << SID_SHIFT;
|
||||||
case 0:
|
struct kvmppc_slb *slb;
|
||||||
*vsid = (VSID_REAL >> 16) | esid;
|
u64 gvsid = esid;
|
||||||
break;
|
|
||||||
case MSR_IR:
|
if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||||
*vsid = (VSID_REAL_IR >> 16) | esid;
|
|
||||||
break;
|
|
||||||
case MSR_DR:
|
|
||||||
*vsid = (VSID_REAL_DR >> 16) | esid;
|
|
||||||
break;
|
|
||||||
case MSR_DR|MSR_IR:
|
|
||||||
{
|
|
||||||
ulong ea;
|
|
||||||
struct kvmppc_slb *slb;
|
|
||||||
ea = esid << SID_SHIFT;
|
|
||||||
slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea);
|
slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea);
|
||||||
if (slb)
|
if (slb)
|
||||||
*vsid = slb->vsid;
|
gvsid = slb->vsid;
|
||||||
else
|
}
|
||||||
|
|
||||||
|
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||||
|
case 0:
|
||||||
|
*vsid = VSID_REAL | esid;
|
||||||
|
break;
|
||||||
|
case MSR_IR:
|
||||||
|
*vsid = VSID_REAL_IR | gvsid;
|
||||||
|
break;
|
||||||
|
case MSR_DR:
|
||||||
|
*vsid = VSID_REAL_DR | gvsid;
|
||||||
|
break;
|
||||||
|
case MSR_DR|MSR_IR:
|
||||||
|
if (!slb)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
|
*vsid = gvsid;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Reference in a new issue