2 Implementation for iSCSI Boot Firmware Table publication.
\r
4 Copyright (c) 2004 - 2009, Intel Corporation.<BR>
\r
5 All rights reserved. This program and the accompanying materials
\r
6 are licensed and made available under the terms and conditions of the BSD License
\r
7 which accompanies this distribution. The full text of the license may be found at
\r
8 http://opensource.org/licenses/bsd-license.php
\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
\r
15 #include "IScsiImpl.h"
\r
17 BOOLEAN mIbftInstalled = FALSE;
\r
21 Initialize the header of the iSCSI Boot Firmware Table.
\r
23 @param[out] Header The header of the iSCSI Boot Firmware Table.
\r
24 @param[in] OemId The OEM ID.
\r
25 @param[in] OemTableId The OEM table ID for the iBFT.
\r
28 IScsiInitIbfTableHeader (
\r
29 OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Header,
\r
31 IN UINT64 *OemTableId
\r
34 ZeroMem (Header, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER));
\r
36 Header->Signature = EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE;
\r
37 Header->Length = IBFT_HEAP_OFFSET;
\r
38 Header->Revision = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION;
\r
39 Header->Checksum = 0;
\r
41 Header->OemId[0] = 'I';
\r
42 Header->OemId[1] = 'N';
\r
43 Header->OemId[2] = 'T';
\r
44 Header->OemId[3] = 'E';
\r
45 Header->OemId[4] = 'L';
\r
47 CopyMem (Header->OemId, OemId, sizeof (Header->OemId));
\r
48 Header->OemTableId = *OemTableId;
\r
52 Initialize the control section of the iSCSI Boot Firmware Table.
\r
54 @param[in] Table The ACPI table.
\r
55 @param[in] HandleCount The number of the handles associated with iSCSI sessions, it's
\r
56 equal to the number of iSCSI sessions.
\r
59 IScsiInitControlSection (
\r
60 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,
\r
61 IN UINTN HandleCount
\r
64 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;
\r
67 Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);
\r
69 ZeroMem (Control, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE));
\r
71 Control->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID;
\r
72 Control->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION;
\r
73 Control->Header.Length = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE);
\r
76 // Each session occupies two offsets, one for the NIC section,
\r
77 // the other for the Target section.
\r
79 NumOffset = 2 * HandleCount;
\r
80 if (NumOffset > 4) {
\r
82 // Need expand the control section if more than 2 NIC/Target sections
\r
85 Control->Header.Length = (UINT16) (Control->Header.Length + (NumOffset - 4) * sizeof (UINT16));
\r
90 Add one item into the heap.
\r
92 @param[in, out] Heap On input, the current address of the heap; On output, the address of
\r
93 the heap after the item is added.
\r
94 @param[in] Data The data to add into the heap.
\r
95 @param[in] Len Length of the Data in byte.
\r
99 IN OUT UINT8 **Heap,
\r
105 // Add one byte for the NULL delimiter.
\r
109 CopyMem (*Heap, Data, Len);
\r
110 *(*Heap + Len) = 0;
\r
114 Fill the Initiator section of the iSCSI Boot Firmware Table.
\r
116 @param[in] Table The ACPI table.
\r
117 @param[in, out] Heap The heap.
\r
118 @param[in] Handle The handle associated with the iSCSI session.
\r
121 IScsiFillInitiatorSection (
\r
122 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,
\r
123 IN OUT UINT8 **Heap,
\r
124 IN EFI_HANDLE Handle
\r
127 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;
\r
128 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *Initiator;
\r
129 ISCSI_DRIVER_DATA *DriverData;
\r
130 ISCSI_SESSION *Session;
\r
131 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;
\r
134 Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);
\r
137 // Initiator section immediately follows the control section.
\r
139 Initiator = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *) ((UINT8 *) Control + IBFT_ROUNDUP (Control->Header.Length));
\r
141 Control->InitiatorOffset = (UINT16) ((UINTN) Initiator - (UINTN) Table);
\r
143 ZeroMem (Initiator, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE));
\r
145 Initiator->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID;
\r
146 Initiator->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION;
\r
147 Initiator->Header.Length = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE);
\r
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;
\r
151 // Get the identifier from the handle.
\r
153 Status = gBS->HandleProtocol (Handle, &gIScsiPrivateGuid, (VOID **) &IScsiIdentifier);
\r
154 if (EFI_ERROR (Status)) {
\r
159 DriverData = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
\r
160 Session = &DriverData->Session;
\r
163 // Fill the iSCSI Initiator Name into the heap.
\r
165 IScsiAddHeapItem (Heap, Session->InitiatorName, Session->InitiatorNameLength - 1);
\r
167 Initiator->IScsiNameLength = (UINT16) (Session->InitiatorNameLength - 1);
\r
168 Initiator->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
\r
172 Map the v4 IP address into v6 IP address.
\r
174 @param[in] V4 The v4 IP address.
\r
175 @param[out] V6 The v6 IP address.
\r
178 IScsiMapV4ToV6Addr (
\r
179 IN EFI_IPv4_ADDRESS *V4,
\r
180 OUT EFI_IPv6_ADDRESS *V6
\r
185 ZeroMem (V6, sizeof (EFI_IPv6_ADDRESS));
\r
187 V6->Addr[10] = 0xff;
\r
188 V6->Addr[11] = 0xff;
\r
190 for (Index = 0; Index < 4; Index++) {
\r
191 V6->Addr[12 + Index] = V4->Addr[Index];
\r
196 Get the NIC's PCI location and return it accroding to the composited
\r
197 format defined in iSCSI Boot Firmware Table.
\r
199 @param[in] Controller The handle of the controller.
\r
201 @return UINT16 The composited representation of the NIC PCI location.
\r
202 @retval 0 Other errors as indicated.
\r
205 IScsiGetNICPciLocation (
\r
206 IN EFI_HANDLE Controller
\r
210 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
\r
211 EFI_HANDLE PciIoHandle;
\r
212 EFI_PCI_IO_PROTOCOL *PciIo;
\r
218 Status = gBS->HandleProtocol (
\r
220 &gEfiDevicePathProtocolGuid,
\r
221 (VOID **)&DevicePath
\r
223 if (EFI_ERROR (Status)) {
\r
227 Status = gBS->LocateDevicePath (
\r
228 &gEfiPciIoProtocolGuid,
\r
232 if (EFI_ERROR (Status)) {
\r
236 Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
\r
237 if (EFI_ERROR (Status)) {
\r
241 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
\r
242 if (EFI_ERROR (Status)) {
\r
246 return (UINT16) ((Bus << 8) | (Device << 3) | Function);
\r
250 Fill the NIC and target sections in iSCSI Boot Firmware Table.
\r
252 @param[in] Table The buffer of the ACPI table.
\r
253 @param[in, out] Heap The heap buffer used to store the variable length parameters such as iSCSI name.
\r
254 @param[in] HandleCount Count The number of handles having iSCSI private protocol installed.
\r
255 @param[in] Handles The handle buffer.
\r
258 IScsiFillNICAndTargetSections (
\r
259 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,
\r
260 IN OUT UINT8 **Heap,
\r
261 IN UINTN HandleCount,
\r
262 IN EFI_HANDLE *Handles
\r
265 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;
\r
266 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *Nic;
\r
267 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *Target;
\r
268 ISCSI_DRIVER_DATA *DriverData;
\r
269 ISCSI_SESSION_CONFIG_DATA *SessionConfigData;
\r
270 ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig;
\r
271 UINT16 *SectionOffset;
\r
274 EFI_MAC_ADDRESS MacAddress;
\r
275 UINTN HwAddressSize;
\r
276 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;
\r
280 // Get the offset of the first Nic and Target section.
\r
282 Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);
\r
283 Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Table +
\r
284 Control->InitiatorOffset + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE)));
\r
285 Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +
\r
286 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));
\r
288 SectionOffset = &Control->NIC0Offset;
\r
290 for (Index = 0; Index < HandleCount; Index++) {
\r
291 Status = gBS->HandleProtocol (Handles[Index], &gIScsiPrivateGuid, (VOID **)&IScsiIdentifier);
\r
292 if (EFI_ERROR (Status)) {
\r
297 DriverData = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
\r
298 SessionConfigData = &DriverData->Session.ConfigData;
\r
299 AuthConfig = &DriverData->Session.AuthData.AuthConfig;
\r
302 // Fill the Nic section.
\r
304 ZeroMem (Nic, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE));
\r
306 Nic->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID;
\r
307 Nic->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION;
\r
308 Nic->Header.Length = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE);
\r
309 Nic->Header.Index = (UINT8) Index;
\r
310 Nic->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID |
\r
311 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED |
\r
312 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL;
\r
315 // Get the subnet mask prefix length.
\r
317 Nic->SubnetMaskPrefixLength = IScsiGetSubnetMaskPrefixLength (&SessionConfigData->NvData.SubnetMask);
\r
319 if (SessionConfigData->NvData.InitiatorInfoFromDhcp) {
\r
320 Nic->Origin = IpPrefixOriginDhcp;
\r
322 Nic->Origin = IpPrefixOriginManual;
\r
325 // Map the various v4 addresses into v6 addresses.
\r
327 IScsiMapV4ToV6Addr (&SessionConfigData->NvData.LocalIp, &Nic->Ip);
\r
328 IScsiMapV4ToV6Addr (&SessionConfigData->NvData.Gateway, &Nic->Gateway);
\r
329 IScsiMapV4ToV6Addr (&SessionConfigData->PrimaryDns, &Nic->PrimaryDns);
\r
330 IScsiMapV4ToV6Addr (&SessionConfigData->SecondaryDns, &Nic->SecondaryDns);
\r
331 IScsiMapV4ToV6Addr (&SessionConfigData->DhcpServer, &Nic->DhcpServer);
\r
333 Nic->VLanTag = NetLibGetVlanId (DriverData->Controller);
\r
335 Status = NetLibGetMacAddress (DriverData->Controller, &MacAddress, &HwAddressSize);
\r
336 ASSERT (Status == EFI_SUCCESS);
\r
337 CopyMem (Nic->Mac, MacAddress.Addr, sizeof (Nic->Mac));
\r
340 // Get the PCI location of the Nic.
\r
342 Nic->PciLocation = IScsiGetNICPciLocation (DriverData->Controller);
\r
344 *SectionOffset = (UINT16) ((UINTN) Nic - (UINTN) Table);
\r
348 // Fill the Target section.
\r
350 ZeroMem (Target, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE));
\r
352 Target->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID;
\r
353 Target->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION;
\r
354 Target->Header.Length = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE);
\r
355 Target->Header.Index = (UINT8) Index;
\r
356 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;
\r
357 Target->Port = SessionConfigData->NvData.TargetPort;
\r
358 Target->CHAPType = AuthConfig->CHAPType;
\r
359 Target->NicIndex = (UINT8) Index;
\r
361 IScsiMapV4ToV6Addr (&SessionConfigData->NvData.TargetIp, &Target->Ip);
\r
362 CopyMem (Target->BootLun, SessionConfigData->NvData.BootLun, sizeof (Target->BootLun));
\r
365 // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.
\r
367 Length = (UINT16) AsciiStrLen (SessionConfigData->NvData.TargetName);
\r
368 IScsiAddHeapItem (Heap, SessionConfigData->NvData.TargetName, Length);
\r
370 Target->IScsiNameLength = Length;
\r
371 Target->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
\r
373 if (Target->CHAPType != ISCSI_CHAP_NONE) {
\r
377 Length = (UINT16) AsciiStrLen (AuthConfig->CHAPName);
\r
378 IScsiAddHeapItem (Heap, AuthConfig->CHAPName, Length);
\r
379 Target->CHAPNameLength = Length;
\r
380 Target->CHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
\r
385 Length = (UINT16) AsciiStrLen (AuthConfig->CHAPSecret);
\r
386 IScsiAddHeapItem (Heap, AuthConfig->CHAPSecret, Length);
\r
387 Target->CHAPSecretLength = Length;
\r
388 Target->CHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
\r
390 if (Target->CHAPType == ISCSI_CHAP_MUTUAL) {
\r
392 // Reverse CHAP Name
\r
394 Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPName);
\r
395 IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPName, Length);
\r
396 Target->ReverseCHAPNameLength = Length;
\r
397 Target->ReverseCHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
\r
400 // Reverse CHAP Secret
\r
402 Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPSecret);
\r
403 IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPSecret, Length);
\r
404 Target->ReverseCHAPSecretLength = Length;
\r
405 Target->ReverseCHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
\r
409 *SectionOffset = (UINT16) ((UINTN) Target - (UINTN) Table);
\r
413 // Advance to the next NIC/Target pair
\r
415 Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Target +
\r
416 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE)));
\r
417 Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +
\r
418 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));
\r
423 Publish and remove the iSCSI Boot Firmware Table according to the iSCSI
\r
432 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
\r
433 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table;
\r
435 EFI_HANDLE *HandleBuffer;
\r
439 EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
\r
440 EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
\r
442 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTableProtocol);
\r
443 if (EFI_ERROR (Status)) {
\r
449 // Find ACPI table RSD_PTR from system table
\r
451 for (Index = 0, Rsdp = NULL; Index < gST->NumberOfTableEntries; Index++) {
\r
452 if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid) ||
\r
453 CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid) ||
\r
454 CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpiTableGuid)
\r
457 // A match was found.
\r
459 Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) gST->ConfigurationTable[Index].VendorTable;
\r
464 if (Rsdp == NULL) {
\r
467 Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;
\r
471 if (mIbftInstalled) {
\r
472 Status = AcpiTableProtocol->UninstallAcpiTable (
\r
476 if (EFI_ERROR (Status)) {
\r
479 mIbftInstalled = FALSE;
\r
483 // Get all iSCSI private protocols.
\r
485 Status = gBS->LocateHandleBuffer (
\r
487 &gIScsiPrivateGuid,
\r
492 if (EFI_ERROR (Status)) {
\r
496 // Allocate 4k bytes to hold the ACPI table.
\r
498 Table = AllocateZeroPool (IBFT_MAX_SIZE);
\r
499 if (Table == NULL) {
\r
503 Heap = (UINT8 *) Table + IBFT_HEAP_OFFSET;
\r
506 // Fill in the various section of the iSCSI Boot Firmware Table.
\r
508 IScsiInitIbfTableHeader (Table, Rsdt->OemId, &Rsdt->OemTableId);
\r
509 IScsiInitControlSection (Table, HandleCount);
\r
510 IScsiFillInitiatorSection (Table, &Heap, HandleBuffer[0]);
\r
511 IScsiFillNICAndTargetSections (Table, &Heap, HandleCount, HandleBuffer);
\r
513 Checksum = CalculateCheckSum8((UINT8 *)Table, Table->Length);
\r
514 Table->Checksum = Checksum;
\r
516 FreePool (HandleBuffer);
\r
519 // Install or update the iBFT table.
\r
521 Status = AcpiTableProtocol->InstallAcpiTable (
\r
527 if (EFI_ERROR(Status)) {
\r
531 mIbftInstalled = TRUE;
\r