From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../EFI/Firmware/NetworkPkg/IScsiDxe/IScsiIbft.c | 545 +++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiIbft.c (limited to 'src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiIbft.c') diff --git a/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiIbft.c b/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiIbft.c new file mode 100644 index 00000000..7f86851f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiIbft.c @@ -0,0 +1,545 @@ +/** @file + Implementation for iSCSI Boot Firmware Table publication. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "IScsiImpl.h" + +BOOLEAN mIbftInstalled = FALSE; +UINTN mTableKey; + +/** + Initialize the header of the iSCSI Boot Firmware Table. + + @param[out] Header The header of the iSCSI Boot Firmware Table. + @param[in] OemId The OEM ID. + @param[in] OemTableId The OEM table ID for the iBFT. + +**/ +VOID +IScsiInitIbfTableHeader ( + OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Header, + IN UINT8 *OemId, + IN UINT64 *OemTableId + ) +{ + Header->Signature = EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE; + Header->Length = IBFT_HEAP_OFFSET; + Header->Revision = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION; + Header->Checksum = 0; + + CopyMem (Header->OemId, OemId, sizeof (Header->OemId)); + CopyMem (&Header->OemTableId, OemTableId, sizeof (UINT64)); +} + + +/** + Initialize the control section of the iSCSI Boot Firmware Table. + + @param[in] Table The ACPI table. + +**/ +VOID +IScsiInitControlSection ( + IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table + ) +{ + EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control; + UINTN NumOffset; + + Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1); + + Control->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID; + Control->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION; + Control->Header.Length = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE); + + // + // If in multipathing mode, enable the Boot Failover Flag. + // If in single path mode, disable it. Mix-model is not allowed. + // + // BUGBUG: if Boot Failover Flag is set to 1, the OS installer cannot + // find the iSCSI mapped disk. So still keep not set for single path mode. + // + if (mPrivate->EnableMpio) { + Control->Header.Flags = 0; + NumOffset = 2 * (mPrivate->MpioCount - mPrivate->Krb5MpioCount); + } else { + NumOffset = 2 * mPrivate->ValidSinglePathCount; + } + + // + // Each attempt occupies two offsets: one for the NIC section; + // the other for the Target section. + // + if (NumOffset > 4) { + // + // Need expand the control section if more than 2 NIC/Target attempts + // exist. + // + Control->Header.Length = (UINT16) (Control->Header.Length + (NumOffset - 4) * sizeof (UINT16)); + } +} + + +/** + Add one item into the heap. + + @param[in, out] Heap On input, the current address of the heap. On output, the address of + the heap after the item is added. + @param[in] Data The data to add into the heap. + @param[in] Len Length of the Data in byte. + +**/ +VOID +IScsiAddHeapItem ( + IN OUT UINT8 **Heap, + IN VOID *Data, + IN UINTN Len + ) +{ + // + // Add one byte for the NULL delimiter. + // + *Heap -= Len + 1; + + CopyMem (*Heap, Data, Len); + *(*Heap + Len) = 0; +} + + +/** + Fill the Initiator section of the iSCSI Boot Firmware Table. + + @param[in] Table The ACPI table. + @param[in, out] Heap The heap. + +**/ +VOID +IScsiFillInitiatorSection ( + IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table, + IN OUT UINT8 **Heap + ) +{ + EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control; + EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *Initiator; + + Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1); + + // + // Initiator section immediately follows the control section. + // + Initiator = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *) + ((UINT8 *) Control + IBFT_ROUNDUP (Control->Header.Length)); + + Control->InitiatorOffset = (UINT16) ((UINTN) Initiator - (UINTN) Table); + + Initiator->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID; + Initiator->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION; + Initiator->Header.Length = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE); + 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; + + // + // Fill the iSCSI Initiator Name into the heap. + // + IScsiAddHeapItem (Heap, mPrivate->InitiatorName, mPrivate->InitiatorNameLength - 1); + + Initiator->IScsiNameLength = (UINT16) (mPrivate->InitiatorNameLength - 1); + Initiator->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table); +} + + +/** + Map the v4 IP address into v6 IP address. + + @param[in] V4 The v4 IP address. + @param[out] V6 The v6 IP address. + +**/ +VOID +IScsiMapV4ToV6Addr ( + IN EFI_IPv4_ADDRESS *V4, + OUT EFI_IPv6_ADDRESS *V6 + ) +{ + UINTN Index; + + ZeroMem (V6, sizeof (EFI_IPv6_ADDRESS)); + + V6->Addr[10] = 0xff; + V6->Addr[11] = 0xff; + + for (Index = 0; Index < 4; Index++) { + V6->Addr[12 + Index] = V4->Addr[Index]; + } +} + + +/** + Fill the NIC and target sections in iSCSI Boot Firmware Table. + + @param[in] Table The buffer of the ACPI table. + @param[in, out] Heap The heap buffer used to store the variable length + parameters such as iSCSI name. + +**/ +VOID +IScsiFillNICAndTargetSections ( + IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table, + IN OUT UINT8 **Heap + ) +{ + EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control; + EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *Nic; + EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *Target; + ISCSI_SESSION_CONFIG_NVDATA *NvData; + ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig; + UINT16 *SectionOffset; + UINTN Index; + UINT16 Length; + LIST_ENTRY *Entry; + ISCSI_ATTEMPT_CONFIG_NVDATA *Attempt; + ISCSI_NIC_INFO *NicInfo; + BOOLEAN Flag; + + // + // Get the offset of the first Nic and Target section. + // + Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1); + Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Table + + Control->InitiatorOffset + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE))); + Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic + + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE))); + + SectionOffset = &Control->NIC0Offset; + + Index = 0; + Flag = TRUE; + + NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) { + if (Index == 0) { + // + // First entry should be boot selected entry. + // + Attempt = IScsiConfigGetAttemptByConfigIndex (mPrivate->BootSelectedIndex); + if (Attempt == NULL) { + // + // First boot selected entry can not be found. + // + break; + } + + ASSERT (Attempt->SessionConfigData.Enabled != ISCSI_DISABLED); + + } else { + if (Index == 1 && Flag) { + Entry = mPrivate->AttemptConfigs.ForwardLink; + Flag = FALSE; + } + + Attempt = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); + if (Attempt->AttemptConfigIndex == mPrivate->BootSelectedIndex) { + continue; + } + } + + if (Attempt->SessionConfigData.Enabled == ISCSI_DISABLED) { + continue; + } + + // + // Krb5 attempt will not be recorded in iBFT. + // + if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_KRB) { + continue; + } + + // + // If multipath mode is enabled, only the attempts in MPIO will be recorded in iBFT. + // + if (mPrivate->EnableMpio && Attempt->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO) { + continue; + } + + // + // Only the valid attempts will be recorded. + // + if (!Attempt->ValidiBFTPath) { + continue; + } + + NvData = &Attempt->SessionConfigData; + AuthConfig = &Attempt->AuthConfigData.CHAP; + + // + // Fill the Nic section. + // + + Nic->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID; + Nic->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION; + Nic->Header.Length = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE); + Nic->Header.Index = (UINT8) Index; + Nic->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID | + EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL; + + if (Index == 0) { + Nic->Header.Flags |= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED; + } + + if (NvData->InitiatorInfoFromDhcp) { + Nic->Origin = IpPrefixOriginDhcp; + } else { + Nic->Origin = IpPrefixOriginManual; + } + + if (NvData->IpMode == IP_MODE_IP4 || NvData->IpMode == IP_MODE_AUTOCONFIG) { + // + // Get the subnet mask prefix length. + // + Nic->SubnetMaskPrefixLength = IScsiGetSubnetMaskPrefixLength (&NvData->SubnetMask); + + // + // Map the various v4 addresses into v6 addresses. + // + IScsiMapV4ToV6Addr (&NvData->LocalIp.v4, &Nic->Ip); + IScsiMapV4ToV6Addr (&NvData->Gateway.v4, &Nic->Gateway); + IScsiMapV4ToV6Addr (&Attempt->PrimaryDns.v4, &Nic->PrimaryDns); + IScsiMapV4ToV6Addr (&Attempt->SecondaryDns.v4, &Nic->SecondaryDns); + IScsiMapV4ToV6Addr (&Attempt->DhcpServer.v4, &Nic->DhcpServer); + + } else if (NvData->IpMode == IP_MODE_IP6 || NvData->IpMode == IP_MODE_AUTOCONFIG) { + + Nic->SubnetMaskPrefixLength = NvData->PrefixLength; + CopyMem (&Nic->Ip, &NvData->LocalIp, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (&Nic->Gateway, &NvData->Gateway, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (&Nic->PrimaryDns, &Attempt->PrimaryDns, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (&Nic->SecondaryDns, &Attempt->SecondaryDns, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (&Nic->DhcpServer, &Attempt->DhcpServer, sizeof (EFI_IPv6_ADDRESS)); + + } else { + ASSERT (FALSE); + } + + // + // Get Nic Info: VLAN tag, Mac address, PCI location. + // + NicInfo = IScsiGetNicInfoByIndex (Attempt->NicIndex); + ASSERT (NicInfo != NULL); + + Nic->VLanTag = NicInfo->VlanId; + CopyMem (Nic->Mac, &NicInfo->PermanentAddress, sizeof (Nic->Mac)); + Nic->PciLocation = (UINT16) ((NicInfo->BusNumber << 8) | + (NicInfo->DeviceNumber << 3) | NicInfo->FunctionNumber); + *SectionOffset = (UINT16) ((UINTN) Nic - (UINTN) Table); + SectionOffset++; + + // + // Fill the Target section. + // + + Target->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID; + Target->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION; + Target->Header.Length = (UINT16) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE); + Target->Header.Index = (UINT8) Index; + Target->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID; + + if (Index == 0) { + Target->Header.Flags |= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED; + } + + Target->Port = NvData->TargetPort; + + if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + if (AuthConfig->CHAPType == ISCSI_CHAP_UNI) { + Target->CHAPType = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_CHAP; + } else if (AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) { + Target->CHAPType = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP; + } + } else if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_NONE) { + Target->CHAPType = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_NO_CHAP; + } + + Target->NicIndex = (UINT8) Index; + + if (NvData->IpMode == IP_MODE_IP4 || NvData->IpMode == IP_MODE_AUTOCONFIG) { + IScsiMapV4ToV6Addr (&NvData->TargetIp.v4, &Target->Ip); + } else if (NvData->IpMode == IP_MODE_IP6 || NvData->IpMode == IP_MODE_AUTOCONFIG) { + CopyMem (&Target->Ip, &NvData->TargetIp, sizeof (EFI_IPv6_ADDRESS)); + } else { + ASSERT (FALSE); + } + + CopyMem (Target->BootLun, NvData->BootLun, sizeof (Target->BootLun)); + + // + // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret. + // + Length = (UINT16) AsciiStrLen (NvData->TargetName); + IScsiAddHeapItem (Heap, NvData->TargetName, Length); + + Target->IScsiNameLength = Length; + Target->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table); + + if (Attempt->AuthenticationType == ISCSI_AUTH_TYPE_CHAP) { + // + // CHAP Name + // + Length = (UINT16) AsciiStrLen (AuthConfig->CHAPName); + IScsiAddHeapItem (Heap, AuthConfig->CHAPName, Length); + Target->CHAPNameLength = Length; + Target->CHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table); + + // + // CHAP Secret + // + Length = (UINT16) AsciiStrLen (AuthConfig->CHAPSecret); + IScsiAddHeapItem (Heap, AuthConfig->CHAPSecret, Length); + Target->CHAPSecretLength = Length; + Target->CHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table); + + if (Target->CHAPType == EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP) { + // + // Reverse CHAP Name. + // + Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPName); + IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPName, Length); + Target->ReverseCHAPNameLength = Length; + Target->ReverseCHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table); + + // + // Reverse CHAP Secret. + // + Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPSecret); + IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPSecret, Length); + Target->ReverseCHAPSecretLength = Length; + Target->ReverseCHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table); + } + } + + *SectionOffset = (UINT16) ((UINTN) Target - (UINTN) Table); + SectionOffset++; + + // + // Advance to the next NIC/Target pair. + // + Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Target + + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE))); + Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic + + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE))); + + Index++; + } +} + + +/** + Publish and remove the iSCSI Boot Firmware Table according to the iSCSI + session status. + +**/ +VOID +IScsiPublishIbft ( + IN VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol; + EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table; + EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; + EFI_ACPI_DESCRIPTION_HEADER *Rsdt; + EFI_ACPI_DESCRIPTION_HEADER *Xsdt; + UINT8 *Heap; + UINT8 Checksum; + + Rsdt = NULL; + Xsdt = NULL; + + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Find ACPI table RSD_PTR from the system table. + // + Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **) &Rsdp); + if (EFI_ERROR (Status)) { + Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **) &Rsdp); + } + + if (EFI_ERROR (Status) || (Rsdp == NULL)) { + return ; + } else if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION && Rsdp->XsdtAddress != 0) { + Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress; + } else if (Rsdp->RsdtAddress != 0) { + Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress; + } + + if ((Xsdt == NULL) && (Rsdt == NULL)) { + return ; + } + + if (mIbftInstalled) { + Status = AcpiTableProtocol->UninstallAcpiTable ( + AcpiTableProtocol, + mTableKey + ); + if (EFI_ERROR (Status)) { + return ; + } + mIbftInstalled = FALSE; + } + + // + // If there is no valid attempt configuration, just return. + // + if ((!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount == 0) || + (mPrivate->EnableMpio && mPrivate->MpioCount <= mPrivate->Krb5MpioCount)) { + return ; + } + + // + // Allocate 4k bytes to hold the ACPI table. + // + Table = AllocateZeroPool (IBFT_MAX_SIZE); + if (Table == NULL) { + return ; + } + + Heap = (UINT8 *) Table + IBFT_HEAP_OFFSET; + + // + // Fill in the various section of the iSCSI Boot Firmware Table. + // + if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) { + IScsiInitIbfTableHeader (Table, Xsdt->OemId, &Xsdt->OemTableId); + } else { + IScsiInitIbfTableHeader (Table, Rsdt->OemId, &Rsdt->OemTableId); + } + + IScsiInitControlSection (Table); + IScsiFillInitiatorSection (Table, &Heap); + IScsiFillNICAndTargetSections (Table, &Heap); + + Checksum = CalculateCheckSum8((UINT8 *)Table, Table->Length); + Table->Checksum = Checksum; + + // + // Install or update the iBFT table. + // + Status = AcpiTableProtocol->InstallAcpiTable ( + AcpiTableProtocol, + Table, + Table->Length, + &mTableKey + ); + if (EFI_ERROR(Status)) { + return; + } + + mIbftInstalled = TRUE; + FreePool (Table); +} -- cgit v1.2.3