blob: 28adb2bf2ca3afa07536bd00a1a9c65c550bd7da [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/*++
2
3Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
4This program and the accompanying materials
5are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution. The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12Module Name:
13
14 PciOptionRomSupport.c
15
16Abstract:
17
18 PCI Bus Driver
19
20Revision History
21
22--*/
23
24#include "PciBus.h"
25
26
27EFI_STATUS
28RomDecode (
29 IN PCI_IO_DEVICE *PciDevice,
30 IN UINT8 RomBarIndex,
31 IN UINT32 RomBar,
32 IN BOOLEAN Enable
33);
34
35EFI_STATUS
36GetOpRomInfo (
37 IN PCI_IO_DEVICE *PciIoDevice
38 )
39/*++
40
41Routine Description:
42
43Arguments:
44
45Returns:
46
47--*/
48{
49 UINT8 RomBarIndex;
50 UINT32 AllOnes;
51 UINT64 Address;
52 EFI_STATUS Status;
53 UINT8 Bus;
54 UINT8 Device;
55 UINT8 Function;
56 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
57
58 Bus = PciIoDevice->BusNumber;
59 Device = PciIoDevice->DeviceNumber;
60 Function = PciIoDevice->FunctionNumber;
61
62 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
63
64 //
65 // offset is 0x30 if is not ppb
66 //
67
68 //
69 // 0x30
70 //
71 RomBarIndex = PCI_EXPANSION_ROM_BASE;
72
73 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
74 //
75 // if is ppb
76 //
77
78 //
79 // 0x38
80 //
81 RomBarIndex = PCI_BRIDGE_ROMBAR;
82 }
83 //
84 // the bit0 is 0 to prevent the enabling of the Rom address decoder
85 //
86 AllOnes = 0xfffffffe;
87 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
88
89 Status = PciRootBridgeIo->Pci.Write (
90 PciRootBridgeIo,
91 EfiPciWidthUint32,
92 Address,
93 1,
94 &AllOnes
95 );
96 if (EFI_ERROR (Status)) {
97 return Status;
98 }
99
100 //
101 // read back
102 //
103 Status = PciRootBridgeIo->Pci.Read (
104 PciRootBridgeIo,
105 EfiPciWidthUint32,
106 Address,
107 1,
108 &AllOnes
109 );
110 if (EFI_ERROR (Status)) {
111 return Status;
112 }
113
114 //
115 // Bits [1, 10] are reserved
116 //
117 AllOnes &= 0xFFFFF800;
118 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
119 return EFI_NOT_FOUND;
120 }
121
122 DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: OPROM detected!\n"));
123 DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: B-%x, D-%x, F-%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Function));
124
125 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
126 return EFI_SUCCESS;
127}
128
129EFI_STATUS
130LoadOpRomImage (
131 IN PCI_IO_DEVICE *PciDevice,
132 IN UINT64 ReservedMemoryBase
133 )
134/*++
135
136Routine Description:
137
138 Load option rom image for specified PCI device
139
140Arguments:
141
142Returns:
143
144--*/
145{
146 UINT8 RomBarIndex;
147 UINT8 Indicator;
148 UINT16 OffsetPcir;
149 UINT32 RomBarOffset;
150 UINT32 RomBar;
151 EFI_STATUS retStatus;
152 BOOLEAN FirstCheck;
153 UINT8 *Image;
154 PCI_EXPANSION_ROM_HEADER *RomHeader;
155 PCI_DATA_STRUCTURE *RomPcir;
156 UINT64 RomSize;
157 UINT64 RomImageSize;
158 UINT32 LegacyImageLength;
159 UINT8 *RomInMemory;
160 UINT8 CodeType;
161
162 RomSize = PciDevice->RomSize;
163
164 Indicator = 0;
165 RomImageSize = 0;
166 RomInMemory = NULL;
167 CodeType = 0xFF;
168
169 //
170 // Get the RomBarIndex
171 //
172
173 //
174 // 0x30
175 //
176 RomBarIndex = PCI_EXPANSION_ROM_BASE;
177 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
178 //
179 // if is ppb
180 //
181
182 //
183 // 0x38
184 //
185 RomBarIndex = PCI_BRIDGE_ROMBAR;
186 }
187 //
188 // Allocate memory for Rom header and PCIR
189 //
190 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
191 if (RomHeader == NULL) {
192 return EFI_OUT_OF_RESOURCES;
193 }
194
195 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
196 if (RomPcir == NULL) {
197 gBS->FreePool (RomHeader);
198 return EFI_OUT_OF_RESOURCES;
199 }
200
201 RomBar = (UINT32)ReservedMemoryBase;
202
203 //
204 // Enable RomBar
205 //
206 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
207
208 RomBarOffset = RomBar;
209 retStatus = EFI_NOT_FOUND;
210 FirstCheck = TRUE;
211 LegacyImageLength = 0;
212
213 do {
214 PciDevice->PciRootBridgeIo->Mem.Read (
215 PciDevice->PciRootBridgeIo,
216 EfiPciWidthUint8,
217 RomBarOffset,
218 sizeof (PCI_EXPANSION_ROM_HEADER),
219 (UINT8 *) RomHeader
220 );
221
222 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
223 RomBarOffset = RomBarOffset + 512;
224 if (FirstCheck) {
225 break;
226 } else {
227 RomImageSize = RomImageSize + 512;
228 continue;
229 }
230 }
231
232 FirstCheck = FALSE;
233 OffsetPcir = RomHeader->PcirOffset;
234 //
235 // If the pointer to the PCI Data Structure is invalid, no further images can be located.
236 // The PCI Data Structure must be DWORD aligned.
237 //
238 if (OffsetPcir == 0 ||
239 (OffsetPcir & 3) != 0 ||
240 RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
241 break;
242 }
243 PciDevice->PciRootBridgeIo->Mem.Read (
244 PciDevice->PciRootBridgeIo,
245 EfiPciWidthUint8,
246 RomBarOffset + OffsetPcir,
247 sizeof (PCI_DATA_STRUCTURE),
248 (UINT8 *) RomPcir
249 );
250 //
251 // If a valid signature is not present in the PCI Data Structure, no further images can be located.
252 //
253 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
254 break;
255 }
256 if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
257 break;
258 }
259 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
260 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
261 LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;
262 }
263 Indicator = RomPcir->Indicator;
264 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;
265 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;
266 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
267
268 //
269 // Some Legacy Cards do not report the correct ImageLength so used the maximum
270 // of the legacy length and the PCIR Image Length
271 //
272 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
273 RomImageSize = MAX (RomImageSize, LegacyImageLength);
274 }
275
276 if (RomImageSize > 0) {
277 retStatus = EFI_SUCCESS;
278 Image = AllocatePool ((UINT32) RomImageSize);
279 if (Image == NULL) {
280 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
281 gBS->FreePool (RomHeader);
282 gBS->FreePool (RomPcir);
283 return EFI_OUT_OF_RESOURCES;
284 }
285
286 //
287 // Copy Rom image into memory
288 //
289 PciDevice->PciRootBridgeIo->Mem.Read (
290 PciDevice->PciRootBridgeIo,
291 EfiPciWidthUint8,
292 RomBar,
293 (UINT32) RomImageSize,
294 Image
295 );
296 RomInMemory = Image;
297 }
298
299 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
300
301 PciDevice->PciIo.RomSize = RomImageSize;
302 PciDevice->PciIo.RomImage = RomInMemory;
303
304 //
305 // Free allocated memory
306 //
307 gBS->FreePool (RomHeader);
308 gBS->FreePool (RomPcir);
309
310 return retStatus;
311}
312
313EFI_STATUS
314RomDecode (
315 IN PCI_IO_DEVICE *PciDevice,
316 IN UINT8 RomBarIndex,
317 IN UINT32 RomBar,
318 IN BOOLEAN Enable
319 )
320/*++
321
322Routine Description:
323
324Arguments:
325
326Returns:
327
328--*/
329{
330 UINT16 CommandValue;
331 UINT32 Value32;
332 UINT64 Address;
333 //EFI_STATUS Status;
334 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
335
336 PciRootBridgeIo = PciDevice->PciRootBridgeIo;
337 if (Enable) {
338 Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
339 //
340 // set the Rom base address: now is hardcode
341 //
342 PciRootBridgeIo->Pci.Write(
343 PciRootBridgeIo,
344 EfiPciWidthUint32,
345 Address,
346 1,
347 &RomBar);
348
349 //
350 // enable its decoder
351 //
352 Value32 = RomBar | 0x1;
353 PciRootBridgeIo->Pci.Write(
354 PciRootBridgeIo,
355 EfiPciWidthUint32,
356 Address,
357 1,
358 &Value32);
359
360 //
361 //setting the memory space bit in the function's command register
362 //
363 Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, 0x04);
364 PciRootBridgeIo->Pci.Read(
365 PciRootBridgeIo,
366 EfiPciWidthUint16,
367 Address,
368 1,
369 &CommandValue);
370
371 CommandValue = (UINT16)(CommandValue | 0x0002); //0x0003
372 PciRootBridgeIo->Pci.Write(
373 PciRootBridgeIo,
374 EfiPciWidthUint16,
375 Address,
376 1,
377 &CommandValue);
378 } else {
379 //
380 // disable rom decode
381 //
382 Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
383 Value32 = 0xfffffffe;
384 PciRootBridgeIo->Pci.Write(
385 PciRootBridgeIo,
386 EfiPciWidthUint32,
387 Address,
388 1,
389 &Value32);
390 }
391
392 return EFI_SUCCESS;
393
394}
395
396EFI_STATUS
397ProcessOpRomImage (
398 PCI_IO_DEVICE *PciDevice
399 )
400/*++
401
402Routine Description:
403
404 Process the oprom image.
405
406Arguments:
407 PciDevice A pointer to a pci device.
408
409Returns:
410
411 EFI Status.
412
413--*/
414{
415 UINT8 Indicator;
416 UINT32 ImageSize;
417 UINT16 ImageOffset;
418 VOID *RomBar;
419 UINT8 *RomBarOffset;
420 EFI_HANDLE ImageHandle;
421 EFI_STATUS Status;
422 EFI_STATUS retStatus;
423 BOOLEAN SkipImage;
424 UINT32 DestinationSize;
425 UINT32 ScratchSize;
426 UINT8 *Scratch;
427 VOID *ImageBuffer;
428 VOID *DecompressedImageBuffer;
429 UINT32 ImageLength;
430 EFI_DECOMPRESS_PROTOCOL *Decompress;
431 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
432 PCI_DATA_STRUCTURE *Pcir;
433 UINT32 InitializationSize;
434
435 Indicator = 0;
436
437 //
438 // Get the Address of the Rom image
439 //
440 RomBar = PciDevice->PciIo.RomImage;
441 RomBarOffset = (UINT8 *) RomBar;
442 retStatus = EFI_NOT_FOUND;
443
444 if (RomBarOffset == NULL) {
445 return retStatus;
446 }
447 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
448
449 do {
450 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
451 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
452 RomBarOffset = RomBarOffset + 512;
453 continue;
454 }
455
456 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
457 ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
458 ImageSize = (UINT32) (Pcir->ImageLength * 512);
459 Indicator = Pcir->Indicator;
460
461 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
462 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
463 ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
464 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) {
465
466 ImageOffset = EfiRomHeader->EfiImageHeaderOffset;
467 InitializationSize = EfiRomHeader->InitializationSize * 512;
468
469 if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) {
470
471 ImageBuffer = (VOID *) (RomBarOffset + ImageOffset);
472 ImageLength = InitializationSize - (UINT32)ImageOffset;
473 DecompressedImageBuffer = NULL;
474
475 //
476 // decompress here if needed
477 //
478 SkipImage = FALSE;
479 if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
480 SkipImage = TRUE;
481 }
482
483 if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
484 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
485 if (EFI_ERROR (Status)) {
486 SkipImage = TRUE;
487 } else {
488 SkipImage = TRUE;
489 Status = Decompress->GetInfo (
490 Decompress,
491 ImageBuffer,
492 ImageLength,
493 &DestinationSize,
494 &ScratchSize
495 );
496 if (!EFI_ERROR (Status)) {
497 DecompressedImageBuffer = NULL;
498 DecompressedImageBuffer = AllocatePool (DestinationSize);
499 if (DecompressedImageBuffer != NULL) {
500 Scratch = AllocatePool (ScratchSize);
501 if (Scratch != NULL) {
502 Status = Decompress->Decompress (
503 Decompress,
504 ImageBuffer,
505 ImageLength,
506 DecompressedImageBuffer,
507 DestinationSize,
508 Scratch,
509 ScratchSize
510 );
511 if (!EFI_ERROR (Status)) {
512 ImageBuffer = DecompressedImageBuffer;
513 ImageLength = DestinationSize;
514 SkipImage = FALSE;
515 }
516
517 gBS->FreePool (Scratch);
518 }
519 }
520 }
521 }
522 }
523
524 if (!SkipImage) {
525 //
526 // load image and start image
527 //
528 Status = gBS->LoadImage (
529 FALSE,
530 gPciBusDriverBinding.DriverBindingHandle,
531 NULL,
532 ImageBuffer,
533 ImageLength,
534 &ImageHandle
535 );
536 if (!EFI_ERROR (Status)) {
537 Status = gBS->StartImage (ImageHandle, NULL, NULL);
538 if (!EFI_ERROR (Status)) {
539 AddDriver (PciDevice, ImageHandle);
540 retStatus = EFI_SUCCESS;
541 }
542 }
543 }
544
545 RomBarOffset = RomBarOffset + ImageSize;
546 } else {
547 RomBarOffset = RomBarOffset + ImageSize;
548 }
549 } else {
550 RomBarOffset = RomBarOffset + ImageSize;
551 }
552
553 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
554
555 return retStatus;
556
557}