]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Virtio10Dxe/Virtio10.c
ef9a00710668daf041b011224a1a9cbc1ba69e7c
[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 IN UINT64 RingBaseShift
494 )
495 {
496 VIRTIO_1_0_DEV *Dev;
497 EFI_STATUS Status;
498 UINT64 Address;
499 UINT16 Enable;
500
501 ASSERT (RingBaseShift == 0);
502
503 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
504
505 Address = (UINTN)Ring->Desc;
506 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
507 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueDesc),
508 sizeof Address, &Address);
509 if (EFI_ERROR (Status)) {
510 return Status;
511 }
512
513 Address = (UINTN)Ring->Avail.Flags;
514 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
515 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueAvail),
516 sizeof Address, &Address);
517 if (EFI_ERROR (Status)) {
518 return Status;
519 }
520
521 Address = (UINTN)Ring->Used.Flags;
522 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
523 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueUsed),
524 sizeof Address, &Address);
525 if (EFI_ERROR (Status)) {
526 return Status;
527 }
528
529 Enable = 1;
530 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
531 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueEnable),
532 sizeof Enable, &Enable);
533 return Status;
534 }
535
536
537 STATIC
538 EFI_STATUS
539 EFIAPI
540 Virtio10SetQueueSel (
541 IN VIRTIO_DEVICE_PROTOCOL *This,
542 IN UINT16 Index
543 )
544 {
545 VIRTIO_1_0_DEV *Dev;
546 EFI_STATUS Status;
547
548 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
549
550 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
551 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
552 sizeof Index, &Index);
553 return Status;
554 }
555
556
557 STATIC
558 EFI_STATUS
559 EFIAPI
560 Virtio10SetQueueNotify (
561 IN VIRTIO_DEVICE_PROTOCOL *This,
562 IN UINT16 Index
563 )
564 {
565 VIRTIO_1_0_DEV *Dev;
566 EFI_STATUS Status;
567 UINT16 SavedQueueSelect;
568 UINT16 NotifyOffset;
569
570 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
571
572 //
573 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
574 // to stash & restore the current queue selector around it.
575 //
576 // So, start with saving the current queue selector.
577 //
578 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
579 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
580 sizeof SavedQueueSelect, &SavedQueueSelect);
581 if (EFI_ERROR (Status)) {
582 return Status;
583 }
584
585 //
586 // Select the requested queue.
587 //
588 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
589 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
590 sizeof Index, &Index);
591 if (EFI_ERROR (Status)) {
592 return Status;
593 }
594
595 //
596 // Read the QueueNotifyOff field.
597 //
598 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
599 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueNotifyOff),
600 sizeof NotifyOffset, &NotifyOffset);
601 if (EFI_ERROR (Status)) {
602 return Status;
603 }
604
605 //
606 // Re-select the original queue.
607 //
608 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
609 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
610 sizeof SavedQueueSelect, &SavedQueueSelect);
611 if (EFI_ERROR (Status)) {
612 return Status;
613 }
614
615 //
616 // We can now kick the queue.
617 //
618 Status = Virtio10Transfer (Dev->PciIo, &Dev->NotifyConfig, TRUE,
619 NotifyOffset * Dev->NotifyOffsetMultiplier,
620 sizeof Index, &Index);
621 return Status;
622 }
623
624
625 STATIC
626 EFI_STATUS
627 EFIAPI
628 Virtio10SetQueueAlign (
629 IN VIRTIO_DEVICE_PROTOCOL *This,
630 IN UINT32 Alignment
631 )
632 {
633 return (Alignment == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
634 }
635
636
637 STATIC
638 EFI_STATUS
639 EFIAPI
640 Virtio10SetPageSize (
641 IN VIRTIO_DEVICE_PROTOCOL *This,
642 IN UINT32 PageSize
643 )
644 {
645 return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
646 }
647
648
649 STATIC
650 EFI_STATUS
651 EFIAPI
652 Virtio10GetQueueNumMax (
653 IN VIRTIO_DEVICE_PROTOCOL *This,
654 OUT UINT16 *QueueNumMax
655 )
656 {
657 VIRTIO_1_0_DEV *Dev;
658 EFI_STATUS Status;
659
660 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
661
662 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
663 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSize),
664 sizeof *QueueNumMax, QueueNumMax);
665 return Status;
666 }
667
668
669 STATIC
670 EFI_STATUS
671 EFIAPI
672 Virtio10SetQueueNum (
673 IN VIRTIO_DEVICE_PROTOCOL *This,
674 IN UINT16 QueueSize
675 )
676 {
677 EFI_STATUS Status;
678 UINT16 CurrentSize;
679
680 //
681 // This member function is required for VirtIo MMIO, and a no-op in
682 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
683 // member to reduce memory consumption, but none of our drivers do. So
684 // just check that they set the size that is already in effect.
685 //
686 Status = Virtio10GetQueueNumMax (This, &CurrentSize);
687 if (EFI_ERROR (Status)) {
688 return Status;
689 }
690 return (CurrentSize == QueueSize) ? EFI_SUCCESS : EFI_UNSUPPORTED;
691 }
692
693
694 STATIC
695 EFI_STATUS
696 EFIAPI
697 Virtio10GetDeviceStatus (
698 IN VIRTIO_DEVICE_PROTOCOL *This,
699 OUT UINT8 *DeviceStatus
700 )
701 {
702 VIRTIO_1_0_DEV *Dev;
703 EFI_STATUS Status;
704
705 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
706
707 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
708 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
709 sizeof *DeviceStatus, DeviceStatus);
710 return Status;
711 }
712
713
714 STATIC
715 EFI_STATUS
716 EFIAPI
717 Virtio10SetDeviceStatus (
718 IN VIRTIO_DEVICE_PROTOCOL *This,
719 IN UINT8 DeviceStatus
720 )
721 {
722 VIRTIO_1_0_DEV *Dev;
723 EFI_STATUS Status;
724
725 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
726
727 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
728 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
729 sizeof DeviceStatus, &DeviceStatus);
730 return Status;
731 }
732
733
734 STATIC
735 EFI_STATUS
736 EFIAPI
737 Virtio10WriteDevice (
738 IN VIRTIO_DEVICE_PROTOCOL *This,
739 IN UINTN FieldOffset,
740 IN UINTN FieldSize,
741 IN UINT64 Value
742 )
743 {
744 VIRTIO_1_0_DEV *Dev;
745 EFI_STATUS Status;
746
747 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
748
749 Status = Virtio10Transfer (Dev->PciIo, &Dev->SpecificConfig, TRUE,
750 FieldOffset, FieldSize, &Value);
751 return Status;
752 }
753
754
755 STATIC
756 EFI_STATUS
757 EFIAPI
758 Virtio10ReadDevice (
759 IN VIRTIO_DEVICE_PROTOCOL *This,
760 IN UINTN FieldOffset,
761 IN UINTN FieldSize,
762 IN UINTN BufferSize,
763 OUT VOID *Buffer
764 )
765 {
766 VIRTIO_1_0_DEV *Dev;
767 EFI_STATUS Status;
768
769 if (FieldSize != BufferSize) {
770 return EFI_INVALID_PARAMETER;
771 }
772
773 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
774
775 Status = Virtio10Transfer (Dev->PciIo, &Dev->SpecificConfig, FALSE,
776 FieldOffset, FieldSize, Buffer);
777 return Status;
778 }
779
780 STATIC
781 EFI_STATUS
782 EFIAPI
783 Virtio10AllocateSharedPages (
784 IN VIRTIO_DEVICE_PROTOCOL *This,
785 IN UINTN Pages,
786 IN OUT VOID **HostAddress
787 )
788 {
789 VIRTIO_1_0_DEV *Dev;
790 EFI_STATUS Status;
791
792 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
793
794 Status = Dev->PciIo->AllocateBuffer (
795 Dev->PciIo,
796 AllocateAnyPages,
797 EfiBootServicesData,
798 Pages,
799 HostAddress,
800 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
801 );
802 return Status;
803 }
804
805 STATIC
806 VOID
807 EFIAPI
808 Virtio10FreeSharedPages (
809 IN VIRTIO_DEVICE_PROTOCOL *This,
810 IN UINTN Pages,
811 IN VOID *HostAddress
812 )
813 {
814 VIRTIO_1_0_DEV *Dev;
815
816 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
817
818 Dev->PciIo->FreeBuffer (
819 Dev->PciIo,
820 Pages,
821 HostAddress
822 );
823 }
824
825 STATIC
826 EFI_STATUS
827 EFIAPI
828 Virtio10MapSharedBuffer (
829 IN VIRTIO_DEVICE_PROTOCOL *This,
830 IN VIRTIO_MAP_OPERATION Operation,
831 IN VOID *HostAddress,
832 IN OUT UINTN *NumberOfBytes,
833 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
834 OUT VOID **Mapping
835 )
836 {
837 EFI_STATUS Status;
838 VIRTIO_1_0_DEV *Dev;
839 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;
840
841 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
842
843 //
844 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION
845 //
846 switch (Operation) {
847 case VirtioOperationBusMasterRead:
848 PciIoOperation = EfiPciIoOperationBusMasterRead;
849 break;
850 case VirtioOperationBusMasterWrite:
851 PciIoOperation = EfiPciIoOperationBusMasterWrite;
852 break;
853 case VirtioOperationBusMasterCommonBuffer:
854 PciIoOperation = EfiPciIoOperationBusMasterCommonBuffer;
855 break;
856 default:
857 return EFI_INVALID_PARAMETER;
858 }
859
860 Status = Dev->PciIo->Map (
861 Dev->PciIo,
862 PciIoOperation,
863 HostAddress,
864 NumberOfBytes,
865 DeviceAddress,
866 Mapping
867 );
868 return Status;
869 }
870
871 STATIC
872 EFI_STATUS
873 EFIAPI
874 Virtio10UnmapSharedBuffer (
875 IN VIRTIO_DEVICE_PROTOCOL *This,
876 IN VOID *Mapping
877 )
878 {
879 EFI_STATUS Status;
880 VIRTIO_1_0_DEV *Dev;
881
882 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
883
884 Status = Dev->PciIo->Unmap (
885 Dev->PciIo,
886 Mapping
887 );
888
889 return Status;
890 }
891
892 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate = {
893 VIRTIO_SPEC_REVISION (1, 0, 0),
894 0, // SubSystemDeviceId, filled in dynamically
895 Virtio10GetDeviceFeatures,
896 Virtio10SetGuestFeatures,
897 Virtio10SetQueueAddress,
898 Virtio10SetQueueSel,
899 Virtio10SetQueueNotify,
900 Virtio10SetQueueAlign,
901 Virtio10SetPageSize,
902 Virtio10GetQueueNumMax,
903 Virtio10SetQueueNum,
904 Virtio10GetDeviceStatus,
905 Virtio10SetDeviceStatus,
906 Virtio10WriteDevice,
907 Virtio10ReadDevice,
908 Virtio10AllocateSharedPages,
909 Virtio10FreeSharedPages,
910 Virtio10MapSharedBuffer,
911 Virtio10UnmapSharedBuffer
912 };
913
914
915 //
916 // EFI_DRIVER_BINDING_PROTOCOL member functions
917 //
918
919 STATIC
920 EFI_STATUS
921 EFIAPI
922 Virtio10BindingSupported (
923 IN EFI_DRIVER_BINDING_PROTOCOL *This,
924 IN EFI_HANDLE DeviceHandle,
925 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
926 )
927 {
928 EFI_STATUS Status;
929 EFI_PCI_IO_PROTOCOL *PciIo;
930 PCI_TYPE00 Pci;
931
932 Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
933 (VOID **)&PciIo, This->DriverBindingHandle,
934 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
935 if (EFI_ERROR (Status)) {
936 return Status;
937 }
938
939 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0,
940 sizeof Pci / sizeof (UINT32), &Pci);
941 if (EFI_ERROR (Status)) {
942 goto CloseProtocol;
943 }
944
945 Status = EFI_UNSUPPORTED;
946 //
947 // Recognize non-transitional modern devices. Also, we'll have to parse the
948 // PCI capability list, so make sure the CapabilityPtr field will be valid.
949 //
950 if (Pci.Hdr.VendorId == VIRTIO_VENDOR_ID &&
951 Pci.Hdr.DeviceId >= 0x1040 &&
952 Pci.Hdr.DeviceId <= 0x107F &&
953 Pci.Hdr.RevisionID >= 0x01 &&
954 Pci.Device.SubsystemID >= 0x40 &&
955 (Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0) {
956 //
957 // The virtio-vga device is special. It can be driven both as a VGA device
958 // with a linear framebuffer, and through its underlying, modern,
959 // virtio-gpu-pci device, which has no linear framebuffer itself. For
960 // compatibility with guest OSes that insist on inheriting a linear
961 // framebuffer from the firmware, we should leave virtio-vga to
962 // QemuVideoDxe, and support only virtio-gpu-pci here.
963 //
964 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
965 // former has device class PCI_CLASS_DISPLAY_VGA.
966 //
967 if (Pci.Hdr.DeviceId != 0x1050 || !IS_PCI_VGA (&Pci)) {
968 Status = EFI_SUCCESS;
969 }
970 }
971
972 CloseProtocol:
973 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
974 This->DriverBindingHandle, DeviceHandle);
975
976 return Status;
977 }
978
979
980 STATIC
981 EFI_STATUS
982 EFIAPI
983 Virtio10BindingStart (
984 IN EFI_DRIVER_BINDING_PROTOCOL *This,
985 IN EFI_HANDLE DeviceHandle,
986 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
987 )
988 {
989 VIRTIO_1_0_DEV *Device;
990 EFI_STATUS Status;
991 PCI_TYPE00 Pci;
992 UINT64 SetAttributes;
993
994 Device = AllocateZeroPool (sizeof *Device);
995 if (Device == NULL) {
996 return EFI_OUT_OF_RESOURCES;
997 }
998
999 Device->Signature = VIRTIO_1_0_SIGNATURE;
1000 CopyMem (&Device->VirtIo, &mVirtIoTemplate, sizeof mVirtIoTemplate);
1001
1002 Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
1003 (VOID **)&Device->PciIo, This->DriverBindingHandle,
1004 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
1005 if (EFI_ERROR (Status)) {
1006 goto FreeDevice;
1007 }
1008
1009 Status = Device->PciIo->Pci.Read (Device->PciIo, EfiPciIoWidthUint32, 0,
1010 sizeof Pci / sizeof (UINT32), &Pci);
1011 if (EFI_ERROR (Status)) {
1012 goto ClosePciIo;
1013 }
1014
1015 Device->VirtIo.SubSystemDeviceId = Pci.Hdr.DeviceId - 0x1040;
1016
1017 Status = ParseCapabilities (Device, Pci.Device.CapabilityPtr);
1018 if (EFI_ERROR (Status)) {
1019 goto ClosePciIo;
1020 }
1021
1022 Status = Device->PciIo->Attributes (Device->PciIo,
1023 EfiPciIoAttributeOperationGet, 0,
1024 &Device->OriginalPciAttributes);
1025 if (EFI_ERROR (Status)) {
1026 goto ClosePciIo;
1027 }
1028
1029 SetAttributes = (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER |
1030 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
1031 UpdateAttributes (&Device->CommonConfig, &SetAttributes);
1032 UpdateAttributes (&Device->NotifyConfig, &SetAttributes);
1033 UpdateAttributes (&Device->SpecificConfig, &SetAttributes);
1034 Status = Device->PciIo->Attributes (Device->PciIo,
1035 EfiPciIoAttributeOperationEnable, SetAttributes,
1036 NULL);
1037 if (EFI_ERROR (Status)) {
1038 goto ClosePciIo;
1039 }
1040
1041 Status = gBS->InstallProtocolInterface (&DeviceHandle,
1042 &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE,
1043 &Device->VirtIo);
1044 if (EFI_ERROR (Status)) {
1045 goto RestorePciAttributes;
1046 }
1047
1048 return EFI_SUCCESS;
1049
1050 RestorePciAttributes:
1051 Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,
1052 Device->OriginalPciAttributes, NULL);
1053
1054 ClosePciIo:
1055 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
1056 This->DriverBindingHandle, DeviceHandle);
1057
1058 FreeDevice:
1059 FreePool (Device);
1060
1061 return Status;
1062 }
1063
1064
1065 STATIC
1066 EFI_STATUS
1067 EFIAPI
1068 Virtio10BindingStop (
1069 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1070 IN EFI_HANDLE DeviceHandle,
1071 IN UINTN NumberOfChildren,
1072 IN EFI_HANDLE *ChildHandleBuffer
1073 )
1074 {
1075 EFI_STATUS Status;
1076 VIRTIO_DEVICE_PROTOCOL *VirtIo;
1077 VIRTIO_1_0_DEV *Device;
1078
1079 Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1080 (VOID **)&VirtIo, This->DriverBindingHandle,
1081 DeviceHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
1082 if (EFI_ERROR (Status)) {
1083 return Status;
1084 }
1085
1086 Device = VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo);
1087
1088 Status = gBS->UninstallProtocolInterface (DeviceHandle,
1089 &gVirtioDeviceProtocolGuid, &Device->VirtIo);
1090 if (EFI_ERROR (Status)) {
1091 return Status;
1092 }
1093
1094 Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,
1095 Device->OriginalPciAttributes, NULL);
1096 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
1097 This->DriverBindingHandle, DeviceHandle);
1098 FreePool (Device);
1099
1100 return EFI_SUCCESS;
1101 }
1102
1103
1104 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
1105 &Virtio10BindingSupported,
1106 &Virtio10BindingStart,
1107 &Virtio10BindingStop,
1108 0x10, // Version
1109 NULL, // ImageHandle, to be overwritten
1110 NULL // DriverBindingHandle, to be overwritten
1111 };
1112
1113
1114 //
1115 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
1116 // implementations
1117 //
1118
1119 STATIC
1120 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1121 { "eng;en", L"Virtio 1.0 PCI Driver" },
1122 { NULL, NULL }
1123 };
1124
1125 STATIC
1126 EFI_COMPONENT_NAME_PROTOCOL mComponentName;
1127
1128 STATIC
1129 EFI_STATUS
1130 EFIAPI
1131 Virtio10GetDriverName (
1132 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1133 IN CHAR8 *Language,
1134 OUT CHAR16 **DriverName
1135 )
1136 {
1137 return LookupUnicodeString2 (
1138 Language,
1139 This->SupportedLanguages,
1140 mDriverNameTable,
1141 DriverName,
1142 (BOOLEAN)(This == &mComponentName) // Iso639Language
1143 );
1144 }
1145
1146 STATIC
1147 EFI_STATUS
1148 EFIAPI
1149 Virtio10GetDeviceName (
1150 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1151 IN EFI_HANDLE DeviceHandle,
1152 IN EFI_HANDLE ChildHandle,
1153 IN CHAR8 *Language,
1154 OUT CHAR16 **ControllerName
1155 )
1156 {
1157 return EFI_UNSUPPORTED;
1158 }
1159
1160 STATIC
1161 EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
1162 &Virtio10GetDriverName,
1163 &Virtio10GetDeviceName,
1164 "eng"
1165 };
1166
1167 STATIC
1168 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
1169 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &Virtio10GetDriverName,
1170 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &Virtio10GetDeviceName,
1171 "en"
1172 };
1173
1174
1175 //
1176 // Entry point of this driver
1177 //
1178
1179 EFI_STATUS
1180 EFIAPI
1181 Virtio10EntryPoint (
1182 IN EFI_HANDLE ImageHandle,
1183 IN EFI_SYSTEM_TABLE *SystemTable
1184 )
1185 {
1186 return EfiLibInstallDriverBindingComponentName2 (
1187 ImageHandle,
1188 SystemTable,
1189 &mDriverBinding,
1190 ImageHandle,
1191 &mComponentName,
1192 &mComponentName2
1193 );
1194 }