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
;
15 Send unlock hdd password cmd through ATA PassThru PPI.
17 @param[in] AtaPassThru The pointer to the ATA PassThru PPI.
18 @param[in] Port The port number of the ATA device.
19 @param[in] PortMultiplierPort The port multiplier port number of the ATA device.
20 @param[in] Identifier The identifier to set user or master password.
21 @param[in] Password The hdd password of attached ATA device.
23 @retval EFI_SUCCESS Successful to send unlock hdd password cmd.
24 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
25 @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.
26 @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd.
31 IN EDKII_PEI_ATA_PASS_THRU_PPI
*AtaPassThru
,
33 IN UINT16 PortMultiplierPort
,
39 EFI_ATA_COMMAND_BLOCK Acb
;
40 EFI_ATA_STATUS_BLOCK
*Asb
;
41 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet
;
42 UINT8 Buffer
[HDD_PAYLOAD
];
44 if ((AtaPassThru
== NULL
) || (Password
== NULL
)) {
45 return EFI_INVALID_PARAMETER
;
49 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
50 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
51 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
52 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
53 // may not be aligned when allocated on stack for some compilers. Hence, we
54 // use the API AllocateAlignedPages to ensure this structure is properly
57 Asb
= AllocateAlignedPages (
58 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)),
59 AtaPassThru
->Mode
->IoAlign
62 return EFI_OUT_OF_RESOURCES
;
66 // Prepare for ATA command block.
68 ZeroMem (&Acb
, sizeof (Acb
));
69 ZeroMem (Asb
, sizeof (EFI_ATA_STATUS_BLOCK
));
70 Acb
.AtaCommand
= ATA_SECURITY_UNLOCK_CMD
;
71 Acb
.AtaDeviceHead
= (UINT8
)(PortMultiplierPort
== 0xFFFF ? 0 : (PortMultiplierPort
<< 4));
74 // Prepare for ATA pass through packet.
76 ZeroMem (&Packet
, sizeof (Packet
));
77 Packet
.Protocol
= EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT
;
78 Packet
.Length
= EFI_ATA_PASS_THRU_LENGTH_BYTES
;
82 ((CHAR16
*)Buffer
)[0] = Identifier
& BIT0
;
83 CopyMem (&((CHAR16
*)Buffer
)[1], Password
, HDD_PASSWORD_MAX_LENGTH
);
85 Packet
.OutDataBuffer
= Buffer
;
86 Packet
.OutTransferLength
= sizeof (Buffer
);
87 Packet
.Timeout
= ATA_TIMEOUT
;
89 Status
= AtaPassThru
->PassThru (
95 if (!EFI_ERROR (Status
) &&
96 ((Asb
->AtaStatus
& ATA_STSREG_ERR
) != 0) &&
97 ((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))
184 Status
= EFI_DEVICE_ERROR
;
187 FreeAlignedPages (Asb
, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK
)));
189 DEBUG ((DEBUG_INFO
, "%a() - %r\n", __FUNCTION__
, Status
));
194 Unlock HDD password for S3.
196 @param[in] AtaPassThruPpi Pointer to the EDKII_PEI_ATA_PASS_THRU_PPI instance.
201 IN EDKII_PEI_ATA_PASS_THRU_PPI
*AtaPassThruPpi
208 HDD_PASSWORD_DEVICE_INFO
*DevInfo
;
210 UINT16 PortMultiplierPort
;
211 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
212 UINTN DevicePathLength
;
215 // Get HDD password device info from LockBox.
217 Buffer
= (VOID
*)&DummyData
;
218 Length
= sizeof (DummyData
);
219 Status
= RestoreLockBox (&mHddPasswordDeviceInfoGuid
, Buffer
, &Length
);
220 if (Status
== EFI_BUFFER_TOO_SMALL
) {
221 Buffer
= AllocatePages (EFI_SIZE_TO_PAGES (Length
));
222 if (Buffer
!= NULL
) {
223 Status
= RestoreLockBox (&mHddPasswordDeviceInfoGuid
, Buffer
, &Length
);
227 if ((Buffer
== NULL
) || (Buffer
== (VOID
*)&DummyData
)) {
229 } else if (EFI_ERROR (Status
)) {
230 FreePages (Buffer
, EFI_SIZE_TO_PAGES (Length
));
234 Status
= AtaPassThruPpi
->GetDevicePath (AtaPassThruPpi
, &DevicePathLength
, &DevicePath
);
235 if (EFI_ERROR (Status
) || (DevicePathLength
<= sizeof (EFI_DEVICE_PATH_PROTOCOL
))) {
240 // Go through all the devices managed by the AtaPassThru PPI instance.
244 Status
= AtaPassThruPpi
->GetNextPort (AtaPassThruPpi
, &Port
);
245 if (EFI_ERROR (Status
)) {
247 // We cannot find more legal port then we are done.
252 PortMultiplierPort
= 0xFFFF;
254 Status
= AtaPassThruPpi
->GetNextDevice (AtaPassThruPpi
, Port
, &PortMultiplierPort
);
255 if (EFI_ERROR (Status
)) {
257 // We cannot find more legal port multiplier port number for ATA device
258 // on the port, then we are done.
264 // Search the device in the restored LockBox.
266 DevInfo
= (HDD_PASSWORD_DEVICE_INFO
*)Buffer
;
267 while ((UINTN
)DevInfo
< ((UINTN
)Buffer
+ Length
)) {
269 // Find the matching device.
271 if ((DevInfo
->Device
.Port
== Port
) &&
272 (DevInfo
->Device
.PortMultiplierPort
== PortMultiplierPort
) &&
273 (DevInfo
->DevicePathLength
>= DevicePathLength
) &&
277 DevicePathLength
- sizeof (EFI_DEVICE_PATH_PROTOCOL
)
281 // If device locked, unlock first.
283 if (!IsZeroBuffer (DevInfo
->Password
, HDD_PASSWORD_MAX_LENGTH
)) {
284 UnlockDevice (AtaPassThruPpi
, Port
, PortMultiplierPort
, 0, DevInfo
->Password
);
288 // Freeze lock the device.
290 FreezeLockDevice (AtaPassThruPpi
, Port
, PortMultiplierPort
);
294 DevInfo
= (HDD_PASSWORD_DEVICE_INFO
*)
295 ((UINTN
)DevInfo
+ sizeof (HDD_PASSWORD_DEVICE_INFO
) + DevInfo
->DevicePathLength
);
301 ZeroMem (Buffer
, Length
);
302 FreePages (Buffer
, EFI_SIZE_TO_PAGES (Length
));
306 Entry point of the notification callback function itself within the PEIM.
307 It is to unlock HDD password for S3.
309 @param PeiServices Indirect reference to the PEI Services Table.
310 @param NotifyDescriptor Address of the notification descriptor data structure.
311 @param Ppi Address of the PPI that was installed.
313 @return Status of the notification.
314 The status code returned from this function is ignored.
318 HddPasswordAtaPassThruNotify (
319 IN EFI_PEI_SERVICES
**PeiServices
,
320 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
324 DEBUG ((DEBUG_INFO
, "%a() - enter at S3 resume\n", __FUNCTION__
));
326 UnlockHddPassword ((EDKII_PEI_ATA_PASS_THRU_PPI
*)Ppi
);
328 DEBUG ((DEBUG_INFO
, "%a() - exit at S3 resume\n", __FUNCTION__
));
333 EFI_PEI_NOTIFY_DESCRIPTOR mHddPasswordAtaPassThruPpiNotifyDesc
= {
334 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
335 &gEdkiiPeiAtaPassThruPpiGuid
,
336 HddPasswordAtaPassThruNotify
340 Main entry for this module.
342 @param FileHandle Handle of the file being invoked.
343 @param PeiServices Pointer to PEI Services table.
345 @return Status from PeiServicesNotifyPpi.
351 IN EFI_PEI_FILE_HANDLE FileHandle
,
352 IN CONST EFI_PEI_SERVICES
**PeiServices
356 EFI_BOOT_MODE BootMode
;
358 Status
= PeiServicesGetBootMode (&BootMode
);
359 if ((EFI_ERROR (Status
)) || (BootMode
!= BOOT_ON_S3_RESUME
)) {
360 return EFI_UNSUPPORTED
;
363 DEBUG ((DEBUG_INFO
, "%a: Enters in S3 path.\n", __FUNCTION__
));
365 Status
= PeiServicesNotifyPpi (&mHddPasswordAtaPassThruPpiNotifyDesc
);
366 ASSERT_EFI_ERROR (Status
);