]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IScsiDxe/IScsiIbft.c
1. Add EFI_COMPONENT_NAME2_PROTOCOL.GetControllerName() support.
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiIbft.c
1 /** @file
2 Implementation for iSCSI Boot Firmware Table publication.
3
4 Copyright (c) 2004 - 2012, 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
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
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
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
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
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
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 Target->CHAPType = AuthConfig->CHAPType;
363 } else if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_NONE) {
364 Target->CHAPType = ISCSI_AUTH_TYPE_NONE;
365 }
366
367 Target->NicIndex = (UINT8) Index;
368
369 if (NvData->IpMode == IP_MODE_IP4 || NvData->IpMode == IP_MODE_AUTOCONFIG) {
370 IScsiMapV4ToV6Addr (&NvData->TargetIp.v4, &Target->Ip);
371 } else if (NvData->IpMode == IP_MODE_IP6 || NvData->IpMode == IP_MODE_AUTOCONFIG) {
372 CopyMem (&Target->Ip, &NvData->TargetIp, sizeof (EFI_IPv6_ADDRESS));
373 } else {
374 ASSERT (FALSE);
375 }
376
377 CopyMem (Target->BootLun, NvData->BootLun, sizeof (Target->BootLun));
378
379 //
380 // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.
381 //
382 Length = (UINT16) AsciiStrLen (NvData->TargetName);
383 IScsiAddHeapItem (Heap, NvData->TargetName, Length);
384
385 Target->IScsiNameLength = Length;
386 Target->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
387
388 if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) {
389 //
390 // CHAP Name
391 //
392 Length = (UINT16) AsciiStrLen (AuthConfig->CHAPName);
393 IScsiAddHeapItem (Heap, AuthConfig->CHAPName, Length);
394 Target->CHAPNameLength = Length;
395 Target->CHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
396
397 //
398 // CHAP Secret
399 //
400 Length = (UINT16) AsciiStrLen (AuthConfig->CHAPSecret);
401 IScsiAddHeapItem (Heap, AuthConfig->CHAPSecret, Length);
402 Target->CHAPSecretLength = Length;
403 Target->CHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
404
405 if (Target->CHAPType == ISCSI_CHAP_MUTUAL) {
406 //
407 // Reverse CHAP Name.
408 //
409 Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPName);
410 IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPName, Length);
411 Target->ReverseCHAPNameLength = Length;
412 Target->ReverseCHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
413
414 //
415 // Reverse CHAP Secret.
416 //
417 Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPSecret);
418 IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPSecret, Length);
419 Target->ReverseCHAPSecretLength = Length;
420 Target->ReverseCHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
421 }
422 }
423
424 *SectionOffset = (UINT16) ((UINTN) Target - (UINTN) Table);
425 SectionOffset++;
426
427 //
428 // Advance to the next NIC/Target pair.
429 //
430 Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Target +
431 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE)));
432 Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +
433 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));
434
435 Index++;
436 }
437 }
438
439
440 /**
441 Publish and remove the iSCSI Boot Firmware Table according to the iSCSI
442 session status.
443
444 **/
445 VOID
446 IScsiPublishIbft (
447 IN VOID
448 )
449 {
450 EFI_STATUS Status;
451 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
452 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table;
453 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
454 EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
455 UINT8 *Heap;
456 UINT8 Checksum;
457 UINTN Index;
458
459
460 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
461 if (EFI_ERROR (Status)) {
462 return ;
463 }
464
465 //
466 // Find ACPI table RSD_PTR from the system table.
467 //
468 for (Index = 0, Rsdp = NULL; Index < gST->NumberOfTableEntries; Index++) {
469 if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid) ||
470 CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid) ||
471 CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpiTableGuid)
472 ) {
473 //
474 // A match was found.
475 //
476 Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) gST->ConfigurationTable[Index].VendorTable;
477 break;
478 }
479 }
480
481 if (Rsdp == NULL) {
482 return ;
483 } else {
484 Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;
485 }
486
487 if (mIbftInstalled) {
488 Status = AcpiTableProtocol->UninstallAcpiTable (
489 AcpiTableProtocol,
490 mTableKey
491 );
492 if (EFI_ERROR (Status)) {
493 return ;
494 }
495 mIbftInstalled = FALSE;
496 }
497
498 //
499 // If there is no valid attempt configuration, just return.
500 //
501 if ((!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount == 0) ||
502 (mPrivate->EnableMpio && mPrivate->MpioCount <= mPrivate->Krb5MpioCount)) {
503 return ;
504 }
505
506 //
507 // Allocate 4k bytes to hold the ACPI table.
508 //
509 Table = AllocateZeroPool (IBFT_MAX_SIZE);
510 if (Table == NULL) {
511 return ;
512 }
513
514 Heap = (UINT8 *) Table + IBFT_HEAP_OFFSET;
515
516 //
517 // Fill in the various section of the iSCSI Boot Firmware Table.
518 //
519 IScsiInitIbfTableHeader (Table, Rsdt->OemId, &Rsdt->OemTableId);
520 IScsiInitControlSection (Table);
521 IScsiFillInitiatorSection (Table, &Heap);
522 IScsiFillNICAndTargetSections (Table, &Heap);
523
524 Checksum = CalculateCheckSum8((UINT8 *)Table, Table->Length);
525 Table->Checksum = Checksum;
526
527 //
528 // Install or update the iBFT table.
529 //
530 Status = AcpiTableProtocol->InstallAcpiTable (
531 AcpiTableProtocol,
532 Table,
533 Table->Length,
534 &mTableKey
535 );
536 if (EFI_ERROR(Status)) {
537 return;
538 }
539
540 mIbftInstalled = TRUE;
541 FreePool (Table);
542 }