/** @file IntelRemapPwd ;****************************************************************************** ;* Copyright (c) 2019 - 2020, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include /** Check if device is a re-mapped NVMe by device path. @param[in] DevicePath Device path info for the device. @retval True It is a Intel remapped device @retval FALSE It is not a Intel remapped device **/ BOOLEAN IsRemappedNvme ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; EFI_HANDLE DiskInfoHandle; EFI_STATUS Status; EFI_DISK_INFO_PROTOCOL *DiskInfo; DiskInfoHandle = NULL; TmpDevicePath = DevicePath; Status = gBS->LocateDevicePath(&gEfiDiskInfoProtocolGuid, &TmpDevicePath, &DiskInfoHandle); if (EFI_ERROR(Status)) { return FALSE; } Status = gBS->HandleProtocol ( DiskInfoHandle, &gEfiDiskInfoProtocolGuid, (VOID **)&DiskInfo ); if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoNvmeInterfaceGuid)) { return TRUE; } return FALSE; } /** Find all agent handles that support HDD Password feature. @param[in] AgentFileGuidList Pointer to AGENT_FILE_GUID_LIST. @param[in] size size of the AGENT_FILE_GUID_LIST. @retval *EFI_HANDLE A list of agent handles that discovered from file Guids **/ EFI_HANDLE* FindAgentHandleListByFileGUID ( AGENT_FILE_GUID_LIST* AgentFileGuidList, UINTN Size ) { EFI_HANDLE *FoundAgentHandleList; UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINTN HandleIndex; EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; EFI_GUID *GuidPoint; EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; UINT8 Index; UINT8 Index1; EFI_STATUS Status; Index1 = 0; // // Add one more entry to the handle list because according to UEFI spec 2.6 // "The list is terminated by a NULL handle value." // FoundAgentHandleList = AllocateZeroPool((Size + 1) * sizeof(EFI_HANDLE)); if (FoundAgentHandleList == NULL) { return NULL; } Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiLoadedImageProtocolGuid, NULL, &HandleCount, &HandleBuffer ); // // find the right driverbinding handle for HDD Password // if (Status == EFI_SUCCESS && HandleBuffer != NULL) { for (Index = 0; Index < Size; Index++) { for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { Status = gBS->HandleProtocol ( HandleBuffer[HandleIndex], &gEfiDriverBindingProtocolGuid, (VOID**) &DriverBinding ); if (EFI_ERROR(Status)) { continue; } Status = gBS->HandleProtocol ( DriverBinding->ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage ); if (EFI_ERROR(Status)) { continue; } TempDevicePath = LoadedImage->FilePath; GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode ( (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempDevicePath ); if (GuidPoint == NULL) { DEBUG ((EFI_D_INFO, " Empty GUID found\n")); continue; } if (CompareGuid(&(AgentFileGuidList[Index].FileGuid), GuidPoint)) { // // store found Agent handles to FoundAgentHandleList in the same order as // AgentFileGuidList defined. // FoundAgentHandleList[Index1] = DriverBinding->ImageHandle; Index1++; } } } } return FoundAgentHandleList; } /** Reconnect Rst Controller after its being unlocked **/ VOID ReConnectRstController ( ) { EFI_STATUS Status; EFI_PCI_IO_PROTOCOL *PciIo; PCI_TYPE00 Pci; EFI_HDD_PASSWORD_SERVICE_PROTOCOL *HddPasswordService; HDD_PASSWORD_HDD_INFO *HddInfoArray; UINTN NumOfHdd; UINTN Index; BOOLEAN FoundSecurityEnabledRaid; UINTN Device; UINTN Seg; UINTN Bus; UINTN Function; UINTN PciIoHandleCount; EFI_HANDLE *PciIoHandleBuffer; UINTN PciIoHandleIndex; EFI_HANDLE *AgentHandleBuffer; AGENT_FILE_GUID_LIST AgentFileGuidList[] = { {0x13863F79, 0xD94B, 0x4205, 0xBB, 0x0F, 0xE4, 0xE0, 0x6A, 0xAA, 0x5A, 0x4E}, // DelayUefiRaid {0x3ACC966D, 0x8E33, 0x45c6, 0xb4, 0xfe, 0x62, 0x72, 0x4B, 0xCD, 0x15, 0xA9}, // AhciBusDxe {0x5BE3BDF4, 0x53CF, 0x46a3, 0xA6, 0xA9, 0x73, 0xC3, 0x4A, 0x6E, 0x5E, 0xE3}, // NVME {0x67BBC344, 0x84BC, 0x4e5c, 0xb4, 0xDF, 0xF5, 0xE4, 0xA0, 0x0E, 0x1F, 0x3A}, // SD {0x70D57D67, 0x7F05, 0x494d, 0xA0, 0x14, 0xB7, 0x5D, 0x73, 0x45, 0xB7, 0x00} // SSCP }; PCH_SETUP *PchSetup; UINTN SetupSize; HddPasswordService = NULL; HddInfoArray = NULL; NumOfHdd = 0; FoundSecurityEnabledRaid = FALSE; PchSetup = NULL; SetupSize = sizeof (PCH_SETUP); PchSetup = AllocateZeroPool (SetupSize); if (PchSetup == NULL) { return; } Status = gRT->GetVariable ( PCH_SETUP_VARIABLE_NAME, &gPchSetupVariableGuid, NULL, &SetupSize, PchSetup ); if (EFI_ERROR(Status)) { FreePool(PchSetup); return; } if(PchSetup->SataLegacyOrom) { return; } Status = gBS->LocateProtocol ( &gEfiHddPasswordServiceProtocolGuid, NULL, (VOID **)&HddPasswordService ); if (EFI_ERROR(Status)) { return; } Status = HddPasswordService->GetHddInfo ( HddPasswordService, &HddInfoArray, &NumOfHdd ); if (NumOfHdd == 0) { return; } Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciIoProtocolGuid, NULL, &PciIoHandleCount, &PciIoHandleBuffer ); if (EFI_ERROR (Status)) { return; } if (Status != EFI_SUCCESS) { return; } if (PciIoHandleCount == 0) { return; } for (PciIoHandleIndex = 0; PciIoHandleIndex < PciIoHandleCount; PciIoHandleIndex++) { Status = gBS->HandleProtocol ( PciIoHandleBuffer[PciIoHandleIndex], &gEfiPciIoProtocolGuid, (VOID **)&PciIo ); if (Status != EFI_SUCCESS) { continue; } Status = PciIo->GetLocation ( PciIo, &Seg, &Bus, &Device, &Function ); if (Status != EFI_SUCCESS) { return; } Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci ); if (Status != EFI_SUCCESS) { continue; } if (!IS_PCI_RAID (&Pci)) { continue; } for (Index = 0; Index < NumOfHdd; Index++) { if ((HddInfoArray[Index].PciSeg == Seg) && (HddInfoArray[Index].PciBus == Bus) && (HddInfoArray[Index].PciDevice == Device) && (HddInfoArray[Index].PciFunction == Function)) { if ((HddInfoArray[Index].HddSecurityStatus & HDD_SECURITY_ENABLE) && !(HddInfoArray[Index].HddSecurityStatus & HDD_SECURITY_LOCK)) { FoundSecurityEnabledRaid = TRUE; break; } } } if (!FoundSecurityEnabledRaid) { continue; } // // Reconnect the Raid handle // Status = gBS->DisconnectController ( PciIoHandleBuffer[PciIoHandleIndex], NULL, NULL ); ASSERT_EFI_ERROR(Status); AgentHandleBuffer = FindAgentHandleListByFileGUID(AgentFileGuidList, sizeof(AgentFileGuidList)/sizeof(EFI_GUID)); if (AgentHandleBuffer == NULL) { return; } Status = gBS->ConnectController ( PciIoHandleBuffer[PciIoHandleIndex], AgentHandleBuffer, NULL, TRUE ); ASSERT_EFI_ERROR(Status); } } /** Build Re-mapped NVMe OPAL device info and save them to LockBox. **/ VOID BuildOpalDeviceInfoForIntelRst ( ) { EFI_STATUS Status; EFI_PCI_IO_PROTOCOL *PciIo; PCI_TYPE00 Pci; EFI_HDD_PASSWORD_SERVICE_PROTOCOL *HddPasswordService; HDD_PASSWORD_HDD_INFO *HddInfoArray; UINTN NumOfHdd; UINTN Index; EFI_HANDLE ControllerHandle; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; UINTN Count; OPAL_DEVICE_INTEL_REMAP *DevInfoRemap; SATA_DEVICE_PATH *SataDevPath; HDD_PASSWORD_TABLE *HddPasswordTable; HDD_PASSWORD_TABLE *HddPasswordTablePtr; UINTN HddPasswordTableIndex; UINT32 HddPasswordCount; UINTN TempPasswordLength; HddPasswordService = NULL; HddInfoArray = NULL; NumOfHdd = 0; Count = 0; DevInfoRemap = NULL; SataDevPath = NULL; HddPasswordCount = 0; HddPasswordTable = NULL; Status = gBS->LocateProtocol ( &gEfiHddPasswordServiceProtocolGuid, NULL, (VOID **)&HddPasswordService ); if (EFI_ERROR(Status)) { return; } Status = HddPasswordService->GetHddInfo ( HddPasswordService, &HddInfoArray, &NumOfHdd ); if (NumOfHdd == 0 || HddInfoArray == NULL) { return; } HddPasswordCount = (UINT32)NumOfHdd; if (FeaturePcdGet (PcdH2OBaseCpHddPasswordGetTableSupported)) { Status = TriggerCpHddPasswordGetTable(&HddPasswordTable, &HddPasswordCount); if (EFI_ERROR (Status)) { if (Status == EFI_WARN_STALE_DATA) { if (FeaturePcdGet (PcdH2OBaseCpHddPasswordSetTableSupported) ) { TriggerCpHddPasswordSetTable(HddPasswordTable, HddPasswordCount); } } else { return; } } } if (HddPasswordTable == NULL){ return; } // // For those devices still lock at this point, no need to store its information to // SAVE_HDD_PASSWORD_FOR_REMAP_DEVICE_NAME variable because no need to autounlock it in S3 // for (Index = 0; Index < NumOfHdd; Index++) { if ((HddInfoArray[Index].HddSecurityStatus & HDD_ENABLE_BIT) != HDD_ENABLE_BIT) { continue; } if ((HddInfoArray[Index].HddSecurityStatus & HDD_LOCKED_BIT) == HDD_LOCKED_BIT) { continue; } Status = gBS->HandleProtocol ( HddInfoArray[Index].DeviceHandleInDxe, &gEfiDevicePathProtocolGuid, (VOID *) &DevicePath ); if (Status != EFI_SUCCESS) { continue; } ControllerHandle = NULL; TmpDevicePath = DevicePath; Status = gBS->LocateDevicePath(&gEfiPciIoProtocolGuid, &TmpDevicePath, &ControllerHandle); if (Status != EFI_SUCCESS || ControllerHandle == NULL) { continue; } Status = gBS->HandleProtocol ( ControllerHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo ); Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci ); if (Status != EFI_SUCCESS) { continue; } if (!IS_PCI_RAID (&Pci)) { continue; } // // Find the SATA device path // TmpDevicePath = DevicePath; while (!IsDevicePathEnd (TmpDevicePath)) { if (TmpDevicePath->Type == MESSAGING_DEVICE_PATH && TmpDevicePath->SubType == MSG_SATA_DP) { SataDevPath = (SATA_DEVICE_PATH *) TmpDevicePath; break; } TmpDevicePath = NextDevicePathNode (TmpDevicePath); } if (SataDevPath == NULL) { continue; } // // get new struncture // DevInfoRemap = (OPAL_DEVICE_INTEL_REMAP*)ReallocatePool ( Count * sizeof(OPAL_DEVICE_INTEL_REMAP), (Count + 1) * sizeof(OPAL_DEVICE_INTEL_REMAP), (VOID *)DevInfoRemap); if (DevInfoRemap == NULL) { return; } DevInfoRemap[Count].Segment = (UINT16)HddInfoArray[Index].PciSeg; DevInfoRemap[Count].Bus = (UINT8)HddInfoArray[Index].PciBus; DevInfoRemap[Count].Device = (UINT8)HddInfoArray[Index].PciDevice; DevInfoRemap[Count].Function = (UINT8)HddInfoArray[Index].PciFunction; DevInfoRemap[Count].ControllerNumberForHddPasswordTable = HddInfoArray[Index].ControllerNumber; // // get original devicepath // TmpDevicePath = DevicePath; if (IsRemappedNvme(TmpDevicePath)) { DevInfoRemap[Count].DeviceType = OPAL_DEVICE_TYPE_REMAP_NVME; } else { DevInfoRemap[Count].DeviceType = OPAL_DEVICE_TYPE_ATA; } HddPasswordTablePtr = (HDD_PASSWORD_TABLE *)HddPasswordTable; for (HddPasswordTableIndex = 0; HddPasswordTableIndex < HddPasswordCount; HddPasswordTableIndex++, HddPasswordTablePtr = GetNextTableEntry (HddPasswordTablePtr)) { if ((HddPasswordTablePtr->ControllerNumber == HddInfoArray[Index].ControllerNumber) && (HddPasswordTablePtr->PortNumber == HddInfoArray[Index].PortNumber) && (HddPasswordTablePtr->PortMulNumber == HddInfoArray[Index].PortMulNumber)) { HddPasswordService->PasswordStringProcess ( HddPasswordService, USER_PSW, HddPasswordTablePtr->PasswordStr, StrLen (HddPasswordTablePtr->PasswordStr), (VOID **)&DevInfoRemap[Count].Password, &TempPasswordLength ); DevInfoRemap[Count].PasswordLength = (UINT8)TempPasswordLength; break; } } // // for Intel PeiOpalDeviceInfoPpi, need original port number from device path // DevInfoRemap[Count].Port = SataDevPath->HBAPortNumber; DevInfoRemap[Count].PortMultiplierPort = HddInfoArray[Index].PortMulNumber; Count++; } Status = CommonSetVariable ( SAVE_HDD_PASSWORD_FOR_REMAP_DEVICE_NAME, &gSaveIntelRemapDevInfoGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, Count * sizeof(OPAL_DEVICE_INTEL_REMAP), (VOID *) DevInfoRemap ); ASSERT_EFI_ERROR(Status); gBS->FreePool (HddInfoArray); return; } /** Collect remap and Raid drive information for s3 auto unlock in Pei phase @param[in] Event Pointer to this event @param[in] Handle The handle associated with a previously registered checkpoint handler. **/ VOID H2OBdsCpEnumerteAfterCallback ( IN EFI_EVENT Event, IN H2O_CP_HANDLE Handle ) { H2OCpUnregisterHandler (Handle); BuildOpalDeviceInfoForIntelRst(); } /** To check if Intel Raid devices have being security enabled, if Yes, reconnect the controller. This is due to Intel Rst Driver can't produce BlockIo, after unlock a device, until re-enumerate device again for security reason. @param[in] Event Pointer to this event @param[in] Handle The handle associated with a previously registered checkpoint handler. **/ VOID H2OBdsCpEnumerteBeforeCallback ( IN EFI_EVENT Event, IN H2O_CP_HANDLE Handle ) { H2OCpUnregisterHandler (Handle); ReConnectRstController(); } /** To support HddPassword for Intel Remapped device, need to dispatch Intel RST driver before reaching H2OBdsCpConOutAfter checkpoint. This is where HddPassword driver collect all supported devices **/ VOID DispatchIntelRstBeforeConOutAfter ( ) { //[-start-200826-IB16740113-remove]// // UINT32 Index; //[-end-200826-IB16740113-remove]// EFI_HANDLE ControllerHandle; PCH_SETUP *PchSetup; UINTN SetupSize; EFI_STATUS Status; BOOLEAN FoundRemappedDevice; FoundRemappedDevice = FALSE; PchSetup = NULL; SetupSize = sizeof (PCH_SETUP); PchSetup = AllocateZeroPool (SetupSize); if (PchSetup == NULL) { return; } Status = gRT->GetVariable ( PCH_SETUP_VARIABLE_NAME, &gPchSetupVariableGuid, NULL, &SetupSize, PchSetup ); if (EFI_ERROR(Status)) { FreePool(PchSetup); return; } if (PchSetup->SataInterfaceMode != SATA_MODE_RAID) { FreePool(PchSetup); return; } ControllerHandle = NULL; //[-start-200826-IB16740113-remove]// The code for RstPcieRemapEnabled has removed in RC1341 // // // // only need to dispatch Rst driver earlier when remapped device password feature is supported // // // for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) { // if (PchSetup->RstPcieRemapEnabled[Index]) { // Status = gBS->InstallProtocolInterface ( // &ControllerHandle, // &gUefiRaidOpromReadyGuid, // EFI_NATIVE_INTERFACE, // NULL // ); // gDS->Dispatch(); // FoundRemappedDevice = TRUE; // break; // } // } //[-end-200826-IB16740113-remove]// if (!PchSetup->SataLegacyOrom && FoundRemappedDevice) { if (FeaturePcdGet (PcdH2OBdsCpBootDeviceEnumBeforeSupported)) { // // Register for callback on Storage Security Protocol publication // EFI_HANDLE H2OBdsCpBootDeviceEnumBeforeHandle = NULL; Status = H2OCpRegisterHandler ( &gH2OBdsCpBootDeviceEnumBeforeGuid, H2OBdsCpEnumerteBeforeCallback, HDD_PASSWORD_CONNECT_CONTROLLER_NOTIFY_TPL, &H2OBdsCpBootDeviceEnumBeforeHandle ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpBootDeviceEnumBeforeGuid, Status)); } DEBUG ((EFI_D_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpBootDeviceEnumBeforeGuid, Status)); } if (FeaturePcdGet (PcdH2OBdsCpBootDeviceEnumAfterSupported)) { // // Register for callback on Storage Security Protocol publication // EFI_HANDLE H2OBdsCpBootDeviceEnumAfterHandle = NULL; Status = H2OCpRegisterHandler ( &gH2OBdsCpBootDeviceEnumAfterGuid, H2OBdsCpEnumerteAfterCallback, HDD_PASSWORD_CONNECT_CONTROLLER_NOTIFY_TPL, &H2OBdsCpBootDeviceEnumAfterHandle ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpBootDeviceEnumAfterGuid, Status)); } DEBUG ((EFI_D_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpBootDeviceEnumAfterGuid, Status)); } } }