# EsrtDxe -- UEFI ESRT (EFI System Resource Table) DXE Driver

## Overview

EsrtDxe is a UEFI DXE driver that manages the EFI System Resource Table (ESRT),
the mechanism by which UEFI firmware reports updatable firmware components to
the operating system. The OS uses the ESRT to discover which firmware devices
support capsule-based updates and their current version/status.

This driver is part of `MdeModulePkg/Universal/EsrtDxe` in the EDK2 source tree.

## Binary Information

| Field          | Value                                      |
|----------------|--------------------------------------------|
| Module         | EsrtDxe.efi                                |
| Size           | 0x27e0 bytes (10,208 bytes)                |
| Architecture   | X64                                        |
| Base Address   | 0x0 (relocatable)                          |
| MD5            | bfbebf10d01756d5fbd879ba69cf4e57           |
| Source         | Lenovo HR650X BIOS (HR6N0XMLK build)       |
| Compiler       | VS2015, DEBUG build                        |
| EDK2 Path      | MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf |

## Function Map

| Address | Name | Size | Description |
|---------|------|------|-------------|
| 0x2C0 | InternalCopyMem | 0x42 | Internal memcpy (forward/backward) |
| 0x370 | InternalZeroMem | 0x20 | Internal memset(0) |
| 0x390 | _ModuleEntryPoint | 0x13 | UEFI driver entry point |
| 0x3A4 | EsrtDxeEntryInit | 0x142 | Init globals (gST, gBS, gRT, gDS, HOB list) |
| 0x4E8 | EsrtDxeRegisterCallbacks | 0xE5 | Register events, init locks, install protocols |
| 0x5D0 | EsrtDxeUpdateEntry | 0xA3 | Update ESRT entry (NonFMP -> FMP) |
| 0x674 | EsrtDxeDeleteEntry | 0x95 | Delete ESRT entry (FMP -> NonFMP) |
| 0x70C | EsrtDxeRemoveEntry | 0x4B | Remove entry from NonFMP only |
| 0x758 | EsrtDxeAddEntry | 0x78 | Add entry to NonFMP (if not exists) |
| 0x7D0 | EsrtDxeCollectFmpEntries | 0x492 | Enumerate FMP protocols, collect descriptors |
| 0xC64 | EsrtDxeLockVariables | 0x8D | Lock ESRT variables via Variable Lock protocol |
| 0xCF4 | EsrtDxeNotifyInstallEsrtTable | 0x1E5 | Build combined ESRT table, install config table |
| 0xEDC | EsrtDxeFindAndCopyEntry | 0x108 | Find entry by GUID in repository |
| 0xFE4 | EsrtDxeAppendNonFmpEntry | 0x19D | Append entry to NonFMP repository |
| 0x1184 | EsrtDxeDeleteNonFmpEntry | 0x12C | Delete entry from NonFMP, shift remaining |
| 0x12B0 | EsrtDxeUpdateRepositoryEntry | 0x14E | Update/append entry in repository by GUID |
| 0x1400 | EsrtDxeCopyCollectedEntry | 0x58 | Copy FMP descriptor to collected format |
| 0x1458 | GetDebugOutputProtocol | 0x7F | Locate debug protocol via CMOS check |
| 0x14D8 | DebugPrint | 0x88 | Debug print via CMOS-controlled debug level |
| 0x1560 | DebugAssert | 0x3E | Debug assert via debug protocol |
| 0x15A0 | CopyMem | 0x9E | Bounds-checking memory copy |
| 0x1640 | CompareGuid | 0x67 | 64-bit unaligned GUID comparison |
| 0x16A8 | AllocatePool | 0x2E | gBS->AllocatePool wrapper |
| 0x16D8 | AllocateZeroPool | 0x27 | Allocate + zero memory |
| 0x1700 | FreePool | 0x44 | gBS->FreePool wrapper |
| 0x1744 | EfiGetSystemConfigurationTable | 0xC4 | Look up config table by GUID |
| 0x1808 | EfiInitializeLock | 0x45 | Initialize EFI_LOCK |
| 0x1850 | EfiAcquireLock | 0x76 | Raise TPL, acquire lock |
| 0x18C8 | EfiReleaseLock | 0x5F | Restore TPL, release lock |
| 0x1928 | GetEfiVariable | 0x11A | Read UEFI variable (auto-alloc) |
| 0x1A44 | HobLibConstructor | 0x82 | Initialize HOB list |
| 0x1AC8 | ReadUnaligned64 | 0x2F | Unaligned QWORD read |
| 0x1AF8 | ZeroMem | 0x6E | Bounds-checking memory zero |

