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 UINT32 * DeviceFeatures)102 VirtioPciGetDeviceFeatures (
103   IN VIRTIO_DEVICE_PROTOCOL *This,
104   OUT UINT32                *DeviceFeatures
105   )
106 {
107   VIRTIO_PCI_DEVICE         *Dev;
108 
109   if (DeviceFeatures == NULL) {
110     return EFI_INVALID_PARAMETER;
111   }
112 
113   Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
114 
115   return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_DEVICE_FEATURES, sizeof (UINT32),
116       sizeof (UINT32), DeviceFeatures);
117 }
118 
119 EFI_STATUS
120 EFIAPI
VirtioPciGetQueueAddress(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT32 * QueueAddress)121 VirtioPciGetQueueAddress (
122   IN  VIRTIO_DEVICE_PROTOCOL *This,
123   OUT UINT32                 *QueueAddress
124   )
125 {
126   VIRTIO_PCI_DEVICE         *Dev;
127 
128   if (QueueAddress == NULL) {
129     return EFI_INVALID_PARAMETER;
130   }
131 
132   Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
133 
134   return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_ADDRESS, sizeof (UINT32),
135       sizeof (UINT32), QueueAddress);
136 }
137 
138 EFI_STATUS
139 EFIAPI
VirtioPciGetQueueSize(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT16 * QueueNumMax)140 VirtioPciGetQueueSize (
141   IN  VIRTIO_DEVICE_PROTOCOL  *This,
142   OUT UINT16                  *QueueNumMax
143   )
144 {
145   VIRTIO_PCI_DEVICE         *Dev;
146 
147   if (QueueNumMax == NULL) {
148     return EFI_INVALID_PARAMETER;
149   }
150 
151   Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
152 
153   return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_SIZE, sizeof (UINT16),
154       sizeof (UINT16), QueueNumMax);
155 }
156 
157 EFI_STATUS
158 EFIAPI
VirtioPciGetDeviceStatus(IN VIRTIO_DEVICE_PROTOCOL * This,OUT UINT8 * DeviceStatus)159 VirtioPciGetDeviceStatus (
160   IN  VIRTIO_DEVICE_PROTOCOL  *This,
161   OUT UINT8                   *DeviceStatus
162   )
163 {
164   VIRTIO_PCI_DEVICE         *Dev;
165 
166   if (DeviceStatus == NULL) {
167     return EFI_INVALID_PARAMETER;
168   }
169 
170   Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
171 
172   return VirtioPciIoRead (Dev, VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS,
173       sizeof (UINT8), sizeof (UINT8), DeviceStatus);
174 }
175 
176 EFI_STATUS
177 EFIAPI
VirtioPciSetGuestFeatures(IN VIRTIO_DEVICE_PROTOCOL * This,IN UINT32 Features)178 VirtioPciSetGuestFeatures (
179   IN VIRTIO_DEVICE_PROTOCOL  *This,
180   IN UINT32                   Features
181   )
182 {
183   VIRTIO_PCI_DEVICE *Dev;
184 
185   Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
186 
187   return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_GUEST_FEATURES,
188       sizeof (UINT32), Features);
189 }
190 
191 EFI_STATUS
192 EFIAPI
VirtioPciSetQueueAddress(VIRTIO_DEVICE_PROTOCOL * This,UINT32 Address)193 VirtioPciSetQueueAddress (
194   VIRTIO_DEVICE_PROTOCOL    *This,
195   UINT32                    Address
196   )
197 {
198   VIRTIO_PCI_DEVICE *Dev;
199 
200   Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
201 
202   return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_ADDRESS, sizeof (UINT32),
203       Address);
204 }
205 
206 EFI_STATUS
207 EFIAPI
VirtioPciSetQueueSel(VIRTIO_DEVICE_PROTOCOL * This,UINT16 Sel)208 VirtioPciSetQueueSel (
209   VIRTIO_DEVICE_PROTOCOL    *This,
210   UINT16                    Sel
211   )
212 {
213   VIRTIO_PCI_DEVICE *Dev;
214 
215   Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
216 
217   return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_SELECT, sizeof (UINT16),
218       Sel);
219 }
220 
221 EFI_STATUS
222 EFIAPI
VirtioPciSetQueueAlignment(VIRTIO_DEVICE_PROTOCOL * This,UINT32 Alignment)223 VirtioPciSetQueueAlignment (
224   VIRTIO_DEVICE_PROTOCOL *This,
225   UINT32                  Alignment
226   )
227 {
228   return EFI_SUCCESS;
229 }
230 
231 EFI_STATUS
232 EFIAPI
VirtioPciSetPageSize(VIRTIO_DEVICE_PROTOCOL * This,UINT32 PageSize)233 VirtioPciSetPageSize (
234   VIRTIO_DEVICE_PROTOCOL *This,
235   UINT32                  PageSize
236   )
237 {
238   return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
239 }
240 
241 EFI_STATUS
242 EFIAPI
VirtioPciSetQueueNotify(VIRTIO_DEVICE_PROTOCOL * This,UINT16 Index)243 VirtioPciSetQueueNotify (
244   VIRTIO_DEVICE_PROTOCOL *This,
245   UINT16                 Index
246   )
247 {
248   VIRTIO_PCI_DEVICE *Dev;
249 
250   Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
251 
252   return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_NOTIFY, sizeof (UINT16),
253       Index);
254 }
255 
256 EFI_STATUS
257 EFIAPI
VirtioPciSetQueueSize(VIRTIO_DEVICE_PROTOCOL * This,UINT16 Size)258 VirtioPciSetQueueSize (
259   VIRTIO_DEVICE_PROTOCOL *This,
260   UINT16                 Size
261   )
262 {
263   //
264   // This function is only applicable in Virtio-MMIO.
265   // (The QueueSize field is read-only in Virtio proper (PCI))
266   //
267   return EFI_SUCCESS;
268 }
269 
270 EFI_STATUS
271 EFIAPI
VirtioPciSetDeviceStatus(VIRTIO_DEVICE_PROTOCOL * This,UINT8 DeviceStatus)272 VirtioPciSetDeviceStatus (
273   VIRTIO_DEVICE_PROTOCOL *This,
274   UINT8                  DeviceStatus
275   )
276 {
277   VIRTIO_PCI_DEVICE *Dev;
278 
279   Dev = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (This);
280 
281   return VirtioPciIoWrite (Dev, VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS,
282       sizeof (UINT8), DeviceStatus);
283 }
284