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