Newer
Older
AMI-Aptio-BIOS-Reversed / AhciSmm / AhciSmm.md
@Ajax Dong Ajax Dong 2 days ago 17 KB Init

AhciSmm Module

Overview

UEFI SMM (System Management Mode) driver for AHCI (Advanced Host Controller Interface) controller management. This module provides SMI-based AHCI port configuration, command execution, error handling, and device presence detection within the SMM environment. It is compiled from AmiModulePkg/AHCI/AhciSmm/AhciSmm.c and resides in the DXE_SMM_DRIVER dispatch phase. The driver manages AHCI ports via MMIO register access, SATA FIS (Frame Information Structure) processing, port multiplier support, and generates SMI callbacks for ATA command execution in SMM.

Address Range

0x2A0 - 0x2830 (41 functions)

Key Functions

Address Name Purpose
0x470 _ModuleEntryPoint UEFI/SMM driver entry point
0x49C sub_49C UEFI boot/run-time services table initialization
0x5DC sub_5DC Main driver dispatch: lock, init, register SMI handler
0x2150 sub_2150 SMM driver initialization: locate protocols, init H/W, install SMI handlers
0x1F0C sub_1F0C SMI handler registration: allocate buffers, register SMI callback via SMM base2
0x13F4 sub_13F4 Soft reset generation for AHCI port (GenerateSoftReset)
0x1F04 sub_1F04 Thunk to sub_13F4 (soft reset)
0x19FC sub_19FC ATA command completions: read FIS, detect PMP/SATA/ATAPI device type
0x1BB8 sub_1BB8 ATA non-data command execution (identify device, etc.)
0x1648 sub_1648 ATA PIO data-in command execution
0x17C0 sub_17C0 ATA DMA command execution
0x1914 sub_1914 ATA software reset execution
0x1D60 sub_1D60 AHCI controller initialization (HBA reset, port config)
0x1EBC sub_1EBC Port FIS receive / command completion dispatch
0xC0C sub_C0C Port command completion handler (FIS receive + SDB notify)
0xE30 sub_E30 AHCI port start/stop (command list activation, PxCMD.PxRUN)
0x1014 sub_1014 Port PMP status check and error recovery via sub_C0C
0x1274 sub_1274 Port multiplier register access (PMP SATA register read/write)
0x9D0 sub_9D0 Port reset sequence (wait for device ready, signature, PxSIG)
0x91C sub_91C Command issue helper: write PxCMD, clear SError, trigger port start
0x11BC sub_11BC Command list entry setup (FIS frame format into PRDT)
0x111C sub_111C Command scatter-gather list construction (PRDT entries)
0x10C8 sub_10C8 FIS shadow area copy (16 bytes from command table to RFIS)
0x107C sub_107C Command header initialization (clear PRD region, set PxISA)
0x7D0 sub_7D0 Polling loop for command completion / error (PxIS, PxSERR, timeout)
0x75C sub_75C MMIO register bit wait loop (poll for bit clear with timeout)
0x6E4 sub_6E4 MMIO register bit match polling (poll for specific bit pattern)
0x9D0 sub_9D0 Port signature read (poll PxSIG for device type detection)
0x690 sub_690 Microsecond delay based on ACPI PM timer (port 0x508)
0x2720 sub_2720 memset implementation (aligned dword fill with residual)
0x2780 sub_2780 memmove implementation (overlap-aware, aligned copy)
0x2314 sub_2314 Debug logging (vprintf to SMM debug output)
0x235C sub_235C ASSERT implementation (conditional via debug protocol)
0x22C4 sub_22C4 SMM debug protocol locator (locate gEfiSmmDebug2ProtocolGuid)
0x239C sub_239C PCD protocol locator (DxePcdLib, locate mMdePkgPcd)
0x2428 sub_2428 SMM child protocol installation (SmmBase2 vs BootServices LocateProtocol)
0x24B0 sub_24B0 SMI handler protocol installation (SmmBase2 or standalone)
0x2594 sub_2594 Runtime services pointer resolution via SMM system table
0x2604 sub_2604 memcmp implementation (byte compare against fixed pattern)
0x2680 sub_2680 CMOS/CMOS register read for platform debug level detection
0x2A0 sub_2A0 SetJump wrapper (save non-volatile register context)
0x340 sub_340 LongJump wrapper (restore context via saved frame)
0x227C sub_227C Jump buffer validation (alignment check for SetJump)

