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