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