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