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
VirtioMmioGetDeviceFeatures(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT64 * DeviceFeatures)17 VirtioMmioGetDeviceFeatures (
18   IN VIRTIO_DEVICE_PROTOCOL *This,
19   OUT UINT64                *DeviceFeatures
20   )
21 {
22   VIRTIO_MMIO_DEVICE *Device;
23 
24   if (DeviceFeatures == NULL) {
25     return EFI_INVALID_PARAMETER;
26   }
27 
28   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
29 
30   *DeviceFeatures = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_HOST_FEATURES);
31 
32   return EFI_SUCCESS;
33 }
34 
35 EFI_STATUS
36 EFIAPI
VirtioMmioGetQueueSize(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT16 * QueueNumMax)37 VirtioMmioGetQueueSize (
38   IN  VIRTIO_DEVICE_PROTOCOL  *This,
39   OUT UINT16                  *QueueNumMax
40   )
41 {
42   VIRTIO_MMIO_DEVICE *Device;
43 
44   if (QueueNumMax == NULL) {
45     return EFI_INVALID_PARAMETER;
46   }
47 
48   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
49 
50   *QueueNumMax = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX) & 0xFFFF;
51 
52   return EFI_SUCCESS;
53 }
54 
55 EFI_STATUS
56 EFIAPI
VirtioMmioGetDeviceStatus(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT8 * DeviceStatus)57 VirtioMmioGetDeviceStatus (
58   IN  VIRTIO_DEVICE_PROTOCOL  *This,
59   OUT UINT8                   *DeviceStatus
60   )
61 {
62   VIRTIO_MMIO_DEVICE *Device;
63 
64   if (DeviceStatus == NULL) {
65     return EFI_INVALID_PARAMETER;
66   }
67 
68   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
69 
70   *DeviceStatus = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_STATUS) & 0xFF;
71 
72   return EFI_SUCCESS;
73 }
74 
75 EFI_STATUS
76 EFIAPI
VirtioMmioSetQueueSize(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT16 QueueSize)77 VirtioMmioSetQueueSize (
78   IN VIRTIO_DEVICE_PROTOCOL *This,
79   IN UINT16                  QueueSize
80   )
81 {
82   VIRTIO_MMIO_DEVICE *Device;
83 
84   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
85 
86   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM, QueueSize);
87 
88   return EFI_SUCCESS;
89 }
90 
91 EFI_STATUS
92 EFIAPI
VirtioMmioSetDeviceStatus(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT8 DeviceStatus)93 VirtioMmioSetDeviceStatus (
94   IN VIRTIO_DEVICE_PROTOCOL *This,
95   IN UINT8                   DeviceStatus
96   )
97 {
98   VIRTIO_MMIO_DEVICE *Device;
99 
100   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
101 
102   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_STATUS, DeviceStatus);
103 
104   return EFI_SUCCESS;
105 }
106 
107 EFI_STATUS
108 EFIAPI
VirtioMmioSetQueueNotify(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT16 QueueNotify)109 VirtioMmioSetQueueNotify (
110   IN VIRTIO_DEVICE_PROTOCOL *This,
111   IN UINT16                  QueueNotify
112   )
113 {
114   VIRTIO_MMIO_DEVICE *Device;
115 
116   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
117 
118   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NOTIFY, QueueNotify);
119 
120   return EFI_SUCCESS;
121 }
122 
123 EFI_STATUS
124 EFIAPI
VirtioMmioSetQueueAlignment(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT32 Alignment)125 VirtioMmioSetQueueAlignment (
126   IN VIRTIO_DEVICE_PROTOCOL *This,
127   IN UINT32                  Alignment
128   )
129 {
130   VIRTIO_MMIO_DEVICE *Device;
131 
132   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
133 
134   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_ALIGN, Alignment);
135 
136   return EFI_SUCCESS;
137 }
138 
139 EFI_STATUS
140 EFIAPI
VirtioMmioSetPageSize(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT32 PageSize)141 VirtioMmioSetPageSize (
142   IN VIRTIO_DEVICE_PROTOCOL *This,
143   IN UINT32                  PageSize
144   )
145 {
146   VIRTIO_MMIO_DEVICE *Device;
147 
148   if (PageSize != EFI_PAGE_SIZE) {
149     return EFI_UNSUPPORTED;
150   }
151 
152   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
153 
154   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_PAGE_SIZE, PageSize);
155 
156   return EFI_SUCCESS;
157 }
158 
159 EFI_STATUS
160 EFIAPI
VirtioMmioSetQueueSel(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT16 Sel)161 VirtioMmioSetQueueSel (
162   IN VIRTIO_DEVICE_PROTOCOL *This,
163   IN UINT16                  Sel
164   )
165 {
166   VIRTIO_MMIO_DEVICE *Device;
167 
168   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
169 
170   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_SEL, Sel);
171 
172   return EFI_SUCCESS;
173 }
174 
175 EFI_STATUS
VirtioMmioSetQueueAddress(IN VIRTIO_DEVICE_PROTOCOL * This,IN VRING * Ring,IN UINT64 RingBaseShift)176 VirtioMmioSetQueueAddress (
177   IN VIRTIO_DEVICE_PROTOCOL  *This,
178   IN VRING                   *Ring,
179   IN UINT64                  RingBaseShift
180   )
181 {
182   VIRTIO_MMIO_DEVICE *Device;
183 
184   ASSERT (RingBaseShift == 0);
185 
186   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
187 
188   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_PFN,
189     (UINT32)((UINTN)Ring->Base >> EFI_PAGE_SHIFT));
190 
191   return EFI_SUCCESS;
192 }
193 
194 EFI_STATUS
195 EFIAPI
VirtioMmioSetGuestFeatures(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT64 Features)196 VirtioMmioSetGuestFeatures (
197   IN VIRTIO_DEVICE_PROTOCOL *This,
198   IN UINT64                  Features
199   )
200 {
201   VIRTIO_MMIO_DEVICE *Device;
202 
203   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
204 
205   if (Features > MAX_UINT32) {
206     return EFI_UNSUPPORTED;
207   }
208   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_FEATURES,
209     (UINT32)Features);
210 
211   return EFI_SUCCESS;
212 }
213 
214 EFI_STATUS
215 EFIAPI
VirtioMmioDeviceWrite(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINT64 Value)216 VirtioMmioDeviceWrite (
217   IN VIRTIO_DEVICE_PROTOCOL *This,
218   IN UINTN                  FieldOffset,
219   IN UINTN                  FieldSize,
220   IN UINT64                 Value
221   )
222 {
223   UINTN                     DstBaseAddress;
224   VIRTIO_MMIO_DEVICE       *Device;
225 
226   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
227 
228   //
229   // Double-check fieldsize
230   //
231   if ((FieldSize != 1) && (FieldSize != 2) &&
232       (FieldSize != 4) && (FieldSize != 8)) {
233     return EFI_INVALID_PARAMETER;
234   }
235 
236   //
237   // Compute base address
238   //
239   DstBaseAddress = Device->BaseAddress +
240       VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO + FieldOffset;
241 
242   //
243   // The device-specific memory area of Virtio-MMIO can only be written in
244   // byte accesses. This is not currently in the Virtio spec.
245   //
246   MmioWriteBuffer8 (DstBaseAddress, FieldSize, (UINT8*)&Value);
247 
248   return EFI_SUCCESS;
249 }
250 
251 EFI_STATUS
252 EFIAPI
VirtioMmioDeviceRead(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINTN BufferSize,OUT VOID * Buffer)253 VirtioMmioDeviceRead (
254   IN  VIRTIO_DEVICE_PROTOCOL    *This,
255   IN  UINTN                     FieldOffset,
256   IN  UINTN                     FieldSize,
257   IN  UINTN                     BufferSize,
258   OUT VOID                      *Buffer
259   )
260 {
261   UINTN                     SrcBaseAddress;
262   VIRTIO_MMIO_DEVICE       *Device;
263 
264   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
265 
266   //
267   // Parameter validation
268   //
269   ASSERT (FieldSize == BufferSize);
270 
271   //
272   // Double-check fieldsize
273   //
274   if ((FieldSize != 1) && (FieldSize != 2) &&
275       (FieldSize != 4) && (FieldSize != 8)) {
276     return EFI_INVALID_PARAMETER;
277   }
278 
279   //
280   // Compute base address
281   //
282   SrcBaseAddress = Device->BaseAddress +
283       VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO + FieldOffset;
284 
285   //
286   // The device-specific memory area of Virtio-MMIO can only be read in
287   // byte reads. This is not currently in the Virtio spec.
288   //
289   MmioReadBuffer8 (SrcBaseAddress, BufferSize, Buffer);
290 
291   return EFI_SUCCESS;
292 }
293 
294 EFI_STATUS
295 EFIAPI
VirtioMmioAllocateSharedPages(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN NumPages,OUT VOID ** HostAddress)296 VirtioMmioAllocateSharedPages (
297   IN  VIRTIO_DEVICE_PROTOCOL  *This,
298   IN  UINTN                   NumPages,
299   OUT VOID                    **HostAddress
300   )
301 {
302   VOID        *Buffer;
303 
304   Buffer = AllocatePages (NumPages);
305   if (Buffer == NULL) {
306     return EFI_OUT_OF_RESOURCES;
307   }
308 
309   *HostAddress = Buffer;
310   return EFI_SUCCESS;
311 }
312 
313 VOID
314 EFIAPI
VirtioMmioFreeSharedPages(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN NumPages,IN VOID * HostAddress)315 VirtioMmioFreeSharedPages (
316   IN  VIRTIO_DEVICE_PROTOCOL  *This,
317   IN  UINTN                   NumPages,
318   IN  VOID                    *HostAddress
319   )
320 {
321   FreePages (HostAddress, NumPages);
322 }
323 
324 EFI_STATUS
325 EFIAPI
VirtioMmioMapSharedBuffer(IN VIRTIO_DEVICE_PROTOCOL * This,IN VIRTIO_MAP_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)326 VirtioMmioMapSharedBuffer (
327   IN      VIRTIO_DEVICE_PROTOCOL  *This,
328   IN      VIRTIO_MAP_OPERATION    Operation,
329   IN      VOID                    *HostAddress,
330   IN OUT  UINTN                   *NumberOfBytes,
331   OUT     EFI_PHYSICAL_ADDRESS    *DeviceAddress,
332   OUT     VOID                    **Mapping
333   )
334 {
335   *DeviceAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
336   *Mapping = NULL;
337 
338   return EFI_SUCCESS;
339 }
340 
341 EFI_STATUS
342 EFIAPI
VirtioMmioUnmapSharedBuffer(IN VIRTIO_DEVICE_PROTOCOL * This,IN VOID * Mapping)343 VirtioMmioUnmapSharedBuffer (
344   IN VIRTIO_DEVICE_PROTOCOL    *This,
345   IN VOID                      *Mapping
346   )
347 {
348   return EFI_SUCCESS;
349 }
350