debuggers.hg

view xen/arch/x86/domain.c @ 3686:5c112b235281

bitkeeper revision 1.1159.212.85 (42038b45EjUo-1JiSCHXW0Wav4TZGQ)

x86_64 progress: now entering ring 3. Need a hypercall (SYSCALL)
entry point, and some kind of DOM0 image to test against.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author kaf24@scramble.cl.cam.ac.uk
date Fri Feb 04 14:48:37 2005 +0000 (2005-02-04)
parents d3f0465c034e
children 393483ae9f62 61899d6ae2eb 523e995bcc57
line source
1 /******************************************************************************
2 * arch/x86/domain.c
3 *
4 * x86-specific domain handling (e.g., register setup and context switching).
5 */
7 /*
8 * Copyright (C) 1995 Linus Torvalds
9 *
10 * Pentium III FXSR, SSE support
11 * Gareth Hughes <gareth@valinux.com>, May 2000
12 */
14 #include <xen/config.h>
15 #include <xen/init.h>
16 #include <xen/lib.h>
17 #include <xen/errno.h>
18 #include <xen/sched.h>
19 #include <xen/smp.h>
20 #include <xen/delay.h>
21 #include <xen/softirq.h>
22 #include <asm/regs.h>
23 #include <asm/mc146818rtc.h>
24 #include <asm/system.h>
25 #include <asm/io.h>
26 #include <asm/processor.h>
27 #include <asm/desc.h>
28 #include <asm/i387.h>
29 #include <asm/mpspec.h>
30 #include <asm/ldt.h>
31 #include <xen/irq.h>
32 #include <xen/event.h>
33 #include <asm/shadow.h>
34 #include <xen/console.h>
35 #include <xen/elf.h>
36 #include <asm/vmx.h>
37 #include <asm/vmx_vmcs.h>
38 #include <xen/kernel.h>
39 #include <public/io/ioreq.h>
40 #include <xen/multicall.h>
42 /* opt_noreboot: If true, machine will need manual reset on error. */
43 static int opt_noreboot = 0;
44 boolean_param("noreboot", opt_noreboot);
46 static void default_idle(void)
47 {
48 __cli();
49 if ( !softirq_pending(smp_processor_id()) )
50 safe_halt();
51 else
52 __sti();
53 }
55 static __attribute_used__ void idle_loop(void)
56 {
57 int cpu = smp_processor_id();
58 for ( ; ; )
59 {
60 irq_stat[cpu].idle_timestamp = jiffies;
61 while ( !softirq_pending(cpu) )
62 default_idle();
63 do_softirq();
64 }
65 }
67 void startup_cpu_idle_loop(void)
68 {
69 /* Just some sanity to ensure that the scheduler is set up okay. */
70 ASSERT(current->domain->id == IDLE_DOMAIN_ID);
71 domain_unpause_by_systemcontroller(current->domain);
72 __enter_scheduler();
74 /*
75 * Declares CPU setup done to the boot processor.
76 * Therefore memory barrier to ensure state is visible.
77 */
78 smp_mb();
79 init_idle();
81 idle_loop();
82 }
84 static long no_idt[2];
85 static int reboot_mode;
86 int reboot_thru_bios = 0;
88 #ifdef CONFIG_SMP
89 int reboot_smp = 0;
90 static int reboot_cpu = -1;
91 /* shamelessly grabbed from lib/vsprintf.c for readability */
92 #define is_digit(c) ((c) >= '0' && (c) <= '9')
93 #endif
96 static inline void kb_wait(void)
97 {
98 int i;
100 for (i=0; i<0x10000; i++)
101 if ((inb_p(0x64) & 0x02) == 0)
102 break;
103 }
106 void machine_restart(char * __unused)
107 {
108 #ifdef CONFIG_SMP
109 int cpuid;
110 #endif
112 if ( opt_noreboot )
113 {
114 printk("Reboot disabled on cmdline: require manual reset\n");
115 for ( ; ; ) __asm__ __volatile__ ("hlt");
116 }
118 #ifdef CONFIG_SMP
119 cpuid = GET_APIC_ID(apic_read(APIC_ID));
121 /* KAF: Need interrupts enabled for safe IPI. */
122 __sti();
124 if (reboot_smp) {
126 /* check to see if reboot_cpu is valid
127 if its not, default to the BSP */
128 if ((reboot_cpu == -1) ||
129 (reboot_cpu > (NR_CPUS -1)) ||
130 !(phys_cpu_present_map & (1<<cpuid)))
131 reboot_cpu = boot_cpu_physical_apicid;
133 reboot_smp = 0; /* use this as a flag to only go through this once*/
134 /* re-run this function on the other CPUs
135 it will fall though this section since we have
136 cleared reboot_smp, and do the reboot if it is the
137 correct CPU, otherwise it halts. */
138 if (reboot_cpu != cpuid)
139 smp_call_function((void *)machine_restart , NULL, 1, 0);
140 }
142 /* if reboot_cpu is still -1, then we want a tradional reboot,
143 and if we are not running on the reboot_cpu,, halt */
144 if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
145 for (;;)
146 __asm__ __volatile__ ("hlt");
147 }
148 /*
149 * Stop all CPUs and turn off local APICs and the IO-APIC, so
150 * other OSs see a clean IRQ state.
151 */
152 smp_send_stop();
153 disable_IO_APIC();
154 #endif
155 #ifdef CONFIG_VMX
156 stop_vmx();
157 #endif
159 if(!reboot_thru_bios) {
160 /* rebooting needs to touch the page at absolute addr 0 */
161 *((unsigned short *)__va(0x472)) = reboot_mode;
162 for (;;) {
163 int i;
164 for (i=0; i<100; i++) {
165 kb_wait();
166 udelay(50);
167 outb(0xfe,0x64); /* pulse reset low */
168 udelay(50);
169 }
170 /* That didn't work - force a triple fault.. */
171 __asm__ __volatile__("lidt %0": "=m" (no_idt));
172 __asm__ __volatile__("int3");
173 }
174 }
176 panic("Need to reinclude BIOS reboot code\n");
177 }
180 void __attribute__((noreturn)) __machine_halt(void *unused)
181 {
182 for ( ; ; )
183 __asm__ __volatile__ ( "cli; hlt" );
184 }
186 void machine_halt(void)
187 {
188 smp_call_function(__machine_halt, NULL, 1, 1);
189 __machine_halt(NULL);
190 }
192 void dump_pageframe_info(struct domain *d)
193 {
194 struct pfn_info *page;
196 if ( d->tot_pages < 10 )
197 {
198 list_for_each_entry ( page, &d->page_list, list )
199 {
200 printk("Page %08x: caf=%08x, taf=%08x\n",
201 page_to_phys(page), page->count_info,
202 page->u.inuse.type_info);
203 }
204 }
206 page = virt_to_page(d->shared_info);
207 printk("Shared_info@%08x: caf=%08x, taf=%08x\n",
208 page_to_phys(page), page->count_info,
209 page->u.inuse.type_info);
210 }
212 struct domain *arch_alloc_domain_struct(void)
213 {
214 return xmalloc(struct domain);
215 }
217 void arch_free_domain_struct(struct domain *d)
218 {
219 xfree(d);
220 }
222 struct exec_domain *arch_alloc_exec_domain_struct(void)
223 {
224 return xmalloc(struct exec_domain);
225 }
227 void arch_free_exec_domain_struct(struct exec_domain *ed)
228 {
229 xfree(ed);
230 }
232 void free_perdomain_pt(struct domain *d)
233 {
234 free_xenheap_page((unsigned long)d->mm_perdomain_pt);
235 }
237 static void continue_idle_task(struct exec_domain *ed)
238 {
239 reset_stack_and_jump(idle_loop);
240 }
242 static void continue_nonidle_task(struct exec_domain *ed)
243 {
244 reset_stack_and_jump(ret_from_intr);
245 }
247 void arch_do_createdomain(struct exec_domain *ed)
248 {
249 struct domain *d = ed->domain;
251 SET_DEFAULT_FAST_TRAP(&ed->thread);
253 if ( d->id == IDLE_DOMAIN_ID )
254 {
255 ed->thread.schedule_tail = continue_idle_task;
256 }
257 else
258 {
259 ed->thread.schedule_tail = continue_nonidle_task;
261 d->shared_info = (void *)alloc_xenheap_page();
262 memset(d->shared_info, 0, PAGE_SIZE);
263 ed->vcpu_info = &d->shared_info->vcpu_data[ed->eid];
264 SHARE_PFN_WITH_DOMAIN(virt_to_page(d->shared_info), d);
265 machine_to_phys_mapping[virt_to_phys(d->shared_info) >>
266 PAGE_SHIFT] = INVALID_P2M_ENTRY;
268 d->mm_perdomain_pt = (l1_pgentry_t *)alloc_xenheap_page();
269 memset(d->mm_perdomain_pt, 0, PAGE_SIZE);
270 machine_to_phys_mapping[virt_to_phys(d->mm_perdomain_pt) >>
271 PAGE_SHIFT] = INVALID_P2M_ENTRY;
272 ed->mm.perdomain_ptes = d->mm_perdomain_pt;
273 }
274 }
276 #ifdef CONFIG_VMX
277 void arch_vmx_do_resume(struct exec_domain *ed)
278 {
279 u64 vmcs_phys_ptr = (u64) virt_to_phys(ed->thread.arch_vmx.vmcs);
281 load_vmcs(&ed->thread.arch_vmx, vmcs_phys_ptr);
282 vmx_do_resume(ed);
283 reset_stack_and_jump(vmx_asm_do_resume);
284 }
286 void arch_vmx_do_launch(struct exec_domain *ed)
287 {
288 u64 vmcs_phys_ptr = (u64) virt_to_phys(ed->thread.arch_vmx.vmcs);
290 load_vmcs(&ed->thread.arch_vmx, vmcs_phys_ptr);
291 vmx_do_launch(ed);
292 reset_stack_and_jump(vmx_asm_do_launch);
293 }
295 static void monitor_mk_pagetable(struct exec_domain *ed)
296 {
297 unsigned long mpfn;
298 l2_pgentry_t *mpl2e;
299 struct pfn_info *mpfn_info;
300 struct mm_struct *m = &ed->mm;
301 struct domain *d = ed->domain;
303 mpfn_info = alloc_domheap_page(NULL);
304 ASSERT( mpfn_info );
306 mpfn = (unsigned long) (mpfn_info - frame_table);
307 mpl2e = (l2_pgentry_t *) map_domain_mem(mpfn << L1_PAGETABLE_SHIFT);
308 memset(mpl2e, 0, PAGE_SIZE);
310 memcpy(&mpl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
311 &idle_pg_table[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
312 HYPERVISOR_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
314 m->monitor_table = mk_pagetable(mpfn << L1_PAGETABLE_SHIFT);
315 m->shadow_mode = SHM_full_32;
317 mpl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
318 mk_l2_pgentry((__pa(d->mm_perdomain_pt) & PAGE_MASK)
319 | __PAGE_HYPERVISOR);
321 unmap_domain_mem(mpl2e);
322 }
324 /*
325 * Free the pages for monitor_table and guest_pl2e_cache
326 */
327 static void monitor_rm_pagetable(struct exec_domain *ed)
328 {
329 struct mm_struct *m = &ed->mm;
330 l2_pgentry_t *mpl2e;
331 unsigned long mpfn;
333 ASSERT( pagetable_val(m->monitor_table) );
335 mpl2e = (l2_pgentry_t *) map_domain_mem(pagetable_val(m->monitor_table));
336 /*
337 * First get the pfn for guest_pl2e_cache by looking at monitor_table
338 */
339 mpfn = l2_pgentry_val(mpl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT])
340 >> PAGE_SHIFT;
342 free_domheap_page(&frame_table[mpfn]);
343 unmap_domain_mem(mpl2e);
345 /*
346 * Then free monitor_table.
347 */
348 mpfn = (pagetable_val(m->monitor_table)) >> PAGE_SHIFT;
349 free_domheap_page(&frame_table[mpfn]);
351 m->monitor_table = mk_pagetable(0);
352 }
354 static int vmx_final_setup_guestos(struct exec_domain *ed,
355 full_execution_context_t *full_context)
356 {
357 int error;
358 execution_context_t *context;
359 struct vmcs_struct *vmcs;
361 context = &full_context->cpu_ctxt;
363 /*
364 * Create a new VMCS
365 */
366 if (!(vmcs = alloc_vmcs())) {
367 printk("Failed to create a new VMCS\n");
368 return -ENOMEM;
369 }
371 memset(&ed->thread.arch_vmx, 0, sizeof (struct arch_vmx_struct));
373 ed->thread.arch_vmx.vmcs = vmcs;
374 error = construct_vmcs(&ed->thread.arch_vmx, context, full_context, VMCS_USE_HOST_ENV);
375 if (error < 0) {
376 printk("Failed to construct a new VMCS\n");
377 goto out;
378 }
380 monitor_mk_pagetable(ed);
381 ed->thread.schedule_tail = arch_vmx_do_launch;
382 clear_bit(VMX_CPU_STATE_PG_ENABLED, &ed->thread.arch_vmx.cpu_state);
384 #if defined (__i386)
385 ed->thread.arch_vmx.vmx_platform.real_mode_data =
386 (unsigned long *) context->esi;
387 #endif
389 if (ed == ed->domain->exec_domain[0]) {
390 /*
391 * Required to do this once per domain
392 */
393 memset(&ed->domain->shared_info->evtchn_mask[0], 0xff,
394 sizeof(ed->domain->shared_info->evtchn_mask));
395 clear_bit(IOPACKET_PORT, &ed->domain->shared_info->evtchn_mask[0]);
396 }
398 return 0;
400 out:
401 free_vmcs(vmcs);
402 ed->thread.arch_vmx.vmcs = 0;
403 return error;
404 }
405 #endif
407 int arch_final_setup_guestos(struct exec_domain *d, full_execution_context_t *c)
408 {
409 unsigned long phys_basetab;
410 int i, rc;
412 clear_bit(EDF_DONEFPUINIT, &d->ed_flags);
413 if ( c->flags & ECF_I387_VALID )
414 set_bit(EDF_DONEFPUINIT, &d->ed_flags);
416 memcpy(&d->thread.user_ctxt,
417 &c->cpu_ctxt,
418 sizeof(d->thread.user_ctxt));
420 /* Clear IOPL for unprivileged domains. */
421 if (!IS_PRIV(d->domain))
422 d->thread.user_ctxt.eflags &= 0xffffcfff;
424 /*
425 * This is sufficient! If the descriptor DPL differs from CS RPL then we'll
426 * #GP. If DS, ES, FS, GS are DPL 0 then they'll be cleared automatically.
427 * If SS RPL or DPL differs from CS RPL then we'll #GP.
428 */
429 if (!(c->flags & ECF_VMX_GUEST))
430 if ( ((d->thread.user_ctxt.cs & 3) == 0) ||
431 ((d->thread.user_ctxt.ss & 3) == 0) )
432 return -EINVAL;
434 memcpy(&d->thread.i387,
435 &c->fpu_ctxt,
436 sizeof(d->thread.i387));
438 memcpy(d->thread.traps,
439 &c->trap_ctxt,
440 sizeof(d->thread.traps));
442 if ( (rc = (int)set_fast_trap(d, c->fast_trap_idx)) != 0 )
443 return rc;
445 d->mm.ldt_base = c->ldt_base;
446 d->mm.ldt_ents = c->ldt_ents;
448 d->thread.guestos_ss = c->guestos_ss;
449 d->thread.guestos_sp = c->guestos_esp;
451 for ( i = 0; i < 8; i++ )
452 (void)set_debugreg(d, i, c->debugreg[i]);
454 d->thread.event_selector = c->event_callback_cs;
455 d->thread.event_address = c->event_callback_eip;
456 d->thread.failsafe_selector = c->failsafe_callback_cs;
457 d->thread.failsafe_address = c->failsafe_callback_eip;
459 phys_basetab = c->pt_base;
460 d->mm.pagetable = mk_pagetable(phys_basetab);
461 if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d->domain,
462 PGT_base_page_table) )
463 return -EINVAL;
465 /* Failure to set GDT is harmless. */
466 SET_GDT_ENTRIES(d, DEFAULT_GDT_ENTRIES);
467 SET_GDT_ADDRESS(d, DEFAULT_GDT_ADDRESS);
468 if ( c->gdt_ents != 0 )
469 {
470 if ( (rc = (int)set_gdt(d, c->gdt_frames, c->gdt_ents)) != 0 )
471 {
472 put_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT]);
473 return rc;
474 }
475 }
477 #ifdef CONFIG_VMX
478 if (c->flags & ECF_VMX_GUEST)
479 return vmx_final_setup_guestos(d, c);
480 #endif
482 return 0;
483 }
485 void new_thread(struct exec_domain *d,
486 unsigned long start_pc,
487 unsigned long start_stack,
488 unsigned long start_info)
489 {
490 execution_context_t *ec = &d->thread.user_ctxt;
492 /*
493 * Initial register values:
494 * DS,ES,FS,GS = FLAT_GUESTOS_DS
495 * CS:EIP = FLAT_GUESTOS_CS:start_pc
496 * SS:ESP = FLAT_GUESTOS_SS:start_stack
497 * ESI = start_info
498 * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
499 */
500 ec->ds = ec->es = ec->fs = ec->gs = FLAT_GUESTOS_DS;
501 ec->ss = FLAT_GUESTOS_SS;
502 ec->cs = FLAT_GUESTOS_CS;
503 ec->eip = start_pc;
504 ec->esp = start_stack;
505 ec->esi = start_info;
507 __save_flags(ec->eflags);
508 ec->eflags |= X86_EFLAGS_IF;
509 }
512 /*
513 * This special macro can be used to load a debugging register
514 */
515 #define loaddebug(thread,register) \
516 __asm__("mov %0,%%db" #register \
517 : /* no output */ \
518 :"r" (thread->debugreg[register]))
520 void switch_to(struct exec_domain *prev_p, struct exec_domain *next_p)
521 {
522 struct thread_struct *next = &next_p->thread;
523 struct tss_struct *tss = init_tss + smp_processor_id();
524 execution_context_t *stack_ec = get_execution_context();
525 int i;
526 #ifdef CONFIG_VMX
527 unsigned long vmx_domain = next_p->thread.arch_vmx.flags;
528 #endif
530 __cli();
532 /* Switch guest general-register state. */
533 if ( !is_idle_task(prev_p->domain) )
534 {
535 memcpy(&prev_p->thread.user_ctxt,
536 stack_ec,
537 sizeof(*stack_ec));
538 unlazy_fpu(prev_p);
539 CLEAR_FAST_TRAP(&prev_p->thread);
540 }
542 if ( !is_idle_task(next_p->domain) )
543 {
544 memcpy(stack_ec,
545 &next_p->thread.user_ctxt,
546 sizeof(*stack_ec));
548 /* Maybe switch the debug registers. */
549 if ( unlikely(next->debugreg[7]) )
550 {
551 loaddebug(next, 0);
552 loaddebug(next, 1);
553 loaddebug(next, 2);
554 loaddebug(next, 3);
555 /* no 4 and 5 */
556 loaddebug(next, 6);
557 loaddebug(next, 7);
558 }
560 #ifdef CONFIG_VMX
561 if ( vmx_domain )
562 {
563 /* Switch page tables. */
564 write_ptbase(&next_p->mm);
566 set_current(next_p);
567 /* Switch GDT and LDT. */
568 __asm__ __volatile__ ("lgdt %0" : "=m" (*next_p->mm.gdt));
570 __sti();
571 return;
572 }
573 #endif
575 SET_FAST_TRAP(&next_p->thread);
577 #ifdef __i386__
578 /* Switch the guest OS ring-1 stack. */
579 tss->esp1 = next->guestos_sp;
580 tss->ss1 = next->guestos_ss;
581 #endif
583 /* Switch page tables. */
584 write_ptbase(&next_p->mm);
585 }
587 if ( unlikely(prev_p->thread.io_bitmap != NULL) )
588 {
589 for ( i = 0; i < sizeof(prev_p->thread.io_bitmap_sel) * 8; i++ )
590 if ( !test_bit(i, &prev_p->thread.io_bitmap_sel) )
591 memset(&tss->io_bitmap[i * IOBMP_BYTES_PER_SELBIT],
592 ~0U, IOBMP_BYTES_PER_SELBIT);
593 tss->bitmap = IOBMP_INVALID_OFFSET;
594 }
596 if ( unlikely(next_p->thread.io_bitmap != NULL) )
597 {
598 for ( i = 0; i < sizeof(next_p->thread.io_bitmap_sel) * 8; i++ )
599 if ( !test_bit(i, &next_p->thread.io_bitmap_sel) )
600 memcpy(&tss->io_bitmap[i * IOBMP_BYTES_PER_SELBIT],
601 &next_p->thread.io_bitmap[i * IOBMP_BYTES_PER_SELBIT],
602 IOBMP_BYTES_PER_SELBIT);
603 tss->bitmap = IOBMP_OFFSET;
604 }
606 set_current(next_p);
608 /* Switch GDT and LDT. */
609 __asm__ __volatile__ ("lgdt %0" : "=m" (*next_p->mm.gdt));
610 load_LDT(next_p);
612 __sti();
613 }
616 /* XXX Currently the 'domain' field is ignored! XXX */
617 long do_iopl(domid_t domain, unsigned int new_io_pl)
618 {
619 execution_context_t *ec = get_execution_context();
620 ec->eflags = (ec->eflags & 0xffffcfff) | ((new_io_pl&3) << 12);
621 return 0;
622 }
624 unsigned long hypercall_create_continuation(
625 unsigned int op, unsigned int nr_args, ...)
626 {
627 struct mc_state *mcs = &mc_state[smp_processor_id()];
628 execution_context_t *ec;
629 unsigned long *preg;
630 unsigned int i;
631 va_list args;
633 va_start(args, nr_args);
635 if ( test_bit(_MCSF_in_multicall, &mcs->flags) )
636 {
637 __set_bit(_MCSF_call_preempted, &mcs->flags);
639 for ( i = 0; i < nr_args; i++ )
640 mcs->call.args[i] = va_arg(args, unsigned long);
641 }
642 else
643 {
644 ec = get_execution_context();
645 #if defined(__i386__)
646 ec->eax = op;
647 ec->eip -= 2; /* re-execute 'int 0x82' */
649 for ( i = 0, preg = &ec->ebx; i < nr_args; i++, preg++ )
650 *preg = va_arg(args, unsigned long);
651 #else
652 preg = NULL; /* XXX x86/64 */
653 #endif
654 }
656 va_end(args);
658 return op;
659 }
661 static void relinquish_list(struct domain *d, struct list_head *list)
662 {
663 struct list_head *ent;
664 struct pfn_info *page;
665 unsigned long x, y;
667 /* Use a recursive lock, as we may enter 'free_domheap_page'. */
668 spin_lock_recursive(&d->page_alloc_lock);
670 ent = list->next;
671 while ( ent != list )
672 {
673 page = list_entry(ent, struct pfn_info, list);
675 /* Grab a reference to the page so it won't disappear from under us. */
676 if ( unlikely(!get_page(page, d)) )
677 {
678 /* Couldn't get a reference -- someone is freeing this page. */
679 ent = ent->next;
680 continue;
681 }
683 if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
684 put_page_and_type(page);
686 if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
687 put_page(page);
689 /*
690 * Forcibly invalidate base page tables at this point to break circular
691 * 'linear page table' references. This is okay because MMU structures
692 * are not shared across domains and this domain is now dead. Thus base
693 * tables are not in use so a non-zero count means circular reference.
694 */
695 y = page->u.inuse.type_info;
696 for ( ; ; )
697 {
698 x = y;
699 if ( likely((x & (PGT_type_mask|PGT_validated)) !=
700 (PGT_base_page_table|PGT_validated)) )
701 break;
703 y = cmpxchg(&page->u.inuse.type_info, x, x & ~PGT_validated);
704 if ( likely(y == x) )
705 {
706 free_page_type(page, PGT_base_page_table);
707 break;
708 }
709 }
711 /* Follow the list chain and /then/ potentially free the page. */
712 ent = ent->next;
713 put_page(page);
714 }
716 spin_unlock_recursive(&d->page_alloc_lock);
717 }
719 #ifdef CONFIG_VMX
720 static void vmx_domain_relinquish_memory(struct exec_domain *ed)
721 {
722 struct domain *d = ed->domain;
724 /*
725 * Free VMCS
726 */
727 ASSERT(ed->thread.arch_vmx.vmcs);
728 free_vmcs(ed->thread.arch_vmx.vmcs);
729 ed->thread.arch_vmx.vmcs = 0;
731 monitor_rm_pagetable(ed);
733 if (ed == d->exec_domain[0]) {
734 int i;
735 unsigned long pfn;
737 for (i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++) {
738 unsigned long l1e;
740 l1e = l1_pgentry_val(d->mm_perdomain_pt[i]);
741 if (l1e & _PAGE_PRESENT) {
742 pfn = l1e >> PAGE_SHIFT;
743 free_domheap_page(&frame_table[pfn]);
744 }
745 }
746 }
748 }
749 #endif
751 void domain_relinquish_memory(struct domain *d)
752 {
753 struct exec_domain *ed;
755 /* Ensure that noone is running over the dead domain's page tables. */
756 synchronise_pagetables(~0UL);
758 /* Exit shadow mode before deconstructing final guest page table. */
759 shadow_mode_disable(d);
761 /* Drop the in-use reference to the page-table base. */
762 for_each_exec_domain ( d, ed )
763 {
764 if ( pagetable_val(ed->mm.pagetable) != 0 )
765 put_page_and_type(&frame_table[pagetable_val(ed->mm.pagetable) >>
766 PAGE_SHIFT]);
767 }
769 #ifdef CONFIG_VMX
770 if ( VMX_DOMAIN(d->exec_domain[0]) )
771 for_each_exec_domain ( d, ed )
772 vmx_domain_relinquish_memory(ed);
773 #endif
775 /*
776 * Relinquish GDT mappings. No need for explicit unmapping of the LDT as
777 * it automatically gets squashed when the guest's mappings go away.
778 */
779 for_each_exec_domain(d, ed)
780 destroy_gdt(ed);
782 /* Relinquish every page of memory. */
783 relinquish_list(d, &d->xenpage_list);
784 relinquish_list(d, &d->page_list);
785 }