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