Building
I do most of my development work on an x86 Linux system, and thus
wanted to be able to cross-build the NetBSD system from within the
Linux environment. Fortunately, NetBSD provides a great build system
that supports both cross-compilation (building for a processor
architecture different from that of the build host) and cross-platform
builds (building the system on a non-NetBSD build host).
The build process consists of several steps:
- Building the toolchain
- Building the kernel
- Building the userspace libraries and applications
- Building the root filesystem
NetBSD comes with a wonderful shell script, build.sh, that makes all of this easy.
Building the Toolchain
Building the toolchain can be accomplished using the build.sh script: just run
./build.sh -u -m evbarm tools
from within the top-level source directory.
Parameters:
- -u: don't run "make clean" before building;
this prevents everything from being rebuilt if changes are made (not
really essential for this first build step)
- -m evbarm: the machine architecture type; this is for ARM evaluation boards
- tools: build just the toolchain, not the whole system
I actually found I had a problem when trying to build the toolchain on
a Fedora Core 5 system because the native Fedora tools (which are used
to build the NetBSD toochain) were too new (gcc 4.1). The NetBSD
toolchain would build cleanly only with gcc version 3 tools. Luckily,
Fedora provides optional packages for the GCC 3.2 toolset, which can be
installed with
yum install compat-gcc-3.2
The toolchain build process then becomes
export HOST_CC=gcc32
export HOST_CXX=g++32
./build.sh -u -m evbarm tools
to ensure the gcc-3-based tools are used to build the toolchain. Note
that these tools (and the export statements) aren't needed once the
NetBSD toolchain is built - they're just needed to "bootstrap" the
toolchain itself. Note also that the latest NetBSD distribution should
build cleanly with the gcc 4-based tools, so this step shouldn't be
necessary.
Building the Kernel
Building the NetBSD kernel is also accomplished using the build.sh script: just run
./build.sh -u -m evbarm kernel=VX115_VEP
from within the top-level source directory.
Parameters:
- -u: don't run "make clean" before building; this prevents the toolchain from being rebuilt
- -m evbarm: the machine architecture type; this is for ARM evaluation boards
- kernel=VX115_VEP: the kernel configuration file
to use; in this case, it's for the VX115_VEP verification board. The
configuration file is in sys/srch/evbarm/conf.
This command performs a number of operations:
- creates a build directory sys/arch/evbarm/compile/obj/VX115_VEP
- runs the nbconfig "config" utility on the VX115_VEP
configuration
file to create required source files for the build. This config command
does quite a lot; it actually creates source files for the autoconfig
framework specific to the system and device configuration. This is
discussed in more detail in the section on autoconfiguration.
- runs "make depend" on the source files to create the dependency tree for the source files
- runs "make" to build the kernel and drivers
When the command completes, it will create the kernel objects in the
sys/arch/evbarm/compile/obj/VX115_VEP directory. The object files will
include the ELF kernel object, and may contain the output in
different formats depending on the configuration.
- netbsd: ELF object file
- netbsd.bin: netbsd converted to plain binary for direct loading into memory
- netbsd.bin.srec: netbsd.bin converted to S-record format for loading to flash
- netbsd.gdb: ELF object file with debugging symbols (for use with debugger)
Building the Userspace Libraries and Applications
Since the NetBSD distribution includes all of the userspace libraries
and applications, the build.sh script handles these, too: just run
./build.sh -u -m evbarm
from within the top-level source directory. This will create a
directory obj/destdir.evbarm with all of the userspace files.
Building the Root Filesystem
The default build for NetBSD creates a filesystem for a desktop system,
which is way too big for an embedded system. I pulled out just the
minimum basic libraries and apps needed to have a console into a
separate directory called rootfs_ramdisk. (In fact, this is almost
certainly not the bare minimum, but was small enough to fit in the
ramdisk, so I didn't bother to strip it further.)
- rootfs_ramdisk
- [ cat chmod cp date df
echo ed expr hostname kill ln
ls mkdir mv ps pwd rm rmdir
sh sleep stty sync test
- dev
- contents auto-generated as discussed below
- etc
- mkttys passwd.conf rc.conf rc.lkm
rc.shutdown ttys group motd rc rc.local
rc.subr
- rc.d
- lib
- libcrypt.so
libcrypt.so.0 libcrypt.so.0.2 libc.so libc.so.12 libc.so.12.128.2
libedit.so libedit.so.2 libedit.so.2.9 libevent.so libevent.so.0
libevent.so.0.2 libkvm.so libkvm.so.5 libkvm.so.5.2 libm.so
libm.so.0 libm.so.0.2 libtermcap.so libtermcap.so.0
libtermcap.so.0.5 libtermlib.so libtermlib.so.0 libtermlib.so.0.5
libutil.so libutil.so.7 libutil.so.7.6 libz.so libz.so.0
libz.so.0.4
- libexec
- sbin
- dmesg
fsck fsck_ffs init init.shell ldconfig mknod modload modunload
mount mount_ffs mount_filecore mount_kernfs mount_mfs mount_null
mount_overlay mount_procfs mount_ufs nologin rndctl savecore
sysctl ttyflags umount
- usr
This directory is a directory of files on the build host filesystem
(Linux, in my case, using an ext3 filesystem). It's necessary to create
a single file which contains the filesystem image for NetBSD - that is,
the set of objects which are currently in the build host
filesystem, but packaged such that they form a NetBSD filesystem. This
is done with the tool nbmakefs, which is built as part of the toolchain.
nbmakefs -s 5000k rootfs_ramdisk.img rootfs_ramdisk
This will create a filesystem of total size 5000 kB - the resulting
image will be 5000 kB in size (or about 4.9 MB). This value is also
used in the kernel configuration to "reserve" this much space in the
kernel for the filesystem ramdisk image.
Inserting the Ramdisk Image into the Kernel
The ramdisk created above is inserted into the kernel using the tool mdsetimage:
arm--netbsdelf-mdsetimage -v -s netbsd rootfs_ramdisk.img
where netbsd is the kernel image created from the kernel build process.
Further Packaging
For the evaluation platform here, the platform loader used s-record
format for the loadable files, so it was necessary to use the objcopy
tool to generate the loadable srec from the kernel+ramdisk image. In
addition, the kernel was to be loaded at address 0x20400000 in the
system Flash, while it was configured to execute at 0x24300000, which
required the --change-addresses argument during s-record generation.
This sort of thin is very platform-specific, so these steps may not be
relevant for another platform.
arm--netbsdelf-objcopy -S -O binary netbsd netbsd.bin
arm--netbsdelf-objcopy --input-target=binary --output-target=srec --change-addresses=0x20400000 -v netbsd.bin netbsd.bin.srec
Comments/questions: jsevy@cs.drexel.edu