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

WdtDxe Module

Overview

Watchdog Timer (WDT) DXE driver for the Intel Purley PCH (South Cluster LBG). Programs the PCH watchdog timer registers via IO ports, manages timer reload/start/stop before OS boot, and hooks into BDS/ReadyToBoot event notification.

Address Range

0x390 - 0x1075 (26 functions)

IDA Port

13338

Image

0178_WdtDxe_9af0b6f4206b/WdtDxe.efi (PE32+ X64, UEFI DXE driver)

Key Functions

Address Name Purpose
0x390 _ModuleEntryPoint DXE entry point: calls init then registration
0x3AC sub_3AC UEFI boot/runtime services init + protocol locates
0x578 sub_578 Main registration: installs timer event + notify callbacks
0x704 sub_704 WDT runtime handler: runs before OS boot (TimerCallback)
0x85C sub_85C WDT allow-known-reset entry point (wrapper for sub_E38)
0x86C sub_86C IO port 32-bit read wrapper (__indword)
0x89C sub_89C IO port 32-bit write wrapper (__outdword)
0x8DC sub_8DC DebugLib singleton: locate and cache debug protocol
0x95C sub_95C DebugPrint wrapper with CMOS-based debug level filtering
0x9E4 sub_9E4 DebugAssert wrapper
0xA24 sub_A24 UEFI config table lookup by GUID (EfiGetSystemConfigurationTable)
0xAE8 sub_AE8 LegacyBoot event registration (EfiCreateEventLegacyBootEx)
0xB8C sub_B8C PCH MMIO PCI config space read (cycle decoding base)
0xBBC sub_BBC HOB list singleton: locate and cache gEfiHobListGuid
0xC40 sub_C40 HOB traversal: find gEfiHobListGuid / HOB type 4
0xC90 sub_C90 Get WDT timer IO base address from PCH cycle decoding
0xCEC sub_CEC ReloadAndStartTimer: program WDT counter + enable
0xD94 sub_D94 DisableTimer: clear WDT enable bit
0xDD4 sub_DD4 CheckTimerStatus: read back WDT status register
0xE38 sub_E38 AllowKnownReset: set debug flag + clear known-reset bit
0xE80 sub_E80 IsWdtRequired: check if WDT is required (bit 22-23 mask)
0xED4 sub_ED4 IsWdtEnabled: check if WDT is currently enabled (bit 14)
0xF28 sub_F28 PCD protocol singleton: locate and cache PCD protocol
0xFB4 sub_FB4 GUID comparison (16-byte compare via ReadUnaligned64)
0x101C sub_101C ReadUnaligned64 wrapper
0x104C sub_104C ReadUnaligned16 wrapper (with alignment assert)

Entry Points (Public API)

  • 0x390 _ModuleEntryPoint: Standard UEFI DXE entry point. Calls sub_3AC (init) then sub_578 (registration). Returns EFI_STATUS.

  • 0x85C sub_85C: Called externally to allow known WDT reset. Delegates to sub_E38. This is the public interface for AllowKnownReset functionality.

Internal Helpers

WDT Timer Operations (IO port register access)

  • 0xC90 sub_C90: Resolves the WDT timer's IO base address by reading the PCH's LPC IO decode registers via MMIO PCI config space (offset +0x84 from cycle decoding base). Returns (pci_reg & 0xFFFC) + 0x54. This is the PCH WDT timer base at IO port 0x54 (+ 0x84 = 0xA0 = TCO Base).
  • 0xCEC sub_CEC: Programs the WDT counter (10-bit value, max 1023). Sets bit 15 (TCO_RLD) and bit 14 (TCO_TMR_HALT) if not debug BIOS, enables timer by setting bit 31. Disabled in debug BIOS (sets bit 22).
  • 0xD94 sub_D94: Clears bits 14-15 (disables timer) and bit 22. Does NOT touch the WDT_IRQ bit (bit 17).
  • 0xDD4 sub_DD4: Reads timer status; returns 1 if bit 23 (TIMEOUT) is set, 0 otherwise.
  • 0xE38 sub_E38: Sets byte_1A28 = 1, then clears bit 17 (WDT_IRQ / SMI) while keeping enable state.
  • 0xE80 sub_E80: Checks bits 22-23 (0x3F0000 mask). Returns 1 if any set, meaning a prior boot timed out or had WDT fault.
  • 0xED4 sub_ED4: Checks bit 14 (TCO_TMR_HALT). Returns 1 if timer is NOT halted (i.e., enabled).

