x86, hvm: Hyper-V guest interface support with small set of enlightenments

A minimal implementation of the Viridian (Hyper-V) guest
interface. The only enlightenments advertised and supported are vAPIC
MSRs and long-spin-wait notifications. The set of enlightenments can
easily be extended in future, as they are found to provide a
performance win, and configured via an extended HVM_PARAM_VIRIDIAN hvm
parameter.

Signed-off-by: Peter Johnston <peter.johnston@citrix.com>
Signed-off-by: Tim Deegan <tim.deegan@citrix.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
This commit is contained in:
Keir Fraser committed 2008-10-14 10:45:29 +01:00
1 parent b525c05cf9
commit 39f97ffa29
22 files changed
+1330 -825

No files matched your search

+16 -10
View File
@@ -101,30 +101,36 @@ asm (
static enum { VGA_none, VGA_std, VGA_cirrus } virtual_vga = VGA_none;
static void
init_hypercalls(void)
static void init_hypercalls(void)
{
uint32_t eax, ebx, ecx, edx;
unsigned long i;
char signature[13];
xen_extraversion_t extraversion;
uint32_t base;
cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
for ( base = 0x40000000; base < 0x40001000; base += 0x100 )
{
cpuid(base, &eax, &ebx, &ecx, &edx);
*(uint32_t *)(signature + 0) = ebx;
*(uint32_t *)(signature + 4) = ecx;
*(uint32_t *)(signature + 8) = edx;
signature[12] = '\0';
*(uint32_t *)(signature + 0) = ebx;
*(uint32_t *)(signature + 4) = ecx;
*(uint32_t *)(signature + 8) = edx;
signature[12] = '\0';
BUG_ON(strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002));
if ( !strcmp("XenVMMXenVMM", signature) )
break;
}
BUG_ON(strcmp("XenVMMXenVMM", signature) || ((eax - base) < 2));
/* Fill in hypercall transfer pages. */
cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
cpuid(base + 2, &eax, &ebx, &ecx, &edx);
for ( i = 0; i < eax; i++ )
wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
/* Print version information. */
cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
cpuid(base + 1, &eax, &ebx, &ecx, &edx);
hypercall_xen_version(XENVER_extraversion, extraversion);
printf("Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
}
+3
View File
@@ -155,6 +155,7 @@ XENAPI_PLATFORM_CFG_TYPES = {
'vncdisplay': int,
'vnclisten': str,
'timer_mode': int,
'viridian': int,
'vncpasswd': str,
'vncunused': int,
'xauthority': str,
@@ -442,6 +443,8 @@ class XendConfig(dict):
if self.is_hvm():
if 'timer_mode' not in self['platform']:
self['platform']['timer_mode'] = 1
if 'viridian' not in self['platform']:
self['platform']['viridian'] = 0
if 'rtc_timeoffset' not in self['platform']:
self['platform']['rtc_timeoffset'] = 0
if 'hpet' not in self['platform']:
+4 -3
View File
@@ -43,9 +43,10 @@ HVM_PARAM_STORE_EVTCHN = 2
HVM_PARAM_PAE_ENABLED = 4
HVM_PARAM_IOREQ_PFN = 5
HVM_PARAM_BUFIOREQ_PFN = 6
HVM_PARAM_NVRAM_FD = 7
HVM_PARAM_VHPT_SIZE = 8
HVM_PARAM_BUFPIOREQ_PFN = 9
HVM_PARAM_NVRAM_FD = 7 # ia64
HVM_PARAM_VHPT_SIZE = 8 # ia64
HVM_PARAM_BUFPIOREQ_PFN = 9 # ia64
HVM_PARAM_VIRIDIAN = 9 # x86
HVM_PARAM_TIMER_MODE = 10
HVM_PARAM_HPET_ENABLED = 11
HVM_PARAM_ACPI_S_STATE = 14
+5
View File
@@ -2078,6 +2078,11 @@ class XendDomainInfo:
xc.hvm_set_param(self.domid, HVM_PARAM_TIMER_MODE,
long(timer_mode))
# Set Viridian interface configuration of domain
viridian = self.info["platform"].get("viridian")
if arch.type == "x86" and hvm and viridian is not None:
xc.hvm_set_param(self.domid, HVM_PARAM_VIRIDIAN, long(viridian))
# Optionally enable virtual HPET
hpet = self.info["platform"].get("hpet")
if hvm and hpet is not None:
+7 -1
View File
@@ -218,6 +218,11 @@ gopts.var('timer_mode', val='TIMER_MODE',
use="""Timer mode (0=delay virtual time when ticks are missed;
1=virtual time is always wallclock time.""")
gopts.var('viridian', val='VIRIDIAN',
fn=set_int, default=0,
use="""Expose Viridian interface to x86 HVM guest?
(Default is 0).""")
gopts.var('acpi', val='ACPI',
fn=set_int, default=1,
use="Disable or enable ACPI of HVM domain.")
@@ -856,7 +861,8 @@ def configure_hvm(config_image, vals):
'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', 'hpet',
'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check']
'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check',
'viridian' ]
for a in args:
if a in vals.__dict__ and vals.__dict__[a] is not None:
+1
View File
@@ -969,6 +969,7 @@ class sxp2xml:
'usbdevice',
'hpet',
'timer_mode',
'viridian',
'vhpt',
'guest_os_type',
'hap',
@@ -111,26 +111,37 @@ unsigned long alloc_xen_mmio(unsigned long len)
#ifndef __ia64__
static int init_hypercall_stubs(void)
static uint32_t xen_cpuid_base(void)
{
uint32_t eax, ebx, ecx, edx, pages, msr, i;
uint32_t base, eax, ebx, ecx, edx;
char signature[13];
cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
*(uint32_t*)(signature + 0) = ebx;
*(uint32_t*)(signature + 4) = ecx;
*(uint32_t*)(signature + 8) = edx;
signature[12] = 0;
for (base = 0x40000000; base < 0x40001000; base += 0x100) {
cpuid(base, &eax, &ebx, &ecx, &edx);
*(uint32_t*)(signature + 0) = ebx;
*(uint32_t*)(signature + 4) = ecx;
*(uint32_t*)(signature + 8) = edx;
signature[12] = 0;
if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
return base;
}
return 0;
}
static int init_hypercall_stubs(void)
{
uint32_t eax, ebx, ecx, edx, pages, msr, i, base;
base = xen_cpuid_base();
if (base == 0) {
printk(KERN_WARNING
"Detected Xen platform device but not Xen VMM?"
" (sig %s, eax %x)\n",
signature, eax);
"Detected Xen platform device but not Xen VMM?\n");
return -EINVAL;
}
cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
cpuid(base + 1, &eax, &ebx, &ecx, &edx);
printk(KERN_INFO "Xen version %d.%d.\n", eax >> 16, eax & 0xffff);
@@ -138,7 +149,7 @@ static int init_hypercall_stubs(void)
* Find largest supported number of hypercall pages.
* We'll create as many as possible up to this number.
*/
cpuid(0x40000002, &pages, &msr, &ecx, &edx);
cpuid(base + 2, &pages, &msr, &ecx, &edx);
/*
* Use __vmalloc() because vmalloc_exec() is not an exported symbol.
@@ -174,18 +185,12 @@ static int init_hypercall_stubs(void)
static void resume_hypercall_stubs(void)
{
uint32_t eax, ebx, ecx, edx, pages, msr, i;
char signature[13];
uint32_t base, ecx, edx, pages, msr, i;
cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
*(uint32_t*)(signature + 0) = ebx;
*(uint32_t*)(signature + 4) = ecx;
*(uint32_t*)(signature + 8) = edx;
signature[12] = 0;
base = xen_cpuid_base();
BUG_ON(base == 0);
BUG_ON(strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002));
cpuid(0x40000002, &pages, &msr, &ecx, &edx);
cpuid(base + 2, &pages, &msr, &ecx, &edx);
if (pages > max_hypercall_stub_pages)
pages = max_hypercall_stub_pages;
+1
View File
@@ -18,3 +18,4 @@ obj-y += vpic.o
obj-y += save.o
obj-y += vmsi.o
obj-y += stdvga.o
obj-y += viridian.o
+10
View File
@@ -1636,6 +1636,9 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
{
struct vcpu *v = current;
if ( cpuid_viridian_leaves(input, eax, ebx, ecx, edx) )
return;
if ( cpuid_hypervisor_leaves(input, eax, ebx, ecx, edx) )
return;
@@ -1954,6 +1957,9 @@ int hvm_do_hypercall(struct cpu_user_regs *regs)
break;
}
if ( (eax & 0x80000000) && is_viridian_domain(curr->domain) )
return viridian_hypercall(regs);
if ( (eax >= NR_hypercalls) || !hvm_hypercall32_table[eax] )
{
regs->eax = -ENOSYS;
@@ -2380,6 +2386,10 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
if ( a.value > HVMPTM_one_missed_tick_pending )
rc = -EINVAL;
break;
case HVM_PARAM_VIRIDIAN:
if ( a.value > 1 )
rc = -EINVAL;
break;
case HVM_PARAM_IDENT_PT:
rc = -EPERM;
if ( !IS_PRIV(current->domain) )
+5 -1
View File
@@ -1005,7 +1005,8 @@ static int svm_msr_read_intercept(struct cpu_user_regs *regs)
break;
default:
if ( rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
if ( rdmsr_viridian_regs(ecx, &eax, &edx) ||
rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
rdmsr_safe(ecx, eax, edx) == 0 )
{
regs->eax = eax;
@@ -1073,6 +1074,9 @@ static int svm_msr_write_intercept(struct cpu_user_regs *regs)
break;
default:
if ( wrmsr_viridian_regs(ecx, regs->eax, regs->edx) )
break;
switch ( long_mode_do_msr_write(regs) )
{
case HNDL_unhandled:
+350
View File
@@ -0,0 +1,350 @@
/******************************************************************************
* viridian.c
*
* An implementation of the Viridian hypercall interface.
*/
#include <xen/sched.h>
#include <xen/version.h>
#include <xen/perfc.h>
#include <xen/hypercall.h>
#include <xen/domain_page.h>
#include <asm/paging.h>
#include <asm/p2m.h>
#include <asm/hvm/support.h>
#include <public/sched.h>
#include <public/hvm/hvm_op.h>
/* Viridian MSR numbers. */
#define VIRIDIAN_MSR_GUEST_OS_ID 0x40000000
#define VIRIDIAN_MSR_HYPERCALL 0x40000001
#define VIRIDIAN_MSR_VP_INDEX 0x40000002
#define VIRIDIAN_MSR_EOI 0x40000070
#define VIRIDIAN_MSR_ICR 0x40000071
#define VIRIDIAN_MSR_TPR 0x40000072
/* Viridian Hypercall Status Codes. */
#define HV_STATUS_SUCCESS 0x0000
#define HV_STATUS_INVALID_HYPERCALL_CODE 0x0002
/* Viridian Hypercall Codes and Parameters. */
#define HvNotifyLongSpinWait 8
/* Viridian CPUID 4000003, Viridian MSR availability. */
#define CPUID3A_MSR_APIC_ACCESS (1 << 4)
#define CPUID3A_MSR_HYPERCALL (1 << 5)
#define CPUID3A_MSR_VP_INDEX (1 << 6)
/* Viridian CPUID 4000004, Implementation Recommendations. */
#define CPUID4A_MSR_BASED_APIC (1 << 3)
int cpuid_viridian_leaves(unsigned int leaf, unsigned int *eax,
unsigned int *ebx, unsigned int *ecx,
unsigned int *edx)
{
struct domain *d = current->domain;
if ( !is_viridian_domain(d) )
return 0;
leaf -= 0x40000000;
if ( leaf > 5 )
return 0;
*eax = *ebx = *ecx = *edx = 0;
switch ( leaf )
{
case 0:
*eax = 0x40000005; /* Maximum leaf */
*ebx = 0x7263694d; /* Magic numbers */
*ecx = 0x666F736F;
*edx = 0x76482074;
break;
case 1:
*eax = 0x31237648; /* Version number */
break;
case 2:
/* Hypervisor information, but only if the guest has set its
own version number. */
if ( d->arch.hvm_domain.viridian.guest_os_id.raw == 0 )
break;
*eax = 1; /* Build number */
*ebx = (xen_major_version() << 16) | xen_minor_version();
*ecx = 0; /* SP */
*edx = 0; /* Service branch and number */
break;
case 3:
/* Which hypervisor MSRs are available to the guest */
*eax = (CPUID3A_MSR_APIC_ACCESS |
CPUID3A_MSR_HYPERCALL |
CPUID3A_MSR_VP_INDEX);
break;
case 4:
/* Recommended hypercall usage. */
if ( (d->arch.hvm_domain.viridian.guest_os_id.raw == 0) ||
(d->arch.hvm_domain.viridian.guest_os_id.fields.os < 4) )
break;
*eax = CPUID4A_MSR_BASED_APIC;
*ebx = 2047; /* long spin count */
break;
}
return 1;
}
static void enable_hypercall_page(void)
{
struct domain *d = current->domain;
unsigned long gmfn = d->arch.hvm_domain.viridian.hypercall_gpa.fields.pfn;
unsigned long mfn = gmfn_to_mfn(d, gmfn);
uint8_t *p;
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
{
gdprintk(XENLOG_WARNING, "Bad GMFN %lx (MFN %lx)\n", gmfn, mfn);
return;
}
p = map_domain_page(mfn);
/*
* We set the bit 31 in %eax (reserved field in the Viridian hypercall
* calling convention) to differentiate Xen and Viridian hypercalls.
*/
*(u8 *)(p + 0) = 0x0d; /* orl $0x80000000, %eax */
*(u32 *)(p + 1) = 0x80000000;
*(u8 *)(p + 5) = 0x0f; /* vmcall/vmmcall */
*(u8 *)(p + 6) = 0x01;
*(u8 *)(p + 7) = ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
? 0xc1 : 0xd9);
*(u8 *)(p + 8) = 0xc3; /* ret */
memset(p + 9, 0xcc, PAGE_SIZE - 9); /* int3, int3, ... */
unmap_domain_page(p);
put_page_and_type(mfn_to_page(mfn));
}
int wrmsr_viridian_regs(uint32_t idx, uint32_t eax, uint32_t edx)
{
struct domain *d = current->domain;
uint64_t val = ((uint64_t)edx << 32) | eax;
if ( !is_viridian_domain(d) )
return 0;
switch ( idx )
{
case VIRIDIAN_MSR_GUEST_OS_ID:
perfc_incr(mshv_wrmsr_osid);
d->arch.hvm_domain.viridian.guest_os_id.raw = val;
gdprintk(XENLOG_INFO, "Guest os:\n");
gdprintk(XENLOG_INFO, "\tvendor: %x\n",
d->arch.hvm_domain.viridian.guest_os_id.fields.vendor);
gdprintk(XENLOG_INFO, "\tos: %x\n",
d->arch.hvm_domain.viridian.guest_os_id.fields.os);
gdprintk(XENLOG_INFO, "\tmajor: %x\n",
d->arch.hvm_domain.viridian.guest_os_id.fields.major);
gdprintk(XENLOG_INFO, "\tminor: %x\n",
d->arch.hvm_domain.viridian.guest_os_id.fields.minor);
gdprintk(XENLOG_INFO, "\tsp: %x\n",
d->arch.hvm_domain.viridian.guest_os_id.fields.service_pack);
gdprintk(XENLOG_INFO, "\tbuild: %x\n",
d->arch.hvm_domain.viridian.guest_os_id.fields.build_number);
break;
case VIRIDIAN_MSR_HYPERCALL:
perfc_incr(mshv_wrmsr_hc_page);
gdprintk(XENLOG_INFO, "Set hypercall page %"PRIx64".\n", val);
if ( d->arch.hvm_domain.viridian.guest_os_id.raw == 0 )
break;
d->arch.hvm_domain.viridian.hypercall_gpa.raw = val;
if ( d->arch.hvm_domain.viridian.hypercall_gpa.fields.enabled )
enable_hypercall_page();
break;
case VIRIDIAN_MSR_VP_INDEX:
perfc_incr(mshv_wrmsr_vp_index);
gdprintk(XENLOG_INFO, "Set VP index %"PRIu64".\n", val);
break;
case VIRIDIAN_MSR_EOI:
perfc_incr(mshv_wrmsr_eoi);
vlapic_EOI_set(vcpu_vlapic(current));
break;
case VIRIDIAN_MSR_ICR: {
struct vlapic *vlapic = vcpu_vlapic(current);
perfc_incr(mshv_wrmsr_icr);
eax &= ~(1 << 12);
edx &= 0xff000000;
vlapic_set_reg(vlapic, APIC_ICR2, edx);
if ( vlapic_ipi(vlapic, eax, edx) == X86EMUL_OKAY )
vlapic_set_reg(vlapic, APIC_ICR, eax);
break;
}
case VIRIDIAN_MSR_TPR:
perfc_incr(mshv_wrmsr_tpr);
vlapic_set_reg(vcpu_vlapic(current), APIC_TASKPRI, eax & 0xff);
break;
default:
return 0;
}
return 1;
}
int rdmsr_viridian_regs(uint32_t idx, uint32_t *eax, uint32_t *edx)
{
uint64_t val;
struct vcpu *v = current;
if ( !is_viridian_domain(v->domain) )
return 0;
switch ( idx )
{
case VIRIDIAN_MSR_GUEST_OS_ID:
perfc_incr(mshv_rdmsr_osid);
val = v->domain->arch.hvm_domain.viridian.guest_os_id.raw;
break;
case VIRIDIAN_MSR_HYPERCALL:
perfc_incr(mshv_rdmsr_hc_page);
val = v->domain->arch.hvm_domain.viridian.hypercall_gpa.raw;
break;
case VIRIDIAN_MSR_VP_INDEX:
perfc_incr(mshv_rdmsr_vp_index);
val = v->vcpu_id;
break;
case VIRIDIAN_MSR_ICR:
perfc_incr(mshv_rdmsr_icr);
val = (((uint64_t)vlapic_get_reg(vcpu_vlapic(v), APIC_ICR2) << 32) |
vlapic_get_reg(vcpu_vlapic(v), APIC_ICR));
break;
case VIRIDIAN_MSR_TPR:
perfc_incr(mshv_rdmsr_tpr);
val = vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI);
break;
default:
return 0;
}
*eax = val;
*edx = val >> 32;
return 1;
}
int viridian_hypercall(struct cpu_user_regs *regs)
{
struct domain *d = current->domain;
int mode = hvm_guest_x86_mode(current);
unsigned long input_params_gpa, output_params_gpa;
uint16_t status = HV_STATUS_SUCCESS;
union hypercall_input {
uint64_t raw;
struct {
uint16_t call_code;
uint16_t rsvd1;
unsigned rep_count:12;
unsigned rsvd2:4;
unsigned rep_start:12;
unsigned rsvd3:4;
};
} input;
union hypercall_output {
uint64_t raw;
struct {
uint16_t result;
uint16_t rsvd1;
unsigned rep_complete:12;
unsigned rsvd2:20;
};
} output = { 0 };
ASSERT(is_viridian_domain(d));
switch ( mode )
{
#ifdef __x86_64__
case 8:
input.raw = regs->rcx;
input_params_gpa = regs->rdx;
output_params_gpa = regs->r8;
break;
#endif
case 4:
input.raw = ((uint64_t)regs->edx << 32) | regs->eax;
input_params_gpa = ((uint64_t)regs->ebx << 32) | regs->ecx;
output_params_gpa = ((uint64_t)regs->edi << 32) | regs->esi;
break;
default:
goto out;
}
switch ( input.call_code )
{
case HvNotifyLongSpinWait:
perfc_incr(mshv_call_long_wait);
do_sched_op_compat(SCHEDOP_yield, 0);
status = HV_STATUS_SUCCESS;
break;
default:
status = HV_STATUS_INVALID_HYPERCALL_CODE;
break;
}
out:
output.result = status;
switch (mode) {
#ifdef __x86_64__
case 8:
regs->rax = output.raw;
break;
#endif
default:
regs->edx = output.raw >> 32;
regs->eax = output.raw;
break;
}
return HVM_HCALL_completed;
}
static int viridian_save_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
{
struct hvm_viridian_context ctxt;
if ( !is_viridian_domain(d) )
return 0;
ctxt.hypercall_gpa = d->arch.hvm_domain.viridian.hypercall_gpa.raw;
ctxt.guest_os_id = d->arch.hvm_domain.viridian.guest_os_id.raw;
return (hvm_save_entry(VIRIDIAN, 0, h, &ctxt) != 0);
}
static int viridian_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
{
struct hvm_viridian_context ctxt;
if ( hvm_load_entry(VIRIDIAN, h, &ctxt) != 0 )
return -EINVAL;
d->arch.hvm_domain.viridian.hypercall_gpa.raw = ctxt.hypercall_gpa;
d->arch.hvm_domain.viridian.guest_os_id.raw = ctxt.guest_os_id;
return 0;
}
HVM_REGISTER_SAVE_RESTORE(VIRIDIAN, viridian_save_cpu_ctxt,
viridian_load_cpu_ctxt, 1, HVMSR_PER_DOM);
+1 -1
View File
@@ -417,7 +417,7 @@ void vlapic_EOI_set(struct vlapic *vlapic)
hvm_dpci_msi_eoi(current->domain, vector);
}
static int vlapic_ipi(
int vlapic_ipi(
struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high)
{
unsigned int dest = GET_xAPIC_DEST_FIELD(icr_high);
+6 -1
View File
@@ -1677,7 +1677,8 @@ static int vmx_msr_read_intercept(struct cpu_user_regs *regs)
break;
}
if ( rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
if ( rdmsr_viridian_regs(ecx, &eax, &edx) ||
rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
rdmsr_safe(ecx, eax, edx) == 0 )
{
regs->eax = eax;
@@ -1852,6 +1853,10 @@ static int vmx_msr_write_intercept(struct cpu_user_regs *regs)
default:
if ( vpmu_do_wrmsr(regs) )
return X86EMUL_OKAY;
if ( wrmsr_viridian_regs(ecx, regs->eax, regs->edx) )
break;
switch ( long_mode_do_msr_write(regs) )
{
case HNDL_unhandled:
+18 -6
View File
@@ -577,7 +577,11 @@ DO_ERROR_NOCODE(TRAP_simd_error, simd_coprocessor_error)
int rdmsr_hypervisor_regs(
uint32_t idx, uint32_t *eax, uint32_t *edx)
{
idx -= 0x40000000;
struct domain *d = current->domain;
/* Optionally shift out of the way of Viridian architectural MSRs. */
uint32_t base = is_viridian_domain(d) ? 0x40000200 : 0x40000000;
idx -= base;
if ( idx > 0 )
return 0;
@@ -599,8 +603,10 @@ int wrmsr_hypervisor_regs(
uint32_t idx, uint32_t eax, uint32_t edx)
{
struct domain *d = current->domain;
/* Optionally shift out of the way of Viridian architectural MSRs. */
uint32_t base = is_viridian_domain(d) ? 0x40000200 : 0x40000000;
idx -= 0x40000000;
idx -= base;
if ( idx > 0 )
return 0;
@@ -628,7 +634,7 @@ int wrmsr_hypervisor_regs(
{
gdprintk(XENLOG_WARNING,
"Bad GMFN %lx (MFN %lx) to MSR %08x\n",
gmfn, mfn, 0x40000000);
gmfn, mfn, base + idx);
return 0;
}
@@ -650,14 +656,18 @@ int wrmsr_hypervisor_regs(
int cpuid_hypervisor_leaves(
uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
idx -= 0x40000000;
if ( idx > 2 )
struct domain *d = current->domain;
/* Optionally shift out of the way of Viridian architectural leaves. */
uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000;
idx -= base;
if ( idx > 2 )
return 0;
switch ( idx )
{
case 0:
*eax = 0x40000002; /* Largest leaf */
*eax = base + 2; /* Largest leaf */
*ebx = XEN_CPUID_SIGNATURE_EBX;
*ecx = XEN_CPUID_SIGNATURE_ECX;
*edx = XEN_CPUID_SIGNATURE_EDX;
@@ -673,6 +683,8 @@ int cpuid_hypervisor_leaves(
case 2:
*eax = 1; /* Number of hypercall-transfer pages */
*ebx = 0x40000000; /* MSR base address */
if ( is_viridian_domain(d) )
*ebx = 0x40000200;
*ecx = 0; /* Features 1 */
*edx = 0; /* Features 2 */
if ( !is_hvm_vcpu(current) )
File diff suppressed because it is too large. Load diff
+3
View File
@@ -28,6 +28,7 @@
#include <asm/hvm/vioapic.h>
#include <asm/hvm/io.h>
#include <xen/hvm/iommu.h>
#include <asm/hvm/viridian.h>
#include <asm/hvm/vmx/vmcs.h>
#include <asm/hvm/svm/vmcb.h>
#include <public/hvm/params.h>
@@ -74,6 +75,8 @@ struct hvm_domain {
/* Pass-through */
struct hvm_iommu hvm_iommu;
struct viridian_domain viridian;
bool_t hap_enabled;
bool_t qemu_mapcache_invalidate;
bool_t is_s3_suspended;
+3
View File
@@ -219,6 +219,9 @@ hvm_set_segment_register(struct vcpu *v, enum x86_segment seg,
hvm_funcs.set_segment_register(v, seg, reg);
}
#define is_viridian_domain(_d) \
(is_hvm_domain(_d) && ((_d)->arch.hvm_domain.params[HVM_PARAM_VIRIDIAN]))
void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx);
void hvm_migrate_timers(struct vcpu *v);
+65
View File
@@ -0,0 +1,65 @@
/*****************************************************************************
*
* include/xen/viridian.h
*
* Copyright (c) 2008 Citrix Corp.
*
*/
#ifndef __ASM_X86_HVM_VIRIDIAN_H__
#define __ASM_X86_HVM_VIRIDIAN_H__
union viridian_guest_os_id
{
uint64_t raw;
struct
{
uint64_t build_number:16;
uint64_t service_pack:8;
uint64_t minor:8;
uint64_t major:8;
uint64_t os:8;
uint64_t vendor:16;
} fields;
};
union viridian_hypercall_gpa
{ uint64_t raw;
struct
{
uint64_t enabled:1;
uint64_t reserved_preserved:11;
uint64_t pfn:48;
} fields;
};
struct viridian_domain
{
union viridian_guest_os_id guest_os_id;
union viridian_hypercall_gpa hypercall_gpa;
};
int
cpuid_viridian_leaves(
unsigned int leaf,
unsigned int *eax,
unsigned int *ebx,
unsigned int *ecx,
unsigned int *edx);
int
wrmsr_viridian_regs(
uint32_t idx,
uint32_t eax,
uint32_t edx);
int
rdmsr_viridian_regs(
uint32_t idx,
uint32_t *eax,
uint32_t *edx);
int
viridian_hypercall(struct cpu_user_regs *regs);
#endif /* __ASM_X86_HVM_VIRIDIAN_H__ */
+4
View File
@@ -98,4 +98,8 @@ struct vlapic *apic_round_robin(
int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda);
void vlapic_EOI_set(struct vlapic *vlapic);
int vlapic_ipi(struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high);
#endif /* __ASM_X86_HVM_VLAPIC_H__ */
+16
View File
@@ -111,4 +111,20 @@ PERFCOUNTER(shadow_unsync, "shadow OOS unsyncs")
PERFCOUNTER(shadow_unsync_evict, "shadow OOS evictions")
PERFCOUNTER(shadow_resync, "shadow OOS resyncs")
PERFCOUNTER(mshv_call_sw_addr_space, "MS Hv Switch Address Space")
PERFCOUNTER(mshv_call_flush_tlb_list, "MS Hv Flush TLB list")
PERFCOUNTER(mshv_call_flush_tlb_all, "MS Hv Flush TLB all")
PERFCOUNTER(mshv_call_long_wait, "MS Hv Notify long wait")
PERFCOUNTER(mshv_rdmsr_osid, "MS Hv rdmsr Guest OS ID")
PERFCOUNTER(mshv_rdmsr_hc_page, "MS Hv rdmsr hypercall page")
PERFCOUNTER(mshv_rdmsr_vp_index, "MS Hv rdmsr vp index")
PERFCOUNTER(mshv_rdmsr_icr, "MS Hv rdmsr icr")
PERFCOUNTER(mshv_rdmsr_tpr, "MS Hv rdmsr tpr")
PERFCOUNTER(mshv_wrmsr_osid, "MS Hv wrmsr Guest OS ID")
PERFCOUNTER(mshv_wrmsr_hc_page, "MS Hv wrmsr hypercall page")
PERFCOUNTER(mshv_wrmsr_vp_index, "MS Hv wrmsr vp index")
PERFCOUNTER(mshv_wrmsr_icr, "MS Hv wrmsr icr")
PERFCOUNTER(mshv_wrmsr_tpr, "MS Hv wrmsr tpr")
PERFCOUNTER(mshv_wrmsr_eoi, "MS Hv wrmsr eoi")
/*#endif*/ /* __XEN_PERFC_DEFN_H__ */
+12 -1
View File
@@ -421,9 +421,20 @@ struct hvm_hw_mtrr {
DECLARE_HVM_SAVE_TYPE(MTRR, 14, struct hvm_hw_mtrr);
/*
* Viridian hypervisor context.
*/
struct hvm_viridian_context {
uint64_t hypercall_gpa;
uint64_t guest_os_id;
};
DECLARE_HVM_SAVE_TYPE(VIRIDIAN, 15, struct hvm_viridian_context);
/*
* Largest type-code in use
*/
#define HVM_SAVE_CODE_MAX 14
#define HVM_SAVE_CODE_MAX 15
#endif /* __XEN_PUBLIC_HVM_SAVE_X86_H__ */
+7
View File
@@ -51,9 +51,16 @@
#define HVM_PARAM_BUFIOREQ_PFN 6
#ifdef __ia64__
#define HVM_PARAM_NVRAM_FD 7
#define HVM_PARAM_VHPT_SIZE 8
#define HVM_PARAM_BUFPIOREQ_PFN 9
#elif defined(__i386__) || defined(__x86_64__)
/* Expose Viridian interfaces to this HVM guest? */
#define HVM_PARAM_VIRIDIAN 9
#endif
/*
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.