Canonical Voices

Posts tagged with 'bios'

Colin Ian King

fwts 13.08.00 released.

Version 13.08.00 of the Firmware Test Suite has been released today.  This latest release includes the following new features:

* uefirtvariable - can now specify number of iterations for high duration soak testing,
* new --acpica option to turn enable core ACPICA functionality (such as ACPI slack mode and serialized AML execution),
* sync klog scan patters with Linux 3.10,
* klog test now parses firmware related kernel warning messages,
* JSON log output now supports "pretty" formatting,
* update to ACPICA version 20130725
* SMBIOS and dmi_decode tests merged into a new dmicheck tests,

..and also the usual bug fixes.  We have been using Coverity Scan and this has helped to improve the quality of the code in the recent releases.

For more details, please consult the release notes
 
The source tarball is available at:  http://fwts.ubuntu.com/release/fwts-V13.08.00.tar.gz and can be cloned from the repository: git://kernel.ubuntu.com/hwe/fwts.git

The fwts 13.08.00 .debs are available in the firmware testing PPA and will soon appear in Ubuntu Saucy 13.10.

Thanks to Alex Hung, Ivan Hu, Keng-Yu Lin and Zhang Rui for their contributions and also to Robert Moore for the on-going work on ACPICA.

Read more
Colin Ian King

fwts 13.07.00 released.

Version 13.07.00 of the Firmware Test Suite has been released today.  This latest release includes the following new features:

* A new uefivarinfo utility to show UEFI NVRAM variable usage
* Use the latest version of ACPICA (version 20130626)
* SMBIOS test now performs some more sanity checks
* kernel log test now scans for lpc_ich warnings
* Add the --acpica-debug option (for debugging purposes only)

..and also a bunch of bug fixes.

For more details, please consult the release notes
 
The source tarball is available at:  http://fwts.ubuntu.com/release/fwts-V13.07.00.tar.gz and can be cloned from the repository: git://kernel.ubuntu.com/hwe/fwts.git

The fwts 13.07.00 .debs are available in the firmware testing PPA and will soon appear in Ubuntu Saucy 13.10.

Read more
Colin Ian King

A new Ubuntu portal http://odm.ubuntu.com is a jump-start page containing links to pages and documents useful for Original Design Manufactures (ODMs), Original Equipment Manufacturers (OEMs) and Independent BIOS vendors.

Some of the highlights include:

  • A BIOS/UEFI requirements document that containing recommendations to ensure firmware is compatible with the Linux kernel.
  • Getting started links describing how to download, install, configure and debug Ubuntu.
  • Links to certified hardware, debugging tools, SystemTap guides, packaging guides, kernel building notes.
  • Debugging tips, covering: hotkeys, suspend/resume, sound, X and wireless and an A5 sized Ubuntu Debugging booklet.
  • Link to fwts-live, the Firmware Test Suite live image.
 ..so lots of useful technical resources to call upon.

Kudos to Chris Van Hoof for organizing this useful portal.

Read more
Colin Ian King

UEFI  Compatibility Support Module (CSM) provides compatibility support for traditional legacy BIOS.  This allows allows the booting an operating system that requires a traditional option ROM support, such as BIOS Int 10h video calls.

While looking at boot and runtime misbehaviour on UEFI systems I would like to know if CSM is enabled or not, but the question is how does one detect CSM support?   Well, making the assumption that CSM is generally enabled to support Int 10h video calls, we look for any video option ROMs and see if the real mode Int 10h vector is set to jump to a handler in one of the ROMs.  

Option ROMs are found in the region 0xc0000 to 0xe0000 and normally the video option ROM is found at 0xc0000.  Option ROMs are found on 512 byte boundaries with a header bytes containing 0x55, 0xaa and ROM length (divided by 512) so we just mmap in 0xc0000..xe0000 and then scan the memory for headers to locate option ROM images.  

My assumption for CSM being enabled is that Int 10h vectors into one of these option ROMs, and we can assume it is a video option ROM if it contains the string "VGA" somewhere in the ROM image.  Yes, it is a hack, but it seems to work on the range of UEFI enabled systems I've so far used.

For reference, I've put the code in my debug-code git repository and available for anyone to use.


Read more
Colin Ian King

Forcing a CMOS reset from userspace

Resetting CMOS memory on x86 platforms is normally achieved by either removing the CMOS battery or by setting a CMOS clear motherboard jumper in the appropriate position.  However, both these methods require access to the motherboard which is time consuming especially when dealing with a laptop or netbook.

An alternative method is to twiddle specific bits in the CMOS memory so that the checksum is no longer valid and on the next boot the BIOS detects this and this generally forces a complete CMOS reset.

