KVM: ppc: support large host pages
[linux-2.6] / arch / powerpc / kvm / 44x_tlb.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License, version 2, as
4  * published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program; if not, write to the Free Software
13  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
14  *
15  * Copyright IBM Corp. 2007
16  *
17  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
18  */
19
20 #include <linux/types.h>
21 #include <linux/string.h>
22 #include <linux/kvm.h>
23 #include <linux/kvm_host.h>
24 #include <linux/highmem.h>
25 #include <asm/mmu-44x.h>
26 #include <asm/kvm_ppc.h>
27 #include <asm/kvm_44x.h>
28
29 #include "44x_tlb.h"
30
31 #ifndef PPC44x_TLBE_SIZE
32 #define PPC44x_TLBE_SIZE        PPC44x_TLB_4K
33 #endif
34
35 #define PAGE_SIZE_4K (1<<12)
36 #define PAGE_MASK_4K (~(PAGE_SIZE_4K - 1))
37
38 #define PPC44x_TLB_UATTR_MASK \
39         (PPC44x_TLB_U0|PPC44x_TLB_U1|PPC44x_TLB_U2|PPC44x_TLB_U3)
40 #define PPC44x_TLB_USER_PERM_MASK (PPC44x_TLB_UX|PPC44x_TLB_UR|PPC44x_TLB_UW)
41 #define PPC44x_TLB_SUPER_PERM_MASK (PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW)
42
43 static unsigned int kvmppc_tlb_44x_pos;
44
45 #ifdef DEBUG
46 void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
47 {
48         struct kvmppc_44x_tlbe *tlbe;
49         int i;
50
51         printk("vcpu %d TLB dump:\n", vcpu->vcpu_id);
52         printk("| %2s | %3s | %8s | %8s | %8s |\n",
53                         "nr", "tid", "word0", "word1", "word2");
54
55         for (i = 0; i < PPC44x_TLB_SIZE; i++) {
56                 tlbe = &vcpu_44x->guest_tlb[i];
57                 if (tlbe->word0 & PPC44x_TLB_VALID)
58                         printk(" G%2d |  %02X | %08X | %08X | %08X |\n",
59                                i, tlbe->tid, tlbe->word0, tlbe->word1,
60                                tlbe->word2);
61         }
62
63         for (i = 0; i < PPC44x_TLB_SIZE; i++) {
64                 tlbe = &vcpu_44x->shadow_tlb[i];
65                 if (tlbe->word0 & PPC44x_TLB_VALID)
66                         printk(" S%2d | %02X | %08X | %08X | %08X |\n",
67                                i, tlbe->tid, tlbe->word0, tlbe->word1,
68                                tlbe->word2);
69         }
70 }
71 #endif
72
73 static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int usermode)
74 {
75         /* We only care about the guest's permission and user bits. */
76         attrib &= PPC44x_TLB_PERM_MASK|PPC44x_TLB_UATTR_MASK;
77
78         if (!usermode) {
79                 /* Guest is in supervisor mode, so we need to translate guest
80                  * supervisor permissions into user permissions. */
81                 attrib &= ~PPC44x_TLB_USER_PERM_MASK;
82                 attrib |= (attrib & PPC44x_TLB_SUPER_PERM_MASK) << 3;
83         }
84
85         /* Make sure host can always access this memory. */
86         attrib |= PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW;
87
88         /* WIMGE = 0b00100 */
89         attrib |= PPC44x_TLB_M;
90
91         return attrib;
92 }
93
94 /* Search the guest TLB for a matching entry. */
95 int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid,
96                          unsigned int as)
97 {
98         struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
99         int i;
100
101         /* XXX Replace loop with fancy data structures. */
102         for (i = 0; i < PPC44x_TLB_SIZE; i++) {
103                 struct kvmppc_44x_tlbe *tlbe = &vcpu_44x->guest_tlb[i];
104                 unsigned int tid;
105
106                 if (eaddr < get_tlb_eaddr(tlbe))
107                         continue;
108
109                 if (eaddr > get_tlb_end(tlbe))
110                         continue;
111
112                 tid = get_tlb_tid(tlbe);
113                 if (tid && (tid != pid))
114                         continue;
115
116                 if (!get_tlb_v(tlbe))
117                         continue;
118
119                 if (get_tlb_ts(tlbe) != as)
120                         continue;
121
122                 return i;
123         }
124
125         return -1;
126 }
127
128 struct kvmppc_44x_tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu,
129                                                gva_t eaddr)
130 {
131         struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
132         unsigned int as = !!(vcpu->arch.msr & MSR_IS);
133         unsigned int index;
134
135         index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
136         if (index == -1)
137                 return NULL;
138         return &vcpu_44x->guest_tlb[index];
139 }
140
141 struct kvmppc_44x_tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu,
142                                                gva_t eaddr)
143 {
144         struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
145         unsigned int as = !!(vcpu->arch.msr & MSR_DS);
146         unsigned int index;
147
148         index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
149         if (index == -1)
150                 return NULL;
151         return &vcpu_44x->guest_tlb[index];
152 }
153
154 static int kvmppc_44x_tlbe_is_writable(struct kvmppc_44x_tlbe *tlbe)
155 {
156         return tlbe->word2 & (PPC44x_TLB_SW|PPC44x_TLB_UW);
157 }
158
159 static void kvmppc_44x_shadow_release(struct kvm_vcpu *vcpu,
160                                       unsigned int index)
161 {
162         struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
163         struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[index];
164         struct page *page = vcpu_44x->shadow_pages[index];
165
166         if (get_tlb_v(stlbe)) {
167                 if (kvmppc_44x_tlbe_is_writable(stlbe))
168                         kvm_release_page_dirty(page);
169                 else
170                         kvm_release_page_clean(page);
171         }
172 }
173
174 void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu)
175 {
176         int i;
177
178         for (i = 0; i <= tlb_44x_hwater; i++)
179                 kvmppc_44x_shadow_release(vcpu, i);
180 }
181
182 void kvmppc_tlbe_set_modified(struct kvm_vcpu *vcpu, unsigned int i)
183 {
184         struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
185
186         vcpu_44x->shadow_tlb_mod[i] = 1;
187 }
188
189 /**
190  * kvmppc_mmu_map -- create a host mapping for guest memory
191  *
192  * If the guest wanted a larger page than the host supports, only the first
193  * host page is mapped here and the rest are demand faulted.
194  *
195  * If the guest wanted a smaller page than the host page size, we map only the
196  * guest-size page (i.e. not a full host page mapping).
197  *
198  * Caller must ensure that the specified guest TLB entry is safe to insert into
199  * the shadow TLB.
200  */
201 void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, u64 asid,
202                     u32 flags, u32 max_bytes)
203 {
204         struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
205         struct page *new_page;
206         struct kvmppc_44x_tlbe *stlbe;
207         hpa_t hpaddr;
208         gfn_t gfn;
209         unsigned int victim;
210
211         /* Future optimization: don't overwrite the TLB entry containing the
212          * current PC (or stack?). */
213         victim = kvmppc_tlb_44x_pos++;
214         if (kvmppc_tlb_44x_pos > tlb_44x_hwater)
215                 kvmppc_tlb_44x_pos = 0;
216         stlbe = &vcpu_44x->shadow_tlb[victim];
217
218         /* Get reference to new page. */
219         gfn = gpaddr >> PAGE_SHIFT;
220         new_page = gfn_to_page(vcpu->kvm, gfn);
221         if (is_error_page(new_page)) {
222                 printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn);
223                 kvm_release_page_clean(new_page);
224                 return;
225         }
226         hpaddr = page_to_phys(new_page);
227
228         /* Drop reference to old page. */
229         kvmppc_44x_shadow_release(vcpu, victim);
230
231         vcpu_44x->shadow_pages[victim] = new_page;
232
233         /* XXX Make sure (va, size) doesn't overlap any other
234          * entries. 440x6 user manual says the result would be
235          * "undefined." */
236
237         /* XXX what about AS? */
238
239         stlbe->tid = !(asid & 0xff);
240
241         /* Force TS=1 for all guest mappings. */
242         stlbe->word0 = PPC44x_TLB_VALID | PPC44x_TLB_TS;
243
244         if (max_bytes >= PAGE_SIZE) {
245                 /* Guest mapping is larger than or equal to host page size. We can use
246                  * a "native" host mapping. */
247                 stlbe->word0 |= (gvaddr & PAGE_MASK) | PPC44x_TLBE_SIZE;
248         } else {
249                 /* Guest mapping is smaller than host page size. We must restrict the
250                  * size of the mapping to be at most the smaller of the two, but for
251                  * simplicity we fall back to a 4K mapping (this is probably what the
252                  * guest is using anyways). */
253                 stlbe->word0 |= (gvaddr & PAGE_MASK_4K) | PPC44x_TLB_4K;
254
255                 /* 'hpaddr' is a host page, which is larger than the mapping we're
256                  * inserting here. To compensate, we must add the in-page offset to the
257                  * sub-page. */
258                 hpaddr |= gpaddr & (PAGE_MASK ^ PAGE_MASK_4K);
259         }
260
261         stlbe->word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf);
262         stlbe->word2 = kvmppc_44x_tlb_shadow_attrib(flags,
263                                                     vcpu->arch.msr & MSR_PR);
264         kvmppc_tlbe_set_modified(vcpu, victim);
265
266         KVMTRACE_5D(STLB_WRITE, vcpu, victim,
267                         stlbe->tid, stlbe->word0, stlbe->word1, stlbe->word2,
268                         handler);
269 }
270
271 static void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr,
272                                   gva_t eend, u32 asid)
273 {
274         struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
275         unsigned int pid = !(asid & 0xff);
276         int i;
277
278         /* XXX Replace loop with fancy data structures. */
279         for (i = 0; i <= tlb_44x_hwater; i++) {
280                 struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i];
281                 unsigned int tid;
282
283                 if (!get_tlb_v(stlbe))
284                         continue;
285
286                 if (eend < get_tlb_eaddr(stlbe))
287                         continue;
288
289                 if (eaddr > get_tlb_end(stlbe))
290                         continue;
291
292                 tid = get_tlb_tid(stlbe);
293                 if (tid && (tid != pid))
294                         continue;
295
296                 kvmppc_44x_shadow_release(vcpu, i);
297                 stlbe->word0 = 0;
298                 kvmppc_tlbe_set_modified(vcpu, i);
299                 KVMTRACE_5D(STLB_INVAL, vcpu, i,
300                                 stlbe->tid, stlbe->word0, stlbe->word1,
301                                 stlbe->word2, handler);
302         }
303 }
304
305 void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode)
306 {
307         vcpu->arch.shadow_pid = !usermode;
308 }
309
310 void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 new_pid)
311 {
312         struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
313         int i;
314
315         if (unlikely(vcpu->arch.pid == new_pid))
316                 return;
317
318         vcpu->arch.pid = new_pid;
319
320         /* Guest userspace runs with TID=0 mappings and PID=0, to make sure it
321          * can't access guest kernel mappings (TID=1). When we switch to a new
322          * guest PID, which will also use host PID=0, we must discard the old guest
323          * userspace mappings. */
324         for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_tlb); i++) {
325                 struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i];
326
327                 if (get_tlb_tid(stlbe) == 0) {
328                         kvmppc_44x_shadow_release(vcpu, i);
329                         stlbe->word0 = 0;
330                         kvmppc_tlbe_set_modified(vcpu, i);
331                 }
332         }
333 }
334
335 static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
336                              const struct kvmppc_44x_tlbe *tlbe)
337 {
338         gpa_t gpa;
339
340         if (!get_tlb_v(tlbe))
341                 return 0;
342
343         /* Does it match current guest AS? */
344         /* XXX what about IS != DS? */
345         if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
346                 return 0;
347
348         gpa = get_tlb_raddr(tlbe);
349         if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT))
350                 /* Mapping is not for RAM. */
351                 return 0;
352
353         return 1;
354 }
355
356 int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws)
357 {
358         struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
359         gva_t eaddr;
360         u64 asid;
361         struct kvmppc_44x_tlbe *tlbe;
362         unsigned int index;
363
364         index = vcpu->arch.gpr[ra];
365         if (index > PPC44x_TLB_SIZE) {
366                 printk("%s: index %d\n", __func__, index);
367                 kvmppc_dump_vcpu(vcpu);
368                 return EMULATE_FAIL;
369         }
370
371         tlbe = &vcpu_44x->guest_tlb[index];
372
373         /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
374         if (tlbe->word0 & PPC44x_TLB_VALID) {
375                 eaddr = get_tlb_eaddr(tlbe);
376                 asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
377                 kvmppc_mmu_invalidate(vcpu, eaddr, get_tlb_end(tlbe), asid);
378         }
379
380         switch (ws) {
381         case PPC44x_TLB_PAGEID:
382                 tlbe->tid = get_mmucr_stid(vcpu);
383                 tlbe->word0 = vcpu->arch.gpr[rs];
384                 break;
385
386         case PPC44x_TLB_XLAT:
387                 tlbe->word1 = vcpu->arch.gpr[rs];
388                 break;
389
390         case PPC44x_TLB_ATTRIB:
391                 tlbe->word2 = vcpu->arch.gpr[rs];
392                 break;
393
394         default:
395                 return EMULATE_FAIL;
396         }
397
398         if (tlbe_is_host_safe(vcpu, tlbe)) {
399                 gpa_t gpaddr;
400                 u32 flags;
401                 u32 bytes;
402
403                 eaddr = get_tlb_eaddr(tlbe);
404                 gpaddr = get_tlb_raddr(tlbe);
405
406                 /* Use the advertised page size to mask effective and real addrs. */
407                 bytes = get_tlb_bytes(tlbe);
408                 eaddr &= ~(bytes - 1);
409                 gpaddr &= ~(bytes - 1);
410
411                 asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
412                 flags = tlbe->word2 & 0xffff;
413
414                 kvmppc_mmu_map(vcpu, eaddr, gpaddr, asid, flags, bytes);
415         }
416
417         KVMTRACE_5D(GTLB_WRITE, vcpu, index,
418                     tlbe->tid, tlbe->word0, tlbe->word1, tlbe->word2,
419                     handler);
420
421         return EMULATE_DONE;
422 }
423
424 int kvmppc_44x_emul_tlbsx(struct kvm_vcpu *vcpu, u8 rt, u8 ra, u8 rb, u8 rc)
425 {
426         u32 ea;
427         int index;
428         unsigned int as = get_mmucr_sts(vcpu);
429         unsigned int pid = get_mmucr_stid(vcpu);
430
431         ea = vcpu->arch.gpr[rb];
432         if (ra)
433                 ea += vcpu->arch.gpr[ra];
434
435         index = kvmppc_44x_tlb_index(vcpu, ea, pid, as);
436         if (rc) {
437                 if (index < 0)
438                         vcpu->arch.cr &= ~0x20000000;
439                 else
440                         vcpu->arch.cr |= 0x20000000;
441         }
442         vcpu->arch.gpr[rt] = index;
443
444         return EMULATE_DONE;
445 }