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