Newer
Older
AMI-Aptio-BIOS-Reversed / TerminalSrc / TerminalSrc.c
@Ajax Dong Ajax Dong 2 days ago 35 KB Init
/**
 * TerminalSrc.c - Terminal Source Driver for HR650X BIOS
 *
 * Source: AmiModulePkg\Terminal\Terminal.c, TerminalSetup.c
 * Binary: TerminalSrc.efi (0132), 75 functions
 *
 * Address Range: 0x2C0 - 0x4FC0 (.text), Entry at 0x390
 * Protocols: EFI_SERIAL_IO_PROTOCOL, EFI_SIMPLE_TEXT_INPUT_PROTOCOL,
 *            EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL, ACPI SPCR
 *
 * UEFI Driver Entry Protocol:
 *   1. ModuleEntryPoint -> TerminalDriverEntry
 *   2. Installs Serial IO + Console In/Out protocols on new handle
 *   3. Installs ACPI SPCR table for OS serial console redirection
 *   4. Reads/writes "TerminalSerialVar" UEFI variable for persistent config
 *
 * Terminal Emulation:
 *   - Serial input parsing: ANSI/VT100 escape sequences, scan codes
 *   - Output via serial with ANSI escape code generation
 *   - Unicode input via UTF-8 multi-byte decoding (modes 2-3)
 *   - 80x25 (Mode 0) and 100x31 (Mode 2) display modes
 *   - Color support: 8 foreground + 8 background colors (ESC[<attr>m)
 *
 * Data Flow:
 *   Serial Port -> RingBuffer -> RingToKeyQueue -> KeyRingBuffer -> SerialToKey
 *   -> QueueEntry -> ConInProcessSerial -> SimpleTextInput.ReadKeyStroke
 *
 *   SimpleTextOutput.OutputString -> ConOutOutputString -> SerialWrite -> Serial Port
 */

#include "TerminalSrc.h"
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>

//=============================================================================
// Global Variables
//=============================================================================

// UEFI system table pointers (set by entry point)
extern EFI_SYSTEM_TABLE      *gST;
extern EFI_BOOT_SERVICES     *gBS;
extern EFI_RUNTIME_SERVICES  *gRT;
extern EFI_HANDLE            gImageHandle;

// Terminal device array (2 entries: port 0 and port 1)
extern TERMINAL_DEV *gTerminalDevices[2];  // qword_9768

// Terminal output type array (2 entries)
extern UINT32 gTerminalTypes[2];           // qword_9758 (0=PCANSI, 1=VT100, etc.)

// Terminal serial variable (from TerminalSerialVar NV var)
extern UINT16 gTerminalSerialVar;          // word_6F18

// Terminal active port flag
extern UINT8  gTerminalSerialPort;         // byte_6F1E

// Debug/assert globals
extern UINT64 gHobList;                    // qword_6EA0
extern VOID   *gDebugMask;                 // qword_6E98
extern VOID   *gPcdDb;                     // qword_6E90

// Language string
extern UINT16 gEnUs[];                     // "en-US"

// Terminal setup config bytes (from Setup NV variable)
extern UINT8  gSetupData[];                // byte_6F20 area

// Screen buffer (100 bytes/row * 31 rows)
extern UINT8  gScreenBuffer[3100];         // qword_72E0

// Attribute buffer (100 words/row * 31 rows)
extern UINT16 gScreenAttr[3100];           // word_7F00

// Escape sequence keymap table
extern ESC_KEYMAP_ENTRY *gEscKeymapTable;  // word_6E58

// Key wait list data
extern UINT64 gKeyWaitCount;               // qword_9740
extern LIST_ENTRY gKeyWaitListHead;        // xmmword_9748

//=============================================================================
// UEFI Entry Point
//=============================================================================

/**
 * ModuleEntryPoint - PE/COFF entry point
 * @0x390
 * Saves ImageHandle, gST, gBS, gRT. Calls HobLibGetHobList()
 * then TerminalDriverEntry().
 */
EFI_STATUS
EFIAPI
ModuleEntryPoint(
    IN EFI_HANDLE        ImageHandle,
    IN EFI_SYSTEM_TABLE  *SystemTable
    );

//=============================================================================
// Terminal Driver Entry
//=============================================================================

/**
 * TerminalDriverEntry - Main driver entry
 * @0x44C
 *
 * Responsibilities:
 *   1. Install Serial IO + Console In/Out protocols on new handle
 *   2. Allocate 2 terminal device contexts (up to 2 serial ports)
 *   3. Register periodic timer callback for key polling (TerminalTimerKeyReset)
 *   4. Initialize terminal device state to 0s
 *   5. Read "TerminalSerialVar" from NV storage for serial port config
 *   6. Write back updated "TerminalSerialVar" as UEFI variable
 *
 * Returns: EFI_SUCCESS or EFI error code
 */
EFI_STATUS
TerminalDriverEntry(
    IN EFI_HANDLE        ImageHandle,
    IN EFI_SYSTEM_TABLE  *SystemTable
    );

//=============================================================================
// Serial Port Detection & Setup
//=============================================================================

