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