## GUIDs Used

| Address | GUID | Purpose |
|---------|------|---------|
| 0x2400 | `CD3D0A05-9E24-437C-A891-1EE053DB7638` | gEfiEventReadyToBootGuid |
| 0x2410 | `86C77A67-0B97-4633-A187-49104D0685C7` | gEfiEventVirtualAddressChangeGuid |
| 0x2420 | `A340C064-723C-4A9C-A4DD-D5B47A26FBB0` | ESRT Table protocol GUID (config table) |
| 0x2430 | `7739F24C-93D7-11D4-9A3A-0090273FC14D` | gEfiHobListGuid |
| 0x2440 | `B122A263-3661-4F68-9929-78F8B0D62180` | ESRT Management protocol GUID |
| 0x2450 | `05AD34BA-6F02-4214-952E-4DA0398E2BB9` | gEfiDxeServicesTableGuid |
| 0x2460 | `999BD818-7DF7-4A9A-A502-9B75033E6A0F` | ESRT variable vendor GUID |

## UEFI Variables Managed

| Variable Name | Type | Description |
|---------------|------|-------------|
| `EsrtFmp` | `EFI_SYSTEM_RESOURCE_ENTRY[]` | FMP-sourced ESRT entries |
| `EsrtNonFmp` | `EFI_SYSTEM_RESOURCE_ENTRY[]` | Non-FMP (legacy) ESRT entries |

Both variables use: `EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS` (attributes = 3).

## Data Flow

```
Boot:
  EsrtDxeEntryInit -> Initialize gST, gBS, gRT, gDS, HOB list
  EsrtDxeRegisterCallbacks ->
    - Create ReadyToBoot event -> EsrtDxeNotifyInstallEsrtTable
    - Create VirtualAddrChange event -> EsrtDxeLockVariables
    - Install ESRT Management protocol interface

At Runtime (other drivers call these):
  EsrtDxeAddEntry(Entry)     -> Appends to EsrtNonFmp
  EsrtDxeUpdateEntry(Guid)   -> Updates EsrtNonFmp (falls back to EsrtFmp)
  EsrtDxeDeleteEntry(Guid)   -> Deletes from EsrtFmp (fallback EsrtNonFmp)
  EsrtDxeRemoveEntry(Guid)   -> Deletes from EsrtNonFmp only
  EsrtDxeCollectFmpEntries() -> Enumerates FMP protocols, writes EsrtFmp

On ReadyToBoot:
  EsrtDxeCollectFmpEntries()
  EsrtDxeNotifyInstallEsrtTable() ->
    - Read EsrtNonFmp + EsrtFmp variables
    - Validate alignment (must be 40-byte aligned)
    - Build combined ESRT table (header + entries)
    - Install via gBS->InstallConfigurationTable(gEfiEsrtTableProtocolGuid)

On VirtualAddressChange:
  EsrtDxeLockVariables() ->
    - Use Variable Lock protocol to prevent further writes
```

## ESRT Entry Structure (0x28 = 40 bytes)

```
+0x00  EFI_GUID  FwClass                  (16 bytes)
+0x10  UINT32    FwType                   (0=Unknown, 1=System, 2=Device)
+0x14  UINT32    FwVersion
+0x18  UINT32    LowestSupportedFwVersion
+0x1C  UINT32    CapsuleFlags
+0x20  UINT32    LastAttemptVersion
+0x24  UINT32    LastAttemptStatus
Total: 40 bytes (0x28)
```

## Locking Architecture

The driver uses two TPL-based locks:
- `mFmpLock` (at `unk_24F0`, 24 bytes): Protects EsrtFmp variable access
- `mNonFmpLock` (at `unk_2508`, 24 bytes): Protects EsrtNonFmp variable access

Both locks operate at TPL_NOTIFY (TPL = 8) and prevent concurrent access
between the FMP enumeration callback and normal ESRT variable operations.

## Repository Constraints

- Each repository variable is limited to 0x500 bytes (1280 bytes = 32 entries)
- Entries must be 0x28 (40) bytes each
- Repository is validated on every read: `Size == (Size / 40) * 40`
- If corrupt, the repository is deleted and rebuilt

## Notes

- This binary was compiled with DEBUG_VS2015 from a debug build
- The driver uses a CMOS-based debug level control (port 0x70/0x71, register 0x4B)
- Debug output is routed through a protocol located via gBS->LocateProtocol
- The protocol notification table at 0x2470 contains function pointer arrays
  for HII Config Access and related protocol interfaces
