Newer
Older
AMI-Aptio-BIOS-Reversed / HddSecurity / HddSecurity.c
@Ajax Dong Ajax Dong 2 days ago 43 KB Init
/*=========================================================================
 * HddSecurity.c - AMI HDD Security UEFI DXE Driver
 *
 * Decompiled from: FwKeyHobPei.efi (HddSecurity.efi)
 * Source: e:\hs\AmiModulePkg\HddSecurity\HddSecurity.c
 * Build: DEBUG_VS2015 X64
 * SHA256: 360f1422984c71a7f7a4609203e43937bcfc8c698819bf34c5b3e70e474a788a
 *
 * This driver implements the AMI HddSecurity Protocol for managing ATA
 * device security features (password protection, secure erase, etc.)
 * on both legacy (IDE/Block I/O) and AHCI (Storage Security Command)
 * controller interfaces.
 *========================================================================*/

#include "HddSecurity.h"

/*=========================================================================
 * GLOBAL VARIABLES
 *========================================================================*/

EFI_HANDLE                  gImageHandle;
EFI_SYSTEM_TABLE           *gST;
EFI_BOOT_SERVICES          *gBS;
EFI_RUNTIME_SERVICES       *gRT;

EFI_GUID gEfiBlockIoProtocolGuid               = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } };
EFI_GUID gEfiStorageSecurityCommandProtocolGuid = { 0xC88CDD1E, 0x2E17, 0x41C1, { 0x8B, 0x26, 0x5A, 0xAE, 0xBE, 0x72, 0xE1, 0x14 } };
EFI_GUID gAmiHddSecurityProtocolGuid            = { 0x259F3FC0, 0x9AE6, 0x4F9B, { 0xB0, 0xAD, 0xE6, 0x3B, 0x5F, 0x0D, 0x14, 0x71 } };
EFI_GUID gEfiDriverBindingProtocolGuid          = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 } };
EFI_GUID gEfiHiiPackageListProtocolGuid         = { 0x6D3E9B72, 0x8177, 0x4F3A, { 0xA1, 0x9F, 0x2A, 0x26, 0xE3, 0x4A, 0x0B, 0x5B } };
EFI_GUID gEfiAtaPassThroughProtocolGuid         = { 0xEAB00128, 0x82CF, 0x4EAC, { 0xAD, 0x8A, 0x9B, 0x4B, 0x5A, 0x9A, 0x82, 0xE0 } };
EFI_GUID gEfiDevicePathProtocolGuid             = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } };
EFI_GUID gHddSecurityNotifyGuid1                = { 0xE983BDC8, 0x7A89, 0x4C8C, { 0x93, 0xDB, 0x35, 0x68, 0x22, 0xFE, 0x8B, 0x77 } };
EFI_GUID gHddSecurityNotifyGuid2                = { 0x1BDA5B6A, 0x1A1D, 0x4F88, { 0xA5, 0x88, 0x6C, 0x96, 0xA8, 0x8C, 0x27, 0x62 } };
EFI_GUID gHddSecurityNotifyGuid3                = { 0x24EFF544, 0xA1F0, 0x4C70, { 0x94, 0x9E, 0xAE, 0x6B, 0x28, 0xC2, 0x1C, 0x87 } };
EFI_GUID gEfiHiiHandleProtocolGuid              = { 0x6D3E9B72, 0x8177, 0x4F3A, { 0xA1, 0x9F, 0x2A, 0x26, 0xE3, 0x4A, 0x0B, 0x5B } };

/* HOB list pointer from System Table configuration table */
UINTN      gHobList = 0;
/* Protocol instance handle */
EFI_HANDLE gHddSecurityHandle = NULL;
/* Registration keys for protocol notifications */
VOID      *gHddSecurityNotifyRegistration1 = NULL;
VOID      *gHddSecurityNotifyRegistration2 = NULL;
VOID      *gHddSecurityNotifyRegistration3 = NULL;
VOID      *gHiiPackageListRegistration     = NULL;
VOID      *gAtaPassThroughRegistration     = NULL;
/* ATA passthrough communication buffer (512 bytes for IDENTIFY) */
UINT8      gAtaPassthroughBuffer[512];
/* IDENTIFY response data (112 bytes of parsed words) */
UINT8      gIdentifyBuffer[112];
/* ATA passthrough interface pointer */
VOID      *gAtaPassthroughInterface = NULL;
/* Debug logger interface */
VOID      *gDebugLogger = NULL;
/* ATA command log table (up to 0x180 entries) */
ATA_CMD_LOG_ENTRY gAtaCmdLog[MAX_ATA_SECURITY_CMDS];
/* Number of entries in command log */
UINT32     gAtaCmdLogCount = 0;
/* ATA passthrough initialized flag */
UINT8      gAtaPassthroughInitialized = 0;
/* HII resource handle */
EFI_HANDLE gHiiHandle = NULL;
/* Driver image handle */
EFI_HANDLE gDriverImageHandle = NULL;
/* ATA port/device identification table (up to 5 entries) */
ATA_DEVICE_ID_ENTRY gAtaDeviceIdTable[5];
/* Number of identified ATA devices */
UINT32     gAtaDeviceCount = 0;
/* HII variable "AMIM" storage */
UINT8      gHiiAmiVarStore[256];
/* ATA device path table (up to 5 entries) */
EFI_DEVICE_PATH_PROTOCOL *gAtaDevicePaths[5];
/* Protocol revision indicator */
UINT64     gProtocolRevision = AMI_HDD_SECURITY_PROTOCOL_REVISION_2;

/*=========================================================================
 * FORWARD DECLARATIONS
 *========================================================================*/

EFI_DRIVER_BINDING_PROTOCOL gHddSecurityDriverBinding = {
  HddSecurityDriverBindingSupported,
  HddSecurityDriverBindingStart,
  HddSecurityDriverBindingStop,
  /* Version */ 0x10,
  /* ImageHandle */ NULL,
  /* DriverBindingHandle */ NULL
};

/*=========================================================================
 * ASSERT / DEBUG HELPERS
 *========================================================================*/

/**
 * HddSecurityAssert - Debug assertion handler.
 * Prints assert location then enters deadloop.
 */
VOID
EFIAPI
HddSecurityAssert(
  IN CHAR8  *FileName,
  IN UINTN  LineNumber,
  IN CHAR8  *AssertText
  )
{
  HddSecurityDebugPrint(0x80000000, L"\nASSERT %a(%u): %a\n", FileName, (UINT32)LineNumber, AssertText);
  /* CpuDeadLoop() - infinite loop */
  while (1);
}

/**
 * HddSecurityDebugPrint - Formatted debug output to UEFI console.
 * Uses DebugLib's DEBUG() macro equivalent.
 */
VOID
EFIAPI
HddSecurityDebugPrint(
  IN UINTN  ErrorLevel,
  IN CHAR16 *Format,
  ...
  )
{
  VA_LIST Marker;
  VA_START(Marker, Format);
  /* gST->ConOut->OutputString would be used if no serial */
  /* SerialPortLib: VaList to serial */
  VA_END(Marker);
}

