]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@6240 6f19259b...
[mirror_edk2.git] / DuetPkg / PciBusNoEnumerationDxe / PciOptionRomSupport.c
1 /*++
2
3 Copyright (c) 2005 - 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
26
27 EFI_STATUS
28 RomDecode (
29 IN PCI_IO_DEVICE *PciDevice,
30 IN UINT8 RomBarIndex,
31 IN UINT32 RomBar,
32 IN BOOLEAN Enable
33 );
34
35 EFI_STATUS
36 GetOpRomInfo (
37 IN PCI_IO_DEVICE *PciIoDevice
38 )
39 /*++
40
41 Routine Description:
42
43 Arguments:
44
45 Returns:
46
47 --*/
48 {
49 UINT8 RomBarIndex;
50 UINT32 AllOnes;
51 UINT64 Address;
52 EFI_STATUS Status;
53 UINT8 Bus;
54 UINT8 Device;
55 UINT8 Function;
56 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
57
58 Bus = PciIoDevice->BusNumber;
59 Device = PciIoDevice->DeviceNumber;
60 Function = PciIoDevice->FunctionNumber;
61
62 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
63
64 //
65 // offset is 0x30 if is not ppb
66 //
67
68 //
69 // 0x30
70 //
71 RomBarIndex = PCI_EXPANSION_ROM_BASE;
72
73 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
74 //
75 // if is ppb
76 //
77
78 //
79 // 0x38
80 //
81 RomBarIndex = PCI_BRIDGE_ROMBAR;
82 }
83 //
84 // the bit0 is 0 to prevent the enabling of the Rom address decoder
85 //
86 AllOnes = 0xfffffffe;
87 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
88
89 Status = PciRootBridgeIo->Pci.Write (
90 PciRootBridgeIo,
91 EfiPciWidthUint32,
92 Address,
93 1,
94 &AllOnes
95 );
96 if (EFI_ERROR (Status)) {
97 return Status;
98 }
99
100 //
101 // read back
102 //
103 Status = PciRootBridgeIo->Pci.Read (
104 PciRootBridgeIo,
105 EfiPciWidthUint32,
106 Address,
107 1,
108 &AllOnes
109 );
110 if (EFI_ERROR (Status)) {
111 return Status;
112 }
113
114 //
115 // Bits [1, 10] are reserved
116 //
117 AllOnes &= 0xFFFFF800;
118 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
119 return EFI_NOT_FOUND;
120 }
121
122 DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: OPROM detected!\n"));
123 DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: B-%x, D-%x, F-%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Function));
124
125 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
126 return EFI_SUCCESS;
127 }
128
129 EFI_STATUS
130 LoadOpRomImage (
131 IN PCI_IO_DEVICE *PciDevice,
132 IN UINT64 ReservedMemoryBase
133 )
134 /*++
135
136 Routine Description:
137
138 Load option rom image for specified PCI device
139
140 Arguments:
141
142 Returns:
143
144 --*/
145 {
146 UINT8 RomBarIndex;
147 UINT8 Indicator;
148 UINT16 OffsetPcir;
149 UINT32 RomBarOffset;
150 UINT32 RomBar;
151 UINT64 Temp;
152 EFI_STATUS retStatus;
153 BOOLEAN FirstCheck;
154 UINT8 *Image;
155 PCI_EXPANSION_ROM_HEADER *RomHeader;
156 PCI_DATA_STRUCTURE *RomPcir;
157 UINT64 RomSize;
158 UINT64 RomImageSize;
159 UINT8 *RomInMemory;
160 UINT8 CodeType;
161
162 RomSize = PciDevice->RomSize;
163
164 Indicator = 0;
165 RomImageSize = 0;
166 RomInMemory = NULL;
167 Temp = 0;
168 CodeType = 0xFF;
169
170 //
171 // Get the RomBarIndex
172 //
173
174 //
175 // 0x30
176 //
177 RomBarIndex = PCI_EXPANSION_ROM_BASE;
178 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
179 //
180 // if is ppb
181 //
182
183 //
184 // 0x38
185 //
186 RomBarIndex = PCI_BRIDGE_ROMBAR;
187 }
188 //
189 // Allocate memory for Rom header and PCIR
190 //
191 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
192 if (RomHeader == NULL) {
193 return EFI_OUT_OF_RESOURCES;
194 }
195
196 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
197 if (RomPcir == NULL) {
198 gBS->FreePool (RomHeader);
199 return EFI_OUT_OF_RESOURCES;
200 }
201
202 RomBar = (UINT32)ReservedMemoryBase;
203
204 //
205 // Enable RomBar
206 //
207 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
208
209 RomBarOffset = RomBar;
210 retStatus = EFI_NOT_FOUND;
211 FirstCheck = TRUE;
212
213 do {
214 PciDevice->PciRootBridgeIo->Mem.Read (
215 PciDevice->PciRootBridgeIo,
216 EfiPciWidthUint8,
217 RomBarOffset,
218 sizeof (PCI_EXPANSION_ROM_HEADER),
219 (UINT8 *) RomHeader
220 );
221
222 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
223 RomBarOffset = RomBarOffset + 512;
224 if (FirstCheck) {
225 break;
226 } else {
227 RomImageSize = RomImageSize + 512;
228 continue;
229 }
230 }
231
232 FirstCheck = FALSE;
233 OffsetPcir = RomHeader->PcirOffset;
234 PciDevice->PciRootBridgeIo->Mem.Read (
235 PciDevice->PciRootBridgeIo,
236 EfiPciWidthUint8,
237 RomBarOffset + OffsetPcir,
238 sizeof (PCI_DATA_STRUCTURE),
239 (UINT8 *) RomPcir
240 );
241 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
242 CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
243 }
244 Indicator = RomPcir->Indicator;
245 RomImageSize = RomImageSize + RomPcir->ImageLength * 512;
246 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;
247 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
248
249 //
250 // Some Legacy Cards do not report the correct ImageLength so used the maximum
251 // of the legacy length and the PCIR Image Length
252 //
253 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
254 RomImageSize = MAX(RomImageSize, (((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512 * 512));
255 }
256
257 if (RomImageSize > 0) {
258 retStatus = EFI_SUCCESS;
259 Image = AllocatePool ((UINT32) RomImageSize);
260 if (Image == NULL) {
261 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
262 gBS->FreePool (RomHeader);
263 gBS->FreePool (RomPcir);
264 return EFI_OUT_OF_RESOURCES;
265 }
266
267 //
268 // Copy Rom image into memory
269 //
270 PciDevice->PciRootBridgeIo->Mem.Read (
271 PciDevice->PciRootBridgeIo,
272 EfiPciWidthUint8,
273 RomBar,
274 (UINT32) RomImageSize,
275 Image
276 );
277 RomInMemory = Image;
278 }
279
280 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
281
282 PciDevice->PciIo.RomSize = RomImageSize;
283 PciDevice->PciIo.RomImage = RomInMemory;
284
285 //
286 // Free allocated memory
287 //
288 gBS->FreePool (RomHeader);
289 gBS->FreePool (RomPcir);
290
291 return retStatus;
292 }
293
294 EFI_STATUS
295 RomDecode (
296 IN PCI_IO_DEVICE *PciDevice,
297 IN UINT8 RomBarIndex,
298 IN UINT32 RomBar,
299 IN BOOLEAN Enable
300 )
301 /*++
302
303 Routine Description:
304
305 Arguments:
306
307 Returns:
308
309 --*/
310 {
311 UINT16 CommandValue;
312 UINT32 Value32;
313 UINT64 Address;
314 //EFI_STATUS Status;
315 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
316
317 PciRootBridgeIo = PciDevice->PciRootBridgeIo;
318 if (Enable) {
319 Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
320 //
321 // set the Rom base address: now is hardcode
322 //
323 PciRootBridgeIo->Pci.Write(
324 PciRootBridgeIo,
325 EfiPciWidthUint32,
326 Address,
327 1,
328 &RomBar);
329
330 //
331 // enable its decoder
332 //
333 Value32 = RomBar | 0x1;
334 PciRootBridgeIo->Pci.Write(
335 PciRootBridgeIo,
336 EfiPciWidthUint32,
337 Address,
338 1,
339 &Value32);
340
341 //
342 //setting the memory space bit in the function's command register
343 //
344 Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, 0x04);
345 PciRootBridgeIo->Pci.Read(
346 PciRootBridgeIo,
347 EfiPciWidthUint16,
348 Address,
349 1,
350 &CommandValue);
351
352 CommandValue = (UINT16)(CommandValue | 0x0002); //0x0003
353 PciRootBridgeIo->Pci.Write(
354 PciRootBridgeIo,
355 EfiPciWidthUint16,
356 Address,
357 1,
358 &CommandValue);
359 } else {
360 //
361 // disable rom decode
362 //
363 Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
364 Value32 = 0xfffffffe;
365 PciRootBridgeIo->Pci.Write(
366 PciRootBridgeIo,
367 EfiPciWidthUint32,
368 Address,
369 1,
370 &Value32);
371 }
372
373 return EFI_SUCCESS;
374
375 }
376
377 EFI_STATUS
378 ProcessOpRomImage (
379 PCI_IO_DEVICE *PciDevice
380 )
381 /*++
382
383 Routine Description:
384
385 Process the oprom image.
386
387 Arguments:
388 PciDevice A pointer to a pci device.
389
390 Returns:
391
392 EFI Status.
393
394 --*/
395 {
396 UINT8 Indicator;
397 UINT32 ImageSize;
398 UINT16 ImageOffset;
399 VOID *RomBar;
400 UINT8 *RomBarOffset;
401 EFI_HANDLE ImageHandle;
402 EFI_STATUS Status;
403 EFI_STATUS retStatus;
404 BOOLEAN FirstCheck;
405 BOOLEAN SkipImage;
406 UINT32 DestinationSize;
407 UINT32 ScratchSize;
408 UINT8 *Scratch;
409 VOID *ImageBuffer;
410 VOID *DecompressedImageBuffer;
411 UINT32 ImageLength;
412 EFI_DECOMPRESS_PROTOCOL *Decompress;
413 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
414 PCI_DATA_STRUCTURE *Pcir;
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 // load image and start image
507 //
508 Status = gBS->LoadImage (
509 FALSE,
510 gPciBusDriverBinding.DriverBindingHandle,
511 NULL,
512 ImageBuffer,
513 ImageLength,
514 &ImageHandle
515 );
516 if (!EFI_ERROR (Status)) {
517 Status = gBS->StartImage (ImageHandle, NULL, NULL);
518 if (!EFI_ERROR (Status)) {
519 AddDriver (PciDevice, ImageHandle);
520 retStatus = EFI_SUCCESS;
521 }
522 }
523 }
524
525 RomBarOffset = RomBarOffset + ImageSize;
526 } else {
527 RomBarOffset = RomBarOffset + ImageSize;
528 }
529 } else {
530 RomBarOffset = RomBarOffset + ImageSize;
531 }
532
533 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
534
535 return retStatus;
536
537 }