Entry Points (Public API)

  • 0x470 _ModuleEntryPoint: Standard UEFI SMM driver entry point. Calls sub_49C to initialize UEFI boot/runtime services globals, then calls sub_5DC which handles the SMM dispatch table registration.

  • 0x2150 sub_2150: SMM driver initialization. Locates gEfiSmmCpuIo2ProtocolGuid protocol at GUID unk_2E30, probes presence via call into qword_2EB0+8, resolves runtime services via sub_2594, installs child protocols via sub_2428 and sub_24B0, then calls sub_1F0C to register the SMI handler.

  • 0x1D60 sub_1D60: AHCI controller HBA-level initialization. Programs port registers (PxCMD start, PxIE interrupt enable, PxSERR clear, PxCFG), sets command list/FIS base addresses via qword_3018. Called via function pointer stored at psub_1D60 (0x3070).

Internal Helpers

  • AHCI Low-Level MMIO:

    • 0x75C sub_75C: Polls an AHCI port MMIO register, waiting for a bitmask to clear with configurable timeout. Base register = a1 + ((a2 + 2) << 7) where a2 is port number.
    • 0x6E4 sub_6E4: Polls an AHCI port MMIO register, waiting for (reg_value & mask) == match_value. Used for status transitions.
    • 0x690 sub_690: Microsecond delay using ACPI PM timer I/O port 0x508. Calculates delay based on timer ticks.
    • 0x1274 sub_1274: SATA port multiplier register access. Builds a PMP register read/write FIS, sends it via command list, waits for completion, reads result from RFIS buffer.
  • Command Processing Pipeline:

    • 0x11BC sub_11BC: Builds a command list entry (49 bytes FIS frame starting at a4+0). Sets command FIS type, port multiplier, ATA registers (features, sector count, LBA, command). Sets CFL=5 and W=1 bits in PxCMD.
    • 0x111C sub_111C: Constructs PRDT (Physical Region Descriptor Table) entries. Walks the data buffer scatter-gather list, setting DBA/DBC/DI bits per 4MB-aligned region. Last entry gets EOF flag.
    • 0x107C sub_107C: Initializes a command header slot. Zeroes PRD region. Sets PxISA (port multiplier) bits. Sets PRDTL (PRD table length).
    • 0x10C8 sub_10C8: Copies 16 bytes from command FIS to received FIS (RFIS) area in the command table. Handles overlap-safe copy.
  • ATA Command Execution:

    • 0x1648 sub_1648: ATA PIO data-in command (READ SECTOR(S), IDENTIFY, etc.). Calls sub_E30 (port start), sub_1014 (PMP check), builds FIS, issues command, polls completion via sub_7D0.
    • 0x17C0 sub_17C0: ATA DMA command (READ DMA, WRITE DMA). Similar flow to PIO but for DMA transfers.
    • 0x1914 sub_1914: ATA software reset command. Sends SRST via command list, polls completion.
    • 0x1EBC sub_1EBC: Port FIS receive handler. Extracts port number and PMP status from register, dispatches to sub_C0C for command completion processing.
    • 0x1BB8 sub_1BB8: ATA non-data command execution. Used for IDENTIFY DEVICE, SET FEATURES, etc. Builds FIS, issues command, polls completion. On error with specific conditions, retries via sub_19FC.
  • AHCI Port Management:

    • 0xE30 sub_E30: Port start/stop. Saves/restores command list and FIS base addresses (stored in qword_3010/qword_3018). Stops PxCMD.PxRUN, clears PxCMD.ST, calls sub_C0C for error recovery if needed, restores base registers.
    • 0x91C sub_91C: Port command issue. Clears PxSERR, sets PxIE, starts port via PxCMD.PxRUN, waits for PxCMD.PxGO. Clears command slot and receiver buffers.
    • 0x7D0 sub_7D0: Command completion polling. Monitors PxIS (interrupt status) and PxSERR (error status) with timeout. Returns error on BSY/DRQ bits or timeout.
    • 0x1014 sub_1014: Checks port multiplier status (PxSSTS.DET). If device not present, returns success. If error, calls sub_C0C for recovery.
  • Debug and Error Handling:

    • 0x2314 sub_2314: Debug/log message printf. Calls sub_22C4 to get SMM debug2 protocol, checks debug mask from sub_2680, and prints via protocol's vprintf.
    • 0x235C sub_235C: ASSERT implementation. Calls sub_22C4 for debug protocol, then calls the protocol's assert handler with file/line/message.
    • 0x22C4 sub_22C4: Locates gEfiSmmDebug2ProtocolGuid via SMM system table. Caches in qword_2E98.
    • 0x2680 sub_2680: Reads CMOS register 0x4C to determine platform debug level. Returns EFI debug masks (0x8000000C or 0x80000006) based on value.
    • 0x2604 sub_2604: memcmp against a fixed pattern at unk_2E40 (16 bytes). Used for runtime services table scanning.
    • 0x2594 sub_2594: Resolves EFI runtime services pointer by scanning SMM system table's SMM runtime services table for a non-NULL entry.
  • Port Reset:

    • 0x9D0 sub_9D0: Complete port reset sequence. Polls PxSIG for device signature (ATA, ATAPI, PMP), waits for PxCMD.PxGO and BSY clear, checks PxSERR error bits. Returns status based on device detection.
    • 0x13F4 sub_13F4: Soft reset. Stops port, sends SRST FIS, waits for completion, starts port, checks signature.
    • 0xC0C sub_C0C: Port command completion handler. Called by sub_1EBC. Programs the command list base, clears PxSERR, sends SDB (Set Device Bits) FIS notification, triggers port reset via sub_9D0 if needed. Works with port multipliers.
  • Library Functions:

    • 0x2720 sub_2720: memset - aligned dword fill with residual byte fill.
    • 0x2780 sub_2780: memmove - overlap-safe memory copy. Checks src/dst overlap direction (forward/backward), uses aligned qword copy for large blocks.
    • 0x2A0 sub_2A0: SetJump - saves all non-volatile registers (rbx, rbp, rdi, rsi, r12-r15), MXCSR, and XMM6-XMM15. Stores at offset 0x72 for return address.
    • 0x340 sub_340: LongJump - restores MXCSR from saved frame, jumps to saved return address.