/**
 * TerminalDetectSerialPorts - Detect available serial ports via FV/HOB
 * @0x16B0
 *
 * Searches the firmware volume file list for a serial terminal device
 * matching the terminal GUID (unk_55E0). If found, locates the serial IO
 * protocol for the device. Extracts device path info and determines the
 * number of serial ports available (up to 2).
 *
 * Called by TerminalSerialRead() during serial port initialization.
 *
 * @param  Device   Terminal device context
 * @param  FvHandle Firmware volume handle for file list lookup
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalDetectSerialPorts(
    IN TERMINAL_DEV *Device,
    IN EFI_HANDLE   FvHandle
    );

/**
 * TerminalSetupSerialPort - Configure serial port parameters
 * @0x18B4
 *
 * Opens serial IO protocol on the detected serial device, queries
 * the device path for ACPI UID, then configures baud rate, line
 * control, and terminal settings via the protocol interface.
 * Sets the baud rate cache in qword_6ED8.
 *
 * Called by TerminalSerialRead() after port detection.
 *
 * @param  Device   Terminal device context
 * @param  FvHandle Firmware volume handle
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalSetupSerialPort(
    IN TERMINAL_DEV *Device,
    IN EFI_HANDLE   FvHandle
    );

//=============================================================================
// EFI_SERIAL_IO_PROTOCOL Implementation
//=============================================================================

/**
 * TerminalSerialReset - Reset serial port
 * @0x680
 *
 * Calls EFI_SERIAL_IO_PROTOCOL.Reset() then .SetAttributes()
 * on the underlying serial device. Validates device type = 3 (terminal).
 *
 * Returns: EFI_SUCCESS, EFI_UNSUPPORTED, EFI_DEVICE_ERROR, or EFI_TIMEOUT
 */
EFI_STATUS
TerminalSerialReset(
    IN TERMINAL_DEV  *This,
    IN EFI_HANDLE    ControllerHandle,
    IN UINT8         *SerialDeviceType
    );

/**
 * TerminalSerialWrite - Write data to serial port
 * @0x800
 *
 * Converts terminal output to serial data. Handles:
 * - Unicode to serial byte conversion
 * - Escape sequence generation
 * - Scroll/cursor management
 * - Reads "Setup" variable for flow control config
 * - Flow control: 0=none, 0x4000=hardware, 0x8000=software
 * - Calls TerminalSetupReadConfig() for baud/parity/stop/data config
 * - Allocates temp buffer for serial data conversion
 * - Calls TerminalSerialRead() to check for input while writing
 *
 * Returns: EFI_STATUS
 */
EFI_STATUS
TerminalSerialWrite(
    IN TERMINAL_DEV  *This,
    IN EFI_HANDLE    ControllerHandle,
    IN UINT8         *Buffer
    );

/**
 * TerminalSerialClose - Close serial port
 * @0x113C
 *
 * Disconnects serial IO protocol from controller.
 * If CloseData is provided, also cleans up terminal device context
 * and unregisters from the key notification system.
 *
 * Returns: EFI_STATUS
 */
EFI_STATUS
TerminalSerialClose(
    IN TERMINAL_DEV  *This,
    IN EFI_HANDLE    ControllerHandle,
    IN VOID          *CloseData,
    IN EFI_HANDLE    *ChildHandle
    );

/**
 * TerminalSerialRead - Read data from serial port (key input)
 * @0x1358
 *
 * Reads serial input and converts to terminal key events.
 * Calls TerminalDetectSerialPorts() and TerminalSetupSerialPort()
 * for initialization. Parses: type-2 entries (keyboard data),
 * type-1 entries (serial data). Handles TerminalSerialVar config.
 *
 * Returns: EFI_STATUS (EFI_UNSUPPORTED if no key available)
 */
EFI_STATUS
TerminalSerialRead(
    IN TERMINAL_DEV  *This,
    IN EFI_HANDLE    ControllerHandle,
    OUT UINT8        *KeyChar,
    OUT UINT8        *KeyFound
    );

/**
 * TerminalSerialWriteAll - Write all bytes to serial
 * @0x3110
 *
 * Writes n bytes to serial IO protocol, handling partial writes.
 * Continues writing remaining bytes until all are sent or error.
 * Handles EFI_TIMEOUT (0x8000000000000012) as non-fatal.
 *
 * @param  SerialIo   EFI_SERIAL_IO_PROTOCOL instance
 * @param  Buffer     Data to write
 * @param  Length     Number of bytes to write
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalSerialWriteAll(
    IN EFI_SERIAL_IO_PROTOCOL  *SerialIo,
    IN UINT8                   *Buffer,
    IN UINT64                  Length
    );

/**
 * TerminalSetupReadConfig - Read serial config from Setup NV var
 * @0x3F9C
 *
 * Reads the "Setup" UEFI variable for serial port configuration.
 * Extracts flow control, baud rate, parity, stop bits, and data bits
 * per port index. Falls back to defaults if variable not found:
 *   Baud rate: 115200
 *   Parity: 1 (none? or even?)
 *   Data bits: 8
 *   Stop bits: 1
 *
 * Baud rate lookup via table at qword_5110.
 *
 * @param  PortIndex  Serial port index (0 or 1)
 * @param  Config     Output config structure (30+ bytes)
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalSetupReadConfig(
    IN  UINT8   PortIndex,
    OUT UINT32  *Config
    );

//=============================================================================
// Serial Input Pipeline
//=============================================================================

/**
 * TerminalSerialBufferRead - Read bytes from serial device
 * @0x2194
 *
 * Reads bytes from the serial device interface into a memory buffer.
 * Called during ring buffer processing to transfer raw serial data
 * into the terminal's internal buffer. Checks for error flags (0x100)
 * and handles overflow conditions.
 *
 * @param  SerialIo  EFI_SERIAL_IO_PROTOCOL instance
 * @param  Buffer    Destination buffer
 * @param  Remaining Pointer to remaining byte count (updated on return)
 */
