9eSec

9elements Cyber Security

  • coreboot and LinuxBoot leadership team
  • systemboot maintainer together with Andrea B.
  • Strong experience in IT-Security since 10+ years
  • Founder of the Open Source Firmware Conference
  • coreboot developer
  • Strong experience in Firmware development since 10+ years
  • Working on Firmware QA.
  • HW Reverse Engineering
  • coreboot developer
  • Working on testing with FWTS
  • Experienced with embedded solutions

Our main business

  • Creating security solutions for our customers, especially based on Open Source firmware

 

  • We are normally upstream our work back into the Open Source projects

 

  • Our core company is a web development agency and sometimes we borrow their power in different situations

 

  • We are running the Open Source Firmware Conference 2018
    • www.osfc.io
  • We are currently building the first public QA system for the Open Source firmware like coreboot

 

  • We are pushing the Open Source firmware development as far as possible. 

Workshop 1

Getting started with the firmware development

In this workshop we will talk about BIOS firmware

The firmware lives on this chip

Can be used for stuff like this

Or more important to bootstrap your hardware and load the bootloader / OS :)

Contents

  • Overview
    • History
    • Architecture
    • Payloads
  • Usage
    • Toolchain
    • Hands-On: Build your own Toolchain
    • Menuconfig
    • Hands-On: Build coreboot for QEMU
    • Hands-On: Hello World
  • Internals
    • Code structure​
    • SMBIOS
    • ACPI
    • SMM
    • FMAP
    • CBMEM
    • Device Tree
    • Init system
    • Hardware Init
    • Hands-On: Add your own SMBIOS strings

Overview

Two guys one goal

"Let's fix the firmware development"

Stefan Reinauer

Ron Minnich

It all began...

Developed in 1999 at clustering research work in the Cluster Reseach Lab at the Advanced Computing Laboratory at Los Alamos National Laboratory (LANL).

 

The original BIOS did not boot, but as there was no VGA port on the cluster nodes, nobody knows why.

 

After hours of looking for the bug, soldering a VGA connector to the board and...

History

Keyboard error or no keyboard present

Press F1 to Resume

History

  1. Basic hardware init
  2. DRAM init
  3. Load x86 GNU/Linux kernel from flash as firmware
  4. Boot it

LinuxBIOS

History

  1. First chromebooks shipped with " Insyde H2C UEFI"
  2. Renamed from LinuxBIOS to coreboot
  3. coreboot was used first in 2012 on the chromebooks
  4. Open Source
  5. CPU/RAM/SB code was available
  6. Multiple boards were ported (Lenovo X220)

coreboot

What is coreboot?

  • It's an Open Source and reproducible firmware
  • Does only minimal hardware initialization
  • Drops afterwards to a payload for OS handoff
  • Written in 3% Assembly, 90% C and 7% ADA
  • Similar to GNU/Linux:
    • Make and Kconfig based build system
    • Same coding style
    • Open Source GPLv2/MIT
  • Multiple Architectures
    • x86 (Intel, AMD, VIA)
    • ARMv6, ARMv7, ARMv8
    • MIPS
    • RISC-V
    • openPOWER
  • Supports verified boot with failure safety and fallback mechanisms
  • Makes use of a custom toolchain

High-level Architecture

Where to get it?

www.coreboot.org

How to contribute

review.coreboot.org

Where is the documentation?  

doc.coreboot.org

Which CI do you use?

qa.coreboot.org

Live Demo

What is coreboot not?

  • It's not a bootloader
  • There are no filesystem drivers
  • No disk drivers
  • No USB drivers
  • No network support
  • No input device support

What is coreboot not?

Keyboard error or no keyboard present

Press F1 to Resume

What is coreboot not?

  • It's not a bootloader
  • No filesystem drivers
  • No disk drivers
  • No USB drivers
  • No input support
  • No graphical output support

What is coreboot not?

What is coreboot not?

  • It's not a bootloader
  • No filesystem drivers
  • No disk drivers
  • No USB drivers
  • No input support
  • No graphical output support
  • Not a reference implementation
  • Not a Basic Input Output System
  • Not a UEFI implementation

Architecture

Stages

  • Each stage is one file in CBFS

  • Each stage has a custom build target

  • Each file in CBFS has a custom compression

  • Allows any combination of compression

  • Supports loading arbitrary files from CBFS

  • Supported compressions:

    • LZ4

    • LZMA1

