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