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