ROMCC

  • Developed in 2002

  • Very basic C compiler in 50k lines of code in a single file.

  • Generated code works without HEAP or STACK !

  • Inlines everything

  • Unrolls loops

  • No global heap usage

  • Emulates stack by CPU registers

  • Copy pastes code if OOM

  • Only required for x86 bootblock

  • Used on non-CAR platforms

Compiles the bootblock

Bootblock

  • CPU Reset vector
  • Partly written in assembly but gives you a C environment
  • On x86:
    • No cache, no DRAM, 16-bit real mode
    • Microcode updates
  • Set up Cache-As-RAM
  • Set up heap / stack for C environment
  • Includes a SPI driver (ARM only)
  • Uncompressed
  • Includes a LZ4 decompressor

Prepares everything for stages written in C

Romstage

  • Minimal device init
    • GPIO init
    • UART init
    • PCI / IO BAR
    • Timer init
  • Read SPD over I2C
  • DDR DRAM training (~5 sec per DIMM)
  • Store DRAM training results in MRC cache
  • Usually, LZ4 compressed in flash
  • Includes a LZMA decompressor

Set up DRAM

Postcar stage

  • Late Cache-As-RAM shutdown
  • Only used on Intel devices.
  • Console Init

Ramstage

  • Memory handling: allocate, use and forget
  • PCI device enumeration/resource allocation
  • Device init
  • Graphics init
  • TPM init
  • CPU init
  • SMM setup
  • ACPI table generation
  • SMBIOS table generation
  • Device Tree patching
  • Platform lockdown
  • The biggest stage in coreboot
  • Usually, LZMA compressed

Set up what payload needs

System Managment Mode

  • x86 only
  • Runs in Ring -1
  • Can't be disabled
  • Can do anything at any time
    • No real-time operation possible
    • Push CPU register to memory -> 768+ clock cycles
    • Always starts in real mode
    • Set up protected mode
    • Handle interrupt
    • Pop CPU state from memory to registers...
  • CPU doesn't know about (only by comparing timers...)
  • Coreboot provides a minimal SMM stub
  • Use ACPI if you can
  • ARM has ARM Trusted Firmware

System Managment Mode: As coreboot stage

  • Installed by firmware
  • Entered on SMI (System Management Interrupt)
  • Lives in protected memory SMRAM (Read protected in Ring 0)
  • SMI generating events
    • USB event
    • TCO
    • Watchdog
    • Periodic
    • Keyboard ports
    • RTC
    • Write to IO port ranges
    • Thermal event
    • Event on GPE pin
    • ...

Payloads

  • The "concept" of executing a lower privileged blob for later OS handoff
  • Minimal Trusted Computing Base is important
  • Depends on architecture
  • Depends on the available flash size
  • Independent development
  • Some know coreboot installed tables
  • The list of payloads is big

 

coreboot

payload

bootloader

OS

Sometimes this is the same!

Payload

  • x86 legacy
  • 16-bit Software Interrupt Services
  • Searches for MBR on disk
  • Has USB and disk driver
  • Legacy VGA Option ROM for native coreboot framebuffer
  • Maintained by SUSE/Redhat/QEMU developers
  • Default on QEMU
  • CSM in TianoCore
  • Includes coreboot drivers
  • TPM 1.2 and 2.0 with TCG interface support

SeaBIOS

www.seabios.org

Payload

  • Open Source UEFI implementation
  • 64bit UEFI interface
  • Has thousands of drivers
  • Up to 8MB size
  • Written in C
  • C++ like object management
  • Everything can be hooked
  • Offers UEFI SecureBoot capabilities
  • coreboot payload pkg and GOP driver for native console and framebuffer
  • Can be used with OVMF pkg in VirtualBox and QEMU

TianoCore

www.tianocore.org

Payload

  • x86
    • needs a trampoline
    • bzImage only
    • Optional initramfs in the filesystem
  • aarch64
    • needs FIT support
    • uImage only
    • Optional initramfs in uImage
    • Needs device tree in uImage
  • Has native support for coreboot framebuffer
  • coreboot VPD
  • coreboot CBMEM console

Linux kernel

www.kernel.org

Payload

  • Boot anything from disk or USB
  • Embed the grub.cfg
  • Supports MBR and EFI boot
  • Has native support for coreboot framebuffer
  • Supports multiple targets like "coreboot"

GRUB

