• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
IScsiInitIbfTableHeader(OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER * Header,IN UINT8 * OemId,IN UINT64 * OemTableId)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
IScsiInitControlSection(IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER * Table)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
IScsiAddHeapItem(IN OUT UINT8 ** Heap,IN VOID * Data,IN UINTN Len)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
IScsiFillInitiatorSection(IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER * Table,IN OUT UINT8 ** Heap)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
IScsiMapV4ToV6Addr(IN EFI_IPv4_ADDRESS * V4,OUT EFI_IPv6_ADDRESS * V6)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
IScsiFillNICAndTargetSections(IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER * Table,IN OUT UINT8 ** Heap)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
IScsiPublishIbft(IN 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   EFI_ACPI_DESCRIPTION_HEADER                   *Xsdt;
460   UINT8                                         *Heap;
461   UINT8                                         Checksum;
462 
463   Rsdt = NULL;
464   Xsdt = NULL;
465 
466   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
467   if (EFI_ERROR (Status)) {
468     return ;
469   }
470 
471   //
472   // Find ACPI table RSD_PTR from the system table.
473   //
474   Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **) &Rsdp);
475   if (EFI_ERROR (Status)) {
476     Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **) &Rsdp);
477   }
478 
479   if (EFI_ERROR (Status) || (Rsdp == NULL)) {
480     return ;
481   } else if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION && Rsdp->XsdtAddress != 0) {
482     Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;
483   } else if (Rsdp->RsdtAddress != 0) {
484     Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;
485   }
486 
487   if ((Xsdt == NULL) && (Rsdt == NULL)) {
488     return ;
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   if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
524     IScsiInitIbfTableHeader (Table, Xsdt->OemId, &Xsdt->OemTableId);
525   } else {
526     IScsiInitIbfTableHeader (Table, Rsdt->OemId, &Rsdt->OemTableId);
527   }
528 
529   IScsiInitControlSection (Table);
530   IScsiFillInitiatorSection (Table, &Heap);
531   IScsiFillNICAndTargetSections (Table, &Heap);
532 
533   Checksum = CalculateCheckSum8((UINT8 *)Table, Table->Length);
534   Table->Checksum = Checksum;
535 
536   //
537   // Install or update the iBFT table.
538   //
539   Status = AcpiTableProtocol->InstallAcpiTable (
540                                 AcpiTableProtocol,
541                                 Table,
542                                 Table->Length,
543                                 &mTableKey
544                                 );
545   if (EFI_ERROR(Status)) {
546     return;
547   }
548 
549   mIbftInstalled = TRUE;
550   FreePool (Table);
551 }
552