Skip to content

ADR: SOL Terminal Emulation & OEM Capabilities Encoding Support

Natalie Gaston edited this page Oct 16, 2026 · 2 revisions

Status

Proposed

Context

Serial-over-LAN (SOL) redirection on Intel vPro and ISM devices transmits text and control sequences from remote platforms during BIOS POST and runtime execution. Currently, ui-toolkit decodes incoming SOL data before passing it down to frontend component wrappers (ui-toolkit-angular, ui-toolkit-react) and consumer applications (such as sample-web-ui and console).

As tracked in ui-toolkit Issue #1855 and ui-toolkit Issue #1768, character rendering corruptions occur under two primary conditions:

  1. Multi-byte UTF-8 split across chunks: Network packets and WebSocket chunks may break multi-byte UTF-8 characters across boundaries, causing chunk-by-chunk decoders to treat partial trailing bytes as invalid sequences.
  2. Character set and emulation mismatches: Legacy BIOS setup screens transmit OEM terminal emulation types (such as PC-ANSI single-byte high-ASCII box-drawing characters like 0xDA, 0xC4, 0xBF), but the toolkit blindly decodes them as UTF-8, resulting in garbled replacement glyphs (reported in Console BIOS Issue #530).

According to the Intel CSME/AMT Redirection specifications, the 2nd Byte of OEM Capabilities (Terminal Emulation) defines the terminal emulation expected by the remote host:

  • Bit 0:3 – Terminal Type:
    • 1 – VT52 (Basic monochrome)
    • 2 – VT100+ (Adds function keys F5–F14; Note: Deprecated/unsupported in CSME 14.0 and later)
    • 3 – VT-UTF8 (Adds function key F8; standard streaming UTF-8)
    • 4 – PC-ANSI (Standard PC-ANSI / Code Page 437 box-drawing characters)
    • 5 and higher – Reserved for future definitions

To support both modern and legacy devices, console operators require the ability to configure or override the terminal emulation type directly from the UI, with sensible automatic defaults derived from device OEM capabilities.


Decision Drivers

  • Spike Objectives (Issue #1855): Resolve character rendering distortions on Intel vPro and ISM devices without regressing legacy BIOS terminal rendering.
  • Fidelity Across Generations: Modern environments expect standard VT-UTF8, whereas legacy BIOS setup utilities depend heavily on CP437/PC-ANSI box-drawing characters or VT52 sequences.
  • Split-Chunk Stream Safety: Seamlessly buffer and stitch multi-byte characters split across chunk boundaries without leaking memory or corrupting succeeding sessions.
  • Separation of Concerns: Keep core byte decoding and emulation translations centralized within ui-toolkit, keeping ui-toolkit-angular and ui-toolkit-react wrappers lightweight.
  • User Control & Fallback: Support auto-negotiation via OEM capabilities while giving UI operators manual dropdown controls to override terminal emulation if firmware reports incorrect flags.

Decisions

D1 — Represent Terminal Types via an Explicit Enum in ui-toolkit

Define a strongly typed enum matching the OEM capability bit definitions:

export enum SolTerminalType {
  VT52 = 1,
  VT100Plus = 2, // Deprecated in CSME >= 14.0; maintained for backwards compatibility
  VTUTF8 = 3,
  PCANSI = 4
}
  • Deprecation metadata and UI annotations will flag VT100Plus as unavailable or deprecated for CSME >= 14.0 platforms.

D2 — Decouple Character Decoding from Terminal Sequence Emulation

TerminalDataProcessor in ui-toolkit will manage both a stateful byte decoder and an emulation profile based on the active terminal mode:

  1. VT-UTF8 Mode: Employs a stateful stream decoder (new TextDecoder('utf-8', { fatal: false }) using { stream: true }). Trailing partial multi-byte sequences are retained between chunk boundaries and resolved with subsequent data.
  2. PC-ANSI / CP437 Mode: Maps single-byte high-ASCII characters (0x80–0xFF) directly to corresponding Unicode characters (e.g., box-drawing glyphs ┌, ─, ┐, │) via a lookup table, preserving legacy BIOS setup screens.
  3. VT52 Mode: Decodes 7-bit ASCII and maps legacy 2-byte escape sequences (<ESC>A through <ESC>K) into standard xterm-compatible cursor movement sequences.

D3 — Implement Safe Buffer Lifecycle and Memory Guardrails

To address vulnerabilities identified during review of PR #1800:

  • Hard Buffer Boundary: The cache for split trailing bytes is capped at 3 bytes (the maximum possible incomplete prefix for a 4-byte UTF-8 character). If an invalid sequence persists beyond this boundary, the buffer is purged, a replacement character (\uFFFD) is output, and the state resets.
  • Session Lifecycle Hook (reset()): An explicit .reset() method flushes all cached state upon WebSocket disconnects, session renegotiation, or terminal type switching, preventing stale bytes from bleeding into new sessions.

D4 — Dynamic UI Configuration and Selection

The UI architecture will support capability-negotiated defaults alongside manual operator overrides:

  • Default Negotiation: When the redirector completes the capability handshake, the initial terminal emulation type defaults to the value parsed from Bit 0:3 of the 2nd Byte of OEM Capabilities.
  • UI Selector: A dropdown menu is exposed in the terminal toolbar across consumer applications (sample-web-ui, console) displaying:
    • VT-UTF8 (Default for modern firmware)
    • PC-ANSI (Recommended for BIOS setup menus)
    • VT52
    • VT100+ (Marked as "Legacy only (< CSME 14)")
  • Dynamic selection changes take effect immediately on TerminalDataProcessor without restarting or dropping the underlying WebSocket redirector connection.

Architecture Flow

┌────────────────────────────────────────────────────────┐
│               Consumer UI / Sample Web UI              │
│     [ Terminal Selector: VT-UTF8 | PC-ANSI | VT52 ]    │
└──────────────────────────┬─────────────────────────────┘
                           │ (Input / Property Change)
┌──────────────────────────▼─────────────────────────────┐
│       ui-toolkit-angular / ui-toolkit-react Wrappers   │
└──────────────────────────┬─────────────────────────────┘
                           │ setTerminalType(type)
┌──────────────────────────▼─────────────────────────────┐
│                 ui-toolkit Core                        │
│  ┌──────────────────────────────────────────────────┐  │
│  │             TerminalDataProcessor                │  │
│  │                                                  │  │
│  │   Incoming Chunks ──► [ Stateful Stream Cache ]  │  │
│  │                                │                 │  │
│  │                      Active Decoder Match        │  │
│  │                     ┌──────────┴──────────┐      │  │
│  │                     ▼                     ▼      │  │
│  │                [VT-UTF8]             [PC-ANSI]   │  │
│  └─────────────────────┬─────────────────────┬──────┘  │
└────────────────────────┼─────────────────────┼─────────┘
                         ▼                     ▼
             ┌─────────────────────────────────────┐
             │       xterm.js Terminal Display     │
             └─────────────────────────────────────┘

Consequences

Positive

  • Resolves Issue #1855: Eliminates character corruption caused by multi-byte UTF-8 splits across network packets.
  • Preserves Legacy Compatibility: Restores accurate layout and line drawing for console BIOS setup menus (Console Issue #530).
  • Specification Compliance: Aligns terminal handling with Intel CSME/AMT Redirection OEM capability bit specifications.
  • Manual Recovery Path: Enables operators to override emulation if BIOS firmware misreports capabilities.

Negative / Trade-offs

  • Encoding Lookup Table: Requires embedding a lightweight CP437-to-Unicode conversion mapping inside ui-toolkit for browser environments lacking native CP437 TextDecoder support.
  • Coordinated Rollout: Requires staged version bumps across multiple downstream repositories.

Repository Implementation & Rollout Plan

Step Repository Scope of Changes
1 ui-toolkit Implement SolTerminalType, update TerminalDataProcessor with stateful TextDecoder, add CP437 mapping, introduce setTerminalType() and reset().
2 ui-toolkit-angular Update ui-toolkit dependency; expose terminalType @Input() and change emitter.
3 ui-toolkit-react Update ui-toolkit dependency; expose terminalType prop and event callback.
4 sample-web-ui & console Upgrade wrapper dependencies; add terminal selection dropdown in the SOL action bar.

References

Clone this wiki locally