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