aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2011-12-20 10:34:39 -0500
committerAvi Kivity <avi@redhat.com>2012-04-08 05:51:16 -0400
commitab9fc4056af338248640ddb18497be386360363d (patch)
tree45f1353679b838ba022359325902799d7ce9a7e7 /arch/powerpc/kvm
parent4f802fe98bd5bd4fe1dd86df3e5c58546e65ad09 (diff)
KVM: PPC: e500: emulate tlbilx
tlbilx is the new, preferred invalidation instruction. It is not found on e500 prior to e500mc, but there should be no harm in supporting it on all e500. Based on code from Ashish Kalra <Ashish.Kalra@freescale.com>. Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r--arch/powerpc/kvm/e500.h1
-rw-r--r--arch/powerpc/kvm/e500_emulate.c9
-rw-r--r--arch/powerpc/kvm/e500_tlb.c52
3 files changed, 62 insertions, 0 deletions
diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h
index f4dee55ae6c7..ce3f163f702e 100644
--- a/arch/powerpc/kvm/e500.h
+++ b/arch/powerpc/kvm/e500.h
@@ -124,6 +124,7 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500,
124int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu); 124int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu);
125int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu); 125int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu);
126int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb); 126int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb);
127int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int rt, int ra, int rb);
127int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb); 128int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb);
128int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500); 129int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500);
129void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500); 130void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500);
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
index c80794d097d3..af02c18fc798 100644
--- a/arch/powerpc/kvm/e500_emulate.c
+++ b/arch/powerpc/kvm/e500_emulate.c
@@ -22,6 +22,7 @@
22#define XOP_TLBSX 914 22#define XOP_TLBSX 914
23#define XOP_TLBRE 946 23#define XOP_TLBRE 946
24#define XOP_TLBWE 978 24#define XOP_TLBWE 978
25#define XOP_TLBILX 18
25 26
26int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, 27int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
27 unsigned int inst, int *advance) 28 unsigned int inst, int *advance)
@@ -29,6 +30,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
29 int emulated = EMULATE_DONE; 30 int emulated = EMULATE_DONE;
30 int ra; 31 int ra;
31 int rb; 32 int rb;
33 int rt;
32 34
33 switch (get_op(inst)) { 35 switch (get_op(inst)) {
34 case 31: 36 case 31:
@@ -47,6 +49,13 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
47 emulated = kvmppc_e500_emul_tlbsx(vcpu,rb); 49 emulated = kvmppc_e500_emul_tlbsx(vcpu,rb);
48 break; 50 break;
49 51
52 case XOP_TLBILX:
53 ra = get_ra(inst);
54 rb = get_rb(inst);
55 rt = get_rt(inst);
56 emulated = kvmppc_e500_emul_tlbilx(vcpu, rt, ra, rb);
57 break;
58
50 case XOP_TLBIVAX: 59 case XOP_TLBIVAX:
51 ra = get_ra(inst); 60 ra = get_ra(inst);
52 rb = get_rb(inst); 61 rb = get_rb(inst);
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c
index c8ce51d03a2f..6eb5d655bdb4 100644
--- a/arch/powerpc/kvm/e500_tlb.c
+++ b/arch/powerpc/kvm/e500_tlb.c
@@ -631,6 +631,58 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb)
631 return EMULATE_DONE; 631 return EMULATE_DONE;
632} 632}
633 633
634static void tlbilx_all(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
635 int pid, int rt)
636{
637 struct kvm_book3e_206_tlb_entry *tlbe;
638 int tid, esel;
639
640 /* invalidate all entries */
641 for (esel = 0; esel < vcpu_e500->gtlb_params[tlbsel].entries; esel++) {
642 tlbe = get_entry(vcpu_e500, tlbsel, esel);
643 tid = get_tlb_tid(tlbe);
644 if (rt == 0 || tid == pid) {
645 inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
646 kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
647 }
648 }
649}
650
651static void tlbilx_one(struct kvmppc_vcpu_e500 *vcpu_e500, int pid,
652 int ra, int rb)
653{
654 int tlbsel, esel;
655 gva_t ea;
656
657 ea = kvmppc_get_gpr(&vcpu_e500->vcpu, rb);
658 if (ra)
659 ea += kvmppc_get_gpr(&vcpu_e500->vcpu, ra);
660
661 for (tlbsel = 0; tlbsel < 2; tlbsel++) {
662 esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, -1);
663 if (esel >= 0) {
664 inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
665 kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
666 break;
667 }
668 }
669}
670
671int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int rt, int ra, int rb)
672{
673 struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
674 int pid = get_cur_spid(vcpu);
675
676 if (rt == 0 || rt == 1) {
677 tlbilx_all(vcpu_e500, 0, pid, rt);
678 tlbilx_all(vcpu_e500, 1, pid, rt);
679 } else if (rt == 3) {
680 tlbilx_one(vcpu_e500, pid, ra, rb);
681 }
682
683 return EMULATE_DONE;
684}
685
634int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu) 686int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu)
635{ 687{
636 struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); 688 struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);