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