Newer
Older
AMI-Aptio-BIOS-Reversed / AmiModulePkg / AtaPassThru / AtaPassThru / AtaPassThru.c
// AtaPassThru.c
// Automatically generated decompilation for AtaPassThru.efi
// HR650X AMI UEFI BIOS ATA Pass Thru Protocol driver
// Source: e:\hs\AmiModulePkg\AtaPassThru\AtaPassThru.c
// SHA256: 989d6f76fa8863b5144165e545c2117a5c93e616789bcd96e0c29172e0cdc163
//
// This driver implements the UEFI EFI_ATA_PASS_THRU_PROTOCOL on ATA/SATA
// controllers detected by the SATA controller driver (SataController.efi).
// It provides register-level ATA command passthrough to upper-layer drivers
// like AtaBusDxe.

#include "AtaPassThru.h"

//=============================================================================
// Global State
//=============================================================================

EFI_HANDLE              gImageHandle    = NULL;
EFI_SYSTEM_TABLE        *gSystemTable   = NULL;
EFI_BOOT_SERVICES       *gBootServices  = NULL;
EFI_RUNTIME_SERVICES    *gRuntimeServices = NULL;

EFI_BOOT_SERVICES       *gBS_copy       = NULL;
EFI_RUNTIME_SERVICES    *gRT_copy       = NULL;
EFI_SYSTEM_TABLE        *gST_copy       = NULL;

VOID                    *gDebugProtocol  = NULL;
VOID                    *gHobList        = NULL;
VOID                    *gAtaDevice      = NULL;
VOID                    *gAtaDeviceInfo  = NULL;
ATA_CONTROLLER_INFO     *gControllerInfo = NULL;

//=============================================================================
// GUIDs
//=============================================================================

EFI_GUID gEfiAtaPassThruProtocolGuid   = EFI_ATA_PASS_THRU_PROTOCOL_GUID;
EFI_GUID gAtaPassThruChildProtocolGuid = ATA_PASS_THRU_CHILD_PROTOCOL_GUID;
EFI_GUID gEfiHobListGuid              = EFI_HOB_LIST_GUID;
EFI_GUID gAtaPassThruControllerGuid   = ATA_PASS_THRU_CONTROLLER_GUID;
EFI_GUID gAtaPassThruDebugProtocolGuid = ATA_PASS_THRU_DEBUG_PROTOCOL_GUID;

//=============================================================================
// Forward declarations of internal helpers
//=============================================================================

STATIC VOID   *AtaPassThruGetDebugProtocol (VOID);

//=============================================================================
// ModuleEntryPoint
//=============================================================================

EFI_STATUS
EFIAPI
ModuleEntryPoint (
    IN EFI_HANDLE       ImageHandle,
    IN EFI_SYSTEM_TABLE *SystemTable
    )
{
    gImageHandle = ImageHandle;
    if (ImageHandle == NULL) {
        AtaPassThruReportAssert(
            "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
            51,
            "gImageHandle != ((void *) 0)");
    }

    gSystemTable = SystemTable;
    if (SystemTable == NULL) {
        AtaPassThruReportAssert(
            "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
            57,
            "gST != ((void *) 0)");
    }

    gBootServices = SystemTable->BootServices;
    if (gBootServices == NULL) {
        AtaPassThruReportAssert(
            "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
            63,
            "gBS != ((void *) 0)");
    }

    gRuntimeServices = SystemTable->RuntimeServices;
    if (gRuntimeServices == NULL) {
        AtaPassThruReportAssert(
            "e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
            47,
            "gRT != ((void *) 0)");
    }

    AtaPassThruGetHobList();
    return AtaPassThruInit(ImageHandle, SystemTable);
}

