[coreboot] [RFC] Universal panic-room serial console, for x86 BIOS bootblock
pete at akeo.ie
Mon Jul 11 19:02:03 CEST 2011
Having recently followed some of the old discussions regarding a
coreboot panic-room (eg. , ), I have been wondering whether it
would be possible to produce a universal panic-room/recovery console
implementation on x86, i.e. one that does not necessarily rely on code
that is mainboard specific, but is instead able to perform Super I/O and
UART detection and init, in a generic fashion (a bit like superiotool or
The main reason for not wanting to go the mainboard-specific route is
that there are a lot of motherboards out there where coreboot support is
unavailable, especially recent ones, and providing those with at least
some form of panic-room support may help with seeing coreboot
implemented. The ability to transfer a bare-metal flashrom, SerialICE,
or any other kind of payload to CAR (or to RAM, if a platform specific
RAM init payload has previously been transferred and run from CAR),
through Y-modem, would probably open a few new avenues for coreboot
This is why I am presenting a Proof of Concept, which I call UBRX, of a
near-universal yet *safe* method for detecting and providing a
panic-room type serial console, aimed at being included in an x86 BIOS
bootblock. My hope is that, should you be interested in such a concept,
it could become the base of the coreboot panic-room implementation.
Obviously, the focus of this exercise has to do with the safety of the
detection, as, if the code that is going to be included in a bona fide
BIOS bootblock, emphasis must be placed on making sure that no damage or
unwanted stress of any kind, will be incurred on the hardware, even when
run at every boot. While this may at first seem like an unreconcilable
goal with blanket detection, I believe it is actually possible to solve
the problem in a satisfactory way. Thus I hope you can take a look at
the proposed solution and decide for yourself if you see technical merit
in it. For some insight on how detection can be performed in a manner
that is deemed safe, I am also pasting the the 'Detection Primer'
section from the UBRX readme at the end of this e-mail.
Now, the other claim of the solution that is likely to raise an eyebrow,
is of course universality. As you can reasonably expect from knowledge
of the various quirks of the Super I/O & early console detection that
coreboot implements, there exist cases where a blanket generic detection
does not apply easily. Plus, mostly because this is a PoC, I added some
limitations on my own. So currently "universality" comes with the
* The motherboard must have a physical serial port, provided by a Super
I/O chip. Console over USB-RS232 adapters is not supported.
* Only 16650 compliant UARTs are supported.
* Only AMD and Intel x86 CPUs are supported. No VIA, no Transmeta.
* The CPU must support the MMX instruction set (Intel Pentium MMX or
later, AMD K6 or later) as we use MMX in lieu of stack.
* Only Super I/O chipsets conforming to the ISA PnP specifications, and
starting in PnP mode on reset are supported (except WMware compatible)
* Some non widespread PnP Super I/O chips with complex config mode
(eg. IT8671) have voluntarily been dropped.
* Powering up of Super I/O Logical Devices is not currently conducted.
We currently assert that UART LDs are powered up by default.
* With regards to Super I/O chips that require extra configuration from
the Southbridge for LPC bus access, only Intel ICH# (any version that
requires it) and AMD SB6x0-SB9x0 are supported.
Even with these limitations (most of which could be addressed), I have
reason to think that the vast majority of post 2000 PC systems should
find their Super I/O and UART properly detected, hence the claim.
The big unknown at the moment has to do with nVidia chipsets, since
non-NDA datasheets are unavailable for those. The other unknown is
whether the current AMD implementation actually works, as I don't have
an AMD system to test against. I tested UBRX on 2 Intel platforms (that
coreboot does not support), and found that everything ran as expected:
one was with a PIII system sporting a 440BX chipset and a W83977TF and
the other was a dual core ICH8 with a W83627DHG.
Therefore, I would greatly appreciate if people interested could have a
look, possibly test the current PoC, and give their thoughts. The
current code and downloads for UBRX can be obtained from visiting:
If you want to have a look at the main source, you can also do so at:
It is pure x86 assembly, but please see point #3 at the end of this
e-mail with regards to that.
If you have a GNU compiler that can produce x86 code (either on Linux or
Windows - 32 or 64 bit doesn't matter), you should easily be able to
produce a BIOS ROM you can flash. See the README for instructions.
You can also try with a VMware image, if you don't want to run on actual
hardware first: just copy the (default) 512 KB bios.rom generated to
your VMware install and add a 'bios440.filename = "bios.rom"' line to
Once you have an UBRX BIOS running, just set up a NULL-modem cable
connection (if using VMware on Windows, you can use com0com to setup a
virtual one), set your terminal to 115200 8N1, no hardware handshake,
and boot the first machine while maintain the space key pressed in the
console. If the detection process worked, you will enter the
'panic-room' console, which currently is limited to just an 'ubrx>'
prompt and a serial repeater.
Right now, I am especially interested in tests being conducted on AMD
hardware to confirm that the AMD LCP/SouthBridge init works. Again, you
should be able to test UBRX even if your platform is not supported by
coreboot, provided of course that you can reflash your BIOS through
external means afterwards (SPI, parallel programmer, etc.).
Also, while I have reasons to believe that, as far as providing a
console is concerned, doing so in a generic/universal fashion on x86
shouldn't be a problem, one of the questions I have is whether the same
can apply for CAR init. I'm new to coreboot and a lot of the romstage.c
sources I see seem to perform their own Cache As RAM init. On the other
hand  seems to indicate that CAR init does not necessarily need to be
Do you see a CAR init as a feature that can be achieved in a generic
panic-room (even if it may require provision of a few platform/CPU
specific parameters through the serial console)? Or are you aware of
major issues that would prevent doing so. I'd say that once we have CAR
as well as Y-modem transfer of code to CAR, for execution, the game is
pretty much won as far as a panic-room implementation is concerned.
Thus, if we can a implement both a generic console detection as well as
a generic CAR, we're done.
Finally, I'm just going to point out a few items that may be seen as as
valid reasons to dismiss UBRX upfront, whereas I don't believe these
should really matter:
1. I am aware that there exists a GSoC project for the panic-room 
but I think this does not touch on the provision of a serial console
(yet?). Even then, separate efforts can of course always be merged,
which is also why I am producing a PoC rather than a full
implementation, and stopping there for the time being.
2. The current license for UBRX is GPLv3 or later (my preference). If
you really believe that this will be an issue, I am open to discussion.
3. The source is pure x86 assembly (what's more using Intel syntax
rather than the GNU default AT&T), and I have to agree that this will be
harder to maintain than say a C source that could be compiled with
ROM_CC. On the other hand, the code is intended to be generic, so it
does not require duplication/changes for each motherboard and, more
importantly, I believe anything that is meant to be part of a
semi-permanent bootblock must focus on optimization and size, even if it
means a drawback in maintainability, hence the choice of assembly. The
current detection process takes less than 2K, which could be optimized
further, and leaves enough room for CAR, Y-modem and console
functionality in an 8K bootblock. I am doubtful that ROM_CC could
include everything we need in 8K.
Comments? Questions? Shoot away...
The paragraphs below highlight the generic Super I/O and 16550 UART
detection process as performed by UBRX. We believe that this process is
safe to be executed at every boot, irrespective of the hardware and
without side effects.
The 2 main components UBRX needs to detect are:
1. a potential PnP Super I/O candidate.
2. a potential 16650 UART Logical Device (LD) on the Super I/O chip.
As we start with absolutely no knowledge of the hardware, and must avoid
writing data at random, since doing so can damage the hardware, our
detection process has been designed with safety in mind from the ground
up, by ensuring that write operations were limited to the bare minimum,
and only executed after we had some assurance that the destination for
the write would match the expectation. Below is a detailed description
of how we ensure that our generic detection
process is as innocuous to the hardware as possible.
1. The Super I/O chip is accessed through the LPC bus, which is not
always accessible after reset, so we may have to enable LPC/SuperIO
Currently we only support Intel ICH# (all versions) and AMD SB6x0-9x0.
The detection and initialisation of the chipset for LPC access is safe,
since it is PCI based, and the PCI VID:PID of the South Bridge can be
read beforehand to unconditionally identify a supported chip before we
proceed with LPC initiation.
You will notice that we use a blanket LPC initialization, as we don't
distinguish between versions of the SouthBridge (eg: ICH6 is initialized
the same as ICH9), but this is the result of a *thorough* review of all
the Intel ICH# and AMD SBxx0 datasheets, to confirm that LPC init could
indeed be factorized. Even for the chips that don't require LPC
initialization (such as Intel ICH5 or earlier) and for which we do send
the LPC initialization command, we have confirmed from the datasheet
that we can simply let the PCI transaction fail as no register conflict
in the destination config space.
As such our LPC bus access initialization is deemed safe.
2. With the LPC bus accessible, we must probe a few common Super I/O ports.
Currently, these are 0x2E, 0x4E, 0x370, 0x3f0, as well as their +1 data
port. The last two I/O ports are commonly assigned to Tape and FDC so we
expect any chip there to withstand unintended writes (plus these can be
disabled through the bios.S build options). But even then, the extra
checks we apply to the 0x2E and 0x4E ports ensure safe access. With
regards to 0x2E and 0x4E, these are more problematic as a non PnP Super
I/Os are expected to reside there on older machines, and unchecked write
access (such as trying to configure PnP access on a non PnP aware chip)
could very well have unintended consequences. To alleviate this problem we:
a) always keep a copy of the original value at base and base+1
b) perform PnP enter conf (write to base only) and attempt to read
the Super I/O ID (at base +1). If the id is either 0x00 of 0xff, we
consider that the address is not one of a PnP Super I/O chip and restore
the base data => only the base register will have been accessed, then
c) attempt to write 8 LDN values, read them back and check that at
least 2 of them stick, indicating that the potential PnP Super I/O chip
has at least 2 LDs. If this isn't the case, we also restore the content
from base+1 and declare the PnP access to have failed. At most, since we
are only writing LDNs, this modifies the 3 lowest bits of base +1.
Considering that both superiotool and sensors-detect have let user
perform similar Super I/O probing (without the extra restore step), and
we are not aware of problems, as well as the fact that any recent PC
from our targeted audience would have a Super I/O running in PnP mode at
either 0x2e or 0x4e, we consider this approach safe to be executed at
3. Even with a possible PnP Super I/O chip accessible (and with the
current PoC assertion that the UART LD we want to access is powered up
by default on reset), we do not have any knowledge of the LDN of the
potential UART. With other LDNs being set up for GPIO or hardware
monitoring or control, trying to access each LDN as an UART, without
exerting any form of caution, is not a viable option. To alleviate this
issue, we perform an extensive yet non intrusive detection of a 16550
UART LD by first making sure, through read-only accesses, that the
registers match the reset value of a 16550 compliant unit. Then, we try
to flip the furthest 'safe' bit in the I/O range (register 7, bit 6,
with backup), to eliminate any LD that has less than 7 registers. Then
we check a significant unflippable bit from the 16550 register range
(which we also restore in case of failure), and finish our testing with
a complete UART loopback test. In all, we perform no less than 16 tests
to confirm that an LD is indeed a 16550 UART, with more than 30 bits
being tested in read-only mode, before we even start trying to flip a
single bit. As such, we seem this form of detection both safe and
At the moment, we test up to 32 LDNs per potential PnP Super I/O for
UART access. The 16550 tests are heavily documented in bios.S/check_16550.
Only once we have successfully identified a 16650 UART do we attempt to
fully configure it and read the console request key. If multiple UARTs
have been identified, these will be checked in sequence, meaning that
any serial port available on the motherboard can be used for console access.
More information about the coreboot