]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/HddPassword/HddPasswordPei.c
SecurityPkg: Apply uncrustify changes
[mirror_edk2.git] / SecurityPkg / HddPassword / HddPasswordPei.c
CommitLineData
e8959f81
HW
1/** @file\r
2 HddPassword PEI module which is used to unlock HDD password for S3.\r
3\r
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
5\r
289b714b 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
e8959f81
HW
7\r
8**/\r
9\r
10#include "HddPasswordPei.h"\r
11\r
c411b485 12EFI_GUID mHddPasswordDeviceInfoGuid = HDD_PASSWORD_DEVICE_INFO_GUID;\r
e8959f81
HW
13\r
14/**\r
15 Send unlock hdd password cmd through ATA PassThru PPI.\r
16\r
17 @param[in] AtaPassThru The pointer to the ATA PassThru PPI.\r
18 @param[in] Port The port number of the ATA device.\r
19 @param[in] PortMultiplierPort The port multiplier port number of the ATA device.\r
20 @param[in] Identifier The identifier to set user or master password.\r
21 @param[in] Password The hdd password of attached ATA device.\r
22\r
23 @retval EFI_SUCCESS Successful to send unlock hdd password cmd.\r
24 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
25 @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.\r
26 @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd.\r
27\r
28**/\r
29EFI_STATUS\r
30UnlockDevice (\r
c411b485
MK
31 IN EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru,\r
32 IN UINT16 Port,\r
33 IN UINT16 PortMultiplierPort,\r
34 IN CHAR8 Identifier,\r
35 IN CHAR8 *Password\r
e8959f81
HW
36 )\r
37{\r
c411b485
MK
38 EFI_STATUS Status;\r
39 EFI_ATA_COMMAND_BLOCK Acb;\r
40 EFI_ATA_STATUS_BLOCK *Asb;\r
41 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
42 UINT8 Buffer[HDD_PAYLOAD];\r
e8959f81
HW
43\r
44 if ((AtaPassThru == NULL) || (Password == NULL)) {\r
45 return EFI_INVALID_PARAMETER;\r
46 }\r
47\r
48 //\r
49 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
50 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
51 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
52 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
53 // may not be aligned when allocated on stack for some compilers. Hence, we\r
54 // use the API AllocateAlignedPages to ensure this structure is properly\r
55 // aligned.\r
56 //\r
57 Asb = AllocateAlignedPages (\r
58 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
59 AtaPassThru->Mode->IoAlign\r
60 );\r
61 if (Asb == NULL) {\r
62 return EFI_OUT_OF_RESOURCES;\r
63 }\r
64\r
65 //\r
66 // Prepare for ATA command block.\r
67 //\r
68 ZeroMem (&Acb, sizeof (Acb));\r
69 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
70 Acb.AtaCommand = ATA_SECURITY_UNLOCK_CMD;\r
c411b485 71 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
e8959f81
HW
72\r
73 //\r
74 // Prepare for ATA pass through packet.\r
75 //\r
76 ZeroMem (&Packet, sizeof (Packet));\r
77 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;\r
78 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
79 Packet.Asb = Asb;\r
80 Packet.Acb = &Acb;\r
81\r
c411b485
MK
82 ((CHAR16 *)Buffer)[0] = Identifier & BIT0;\r
83 CopyMem (&((CHAR16 *)Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);\r
e8959f81
HW
84\r
85 Packet.OutDataBuffer = Buffer;\r
86 Packet.OutTransferLength = sizeof (Buffer);\r
87 Packet.Timeout = ATA_TIMEOUT;\r
88\r
89 Status = AtaPassThru->PassThru (\r
90 AtaPassThru,\r
91 Port,\r
92 PortMultiplierPort,\r
93 &Packet\r
94 );\r
95 if (!EFI_ERROR (Status) &&\r
96 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
c411b485
MK
97 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))\r
98 {\r
e8959f81
HW
99 Status = EFI_DEVICE_ERROR;\r
100 }\r
101\r
102 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
103\r
104 ZeroMem (Buffer, sizeof (Buffer));\r
105\r
106 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
107 return Status;\r
108}\r
109\r
110/**\r
111 Send security freeze lock cmd through ATA PassThru PPI.\r
112\r
113 @param[in] AtaPassThru The pointer to the ATA PassThru PPI.\r
114 @param[in] Port The port number of the ATA device.\r
115 @param[in] PortMultiplierPort The port multiplier port number of the ATA device.\r
116\r
117 @retval EFI_SUCCESS Successful to send security freeze lock cmd.\r
118 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
119 @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.\r
120 @retval EFI_DEVICE_ERROR Can not send security freeze lock cmd.\r
121\r
122**/\r
123EFI_STATUS\r
124FreezeLockDevice (\r
c411b485
MK
125 IN EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru,\r
126 IN UINT16 Port,\r
127 IN UINT16 PortMultiplierPort\r
e8959f81
HW
128 )\r
129{\r
c411b485
MK
130 EFI_STATUS Status;\r
131 EFI_ATA_COMMAND_BLOCK Acb;\r
132 EFI_ATA_STATUS_BLOCK *Asb;\r
133 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
e8959f81
HW
134\r
135 if (AtaPassThru == NULL) {\r
136 return EFI_INVALID_PARAMETER;\r
137 }\r
138\r
139 //\r
140 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
141 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
142 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
143 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
144 // may not be aligned when allocated on stack for some compilers. Hence, we\r
145 // use the API AllocateAlignedPages to ensure this structure is properly\r
146 // aligned.\r
147 //\r
148 Asb = AllocateAlignedPages (\r
149 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
150 AtaPassThru->Mode->IoAlign\r
151 );\r
152 if (Asb == NULL) {\r
153 return EFI_OUT_OF_RESOURCES;\r
154 }\r
155\r
156 //\r
157 // Prepare for ATA command block.\r
158 //\r
159 ZeroMem (&Acb, sizeof (Acb));\r
160 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
161 Acb.AtaCommand = ATA_SECURITY_FREEZE_LOCK_CMD;\r
c411b485 162 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
e8959f81
HW
163\r
164 //\r
165 // Prepare for ATA pass through packet.\r
166 //\r
167 ZeroMem (&Packet, sizeof (Packet));\r
168 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;\r
169 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER;\r
170 Packet.Asb = Asb;\r
171 Packet.Acb = &Acb;\r
172 Packet.Timeout = ATA_TIMEOUT;\r
173\r
174 Status = AtaPassThru->PassThru (\r
175 AtaPassThru,\r
176 Port,\r
177 PortMultiplierPort,\r
178 &Packet\r
179 );\r
180 if (!EFI_ERROR (Status) &&\r
181 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
c411b485
MK
182 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))\r
183 {\r
e8959f81
HW
184 Status = EFI_DEVICE_ERROR;\r
185 }\r
186\r
187 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
188\r
189 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
190 return Status;\r
191}\r
192\r
193/**\r
194 Unlock HDD password for S3.\r
195\r
196 @param[in] AtaPassThruPpi Pointer to the EDKII_PEI_ATA_PASS_THRU_PPI instance.\r
197\r
198**/\r
199VOID\r
200UnlockHddPassword (\r
c411b485 201 IN EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThruPpi\r
e8959f81
HW
202 )\r
203{\r
c411b485
MK
204 EFI_STATUS Status;\r
205 VOID *Buffer;\r
206 UINTN Length;\r
207 UINT8 DummyData;\r
208 HDD_PASSWORD_DEVICE_INFO *DevInfo;\r
209 UINT16 Port;\r
210 UINT16 PortMultiplierPort;\r
211 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
212 UINTN DevicePathLength;\r
e8959f81
HW
213\r
214 //\r
215 // Get HDD password device info from LockBox.\r
216 //\r
c411b485 217 Buffer = (VOID *)&DummyData;\r
e8959f81
HW
218 Length = sizeof (DummyData);\r
219 Status = RestoreLockBox (&mHddPasswordDeviceInfoGuid, Buffer, &Length);\r
220 if (Status == EFI_BUFFER_TOO_SMALL) {\r
221 Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Length));\r
222 if (Buffer != NULL) {\r
223 Status = RestoreLockBox (&mHddPasswordDeviceInfoGuid, Buffer, &Length);\r
224 }\r
225 }\r
c411b485
MK
226\r
227 if ((Buffer == NULL) || (Buffer == (VOID *)&DummyData)) {\r
e8959f81
HW
228 return;\r
229 } else if (EFI_ERROR (Status)) {\r
230 FreePages (Buffer, EFI_SIZE_TO_PAGES (Length));\r
231 return;\r
232 }\r
233\r
234 Status = AtaPassThruPpi->GetDevicePath (AtaPassThruPpi, &DevicePathLength, &DevicePath);\r
235 if (EFI_ERROR (Status) || (DevicePathLength <= sizeof (EFI_DEVICE_PATH_PROTOCOL))) {\r
236 goto Exit;\r
237 }\r
238\r
239 //\r
240 // Go through all the devices managed by the AtaPassThru PPI instance.\r
241 //\r
242 Port = 0xFFFF;\r
243 while (TRUE) {\r
244 Status = AtaPassThruPpi->GetNextPort (AtaPassThruPpi, &Port);\r
245 if (EFI_ERROR (Status)) {\r
246 //\r
247 // We cannot find more legal port then we are done.\r
248 //\r
249 break;\r
250 }\r
251\r
252 PortMultiplierPort = 0xFFFF;\r
253 while (TRUE) {\r
254 Status = AtaPassThruPpi->GetNextDevice (AtaPassThruPpi, Port, &PortMultiplierPort);\r
255 if (EFI_ERROR (Status)) {\r
256 //\r
257 // We cannot find more legal port multiplier port number for ATA device\r
258 // on the port, then we are done.\r
259 //\r
260 break;\r
261 }\r
262\r
263 //\r
264 // Search the device in the restored LockBox.\r
265 //\r
c411b485
MK
266 DevInfo = (HDD_PASSWORD_DEVICE_INFO *)Buffer;\r
267 while ((UINTN)DevInfo < ((UINTN)Buffer + Length)) {\r
e8959f81
HW
268 //\r
269 // Find the matching device.\r
270 //\r
271 if ((DevInfo->Device.Port == Port) &&\r
272 (DevInfo->Device.PortMultiplierPort == PortMultiplierPort) &&\r
273 (DevInfo->DevicePathLength >= DevicePathLength) &&\r
274 (CompareMem (\r
c411b485
MK
275 DevInfo->DevicePath,\r
276 DevicePath,\r
277 DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)\r
278 ) == 0))\r
279 {\r
e8959f81
HW
280 //\r
281 // If device locked, unlock first.\r
282 //\r
283 if (!IsZeroBuffer (DevInfo->Password, HDD_PASSWORD_MAX_LENGTH)) {\r
284 UnlockDevice (AtaPassThruPpi, Port, PortMultiplierPort, 0, DevInfo->Password);\r
285 }\r
c411b485 286\r
e8959f81
HW
287 //\r
288 // Freeze lock the device.\r
289 //\r
290 FreezeLockDevice (AtaPassThruPpi, Port, PortMultiplierPort);\r
291 break;\r
292 }\r
293\r
294 DevInfo = (HDD_PASSWORD_DEVICE_INFO *)\r
c411b485 295 ((UINTN)DevInfo + sizeof (HDD_PASSWORD_DEVICE_INFO) + DevInfo->DevicePathLength);\r
e8959f81
HW
296 }\r
297 }\r
298 }\r
299\r
300Exit:\r
301 ZeroMem (Buffer, Length);\r
302 FreePages (Buffer, EFI_SIZE_TO_PAGES (Length));\r
e8959f81
HW
303}\r
304\r
305/**\r
306 Entry point of the notification callback function itself within the PEIM.\r
307 It is to unlock HDD password for S3.\r
308\r
309 @param PeiServices Indirect reference to the PEI Services Table.\r
310 @param NotifyDescriptor Address of the notification descriptor data structure.\r
311 @param Ppi Address of the PPI that was installed.\r
312\r
313 @return Status of the notification.\r
314 The status code returned from this function is ignored.\r
315**/\r
316EFI_STATUS\r
317EFIAPI\r
318HddPasswordAtaPassThruNotify (\r
c411b485
MK
319 IN EFI_PEI_SERVICES **PeiServices,\r
320 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
321 IN VOID *Ppi\r
e8959f81
HW
322 )\r
323{\r
324 DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__));\r
325\r
c411b485 326 UnlockHddPassword ((EDKII_PEI_ATA_PASS_THRU_PPI *)Ppi);\r
e8959f81
HW
327\r
328 DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__));\r
329\r
330 return EFI_SUCCESS;\r
331}\r
332\r
c411b485 333EFI_PEI_NOTIFY_DESCRIPTOR mHddPasswordAtaPassThruPpiNotifyDesc = {\r
e8959f81
HW
334 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
335 &gEdkiiPeiAtaPassThruPpiGuid,\r
336 HddPasswordAtaPassThruNotify\r
337};\r
338\r
e8959f81
HW
339/**\r
340 Main entry for this module.\r
341\r
342 @param FileHandle Handle of the file being invoked.\r
343 @param PeiServices Pointer to PEI Services table.\r
344\r
345 @return Status from PeiServicesNotifyPpi.\r
346\r
347**/\r
348EFI_STATUS\r
349EFIAPI\r
350HddPasswordPeiInit (\r
c411b485
MK
351 IN EFI_PEI_FILE_HANDLE FileHandle,\r
352 IN CONST EFI_PEI_SERVICES **PeiServices\r
e8959f81
HW
353 )\r
354{\r
c411b485
MK
355 EFI_STATUS Status;\r
356 EFI_BOOT_MODE BootMode;\r
e8959f81
HW
357\r
358 Status = PeiServicesGetBootMode (&BootMode);\r
359 if ((EFI_ERROR (Status)) || (BootMode != BOOT_ON_S3_RESUME)) {\r
360 return EFI_UNSUPPORTED;\r
361 }\r
362\r
363 DEBUG ((DEBUG_INFO, "%a: Enters in S3 path.\n", __FUNCTION__));\r
364\r
365 Status = PeiServicesNotifyPpi (&mHddPasswordAtaPassThruPpiNotifyDesc);\r
366 ASSERT_EFI_ERROR (Status);\r
367 return Status;\r
368}\r