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