www.gnu.org/software/grub/

Payload

  • Cross-platform Linux-As-Firmware
  • Linux with initramfs written in Go
  • coreutils tools written in Go
  • Rescue shell in firmware
  • Boot anything with no cost:
    • Linux filesystem drivers
    • Linux disk drivers
    • Linux network drivers
    • Linux disk encryption
    • Linux HID drivers
  • Bootloader implementation is called "systemboot"

LinuxBoot

www.linuxboot.org

Payload

  • Simple Executable Loader Format
  • Binary compiled in flat RAM mode
  • Can be anything, but you must ...
    • Set up MMU yourself
    • Enable the cache
    • Enable floating point support
    • Include own drivers
  • Libpayload implements basic support and can be used to create your own SELF payload
  • One of the most famous payloads is depthcharge by Google

SELF

www.coreboot.org/SELF

Usage

Toolchain

  • Patched GCC
  • Allows timeless a.k.a. reproducible builds
  • "No" toolchain bugs due to custom GCC config
  • One toolchain for each ARCH
  • -Werror enabled
  • Some payloads are compiled using the coreboot toolchain, some are not...
  • util/abuild script builds multiple boards with different toolchains
  • ADA support was added for libgfxinit and needs GNAT installed on host OS

Hands-On: Build your Toolchain

Hands-On: Build your Toolchain

  1. GNU/Linux or BSD (might have bugs)
  2. Internet Access
  3. Sufficient disk space for a complete GCC toolchain

What you need:

Steps:

  1. Install packages
  2. Clone coreboot repo
  3. Download & Build the toolchain
  4. Get a coffee, that will take a while...

20min

Hands-On: Build your Toolchain

Install the following packages (Debian naming conventions):

apt install git make build-essential gnat flex bison libncurses5-dev \ 
wget zlib1g-dev acpica-tools patch pciutils-dev ccache qemu

Clone coreboot repository and submodules:

git clone --recurse-submodules https://review.coreboot.org/coreboot.git
cd coreboot/
git submodule update --init --checkout 

Download and build the toolchain:

make crossgcc-i386 CPUS=2
make iasl

Hands-On: Build your Toolchain

Verify that the toolchain has been build:

$ ls util/crossgcc/xgcc/bin

Menuconfig

  • Same mechanism as in GNU/Linux
  • Kconfig
    • Defines dependencies
    • User-specific configuration
    • Lots of defaults
  • Makefile
  • Makefile.inc
    • Depends in Kconfig choices
    • Allows to skip building files

Menuconfig

$ make menuconfig

Menuconfig

Menuconfig

Hands-On: Build your first coreboot.rom

Hands-On: Build your first coreboot.rom

  1. Cloned coreboot repo
  2. Coreboot toolchain for the aimed architecture
  3. BLOBs
    1. 3rdparty/blobs
    2. 3rdparty/fsp (WIP)
    3. Dump from vendor image

What you need:

Steps:

  1. Configure coreboot
    1. Select path to BLOBs
    2. Enable optional features
    3. Save
  2. Build

20min

Hands-On: Build your first coreboot.rom

Select the payload:

Emulation / Qemu Q35

You need the following BLOBs:

(None)

Select the mainboard:

SeaBIOS

Include generated Option ROM (x)

Hands-On: Run your first coreboot.rom

Run it in qemu:

$ qemu-system-x86_64 -m 2048 -bios build/coreboot.rom -M q35

Or with KVM enabled:

$ qemu-system-x86_64 -enable-kvm -m 2048 -bios build/coreboot.rom -M q35

Add -nographic to the command line arguments giving you coreboot log output on the comand line.

Congratulation! coreboot runs now as QEMU firmware

Hands-On:

Hello World

Hands-On: Hello World

  • Add a printk in qemu_nb_init
  • Can be found in src/mainboard/<vendor>/<board>/mainboard.c
  • Save
  • Compile
  • Run in QEMU with -stdio serial
static void qemu_nb_init(struct device *dev)
{

    ...
    
    printk(BIOS_DEBUG, "Hello World\n");

}

Task:

10min

Hands-On: Hello World

Break / Lunch

Internals

Code structure

src/mainboard/

src/soc/

src/drivers/

src/lib/

src/include/

src/arch/

src/cpu/

src/northbridge/

src/southbridge/

src/vendorcode/

util/

build/

 

mainboard specific files

SoC specific files

