]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
ShellPkg/for: Fix potential null pointer deference
[mirror_edk2.git] / OvmfPkg / VirtioNetDxe / SnpSharedHelpers.c
1 /** @file
2
3 Helper functions used by at least two Simple Network Protocol methods.
4
5 Copyright (C) 2013, Red Hat, Inc.
6
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include <Library/MemoryAllocationLib.h>
18
19 #include "VirtioNet.h"
20
21 //
22 // The user structure for the ordered collection that will track the mapping
23 // info of the packets queued in TxRing
24 //
25 typedef struct {
26 VOID *Buffer;
27 EFI_PHYSICAL_ADDRESS DeviceAddress; // lookup key for reverse mapping
28 VOID *BufMap;
29 } TX_BUF_MAP_INFO;
30
31 /**
32 Release RX and TX resources on the boundary of the
33 EfiSimpleNetworkInitialized state.
34
35 These functions contribute to rolling back a partial, failed initialization
36 of the virtio-net SNP driver instance, or to shutting down a fully
37 initialized, running instance.
38
39 They are only callable by the VirtioNetInitialize() and the
40 VirtioNetShutdown() SNP methods. See the state diagram in "VirtioNet.h".
41
42 @param[in,out] Dev The VNET_DEV driver instance being shut down, or whose
43 partial, failed initialization is being rolled back.
44 */
45
46 VOID
47 EFIAPI
48 VirtioNetShutdownRx (
49 IN OUT VNET_DEV *Dev
50 )
51 {
52 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RxBufMap);
53 Dev->VirtIo->FreeSharedPages (
54 Dev->VirtIo,
55 Dev->RxBufNrPages,
56 Dev->RxBuf
57 );
58 }
59
60
61 VOID
62 EFIAPI
63 VirtioNetShutdownTx (
64 IN OUT VNET_DEV *Dev
65 )
66 {
67 ORDERED_COLLECTION_ENTRY *Entry, *Entry2;
68 TX_BUF_MAP_INFO *TxBufMapInfo;
69 VOID *UserStruct;
70
71 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->TxSharedReqMap);
72 Dev->VirtIo->FreeSharedPages (
73 Dev->VirtIo,
74 EFI_SIZE_TO_PAGES (sizeof *(Dev->TxSharedReq)),
75 Dev->TxSharedReq
76 );
77
78 for (Entry = OrderedCollectionMin (Dev->TxBufCollection);
79 Entry != NULL;
80 Entry = Entry2) {
81 Entry2 = OrderedCollectionNext (Entry);
82 OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
83 TxBufMapInfo = UserStruct;
84 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);
85 FreePool (TxBufMapInfo);
86 }
87 OrderedCollectionUninit (Dev->TxBufCollection);
88
89 FreePool (Dev->TxFreeStack);
90 }
91
92 /**
93 Release TX and RX VRING resources.
94
95 @param[in,out] Dev The VNET_DEV driver instance which was using
96 the ring.
97 @param[in,out] Ring The virtio ring to clean up.
98 @param[in] RingMap A token return from the VirtioRingMap()
99 */
100 VOID
101 EFIAPI
102 VirtioNetUninitRing (
103 IN OUT VNET_DEV *Dev,
104 IN OUT VRING *Ring,
105 IN VOID *RingMap
106 )
107 {
108 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RingMap);
109 VirtioRingUninit (Dev->VirtIo, Ring);
110 }
111
112
113 /**
114 Map Caller-supplied TxBuf buffer to the device-mapped address
115
116 @param[in] Dev The VNET_DEV driver instance which wants to
117 map the Tx packet.
118 @param[in] Buffer The system physical address of TxBuf
119 @param[in] NumberOfBytes Number of bytes to map
120 @param[out] DeviceAddress The resulting device address for the bus
121 master access.
122
123 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to
124 a lack of resources.
125 @return Status codes from
126 VirtioMapAllBytesInSharedBuffer()
127 @retval EFI_SUCCESS Caller-supplied buffer is succesfully mapped.
128 */
129 EFI_STATUS
130 EFIAPI
131 VirtioNetMapTxBuf (
132 IN VNET_DEV *Dev,
133 IN VOID *Buffer,
134 IN UINTN NumberOfBytes,
135 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
136 )
137 {
138 EFI_STATUS Status;
139 TX_BUF_MAP_INFO *TxBufMapInfo;
140 EFI_PHYSICAL_ADDRESS Address;
141 VOID *Mapping;
142
143 TxBufMapInfo = AllocatePool (sizeof (*TxBufMapInfo));
144 if (TxBufMapInfo == NULL) {
145 return EFI_OUT_OF_RESOURCES;
146 }
147
148 Status = VirtioMapAllBytesInSharedBuffer (
149 Dev->VirtIo,
150 VirtioOperationBusMasterRead,
151 Buffer,
152 NumberOfBytes,
153 &Address,
154 &Mapping
155 );
156 if (EFI_ERROR (Status)) {
157 goto FreeTxBufMapInfo;
158 }
159
160 TxBufMapInfo->Buffer = Buffer;
161 TxBufMapInfo->DeviceAddress = Address;
162 TxBufMapInfo->BufMap = Mapping;
163
164 Status = OrderedCollectionInsert (
165 Dev->TxBufCollection,
166 NULL,
167 TxBufMapInfo
168 );
169 switch (Status) {
170 case EFI_OUT_OF_RESOURCES:
171 goto UnmapTxBuf;
172 case EFI_ALREADY_STARTED:
173 //
174 // This should never happen: it implies
175 //
176 // - an identity-mapping VIRTIO_DEVICE_PROTOCOL.MapSharedBuffer()
177 // implementation -- which is fine,
178 //
179 // - and an SNP client that queues multiple instances of the exact same
180 // buffer address with SNP.Transmit() -- which is undefined behavior,
181 // based on the TxBuf language in UEFI-2.7,
182 // EFI_SIMPLE_NETWORK.GetStatus().
183 //
184 ASSERT (FALSE);
185 Status = EFI_INVALID_PARAMETER;
186 goto UnmapTxBuf;
187 default:
188 ASSERT_EFI_ERROR (Status);
189 break;
190 }
191
192 *DeviceAddress = Address;
193 return EFI_SUCCESS;
194
195 UnmapTxBuf:
196 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Mapping);
197
198 FreeTxBufMapInfo:
199 FreePool (TxBufMapInfo);
200 return Status;
201 }
202
203 /**
204 Unmap (aka reverse mapping) device mapped TxBuf buffer to the system
205 physical address
206
207 @param[in] Dev The VNET_DEV driver instance which wants to
208 reverse- and unmap the Tx packet.
209 @param[out] Buffer The system physical address of TxBuf
210 @param[in] DeviceAddress The device address for the TxBuf
211
212 @retval EFI_INVALID_PARAMETER The DeviceAddress is not mapped
213 @retval EFI_SUCCESS The TxBuf at DeviceAddress has been unmapped,
214 and Buffer has been set to TxBuf's system
215 physical address.
216
217 */
218 EFI_STATUS
219 EFIAPI
220 VirtioNetUnmapTxBuf (
221 IN VNET_DEV *Dev,
222 OUT VOID **Buffer,
223 IN EFI_PHYSICAL_ADDRESS DeviceAddress
224 )
225 {
226 ORDERED_COLLECTION_ENTRY *Entry;
227 TX_BUF_MAP_INFO *TxBufMapInfo;
228 VOID *UserStruct;
229
230 Entry = OrderedCollectionFind (Dev->TxBufCollection, &DeviceAddress);
231 if (Entry == NULL) {
232 return EFI_INVALID_PARAMETER;
233 }
234
235 OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
236
237 TxBufMapInfo = UserStruct;
238
239 *Buffer = TxBufMapInfo->Buffer;
240 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);
241 FreePool (TxBufMapInfo);
242
243 return EFI_SUCCESS;
244 }
245
246 /**
247 Comparator function for two TX_BUF_MAP_INFO objects.
248
249 @param[in] UserStruct1 Pointer to the first TX_BUF_MAP_INFO object.
250
251 @param[in] UserStruct2 Pointer to the second TX_BUF_MAP_INFO object.
252
253 @retval <0 If UserStruct1 compares less than UserStruct2.
254
255 @retval 0 If UserStruct1 compares equal to UserStruct2.
256
257 @retval >0 If UserStruct1 compares greater than UserStruct2.
258 */
259 INTN
260 EFIAPI
261 VirtioNetTxBufMapInfoCompare (
262 IN CONST VOID *UserStruct1,
263 IN CONST VOID *UserStruct2
264 )
265 {
266 CONST TX_BUF_MAP_INFO *MapInfo1;
267 CONST TX_BUF_MAP_INFO *MapInfo2;
268
269 MapInfo1 = UserStruct1;
270 MapInfo2 = UserStruct2;
271
272 return MapInfo1->DeviceAddress < MapInfo2->DeviceAddress ? -1 :
273 MapInfo1->DeviceAddress > MapInfo2->DeviceAddress ? 1 :
274 0;
275 }
276
277 /**
278 Compare a standalone DeviceAddress against a TX_BUF_MAP_INFO object
279 containing an embedded DeviceAddress.
280
281 @param[in] StandaloneKey Pointer to DeviceAddress, which has type
282 EFI_PHYSICAL_ADDRESS.
283
284 @param[in] UserStruct Pointer to the TX_BUF_MAP_INFO object with the
285 embedded DeviceAddress.
286
287 @retval <0 If StandaloneKey compares less than UserStruct's key.
288
289 @retval 0 If StandaloneKey compares equal to UserStruct's key.
290
291 @retval >0 If StandaloneKey compares greater than UserStruct's key.
292 **/
293 INTN
294 EFIAPI
295 VirtioNetTxBufDeviceAddressCompare (
296 IN CONST VOID *StandaloneKey,
297 IN CONST VOID *UserStruct
298 )
299 {
300 CONST EFI_PHYSICAL_ADDRESS *DeviceAddress;
301 CONST TX_BUF_MAP_INFO *MapInfo;
302
303 DeviceAddress = StandaloneKey;
304 MapInfo = UserStruct;
305
306 return *DeviceAddress < MapInfo->DeviceAddress ? -1 :
307 *DeviceAddress > MapInfo->DeviceAddress ? 1 :
308 0;
309 }