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
));
39 Initialize the control section of the iSCSI Boot Firmware Table.
41 @param[in] Table The ACPI table.
45 IScsiInitControlSection (
46 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
49 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
52 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*)(Table
+ 1);
54 Control
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID
;
55 Control
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION
;
56 Control
->Header
.Length
= (UINT16
)sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
);
59 // If in multipathing mode, enable the Boot Failover Flag.
60 // If in single path mode, disable it. Mix-model is not allowed.
62 // BUGBUG: if Boot Failover Flag is set to 1, the OS installer cannot
63 // find the iSCSI mapped disk. So still keep not set for single path mode.
65 if (mPrivate
->EnableMpio
) {
66 Control
->Header
.Flags
= 0;
67 NumOffset
= 2 * (mPrivate
->MpioCount
- mPrivate
->Krb5MpioCount
);
69 NumOffset
= 2 * mPrivate
->ValidSinglePathCount
;
73 // Each attempt occupies two offsets: one for the NIC section;
74 // the other for the Target section.
78 // Need expand the control section if more than 2 NIC/Target attempts
81 Control
->Header
.Length
= (UINT16
)(Control
->Header
.Length
+ (NumOffset
- 4) * sizeof (UINT16
));
86 Add one item into the heap.
88 @param[in, out] Heap On input, the current address of the heap. On output, the address of
89 the heap after the item is added.
90 @param[in] Data The data to add into the heap.
91 @param[in] Len Length of the Data in byte.
102 // Add one byte for the NULL delimiter.
106 CopyMem (*Heap
, Data
, Len
);
111 Fill the Initiator section of the iSCSI Boot Firmware Table.
113 @param[in] Table The ACPI table.
114 @param[in, out] Heap The heap.
118 IScsiFillInitiatorSection (
119 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
123 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
124 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*Initiator
;
126 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*)(Table
+ 1);
129 // Initiator section immediately follows the control section.
131 Initiator
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*)
132 ((UINT8
*)Control
+ IBFT_ROUNDUP (Control
->Header
.Length
));
134 Control
->InitiatorOffset
= (UINT16
)((UINTN
)Initiator
- (UINTN
)Table
);
136 Initiator
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID
;
137 Initiator
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION
;
138 Initiator
->Header
.Length
= (UINT16
)sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
);
139 Initiator
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BLOCK_VALID
|
140 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BOOT_SELECTED
;
143 // Fill the iSCSI Initiator Name into the heap.
145 IScsiAddHeapItem (Heap
, mPrivate
->InitiatorName
, mPrivate
->InitiatorNameLength
- 1);
147 Initiator
->IScsiNameLength
= (UINT16
)(mPrivate
->InitiatorNameLength
- 1);
148 Initiator
->IScsiNameOffset
= (UINT16
)((UINTN
)*Heap
- (UINTN
)Table
);
152 Map the v4 IP address into v6 IP address.
154 @param[in] V4 The v4 IP address.
155 @param[out] V6 The v6 IP address.
160 IN EFI_IPv4_ADDRESS
*V4
,
161 OUT EFI_IPv6_ADDRESS
*V6
166 ZeroMem (V6
, sizeof (EFI_IPv6_ADDRESS
));
171 for (Index
= 0; Index
< 4; Index
++) {
172 V6
->Addr
[12 + Index
] = V4
->Addr
[Index
];
177 Fill the NIC and target sections in iSCSI Boot Firmware Table.
179 @param[in] Table The buffer of the ACPI table.
180 @param[in, out] Heap The heap buffer used to store the variable length
181 parameters such as iSCSI name.
185 IScsiFillNICAndTargetSections (
186 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
190 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
191 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*Nic
;
192 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*Target
;
193 ISCSI_SESSION_CONFIG_NVDATA
*NvData
;
194 ISCSI_CHAP_AUTH_CONFIG_NVDATA
*AuthConfig
;
195 UINT16
*SectionOffset
;
199 ISCSI_ATTEMPT_CONFIG_NVDATA
*Attempt
;
200 ISCSI_NIC_INFO
*NicInfo
;
204 // Get the offset of the first Nic and Target section.
206 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*)(Table
+ 1);
207 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*)((UINTN
)Table
+
208 Control
->InitiatorOffset
+ IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
)));
209 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*)((UINTN
)Nic
+
210 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
212 SectionOffset
= &Control
->NIC0Offset
;
217 NET_LIST_FOR_EACH (Entry
, &mPrivate
->AttemptConfigs
) {
220 // First entry should be boot selected entry.
222 Attempt
= IScsiConfigGetAttemptByConfigIndex (mPrivate
->BootSelectedIndex
);
223 if (Attempt
== NULL
) {
225 // First boot selected entry can not be found.
230 ASSERT (Attempt
->SessionConfigData
.Enabled
!= ISCSI_DISABLED
);
232 if ((Index
== 1) && Flag
) {
233 Entry
= mPrivate
->AttemptConfigs
.ForwardLink
;
237 Attempt
= NET_LIST_USER_STRUCT (Entry
, ISCSI_ATTEMPT_CONFIG_NVDATA
, Link
);
238 if (Attempt
->AttemptConfigIndex
== mPrivate
->BootSelectedIndex
) {
243 if (Attempt
->SessionConfigData
.Enabled
== ISCSI_DISABLED
) {
248 // Krb5 attempt will not be recorded in iBFT.
250 if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_KRB
) {
255 // If multipath mode is enabled, only the attempts in MPIO will be recorded in iBFT.
257 if (mPrivate
->EnableMpio
&& (Attempt
->SessionConfigData
.Enabled
!= ISCSI_ENABLED_FOR_MPIO
)) {
262 // Only the valid attempts will be recorded.
264 if (!Attempt
->ValidiBFTPath
) {
268 NvData
= &Attempt
->SessionConfigData
;
269 AuthConfig
= &Attempt
->AuthConfigData
.CHAP
;
272 // Fill the Nic section.
275 Nic
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID
;
276 Nic
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION
;
277 Nic
->Header
.Length
= (UINT16
)sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
);
278 Nic
->Header
.Index
= (UINT8
)Index
;
279 Nic
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID
|
280 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL
;
283 Nic
->Header
.Flags
|= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED
;
286 if (NvData
->InitiatorInfoFromDhcp
) {
287 Nic
->Origin
= IpPrefixOriginDhcp
;
289 Nic
->Origin
= IpPrefixOriginManual
;
292 if ((NvData
->IpMode
== IP_MODE_IP4
) || (NvData
->IpMode
== IP_MODE_AUTOCONFIG
)) {
294 // Get the subnet mask prefix length.
296 Nic
->SubnetMaskPrefixLength
= IScsiGetSubnetMaskPrefixLength (&NvData
->SubnetMask
);
299 // Map the various v4 addresses into v6 addresses.
301 IScsiMapV4ToV6Addr (&NvData
->LocalIp
.v4
, &Nic
->Ip
);
302 IScsiMapV4ToV6Addr (&NvData
->Gateway
.v4
, &Nic
->Gateway
);
303 IScsiMapV4ToV6Addr (&Attempt
->PrimaryDns
.v4
, &Nic
->PrimaryDns
);
304 IScsiMapV4ToV6Addr (&Attempt
->SecondaryDns
.v4
, &Nic
->SecondaryDns
);
305 IScsiMapV4ToV6Addr (&Attempt
->DhcpServer
.v4
, &Nic
->DhcpServer
);
306 } else if ((NvData
->IpMode
== IP_MODE_IP6
) || (NvData
->IpMode
== IP_MODE_AUTOCONFIG
)) {
307 Nic
->SubnetMaskPrefixLength
= NvData
->PrefixLength
;
308 CopyMem (&Nic
->Ip
, &NvData
->LocalIp
, sizeof (EFI_IPv6_ADDRESS
));
309 CopyMem (&Nic
->Gateway
, &NvData
->Gateway
, sizeof (EFI_IPv6_ADDRESS
));
310 CopyMem (&Nic
->PrimaryDns
, &Attempt
->PrimaryDns
, sizeof (EFI_IPv6_ADDRESS
));
311 CopyMem (&Nic
->SecondaryDns
, &Attempt
->SecondaryDns
, sizeof (EFI_IPv6_ADDRESS
));
312 CopyMem (&Nic
->DhcpServer
, &Attempt
->DhcpServer
, sizeof (EFI_IPv6_ADDRESS
));
318 // Get Nic Info: VLAN tag, Mac address, PCI location.
320 NicInfo
= IScsiGetNicInfoByIndex (Attempt
->NicIndex
);
321 ASSERT (NicInfo
!= NULL
);
323 Nic
->VLanTag
= NicInfo
->VlanId
;
324 CopyMem (Nic
->Mac
, &NicInfo
->PermanentAddress
, sizeof (Nic
->Mac
));
325 Nic
->PciLocation
= (UINT16
)((NicInfo
->BusNumber
<< 8) |
326 (NicInfo
->DeviceNumber
<< 3) | NicInfo
->FunctionNumber
);
327 *SectionOffset
= (UINT16
)((UINTN
)Nic
- (UINTN
)Table
);
331 // Fill the Target section.
334 Target
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID
;
335 Target
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION
;
336 Target
->Header
.Length
= (UINT16
)sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
);
337 Target
->Header
.Index
= (UINT8
)Index
;
338 Target
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID
;
341 Target
->Header
.Flags
|= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED
;
344 Target
->Port
= NvData
->TargetPort
;
346 if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_CHAP
) {
347 if (AuthConfig
->CHAPType
== ISCSI_CHAP_UNI
) {
348 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_CHAP
;
349 } else if (AuthConfig
->CHAPType
== ISCSI_CHAP_MUTUAL
) {
350 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP
;
352 } else if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_NONE
) {
353 Target
->CHAPType
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_NO_CHAP
;
356 Target
->NicIndex
= (UINT8
)Index
;
358 if ((NvData
->IpMode
== IP_MODE_IP4
) || (NvData
->IpMode
== IP_MODE_AUTOCONFIG
)) {
359 IScsiMapV4ToV6Addr (&NvData
->TargetIp
.v4
, &Target
->Ip
);
360 } else if ((NvData
->IpMode
== IP_MODE_IP6
) || (NvData
->IpMode
== IP_MODE_AUTOCONFIG
)) {
361 CopyMem (&Target
->Ip
, &NvData
->TargetIp
, sizeof (EFI_IPv6_ADDRESS
));
366 CopyMem (Target
->BootLun
, NvData
->BootLun
, sizeof (Target
->BootLun
));
369 // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.
371 Length
= (UINT16
)AsciiStrLen (NvData
->TargetName
);
372 IScsiAddHeapItem (Heap
, NvData
->TargetName
, Length
);
374 Target
->IScsiNameLength
= Length
;
375 Target
->IScsiNameOffset
= (UINT16
)((UINTN
)*Heap
- (UINTN
)Table
);
377 if (Attempt
->AuthenticationType
== ISCSI_AUTH_TYPE_CHAP
) {
381 Length
= (UINT16
)AsciiStrLen (AuthConfig
->CHAPName
);
382 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPName
, Length
);
383 Target
->CHAPNameLength
= Length
;
384 Target
->CHAPNameOffset
= (UINT16
)((UINTN
)*Heap
- (UINTN
)Table
);
389 Length
= (UINT16
)AsciiStrLen (AuthConfig
->CHAPSecret
);
390 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPSecret
, Length
);
391 Target
->CHAPSecretLength
= Length
;
392 Target
->CHAPSecretOffset
= (UINT16
)((UINTN
)*Heap
- (UINTN
)Table
);
394 if (Target
->CHAPType
== EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_CHAP_TYPE_MUTUAL_CHAP
) {
396 // Reverse CHAP Name.
398 Length
= (UINT16
)AsciiStrLen (AuthConfig
->ReverseCHAPName
);
399 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPName
, Length
);
400 Target
->ReverseCHAPNameLength
= Length
;
401 Target
->ReverseCHAPNameOffset
= (UINT16
)((UINTN
)*Heap
- (UINTN
)Table
);
404 // Reverse CHAP Secret.
406 Length
= (UINT16
)AsciiStrLen (AuthConfig
->ReverseCHAPSecret
);
407 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPSecret
, Length
);
408 Target
->ReverseCHAPSecretLength
= Length
;
409 Target
->ReverseCHAPSecretOffset
= (UINT16
)((UINTN
)*Heap
- (UINTN
)Table
);
413 *SectionOffset
= (UINT16
)((UINTN
)Target
- (UINTN
)Table
);
417 // Advance to the next NIC/Target pair.
419 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*)((UINTN
)Target
+
420 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
)));
421 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*)((UINTN
)Nic
+
422 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
429 Publish and remove the iSCSI Boot Firmware Table according to the iSCSI
439 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
440 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
;
441 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*Rsdp
;
442 EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
;
443 EFI_ACPI_DESCRIPTION_HEADER
*Xsdt
;
450 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**)&AcpiTableProtocol
);
451 if (EFI_ERROR (Status
)) {
456 // Find ACPI table RSD_PTR from the system table.
458 Status
= EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid
, (VOID
**)&Rsdp
);
459 if (EFI_ERROR (Status
)) {
460 Status
= EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid
, (VOID
**)&Rsdp
);
463 if (EFI_ERROR (Status
) || (Rsdp
== NULL
)) {
465 } else if ((Rsdp
->Revision
>= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION
) && (Rsdp
->XsdtAddress
!= 0)) {
466 Xsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*)(UINTN
)Rsdp
->XsdtAddress
;
467 } else if (Rsdp
->RsdtAddress
!= 0) {
468 Rsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*)(UINTN
)Rsdp
->RsdtAddress
;
471 if ((Xsdt
== NULL
) && (Rsdt
== NULL
)) {
475 if (mIbftInstalled
) {
476 Status
= AcpiTableProtocol
->UninstallAcpiTable (
480 if (EFI_ERROR (Status
)) {
484 mIbftInstalled
= FALSE
;
488 // If there is no valid attempt configuration, just return.
490 if ((!mPrivate
->EnableMpio
&& (mPrivate
->ValidSinglePathCount
== 0)) ||
491 (mPrivate
->EnableMpio
&& (mPrivate
->MpioCount
<= mPrivate
->Krb5MpioCount
)))
497 // Allocate 4k bytes to hold the ACPI table.
499 Table
= AllocateZeroPool (IBFT_MAX_SIZE
);
504 Heap
= (UINT8
*)Table
+ IBFT_HEAP_OFFSET
;
507 // Fill in the various section of the iSCSI Boot Firmware Table.
509 if (Rsdp
->Revision
>= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION
) {
510 IScsiInitIbfTableHeader (Table
, Xsdt
->OemId
, &Xsdt
->OemTableId
);
512 IScsiInitIbfTableHeader (Table
, Rsdt
->OemId
, &Rsdt
->OemTableId
);
515 IScsiInitControlSection (Table
);
516 IScsiFillInitiatorSection (Table
, &Heap
);
517 IScsiFillNICAndTargetSections (Table
, &Heap
);
519 Checksum
= CalculateCheckSum8 ((UINT8
*)Table
, Table
->Length
);
520 Table
->Checksum
= Checksum
;
523 // Install or update the iBFT table.
525 Status
= AcpiTableProtocol
->InstallAcpiTable (
531 if (EFI_ERROR (Status
)) {
535 mIbftInstalled
= TRUE
;