Skip to content
FreeDOSDeep Dive Published Updated 7 min readViews unavailable

INT 10h Character Fonts: Load, Select, and Restore EGA/VGA Text Glyphs

Load EGA/VGA text glyphs through INT 10h font services while respecting character maps, segment pointers, mode changes, and display restoration.

EGA and VGA video BIOS implementations provide INT 10h character-generator services for loading text-mode glyph data, selecting character maps, and retrieving font pointers. These operations change display hardware state, not the DOS keyboard layout or a text file’s encoding. A custom font can make a byte appear as a different glyph while leaving the byte value unchanged, so font loading is a presentation change rather than a character-code conversion.

The family of calls has multiple subfunctions with different consequences. AH=11h, AL=10h loads user-specified text-mode patterns and, according to the BIOS reference, recalculates display geometry and reprograms controller state. Other subfunctions load ROM fonts or copy patterns without the same complete mode-state transition. The exact target is EGA/VGA-family BIOS behavior, not a universal feature of every PC display adapter.

Character codes are indexes into a font map

In text mode, video memory stores character codes and attribute bytes. The active character generator uses the code to select glyph bits. A font table therefore associates a sequence of glyph patterns with character codes; it does not rewrite the screen’s stored bytes, convert a keyboard scan code, or update DOS code-page services.

This distinction matters for international text and box-drawing characters. If the keyboard produces one byte but the active font renders that code as another shape, changing the font may fix the visual appearance without changing file contents. Conversely, a font can make a screen look correct while the application still stores bytes from the wrong code page. Coordinate font state with DISPLAY.SYS, MODE CON, application encoding, and the actual data source rather than treating them as one feature.

Font geometry also affects the number of displayed rows. A character pattern’s height is expressed as bytes per character in the BIOS interface because each byte represents a scan line. If the mode or font height changes, the visible text area and cursor geometry may change as well. Do not assume that 80 columns by 25 rows remains active after a call that reprograms the display controller.

The AX=1110h user-font interface

The documented INT 10h call for loading user patterns uses AX=1110h. ES:BP points to the font table, CX is the count of patterns to store, DX is the starting character offset in the map-2 block, BH is bytes per character pattern, and BL selects the target block. RBIL notes that this function performs a mode-set-like reconfiguration without clearing the video buffer, is designed to be called immediately after a mode set, and requires page 0 to be active.

The following MASM/TASM-style register setup illustrates a 256-character, 8-by-16 font table located in the program’s code segment. It assumes MyFont contains exactly 4096 bytes and that the target BIOS supports this EGA/VGA service:

    mov ax, cs
    mov es, ax                 ; ES:BP addresses the font table
    mov bp, OFFSET MyFont
    mov cx, 256                ; glyph count
    xor dx, dx                 ; first character code
    mov bx, 1000h              ; BH=16 bytes/glyph, BL=font block 0
    mov ax, 1110h
    int 10h

MyFont db 4096 dup (?)         ; supply real glyph data in production

The placeholder table is not a useful font and must be replaced by valid glyph bytes. Keep the entire table readable through the segment pointer for the duration of the call, and ensure the data does not cross an invalid real-mode address boundary. A large or dynamically allocated table needs explicit segment:offset and size validation; a near pointer alone is not enough.

Because AL=10h changes video timing and row parameters, call it only in the documented sequence and verify mode/page/rows afterward. Preserve the existing screen state and font if the application must return control to a shell or another program. A call that works under a VGA emulator may still differ on EGA cards or clone BIOSes.

Query ROM fonts instead of guessing their address

AX=1130h retrieves font information on EGA/MCGA/VGA BIOSes. BH selects a pointer type, and the documented return includes ES:BP for the selected font, CX bytes per character, and DL row information. The returned ES:BP is an address supplied by the BIOS; do not substitute a hard-coded ROM address from a different adapter model.

The ROM-font selector values distinguish several font geometries, including 8-by-14, 8-by-8, and 8-by-16 variants on supported systems. The function can help an application copy a known system font into a working buffer before changing a small subset of glyphs. Validate the selected font and returned geometry; the current screen’s character size can differ from the requested pointer’s font size.

Some BIOS documentation reports off-by-one or row-count differences in returned display geometry on specific EGA implementations. Treat this as a compatibility concern: normalize using the relevant BIOS reference, query the active mode separately, and test the result on every supported adapter. Never use an unverified row count as a buffer-size calculation for direct screen writes.

Character-map selection and dual fonts

VGA hardware can support multiple character maps, and attribute bits can participate in selecting font blocks. The INT 10h font and block-selection calls are therefore related to attribute-controller state. The available blocks, supported height, and exact adapter behavior depend on BIOS and hardware capabilities. Before loading two fonts or changing block specifiers, inspect the adapter reference and test a controlled text screen.

Keep font changes coordinated with text attributes. If an application relies on the intensity bit for foreground colors, using that bit to select another font map can change color behavior. BIOS functions can update related state in coordinated ways, but a program that writes attribute-controller registers directly must understand the full VGA register model and should not concurrently rely on BIOS-maintained state.

For compatibility across adapters, prefer one active font and one documented geometry. If dual fonts or custom map blocks are essential, restrict the program to a tested EGA/VGA class and detect the required service before using it. Maintain a fallback ROM font or basic text mode that lets the operator recover when a custom glyph table cannot be loaded.

Restore the display as a shared resource

The current display is global machine state. A TSR, shell, ANSI driver, or another application may expect the standard font and row count. Saving only the current video mode is not enough if the application also changed font contents, character-map selection, blink/intensity mode, active page, or cursor shape.

Where BIOS services expose a supported way to retrieve the original font, copy it before modifying the active map. Save the mode and display geometry, perform the change, and restore in an order validated for the specific BIOS. Some custom calls should be used immediately after a mode set, so restoring a saved font may itself require resetting the mode first. Avoid a generic “restore everything” routine unless it is tested against the exact adapter family.

Provide a recovery path for abnormal termination. A program can display a message telling the operator how to reset to a standard mode, but that is not a substitute for normal cleanup. If the software cannot reliably restore a font after Ctrl-C, a crash, or a TSR conflict, keep the font operation out of general-purpose utilities and use it only in a program that owns the display session.

Validate content, geometry, and behavior separately

Build a test screen with all character codes the application needs and label the codes in hexadecimal. Confirm each glyph against an independent expected table. Then test row count, cursor visibility, page behavior, and the font after switching modes. If keyboard input is involved, separately record the byte read from BIOS/DOS and the glyph shown for that byte. This prevents a visual font correction from masking a code-page bug.

Test on the actual BIOS classes in scope: at minimum, the intended emulator profile and any physical VGA or EGA hardware claimed as supported. Include unsupported-function behavior, a missing or malformed font table, mode changes, page changes, and every exit path. A correct output image in one VM is useful but does not establish that every compatible BIOS will implement the function the same way.

For deployment, record adapter and BIOS identity, mode, font source hash, font dimensions, selected block, function numbers, return behavior, test glyphs, and restoration result. Keep the font file and expected checksum with the release. Treat custom glyph loading as a reversible display-state transition and never confuse it with file encoding or keyboard localization.

Related:

Sources:

Comments