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