2 Implementation for iSCSI Boot Firmware Table publication.
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 BOOLEAN mIbftInstalled
= FALSE
;
15 Initialize the header of the iSCSI Boot Firmware Table.
17 @param[out] Header The header of the iSCSI Boot Firmware Table.
18 @param[in] OemId The OEM ID.
19 @param[in] OemTableId The OEM table ID for the iBFT.
23 IScsiInitIbfTableHeader (
24 OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Header
,
29 Header
->Signature
= EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE
;
30 Header
->Length
= IBFT_HEAP_OFFSET
;
31 Header
->Revision
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION
;
34 CopyMem (Header
->OemId
, OemId
, sizeof (Header
->OemId
));
35 CopyMem (&Header
->OemTableId
, OemTableId
, sizeof (UINT64
));
40 Initialize the control section of the iSCSI Boot Firmware Table.
42 @param[in] Table The ACPI table.
46 IScsiInitControlSection (
47 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
50 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
53 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
55 Control
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID
;
56 Control
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION
;
57 Control
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
);
60 // If in multipathing mode, enable the Boot Failover Flag.
61 // If in single path mode, disable it. Mix-model is not allowed.
63 // BUGBUG: if Boot Failover Flag is set to 1, the OS installer cannot
64 // find the iSCSI mapped disk. So still keep not set for single path mode.
66 if (mPrivate
->EnableMpio
) {
67 Control
->Header
.Flags
= 0;
68 NumOffset
= 2 * (mPrivate
->MpioCount
- mPrivate
->Krb5MpioCount
);
70 NumOffset
= 2 * mPrivate
->ValidSinglePathCount
;
74 // Each attempt occupies two offsets: one for the NIC section;
75 // the other for the Target section.
79 // Need expand the control section if more than 2 NIC/Target attempts
82 Control
->Header
.Length
= (UINT16
) (Control
->Header
.Length
+ (NumOffset
- 4) * sizeof (UINT16
));
88 Add one item into the heap.
90 @param[in, out] Heap On input, the current address of the heap. On output, the address of
91 the heap after the item is added.
92 @param[in] Data The data to add into the heap.
93 @param[in] Len Length of the Data in byte.
104 // Add one byte for the NULL delimiter.
108 CopyMem (*Heap
, Data
, Len
);
114 Fill the Initiator section of the iSCSI Boot Firmware Table.
116 @param[in] Table The ACPI table.
117 @param[in, out] Heap The heap.
121 IScsiFillInitiatorSection (
122 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
126 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
127 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*Initiator
;
129 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
132 // Initiator section immediately follows the control section.
134 Initiator
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*)
135 ((UINT8
*) Control
+ IBFT_ROUNDUP (Control
->Header
.Length
));
137 Control
->InitiatorOffset
= (UINT16
) ((UINTN
) Initiator
- (UINTN
) Table
);
139 Initiator
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID
;
140 Initiator
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION
;
141 Initiator
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
);
142 Initiator
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BLOCK_VALID
|
143 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BOOT_SELECTED
;
146 // Fill the iSCSI Initiator Name into the heap.
148 IScsiAddHeapItem (Heap
, mPrivate
->InitiatorName
, mPrivate
->InitiatorNameLength
- 1);
150 Initiator
->IScsiNameLength
= (UINT16
) (mPrivate
->InitiatorNameLength
- 1);
151 Initiator
->IScsiNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
156 Map the v4 IP address into v6 IP address.
158 @param[in] V4 The v4 IP address.
159 @param[out] V6 The v6 IP address.
164 IN EFI_IPv4_ADDRESS
*V4
,
165 OUT EFI_IPv6_ADDRESS
*V6
170 ZeroMem (V6
, sizeof (EFI_IPv6_ADDRESS
));
175 for (Index
= 0; Index
< 4; Index
++) {
176 V6
->Addr
[12 + Index
] = V4
->Addr
[Index
];
182 Fill the NIC and target sections in iSCSI Boot Firmware Table.
184 @param[in] Table The buffer of the ACPI table.
185 @param[in, out] Heap The heap buffer used to store the variable length
186 parameters such as iSCSI name.
190 IScsiFillNICAndTargetSections (
191 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
195 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
196 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*Nic
;
197 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*Target
;
198 ISCSI_SESSION_CONFIG_NVDATA
*NvData
;
199 ISCSI_CHAP_AUTH_CONFIG_NVDATA
*AuthConfig
;
200 UINT16
*SectionOffset
;
204 ISCSI_ATTEMPT_CONFIG_NVDATA
*Attempt
;
205 ISCSI_NIC_INFO
*NicInfo
;
209 // Get the offset of the first Nic and Target section.
211 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
212 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*) ((UINTN
) Table
+
213 Control
->InitiatorOffset
+ IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
)));
214 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*) ((UINTN
) Nic
+
215 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
217 SectionOffset
= &Control
->NIC0Offset
;
222 NET_LIST_FOR_EACH (Entry
, &mPrivate
->AttemptConfigs
) {
225 // First entry should be boot selected entry.
227 Attempt
= IScsiConfigGetAttemptByConfigIndex (mPrivate
->BootSelectedIndex
);
228 if (Attempt
== NULL
) {
230 // First boot selected entry can not be found.
235 ASSERT (Attempt
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
);
238 if (Index
== 1 && Flag
) {
239 Entry
= mPrivate
->AttemptConfigs
.ForwardLink
;
243 Attempt
= NET_LIST_USER_STRUCT (Entry
, ISCSI_ATTEMPT_CONFIG_NVDATA
, Link
);
244 if (Attempt
->AttemptConfigIndex
== mPrivate
->BootSelectedIndex
) {
249 if (Attempt
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
254 // Krb5 attempt will not be recorded in iBFT.
256 if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
) {
261 // If multipath mode is enabled, only the attempts in MPIO will be recorded in iBFT.
263 if (mPrivate
->EnableMpio
&& Attempt
->SessionConfigData
.Enabled
!= ISCSI_ENABLED_FOR_MPIO
) {
268 // Only the valid attempts will be recorded.
270 if (!Attempt
->ValidiBFTPath
) {
274 NvData
= &Attempt
->SessionConfigData
;
275 AuthConfig
= &Attempt
->AuthConfigData
.CHAP
;
278 // Fill the Nic section.
281 Nic
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID
;
282 Nic
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION
;
283 Nic
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
);
284 Nic
->Header
.Index
= (UINT8
) Index
;
285 Nic
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID
|
286 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL
;
289 Nic
->Header
.Flags
|= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED
;
292 if (NvData
->InitiatorInfoFromDhcp
) {
293 Nic
->Origin
= IpPrefixOriginDhcp
;
295 Nic
->Origin
= IpPrefixOriginManual
;
298 if (NvData
->IpMode
== IP_MODE_IP4
|| NvData
->IpMode
== IP_MODE_AUTOCONFIG
) {
300 // Get the subnet mask prefix length.
302 Nic
->SubnetMaskPrefixLength
= IScsiGetSubnetMaskPrefixLength (&NvData
->SubnetMask
);
305 // Map the various v4 addresses into v6 addresses.
307 IScsiMapV4ToV6Addr (&NvData
->LocalIp
.v4
, &Nic
->Ip
);
308 IScsiMapV4ToV6Addr (&NvData
->Gateway
.v4
, &Nic
->Gateway
);
309 IScsiMapV4ToV6Addr (&Attempt
->PrimaryDns
.v4
, &Nic
->PrimaryDns
);
310 IScsiMapV4ToV6Addr (&Attempt
->SecondaryDns
.v4
, &Nic
->SecondaryDns
);
311 IScsiMapV4ToV6Addr (&Attempt
->DhcpServer
.v4
, &Nic
->DhcpServer
);
313 } else if (NvData
->IpMode
== IP_MODE_IP6
|| NvData
->IpMode
== IP_MODE_AUTOCONFIG
) {
315 Nic
->SubnetMaskPrefixLength
= NvData
->PrefixLength
;
316 CopyMem (&Nic
->Ip
, &NvData
->LocalIp
, sizeof (EFI_IPv6_ADDRESS
));
317 CopyMem (&Nic
->Gateway
, &NvData
->Gateway
, sizeof (EFI_IPv6_ADDRESS
));
318 CopyMem (&Nic
->PrimaryDns
, &Attempt
->PrimaryDns
, sizeof (EFI_IPv6_ADDRESS
));
319 CopyMem (&Nic
->SecondaryDns
, &Attempt
->SecondaryDns
, sizeof (EFI_IPv6_ADDRESS
));
320 CopyMem (&Nic
->DhcpServer
, &Attempt
->DhcpServer
, sizeof (EFI_IPv6_ADDRESS
));
327 // Get Nic Info: VLAN tag, Mac address, PCI location.
329 NicInfo
= IScsiGetNicInfoByIndex (Attempt
->NicIndex
);
330 ASSERT (NicInfo
!= NULL
);
332 Nic
->VLanTag
= NicInfo
->VlanId
;
333 CopyMem (Nic
->Mac
, &NicInfo
->PermanentAddress
, sizeof (Nic
->Mac
));
334 Nic
->PciLocation
= (UINT16
) ((NicInfo
->BusNumber
<< 8) |
335 (NicInfo
->DeviceNumber
<< 3) | NicInfo
->FunctionNumber
);
336 *SectionOffset
= (UINT16
) ((UINTN
) Nic
- (UINTN
) Table
);
340 // Fill the Target section.
343 Target
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID
;
344 Target
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION
;
345 Target
->Header
.Length
= (UINT16
) sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
);
346 Target
->Header
.Index
= (UINT8
) Index
;
347 Target
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID
;
350 Target
->Header
.Flags
|= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED
;
353 Target
->Port
= NvData
->TargetPort
;
355 if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_CHAP
) {
356 if (AuthConfig
->CHAPType
== ISCSI_CHAP_UNI
) {
357 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_CHAP
;
358 } else if (AuthConfig
->CHAPType
== ISCSI_CHAP_MUTUAL
) {
359 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP
;
361 } else if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_NONE
) {
362 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_NO_CHAP
;
365 Target
->NicIndex
= (UINT8
) Index
;
367 if (NvData
->IpMode
== IP_MODE_IP4
|| NvData
->IpMode
== IP_MODE_AUTOCONFIG
) {
368 IScsiMapV4ToV6Addr (&NvData
->TargetIp
.v4
, &Target
->Ip
);
369 } else if (NvData
->IpMode
== IP_MODE_IP6
|| NvData
->IpMode
== IP_MODE_AUTOCONFIG
) {
370 CopyMem (&Target
->Ip
, &NvData
->TargetIp
, sizeof (EFI_IPv6_ADDRESS
));
375 CopyMem (Target
->BootLun
, NvData
->BootLun
, sizeof (Target
->BootLun
));
378 // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.
380 Length
= (UINT16
) AsciiStrLen (NvData
->TargetName
);
381 IScsiAddHeapItem (Heap
, NvData
->TargetName
, Length
);
383 Target
->IScsiNameLength
= Length
;
384 Target
->IScsiNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
386 if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_CHAP
) {
390 Length
= (UINT16
) AsciiStrLen (AuthConfig
->CHAPName
);
391 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPName
, Length
);
392 Target
->CHAPNameLength
= Length
;
393 Target
->CHAPNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
398 Length
= (UINT16
) AsciiStrLen (AuthConfig
->CHAPSecret
);
399 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPSecret
, Length
);
400 Target
->CHAPSecretLength
= Length
;
401 Target
->CHAPSecretOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
403 if (Target
->CHAPType
== EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP
) {
405 // Reverse CHAP Name.
407 Length
= (UINT16
) AsciiStrLen (AuthConfig
->ReverseCHAPName
);
408 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPName
, Length
);
409 Target
->ReverseCHAPNameLength
= Length
;
410 Target
->ReverseCHAPNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
413 // Reverse CHAP Secret.
415 Length
= (UINT16
) AsciiStrLen (AuthConfig
->ReverseCHAPSecret
);
416 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPSecret
, Length
);
417 Target
->ReverseCHAPSecretLength
= Length
;
418 Target
->ReverseCHAPSecretOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
422 *SectionOffset
= (UINT16
) ((UINTN
) Target
- (UINTN
) Table
);
426 // Advance to the next NIC/Target pair.
428 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*) ((UINTN
) Target
+
429 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
)));
430 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*) ((UINTN
) Nic
+
431 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
439 Publish and remove the iSCSI Boot Firmware Table according to the iSCSI
449 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
450 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
;
451 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*Rsdp
;
452 EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
;
453 EFI_ACPI_DESCRIPTION_HEADER
*Xsdt
;
460 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTableProtocol
);
461 if (EFI_ERROR (Status
)) {
466 // Find ACPI table RSD_PTR from the system table.
468 Status
= EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid
, (VOID
**) &Rsdp
);
469 if (EFI_ERROR (Status
)) {
470 Status
= EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid
, (VOID
**) &Rsdp
);
473 if (EFI_ERROR (Status
) || (Rsdp
== NULL
)) {
475 } else if (Rsdp
->Revision
>= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION
&& Rsdp
->XsdtAddress
!= 0) {
476 Xsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*) (UINTN
) Rsdp
->XsdtAddress
;
477 } else if (Rsdp
->RsdtAddress
!= 0) {
478 Rsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*) (UINTN
) Rsdp
->RsdtAddress
;
481 if ((Xsdt
== NULL
) && (Rsdt
== NULL
)) {
485 if (mIbftInstalled
) {
486 Status
= AcpiTableProtocol
->UninstallAcpiTable (
490 if (EFI_ERROR (Status
)) {
493 mIbftInstalled
= FALSE
;
497 // If there is no valid attempt configuration, just return.
499 if ((!mPrivate
->EnableMpio
&& mPrivate
->ValidSinglePathCount
== 0) ||
500 (mPrivate
->EnableMpio
&& mPrivate
->MpioCount
<= mPrivate
->Krb5MpioCount
)) {
505 // Allocate 4k bytes to hold the ACPI table.
507 Table
= AllocateZeroPool (IBFT_MAX_SIZE
);
512 Heap
= (UINT8
*) Table
+ IBFT_HEAP_OFFSET
;
515 // Fill in the various section of the iSCSI Boot Firmware Table.
517 if (Rsdp
->Revision
>= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION
) {
518 IScsiInitIbfTableHeader (Table
, Xsdt
->OemId
, &Xsdt
->OemTableId
);
520 IScsiInitIbfTableHeader (Table
, Rsdt
->OemId
, &Rsdt
->OemTableId
);
523 IScsiInitControlSection (Table
);
524 IScsiFillInitiatorSection (Table
, &Heap
);
525 IScsiFillNICAndTargetSections (Table
, &Heap
);
527 Checksum
= CalculateCheckSum8((UINT8
*)Table
, Table
->Length
);
528 Table
->Checksum
= Checksum
;
531 // Install or update the iBFT table.
533 Status
= AcpiTableProtocol
->InstallAcpiTable (
539 if (EFI_ERROR(Status
)) {
543 mIbftInstalled
= TRUE
;