VOID
TerminalSerialBufferRead(
    IN  EFI_SERIAL_IO_PROTOCOL  *SerialIo,
    OUT UINT8                   *Buffer,
    IN  UINT64                  *Remaining
    );

/**
 * TerminalRingBufferRead - Read one byte from ring buffer
 * @0x2204
 *
 * Reads byte from serial ring buffer at current head index.
 * Advances head index (with wrap at 1000).
 * Used by TerminalUtf8Decode() and TerminalRingToKeyQueue().
 *
 * @param  Device  Terminal device with ring buffer
 * @param  OutByte Output byte
 * @return TRUE if byte was available, FALSE if buffer empty
 */
BOOLEAN
TerminalRingBufferRead(
    IN  TERMINAL_DEV *Device,
    OUT UINT8        *OutByte
    );

/**
 * TerminalRingWrite - Write Unicode char to key ring buffer
 * @0x223C
 *
 * Enqueues a Unicode character into the circular key ring buffer
 * (1000 entries). Checks for overflow against the read head (KeyRingHead).
 * Advances KeyRingTail with wrap at 1000.
 *
 * @param  Device Terminal device context
 * @param  Char   Unicode character to enqueue
 * @return Updated tail index
 */
UINT16
TerminalRingWrite(
    IN TERMINAL_DEV *Device,
    IN UINT16       Char
    );

/**
 * TerminalUtf8Decode - Decode UTF-8 from ring buffer
 * @0x22A4
 *
 * Reads bytes from the ring buffer and decodes a multi-byte UTF-8 sequence:
 *   1-byte: 0xxxxxxx (ASCII, returns byte directly)
 *   2-byte: 110xxxxx 10xxxxxx (U+0080-U+07FF)
 *   3-byte: 1110xxxx 10xxxxxx 10xxxxxx (U+0800-U+FFFF)
 *
 * Each byte consumed is removed from the ring buffer. The decoded
 * Unicode character is written to the output. The n3 parameter
 * indicates how many bytes were consumed (1, 2, or 3).
 *
 * @param  Device      Terminal device context
 * @param  OutChar     Output decoded Unicode character
 * @param  NumBytesOut Output: number of bytes consumed (1-3)
 * @return TRUE if character decoded successfully
 */
BOOLEAN
TerminalUtf8Decode(
    IN  TERMINAL_DEV *Device,
    OUT UINT16       *OutChar,
    OUT UINT8        *NumBytesOut
    );

/**
 * TerminalRingToKeyQueue - Process ring buffer into key queue
 * @0x23B8
 *
 * Reads bytes from ring buffer and converts them to key events
 * in the key ring buffer via TerminalRingWrite().
 *
 * Handles per output mode:
 *   Mode 0 (PC-ANSI) / Mode 1 (VT100): Direct byte-to-char mapping
 *   Mode 2 (VT100+): UTF-8 multi-byte decoding via TerminalUtf8Decode()
 *   Mode 3 (VT-UTF8): Direct passthrough
 *
 * Calls TerminalSerialBufferRead() to fetch raw bytes from serial,
 * then decodes and writes to key ring buffer.
 */
VOID
TerminalRingToKeyQueue(
    IN TERMINAL_DEV *Device
    );

/**
 * TerminalKeyRingDequeue - Dequeue from key ring buffer
 * @0x2598
 *
 * Reads one Unicode character from the key ring buffer (KeyRingData).
 * Checks KeyRingHead != KeyRingTail to determine if data is available.
 * Advances KeyRingHead with wrap at 1000.
 *
 * @param  Device  Terminal device context
 * @param  OutChar Output Unicode character
 * @return TRUE if character was available
 */
BOOLEAN
TerminalKeyRingDequeue(
    IN  TERMINAL_DEV *Device,
    OUT UINT16       *OutChar
    );

/**
 * TerminalSerialToKey - Convert serial input to key events
 * @0x263C
 *
 * Core serial-to-key conversion pipeline:
 *   1. Calls TerminalRingToKeyQueue() to process raw ring buffer data
 *   2. Reads key from TerminalKeyRingDequeue()
 *   3. If 0x1B (ESC) received, enters escape sequence mode:
 *      a. Sets 10-second timer for escape sequence timeout
 *      b. Reads subsequent bytes into EscKeyBuffer[32]
 *      c. Matches against keymap table at gEscKeymapTable
 *      d. Returns converted scan code or 0x17 (ESC) on timeout
 *   4. Returns 20-byte SERIAL_QUEUE_ENTRY with scan code + Unicode + flags
 *
 * If escape sequence does not match, buffered bytes are replayed
 * into the key ring buffer by wrapping around KeyRingHead backwards.
 *
 * Keymap entry format (24 bytes):
 *   +0x00: WORD KeyChar
 *   +0x08: QWORD Next (next entry)
 *   +0x10: WORD ScanCode (output)
 *   +0x12: WORD Unicode (output)
 *   +0x14: BYTE ModMask
 *
 * Returns: EFI_SUCCESS, EFI_NOT_READY (no data)
 */
