# HG changeset patch # User cegger # Date 1289574159 -3600 Nested Virtualization core implementation Signed-off-by: Christoph Egger diff -r abc8558e0fd6 -r 5ea6bde78dc6 xen/arch/x86/hvm/Makefile --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -10,6 +10,7 @@ obj-y += intercept.o obj-y += io.o obj-y += irq.o obj-y += mtrr.o +obj-y += nestedhvm.o obj-y += pmtimer.o obj-y += quirks.o obj-y += rtc.o diff -r abc8558e0fd6 -r 5ea6bde78dc6 xen/arch/x86/hvm/nestedhvm.c --- /dev/null +++ b/xen/arch/x86/hvm/nestedhvm.c @@ -0,0 +1,110 @@ +/* + * Nested HVM + * Copyright (c) 2010, Advanced Micro Devices, Inc. + * Author: Christoph Egger + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include /* for HVM_DELIVER_NO_ERROR_CODE */ +#include +#include +#include /* for local_event_delivery_(en|dis)able */ +#include /* for paging_mode_hap() */ + + +/* Nested HVM on/off per domain */ +bool_t +nestedhvm_enabled(struct domain *d) +{ + bool_t enabled; + + enabled = !!(d->arch.hvm_domain.params[HVM_PARAM_NESTEDHVM]); + /* sanity check */ + BUG_ON(enabled && !is_hvm_domain(d)); + + if (!is_hvm_domain(d)) + return 0; + + return enabled; +} + +/* Nested VCPU */ +bool_t +nestedhvm_vcpu_in_guestmode(struct vcpu *v) +{ + return vcpu_nestedhvm(v).nv_guestmode; +} + +void +nestedhvm_vcpu_reset(struct vcpu *v) +{ + struct nestedvcpu *nv = &vcpu_nestedhvm(v); + + if (nv->nv_vmcx) + hvm_unmap_guest_frame(nv->nv_vmcx); + nv->nv_vmcx = NULL; + nv->nv_vmcxaddr = 0; + nv->nv_flushp2m = 0; + nv->nv_p2m = NULL; + + nhvm_vcpu_reset(v); + + /* vcpu is in host mode */ + nestedhvm_vcpu_exit_guestmode(v); +} + +int +nestedhvm_vcpu_initialise(struct vcpu *v) +{ + int rc; + struct nestedvcpu *nv = &vcpu_nestedhvm(v); + + if (!nestedhvm_enabled(v->domain)) + return 0; + + memset(nv, 0x0, sizeof(struct nestedvcpu)); + + /* initialise hostsave, for example */ + rc = nhvm_vcpu_initialise(v); + if (rc) { + nhvm_vcpu_destroy(v); + return rc; + } + + nestedhvm_vcpu_reset(v); + return 0; +} + +int +nestedhvm_vcpu_destroy(struct vcpu *v) +{ + if (!nestedhvm_enabled(v->domain)) + return 0; + + return nhvm_vcpu_destroy(v); +} + +void +nestedhvm_vcpu_enter_guestmode(struct vcpu *v) +{ + vcpu_nestedhvm(v).nv_guestmode = 1; +} + +void +nestedhvm_vcpu_exit_guestmode(struct vcpu *v) +{ + vcpu_nestedhvm(v).nv_guestmode = 0; +} diff -r abc8558e0fd6 -r 5ea6bde78dc6 xen/include/asm-x86/hvm/nestedhvm.h --- /dev/null +++ b/xen/include/asm-x86/hvm/nestedhvm.h @@ -0,0 +1,88 @@ +/* + * Nested HVM + * Copyright (c) 2010, Advanced Micro Devices, Inc. + * Author: Christoph Egger + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _HVM_NESTEDHVM_H +#define _HVM_NESTEDHVM_H + +#include /* for uintNN_t */ +#include /* for struct vcpu, struct domain */ +#include /* for vcpu_nestedhvm */ + +enum nestedhvm_vmexits { + NESTEDHVM_VMEXIT_ERROR = 0, /* inject VMEXIT w/ invalid VMCB */ + NESTEDHVM_VMEXIT_FATALERROR = 1, /* crash first level guest */ + NESTEDHVM_VMEXIT_HOST = 2, /* exit handled on host level */ + NESTEDHVM_VMEXIT_CONTINUE = 3, /* further handling */ + NESTEDHVM_VMEXIT_INJECT = 4, /* inject VMEXIT */ + NESTEDHVM_VMEXIT_DONE = 5, /* VMEXIT handled */ +}; + +/* Generic exit codes + * Note: This is not a complete list. Only maintain those which are + * used in the generic code. All other exit codes are represented + * by NESTEDHVM_INTERCEPT_LAST. + */ +enum nestedhvm_intercepts { + /* exitinfo1 and exitinfo2 undefined */ + NESTEDHVM_INTERCEPT_INVALID = 0, /* INVALID vmcb/vmcs */ + NESTEDHVM_INTERCEPT_SHUTDOWN = 1, /* kill guest */ + NESTEDHVM_INTERCEPT_MCE = 2, /* machine check exception */ + NESTEDHVM_INTERCEPT_VMMCALL = 3, /* VMMCALL/VMCALL */ + + /* exitinfo1 is hvm_intsrc_*, exitinfo2 is the vector */ + NESTEDHVM_INTERCEPT_INTR = 4, /* interrupt exit code */ + NESTEDHVM_INTERCEPT_NMI = 5, /* NMI exit code */ + + /* exitinfo1 is PF error code, exitinfo2 is PF fault address */ + NESTEDHVM_INTERCEPT_NPF = 6, /* nested page fault */ + NESTEDHVM_INTERCEPT_PF = 7, /* page fault */ + + /* exceptions: exitinfo1 and exitinfo2 are undefined */ + NESTEDHVM_INTERCEPT_NM = 8, /* device-not-available */ + + /* end mark */ + NESTEDHVM_INTERCEPT_LAST, +}; + +/* Nested HVM on/off per domain */ +bool_t nestedhvm_enabled(struct domain *d); +int nestedhvm_initialise(struct domain *d); + +/* Nested VCPU */ +int nestedhvm_vcpu_initialise(struct vcpu *v); +int nestedhvm_vcpu_destroy(struct vcpu *v); +void nestedhvm_vcpu_reset(struct vcpu *v); +bool_t nestedhvm_vcpu_in_guestmode(struct vcpu *v); +void nestedhvm_vcpu_enter_guestmode(struct vcpu *v); +void nestedhvm_vcpu_exit_guestmode(struct vcpu *v); + +/* Nested paging */ +#define NESTEDHVM_PAGEFAULT_DONE 0 +#define NESTEDHVM_PAGEFAULT_INJECT 1 +#define NESTEDHVM_PAGEFAULT_ERROR 2 +int nestedhvm_hap_nested_page_fault(struct vcpu *v, paddr_t L2_gpa); + +/* Misc */ +#define nestedhvm_paging_mode_hap(v) (!!nhvm_vmcx_hap_enabled(v)) +#define nestedhvm_vmswitch_in_progress(v) \ + (!!vcpu_nestedhvm((v)).nv_hostflags.fields.vmswitch_in_progress) +#define nestedhvm_vmcx_flushtlb(d) \ + flush_tlb_mask(&(d)->arch.hvm_domain.nh_dirty_cpumask) + +#endif /* _HVM_NESTEDHVM_H */