]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c
SecurityPkg OpalPasswordDxe: Check BlockSid capability before send command.
[mirror_edk2.git] / SecurityPkg / Tcg / Opal / OpalPasswordDxe / OpalDriver.c
1 /** @file
2 Entrypoint of Opal UEFI Driver and contains all the logic to
3 register for new Opal device instances.
4
5 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 // This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances and installs an
17 // HII GUI to manage Opal features if the device is Opal capable
18 // If the Opal device is being managed by the UEFI Driver, it shall provide a popup
19 // window during boot requesting a user password
20
21 #include "OpalDriver.h"
22 #include "OpalDriverPrivate.h"
23 #include "OpalHii.h"
24
25 OPAL_DRIVER mOpalDriver;
26
27 #define MAX_PASSWORD_SIZE 32
28 #define MAX_PASSWORD_TRY_COUNT 5
29
30 //
31 // Globals
32 //
33 EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = {
34 OpalEfiDriverBindingSupported,
35 OpalEfiDriverBindingStart,
36 OpalEfiDriverBindingStop,
37 0x1b,
38 NULL,
39 NULL
40 };
41
42
43 /**
44 Add new device to the global device list.
45
46 @param Dev New create device.
47
48 **/
49 VOID
50 AddDeviceToTail(
51 IN OPAL_DRIVER_DEVICE *Dev
52 )
53 {
54 OPAL_DRIVER_DEVICE *TmpDev;
55
56 if (mOpalDriver.DeviceList == NULL) {
57 mOpalDriver.DeviceList = Dev;
58 } else {
59 TmpDev = mOpalDriver.DeviceList;
60 while (TmpDev->Next != NULL) {
61 TmpDev = TmpDev->Next;
62 }
63
64 TmpDev->Next = Dev;
65 }
66 }
67
68 /**
69 Remove one device in the global device list.
70
71 @param Dev The device need to be removed.
72
73 **/
74 VOID
75 RemoveDevice (
76 IN OPAL_DRIVER_DEVICE *Dev
77 )
78 {
79 OPAL_DRIVER_DEVICE *TmpDev;
80
81 if (mOpalDriver.DeviceList == NULL) {
82 return;
83 }
84
85 if (mOpalDriver.DeviceList == Dev) {
86 mOpalDriver.DeviceList = NULL;
87 return;
88 }
89
90 TmpDev = mOpalDriver.DeviceList;
91 while (TmpDev->Next != NULL) {
92 if (TmpDev->Next == Dev) {
93 TmpDev->Next = Dev->Next;
94 break;
95 }
96 }
97 }
98
99 /**
100 Get current device count.
101
102 @retval return the current created device count.
103
104 **/
105 UINT8
106 GetDeviceCount (
107 VOID
108 )
109 {
110 UINT8 Count;
111 OPAL_DRIVER_DEVICE *TmpDev;
112
113 Count = 0;
114 TmpDev = mOpalDriver.DeviceList;
115
116 while (TmpDev != NULL) {
117 Count++;
118 TmpDev = TmpDev->Next;
119 }
120
121 return Count;
122 }
123
124 /**
125 Get password input from the popup windows, and unlock the device.
126
127 @param[in] Dev The device which need to be unlock.
128 @param[out] PressEsc Whether user escape function through Press ESC.
129
130 @retval Password string if success. NULL if failed.
131
132 **/
133 CHAR8 *
134 OpalDriverPopUpHddPassword (
135 IN OPAL_DRIVER_DEVICE *Dev,
136 OUT BOOLEAN *PressEsc
137 )
138 {
139 EFI_INPUT_KEY InputKey;
140 UINTN InputLength;
141 CHAR16 Mask[MAX_PASSWORD_SIZE + 1];
142 CHAR16 Unicode[MAX_PASSWORD_SIZE + 1];
143 CHAR8 *Ascii;
144 CHAR16 *PopUpString;
145 UINTN StrLength;
146
147 ZeroMem(Unicode, sizeof(Unicode));
148 ZeroMem(Mask, sizeof(Mask));
149
150 StrLength = StrLen(Dev->Name16);
151 PopUpString = (CHAR16*) AllocateZeroPool ((8 + StrLength) * 2);
152 *PressEsc = FALSE;
153
154 if (Dev->Name16 == NULL) {
155 UnicodeSPrint(PopUpString, StrLen(L"Unlock Disk") + 1, L"Unlock Disk");
156 } else {
157 UnicodeSPrint(PopUpString, StrLen(L"Unlock ") + StrLength + 1, L"Unlock %s", Dev->Name16);
158 }
159
160 gST->ConOut->ClearScreen(gST->ConOut);
161
162 InputLength = 0;
163 while (TRUE) {
164 Mask[InputLength] = L'_';
165 CreatePopUp(
166 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
167 &InputKey,
168 PopUpString,
169 L"---------------------",
170 Mask,
171 NULL
172 );
173
174 //
175 // Check key.
176 //
177 if (InputKey.ScanCode == SCAN_NULL) {
178 //
179 // password finished
180 //
181 if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {
182 //
183 // Add the null terminator.
184 //
185 Unicode[InputLength] = 0;
186 InputLength++;
187 break;
188 } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
189 (InputKey.UnicodeChar == CHAR_TAB) ||
190 (InputKey.UnicodeChar == CHAR_LINEFEED)
191 ) {
192 continue;
193 } else {
194 //
195 // delete last key entered
196 //
197 if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
198 if (InputLength > 0) {
199 Unicode[InputLength] = 0;
200 Mask[InputLength] = 0;
201 InputLength--;
202 }
203 } else {
204 //
205 // add Next key entry
206 //
207 Unicode[InputLength] = InputKey.UnicodeChar;
208 Mask[InputLength] = L'*';
209 InputLength++;
210 if (InputLength == MAX_PASSWORD_SIZE) {
211 //
212 // Add the null terminator.
213 //
214 Unicode[InputLength] = 0;
215 Mask[InputLength] = 0;
216 break;
217 }
218 }
219 }
220 }
221
222 //
223 // exit on ESC
224 //
225 if (InputKey.ScanCode == SCAN_ESC) {
226 *PressEsc = TRUE;
227 break;
228 }
229 }
230
231 gST->ConOut->ClearScreen(gST->ConOut);
232
233 if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {
234 return NULL;
235 }
236
237 Ascii = AllocateZeroPool (MAX_PASSWORD_SIZE + 1);
238 if (Ascii == NULL) {
239 return NULL;
240 }
241
242 UnicodeStrToAsciiStr(Unicode, Ascii);
243
244 return Ascii;
245 }
246
247 /**
248 Check if disk is locked, show popup window and ask for password if it is
249
250 @param[in] Dev The device which need to be unlock.
251
252 **/
253 VOID
254 OpalDriverRequestPassword (
255 OPAL_DRIVER_DEVICE *Dev
256 )
257 {
258 UINT8 Count;
259 BOOLEAN IsEnabled;
260 CHAR8 *Password;
261 UINT32 PasswordLen;
262 TCG_RESULT Ret;
263 EFI_INPUT_KEY Key;
264 OPAL_SESSION Session;
265 BOOLEAN PressEsc;
266
267 if (Dev == NULL) {
268 return;
269 }
270
271 Count = 0;
272
273 IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);
274 if (IsEnabled) {
275 ZeroMem(&Session, sizeof(Session));
276 Session.Sscp = Dev->OpalDisk.Sscp;
277 Session.MediaId = Dev->OpalDisk.MediaId;
278 Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
279
280 while (Count < MAX_PASSWORD_TRY_COUNT) {
281 Password = OpalDriverPopUpHddPassword (Dev, &PressEsc);
282 if (PressEsc) {
283 //
284 // User not input password and press ESC, keep device in lock status and continue boot.
285 //
286 do {
287 CreatePopUp (
288 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
289 &Key,
290 L"Confirm: Not unlock device and continue boot?.",
291 L"Press ENTER to confirm, Press Esc to input password",
292 NULL
293 );
294 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
295
296 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
297 gST->ConOut->ClearScreen(gST->ConOut);
298 //
299 // Keep lock and continue boot.
300 //
301 return;
302 } else {
303 //
304 // Let user input password again.
305 //
306 continue;
307 }
308 }
309
310 if (Password == NULL) {
311 Count ++;
312 continue;
313 }
314 PasswordLen = (UINT32) AsciiStrLen(Password);
315
316 if (OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature)) {
317 Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
318 } else {
319 Ret = OpalSupportLock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
320 if (Ret == TcgResultSuccess) {
321 Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
322 }
323 }
324
325 if (Password != NULL) {
326 ZeroMem (Password, PasswordLen);
327 FreePool (Password);
328 }
329
330 if (Ret == TcgResultSuccess) {
331 break;
332 }
333
334 Count++;
335
336 do {
337 CreatePopUp (
338 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
339 &Key,
340 L"Invalid password.",
341 L"Press ENTER to retry",
342 NULL
343 );
344 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
345 }
346
347 if (Count >= MAX_PASSWORD_TRY_COUNT) {
348 do {
349 CreatePopUp (
350 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
351 &Key,
352 L"Opal password retry count is expired. Keep lock and continue boot.",
353 L"Press ENTER to continue",
354 NULL
355 );
356 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
357 gST->ConOut->ClearScreen(gST->ConOut);
358 }
359 }
360 }
361
362 /**
363 Get devcie list info.
364
365 @retval return the device list pointer.
366 **/
367 OPAL_DRIVER_DEVICE*
368 OpalDriverGetDeviceList(
369 VOID
370 )
371 {
372 return mOpalDriver.DeviceList;
373 }
374
375 /**
376 ReadyToBoot callback to send BlockSid command.
377
378 @param Event Pointer to this event
379 @param Context Event hanlder private Data
380
381 **/
382 VOID
383 EFIAPI
384 ReadyToBootCallback (
385 IN EFI_EVENT Event,
386 IN VOID *Context
387 )
388 {
389 EFI_STATUS Status;
390 OPAL_DRIVER_DEVICE* Itr;
391 TCG_RESULT Result;
392 OPAL_EXTRA_INFO_VAR OpalExtraInfo;
393 UINTN DataSize;
394 OPAL_SESSION Session;
395
396 gBS->CloseEvent (Event);
397
398 DataSize = sizeof (OPAL_EXTRA_INFO_VAR);
399 Status = gRT->GetVariable (
400 OPAL_EXTRA_INFO_VAR_NAME,
401 &gOpalExtraInfoVariableGuid,
402 NULL,
403 &DataSize,
404 &OpalExtraInfo
405 );
406 if (EFI_ERROR (Status)) {
407 return;
408 }
409
410 if (OpalExtraInfo.EnableBlockSid == TRUE) {
411 //
412 // Send BlockSID command to each Opal disk
413 //
414 Itr = mOpalDriver.DeviceList;
415 while (Itr != NULL) {
416 if (Itr->OpalDisk.SupportedAttributes.BlockSid) {
417 ZeroMem(&Session, sizeof(Session));
418 Session.Sscp = Itr->OpalDisk.Sscp;
419 Session.MediaId = Itr->OpalDisk.MediaId;
420 Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId;
421
422 Result = OpalBlockSid (&Session, TRUE); // HardwareReset must always be TRUE
423 if (Result != TcgResultSuccess) {
424 DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n"));
425 break;
426 }
427 }
428
429 Itr = Itr->Next;
430 }
431 }
432 }
433
434 /**
435 Stop this Controller.
436
437 @param Dev The device need to be stopped.
438
439 **/
440 VOID
441 OpalDriverStopDevice (
442 OPAL_DRIVER_DEVICE *Dev
443 )
444 {
445 //
446 // free each name
447 //
448 FreePool(Dev->Name16);
449
450 //
451 // remove OPAL_DRIVER_DEVICE from the list
452 // it updates the controllerList pointer
453 //
454 RemoveDevice(Dev);
455
456 //
457 // close protocols that were opened
458 //
459 gBS->CloseProtocol(
460 Dev->Handle,
461 &gEfiStorageSecurityCommandProtocolGuid,
462 gOpalDriverBinding.DriverBindingHandle,
463 Dev->Handle
464 );
465
466 gBS->CloseProtocol(
467 Dev->Handle,
468 &gEfiBlockIoProtocolGuid,
469 gOpalDriverBinding.DriverBindingHandle,
470 Dev->Handle
471 );
472
473 FreePool(Dev);
474 }
475
476 /**
477 Get devcie name through the component name protocol.
478
479 @param[in] AllHandlesBuffer The handle buffer for current system.
480 @param[in] NumAllHandles The number of handles for the handle buffer.
481 @param[in] Dev The device which need to get name.
482 @param[in] UseComp1 Whether use component name or name2 protocol.
483
484 @retval TRUE Find the name for this device.
485 @retval FALSE Not found the name for this device.
486 **/
487 BOOLEAN
488 OpalDriverGetDeviceNameByProtocol(
489 EFI_HANDLE *AllHandlesBuffer,
490 UINTN NumAllHandles,
491 OPAL_DRIVER_DEVICE *Dev,
492 BOOLEAN UseComp1
493 )
494 {
495 EFI_HANDLE* ProtocolHandlesBuffer;
496 UINTN NumProtocolHandles;
497 EFI_STATUS Status;
498 EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name and componentName2 have same layout
499 EFI_GUID Protocol;
500 UINTN StrLength;
501 EFI_DEVICE_PATH_PROTOCOL* TmpDevPath;
502 UINTN Index1;
503 UINTN Index2;
504 EFI_HANDLE TmpHandle;
505 CHAR16 *DevName;
506
507 if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) {
508 return FALSE;
509 }
510
511 Protocol = UseComp1 ? gEfiComponentNameProtocolGuid : gEfiComponentName2ProtocolGuid;
512
513 //
514 // Find all EFI_HANDLES with protocol
515 //
516 Status = gBS->LocateHandleBuffer(
517 ByProtocol,
518 &Protocol,
519 NULL,
520 &NumProtocolHandles,
521 &ProtocolHandlesBuffer
522 );
523 if (EFI_ERROR(Status)) {
524 return FALSE;
525 }
526
527
528 //
529 // Exit early if no supported devices
530 //
531 if (NumProtocolHandles == 0) {
532 return FALSE;
533 }
534
535 //
536 // Get printable name by iterating through all protocols
537 // using the handle as the child, and iterate through all handles for the controller
538 // exit loop early once found, if not found, then delete device
539 // storage security protocol instances already exist, add them to internal list
540 //
541 Status = EFI_DEVICE_ERROR;
542 for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) {
543 DevName = NULL;
544
545 if (Dev->Name16 != NULL) {
546 return TRUE;
547 }
548
549 TmpHandle = ProtocolHandlesBuffer[Index1];
550
551 Status = gBS->OpenProtocol(
552 TmpHandle,
553 &Protocol,
554 (VOID**)&Cnp1_2,
555 gImageHandle,
556 NULL,
557 EFI_OPEN_PROTOCOL_GET_PROTOCOL
558 );
559 if (EFI_ERROR(Status) || Cnp1_2 == NULL) {
560 continue;
561 }
562
563 //
564 // Use all handles array as controller handle
565 //
566 for (Index2 = 0; Index2 < NumAllHandles; Index2++) {
567 Status = Cnp1_2->GetControllerName(
568 Cnp1_2,
569 AllHandlesBuffer[Index2],
570 Dev->Handle,
571 LANGUAGE_ISO_639_2_ENGLISH,
572 &DevName
573 );
574 if (EFI_ERROR(Status)) {
575 Status = Cnp1_2->GetControllerName(
576 Cnp1_2,
577 AllHandlesBuffer[Index2],
578 Dev->Handle,
579 LANGUAGE_RFC_3066_ENGLISH,
580 &DevName
581 );
582 }
583 if (!EFI_ERROR(Status) && DevName != NULL) {
584 StrLength = StrLen(DevName) + 1; // Add one for NULL terminator
585 Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16));
586 ASSERT (Dev->Name16 != NULL);
587 StrCpyS (Dev->Name16, StrLength, DevName);
588 Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength);
589 UnicodeStrToAsciiStr(DevName, Dev->NameZ);
590
591 //
592 // Retrieve bridge BDF info and port number or namespace depending on type
593 //
594 TmpDevPath = NULL;
595 Status = gBS->OpenProtocol(
596 Dev->Handle,
597 &gEfiDevicePathProtocolGuid,
598 (VOID**)&TmpDevPath,
599 gImageHandle,
600 NULL,
601 EFI_OPEN_PROTOCOL_GET_PROTOCOL
602 );
603 if (!EFI_ERROR(Status)) {
604 Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath);
605 return TRUE;
606 }
607
608 if (Dev->Name16 != NULL) {
609 FreePool(Dev->Name16);
610 Dev->Name16 = NULL;
611 }
612 if (Dev->NameZ != NULL) {
613 FreePool(Dev->NameZ);
614 Dev->NameZ = NULL;
615 }
616 }
617 }
618 }
619
620 return FALSE;
621 }
622
623 /**
624 Get devcie name through the component name protocol.
625
626 @param[in] Dev The device which need to get name.
627
628 @retval TRUE Find the name for this device.
629 @retval FALSE Not found the name for this device.
630 **/
631 BOOLEAN
632 OpalDriverGetDriverDeviceName(
633 OPAL_DRIVER_DEVICE *Dev
634 )
635 {
636 EFI_HANDLE* AllHandlesBuffer;
637 UINTN NumAllHandles;
638 EFI_STATUS Status;
639
640 if (Dev == NULL) {
641 DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName Exiting, Dev=NULL\n"));
642 return FALSE;
643 }
644
645 //
646 // Iterate through ComponentName2 handles to get name, if fails, try ComponentName
647 //
648 if (Dev->Name16 == NULL) {
649 DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n"));
650 //
651 // Find all EFI_HANDLES
652 //
653 Status = gBS->LocateHandleBuffer(
654 AllHandles,
655 NULL,
656 NULL,
657 &NumAllHandles,
658 &AllHandlesBuffer
659 );
660 if (EFI_ERROR(Status)) {
661 DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n", Status ));
662 return FALSE;
663 }
664
665 //
666 // Try component Name2
667 //
668 if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, FALSE)) {
669 DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get device name, try ComponentName\n"));
670 if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, TRUE)) {
671 DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to get device name, skip device\n"));
672 return FALSE;
673 }
674 }
675 }
676
677 return TRUE;
678 }
679
680 /**
681 Main entry for this driver.
682
683 @param ImageHandle Image Handle this driver.
684 @param SystemTable Pointer to SystemTable.
685
686 @retval EFI_SUCESS This function always complete successfully.
687 **/
688 EFI_STATUS
689 EFIAPI
690 EfiDriverEntryPoint(
691 IN EFI_HANDLE ImageHandle,
692 IN EFI_SYSTEM_TABLE* SystemTable
693 )
694 {
695 EFI_STATUS Status;
696 EFI_EVENT ReadyToBootEvent;
697
698 Status = EfiLibInstallDriverBindingComponentName2 (
699 ImageHandle,
700 SystemTable,
701 &gOpalDriverBinding,
702 ImageHandle,
703 &gOpalComponentName,
704 &gOpalComponentName2
705 );
706
707 if (EFI_ERROR(Status)) {
708 DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle failed\n"));
709 return Status ;
710 }
711
712 //
713 // Initialize Driver object
714 //
715 ZeroMem(&mOpalDriver, sizeof(mOpalDriver));
716 mOpalDriver.Handle = ImageHandle;
717
718 //
719 // register a ReadyToBoot event callback for sending BlockSid command
720 //
721 Status = EfiCreateEventReadyToBootEx (
722 TPL_CALLBACK,
723 ReadyToBootCallback,
724 (VOID *) &ImageHandle,
725 &ReadyToBootEvent
726 );
727
728 //
729 // Install Hii packages.
730 //
731 HiiInstall();
732
733 return Status;
734 }
735
736 /**
737 Tests to see if this driver supports a given controller.
738
739 This function checks to see if the controller contains an instance of the
740 EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the EFI_BLOCK_IO_PROTOCL
741 and returns EFI_SUCCESS if it does.
742
743 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
744 @param[in] ControllerHandle The Handle of the controller to test. This Handle
745 must support a protocol interface that supplies
746 an I/O abstraction to the driver.
747 @param[in] RemainingDevicePath This parameter is ignored.
748
749 @retval EFI_SUCCESS The device contains required protocols
750 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
751 RemainingDevicePath is already being managed by the driver
752 specified by This.
753 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
754 RemainingDevicePath is already being managed by a different
755 driver or an application that requires exclusive access.
756 Currently not implemented.
757 @retval EFI_UNSUPPORTED The device does not contain requires protocols
758
759 **/
760 EFI_STATUS
761 EFIAPI
762 OpalEfiDriverBindingSupported(
763 IN EFI_DRIVER_BINDING_PROTOCOL* This,
764 IN EFI_HANDLE Controller,
765 IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
766 )
767 {
768 EFI_STATUS Status;
769 EFI_STORAGE_SECURITY_COMMAND_PROTOCOL* SecurityCommand;
770 EFI_BLOCK_IO_PROTOCOL* BlkIo;
771
772 //
773 // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller Handle.
774 //
775 Status = gBS->OpenProtocol(
776 Controller,
777 &gEfiStorageSecurityCommandProtocolGuid,
778 ( VOID ** )&SecurityCommand,
779 This->DriverBindingHandle,
780 Controller,
781 EFI_OPEN_PROTOCOL_BY_DRIVER
782 );
783
784 if (Status == EFI_ALREADY_STARTED) {
785 return EFI_SUCCESS;
786 }
787
788 if (EFI_ERROR(Status)) {
789 return Status;
790 }
791
792 //
793 // Close protocol and reopen in Start call
794 //
795 gBS->CloseProtocol(
796 Controller,
797 &gEfiStorageSecurityCommandProtocolGuid,
798 This->DriverBindingHandle,
799 Controller
800 );
801
802 //
803 // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
804 // function APIs
805 //
806 Status = gBS->OpenProtocol(
807 Controller,
808 &gEfiBlockIoProtocolGuid,
809 (VOID **)&BlkIo,
810 This->DriverBindingHandle,
811 Controller,
812 EFI_OPEN_PROTOCOL_BY_DRIVER
813 );
814
815 if (EFI_ERROR(Status)) {
816 DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n"));
817 return Status;
818 }
819
820 //
821 // Close protocol and reopen in Start call
822 //
823 gBS->CloseProtocol(
824 Controller,
825 &gEfiBlockIoProtocolGuid,
826 This->DriverBindingHandle,
827 Controller
828 );
829
830 return EFI_SUCCESS;
831 }
832
833 /**
834 Enables Opal Management on a supported device if available.
835
836 The start function is designed to be called after the Opal UEFI Driver has confirmed the
837 "controller", which is a child Handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.
838 This function will complete the other necessary checks, such as verifying the device supports
839 the correct version of Opal. Upon verification, it will add the device to the
840 Opal HII list in order to expose Opal managmeent options.
841
842 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
843 @param[in] ControllerHandle The Handle of the controller to start. This Handle
844 must support a protocol interface that supplies
845 an I/O abstraction to the driver.
846 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
847 parameter is ignored by device drivers, and is optional for bus
848 drivers. For a bus driver, if this parameter is NULL, then handles
849 for all the children of Controller are created by this driver.
850 If this parameter is not NULL and the first Device Path Node is
851 not the End of Device Path Node, then only the Handle for the
852 child device specified by the first Device Path Node of
853 RemainingDevicePath is created by this driver.
854 If the first Device Path Node of RemainingDevicePath is
855 the End of Device Path Node, no child Handle is created by this
856 driver.
857
858 @retval EFI_SUCCESS Opal management was enabled.
859 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
860 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
861 @retval Others The driver failed to start the device.
862
863 **/
864 EFI_STATUS
865 EFIAPI
866 OpalEfiDriverBindingStart(
867 IN EFI_DRIVER_BINDING_PROTOCOL* This,
868 IN EFI_HANDLE Controller,
869 IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
870 )
871 {
872 EFI_STATUS Status;
873 EFI_BLOCK_IO_PROTOCOL *BlkIo;
874 OPAL_DRIVER_DEVICE *Dev;
875 OPAL_DRIVER_DEVICE *Itr;
876 BOOLEAN Result;
877
878 Itr = mOpalDriver.DeviceList;
879 while (Itr != NULL) {
880 if (Controller == Itr->Handle) {
881 return EFI_SUCCESS;
882 }
883 Itr = Itr->Next;
884 }
885
886 //
887 // Create internal device for tracking. This allows all disks to be tracked
888 // by same HII form
889 //
890 Dev = (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE));
891 if (Dev == NULL) {
892 return EFI_OUT_OF_RESOURCES;
893 }
894 Dev->Handle = Controller;
895
896 //
897 // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal supported checks
898 //
899 Status = gBS->OpenProtocol(
900 Controller,
901 &gEfiStorageSecurityCommandProtocolGuid,
902 (VOID **)&Dev->Sscp,
903 This->DriverBindingHandle,
904 Controller,
905 EFI_OPEN_PROTOCOL_BY_DRIVER
906 );
907 if (EFI_ERROR(Status)) {
908 FreePool(Dev);
909 return Status;
910 }
911
912 //
913 // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
914 // function APIs
915 //
916 Status = gBS->OpenProtocol(
917 Controller,
918 &gEfiBlockIoProtocolGuid,
919 (VOID **)&BlkIo,
920 This->DriverBindingHandle,
921 Controller,
922 EFI_OPEN_PROTOCOL_BY_DRIVER
923 );
924 if (EFI_ERROR(Status)) {
925 //
926 // Close storage security that was opened
927 //
928 gBS->CloseProtocol(
929 Controller,
930 &gEfiStorageSecurityCommandProtocolGuid,
931 This->DriverBindingHandle,
932 Controller
933 );
934
935 FreePool(Dev);
936 return Status;
937 }
938
939 //
940 // Save mediaId
941 //
942 Dev->MediaId = BlkIo->Media->MediaId;
943
944 gBS->CloseProtocol(
945 Controller,
946 &gEfiBlockIoProtocolGuid,
947 This->DriverBindingHandle,
948 Controller
949 );
950
951 //
952 // Acquire Ascii printable name of child, if not found, then ignore device
953 //
954 Result = OpalDriverGetDriverDeviceName (Dev);
955 if (!Result) {
956 goto Done;
957 }
958
959 Status = OpalDiskInitialize (Dev);
960 if (EFI_ERROR (Status)) {
961 goto Done;
962 }
963
964 AddDeviceToTail(Dev);
965
966 //
967 // check if device is locked and prompt for password
968 //
969 OpalDriverRequestPassword (Dev);
970
971 return EFI_SUCCESS;
972
973 Done:
974 //
975 // free device, close protocols and exit
976 //
977 gBS->CloseProtocol(
978 Controller,
979 &gEfiStorageSecurityCommandProtocolGuid,
980 This->DriverBindingHandle,
981 Controller
982 );
983
984 FreePool(Dev);
985
986 return EFI_DEVICE_ERROR;
987 }
988
989 /**
990 Stop this driver on Controller.
991
992 @param This Protocol instance pointer.
993 @param Controller Handle of device to stop driver on
994 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
995 children is zero stop the entire bus driver.
996 @param ChildHandleBuffer List of Child Handles to Stop.
997
998 @retval EFI_SUCCESS This driver is removed Controller.
999 @retval other This driver could not be removed from this device.
1000
1001 **/
1002 EFI_STATUS
1003 EFIAPI
1004 OpalEfiDriverBindingStop(
1005 EFI_DRIVER_BINDING_PROTOCOL* This,
1006 EFI_HANDLE Controller,
1007 UINTN NumberOfChildren,
1008 EFI_HANDLE* ChildHandleBuffer
1009 )
1010 {
1011 OPAL_DRIVER_DEVICE* Itr;
1012
1013 Itr = mOpalDriver.DeviceList;
1014
1015 //
1016 // does Controller match any of the devices we are managing for Opal
1017 //
1018 while (Itr != NULL) {
1019 if (Itr->Handle == Controller) {
1020 OpalDriverStopDevice (Itr);
1021 return EFI_SUCCESS;
1022 }
1023
1024 Itr = Itr->Next;
1025 }
1026
1027 return EFI_NOT_FOUND;
1028 }
1029
1030
1031 /**
1032 Unloads UEFI Driver. Very useful for debugging and testing.
1033
1034 @param ImageHandle Image Handle this driver.
1035
1036 @retval EFI_SUCCESS This function always complete successfully.
1037 @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.
1038 **/
1039 EFI_STATUS
1040 EFIAPI
1041 OpalEfiDriverUnload (
1042 IN EFI_HANDLE ImageHandle
1043 )
1044 {
1045 EFI_STATUS Status;
1046 OPAL_DRIVER_DEVICE *Itr;
1047
1048 Status = EFI_SUCCESS;
1049
1050 if (ImageHandle != gImageHandle) {
1051 return (EFI_INVALID_PARAMETER);
1052 }
1053
1054 //
1055 // Uninstall any interface added to each device by us
1056 //
1057 while (mOpalDriver.DeviceList) {
1058 Itr = mOpalDriver.DeviceList;
1059 //
1060 // Remove OPAL_DRIVER_DEVICE from the list
1061 // it updates the controllerList pointer
1062 //
1063 OpalDriverStopDevice(Itr);
1064 }
1065
1066 //
1067 // Uninstall the HII capability
1068 //
1069 Status = HiiUninstall();
1070
1071 return Status;
1072 }
1073