]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c
ShellPkg/Ping: fix loss of first packet
[mirror_edk2.git] / DuetPkg / PciBusNoEnumerationDxe / PciOptionRomSupport.c
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 }