2 Implementation for iSCSI Boot Firmware Table publication.
4 Copyright (c) 2004 - 2009, Intel Corporation.<BR>
5 All rights reserved. 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
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.
15 #include "IScsiImpl.h"
17 BOOLEAN mIbftInstalled
= FALSE
;
21 Initialize the header of the iSCSI Boot Firmware Table.
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.
28 IScsiInitIbfTableHeader (
29 OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Header
,
34 ZeroMem (Header
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
));
36 Header
->Signature
= EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE
;
37 Header
->Length
= IBFT_HEAP_OFFSET
;
38 Header
->Revision
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION
;
41 Header
->OemId
[0] = 'I';
42 Header
->OemId
[1] = 'N';
43 Header
->OemId
[2] = 'T';
44 Header
->OemId
[3] = 'E';
45 Header
->OemId
[4] = 'L';
47 CopyMem (Header
->OemId
, OemId
, sizeof (Header
->OemId
));
48 Header
->OemTableId
= *OemTableId
;
52 Initialize the control section of the iSCSI Boot Firmware Table.
54 @param[in] Table The ACPI table.
55 @param[in] HandleCount The number of the handles associated with iSCSI sessions, it's
56 equal to the number of iSCSI sessions.
59 IScsiInitControlSection (
60 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
64 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
67 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
69 ZeroMem (Control
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
));
71 Control
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID
;
72 Control
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION
;
73 Control
->Header
.Length
= sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
);
76 // Each session occupies two offsets, one for the NIC section,
77 // the other for the Target section.
79 NumOffset
= 2 * HandleCount
;
82 // Need expand the control section if more than 2 NIC/Target sections
85 Control
->Header
.Length
= (UINT16
) (Control
->Header
.Length
+ (NumOffset
- 4) * sizeof (UINT16
));
90 Add one item into the heap.
92 @param[in, out] Heap On input, the current address of the heap; On output, the address of
93 the heap after the item is added.
94 @param[in] Data The data to add into the heap.
95 @param[in] Len Length of the Data in byte.
105 // Add one byte for the NULL delimiter.
109 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.
118 @param[in] Handle The handle associated with the iSCSI session.
121 IScsiFillInitiatorSection (
122 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
127 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
128 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*Initiator
;
129 ISCSI_DRIVER_DATA
*DriverData
;
130 ISCSI_SESSION
*Session
;
131 ISCSI_PRIVATE_PROTOCOL
*IScsiIdentifier
;
134 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
137 // Initiator section immediately follows the control section.
139 Initiator
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
*) ((UINT8
*) Control
+ IBFT_ROUNDUP (Control
->Header
.Length
));
141 Control
->InitiatorOffset
= (UINT16
) ((UINTN
) Initiator
- (UINTN
) Table
);
143 ZeroMem (Initiator
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
));
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
= sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
);
148 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
;
151 // Get the identifier from the handle.
153 Status
= gBS
->HandleProtocol (Handle
, &gIScsiPrivateGuid
, (VOID
**) &IScsiIdentifier
);
154 if (EFI_ERROR (Status
)) {
159 DriverData
= ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier
);
160 Session
= &DriverData
->Session
;
163 // Fill the iSCSI Initiator Name into the heap.
165 IScsiAddHeapItem (Heap
, Session
->InitiatorName
, Session
->InitiatorNameLength
- 1);
167 Initiator
->IScsiNameLength
= (UINT16
) (Session
->InitiatorNameLength
- 1);
168 Initiator
->IScsiNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
172 Map the v4 IP address into v6 IP address.
174 @param[in] V4 The v4 IP address.
175 @param[out] V6 The v6 IP address.
179 IN EFI_IPv4_ADDRESS
*V4
,
180 OUT EFI_IPv6_ADDRESS
*V6
185 ZeroMem (V6
, sizeof (EFI_IPv6_ADDRESS
));
190 for (Index
= 0; Index
< 4; Index
++) {
191 V6
->Addr
[12 + Index
] = V4
->Addr
[Index
];
196 Get the NIC's PCI location and return it accroding to the composited
197 format defined in iSCSI Boot Firmware Table.
199 @param[in] Controller The handle of the controller.
201 @return UINT16 The composited representation of the NIC PCI location.
202 @retval 0 Other errors as indicated.
205 IScsiGetNICPciLocation (
206 IN EFI_HANDLE Controller
210 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
211 EFI_HANDLE PciIoHandle
;
212 EFI_PCI_IO_PROTOCOL
*PciIo
;
218 Status
= gBS
->HandleProtocol (
220 &gEfiDevicePathProtocolGuid
,
223 if (EFI_ERROR (Status
)) {
227 Status
= gBS
->LocateDevicePath (
228 &gEfiPciIoProtocolGuid
,
232 if (EFI_ERROR (Status
)) {
236 Status
= gBS
->HandleProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
, (VOID
**)&PciIo
);
237 if (EFI_ERROR (Status
)) {
241 Status
= PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
, &Function
);
242 if (EFI_ERROR (Status
)) {
246 return (UINT16
) ((Bus
<< 8) | (Device
<< 3) | Function
);
250 Get the MAC address of the controller.
252 @param[in] Controller The handle of the controller.
254 @return EFI_MAC_ADDRESS * The mac address.
258 IN EFI_HANDLE Controller
262 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
264 Status
= gBS
->HandleProtocol (
266 &gEfiSimpleNetworkProtocolGuid
,
269 ASSERT_EFI_ERROR (Status
);
271 return &Snp
->Mode
->PermanentAddress
;
275 Fill the NIC and target sections in iSCSI Boot Firmware Table.
277 @param[in] Table The buffer of the ACPI table.
278 @param[in, out] Heap The heap buffer used to store the variable length parameters such as iSCSI name.
279 @param[in] HandleCount Count The number of handles having iSCSI private protocol installed.
280 @param[in] Handles The handle buffer.
283 IScsiFillNICAndTargetSections (
284 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
,
286 IN UINTN HandleCount
,
287 IN EFI_HANDLE
*Handles
290 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*Control
;
291 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*Nic
;
292 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*Target
;
293 ISCSI_DRIVER_DATA
*DriverData
;
294 ISCSI_SESSION_CONFIG_DATA
*SessionConfigData
;
295 ISCSI_CHAP_AUTH_CONFIG_NVDATA
*AuthConfig
;
296 UINT16
*SectionOffset
;
299 EFI_MAC_ADDRESS
*Mac
;
300 ISCSI_PRIVATE_PROTOCOL
*IScsiIdentifier
;
304 // Get the offset of the first Nic and Target section.
306 Control
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE
*) (Table
+ 1);
307 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*) ((UINTN
) Table
+
308 Control
->InitiatorOffset
+ IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE
)));
309 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*) ((UINTN
) Nic
+
310 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
312 SectionOffset
= &Control
->NIC0Offset
;
314 for (Index
= 0; Index
< HandleCount
; Index
++) {
315 Status
= gBS
->HandleProtocol (Handles
[Index
], &gIScsiPrivateGuid
, (VOID
**)&IScsiIdentifier
);
316 if (EFI_ERROR (Status
)) {
321 DriverData
= ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier
);
322 SessionConfigData
= &DriverData
->Session
.ConfigData
;
323 AuthConfig
= &DriverData
->Session
.AuthData
.AuthConfig
;
326 // Fill the Nic section.
328 ZeroMem (Nic
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
));
330 Nic
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID
;
331 Nic
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION
;
332 Nic
->Header
.Length
= sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
);
333 Nic
->Header
.Index
= (UINT8
) Index
;
334 Nic
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID
|
335 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED
|
336 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL
;
339 // Get the subnet mask prefix length.
341 Nic
->SubnetMaskPrefixLength
= IScsiGetSubnetMaskPrefixLength (&SessionConfigData
->NvData
.SubnetMask
);
343 if (SessionConfigData
->NvData
.InitiatorInfoFromDhcp
) {
344 Nic
->Origin
= IpPrefixOriginDhcp
;
346 Nic
->Origin
= IpPrefixOriginManual
;
349 // Map the various v4 addresses into v6 addresses.
351 IScsiMapV4ToV6Addr (&SessionConfigData
->NvData
.LocalIp
, &Nic
->Ip
);
352 IScsiMapV4ToV6Addr (&SessionConfigData
->NvData
.Gateway
, &Nic
->Gateway
);
353 IScsiMapV4ToV6Addr (&SessionConfigData
->PrimaryDns
, &Nic
->PrimaryDns
);
354 IScsiMapV4ToV6Addr (&SessionConfigData
->SecondaryDns
, &Nic
->SecondaryDns
);
355 IScsiMapV4ToV6Addr (&SessionConfigData
->DhcpServer
, &Nic
->DhcpServer
);
357 Mac
= IScsiGetMacAddress (DriverData
->Controller
);
358 CopyMem (Nic
->Mac
, Mac
, sizeof (Nic
->Mac
));
361 // Get the PCI location of the Nic.
363 Nic
->PciLocation
= IScsiGetNICPciLocation (DriverData
->Controller
);
365 *SectionOffset
= (UINT16
) ((UINTN
) Nic
- (UINTN
) Table
);
369 // Fill the Target section.
371 ZeroMem (Target
, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
));
373 Target
->Header
.StructureId
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID
;
374 Target
->Header
.Version
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION
;
375 Target
->Header
.Length
= sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
);
376 Target
->Header
.Index
= (UINT8
) Index
;
377 Target
->Header
.Flags
= EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID
| EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED
;
378 Target
->Port
= SessionConfigData
->NvData
.TargetPort
;
379 Target
->CHAPType
= AuthConfig
->CHAPType
;
380 Target
->NicIndex
= (UINT8
) Index
;
382 IScsiMapV4ToV6Addr (&SessionConfigData
->NvData
.TargetIp
, &Target
->Ip
);
383 CopyMem (Target
->BootLun
, SessionConfigData
->NvData
.BootLun
, sizeof (Target
->BootLun
));
386 // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.
388 Length
= (UINT16
) AsciiStrLen (SessionConfigData
->NvData
.TargetName
);
389 IScsiAddHeapItem (Heap
, SessionConfigData
->NvData
.TargetName
, Length
);
391 Target
->IScsiNameLength
= Length
;
392 Target
->IScsiNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
394 if (Target
->CHAPType
!= ISCSI_CHAP_NONE
) {
398 Length
= (UINT16
) AsciiStrLen (AuthConfig
->CHAPName
);
399 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPName
, Length
);
400 Target
->CHAPNameLength
= Length
;
401 Target
->CHAPNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
406 Length
= (UINT16
) AsciiStrLen (AuthConfig
->CHAPSecret
);
407 IScsiAddHeapItem (Heap
, AuthConfig
->CHAPSecret
, Length
);
408 Target
->CHAPSecretLength
= Length
;
409 Target
->CHAPSecretOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
411 if (Target
->CHAPType
== ISCSI_CHAP_MUTUAL
) {
415 Length
= (UINT16
) AsciiStrLen (AuthConfig
->ReverseCHAPName
);
416 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPName
, Length
);
417 Target
->ReverseCHAPNameLength
= Length
;
418 Target
->ReverseCHAPNameOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
421 // Reverse CHAP Secret
423 Length
= (UINT16
) AsciiStrLen (AuthConfig
->ReverseCHAPSecret
);
424 IScsiAddHeapItem (Heap
, AuthConfig
->ReverseCHAPSecret
, Length
);
425 Target
->ReverseCHAPSecretLength
= Length
;
426 Target
->ReverseCHAPSecretOffset
= (UINT16
) ((UINTN
) *Heap
- (UINTN
) Table
);
430 *SectionOffset
= (UINT16
) ((UINTN
) Target
- (UINTN
) Table
);
434 // Advance to the next NIC/Target pair
436 Nic
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
*) ((UINTN
) Target
+
437 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
)));
438 Target
= (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE
*) ((UINTN
) Nic
+
439 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE
)));
444 Publish and remove the iSCSI Boot Firmware Table according to the iSCSI
453 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
454 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER
*Table
;
456 EFI_HANDLE
*HandleBuffer
;
460 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*Rsdp
;
461 EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
;
463 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**)&AcpiTableProtocol
);
464 if (EFI_ERROR (Status
)) {
470 // Find ACPI table RSD_PTR from system table
472 for (Index
= 0, Rsdp
= NULL
; Index
< gST
->NumberOfTableEntries
; Index
++) {
473 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi20TableGuid
) ||
474 CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi10TableGuid
) ||
475 CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpiTableGuid
)
478 // A match was found.
480 Rsdp
= (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*) gST
->ConfigurationTable
[Index
].VendorTable
;
488 Rsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*) (UINTN
) Rsdp
->RsdtAddress
;
492 if (mIbftInstalled
) {
493 Status
= AcpiTableProtocol
->UninstallAcpiTable (
497 if (EFI_ERROR (Status
)) {
500 mIbftInstalled
= FALSE
;
504 // Get all iSCSI private protocols.
506 Status
= gBS
->LocateHandleBuffer (
513 if (EFI_ERROR (Status
)) {
517 // Allocate 4k bytes to hold the ACPI table.
519 Table
= AllocateZeroPool (IBFT_MAX_SIZE
);
524 Heap
= (UINT8
*) Table
+ IBFT_HEAP_OFFSET
;
527 // Fill in the various section of the iSCSI Boot Firmware Table.
529 IScsiInitIbfTableHeader (Table
, Rsdt
->OemId
, &Rsdt
->OemTableId
);
530 IScsiInitControlSection (Table
, HandleCount
);
531 IScsiFillInitiatorSection (Table
, &Heap
, HandleBuffer
[0]);
532 IScsiFillNICAndTargetSections (Table
, &Heap
, HandleCount
, HandleBuffer
);
534 Checksum
= CalculateCheckSum8((UINT8
*)Table
, Table
->Length
);
535 Table
->Checksum
= Checksum
;
537 FreePool (HandleBuffer
);
540 // Install or update the iBFT table.
542 Status
= AcpiTableProtocol
->InstallAcpiTable (
548 if (EFI_ERROR(Status
)) {
552 mIbftInstalled
= TRUE
;