# 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\`