2 HddPassword PEI module which is used to unlock HDD password for S3.
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "HddPasswordPei.h"
19 EFI_GUID mHddPasswordDeviceInfoGuid
= HDD_PASSWORD_DEVICE_INFO_GUID
;
23 Send unlock hdd password cmd through ATA PassThru PPI.
25 @param[in] AtaPassThru The pointer to the ATA PassThru PPI.
26 @param[in] Port The port number of the ATA device.
27 @param[in] PortMultiplierPort The port multiplier port number of the ATA device.
28 @param[in] Identifier The identifier to set user or master password.
29 @param[in] Password The hdd password of attached ATA device.
31 @retval EFI_SUCCESS Successful to send unlock hdd password cmd.
32 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
33 @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.
34 @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd.
39 IN EDKII_PEI_ATA_PASS_THRU_PPI
*AtaPassThru
,
41 IN UINT16 PortMultiplierPort
,
47 EFI_ATA_COMMAND_BLOCK Acb
;
48 EFI_ATA_STATUS_BLOCK
*Asb
;
49 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet
;
50 UINT8 Buffer
[HDD_PAYLOAD
];
52 if ((AtaPassThru
== NULL
) || (Password
== NULL
)) {
53 return EFI_INVALID_PARAMETER
;
57 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
58 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
59 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
60 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
61 // may not be aligned when allocated on stack for some compilers. Hence, we
62 // use the API AllocateAlignedPages to ensure this structure is properly
65 Asb
= AllocateAlignedPages (
66 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)),
67 AtaPassThru
->Mode
->IoAlign
70 return EFI_OUT_OF_RESOURCES
;
74 // Prepare for ATA command block.
76 ZeroMem (&Acb
, sizeof (Acb
));
77 ZeroMem (Asb
, sizeof (EFI_ATA_STATUS_BLOCK
));
78 Acb
.AtaCommand
= ATA_SECURITY_UNLOCK_CMD
;
79 Acb
.AtaDeviceHead
= (UINT8
) (PortMultiplierPort
== 0xFFFF ? 0 : (PortMultiplierPort
<< 4));
82 // Prepare for ATA pass through packet.
84 ZeroMem (&Packet
, sizeof (Packet
));
85 Packet
.Protocol
= EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT
;
86 Packet
.Length
= EFI_ATA_PASS_THRU_LENGTH_BYTES
;
90 ((CHAR16
*) Buffer
)[0] = Identifier
& BIT0
;
91 CopyMem (&((CHAR16
*) Buffer
)[1], Password
, HDD_PASSWORD_MAX_LENGTH
);
93 Packet
.OutDataBuffer
= Buffer
;
94 Packet
.OutTransferLength
= sizeof (Buffer
);
95 Packet
.Timeout
= ATA_TIMEOUT
;
97 Status
= AtaPassThru
->PassThru (
103 if (!EFI_ERROR (Status
) &&
104 ((Asb
->AtaStatus
& ATA_STSREG_ERR
) != 0) &&
105 ((Asb
->AtaError
& ATA_ERRREG_ABRT
) != 0)) {
106 Status
= EFI_DEVICE_ERROR
;
109 FreeAlignedPages (Asb
, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)));
111 ZeroMem (Buffer
, sizeof (Buffer
));
113 DEBUG ((DEBUG_INFO
, "%a() - %r\n", __FUNCTION__
, Status
));
118 Send security freeze lock cmd through ATA PassThru PPI.
120 @param[in] AtaPassThru The pointer to the ATA PassThru PPI.
121 @param[in] Port The port number of the ATA device.
122 @param[in] PortMultiplierPort The port multiplier port number of the ATA device.
124 @retval EFI_SUCCESS Successful to send security freeze lock cmd.
125 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
126 @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.
127 @retval EFI_DEVICE_ERROR Can not send security freeze lock cmd.
132 IN EDKII_PEI_ATA_PASS_THRU_PPI
*AtaPassThru
,
134 IN UINT16 PortMultiplierPort
138 EFI_ATA_COMMAND_BLOCK Acb
;
139 EFI_ATA_STATUS_BLOCK
*Asb
;
140 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet
;
142 if (AtaPassThru
== NULL
) {
143 return EFI_INVALID_PARAMETER
;
147 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
148 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
149 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
150 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
151 // may not be aligned when allocated on stack for some compilers. Hence, we
152 // use the API AllocateAlignedPages to ensure this structure is properly
155 Asb
= AllocateAlignedPages (
156 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)),
157 AtaPassThru
->Mode
->IoAlign
160 return EFI_OUT_OF_RESOURCES
;
164 // Prepare for ATA command block.
166 ZeroMem (&Acb
, sizeof (Acb
));
167 ZeroMem (Asb
, sizeof (EFI_ATA_STATUS_BLOCK
));
168 Acb
.AtaCommand
= ATA_SECURITY_FREEZE_LOCK_CMD
;
169 Acb
.AtaDeviceHead
= (UINT8
) (PortMultiplierPort
== 0xFFFF ? 0 : (PortMultiplierPort
<< 4));
172 // Prepare for ATA pass through packet.
174 ZeroMem (&Packet
, sizeof (Packet
));
175 Packet
.Protocol
= EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA
;
176 Packet
.Length
= EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER
;
179 Packet
.Timeout
= ATA_TIMEOUT
;
181 Status
= AtaPassThru
->PassThru (
187 if (!EFI_ERROR (Status
) &&
188 ((Asb
->AtaStatus
& ATA_STSREG_ERR
) != 0) &&
189 ((Asb
->AtaError
& ATA_ERRREG_ABRT
) != 0)) {
190 Status
= EFI_DEVICE_ERROR
;
193 FreeAlignedPages (Asb
, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)));
195 DEBUG ((DEBUG_INFO
, "%a() - %r\n", __FUNCTION__
, Status
));
200 Unlock HDD password for S3.
202 @param[in] AtaPassThruPpi Pointer to the EDKII_PEI_ATA_PASS_THRU_PPI instance.
207 IN EDKII_PEI_ATA_PASS_THRU_PPI
*AtaPassThruPpi
214 HDD_PASSWORD_DEVICE_INFO
*DevInfo
;
216 UINT16 PortMultiplierPort
;
217 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
218 UINTN DevicePathLength
;
221 // Get HDD password device info from LockBox.
223 Buffer
= (VOID
*) &DummyData
;
224 Length
= sizeof (DummyData
);
225 Status
= RestoreLockBox (&mHddPasswordDeviceInfoGuid
, Buffer
, &Length
);
226 if (Status
== EFI_BUFFER_TOO_SMALL
) {
227 Buffer
= AllocatePages (EFI_SIZE_TO_PAGES (Length
));
228 if (Buffer
!= NULL
) {
229 Status
= RestoreLockBox (&mHddPasswordDeviceInfoGuid
, Buffer
, &Length
);
232 if ((Buffer
== NULL
) || (Buffer
== (VOID
*) &DummyData
)) {
234 } else if (EFI_ERROR (Status
)) {
235 FreePages (Buffer
, EFI_SIZE_TO_PAGES (Length
));
239 Status
= AtaPassThruPpi
->GetDevicePath (AtaPassThruPpi
, &DevicePathLength
, &DevicePath
);
240 if (EFI_ERROR (Status
) || (DevicePathLength
<= sizeof (EFI_DEVICE_PATH_PROTOCOL
))) {
245 // Go through all the devices managed by the AtaPassThru PPI instance.
249 Status
= AtaPassThruPpi
->GetNextPort (AtaPassThruPpi
, &Port
);
250 if (EFI_ERROR (Status
)) {
252 // We cannot find more legal port then we are done.
257 PortMultiplierPort
= 0xFFFF;
259 Status
= AtaPassThruPpi
->GetNextDevice (AtaPassThruPpi
, Port
, &PortMultiplierPort
);
260 if (EFI_ERROR (Status
)) {
262 // We cannot find more legal port multiplier port number for ATA device
263 // on the port, then we are done.
269 // Search the device in the restored LockBox.
271 DevInfo
= (HDD_PASSWORD_DEVICE_INFO
*) Buffer
;
272 while ((UINTN
) DevInfo
< ((UINTN
) Buffer
+ Length
)) {
274 // Find the matching device.
276 if ((DevInfo
->Device
.Port
== Port
) &&
277 (DevInfo
->Device
.PortMultiplierPort
== PortMultiplierPort
) &&
278 (DevInfo
->DevicePathLength
>= DevicePathLength
) &&
282 DevicePathLength
- sizeof (EFI_DEVICE_PATH_PROTOCOL
)) == 0)) {
284 // If device locked, unlock first.
286 if (!IsZeroBuffer (DevInfo
->Password
, HDD_PASSWORD_MAX_LENGTH
)) {
287 UnlockDevice (AtaPassThruPpi
, Port
, PortMultiplierPort
, 0, DevInfo
->Password
);
290 // Freeze lock the device.
292 FreezeLockDevice (AtaPassThruPpi
, Port
, PortMultiplierPort
);
296 DevInfo
= (HDD_PASSWORD_DEVICE_INFO
*)
297 ((UINTN
) DevInfo
+ sizeof (HDD_PASSWORD_DEVICE_INFO
) + DevInfo
->DevicePathLength
);
303 ZeroMem (Buffer
, Length
);
304 FreePages (Buffer
, EFI_SIZE_TO_PAGES (Length
));
309 Entry point of the notification callback function itself within the PEIM.
310 It is to unlock HDD password for S3.
312 @param PeiServices Indirect reference to the PEI Services Table.
313 @param NotifyDescriptor Address of the notification descriptor data structure.
314 @param Ppi Address of the PPI that was installed.
316 @return Status of the notification.
317 The status code returned from this function is ignored.
321 HddPasswordAtaPassThruNotify (
322 IN EFI_PEI_SERVICES
**PeiServices
,
323 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
327 DEBUG ((DEBUG_INFO
, "%a() - enter at S3 resume\n", __FUNCTION__
));
329 UnlockHddPassword ((EDKII_PEI_ATA_PASS_THRU_PPI
*) Ppi
);
331 DEBUG ((DEBUG_INFO
, "%a() - exit at S3 resume\n", __FUNCTION__
));
337 EFI_PEI_NOTIFY_DESCRIPTOR mHddPasswordAtaPassThruPpiNotifyDesc
= {
338 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
339 &gEdkiiPeiAtaPassThruPpiGuid
,
340 HddPasswordAtaPassThruNotify
345 Main entry for this module.
347 @param FileHandle Handle of the file being invoked.
348 @param PeiServices Pointer to PEI Services table.
350 @return Status from PeiServicesNotifyPpi.
356 IN EFI_PEI_FILE_HANDLE FileHandle
,
357 IN CONST EFI_PEI_SERVICES
**PeiServices
361 EFI_BOOT_MODE BootMode
;
363 Status
= PeiServicesGetBootMode (&BootMode
);
364 if ((EFI_ERROR (Status
)) || (BootMode
!= BOOT_ON_S3_RESUME
)) {
365 return EFI_UNSUPPORTED
;
368 DEBUG ((DEBUG_INFO
, "%a: Enters in S3 path.\n", __FUNCTION__
));
370 Status
= PeiServicesNotifyPpi (&mHddPasswordAtaPassThruPpiNotifyDesc
);
371 ASSERT_EFI_ERROR (Status
);