EFI_STATUS
TerminalSerialToKey(
    IN  TERMINAL_DEV           *Device,
    OUT SERIAL_QUEUE_ENTRY     *KeyEntry
    );

/**
 * TerminalKeyboardCheck - Check keyboard state
 * @0x25F0
 *
 * If key notify state is set and serial processing indicates
 * a key is available, resets the read timer to stop polling.
 *
 * @param  Device Terminal device context
 * @param  Context Timer context pointer (pointer to Device pointer)
 */
VOID
TerminalKeyboardCheck(
    IN TERMINAL_DEV *Device,
    IN VOID         **Context
    );

//=============================================================================
// EFI_SIMPLE_TEXT_INPUT_PROTOCOL Implementation
//=============================================================================

/**
 * TerminalConInReset - Reset console input
 * @0x2B98
 *
 * Resets the console input key queue by zeroing the queue buffer
 * and resetting head/tail pointers.
 *
 * @param  This                 Terminal device
 * @param  ExtendedVerification Not used
 * @return EFI_SUCCESS
 */
EFI_STATUS
TerminalConInReset(
    IN TERMINAL_DEV *This,
    IN BOOLEAN      ExtendedVerification
    );

/**
 * TerminalConInCheckKey - Check if key is available
 * @0x2B1C
 *
 * If SerialInHead != SerialInTail in key queue, key is immediately
 * available. Otherwise calls TerminalConInProcessSerial() to read
 * more data from serial. If serial data is found, schedules timer.
 *
 * @param  This Terminal device
 * @return 0 if no key, non-zero if key state available
 */
UINT8
TerminalConInCheckKey(
    IN TERMINAL_DEV *This
    );

/**
 * TerminalConInProcessSerial - Read and process serial data
 * @0x2918
 *
 * Main serial input processor:
 *   1. Reads 20 bytes from serial into temporary SERIAL_QUEUE_ENTRY
 *   2. Handles Ctrl-Z (0x1A = 26) -> triggers TerminalScreenRedraw()
 *   3. Parses control codes:
 *      - 0x08 (BS) -> scan code 0x51 (SCAN_LEFT)
 *      - 0x09 (TAB) -> scan code 0x30 (SCAN_F1?)
 *      - 0x0D (CR) -> scan code 0x2B (SCAN_ENTER)
 *   4. Converts printable ASCII (0x20-0x7E) using attribute table
 *      (byte_57A0/byte_57A1: 2-byte lookup per char)
 *   5. Handles DEL (0x7F) as backspace
 *   6. Maps Unicode > 0x7E via ANSI translation table
 *   7. Enqueues processed entry into serial output queue
 *   8. Calls TerminalQueueDequeue() to dequeue from serial in queue
 *
 * Scan code lookup table at byte_5862 (3-byte entries per scan code)
 * Attribute table at byte_5864 (6-byte entries per scan code)
 *
 * @param  Device Terminal device context
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalConInProcessSerial(
    IN TERMINAL_DEV *Device
    );

/**
 * TerminalWaitForKey - Wait for a key press
 * @0x2C7C
 *
 * Processes incoming serial data via TerminalConInProcessSerial()
 * and if a key notification is pending, schedules the timer to
 * poll for it.
 *
 * @param  This Terminal device
 * @return EFI_SUCCESS or EFI_NOT_READY
 */
EFI_STATUS
TerminalWaitForKey(
    IN TERMINAL_DEV *This
    );

/**
 * TerminalNotifyKeyListeners - Notify registered key listeners
 * @0x2CC8
 *
 * Walks the key wait list (gKeyWaitListHead linked list) and for
 * each entry, checks if the new key matches the listener's criteria.
 * If match found, calls the listener's notification function.
 * Uses LIST_ENTRY flink/blink pointers (48-byte KEY_WAIT_ITEM).
 *
 * @param  KeyEntry Key data entry (20 bytes)
 * @param  Context  Notify context
 * @return EFI_SUCCESS
 */
EFI_STATUS
TerminalNotifyKeyListeners(
    IN UINT32  *KeyEntry,
    IN VOID    *Context
    );

/**
 * TerminalCreateKeyWait - Create key wait item
 * @0x2E6C
 *
 * Allocates a 48-byte KEY_WAIT_ITEM, initializes with key data
 * and notification function, links into global key wait list.
 * Schedules timer to check for matching key.
 *
 * @param  This         Terminal device (minus 24 bytes from device start)
 * @param  KeyData      Key data to match
 * @param  NotifyFn     Notification callback function
 * @param  WaitItem     Output: pointer to created wait item
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalCreateKeyWait(
    IN TERMINAL_DEV  *This,
    IN EFI_KEY_DATA  *KeyData,
    IN VOID          *NotifyFn,
    OUT VOID         **WaitItem
    );

/**
 * TerminalRemoveKeyWait - Remove key wait item
 * @0x2F88
 *
 * Unlinks a KEY_WAIT_ITEM from the notification list,
 * frees allocated memory, and resets the timer.
 *
 * @param  This     Terminal device
 * @param  WaitItem Wait item to remove
 * @return EFI_SUCCESS or EFI_INVALID_PARAMETER
 */
