• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   A non-transitional driver for VirtIo 1.0 PCI devices.
3 
4   Copyright (C) 2016, Red Hat, Inc.
5 
6   This program and the accompanying materials are licensed and made available
7   under the terms and conditions of the BSD License which accompanies this
8   distribution. The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
12   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 **/
14 
15 #include <IndustryStandard/Pci.h>
16 #include <IndustryStandard/Virtio.h>
17 #include <Protocol/PciIo.h>
18 #include <Protocol/VirtioDevice.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/UefiLib.h>
24 
25 #include "Virtio10.h"
26 
27 
28 //
29 // Utility functions
30 //
31 
32 /**
33   Transfer data between the caller and a register in a virtio-1.0 register
34   block.
35 
36   @param[in]     PciIo        The EFI_PCI_IO_PROTOCOL instance that represents
37                               the device.
38 
39   @param[in]     Config       The "fat pointer" structure that identifies the
40                               register block to access.
41 
42   @param[in]     Write        TRUE if the register should be written, FALSE if
43                               the register should be read.
44 
45   @param[in]     FieldOffset  The offset of the register within the register
46                               block.
47 
48   @param[in]     FieldSize    The size of the register within the register
49                               block. Can be one of 1, 2, 4 and 8. Accesses to
50                               8-byte registers are broken up into two 4-byte
51                               accesses.
52 
53   @param[in,out] Buffer       When Write is TRUE, the register is written with
54                               data from Buffer. When Write is FALSE, the caller
55                               receives the register value into Buffer.
56 
57   @retval  EFI_SUCCESS            Register access successful.
58 
59   @retval  EFI_INVALID_PARAMETER  The register block pointed-to by Config
60                                   doesn't exist; or FieldOffset and FieldSize
61                                   would overflow the register block; or
62                                   FieldSize is invalid.
63 
64   @return                         Error codes from
65                                   EFI_PCI_IO_PROTOCOL.(Io|Mem).(Read|Write)
66                                   member functions.
67 **/
68 STATIC
69 EFI_STATUS
Virtio10Transfer(IN EFI_PCI_IO_PROTOCOL * PciIo,IN VIRTIO_1_0_CONFIG * Config,IN BOOLEAN Write,IN UINTN FieldOffset,IN UINTN FieldSize,IN OUT VOID * Buffer)70 Virtio10Transfer (
71   IN     EFI_PCI_IO_PROTOCOL *PciIo,
72   IN     VIRTIO_1_0_CONFIG   *Config,
73   IN     BOOLEAN             Write,
74   IN     UINTN               FieldOffset,
75   IN     UINTN               FieldSize,
76   IN OUT VOID                *Buffer
77   )
78 {
79   UINTN                      Count;
80   EFI_PCI_IO_PROTOCOL_WIDTH  Width;
81   EFI_PCI_IO_PROTOCOL_ACCESS *BarType;
82   EFI_PCI_IO_PROTOCOL_IO_MEM Access;
83 
84   if (!Config->Exists ||
85       FieldSize > Config->Length ||
86       FieldOffset > Config->Length - FieldSize) {
87     return EFI_INVALID_PARAMETER;
88   }
89 
90   Count = 1;
91   switch (FieldSize) {
92     case 1:
93       Width = EfiPciIoWidthUint8;
94       break;
95 
96     case 2:
97       Width = EfiPciIoWidthUint16;
98       break;
99 
100     case 8:
101       Count = 2;
102       //
103       // fall through
104       //
105 
106     case 4:
107       Width = EfiPciIoWidthUint32;
108       break;
109 
110     default:
111       return EFI_INVALID_PARAMETER;
112   }
113 
114   BarType = (Config->BarType == Virtio10BarTypeMem) ? &PciIo->Mem : &PciIo->Io;
115   Access = Write ? BarType->Write : BarType->Read;
116 
117   return Access (PciIo, Width, Config->Bar, Config->Offset + FieldOffset,
118            Count, Buffer);
119 }
120 
121 
122 /**
123   Determine if a PCI BAR is IO or MMIO.
124 
125   @param[in]  PciIo     The EFI_PCI_IO_PROTOCOL instance that represents the
126                         device.
127 
128   @param[in]  BarIndex  The number of the BAR whose type the caller is
129                         interested in.
130 
131   @param[out] BarType   On output, a VIRTIO_1_0_BAR_TYPE value that gives the
132                         type of the BAR.
133 
134   @retval EFI_SUCCESS      The BAR type has been recognized and stored in
135                            BarType.
136 
137   @retval EFI_UNSUPPORTED  The BAR type couldn't be identified.
138 
139   @return                  Error codes from
140                            EFI_PCI_IO_PROTOCOL.GetBarAttributes().
141 **/
142 STATIC
143 EFI_STATUS
GetBarType(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 BarIndex,OUT VIRTIO_1_0_BAR_TYPE * BarType)144 GetBarType (
145   IN  EFI_PCI_IO_PROTOCOL *PciIo,
146   IN  UINT8               BarIndex,
147   OUT VIRTIO_1_0_BAR_TYPE *BarType
148   )
149 {
150   EFI_STATUS Status;
151   VOID       *Resources;
152 
153   Status = PciIo->GetBarAttributes (PciIo, BarIndex, NULL, &Resources);
154   if (EFI_ERROR (Status)) {
155     return Status;
156   }
157 
158   Status = EFI_UNSUPPORTED;
159 
160   if (*(UINT8 *)Resources == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) {
161     EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
162 
163     Descriptor = Resources;
164     switch (Descriptor->ResType) {
165     case ACPI_ADDRESS_SPACE_TYPE_MEM:
166       *BarType = Virtio10BarTypeMem;
167       Status = EFI_SUCCESS;
168       break;
169 
170     case ACPI_ADDRESS_SPACE_TYPE_IO:
171       *BarType = Virtio10BarTypeIo;
172       Status = EFI_SUCCESS;
173       break;
174 
175     default:
176       break;
177     }
178   }
179 
180   FreePool (Resources);
181   return Status;
182 }
183 
184 
185 /**
186   Read a slice from PCI config space at the given offset, then advance the
187   offset.
188 
189   @param [in]     PciIo   The EFI_PCI_IO_PROTOCOL instance that represents the
190                           device.
191 
192   @param [in,out] Offset  On input, the offset in PCI config space to start
193                           reading from. On output, the offset of the first byte
194                           that was not read. On error, Offset is not modified.
195 
196   @param [in]     Size    The number of bytes to read.
197 
198   @param [out]    Buffer  On output, the bytes read from PCI config space are
199                           stored in this object.
200 
201   @retval EFI_SUCCESS  Size bytes have been transferred from PCI config space
202                        (from Offset) to Buffer, and Offset has been incremented
203                        by Size.
204 
205   @return              Error codes from PciIo->Pci.Read().
206 **/
207 STATIC
208 EFI_STATUS
ReadConfigSpace(IN EFI_PCI_IO_PROTOCOL * PciIo,IN OUT UINT32 * Offset,IN UINTN Size,OUT VOID * Buffer)209 ReadConfigSpace (
210   IN     EFI_PCI_IO_PROTOCOL *PciIo,
211   IN OUT UINT32              *Offset,
212   IN     UINTN               Size,
213      OUT VOID                *Buffer
214   )
215 {
216   EFI_STATUS Status;
217 
218   Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, *Offset, Size, Buffer);
219   if (EFI_ERROR (Status)) {
220     return Status;
221   }
222   *Offset += (UINT32)Size;
223   return EFI_SUCCESS;
224 }
225 
226 
227 /*
228   Traverse the PCI capabilities list of a virtio-1.0 device, and capture the
229   locations of the interesting virtio-1.0 register blocks.
230 
231   @param[in,out] Device         The VIRTIO_1_0_DEV structure that identifies
232                                 the device. On input, the caller is responsible
233                                 that the Device->PciIo member be live, and that
234                                 the CommonConfig, NotifyConfig,
235                                 NotifyOffsetMultiplier and SpecificConfig
236                                 members be zeroed. On output,  said members
237                                 will have been updated from the PCI
238                                 capabilities found.
239 
240   @param[in]     CapabilityPtr  The offset of the first capability in PCI
241                                 config space, taken from the standard PCI
242                                 device header.
243 
244   @retval EFI_SUCCESS  Traversal successful.
245 
246   @return              Error codes from the ReadConfigSpace() and GetBarType()
247                        helper functions.
248 */
249 STATIC
250 EFI_STATUS
ParseCapabilities(IN OUT VIRTIO_1_0_DEV * Device,IN UINT8 CapabilityPtr)251 ParseCapabilities (
252   IN OUT VIRTIO_1_0_DEV *Device,
253   IN     UINT8          CapabilityPtr
254   )
255 {
256   UINT32              Offset;
257   VIRTIO_PCI_CAP_LINK CapLink;
258 
259   for (Offset = CapabilityPtr & 0xFC;
260        Offset > 0;
261        Offset = CapLink.CapNext & 0xFC
262        ) {
263     EFI_STATUS        Status;
264     UINT8             CapLen;
265     VIRTIO_PCI_CAP    VirtIoCap;
266     VIRTIO_1_0_CONFIG *ParsedConfig;
267 
268     //
269     // Read capability identifier and link to next capability.
270     //
271     Status = ReadConfigSpace (Device->PciIo, &Offset, sizeof CapLink,
272                &CapLink);
273     if (EFI_ERROR (Status)) {
274       return Status;
275     }
276     if (CapLink.CapId != 0x09) {
277       //
278       // Not a vendor-specific capability, move to the next one.
279       //
280       continue;
281     }
282 
283     //
284     // Big enough to accommodate a VIRTIO_PCI_CAP structure?
285     //
286     Status = ReadConfigSpace (Device->PciIo, &Offset, sizeof CapLen, &CapLen);
287     if (EFI_ERROR (Status)) {
288       return Status;
289     }
290     if (CapLen < sizeof CapLink + sizeof CapLen + sizeof VirtIoCap) {
291       //
292       // Too small, move to next.
293       //
294       continue;
295     }
296 
297     //
298     // Read interesting part of capability.
299     //
300     Status = ReadConfigSpace (Device->PciIo, &Offset, sizeof VirtIoCap,
301                &VirtIoCap);
302     if (EFI_ERROR (Status)) {
303       return Status;
304     }
305     switch (VirtIoCap.ConfigType) {
306     case VIRTIO_PCI_CAP_COMMON_CFG:
307       ParsedConfig = &Device->CommonConfig;
308       break;
309     case VIRTIO_PCI_CAP_NOTIFY_CFG:
310       ParsedConfig = &Device->NotifyConfig;
311       break;
312     case VIRTIO_PCI_CAP_DEVICE_CFG:
313       ParsedConfig = &Device->SpecificConfig;
314       break;
315     default:
316       //
317       // Capability is not interesting.
318       //
319       continue;
320     }
321 
322     //
323     // Save the location of the register block into ParsedConfig.
324     //
325     Status = GetBarType (Device->PciIo, VirtIoCap.Bar, &ParsedConfig->BarType);
326     if (EFI_ERROR (Status)) {
327       return Status;
328     }
329     ParsedConfig->Bar    = VirtIoCap.Bar;
330     ParsedConfig->Offset = VirtIoCap.Offset;
331     ParsedConfig->Length = VirtIoCap.Length;
332 
333     if (VirtIoCap.ConfigType == VIRTIO_PCI_CAP_NOTIFY_CFG) {
334       //
335       // This capability has an additional field called NotifyOffsetMultiplier;
336       // parse it too.
337       //
338       if (CapLen < sizeof CapLink + sizeof CapLen + sizeof VirtIoCap +
339                    sizeof Device->NotifyOffsetMultiplier) {
340         //
341         // Too small, move to next.
342         //
343         continue;
344       }
345 
346       Status = ReadConfigSpace (Device->PciIo, &Offset,
347                  sizeof Device->NotifyOffsetMultiplier,
348                  &Device->NotifyOffsetMultiplier);
349       if (EFI_ERROR (Status)) {
350         return Status;
351       }
352     }
353 
354     //
355     // Capability parsed successfully.
356     //
357     ParsedConfig->Exists = TRUE;
358   }
359 
360   return EFI_SUCCESS;
361 }
362 
363 
364 /**
365   Accumulate the BAR type of a virtio-1.0 register block into a UINT64
366   attribute map, such that the latter is suitable for enabling IO / MMIO
367   decoding with EFI_PCI_IO_PROTOCOL.Attributes().
368 
369   @param[in]     Config      The "fat pointer" structure that identifies the
370                              register block. It is allowed for the register
371                              block not to exist.
372 
373   @param[in,out] Attributes  On output, if the register block exists,
374                              EFI_PCI_IO_ATTRIBUTE_MEMORY or
375                              EFI_PCI_IO_ATTRIBUTE_IO is OR-ed into Attributes,
376                              according to the register block's BAR type.
377 **/
378 STATIC
379 VOID
UpdateAttributes(IN VIRTIO_1_0_CONFIG * Config,IN OUT UINT64 * Attributes)380 UpdateAttributes (
381   IN     VIRTIO_1_0_CONFIG *Config,
382   IN OUT UINT64            *Attributes
383   )
384 {
385   if (Config->Exists) {
386     *Attributes |= (Config->BarType == Virtio10BarTypeMem) ?
387                      EFI_PCI_IO_ATTRIBUTE_MEMORY:
388                      EFI_PCI_IO_ATTRIBUTE_IO;
389   }
390 }
391 
392 
393 //
394 // VIRTIO_DEVICE_PROTOCOL member functions
395 //
396 
397 STATIC
398 EFI_STATUS
399 EFIAPI
Virtio10GetDeviceFeatures(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT64 * DeviceFeatures)400 Virtio10GetDeviceFeatures (
401   IN VIRTIO_DEVICE_PROTOCOL *This,
402   OUT UINT64                *DeviceFeatures
403   )
404 {
405   VIRTIO_1_0_DEV *Dev;
406   UINT32         Selector;
407   UINT32         Features32[2];
408 
409   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
410 
411   for (Selector = 0; Selector < 2; ++Selector) {
412     EFI_STATUS Status;
413 
414     //
415     // Select the low or high half of the features.
416     //
417     Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
418                OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeatureSelect),
419                sizeof Selector, &Selector);
420     if (EFI_ERROR (Status)) {
421       return Status;
422     }
423 
424     //
425     // Fetch that half.
426     //
427     Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
428                OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeature),
429                sizeof Features32[Selector], &Features32[Selector]);
430     if (EFI_ERROR (Status)) {
431       return Status;
432     }
433   }
434 
435   *DeviceFeatures = LShiftU64 (Features32[1], 32) | Features32[0];
436   return EFI_SUCCESS;
437 }
438 
439 
440 STATIC
441 EFI_STATUS
442 EFIAPI
Virtio10SetGuestFeatures(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT64 Features)443 Virtio10SetGuestFeatures (
444   IN VIRTIO_DEVICE_PROTOCOL  *This,
445   IN UINT64                   Features
446   )
447 {
448   VIRTIO_1_0_DEV *Dev;
449   UINT32         Selector;
450   UINT32         Features32[2];
451 
452   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
453 
454   Features32[0] = (UINT32)Features;
455   Features32[1] = (UINT32)RShiftU64 (Features, 32);
456 
457   for (Selector = 0; Selector < 2; ++Selector) {
458     EFI_STATUS Status;
459 
460     //
461     // Select the low or high half of the features.
462     //
463     Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
464                OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeatureSelect),
465                sizeof Selector, &Selector);
466     if (EFI_ERROR (Status)) {
467       return Status;
468     }
469 
470     //
471     // Write that half.
472     //
473     Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
474                OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeature),
475                sizeof Features32[Selector], &Features32[Selector]);
476     if (EFI_ERROR (Status)) {
477       return Status;
478     }
479   }
480 
481   return EFI_SUCCESS;
482 }
483 
484 
485 STATIC
486 EFI_STATUS
487 EFIAPI
Virtio10SetQueueAddress(IN VIRTIO_DEVICE_PROTOCOL * This,IN VRING * Ring)488 Virtio10SetQueueAddress (
489   IN VIRTIO_DEVICE_PROTOCOL  *This,
490   IN VRING                   *Ring
491   )
492 {
493   VIRTIO_1_0_DEV *Dev;
494   EFI_STATUS     Status;
495   UINT64         Address;
496   UINT16         Enable;
497 
498   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
499 
500   Address = (UINTN)Ring->Desc;
501   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
502              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueDesc),
503              sizeof Address, &Address);
504   if (EFI_ERROR (Status)) {
505     return Status;
506   }
507 
508   Address = (UINTN)Ring->Avail.Flags;
509   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
510              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueAvail),
511              sizeof Address, &Address);
512   if (EFI_ERROR (Status)) {
513     return Status;
514   }
515 
516   Address = (UINTN)Ring->Used.Flags;
517   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
518              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueUsed),
519              sizeof Address, &Address);
520   if (EFI_ERROR (Status)) {
521     return Status;
522   }
523 
524   Enable = 1;
525   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
526              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueEnable),
527              sizeof Enable, &Enable);
528   return Status;
529 }
530 
531 
532 STATIC
533 EFI_STATUS
534 EFIAPI
Virtio10SetQueueSel(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT16 Index)535 Virtio10SetQueueSel (
536   IN VIRTIO_DEVICE_PROTOCOL  *This,
537   IN UINT16                   Index
538   )
539 {
540   VIRTIO_1_0_DEV *Dev;
541   EFI_STATUS     Status;
542 
543   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
544 
545   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
546              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
547              sizeof Index, &Index);
548   return Status;
549 }
550 
551 
552 STATIC
553 EFI_STATUS
554 EFIAPI
Virtio10SetQueueNotify(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT16 Index)555 Virtio10SetQueueNotify (
556   IN VIRTIO_DEVICE_PROTOCOL  *This,
557   IN UINT16                   Index
558   )
559 {
560   VIRTIO_1_0_DEV *Dev;
561   EFI_STATUS     Status;
562   UINT16         SavedQueueSelect;
563   UINT16         NotifyOffset;
564 
565   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
566 
567   //
568   // Read NotifyOffset first. NotifyOffset is queue specific, so we have
569   // to stash & restore the current queue selector around it.
570   //
571   // So, start with saving the current queue selector.
572   //
573   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
574              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
575              sizeof SavedQueueSelect, &SavedQueueSelect);
576   if (EFI_ERROR (Status)) {
577     return Status;
578   }
579 
580   //
581   // Select the requested queue.
582   //
583   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
584              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
585              sizeof Index, &Index);
586   if (EFI_ERROR (Status)) {
587     return Status;
588   }
589 
590   //
591   // Read the QueueNotifyOff field.
592   //
593   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
594              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueNotifyOff),
595              sizeof NotifyOffset, &NotifyOffset);
596   if (EFI_ERROR (Status)) {
597     return Status;
598   }
599 
600   //
601   // Re-select the original queue.
602   //
603   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
604              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
605              sizeof SavedQueueSelect, &SavedQueueSelect);
606   if (EFI_ERROR (Status)) {
607     return Status;
608   }
609 
610   //
611   // We can now kick the queue.
612   //
613   Status = Virtio10Transfer (Dev->PciIo, &Dev->NotifyConfig, TRUE,
614              NotifyOffset * Dev->NotifyOffsetMultiplier,
615              sizeof Index, &Index);
616   return Status;
617 }
618 
619 
620 STATIC
621 EFI_STATUS
622 EFIAPI
Virtio10SetQueueAlign(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT32 Alignment)623 Virtio10SetQueueAlign (
624   IN VIRTIO_DEVICE_PROTOCOL  *This,
625   IN UINT32                   Alignment
626   )
627 {
628   return (Alignment == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
629 }
630 
631 
632 STATIC
633 EFI_STATUS
634 EFIAPI
Virtio10SetPageSize(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT32 PageSize)635 Virtio10SetPageSize (
636   IN VIRTIO_DEVICE_PROTOCOL  *This,
637   IN UINT32                   PageSize
638   )
639 {
640   return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
641 }
642 
643 
644 STATIC
645 EFI_STATUS
646 EFIAPI
Virtio10GetQueueNumMax(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT16 * QueueNumMax)647 Virtio10GetQueueNumMax (
648   IN  VIRTIO_DEVICE_PROTOCOL  *This,
649   OUT UINT16                  *QueueNumMax
650   )
651 {
652   VIRTIO_1_0_DEV *Dev;
653   EFI_STATUS     Status;
654 
655   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
656 
657   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
658              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSize),
659              sizeof *QueueNumMax, QueueNumMax);
660   return Status;
661 }
662 
663 
664 STATIC
665 EFI_STATUS
666 EFIAPI
Virtio10SetQueueNum(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT16 QueueSize)667 Virtio10SetQueueNum (
668   IN VIRTIO_DEVICE_PROTOCOL  *This,
669   IN UINT16                   QueueSize
670   )
671 {
672   EFI_STATUS     Status;
673   UINT16         CurrentSize;
674 
675   //
676   // This member function is required for VirtIo MMIO, and a no-op in
677   // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
678   // member to reduce memory consumption, but none of our drivers do. So
679   // just check that they set the size that is already in effect.
680   //
681   Status = Virtio10GetQueueNumMax (This, &CurrentSize);
682   if (EFI_ERROR (Status)) {
683     return Status;
684   }
685   return (CurrentSize == QueueSize) ? EFI_SUCCESS : EFI_UNSUPPORTED;
686 }
687 
688 
689 STATIC
690 EFI_STATUS
691 EFIAPI
Virtio10GetDeviceStatus(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT8 * DeviceStatus)692 Virtio10GetDeviceStatus (
693   IN  VIRTIO_DEVICE_PROTOCOL  *This,
694   OUT UINT8                   *DeviceStatus
695   )
696 {
697   VIRTIO_1_0_DEV *Dev;
698   EFI_STATUS     Status;
699 
700   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
701 
702   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
703              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
704              sizeof *DeviceStatus, DeviceStatus);
705   return Status;
706 }
707 
708 
709 STATIC
710 EFI_STATUS
711 EFIAPI
Virtio10SetDeviceStatus(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT8 DeviceStatus)712 Virtio10SetDeviceStatus (
713   IN VIRTIO_DEVICE_PROTOCOL  *This,
714   IN UINT8                   DeviceStatus
715   )
716 {
717   VIRTIO_1_0_DEV *Dev;
718   EFI_STATUS     Status;
719 
720   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
721 
722   Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
723              OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
724              sizeof DeviceStatus, &DeviceStatus);
725   return Status;
726 }
727 
728 
729 STATIC
730 EFI_STATUS
731 EFIAPI
Virtio10WriteDevice(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINT64 Value)732 Virtio10WriteDevice (
733   IN VIRTIO_DEVICE_PROTOCOL *This,
734   IN UINTN                  FieldOffset,
735   IN UINTN                  FieldSize,
736   IN UINT64                 Value
737   )
738 {
739   VIRTIO_1_0_DEV *Dev;
740   EFI_STATUS     Status;
741 
742   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
743 
744   Status = Virtio10Transfer (Dev->PciIo, &Dev->SpecificConfig, TRUE,
745              FieldOffset, FieldSize, &Value);
746   return Status;
747 }
748 
749 
750 STATIC
751 EFI_STATUS
752 EFIAPI
Virtio10ReadDevice(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINTN BufferSize,OUT VOID * Buffer)753 Virtio10ReadDevice (
754   IN  VIRTIO_DEVICE_PROTOCOL *This,
755   IN  UINTN                  FieldOffset,
756   IN  UINTN                  FieldSize,
757   IN  UINTN                  BufferSize,
758   OUT VOID                   *Buffer
759   )
760 {
761   VIRTIO_1_0_DEV *Dev;
762   EFI_STATUS     Status;
763 
764   if (FieldSize != BufferSize) {
765     return EFI_INVALID_PARAMETER;
766   }
767 
768   Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
769 
770   Status = Virtio10Transfer (Dev->PciIo, &Dev->SpecificConfig, FALSE,
771              FieldOffset, FieldSize, Buffer);
772   return Status;
773 }
774 
775 
776 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate = {
777   VIRTIO_SPEC_REVISION (1, 0, 0),
778   0,                              // SubSystemDeviceId, filled in dynamically
779   Virtio10GetDeviceFeatures,
780   Virtio10SetGuestFeatures,
781   Virtio10SetQueueAddress,
782   Virtio10SetQueueSel,
783   Virtio10SetQueueNotify,
784   Virtio10SetQueueAlign,
785   Virtio10SetPageSize,
786   Virtio10GetQueueNumMax,
787   Virtio10SetQueueNum,
788   Virtio10GetDeviceStatus,
789   Virtio10SetDeviceStatus,
790   Virtio10WriteDevice,
791   Virtio10ReadDevice
792 };
793 
794 
795 //
796 // EFI_DRIVER_BINDING_PROTOCOL member functions
797 //
798 
799 STATIC
800 EFI_STATUS
801 EFIAPI
Virtio10BindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)802 Virtio10BindingSupported (
803   IN EFI_DRIVER_BINDING_PROTOCOL *This,
804   IN EFI_HANDLE                  DeviceHandle,
805   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
806   )
807 {
808   EFI_STATUS          Status;
809   EFI_PCI_IO_PROTOCOL *PciIo;
810   PCI_TYPE00          Pci;
811 
812   Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
813                   (VOID **)&PciIo, This->DriverBindingHandle,
814                   DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
815   if (EFI_ERROR (Status)) {
816     return Status;
817   }
818 
819   Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0,
820                         sizeof Pci / sizeof (UINT32), &Pci);
821   if (EFI_ERROR (Status)) {
822     goto CloseProtocol;
823   }
824 
825   Status = EFI_UNSUPPORTED;
826   //
827   // Recognize non-transitional modern devices. Also, we'll have to parse the
828   // PCI capability list, so make sure the CapabilityPtr field will be valid.
829   //
830   if (Pci.Hdr.VendorId == VIRTIO_VENDOR_ID &&
831       Pci.Hdr.DeviceId >= 0x1040 &&
832       Pci.Hdr.DeviceId <= 0x107F &&
833       Pci.Hdr.RevisionID >= 0x01 &&
834       Pci.Device.SubsystemID >= 0x40 &&
835       (Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0) {
836     //
837     // The virtio-vga device is special. It can be driven both as a VGA device
838     // with a linear framebuffer, and through its underlying, modern,
839     // virtio-gpu-pci device, which has no linear framebuffer itself. For
840     // compatibility with guest OSes that insist on inheriting a linear
841     // framebuffer from the firmware, we should leave virtio-vga to
842     // QemuVideoDxe, and support only virtio-gpu-pci here.
843     //
844     // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
845     // former has device class PCI_CLASS_DISPLAY_VGA.
846     //
847     if (Pci.Hdr.DeviceId != 0x1050 || !IS_PCI_VGA (&Pci)) {
848       Status = EFI_SUCCESS;
849     }
850   }
851 
852 CloseProtocol:
853   gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
854          This->DriverBindingHandle, DeviceHandle);
855 
856   return Status;
857 }
858 
859 
860 STATIC
861 EFI_STATUS
862 EFIAPI
Virtio10BindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)863 Virtio10BindingStart (
864   IN EFI_DRIVER_BINDING_PROTOCOL *This,
865   IN EFI_HANDLE                  DeviceHandle,
866   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
867   )
868 {
869   VIRTIO_1_0_DEV *Device;
870   EFI_STATUS     Status;
871   PCI_TYPE00     Pci;
872   UINT64         SetAttributes;
873 
874   Device = AllocateZeroPool (sizeof *Device);
875   if (Device == NULL) {
876     return EFI_OUT_OF_RESOURCES;
877   }
878 
879   Device->Signature = VIRTIO_1_0_SIGNATURE;
880   CopyMem (&Device->VirtIo, &mVirtIoTemplate, sizeof mVirtIoTemplate);
881 
882   Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
883                   (VOID **)&Device->PciIo, This->DriverBindingHandle,
884                   DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
885   if (EFI_ERROR (Status)) {
886     goto FreeDevice;
887   }
888 
889   Status = Device->PciIo->Pci.Read (Device->PciIo, EfiPciIoWidthUint32, 0,
890                                 sizeof Pci / sizeof (UINT32), &Pci);
891   if (EFI_ERROR (Status)) {
892     goto ClosePciIo;
893   }
894 
895   Device->VirtIo.SubSystemDeviceId = Pci.Hdr.DeviceId - 0x1040;
896 
897   Status = ParseCapabilities (Device, Pci.Device.CapabilityPtr);
898   if (EFI_ERROR (Status)) {
899     goto ClosePciIo;
900   }
901 
902   Status = Device->PciIo->Attributes (Device->PciIo,
903                             EfiPciIoAttributeOperationGet, 0,
904                             &Device->OriginalPciAttributes);
905   if (EFI_ERROR (Status)) {
906     goto ClosePciIo;
907   }
908 
909   SetAttributes = 0;
910   UpdateAttributes (&Device->CommonConfig, &SetAttributes);
911   UpdateAttributes (&Device->NotifyConfig, &SetAttributes);
912   UpdateAttributes (&Device->SpecificConfig, &SetAttributes);
913   Status = Device->PciIo->Attributes (Device->PciIo,
914                             EfiPciIoAttributeOperationEnable, SetAttributes,
915                             NULL);
916   if (EFI_ERROR (Status)) {
917     goto ClosePciIo;
918   }
919 
920   Status = gBS->InstallProtocolInterface (&DeviceHandle,
921                   &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE,
922                   &Device->VirtIo);
923   if (EFI_ERROR (Status)) {
924     goto RestorePciAttributes;
925   }
926 
927   return EFI_SUCCESS;
928 
929 RestorePciAttributes:
930   Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,
931                    Device->OriginalPciAttributes, NULL);
932 
933 ClosePciIo:
934   gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
935          This->DriverBindingHandle, DeviceHandle);
936 
937 FreeDevice:
938   FreePool (Device);
939 
940   return Status;
941 }
942 
943 
944 STATIC
945 EFI_STATUS
946 EFIAPI
Virtio10BindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)947 Virtio10BindingStop (
948   IN EFI_DRIVER_BINDING_PROTOCOL *This,
949   IN EFI_HANDLE                  DeviceHandle,
950   IN UINTN                       NumberOfChildren,
951   IN EFI_HANDLE                  *ChildHandleBuffer
952   )
953 {
954   EFI_STATUS             Status;
955   VIRTIO_DEVICE_PROTOCOL *VirtIo;
956   VIRTIO_1_0_DEV         *Device;
957 
958   Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
959                   (VOID **)&VirtIo, This->DriverBindingHandle,
960                   DeviceHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
961   if (EFI_ERROR (Status)) {
962     return Status;
963   }
964 
965   Device = VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo);
966 
967   Status = gBS->UninstallProtocolInterface (DeviceHandle,
968                   &gVirtioDeviceProtocolGuid, &Device->VirtIo);
969   if (EFI_ERROR (Status)) {
970     return Status;
971   }
972 
973   Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,
974                    Device->OriginalPciAttributes, NULL);
975   gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
976          This->DriverBindingHandle, DeviceHandle);
977   FreePool (Device);
978 
979   return EFI_SUCCESS;
980 }
981 
982 
983 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
984   &Virtio10BindingSupported,
985   &Virtio10BindingStart,
986   &Virtio10BindingStop,
987   0x10, // Version
988   NULL, // ImageHandle, to be overwritten
989   NULL  // DriverBindingHandle, to be overwritten
990 };
991 
992 
993 //
994 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
995 // implementations
996 //
997 
998 STATIC
999 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1000   { "eng;en", L"Virtio 1.0 PCI Driver" },
1001   { NULL,     NULL                     }
1002 };
1003 
1004 STATIC
1005 EFI_COMPONENT_NAME_PROTOCOL mComponentName;
1006 
1007 STATIC
1008 EFI_STATUS
1009 EFIAPI
Virtio10GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN CHAR8 * Language,OUT CHAR16 ** DriverName)1010 Virtio10GetDriverName (
1011   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
1012   IN  CHAR8                       *Language,
1013   OUT CHAR16                      **DriverName
1014   )
1015 {
1016   return LookupUnicodeString2 (
1017            Language,
1018            This->SupportedLanguages,
1019            mDriverNameTable,
1020            DriverName,
1021            (BOOLEAN)(This == &mComponentName) // Iso639Language
1022            );
1023 }
1024 
1025 STATIC
1026 EFI_STATUS
1027 EFIAPI
Virtio10GetDeviceName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_HANDLE ChildHandle,IN CHAR8 * Language,OUT CHAR16 ** ControllerName)1028 Virtio10GetDeviceName (
1029   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
1030   IN  EFI_HANDLE                  DeviceHandle,
1031   IN  EFI_HANDLE                  ChildHandle,
1032   IN  CHAR8                       *Language,
1033   OUT CHAR16                      **ControllerName
1034   )
1035 {
1036   return EFI_UNSUPPORTED;
1037 }
1038 
1039 STATIC
1040 EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
1041   &Virtio10GetDriverName,
1042   &Virtio10GetDeviceName,
1043   "eng"
1044 };
1045 
1046 STATIC
1047 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
1048   (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &Virtio10GetDriverName,
1049   (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &Virtio10GetDeviceName,
1050   "en"
1051 };
1052 
1053 
1054 //
1055 // Entry point of this driver
1056 //
1057 
1058 EFI_STATUS
1059 EFIAPI
Virtio10EntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1060 Virtio10EntryPoint (
1061   IN EFI_HANDLE       ImageHandle,
1062   IN EFI_SYSTEM_TABLE *SystemTable
1063   )
1064 {
1065   return EfiLibInstallDriverBindingComponentName2 (
1066            ImageHandle,
1067            SystemTable,
1068            &mDriverBinding,
1069            ImageHandle,
1070            &mComponentName,
1071            &mComponentName2
1072            );
1073 }
1074