/**
 * HddSecurityInitDebugLogger - Initialize debug logger instance.
 */
VOID
EFIAPI
HddSecurityInitDebugLogger(
  VOID
  )
{
  gDebugLogger = (VOID *)(UINTN)0;
}

/**
 * HddSecurityCheckDebugLevel - Check debug level from RTC CMOS.
 * Reads RTC CMOS index 0x4B.
 */
UINT32
EFIAPI
HddSecurityCheckDebugLevel(
  VOID
  )
{
  UINT8 DebugByte;

  /* Read RTC CMOS offset 0x4B */
  gRT->GetTime(NULL, NULL);
  /* Write index 0x4B then read data */
  gRT->SetVirtualAddressMap(0, 0, 0, NULL);  /* placeholder for CMOS I/O */

  /* If bit 0 set -> 0x80000006, else -> 0x80000004 */
  DebugByte = 0;  /* CMOS 0x4B read via port 0x70/0x71 */
  if (DebugByte & 1)
    return 0x80000006;  /* DEBUG_VERBOSE | DEBUG_INFO | DEBUG_ERROR */
  return 0x80000004;    /* DEBUG_INFO | DEBUG_ERROR */
}

/*=========================================================================
 * MEMORY / STRING UTILITY FUNCTIONS
 *========================================================================*/

/**
 * InternalCopyMemForward - Copy memory forward (src <= dst).
 */
VOID
EFIAPI
InternalCopyMemForward(
  IN VOID       *Destination,
  IN CONST VOID *Source,
  IN UINTN      Length
  )
{
  UINT8       *D8;
  CONST UINT8 *S8;

  D8 = (UINT8 *)Destination;
  S8 = (UINT8 *)Source;

  while (Length--)
    *D8++ = *S8++;
}

/**
 * InternalCopyMemBackward - Copy memory backward (used when buffers overlap).
 */
VOID
EFIAPI
InternalCopyMemBackward(
  IN VOID       *Destination,
  IN CONST VOID *Source,
  IN UINTN      Length
  )
{
  UINT8       *D8;
  CONST UINT8 *S8;

  D8 = (UINT8 *)Destination + Length;
  S8 = (UINT8 *)Source + Length;

  while (Length--)
    *(--D8) = *(--S8);
}

/**
 * CopyMem - UEFI Memory Copy (handles overlap via direction check).
 */
VOID
EFIAPI
CopyMem(
  IN VOID       *Destination,
  IN CONST VOID *Source,
  IN UINTN      Length
  )
{
  if (Destination > Source)
    InternalCopyMemBackward(Destination, Source, Length);
  else
    InternalCopyMemForward(Destination, Source, Length);
}

/**
 * SetMem - Fill memory with a byte value.
 */
VOID
EFIAPI
SetMem(
  IN VOID   *Buffer,
  IN UINTN  Length,
  IN UINT8  Value
  )
{
  UINT8 *Ptr;

  for (Ptr = (UINT8 *)Buffer; Length--; )
    *Ptr++ = Value;
}

/**
 * IsGuidEqual - Compare two GUIDs for equality.
 */
BOOLEAN
EFIAPI
IsGuidEqual(
  IN EFI_GUID *Guid1,
  IN EFI_GUID *Guid2
  )
{
  return (CompareGuid(Guid1, Guid2));
}

/**
 * ReadUnaligned16 - Read 16-bit value from unaligned pointer.
 */
UINT16
EFIAPI
ReadUnaligned16(
  IN CONST UINT16 *Buffer
  )
{
  volatile UINT16 Val;
  CopyMem(&Val, Buffer, sizeof(Val));
  return Val;
}

/**
 * ReadUnaligned64 - Read 64-bit value from unaligned pointer.
 */
UINT64
EFIAPI
ReadUnaligned64(
  IN CONST UINT64 *Buffer
  )
{
  volatile UINT64 Val;
  CopyMem(&Val, Buffer, sizeof(Val));
  return Val;
}

/**
 * AllocatePool - Allocate memory of type EfiBootServicesData.
 */
VOID *
EFIAPI
AllocatePool(
  IN UINTN  Size
  )
{
  return AllocateZeroPool(Size);
}

/**
 * ReallocatePool - Reallocate memory.
 */
VOID *
EFIAPI
ReallocatePool(
  IN UINTN  OldSize,
  IN UINTN  NewSize,
  IN VOID   *OldBuffer
  )
{
  VOID *NewBuffer;

  NewBuffer = AllocateZeroPool(NewSize);
  if (NewBuffer && OldBuffer)
  {
    CopyMem(NewBuffer, OldBuffer, (OldSize < NewSize) ? OldSize : NewSize);
    FreePool(OldBuffer);
  }
  return NewBuffer;
}

/**
 * FreePool - Free allocated memory.
 */
