PageRenderTime 54ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/PciBusNoEnumerationDxe/PciOptionRomSupport.c

https://github.com/SunnyKi/bareBoot
C | 557 lines | 354 code | 60 blank | 143 comment | 66 complexity | b15347d1458fdecf22b1ef386b312d93 MD5 | raw file
  1. /*++
  2. Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
  3. This program and the accompanying materials
  4. are licensed and made available under the terms and conditions of the BSD License
  5. which accompanies this distribution. The full text of the license may be found at
  6. http://opensource.org/licenses/bsd-license.php
  7. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
  9. Module Name:
  10. PciOptionRomSupport.c
  11. Abstract:
  12. PCI Bus Driver
  13. Revision History
  14. --*/
  15. #include "PciBus.h"
  16. EFI_STATUS
  17. RomDecode (
  18. IN PCI_IO_DEVICE *PciDevice,
  19. IN UINT8 RomBarIndex,
  20. IN UINT32 RomBar,
  21. IN BOOLEAN Enable
  22. );
  23. EFI_STATUS
  24. GetOpRomInfo (
  25. IN PCI_IO_DEVICE *PciIoDevice
  26. )
  27. /*++
  28. Routine Description:
  29. Arguments:
  30. Returns:
  31. --*/
  32. {
  33. UINT8 RomBarIndex;
  34. UINT32 AllOnes;
  35. UINT64 Address;
  36. EFI_STATUS Status;
  37. UINT8 Bus;
  38. UINT8 Device;
  39. UINT8 Function;
  40. EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
  41. Bus = PciIoDevice->BusNumber;
  42. Device = PciIoDevice->DeviceNumber;
  43. Function = PciIoDevice->FunctionNumber;
  44. PciRootBridgeIo = PciIoDevice->PciRootBridgeIo;
  45. //
  46. // offset is 0x30 if is not ppb
  47. //
  48. //
  49. // 0x30
  50. //
  51. RomBarIndex = PCI_EXPANSION_ROM_BASE;
  52. if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
  53. //
  54. // if is ppb
  55. //
  56. //
  57. // 0x38
  58. //
  59. RomBarIndex = PCI_BRIDGE_ROMBAR;
  60. }
  61. //
  62. // the bit0 is 0 to prevent the enabling of the Rom address decoder
  63. //
  64. AllOnes = 0xfffffffe;
  65. Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);
  66. Status = PciRootBridgeIo->Pci.Write (
  67. PciRootBridgeIo,
  68. EfiPciWidthUint32,
  69. Address,
  70. 1,
  71. &AllOnes
  72. );
  73. if (EFI_ERROR (Status)) {
  74. return Status;
  75. }
  76. //
  77. // read back
  78. //
  79. Status = PciRootBridgeIo->Pci.Read (
  80. PciRootBridgeIo,
  81. EfiPciWidthUint32,
  82. Address,
  83. 1,
  84. &AllOnes
  85. );
  86. if (EFI_ERROR (Status)) {
  87. return Status;
  88. }
  89. //
  90. // Bits [1, 10] are reserved
  91. //
  92. AllOnes &= 0xFFFFF800;
  93. if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
  94. return EFI_NOT_FOUND;
  95. }
  96. DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: OPROM detected!\n"));
  97. DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: B-%x, D-%x, F-%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Function));
  98. PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);
  99. return EFI_SUCCESS;
  100. }
  101. EFI_STATUS
  102. LoadOpRomImage (
  103. IN PCI_IO_DEVICE *PciDevice,
  104. IN UINT64 ReservedMemoryBase
  105. )
  106. /*++
  107. Routine Description:
  108. Load option rom image for specified PCI device
  109. Arguments:
  110. Returns:
  111. --*/
  112. {
  113. UINT8 RomBarIndex;
  114. UINT8 Indicator;
  115. UINT16 OffsetPcir;
  116. UINT32 RomBarOffset;
  117. UINT32 RomBar;
  118. EFI_STATUS retStatus;
  119. BOOLEAN FirstCheck;
  120. UINT8 *Image;
  121. PCI_EXPANSION_ROM_HEADER *RomHeader;
  122. PCI_DATA_STRUCTURE *RomPcir;
  123. UINT64 RomSize;
  124. UINT64 RomImageSize;
  125. UINT32 LegacyImageLength;
  126. UINT8 *RomInMemory;
  127. UINT8 CodeType;
  128. RomSize = PciDevice->RomSize;
  129. Indicator = 0;
  130. RomImageSize = 0;
  131. RomInMemory = NULL;
  132. CodeType = 0xFF;
  133. //
  134. // Get the RomBarIndex
  135. //
  136. //
  137. // 0x30
  138. //
  139. RomBarIndex = PCI_EXPANSION_ROM_BASE;
  140. if (IS_PCI_BRIDGE (&(PciDevice->Pci))) {
  141. //
  142. // if is ppb
  143. //
  144. //
  145. // 0x38
  146. //
  147. RomBarIndex = PCI_BRIDGE_ROMBAR;
  148. }
  149. //
  150. // Allocate memory for Rom header and PCIR
  151. //
  152. RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER));
  153. if (RomHeader == NULL) {
  154. return EFI_OUT_OF_RESOURCES;
  155. }
  156. RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE));
  157. if (RomPcir == NULL) {
  158. gBS->FreePool (RomHeader);
  159. return EFI_OUT_OF_RESOURCES;
  160. }
  161. RomBar = (UINT32)ReservedMemoryBase;
  162. //
  163. // Enable RomBar
  164. //
  165. RomDecode (PciDevice, RomBarIndex, RomBar, TRUE);
  166. RomBarOffset = RomBar;
  167. retStatus = EFI_NOT_FOUND;
  168. FirstCheck = TRUE;
  169. LegacyImageLength = 0;
  170. do {
  171. PciDevice->PciRootBridgeIo->Mem.Read (
  172. PciDevice->PciRootBridgeIo,
  173. EfiPciWidthUint8,
  174. RomBarOffset,
  175. sizeof (PCI_EXPANSION_ROM_HEADER),
  176. (UINT8 *) RomHeader
  177. );
  178. if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
  179. RomBarOffset = RomBarOffset + 512;
  180. if (FirstCheck) {
  181. break;
  182. } else {
  183. RomImageSize = RomImageSize + 512;
  184. continue;
  185. }
  186. }
  187. FirstCheck = FALSE;
  188. OffsetPcir = RomHeader->PcirOffset;
  189. //
  190. // If the pointer to the PCI Data Structure is invalid, no further images can be located.
  191. // The PCI Data Structure must be DWORD aligned.
  192. //
  193. if (OffsetPcir == 0 ||
  194. (OffsetPcir & 3) != 0 ||
  195. RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
  196. break;
  197. }
  198. PciDevice->PciRootBridgeIo->Mem.Read (
  199. PciDevice->PciRootBridgeIo,
  200. EfiPciWidthUint8,
  201. RomBarOffset + OffsetPcir,
  202. sizeof (PCI_DATA_STRUCTURE),
  203. (UINT8 *) RomPcir
  204. );
  205. //
  206. // If a valid signature is not present in the PCI Data Structure, no further images can be located.
  207. //
  208. if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
  209. break;
  210. }
  211. if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) {
  212. break;
  213. }
  214. if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
  215. CodeType = PCI_CODE_TYPE_PCAT_IMAGE;
  216. LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512;
  217. }
  218. Indicator = RomPcir->Indicator;
  219. RomImageSize = RomImageSize + RomPcir->ImageLength * 512;
  220. RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512;
  221. } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize));
  222. //
  223. // Some Legacy Cards do not report the correct ImageLength so used the maximum
  224. // of the legacy length and the PCIR Image Length
  225. //
  226. if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
  227. RomImageSize = MAX (RomImageSize, LegacyImageLength);
  228. }
  229. if (RomImageSize > 0) {
  230. retStatus = EFI_SUCCESS;
  231. Image = AllocatePool ((UINT32) RomImageSize);
  232. if (Image == NULL) {
  233. RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
  234. gBS->FreePool (RomHeader);
  235. gBS->FreePool (RomPcir);
  236. return EFI_OUT_OF_RESOURCES;
  237. }
  238. //
  239. // Copy Rom image into memory
  240. //
  241. PciDevice->PciRootBridgeIo->Mem.Read (
  242. PciDevice->PciRootBridgeIo,
  243. EfiPciWidthUint8,
  244. RomBar,
  245. (UINT32) RomImageSize,
  246. Image
  247. );
  248. RomInMemory = Image;
  249. }
  250. RomDecode (PciDevice, RomBarIndex, RomBar, FALSE);
  251. PciDevice->PciIo.RomSize = RomImageSize;
  252. PciDevice->PciIo.RomImage = RomInMemory;
  253. //
  254. // Free allocated memory
  255. //
  256. gBS->FreePool (RomHeader);
  257. gBS->FreePool (RomPcir);
  258. return retStatus;
  259. }
  260. EFI_STATUS
  261. RomDecode (
  262. IN PCI_IO_DEVICE *PciDevice,
  263. IN UINT8 RomBarIndex,
  264. IN UINT32 RomBar,
  265. IN BOOLEAN Enable
  266. )
  267. /*++
  268. Routine Description:
  269. Arguments:
  270. Returns:
  271. --*/
  272. {
  273. UINT16 CommandValue;
  274. UINT32 Value32;
  275. UINT64 Address;
  276. //EFI_STATUS Status;
  277. EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
  278. PciRootBridgeIo = PciDevice->PciRootBridgeIo;
  279. if (Enable) {
  280. Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
  281. //
  282. // set the Rom base address: now is hardcode
  283. //
  284. PciRootBridgeIo->Pci.Write(
  285. PciRootBridgeIo,
  286. EfiPciWidthUint32,
  287. Address,
  288. 1,
  289. &RomBar);
  290. //
  291. // enable its decoder
  292. //
  293. Value32 = RomBar | 0x1;
  294. PciRootBridgeIo->Pci.Write(
  295. PciRootBridgeIo,
  296. EfiPciWidthUint32,
  297. Address,
  298. 1,
  299. &Value32);
  300. //
  301. //setting the memory space bit in the function's command register
  302. //
  303. Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, 0x04);
  304. PciRootBridgeIo->Pci.Read(
  305. PciRootBridgeIo,
  306. EfiPciWidthUint16,
  307. Address,
  308. 1,
  309. &CommandValue);
  310. CommandValue = (UINT16)(CommandValue | 0x0002); //0x0003
  311. PciRootBridgeIo->Pci.Write(
  312. PciRootBridgeIo,
  313. EfiPciWidthUint16,
  314. Address,
  315. 1,
  316. &CommandValue);
  317. } else {
  318. //
  319. // disable rom decode
  320. //
  321. Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex);
  322. Value32 = 0xfffffffe;
  323. PciRootBridgeIo->Pci.Write(
  324. PciRootBridgeIo,
  325. EfiPciWidthUint32,
  326. Address,
  327. 1,
  328. &Value32);
  329. }
  330. return EFI_SUCCESS;
  331. }
  332. EFI_STATUS
  333. ProcessOpRomImage (
  334. PCI_IO_DEVICE *PciDevice
  335. )
  336. /*++
  337. Routine Description:
  338. Process the oprom image.
  339. Arguments:
  340. PciDevice A pointer to a pci device.
  341. Returns:
  342. EFI Status.
  343. --*/
  344. {
  345. UINT8 Indicator;
  346. UINT32 ImageSize;
  347. UINT16 ImageOffset;
  348. VOID *RomBar;
  349. UINT8 *RomBarOffset;
  350. EFI_HANDLE ImageHandle;
  351. EFI_STATUS Status;
  352. EFI_STATUS retStatus;
  353. BOOLEAN SkipImage;
  354. UINT32 DestinationSize;
  355. UINT32 ScratchSize;
  356. UINT8 *Scratch;
  357. VOID *ImageBuffer;
  358. VOID *DecompressedImageBuffer;
  359. UINT32 ImageLength;
  360. EFI_DECOMPRESS_PROTOCOL *Decompress;
  361. EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader;
  362. PCI_DATA_STRUCTURE *Pcir;
  363. UINT32 InitializationSize;
  364. Indicator = 0;
  365. //
  366. // Get the Address of the Rom image
  367. //
  368. RomBar = PciDevice->PciIo.RomImage;
  369. RomBarOffset = (UINT8 *) RomBar;
  370. retStatus = EFI_NOT_FOUND;
  371. if (RomBarOffset == NULL) {
  372. return retStatus;
  373. }
  374. ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE);
  375. do {
  376. EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset;
  377. if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
  378. RomBarOffset = RomBarOffset + 512;
  379. continue;
  380. }
  381. Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset);
  382. ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE);
  383. ImageSize = (UINT32) (Pcir->ImageLength * 512);
  384. Indicator = Pcir->Indicator;
  385. if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
  386. (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
  387. ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
  388. (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) {
  389. ImageOffset = EfiRomHeader->EfiImageHeaderOffset;
  390. InitializationSize = EfiRomHeader->InitializationSize * 512;
  391. if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) {
  392. ImageBuffer = (VOID *) (RomBarOffset + ImageOffset);
  393. ImageLength = InitializationSize - (UINT32)ImageOffset;
  394. DecompressedImageBuffer = NULL;
  395. //
  396. // decompress here if needed
  397. //
  398. SkipImage = FALSE;
  399. if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
  400. SkipImage = TRUE;
  401. }
  402. if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
  403. Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
  404. if (EFI_ERROR (Status)) {
  405. SkipImage = TRUE;
  406. } else {
  407. SkipImage = TRUE;
  408. Status = Decompress->GetInfo (
  409. Decompress,
  410. ImageBuffer,
  411. ImageLength,
  412. &DestinationSize,
  413. &ScratchSize
  414. );
  415. if (!EFI_ERROR (Status)) {
  416. DecompressedImageBuffer = NULL;
  417. DecompressedImageBuffer = AllocatePool (DestinationSize);
  418. if (DecompressedImageBuffer != NULL) {
  419. Scratch = AllocatePool (ScratchSize);
  420. if (Scratch != NULL) {
  421. Status = Decompress->Decompress (
  422. Decompress,
  423. ImageBuffer,
  424. ImageLength,
  425. DecompressedImageBuffer,
  426. DestinationSize,
  427. Scratch,
  428. ScratchSize
  429. );
  430. if (!EFI_ERROR (Status)) {
  431. ImageBuffer = DecompressedImageBuffer;
  432. ImageLength = DestinationSize;
  433. SkipImage = FALSE;
  434. }
  435. gBS->FreePool (Scratch);
  436. }
  437. }
  438. }
  439. }
  440. }
  441. if (!SkipImage) {
  442. //
  443. // load image and start image
  444. //
  445. Status = gBS->LoadImage (
  446. FALSE,
  447. gPciBusDriverBinding.DriverBindingHandle,
  448. NULL,
  449. ImageBuffer,
  450. ImageLength,
  451. &ImageHandle
  452. );
  453. if (!EFI_ERROR (Status)) {
  454. Status = gBS->StartImage (ImageHandle, NULL, NULL);
  455. if (!EFI_ERROR (Status)) {
  456. AddDriver (PciDevice, ImageHandle);
  457. retStatus = EFI_SUCCESS;
  458. }
  459. }
  460. }
  461. RomBarOffset = RomBarOffset + ImageSize;
  462. } else {
  463. RomBarOffset = RomBarOffset + ImageSize;
  464. }
  465. } else {
  466. RomBarOffset = RomBarOffset + ImageSize;
  467. }
  468. } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize));
  469. return retStatus;
  470. }