xen/hv_xen_extension.patch

1763 lines
48 KiB
Diff
Raw Normal View History

--- /dev/null
+++ b/xen/include/asm-x86/hvm/hvm_extensions.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+ |
+ | Copyright (c) [2007, 2008] Novell, Inc.
+ | All Rights Reserved.
+ |
+ | This program is free software; you can redistribute it and/or
+ | modify it under the terms of version 2 of the GNU General Public License as
+ | published by the Free Software Foundation.
+ |
+ | This program is distributed in the hope that 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, contact Novell, Inc.
+ |
+ | To contact Novell about this file by physical or electronic mail,
+ | you may find current contact information at www.novell.com
+ |
+ |***************************************************************************
+*/
+
+/*
+ * hvm_extensions.h
+ * Implement Hyperv extensions.
+ * Engineering Contact: K. Y. Srinivasan
+ */
+
+#ifndef HVM_EXTENSION_H
+#define HVM_EXTENSION_H
+
+#include <xen/sched.h>
+#include <asm/domain.h>
+#include <xen/timer.h>
+#include <xen/time.h>
+#include <asm/regs.h>
+#include <asm/types.h>
+#include <asm/hvm/io.h>
+#include <asm/hvm/hvm.h>
+#include <asm/hvm/domain.h>
+
+int
+hyperv_dom_create(struct domain *d);
+void
+hyperv_dom_destroy(struct domain *d);
+int
+hyperv_vcpu_initialize(struct vcpu *v);
+void
+hyperv_vcpu_up(struct vcpu *v);
+void
+hyperv_vcpu_destroy(struct vcpu *v);
+int
+hyperv_do_cpu_id(uint32_t input, unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx);
+int
+hyperv_do_rd_msr(uint32_t idx, struct cpu_user_regs *regs);
+int
+hyperv_do_wr_msr(uint32_t idx, struct cpu_user_regs *regs);
+int
+hyperv_do_hypercall(struct cpu_user_regs *pregs);
+int
+hyperv_initialize(struct domain *d);
+
+
+
+
+static inline int
+hyperx_intercept_domain_create(struct domain *d)
+{
+#ifdef __x86_64__
+ if (d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] == 1) {
+ return(hyperv_dom_create(d));
+ }
+#endif
+ return (0);
+}
+
+static inline void
+hyperx_intercept_domain_destroy(struct domain *d)
+{
+#ifdef __x86_64__
+ if (d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] == 1)
+ {
+ hyperv_dom_destroy(d);
+ }
+#endif
+}
+
+static inline int
+hyperx_intercept_vcpu_initialize(struct vcpu *v)
+{
+#ifdef __x86_64__
+ struct domain *d = v->domain;
+ if (d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] == 1)
+ {
+ return(hyperv_vcpu_initialize(v));
+ }
+#endif
+ return (0);
+}
+
+
+static inline void
+hyperx_intercept_vcpu_up(struct vcpu *v)
+{
+#ifdef __x86_64__
+ struct domain *d = current->domain;
+ if (d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] == 1)
+ {
+ hyperv_vcpu_up(v);
+ }
+#endif
+}
+
+static inline void
+hyperx_intercept_vcpu_destroy(struct vcpu *v)
+{
+#ifdef __x86_64__
+ struct domain *d = v->domain;
+ if (d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] == 1)
+ {
+ hyperv_vcpu_destroy(v);
+ }
+#endif
+}
+
+static inline int
+hyperx_intercept_do_cpuid(uint32_t idx, unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+#ifdef __x86_64__
+ struct domain *d = current->domain;
+ if (d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] == 1)
+ {
+ return(hyperv_do_cpu_id(idx, eax, ebx, ecx, edx));
+ }
+#endif
+ return (0);
+}
+
+static inline int
+hyperx_intercept_do_msr_read(uint32_t idx, struct cpu_user_regs *regs)
+{
+#ifdef __x86_64__
+ struct domain *d = current->domain;
+ if (d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] == 1)
+ {
+ return(hyperv_do_rd_msr(idx, regs));
+ }
+#endif
+ return (0);
+}
+
+static inline int
+hyperx_intercept_do_msr_write(uint32_t idx, struct cpu_user_regs *regs)
+{
+#ifdef __x86_64__
+ struct domain *d = current->domain;
+ if (d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] == 1)
+ {
+ return(hyperv_do_wr_msr(idx, regs));
+ }
+#endif
+ return (0);
+}
+
+static inline int
+hyperx_intercept_do_hypercall(struct cpu_user_regs *regs)
+{
+#ifdef __x86_64__
+ struct domain *d = current->domain;
+ if (d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] == 1)
+ {
+ return(hyperv_do_hypercall(regs));
+ }
+#endif
+ return (0);
+}
+
+int hyperx_initialize(struct domain *d);
+
+#endif
--- /dev/null
+++ b/xen/arch/x86/hvm/hyperv/Makefile
@@ -0,0 +1,2 @@
+obj-y += hv_intercept.o
+obj-y += hv_hypercall.o
--- /dev/null
+++ b/xen/arch/x86/hvm/hyperv/hv_errno.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+ |
+ | Copyright (c) [2007, 2008] Novell, Inc.
+ | All Rights Reserved.
+ |
+ | This program is free software; you can redistribute it and/or
+ | modify it under the terms of version 2 of the GNU General Public License as
+ | published by the Free Software Foundation.
+ |
+ | This program is distributed in the hope that 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, contact Novell, Inc.
+ |
+ | To contact Novell about this file by physical or electronic mail,
+ | you may find current contact information at www.novell.com
+ |
+ |***************************************************************************
+*/
+
+/*
+ * hv_errno.h
+ * Error codes for the Novell Shim.
+ *
+ * Engineering Contact: K. Y. Srinivasan
+ */
+
+#ifndef HV_ERRNO_H
+#define HV_ERRNO_H
+
+#define HV_STATUS_SUCCESS 0x0000
+#define HV_STATUS_INVALID_HYPERCALL_CODE 0x0002
+#define HV_STATUS_INVALID_HYPERCALL_INPUT 0x0003
+#define HV_STATUS_INVALID_ALIGNMENT 0x0004
+#define HV_STATUS_INVALID_PARAMETER 0x0005
+#define HV_STATUS_ACCESS_DENIED 0x0006
+#define HV_STATUS_INVALID_PARTITION_STATE 0x0007
+#define HV_STATUS_OPERATION_DENIED 0x0008
+#define HV_STATUS_UNKNOWN_PROPERTY 0x0009
+#define HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE 0x000A
+#define HV_STATUS_INSUFFICIENT_MEMORY 0x000B
+#define HV_STATUS_PARTITION_TOO_DEEP 0x000C
+#define HV_STATUS_INVALID_PARTITION_ID 0x000D
+#define HV_STATUS_INVALID_VP_INDEX 0x000E
+#define HV_STATUS_UNABLE_TO_RESTORE_STATE 0x000F
+#define HV_STATUS_NOT_FOUND 0x0010
+#define HV_STATUS_INVALID_PORT_ID 0x0011
+#define HV_STATUS_INVALID_CONNECTION_ID 0x0012
+#define HV_STATUS_INSUFFICIENT_BUFFERS 0x0013
+#define HV_STATUS_NOT_ACKNOWLEDGED 0x0014
+#define HV_STATUS_INVALID_VP_STATE 0x0015
+#define HV_STATUS_ACKNOWLEDGED 0x0016
+#define HV_STATUS_INVALID_SAVE_RESTORE_STATE 0x0017
+#define HV_STATUS_NO_MEMORY_4PAGES 0x0100
+#define HV_STATUS_NO_MEMORY_16PAGES 0x0101
+#define HV_STATUS_NO_MEMORY_64PAGES 0x0102
+#define HV_STATUS_NO_MEMORY_256PAGES 0x0103
+#define HV_STATUS_NO_MEMORY_1024PAGES 0x0104
+#endif
--- /dev/null
+++ b/xen/arch/x86/hvm/hyperv/hv_hypercall.c
@@ -0,0 +1,153 @@
+/****************************************************************************
+ |
+ | Copyright (c) [2007, 2008] Novell, Inc.
+ | All Rights Reserved.
+ |
+ | This program is free software; you can redistribute it and/or
+ | modify it under the terms of version 2 of the GNU General Public License as
+ | published by the Free Software Foundation.
+ |
+ | This program is distributed in the hope that 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, contact Novell, Inc.
+ |
+ | To contact Novell about this file by physical or electronic mail,
+ | you may find current contact information at www.novell.com
+ |
+ |***************************************************************************
+*/
+
+/*
+ * nshypercall.c.
+ * This file implements the hypercall component of the hyperv Shim.
+ *
+ * Engineering Contact: K. Y. Srinivasan
+ */
+
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/hvm/support.h>
+#include <xen/cpumask.h>
+#include <xen/event.h>
+#include <xen/domain.h>
+#include <xen/hypercall.h>
+#include <public/sched.h>
+
+#include <asm/hvm/hvm_extensions.h>
+#include "hv_shim.h"
+#include "hv_errno.h"
+#include "hv_hypercall.h"
+
+
+void
+hv_print_stats(hv_partition_t *curp, int i)
+{
+ hv_vcpu_t *v;
+ v = &curp->vcpu_state[i];
+ printk("Printing stats for vcpu ID: %d\n", i);
+
+ printk("Number of context switches: %lu\n", v->stats.num_switches);
+ printk("Number of long spin waits: %lu\n", v->stats.num_long_spinwaits);
+ printk("Number of TPR reads: %lu\n", v->stats.num_tpr_reads);
+ printk("Number of ICR reads: %lu\n", v->stats.num_icr_reads);
+ printk("Number of Eoi writes: %lu\n", v->stats.num_eoi_writes);
+ printk("Number of Tpr writes: %lu\n", v->stats.num_tpr_writes);
+ printk("Number of Icr writes: %lu\n", v->stats.num_icr_writes);
+
+}
+
+static int
+hv_switch_va(hv_vcpu_t *vcpup, int fast, paddr_t input)
+{
+ paddr_t new_cr3;
+ int ret_val = HV_STATUS_SUCCESS;
+
+ /*
+ * XXXKYS: the spec sys the asID is passed via memory at offset 0 of
+ * the page whose GPA is in the input register. However, it appears
+ * the current build of longhorn (longhorn-2007-02-06-x86_64-fv-02)
+ * passes the asID in the input register instead. Need to check if
+ * future builds do this.
+ * The fast bit defines how the parameter is passed.
+ */
+ if (fast)
+ {
+ hvm_set_cr3(input);
+ }
+ else
+ {
+ /*
+ * Slow path; copy the new value.
+ */
+ if (!hvm_copy_from_guest_phys(&new_cr3, input, sizeof(paddr_t)))
+ hvm_set_cr3(new_cr3);
+ else
+ ret_val = HV_STATUS_INVALID_PARAMETER;
+ }
+
+#ifdef HV_STATS
+ vcpup->stats.num_switches++;
+#endif
+ return (ret_val);
+}
+
+void
+hv_handle_hypercall(u64 opcode, u64 input, u64 output,
+ u64 *ret_val)
+{
+ unsigned short verb;
+ int fast;
+ unsigned short rep_count;
+ unsigned short start_index;
+ hv_partition_t *curp = hv_get_current_partition();
+ hv_vcpu_t *vcpup = &curp->vcpu_state[hv_get_current_vcpu_index()];
+ u64 partition_id;
+
+ fast = (int)((opcode >>16) & 0x1);
+ verb = (short)(opcode & 0xffff);
+ rep_count = (short)((opcode >>32) & 0xfff);
+ start_index = (short)((opcode >> 48) & 0xfff);
+ switch (verb)
+ {
+ case HV_GET_PARTITION_ID:
+ if (!hv_privilege_check(curp, HV_ACCESS_PARTITION_ID))
+ {
+ *ret_val =
+ hv_build_hcall_retval(HV_STATUS_ACCESS_DENIED, 0);
+ return;
+ }
+ partition_id = (u64)current->domain->domain_id;
+ if (hvm_copy_to_guest_phys(output, &partition_id, 8))
+ {
+ /*
+ * Invalid output area.
+ */
+ *ret_val =
+ hv_build_hcall_retval(HV_STATUS_INVALID_PARAMETER, 0);
+ return;
+ }
+ *ret_val = hv_build_hcall_retval(HV_STATUS_SUCCESS, 0);
+ return;
+ case HV_SWITCH_VA:
+ *ret_val = hv_build_hcall_retval(hv_switch_va(vcpup, fast, input), 0);
+ return;
+
+ case HV_NOTIFY_LONG_SPIN_WAIT:
+#ifdef HV_STATS
+ vcpup->stats.num_long_spinwaits++;
+#endif
+ do_sched_op_compat(SCHEDOP_yield, 0);
+ *ret_val = hv_build_hcall_retval(HV_STATUS_SUCCESS, 0);
+ return;
+
+ default:
+ printk("Unkown/Unsupported hypercall: verb is: %d\n", verb);
+ *ret_val =
+ hv_build_hcall_retval(HV_STATUS_INVALID_HYPERCALL_CODE, 0);
+ return;
+ }
+}
--- /dev/null
+++ b/xen/arch/x86/hvm/hyperv/hv_hypercall.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+ |
+ | Copyright (c) [2007, 2008] Novell, Inc.
+ | All Rights Reserved.
+ |
+ | This program is free software; you can redistribute it and/or
+ | modify it under the terms of version 2 of the GNU General Public License as
+ | published by the Free Software Foundation.
+ |
+ | This program is distributed in the hope that 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, contact Novell, Inc.
+ |
+ | To contact Novell about this file by physical or electronic mail,
+ | you may find current contact information at www.novell.com
+ |
+ |***************************************************************************
+*/
+
+/*
+ * hv_hypercall.h
+ *
+ * Engineering Contact: K. Y. Srinivasan
+ */
+
+#ifndef HV_HYPERCALL_H
+#define HV_HYPERCALL_H
+
+
+/*
+ * Hypercall verbs.
+ */
+
+#define HV_GET_PARTITION_PROPERTY 0x0044
+#define HV_SET_PARTITION_PROPERTY 0x0045
+#define HV_GET_PARTITION_ID 0x0046
+#define HV_SWITCH_VA 0x0001
+#define HV_FLUSH_VA 0x0002
+#define HV_FLUSH_VA_LIST 0x0003
+#define HV_NOTIFY_LONG_SPIN_WAIT 0x0008
+
+#endif /* HV_HYPERCALL_H */
--- /dev/null
+++ b/xen/arch/x86/hvm/hyperv/hv_intercept.c
- bnc#564406 - Make the new PV drivers work with older hosts that do not understand the new PV driver protocol. - Upstream Xen version renamed to 4.0.0 in changeset 20624 & 20625. - fate#307594: HP-MCBS: XEN: support NR_CPUS=256 This is a spec file change (xen.spec) - bnc#555152 - "NAME" column in xentop (SLES11) output limited to 10 characters unlike SLES10 The update to c/s 20572 includes this fix (at c/s 20567). - Modify xen-paths.diff - Merge xend-tap-fix.patch to xen-domUloader.diff remove part of it which accepted by upstream - Load gntdev module in xend init script similar to blkbk, netbk, etc. - Backport dmmd from sles11/xen block-dmmd xen-qemu-iscsi-fix.patch xen.spec - Fix regression when create_vbd for tap xend-tap-fix.patch - Temporarily disable libxl because of libconfig dependency. - fate#302864 domUloader support lvm in disk domUloader.py Note: for test in Beta1, if not good, remove it - fate#302864 domUloader support fs on whole disk domUloader.py - Turn KMPs back on now that kernel side fix is checked in. - fate#304415 VMM: ability to switch networking mode Add vif-route-ifup to handle routed configurations using sysconfig scripts. vif-route-ifup.patch - fate#307540 USB for Xen VMs usb-add.patch - fate#305545 XEN extra descriptive field within xenstore add_des.patch - Update to Xen version 3.5.0 for the following features. fate#304226 XEN: FlexMigration feature of VT-x2 support fate#305004 Add SR-IOV PF and VF drivers to Vt-d enabled Xen fate#306830 T states in Xen controlling by MSR fate#306832 Fix for xen panic on new processors fate#306833 Westmere and Nehalem-EX: Add support for Pause Loop exiting feature for Xen fate#306835 Xen: server virtual power management enhacement fate#306837 VT-d2 - PCI SIG ATS support fate#306872 Xen: Node manager support P/T-states change when Vt-d enable fate#306873 Xen: SMP guest live migration may fail with hap=1 on NHM fate#306875 Westmere: LT-SX (Xen) fate#306891 RAS features for Xen: Add support for Machine Check and CPU/Memory online/offline features fate#307322 1GB page support in Xen fate#307324 Xen IOMMU support OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=26
2010-01-16 01:12:54 +01:00
@@ -0,0 +1,1009 @@
+/****************************************************************************
+ |
+ | Copyright (c) [2007, 2008] Novell, Inc.
+ | All Rights Reserved.
+ |
+ | This program is free software; you can redistribute it and/or
+ | modify it under the terms of version 2 of the GNU General Public License as
+ | published by the Free Software Foundation.
+ |
+ | This program is distributed in the hope that 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, contact Novell, Inc.
+ |
+ | To contact Novell about this file by physical or electronic mail,
+ | you may find current contact information at www.novell.com
+ |
+ |***************************************************************************
+*/
+
+/*
+ * nsintercept.c.
+ * This file implements the intercepts to support the Hyperv Shim.
+ *
+ * Engineering Contact: K. Y. Srinivasan
+ */
+
+#include <asm/hvm/hvm_extensions.h>
+
+
+#include <asm/config.h>
+#include <asm/hvm/io.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/apicdef.h>
+#include <asm/regs.h>
+#include <asm/msr.h>
+#include <asm-x86/event.h>
+#include <asm-x86/apicdef.h>
+
+#include <xen/string.h>
+#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/compile.h>
+#include <xen/hvm/save.h>
+#include <public/sched.h>
+
+
+/*
+ * Local includes; extension specific.
+ */
+#include "hv_errno.h"
+#include "hv_shim.h"
+
+
+/*
+ * Implement the Hyperv Shim.
+ */
+
+extern struct hvm_mmio_handler vlapic_mmio_handler;
+
+
+static inline void
+hv_hypercall_page_initialize(void *hypercall_page);
+
+static inline void *
+get_virt_from_gmfn(struct domain *d, unsigned long gmfn)
+{
+ unsigned long mfn = gmfn_to_mfn(d, gmfn);
+ if (mfn == INVALID_MFN)
+ return (NULL);
+ return (map_domain_page(mfn));
+}
+
+static inline void
+inject_interrupt(struct vcpu *v, int vector, int type)
+{
+ struct vlapic *vlapic = vcpu_vlapic(v);
+
+ /*
+ * XXXKYS: Check the trigger mode.
+ */
+ if (vlapic_set_irq(vlapic, vector, 1))
+ vcpu_kick(v);
+}
+
+
+static inline void
+hv_write_guestid_msr(hv_partition_t *curp, hv_vcpu_t *cur_vcpu, u64 msr_content)
+{
+ curp->guest_id_msr = msr_content;
+ if (curp->guest_id_msr == 0)
+ {
+ /*
+ * Guest has cleared the guest ID;
+ * clear the hypercall page.
+ */
+ if (curp->hypercall_msr)
+ cur_vcpu->flags &= ~HV_VCPU_UP;
+ }
+}
+
+
+static inline void
+hv_write_hypercall_msr(hv_partition_t *curp,
+ hv_vcpu_t *cur_vcpu,
+ u64 msr_content)
+{
+ unsigned long gmfn;
+ void *hypercall_page;
+ struct domain *d = cur_vcpu->xen_vcpu->domain;
+
+ spin_lock(&curp->lock);
+ gmfn = (msr_content >> 12);
+ if (curp->guest_id_msr == 0)
+ {
+ /* Nothing to do if the guest is not registered*/
+ spin_unlock(&curp->lock);
+ return;
+ }
+ /*
+ * Guest is registered; see if we can turn-on the
+ * hypercall page.
+ * XXXKYS: Can the guest write the GPA in one call and
+ * subsequently enable it? Check. For now assume that all the
+ * info is specified in one call.
+ */
+ if (((u32)msr_content & (0x00000001)) == 0)
+ {
+ /*
+ * The client is not enabling the hypercall; just
+ * ignore everything.
+ */
+ spin_unlock(&curp->lock);
+ return;
+ }
+ hypercall_page = get_virt_from_gmfn(d,gmfn);
+ if (hypercall_page == NULL)
+ {
+ /*
+ * The guest specified a bogus GPA; inject a GP fault
+ * into the guest.
+ */
+ hvm_inject_exception(TRAP_gp_fault, 0, 0);
+ spin_unlock(&curp->lock);
+ return;
+ }
+ hv_hypercall_page_initialize(hypercall_page);
+ unmap_domain_page(hypercall_page);
+ if (hvm_funcs.guest_x86_mode(current) == 8)
+ curp->long_mode_guest = 1;
+ else
+ curp->long_mode_guest = 0;
+ curp->hypercall_msr = msr_content;
+ spin_unlock(&curp->lock);
+ cur_vcpu->flags |= HV_VCPU_UP;
+}
+
+
+int
+hyperv_initialize(struct domain *d)
+{
+ int i;
+ printk("Hyperv extensions initialized\n");
+ if (hyperv_dom_create(d))
+ {
+ printk("Hyperv dom create failed\n");
+ return (1);
+ }
+ for (i = 0; i < d->max_vcpus; i++)
+ {
+ if (d->vcpu[i] != NULL)
+ {
+ if (hyperv_vcpu_initialize(d->vcpu[i]))
+ {
+ int j;
+ for (j= (i-1); j >=0; j--)
+ {
+ hyperv_vcpu_destroy(d->vcpu[j]);
+ }
+ hyperv_dom_destroy(d);
+ return (1);
+ }
+ }
+ }
+ return (0);
+}
+
+static inline u64
+hv_get_time_since_boot(hv_partition_t *curp)
+{
+ u64 curTime = get_s_time();
+ return ((curTime - curp->domain_boot_time)/100) ;
+}
+
+static inline int
+hv_call_from_bios(void)
+{
+ if (hvm_paging_enabled(current))
+ return (0);
+ else
+ return (1);
+}
+
+
+static inline int
+hv_os_registered(void)
+{
+ hv_partition_t *curp = hv_get_current_partition();
+ return (curp->guest_id_msr != 0?1:0);
+}
+
+
+
+static inline void
+hv_set_partition_privileges(hv_partition_t *hvpp)
+{
+ /*
+ * This is based on the hypervisor spec under section 5.2.3.
+ */
+ hvpp->privileges = HV_SHIM_PRIVILEGES;
+}
+
+static inline u32
+hv_get_recommendations(void)
+{
+ /*
+ *For now we recommend all the features. Need to validate.
+ */
+ if ( paging_mode_hap(current->domain))
+ /*
+ * If HAP is enabled; the guest should not use TLB flush
+ * related enlightenments.
+ */
+ return (USE_CSWITCH_HCALL | USE_APIC_MSRS | USE_RESET_MSR | USE_RELAXED_TIMING);
+ else
+ /*
+ * For now disable TLB flush enlightenments.
+ */
+ return (USE_CSWITCH_HCALL | USE_APIC_MSRS | USE_RESET_MSR | USE_RELAXED_TIMING);
+}
+
+static inline u32
+hv_get_max_vcpus_supported(void)
+{
+ return HVM_MAX_VCPUS;
+}
+
+
+static inline void
+hv_read_icr(u64 *icr_content)
+{
+ unsigned long icr_low, icr_high;
+
+ icr_low = vlapic_mmio_handler.read_handler(current,
+ (vlapic_base_address(vcpu_vlapic(current)) + APIC_ICR), 4, &icr_low);
+ icr_high = vlapic_mmio_handler.read_handler(current,
+ (vlapic_base_address(vcpu_vlapic(current)) + APIC_ICR2), 4, &icr_high);
+ *icr_content = (((u64)icr_high<< 32) | icr_low);
+
+}
+
+static inline void
+hv_read_tpr(u64 *tpr_content)
+{
+
+ vlapic_mmio_handler.read_handler(current,
+ (vlapic_base_address(vcpu_vlapic(current)) + APIC_TASKPRI),
+ 4, (unsigned long *)&tpr_content);
+}
+
+static inline void
+hv_write_eoi(u64 msr_content)
+{
+ u32 eoi = (u32)msr_content;
+
+ vlapic_mmio_handler.write_handler(current,
+ (vlapic_base_address(vcpu_vlapic(current)) + APIC_EOI), 4, eoi);
+
+}
+
+static inline void
+hv_write_icr(u64 msr_content)
+{
+ u32 icr_low, icr_high;
+ icr_low = (u32)msr_content;
+ icr_high = (u32)(msr_content >> 32);
+
+ if (icr_high != 0)
+ {
+ vlapic_mmio_handler.write_handler(current,
+ (vlapic_base_address(vcpu_vlapic(current)) + APIC_ICR2), 4,
+ icr_high);
+ }
+ if (icr_low != 0)
+ {
+ vlapic_mmio_handler.write_handler(current,
+ (vlapic_base_address(vcpu_vlapic(current)) + APIC_ICR), 4,
+ icr_low);
+ }
+
+}
+
+static inline void
+hv_write_tpr(u64 msr_content)
+{
+ u32 tpr = (u32)msr_content;
+
+
+ vlapic_mmio_handler.write_handler(current,
+ (vlapic_base_address(vcpu_vlapic(current)) + APIC_TASKPRI), 4, tpr);
+
+}
+
+static inline void
+hv_hypercall_page_initialize(void *hypercall_page)
+{
+ char *p;
+
+ memset(hypercall_page, 0, PAGE_SIZE);
+ p = (char *)(hypercall_page) ;
+ /*
+ * We need to differentiate hypercalls that are to be processed by Xen
+ * from those that need to be processed by the hyperV shim. Xen hypercalls
+ * use eax to pass the opcode; set the high order bit in eax for hypercalls
+ * destined for the hyperV shim (thanks Steven)
+ */
+ *(u8 *)(p + 0) = 0x0d; /* eax or imm32 */
+ *(u8 *)(p + 1) = 0x00;
+ *(u8 *)(p + 2) = 0x00;
+ *(u8 *)(p + 3) = 0x00;
+ *(u8 *)(p + 4) = 0x80; /* eax |= HYPERV_HCALL */
+
+ *(u8 *)(p + 5) = 0x0f; /* vmcall */
+ *(u8 *)(p + 6) = 0x01;
+ if (boot_cpu_data.x86_vendor == 0)
+ *(u8 *)(p + 7) = 0xc1;
+ else
+ *(u8 *)(p + 7) = 0xd9;
+ *(u8 *)(p + 8) = 0xc3; /* ret */
+}
+
+static inline int
+hv_access_time_refcnt(hv_partition_t *curp, u64 *msr_content)
+{
+ if (!hv_privilege_check(curp, HV_ACCESS_TIME_REF_CNT))
+ {
+ /*
+ * The partition does not have the privilege to
+ * read this; return error.
+ */
+ return (0);
+ }
+ *msr_content = hv_get_time_since_boot(curp);
+ return (1);
+}
+
+
+void
+hyperv_vcpu_up(struct vcpu *v)
+{
+ hv_partition_t *curp = hv_get_current_partition();
+ hv_vcpu_t *vcpup;
+ vcpup = &curp->vcpu_state[v->vcpu_id];
+ vcpup->flags |= HV_VCPU_UP;
+}
+
+int
+hyperv_do_hypercall(struct cpu_user_regs *pregs)
+{
+ hv_partition_t *curp = hv_get_current_partition();
+ hv_vcpu_t *vcpup;
+ int long_mode_guest = curp->long_mode_guest;
+
+ if (pregs->_eax & HYPERV_HCALL)
+ {
+ u64 opcode, input, output, ret_val;
+ vcpup = &curp->vcpu_state[hv_get_current_vcpu_index()];
+
+ pregs->_eax &= ~HYPERV_HCALL;
+ /*
+ * This is an extension hypercall; process it; but first make
+ * sure that the CPU is in the right state for invoking
+ * the hypercall - protected mode at CPL 0.
+ */
+ if (hv_invalid_cpu_state())
+ {
+ hvm_inject_exception(TRAP_gp_fault, 0, 0);
+ ret_val = hv_build_hcall_retval(HV_STATUS_INVALID_VP_STATE, 0);
+ hv_set_syscall_retval(pregs, long_mode_guest, ret_val);
+ return (1);
+ }
+ if (long_mode_guest)
+ {
+ opcode = pregs->ecx;
+ input = pregs->edx;
+ output = pregs->r8;
+ } else
+ {
+ opcode =
+ ((((u64)pregs->edx) << 32) | ((u64)pregs->eax));
+ input =
+ ((((u64)pregs->ebx) << 32) | ((u64)pregs->ecx));
+ output =
+ ((((u64)pregs->edi) << 32) | ((u64)pregs->esi));
+ }
+ hv_handle_hypercall(opcode, input, output, &ret_val);
+ hv_set_syscall_retval(pregs, long_mode_guest, ret_val);
+ return (1);
+ }
+ /*
+ * This hypercall page is not the page for the Veridian extension.
+ */
+ return (0);
+}
+
+
+int
+hyperv_dom_create(struct domain *d)
+{
+ hv_partition_t *hvpp;
+ hvpp = xmalloc_bytes(sizeof(hv_partition_t));
+ if (hvpp == NULL)
+ {
+ printk("Hyprv Dom Create: Memory allocation failed\n");
+ return (1);
+ }
+ memset(hvpp, 0, sizeof(*hvpp));
+ spin_lock_init(&hvpp->lock);
+ /*
+ * Set the partition wide privilege; We can start with no privileges
+ * and progressively turn on fancier hypervisor features.
+ */
+ hv_set_partition_privileges(hvpp);
+ /*
+ * Stash away pointer to our state in the hvm domain structure.
+ */
+ d->arch.hvm_domain.hyperv_handle = hvpp;
+ hvpp->domain_boot_time = get_s_time();
+ return (0);
+}
+
+void
+hyperv_dom_destroy(struct domain *d)
+{
+ int i;
+ hv_partition_t *curp = d->arch.hvm_domain.hyperv_handle;
+ printk("Hyper-V Domain Being Destroyed\n");
+ ASSERT(curp != NULL);
+#ifdef HV_STATS
+ printk("DUMP STATS\n");
+ for (i = 0; i < d->max_vcpus; i++)
+ if (d->vcpu[i] != NULL)
+ hv_print_stats(curp, i);
+#endif
+
+ xfree(d->arch.hvm_domain.hyperv_handle);
+ d->arch.hvm_domain.hyperv_handle = NULL;
+}
+
+int
+hyperv_vcpu_initialize(struct vcpu *v)
+{
+ hv_vcpu_t *vcpup;
+ hv_partition_t *curp = v->domain->arch.hvm_domain.hyperv_handle;
+ vcpup = &curp->vcpu_state[v->vcpu_id];
+ atomic_inc(&curp->vcpus_active);
+ if (v->vcpu_id == 0)
+ vcpup->flags |= HV_VCPU_BOOT_CPU;
+ /*
+ * Initialize all the synthetic MSRs corresponding to this VCPU.
+ * Note that all state is set to 0 to begin
+ * with.
+ */
+ vcpup->version_msr = 0x00000001;
+ vcpup->xen_vcpu = v;
+
+ return (0);
+}
+
+void
+hyperv_vcpu_destroy(struct vcpu *v)
+{
+ hv_vcpu_t *vcpup;
+ hv_partition_t *curp = v->domain->arch.hvm_domain.hyperv_handle;
+
+ vcpup = &curp->vcpu_state[v->vcpu_id];
+ atomic_dec(&curp->vcpus_active);
+ vcpup->flags &= ~HV_VCPU_UP;
+}
+
+static int
+hyperv_vcpu_save(struct domain *d, hvm_domain_context_t *h)
+{
+ struct vcpu *v;
+ struct hvm_hyperv_cpu ctxt;
+
+ hv_vcpu_t *vcpup;
+ hv_partition_t *curp = d->arch.hvm_domain.hyperv_handle;
+
+ if (curp == NULL)
+ return 0;
+
+ for_each_vcpu(d, v)
+ {
+ vcpup = &curp->vcpu_state[v->vcpu_id];
+
+ /*
+ * We don't need to save state for a
+ * vcpu that is down; the restore
+ * code will leave it down if there is nothing saved.
+ */
+ if ( test_bit(_VPF_down, &v->pause_flags) )
+ continue;
+ ctxt.control_msr = vcpup->control_msr;
+ ctxt.version_msr = vcpup->version_msr;
+ if (hvm_save_entry(HYPERV_CPU, v->vcpu_id, h, &ctxt) != 0 )
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+hyperv_vcpu_restore(struct domain *d, hvm_domain_context_t *h)
+{
+ int vcpuid;
+ struct hvm_hyperv_cpu ctxt;
+
+ hv_vcpu_t *vcpup;
+ hv_partition_t *curp = d->arch.hvm_domain.hyperv_handle;
+
+ if (curp == NULL)
+ return 0;
+ /* Which vcpu is this? */
+ vcpuid = hvm_load_instance(h);
+ vcpup = &curp->vcpu_state[vcpuid];
+ ASSERT(vcpup != NULL);
+ if ( hvm_load_entry(HYPERV_CPU, h, &ctxt) != 0 )
+ return -EINVAL;
+
+ vcpup->control_msr = ctxt.control_msr;
+ vcpup->version_msr = ctxt.version_msr;
+
+ vcpup->flags |= HV_VCPU_UP;
+ return 0;
+}
+
+static int
+hyperv_dom_save(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_hyperv_dom ctxt;
+ hv_partition_t *curp = d->arch.hvm_domain.hyperv_handle;
+
+ if (curp == NULL) {
+ return 0;
+ }
+
+ ctxt.guestid_msr = curp->guest_id_msr;
+ ctxt.hypercall_msr = curp->hypercall_msr;
+ ctxt.long_mode = curp->long_mode_guest;
+ ctxt.ext_id = d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR];
+ return (hvm_save_entry(HYPERV_DOM, 0, h, &ctxt));
+}
+
+static int
+hyperv_dom_restore(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_hyperv_dom ctxt;
+ hv_partition_t *curp;
+ void *hypercall_page;
+
+ if ( hvm_load_entry(HYPERV_DOM, h, &ctxt) != 0 )
+ return -EINVAL;
+ d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR] = 1;
+ if (hyperv_initialize(d))
+ return -EINVAL;
+ curp = d->arch.hvm_domain.hyperv_handle;
+
+ curp->guest_id_msr = ctxt.guestid_msr;
+ curp->hypercall_msr = ctxt.hypercall_msr;
+ /*
+ * We may have migrated from a sles10 host; re-initialize the
+ * hypercall page.
+ */
+ hypercall_page = get_virt_from_gmfn(d, (curp->hypercall_msr >>12));
+ if (hypercall_page == NULL)
+ return -EINVAL;
+ hv_hypercall_page_initialize(hypercall_page);
+ unmap_domain_page(hypercall_page);
+ curp->long_mode_guest = ctxt.long_mode;
+ return 0;
+}
+
+HVM_REGISTER_SAVE_RESTORE(HYPERV_DOM, hyperv_dom_save, hyperv_dom_restore,
+ 1, HVMSR_PER_DOM);
+
+
+HVM_REGISTER_SAVE_RESTORE(HYPERV_CPU,hyperv_vcpu_save,hyperv_vcpu_restore,
+ 1, HVMSR_PER_VCPU);
+
+
+static int
+hv_preprocess_cpuid_leaves(unsigned int input, unsigned int *eax,
+ unsigned int *ebx, unsigned int *ecx,
+ unsigned int *edx )
+{
+ struct domain *d = current->domain;
+ int extid = d->arch.hvm_domain.params[HVM_PARAM_EXTEND_HYPERVISOR];
- bnc#564406 - Make the new PV drivers work with older hosts that do not understand the new PV driver protocol. - Upstream Xen version renamed to 4.0.0 in changeset 20624 & 20625. - fate#307594: HP-MCBS: XEN: support NR_CPUS=256 This is a spec file change (xen.spec) - bnc#555152 - "NAME" column in xentop (SLES11) output limited to 10 characters unlike SLES10 The update to c/s 20572 includes this fix (at c/s 20567). - Modify xen-paths.diff - Merge xend-tap-fix.patch to xen-domUloader.diff remove part of it which accepted by upstream - Load gntdev module in xend init script similar to blkbk, netbk, etc. - Backport dmmd from sles11/xen block-dmmd xen-qemu-iscsi-fix.patch xen.spec - Fix regression when create_vbd for tap xend-tap-fix.patch - Temporarily disable libxl because of libconfig dependency. - fate#302864 domUloader support lvm in disk domUloader.py Note: for test in Beta1, if not good, remove it - fate#302864 domUloader support fs on whole disk domUloader.py - Turn KMPs back on now that kernel side fix is checked in. - fate#304415 VMM: ability to switch networking mode Add vif-route-ifup to handle routed configurations using sysconfig scripts. vif-route-ifup.patch - fate#307540 USB for Xen VMs usb-add.patch - fate#305545 XEN extra descriptive field within xenstore add_des.patch - Update to Xen version 3.5.0 for the following features. fate#304226 XEN: FlexMigration feature of VT-x2 support fate#305004 Add SR-IOV PF and VF drivers to Vt-d enabled Xen fate#306830 T states in Xen controlling by MSR fate#306832 Fix for xen panic on new processors fate#306833 Westmere and Nehalem-EX: Add support for Pause Loop exiting feature for Xen fate#306835 Xen: server virtual power management enhacement fate#306837 VT-d2 - PCI SIG ATS support fate#306872 Xen: Node manager support P/T-states change when Vt-d enable fate#306873 Xen: SMP guest live migration may fail with hap=1 on NHM fate#306875 Westmere: LT-SX (Xen) fate#306891 RAS features for Xen: Add support for Machine Check and CPU/Memory online/offline features fate#307322 1GB page support in Xen fate#307324 Xen IOMMU support OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=26
2010-01-16 01:12:54 +01:00
+ unsigned int count = *ecx;
+
+ if (extid == 1) {
+ /*
+ * Enlightened Windows guest; need to remap and handle
+ * leaves used by PV front-end drivers.
+ */
+ if ((input >= 0x40000000) && (input <= 0x40000005))
+ return (0);
+ /*
+ * PV drivers use cpuid to query the hypervisor for details. On
+ * Windows we will use the following leaves for this:
+ *
+ * 4096: VMM Sinature (corresponds to 0x40000000 on Linux)
+ * 4097: VMM Version (corresponds to 0x40000001 on Linux)
+ * 4098: Hypercall details (corresponds to 0x40000002 on Linux)
+ */
+ if ((input >= 0x40001000) && (input <= 0x40001002))
+ {
+ /* Get rid of the offset and let xen handle it */
+ input -= 0x1000;
- bnc#564406 - Make the new PV drivers work with older hosts that do not understand the new PV driver protocol. - Upstream Xen version renamed to 4.0.0 in changeset 20624 & 20625. - fate#307594: HP-MCBS: XEN: support NR_CPUS=256 This is a spec file change (xen.spec) - bnc#555152 - "NAME" column in xentop (SLES11) output limited to 10 characters unlike SLES10 The update to c/s 20572 includes this fix (at c/s 20567). - Modify xen-paths.diff - Merge xend-tap-fix.patch to xen-domUloader.diff remove part of it which accepted by upstream - Load gntdev module in xend init script similar to blkbk, netbk, etc. - Backport dmmd from sles11/xen block-dmmd xen-qemu-iscsi-fix.patch xen.spec - Fix regression when create_vbd for tap xend-tap-fix.patch - Temporarily disable libxl because of libconfig dependency. - fate#302864 domUloader support lvm in disk domUloader.py Note: for test in Beta1, if not good, remove it - fate#302864 domUloader support fs on whole disk domUloader.py - Turn KMPs back on now that kernel side fix is checked in. - fate#304415 VMM: ability to switch networking mode Add vif-route-ifup to handle routed configurations using sysconfig scripts. vif-route-ifup.patch - fate#307540 USB for Xen VMs usb-add.patch - fate#305545 XEN extra descriptive field within xenstore add_des.patch - Update to Xen version 3.5.0 for the following features. fate#304226 XEN: FlexMigration feature of VT-x2 support fate#305004 Add SR-IOV PF and VF drivers to Vt-d enabled Xen fate#306830 T states in Xen controlling by MSR fate#306832 Fix for xen panic on new processors fate#306833 Westmere and Nehalem-EX: Add support for Pause Loop exiting feature for Xen fate#306835 Xen: server virtual power management enhacement fate#306837 VT-d2 - PCI SIG ATS support fate#306872 Xen: Node manager support P/T-states change when Vt-d enable fate#306873 Xen: SMP guest live migration may fail with hap=1 on NHM fate#306875 Westmere: LT-SX (Xen) fate#306891 RAS features for Xen: Add support for Machine Check and CPU/Memory online/offline features fate#307322 1GB page support in Xen fate#307324 Xen IOMMU support OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=26
2010-01-16 01:12:54 +01:00
+ cpuid_hypervisor_leaves(input, count, eax, ebx, ecx, edx);
+ /* Setup hypercall MSR value - add the offset*/
+ if (input == 0x40000002)
+ *ebx |= 0x1000;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+int
+hyperv_do_cpu_id(unsigned int input, unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+ uint32_t idx;
+ hv_partition_t *curp = hv_get_current_partition();
+
+ /*
+ * hvmloader uses cpuid to set up a hypercall page; we don't want to
+ * intercept calls coming from the bootstrap (bios) code in the HVM
+ * guest; we discriminate based on if paging is enabled or not.
+ */
+ if (hv_call_from_bios())
+ /*
+ * We don't intercept this.
+ */
+ return (0);
+
+ if (input == 0x00000001)
+ {
+ *ecx |= 0x80000000;
+ return (1);
+ }
+
+ if (hv_preprocess_cpuid_leaves(input, eax, ebx, ecx, edx))
+ return (1);
+ idx = (input - 0x40000000);
+
+ switch (idx)
+ {
+ case 0:
+ /*
+ * 0x40000000: Hypervisor identification.
+ */
+ *eax = 0x40000005; /* For now clamp this */
+ *ebx = 0x65766f4e; /* "Nove" */
+ *ecx = 0x68536c6c; /* "llSh" */
+ *edx = 0x76486d69; /* "imHv" */
+ break;
+
+ case 1:
+ /*
+ * 0x40000001: Hypervisor identification.
+ */
+ *eax = 0x31237648; /* "Hv#1*/
+ *ebx = 0; /* Reserved */
+ *ecx = 0; /* Reserved */
+ *edx = 0; /* Reserved */
+ break;
+ case 2:
+ /*
+ * 0x40000002: Guest Info
+ */
+ if (hv_os_registered())
+ {
+ u64 guest_id = curp->guest_id_msr;
+ u32 guest_major, guest_minor;
+
+ guest_major = ((guest_id >> 32) & 0xff);
+ guest_minor = ((guest_id >> 24) & 0xff);
+ *eax = (guest_id & 0xffff); /* Build # 15:0 */
+ *ebx =
+ (guest_major << 16) | (guest_minor); /*Major: 31:16; Minor: 15:0*/
+ *ecx = ((guest_id >>16) & 0xff); /*Service Pack/Version: 23:16*/
+ /*
+ * Service branch (31:24)|Service number (23:0)
+ * Not sure what these numbers are: XXXKYS.
+ */
+ *edx = 0; /*Service branch (31:24)|Service number (23:0) */
+ } else
+ {
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ }
+ break;
+ case 3:
+ /*
+ * 0x40000003: Feature identification.
+ */
+ *eax = HV_SHIM_SUPPORTED_MSRS;
+ /* We only support AcessSelfPartitionId bit 1 */
+ *ebx = (HV_SHIM_PRIVILEGES>>32);
+ *ecx = 0; /* Reserved */
+ *edx = 0; /*No MWAIT (bit 0), No debugging (bit 1)*/
+ break;
+ case 4:
+ /*
+ * 0x40000004: Imlementation recommendations.
+ */
+ *eax = hv_get_recommendations();
+ *ebx = 2047;
+ *ebx = 0; /* Reserved */
+ *ecx = 0; /* Reserved */
+ *edx = 0; /* Reserved */
+ break;
+ case 5:
+ /*
+ * 0x40000005: Implementation limits.
+ * Currently we retrieve maximum number of vcpus and
+ * logical processors (hardware threads) supported.
+ */
+ *eax = hv_get_max_vcpus_supported();
+ *ebx = 0; /* Reserved */
+ *ecx = 0; /* Reserved */
+ *edx = 0; /* Reserved */
+ break;
+ case 6:
+ /*
+ * Implementation hardware features; for now set them all to zero.
+ */
+ *eax = 0;
+ *ebx = 0; /* Reserved */
+ *ecx = 0; /* Reserved */
+ *edx = 0; /* Reserved */
+ break;
+
+ default:
+ /*
+ * We don't handle this leaf.
+ */
+ return (0);
+
+ }
+ return (1);
+}
+
+int
+hyperv_do_rd_msr(uint32_t idx, struct cpu_user_regs *regs)
+{
+ hv_partition_t *curp = hv_get_current_partition();
+ unsigned int vcp_index = hv_get_current_vcpu_index();
+ u64 msr_content = 0;
+ hv_vcpu_t *cur_vcpu = &curp->vcpu_state[vcp_index];
+
+ /*
+ * hvmloader uses rdmsr; we don't want to
+ * intercept calls coming from the bootstrap (bios) code in the HVM
+ * guest; we descriminate based on the instruction pointer.
+ */
+ if (hv_call_from_bios())
+ /*
+ * We don't intercept this.
+ */
+ return (0);
+ switch (idx)
+ {
+ case HV_MSR_GUEST_OS_ID:
+ spin_lock(&curp->lock);
+ regs->eax = (u32)(curp->guest_id_msr & 0xFFFFFFFF);
+ regs->edx = (u32)(curp->guest_id_msr >> 32);
+ spin_unlock(&curp->lock);
+ break;
+ case HV_MSR_HYPERCALL:
+ spin_lock(&curp->lock);
+ regs->eax = (u32)(curp->hypercall_msr & 0xFFFFFFFF);
+ regs->edx = (u32)(curp->hypercall_msr >> 32);
+ spin_unlock(&curp->lock);
+ if ((((u32)curp->hypercall_msr) & (0x00000001)) != 0) {
+ cur_vcpu->flags |= HV_VCPU_UP;
+ }
+ break;
+ case HV_MSR_VP_INDEX:
+ regs->eax = (u32)(vcp_index);
+ regs->edx = (u32)(0x0);
+ break;
+ case HV_MSR_ICR:
+ if (!hv_privilege_check(curp, HV_ACCESS_APIC_MSRS)) {
+ goto msr_read_error;
+ }
+ hv_read_icr(&msr_content);
+#ifdef HV_STATS
+ cur_vcpu->stats.num_icr_reads++;
+#endif
+ regs->eax = (u32)(msr_content & 0xFFFFFFFF);
+ regs->edx = (u32)(msr_content >> 32);
+ break;
+ case HV_MSR_TPR:
+ if (!hv_privilege_check(curp, HV_ACCESS_APIC_MSRS)) {
+ goto msr_read_error;
+ }
+ hv_read_tpr(&msr_content);
+#ifdef HV_STATS
+ cur_vcpu->stats.num_tpr_reads++;
+#endif
+ regs->eax = (u32)(msr_content & 0xFFFFFFFF);
+ regs->edx = (u32)(msr_content >> 32);
+ break;
+ /*
+ * The following synthetic MSRs are implemented in the Novell Shim.
+ */
+ case HV_MSR_SCONTROL:
+ if (!hv_privilege_check(curp, HV_ACCESS_SYNC_MSRS)) {
+ goto msr_read_error;
+ }
+ regs->eax = (u32)(cur_vcpu->control_msr & 0xFFFFFFFF);
+ regs->edx = (u32)(cur_vcpu->control_msr >> 32);
+ break;
+ case HV_MSR_SVERSION:
+ if (!hv_privilege_check(curp, HV_ACCESS_SYNC_MSRS)) {
+ goto msr_read_error;
+ }
+ regs->eax = (u32)(cur_vcpu->version_msr & 0xFFFFFFFF);
+ regs->edx = (u32)(cur_vcpu->version_msr >> 32);
+ break;
+ case HV_MSR_TIME_REF_COUNT:
+ if (!hv_access_time_refcnt(curp, &msr_content)) {
+ goto msr_read_error;
+ }
+ regs->eax = (u32)(msr_content & 0xFFFFFFFF);
+ regs->edx = (u32)(msr_content >> 32);
+ break;
+ case HV_MSR_PVDRV_HCALL:
+ regs->eax = 0;
+ regs->edx = 0;
+ break;
+ case HV_MSR_SYSTEM_RESET:
+ regs->eax = 0;
+ regs->edx = 0;
+ break;
+ case HV_MSR_APIC_ASSIST_PAGE:
+ /*
+ * For now ignore this.
+ */
+ regs->eax = 0;
+ regs->edx = 0;
+ break;
+ default:
+ /*
+ * We did not handle the MSR address specified;
+ * let the caller figure out
+ * What to do.
+ */
+ return (0);
+ }
+ return (1);
+msr_read_error:
+ /*
+ * Have to inject #GP fault.
+ */
+ hvm_inject_exception(TRAP_gp_fault, 0, 0);
+ return (1);
+}
+
+int
+hyperv_do_wr_msr(uint32_t idx, struct cpu_user_regs *regs)
+{
+ hv_partition_t *curp = hv_get_current_partition();
+ unsigned int vcp_index = hv_get_current_vcpu_index();
+ u64 msr_content = 0;
+ hv_vcpu_t *cur_vcpu = &curp->vcpu_state[vcp_index];
+ struct domain *d = current->domain;
+
+ /*
+ * hvmloader uses wrmsr; we don't want to
+ * intercept calls coming from the bootstrap (bios) code in the HVM
+ * guest; we descriminate based on the instruction pointer.
+ */
+ if (hv_call_from_bios())
+ /*
+ * We don't intercept this.
+ */
+ return (0);
+ msr_content =
+ (u32)regs->eax | ((u64)regs->edx << 32);
+
+ switch (idx)
+ {
+ case HV_MSR_GUEST_OS_ID:
+ hv_write_guestid_msr(curp, cur_vcpu, msr_content);
+ break;
+ case HV_MSR_HYPERCALL:
+ hv_write_hypercall_msr(curp, cur_vcpu, msr_content);
+ break;
+
+ case HV_MSR_VP_INDEX:
+ goto msr_write_error;
+
+ case HV_MSR_EOI:
+ if (!hv_privilege_check(curp, HV_ACCESS_APIC_MSRS)) {
+ goto msr_write_error;
+ }
+ hv_write_eoi(msr_content);
+#ifdef HV_STATS
+ cur_vcpu->stats.num_eoi_writes++;
+#endif
+ break;
+ case HV_MSR_ICR:
+ if (!hv_privilege_check(curp, HV_ACCESS_APIC_MSRS)) {
+ goto msr_write_error;
+ }
+ hv_write_icr(msr_content);
+#ifdef HV_STATS
+ cur_vcpu->stats.num_icr_writes++;
+#endif
+ break;
+ case HV_MSR_TPR:
+ if (!hv_privilege_check(curp, HV_ACCESS_APIC_MSRS)) {
+ goto msr_write_error;
+ }
+ hv_write_tpr(msr_content);
+#ifdef HV_STATS
+ cur_vcpu->stats.num_tpr_writes++;
+#endif
+ break;
+
+ /*
+ * The following MSRs are synthetic MSRs supported in the Novell Shim.
+ */
+ case HV_MSR_SCONTROL:
+ if (!hv_privilege_check(curp, HV_ACCESS_SYNC_MSRS)) {
+ goto msr_write_error;
+ }
+ cur_vcpu->control_msr = msr_content;
+ break;
+ case HV_MSR_SVERSION:
+ if (!hv_privilege_check(curp, HV_ACCESS_SYNC_MSRS)) {
+ goto msr_write_error;
+ }
+ /*
+ * This is a read-only MSR; generate #GP
+ */
+ hvm_inject_exception(TRAP_gp_fault, 0, 0);
+ break;
+ case HV_MSR_TIME_REF_COUNT:
+ /*
+ * This is a read-only msr.
+ */
+ goto msr_write_error;
+ break;
+ case HV_MSR_PVDRV_HCALL:
+ /*
+ * Establish the hypercall page for PV drivers.
+ */
- bnc#564406 - Make the new PV drivers work with older hosts that do not understand the new PV driver protocol. - Upstream Xen version renamed to 4.0.0 in changeset 20624 & 20625. - fate#307594: HP-MCBS: XEN: support NR_CPUS=256 This is a spec file change (xen.spec) - bnc#555152 - "NAME" column in xentop (SLES11) output limited to 10 characters unlike SLES10 The update to c/s 20572 includes this fix (at c/s 20567). - Modify xen-paths.diff - Merge xend-tap-fix.patch to xen-domUloader.diff remove part of it which accepted by upstream - Load gntdev module in xend init script similar to blkbk, netbk, etc. - Backport dmmd from sles11/xen block-dmmd xen-qemu-iscsi-fix.patch xen.spec - Fix regression when create_vbd for tap xend-tap-fix.patch - Temporarily disable libxl because of libconfig dependency. - fate#302864 domUloader support lvm in disk domUloader.py Note: for test in Beta1, if not good, remove it - fate#302864 domUloader support fs on whole disk domUloader.py - Turn KMPs back on now that kernel side fix is checked in. - fate#304415 VMM: ability to switch networking mode Add vif-route-ifup to handle routed configurations using sysconfig scripts. vif-route-ifup.patch - fate#307540 USB for Xen VMs usb-add.patch - fate#305545 XEN extra descriptive field within xenstore add_des.patch - Update to Xen version 3.5.0 for the following features. fate#304226 XEN: FlexMigration feature of VT-x2 support fate#305004 Add SR-IOV PF and VF drivers to Vt-d enabled Xen fate#306830 T states in Xen controlling by MSR fate#306832 Fix for xen panic on new processors fate#306833 Westmere and Nehalem-EX: Add support for Pause Loop exiting feature for Xen fate#306835 Xen: server virtual power management enhacement fate#306837 VT-d2 - PCI SIG ATS support fate#306872 Xen: Node manager support P/T-states change when Vt-d enable fate#306873 Xen: SMP guest live migration may fail with hap=1 on NHM fate#306875 Westmere: LT-SX (Xen) fate#306891 RAS features for Xen: Add support for Machine Check and CPU/Memory online/offline features fate#307322 1GB page support in Xen fate#307324 Xen IOMMU support OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=26
2010-01-16 01:12:54 +01:00
+ wrmsr_hypervisor_regs(0x40000000, msr_content);
+ break;
+ case HV_MSR_SYSTEM_RESET:
+ /*
+ * Shutdown the domain/partition.
+ */
+ if (msr_content & 0x1) {
+ domain_shutdown(d, SHUTDOWN_reboot);
+ }
+ break;
+ case HV_MSR_APIC_ASSIST_PAGE:
+ /*
+ * For now ignore this.
+ */
+ break;
+
+ default:
+ /*
+ * We did not handle the MSR address;
+ * let the caller deal with this.
+ */
+ return (0);
+ }
+ return (1);
+msr_write_error:
+ /*
+ * Have to inject #GP fault.
+ */
+ hvm_inject_exception(TRAP_gp_fault, 0, 0);
+ return (1);
+}
--- /dev/null
+++ b/xen/arch/x86/hvm/hyperv/hv_shim.h
@@ -0,0 +1,286 @@
+/****************************************************************************
+ |
+ | Copyright (c) [2007, 2008] Novell, Inc.
+ | All Rights Reserved.
+ |
+ | This program is free software; you can redistribute it and/or
+ | modify it under the terms of version 2 of the GNU General Public License as
+ | published by the Free Software Foundation.
+ |
+ | This program is distributed in the hope that 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, contact Novell, Inc.
+ |
+ | To contact Novell about this file by physical or electronic mail,
+ | you may find current contact information at www.novell.com
+ |
+ |***************************************************************************
+*/
+
+/*
+ * Hyperv Shim Implementation.
+ *
+ * Engineering Contact: K. Y. Srinivasan
+ */
+
+#ifndef HV_SHIM_H
+#define HV_SHIM_H
+
+#include <xen/sched.h>
+#include <xen/types.h>
+#include <xen/timer.h>
+#include <asm/current.h>
+#include <asm/domain.h>
+#include <asm/shadow.h>
+#include <public/xen.h>
+#include <public/hvm/hvm_info_table.h>
+
+#include "hv_hypercall.h"
+
+/*
+ * Synthetic MSR addresses
+ */
+#define HV_MSR_GUEST_OS_ID 0x40000000
+#define HV_MSR_HYPERCALL 0x40000001
+#define HV_MSR_VP_INDEX 0x40000002
+#define HV_MSR_SYSTEM_RESET 0x40000003
+#define HV_MSR_TIME_REF_COUNT 0x40000020
+#define HV_MSR_EOI 0x40000070
+#define HV_MSR_ICR 0x40000071
+#define HV_MSR_TPR 0x40000072
+#define HV_MSR_APIC_ASSIST_PAGE 0x40000073
+
+#define HV_MSR_SCONTROL 0x40000080
+#define HV_MSR_SVERSION 0x40000081
+#define HV_MSR_SIEFP 0x40000082
+#define HV_MSR_SIMP 0x40000083
+#define HV_MSR_SEOM 0x40000084
+#define HV_MSR_SINT0 0x40000090
+#define HV_MSR_SINT1 0x40000091
+#define HV_MSR_SINT2 0x40000092
+#define HV_MSR_SINT3 0x40000093
+#define HV_MSR_SINT4 0x40000094
+#define HV_MSR_SINT5 0x40000095
+#define HV_MSR_SINT6 0x40000096
+#define HV_MSR_SINT7 0x40000097
+#define HV_MSR_SINT8 0x40000098
+#define HV_MSR_SINT9 0x40000099
+#define HV_MSR_SINT10 0x4000009A
+#define HV_MSR_SINT11 0x4000009B
+#define HV_MSR_SINT12 0x4000009C
+#define HV_MSR_SINT13 0x4000009D
+#define HV_MSR_SINT14 0x4000009E
+#define HV_MSR_SINT15 0x4000009F
+
+#define HV_MSR_TIMER0_CONFIG 0x400000B0
+#define HV_MSR_TIMER0_COUNT 0x400000B1
+#define HV_MSR_TIMER1_CONFIG 0x400000B2
+#define HV_MSR_TIMER1_COUNT 0x400000B3
+#define HV_MSR_TIMER2_CONFIG 0x400000B4
+#define HV_MSR_TIMER2_COUNT 0x400000B5
+#define HV_MSR_TIMER3_CONFIG 0x400000B6
+#define HV_MSR_TIMER3_COUNT 0x400000B7
+
+/*
+ * Domain privilege flags
+ */
+
+#define _ACCESS_VP_RUNTIME 0
+#define ACCESS_VP_RUNTIME (1L<<_ACCESS_VP_RUNTIME)
+#define _ACCESS_TIME_REF_COUNT 1
+#define ACCESS_TIME_REF_COUNT (1L<<_ACCESS_TIME_REF_COUNT)
+#define _ACCESS_SYNIC_MSRS 2
+#define ACCESS_SYNIC_MSRS (1L<<_ACCESS_TIME_REF_COUNT)
+#define _ACCESS_SYNTHETIC_TIMERS 3
+#define ACCESS_SYNTHETIC_TIMERS (1L<<_ACCESS_SYNTHETIC_TIMERS)
+#define _ACCESS_APIC_MSRS 4
+#define ACCESS_APIC_MSRS (1L<<_ACCESS_APIC_MSRS)
+#define _ACCESS_HYPERCALL_MSRS 5
+#define ACCESS_HYPERCALL_MSRS (1L<<_ACCESS_HYPERCALL_MSRS)
+#define _ACCESS_VP_INDEX 6
+#define ACCESS_VP_INDEX (1L<<_ACCESS_VP_INDEX)
+#define _ACCESS_SELF_PARTITION_ID 33
+#define ACCESS_SELF_PARTITION_ID (1L<<_ACCESS_SELF_PARTITION_ID)
+
+#define HV_SHIM_PRIVILEGES \
+ (ACCESS_TIME_REF_COUNT | ACCESS_APIC_MSRS | ACCESS_HYPERCALL_MSRS | \
+ ACCESS_VP_INDEX |ACCESS_SELF_PARTITION_ID)
+
+/*
+ * Guest recommendations
+ */
+#define _USE_CSWITCH_HCALL 0
+#define USE_CSWITCH_HCALL (1U<<_USE_CSWITCH_HCALL)
+#define _USE_TLBFLUSH_HCALL 1
+#define USE_TLBFLUSH_HCALL (1U<<_USE_TLBFLUSH_HCALL)
+#define _USE_REMOTE_TLBFLUSH_HCALL 2
+#define USE_REMOTE_TLBFLUSH_HCALL (1U<<_USE_REMOTE_TLBFLUSH_HCALL)
+#define _USE_APIC_MSRS 3
+#define USE_APIC_MSRS (1U<<_USE_APIC_MSRS)
+#define _USE_RESET_MSR 4
+#define USE_RESET_MSR (1U<<_USE_RESET_MSR)
+#define _USE_RELAXED_TIMING 5
+#define USE_RELAXED_TIMING (1U<<_USE_RELAXED_TIMING)
+
+/*
+ * Supported Synthetic MSRs. 0.83 HyperV spec, section 3.4
+ * Supported features.
+ */
+#define _MSR_VP_RUNTIME 0
+#define MSR_VP_RUNTIME (1U<<_MSR_VP_RUNTIME)
+#define _MSR_TIME_REF_CNT 1
+#define MSR_TIME_REF_CNT (1U<<_MSR_TIME_REF_CNT)
+#define _MSR_SYN_IC 2
+#define MSR_SYN_IC (1U<<_MSR_SYN_IC)
+#define _MSR_SYN_TIMER 3
+#define MSR_SYN_TIMER (1U<<_MSR_SYN_TIMER)
+#define _APIC_MSRS 4
+#define APIC_MSRS (1U<<_APIC_MSRS)
+#define _HYPERCALL_MSRS 5
+#define HYPERCALL_MSRS (1U<<_HYPERCALL_MSRS)
+#define _MSR_VP_INDEX 6
+#define MSR_VP_INDEX (1U<<_MSR_VP_INDEX)
+#define _RESET_MSR 7
+#define RESET_MSR (1U<<_RESET_MSR)
+
+#define HV_SHIM_SUPPORTED_MSRS \
+ (MSR_TIME_REF_CNT|APIC_MSRS|HYPERCALL_MSRS|MSR_VP_INDEX|RESET_MSR)
+
+/*
+ * MSR for supporting PV drivers on longhorn.
+ */
+#define HV_MSR_PVDRV_HCALL 0x40001000
+
+/*
+ * Tag for HyperV hcalls.
+ */
+#define HYPERV_HCALL 0x80000000
+
+/*
+ * Hyperv Shim VCPU flags.
+ */
+#define HV_VCPU_BOOT_CPU 0x00000001
+#define HV_VCPU_UP 0x00000002
+
+
+/*
+ * Stats structure.
+ */
+
+typedef struct {
+ u64 num_switches;
+ u64 num_long_spinwaits;
+ u64 num_tpr_reads;
+ u64 num_icr_reads;
+ u64 num_eoi_writes;
+ u64 num_tpr_writes;
+ u64 num_icr_writes;
+} hv_vcpu_stats_t;
+
+typedef struct hv_vcpu {
+ /*
+ * Per-vcpu state to support the hyperv shim;
+ */
+ unsigned long flags;
+ /*
+ * Synthetic msrs.
+ */
+ u64 control_msr;
+ u64 version_msr;
+ struct vcpu *xen_vcpu; /*corresponding xen vcpu*/
+ hv_vcpu_stats_t stats;
+} hv_vcpu_t;
+
+
+#define HV_STATS //KYS: Temporary
+
+typedef struct hv_partition {
+ /*
+ * State maintained on a per guest basis to implement
+ * the Hyperv shim.
+ */
+ s_time_t domain_boot_time;
+ spinlock_t lock;
+ atomic_t vcpus_active;
+ u64 guest_id_msr;
+ u64 hypercall_msr;
+ u64 privileges;
+ int long_mode_guest;
+ /*
+ * Each VCPU here corresponds to the vcpu in the underlying hypervisor;
+ * they share the same ID.
+ */
+ hv_vcpu_t vcpu_state[HVM_MAX_VCPUS];
+} hv_partition_t;
+
+
+/*
+ * Privilege flags.
+ */
+
+#define HV_ACCESS_VP_RUNTIME (1ULL << 0)
+#define HV_ACCESS_TIME_REF_CNT (1ULL << 1)
+#define HV_ACCESS_SYNC_MSRS (1ULL << 2)
+#define HV_ACCESS_SYNC_TIMERS (1ULL << 3)
+#define HV_ACCESS_APIC_MSRS (1ULL << 4)
+#define HV_ACCESS_PARTITION_ID (1ULL << 33)
+
+#define hv_get_current_partition() \
+((current)->domain->arch.hvm_domain.hyperv_handle)
+
+#define hv_get_current_vcpu_index() (current)->vcpu_id
+
+
+static inline int
+hv_invalid_cpu_state(void)
+{
+ int state;
+ state = hvm_funcs.guest_x86_mode(current);
+ if ((state == 4) || (state == 8))
+ {
+ return (0);
+ }
+ return (1);
+}
+
+static inline u64
+hv_build_hcall_retval(int code, int reps)
+{
+ u64 ret_val=0;
+ ret_val |= (code & 0xff);
+ ret_val |= (((long long)(reps & 0xfff)) << 32);
+ return (ret_val);
+}
+
+static inline void hv_set_syscall_retval(struct cpu_user_regs *pregs,
+ int long_mode, u64 ret_val)
+{
+ if (long_mode)
+ {
+ pregs->eax = ret_val;
+ }
+ else
+ {
+ pregs->edx = (u32)(ret_val >> 32);
+ pregs->eax = (u32)(ret_val);
+ }
+}
+
+static inline int
+hv_privilege_check(hv_partition_t *curp, u64 flags)
+{
+ return ((curp->privileges & flags)? 1: 0);
+}
+
+void
+hv_handle_hypercall(u64 opcode, u64 input, u64 output,
+ u64 *ret_val);
+
+
+void hv_print_stats(hv_partition_t *curp, int i);
+
+#endif /*HV_SHIM_H */