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