EFI_STATUS
TerminalRemoveKeyWait(
    IN TERMINAL_DEV  *This,
    IN VOID          *WaitItem
    );

/**
 * TerminalKeyFindOrAlloc - Find or allocate key slot
 * @0x3F24
 *
 * Manages the 2-entry key mapping table (gTerminalSerialVar based).
 * Searches for key character in existing entries, then looks for
 * an active slot to reuse. Returns 0xFF if table full.
 *
 * @param  KeyChar Character to find/allocate
 * @return Index (0 or 1) or 0xFF if table full
 */
UINT8
TerminalKeyFindOrAlloc(
    IN UINT8  KeyChar
    );

/**
 * TerminalQueueDequeue - Dequeue entry from circular queue
 * @0x304C
 *
 * Dequeues a 20-byte SERIAL_QUEUE_ENTRY from the 33-entry
 * circular FIFO queue at Queue base address. Checks head != tail.
 *
 * @param  Queue    Queue base address
 * @param  OutEntry Output buffer (20 bytes)
 * @return EFI_SUCCESS or EFI_NOT_READY (queue empty)
 */
EFI_STATUS
EFIAPI
TerminalQueueDequeue(
    IN  UINT8                *Queue,
    OUT SERIAL_QUEUE_ENTRY   *OutEntry
    );

//=============================================================================
// EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL Implementation
//=============================================================================

/**
 * TerminalConOutReset - Reset console output
 * @0x2BF0
 *
 * Zeroes the output queue buffer and resets head/tail pointers.
 *
 * @param  This                 Terminal device
 * @param  ExtendedVerification Not used
 * @return EFI_SUCCESS
 */
EFI_STATUS
TerminalConOutReset(
    IN TERMINAL_DEV *This,
    IN BOOLEAN      ExtendedVerification
    );

/**
 * TerminalConOutOutputString - Main text output function (largest function)
 * @0x3274 (1602 bytes)
 *
 * Outputs a Unicode string to the serial terminal:
 *   1. Determines current mode (80x25 or 100x31) from ModePtr
 *   2. Iterates through Unicode string
 *   3. Handles special characters:
 *      - \b (0x08): Backspace, move cursor left
 *      - \t (0x09): Tab, expand to column boundary
 *      - \r (0x0D): Carriage return
 *      - \n (0x0A): Line feed, scroll if at bottom
 *   4. Printable chars written to serial and screen buffer
 *   5. Line wrapping at column boundary (80 or 100)
 *   6. Scrolling: shift all rows up, clear last row
 *   7. Uses gScreenBuffer for character memory
 *   8. Uses gScreenAttr for color attributes
 *   9. Checks OutputDisabled flag before serial output
 *  10. Can suppress output for deferred screen update
 *
 * @param  This     Terminal device
 * @param  WString  Unicode string to output
 * @param  a3       Flag parameter (output mode flags)
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalConOutOutputString(
    IN TERMINAL_DEV     *This,
    IN CONST UINT16     *WString,
    IN UINT8            a3
    );

/**
 * TerminalConOutTestString - Test if string can be output
 * @0x3A78
 *
 * Validates Unicode string for output compatibility by terminal type:
 *   Mode 0 (PC-ANSI): Only chars < 0x80 valid
 *   Mode 1 (VT100): Validates 0x2100-0x27FF against translation table
 *   Mode 2 (VT100+): Uses TerminalUniToUtf8 for validation
 *   Mode 3 (VT-UTF8): Uses TerminalUniToGraphByte for validation
 *
 * @param  This     Terminal device
 * @param  WString  Unicode string to test
 * @return EFI_SUCCESS if string can be displayed, EFI_UNSUPPORTED otherwise
 */
EFI_STATUS
TerminalConOutTestString(
    IN TERMINAL_DEV     *This,
    IN CONST UINT16     *WString
    );

/**
 * TerminalConOutSetAttribute - Set text attribute
 * @0x3174
 *
 * Sets foreground/background color attribute. If attribute changes,
 * calls TerminalConOutClearScreen() then TerminalConOutSetColor()
 * to apply the new color to the entire screen.
 *
 * @param  This      Terminal device
 * @param  Attribute Color attribute (foreground | background << 4)
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalConOutSetAttribute(
    IN TERMINAL_DEV *This,
    IN UINT32       Attribute
    );

/**
 * TerminalConOutSetAttributeDefault - Set default attribute
 * @0x3A70
 * Wrapper: TerminalConOutOutputString(This, 1, ...)
 * Sets terminal to default attribute (white on black).
 *
 * @param  This Terminal device
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalConOutSetAttributeDefault(
    IN TERMINAL_DEV *This
    );

/**
 * TerminalConOutSetAttributeDirect - Set attribute byte directly
 * @0x2C4C
 *
 * Validates and stores an attribute byte at Device->AttributeByte (+3944).
 * Attribute must be negative (bit 7 set) with bits 3-5 clear, or
 * returns EFI_UNSUPPORTED.
 *
 * @param  Device    Terminal device
 * @param  Attribute Attribute byte to set
 * @return EFI_SUCCESS or EFI_UNSUPPORTED
 */
EFI_STATUS
TerminalConOutSetAttributeDirect(
    IN TERMINAL_DEV *Device,
    IN UINT8        *Attribute
    );

