[coreboot] [RFC] Universal panic-room serial console, for x86 BIOS bootblock

Pete Batard pete at akeo.ie
Mon Jul 11 19:02:03 CEST 2011


Hello all,

Having recently followed some of the old discussions regarding a 
coreboot panic-room (eg. [1], [2]), 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 
sensors-detect).

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 
development.

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 
following restrictions:

* 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:
http://code.google.com/p/akeo/

If you want to have a look at the main source, you can also do so at: 
http://code.google.com/p/akeo/source/browse/ubrx/bios.S
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 
your .vmx

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 [3] seems to indicate that CAR init does not necessarily need to be 
mainboard specific.
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 [4] 
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...

Regards,

/Pete

[1] http://thread.gmane.org/gmane.linux.bios/25740/focus=26022
[2] 
http://www.coreboot.org/pipermail/coreboot/2010-February/thread.html#55950
[3] http://www.coreboot.org/data/yhlu/cache_as_ram_lb_09142006.pdf
[4] 
http://blogs.coreboot.org/blog/2011/05/09/gsoc-project-coreboot-panic-room-diagnostics-also-remote-flashing/


----------------------------------------------------------------------
Detection primer:

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 
access first.
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 
restored.
    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 
every boot.

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 
conclusive.
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 mailing list