IO Port Access

  • 0x86C sub_86C: __indword(port) -- aligned DWORD IO read.
  • 0x89C sub_89C: __outdword(port, value) -- aligned DWORD IO write.

Memory Access

  • 0x104C sub_104C: *(uint16 *)addr with alignment assert.
  • 0x101C sub_101C: *(uint64 *)addr with null check.

Debug Output

  • 0x8DC sub_8DC: Lazily locates the EFI_DEBUG_PROTOCOL via BootServices->LocateProtocol on first call, caches in qword_1A08.
  • 0x95C sub_95C: DebugPrint with CMOS-based severity filter. Reads CMOS 0x4B to get debug level. If level > 3, checks 0xFDAF0490 bit 1 for chipset override. Maps level to mask (EFI_D_ERROR for level 1, EFI_D_WARN for others) and calls protocol's DebugPrint.
  • 0x9E4 sub_9E4: DebugAssert. Calls protocol's Assert at index 8.

Initialization (sub_3AC flow)

  • Stores ImageHandle, SystemTable, BootServices, RuntimeServices in globals.
  • Locates DxeServicesTable (gDS) via config table lookup.
  • Locates MmPciBase protocol (mPciUsra) via LocateProtocol for PCH cycle decoding.
  • Initializes HOB list via sub_BBC.
  • Initializes PCD protocol via sub_F28.
  • Calls sub_F28()+32(5) -- reads PCD token 5 (likely PcdWdtTimeout or similar).

State Management

.data Section Globals

Address Name Purpose
0x19E8 SystemTable Cached EFI_SYSTEM_TABLE pointer
0x19F0 BootServices Cached gBS pointer
0x19F8 ImageHandle Cached driver image handle
0x1A00 RuntimeServices Cached gRT pointer
0x1A08 qword_1A08 EFI_DEBUG_PROTOCOL (lazy init)
0x1A10 qword_1A10 DxeServicesTable (gDS)
0x1A18 qword_1A18 MmPci base protocol (mPciUsra)
0x1A20 qword_1A20 HOB list pointer (mHobList)
0x1A28 byte_1A28 WDT debug flag: disables WDT in debug BIOS builds
0x1A30 qword_1A30 PCD protocol pointer (mPcd)
0x1A40 ImageHandle_0 Image handle for event registration (NotifyTpl)

.data Section Unnamed Data (0x1920 - 0x1960)

  • 0x1920 (40 bytes): EFI_DEVICE_PATH_PROTOCOL GUID for MmPci base device path
  • 0x1930 (40 bytes): MmPci base protocol GUID
  • 0x1950 (40 bytes): PCD protocol GUID
  • 0x1970 (40 bytes): gEfiHobListGuid
  • 0x1980 (40 bytes): ReadyToBoot event GUID
  • 0x1990 (40 bytes): DxeServicesTable GUID
  • 0x19A0 (40 bytes): LegacyBoot event GUID
  • 0x19B0 (8 bytes): Function pointer: sub_D94 (DisableTimer) -- LegacyBoot notify
  • 0x19B8 (8 bytes): Function pointer: sub_704 (RunWdtBeforeOsBoot) -- ReadyToBoot notify
  • 0x19C0-0x19E0 (24 bytes): Function pointers referenced in registration calls

Data Structures

CMOS Debug Level (RTC CMOS 0x4B)

  • Offset 0: bit 7 = lock bit; bits 6-0 = debug level
  • Level 0-3: standard debug masks
  • Level >3: chipset override via MMIO 0xFDAF0490 bit 1, falls back to level 1

