/** Dispatch function for a Software SMI handler. @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). @param[in] RegisterContext Points to an optional handler context which was specified when the handler was registered. @param[in, out] CommBuffer A pointer to a collection of Data in memory that will be conveyed from a non-SMM environment into an SMM environment. @param[in, out] CommBufferSize The Size of the CommBuffer. @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers should still be called. @retval Others Other execution results. **/ EFI_STATUS EFIAPI SmmUnlockOpalPassword ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *RegisterContext, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize ) { EFI_STATUS Status; OPAL_SMM_DEVICE *OpalDev; LIST_ENTRY *Entry; UINT8 BaseClassCode; UINT8 SubClassCode; UINT8 ProgInt; TCG_RESULT Result; UINT8 SataCmdSt; UINT8 *StorePcieConfDataList[16]; UINTN RpBase; UINTN MemoryBase; UINTN MemoryLength; OPAL_SESSION Session; BOOLEAN BlockSidSupport; ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList)); Status = EFI_DEVICE_ERROR; // // try to unlock all locked hdd disks. // for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) { OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link); RpBase = 0; SataCmdSt = 0; /// /// Configure RootPort for PCIe AHCI/NVME devices. /// if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { /// /// Save original RootPort configuration space to heap /// RpBase = SaveRestoreRootportConfSpace ( OpalDev, TRUE, StorePcieConfDataList ); MemoryBase = mNvmeContext.Nbar; MemoryLength = 0; ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength); /// /// Enable PCIE decode for RootPort /// SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD); PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6); } else { SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD)); PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), 0x6); } BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0B)); SubClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0A)); ProgInt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x09)); if (BaseClassCode != PCI_CLASS_MASS_STORAGE) { Status = EFI_INVALID_PARAMETER; break; } Status = EFI_DEVICE_ERROR; if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_SATA) { if ((SubClassCode == PCI_CLASS_MASS_STORAGE_AHCI) || (SubClassCode == PCI_CLASS_MASS_STORAGE_RAID)) { Status = GetAhciBaseAddress (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "GetAhciBaseAddress error, Status: %r\n", Status)); goto done; } Status = AhciModeInitialize ((UINT8)OpalDev->SataPort); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "AhciModeInitialize error, Status: %r\n", Status)); goto done; } } else { DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n")); } } else if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { if (ProgInt != PCI_IF_NVMHCI) { DEBUG ((DEBUG_ERROR, "PI not support, skipped\n")); Status = EFI_NOT_FOUND; goto done; } mNvmeContext.PciBase = PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0); mNvmeContext.NvmeInitWaitTime = 0; mNvmeContext.Nsid = OpalDev->NvmeNamespaceId; Status = NvmeControllerInit (&mNvmeContext); } else { DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n")); } } else { DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n")); goto done; } Status = EFI_DEVICE_ERROR; BlockSidSupport = FALSE; if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) { ZeroMem(&Session, sizeof(Session)); Session.Sscp = &OpalDev->Sscp; Session.MediaId = 0; Session.OpalBaseComId = OpalDev->OpalBaseComId; Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL); if (Result == TcgResultSuccess) { Status = EFI_SUCCESS; } } if (mSendBlockSID && BlockSidSupport) { Result = OpalBlockSid (&Session, TRUE); if (Result != TcgResultSuccess) { break; } } if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { Status = NvmeControllerExit (&mNvmeContext); } } done: if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { ASSERT (RpBase != 0); PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0); RpBase = SaveRestoreRootportConfSpace ( OpalDev, FALSE, // restore StorePcieConfDataList ); PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt); } else { PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt); } if (EFI_ERROR (Status)) { break; } } return Status; }
/** Check if disk is locked, show popup window and ask for password if it is @param[in] Dev The device which need to be unlock. **/ VOID OpalDriverRequestPassword ( OPAL_DRIVER_DEVICE *Dev ) { UINT8 Count; BOOLEAN IsEnabled; CHAR8 *Password; UINT32 PasswordLen; TCG_RESULT Ret; EFI_INPUT_KEY Key; OPAL_SESSION Session; BOOLEAN PressEsc; BOOLEAN Locked; if (Dev == NULL) { return; } Count = 0; IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature); if (IsEnabled) { ZeroMem(&Session, sizeof(Session)); Session.Sscp = Dev->OpalDisk.Sscp; Session.MediaId = Dev->OpalDisk.MediaId; Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; Locked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature); while (Count < MAX_PASSWORD_TRY_COUNT) { Password = OpalDriverPopUpHddPassword (Dev, &PressEsc); if (PressEsc) { if (Locked) { // // Current device in the lock status and // User not input password and press ESC, // keep device in lock status and continue boot. // do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Press ENTER to skip password, Press ESC to input password", NULL ); } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { gST->ConOut->ClearScreen(gST->ConOut); // // Keep lock and continue boot. // return; } else { // // Let user input password again. // continue; } } else { // // Current device in the unlock status and // User not input password and press ESC, // Shutdown the device. // do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Press ENTER to shutdown, Press ESC to input password", NULL ); } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); } else { // // Let user input password again. // continue; } } } if (Password == NULL) { Count ++; continue; } PasswordLen = (UINT32) AsciiStrLen(Password); if (Locked) { Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath); } else { Ret = OpalSupportLock(&Session, Password, PasswordLen, Dev->OpalDevicePath); if (Ret == TcgResultSuccess) { Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath); } } if (Password != NULL) { ZeroMem (Password, PasswordLen); FreePool (Password); } if (Ret == TcgResultSuccess) { break; } Count++; do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid password.", L"Press ENTER to retry", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); } if (Count >= MAX_PASSWORD_TRY_COUNT) { do { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Opal password retry count exceeds the limit. Must shutdown!", L"Press ENTER to shutdown", NULL ); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); } } }