KVM Guide

Configure remote keyboard, video, and mouse access on OpenBMC.

Table of Contents

  1. Overview
  2. Hardware Requirements
    1. Video Capture
    2. USB Device Controller
  3. Setup & Configuration
    1. Build-Time Configuration (Yocto)
    2. bmcweb KVM Options
    3. Device Tree Configuration
    4. Runtime Configuration
  4. Accessing KVM
    1. Via WebUI
    2. Via Direct noVNC
    3. Via VNC Client
  5. Configuration Options
    1. Video Quality Settings
    2. USB HID Configuration
    3. Session Limits
  6. Power State Considerations
    1. KVM Availability by State
    2. BIOS/UEFI Configuration
  7. Input Handling
    1. Keyboard Mapping
    2. Special Key Combinations
    3. Mouse Configuration
  8. Troubleshooting
    1. No Video Display
    2. Black Screen
    3. Keyboard/Mouse Not Working
    4. Connection Drops
    5. Performance Issues
  9. Security Considerations
    1. Authentication
    2. Session Management
    3. Encryption
  10. Enabling/Disabling KVM
    1. Build-Time Disable
    2. Runtime Disable
  11. Deep Dive
    1. Video Capture Pipeline
    2. RFB (VNC) Protocol Frame Updates
    3. USB HID Gadget Protocol
    4. WebSocket to VNC Bridge
    5. Source Code Reference
  12. References

Overview

KVM (Keyboard, Video, Mouse) provides remote graphical console access to the host system, allowing operators to interact with the system as if they were physically present. OpenBMC implements KVM through obmc-ikvm.

---
title: KVM Architecture
---
flowchart TB
    subgraph client["Browser/Client"]
        direction LR
        subgraph novnc["noVNC (JavaScript VNC Client)"]
            direction LR
            video["Video Display"]
            keyboard["Keyboard Input"]
            mouse["Mouse Input"]
        end
    end

    client -->|"WebSocket / TCP:5900"| bmcweb

    subgraph bmcweb["bmcweb (WebSocket proxy)"]
    end

    bmcweb --> ikvm

    subgraph ikvm["obmc-ikvm"]
        direction LR
        capture["Video Capture<br/>(JPEG/ASTC)"]
        hid["USB HID Gadget<br/>(Keyboard/Mouse)"]
    end

    capture --> videohw["Video Capture HW<br/>(ASPEED/Nuvoton)"]
    hid --> usbctrl["USB Device Controller"]

    videohw --> host
    usbctrl --> host

    subgraph host["Host System"]
        direction LR
        vga["VGA output"]
        usb["USB ports"]
    end
