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