PCH WDT Timer Registers (IO mapped, base at TCOBASE + 0x54)

  • TCOBASE derived from PCH LPC I/O decode registers (PCI config offset +0x84)
  • Offset +0: TCO1_CNT (WDT control register)
    • Bit 31: TCO_TMR_EN (timer enable)
    • Bits 23-22: WDT status (SOFTWARE_FAULT, TIMEOUT)
    • Bit 17: WDT_IRQ (SMI/NMI routing)
    • Bit 16: TCO_IRQ_EN (interrupt enable)
    • Bit 15: TCO_RLD (reload)
    • Bit 14: TCO_TMR_HALT (halt timer)
    • Bits 9-0: TCO_TMR (counter value, 10-bit, 0=1024)
  • WDT counter formula: (counter - 1) programmed into bits 9-0
  • 600 ticks = ~5 seconds at typical 83ms tick rate

Calling Patterns

  1. Init flow: _ModuleEntryPoint -> sub_3AC (protocols, tables, PCD) -> sub_578 (register callbacks)
  2. ReadyToBoot: Boot services fires -> sub_704 (TimerCallback):
    • Disable event notifications -> locate HOB -> find EFI_RESOURCE_HOB -> check WDT required -> reload and start timer with PCH-specific timeout
  3. LegacyBoot: Boot services fires -> off_19B0 (sub_D94): disable WDT timer
  4. External API: sub_85C -> sub_E38: allow known reset (debug path)

sub_704 (TimerCallback) Detailed Flow

  1. Restore TPL (raise to CALLBACK then restore)
  2. Unregister both ReadyToBoot and LegacyBoot events
  3. Get HOB list -> find Hand-Off HOB (type 1) -> extract ResourceId (field +12)
  4. Get PCH cycle decoding base -> iterate PCI devices matching PCH VID/DID
  5. Compute WDT timer base -> read existing timer config
  6. Compute default timeout: 16 * (HIWORD(timer_val) & 0x3F) -- derived from existing prescaler
  7. If ResourceId == 5 (BDS phase) and HOB byte at +26 == 1 (WDT required):
    • Program timer with calculated timeout or fallback 600
  8. If ResourceId != 5 but timeout > 0:
    • Reprogram timer with new timeout value
  9. Otherwise: disable WDT timer entirely

Dependencies

Consumed (this module calls)

  • UefiBootServicesTableLib -- gImageHandle, gST, gBS, gRT globals
  • DxeServicesTableLib -- gDS config table
  • DxeMmPciBaseLib -- MmPci base protocol for PCH cycle decoding
  • DxeHobLib -- HOB traversal (mHobList)
  • DxePcdLib -- PCD protocol access (mPcd)
  • UefiLib -- EfiGetSystemConfigurationTable, EfiCreateEventLegacyBootEx
  • BaseIoLibIntrinsic -- indword/outdword (IO ports)
  • BaseLib -- ReadUnaligned64/ReadUnaligned16
  • Hardware IO ports:
    • CMOS RTC ports 0x70/0x71 (debug level)
    • PCH WDT IO port (TCOBASE + 0x54, typically 0x410 or 0x440)

Consumed By (other modules call this)

  • DXE Foundation -- calls _ModuleEntryPoint on driver load
  • BDS Phase -- receives sub_704 via ReadyToBoot event notification
  • LegacyBoot -- receives sub_D94 via LegacyBoot event notification
  • External modules can call sub_85C to allow known WDT reset

Strings

  • (Wdt) Entry Point to WdtDxe -- driver startup
  • (Wdt) WDT event registration; Status = %r -- event registration result
  • (Wdt) RunWdtBeforeOsBoot -- timer callback entry
  • (Wdt) Handoff Hob missing! -- HOB not found during timer callback
  • (Wdt) ReloadAndStartTimer(%d) -- timer being programmed
  • (Wdt) Wdt disabled in Debug BIOS -- debug build skips enable
  • (Wdt) DisableTimer -- timer disable
  • (Wdt) CheckTimerStatus -- status check
  • (Wdt) Readback = (%x) -- register readback
  • (Wdt) Status = FAILURE -- timeout detected
  • (Wdt) AllowKnownReset -- known reset allowed
  • (Wdt) IsWdtRequired / - yes / - no -- requirement check
  • (Wdt) IsWdtEnabled -- enable state check

Source path: e:\hs\PurleySktPkg\SouthClusterLbg\Wdt\Dxe\WdtDxe.c
Build path: e:\hs\Build\HR6N0XMLK\DEBUG_VS2015\X64\PurleySktPkg\SouthClusterLbg\Wdt\Dxe\WdtDxe\DEBUG\