Commit | Line | Data |
---|---|---|
3e7ee490 HJ |
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 | ||
09d50ff8 | 25 | #include "include/logging.h" |
3e7ee490 HJ |
26 | #include "VmbusPrivate.h" |
27 | ||
454f18a9 | 28 | /* Globals */ |
3e7ee490 | 29 | |
454f18a9 | 30 | /* The one and only */ |
3e7ee490 | 31 | HV_CONTEXT gHvContext={ |
0e727613 | 32 | .SynICInitialized = false, |
3e7ee490 HJ |
33 | .HypercallPage = NULL, |
34 | .SignalEventParam = NULL, | |
35 | .SignalEventBuffer = NULL, | |
36 | }; | |
37 | ||
38 | ||
39 | /*++ | |
40 | ||
41 | Name: | |
42 | HvQueryHypervisorPresence() | |
43 | ||
44 | Description: | |
45 | Query the cpuid for presense of windows hypervisor | |
46 | ||
47 | --*/ | |
48 | static int | |
49 | HvQueryHypervisorPresence ( | |
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 | ||
72 | Name: | |
73 | HvQueryHypervisorInfo() | |
74 | ||
75 | Description: | |
76 | Get version info of the windows hypervisor | |
77 | ||
78 | --*/ | |
79 | static int | |
80 | HvQueryHypervisorInfo ( | |
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 | ||
454f18a9 BP |
91 | /* |
92 | * Its assumed that this is called after confirming that Viridian | |
93 | * is present. Query id and revision. | |
94 | */ | |
95 | ||
3e7ee490 HJ |
96 | |
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", | |
454f18a9 BP |
105 | (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)); | |
3e7ee490 HJ |
117 | |
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", | |
454f18a9 BP |
127 | (eax & 0xFF), |
128 | ((eax >> 8) & 0xFF), | |
129 | ((eax >> 16) & 0xFF), | |
130 | ((eax >> 24) & 0xFF)); | |
3e7ee490 HJ |
131 | |
132 | if (maxLeaf >= HvCpuIdFunctionMsHvVersion) { | |
454f18a9 BP |
133 | 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); | |
3e7ee490 HJ |
146 | } |
147 | return maxLeaf; | |
148 | } | |
149 | ||
150 | ||
151 | /*++ | |
152 | ||
153 | Name: | |
154 | HvDoHypercall() | |
155 | ||
156 | Description: | |
157 | Invoke the specified hypercall | |
158 | ||
159 | --*/ | |
59471438 | 160 | static u64 |
3e7ee490 | 161 | HvDoHypercall ( |
59471438 | 162 | u64 Control, |
3e7ee490 HJ |
163 | void* Input, |
164 | void* Output | |
165 | ) | |
166 | { | |
530cf207 | 167 | #ifdef CONFIG_X86_64 |
59471438 GKH |
168 | u64 hvStatus=0; |
169 | u64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0; | |
170 | u64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0; | |
3e7ee490 HJ |
171 | 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 | ||
4d643114 GKH |
190 | u32 controlHi = Control >> 32; |
191 | u32 controlLo = Control & 0xFFFFFFFF; | |
192 | u32 hvStatusHi = 1; | |
193 | u32 hvStatusLo = 1; | |
59471438 | 194 | u64 inputAddress = (Input) ? GetPhysicalAddress(Input) : 0; |
4d643114 GKH |
195 | u32 inputAddressHi = inputAddress >> 32; |
196 | u32 inputAddressLo = inputAddress & 0xFFFFFFFF; | |
59471438 | 197 | u64 outputAddress = (Output) ?GetPhysicalAddress(Output) : 0; |
4d643114 GKH |
198 | u32 outputAddressHi = outputAddress >> 32; |
199 | u32 outputAddressLo = outputAddress & 0xFFFFFFFF; | |
3e7ee490 HJ |
200 | 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 | ||
59471438 | 210 | DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((u64)hvStatusHi << 32)); |
3e7ee490 | 211 | |
59471438 | 212 | return (hvStatusLo | ((u64)hvStatusHi << 32)); |
454f18a9 | 213 | #endif /* x86_64 */ |
3e7ee490 HJ |
214 | } |
215 | ||
216 | /*++ | |
217 | ||
218 | Name: | |
219 | HvInit() | |
220 | ||
221 | Description: | |
222 | Main initialization routine. This routine must be called | |
223 | before any other routines in here are called | |
224 | ||
225 | --*/ | |
226 | static int | |
227 | HvInit ( | |
228 | void | |
229 | ) | |
230 | { | |
231 | int ret=0; | |
232 | int maxLeaf; | |
233 | HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; | |
234 | void* virtAddr=0; | |
3e7ee490 HJ |
235 | |
236 | DPRINT_ENTER(VMBUS); | |
237 | ||
44f357f8 BP |
238 | memset(gHvContext.synICEventPage, 0, sizeof(void *) * MAX_NUM_CPUS); |
239 | memset(gHvContext.synICMessagePage, 0, sizeof(void *) * MAX_NUM_CPUS); | |
3e7ee490 HJ |
240 | |
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(); | |
454f18a9 | 250 | /* HvQueryHypervisorFeatures(maxLeaf); */ |
3e7ee490 | 251 | |
454f18a9 | 252 | /* Determine if we are running on xenlinux (ie x2v shim) or native linux */ |
3e7ee490 HJ |
253 | gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID); |
254 | ||
255 | if (gHvContext.GuestId == 0) | |
256 | { | |
454f18a9 | 257 | /* Write our OS info */ |
3e7ee490 HJ |
258 | WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); |
259 | ||
260 | gHvContext.GuestId = HV_LINUX_GUEST_ID; | |
261 | } | |
262 | ||
454f18a9 | 263 | /* See if the hypercall page is already set */ |
3e7ee490 HJ |
264 | hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL); |
265 | ||
266 | if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | |
267 | { | |
454f18a9 BP |
268 | /* Allocate the hypercall page memory */ |
269 | /* virtAddr = PageAlloc(1); */ | |
3e7ee490 HJ |
270 | 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; | |
454f18a9 | 279 | /* hypercallMsr.GuestPhysicalAddress = Logical2PhysicalAddr(virtAddr) >> PAGE_SHIFT; */ |
3e7ee490 HJ |
280 | hypercallMsr.GuestPhysicalAddress = Virtual2Physical(virtAddr) >> PAGE_SHIFT; |
281 | WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | |
282 | ||
454f18a9 | 283 | /* Confirm that hypercall page did get setup. */ |
3e7ee490 HJ |
284 | 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 | ||
2701f686 GKH |
301 | DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx", |
302 | gHvContext.HypercallPage, | |
303 | (u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT); | |
3e7ee490 | 304 | |
454f18a9 | 305 | /* Setup the global signal event param for the signal event hypercall */ |
e40d37cc | 306 | gHvContext.SignalEventBuffer = kmalloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER), GFP_KERNEL); |
3e7ee490 HJ |
307 | if (!gHvContext.SignalEventBuffer) |
308 | { | |
309 | goto Cleanup; | |
310 | } | |
311 | ||
c4b0bc94 | 312 | gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((unsigned long)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN)); |
4d643114 | 313 | gHvContext.SignalEventParam->ConnectionId.Asu32 = 0; |
3e7ee490 HJ |
314 | gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID; |
315 | gHvContext.SignalEventParam->FlagNumber = 0; | |
316 | gHvContext.SignalEventParam->RsvdZ = 0; | |
317 | ||
454f18a9 | 318 | /* DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); */ |
3e7ee490 HJ |
319 | |
320 | DPRINT_EXIT(VMBUS); | |
321 | ||
322 | return ret; | |
323 | ||
324 | Cleanup: | |
325 | if (virtAddr) | |
326 | { | |
327 | if (hypercallMsr.Enable) | |
328 | { | |
329 | hypercallMsr.AsUINT64 = 0; | |
330 | WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | |
331 | } | |
332 | ||
333 | VirtualFree(virtAddr); | |
334 | } | |
335 | ret = -1; | |
336 | DPRINT_EXIT(VMBUS); | |
337 | ||
338 | return ret; | |
339 | } | |
340 | ||
341 | ||
342 | /*++ | |
343 | ||
344 | Name: | |
345 | HvCleanup() | |
346 | ||
347 | Description: | |
348 | Cleanup routine. This routine is called normally during driver unloading or exiting. | |
349 | ||
350 | --*/ | |
bd1de709 | 351 | static void |
3e7ee490 HJ |
352 | HvCleanup ( |
353 | void | |
354 | ) | |
355 | { | |
356 | HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; | |
357 | ||
358 | DPRINT_ENTER(VMBUS); | |
359 | ||
360 | if (gHvContext.SignalEventBuffer) | |
361 | { | |
8c69f52a | 362 | kfree(gHvContext.SignalEventBuffer); |
3e7ee490 HJ |
363 | 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); | |
373 | VirtualFree(gHvContext.HypercallPage); | |
374 | gHvContext.HypercallPage = NULL; | |
375 | } | |
376 | } | |
377 | ||
378 | DPRINT_EXIT(VMBUS); | |
379 | ||
380 | } | |
381 | ||
382 | ||
383 | /*++ | |
384 | ||
385 | Name: | |
386 | HvPostMessage() | |
387 | ||
388 | Description: | |
389 | Post a message using the hypervisor message IPC. This | |
390 | involves a hypercall. | |
391 | ||
392 | --*/ | |
bd1de709 | 393 | static HV_STATUS |
3e7ee490 HJ |
394 | HvPostMessage( |
395 | HV_CONNECTION_ID connectionId, | |
396 | HV_MESSAGE_TYPE messageType, | |
8282c400 | 397 | void * payload, |
45635d97 | 398 | size_t payloadSize |
3e7ee490 HJ |
399 | ) |
400 | { | |
401 | struct alignedInput { | |
59471438 | 402 | u64 alignment8; |
3e7ee490 HJ |
403 | HV_INPUT_POST_MESSAGE msg; |
404 | }; | |
405 | ||
406 | PHV_INPUT_POST_MESSAGE alignedMsg; | |
407 | HV_STATUS status; | |
c4b0bc94 | 408 | unsigned long addr; |
3e7ee490 HJ |
409 | |
410 | if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT) | |
411 | { | |
412 | return -1; | |
413 | } | |
414 | ||
0a72f3cf | 415 | addr = (unsigned long)kmalloc(sizeof(struct alignedInput), GFP_ATOMIC); |
3e7ee490 HJ |
416 | |
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 | ||
429 | status = HvDoHypercall(HvCallPostMessage, alignedMsg, 0) & 0xFFFF; | |
430 | ||
8c69f52a | 431 | kfree((void*)addr); |
3e7ee490 HJ |
432 | |
433 | return status; | |
434 | } | |
435 | ||
436 | ||
437 | /*++ | |
438 | ||
439 | Name: | |
440 | HvSignalEvent() | |
441 | ||
442 | Description: | |
443 | Signal an event on the specified connection using the hypervisor event IPC. This | |
444 | involves a hypercall. | |
445 | ||
446 | --*/ | |
bd1de709 | 447 | static HV_STATUS |
12772906 | 448 | HvSignalEvent(void) |
3e7ee490 HJ |
449 | { |
450 | HV_STATUS status; | |
451 | ||
452 | status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, 0) & 0xFFFF; | |
453 | ||
454 | return status; | |
455 | } | |
456 | ||
457 | ||
458 | /*++ | |
459 | ||
460 | Name: | |
461 | HvSynicInit() | |
462 | ||
463 | Description: | |
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 | --*/ | |
bd1de709 | 469 | static int |
3e7ee490 | 470 | HvSynicInit ( |
4d643114 | 471 | u32 irqVector |
3e7ee490 HJ |
472 | ) |
473 | { | |
59471438 | 474 | u64 version; |
3e7ee490 HJ |
475 | HV_SYNIC_SIMP simp; |
476 | HV_SYNIC_SIEFP siefp; | |
477 | HV_SYNIC_SINT sharedSint; | |
478 | HV_SYNIC_SCONTROL sctrl; | |
59471438 | 479 | u64 guestID; |
3e7ee490 HJ |
480 | int ret=0; |
481 | ||
482 | DPRINT_ENTER(VMBUS); | |
483 | ||
484 | if (!gHvContext.HypercallPage) | |
485 | { | |
486 | DPRINT_EXIT(VMBUS); | |
487 | return ret; | |
488 | } | |
489 | ||
454f18a9 | 490 | /* Check the version */ |
3e7ee490 HJ |
491 | version = ReadMsr(HV_X64_MSR_SVERSION); |
492 | ||
493 | DPRINT_INFO(VMBUS, "SynIC version: %llx", version); | |
494 | ||
454f18a9 | 495 | /* TODO: Handle SMP */ |
3e7ee490 HJ |
496 | 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 | ||
454f18a9 | 505 | /* Determine if we are running on xenlinux (ie x2v shim) or native linux */ |
3e7ee490 HJ |
506 | 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 | ||
454f18a9 | 536 | /* Setup the Synic's message page */ |
3e7ee490 HJ |
537 | 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 | ||
454f18a9 | 545 | /* Setup the Synic's event page */ |
3e7ee490 HJ |
546 | 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 | } | |
454f18a9 BP |
554 | /* Setup the interception SINT. */ |
555 | /* WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */ | |
556 | /* interceptionSint.AsUINT64); */ | |
557 | ||
558 | /* Setup the shared SINT. */ | |
3e7ee490 HJ |
559 | sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT); |
560 | ||
561 | sharedSint.AsUINT64 = 0; | |
454f18a9 BP |
562 | sharedSint.Vector = irqVector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */ |
563 | sharedSint.Masked = false; | |
564 | sharedSint.AutoEoi = true; | |
3e7ee490 HJ |
565 | |
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 | ||
454f18a9 | 570 | /* Enable the global synic bit */ |
3e7ee490 HJ |
571 | sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL); |
572 | sctrl.Enable = 1; | |
573 | ||
454f18a9 | 574 | WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64); |
3e7ee490 | 575 | |
0e727613 | 576 | gHvContext.SynICInitialized = true; |
3e7ee490 HJ |
577 | |
578 | DPRINT_EXIT(VMBUS); | |
579 | ||
580 | return ret; | |
581 | ||
582 | Cleanup: | |
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 | ||
606 | Name: | |
607 | HvSynicCleanup() | |
608 | ||
609 | Description: | |
610 | Cleanup routine for HvSynicInit(). | |
611 | ||
612 | --*/ | |
bd1de709 | 613 | static void |
3e7ee490 | 614 | HvSynicCleanup( |
e20f683b | 615 | void |
3e7ee490 HJ |
616 | ) |
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 | ||
454f18a9 | 634 | /* Disable the interrupt */ |
3e7ee490 HJ |
635 | WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); |
636 | ||
454f18a9 BP |
637 | /* |
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 | */ | |
3e7ee490 HJ |
642 | 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 | ||
454f18a9 | 664 | /* eof */ |