]>
Commit | Line | Data |
---|---|---|
81a23a0f LL |
1 | /*++ |
2 | ||
3 | Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR> | |
4 | 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 | EFI_STATUS retStatus; | |
152 | BOOLEAN FirstCheck; | |
153 | UINT8 *Image; | |
154 | PCI_EXPANSION_ROM_HEADER *RomHeader; | |
155 | PCI_DATA_STRUCTURE *RomPcir; | |
156 | UINT64 RomSize; | |
157 | UINT64 RomImageSize; | |
158 | UINT32 LegacyImageLength; | |
159 | UINT8 *RomInMemory; | |
160 | UINT8 CodeType; | |
161 | ||
162 | RomSize = PciDevice->RomSize; | |
163 | ||
164 | Indicator = 0; | |
165 | RomImageSize = 0; | |
166 | RomInMemory = NULL; | |
167 | CodeType = 0xFF; | |
168 | ||
169 | // | |
170 | // Get the RomBarIndex | |
171 | // | |
172 | ||
173 | // | |
174 | // 0x30 | |
175 | // | |
176 | RomBarIndex = PCI_EXPANSION_ROM_BASE; | |
177 | if (IS_PCI_BRIDGE (&(PciDevice->Pci))) { | |
178 | // | |
179 | // if is ppb | |
180 | // | |
181 | ||
182 | // | |
183 | // 0x38 | |
184 | // | |
185 | RomBarIndex = PCI_BRIDGE_ROMBAR; | |
186 | } | |
187 | // | |
188 | // Allocate memory for Rom header and PCIR | |
189 | // | |
190 | RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER)); | |
191 | if (RomHeader == NULL) { | |
192 | return EFI_OUT_OF_RESOURCES; | |
193 | } | |
194 | ||
195 | RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE)); | |
196 | if (RomPcir == NULL) { | |
197 | gBS->FreePool (RomHeader); | |
198 | return EFI_OUT_OF_RESOURCES; | |
199 | } | |
200 | ||
201 | RomBar = (UINT32)ReservedMemoryBase; | |
202 | ||
203 | // | |
204 | // Enable RomBar | |
205 | // | |
206 | RomDecode (PciDevice, RomBarIndex, RomBar, TRUE); | |
207 | ||
208 | RomBarOffset = RomBar; | |
209 | retStatus = EFI_NOT_FOUND; | |
210 | FirstCheck = TRUE; | |
211 | LegacyImageLength = 0; | |
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 | // | |
235 | // If the pointer to the PCI Data Structure is invalid, no further images can be located. | |
236 | // The PCI Data Structure must be DWORD aligned. | |
237 | // | |
238 | if (OffsetPcir == 0 || | |
239 | (OffsetPcir & 3) != 0 || | |
240 | RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) { | |
241 | break; | |
242 | } | |
243 | PciDevice->PciRootBridgeIo->Mem.Read ( | |
244 | PciDevice->PciRootBridgeIo, | |
245 | EfiPciWidthUint8, | |
246 | RomBarOffset + OffsetPcir, | |
247 | sizeof (PCI_DATA_STRUCTURE), | |
248 | (UINT8 *) RomPcir | |
249 | ); | |
250 | // | |
251 | // If a valid signature is not present in the PCI Data Structure, no further images can be located. | |
252 | // | |
253 | if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { | |
254 | break; | |
255 | } | |
256 | if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) { | |
257 | break; | |
258 | } | |
259 | if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) { | |
260 | CodeType = PCI_CODE_TYPE_PCAT_IMAGE; | |
261 | LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512; | |
262 | } | |
263 | Indicator = RomPcir->Indicator; | |
264 | RomImageSize = RomImageSize + RomPcir->ImageLength * 512; | |
265 | RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512; | |
266 | } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize)); | |
267 | ||
268 | // | |
269 | // Some Legacy Cards do not report the correct ImageLength so used the maximum | |
270 | // of the legacy length and the PCIR Image Length | |
271 | // | |
272 | if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) { | |
273 | RomImageSize = MAX (RomImageSize, LegacyImageLength); | |
274 | } | |
275 | ||
276 | if (RomImageSize > 0) { | |
277 | retStatus = EFI_SUCCESS; | |
278 | Image = AllocatePool ((UINT32) RomImageSize); | |
279 | if (Image == NULL) { | |
280 | RomDecode (PciDevice, RomBarIndex, RomBar, FALSE); | |
281 | gBS->FreePool (RomHeader); | |
282 | gBS->FreePool (RomPcir); | |
283 | return EFI_OUT_OF_RESOURCES; | |
284 | } | |
285 | ||
286 | // | |
287 | // Copy Rom image into memory | |
288 | // | |
289 | PciDevice->PciRootBridgeIo->Mem.Read ( | |
290 | PciDevice->PciRootBridgeIo, | |
291 | EfiPciWidthUint8, | |
292 | RomBar, | |
293 | (UINT32) RomImageSize, | |
294 | Image | |
295 | ); | |
296 | RomInMemory = Image; | |
297 | } | |
298 | ||
299 | RomDecode (PciDevice, RomBarIndex, RomBar, FALSE); | |
300 | ||
301 | PciDevice->PciIo.RomSize = RomImageSize; | |
302 | PciDevice->PciIo.RomImage = RomInMemory; | |
303 | ||
304 | // | |
305 | // Free allocated memory | |
306 | // | |
307 | gBS->FreePool (RomHeader); | |
308 | gBS->FreePool (RomPcir); | |
309 | ||
310 | return retStatus; | |
311 | } | |
312 | ||
313 | EFI_STATUS | |
314 | RomDecode ( | |
315 | IN PCI_IO_DEVICE *PciDevice, | |
316 | IN UINT8 RomBarIndex, | |
317 | IN UINT32 RomBar, | |
318 | IN BOOLEAN Enable | |
319 | ) | |
320 | /*++ | |
321 | ||
322 | Routine Description: | |
323 | ||
324 | Arguments: | |
325 | ||
326 | Returns: | |
327 | ||
328 | --*/ | |
329 | { | |
330 | UINT16 CommandValue; | |
331 | UINT32 Value32; | |
332 | UINT64 Address; | |
333 | //EFI_STATUS Status; | |
334 | EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; | |
335 | ||
336 | PciRootBridgeIo = PciDevice->PciRootBridgeIo; | |
337 | if (Enable) { | |
338 | Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex); | |
339 | // | |
340 | // set the Rom base address: now is hardcode | |
341 | // | |
342 | PciRootBridgeIo->Pci.Write( | |
343 | PciRootBridgeIo, | |
344 | EfiPciWidthUint32, | |
345 | Address, | |
346 | 1, | |
347 | &RomBar); | |
348 | ||
349 | // | |
350 | // enable its decoder | |
351 | // | |
352 | Value32 = RomBar | 0x1; | |
353 | PciRootBridgeIo->Pci.Write( | |
354 | PciRootBridgeIo, | |
355 | EfiPciWidthUint32, | |
356 | Address, | |
357 | 1, | |
358 | &Value32); | |
359 | ||
360 | // | |
361 | //setting the memory space bit in the function's command register | |
362 | // | |
363 | Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, 0x04); | |
364 | PciRootBridgeIo->Pci.Read( | |
365 | PciRootBridgeIo, | |
366 | EfiPciWidthUint16, | |
367 | Address, | |
368 | 1, | |
369 | &CommandValue); | |
370 | ||
371 | CommandValue = (UINT16)(CommandValue | 0x0002); //0x0003 | |
372 | PciRootBridgeIo->Pci.Write( | |
373 | PciRootBridgeIo, | |
374 | EfiPciWidthUint16, | |
375 | Address, | |
376 | 1, | |
377 | &CommandValue); | |
378 | } else { | |
379 | // | |
380 | // disable rom decode | |
381 | // | |
382 | Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex); | |
383 | Value32 = 0xfffffffe; | |
384 | PciRootBridgeIo->Pci.Write( | |
385 | PciRootBridgeIo, | |
386 | EfiPciWidthUint32, | |
387 | Address, | |
388 | 1, | |
389 | &Value32); | |
390 | } | |
391 | ||
392 | return EFI_SUCCESS; | |
393 | ||
394 | } | |
395 | ||
396 | EFI_STATUS | |
397 | ProcessOpRomImage ( | |
398 | PCI_IO_DEVICE *PciDevice | |
399 | ) | |
400 | /*++ | |
401 | ||
402 | Routine Description: | |
403 | ||
404 | Process the oprom image. | |
405 | ||
406 | Arguments: | |
407 | PciDevice A pointer to a pci device. | |
408 | ||
409 | Returns: | |
410 | ||
411 | EFI Status. | |
412 | ||
413 | --*/ | |
414 | { | |
415 | UINT8 Indicator; | |
416 | UINT32 ImageSize; | |
417 | UINT16 ImageOffset; | |
418 | VOID *RomBar; | |
419 | UINT8 *RomBarOffset; | |
420 | EFI_HANDLE ImageHandle; | |
421 | EFI_STATUS Status; | |
422 | EFI_STATUS retStatus; | |
423 | BOOLEAN SkipImage; | |
424 | UINT32 DestinationSize; | |
425 | UINT32 ScratchSize; | |
426 | UINT8 *Scratch; | |
427 | VOID *ImageBuffer; | |
428 | VOID *DecompressedImageBuffer; | |
429 | UINT32 ImageLength; | |
430 | EFI_DECOMPRESS_PROTOCOL *Decompress; | |
431 | EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; | |
432 | PCI_DATA_STRUCTURE *Pcir; | |
433 | UINT32 InitializationSize; | |
434 | ||
435 | Indicator = 0; | |
436 | ||
437 | // | |
438 | // Get the Address of the Rom image | |
439 | // | |
440 | RomBar = PciDevice->PciIo.RomImage; | |
441 | RomBarOffset = (UINT8 *) RomBar; | |
442 | retStatus = EFI_NOT_FOUND; | |
443 | ||
444 | if (RomBarOffset == NULL) { | |
445 | return retStatus; | |
446 | } | |
447 | ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE); | |
448 | ||
449 | do { | |
450 | EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset; | |
451 | if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { | |
452 | RomBarOffset = RomBarOffset + 512; | |
453 | continue; | |
454 | } | |
455 | ||
456 | Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset); | |
457 | ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE); | |
458 | ImageSize = (UINT32) (Pcir->ImageLength * 512); | |
459 | Indicator = Pcir->Indicator; | |
460 | ||
461 | if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && | |
462 | (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) && | |
463 | ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || | |
464 | (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) { | |
465 | ||
466 | ImageOffset = EfiRomHeader->EfiImageHeaderOffset; | |
467 | InitializationSize = EfiRomHeader->InitializationSize * 512; | |
468 | ||
469 | if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) { | |
470 | ||
471 | ImageBuffer = (VOID *) (RomBarOffset + ImageOffset); | |
472 | ImageLength = InitializationSize - (UINT32)ImageOffset; | |
473 | DecompressedImageBuffer = NULL; | |
474 | ||
475 | // | |
476 | // decompress here if needed | |
477 | // | |
478 | SkipImage = FALSE; | |
479 | if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { | |
480 | SkipImage = TRUE; | |
481 | } | |
482 | ||
483 | if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { | |
484 | Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress); | |
485 | if (EFI_ERROR (Status)) { | |
486 | SkipImage = TRUE; | |
487 | } else { | |
488 | SkipImage = TRUE; | |
489 | Status = Decompress->GetInfo ( | |
490 | Decompress, | |
491 | ImageBuffer, | |
492 | ImageLength, | |
493 | &DestinationSize, | |
494 | &ScratchSize | |
495 | ); | |
496 | if (!EFI_ERROR (Status)) { | |
497 | DecompressedImageBuffer = NULL; | |
498 | DecompressedImageBuffer = AllocatePool (DestinationSize); | |
499 | if (DecompressedImageBuffer != NULL) { | |
500 | Scratch = AllocatePool (ScratchSize); | |
501 | if (Scratch != NULL) { | |
502 | Status = Decompress->Decompress ( | |
503 | Decompress, | |
504 | ImageBuffer, | |
505 | ImageLength, | |
506 | DecompressedImageBuffer, | |
507 | DestinationSize, | |
508 | Scratch, | |
509 | ScratchSize | |
510 | ); | |
511 | if (!EFI_ERROR (Status)) { | |
512 | ImageBuffer = DecompressedImageBuffer; | |
513 | ImageLength = DestinationSize; | |
514 | SkipImage = FALSE; | |
515 | } | |
516 | ||
517 | gBS->FreePool (Scratch); | |
518 | } | |
519 | } | |
520 | } | |
521 | } | |
522 | } | |
523 | ||
524 | if (!SkipImage) { | |
525 | // | |
526 | // load image and start image | |
527 | // | |
528 | Status = gBS->LoadImage ( | |
529 | FALSE, | |
530 | gPciBusDriverBinding.DriverBindingHandle, | |
531 | NULL, | |
532 | ImageBuffer, | |
533 | ImageLength, | |
534 | &ImageHandle | |
535 | ); | |
536 | if (!EFI_ERROR (Status)) { | |
537 | Status = gBS->StartImage (ImageHandle, NULL, NULL); | |
538 | if (!EFI_ERROR (Status)) { | |
539 | AddDriver (PciDevice, ImageHandle); | |
540 | retStatus = EFI_SUCCESS; | |
541 | } | |
542 | } | |
543 | } | |
544 | ||
545 | RomBarOffset = RomBarOffset + ImageSize; | |
546 | } else { | |
547 | RomBarOffset = RomBarOffset + ImageSize; | |
548 | } | |
549 | } else { | |
550 | RomBarOffset = RomBarOffset + ImageSize; | |
551 | } | |
552 | ||
553 | } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize)); | |
554 | ||
555 | return retStatus; | |
556 | ||
557 | } |