]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/SnpDxe/Callback.c
NetworkPkg/SnpDxe: Prevent invalid PCI BAR access
[mirror_edk2.git] / NetworkPkg / SnpDxe / Callback.c
1 /** @file
2 This file contains the callback routines for undi3.1.
3 the callback routines for Undi3.1 have an extra parameter UniqueId which
4 stores the interface context for the NIC that snp is trying to talk.
5
6 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) Microsoft Corporation.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include "Snp.h"
13
14 /**
15 Acquire or release a lock of the exclusive access to a critical section of the
16 code/data.
17
18 This is a callback routine supplied to UNDI3.1 at undi_start time.
19 New callbacks for 3.1: there won't be a virtual2physical callback for UNDI 3.1
20 because undi3.1 uses the MemMap call to map the required address by itself!
21
22 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
23 store Undi interface context (Undi does not read or write
24 this variable).
25 @param Enable Non-zero indicates acquire; Zero indicates release.
26
27 **/
28 VOID
29 EFIAPI
30 SnpUndi32CallbackBlock (
31 IN UINT64 UniqueId,
32 IN UINT32 Enable
33 )
34 {
35 SNP_DRIVER *Snp;
36
37 Snp = (SNP_DRIVER *) (UINTN) UniqueId;
38 //
39 // tcpip was calling snp at tpl_notify and when we acquire a lock that was
40 // created at a lower level (TPL_CALLBACK) it gives an assert!
41 //
42 if (Enable != 0) {
43 EfiAcquireLock (&Snp->Lock);
44 } else {
45 EfiReleaseLock (&Snp->Lock);
46 }
47 }
48
49 /**
50 Delay MicroSeconds of micro seconds.
51
52 This is a callback routine supplied to UNDI at undi_start time.
53
54 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
55 store Undi interface context (Undi does not read or write
56 this variable).
57 @param MicroSeconds Number of micro seconds to pause, usually multiple of 10.
58
59 **/
60 VOID
61 EFIAPI
62 SnpUndi32CallbackDelay (
63 IN UINT64 UniqueId,
64 IN UINT64 MicroSeconds
65 )
66 {
67 if (MicroSeconds != 0) {
68 gBS->Stall ((UINTN) MicroSeconds);
69 }
70 }
71
72 /**
73 IO routine for UNDI3.1.
74
75 This is a callback routine supplied to UNDI at undi_start time.
76
77 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this
78 to store Undi interface context (Undi does not read or
79 write this variable).
80 @param ReadOrWrite Indicates read or write, IO or Memory.
81 @param NumBytes Number of bytes to read or write.
82 @param MemOrPortAddr IO or memory address to read from or write to.
83 @param BufferPtr Memory location to read into or that contains the bytes
84 to write.
85
86 **/
87 VOID
88 EFIAPI
89 SnpUndi32CallbackMemio (
90 IN UINT64 UniqueId,
91 IN UINT8 ReadOrWrite,
92 IN UINT8 NumBytes,
93 IN UINT64 MemOrPortAddr,
94 IN OUT UINT64 BufferPtr
95 )
96 {
97 SNP_DRIVER *Snp;
98 EFI_PCI_IO_PROTOCOL_WIDTH Width;
99
100 Snp = (SNP_DRIVER *) (UINTN) UniqueId;
101
102 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
103 switch (NumBytes) {
104 case 2:
105 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
106 break;
107
108 case 4:
109 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
110 break;
111
112 case 8:
113 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
114 break;
115 }
116
117 switch (ReadOrWrite) {
118 case PXE_IO_READ:
119 ASSERT (Snp->IoBarIndex < PCI_MAX_BAR);
120 if (Snp->IoBarIndex < PCI_MAX_BAR) {
121 Snp->PciIo->Io.Read (
122 Snp->PciIo,
123 Width,
124 Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
125 MemOrPortAddr,
126 1, // count
127 (VOID *) (UINTN) BufferPtr
128 );
129 }
130 break;
131
132 case PXE_IO_WRITE:
133 ASSERT (Snp->IoBarIndex < PCI_MAX_BAR);
134 if (Snp->IoBarIndex < PCI_MAX_BAR) {
135 Snp->PciIo->Io.Write (
136 Snp->PciIo,
137 Width,
138 Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
139 MemOrPortAddr,
140 1, // count
141 (VOID *) (UINTN) BufferPtr
142 );
143 }
144 break;
145
146 case PXE_MEM_READ:
147 ASSERT (Snp->MemoryBarIndex < PCI_MAX_BAR);
148 if (Snp->MemoryBarIndex < PCI_MAX_BAR) {
149 Snp->PciIo->Mem.Read (
150 Snp->PciIo,
151 Width,
152 Snp->MemoryBarIndex, // BAR 0, Memory base address
153 MemOrPortAddr,
154 1, // count
155 (VOID *) (UINTN) BufferPtr
156 );
157 }
158 break;
159
160 case PXE_MEM_WRITE:
161 ASSERT (Snp->MemoryBarIndex < PCI_MAX_BAR);
162 if (Snp->MemoryBarIndex < PCI_MAX_BAR) {
163 Snp->PciIo->Mem.Write (
164 Snp->PciIo,
165 Width,
166 Snp->MemoryBarIndex, // BAR 0, Memory base address
167 MemOrPortAddr,
168 1, // count
169 (VOID *) (UINTN) BufferPtr
170 );
171 }
172 break;
173 }
174
175 return ;
176 }
177
178 /**
179 Map a CPU address to a device address.
180
181 This is a callback routine supplied to UNDI at undi_start time.
182
183 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
184 store Undi interface context (Undi does not read or write
185 this variable).
186 @param CpuAddr Virtual address to be mapped.
187 @param NumBytes Size of memory to be mapped.
188 @param Direction Direction of data flow for this memory's usage:
189 cpu->device, device->cpu or both ways.
190 @param DeviceAddrPtr Pointer to return the mapped device address.
191
192 **/
193 VOID
194 EFIAPI
195 SnpUndi32CallbackMap (
196 IN UINT64 UniqueId,
197 IN UINT64 CpuAddr,
198 IN UINT32 NumBytes,
199 IN UINT32 Direction,
200 IN OUT UINT64 DeviceAddrPtr
201 )
202 {
203 EFI_PHYSICAL_ADDRESS *DevAddrPtr;
204 EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;
205 UINTN BuffSize;
206 SNP_DRIVER *Snp;
207 UINTN Index;
208 EFI_STATUS Status;
209
210 BuffSize = (UINTN) NumBytes;
211 Snp = (SNP_DRIVER *) (UINTN) UniqueId;
212 DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;
213
214 if (CpuAddr == 0) {
215 *DevAddrPtr = 0;
216 return ;
217 }
218
219 switch (Direction) {
220 case TO_AND_FROM_DEVICE:
221 DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;
222 break;
223
224 case FROM_DEVICE:
225 DirectionFlag = EfiPciIoOperationBusMasterWrite;
226 break;
227
228 case TO_DEVICE:
229 DirectionFlag = EfiPciIoOperationBusMasterRead;
230 break;
231
232 default:
233 *DevAddrPtr = 0;
234 //
235 // any non zero indicates error!
236 //
237 return ;
238 }
239 //
240 // find an unused map_list entry
241 //
242 for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
243 if (Snp->MapList[Index].VirtualAddress == 0) {
244 break;
245 }
246 }
247
248 if (Index >= MAX_MAP_LENGTH) {
249 DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));
250 *DevAddrPtr = 0;
251 return ;
252 }
253
254 Snp->MapList[Index].VirtualAddress = (EFI_PHYSICAL_ADDRESS) CpuAddr;
255
256 Status = Snp->PciIo->Map (
257 Snp->PciIo,
258 DirectionFlag,
259 (VOID *) (UINTN) CpuAddr,
260 &BuffSize,
261 DevAddrPtr,
262 &(Snp->MapList[Index].MapCookie)
263 );
264 if (Status != EFI_SUCCESS) {
265 *DevAddrPtr = 0;
266 Snp->MapList[Index].VirtualAddress = 0;
267 }
268
269 return ;
270 }
271
272 /**
273 Unmap an address that was previously mapped using map callback.
274
275 This is a callback routine supplied to UNDI at undi_start time.
276
277 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
278 store. Undi interface context (Undi does not read or write
279 this variable).
280 @param CpuAddr Virtual address that was mapped.
281 @param NumBytes Size of memory mapped.
282 @param Direction Direction of data flow for this memory's usage:
283 cpu->device, device->cpu or both ways.
284 @param DeviceAddr The mapped device address.
285
286 **/
287 VOID
288 EFIAPI
289 SnpUndi32CallbackUnmap (
290 IN UINT64 UniqueId,
291 IN UINT64 CpuAddr,
292 IN UINT32 NumBytes,
293 IN UINT32 Direction,
294 IN UINT64 DeviceAddr
295 )
296 {
297 SNP_DRIVER *Snp;
298 UINT16 Index;
299
300 Snp = (SNP_DRIVER *) (UINTN) UniqueId;
301
302 for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
303 if (Snp->MapList[Index].VirtualAddress == CpuAddr) {
304 break;
305 }
306 }
307
308 if (Index >= MAX_MAP_LENGTH) {
309 DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));
310 return ;
311 }
312
313 Snp->PciIo->Unmap (Snp->PciIo, Snp->MapList[Index].MapCookie);
314 Snp->MapList[Index].VirtualAddress = 0;
315 Snp->MapList[Index].MapCookie = NULL;
316 return ;
317 }
318
319 /**
320 Synchronize the virtual buffer contents with the mapped buffer contents.
321
322 This is a callback routine supplied to UNDI at undi_start time. The virtual
323 and mapped buffers need not correspond to the same physical memory (especially
324 if the virtual address is > 4GB). Depending on the direction for which the
325 buffer is mapped, undi will need to synchronize their contents whenever it
326 writes to/reads from the buffer using either the cpu address or the device
327 address.
328 EFI does not provide a sync call since virt=physical, we should just do the
329 synchronization ourselves here.
330
331 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
332 store Undi interface context (Undi does not read or write
333 this variable).
334 @param CpuAddr Virtual address that was mapped.
335 @param NumBytes Size of memory mapped.
336 @param Direction Direction of data flow for this memory's usage:
337 cpu->device, device->cpu or both ways.
338 @param DeviceAddr The mapped device address.
339
340 **/
341 VOID
342 EFIAPI
343 SnpUndi32CallbackSync (
344 IN UINT64 UniqueId,
345 IN UINT64 CpuAddr,
346 IN UINT32 NumBytes,
347 IN UINT32 Direction,
348 IN UINT64 DeviceAddr
349 )
350 {
351 if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {
352 return ;
353
354 }
355
356 switch (Direction) {
357 case FROM_DEVICE:
358 CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);
359 break;
360
361 case TO_DEVICE:
362 CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);
363 break;
364 }
365
366 return ;
367 }