direct-io.hg

view xen/arch/x86/hvm/hvm.c @ 12350:5a4517468f4f

[HVM] Remove HVM halt timer. It's no longer needed since interrupts
can wake it up now.

Signed-off-by: Xin Li <xin.b.li@intel.com>
author kfraser@localhost.localdomain
date Fri Nov 10 11:01:15 2006 +0000 (2006-11-10)
parents 6c975e642719
children f78bfe7bff73
line source
1 /*
2 * hvm.c: Common hardware virtual machine abstractions.
3 *
4 * Copyright (c) 2004, Intel Corporation.
5 * Copyright (c) 2005, International Business Machines Corporation.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place - Suite 330, Boston, MA 02111-1307 USA.
19 */
21 #include <xen/config.h>
22 #include <xen/init.h>
23 #include <xen/lib.h>
24 #include <xen/trace.h>
25 #include <xen/sched.h>
26 #include <xen/irq.h>
27 #include <xen/softirq.h>
28 #include <xen/domain.h>
29 #include <xen/domain_page.h>
30 #include <xen/hypercall.h>
31 #include <xen/guest_access.h>
32 #include <xen/event.h>
33 #include <xen/shadow.h>
34 #include <asm/current.h>
35 #include <asm/e820.h>
36 #include <asm/io.h>
37 #include <asm/shadow.h>
38 #include <asm/regs.h>
39 #include <asm/cpufeature.h>
40 #include <asm/processor.h>
41 #include <asm/types.h>
42 #include <asm/msr.h>
43 #include <asm/mc146818rtc.h>
44 #include <asm/spinlock.h>
45 #include <asm/hvm/hvm.h>
46 #include <asm/hvm/vpt.h>
47 #include <asm/hvm/support.h>
48 #include <public/sched.h>
49 #include <public/hvm/ioreq.h>
50 #include <public/version.h>
51 #include <public/memory.h>
53 int hvm_enabled = 0;
55 unsigned int opt_hvm_debug_level = 0;
56 integer_param("hvm_debug", opt_hvm_debug_level);
58 struct hvm_function_table hvm_funcs;
60 void hvm_stts(struct vcpu *v)
61 {
62 /* FPU state already dirty? Then no need to setup_fpu() lazily. */
63 if ( !test_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags) )
64 hvm_funcs.stts(v);
65 }
67 void hvm_set_guest_time(struct vcpu *v, u64 gtime)
68 {
69 u64 host_tsc;
71 rdtscll(host_tsc);
73 v->arch.hvm_vcpu.cache_tsc_offset = gtime - host_tsc;
74 hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
75 }
77 void hvm_do_resume(struct vcpu *v)
78 {
79 ioreq_t *p;
80 struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
82 hvm_stts(v);
84 /* Pick up the elapsed PIT ticks and re-enable pit_timer. */
85 if ( pt->enabled && (v->vcpu_id == pt->bind_vcpu) && pt->first_injected )
86 {
87 if ( v->arch.hvm_vcpu.guest_time )
88 {
89 hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
90 v->arch.hvm_vcpu.guest_time = 0;
91 }
92 pickup_deactive_ticks(pt);
93 }
95 /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
96 p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
97 while ( p->state != STATE_IOREQ_NONE )
98 {
99 switch ( p->state )
100 {
101 case STATE_IORESP_READY: /* IORESP_READY -> NONE */
102 hvm_io_assist(v);
103 break;
104 case STATE_IOREQ_READY: /* IOREQ_{READY,INPROCESS} -> IORESP_READY */
105 case STATE_IOREQ_INPROCESS:
106 wait_on_xen_event_channel(v->arch.hvm_vcpu.xen_port,
107 (p->state != STATE_IOREQ_READY) &&
108 (p->state != STATE_IOREQ_INPROCESS));
109 break;
110 default:
111 gdprintk(XENLOG_ERR, "Weird HVM iorequest state %d.\n", p->state);
112 domain_crash_synchronous();
113 }
114 }
115 }
117 int hvm_domain_initialise(struct domain *d)
118 {
119 struct hvm_domain *platform = &d->arch.hvm_domain;
120 int rc;
122 if ( !hvm_enabled )
123 {
124 gdprintk(XENLOG_WARNING, "Attempt to create a HVM guest "
125 "on a non-VT/AMDV platform.\n");
126 return -EINVAL;
127 }
129 spin_lock_init(&d->arch.hvm_domain.pbuf_lock);
130 spin_lock_init(&d->arch.hvm_domain.round_robin_lock);
131 spin_lock_init(&d->arch.hvm_domain.buffered_io_lock);
133 rc = shadow_enable(d, SHM2_refcounts|SHM2_translate|SHM2_external);
134 if ( rc != 0 )
135 return rc;
137 pic_init(&platform->vpic, pic_irq_request, &platform->interrupt_request);
138 register_pic_io_hook(d);
140 vioapic_init(d);
142 return 0;
143 }
145 void hvm_domain_destroy(struct domain *d)
146 {
147 kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
148 rtc_deinit(d);
149 pmtimer_deinit(d);
151 if ( d->arch.hvm_domain.shared_page_va )
152 unmap_domain_page_global(
153 (void *)d->arch.hvm_domain.shared_page_va);
155 if ( d->arch.hvm_domain.buffered_io_va )
156 unmap_domain_page_global((void *)d->arch.hvm_domain.buffered_io_va);
157 }
159 int hvm_vcpu_initialise(struct vcpu *v)
160 {
161 struct hvm_domain *platform;
162 int rc;
164 if ( (rc = vlapic_init(v)) != 0 )
165 return rc;
167 if ( (rc = hvm_funcs.vcpu_initialise(v)) != 0 )
168 {
169 vlapic_destroy(v);
170 return rc;
171 }
173 /* Create ioreq event channel. */
174 v->arch.hvm_vcpu.xen_port = alloc_unbound_xen_event_channel(v, 0);
175 if ( get_sp(v->domain) && get_vio(v->domain, v->vcpu_id) )
176 get_vio(v->domain, v->vcpu_id)->vp_eport =
177 v->arch.hvm_vcpu.xen_port;
179 if ( v->vcpu_id != 0 )
180 return 0;
182 /* XXX Below should happen in hvm_domain_initialise(). */
183 platform = &v->domain->arch.hvm_domain;
185 init_timer(&platform->pl_time.periodic_tm.timer,
186 pt_timer_fn, v, v->processor);
187 pit_init(v, cpu_khz);
188 rtc_init(v, RTC_PORT(0), RTC_IRQ);
189 pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS);
191 /* Init guest TSC to start from zero. */
192 hvm_set_guest_time(v, 0);
194 return 0;
195 }
197 void hvm_vcpu_destroy(struct vcpu *v)
198 {
199 vlapic_destroy(v);
200 hvm_funcs.vcpu_destroy(v);
202 /* Event channel is already freed by evtchn_destroy(). */
203 /*free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);*/
204 }
206 void pic_irq_request(void *data, int level)
207 {
208 int *interrupt_request = data;
209 *interrupt_request = level;
210 }
212 u64 hvm_get_guest_time(struct vcpu *v)
213 {
214 u64 host_tsc;
216 rdtscll(host_tsc);
217 return host_tsc + v->arch.hvm_vcpu.cache_tsc_offset;
218 }
220 int cpu_get_interrupt(struct vcpu *v, int *type)
221 {
222 int intno;
223 struct vpic *vpic = domain_vpic(v->domain);
224 unsigned long flags;
226 if ( (intno = cpu_get_apic_interrupt(v, type)) != -1 ) {
227 /* set irq request if a PIC irq is still pending */
228 /* XXX: improve that */
229 spin_lock_irqsave(&vpic->lock, flags);
230 pic_update_irq(vpic);
231 spin_unlock_irqrestore(&vpic->lock, flags);
232 return intno;
233 }
234 /* read the irq from the PIC */
235 if ( v->vcpu_id == 0 && (intno = cpu_get_pic_interrupt(v, type)) != -1 )
236 return intno;
238 return -1;
239 }
241 static void hvm_vcpu_down(void)
242 {
243 struct vcpu *v = current;
244 struct domain *d = v->domain;
245 int online_count = 0;
247 gdprintk(XENLOG_INFO, "DOM%d/VCPU%d: going offline.\n",
248 d->domain_id, v->vcpu_id);
250 /* Doesn't halt us immediately, but we'll never return to guest context. */
251 set_bit(_VCPUF_down, &v->vcpu_flags);
252 vcpu_sleep_nosync(v);
254 /* Any other VCPUs online? ... */
255 LOCK_BIGLOCK(d);
256 for_each_vcpu ( d, v )
257 if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
258 online_count++;
259 UNLOCK_BIGLOCK(d);
261 /* ... Shut down the domain if not. */
262 if ( online_count == 0 )
263 {
264 gdprintk(XENLOG_INFO, "DOM%d: all CPUs offline -- powering off.\n",
265 d->domain_id);
266 domain_shutdown(d, SHUTDOWN_poweroff);
267 }
268 }
270 void hvm_hlt(unsigned long rflags)
271 {
272 /*
273 * If we halt with interrupts disabled, that's a pretty sure sign that we
274 * want to shut down. In a real processor, NMIs are the only way to break
275 * out of this.
276 */
277 if ( unlikely(!(rflags & X86_EFLAGS_IF)) )
278 return hvm_vcpu_down();
280 do_sched_op_compat(SCHEDOP_block, 0);
281 }
283 /*
284 * __hvm_copy():
285 * @buf = hypervisor buffer
286 * @addr = guest physical address to copy to/from
287 * @size = number of bytes to copy
288 * @dir = copy *to* guest (TRUE) or *from* guest (FALSE)?
289 * Returns number of bytes failed to copy (0 == complete success).
290 */
291 static int __hvm_copy(void *buf, paddr_t addr, int size, int dir)
292 {
293 unsigned long mfn;
294 char *p;
295 int count, todo;
297 todo = size;
298 while ( todo > 0 )
299 {
300 count = min_t(int, PAGE_SIZE - (addr & ~PAGE_MASK), todo);
302 mfn = get_mfn_from_gpfn(addr >> PAGE_SHIFT);
303 if ( mfn == INVALID_MFN )
304 return todo;
306 p = (char *)map_domain_page(mfn) + (addr & ~PAGE_MASK);
308 if ( dir )
309 memcpy(p, buf, count); /* dir == TRUE: *to* guest */
310 else
311 memcpy(buf, p, count); /* dir == FALSE: *from guest */
313 unmap_domain_page(p);
315 addr += count;
316 buf += count;
317 todo -= count;
318 }
320 return 0;
321 }
323 int hvm_copy_to_guest_phys(paddr_t paddr, void *buf, int size)
324 {
325 return __hvm_copy(buf, paddr, size, 1);
326 }
328 int hvm_copy_from_guest_phys(void *buf, paddr_t paddr, int size)
329 {
330 return __hvm_copy(buf, paddr, size, 0);
331 }
333 int hvm_copy_to_guest_virt(unsigned long vaddr, void *buf, int size)
334 {
335 return __hvm_copy(buf, shadow_gva_to_gpa(current, vaddr), size, 1);
336 }
338 int hvm_copy_from_guest_virt(void *buf, unsigned long vaddr, int size)
339 {
340 return __hvm_copy(buf, shadow_gva_to_gpa(current, vaddr), size, 0);
341 }
343 /* HVM specific printbuf. Mostly used for hvmloader chit-chat. */
344 void hvm_print_line(struct vcpu *v, const char c)
345 {
346 struct hvm_domain *hd = &v->domain->arch.hvm_domain;
348 spin_lock(&hd->pbuf_lock);
349 hd->pbuf[hd->pbuf_idx++] = c;
350 if ( (hd->pbuf_idx == (sizeof(hd->pbuf) - 2)) || (c == '\n') )
351 {
352 if ( c != '\n' )
353 hd->pbuf[hd->pbuf_idx++] = '\n';
354 hd->pbuf[hd->pbuf_idx] = '\0';
355 printk(XENLOG_G_DEBUG "HVM%u: %s", v->domain->domain_id, hd->pbuf);
356 hd->pbuf_idx = 0;
357 }
358 spin_unlock(&hd->pbuf_lock);
359 }
361 typedef unsigned long hvm_hypercall_t(
362 unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
364 #define HYPERCALL(x) \
365 [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x
366 #define HYPERCALL_COMPAT32(x) \
367 [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x ## _compat32
369 #if defined(__i386__)
371 static hvm_hypercall_t *hvm_hypercall_table[NR_hypercalls] = {
372 HYPERCALL(memory_op),
373 HYPERCALL(multicall),
374 HYPERCALL(xen_version),
375 HYPERCALL(event_channel_op),
376 HYPERCALL(hvm_op)
377 };
379 void hvm_do_hypercall(struct cpu_user_regs *pregs)
380 {
381 if ( unlikely(ring_3(pregs)) )
382 {
383 pregs->eax = -EPERM;
384 return;
385 }
387 if ( (pregs->eax >= NR_hypercalls) || !hvm_hypercall_table[pregs->eax] )
388 {
389 gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d did a bad hypercall %d.\n",
390 current->domain->domain_id, current->vcpu_id,
391 pregs->eax);
392 pregs->eax = -ENOSYS;
393 return;
394 }
396 pregs->eax = hvm_hypercall_table[pregs->eax](
397 pregs->ebx, pregs->ecx, pregs->edx, pregs->esi, pregs->edi);
398 }
400 #else /* defined(__x86_64__) */
402 static long do_memory_op_compat32(int cmd, XEN_GUEST_HANDLE(void) arg)
403 {
404 extern long do_add_to_physmap(struct xen_add_to_physmap *xatp);
405 long rc;
407 switch ( cmd )
408 {
409 case XENMEM_add_to_physmap:
410 {
411 struct {
412 domid_t domid;
413 uint32_t space;
414 uint32_t idx;
415 uint32_t gpfn;
416 } u;
417 struct xen_add_to_physmap h;
419 if ( copy_from_guest(&u, arg, 1) )
420 return -EFAULT;
422 h.domid = u.domid;
423 h.space = u.space;
424 h.idx = u.idx;
425 h.gpfn = u.gpfn;
427 this_cpu(guest_handles_in_xen_space) = 1;
428 rc = do_memory_op(cmd, guest_handle_from_ptr(&h, void));
429 this_cpu(guest_handles_in_xen_space) = 0;
431 break;
432 }
434 default:
435 gdprintk(XENLOG_WARNING, "memory_op %d.\n", cmd);
436 rc = -ENOSYS;
437 break;
438 }
440 return rc;
441 }
443 static hvm_hypercall_t *hvm_hypercall64_table[NR_hypercalls] = {
444 HYPERCALL(memory_op),
445 HYPERCALL(xen_version),
446 HYPERCALL(hvm_op),
447 HYPERCALL(event_channel_op)
448 };
450 static hvm_hypercall_t *hvm_hypercall32_table[NR_hypercalls] = {
451 HYPERCALL_COMPAT32(memory_op),
452 HYPERCALL(xen_version),
453 HYPERCALL(hvm_op),
454 HYPERCALL(event_channel_op)
455 };
457 void hvm_do_hypercall(struct cpu_user_regs *pregs)
458 {
459 if ( unlikely(ring_3(pregs)) )
460 {
461 pregs->rax = -EPERM;
462 return;
463 }
465 pregs->rax = (uint32_t)pregs->eax; /* mask in case compat32 caller */
466 if ( (pregs->rax >= NR_hypercalls) || !hvm_hypercall64_table[pregs->rax] )
467 {
468 gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d did a bad hypercall %ld.\n",
469 current->domain->domain_id, current->vcpu_id,
470 pregs->rax);
471 pregs->rax = -ENOSYS;
472 return;
473 }
475 if ( current->arch.shadow.mode->guest_levels == 4 )
476 {
477 pregs->rax = hvm_hypercall64_table[pregs->rax](pregs->rdi,
478 pregs->rsi,
479 pregs->rdx,
480 pregs->r10,
481 pregs->r8);
482 }
483 else
484 {
485 pregs->eax = hvm_hypercall32_table[pregs->eax]((uint32_t)pregs->ebx,
486 (uint32_t)pregs->ecx,
487 (uint32_t)pregs->edx,
488 (uint32_t)pregs->esi,
489 (uint32_t)pregs->edi);
490 }
491 }
493 #endif /* defined(__x86_64__) */
495 /* Initialise a hypercall transfer page for a VMX domain using
496 paravirtualised drivers. */
497 void hvm_hypercall_page_initialise(struct domain *d,
498 void *hypercall_page)
499 {
500 hvm_funcs.init_hypercall_page(d, hypercall_page);
501 }
504 /*
505 * only called in HVM domain BSP context
506 * when booting, vcpuid is always equal to apic_id
507 */
508 int hvm_bringup_ap(int vcpuid, int trampoline_vector)
509 {
510 struct vcpu *bsp = current, *v;
511 struct domain *d = bsp->domain;
512 struct vcpu_guest_context *ctxt;
513 int rc = 0;
515 BUG_ON(!is_hvm_domain(d));
517 if ( bsp->vcpu_id != 0 )
518 {
519 gdprintk(XENLOG_ERR, "Not calling hvm_bringup_ap from BSP context.\n");
520 domain_crash_synchronous();
521 }
523 if ( (v = d->vcpu[vcpuid]) == NULL )
524 return -ENOENT;
526 if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
527 {
528 gdprintk(XENLOG_ERR,
529 "Failed to allocate memory in hvm_bringup_ap.\n");
530 return -ENOMEM;
531 }
533 hvm_init_ap_context(ctxt, vcpuid, trampoline_vector);
535 /* Sync AP's TSC with BSP's. */
536 v->arch.hvm_vcpu.cache_tsc_offset =
537 v->domain->vcpu[0]->arch.hvm_vcpu.cache_tsc_offset;
538 hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
540 LOCK_BIGLOCK(d);
541 rc = -EEXIST;
542 if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
543 rc = boot_vcpu(d, vcpuid, ctxt);
544 UNLOCK_BIGLOCK(d);
546 if ( rc != 0 )
547 {
548 gdprintk(XENLOG_ERR,
549 "AP %d bringup failed in boot_vcpu %x.\n", vcpuid, rc);
550 goto out;
551 }
553 if ( test_and_clear_bit(_VCPUF_down, &d->vcpu[vcpuid]->vcpu_flags) )
554 vcpu_wake(d->vcpu[vcpuid]);
555 gdprintk(XENLOG_INFO, "AP %d bringup suceeded.\n", vcpuid);
557 out:
558 xfree(ctxt);
559 return rc;
560 }
562 long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
564 {
565 long rc = 0;
567 switch ( op )
568 {
569 case HVMOP_set_param:
570 case HVMOP_get_param:
571 {
572 struct xen_hvm_param a;
573 struct domain *d;
574 struct vcpu *v;
575 unsigned long mfn;
576 void *p;
578 if ( copy_from_guest(&a, arg, 1) )
579 return -EFAULT;
581 if ( a.index >= HVM_NR_PARAMS )
582 return -EINVAL;
584 if ( a.domid == DOMID_SELF )
585 {
586 get_knownalive_domain(current->domain);
587 d = current->domain;
588 }
589 else if ( IS_PRIV(current->domain) )
590 {
591 d = find_domain_by_id(a.domid);
592 if ( d == NULL )
593 return -ESRCH;
594 }
595 else
596 {
597 return -EPERM;
598 }
600 rc = -EINVAL;
601 if ( !is_hvm_domain(d) )
602 goto param_fail;
604 if ( op == HVMOP_set_param )
605 {
606 switch ( a.index )
607 {
608 case HVM_PARAM_IOREQ_PFN:
609 if ( d->arch.hvm_domain.shared_page_va )
610 goto param_fail;
611 mfn = gmfn_to_mfn(d, a.value);
612 if ( mfn == INVALID_MFN )
613 goto param_fail;
614 p = map_domain_page_global(mfn);
615 if ( p == NULL )
616 goto param_fail;
617 d->arch.hvm_domain.shared_page_va = (unsigned long)p;
618 /* Initialise evtchn port info if VCPUs already created. */
619 for_each_vcpu ( d, v )
620 get_vio(d, v->vcpu_id)->vp_eport =
621 v->arch.hvm_vcpu.xen_port;
622 break;
623 case HVM_PARAM_BUFIOREQ_PFN:
624 if ( d->arch.hvm_domain.buffered_io_va )
625 goto param_fail;
626 mfn = gmfn_to_mfn(d, a.value);
627 if ( mfn == INVALID_MFN )
628 goto param_fail;
629 p = map_domain_page_global(mfn);
630 if ( p == NULL )
631 goto param_fail;
632 d->arch.hvm_domain.buffered_io_va = (unsigned long)p;
633 break;
634 }
635 d->arch.hvm_domain.params[a.index] = a.value;
636 rc = 0;
637 }
638 else
639 {
640 a.value = d->arch.hvm_domain.params[a.index];
641 rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0;
642 }
644 param_fail:
645 put_domain(d);
646 break;
647 }
649 case HVMOP_set_irq_level:
650 {
651 struct xen_hvm_set_irq_level op;
652 struct domain *d;
654 if ( copy_from_guest(&op, arg, 1) )
655 return -EFAULT;
657 if ( !IS_PRIV(current->domain) )
658 return -EPERM;
660 d = find_domain_by_id(op.domid);
661 if ( d == NULL )
662 return -ESRCH;
664 rc = -EINVAL;
665 if ( is_hvm_domain(d) )
666 {
667 pic_set_irq(domain_vpic(d), op.irq, op.level);
668 rc = 0;
669 }
671 put_domain(d);
672 break;
673 }
675 default:
676 {
677 gdprintk(XENLOG_WARNING, "Bad HVM op %ld.\n", op);
678 rc = -ENOSYS;
679 break;
680 }
681 }
683 return rc;
684 }
686 /*
687 * Local variables:
688 * mode: C
689 * c-set-style: "BSD"
690 * c-basic-offset: 4
691 * tab-width: 4
692 * indent-tabs-mode: nil
693 * End:
694 */