ASCII-art version (click to expand)
┌─────────────────────────────────────────────────────────────────┐
│                       KVM Architecture                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │                      Browser/Client                         ││
│  │                                                             ││
│  │   ┌──────────────────────────────────────────────────────┐  ││
│  │   │     noVNC (JavaScript VNC Client)                    │  ││
│  │   │                                                      │  ││
│  │   │   Video Display  │  Keyboard Input  │  Mouse Input   │  ││
│  │   └──────────────────────────────────────────────────────┘  ││
│  └──────────────────────────┬──────────────────────────────────┘│
│                             │                                   │
│                     WebSocket / TCP:5900                        │
│                             │                                   │
│  ┌──────────────────────────┴──────────────────────────────────┐│
│  │                        bmcweb                               ││
│  │                  (WebSocket proxy)                          ││
│  └──────────────────────────┬──────────────────────────────────┘│
│                             │                                   │
│  ┌──────────────────────────┴──────────────────────────────────┐│
│  │                       obmc-ikvm                             ││
│  │                                                             ││
│  │   ┌─────────────────┐  ┌─────────────────┐                  ││
│  │   │  Video Capture  │  │  USB HID Gadget │                  ││
│  │   │  (JPEG/ASTC)    │  │  (Keyboard/Mouse│                  ││
│  │   └────────┬────────┘  └────────┬────────┘                  ││
│  └────────────┼────────────────────┼───────────────────────────┘│
│               │                    │                            │
│  ┌────────────┴────────┐  ┌────────┴────────┐                   │
│  │  Video Capture HW   │  │   USB Device    │                   │
│  │  (ASPEED/Nuvoton)   │  │   Controller    │                   │
│  └─────────────────────┘  └─────────────────┘                   │
│               │                    │                            │
│               └────────┬───────────┘                            │
│                        │                                        │
│  ┌─────────────────────┴───────────────────────────────────────┐│
│  │                    Host System                              ││
│  │              (VGA output, USB ports)                        ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘

Hardware Requirements

Video Capture

KVM requires hardware video capture capability:

BMC SoC Video Capture Compression
ASPEED AST2500/2600 VGA capture engine JPEG, ASPEED proprietary
Nuvoton NPCM7xx GFX capture JPEG

USB Device Controller

For keyboard/mouse input:

BMC SoC USB Controller Gadget Support
ASPEED AST2500/2600 USB 2.0 device HID gadget
Nuvoton NPCM7xx USB device HID gadget

Setup & Configuration

Build-Time Configuration (Yocto)

# In your machine .conf or local.conf

# Include KVM support
IMAGE_INSTALL:append = " obmc-ikvm"

# Enable KVM in bmcweb
EXTRA_OEMESON:pn-bmcweb = " \
    -Dkvm=enabled \
"

# For ASPEED-based systems
PREFERRED_PROVIDER_virtual/obmc-host-ipmi-hw = "phosphor-ipmi-kcs"
MACHINE_FEATURES:append = " obmc-ikvm"

bmcweb KVM Options

Option Default Description
kvm enabled Enable KVM WebSocket support
insecure-kvm-auth disabled Allow unauthenticated KVM (testing only)

Device Tree Configuration

ASPEED systems require video capture configuration:

// Device tree snippet for AST2500/2600
&video {
    status = "okay";
    memory-region = <&video_memory>;
};

&gfx {
    status = "okay";
    memory-region = <&gfx_memory>;
};

Runtime Configuration

# Check obmc-ikvm service
systemctl status obmc-ikvm

# View KVM logs
journalctl -u obmc-ikvm -f

# Restart KVM service
systemctl restart obmc-ikvm

Accessing KVM

Via WebUI

  1. Login to WebUI at https://<bmc-ip>/
  2. Navigate to OperationsKVM Console
  3. Click Open in new tab or use embedded viewer
  4. Interact with host display, keyboard, and mouse

Via Direct noVNC

# Access noVNC directly (if exposed)
https://<bmc-ip>/kvm/0

# Or via Redfish link
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/Managers/bmc
# Look for GraphicalConsole link

Via VNC Client

For direct VNC client access (if enabled):

# Connect with VNC viewer
vncviewer bmc-ip:5900

# With password (if configured)
vncviewer -passwd ~/.vnc/passwd bmc-ip:5900

Configuration Options

Video Quality Settings

# Video quality is typically controlled via obmc-ikvm configuration
# Check available options
obmc-ikvm --help

# Common options:
# -f framerate    : Target frame rate
# -q quality      : JPEG quality (1-100)
# -r resolution   : Force resolution

USB HID Configuration

# USB HID gadget is typically auto-configured
# Check USB gadget status
ls /sys/kernel/config/usb_gadget/

# Verify HID devices
ls /dev/hidg*

Session Limits

Configure via bmcweb:

// In bmcweb configuration
// Maximum concurrent KVM sessions (typically 1-2)
static constexpr size_t maxKvmSessions = 2;

Power State Considerations

KVM Availability by State

Host Power State Video Capture KVM Available
Off No output Blank screen
On (POST) BIOS output Yes
On (OS) OS display Yes
Sleep May blank Limited

BIOS/UEFI Configuration

For best KVM experience, configure host BIOS:

  1. Set video output to onboard/BMC VGA
  2. Disable GPU priority if using external graphics
  3. Enable legacy VGA for BIOS screens

Input Handling

Keyboard Mapping

Client Keyboard → noVNC → bmcweb WebSocket → obmc-ikvm → USB HID → Host

Common key mappings:

Client Key Host Key Notes
Ctrl+Alt+Del Ctrl+Alt+Del Captured by noVNC
F1-F12 F1-F12 Pass through
Alt+Tab Alt+Tab May be captured locally
Print Screen Print Screen Pass through

Special Key Combinations

Access via noVNC toolbar or keyboard shortcuts:

  • Ctrl+Alt+Delete: Send to remote
  • Ctrl+Alt+F1-F6: Virtual terminal switch (Linux)
  • Windows Key: May need special handling

Mouse Configuration

# Mouse is typically absolute positioning
# If relative mode needed, configure in obmc-ikvm

# Check mouse mode
cat /sys/class/usb_role/*/role

Troubleshooting

No Video Display

# Check video capture hardware
ls /dev/video*

# Check video capture service
systemctl status obmc-ikvm

# View video device info
v4l2-ctl --all

# Check memory regions
cat /proc/iomem | grep -i video

Black Screen

# Verify host is powered on
obmcutil state

# Check if host is generating video
# May need to check VGA cable connection

# Try resetting video capture
systemctl restart obmc-ikvm

Keyboard/Mouse Not Working

# Check USB HID gadget
ls /dev/hidg*

# Verify USB connection to host
# Check host BIOS for USB settings

# Reload USB gadget
modprobe -r g_hid
modprobe g_hid

Connection Drops

# Check bmcweb WebSocket
journalctl -u bmcweb | grep -i kvm

# Check network connectivity
ping bmc-ip

# Verify KVM session count
# Too many sessions may cause issues

Performance Issues

# Reduce quality for bandwidth
# Adjust frame rate
# Check network latency

# Monitor bandwidth usage
iftop -i eth0

Security Considerations

Authentication

KVM access requires Redfish authentication:

# KVM WebSocket is authenticated via session token
# Ensure strong passwords for KVM users

# Create operator account for KVM
curl -k -u root:0penBmc -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "UserName": "kvmuser",
        "Password": "SecurePass123!",
        "RoleId": "Operator"
    }' \
    https://localhost/redfish/v1/AccountService/Accounts

Session Management

# View active sessions
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/SessionService/Sessions

# Terminate KVM session (close WebSocket)
# Sessions auto-terminate on browser close

Encryption

All KVM traffic is encrypted via HTTPS/WSS:

Browser ←→ bmcweb: TLS 1.2/1.3

Enabling/Disabling KVM

Build-Time Disable

# Remove KVM from build
EXTRA_OEMESON:pn-bmcweb = " \
    -Dkvm=disabled \
"
IMAGE_INSTALL:remove = "obmc-ikvm"

Runtime Disable

# Stop KVM service
systemctl stop obmc-ikvm
systemctl disable obmc-ikvm

# Re-enable
systemctl enable obmc-ikvm
systemctl start obmc-ikvm

Deep Dive

Advanced implementation details for KVM developers.

Video Capture Pipeline

---
title: Video Capture Processing Pipeline
---
flowchart TB
    vga["HOST VGA OUTPUT<br/>Analog VGA signals<br/>(R, G, B, HSync, VSync)"]

    subgraph aspeed["ASPEED Video Engine (AST2500/2600)"]
        direction TB
        adc["1. ADC Capture<br/>VGA signals → 10-bit ADC sampling<br/>Sync detection → resolution auto-detect"]
        fb["2. Frame Buffer<br/>Raw pixels → Video memory<br/>Format: RGB565 or RGB888"]
        jpeg["3. Hardware JPEG Encoder<br/>Full frame → DCT → Quantization → Huffman<br/>Or: Software via libjpeg-turbo"]
        adc --> fb --> jpeg
    end

    subgraph ikvm["obmc-ikvm Video Processing"]
        direction TB
        capture["Frame Capture Loop"]
        dequeue["1. Dequeue buffer from V4L2"]
        dirty["2. Check for frame changes<br/>(dirty detection)"]
        compress["3. Compress changed regions"]
        send["4. Send via RFB protocol"]
        requeue["5. Requeue buffer"]
        capture --> dequeue --> dirty --> compress --> send --> requeue
        requeue -.->|"loop"| dequeue
    end

    vga --> aspeed
    aspeed -->|"/dev/video0 (V4L2)"| ikvm

    options["Compression Options:<br/>• JPEG (quality 10-100)<br/>• Raw (high bandwidth)<br/>• Tight encoding with zlib"]
ASCII-art version (click to expand)
┌────────────────────────────────────────────────────────────────────────────┐
│                      Video Capture Processing Pipeline                     │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                            │
│  HOST VGA OUTPUT                                                           │
│  ───────────────                                                           │
│        │                                                                   │
│        │ Analog VGA signals (R, G, B, HSync, VSync)                        │
│        v                                                                   │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  ASPEED Video Engine (AST2500/2600)                                 │   │
│  │                                                                     │   │
│  │  1. ADC Capture                                                     │   │
│  │     ─────────────                                                   │   │
│  │     VGA signals → 10-bit ADC sampling                               │   │
│  │     Sync detection → resolution/timing auto-detect                  │   │
│  │                                                                     │   │
│  │  2. Frame Buffer                                                    │   │
│  │     ────────────                                                    │   │
│  │     Raw pixels → Video memory (shared with ARM)                     │   │
│  │     Format: RGB565 or RGB888                                        │   │
│  │     Memory region: /dev/mem or videobuf2                            │   │
│  │                                                                     │   │
│  │  3. Hardware JPEG Encoder (Optional)                                │   │
│  │     ────────────────────────────────                                │   │
│  │     Full frame → DCT → Quantization → Huffman → JPEG stream         │   │
│  │     Or: Software compression via libjpeg-turbo                      │   │
│  └────────────────────────────────────────────────────────────────────-┘   │
│        │                                                                   │
│        │ /dev/video0 (V4L2 interface)                                      │
│        v                                                                   │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  obmc-ikvm Video Processing                                         │   │
│  │                                                                     │   │
│  │  Frame Capture Loop:                                                │   │
│  │  ─────────────────────                                              │   │
│  │  while (running) {                                                  │   │
│  │      // 1. Dequeue buffer from V4L2                                 │   │
│  │      ioctl(fd, VIDIOC_DQBUF, &buf);                                 │   │
│  │                                                                     │   │
│  │      // 2. Check for frame changes (dirty detection)                │   │
│  │      if (memcmp(current_frame, last_frame, size) != 0) {            │   │
│  │          // 3. Compress changed regions                             │   │
│  │          jpeg_data = compress_jpeg(current_frame, quality);         │   │
│  │                                                                     │   │
│  │          // 4. Send via RFB protocol                                │   │
│  │          send_rfb_update(jpeg_data);                                │   │
│  │      }                                                              │   │
│  │                                                                     │   │
│  │      // 5. Requeue buffer                                           │   │
│  │      ioctl(fd, VIDIOC_QBUF, &buf);                                  │   │
│  │  }                                                                  │   │
│  │                                                                     │   │
│  │  Compression Options:                                               │   │
│  │    - JPEG (quality 10-100, typical 50-80)                           │   │
│  │    - Raw (no compression, high bandwidth)                           │   │
│  │    - Tight encoding with zlib                                       │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                            │
└────────────────────────────────────────────────────────────────────────────┘

RFB (VNC) Protocol Frame Updates

---
title: RFB Protocol Frame Updates
---
sequenceDiagram
    participant Client as Client (noVNC)
    participant Server as Server (obmc-ikvm)

    Client->>Server: FramebufferUpdateRequest<br/>message-type: 3<br/>incremental: 1<br/>x: 0, y: 0<br/>width: 1920, height: 1080

    Note right of Server: Capture frame<br/>Detect changes<br/>Compress regions

    Server->>Client: FramebufferUpdate<br/>message-type: 0<br/>rectangles: 2

    Note left of Client: Rectangle 1: x:100 y:200<br/>400x300, JPEG encoding<br/>Rectangle 2: Cursor update

Encoding Types Supported:

Encoding ID Description
Raw 0 Uncompressed pixels (RGB888/RGB565)
CopyRect 1 Copy from another screen region
RRE 2 Rise and Run length Encoding
Hextile 5 16x16 tile-based compression
ZRLE 16 Zlib Run-Length Encoding
Tight 7 Tight compression with JPEG option
JPEG 21 JPEG-compressed rectangle
Cursor -239 Client-side cursor rendering
DesktopSize -223 Desktop size change notification

Tight Encoding Control Byte:

  • Bits 0-2: zlib stream reset flags
  • Bits 3-4: fill mode / filter
  • Bits 5-7: compression type (0x09 = JPEG, 0x00-0x07 = Basic)
  • JPEG Quality: pseudo-encoding -23 to -32 sets quality 0-9 (maps to 5-95%)
ASCII-art version (click to expand)
┌────────────────────────────────────────────────────────────────────────────┐
│                        RFB Protocol Frame Updates                          │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                            │
│  VNC (RFB) PROTOCOL MESSAGE FLOW                                           │
│  ───────────────────────────────                                           │
│                                                                            │
│  Client (noVNC)                            Server (obmc-ikvm)              │
│       │                                           │                        │
│       │  FramebufferUpdateRequest                 │                        │
│       │  ┌─────────────────────────┐              │                        │
│       │  │ message-type: 3         │              │                        │
│       │  │ incremental: 1          │              │                        │
│       │  │ x: 0, y: 0              │              │                        │
│       │  │ width: 1920             │              │                        │
│       │  │ height: 1080            │              │                        │
│       │  └─────────────────────────┘              │                        │
│       │────────────────────────────────────────-->│                        │
│       │                                           │                        │
│       │                                           │ Capture frame          │
│       │                                           │ Detect changes         │
│       │                                           │ Compress regions       │
│       │                                           │                        │
│       │              FramebufferUpdate            │                        │
│       │  ┌─────────────────────────────────────┐  │                        │
│       │  │ message-type: 0                     │  │                        │
│       │  │ number-of-rectangles: 2             │  │                        │
│       │  │                                     │  │                        │
│       │  │ Rectangle 1 (changed region):       │  │                        │
│       │  │   x: 100, y: 200                    │  │                        │
│       │  │   width: 400, height: 300           │  │                        │
│       │  │   encoding: JPEG (21)               │  │                        │
│       │  │   data: [compressed JPEG bytes]     │  │                        │
│       │  │                                     │  │                        │
│       │  │ Rectangle 2 (cursor update):        │  │                        │
│       │  │   encoding: Cursor (-239)           │  │                        │
│       │  │   data: [cursor bitmap + mask]      │  │                        │
│       │  └─────────────────────────────────────┘  │                        │
│       │<──────────────────────────────────────────│                        │
│       │                                           │                        │
│                                                                            │
│  ENCODING TYPES SUPPORTED:                                                 │
│  ─────────────────────────                                                 │
│                                                                            │
│  │ Encoding    │ ID   │ Description                              │         │
│  │─────────────│──────│──────────────────────────────────────────│         │
│  │ Raw         │ 0    │ Uncompressed pixels (RGB888/RGB565)      │         │
│  │ CopyRect    │ 1    │ Copy from another screen region          │         │
│  │ RRE         │ 2    │ Rise and Run length Encoding             │         │
│  │ Hextile     │ 5    │ 16x16 tile-based compression             │         │
│  │ ZRLE        │ 16   │ Zlib Run-Length Encoding                 │         │
│  │ Tight       │ 7    │ Tight compression with JPEG option       │         │
│  │ JPEG        │ 21   │ JPEG-compressed rectangle                │         │
│  │ Cursor      │ -239 │ Client-side cursor rendering             │         │
│  │ DesktopSize │ -223 │ Desktop size change notification         │         │
│                                                                            │
│  TIGHT ENCODING WITH JPEG (commonly used):                                 │
│  ─────────────────────────────────────────                                 │
│                                                                            │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  Tight Compression Control Byte:                                    │   │
│  │  ┌───┬───┬───┬───┬───┬───┬───┬───┐                                  │   │
│  │  │ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │                                  │   │
│  │  └───┴───┴───┴───┴───┴───┴───┴───┘                                  │   │
│  │    │   │   │   │   │   └───┴───┴─── zlib stream reset flags         │   │
│  │    │   │   │   └───┴────────────── fill mode / filter               │   │
│  │    └───┴───┴────────────────────── compression type                 │   │
│  │         0x09 = JPEG compression                                     │   │
│  │         0x00-0x07 = Basic compression                               │   │
│  │                                                                     │   │
│  │  JPEG Quality Level:                                                │   │
│  │    -23 to -32 pseudo-encoding sets quality 0-9 (maps to 5-95%)      │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                            │
└────────────────────────────────────────────────────────────────────────────┘

USB HID Gadget Protocol

┌────────────────────────────────────────────────────────────────────────────┐
│                        USB HID Gadget Implementation                       │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                            │
│  USB HID GADGET SETUP                                                      │
│  ────────────────────                                                      │
│                                                                            │
│  /sys/kernel/config/usb_gadget/kvm_gadget/                                 │
│  ├── idVendor              # 0x1d6b (Linux Foundation)                     │
│  ├── idProduct             # 0x0104 (Multifunction Composite Gadget)       │
│  ├── bcdDevice             # 0x0100                                        │
│  ├── bcdUSB                # 0x0200 (USB 2.0)                              │
│  ├── strings/0x409/                                                        │
│  │   ├── serialnumber      # BMC serial                                    │
│  │   ├── manufacturer      # OpenBMC                                       │
│  │   └── product           # Virtual KVM                                   │
│  ├── configs/c.1/                                                          │
│  │   ├── MaxPower          # 500 (mA)                                      │
│  │   ├── hid.keyboard -> functions/hid.keyboard                            │
│  │   └── hid.mouse -> functions/hid.mouse                                  │
│  └── functions/                                                            │
│      ├── hid.keyboard/                                                     │
│      │   ├── protocol      # 1 (Keyboard)                                  │
│      │   ├── subclass      # 1 (Boot Interface)                            │
│      │   ├── report_length # 8                                             │
│      │   └── report_desc   # HID Report Descriptor (binary)                │
│      └── hid.mouse/                                                        │
│          ├── protocol      # 2 (Mouse)                                     │
│          ├── subclass      # 1 (Boot Interface)                            │
│          ├── report_length # 6                                             │
│          └── report_desc   # HID Report Descriptor (binary)                │
│                                                                            │
│  KEYBOARD HID REPORT FORMAT (8 bytes):                                     │
│  ─────────────────────────────────────                                     │
│                                                                            │
│  ┌─────────┬─────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│  │ Byte 0  │ Byte 1  │ Byte 2 │ Byte 3 │ Byte 4 │ Byte 5 │ Byte 6 │ Byte 7 │
│  ├─────────┼─────────┼────────┼────────┼────────┼────────┼────────┼────────┤
│  │Modifier │Reserved │ Key 1  │ Key 2  │ Key 3  │ Key 4  │ Key 5  │ Key 6  │
│  │ Flags   │  (0x00) │        │        │        │        │        │        │
│  └─────────┴─────────┴────────┴────────┴────────┴────────┴────────┴────────┘
│                                                                            │
│  Modifier Flags (Byte 0):                                                  │
│    Bit 0: Left Ctrl     Bit 4: Right Ctrl                                  │
│    Bit 1: Left Shift    Bit 5: Right Shift                                 │
│    Bit 2: Left Alt      Bit 6: Right Alt                                   │
│    Bit 3: Left GUI      Bit 7: Right GUI (Windows key)                     │
│                                                                            │
│  Example: Ctrl+Alt+Delete                                                  │
│    [0x05, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00]                        │
│    0x05 = Left Ctrl (0x01) + Left Alt (0x04)                               │
│    0x4C = Delete key scancode                                              │
│                                                                            │
│  MOUSE HID REPORT FORMAT (6 bytes - Absolute):                             │
│  ────────────────────────────────────────────                              │
│                                                                            │
│  ┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐             │
│  │ Byte 0  │ Byte 1  │ Byte 2  │ Byte 3  │ Byte 4  │ Byte 5  │             │
│  ├─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤             │
│  │ Buttons │  X Low  │ X High  │  Y Low  │ Y High  │ Wheel   │             │
│  └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘             │
│                                                                            │
│  Buttons (Byte 0):                                                         │
│    Bit 0: Left button    Bit 2: Middle button                              │
│    Bit 1: Right button   Bits 3-7: Reserved                                │
│                                                                            │
│  X/Y: 16-bit absolute position (0-32767 maps to screen)                    │
│  Wheel: Signed 8-bit scroll delta                                          │
│                                                                            │
│  WRITING TO HID DEVICE:                                                    │
│  ──────────────────────                                                    │
│                                                                            │
│  // Send keyboard report                                                   │
│  int fd = open("/dev/hidg0", O_WRONLY);                                    │
│  uint8_t report[8] = {0x05, 0, 0x4C, 0, 0, 0, 0, 0};  // Ctrl+Alt+Del      │
│  write(fd, report, sizeof(report));                                        │
│                                                                            │
│  // Key release                                                            │
│  memset(report, 0, sizeof(report));                                        │
│  write(fd, report, sizeof(report));                                        │
│                                                                            │
└────────────────────────────────────────────────────────────────────────────┘

WebSocket to VNC Bridge

---
title: WebSocket Connection Establishment
---
sequenceDiagram
    participant Browser
    participant bmcweb
    participant ikvm as obmc-ikvm

    Browser->>bmcweb: GET /kvm/0<br/>Upgrade: websocket<br/>Sec-WebSocket-Protocol: binary
    bmcweb->>Browser: HTTP/1.1 101 Switching<br/>Connection: Upgrade<br/>Sec-WebSocket-Accept: [hash]

    Browser->>bmcweb: WebSocket Binary Frame
    bmcweb->>ikvm: Unix Socket<br/>/var/run/obmc-ikvm.sock
    ikvm->>bmcweb: RFB Protocol Version
    bmcweb->>Browser: WebSocket Binary Frame
---
title: KVM Data Flow
---
sequenceDiagram
    participant noVNC as noVNC (browser)
    participant bmcweb
    participant ikvm as obmc-ikvm
    participant Host

    noVNC->>bmcweb: KeyEvent (RFB msg)<br/>WebSocket binary frame
    bmcweb->>ikvm: Unix socket
    ikvm->>Host: write() /dev/hidg0<br/>USB HID report

    Host->>ikvm: Video capture<br/>V4L2 frame
    ikvm->>bmcweb: Unix socket (JPEG data)
    bmcweb->>noVNC: FramebufferUpdate<br/>WebSocket binary frame

bmcweb KVM Handler (kvm.hpp):

void handleKvmWebSocket(crow::websocket::Connection& conn) {
    // 1. Connect to obmc-ikvm Unix socket
    int sock = socket(AF_UNIX, SOCK_STREAM, 0);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, "/var/run/obmc-ikvm.sock", sizeof(...));
    connect(sock, (struct sockaddr*)&addr, sizeof(addr));

    // 2. Bidirectional forwarding
    // WebSocket → Unix socket (client input)
    conn.onMessage([sock](const std::string& msg) {
        write(sock, msg.data(), msg.size());
    });

    // Unix socket → WebSocket (video/responses)
    async_read(sock, buffer, [&conn](size_t bytes) {
        conn.sendBinary(buffer, bytes);
    });
}
ASCII-art version (click to expand)
┌────────────────────────────────────────────────────────────────────────────┐
│                    bmcweb KVM WebSocket Implementation                     │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                            │
│  WEBSOCKET CONNECTION ESTABLISHMENT                                        │
│  ─────────────────────────────────                                         │
│                                                                            │
│  Browser                      bmcweb                      obmc-ikvm        │
│     │                           │                             │            │
│     │  GET /kvm/0               │                             │            │
│     │  Upgrade: websocket       │                             │            │
│     │  Sec-WebSocket-Protocol:  │                             │            │
│     │    binary                 │                             │            │
│     │──────────────────────────>│                             │            │
│     │                           │                             │            │
│     │  HTTP/1.1 101 Switching   │                             │            │
│     │  Connection: Upgrade      │                             │            │
│     │  Sec-WebSocket-Accept:    │                             │            │
│     │    [calculated hash]      │                             │            │
│     │<──────────────────────────│                             │            │
│     │                           │                             │            │
│     │  [WebSocket Binary Frame] │  Unix Socket                │            │
│     │  RFB Protocol Version     │  /var/run/obmc-ikvm.sock    │            │
│     │<─────────────────────────>│<───────────────────────────>│            │
│     │                           │                             │            │
│                                                                            │
│  DATA FLOW:                                                                │
│  ─────────                                                                 │
│                                                                            │
│  ┌──────────┐      ┌──────────┐      ┌──────────┐      ┌──────────┐        │
│  │  noVNC   │      │  bmcweb  │      │obmc-ikvm │      │   Host   │        │
│  │(browser) │      │          │      │          │      │          │        │
│  └────┬─────┘      └────┬─────┘      └────┬─────┘      └────┬─────┘        │
│       │                 │                 │                 │              │
│       │  KeyEvent       │                 │                 │              │
│       │  (RFB msg)      │                 │                 │              │
│       │────────────────>│────────────────>│                 │              │
│       │   WebSocket     │  Unix socket    │  write()        │              │
│       │   binary frame  │                 │  /dev/hidg0     │              │
│       │                 │                 │────────────────>│              │
│       │                 │                 │   USB HID       │              │
│       │                 │                 │   report        │              │
│       │                 │                 │                 │              │
│       │                 │                 │  Video capture  │              │
│       │                 │                 │<────────────────│              │
│       │                 │                 │   V4L2 frame    │              │
│       │  FramebufferUp  │                 │                 │              │
│       │<────────────────│<────────────────│                 │              │
│       │   WebSocket     │  Unix socket    │                 │              │
│       │   binary frame  │  (JPEG data)    │                 │              │
│       │                 │                 │                 │              │
│                                                                            │
└────────────────────────────────────────────────────────────────────────────┘

Source Code Reference

Key implementation files in obmc-ikvm and bmcweb:

File Description
obmc-ikvm/ikvm_video.cpp V4L2 video capture and JPEG compression
obmc-ikvm/ikvm_input.cpp USB HID gadget keyboard/mouse handling
obmc-ikvm/ikvm_server.cpp RFB/VNC protocol server implementation
bmcweb/include/kvm_websocket.hpp WebSocket to Unix socket bridge
bmcweb/redfish-core/lib/managers.hpp GraphicalConsole Redfish resource

References


Tested on: OpenBMC master, requires hardware with video capture support


Back to top

OpenBMC Guide Tutorial is not affiliated with the OpenBMC project. Content is provided for educational purposes.

This site uses Just the Docs, a documentation theme for Jekyll.