2 HddPassword PEI module which is used to unlock HDD password for S3.
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "HddPasswordPei.h"
12 EFI_GUID mHddPasswordDeviceInfoGuid
= HDD_PASSWORD_DEVICE_INFO_GUID
;
16 Send unlock hdd password cmd through ATA PassThru PPI.
18 @param[in] AtaPassThru The pointer to the ATA PassThru PPI.
19 @param[in] Port The port number of the ATA device.
20 @param[in] PortMultiplierPort The port multiplier port number of the ATA device.
21 @param[in] Identifier The identifier to set user or master password.
22 @param[in] Password The hdd password of attached ATA device.
24 @retval EFI_SUCCESS Successful to send unlock hdd password cmd.
25 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
26 @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.
27 @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd.
32 IN EDKII_PEI_ATA_PASS_THRU_PPI
*AtaPassThru
,
34 IN UINT16 PortMultiplierPort
,
40 EFI_ATA_COMMAND_BLOCK Acb
;
41 EFI_ATA_STATUS_BLOCK
*Asb
;
42 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet
;
43 UINT8 Buffer
[HDD_PAYLOAD
];
45 if ((AtaPassThru
== NULL
) || (Password
== NULL
)) {
46 return EFI_INVALID_PARAMETER
;
50 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
51 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
52 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
53 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
54 // may not be aligned when allocated on stack for some compilers. Hence, we
55 // use the API AllocateAlignedPages to ensure this structure is properly
58 Asb
= AllocateAlignedPages (
59 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)),
60 AtaPassThru
->Mode
->IoAlign
63 return EFI_OUT_OF_RESOURCES
;
67 // Prepare for ATA command block.
69 ZeroMem (&Acb
, sizeof (Acb
));
70 ZeroMem (Asb
, sizeof (EFI_ATA_STATUS_BLOCK
));
71 Acb
.AtaCommand
= ATA_SECURITY_UNLOCK_CMD
;
72 Acb
.AtaDeviceHead
= (UINT8
) (PortMultiplierPort
== 0xFFFF ? 0 : (PortMultiplierPort
<< 4));
75 // Prepare for ATA pass through packet.
77 ZeroMem (&Packet
, sizeof (Packet
));
78 Packet
.Protocol
= EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT
;
79 Packet
.Length
= EFI_ATA_PASS_THRU_LENGTH_BYTES
;
83 ((CHAR16
*) Buffer
)[0] = Identifier
& BIT0
;
84 CopyMem (&((CHAR16
*) Buffer
)[1], Password
, HDD_PASSWORD_MAX_LENGTH
);
86 Packet
.OutDataBuffer
= Buffer
;
87 Packet
.OutTransferLength
= sizeof (Buffer
);
88 Packet
.Timeout
= ATA_TIMEOUT
;
90 Status
= AtaPassThru
->PassThru (
96 if (!EFI_ERROR (Status
) &&
97 ((Asb
->AtaStatus
& ATA_STSREG_ERR
) != 0) &&
98 ((Asb
->AtaError
& ATA_ERRREG_ABRT
) != 0)) {
99 Status
= EFI_DEVICE_ERROR
;
102 FreeAlignedPages (Asb
, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)));
104 ZeroMem (Buffer
, sizeof (Buffer
));
106 DEBUG ((DEBUG_INFO
, "%a() - %r\n", __FUNCTION__
, Status
));
111 Send security freeze lock cmd through ATA PassThru PPI.
113 @param[in] AtaPassThru The pointer to the ATA PassThru PPI.
114 @param[in] Port The port number of the ATA device.
115 @param[in] PortMultiplierPort The port multiplier port number of the ATA device.
117 @retval EFI_SUCCESS Successful to send security freeze lock cmd.
118 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
119 @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.
120 @retval EFI_DEVICE_ERROR Can not send security freeze lock cmd.
125 IN EDKII_PEI_ATA_PASS_THRU_PPI
*AtaPassThru
,
127 IN UINT16 PortMultiplierPort
131 EFI_ATA_COMMAND_BLOCK Acb
;
132 EFI_ATA_STATUS_BLOCK
*Asb
;
133 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet
;
135 if (AtaPassThru
== NULL
) {
136 return EFI_INVALID_PARAMETER
;
140 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
141 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
142 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
143 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
144 // may not be aligned when allocated on stack for some compilers. Hence, we
145 // use the API AllocateAlignedPages to ensure this structure is properly
148 Asb
= AllocateAlignedPages (
149 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)),
150 AtaPassThru
->Mode
->IoAlign
153 return EFI_OUT_OF_RESOURCES
;
157 // Prepare for ATA command block.
159 ZeroMem (&Acb
, sizeof (Acb
));
160 ZeroMem (Asb
, sizeof (EFI_ATA_STATUS_BLOCK
));
161 Acb
.AtaCommand
= ATA_SECURITY_FREEZE_LOCK_CMD
;
162 Acb
.AtaDeviceHead
= (UINT8
) (PortMultiplierPort
== 0xFFFF ? 0 : (PortMultiplierPort
<< 4));
165 // Prepare for ATA pass through packet.
167 ZeroMem (&Packet
, sizeof (Packet
));
168 Packet
.Protocol
= EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA
;
169 Packet
.Length
= EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER
;
172 Packet
.Timeout
= ATA_TIMEOUT
;
174 Status
= AtaPassThru
->PassThru (
180 if (!EFI_ERROR (Status
) &&
181 ((Asb
->AtaStatus
& ATA_STSREG_ERR
) != 0) &&
182 ((Asb
->AtaError
& ATA_ERRREG_ABRT
) != 0)) {
183 Status
= EFI_DEVICE_ERROR
;
186 FreeAlignedPages (Asb
, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)));
188 DEBUG ((DEBUG_INFO
, "%a() - %r\n", __FUNCTION__
, Status
));
193 Unlock HDD password for S3.
195 @param[in] AtaPassThruPpi Pointer to the EDKII_PEI_ATA_PASS_THRU_PPI instance.
200 IN EDKII_PEI_ATA_PASS_THRU_PPI
*AtaPassThruPpi
207 HDD_PASSWORD_DEVICE_INFO
*DevInfo
;
209 UINT16 PortMultiplierPort
;
210 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
211 UINTN DevicePathLength
;
214 // Get HDD password device info from LockBox.
216 Buffer
= (VOID
*) &DummyData
;
217 Length
= sizeof (DummyData
);
218 Status
= RestoreLockBox (&mHddPasswordDeviceInfoGuid
, Buffer
, &Length
);
219 if (Status
== EFI_BUFFER_TOO_SMALL
) {
220 Buffer
= AllocatePages (EFI_SIZE_TO_PAGES (Length
));
221 if (Buffer
!= NULL
) {
222 Status
= RestoreLockBox (&mHddPasswordDeviceInfoGuid
, Buffer
, &Length
);
225 if ((Buffer
== NULL
) || (Buffer
== (VOID
*) &DummyData
)) {
227 } else if (EFI_ERROR (Status
)) {
228 FreePages (Buffer
, EFI_SIZE_TO_PAGES (Length
));
232 Status
= AtaPassThruPpi
->GetDevicePath (AtaPassThruPpi
, &DevicePathLength
, &DevicePath
);
233 if (EFI_ERROR (Status
) || (DevicePathLength
<= sizeof (EFI_DEVICE_PATH_PROTOCOL
))) {
238 // Go through all the devices managed by the AtaPassThru PPI instance.
242 Status
= AtaPassThruPpi
->GetNextPort (AtaPassThruPpi
, &Port
);
243 if (EFI_ERROR (Status
)) {
245 // We cannot find more legal port then we are done.
250 PortMultiplierPort
= 0xFFFF;
252 Status
= AtaPassThruPpi
->GetNextDevice (AtaPassThruPpi
, Port
, &PortMultiplierPort
);
253 if (EFI_ERROR (Status
)) {
255 // We cannot find more legal port multiplier port number for ATA device
256 // on the port, then we are done.
262 // Search the device in the restored LockBox.
264 DevInfo
= (HDD_PASSWORD_DEVICE_INFO
*) Buffer
;
265 while ((UINTN
) DevInfo
< ((UINTN
) Buffer
+ Length
)) {
267 // Find the matching device.
269 if ((DevInfo
->Device
.Port
== Port
) &&
270 (DevInfo
->Device
.PortMultiplierPort
== PortMultiplierPort
) &&
271 (DevInfo
->DevicePathLength
>= DevicePathLength
) &&
275 DevicePathLength
- sizeof (EFI_DEVICE_PATH_PROTOCOL
)) == 0)) {
277 // If device locked, unlock first.
279 if (!IsZeroBuffer (DevInfo
->Password
, HDD_PASSWORD_MAX_LENGTH
)) {
280 UnlockDevice (AtaPassThruPpi
, Port
, PortMultiplierPort
, 0, DevInfo
->Password
);
283 // Freeze lock the device.
285 FreezeLockDevice (AtaPassThruPpi
, Port
, PortMultiplierPort
);
289 DevInfo
= (HDD_PASSWORD_DEVICE_INFO
*)
290 ((UINTN
) DevInfo
+ sizeof (HDD_PASSWORD_DEVICE_INFO
) + DevInfo
->DevicePathLength
);
296 ZeroMem (Buffer
, Length
);
297 FreePages (Buffer
, EFI_SIZE_TO_PAGES (Length
));
302 Entry point of the notification callback function itself within the PEIM.
303 It is to unlock HDD password for S3.
305 @param PeiServices Indirect reference to the PEI Services Table.
306 @param NotifyDescriptor Address of the notification descriptor data structure.
307 @param Ppi Address of the PPI that was installed.
309 @return Status of the notification.
310 The status code returned from this function is ignored.
314 HddPasswordAtaPassThruNotify (
315 IN EFI_PEI_SERVICES
**PeiServices
,
316 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
320 DEBUG ((DEBUG_INFO
, "%a() - enter at S3 resume\n", __FUNCTION__
));
322 UnlockHddPassword ((EDKII_PEI_ATA_PASS_THRU_PPI
*) Ppi
);
324 DEBUG ((DEBUG_INFO
, "%a() - exit at S3 resume\n", __FUNCTION__
));
330 EFI_PEI_NOTIFY_DESCRIPTOR mHddPasswordAtaPassThruPpiNotifyDesc
= {
331 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
332 &gEdkiiPeiAtaPassThruPpiGuid
,
333 HddPasswordAtaPassThruNotify
338 Main entry for this module.
340 @param FileHandle Handle of the file being invoked.
341 @param PeiServices Pointer to PEI Services table.
343 @return Status from PeiServicesNotifyPpi.
349 IN EFI_PEI_FILE_HANDLE FileHandle
,
350 IN CONST EFI_PEI_SERVICES
**PeiServices
354 EFI_BOOT_MODE BootMode
;
356 Status
= PeiServicesGetBootMode (&BootMode
);
357 if ((EFI_ERROR (Status
)) || (BootMode
!= BOOT_ON_S3_RESUME
)) {
358 return EFI_UNSUPPORTED
;
361 DEBUG ((DEBUG_INFO
, "%a: Enters in S3 path.\n", __FUNCTION__
));
363 Status
= PeiServicesNotifyPpi (&mHddPasswordAtaPassThruPpiNotifyDesc
);
364 ASSERT_EFI_ERROR (Status
);