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