xen/hv_xen_extension.patch
Charles Arnold f196fa2c00 - bnc#573376 - OS reboot while create DomU with Windows CD
- 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
2010-01-29 20:39:04 +00:00

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 */