For a new feature in my application I want to detect keypresses in the ROM-BIOS's circular buffer in the BIOS Data Area at segment 40h. I need to detect keypresses anywhere in the buffer, not just at the current head, therefore using interrupt 16h function 01h is not sufficient. The circular buffer defaults to extending from 40h:1Eh up to below 40h:3Eh. The "head" offset into the buffer is stored in the word [40h:1Ah] and the "tail" offset is in word [40h:1Ch].
However, some ROM-BIOSes allow relocating the buffer away from its default location. Those that do use the word [40h:80h] as the start offset of the buffer and word [40h:82h] as the end offset of the buffer. References such as this one often contain notes like this though:
Note: this variable is not supported on many systems, be careful if you use it.
Another reference appears to indicate that some specific ROM-BIOS revisions support these fields, presumably implying that others don't:
BIOS 10-27-82
I put this code into my application's initialisation. It checks whether the values in the extension fields appear valid. This means they must be nonzero both, the end must be above the start, the delta end minus start must be even, and both the head and the tail offsets must each be above-or-equal the start, below the end, and an even amount of bytes from the start.
push ds
mov ax, 40h
mov ds, ax
mov ax, word [82h] ; end of circular keypress buffer
mov dx, word [80h] ; start of circular buffer
test ax, ax
jz .forcekeybuffer
test dx, dx
jz .forcekeybuffer
mov bx, ax
sub bx, dx ; cmp end, start
jbe .forcekeybuffer ; below or equal is invalid -->
test bl, 1 ; even amount of bytes ?
jnz .forcekeybuffer ; no, invalid -->
mov bx, word [1Ah] ; current head of circular buffer
cmp bx, ax
jae .forcekeybuffer
sub bx, dx
jb .forcekeybuffer
test bl, 1
jnz .forcekeybuffer ; invalid -->
mov bx, word [1Ch] ; current tail of circular buffer
cmp bx, ax
jae .forcekeybuffer
sub bx, dx
jb .forcekeybuffer
test bl, 1
jz @F ; valid -->
.forcekeybuffer:
pop ds
mov word [io_end_buffer], 3Eh
mov word [io_start_buffer], 1Eh
db __TEST_IMM8 ; (skip pop)
@@:
pop ds
This code is meant to check the keypress buffer for Ctrl-C presses. It is where I use the variables:
handle_serial_flags_ctrl_c:
[...]
.check_rombios_buffer:
push bx
push dx
mov ax, 40h ; dual mode segment/selector
push ax
mov ax, word [io_end_buffer]
mov dx, word [io_start_buffer]
pop ds
test ax, ax
jnz @F
mov ax, word [82h] ; end of circular keypress buffer
@@:
test dx, dx
jnz @F
mov dx, word [80h] ; start of circular buffer
@@:
mov bx, ax
sub bx, dx ; cmp end, start
jbe .ret_dx_bx ; invalid -->
test bl, 1 ; even amount of bytes ?
jnz .ret_dx_bx ; invalid -->
mov bx, word [1Ah] ; current head of circular buffer
.loop:
cmp bx, word [1Ch] ; equal to current tail ?
je .ret_dx_bx ; yes, all entries checked -->
cmp byte [bx], 3 ; is it Ctrl-C ?
je handle_ctrl_c ; yes, handle -->
inc bx
inc bx ; -> next entry
cmp bx, ax ; at end of buffer ?
jb .loop ; no, loop -->
ja .ret_dx_bx ; invalid -->
mov bx, dx ; reset to start of buffer
jmp .loop ; then loop -->
.ret_dx_bx:
pop dx
pop bx
Before the initialisation the variables default to zero both. A user can force the variables to any nonzero value (usually 1Eh and 3Eh then to use the default buffer area) or to zero (to use the extension's fields).
Is there any more reliable way to detect whether the extension is supported by the BIOS?
Note: I do not want to disassemble or trace the interrupt 09h (IRQ #1) or interrupt 16h handlers. I also do not want to wait for an actual keypress to arrive, so I cannot experimentally change/set the extension fields to find out whether they are supported.