]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceFunctions.c
b43850e69da9dce196c2c5289954ad87fd65e1c2
[mirror_edk2.git] / OvmfPkg / Library / VirtioMmioDeviceLib / VirtioMmioDeviceFunctions.c
1 /** @file
2
3 This driver produces Virtio Device Protocol instances for Virtio MMIO devices.
4
5 Copyright (C) 2012, Red Hat, Inc.
6 Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
7 Copyright (C) 2013, ARM Ltd.
8
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10
11 **/
12
13 #include "VirtioMmioDevice.h"
14
15 EFI_STATUS
16 EFIAPI
17 VirtioMmioGetDeviceFeatures (
18 IN VIRTIO_DEVICE_PROTOCOL *This,
19 OUT UINT64 *DeviceFeatures
20 )
21 {
22 VIRTIO_MMIO_DEVICE *Device;
23 UINT32 LowBits, HighBits;
24
25 if (DeviceFeatures == NULL) {
26 return EFI_INVALID_PARAMETER;
27 }
28
29 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
30
31 if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
32 *DeviceFeatures = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_HOST_FEATURES);
33 } else {
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;
39 }
40
41 return EFI_SUCCESS;
42 }
43
44 EFI_STATUS
45 EFIAPI
46 VirtioMmioGetQueueSize (
47 IN VIRTIO_DEVICE_PROTOCOL *This,
48 OUT UINT16 *QueueNumMax
49 )
50 {
51 VIRTIO_MMIO_DEVICE *Device;
52
53 if (QueueNumMax == NULL) {
54 return EFI_INVALID_PARAMETER;
55 }
56
57 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
58
59 *QueueNumMax = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX) & 0xFFFF;
60
61 return EFI_SUCCESS;
62 }
63
64 EFI_STATUS
65 EFIAPI
66 VirtioMmioGetDeviceStatus (
67 IN VIRTIO_DEVICE_PROTOCOL *This,
68 OUT UINT8 *DeviceStatus
69 )
70 {
71 VIRTIO_MMIO_DEVICE *Device;
72
73 if (DeviceStatus == NULL) {
74 return EFI_INVALID_PARAMETER;
75 }
76
77 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
78
79 *DeviceStatus = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_STATUS) & 0xFF;
80
81 return EFI_SUCCESS;
82 }
83
84 EFI_STATUS
85 EFIAPI
86 VirtioMmioSetQueueSize (
87 IN VIRTIO_DEVICE_PROTOCOL *This,
88 IN UINT16 QueueSize
89 )
90 {
91 VIRTIO_MMIO_DEVICE *Device;
92
93 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
94
95 if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
96 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM, QueueSize);
97 } else {
98 Device->QueueNum = QueueSize;
99 }
100
101 return EFI_SUCCESS;
102 }
103
104 EFI_STATUS
105 EFIAPI
106 VirtioMmioSetDeviceStatus (
107 IN VIRTIO_DEVICE_PROTOCOL *This,
108 IN UINT8 DeviceStatus
109 )
110 {
111 VIRTIO_MMIO_DEVICE *Device;
112
113 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
114
115 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_STATUS, DeviceStatus);
116
117 return EFI_SUCCESS;
118 }
119
120 EFI_STATUS
121 EFIAPI
122 VirtioMmioSetQueueNotify (
123 IN VIRTIO_DEVICE_PROTOCOL *This,
124 IN UINT16 QueueNotify
125 )
126 {
127 VIRTIO_MMIO_DEVICE *Device;
128
129 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
130
131 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NOTIFY, QueueNotify);
132
133 return EFI_SUCCESS;
134 }
135
136 EFI_STATUS
137 EFIAPI
138 VirtioMmioSetQueueAlignment (
139 IN VIRTIO_DEVICE_PROTOCOL *This,
140 IN UINT32 Alignment
141 )
142 {
143 VIRTIO_MMIO_DEVICE *Device;
144
145 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
146
147 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_ALIGN, Alignment);
148
149 return EFI_SUCCESS;
150 }
151
152 EFI_STATUS
153 EFIAPI
154 VirtioMmioSetPageSize (
155 IN VIRTIO_DEVICE_PROTOCOL *This,
156 IN UINT32 PageSize
157 )
158 {
159 VIRTIO_MMIO_DEVICE *Device;
160
161 if (PageSize != EFI_PAGE_SIZE) {
162 return EFI_UNSUPPORTED;
163 }
164
165 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
166
167 if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
168 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_PAGE_SIZE, PageSize);
169 }
170
171 return EFI_SUCCESS;
172 }
173
174 EFI_STATUS
175 EFIAPI
176 VirtioMmioSetQueueSel (
177 IN VIRTIO_DEVICE_PROTOCOL *This,
178 IN UINT16 Sel
179 )
180 {
181 VIRTIO_MMIO_DEVICE *Device;
182
183 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
184
185 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_SEL, Sel);
186
187 if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
188 Device->QueueNum = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX) & 0xFFFF;
189 }
190
191 return EFI_SUCCESS;
192 }
193
194 EFI_STATUS
195 EFIAPI
196 VirtioMmioSetQueueAddress (
197 IN VIRTIO_DEVICE_PROTOCOL *This,
198 IN VRING *Ring,
199 IN UINT64 RingBaseShift
200 )
201 {
202 VIRTIO_MMIO_DEVICE *Device;
203 UINT64 Address;
204
205 ASSERT (RingBaseShift == 0);
206
207 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
208
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));
212 } else {
213 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM, Device->QueueNum);
214
215 Address = (UINTN)Ring->Base;
216 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_DESC_LO,
217 (UINT32)Address);
218 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_DESC_HI,
219 (UINT32)RShiftU64(Address, 32));
220
221 Address = (UINTN)Ring->Avail.Flags;
222 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_AVAIL_LO,
223 (UINT32)Address);
224 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_AVAIL_HI,
225 (UINT32)RShiftU64(Address, 32));
226
227 Address = (UINTN)Ring->Used.Flags;
228 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_USED_LO,
229 (UINT32)Address);
230 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_USED_HI,
231 (UINT32)RShiftU64(Address, 32));
232
233 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_READY, 1);
234 }
235
236 return EFI_SUCCESS;
237 }
238
239 EFI_STATUS
240 EFIAPI
241 VirtioMmioSetGuestFeatures (
242 IN VIRTIO_DEVICE_PROTOCOL *This,
243 IN UINT64 Features
244 )
245 {
246 VIRTIO_MMIO_DEVICE *Device;
247
248 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
249
250 if (Device->Version == VIRTIO_MMIO_DEVICE_VERSION_0_95) {
251 if (Features > MAX_UINT32) {
252 return EFI_UNSUPPORTED;
253 }
254 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_FEATURES,
255 (UINT32)Features);
256 } else {
257 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_FEATURES_SEL, 0);
258 VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_FEATURES,
259 (UINT32)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));
263 }
264
265 return EFI_SUCCESS;
266 }
267
268 EFI_STATUS
269 EFIAPI
270 VirtioMmioDeviceWrite (
271 IN VIRTIO_DEVICE_PROTOCOL *This,
272 IN UINTN FieldOffset,
273 IN UINTN FieldSize,
274 IN UINT64 Value
275 )
276 {
277 UINTN DstBaseAddress;
278 VIRTIO_MMIO_DEVICE *Device;
279
280 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
281
282 //
283 // Double-check fieldsize
284 //
285 if ((FieldSize != 1) && (FieldSize != 2) &&
286 (FieldSize != 4) && (FieldSize != 8)) {
287 return EFI_INVALID_PARAMETER;
288 }
289
290 //
291 // Compute base address
292 //
293 DstBaseAddress = Device->BaseAddress +
294 VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO + FieldOffset;
295
296 //
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.
299 //
300 MmioWriteBuffer8 (DstBaseAddress, FieldSize, (UINT8*)&Value);
301
302 return EFI_SUCCESS;
303 }
304
305 EFI_STATUS
306 EFIAPI
307 VirtioMmioDeviceRead (
308 IN VIRTIO_DEVICE_PROTOCOL *This,
309 IN UINTN FieldOffset,
310 IN UINTN FieldSize,
311 IN UINTN BufferSize,
312 OUT VOID *Buffer
313 )
314 {
315 UINTN SrcBaseAddress;
316 VIRTIO_MMIO_DEVICE *Device;
317
318 Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
319
320 //
321 // Parameter validation
322 //
323 ASSERT (FieldSize == BufferSize);
324
325 //
326 // Double-check fieldsize
327 //
328 if ((FieldSize != 1) && (FieldSize != 2) &&
329 (FieldSize != 4) && (FieldSize != 8)) {
330 return EFI_INVALID_PARAMETER;
331 }
332
333 //
334 // Compute base address
335 //
336 SrcBaseAddress = Device->BaseAddress +
337 VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO + FieldOffset;
338
339 //
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.
342 //
343 MmioReadBuffer8 (SrcBaseAddress, BufferSize, Buffer);
344
345 return EFI_SUCCESS;
346 }
347
348 EFI_STATUS
349 EFIAPI
350 VirtioMmioAllocateSharedPages (
351 IN VIRTIO_DEVICE_PROTOCOL *This,
352 IN UINTN NumPages,
353 OUT VOID **HostAddress
354 )
355 {
356 VOID *Buffer;
357
358 Buffer = AllocatePages (NumPages);
359 if (Buffer == NULL) {
360 return EFI_OUT_OF_RESOURCES;
361 }
362
363 *HostAddress = Buffer;
364 return EFI_SUCCESS;
365 }
366
367 VOID
368 EFIAPI
369 VirtioMmioFreeSharedPages (
370 IN VIRTIO_DEVICE_PROTOCOL *This,
371 IN UINTN NumPages,
372 IN VOID *HostAddress
373 )
374 {
375 FreePages (HostAddress, NumPages);
376 }
377
378 EFI_STATUS
379 EFIAPI
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,
386 OUT VOID **Mapping
387 )
388 {
389 *DeviceAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
390 *Mapping = NULL;
391
392 return EFI_SUCCESS;
393 }
394
395 EFI_STATUS
396 EFIAPI
397 VirtioMmioUnmapSharedBuffer (
398 IN VIRTIO_DEVICE_PROTOCOL *This,
399 IN VOID *Mapping
400 )
401 {
402 return EFI_SUCCESS;
403 }