987 lines
29 KiB
C
987 lines
29 KiB
C
/** @file
|
|
Misc. function in HDD Password Protocol
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2021, 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 "HddPassword.h"
|
|
DRIVER_INSTALL_INFO *mDriverInstallInfo;
|
|
MEMORY_PAGE_TABLE *mMemoryBuffer;
|
|
|
|
CONTROLER_CLASS_CODE_LIST mClassCodeList[] = {
|
|
{PCI_CLASS_MASS_STORAGE, PCI_SUB_CLASS_NVME, PCI_IF_NVMHCI},
|
|
{PCI_CLASS_MASS_STORAGE, PCI_SUB_CLASS_AHCI, PCI_IF_AHCI},
|
|
{PCI_CLASS_MASS_STORAGE, PCI_SUB_CLASS_RAID, PCI_IF_RAID},
|
|
{PCI_CLASS_SD_HC, PCI_SUB_CLASS_SDHC, PCI_IF_SD}
|
|
};
|
|
|
|
//
|
|
// DelayUefiRaid should always listed before other drivers because it will
|
|
// register passthru related callbacks which produce by others
|
|
//
|
|
AGENT_FILE_GUID_LIST mAgentFileGuidList[] = {
|
|
{0x13863F79, 0xD94B, 0x4205, 0xBB, 0x0F, 0xE4, 0xE0, 0x6A, 0xAA, 0x5A, 0x4E}, // DelayUefiRaid
|
|
{0xBB65942B, 0x521F, 0x4ec3, 0xBA, 0xF9, 0xA9, 0x25, 0x40, 0xCF, 0x60, 0xD2}, // SataController INTEL
|
|
{0x0325B5A1, 0x0937, 0x4A4F, 0xB8, 0xAF, 0xEC, 0x3F, 0x80, 0xEE, 0x6B, 0x35}, // SataController AMD
|
|
{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
|
|
};
|
|
|
|
/**
|
|
Initializes pre-allocated memory.
|
|
|
|
@param[out] MemoryPageTable Pointer to memory page table.
|
|
|
|
@retval EFI_SUCCESS Successful initialization.
|
|
@retval Others Initialization failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InitializeMemoryBuffer (
|
|
OUT MEMORY_PAGE_TABLE **MemoryPageTable
|
|
)
|
|
{
|
|
UINTN Index;
|
|
VOID *Buffer;
|
|
MEMORY_PAGE_TABLE *PageTable;
|
|
|
|
PageTable = AllocateReservedPool(sizeof (MEMORY_PAGE_TABLE) + (sizeof (MEMORY_PAGE_ENTRY) * (MIN_REQUIRED_BLOCKS - 1)));
|
|
if(PageTable == NULL){
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Pre-allocates memory space
|
|
//
|
|
Buffer = AllocateReservedPool(MEMORY_PREALLOCATE_SIZE);
|
|
if (Buffer == NULL) {
|
|
FreePool (PageTable);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Initialize Internal Page Table for Memory Management
|
|
//
|
|
SetMem (Buffer, MEMORY_PREALLOCATE_SIZE, 0xFF);
|
|
SetMem (PageTable, (sizeof (MEMORY_PAGE_TABLE) + (sizeof (MEMORY_PAGE_ENTRY) * (MIN_REQUIRED_BLOCKS - 1))), 0);
|
|
|
|
PageTable->PageCount = MEMORY_PREALLOCATE_SIZE / PAGE_BLOCK_SIZE;
|
|
PageTable->LastEmptyPageOffset = 0x0;
|
|
|
|
for (Index = 0; Index < PageTable->PageCount; Index++) {
|
|
PageTable->Pages[Index].PageFlag = PAGE_FREE;
|
|
PageTable->Pages[Index].StartPageOffset = 0;
|
|
}
|
|
|
|
PageTable->DataAreaBase = Buffer;
|
|
|
|
*MemoryPageTable = PageTable;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Look-up Free memory Region for object allocation.
|
|
|
|
@param[in] AllocationSize Bytes to be allocated.
|
|
|
|
@return Return available page offset for object allocation.
|
|
|
|
**/
|
|
UINTN
|
|
LookupFreeMemRegion (
|
|
IN UINTN AllocationSize
|
|
)
|
|
{
|
|
UINTN StartPageIndex;
|
|
UINTN Index;
|
|
UINTN SubIndex;
|
|
UINTN ReqPages;
|
|
MEMORY_PAGE_TABLE *PageTable;
|
|
|
|
PageTable = mMemoryBuffer;
|
|
|
|
StartPageIndex = SIZE_TO_PAGES (PageTable->LastEmptyPageOffset);
|
|
ReqPages = SIZE_TO_PAGES (AllocationSize);
|
|
|
|
//
|
|
// Look up the free memory region from the beginning of the memory table
|
|
// until the StartCursorOffset
|
|
//
|
|
for (Index = 0; Index < (StartPageIndex - ReqPages); ) {
|
|
//
|
|
// Check Consecutive ReqPages Pages.
|
|
//
|
|
for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) {
|
|
if ((PageTable->Pages[SubIndex + Index].PageFlag & PAGE_USED) != 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SubIndex == ReqPages) {
|
|
//
|
|
// Succeed! Return the Starting Offset.
|
|
//
|
|
return PAGES_TO_SIZE (Index);
|
|
}
|
|
|
|
//
|
|
// Failed! Skip current adjacent Used pages
|
|
//
|
|
while ((SubIndex < (StartPageIndex - ReqPages)) &&
|
|
((PageTable->Pages[SubIndex + Index].PageFlag & PAGE_USED) != 0)) {
|
|
SubIndex++;
|
|
}
|
|
|
|
Index += SubIndex;
|
|
}
|
|
|
|
//
|
|
// Look up the free memory region with in current memory map table.
|
|
//
|
|
for (Index = StartPageIndex; Index <= (PageTable->PageCount - ReqPages); ) {
|
|
//
|
|
// Check consecutive ReqPages pages.
|
|
//
|
|
for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) {
|
|
if ((PageTable->Pages[SubIndex + Index].PageFlag & PAGE_USED) != 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SubIndex == ReqPages) {
|
|
//
|
|
// Succeed! Return the Starting Offset.
|
|
//
|
|
return PAGES_TO_SIZE (Index);
|
|
}
|
|
|
|
//
|
|
// Failed! Skip current free memory pages and adjacent Used pages
|
|
//
|
|
while ((PageTable->Pages[SubIndex + Index].PageFlag & PAGE_USED) != 0) {
|
|
SubIndex++;
|
|
}
|
|
|
|
Index += SubIndex;
|
|
}
|
|
|
|
//
|
|
// No availabe region for object allocation!
|
|
//
|
|
return (UINTN)(-1);
|
|
}
|
|
|
|
|
|
/**
|
|
Allocates a buffer at runtime phase.
|
|
|
|
@param[in] AllocationSize Bytes to be allocated.
|
|
|
|
@return A pointer to the allocated buffer or NULL if allocation fails.
|
|
|
|
**/
|
|
VOID *
|
|
AllocateBuffer (
|
|
IN UINTN AllocationSize
|
|
)
|
|
{
|
|
UINT8 *AllocPtr;
|
|
UINTN ReqPages;
|
|
UINTN Index;
|
|
UINTN StartPage;
|
|
UINTN AllocOffset;
|
|
MEMORY_PAGE_TABLE *PageTable;
|
|
|
|
PageTable = mMemoryBuffer;
|
|
|
|
if (mSmst2 != NULL) {
|
|
AllocPtr = AllocateRuntimeZeroPool(AllocationSize);
|
|
|
|
return AllocPtr;
|
|
}
|
|
|
|
AllocPtr = NULL;
|
|
ReqPages = 0;
|
|
|
|
//
|
|
// Look for available consecutive memory region starting from LastEmptyPageOffset.
|
|
// If no proper memory region found, look up from the beginning.
|
|
// If still not found, return NULL to indicate failed allocation.
|
|
//
|
|
AllocOffset = LookupFreeMemRegion (AllocationSize);
|
|
if (AllocOffset == (UINTN)(-1)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Allocates consecutive memory pages with length of Size. Update the page
|
|
// table status. Returns the starting address.
|
|
//
|
|
ReqPages = SIZE_TO_PAGES (AllocationSize);
|
|
AllocPtr = PageTable->DataAreaBase + AllocOffset;
|
|
StartPage = SIZE_TO_PAGES (AllocOffset);
|
|
Index = 0;
|
|
while (Index < ReqPages) {
|
|
PageTable->Pages[StartPage + Index].PageFlag |= PAGE_USED;
|
|
PageTable->Pages[StartPage + Index].StartPageOffset = AllocOffset;
|
|
|
|
Index++;
|
|
}
|
|
|
|
PageTable->LastEmptyPageOffset = AllocOffset + PAGES_TO_SIZE (ReqPages);
|
|
|
|
ZeroMem (AllocPtr, AllocationSize);
|
|
//
|
|
// Returns a void pointer to the allocated space
|
|
//
|
|
return AllocPtr;
|
|
}
|
|
|
|
|
|
/**
|
|
Frees a buffer that was previously allocated at runtime phase.
|
|
|
|
@param[in] Buffer Pointer to the buffer to free.
|
|
|
|
**/
|
|
VOID
|
|
FreeBuffer (
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
UINTN StartOffset;
|
|
UINTN StartPageIndex;
|
|
MEMORY_PAGE_TABLE *PageTable;
|
|
|
|
PageTable = mMemoryBuffer;
|
|
|
|
if (mSmst2 != NULL) {
|
|
FreePool (Buffer);
|
|
return;
|
|
}
|
|
|
|
StartOffset = (UINTN) ((UINT8 *)Buffer - PageTable->DataAreaBase);
|
|
StartPageIndex = SIZE_TO_PAGES (PageTable->Pages[SIZE_TO_PAGES(StartOffset)].StartPageOffset);
|
|
|
|
while (StartPageIndex < PageTable->PageCount) {
|
|
if (((PageTable->Pages[StartPageIndex].PageFlag & PAGE_USED) != 0) &&
|
|
(PageTable->Pages[StartPageIndex].StartPageOffset == StartOffset)) {
|
|
//
|
|
// Free this page
|
|
//
|
|
PageTable->Pages[StartPageIndex].PageFlag &= ~PAGE_USED;
|
|
PageTable->Pages[StartPageIndex].PageFlag |= PAGE_FREE;
|
|
PageTable->Pages[StartPageIndex].StartPageOffset = 0;
|
|
|
|
StartPageIndex++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Creates a new copy of an existing device path.
|
|
|
|
This function allocates space for a new copy of the device path specified by DevicePath.
|
|
If DevicePath is NULL, then NULL is returned. If the memory is successfully
|
|
allocated, then the contents of DevicePath are copied to the newly allocated
|
|
buffer, and a pointer to that buffer is returned. Otherwise, NULL is returned.
|
|
The memory for the new device path is allocated from EFI boot services memory.
|
|
It is the responsibility of the caller to free the memory allocated.
|
|
|
|
@param[in] DevicePath A pointer to a device path data structure.
|
|
|
|
@retval NULL DevicePath is NULL or invalid.
|
|
@retval Others A pointer to the duplicated device path.
|
|
|
|
**/
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
HddPasswordDuplicateDevicePath (
|
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
UINTN Size;
|
|
VOID *Memory;
|
|
|
|
//
|
|
// Compute the size
|
|
//
|
|
Size = GetDevicePathSize (DevicePath);
|
|
if (Size == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Allocate space for duplicate device path
|
|
//
|
|
Memory = AllocateBuffer ((UINTN)Size);
|
|
if (Memory == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
return (EFI_DEVICE_PATH_PROTOCOL*)CopyMem (Memory, DevicePath, Size);
|
|
}
|
|
|
|
/**
|
|
Initialize the communicate buffer using DataSize and Function.
|
|
|
|
@param[out] DataPtr Points to the data in the communicate buffer.
|
|
@param[in] DataSize The data size to send to SMM.
|
|
@param[in] Function The function number to initialize the communicate header.
|
|
|
|
@retval The communicate buffer. Caller should free it after use.
|
|
|
|
**/
|
|
VOID *
|
|
InitCommunicateBuffer (
|
|
OUT VOID **DataPtr OPTIONAL,
|
|
IN UINTN DataSize,
|
|
IN UINTN Function
|
|
)
|
|
{
|
|
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
|
|
HDD_PASSWORD_SMM_PARAMETER_HEADER *SmmFunctionHeader;
|
|
VOID *Buffer;
|
|
UINTN BufferSize;
|
|
|
|
Buffer = NULL;
|
|
BufferSize = SMM_COMMUNICATE_HEADER_SIZE + OFFSET_OF (HDD_PASSWORD_SMM_PARAMETER_HEADER, Data) + DataSize;
|
|
Buffer = AllocateBuffer ((UINTN)BufferSize);
|
|
if (Buffer == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)Buffer;
|
|
CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiHddPasswordServiceProtocolGuid);
|
|
SmmCommunicateHeader->MessageLength = OFFSET_OF (HDD_PASSWORD_SMM_PARAMETER_HEADER, Data) + DataSize;
|
|
|
|
SmmFunctionHeader = (HDD_PASSWORD_SMM_PARAMETER_HEADER *) SmmCommunicateHeader->Data;
|
|
|
|
//
|
|
// For security check in SMM
|
|
//
|
|
mMemoryBuffer->CommBuffPtr = SmmFunctionHeader;
|
|
ZeroMem (SmmFunctionHeader, SmmCommunicateHeader->MessageLength);
|
|
SmmFunctionHeader->Function = Function;
|
|
SmmFunctionHeader->ReturnStatus = 0;
|
|
if (DataPtr != NULL) {
|
|
*DataPtr = SmmFunctionHeader->Data;
|
|
}
|
|
|
|
return Buffer;
|
|
}
|
|
|
|
/**
|
|
According Bus, Device, Function, PrimarySecondary, SlaveMaster to get corresponding
|
|
SATA port number
|
|
|
|
@param[in] Bus PCI bus number
|
|
@param[in] Device PCI device number
|
|
@param[in] Function PCI function number
|
|
@param[in] PrimarySecondary primary or scondary
|
|
@param[in] SlaveMaster slave or master
|
|
@param[out] PortNum output port number
|
|
|
|
@retval EFI_SUCCESS Get corresponding port number successfully
|
|
@retval EFI_NOT_FOUND Can't get corresponding port number
|
|
**/
|
|
EFI_STATUS
|
|
ChangeChannelDevice2PortNum (
|
|
IN UINT32 Bus,
|
|
IN UINT32 Device,
|
|
IN UINT32 Function,
|
|
IN UINT8 PrimarySecondary,
|
|
IN UINT8 SlaveMaster,
|
|
OUT UINTN *PortNum
|
|
)
|
|
{
|
|
UINTN Index;
|
|
PORT_NUMBER_MAP *PortMappingTable;
|
|
PORT_NUMBER_MAP EndEntry;
|
|
UINTN NoPorts;
|
|
|
|
if (PortNum == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
NoPorts = 0;
|
|
PortMappingTable = NULL;
|
|
|
|
ZeroMem (&EndEntry, sizeof (PORT_NUMBER_MAP));
|
|
|
|
PortMappingTable = (PORT_NUMBER_MAP *)PcdGetPtr (PcdPortNumberMapTable);
|
|
|
|
while (CompareMem (&EndEntry, &PortMappingTable[NoPorts], sizeof (PORT_NUMBER_MAP)) != 0) {
|
|
NoPorts++;
|
|
}
|
|
|
|
if (NoPorts == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
for (Index = 0; Index < NoPorts; Index++) {
|
|
if ((PortMappingTable[Index].Bus == Bus) &&
|
|
(PortMappingTable[Index].Device == Device) &&
|
|
(PortMappingTable[Index].Function == Function) &&
|
|
(PortMappingTable[Index].PrimarySecondary == PrimarySecondary) &&
|
|
(PortMappingTable[Index].SlaveMaster == SlaveMaster)) {
|
|
*PortNum = PortMappingTable[Index].PortNum;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
According the Bus, Device, Function to check this controller is in Port Number Map table or not.
|
|
If yes, then this is a on board PCI device.
|
|
|
|
@param[in] Bus PCI bus number
|
|
@param[in] Device PCI device number
|
|
@param[in] Function PCI function number
|
|
|
|
@retval TRUE Is on board device
|
|
@retval FALSE Not on board device
|
|
**/
|
|
BOOLEAN
|
|
IsOnBoardPciDevice (
|
|
IN UINT32 Bus,
|
|
IN UINT32 Device,
|
|
IN UINT32 Function
|
|
)
|
|
{
|
|
UINTN Index;
|
|
PORT_NUMBER_MAP *PortMappingTable;
|
|
PORT_NUMBER_MAP EndEntry;
|
|
UINTN NumOfPorts;
|
|
|
|
PortMappingTable = NULL;
|
|
|
|
ZeroMem (&EndEntry, sizeof (PORT_NUMBER_MAP));
|
|
|
|
PortMappingTable = (PORT_NUMBER_MAP *)PcdGetPtr (PcdPortNumberMapTable);
|
|
|
|
NumOfPorts = 0;
|
|
while (CompareMem (&EndEntry, &PortMappingTable[NumOfPorts], sizeof (PORT_NUMBER_MAP)) != 0) {
|
|
NumOfPorts++;
|
|
}
|
|
|
|
if (NumOfPorts == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (Index = 0; Index < NumOfPorts; Index++) {
|
|
if ((PortMappingTable[Index].Bus == Bus) &&
|
|
(PortMappingTable[Index].Device == Device) &&
|
|
(PortMappingTable[Index].Function == Function)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Get memory space from allocated reserved pages.
|
|
This function is ONLY used in Hdd Password driver due to not allocated more memory when not enough.
|
|
|
|
@param[in] AllocSize how many size to be allocated
|
|
@param[out] AllocAddr where to be allocated
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
GetMem (
|
|
IN UINTN RequestSize,
|
|
OUT VOID **AllocAddr
|
|
)
|
|
{
|
|
if (AllocAddr == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (mHddPasswordPrivate->MemRecord->RemainSize == 0 ||
|
|
mHddPasswordPrivate->MemRecord->RemainSize < RequestSize) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
*AllocAddr = *(VOID **)&(mHddPasswordPrivate->MemRecord->RemainMemAddr);
|
|
|
|
mHddPasswordPrivate->MemRecord->RemainMemAddr += ALIGN_SIZEOF_UINTN (RequestSize);
|
|
mHddPasswordPrivate->MemRecord->RemainSize -= ALIGN_SIZEOF_UINTN (RequestSize);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Copy SourceBufferPtr string to DescBufferPtr.
|
|
|
|
@param[in] DescBufferPtr Destination buffer address.
|
|
@param[in] SourceBufferPtr Source buffer addess.
|
|
|
|
@retval EFI_SUCCESS
|
|
**/
|
|
EFI_STATUS
|
|
GetModelNumber (
|
|
IN VOID *DescBufferPtr,
|
|
IN VOID *SourceBufferPtr
|
|
)
|
|
{
|
|
UINT8 *IdentifyPtr;
|
|
UINT16 *HddInfoPtr;
|
|
UINT16 Index;
|
|
UINT32 *SwapPtr;
|
|
UINTN DwordConunt;
|
|
|
|
IdentifyPtr = SourceBufferPtr;
|
|
HddInfoPtr = DescBufferPtr;
|
|
SwapPtr = DescBufferPtr;
|
|
|
|
for (Index = 0; Index < MODEL_NUMBER_LENGTH; Index++) {
|
|
HddInfoPtr[Index] = (UINT16) (IdentifyPtr[Index] & 0x0ff);
|
|
}
|
|
|
|
//
|
|
// MAX_SUPPORT_SERIAL_NUM_COUNT is Serial Count.
|
|
// It's unit is CHAR16.
|
|
//
|
|
DwordConunt = MODEL_NUMBER_LENGTH >> 1;
|
|
for (Index = 0; Index < DwordConunt; Index++) {
|
|
SwapPtr[Index] = (UINT32) (((SwapPtr[Index] & 0xffff0000) >> 16) + \
|
|
((SwapPtr[Index] & 0x0000ffff) << 16));
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
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)) {
|
|
DEBUG_CODE_BEGIN ();
|
|
switch(Index) {
|
|
case 0:
|
|
DEBUG ((EFI_D_INFO, " DelayUefiRaid driver found\n"));
|
|
break;
|
|
|
|
case 1:
|
|
DEBUG ((EFI_D_INFO, " SataController driver for INTEL found\n"));
|
|
break;
|
|
|
|
case 2:
|
|
DEBUG ((EFI_D_INFO, " SataController driver for AMD found\n"));
|
|
break;
|
|
|
|
case 3:
|
|
DEBUG ((EFI_D_INFO, " AhciBusDxe driver found\n"));
|
|
break;
|
|
|
|
case 4:
|
|
DEBUG ((EFI_D_INFO, " NVMExpressDxe driver found\n"));
|
|
break;
|
|
|
|
case 5:
|
|
DEBUG ((EFI_D_INFO, " SDHostDxe driver found\n"));
|
|
break;
|
|
|
|
case 6:
|
|
DEBUG ((EFI_D_INFO, " StorageSecurityCommandProtocolDxe driver found\n"));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
DEBUG_CODE_END ();
|
|
|
|
//
|
|
// store found Agent handles to FoundAgentHandleList in the same order as
|
|
// mAgentFileGuidList defined.
|
|
//
|
|
FoundAgentHandleList[Index1] = DriverBinding->ImageHandle;
|
|
Index1++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FoundAgentHandleList;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Find controller handle that satisfy class code listed in .
|
|
|
|
@retval EFI_SUCCESS Connect SATA controller successfully.
|
|
@retval Other Connect SATA controller failed.
|
|
**/
|
|
BOOLEAN
|
|
SpecificControllerFound (
|
|
UINT8 *ClassCode
|
|
)
|
|
{
|
|
UINT8 EntryCount;
|
|
UINT8 Index;
|
|
|
|
EntryCount = (sizeof(mClassCodeList) / sizeof(CONTROLER_CLASS_CODE_LIST));
|
|
for (Index = 0; Index < EntryCount; Index++) {
|
|
if ((ClassCode[2] == mClassCodeList[Index].BaseClassCode &&
|
|
ClassCode[1] == mClassCodeList[Index].SubClassCode)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
Connect all Storage controller.
|
|
|
|
@retval EFI_SUCCESS Connect SATA controller successfully.
|
|
@retval Other Connect SATA controller failed.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CollectStorageController (
|
|
IN BOOLEAN NeedConnectController
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN PciIoHandleCount;
|
|
EFI_HANDLE *PciIoHandleBuffer;
|
|
UINTN PciIoHandleIndex;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINTN Device;
|
|
UINTN Seg;
|
|
UINTN Bus;
|
|
UINTN Function;
|
|
UINT8 PCIClassCReg[3];
|
|
ATA_CONTROLLER_INFO *AtaControllerInfo;
|
|
DRIVER_INSTALL_INFO *DriverInstallInfo;
|
|
EFI_HANDLE *AgentHandleBuffer;
|
|
LIST_ENTRY *AtaControllerInfoListHead;
|
|
LIST_ENTRY *Link;
|
|
|
|
PciIoHandleCount = 0;
|
|
PciIoHandleBuffer = NULL;
|
|
AgentHandleBuffer = NULL;
|
|
AtaControllerInfo = NULL;
|
|
AgentHandleBuffer = FindAgentHandleListByFileGUID(mAgentFileGuidList, sizeof(mAgentFileGuidList)/sizeof(AGENT_FILE_GUID_LIST));
|
|
if (AgentHandleBuffer == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
DriverInstallInfo = mDriverInstallInfo;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciIoProtocolGuid,
|
|
NULL,
|
|
&PciIoHandleCount,
|
|
&PciIoHandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
|
|
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) {
|
|
continue;
|
|
}
|
|
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
PCI_CLASSCODE_OFFSET,
|
|
3,
|
|
PCIClassCReg
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
if (!SpecificControllerFound(PCIClassCReg) || !NeedConnectController) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// don't need to connect again when controllers are being reconnected
|
|
//
|
|
if (!mHddPasswordPrivate->ControllerReconnected) {
|
|
Status = gBS->ConnectController (
|
|
PciIoHandleBuffer[PciIoHandleIndex],
|
|
AgentHandleBuffer,
|
|
NULL,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
if ((FindMappedController(Seg, Bus, Device, Function) != INVALID_CONTROLLER_INDEX_NUMBER) || (EFI_ERROR(Status))) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// only update AtaControllerInfo when reconnect
|
|
//
|
|
if (mHddPasswordPrivate->ControllerReconnected) {
|
|
AtaControllerInfoListHead = &DriverInstallInfo->AtaControllerInfoListHead;
|
|
for (Link = GetFirstNode (AtaControllerInfoListHead);
|
|
!IsNull (AtaControllerInfoListHead, Link) ;
|
|
Link = GetNextNode (AtaControllerInfoListHead, Link)) {
|
|
AtaControllerInfo = (ATA_CONTROLLER_INFO *)Link;
|
|
if (AtaControllerInfo->PciSeg == Seg &&
|
|
AtaControllerInfo->PciBus == Bus &&
|
|
AtaControllerInfo->PciDevice == Device &&
|
|
AtaControllerInfo->PciFunction == Function) {
|
|
AtaControllerInfo->AtaControllerHandle = PciIoHandleBuffer[PciIoHandleIndex];
|
|
AtaControllerInfo->AtaMode = PCIClassCReg[1];
|
|
AtaControllerInfo->BaseCode = PCIClassCReg[2];
|
|
AtaControllerInfo->SubClassCode = PCIClassCReg[1];
|
|
AtaControllerInfo->PI = PCIClassCReg[0];
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// when controller reconnect, don't need to collect AtaControllerInfo again
|
|
//
|
|
continue;
|
|
}
|
|
|
|
AtaControllerInfo = NULL;
|
|
|
|
AtaControllerInfo = AllocateZeroPool(sizeof (ATA_CONTROLLER_INFO));
|
|
|
|
if (AtaControllerInfo != NULL) {
|
|
AtaControllerInfo->AtaControllerHandle = PciIoHandleBuffer[PciIoHandleIndex];
|
|
AtaControllerInfo->AtaMode = PCIClassCReg[1];
|
|
AtaControllerInfo->PciSeg = Seg;
|
|
AtaControllerInfo->PciBus = Bus;
|
|
AtaControllerInfo->PciDevice = Device;
|
|
AtaControllerInfo->PciFunction = Function;
|
|
AtaControllerInfo->BaseCode = PCIClassCReg[2];
|
|
AtaControllerInfo->SubClassCode = PCIClassCReg[1];
|
|
AtaControllerInfo->PI = PCIClassCReg[0];
|
|
|
|
InsertTailList (
|
|
&DriverInstallInfo->AtaControllerInfoListHead,
|
|
&AtaControllerInfo->Link
|
|
);
|
|
|
|
DriverInstallInfo->NumOfController++;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
DriverInstallInfo->AtaControllerSearched = TRUE;
|
|
|
|
if (AgentHandleBuffer != NULL) {
|
|
FreePool (AgentHandleBuffer);
|
|
}
|
|
|
|
if (PciIoHandleBuffer != NULL) {
|
|
FreePool (PciIoHandleBuffer);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Find mapped controller.
|
|
|
|
@retval Others found.
|
|
@retval 0xFFFF not found.
|
|
**/
|
|
UINT16
|
|
EFIAPI
|
|
FindMappedController (
|
|
IN UINTN Seg,
|
|
IN UINTN Bus,
|
|
IN UINTN Device,
|
|
IN UINTN Function
|
|
)
|
|
{
|
|
ATA_CONTROLLER_INFO *AtaControllerInfo;
|
|
DRIVER_INSTALL_INFO *DriverInstallInfo;
|
|
UINT16 ControllerIndex;
|
|
LIST_ENTRY *AtaControllerInfoListHead;
|
|
LIST_ENTRY *Link;
|
|
|
|
DriverInstallInfo = mDriverInstallInfo;
|
|
|
|
AtaControllerInfoListHead = &DriverInstallInfo->AtaControllerInfoListHead;
|
|
for (Link = GetFirstNode (AtaControllerInfoListHead), ControllerIndex = CONTROLLER_INDEX_START;
|
|
!IsNull (AtaControllerInfoListHead, Link) && ControllerIndex <= DriverInstallInfo->NumOfController;
|
|
Link = GetNextNode (AtaControllerInfoListHead, Link), ControllerIndex++) {
|
|
AtaControllerInfo = (ATA_CONTROLLER_INFO *)Link;
|
|
if (AtaControllerInfo->PciSeg == Seg &&
|
|
AtaControllerInfo->PciBus == Bus &&
|
|
AtaControllerInfo->PciDevice == Device &&
|
|
AtaControllerInfo->PciFunction == Function) {
|
|
return ControllerIndex;
|
|
}
|
|
|
|
}
|
|
|
|
return INVALID_CONTROLLER_INDEX_NUMBER;
|
|
}
|
|
|
|
/**
|
|
Check whether the EFI_COMPONENT_NAME_PROTOCOL instance is valid for use.
|
|
|
|
@param[in] ComponentName A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance
|
|
@param[in] Handle The handle of Block IO device
|
|
|
|
@retval TRUE The protocol is valid
|
|
@retval FALSE The protocol is invalid
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsValidComponentNameProtocol (
|
|
IN EFI_COMPONENT_NAME_PROTOCOL *ComponentName,
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR16 *String1;
|
|
CHAR16 *String2;
|
|
|
|
//
|
|
// Some incomplete ComponentName protocols return success regardless of invalid inputs, which brings the wrong device name received.
|
|
// Try the cases that gives illegal inputs to filter these incomplete ComponentName protocol.
|
|
//
|
|
// Give illegal inputs (ControllerHandle = NULL)
|
|
//
|
|
Status = ComponentName->GetControllerName (
|
|
ComponentName,
|
|
NULL,
|
|
Handle,
|
|
ComponentName->SupportedLanguages,
|
|
&String1
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Give illegal inputs (ControllerHandle = NULL, ChildHandle = NULL)
|
|
//
|
|
Status = ComponentName->GetControllerName (
|
|
ComponentName,
|
|
NULL,
|
|
NULL,
|
|
ComponentName->SupportedLanguages,
|
|
&String2
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// The protocol that return a fixed data in the above cases is considered invalid
|
|
//
|
|
return (CompareMem (String1, String2, StrLen (String1)) != 0);
|
|
}
|
|
|
|
|