IScsiIbft.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /** @file
  2. Implementation for iSCSI Boot Firmware Table publication.
  3. Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "IScsiImpl.h"
  7. BOOLEAN mIbftInstalled = FALSE;
  8. UINTN mTableKey;
  9. /**
  10. Initialize the header of the iSCSI Boot Firmware Table.
  11. @param[out] Header The header of the iSCSI Boot Firmware Table.
  12. @param[in] OemId The OEM ID.
  13. @param[in] OemTableId The OEM table ID for the iBFT.
  14. **/
  15. VOID
  16. IScsiInitIbfTableHeader (
  17. OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Header,
  18. IN UINT8 *OemId,
  19. IN UINT64 *OemTableId
  20. )
  21. {
  22. Header->Signature = EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE;
  23. Header->Length = IBFT_HEAP_OFFSET;
  24. Header->Revision = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION;
  25. Header->Checksum = 0;
  26. CopyMem (Header->OemId, OemId, sizeof (Header->OemId));
  27. CopyMem (&Header->OemTableId, OemTableId, sizeof (UINT64));
  28. }
  29. /**
  30. Initialize the control section of the iSCSI Boot Firmware Table.
  31. @param[in] Table The ACPI table.
  32. **/
  33. VOID
  34. IScsiInitControlSection (
  35. IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table
  36. )
  37. {
  38. EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;
  39. UINTN NumOffset;
  40. Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *)(Table + 1);
  41. Control->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID;
  42. Control->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION;
  43. Control->Header.Length = (UINT16)sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE);
  44. //
  45. // If in multipathing mode, enable the Boot Failover Flag.
  46. // If in single path mode, disable it. Mix-model is not allowed.
  47. //
  48. // BUGBUG: if Boot Failover Flag is set to 1, the OS installer cannot
  49. // find the iSCSI mapped disk. So still keep not set for single path mode.
  50. //
  51. if (mPrivate->EnableMpio) {
  52. Control->Header.Flags = 0;
  53. NumOffset = 2 * (mPrivate->MpioCount - mPrivate->Krb5MpioCount);
  54. } else {
  55. NumOffset = 2 * mPrivate->ValidSinglePathCount;
  56. }
  57. //
  58. // Each attempt occupies two offsets: one for the NIC section;
  59. // the other for the Target section.
  60. //
  61. if (NumOffset > 4) {
  62. //
  63. // Need expand the control section if more than 2 NIC/Target attempts
  64. // exist.
  65. //
  66. Control->Header.Length = (UINT16)(Control->Header.Length + (NumOffset - 4) * sizeof (UINT16));
  67. }
  68. }
  69. /**
  70. Add one item into the heap.
  71. @param[in, out] Heap On input, the current address of the heap. On output, the address of
  72. the heap after the item is added.
  73. @param[in] Data The data to add into the heap.
  74. @param[in] Len Length of the Data in byte.
  75. **/
  76. VOID
  77. IScsiAddHeapItem (
  78. IN OUT UINT8 **Heap,
  79. IN VOID *Data,
  80. IN UINTN Len
  81. )
  82. {
  83. //
  84. // Add one byte for the NULL delimiter.
  85. //
  86. *Heap -= Len + 1;
  87. CopyMem (*Heap, Data, Len);
  88. *(*Heap + Len) = 0;
  89. }
  90. /**
  91. Fill the Initiator section of the iSCSI Boot Firmware Table.
  92. @param[in] Table The ACPI table.
  93. @param[in, out] Heap The heap.
  94. **/
  95. VOID
  96. IScsiFillInitiatorSection (
  97. IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,
  98. IN OUT UINT8 **Heap
  99. )
  100. {
  101. EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;
  102. EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *Initiator;
  103. Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *)(Table + 1);
  104. //
  105. // Initiator section immediately follows the control section.
  106. //
  107. Initiator = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *)
  108. ((UINT8 *)Control + IBFT_ROUNDUP (Control->Header.Length));
  109. Control->InitiatorOffset = (UINT16)((UINTN)Initiator - (UINTN)Table);
  110. Initiator->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID;
  111. Initiator->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION;
  112. Initiator->Header.Length = (UINT16)sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE);
  113. Initiator->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BLOCK_VALID |
  114. EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BOOT_SELECTED;
  115. //
  116. // Fill the iSCSI Initiator Name into the heap.
  117. //
  118. IScsiAddHeapItem (Heap, mPrivate->InitiatorName, mPrivate->InitiatorNameLength - 1);
  119. Initiator->IScsiNameLength = (UINT16)(mPrivate->InitiatorNameLength - 1);
  120. Initiator->IScsiNameOffset = (UINT16)((UINTN)*Heap - (UINTN)Table);
  121. }
  122. /**
  123. Map the v4 IP address into v6 IP address.
  124. @param[in] V4 The v4 IP address.
  125. @param[out] V6 The v6 IP address.
  126. **/
  127. VOID
  128. IScsiMapV4ToV6Addr (
  129. IN EFI_IPv4_ADDRESS *V4,
  130. OUT EFI_IPv6_ADDRESS *V6
  131. )
  132. {
  133. UINTN Index;
  134. ZeroMem (V6, sizeof (EFI_IPv6_ADDRESS));
  135. V6->Addr[10] = 0xff;
  136. V6->Addr[11] = 0xff;
  137. for (Index = 0; Index < 4; Index++) {
  138. V6->Addr[12 + Index] = V4->Addr[Index];
  139. }
  140. }
  141. /**
  142. Fill the NIC and target sections in iSCSI Boot Firmware Table.
  143. @param[in] Table The buffer of the ACPI table.
  144. @param[in, out] Heap The heap buffer used to store the variable length
  145. parameters such as iSCSI name.
  146. **/
  147. VOID
  148. IScsiFillNICAndTargetSections (
  149. IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,
  150. IN OUT UINT8 **Heap
  151. )
  152. {
  153. EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;
  154. EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *Nic;
  155. EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *Target;
  156. ISCSI_SESSION_CONFIG_NVDATA *NvData;
  157. ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig;
  158. UINT16 *SectionOffset;
  159. UINTN Index;
  160. UINT16 Length;
  161. LIST_ENTRY *Entry;
  162. ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt;
  163. ISCSI_NIC_INFO *NicInfo;
  164. BOOLEAN Flag;
  165. //
  166. // Get the offset of the first Nic and Target section.
  167. //
  168. Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *)(Table + 1);
  169. Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *)((UINTN)Table +
  170. Control->InitiatorOffset + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE)));
  171. Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *)((UINTN)Nic +
  172. IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));
  173. SectionOffset = &Control->NIC0Offset;
  174. Index = 0;
  175. Flag = TRUE;
  176. NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
  177. if (Index == 0) {
  178. //
  179. // First entry should be boot selected entry.
  180. //
  181. Attempt = IScsiConfigGetAttemptByConfigIndex (mPrivate->BootSelectedIndex);
  182. if (Attempt == NULL) {
  183. //
  184. // First boot selected entry can not be found.
  185. //
  186. break;
  187. }
  188. ASSERT (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED);
  189. } else {
  190. if ((Index == 1) && Flag) {
  191. Entry = mPrivate->AttemptConfigs.ForwardLink;
  192. Flag = FALSE;
  193. }
  194. Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
  195. if (Attempt->AttemptConfigIndex == mPrivate->BootSelectedIndex) {
  196. continue;
  197. }
  198. }
  199. if (Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) {
  200. continue;
  201. }
  202. //
  203. // Krb5 attempt will not be recorded in iBFT.
  204. //
  205. if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {
  206. continue;
  207. }
  208. //
  209. // If multipath mode is enabled, only the attempts in MPIO will be recorded in iBFT.
  210. //
  211. if (mPrivate->EnableMpio && (Attempt->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO)) {
  212. continue;
  213. }
  214. //
  215. // Only the valid attempts will be recorded.
  216. //
  217. if (!Attempt->ValidiBFTPath) {
  218. continue;
  219. }
  220. NvData = &Attempt->SessionConfigData;
  221. AuthConfig = &Attempt->AuthConfigData.CHAP;
  222. //
  223. // Fill the Nic section.
  224. //
  225. Nic->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID;
  226. Nic->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION;
  227. Nic->Header.Length = (UINT16)sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE);
  228. Nic->Header.Index = (UINT8)Index;
  229. Nic->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID |
  230. EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL;
  231. if (Index == 0) {
  232. Nic->Header.Flags |= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED;
  233. }
  234. if (NvData->InitiatorInfoFromDhcp) {
  235. Nic->Origin = IpPrefixOriginDhcp;
  236. } else {
  237. Nic->Origin = IpPrefixOriginManual;
  238. }
  239. if ((NvData->IpMode == IP_MODE_IP4) || (NvData->IpMode == IP_MODE_AUTOCONFIG)) {
  240. //
  241. // Get the subnet mask prefix length.
  242. //
  243. Nic->SubnetMaskPrefixLength = IScsiGetSubnetMaskPrefixLength (&NvData->SubnetMask);
  244. //
  245. // Map the various v4 addresses into v6 addresses.
  246. //
  247. IScsiMapV4ToV6Addr (&NvData->LocalIp.v4, &Nic->Ip);
  248. IScsiMapV4ToV6Addr (&NvData->Gateway.v4, &Nic->Gateway);
  249. IScsiMapV4ToV6Addr (&Attempt->PrimaryDns.v4, &Nic->PrimaryDns);
  250. IScsiMapV4ToV6Addr (&Attempt->SecondaryDns.v4, &Nic->SecondaryDns);
  251. IScsiMapV4ToV6Addr (&Attempt->DhcpServer.v4, &Nic->DhcpServer);
  252. } else if ((NvData->IpMode == IP_MODE_IP6) || (NvData->IpMode == IP_MODE_AUTOCONFIG)) {
  253. Nic->SubnetMaskPrefixLength = NvData->PrefixLength;
  254. CopyMem (&Nic->Ip, &NvData->LocalIp, sizeof (EFI_IPv6_ADDRESS));
  255. CopyMem (&Nic->Gateway, &NvData->Gateway, sizeof (EFI_IPv6_ADDRESS));
  256. CopyMem (&Nic->PrimaryDns, &Attempt->PrimaryDns, sizeof (EFI_IPv6_ADDRESS));
  257. CopyMem (&Nic->SecondaryDns, &Attempt->SecondaryDns, sizeof (EFI_IPv6_ADDRESS));
  258. CopyMem (&Nic->DhcpServer, &Attempt->DhcpServer, sizeof (EFI_IPv6_ADDRESS));
  259. } else {
  260. ASSERT (FALSE);
  261. }
  262. //
  263. // Get Nic Info: VLAN tag, Mac address, PCI location.
  264. //
  265. NicInfo = IScsiGetNicInfoByIndex (Attempt->NicIndex);
  266. ASSERT (NicInfo != NULL);
  267. Nic->VLanTag = NicInfo->VlanId;
  268. CopyMem (Nic->Mac, &NicInfo->PermanentAddress, sizeof (Nic->Mac));
  269. Nic->PciLocation = (UINT16)((NicInfo->BusNumber << 8) |
  270. (NicInfo->DeviceNumber << 3) | NicInfo->FunctionNumber);
  271. *SectionOffset = (UINT16)((UINTN)Nic - (UINTN)Table);
  272. SectionOffset++;
  273. //
  274. // Fill the Target section.
  275. //
  276. Target->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID;
  277. Target->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION;
  278. Target->Header.Length = (UINT16)sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE);
  279. Target->Header.Index = (UINT8)Index;
  280. Target->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID;
  281. if (Index == 0) {
  282. Target->Header.Flags |= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED;
  283. }
  284. Target->Port = NvData->TargetPort;
  285. if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
  286. if (AuthConfig->CHAPType == ISCSI_CHAP_UNI) {
  287. Target->CHAPType = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_CHAP;
  288. } else if (AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) {
  289. Target->CHAPType = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP;
  290. }
  291. } else if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_NONE) {
  292. Target->CHAPType = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_NO_CHAP;
  293. }
  294. Target->NicIndex = (UINT8)Index;
  295. if ((NvData->IpMode == IP_MODE_IP4) || (NvData->IpMode == IP_MODE_AUTOCONFIG)) {
  296. IScsiMapV4ToV6Addr (&NvData->TargetIp.v4, &Target->Ip);
  297. } else if ((NvData->IpMode == IP_MODE_IP6) || (NvData->IpMode == IP_MODE_AUTOCONFIG)) {
  298. CopyMem (&Target->Ip, &NvData->TargetIp, sizeof (EFI_IPv6_ADDRESS));
  299. } else {
  300. ASSERT (FALSE);
  301. }
  302. CopyMem (Target->BootLun, NvData->BootLun, sizeof (Target->BootLun));
  303. //
  304. // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.
  305. //
  306. Length = (UINT16)AsciiStrLen (NvData->TargetName);
  307. IScsiAddHeapItem (Heap, NvData->TargetName, Length);
  308. Target->IScsiNameLength = Length;
  309. Target->IScsiNameOffset = (UINT16)((UINTN)*Heap - (UINTN)Table);
  310. if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
  311. //
  312. // CHAP Name
  313. //
  314. Length = (UINT16)AsciiStrLen (AuthConfig->CHAPName);
  315. IScsiAddHeapItem (Heap, AuthConfig->CHAPName, Length);
  316. Target->CHAPNameLength = Length;
  317. Target->CHAPNameOffset = (UINT16)((UINTN)*Heap - (UINTN)Table);
  318. //
  319. // CHAP Secret
  320. //
  321. Length = (UINT16)AsciiStrLen (AuthConfig->CHAPSecret);
  322. IScsiAddHeapItem (Heap, AuthConfig->CHAPSecret, Length);
  323. Target->CHAPSecretLength = Length;
  324. Target->CHAPSecretOffset = (UINT16)((UINTN)*Heap - (UINTN)Table);
  325. if (Target->CHAPType == EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP) {
  326. //
  327. // Reverse CHAP Name.
  328. //
  329. Length = (UINT16)AsciiStrLen (AuthConfig->ReverseCHAPName);
  330. IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPName, Length);
  331. Target->ReverseCHAPNameLength = Length;
  332. Target->ReverseCHAPNameOffset = (UINT16)((UINTN)*Heap - (UINTN)Table);
  333. //
  334. // Reverse CHAP Secret.
  335. //
  336. Length = (UINT16)AsciiStrLen (AuthConfig->ReverseCHAPSecret);
  337. IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPSecret, Length);
  338. Target->ReverseCHAPSecretLength = Length;
  339. Target->ReverseCHAPSecretOffset = (UINT16)((UINTN)*Heap - (UINTN)Table);
  340. }
  341. }
  342. *SectionOffset = (UINT16)((UINTN)Target - (UINTN)Table);
  343. SectionOffset++;
  344. //
  345. // Advance to the next NIC/Target pair.
  346. //
  347. Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *)((UINTN)Target +
  348. IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE)));
  349. Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *)((UINTN)Nic +
  350. IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));
  351. Index++;
  352. }
  353. }
  354. /**
  355. Publish and remove the iSCSI Boot Firmware Table according to the iSCSI
  356. session status.
  357. **/
  358. VOID
  359. IScsiPublishIbft (
  360. IN VOID
  361. )
  362. {
  363. EFI_STATUS Status;
  364. EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
  365. EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table;
  366. EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
  367. EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
  368. EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
  369. UINT8 *Heap;
  370. UINT8 Checksum;
  371. Rsdt = NULL;
  372. Xsdt = NULL;
  373. Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTableProtocol);
  374. if (EFI_ERROR (Status)) {
  375. return;
  376. }
  377. //
  378. // Find ACPI table RSD_PTR from the system table.
  379. //
  380. Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **)&Rsdp);
  381. if (EFI_ERROR (Status)) {
  382. Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **)&Rsdp);
  383. }
  384. if (EFI_ERROR (Status) || (Rsdp == NULL)) {
  385. return;
  386. } else if ((Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) && (Rsdp->XsdtAddress != 0)) {
  387. Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->XsdtAddress;
  388. } else if (Rsdp->RsdtAddress != 0) {
  389. Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->RsdtAddress;
  390. }
  391. if ((Xsdt == NULL) && (Rsdt == NULL)) {
  392. return;
  393. }
  394. if (mIbftInstalled) {
  395. Status = AcpiTableProtocol->UninstallAcpiTable (
  396. AcpiTableProtocol,
  397. mTableKey
  398. );
  399. if (EFI_ERROR (Status)) {
  400. return;
  401. }
  402. mIbftInstalled = FALSE;
  403. }
  404. //
  405. // If there is no valid attempt configuration, just return.
  406. //
  407. if ((!mPrivate->EnableMpio && (mPrivate->ValidSinglePathCount == 0)) ||
  408. (mPrivate->EnableMpio && (mPrivate->MpioCount <= mPrivate->Krb5MpioCount)))
  409. {
  410. return;
  411. }
  412. //
  413. // Allocate 4k bytes to hold the ACPI table.
  414. //
  415. Table = AllocateZeroPool (IBFT_MAX_SIZE);
  416. if (Table == NULL) {
  417. return;
  418. }
  419. Heap = (UINT8 *)Table + IBFT_HEAP_OFFSET;
  420. //
  421. // Fill in the various section of the iSCSI Boot Firmware Table.
  422. //
  423. if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
  424. IScsiInitIbfTableHeader (Table, Xsdt->OemId, &Xsdt->OemTableId);
  425. } else {
  426. IScsiInitIbfTableHeader (Table, Rsdt->OemId, &Rsdt->OemTableId);
  427. }
  428. IScsiInitControlSection (Table);
  429. IScsiFillInitiatorSection (Table, &Heap);
  430. IScsiFillNICAndTargetSections (Table, &Heap);
  431. Checksum = CalculateCheckSum8 ((UINT8 *)Table, Table->Length);
  432. Table->Checksum = Checksum;
  433. //
  434. // Install or update the iBFT table.
  435. //
  436. Status = AcpiTableProtocol->InstallAcpiTable (
  437. AcpiTableProtocol,
  438. Table,
  439. Table->Length,
  440. &mTableKey
  441. );
  442. if (EFI_ERROR (Status)) {
  443. return;
  444. }
  445. mIbftInstalled = TRUE;
  446. FreePool (Table);
  447. }