State Management

SMM Protocol Cache (initialized in sub_49C/sub_2150):

  • qword_2E80 (0x2E80): gImageHandle (cached)
  • qword_2E70 (0x2E70): gST (SystemTable)
  • qword_2E78 (0x2E78): gBS (BootServices)
  • qword_2E88 (0x2E88): gRT (RuntimeServices)
  • qword_2E90 (0x2E90): gSmst (SMM System Table)
  • qword_2EA0 (0x2EA0): mPcd (PCD protocol, resolved lazily)

SMM Driver Globals (initialized in sub_2150):

  • qword_2EB0 (0x2EB0): SMM CPU I/O2 protocol instance
  • byte_2EB8 (0x2EB8): SMM mode flag (1 = SMM, 0 = DXE)
  • qword_2EE8 (0x2EE8): SmmServicesTableBase2 protocol
  • qword_2EC0 (0x2EC0): SMM child protocol (in SMM)
  • qword_2ED8 (0x2ED8): Protocol in DXE (BootServices)
  • qword_2ED0 (0x2ED0): SMI handler protocol (in SMM)
  • qword_2EF0 (0x2EF0): SMI handler protocol (in DXE)
  • byte_2EC8 (0x2EC8): Protocol ready flag

AHCI Hardware State:

  • qword_3010 (0x3010): Saved PxCLB (command list base address) during port stop
  • qword_3018 (0x3018): Saved PxFB (FIS base address) during port stop
  • qword_3008 (0x3008): Driver return status
  • byte_2E60 (0x2E60): Reentry guard for sub_C0C (port complete handler)
  • byte_2E61 (0x2E61): Reentry guard for sub_13F4 (soft reset)
  • dword_3020 (0x3020): SMI callback registration handle

SMI Handler Function Pointers (at 0x3070-0x30A0):

  • psub_1D60 (0x3070): HBA initialization handler
  • psub_17C0 (0x3078): ATA DMA command handler
  • psub_1648 (0x3080): ATA PIO data-in command handler
  • psub_1914 (0x3088): ATA software reset handler
  • psub_1BB8 (0x3090): ATA non-data command handler
  • psub_1F04 (0x30A0): ATA soft reset (port-level) handler
  • psub_1EBC (0x3098): FIS receive / command completion handler

