]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciOptionRomSupport.c
68820baac984be36b7f72b8efa538ccd5554a159
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciOptionRomSupport.c
1 /**@file
2
3 Copyright (c) 2006, 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 // Min Max
20 //
21 #define EFI_MIN(a, b) (((a) < (b)) ? (a) : (b))
22 #define EFI_MAX(a, b) (((a) > (b)) ? (a) : (b))
23
24
25 EFI_STATUS
26 GetOpRomInfo (
27 IN PCI_IO_DEVICE *PciIoDevice
28 )
29 /*++
30
31 Routine Description:
32
33 Arguments:
34
35 Returns:
36
37 --*/
38 // TODO: PciIoDevice - add argument and description to function comment
39 // TODO: EFI_NOT_FOUND - add return value to function comment
40 // TODO: EFI_SUCCESS - add return value to function comment
41 {
42 UINT8 RomBarIndex;
43 UINT32 AllOnes;
44 UINT64 Address;
45 EFI_STATUS Status;
46 UINT8 Bus;
47 UINT8 Device;
48 UINT8 Function;
49 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
50
51 Bus = PciIoDevice->BusNumber;
52 Device = PciIoDevice->DeviceNumber;
53 Function = PciIoDevice->FunctionNumber;
54
55 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
56
57 //
58 // offset is 0x30 if is not ppb
59 //
60
61 //
62 // 0x30
63 //
64 RomBarIndex = PCI_DEVICE_ROMBAR;
65
66 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
67 //
68 // if is ppb
69 //
70
71 //
72 // 0x38
73 //
74 RomBarIndex = PCI_BRIDGE_ROMBAR;
75 }
76 //
77 // the bit0 is 0 to prevent the enabling of the Rom address decoder
78 //
79 AllOnes = 0xfffffffe;
80 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
81
82 Status = PciRootBridgeIoWrite (
83 PciRootBridgeIo,
84 &PciIoDevice->Pci,
85 EfiPciWidthUint32,
86 Address,
87 1,
88 &AllOnes
89 );
90 if (EFI_ERROR (Status)) {
91 return Status;
92 }
93
94 //
95 // read back
96 //
97 Status = PciRootBridgeIoRead (
98 PciRootBridgeIo,
99 &PciIoDevice->Pci,
100 EfiPciWidthUint32,
101 Address,
102 1,
103 &AllOnes
104 );
105 if (EFI_ERROR (Status)) {
106 return Status;
107 }
108 //
109 // Bits [1, 10] are reserved
110 //
111 AllOnes &= 0xFFFFF800;
112 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
113 return EFI_NOT_FOUND;
114 }
115
116 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
117 return EFI_SUCCESS;
118 }
119
120 EFI_STATUS
121 LoadOpRomImage (
122 IN PCI_IO_DEVICE *PciDevice,
123 IN UINT64 RomBase
124 )
125 /*++
126
127 Routine Description:
128
129 Load option rom image for specified PCI device
130
131 Arguments:
132
133 Returns:
134
135 --*/
136 // TODO: PciDevice - add argument and description to function comment
137 // TODO: RomBase - add argument and description to function comment
138 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
139 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
140 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
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_DEVICE_ROMBAR;
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 = EFI_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 PciRomAddImageMapping (
280 NULL,
281 PciDevice->PciRootBridgeIo->SegmentNumber,
282 PciDevice->BusNumber,
283 PciDevice->DeviceNumber,
284 PciDevice->FunctionNumber,
285 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
286 PciDevice->PciIo.RomSize
287 );
288
289 //
290 // Free allocated memory
291 //
292 gBS->FreePool (RomHeader);
293 gBS->FreePool (RomPcir);
294
295 return retStatus;
296 }
297
298 EFI_STATUS
299 RomDecode (
300 IN PCI_IO_DEVICE *PciDevice,
301 IN UINT8 RomBarIndex,
302 IN UINT32 RomBar,
303 IN BOOLEAN Enable
304 )
305 /*++
306
307 Routine Description:
308
309 Arguments:
310
311 Returns:
312
313 --*/
314 // TODO: PciDevice - add argument and description to function comment
315 // TODO: RomBarIndex - add argument and description to function comment
316 // TODO: RomBar - add argument and description to function comment
317 // TODO: Enable - add argument and description to function comment
318 // TODO: EFI_SUCCESS - add return value to function comment
319 {
320 UINT32 Value32;
321 UINT32 Offset;
322 EFI_PCI_IO_PROTOCOL *PciIo;
323
324 PciIo = &PciDevice->PciIo;
325 if (Enable) {
326 //
327 // Clear all bars
328 //
329 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
330 PciIoWrite (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero);
331 }
332
333 //
334 // set the Rom base address: now is hardcode
335 // enable its decoder
336 //
337 Value32 = RomBar | 0x1;
338 PciIoWrite (
339 PciIo,
340 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
341 RomBarIndex,
342 1,
343 &Value32
344 );
345
346 //
347 // Programe all upstream bridge
348 //
349 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE);
350
351 //
352 // Setting the memory space bit in the function's command register
353 //
354 PciEnableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
355
356 } else {
357
358 //
359 // disable command register decode to memory
360 //
361 PciDisableCommandRegister(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE);
362
363 //
364 // Destroy the programmed bar in all the upstream bridge.
365 //
366 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE);
367
368 //
369 // disable rom decode
370 //
371 Value32 = 0xFFFFFFFE;
372 PciIoWrite (
373 PciIo,
374 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32,
375 RomBarIndex,
376 1,
377 &Value32
378 );
379
380 }
381
382 return EFI_SUCCESS;
383
384 }
385
386 EFI_STATUS
387 ProcessOpRomImage (
388 PCI_IO_DEVICE *PciDevice
389 )
390 /*++
391
392 Routine Description:
393
394 Process the oprom image.
395
396 Arguments:
397 PciDevice A pointer to a pci device.
398
399 Returns:
400
401 EFI Status.
402
403 --*/
404 {
405 UINT8 Indicator;
406 UINT32 ImageSize;
407 UINT16 ImageOffset;
408 VOID *RomBar;
409 UINT8 *RomBarOffset;
410 EFI_HANDLE ImageHandle;
411 EFI_STATUS Status;
412 EFI_STATUS retStatus;
413 BOOLEAN FirstCheck;
414 BOOLEAN SkipImage;
415 UINT32 DestinationSize;
416 UINT32 ScratchSize;
417 UINT8 *Scratch;
418 VOID *ImageBuffer;
419 VOID *DecompressedImageBuffer;
420 UINT32 ImageLength;
421 EFI_DECOMPRESS_PROTOCOL *Decompress;
422 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
423 PCI_DATA_STRUCTURE *Pcir;
424
425 Indicator = 0;
426
427 //
428 // Get the Address of the Rom image
429 //
430 RomBar = PciDevice->PciIo.RomImage;
431 RomBarOffset = (UINT8 *) RomBar;
432 retStatus = EFI_NOT_FOUND;
433 FirstCheck = TRUE;
434
435 do {
436 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
437 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
438 RomBarOffset = RomBarOffset + 512;
439 if (FirstCheck) {
440 break;
441 } else {
442 continue;
443 }
444 }
445
446 FirstCheck = FALSE;
447 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
448 ImageSize = (UINT32) (Pcir->ImageLength * 512);
449 Indicator = Pcir->Indicator;
450
451 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
452 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE)) {
453
454 if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
455 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) {
456
457 ImageOffset = EfiRomHeader->EfiImageHeaderOffset;
458 ImageSize = (UINT32) (EfiRomHeader->InitializationSize * 512);
459
460 ImageBuffer = (VOID *) (RomBarOffset + ImageOffset);
461 ImageLength = ImageSize - (UINT32)ImageOffset;
462 DecompressedImageBuffer = NULL;
463
464 //
465 // decompress here if needed
466 //
467 SkipImage = FALSE;
468 if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
469 SkipImage = TRUE;
470 }
471
472 if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
473 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
474 if (EFI_ERROR (Status)) {
475 SkipImage = TRUE;
476 } else {
477 SkipImage = TRUE;
478 Status = Decompress->GetInfo (
479 Decompress,
480 ImageBuffer,
481 ImageLength,
482 &DestinationSize,
483 &ScratchSize
484 );
485 if (!EFI_ERROR (Status)) {
486 DecompressedImageBuffer = NULL;
487 DecompressedImageBuffer = AllocatePool (DestinationSize);
488 if (DecompressedImageBuffer != NULL) {
489 Scratch = AllocatePool (ScratchSize);
490 if (Scratch != NULL) {
491 Status = Decompress->Decompress (
492 Decompress,
493 ImageBuffer,
494 ImageLength,
495 DecompressedImageBuffer,
496 DestinationSize,
497 Scratch,
498 ScratchSize
499 );
500 if (!EFI_ERROR (Status)) {
501 ImageBuffer = DecompressedImageBuffer;
502 ImageLength = DestinationSize;
503 SkipImage = FALSE;
504 }
505
506 gBS->FreePool (Scratch);
507 }
508 }
509 }
510 }
511 }
512
513 if (!SkipImage) {
514 //
515 // load image and start image
516 //
517 Status = gBS->LoadImage (
518 FALSE,
519 gPciBusDriverBinding.DriverBindingHandle,
520 PciDevice->Handle,
521 ImageBuffer,
522 ImageLength,
523 &ImageHandle
524 );
525 if (!EFI_ERROR (Status)) {
526 Status = gBS->StartImage (ImageHandle, NULL, NULL);
527 if (!EFI_ERROR (Status)) {
528 AddDriver (PciDevice, ImageHandle);
529 PciRomAddImageMapping (
530 ImageHandle,
531 PciDevice->PciRootBridgeIo->SegmentNumber,
532 PciDevice->BusNumber,
533 PciDevice->DeviceNumber,
534 PciDevice->FunctionNumber,
535 (UINT64) (UINTN) PciDevice->PciIo.RomImage,
536 PciDevice->PciIo.RomSize
537 );
538 retStatus = EFI_SUCCESS;
539 }
540 }
541 }
542
543 RomBarOffset = RomBarOffset + ImageSize;
544 } else {
545 RomBarOffset = RomBarOffset + ImageSize;
546 }
547 } else {
548 RomBarOffset = RomBarOffset + ImageSize;
549 }
550
551 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
552
553 return retStatus;
554
555 }