ia64/xen-unstable

view xen/arch/ia64/vmx/vmmu.c @ 17202:e6d6595d29f7

[IA64] Additional user of pa_clear_uc()

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
author Alex Williamson <alex.williamson@hp.com>
date Mon Mar 10 11:27:42 2008 -0600 (2008-03-10)
parents 85d25d01d93f
children 7f04cbf2fa52
line source
1 /* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
2 /*
3 * vmmu.c: virtual memory management unit components.
4 * Copyright (c) 2005, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 *
19 * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com)
20 * Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com)
21 */
22 #include <asm/vmx_vcpu.h>
23 #include <asm/vmx_pal_vsa.h>
24 #include <xen/sched-if.h>
25 #include <asm/vhpt.h>
27 static int default_vtlb_sz = DEFAULT_VTLB_SZ;
28 static int default_vhpt_sz = DEFAULT_VHPT_SZ;
30 static void __init parse_vtlb_size(char *s)
31 {
32 int sz = parse_size_and_unit(s, NULL);
34 if (sz > 0) {
35 default_vtlb_sz = fls(sz - 1);
36 /* minimum 16KB (for tag uniqueness) */
37 if (default_vtlb_sz < 14)
38 default_vtlb_sz = 14;
39 }
40 }
42 static void __init parse_vhpt_size(char *s)
43 {
44 int sz = parse_size_and_unit(s, NULL);
45 if (sz > 0) {
46 default_vhpt_sz = fls(sz - 1);
47 default_vhpt_sz = canonicalize_vhpt_size(default_vhpt_sz);
48 }
49 }
51 custom_param("vti_vtlb_size", parse_vtlb_size);
52 custom_param("vti_vhpt_size", parse_vhpt_size);
55 static int init_domain_vhpt(struct vcpu *v)
56 {
57 int rc;
58 u64 size = v->domain->arch.hvm_domain.params[HVM_PARAM_VHPT_SIZE];
60 if (size == 0)
61 size = default_vhpt_sz;
62 else
63 size = canonicalize_vhpt_size(size);
65 rc = thash_alloc(&(v->arch.vhpt), size, "vhpt");
66 v->arch.arch_vmx.mpta = v->arch.vhpt.pta.val;
67 return rc;
68 }
71 static void free_domain_vhpt(struct vcpu *v)
72 {
73 if (v->arch.vhpt.hash)
74 thash_free(&(v->arch.vhpt));
75 }
77 int init_domain_tlb(struct vcpu *v)
78 {
79 int rc;
81 rc = init_domain_vhpt(v);
82 if (rc)
83 return rc;
85 rc = thash_alloc(&(v->arch.vtlb), default_vtlb_sz, "vtlb");
86 if (rc) {
87 free_domain_vhpt(v);
88 return rc;
89 }
91 return 0;
92 }
95 void free_domain_tlb(struct vcpu *v)
96 {
97 if (v->arch.vtlb.hash)
98 thash_free(&(v->arch.vtlb));
100 free_domain_vhpt(v);
101 }
104 int vhpt_enabled(VCPU *vcpu, uint64_t vadr, vhpt_ref_t ref)
105 {
106 ia64_rr vrr;
107 PTA vpta;
108 IA64_PSR vpsr;
110 vpsr.val = VCPU(vcpu, vpsr);
111 vcpu_get_rr(vcpu, vadr, &vrr.rrval);
112 vpta.val = vmx_vcpu_get_pta(vcpu);
114 if ( vrr.ve & vpta.ve ) {
115 switch ( ref ) {
116 case DATA_REF:
117 case NA_REF:
118 return vpsr.dt;
119 case INST_REF:
120 return vpsr.dt && vpsr.it && vpsr.ic;
121 case RSE_REF:
122 return vpsr.dt && vpsr.rt;
124 }
125 }
126 return 0;
127 }
130 int unimplemented_gva(VCPU *vcpu,u64 vadr)
131 {
132 #if 0
133 int bit=vcpu->domain->arch.imp_va_msb;
134 u64 ladr =(vadr<<3)>>(3+bit);
135 if(!ladr||ladr==(1U<<(61-bit))-1){
136 return 0;
137 }else{
138 return 1;
139 }
140 #else
141 return 0;
142 #endif
143 }
146 /*
147 * Fetch guest bundle code.
148 * INPUT:
149 * gip: guest ip
150 * pbundle: used to return fetched bundle.
151 */
152 unsigned long
153 fetch_code(VCPU *vcpu, u64 gip, IA64_BUNDLE *pbundle)
154 {
155 u64 gpip=0; // guest physical IP
156 u64 *vpa;
157 thash_data_t *tlb;
158 u64 mfn, maddr;
159 struct page_info* page;
161 again:
162 if ( !(VCPU(vcpu, vpsr) & IA64_PSR_IT) ) { // I-side physical mode
163 gpip = pa_clear_uc(gip); // clear UC bit
164 }
165 else {
166 tlb = vtlb_lookup(vcpu, gip, ISIDE_TLB);
167 // if( tlb == NULL )
168 // tlb = vtlb_lookup(vcpu, gip, DSIDE_TLB );
169 if (tlb)
170 gpip = (tlb->ppn >>(tlb->ps-12)<<tlb->ps) | ( gip & (PSIZE(tlb->ps)-1) );
171 }
172 if( gpip){
173 mfn = gmfn_to_mfn(vcpu->domain, gpip >>PAGE_SHIFT);
174 if (mfn == INVALID_MFN)
175 panic_domain(vcpu_regs(vcpu), "fetch_code: invalid memory\n");
176 maddr = (mfn << PAGE_SHIFT) | (gpip & (PAGE_SIZE - 1));
177 }else{
178 tlb = vhpt_lookup(gip);
179 if (tlb == NULL) {
180 ia64_ptcl(gip, ARCH_PAGE_SHIFT << 2);
181 return IA64_RETRY;
182 }
183 maddr = (tlb->ppn >> (tlb->ps - 12) << tlb->ps) |
184 (gip & (PSIZE(tlb->ps) - 1));
185 mfn = maddr >> PAGE_SHIFT;
186 }
188 page = mfn_to_page(mfn);
189 if (get_page(page, vcpu->domain) == 0) {
190 if (page_get_owner(page) != vcpu->domain) {
191 // This page might be a page granted by another domain.
192 panic_domain(NULL, "domain tries to execute foreign domain "
193 "page which might be mapped by grant table.\n");
194 }
195 goto again;
196 }
197 vpa = (u64 *)__va(maddr);
199 pbundle->i64[0] = *vpa++;
200 pbundle->i64[1] = *vpa;
201 put_page(page);
202 return IA64_NO_FAULT;
203 }
205 IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, u64 pte, u64 itir, u64 ifa)
206 {
207 #ifdef VTLB_DEBUG
208 int slot;
209 u64 ps, va;
210 ps = itir_ps(itir);
211 va = PAGEALIGN(ifa, ps);
212 slot = vtr_find_overlap(vcpu, va, ps, ISIDE_TLB);
213 if (slot >=0) {
214 // generate MCA.
215 panic_domain(vcpu_regs(vcpu),"Tlb conflict!!");
216 return IA64_FAULT;
217 }
218 #endif //VTLB_DEBUG
219 pte &= ~PAGE_FLAGS_RV_MASK;
220 thash_purge_and_insert(vcpu, pte, itir, ifa, ISIDE_TLB);
221 return IA64_NO_FAULT;
222 }
224 IA64FAULT vmx_vcpu_itc_d(VCPU *vcpu, u64 pte, u64 itir, u64 ifa)
225 {
226 #ifdef VTLB_DEBUG
227 int slot;
228 u64 ps, va;
229 ps = itir_ps(itir);
230 va = PAGEALIGN(ifa, ps);
231 slot = vtr_find_overlap(vcpu, va, ps, DSIDE_TLB);
232 if (slot >=0) {
233 // generate MCA.
234 panic_domain(vcpu_regs(vcpu),"Tlb conflict!!");
235 return IA64_FAULT;
236 }
237 #endif //VTLB_DEBUG
238 pte &= ~PAGE_FLAGS_RV_MASK;
239 thash_purge_and_insert(vcpu, pte, itir, ifa, DSIDE_TLB);
240 return IA64_NO_FAULT;
242 }
247 IA64FAULT vmx_vcpu_itr_i(VCPU *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa)
248 {
249 #ifdef VTLB_DEBUG
250 int index;
251 #endif
252 u64 ps, va, rid;
253 thash_data_t * p_itr;
254 ps = itir_ps(itir);
255 va = PAGEALIGN(ifa, ps);
256 #ifdef VTLB_DEBUG
257 index = vtr_find_overlap(vcpu, va, ps, ISIDE_TLB);
258 if (index >=0) {
259 // generate MCA.
260 panic_domain(vcpu_regs(vcpu),"Tlb conflict!!");
261 return IA64_FAULT;
262 }
263 thash_purge_entries(vcpu, va, ps);
264 #endif
266 if (slot >= NITRS) {
267 panic_domain(NULL, "bad itr.i slot (%ld)", slot);
268 return IA64_FAULT;
269 }
271 pte &= ~PAGE_FLAGS_RV_MASK;
272 vcpu_get_rr(vcpu, va, &rid);
273 rid = rid& RR_RID_MASK;
274 p_itr = (thash_data_t *)&vcpu->arch.itrs[slot];
275 vmx_vcpu_set_tr(p_itr, pte, itir, va, rid);
276 vcpu_quick_region_set(PSCBX(vcpu,itr_regions),va);
277 return IA64_NO_FAULT;
278 }
281 IA64FAULT vmx_vcpu_itr_d(VCPU *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa)
282 {
283 #ifdef VTLB_DEBUG
284 int index;
285 #endif
286 u64 gpfn, gpte;
287 u64 ps, va, rid;
288 thash_data_t * p_dtr;
290 ps = itir_ps(itir);
291 va = PAGEALIGN(ifa, ps);
292 #ifdef VTLB_DEBUG
293 index = vtr_find_overlap(vcpu, va, ps, DSIDE_TLB);
294 if (index>=0) {
295 // generate MCA.
296 panic_domain(vcpu_regs(vcpu),"Tlb conflict!!");
297 return IA64_FAULT;
298 }
299 #endif
301 if (slot >= NDTRS) {
302 panic_domain(NULL, "bad itr.d slot (%ld)", slot);
303 return IA64_FAULT;
304 }
306 pte &= ~PAGE_FLAGS_RV_MASK;
308 /* This is a bad workaround
309 In Linux, region 7 use 16M pagesize and is identity mapped.
310 VHPT page size is 16K in XEN. If purge VHPT while guest insert 16M,
311 it will iteratively purge VHPT 1024 times, which makes XEN/IPF very
312 slow. XEN doesn't purge VHPT
313 */
314 if (ps != _PAGE_SIZE_16M)
315 thash_purge_entries(vcpu, va, ps);
316 gpfn = (pte & _PAGE_PPN_MASK)>> PAGE_SHIFT;
317 gpte = lookup_domain_mpa(vcpu->domain, gpfn, NULL);
318 if (gpte & GPFN_IO_MASK)
319 pte |= VTLB_PTE_IO;
320 vcpu_get_rr(vcpu, va, &rid);
321 rid &= RR_RID_MASK;
322 p_dtr = (thash_data_t *)&vcpu->arch.dtrs[slot];
323 vmx_vcpu_set_tr((thash_data_t *)&vcpu->arch.dtrs[slot], pte, itir, va, rid);
324 vcpu_quick_region_set(PSCBX(vcpu,dtr_regions),va);
325 return IA64_NO_FAULT;
326 }
330 IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,u64 ifa, u64 ps)
331 {
332 int index;
333 u64 va;
335 va = PAGEALIGN(ifa, ps);
336 while ((index = vtr_find_overlap(vcpu, va, ps, DSIDE_TLB)) >= 0) {
337 vcpu->arch.dtrs[index].pte.p=0;
338 }
339 thash_purge_entries(vcpu, va, ps);
340 return IA64_NO_FAULT;
341 }
343 IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu, u64 ifa, u64 ps)
344 {
345 int index;
346 u64 va;
348 va = PAGEALIGN(ifa, ps);
349 while ((index = vtr_find_overlap(vcpu, va, ps, ISIDE_TLB)) >= 0) {
350 vcpu->arch.itrs[index].pte.p=0;
351 }
352 thash_purge_entries(vcpu, va, ps);
353 return IA64_NO_FAULT;
354 }
356 IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, u64 va, u64 ps)
357 {
358 va = PAGEALIGN(va, ps);
359 thash_purge_entries(vcpu, va, ps);
360 return IA64_NO_FAULT;
361 }
364 IA64FAULT vmx_vcpu_ptc_e(VCPU *vcpu, u64 va)
365 {
366 thash_purge_all(vcpu);
367 return IA64_NO_FAULT;
368 }
370 IA64FAULT vmx_vcpu_ptc_g(VCPU *vcpu, u64 va, u64 ps)
371 {
372 return vmx_vcpu_ptc_ga(vcpu, va, ps);
373 }
374 /*
375 IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu, u64 va, u64 ps)
376 {
377 vmx_vcpu_ptc_l(vcpu, va, ps);
378 return IA64_NO_FAULT;
379 }
380 */
381 struct ptc_ga_args {
382 unsigned long vadr;
383 unsigned long rid;
384 unsigned long ps;
385 struct vcpu *vcpu;
386 };
388 static void ptc_ga_remote_func (void *varg)
389 {
390 u64 oldrid, moldrid, mpta, oldpsbits, vadr, flags;
391 struct ptc_ga_args *args = (struct ptc_ga_args *)varg;
392 VCPU *v = args->vcpu;
393 int cpu = v->processor;
395 vadr = args->vadr;
397 /* Try again if VCPU has migrated. */
398 if (cpu != current->processor)
399 return;
400 local_irq_save(flags);
401 if (!spin_trylock(&per_cpu(schedule_data, cpu).schedule_lock))
402 goto bail2;
403 if (v->processor != cpu)
404 goto bail1;
405 oldrid = VMX(v, vrr[0]);
406 VMX(v, vrr[0]) = args->rid;
407 oldpsbits = VMX(v, psbits[0]);
408 VMX(v, psbits[0]) = VMX(v, psbits[REGION_NUMBER(vadr)]);
409 moldrid = ia64_get_rr(0x0);
410 ia64_set_rr(0x0,vrrtomrr(v,args->rid));
411 mpta = ia64_get_pta();
412 ia64_set_pta(v->arch.arch_vmx.mpta&(~1));
413 ia64_srlz_d();
414 vadr = PAGEALIGN(vadr, args->ps);
415 thash_purge_entries_remote(v, vadr, args->ps);
416 VMX(v, vrr[0]) = oldrid;
417 VMX(v, psbits[0]) = oldpsbits;
418 ia64_set_rr(0x0,moldrid);
419 ia64_set_pta(mpta);
420 ia64_dv_serialize_data();
421 args->vcpu = NULL;
422 bail1:
423 spin_unlock(&per_cpu(schedule_data, cpu).schedule_lock);
424 bail2:
425 local_irq_restore(flags);
426 }
429 IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu, u64 va, u64 ps)
430 {
432 struct domain *d = vcpu->domain;
433 struct vcpu *v;
434 struct ptc_ga_args args;
435 int cpu;
437 args.vadr = va;
438 vcpu_get_rr(vcpu, va, &args.rid);
439 args.ps = ps;
440 for_each_vcpu (d, v) {
441 if (!v->is_initialised)
442 continue;
444 if (v == vcpu) {
445 vmx_vcpu_ptc_l(v, va, ps);
446 continue;
447 }
449 args.vcpu = v;
450 do {
451 cpu = v->processor;
452 if (cpu != current->processor) {
453 spin_unlock_wait(&per_cpu(schedule_data, cpu).schedule_lock);
454 /* Flush VHPT on remote processors. */
455 smp_call_function_single(cpu, &ptc_ga_remote_func,
456 &args, 0, 1);
457 } else {
458 ptc_ga_remote_func(&args);
459 }
460 } while (args.vcpu != NULL);
461 }
462 return IA64_NO_FAULT;
463 }
466 u64 vmx_vcpu_thash(VCPU *vcpu, u64 vadr)
467 {
468 PTA vpta;
469 ia64_rr vrr;
470 u64 pval;
471 u64 vhpt_offset;
472 u64 mask;
474 vpta.val = vmx_vcpu_get_pta(vcpu);
475 vcpu_get_rr(vcpu, vadr, &vrr.rrval);
476 mask = (1UL << vpta.size) - 1;
477 if (vpta.vf) {
478 vadr = (vadr & 0x1fffffffffffffffUL) >> vrr.ps;
479 vhpt_offset = vadr ^ vrr.rid;
480 pval = (vpta.val & ~0x7fffUL) + ((vhpt_offset << 5) & mask);
481 } else {
482 vhpt_offset=((vadr >> vrr.ps) << 3) & mask;
483 pval = (vadr & VRN_MASK) |
484 (vpta.val << 3 >> (vpta.size + 3) << vpta.size) |
485 vhpt_offset;
486 }
487 return pval;
488 }
491 u64 vmx_vcpu_ttag(VCPU *vcpu, u64 vadr)
492 {
493 ia64_rr vrr;
494 PTA vpta;
495 u64 pval;
496 u64 rid;
497 vpta.val = vmx_vcpu_get_pta(vcpu);
498 vcpu_get_rr(vcpu, vadr, &vrr.rrval);
499 if(vpta.vf){
500 vadr = (vadr & 0x1fffffffffffffffUL) >> vrr.ps;
501 rid = vrr.rid;
502 pval = vadr ^ (rid << 39);
503 }else{
504 pval = 1;
505 }
506 return pval;
507 }
511 IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, u64 vadr, u64 *padr)
512 {
513 thash_data_t *data;
514 ISR visr,pt_isr;
515 REGS *regs;
516 u64 vhpt_adr, madr;
517 IA64_PSR vpsr;
519 regs = vcpu_regs(vcpu);
520 pt_isr.val = VMX(vcpu, cr_isr);
521 visr.val = 0;
522 visr.ei = pt_isr.ei;
523 visr.ir = pt_isr.ir;
524 vpsr.val = VCPU(vcpu, vpsr);
525 visr.na = 1;
527 /* First look in VTLB. */
528 data = vtlb_lookup(vcpu, vadr, DSIDE_TLB);
529 if (data) {
530 if (data->p == 0) {
531 vcpu_set_isr(vcpu,visr.val);
532 data_page_not_present(vcpu, vadr);
533 return IA64_FAULT;
534 } else if (data->ma == VA_MATTR_NATPAGE) {
535 vcpu_set_isr(vcpu, visr.val);
536 dnat_page_consumption(vcpu, vadr);
537 return IA64_FAULT;
538 } else {
539 *padr = ((data->ppn >> (data->ps - 12)) << data->ps) |
540 (vadr & (PSIZE(data->ps) - 1));
541 return IA64_NO_FAULT;
542 }
543 }
545 /* Look in mVHPT. */
546 data = vhpt_lookup(vadr);
547 if (data) {
548 if (data->p == 0) {
549 vcpu_set_isr(vcpu,visr.val);
550 data_page_not_present(vcpu, vadr);
551 return IA64_FAULT;
552 } else if (data->ma == VA_MATTR_NATPAGE) {
553 vcpu_set_isr(vcpu, visr.val);
554 dnat_page_consumption(vcpu, vadr);
555 return IA64_FAULT;
556 } else {
557 madr = (data->ppn >> (data->ps - 12) << data->ps) |
558 (vadr & (PSIZE(data->ps) - 1));
559 *padr = __mpa_to_gpa(madr);
560 return IA64_NO_FAULT;
561 }
562 }
564 /* If VHPT is not enabled, inject fault. */
565 if (!vhpt_enabled(vcpu, vadr, NA_REF)) {
566 if (vpsr.ic) {
567 vcpu_set_isr(vcpu, visr.val);
568 alt_dtlb(vcpu, vadr);
569 return IA64_FAULT;
570 } else {
571 nested_dtlb(vcpu);
572 return IA64_FAULT;
573 }
574 }
576 /* Get gVHPT entry. */
577 vhpt_adr = vmx_vcpu_thash(vcpu, vadr);
578 data = vtlb_lookup(vcpu, vhpt_adr, DSIDE_TLB);
579 if (data) {
580 /* FIXME: we should read gadr from the entry! */
581 if (vpsr.ic) {
582 vcpu_set_isr(vcpu, visr.val);
583 dtlb_fault(vcpu, vadr);
584 return IA64_FAULT;
585 } else {
586 nested_dtlb(vcpu);
587 return IA64_FAULT;
588 }
589 } else {
590 if (vpsr.ic) {
591 vcpu_set_isr(vcpu, visr.val);
592 dvhpt_fault(vcpu, vadr);
593 return IA64_FAULT;
594 } else {
595 nested_dtlb(vcpu);
596 return IA64_FAULT;
597 }
598 }
599 }
601 u64 vmx_vcpu_tak(VCPU *vcpu, u64 vadr)
602 {
603 thash_data_t *data;
604 u64 key;
606 if (unimplemented_gva(vcpu, vadr)) {
607 key = 1;
608 return key;
609 }
611 data = vtlb_lookup(vcpu, vadr, DSIDE_TLB);
612 if (data) {
613 if (data->p)
614 return data->key << 8;
615 else
616 return 1;
617 }
619 data = vhpt_lookup(vadr);
620 if (data) {
621 if (data->p)
622 return data->key << 8; /* FIXME: possible mangling/masking. */
623 else
624 return 1;
625 }
627 if (!vhpt_enabled(vcpu, vadr, NA_REF))
628 return 1;
630 /* FIXME: look in the guest VHPT. */
631 return 1;
632 }