[Soekris] A bug in BIOS causes the "invisible output from FreeBSD boot loader" problem (analysis and interim workaround inside)
Eugene M. Kim
20080619.soekris.com at ab.ote.we.lv
Wed Jun 25 09:36:25 UTC 2008
Hello,
I just received my net5501 and have been playing with it;
unsurprisingly, the "invisible output" problem has hit me too. :-)
After a script(1)-ed console session and a dive into the boot loader
code, I think I have found the problem: BIOS seems to incorrectly
implement the video INT 0x10 AH=0x09 "write character and attribute at
cursor position" (and possibly AH=0x0A "write character only at cursor
position" as well, as the two are very similar).
These two video INTs make BIOS write a character at the current cursor
position, /without/ advancing the cursor (unlike the "teletype" mode,
AH=0x0e). When emulating this on the serial console, just emitting the
character is not enough, because the terminal emulator is in the
teletype mode (surprise!) and advances the cursor to the next position;
the BIOS must emulate the "cursor not moved" behavior by emitting an
escape sequence (ESC H) to restore the cursor to the previous position.
However, the current BIOS does not restore the cursor position.
FreeBSD's vidconsole library has a subroutine named curs_move() (found
at src/sys/boot/i386/libi386/vidconsole.c:209 as of revision 1.20, which
is current in all of HEAD, RELENG_7 and RELENG_6). curs_move() uses INT
0x10 AH=0x09 internally to reset the character at the new cursor
position to ASCII space in order to ensure the cursor is visible at the
current location (this is a workaround for some buggy VGA hardware where
the cursor disappears if it is placed where a non-printable character is).
The FreeBSD boot loader interleaves calls to curs_move() and
write_char() (also in vidconsole.c) in order to print a string one
character a time, and with the Soekris BIOS not resetting the cursor
position after writing a character, only a space is displayed (by
curs_move()) at the desired position, and the real character (that
write_char() displays) ends up one column to the right, which then the
next call to curs_move() clobbers with another space. The end result is
that whatever character displayed is immediately erased, which precisely
is the problematic symptom.
There is a workaround, although it involves recompiling boot loaders
(unfortunately): Since we are not dealing with the real video hardware,
boot loader need not reset the character at the new cursor location
after moving the cursor; this can be done by commenting out the call to
write_char() in curs_move().
Cheers,
Eugene
More information about the Soekris-tech
mailing list