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