I've read several ways to do this, however the CMOS memory layout varies from machine to machine so some suggested solutions may be unreliable across all platforms.  Apart from the Real Time Clock (which writing to won't affect a CMOS reset), the only CMOS addresses to be consistently used across most machines are 0x10 (Floppy Drive Type), 0x2e (CMOS checksum high byte) and 0x2f (CMOS checksum low byte).  With this in mind, it seems that the best way to force a CMOS reset is to corrupt the checksum bytes, so my suggested solution is to totally invert each bit of the checksum bytes.

To be able to read the contents of CMOS memory we need to write the address of the memory to port 0x70 then delay a small amount of time and then read the contents by reading port 0x71.    To write to CMOS memory we again write the address to port 0x70, delay a little, and then write the value to port 0x71.   A small delay of 1 microsecond (independent of CPU speed)  can be achieved by writing to port 0x80 (the Power-On-Self-Test (POST) code debug port).

 static inline uint8_t cmos_read(uint8_t addr)  
 {  
     outb(addr, 0x70);    /* specify address to read */  
     outb(0, 0x80);       /* tiny delay */  
     return inb(0x71);    /* read value */  
 }  
   
 static inline void cmos_write(uint8_t addr, uint8_t val)  
 {  
     outb(addr, 0x70);    /* specify address to write */  
     outb(0, 0x80);       /* tiny delay */  
     outb(val, 0x71);     /* write value */  
 }  

And hence inverting CMOS memory at a specified address is thus:

 static inline void cmos_invert(uint8_t addr)  
 {  
     cmos_write(addr, 255 ^ cmos_read(addr));  
 }  

To ensure we are the only process accessing the CMOS memory we should also turn off interrupts, so we use iopl(3) and asm("cli") to do this and then asm("sti") and iopl(0) to undo this.   We also need to use ioperm() to get access to ports 0x70, 0x71 and 0x80 for cmos_read() and cmos_write() to work and we need to run the program with root privileges.  The final program is as follows:

 #include <stdio.h>  
 #include <stdlib.h>  
 #include <stdint.h>  
 #include <unistd.h>  
 #include <sys/io.h>  
   
 #define CMOS_CHECKSUM_HI (0x2e)  
 #define CMOS_CHECKSUM_LO (0x2f)  
   
 static inline uint8_t cmos_read(uint8_t addr)  
 {  
     outb(addr, 0x70);    /* specify address to read */  
     outb(0, 0x80);       /* tiny delay */  
     return inb(0x71);    /* read value */  
 }  
   
 static inline void cmos_write(uint8_t addr, uint8_t val)  
 {  
     outb(addr, 0x70);    /* specify address to write */  
     outb(0, 0x80);       /* tiny delay */  
     outb(val, 0x71);     /* write value */  
 }  
   
 static inline void cmos_invert(uint8_t addr)  
 {  
     cmos_write(addr, 255 ^ cmos_read(addr));  
 }  
   
 int main(int argc, char **argv)  
 {  
     if (ioperm(0x70, 2, 1) < 0) {  
         fprintf(stderr, "ioperm failed on ports 0x70 and 0x71\n");  
         exit(1);  
     }  
     if (ioperm(0x80, 1, 1) < 0) {  
         fprintf(stderr, "ioperm failed on port 0x80\n");  
         exit(1);  
     }  
     if (iopl(3) < 0) {  
         fprintf(stderr, "iopl failed\n");  
         exit(1);  
     }  
   
     asm("cli");  
     /* Invert CMOS checksum, high and low bytes*/  
     cmos_invert(CMOS_CHECKSUM_HI);  
     cmos_invert(CMOS_CHECKSUM_LO);  
     asm("sti");  
   
     (void)iopl(0);  
     (void)ioperm(0x80, 1, 0);  
     (void)ioperm(0x70, 2, 0);  
   
     exit(0);  
 }  

You can find this source in by debug code git repo.

Before you run this program, make sure you know which key should be pressed to jump into the BIOS settings on reboot (such as F2, delete, backspace,ESC, etc.) as some machines may just display a warning message on reboot and need you to press this key to progress further.

So to reset, simple run the program with sudo and reboot.  Easy.  (Just don't complain to me if your machine isn't easily bootable after running this!)


Read more
Colin Ian King

I've now competed the documentation of the Firmware Test Suite and this include documenting each of the 50+ tests (which was a bit of a typing marathon).  Each test has a brief description of what the test covers, example output from the test, how to run the test (possibly with different options) and explanations of test failure messages.

For example of the per-test documentation, check out the the suspend/resume test page and the ACPI tables test page.

I hope this is useful!


Read more
Colin Ian King

The Firmware Test Suite (fwts) is still a relatively new tool and hence this cycle I've still been adding some features and fixing bugs.  I've been running fwts against large data sets to soak test the tool to catch a lot of stupid corner cases (e.g. broken ACPI tables). Also, I am focused on getting some better documentation written (this is still "work in progress").