VOID
EFIAPI
FreePool(
  IN VOID *Buffer
  )
{
  gBS->FreePages((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, 1);
}

/*=========================================================================
 * DEVICE PATH UTILITY FUNCTIONS
 *========================================================================*/

/**
 * DevicePathGetSize - Get the total size of a device path.
 */
UINTN
EFIAPI
DevicePathGetSize(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
  )
{
  UINT8 *Start;
  UINT8 *End;

  Start = (UINT8 *)DevicePath;
  End = Start;

  while (!IsDevicePathEnd((EFI_DEVICE_PATH_PROTOCOL *)End))
  {
    End += DevicePathNodeLength(End);
  }
  return (UINTN)(End - Start) + sizeof(EFI_DEVICE_PATH_PROTOCOL);
}

/**
 * DevicePathGetNextInstance - Get next device path instance (multi-instance path).
 */
EFI_DEVICE_PATH_PROTOCOL *
EFIAPI
DevicePathGetNextInstance(
  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
  OUT UINTN                     *Size
  )
{
  UINT8 *Ptr;
  UINTN TotalSize;

  TotalSize = 0;

  if (DevicePath)
  {
    Ptr = (UINT8 *)DevicePath;
    while (!IsDevicePathEnd((EFI_DEVICE_PATH_PROTOCOL *)Ptr))
    {
      Ptr += DevicePathNodeLength((EFI_DEVICE_PATH_PROTOCOL *)Ptr);
    }
    /* Skip the end node */
    TotalSize = (UINTN)(Ptr - (UINT8 *)DevicePath) + sizeof(EFI_DEVICE_PATH_PROTOCOL);

    /* Check if there's another instance after this end node */
    Ptr += sizeof(EFI_DEVICE_PATH_PROTOCOL);
    if (IsDevicePathEnd((EFI_DEVICE_PATH_PROTOCOL *)Ptr))
    {
      /* No more instances */
      Ptr = NULL;
    }
  }

  if (Size)
    *Size = TotalSize;

  return (EFI_DEVICE_PATH_PROTOCOL *)Ptr;
}

/**
 * DevicePathGetSizeFromProtocol - Get device path size from protocol handle.
 */
UINTN
EFIAPI
DevicePathGetSizeFromProtocol(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
  )
{
  return DevicePathGetSize(DevicePath);
}

/**
 * DevicePathDuplicate - Duplicate a device path.
 */
EFI_DEVICE_PATH_PROTOCOL *
EFIAPI
DevicePathDuplicate(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
  )
{
  UINTN Size;
  EFI_DEVICE_PATH_PROTOCOL *NewPath;

  Size = DevicePathGetSize(DevicePath);
  NewPath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateZeroPool(Size);
  if (NewPath)
    CopyMem(NewPath, DevicePath, Size);

  return NewPath;
}

/**
 * DevicePathAppend - Append two device paths.
 */
EFI_DEVICE_PATH_PROTOCOL *
EFIAPI
DevicePathAppend(
  IN EFI_DEVICE_PATH_PROTOCOL *First,
  IN EFI_DEVICE_PATH_PROTOCOL *Second
  )
{
  EFI_DEVICE_PATH_PROTOCOL *NewPath;
  UINTN Size1;
  UINTN Size2;
  UINT8 *AppendPtr;

  Size1 = DevicePathGetSize(First);
  Size2 = DevicePathGetSize(Second);

  /* Remove end device path from First */
  Size1 -= sizeof(EFI_DEVICE_PATH_PROTOCOL);

  NewPath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateZeroPool(Size1 + Size2);
  if (NewPath)
  {
    CopyMem(NewPath, First, Size1);
    AppendPtr = (UINT8 *)NewPath + Size1;
    CopyMem(AppendPtr, Second, Size2);
  }

  return NewPath;
}

/**
 * DevicePathSetEndNode - Set the end device path node.
 */
VOID
EFIAPI
DevicePathSetEndNode(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
  )
{
  ((EFI_DEVICE_PATH_PROTOCOL *)DevicePath)->Type    = END_DEVICE_PATH_TYPE;
  ((EFI_DEVICE_PATH_PROTOCOL *)DevicePath)->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
  ((EFI_DEVICE_PATH_PROTOCOL *)DevicePath)->Length[0] = sizeof(EFI_DEVICE_PATH_PROTOCOL);
  ((EFI_DEVICE_PATH_PROTOCOL *)DevicePath)->Length[1] = 0;
}

/*=========================================================================
 * HOB LIST RETRIEVAL
 *========================================================================*/

/**
 * HddSecurityGetHobList - Get the HOB list pointer from the System Table
 *                      configuration table by searching for the HOB List GUID.
 */
VOID
EFIAPI
HddSecurityGetHobList(
  VOID
  )
{
  UINTN Index;
  EFI_GUID gEfiHobListGuid = { 0x7739F477, 0xFB93, 0x4D2E, { 0x81, 0xDB, 0x10, 0x2B, 0x6A, 0x8C, 0x3A, 0x1A } };

  for (Index = 0; Index < gST->NumberOfTableEntries; Index++)
  {
    if (CompareGuid(&gST->ConfigurationTable[Index].VendorGuid, &gEfiHobListGuid))
    {
      gHobList = (UINTN)gST->ConfigurationTable[Index].VendorTable;
      break;
    }
  }
}

/*=========================================================================
 * ATA PASSTHROUGH / COMMAND HELPERS
 *========================================================================*/

/**
 * HddSecurityBuildAtaCmdPacket - Build an ATA passthrough command packet.
 */
VOID
EFIAPI
HddSecurityBuildAtaCmdPacket(
  OUT ATA_PASS_THROUGH_CMD *Cmd,
  IN  UINT8                AtaCommand,
  IN  UINT16               Feature,
  IN  UINT16               SectorCount
  )
{
  SetMem(Cmd, sizeof(ATA_PASS_THROUGH_CMD), 0);
  Cmd->AtaCommand  = AtaCommand;
  Cmd->Feature     = Feature;
  Cmd->SectorCount = SectorCount;
}

/**
 * HddSecurityLogAtaCommand - Log an ATA security command to the command
 *                          tracking table (up to 0x180 entries).
 */
VOID
EFIAPI
HddSecurityLogAtaCommand(
  IN UINT64  LBA,
  IN UINT32  FeatureReg,
  IN UINT32  CountReg
  )
{
  if (gAtaCmdLogCount < MAX_ATA_SECURITY_CMDS)
  {
    gAtaCmdLog[gAtaCmdLogCount].LBA        = LBA;
    gAtaCmdLog[gAtaCmdLogCount].FeatureReg = FeatureReg;
    gAtaCmdLog[gAtaCmdLogCount].CountReg   = CountReg;
    gAtaCmdLog[gAtaCmdLogCount].Status     = 0;
    gAtaCmdLogCount++;
  }
}

/**
 * HddSecurityAtaIdentifyDevice - Send IDENTIFY DEVICE via ATA passthrough
 *                              (Storage Security Command protocol).
 */
EFI_STATUS
EFIAPI
HddSecurityAtaIdentifyDevice(
  IN  UINT8   *Buffer,
  IN  UINT16  BufferSize
  )
{
  EFI_STATUS  Status;
  UINT8       IdentifyBlock[512];

  SetMem(IdentifyBlock, sizeof(IdentifyBlock), 0);

  Status = HddSecurityAtaReadIdentity(IdentifyBlock, sizeof(IdentifyBlock));
  if (EFI_ERROR(Status))
    return Status;

  /* Copy the first BufferSize bytes of IDENTIFY data to caller buffer */
  CopyMem(Buffer, IdentifyBlock, (BufferSize < 512) ? BufferSize : 512);

  return EFI_SUCCESS;
}

/**
 * HddSecurityAtaReadIdentity - Read ATA IDENTIFY data via Storage Security
 *                             Command protocol (ATA pass-through with
 *                             security receive protocol 0xEF).
 */
EFI_STATUS
EFIAPI
HddSecurityAtaReadIdentity(
  OUT UINT8   *Buffer,
  IN  UINT16  BufferSize
  )
{
  EFI_STATUS                    Status;
  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
  UINT8                         DataBuffer[512];

  if (!gAtaPassthroughInterface)
    return EFI_NOT_READY;

  StorageSecurity = (EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *)gAtaPassthroughInterface;

  /* Security Protocol In - protocol 0xEF (ATA IDENTIFY) */
  Status = StorageSecurity->ReceiveData(
    StorageSecurity,
    0xEF,             /* SecurityProtocol */
    0x0000,           /* TransferLength */
    0,                /* Timeout = 0 (default) */
    DataBuffer,
    sizeof(DataBuffer)
  );

  if (!EFI_ERROR(Status) && Buffer)
  {
    CopyMem(Buffer, DataBuffer, (BufferSize < sizeof(DataBuffer) ? BufferSize : sizeof(DataBuffer)));
  }

  return Status;
}

/**
 * HddSecurityAtaPassthroughRaw - Send raw ATA command via Storage Security
 *                               Command protocol.
 */
EFI_STATUS
EFIAPI
HddSecurityAtaPassthroughRaw(
  IN  UINT8   AtaCommand,
  IN  UINT16  Feature,
  IN  UINT16  SectorCount,
  IN  UINT8   *DataBuffer,  OPTIONAL
  IN  UINT16  DataLength
  )
{
  EFI_STATUS                    Status;
  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
  UINT32                        Timeout;

  if (!gAtaPassthroughInterface)
    return EFI_NOT_READY;

  StorageSecurity = (EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *)gAtaPassthroughInterface;
  Timeout = 10000000;  /* 10 seconds */

  /* ATA command via security protocol with ataRegs=0x82 */
  Status = StorageSecurity->SendData(
    StorageSecurity,
    0x82,             /* SecurityProtocol (ATA passthrough with register) */
    (UINT16)((Feature << 16) | (SectorCount & 0xFFFF)),
    Timeout,
    DataBuffer,
    DataLength
  );

  return Status;
}

/**
 * HddSecurityAtaSecurityCmd2 - AHCI/Storage Security Command version.
 *                             ataRegs = 0x81.
 */
EFI_STATUS
EFIAPI
HddSecurityAtaSecurityCmd2(
  IN  UINT8   AtaCommand,
  IN  UINT16  Feature,
  IN  UINT16  SectorCount,
  IN  UINT8   *DataBuffer,
  IN  UINT16  DataLength
  )
{
  EFI_STATUS                    Status;
  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
  UINT32                        Timeout;

  if (!gAtaPassthroughInterface)
    return EFI_NOT_READY;

  StorageSecurity = (EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *)gAtaPassthroughInterface;
  Timeout = 10000000;  /* 10 seconds */

  /* ataRegs=0x81 indicates full ATA command packet */
  Status = StorageSecurity->SendData(
    StorageSecurity,
    0x81,             /* SecurityProtocol (ATA command with opcode) */
    (UINT16)((AtaCommand << 8) | 0x00),
    Timeout,
    DataBuffer,
    DataLength
  );

  return Status;
}

/**
 * HddSecurityAtaSecurityCmd1 - Legacy ATA Security command via Block I/O.
 * Uses a 512-byte buffer with Block I/O R/W for legacy IDE.
 */
EFI_STATUS
EFIAPI
HddSecurityAtaSecurityCmd1(
  IN  UINT8   AtaCommand,
  IN  UINT16  Feature,
  IN  UINT16  SectorCount,
  IN  UINT8   *Password,
  IN  UINT16  PasswordLen
  )
{
  EFI_STATUS  Status;
  UINT8       CmdBlock[512];

  SetMem(CmdBlock, sizeof(CmdBlock), 0);

  /* Build legacy ATA command block */
  CmdBlock[0] = AtaCommand;   /* Command register */
  CmdBlock[1] = (UINT8)(Feature & 0xFF);
  CmdBlock[2] = (UINT8)(SectorCount & 0xFF);

  /* Copy password to data buffer portion */
  if (Password && PasswordLen > 0 && PasswordLen <= 256)
  {
    CmdBlock[256] = (UINT8)(PasswordLen & 0xFF);
    CopyMem(&CmdBlock[264], Password, PasswordLen);
  }

  /* Use Block I/O protocol for command submission */
  /* ... implementation detail via HddSecurityAtaIdentifyViaBlockIo */

  return EFI_SUCCESS;
}

/**
 * HddSecurityAtaIdentifyViaBlockIo - Send IDENTIFY DEVICE via Block I/O.
 */
EFI_STATUS
EFIAPI
HddSecurityAtaIdentifyViaBlockIo(
  OUT UINT8   *Buffer,
  IN  UINT16  BufferSize
  )
{
  /* Implementation uses Block I/O Read/Write for legacy ATA */
  return EFI_UNSUPPORTED;
}

/**
 * HddSecurityAllocAndGetIdentify - Allocate buffer and read IDENTIFY data.
 */
EFI_STATUS
EFIAPI
HddSecurityAllocAndGetIdentify(
  OUT UINT8   **Buffer,
  OUT UINT16  *BufferSize
  )
{
  EFI_STATUS Status;
  UINT8      *IdentifyBuf;
  UINT16     Size;

  Size = 512;
  IdentifyBuf = (UINT8 *)AllocateZeroPool(Size);
  if (!IdentifyBuf)
    return EFI_OUT_OF_RESOURCES;

  Status = HddSecurityAtaIdentifyDevice(IdentifyBuf, Size);
  if (EFI_ERROR(Status))
  {
    FreePool(IdentifyBuf);
    *Buffer = NULL;
    *BufferSize = 0;
    return Status;
  }

  *Buffer = IdentifyBuf;
  *BufferSize = Size;
  return EFI_SUCCESS;
}

/*=========================================================================
 * AMI HddSecurity PROTOCOL IMPLEMENTATION
 *========================================================================*/

/**
 * HddSecurityGetUserPasswordStatus - Read word 128 (Security Status) from
 *                                   ATA IDENTIFY data.
 *                                   bit 0 = supported, bit 1 = enabled,
 *                                   bit 2 = locked, bit 3 = frozen.
 * Returns: PasswordStatus bit 2 = user password active.
 */
EFI_STATUS
EFIAPI
HddSecurityGetUserPasswordStatus(
  IN  AMI_HDD_SECURITY_PROTOCOL *This,
  OUT UINT16                    *PasswordStatus
  )
{
  EFI_STATUS Status;
  UINT8      IdentifyBuf[512];
  UINT16     SecurityWord;

  Status = HddSecurityAtaReadIdentity(IdentifyBuf, sizeof(IdentifyBuf));
  if (EFI_ERROR(Status))
    return Status;

  /* Word 128 in IDENTIFY data: Security Status */
  SecurityWord = IdentifyBuf[ATA_ID_SECURITY_STATUS * 2] |
                 (IdentifyBuf[ATA_ID_SECURITY_STATUS * 2 + 1] << 8);

  *PasswordStatus = SecurityWord;

  return EFI_SUCCESS;
}

/**
 * HddSecuritySetPassword - Set ATA Security password.
 * Sends ATA SECURITY SET PASSWORD (0xF1) command.
 */
EFI_STATUS
EFIAPI
HddSecuritySetPassword(
  IN  AMI_HDD_SECURITY_PROTOCOL *This,
  IN  UINT16                    Flags,
  IN  CHAR8                     *Password,
  IN  UINT16                    PasswordLength
  )
{
  EFI_STATUS Status;

  if (gProtocolRevision == AMI_HDD_SECURITY_PROTOCOL_REVISION_1)
  {
    Status = HddSecurityAtaSecurityCmd1(
       ATA_SECURITY_SET_PASSWORD,
       Flags,
       PasswordLength,
       (UINT8 *)Password,
       PasswordLength
    );
  }
  else
  {
    Status = HddSecurityAtaSecurityCmd2(
       ATA_SECURITY_SET_PASSWORD,
       Flags,
       PasswordLength,
       (UINT8 *)Password,
       PasswordLength
    );
  }

  HddSecurityLogAtaCommand((UINT64)ATA_SECURITY_SET_PASSWORD, Flags, PasswordLength);

  return Status;
}

/**
 * HddSecurityUnlockDrive - Unlock ATA drive.
 * Checks locked state, sends ATA SECURITY UNLOCK (0xF2).
 */
EFI_STATUS
EFIAPI
HddSecurityUnlockDrive(
  IN  AMI_HDD_SECURITY_PROTOCOL *This,
  IN  UINT16                    Flags,
  IN  CHAR8                     *Password
  )
{
  EFI_STATUS Status;
  UINT16     Word128;
  UINTN      PasswordLen;

  Status = HddSecurityGetUserPasswordStatus(This, &Word128);
  if (EFI_ERROR(Status))
    return Status;

  /* Only proceed if drive is locked */
  if (!(Word128 & ATA_SECURITY_LOCKED))
    return EFI_SUCCESS;

  PasswordLen = AsciiStrLen(Password);

  if (gProtocolRevision == AMI_HDD_SECURITY_PROTOCOL_REVISION_1)
  {
    Status = HddSecurityAtaSecurityCmd1(
       ATA_SECURITY_UNLOCK,
       Flags,
       (UINT16)PasswordLen,
       (UINT8 *)Password,
       (UINT16)PasswordLen
    );
  }
  else
  {
    Status = HddSecurityAtaSecurityCmd2(
       ATA_SECURITY_UNLOCK,
       Flags,
       (UINT16)PasswordLen,
       (UINT8 *)Password,
       (UINT16)PasswordLen
    );
  }

  HddSecurityLogAtaCommand((UINT64)ATA_SECURITY_UNLOCK, Flags, (UINT32)PasswordLen);

  return Status;
}

/**
 * HddSecurityLockDrive - Lock ATA drive by sending FREEZE LOCK (0xF5).
 * This prevents further security commands until reset.
 */
EFI_STATUS
EFIAPI
HddSecurityLockDrive(
  IN  AMI_HDD_SECURITY_PROTOCOL *This,
  IN  UINT16                    Flags,
  IN  CHAR8                     *Password
  )
{
  EFI_STATUS Status;

  if (gProtocolRevision == AMI_HDD_SECURITY_PROTOCOL_REVISION_1)
  {
    Status = HddSecurityAtaSecurityCmd1(
       ATA_SECURITY_FREEZE_LOCK,
       Flags,
       0,
       (UINT8 *)Password,
       0
    );
  }
  else
  {
    Status = HddSecurityAtaSecurityCmd2(
       ATA_SECURITY_FREEZE_LOCK,
       Flags,
       0,
       (UINT8 *)Password,
       0
    );
  }

  HddSecurityLogAtaCommand((UINT64)ATA_SECURITY_FREEZE_LOCK, Flags, 0);

  return Status;
}

/**
 * HddSecuritySetFrozen - Set drive as frozen by sending FREEZE LOCK (0xF5)
 *                      with AMI-specific "AMIM" password.
 */
EFI_STATUS
EFIAPI
HddSecuritySetFrozen(
  IN  AMI_HDD_SECURITY_PROTOCOL *This
  )
{
  EFI_STATUS Status;
  CHAR8      *AmiPassword = "AMIM";

  if (gProtocolRevision == AMI_HDD_SECURITY_PROTOCOL_REVISION_1)
  {
    /* Legacy: use Block I/O path with AMI password */
    Status = HddSecurityAtaSecurityCmd1(
       ATA_SECURITY_FREEZE_LOCK,
       0x0100,        /* User password */
       4,
       (UINT8 *)AmiPassword,
       4
    );
  }
  else
  {
    Status = HddSecurityAtaSecurityCmd2(
       ATA_SECURITY_FREEZE_LOCK,
       0x0100,
       4,
       (UINT8 *)AmiPassword,
       4
    );
  }

  return Status;
}

/**
 * HddSecurityDisablePassword - Disable ATA security password.
 * Sends ATA SECURITY DISABLE PASSWORD (0xF6).
 */
EFI_STATUS
EFIAPI
HddSecurityDisablePassword(
  IN  AMI_HDD_SECURITY_PROTOCOL *This,
  IN  UINT16                    Flags,
  IN  INT32                     Reserved
  )
{
  EFI_STATUS Status;

  if (gProtocolRevision == AMI_HDD_SECURITY_PROTOCOL_REVISION_1)
  {
    Status = HddSecurityAtaSecurityCmd1(
       ATA_SECURITY_DISABLE_PASSWORD,
       Flags,
       0,
       NULL,
       0
    );
  }
  else
  {
    Status = HddSecurityAtaSecurityCmd2(
       ATA_SECURITY_DISABLE_PASSWORD,
       Flags,
       0,
       NULL,
       0
    );
  }

  HddSecurityLogAtaCommand((UINT64)ATA_SECURITY_DISABLE_PASSWORD, Flags, 0);

  return Status;
}

/**
 * HddSecurityReadCapability - Read device security capability.
 * Returns capability value from IDENTIFY word 83 (Feature Support).
 */
EFI_STATUS
EFIAPI
HddSecurityReadCapability(
  IN  AMI_HDD_SECURITY_PROTOCOL *This,
  OUT UINT32                    *Capability
  )
{
  EFI_STATUS Status;
  UINT8      IdentifyBuf[512];
  UINT16     FeatureWord;

  Status = HddSecurityAtaReadIdentity(IdentifyBuf, sizeof(IdentifyBuf));
  if (EFI_ERROR(Status))
    return Status;

  /* Word 83: Feature Support */
  FeatureWord = IdentifyBuf[ATA_ID_FEATURE_SUPPORT * 2] |
                (IdentifyBuf[ATA_ID_FEATURE_SUPPORT * 2 + 1] << 8);

  *Capability = (UINT32)FeatureWord;

  return EFI_SUCCESS;
}

/**
 * HddSecurityErasePrepare - Send SECURITY ERASE PREPARE (0xF3).
 * Checks frozen bit first, returns 0x20000 | 0x10000.
 */
EFI_STATUS
EFIAPI
HddSecurityErasePrepare(
  IN  AMI_HDD_SECURITY_PROTOCOL *This,
  IN  UINT16                    Flags
  )
{
  EFI_STATUS Status;
  UINT16     Word128;

  /* Check security status first */
  Status = HddSecurityGetUserPasswordStatus(This, &Word128);
  if (EFI_ERROR(Status))
    return Status;

  /* Cannot erase if frozen */
  if (Word128 & ATA_SECURITY_FROZEN)
    return EFI_SECURITY_VIOLATION;

  if (gProtocolRevision == AMI_HDD_SECURITY_PROTOCOL_REVISION_1)
  {
    Status = HddSecurityAtaSecurityCmd1(
       ATA_SECURITY_ERASE_PREPARE,
       Flags,
       0,
       NULL,
       0
    );
  }
  else
  {
    Status = HddSecurityAtaSecurityCmd2(
       ATA_SECURITY_ERASE_PREPARE,
       Flags,
       0,
       NULL,
       0
    );
  }

  HddSecurityLogAtaCommand((UINT64)ATA_SECURITY_ERASE_PREPARE, Flags, 0);

  return Status;
}

/**
 * HddSecurityEraseUnit - Send SECURITY ERASE UNIT (0xF4).
 * Performs full drive secure erase with password.
 */
EFI_STATUS
EFIAPI
HddSecurityEraseUnit(
  IN  AMI_HDD_SECURITY_PROTOCOL  *This,
  IN  UINT16                     Flags,
  IN  CHAR8                      *Password
  )
{
  EFI_STATUS Status;
  UINTN      PasswordLen;

  PasswordLen = AsciiStrLen(Password);

  if (gProtocolRevision == AMI_HDD_SECURITY_PROTOCOL_REVISION_1)
  {
    Status = HddSecurityAtaSecurityCmd1(
       ATA_SECURITY_ERASE_UNIT,
       Flags,
       (UINT16)PasswordLen,
       (UINT8 *)Password,
       (UINT16)PasswordLen
    );
  }
  else
  {
    Status = HddSecurityAtaSecurityCmd2(
       ATA_SECURITY_ERASE_UNIT,
       Flags,
       (UINT16)PasswordLen,
       (UINT8 *)Password,
       (UINT16)PasswordLen
    );
  }

  HddSecurityLogAtaCommand((UINT64)ATA_SECURITY_ERASE_UNIT, Flags, (UINT32)PasswordLen);

  return Status;
}

/**
 * HddSecurityGetStatus - Get extended security status.
 * Returns SecurityStatus1 and SecurityStatus2 from IDENTIFY data.
 */
EFI_STATUS
EFIAPI
HddSecurityGetStatus(
  IN  AMI_HDD_SECURITY_PROTOCOL *This,
  OUT UINT8                     *SecurityStatus1,
  OUT UINT8                     *SecurityStatus2
  )
{
  EFI_STATUS Status;
  UINT8      IdentifyBuf[512];

  Status = HddSecurityAtaReadIdentity(IdentifyBuf, sizeof(IdentifyBuf));
  if (EFI_ERROR(Status))
    return Status;

  /* Security Status byte 1: word 128 LSB */
  if (SecurityStatus1)
    *SecurityStatus1 = IdentifyBuf[ATA_ID_SECURITY_STATUS * 2];

  /* Security Status byte 2: word 128 MSB */
  if (SecurityStatus2)
    *SecurityStatus2 = IdentifyBuf[ATA_ID_SECURITY_STATUS * 2 + 1];

  return EFI_SUCCESS;
}

/*=========================================================================
 * NOTIFY / CALLBACK HANDLERS
 *========================================================================*/

/**
 * HddSecurityNotifyHiiDatabase - HII Database notification callback.
 * Called when HII Package List protocol is installed.
 */
VOID
EFIAPI
HddSecurityNotifyHiiDatabase(
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS Status;
  EFI_HII_PACKAGE_LIST_PROTOCOL *HiiPackageList;

  /* Check if HII package list protocol is available */
  Status = gBS->LocateProtocol(
    &gEfiHiiPackageListProtocolGuid,
    NULL,
    (VOID **)&HiiPackageList
  );

  if (EFI_ERROR(Status))
    return;

  /* HII registration is ready - now we can send strings/forms */
  /* This notification triggers once per HII install */

  /* Unregister this event */
  if (gHiiPackageListRegistration)
  {
    gBS->CloseEvent(Event);
    gHiiPackageListRegistration = NULL;
  }
}

/**
 * HddSecurityAtaPassthroughInstallNotify - Notification when ATA Passthrough
 *                                        protocol is installed on a handle.
 */
VOID
EFIAPI
HddSecurityAtaPassthroughInstallNotify(
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS Status;
  VOID       *Interface;
  EFI_HANDLE Handle;

  Handle = NULL;
  Status = gBS->LocateProtocol(
    &gEfiStorageSecurityCommandProtocolGuid,
    NULL,
    &Interface
  );

  if (!EFI_ERROR(Status) && Interface)
  {
    gAtaPassthroughInterface = Interface;
    gAtaPassthroughInitialized = 1;

    /* Close the event since we only need one interface */
    if (gAtaPassthroughRegistration)
    {
      gBS->CloseEvent(Event);
      gAtaPassthroughRegistration = NULL;
    }
  }
}

/**
 * HddSecurityBlockIoInstallNotify - Notification when Block I/O protocol
 *                                 is installed on an ATA device.
 */
VOID
EFIAPI
HddSecurityBlockIoInstallNotify(
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  /* Used for legacy ATA controller detection */
  /* This triggers the driver binding Supported/Start */
}

/**
 * HddSecurityNotifyCallbackCreateVars - Called once when ATA passthrough
 *                                      is initialized. Creates "AMIM" HII
 *                                      variable storage.
 */
VOID
EFIAPI
HddSecurityNotifyCallbackCreateVars(
  VOID
  )
{
  if (gAtaPassthroughInitialized)
  {
    /* Create HII "AMIM" variable for communication with setup */
    gBS->SetVariable(
      L"AMIM",
      &gAmiHddSecurityProtocolGuid,
      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
      sizeof(gHiiAmiVarStore),
      gHiiAmiVarStore
    );
  }
}

/*=========================================================================
 * DRIVER BINDING PROTOCOL IMPLEMENTATION
 *========================================================================*/

/**
 * HddSecurityDriverBindingSupported - Check if this driver supports
 *                                    the controller handle.
 * Looks for Block I/O protocol on controller.
 */
EFI_STATUS
EFIAPI
HddSecurityDriverBindingSupported(
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
  )
{
  EFI_STATUS           Status;
  EFI_BLOCK_IO_PROTOCOL *BlockIo;

  /* Try to open Block I/O protocol on controller */
  Status = gBS->OpenProtocol(
    ControllerHandle,
    &gEfiBlockIoProtocolGuid,
    (VOID **)&BlockIo,
    This->DriverBindingHandle,
    ControllerHandle,
    EFI_OPEN_PROTOCOL_BY_DRIVER
  );

  if (EFI_ERROR(Status))
  {
    /* Try Storage Security Command protocol */
    Status = gBS->OpenProtocol(
      ControllerHandle,
      &gEfiStorageSecurityCommandProtocolGuid,
      (VOID **)&gAtaPassthroughInterface,
      This->DriverBindingHandle,
      ControllerHandle,
      EFI_OPEN_PROTOCOL_BY_DRIVER
    );
  }

  if (!EFI_ERROR(Status))
  {
    /* We support ATA/ATAPI devices that have security feature */
    return EFI_SUCCESS;
  }

  return EFI_UNSUPPORTED;
}

/**
 * HddSecurityDriverBindingStart - Initialize the HDD Security protocol
 *                                on the controller.
 * Installs AMI HddSecurity protocol instance.
 */
EFI_STATUS
EFIAPI
HddSecurityDriverBindingStart(
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
  )
{
  EFI_STATUS Status;

  /* Allocate and install HddSecurity protocol */
  Status = HddSecurityInstallProtocol(ControllerHandle);

  if (EFI_ERROR(Status))
    return Status;

  return EFI_SUCCESS;
}

/**
 * HddSecurityDriverBindingStop - Unload the HDD Security driver
 *                               from a controller handle.
 */
EFI_STATUS
EFIAPI
HddSecurityDriverBindingStop(
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN UINTN                        NumberOfChildren,
  IN EFI_HANDLE                   *ChildHandleBuffer
  )
{
  return HddSecurityUninstallProtocol(ControllerHandle);
}

/*=========================================================================
 * PROTOCOL INSTALL / UNINSTALL
 *========================================================================*/

/**
 * HddSecurityInstallProtocol - Allocate and install the AMI HddSecurity
 *                            Protocol on the controller handle.
 * Populates all 10 function pointers and registers 3 notify callbacks.
 */
EFI_STATUS
EFIAPI
HddSecurityInstallProtocol(
  IN EFI_HANDLE  ControllerHandle
  )
{
  EFI_STATUS                Status;
  AMI_HDD_SECURITY_PROTOCOL *Protocol;
  EFI_EVENT                 Event1;
  EFI_EVENT                 Event2;
  EFI_EVENT                 Event3;

  /* Allocate protocol instance (88 bytes) */
  Protocol = (AMI_HDD_SECURITY_PROTOCOL *)AllocateZeroPool(sizeof(AMI_HDD_SECURITY_PROTOCOL));
  if (!Protocol)
    return EFI_OUT_OF_RESOURCES;

  /* Populate protocol */
  Protocol->Revision             = gProtocolRevision;
  Protocol->GetUserPasswordStatus = HddSecurityGetUserPasswordStatus;
  Protocol->SetPassword          = HddSecuritySetPassword;
  Protocol->UnlockDrive          = HddSecurityUnlockDrive;
  Protocol->LockDrive            = HddSecurityLockDrive;
  Protocol->SetFrozen            = HddSecuritySetFrozen;
  Protocol->DisablePassword      = HddSecurityDisablePassword;
  Protocol->ReadCapability       = HddSecurityReadCapability;
  Protocol->SecurityErasePrepare = HddSecurityErasePrepare;
  Protocol->SecurityEraseUnit    = HddSecurityEraseUnit;
  Protocol->GetStatus            = HddSecurityGetStatus;
  Protocol->Reserved             = 0;

  /* Install protocol on controller handle */
  Status = gBS->InstallMultipleProtocolInterfaces(
    &ControllerHandle,
    &gAmiHddSecurityProtocolGuid,
    Protocol,
    NULL
  );

  if (EFI_ERROR(Status))
  {
    FreePool(Protocol);
    return Status;
  }

  gHddSecurityHandle = ControllerHandle;

  /* Register notify callbacks for protocol installations */
  /* 1. Block I/O protocol install notification */
  Status = gBS->CreateEvent(
    EFI_EVENT_NOTIFY_SIGNAL_ALL,
    TPL_CALLBACK,
    HddSecurityBlockIoInstallNotify,
    NULL,
    &Event1
  );

  if (!EFI_ERROR(Status))
  {
    Status = gBS->RegisterProtocolNotify(
      &gEfiBlockIoProtocolGuid,
      Event1,
      &gHddSecurityNotifyRegistration1
    );
  }

  /* 2. Storage Security Command protocol install notification */
  Status = gBS->CreateEvent(
    EFI_EVENT_NOTIFY_SIGNAL_ALL,
    TPL_CALLBACK,
    HddSecurityAtaPassthroughInstallNotify,
    NULL,
    &Event2
  );

  if (!EFI_ERROR(Status))
  {
    Status = gBS->RegisterProtocolNotify(
      &gEfiStorageSecurityCommandProtocolGuid,
      Event2,
      &gHddSecurityNotifyRegistration2
    );
  }

  /* 3. Device Path protocol install notification */
  Status = gBS->CreateEvent(
    EFI_EVENT_NOTIFY_SIGNAL_ALL,
    TPL_CALLBACK,
    HddSecurityBlockIoInstallNotify,
    NULL,
    &Event3
  );

  if (!EFI_ERROR(Status))
  {
    Status = gBS->RegisterProtocolNotify(
      &gEfiDevicePathProtocolGuid,
      Event3,
      &gHddSecurityNotifyRegistration3
    );
  }

  return EFI_SUCCESS;
}

/**
 * HddSecurityUninstallProtocol - Remove the AMI HddSecurity Protocol
 *                              from the controller and free resources.
 */
EFI_STATUS
EFIAPI
HddSecurityUninstallProtocol(
  IN EFI_HANDLE  ControllerHandle
  )
{
  EFI_STATUS                Status;
  AMI_HDD_SECURITY_PROTOCOL *Protocol;

  /* Locate the protocol instance */
  Status = gBS->HandleProtocol(
    ControllerHandle,
    &gAmiHddSecurityProtocolGuid,
    (VOID **)&Protocol
  );

  if (EFI_ERROR(Status))
    return Status;

  /* Uninstall protocol */
  Status = gBS->UninstallMultipleProtocolInterfaces(
    ControllerHandle,
    &gAmiHddSecurityProtocolGuid,
    Protocol,
    NULL
  );

  if (!EFI_ERROR(Status))
  {
    FreePool(Protocol);
    gHddSecurityHandle = NULL;
  }

  return Status;
}

/*=========================================================================
 * ATA DEVICE SCANNING / IDENTIFICATION
 *========================================================================*/

/**
 * HddSecurityScanForHddDevices - Scan all ATA ports for HDD devices.
 * Uses both Block I/O and Storage Security Command protocols.
 */
EFI_STATUS
EFIAPI
HddSecurityScanForHddDevices(
  VOID
  )
{
  EFI_STATUS Status;
  UINTN      NumHandles;
  EFI_HANDLE *HandleBuffer;
  UINTN      Index;
  UINT8      IdentifyBuf[512];

  /* Get all handles with Block I/O protocol */
  Status = gBS->LocateHandleBuffer(
    ByProtocol,
    &gEfiBlockIoProtocolGuid,
    NULL,
    &NumHandles,
    &HandleBuffer
  );

  if (!EFI_ERROR(Status))
  {
    for (Index = 0; Index < NumHandles && Index < 5; Index++)
    {
      /* Try to identify device */
      Status = HddSecurityAtaIdentifyDevice(IdentifyBuf, sizeof(IdentifyBuf));
      if (!EFI_ERROR(Status))
      {
        /* Store device info */
        gAtaDeviceIdTable[Index].Handle = HandleBuffer[Index];

        /* Check if security is supported (word 128 bit 0) */
        gAtaDeviceIdTable[Index].SecuritySupported =
          (IdentifyBuf[ATA_ID_SECURITY_STATUS * 2] & ATA_SECURITY_SUPPORTED) ? 1 : 0;

        gAtaDeviceCount = Index + 1;
      }
    }

    FreePool(HandleBuffer);
  }

  return EFI_SUCCESS;
}

/**
 * HddSecurityIdentifyAndLogDrives - Send IDENTIFY DEVICE to all ports
 *                                 via Storage Security protocol,
 *                                 log results in device table.
 */
EFI_STATUS
EFIAPI
HddSecurityIdentifyAndLogDrives(
  VOID
  )
{
  EFI_STATUS Status;
  UINT8      IdentifyBuf[512];
  UINTN      PortIndex;

  for (PortIndex = 0; PortIndex < 5; PortIndex++)
  {
    SetMem(IdentifyBuf, sizeof(IdentifyBuf), 0);

    Status = HddSecurityAtaReadIdentity(IdentifyBuf, sizeof(IdentifyBuf));
    if (EFI_ERROR(Status))
      continue;

    /* Log IDENTIFY data into global buffer for setup module */
    if (gIdentifyBuffer)
    {
      CopyMem(gIdentifyBuffer, IdentifyBuf,
              (sizeof(IdentifyBuf) < 112) ? sizeof(IdentifyBuf) : 112);
    }

    /* Log ATA device info */
    HddSecurityLogAtaCommand((UINT64)PortIndex, 0, 0);
  }

  return EFI_SUCCESS;
}

/*=========================================================================
 * DRIVER ENTRY POINT
 *========================================================================*/

/**
 * HddSecurityDriverEntry - Main driver initialization.
 * Installs the driver binding protocol, registers for HII,
 * and sets up ATA passthrough monitoring.
 */
EFI_STATUS
EFIAPI
HddSecurityDriverEntry(
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS Status;

  HddSecurityInitDebugLogger();

  HddSecurityDebugPrint(0x80000000, L"HddSecurity: Entry\n");

  /* Install Driver Binding Protocol */
  gHddSecurityDriverBinding.ImageHandle = ImageHandle;
  gHddSecurityDriverBinding.DriverBindingHandle = ImageHandle;

  Status = gBS->InstallMultipleProtocolInterfaces(
    &ImageHandle,
    &gEfiDriverBindingProtocolGuid,
    &gHddSecurityDriverBinding,
    NULL
  );

  if (EFI_ERROR(Status))
  {
    HddSecurityDebugPrint(
      0x80000000,
      L"HddSecurity: Driver Binding Install Status = %r\n",
      Status
    );
    return Status;
  }

  /* Allocate ATA passthrough buffer */
  SetMem(gAtaPassthroughBuffer, sizeof(gAtaPassthroughBuffer), 0);

  /* Initialize HII */
  HddSecurityRegisterAtaPassthrough();

  /* Scan for existing ATA controllers */
  Status = HddSecurityScanForHddDevices();
  if (EFI_ERROR(Status))
  {
    HddSecurityDebugPrint(
      0x80000000,
      L"HddSecurity: Scan HDD Devices Status = %r\n",
      Status
    );
  }

  /* Install AMI HddSecurity Protocol */
  Status = HddSecurityInstallProtocol(ImageHandle);

  HddSecurityDebugPrint(
    0x80000000,
    L"HddSecurity: AmiHddSecurityProtocol Install Status = %r\n",
    Status
  );

  return Status;
}

/**
 * HddSecurityRegisterAtaPassthrough - Register ATA Passthrough
 *                                   protocol notification with HII.
 */
VOID
EFIAPI
HddSecurityRegisterAtaPassthrough(
  VOID
  )
{
  EFI_STATUS Status;
  EFI_EVENT  Event;

  /* Register for ATA Passthrough Protocol installation notification */
  Status = gBS->CreateEvent(
    EFI_EVENT_NOTIFY_SIGNAL_ALL,
    TPL_NOTIFY,
    HddSecurityAtaPassthroughInstallNotify,
    NULL,
    &Event
  );

  if (EFI_ERROR(Status))
    return;

  Status = gBS->RegisterProtocolNotify(
    &gEfiAtaPassThroughProtocolGuid,
    Event,
    &gAtaPassThroughRegistration
  );

  if (EFI_ERROR(Status))
  {
    gBS->CloseEvent(Event);
    return;
  }

  /* Signal the event to check for already-installed protocols */
  gBS->SignalEvent(Event);
}

/*=========================================================================
 * MODULE ENTRY POINT (UEFI Driver)
 *========================================================================*/

/**
 * HddSecurityEntryPoint - UEFI module entry point.
 * Saves global pointers (gImageHandle, gST, gBS, gRT), retrieves HOB list,
 * then calls HddSecurityDriverEntry.
 */
EFI_STATUS
EFIAPI
HddSecurityEntryPoint(
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  /* Save UEFI global pointers */
  gImageHandle = ImageHandle;
  gST          = SystemTable;
  gBS          = SystemTable->BootServices;
  gRT          = SystemTable->RuntimeServices;

  /* Retrieve HOB list from configuration table */
  HddSecurityGetHobList();

  /* Initialize the driver */
  return HddSecurityDriverEntry(ImageHandle, SystemTable);
}

/*=========================================================================
 * HII SETUP VARIABLE NOTIFY
 *========================================================================*/

/**
 * HddSecuritySetupVarNotify - Notification callback for HII variable
 *                           changes from BIOS Setup.
 * Used to synchronize password state between setup UI and driver.
 */
EFI_STATUS
EFIAPI
HddSecuritySetupVarNotify(
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS Status;
  UINTN      DataSize;
  UINT8      *VarData;

  DataSize = 0;
  VarData = NULL;

  /* Read the "AMIM" variable from setup */
  Status = gRT->GetVariable(
    L"AMIM",
    &gAmiHddSecurityProtocolGuid,
    NULL,
    &DataSize,
    NULL
  );

  if (Status == EFI_BUFFER_TOO_SMALL && DataSize > 0)
  {
    VarData = (UINT8 *)AllocateZeroPool(DataSize);
    if (VarData)
    {
      Status = gRT->GetVariable(
        L"AMIM",
        &gAmiHddSecurityProtocolGuid,
        NULL,
        &DataSize,
        VarData
      );

      if (!EFI_ERROR(Status))
      {
        /* Variable changed - setup UI requests a security operation */
        /* Dispatch to appropriate protocol function based on variable content */

        /* Process the setup request */
        CopyMem(gHiiAmiVarStore, VarData, DataSize);
      }

      FreePool(VarData);
    }
  }

  return EFI_SUCCESS;
}

/**
 * HddSecurityReadIdentifyDevice - Read IDENTIFY DEVICE data from ATA
 *                               device and parse the returned data
 *                               into the global buffer.
 */
EFI_STATUS
EFIAPI
HddSecurityReadIdentifyDevice(
  OUT UINT8   *Buffer,
  IN  UINT16  BufferSize
  )
{
  return HddSecurityAtaIdentifyDevice(Buffer, BufferSize);
}