platform independent (PCI) drivers

general helper functions CBFS, libc, printk, ...

includes of src/lib

architecture specific code (x86, arm, riscv, mips, ...)

CPU specific code

NB specific code (Open Source)

SB specific code (Open Source)

3rd Party code dump

Utilities useful for coreboot development

Object files and final image land here

src/mainboard/

  • 90% of new board ports are done here
  • 10% are:
    • EC
    • SuperIO
    • PCI drivers
  • Every board directory contains
    • board specific code
    • devicetree.cb
    • Kconfig
    • Makefile.inc
    • addtional board specific files
      • VBT.data
      • devicetree.dts
      • cmos.layout
      • dsdt.asl

Hardware Init

  • SoC / CPU / Architecture support
    • Done by firmware developers
      • Intel
      • Google
      • Facebook / 9e
  • Mainboard / EC / SuperIO support
    • Done by hardware vendor
    • Community by reverse engineering
  • DRAM init
    • Cavium
      • Open Source
    • Intel / AMD / Qualcomm
      • Secret
      • Reverse engineered on DDR3 platforms
    • Google used MRC to get rid of BLOBs

Levels of complexity

Architecture support

Difficulty

SoC support

Mainboard support

Payload support

Bootblock support

MMU support

easy

difficult

FMAP

  • The coreboot partition table format
  • Flashmap was invented for better partitioning on Intel flash instead of IFD
  • In conjunction used with the coreboot filesystem
  • The definition is done in a ASCII text file and later compiled to a binary format
  • Unique keywords are defined
  • Badly documented which is not good
  • FMAP must be written by hand at the moment

FMAP

  •  FLASH 8M {
            SI_ALL 2M {
                    # Firmware Descriptor section of the Intel Firmware Descriptor
                    # image.
                    SI_DESC 4K
                    # Intel Management Engine section of the Intel Firmware
                    # Descriptor image.
                    SI_ME
            }
            SI_BIOS 6M {
                    COREBOOT(CBFS)@0x200000​ 0x600000
            }
     }

CBFS - coreboot file system

  • Simple filesystem inside a flash partition
  • Derived of a key/value store
  • Attributes:
    • Name (Key)
    • Compression
    • Size
    • Type
  • No directories
  • Read/Writeable from within coreboot
  • util/cbfstool for binary data handling

CBFS - coreboot file system

$ ./util/cbfstool/cbfstool build/coreboot.rom print
FMAP REGION: COREBOOT
Name                           Offset     Type           Size   Comp
cbfs master header             0x0        cbfs header        32 none
fallback/romstage              0x80       stage           79620 none
cpu_microcode_blob.bin         0x13800    microcode       25600 none
fallback/ramstage              0x19c80    stage           85153 none
config                         0x2e980    raw               268 none
revision                       0x2eb00    raw               581 none

Init System

  • Ramstage only
  • Single thread
  • Consists of multiple stages
  • Each stage calls hooks
  • Hooks are determined at build time
  • Stages are immutable

Init System

states

Init System

states

BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_ENTRY, init_cpus, NULL);
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, post_cpus_init, NULL);
  • Place BOOT_STATE_INIT_ENTRY in your source file
  • Build system will place reference in section .bs_init
  • lib/hardwaremain.c iterates over .bs_init it at runtime
  • Allows to write modular drivers

Init System

PCI init system

  • Well tested on x86 and ARM64
  • BS_DEV_ENUMERATE scans PCI buses and PCI bridge defined in coreboot's devicetree
  • BS_DEV_RESOURCES assign PCI BARs
  • BS_DEV_ENABLE Device specific enable methods
  • BS_DEV_INIT Run VGA Option ROMs, driver specific implementations
  • Custom PCI drivers possible:

 

static const struct pci_driver r8168_driver __pci_driver = {
    .ops    = &r8168_ops,
    .vendor = 0x10ec,
    .device = 0x8168,
};

Device Tree

  • Located under src/mainboard/<vendor>/<board>/ devicetree.cb
  • Board specific configuration
  • Aims to reduce code duplication
  • Immutable at build time
  • Simple text file
  • One device tree for each board variant
  • Everything that is static
    • PCI devices (enable, disable)
    • chip drivers
    • "unprobeable" devices
    • SuperIO registers
    • TPM
    • GPIOs
    • configuration values