Buffers (allocated in sub_1F0C):

  • buf at qword_2E68 (0x2E68): 256-byte buffer for command response data
  • qword_3038 (0x3038): 256-byte command list for SMM
  • qword_3030 (0x3030): 1024-byte AHCI receive area
  • qword_3028 (0x3028): 1152-byte AHCI command table

Data Structures

AHCI Port Context (a1 pointer, at least 40 bytes):
Offset | Size | Field | Description |
--------|------|-------|-------------|
+0 | 4 | HBA_BASE | AHCI controller MMIO base address |
+4 | 4 | RESERVED | Padding |
+8 | 8 | RFIS_BUF_NEXT | Received FIS buffer physical address (next slot) |
+16 | 8 | CMD_LIST | Command list physical address |
+24 | 4 | CMD_TBL_SIZE | Command table size (upper 32 bits of RFIS address) |
+28 | 4 | port_status | Port status / register value |
+32 | 1 | port | Port number |
+33 | 1 | port_mult | Port multiplier (0xFF = none) |
+34 | 2 | RESERVED | Padding |
+36 | 4 | timeout | Timeout value in milliseconds |

AHCI Port Register Layout (per port, 128 bytes each, base + (port+2) << 7):
Offset | Register | Description |
--------|----------|-------------|
+0 | PxCLB | Command list base address (lower 32 bits) |
+4 | PxCLBU | Command list base address (upper 32 bits) |
+8 | PxFB | FIS base address (lower 32 bits) |
+12 | PxFBU | FIS base address (upper 32 bits) |
+16 | PxIS | Interrupt status register |
+20 | PxIE | Interrupt enable register |
+24 | PxCMD | Command and status register |
+28 | RESERVED | - |
+32 | PxSSTS | Serial ATA status (SCR0) |
+36 | PxSCTL | Serial ATA control (SCR2) |
+40 | PxSERR | Serial ATA error (SCR1) |
+44 | PxSACT | Serial ATA active (SCR3) |
+48 | PxCI | Command issue register |
+52 | PxSNTF | Serial ATA notification (SCR4) |
+56 | PxFBS | FIS-based switching |

FIS Frame Structure (49 bytes, built by sub_11BC):
Offset | Size | Field |
--------|------|-------|
+0 | 1 | FIS type (0x27 = register H2D) |
+1 | 1 | PM port (lower nibble) + C=1 bit |
+2 | 1 | Command (CFL in upper nibble) |
+3 | 1 | Features |
+4 | 1 | Sector count (byte 0) |
+8 | 1 | Sector count (byte 1) |
+12 | 1 | LBA low (byte 0) |
+13 | 1 | LBA low (byte 1) |
+14 | 1 | LBA mid (byte 0) |
+15 | 1 | LBA mid (byte 1) |
+16 | 1 | LBA high (byte 0) |
+17 | 1 | LBA high (byte 1) |
+18 | 1 | Device register |
+19 | 1 | Command register |
+20 | 1 | Reserved |
+21 | 1 | Reserved |
+22 | 1 | Control (0xA0 = device reset) |
+23 | 1 | Reserved (low bit = PM port valid) |

Jump Buffer Structure (248+ bytes, managed by sub_2A0/sub_340):
Offset | Register |
--------|----------|
+0 | rbx |
+8 | Return address (from retaddr) |
+16 | rbp |
+24 | rdi |
+32 | rsi |
+40 | r12 |
+48 | r13 |
+56 | r14 |
+64 | r15 |
+72 | Function pointer (return target) |
+80 | MXCSR |
+88 | xmm6 |
+104 | xmm7 |
+120 | xmm8 |
+136 | xmm9 |
+152 | xmm10 |
+168 | xmm11 |
+184 | xmm12 |
+200 | xmm13 |
+216 | xmm14 |
+232 | xmm15 |

