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