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