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