// 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 (0x370)
//=============================================================================
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 (sub_41C, 0x41C)
//=============================================================================
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 (sub_4FC, 0x4FC)
//=============================================================================
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 (sub_730, 0x730)
//=============================================================================
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 (sub_79C, 0x79C)
//=============================================================================
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 (sub_7D4, 0x7D4)
//=============================================================================
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 (sub_854, 0x854)
//=============================================================================
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 (sub_960, 0x960)
//=============================================================================
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 (sub_D88, 0xD88)
//=============================================================================
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 (sub_E5C, 0xE5C)
//=============================================================================
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 (sub_F88, 0xF88)
//=============================================================================
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 (sub_10A0, 0x10A0)
//=============================================================================
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 (sub_1128, 0x1128)
//=============================================================================
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 (sub_1188, 0x1188)
//=============================================================================
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 (sub_12A8, 0x12A8)
//=============================================================================
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 (sub_11E0, 0x11E0)
//=============================================================================
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 (sub_12E8, 0x12E8)
//=============================================================================
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 (sub_13C0, 0x13C0)
//=============================================================================
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 (sub_1410, 0x1410)
//=============================================================================
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 (sub_1480, 0x1480)
//=============================================================================
UINT64
AtaPassThruReadUnaligned64 (
IN CONST VOID *Buffer
)
{
if (Buffer == NULL) {
AtaPassThruReportAssert(
"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
192, "Buffer != ((void *) 0)");
}
return *(UINT64 *)Buffer;
}
//=============================================================================
// CpuidWrapper (sub_14B0, 0x14B0)
//=============================================================================
UINT32
CpuidWrapper (
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];
}
//=============================================================================
// Memset32Pattern (sub_14F0, 0x14F0)
//=============================================================================
VOID *
Memset32Pattern (
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;
}
//=============================================================================
// InternalMemcpy (sub_1550, 0x1550) - overlapping-safe memmove
//=============================================================================
VOID *
InternalMemcpy (
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
//=============================================================================