Calling Patterns

  1. Driver Entry and Initialization:
    _ModuleEntryPoint -> sub_49C (init UEFI globals) -> sub_5DC (main dispatch)

  2. SMM Driver Registration (sub_5DC flow):
    sub_5DC -> sub_2A0 (SetJump/lock) -> sub_2150 (init SMM) -> sub_227C (validate) -> sub_340 (LongJump/unlock)

  3. SMM Initialization Chain (sub_2150):
    sub_2150 -> sub_239C (PCD) -> LocateProtocol(SmmCpuIo2) -> Probe -> sub_2594 (Runtime) -> sub_2428 (child proto) -> sub_24B0 (SMI handler) -> sub_1F0C (register callback)

  4. SMI Handler Registration (sub_1F0C):
    Allocate buffer -> zero -> sub_2720 (memset) -> Set function pointers -> Locate SMM base2 -> Register SmiHandler with GUID unk_2DF0 -> Return

  5. ATA Command Execution Flow:
    sub_1648/sub_17C0/sub_1914/sub_1BB8:

    • sub_E30 (start port, arg=1)
    • sub_1014 (PMP check)
    • sub_107C (init cmd header)
    • sub_11BC (write FIS to command list)
    • sub_91C (issue command / start DMA)
    • sub_7D0 (poll for completion)
    • sub_E30 (stop port, arg=0)
  6. Command Completion Path:
    sub_1EBC -> sub_C0C -> sub_9D0 (port reset if error)

  7. Debug Logging:
    sub_2314 -> sub_22C4 (locate debug protocol) -> sub_2680 (check CMOS debug level) -> protocol vprintf

  8. Soft Reset Flow:
    sub_13F4 (or thunked via sub_1F04):

    • Check reentry guard (byte_2E61)
    • sub_E30 (start port)
    • sub_107C + sub_11BC (build SRST FIS)
    • sub_91C (issue)
    • Poll PxCMD.PxRUN
    • sub_690 (100us delay)
    • Re-read FIS
    • sub_7D0 (poll command completion with 30s timeout)
    • sub_E30 (stop port)

Dependencies

Consumed (this module calls)

  • SMM System Table (gSmst): LocateProtocol, SmiHandlerRegister (via qword_2EE8 offsets 208, etc.)
  • UEFI Boot Services (gBS): LocateProtocol, AllocatePages (offset 64), Stall (offset 24/32)
  • SMM Debug2 Protocol: sub_22C4 locates at unk_2DE0 (gEfiSmmDebug2ProtocolGuid), used for assert/debug print
  • SMM CPU I/O2 Protocol: sub_2150 locates at unk_2E30, used for SMM I/O operations
  • PCD Protocol: sub_239C locates at unk_2DD0 (gEfiPcdProtocolGuid)
  • ACPI PM Timer: I/O port 0x508 for microsecond delays in sub_690
  • CMOS: I/O ports 0x70/0x71 for debug level detection in sub_2680
  • SMM Runtime Services Table: Scanned in sub_2594 for EFI runtime services pointer

Consumed By (other modules call this)

  • UEFI SMM Dispatcher: Calls _ModuleEntryPoint as standard SMM driver entry point
  • SMI Callback Infrastructure: The registered SMI handler (via sub_1F0C) is invoked by the SMM core when the AHCI SMI is triggered

Notes

  • The module supports both SMM and non-SMM (DXE) modes, detected via byte_2EB8. In DXE mode, it uses BootServices directly; in SMM mode, it uses SmmServicesTableBase2.
  • Port multiplier (PMP) support is indicated by port_mult == 0xFF meaning no PMP, otherwise 0-15.
  • ATA command types are encoded in the context byte at offset +55: 0=unknown, 1=ATAPI, 2=PM, 3/4/5/6/7=other device types.
  • All MMIO register accesses use a port-relative addressing scheme: base + ((port + 2) << 7) for 128-byte port register blocks.
  • The PRDT construction in sub_111C uses 4MB-aligned region descriptors with DBC field limiting to 4MB minus 1 per descriptor.
  • Command completion polling (sub_7D0) has timeout of 30000ms for most commands, 1000ms for PMP register access.
  • Reentry guards (byte_2E60, byte_2E61) prevent recursive calls into the port completion and soft reset handlers.
  • The debug print level is controlled by CMOS register 0x4C (bitmask), read via I/O ports 0x70/0x71.
  • Function pointer table at 0x3070-0x30A0 is populated during initialization in sub_1F0C and used by the SMI dispatch to route ATA commands.