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