The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/hyperv/vmbus/x86/hyperv_x86.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    2  * Copyright (c) 2009-2012,2016-2017, 2022 Microsoft Corp.
    3  * Copyright (c) 2012 NetApp Inc.
    4  * Copyright (c) 2012 Citrix Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice unmodified, this list of conditions, and the following
   12  *    disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 /**
   30  * Implements low-level interactions with Hyper-V/Azure
   31  */
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 #include <sys/timetc.h>
   40 
   41 #include <vm/vm.h>
   42 #include <vm/pmap.h>
   43 #include <vm/vm_extern.h>
   44 #include <vm/vm_kern.h>
   45 
   46 #include <dev/hyperv/include/hyperv.h>
   47 #include <dev/hyperv/include/hyperv_busdma.h>
   48 #include <dev/hyperv/vmbus/hyperv_var.h>
   49 #include <dev/hyperv/vmbus/x86/hyperv_machdep.h>
   50 #include <dev/hyperv/vmbus/x86/hyperv_reg.h>
   51 #include <dev/hyperv/vmbus/hyperv_common_reg.h>
   52 
   53 #define HYPERV_FREEBSD_BUILD 0ULL
   54 #define HYPERV_FREEBSD_VERSION ((uint64_t)__FreeBSD_version)
   55 #define HYPERV_FREEBSD_OSID 0ULL
   56 
   57 void hyperv_init_tc(void);
   58 int hypercall_page_setup(vm_paddr_t);
   59 void hypercall_disable(void);
   60 bool hyperv_identify_features(void);
   61 
   62 u_int hyperv_ver_major;
   63 u_int hyperv_features;
   64 u_int hyperv_recommends;
   65 
   66 hyperv_tc64_t hyperv_tc64;
   67 
   68 static u_int hyperv_pm_features;
   69 static u_int hyperv_features3;
   70 static u_int hyperv_get_timecount(struct timecounter *);
   71 
   72 static struct timecounter hyperv_timecounter = {
   73         .tc_get_timecount = hyperv_get_timecount,
   74         .tc_poll_pps = NULL,
   75         .tc_counter_mask = 0xffffffff,
   76         .tc_frequency = HYPERV_TIMER_FREQ,
   77         .tc_name = "Hyper-V",
   78         .tc_quality = 2000,
   79         .tc_flags = 0,
   80         .tc_priv = NULL
   81 };
   82 
   83 static u_int
   84 hyperv_get_timecount(struct timecounter *tc __unused)
   85 {
   86         return rdmsr(MSR_HV_TIME_REF_COUNT);
   87 }
   88 
   89 static uint64_t
   90 hyperv_tc64_rdmsr(void)
   91 {
   92 
   93         return (rdmsr(MSR_HV_TIME_REF_COUNT));
   94 }
   95 
   96 void
   97 hyperv_init_tc(void)
   98 {
   99         if (hyperv_features & CPUID_HV_MSR_TIME_REFCNT) {
  100                 /*
  101                  * Register Hyper-V timecounter.  This should be done as early
  102                  * as possible to let DELAY() work, since the 8254 PIT is not
  103                  * reliably emulated or even available.
  104                  */
  105                 tc_init(&hyperv_timecounter);
  106 
  107                 /*
  108                  * Install 64 bits timecounter method for other modules
  109                  * to use.
  110                  */
  111                 hyperv_tc64 = hyperv_tc64_rdmsr;
  112         }
  113 }
  114 
  115 int
  116 hypercall_page_setup(vm_paddr_t paddr)
  117 {
  118         uint64_t hc, hc_orig;
  119         hc_orig = rdmsr(MSR_HV_HYPERCALL);
  120 
  121         /*
  122          * Setup the Hypercall page.
  123          *
  124          * NOTE: 'reserved' bits MUST be preserved.
  125          */
  126         hc = ((paddr >> PAGE_SHIFT) << MSR_HV_HYPERCALL_PGSHIFT) |
  127             (hc_orig & MSR_HV_HYPERCALL_RSVD_MASK) | MSR_HV_HYPERCALL_ENABLE;
  128         wrmsr(MSR_HV_HYPERCALL, hc);
  129 
  130         /*
  131          * Confirm that Hypercall page did get setup.
  132          */
  133         hc = rdmsr(MSR_HV_HYPERCALL);
  134         if ((hc & MSR_HV_HYPERCALL_ENABLE) == 0) {
  135                 printf("hyperv: Hypercall setup failed\n");
  136                 /* Can't perform any Hyper-V specific actions */
  137                 vm_guest = VM_GUEST_VM;
  138                 return (-1);
  139         }
  140         return (0);
  141 }
  142 
  143 void
  144 hypercall_disable(void)
  145 {
  146         uint64_t hc;
  147         /* Disable Hypercall */
  148         hc = rdmsr(MSR_HV_HYPERCALL);
  149         wrmsr(MSR_HV_HYPERCALL, (hc & MSR_HV_HYPERCALL_RSVD_MASK));
  150 }
  151 
  152 bool
  153 hyperv_identify_features(void)
  154 {
  155         u_int regs[4];
  156         unsigned int maxleaf;
  157 
  158         if (vm_guest != VM_GUEST_HV)
  159                 return (false);
  160 
  161         do_cpuid(CPUID_LEAF_HV_MAXLEAF, regs);
  162         maxleaf = regs[0];
  163         if (maxleaf < CPUID_LEAF_HV_LIMITS)
  164                 return (false);
  165 
  166         do_cpuid(CPUID_LEAF_HV_INTERFACE, regs);
  167         if (regs[0] != CPUID_HV_IFACE_HYPERV)
  168                 return (false);
  169 
  170         do_cpuid(CPUID_LEAF_HV_FEATURES, regs);
  171         if ((regs[0] & CPUID_HV_MSR_HYPERCALL) == 0) {
  172                 /*
  173                  * Hyper-V w/o Hypercall is impossible; someone
  174                  * is faking Hyper-V.
  175                  */
  176                 return (false);
  177         }
  178         hyperv_features = regs[0];
  179         hyperv_pm_features = regs[2];
  180         hyperv_features3 = regs[3];
  181         do_cpuid(CPUID_LEAF_HV_IDENTITY, regs);
  182         hyperv_ver_major = regs[1] >> 16;
  183         printf("Hyper-V Version: %d.%d.%d [SP%d]\n", hyperv_ver_major,
  184             regs[1] & 0xffff, regs[0], regs[2]);
  185 
  186         printf("  Features=0x%b\n", hyperv_features,
  187             "\020"
  188             "\001VPRUNTIME" /* MSR_HV_VP_RUNTIME */
  189             "\002TMREFCNT"  /* MSR_HV_TIME_REF_COUNT */
  190             "\003SYNIC"     /* MSRs for SynIC */
  191             "\004SYNTM"     /* MSRs for SynTimer */
  192             "\005APIC"      /* MSR_HV_{EOI,ICR,TPR} */
  193             "\006HYPERCALL" /* MSR_HV_{GUEST_OS_ID,HYPERCALL} */
  194             "\007VPINDEX"   /* MSR_HV_VP_INDEX */
  195             "\010RESET"     /* MSR_HV_RESET */
  196             "\011STATS"     /* MSR_HV_STATS_ */
  197             "\012REFTSC"    /* MSR_HV_REFERENCE_TSC */
  198             "\013IDLE"      /* MSR_HV_GUEST_IDLE */
  199             "\014TMFREQ"    /* MSR_HV_{TSC,APIC}_FREQUENCY */
  200             "\015DEBUG");   /* MSR_HV_SYNTH_DEBUG_ */
  201         printf("  PM Features=0x%b [C%u]\n",
  202             (hyperv_pm_features & ~CPUPM_HV_CSTATE_MASK),
  203             "\020"
  204             "\005C3HPET", /* HPET is required for C3 state */
  205             CPUPM_HV_CSTATE(hyperv_pm_features));
  206         printf("  Features3=0x%b\n", hyperv_features3,
  207             "\020"
  208             "\001MWAIT"    /* MWAIT */
  209             "\002DEBUG"    /* guest debug support */
  210             "\003PERFMON"  /* performance monitor */
  211             "\004PCPUDPE"  /* physical CPU dynamic partition event */
  212             "\005XMMHC"    /* hypercall input through XMM regs */
  213             "\006IDLE"     /* guest idle support */
  214             "\007SLEEP"    /* hypervisor sleep support */
  215             "\010NUMA"     /* NUMA distance query support */
  216             "\011TMFREQ"   /* timer frequency query (TSC, LAPIC) */
  217             "\012SYNCMC"   /* inject synthetic machine checks */
  218             "\013CRASH"    /* MSRs for guest crash */
  219             "\014DEBUGMSR" /* MSRs for guest debug */
  220             "\015NPIEP"    /* NPIEP */
  221             "\016HVDIS");  /* disabling hypervisor */
  222 
  223         do_cpuid(CPUID_LEAF_HV_RECOMMENDS, regs);
  224         hyperv_recommends = regs[0];
  225         if (bootverbose)
  226                 printf("  Recommends: %08x %08x\n", regs[0], regs[1]);
  227 
  228         do_cpuid(CPUID_LEAF_HV_LIMITS, regs);
  229         if (bootverbose) {
  230                 printf("  Limits: Vcpu:%d Lcpu:%d Int:%d\n", regs[0], regs[1],
  231                     regs[2]);
  232         }
  233 
  234         if (maxleaf >= CPUID_LEAF_HV_HWFEATURES) {
  235                 do_cpuid(CPUID_LEAF_HV_HWFEATURES, regs);
  236                 if (bootverbose) {
  237                         printf("  HW Features: %08x, AMD: %08x\n", regs[0],
  238                             regs[3]);
  239                 }
  240         }
  241         return (true);
  242 }

Cache object: 35aefd45ea9a4701d0b35a778766df87


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.