f196fa2c00
- bnc#573881 - /usr/lib64/xen/bin/qemu-dm is a broken link - Update to changeset 20840 RC1+ for sle11-sp1 beta3. - bnc#569581 - SuSEfirewall2 should handle rules. Disable handle_iptable in vif-bridge script vif-bridge-no-iptables.patch - bnc#569577 - /etc/modprove.d/xen_pvdrivers, installed by xen-kmp-default, to ../xen_pvdrivers.conf - bnc#536176 - Xen panic when using iommu after updating hypervisor 19380-vtd-feature-check.patch - bnc#530959 - virsh autostart doesn't work Fixing this libvirt bug also required fixing xend's op_pincpu method with upstream c/s 19580 19580-xend-pincpu.patch - bnc#534146 - Xen: Fix SRAT check for discontig memory 20120-x86-srat-check-discontig.patch - bnc#491081 - Xen time goes backwards x3950M2 - disable module build for ec2 correctly to fix build (at the suse_kernel_module_package macro) runs - Upstream bugfixes from Jan. 19896-32on64-arg-xlat.patch 19960-show-page-walk.patch 19945-pae-xen-l2-entries.patch 19953-x86-fsgs-base.patch 19931-gnttblop-preempt.patch 19885-kexec-gdt-switch.patch 19894-shadow-resync-fastpath-race.patch - hvperv shim patches no longer require being applied conditionally - bnc#520234 - npiv does not work with XEN in SLE11 Update block-npiv - bnc#496033 - Support for creating NPIV ports without starting vm block-npiv-common.sh block-npiv-vport Update block-npiv - bnc#500043 - Fix access to NPIV disk from HVM vm Update xen-qemu-iscsi-fix.patch - Don't build the KMPs for the ec2 kernel. - Upstream fixes from Jan Beulich 19606-hvm-x2apic-cpuid.patch 19734-vtd-gcmd-submit.patch 19752-vtd-srtp-sirtp-flush.patch 19753-vtd-reg-write-lock.patch 19764-hvm-domain-lock-leak.patch 19765-hvm-post-restore-vcpu-state.patch 19767-hvm-port80-inhibit.patch 19768-x86-dom0-stack-dump.patch 19770-x86-amd-s3-resume.patch 19801-x86-p2m-2mb-hap-only.patch 19815-vtd-kill-correct-timer.patch - Patch from Jan Beulich to aid in debugging bnc#509911 gnttblop-preempt.patch - bnc#515220 - qemu-img-xen snapshot Segmentation fault qemu-img-snapshot.patch update - Upstream fixes from Jan Beulich. 19474-32on64-S3.patch 19490-log-dirty.patch 19492-sched-timer-non-idle.patch 19493-hvm-io-intercept-count.patch 19505-x86_64-clear-cr1.patch 19519-domctl-deadlock.patch 19523-32on64-restore-p2m.patch 19555-ept-live-migration.patch 19557-amd-iommu-ioapic-remap.patch 19560-x86-flush-tlb-empty-mask.patch 19571-x86-numa-shift.patch 19578-hvm-load-ldt-first.patch 19592-vmx-exit-reason-perfc-size.patch 19595-hvm-set-callback-irq-level.patch 19597-x86-ioport-quirks-BL2xx.patch 19602-vtd-multi-ioapic-remap.patch 19631-x86-frametable-map.patch 19653-hvm-vcpuid-range-checks.patch - bnc#382112 - Caps lock not being passed to vm correctly. capslock_enable.patch - bnc#506833 - Use pidof in xend and xendomains init scripts - bnc#484778 - XEN: PXE boot of FV domU using non-Realtek NIC fails enable_more_nic_pxe.patch cross-migrate.patch - bnc#390961 - cross-migration of a VM causes it to become unresponsive (remains paused after migration) - Patches taken to fix the xenctx tool. The fixed version of this tool is needed to debug bnc#502735. 18962-xc_translate_foreign_address.patch 18963-xenctx.patch 19168-hvm-domctl.patch 19169-remove-declare-bitmap.patch 19170-libxc.patch 19171-xenctx.patch 19450-xc_translate_foreign_address.patch -bnc#503782 - Using converted vmdk image does not work ioemu-tapdisk-compat-QEMU_IMG.patch - bnc#474738 - adding CD drive to VM guest makes it unbootable. parse_boot_disk.patch - bnc#495300 - L3: Xen unable to PXE boot Windows based DomU's 18545-hvm-gpxe-rom.patch, 18548-hvm-gpxe-rom.patch - bnc#459836 - Fix rtc_timeoffset when localtime=0 xend-timeoffset.patch - bnc#497440 - xmclone.sh script incorrectly handles networking for SLE11. - bnc#477890 - VM becomes unresponsive after applying snapshot - bnc#494892 - Update xend-domain-lock.patch to flock the lock file. - bnc#439639 - SVVP Test 273 System - Sleep Stress With IO" fails Turned off s3/s4 sleep states for HVM guests. - bnc#468169 - fix domUloader to umount the mounted device mapper target in dom0 when install a sles10 guest with disk = /dev/disk/by_path - bnc#488490 - domUloader can't handle block device names with ':' - bnc#486244 - vms fail to start after reboot when using qcow2 - bnc#490835 - VTd errata on Cantiga chipset 19230-vtd-mobile-series4-chipset.patch - bnc#482515 - Missing dependency in xen.spec - Additional upstream bug fix patches from Jan Beulich. 19132-page-list-mfn-links.patch 19134-fold-shadow-page-info.patch 19135-next-shadow-mfn.patch 19136-page-info-rearrange.patch 19156-page-list-simplify.patch 19161-pv-ldt-handling.patch 19162-page-info-no-cpumask.patch 19216-msix-fixmap.patch 19268-page-get-owner.patch 19293-vcpu-migration-delay.patch 19391-vpmu-double-free.patch 19415-vtd-dom0-s3.patch - Imported numerous upstream bug fix patches. 19083-memory-is-conventional-fix.patch 19097-M2P-table-1G-page-mappings.patch 19137-lock-domain-page-list.patch 19140-init-heap-pages-max-order.patch 19167-recover-pat-value-s3-resume.patch 19172-irq-to-vector.patch 19173-pci-passthrough-fix.patch 19176-free-irq-shutdown-fix.patch 19190-pciif-typo-fix.patch 19204-allow-old-images-restore.patch 19232-xend-exception-fix.patch 19239-ioapic-s3-suspend-fix.patch 19240-ioapic-s3-suspend-fix.patch 19242-xenstored-use-after-free-fix.patch 19259-ignore-shutdown-deferrals.patch 19266-19365-event-channel-access-fix.patch 19275-19296-schedular-deadlock-fixes.patch 19276-cpu-selection-allocation-fix.patch 19302-passthrough-pt-irq-time-out.patch 19313-hvmemul-read-msr-fix.patch 19317-vram-tracking-fix.patch 19335-apic-s3-resume-error-fix.patch 19353-amd-migration-fix.patch 19354-amd-migration-fix.patch 19371-in-sync-L1s-writable.patch 19372-2-on-3-shadow-mode-fix.patch 19377-xend-vnclisten.patch 19400-ensure-ltr-execute.patch 19410-virt-to-maddr-fix.patch - bnc#483565 - Fix block-iscsi script. Updated block-iscsi and xen-domUloader.diff - bnc#465814 - Mouse stops responding when wheel is used in Windows VM. mouse-wheel-roll.patch (James Song) - bnc#470704 - save/restore of windows VM throws off the mouse tracking. usb-save-restore.patch (James Song) - bnc#436629 - Use global vnc-listen setting specified in xend configuration file. xend-vnclisten.patch - bnc#482623 - Fix pygrub to append user-supplied 'extra' args to kernel args. 19234_pygrub.patch - bnc#481161 upgrade - sles10sp2 to sles11 upgrade keeps xen-tools-ioemu OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=28
1763 lines
48 KiB
Diff
1763 lines
48 KiB
Diff
--- /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
|
|
@@ -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];
|
|
+ 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;
|
|
+ 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.
|
|
+ */
|
|
+ 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 */
|