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.
You will need:
- debootstrap; your debootstrap should be recent enough to debootstrap the suite you're interested in
- one of qemu-arm-static (syscall emulation) or qemu-system-arm (machine emulation)
- e2fsprogs or some mkfs.something tool if you want to create an actual filesytem
- a kernel for qemu/versatile/cortex-a8
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 --arch armel lucid
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:
- bootstrap for armel
- verify the downloaded data with the installed Ubuntu keyring (from the ubuntu-keyring package); if you want to install e.g. Debian, point at the Debian keyring instead (in the debian-archive-keyring package)
- give some progress information
- only do the first phase of the bootstrapping
- target the Ubuntu 9.10 (karmic) suite
- use "rootfs" as target directory
Things you might want to customize:
- by default, only packages from the "main" component are used, you can enable other components (such as "restricted", "universe", and "multiverse" for Ubuntu and "contrib" and "non-free" for Debian) with the --components= flag
- you can include/exclude some packages via the --include= and --exclude= flags
- you can select different package selections depending on the intended use of the rootfs via the --variant= flag; for instance, --variant=minbase will create a minimal environment with essential packages and apt, while --variant=buildd will install build-essential packages
Check the debootstrap(8) manpage for details. TODO link to man page
Second stage debootstrap with QEMU
QEMU sports two types of emulation:
- syscall emulation: this translates code from one architecture to another, remapping system calls (calls to the kernel) between the two architectures
- machine emulation: this emulates a complete computer, including a virtual CPU, a virtual video card, a virtual clock, a virtual SCSI controller etc.
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:
(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:
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:
- emulate a Versatile PB board
- emulate a Cortex A8 CPU (ARMv7, what the kernel expects and supports all Debian/Ubuntu releases)
- use the rootfs.img file as the contents of the emulated SCSI hard disk
- emulate 256 MB of RAM
- use the downloaded kernel
- and pass some arguments to the kernel to set the root device and start a shell instead of starting /sbin/init
Once booted, run:
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.
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:
and create an additional non-root user (e.g. ubuntu) with:
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)
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):
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
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
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'