Chromium OS Board Porting Guide

Introduction

You've got a wonderful new platform that you'd like to run Chromium OS on, but have no idea how to get there from here?  Fret not my fellow traveler, for this document shall be your guide.  We promise it'll be a wondrous and enlightening journey.

An overlay is the set of configuration files that define how the build system will build a Chromium OS disk image.  Configurations will be different depending on the board and architecture type, and what files a developer wants installed on a given disk image.  Every command in the build process takes a required `--board` parameter, which developers should pass the overlay name to.

On your first run through this document for creating your first platform, you can skip the sections labeled (advanced).  This will let you focus on the minimum bits to get running, and then you can revisit once you're more comfortable with things.

Private Boards (advanced)

This guide covers doing a public build (one that will be released to the world). There is a separate guide (meant as an add-on to this one) for creating a private board.  Setting up a private board is useful for when you want to keep your project details a secret before launch, or if your board contains proprietary drivers or firmware that can't be released publicly.

Naming

Possible board names follow a simple specification:

  • must have no upper case letters
    • normalization to lower case keeps things simple
  • must start with a letter [a-z]
  • may contain as many letters [a-z] or numbers [0-9] as you like
  • should contain no more than one dash
    • technically there is no limit, but the more dashes you add, the uglier it gets
  • must not contain any other character
    • e.g. characters such as, but not limited to, + or % or @ or _ or / or . or : or ... are invalid
  • must avoid words that are used with generic (board independent) configurations
    • e.g. "release" or "canary" or "firmware" or "factory" or "pfq" or "paladin" or "incremental" or "asan" or ...
    • see cbuildbot_config.py in the chromite repo for more examples (look at the CONFIG constants at the top)
      • you can also run `cbuildbot -l -a` to get a feel for the "group" names
  • should not be generic terms
    • e.g. "board" or "boat" or "car" or "airplane" or "computer" or ...
  • should be clever
  • must not be phonetically similar to an existing board
    • it is not worth the hassle when talking or writing to try and figure out what people mean
    • it might make it harder for non-native speakers to differentiate
    • e.g. with "red" and "read", or "pour" and "pored", or "accept" and "except", or "flaunt" and "flout"
  • should be pronounceable in conversation
    • no one likes to talk about the XK123A-Z03 board -- that's just boring
  • must not pick a name that Google intends to use with a Chrome OS board
    • don't worry, it's unlikely

Settled on a name?  Hopefully it's nifty.

Board Variants (advanced)

Often times you will have a base/reference board on which you will build other boards/devices, and you want to customize each in ways that are incompatible with the others.  The board variant framework is designed to handle this setup.  Note: at the moment, the variant framework is only one level deep.  So you cannot do a variant of a variant.  A need for this has not been found, so we haven't worried about it.

When it comes to naming, you will take the existing reference board name and add on the new project's name separated by an underscore.  Both projects must follow the naming convention laid out in the above section.

As an example, Google has a reference board named daisy.  Using that base, other board variations have been created such as the snow board.  Thus the final board name is daisy_snow.

Bare Framework

Let's start by laying the ground work for the board.  We won't worry about the fine details (like custom set of packages or flags or ...) at this point.  We just want a board that the build system will recognize and be able to produce a generic set of artifacts.  Once we have that, we'll start customizing things.

Architecture

Be aware that we assume your board falls under one of the main (currently supported) architectures:

  • amd64 (x86_64) -- 64-bit Intel/AMD processors
  • arm -- 32-bit ARM processors
  • x86 (i386/i486/i586/i686) -- 32-bit Intel/AMD/etc... processors
If you're using a different architecture, please see the Chromium OS Architecture Porting Guide first.

src/overlays/overlay-$BOARD/

This is the main location for per-board customization.  Let's start off with a simple overlay:

overlay-$BOARD/
|-- make.conf                # Global board customizations (USE/CFLAGS/etc...)
|-- metadata/
|   `-- layout.conf          # Gentoo repo syntatic sugar
|-- profiles/
|   `-- base/
|       `-- parent           # Parent profile for this board (common arch/OS settings)
`-- toolchain.conf           # Toolchains needed to compile this board

Most of these files are one or two lines.  Let's go through them one at a time.

make.conf

This file can be used to customize global settings for your board.  In this first go, we'll leave it empty.  It's ok ... we'll come back.

$ touch make.conf

toolchain.conf

