mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
Nested Virtualization core implementation
Signed-off-by: Christoph Egger <Christoph.Egger@amd.com> Acked-by: Eddie Dong <eddie.dong@intel.com> Acked-by: Tim Deegan <Tim.Deegan@citrix.com> Committed-by: Tim Deegan <Tim.Deegan@citrix.com>
This commit is contained in:
1 parent
5ad20e41a8
commit
67bb195fe2
5 files changed
+244
No files matched your search
@@ -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
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Nested HVM
|
||||
* Copyright (c) 2011, Advanced Micro Devices, Inc.
|
||||
* Author: Christoph Egger <Christoph.Egger@amd.com>
|
||||
*
|
||||
* 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 <asm/msr.h>
|
||||
#include <asm/hvm/support.h> /* for HVM_DELIVER_NO_ERROR_CODE */
|
||||
#include <asm/hvm/hvm.h>
|
||||
#include <asm/hvm/nestedhvm.h>
|
||||
#include <asm/event.h> /* for local_event_delivery_(en|dis)able */
|
||||
#include <asm/paging.h> /* 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);
|
||||
|
||||
nv->nv_vmentry_pending = 0;
|
||||
nv->nv_vmexit_pending = 0;
|
||||
nv->nv_vmswitch_in_progress = 0;
|
||||
nv->nv_ioport80 = 0;
|
||||
nv->nv_ioportED = 0;
|
||||
|
||||
if (nv->nv_vvmcx)
|
||||
hvm_unmap_guest_frame(nv->nv_vvmcx);
|
||||
nv->nv_vvmcx = NULL;
|
||||
nv->nv_vvmcxaddr = VMCX_EADDR;
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Common shadow IO Permission bitmap */
|
||||
|
||||
/* There four global patterns of io bitmap each guest can
|
||||
* choose depending on interception of io port 0x80 and/or
|
||||
* 0xED (shown in table below).
|
||||
* The users of the bitmap patterns are in SVM/VMX specific code.
|
||||
*
|
||||
* bitmap port 0x80 port 0xed
|
||||
* hvm_io_bitmap cleared cleared
|
||||
* iomap[0] cleared set
|
||||
* iomap[1] set cleared
|
||||
* iomap[2] set set
|
||||
*/
|
||||
|
||||
/* same format and size as hvm_io_bitmap */
|
||||
#define IOBITMAP_SIZE 3*PAGE_SIZE/BYTES_PER_LONG
|
||||
/* same format as hvm_io_bitmap */
|
||||
#define IOBITMAP_VMX_SIZE 2*PAGE_SIZE/BYTES_PER_LONG
|
||||
|
||||
static unsigned long *shadow_io_bitmap[3];
|
||||
|
||||
void
|
||||
nestedhvm_setup(void)
|
||||
{
|
||||
/* shadow_io_bitmaps can't be declared static because
|
||||
* they must fulfill hw requirements (page aligned section)
|
||||
* and doing so triggers the ASSERT(va >= XEN_VIRT_START)
|
||||
* in __virt_to_maddr()
|
||||
*
|
||||
* So as a compromise pre-allocate them when xen boots.
|
||||
* This function must be called from within start_xen() when
|
||||
* it is valid to use _xmalloc()
|
||||
*/
|
||||
|
||||
/* shadow I/O permission bitmaps */
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
|
||||
/* Same format as hvm_io_bitmap */
|
||||
shadow_io_bitmap[0] = _xmalloc(IOBITMAP_VMX_SIZE, PAGE_SIZE);
|
||||
shadow_io_bitmap[1] = _xmalloc(IOBITMAP_VMX_SIZE, PAGE_SIZE);
|
||||
shadow_io_bitmap[2] = _xmalloc(IOBITMAP_VMX_SIZE, PAGE_SIZE);
|
||||
memset(shadow_io_bitmap[0], ~0U, IOBITMAP_VMX_SIZE);
|
||||
memset(shadow_io_bitmap[1], ~0U, IOBITMAP_VMX_SIZE);
|
||||
memset(shadow_io_bitmap[2], ~0U, IOBITMAP_VMX_SIZE);
|
||||
} else {
|
||||
/* Same size and format as hvm_io_bitmap */
|
||||
shadow_io_bitmap[0] = _xmalloc(IOBITMAP_SIZE, PAGE_SIZE);
|
||||
shadow_io_bitmap[1] = _xmalloc(IOBITMAP_SIZE, PAGE_SIZE);
|
||||
shadow_io_bitmap[2] = _xmalloc(IOBITMAP_SIZE, PAGE_SIZE);
|
||||
memset(shadow_io_bitmap[0], ~0U, IOBITMAP_SIZE);
|
||||
memset(shadow_io_bitmap[1], ~0U, IOBITMAP_SIZE);
|
||||
memset(shadow_io_bitmap[2], ~0U, IOBITMAP_SIZE);
|
||||
}
|
||||
|
||||
__clear_bit(0x80, shadow_io_bitmap[0]);
|
||||
__clear_bit(0xed, shadow_io_bitmap[1]);
|
||||
}
|
||||
|
||||
unsigned long *
|
||||
nestedhvm_vcpu_iomap_get(bool_t port_80, bool_t port_ed)
|
||||
{
|
||||
int i;
|
||||
extern int hvm_port80_allowed;
|
||||
|
||||
if (!hvm_port80_allowed)
|
||||
port_80 = 1;
|
||||
|
||||
if (port_80 == 0) {
|
||||
if (port_ed == 0)
|
||||
return hvm_io_bitmap;
|
||||
i = 0;
|
||||
} else {
|
||||
if (port_ed == 0)
|
||||
i = 1;
|
||||
else
|
||||
i = 2;
|
||||
}
|
||||
|
||||
return shadow_io_bitmap[i];
|
||||
}
|
||||
@@ -1260,6 +1260,8 @@ void __init __start_xen(unsigned long mbi_p)
|
||||
|
||||
if ( opt_watchdog )
|
||||
watchdog_setup();
|
||||
|
||||
nestedhvm_setup();
|
||||
|
||||
if ( !tboot_protect_mem_regions() )
|
||||
panic("Could not protect TXT memory regions\n");
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Nested HVM
|
||||
* Copyright (c) 2011, Advanced Micro Devices, Inc.
|
||||
* Author: Christoph Egger <Christoph.Egger@amd.com>
|
||||
*
|
||||
* 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 <xen/types.h> /* for uintNN_t */
|
||||
#include <xen/sched.h> /* for struct vcpu, struct domain */
|
||||
#include <asm/hvm/vcpu.h> /* 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 */
|
||||
};
|
||||
|
||||
/* Nested HVM on/off per domain */
|
||||
bool_t nestedhvm_enabled(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);
|
||||
#define nestedhvm_vcpu_enter_guestmode(v) \
|
||||
vcpu_nestedhvm(v).nv_guestmode = 1
|
||||
#define nestedhvm_vcpu_exit_guestmode(v) \
|
||||
vcpu_nestedhvm(v).nv_guestmode = 0
|
||||
|
||||
/* 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);
|
||||
|
||||
/* IO permission map */
|
||||
unsigned long *nestedhvm_vcpu_iomap_get(bool_t ioport_80, bool_t ioport_ed);
|
||||
|
||||
/* Misc */
|
||||
#define nestedhvm_paging_mode_hap(v) (!!nhvm_vmcx_hap_enabled(v))
|
||||
#define nestedhvm_vmswitch_in_progress(v) \
|
||||
(!!vcpu_nestedhvm((v)).nv_vmswitch_in_progress)
|
||||
|
||||
#endif /* _HVM_NESTEDHVM_H */
|
||||
@@ -23,6 +23,7 @@ int transmeta_init_cpu(void);
|
||||
void numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
|
||||
void arch_init_memory(void);
|
||||
void subarch_init_memory(void);
|
||||
void nestedhvm_setup(void);
|
||||
|
||||
void init_IRQ(void);
|
||||
void vesa_init(void);
|
||||
|
||||