blob: 334812fdc84b49e5bfaa392fb500b73d96b2a029 [file] [log] [blame]
Hank Janssen3e7ee492009-07-13 16:02:34 -07001/*
2 *
3 * Copyright (c) 2009, Microsoft Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 * Authors:
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
21 *
22 */
23
Bill Pembertonb7c947f2009-07-29 17:00:13 -040024#include <linux/vmalloc.h>
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -070025#include "include/logging.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070026#include "VmbusPrivate.h"
27
Bill Pemberton454f18a2009-07-27 16:47:24 -040028/* Globals */
Hank Janssen3e7ee492009-07-13 16:02:34 -070029
Bill Pemberton454f18a2009-07-27 16:47:24 -040030/* The one and only */
Hank Janssen3e7ee492009-07-13 16:02:34 -070031HV_CONTEXT gHvContext={
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -070032 .SynICInitialized = false,
Hank Janssen3e7ee492009-07-13 16:02:34 -070033 .HypercallPage = NULL,
34 .SignalEventParam = NULL,
35 .SignalEventBuffer = NULL,
36};
37
38
39/*++
40
41Name:
42 HvQueryHypervisorPresence()
43
44Description:
45 Query the cpuid for presense of windows hypervisor
46
47--*/
48static int
49HvQueryHypervisorPresence (
50 void
51 )
52{
53 unsigned int eax;
54 unsigned int ebx;
55 unsigned int ecx;
56 unsigned int edx;
57 unsigned int op;
58
59 eax = 0;
60 ebx = 0;
61 ecx = 0;
62 edx = 0;
63 op = HvCpuIdFunctionVersionAndFeatures;
64 do_cpuid(op, &eax, &ebx, &ecx, &edx);
65
66 return (ecx & HV_PRESENT_BIT);
67}
68
69
70/*++
71
72Name:
73 HvQueryHypervisorInfo()
74
75Description:
76 Get version info of the windows hypervisor
77
78--*/
79static int
80HvQueryHypervisorInfo (
81 void
82 )
83{
84 unsigned int eax;
85 unsigned int ebx;
86 unsigned int ecx;
87 unsigned int edx;
88 unsigned int maxLeaf;
89 unsigned int op;
90
Bill Pemberton454f18a2009-07-27 16:47:24 -040091 /*
92 * Its assumed that this is called after confirming that Viridian
93 * is present. Query id and revision.
94 */
95
Hank Janssen3e7ee492009-07-13 16:02:34 -070096
97 eax = 0;
98 ebx = 0;
99 ecx = 0;
100 edx = 0;
101 op = HvCpuIdFunctionHvVendorAndMaxFunction;
102 do_cpuid(op, &eax, &ebx, &ecx, &edx);
103
104 DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
Bill Pemberton454f18a2009-07-27 16:47:24 -0400105 (ebx & 0xFF),
106 ((ebx >> 8) & 0xFF),
107 ((ebx >> 16) & 0xFF),
108 ((ebx >> 24) & 0xFF),
109 (ecx & 0xFF),
110 ((ecx >> 8) & 0xFF),
111 ((ecx >> 16) & 0xFF),
112 ((ecx >> 24) & 0xFF),
113 (edx & 0xFF),
114 ((edx >> 8) & 0xFF),
115 ((edx >> 16) & 0xFF),
116 ((edx >> 24) & 0xFF));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700117
118 maxLeaf = eax;
119 eax = 0;
120 ebx = 0;
121 ecx = 0;
122 edx = 0;
123 op = HvCpuIdFunctionHvInterface;
124 do_cpuid(op, &eax, &ebx, &ecx, &edx);
125
126 DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
Bill Pemberton454f18a2009-07-27 16:47:24 -0400127 (eax & 0xFF),
128 ((eax >> 8) & 0xFF),
129 ((eax >> 16) & 0xFF),
130 ((eax >> 24) & 0xFF));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700131
132 if (maxLeaf >= HvCpuIdFunctionMsHvVersion) {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400133 eax = 0;
134 ebx = 0;
135 ecx = 0;
136 edx = 0;
137 op = HvCpuIdFunctionMsHvVersion;
138 do_cpuid(op, &eax, &ebx, &ecx, &edx);
139 DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",
140 eax,
141 ebx >> 16,
142 ebx & 0xFFFF,
143 ecx,
144 edx >> 24,
145 edx & 0xFFFFFF);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700146 }
147 return maxLeaf;
148}
149
150
151/*++
152
153Name:
154 HvDoHypercall()
155
156Description:
157 Invoke the specified hypercall
158
159--*/
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700160static u64
Hank Janssen3e7ee492009-07-13 16:02:34 -0700161HvDoHypercall (
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700162 u64 Control,
Hank Janssen3e7ee492009-07-13 16:02:34 -0700163 void* Input,
164 void* Output
165 )
166{
Greg Kroah-Hartman530cf202009-07-16 22:31:15 -0700167#ifdef CONFIG_X86_64
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700168 u64 hvStatus=0;
169 u64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0;
170 u64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700171 volatile void* hypercallPage = gHvContext.HypercallPage;
172
173 DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>",
174 Control,
175 inputAddress,
176 Input,
177 outputAddress,
178 Output,
179 hypercallPage);
180
181 __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8");
182 __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage));
183
184 DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus);
185
186 return hvStatus;
187
188#else
189
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700190 u32 controlHi = Control >> 32;
191 u32 controlLo = Control & 0xFFFFFFFF;
192 u32 hvStatusHi = 1;
193 u32 hvStatusLo = 1;
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700194 u64 inputAddress = (Input) ? GetPhysicalAddress(Input) : 0;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700195 u32 inputAddressHi = inputAddress >> 32;
196 u32 inputAddressLo = inputAddress & 0xFFFFFFFF;
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700197 u64 outputAddress = (Output) ?GetPhysicalAddress(Output) : 0;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700198 u32 outputAddressHi = outputAddress >> 32;
199 u32 outputAddressLo = outputAddress & 0xFFFFFFFF;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700200 volatile void* hypercallPage = gHvContext.HypercallPage;
201
202 DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
203 Control,
204 Input,
205 Output);
206
207 __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage));
208
209
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700210 DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((u64)hvStatusHi << 32));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700211
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700212 return (hvStatusLo | ((u64)hvStatusHi << 32));
Bill Pemberton454f18a2009-07-27 16:47:24 -0400213#endif /* x86_64 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700214}
215
216/*++
217
218Name:
219 HvInit()
220
221Description:
222 Main initialization routine. This routine must be called
223 before any other routines in here are called
224
225--*/
226static int
227HvInit (
228 void
229 )
230{
231 int ret=0;
232 int maxLeaf;
233 HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
Greg Kroah-Hartman949cada2009-07-29 09:06:51 -0700234 void *virtAddr = NULL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700235
236 DPRINT_ENTER(VMBUS);
237
Bill Pemberton44f357f2009-07-28 13:46:26 -0400238 memset(gHvContext.synICEventPage, 0, sizeof(void *) * MAX_NUM_CPUS);
239 memset(gHvContext.synICMessagePage, 0, sizeof(void *) * MAX_NUM_CPUS);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700240
241 if (!HvQueryHypervisorPresence())
242 {
243 DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
244 goto Cleanup;
245 }
246
247 DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info...");
248
249 maxLeaf = HvQueryHypervisorInfo();
Bill Pemberton454f18a2009-07-27 16:47:24 -0400250 /* HvQueryHypervisorFeatures(maxLeaf); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700251
Bill Pemberton454f18a2009-07-27 16:47:24 -0400252 /* Determine if we are running on xenlinux (ie x2v shim) or native linux */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700253 gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
254
255 if (gHvContext.GuestId == 0)
256 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400257 /* Write our OS info */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700258 WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
259
260 gHvContext.GuestId = HV_LINUX_GUEST_ID;
261 }
262
Bill Pemberton454f18a2009-07-27 16:47:24 -0400263 /* See if the hypercall page is already set */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700264 hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
265
266 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
267 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400268 /* Allocate the hypercall page memory */
269 /* virtAddr = PageAlloc(1); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700270 virtAddr = VirtualAllocExec(PAGE_SIZE);
271
272 if (!virtAddr)
273 {
274 DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!");
275 goto Cleanup;
276 }
277
278 hypercallMsr.Enable = 1;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400279 /* hypercallMsr.GuestPhysicalAddress = Logical2PhysicalAddr(virtAddr) >> PAGE_SHIFT; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700280 hypercallMsr.GuestPhysicalAddress = Virtual2Physical(virtAddr) >> PAGE_SHIFT;
281 WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
282
Bill Pemberton454f18a2009-07-27 16:47:24 -0400283 /* Confirm that hypercall page did get setup. */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700284 hypercallMsr.AsUINT64 = 0;
285 hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
286
287 if (!hypercallMsr.Enable)
288 {
289 DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
290 goto Cleanup;
291 }
292
293 gHvContext.HypercallPage = virtAddr;
294 }
295 else
296 {
297 DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId);
298 goto Cleanup;
299 }
300
Greg Kroah-Hartman2701f682009-07-16 12:36:37 -0700301 DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx",
302 gHvContext.HypercallPage,
303 (u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700304
Bill Pemberton454f18a2009-07-27 16:47:24 -0400305 /* Setup the global signal event param for the signal event hypercall */
Greg Kroah-Hartmane40d37c2009-07-15 12:47:22 -0700306 gHvContext.SignalEventBuffer = kmalloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER), GFP_KERNEL);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700307 if (!gHvContext.SignalEventBuffer)
308 {
309 goto Cleanup;
310 }
311
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700312 gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((unsigned long)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN));
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700313 gHvContext.SignalEventParam->ConnectionId.Asu32 = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700314 gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID;
315 gHvContext.SignalEventParam->FlagNumber = 0;
316 gHvContext.SignalEventParam->RsvdZ = 0;
317
Bill Pemberton454f18a2009-07-27 16:47:24 -0400318 /* DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700319
320 DPRINT_EXIT(VMBUS);
321
322 return ret;
323
324Cleanup:
325 if (virtAddr)
326 {
327 if (hypercallMsr.Enable)
328 {
329 hypercallMsr.AsUINT64 = 0;
330 WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
331 }
332
Bill Pembertonb7c947f2009-07-29 17:00:13 -0400333 vfree(virtAddr);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700334 }
335 ret = -1;
336 DPRINT_EXIT(VMBUS);
337
338 return ret;
339}
340
341
342/*++
343
344Name:
345 HvCleanup()
346
347Description:
348 Cleanup routine. This routine is called normally during driver unloading or exiting.
349
350--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700351static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700352HvCleanup (
353 void
354 )
355{
356 HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
357
358 DPRINT_ENTER(VMBUS);
359
360 if (gHvContext.SignalEventBuffer)
361 {
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700362 kfree(gHvContext.SignalEventBuffer);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700363 gHvContext.SignalEventBuffer = NULL;
364 gHvContext.SignalEventParam = NULL;
365 }
366
367 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
368 {
369 if (gHvContext.HypercallPage)
370 {
371 hypercallMsr.AsUINT64 = 0;
372 WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
Bill Pembertonb7c947f2009-07-29 17:00:13 -0400373 vfree(gHvContext.HypercallPage);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700374 gHvContext.HypercallPage = NULL;
375 }
376 }
377
378 DPRINT_EXIT(VMBUS);
379
380}
381
382
383/*++
384
385Name:
386 HvPostMessage()
387
388Description:
389 Post a message using the hypervisor message IPC. This
390 involves a hypercall.
391
392--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700393static HV_STATUS
Hank Janssen3e7ee492009-07-13 16:02:34 -0700394HvPostMessage(
395 HV_CONNECTION_ID connectionId,
396 HV_MESSAGE_TYPE messageType,
Greg Kroah-Hartman8282c402009-07-14 15:06:28 -0700397 void * payload,
Greg Kroah-Hartman45635d92009-07-14 15:14:20 -0700398 size_t payloadSize
Hank Janssen3e7ee492009-07-13 16:02:34 -0700399 )
400{
401 struct alignedInput {
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700402 u64 alignment8;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700403 HV_INPUT_POST_MESSAGE msg;
404 };
405
406 PHV_INPUT_POST_MESSAGE alignedMsg;
407 HV_STATUS status;
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700408 unsigned long addr;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700409
410 if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
411 {
412 return -1;
413 }
414
Greg Kroah-Hartman0a72f3c2009-07-15 12:48:01 -0700415 addr = (unsigned long)kmalloc(sizeof(struct alignedInput), GFP_ATOMIC);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700416
417 if (!addr)
418 {
419 return -1;
420 }
421
422 alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
423
424 alignedMsg->ConnectionId = connectionId;
425 alignedMsg->MessageType = messageType;
426 alignedMsg->PayloadSize = payloadSize;
427 memcpy((void*)alignedMsg->Payload, payload, payloadSize);
428
Greg Kroah-Hartman949cada2009-07-29 09:06:51 -0700429 status = HvDoHypercall(HvCallPostMessage, alignedMsg, NULL) & 0xFFFF;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700430
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700431 kfree((void*)addr);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700432
433 return status;
434}
435
436
437/*++
438
439Name:
440 HvSignalEvent()
441
442Description:
443 Signal an event on the specified connection using the hypervisor event IPC. This
444 involves a hypercall.
445
446--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700447static HV_STATUS
Greg Kroah-Hartman12772902009-07-29 09:05:33 -0700448HvSignalEvent(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700449{
450 HV_STATUS status;
451
Greg Kroah-Hartman949cada2009-07-29 09:06:51 -0700452 status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, NULL) & 0xFFFF;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700453
454 return status;
455}
456
457
458/*++
459
460Name:
461 HvSynicInit()
462
463Description:
464 Initialize the Synthethic Interrupt Controller. If it is already initialized by
465 another entity (ie x2v shim), we need to retrieve the initialized message and event pages.
466 Otherwise, we create and initialize the message and event pages.
467
468--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700469static int
Hank Janssen3e7ee492009-07-13 16:02:34 -0700470HvSynicInit (
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700471 u32 irqVector
Hank Janssen3e7ee492009-07-13 16:02:34 -0700472 )
473{
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700474 u64 version;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700475 HV_SYNIC_SIMP simp;
476 HV_SYNIC_SIEFP siefp;
477 HV_SYNIC_SINT sharedSint;
478 HV_SYNIC_SCONTROL sctrl;
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700479 u64 guestID;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700480 int ret=0;
481
482 DPRINT_ENTER(VMBUS);
483
484 if (!gHvContext.HypercallPage)
485 {
486 DPRINT_EXIT(VMBUS);
487 return ret;
488 }
489
Bill Pemberton454f18a2009-07-27 16:47:24 -0400490 /* Check the version */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700491 version = ReadMsr(HV_X64_MSR_SVERSION);
492
493 DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
494
Bill Pemberton454f18a2009-07-27 16:47:24 -0400495 /* TODO: Handle SMP */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700496 if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID)
497 {
498 DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set.");
499
500 simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
501 siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
502
503 DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64);
504
Bill Pemberton454f18a2009-07-27 16:47:24 -0400505 /* Determine if we are running on xenlinux (ie x2v shim) or native linux */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700506 guestID = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
507
508 if (guestID == HV_LINUX_GUEST_ID)
509 {
510 gHvContext.synICMessagePage[0] = GetVirtualAddress(simp.BaseSimpGpa << PAGE_SHIFT);
511 gHvContext.synICEventPage[0] = GetVirtualAddress(siefp.BaseSiefpGpa << PAGE_SHIFT);
512 }
513 else
514 {
515 DPRINT_ERR(VMBUS, "unknown guest id!!");
516 goto Cleanup;
517 }
518 DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]);
519 }
520 else
521 {
522 gHvContext.synICMessagePage[0] = PageAlloc(1);
523 if (gHvContext.synICMessagePage[0] == NULL)
524 {
525 DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!");
526 goto Cleanup;
527 }
528
529 gHvContext.synICEventPage[0] = PageAlloc(1);
530 if (gHvContext.synICEventPage[0] == NULL)
531 {
532 DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!");
533 goto Cleanup;
534 }
535
Bill Pemberton454f18a2009-07-27 16:47:24 -0400536 /* Setup the Synic's message page */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700537 simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
538 simp.SimpEnabled = 1;
539 simp.BaseSimpGpa = GetPhysicalAddress(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT;
540
541 DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
542
543 WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
544
Bill Pemberton454f18a2009-07-27 16:47:24 -0400545 /* Setup the Synic's event page */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700546 siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
547 siefp.SiefpEnabled = 1;
548 siefp.BaseSiefpGpa = GetPhysicalAddress(gHvContext.synICEventPage[0]) >> PAGE_SHIFT;
549
550 DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
551
552 WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
553 }
Bill Pemberton454f18a2009-07-27 16:47:24 -0400554 /* Setup the interception SINT. */
555 /* WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */
556 /* interceptionSint.AsUINT64); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700557
Bill Pemberton454f18a2009-07-27 16:47:24 -0400558 /* Setup the shared SINT. */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700559 sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
560
561 sharedSint.AsUINT64 = 0;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400562 sharedSint.Vector = irqVector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */
563 sharedSint.Masked = false;
564 sharedSint.AutoEoi = true;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700565
566 DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64);
567
568 WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
569
Bill Pemberton454f18a2009-07-27 16:47:24 -0400570 /* Enable the global synic bit */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700571 sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL);
572 sctrl.Enable = 1;
573
Bill Pemberton454f18a2009-07-27 16:47:24 -0400574 WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700575
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700576 gHvContext.SynICInitialized = true;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700577
578 DPRINT_EXIT(VMBUS);
579
580 return ret;
581
582Cleanup:
583 ret = -1;
584
585 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
586 {
587 if (gHvContext.synICEventPage[0])
588 {
589 PageFree(gHvContext.synICEventPage[0],1);
590 }
591
592 if (gHvContext.synICMessagePage[0])
593 {
594 PageFree(gHvContext.synICMessagePage[0], 1);
595 }
596 }
597
598 DPRINT_EXIT(VMBUS);
599
600 return ret;
601
602}
603
604/*++
605
606Name:
607 HvSynicCleanup()
608
609Description:
610 Cleanup routine for HvSynicInit().
611
612--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700613static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700614HvSynicCleanup(
Greg Kroah-Hartmane20f6832009-07-14 15:07:21 -0700615 void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700616 )
617{
618 HV_SYNIC_SINT sharedSint;
619 HV_SYNIC_SIMP simp;
620 HV_SYNIC_SIEFP siefp;
621
622 DPRINT_ENTER(VMBUS);
623
624 if (!gHvContext.SynICInitialized)
625 {
626 DPRINT_EXIT(VMBUS);
627 return;
628 }
629
630 sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
631
632 sharedSint.Masked = 1;
633
Bill Pemberton454f18a2009-07-27 16:47:24 -0400634 /* Disable the interrupt */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700635 WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
636
Bill Pemberton454f18a2009-07-27 16:47:24 -0400637 /*
638 * Disable and free the resources only if we are running as
639 * native linux since in xenlinux, we are sharing the
640 * resources with the x2v shim
641 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700642 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
643 {
644 simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
645 simp.SimpEnabled = 0;
646 simp.BaseSimpGpa = 0;
647
648 WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
649
650 siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
651 siefp.SiefpEnabled = 0;
652 siefp.BaseSiefpGpa = 0;
653
654 WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
655
656 PageFree(gHvContext.synICMessagePage[0], 1);
657 PageFree(gHvContext.synICEventPage[0], 1);
658 }
659
660 DPRINT_EXIT(VMBUS);
661}
662
663
Bill Pemberton454f18a2009-07-27 16:47:24 -0400664/* eof */