From: BitKeeper B. <ri...@su...> - 2005-01-16 05:09:40
|
ChangeSet 1.1717, 2005/01/14 17:53:43+00:00, so...@do... Merge arch/x86/domain.c | 223 ++++++++++++++++++++++++++++++++++++++++----------- arch/x86/memory.c | 206 +++++++++++++++++++++++++++-------------------- arch/x86/x86_32/mm.c | 62 ++++++++------ include/asm-x86/mm.h | 13 ++ 4 files changed, 344 insertions(+), 160 deletions(-) diff -Nru a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c 2005-01-15 06:01:57 -05:00 +++ b/xen/arch/x86/domain.c 2005-01-15 06:01:57 -05:00 @@ -33,6 +33,10 @@ #include <asm/shadow.h> #include <xen/console.h> #include <xen/elf.h> +#include <asm/vmx.h> +#include <asm/vmx_vmcs.h> +#include <xen/kernel.h> +#include <public/io/ioreq.h> #include <xen/multicall.h> /* opt_noreboot: If true, machine will need manual reset on error. */ @@ -77,8 +81,8 @@ void startup_cpu_idle_loop(void) { /* Just some sanity to ensure that the scheduler is set up okay. */ - ASSERT(current->id == IDLE_DOMAIN_ID); - domain_unpause_by_systemcontroller(current); + ASSERT(current->domain->id == IDLE_DOMAIN_ID); + domain_unpause_by_systemcontroller(current->domain); __enter_scheduler(); /* @@ -162,6 +166,9 @@ smp_send_stop(); disable_IO_APIC(); #endif +#ifdef CONFIG_VMX + stop_vmx(); +#endif if(!reboot_thru_bios) { /* rebooting needs to touch the page at absolute addr 0 */ @@ -198,68 +205,167 @@ void free_perdomain_pt(struct domain *d) { - free_xenheap_page((unsigned long)d->mm.perdomain_pt); + free_xenheap_page((unsigned long)d->mm_perdomain_pt); } -static void continue_idle_task(struct domain *d) +static void continue_idle_task(struct exec_domain *ed) { reset_stack_and_jump(idle_loop); } -static void continue_nonidle_task(struct domain *d) +static void continue_nonidle_task(struct exec_domain *ed) { reset_stack_and_jump(ret_from_intr); } -void arch_do_createdomain(struct domain *d) +void arch_do_createdomain(struct exec_domain *ed) { + struct domain *d = ed->domain; #ifdef ARCH_HAS_FAST_TRAP - SET_DEFAULT_FAST_TRAP(&d->thread); + SET_DEFAULT_FAST_TRAP(&ed->thread); #endif if ( d->id == IDLE_DOMAIN_ID ) { - d->thread.schedule_tail = continue_idle_task; + ed->thread.schedule_tail = continue_idle_task; } else { - d->thread.schedule_tail = continue_nonidle_task; + ed->thread.schedule_tail = continue_nonidle_task; d->shared_info = (void *)alloc_xenheap_page(); memset(d->shared_info, 0, PAGE_SIZE); + ed->vcpu_info = &d->shared_info->vcpu_data[ed->eid]; d->shared_info->arch.mfn_to_pfn_start = m2p_start_mfn; SHARE_PFN_WITH_DOMAIN(virt_to_page(d->shared_info), d); machine_to_phys_mapping[virt_to_phys(d->shared_info) >> PAGE_SHIFT] = INVALID_P2M_ENTRY; - d->mm.perdomain_pt = (l1_pgentry_t *)alloc_xenheap_page(); - memset(d->mm.perdomain_pt, 0, PAGE_SIZE); - machine_to_phys_mapping[virt_to_phys(d->mm.perdomain_pt) >> + d->mm_perdomain_pt = (l1_pgentry_t *)alloc_xenheap_page(); + memset(d->mm_perdomain_pt, 0, PAGE_SIZE); + machine_to_phys_mapping[virt_to_phys(d->mm_perdomain_pt) >> PAGE_SHIFT] = INVALID_P2M_ENTRY; + ed->mm.perdomain_ptes = d->mm_perdomain_pt; } } -int arch_final_setup_guestos(struct domain *d, full_execution_context_t *c) +#ifdef CONFIG_VMX +void arch_vmx_do_resume(struct exec_domain *d) +{ + vmx_do_resume(d); + reset_stack_and_jump(vmx_asm_do_resume); +} + +void arch_vmx_do_launch(struct exec_domain *d) +{ + vmx_do_launch(d); + reset_stack_and_jump(vmx_asm_do_launch); +} + +static void monitor_mk_pagetable(struct exec_domain *ed) +{ + unsigned long mpfn; + l2_pgentry_t *mpl2e; + struct pfn_info *mpfn_info; + struct mm_struct *m = &ed->mm; + struct domain *d = ed->domain; + + mpfn_info = alloc_domheap_page(NULL); + ASSERT( mpfn_info ); + + mpfn = (unsigned long) (mpfn_info - frame_table); + mpl2e = (l2_pgentry_t *) map_domain_mem(mpfn << PAGE_SHIFT); + memset(mpl2e, 0, PAGE_SIZE); + + memcpy(&mpl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE], + &idle_pg_table[DOMAIN_ENTRIES_PER_L2_PAGETABLE], + HYPERVISOR_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t)); + + m->monitor_table = mk_pagetable(mpfn << PAGE_SHIFT); + m->shadow_mode = SHM_full_32; + + mpl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] = + mk_l2_pgentry((__pa(d->mm_perdomain_pt) & PAGE_MASK) + | __PAGE_HYPERVISOR); + + unmap_domain_mem(mpl2e); +} + +static int vmx_final_setup_guestos(struct exec_domain *d, + full_execution_context_t *full_context) +{ + int error; + execution_context_t *context; + struct vmcs_struct *vmcs; + unsigned long guest_pa; + + context = &full_context->cpu_ctxt; + + /* + * Create a new VMCS + */ + if (!(vmcs = alloc_vmcs())) { + printk("Failed to create a new VMCS\n"); + return -ENOMEM; + } + + memset(&d->thread.arch_vmx, 0, sizeof (struct arch_vmx_struct)); + + d->thread.arch_vmx.vmcs = vmcs; + error = construct_vmcs(&d->thread.arch_vmx, context, full_context, VMCS_USE_HOST_ENV); + if (error < 0) { + printk("Failed to construct a new VMCS\n"); + goto out; + } + + monitor_mk_pagetable(d); + guest_pa = pagetable_val(d->mm.pagetable); + clear_bit(VMX_CPU_STATE_PG_ENABLED, &d->thread.arch_vmx.cpu_state); + + d->thread.arch_vmx.vmx_platform.real_mode_data = + (unsigned long *) context->esi; + + memset(&d->domain->shared_info->evtchn_mask[0], 0xff, + sizeof(d->domain->shared_info->evtchn_mask)); + clear_bit(IOPACKET_PORT, &d->domain->shared_info->evtchn_mask[0]); + + d->thread.schedule_tail = arch_vmx_do_launch; + + return 0; + +out: + free_vmcs(vmcs); + d->thread.arch_vmx.vmcs = 0; + return error; +} +#endif + +int arch_final_setup_guestos(struct exec_domain *d, full_execution_context_t *c) { unsigned long phys_basetab; int i, rc; - clear_bit(DF_DONEFPUINIT, &d->flags); + clear_bit(EDF_DONEFPUINIT, &d->ed_flags); if ( c->flags & ECF_I387_VALID ) - set_bit(DF_DONEFPUINIT, &d->flags); + set_bit(EDF_DONEFPUINIT, &d->ed_flags); memcpy(&d->thread.user_ctxt, &c->cpu_ctxt, sizeof(d->thread.user_ctxt)); + /* Clear IOPL for unprivileged domains. */ + if (!IS_PRIV(d->domain)) + d->thread.user_ctxt.eflags &= 0xffffcfff; + /* * This is sufficient! If the descriptor DPL differs from CS RPL then we'll * #GP. If DS, ES, FS, GS are DPL 0 then they'll be cleared automatically. * If SS RPL or DPL differs from CS RPL then we'll #GP. */ - if ( ((d->thread.user_ctxt.cs & 3) == 0) || - ((d->thread.user_ctxt.ss & 3) == 0) ) - return -EINVAL; + if (!(c->flags & ECF_VMX_GUEST)) + if ( ((d->thread.user_ctxt.cs & 3) == 0) || + ((d->thread.user_ctxt.ss & 3) == 0) ) + return -EINVAL; memcpy(&d->thread.i387, &c->fpu_ctxt, @@ -290,7 +396,7 @@ phys_basetab = c->pt_base; d->mm.pagetable = mk_pagetable(phys_basetab); - if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d, + if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d->domain, PGT_base_page_table) ) return -EINVAL; @@ -306,12 +412,15 @@ } } + if (c->flags & ECF_VMX_GUEST) + return vmx_final_setup_guestos(d, c); + return 0; } #if defined(__i386__) -void new_thread(struct domain *d, +void new_thread(struct exec_domain *d, unsigned long start_pc, unsigned long start_stack, unsigned long start_info) @@ -346,17 +455,18 @@ :"r" (thread->debugreg[register])) -void switch_to(struct domain *prev_p, struct domain *next_p) |