For standard architectures, you only need one line here.  Pick the one that matches the architecture for your board.

 architecture  tuple
 amd64 (64-bit)  x86_64-cros-linux-gnu
 arm (armv7)  armv7a-cros-linux-gnueabi
 x86 (32-bit)  i686-pc-linux-gnu

Example file for an x86_64 board:

$ cat toolchain.conf
x86_64-cros-linux-gnu

Note that if you do need more than one toolchain, you can list as many as you like (one per line). But the first entry must be the default one for your board.

metadata/layout.conf

Don't worry about the content of this file.  Simply copy & paste what you see below, and then update the repo-name field to match your $BOARD.

$ cat metadata/layout.conf
masters = portage-stable chromiumos
profile-formats = portage-2
repo-name = lumpy
thin-manifests = true
use-manifests = true

profiles/base/ (advanced)

This is the "base" profile (aka the default) for your board.  It allows you to customize a wide array of settings.  You really only need to create one file (the parent file; see the next section).

Most commonly this directory is used to control USE and KEYWORDS on a per-package basis (via the package.use and package.keywords files respectively), or profile-specific tweaks in make.defaults that you don't want to keep in make.conf (since it's specific to a profile). See the portage(5) man page for all the gory details.

profiles/base/parent

This will vary based on your architecture.

architecture parent profile
 amd64 chromiumos:default/linux/amd64/10.0/chromeos
 arm chromiumos:default/linux/arm/10.0/chromeos
 x86 chromiumos:default/linux/x86/10.0/chromeos

Example file for an x86_64 board:

$ cat profiles/base/parent
chromiumos:default/linux/amd64/10.0/chromeos

profiles/<sub-profile>/ (advanced)

Sometimes you will want to take an existing board and try out some tweaks on it.  Perhaps you want to use a different kernel, or change one or two USE flags, or use a different compiler settings (like more debugging or technology like ASAN).  You could create a board variant, but that is more for different boards, and is much more heavy handed.

To create a sub-profile, simply make a new directory under the profiles/ and name it whatever you like.  Many Google based systems have one called kernel-next and we use this to easily test the new development kernel tree.

You should then create a parent file in there like so:

$ cat profiles/kernel-next/parent
../base

This says the sub-profile will start off using the existing base profile (so you don't have to duplicate all the settings you've already put into that directory).  From here, you can add any files like you would any other profile directory.

Now to select this new profile, you use the --profile option when running setup_board.  You can either blow away the existing build dir (if one exists), or tell the system to simply rewrite the configs to point to the new profile.  You'll have to make the decision using your knowledge of the profile (whether it means a lot of changes or just swapping of one or two packages).

# Recreate from scratch.
$ ./setup_board --profile=kernel-next --board=lumpy --force

# Or just rewrite the configs to use the new profile.
$ ./setup_board --profile=kernel-next --board=lumpy --regen_configs

src/third_party/chromiumos-overlay/eclass/cros-board.eclass

Since we need some central location to store all the possible board names, we have the cros-board.eclass.  It should be pretty self-explanatory.

We actively welcome commits to this file.  Simply upload a CL to gerrit that adds your fun board and we'll gladly take a look for you.

Board Variant Framework (advanced)

Rather than create an entire hardware board from scratch every time a new project comes along, companies will often take existing projects and make tweaks to fit the new one.  It's a common industry practice which allows for rapid expansion into more areas.  Since these boards are pretty close to each other, it'd be annoying to have to duplicate the entire board settings just to make a handful of changes.  The variant framework was designed to address this.

Basically, refer to the sections above for creating a new board overlay.  However, this time name it slightly different.  If the base board is named daisy and the variant is named snow, we would create the directory overlay-variant-daisy-snow.  Yes, the separator is now a dash rather than an underscore.

You will still need to create at least these files (see the previous section for what to put into them):

  • make.conf
    • Note: You only need to put stuff specific to your variant; the parent board will be loaded before the variant is read
  • metadata/layout.conf
    • Usually you can just copy the version verbatim from the parent board and update the repo-name field
The base board overlay will be set as the parent of this variant automatically.  So settings/packages that exist in there will be the starting point for this variant.

Testing Initial Build

Since your board should be all set up and ready to go, let's test it.  All operations will be done inside the chroot (so run `cros_sdk` to get in first).

$ ./setup_board --board=$BOARD
<random build output>
$ ./build_packages --board=$BOARD
<lots of build output>

