]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/HddPassword/HddPasswordDxe.c
SecurityPkg: don't require PK to be self-signed by default
[mirror_edk2.git] / SecurityPkg / HddPassword / HddPasswordDxe.c
CommitLineData
e8959f81
HW
1/** @file\r
2 HDD password driver which is used to support HDD security feature.\r
3\r
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
3571e136 5 Copyright (c) Microsoft Corporation.<BR>\r
e8959f81 6\r
289b714b 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
e8959f81
HW
8\r
9**/\r
10\r
11#include "HddPasswordDxe.h"\r
12\r
c411b485
MK
13EFI_GUID mHddPasswordVendorGuid = HDD_PASSWORD_CONFIG_GUID;\r
14CHAR16 mHddPasswordVendorStorageName[] = L"HDD_PASSWORD_CONFIG";\r
15LIST_ENTRY mHddPasswordConfigFormList;\r
16UINT32 mNumberOfHddDevices = 0;\r
e8959f81 17\r
c411b485
MK
18EFI_GUID mHddPasswordDeviceInfoGuid = HDD_PASSWORD_DEVICE_INFO_GUID;\r
19BOOLEAN mHddPasswordEndOfDxe = FALSE;\r
20HDD_PASSWORD_REQUEST_VARIABLE *mHddPasswordRequestVariable = NULL;\r
21UINTN mHddPasswordRequestVariableSize = 0;\r
e8959f81 22\r
c411b485 23HII_VENDOR_DEVICE_PATH mHddPasswordHiiVendorDevicePath = {\r
e8959f81
HW
24 {\r
25 {\r
26 HARDWARE_DEVICE_PATH,\r
27 HW_VENDOR_DP,\r
28 {\r
c411b485
MK
29 (UINT8)(sizeof (VENDOR_DEVICE_PATH)),\r
30 (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
e8959f81
HW
31 }\r
32 },\r
33 HDD_PASSWORD_CONFIG_GUID\r
34 },\r
35 {\r
36 END_DEVICE_PATH_TYPE,\r
37 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
38 {\r
c411b485
MK
39 (UINT8)(END_DEVICE_PATH_LENGTH),\r
40 (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)\r
e8959f81
HW
41 }\r
42 }\r
43};\r
44\r
e8959f81
HW
45/**\r
46 Check if the password is full zero.\r
47\r
48 @param[in] Password Points to the data buffer\r
49\r
50 @retval TRUE This password string is full zero.\r
51 @retval FALSE This password string is not full zero.\r
52\r
53**/\r
54BOOLEAN\r
55PasswordIsFullZero (\r
c411b485 56 IN CHAR8 *Password\r
e8959f81
HW
57 )\r
58{\r
c411b485 59 UINTN Index;\r
e8959f81
HW
60\r
61 for (Index = 0; Index < HDD_PASSWORD_MAX_LENGTH; Index++) {\r
62 if (Password[Index] != 0) {\r
63 return FALSE;\r
64 }\r
65 }\r
66\r
67 return TRUE;\r
68}\r
69\r
70/**\r
71 Save device info.\r
72\r
73 @param[in] ConfigFormEntry Points to HDD_PASSWORD_CONFIG_FORM_ENTRY buffer\r
74 @param[in,out] TempDevInfo Points to HDD_PASSWORD_DEVICE_INFO buffer\r
75\r
76**/\r
77VOID\r
78SaveDeviceInfo (\r
c411b485
MK
79 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,\r
80 IN OUT HDD_PASSWORD_DEVICE_INFO *TempDevInfo\r
e8959f81
HW
81 )\r
82{\r
c411b485
MK
83 TempDevInfo->Device.Bus = (UINT8)ConfigFormEntry->Bus;\r
84 TempDevInfo->Device.Device = (UINT8)ConfigFormEntry->Device;\r
85 TempDevInfo->Device.Function = (UINT8)ConfigFormEntry->Function;\r
e8959f81
HW
86 TempDevInfo->Device.Port = ConfigFormEntry->Port;\r
87 TempDevInfo->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
88 CopyMem (TempDevInfo->Password, ConfigFormEntry->Password, HDD_PASSWORD_MAX_LENGTH);\r
c411b485 89 TempDevInfo->DevicePathLength = (UINT32)GetDevicePathSize (ConfigFormEntry->DevicePath);\r
e8959f81
HW
90 CopyMem (TempDevInfo->DevicePath, ConfigFormEntry->DevicePath, TempDevInfo->DevicePathLength);\r
91}\r
92\r
93/**\r
94 Build HDD password device info and save them to LockBox.\r
95\r
96 **/\r
97VOID\r
98BuildHddPasswordDeviceInfo (\r
99 VOID\r
100 )\r
101{\r
c411b485
MK
102 EFI_STATUS Status;\r
103 LIST_ENTRY *Entry;\r
104 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
105 HDD_PASSWORD_DEVICE_INFO *DevInfo;\r
106 HDD_PASSWORD_DEVICE_INFO *TempDevInfo;\r
107 UINTN DevInfoLength;\r
108 UINT8 DummyData;\r
109 BOOLEAN S3InitDevicesExist;\r
110 UINTN S3InitDevicesLength;\r
111 EFI_DEVICE_PATH_PROTOCOL *S3InitDevices;\r
112 EFI_DEVICE_PATH_PROTOCOL *S3InitDevicesBak;\r
e8959f81
HW
113\r
114 //\r
115 // Build HDD password device info and save them to LockBox.\r
116 //\r
117 DevInfoLength = 0;\r
3571e136 118 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
e8959f81
HW
119 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
120\r
121 //\r
122 // 1. Handle device which already set password.\r
d6b926e7 123 // 2. When request to send freeze command, driver also needs to handle device\r
e8959f81
HW
124 // which support security feature.\r
125 //\r
126 if ((!PasswordIsFullZero (ConfigFormEntry->Password)) ||\r
127 ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&\r
c411b485
MK
128 (ConfigFormEntry->IfrData.SecurityStatus.Enabled == 0)))\r
129 {\r
e8959f81
HW
130 DevInfoLength += sizeof (HDD_PASSWORD_DEVICE_INFO) +\r
131 GetDevicePathSize (ConfigFormEntry->DevicePath);\r
132 }\r
133 }\r
134\r
135 if (DevInfoLength == 0) {\r
136 return;\r
137 }\r
138\r
139 S3InitDevicesLength = sizeof (DummyData);\r
c411b485
MK
140 Status = RestoreLockBox (\r
141 &gS3StorageDeviceInitListGuid,\r
142 &DummyData,\r
143 &S3InitDevicesLength\r
144 );\r
e8959f81
HW
145 ASSERT ((Status == EFI_NOT_FOUND) || (Status == EFI_BUFFER_TOO_SMALL));\r
146 if (Status == EFI_NOT_FOUND) {\r
147 S3InitDevices = NULL;\r
148 S3InitDevicesExist = FALSE;\r
149 } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
150 S3InitDevices = AllocatePool (S3InitDevicesLength);\r
151 ASSERT (S3InitDevices != NULL);\r
152\r
153 Status = RestoreLockBox (\r
154 &gS3StorageDeviceInitListGuid,\r
155 S3InitDevices,\r
156 &S3InitDevicesLength\r
157 );\r
158 ASSERT_EFI_ERROR (Status);\r
159 S3InitDevicesExist = TRUE;\r
160 } else {\r
161 return;\r
162 }\r
163\r
164 DevInfo = AllocateZeroPool (DevInfoLength);\r
165 ASSERT (DevInfo != NULL);\r
166\r
167 TempDevInfo = DevInfo;\r
3571e136 168 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
e8959f81
HW
169 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
170\r
171 if ((!PasswordIsFullZero (ConfigFormEntry->Password)) ||\r
172 ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&\r
c411b485
MK
173 (ConfigFormEntry->IfrData.SecurityStatus.Enabled == 0)))\r
174 {\r
e8959f81
HW
175 SaveDeviceInfo (ConfigFormEntry, TempDevInfo);\r
176\r
177 S3InitDevicesBak = S3InitDevices;\r
178 S3InitDevices = AppendDevicePathInstance (\r
179 S3InitDevicesBak,\r
180 ConfigFormEntry->DevicePath\r
181 );\r
182 if (S3InitDevicesBak != NULL) {\r
183 FreePool (S3InitDevicesBak);\r
184 }\r
c411b485 185\r
e8959f81
HW
186 ASSERT (S3InitDevices != NULL);\r
187\r
c411b485
MK
188 TempDevInfo = (HDD_PASSWORD_DEVICE_INFO *)((UINTN)TempDevInfo +\r
189 sizeof (HDD_PASSWORD_DEVICE_INFO) +\r
190 TempDevInfo->DevicePathLength);\r
e8959f81
HW
191 }\r
192 }\r
193\r
194 Status = SaveLockBox (\r
195 &mHddPasswordDeviceInfoGuid,\r
196 DevInfo,\r
197 DevInfoLength\r
198 );\r
199 ASSERT_EFI_ERROR (Status);\r
200\r
201 Status = SetLockBoxAttributes (\r
202 &mHddPasswordDeviceInfoGuid,\r
203 LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
204 );\r
205 ASSERT_EFI_ERROR (Status);\r
206\r
207 S3InitDevicesLength = GetDevicePathSize (S3InitDevices);\r
208 if (S3InitDevicesExist) {\r
209 Status = UpdateLockBox (\r
210 &gS3StorageDeviceInitListGuid,\r
211 0,\r
212 S3InitDevices,\r
213 S3InitDevicesLength\r
214 );\r
215 ASSERT_EFI_ERROR (Status);\r
216 } else {\r
217 Status = SaveLockBox (\r
218 &gS3StorageDeviceInitListGuid,\r
219 S3InitDevices,\r
220 S3InitDevicesLength\r
221 );\r
222 ASSERT_EFI_ERROR (Status);\r
223\r
224 Status = SetLockBoxAttributes (\r
225 &gS3StorageDeviceInitListGuid,\r
226 LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
227 );\r
228 ASSERT_EFI_ERROR (Status);\r
229 }\r
230\r
231 ZeroMem (DevInfo, DevInfoLength);\r
232 FreePool (DevInfo);\r
233 FreePool (S3InitDevices);\r
234}\r
235\r
236/**\r
237 Send freeze lock cmd through Ata Pass Thru Protocol.\r
238\r
239 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
240 @param[in] Port The port number of the ATA device to send the command.\r
241 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
242 If there is no port multiplier, then specify 0xFFFF.\r
243\r
244 @retval EFI_SUCCESS Successful to send freeze lock cmd.\r
245 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
246 @retval EFI_OUT_OF_RESOURCES Not enough memory to send freeze lock cmd.\r
247 @retval EFI_DEVICE_ERROR Can not send freeze lock cmd.\r
248\r
249**/\r
250EFI_STATUS\r
251FreezeLockDevice (\r
c411b485
MK
252 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
253 IN UINT16 Port,\r
254 IN UINT16 PortMultiplierPort\r
e8959f81
HW
255 )\r
256{\r
257 EFI_STATUS Status;\r
258 EFI_ATA_COMMAND_BLOCK Acb;\r
259 EFI_ATA_STATUS_BLOCK *Asb;\r
260 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
261\r
262 if (AtaPassThru == NULL) {\r
263 return EFI_INVALID_PARAMETER;\r
264 }\r
265\r
266 //\r
267 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
268 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
269 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
270 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
271 // may not be aligned when allocated on stack for some compilers. Hence, we\r
272 // use the API AllocateAlignedPages to ensure this structure is properly\r
273 // aligned.\r
274 //\r
275 Asb = AllocateAlignedPages (\r
276 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
277 AtaPassThru->Mode->IoAlign\r
278 );\r
279 if (Asb == NULL) {\r
280 return EFI_OUT_OF_RESOURCES;\r
281 }\r
282\r
283 //\r
284 // Prepare for ATA command block.\r
285 //\r
286 ZeroMem (&Acb, sizeof (Acb));\r
287 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
288 Acb.AtaCommand = ATA_SECURITY_FREEZE_LOCK_CMD;\r
c411b485 289 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
e8959f81
HW
290\r
291 //\r
292 // Prepare for ATA pass through packet.\r
293 //\r
294 ZeroMem (&Packet, sizeof (Packet));\r
295 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;\r
296 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER;\r
297 Packet.Asb = Asb;\r
298 Packet.Acb = &Acb;\r
299 Packet.Timeout = ATA_TIMEOUT;\r
300\r
301 Status = AtaPassThru->PassThru (\r
302 AtaPassThru,\r
303 Port,\r
304 PortMultiplierPort,\r
305 &Packet,\r
306 NULL\r
307 );\r
308 if (!EFI_ERROR (Status) &&\r
309 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
c411b485
MK
310 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))\r
311 {\r
e8959f81
HW
312 Status = EFI_DEVICE_ERROR;\r
313 }\r
314\r
315 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
316\r
317 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
318 return Status;\r
319}\r
320\r
321/**\r
322 Get attached harddisk identify data through Ata Pass Thru Protocol.\r
323\r
324 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
325 @param[in] Port The port number of the ATA device to send the command.\r
326 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
327 If there is no port multiplier, then specify 0xFFFF.\r
328 @param[in] IdentifyData The buffer to store identify data.\r
329\r
330 @retval EFI_SUCCESS Successful to get identify data.\r
331 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
332 @retval EFI_OUT_OF_RESOURCES Not enough memory to get identify data.\r
333 @retval EFI_DEVICE_ERROR Can not get identify data.\r
334\r
335**/\r
336EFI_STATUS\r
337GetHddDeviceIdentifyData (\r
c411b485
MK
338 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
339 IN UINT16 Port,\r
340 IN UINT16 PortMultiplierPort,\r
341 IN ATA_IDENTIFY_DATA *IdentifyData\r
e8959f81
HW
342 )\r
343{\r
344 EFI_STATUS Status;\r
345 EFI_ATA_COMMAND_BLOCK Acb;\r
346 EFI_ATA_STATUS_BLOCK *Asb;\r
347 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
348\r
349 if ((AtaPassThru == NULL) || (IdentifyData == NULL)) {\r
350 return EFI_INVALID_PARAMETER;\r
351 }\r
352\r
353 //\r
354 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
355 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
356 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
357 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
358 // may not be aligned when allocated on stack for some compilers. Hence, we\r
359 // use the API AllocateAlignedPages to ensure this structure is properly\r
360 // aligned.\r
361 //\r
362 Asb = AllocateAlignedPages (\r
363 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
364 AtaPassThru->Mode->IoAlign\r
365 );\r
366 if (Asb == NULL) {\r
367 return EFI_OUT_OF_RESOURCES;\r
368 }\r
369\r
370 //\r
371 // Prepare for ATA command block.\r
372 //\r
373 ZeroMem (&Acb, sizeof (Acb));\r
374 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
375 Acb.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
c411b485 376 Acb.AtaDeviceHead = (UINT8)(BIT7 | BIT6 | BIT5 | (PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4)));\r
e8959f81
HW
377\r
378 //\r
379 // Prepare for ATA pass through packet.\r
380 //\r
381 ZeroMem (&Packet, sizeof (Packet));\r
c411b485
MK
382 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;\r
383 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
384 Packet.Asb = Asb;\r
385 Packet.Acb = &Acb;\r
e8959f81
HW
386 Packet.InDataBuffer = IdentifyData;\r
387 Packet.InTransferLength = sizeof (ATA_IDENTIFY_DATA);\r
388 Packet.Timeout = ATA_TIMEOUT;\r
389\r
390 Status = AtaPassThru->PassThru (\r
391 AtaPassThru,\r
392 Port,\r
393 PortMultiplierPort,\r
394 &Packet,\r
395 NULL\r
396 );\r
397\r
398 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
399\r
400 return Status;\r
401}\r
402\r
403/**\r
404 Parse security status according to identify data.\r
405\r
406 @param[in] IdentifyData The buffer to store identify data.\r
407 @param[in, out] IfrData IFR data to hold security status.\r
408\r
409**/\r
410VOID\r
411GetHddPasswordSecurityStatus (\r
412 IN ATA_IDENTIFY_DATA *IdentifyData,\r
413 IN OUT HDD_PASSWORD_CONFIG *IfrData\r
414 )\r
415{\r
c411b485
MK
416 IfrData->SecurityStatus.Supported = (IdentifyData->command_set_supported_82 & BIT1) ? 1 : 0;\r
417 IfrData->SecurityStatus.Enabled = (IdentifyData->security_status & BIT1) ? 1 : 0;\r
418 IfrData->SecurityStatus.Locked = (IdentifyData->security_status & BIT2) ? 1 : 0;\r
419 IfrData->SecurityStatus.Frozen = (IdentifyData->security_status & BIT3) ? 1 : 0;\r
e8959f81
HW
420 IfrData->SecurityStatus.UserPasswordStatus = IfrData->SecurityStatus.Enabled;\r
421 IfrData->SecurityStatus.MasterPasswordStatus = IfrData->SecurityStatus.Supported;\r
422\r
423 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Supported = %x\n", IfrData->SecurityStatus.Supported));\r
424 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Enabled = %x\n", IfrData->SecurityStatus.Enabled));\r
425 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Locked = %x\n", IfrData->SecurityStatus.Locked));\r
426 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Frozen = %x\n", IfrData->SecurityStatus.Frozen));\r
427 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.UserPasswordStatus = %x\n", IfrData->SecurityStatus.UserPasswordStatus));\r
428 DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.MasterPasswordStatus = %x\n", IfrData->SecurityStatus.MasterPasswordStatus));\r
429}\r
430\r
431/**\r
432 Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
433\r
434 This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
435\r
436 @param Event Event whose notification function is being invoked.\r
437 @param Context Pointer to the notification function's context.\r
438\r
439**/\r
440VOID\r
441EFIAPI\r
442HddPasswordEndOfDxeEventNotify (\r
c411b485
MK
443 EFI_EVENT Event,\r
444 VOID *Context\r
e8959f81
HW
445 )\r
446{\r
c411b485
MK
447 LIST_ENTRY *Entry;\r
448 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
449 EFI_STATUS Status;\r
450 ATA_IDENTIFY_DATA IdentifyData;\r
e8959f81
HW
451\r
452 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
453\r
454 mHddPasswordEndOfDxe = TRUE;\r
455\r
456 if (mHddPasswordRequestVariable != NULL) {\r
457 //\r
458 // Free the HDD password request variable buffer here\r
459 // as the HDD password requests should have been processed.\r
460 //\r
461 FreePool (mHddPasswordRequestVariable);\r
c411b485 462 mHddPasswordRequestVariable = NULL;\r
e8959f81
HW
463 mHddPasswordRequestVariableSize = 0;\r
464 }\r
465\r
466 //\r
467 // If no any device, return directly.\r
468 //\r
469 if (IsListEmpty (&mHddPasswordConfigFormList)) {\r
470 gBS->CloseEvent (Event);\r
471 return;\r
472 }\r
473\r
474 BuildHddPasswordDeviceInfo ();\r
475\r
476 //\r
477 // Zero passsword and freeze lock device.\r
478 //\r
3571e136 479 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
e8959f81
HW
480 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
481\r
482 ZeroMem (ConfigFormEntry->Password, HDD_PASSWORD_MAX_LENGTH);\r
483\r
484 //\r
485 // Check whether need send freeze lock command.\r
486 // Below device will be froze:\r
487 // 1. Device not enable password.\r
488 // 2. Device enable password and unlocked.\r
489 //\r
490 if ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&\r
491 (ConfigFormEntry->IfrData.SecurityStatus.Locked == 0) &&\r
c411b485
MK
492 (ConfigFormEntry->IfrData.SecurityStatus.Frozen == 0))\r
493 {\r
e8959f81
HW
494 Status = FreezeLockDevice (ConfigFormEntry->AtaPassThru, ConfigFormEntry->Port, ConfigFormEntry->PortMultiplierPort);\r
495 DEBUG ((DEBUG_INFO, "FreezeLockDevice return %r!\n", Status));\r
496 Status = GetHddDeviceIdentifyData (\r
497 ConfigFormEntry->AtaPassThru,\r
498 ConfigFormEntry->Port,\r
499 ConfigFormEntry->PortMultiplierPort,\r
500 &IdentifyData\r
501 );\r
502 GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);\r
503 }\r
504 }\r
505\r
506 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
507\r
508 gBS->CloseEvent (Event);\r
509}\r
510\r
511/**\r
512 Generate Salt value.\r
513\r
514 @param[in, out] SaltValue Points to the salt buffer, 32 bytes\r
515\r
516**/\r
517VOID\r
518GenSalt (\r
519 IN OUT UINT8 *SaltValue\r
520 )\r
521{\r
522 RandomSeed (NULL, 0);\r
523 RandomBytes (SaltValue, PASSWORD_SALT_SIZE);\r
524}\r
525\r
526/**\r
527 Hash the data to get credential.\r
528\r
529 @param[in] Buffer Points to the data buffer\r
530 @param[in] BufferSize Buffer size\r
531 @param[in] SaltValue Points to the salt buffer, 32 bytes\r
532 @param[out] Credential Points to the hashed result\r
533\r
534 @retval TRUE Hash the data successfully.\r
535 @retval FALSE Failed to hash the data.\r
536\r
537**/\r
538BOOLEAN\r
539GenerateCredential (\r
c411b485
MK
540 IN UINT8 *Buffer,\r
541 IN UINTN BufferSize,\r
542 IN UINT8 *SaltValue,\r
543 OUT UINT8 *Credential\r
e8959f81
HW
544 )\r
545{\r
c411b485
MK
546 BOOLEAN Status;\r
547 UINTN HashSize;\r
548 VOID *Hash;\r
549 VOID *HashData;\r
e8959f81 550\r
c411b485
MK
551 Hash = NULL;\r
552 HashData = NULL;\r
553 Status = FALSE;\r
e8959f81
HW
554\r
555 HashSize = Sha256GetContextSize ();\r
556 Hash = AllocateZeroPool (HashSize);\r
557 ASSERT (Hash != NULL);\r
558 if (Hash == NULL) {\r
559 goto Done;\r
560 }\r
561\r
562 Status = Sha256Init (Hash);\r
563 if (!Status) {\r
564 goto Done;\r
565 }\r
566\r
567 HashData = AllocateZeroPool (PASSWORD_SALT_SIZE + BufferSize);\r
568 ASSERT (HashData != NULL);\r
569 if (HashData == NULL) {\r
570 goto Done;\r
571 }\r
572\r
573 CopyMem (HashData, SaltValue, PASSWORD_SALT_SIZE);\r
c411b485 574 CopyMem ((UINT8 *)HashData + PASSWORD_SALT_SIZE, Buffer, BufferSize);\r
e8959f81
HW
575\r
576 Status = Sha256Update (Hash, HashData, PASSWORD_SALT_SIZE + BufferSize);\r
577 if (!Status) {\r
578 goto Done;\r
579 }\r
580\r
581 Status = Sha256Final (Hash, Credential);\r
582\r
583Done:\r
584 if (Hash != NULL) {\r
585 FreePool (Hash);\r
586 }\r
c411b485 587\r
e8959f81
HW
588 if (HashData != NULL) {\r
589 ZeroMem (HashData, PASSWORD_SALT_SIZE + BufferSize);\r
590 FreePool (HashData);\r
591 }\r
c411b485 592\r
e8959f81
HW
593 return Status;\r
594}\r
595\r
596/**\r
597 Save HDD password variable that will be used to validate HDD password\r
598 when the device is at frozen state.\r
599\r
600 @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
601 @param[in] Password The hdd password of attached ATA device.\r
602\r
603**/\r
604VOID\r
605SaveHddPasswordVariable (\r
c411b485
MK
606 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,\r
607 IN CHAR8 *Password\r
e8959f81
HW
608 )\r
609{\r
c411b485
MK
610 EFI_STATUS Status;\r
611 HDD_PASSWORD_VARIABLE *TempVariable;\r
612 UINTN TempVariableSize;\r
613 HDD_PASSWORD_VARIABLE *NextNode;\r
614 HDD_PASSWORD_VARIABLE *Variable;\r
615 UINTN VariableSize;\r
616 HDD_PASSWORD_VARIABLE *NewVariable;\r
617 UINTN NewVariableSize;\r
618 BOOLEAN Delete;\r
619 BOOLEAN HashOk;\r
620 UINT8 HashData[SHA256_DIGEST_SIZE];\r
621 UINT8 SaltData[PASSWORD_SALT_SIZE];\r
e8959f81
HW
622\r
623 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
624\r
625 Delete = FALSE;\r
626 if (!PasswordIsFullZero (Password)) {\r
627 //\r
628 // It is Set/Update HDD Password.\r
629 //\r
630 ZeroMem (HashData, sizeof (HashData));\r
631 ZeroMem (SaltData, sizeof (SaltData));\r
632 GenSalt (SaltData);\r
c411b485 633 HashOk = GenerateCredential ((UINT8 *)Password, HDD_PASSWORD_MAX_LENGTH, SaltData, HashData);\r
e8959f81
HW
634 if (!HashOk) {\r
635 DEBUG ((DEBUG_INFO, "GenerateCredential failed\n"));\r
636 return;\r
637 }\r
638 } else {\r
639 //\r
640 // It is Disable HDD Password.\r
641 // Go to delete the variable node for the HDD password device.\r
642 //\r
643 Delete = TRUE;\r
644 }\r
645\r
c411b485
MK
646 Variable = NULL;\r
647 VariableSize = 0;\r
648 NewVariable = NULL;\r
e8959f81
HW
649 NewVariableSize = 0;\r
650\r
651 Status = GetVariable2 (\r
652 HDD_PASSWORD_VARIABLE_NAME,\r
653 &mHddPasswordVendorGuid,\r
c411b485 654 (VOID **)&Variable,\r
e8959f81
HW
655 &VariableSize\r
656 );\r
657 if (Delete) {\r
658 if (!EFI_ERROR (Status) && (Variable != NULL)) {\r
c411b485 659 TempVariable = Variable;\r
e8959f81
HW
660 TempVariableSize = VariableSize;\r
661 while (TempVariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {\r
662 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
663 (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
664 (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
665 (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
c411b485
MK
666 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))\r
667 {\r
e8959f81
HW
668 //\r
669 // Found the node for the HDD password device.\r
670 // Delete the node.\r
671 //\r
672 NextNode = TempVariable + 1;\r
c411b485
MK
673 CopyMem (TempVariable, NextNode, (UINTN)Variable + VariableSize - (UINTN)NextNode);\r
674 NewVariable = Variable;\r
e8959f81
HW
675 NewVariableSize = VariableSize - sizeof (HDD_PASSWORD_VARIABLE);\r
676 break;\r
677 }\r
c411b485 678\r
e8959f81 679 TempVariableSize -= sizeof (HDD_PASSWORD_VARIABLE);\r
c411b485 680 TempVariable += 1;\r
e8959f81 681 }\r
c411b485 682\r
e8959f81
HW
683 if (NewVariable == NULL) {\r
684 DEBUG ((DEBUG_INFO, "The variable node for the HDD password device is not found\n"));\r
685 }\r
686 } else {\r
687 DEBUG ((DEBUG_INFO, "HddPassword variable get failed (%r)\n", Status));\r
688 }\r
689 } else {\r
690 if (!EFI_ERROR (Status) && (Variable != NULL)) {\r
c411b485 691 TempVariable = Variable;\r
e8959f81
HW
692 TempVariableSize = VariableSize;\r
693 while (TempVariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {\r
694 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
695 (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
696 (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
697 (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
c411b485
MK
698 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))\r
699 {\r
e8959f81
HW
700 //\r
701 // Found the node for the HDD password device.\r
702 // Update the node.\r
703 //\r
704 CopyMem (TempVariable->PasswordHash, HashData, sizeof (HashData));\r
705 CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltData));\r
c411b485 706 NewVariable = Variable;\r
e8959f81
HW
707 NewVariableSize = VariableSize;\r
708 break;\r
709 }\r
c411b485 710\r
e8959f81 711 TempVariableSize -= sizeof (HDD_PASSWORD_VARIABLE);\r
c411b485 712 TempVariable += 1;\r
e8959f81 713 }\r
c411b485 714\r
e8959f81
HW
715 if (NewVariable == NULL) {\r
716 //\r
717 // The node for the HDD password device is not found.\r
718 // Create node for the HDD password device.\r
719 //\r
720 NewVariableSize = VariableSize + sizeof (HDD_PASSWORD_VARIABLE);\r
c411b485 721 NewVariable = AllocateZeroPool (NewVariableSize);\r
e8959f81
HW
722 ASSERT (NewVariable != NULL);\r
723 CopyMem (NewVariable, Variable, VariableSize);\r
c411b485
MK
724 TempVariable = (HDD_PASSWORD_VARIABLE *)((UINTN)NewVariable + VariableSize);\r
725 TempVariable->Device.Bus = (UINT8)ConfigFormEntry->Bus;\r
726 TempVariable->Device.Device = (UINT8)ConfigFormEntry->Device;\r
727 TempVariable->Device.Function = (UINT8)ConfigFormEntry->Function;\r
e8959f81
HW
728 TempVariable->Device.Port = ConfigFormEntry->Port;\r
729 TempVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
730 CopyMem (TempVariable->PasswordHash, HashData, sizeof (HashData));\r
731 CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltData));\r
732 }\r
733 } else {\r
734 NewVariableSize = sizeof (HDD_PASSWORD_VARIABLE);\r
c411b485 735 NewVariable = AllocateZeroPool (NewVariableSize);\r
e8959f81 736 ASSERT (NewVariable != NULL);\r
c411b485
MK
737 NewVariable->Device.Bus = (UINT8)ConfigFormEntry->Bus;\r
738 NewVariable->Device.Device = (UINT8)ConfigFormEntry->Device;\r
739 NewVariable->Device.Function = (UINT8)ConfigFormEntry->Function;\r
e8959f81
HW
740 NewVariable->Device.Port = ConfigFormEntry->Port;\r
741 NewVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
742 CopyMem (NewVariable->PasswordHash, HashData, sizeof (HashData));\r
743 CopyMem (NewVariable->PasswordSalt, SaltData, sizeof (SaltData));\r
744 }\r
745 }\r
746\r
747 if (NewVariable != NULL) {\r
748 Status = gRT->SetVariable (\r
749 HDD_PASSWORD_VARIABLE_NAME,\r
750 &mHddPasswordVendorGuid,\r
751 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
752 NewVariableSize,\r
753 NewVariable\r
754 );\r
755 if (EFI_ERROR (Status)) {\r
756 DEBUG ((DEBUG_INFO, "HddPassword variable set failed (%r)\n", Status));\r
757 }\r
758 }\r
759\r
760 if (NewVariable != Variable) {\r
761 FreePool (NewVariable);\r
762 }\r
c411b485 763\r
e8959f81
HW
764 if (Variable != NULL) {\r
765 FreePool (Variable);\r
766 }\r
767\r
768 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
769}\r
770\r
771/**\r
772 Get saved HDD password variable that will be used to validate HDD password\r
773 when the device is at frozen state.\r
774\r
775 @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
776 @param[out] HddPasswordVariable The variable node for the HDD password device.\r
777\r
778 @retval TRUE The variable node for the HDD password device is found and returned.\r
779 @retval FALSE The variable node for the HDD password device is not found.\r
780\r
781**/\r
782BOOLEAN\r
783GetSavedHddPasswordVariable (\r
c411b485
MK
784 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,\r
785 OUT HDD_PASSWORD_VARIABLE *HddPasswordVariable\r
e8959f81
HW
786 )\r
787{\r
c411b485
MK
788 EFI_STATUS Status;\r
789 HDD_PASSWORD_VARIABLE *TempVariable;\r
790 HDD_PASSWORD_VARIABLE *Variable;\r
791 UINTN VariableSize;\r
792 BOOLEAN Found;\r
e8959f81
HW
793\r
794 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
795\r
c411b485 796 Variable = NULL;\r
e8959f81
HW
797 VariableSize = 0;\r
798\r
799 Status = GetVariable2 (\r
800 HDD_PASSWORD_VARIABLE_NAME,\r
801 &mHddPasswordVendorGuid,\r
c411b485 802 (VOID **)&Variable,\r
e8959f81
HW
803 &VariableSize\r
804 );\r
805 if (EFI_ERROR (Status) || (Variable == NULL)) {\r
806 DEBUG ((DEBUG_INFO, "HddPassword variable get failed (%r)\n", Status));\r
807 return FALSE;\r
808 }\r
809\r
c411b485 810 Found = FALSE;\r
e8959f81
HW
811 TempVariable = Variable;\r
812 while (VariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {\r
813 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
814 (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
815 (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
816 (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
c411b485
MK
817 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))\r
818 {\r
e8959f81
HW
819 //\r
820 // Found the node for the HDD password device.\r
821 // Get the node.\r
822 //\r
823 CopyMem (HddPasswordVariable, TempVariable, sizeof (HDD_PASSWORD_VARIABLE));\r
824 Found = TRUE;\r
825 break;\r
826 }\r
c411b485 827\r
e8959f81
HW
828 VariableSize -= sizeof (HDD_PASSWORD_VARIABLE);\r
829 TempVariable += 1;\r
830 }\r
831\r
832 FreePool (Variable);\r
833\r
834 if (!Found) {\r
835 DEBUG ((DEBUG_INFO, "The variable node for the HDD password device is not found\n"));\r
836 }\r
837\r
838 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
839\r
840 return Found;\r
841}\r
842\r
843/**\r
844 Use saved HDD password variable to validate HDD password\r
845 when the device is at frozen state.\r
846\r
847 @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
848 @param[in] Password The hdd password of attached ATA device.\r
849\r
850 @retval EFI_SUCCESS Pass to validate the HDD password.\r
851 @retval EFI_NOT_FOUND The variable node for the HDD password device is not found.\r
852 @retval EFI_DEVICE_ERROR Failed to generate credential for the HDD password.\r
853 @retval EFI_INVALID_PARAMETER Failed to validate the HDD password.\r
854\r
855**/\r
856EFI_STATUS\r
857ValidateHddPassword (\r
c411b485
MK
858 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,\r
859 IN CHAR8 *Password\r
e8959f81
HW
860 )\r
861{\r
c411b485
MK
862 EFI_STATUS Status;\r
863 HDD_PASSWORD_VARIABLE HddPasswordVariable;\r
864 BOOLEAN HashOk;\r
865 UINT8 HashData[SHA256_DIGEST_SIZE];\r
e8959f81
HW
866\r
867 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
868\r
869 if (!GetSavedHddPasswordVariable (ConfigFormEntry, &HddPasswordVariable)) {\r
870 DEBUG ((DEBUG_INFO, "GetSavedHddPasswordVariable failed\n"));\r
871 return EFI_NOT_FOUND;\r
872 }\r
873\r
874 ZeroMem (HashData, sizeof (HashData));\r
c411b485 875 HashOk = GenerateCredential ((UINT8 *)Password, HDD_PASSWORD_MAX_LENGTH, HddPasswordVariable.PasswordSalt, HashData);\r
e8959f81
HW
876 if (!HashOk) {\r
877 DEBUG ((DEBUG_INFO, "GenerateCredential failed\n"));\r
878 return EFI_DEVICE_ERROR;\r
879 }\r
880\r
881 if (CompareMem (HddPasswordVariable.PasswordHash, HashData, sizeof (HashData)) != 0) {\r
882 Status = EFI_INVALID_PARAMETER;\r
883 } else {\r
884 Status = EFI_SUCCESS;\r
885 }\r
886\r
887 DEBUG ((DEBUG_INFO, "%a() - exit (%r)\n", __FUNCTION__, Status));\r
888 return Status;\r
889}\r
890\r
891/**\r
892 Send unlock hdd password cmd through Ata Pass Thru Protocol.\r
893\r
894 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
895 @param[in] Port The port number of the ATA device to send the command.\r
896 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
897 If there is no port multiplier, then specify 0xFFFF.\r
898 @param[in] Identifier The identifier to set user or master password.\r
899 @param[in] Password The hdd password of attached ATA device.\r
900\r
901 @retval EFI_SUCCESS Successful to send unlock hdd password cmd.\r
902 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
903 @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.\r
904 @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd.\r
905\r
906**/\r
907EFI_STATUS\r
908UnlockHddPassword (\r
c411b485
MK
909 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
910 IN UINT16 Port,\r
911 IN UINT16 PortMultiplierPort,\r
912 IN CHAR8 Identifier,\r
913 IN CHAR8 *Password\r
e8959f81
HW
914 )\r
915{\r
916 EFI_STATUS Status;\r
917 EFI_ATA_COMMAND_BLOCK Acb;\r
918 EFI_ATA_STATUS_BLOCK *Asb;\r
919 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
920 UINT8 Buffer[HDD_PAYLOAD];\r
921\r
922 if ((AtaPassThru == NULL) || (Password == NULL)) {\r
923 return EFI_INVALID_PARAMETER;\r
924 }\r
925\r
926 //\r
927 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
928 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
929 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
930 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
931 // may not be aligned when allocated on stack for some compilers. Hence, we\r
932 // use the API AllocateAlignedPages to ensure this structure is properly\r
933 // aligned.\r
934 //\r
935 Asb = AllocateAlignedPages (\r
936 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
937 AtaPassThru->Mode->IoAlign\r
938 );\r
939 if (Asb == NULL) {\r
940 return EFI_OUT_OF_RESOURCES;\r
941 }\r
942\r
943 //\r
944 // Prepare for ATA command block.\r
945 //\r
946 ZeroMem (&Acb, sizeof (Acb));\r
947 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
948 Acb.AtaCommand = ATA_SECURITY_UNLOCK_CMD;\r
c411b485 949 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
e8959f81
HW
950\r
951 //\r
952 // Prepare for ATA pass through packet.\r
953 //\r
954 ZeroMem (&Packet, sizeof (Packet));\r
955 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;\r
956 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
957 Packet.Asb = Asb;\r
958 Packet.Acb = &Acb;\r
959\r
c411b485
MK
960 ((CHAR16 *)Buffer)[0] = Identifier & BIT0;\r
961 CopyMem (&((CHAR16 *)Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);\r
e8959f81
HW
962\r
963 Packet.OutDataBuffer = Buffer;\r
964 Packet.OutTransferLength = sizeof (Buffer);\r
965 Packet.Timeout = ATA_TIMEOUT;\r
966\r
967 Status = AtaPassThru->PassThru (\r
968 AtaPassThru,\r
969 Port,\r
970 PortMultiplierPort,\r
971 &Packet,\r
972 NULL\r
973 );\r
974 if (!EFI_ERROR (Status) &&\r
975 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
c411b485
MK
976 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))\r
977 {\r
e8959f81
HW
978 Status = EFI_DEVICE_ERROR;\r
979 }\r
980\r
981 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
982\r
983 ZeroMem (Buffer, sizeof (Buffer));\r
984\r
985 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
986 return Status;\r
987}\r
988\r
989/**\r
990 Send disable hdd password cmd through Ata Pass Thru Protocol.\r
991\r
992 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
993 @param[in] Port The port number of the ATA device to send the command.\r
994 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
995 If there is no port multiplier, then specify 0xFFFF.\r
996 @param[in] Identifier The identifier to set user or master password.\r
997 @param[in] Password The hdd password of attached ATA device.\r
998\r
999 @retval EFI_SUCCESS Successful to disable hdd password cmd.\r
1000 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
1001 @retval EFI_OUT_OF_RESOURCES Not enough memory to disable hdd password cmd.\r
1002 @retval EFI_DEVICE_ERROR Can not disable hdd password cmd.\r
1003\r
1004**/\r
1005EFI_STATUS\r
1006DisableHddPassword (\r
c411b485
MK
1007 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
1008 IN UINT16 Port,\r
1009 IN UINT16 PortMultiplierPort,\r
1010 IN CHAR8 Identifier,\r
1011 IN CHAR8 *Password\r
e8959f81
HW
1012 )\r
1013{\r
1014 EFI_STATUS Status;\r
1015 EFI_ATA_COMMAND_BLOCK Acb;\r
1016 EFI_ATA_STATUS_BLOCK *Asb;\r
1017 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
1018 UINT8 Buffer[HDD_PAYLOAD];\r
1019\r
1020 if ((AtaPassThru == NULL) || (Password == NULL)) {\r
1021 return EFI_INVALID_PARAMETER;\r
1022 }\r
1023\r
1024 //\r
1025 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
1026 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
1027 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
1028 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
1029 // may not be aligned when allocated on stack for some compilers. Hence, we\r
1030 // use the API AllocateAlignedPages to ensure this structure is properly\r
1031 // aligned.\r
1032 //\r
1033 Asb = AllocateAlignedPages (\r
1034 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
1035 AtaPassThru->Mode->IoAlign\r
1036 );\r
1037 if (Asb == NULL) {\r
1038 return EFI_OUT_OF_RESOURCES;\r
1039 }\r
1040\r
1041 //\r
1042 // Prepare for ATA command block.\r
1043 //\r
1044 ZeroMem (&Acb, sizeof (Acb));\r
1045 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
1046 Acb.AtaCommand = ATA_SECURITY_DIS_PASSWORD_CMD;\r
c411b485 1047 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
e8959f81
HW
1048\r
1049 //\r
1050 // Prepare for ATA pass through packet.\r
1051 //\r
1052 ZeroMem (&Packet, sizeof (Packet));\r
1053 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;\r
1054 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
1055 Packet.Asb = Asb;\r
1056 Packet.Acb = &Acb;\r
1057\r
c411b485
MK
1058 ((CHAR16 *)Buffer)[0] = Identifier & BIT0;\r
1059 CopyMem (&((CHAR16 *)Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);\r
e8959f81
HW
1060\r
1061 Packet.OutDataBuffer = Buffer;\r
1062 Packet.OutTransferLength = sizeof (Buffer);\r
1063 Packet.Timeout = ATA_TIMEOUT;\r
1064\r
1065 Status = AtaPassThru->PassThru (\r
1066 AtaPassThru,\r
1067 Port,\r
1068 PortMultiplierPort,\r
1069 &Packet,\r
1070 NULL\r
1071 );\r
1072 if (!EFI_ERROR (Status) &&\r
1073 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
c411b485
MK
1074 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))\r
1075 {\r
e8959f81
HW
1076 Status = EFI_DEVICE_ERROR;\r
1077 }\r
1078\r
1079 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
1080\r
1081 ZeroMem (Buffer, sizeof (Buffer));\r
1082\r
1083 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
1084 return Status;\r
1085}\r
1086\r
1087/**\r
1088 Send set hdd password cmd through Ata Pass Thru Protocol.\r
1089\r
1090 @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
1091 @param[in] Port The port number of the ATA device to send the command.\r
1092 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
1093 If there is no port multiplier, then specify 0xFFFF.\r
1094 @param[in] Identifier The identifier to set user or master password.\r
1095 @param[in] SecurityLevel The security level to be set to device.\r
1096 @param[in] MasterPasswordIdentifier The master password identifier to be set to device.\r
1097 @param[in] Password The hdd password of attached ATA device.\r
1098\r
1099 @retval EFI_SUCCESS Successful to set hdd password cmd.\r
1100 @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
1101 @retval EFI_OUT_OF_RESOURCES Not enough memory to set hdd password cmd.\r
1102 @retval EFI_DEVICE_ERROR Can not set hdd password cmd.\r
1103\r
1104**/\r
1105EFI_STATUS\r
1106SetHddPassword (\r
c411b485
MK
1107 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
1108 IN UINT16 Port,\r
1109 IN UINT16 PortMultiplierPort,\r
1110 IN CHAR8 Identifier,\r
1111 IN CHAR8 SecurityLevel,\r
1112 IN CHAR16 MasterPasswordIdentifier,\r
1113 IN CHAR8 *Password\r
e8959f81
HW
1114 )\r
1115{\r
1116 EFI_STATUS Status;\r
1117 EFI_ATA_COMMAND_BLOCK Acb;\r
1118 EFI_ATA_STATUS_BLOCK *Asb;\r
1119 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
1120 UINT8 Buffer[HDD_PAYLOAD];\r
1121\r
1122 if ((AtaPassThru == NULL) || (Password == NULL)) {\r
1123 return EFI_INVALID_PARAMETER;\r
1124 }\r
1125\r
1126 //\r
1127 // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
1128 // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
1129 // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
1130 // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
1131 // may not be aligned when allocated on stack for some compilers. Hence, we\r
1132 // use the API AllocateAlignedPages to ensure this structure is properly\r
1133 // aligned.\r
1134 //\r
1135 Asb = AllocateAlignedPages (\r
1136 EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
1137 AtaPassThru->Mode->IoAlign\r
1138 );\r
1139 if (Asb == NULL) {\r
1140 return EFI_OUT_OF_RESOURCES;\r
1141 }\r
1142\r
1143 //\r
1144 // Prepare for ATA command block.\r
1145 //\r
1146 ZeroMem (&Acb, sizeof (Acb));\r
1147 ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
1148 Acb.AtaCommand = ATA_SECURITY_SET_PASSWORD_CMD;\r
c411b485 1149 Acb.AtaDeviceHead = (UINT8)(PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
e8959f81
HW
1150\r
1151 //\r
1152 // Prepare for ATA pass through packet.\r
1153 //\r
1154 ZeroMem (&Packet, sizeof (Packet));\r
1155 Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;\r
1156 Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
1157 Packet.Asb = Asb;\r
1158 Packet.Acb = &Acb;\r
1159\r
c411b485
MK
1160 ((CHAR16 *)Buffer)[0] = (Identifier | (UINT16)(SecurityLevel << 8)) & (BIT0 | BIT8);\r
1161 CopyMem (&((CHAR16 *)Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);\r
e8959f81 1162 if ((Identifier & BIT0) != 0) {\r
c411b485 1163 ((CHAR16 *)Buffer)[17] = MasterPasswordIdentifier;\r
e8959f81
HW
1164 }\r
1165\r
1166 Packet.OutDataBuffer = Buffer;\r
1167 Packet.OutTransferLength = sizeof (Buffer);\r
1168 Packet.Timeout = ATA_TIMEOUT;\r
1169\r
1170 Status = AtaPassThru->PassThru (\r
1171 AtaPassThru,\r
1172 Port,\r
1173 PortMultiplierPort,\r
1174 &Packet,\r
1175 NULL\r
1176 );\r
1177 if (!EFI_ERROR (Status) &&\r
1178 ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
c411b485
MK
1179 ((Asb->AtaError & ATA_ERRREG_ABRT) != 0))\r
1180 {\r
e8959f81
HW
1181 Status = EFI_DEVICE_ERROR;\r
1182 }\r
1183\r
1184 FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
1185\r
1186 ZeroMem (Buffer, sizeof (Buffer));\r
1187\r
1188 DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
1189 return Status;\r
1190}\r
1191\r
1192/**\r
1193 Get attached harddisk model number from identify data buffer.\r
1194\r
1195 @param[in] IdentifyData Pointer to identify data buffer.\r
1196 @param[in, out] String The buffer to store harddisk model number.\r
1197\r
1198**/\r
1199VOID\r
1200GetHddDeviceModelNumber (\r
c411b485
MK
1201 IN ATA_IDENTIFY_DATA *IdentifyData,\r
1202 IN OUT CHAR16 *String\r
e8959f81
HW
1203 )\r
1204{\r
c411b485 1205 UINTN Index;\r
e8959f81
HW
1206\r
1207 //\r
1208 // Swap the byte order in the original module name.\r
1209 // From Ata spec, the maximum length is 40 bytes.\r
1210 //\r
1211 for (Index = 0; Index < 40; Index += 2) {\r
c411b485
MK
1212 String[Index] = IdentifyData->ModelName[Index + 1];\r
1213 String[Index + 1] = IdentifyData->ModelName[Index];\r
e8959f81
HW
1214 }\r
1215\r
1216 //\r
1217 // Chap it off after 20 characters\r
1218 //\r
1219 String[20] = L'\0';\r
1220\r
c411b485 1221 return;\r
e8959f81
HW
1222}\r
1223\r
1224/**\r
1225 Get password input from the popup windows.\r
1226\r
1227 @param[in] PopUpString1 Pop up string 1.\r
1228 @param[in] PopUpString2 Pop up string 2.\r
1229 @param[in, out] Password The buffer to hold the input password.\r
1230\r
1231 @retval EFI_ABORTED It is given up by pressing 'ESC' key.\r
1232 @retval EFI_SUCCESS Get password input successfully.\r
1233\r
1234**/\r
1235EFI_STATUS\r
1236PopupHddPasswordInputWindows (\r
c411b485
MK
1237 IN CHAR16 *PopUpString1,\r
1238 IN CHAR16 *PopUpString2,\r
1239 IN OUT CHAR8 *Password\r
e8959f81
HW
1240 )\r
1241{\r
c411b485
MK
1242 EFI_INPUT_KEY Key;\r
1243 UINTN Length;\r
1244 CHAR16 Mask[HDD_PASSWORD_MAX_LENGTH + 1];\r
1245 CHAR16 Unicode[HDD_PASSWORD_MAX_LENGTH + 1];\r
1246 CHAR8 Ascii[HDD_PASSWORD_MAX_LENGTH + 1];\r
e8959f81
HW
1247\r
1248 ZeroMem (Unicode, sizeof (Unicode));\r
1249 ZeroMem (Ascii, sizeof (Ascii));\r
1250 ZeroMem (Mask, sizeof (Mask));\r
1251\r
c411b485 1252 gST->ConOut->ClearScreen (gST->ConOut);\r
e8959f81
HW
1253\r
1254 Length = 0;\r
1255 while (TRUE) {\r
1256 Mask[Length] = L'_';\r
1257 if (PopUpString2 == NULL) {\r
1258 CreatePopUp (\r
1259 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1260 &Key,\r
1261 PopUpString1,\r
1262 L"---------------------",\r
1263 Mask,\r
1264 NULL\r
c411b485 1265 );\r
e8959f81
HW
1266 } else {\r
1267 CreatePopUp (\r
1268 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1269 &Key,\r
1270 PopUpString1,\r
1271 PopUpString2,\r
1272 L"---------------------",\r
1273 Mask,\r
1274 NULL\r
c411b485 1275 );\r
e8959f81 1276 }\r
c411b485 1277\r
e8959f81
HW
1278 //\r
1279 // Check key.\r
1280 //\r
1281 if (Key.ScanCode == SCAN_NULL) {\r
1282 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
1283 //\r
1284 // Add the null terminator.\r
1285 //\r
1286 Unicode[Length] = 0;\r
1287 break;\r
1288 } else if ((Key.UnicodeChar == CHAR_NULL) ||\r
1289 (Key.UnicodeChar == CHAR_TAB) ||\r
1290 (Key.UnicodeChar == CHAR_LINEFEED)\r
c411b485
MK
1291 )\r
1292 {\r
e8959f81
HW
1293 continue;\r
1294 } else {\r
1295 if (Key.UnicodeChar == CHAR_BACKSPACE) {\r
1296 if (Length > 0) {\r
1297 Unicode[Length] = 0;\r
c411b485 1298 Mask[Length] = 0;\r
e8959f81
HW
1299 Length--;\r
1300 }\r
1301 } else {\r
1302 Unicode[Length] = Key.UnicodeChar;\r
c411b485 1303 Mask[Length] = L'*';\r
e8959f81
HW
1304 Length++;\r
1305 if (Length == HDD_PASSWORD_MAX_LENGTH) {\r
1306 //\r
1307 // Add the null terminator.\r
1308 //\r
1309 Unicode[Length] = 0;\r
c411b485 1310 Mask[Length] = 0;\r
e8959f81
HW
1311 break;\r
1312 }\r
1313 }\r
1314 }\r
1315 }\r
1316\r
1317 if (Key.ScanCode == SCAN_ESC) {\r
1318 ZeroMem (Unicode, sizeof (Unicode));\r
1319 ZeroMem (Ascii, sizeof (Ascii));\r
c411b485 1320 gST->ConOut->ClearScreen (gST->ConOut);\r
e8959f81
HW
1321 return EFI_ABORTED;\r
1322 }\r
1323 }\r
1324\r
1325 UnicodeStrToAsciiStrS (Unicode, Ascii, sizeof (Ascii));\r
1326 CopyMem (Password, Ascii, HDD_PASSWORD_MAX_LENGTH);\r
1327 ZeroMem (Unicode, sizeof (Unicode));\r
1328 ZeroMem (Ascii, sizeof (Ascii));\r
1329\r
c411b485 1330 gST->ConOut->ClearScreen (gST->ConOut);\r
e8959f81
HW
1331 return EFI_SUCCESS;\r
1332}\r
1333\r
1334/**\r
1335 Check if disk is locked, show popup window and ask for password if it is.\r
1336\r
1337 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
1338 @param[in] Port The port number of attached ATA device.\r
1339 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
1340 @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
1341\r
1342**/\r
1343VOID\r
1344HddPasswordRequestPassword (\r
c411b485
MK
1345 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
1346 IN UINT16 Port,\r
1347 IN UINT16 PortMultiplierPort,\r
1348 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
e8959f81
HW
1349 )\r
1350{\r
c411b485
MK
1351 EFI_STATUS Status;\r
1352 CHAR16 PopUpString[100];\r
1353 ATA_IDENTIFY_DATA IdentifyData;\r
1354 EFI_INPUT_KEY Key;\r
1355 UINT16 RetryCount;\r
1356 CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];\r
e8959f81
HW
1357\r
1358 RetryCount = 0;\r
1359\r
1360 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1361\r
1362 UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Unlock: %s", ConfigFormEntry->HddString);\r
1363\r
1364 //\r
1365 // Check the device security status.\r
1366 //\r
1367 if ((ConfigFormEntry->IfrData.SecurityStatus.Supported) &&\r
c411b485
MK
1368 (ConfigFormEntry->IfrData.SecurityStatus.Enabled))\r
1369 {\r
1370 //\r
1371 // Add PcdSkipHddPasswordPrompt to determin whether to skip password prompt.\r
1372 // Due to board design, device may not power off during system warm boot, which result in\r
1373 // security status remain unlocked status, hence we add device security status check here.\r
1374 //\r
1375 // If device is in the locked status, device keeps locked and system continues booting.\r
1376 // If device is in the unlocked status, system is forced shutdown for security concern.\r
1377 //\r
1378 if (PcdGetBool (PcdSkipHddPasswordPrompt)) {\r
1379 if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {\r
1380 return;\r
1381 } else {\r
1382 gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
1383 }\r
9e2416ae 1384 }\r
c411b485 1385\r
e8959f81
HW
1386 //\r
1387 // As soon as the HDD password is in enabled state, we pop up a window to unlock hdd\r
1388 // no matter it's really in locked or unlocked state.\r
1389 // This way forces user to enter password every time to provide best safety.\r
1390 //\r
1391 while (TRUE) {\r
1392 Status = PopupHddPasswordInputWindows (PopUpString, NULL, Password);\r
1393 if (!EFI_ERROR (Status)) {\r
1394 //\r
1395 // The HDD is in locked state, unlock it by user input.\r
1396 //\r
1397 if (!PasswordIsFullZero (Password)) {\r
1398 if (!ConfigFormEntry->IfrData.SecurityStatus.Frozen) {\r
1399 Status = UnlockHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, Password);\r
1400 } else {\r
1401 //\r
1402 // Use saved HDD password variable to validate HDD password\r
1403 // when the device is at frozen state.\r
1404 //\r
1405 Status = ValidateHddPassword (ConfigFormEntry, Password);\r
1406 }\r
1407 } else {\r
1408 Status = EFI_INVALID_PARAMETER;\r
1409 }\r
c411b485 1410\r
e8959f81
HW
1411 if (!EFI_ERROR (Status)) {\r
1412 CopyMem (ConfigFormEntry->Password, Password, HDD_PASSWORD_MAX_LENGTH);\r
1413 if (!ConfigFormEntry->IfrData.SecurityStatus.Frozen) {\r
1414 SaveHddPasswordVariable (ConfigFormEntry, Password);\r
1415 }\r
c411b485 1416\r
e8959f81
HW
1417 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
1418 Status = GetHddDeviceIdentifyData (AtaPassThru, Port, PortMultiplierPort, &IdentifyData);\r
1419 ASSERT_EFI_ERROR (Status);\r
1420\r
1421 //\r
1422 // Check the device security status again.\r
1423 //\r
1424 GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);\r
1425 return;\r
1426 }\r
1427\r
1428 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
1429\r
1430 if (EFI_ERROR (Status)) {\r
c411b485 1431 RetryCount++;\r
e8959f81
HW
1432 if (RetryCount < MAX_HDD_PASSWORD_RETRY_COUNT) {\r
1433 do {\r
1434 CreatePopUp (\r
1435 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1436 &Key,\r
1437 L"Invalid password.",\r
1438 L"Press ENTER to retry",\r
1439 NULL\r
1440 );\r
1441 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
c411b485 1442\r
e8959f81
HW
1443 continue;\r
1444 } else {\r
1445 do {\r
1446 CreatePopUp (\r
1447 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1448 &Key,\r
1449 L"Hdd password retry count is expired. Please shutdown the machine.",\r
1450 L"Press ENTER to shutdown",\r
1451 NULL\r
1452 );\r
1453 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
c411b485 1454\r
e8959f81
HW
1455 gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
1456 break;\r
1457 }\r
1458 }\r
1459 } else if (Status == EFI_ABORTED) {\r
1460 if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {\r
1461 //\r
1462 // Current device in the lock status and\r
1463 // User not input password and press ESC,\r
1464 // keep device in lock status and continue boot.\r
1465 //\r
1466 do {\r
1467 CreatePopUp (\r
1468 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1469 &Key,\r
1470 L"Press ENTER to skip the request and continue boot,",\r
1471 L"Press ESC to input password again",\r
1472 NULL\r
1473 );\r
1474 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1475\r
1476 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
c411b485 1477 gST->ConOut->ClearScreen (gST->ConOut);\r
e8959f81
HW
1478 //\r
1479 // Keep lock and continue boot.\r
1480 //\r
1481 return;\r
1482 } else {\r
1483 //\r
1484 // Let user input password again.\r
1485 //\r
1486 continue;\r
1487 }\r
1488 } else {\r
1489 //\r
1490 // Current device in the unlock status and\r
1491 // User not input password and press ESC,\r
1492 // Shutdown the device.\r
1493 //\r
1494 do {\r
1495 CreatePopUp (\r
1496 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1497 &Key,\r
1498 L"Press ENTER to shutdown, Press ESC to input password again",\r
1499 NULL\r
1500 );\r
1501 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1502\r
1503 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
1504 gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
1505 } else {\r
1506 //\r
1507 // Let user input password again.\r
1508 //\r
1509 continue;\r
1510 }\r
1511 }\r
1512 }\r
1513 }\r
1514 }\r
1515}\r
1516\r
1517/**\r
1518 Process Set User Pwd HDD password request.\r
1519\r
1520 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
1521 @param[in] Port The port number of attached ATA device.\r
1522 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
1523 @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
1524\r
1525**/\r
1526VOID\r
1527ProcessHddPasswordRequestSetUserPwd (\r
c411b485
MK
1528 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
1529 IN UINT16 Port,\r
1530 IN UINT16 PortMultiplierPort,\r
1531 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
e8959f81
HW
1532 )\r
1533{\r
c411b485
MK
1534 EFI_STATUS Status;\r
1535 CHAR16 PopUpString[100];\r
1536 ATA_IDENTIFY_DATA IdentifyData;\r
1537 EFI_INPUT_KEY Key;\r
1538 UINT16 RetryCount;\r
1539 CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];\r
1540 CHAR8 PasswordConfirm[HDD_PASSWORD_MAX_LENGTH];\r
e8959f81
HW
1541\r
1542 RetryCount = 0;\r
1543\r
1544 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1545\r
1546 if (ConfigFormEntry->IfrData.SecurityStatus.Frozen) {\r
1547 DEBUG ((DEBUG_INFO, "%s is frozen, do nothing\n", ConfigFormEntry->HddString));\r
1548 return;\r
1549 }\r
1550\r
1551 if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {\r
1552 DEBUG ((DEBUG_INFO, "%s is locked, do nothing\n", ConfigFormEntry->HddString));\r
1553 return;\r
1554 }\r
1555\r
1556 UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Set User Pwd: %s", ConfigFormEntry->HddString);\r
1557\r
1558 //\r
1559 // Check the device security status.\r
1560 //\r
1561 if (ConfigFormEntry->IfrData.SecurityStatus.Supported) {\r
1562 while (TRUE) {\r
1563 Status = PopupHddPasswordInputWindows (PopUpString, L"Please type in your new password", Password);\r
1564 if (!EFI_ERROR (Status)) {\r
1565 Status = PopupHddPasswordInputWindows (PopUpString, L"Please confirm your new password", PasswordConfirm);\r
1566 if (!EFI_ERROR (Status)) {\r
1567 if (CompareMem (Password, PasswordConfirm, HDD_PASSWORD_MAX_LENGTH) == 0) {\r
1568 if (!PasswordIsFullZero (Password)) {\r
1569 Status = SetHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, 1, 0, Password);\r
1570 } else {\r
1571 if (ConfigFormEntry->IfrData.SecurityStatus.Enabled) {\r
1572 Status = DisableHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, ConfigFormEntry->Password);\r
1573 } else {\r
1574 Status = EFI_INVALID_PARAMETER;\r
1575 }\r
1576 }\r
c411b485 1577\r
e8959f81
HW
1578 if (!EFI_ERROR (Status)) {\r
1579 CopyMem (ConfigFormEntry->Password, Password, HDD_PASSWORD_MAX_LENGTH);\r
1580 SaveHddPasswordVariable (ConfigFormEntry, Password);\r
1581 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
1582 ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);\r
1583 Status = GetHddDeviceIdentifyData (AtaPassThru, Port, PortMultiplierPort, &IdentifyData);\r
1584 ASSERT_EFI_ERROR (Status);\r
1585\r
1586 //\r
1587 // Check the device security status again.\r
1588 //\r
1589 GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);\r
1590 return;\r
1591 } else {\r
1592 do {\r
1593 CreatePopUp (\r
1594 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1595 &Key,\r
1596 L"Set/Disable User Pwd failed or invalid password.",\r
1597 L"Press ENTER to retry",\r
1598 NULL\r
1599 );\r
1600 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1601 }\r
1602 } else {\r
1603 do {\r
1604 CreatePopUp (\r
1605 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1606 &Key,\r
1607 L"Passwords are not the same.",\r
1608 L"Press ENTER to retry",\r
1609 NULL\r
1610 );\r
1611 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
c411b485 1612\r
e8959f81
HW
1613 Status = EFI_INVALID_PARAMETER;\r
1614 }\r
1615 }\r
1616\r
1617 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
1618 ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);\r
1619\r
1620 if (EFI_ERROR (Status)) {\r
c411b485 1621 RetryCount++;\r
e8959f81
HW
1622 if (RetryCount >= MAX_HDD_PASSWORD_RETRY_COUNT) {\r
1623 do {\r
1624 CreatePopUp (\r
1625 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1626 &Key,\r
1627 L"Hdd password retry count is expired.",\r
1628 L"Press ENTER to skip the request and continue boot",\r
1629 NULL\r
1630 );\r
1631 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
c411b485
MK
1632\r
1633 gST->ConOut->ClearScreen (gST->ConOut);\r
e8959f81
HW
1634 return;\r
1635 }\r
1636 }\r
1637 } else if (Status == EFI_ABORTED) {\r
1638 do {\r
1639 CreatePopUp (\r
1640 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1641 &Key,\r
1642 L"Press ENTER to skip the request and continue boot,",\r
1643 L"Press ESC to input password again",\r
1644 NULL\r
1645 );\r
1646 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1647\r
1648 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
c411b485 1649 gST->ConOut->ClearScreen (gST->ConOut);\r
e8959f81
HW
1650 return;\r
1651 } else {\r
1652 //\r
1653 // Let user input password again.\r
1654 //\r
1655 continue;\r
1656 }\r
1657 }\r
1658 }\r
1659 }\r
1660}\r
1661\r
1662/**\r
1663 Process Set Master Pwd HDD password request.\r
1664\r
1665 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
1666 @param[in] Port The port number of attached ATA device.\r
1667 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
1668 @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
1669\r
1670**/\r
1671VOID\r
1672ProcessHddPasswordRequestSetMasterPwd (\r
c411b485
MK
1673 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
1674 IN UINT16 Port,\r
1675 IN UINT16 PortMultiplierPort,\r
1676 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
e8959f81
HW
1677 )\r
1678{\r
c411b485
MK
1679 EFI_STATUS Status;\r
1680 CHAR16 PopUpString[100];\r
1681 EFI_INPUT_KEY Key;\r
1682 UINT16 RetryCount;\r
1683 CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];\r
1684 CHAR8 PasswordConfirm[HDD_PASSWORD_MAX_LENGTH];\r
e8959f81
HW
1685\r
1686 RetryCount = 0;\r
1687\r
1688 DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
1689\r
1690 if (ConfigFormEntry->IfrData.SecurityStatus.Frozen) {\r
1691 DEBUG ((DEBUG_INFO, "%s is frozen, do nothing\n", ConfigFormEntry->HddString));\r
1692 return;\r
1693 }\r
1694\r
1695 if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {\r
1696 DEBUG ((DEBUG_INFO, "%s is locked, do nothing\n", ConfigFormEntry->HddString));\r
1697 return;\r
1698 }\r
1699\r
1700 UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Set Master Pwd: %s", ConfigFormEntry->HddString);\r
1701\r
1702 //\r
1703 // Check the device security status.\r
1704 //\r
1705 if (ConfigFormEntry->IfrData.SecurityStatus.Supported) {\r
1706 while (TRUE) {\r
1707 Status = PopupHddPasswordInputWindows (PopUpString, L"Please type in your new password", Password);\r
1708 if (!EFI_ERROR (Status)) {\r
1709 Status = PopupHddPasswordInputWindows (PopUpString, L"Please confirm your new password", PasswordConfirm);\r
1710 if (!EFI_ERROR (Status)) {\r
1711 if (CompareMem (Password, PasswordConfirm, HDD_PASSWORD_MAX_LENGTH) == 0) {\r
1712 if (!PasswordIsFullZero (Password)) {\r
1713 Status = SetHddPassword (AtaPassThru, Port, PortMultiplierPort, 1, 1, 1, Password);\r
1714 } else {\r
1715 Status = EFI_INVALID_PARAMETER;\r
1716 }\r
c411b485 1717\r
e8959f81
HW
1718 if (!EFI_ERROR (Status)) {\r
1719 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
1720 ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);\r
1721 return;\r
1722 } else {\r
1723 do {\r
1724 CreatePopUp (\r
1725 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1726 &Key,\r
1727 L"Set Master Pwd failed or invalid password.",\r
1728 L"Press ENTER to retry",\r
1729 NULL\r
1730 );\r
1731 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1732 }\r
1733 } else {\r
1734 do {\r
1735 CreatePopUp (\r
1736 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1737 &Key,\r
1738 L"Passwords are not the same.",\r
1739 L"Press ENTER to retry",\r
1740 NULL\r
1741 );\r
1742 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
c411b485 1743\r
e8959f81
HW
1744 Status = EFI_INVALID_PARAMETER;\r
1745 }\r
1746 }\r
1747\r
1748 ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
1749 ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);\r
1750\r
1751 if (EFI_ERROR (Status)) {\r
c411b485 1752 RetryCount++;\r
e8959f81
HW
1753 if (RetryCount >= MAX_HDD_PASSWORD_RETRY_COUNT) {\r
1754 do {\r
1755 CreatePopUp (\r
1756 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1757 &Key,\r
1758 L"Hdd password retry count is expired.",\r
1759 L"Press ENTER to skip the request and continue boot",\r
1760 NULL\r
1761 );\r
1762 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
c411b485
MK
1763\r
1764 gST->ConOut->ClearScreen (gST->ConOut);\r
e8959f81
HW
1765 return;\r
1766 }\r
1767 }\r
1768 } else if (Status == EFI_ABORTED) {\r
1769 do {\r
1770 CreatePopUp (\r
1771 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
1772 &Key,\r
1773 L"Press ENTER to skip the request and continue boot,",\r
1774 L"Press ESC to input password again",\r
1775 NULL\r
1776 );\r
1777 } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
1778\r
1779 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
c411b485 1780 gST->ConOut->ClearScreen (gST->ConOut);\r
e8959f81
HW
1781 return;\r
1782 } else {\r
1783 //\r
1784 // Let user input password again.\r
1785 //\r
1786 continue;\r
1787 }\r
1788 }\r
1789 }\r
1790 }\r
1791}\r
1792\r
1793/**\r
1794 Process HDD password request.\r
1795\r
1796 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
1797 @param[in] Port The port number of attached ATA device.\r
1798 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
1799 @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
1800\r
1801**/\r
1802VOID\r
1803ProcessHddPasswordRequest (\r
c411b485
MK
1804 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
1805 IN UINT16 Port,\r
1806 IN UINT16 PortMultiplierPort,\r
1807 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
e8959f81
HW
1808 )\r
1809{\r
c411b485
MK
1810 EFI_STATUS Status;\r
1811 HDD_PASSWORD_REQUEST_VARIABLE *TempVariable;\r
1812 HDD_PASSWORD_REQUEST_VARIABLE *Variable;\r
1813 UINTN VariableSize;\r
e8959f81
HW
1814\r
1815 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
1816\r
1817 if (mHddPasswordRequestVariable == NULL) {\r
1818 Status = GetVariable2 (\r
1819 HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
1820 &mHddPasswordVendorGuid,\r
c411b485 1821 (VOID **)&Variable,\r
e8959f81
HW
1822 &VariableSize\r
1823 );\r
1824 if (EFI_ERROR (Status) || (Variable == NULL)) {\r
1825 return;\r
1826 }\r
c411b485
MK
1827\r
1828 mHddPasswordRequestVariable = Variable;\r
e8959f81
HW
1829 mHddPasswordRequestVariableSize = VariableSize;\r
1830\r
1831 //\r
1832 // Delete the HDD password request variable.\r
1833 //\r
1834 Status = gRT->SetVariable (\r
1835 HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
1836 &mHddPasswordVendorGuid,\r
1837 0,\r
1838 0,\r
1839 NULL\r
1840 );\r
1841 ASSERT_EFI_ERROR (Status);\r
1842 } else {\r
c411b485 1843 Variable = mHddPasswordRequestVariable;\r
e8959f81
HW
1844 VariableSize = mHddPasswordRequestVariableSize;\r
1845 }\r
1846\r
1847 //\r
1848 // Process the HDD password requests.\r
1849 //\r
1850 TempVariable = Variable;\r
1851 while (VariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {\r
1852 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
1853 (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
1854 (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
1855 (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
c411b485
MK
1856 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))\r
1857 {\r
e8959f81
HW
1858 //\r
1859 // Found the node for the HDD password device.\r
1860 //\r
1861 if (TempVariable->Request.UserPassword != 0) {\r
1862 ProcessHddPasswordRequestSetUserPwd (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);\r
1863 }\r
c411b485 1864\r
e8959f81
HW
1865 if (TempVariable->Request.MasterPassword != 0) {\r
1866 ProcessHddPasswordRequestSetMasterPwd (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);\r
1867 }\r
1868\r
1869 break;\r
1870 }\r
1871\r
1872 VariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
1873 TempVariable += 1;\r
1874 }\r
1875\r
1876 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
1877}\r
1878\r
1879/**\r
1880 Get saved HDD password request.\r
1881\r
1882 @param[in, out] ConfigFormEntry The HDD Password configuration form entry.\r
1883\r
1884**/\r
1885VOID\r
1886GetSavedHddPasswordRequest (\r
c411b485 1887 IN OUT HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
e8959f81
HW
1888 )\r
1889{\r
c411b485
MK
1890 EFI_STATUS Status;\r
1891 HDD_PASSWORD_REQUEST_VARIABLE *TempVariable;\r
1892 HDD_PASSWORD_REQUEST_VARIABLE *Variable;\r
1893 UINTN VariableSize;\r
e8959f81
HW
1894\r
1895 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
1896\r
c411b485 1897 Variable = NULL;\r
e8959f81
HW
1898 VariableSize = 0;\r
1899\r
1900 Status = GetVariable2 (\r
1901 HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
1902 &mHddPasswordVendorGuid,\r
c411b485 1903 (VOID **)&Variable,\r
e8959f81
HW
1904 &VariableSize\r
1905 );\r
1906 if (EFI_ERROR (Status) || (Variable == NULL)) {\r
1907 return;\r
1908 }\r
1909\r
1910 TempVariable = Variable;\r
1911 while (VariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {\r
1912 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
1913 (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
1914 (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
1915 (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
c411b485
MK
1916 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))\r
1917 {\r
e8959f81
HW
1918 //\r
1919 // Found the node for the HDD password device.\r
1920 // Get the HDD password request.\r
1921 //\r
1922 CopyMem (&ConfigFormEntry->IfrData.Request, &TempVariable->Request, sizeof (HDD_PASSWORD_REQUEST));\r
1923 DEBUG ((\r
1924 DEBUG_INFO,\r
1925 "HddPasswordRequest got: 0x%x\n",\r
1926 ConfigFormEntry->IfrData.Request\r
1927 ));\r
1928 break;\r
1929 }\r
c411b485 1930\r
e8959f81
HW
1931 VariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
1932 TempVariable += 1;\r
1933 }\r
1934\r
1935 FreePool (Variable);\r
1936\r
1937 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
1938}\r
1939\r
1940/**\r
1941 Save HDD password request.\r
1942\r
1943 @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
1944\r
1945**/\r
1946VOID\r
1947SaveHddPasswordRequest (\r
c411b485 1948 IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
e8959f81
HW
1949 )\r
1950{\r
c411b485
MK
1951 EFI_STATUS Status;\r
1952 HDD_PASSWORD_REQUEST_VARIABLE *TempVariable;\r
1953 UINTN TempVariableSize;\r
1954 HDD_PASSWORD_REQUEST_VARIABLE *Variable;\r
1955 UINTN VariableSize;\r
1956 HDD_PASSWORD_REQUEST_VARIABLE *NewVariable;\r
1957 UINTN NewVariableSize;\r
e8959f81
HW
1958\r
1959 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
1960\r
1961 DEBUG ((\r
1962 DEBUG_INFO,\r
1963 "HddPasswordRequest to save: 0x%x\n",\r
1964 ConfigFormEntry->IfrData.Request\r
1965 ));\r
1966\r
c411b485
MK
1967 Variable = NULL;\r
1968 VariableSize = 0;\r
1969 NewVariable = NULL;\r
e8959f81
HW
1970 NewVariableSize = 0;\r
1971\r
1972 Status = GetVariable2 (\r
1973 HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
1974 &mHddPasswordVendorGuid,\r
c411b485 1975 (VOID **)&Variable,\r
e8959f81
HW
1976 &VariableSize\r
1977 );\r
1978 if (!EFI_ERROR (Status) && (Variable != NULL)) {\r
c411b485 1979 TempVariable = Variable;\r
e8959f81
HW
1980 TempVariableSize = VariableSize;\r
1981 while (TempVariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {\r
1982 if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
1983 (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
1984 (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
1985 (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
c411b485
MK
1986 (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort))\r
1987 {\r
e8959f81
HW
1988 //\r
1989 // Found the node for the HDD password device.\r
1990 // Update the HDD password request.\r
1991 //\r
1992 CopyMem (&TempVariable->Request, &ConfigFormEntry->IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));\r
c411b485 1993 NewVariable = Variable;\r
e8959f81
HW
1994 NewVariableSize = VariableSize;\r
1995 break;\r
1996 }\r
c411b485 1997\r
e8959f81 1998 TempVariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
c411b485 1999 TempVariable += 1;\r
e8959f81 2000 }\r
c411b485 2001\r
e8959f81
HW
2002 if (NewVariable == NULL) {\r
2003 //\r
2004 // The node for the HDD password device is not found.\r
2005 // Create node for the HDD password device.\r
2006 //\r
2007 NewVariableSize = VariableSize + sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
c411b485 2008 NewVariable = AllocateZeroPool (NewVariableSize);\r
e8959f81
HW
2009 ASSERT (NewVariable != NULL);\r
2010 CopyMem (NewVariable, Variable, VariableSize);\r
c411b485
MK
2011 TempVariable = (HDD_PASSWORD_REQUEST_VARIABLE *)((UINTN)NewVariable + VariableSize);\r
2012 TempVariable->Device.Bus = (UINT8)ConfigFormEntry->Bus;\r
2013 TempVariable->Device.Device = (UINT8)ConfigFormEntry->Device;\r
2014 TempVariable->Device.Function = (UINT8)ConfigFormEntry->Function;\r
e8959f81
HW
2015 TempVariable->Device.Port = ConfigFormEntry->Port;\r
2016 TempVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
2017 CopyMem (&TempVariable->Request, &ConfigFormEntry->IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));\r
2018 }\r
2019 } else {\r
2020 NewVariableSize = sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
c411b485 2021 NewVariable = AllocateZeroPool (NewVariableSize);\r
e8959f81 2022 ASSERT (NewVariable != NULL);\r
c411b485
MK
2023 NewVariable->Device.Bus = (UINT8)ConfigFormEntry->Bus;\r
2024 NewVariable->Device.Device = (UINT8)ConfigFormEntry->Device;\r
2025 NewVariable->Device.Function = (UINT8)ConfigFormEntry->Function;\r
e8959f81
HW
2026 NewVariable->Device.Port = ConfigFormEntry->Port;\r
2027 NewVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
2028 CopyMem (&NewVariable->Request, &ConfigFormEntry->IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));\r
2029 }\r
c411b485 2030\r
e8959f81
HW
2031 Status = gRT->SetVariable (\r
2032 HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
2033 &mHddPasswordVendorGuid,\r
2034 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
2035 NewVariableSize,\r
2036 NewVariable\r
2037 );\r
2038 if (EFI_ERROR (Status)) {\r
2039 DEBUG ((DEBUG_INFO, "HddPasswordRequest variable set failed (%r)\n", Status));\r
2040 }\r
c411b485 2041\r
e8959f81
HW
2042 if (NewVariable != Variable) {\r
2043 FreePool (NewVariable);\r
2044 }\r
c411b485 2045\r
e8959f81
HW
2046 if (Variable != NULL) {\r
2047 FreePool (Variable);\r
2048 }\r
2049\r
2050 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
2051}\r
2052\r
2053/**\r
d6b926e7 2054 Get the HDD Password configuration form entry by the index of the goto opcode activated.\r
e8959f81 2055\r
d6b926e7 2056 @param[in] Index The 0-based index of the goto opcode activated.\r
e8959f81
HW
2057\r
2058 @return The HDD Password configuration form entry found.\r
2059**/\r
2060HDD_PASSWORD_CONFIG_FORM_ENTRY *\r
2061HddPasswordGetConfigFormEntryByIndex (\r
c411b485 2062 IN UINT32 Index\r
e8959f81
HW
2063 )\r
2064{\r
c411b485
MK
2065 LIST_ENTRY *Entry;\r
2066 UINT32 CurrentIndex;\r
2067 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
e8959f81
HW
2068\r
2069 CurrentIndex = 0;\r
2070 ConfigFormEntry = NULL;\r
2071\r
3571e136 2072 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
e8959f81
HW
2073 if (CurrentIndex == Index) {\r
2074 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
2075 break;\r
2076 }\r
2077\r
2078 CurrentIndex++;\r
2079 }\r
2080\r
2081 return ConfigFormEntry;\r
2082}\r
2083\r
2084/**\r
2085 This function allows the caller to request the current\r
2086 configuration for one or more named elements. The resulting\r
2087 string is in <ConfigAltResp> format. Any and all alternative\r
2088 configuration strings shall also be appended to the end of the\r
2089 current configuration string. If they are, they must appear\r
2090 after the current configuration. They must contain the same\r
2091 routing (GUID, NAME, PATH) as the current configuration string.\r
2092 They must have an additional description indicating the type of\r
2093 alternative configuration the string represents,\r
2094 "ALTCFG=<StringToken>". That <StringToken> (when\r
2095 converted from Hex UNICODE to binary) is a reference to a\r
2096 string in the associated string pack.\r
2097\r
2098 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
2099 @param[in] Request A null-terminated Unicode string in\r
2100 <ConfigRequest> format. Note that this\r
2101 includes the routing information as well as\r
2102 the configurable name / value pairs. It is\r
2103 invalid for this string to be in\r
2104 <MultiConfigRequest> format.\r
2105 @param[out] Progress On return, points to a character in the\r
2106 Request string. Points to the string's null\r
2107 terminator if request was successful. Points\r
2108 to the most recent "&" before the first\r
2109 failing name / value pair (or the beginning\r
2110 of the string if the failure is in the first\r
2111 name / value pair) if the request was not\r
2112 successful.\r
2113 @param[out] Results A null-terminated Unicode string in\r
2114 <ConfigAltResp> format which has all values\r
2115 filled in for the names in the Request string.\r
2116 String to be allocated by the called function.\r
2117\r
2118 @retval EFI_SUCCESS The Results string is filled with the\r
2119 values corresponding to all requested\r
2120 names.\r
2121 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
2122 parts of the results that must be\r
2123 stored awaiting possible future\r
2124 protocols.\r
2125 @retval EFI_INVALID_PARAMETER For example, passing in a NULL\r
2126 for the Request parameter\r
2127 would result in this type of\r
2128 error. In this case, the\r
2129 Progress parameter would be\r
2130 set to NULL.\r
2131 @retval EFI_NOT_FOUND Routing data doesn't match any\r
2132 known driver. Progress set to the\r
2133 first character in the routing header.\r
2134 Note: There is no requirement that the\r
2135 driver validate the routing data. It\r
2136 must skip the <ConfigHdr> in order to\r
2137 process the names.\r
2138 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set\r
2139 to most recent & before the\r
2140 error or the beginning of the\r
2141 string.\r
2142 @retval EFI_INVALID_PARAMETER Unknown name. Progress points\r
2143 to the & before the name in\r
2144 question.Currently not implemented.\r
2145**/\r
2146EFI_STATUS\r
2147EFIAPI\r
2148HddPasswordFormExtractConfig (\r
c411b485
MK
2149 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
2150 IN CONST EFI_STRING Request,\r
2151 OUT EFI_STRING *Progress,\r
2152 OUT EFI_STRING *Results\r
e8959f81
HW
2153 )\r
2154{\r
c411b485
MK
2155 EFI_STATUS Status;\r
2156 UINTN BufferSize;\r
2157 HDD_PASSWORD_CONFIG *IfrData;\r
2158 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
2159 EFI_STRING ConfigRequestHdr;\r
2160 EFI_STRING ConfigRequest;\r
2161 BOOLEAN AllocatedRequest;\r
2162 UINTN Size;\r
2163\r
2164 if ((Progress == NULL) || (Results == NULL)) {\r
e8959f81
HW
2165 return EFI_INVALID_PARAMETER;\r
2166 }\r
2167\r
2168 *Progress = Request;\r
2169 if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) {\r
2170 return EFI_NOT_FOUND;\r
2171 }\r
2172\r
2173 ConfigRequestHdr = NULL;\r
2174 ConfigRequest = NULL;\r
2175 AllocatedRequest = FALSE;\r
2176 Size = 0;\r
2177\r
2178 Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);\r
2179 IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));\r
2180 ASSERT (IfrData != NULL);\r
2181 if (Private->Current != NULL) {\r
2182 CopyMem (IfrData, &Private->Current->IfrData, sizeof (HDD_PASSWORD_CONFIG));\r
2183 }\r
2184\r
2185 //\r
2186 // Convert buffer data to <ConfigResp> by helper function BlockToConfig()\r
2187 //\r
c411b485 2188 BufferSize = sizeof (HDD_PASSWORD_CONFIG);\r
e8959f81
HW
2189 ConfigRequest = Request;\r
2190 if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
2191 //\r
2192 // Request has no request element, construct full request string.\r
2193 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
2194 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
2195 //\r
2196 ConfigRequestHdr = HiiConstructConfigHdr (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, Private->DriverHandle);\r
c411b485
MK
2197 Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
2198 ConfigRequest = AllocateZeroPool (Size);\r
e8959f81
HW
2199 ASSERT (ConfigRequest != NULL);\r
2200 AllocatedRequest = TRUE;\r
2201 UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
2202 FreePool (ConfigRequestHdr);\r
2203 }\r
c411b485 2204\r
e8959f81
HW
2205 Status = gHiiConfigRouting->BlockToConfig (\r
2206 gHiiConfigRouting,\r
2207 ConfigRequest,\r
c411b485 2208 (UINT8 *)IfrData,\r
e8959f81
HW
2209 BufferSize,\r
2210 Results,\r
2211 Progress\r
2212 );\r
2213 FreePool (IfrData);\r
2214 //\r
2215 // Free the allocated config request string.\r
2216 //\r
2217 if (AllocatedRequest) {\r
2218 FreePool (ConfigRequest);\r
2219 ConfigRequest = NULL;\r
2220 }\r
2221\r
2222 //\r
2223 // Set Progress string to the original request string.\r
2224 //\r
2225 if (Request == NULL) {\r
2226 *Progress = NULL;\r
2227 } else if (StrStr (Request, L"OFFSET") == NULL) {\r
2228 *Progress = Request + StrLen (Request);\r
2229 }\r
2230\r
2231 return Status;\r
2232}\r
2233\r
2234/**\r
2235 This function applies changes in a driver's configuration.\r
2236 Input is a Configuration, which has the routing data for this\r
2237 driver followed by name / value configuration pairs. The driver\r
2238 must apply those pairs to its configurable storage. If the\r
2239 driver's configuration is stored in a linear block of data\r
2240 and the driver's name / value pairs are in <BlockConfig>\r
2241 format, it may use the ConfigToBlock helper function (above) to\r
2242 simplify the job. Currently not implemented.\r
2243\r
2244 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
2245 @param[in] Configuration A null-terminated Unicode string in\r
2246 <ConfigString> format.\r
2247 @param[out] Progress A pointer to a string filled in with the\r
2248 offset of the most recent '&' before the\r
2249 first failing name / value pair (or the\r
2250 beginn ing of the string if the failure\r
2251 is in the first name / value pair) or\r
2252 the terminating NULL if all was\r
2253 successful.\r
2254\r
2255 @retval EFI_SUCCESS The results have been distributed or are\r
2256 awaiting distribution.\r
2257 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
2258 parts of the results that must be\r
2259 stored awaiting possible future\r
2260 protocols.\r
2261 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the\r
2262 Results parameter would result\r
2263 in this type of error.\r
2264 @retval EFI_NOT_FOUND Target for the specified routing data\r
2265 was not found.\r
2266**/\r
2267EFI_STATUS\r
2268EFIAPI\r
2269HddPasswordFormRouteConfig (\r
c411b485
MK
2270 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
2271 IN CONST EFI_STRING Configuration,\r
2272 OUT EFI_STRING *Progress\r
e8959f81
HW
2273 )\r
2274{\r
c411b485 2275 if ((Configuration == NULL) || (Progress == NULL)) {\r
e8959f81
HW
2276 return EFI_INVALID_PARAMETER;\r
2277 }\r
2278\r
2279 //\r
2280 // Check routing data in <ConfigHdr>.\r
2281 // Note: if only one Storage is used, then this checking could be skipped.\r
2282 //\r
2283 if (!HiiIsConfigHdrMatch (Configuration, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) {\r
2284 *Progress = Configuration;\r
2285 return EFI_NOT_FOUND;\r
2286 }\r
2287\r
2288 *Progress = Configuration + StrLen (Configuration);\r
2289 return EFI_SUCCESS;\r
2290}\r
2291\r
2292/**\r
2293 This function is called to provide results data to the driver.\r
2294 This data consists of a unique key that is used to identify\r
2295 which data is either being passed back or being asked for.\r
2296\r
2297 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
2298 @param[in] Action Specifies the type of action taken by the browser.\r
2299 @param[in] QuestionId A unique value which is sent to the original\r
2300 exporting driver so that it can identify the type\r
2301 of data to expect. The format of the data tends to\r
2302 vary based on the opcode that enerated the callback.\r
2303 @param[in] Type The type of value for the question.\r
2304 @param[in] Value A pointer to the data being sent to the original\r
2305 exporting driver.\r
2306 @param[out] ActionRequest On return, points to the action requested by the\r
2307 callback function.\r
2308\r
2309 @retval EFI_SUCCESS The callback successfully handled the action.\r
2310 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the\r
2311 variable and its data.\r
2312 @retval EFI_DEVICE_ERROR The variable could not be saved.\r
2313 @retval EFI_UNSUPPORTED The specified Action is not supported by the\r
2314 callback.Currently not implemented.\r
2315 @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.\r
2316 @retval Others Other errors as indicated.\r
2317**/\r
2318EFI_STATUS\r
2319EFIAPI\r
2320HddPasswordFormCallback (\r
c411b485
MK
2321 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
2322 IN EFI_BROWSER_ACTION Action,\r
2323 IN EFI_QUESTION_ID QuestionId,\r
2324 IN UINT8 Type,\r
2325 IN EFI_IFR_TYPE_VALUE *Value,\r
2326 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
e8959f81
HW
2327 )\r
2328{\r
2329 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
c411b485
MK
2330 EFI_STRING_ID DeviceFormTitleToken;\r
2331 HDD_PASSWORD_CONFIG *IfrData;\r
2332 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
e8959f81
HW
2333\r
2334 if (ActionRequest != NULL) {\r
2335 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
2336 } else {\r
2337 return EFI_INVALID_PARAMETER;\r
2338 }\r
2339\r
2340 if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {\r
2341 //\r
2342 // Do nothing for other UEFI Action. Only do call back when data is changing or changed.\r
2343 //\r
2344 return EFI_UNSUPPORTED;\r
2345 }\r
2346\r
2347 Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);\r
2348\r
2349 //\r
2350 // Retrive data from Browser\r
2351 //\r
2352 IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));\r
2353 ASSERT (IfrData != NULL);\r
c411b485 2354 if (!HiiGetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *)IfrData)) {\r
e8959f81
HW
2355 FreePool (IfrData);\r
2356 return EFI_NOT_FOUND;\r
2357 }\r
2358\r
2359 switch (QuestionId) {\r
c411b485
MK
2360 case KEY_HDD_USER_PASSWORD:\r
2361 if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
2362 DEBUG ((DEBUG_INFO, "KEY_HDD_USER_PASSWORD\n"));\r
2363 ConfigFormEntry = Private->Current;\r
2364 ConfigFormEntry->IfrData.Request.UserPassword = Value->b;\r
2365 SaveHddPasswordRequest (ConfigFormEntry);\r
2366 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
2367 }\r
e8959f81 2368\r
c411b485
MK
2369 break;\r
2370 case KEY_HDD_MASTER_PASSWORD:\r
2371 if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
2372 DEBUG ((DEBUG_INFO, "KEY_HDD_MASTER_PASSWORD\n"));\r
2373 ConfigFormEntry = Private->Current;\r
2374 ConfigFormEntry->IfrData.Request.MasterPassword = Value->b;\r
2375 SaveHddPasswordRequest (ConfigFormEntry);\r
2376 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
2377 }\r
e8959f81 2378\r
c411b485
MK
2379 break;\r
2380\r
2381 default:\r
2382 if ((QuestionId >= KEY_HDD_DEVICE_ENTRY_BASE) && (QuestionId < (mNumberOfHddDevices + KEY_HDD_DEVICE_ENTRY_BASE))) {\r
2383 if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
2384 //\r
2385 // In case goto the device configuration form, update the device form title.\r
2386 //\r
2387 ConfigFormEntry = HddPasswordGetConfigFormEntryByIndex ((UINT32)(QuestionId - KEY_HDD_DEVICE_ENTRY_BASE));\r
2388 ASSERT (ConfigFormEntry != NULL);\r
e8959f81 2389\r
c411b485
MK
2390 DeviceFormTitleToken = (EFI_STRING_ID)STR_HDD_SECURITY_HD;\r
2391 HiiSetString (Private->HiiHandle, DeviceFormTitleToken, ConfigFormEntry->HddString, NULL);\r
2392\r
2393 Private->Current = ConfigFormEntry;\r
2394 CopyMem (IfrData, &ConfigFormEntry->IfrData, sizeof (HDD_PASSWORD_CONFIG));\r
2395 }\r
e8959f81 2396 }\r
e8959f81 2397\r
c411b485 2398 break;\r
e8959f81
HW
2399 }\r
2400\r
2401 //\r
2402 // Pass changed uncommitted data back to Form Browser\r
2403 //\r
c411b485 2404 HiiSetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *)IfrData, NULL);\r
e8959f81
HW
2405\r
2406 FreePool (IfrData);\r
2407 return EFI_SUCCESS;\r
2408}\r
2409\r
2410/**\r
2411 Updates the HDD Password configuration form to add an entry for the attached\r
2412 ata harddisk device specified by the Controller.\r
2413\r
2414 @param[in] HiiHandle The HII Handle associated with the registered package list.\r
2415 @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
2416 @param[in] PciIo Pointer to PCI_IO instance.\r
2417 @param[in] Controller The controller handle of the attached ata controller.\r
2418 @param[in] Bus The bus number of ATA controller.\r
2419 @param[in] Device The device number of ATA controller.\r
2420 @param[in] Function The function number of ATA controller.\r
2421 @param[in] Port The port number of attached ATA device.\r
2422 @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
2423\r
2424 @retval EFI_SUCCESS The Hdd Password configuration form is updated.\r
2425 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
2426 @retval Others Other errors as indicated.\r
2427\r
2428**/\r
2429EFI_STATUS\r
2430HddPasswordConfigUpdateForm (\r
2431 IN EFI_HII_HANDLE HiiHandle,\r
2432 IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
2433 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2434 IN EFI_HANDLE Controller,\r
2435 IN UINTN Bus,\r
2436 IN UINTN Device,\r
2437 IN UINTN Function,\r
2438 IN UINT16 Port,\r
2439 IN UINT16 PortMultiplierPort\r
2440 )\r
2441{\r
c411b485
MK
2442 LIST_ENTRY *Entry;\r
2443 HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
2444 BOOLEAN EntryExisted;\r
2445 EFI_STATUS Status;\r
2446 VOID *StartOpCodeHandle;\r
2447 VOID *EndOpCodeHandle;\r
2448 EFI_IFR_GUID_LABEL *StartLabel;\r
2449 EFI_IFR_GUID_LABEL *EndLabel;\r
2450 CHAR16 HddString[40];\r
2451 ATA_IDENTIFY_DATA IdentifyData;\r
2452 EFI_DEVICE_PATH_PROTOCOL *AtaDeviceNode;\r
e8959f81
HW
2453\r
2454 ConfigFormEntry = NULL;\r
2455 EntryExisted = FALSE;\r
2456\r
3571e136 2457 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
e8959f81
HW
2458 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
2459\r
2460 if ((ConfigFormEntry->Bus == Bus) &&\r
2461 (ConfigFormEntry->Device == Device) &&\r
2462 (ConfigFormEntry->Function == Function) &&\r
2463 (ConfigFormEntry->Port == Port) &&\r
c411b485
MK
2464 (ConfigFormEntry->PortMultiplierPort == PortMultiplierPort))\r
2465 {\r
e8959f81
HW
2466 EntryExisted = TRUE;\r
2467 break;\r
2468 }\r
2469 }\r
2470\r
2471 if (!EntryExisted) {\r
2472 //\r
2473 // Add a new form.\r
2474 //\r
2475 ConfigFormEntry = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG_FORM_ENTRY));\r
2476 if (ConfigFormEntry == NULL) {\r
2477 return EFI_OUT_OF_RESOURCES;\r
2478 }\r
2479\r
2480 InitializeListHead (&ConfigFormEntry->Link);\r
2481 ConfigFormEntry->Controller = Controller;\r
2482 ConfigFormEntry->Bus = Bus;\r
2483 ConfigFormEntry->Device = Device;\r
2484 ConfigFormEntry->Function = Function;\r
2485 ConfigFormEntry->Port = Port;\r
2486 ConfigFormEntry->PortMultiplierPort = PortMultiplierPort;\r
2487 ConfigFormEntry->AtaPassThru = AtaPassThru;\r
2488\r
2489 DEBUG ((DEBUG_INFO, "HddPasswordDxe: Create new form for device[%d][%d] at Bus 0x%x Dev 0x%x Func 0x%x\n", Port, PortMultiplierPort, Bus, Device, Function));\r
2490\r
2491 //\r
2492 // Construct the device path for the HDD password device\r
2493 //\r
2494 Status = AtaPassThru->BuildDevicePath (\r
2495 AtaPassThru,\r
2496 Port,\r
2497 PortMultiplierPort,\r
2498 &AtaDeviceNode\r
2499 );\r
2500 if (EFI_ERROR (Status)) {\r
2501 return Status;\r
2502 }\r
c411b485 2503\r
e8959f81
HW
2504 ConfigFormEntry->DevicePath = AppendDevicePathNode (DevicePathFromHandle (Controller), AtaDeviceNode);\r
2505 FreePool (AtaDeviceNode);\r
2506 if (ConfigFormEntry->DevicePath == NULL) {\r
2507 return EFI_OUT_OF_RESOURCES;\r
2508 }\r
2509\r
2510 //\r
2511 // Get attached harddisk model number\r
2512 //\r
2513 Status = GetHddDeviceIdentifyData (AtaPassThru, Port, PortMultiplierPort, &IdentifyData);\r
2514 ASSERT_EFI_ERROR (Status);\r
2515 if (EFI_ERROR (Status)) {\r
2516 return Status;\r
2517 }\r
c411b485 2518\r
e8959f81
HW
2519 GetHddDeviceModelNumber (&IdentifyData, HddString);\r
2520 //\r
2521 // Compose the HDD title string and help string of this port and create a new EFI_STRING_ID.\r
2522 //\r
2523 UnicodeSPrint (ConfigFormEntry->HddString, sizeof (ConfigFormEntry->HddString), L"HDD %d:%s", mNumberOfHddDevices, HddString);\r
2524 ConfigFormEntry->TitleToken = HiiSetString (HiiHandle, 0, ConfigFormEntry->HddString, NULL);\r
2525 ConfigFormEntry->TitleHelpToken = HiiSetString (HiiHandle, 0, L"Request to set HDD Password", NULL);\r
2526\r
2527 GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);\r
2528\r
2529 InsertTailList (&mHddPasswordConfigFormList, &ConfigFormEntry->Link);\r
2530\r
2531 //\r
2532 // Init OpCode Handle\r
2533 //\r
2534 StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2535 ASSERT (StartOpCodeHandle != NULL);\r
2536\r
2537 EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2538 ASSERT (EndOpCodeHandle != NULL);\r
2539\r
2540 //\r
2541 // Create Hii Extend Label OpCode as the start opcode\r
2542 //\r
c411b485 2543 StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
e8959f81
HW
2544 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
2545 StartLabel->Number = HDD_DEVICE_ENTRY_LABEL;\r
2546\r
2547 //\r
2548 // Create Hii Extend Label OpCode as the end opcode\r
2549 //\r
c411b485 2550 EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
e8959f81
HW
2551 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
2552 EndLabel->Number = HDD_DEVICE_LABEL_END;\r
2553\r
2554 mNumberOfHddDevices = 0;\r
3571e136 2555 BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
e8959f81
HW
2556 ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
2557\r
2558 HiiCreateGotoOpCode (\r
c411b485
MK
2559 StartOpCodeHandle, // Container for dynamic created opcodes\r
2560 FORMID_HDD_DEVICE_FORM, // Target Form ID\r
2561 ConfigFormEntry->TitleToken, // Prompt text\r
2562 ConfigFormEntry->TitleHelpToken, // Help text\r
2563 EFI_IFR_FLAG_CALLBACK, // Question flag\r
2564 (UINT16)(KEY_HDD_DEVICE_ENTRY_BASE + mNumberOfHddDevices) // Question ID\r
e8959f81
HW
2565 );\r
2566\r
2567 mNumberOfHddDevices++;\r
2568 }\r
2569\r
2570 HiiUpdateForm (\r
2571 HiiHandle,\r
2572 &mHddPasswordVendorGuid,\r
2573 FORMID_HDD_MAIN_FORM,\r
2574 StartOpCodeHandle,\r
2575 EndOpCodeHandle\r
2576 );\r
2577\r
2578 HiiFreeOpCodeHandle (StartOpCodeHandle);\r
2579 HiiFreeOpCodeHandle (EndOpCodeHandle);\r
2580\r
2581 //\r
2582 // Check if device is locked and prompt for password.\r
2583 //\r
2584 HddPasswordRequestPassword (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);\r
2585\r
2586 //\r
2587 // Process HDD password request from last boot.\r
2588 //\r
2589 ProcessHddPasswordRequest (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);\r
2590 }\r
2591\r
2592 return EFI_SUCCESS;\r
2593}\r
2594\r
2595/**\r
2596 Ata Pass Thru Protocol notification event handler.\r
2597\r
2598 Check attached harddisk status to see if it's locked. If yes, then pop up a password windows to require user input.\r
2599 It also registers a form for user configuration on Hdd password configuration.\r
2600\r
2601 @param[in] Event Event whose notification function is being invoked.\r
2602 @param[in] Context Pointer to the notification function's context.\r
2603\r
2604**/\r
2605VOID\r
2606EFIAPI\r
2607HddPasswordNotificationEvent (\r
c411b485
MK
2608 IN EFI_EVENT Event,\r
2609 IN VOID *Context\r
e8959f81
HW
2610 )\r
2611{\r
c411b485
MK
2612 EFI_STATUS Status;\r
2613 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
2614 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
2615 UINT16 Port;\r
2616 UINT16 PortMultiplierPort;\r
2617 EFI_HANDLE Controller;\r
2618 EFI_HANDLE *HandleBuffer;\r
2619 UINTN HandleCount;\r
2620 UINTN Index;\r
2621 EFI_PCI_IO_PROTOCOL *PciIo;\r
2622 UINTN SegNum;\r
2623 UINTN BusNum;\r
2624 UINTN DevNum;\r
2625 UINTN FuncNum;\r
e8959f81
HW
2626\r
2627 if (mHddPasswordEndOfDxe) {\r
2628 gBS->CloseEvent (Event);\r
2629 return;\r
2630 }\r
2631\r
2632 Private = (HDD_PASSWORD_DXE_PRIVATE_DATA *)Context;\r
2633\r
2634 //\r
2635 // Locate all handles of AtaPassThru protocol\r
2636 //\r
2637 Status = gBS->LocateHandleBuffer (\r
2638 ByProtocol,\r
2639 &gEfiAtaPassThruProtocolGuid,\r
2640 NULL,\r
2641 &HandleCount,\r
2642 &HandleBuffer\r
2643 );\r
2644 if (EFI_ERROR (Status)) {\r
c411b485 2645 return;\r
e8959f81
HW
2646 }\r
2647\r
2648 //\r
2649 // Check attached hard disk status to see if it's locked\r
2650 //\r
2651 for (Index = 0; Index < HandleCount; Index += 1) {\r
2652 Controller = HandleBuffer[Index];\r
c411b485
MK
2653 Status = gBS->HandleProtocol (\r
2654 Controller,\r
2655 &gEfiAtaPassThruProtocolGuid,\r
2656 (VOID **)&AtaPassThru\r
2657 );\r
e8959f81
HW
2658 if (EFI_ERROR (Status)) {\r
2659 break;\r
2660 }\r
2661\r
2662 //\r
2663 // Ignore those logical ATA_PASS_THRU instance.\r
2664 //\r
2665 if ((AtaPassThru->Mode->Attributes & EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL) == 0) {\r
2666 continue;\r
2667 }\r
2668\r
2669 Status = gBS->HandleProtocol (\r
2670 Controller,\r
2671 &gEfiPciIoProtocolGuid,\r
c411b485 2672 (VOID **)&PciIo\r
e8959f81
HW
2673 );\r
2674 ASSERT_EFI_ERROR (Status);\r
2675 if (EFI_ERROR (Status)) {\r
2676 break;\r
2677 }\r
2678\r
2679 Status = PciIo->GetLocation (\r
2680 PciIo,\r
2681 &SegNum,\r
2682 &BusNum,\r
2683 &DevNum,\r
2684 &FuncNum\r
2685 );\r
2686 ASSERT_EFI_ERROR (Status);\r
2687 if (EFI_ERROR (Status)) {\r
2688 break;\r
2689 }\r
2690\r
2691 //\r
2692 // Assume and only support Segment == 0.\r
2693 //\r
2694 ASSERT (SegNum == 0);\r
2695\r
2696 //\r
2697 // traverse all attached harddisk devices to update form and unlock it\r
2698 //\r
2699 Port = 0xFFFF;\r
2700\r
2701 while (TRUE) {\r
2702 Status = AtaPassThru->GetNextPort (AtaPassThru, &Port);\r
2703 if (EFI_ERROR (Status)) {\r
2704 //\r
2705 // We cannot find more legal port then we are done.\r
2706 //\r
2707 break;\r
2708 }\r
2709\r
2710 PortMultiplierPort = 0xFFFF;\r
2711 while (TRUE) {\r
2712 Status = AtaPassThru->GetNextDevice (AtaPassThru, Port, &PortMultiplierPort);\r
2713 if (EFI_ERROR (Status)) {\r
2714 //\r
2715 // We cannot find more legal port multiplier port number for ATA device\r
2716 // on the port, then we are done.\r
2717 //\r
2718 break;\r
2719 }\r
c411b485 2720\r
e8959f81
HW
2721 //\r
2722 // Find out the attached harddisk devices.\r
2723 // Try to add a HDD Password configuration page for the attached devices.\r
2724 //\r
2725 gBS->RestoreTPL (TPL_APPLICATION);\r
2726 Status = HddPasswordConfigUpdateForm (Private->HiiHandle, AtaPassThru, PciIo, Controller, BusNum, DevNum, FuncNum, Port, PortMultiplierPort);\r
2727 gBS->RaiseTPL (TPL_CALLBACK);\r
2728 if (EFI_ERROR (Status)) {\r
2729 break;\r
2730 }\r
2731 }\r
2732 }\r
2733 }\r
2734\r
2735 FreePool (HandleBuffer);\r
c411b485 2736 return;\r
e8959f81
HW
2737}\r
2738\r
2739/**\r
2740 Initialize the HDD Password configuration form.\r
2741\r
2742 @param[out] Instance Pointer to private instance.\r
2743\r
2744 @retval EFI_SUCCESS The HDD Password configuration form is initialized.\r
2745 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
2746 @retval Others Other errors as indicated.\r
2747**/\r
2748EFI_STATUS\r
2749HddPasswordConfigFormInit (\r
c411b485 2750 OUT HDD_PASSWORD_DXE_PRIVATE_DATA **Instance\r
e8959f81
HW
2751 )\r
2752{\r
c411b485
MK
2753 EFI_STATUS Status;\r
2754 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
e8959f81
HW
2755\r
2756 InitializeListHead (&mHddPasswordConfigFormList);\r
2757\r
2758 Private = AllocateZeroPool (sizeof (HDD_PASSWORD_DXE_PRIVATE_DATA));\r
2759 if (Private == NULL) {\r
2760 return EFI_OUT_OF_RESOURCES;\r
2761 }\r
2762\r
c411b485 2763 Private->Signature = HDD_PASSWORD_DXE_PRIVATE_SIGNATURE;\r
e8959f81
HW
2764\r
2765 Private->ConfigAccess.ExtractConfig = HddPasswordFormExtractConfig;\r
2766 Private->ConfigAccess.RouteConfig = HddPasswordFormRouteConfig;\r
2767 Private->ConfigAccess.Callback = HddPasswordFormCallback;\r
2768\r
2769 //\r
2770 // Install Device Path Protocol and Config Access protocol to driver handle\r
2771 //\r
2772 Status = gBS->InstallMultipleProtocolInterfaces (\r
2773 &Private->DriverHandle,\r
2774 &gEfiDevicePathProtocolGuid,\r
2775 &mHddPasswordHiiVendorDevicePath,\r
2776 &gEfiHiiConfigAccessProtocolGuid,\r
2777 &Private->ConfigAccess,\r
2778 NULL\r
2779 );\r
2780 ASSERT_EFI_ERROR (Status);\r
2781 if (EFI_ERROR (Status)) {\r
c411b485 2782 FreePool (Private);\r
e8959f81
HW
2783 return Status;\r
2784 }\r
2785\r
2786 //\r
2787 // Publish our HII data\r
2788 //\r
2789 Private->HiiHandle = HiiAddPackages (\r
2790 &mHddPasswordVendorGuid,\r
2791 Private->DriverHandle,\r
2792 HddPasswordDxeStrings,\r
2793 HddPasswordBin,\r
2794 NULL\r
2795 );\r
2796 if (Private->HiiHandle == NULL) {\r
c411b485 2797 FreePool (Private);\r
e8959f81
HW
2798 return EFI_OUT_OF_RESOURCES;\r
2799 }\r
2800\r
2801 *Instance = Private;\r
2802 return Status;\r
2803}\r
2804\r
2805/**\r
2806 Main entry for this driver.\r
2807\r
2808 @param ImageHandle Image handle this driver.\r
2809 @param SystemTable Pointer to SystemTable.\r
2810\r
d6b926e7 2811 @retval EFI_SUCCESS This function always complete successfully.\r
e8959f81
HW
2812\r
2813**/\r
2814EFI_STATUS\r
2815EFIAPI\r
2816HddPasswordDxeInit (\r
c411b485
MK
2817 IN EFI_HANDLE ImageHandle,\r
2818 IN EFI_SYSTEM_TABLE *SystemTable\r
e8959f81
HW
2819 )\r
2820{\r
2821 EFI_STATUS Status;\r
2822 HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
fcf8bdcd 2823 VOID *Registration;\r
e8959f81
HW
2824 EFI_EVENT EndOfDxeEvent;\r
2825 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
2826\r
2827 Private = NULL;\r
2828\r
2829 //\r
2830 // Initialize the configuration form of HDD Password.\r
2831 //\r
2832 Status = HddPasswordConfigFormInit (&Private);\r
2833 if (EFI_ERROR (Status)) {\r
2834 return Status;\r
2835 }\r
2836\r
2837 //\r
2838 // Register HddPasswordNotificationEvent() notify function.\r
2839 //\r
2840 EfiCreateProtocolNotifyEvent (\r
2841 &gEfiAtaPassThruProtocolGuid,\r
2842 TPL_CALLBACK,\r
2843 HddPasswordNotificationEvent,\r
2844 (VOID *)Private,\r
2845 &Registration\r
2846 );\r
2847\r
2848 Status = gBS->CreateEventEx (\r
2849 EVT_NOTIFY_SIGNAL,\r
2850 TPL_CALLBACK,\r
2851 HddPasswordEndOfDxeEventNotify,\r
2852 NULL,\r
2853 &gEfiEndOfDxeEventGroupGuid,\r
2854 &EndOfDxeEvent\r
2855 );\r
2856 ASSERT_EFI_ERROR (Status);\r
2857\r
2858 //\r
d6b926e7 2859 // Make HDD_PASSWORD_VARIABLE_NAME variable read-only.\r
e8959f81 2860 //\r
c411b485 2861 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
e8959f81
HW
2862 if (!EFI_ERROR (Status)) {\r
2863 Status = VariableLock->RequestToLock (\r
2864 VariableLock,\r
2865 HDD_PASSWORD_VARIABLE_NAME,\r
2866 &mHddPasswordVendorGuid\r
2867 );\r
2868 DEBUG ((DEBUG_INFO, "%a(): Lock %s variable (%r)\n", __FUNCTION__, HDD_PASSWORD_VARIABLE_NAME, Status));\r
2869 ASSERT_EFI_ERROR (Status);\r
2870 }\r
2871\r
2872 return Status;\r
2873}\r