3 This driver produces Virtio Device Protocol instances for Virtio MMIO devices.
5 Copyright (C) 2012, Red Hat, Inc.
6 Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
7 Copyright (C) 2013, ARM Ltd.
9 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "VirtioMmioDevice.h"
17 VirtioMmioGetDeviceFeatures (
18 IN VIRTIO_DEVICE_PROTOCOL
*This
,
19 OUT UINT64
*DeviceFeatures
22 VIRTIO_MMIO_DEVICE
*Device
;
23 UINT32 LowBits
, HighBits
;
25 if (DeviceFeatures
== NULL
) {
26 return EFI_INVALID_PARAMETER
;
29 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
31 if (Device
->Version
== VIRTIO_MMIO_DEVICE_VERSION_0_95
) {
32 *DeviceFeatures
= VIRTIO_CFG_READ (Device
, VIRTIO_MMIO_OFFSET_HOST_FEATURES
);
34 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_HOST_FEATURES_SEL
, 0);
35 LowBits
= VIRTIO_CFG_READ (Device
, VIRTIO_MMIO_OFFSET_HOST_FEATURES
);
36 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_HOST_FEATURES_SEL
, 1);
37 HighBits
= VIRTIO_CFG_READ (Device
, VIRTIO_MMIO_OFFSET_HOST_FEATURES
);
38 *DeviceFeatures
= LShiftU64(HighBits
, 32) | LowBits
;
46 VirtioMmioGetQueueSize (
47 IN VIRTIO_DEVICE_PROTOCOL
*This
,
48 OUT UINT16
*QueueNumMax
51 VIRTIO_MMIO_DEVICE
*Device
;
53 if (QueueNumMax
== NULL
) {
54 return EFI_INVALID_PARAMETER
;
57 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
59 *QueueNumMax
= VIRTIO_CFG_READ (Device
, VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX
) & 0xFFFF;
66 VirtioMmioGetDeviceStatus (
67 IN VIRTIO_DEVICE_PROTOCOL
*This
,
68 OUT UINT8
*DeviceStatus
71 VIRTIO_MMIO_DEVICE
*Device
;
73 if (DeviceStatus
== NULL
) {
74 return EFI_INVALID_PARAMETER
;
77 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
79 *DeviceStatus
= VIRTIO_CFG_READ (Device
, VIRTIO_MMIO_OFFSET_STATUS
) & 0xFF;
86 VirtioMmioSetQueueSize (
87 IN VIRTIO_DEVICE_PROTOCOL
*This
,
91 VIRTIO_MMIO_DEVICE
*Device
;
93 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
95 if (Device
->Version
== VIRTIO_MMIO_DEVICE_VERSION_0_95
) {
96 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_NUM
, QueueSize
);
98 Device
->QueueNum
= QueueSize
;
106 VirtioMmioSetDeviceStatus (
107 IN VIRTIO_DEVICE_PROTOCOL
*This
,
108 IN UINT8 DeviceStatus
111 VIRTIO_MMIO_DEVICE
*Device
;
113 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
115 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_STATUS
, DeviceStatus
);
122 VirtioMmioSetQueueNotify (
123 IN VIRTIO_DEVICE_PROTOCOL
*This
,
124 IN UINT16 QueueNotify
127 VIRTIO_MMIO_DEVICE
*Device
;
129 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
131 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_NOTIFY
, QueueNotify
);
138 VirtioMmioSetQueueAlignment (
139 IN VIRTIO_DEVICE_PROTOCOL
*This
,
143 VIRTIO_MMIO_DEVICE
*Device
;
145 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
147 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_ALIGN
, Alignment
);
154 VirtioMmioSetPageSize (
155 IN VIRTIO_DEVICE_PROTOCOL
*This
,
159 VIRTIO_MMIO_DEVICE
*Device
;
161 if (PageSize
!= EFI_PAGE_SIZE
) {
162 return EFI_UNSUPPORTED
;
165 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
167 if (Device
->Version
== VIRTIO_MMIO_DEVICE_VERSION_0_95
) {
168 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_GUEST_PAGE_SIZE
, PageSize
);
176 VirtioMmioSetQueueSel (
177 IN VIRTIO_DEVICE_PROTOCOL
*This
,
181 VIRTIO_MMIO_DEVICE
*Device
;
183 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
185 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_SEL
, Sel
);
187 if (Device
->Version
== VIRTIO_MMIO_DEVICE_VERSION_0_95
) {
188 Device
->QueueNum
= VIRTIO_CFG_READ (Device
, VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX
) & 0xFFFF;
196 VirtioMmioSetQueueAddress (
197 IN VIRTIO_DEVICE_PROTOCOL
*This
,
199 IN UINT64 RingBaseShift
202 VIRTIO_MMIO_DEVICE
*Device
;
205 ASSERT (RingBaseShift
== 0);
207 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
209 if (Device
->Version
== VIRTIO_MMIO_DEVICE_VERSION_0_95
) {
210 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_PFN
,
211 (UINT32
)((UINTN
)Ring
->Base
>> EFI_PAGE_SHIFT
));
213 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_NUM
, Device
->QueueNum
);
215 Address
= (UINTN
)Ring
->Base
;
216 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_DESC_LO
,
218 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_DESC_HI
,
219 (UINT32
)RShiftU64(Address
, 32));
221 Address
= (UINTN
)Ring
->Avail
.Flags
;
222 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_AVAIL_LO
,
224 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_AVAIL_HI
,
225 (UINT32
)RShiftU64(Address
, 32));
227 Address
= (UINTN
)Ring
->Used
.Flags
;
228 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_USED_LO
,
230 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_USED_HI
,
231 (UINT32
)RShiftU64(Address
, 32));
233 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_QUEUE_READY
, 1);
241 VirtioMmioSetGuestFeatures (
242 IN VIRTIO_DEVICE_PROTOCOL
*This
,
246 VIRTIO_MMIO_DEVICE
*Device
;
248 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
250 if (Device
->Version
== VIRTIO_MMIO_DEVICE_VERSION_0_95
) {
251 if (Features
> MAX_UINT32
) {
252 return EFI_UNSUPPORTED
;
254 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_GUEST_FEATURES
,
257 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_GUEST_FEATURES_SEL
, 0);
258 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_GUEST_FEATURES
,
260 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_GUEST_FEATURES_SEL
, 1);
261 VIRTIO_CFG_WRITE (Device
, VIRTIO_MMIO_OFFSET_GUEST_FEATURES
,
262 (UINT32
)RShiftU64(Features
, 32));
270 VirtioMmioDeviceWrite (
271 IN VIRTIO_DEVICE_PROTOCOL
*This
,
272 IN UINTN FieldOffset
,
277 UINTN DstBaseAddress
;
278 VIRTIO_MMIO_DEVICE
*Device
;
280 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
283 // Double-check fieldsize
285 if ((FieldSize
!= 1) && (FieldSize
!= 2) &&
286 (FieldSize
!= 4) && (FieldSize
!= 8)) {
287 return EFI_INVALID_PARAMETER
;
291 // Compute base address
293 DstBaseAddress
= Device
->BaseAddress
+
294 VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO
+ FieldOffset
;
297 // The device-specific memory area of Virtio-MMIO can only be written in
298 // byte accesses. This is not currently in the Virtio spec.
300 MmioWriteBuffer8 (DstBaseAddress
, FieldSize
, (UINT8
*)&Value
);
307 VirtioMmioDeviceRead (
308 IN VIRTIO_DEVICE_PROTOCOL
*This
,
309 IN UINTN FieldOffset
,
315 UINTN SrcBaseAddress
;
316 VIRTIO_MMIO_DEVICE
*Device
;
318 Device
= VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This
);
321 // Parameter validation
323 ASSERT (FieldSize
== BufferSize
);
326 // Double-check fieldsize
328 if ((FieldSize
!= 1) && (FieldSize
!= 2) &&
329 (FieldSize
!= 4) && (FieldSize
!= 8)) {
330 return EFI_INVALID_PARAMETER
;
334 // Compute base address
336 SrcBaseAddress
= Device
->BaseAddress
+
337 VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO
+ FieldOffset
;
340 // The device-specific memory area of Virtio-MMIO can only be read in
341 // byte reads. This is not currently in the Virtio spec.
343 MmioReadBuffer8 (SrcBaseAddress
, BufferSize
, Buffer
);
350 VirtioMmioAllocateSharedPages (
351 IN VIRTIO_DEVICE_PROTOCOL
*This
,
353 OUT VOID
**HostAddress
358 Buffer
= AllocatePages (NumPages
);
359 if (Buffer
== NULL
) {
360 return EFI_OUT_OF_RESOURCES
;
363 *HostAddress
= Buffer
;
369 VirtioMmioFreeSharedPages (
370 IN VIRTIO_DEVICE_PROTOCOL
*This
,
375 FreePages (HostAddress
, NumPages
);
380 VirtioMmioMapSharedBuffer (
381 IN VIRTIO_DEVICE_PROTOCOL
*This
,
382 IN VIRTIO_MAP_OPERATION Operation
,
383 IN VOID
*HostAddress
,
384 IN OUT UINTN
*NumberOfBytes
,
385 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
389 *DeviceAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
397 VirtioMmioUnmapSharedBuffer (
398 IN VIRTIO_DEVICE_PROTOCOL
*This
,