]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/IScsiDxe/IScsiIbft.c
6d2b184aad9ea1909cdea4c880c75e6b181e09e5
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / IScsiIbft.c
1 /** @file
2 Implementation for iSCSI Boot Firmware Table publication.
3
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
9
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.
12
13 **/
14
15 #include "IScsiImpl.h"
16
17 BOOLEAN mIbftInstalled = FALSE;
18 UINTN mTableKey;
19
20 /**
21 Initialize the header of the iSCSI Boot Firmware Table.
22
23 @param[out] Header The header of the iSCSI Boot Firmware Table.
24 **/
25 VOID
26 IScsiInitIbfTableHeader (
27 OUT EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Header
28 )
29 {
30 ZeroMem (Header, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER));
31
32 Header->Signature = EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE;
33 Header->Length = IBFT_HEAP_OFFSET;
34 Header->Revision = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION;
35 Header->Checksum = 0;
36
37 Header->OemId[0] = 'I';
38 Header->OemId[1] = 'N';
39 Header->OemId[2] = 'T';
40 Header->OemId[3] = 'E';
41 Header->OemId[4] = 'L';
42 }
43
44 /**
45 Initialize the control section of the iSCSI Boot Firmware Table.
46
47 @param[in] Table The ACPI table.
48 @param[in] HandleCount The number of the handles associated with iSCSI sessions, it's
49 equal to the number of iSCSI sessions.
50 **/
51 VOID
52 IScsiInitControlSection (
53 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,
54 IN UINTN HandleCount
55 )
56 {
57 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;
58 UINTN NumOffset;
59
60 Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);
61
62 ZeroMem (Control, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE));
63
64 Control->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID;
65 Control->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION;
66 Control->Header.Length = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE);
67
68 //
69 // Each session occupies two offsets, one for the NIC section,
70 // the other for the Target section.
71 //
72 NumOffset = 2 * HandleCount;
73 if (NumOffset > 4) {
74 //
75 // Need expand the control section if more than 2 NIC/Target sections
76 // exist.
77 //
78 Control->Header.Length = (UINT16) (Control->Header.Length + (NumOffset - 4) * sizeof (UINT16));
79 }
80 }
81
82 /**
83 Add one item into the heap.
84
85 @param[in, out] Heap On input, the current address of the heap; On output, the address of
86 the heap after the item is added.
87 @param[in] Data The data to add into the heap.
88 @param[in] Len Length of the Data in byte.
89 **/
90 VOID
91 IScsiAddHeapItem (
92 IN OUT UINT8 **Heap,
93 IN VOID *Data,
94 IN UINTN Len
95 )
96 {
97 //
98 // Add one byte for the NULL delimiter.
99 //
100 *Heap -= Len + 1;
101
102 CopyMem (*Heap, Data, Len);
103 *(*Heap + Len) = 0;
104 }
105
106 /**
107 Fill the Initiator section of the iSCSI Boot Firmware Table.
108
109 @param[in] Table The ACPI table.
110 @param[in, out] Heap The heap.
111 @param[in] Handle The handle associated with the iSCSI session.
112 **/
113 VOID
114 IScsiFillInitiatorSection (
115 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,
116 IN OUT UINT8 **Heap,
117 IN EFI_HANDLE Handle
118 )
119 {
120 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;
121 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *Initiator;
122 ISCSI_DRIVER_DATA *DriverData;
123 ISCSI_SESSION *Session;
124 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;
125 EFI_STATUS Status;
126
127 Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);
128
129 //
130 // Initiator section immediately follows the control section.
131 //
132 Initiator = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *) ((UINT8 *) Control + IBFT_ROUNDUP (Control->Header.Length));
133
134 Control->InitiatorOffset = (UINT16) ((UINTN) Initiator - (UINTN) Table);
135
136 ZeroMem (Initiator, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE));
137
138 Initiator->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID;
139 Initiator->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION;
140 Initiator->Header.Length = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE);
141 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;
142
143 //
144 // Get the identifier from the handle.
145 //
146 Status = gBS->HandleProtocol (Handle, &gIScsiPrivateGuid, (VOID **) &IScsiIdentifier);
147 if (EFI_ERROR (Status)) {
148 ASSERT (FALSE);
149 return ;
150 }
151
152 DriverData = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
153 Session = &DriverData->Session;
154
155 //
156 // Fill the iSCSI Initiator Name into the heap.
157 //
158 IScsiAddHeapItem (Heap, Session->InitiatorName, Session->InitiatorNameLength - 1);
159
160 Initiator->IScsiNameLength = (UINT16) (Session->InitiatorNameLength - 1);
161 Initiator->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
162 }
163
164 /**
165 Map the v4 IP address into v6 IP address.
166
167 @param[in] V4 The v4 IP address.
168 @param[out] V6 The v6 IP address.
169 **/
170 VOID
171 IScsiMapV4ToV6Addr (
172 IN EFI_IPv4_ADDRESS *V4,
173 OUT EFI_IPv6_ADDRESS *V6
174 )
175 {
176 UINTN Index;
177
178 ZeroMem (V6, sizeof (EFI_IPv6_ADDRESS));
179
180 V6->Addr[10] = 0xff;
181 V6->Addr[11] = 0xff;
182
183 for (Index = 0; Index < 4; Index++) {
184 V6->Addr[12 + Index] = V4->Addr[Index];
185 }
186 }
187
188 /**
189 Get the NIC's PCI location and return it accroding to the composited
190 format defined in iSCSI Boot Firmware Table.
191
192 @param[in] Controller The handle of the controller.
193
194 @return UINT16 The composited representation of the NIC PCI location.
195 @retval 0 Other errors as indicated.
196 **/
197 UINT16
198 IScsiGetNICPciLocation (
199 IN EFI_HANDLE Controller
200 )
201 {
202 EFI_STATUS Status;
203 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
204 EFI_HANDLE PciIoHandle;
205 EFI_PCI_IO_PROTOCOL *PciIo;
206 UINTN Segment;
207 UINTN Bus;
208 UINTN Device;
209 UINTN Function;
210
211 Status = gBS->HandleProtocol (
212 Controller,
213 &gEfiDevicePathProtocolGuid,
214 (VOID **)&DevicePath
215 );
216 if (EFI_ERROR (Status)) {
217 return 0;
218 }
219
220 Status = gBS->LocateDevicePath (
221 &gEfiPciIoProtocolGuid,
222 &DevicePath,
223 &PciIoHandle
224 );
225 if (EFI_ERROR (Status)) {
226 return 0;
227 }
228
229 Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
230 if (EFI_ERROR (Status)) {
231 return 0;
232 }
233
234 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
235 if (EFI_ERROR (Status)) {
236 return 0;
237 }
238
239 return (UINT16) ((Bus << 8) | (Device << 3) | Function);
240 }
241
242 /**
243 Get the MAC address of the controller.
244
245 @param[in] Controller The handle of the controller.
246
247 @return EFI_MAC_ADDRESS * The mac address.
248 **/
249 EFI_MAC_ADDRESS *
250 IScsiGetMacAddress (
251 IN EFI_HANDLE Controller
252 )
253 {
254 EFI_STATUS Status;
255 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
256
257 Status = gBS->HandleProtocol (
258 Controller,
259 &gEfiSimpleNetworkProtocolGuid,
260 (VOID **) &Snp
261 );
262 ASSERT_EFI_ERROR (Status);
263
264 return &Snp->Mode->PermanentAddress;
265 }
266
267 /**
268 Fill the NIC and target sections in iSCSI Boot Firmware Table.
269
270 @param[in] Table The buffer of the ACPI table.
271 @param[in, out] Heap The heap buffer used to store the variable length parameters such as iSCSI name.
272 @param[in] HandleCount Count The number of handles having iSCSI private protocol installed.
273 @param[in] Handles The handle buffer.
274 **/
275 VOID
276 IScsiFillNICAndTargetSections (
277 IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table,
278 IN OUT UINT8 **Heap,
279 IN UINTN HandleCount,
280 IN EFI_HANDLE *Handles
281 )
282 {
283 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *Control;
284 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *Nic;
285 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *Target;
286 ISCSI_DRIVER_DATA *DriverData;
287 ISCSI_SESSION_CONFIG_DATA *SessionConfigData;
288 ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig;
289 UINT16 *SectionOffset;
290 UINTN Index;
291 UINT16 Length;
292 EFI_MAC_ADDRESS *Mac;
293 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;
294 EFI_STATUS Status;
295
296 //
297 // Get the offset of the first Nic and Target section.
298 //
299 Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);
300 Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Table +
301 Control->InitiatorOffset + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE)));
302 Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +
303 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));
304
305 SectionOffset = &Control->NIC0Offset;
306
307 for (Index = 0; Index < HandleCount; Index++) {
308 Status = gBS->HandleProtocol (Handles[Index], &gIScsiPrivateGuid, (VOID **)&IScsiIdentifier);
309 if (EFI_ERROR (Status)) {
310 ASSERT (FALSE);
311 return ;
312 }
313
314 DriverData = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
315 SessionConfigData = &DriverData->Session.ConfigData;
316 AuthConfig = &DriverData->Session.AuthData.AuthConfig;
317
318 //
319 // Fill the Nic section.
320 //
321 ZeroMem (Nic, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE));
322
323 Nic->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID;
324 Nic->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION;
325 Nic->Header.Length = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE);
326 Nic->Header.Index = (UINT8) Index;
327 Nic->Header.Flags = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID |
328 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED |
329 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL;
330
331 //
332 // Get the subnet mask prefix length.
333 //
334 Nic->SubnetMaskPrefixLength = IScsiGetSubnetMaskPrefixLength (&SessionConfigData->NvData.SubnetMask);
335
336 if (SessionConfigData->NvData.InitiatorInfoFromDhcp) {
337 Nic->Origin = IpPrefixOriginDhcp;
338 } else {
339 Nic->Origin = IpPrefixOriginManual;
340 }
341 //
342 // Map the various v4 addresses into v6 addresses.
343 //
344 IScsiMapV4ToV6Addr (&SessionConfigData->NvData.LocalIp, &Nic->Ip);
345 IScsiMapV4ToV6Addr (&SessionConfigData->NvData.Gateway, &Nic->Gateway);
346 IScsiMapV4ToV6Addr (&SessionConfigData->PrimaryDns, &Nic->PrimaryDns);
347 IScsiMapV4ToV6Addr (&SessionConfigData->SecondaryDns, &Nic->SecondaryDns);
348 IScsiMapV4ToV6Addr (&SessionConfigData->DhcpServer, &Nic->DhcpServer);
349
350 Mac = IScsiGetMacAddress (DriverData->Controller);
351 CopyMem (Nic->Mac, Mac, sizeof (Nic->Mac));
352
353 //
354 // Get the PCI location of the Nic.
355 //
356 Nic->PciLocation = IScsiGetNICPciLocation (DriverData->Controller);
357
358 *SectionOffset = (UINT16) ((UINTN) Nic - (UINTN) Table);
359 SectionOffset++;
360
361 //
362 // Fill the Target section.
363 //
364 ZeroMem (Target, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE));
365
366 Target->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID;
367 Target->Header.Version = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION;
368 Target->Header.Length = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE);
369 Target->Header.Index = (UINT8) Index;
370 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;
371 Target->Port = SessionConfigData->NvData.TargetPort;
372 Target->CHAPType = AuthConfig->CHAPType;
373 Target->NicIndex = (UINT8) Index;
374
375 IScsiMapV4ToV6Addr (&SessionConfigData->NvData.TargetIp, &Target->Ip);
376 CopyMem (Target->BootLun, SessionConfigData->NvData.BootLun, sizeof (Target->BootLun));
377
378 //
379 // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.
380 //
381 Length = (UINT16) AsciiStrLen (SessionConfigData->NvData.TargetName);
382 IScsiAddHeapItem (Heap, SessionConfigData->NvData.TargetName, Length);
383
384 Target->IScsiNameLength = Length;
385 Target->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
386
387 if (Target->CHAPType != ISCSI_CHAP_NONE) {
388 //
389 // CHAP Name
390 //
391 Length = (UINT16) AsciiStrLen (AuthConfig->CHAPName);
392 IScsiAddHeapItem (Heap, AuthConfig->CHAPName, Length);
393 Target->CHAPNameLength = Length;
394 Target->CHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
395
396 //
397 // CHAP Secret
398 //
399 Length = (UINT16) AsciiStrLen (AuthConfig->CHAPSecret);
400 IScsiAddHeapItem (Heap, AuthConfig->CHAPSecret, Length);
401 Target->CHAPSecretLength = Length;
402 Target->CHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
403
404 if (Target->CHAPType == ISCSI_CHAP_MUTUAL) {
405 //
406 // Reverse CHAP Name
407 //
408 Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPName);
409 IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPName, Length);
410 Target->ReverseCHAPNameLength = Length;
411 Target->ReverseCHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
412
413 //
414 // Reverse CHAP Secret
415 //
416 Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPSecret);
417 IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPSecret, Length);
418 Target->ReverseCHAPSecretLength = Length;
419 Target->ReverseCHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);
420 }
421 }
422
423 *SectionOffset = (UINT16) ((UINTN) Target - (UINTN) Table);
424 SectionOffset++;
425
426 //
427 // Advance to the next NIC/Target pair
428 //
429 Nic = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Target +
430 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE)));
431 Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +
432 IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));
433 }
434 }
435
436 /**
437 Publish and remove the iSCSI Boot Firmware Table according to the iSCSI
438 session status.
439 **/
440 VOID
441 IScsiPublishIbft (
442 VOID
443 )
444 {
445 EFI_STATUS Status;
446 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
447 EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table;
448 UINTN HandleCount;
449 EFI_HANDLE *HandleBuffer;
450 UINT8 *Heap;
451 UINT8 Checksum;
452
453 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTableProtocol);
454 if (EFI_ERROR (Status)) {
455 return ;
456 }
457
458 if (mIbftInstalled) {
459 Status = AcpiTableProtocol->UninstallAcpiTable (
460 AcpiTableProtocol,
461 mTableKey
462 );
463 if (EFI_ERROR (Status)) {
464 return ;
465 }
466 mIbftInstalled = FALSE;
467 }
468
469 //
470 // Get all iSCSI private protocols.
471 //
472 Status = gBS->LocateHandleBuffer (
473 ByProtocol,
474 &gIScsiPrivateGuid,
475 NULL,
476 &HandleCount,
477 &HandleBuffer
478 );
479 if (EFI_ERROR (Status)) {
480 return ;
481 }
482 //
483 // Allocate 4k bytes to hold the ACPI table.
484 //
485 Table = AllocateZeroPool (IBFT_MAX_SIZE);
486 if (Table == NULL) {
487 return ;
488 }
489
490 Heap = (UINT8 *) Table + IBFT_HEAP_OFFSET;
491
492 //
493 // Fill in the various section of the iSCSI Boot Firmware Table.
494 //
495 IScsiInitIbfTableHeader (Table);
496 IScsiInitControlSection (Table, HandleCount);
497 IScsiFillInitiatorSection (Table, &Heap, HandleBuffer[0]);
498 IScsiFillNICAndTargetSections (Table, &Heap, HandleCount, HandleBuffer);
499
500 Checksum = CalculateCheckSum8((UINT8 *)Table, Table->Length);
501 Table->Checksum = Checksum;
502
503 FreePool (HandleBuffer);
504
505 //
506 // Install or update the iBFT table.
507 //
508 Status = AcpiTableProtocol->InstallAcpiTable (
509 AcpiTableProtocol,
510 Table,
511 Table->Length,
512 &mTableKey
513 );
514 if (EFI_ERROR(Status)) {
515 return;
516 }
517
518 mIbftInstalled = TRUE;
519 FreePool (Table);
520 }