]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/HddPassword/HddPasswordDxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / SecurityPkg / HddPassword / HddPasswordDxe.c
1 /** @file
2 HDD password driver which is used to support HDD security feature.
3
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) Microsoft Corporation.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "HddPasswordDxe.h"
12
13 EFI_GUID mHddPasswordVendorGuid = HDD_PASSWORD_CONFIG_GUID;
14 CHAR16 mHddPasswordVendorStorageName[] = L"HDD_PASSWORD_CONFIG";
15 LIST_ENTRY mHddPasswordConfigFormList;
16 UINT32 mNumberOfHddDevices = 0;
17
18 EFI_GUID mHddPasswordDeviceInfoGuid = HDD_PASSWORD_DEVICE_INFO_GUID;
19 BOOLEAN mHddPasswordEndOfDxe = FALSE;
20 HDD_PASSWORD_REQUEST_VARIABLE *mHddPasswordRequestVariable = NULL;
21 UINTN mHddPasswordRequestVariableSize = 0;
22
23 HII_VENDOR_DEVICE_PATH mHddPasswordHiiVendorDevicePath = {
24 {
25 {
26 HARDWARE_DEVICE_PATH,
27 HW_VENDOR_DP,
28 {
29 (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
30 (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
31 }
32 },
33 HDD_PASSWORD_CONFIG_GUID
34 },
35 {
36 END_DEVICE_PATH_TYPE,
37 END_ENTIRE_DEVICE_PATH_SUBTYPE,
38 {
39 (UINT8)(END_DEVICE_PATH_LENGTH),
40 (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
41 }
42 }
43 };
44
45 /**
46 Check if the password is full zero.
47
48 @param[in] Password Points to the data buffer
49
50 @retval TRUE This password string is full zero.
51 @retval FALSE This password string is not full zero.
52
53 **/
54 BOOLEAN
55 PasswordIsFullZero (
56 IN CHAR8 *Password
57 )
58 {
59 UINTN Index;
60
61 for (Index = 0; Index < HDD_PASSWORD_MAX_LENGTH; Index++) {
62 if (Password[Index] != 0) {
63 return FALSE;
64 }
65 }
66
67 return TRUE;
68 }
69
70 /**
71 Save device info.
72
73 @param[in] ConfigFormEntry Points to HDD_PASSWORD_CONFIG_FORM_ENTRY buffer
74 @param[in,out] TempDevInfo Points to HDD_PASSWORD_DEVICE_INFO buffer
75
76 **/
77 VOID
78 SaveDeviceInfo (
79 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,
80 IN OUT HDD_PASSWORD_DEVICE_INFO *TempDevInfo
81 )
82 {
83 TempDevInfo->Device.Bus = (UINT8)ConfigFormEntry->Bus;
84 TempDevInfo->Device.Device = (UINT8)ConfigFormEntry->Device;
85 TempDevInfo->Device.Function = (UINT8)ConfigFormEntry->Function;
86 TempDevInfo->Device.Port = ConfigFormEntry->Port;
87 TempDevInfo->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;
88 CopyMem (TempDevInfo->Password, ConfigFormEntry->Password, HDD_PASSWORD_MAX_LENGTH);
89 TempDevInfo->DevicePathLength = (UINT32)GetDevicePathSize (ConfigFormEntry->DevicePath);
90 CopyMem (TempDevInfo->DevicePath, ConfigFormEntry->DevicePath, TempDevInfo->DevicePathLength);
91 }
92
93 /**
94 Build HDD password device info and save them to LockBox.
95
96 **/
97 VOID
98 BuildHddPasswordDeviceInfo (
99 VOID
100 )
101 {
102 EFI_STATUS Status;
103 LIST_ENTRY *Entry;
104 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;
105 HDD_PASSWORD_DEVICE_INFO *DevInfo;
106 HDD_PASSWORD_DEVICE_INFO *TempDevInfo;
107 UINTN DevInfoLength;
108 UINT8 DummyData;
109 BOOLEAN S3InitDevicesExist;
110 UINTN S3InitDevicesLength;
111 EFI_DEVICE_PATH_PROTOCOL *S3InitDevices;
112 EFI_DEVICE_PATH_PROTOCOL *S3InitDevicesBak;
113
114 //
115 // Build HDD password device info and save them to LockBox.
116 //
117 DevInfoLength = 0;
118 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
119 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
120
121 //
122 // 1. Handle device which already set password.
123 // 2. When request to send freeze command, driver also needs to handle device
124 // which support security feature.
125 //
126 if ((!PasswordIsFullZero (ConfigFormEntry->Password)) ||
127 ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&
128 (ConfigFormEntry->IfrData.SecurityStatus.Enabled == 0)))
129 {
130 DevInfoLength += sizeof (HDD_PASSWORD_DEVICE_INFO) +
131 GetDevicePathSize (ConfigFormEntry->DevicePath);
132 }
133 }
134
135 if (DevInfoLength == 0) {
136 return;
137 }
138
139 S3InitDevicesLength = sizeof (DummyData);
140 Status = RestoreLockBox (
141 &gS3StorageDeviceInitListGuid,
142 &DummyData,
143 &S3InitDevicesLength
144 );
145 ASSERT ((Status == EFI_NOT_FOUND) || (Status == EFI_BUFFER_TOO_SMALL));
146 if (Status == EFI_NOT_FOUND) {
147 S3InitDevices = NULL;
148 S3InitDevicesExist = FALSE;
149 } else if (Status == EFI_BUFFER_TOO_SMALL) {
150 S3InitDevices = AllocatePool (S3InitDevicesLength);
151 ASSERT (S3InitDevices != NULL);
152
153 Status = RestoreLockBox (
154 &gS3StorageDeviceInitListGuid,
155 S3InitDevices,
156 &S3InitDevicesLength
157 );
158 ASSERT_EFI_ERROR (Status);
159 S3InitDevicesExist = TRUE;
160 } else {
161 return;
162 }
163
164 DevInfo = AllocateZeroPool (DevInfoLength);
165 ASSERT (DevInfo != NULL);
166
167 TempDevInfo = DevInfo;
168 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
169 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
170
171 if ((!PasswordIsFullZero (ConfigFormEntry->Password)) ||
172 ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&
173 (ConfigFormEntry->IfrData.SecurityStatus.Enabled == 0)))
174 {
175 SaveDeviceInfo (ConfigFormEntry, TempDevInfo);
176
177 S3InitDevicesBak = S3InitDevices;
178 S3InitDevices = AppendDevicePathInstance (
179 S3InitDevicesBak,
180 ConfigFormEntry->DevicePath
181 );
182 if (S3InitDevicesBak != NULL) {
183 FreePool (S3InitDevicesBak);
184 }
185
186 ASSERT (S3InitDevices != NULL);
187
188 TempDevInfo = (HDD_PASSWORD_DEVICE_INFO *)((UINTN)TempDevInfo +
189 sizeof (HDD_PASSWORD_DEVICE_INFO) +
190 TempDevInfo->DevicePathLength);
191 }
192 }
193
194 Status = SaveLockBox (
195 &mHddPasswordDeviceInfoGuid,
196 DevInfo,
197 DevInfoLength
198 );
199 ASSERT_EFI_ERROR (Status);
200
201 Status = SetLockBoxAttributes (
202 &mHddPasswordDeviceInfoGuid,
203 LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY
204 );
205 ASSERT_EFI_ERROR (Status);
206
207 S3InitDevicesLength = GetDevicePathSize (S3InitDevices);
208 if (S3InitDevicesExist) {
209 Status = UpdateLockBox (
210 &gS3StorageDeviceInitListGuid,
211 0,
212 S3InitDevices,
213 S3InitDevicesLength
214 );
215 ASSERT_EFI_ERROR (Status);
216 } else {
217 Status = SaveLockBox (
218 &gS3StorageDeviceInitListGuid,
219 S3InitDevices,
220 S3InitDevicesLength
221 );
222 ASSERT_EFI_ERROR (Status);
223
224 Status = SetLockBoxAttributes (
225 &gS3StorageDeviceInitListGuid,
226 LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY
227 );
228 ASSERT_EFI_ERROR (Status);
229 }
230
231 ZeroMem (DevInfo, DevInfoLength);
232 FreePool (DevInfo);
233 FreePool (S3InitDevices);
234 }
235
236 /**
237 Send freeze lock cmd through Ata Pass Thru Protocol.
238
239 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.
240 @param[in] Port The port number of the ATA device to send the command.
241 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
242 If there is no port multiplier, then specify 0xFFFF.
243
244 @retval EFI_SUCCESS Successful to send freeze lock cmd.
245 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
246 @retval EFI_OUT_OF_RESOURCES Not enough memory to send freeze lock cmd.
247 @retval EFI_DEVICE_ERROR Can not send freeze lock cmd.
248
249 **/
250 EFI_STATUS
251 FreezeLockDevice (
252 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
253 IN UINT16 Port,
254 IN UINT16 PortMultiplierPort
255 )
256 {
257 EFI_STATUS Status;
258 EFI_ATA_COMMAND_BLOCK Acb;
259 EFI_ATA_STATUS_BLOCK *Asb;
260 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
261
262 if (AtaPassThru == NULL) {
263 return EFI_INVALID_PARAMETER;
264 }
265
266 //
267 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
268 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
269 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
270 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
271 // may not be aligned when allocated on stack for some compilers. Hence, we
272 // use the API AllocateAlignedPages to ensure this structure is properly
273 // aligned.
274 //
275 Asb = AllocateAlignedPages (
276 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
277 AtaPassThru->Mode->IoAlign
278 );
279 if (Asb == NULL) {
280 return EFI_OUT_OF_RESOURCES;
281 }
282
283 //
284 // Prepare for ATA command block.
285 //
286 ZeroMem (&Acb, sizeof (Acb));
287 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
288 Acb.AtaCommand = ATA_SECURITY_FREEZE_LOCK_CMD;
289 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));
290
291 //
292 // Prepare for ATA pass through packet.
293 //
294 ZeroMem (&Packet, sizeof (Packet));
295 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;
296 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER;
297 Packet.Asb = Asb;
298 Packet.Acb = &Acb;
299 Packet.Timeout = ATA_TIMEOUT;
300
301 Status = AtaPassThru->PassThru (
302 AtaPassThru,
303 Port,
304 PortMultiplierPort,
305 &Packet,
306 NULL
307 );
308 if (!EFI_ERROR (Status) &&
309 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
310 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))
311 {
312 Status = EFI_DEVICE_ERROR;
313 }
314
315 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));
316
317 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));
318 return Status;
319 }
320
321 /**
322 Get attached harddisk identify data through Ata Pass Thru Protocol.
323
324 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.
325 @param[in] Port The port number of the ATA device to send the command.
326 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
327 If there is no port multiplier, then specify 0xFFFF.
328 @param[in] IdentifyData The buffer to store identify data.
329
330 @retval EFI_SUCCESS Successful to get identify data.
331 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
332 @retval EFI_OUT_OF_RESOURCES Not enough memory to get identify data.
333 @retval EFI_DEVICE_ERROR Can not get identify data.
334
335 **/
336 EFI_STATUS
337 GetHddDeviceIdentifyData (
338 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
339 IN UINT16 Port,
340 IN UINT16 PortMultiplierPort,
341 IN ATA_IDENTIFY_DATA *IdentifyData
342 )
343 {
344 EFI_STATUS Status;
345 EFI_ATA_COMMAND_BLOCK Acb;
346 EFI_ATA_STATUS_BLOCK *Asb;
347 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
348
349 if ((AtaPassThru == NULL) || (IdentifyData == NULL)) {
350 return EFI_INVALID_PARAMETER;
351 }
352
353 //
354 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
355 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
356 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
357 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
358 // may not be aligned when allocated on stack for some compilers. Hence, we
359 // use the API AllocateAlignedPages to ensure this structure is properly
360 // aligned.
361 //
362 Asb = AllocateAlignedPages (
363 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
364 AtaPassThru->Mode->IoAlign
365 );
366 if (Asb == NULL) {
367 return EFI_OUT_OF_RESOURCES;
368 }
369
370 //
371 // Prepare for ATA command block.
372 //
373 ZeroMem (&Acb, sizeof (Acb));
374 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
375 Acb.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
376 Acb.AtaDeviceHead = (UINT8)(BIT7 | BIT6 | BIT5 | (PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4)));
377
378 //
379 // Prepare for ATA pass through packet.
380 //
381 ZeroMem (&Packet, sizeof (Packet));
382 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;
383 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
384 Packet.Asb = Asb;
385 Packet.Acb = &Acb;
386 Packet.InDataBuffer = IdentifyData;
387 Packet.InTransferLength = sizeof (ATA_IDENTIFY_DATA);
388 Packet.Timeout = ATA_TIMEOUT;
389
390 Status = AtaPassThru->PassThru (
391 AtaPassThru,
392 Port,
393 PortMultiplierPort,
394 &Packet,
395 NULL
396 );
397
398 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));
399
400 return Status;
401 }
402
403 /**
404 Parse security status according to identify data.
405
406 @param[in] IdentifyData The buffer to store identify data.
407 @param[in, out] IfrData IFR data to hold security status.
408
409 **/
410 VOID
411 GetHddPasswordSecurityStatus (
412 IN ATA_IDENTIFY_DATA *IdentifyData,
413 IN OUT HDD_PASSWORD_CONFIG *IfrData
414 )
415 {
416 IfrData->SecurityStatus.Supported = (IdentifyData->command_set_supported_82 & BIT1) ? 1 : 0;
417 IfrData->SecurityStatus.Enabled = (IdentifyData->security_status & BIT1) ? 1 : 0;
418 IfrData->SecurityStatus.Locked = (IdentifyData->security_status & BIT2) ? 1 : 0;
419 IfrData->SecurityStatus.Frozen = (IdentifyData->security_status & BIT3) ? 1 : 0;
420 IfrData->SecurityStatus.UserPasswordStatus = IfrData->SecurityStatus.Enabled;
421 IfrData->SecurityStatus.MasterPasswordStatus = IfrData->SecurityStatus.Supported;
422
423 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Supported = %x\n", IfrData->SecurityStatus.Supported));
424 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Enabled = %x\n", IfrData->SecurityStatus.Enabled));
425 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Locked = %x\n", IfrData->SecurityStatus.Locked));
426 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Frozen = %x\n", IfrData->SecurityStatus.Frozen));
427 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.UserPasswordStatus = %x\n", IfrData->SecurityStatus.UserPasswordStatus));
428 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.MasterPasswordStatus = %x\n", IfrData->SecurityStatus.MasterPasswordStatus));
429 }
430
431 /**
432 Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
433
434 This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
435
436 @param Event Event whose notification function is being invoked.
437 @param Context Pointer to the notification function's context.
438
439 **/
440 VOID
441 EFIAPI
442 HddPasswordEndOfDxeEventNotify (
443 EFI_EVENT Event,
444 VOID *Context
445 )
446 {
447 LIST_ENTRY *Entry;
448 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;
449 EFI_STATUS Status;
450 ATA_IDENTIFY_DATA IdentifyData;
451
452 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
453
454 mHddPasswordEndOfDxe = TRUE;
455
456 if (mHddPasswordRequestVariable != NULL) {
457 //
458 // Free the HDD password request variable buffer here
459 // as the HDD password requests should have been processed.
460 //
461 FreePool (mHddPasswordRequestVariable);
462 mHddPasswordRequestVariable = NULL;
463 mHddPasswordRequestVariableSize = 0;
464 }
465
466 //
467 // If no any device, return directly.
468 //
469 if (IsListEmpty (&mHddPasswordConfigFormList)) {
470 gBS->CloseEvent (Event);
471 return;
472 }
473
474 BuildHddPasswordDeviceInfo ();
475
476 //
477 // Zero passsword and freeze lock device.
478 //
479 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
480 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
481
482 ZeroMem (ConfigFormEntry->Password, HDD_PASSWORD_MAX_LENGTH);
483
484 //
485 // Check whether need send freeze lock command.
486 // Below device will be froze:
487 // 1. Device not enable password.
488 // 2. Device enable password and unlocked.
489 //
490 if ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&
491 (ConfigFormEntry->IfrData.SecurityStatus.Locked == 0) &&
492 (ConfigFormEntry->IfrData.SecurityStatus.Frozen == 0))
493 {
494 Status = FreezeLockDevice (ConfigFormEntry->AtaPassThru, ConfigFormEntry->Port, ConfigFormEntry->PortMultiplierPort);
495 DEBUG ((DEBUG_INFO, "FreezeLockDevice return %r!\n", Status));
496 Status = GetHddDeviceIdentifyData (
497 ConfigFormEntry->AtaPassThru,
498 ConfigFormEntry->Port,
499 ConfigFormEntry->PortMultiplierPort,
500 &IdentifyData
501 );
502 GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);
503 }
504 }
505
506 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
507
508 gBS->CloseEvent (Event);
509 }
510
511 /**
512 Generate Salt value.
513
514 @param[in, out] SaltValue Points to the salt buffer, 32 bytes
515
516 **/
517 VOID
518 GenSalt (
519 IN OUT UINT8 *SaltValue
520 )
521 {
522 RandomSeed (NULL, 0);
523 RandomBytes (SaltValue, PASSWORD_SALT_SIZE);
524 }
525
526 /**
527 Hash the data to get credential.
528
529 @param[in] Buffer Points to the data buffer
530 @param[in] BufferSize Buffer size
531 @param[in] SaltValue Points to the salt buffer, 32 bytes
532 @param[out] Credential Points to the hashed result
533
534 @retval TRUE Hash the data successfully.
535 @retval FALSE Failed to hash the data.
536
537 **/
538 BOOLEAN
539 GenerateCredential (
540 IN UINT8 *Buffer,
541 IN UINTN BufferSize,
542 IN UINT8 *SaltValue,
543 OUT UINT8 *Credential
544 )
545 {
546 BOOLEAN Status;
547 UINTN HashSize;
548 VOID *Hash;
549 VOID *HashData;
550
551 Hash = NULL;
552 HashData = NULL;
553 Status = FALSE;
554
555 HashSize = Sha256GetContextSize ();
556 Hash = AllocateZeroPool (HashSize);
557 ASSERT (Hash != NULL);
558 if (Hash == NULL) {
559 goto Done;
560 }
561
562 Status = Sha256Init (Hash);
563 if (!Status) {
564 goto Done;
565 }
566
567 HashData = AllocateZeroPool (PASSWORD_SALT_SIZE + BufferSize);
568 ASSERT (HashData != NULL);
569 if (HashData == NULL) {
570 goto Done;
571 }
572
573 CopyMem (HashData, SaltValue, PASSWORD_SALT_SIZE);
574 CopyMem ((UINT8 *)HashData + PASSWORD_SALT_SIZE, Buffer, BufferSize);
575
576 Status = Sha256Update (Hash, HashData, PASSWORD_SALT_SIZE + BufferSize);
577 if (!Status) {
578 goto Done;
579 }
580
581 Status = Sha256Final (Hash, Credential);
582
583 Done:
584 if (Hash != NULL) {
585 FreePool (Hash);
586 }
587
588 if (HashData != NULL) {
589 ZeroMem (HashData, PASSWORD_SALT_SIZE + BufferSize);
590 FreePool (HashData);
591 }
592
593 return Status;
594 }
595
596 /**
597 Save HDD password variable that will be used to validate HDD password
598 when the device is at frozen state.
599
600 @param[in] ConfigFormEntry The HDD Password configuration form entry.
601 @param[in] Password The hdd password of attached ATA device.
602
603 **/
604 VOID
605 SaveHddPasswordVariable (
606 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,
607 IN CHAR8 *Password
608 )
609 {
610 EFI_STATUS Status;
611 HDD_PASSWORD_VARIABLE *TempVariable;
612 UINTN TempVariableSize;
613 HDD_PASSWORD_VARIABLE *NextNode;
614 HDD_PASSWORD_VARIABLE *Variable;
615 UINTN VariableSize;
616 HDD_PASSWORD_VARIABLE *NewVariable;
617 UINTN NewVariableSize;
618 BOOLEAN Delete;
619 BOOLEAN HashOk;
620 UINT8 HashData[SHA256_DIGEST_SIZE];
621 UINT8 SaltData[PASSWORD_SALT_SIZE];
622
623 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
624
625 Delete = FALSE;
626 if (!PasswordIsFullZero (Password)) {
627 //
628 // It is Set/Update HDD Password.
629 //
630 ZeroMem (HashData, sizeof (HashData));
631 ZeroMem (SaltData, sizeof (SaltData));
632 GenSalt (SaltData);
633 HashOk = GenerateCredential ((UINT8 *)Password, HDD_PASSWORD_MAX_LENGTH, SaltData, HashData);
634 if (!HashOk) {
635 DEBUG ((DEBUG_INFO, "GenerateCredential failed\n"));
636 return;
637 }
638 } else {
639 //
640 // It is Disable HDD Password.
641 // Go to delete the variable node for the HDD password device.
642 //
643 Delete = TRUE;
644 }
645
646 Variable = NULL;
647 VariableSize = 0;
648 NewVariable = NULL;
649 NewVariableSize = 0;
650
651 Status = GetVariable2 (
652 HDD_PASSWORD_VARIABLE_NAME,
653 &mHddPasswordVendorGuid,
654 (VOID **)&Variable,
655 &VariableSize
656 );
657 if (Delete) {
658 if (!EFI_ERROR (Status) && (Variable != NULL)) {
659 TempVariable = Variable;
660 TempVariableSize = VariableSize;
661 while (TempVariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {
662 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&
663 (TempVariable->Device.Device == ConfigFormEntry->Device) &&
664 (TempVariable->Device.Function == ConfigFormEntry->Function) &&
665 (TempVariable->Device.Port == ConfigFormEntry->Port) &&
666 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))
667 {
668 //
669 // Found the node for the HDD password device.
670 // Delete the node.
671 //
672 NextNode = TempVariable + 1;
673 CopyMem (TempVariable, NextNode, (UINTN)Variable + VariableSize - (UINTN)NextNode);
674 NewVariable = Variable;
675 NewVariableSize = VariableSize - sizeof (HDD_PASSWORD_VARIABLE);
676 break;
677 }
678
679 TempVariableSize -= sizeof (HDD_PASSWORD_VARIABLE);
680 TempVariable += 1;
681 }
682
683 if (NewVariable == NULL) {
684 DEBUG ((DEBUG_INFO, "The variable node for the HDD password device is not found\n"));
685 }
686 } else {
687 DEBUG ((DEBUG_INFO, "HddPassword variable get failed (%r)\n", Status));
688 }
689 } else {
690 if (!EFI_ERROR (Status) && (Variable != NULL)) {
691 TempVariable = Variable;
692 TempVariableSize = VariableSize;
693 while (TempVariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {
694 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&
695 (TempVariable->Device.Device == ConfigFormEntry->Device) &&
696 (TempVariable->Device.Function == ConfigFormEntry->Function) &&
697 (TempVariable->Device.Port == ConfigFormEntry->Port) &&
698 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))
699 {
700 //
701 // Found the node for the HDD password device.
702 // Update the node.
703 //
704 CopyMem (TempVariable->PasswordHash, HashData, sizeof (HashData));
705 CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltData));
706 NewVariable = Variable;
707 NewVariableSize = VariableSize;
708 break;
709 }
710
711 TempVariableSize -= sizeof (HDD_PASSWORD_VARIABLE);
712 TempVariable += 1;
713 }
714
715 if (NewVariable == NULL) {
716 //
717 // The node for the HDD password device is not found.
718 // Create node for the HDD password device.
719 //
720 NewVariableSize = VariableSize + sizeof (HDD_PASSWORD_VARIABLE);
721 NewVariable = AllocateZeroPool (NewVariableSize);
722 ASSERT (NewVariable != NULL);
723 CopyMem (NewVariable, Variable, VariableSize);
724 TempVariable = (HDD_PASSWORD_VARIABLE *)((UINTN)NewVariable + VariableSize);
725 TempVariable->Device.Bus = (UINT8)ConfigFormEntry->Bus;
726 TempVariable->Device.Device = (UINT8)ConfigFormEntry->Device;
727 TempVariable->Device.Function = (UINT8)ConfigFormEntry->Function;
728 TempVariable->Device.Port = ConfigFormEntry->Port;
729 TempVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;
730 CopyMem (TempVariable->PasswordHash, HashData, sizeof (HashData));
731 CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltData));
732 }
733 } else {
734 NewVariableSize = sizeof (HDD_PASSWORD_VARIABLE);
735 NewVariable = AllocateZeroPool (NewVariableSize);
736 ASSERT (NewVariable != NULL);
737 NewVariable->Device.Bus = (UINT8)ConfigFormEntry->Bus;
738 NewVariable->Device.Device = (UINT8)ConfigFormEntry->Device;
739 NewVariable->Device.Function = (UINT8)ConfigFormEntry->Function;
740 NewVariable->Device.Port = ConfigFormEntry->Port;
741 NewVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;
742 CopyMem (NewVariable->PasswordHash, HashData, sizeof (HashData));
743 CopyMem (NewVariable->PasswordSalt, SaltData, sizeof (SaltData));
744 }
745 }
746
747 if (NewVariable != NULL) {
748 Status = gRT->SetVariable (
749 HDD_PASSWORD_VARIABLE_NAME,
750 &mHddPasswordVendorGuid,
751 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
752 NewVariableSize,
753 NewVariable
754 );
755 if (EFI_ERROR (Status)) {
756 DEBUG ((DEBUG_INFO, "HddPassword variable set failed (%r)\n", Status));
757 }
758 }
759
760 if (NewVariable != Variable) {
761 FreePool (NewVariable);
762 }
763
764 if (Variable != NULL) {
765 FreePool (Variable);
766 }
767
768 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
769 }
770
771 /**
772 Get saved HDD password variable that will be used to validate HDD password
773 when the device is at frozen state.
774
775 @param[in] ConfigFormEntry The HDD Password configuration form entry.
776 @param[out] HddPasswordVariable The variable node for the HDD password device.
777
778 @retval TRUE The variable node for the HDD password device is found and returned.
779 @retval FALSE The variable node for the HDD password device is not found.
780
781 **/
782 BOOLEAN
783 GetSavedHddPasswordVariable (
784 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,
785 OUT HDD_PASSWORD_VARIABLE *HddPasswordVariable
786 )
787 {
788 EFI_STATUS Status;
789 HDD_PASSWORD_VARIABLE *TempVariable;
790 HDD_PASSWORD_VARIABLE *Variable;
791 UINTN VariableSize;
792 BOOLEAN Found;
793
794 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
795
796 Variable = NULL;
797 VariableSize = 0;
798
799 Status = GetVariable2 (
800 HDD_PASSWORD_VARIABLE_NAME,
801 &mHddPasswordVendorGuid,
802 (VOID **)&Variable,
803 &VariableSize
804 );
805 if (EFI_ERROR (Status) || (Variable == NULL)) {
806 DEBUG ((DEBUG_INFO, "HddPassword variable get failed (%r)\n", Status));
807 return FALSE;
808 }
809
810 Found = FALSE;
811 TempVariable = Variable;
812 while (VariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {
813 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&
814 (TempVariable->Device.Device == ConfigFormEntry->Device) &&
815 (TempVariable->Device.Function == ConfigFormEntry->Function) &&
816 (TempVariable->Device.Port == ConfigFormEntry->Port) &&
817 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))
818 {
819 //
820 // Found the node for the HDD password device.
821 // Get the node.
822 //
823 CopyMem (HddPasswordVariable, TempVariable, sizeof (HDD_PASSWORD_VARIABLE));
824 Found = TRUE;
825 break;
826 }
827
828 VariableSize -= sizeof (HDD_PASSWORD_VARIABLE);
829 TempVariable += 1;
830 }
831
832 FreePool (Variable);
833
834 if (!Found) {
835 DEBUG ((DEBUG_INFO, "The variable node for the HDD password device is not found\n"));
836 }
837
838 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
839
840 return Found;
841 }
842
843 /**
844 Use saved HDD password variable to validate HDD password
845 when the device is at frozen state.
846
847 @param[in] ConfigFormEntry The HDD Password configuration form entry.
848 @param[in] Password The hdd password of attached ATA device.
849
850 @retval EFI_SUCCESS Pass to validate the HDD password.
851 @retval EFI_NOT_FOUND The variable node for the HDD password device is not found.
852 @retval EFI_DEVICE_ERROR Failed to generate credential for the HDD password.
853 @retval EFI_INVALID_PARAMETER Failed to validate the HDD password.
854
855 **/
856 EFI_STATUS
857 ValidateHddPassword (
858 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,
859 IN CHAR8 *Password
860 )
861 {
862 EFI_STATUS Status;
863 HDD_PASSWORD_VARIABLE HddPasswordVariable;
864 BOOLEAN HashOk;
865 UINT8 HashData[SHA256_DIGEST_SIZE];
866
867 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
868
869 if (!GetSavedHddPasswordVariable (ConfigFormEntry, &HddPasswordVariable)) {
870 DEBUG ((DEBUG_INFO, "GetSavedHddPasswordVariable failed\n"));
871 return EFI_NOT_FOUND;
872 }
873
874 ZeroMem (HashData, sizeof (HashData));
875 HashOk = GenerateCredential ((UINT8 *)Password, HDD_PASSWORD_MAX_LENGTH, HddPasswordVariable.PasswordSalt, HashData);
876 if (!HashOk) {
877 DEBUG ((DEBUG_INFO, "GenerateCredential failed\n"));
878 return EFI_DEVICE_ERROR;
879 }
880
881 if (CompareMem (HddPasswordVariable.PasswordHash, HashData, sizeof (HashData)) != 0) {
882 Status = EFI_INVALID_PARAMETER;
883 } else {
884 Status = EFI_SUCCESS;
885 }
886
887 DEBUG ((DEBUG_INFO, "%a() - exit (%r)\n", __FUNCTION__, Status));
888 return Status;
889 }
890
891 /**
892 Send unlock hdd password cmd through Ata Pass Thru Protocol.
893
894 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.
895 @param[in] Port The port number of the ATA device to send the command.
896 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
897 If there is no port multiplier, then specify 0xFFFF.
898 @param[in] Identifier The identifier to set user or master password.
899 @param[in] Password The hdd password of attached ATA device.
900
901 @retval EFI_SUCCESS Successful to send unlock hdd password cmd.
902 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
903 @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.
904 @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd.
905
906 **/
907 EFI_STATUS
908 UnlockHddPassword (
909 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
910 IN UINT16 Port,
911 IN UINT16 PortMultiplierPort,
912 IN CHAR8 Identifier,
913 IN CHAR8 *Password
914 )
915 {
916 EFI_STATUS Status;
917 EFI_ATA_COMMAND_BLOCK Acb;
918 EFI_ATA_STATUS_BLOCK *Asb;
919 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
920 UINT8 Buffer[HDD_PAYLOAD];
921
922 if ((AtaPassThru == NULL) || (Password == NULL)) {
923 return EFI_INVALID_PARAMETER;
924 }
925
926 //
927 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
928 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
929 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
930 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
931 // may not be aligned when allocated on stack for some compilers. Hence, we
932 // use the API AllocateAlignedPages to ensure this structure is properly
933 // aligned.
934 //
935 Asb = AllocateAlignedPages (
936 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
937 AtaPassThru->Mode->IoAlign
938 );
939 if (Asb == NULL) {
940 return EFI_OUT_OF_RESOURCES;
941 }
942
943 //
944 // Prepare for ATA command block.
945 //
946 ZeroMem (&Acb, sizeof (Acb));
947 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
948 Acb.AtaCommand = ATA_SECURITY_UNLOCK_CMD;
949 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));
950
951 //
952 // Prepare for ATA pass through packet.
953 //
954 ZeroMem (&Packet, sizeof (Packet));
955 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;
956 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;
957 Packet.Asb = Asb;
958 Packet.Acb = &Acb;
959
960 ((CHAR16 *)Buffer)[0] = Identifier & BIT0;
961 CopyMem (&((CHAR16 *)Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);
962
963 Packet.OutDataBuffer = Buffer;
964 Packet.OutTransferLength = sizeof (Buffer);
965 Packet.Timeout = ATA_TIMEOUT;
966
967 Status = AtaPassThru->PassThru (
968 AtaPassThru,
969 Port,
970 PortMultiplierPort,
971 &Packet,
972 NULL
973 );
974 if (!EFI_ERROR (Status) &&
975 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
976 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))
977 {
978 Status = EFI_DEVICE_ERROR;
979 }
980
981 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));
982
983 ZeroMem (Buffer, sizeof (Buffer));
984
985 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));
986 return Status;
987 }
988
989 /**
990 Send disable hdd password cmd through Ata Pass Thru Protocol.
991
992 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.
993 @param[in] Port The port number of the ATA device to send the command.
994 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
995 If there is no port multiplier, then specify 0xFFFF.
996 @param[in] Identifier The identifier to set user or master password.
997 @param[in] Password The hdd password of attached ATA device.
998
999 @retval EFI_SUCCESS Successful to disable hdd password cmd.
1000 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
1001 @retval EFI_OUT_OF_RESOURCES Not enough memory to disable hdd password cmd.
1002 @retval EFI_DEVICE_ERROR Can not disable hdd password cmd.
1003
1004 **/
1005 EFI_STATUS
1006 DisableHddPassword (
1007 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
1008 IN UINT16 Port,
1009 IN UINT16 PortMultiplierPort,
1010 IN CHAR8 Identifier,
1011 IN CHAR8 *Password
1012 )
1013 {
1014 EFI_STATUS Status;
1015 EFI_ATA_COMMAND_BLOCK Acb;
1016 EFI_ATA_STATUS_BLOCK *Asb;
1017 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
1018 UINT8 Buffer[HDD_PAYLOAD];
1019
1020 if ((AtaPassThru == NULL) || (Password == NULL)) {
1021 return EFI_INVALID_PARAMETER;
1022 }
1023
1024 //
1025 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
1026 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
1027 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
1028 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
1029 // may not be aligned when allocated on stack for some compilers. Hence, we
1030 // use the API AllocateAlignedPages to ensure this structure is properly
1031 // aligned.
1032 //
1033 Asb = AllocateAlignedPages (
1034 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
1035 AtaPassThru->Mode->IoAlign
1036 );
1037 if (Asb == NULL) {
1038 return EFI_OUT_OF_RESOURCES;
1039 }
1040
1041 //
1042 // Prepare for ATA command block.
1043 //
1044 ZeroMem (&Acb, sizeof (Acb));
1045 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
1046 Acb.AtaCommand = ATA_SECURITY_DIS_PASSWORD_CMD;
1047 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));
1048
1049 //
1050 // Prepare for ATA pass through packet.
1051 //
1052 ZeroMem (&Packet, sizeof (Packet));
1053 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;
1054 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;
1055 Packet.Asb = Asb;
1056 Packet.Acb = &Acb;
1057
1058 ((CHAR16 *)Buffer)[0] = Identifier & BIT0;
1059 CopyMem (&((CHAR16 *)Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);
1060
1061 Packet.OutDataBuffer = Buffer;
1062 Packet.OutTransferLength = sizeof (Buffer);
1063 Packet.Timeout = ATA_TIMEOUT;
1064
1065 Status = AtaPassThru->PassThru (
1066 AtaPassThru,
1067 Port,
1068 PortMultiplierPort,
1069 &Packet,
1070 NULL
1071 );
1072 if (!EFI_ERROR (Status) &&
1073 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
1074 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))
1075 {
1076 Status = EFI_DEVICE_ERROR;
1077 }
1078
1079 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));
1080
1081 ZeroMem (Buffer, sizeof (Buffer));
1082
1083 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));
1084 return Status;
1085 }
1086
1087 /**
1088 Send set hdd password cmd through Ata Pass Thru Protocol.
1089
1090 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.
1091 @param[in] Port The port number of the ATA device to send the command.
1092 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
1093 If there is no port multiplier, then specify 0xFFFF.
1094 @param[in] Identifier The identifier to set user or master password.
1095 @param[in] SecurityLevel The security level to be set to device.
1096 @param[in] MasterPasswordIdentifier The master password identifier to be set to device.
1097 @param[in] Password The hdd password of attached ATA device.
1098
1099 @retval EFI_SUCCESS Successful to set hdd password cmd.
1100 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
1101 @retval EFI_OUT_OF_RESOURCES Not enough memory to set hdd password cmd.
1102 @retval EFI_DEVICE_ERROR Can not set hdd password cmd.
1103
1104 **/
1105 EFI_STATUS
1106 SetHddPassword (
1107 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
1108 IN UINT16 Port,
1109 IN UINT16 PortMultiplierPort,
1110 IN CHAR8 Identifier,
1111 IN CHAR8 SecurityLevel,
1112 IN CHAR16 MasterPasswordIdentifier,
1113 IN CHAR8 *Password
1114 )
1115 {
1116 EFI_STATUS Status;
1117 EFI_ATA_COMMAND_BLOCK Acb;
1118 EFI_ATA_STATUS_BLOCK *Asb;
1119 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
1120 UINT8 Buffer[HDD_PAYLOAD];
1121
1122 if ((AtaPassThru == NULL) || (Password == NULL)) {
1123 return EFI_INVALID_PARAMETER;
1124 }
1125
1126 //
1127 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
1128 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
1129 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
1130 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
1131 // may not be aligned when allocated on stack for some compilers. Hence, we
1132 // use the API AllocateAlignedPages to ensure this structure is properly
1133 // aligned.
1134 //
1135 Asb = AllocateAlignedPages (
1136 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
1137 AtaPassThru->Mode->IoAlign
1138 );
1139 if (Asb == NULL) {
1140 return EFI_OUT_OF_RESOURCES;
1141 }
1142
1143 //
1144 // Prepare for ATA command block.
1145 //
1146 ZeroMem (&Acb, sizeof (Acb));
1147 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
1148 Acb.AtaCommand = ATA_SECURITY_SET_PASSWORD_CMD;
1149 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));
1150
1151 //
1152 // Prepare for ATA pass through packet.
1153 //
1154 ZeroMem (&Packet, sizeof (Packet));
1155 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;
1156 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;
1157 Packet.Asb = Asb;
1158 Packet.Acb = &Acb;
1159
1160 ((CHAR16 *)Buffer)[0] = (Identifier | (UINT16)(SecurityLevel << 8)) & (BIT0 | BIT8);
1161 CopyMem (&((CHAR16 *)Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);
1162 if ((Identifier & BIT0) != 0) {
1163 ((CHAR16 *)Buffer)[17] = MasterPasswordIdentifier;
1164 }
1165
1166 Packet.OutDataBuffer = Buffer;
1167 Packet.OutTransferLength = sizeof (Buffer);
1168 Packet.Timeout = ATA_TIMEOUT;
1169
1170 Status = AtaPassThru->PassThru (
1171 AtaPassThru,
1172 Port,
1173 PortMultiplierPort,
1174 &Packet,
1175 NULL
1176 );
1177 if (!EFI_ERROR (Status) &&
1178 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
1179 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))
1180 {
1181 Status = EFI_DEVICE_ERROR;
1182 }
1183
1184 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));
1185
1186 ZeroMem (Buffer, sizeof (Buffer));
1187
1188 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));
1189 return Status;
1190 }
1191
1192 /**
1193 Get attached harddisk model number from identify data buffer.
1194
1195 @param[in] IdentifyData Pointer to identify data buffer.
1196 @param[in, out] String The buffer to store harddisk model number.
1197
1198 **/
1199 VOID
1200 GetHddDeviceModelNumber (
1201 IN ATA_IDENTIFY_DATA *IdentifyData,
1202 IN OUT CHAR16 *String
1203 )
1204 {
1205 UINTN Index;
1206
1207 //
1208 // Swap the byte order in the original module name.
1209 // From Ata spec, the maximum length is 40 bytes.
1210 //
1211 for (Index = 0; Index < 40; Index += 2) {
1212 String[Index] = IdentifyData->ModelName[Index + 1];
1213 String[Index + 1] = IdentifyData->ModelName[Index];
1214 }
1215
1216 //
1217 // Chap it off after 20 characters
1218 //
1219 String[20] = L'\0';
1220
1221 return;
1222 }
1223
1224 /**
1225 Get password input from the popup windows.
1226
1227 @param[in] PopUpString1 Pop up string 1.
1228 @param[in] PopUpString2 Pop up string 2.
1229 @param[in, out] Password The buffer to hold the input password.
1230
1231 @retval EFI_ABORTED It is given up by pressing 'ESC' key.
1232 @retval EFI_SUCCESS Get password input successfully.
1233
1234 **/
1235 EFI_STATUS
1236 PopupHddPasswordInputWindows (
1237 IN CHAR16 *PopUpString1,
1238 IN CHAR16 *PopUpString2,
1239 IN OUT CHAR8 *Password
1240 )
1241 {
1242 EFI_INPUT_KEY Key;
1243 UINTN Length;
1244 CHAR16 Mask[HDD_PASSWORD_MAX_LENGTH + 1];
1245 CHAR16 Unicode[HDD_PASSWORD_MAX_LENGTH + 1];
1246 CHAR8 Ascii[HDD_PASSWORD_MAX_LENGTH + 1];
1247
1248 ZeroMem (Unicode, sizeof (Unicode));
1249 ZeroMem (Ascii, sizeof (Ascii));
1250 ZeroMem (Mask, sizeof (Mask));
1251
1252 gST->ConOut->ClearScreen (gST->ConOut);
1253
1254 Length = 0;
1255 while (TRUE) {
1256 Mask[Length] = L'_';
1257 if (PopUpString2 == NULL) {
1258 CreatePopUp (
1259 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1260 &Key,
1261 PopUpString1,
1262 L"---------------------",
1263 Mask,
1264 NULL
1265 );
1266 } else {
1267 CreatePopUp (
1268 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1269 &Key,
1270 PopUpString1,
1271 PopUpString2,
1272 L"---------------------",
1273 Mask,
1274 NULL
1275 );
1276 }
1277
1278 //
1279 // Check key.
1280 //
1281 if (Key.ScanCode == SCAN_NULL) {
1282 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
1283 //
1284 // Add the null terminator.
1285 //
1286 Unicode[Length] = 0;
1287 break;
1288 } else if ((Key.UnicodeChar == CHAR_NULL) ||
1289 (Key.UnicodeChar == CHAR_TAB) ||
1290 (Key.UnicodeChar == CHAR_LINEFEED)
1291 )
1292 {
1293 continue;
1294 } else {
1295 if (Key.UnicodeChar == CHAR_BACKSPACE) {
1296 if (Length > 0) {
1297 Unicode[Length] = 0;
1298 Mask[Length] = 0;
1299 Length--;
1300 }
1301 } else {
1302 Unicode[Length] = Key.UnicodeChar;
1303 Mask[Length] = L'*';
1304 Length++;
1305 if (Length == HDD_PASSWORD_MAX_LENGTH) {
1306 //
1307 // Add the null terminator.
1308 //
1309 Unicode[Length] = 0;
1310 Mask[Length] = 0;
1311 break;
1312 }
1313 }
1314 }
1315 }
1316
1317 if (Key.ScanCode == SCAN_ESC) {
1318 ZeroMem (Unicode, sizeof (Unicode));
1319 ZeroMem (Ascii, sizeof (Ascii));
1320 gST->ConOut->ClearScreen (gST->ConOut);
1321 return EFI_ABORTED;
1322 }
1323 }
1324
1325 UnicodeStrToAsciiStrS (Unicode, Ascii, sizeof (Ascii));
1326 CopyMem (Password, Ascii, HDD_PASSWORD_MAX_LENGTH);
1327 ZeroMem (Unicode, sizeof (Unicode));
1328 ZeroMem (Ascii, sizeof (Ascii));
1329
1330 gST->ConOut->ClearScreen (gST->ConOut);
1331 return EFI_SUCCESS;
1332 }
1333
1334 /**
1335 Check if disk is locked, show popup window and ask for password if it is.
1336
1337 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.
1338 @param[in] Port The port number of attached ATA device.
1339 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.
1340 @param[in] ConfigFormEntry The HDD Password configuration form entry.
1341
1342 **/
1343 VOID
1344 HddPasswordRequestPassword (
1345 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
1346 IN UINT16 Port,
1347 IN UINT16 PortMultiplierPort,
1348 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry
1349 )
1350 {
1351 EFI_STATUS Status;
1352 CHAR16 PopUpString[100];
1353 ATA_IDENTIFY_DATA IdentifyData;
1354 EFI_INPUT_KEY Key;
1355 UINT16 RetryCount;
1356 CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];
1357
1358 RetryCount = 0;
1359
1360 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
1361
1362 UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Unlock: %s", ConfigFormEntry->HddString);
1363
1364 //
1365 // Check the device security status.
1366 //
1367 if ((ConfigFormEntry->IfrData.SecurityStatus.Supported) &&
1368 (ConfigFormEntry->IfrData.SecurityStatus.Enabled))
1369 {
1370 //
1371 // Add PcdSkipHddPasswordPrompt to determin whether to skip password prompt.
1372 // Due to board design, device may not power off during system warm boot, which result in
1373 // security status remain unlocked status, hence we add device security status check here.
1374 //
1375 // If device is in the locked status, device keeps locked and system continues booting.
1376 // If device is in the unlocked status, system is forced shutdown for security concern.
1377 //
1378 if (PcdGetBool (PcdSkipHddPasswordPrompt)) {
1379 if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {
1380 return;
1381 } else {
1382 gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1383 }
1384 }
1385
1386 //
1387 // As soon as the HDD password is in enabled state, we pop up a window to unlock hdd
1388 // no matter it's really in locked or unlocked state.
1389 // This way forces user to enter password every time to provide best safety.
1390 //
1391 while (TRUE) {
1392 Status = PopupHddPasswordInputWindows (PopUpString, NULL, Password);
1393 if (!EFI_ERROR (Status)) {
1394 //
1395 // The HDD is in locked state, unlock it by user input.
1396 //
1397 if (!PasswordIsFullZero (Password)) {
1398 if (!ConfigFormEntry->IfrData.SecurityStatus.Frozen) {
1399 Status = UnlockHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, Password);
1400 } else {
1401 //
1402 // Use saved HDD password variable to validate HDD password
1403 // when the device is at frozen state.
1404 //
1405 Status = ValidateHddPassword (ConfigFormEntry, Password);
1406 }
1407 } else {
1408 Status = EFI_INVALID_PARAMETER;
1409 }
1410
1411 if (!EFI_ERROR (Status)) {
1412 CopyMem (ConfigFormEntry->Password, Password, HDD_PASSWORD_MAX_LENGTH);
1413 if (!ConfigFormEntry->IfrData.SecurityStatus.Frozen) {
1414 SaveHddPasswordVariable (ConfigFormEntry, Password);
1415 }
1416
1417 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);
1418 Status = GetHddDeviceIdentifyData (AtaPassThru, Port, PortMultiplierPort, &IdentifyData);
1419 ASSERT_EFI_ERROR (Status);
1420
1421 //
1422 // Check the device security status again.
1423 //
1424 GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);
1425 return;
1426 }
1427
1428 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);
1429
1430 if (EFI_ERROR (Status)) {
1431 RetryCount++;
1432 if (RetryCount < MAX_HDD_PASSWORD_RETRY_COUNT) {
1433 do {
1434 CreatePopUp (
1435 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1436 &Key,
1437 L"Invalid password.",
1438 L"Press ENTER to retry",
1439 NULL
1440 );
1441 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1442
1443 continue;
1444 } else {
1445 do {
1446 CreatePopUp (
1447 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1448 &Key,
1449 L"Hdd password retry count is expired. Please shutdown the machine.",
1450 L"Press ENTER to shutdown",
1451 NULL
1452 );
1453 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1454
1455 gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1456 break;
1457 }
1458 }
1459 } else if (Status == EFI_ABORTED) {
1460 if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {
1461 //
1462 // Current device in the lock status and
1463 // User not input password and press ESC,
1464 // keep device in lock status and continue boot.
1465 //
1466 do {
1467 CreatePopUp (
1468 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1469 &Key,
1470 L"Press ENTER to skip the request and continue boot,",
1471 L"Press ESC to input password again",
1472 NULL
1473 );
1474 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
1475
1476 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
1477 gST->ConOut->ClearScreen (gST->ConOut);
1478 //
1479 // Keep lock and continue boot.
1480 //
1481 return;
1482 } else {
1483 //
1484 // Let user input password again.
1485 //
1486 continue;
1487 }
1488 } else {
1489 //
1490 // Current device in the unlock status and
1491 // User not input password and press ESC,
1492 // Shutdown the device.
1493 //
1494 do {
1495 CreatePopUp (
1496 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1497 &Key,
1498 L"Press ENTER to shutdown, Press ESC to input password again",
1499 NULL
1500 );
1501 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
1502
1503 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
1504 gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1505 } else {
1506 //
1507 // Let user input password again.
1508 //
1509 continue;
1510 }
1511 }
1512 }
1513 }
1514 }
1515 }
1516
1517 /**
1518 Process Set User Pwd HDD password request.
1519
1520 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.
1521 @param[in] Port The port number of attached ATA device.
1522 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.
1523 @param[in] ConfigFormEntry The HDD Password configuration form entry.
1524
1525 **/
1526 VOID
1527 ProcessHddPasswordRequestSetUserPwd (
1528 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
1529 IN UINT16 Port,
1530 IN UINT16 PortMultiplierPort,
1531 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry
1532 )
1533 {
1534 EFI_STATUS Status;
1535 CHAR16 PopUpString[100];
1536 ATA_IDENTIFY_DATA IdentifyData;
1537 EFI_INPUT_KEY Key;
1538 UINT16 RetryCount;
1539 CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];
1540 CHAR8 PasswordConfirm[HDD_PASSWORD_MAX_LENGTH];
1541
1542 RetryCount = 0;
1543
1544 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
1545
1546 if (ConfigFormEntry->IfrData.SecurityStatus.Frozen) {
1547 DEBUG ((DEBUG_INFO, "%s is frozen, do nothing\n", ConfigFormEntry->HddString));
1548 return;
1549 }
1550
1551 if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {
1552 DEBUG ((DEBUG_INFO, "%s is locked, do nothing\n", ConfigFormEntry->HddString));
1553 return;
1554 }
1555
1556 UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Set User Pwd: %s", ConfigFormEntry->HddString);
1557
1558 //
1559 // Check the device security status.
1560 //
1561 if (ConfigFormEntry->IfrData.SecurityStatus.Supported) {
1562 while (TRUE) {
1563 Status = PopupHddPasswordInputWindows (PopUpString, L"Please type in your new password", Password);
1564 if (!EFI_ERROR (Status)) {
1565 Status = PopupHddPasswordInputWindows (PopUpString, L"Please confirm your new password", PasswordConfirm);
1566 if (!EFI_ERROR (Status)) {
1567 if (CompareMem (Password, PasswordConfirm, HDD_PASSWORD_MAX_LENGTH) == 0) {
1568 if (!PasswordIsFullZero (Password)) {
1569 Status = SetHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, 1, 0, Password);
1570 } else {
1571 if (ConfigFormEntry->IfrData.SecurityStatus.Enabled) {
1572 Status = DisableHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, ConfigFormEntry->Password);
1573 } else {
1574 Status = EFI_INVALID_PARAMETER;
1575 }
1576 }
1577
1578 if (!EFI_ERROR (Status)) {
1579 CopyMem (ConfigFormEntry->Password, Password, HDD_PASSWORD_MAX_LENGTH);
1580 SaveHddPasswordVariable (ConfigFormEntry, Password);
1581 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);
1582 ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);
1583 Status = GetHddDeviceIdentifyData (AtaPassThru, Port, PortMultiplierPort, &IdentifyData);
1584 ASSERT_EFI_ERROR (Status);
1585
1586 //
1587 // Check the device security status again.
1588 //
1589 GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);
1590 return;
1591 } else {
1592 do {
1593 CreatePopUp (
1594 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1595 &Key,
1596 L"Set/Disable User Pwd failed or invalid password.",
1597 L"Press ENTER to retry",
1598 NULL
1599 );
1600 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1601 }
1602 } else {
1603 do {
1604 CreatePopUp (
1605 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1606 &Key,
1607 L"Passwords are not the same.",
1608 L"Press ENTER to retry",
1609 NULL
1610 );
1611 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1612
1613 Status = EFI_INVALID_PARAMETER;
1614 }
1615 }
1616
1617 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);
1618 ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);
1619
1620 if (EFI_ERROR (Status)) {
1621 RetryCount++;
1622 if (RetryCount >= MAX_HDD_PASSWORD_RETRY_COUNT) {
1623 do {
1624 CreatePopUp (
1625 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1626 &Key,
1627 L"Hdd password retry count is expired.",
1628 L"Press ENTER to skip the request and continue boot",
1629 NULL
1630 );
1631 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1632
1633 gST->ConOut->ClearScreen (gST->ConOut);
1634 return;
1635 }
1636 }
1637 } else if (Status == EFI_ABORTED) {
1638 do {
1639 CreatePopUp (
1640 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1641 &Key,
1642 L"Press ENTER to skip the request and continue boot,",
1643 L"Press ESC to input password again",
1644 NULL
1645 );
1646 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
1647
1648 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
1649 gST->ConOut->ClearScreen (gST->ConOut);
1650 return;
1651 } else {
1652 //
1653 // Let user input password again.
1654 //
1655 continue;
1656 }
1657 }
1658 }
1659 }
1660 }
1661
1662 /**
1663 Process Set Master Pwd HDD password request.
1664
1665 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.
1666 @param[in] Port The port number of attached ATA device.
1667 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.
1668 @param[in] ConfigFormEntry The HDD Password configuration form entry.
1669
1670 **/
1671 VOID
1672 ProcessHddPasswordRequestSetMasterPwd (
1673 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
1674 IN UINT16 Port,
1675 IN UINT16 PortMultiplierPort,
1676 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry
1677 )
1678 {
1679 EFI_STATUS Status;
1680 CHAR16 PopUpString[100];
1681 EFI_INPUT_KEY Key;
1682 UINT16 RetryCount;
1683 CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];
1684 CHAR8 PasswordConfirm[HDD_PASSWORD_MAX_LENGTH];
1685
1686 RetryCount = 0;
1687
1688 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
1689
1690 if (ConfigFormEntry->IfrData.SecurityStatus.Frozen) {
1691 DEBUG ((DEBUG_INFO, "%s is frozen, do nothing\n", ConfigFormEntry->HddString));
1692 return;
1693 }
1694
1695 if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {
1696 DEBUG ((DEBUG_INFO, "%s is locked, do nothing\n", ConfigFormEntry->HddString));
1697 return;
1698 }
1699
1700 UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Set Master Pwd: %s", ConfigFormEntry->HddString);
1701
1702 //
1703 // Check the device security status.
1704 //
1705 if (ConfigFormEntry->IfrData.SecurityStatus.Supported) {
1706 while (TRUE) {
1707 Status = PopupHddPasswordInputWindows (PopUpString, L"Please type in your new password", Password);
1708 if (!EFI_ERROR (Status)) {
1709 Status = PopupHddPasswordInputWindows (PopUpString, L"Please confirm your new password", PasswordConfirm);
1710 if (!EFI_ERROR (Status)) {
1711 if (CompareMem (Password, PasswordConfirm, HDD_PASSWORD_MAX_LENGTH) == 0) {
1712 if (!PasswordIsFullZero (Password)) {
1713 Status = SetHddPassword (AtaPassThru, Port, PortMultiplierPort, 1, 1, 1, Password);
1714 } else {
1715 Status = EFI_INVALID_PARAMETER;
1716 }
1717
1718 if (!EFI_ERROR (Status)) {
1719 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);
1720 ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);
1721 return;
1722 } else {
1723 do {
1724 CreatePopUp (
1725 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1726 &Key,
1727 L"Set Master Pwd failed or invalid password.",
1728 L"Press ENTER to retry",
1729 NULL
1730 );
1731 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1732 }
1733 } else {
1734 do {
1735 CreatePopUp (
1736 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1737 &Key,
1738 L"Passwords are not the same.",
1739 L"Press ENTER to retry",
1740 NULL
1741 );
1742 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1743
1744 Status = EFI_INVALID_PARAMETER;
1745 }
1746 }
1747
1748 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);
1749 ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);
1750
1751 if (EFI_ERROR (Status)) {
1752 RetryCount++;
1753 if (RetryCount >= MAX_HDD_PASSWORD_RETRY_COUNT) {
1754 do {
1755 CreatePopUp (
1756 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1757 &Key,
1758 L"Hdd password retry count is expired.",
1759 L"Press ENTER to skip the request and continue boot",
1760 NULL
1761 );
1762 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1763
1764 gST->ConOut->ClearScreen (gST->ConOut);
1765 return;
1766 }
1767 }
1768 } else if (Status == EFI_ABORTED) {
1769 do {
1770 CreatePopUp (
1771 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1772 &Key,
1773 L"Press ENTER to skip the request and continue boot,",
1774 L"Press ESC to input password again",
1775 NULL
1776 );
1777 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
1778
1779 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
1780 gST->ConOut->ClearScreen (gST->ConOut);
1781 return;
1782 } else {
1783 //
1784 // Let user input password again.
1785 //
1786 continue;
1787 }
1788 }
1789 }
1790 }
1791 }
1792
1793 /**
1794 Process HDD password request.
1795
1796 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.
1797 @param[in] Port The port number of attached ATA device.
1798 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.
1799 @param[in] ConfigFormEntry The HDD Password configuration form entry.
1800
1801 **/
1802 VOID
1803 ProcessHddPasswordRequest (
1804 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
1805 IN UINT16 Port,
1806 IN UINT16 PortMultiplierPort,
1807 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry
1808 )
1809 {
1810 EFI_STATUS Status;
1811 HDD_PASSWORD_REQUEST_VARIABLE *TempVariable;
1812 HDD_PASSWORD_REQUEST_VARIABLE *Variable;
1813 UINTN VariableSize;
1814
1815 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
1816
1817 if (mHddPasswordRequestVariable == NULL) {
1818 Status = GetVariable2 (
1819 HDD_PASSWORD_REQUEST_VARIABLE_NAME,
1820 &mHddPasswordVendorGuid,
1821 (VOID **)&Variable,
1822 &VariableSize
1823 );
1824 if (EFI_ERROR (Status) || (Variable == NULL)) {
1825 return;
1826 }
1827
1828 mHddPasswordRequestVariable = Variable;
1829 mHddPasswordRequestVariableSize = VariableSize;
1830
1831 //
1832 // Delete the HDD password request variable.
1833 //
1834 Status = gRT->SetVariable (
1835 HDD_PASSWORD_REQUEST_VARIABLE_NAME,
1836 &mHddPasswordVendorGuid,
1837 0,
1838 0,
1839 NULL
1840 );
1841 ASSERT_EFI_ERROR (Status);
1842 } else {
1843 Variable = mHddPasswordRequestVariable;
1844 VariableSize = mHddPasswordRequestVariableSize;
1845 }
1846
1847 //
1848 // Process the HDD password requests.
1849 //
1850 TempVariable = Variable;
1851 while (VariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {
1852 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&
1853 (TempVariable->Device.Device == ConfigFormEntry->Device) &&
1854 (TempVariable->Device.Function == ConfigFormEntry->Function) &&
1855 (TempVariable->Device.Port == ConfigFormEntry->Port) &&
1856 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))
1857 {
1858 //
1859 // Found the node for the HDD password device.
1860 //
1861 if (TempVariable->Request.UserPassword != 0) {
1862 ProcessHddPasswordRequestSetUserPwd (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);
1863 }
1864
1865 if (TempVariable->Request.MasterPassword != 0) {
1866 ProcessHddPasswordRequestSetMasterPwd (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);
1867 }
1868
1869 break;
1870 }
1871
1872 VariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);
1873 TempVariable += 1;
1874 }
1875
1876 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
1877 }
1878
1879 /**
1880 Get saved HDD password request.
1881
1882 @param[in, out] ConfigFormEntry The HDD Password configuration form entry.
1883
1884 **/
1885 VOID
1886 GetSavedHddPasswordRequest (
1887 IN OUT HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry
1888 )
1889 {
1890 EFI_STATUS Status;
1891 HDD_PASSWORD_REQUEST_VARIABLE *TempVariable;
1892 HDD_PASSWORD_REQUEST_VARIABLE *Variable;
1893 UINTN VariableSize;
1894
1895 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
1896
1897 Variable = NULL;
1898 VariableSize = 0;
1899
1900 Status = GetVariable2 (
1901 HDD_PASSWORD_REQUEST_VARIABLE_NAME,
1902 &mHddPasswordVendorGuid,
1903 (VOID **)&Variable,
1904 &VariableSize
1905 );
1906 if (EFI_ERROR (Status) || (Variable == NULL)) {
1907 return;
1908 }
1909
1910 TempVariable = Variable;
1911 while (VariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {
1912 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&
1913 (TempVariable->Device.Device == ConfigFormEntry->Device) &&
1914 (TempVariable->Device.Function == ConfigFormEntry->Function) &&
1915 (TempVariable->Device.Port == ConfigFormEntry->Port) &&
1916 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))
1917 {
1918 //
1919 // Found the node for the HDD password device.
1920 // Get the HDD password request.
1921 //
1922 CopyMem (&ConfigFormEntry->IfrData.Request, &TempVariable->Request, sizeof (HDD_PASSWORD_REQUEST));
1923 DEBUG ((
1924 DEBUG_INFO,
1925 "HddPasswordRequest got: 0x%x\n",
1926 ConfigFormEntry->IfrData.Request
1927 ));
1928 break;
1929 }
1930
1931 VariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);
1932 TempVariable += 1;
1933 }
1934
1935 FreePool (Variable);
1936
1937 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
1938 }
1939
1940 /**
1941 Save HDD password request.
1942
1943 @param[in] ConfigFormEntry The HDD Password configuration form entry.
1944
1945 **/
1946 VOID
1947 SaveHddPasswordRequest (
1948 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry
1949 )
1950 {
1951 EFI_STATUS Status;
1952 HDD_PASSWORD_REQUEST_VARIABLE *TempVariable;
1953 UINTN TempVariableSize;
1954 HDD_PASSWORD_REQUEST_VARIABLE *Variable;
1955 UINTN VariableSize;
1956 HDD_PASSWORD_REQUEST_VARIABLE *NewVariable;
1957 UINTN NewVariableSize;
1958
1959 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
1960
1961 DEBUG ((
1962 DEBUG_INFO,
1963 "HddPasswordRequest to save: 0x%x\n",
1964 ConfigFormEntry->IfrData.Request
1965 ));
1966
1967 Variable = NULL;
1968 VariableSize = 0;
1969 NewVariable = NULL;
1970 NewVariableSize = 0;
1971
1972 Status = GetVariable2 (
1973 HDD_PASSWORD_REQUEST_VARIABLE_NAME,
1974 &mHddPasswordVendorGuid,
1975 (VOID **)&Variable,
1976 &VariableSize
1977 );
1978 if (!EFI_ERROR (Status) && (Variable != NULL)) {
1979 TempVariable = Variable;
1980 TempVariableSize = VariableSize;
1981 while (TempVariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {
1982 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&
1983 (TempVariable->Device.Device == ConfigFormEntry->Device) &&
1984 (TempVariable->Device.Function == ConfigFormEntry->Function) &&
1985 (TempVariable->Device.Port == ConfigFormEntry->Port) &&
1986 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))
1987 {
1988 //
1989 // Found the node for the HDD password device.
1990 // Update the HDD password request.
1991 //
1992 CopyMem (&TempVariable->Request, &ConfigFormEntry->IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));
1993 NewVariable = Variable;
1994 NewVariableSize = VariableSize;
1995 break;
1996 }
1997
1998 TempVariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);
1999 TempVariable += 1;
2000 }
2001
2002 if (NewVariable == NULL) {
2003 //
2004 // The node for the HDD password device is not found.
2005 // Create node for the HDD password device.
2006 //
2007 NewVariableSize = VariableSize + sizeof (HDD_PASSWORD_REQUEST_VARIABLE);
2008 NewVariable = AllocateZeroPool (NewVariableSize);
2009 ASSERT (NewVariable != NULL);
2010 CopyMem (NewVariable, Variable, VariableSize);
2011 TempVariable = (HDD_PASSWORD_REQUEST_VARIABLE *)((UINTN)NewVariable + VariableSize);
2012 TempVariable->Device.Bus = (UINT8)ConfigFormEntry->Bus;
2013 TempVariable->Device.Device = (UINT8)ConfigFormEntry->Device;
2014 TempVariable->Device.Function = (UINT8)ConfigFormEntry->Function;
2015 TempVariable->Device.Port = ConfigFormEntry->Port;
2016 TempVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;
2017 CopyMem (&TempVariable->Request, &ConfigFormEntry->IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));
2018 }
2019 } else {
2020 NewVariableSize = sizeof (HDD_PASSWORD_REQUEST_VARIABLE);
2021 NewVariable = AllocateZeroPool (NewVariableSize);
2022 ASSERT (NewVariable != NULL);
2023 NewVariable->Device.Bus = (UINT8)ConfigFormEntry->Bus;
2024 NewVariable->Device.Device = (UINT8)ConfigFormEntry->Device;
2025 NewVariable->Device.Function = (UINT8)ConfigFormEntry->Function;
2026 NewVariable->Device.Port = ConfigFormEntry->Port;
2027 NewVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;
2028 CopyMem (&NewVariable->Request, &ConfigFormEntry->IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));
2029 }
2030
2031 Status = gRT->SetVariable (
2032 HDD_PASSWORD_REQUEST_VARIABLE_NAME,
2033 &mHddPasswordVendorGuid,
2034 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
2035 NewVariableSize,
2036 NewVariable
2037 );
2038 if (EFI_ERROR (Status)) {
2039 DEBUG ((DEBUG_INFO, "HddPasswordRequest variable set failed (%r)\n", Status));
2040 }
2041
2042 if (NewVariable != Variable) {
2043 FreePool (NewVariable);
2044 }
2045
2046 if (Variable != NULL) {
2047 FreePool (Variable);
2048 }
2049
2050 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
2051 }
2052
2053 /**
2054 Get the HDD Password configuration form entry by the index of the goto opcode activated.
2055
2056 @param[in] Index The 0-based index of the goto opcode activated.
2057
2058 @return The HDD Password configuration form entry found.
2059 **/
2060 HDD_PASSWORD_CONFIG_FORM_ENTRY *
2061 HddPasswordGetConfigFormEntryByIndex (
2062 IN UINT32 Index
2063 )
2064 {
2065 LIST_ENTRY *Entry;
2066 UINT32 CurrentIndex;
2067 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;
2068
2069 CurrentIndex = 0;
2070 ConfigFormEntry = NULL;
2071
2072 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
2073 if (CurrentIndex == Index) {
2074 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
2075 break;
2076 }
2077
2078 CurrentIndex++;
2079 }
2080
2081 return ConfigFormEntry;
2082 }
2083
2084 /**
2085 This function allows the caller to request the current
2086 configuration for one or more named elements. The resulting
2087 string is in <ConfigAltResp> format. Any and all alternative
2088 configuration strings shall also be appended to the end of the
2089 current configuration string. If they are, they must appear
2090 after the current configuration. They must contain the same
2091 routing (GUID, NAME, PATH) as the current configuration string.
2092 They must have an additional description indicating the type of
2093 alternative configuration the string represents,
2094 "ALTCFG=<StringToken>". That <StringToken> (when
2095 converted from Hex UNICODE to binary) is a reference to a
2096 string in the associated string pack.
2097
2098 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
2099 @param[in] Request A null-terminated Unicode string in
2100 <ConfigRequest> format. Note that this
2101 includes the routing information as well as
2102 the configurable name / value pairs. It is
2103 invalid for this string to be in
2104 <MultiConfigRequest> format.
2105 @param[out] Progress On return, points to a character in the
2106 Request string. Points to the string's null
2107 terminator if request was successful. Points
2108 to the most recent "&" before the first
2109 failing name / value pair (or the beginning
2110 of the string if the failure is in the first
2111 name / value pair) if the request was not
2112 successful.
2113 @param[out] Results A null-terminated Unicode string in
2114 <ConfigAltResp> format which has all values
2115 filled in for the names in the Request string.
2116 String to be allocated by the called function.
2117
2118 @retval EFI_SUCCESS The Results string is filled with the
2119 values corresponding to all requested
2120 names.
2121 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
2122 parts of the results that must be
2123 stored awaiting possible future
2124 protocols.
2125 @retval EFI_INVALID_PARAMETER For example, passing in a NULL
2126 for the Request parameter
2127 would result in this type of
2128 error. In this case, the
2129 Progress parameter would be
2130 set to NULL.
2131 @retval EFI_NOT_FOUND Routing data doesn't match any
2132 known driver. Progress set to the
2133 first character in the routing header.
2134 Note: There is no requirement that the
2135 driver validate the routing data. It
2136 must skip the <ConfigHdr> in order to
2137 process the names.
2138 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set
2139 to most recent & before the
2140 error or the beginning of the
2141 string.
2142 @retval EFI_INVALID_PARAMETER Unknown name. Progress points
2143 to the & before the name in
2144 question.Currently not implemented.
2145 **/
2146 EFI_STATUS
2147 EFIAPI
2148 HddPasswordFormExtractConfig (
2149 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
2150 IN CONST EFI_STRING Request,
2151 OUT EFI_STRING *Progress,
2152 OUT EFI_STRING *Results
2153 )
2154 {
2155 EFI_STATUS Status;
2156 UINTN BufferSize;
2157 HDD_PASSWORD_CONFIG *IfrData;
2158 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;
2159 EFI_STRING ConfigRequestHdr;
2160 EFI_STRING ConfigRequest;
2161 BOOLEAN AllocatedRequest;
2162 UINTN Size;
2163
2164 if ((Progress == NULL) || (Results == NULL)) {
2165 return EFI_INVALID_PARAMETER;
2166 }
2167
2168 *Progress = Request;
2169 if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) {
2170 return EFI_NOT_FOUND;
2171 }
2172
2173 ConfigRequestHdr = NULL;
2174 ConfigRequest = NULL;
2175 AllocatedRequest = FALSE;
2176 Size = 0;
2177
2178 Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);
2179 IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));
2180 ASSERT (IfrData != NULL);
2181 if (Private->Current != NULL) {
2182 CopyMem (IfrData, &Private->Current->IfrData, sizeof (HDD_PASSWORD_CONFIG));
2183 }
2184
2185 //
2186 // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
2187 //
2188 BufferSize = sizeof (HDD_PASSWORD_CONFIG);
2189 ConfigRequest = Request;
2190 if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
2191 //
2192 // Request has no request element, construct full request string.
2193 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
2194 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
2195 //
2196 ConfigRequestHdr = HiiConstructConfigHdr (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, Private->DriverHandle);
2197 Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
2198 ConfigRequest = AllocateZeroPool (Size);
2199 ASSERT (ConfigRequest != NULL);
2200 AllocatedRequest = TRUE;
2201 UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
2202 FreePool (ConfigRequestHdr);
2203 }
2204
2205 Status = gHiiConfigRouting->BlockToConfig (
2206 gHiiConfigRouting,
2207 ConfigRequest,
2208 (UINT8 *)IfrData,
2209 BufferSize,
2210 Results,
2211 Progress
2212 );
2213 FreePool (IfrData);
2214 //
2215 // Free the allocated config request string.
2216 //
2217 if (AllocatedRequest) {
2218 FreePool (ConfigRequest);
2219 ConfigRequest = NULL;
2220 }
2221
2222 //
2223 // Set Progress string to the original request string.
2224 //
2225 if (Request == NULL) {
2226 *Progress = NULL;
2227 } else if (StrStr (Request, L"OFFSET") == NULL) {
2228 *Progress = Request + StrLen (Request);
2229 }
2230
2231 return Status;
2232 }
2233
2234 /**
2235 This function applies changes in a driver's configuration.
2236 Input is a Configuration, which has the routing data for this
2237 driver followed by name / value configuration pairs. The driver
2238 must apply those pairs to its configurable storage. If the
2239 driver's configuration is stored in a linear block of data
2240 and the driver's name / value pairs are in <BlockConfig>
2241 format, it may use the ConfigToBlock helper function (above) to
2242 simplify the job. Currently not implemented.
2243
2244 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
2245 @param[in] Configuration A null-terminated Unicode string in
2246 <ConfigString> format.
2247 @param[out] Progress A pointer to a string filled in with the
2248 offset of the most recent '&' before the
2249 first failing name / value pair (or the
2250 beginn ing of the string if the failure
2251 is in the first name / value pair) or
2252 the terminating NULL if all was
2253 successful.
2254
2255 @retval EFI_SUCCESS The results have been distributed or are
2256 awaiting distribution.
2257 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
2258 parts of the results that must be
2259 stored awaiting possible future
2260 protocols.
2261 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
2262 Results parameter would result
2263 in this type of error.
2264 @retval EFI_NOT_FOUND Target for the specified routing data
2265 was not found.
2266 **/
2267 EFI_STATUS
2268 EFIAPI
2269 HddPasswordFormRouteConfig (
2270 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
2271 IN CONST EFI_STRING Configuration,
2272 OUT EFI_STRING *Progress
2273 )
2274 {
2275 if ((Configuration == NULL) || (Progress == NULL)) {
2276 return EFI_INVALID_PARAMETER;
2277 }
2278
2279 //
2280 // Check routing data in <ConfigHdr>.
2281 // Note: if only one Storage is used, then this checking could be skipped.
2282 //
2283 if (!HiiIsConfigHdrMatch (Configuration, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) {
2284 *Progress = Configuration;
2285 return EFI_NOT_FOUND;
2286 }
2287
2288 *Progress = Configuration + StrLen (Configuration);
2289 return EFI_SUCCESS;
2290 }
2291
2292 /**
2293 This function is called to provide results data to the driver.
2294 This data consists of a unique key that is used to identify
2295 which data is either being passed back or being asked for.
2296
2297 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
2298 @param[in] Action Specifies the type of action taken by the browser.
2299 @param[in] QuestionId A unique value which is sent to the original
2300 exporting driver so that it can identify the type
2301 of data to expect. The format of the data tends to
2302 vary based on the opcode that enerated the callback.
2303 @param[in] Type The type of value for the question.
2304 @param[in] Value A pointer to the data being sent to the original
2305 exporting driver.
2306 @param[out] ActionRequest On return, points to the action requested by the
2307 callback function.
2308
2309 @retval EFI_SUCCESS The callback successfully handled the action.
2310 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
2311 variable and its data.
2312 @retval EFI_DEVICE_ERROR The variable could not be saved.
2313 @retval EFI_UNSUPPORTED The specified Action is not supported by the
2314 callback.Currently not implemented.
2315 @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
2316 @retval Others Other errors as indicated.
2317 **/
2318 EFI_STATUS
2319 EFIAPI
2320 HddPasswordFormCallback (
2321 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
2322 IN EFI_BROWSER_ACTION Action,
2323 IN EFI_QUESTION_ID QuestionId,
2324 IN UINT8 Type,
2325 IN EFI_IFR_TYPE_VALUE *Value,
2326 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
2327 )
2328 {
2329 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;
2330 EFI_STRING_ID DeviceFormTitleToken;
2331 HDD_PASSWORD_CONFIG *IfrData;
2332 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;
2333
2334 if (ActionRequest != NULL) {
2335 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2336 } else {
2337 return EFI_INVALID_PARAMETER;
2338 }
2339
2340 if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
2341 //
2342 // Do nothing for other UEFI Action. Only do call back when data is changing or changed.
2343 //
2344 return EFI_UNSUPPORTED;
2345 }
2346
2347 Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);
2348
2349 //
2350 // Retrive data from Browser
2351 //
2352 IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));
2353 ASSERT (IfrData != NULL);
2354 if (!HiiGetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *)IfrData)) {
2355 FreePool (IfrData);
2356 return EFI_NOT_FOUND;
2357 }
2358
2359 switch (QuestionId) {
2360 case KEY_HDD_USER_PASSWORD:
2361 if (Action == EFI_BROWSER_ACTION_CHANGED) {
2362 DEBUG ((DEBUG_INFO, "KEY_HDD_USER_PASSWORD\n"));
2363 ConfigFormEntry = Private->Current;
2364 ConfigFormEntry->IfrData.Request.UserPassword = Value->b;
2365 SaveHddPasswordRequest (ConfigFormEntry);
2366 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
2367 }
2368
2369 break;
2370 case KEY_HDD_MASTER_PASSWORD:
2371 if (Action == EFI_BROWSER_ACTION_CHANGED) {
2372 DEBUG ((DEBUG_INFO, "KEY_HDD_MASTER_PASSWORD\n"));
2373 ConfigFormEntry = Private->Current;
2374 ConfigFormEntry->IfrData.Request.MasterPassword = Value->b;
2375 SaveHddPasswordRequest (ConfigFormEntry);
2376 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
2377 }
2378
2379 break;
2380
2381 default:
2382 if ((QuestionId >= KEY_HDD_DEVICE_ENTRY_BASE) && (QuestionId < (mNumberOfHddDevices + KEY_HDD_DEVICE_ENTRY_BASE))) {
2383 if (Action == EFI_BROWSER_ACTION_CHANGING) {
2384 //
2385 // In case goto the device configuration form, update the device form title.
2386 //
2387 ConfigFormEntry = HddPasswordGetConfigFormEntryByIndex ((UINT32)(QuestionId - KEY_HDD_DEVICE_ENTRY_BASE));
2388 ASSERT (ConfigFormEntry != NULL);
2389
2390 DeviceFormTitleToken = (EFI_STRING_ID)STR_HDD_SECURITY_HD;
2391 HiiSetString (Private->HiiHandle, DeviceFormTitleToken, ConfigFormEntry->HddString, NULL);
2392
2393 Private->Current = ConfigFormEntry;
2394 CopyMem (IfrData, &ConfigFormEntry->IfrData, sizeof (HDD_PASSWORD_CONFIG));
2395 }
2396 }
2397
2398 break;
2399 }
2400
2401 //
2402 // Pass changed uncommitted data back to Form Browser
2403 //
2404 HiiSetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *)IfrData, NULL);
2405
2406 FreePool (IfrData);
2407 return EFI_SUCCESS;
2408 }
2409
2410 /**
2411 Updates the HDD Password configuration form to add an entry for the attached
2412 ata harddisk device specified by the Controller.
2413
2414 @param[in] HiiHandle The HII Handle associated with the registered package list.
2415 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.
2416 @param[in] PciIo Pointer to PCI_IO instance.
2417 @param[in] Controller The controller handle of the attached ata controller.
2418 @param[in] Bus The bus number of ATA controller.
2419 @param[in] Device The device number of ATA controller.
2420 @param[in] Function The function number of ATA controller.
2421 @param[in] Port The port number of attached ATA device.
2422 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.
2423
2424 @retval EFI_SUCCESS The Hdd Password configuration form is updated.
2425 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
2426 @retval Others Other errors as indicated.
2427
2428 **/
2429 EFI_STATUS
2430 HddPasswordConfigUpdateForm (
2431 IN EFI_HII_HANDLE HiiHandle,
2432 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,
2433 IN EFI_PCI_IO_PROTOCOL *PciIo,
2434 IN EFI_HANDLE Controller,
2435 IN UINTN Bus,
2436 IN UINTN Device,
2437 IN UINTN Function,
2438 IN UINT16 Port,
2439 IN UINT16 PortMultiplierPort
2440 )
2441 {
2442 LIST_ENTRY *Entry;
2443 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;
2444 BOOLEAN EntryExisted;
2445 EFI_STATUS Status;
2446 VOID *StartOpCodeHandle;
2447 VOID *EndOpCodeHandle;
2448 EFI_IFR_GUID_LABEL *StartLabel;
2449 EFI_IFR_GUID_LABEL *EndLabel;
2450 CHAR16 HddString[40];
2451 ATA_IDENTIFY_DATA IdentifyData;
2452 EFI_DEVICE_PATH_PROTOCOL *AtaDeviceNode;
2453
2454 ConfigFormEntry = NULL;
2455 EntryExisted = FALSE;
2456
2457 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
2458 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
2459
2460 if ((ConfigFormEntry->Bus == Bus) &&
2461 (ConfigFormEntry->Device == Device) &&
2462 (ConfigFormEntry->Function == Function) &&
2463 (ConfigFormEntry->Port == Port) &&
2464 (ConfigFormEntry->PortMultiplierPort == PortMultiplierPort))
2465 {
2466 EntryExisted = TRUE;
2467 break;
2468 }
2469 }
2470
2471 if (!EntryExisted) {
2472 //
2473 // Add a new form.
2474 //
2475 ConfigFormEntry = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG_FORM_ENTRY));
2476 if (ConfigFormEntry == NULL) {
2477 return EFI_OUT_OF_RESOURCES;
2478 }
2479
2480 InitializeListHead (&ConfigFormEntry->Link);
2481 ConfigFormEntry->Controller = Controller;
2482 ConfigFormEntry->Bus = Bus;
2483 ConfigFormEntry->Device = Device;
2484 ConfigFormEntry->Function = Function;
2485 ConfigFormEntry->Port = Port;
2486 ConfigFormEntry->PortMultiplierPort = PortMultiplierPort;
2487 ConfigFormEntry->AtaPassThru = AtaPassThru;
2488
2489 DEBUG ((DEBUG_INFO, "HddPasswordDxe: Create new form for device[%d][%d] at Bus 0x%x Dev 0x%x Func 0x%x\n", Port, PortMultiplierPort, Bus, Device, Function));
2490
2491 //
2492 // Construct the device path for the HDD password device
2493 //
2494 Status = AtaPassThru->BuildDevicePath (
2495 AtaPassThru,
2496 Port,
2497 PortMultiplierPort,
2498 &AtaDeviceNode
2499 );
2500 if (EFI_ERROR (Status)) {
2501 return Status;
2502 }
2503
2504 ConfigFormEntry->DevicePath = AppendDevicePathNode (DevicePathFromHandle (Controller), AtaDeviceNode);
2505 FreePool (AtaDeviceNode);
2506 if (ConfigFormEntry->DevicePath == NULL) {
2507 return EFI_OUT_OF_RESOURCES;
2508 }
2509
2510 //
2511 // Get attached harddisk model number
2512 //
2513 Status = GetHddDeviceIdentifyData (AtaPassThru, Port, PortMultiplierPort, &IdentifyData);
2514 ASSERT_EFI_ERROR (Status);
2515 if (EFI_ERROR (Status)) {
2516 return Status;
2517 }
2518
2519 GetHddDeviceModelNumber (&IdentifyData, HddString);
2520 //
2521 // Compose the HDD title string and help string of this port and create a new EFI_STRING_ID.
2522 //
2523 UnicodeSPrint (ConfigFormEntry->HddString, sizeof (ConfigFormEntry->HddString), L"HDD %d:%s", mNumberOfHddDevices, HddString);
2524 ConfigFormEntry->TitleToken = HiiSetString (HiiHandle, 0, ConfigFormEntry->HddString, NULL);
2525 ConfigFormEntry->TitleHelpToken = HiiSetString (HiiHandle, 0, L"Request to set HDD Password", NULL);
2526
2527 GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);
2528
2529 InsertTailList (&mHddPasswordConfigFormList, &ConfigFormEntry->Link);
2530
2531 //
2532 // Init OpCode Handle
2533 //
2534 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
2535 ASSERT (StartOpCodeHandle != NULL);
2536
2537 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
2538 ASSERT (EndOpCodeHandle != NULL);
2539
2540 //
2541 // Create Hii Extend Label OpCode as the start opcode
2542 //
2543 StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
2544 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
2545 StartLabel->Number = HDD_DEVICE_ENTRY_LABEL;
2546
2547 //
2548 // Create Hii Extend Label OpCode as the end opcode
2549 //
2550 EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
2551 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
2552 EndLabel->Number = HDD_DEVICE_LABEL_END;
2553
2554 mNumberOfHddDevices = 0;
2555 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
2556 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
2557
2558 HiiCreateGotoOpCode (
2559 StartOpCodeHandle, // Container for dynamic created opcodes
2560 FORMID_HDD_DEVICE_FORM, // Target Form ID
2561 ConfigFormEntry->TitleToken, // Prompt text
2562 ConfigFormEntry->TitleHelpToken, // Help text
2563 EFI_IFR_FLAG_CALLBACK, // Question flag
2564 (UINT16)(KEY_HDD_DEVICE_ENTRY_BASE + mNumberOfHddDevices) // Question ID
2565 );
2566
2567 mNumberOfHddDevices++;
2568 }
2569
2570 HiiUpdateForm (
2571 HiiHandle,
2572 &mHddPasswordVendorGuid,
2573 FORMID_HDD_MAIN_FORM,
2574 StartOpCodeHandle,
2575 EndOpCodeHandle
2576 );
2577
2578 HiiFreeOpCodeHandle (StartOpCodeHandle);
2579 HiiFreeOpCodeHandle (EndOpCodeHandle);
2580
2581 //
2582 // Check if device is locked and prompt for password.
2583 //
2584 HddPasswordRequestPassword (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);
2585
2586 //
2587 // Process HDD password request from last boot.
2588 //
2589 ProcessHddPasswordRequest (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);
2590 }
2591
2592 return EFI_SUCCESS;
2593 }
2594
2595 /**
2596 Ata Pass Thru Protocol notification event handler.
2597
2598 Check attached harddisk status to see if it's locked. If yes, then pop up a password windows to require user input.
2599 It also registers a form for user configuration on Hdd password configuration.
2600
2601 @param[in] Event Event whose notification function is being invoked.
2602 @param[in] Context Pointer to the notification function's context.
2603
2604 **/
2605 VOID
2606 EFIAPI
2607 HddPasswordNotificationEvent (
2608 IN EFI_EVENT Event,
2609 IN VOID *Context
2610 )
2611 {
2612 EFI_STATUS Status;
2613 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;
2614 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
2615 UINT16 Port;
2616 UINT16 PortMultiplierPort;
2617 EFI_HANDLE Controller;
2618 EFI_HANDLE *HandleBuffer;
2619 UINTN HandleCount;
2620 UINTN Index;
2621 EFI_PCI_IO_PROTOCOL *PciIo;
2622 UINTN SegNum;
2623 UINTN BusNum;
2624 UINTN DevNum;
2625 UINTN FuncNum;
2626
2627 if (mHddPasswordEndOfDxe) {
2628 gBS->CloseEvent (Event);
2629 return;
2630 }
2631
2632 Private = (HDD_PASSWORD_DXE_PRIVATE_DATA *)Context;
2633
2634 //
2635 // Locate all handles of AtaPassThru protocol
2636 //
2637 Status = gBS->LocateHandleBuffer (
2638 ByProtocol,
2639 &gEfiAtaPassThruProtocolGuid,
2640 NULL,
2641 &HandleCount,
2642 &HandleBuffer
2643 );
2644 if (EFI_ERROR (Status)) {
2645 return;
2646 }
2647
2648 //
2649 // Check attached hard disk status to see if it's locked
2650 //
2651 for (Index = 0; Index < HandleCount; Index += 1) {
2652 Controller = HandleBuffer[Index];
2653 Status = gBS->HandleProtocol (
2654 Controller,
2655 &gEfiAtaPassThruProtocolGuid,
2656 (VOID **)&AtaPassThru
2657 );
2658 if (EFI_ERROR (Status)) {
2659 break;
2660 }
2661
2662 //
2663 // Ignore those logical ATA_PASS_THRU instance.
2664 //
2665 if ((AtaPassThru->Mode->Attributes & EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL) == 0) {
2666 continue;
2667 }
2668
2669 Status = gBS->HandleProtocol (
2670 Controller,
2671 &gEfiPciIoProtocolGuid,
2672 (VOID **)&PciIo
2673 );
2674 ASSERT_EFI_ERROR (Status);
2675 if (EFI_ERROR (Status)) {
2676 break;
2677 }
2678
2679 Status = PciIo->GetLocation (
2680 PciIo,
2681 &SegNum,
2682 &BusNum,
2683 &DevNum,
2684 &FuncNum
2685 );
2686 ASSERT_EFI_ERROR (Status);
2687 if (EFI_ERROR (Status)) {
2688 break;
2689 }
2690
2691 //
2692 // Assume and only support Segment == 0.
2693 //
2694 ASSERT (SegNum == 0);
2695
2696 //
2697 // traverse all attached harddisk devices to update form and unlock it
2698 //
2699 Port = 0xFFFF;
2700
2701 while (TRUE) {
2702 Status = AtaPassThru->GetNextPort (AtaPassThru, &Port);
2703 if (EFI_ERROR (Status)) {
2704 //
2705 // We cannot find more legal port then we are done.
2706 //
2707 break;
2708 }
2709
2710 PortMultiplierPort = 0xFFFF;
2711 while (TRUE) {
2712 Status = AtaPassThru->GetNextDevice (AtaPassThru, Port, &PortMultiplierPort);
2713 if (EFI_ERROR (Status)) {
2714 //
2715 // We cannot find more legal port multiplier port number for ATA device
2716 // on the port, then we are done.
2717 //
2718 break;
2719 }
2720
2721 //
2722 // Find out the attached harddisk devices.
2723 // Try to add a HDD Password configuration page for the attached devices.
2724 //
2725 gBS->RestoreTPL (TPL_APPLICATION);
2726 Status = HddPasswordConfigUpdateForm (Private->HiiHandle, AtaPassThru, PciIo, Controller, BusNum, DevNum, FuncNum, Port, PortMultiplierPort);
2727 gBS->RaiseTPL (TPL_CALLBACK);
2728 if (EFI_ERROR (Status)) {
2729 break;
2730 }
2731 }
2732 }
2733 }
2734
2735 FreePool (HandleBuffer);
2736 return;
2737 }
2738
2739 /**
2740 Initialize the HDD Password configuration form.
2741
2742 @param[out] Instance Pointer to private instance.
2743
2744 @retval EFI_SUCCESS The HDD Password configuration form is initialized.
2745 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
2746 @retval Others Other errors as indicated.
2747 **/
2748 EFI_STATUS
2749 HddPasswordConfigFormInit (
2750 OUT HDD_PASSWORD_DXE_PRIVATE_DATA **Instance
2751 )
2752 {
2753 EFI_STATUS Status;
2754 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;
2755
2756 InitializeListHead (&mHddPasswordConfigFormList);
2757
2758 Private = AllocateZeroPool (sizeof (HDD_PASSWORD_DXE_PRIVATE_DATA));
2759 if (Private == NULL) {
2760 return EFI_OUT_OF_RESOURCES;
2761 }
2762
2763 Private->Signature = HDD_PASSWORD_DXE_PRIVATE_SIGNATURE;
2764
2765 Private->ConfigAccess.ExtractConfig = HddPasswordFormExtractConfig;
2766 Private->ConfigAccess.RouteConfig = HddPasswordFormRouteConfig;
2767 Private->ConfigAccess.Callback = HddPasswordFormCallback;
2768
2769 //
2770 // Install Device Path Protocol and Config Access protocol to driver handle
2771 //
2772 Status = gBS->InstallMultipleProtocolInterfaces (
2773 &Private->DriverHandle,
2774 &gEfiDevicePathProtocolGuid,
2775 &mHddPasswordHiiVendorDevicePath,
2776 &gEfiHiiConfigAccessProtocolGuid,
2777 &Private->ConfigAccess,
2778 NULL
2779 );
2780 ASSERT_EFI_ERROR (Status);
2781 if (EFI_ERROR (Status)) {
2782 FreePool (Private);
2783 return Status;
2784 }
2785
2786 //
2787 // Publish our HII data
2788 //
2789 Private->HiiHandle = HiiAddPackages (
2790 &mHddPasswordVendorGuid,
2791 Private->DriverHandle,
2792 HddPasswordDxeStrings,
2793 HddPasswordBin,
2794 NULL
2795 );
2796 if (Private->HiiHandle == NULL) {
2797 FreePool (Private);
2798 return EFI_OUT_OF_RESOURCES;
2799 }
2800
2801 *Instance = Private;
2802 return Status;
2803 }
2804
2805 /**
2806 Main entry for this driver.
2807
2808 @param ImageHandle Image handle this driver.
2809 @param SystemTable Pointer to SystemTable.
2810
2811 @retval EFI_SUCCESS This function always complete successfully.
2812
2813 **/
2814 EFI_STATUS
2815 EFIAPI
2816 HddPasswordDxeInit (
2817 IN EFI_HANDLE ImageHandle,
2818 IN EFI_SYSTEM_TABLE *SystemTable
2819 )
2820 {
2821 EFI_STATUS Status;
2822 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;
2823 VOID *Registration;
2824 EFI_EVENT EndOfDxeEvent;
2825 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
2826
2827 Private = NULL;
2828
2829 //
2830 // Initialize the configuration form of HDD Password.
2831 //
2832 Status = HddPasswordConfigFormInit (&Private);
2833 if (EFI_ERROR (Status)) {
2834 return Status;
2835 }
2836
2837 //
2838 // Register HddPasswordNotificationEvent() notify function.
2839 //
2840 EfiCreateProtocolNotifyEvent (
2841 &gEfiAtaPassThruProtocolGuid,
2842 TPL_CALLBACK,
2843 HddPasswordNotificationEvent,
2844 (VOID *)Private,
2845 &Registration
2846 );
2847
2848 Status = gBS->CreateEventEx (
2849 EVT_NOTIFY_SIGNAL,
2850 TPL_CALLBACK,
2851 HddPasswordEndOfDxeEventNotify,
2852 NULL,
2853 &gEfiEndOfDxeEventGroupGuid,
2854 &EndOfDxeEvent
2855 );
2856 ASSERT_EFI_ERROR (Status);
2857
2858 //
2859 // Make HDD_PASSWORD_VARIABLE_NAME variable read-only.
2860 //
2861 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
2862 if (!EFI_ERROR (Status)) {
2863 Status = VariableLock->RequestToLock (
2864 VariableLock,
2865 HDD_PASSWORD_VARIABLE_NAME,
2866 &mHddPasswordVendorGuid
2867 );
2868 DEBUG ((DEBUG_INFO, "%a(): Lock %s variable (%r)\n", __FUNCTION__, HDD_PASSWORD_VARIABLE_NAME, Status));
2869 ASSERT_EFI_ERROR (Status);
2870 }
2871
2872 return Status;
2873 }