Device Tree

  • Integrated into the init system
  • Each chip's driver is run
  • Converted to static.c by util/sconfig
  • Compiled on build
  • Not the ARM device tree you know!
chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 on end # PCI bridge
    end
  end
end

Device Tree

example

Device Tree

chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 on end # PCI bridge
    end
  end
end

#include "soc/cavium/cn81xx/chip.h"
#include "soc/cavium/common/pci/chip.h"

example

chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 on end # PCI bridge
    end
  end
end
DEVTREE_CONST struct soc_cavium_cn81xx_config soc_cavium_cn81xx_info_1 = {};

 

Device Tree

example

chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 on end # PCI bridge
    end
  end
end
DEVTREE_CONST struct soc_cavium_common_pci_config soc_cavium_common_pci_info_1 = {
        .secure = 0,
};

Device Tree

DEVTREE_CONST struct soc_cavium_cn81xx_config soc_cavium_cn81xx_info_1 = {};

example

chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 on # PCI bridge
    end
  end
end
static DEVTREE_CONST struct device _dev3 = {
        .bus = &dev_root_links[0],
        .path = {.type=DEVICE_PATH_DOMAIN,{.domain={ .domain = 0x0 }}},
        .enabled = 1,
        .on_mainboard = 1,
        .link_list = &_dev3_links[0],
        .chip_info = &soc_cavium_cn81xx_info_1,
        .next=&_dev5
};

Device Tree

example

chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 on # PCI bridge
    end
  end
end

Device Tree

static DEVTREE_CONST struct device _dev5 = {
        .bus = &_dev3_links[0],
        .path = {.type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x1,0)}}},
        .enabled = 1,
        .on_mainboard = 1,
        .link_list = &_dev5_links[0],
        .sibling = &_dev84,
        .chip_info = &soc_cavium_common_pci_info_1,
        .next=&_dev84
};

example

chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 off # PCI bridge
    end
  end
end

Device Tree

static DEVTREE_CONST struct device _dev5 = {
        .bus = &_dev3_links[0],
        .path = {.type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x1,0)}}},
        .enabled = 0,
        .on_mainboard = 1,
        .link_list = &_dev5_links[0],
        .sibling = &_dev84,
        .chip_info = &soc_cavium_common_pci_info_1,
        .next=&_dev84
};

example

chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 off # PCI bridge
    end
  end
end
static DEVTREE_CONST struct device _dev2 = {
        .bus = &dev_root_links[0],
        .path = {.type=DEVICE_PATH_CPU_CLUSTER,{.cpu_cluster={ .cluster = 0x0 }}},
        .enabled = 1,
        .on_mainboard = 1,
        .link_list = NULL,
        .sibling = &_dev3,
        .chip_info = &soc_cavium_cn81xx_info_1,
        .next=&_dev3
};

Device Tree

example

#ifndef __SOC_CAVIUM_COMMON_PCI_CHIP_H
#define __SOC_CAVIUM_COMMON_PCI_CHIP_H

struct soc_cavium_common_pci_config {
    u8 secure;
};

#endif /* __SOC_CAVIUM_COMMON_PCI_CHIP_H */

src/soc/cavium/common/pci/chip.h

chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 on # PCI bridge
    end
  end
end

Accessing the device tree

#include "soc/cavium/common/pci/chip.h"

void func() {
  const struct device *dev;
  const struct soc_cavium_common_pci_config *cfg = NULL;

  dev = dev_find_slot(0, PCI_DEVFN(1, 0));
  if (dev)
    cfg = dev->chip_info;
}

Accessing the device tree

chip soc/cavium/cn81xx
  device cpu_cluster 0 on end
  device domain 0 on
    chip soc/cavium/common/pci
      register "secure" = "0"
      device pci 01.0 on # PCI bridge
    end
  end
end

CBMEM

  • Similar to UEFI's "Runtime" memory
  • A memory store where data can reside during stage transitions down to the OS
  • Persistent memory across ACPI S3 resume
  • Accessible from SMM and OS
  • Memory region marked as "reserved"
  • Each segment is identified by 32bit integer
  • Migrated from romstage to ramstage
  • Not available in bootblock
  • At the end of coreboot CBMEM is partly converted to the coreboot tables.

CBMEM

src/include/cbmem.h:

void *cbmem_add(u32 id, u64 size);

void *cbmem_find(u32 id);

...

