hv.c revision eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4f
13e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*
23e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
33e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * Copyright (c) 2009, Microsoft Corporation.
43e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
53e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * This program is free software; you can redistribute it and/or modify it
63e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * under the terms and conditions of the GNU General Public License,
73e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * version 2, as published by the Free Software Foundation.
83e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
93e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * This program is distributed in the hope it will be useful, but WITHOUT
103e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
113e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
123e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * more details.
133e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
143e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * You should have received a copy of the GNU General Public License along with
153e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
163e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * Place - Suite 330, Boston, MA 02111-1307 USA.
173e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
183e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * Authors:
193e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *   Haiyang Zhang <haiyangz@microsoft.com>
203e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *   Hank Janssen  <hjanssen@microsoft.com>
213e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
223e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen */
233e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
24a0086dc512ba6c2161dcf48195daf177ad0c3615Greg Kroah-Hartman#include <linux/kernel.h>
25a0086dc512ba6c2161dcf48195daf177ad0c3615Greg Kroah-Hartman#include <linux/mm.h>
26b7c947f04888b8bb2dc79832c10ede73c5b8dae2Bill Pemberton#include <linux/vmalloc.h>
274983b39a0687b00688478e6748b979a02934b234Greg Kroah-Hartman#include "osd.h"
2809d50ff8a233a39e8697e776b06cf5be2de48bb1Greg Kroah-Hartman#include "include/logging.h"
293e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen#include "VmbusPrivate.h"
303e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
31454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton/* Globals */
323e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
33454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton/* The one and only */
34af248e1f1283792e95fd9842fe343f9260300c9dGreg Kroah-Hartmanstruct hv_context gHvContext = {
35af248e1f1283792e95fd9842fe343f9260300c9dGreg Kroah-Hartman	.SynICInitialized	= false,
36af248e1f1283792e95fd9842fe343f9260300c9dGreg Kroah-Hartman	.HypercallPage		= NULL,
37af248e1f1283792e95fd9842fe343f9260300c9dGreg Kroah-Hartman	.SignalEventParam	= NULL,
38af248e1f1283792e95fd9842fe343f9260300c9dGreg Kroah-Hartman	.SignalEventBuffer	= NULL,
393e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen};
403e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
413e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
423e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*++
433e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
443e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenName:
453e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HvQueryHypervisorPresence()
463e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
473e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenDescription:
483e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Query the cpuid for presense of windows hypervisor
493e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
503e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen--*/
513e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssenstatic int
523e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenHvQueryHypervisorPresence (
533e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    void
543e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    )
553e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
563e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int eax;
573e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int ebx;
583e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int ecx;
593e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int edx;
603e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int op;
613e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
623e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    eax = 0;
633e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    ebx = 0;
643e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    ecx = 0;
653e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    edx = 0;
663e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    op = HvCpuIdFunctionVersionAndFeatures;
67f931a70c370cc826191a51a79500b34cd592b25bGreg Kroah-Hartman    cpuid(op, &eax, &ebx, &ecx, &edx);
683e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
693e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	return (ecx & HV_PRESENT_BIT);
703e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
713e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
723e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
733e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*++
743e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
753e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenName:
763e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HvQueryHypervisorInfo()
773e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
783e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenDescription:
793e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Get version info of the windows hypervisor
803e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
813e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen--*/
823e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssenstatic int
833e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenHvQueryHypervisorInfo (
843e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    void
853e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    )
863e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
873e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int eax;
883e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int ebx;
893e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int ecx;
903e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int edx;
913e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int maxLeaf;
923e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    unsigned int op;
933e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
94454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton    /*
95454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton     * Its assumed that this is called after confirming that Viridian
96454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton     * is present. Query id and revision.
97454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton     */
98454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton
993e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1003e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    eax = 0;
1013e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    ebx = 0;
1023e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    ecx = 0;
1033e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    edx = 0;
1043e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    op = HvCpuIdFunctionHvVendorAndMaxFunction;
105f931a70c370cc826191a51a79500b34cd592b25bGreg Kroah-Hartman    cpuid(op, &eax, &ebx, &ecx, &edx);
1063e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1073e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
108454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   (ebx & 0xFF),
109454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((ebx >> 8) & 0xFF),
110454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((ebx >> 16) & 0xFF),
111454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((ebx >> 24) & 0xFF),
112454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   (ecx & 0xFF),
113454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((ecx >> 8) & 0xFF),
114454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((ecx >> 16) & 0xFF),
115454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((ecx >> 24) & 0xFF),
116454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   (edx & 0xFF),
117454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((edx >> 8) & 0xFF),
118454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((edx >> 16) & 0xFF),
119454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((edx >> 24) & 0xFF));
1203e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1213e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    maxLeaf = eax;
1223e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    eax = 0;
1233e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    ebx = 0;
1243e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    ecx = 0;
1253e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    edx = 0;
1263e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    op = HvCpuIdFunctionHvInterface;
127f931a70c370cc826191a51a79500b34cd592b25bGreg Kroah-Hartman    cpuid(op, &eax, &ebx, &ecx, &edx);
1283e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1293e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
130454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   (eax & 0xFF),
131454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((eax >> 8) & 0xFF),
132454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((eax >> 16) & 0xFF),
133454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	   ((eax >> 24) & 0xFF));
1343e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1353e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	 if (maxLeaf >= HvCpuIdFunctionMsHvVersion) {
136454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	eax = 0;
137454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	ebx = 0;
138454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	ecx = 0;
139454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	edx = 0;
140454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	op = HvCpuIdFunctionMsHvVersion;
141f931a70c370cc826191a51a79500b34cd592b25bGreg Kroah-Hartman	cpuid(op, &eax, &ebx, &ecx, &edx);
142454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",
143454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	       eax,
144454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	       ebx >> 16,
145454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	       ebx & 0xFFFF,
146454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	       ecx,
147454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	       edx >> 24,
148454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	       edx & 0xFFFFFF);
1493e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    }
1503e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    return maxLeaf;
1513e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
1523e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1533e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1543e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*++
1553e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1563e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenName:
1573e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HvDoHypercall()
1583e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1593e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenDescription:
1603e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Invoke the specified hypercall
1613e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1623e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen--*/
16359471438ccbebafb0d63baf8b818d0ca692f882aGreg Kroah-Hartmanstatic u64
1643e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenHvDoHypercall (
16559471438ccbebafb0d63baf8b818d0ca692f882aGreg Kroah-Hartman    u64  Control,
1663e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    void*   Input,
1673e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    void*   Output
1683e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    )
1693e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
170530cf2070be30831a371b6c7181d15e5976b6fc7Greg Kroah-Hartman#ifdef CONFIG_X86_64
17159471438ccbebafb0d63baf8b818d0ca692f882aGreg Kroah-Hartman    u64 hvStatus=0;
172fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman	u64 inputAddress = (Input)? virt_to_phys(Input) : 0;
173fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman	u64 outputAddress = (Output)? virt_to_phys(Output) : 0;
1743e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    volatile void* hypercallPage = gHvContext.HypercallPage;
1753e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1763e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>",
1773e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		Control,
1783e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		inputAddress,
1793e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		Input,
1803e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		outputAddress,
1813e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		Output,
1823e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		hypercallPage);
1833e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1843e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	__asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress):  "r8");
1853e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	__asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage));
1863e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1873e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    DPRINT_DBG(VMBUS, "Hypercall <return %llx>",  hvStatus);
1883e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1893e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    return hvStatus;
1903e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1913e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen#else
1923e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1934d64311468a90d4ab1e83c62d63b27da598b73eaGreg Kroah-Hartman    u32 controlHi = Control >> 32;
1944d64311468a90d4ab1e83c62d63b27da598b73eaGreg Kroah-Hartman    u32 controlLo = Control & 0xFFFFFFFF;
1954d64311468a90d4ab1e83c62d63b27da598b73eaGreg Kroah-Hartman    u32 hvStatusHi = 1;
1964d64311468a90d4ab1e83c62d63b27da598b73eaGreg Kroah-Hartman    u32 hvStatusLo = 1;
197fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman    u64 inputAddress = (Input) ? virt_to_phys(Input) : 0;
1984d64311468a90d4ab1e83c62d63b27da598b73eaGreg Kroah-Hartman    u32 inputAddressHi = inputAddress >> 32;
1994d64311468a90d4ab1e83c62d63b27da598b73eaGreg Kroah-Hartman    u32 inputAddressLo = inputAddress & 0xFFFFFFFF;
200fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman	u64 outputAddress = (Output) ? virt_to_phys(Output) : 0;
2014d64311468a90d4ab1e83c62d63b27da598b73eaGreg Kroah-Hartman    u32 outputAddressHi = outputAddress >> 32;
2024d64311468a90d4ab1e83c62d63b27da598b73eaGreg Kroah-Hartman    u32 outputAddressLo = outputAddress & 0xFFFFFFFF;
2033e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    volatile void* hypercallPage = gHvContext.HypercallPage;
2043e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2053e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
2063e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		Control,
2073e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		Input,
2083e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		Output);
2093e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2103e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	__asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage));
2113e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2123e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
21359471438ccbebafb0d63baf8b818d0ca692f882aGreg Kroah-Hartman    DPRINT_DBG(VMBUS, "Hypercall <return %llx>",  hvStatusLo | ((u64)hvStatusHi << 32));
2143e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
21559471438ccbebafb0d63baf8b818d0ca692f882aGreg Kroah-Hartman    return (hvStatusLo | ((u64)hvStatusHi << 32));
216454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton#endif /* x86_64 */
2173e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
2183e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2193e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*++
2203e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2213e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenName:
2223e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HvInit()
2233e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2243e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenDescription:
2253e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Main initialization routine. This routine must be called
2263e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	before any other routines in here are called
2273e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2283e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen--*/
22998d9fac4f0dec8545ed94abe729a15865cff6686Greg Kroah-Hartmanint HvInit (void)
2303e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
2313e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	int ret=0;
2323e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    int maxLeaf;
233f80b3d51a6708b5f14a59c53b1343db59efdda1eGreg Kroah-Hartman	union hv_x64_msr_hypercall_contents hypercallMsr;
234949cadaa054588db0c4a3a0cfc3ac93f08fda913Greg Kroah-Hartman	void *virtAddr = NULL;
2353e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2363e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_ENTER(VMBUS);
2373e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
23844f357f835d8a8223b922984eea01aaea29a5f0fBill Pemberton	memset(gHvContext.synICEventPage, 0, sizeof(void *) * MAX_NUM_CPUS);
23944f357f835d8a8223b922984eea01aaea29a5f0fBill Pemberton	memset(gHvContext.synICMessagePage, 0, sizeof(void *) * MAX_NUM_CPUS);
2403e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2413e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (!HvQueryHypervisorPresence())
2423e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
2433e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
2443e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		goto Cleanup;
2453e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
2463e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2473e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info...");
2483e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2493e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    maxLeaf = HvQueryHypervisorInfo();
250454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton    /* HvQueryHypervisorFeatures(maxLeaf); */
2513e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
252454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Determine if we are running on xenlinux (ie x2v shim) or native linux */
253a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	rdmsrl(HV_X64_MSR_GUEST_OS_ID, gHvContext.GuestId);
2543e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (gHvContext.GuestId == 0)
2553e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
256454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Write our OS info */
257a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
2583e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2593e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		gHvContext.GuestId = HV_LINUX_GUEST_ID;
2603e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
2613e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
262454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* See if the hypercall page is already set */
263a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
2643e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
2653e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
266454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Allocate the hypercall page memory */
267bfc30aae73b6be57528059a9e03ce8674320e67bGreg Kroah-Hartman		/* virtAddr = osd_PageAlloc(1); */
268bfc30aae73b6be57528059a9e03ce8674320e67bGreg Kroah-Hartman		virtAddr = osd_VirtualAllocExec(PAGE_SIZE);
2693e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2703e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		if (!virtAddr)
2713e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
2723e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!");
2733e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			goto Cleanup;
2743e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
2753e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2763e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		hypercallMsr.Enable = 1;
277fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman		/* hypercallMsr.GuestPhysicalAddress = virt_to_phys(virtAddr) >> PAGE_SHIFT; */
278fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman		hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr);
279a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
2803e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
281454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Confirm that hypercall page did get setup. */
2823e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		hypercallMsr.AsUINT64 = 0;
283a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
2843e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		if (!hypercallMsr.Enable)
2853e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
2863e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
2873e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			goto Cleanup;
2883e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
2893e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2903e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		gHvContext.HypercallPage = virtAddr;
2913e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
2923e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	else
2933e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
2943e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId);
2953e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		goto Cleanup;
2963e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
2973e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2982701f686d7083d516c2f937031515b032d71f563Greg Kroah-Hartman	DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx",
2992701f686d7083d516c2f937031515b032d71f563Greg Kroah-Hartman		    gHvContext.HypercallPage,
3002701f686d7083d516c2f937031515b032d71f563Greg Kroah-Hartman		    (u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
3013e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
302454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Setup the global signal event param for the signal event hypercall */
303af248e1f1283792e95fd9842fe343f9260300c9dGreg Kroah-Hartman	gHvContext.SignalEventBuffer = kmalloc(sizeof(struct hv_input_signal_event_buffer), GFP_KERNEL);
3043e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (!gHvContext.SignalEventBuffer)
3053e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
3063e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		goto Cleanup;
3073e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
3083e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
309cba4decdd3dcd224b17631572456951aace0a27eGreg Kroah-Hartman	gHvContext.SignalEventParam = (struct hv_input_signal_event *)(ALIGN_UP((unsigned long)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN));
3104d64311468a90d4ab1e83c62d63b27da598b73eaGreg Kroah-Hartman	gHvContext.SignalEventParam->ConnectionId.Asu32 = 0;
3113e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID;
3123e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	gHvContext.SignalEventParam->FlagNumber = 0;
3133e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	gHvContext.SignalEventParam->RsvdZ = 0;
3143e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
315454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton    /* DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); */
3163e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3173e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_EXIT(VMBUS);
3183e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3193e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen    return ret;
3203e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3213e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenCleanup:
3223e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (virtAddr)
3233e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
3243e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		if (hypercallMsr.Enable)
3253e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
3263e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			hypercallMsr.AsUINT64 = 0;
327a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman			wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
3283e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
3293e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
330b7c947f04888b8bb2dc79832c10ede73c5b8dae2Bill Pemberton		vfree(virtAddr);
3313e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
3323e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	ret = -1;
3333e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_EXIT(VMBUS);
3343e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3353e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	return ret;
3363e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
3373e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3383e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3393e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*++
3403e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3413e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenName:
3423e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HvCleanup()
3433e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3443e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenDescription:
3453e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Cleanup routine. This routine is called normally during driver unloading or exiting.
3463e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3473e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen--*/
34898d9fac4f0dec8545ed94abe729a15865cff6686Greg Kroah-Hartmanvoid HvCleanup (void)
3493e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
350f80b3d51a6708b5f14a59c53b1343db59efdda1eGreg Kroah-Hartman	union hv_x64_msr_hypercall_contents hypercallMsr;
3513e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3523e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_ENTER(VMBUS);
3533e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3543e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (gHvContext.SignalEventBuffer)
3553e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
3568c69f52ab3d918be9d91c8202e5321421876ea50Greg Kroah-Hartman		kfree(gHvContext.SignalEventBuffer);
3573e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		gHvContext.SignalEventBuffer = NULL;
3583e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		gHvContext.SignalEventParam = NULL;
3593e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
3603e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3613e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
3623e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
3633e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		if (gHvContext.HypercallPage)
3643e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
3653e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			hypercallMsr.AsUINT64 = 0;
366a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman			wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
367b7c947f04888b8bb2dc79832c10ede73c5b8dae2Bill Pemberton			vfree(gHvContext.HypercallPage);
3683e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			gHvContext.HypercallPage = NULL;
3693e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
3703e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
3713e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3723e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_EXIT(VMBUS);
3733e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3743e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
3753e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3763e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3773e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*++
3783e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3793e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenName:
3803e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HvPostMessage()
3813e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3823e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenDescription:
3833e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Post a message using the hypervisor message IPC. This
3843e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	involves a hypercall.
3853e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3863e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen--*/
38798d9fac4f0dec8545ed94abe729a15865cff6686Greg Kroah-HartmanHV_STATUS HvPostMessage(
388eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4fGreg Kroah-Hartman	union hv_connection_id connectionId,
389eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4fGreg Kroah-Hartman	enum hv_message_type messageType,
3908282c400144a83f85f637a5251740d670e392e84Greg Kroah-Hartman	void *            payload,
39145635d9703d649645afa52b23896d02e38a73852Greg Kroah-Hartman	size_t           payloadSize
3923e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	)
3933e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
3943e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	struct alignedInput {
39559471438ccbebafb0d63baf8b818d0ca692f882aGreg Kroah-Hartman		u64					alignment8;
396cba4decdd3dcd224b17631572456951aace0a27eGreg Kroah-Hartman		struct hv_input_post_message msg;
3973e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	};
3983e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
399cba4decdd3dcd224b17631572456951aace0a27eGreg Kroah-Hartman	struct hv_input_post_message *alignedMsg;
4003e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HV_STATUS status;
401c4b0bc94828a86cfb6a975b0e0d92dc1cd389565Greg Kroah-Hartman	unsigned long addr;
4023e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4033e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
4043e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
4053e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		return -1;
4063e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
4073e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4080a72f3cf9f53ae0f4f1c6e05bb081d99b5d72db2Greg Kroah-Hartman	addr = (unsigned long)kmalloc(sizeof(struct alignedInput), GFP_ATOMIC);
4093e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4103e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (!addr)
4113e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
4123e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		return -1;
4133e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
4143e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
415cba4decdd3dcd224b17631572456951aace0a27eGreg Kroah-Hartman	alignedMsg = (struct hv_input_post_message *)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
4163e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4173e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	alignedMsg->ConnectionId = connectionId;
4183e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	alignedMsg->MessageType = messageType;
4193e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	alignedMsg->PayloadSize = payloadSize;
4203e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	memcpy((void*)alignedMsg->Payload, payload, payloadSize);
4213e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
422949cadaa054588db0c4a3a0cfc3ac93f08fda913Greg Kroah-Hartman	status = HvDoHypercall(HvCallPostMessage, alignedMsg, NULL) & 0xFFFF;
4233e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4248c69f52ab3d918be9d91c8202e5321421876ea50Greg Kroah-Hartman	kfree((void*)addr);
4253e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4263e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	return status;
4273e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
4283e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4293e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4303e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*++
4313e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4323e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenName:
4333e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HvSignalEvent()
4343e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4353e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenDescription:
4363e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Signal an event on the specified connection using the hypervisor event IPC. This
4373e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	involves a hypercall.
4383e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4393e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen--*/
44098d9fac4f0dec8545ed94abe729a15865cff6686Greg Kroah-HartmanHV_STATUS HvSignalEvent(void)
4413e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
4423e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HV_STATUS status;
4433e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
444949cadaa054588db0c4a3a0cfc3ac93f08fda913Greg Kroah-Hartman	status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, NULL) & 0xFFFF;
4453e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4463e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	return status;
4473e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
4483e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4493e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4503e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*++
4513e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4523e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenName:
4533e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HvSynicInit()
4543e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4553e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenDescription:
4563e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Initialize the Synthethic Interrupt Controller. If it is already initialized by
4573e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	another entity (ie x2v shim), we need to retrieve the initialized message and event pages.
4583e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Otherwise, we create and initialize the message and event pages.
4593e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4603e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen--*/
46198d9fac4f0dec8545ed94abe729a15865cff6686Greg Kroah-Hartmanint HvSynicInit (u32 irqVector)
4623e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
46359471438ccbebafb0d63baf8b818d0ca692f882aGreg Kroah-Hartman	u64			version;
464eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4fGreg Kroah-Hartman	union hv_synic_simp simp;
465eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4fGreg Kroah-Hartman	union hv_synic_siefp siefp;
466eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4fGreg Kroah-Hartman	union hv_synic_sint sharedSint;
467eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4fGreg Kroah-Hartman	union hv_synic_scontrol sctrl;
46859471438ccbebafb0d63baf8b818d0ca692f882aGreg Kroah-Hartman	u64			guestID;
4693e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	int ret=0;
4703e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4713e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_ENTER(VMBUS);
4723e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4733e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (!gHvContext.HypercallPage)
4743e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
4753e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		DPRINT_EXIT(VMBUS);
4763e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		return ret;
4773e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
4783e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
479454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Check the version */
480a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	rdmsrl(HV_X64_MSR_SVERSION, version);
4813e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4823e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
4833e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
484454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* TODO: Handle SMP */
4853e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID)
4863e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
4873e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set.");
4883e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
489a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
490a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
4913e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
4923e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64);
4933e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
494454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Determine if we are running on xenlinux (ie x2v shim) or native linux */
495a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		rdmsrl(HV_X64_MSR_GUEST_OS_ID, guestID);
4963e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		if (guestID == HV_LINUX_GUEST_ID)
4973e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
498fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman			gHvContext.synICMessagePage[0] = phys_to_virt(simp.BaseSimpGpa << PAGE_SHIFT);
499fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman			gHvContext.synICEventPage[0] = phys_to_virt(siefp.BaseSiefpGpa << PAGE_SHIFT);
5003e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
5013e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		else
5023e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
5033e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			DPRINT_ERR(VMBUS, "unknown guest id!!");
5043e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			goto Cleanup;
5053e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
5063e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]);
5073e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
5083e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	else
5093e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
510bfc30aae73b6be57528059a9e03ce8674320e67bGreg Kroah-Hartman		gHvContext.synICMessagePage[0] = osd_PageAlloc(1);
5113e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		if (gHvContext.synICMessagePage[0] == NULL)
5123e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
5133e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!");
5143e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			goto Cleanup;
5153e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
5163e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
517bfc30aae73b6be57528059a9e03ce8674320e67bGreg Kroah-Hartman		gHvContext.synICEventPage[0] = osd_PageAlloc(1);
5183e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		if (gHvContext.synICEventPage[0] == NULL)
5193e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
5203e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!");
5213e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			goto Cleanup;
5223e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
5233e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
524454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Setup the Synic's message page */
525a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
5263e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		simp.SimpEnabled = 1;
527fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman		simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT;
5283e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5293e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
5303e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
531a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
5323e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
533454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Setup the Synic's event page */
534a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
5353e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		siefp.SiefpEnabled = 1;
536fa56d361b07513cba87cc5c2b57f3f51248f89a8Greg Kroah-Hartman		siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[0]) >> PAGE_SHIFT;
5373e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5383e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
5393e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
540a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
5413e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
542454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton    /* Setup the interception SINT. */
543a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	/* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */
544454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton    /*             interceptionSint.AsUINT64); */
545454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton
546454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton    /* Setup the shared SINT. */
547a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
5483e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5493e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	sharedSint.AsUINT64 = 0;
550454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	sharedSint.Vector = irqVector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */
551454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	sharedSint.Masked = false;
552454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	sharedSint.AutoEoi = true;
5533e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5543e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64);
5553e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
556a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
5573e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
558454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Enable the global synic bit */
559a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	rdmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
5603e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	sctrl.Enable = 1;
5613e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
562a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	wrmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
5633e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5640e727613ac6e1648d681a75d794862225c801d4bGreg Kroah-Hartman	gHvContext.SynICInitialized = true;
5653e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5663e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_EXIT(VMBUS);
5673e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5683e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	return ret;
5693e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5703e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenCleanup:
5713e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	ret = -1;
5723e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5733e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
5743e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
5753e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		if (gHvContext.synICEventPage[0])
5763e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
577bfc30aae73b6be57528059a9e03ce8674320e67bGreg Kroah-Hartman			osd_PageFree(gHvContext.synICEventPage[0],1);
5783e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
5793e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5803e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		if (gHvContext.synICMessagePage[0])
5813e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		{
582bfc30aae73b6be57528059a9e03ce8674320e67bGreg Kroah-Hartman			osd_PageFree(gHvContext.synICMessagePage[0], 1);
5833e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
5843e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
5853e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5863e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_EXIT(VMBUS);
5873e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5883e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	return ret;
5893e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5903e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
5913e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5923e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*++
5933e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5943e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenName:
5953e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	HvSynicCleanup()
5963e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
5973e7ee4902fe6996048f03433dd111426db3cfa92Hank JanssenDescription:
5983e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	Cleanup routine for HvSynicInit().
5993e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
6003e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen--*/
60198d9fac4f0dec8545ed94abe729a15865cff6686Greg Kroah-Hartmanvoid HvSynicCleanup(void)
6023e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
603eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4fGreg Kroah-Hartman	union hv_synic_sint sharedSint;
604eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4fGreg Kroah-Hartman	union hv_synic_simp simp;
605eacb1b4d24c2a8b7c1d73bb72e04920980ec8a4fGreg Kroah-Hartman	union hv_synic_siefp siefp;
6063e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
6073e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_ENTER(VMBUS);
6083e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
6093e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (!gHvContext.SynICInitialized)
6103e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
6113e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		DPRINT_EXIT(VMBUS);
6123e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		return;
6133e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
6143e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
615a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
6163e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
6173e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	sharedSint.Masked = 1;
6183e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
619454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Disable the interrupt */
620a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman	wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
6213e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
622454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/*
623454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * Disable and free the resources only if we are running as
624454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * native linux since in xenlinux, we are sharing the
625454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * resources with the x2v shim
626454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 */
6273e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
6283e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	{
629a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
6303e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		simp.SimpEnabled = 0;
6313e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		simp.BaseSimpGpa = 0;
6323e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
633a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
6343e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
635a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
6363e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		siefp.SiefpEnabled = 0;
6373e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		siefp.BaseSiefpGpa = 0;
6383e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
639a51ed7d65d62aa5ad8d364aa76af30328c26263fGreg Kroah-Hartman		wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
6403e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
641bfc30aae73b6be57528059a9e03ce8674320e67bGreg Kroah-Hartman		osd_PageFree(gHvContext.synICMessagePage[0], 1);
642bfc30aae73b6be57528059a9e03ce8674320e67bGreg Kroah-Hartman		osd_PageFree(gHvContext.synICEventPage[0], 1);
6433e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
6443e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
6453e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	DPRINT_EXIT(VMBUS);
6463e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
6473e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
6483e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
649454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton/* eof */
650