/**
 * TerminalConOutSetMode - Set display mode
 * @0x3BC4
 *
 * Switches between display modes:
 *   Mode 0: 80 columns x 25 rows
 *   Mode 2: 100 columns x 31 rows
 * Mode 1 is rejected (returns EFI_UNSUPPORTED).
 * Fills screen buffer with 0xFF and clears display.
 *
 * @param  This Terminal device
 * @param  Mode 0 = 80x25, 2 = 100x31
 * @return EFI_SUCCESS or EFI_UNSUPPORTED
 */
EFI_STATUS
TerminalConOutSetMode(
    IN TERMINAL_DEV *This,
    IN UINT64       Mode
    );

/**
 * TerminalConOutQueryMode - Query display mode dimensions
 * @0x3B7C
 *
 * Returns columns and rows for requested mode:
 *   Mode 0: 80 columns, 25 rows
 *   Mode 2: 100 columns, 31 rows
 * Mode 1 and others > MaxMode return EFI_UNSUPPORTED.
 *
 * @param  This     Terminal device
 * @param  Mode     Mode number
 * @param  Columns  Output: number of columns
 * @param  Rows     Output: number of rows
 * @return EFI_SUCCESS or EFI_UNSUPPORTED
 */
EFI_STATUS
TerminalConOutQueryMode(
    IN  TERMINAL_DEV *This,
    IN  UINT64       Mode,
    OUT UINT64       *Columns,
    OUT UINT64       *Rows
    );

/**
 * TerminalConOutSetColor - Set foreground/background color
 * @0x3C4C
 *
 * Generates ANSI escape sequence ESC[<attr>m for color change.
 * Uses color translation table byte_5080:
 *   byte_5080[0..7] = foreground color codes (30-37)
 *   byte_5080[8..15] = background color codes (40-47)
 *
 * Outputs: ESC[<bright>;<bg>;<fg>m or ESC[<code>m
 * Caches attribute to avoid redundant output.
 *
 * @param  This  Terminal device
 * @param  Color Color code (bit 3 = bright, bits 0-2 = fg, bits 4-6 = bg)
 * @return EFI_SUCCESS
 */
EFI_STATUS
TerminalConOutSetColor(
    IN TERMINAL_DEV *This,
    IN UINT64       Color
    );

/**
 * TerminalConOutClearScreen - Clear terminal screen
 * @0x3D6C
 *
 * Sends ESC[2J (clear screen) ANSI sequence, then:
 *   1. Fills screen buffer with 0xFF (empty char)
 *   2. Fills attribute buffer with 0 (default attr)
 *   3. Resets cursor column + row to 0
 *   4. Calls TerminalConOutSetCursorPos(0, 0)
 *
 * @param  This Terminal device
 * @return EFI_SUCCESS
 */
EFI_STATUS
TerminalConOutClearScreen(
    IN TERMINAL_DEV *This
    );

/**
 * TerminalConOutSetCursorPos - Set cursor position
 * @0x3E58
 *
 * Generates ANSI escape: ESC[<row+1>;<col+1>H
 * Validates position based on current mode dimensions.
 * Caches cursor column + row in ModePtr struct.
 *
 * @param  This    Terminal device
 * @param  Column  Column (0-based)
 * @param  Row     Row (0-based)
 * @return EFI_SUCCESS or EFI_UNSUPPORTED
 */
EFI_STATUS
TerminalConOutSetCursorPos(
    IN TERMINAL_DEV *This,
    IN UINT64       Column,
    IN UINT64       Row
    );

/**
 * TerminalConOutEnableCursor - Enable/disable cursor
 * @0x3F0C
 *
 * Always returns EFI_SUCCESS except when ExtendedVerification
 * is TRUE, which returns EFI_UNSUPPORTED.
 *
 * @param  This                 Terminal device
 * @param  ExtendedVerification Not supported
 * @return EFI_SUCCESS or EFI_UNSUPPORTED
 */
EFI_STATUS
TerminalConOutEnableCursor(
    IN TERMINAL_DEV *This,
    IN BOOLEAN      ExtendedVerification
    );

/**
 * TerminalConOutModeQueryFail - Mode query stub
 * @0x410C
 * Always returns EFI_UNSUPPORTED
 */
EFI_STATUS
TerminalConOutModeQueryFail(
    VOID
    );

/**
 * TerminalConOutOutputChar - Output a single character
 * @0x2870
 *
 * Outputs a single terminal character to serial via the output queue.
 * If serial input data is pending, schedules keyboard check timer.
 * For newline (0x0A), inserts carriage return (0x0D) before.
 *
 * @param  This      Terminal device
 * @param  Char      Character to output
 * @param  CharCount Character count parameter (output type variant)
 * @return EFI_SUCCESS
 */
EFI_STATUS
TerminalConOutOutputChar(
    IN TERMINAL_DEV *This,
    IN UINT8        *Char,
    IN UINT8        CharCount
    );

/**
 * TerminalConOutOutputCharType4 - Output char callback (type 4)
 * @0x2BD8
 *
 * Callback variant that outputs char with type=4.
 * Wrapper: TerminalConOutOutputChar(a1, a2, 4)
 * Registered as SimpleTextOut.OutputString callback.
 */
EFI_STATUS
TerminalConOutOutputCharType4(
    IN TERMINAL_DEV *This,
    IN UINT8        *Char
    );