//=============================================================================
// AtaPassThruInit
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruInit (
    IN EFI_HANDLE       ImageHandle,
    IN EFI_SYSTEM_TABLE *SystemTable
    )
{
    EFI_STATUS  Status;
    EFI_HANDLE  ChildHandle = NULL;

    if (gST_copy == NULL) {
        gST_copy      = SystemTable;
        gBS_copy      = SystemTable->BootServices;
        gRT_copy      = SystemTable->RuntimeServices;
    }

    // Allocate 16-byte private registration protocol structure
    Status = gBS_copy->AllocatePool(
                EfiBootServicesData,
                16,
                &gAtaDevice
                );
    if (!EFI_ERROR(Status)) {
        // Slot 0 = Initialize callback (AtaPassThruDriverBindingStart)
        // Slot 1 = Unload callback (AtaPassThruDriverBindingStop)
        *(UINT64 *)((UINT8 *)gAtaDevice + 0) = (UINT64)AtaPassThruDriverBindingStart;
        *(UINT64 *)((UINT8 *)gAtaDevice + 8) = (UINT64)AtaPassThruDriverBindingStop;

        Status = gBS_copy->InstallProtocolInterface(
                    &ChildHandle,
                    &gAtaPassThruChildProtocolGuid,
                    EFI_NATIVE_INTERFACE,
                    gAtaDevice
                    );
        if (EFI_ERROR(Status)) {
            DEBUG((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
            AtaPassThruReportAssert(
                "e:\\hs\\AmiModulePkg\\AtaPassThru\\AtaPassThru.c",
                81,
                "!EFI_ERROR (Status)");
        }
    }

    return Status;
}

//=============================================================================
// AtaPassThruDriverBindingStart
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruDriverBindingStart (
    IN EFI_HANDLE  ControllerHandle,
    IN CHAR8       ChannelFlag
    )
{
    EFI_STATUS  Status;
    UINT64      *PortArray = NULL;
    UINT16      PortCount;

    Status = gBS_copy->AllocatePool(
                EfiBootServicesData,
                sizeof(ATA_PASS_THRU_DEVICE),
                &gAtaDeviceInfo
                );
    if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES;

    Status = gBS_copy->AllocatePool(
                EfiBootServicesData,
                sizeof(ATA_CONTROLLER_INFO),
                &gControllerInfo
                );
    if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES;

    ATA_PASS_THRU_DEVICE *Device = (ATA_PASS_THRU_DEVICE *)gAtaDeviceInfo;
    ATA_CONTROLLER_INFO  *Ctl    = (ATA_CONTROLLER_INFO *)gControllerInfo;

    Device->ControllerInfo   = Ctl;
    Device->SendCmd          = AtaPassThruSendCommand;
    Device->GetNextPort      = AtaPassThruGetNextPort;
    Device->GetNextDevice    = AtaPassThruGetNextDevice;
    Device->BuildDevicePath  = AtaPassThruBuildDevicePath;
    Device->GetDevicePath    = AtaPassThruGetDeviceFromPath;
    Device->ResetPort        = AtaPassThruResetPort;
    Device->ResetDevice      = AtaPassThruResetDevice;
    Device->ChannelFlag      = (UINT8)ChannelFlag;
    Device->ControllerHandle = ControllerHandle;

    Ctl->ChannelType = 3;  // IoAlign
    Ctl->Reserved    = 0;  // Attributes

    if (ChannelFlag) {
        PortCount = AtaPassThruEnumeratePorts(ControllerHandle, NULL);
        if (PortCount != 0 && PortCount != 0xFFFF) {
            Status = gBS_copy->AllocatePool(
                        EfiBootServicesData,
                        8 * PortCount,
                        (VOID **)&PortArray
                        );
            if (!EFI_ERROR(Status)) {
                AtaPassThruEnumeratePorts(ControllerHandle, PortArray);
                if (PortCount > 0) {
                    Device->PortEntries = PortArray;
                    Device->PortCount   = PortCount;
                    UINT64 FirstChild = *(UINT64 *)PortArray;
                    //
                    // Initialize port/device context tracking
                    // Offset +228 = current port, +230 = current device
                    //
                    *(UINT16 *)(*(UINT64 *)(FirstChild + 848) + 228) = 0xFFFF;
                    *(UINT16 *)(*(UINT64 *)(FirstChild + 848) + 230) = 0;
                }
            }
        }
        if (PortArray == NULL || PortCount == 0) {
            Device->PortEntries = NULL;
            Device->PortCount   = 0;
        }
    }

    return gBS_copy->InstallProtocolInterface(
               &ControllerHandle,
               &gEfiAtaPassThruProtocolGuid,
               EFI_NATIVE_INTERFACE,
               Device
               );
}

//=============================================================================
// AtaPassThruDriverBindingStop
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruDriverBindingStop (
    IN EFI_HANDLE  ControllerHandle
    )
{
    EFI_STATUS Status;

    Status = gBS_copy->UninstallProtocolInterface(
                ControllerHandle,
                &gEfiAtaPassThruProtocolGuid,
                gAtaDeviceInfo
                );
    if (!EFI_ERROR(Status)) {
        ATA_PASS_THRU_DEVICE *Dev = (ATA_PASS_THRU_DEVICE *)gAtaDeviceInfo;
        if (Dev->PortEntries != NULL) {
            gBS_copy->FreePool(Dev->PortEntries);
        }
        gBS_copy->FreePool(gAtaDeviceInfo);
        gBS_copy->FreePool(gControllerInfo);
    }

    return Status;
}

//=============================================================================
// AtaPassThruFindDevice
//=============================================================================

UINT64
AtaPassThruFindDevice (
    IN ATA_PASS_THRU_DEVICE *Device,
    IN UINT16                Port,
    IN UINT16                PortMultiplierPort
    )
{
    UINT64  *PortArray = (UINT64 *)Device->PortEntries;
    if (PortArray == NULL || Device->PortCount == 0) return 0;

    for (UINT16 i = 0; i < Device->PortCount; i++) {
        UINT64 Entry = PortArray[i];
        if (*(UINT8 *)(Entry + 8) == (UINT8)Port &&
            *(UINT8 *)(Entry + 9) == (UINT8)PortMultiplierPort) {
            return Entry;
        }
    }
    return 0;
}

//=============================================================================
// AtaPassThruEnumeratePorts
//=============================================================================

UINT16
AtaPassThruEnumeratePorts (
    IN  EFI_HANDLE ControllerHandle,
    OUT UINT64     *PortArray OPTIONAL
    )
{
    UINT16      PortCount = 0;
    EFI_STATUS  Status;
    VOID       *ControllerProtocol;

    Status = gBS_copy->OpenProtocol(
                ControllerHandle,
                &gAtaPassThruControllerGuid,
                &ControllerProtocol,
                NULL,
                NULL,
                EFI_OPEN_PROTOCOL_GET_PROTOCOL
                );
    if (EFI_ERROR(Status)) return 0xFFFF;

    // Walk child handle linked list at controller protocol + 88
    UINT64 *HandleInfo = *(UINT64 **)((UINT64)ControllerProtocol + 88);
    while (HandleInfo && *HandleInfo) {
        // Check child type == 4 (ATA channel) at offset -909
        if (*(UINT8 *)((UINT64)HandleInfo - 909) == 4) {
            if (PortArray != NULL) {
                PortArray[PortCount] = (UINT64)HandleInfo - 115;
            }
            PortCount++;
        }
        HandleInfo = (UINT64 *)(UINTN)*HandleInfo;
    }

    return PortCount;
}

//=============================================================================
// AtaPassThruReadDeviceStatus
//=============================================================================

UINT8
AtaPassThruReadDeviceStatus (
    IN  UINT64 ChildDeviceHandle,
    OUT UINT8  *StatusBuffer OPTIONAL
    )
{
    UINT64 RegOff = (UINT64)*(UINT8 *)(ChildDeviceHandle + 8) << 7;
    UINT64 CfgPtr = *(UINT64 *)(ChildDeviceHandle + 848);
    UINT32 Status = *(UINT32 *)(RegOff + *(UINT64 *)(CfgPtr + 8) + 288);

    if (StatusBuffer != NULL) {
        gBS_copy->SetMem(StatusBuffer, 20, 0);
        UINT64 DevInfoBase = ChildDeviceHandle + 840;

        if (*(UINT8 *)(DevInfoBase + 64) == 52) {
            // 52-byte register block (native ATA)
            StatusBuffer[2]  = *(UINT8 *)(DevInfoBase + 66);  // Status / AltStatus
            StatusBuffer[3]  = *(UINT8 *)(DevInfoBase + 67);  // Device
            StatusBuffer[12] = *(UINT8 *)(DevInfoBase + 76);  // DeviceControl
            StatusBuffer[13] = *(UINT8 *)(DevInfoBase + 77);  // (unused)
            StatusBuffer[4]  = *(UINT8 *)(DevInfoBase + 68);  // SectorCount
            StatusBuffer[8]  = *(UINT8 *)(DevInfoBase + 72);  // LbaHigh
            StatusBuffer[5]  = *(UINT8 *)(DevInfoBase + 69);  // LbaLow
            StatusBuffer[9]  = *(UINT8 *)(DevInfoBase + 73);  // (unused)
            StatusBuffer[6]  = *(UINT8 *)(DevInfoBase + 70);  // LbaMid
            StatusBuffer[10] = *(UINT8 *)(DevInfoBase + 74);  // (unused)
            StatusBuffer[7]  = *(UINT8 *)(DevInfoBase + 71);  // LbaHigh / Error
        } else if (*(UINT8 *)(DevInfoBase + 32) == 95) {
            // 95-byte register block (AHCI)
            StatusBuffer[2]  = *(UINT8 *)(DevInfoBase + 34);
            StatusBuffer[3]  = *(UINT8 *)(DevInfoBase + 35);
            StatusBuffer[12] = *(UINT8 *)(DevInfoBase + 44);
            StatusBuffer[13] = *(UINT8 *)(DevInfoBase + 45);
            StatusBuffer[4]  = *(UINT8 *)(DevInfoBase + 36);
            StatusBuffer[8]  = *(UINT8 *)(DevInfoBase + 40);
            StatusBuffer[5]  = *(UINT8 *)(DevInfoBase + 37);
            StatusBuffer[9]  = *(UINT8 *)(DevInfoBase + 41);
            StatusBuffer[6]  = *(UINT8 *)(DevInfoBase + 38);
            StatusBuffer[10] = *(UINT8 *)(DevInfoBase + 42);
            StatusBuffer[7]  = *(UINT8 *)(DevInfoBase + 39);
        }
    }

    return (UINT8)(Status & 0xFF);
}

//=============================================================================
// AtaPassThruSendCommand
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruSendCommand (
    IN     ATA_PASS_THRU_DEVICE            *Device,
    IN     UINT16                           Port,
    IN     UINT16                           PortMultiplierPort,
    IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet
    )
{
    EFI_STATUS Status = EFI_SUCCESS;
    UINT64     ChildDevice = 0;
    UINT64     DeviceInterface = 0;
    UINT16     Features = 0;
    UINT32     BlockSize = 512;
    UINT64     Lba = 0;
    UINT8      ChannelActive;
    UINT8      Protocol;

    UINT8 Acb[49];
    gBS_copy->SetMem(Acb, sizeof(Acb), 0);

    ChannelActive = *(UINT8 *)((UINT8 *)Device + 0x40);
    Protocol      = *((UINT8 *)Packet + 48);

    // Validate buffer alignment
    UINT32 Alignment = *(UINT32 *)((UINT8 *)Packet + 4);
    if (Alignment > 1) {
        UINT64 ThisLen = ChannelActive ? *(UINT64 *)((UINT8 *)Packet + 0x18) : *(UINT64 *)((UINT8 *)Packet + 0x20);
        if (ThisLen % Alignment)                     return EFI_INVALID_PARAMETER;
        if (*(UINT32 *)((UINT8 *)Packet + 0x28) % Alignment) return EFI_INVALID_PARAMETER;
        if (*(UINT64 *)((UINT8 *)Packet + 0x08) % Alignment) return EFI_INVALID_PARAMETER;
        if (*(UINT64 *)Packet % Alignment)            return EFI_INVALID_PARAMETER;
    }

    // Resolve child device for non-blocking mode
    if (ChannelActive) {
        ChildDevice = AtaPassThruFindDevice(Device, Port, PortMultiplierPort);
        if (ChildDevice == 0) return EFI_INVALID_PARAMETER;

        DeviceInterface = *(UINT64 *)(ChildDevice + 848);
        if (DeviceInterface == 0) return EFI_INVALID_PARAMETER;

        Features = *(UINT16 *)(ChildDevice + 201);
        Lba      = *(UINT64 *)(ChildDevice + 235);

        // Detect 4K sector (IDENTIFY word 247)
        if ((*(UINT16 *)(ChildDevice + 247) & 0xD000) == 0x5000) {
            BlockSize = 2 * (*(UINT16 *)(ChildDevice + 269) +
                            (*(UINT16 *)(ChildDevice + 271) << 16));
        }
    } else {
        Lba = (UINT64)Device;
    }

    // Adjust transfer lengths from bytes to blocks
    UINT32 *pInLen  = (UINT32 *)((UINT8 *)Packet + 0x28);
    UINT32 *pOutLen = (UINT32 *)((UINT8 *)Packet + 0x2C);
    if (*pInLen)  *pInLen  = BlockSize * *pInLen;
    if (*pOutLen) *pOutLen = BlockSize * *pOutLen;

    // Max transfer: 256 sectors, or 65536 for 48-bit LBA
    UINT32 MaxSectors = 256;
    if ((Features & 0xC400) == 0x4400 && Lba > 0xFFFFFFF) {
        MaxSectors = 0x10000;
    }

    if ((*pInLen && *pInLen > BlockSize * MaxSectors) ||
        (*pOutLen && *pOutLen > BlockSize * MaxSectors)) {
        *pInLen = BlockSize * MaxSectors;
        return EFI_BAD_BUFFER_SIZE;
    }

    // Build ACB from Asb register block
    UINT8 *Asb = (UINT8 *)Packet->Asb;
    // Asb layout used by this driver:
    //   [2] = DeviceHead, [3] = ? , [4] = Features, [5] = SectorCount
    //   [6] = SectorNumber, [7] = CylinderLow, [8] = CylinderHigh
    //   [12] = SectorCountExp, [13] = SectorNumberExp
    Acb[2]  = Asb[12];   // Device/Head from Asb[12]
    Acb[4]  = Asb[4];    // Features
    Acb[5]  = Asb[5];    // SectorCount
    Acb[6]  = Asb[6];    // SectorNumber
    Acb[7]  = Asb[7];    // CylinderLow
    Acb[8]  = Asb[8];    // CylinderHigh
    Acb[12] = Asb[2];    // SectorCountExp from Asb[2]
    Acb[3]  = Asb[3];    // (register mapping)
    Acb[13] = Asb[13];   // SectorNumberExp

    // Timeout conversion (100ns -> 1ms)
    if (Packet->Timeout > 0) {
        Packet->Timeout = (Packet->Timeout >= 10000) ? Packet->Timeout / 10000 : 1;
    } else {
        Packet->Timeout = (UINT64)-1;
    }

    // ATA register block construction
    *(UINT64 *)Acb      = *(UINT64 *)((UINT8 *)Packet + 0x18);
    *(UINT32 *)(Acb + 8) = *pInLen;

    // Detect 48-bit LBA commands by checking Asb[2]
    if (Asb[2] <= 0x39) {
        UINT64 ExtMask = 0x230023000000000LL;
        if ((ExtMask >> Asb[2]) & 1) {
            // Extended register command (48-bit LBA)
            Acb[1] = Asb[8];
            Acb[3] = Asb[9];
            Acb[5] = Asb[10];
            Acb[6] = 64;  // DEV bit
        } else {
            Acb[6] = Asb[8] & 0xF | 0x40;
        }
    }

    if (!ChannelActive) return EFI_SUCCESS;

    // Dispatch by protocol type (command register [48])
    // Function pointer table at DeviceInterface:
    //   +168 (21*8): NonData cmd
    //   +176 (22*8): PIO Data-In
    //   +184 (23*8): PIO Data-Out / DMA
    //   +200 (25*8): Reset
    //   +208 (26*8): Software Reset

    switch (Protocol) {
    case 0: // ATA Non-Data
        Asb[7] = Asb[2] & 0x0F | 0x40;
        Status = ((UINT64 (*)(UINT64, UINT64, UINT8, UINT8, UINT8, UINT8)) \
                  (DeviceInterface + 168))(DeviceInterface, ChildDevice,
                    (UINT8)Port, (UINT8)PortMultiplierPort, 0, 0);
        break;

    case 1: // ATA Software Reset
        Status = ((UINT64 (*)(UINT64, UINT8)) \
                  (DeviceInterface + 208))(ChildDevice, (UINT8)PortMultiplierPort);
        break;

    case 2: // ATA PIO Data-Out
        *(UINT64 *)Acb = *(UINT64 *)((UINT8 *)Packet + 0x20);
        *(UINT32 *)(Acb + 8) = *pOutLen;
        Status = ((UINT64 (*)(UINT64, UINT64, UINT8)) \
                  (DeviceInterface + 184))(DeviceInterface, (UINT64)Acb, (*pInLen == 0) ? 1 : 0);
        break;

    case 3: // ATA PIO Data-In
        Status = ((UINT64 (*)(UINT64, UINT64)) \
                  (DeviceInterface + 176))(DeviceInterface, (UINT64)Acb);
        break;

    case 4: // ATA PIO Data-Out (alternate)
        *(UINT64 *)Acb = *(UINT64 *)((UINT8 *)Packet + 0x20);
        *(UINT32 *)(Acb + 8) = *pOutLen;
        Status = ((UINT64 (*)(UINT64, UINT64, UINT8)) \
                  (DeviceInterface + 184))(DeviceInterface, (UINT64)Acb, 0);
        break;

    case 5: // ATAPI IDENTIFY
        Status = ((UINT64 (*)(UINT64, UINT64)) \
                  (DeviceInterface + 176))(DeviceInterface, (UINT64)Acb);
        break;

    case 6: // ATAPI Packet / FPDMA
        if (*pInLen == 0) {
            *(UINT64 *)Acb = *(UINT64 *)((UINT8 *)Packet + 0x20);
            *(UINT32 *)(Acb + 8) = *pOutLen;
        }
        Status = ((UINT64 (*)(UINT64, UINT64, UINT8)) \
                  (DeviceInterface + 184))(DeviceInterface, (UINT64)Acb, (*pInLen == 0) ? 1 : 0);
        break;

    case 8: // ATA Non-Data (alt path - Set Features)
        gBS_copy->SetMem(Acb, 49, 0);
        Acb[7] = Asb[2] & 0x0F | 0x40;
        Acb[5] |= 0x80;
        Status = ((UINT64 (*)(UINT64, UINT64, UINT8, UINT8, UINT8, UINT8)) \
                  (DeviceInterface + 168))(DeviceInterface, ChildDevice,
                    (UINT8)Port, (UINT8)PortMultiplierPort, 0, 0);
        break;

    case 9: // ATA Read Status
        if (*(UINT32 *)(ChildDevice + 24) == 0) return EFI_UNSUPPORTED;
        gBS_copy->SetMem(Acb, 49, 0);
        Acb[7] = 0x90;
        Acb[4] = 8;
        Status = ((UINT64 (*)(UINT64, UINT64)) \
                  (DeviceInterface + 176))(DeviceInterface, (UINT64)Acb);
        break;

    case 10: // ATA DMA (alt path)
        Status = ((UINT64 (*)(UINT64, UINT64, UINT8)) \
                  (DeviceInterface + 184))(DeviceInterface, (UINT64)Acb, (*pInLen == 0) ? 1 : 0);
        break;

    case 244: // ATA Device Reset (read status to clear)
        AtaPassThruReadDeviceStatus(ChildDevice, NULL);
        Status = EFI_SUCCESS;
        break;

    default:
        Status = EFI_UNSUPPORTED;
        break;
    }

    // Read register status after command
    AtaPassThruReadDeviceStatus(ChildDevice, NULL);
    return Status;
}

//=============================================================================
// AtaPassThruGetNextPort
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruGetNextPort (
    IN     ATA_PASS_THRU_DEVICE *Device,
    IN OUT UINT16               *Port
    )
{
    if (Port == NULL) return EFI_INVALID_PARAMETER;
    if (!Device->ChannelFlag) return EFI_NOT_FOUND;

    UINT64 *PortArray = Device->PortEntries;
    if (PortArray == NULL || Device->PortCount == 0 || *PortArray == 0)
        return EFI_NOT_FOUND;

    UINT64 FirstChild   = *PortArray;
    UINT64 DeviceConfig = *(UINT64 *)(FirstChild + 848);
    UINT16 CurrentPort  = *(UINT16 *)(DeviceConfig + 228);

    if (*Port == 0xFFFF) {
        // Start: return first port
        *(UINT16 *)(DeviceConfig + 228) = *(UINT8 *)(FirstChild + 8);
        *Port = *(UINT8 *)(FirstChild + 8);
        return EFI_SUCCESS;
    }

    if (CurrentPort != *Port) return EFI_INVALID_PARAMETER;

    for (UINT8 i = 0; i < Device->PortCount; i++) {
        UINT64 Entry = PortArray[i];
        if (*(UINT8 *)(Entry + 8) > (UINT8)*Port) {
            *(UINT16 *)(DeviceConfig + 228) = *(UINT8 *)(Entry + 8);
            *Port = *(UINT8 *)(Entry + 8);
            return EFI_SUCCESS;
        }
    }

    return EFI_NOT_FOUND;
}

//=============================================================================
// AtaPassThruGetNextDevice
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruGetNextDevice (
    IN     ATA_PASS_THRU_DEVICE *Device,
    IN     UINT16                Port,
    IN OUT UINT16               *PortMultiplierPort
    )
{
    if (PortMultiplierPort == NULL) return EFI_INVALID_PARAMETER;
    if (!Device->ChannelFlag) return EFI_NOT_FOUND;

    UINT64 *PortArray = Device->PortEntries;
    if (PortArray == NULL || Device->PortCount == 0 || *PortArray == 0)
        return EFI_NOT_FOUND;

    UINT64 DeviceConfig = *(UINT64 *)(*PortArray + 848);
    UINT16 CurrentDev   = *(UINT16 *)(DeviceConfig + 230);

    if (CurrentDev == 0xFFFF) {
        // End of device list
        *(UINT16 *)(DeviceConfig + 230) = 0;
        return EFI_NOT_FOUND;
    }

    if (*PortMultiplierPort != 0xFFFF && CurrentDev != *PortMultiplierPort)
        return EFI_INVALID_PARAMETER;

    // Scan for device matching port with higher port multiplier
    for (UINT8 i = 0; i < Device->PortCount; i++) {
        UINT64 Entry = PortArray[i];
        UINT16 EntryDev = (*(UINT8 *)(Entry + 9) == 0xFF)
                          ? 0xFFFF : *(UINT8 *)(Entry + 9);
        if (*(UINT8 *)(Entry + 8) == (UINT8)Port &&
            EntryDev > *PortMultiplierPort) {
            *(UINT16 *)(DeviceConfig + 230) = EntryDev;
            *PortMultiplierPort = EntryDev;
            return EFI_SUCCESS;
        }
    }

    return EFI_NOT_FOUND;
}

//=============================================================================
// AtaPassThruBuildDevicePath
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruBuildDevicePath (
    IN     ATA_PASS_THRU_DEVICE *Device,
    IN     UINT16                Port,
    IN     UINT16                PortMultiplierPort,
    OUT    EFI_DEVICE_PATH      **DevicePath
    )
{
    *DevicePath = NULL;
    if (DevicePath == NULL) return EFI_INVALID_PARAMETER;
    if (!Device->ChannelFlag) return EFI_SUCCESS;

    EFI_STATUS Status = gBS_copy->AllocatePool(EfiBootServicesData, 10, (VOID **)DevicePath);
    if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES;

    UINT64 ChildDevice = AtaPassThruFindDevice(Device, Port, PortMultiplierPort);
    if (ChildDevice == 0) return EFI_NOT_FOUND;

    // Walk IDENTIFY data descriptor list (device + 856)
    UINT64 IdentifyData = *(UINT64 *)(ChildDevice + 856);
    if (IdentifyData == 0) return EFI_NOT_FOUND;

    UINT8 *Identify = (UINT8 *)IdentifyData;
    while (1) {
        UINT8  Type   = Identify[0] & 0x7F;
        UINT8  Sub    = Identify[1];
        UINT16 Length = *(UINT16 *)(Identify + 2);

        if (Type == 0x7F && Sub == 0xFF) break;
        if (Type == 3 && Sub == 0x12) {
            // Found ATA target descriptor: copy type+length
            gBS_copy->CopyMem(*DevicePath, Identify, 4);
            // Overwrite with port/multiplier info
            (*DevicePath)->Type[2] = (UINT8)Port;
            (*DevicePath)->Type[3] = (UINT8)PortMultiplierPort;
            // Note: the actual data written is:
            //   devpath[4..5] = Port (word)
            //   devpath[6..7] = PortMultiplierPort (word)
            return EFI_SUCCESS;
        }
        Identify += Length;
    }

    return EFI_NOT_FOUND;
}

//=============================================================================
// AtaPassThruGetDeviceFromPath
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruGetDeviceFromPath (
    IN     ATA_PASS_THRU_DEVICE *Device,
    IN     EFI_DEVICE_PATH      *DevicePath,
    OUT    UINT16               *Port,
    OUT    UINT16               *PortMultiplierPort
    )
{
    if (DevicePath == NULL || Port == NULL || PortMultiplierPort == NULL)
        return EFI_INVALID_PARAMETER;

    // Active channels use ATAPI device path (type=3, submode=18, length=10)
    if (Device->ChannelFlag) {
        if (*(UINT8 *)DevicePath == 3 &&
            *((UINT8 *)DevicePath + 1) == 0x12 &&
            *(UINT16 *)((UINT8 *)DevicePath + 2) == 10) {
            *Port               = *(UINT16 *)((UINT8 *)DevicePath + 4);
            *PortMultiplierPort = *(UINT16 *)((UINT8 *)DevicePath + 6);
            return EFI_SUCCESS;
        }
    } else {
        // Primary-only uses legacy ATA path (type=3, submode=1, length=8)
        if (*(UINT8 *)DevicePath == 3 &&
            *((UINT8 *)DevicePath + 1) == 1 &&
            *(UINT16 *)((UINT8 *)DevicePath + 2) == 8) {
            *Port               = *((UINT8 *)DevicePath + 4);
            *PortMultiplierPort = *((UINT8 *)DevicePath + 5);
            return EFI_SUCCESS;
        }
    }

    return EFI_UNSUPPORTED;
}

//=============================================================================
// AtaPassThruResetPort
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruResetPort (
    IN ATA_PASS_THRU_DEVICE *Device,
    IN UINT16                Port
    )
{
    if (!Device->ChannelFlag) return EFI_UNSUPPORTED;

    UINT64 ChildDevice = AtaPassThruFindDevice(Device, Port, 0xFFFF);
    if (ChildDevice == 0) return EFI_INVALID_PARAMETER;

    // Call device vtable + 200 (25*8) with NonData reset signature
    UINT64 DevInterface = *(UINT64 *)(ChildDevice + 848);
    return ((UINT64 (*)(UINT64, UINT64, UINT8, UINT8, UINT8, UINT8)) \
            (DevInterface + 200))(DevInterface, ChildDevice, (UINT8)Port, 0xFF, 0, 0);
}

//=============================================================================
// AtaPassThruResetDevice
//=============================================================================

EFI_STATUS
EFIAPI
AtaPassThruResetDevice (
    IN ATA_PASS_THRU_DEVICE *Device,
    IN UINT16                Port,
    IN UINT16                PortMultiplierPort
    )
{
    if (!Device->ChannelFlag) return EFI_UNSUPPORTED;

    UINT64 ChildDevice = AtaPassThruFindDevice(Device, Port, PortMultiplierPort);
    if (ChildDevice == 0) return EFI_INVALID_PARAMETER;

    // Call device vtable + 200 (25*8) with NonData reset signature
    UINT64 DevInterface = *(UINT64 *)(ChildDevice + 848);
    return ((UINT64 (*)(UINT64, UINT64, UINT8, UINT8, UINT8, UINT8)) \
            (DevInterface + 200))(DevInterface, ChildDevice, (UINT8)Port, (UINT8)PortMultiplierPort, 0, 0);
}

//=============================================================================
// AtaPassThruReportAssert
//=============================================================================

VOID
AtaPassThruReportAssert (
    IN CONST CHAR8 *FileName,
    IN UINTN        LineNumber,
    IN CONST CHAR8 *Description
    )
{
    VOID *Protocol = AtaPassThruGetDebugProtocol();
    if (Protocol != NULL) {
        ((DEBUG_SUPPORT_PROTOCOL *)Protocol)->DebugAssert(
            FileName, LineNumber, Description);
    }
}

//=============================================================================
// AtaPassThruGetDebugProtocol
//=============================================================================

STATIC VOID *
AtaPassThruGetDebugProtocol (
    VOID
    )
{
    if (gDebugProtocol == NULL) {
        // Check TPL: GetTimerValue(31), if > 0x10 return NULL
        // Note: actual implementation uses gBS->GetTimerValue
        // This pattern is AMI-specific for lazy debug protocol init
        if (gBootServices != NULL) {
            EFI_STATUS Status = gBootServices->LocateProtocol(
                        &gAtaPassThruDebugProtocolGuid, NULL, &gDebugProtocol);
            if (EFI_ERROR(Status)) gDebugProtocol = NULL;
        }
    }
    return gDebugProtocol;
}

//=============================================================================
// AtaPassThruGetHobList
//=============================================================================

EFI_HOB_HANDOFF_INFO_TABLE *
AtaPassThruGetHobList (
    VOID
    )
{
    if (gHobList == NULL) {
        UINT64 TableCount = *(UINT64 *)((UINT64)gSystemTable + 104);
        if (TableCount != 0) {
            UINT64 ConfigTable = *(UINT64 *)((UINT64)gSystemTable + 112);
            for (UINT64 i = 0; i < TableCount; i++) {
                if (AtaPassThruCompareHobGuid(
                        &gEfiHobListGuid,
                        (EFI_GUID *)(ConfigTable + 24 * i))) {
                    gHobList = (VOID *)*(UINT64 *)(ConfigTable + 24 * i + 16);
                    break;
                }
            }
        }
        if (gHobList == NULL) {
            DEBUG((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND));
            AtaPassThruReportAssert(
                "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
                54, "!EFI_ERROR (Status)");
        }
        if (gHobList == NULL) {
            AtaPassThruReportAssert(
                "e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
                55, "mHobList != ((void *) 0)");
        }
    }
    return (EFI_HOB_HANDOFF_INFO_TABLE *)gHobList;
}

//=============================================================================
// AtaPassThruReadDebugCmos
//=============================================================================

UINT32
AtaPassThruReadDebugCmos (
    VOID
    )
{
    UINT8 Prev = IoRead8(0x70);
    IoWrite8(0x70, (Prev & 0x80) | 0x4B);  // Preserve NMI, select reg 0x4B
    UINT8 Level = IoRead8(0x71);

    if ((UINT8)Level > 3) {
        if (Level == 0) {
            // Read platform config from fixed address
            Level = (*(volatile UINT8 *)0xFDAF0490 & 2) | 1;
        }
    }

    // Validate debug level (1 or 2+)
    if ((UINT8)(Level - 1) > 0xFD) return 0;

    // Return debug level mask
    // Level 1 -> 0x80000004 (EFI_D_ERROR in AMI convention)
    // Level 2+ -> 0x80000006 (EFI_D_INFO | EFI_D_ERROR in AMI convention)
    if (Level == 1) return 0x80000004;
    return 0x80000006;
}

//=============================================================================
// AtaPassThruCompareHobGuid
//=============================================================================

BOOLEAN
AtaPassThruCompareHobGuid (
    IN CONST EFI_GUID *Guid1,
    IN CONST EFI_GUID *Guid2
    )
{
    return AtaPassThruReadUnaligned64(Guid1) == AtaPassThruReadUnaligned64(Guid2) &&
           AtaPassThruReadUnaligned64((UINT8 *)Guid1 + 8) == AtaPassThruReadUnaligned64((UINT8 *)Guid2 + 8);
}

//=============================================================================
// AtaPassThruReadUnaligned64
//=============================================================================

UINT64
AtaPassThruReadUnaligned64 (
    IN CONST VOID *Buffer
    )
{
    if (Buffer == NULL) {
        AtaPassThruReportAssert(
            "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
            192, "Buffer != ((void *) 0)");
    }
    return *(UINT64 *)Buffer;
}

//=============================================================================
// AtaPassThruCpuid
//=============================================================================

UINT32
AtaPassThruCpuid (
    UINT32  Function,
    UINT32  *Eax OPTIONAL,
    UINT32  *Ebx OPTIONAL,
    UINT32  *Ecx OPTIONAL,
    UINT32  *Edx OPTIONAL
    )
{
    UINT32 Regs[4];
    AsmCpuid(Function, &Regs[0], &Regs[1], &Regs[2], &Regs[3]);

    if (Eax != NULL) *Eax = Regs[0];
    if (Ebx != NULL) *Ebx = Regs[1];
    if (Ecx != NULL) *Ecx = Regs[2];
    if (Edx != NULL) *Edx = Regs[3];

    return Regs[0];
}

//=============================================================================
// AtaPassThruSetMem32Pattern
//=============================================================================

VOID *
AtaPassThruSetMem32Pattern (
    VOID    *Buffer,
    INT32   Value,
    UINTN   Count
    )
{
    UINT8   *ByteBuf = (UINT8 *)Buffer;
    UINT32  Pattern;
    UINTN   AlignedBytes;

    // Build 32-bit repeating pattern from low 16 bits
    Pattern  = (UINT32)(Value & 0xFFFF) | ((UINT32)(Value & 0xFFFF) << 8);
    Pattern  = Pattern | (Pattern << 16);

    // Handle unaligned head
    AlignedBytes = (UINTN)ByteBuf & 3;
    if (AlignedBytes != 0) {
        AlignedBytes = 4 - AlignedBytes;
        if (AlignedBytes > Count) {
            AlignedBytes = Count;
        }
        SetMem(ByteBuf, AlignedBytes, (UINT8)Value);
        ByteBuf += AlignedBytes;
        Count   -= AlignedBytes;
    }

    // Fill aligned portion with 32-bit pattern
    {
        UINTN Index;
        for (Index = Count >> 2; Index > 0; Index--) {
            *(UINT32 *)ByteBuf = Pattern;
            ByteBuf += 4;
        }
    }

    // Trailing bytes
    Count &= 3;
    if (Count > 0) {
        SetMem(ByteBuf, Count, (UINT8)Value);
    }

    return Buffer;
}

//=============================================================================
// AtaPassThruCopyMemOverlap - overlapping-safe memmove
//=============================================================================

VOID *
AtaPassThruCopyMemOverlap (
    VOID        *Destination,
    CONST VOID  *Source,
    UINTN       Count
    )
{
    UINT8       *Dst = (UINT8 *)Destination;
    const UINT8 *Src = (const UINT8 *)Source;
    BOOLEAN      Reverse = FALSE;

    // Detect backward overlap: src < dst and src+count > dst
    if (Src < Dst && Src + Count > Dst) {
        Reverse = TRUE;
        Src  += Count;
        Dst  += Count;
    }

    // Fast path for aligned >= 8 byte copy
    if (Count >= 8 && ((UINTN)Dst - (UINTN)Src) >= 8) {
        UINTN Align = (UINTN)Src & 7;

        // Match source/dest alignment for head
        if (Align != 0 && ((UINTN)Dst & 7) == Align) {
            UINTN Head = Reverse ? Align : (8 - Align);
            CopyMem(Dst, Src, Head);
            if (!Reverse) {
                Src  += Head;
                Dst  += Head;
                Count -= Head;
            } else {
                Src  -= Head;
                Dst  -= Head;
                Count -= Head;
            }
        }

        // Reverse copy alignment fixup
        if (Reverse) {
            Src -= 7;
            Dst -= 7;
        }

        // Copy 8-byte chunks
        {
            UINTN Qwords = Count >> 3;
            CopyMem(Dst, Src, Qwords << 3);
            Src  += Qwords << 3;
            Dst  += Qwords << 3;
            Count &= 7;
        }
    }

    // Remaining bytes
    if (Count > 0) {
        if (Reverse) {
            Src += 8;
            Dst += 8;
            Src--;
            Dst--;
        }
        CopyMem(Dst, Src, Count);
    }

    return Destination;
}

//=============================================================================
// END AtaPassThru.c
//=============================================================================