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