diff options
Diffstat (limited to 'arch/powerpc/kvm/emulate.c')
-rw-r--r-- | arch/powerpc/kvm/emulate.c | 120 |
1 files changed, 7 insertions, 113 deletions
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index 0fce4fbdc20d..0ce8ed539bae 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c | |||
@@ -29,8 +29,6 @@ | |||
29 | #include <asm/byteorder.h> | 29 | #include <asm/byteorder.h> |
30 | #include <asm/kvm_ppc.h> | 30 | #include <asm/kvm_ppc.h> |
31 | 31 | ||
32 | #include "44x_tlb.h" | ||
33 | |||
34 | /* Instruction decoding */ | 32 | /* Instruction decoding */ |
35 | static inline unsigned int get_op(u32 inst) | 33 | static inline unsigned int get_op(u32 inst) |
36 | { | 34 | { |
@@ -87,96 +85,6 @@ static inline unsigned int get_d(u32 inst) | |||
87 | return inst & 0xffff; | 85 | return inst & 0xffff; |
88 | } | 86 | } |
89 | 87 | ||
90 | static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, | ||
91 | const struct tlbe *tlbe) | ||
92 | { | ||
93 | gpa_t gpa; | ||
94 | |||
95 | if (!get_tlb_v(tlbe)) | ||
96 | return 0; | ||
97 | |||
98 | /* Does it match current guest AS? */ | ||
99 | /* XXX what about IS != DS? */ | ||
100 | if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS)) | ||
101 | return 0; | ||
102 | |||
103 | gpa = get_tlb_raddr(tlbe); | ||
104 | if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT)) | ||
105 | /* Mapping is not for RAM. */ | ||
106 | return 0; | ||
107 | |||
108 | return 1; | ||
109 | } | ||
110 | |||
111 | static int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u32 inst) | ||
112 | { | ||
113 | u64 eaddr; | ||
114 | u64 raddr; | ||
115 | u64 asid; | ||
116 | u32 flags; | ||
117 | struct tlbe *tlbe; | ||
118 | unsigned int ra; | ||
119 | unsigned int rs; | ||
120 | unsigned int ws; | ||
121 | unsigned int index; | ||
122 | |||
123 | ra = get_ra(inst); | ||
124 | rs = get_rs(inst); | ||
125 | ws = get_ws(inst); | ||
126 | |||
127 | index = vcpu->arch.gpr[ra]; | ||
128 | if (index > PPC44x_TLB_SIZE) { | ||
129 | printk("%s: index %d\n", __func__, index); | ||
130 | kvmppc_dump_vcpu(vcpu); | ||
131 | return EMULATE_FAIL; | ||
132 | } | ||
133 | |||
134 | tlbe = &vcpu->arch.guest_tlb[index]; | ||
135 | |||
136 | /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */ | ||
137 | if (tlbe->word0 & PPC44x_TLB_VALID) { | ||
138 | eaddr = get_tlb_eaddr(tlbe); | ||
139 | asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid; | ||
140 | kvmppc_mmu_invalidate(vcpu, eaddr, get_tlb_end(tlbe), asid); | ||
141 | } | ||
142 | |||
143 | switch (ws) { | ||
144 | case PPC44x_TLB_PAGEID: | ||
145 | tlbe->tid = vcpu->arch.mmucr & 0xff; | ||
146 | tlbe->word0 = vcpu->arch.gpr[rs]; | ||
147 | break; | ||
148 | |||
149 | case PPC44x_TLB_XLAT: | ||
150 | tlbe->word1 = vcpu->arch.gpr[rs]; | ||
151 | break; | ||
152 | |||
153 | case PPC44x_TLB_ATTRIB: | ||
154 | tlbe->word2 = vcpu->arch.gpr[rs]; | ||
155 | break; | ||
156 | |||
157 | default: | ||
158 | return EMULATE_FAIL; | ||
159 | } | ||
160 | |||
161 | if (tlbe_is_host_safe(vcpu, tlbe)) { | ||
162 | eaddr = get_tlb_eaddr(tlbe); | ||
163 | raddr = get_tlb_raddr(tlbe); | ||
164 | asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid; | ||
165 | flags = tlbe->word2 & 0xffff; | ||
166 | |||
167 | /* Create a 4KB mapping on the host. If the guest wanted a | ||
168 | * large page, only the first 4KB is mapped here and the rest | ||
169 | * are mapped on the fly. */ | ||
170 | kvmppc_mmu_map(vcpu, eaddr, raddr >> PAGE_SHIFT, asid, flags); | ||
171 | } | ||
172 | |||
173 | KVMTRACE_5D(GTLB_WRITE, vcpu, index, | ||
174 | tlbe->tid, tlbe->word0, tlbe->word1, tlbe->word2, | ||
175 | handler); | ||
176 | |||
177 | return EMULATE_DONE; | ||
178 | } | ||
179 | |||
180 | static void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) | 88 | static void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) |
181 | { | 89 | { |
182 | if (vcpu->arch.tcr & TCR_DIE) { | 90 | if (vcpu->arch.tcr & TCR_DIE) { |
@@ -222,6 +130,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
222 | int rc; | 130 | int rc; |
223 | int rs; | 131 | int rs; |
224 | int rt; | 132 | int rt; |
133 | int ws; | ||
225 | int sprn; | 134 | int sprn; |
226 | int dcrn; | 135 | int dcrn; |
227 | enum emulation_result emulated = EMULATE_DONE; | 136 | enum emulation_result emulated = EMULATE_DONE; |
@@ -630,33 +539,18 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
630 | break; | 539 | break; |
631 | 540 | ||
632 | case 978: /* tlbwe */ | 541 | case 978: /* tlbwe */ |
633 | emulated = kvmppc_emul_tlbwe(vcpu, inst); | 542 | ra = get_ra(inst); |
543 | rs = get_rs(inst); | ||
544 | ws = get_ws(inst); | ||
545 | emulated = kvmppc_emul_tlbwe(vcpu, ra, rs, ws); | ||
634 | break; | 546 | break; |
635 | 547 | ||
636 | case 914: { /* tlbsx */ | 548 | case 914: /* tlbsx */ |
637 | int index; | ||
638 | unsigned int as = get_mmucr_sts(vcpu); | ||
639 | unsigned int pid = get_mmucr_stid(vcpu); | ||
640 | |||
641 | rt = get_rt(inst); | 549 | rt = get_rt(inst); |
642 | ra = get_ra(inst); | 550 | ra = get_ra(inst); |
643 | rb = get_rb(inst); | 551 | rb = get_rb(inst); |
644 | rc = get_rc(inst); | 552 | rc = get_rc(inst); |
645 | 553 | emulated = kvmppc_emul_tlbsx(vcpu, rt, ra, rb, rc); | |
646 | ea = vcpu->arch.gpr[rb]; | ||
647 | if (ra) | ||
648 | ea += vcpu->arch.gpr[ra]; | ||
649 | |||
650 | index = kvmppc_44x_tlb_index(vcpu, ea, pid, as); | ||
651 | if (rc) { | ||
652 | if (index < 0) | ||
653 | vcpu->arch.cr &= ~0x20000000; | ||
654 | else | ||
655 | vcpu->arch.cr |= 0x20000000; | ||
656 | } | ||
657 | vcpu->arch.gpr[rt] = index; | ||
658 | |||
659 | } | ||
660 | break; | 554 | break; |
661 | 555 | ||
662 | case 790: /* lhbrx */ | 556 | case 790: /* lhbrx */ |