This page explains how to create a Debian/Ubuntu rootfs from scratch using debootstrap and QEMU.

This is not the recommended nor the easiest way to create a Debian/Ubuntu armel rootfs; see ARM/RootfsFromScratch for other ways.

Prerequisites

You will need:

TODO provide a PPA with backports.

Building the Root Filesystem

The initial image of the root filesystem can be done manually via "debootstrap", or more easily via the "mk-sbuild" wrapper.

mk-sbuild

Trivially easy:

   mk-sbuild --arch armel lucid

debootstrap

First stage debootstrap

debootstrap bootstraps a Debian/Ubuntu system in multiple steps which can be divided in two stages: the parts running code/tools from the build environment, and the parts running code/tools from the target environment.

For the first stage, run something like:

    sudo debootstrap \
        --arch=armel \
        --keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg \
        --verbose \
        --foreign \
        karmic \
        rootfs

The arguments tells debootstrap respectively to:

Things you might want to customize:

Check the debootstrap(8) manpage for details. TODO link to man page

Second stage debootstrap with QEMU

QEMU sports two types of emulation:

QEMU's syscall emulation is much faster than machine emulation, but both are relatively slow when compared to native programs for your computer. One major drawback of syscall emulation is that it that some syscalls are not emulated, so some programs might now work, also when building programs, these might configure themselve for the features of the kernel they run on instead of what the target architecture actually supports.

For rootfs creation, using syscall emulation is probably fine for core packages, but you might run into issues with higher level ones.

Using syscall emulation

While qemu-arm can be used to run a single armel binary from the command-line, it's impractical to use it to run a program which will fork and execute other programs. Also, because qemu-arm itself uses shared libraries and the ld.so dynamic linker/loader from the build environment, it's impractical to copy it in the rootfs to use it with chroot-ed programs. So the following instructions expect that you're using a static version of qemu-arm ("qemu-arm-static"), and that your build environment supports the binfmt-misc module, this modules allows running any executable matching some configured pattern with an interpreter of your choice.

    # Ubuntu 10.04 (lucid)
    sudo apt-get install qemu-kvm-extras-static

(Under Debian, the package is named qemu-user-static and under Ubuntu 9.10 (karmic) it's called qemu-arm-static.)

Under Debian and Ubuntu, the package should automatically pull in the "binfmt-support" package and registers the qemu-arm format; check with:

    cat /proc/sys/fs/binfmt_misc/qemu-arm

(the format is named "arm" under Ubuntu 9.10 (karmic)).

Because we're going to chroot into the rootfs directory, the kernel will look for the interepreter in the chroot; copy the interpreter in the chroot:

    sudo cp /usr/bin/qemu-arm-static rootfs/usr/bin

Enter the rootfs chroot and run the second-stage:

    sudo chroot rootfs /bin/bash
    /debootstrap/debootstrap --second-stage

And you're done! You can create a tarball of the rootfs directory, or copy the files into an actual filesystem; see Creating a filesystem from a directory.

You might want to do some system configuration before using this rootfs on devices though; see System configuration.

You may also re-enter the chroot as above, e.g. to install additional packages, but note that usual chroot rules apply, so you will have to mount /proc manually, perhaps bind-mount /dev/pts or /tmp depending on programs you're trying to run, and you should be careful that installin packages might start (duplicate) services/jobs in the chroot or kill ones from outside the chroot!

Using machine emulation

Install qemu-system-arm (you don't need a static version):

    # Ubuntu 10.04 (lucid)
    sudo apt-get install qemu-kvm-extras

(Under Debian and Ubuntu 9.04 (jaunty) and earlier the package is named qemu.)

Create a filesystem image from the rootfs directory; see Creating a filesystem from a directory.

Grab a pre-built kernel for ARM "Versatile" boards patched to run with Cortex-A8 CPU (ARMv7). Use the latest Lucid kernel, or the netboot image, which may not always work:

    wget http://ports.ubuntu.com/ubuntu-ports/dists/lucid/main/installer-armel/current/images/versatile/netboot/vmlinuz

Start qemu as follows:

    qemu-system-arm \
        -M versatilepb \
        -cpu cortex-a8 \
        -hda rootfs.img \
        -m 256 \
        -kernel vmlinuz \
        -append 'rootwait root=/dev/sda init=/bin/sh rw'

The arguments tells qemu ARM machine emulation respectively to:

Once booted, run:

    /debootstrap/debootstrap --second-stage

System configuration

After bootstrapping, a Debian/Ubuntu installation isn't quite complete; depending on the intended use, some final things have to be setup.

You might want to do some system configuration before using this rootfs on devics though; see System configuration.

fstab

The "mountall" process requires an entry in /etc/fstab for the root partition. Normally, it's best to use UUIDs to refer to the rootfs as to be independent of the device path/name; for instance:

    UUID=01234567-89ab-cdef-0123-456789abcdef / ext4 relatime,errors=remount-ro 0 1

but for the initial machine emulation, just use the default disk path, e.g.:

    /dev/sda / ext4 relatime,errors=remount-ro 0 1

Users and passwords

Set a root password with:

    passwd

and create an additional non-root user (e.g. ubuntu) with:

    adduser ubuntu

APT sources

Edit etc/apt/sources.list and configure some APT sources; e.g. for Ubuntu 10.04 (lucid):

    deb http://ports.ubuntu.com/ubuntu-ports/ lucid main

(This will have been done already if you used mk-sbuild)

Kernel

Install the official kernel, for later use.

    apt-get install linux-image-versatile

Hosts and hostname

Give a name to the host device by creating an etc/hostname file with just the short name (e.g. qemu):

    qemu

And add a basic etc/hosts file referencing that short name and definit localhost:

    127.0.0.1 localhost qemu

Virtual network setup

You probably want a loopback interface (lo) and if you're not using Network-Manager to setup the network, you probably want to bring up the virtual ethernet card; create an etc/network/interfaces file with:

    auto lo
    iface lo inet loopback

    auto eth0
    iface eth0 inet dhcp

Serial console

TODO

Creating an Image file from a directory

First, check how much space the files from the rootfs dir would use when copied into a filesystem of a specific block size; for example for a blocksize of 4096 bytes (see the documentation of your filesystem to check which blocksize it uses):

    du -s -B 4096 rootfs

This will return the number of blocks which your filesystem uses, so multiply this number by the blocksize to get the minimum size of your filesystem.

Next, add to that amount the number in bytes of extra space you want in the filesystem.

Create a file, preferably a sparse one, which will hold the rootfs, for instance for a rootfs of 300 000 000 bytes:

    dd if=/dev/zero of=rootfs.img bs=1 count=0 seek=300M

Then format the filesystem, e.g. for ext4 with 4096 bytes blocks:

    mkfs.ext4 -b 4096 -F rootfs.img

Mount the filesystem and move the files over:

    mount -o loop rootfs.img /mnt
    sudo cp -a rootfs/. /mnt/
    umount /mnt

Copy the kernel to outside the image:

    cp rootfs/boot/vmlinuz* .
    ln -s vmlinuz-* vmlinuz

Starting QEMU

Now you can start QEMU on the disk image:

    qemu-system-arm \
        -M versatilepb -cpu cortex-a8 \
        -m 256 \
        -drive file=rootfs.img,media=disk \
        -kernel vmlinuz -append 'root=/dev/sda rootwait'

ARM/RootfsFromScratch/QemuDebootstrap (last edited 2010-03-23 20:53:58 by kees)