coreboot tables

  • 32bit data structures
  • Tables which are visible from the OS
  • Used in kernel drivers for:
    • log output
    • VPD entries
    • framebuffer console
    • CBMEM region access
  • Populated by CBMEM contents
  • ACPI and SMBIOS

coreboot tables

ACPI

  • The Advanced Configuration and Power Interface

  • uefi.org/sites/default/files/resources/ACPI_6_2.pdf

  • Placed in reserved memory by firmware

  • Consists of tables

    • Describes the hardware

    • Register locations

    • DSDT / SSDT is an AML to be run by ACPI aware OS

  • Always visible from OS
  • Without ACPI the OS won't boot!
  • Contains bugs, too...
  • Legacy OS (like DOS) doesn't know about it!

ACPI

  • AML
    • Defines Scopes, Names and Methods, ...
    • Has a byte code and textual representation
    • Lossless conversion
    • Interpreter throws exception on malformed bytecode
  • Windows
    • BSOD on "bad" ACPI code
    • Follows an own unknown spec
  • Apple
    • Needs methods outside of ACPI spec
  • Spec isn't very precise
    • Trail and error
    • Every OS interpreter works different...
  • Firmware vendors decide to "improve" it

ACPI vs SMM

Legacy power and fan control

ACPI power and fan control

OS

SMM

Hardware

OS

ACPI

Hardware

Under firmware control, OS unaware if it

Provided by firmware, run by OS

Ring -1

Ring 0

Ring 0

Ring 0

?

ACPI vs SMM

Legacy power and fan control

ACPI power and fan control

OS

SMM

Hardware

OS

ACPI

Hardware

Under firmware control, OS unaware if it

Obfuscated hardware access

Ring -1

Ring 0

Ring 0

Ring 0

?

what other firmware vendors do...

SMM

Ring -1

SMI TRAP

?

ACPI

  • At build time:
    • DSDT is generated using iasl
    • src/mainboard/$(CONFIG_MAINBOARD_DIR)/dsdt.asl
    • includes other *.asl
  • At compile time:
    • SSDT is generated using acpigen
  • SMM and ACPI share data using GNVS
    • GNVS is a memory segment in CBMEM
  • Mechanism to enter SMM from ACPI
    • SMI TRAP
    • Southbridge specific

ACPI

What does it looks like ?

DefinitionBlock(
    "dsdt.aml",
    "DSDT",
    0x02,        // DSDT revision: ACPI v2.0
    "COREv4",    // OEM id
    "COREBOOT",    // OEM table id
    0x20110725    // OEM revision
)
{
    #include <southbridge/intel/bd82x6x/acpi/platform.asl>
    #include "acpi/platform.asl"
    #include <southbridge/intel/bd82x6x/acpi/globalnvs.asl>
    #include <cpu/intel/model_206ax/acpi/cpu.asl>
    Scope (\_SB) {
        Device (PCI0) {
            #include <northbridge/intel/sandybridge/acpi/sandybridge.asl>
            #include <southbridge/intel/bd82x6x/acpi/pch.asl>
        }
    }
}

ACPI

Sharing data between ACPI and SMM / firmware:

