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