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