]> git.proxmox.com Git - mirror_edk2.git/blame - Vlv2TbltDevicePkg/PlatformDxe/PciDevice.c
MdeModulePkg: Fix use-after-free error in InstallConfigurationTable()
[mirror_edk2.git] / Vlv2TbltDevicePkg / PlatformDxe / PciDevice.c
CommitLineData
3cbfba02
DW
1/** @file\r
2\r
3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>\r
4 \r\r
5 This program and the accompanying materials are licensed and made available under\r\r
6 the terms and conditions of the BSD License that accompanies this distribution. \r\r
7 The full text of the license may be found at \r\r
8 http://opensource.org/licenses/bsd-license.php. \r\r
9 \r\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r\r
12 \r\r
13\r
14Module Name:\r
15\r
16\r
17 PciDevice.c\r
18\r
19Abstract:\r
20\r
21 Platform Initialization Driver.\r
22\r
23Revision History\r
24\r
25--*/\r
26\r
27#include "PlatformDxe.h"\r
28#include "Library/DxeServicesTableLib.h"\r
29#include "PciBus.h"\r
30#include "Guid/PciLanInfo.h"\r
31\r
32extern VOID *mPciLanInfo;\r
33extern UINTN mPciLanCount;\r
34\r
35extern EFI_HANDLE mImageHandle;\r
36extern SYSTEM_CONFIGURATION mSystemConfiguration;\r
37\r
38\r
39VOID *mPciRegistration;\r
40#define NCR_VENDOR_ID 0x1000\r
41#define ATI_VENDOR_ID 0x1002\r
42#define INTEL_VENDOR_ID 0x8086\r
43#define ATI_RV423_ID 0x5548\r
44#define ATI_RV423_ID2 0x5d57\r
45#define ATI_RV380_ID 0x3e50\r
46#define ATI_RV370_ID 0x5b60\r
47#define SI_VENDOR_ID 0x1095\r
48#define SI_SISATA_ID 0x3114\r
49#define SI_SIRAID_PCIUNL 0x40\r
50#define INTEL_82573E_IDER 0x108D\r
51\r
52typedef struct {\r
53 UINT8 ClassCode;\r
54 UINT8 SubClassCode;\r
55 UINT16 VendorId;\r
56 UINT16 DeviceId;\r
57} BAD_DEVICE_TABLE;\r
58\r
59BAD_DEVICE_TABLE BadDeviceTable[] = {\r
60 {(UINT8)PCI_CLASS_MASS_STORAGE,(UINT8)PCI_CLASS_MASS_STORAGE_SCSI,(UINT16)NCR_VENDOR_ID, (UINT16)0xffff}, // Any NCR cards\r
61 {(UINT8)PCI_CLASS_MASS_STORAGE,(UINT8)PCI_CLASS_MASS_STORAGE_IDE,(UINT16)INTEL_VENDOR_ID, (UINT16)INTEL_82573E_IDER}, // Intel i82573E Tekoa GBit Lan IDE-R\r
62 {(UINT8)0xff,(UINT8)0xff,(UINT16)0xffff,(UINT16)0xffff}\r
63 };\r
64\r
65EFI_STATUS\r
66PciBusDriverHook (\r
67 )\r
68{\r
69 EFI_STATUS Status;\r
70 EFI_EVENT FilterEvent;\r
71\r
72 //\r
73 // Register for callback to PCI I/O protocol\r
74 //\r
75 Status = gBS->CreateEvent (\r
76 EVT_NOTIFY_SIGNAL,\r
77 TPL_CALLBACK,\r
78 PciBusEvent,\r
79 NULL,\r
80 &FilterEvent\r
81 );\r
82 ASSERT_EFI_ERROR(Status);\r
83\r
84 //\r
85 // Register for protocol notifications on this event\r
86 //\r
87 Status = gBS->RegisterProtocolNotify (\r
88 &gEfiPciIoProtocolGuid,\r
89 FilterEvent,\r
90 &mPciRegistration\r
91 );\r
92 ASSERT_EFI_ERROR (Status);\r
93\r
94 return EFI_SUCCESS;\r
95}\r
96\r
97VOID\r
98InitBadBars(\r
99 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
100 IN UINT16 VendorId,\r
101 IN UINT16 DeviceId\r
102 )\r
103{\r
104\r
3cbfba02
DW
105 UINT64 BaseAddress = 0;\r
106 UINT64 TempBaseAddress = 0;\r
107 UINT8 RevId = 0;\r
108 UINT32 Bar;\r
109 UINT64 IoSize;\r
110 UINT64 MemSize;\r
111 UINTN MemSizeBits;\r
112\r
3cbfba02
DW
113 switch ( VendorId) {\r
114 case ATI_VENDOR_ID:\r
115 //\r
116 // ATI fix-ups. At this time all ATI cards in BadDeviceTable\r
117 // have same problem in that OPROM BAR needs to be increased.\r
118 //\r
119 Bar = 0x30 ;\r
120 //\r
121 // Get original BAR address\r
122 //\r
076d0d64
GL
123 PciIo->Pci.Read (\r
124 PciIo,\r
125 EfiPciIoWidthUint32,\r
126 Bar,\r
127 1,\r
128 (VOID *) &BaseAddress\r
129 );\r
3cbfba02
DW
130 //\r
131 // Find BAR size\r
132 //\r
133 TempBaseAddress = 0xffffffff;\r
076d0d64
GL
134 PciIo->Pci.Write (\r
135 PciIo,\r
136 EfiPciIoWidthUint32,\r
137 Bar,\r
138 1,\r
139 (VOID *) &TempBaseAddress\r
140 );\r
141 PciIo->Pci.Read (\r
142 PciIo,\r
143 EfiPciIoWidthUint32,\r
144 Bar,\r
145 1,\r
146 (VOID *) &TempBaseAddress\r
147 );\r
3cbfba02
DW
148 TempBaseAddress &= 0xfffffffe;\r
149 MemSize = 1;\r
150 while ((TempBaseAddress & 0x01) == 0) {\r
151 TempBaseAddress = TempBaseAddress >> 1;\r
152 MemSize = MemSize << 1;\r
153 }\r
154\r
155 //\r
156 // Free up allocated memory memory and re-allocate with increased size.\r
157 //\r
076d0d64
GL
158 gDS->FreeMemorySpace (\r
159 BaseAddress,\r
160 MemSize\r
161 );\r
3cbfba02
DW
162 //\r
163 // Force new alignment\r
164 //\r
165 MemSize = 0x8000000;\r
166 MemSizeBits = 28;\r
167\r
076d0d64
GL
168 gDS->AllocateMemorySpace (\r
169 EfiGcdAllocateAnySearchBottomUp,\r
170 EfiGcdMemoryTypeMemoryMappedIo,\r
171 MemSizeBits, // Alignment\r
172 MemSize,\r
173 &BaseAddress,\r
174 mImageHandle,\r
175 NULL\r
176 );\r
177 PciIo->Pci.Write (\r
178 PciIo,\r
179 EfiPciIoWidthUint32,\r
180 Bar,\r
181 1,\r
182 (VOID *) &BaseAddress\r
183 );\r
3cbfba02
DW
184\r
185 break;\r
186 case NCR_VENDOR_ID:\r
187#define MIN_NCR_IO_SIZE 0x800\r
188#define NCR_GRAN 11 // 2**11 = 0x800\r
189 //\r
190 // NCR SCSI cards like 8250S lie about IO needed. Assign as least 0x80.\r
191 //\r
192 for (Bar = 0x10; Bar < 0x28; Bar+= 4) {\r
193\r
076d0d64
GL
194 PciIo->Pci.Read (\r
195 PciIo,\r
196 EfiPciIoWidthUint32,\r
197 Bar,\r
198 1,\r
199 (VOID *) &BaseAddress\r
200 );\r
3cbfba02
DW
201 if (BaseAddress && 0x01) {\r
202 TempBaseAddress = 0xffffffff;\r
076d0d64
GL
203 PciIo->Pci.Write (\r
204 PciIo,\r
205 EfiPciIoWidthUint32,\r
206 Bar,\r
207 1,\r
208 (VOID *) &TempBaseAddress\r
209 );\r
3cbfba02
DW
210 TempBaseAddress &= 0xfffffffc;\r
211 IoSize = 1;\r
212 while ((TempBaseAddress & 0x01) == 0) {\r
213 TempBaseAddress = TempBaseAddress >> 1;\r
214 IoSize = IoSize << 1;\r
215 }\r
216 if (IoSize < MIN_NCR_IO_SIZE) {\r
076d0d64
GL
217 gDS->FreeIoSpace (\r
218 BaseAddress,\r
219 IoSize\r
220 );\r
221\r
222 gDS->AllocateIoSpace (\r
223 EfiGcdAllocateAnySearchTopDown,\r
224 EfiGcdIoTypeIo,\r
225 NCR_GRAN, // Alignment\r
226 MIN_NCR_IO_SIZE,\r
227 &BaseAddress,\r
228 mImageHandle,\r
229 NULL\r
230 );\r
3cbfba02 231 TempBaseAddress = BaseAddress + 1;\r
076d0d64
GL
232 PciIo->Pci.Write (\r
233 PciIo,\r
234 EfiPciIoWidthUint32,\r
235 Bar,\r
236 1,\r
237 (VOID *) &TempBaseAddress\r
238 );\r
3cbfba02
DW
239 }\r
240 }\r
241 }\r
242\r
243 break;\r
244\r
245 case INTEL_VENDOR_ID:\r
246 if (DeviceId == INTEL_82573E_IDER) {\r
247 //\r
248 // Tekoa i82573E IDE-R fix-ups. At this time A2 step and earlier parts do not\r
249 // support any BARs except BAR0. Other BARS will actualy map to BAR0 so disable\r
250 // them all for Control Blocks and Bus mastering ops as well as Secondary IDE\r
251 // Controller.\r
252 // All Tekoa A2 or earlier step chips for now.\r
253 //\r
076d0d64
GL
254 PciIo->Pci.Read (\r
255 PciIo,\r
256 EfiPciIoWidthUint8,\r
257 PCI_REVISION_ID_OFFSET,\r
258 1,\r
259 &RevId\r
260 );\r
3cbfba02
DW
261 if (RevId <= 0x02) {\r
262 for (Bar = 0x14; Bar < 0x24; Bar+= 4) {\r
263 //\r
264 // Maybe want to clean this up a bit later but for now just clear out the secondary\r
265 // Bars don't worry aboyut freeing up thge allocs.\r
266 //\r
267 TempBaseAddress = 0x0;\r
076d0d64
GL
268 PciIo->Pci.Write (\r
269 PciIo,\r
270 EfiPciIoWidthUint32,\r
271 Bar,\r
272 1,\r
273 (VOID *) &TempBaseAddress\r
274 );\r
3cbfba02
DW
275 } // end for\r
276 }\r
277 else\r
278 {\r
279 //\r
280 //Tekoa A3 or above:\r
281 //Clear bus master base address (PCI register 0x20)\r
282 //since Tekoa does not fully support IDE Bus Mastering\r
283 //\r
284 TempBaseAddress = 0x0;\r
076d0d64
GL
285 PciIo->Pci.Write (\r
286 PciIo,\r
287 EfiPciIoWidthUint32,\r
288 0x20,\r
289 1,\r
290 (VOID *) &TempBaseAddress\r
291 );\r
3cbfba02
DW
292 }\r
293 }\r
294 break;\r
295\r
296 default:\r
297 break;\r
298 }\r
299 return;\r
300}\r
301\r
302VOID\r
303ProgramPciLatency(\r
304 IN EFI_PCI_IO_PROTOCOL *PciIo\r
305 )\r
306{\r
3cbfba02
DW
307 //\r
308 // Program Master Latency Timer\r
309 //\r
310 if (mSystemConfiguration.PciLatency != 0) {\r
076d0d64
GL
311 PciIo->Pci.Write (\r
312 PciIo,\r
313 EfiPciIoWidthUint8,\r
314 PCI_LATENCY_TIMER_OFFSET,\r
315 1,\r
316 &mSystemConfiguration.PciLatency\r
317 );\r
3cbfba02
DW
318 }\r
319 return;\r
320}\r
321\r
322/**\r
323During S5 shutdown, we need to program PME in all LAN devices.\r
324Here we identify LAN devices and save their bus/dev/func.\r
325\r
326**/\r
327VOID\r
328SavePciLanAddress(\r
329 IN EFI_PCI_IO_PROTOCOL *PciIo\r
330 )\r
331{\r
332 EFI_STATUS Status;\r
333 UINTN PciSegment,\r
334 PciBus,\r
335 PciDevice,\r
336 PciFunction;\r
337 VOID *NewBuffer;\r
338 PCI_LAN_INFO *x;\r
339\r
340 Status = PciIo->GetLocation (\r
341 PciIo,\r
342 &PciSegment,\r
343 &PciBus,\r
344 &PciDevice,\r
345 &PciFunction\r
346 );\r
347 if (EFI_ERROR (Status)) {\r
348 return;\r
349 }\r
350\r
351 mPciLanCount ++;\r
352 Status = gBS->AllocatePool (\r
353 EfiBootServicesData,\r
354 mPciLanCount * sizeof(PCI_LAN_INFO),\r
355 &NewBuffer\r
356 );\r
357 if (EFI_ERROR (Status)) {\r
358 return;\r
359 }\r
360\r
361 if (mPciLanCount > 1) {\r
362 //\r
363 // copy old data into new, larger buffer\r
364 //\r
365 gBS->CopyMem (\r
366 NewBuffer,\r
367 mPciLanInfo,\r
368 (mPciLanCount - 1) * sizeof(PCI_LAN_INFO)\r
369 );\r
370\r
371 //\r
372 // free the old memory buffer\r
373 //\r
374 gBS->FreePool (mPciLanInfo);\r
375\r
376 }\r
377\r
378 //\r
379 // init the new entry\r
380 //\r
381 x = (PCI_LAN_INFO *)NewBuffer + (mPciLanCount - 1);\r
382 x->PciBus = (UINT8)PciBus;\r
383 x->PciDevice = (UINT8)PciDevice;\r
384 x->PciFunction = (UINT8)PciFunction;\r
385\r
386 mPciLanInfo = NewBuffer;\r
387\r
388 return;\r
389}\r
390\r
391/**\r
392 @param Event the event that is signaled.\r
393 @param Context not used here.\r
394\r
395\r
396**/\r
397VOID\r
398EFIAPI\r
399PciBusEvent (\r
400 IN EFI_EVENT Event,\r
401 IN VOID* Context\r
402 )\r
403{\r
404\r
405 EFI_STATUS Status;\r
406 UINTN BufferSize;\r
407 EFI_HANDLE Handle;\r
408 EFI_PCI_IO_PROTOCOL *PciIo;\r
409 PCI_IO_DEVICE *PciIoDevice;\r
410 UINT64 Supports;\r
411 UINTN Index;\r
412 UINT8 mCacheLineSize = 0x10;\r
413\r
414 while (TRUE) {\r
415 BufferSize = sizeof (EFI_HANDLE);\r
416 Status = gBS->LocateHandle (\r
417 ByRegisterNotify,\r
418 NULL,\r
419 mPciRegistration,\r
420 &BufferSize,\r
421 &Handle\r
422 );\r
423 if (EFI_ERROR (Status)) {\r
424 //\r
425 // If no more notification events exist\r
426 //\r
427 return;\r
428 }\r
429\r
430 Status = gBS->HandleProtocol (\r
431 Handle,\r
432 &gEfiPciIoProtocolGuid,\r
433 (void **)&PciIo\r
434 );\r
435\r
436 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
437\r
438 //\r
439 // Enable I/O for bridge so port 0x80 codes will come out\r
440 //\r
441 if (PciIoDevice->Pci.Hdr.VendorId == V_PCH_INTEL_VENDOR_ID)\r
442 {\r
443 Status = PciIo->Attributes(\r
444 PciIo,\r
445 EfiPciIoAttributeOperationSupported,\r
446 0,\r
447 &Supports\r
448 );\r
449 Supports &= EFI_PCI_DEVICE_ENABLE;\r
450 Status = PciIo->Attributes (\r
451 PciIo,\r
452 EfiPciIoAttributeOperationEnable,\r
453 Supports,\r
454 NULL\r
455 );\r
456 break;\r
457 }\r
458\r
459 //\r
460 // Program PCI Latency Timer\r
461 //\r
462 ProgramPciLatency(PciIo);\r
463\r
464 //\r
465 // Program Cache Line Size to 64 bytes (0x10 DWORDs)\r
466 //\r
467 Status = PciIo->Pci.Write (\r
468 PciIo,\r
469 EfiPciIoWidthUint8,\r
470 PCI_CACHELINE_SIZE_OFFSET,\r
471 1,\r
472 &mCacheLineSize\r
473 );\r
474\r
475 //\r
476 // If PCI LAN device, save bus/dev/func info\r
477 // so we can program PME during S5 shutdown\r
478 //\r
479 if (PciIoDevice->Pci.Hdr.ClassCode[2] == PCI_CLASS_NETWORK) {\r
480 SavePciLanAddress(PciIo);\r
481 break;\r
482 }\r
483\r
484 //\r
485 // Workaround for cards with bad BARs\r
486 //\r
487 Index = 0;\r
488 while (BadDeviceTable[Index].ClassCode != 0xff) {\r
489 if (BadDeviceTable[Index].DeviceId == 0xffff) {\r
490 if ((PciIoDevice->Pci.Hdr.ClassCode[2] == BadDeviceTable[Index].ClassCode) &&\r
491 (PciIoDevice->Pci.Hdr.ClassCode[1] == BadDeviceTable[Index].SubClassCode) &&\r
492 (PciIoDevice->Pci.Hdr.VendorId == BadDeviceTable[Index].VendorId)) {\r
493 InitBadBars(PciIo,BadDeviceTable[Index].VendorId,BadDeviceTable[Index].DeviceId);\r
494 }\r
495 } else {\r
496 if ((PciIoDevice->Pci.Hdr.ClassCode[2] == BadDeviceTable[Index].ClassCode) &&\r
497 (PciIoDevice->Pci.Hdr.ClassCode[1] == BadDeviceTable[Index].SubClassCode) &&\r
498 (PciIoDevice->Pci.Hdr.VendorId == BadDeviceTable[Index].VendorId) &&\r
499 (PciIoDevice->Pci.Hdr.DeviceId == BadDeviceTable[Index].DeviceId)) {\r
500\r
501 InitBadBars(PciIo,BadDeviceTable[Index].VendorId,BadDeviceTable[Index].DeviceId);\r
502 }\r
503 }\r
504 ++Index;\r
505 }\r
506 break;\r
507 }\r
508\r
509 return;\r
510}\r
511\r