diff options
author | Hank Janssen <hjanssen@microsoft.com> | 2009-07-13 19:02:34 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-15 15:01:43 -0400 |
commit | 3e7ee4902fe6996048f03433dd111426db3cfa92 (patch) | |
tree | c42d158ecca25ddb0b99a400fa2682eeaa0aa82e /drivers/staging/hv/Hv.c | |
parent | ab05778195b5cc1e77130424f7f6b6f848a137f1 (diff) |
Staging: hv: add the Hyper-V virtual bus
This is the virtual bus that all of the Linux Hyper-V drivers use.
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/hv/Hv.c')
-rw-r--r-- | drivers/staging/hv/Hv.c | 672 |
1 files changed, 672 insertions, 0 deletions
diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/Hv.c new file mode 100644 index 00000000000..7aec8c94b2e --- /dev/null +++ b/drivers/staging/hv/Hv.c | |||
@@ -0,0 +1,672 @@ | |||
1 | /* | ||
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 | |||
24 | |||
25 | #include "logging.h" | ||
26 | #include "VmbusPrivate.h" | ||
27 | |||
28 | // | ||
29 | // Globals | ||
30 | // | ||
31 | |||
32 | // The one and only | ||
33 | HV_CONTEXT gHvContext={ | ||
34 | .SynICInitialized = FALSE, | ||
35 | .HypercallPage = NULL, | ||
36 | .SignalEventParam = NULL, | ||
37 | .SignalEventBuffer = NULL, | ||
38 | }; | ||
39 | |||
40 | |||
41 | /*++ | ||
42 | |||
43 | Name: | ||
44 | HvQueryHypervisorPresence() | ||
45 | |||
46 | Description: | ||
47 | Query the cpuid for presense of windows hypervisor | ||
48 | |||
49 | --*/ | ||
50 | static int | ||
51 | HvQueryHypervisorPresence ( | ||
52 | void | ||
53 | ) | ||
54 | { | ||
55 | unsigned int eax; | ||
56 | unsigned int ebx; | ||
57 | unsigned int ecx; | ||
58 | unsigned int edx; | ||
59 | unsigned int op; | ||
60 | |||
61 | eax = 0; | ||
62 | ebx = 0; | ||
63 | ecx = 0; | ||
64 | edx = 0; | ||
65 | op = HvCpuIdFunctionVersionAndFeatures; | ||
66 | do_cpuid(op, &eax, &ebx, &ecx, &edx); | ||
67 | |||
68 | return (ecx & HV_PRESENT_BIT); | ||
69 | } | ||
70 | |||
71 | |||
72 | /*++ | ||
73 | |||
74 | Name: | ||
75 | HvQueryHypervisorInfo() | ||
76 | |||
77 | Description: | ||
78 | Get version info of the windows hypervisor | ||
79 | |||
80 | --*/ | ||
81 | static int | ||
82 | HvQueryHypervisorInfo ( | ||
83 | void | ||
84 | ) | ||
85 | { | ||
86 | unsigned int eax; | ||
87 | unsigned int ebx; | ||
88 | unsigned int ecx; | ||
89 | unsigned int edx; | ||
90 | unsigned int maxLeaf; | ||
91 | unsigned int op; | ||
92 | |||
93 | // | ||
94 | // Its assumed that this is called after confirming that Viridian is present. | ||
95 | // Query id and revision. | ||
96 | // | ||
97 | |||
98 | eax = 0; | ||
99 | ebx = 0; | ||
100 | ecx = 0; | ||
101 | edx = 0; | ||
102 | op = HvCpuIdFunctionHvVendorAndMaxFunction; | ||
103 | do_cpuid(op, &eax, &ebx, &ecx, &edx); | ||
104 | |||
105 | DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c", | ||
106 | (ebx & 0xFF), | ||
107 | ((ebx >> 8) & 0xFF), | ||
108 | ((ebx >> 16) & 0xFF), | ||
109 | ((ebx >> 24) & 0xFF), | ||
110 | (ecx & 0xFF), | ||
111 | ((ecx >> 8) & 0xFF), | ||
112 | ((ecx >> 16) & 0xFF), | ||
113 | ((ecx >> 24) & 0xFF), | ||
114 | (edx & 0xFF), | ||
115 | ((edx >> 8) & 0xFF), | ||
116 | ((edx >> 16) & 0xFF), | ||
117 | ((edx >> 24) & 0xFF)); | ||
118 | |||
119 | maxLeaf = eax; | ||
120 | eax = 0; | ||
121 | ebx = 0; | ||
122 | ecx = 0; | ||
123 | edx = 0; | ||
124 | op = HvCpuIdFunctionHvInterface; | ||
125 | do_cpuid(op, &eax, &ebx, &ecx, &edx); | ||
126 | |||
127 | DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c", | ||
128 | (eax & 0xFF), | ||
129 | ((eax >> 8) & 0xFF), | ||
130 | ((eax >> 16) & 0xFF), | ||
131 | ((eax >> 24) & 0xFF)); | ||
132 | |||
133 | if (maxLeaf >= HvCpuIdFunctionMsHvVersion) { | ||
134 | eax = 0; | ||
135 | ebx = 0; | ||
136 | ecx = 0; | ||
137 | edx = 0; | ||
138 | op = HvCpuIdFunctionMsHvVersion; | ||
139 | do_cpuid(op, &eax, &ebx, &ecx, &edx); | ||
140 | DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d", | ||
141 | eax, | ||
142 | ebx >> 16, | ||
143 | ebx & 0xFFFF, | ||
144 | ecx, | ||
145 | edx >> 24, | ||
146 | edx & 0xFFFFFF); | ||
147 | } | ||
148 | return maxLeaf; | ||
149 | } | ||
150 | |||
151 | |||
152 | /*++ | ||
153 | |||
154 | Name: | ||
155 | HvDoHypercall() | ||
156 | |||
157 | Description: | ||
158 | Invoke the specified hypercall | ||
159 | |||
160 | --*/ | ||
161 | static UINT64 | ||
162 | HvDoHypercall ( | ||
163 | UINT64 Control, | ||
164 | void* Input, | ||
165 | void* Output | ||
166 | ) | ||
167 | { | ||
168 | #ifdef x86_64 | ||
169 | UINT64 hvStatus=0; | ||
170 | UINT64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0; | ||
171 | UINT64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0; | ||
172 | volatile void* hypercallPage = gHvContext.HypercallPage; | ||
173 | |||
174 | DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>", | ||
175 | Control, | ||
176 | inputAddress, | ||
177 | Input, | ||
178 | outputAddress, | ||
179 | Output, | ||
180 | hypercallPage); | ||
181 | |||
182 | __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8"); | ||
183 | __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage)); | ||
184 | |||
185 | DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus); | ||
186 | |||
187 | return hvStatus; | ||
188 | |||
189 | #else | ||
190 | |||
191 | UINT32 controlHi = Control >> 32; | ||
192 | UINT32 controlLo = Control & 0xFFFFFFFF; | ||
193 | UINT32 hvStatusHi = 1; | ||
194 | UINT32 hvStatusLo = 1; | ||
195 | UINT64 inputAddress = (Input) ? GetPhysicalAddress(Input) : 0; | ||
196 | UINT32 inputAddressHi = inputAddress >> 32; | ||
197 | UINT32 inputAddressLo = inputAddress & 0xFFFFFFFF; | ||
198 | UINT64 outputAddress = (Output) ?GetPhysicalAddress(Output) : 0; | ||
199 | UINT32 outputAddressHi = outputAddress >> 32; | ||
200 | UINT32 outputAddressLo = outputAddress & 0xFFFFFFFF; | ||
201 | volatile void* hypercallPage = gHvContext.HypercallPage; | ||
202 | |||
203 | DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>", | ||
204 | Control, | ||
205 | Input, | ||
206 | Output); | ||
207 | |||
208 | __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage)); | ||
209 | |||
210 | |||
211 | DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((UINT64)hvStatusHi << 32)); | ||
212 | |||
213 | return (hvStatusLo | ((UINT64)hvStatusHi << 32)); | ||
214 | #endif // x86_64 | ||
215 | } | ||
216 | |||
217 | /*++ | ||
218 | |||
219 | Name: | ||
220 | HvInit() | ||
221 | |||
222 | Description: | ||
223 | Main initialization routine. This routine must be called | ||
224 | before any other routines in here are called | ||
225 | |||
226 | --*/ | ||
227 | static int | ||
228 | HvInit ( | ||
229 | void | ||
230 | ) | ||
231 | { | ||
232 | int ret=0; | ||
233 | int maxLeaf; | ||
234 | HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; | ||
235 | void* virtAddr=0; | ||
236 | ULONG_PTR physAddr=0; | ||
237 | |||
238 | DPRINT_ENTER(VMBUS); | ||
239 | |||
240 | memset(gHvContext.synICEventPage, 0, sizeof(HANDLE)*MAX_NUM_CPUS); | ||
241 | memset(gHvContext.synICMessagePage, 0, sizeof(HANDLE)*MAX_NUM_CPUS); | ||
242 | |||
243 | if (!HvQueryHypervisorPresence()) | ||
244 | { | ||
245 | DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!"); | ||
246 | goto Cleanup; | ||
247 | } | ||
248 | |||
249 | DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info..."); | ||
250 | |||
251 | maxLeaf = HvQueryHypervisorInfo(); | ||
252 | //HvQueryHypervisorFeatures(maxLeaf); | ||
253 | |||
254 | // Determine if we are running on xenlinux (ie x2v shim) or native linux | ||
255 | gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID); | ||
256 | |||
257 | if (gHvContext.GuestId == 0) | ||
258 | { | ||
259 | // Write our OS info | ||
260 | WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); | ||
261 | |||
262 | gHvContext.GuestId = HV_LINUX_GUEST_ID; | ||
263 | } | ||
264 | |||
265 | // See if the hypercall page is already set | ||
266 | hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL); | ||
267 | |||
268 | if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | ||
269 | { | ||
270 | // Allocate the hypercall page memory | ||
271 | //virtAddr = PageAlloc(1); | ||
272 | virtAddr = VirtualAllocExec(PAGE_SIZE); | ||
273 | |||
274 | if (!virtAddr) | ||
275 | { | ||
276 | DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!"); | ||
277 | goto Cleanup; | ||
278 | } | ||
279 | |||
280 | hypercallMsr.Enable = 1; | ||
281 | //hypercallMsr.GuestPhysicalAddress = Logical2PhysicalAddr(virtAddr) >> PAGE_SHIFT; | ||
282 | hypercallMsr.GuestPhysicalAddress = Virtual2Physical(virtAddr) >> PAGE_SHIFT; | ||
283 | WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | ||
284 | |||
285 | // Confirm that hypercall page did get setup. | ||
286 | hypercallMsr.AsUINT64 = 0; | ||
287 | hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL); | ||
288 | |||
289 | if (!hypercallMsr.Enable) | ||
290 | { | ||
291 | DPRINT_ERR(VMBUS, "unable to set hypercall page!!"); | ||
292 | goto Cleanup; | ||
293 | } | ||
294 | |||
295 | gHvContext.HypercallPage = virtAddr; | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId); | ||
300 | goto Cleanup; | ||
301 | } | ||
302 | |||
303 | DPRINT_INFO(VMBUS, "Hypercall page VA=0x%08x, PA=0x%08x", | ||
304 | (unsigned long)gHvContext.HypercallPage, | ||
305 | (unsigned long)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT); | ||
306 | |||
307 | // Setup the global signal event param for the signal event hypercall | ||
308 | gHvContext.SignalEventBuffer = MemAlloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER)); | ||
309 | if (!gHvContext.SignalEventBuffer) | ||
310 | { | ||
311 | goto Cleanup; | ||
312 | } | ||
313 | |||
314 | gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((ULONG_PTR)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN)); | ||
315 | gHvContext.SignalEventParam->ConnectionId.AsUINT32 = 0; | ||
316 | gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID; | ||
317 | gHvContext.SignalEventParam->FlagNumber = 0; | ||
318 | gHvContext.SignalEventParam->RsvdZ = 0; | ||
319 | |||
320 | //DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); | ||
321 | |||
322 | DPRINT_EXIT(VMBUS); | ||
323 | |||
324 | return ret; | ||
325 | |||
326 | Cleanup: | ||
327 | if (virtAddr) | ||
328 | { | ||
329 | if (hypercallMsr.Enable) | ||
330 | { | ||
331 | hypercallMsr.AsUINT64 = 0; | ||
332 | WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | ||
333 | } | ||
334 | |||
335 | VirtualFree(virtAddr); | ||
336 | } | ||
337 | ret = -1; | ||
338 | DPRINT_EXIT(VMBUS); | ||
339 | |||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | |||
344 | /*++ | ||
345 | |||
346 | Name: | ||
347 | HvCleanup() | ||
348 | |||
349 | Description: | ||
350 | Cleanup routine. This routine is called normally during driver unloading or exiting. | ||
351 | |||
352 | --*/ | ||
353 | void | ||
354 | HvCleanup ( | ||
355 | void | ||
356 | ) | ||
357 | { | ||
358 | HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; | ||
359 | |||
360 | DPRINT_ENTER(VMBUS); | ||
361 | |||
362 | if (gHvContext.SignalEventBuffer) | ||
363 | { | ||
364 | MemFree(gHvContext.SignalEventBuffer); | ||
365 | gHvContext.SignalEventBuffer = NULL; | ||
366 | gHvContext.SignalEventParam = NULL; | ||
367 | } | ||
368 | |||
369 | if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | ||
370 | { | ||
371 | if (gHvContext.HypercallPage) | ||
372 | { | ||
373 | hypercallMsr.AsUINT64 = 0; | ||
374 | WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | ||
375 | VirtualFree(gHvContext.HypercallPage); | ||
376 | gHvContext.HypercallPage = NULL; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | DPRINT_EXIT(VMBUS); | ||
381 | |||
382 | } | ||
383 | |||
384 | |||
385 | /*++ | ||
386 | |||
387 | Name: | ||
388 | HvPostMessage() | ||
389 | |||
390 | Description: | ||
391 | Post a message using the hypervisor message IPC. This | ||
392 | involves a hypercall. | ||
393 | |||
394 | --*/ | ||
395 | HV_STATUS | ||
396 | HvPostMessage( | ||
397 | HV_CONNECTION_ID connectionId, | ||
398 | HV_MESSAGE_TYPE messageType, | ||
399 | PVOID payload, | ||
400 | SIZE_T payloadSize | ||
401 | ) | ||
402 | { | ||
403 | struct alignedInput { | ||
404 | UINT64 alignment8; | ||
405 | HV_INPUT_POST_MESSAGE msg; | ||
406 | }; | ||
407 | |||
408 | PHV_INPUT_POST_MESSAGE alignedMsg; | ||
409 | HV_STATUS status; | ||
410 | ULONG_PTR addr; | ||
411 | |||
412 | if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT) | ||
413 | { | ||
414 | return -1; | ||
415 | } | ||
416 | |||
417 | addr = (ULONG_PTR)MemAllocAtomic(sizeof(struct alignedInput)); | ||
418 | |||
419 | if (!addr) | ||
420 | { | ||
421 | return -1; | ||
422 | } | ||
423 | |||
424 | alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN)); | ||
425 | |||
426 | alignedMsg->ConnectionId = connectionId; | ||
427 | alignedMsg->MessageType = messageType; | ||
428 | alignedMsg->PayloadSize = payloadSize; | ||
429 | memcpy((void*)alignedMsg->Payload, payload, payloadSize); | ||
430 | |||
431 | status = HvDoHypercall(HvCallPostMessage, alignedMsg, 0) & 0xFFFF; | ||
432 | |||
433 | MemFree((void*)addr); | ||
434 | |||
435 | return status; | ||
436 | } | ||
437 | |||
438 | |||
439 | /*++ | ||
440 | |||
441 | Name: | ||
442 | HvSignalEvent() | ||
443 | |||
444 | Description: | ||
445 | Signal an event on the specified connection using the hypervisor event IPC. This | ||
446 | involves a hypercall. | ||
447 | |||
448 | --*/ | ||
449 | HV_STATUS | ||
450 | HvSignalEvent( | ||
451 | ) | ||
452 | { | ||
453 | HV_STATUS status; | ||
454 | |||
455 | status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, 0) & 0xFFFF; | ||
456 | |||
457 | return status; | ||
458 | } | ||
459 | |||
460 | |||
461 | /*++ | ||
462 | |||
463 | Name: | ||
464 | HvSynicInit() | ||
465 | |||
466 | Description: | ||
467 | Initialize the Synthethic Interrupt Controller. If it is already initialized by | ||
468 | another entity (ie x2v shim), we need to retrieve the initialized message and event pages. | ||
469 | Otherwise, we create and initialize the message and event pages. | ||
470 | |||
471 | --*/ | ||
472 | int | ||
473 | HvSynicInit ( | ||
474 | UINT32 irqVector | ||
475 | ) | ||
476 | { | ||
477 | UINT64 version; | ||
478 | HV_SYNIC_SIMP simp; | ||
479 | HV_SYNIC_SIEFP siefp; | ||
480 | HV_SYNIC_SINT sharedSint; | ||
481 | HV_SYNIC_SCONTROL sctrl; | ||
482 | UINT64 guestID; | ||
483 | int ret=0; | ||
484 | |||
485 | DPRINT_ENTER(VMBUS); | ||
486 | |||
487 | if (!gHvContext.HypercallPage) | ||
488 | { | ||
489 | DPRINT_EXIT(VMBUS); | ||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | // Check the version | ||
494 | version = ReadMsr(HV_X64_MSR_SVERSION); | ||
495 | |||
496 | DPRINT_INFO(VMBUS, "SynIC version: %llx", version); | ||
497 | |||
498 | // TODO: Handle SMP | ||
499 | if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID) | ||
500 | { | ||
501 | DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set."); | ||
502 | |||
503 | simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); | ||
504 | siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); | ||
505 | |||
506 | DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64); | ||
507 | |||
508 | // Determine if we are running on xenlinux (ie x2v shim) or native linux | ||
509 | guestID = ReadMsr(HV_X64_MSR_GUEST_OS_ID); | ||
510 | |||
511 | if (guestID == HV_LINUX_GUEST_ID) | ||
512 | { | ||
513 | gHvContext.synICMessagePage[0] = GetVirtualAddress(simp.BaseSimpGpa << PAGE_SHIFT); | ||
514 | gHvContext.synICEventPage[0] = GetVirtualAddress(siefp.BaseSiefpGpa << PAGE_SHIFT); | ||
515 | } | ||
516 | else | ||
517 | { | ||
518 | DPRINT_ERR(VMBUS, "unknown guest id!!"); | ||
519 | goto Cleanup; | ||
520 | } | ||
521 | DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]); | ||
522 | } | ||
523 | else | ||
524 | { | ||
525 | gHvContext.synICMessagePage[0] = PageAlloc(1); | ||
526 | if (gHvContext.synICMessagePage[0] == NULL) | ||
527 | { | ||
528 | DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!"); | ||
529 | goto Cleanup; | ||
530 | } | ||
531 | |||
532 | gHvContext.synICEventPage[0] = PageAlloc(1); | ||
533 | if (gHvContext.synICEventPage[0] == NULL) | ||
534 | { | ||
535 | DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!"); | ||
536 | goto Cleanup; | ||
537 | } | ||
538 | |||
539 | // | ||
540 | // Setup the Synic's message page | ||
541 | // | ||
542 | simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); | ||
543 | simp.SimpEnabled = 1; | ||
544 | simp.BaseSimpGpa = GetPhysicalAddress(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT; | ||
545 | |||
546 | DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64); | ||
547 | |||
548 | WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64); | ||
549 | |||
550 | // | ||
551 | // Setup the Synic's event page | ||
552 | // | ||
553 | siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); | ||
554 | siefp.SiefpEnabled = 1; | ||
555 | siefp.BaseSiefpGpa = GetPhysicalAddress(gHvContext.synICEventPage[0]) >> PAGE_SHIFT; | ||
556 | |||
557 | DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64); | ||
558 | |||
559 | WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64); | ||
560 | } | ||
561 | // | ||
562 | // Setup the interception SINT. | ||
563 | // | ||
564 | //WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), | ||
565 | // interceptionSint.AsUINT64); | ||
566 | |||
567 | // | ||
568 | // Setup the shared SINT. | ||
569 | // | ||
570 | sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT); | ||
571 | |||
572 | sharedSint.AsUINT64 = 0; | ||
573 | sharedSint.Vector = irqVector; //HV_SHARED_SINT_IDT_VECTOR + 0x20; | ||
574 | sharedSint.Masked = FALSE; | ||
575 | sharedSint.AutoEoi = TRUE; | ||
576 | |||
577 | DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64); | ||
578 | |||
579 | WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); | ||
580 | |||
581 | // Enable the global synic bit | ||
582 | sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL); | ||
583 | sctrl.Enable = 1; | ||
584 | |||
585 | WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64); | ||
586 | |||
587 | gHvContext.SynICInitialized = TRUE; | ||
588 | |||
589 | DPRINT_EXIT(VMBUS); | ||
590 | |||
591 | return ret; | ||
592 | |||
593 | Cleanup: | ||
594 | ret = -1; | ||
595 | |||
596 | if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | ||
597 | { | ||
598 | if (gHvContext.synICEventPage[0]) | ||
599 | { | ||
600 | PageFree(gHvContext.synICEventPage[0],1); | ||
601 | } | ||
602 | |||
603 | if (gHvContext.synICMessagePage[0]) | ||
604 | { | ||
605 | PageFree(gHvContext.synICMessagePage[0], 1); | ||
606 | } | ||
607 | } | ||
608 | |||
609 | DPRINT_EXIT(VMBUS); | ||
610 | |||
611 | return ret; | ||
612 | |||
613 | } | ||
614 | |||
615 | /*++ | ||
616 | |||
617 | Name: | ||
618 | HvSynicCleanup() | ||
619 | |||
620 | Description: | ||
621 | Cleanup routine for HvSynicInit(). | ||
622 | |||
623 | --*/ | ||
624 | VOID | ||
625 | HvSynicCleanup( | ||
626 | VOID | ||
627 | ) | ||
628 | { | ||
629 | HV_SYNIC_SINT sharedSint; | ||
630 | HV_SYNIC_SIMP simp; | ||
631 | HV_SYNIC_SIEFP siefp; | ||
632 | |||
633 | DPRINT_ENTER(VMBUS); | ||
634 | |||
635 | if (!gHvContext.SynICInitialized) | ||
636 | { | ||
637 | DPRINT_EXIT(VMBUS); | ||
638 | return; | ||
639 | } | ||
640 | |||
641 | sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT); | ||
642 | |||
643 | sharedSint.Masked = 1; | ||
644 | |||
645 | // Disable the interrupt | ||
646 | WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); | ||
647 | |||
648 | // Disable and free the resources only if we are running as native linux | ||
649 | // since in xenlinux, we are sharing the resources with the x2v shim | ||
650 | if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | ||
651 | { | ||
652 | simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); | ||
653 | simp.SimpEnabled = 0; | ||
654 | simp.BaseSimpGpa = 0; | ||
655 | |||
656 | WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64); | ||
657 | |||
658 | siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); | ||
659 | siefp.SiefpEnabled = 0; | ||
660 | siefp.BaseSiefpGpa = 0; | ||
661 | |||
662 | WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64); | ||
663 | |||
664 | PageFree(gHvContext.synICMessagePage[0], 1); | ||
665 | PageFree(gHvContext.synICEventPage[0], 1); | ||
666 | } | ||
667 | |||
668 | DPRINT_EXIT(VMBUS); | ||
669 | } | ||
670 | |||
671 | |||
672 | // eof | ||