/**
 * TerminalConOutOutputCharType12 - Output char callback (type 0xC)
 * @0x2C30
 *
 * Callback variant that outputs char with type=0xC.
 * Adjusts device pointer: arg = device - 24, then
 * calls TerminalConOutOutputChar(arg, a2, 0xC).
 */
EFI_STATUS
TerminalConOutOutputCharType12(
    IN VOID    *ModeStruct,
    IN UINT8   *Char
    );

/**
 * TerminalConOutOutputCharType20 - Output char callback (type 0x14)
 * @0x3030
 *
 * Callback variant that outputs char with type=0x14 (20).
 * Adjusts device pointer: arg = device - 72, then
 * calls TerminalConOutOutputChar(arg, a2, 0x14).
 */
EFI_STATUS
TerminalConOutOutputCharType20(
    IN VOID    *ModeStruct,
    IN UINT8   *Char
    );

//=============================================================================
// Character Encoding / Translation
//=============================================================================

/**
 * TerminalUniToGraphByte - Convert Unicode to PC graphics byte
 * @0x30BC
 *
 * Translates Unicode character (0x2100-0x27FF range) to PC graphics
 * byte using translation table at word_5920:
 *   - table[2*v] = Unicode match value
 *   - table[2*v+1].HIWORD = attribute
 *   - table[2*v+1].LOWORD = display byte
 *
 * @param  Unicode  Unicode character
 * @return Graphics byte or 0 if no translation
 */
UINT8
TerminalUniToGraphByte(
    IN UINT16  Unicode
    );

/**
 * TerminalUniToUtf8 - Convert Unicode to UTF-8
 * @0x3218
 *
 * Converts Unicode to 2 or 3 byte UTF-8:
 *   U+0080-U+07FF: 2 bytes (110xxxxx 10xxxxxx)
 *   U+0800-U+FFFF: 3 bytes (1110xxxx 10xxxxxx 10xxxxxx)
 *
 * @param  Unicode  Unicode character
 * @param  Utf8Out  Output buffer (at least 3 bytes)
 * @param  NumBytes Output: number of UTF-8 bytes (2 or 3)
 * @return Last byte of UTF-8 sequence
 */
UINT8
TerminalUniToUtf8(
    IN  UINT16  Unicode,
    OUT UINT8   *Utf8Out,
    OUT UINT8   *NumBytes
    );

//=============================================================================
// Screen Management
//=============================================================================

/**
 * TerminalScreenRedraw - Redraw entire terminal screen
 * @0x38B8
 *
 * Full screen redraw of both terminal devices (up to 2):
 *   1. For each device (iterated from gTerminalDevices array):
 *      a. Determine mode dimensions (80x25 or 100x31)
 *      b. Clear screen with ESC[2J
 *      c. Redraw each character from gScreenBuffer
 *      d. Apply colors from gScreenAttr
 *      e. Restore cursor position
 *   2. Uses TerminalConOutOutputString() for chars
 *   3. Uses TerminalConOutSetColor() for attributes
 *   4. Checks OutputDisabled flag per device
 */
VOID
TerminalScreenRedraw(
    VOID
    );

//=============================================================================
// Timer/Event Infrastructure
//=============================================================================

/**
 * TerminalTimerNotify - Timer callback for SPCR refresh
 * @0x1C6C
 *
 * Periodic timer callback. Queries the key wait list and
 * calls TerminalInstallSpcrTable() to refresh the SPCR table.
 *
 * @param  Event   Timer event
 * @param  Context Terminal device context
 */
VOID
EFIAPI
TerminalTimerNotify(
    IN EFI_EVENT  Event,
    IN VOID       *Context
    );

/**
 * TerminalTimerKeyReset - Timer to reset key state
 * @0x2120
 *
 * Fires periodically (500ms) to clear key notification state.
 * Resets ring buffer and key tracking. Registered via
 * gBS->SetTimer() at TIMER_KEY_POLL_US interval.
 *
 * @param  Event Timer event
 */
VOID
EFIAPI
TerminalTimerKeyReset(
    IN EFI_EVENT  Event
    );

//=============================================================================
// Console Output Key Handler (for Setup UI)
//=============================================================================

/**
 * TerminalConOutHandleKey - Handle key event on console output
 * @0x1CC8 (1110 bytes)
 *
 * Processes a key event on the console output device for Setup UI:
 *   1. Reads "Setup" NV variable for terminal configuration
 *   2. Extracts terminal emulation type per serial port
 *   3. Locates matching serial IO device handle
 *   4. Queries HII database for font data via PcdGetPtr()
 *   5. Reads font glyph at X,Y position
 *   6. Processes key input for terminal configuration UI
 *   7. Routes to correct terminal device by key index
 *
 * @param  KeyIndex      Key index (0 or 1)
 * @param  Context       Terminal device context
 * @param  SerialIoGUID  Serial IO protocol GUID
 * @return TRUE if key was handled
 */
BOOLEAN
TerminalConOutHandleKey(
    IN UINT8        KeyIndex,
    IN TERMINAL_DEV *Context,
    IN EFI_GUID     *SerialIoGUID
    );

//=============================================================================
// SPCR Table Installation
//=============================================================================

