1 /** @file
2
3 This driver produces Virtio Device Protocol instances for Virtio PCI 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 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/UefiLib.h>
23 #include "VirtioPciDevice.h"
24
25 /**
26
27 Read a word from Region 0 of the device specified by VirtIo Device protocol.
28
29 The function implements the ReadDevice protocol member of
30 VIRTIO_DEVICE_PROTOCOL.
31
32 @param[in] This VirtIo Device protocol.
33
34 @param[in] FieldOffset Source offset.
35
36 @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.
37
38 @param[in] BufferSize Number of bytes available in the target buffer. Must
39 equal FieldSize.
40
41 @param[out] Buffer Target buffer.
42
43
44 @return Status code returned by PciIo->Io.Read().
45
46 **/
47 EFI_STATUS
48 EFIAPI
VirtioPciDeviceRead(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINTN BufferSize,OUT VOID * Buffer)49 VirtioPciDeviceRead (
50 IN VIRTIO_DEVICE_PROTOCOL *This,
51 IN UINTN FieldOffset,
52 IN UINTN FieldSize,
53 IN UINTN BufferSize,
54 OUT VOID *Buffer
55 )
56 {
57 VIRTIO_PCI_DEVICE *Dev;
58
59 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
60
61 return VirtioPciIoRead (Dev,
62 Dev->DeviceSpecificConfigurationOffset + FieldOffset,
63 FieldSize, BufferSize, Buffer);
64 }
65
66 /**
67
68 Write a word into Region 0 of the device specified by VirtIo Device protocol.
69
70 @param[in] This VirtIo Device protocol.
71
72 @param[in] FieldOffset Destination offset.
73
74 @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.
75
76 @param[in] Value Little endian value to write, converted to UINT64.
77 The least significant FieldSize bytes will be used.
78
79
80 @return Status code returned by PciIo->Io.Write().
81
82 **/
83 EFI_STATUS
84 EFIAPI
VirtioPciDeviceWrite(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINT64 Value)85 VirtioPciDeviceWrite (
86 IN VIRTIO_DEVICE_PROTOCOL *This,
87 IN UINTN FieldOffset,
88 IN UINTN FieldSize,
89 IN UINT64 Value
90 )
91 {
92 VIRTIO_PCI_DEVICE *Dev;
93
94 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
95
96 return VirtioPciIoWrite (Dev,
97 Dev->DeviceSpecificConfigurationOffset + FieldOffset, FieldSize, Value);
98 }
99
100 EFI_STATUS
101 EFIAPI
VirtioPciGetDeviceFeatures(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT64 * DeviceFeatures)102 VirtioPciGetDeviceFeatures (
103 IN VIRTIO_DEVICE_PROTOCOL *This,
104 OUT UINT64 *DeviceFeatures
105 )
106 {
107 VIRTIO_PCI_DEVICE *Dev;
108 EFI_STATUS Status;
109 UINT32 Features32;
110
111 if (DeviceFeatures == NULL) {
112 return EFI_INVALID_PARAMETER;
113 }
114
115 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
116
117 Status = VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_DEVICE_FEATURES,
118 sizeof (UINT32), sizeof (UINT32), &Features32);
119 if (!EFI_ERROR (Status)) {
120 *DeviceFeatures = Features32;
121 }
122 return Status;
123 }
124
125 EFI_STATUS
126 EFIAPI
VirtioPciGetQueueSize(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT16 * QueueNumMax)127 VirtioPciGetQueueSize (
128 IN VIRTIO_DEVICE_PROTOCOL *This,
129 OUT UINT16 *QueueNumMax
130 )
131 {
132 VIRTIO_PCI_DEVICE *Dev;
133
134 if (QueueNumMax == NULL) {
135 return EFI_INVALID_PARAMETER;
136 }
137
138 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
139
140 return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_SIZE, sizeof (UINT16),
141 sizeof (UINT16), QueueNumMax);
142 }
143
144 EFI_STATUS
145 EFIAPI
VirtioPciGetDeviceStatus(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT8 * DeviceStatus)146 VirtioPciGetDeviceStatus (
147 IN VIRTIO_DEVICE_PROTOCOL *This,
148 OUT UINT8 *DeviceStatus
149 )
150 {
151 VIRTIO_PCI_DEVICE *Dev;
152
153 if (DeviceStatus == NULL) {
154 return EFI_INVALID_PARAMETER;
155 }
156
157 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
158
159 return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS,
160 sizeof (UINT8), sizeof (UINT8), DeviceStatus);
161 }
162
163 EFI_STATUS
164 EFIAPI
VirtioPciSetGuestFeatures(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT64 Features)165 VirtioPciSetGuestFeatures (
166 IN VIRTIO_DEVICE_PROTOCOL *This,
167 IN UINT64 Features
168 )
169 {
170 VIRTIO_PCI_DEVICE *Dev;
171
172 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
173
174 if (Features > MAX_UINT32) {
175 return EFI_UNSUPPORTED;
176 }
177 return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_GUEST_FEATURES,
178 sizeof (UINT32), Features);
179 }
180
181 EFI_STATUS
182 EFIAPI
VirtioPciSetQueueAddress(IN VIRTIO_DEVICE_PROTOCOL * This,IN VRING * Ring)183 VirtioPciSetQueueAddress (
184 IN VIRTIO_DEVICE_PROTOCOL *This,
185 IN VRING *Ring
186 )
187 {
188 VIRTIO_PCI_DEVICE *Dev;
189
190 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
191
192 return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_ADDRESS, sizeof (UINT32),
193 (UINT32)((UINTN)Ring->Base >> EFI_PAGE_SHIFT));
194 }
195
196 EFI_STATUS
197 EFIAPI
VirtioPciSetQueueSel(VIRTIO_DEVICE_PROTOCOL * This,UINT16 Sel)198 VirtioPciSetQueueSel (
199 VIRTIO_DEVICE_PROTOCOL *This,
200 UINT16 Sel
201 )
202 {
203 VIRTIO_PCI_DEVICE *Dev;
204
205 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
206
207 return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_SELECT, sizeof (UINT16),
208 Sel);
209 }
210
211 EFI_STATUS
212 EFIAPI
VirtioPciSetQueueAlignment(VIRTIO_DEVICE_PROTOCOL * This,UINT32 Alignment)213 VirtioPciSetQueueAlignment (
214 VIRTIO_DEVICE_PROTOCOL *This,
215 UINT32 Alignment
216 )
217 {
218 return EFI_SUCCESS;
219 }
220
221 EFI_STATUS
222 EFIAPI
VirtioPciSetPageSize(VIRTIO_DEVICE_PROTOCOL * This,UINT32 PageSize)223 VirtioPciSetPageSize (
224 VIRTIO_DEVICE_PROTOCOL *This,
225 UINT32 PageSize
226 )
227 {
228 return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
229 }
230
231 EFI_STATUS
232 EFIAPI
VirtioPciSetQueueNotify(VIRTIO_DEVICE_PROTOCOL * This,UINT16 Index)233 VirtioPciSetQueueNotify (
234 VIRTIO_DEVICE_PROTOCOL *This,
235 UINT16 Index
236 )
237 {
238 VIRTIO_PCI_DEVICE *Dev;
239
240 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
241
242 return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_NOTIFY, sizeof (UINT16),
243 Index);
244 }
245
246 EFI_STATUS
247 EFIAPI
VirtioPciSetQueueSize(VIRTIO_DEVICE_PROTOCOL * This,UINT16 Size)248 VirtioPciSetQueueSize (
249 VIRTIO_DEVICE_PROTOCOL *This,
250 UINT16 Size
251 )
252 {
253 //
254 // This function is only applicable in Virtio-MMIO.
255 // (The QueueSize field is read-only in Virtio proper (PCI))
256 //
257 return EFI_SUCCESS;
258 }
259
260 EFI_STATUS
261 EFIAPI
VirtioPciSetDeviceStatus(VIRTIO_DEVICE_PROTOCOL * This,UINT8 DeviceStatus)262 VirtioPciSetDeviceStatus (
263 VIRTIO_DEVICE_PROTOCOL *This,
264 UINT8 DeviceStatus
265 )
266 {
267 VIRTIO_PCI_DEVICE *Dev;
268
269 Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
270
271 return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS,
272 sizeof (UINT8), DeviceStatus);
273 }
274