Those should both have worked and produced a generic build for that architecture (using your $BOARD name).  Let's set about customizing the build now.

Note: as you make changes below to your overlay, re-running build_packages again will rebuild packages that have changed based on your USE flags.  But other changes (like compiler settings or kernel configs) will not trigger automatic rebuilds.  Only new package builds will use the new settings.  Once you're happy with all your settings though, you can re-run setup_board with the --force flag.  Then running build_packages will build everything from scratch with the latest settings.

make.conf: Global Build Settings

This file contains a few key variables you'll be interested in.  Since each of these can be a large topic all by themselves, this is just an overview.

You can set variables like you would in a shell script (VAR="value"), as well as expand them (FOO="${VAR} foo").  But do not try to use shell commands like if [...]; then or sub-shells like $(...) or `...` as things will fail.

Setting Meaning
 CHROMEOS_KERNEL_SPLITCONFIG  The kernel defconfig to start with
 CHROMEOS_KERNEL_ARCH  The kernel $ARCH to use (normally you do not need to set this)
 USE  Global control of features (e.g. alsa or ldap or opengl or sse or ...)
 INPUT_DEVICES  List of drivers used for input (e.g. keyboard or mouse or evdev or ...)
 VIDEO_CARDS  List of drivers used for video output (e.g. intel or armsoc or nouveau or ...)
 ARM_FPU  The FPU technology to use (ARM only)
 MARCH_TUNE  The common set of compiler flags used to optimize for your processor (e.g. -mtune/-march)
 CFLAGS  Compiler flags used to optimize when building C code
 CXXFLAGS  Compiler flags used to optimize when building C++ code
 LDFLAGS  Linker flags used to optimize when linking objects (normally you do not need to set this)

Linux Kernel Settings

CHROMEOS_KERNEL_SPLITCONFIG

The kernel is automatically compiled & installed by the build system.  In order to configure it, you have to start with a defconfig file as the base (it can later be refined by various USE flags).  This value allows you to control exactly that.

You can specify the relative path (to the root of the kernel tree) to your defconfig.  This is useful if you are using a custom kernel tree rather than the official Chromium OS Linux kernel tree.

$ grep CHROMEOS_KERNEL_CONFIG make.conf
CHROMEOS_KERNEL_CONFIG="arch/arm/configs/bcmrpi_defconfig"

Or you can specify a Chromium OS config base.  We have one for each major platform/SoC that ships in an official Chrome OS device, and we have architecture generic configs.  You can find the full list by browsing the chromeos/config/ directory in the kernel tree.  Unlike a defconfig, splitconfigs are much smaller fragments which start with a common base and then enable/disable a few options relative to that.

$ grep CHROMEOS_KERNEL_SPLITCONFIG make.conf
CHROMEOS_KERNEL_SPLITCONFIG="chromeos-pinetrail-i386"

CHROMEOS_KERNEL_ARCH

The kernel build system normally detects what architecture you're using based on your overall profile.  For example, if you have an amd64 board overlay setup, the build knows it should use ARCH=x86_64.

However, there arises edge cases where you want to run a kernel architecture that is different from the userland.  For example, say you wanted to run a 64-bit x86_64 kernel, but you wanted to use a 32-bit i386 userland.  If your profile is normally setup for an x86 system, you can set this variable to x86_64 to get a 64-bit kernel.

$ grep CHROMEOS_KERNEL_ARCH make.conf
CHROMEOS_KERNEL_ARCH="x86_64"

Global USE Feature Selection

One of the strengths of the Gentoo distribution is that you can easily control general feature availability in your builds by changing your USE settings.  For example, if you don't want audio, you can disable alsa & oss.  Or if you don't want LDAP, you can disable that.  All of the ebuild files (the package scripts used to build/install code) have logic to check each setting that is optional so you don't have to.

The downside, as you can imagine, is that with thousands and thousands of packages, the number of possible USE flags is vast.  There are also some optional settings which only make sense with one or two packages (global vs local USE flags).  So weeding through which USE flags exactly matter can be a bit of a monstrous task.

Userland Device Driver Selection

An extension to the USE flag system are so called USE-expanded variables.  This helps reduce the global USE flag noise a bit by having specially named variables with specific meaning.  In this case, we'll discuss device inputs (keyboards/mouse/etc...) and video outputs.

