Welcome to the dark corner of BIOS reverse engineering, code injection and various modification techniques only deemed by those immensely curious about BIOS

Monday, October 17, 2011

PCI "Generic" Option ROM Debugging with SeaBIOS, Coreboot and IDA Pro

In this post, I assume the PCI Option ROM is named TEST.ROM. Which is an option ROM not tied to particular hardware.  The debugging environment consists of two machines, either virtual or physical. In my particular setup, I used two physical machines. The debugging “host” runs Windows 7 64 with IDA Pro as a remote debugger. The “target (gdb server)” runs Linux—with Qemu as the “real” target of the debugging in the Linux machine. The sole reason to use Linux in the “target” is to enable rebuilding Coreboot and SeaBIOS which acts as the “container” of the target PCI option ROM. The steps to prepare the debugging environment as follows:
  1. Configure and build SeaBIOS.
    1. Run make menuconfig in SeaBIOS root source directory. If you’re downloading SeaBIOS as Coreboot payload, it’s located at <coreboot_source_path>/payloads/external/SeaBIOS/seabios.
    2. Enable CONFIG_OPTIONROMS, CONFIG_PMM, CONFIG_COREBOOT_FLASH when you run make menuconfig.
    3. Configure debug level to 8 (CONFIG_DEBUG_LEVEL)
    4. Save your changes and quit from the configuration menu (make menuconfig).
    5. Build SeaBIOS by invoking make.
  2. Configure and build Coreboot.
    1. Run make menuconfig in Coreboot root source directory.
    2. Disable both CONFIG_VGA_ROM_RUN and CONFIG_PCI_ROM_RUN as either of these options will confuse the virtual machine (Qemu) and possibly modify the contents of the PCI option ROM at runtime (debugging). Producing unwanted side effects.
    3. Configure SeaBIOS binary not as ordinary payload, but as an ELF payload. Configure CONFIG_PAYLOAD_FILE to point to the SeaBIOS ELF file, i.e. <seabios_source_path>/out/bios.bin.elf.
    4. Save your changes and quit from configuration menu (make menuconfig).
    5. Build Coreboot by invoking make.
  3. Insert TEST.ROM as CBFS component to Coreboot ROM file. The following are the steps to insert the PCI option ROM (the steps could be scripted):
    1. Combine TEST.ROM as CBFS component to Coreboot ROM with this command (invoked from Coreboot source code root directory):
                  ./build/cbfstool build/coreboot.rom add <path_to_TEST_ROM> genroms/test.rom raw
    2. Check whether everything is OK with this command:
                 ./build/cbfstool build/coreboot.rom print
  4. Run Qemu utilizing the newly built Coreboot ROM file as its BIOS (configured to stop and wait for the GDB connection).
    qemu –m 128 –bios <path_to_coreboot_rom> -hda linux.img –net none –nographic –s –S 
    The –net none option disables gPXE option ROM from Qemu to load. The gPXE option ROM complicates the analysis a bit. Therefore, it’s better to get rid of it.
    NOTE: If Qemu gPXE option ROM is enabled (default), the TEST.ROM option ROM would always be loaded at C980h segment. If Qemu gPXE option ROM is disabled, the TEST.ROM option ROM would always be loaded at C900h segment.
  5. Run IDA Pro and connect via GDB remote debugging.
    1. Configure IDA Pro debugger to run in x86 16-bit mode.
    2. Attach to the qemu machine via Debugger|Attach|Remote GDB Debugger menu. Configure the IP address of your virtual or physical target machine there (which runs Qemu) and set the debugger specific option to run 16-bit code.
    3. When stopped at reset vector (FFFF:FFF0), create your required memory regions (Debugger|Debugger Options…|Set Specific Options|Memory Map)
    4. Configure breakpoints as needed.
    5. Run (press F9) and debug.
That's it. Now you can debug the "generic" option ROM to your hearts content :-)