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   This program and the accompanying materials are licensed and made available
10   under the terms and conditions of the BSD License which accompanies this
11   distribution. The full text of the license may be found at
12   http://opensource.org/licenses/bsd-license.php
13 
14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
15   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 
17 **/
18 
19 #include "VirtioMmioDevice.h"
20 
21 EFI_STATUS
22 EFIAPI
VirtioMmioGetDeviceFeatures(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT32 * DeviceFeatures)23 VirtioMmioGetDeviceFeatures (
24   IN VIRTIO_DEVICE_PROTOCOL *This,
25   OUT UINT32                *DeviceFeatures
26   )
27 {
28   VIRTIO_MMIO_DEVICE *Device;
29 
30   if (DeviceFeatures == NULL) {
31     return EFI_INVALID_PARAMETER;
32   }
33 
34   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
35 
36   *DeviceFeatures = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_HOST_FEATURES);
37 
38   return EFI_SUCCESS;
39 }
40 
41 EFI_STATUS
42 EFIAPI
VirtioMmioGetQueueAddress(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT32 * QueueAddress)43 VirtioMmioGetQueueAddress (
44   IN  VIRTIO_DEVICE_PROTOCOL *This,
45   OUT UINT32                 *QueueAddress
46   )
47 {
48   VIRTIO_MMIO_DEVICE *Device;
49 
50   if (QueueAddress == NULL) {
51     return EFI_INVALID_PARAMETER;
52   }
53 
54   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
55 
56   *QueueAddress = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_QUEUE_PFN);
57 
58   return EFI_SUCCESS;
59 }
60 
61 EFI_STATUS
62 EFIAPI
VirtioMmioGetQueueSize(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT16 * QueueNumMax)63 VirtioMmioGetQueueSize (
64   IN  VIRTIO_DEVICE_PROTOCOL  *This,
65   OUT UINT16                  *QueueNumMax
66   )
67 {
68   VIRTIO_MMIO_DEVICE *Device;
69 
70   if (QueueNumMax == NULL) {
71     return EFI_INVALID_PARAMETER;
72   }
73 
74   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
75 
76   *QueueNumMax = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX) & 0xFFFF;
77 
78   return EFI_SUCCESS;
79 }
80 
81 EFI_STATUS
82 EFIAPI
VirtioMmioGetDeviceStatus(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT8 * DeviceStatus)83 VirtioMmioGetDeviceStatus (
84   IN  VIRTIO_DEVICE_PROTOCOL  *This,
85   OUT UINT8                   *DeviceStatus
86   )
87 {
88   VIRTIO_MMIO_DEVICE *Device;
89 
90   if (DeviceStatus == NULL) {
91     return EFI_INVALID_PARAMETER;
92   }
93 
94   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
95 
96   *DeviceStatus = VIRTIO_CFG_READ (Device, VIRTIO_MMIO_OFFSET_STATUS) & 0xFF;
97 
98   return EFI_SUCCESS;
99 }
100 
101 EFI_STATUS
102 EFIAPI
VirtioMmioSetQueueSize(VIRTIO_DEVICE_PROTOCOL * This,UINT16 QueueSize)103 VirtioMmioSetQueueSize (
104   VIRTIO_DEVICE_PROTOCOL *This,
105   UINT16                  QueueSize
106   )
107 {
108   VIRTIO_MMIO_DEVICE *Device;
109 
110   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
111 
112   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NUM, QueueSize);
113 
114   return EFI_SUCCESS;
115 }
116 
117 EFI_STATUS
118 EFIAPI
VirtioMmioSetDeviceStatus(VIRTIO_DEVICE_PROTOCOL * This,UINT8 DeviceStatus)119 VirtioMmioSetDeviceStatus (
120   VIRTIO_DEVICE_PROTOCOL *This,
121   UINT8                   DeviceStatus
122   )
123 {
124   VIRTIO_MMIO_DEVICE *Device;
125 
126   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
127 
128   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_STATUS, DeviceStatus);
129 
130   return EFI_SUCCESS;
131 }
132 
133 EFI_STATUS
134 EFIAPI
VirtioMmioSetQueueNotify(VIRTIO_DEVICE_PROTOCOL * This,UINT16 QueueNotify)135 VirtioMmioSetQueueNotify (
136   VIRTIO_DEVICE_PROTOCOL *This,
137   UINT16                  QueueNotify
138   )
139 {
140   VIRTIO_MMIO_DEVICE *Device;
141 
142   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
143 
144   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_NOTIFY, QueueNotify);
145 
146   return EFI_SUCCESS;
147 }
148 
149 EFI_STATUS
150 EFIAPI
VirtioMmioSetQueueAlignment(VIRTIO_DEVICE_PROTOCOL * This,UINT32 Alignment)151 VirtioMmioSetQueueAlignment (
152   VIRTIO_DEVICE_PROTOCOL *This,
153   UINT32                  Alignment
154   )
155 {
156   VIRTIO_MMIO_DEVICE *Device;
157 
158   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
159 
160   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_ALIGN, Alignment);
161 
162   return EFI_SUCCESS;
163 }
164 
165 EFI_STATUS
166 EFIAPI
VirtioMmioSetPageSize(VIRTIO_DEVICE_PROTOCOL * This,UINT32 PageSize)167 VirtioMmioSetPageSize (
168   VIRTIO_DEVICE_PROTOCOL *This,
169   UINT32                  PageSize
170   )
171 {
172   VIRTIO_MMIO_DEVICE *Device;
173 
174   if (PageSize != EFI_PAGE_SIZE) {
175     return EFI_UNSUPPORTED;
176   }
177 
178   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
179 
180   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_PAGE_SIZE, PageSize);
181 
182   return EFI_SUCCESS;
183 }
184 
185 EFI_STATUS
186 EFIAPI
VirtioMmioSetQueueSel(VIRTIO_DEVICE_PROTOCOL * This,UINT16 Sel)187 VirtioMmioSetQueueSel (
188   VIRTIO_DEVICE_PROTOCOL *This,
189   UINT16                  Sel
190   )
191 {
192   VIRTIO_MMIO_DEVICE *Device;
193 
194   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
195 
196   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_SEL, Sel);
197 
198   return EFI_SUCCESS;
199 }
200 
201 EFI_STATUS
VirtioMmioSetQueueAddress(VIRTIO_DEVICE_PROTOCOL * This,UINT32 Address)202 VirtioMmioSetQueueAddress (
203   VIRTIO_DEVICE_PROTOCOL *This,
204   UINT32                  Address
205   )
206 {
207   VIRTIO_MMIO_DEVICE *Device;
208 
209   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
210 
211   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_QUEUE_PFN, Address);
212 
213   return EFI_SUCCESS;
214 }
215 
216 EFI_STATUS
217 EFIAPI
VirtioMmioSetGuestFeatures(VIRTIO_DEVICE_PROTOCOL * This,UINT32 Features)218 VirtioMmioSetGuestFeatures (
219   VIRTIO_DEVICE_PROTOCOL *This,
220   UINT32                  Features
221   )
222 {
223   VIRTIO_MMIO_DEVICE *Device;
224 
225   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
226 
227   VIRTIO_CFG_WRITE (Device, VIRTIO_MMIO_OFFSET_GUEST_FEATURES, Features);
228 
229   return EFI_SUCCESS;
230 }
231 
232 EFI_STATUS
233 EFIAPI
VirtioMmioDeviceWrite(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINT64 Value)234 VirtioMmioDeviceWrite (
235   IN VIRTIO_DEVICE_PROTOCOL *This,
236   IN UINTN                  FieldOffset,
237   IN UINTN                  FieldSize,
238   IN UINT64                 Value
239   )
240 {
241   UINTN                     DstBaseAddress;
242   VIRTIO_MMIO_DEVICE       *Device;
243 
244   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
245 
246   //
247   // Double-check fieldsize
248   //
249   if ((FieldSize != 1) && (FieldSize != 2) &&
250       (FieldSize != 4) && (FieldSize != 8)) {
251     return EFI_INVALID_PARAMETER;
252   }
253 
254   //
255   // Compute base address
256   //
257   DstBaseAddress = Device->BaseAddress +
258       VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO + FieldOffset;
259 
260   //
261   // The device-specific memory area of Virtio-MMIO can only be written in
262   // byte accesses. This is not currently in the Virtio spec.
263   //
264   MmioWriteBuffer8 (DstBaseAddress, FieldSize, (UINT8*)&Value);
265 
266   return EFI_SUCCESS;
267 }
268 
269 EFI_STATUS
270 EFIAPI
VirtioMmioDeviceRead(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINTN BufferSize,OUT VOID * Buffer)271 VirtioMmioDeviceRead (
272   IN  VIRTIO_DEVICE_PROTOCOL    *This,
273   IN  UINTN                     FieldOffset,
274   IN  UINTN                     FieldSize,
275   IN  UINTN                     BufferSize,
276   OUT VOID                      *Buffer
277   )
278 {
279   UINTN                     SrcBaseAddress;
280   VIRTIO_MMIO_DEVICE       *Device;
281 
282   Device = VIRTIO_MMIO_DEVICE_FROM_VIRTIO_DEVICE (This);
283 
284   //
285   // Parameter validation
286   //
287   ASSERT (FieldSize == BufferSize);
288 
289   //
290   // Double-check fieldsize
291   //
292   if ((FieldSize != 1) && (FieldSize != 2) &&
293       (FieldSize != 4) && (FieldSize != 8)) {
294     return EFI_INVALID_PARAMETER;
295   }
296 
297   //
298   // Compute base address
299   //
300   SrcBaseAddress = Device->BaseAddress +
301       VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO + FieldOffset;
302 
303   //
304   // The device-specific memory area of Virtio-MMIO can only be read in
305   // byte reads. This is not currently in the Virtio spec.
306   //
307   MmioReadBuffer8 (SrcBaseAddress, BufferSize, Buffer);
308 
309   return EFI_SUCCESS;
310 }
311