The exact driver availability (and naming convention) depends on what graphic system you intend to use.  The X project tends to have the widest selection but is a larger overall install size, while DirectFB tends to have smaller selection of drivers but be much smaller.  We'll focus on X here as that is the main system that Chromium supports.

INPUT_DEVICES

TBD

VIDEO_DEVICES

TBD

Compiler Settings

Everyone likes optimizations.  Faster is better, right?  Here's the nuts and bolts of it.

While picking out flags to use, keep in mind that Chromium OS uses GCC for its compiler suite.  It also uses the gold linker.  So see the respective documentation.

ARM_FPU

This is for ARM targets only.  Any value that GCC accepts to the -mfpu= flag is valid.  This will be used by various packages (mostly Chromium) to select FPU-specific optimizations.

Typical values are neon and vfpv3-d16.  If you have an ARMv7, pick between these two values.  If you don't have an ARMv7, then you should already know the answer to this question :).

MARCH_TUNE

You should put compiler optimizations that target your specific cpu into this variable.  Commonly, this means:

  • -march=<arch> -- see the GCC manual for complete lists of possible values here
    • This selects the minimum required processor/architecture that the code will run on
    • armv7-a is common for ARMv7 parts
    • core2 is common for Intel Core2 parts
    • corei7 is common for Intel Core i7 parts
  • -mtune=<arch> -- see the GCC manual for complete lists of possible values here
    • This selects the processor that the code will be optimized best for without requiring it
    • If you don't specify this, then the -march setting will be used
    • cortex-a8 or cortex-a9 or cortex-a15 are common for ARM parts
  • -mfpu=${ARM_FPU} (ARM only)
    • By setting the ARM_FPU variable, you can expand it here.
  • -mfloat-abi=hard (ARM only)
    • Keep in mind that Chromium OS assumes you are using the hard float ABI.  While it is certainly possible to get things working with a soft float ABI, you shouldn't waste your time.  Join us in the future and migrate away from the old & slow soft float ABI (this also includes the softfp ABI -- it's just as bad).
  • -mmmx / -msse / -msse2 / etc...
    • There are a variety of machine-specific optimization flags that start with -m that you might want to try out

CFLAGS

If you have flags that you want to use only when compiling C code, use this variable.  Otherwise, things will default to -O2 -g -pipe.

$ grep CFLAGS make.conf
CFLAGS="${CFLAGS} ${MARCH_TUNE}"

CXXFLAGS

If you have flags that you want to use only when compiling C++ code, use this variable.  Otherwise, things will default to -O2 -g -pipe.

$ grep CXXFLAGS make.conf
CXXFLAGS="${CXXFLAGS} ${MARCH_TUNE}"

LDFLAGS

If you have flags that you want to send directly to the linker for all links, use this variable.

These should take the form as given to the compiler driver.  i.e. use -Wl,-z,relro rather than -z relro.

You can find common settings in the GNU Linker manual.

Buildbot Configs

Presumably you'd like to be able to easily (and cleanly) produce artifacts for your board. In our chromite repo, we have a tool called cbuildbot that takes care of all that for us. Normally it's run by buildbot on a waterfall to produce all the goodness, but there's no requirement that buildbot be the tool you use. You can even run it locally.

chromite/buildbot/cbuildbot_config.py

At any rate, you'll need to update this master file to add your new board configs. There are a few classes of configs to be familiar with:

  • $BOARD-paladin: used by the Chromium OS CQ -- not needed if you aren't an official Chrome OS device
  • $BOARD-full: a public build of the build
  • $BOARD-release: a private build of the board
  • $BOARD-firmware: build just the firmware (bootloader/etc...) for the board
  • $BOARD-factory: build the factory install shim -- used to create an image for programming devices in the factory/RMA/etc...

The file should be largely self-documenting.

Google Storage Integration

Sometimes you'll want to host large files or prebuilt binary packages for your repo, but you don't want to give out access to everyone in the world. You can great some boto config files, and the build scripts will automatically use them when they're found.

googlestorage_account.boto

Create this file in the root of the overlay. This file stores the access credential (in cleartext) for the role account.

googlestorage_acl.*

These are the ACL files used by gsutil to apply access for people. Used whenever you want to upload files and grant access to people who have the boto file.

The XML variant is deprecated as it only works with gsutil-3.x. The TXT variant is currently what is used everywhere and is documented in the gsutil FAQ. The JSON variant is not yet used as it only works with gsutil-4.x.

Comments