How CSMWrap Works - FlyGoat/csmwrap GitHub Wiki

How CSMWrap Works

CSMWrap bridges the gap between a modern UEFI environment and the requirements of a legacy BIOS by performing a series of setup steps before handing control to a legacy operating system.

1. UEFI Entry Point (efi_main in csmwrap.c)

  • Initialization:
    • Sets up basic EFI services (console output via printf.c).
    • Allocates a private data structure (struct csmwrap_priv) to store state.
  • Hardware/Firmware Checks & Setup:
    • Legacy Region Unlocking (unlock_region.c): This is a critical step. The memory range 0xC0000-0xFFFFF (Option ROM and UMA area) must be made writable.
      • It first attempts to use EFI_LEGACY_REGION2_PROTOCOL.
      • If the protocol is unavailable or fails, it falls back to chipset-specific methods:
        • Intel chipsets: Modifies PAM (Programmable Attribute Map) registers via PCI configuration space (e.g., for PIIX4, Q35, Skylake+).
        • AMD chipsets: Modifies MTRRs (Memory Type Range Registers) to make the region write-back.
    • Video Initialization (video.c):
      • Identifies the active PCI VGA device, often by locating the EFI Graphics Output Protocol (GOP) provider.
      • Sets up the cb_framebuffer structure (part of the Coreboot table) with information from EFI GOP (resolution, framebuffer address, color depth). This information is used by SeaVGABIOS.
      • Decides whether to use the embedded SeaVGABIOS or try to load an Option ROM from the GPU.
    • ACPI Initialization (acpi.c):
      • Initializes the uACPI library.
      • Locates the RSDP (Root System Description Pointer) provided by the UEFI firmware. This RSDP will be passed to the legacy environment.
    • SMBIOS Table: The physical address of the SMBIOS table from UEFI is stored and later passed to the CSM.
    • E820 Memory Map (e820.c):
      • Calls UEFI GetMemoryMap() to get the current memory layout.
      • Converts UEFI memory types to E820 types.
      • Populates an E820 map, reserving space for the low stub, EBDA, and Option ROMs. This map is stored in the low stub area.
    • Coreboot Table (coreboot.c):
      • Builds a Coreboot-compatible parameter table in low memory. This table includes:
        • Memory ranges.
        • Serial port configuration (if any, usually stubbed).
        • Framebuffer information (from video.c).
        • ACPI RSDP pointer.
        • SMBIOS entry point.
        • CBMEM (Coreboot Memory) console (if logging via CBMEM is enabled).

2. Low Memory Stub Setup (csmwrap.h, csmwrap.c)

  • A block of conventional memory (below 1MB, typically starting at 0x00000) is allocated or reserved. This "low stub" area is crucial for the 16-bit environment.
  • It contains:
    • The SeaBIOS CSM binary (Csm16.bin from src/bins/Csm16.h, relocated here).
    • The SeaBIOS VBIOS binary (vgabios.bin from src/bins/vgabios.h, placed typically at 0xC0000 after shadowing).
    • The generated E820 memory map.
    • The Coreboot table.
    • Space for the CSM's BDA (BIOS Data Area) and EBDA (Extended BIOS Data Area).
    • A small 16-bit thunking mechanism (Thunk16.asm*, x86thunk.c) to transition between UEFI's protected/long mode and the CSM's 16-bit real mode.
    • Space for the CSM's runtime stack.

3. CSM Initialization and Boot Handoff

  • Intel Platform Workarounds (intel_workarounds.c): Applies specific workarounds, such as disabling the 8254 PIT Programmable Interval Timer's "Gate Enable" (8254CGE) on certain Intel chipsets to prevent conflicts.
  • Thunking to CSM:
    • The EFI_LEGACY_BIOS_PROTOCOL equivalent functions are invoked using the 16-bit thunk.
    • The primary function called is Compatibility16InitializeYourself (or its modern equivalent name in SeaBIOS CSM). This function within Csm16.bin:
      • Initializes legacy hardware (PIC, PIT, DMA controllers).
      • Sets up interrupt vectors.
      • Scans for and initializes Option ROMs (including the VBIOS at 0xC0000).
      • Builds the BBS (BIOS Boot Specification) table.
  • Video Option ROM / SeaVGABIOS:
    • If a GPU Option ROM is used, it's loaded and executed.
    • If SeaVGABIOS is used, it's copied to 0xC0000 and initialized. It uses the framebuffer information from the Coreboot table to set up a VBE (VESA BIOS Extensions) compatible display mode.
  • Preparing for ExitBootServices:
    • ACPI tables are finalized for handoff (acpi_prepare_exitbs).
    • UEFI video output via GOP might be disabled if SeaVGABIOS has taken over.
  • Exiting Boot Services:
    • ExitBootServices() is called. This terminates all UEFI runtime services except for a minimal set (like reset/shutdown, GetTime, SetVariable if persistent).
    • CSMWrap takes full control of the hardware.
  • Final Legacy Setup:
    • External interrupts are disabled.
    • The 8259 PIC is programmed to its default legacy state.
    • The PIT is programmed to its default legacy state.
  • Legacy Boot:
    • The CSM's Compatibility16Boot function (or equivalent) is called via thunk.
    • This function typically performs an INT 19h (System Bootstrap) to load the boot sector from the highest priority device in the BBS table.

Key Components and Binaries

  • Csm16.bin (from SeaBIOS, embedded in src/bins/Csm16.h): The core Compatibility Support Module. It handles most of the legacy BIOS emulation, Option ROM scanning, and boot device management.
  • vgabios.bin (from SeaBIOS, embedded in src/bins/vgabios.h): A VESA-compliant VBIOS. It provides INT 10h video services.
  • Thunk16.asm32 / Thunk16.asm64 and x86thunk.c: Code responsible for transitioning the CPU between UEFI's native mode (32-bit protected or 64-bit long mode) and the 16-bit real mode required by the CSM.
  • uACPI (uACPI/ submodule): A lightweight ACPI library used to parse and manage ACPI tables.
  • Nyu-EFI (nyu-efi/ submodule): Provides a minimal C runtime, EFI headers, and the linker script for building UEFI applications.

This steps allows CSMWrap to create an environment where legacy operating systems believe they are running on a traditional BIOS-based machine.