]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
ea9ac25b13195ce6ce7d3d154d263bb28e2bdf4b
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciOptionRomSupport.c
1 /** @file
2
3 Copyright (c) 2006 - 2008, 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 **/
13
14 #include "PciBus.h"
15 #include "PciResourceSupport.h"
16
17 #include <IndustryStandard/Pci23.h>
18
19 //
20 // Module global for a template of the PCI option ROM Image Device Path Node
21 //
22 MEMMAP_DEVICE_PATH mPciOptionRomImageDevicePathNodeTemplate = {
23 {
24 HARDWARE_DEVICE_PATH,
25 HW_MEMMAP_DP,
26 {
27 (UINT8) (sizeof (MEMMAP_DEVICE_PATH)),
28 (UINT8) ((sizeof (MEMMAP_DEVICE_PATH)) >> 8)
29 }
30 },
31 EfiMemoryMappedIO,
32 0,
33 0
34 };
35
36 /**
37 Get Pci device's oprom infor bits.
38
39 @param PciIoDevice Pci device instance
40
41 @retval EFI_NOT_FOUND Pci device has not oprom
42 @retval EFI_SUCCESS Pci device has oprom
43 **/
44 EFI_STATUS
45 GetOpRomInfo (
46 IN PCI_IO_DEVICE *PciIoDevice
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 = PciRootBridgeIoWrite (
90 PciRootBridgeIo,
91 &PciIoDevice->Pci,
92 EfiPciWidthUint32,
93 Address,
94 1,
95 &AllOnes
96 );
97 if (EFI_ERROR (Status)) {
98 return Status;
99 }
100
101 //
102 // read back
103 //
104 Status = PciRootBridgeIoRead (
105 PciRootBridgeIo,
106 &PciIoDevice->Pci,
107 EfiPciWidthUint32,
108 Address,
109 1,
110 &AllOnes
111 );
112 if (EFI_ERROR (Status)) {
113 return Status;
114 }
115 //
116 // Bits [1, 10] are reserved
117 //
118 AllOnes &= 0xFFFFF800;
119 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
120 return EFI_NOT_FOUND;
121 }
122
123 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
124 return EFI_SUCCESS;
125 }
126
127 /**
128 Load option rom image for specified PCI device
129
130 @param PciDevice Pci device instance
131 @param RomBase Base address of oprom.
132
133 @retval EFI_OUT_OF_RESOURCES not enough memory to hold image
134 @retval EFI_SUCESS Success
135 **/
136 EFI_STATUS
137 LoadOpRomImage (
138 IN PCI_IO_DEVICE *PciDevice,
139 IN UINT64 RomBase
140 )
141 {
142 UINT8 RomBarIndex;
143 UINT8 Indicator;
144 UINT16 OffsetPcir;
145 UINT32 RomBarOffset;
146 UINT32 RomBar;
147 EFI_STATUS RetStatus;
148 BOOLEAN FirstCheck;
149 UINT8 *Image;
150 PCI_EXPANSION_ROM_HEADER *RomHeader;
151 PCI_DATA_STRUCTURE *RomPcir;
152 UINT64 RomSize;
153 UINT64 RomImageSize;
154 UINT8 *RomInMemory;
155 UINT8 CodeType;
156
157 RomSize = PciDevice->RomSize;
158
159 Indicator = 0;
160 RomImageSize = 0;
161 RomInMemory = NULL;
162 CodeType = 0xFF;
163
164 //
165 // Get the RomBarIndex
166 //
167
168 //
169 // 0x30
170 //
171 RomBarIndex = PCI_EXPANSION_ROM_BASE;
172 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
173 //
174 // if is ppb
175 //
176
177 //
178 // 0x38
179 //
180 RomBarIndex = PCI_BRIDGE_ROMBAR;
181 }
182 //
183 // Allocate memory for Rom header and PCIR
184 //
185 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
186 if (RomHeader == NULL) {
187 return EFI_OUT_OF_RESOURCES;
188 }
189
190 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
191 if (RomPcir == NULL) {
192 gBS->FreePool (RomHeader);
193 return EFI_OUT_OF_RESOURCES;
194 }
195
196 RomBar = (UINT32) RomBase;
197
198 //
199 // Enable RomBar
200 //
201 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
202
203 RomBarOffset = RomBar;
204 RetStatus = EFI_NOT_FOUND;
205 FirstCheck = TRUE;
206
207 do {
208 PciDevice->PciRootBridgeIo->Mem.Read (
209 PciDevice->PciRootBridgeIo,
210 EfiPciWidthUint8,
211 RomBarOffset,
212 sizeof (PCI_EXPANSION_ROM_HEADER),
213 (UINT8 *) RomHeader
214 );
215
216 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
217 RomBarOffset = RomBarOffset + 512;
218 if (FirstCheck) {
219 break;
220 } else {
221 RomImageSize = RomImageSize + 512;
222 continue;
223 }
224 }
225
226 FirstCheck = FALSE;
227 OffsetPcir = RomHeader->PcirOffset;
228 PciDevice->PciRootBridgeIo->Mem.Read (
229 PciDevice->PciRootBridgeIo,
230 EfiPciWidthUint8,
231 RomBarOffset + OffsetPcir,
232 sizeof (PCI_DATA_STRUCTURE),
233 (UINT8 *) RomPcir
234 );
235 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
236 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
237 }
238 Indicator = RomPcir->Indicator;
239 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;
240 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;
241 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
242
243 //
244 // Some Legacy Cards do not report the correct ImageLength so used the maximum
245 // of the legacy length and the PCIR Image Length
246 //
247 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
248 RomImageSize = MAX(RomImageSize, (((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512 * 512));
249 }
250
251 if (RomImageSize > 0) {
252 RetStatus = EFI_SUCCESS;
253 Image = AllocatePool ((UINT32) RomImageSize);
254 if (Image == NULL) {
255 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
256 gBS->FreePool (RomHeader);
257 gBS->FreePool (RomPcir);
258 return EFI_OUT_OF_RESOURCES;
259 }
260
261 //
262 // Copy Rom image into memory
263 //
264 PciDevice->PciRootBridgeIo->Mem.Read (
265 PciDevice->PciRootBridgeIo,
266 EfiPciWidthUint8,
267 RomBar,
268 (UINT32) RomImageSize,
269 Image
270 );
271 RomInMemory = Image;
272 }
273
274 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
275
276 PciDevice->PciIo.RomSize = RomImageSize;
277 PciDevice->PciIo.RomImage = RomInMemory;
278
279 //
280 // For OpROM read from PCI device:
281 // Add the Rom Image to internal database for later PCI light enumeration
282 //
283 PciRomAddImageMapping (
284 NULL,
285 PciDevice->PciRootBridgeIo->SegmentNumber,
286 PciDevice->BusNumber,
287 PciDevice->DeviceNumber,
288 PciDevice->FunctionNumber,
289 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
290 PciDevice->PciIo.RomSize
291 );
292
293 //
294 // Free allocated memory
295 //
296 gBS->FreePool (RomHeader);
297 gBS->FreePool (RomPcir);
298
299 return RetStatus;
300 }
301
302 /**
303 enable/disable oprom decode
304
305 @param PciDevice pci device instance
306 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the
307 base address for resource range. The legal range for this field is 0..5.
308 @param RomBar Base address of rom
309 @param Enable Flag for enable/disable decode.
310
311 @retval EFI_SUCCESS Success
312 **/
313 EFI_STATUS
314 RomDecode (
315 IN PCI_IO_DEVICE *PciDevice,
316 IN UINT8 RomBarIndex,
317 IN UINT32 RomBar,
318 IN BOOLEAN Enable
319 )
320 {
321 UINT32 Value32;
322 UINT32 Offset;
323 EFI_PCI_IO_PROTOCOL *PciIo;
324
325 PciIo = &PciDevice->PciIo;
326 if (Enable) {
327 //
328 // Clear all bars
329 //
330 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
331 PciIoWrite (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);
332 }
333
334 //
335 // set the Rom base address: now is hardcode
336 // enable its decoder
337 //
338 Value32 = RomBar | 0x1;
339 PciIoWrite (
340 PciIo,
341 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
342 RomBarIndex,
343 1,
344 &Value32
345 );
346
347 //
348 // Programe all upstream bridge
349 //
350 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);
351
352 //
353 // Setting the memory space bit in the function's command register
354 //
355 PciEnableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
356
357 } else {
358
359 //
360 // disable command register decode to memory
361 //
362 PciDisableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
363
364 //
365 // Destroy the programmed bar in all the upstream bridge.
366 //
367 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);
368
369 //
370 // disable rom decode
371 //
372 Value32 = 0xFFFFFFFE;
373 PciIoWrite (
374 PciIo,
375 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
376 RomBarIndex,
377 1,
378 &Value32
379 );
380
381 }
382
383 return EFI_SUCCESS;
384
385 }
386
387 /**
388 Process the oprom image.
389
390 @param PciDevice Pci device instance
391 **/
392 EFI_STATUS
393 ProcessOpRomImage (
394 PCI_IO_DEVICE *PciDevice
395 )
396 {
397 UINT8 Indicator;
398 UINT32 ImageSize;
399 UINT16 ImageOffset;
400 VOID *RomBar;
401 UINT8 *RomBarOffset;
402 EFI_HANDLE ImageHandle;
403 EFI_STATUS Status;
404 EFI_STATUS RetStatus;
405 BOOLEAN FirstCheck;
406 BOOLEAN SkipImage;
407 UINT32 DestinationSize;
408 UINT32 ScratchSize;
409 UINT8 *Scratch;
410 VOID *ImageBuffer;
411 VOID *DecompressedImageBuffer;
412 UINT32 ImageLength;
413 EFI_DECOMPRESS_PROTOCOL *Decompress;
414 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
415 PCI_DATA_STRUCTURE *Pcir;
416 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath;
417
418 Indicator = 0;
419
420 //
421 // Get the Address of the Rom image
422 //
423 RomBar = PciDevice->PciIo.RomImage;
424 RomBarOffset = (UINT8 *) RomBar;
425 RetStatus = EFI_NOT_FOUND;
426 FirstCheck = TRUE;
427
428 do {
429 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
430 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
431 RomBarOffset = RomBarOffset + 512;
432 if (FirstCheck) {
433 break;
434 } else {
435 continue;
436 }
437 }
438
439 FirstCheck = FALSE;
440 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
441 ImageSize = (UINT32) (Pcir->ImageLength * 512);
442 Indicator = Pcir->Indicator;
443
444 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
445 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE)) {
446
447 if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
448 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) {
449
450 ImageOffset = EfiRomHeader->EfiImageHeaderOffset;
451 ImageSize = (UINT32) (EfiRomHeader->InitializationSize * 512);
452
453 ImageBuffer = (VOID *) (RomBarOffset + ImageOffset);
454 ImageLength = ImageSize - (UINT32)ImageOffset;
455 DecompressedImageBuffer = NULL;
456
457 //
458 // decompress here if needed
459 //
460 SkipImage = FALSE;
461 if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
462 SkipImage = TRUE;
463 }
464
465 if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
466 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
467 if (EFI_ERROR (Status)) {
468 SkipImage = TRUE;
469 } else {
470 SkipImage = TRUE;
471 Status = Decompress->GetInfo (
472 Decompress,
473 ImageBuffer,
474 ImageLength,
475 &DestinationSize,
476 &ScratchSize
477 );
478 if (!EFI_ERROR (Status)) {
479 DecompressedImageBuffer = NULL;
480 DecompressedImageBuffer = AllocatePool (DestinationSize);
481 if (DecompressedImageBuffer != NULL) {
482 Scratch = AllocatePool (ScratchSize);
483 if (Scratch != NULL) {
484 Status = Decompress->Decompress (
485 Decompress,
486 ImageBuffer,
487 ImageLength,
488 DecompressedImageBuffer,
489 DestinationSize,
490 Scratch,
491 ScratchSize
492 );
493 if (!EFI_ERROR (Status)) {
494 ImageBuffer = DecompressedImageBuffer;
495 ImageLength = DestinationSize;
496 SkipImage = FALSE;
497 }
498
499 gBS->FreePool (Scratch);
500 }
501 }
502 }
503 }
504 }
505
506 if (!SkipImage) {
507 //
508 // Build Memory Mapped device path node to record the image offset into the PCI Option ROM
509 //
510 mPciOptionRomImageDevicePathNodeTemplate.StartingAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (RomBarOffset - (UINT8 *) RomBar);
511 mPciOptionRomImageDevicePathNodeTemplate.EndingAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (RomBarOffset + ImageSize - 1 - (UINT8 *) RomBar);
512 PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, (const EFI_DEVICE_PATH_PROTOCOL *)&mPciOptionRomImageDevicePathNodeTemplate);
513 ASSERT (PciOptionRomImageDevicePath != NULL);
514
515 //
516 // load image and start image
517 //
518 Status = gBS->LoadImage (
519 FALSE,
520 gPciBusDriverBinding.DriverBindingHandle,
521 PciOptionRomImageDevicePath,
522 ImageBuffer,
523 ImageLength,
524 &ImageHandle
525 );
526
527 //
528 // Free the device path after it has been used by LoadImage
529 //
530 gBS->FreePool (PciOptionRomImageDevicePath);
531
532 if (!EFI_ERROR (Status)) {
533 Status = gBS->StartImage (ImageHandle, NULL, NULL);
534 if (!EFI_ERROR (Status)) {
535 AddDriver (PciDevice, ImageHandle);
536 PciRomAddImageMapping (
537 ImageHandle,
538 PciDevice->PciRootBridgeIo->SegmentNumber,
539 PciDevice->BusNumber,
540 PciDevice->DeviceNumber,
541 PciDevice->FunctionNumber,
542 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
543 PciDevice->PciIo.RomSize
544 );
545 RetStatus = EFI_SUCCESS;
546 }
547 }
548 }
549
550 RomBarOffset = RomBarOffset + ImageSize;
551 } else {
552 RomBarOffset = RomBarOffset + ImageSize;
553 }
554 } else {
555 RomBarOffset = RomBarOffset + ImageSize;
556 }
557
558 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
559
560 return RetStatus;
561
562 }
563