]>
Commit | Line | Data |
---|---|---|
3bb56c06 OM |
1 | /** @file\r |
2 | \r | |
3 | This driver produces Virtio Device Protocol instances for Virtio PCI devices.\r | |
4 | \r | |
5 | Copyright (C) 2012, Red Hat, Inc.\r | |
6 | Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r | |
7 | Copyright (C) 2013, ARM Ltd.\r | |
8 | \r | |
9 | This program and the accompanying materials are licensed and made available\r | |
10 | under the terms and conditions of the BSD License which accompanies this\r | |
11 | distribution. The full text of the license may be found at\r | |
12 | http://opensource.org/licenses/bsd-license.php\r | |
13 | \r | |
14 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r | |
15 | WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
16 | \r | |
17 | **/\r | |
18 | \r | |
19 | #include <IndustryStandard/Pci.h>\r | |
20 | #include <Library/BaseMemoryLib.h>\r | |
21 | #include <Library/DebugLib.h>\r | |
22 | #include <Library/MemoryAllocationLib.h>\r | |
23 | #include <Library/UefiBootServicesTableLib.h>\r | |
24 | #include <Library/UefiLib.h>\r | |
25 | \r | |
26 | #include "VirtioPciDevice.h"\r | |
27 | \r | |
28 | STATIC VIRTIO_DEVICE_PROTOCOL mDeviceProtocolTemplate = {\r | |
29 | 0, // Revision\r | |
30 | 0, // SubSystemDeviceId\r | |
31 | VirtioPciGetDeviceFeatures, // GetDeviceFeatures\r | |
32 | VirtioPciSetGuestFeatures, // SetGuestFeatures\r | |
33 | VirtioPciGetQueueAddress, // GetQueueAddress\r | |
34 | VirtioPciSetQueueAddress, // SetQueueAddress\r | |
35 | VirtioPciSetQueueSel, // SetQueueSel\r | |
36 | VirtioPciSetQueueNotify, // SetQueueNotify\r | |
37 | VirtioPciSetQueueAlignment, // SetQueueAlignment\r | |
38 | VirtioPciSetPageSize, // SetPageSize\r | |
39 | VirtioPciGetQueueSize, // GetQueueNumMax\r | |
40 | VirtioPciSetQueueSize, // SetQueueNum\r | |
41 | VirtioPciGetDeviceStatus, // GetDeviceStatus\r | |
42 | VirtioPciSetDeviceStatus, // SetDeviceStatus\r | |
43 | VirtioPciDeviceWrite, // WriteDevice\r | |
44 | VirtioPciDeviceRead // ReadDevice\r | |
45 | };\r | |
46 | \r | |
47 | /**\r | |
48 | \r | |
49 | Read a word from Region 0 of the device specified by PciIo.\r | |
50 | \r | |
51 | Region 0 must be an iomem region. This is an internal function for the PCI\r | |
52 | implementation of the protocol.\r | |
53 | \r | |
54 | @param[in] Dev Virtio PCI device.\r | |
55 | \r | |
56 | @param[in] FieldOffset Source offset.\r | |
57 | \r | |
58 | @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.\r | |
59 | \r | |
60 | @param[in] BufferSize Number of bytes available in the target buffer. Must\r | |
61 | equal FieldSize.\r | |
62 | \r | |
63 | @param[out] Buffer Target buffer.\r | |
64 | \r | |
65 | \r | |
66 | @return Status code returned by PciIo->Io.Read().\r | |
67 | \r | |
68 | **/\r | |
69 | EFI_STATUS\r | |
70 | EFIAPI\r | |
71 | VirtioPciIoRead (\r | |
72 | IN VIRTIO_PCI_DEVICE *Dev,\r | |
73 | IN UINTN FieldOffset,\r | |
74 | IN UINTN FieldSize,\r | |
75 | IN UINTN BufferSize,\r | |
76 | OUT VOID *Buffer\r | |
77 | )\r | |
78 | {\r | |
79 | UINTN Count;\r | |
80 | EFI_PCI_IO_PROTOCOL_WIDTH Width;\r | |
81 | EFI_PCI_IO_PROTOCOL *PciIo;\r | |
82 | \r | |
83 | ASSERT (FieldSize == BufferSize);\r | |
84 | \r | |
85 | PciIo = Dev->PciIo;\r | |
86 | Count = 1;\r | |
87 | \r | |
88 | switch (FieldSize) {\r | |
89 | case 1:\r | |
90 | Width = EfiPciIoWidthUint8;\r | |
91 | break;\r | |
92 | \r | |
93 | case 2:\r | |
94 | Width = EfiPciIoWidthUint16;\r | |
95 | break;\r | |
96 | \r | |
97 | case 8:\r | |
98 | //\r | |
99 | // The 64bit PCI I/O is broken down into two 32bit reads to prevent\r | |
100 | // any alignment or width issues.\r | |
101 | // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():\r | |
102 | //\r | |
103 | // The I/O operations are carried out exactly as requested. The caller\r | |
104 | // is responsible for any alignment and I/O width issues which the\r | |
105 | // bus, device, platform, or type of I/O might require. For example on\r | |
106 | // some platforms, width requests of EfiPciIoWidthUint64 do not work.\r | |
107 | //\r | |
108 | Count = 2;\r | |
109 | \r | |
110 | //\r | |
111 | // fall through\r | |
112 | //\r | |
113 | case 4:\r | |
114 | Width = EfiPciIoWidthUint32;\r | |
115 | break;\r | |
116 | \r | |
117 | default:\r | |
118 | ASSERT (FALSE);\r | |
119 | return EFI_INVALID_PARAMETER;\r | |
120 | }\r | |
121 | \r | |
122 | return PciIo->Io.Read (\r | |
123 | PciIo,\r | |
124 | Width,\r | |
125 | PCI_BAR_IDX0,\r | |
126 | FieldOffset,\r | |
127 | Count,\r | |
128 | Buffer\r | |
129 | );\r | |
130 | }\r | |
131 | \r | |
132 | /**\r | |
133 | \r | |
134 | Write a word into Region 0 of the device specified by PciIo.\r | |
135 | \r | |
136 | Region 0 must be an iomem region. This is an internal function for the PCI\r | |
137 | implementation of the protocol.\r | |
138 | \r | |
139 | @param[in] Dev Virtio PCI device.\r | |
140 | \r | |
141 | @param[in] FieldOffset Destination offset.\r | |
142 | \r | |
143 | @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.\r | |
144 | \r | |
145 | @param[in] Value Little endian value to write, converted to UINT64.\r | |
146 | The least significant FieldSize bytes will be used.\r | |
147 | \r | |
148 | \r | |
149 | @return Status code returned by PciIo->Io.Write().\r | |
150 | \r | |
151 | **/\r | |
152 | EFI_STATUS\r | |
153 | EFIAPI\r | |
154 | VirtioPciIoWrite (\r | |
155 | IN VIRTIO_PCI_DEVICE *Dev,\r | |
156 | IN UINTN FieldOffset,\r | |
157 | IN UINTN FieldSize,\r | |
158 | IN UINT64 Value\r | |
159 | )\r | |
160 | {\r | |
161 | UINTN Count;\r | |
162 | EFI_PCI_IO_PROTOCOL_WIDTH Width;\r | |
163 | EFI_PCI_IO_PROTOCOL *PciIo;\r | |
164 | \r | |
165 | PciIo = Dev->PciIo;\r | |
166 | Count = 1;\r | |
167 | \r | |
168 | switch (FieldSize) {\r | |
169 | case 1:\r | |
170 | Width = EfiPciIoWidthUint8;\r | |
171 | break;\r | |
172 | \r | |
173 | case 2:\r | |
174 | Width = EfiPciIoWidthUint16;\r | |
175 | break;\r | |
176 | \r | |
177 | case 8:\r | |
178 | //\r | |
179 | // The 64bit PCI I/O is broken down into two 32bit writes to prevent\r | |
180 | // any alignment or width issues.\r | |
181 | // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():\r | |
182 | //\r | |
183 | // The I/O operations are carried out exactly as requested. The caller\r | |
184 | // is responsible for any alignment and I/O width issues which the\r | |
185 | // bus, device, platform, or type of I/O might require. For example on\r | |
186 | // some platforms, width requests of EfiPciIoWidthUint64 do not work\r | |
187 | //\r | |
188 | Count = Count * 2;\r | |
189 | \r | |
190 | //\r | |
191 | // fall through\r | |
192 | //\r | |
193 | case 4:\r | |
194 | Width = EfiPciIoWidthUint32;\r | |
195 | break;\r | |
196 | \r | |
197 | default:\r | |
198 | ASSERT (FALSE);\r | |
199 | return EFI_INVALID_PARAMETER;\r | |
200 | }\r | |
201 | \r | |
202 | return PciIo->Io.Write (\r | |
203 | PciIo,\r | |
204 | Width,\r | |
205 | PCI_BAR_IDX0,\r | |
206 | FieldOffset,\r | |
207 | Count,\r | |
208 | &Value\r | |
209 | );\r | |
210 | }\r | |
211 | \r | |
212 | /**\r | |
213 | \r | |
214 | Device probe function for this driver.\r | |
215 | \r | |
216 | The DXE core calls this function for any given device in order to see if the\r | |
217 | driver can drive the device.\r | |
218 | \r | |
219 | @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r | |
220 | incorporating this driver (independently of\r | |
221 | any device).\r | |
222 | \r | |
223 | @param[in] DeviceHandle The device to probe.\r | |
224 | \r | |
225 | @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r | |
226 | \r | |
227 | \r | |
228 | @retval EFI_SUCCESS The driver supports the device being probed.\r | |
229 | \r | |
230 | @retval EFI_UNSUPPORTED Based on virtio-pci discovery, we do not support\r | |
231 | the device.\r | |
232 | \r | |
233 | @return Error codes from the OpenProtocol() boot service or\r | |
234 | the PciIo protocol.\r | |
235 | \r | |
236 | **/\r | |
237 | STATIC\r | |
238 | EFI_STATUS\r | |
239 | EFIAPI\r | |
240 | VirtioPciDeviceBindingSupported (\r | |
241 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r | |
242 | IN EFI_HANDLE DeviceHandle,\r | |
243 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r | |
244 | )\r | |
245 | {\r | |
246 | EFI_STATUS Status;\r | |
247 | EFI_PCI_IO_PROTOCOL *PciIo;\r | |
248 | PCI_TYPE00 Pci;\r | |
249 | \r | |
250 | //\r | |
251 | // Attempt to open the device with the PciIo set of interfaces. On success,\r | |
252 | // the protocol is "instantiated" for the PCI device. Covers duplicate open\r | |
253 | // attempts (EFI_ALREADY_STARTED).\r | |
254 | //\r | |
255 | Status = gBS->OpenProtocol (\r | |
256 | DeviceHandle, // candidate device\r | |
257 | &gEfiPciIoProtocolGuid, // for generic PCI access\r | |
258 | (VOID **)&PciIo, // handle to instantiate\r | |
259 | This->DriverBindingHandle, // requestor driver identity\r | |
260 | DeviceHandle, // ControllerHandle, according to\r | |
261 | // the UEFI Driver Model\r | |
262 | EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to\r | |
263 | // the device; to be released\r | |
264 | );\r | |
265 | if (EFI_ERROR (Status)) {\r | |
266 | return Status;\r | |
267 | }\r | |
268 | \r | |
269 | //\r | |
270 | // Read entire PCI configuration header for more extensive check ahead.\r | |
271 | //\r | |
272 | Status = PciIo->Pci.Read (\r | |
273 | PciIo, // (protocol, device)\r | |
274 | // handle\r | |
275 | EfiPciIoWidthUint32, // access width & copy\r | |
276 | // mode\r | |
277 | 0, // Offset\r | |
278 | sizeof Pci / sizeof (UINT32), // Count\r | |
279 | &Pci // target buffer\r | |
280 | );\r | |
281 | \r | |
282 | if (Status == EFI_SUCCESS) {\r | |
283 | //\r | |
284 | // virtio-0.9.5, 2.1 PCI Discovery\r | |
285 | //\r | |
286 | if ((Pci.Hdr.VendorId == VIRTIO_VENDOR_ID) &&\r | |
287 | (Pci.Hdr.DeviceId >= 0x1000) &&\r | |
288 | (Pci.Hdr.DeviceId <= 0x103F) &&\r | |
289 | (Pci.Hdr.RevisionID == 0x00)) {\r | |
290 | Status = EFI_SUCCESS;\r | |
291 | } else {\r | |
292 | Status = EFI_UNSUPPORTED;\r | |
293 | }\r | |
294 | }\r | |
295 | \r | |
296 | //\r | |
297 | // We needed PCI IO access only transitorily, to see whether we support the\r | |
298 | // device or not.\r | |
299 | //\r | |
300 | gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r | |
301 | This->DriverBindingHandle, DeviceHandle);\r | |
302 | \r | |
303 | return Status;\r | |
304 | }\r | |
305 | \r | |
306 | /**\r | |
307 | \r | |
308 | Initialize the VirtIo PCI Device\r | |
309 | \r | |
310 | @param[in, out] Dev The driver instance to configure. The caller is\r | |
311 | responsible for Device->PciIo's validity (ie. working IO\r | |
312 | access to the underlying virtio-pci device).\r | |
313 | \r | |
314 | @retval EFI_SUCCESS Setup complete.\r | |
315 | \r | |
316 | @retval EFI_UNSUPPORTED The underlying IO device doesn't support the\r | |
317 | provided address offset and read size.\r | |
318 | \r | |
319 | @return Error codes from PciIo->Pci.Read().\r | |
320 | \r | |
321 | **/\r | |
322 | STATIC\r | |
323 | EFI_STATUS\r | |
324 | EFIAPI\r | |
325 | VirtioPciInit (\r | |
326 | IN OUT VIRTIO_PCI_DEVICE *Device\r | |
327 | )\r | |
328 | {\r | |
329 | EFI_STATUS Status;\r | |
330 | EFI_PCI_IO_PROTOCOL *PciIo;\r | |
331 | PCI_TYPE00 Pci;\r | |
332 | \r | |
333 | ASSERT (Device != NULL);\r | |
334 | PciIo = Device->PciIo;\r | |
335 | ASSERT (PciIo != NULL);\r | |
336 | ASSERT (PciIo->Pci.Read != NULL);\r | |
337 | \r | |
338 | Status = PciIo->Pci.Read (\r | |
339 | PciIo, // (protocol, device)\r | |
340 | // handle\r | |
341 | EfiPciIoWidthUint32, // access width & copy\r | |
342 | // mode\r | |
343 | 0, // Offset\r | |
344 | sizeof (Pci) / sizeof (UINT32), // Count\r | |
345 | &Pci // target buffer\r | |
346 | );\r | |
347 | if (EFI_ERROR (Status)) {\r | |
348 | return Status;\r | |
349 | }\r | |
350 | \r | |
351 | //\r | |
352 | // Copy protocol template\r | |
353 | //\r | |
354 | CopyMem (&Device->VirtioDevice, &mDeviceProtocolTemplate,\r | |
355 | sizeof (VIRTIO_DEVICE_PROTOCOL));\r | |
356 | \r | |
357 | //\r | |
358 | // Initialize the protocol interface attributes\r | |
359 | //\r | |
360 | Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5);\r | |
361 | Device->VirtioDevice.SubSystemDeviceId = Pci.Device.SubsystemID;\r | |
362 | \r | |
363 | //\r | |
364 | // Note: We don't support the MSI-X capability. If we did,\r | |
365 | // the offset would become 24 after enabling MSI-X.\r | |
366 | //\r | |
367 | Device->DeviceSpecificConfigurationOffset =\r | |
368 | VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI;\r | |
369 | \r | |
370 | return EFI_SUCCESS;\r | |
371 | }\r | |
372 | \r | |
373 | /**\r | |
374 | \r | |
375 | Uninitialize the internals of a virtio-pci device that has been successfully\r | |
376 | set up with VirtioPciInit().\r | |
377 | \r | |
378 | @param[in, out] Dev The device to clean up.\r | |
379 | \r | |
380 | **/\r | |
381 | \r | |
382 | STATIC\r | |
383 | VOID\r | |
384 | EFIAPI\r | |
385 | VirtioPciUninit (\r | |
386 | IN OUT VIRTIO_PCI_DEVICE *Device\r | |
387 | )\r | |
388 | {\r | |
389 | // Note: This function mirrors VirtioPciInit() that does not allocate any\r | |
390 | // resources - there's nothing to free here.\r | |
391 | }\r | |
392 | \r | |
393 | /**\r | |
394 | \r | |
395 | After we've pronounced support for a specific device in\r | |
396 | DriverBindingSupported(), we start managing said device (passed in by the\r | |
397 | Driver Exeuction Environment) with the following service.\r | |
398 | \r | |
399 | See DriverBindingSupported() for specification references.\r | |
400 | \r | |
401 | @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r | |
402 | incorporating this driver (independently of\r | |
403 | any device).\r | |
404 | \r | |
405 | @param[in] DeviceHandle The supported device to drive.\r | |
406 | \r | |
407 | @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r | |
408 | \r | |
409 | \r | |
410 | @retval EFI_SUCCESS Driver instance has been created and\r | |
411 | initialized for the virtio-pci device, it\r | |
412 | is now accessible via VIRTIO_DEVICE_PROTOCOL.\r | |
413 | \r | |
414 | @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r | |
415 | \r | |
416 | @return Error codes from the OpenProtocol() boot\r | |
417 | service, the PciIo protocol, VirtioPciInit(),\r | |
418 | or the InstallProtocolInterface() boot service.\r | |
419 | \r | |
420 | **/\r | |
421 | STATIC\r | |
422 | EFI_STATUS\r | |
423 | EFIAPI\r | |
424 | VirtioPciDeviceBindingStart (\r | |
425 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r | |
426 | IN EFI_HANDLE DeviceHandle,\r | |
427 | IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r | |
428 | )\r | |
429 | {\r | |
430 | VIRTIO_PCI_DEVICE *Device;\r | |
431 | EFI_STATUS Status;\r | |
432 | \r | |
433 | Device = (VIRTIO_PCI_DEVICE *) AllocateZeroPool (sizeof *Device);\r | |
434 | if (Device == NULL) {\r | |
435 | return EFI_OUT_OF_RESOURCES;\r | |
436 | }\r | |
437 | \r | |
438 | Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r | |
439 | (VOID **)&Device->PciIo, This->DriverBindingHandle,\r | |
440 | DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);\r | |
441 | if (EFI_ERROR (Status)) {\r | |
442 | goto FreeVirtioPci;\r | |
443 | }\r | |
444 | \r | |
445 | //\r | |
446 | // We must retain and ultimately restore the original PCI attributes of the\r | |
447 | // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /\r | |
448 | // 18.3.2 Start() and Stop().\r | |
449 | //\r | |
450 | // The third parameter ("Attributes", input) is ignored by the Get operation.\r | |
451 | // The fourth parameter ("Result", output) is ignored by the Enable and Set\r | |
452 | // operations.\r | |
453 | //\r | |
454 | // For virtio-pci we only need IO space access.\r | |
455 | //\r | |
456 | Status = Device->PciIo->Attributes (Device->PciIo,\r | |
457 | EfiPciIoAttributeOperationGet, 0, &Device->OriginalPciAttributes);\r | |
458 | if (EFI_ERROR (Status)) {\r | |
459 | goto ClosePciIo;\r | |
460 | }\r | |
461 | \r | |
462 | Status = Device->PciIo->Attributes (Device->PciIo,\r | |
463 | EfiPciIoAttributeOperationEnable,\r | |
464 | EFI_PCI_IO_ATTRIBUTE_IO, NULL);\r | |
465 | if (EFI_ERROR (Status)) {\r | |
466 | goto ClosePciIo;\r | |
467 | }\r | |
468 | \r | |
469 | //\r | |
470 | // PCI IO access granted, configure protocol instance\r | |
471 | //\r | |
472 | \r | |
473 | Status = VirtioPciInit (Device);\r | |
474 | if (EFI_ERROR (Status)) {\r | |
475 | goto RestorePciAttributes;\r | |
476 | }\r | |
477 | \r | |
478 | //\r | |
479 | // Setup complete, attempt to export the driver instance's VirtioDevice\r | |
480 | // interface.\r | |
481 | //\r | |
482 | Device->Signature = VIRTIO_PCI_DEVICE_SIGNATURE;\r | |
483 | Status = gBS->InstallProtocolInterface (&DeviceHandle,\r | |
484 | &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE,\r | |
485 | &Device->VirtioDevice);\r | |
486 | if (EFI_ERROR (Status)) {\r | |
487 | goto UninitDev;\r | |
488 | }\r | |
489 | \r | |
490 | return EFI_SUCCESS;\r | |
491 | \r | |
492 | UninitDev:\r | |
493 | VirtioPciUninit (Device);\r | |
494 | \r | |
495 | RestorePciAttributes:\r | |
496 | Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,\r | |
497 | Device->OriginalPciAttributes, NULL);\r | |
498 | \r | |
499 | ClosePciIo:\r | |
500 | gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r | |
501 | This->DriverBindingHandle, DeviceHandle);\r | |
502 | \r | |
503 | FreeVirtioPci:\r | |
504 | FreePool (Device);\r | |
505 | \r | |
506 | return Status;\r | |
507 | }\r | |
508 | \r | |
509 | /**\r | |
510 | \r | |
511 | Stop driving the Virtio PCI device\r | |
512 | \r | |
513 | @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r | |
514 | incorporating this driver (independently of any\r | |
515 | device).\r | |
516 | \r | |
517 | @param[in] DeviceHandle Stop driving this device.\r | |
518 | \r | |
519 | @param[in] NumberOfChildren Since this function belongs to a device driver\r | |
520 | only (as opposed to a bus driver), the caller\r | |
521 | environment sets NumberOfChildren to zero, and\r | |
522 | we ignore it.\r | |
523 | \r | |
524 | @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren).\r | |
525 | \r | |
526 | @retval EFI_SUCCESS Driver instance has been stopped and the PCI\r | |
527 | configuration attributes have been restored.\r | |
528 | \r | |
529 | @return Error codes from the OpenProtocol() or\r | |
530 | CloseProtocol(), UninstallProtocolInterface()\r | |
531 | boot services.\r | |
532 | \r | |
533 | **/\r | |
534 | STATIC\r | |
535 | EFI_STATUS\r | |
536 | EFIAPI\r | |
537 | VirtioPciDeviceBindingStop (\r | |
538 | IN EFI_DRIVER_BINDING_PROTOCOL *This,\r | |
539 | IN EFI_HANDLE DeviceHandle,\r | |
540 | IN UINTN NumberOfChildren,\r | |
541 | IN EFI_HANDLE *ChildHandleBuffer\r | |
542 | )\r | |
543 | {\r | |
544 | EFI_STATUS Status;\r | |
545 | VIRTIO_DEVICE_PROTOCOL *VirtioDevice;\r | |
546 | VIRTIO_PCI_DEVICE *Device;\r | |
547 | \r | |
548 | Status = gBS->OpenProtocol (\r | |
549 | DeviceHandle, // candidate device\r | |
550 | &gVirtioDeviceProtocolGuid, // retrieve the VirtIo iface\r | |
551 | (VOID **)&VirtioDevice, // target pointer\r | |
552 | This->DriverBindingHandle, // requestor driver identity\r | |
553 | DeviceHandle, // requesting lookup for dev.\r | |
554 | EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added\r | |
555 | );\r | |
556 | if (EFI_ERROR (Status)) {\r | |
557 | return Status;\r | |
558 | }\r | |
559 | \r | |
560 | Device = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice);\r | |
561 | \r | |
562 | //\r | |
563 | // Handle Stop() requests for in-use driver instances gracefully.\r | |
564 | //\r | |
565 | Status = gBS->UninstallProtocolInterface (DeviceHandle,\r | |
566 | &gVirtioDeviceProtocolGuid, &Device->VirtioDevice);\r | |
567 | if (EFI_ERROR (Status)) {\r | |
568 | return Status;\r | |
569 | }\r | |
570 | \r | |
571 | VirtioPciUninit (Device);\r | |
572 | \r | |
573 | Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,\r | |
574 | Device->OriginalPciAttributes, NULL);\r | |
575 | \r | |
576 | Status = gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r | |
577 | This->DriverBindingHandle, DeviceHandle);\r | |
578 | \r | |
579 | FreePool (Device);\r | |
580 | \r | |
581 | return Status;\r | |
582 | }\r | |
583 | \r | |
584 | \r | |
585 | //\r | |
586 | // The static object that groups the Supported() (ie. probe), Start() and\r | |
587 | // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata\r | |
588 | // C, 10.1 EFI Driver Binding Protocol.\r | |
589 | //\r | |
590 | STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r | |
591 | &VirtioPciDeviceBindingSupported,\r | |
592 | &VirtioPciDeviceBindingStart,\r | |
593 | &VirtioPciDeviceBindingStop,\r | |
594 | 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers\r | |
595 | NULL, // ImageHandle, to be overwritten by\r | |
596 | // EfiLibInstallDriverBindingComponentName2() in VirtioPciEntryPoint()\r | |
597 | NULL // DriverBindingHandle, ditto\r | |
598 | };\r | |
599 | \r | |
600 | \r | |
601 | //\r | |
602 | // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and\r | |
603 | // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name\r | |
604 | // in English, for display on standard console devices. This is recommended for\r | |
605 | // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's\r | |
606 | // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.\r | |
607 | //\r | |
608 | STATIC\r | |
609 | EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r | |
610 | { "eng;en", L"Virtio PCI Driver" },\r | |
611 | { NULL, NULL }\r | |
612 | };\r | |
613 | \r | |
614 | STATIC\r | |
615 | EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r | |
616 | \r | |
617 | EFI_STATUS\r | |
618 | EFIAPI\r | |
619 | VirtioPciGetDriverName (\r | |
620 | IN EFI_COMPONENT_NAME_PROTOCOL *This,\r | |
621 | IN CHAR8 *Language,\r | |
622 | OUT CHAR16 **DriverName\r | |
623 | )\r | |
624 | {\r | |
625 | return LookupUnicodeString2 (\r | |
626 | Language,\r | |
627 | This->SupportedLanguages,\r | |
628 | mDriverNameTable,\r | |
629 | DriverName,\r | |
630 | (BOOLEAN)(This == &gComponentName) // Iso639Language\r | |
631 | );\r | |
632 | }\r | |
633 | \r | |
634 | EFI_STATUS\r | |
635 | EFIAPI\r | |
636 | VirtioPciGetDeviceName (\r | |
637 | IN EFI_COMPONENT_NAME_PROTOCOL *This,\r | |
638 | IN EFI_HANDLE DeviceHandle,\r | |
639 | IN EFI_HANDLE ChildHandle,\r | |
640 | IN CHAR8 *Language,\r | |
641 | OUT CHAR16 **ControllerName\r | |
642 | )\r | |
643 | {\r | |
644 | return EFI_UNSUPPORTED;\r | |
645 | }\r | |
646 | \r | |
647 | STATIC\r | |
648 | EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r | |
649 | &VirtioPciGetDriverName,\r | |
650 | &VirtioPciGetDeviceName,\r | |
651 | "eng" // SupportedLanguages, ISO 639-2 language codes\r | |
652 | };\r | |
653 | \r | |
654 | STATIC\r | |
655 | EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r | |
656 | (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &VirtioPciGetDriverName,\r | |
657 | (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioPciGetDeviceName,\r | |
658 | "en" // SupportedLanguages, RFC 4646 language codes\r | |
659 | };\r | |
660 | \r | |
661 | \r | |
662 | //\r | |
663 | // Entry point of this driver.\r | |
664 | //\r | |
665 | EFI_STATUS\r | |
666 | EFIAPI\r | |
667 | VirtioPciDeviceEntryPoint (\r | |
668 | IN EFI_HANDLE ImageHandle,\r | |
669 | IN EFI_SYSTEM_TABLE *SystemTable\r | |
670 | )\r | |
671 | {\r | |
672 | return EfiLibInstallDriverBindingComponentName2 (\r | |
673 | ImageHandle,\r | |
674 | SystemTable,\r | |
675 | &gDriverBinding,\r | |
676 | ImageHandle,\r | |
677 | &gComponentName,\r | |
678 | &gComponentName2\r | |
679 | );\r | |
680 | }\r |