]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Virtio10Dxe/Virtio10.c
OvmfPkg/Virtio10Dxe: supply missing BUS_MASTER attribute
[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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 = EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
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
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
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
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
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 }