/**
 * TerminalInstallSpcrTable - Install ACPI SPCR table
 * @0x1ABC
 *
 * Constructs and installs the Serial Port Console Redirection (SPCR) table:
 *   Signature: "SPCR" (0x52435053)
 *   Length: 80 bytes
 *   Revision: 2
 *   OEM ID: "A M I "
 *   OEM Table ID: 0x56204F49545041 ("APTIO V")
 *   Creator ID: 0x2E494D41 ("AMI.")
 *   Creator Rev: 0x0005000E
 *
 * Data sourced from hardware config bytes:
 *   byte_6E4B, byte_5C28 (interface type)
 *   byte_6E51, byte_6E49, byte_6E4A (config)
 *   byte_6E4D-E (legacy config for < rev 2)
 *
 * @param  AcpiTable  ACPI Table Protocol interface
 * @param  SerialIo   Serial IO config pointer (for baud/parity/stop/flow)
 * @return EFI_STATUS
 */
EFI_STATUS
TerminalInstallSpcrTable(
    IN EFI_ACPI_TABLE_PROTOCOL  *AcpiTable,
    IN TERMINAL_DEV             *SerialIo
    );

//=============================================================================
// Library Functions (Statically linked)
//=============================================================================

/**
 * GuidCompare - Compare two GUIDs
 * @0x4118
 * Compares two 16-byte GUIDs via two 8-byte uint64 comparisons.
 */
BOOLEAN
GuidCompare(
    IN EFI_GUID  *Guid1,
    IN EFI_GUID  *Guid2
    );

/**
 * PcdGetPtr - Get PCD database pointer
 * @0x4180
 * Locates and caches EFI_PCD_PROTOCOL. First call locates via
 * gBS->LocateProtocol, subsequent calls return cached pointer.
 */
VOID *
PcdGetPtr(
    VOID
    );

/**
 * ReadUnaligned64 - Read unaligned 64-bit value
 * @0x420C
 */
UINT64
ReadUnaligned64(
    IN VOID  *Buffer
    );

/**
 * DebugLibGetDebugMask - Get debug mask
 * @0x423C
 */
UINT64
DebugLibGetDebugMask(
    VOID
    );

/**
 * DebugPrint - Print debug message
 * @0x42BC
 */
UINTN
DebugPrint(
    IN UINTN       ErrorLevel,
    IN CONST CHAR8 *Format,
    ...
    );

/**
 * AssertReport - Report assertion failure
 * @0x4304
 */
VOID
AssertReport(
    IN CONST CHAR8  *FileName,
    IN UINTN        LineNumber,
    IN CONST CHAR8  *Condition
    );

/**
 * HobLibGetHobList - Get HOB list pointer
 * @0x4344
 * Finds HOB list from system table configuration table array.
 */
VOID *
HobLibGetHobList(
    VOID
    );

/**
 * PoolAllocate - Allocate memory pool
 * @0x4424
 */
VOID *
PoolAllocate(
    IN UINTN  Size
    );

/**
 * PoolAllocateZero - Allocate + zero memory pool
 * @0x4450
 */
VOID *
PoolAllocateZero(
    IN UINTN  Size
    );

/**
 * FvFileListSize - Calculate FV file list size
 * @0x4490
 */
UINTN
FvFileListSize(
    IN UINT8  *List
    );

/**
 * FvFileListAppend - Append entry to FV file list
 * @0x44E4
 */
UINT8 *
FvFileListAppend(
    IN UINT8  *List,
    IN UINT8  *Entry
    );

/**
 * FvFileListFindEnd - Find end marker in FV file list
 * @0x45BC
 */
UINT8 *
FvFileListFindEnd(
    IN UINT8  *List
    );

/**
 * FvFileListFindPrev - Find previous entry in FV file list
 * @0x460C
 */
UINT8 *
FvFileListFindPrev(
    IN UINT8  *List
    );

/**
 * FvFileListDuplicate - Duplicate FV file list
 * @0x463C
 */
UINT8 *
FvFileListDuplicate(
    IN UINT8  *List
    );

/**
 * CompareMem - Compare memory regions
 * @0x46B8
 */
INTN
CompareMem(
    IN CONST VOID  *Dest,
    IN CONST VOID  *Src,
    IN UINTN       Length
    );

/**
 * UnicodeSPrintAsciiFmt - SPrint with ASCII format string
 * @0x4940
 */
UINTN
UnicodeSPrintAsciiFmt(
    OUT CHAR16      *Buffer,
    IN CONST CHAR8  *Format,
    ...
    );

/**
 * UnicodeSPrint - Full Unicode SPrint
 * @0x4968
 */
UINTN
UnicodeSPrint(
    OUT CHAR16      *Buffer,
    IN UINTN        BufferSize,
    IN CONST CHAR8  *Format,
    IN VA_LIST      Args
    );

/**
 * DebugPortDetect - Detect debug port via CMOS
 * @0x4E00
 */
UINTN
DebugPortDetect(
    VOID
    );

/**
 * SetMem - Fill memory with byte value
 * @0x4EA0
 */
VOID *
SetMem(
    OUT VOID   *Buffer,
    IN UINTN   Size,
    IN UINT8   Value
    );

/**
 * CopyMem - Copy memory (handles overlap)
 * @0x4F00
 */
VOID *
CopyMem(
    OUT VOID       *Dest,
    IN CONST VOID  *Src,
    IN UINTN       Size
    );