New tests for the Oneiric 11.10 release are as follows:

mpcheck:
    Sanity check tables against the MultiProcessor Specification (MPS). For more information about MPS, see the wikipedia MPS page.

mpdump:
    Dump annotated MPS tables.

msr:
    Sanity check Model Specific Registers across all CPUs. Does some form of MSR default field sanity checking.

s3power:
    Very simple suspend (S3) power checks.  This puts the machine into suspend and attempts to measure the power consumed while suspended. Generally this test gives more accurate results the longer one suspends the machine.  Your mileage may vary on this test.

ebdadump:
     Hex dump of the Extended BIOS Data Area.

In addition to the above, the fwts "method" test is now expanded to evaluate and exercise over 90 ACPI objects and methods.

One can also join the fwts mailing list by going to the project page and subscribing.


Read more
Colin Ian King

How x86 computers boot up

Gustavo Duarte has written a concise and very readable article describing how computers boot up.  Well worth reading.


Read more
Colin Ian King

The Linux PCI core driver provides a useful (and probably overlooked) sysfs interface to read PCI ROM resources.  A PCI device that has a ROM resource will have a "rom" sysfs file associated with it, writing anything other than 0 to it will enable one to then read the ROM image from this file.

For example, on my laptop, to find PCI devices that have ROM images associated with them I used:

find /sys/devices -name "rom"
/sys/devices/pci0000:00/0000:00:02.0/rom

and this corresponds to my Integrated  Graphics Controller:

lspci | grep 02.0
00:02.0 VGA compatible controller: Intel Corporation Mobile GM965/GL960 Integrated Graphics Controller (primary) (rev 0c)

To dump the ROM I used:

echo 1 | sudo tee /sys/devices/pci0000\:00/0000\:00\:02.0/rom
sudo cat /sys/devices/pci0000\:00/0000\:00\:02.0/rom > vbios.rom

To disassemble this I used ndisasm:

sudo apt-get install nasm
ndisasm -k 0,3 vbios.rom | less

..and just use strings on the ROM image to dump out interesting text, e.g.

