965205c0b22447f46a6070018eed23a04379f0d5
[mirror_edk2.git] / SecurityPkg / Tcg / Opal / OpalPassword / OpalDriver.c
1 /** @file\r
2   Entrypoint of Opal UEFI Driver and contains all the logic to\r
3   register for new Opal device instances.\r
4 \r
5 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7 \r
8 **/\r
9 \r
10 // This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances and installs an\r
11 // HII GUI to manage Opal features if the device is Opal capable\r
12 // If the Opal device is being managed by the UEFI Driver, it shall provide a popup\r
13 // window during boot requesting a user password\r
14 \r
15 #include "OpalDriver.h"\r
16 #include "OpalHii.h"\r
17 \r
18 EFI_GUID mOpalDeviceLockBoxGuid = OPAL_DEVICE_LOCKBOX_GUID;\r
19 \r
20 BOOLEAN                 mOpalEndOfDxe = FALSE;\r
21 OPAL_REQUEST_VARIABLE   *mOpalRequestVariable = NULL;\r
22 UINTN                   mOpalRequestVariableSize = 0;\r
23 CHAR16                  mPopUpString[100];\r
24 \r
25 OPAL_DRIVER mOpalDriver;\r
26 \r
27 //\r
28 // Globals\r
29 //\r
30 EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = {\r
31   OpalEfiDriverBindingSupported,\r
32   OpalEfiDriverBindingStart,\r
33   OpalEfiDriverBindingStop,\r
34   0x1b,\r
35   NULL,\r
36   NULL\r
37 };\r
38 \r
39 /**\r
40 \r
41   The function determines the available actions for the OPAL_DISK provided.\r
42 \r
43   @param[in]   SupportedAttributes   The supported attributes for the device.\r
44   @param[in]   LockingFeature        The locking status for the device.\r
45   @param[in]   OwnerShip             The ownership for the device.\r
46   @param[out]  AvalDiskActions       Pointer to fill-out with appropriate disk actions.\r
47 \r
48 **/\r
49 TCG_RESULT\r
50 EFIAPI\r
51 OpalSupportGetAvailableActions(\r
52   IN  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes,\r
53   IN  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature,\r
54   IN  UINT16                           OwnerShip,\r
55   OUT OPAL_DISK_ACTIONS                *AvalDiskActions\r
56   )\r
57 {\r
58   BOOLEAN ExistingPassword;\r
59 \r
60   NULL_CHECK(AvalDiskActions);\r
61 \r
62   AvalDiskActions->AdminPass = 1;\r
63   AvalDiskActions->UserPass = 0;\r
64   AvalDiskActions->DisableUser = 0;\r
65   AvalDiskActions->Unlock = 0;\r
66 \r
67   //\r
68   // Revert is performed on locking sp, so only allow if locking sp is enabled\r
69   //\r
70   if (LockingFeature->LockingEnabled) {\r
71     AvalDiskActions->Revert = 1;\r
72   }\r
73 \r
74   //\r
75   // Psid revert is available for any device with media encryption support or pyrite 2.0 type support.\r
76   //\r
77   if (SupportedAttributes->PyriteSscV2 || SupportedAttributes->MediaEncryption) {\r
78 \r
79     //\r
80     // Only allow psid revert if media encryption is enabled or pyrite 2.0 type support..\r
81     // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still\r
82     // intact and accessible\r
83     //\r
84     AvalDiskActions->PsidRevert = 1;\r
85     AvalDiskActions->RevertKeepDataForced = 0;\r
86 \r
87     //\r
88     // Secure erase is performed by generating a new encryption key\r
89     // this is only available if encryption is supported\r
90     //\r
91     AvalDiskActions->SecureErase = 1;\r
92   } else {\r
93     AvalDiskActions->PsidRevert = 0;\r
94     AvalDiskActions->SecureErase = 0;\r
95 \r
96     //\r
97     // If no media encryption is supported, then a revert (using password) will not\r
98     // erase the Data (since you can't generate a new encryption key)\r
99     //\r
100     AvalDiskActions->RevertKeepDataForced = 1;\r
101   }\r
102 \r
103   if (LockingFeature->Locked) {\r
104     AvalDiskActions->Unlock = 1;\r
105   } else {\r
106     AvalDiskActions->Unlock = 0;\r
107   }\r
108 \r
109   //\r
110   // Only allow user to set password if an admin password exists\r
111   //\r
112   ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip, LockingFeature);\r
113   AvalDiskActions->UserPass = ExistingPassword;\r
114 \r
115   //\r
116   // This will still show up even if there isn't a user, which is fine\r
117   //\r
118   AvalDiskActions->DisableUser = ExistingPassword;\r
119 \r
120   return TcgResultSuccess;\r
121 }\r
122 \r
123 /**\r
124   Enable Opal Feature for the input device.\r
125 \r
126   @param[in]      Session            The opal session for the opal device.\r
127   @param[in]      Msid               Msid\r
128   @param[in]      MsidLength         Msid Length\r
129   @param[in]      Password           Admin password\r
130   @param[in]      PassLength         Length of password in bytes\r
131 \r
132 **/\r
133 TCG_RESULT\r
134 EFIAPI\r
135 OpalSupportEnableOpalFeature (\r
136   IN OPAL_SESSION              *Session,\r
137   IN VOID                      *Msid,\r
138   IN UINT32                    MsidLength,\r
139   IN VOID                      *Password,\r
140   IN UINT32                    PassLength\r
141   )\r
142 {\r
143   TCG_RESULT   Ret;\r
144 \r
145   NULL_CHECK(Session);\r
146   NULL_CHECK(Msid);\r
147   NULL_CHECK(Password);\r
148 \r
149   Ret = OpalUtilSetAdminPasswordAsSid(\r
150                           Session,\r
151                           Msid,\r
152                           MsidLength,\r
153                           Password,\r
154                           PassLength\r
155                           );\r
156   if (Ret == TcgResultSuccess) {\r
157     //\r
158     // Enable global locking range\r
159     //\r
160     Ret = OpalUtilSetOpalLockingRange(\r
161                               Session,\r
162                               Password,\r
163                               PassLength,\r
164                               OPAL_LOCKING_SP_LOCKING_GLOBALRANGE,\r
165                               0,\r
166                               0,\r
167                               TRUE,\r
168                               TRUE,\r
169                               FALSE,\r
170                               FALSE\r
171                               );\r
172   }\r
173 \r
174   return Ret;\r
175 }\r
176 \r
177 /**\r
178   Update password for the Opal disk.\r
179 \r
180   @param[in, out] OpalDisk          The disk to update password.\r
181   @param[in]      Password          The input password.\r
182   @param[in]      PasswordLength    The input password length.\r
183 \r
184 **/\r
185 VOID\r
186 OpalSupportUpdatePassword (\r
187   IN OUT OPAL_DISK      *OpalDisk,\r
188   IN VOID               *Password,\r
189   IN UINT32             PasswordLength\r
190   )\r
191 {\r
192   CopyMem (OpalDisk->Password, Password, PasswordLength);\r
193   OpalDisk->PasswordLength = (UINT8) PasswordLength;\r
194 }\r
195 \r
196 /**\r
197   Extract device info from the device path.\r
198 \r
199   @param[in]  DevicePath        Device path info for the device.\r
200   @param[out] DevInfoLength     Device information length needed.\r
201   @param[out] DevInfo           Device information extracted.\r
202 \r
203 **/\r
204 VOID\r
205 ExtractDeviceInfoFromDevicePath (\r
206   IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
207   OUT UINT32                    *DevInfoLength,\r
208   OUT OPAL_DEVICE_LOCKBOX_DATA  *DevInfo OPTIONAL\r
209   )\r
210 {\r
211   EFI_DEVICE_PATH_PROTOCOL      *TmpDevPath;\r
212   EFI_DEVICE_PATH_PROTOCOL      *TmpDevPath2;\r
213   PCI_DEVICE_PATH               *PciDevPath;\r
214   UINT8                         DeviceType;\r
215   UINT8                         BusNum;\r
216   OPAL_PCI_DEVICE               *PciDevice;\r
217 \r
218   ASSERT (DevicePath != NULL);\r
219   ASSERT (DevInfoLength != NULL);\r
220 \r
221   DeviceType = OPAL_DEVICE_TYPE_UNKNOWN;\r
222   *DevInfoLength = 0;\r
223 \r
224   TmpDevPath = DevicePath;\r
225 \r
226   //\r
227   // Get device type.\r
228   //\r
229   while (!IsDevicePathEnd (TmpDevPath)) {\r
230     if ((TmpDevPath->Type == MESSAGING_DEVICE_PATH) &&\r
231         (TmpDevPath->SubType == MSG_SATA_DP || TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP)) {\r
232       if (DevInfo != NULL) {\r
233         DevInfo->DevicePathLength = (UINT32) GetDevicePathSize (DevicePath);\r
234         CopyMem (DevInfo->DevicePath, DevicePath, DevInfo->DevicePathLength);\r
235       }\r
236 \r
237       DeviceType = (TmpDevPath->SubType == MSG_SATA_DP) ? OPAL_DEVICE_TYPE_ATA : OPAL_DEVICE_TYPE_NVME;\r
238       *DevInfoLength = sizeof (OPAL_DEVICE_LOCKBOX_DATA) + (UINT32) GetDevicePathSize (DevicePath);\r
239       break;\r
240     }\r
241     TmpDevPath = NextDevicePathNode (TmpDevPath);\r
242   }\r
243 \r
244   //\r
245   // Get device info.\r
246   //\r
247   BusNum = 0;\r
248   TmpDevPath = DevicePath;\r
249   TmpDevPath2 = NextDevicePathNode (DevicePath);\r
250   while (!IsDevicePathEnd (TmpDevPath2)) {\r
251     if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) {\r
252       PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath;\r
253       if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH) &&\r
254           (TmpDevPath2->SubType == MSG_SATA_DP || TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)) {\r
255         if (DevInfo != NULL) {\r
256           PciDevice = &DevInfo->Device;\r
257           PciDevice->Segment = 0;\r
258           PciDevice->Bus = BusNum;\r
259           PciDevice->Device = PciDevPath->Device;\r
260           PciDevice->Function = PciDevPath->Function;\r
261         }\r
262       } else {\r
263         if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) {\r
264           BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
265         }\r
266       }\r
267     }\r
268 \r
269     TmpDevPath  = NextDevicePathNode (TmpDevPath);\r
270     TmpDevPath2 = NextDevicePathNode (TmpDevPath2);\r
271   }\r
272 \r
273   ASSERT (DeviceType != OPAL_DEVICE_TYPE_UNKNOWN);\r
274   return;\r
275 }\r
276 \r
277 /**\r
278   Build OPAL device info and save them to LockBox.\r
279 \r
280  **/\r
281 VOID\r
282 BuildOpalDeviceInfo (\r
283   VOID\r
284   )\r
285 {\r
286   EFI_STATUS                  Status;\r
287   OPAL_DEVICE_LOCKBOX_DATA    *DevInfo;\r
288   OPAL_DEVICE_LOCKBOX_DATA    *TempDevInfo;\r
289   UINTN                       TotalDevInfoLength;\r
290   UINT32                      DevInfoLength;\r
291   OPAL_DRIVER_DEVICE          *TmpDev;\r
292   UINT8                       DummyData;\r
293   BOOLEAN                     S3InitDevicesExist;\r
294   UINTN                       S3InitDevicesLength;\r
295   EFI_DEVICE_PATH_PROTOCOL    *S3InitDevices;\r
296   EFI_DEVICE_PATH_PROTOCOL    *S3InitDevicesBak;\r
297 \r
298   //\r
299   // Build OPAL device info and save them to LockBox.\r
300   //\r
301   TotalDevInfoLength = 0;\r
302   TmpDev = mOpalDriver.DeviceList;\r
303   while (TmpDev != NULL) {\r
304     ExtractDeviceInfoFromDevicePath (\r
305       TmpDev->OpalDisk.OpalDevicePath,\r
306       &DevInfoLength,\r
307       NULL\r
308       );\r
309     TotalDevInfoLength += DevInfoLength;\r
310     TmpDev = TmpDev->Next;\r
311   }\r
312 \r
313   if (TotalDevInfoLength == 0) {\r
314     return;\r
315   }\r
316 \r
317   S3InitDevicesLength = sizeof (DummyData);\r
318   Status = RestoreLockBox (\r
319              &gS3StorageDeviceInitListGuid,\r
320              &DummyData,\r
321              &S3InitDevicesLength\r
322              );\r
323   ASSERT ((Status == EFI_NOT_FOUND) || (Status == EFI_BUFFER_TOO_SMALL));\r
324   if (Status == EFI_NOT_FOUND) {\r
325     S3InitDevices      = NULL;\r
326     S3InitDevicesExist = FALSE;\r
327   } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
328     S3InitDevices = AllocatePool (S3InitDevicesLength);\r
329     ASSERT (S3InitDevices != NULL);\r
330     if (S3InitDevices == NULL) {\r
331       return;\r
332     }\r
333 \r
334     Status = RestoreLockBox (\r
335                &gS3StorageDeviceInitListGuid,\r
336                S3InitDevices,\r
337                &S3InitDevicesLength\r
338                );\r
339     ASSERT_EFI_ERROR (Status);\r
340     S3InitDevicesExist = TRUE;\r
341   } else {\r
342     return;\r
343   }\r
344 \r
345   DevInfo = AllocateZeroPool (TotalDevInfoLength);\r
346   ASSERT (DevInfo != NULL);\r
347   if (DevInfo == NULL) {\r
348     return;\r
349   }\r
350 \r
351   TempDevInfo = DevInfo;\r
352   TmpDev      = mOpalDriver.DeviceList;\r
353   while (TmpDev != NULL) {\r
354     ExtractDeviceInfoFromDevicePath (\r
355       TmpDev->OpalDisk.OpalDevicePath,\r
356       &DevInfoLength,\r
357       TempDevInfo\r
358       );\r
359     TempDevInfo->Length = DevInfoLength;\r
360     TempDevInfo->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId;\r
361     CopyMem (\r
362       TempDevInfo->Password,\r
363       TmpDev->OpalDisk.Password,\r
364       TmpDev->OpalDisk.PasswordLength\r
365       );\r
366     TempDevInfo->PasswordLength = TmpDev->OpalDisk.PasswordLength;\r
367 \r
368     S3InitDevicesBak = S3InitDevices;\r
369     S3InitDevices    = AppendDevicePathInstance (\r
370                          S3InitDevicesBak,\r
371                          TmpDev->OpalDisk.OpalDevicePath\r
372                          );\r
373     if (S3InitDevicesBak != NULL) {\r
374       FreePool (S3InitDevicesBak);\r
375     }\r
376     ASSERT (S3InitDevices != NULL);\r
377     if (S3InitDevices == NULL) {\r
378       return;\r
379     }\r
380 \r
381     TempDevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) ((UINTN) TempDevInfo + DevInfoLength);\r
382     TmpDev = TmpDev->Next;\r
383   }\r
384 \r
385   Status = SaveLockBox (\r
386              &mOpalDeviceLockBoxGuid,\r
387              DevInfo,\r
388              TotalDevInfoLength\r
389              );\r
390   ASSERT_EFI_ERROR (Status);\r
391 \r
392   Status = SetLockBoxAttributes (\r
393              &mOpalDeviceLockBoxGuid,\r
394              LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
395              );\r
396   ASSERT_EFI_ERROR (Status);\r
397 \r
398   S3InitDevicesLength = GetDevicePathSize (S3InitDevices);\r
399   if (S3InitDevicesExist) {\r
400     Status = UpdateLockBox (\r
401                &gS3StorageDeviceInitListGuid,\r
402                0,\r
403                S3InitDevices,\r
404                S3InitDevicesLength\r
405                );\r
406     ASSERT_EFI_ERROR (Status);\r
407   } else {\r
408     Status = SaveLockBox (\r
409                &gS3StorageDeviceInitListGuid,\r
410                S3InitDevices,\r
411                S3InitDevicesLength\r
412                );\r
413     ASSERT_EFI_ERROR (Status);\r
414 \r
415     Status = SetLockBoxAttributes (\r
416                &gS3StorageDeviceInitListGuid,\r
417                LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
418                );\r
419     ASSERT_EFI_ERROR (Status);\r
420   }\r
421 \r
422   ZeroMem (DevInfo, TotalDevInfoLength);\r
423   FreePool (DevInfo);\r
424   FreePool (S3InitDevices);\r
425 }\r
426 \r
427 /**\r
428 \r
429   Send BlockSid command if needed.\r
430 \r
431 **/\r
432 VOID\r
433 SendBlockSidCommand (\r
434   VOID\r
435   )\r
436 {\r
437   OPAL_DRIVER_DEVICE                         *Itr;\r
438   TCG_RESULT                                 Result;\r
439   OPAL_SESSION                               Session;\r
440   UINT32                                     PpStorageFlag;\r
441 \r
442   PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();\r
443   if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {\r
444     //\r
445     // Send BlockSID command to each Opal disk\r
446     //\r
447     Itr = mOpalDriver.DeviceList;\r
448     while (Itr != NULL) {\r
449       if (Itr->OpalDisk.SupportedAttributes.BlockSid) {\r
450         ZeroMem(&Session, sizeof(Session));\r
451         Session.Sscp = Itr->OpalDisk.Sscp;\r
452         Session.MediaId = Itr->OpalDisk.MediaId;\r
453         Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId;\r
454 \r
455         DEBUG ((DEBUG_INFO, "OpalPassword: EndOfDxe point, send BlockSid command to device!\n"));\r
456         Result = OpalBlockSid (&Session, TRUE);  // HardwareReset must always be TRUE\r
457         if (Result != TcgResultSuccess) {\r
458           DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n"));\r
459           break;\r
460         }\r
461 \r
462         //\r
463         // Record BlockSID command has been sent.\r
464         //\r
465         Itr->OpalDisk.SentBlockSID = TRUE;\r
466       }\r
467 \r
468       Itr = Itr->Next;\r
469     }\r
470   }\r
471 }\r
472 \r
473 /**\r
474   Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
475 \r
476   This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
477 \r
478   @param  Event        Event whose notification function is being invoked.\r
479   @param  Context      Pointer to the notification function's context.\r
480 \r
481 **/\r
482 VOID\r
483 EFIAPI\r
484 OpalEndOfDxeEventNotify (\r
485   EFI_EVENT                               Event,\r
486   VOID                                    *Context\r
487   )\r
488 {\r
489   OPAL_DRIVER_DEVICE    *TmpDev;\r
490 \r
491   DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
492 \r
493   mOpalEndOfDxe = TRUE;\r
494 \r
495   if (mOpalRequestVariable != NULL) {\r
496     //\r
497     // Free the OPAL request variable buffer here\r
498     // as the OPAL requests should have been processed.\r
499     //\r
500     FreePool (mOpalRequestVariable);\r
501     mOpalRequestVariable = NULL;\r
502     mOpalRequestVariableSize = 0;\r
503   }\r
504 \r
505   //\r
506   // If no any device, return directly.\r
507   //\r
508   if (mOpalDriver.DeviceList == NULL) {\r
509     gBS->CloseEvent (Event);\r
510     return;\r
511   }\r
512 \r
513   BuildOpalDeviceInfo ();\r
514 \r
515   //\r
516   // Zero passsword.\r
517   //\r
518   TmpDev = mOpalDriver.DeviceList;\r
519   while (TmpDev != NULL) {\r
520     ZeroMem (TmpDev->OpalDisk.Password, TmpDev->OpalDisk.PasswordLength);\r
521     TmpDev = TmpDev->Next;\r
522   }\r
523 \r
524   //\r
525   // Send BlockSid command if needed.\r
526   //\r
527   SendBlockSidCommand ();\r
528 \r
529   DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
530 \r
531   gBS->CloseEvent (Event);\r
532 }\r
533 \r
534 /**\r
535   Get Psid input from the popup window.\r
536 \r
537   @param[in]  Dev           The device which need Psid to process Psid Revert\r
538                             OPAL request.\r
539   @param[in]  PopUpString   Pop up string.\r
540   @param[in]  PopUpString2  Pop up string in line 2.\r
541   @param[in]  PopUpString3  Pop up string in line 3.\r
542 \r
543   @param[out] PressEsc      Whether user escape function through Press ESC.\r
544 \r
545   @retval Psid string if success. NULL if failed.\r
546 \r
547 **/\r
548 CHAR8 *\r
549 OpalDriverPopUpPsidInput (\r
550   IN OPAL_DRIVER_DEVICE     *Dev,\r
551   IN CHAR16                 *PopUpString,\r
552   IN CHAR16                 *PopUpString2,\r
553   IN CHAR16                 *PopUpString3,\r
554   OUT BOOLEAN               *PressEsc\r
555   )\r
556 {\r
557   EFI_INPUT_KEY             InputKey;\r
558   UINTN                     InputLength;\r
559   CHAR16                    Mask[PSID_CHARACTER_LENGTH + 1];\r
560   CHAR16                    Unicode[PSID_CHARACTER_LENGTH + 1];\r
561   CHAR8                     *Ascii;\r
562 \r
563   ZeroMem(Unicode, sizeof(Unicode));\r
564   ZeroMem(Mask, sizeof(Mask));\r
565 \r
566   *PressEsc = FALSE;\r
567 \r
568   gST->ConOut->ClearScreen(gST->ConOut);\r
569 \r
570   InputLength = 0;\r
571   while (TRUE) {\r
572     Mask[InputLength] = L'_';\r
573     if (PopUpString2 == NULL) {\r
574       CreatePopUp (\r
575         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
576         &InputKey,\r
577         PopUpString,\r
578         L"---------------------",\r
579         Mask,\r
580         NULL\r
581       );\r
582     } else {\r
583       if (PopUpString3 == NULL) {\r
584         CreatePopUp (\r
585           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
586           &InputKey,\r
587           PopUpString,\r
588           PopUpString2,\r
589           L"---------------------",\r
590           Mask,\r
591           NULL\r
592         );\r
593       } else {\r
594         CreatePopUp (\r
595           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
596           &InputKey,\r
597           PopUpString,\r
598           PopUpString2,\r
599           PopUpString3,\r
600           L"---------------------",\r
601           Mask,\r
602           NULL\r
603         );\r
604       }\r
605     }\r
606 \r
607     //\r
608     // Check key.\r
609     //\r
610     if (InputKey.ScanCode == SCAN_NULL) {\r
611       //\r
612       // password finished\r
613       //\r
614       if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
615         //\r
616         // Add the null terminator.\r
617         //\r
618         Unicode[InputLength] = 0;\r
619         Mask[InputLength] = 0;\r
620         break;\r
621       } else if ((InputKey.UnicodeChar == CHAR_NULL) ||\r
622                  (InputKey.UnicodeChar == CHAR_TAB) ||\r
623                  (InputKey.UnicodeChar == CHAR_LINEFEED)\r
624                 ) {\r
625         continue;\r
626       } else {\r
627         //\r
628         // delete last key entered\r
629         //\r
630         if (InputKey.UnicodeChar == CHAR_BACKSPACE) {\r
631           if (InputLength > 0) {\r
632             Unicode[InputLength] = 0;\r
633             Mask[InputLength] = 0;\r
634             InputLength--;\r
635           }\r
636         } else {\r
637           //\r
638           // add Next key entry\r
639           //\r
640           Unicode[InputLength] = InputKey.UnicodeChar;\r
641           Mask[InputLength] = InputKey.UnicodeChar;\r
642           InputLength++;\r
643           if (InputLength == PSID_CHARACTER_LENGTH) {\r
644             //\r
645             // Add the null terminator.\r
646             //\r
647             Unicode[InputLength] = 0;\r
648             Mask[InputLength] = 0;\r
649             break;\r
650           }\r
651         }\r
652       }\r
653     }\r
654 \r
655     //\r
656     // exit on ESC\r
657     //\r
658     if (InputKey.ScanCode == SCAN_ESC) {\r
659       *PressEsc = TRUE;\r
660       break;\r
661     }\r
662   }\r
663 \r
664   gST->ConOut->ClearScreen(gST->ConOut);\r
665 \r
666   if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {\r
667     ZeroMem (Unicode, sizeof (Unicode));\r
668     ZeroMem (Mask, sizeof (Mask));\r
669     return NULL;\r
670   }\r
671 \r
672   Ascii = AllocateZeroPool (PSID_CHARACTER_LENGTH + 1);\r
673   if (Ascii == NULL) {\r
674     ZeroMem (Unicode, sizeof (Unicode));\r
675     ZeroMem (Mask, sizeof (Mask));\r
676     return NULL;\r
677   }\r
678 \r
679   UnicodeStrToAsciiStrS (Unicode, Ascii, PSID_CHARACTER_LENGTH + 1);\r
680   ZeroMem (Unicode, sizeof (Unicode));\r
681   ZeroMem (Mask, sizeof (Mask));\r
682 \r
683   return Ascii;\r
684 }\r
685 \r
686 \r
687 /**\r
688   Get password input from the popup window.\r
689 \r
690   @param[in]  Dev           The device which need password to unlock or\r
691                             process OPAL request.\r
692   @param[in]  PopUpString1  Pop up string 1.\r
693   @param[in]  PopUpString2  Pop up string 2.\r
694   @param[in]  PopUpString3  Pop up string 3.\r
695   @param[out] PressEsc      Whether user escape function through Press ESC.\r
696 \r
697   @retval Password string if success. NULL if failed.\r
698 \r
699 **/\r
700 CHAR8 *\r
701 OpalDriverPopUpPasswordInput (\r
702   IN OPAL_DRIVER_DEVICE     *Dev,\r
703   IN CHAR16                 *PopUpString1,\r
704   IN CHAR16                 *PopUpString2,\r
705   IN CHAR16                 *PopUpString3,\r
706   OUT BOOLEAN               *PressEsc\r
707   )\r
708 {\r
709   EFI_INPUT_KEY             InputKey;\r
710   UINTN                     InputLength;\r
711   CHAR16                    Mask[OPAL_MAX_PASSWORD_SIZE + 1];\r
712   CHAR16                    Unicode[OPAL_MAX_PASSWORD_SIZE + 1];\r
713   CHAR8                     *Ascii;\r
714 \r
715   ZeroMem(Unicode, sizeof(Unicode));\r
716   ZeroMem(Mask, sizeof(Mask));\r
717 \r
718   *PressEsc = FALSE;\r
719 \r
720   gST->ConOut->ClearScreen(gST->ConOut);\r
721 \r
722   InputLength = 0;\r
723   while (TRUE) {\r
724     Mask[InputLength] = L'_';\r
725     if (PopUpString2 == NULL) {\r
726       CreatePopUp (\r
727         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
728         &InputKey,\r
729         PopUpString1,\r
730         L"---------------------",\r
731         Mask,\r
732         NULL\r
733       );\r
734     } else {\r
735       if (PopUpString3 == NULL) {\r
736         CreatePopUp (\r
737           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
738           &InputKey,\r
739           PopUpString1,\r
740           PopUpString2,\r
741           L"---------------------",\r
742           Mask,\r
743           NULL\r
744         );\r
745       } else {\r
746         CreatePopUp (\r
747           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
748           &InputKey,\r
749           PopUpString1,\r
750           PopUpString2,\r
751           PopUpString3,\r
752           L"---------------------",\r
753           Mask,\r
754           NULL\r
755         );\r
756       }\r
757     }\r
758 \r
759     //\r
760     // Check key.\r
761     //\r
762     if (InputKey.ScanCode == SCAN_NULL) {\r
763       //\r
764       // password finished\r
765       //\r
766       if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
767         //\r
768         // Add the null terminator.\r
769         //\r
770         Unicode[InputLength] = 0;\r
771         Mask[InputLength] = 0;\r
772         break;\r
773       } else if ((InputKey.UnicodeChar == CHAR_NULL) ||\r
774                  (InputKey.UnicodeChar == CHAR_TAB) ||\r
775                  (InputKey.UnicodeChar == CHAR_LINEFEED)\r
776                 ) {\r
777         continue;\r
778       } else {\r
779         //\r
780         // delete last key entered\r
781         //\r
782         if (InputKey.UnicodeChar == CHAR_BACKSPACE) {\r
783           if (InputLength > 0) {\r
784             Unicode[InputLength] = 0;\r
785             Mask[InputLength] = 0;\r
786             InputLength--;\r
787           }\r
788         } else {\r
789           //\r
790           // add Next key entry\r
791           //\r
792           Unicode[InputLength] = InputKey.UnicodeChar;\r
793           Mask[InputLength] = L'*';\r
794           InputLength++;\r
795           if (InputLength == OPAL_MAX_PASSWORD_SIZE) {\r
796             //\r
797             // Add the null terminator.\r
798             //\r
799             Unicode[InputLength] = 0;\r
800             Mask[InputLength] = 0;\r
801             break;\r
802           }\r
803         }\r
804       }\r
805     }\r
806 \r
807     //\r
808     // exit on ESC\r
809     //\r
810     if (InputKey.ScanCode == SCAN_ESC) {\r
811       *PressEsc = TRUE;\r
812       break;\r
813     }\r
814   }\r
815 \r
816   gST->ConOut->ClearScreen(gST->ConOut);\r
817 \r
818   if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {\r
819     ZeroMem (Unicode, sizeof (Unicode));\r
820     return NULL;\r
821   }\r
822 \r
823   Ascii = AllocateZeroPool (OPAL_MAX_PASSWORD_SIZE + 1);\r
824   if (Ascii == NULL) {\r
825     ZeroMem (Unicode, sizeof (Unicode));\r
826     return NULL;\r
827   }\r
828 \r
829   UnicodeStrToAsciiStrS (Unicode, Ascii, OPAL_MAX_PASSWORD_SIZE + 1);\r
830   ZeroMem (Unicode, sizeof (Unicode));\r
831 \r
832   return Ascii;\r
833 }\r
834 \r
835 /**\r
836   Get pop up string.\r
837 \r
838   @param[in] Dev            The OPAL device.\r
839   @param[in] RequestString  Request string.\r
840 \r
841   @return Pop up string.\r
842 \r
843 **/\r
844 CHAR16 *\r
845 OpalGetPopUpString (\r
846   IN OPAL_DRIVER_DEVICE *Dev,\r
847   IN CHAR16             *RequestString\r
848   )\r
849 {\r
850   if (Dev->Name16 == NULL) {\r
851     UnicodeSPrint (mPopUpString, sizeof (mPopUpString), L"%s Disk", RequestString);\r
852   } else {\r
853     UnicodeSPrint (mPopUpString, sizeof (mPopUpString), L"%s %s", RequestString, Dev->Name16);\r
854   }\r
855 \r
856   return mPopUpString;\r
857 }\r
858 \r
859 /**\r
860   Check if disk is locked, show popup window and ask for password if it is.\r
861 \r
862   @param[in] Dev            The device which need to be unlocked.\r
863   @param[in] RequestString  Request string.\r
864 \r
865 **/\r
866 VOID\r
867 OpalDriverRequestPassword (\r
868   IN OPAL_DRIVER_DEVICE *Dev,\r
869   IN CHAR16             *RequestString\r
870   )\r
871 {\r
872   UINT8                 Count;\r
873   BOOLEAN               IsEnabled;\r
874   BOOLEAN               IsLocked;\r
875   CHAR8                 *Password;\r
876   UINT32                PasswordLen;\r
877   OPAL_SESSION          Session;\r
878   BOOLEAN               PressEsc;\r
879   EFI_INPUT_KEY         Key;\r
880   TCG_RESULT            Ret;\r
881   CHAR16                *PopUpString;\r
882 \r
883   if (Dev == NULL) {\r
884     return;\r
885   }\r
886 \r
887   DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
888 \r
889   PopUpString = OpalGetPopUpString (Dev, RequestString);\r
890 \r
891   Count = 0;\r
892 \r
893   IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);\r
894   if (IsEnabled) {\r
895     ZeroMem(&Session, sizeof(Session));\r
896     Session.Sscp = Dev->OpalDisk.Sscp;\r
897     Session.MediaId = Dev->OpalDisk.MediaId;\r
898     Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
899 \r
900     IsLocked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);\r
901 \r
902     if (IsLocked && PcdGetBool (PcdSkipOpalDxeUnlock)) {\r
903       return;\r
904     }\r
905 \r
906     while (Count < MAX_PASSWORD_TRY_COUNT) {\r
907       Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, NULL, &PressEsc);\r
908       if (PressEsc) {\r
909         if (IsLocked) {\r
910           //\r
911           // Current device in the lock status and\r
912           // User not input password and press ESC,\r
913           // keep device in lock status and continue boot.\r
914           //\r
915           do {\r
916             CreatePopUp (\r
917               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
918               &Key,\r
919               L"Press ENTER to skip the request and continue boot,",\r
920               L"Press ESC to input password again",\r
921               NULL\r
922               );\r
923           } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
924 \r
925           if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
926             gST->ConOut->ClearScreen(gST->ConOut);\r
927             //\r
928             // Keep lock and continue boot.\r
929             //\r
930             return;\r
931           } else {\r
932             //\r
933             // Let user input password again.\r
934             //\r
935             continue;\r
936           }\r
937         } else {\r
938           //\r
939           // Current device in the unlock status and\r
940           // User not input password and press ESC,\r
941           // Shutdown the device.\r
942           //\r
943           do {\r
944             CreatePopUp (\r
945               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
946               &Key,\r
947               L"Press ENTER to shutdown, Press ESC to input password again",\r
948               NULL\r
949               );\r
950           } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
951 \r
952           if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
953             gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
954           } else {\r
955             //\r
956             // Let user input password again.\r
957             //\r
958             continue;\r
959           }\r
960         }\r
961       }\r
962 \r
963       if (Password == NULL) {\r
964         Count ++;\r
965         continue;\r
966       }\r
967       PasswordLen = (UINT32) AsciiStrLen(Password);\r
968 \r
969       if (IsLocked) {\r
970         Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE);\r
971       } else {\r
972         Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, TRUE, TRUE);\r
973         if (Ret == TcgResultSuccess) {\r
974           Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE);\r
975         }\r
976       }\r
977 \r
978       if (Ret == TcgResultSuccess) {\r
979         OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
980         DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
981       } else {\r
982         DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
983       }\r
984 \r
985       if (Password != NULL) {\r
986         ZeroMem (Password, PasswordLen);\r
987         FreePool (Password);\r
988       }\r
989 \r
990       if (Ret == TcgResultSuccess) {\r
991         break;\r
992       }\r
993 \r
994       //\r
995       // Check whether opal device's Tries value has reach the TryLimit value, if yes, force a shutdown\r
996       // before accept new password.\r
997       //\r
998       if (Ret == TcgResultFailureInvalidType) {\r
999         Count = MAX_PASSWORD_TRY_COUNT;\r
1000         break;\r
1001       }\r
1002 \r
1003       Count++;\r
1004 \r
1005       do {\r
1006         CreatePopUp (\r
1007           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1008           &Key,\r
1009           L"Invalid password.",\r
1010           L"Press ENTER to retry",\r
1011           NULL\r
1012           );\r
1013       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1014     }\r
1015 \r
1016     if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
1017       do {\r
1018         CreatePopUp (\r
1019           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1020           &Key,\r
1021           L"Opal password retry count exceeds the limit. Must shutdown!",\r
1022           L"Press ENTER to shutdown",\r
1023           NULL\r
1024           );\r
1025       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1026 \r
1027       gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
1028     }\r
1029   }\r
1030 }\r
1031 \r
1032 /**\r
1033   Process Enable Feature OPAL request.\r
1034 \r
1035   @param[in] Dev            The device which has Enable Feature OPAL request.\r
1036   @param[in] RequestString  Request string.\r
1037 \r
1038 **/\r
1039 VOID\r
1040 ProcessOpalRequestEnableFeature (\r
1041   IN OPAL_DRIVER_DEVICE *Dev,\r
1042   IN CHAR16             *RequestString\r
1043   )\r
1044 {\r
1045   UINT8                 Count;\r
1046   CHAR8                 *Password;\r
1047   UINT32                PasswordLen;\r
1048   CHAR8                 *PasswordConfirm;\r
1049   UINT32                PasswordLenConfirm;\r
1050   OPAL_SESSION          Session;\r
1051   BOOLEAN               PressEsc;\r
1052   EFI_INPUT_KEY         Key;\r
1053   TCG_RESULT            Ret;\r
1054   CHAR16                *PopUpString;\r
1055 \r
1056   if (Dev == NULL) {\r
1057     return;\r
1058   }\r
1059 \r
1060   DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1061 \r
1062   PopUpString = OpalGetPopUpString (Dev, RequestString);\r
1063 \r
1064   Count = 0;\r
1065 \r
1066   ZeroMem(&Session, sizeof(Session));\r
1067   Session.Sscp = Dev->OpalDisk.Sscp;\r
1068   Session.MediaId = Dev->OpalDisk.MediaId;\r
1069   Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
1070 \r
1071   while (Count < MAX_PASSWORD_TRY_COUNT) {\r
1072     Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", NULL, &PressEsc);\r
1073     if (PressEsc) {\r
1074         do {\r
1075           CreatePopUp (\r
1076             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1077             &Key,\r
1078             L"Press ENTER to skip the request and continue boot,",\r
1079             L"Press ESC to input password again",\r
1080             NULL\r
1081             );\r
1082         } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1083 \r
1084         if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
1085           gST->ConOut->ClearScreen(gST->ConOut);\r
1086           return;\r
1087         } else {\r
1088           //\r
1089           // Let user input password again.\r
1090           //\r
1091           continue;\r
1092         }\r
1093     }\r
1094 \r
1095     if (Password == NULL) {\r
1096       Count ++;\r
1097       continue;\r
1098     }\r
1099     PasswordLen = (UINT32) AsciiStrLen(Password);\r
1100 \r
1101     PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", NULL, &PressEsc);\r
1102     if (PasswordConfirm == NULL) {\r
1103       ZeroMem (Password, PasswordLen);\r
1104       FreePool (Password);\r
1105       Count ++;\r
1106       continue;\r
1107     }\r
1108     PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);\r
1109     if ((PasswordLen != PasswordLenConfirm) ||\r
1110         (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {\r
1111       ZeroMem (Password, PasswordLen);\r
1112       FreePool (Password);\r
1113       ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
1114       FreePool (PasswordConfirm);\r
1115       do {\r
1116         CreatePopUp (\r
1117           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1118           &Key,\r
1119           L"Passwords are not the same.",\r
1120           L"Press ENTER to retry",\r
1121           NULL\r
1122           );\r
1123       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1124       Count ++;\r
1125       continue;\r
1126     }\r
1127 \r
1128     if (PasswordConfirm != NULL) {\r
1129       ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
1130       FreePool (PasswordConfirm);\r
1131     }\r
1132 \r
1133     Ret = OpalSupportEnableOpalFeature (&Session, Dev->OpalDisk.Msid,  Dev->OpalDisk.MsidLength, Password, PasswordLen);\r
1134     if (Ret == TcgResultSuccess) {\r
1135       OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
1136       DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
1137     } else {\r
1138       DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
1139     }\r
1140 \r
1141     if (Password != NULL) {\r
1142       ZeroMem (Password, PasswordLen);\r
1143       FreePool (Password);\r
1144     }\r
1145 \r
1146     if (Ret == TcgResultSuccess) {\r
1147       break;\r
1148     }\r
1149 \r
1150     Count++;\r
1151 \r
1152     do {\r
1153       CreatePopUp (\r
1154         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1155         &Key,\r
1156         L"Request failed.",\r
1157         L"Press ENTER to retry",\r
1158         NULL\r
1159         );\r
1160     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1161   }\r
1162 \r
1163   if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
1164     do {\r
1165       CreatePopUp (\r
1166         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1167         &Key,\r
1168         L"Opal password retry count exceeds the limit.",\r
1169         L"Press ENTER to skip the request and continue boot",\r
1170         NULL\r
1171         );\r
1172     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1173     gST->ConOut->ClearScreen(gST->ConOut);\r
1174   }\r
1175 }\r
1176 \r
1177 /**\r
1178   Process Disable User OPAL request.\r
1179 \r
1180   @param[in] Dev            The device which has Disable User OPAL request.\r
1181   @param[in] RequestString  Request string.\r
1182 \r
1183 **/\r
1184 VOID\r
1185 ProcessOpalRequestDisableUser (\r
1186   IN OPAL_DRIVER_DEVICE *Dev,\r
1187   IN CHAR16             *RequestString\r
1188   )\r
1189 {\r
1190   UINT8                 Count;\r
1191   CHAR8                 *Password;\r
1192   UINT32                PasswordLen;\r
1193   OPAL_SESSION          Session;\r
1194   BOOLEAN               PressEsc;\r
1195   EFI_INPUT_KEY         Key;\r
1196   TCG_RESULT            Ret;\r
1197   BOOLEAN               PasswordFailed;\r
1198   CHAR16                *PopUpString;\r
1199 \r
1200   if (Dev == NULL) {\r
1201     return;\r
1202   }\r
1203 \r
1204   DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1205 \r
1206   PopUpString = OpalGetPopUpString (Dev, RequestString);\r
1207 \r
1208   Count = 0;\r
1209 \r
1210   ZeroMem(&Session, sizeof(Session));\r
1211   Session.Sscp = Dev->OpalDisk.Sscp;\r
1212   Session.MediaId = Dev->OpalDisk.MediaId;\r
1213   Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
1214 \r
1215   while (Count < MAX_PASSWORD_TRY_COUNT) {\r
1216     Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, NULL, &PressEsc);\r
1217     if (PressEsc) {\r
1218         do {\r
1219           CreatePopUp (\r
1220             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1221             &Key,\r
1222             L"Press ENTER to skip the request and continue boot,",\r
1223             L"Press ESC to input password again",\r
1224             NULL\r
1225             );\r
1226         } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1227 \r
1228         if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
1229           gST->ConOut->ClearScreen(gST->ConOut);\r
1230           return;\r
1231         } else {\r
1232           //\r
1233           // Let user input password again.\r
1234           //\r
1235           continue;\r
1236         }\r
1237     }\r
1238 \r
1239     if (Password == NULL) {\r
1240       Count ++;\r
1241       continue;\r
1242     }\r
1243     PasswordLen = (UINT32) AsciiStrLen(Password);\r
1244 \r
1245     Ret = OpalUtilDisableUser(&Session, Password, PasswordLen, &PasswordFailed);\r
1246     if (Ret == TcgResultSuccess) {\r
1247       OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
1248       DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
1249     } else {\r
1250       DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
1251     }\r
1252 \r
1253     if (Password != NULL) {\r
1254       ZeroMem (Password, PasswordLen);\r
1255       FreePool (Password);\r
1256     }\r
1257 \r
1258     if (Ret == TcgResultSuccess) {\r
1259       break;\r
1260     }\r
1261 \r
1262     Count++;\r
1263 \r
1264     do {\r
1265       CreatePopUp (\r
1266         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1267         &Key,\r
1268         L"Invalid password, request failed.",\r
1269         L"Press ENTER to retry",\r
1270         NULL\r
1271         );\r
1272     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1273   }\r
1274 \r
1275   if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
1276     do {\r
1277       CreatePopUp (\r
1278         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1279         &Key,\r
1280         L"Opal password retry count exceeds the limit.",\r
1281         L"Press ENTER to skip the request and continue boot",\r
1282         NULL\r
1283         );\r
1284     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1285     gST->ConOut->ClearScreen(gST->ConOut);\r
1286   }\r
1287 }\r
1288 \r
1289 /**\r
1290   Process Psid Revert OPAL request.\r
1291 \r
1292   @param[in] Dev            The device which has Psid Revert OPAL request.\r
1293   @param[in] RequestString  Request string.\r
1294 \r
1295 **/\r
1296 VOID\r
1297 ProcessOpalRequestPsidRevert (\r
1298   IN OPAL_DRIVER_DEVICE *Dev,\r
1299   IN CHAR16             *RequestString\r
1300   )\r
1301 {\r
1302   UINT8                 Count;\r
1303   CHAR8                 *Psid;\r
1304   UINT32                PsidLen;\r
1305   OPAL_SESSION          Session;\r
1306   BOOLEAN               PressEsc;\r
1307   EFI_INPUT_KEY         Key;\r
1308   TCG_RESULT            Ret;\r
1309   CHAR16                *PopUpString;\r
1310   CHAR16                *PopUpString2;\r
1311   CHAR16                *PopUpString3;\r
1312   UINTN                 BufferSize;\r
1313 \r
1314   if (Dev == NULL) {\r
1315     return;\r
1316   }\r
1317 \r
1318   DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1319 \r
1320   PopUpString = OpalGetPopUpString (Dev, RequestString);\r
1321 \r
1322   if (Dev->OpalDisk.EstimateTimeCost > MAX_ACCEPTABLE_REVERTING_TIME) {\r
1323     BufferSize = StrSize (L"Warning: Revert action will take about ####### seconds");\r
1324     PopUpString2 = AllocateZeroPool (BufferSize);\r
1325     ASSERT (PopUpString2 != NULL);\r
1326     UnicodeSPrint (\r
1327         PopUpString2,\r
1328         BufferSize,\r
1329         L"WARNING: Revert action will take about %d seconds",\r
1330         Dev->OpalDisk.EstimateTimeCost\r
1331       );\r
1332     PopUpString3 = L"DO NOT power off system during the revert action!";\r
1333   } else {\r
1334     PopUpString2 = NULL;\r
1335     PopUpString3 = NULL;\r
1336   }\r
1337 \r
1338   Count = 0;\r
1339 \r
1340   ZeroMem(&Session, sizeof(Session));\r
1341   Session.Sscp = Dev->OpalDisk.Sscp;\r
1342   Session.MediaId = Dev->OpalDisk.MediaId;\r
1343   Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
1344 \r
1345   while (Count < MAX_PSID_TRY_COUNT) {\r
1346     Psid = OpalDriverPopUpPsidInput (Dev, PopUpString, PopUpString2, PopUpString3, &PressEsc);\r
1347     if (PressEsc) {\r
1348         do {\r
1349           CreatePopUp (\r
1350             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1351             &Key,\r
1352             L"Press ENTER to skip the request and continue boot,",\r
1353             L"Press ESC to input Psid again",\r
1354             NULL\r
1355             );\r
1356         } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1357 \r
1358         if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
1359           gST->ConOut->ClearScreen(gST->ConOut);\r
1360           goto Done;\r
1361         } else {\r
1362           //\r
1363           // Let user input Psid again.\r
1364           //\r
1365           continue;\r
1366         }\r
1367     }\r
1368 \r
1369     if (Psid == NULL) {\r
1370       Count ++;\r
1371       continue;\r
1372     }\r
1373     PsidLen = (UINT32) AsciiStrLen(Psid);\r
1374 \r
1375     Ret = OpalUtilPsidRevert(&Session, Psid, PsidLen);\r
1376     if (Ret == TcgResultSuccess) {\r
1377       DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
1378     } else {\r
1379       DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
1380     }\r
1381 \r
1382     if (Psid != NULL) {\r
1383       ZeroMem (Psid, PsidLen);\r
1384       FreePool (Psid);\r
1385     }\r
1386 \r
1387     if (Ret == TcgResultSuccess) {\r
1388       break;\r
1389     }\r
1390 \r
1391     Count++;\r
1392 \r
1393     do {\r
1394       CreatePopUp (\r
1395         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1396         &Key,\r
1397         L"Invalid Psid, request failed.",\r
1398         L"Press ENTER to retry",\r
1399         NULL\r
1400         );\r
1401     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1402   }\r
1403 \r
1404   if (Count >= MAX_PSID_TRY_COUNT) {\r
1405     do {\r
1406       CreatePopUp (\r
1407         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1408         &Key,\r
1409         L"Opal Psid retry count exceeds the limit.",\r
1410         L"Press ENTER to skip the request and continue boot",\r
1411         NULL\r
1412         );\r
1413     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1414     gST->ConOut->ClearScreen(gST->ConOut);\r
1415   }\r
1416 \r
1417 Done:\r
1418   if (PopUpString2 != NULL) {\r
1419     FreePool (PopUpString2);\r
1420   }\r
1421 }\r
1422 \r
1423 /**\r
1424   Process Admin Revert OPAL request.\r
1425 \r
1426   @param[in] Dev            The device which has Revert OPAL request.\r
1427   @param[in] KeepUserData   Whether to keep user data or not.\r
1428   @param[in] RequestString  Request string.\r
1429 \r
1430 **/\r
1431 VOID\r
1432 ProcessOpalRequestRevert (\r
1433   IN OPAL_DRIVER_DEVICE *Dev,\r
1434   IN BOOLEAN            KeepUserData,\r
1435   IN CHAR16             *RequestString\r
1436   )\r
1437 {\r
1438   UINT8                 Count;\r
1439   CHAR8                 *Password;\r
1440   UINT32                PasswordLen;\r
1441   OPAL_SESSION          Session;\r
1442   BOOLEAN               PressEsc;\r
1443   EFI_INPUT_KEY         Key;\r
1444   TCG_RESULT            Ret;\r
1445   BOOLEAN               PasswordFailed;\r
1446   CHAR16                *PopUpString;\r
1447   CHAR16                *PopUpString2;\r
1448   CHAR16                *PopUpString3;\r
1449   UINTN                 BufferSize;\r
1450 \r
1451   if (Dev == NULL) {\r
1452     return;\r
1453   }\r
1454 \r
1455   DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1456 \r
1457   PopUpString = OpalGetPopUpString (Dev, RequestString);\r
1458 \r
1459   if ((!KeepUserData) &&\r
1460       (Dev->OpalDisk.EstimateTimeCost > MAX_ACCEPTABLE_REVERTING_TIME)) {\r
1461     BufferSize = StrSize (L"Warning: Revert action will take about ####### seconds");\r
1462     PopUpString2 = AllocateZeroPool (BufferSize);\r
1463     ASSERT (PopUpString2 != NULL);\r
1464     UnicodeSPrint (\r
1465         PopUpString2,\r
1466         BufferSize,\r
1467         L"WARNING: Revert action will take about %d seconds",\r
1468         Dev->OpalDisk.EstimateTimeCost\r
1469       );\r
1470     PopUpString3 = L"DO NOT power off system during the revert action!";\r
1471   } else {\r
1472     PopUpString2 = NULL;\r
1473     PopUpString3 = NULL;\r
1474   }\r
1475 \r
1476   Count = 0;\r
1477 \r
1478   ZeroMem(&Session, sizeof(Session));\r
1479   Session.Sscp = Dev->OpalDisk.Sscp;\r
1480   Session.MediaId = Dev->OpalDisk.MediaId;\r
1481   Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
1482 \r
1483   while (Count < MAX_PASSWORD_TRY_COUNT) {\r
1484     Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, PopUpString2, PopUpString3, &PressEsc);\r
1485     if (PressEsc) {\r
1486         do {\r
1487           CreatePopUp (\r
1488             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1489             &Key,\r
1490             L"Press ENTER to skip the request and continue boot,",\r
1491             L"Press ESC to input password again",\r
1492             NULL\r
1493             );\r
1494         } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1495 \r
1496         if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
1497           gST->ConOut->ClearScreen(gST->ConOut);\r
1498           goto Done;\r
1499         } else {\r
1500           //\r
1501           // Let user input password again.\r
1502           //\r
1503           continue;\r
1504         }\r
1505     }\r
1506 \r
1507     if (Password == NULL) {\r
1508       Count ++;\r
1509       continue;\r
1510     }\r
1511     PasswordLen = (UINT32) AsciiStrLen(Password);\r
1512 \r
1513     if ((Dev->OpalDisk.SupportedAttributes.PyriteSsc == 1) &&\r
1514         (Dev->OpalDisk.LockingFeature.MediaEncryption == 0)) {\r
1515       //\r
1516       // For pyrite type device which does not support media encryption,\r
1517       // it does not accept "Keep User Data" parameter.\r
1518       // So here hardcode a FALSE for this case.\r
1519       //\r
1520       Ret = OpalUtilRevert(\r
1521               &Session,\r
1522               FALSE,\r
1523               Password,\r
1524               PasswordLen,\r
1525               &PasswordFailed,\r
1526               Dev->OpalDisk.Msid,\r
1527               Dev->OpalDisk.MsidLength\r
1528               );\r
1529     } else {\r
1530       Ret = OpalUtilRevert(\r
1531               &Session,\r
1532               KeepUserData,\r
1533               Password,\r
1534               PasswordLen,\r
1535               &PasswordFailed,\r
1536               Dev->OpalDisk.Msid,\r
1537               Dev->OpalDisk.MsidLength\r
1538               );\r
1539     }\r
1540     if (Ret == TcgResultSuccess) {\r
1541       OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
1542       DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
1543     } else {\r
1544       DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
1545     }\r
1546 \r
1547     if (Password != NULL) {\r
1548       ZeroMem (Password, PasswordLen);\r
1549       FreePool (Password);\r
1550     }\r
1551 \r
1552     if (Ret == TcgResultSuccess) {\r
1553       break;\r
1554     }\r
1555 \r
1556     Count++;\r
1557 \r
1558     do {\r
1559       CreatePopUp (\r
1560         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1561         &Key,\r
1562         L"Invalid password, request failed.",\r
1563         L"Press ENTER to retry",\r
1564         NULL\r
1565         );\r
1566     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1567   }\r
1568 \r
1569   if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
1570     do {\r
1571       CreatePopUp (\r
1572         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1573         &Key,\r
1574         L"Opal password retry count exceeds the limit.",\r
1575         L"Press ENTER to skip the request and continue boot",\r
1576         NULL\r
1577         );\r
1578     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1579     gST->ConOut->ClearScreen(gST->ConOut);\r
1580   }\r
1581 \r
1582 Done:\r
1583   if (PopUpString2 != NULL) {\r
1584     FreePool (PopUpString2);\r
1585   }\r
1586 }\r
1587 \r
1588 /**\r
1589   Process Secure Erase OPAL request.\r
1590 \r
1591   @param[in] Dev            The device which has Secure Erase OPAL request.\r
1592   @param[in] RequestString  Request string.\r
1593 \r
1594 **/\r
1595 VOID\r
1596 ProcessOpalRequestSecureErase (\r
1597   IN OPAL_DRIVER_DEVICE *Dev,\r
1598   IN CHAR16             *RequestString\r
1599   )\r
1600 {\r
1601   UINT8                 Count;\r
1602   CHAR8                 *Password;\r
1603   UINT32                PasswordLen;\r
1604   OPAL_SESSION          Session;\r
1605   BOOLEAN               PressEsc;\r
1606   EFI_INPUT_KEY         Key;\r
1607   TCG_RESULT            Ret;\r
1608   BOOLEAN               PasswordFailed;\r
1609   CHAR16                *PopUpString;\r
1610   CHAR16                *PopUpString2;\r
1611   CHAR16                *PopUpString3;\r
1612   UINTN                 BufferSize;\r
1613 \r
1614   if (Dev == NULL) {\r
1615     return;\r
1616   }\r
1617 \r
1618   DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1619 \r
1620   PopUpString = OpalGetPopUpString (Dev, RequestString);\r
1621 \r
1622   if (Dev->OpalDisk.EstimateTimeCost > MAX_ACCEPTABLE_REVERTING_TIME) {\r
1623     BufferSize = StrSize (L"Warning: Secure erase action will take about ####### seconds");\r
1624     PopUpString2 = AllocateZeroPool (BufferSize);\r
1625     ASSERT (PopUpString2 != NULL);\r
1626     UnicodeSPrint (\r
1627         PopUpString2,\r
1628         BufferSize,\r
1629         L"WARNING: Secure erase action will take about %d seconds",\r
1630         Dev->OpalDisk.EstimateTimeCost\r
1631       );\r
1632     PopUpString3 = L"DO NOT power off system during the action!";\r
1633   } else {\r
1634     PopUpString2 = NULL;\r
1635     PopUpString3 = NULL;\r
1636   }\r
1637   Count = 0;\r
1638 \r
1639   ZeroMem(&Session, sizeof(Session));\r
1640   Session.Sscp = Dev->OpalDisk.Sscp;\r
1641   Session.MediaId = Dev->OpalDisk.MediaId;\r
1642   Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
1643 \r
1644   while (Count < MAX_PASSWORD_TRY_COUNT) {\r
1645     Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, PopUpString2, PopUpString3, &PressEsc);\r
1646     if (PressEsc) {\r
1647         do {\r
1648           CreatePopUp (\r
1649             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1650             &Key,\r
1651             L"Press ENTER to skip the request and continue boot,",\r
1652             L"Press ESC to input password again",\r
1653             NULL\r
1654             );\r
1655         } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1656 \r
1657         if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
1658           gST->ConOut->ClearScreen(gST->ConOut);\r
1659           goto Done;\r
1660         } else {\r
1661           //\r
1662           // Let user input password again.\r
1663           //\r
1664           continue;\r
1665         }\r
1666     }\r
1667 \r
1668     if (Password == NULL) {\r
1669       Count ++;\r
1670       continue;\r
1671     }\r
1672     PasswordLen = (UINT32) AsciiStrLen(Password);\r
1673 \r
1674     Ret = OpalUtilSecureErase(&Session, Password, PasswordLen, &PasswordFailed);\r
1675     if (Ret == TcgResultSuccess) {\r
1676       OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
1677       DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
1678     } else {\r
1679       DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
1680     }\r
1681 \r
1682     if (Password != NULL) {\r
1683       ZeroMem (Password, PasswordLen);\r
1684       FreePool (Password);\r
1685     }\r
1686 \r
1687     if (Ret == TcgResultSuccess) {\r
1688       break;\r
1689     }\r
1690 \r
1691     Count++;\r
1692 \r
1693     do {\r
1694       CreatePopUp (\r
1695         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1696         &Key,\r
1697         L"Invalid password, request failed.",\r
1698         L"Press ENTER to retry",\r
1699         NULL\r
1700         );\r
1701     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1702   }\r
1703 \r
1704   if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
1705     do {\r
1706       CreatePopUp (\r
1707         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1708         &Key,\r
1709         L"Opal password retry count exceeds the limit.",\r
1710         L"Press ENTER to skip the request and continue boot",\r
1711         NULL\r
1712         );\r
1713     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1714     gST->ConOut->ClearScreen(gST->ConOut);\r
1715   }\r
1716 \r
1717 Done:\r
1718   if (PopUpString2 != NULL) {\r
1719     FreePool (PopUpString2);\r
1720   }\r
1721 }\r
1722 \r
1723 /**\r
1724   Process Set Admin Pwd OPAL request.\r
1725 \r
1726   @param[in] Dev            The device which has Set Admin Pwd Feature OPAL request.\r
1727   @param[in] RequestString  Request string.\r
1728 \r
1729 **/\r
1730 VOID\r
1731 ProcessOpalRequestSetUserPwd (\r
1732   IN OPAL_DRIVER_DEVICE *Dev,\r
1733   IN CHAR16             *RequestString\r
1734   )\r
1735 {\r
1736   UINT8                 Count;\r
1737   CHAR8                 *OldPassword;\r
1738   UINT32                OldPasswordLen;\r
1739   CHAR8                 *Password;\r
1740   UINT32                PasswordLen;\r
1741   CHAR8                 *PasswordConfirm;\r
1742   UINT32                PasswordLenConfirm;\r
1743   OPAL_SESSION          Session;\r
1744   BOOLEAN               PressEsc;\r
1745   EFI_INPUT_KEY         Key;\r
1746   TCG_RESULT            Ret;\r
1747   CHAR16                *PopUpString;\r
1748 \r
1749   if (Dev == NULL) {\r
1750     return;\r
1751   }\r
1752 \r
1753   DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1754 \r
1755   PopUpString = OpalGetPopUpString (Dev, RequestString);\r
1756 \r
1757   Count = 0;\r
1758 \r
1759   while (Count < MAX_PASSWORD_TRY_COUNT) {\r
1760     OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", NULL, &PressEsc);\r
1761     if (PressEsc) {\r
1762         do {\r
1763           CreatePopUp (\r
1764             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1765             &Key,\r
1766             L"Press ENTER to skip the request and continue boot,",\r
1767             L"Press ESC to input password again",\r
1768             NULL\r
1769             );\r
1770         } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1771 \r
1772         if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
1773           gST->ConOut->ClearScreen(gST->ConOut);\r
1774           return;\r
1775         } else {\r
1776           //\r
1777           // Let user input password again.\r
1778           //\r
1779           continue;\r
1780         }\r
1781     }\r
1782 \r
1783     if (OldPassword == NULL) {\r
1784       Count ++;\r
1785       continue;\r
1786     }\r
1787     OldPasswordLen = (UINT32) AsciiStrLen(OldPassword);\r
1788 \r
1789     ZeroMem(&Session, sizeof(Session));\r
1790     Session.Sscp = Dev->OpalDisk.Sscp;\r
1791     Session.MediaId = Dev->OpalDisk.MediaId;\r
1792     Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
1793     Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_USER1_AUTHORITY);\r
1794     if (Ret == TcgResultSuccess) {\r
1795       DEBUG ((DEBUG_INFO, "Verify with USER1 authority : Success\n"));\r
1796     } else {\r
1797       Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY);\r
1798       if (Ret == TcgResultSuccess) {\r
1799         DEBUG ((DEBUG_INFO, "Verify with ADMIN1 authority: Success\n"));\r
1800       } else {\r
1801         ZeroMem (OldPassword, OldPasswordLen);\r
1802         FreePool (OldPassword);\r
1803         DEBUG ((DEBUG_INFO, "Verify: Failure\n"));\r
1804         do {\r
1805           CreatePopUp (\r
1806             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1807             &Key,\r
1808             L"Incorrect password.",\r
1809             L"Press ENTER to retry",\r
1810             NULL\r
1811             );\r
1812         } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1813         Count ++;\r
1814         continue;\r
1815       }\r
1816     }\r
1817 \r
1818     Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", NULL, &PressEsc);\r
1819     if (Password == NULL) {\r
1820       ZeroMem (OldPassword, OldPasswordLen);\r
1821       FreePool (OldPassword);\r
1822       Count ++;\r
1823       continue;\r
1824     }\r
1825     PasswordLen = (UINT32) AsciiStrLen(Password);\r
1826 \r
1827     PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", NULL, &PressEsc);\r
1828     if (PasswordConfirm == NULL) {\r
1829       ZeroMem (OldPassword, OldPasswordLen);\r
1830       FreePool (OldPassword);\r
1831       ZeroMem (Password, PasswordLen);\r
1832       FreePool (Password);\r
1833       Count ++;\r
1834       continue;\r
1835     }\r
1836     PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);\r
1837     if ((PasswordLen != PasswordLenConfirm) ||\r
1838         (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {\r
1839       ZeroMem (OldPassword, OldPasswordLen);\r
1840       FreePool (OldPassword);\r
1841       ZeroMem (Password, PasswordLen);\r
1842       FreePool (Password);\r
1843       ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
1844       FreePool (PasswordConfirm);\r
1845       do {\r
1846         CreatePopUp (\r
1847           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1848           &Key,\r
1849           L"Passwords are not the same.",\r
1850           L"Press ENTER to retry",\r
1851           NULL\r
1852           );\r
1853       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1854       Count ++;\r
1855       continue;\r
1856     }\r
1857 \r
1858     if (PasswordConfirm != NULL) {\r
1859       ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
1860       FreePool (PasswordConfirm);\r
1861     }\r
1862 \r
1863     ZeroMem(&Session, sizeof(Session));\r
1864     Session.Sscp = Dev->OpalDisk.Sscp;\r
1865     Session.MediaId = Dev->OpalDisk.MediaId;\r
1866     Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
1867     Ret = OpalUtilSetUserPassword(\r
1868             &Session,\r
1869             OldPassword,\r
1870             OldPasswordLen,\r
1871             Password,\r
1872             PasswordLen\r
1873             );\r
1874     if (Ret == TcgResultSuccess) {\r
1875       OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
1876       DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
1877     } else {\r
1878       DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
1879     }\r
1880 \r
1881     if (OldPassword != NULL) {\r
1882       ZeroMem (OldPassword, OldPasswordLen);\r
1883       FreePool (OldPassword);\r
1884     }\r
1885 \r
1886     if (Password != NULL) {\r
1887       ZeroMem (Password, PasswordLen);\r
1888       FreePool (Password);\r
1889     }\r
1890 \r
1891     if (Ret == TcgResultSuccess) {\r
1892       break;\r
1893     }\r
1894 \r
1895     Count++;\r
1896 \r
1897     do {\r
1898       CreatePopUp (\r
1899         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1900         &Key,\r
1901         L"Request failed.",\r
1902         L"Press ENTER to retry",\r
1903         NULL\r
1904         );\r
1905     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1906   }\r
1907 \r
1908   if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
1909     do {\r
1910       CreatePopUp (\r
1911         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1912         &Key,\r
1913         L"Opal password retry count exceeds the limit.",\r
1914         L"Press ENTER to skip the request and continue boot",\r
1915         NULL\r
1916         );\r
1917     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1918     gST->ConOut->ClearScreen(gST->ConOut);\r
1919   }\r
1920 }\r
1921 \r
1922 /**\r
1923   Process Set Admin Pwd OPAL request.\r
1924 \r
1925   @param[in] Dev            The device which has Set Admin Pwd Feature OPAL request.\r
1926   @param[in] RequestString  Request string.\r
1927 \r
1928 **/\r
1929 VOID\r
1930 ProcessOpalRequestSetAdminPwd (\r
1931   IN OPAL_DRIVER_DEVICE *Dev,\r
1932   IN CHAR16             *RequestString\r
1933   )\r
1934 {\r
1935   UINT8                 Count;\r
1936   CHAR8                 *OldPassword;\r
1937   UINT32                OldPasswordLen;\r
1938   CHAR8                 *Password;\r
1939   UINT32                PasswordLen;\r
1940   CHAR8                 *PasswordConfirm;\r
1941   UINT32                PasswordLenConfirm;\r
1942   OPAL_SESSION          Session;\r
1943   BOOLEAN               PressEsc;\r
1944   EFI_INPUT_KEY         Key;\r
1945   TCG_RESULT            Ret;\r
1946   CHAR16                *PopUpString;\r
1947 \r
1948   if (Dev == NULL) {\r
1949     return;\r
1950   }\r
1951 \r
1952   DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1953 \r
1954   PopUpString = OpalGetPopUpString (Dev, RequestString);\r
1955 \r
1956   Count = 0;\r
1957 \r
1958   while (Count < MAX_PASSWORD_TRY_COUNT) {\r
1959     OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", NULL, &PressEsc);\r
1960     if (PressEsc) {\r
1961         do {\r
1962           CreatePopUp (\r
1963             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1964             &Key,\r
1965             L"Press ENTER to skip the request and continue boot,",\r
1966             L"Press ESC to input password again",\r
1967             NULL\r
1968             );\r
1969         } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1970 \r
1971         if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
1972           gST->ConOut->ClearScreen(gST->ConOut);\r
1973           return;\r
1974         } else {\r
1975           //\r
1976           // Let user input password again.\r
1977           //\r
1978           continue;\r
1979         }\r
1980     }\r
1981 \r
1982     if (OldPassword == NULL) {\r
1983       Count ++;\r
1984       continue;\r
1985     }\r
1986     OldPasswordLen = (UINT32) AsciiStrLen(OldPassword);\r
1987 \r
1988     ZeroMem(&Session, sizeof(Session));\r
1989     Session.Sscp = Dev->OpalDisk.Sscp;\r
1990     Session.MediaId = Dev->OpalDisk.MediaId;\r
1991     Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
1992     Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY);\r
1993     if (Ret == TcgResultSuccess) {\r
1994       DEBUG ((DEBUG_INFO, "Verify: Success\n"));\r
1995     } else {\r
1996       ZeroMem (OldPassword, OldPasswordLen);\r
1997       FreePool (OldPassword);\r
1998       DEBUG ((DEBUG_INFO, "Verify: Failure\n"));\r
1999       do {\r
2000         CreatePopUp (\r
2001           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
2002           &Key,\r
2003           L"Incorrect password.",\r
2004           L"Press ENTER to retry",\r
2005           NULL\r
2006           );\r
2007       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
2008       Count ++;\r
2009       continue;\r
2010     }\r
2011 \r
2012     Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", NULL, &PressEsc);\r
2013     if (Password == NULL) {\r
2014       ZeroMem (OldPassword, OldPasswordLen);\r
2015       FreePool (OldPassword);\r
2016       Count ++;\r
2017       continue;\r
2018     }\r
2019     PasswordLen = (UINT32) AsciiStrLen(Password);\r
2020 \r
2021     PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", NULL, &PressEsc);\r
2022     if (PasswordConfirm == NULL) {\r
2023       ZeroMem (OldPassword, OldPasswordLen);\r
2024       FreePool (OldPassword);\r
2025       ZeroMem (Password, PasswordLen);\r
2026       FreePool (Password);\r
2027       Count ++;\r
2028       continue;\r
2029     }\r
2030     PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);\r
2031     if ((PasswordLen != PasswordLenConfirm) ||\r
2032         (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {\r
2033       ZeroMem (OldPassword, OldPasswordLen);\r
2034       FreePool (OldPassword);\r
2035       ZeroMem (Password, PasswordLen);\r
2036       FreePool (Password);\r
2037       ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
2038       FreePool (PasswordConfirm);\r
2039       do {\r
2040         CreatePopUp (\r
2041           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
2042           &Key,\r
2043           L"Passwords are not the same.",\r
2044           L"Press ENTER to retry",\r
2045           NULL\r
2046           );\r
2047       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
2048       Count ++;\r
2049       continue;\r
2050     }\r
2051 \r
2052     if (PasswordConfirm != NULL) {\r
2053       ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
2054       FreePool (PasswordConfirm);\r
2055     }\r
2056 \r
2057 \r
2058     ZeroMem(&Session, sizeof(Session));\r
2059     Session.Sscp = Dev->OpalDisk.Sscp;\r
2060     Session.MediaId = Dev->OpalDisk.MediaId;\r
2061     Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
2062     Ret = OpalUtilSetAdminPassword(\r
2063             &Session,\r
2064             OldPassword,\r
2065             OldPasswordLen,\r
2066             Password,\r
2067             PasswordLen\r
2068             );\r
2069     if (Ret == TcgResultSuccess) {\r
2070       OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
2071       DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
2072     } else {\r
2073       DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
2074     }\r
2075 \r
2076     if (OldPassword != NULL) {\r
2077       ZeroMem (OldPassword, OldPasswordLen);\r
2078       FreePool (OldPassword);\r
2079     }\r
2080 \r
2081     if (Password != NULL) {\r
2082       ZeroMem (Password, PasswordLen);\r
2083       FreePool (Password);\r
2084     }\r
2085 \r
2086     if (Ret == TcgResultSuccess) {\r
2087       break;\r
2088     }\r
2089 \r
2090     Count++;\r
2091 \r
2092     do {\r
2093       CreatePopUp (\r
2094         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
2095         &Key,\r
2096         L"Request failed.",\r
2097         L"Press ENTER to retry",\r
2098         NULL\r
2099         );\r
2100     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
2101   }\r
2102 \r
2103   if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
2104     do {\r
2105       CreatePopUp (\r
2106         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
2107         &Key,\r
2108         L"Opal password retry count exceeds the limit.",\r
2109         L"Press ENTER to skip the request and continue boot",\r
2110         NULL\r
2111         );\r
2112     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
2113     gST->ConOut->ClearScreen(gST->ConOut);\r
2114   }\r
2115 }\r
2116 \r
2117 /**\r
2118   Process OPAL request.\r
2119 \r
2120   @param[in] Dev            The device which has OPAL request.\r
2121 \r
2122 **/\r
2123 VOID\r
2124 ProcessOpalRequest (\r
2125   IN OPAL_DRIVER_DEVICE     *Dev\r
2126   )\r
2127 {\r
2128   EFI_STATUS                Status;\r
2129   OPAL_REQUEST_VARIABLE     *TempVariable;\r
2130   OPAL_REQUEST_VARIABLE     *Variable;\r
2131   UINTN                     VariableSize;\r
2132   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInVariable;\r
2133   UINTN                     DevicePathSizeInVariable;\r
2134   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
2135   UINTN                     DevicePathSize;\r
2136   BOOLEAN                   KeepUserData;\r
2137 \r
2138   DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
2139 \r
2140   if (mOpalRequestVariable == NULL) {\r
2141     Status = GetVariable2 (\r
2142                OPAL_REQUEST_VARIABLE_NAME,\r
2143                &gHiiSetupVariableGuid,\r
2144                (VOID **) &Variable,\r
2145                &VariableSize\r
2146                );\r
2147     if (EFI_ERROR (Status) || (Variable == NULL)) {\r
2148       return;\r
2149     }\r
2150     mOpalRequestVariable = Variable;\r
2151     mOpalRequestVariableSize = VariableSize;\r
2152 \r
2153     //\r
2154     // Delete the OPAL request variable.\r
2155     //\r
2156     Status = gRT->SetVariable (\r
2157                     OPAL_REQUEST_VARIABLE_NAME,\r
2158                     (EFI_GUID *) &gHiiSetupVariableGuid,\r
2159                     0,\r
2160                     0,\r
2161                     NULL\r
2162                     );\r
2163     ASSERT_EFI_ERROR (Status);\r
2164   } else {\r
2165     Variable = mOpalRequestVariable;\r
2166     VariableSize = mOpalRequestVariableSize;\r
2167   }\r
2168 \r
2169   //\r
2170   // Process the OPAL requests.\r
2171   //\r
2172   TempVariable = Variable;\r
2173   while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&\r
2174          (VariableSize >= TempVariable->Length) &&\r
2175          (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {\r
2176     DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
2177     DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);\r
2178     DevicePath = Dev->OpalDisk.OpalDevicePath;\r
2179     DevicePathSize = GetDevicePathSize (DevicePath);\r
2180     if ((DevicePathSize == DevicePathSizeInVariable) &&\r
2181         (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) {\r
2182       //\r
2183       // Found the node for the OPAL device.\r
2184       //\r
2185       if (TempVariable->OpalRequest.SetAdminPwd != 0) {\r
2186         ProcessOpalRequestSetAdminPwd (Dev, L"Update Admin Pwd:");\r
2187       }\r
2188       if (TempVariable->OpalRequest.SetUserPwd != 0) {\r
2189         ProcessOpalRequestSetUserPwd (Dev, L"Set User Pwd:");\r
2190       }\r
2191       if (TempVariable->OpalRequest.SecureErase!= 0) {\r
2192         ProcessOpalRequestSecureErase (Dev, L"Secure Erase:");\r
2193       }\r
2194       if (TempVariable->OpalRequest.Revert != 0) {\r
2195         KeepUserData = (BOOLEAN) TempVariable->OpalRequest.KeepUserData;\r
2196         ProcessOpalRequestRevert (\r
2197           Dev,\r
2198           KeepUserData,\r
2199           KeepUserData ? L"Admin Revert(keep):" : L"Admin Revert:"\r
2200           );\r
2201       }\r
2202       if (TempVariable->OpalRequest.PsidRevert != 0) {\r
2203         ProcessOpalRequestPsidRevert (Dev, L"Psid Revert:");\r
2204       }\r
2205       if (TempVariable->OpalRequest.DisableUser != 0) {\r
2206         ProcessOpalRequestDisableUser (Dev, L"Disable User:");\r
2207       }\r
2208       if (TempVariable->OpalRequest.EnableFeature != 0) {\r
2209         ProcessOpalRequestEnableFeature (Dev, L"Enable Feature:");\r
2210       }\r
2211 \r
2212       //\r
2213       // Update Device ownership.\r
2214       // Later BlockSID command may block the update.\r
2215       //\r
2216       OpalDiskUpdateOwnerShip (&Dev->OpalDisk);\r
2217 \r
2218       break;\r
2219     }\r
2220 \r
2221     VariableSize -= TempVariable->Length;\r
2222     TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length);\r
2223   }\r
2224 \r
2225   DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
2226 }\r
2227 \r
2228 /**\r
2229   Add new device to the global device list.\r
2230 \r
2231   @param Dev             New create device.\r
2232 \r
2233 **/\r
2234 VOID\r
2235 AddDeviceToTail(\r
2236   IN OPAL_DRIVER_DEVICE    *Dev\r
2237   )\r
2238 {\r
2239   OPAL_DRIVER_DEVICE                *TmpDev;\r
2240 \r
2241   if (mOpalDriver.DeviceList == NULL) {\r
2242     mOpalDriver.DeviceList = Dev;\r
2243   } else {\r
2244     TmpDev = mOpalDriver.DeviceList;\r
2245     while (TmpDev->Next != NULL) {\r
2246       TmpDev = TmpDev->Next;\r
2247     }\r
2248 \r
2249     TmpDev->Next = Dev;\r
2250   }\r
2251 }\r
2252 \r
2253 /**\r
2254   Remove one device in the global device list.\r
2255 \r
2256   @param Dev             The device need to be removed.\r
2257 \r
2258 **/\r
2259 VOID\r
2260 RemoveDevice (\r
2261   IN OPAL_DRIVER_DEVICE    *Dev\r
2262   )\r
2263 {\r
2264   OPAL_DRIVER_DEVICE                *TmpDev;\r
2265 \r
2266   if (mOpalDriver.DeviceList == NULL) {\r
2267     return;\r
2268   }\r
2269 \r
2270   if (mOpalDriver.DeviceList == Dev) {\r
2271     mOpalDriver.DeviceList = NULL;\r
2272     return;\r
2273   }\r
2274 \r
2275   TmpDev = mOpalDriver.DeviceList;\r
2276   while (TmpDev->Next != NULL) {\r
2277     if (TmpDev->Next == Dev) {\r
2278       TmpDev->Next = Dev->Next;\r
2279       break;\r
2280     }\r
2281   }\r
2282 }\r
2283 \r
2284 /**\r
2285   Get current device count.\r
2286 \r
2287   @retval  return the current created device count.\r
2288 \r
2289 **/\r
2290 UINT8\r
2291 GetDeviceCount (\r
2292   VOID\r
2293   )\r
2294 {\r
2295   UINT8                Count;\r
2296   OPAL_DRIVER_DEVICE   *TmpDev;\r
2297 \r
2298   Count = 0;\r
2299   TmpDev = mOpalDriver.DeviceList;\r
2300 \r
2301   while (TmpDev != NULL) {\r
2302     Count++;\r
2303     TmpDev = TmpDev->Next;\r
2304   }\r
2305 \r
2306   return Count;\r
2307 }\r
2308 \r
2309 /**\r
2310   Get devcie list info.\r
2311 \r
2312   @retval     return the device list pointer.\r
2313 **/\r
2314 OPAL_DRIVER_DEVICE*\r
2315 OpalDriverGetDeviceList(\r
2316   VOID\r
2317   )\r
2318 {\r
2319   return mOpalDriver.DeviceList;\r
2320 }\r
2321 \r
2322 /**\r
2323   Stop this Controller.\r
2324 \r
2325   @param  Dev               The device need to be stopped.\r
2326 \r
2327 **/\r
2328 VOID\r
2329 OpalDriverStopDevice (\r
2330   OPAL_DRIVER_DEVICE     *Dev\r
2331   )\r
2332 {\r
2333   //\r
2334   // free each name\r
2335   //\r
2336   FreePool(Dev->Name16);\r
2337 \r
2338   //\r
2339   // remove OPAL_DRIVER_DEVICE from the list\r
2340   // it updates the controllerList pointer\r
2341   //\r
2342   RemoveDevice(Dev);\r
2343 \r
2344   //\r
2345   // close protocols that were opened\r
2346   //\r
2347   gBS->CloseProtocol(\r
2348     Dev->Handle,\r
2349     &gEfiStorageSecurityCommandProtocolGuid,\r
2350     gOpalDriverBinding.DriverBindingHandle,\r
2351     Dev->Handle\r
2352     );\r
2353 \r
2354   gBS->CloseProtocol(\r
2355     Dev->Handle,\r
2356     &gEfiBlockIoProtocolGuid,\r
2357     gOpalDriverBinding.DriverBindingHandle,\r
2358     Dev->Handle\r
2359     );\r
2360 \r
2361   FreePool(Dev);\r
2362 }\r
2363 \r
2364 /**\r
2365   Get devcie name through the component name protocol.\r
2366 \r
2367   @param[in]       AllHandlesBuffer   The handle buffer for current system.\r
2368   @param[in]       NumAllHandles      The number of handles for the handle buffer.\r
2369   @param[in]       Dev                The device which need to get name.\r
2370   @param[in]       UseComp1           Whether use component name or name2 protocol.\r
2371 \r
2372   @retval     TRUE        Find the name for this device.\r
2373   @retval     FALSE       Not found the name for this device.\r
2374 **/\r
2375 BOOLEAN\r
2376 OpalDriverGetDeviceNameByProtocol(\r
2377   EFI_HANDLE             *AllHandlesBuffer,\r
2378   UINTN                  NumAllHandles,\r
2379   OPAL_DRIVER_DEVICE     *Dev,\r
2380   BOOLEAN                UseComp1\r
2381   )\r
2382 {\r
2383   EFI_HANDLE*                   ProtocolHandlesBuffer;\r
2384   UINTN                         NumProtocolHandles;\r
2385   EFI_STATUS                    Status;\r
2386   EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name and componentName2 have same layout\r
2387   EFI_GUID                      Protocol;\r
2388   UINTN                         StrLength;\r
2389   EFI_DEVICE_PATH_PROTOCOL*     TmpDevPath;\r
2390   UINTN                         Index1;\r
2391   UINTN                         Index2;\r
2392   EFI_HANDLE                    TmpHandle;\r
2393   CHAR16                        *DevName;\r
2394 \r
2395   if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) {\r
2396     return FALSE;\r
2397   }\r
2398 \r
2399   Protocol = UseComp1 ? gEfiComponentNameProtocolGuid : gEfiComponentName2ProtocolGuid;\r
2400 \r
2401   //\r
2402   // Find all EFI_HANDLES with protocol\r
2403   //\r
2404   Status = gBS->LocateHandleBuffer(\r
2405                ByProtocol,\r
2406                &Protocol,\r
2407                NULL,\r
2408                &NumProtocolHandles,\r
2409                &ProtocolHandlesBuffer\r
2410                );\r
2411   if (EFI_ERROR(Status)) {\r
2412     return FALSE;\r
2413   }\r
2414 \r
2415 \r
2416   //\r
2417   // Exit early if no supported devices\r
2418   //\r
2419   if (NumProtocolHandles == 0) {\r
2420     return FALSE;\r
2421   }\r
2422 \r
2423   //\r
2424   // Get printable name by iterating through all protocols\r
2425   // using the handle as the child, and iterate through all handles for the controller\r
2426   // exit loop early once found, if not found, then delete device\r
2427   // storage security protocol instances already exist, add them to internal list\r
2428   //\r
2429   Status = EFI_DEVICE_ERROR;\r
2430   for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) {\r
2431     DevName = NULL;\r
2432 \r
2433     if (Dev->Name16 != NULL) {\r
2434       return TRUE;\r
2435     }\r
2436 \r
2437     TmpHandle = ProtocolHandlesBuffer[Index1];\r
2438 \r
2439     Status = gBS->OpenProtocol(\r
2440                  TmpHandle,\r
2441                  &Protocol,\r
2442                  (VOID**)&Cnp1_2,\r
2443                  gImageHandle,\r
2444                  NULL,\r
2445                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2446                  );\r
2447     if (EFI_ERROR(Status) || Cnp1_2 == NULL) {\r
2448       continue;\r
2449     }\r
2450 \r
2451     //\r
2452     // Use all handles array as controller handle\r
2453     //\r
2454     for (Index2 = 0; Index2 < NumAllHandles; Index2++) {\r
2455       Status = Cnp1_2->GetControllerName(\r
2456                    Cnp1_2,\r
2457                    AllHandlesBuffer[Index2],\r
2458                    Dev->Handle,\r
2459                    LANGUAGE_ISO_639_2_ENGLISH,\r
2460                    &DevName\r
2461                    );\r
2462       if (EFI_ERROR(Status)) {\r
2463         Status = Cnp1_2->GetControllerName(\r
2464                      Cnp1_2,\r
2465                      AllHandlesBuffer[Index2],\r
2466                      Dev->Handle,\r
2467                      LANGUAGE_RFC_3066_ENGLISH,\r
2468                      &DevName\r
2469                      );\r
2470       }\r
2471       if (!EFI_ERROR(Status) && DevName != NULL) {\r
2472         StrLength = StrLen(DevName) + 1;        // Add one for NULL terminator\r
2473         Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16));\r
2474         ASSERT (Dev->Name16 != NULL);\r
2475         StrCpyS (Dev->Name16, StrLength, DevName);\r
2476         Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength);\r
2477         UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength);\r
2478 \r
2479         //\r
2480         // Retrieve bridge BDF info and port number or namespace depending on type\r
2481         //\r
2482         TmpDevPath = NULL;\r
2483         Status = gBS->OpenProtocol(\r
2484             Dev->Handle,\r
2485             &gEfiDevicePathProtocolGuid,\r
2486             (VOID**)&TmpDevPath,\r
2487             gImageHandle,\r
2488             NULL,\r
2489             EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2490             );\r
2491         if (!EFI_ERROR(Status)) {\r
2492           Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath);\r
2493           return TRUE;\r
2494         }\r
2495 \r
2496         if (Dev->Name16 != NULL) {\r
2497           FreePool(Dev->Name16);\r
2498           Dev->Name16 = NULL;\r
2499         }\r
2500         if (Dev->NameZ != NULL) {\r
2501           FreePool(Dev->NameZ);\r
2502           Dev->NameZ = NULL;\r
2503         }\r
2504       }\r
2505     }\r
2506   }\r
2507 \r
2508   return FALSE;\r
2509 }\r
2510 \r
2511 /**\r
2512   Get devcie name through the component name protocol.\r
2513 \r
2514   @param[in]       Dev                The device which need to get name.\r
2515 \r
2516   @retval     TRUE        Find the name for this device.\r
2517   @retval     FALSE       Not found the name for this device.\r
2518 **/\r
2519 BOOLEAN\r
2520 OpalDriverGetDriverDeviceName(\r
2521   OPAL_DRIVER_DEVICE          *Dev\r
2522   )\r
2523 {\r
2524   EFI_HANDLE*                  AllHandlesBuffer;\r
2525   UINTN                        NumAllHandles;\r
2526   EFI_STATUS                   Status;\r
2527 \r
2528   if (Dev == NULL) {\r
2529     DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName Exiting, Dev=NULL\n"));\r
2530     return FALSE;\r
2531   }\r
2532 \r
2533   //\r
2534   // Iterate through ComponentName2 handles to get name, if fails, try ComponentName\r
2535   //\r
2536   if (Dev->Name16 == NULL) {\r
2537     DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n"));\r
2538     //\r
2539     // Find all EFI_HANDLES\r
2540     //\r
2541     Status = gBS->LocateHandleBuffer(\r
2542                  AllHandles,\r
2543                  NULL,\r
2544                  NULL,\r
2545                  &NumAllHandles,\r
2546                  &AllHandlesBuffer\r
2547                  );\r
2548     if (EFI_ERROR(Status)) {\r
2549       DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n", Status ));\r
2550       return FALSE;\r
2551     }\r
2552 \r
2553     //\r
2554     // Try component Name2\r
2555     //\r
2556     if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, FALSE)) {\r
2557       DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get device name, try ComponentName\n"));\r
2558       if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, TRUE)) {\r
2559         DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to get device name, skip device\n"));\r
2560         return FALSE;\r
2561       }\r
2562     }\r
2563   }\r
2564 \r
2565   return TRUE;\r
2566 }\r
2567 \r
2568 /**\r
2569   Main entry for this driver.\r
2570 \r
2571   @param ImageHandle     Image Handle this driver.\r
2572   @param SystemTable     Pointer to SystemTable.\r
2573 \r
2574   @retval EFI_SUCESS     This function always complete successfully.\r
2575 **/\r
2576 EFI_STATUS\r
2577 EFIAPI\r
2578 EfiDriverEntryPoint(\r
2579   IN EFI_HANDLE         ImageHandle,\r
2580   IN EFI_SYSTEM_TABLE*  SystemTable\r
2581   )\r
2582 {\r
2583   EFI_STATUS                     Status;\r
2584   EFI_EVENT                      EndOfDxeEvent;\r
2585 \r
2586   Status = EfiLibInstallDriverBindingComponentName2 (\r
2587              ImageHandle,\r
2588              SystemTable,\r
2589              &gOpalDriverBinding,\r
2590              ImageHandle,\r
2591              &gOpalComponentName,\r
2592              &gOpalComponentName2\r
2593              );\r
2594 \r
2595   if (EFI_ERROR(Status)) {\r
2596     DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle failed\n"));\r
2597     return Status ;\r
2598   }\r
2599 \r
2600   //\r
2601   // Initialize Driver object\r
2602   //\r
2603   ZeroMem(&mOpalDriver, sizeof(mOpalDriver));\r
2604   mOpalDriver.Handle = ImageHandle;\r
2605 \r
2606   Status = gBS->CreateEventEx (\r
2607                   EVT_NOTIFY_SIGNAL,\r
2608                   TPL_CALLBACK,\r
2609                   OpalEndOfDxeEventNotify,\r
2610                   NULL,\r
2611                   &gEfiEndOfDxeEventGroupGuid,\r
2612                   &EndOfDxeEvent\r
2613                   );\r
2614   ASSERT_EFI_ERROR (Status);\r
2615 \r
2616   //\r
2617   // Install Hii packages.\r
2618   //\r
2619   HiiInstall();\r
2620 \r
2621   return Status;\r
2622 }\r
2623 \r
2624 /**\r
2625   Tests to see if this driver supports a given controller.\r
2626 \r
2627   This function checks to see if the controller contains an instance of the\r
2628   EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the EFI_BLOCK_IO_PROTOCL\r
2629   and returns EFI_SUCCESS if it does.\r
2630 \r
2631   @param[in]  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
2632   @param[in]  ControllerHandle      The Handle of the controller to test. This Handle\r
2633                                     must support a protocol interface that supplies\r
2634                                     an I/O abstraction to the driver.\r
2635   @param[in]  RemainingDevicePath  This parameter is ignored.\r
2636 \r
2637   @retval EFI_SUCCESS               The device contains required protocols\r
2638   @retval EFI_ALREADY_STARTED       The device specified by ControllerHandle and\r
2639                                     RemainingDevicePath is already being managed by the driver\r
2640                                     specified by This.\r
2641   @retval EFI_ACCESS_DENIED         The device specified by ControllerHandle and\r
2642                                     RemainingDevicePath is already being managed by a different\r
2643                                     driver or an application that requires exclusive access.\r
2644                                     Currently not implemented.\r
2645   @retval EFI_UNSUPPORTED           The device does not contain requires protocols\r
2646 \r
2647 **/\r
2648 EFI_STATUS\r
2649 EFIAPI\r
2650 OpalEfiDriverBindingSupported(\r
2651   IN EFI_DRIVER_BINDING_PROTOCOL* This,\r
2652   IN EFI_HANDLE                   Controller,\r
2653   IN EFI_DEVICE_PATH_PROTOCOL*    RemainingDevicePath\r
2654   )\r
2655 {\r
2656   EFI_STATUS                              Status;\r
2657   EFI_STORAGE_SECURITY_COMMAND_PROTOCOL*  SecurityCommand;\r
2658   EFI_BLOCK_IO_PROTOCOL*                  BlkIo;\r
2659 \r
2660   if (mOpalEndOfDxe) {\r
2661     return EFI_UNSUPPORTED;\r
2662   }\r
2663 \r
2664   //\r
2665   // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller Handle.\r
2666   //\r
2667   Status = gBS->OpenProtocol(\r
2668     Controller,\r
2669     &gEfiStorageSecurityCommandProtocolGuid,\r
2670     ( VOID ** )&SecurityCommand,\r
2671     This->DriverBindingHandle,\r
2672     Controller,\r
2673     EFI_OPEN_PROTOCOL_BY_DRIVER\r
2674     );\r
2675 \r
2676   if (Status == EFI_ALREADY_STARTED) {\r
2677     return EFI_SUCCESS;\r
2678   }\r
2679 \r
2680   if (EFI_ERROR(Status)) {\r
2681     return Status;\r
2682   }\r
2683 \r
2684   //\r
2685   // Close protocol and reopen in Start call\r
2686   //\r
2687   gBS->CloseProtocol(\r
2688       Controller,\r
2689       &gEfiStorageSecurityCommandProtocolGuid,\r
2690       This->DriverBindingHandle,\r
2691       Controller\r
2692       );\r
2693 \r
2694   //\r
2695   // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL\r
2696   // function APIs\r
2697   //\r
2698   Status = gBS->OpenProtocol(\r
2699     Controller,\r
2700     &gEfiBlockIoProtocolGuid,\r
2701     (VOID **)&BlkIo,\r
2702     This->DriverBindingHandle,\r
2703     Controller,\r
2704     EFI_OPEN_PROTOCOL_BY_DRIVER\r
2705     );\r
2706 \r
2707   if (EFI_ERROR(Status)) {\r
2708     DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n"));\r
2709     return Status;\r
2710   }\r
2711 \r
2712   //\r
2713   // Close protocol and reopen in Start call\r
2714   //\r
2715   gBS->CloseProtocol(\r
2716     Controller,\r
2717     &gEfiBlockIoProtocolGuid,\r
2718     This->DriverBindingHandle,\r
2719     Controller\r
2720     );\r
2721 \r
2722   return EFI_SUCCESS;\r
2723 }\r
2724 \r
2725 /**\r
2726   Enables Opal Management on a supported device if available.\r
2727 \r
2728   The start function is designed to be called after the Opal UEFI Driver has confirmed the\r
2729   "controller", which is a child Handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.\r
2730   This function will complete the other necessary checks, such as verifying the device supports\r
2731   the correct version of Opal.  Upon verification, it will add the device to the\r
2732   Opal HII list in order to expose Opal managmeent options.\r
2733 \r
2734   @param[in]  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
2735   @param[in]  ControllerHandle      The Handle of the controller to start. This Handle\r
2736                                     must support a protocol interface that supplies\r
2737                                     an I/O abstraction to the driver.\r
2738   @param[in]  RemainingDevicePath   A pointer to the remaining portion of a device path.  This\r
2739                                     parameter is ignored by device drivers, and is optional for bus\r
2740                                     drivers. For a bus driver, if this parameter is NULL, then handles\r
2741                                     for all the children of Controller are created by this driver.\r
2742                                     If this parameter is not NULL and the first Device Path Node is\r
2743                                     not the End of Device Path Node, then only the Handle for the\r
2744                                     child device specified by the first Device Path Node of\r
2745                                     RemainingDevicePath is created by this driver.\r
2746                                     If the first Device Path Node of RemainingDevicePath is\r
2747                                     the End of Device Path Node, no child Handle is created by this\r
2748                                     driver.\r
2749 \r
2750   @retval EFI_SUCCESS               Opal management was enabled.\r
2751   @retval EFI_DEVICE_ERROR          The device could not be started due to a device error.Currently not implemented.\r
2752   @retval EFI_OUT_OF_RESOURCES      The request could not be completed due to a lack of resources.\r
2753   @retval Others                    The driver failed to start the device.\r
2754 \r
2755 **/\r
2756 EFI_STATUS\r
2757 EFIAPI\r
2758 OpalEfiDriverBindingStart(\r
2759   IN EFI_DRIVER_BINDING_PROTOCOL* This,\r
2760   IN EFI_HANDLE                   Controller,\r
2761   IN EFI_DEVICE_PATH_PROTOCOL*    RemainingDevicePath\r
2762   )\r
2763 {\r
2764   EFI_STATUS                  Status;\r
2765   EFI_BLOCK_IO_PROTOCOL       *BlkIo;\r
2766   OPAL_DRIVER_DEVICE          *Dev;\r
2767   OPAL_DRIVER_DEVICE          *Itr;\r
2768   BOOLEAN                     Result;\r
2769 \r
2770   Itr = mOpalDriver.DeviceList;\r
2771   while (Itr != NULL) {\r
2772     if (Controller == Itr->Handle) {\r
2773       return EFI_SUCCESS;\r
2774     }\r
2775     Itr = Itr->Next;\r
2776   }\r
2777 \r
2778   //\r
2779   // Create internal device for tracking.  This allows all disks to be tracked\r
2780   // by same HII form\r
2781   //\r
2782   Dev = (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE));\r
2783   if (Dev == NULL) {\r
2784     return EFI_OUT_OF_RESOURCES;\r
2785   }\r
2786   Dev->Handle = Controller;\r
2787 \r
2788   //\r
2789   // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal supported checks\r
2790   //\r
2791   Status = gBS->OpenProtocol(\r
2792     Controller,\r
2793     &gEfiStorageSecurityCommandProtocolGuid,\r
2794     (VOID **)&Dev->Sscp,\r
2795     This->DriverBindingHandle,\r
2796     Controller,\r
2797     EFI_OPEN_PROTOCOL_BY_DRIVER\r
2798     );\r
2799   if (EFI_ERROR(Status)) {\r
2800     FreePool(Dev);\r
2801     return Status;\r
2802   }\r
2803 \r
2804   //\r
2805   // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL\r
2806   // function APIs\r
2807   //\r
2808   Status = gBS->OpenProtocol(\r
2809     Controller,\r
2810     &gEfiBlockIoProtocolGuid,\r
2811     (VOID **)&BlkIo,\r
2812     This->DriverBindingHandle,\r
2813     Controller,\r
2814     EFI_OPEN_PROTOCOL_BY_DRIVER\r
2815     );\r
2816   if (EFI_ERROR(Status)) {\r
2817     //\r
2818     // Close storage security that was opened\r
2819     //\r
2820     gBS->CloseProtocol(\r
2821         Controller,\r
2822         &gEfiStorageSecurityCommandProtocolGuid,\r
2823         This->DriverBindingHandle,\r
2824         Controller\r
2825         );\r
2826 \r
2827     FreePool(Dev);\r
2828     return Status;\r
2829   }\r
2830 \r
2831   //\r
2832   // Save mediaId\r
2833   //\r
2834   Dev->MediaId = BlkIo->Media->MediaId;\r
2835 \r
2836   gBS->CloseProtocol(\r
2837     Controller,\r
2838     &gEfiBlockIoProtocolGuid,\r
2839     This->DriverBindingHandle,\r
2840     Controller\r
2841     );\r
2842 \r
2843   //\r
2844   // Acquire Ascii printable name of child, if not found, then ignore device\r
2845   //\r
2846   Result = OpalDriverGetDriverDeviceName (Dev);\r
2847   if (!Result) {\r
2848     goto Done;\r
2849   }\r
2850 \r
2851   Status = OpalDiskInitialize (Dev);\r
2852   if (EFI_ERROR (Status)) {\r
2853     goto Done;\r
2854   }\r
2855 \r
2856   AddDeviceToTail(Dev);\r
2857 \r
2858   //\r
2859   // Check if device is locked and prompt for password.\r
2860   //\r
2861   OpalDriverRequestPassword (Dev, L"Unlock:");\r
2862 \r
2863   //\r
2864   // Process OPAL request from last boot.\r
2865   //\r
2866   ProcessOpalRequest (Dev);\r
2867 \r
2868   return EFI_SUCCESS;\r
2869 \r
2870 Done:\r
2871   //\r
2872   // free device, close protocols and exit\r
2873   //\r
2874   gBS->CloseProtocol(\r
2875       Controller,\r
2876       &gEfiStorageSecurityCommandProtocolGuid,\r
2877       This->DriverBindingHandle,\r
2878       Controller\r
2879       );\r
2880 \r
2881   FreePool(Dev);\r
2882 \r
2883   return EFI_DEVICE_ERROR;\r
2884 }\r
2885 \r
2886 /**\r
2887   Stop this driver on Controller.\r
2888 \r
2889   @param  This              Protocol instance pointer.\r
2890   @param  Controller        Handle of device to stop driver on\r
2891   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
2892                             children is zero stop the entire bus driver.\r
2893   @param  ChildHandleBuffer List of Child Handles to Stop.\r
2894 \r
2895   @retval EFI_SUCCESS       This driver is removed Controller.\r
2896   @retval other             This driver could not be removed from this device.\r
2897 \r
2898 **/\r
2899 EFI_STATUS\r
2900 EFIAPI\r
2901 OpalEfiDriverBindingStop(\r
2902   EFI_DRIVER_BINDING_PROTOCOL*    This,\r
2903   EFI_HANDLE                      Controller,\r
2904   UINTN                           NumberOfChildren,\r
2905   EFI_HANDLE*                     ChildHandleBuffer\r
2906   )\r
2907 {\r
2908   OPAL_DRIVER_DEVICE*   Itr;\r
2909 \r
2910   Itr = mOpalDriver.DeviceList;\r
2911 \r
2912   //\r
2913   // does Controller match any of the devices we are managing for Opal\r
2914   //\r
2915   while (Itr != NULL) {\r
2916     if (Itr->Handle == Controller) {\r
2917       OpalDriverStopDevice (Itr);\r
2918       return EFI_SUCCESS;\r
2919     }\r
2920 \r
2921     Itr = Itr->Next;\r
2922   }\r
2923 \r
2924   return EFI_NOT_FOUND;\r
2925 }\r
2926 \r
2927 \r
2928 /**\r
2929   Unloads UEFI Driver.  Very useful for debugging and testing.\r
2930 \r
2931   @param ImageHandle            Image Handle this driver.\r
2932 \r
2933   @retval EFI_SUCCESS           This function always complete successfully.\r
2934   @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.\r
2935 **/\r
2936 EFI_STATUS\r
2937 EFIAPI\r
2938 OpalEfiDriverUnload (\r
2939   IN EFI_HANDLE ImageHandle\r
2940   )\r
2941 {\r
2942   EFI_STATUS                     Status;\r
2943   OPAL_DRIVER_DEVICE                   *Itr;\r
2944 \r
2945   Status = EFI_SUCCESS;\r
2946 \r
2947   if (ImageHandle != gImageHandle) {\r
2948     return (EFI_INVALID_PARAMETER);\r
2949   }\r
2950 \r
2951   //\r
2952   // Uninstall any interface added to each device by us\r
2953   //\r
2954   while (mOpalDriver.DeviceList) {\r
2955     Itr = mOpalDriver.DeviceList;\r
2956     //\r
2957     // Remove OPAL_DRIVER_DEVICE from the list\r
2958     // it updates the controllerList pointer\r
2959     //\r
2960     OpalDriverStopDevice(Itr);\r
2961   }\r
2962 \r
2963   //\r
2964   // Uninstall the HII capability\r
2965   //\r
2966   Status = HiiUninstall();\r
2967 \r
2968   return Status;\r
2969 }\r
2970 \r