]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/IScsiDxe/IScsiIbft.c
Add IScsiDxe driver to NetworkPkg in order to support iSCSI over IPv6 stack and iSCSI...
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiIbft.c
diff --git a/NetworkPkg/IScsiDxe/IScsiIbft.c b/NetworkPkg/IScsiDxe/IScsiIbft.c
new file mode 100644 (file)
index 0000000..e90c982
--- /dev/null
@@ -0,0 +1,546 @@
+/** @file\r
+  Implementation for iSCSI Boot Firmware Table publication.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+BOOLEAN mIbftInstalled = FALSE;\r
+UINTN   mTableKey;\r
+\r
+/**\r
+  Initialize the header of the iSCSI Boot Firmware Table.\r
+  \r
+  @param[out]  Header     The header of the iSCSI Boot Firmware Table.\r
+  @param[in]   OemId      The OEM ID.\r
+  @param[in]   OemTableId The OEM table ID for the iBFT.\r
+\r
+**/\r
+VOID\r
+IScsiInitIbfTableHeader (\r
+  OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER   *Header,\r
+  IN  UINT8                                       *OemId,\r
+  IN  UINT64                                      *OemTableId\r
+  )\r
+{\r
+  Header->Signature = EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE;\r
+  Header->Length    = IBFT_HEAP_OFFSET;\r
+  Header->Revision  = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION;\r
+  Header->Checksum  = 0;\r
+\r
+  CopyMem (Header->OemId, OemId, sizeof (Header->OemId));\r
+  CopyMem (&Header->OemTableId, OemTableId, sizeof (UINT64));\r
+}\r
+\r
+\r
+/**\r
+  Initialize the control section of the iSCSI Boot Firmware Table.\r
+\r
+  @param[in]  Table       The ACPI table.\r
+\r
+**/\r
+VOID\r
+IScsiInitControlSection (\r
+  IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER  *Table\r
+  )\r
+{\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE  *Control;\r
+  UINTN                                                 NumOffset;\r
+\r
+  Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);\r
+\r
+  Control->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID;\r
+  Control->Header.Version     = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION;\r
+  Control->Header.Length      = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE);\r
+\r
+  //\r
+  // If in multipathing mode, enable the Boot Failover Flag.\r
+  // If in single path mode, disable it. Mix-model is not allowed.\r
+  //\r
+  // BUGBUG: if Boot Failover Flag is set to 1, the OS installer cannot\r
+  // find the iSCSI mapped disk. So still keep not set for single path mode.\r
+  //\r
+  if (mPrivate->EnableMpio) {\r
+    Control->Header.Flags = 0;\r
+    NumOffset = 2 * (mPrivate->MpioCount - mPrivate->Krb5MpioCount);\r
+  } else {\r
+    NumOffset = 2 * mPrivate->ValidSinglePathCount;\r
+  }\r
+\r
+  //\r
+  // Each attempt occupies two offsets: one for the NIC section;\r
+  // the other for the Target section.\r
+  //\r
+  if (NumOffset > 4) {\r
+    //\r
+    // Need expand the control section if more than 2 NIC/Target attempts\r
+    // exist.\r
+    //\r
+    Control->Header.Length = (UINT16) (Control->Header.Length + (NumOffset - 4) * sizeof (UINT16));\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Add one item into the heap.\r
+\r
+  @param[in, out]  Heap  On input, the current address of the heap. On output, the address of\r
+                         the heap after the item is added.\r
+  @param[in]       Data  The data to add into the heap.\r
+  @param[in]       Len   Length of the Data in byte.\r
+\r
+**/\r
+VOID\r
+IScsiAddHeapItem (\r
+  IN OUT UINT8  **Heap,\r
+  IN     VOID   *Data,\r
+  IN     UINTN  Len\r
+  )\r
+{\r
+  //\r
+  // Add one byte for the NULL delimiter.\r
+  //\r
+  *Heap -= Len + 1;\r
+\r
+  CopyMem (*Heap, Data, Len);\r
+  *(*Heap + Len) = 0;\r
+}\r
+\r
+\r
+/**\r
+  Fill the Initiator section of the iSCSI Boot Firmware Table.\r
+\r
+  @param[in]       Table    The ACPI table.\r
+  @param[in, out]  Heap     The heap.\r
+\r
+**/\r
+VOID\r
+IScsiFillInitiatorSection (\r
+  IN     EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER  *Table,\r
+  IN OUT UINT8                                      **Heap\r
+  )\r
+{\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE    *Control;\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE  *Initiator;\r
+\r
+  Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);\r
+\r
+  //\r
+  // Initiator section immediately follows the control section.\r
+  //\r
+  Initiator = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *)\r
+              ((UINT8 *) Control + IBFT_ROUNDUP (Control->Header.Length));\r
+\r
+  Control->InitiatorOffset = (UINT16) ((UINTN) Initiator - (UINTN) Table);\r
+\r
+  Initiator->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID;\r
+  Initiator->Header.Version     = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION;\r
+  Initiator->Header.Length      = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE);\r
+  Initiator->Header.Flags       = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BLOCK_VALID |\r
+                                  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BOOT_SELECTED;\r
+\r
+  //\r
+  // Fill the iSCSI Initiator Name into the heap.\r
+  //\r
+  IScsiAddHeapItem (Heap, mPrivate->InitiatorName, mPrivate->InitiatorNameLength - 1);\r
+\r
+  Initiator->IScsiNameLength  = (UINT16) (mPrivate->InitiatorNameLength - 1);\r
+  Initiator->IScsiNameOffset  = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+}\r
+\r
+\r
+/**\r
+  Map the v4 IP address into v6 IP address.\r
+\r
+  @param[in]   V4 The v4 IP address.\r
+  @param[out]  V6 The v6 IP address.\r
+\r
+**/\r
+VOID\r
+IScsiMapV4ToV6Addr (\r
+  IN  EFI_IPv4_ADDRESS *V4,\r
+  OUT EFI_IPv6_ADDRESS *V6\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  ZeroMem (V6, sizeof (EFI_IPv6_ADDRESS));\r
+\r
+  V6->Addr[10]  = 0xff;\r
+  V6->Addr[11]  = 0xff;\r
+\r
+  for (Index = 0; Index < 4; Index++) {\r
+    V6->Addr[12 + Index] = V4->Addr[Index];\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Fill the NIC and target sections in iSCSI Boot Firmware Table.\r
+\r
+  @param[in]       Table    The buffer of the ACPI table.\r
+  @param[in, out]  Heap     The heap buffer used to store the variable length\r
+                            parameters such as iSCSI name.\r
+\r
+**/\r
+VOID\r
+IScsiFillNICAndTargetSections (\r
+  IN     EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER  *Table,\r
+  IN OUT UINT8                                      **Heap\r
+  )\r
+{\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE  *Control;\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE      *Nic;\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE   *Target;\r
+  ISCSI_SESSION_CONFIG_NVDATA                           *NvData;\r
+  ISCSI_CHAP_AUTH_CONFIG_NVDATA                         *AuthConfig;\r
+  UINT16                                                *SectionOffset;\r
+  UINTN                                                 Index;\r
+  UINT16                                                Length;\r
+  LIST_ENTRY                                            *Entry;\r
+  ISCSI_ATTEMPT_CONFIG_NVDATA                           *Attempt;\r
+  ISCSI_NIC_INFO                                        *NicInfo;\r
+  BOOLEAN                                               Flag;\r
+\r
+  //\r
+  // Get the offset of the first Nic and Target section.\r
+  //\r
+  Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);\r
+  Nic     = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Table +\r
+          Control->InitiatorOffset + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE)));\r
+  Target  = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +\r
+          IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));\r
+\r
+  SectionOffset = &Control->NIC0Offset;\r
+\r
+  Index = 0;\r
+  Flag  = TRUE;\r
+\r
+  NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {\r
+    if (Index == 0) {\r
+      //\r
+      // First entry should be boot selected entry.\r
+      //\r
+      Attempt = IScsiConfigGetAttemptByConfigIndex (mPrivate->BootSelectedIndex);\r
+      if (Attempt == NULL) {\r
+        //\r
+        // First boot selected entry can not be found.\r
+        //\r
+        break;\r
+      }\r
+\r
+      ASSERT (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED);\r
+\r
+    } else {\r
+      if (Index == 1 && Flag) {\r
+        Entry = mPrivate->AttemptConfigs.ForwardLink;\r
+        Flag = FALSE;\r
+      }\r
+\r
+      Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);\r
+      if (Attempt->AttemptConfigIndex == mPrivate->BootSelectedIndex) {\r
+        continue;\r
+      }\r
+    }\r
+\r
+    if (Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Krb5 attempt will not be recorded in iBFT.\r
+    //\r
+    if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // If multipath mode is enabled, only the attempts in MPIO will be recorded in iBFT.\r
+    //\r
+    if (mPrivate->EnableMpio && Attempt->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Only the valid attempts will be recorded.\r
+    //\r
+    if (!Attempt->ValidiBFTPath) {\r
+      continue;\r
+    }\r
+\r
+    NvData     = &Attempt->SessionConfigData;\r
+    AuthConfig = &Attempt->AuthConfigData.CHAP;\r
+\r
+    //\r
+    // Fill the Nic section.\r
+    //\r
+\r
+    Nic->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID;\r
+    Nic->Header.Version     = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION;\r
+    Nic->Header.Length      = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE);\r
+    Nic->Header.Index       = (UINT8) Index;\r
+    Nic->Header.Flags       = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID |\r
+                            EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL;\r
+\r
+    if (Index == 0) {\r
+      Nic->Header.Flags    |= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED;\r
+    }\r
+\r
+    if (NvData->InitiatorInfoFromDhcp) {\r
+      Nic->Origin = IpPrefixOriginDhcp;\r
+    } else {\r
+      Nic->Origin = IpPrefixOriginManual;\r
+    }\r
+\r
+    if (NvData->IpMode == IP_MODE_IP4 || NvData->IpMode == IP_MODE_AUTOCONFIG) {\r
+      //\r
+      // Get the subnet mask prefix length.\r
+      //\r
+      Nic->SubnetMaskPrefixLength = IScsiGetSubnetMaskPrefixLength (&NvData->SubnetMask);\r
+\r
+      //\r
+      // Map the various v4 addresses into v6 addresses.\r
+      //\r
+      IScsiMapV4ToV6Addr (&NvData->LocalIp, &Nic->Ip);\r
+      IScsiMapV4ToV6Addr (&NvData->Gateway, &Nic->Gateway);\r
+      IScsiMapV4ToV6Addr (&Attempt->PrimaryDns.v4, &Nic->PrimaryDns);\r
+      IScsiMapV4ToV6Addr (&Attempt->SecondaryDns.v4, &Nic->SecondaryDns);\r
+      IScsiMapV4ToV6Addr (&Attempt->DhcpServer.v4, &Nic->DhcpServer);\r
+\r
+    } else if (NvData->IpMode == IP_MODE_IP6 || NvData->IpMode == IP_MODE_AUTOCONFIG) {\r
+      //\r
+      // TODO: The subnet mask/local ip/gateway/dhcpserver for iBFT-IPv6 needs to be \r
+      // confirmed with spec owner.\r
+      //\r
+\r
+      CopyMem (&Nic->PrimaryDns, &Attempt->PrimaryDns, sizeof (EFI_IPv6_ADDRESS));\r
+      CopyMem (&Nic->SecondaryDns, &Attempt->SecondaryDns, sizeof (EFI_IPv6_ADDRESS));\r
+      //\r
+      // TODO: DHCP server address cannot be retrieved by DHCPv6 process since \r
+      // DHCP server option is removed.\r
+      //CopyMem (&Nic->DhcpServer, &Attempt->DhcpServer, sizeof (EFI_IPv6_ADDRESS));\r
+      //\r
+    } else {\r
+      ASSERT (FALSE);\r
+    }\r
+\r
+    //\r
+    // Get Nic Info: VLAN tag, Mac address, PCI location.\r
+    //\r
+    NicInfo = IScsiGetNicInfoByIndex (Attempt->NicIndex);\r
+    ASSERT (NicInfo != NULL);\r
+\r
+    Nic->VLanTag = NicInfo->VlanId;\r
+    CopyMem (Nic->Mac, &NicInfo->PermanentAddress, sizeof (Nic->Mac));\r
+    Nic->PciLocation = (UINT16) ((NicInfo->BusNumber << 8)    |\r
+                                 (NicInfo->DeviceNumber << 3) | NicInfo->FunctionNumber);\r
+    *SectionOffset    = (UINT16) ((UINTN) Nic - (UINTN) Table);\r
+    SectionOffset++;\r
+\r
+    //\r
+    // Fill the Target section.\r
+    //\r
+\r
+    Target->Header.StructureId  = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID;\r
+    Target->Header.Version      = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION;\r
+    Target->Header.Length       = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE);\r
+    Target->Header.Index        = (UINT8) Index;\r
+    Target->Header.Flags        = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID;\r
+\r
+    if (Index == 0) {\r
+      Target->Header.Flags     |= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED;\r
+    }\r
+\r
+    Target->Port                = NvData->TargetPort;\r
+\r
+    if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {\r
+      Target->CHAPType          = AuthConfig->CHAPType;\r
+    } else if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_NONE) {\r
+      Target->CHAPType          = ISCSI_AUTH_TYPE_NONE;\r
+    }\r
+\r
+    Target->NicIndex            = (UINT8) Index;\r
+\r
+    if (NvData->IpMode == IP_MODE_IP4 || NvData->IpMode == IP_MODE_AUTOCONFIG) {\r
+      IScsiMapV4ToV6Addr (&NvData->TargetIp.v4, &Target->Ip);\r
+    } else if (NvData->IpMode == IP_MODE_IP6 || NvData->IpMode == IP_MODE_AUTOCONFIG) {\r
+      CopyMem (&Target->Ip, &NvData->TargetIp, sizeof (EFI_IPv6_ADDRESS));\r
+    } else {\r
+      ASSERT (FALSE);\r
+    }\r
+\r
+    CopyMem (Target->BootLun, NvData->BootLun, sizeof (Target->BootLun));\r
+\r
+    //\r
+    // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.\r
+    //\r
+    Length = (UINT16) AsciiStrLen (NvData->TargetName);\r
+    IScsiAddHeapItem (Heap, NvData->TargetName, Length);\r
+\r
+    Target->IScsiNameLength = Length;\r
+    Target->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+    if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {\r
+      //\r
+      // CHAP Name\r
+      //\r
+      Length = (UINT16) AsciiStrLen (AuthConfig->CHAPName);\r
+      IScsiAddHeapItem (Heap, AuthConfig->CHAPName, Length);\r
+      Target->CHAPNameLength  = Length;\r
+      Target->CHAPNameOffset  = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+      //\r
+      // CHAP Secret\r
+      //\r
+      Length = (UINT16) AsciiStrLen (AuthConfig->CHAPSecret);\r
+      IScsiAddHeapItem (Heap, AuthConfig->CHAPSecret, Length);\r
+      Target->CHAPSecretLength  = Length;\r
+      Target->CHAPSecretOffset  = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+      if (Target->CHAPType == ISCSI_CHAP_MUTUAL) {\r
+        //\r
+        // Reverse CHAP Name.\r
+        //\r
+        Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPName);\r
+        IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPName, Length);\r
+        Target->ReverseCHAPNameLength = Length;\r
+        Target->ReverseCHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+        //\r
+        // Reverse CHAP Secret.\r
+        //\r
+        Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPSecret);\r
+        IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPSecret, Length);\r
+        Target->ReverseCHAPSecretLength = Length;\r
+        Target->ReverseCHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+      }\r
+    }\r
+\r
+    *SectionOffset = (UINT16) ((UINTN) Target - (UINTN) Table);\r
+    SectionOffset++;\r
+\r
+    //\r
+    // Advance to the next NIC/Target pair.\r
+    //\r
+    Nic    = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Target +\r
+           IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE)));\r
+    Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +\r
+           IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));\r
+\r
+    Index++;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Publish and remove the iSCSI Boot Firmware Table according to the iSCSI\r
+  session status.\r
+\r
+**/\r
+VOID\r
+IScsiPublishIbft (\r
+  IN VOID\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_ACPI_TABLE_PROTOCOL                       *AcpiTableProtocol;\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER     *Table;\r
+  EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;\r
+  EFI_ACPI_DESCRIPTION_HEADER                   *Rsdt;\r
+  UINT8                                         *Heap;\r
+  UINT8                                         Checksum;\r
+  UINTN                                         Index;\r
+\r
+\r
+  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Find ACPI table RSD_PTR from the system table.\r
+  //\r
+  for (Index = 0, Rsdp = NULL; Index < gST->NumberOfTableEntries; Index++) {\r
+    if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid) ||\r
+      CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid) ||\r
+      CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpiTableGuid)\r
+      ) {\r
+      //\r
+      // A match was found.\r
+      //\r
+      Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) gST->ConfigurationTable[Index].VendorTable;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Rsdp == NULL) {\r
+    return ;\r
+  } else {\r
+    Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;\r
+  }\r
+\r
+  if (mIbftInstalled) {\r
+    Status = AcpiTableProtocol->UninstallAcpiTable (\r
+                                  AcpiTableProtocol,\r
+                                  mTableKey\r
+                                  );\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+    mIbftInstalled = FALSE;\r
+  }\r
+\r
+  //\r
+  // If there is no valid attempt configuration, just return.\r
+  //\r
+  if ((!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount == 0) ||\r
+      (mPrivate->EnableMpio && mPrivate->MpioCount <= mPrivate->Krb5MpioCount)) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Allocate 4k bytes to hold the ACPI table.\r
+  //\r
+  Table = AllocateZeroPool (IBFT_MAX_SIZE);\r
+  if (Table == NULL) {\r
+    return ;\r
+  }\r
+\r
+  Heap = (UINT8 *) Table + IBFT_HEAP_OFFSET;\r
+\r
+  //\r
+  // Fill in the various section of the iSCSI Boot Firmware Table.\r
+  //\r
+  IScsiInitIbfTableHeader (Table, Rsdt->OemId, &Rsdt->OemTableId);\r
+  IScsiInitControlSection (Table);\r
+  IScsiFillInitiatorSection (Table, &Heap);\r
+  IScsiFillNICAndTargetSections (Table, &Heap);\r
+\r
+  Checksum = CalculateCheckSum8((UINT8 *)Table, Table->Length);\r
+  Table->Checksum = Checksum;\r
+\r
+  //\r
+  // Install or update the iBFT table.\r
+  //\r
+  Status = AcpiTableProtocol->InstallAcpiTable (\r
+                                AcpiTableProtocol,\r
+                                Table,\r
+                                Table->Length,\r
+                                &mTableKey\r
+                                );\r
+  if (EFI_ERROR(Status)) {\r
+    return;\r
+  }\r
+\r
+  mIbftInstalled = TRUE;\r
+  FreePool (Table);\r
+}\r