123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- /** @file
- HddPassword PEI module which is used to unlock HDD password for S3.
- Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "HddPasswordPei.h"
- EFI_GUID mHddPasswordDeviceInfoGuid = HDD_PASSWORD_DEVICE_INFO_GUID;
- /**
- Send unlock hdd password cmd through ATA PassThru PPI.
- @param[in] AtaPassThru The pointer to the ATA PassThru PPI.
- @param[in] Port The port number of the ATA device.
- @param[in] PortMultiplierPort The port multiplier port number of the ATA device.
- @param[in] Identifier The identifier to set user or master password.
- @param[in] Password The hdd password of attached ATA device.
- @retval EFI_SUCCESS Successful to send unlock hdd password cmd.
- @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
- @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.
- @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd.
- **/
- EFI_STATUS
- UnlockDevice (
- IN EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru,
- IN UINT16 Port,
- IN UINT16 PortMultiplierPort,
- IN CHAR8 Identifier,
- IN CHAR8 *Password
- )
- {
- EFI_STATUS Status;
- EFI_ATA_COMMAND_BLOCK Acb;
- EFI_ATA_STATUS_BLOCK *Asb;
- EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
- UINT8 Buffer[HDD_PAYLOAD];
- if ((AtaPassThru == NULL) || (Password == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
- // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
- // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
- // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
- // may not be aligned when allocated on stack for some compilers. Hence, we
- // use the API AllocateAlignedPages to ensure this structure is properly
- // aligned.
- //
- Asb = AllocateAlignedPages (
- EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
- AtaPassThru->Mode->IoAlign
- );
- if (Asb == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Prepare for ATA command block.
- //
- ZeroMem (&Acb, sizeof (Acb));
- ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
- Acb.AtaCommand = ATA_SECURITY_UNLOCK_CMD;
- Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));
- //
- // Prepare for ATA pass through packet.
- //
- ZeroMem (&Packet, sizeof (Packet));
- Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;
- Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;
- Packet.Asb = Asb;
- Packet.Acb = &Acb;
- ((CHAR16 *) Buffer)[0] = Identifier & BIT0;
- CopyMem (&((CHAR16 *) Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);
- Packet.OutDataBuffer = Buffer;
- Packet.OutTransferLength = sizeof (Buffer);
- Packet.Timeout = ATA_TIMEOUT;
- Status = AtaPassThru->PassThru (
- AtaPassThru,
- Port,
- PortMultiplierPort,
- &Packet
- );
- if (!EFI_ERROR (Status) &&
- ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
- ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {
- Status = EFI_DEVICE_ERROR;
- }
- FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));
- ZeroMem (Buffer, sizeof (Buffer));
- DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));
- return Status;
- }
- /**
- Send security freeze lock cmd through ATA PassThru PPI.
- @param[in] AtaPassThru The pointer to the ATA PassThru PPI.
- @param[in] Port The port number of the ATA device.
- @param[in] PortMultiplierPort The port multiplier port number of the ATA device.
- @retval EFI_SUCCESS Successful to send security freeze lock cmd.
- @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.
- @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.
- @retval EFI_DEVICE_ERROR Can not send security freeze lock cmd.
- **/
- EFI_STATUS
- FreezeLockDevice (
- IN EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru,
- IN UINT16 Port,
- IN UINT16 PortMultiplierPort
- )
- {
- EFI_STATUS Status;
- EFI_ATA_COMMAND_BLOCK Acb;
- EFI_ATA_STATUS_BLOCK *Asb;
- EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
- if (AtaPassThru == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
- // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by
- // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,
- // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it
- // may not be aligned when allocated on stack for some compilers. Hence, we
- // use the API AllocateAlignedPages to ensure this structure is properly
- // aligned.
- //
- Asb = AllocateAlignedPages (
- EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
- AtaPassThru->Mode->IoAlign
- );
- if (Asb == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Prepare for ATA command block.
- //
- ZeroMem (&Acb, sizeof (Acb));
- ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
- Acb.AtaCommand = ATA_SECURITY_FREEZE_LOCK_CMD;
- Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));
- //
- // Prepare for ATA pass through packet.
- //
- ZeroMem (&Packet, sizeof (Packet));
- Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;
- Packet.Length = EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER;
- Packet.Asb = Asb;
- Packet.Acb = &Acb;
- Packet.Timeout = ATA_TIMEOUT;
- Status = AtaPassThru->PassThru (
- AtaPassThru,
- Port,
- PortMultiplierPort,
- &Packet
- );
- if (!EFI_ERROR (Status) &&
- ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
- ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {
- Status = EFI_DEVICE_ERROR;
- }
- FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));
- DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));
- return Status;
- }
- /**
- Unlock HDD password for S3.
- @param[in] AtaPassThruPpi Pointer to the EDKII_PEI_ATA_PASS_THRU_PPI instance.
- **/
- VOID
- UnlockHddPassword (
- IN EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThruPpi
- )
- {
- EFI_STATUS Status;
- VOID *Buffer;
- UINTN Length;
- UINT8 DummyData;
- HDD_PASSWORD_DEVICE_INFO *DevInfo;
- UINT16 Port;
- UINT16 PortMultiplierPort;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- UINTN DevicePathLength;
- //
- // Get HDD password device info from LockBox.
- //
- Buffer = (VOID *) &DummyData;
- Length = sizeof (DummyData);
- Status = RestoreLockBox (&mHddPasswordDeviceInfoGuid, Buffer, &Length);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Length));
- if (Buffer != NULL) {
- Status = RestoreLockBox (&mHddPasswordDeviceInfoGuid, Buffer, &Length);
- }
- }
- if ((Buffer == NULL) || (Buffer == (VOID *) &DummyData)) {
- return;
- } else if (EFI_ERROR (Status)) {
- FreePages (Buffer, EFI_SIZE_TO_PAGES (Length));
- return;
- }
- Status = AtaPassThruPpi->GetDevicePath (AtaPassThruPpi, &DevicePathLength, &DevicePath);
- if (EFI_ERROR (Status) || (DevicePathLength <= sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
- goto Exit;
- }
- //
- // Go through all the devices managed by the AtaPassThru PPI instance.
- //
- Port = 0xFFFF;
- while (TRUE) {
- Status = AtaPassThruPpi->GetNextPort (AtaPassThruPpi, &Port);
- if (EFI_ERROR (Status)) {
- //
- // We cannot find more legal port then we are done.
- //
- break;
- }
- PortMultiplierPort = 0xFFFF;
- while (TRUE) {
- Status = AtaPassThruPpi->GetNextDevice (AtaPassThruPpi, Port, &PortMultiplierPort);
- if (EFI_ERROR (Status)) {
- //
- // We cannot find more legal port multiplier port number for ATA device
- // on the port, then we are done.
- //
- break;
- }
- //
- // Search the device in the restored LockBox.
- //
- DevInfo = (HDD_PASSWORD_DEVICE_INFO *) Buffer;
- while ((UINTN) DevInfo < ((UINTN) Buffer + Length)) {
- //
- // Find the matching device.
- //
- if ((DevInfo->Device.Port == Port) &&
- (DevInfo->Device.PortMultiplierPort == PortMultiplierPort) &&
- (DevInfo->DevicePathLength >= DevicePathLength) &&
- (CompareMem (
- DevInfo->DevicePath,
- DevicePath,
- DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) == 0)) {
- //
- // If device locked, unlock first.
- //
- if (!IsZeroBuffer (DevInfo->Password, HDD_PASSWORD_MAX_LENGTH)) {
- UnlockDevice (AtaPassThruPpi, Port, PortMultiplierPort, 0, DevInfo->Password);
- }
- //
- // Freeze lock the device.
- //
- FreezeLockDevice (AtaPassThruPpi, Port, PortMultiplierPort);
- break;
- }
- DevInfo = (HDD_PASSWORD_DEVICE_INFO *)
- ((UINTN) DevInfo + sizeof (HDD_PASSWORD_DEVICE_INFO) + DevInfo->DevicePathLength);
- }
- }
- }
- Exit:
- ZeroMem (Buffer, Length);
- FreePages (Buffer, EFI_SIZE_TO_PAGES (Length));
- }
- /**
- Entry point of the notification callback function itself within the PEIM.
- It is to unlock HDD password for S3.
- @param PeiServices Indirect reference to the PEI Services Table.
- @param NotifyDescriptor Address of the notification descriptor data structure.
- @param Ppi Address of the PPI that was installed.
- @return Status of the notification.
- The status code returned from this function is ignored.
- **/
- EFI_STATUS
- EFIAPI
- HddPasswordAtaPassThruNotify (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
- IN VOID *Ppi
- )
- {
- DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__));
- UnlockHddPassword ((EDKII_PEI_ATA_PASS_THRU_PPI *) Ppi);
- DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__));
- return EFI_SUCCESS;
- }
- EFI_PEI_NOTIFY_DESCRIPTOR mHddPasswordAtaPassThruPpiNotifyDesc = {
- (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
- &gEdkiiPeiAtaPassThruPpiGuid,
- HddPasswordAtaPassThruNotify
- };
- /**
- Main entry for this module.
- @param FileHandle Handle of the file being invoked.
- @param PeiServices Pointer to PEI Services table.
- @return Status from PeiServicesNotifyPpi.
- **/
- EFI_STATUS
- EFIAPI
- HddPasswordPeiInit (
- IN EFI_PEI_FILE_HANDLE FileHandle,
- IN CONST EFI_PEI_SERVICES **PeiServices
- )
- {
- EFI_STATUS Status;
- EFI_BOOT_MODE BootMode;
- Status = PeiServicesGetBootMode (&BootMode);
- if ((EFI_ERROR (Status)) || (BootMode != BOOT_ON_S3_RESUME)) {
- return EFI_UNSUPPORTED;
- }
- DEBUG ((DEBUG_INFO, "%a: Enters in S3 path.\n", __FUNCTION__));
- Status = PeiServicesNotifyPpi (&mHddPasswordAtaPassThruPpiNotifyDesc);
- ASSERT_EFI_ERROR (Status);
- return Status;
- }
|