strings vbios.rom
000000000000
00IBM VGA Compatible BIOS.
PCIR
(00`
*@0p
H?@0b
..


..and then used a tool like bvi to edit the ROM.


Read more
Colin Ian King

Dumping the contents of the Embedded Controller (EC) can be useful when debugging some x86 BIOS/kernel related issues.  At a hardware level to get access to the EC memory one goes via the EC command/status and data port.   As a side note, one can determine these ports as follows:

cat /proc/ioports  | grep EC

The preferred way to access these is via the ACPI EC driver in drivers/acpi/ec.c which is used by the ACPI driver to handle read/write operations to the EC memory region.

In addition to this driver, there the ec_sys module that provides a useful debugfs interface to allow one to read + write to the EC memory.  Write support is enabled with the ec_sys module parameter 'write_support' but it is generally discouraged as one may be poking data into memory may break things in an unpredictable manner, hence by default write support is disabled.

So, to dump the contents of the first EC (assuming debugfs is mounted), do:

sudo modprobe ec_sys
sudo od -t x1 /sys/kernel/debug/ec/ec0/io

Simple!

As a bonus, the General Purpose Event bits are also readable from /sys/kernel/debug/ec/ec0/gpe.

Before I stumbled upon ec_sys.c I used a SystemTap script to execute ec_read() in ec.c to do the reading directly.  Yes it's ugly and stupid, but it does prove SystemTap is a very useful tool.


Read more
Colin Ian King

Making sense of PCIe ASPM

PCI Express based serial linked devices can be managed by Active State Power Management (ASPM) to extend battery life on mobile devices such as laptops and netbooks.  ASPM is a power management protocol that allows an operating system's power management to place the link physical layer into a low power mode and it has the ability to instruct other devices on the link to go into a lower power mode too.

The plus side is that we save power with ASPM, however, it will introduce some latency as the bus needs time to be woken up when in a low power state.
The PCIe specification (version 2.0) defines two power modes:

  • L0s, which set low power mode in in direction on the link (usually from the physical link layer controller downstream)
  • L1, which sets low power mode in both directions on the link, however there is greater wakeup latency.
The Linux ASPM driver implements the nitty-gritty details of ASPM - by default it reads the ASPM config from the PCI configuration space. The ASPM config is contained in one of the Capabilities List items, the head of this is pointed to by CapPntr (offset 0x34 in the Configuration Header).

However, the firmware (BIOS) may have misconfigured the PCI configuration space, and apparently this can cause issues, such as hangs if the link is put into low power and the device cannot handle this.   I managed to dig up some information concerning the ASPM implementation on Windows Vista and this states that the BIOS can indicate that ASPM should be disabled by setting the PCIe ASPM Controls bit in the IACP_BOOT_ARCH flag in the Fixed ACPI Description Table (FADT).
Poking around a bit deeper, it seems that this is a requirement in the ACPI specification to set this bit appropriately.   Version 4.0a of the ACPI specification, Table 5-11 Fixed ACPI Description Table Boot Architecture Flags states for following for bit 4 (PCIe ASPM Controls) of the BOOT_ARCH flag:

"If set, indicates to OSPM that it must not enable OSPM ASPM control on this platform."

Linux checks for this in acpi_pci_init() and will disable ASPM if the bit 4 is set.  But what happens if the BIOS is misconfigured, how can one disable ASPM?
Well, Linux does provide some ASPM driver kernel parameters to allow some level of tweakability.  The following kernel parameters can be used:

  • "pcie_aspm=off" - disables ASPM
  • "pcie_aspm=default" - use default firmware configuration as set in the PCI Express Capabalities list item with ID 0x10
  • "pcie_aspm=performance"  - disables ASPM and clock power management
  • "pcie_aspm=powersave" - highest power saving mode, enable ASPM and clock power management
"pcie_aspm=off" has seemed to help some users with some PCIe devices that case Linux hang at boot time.  I deeply suspect that the IACP_BOOT_ARCH flag may be telling Linux to do this but it's being ignored.

I measured "pcie_aspm=powersave" on one of my netbooks and I believe I get a small amount of power saving, powertop seemed to indicate about 0.2 Watts being saved, but this could be within the margin of error in my measurements.

Anyhow, if you want to tinker with more power savings, maybe overriding the firmware configured defaults with "pcie_aspm=powersave" may help. It's worth a try.
 
p { margin-bottom: 0.28cm; }


Read more
Colin Ian King

Firmware Test Suite for Ubuntu 11.04

The  Firmware Test Suite (fwts) is a tool I've been working on over the past few months that does automated testing of PC firmware.  The main aim is to check for errors in BIOS code and ACPI tables.  I have put most effort into ACPI testing as my analysis shows that it constitutes over 90% of firmware related errors reported against the kernel in LaunchPad.

Most of the key features for Ubuntu 11.04 are now in the Firmware Test Suite, so now seems an appropriate time to mention them.

Automated ACPI Method Testing.

The ACPI DSDT and SSDT tables contain ACPI Machine Language (AML) bytecode.  This code is executed by the Linux kernel by the ACPI driver and is an abstract interface between the operating system and the underlying machine hardware, such as the embedded controller, the closed proprietary BIOS and various hardware registers.   The AML can describe hardware layout and contains methods that operate in a manner that should conform to the ACPI specification.   For example, there are methods to handle power management,  thermal control, battery status and much more besides.   The main problem we face is when these implementations are buggy and may not conform to the specification.   The kernel can execute the AML code and so if the AML is broken you may get a machine that does not work correctly.

I've added a method test to fwts that will extract the AML byte code from the DSDT and then using the ACPICA execution engine run these in user space and check methods are returning the expected return types and in some cases (where appropriate) check expected return values.  Over 70 standard methods described in version 4.0a of the ACPI specification are sanity checked.  The code also checks mutex acquire/release counts to see if methods are incorrectly not releasing locks.

To run these test using 11.04 fwts, use:


sudo fwts method

..and the results are appended to the file results.log.  (One has to use sudo to be able to read the ACPI tables).

Another way to sanity check the AML code is to extract it, dis-assemble and then re-assemble it using the ACPICA iasl compiler.  A lot of AML is compiled using the Microsoft AML compiler and this appears to be less strict. Hence, recompiling with a more strict compiler can pick up errors.   The syntaxcheck test existed in fwts for Ubuntu 10.10, but I've re-worked this by integrating in the ACPICA core into the tool and then enhancing the error reporting.  For most error messages produced by the compiler fwts now also outputs 8 lines of disassembled code around the error (to provide context) and also outputs extra feedback advice.  This advice is based on looking at all the reasons why this error can be emitted by the compiler and explaining these with more context.

To run this test, use:

sudo fwts syntaxcheck

..again, output is appended to results.log

Since the ACPICA core is integrated in, we can also use this to easily dump out the disassembled AML byte code from all the ACPI tables.  To do so use:

sudo fwts --disassemble-aml

and the AML code for each table is dumped into files DSDT.dsl and SSDTn.dsl (where n is the Nth SSDT).  This is much easier than running acpixtract, acpidump and the iasl -d on the DSDT and SSDT tables.

The final ACPI table test added to fwts in Ubuntu 11.04 performs about 40 sanity checks on configuration data in common ACPI tables.  To run this test use:

sudo fwts acpitables
 
..and this checks various configurations, e.g. of HPET, SCI interrupt, GPE blocks, reset register + reset values, APIC flags, etc.

Although it's strictly not a test, fwts now includes a tool that will dump out the ACPI tables in an annotated form so that one can examine the configuration settings in a more human readable form than just looking at the raw data in a hex editor. To do use:

sudo fwts acpidump

UEFI

The Firmware Test Suite also needs to work on UEFI firmware based machines which are now becoming far more common.  I've re-worked some of the underlying code in fwts to work with UEFI and standard BIOS.  My next step is to extend fwts to add in more UEFI only tests, but this is still "work-in-progress".

Other goodness

As it is an evolving tool, fwts includes a lot more refinements (and bug fixes) compared the first cut that came out in Ubuntu 10.10.   The log format to be less verbose and there is the new "-" option that dumps the log straight to stdout rather than appending it to a log file.

To see all the tests built into fwts, you can use the "--show-tests-full" option, rather than the more terse option "--show-tests".  

Originally fwts ran silently and this caused some confusion as it was not obvious what was happening.  For Ubuntu 11.04  fwts now runs in verbose mode and reports a brief per test progress information.  The silent mode can be enabled using the "-q" or "--quiet" options.

One can also run the tool on dumped ACPI tables from other machines allowing to remotely diagnose bugs just from raw table data.  Dump the tables using:

sudo fwts --dump

..this produces a dump of kernel log, dmidecode, lspci and the ACPI tables. One can read in the ACPI tables into fwts and run appropriate ACPI specific tests on this data, e.g.

fwts --dumpfile=acpidump.log syntaxcheck method acpitables

There are many more refinements and minor new features.  I recommend reading the manual page to get more familiar with the tool.

To install fwts in Ubuntu 11.04 use:

sudo apt-get install fwts

Enjoy!

[ Update ]

I've written a fwts reference guide, available here: https://wiki.ubuntu.com/Kernel/Reference/fwts


Read more
Colin Ian King

Int 0x15 e820 and libx86

One of the more obscure libraries I've looked at recently is libx86 which provides some x86 real mode functionality to do tricks such as BIOS calls from user space. The library provides routines to do real mode malloc/free and also a structure to pass/return CPU register to/from an Interrupt call. One uses:

sudo apt-get install libx86-dev

..to install the libx86 devel library.

I experimented with libx86 by using the Int 0x15 AX=0xe820 call to query the system address map. One loads EAX with 0xe820, EBX initially with zero (for the first address map structure), ES:DI with a pointer a 20 byte real mode buffer, ECX with 20 (size of the buffer) and EDX with the signature 'SMAP'. If the carry is set or EBX is zero after the call, then either an error occurred or one has reached the end of the table. After the call, EBX contains a continuation value that is passed back in EBX on the next call. The 20 byte real mode buffer is populated as follows:

 uint32     BaseAddrLo   Lo 32 Bits of Base Address
 uint32     BaseAddrHi   Hi 32 Bits of Base Address
 uint32     LengthLo     Lo 32 Bits of Length in Bytes
 uint32     LengthHi     Hi 32 Bits of Length in Bytes
 uint32     Type         Address type 
 
My implementation to dump out the entire system address map can be found here. Compile and link with libx86 and then run the executable using sudo:

sudo ./e820
Base Address Length Type
0000000000000000 000000000009fc00 RAM
000000000009fc00 0000000000000400 Reserved
00000000000e0000 0000000000020000 Reserved
0000000000100000 000000003f6b0000 RAM
000000003f7b0000 000000000000e000 ACPI Reclaim
000000003f7be000 0000000000032000 ACPI NVS memory
000000003f7f0000 0000000000010000 Reserved
00000000fee00000 0000000000001000 Reserved
00000000fff00000 0000000000100000 Reserved

Anyhow, I hope this example shows how to do BIOS interrupts using libx86 from userspace in Linux.


Read more
Colin Ian King

Video Mode Interrogation via BIOS calls.

While investigating the video modes on my laptop to do some sanity checking I thought I'd have a go at using libx86 to allow me to call into the BIOS directly from userspace.  After short consultation with the trusty Ralph Brown Interrupt List, I hacked up some code to get the list of all the video modes and interrogate each one to get the resolution.

I was getting random crashes before I realised that clearing the LRMI_regs struct before populating it with the desired x86 register settings fixed the problem.

Anyhow, the code is available in my git repository here - and it requires one to install libx86-dev and run with root privileges.   I'm still amazed that the code can jump from userspace into the BIOS, gather data and return without totally messing up the system.

Interestingly, a lot of UEFI systems still provide a legacy mode BIOS, so this code still works on these newer systems.


Read more
Colin Ian King

Hacking a custom DSDT into a QEMU BIOS

Today I was trying to reproduce a bunch of weird ACPI errors when executing AML code from a DSDT extracted from a remote machine. For some reason the AML in the 2.6.32 kernel was causing a bunch of warnings, but not in 2.6.35 and I wanted to see when the fix landed. This was a dirty hack so that I could quickly do kernel bisects running the kernel inside QEMU.

Firstly, I got the DSDT from the remote machine and converted into it form that could be included into the seabios BIOS images. I used the following C source:


#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
int data;
int i = 0;

printf("unsigned char AmlCode[] = {");
for (i=0; (data = getchar()) != EOF; i++)
printf("%s%s0x%2.2x", i>0 ? "," : "",
(i & 7) ? "" : "\n\t", data);
printf("\n};\n");

exit(EXIT_SUCCESS);
}
And built it with:

gcc -Wall hexdump.c -o hexdump

Next I generated a C compilable hex dump of the DSDT.dat raw image:

./hexdump < DSDT.dat > acpi-dsdt.hex

Then I got the seabios sources:

git clone git://git.linuxtogo.org/home/kevin/seabios.git

and the copied the acpi-dsdt.hex to seabios/src

..and then cd into seabios and built using make. This creates bios.bin in the directory called out.

Then I copied the current QEMU bios, vgabios and seabios images to my working directory:

cp -R /usr/share/qemu /usr/share/vgabios /usr/share/seabios/ .

and then copied the compiled seabios image into the newly copied seabios directory:

cp seabios/out/bios.bin seabios

Finally, I ran QEMU using new BIOS image as follows:

qemu -L qemu ubuntu.img

Bit of a hack, but it helped when I did not have the hardware to hand.


Read more
Colin Ian King

Digging into the BIOS CMOS Memory

The BIOS settings of a PC are stored in non-volatile memory (sometimes known as NVRAM) to ensure they are saved when the machine is off. On a PC, this NVRAM is CMOS (Complimentary Metal Oxide Semiconductor) memory and is trickle charged by a small battery to ensure the data is preserved. CMOS memory requires very little power hence it can be kept non-volatile by a battery for several years.

One can access the CMOS memory via ports 0x70 and 0x71. One writes the address of the CMOS memory location you want to read to port 0x70 and then read the contents via a read of port 0x70. I implemented this as follows:


unsigned char cmos_read(int offset)
{
unsigned char value;

ioperm(0x70, 0x2, 1);
ioperm(0x80, 0x1, 1);

outb(offset, 0x70);
outb(0, 0x80); /* Small delay */
value = inb(0x71);

ioperm(0x80, 0x1, 0);
ioperm(0x70, 0x2, 0);

return value;
}
..I was not 100% sure of a small port delay was required between the write to port 0x70 and the read of data on port 0x71, but I added one in by writing to port 0x80 just in case. The ioperm() calls are required to get access to the I/O ports, and one needs to run this code with root privileges otherwise you will get a segmentation fault.

Then it is a case of reading 128 bytes or so of CMOS memory using this function. The next step is decoding this raw data. Web-pages such as http://www.bioscentral.com/misc/cmosmap.htm contain CMOS memory maps, but it does tend to vary from machine to machine. With data from several memory map descriptions that I found on the Web I have figured out some common across different BIOS implementations and written some code to annotate the contents of the CMOS memory. There are a bunch of fields that need a little more decoding, but that's work in progress...

My aim is to add this into the Firmware Test Suite for 11.04 as part of a diagnostic feature.


Read more
Colin Ian King

The FirmWare Test Suite (fwts) is a tool I've been working on to do automatic testing of a PC's firmware. There can be a lot of subtle or vexing Linux Kernel/firmware issues caused when firmware is buggy, so it's useful to have a tool that can automatically check for common BIOS and ACPI errors. Where possible the tool will give some form of advice on how to fix issues or workaround firmware issues.

It's packaged up and in Maverick universe, you can install it using:

sudo apt-get install fwts

To see the tests available in the tool use:

fwts --show-tests

There are over 30 tests and I hope to expand this every time I find new firmware issues which can be diagnosed automatically in a tool.

To run a test use, for example the ACPI AML syntax checking test use:

sudo fwts syntaxcheck

There are categories of tests, for example, by default fwts will run batch mode tests which run without the need of user intervention. Some tests, such as checking the laptop lid works or hotkeys requires user intervention - these are interactive tests and can be invoked using:

sudo fwts --interactive

By default the tool will append the test results into a log file called results.log. This logs the date/time the test was run, the name of the test and the test results and hopefully some useful advice if a test fails.

I suggest checking out the manual page to see some examples how to fully drive this tool.

Quite a lot of the tests have been picked up from the core of linuxfirmwarekit.org, but I've added a bunch more tests, and expanded the types of errors it checks for and the feedback advice it reports. I've targeted fwts to run with the Maverick 2.6.35 kernel but it should work fine on Lucid kernels too. I've written fwts with command line driven test framework to run the tests mainly to allow fwts to easily plug into more powerful test frameworks.

If you want to run the tool from a bootable USB flash key, then one can download a i386 or amd64 image and dd it to a USB flash key.

For example:

wget http://kernel.ubuntu.com/~kernel-ppa/testing/maverick-desktop-i386-fwts.img
sudo dd if=maverick-desktop-i386-fwts.img of=/dev/sdX

where /dev/sdX is the block device of your USB flash key

then boot off this USB flash key and let it run the tests. At the end it will automatically shutdown the PC and you can then remove the key. The key has a FAT formatted partition containing the results of the test in a directory named: fwts/ddmmyyyy/hhmm/results.log, where ddmmyyyy are the digits in the date and hhmm for the time the test was started.

The fwts PPA can be found in the Firmware Testing Team project and the source code is available in a git repository here.

I've also written a short OpenOffice presentation on the tool which also may prove instructive.


Read more
Colin Ian King

Looking at a PC's option ROMs

An Option ROM is firmware called by the BIOS, for example the Video BIOS or a SCSI controller card. The BIOS Boot Specification requires that option ROMs are aligned to 2K boundaries and must begin with bytes 0x55 0xaa. After Power On Self Test (POST) the BIOS scans for option ROMs and if it finds a correct header executes the initialisation code at byte offset 0x3.

The Option ROM header is as follows:

Byte 0: 0x55
Byte 1: 0xaa
Byte 2: size of ROM in 512 byte pages
Byte 3: Option ROM entry point

To dump out the option ROMs, use the ree utility:

sudo apt-get install ree

..and run as follows:

sudo ree

..this will dump out all the option ROMs in the form: hexaddress.rom where hexaddress is the memory segment where the ROM is located. e.g. for my Video BIOS ROM, I get the file c0000.rom.

To disassemble this use ndisasm:

sudo apt-get install nasm

ndisasm -k 0,3 c0000.rom | less

..or just use strings on the ROM image to get an idea what the Option ROM is, e.g.

strings c0000.rom
000000000000
00IBM VGA Compatible BIOS.
PCIR
(00`
*@0p
H?@0b
..

..in this case it is a VGA BIOS, and this makes sense as VGA BIOS ROMs normally start from segment c0000. On my Lenovo laptop I observe that the ROM contains the string "DECOMPILATION OR DISASSEMBLY PROHIBITED" which spoils our fun in finding out what the ROM is doing...

Anyhow, ree + ndisasm are useful tools for poking around your PCs option ROMs on Linux.


Read more
Colin Ian King

x86 BIOS calls used by grub and Linux

The other day I was checking up to see which BIOS calls are used by grub and Linux.  I naively believed grub used just a few to get some disk geometry information and to do some reads as well as a little bit of console/keyboard I/O.  In fact Grub uses quite a few BIOS calls, namely:

BIOS "int 0x13 Function 0x41, bx=0x55aa" to check if LBA mode is
supported
BIOS "int 0x13 Function 0x42" read sectors from disk into memory (LBA
mode)
BIOS "int 0x13 Function 0x08" determine HDD geometry
BIOS "int 0x13 Function 0x02" read sectors from disk into memory
(non-LBA mode)
BIOS "int 0x13 Function 0x00" reset floppy drive (if not booted from
HDD)
BIOS "int 0x13 Function 0x4B01" check bootable CD-ROM emulation
status
BIOS "int 0x13 Function 0x4800" get driver paramaters

BIOS "int 0x15 Function 0xe801" get memory size (Phoenix BIOS v4.0)
BIOS "int 0x15 Function 0xe820" get memory map
BIOS "int 0x15 Function 0xc0" get ROM configuration
BIOS "int 0x15 Function 0x2400" disable A20 gate

BIOS "int 0x10 Function 0x4f00" get SVGA information (VBE)
BIOS "int 0x10 Function 0x4f01" get SVGA mode
BIOS "int 0x10 Function 0x4f02" set SVGA mode

BIOS "int 0x10 Function 0x01" set cursor shape
BIOS "int 0x10 Function 0x02" set cursor position
BIOS "int 0x10 Function 0x03" get cursor position and size
BIOS "int 0x10 Function 0x09" write character and attribute at cursor
BIOS "int 0x10 Function 0x0e" write character in teletype mode

BIOS "int 0x16 Function 0x00" keyboard - get keystroke
BIOS "int 0x16 Function 0x01" keyboard - check for keystroke

BIOS "int 0x1a Function 0x02" get real-time clock

BIOS Advanced Power Management (APM) calls: Grub will ignore APM if it does not detect it - it's not manditory to have APM for grub to work. So these are non required.

APM "int 0x15 Function 0x5300" check for APM
APM "int 0x15 Function 0x5301" connection real-mode interface
APM "int 0x15 Function 0x5304" disconnect interface
APM "int 0x15 Function 0x5307" set power state
APM "int 0x15 Function 0x530E" driver version


As for the Linux kernel, it also uses quite a range of BIOS calls, for example figuring out specific system settings and doing console work.

Below is a list of calls that I could find in the x86 arch specific code, I'm not sure if it's the fully definitive list, but I believe I found the majority of the BIOS calls.

BIOS "int 0x10 Function 0x00" set video mode
BIOS "int 0x10 Function 0x02" set cursor position
BIOS "int 0x10 Function 0x03" get cursor position and size
BIOS "int 0x10 Function 0x0e" write character in teletype mode
BIOS "int 0x10 Function 0x0f" get current video mode
BIOS "int 0x10 Function 0x0100" set cursor scan lines
BIOS "int 0x10 Function 0x1111" set 9x14 font
BIOS "int 0x10 Function 0x1112" set 8x8 font
BIOS "int 0x10 Function 0x1200" bl=0x10, check EGA/VGA
BIOS "int 0x10 Function 0x1200" bl=0x20, video, alternative function
select
BIOS "int 0x10 Function 0x1201" bl=0x34, turn of cursor emulation
BIOS "int 0x10 Function 0x1a00" get display combination code
BIOS "int 0x10 Function 0x4f00" get SVGA information (VBE)
BIOS "int 0x10 Function 0x4f01" get SVGA mode
BIOS "int 0x10 Function 0x4f02" set SVGA mode
BIOS "int 0x10 Function 0x4f08" get/sec DAC palette control
BIOS "int 0x10 Function 0x4f0a" get protected mode interface
BIOS "int 0x10 Function 0x4f15" check DDC capabilities

BIOS "int 0x15 Function 0x2401" enable A20 gate
APM "int 0x15 Function 0x5300" check for APM
APM "int 0x15 Function 0x5303" connect interface
APM "int 0x15 Function 0x5304" disconnect interface
BIOS "int 0x15 Function 0xe980" get Intel speedset information
BIOS "int 0x15 Function 0xec00" set BIOS CPU mode
BIOS "int 0x15 Function 0xc0" query MCA
BIOS "int 0x15 Function 0xe801" get memory size (Phoenix BIOS v4.0)
BIOS "int 0x15 Function 0xe820" get memory map
BIOS "int 0x15 Function 0x88" get extended memory size

BIOS "int 0x16 Function 0x00" keyboard - get keystroke
BIOS "int 0x16 Function 0x01" keyboard - check for keystroke
BIOS "int 0x16 Function 0x0305" set keyboard rate

BIOS "int 0x1a Function 0x02" get real time clock
BIOS "int 0x1a Function 0x02" get real time clock

Needless to say, some of these are not used for example, the use of some depend on how the console is configured.

Anyhow, it's quite surprising how much we still rely on core BIOS functionality to get a system up and running.  Kudos to Ralph Brown's interrupt list to help me figure out the BIOS int and function code mappings.


Read more
Colin Ian King

The past few days I've been tinkering with the TianoCore EFI and trying to get Ubuntu Karmic to boot with the EFI enabled grub2. To make debugging easier, I did all this inside a virtualised QEMU environment. A lot of this earlier hackery was blogged about in a previous article.

In trying to get this to work I hit a couple of issues; figuring out workarounds took some thought and time. Some of it is still "work in progress", but at least now I know what needs to be fixed.

Below is a video (grabbed using the recordmydesktop tool) showing Ubuntu Karmic booting:





First you see the TianoCore EFI starting and then loading grub2 - this then loads a very slimmed down grub.cfg and eventually boots the system.

I hit several issues; firstly the kernel oops'd when trying to call virt_efi_get_next_variable() - for some reason calling this EFI runtime service support function in the EFI is causing the kernel to oops. Other EFI support functions seem to work correctly, so my current belief is that the bug is not in the kernel EFI driver, but this needs a little more poking around to verify this assumption.

Second issue is that loading some grub2 modules and using some fundamental grub2 commands such as 'set' cause the EFI get caught in a loop. It took me a while to corner this - eventually I cut down the default grub config file down to a really minimal version which could at least boot the kernel! Anyhow, this grub2 issue is first on my list of bugs to fix.

Debugging these issues is a little tricky, but using QEMU helps as I can dump out debug from grub2 over a pseudo serial port which I can capture and view in real-time. Secondly, debugging the kernel using a serial console in QEMU (using the console=ttyS0 boot option) allows me to capture all kernel boot messages (including the offending kernel oops).

I still need to look into ACPI support and how to get the video initialised to get more than bog-standard VGA resolution, but these are currently lower priorities.

Without QEMU and Tristan Gingold's port of the TianoCore EFI to QEMU, this work would have been much harder.


Read more