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