typedef struct global_nvs_t {
    /* Miscellaneous */
    uint8_t        pcnt; /* 0x00 - Processor Count */
    uint8_t        ppcm; /* 0x01 - Max PPC State */
    uint8_t        lids; /* 0x02 - LID State */
    uint8_t        pwrs; /* 0x03 - AC Power State */
    uint8_t        dpte; /* 0x04 - Enable DPTF */

...

Field (GNVS, ByteAcc, NoLock, Preserve) {
        /* Miscellaneous */
        Offset (0x00),
        PCNT, 8, /* 0x00 - Processor Count *
        PPCM, 8, /* 0x01 - Max PPC State */
        LIDS, 8, /* 0x02 - LID State */
        PWRS, 8, /* 0x03 - AC Power State */
        DPTE, 8, /* 0x04 - Enable DPTF */

...

AML

C

GNVS

Sharing data between ACPI and SMM / firmware:

External (NVSA)

OperationRegion (GNVS, SystemMemory, NVSA, 0x1000)

gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
if (gnvs) {
        acpi_create_gnvs(gnvs);

        /* Add it to DSDT.  */
        acpigen_write_scope("\\");
        acpigen_write_name_dword("NVSA", (u32)gnvs);
        acpigen_pop_len();
}

C

AML

SSDT

  • Implemented on x86 only
  • generates ACPI bytecode in ramstage
  • No build time validation possible
  • Needs to be tested on real hardware / QEMU
  • Only a single SSDT is supported

SSDT

acpigen_write_scope("PCI0.DEV0");
acpigen_write_method("_ROM", 2);

struct opregion opreg = OPREGION("ROMS",
          SYSTEMMEMORY, (uintptr_t)0xf0000, 0x10000);
acpigen_write_opregion(&opreg);

struct fieldlist l[] = { FIELDLIST_OFFSET(0),
          FIELDLIST_NAMESTR("RBF0", 8 * 0x10000), };
acpigen_write_field(opreg.name, l, 2, FIELD_ANYACC |
                    FIELD_NOLOCK | FIELD_PRESERVE);

acpigen_write_store();
acpigen_emit_byte(ARG0_OP);
acpigen_emit_byte(LOCAL0_OP);

acpigen_pop_len(); /* pop method */
acpigen_pop_len(); /* pop scope */
Scope("PCI0.DEV0") {
  Method (_ROM, 2, NotSerialized) {
    OperationRegion("ROMS", SYSTEMMEMORY, 0xf0000, 0x10000)

    Field (ROMS, AnyAcc, NoLock, Preserve) {
      Offset (0),
      RBF0,   0x80000
    }

    Store (Arg0, Local0)
  } 
}

 

SMBIOS

  • SMBIOS are tables stored in DRAM
  • Static data
  • Describes the mainboard, components and enclosure
  • Can be device specific

SMBIOS

  • SMBIOS provides basic board specific information
  • Dynamic generation at runtime
  • Provides enclosure type
  • Memory DIMMs populated
  • CPU and cache information
  • OEM specific data
  • Some drivers depend on special strings...
$ dmidecode
SMBIOS 3.0.0 present.
Handle 0x000B, DMI type 0, 24 bytes
BIOS Information
    Vendor: LENOVO
    Release Date: 03/07/2017
    Runtime Size: 128 kB
    ROM Size: 16 MB
    Characteristics:
        PCI is supported
        UEFI is supported
    BIOS Revision: 1.10
    Firmware Revision: 1.1

SMBIOS

  • SMBIOS provides basic board specific information
  • Dynamic generation at runtime
  • Provides enclosure type
  • Memory DIMMs populated
  • CPU and cache information
  • OEM specific data
  • Some drivers depend on special strings

Wait what ?

SMBIOS

???

    /*
     * Intel wifi driver expects this string to be in the table 0x85
     * with PCI IDs enumerated below.
     */
    t->str = smbios_add_string(t->eos, "KHOIHGIUCCHHII");

Hands-On:

SMBIOS tables

Hands-On: SMBIOS tables

  1. QEMU
  2. Linux Live System (Ubuntu)
  3. dmidecode

What you need:

Steps:

  1. Add SMBIOS strings
  2. Build coreboot.rom
  3. Download a Linux Live system
  4. Run it in QEMU with coreboot enabled
  5. Dump the SMBIOS tables

30min

Hands-On: SMBIOS tables

  1. Modify mainboard.c
  2. Build coreboot.rom
  3. Get a Linux live system
  4. Start in QEMU using:

Task:

$ qemu-system-x86_64 -m 4096 -enable-kvm
-bios build/coreboot.rom -M q35 -cdrom live.iso -boot d

5. Dump SMBIOS with dmidecode

Hands-On: SMBIOS tables

Hint:

static struct device_operations nb_operations = {
#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLES)
        .get_smbios_strings = qemu_smbios_strings,
#endif
       
  1. Place it in mainboard.c

It's not working :(

What happened?

  • If you work on firmware used in virtualized environments like QEMU or VirtualBox, ACPI doesn't come from the firmware
  • QEMU will deliver ACPI and SMBIOS tables itself and coreboot populates it
  • coreboot just allows writing SMBIOS table 0 which is the firmware table.

Hands On: SMBIOS tables v2

Task:

  1. Place it in mainboard.c
  2. Overwrite the weak function smbios_mainboard_bios_version
  3. Add the string "coreboot class v1" as return value
  4. Compile coreboot
  5. Run QEMU
  6. Dump the SMBIOS tables

Now it works!

Test time ;)

10min

An introduction into coreboot

By 9elements Agency GmbH

An introduction into coreboot

  • 1,290