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