Betriebssystem für PC104-Rechner

Die Erzeugung eines Crosscompilers mit Integration einer bestimmten libc ist ein komplexer Vorgang, der einiges an Wissen und Erfahrung erfordert. Ohne die erforderlichen Patches und Konfigurationseinstellungen scheitert in der Regel bereits der Versuch. Glücklicherweise gibt es mit buildroot ein System, das den gesamten Prozeß automatisiert und zusätzlich ein einfaches Root-Dateisystem mit konfigurierbarer Softwareausstattung erzeugen kann. Der Benutzer wählt menügesteuert die gewünschten Eigenschaften aus, buildroot lädt alle nötigen Dateien aus dem Internet, übersetzt sie und erstellt dabei neben dem Crosscompiler ein TAR-Archiv, das sich in dem späteren Root-Dateisystem auspacken läßt.

Vorbereitung der Installation

Der hier beschriebene Buildprozeß geht davon aus, daß alle erforderlichen Quellcodearchive und Konfigurationsdateien im Home-Verzeichnis des Benutzers pc104 liegen. Dort wird später auch der Crosscompiler installiert. Die Quellen befinden sich auf dem pc104-Account, wichtig sind die Verzeichnisse source und config. Zum Übersetzen müssen die üblichen Werkzeuge installiert sein, zusätzlich werden die Pakete etherboot, grub, syslinux und die Entwicklerversionen von ncurses und gettext gebraucht.

Die Installation der Kernel-Module erfordert eine Version des Programmes depmod, die für Kernel der Serie 2.4 geeignet ist und bei neueren Distributionen zum Beispiel depmod.old heißen kann. Das Arbeitsverzeichnis für den gesamten Vorgang sollte auf einer lokalen Festplatte liegen, die mehr als ein Gigabyte freien Speicherplatz bieten muß.

Zu Beginn der Installation werden die wichtigsten Verzeichnisse in Variablen gespeichert.

  SOURCE=/home/pc104/source
  CONFIG=/home/pc104/config
  TMP=/tmp

Die Variable TOOLCHAIN legt das Zielverzeichnis für den Crosscompiler fest, ROOTFS verweist in die spätere buildroot-Installation und gibt den Ort an, wo die Vorlage für das Root-Dateisystem später liegen wird.

  TOOLCHAIN=/home/pc104/toolchain
  ROOTFS=$TMP/buildroot/build_i386/root

Es dürfen keine Reste von einer vorher durchgeführten Installationen existieren, insbesondere müssen die Quellcodeverzeichnisse und der Crosscompiler gelöscht sein.

  rm -rf $TMP/buildroot
  rm -rf $TMP/linux-2.4.31
  rm -rf $TMP/peak-linux-driver-3.17
  rm -rf $TOOLCHAIN

Basissystem und Crosscompiler

Den größten Teil der Arbeit übernimmt jetzt buildroot, zunächst wird das Archiv ausgepackt.

  cd $TMP
  tar xfvj $SOURCE/buildroot/buildroot-snapshot.tar.bz2
  cd buildroot

Damit das Ergebnis reproduzierbar bleibt, sollen die Quelldateien nicht neu aus dem Internet heruntergeladen werden. Stattdessen werden Versionen in das buildroot-Verzeichnis kopiert, die sich als funktionierend herausgestellt haben.

  cp -av $SOURCE/buildroot/dl .

Das Paket unterstützt das Remote Shell Protokoll nicht, ein Patch ergänzt die Funktionalität.

  patch -p0 < $SOURCE/buildroot/buildroot-netkitrsh.patch

Die Konfiguration des Paketes wird aus den Vorgaben übernommen. Die Einstellungen und der Softwareumfang können in den verschiedenen Dateien oder über die Menüs von buildroot eingesehen und verändert werden.

  cp $CONFIG/buildroot .config
  cp $CONFIG/busybox package/busybox/busybox.config
  cp $CONFIG/uclibc toolchain/uClibc/uClibc.config

Wenn der Crosscompiler in einem anderen Verzeichnis als /home/pc104/toolchain installiert werden soll, müssen in .config und toolchain/uClibc/uClibc.config die Einstellungen von BR2_STAGING_DIR sowie CROSS_COMPILER_PREFIX entsprechend geändert werden. Damit ist das Paket bereit zum Übersetzen.

  make oldconfig
  make

Nach dem erfolgreichen Durchlauf ist der Crosscompiler einsatzbereit und ein erstes lauffähiges Root-Dateisystem erstellt. Es wird in den nächsten Schritten mit den noch fehlenden Tools angereichert und konfiguriert.

Übersetzung des Linux-Kernels

Der Linux-Kernel wird passend für das PC104-System erzeugt und später auf die Flashdisc sowie in ein Image für den Bootserver verpackt. Alle Einstellungen sind auf möglichst geringen Speicherbedarf hin optimiert, die meisten Funktionen deaktiviert und alle wichtigen fest in den Kernel eingebaut. Besonders wichtig sind die Fließkomma-Emulation, die Netzwerkfunktionen und die Möglichkeit zum Mounten des Root-Dateisystems per NFS Version 3.

Zuerst wird der Quellcode ausgepackt.

  cd $TMP
  tar xfvj $SOURCE/linux/linux-2.4.31.tar.bz2
  cd linux-2.4.31

Eine problematische Header-Datei muß vor dem Compilieren noch korrigiert werden.

  patch -p0 < $SOURCE/linux/linux-2.4.31-asmerror.patch

Dann wird die gespeicherten Konfiguration übernommen und der Kernel übersetzt.

  make mrproper
  cp $CONFIG/linux .config
  make oldconfig
  make dep
  make bzImage
  make modules

Der Kernel und die erzeugten Module werden in das Root-Image von buildroot installiert.

  cp -a arch/i386/boot/bzImage $ROOTFS
  cp -a System.map $ROOTFS
  INSTALL_MOD_PATH=$ROOTFS make modules_install
  rm -f $ROOTFS/lib/modules/2.4.31/build

An dieser Stelle kann eine Warnung ausgegeben werden, falls das Paket modutils nicht installiert ist. Sie darf ignoriert werden, das spätere System sollte auch ohne den Aufruf von depmod -a problemlos benutzbar sein.

CAN-Treiber, Library und Testprogramme

Das Treiberpaket von Peak System enthält neben dem Kernelmodul die Bibliotheken sowie verschiedene Testprogramme. Zunächst wird wieder der Quellcode ausgepackt.

  cd $TMP
  tar xfvz $SOURCE/pcan/peak-linux-driver.3.17.tar.gz
  cd peak-linux-driver-3.17

Ein einfacher Befehl compiliert das Modul gegen die zuvor benutzten Kernelquellen.

  make -C driver -f Makefile-2.4 CC=$TOOLCHAIN/bin/i386-linux-uclibc-gcc \
    KERNEL_LOCATION=$TMP/linux-2.4.31 \
    USB=NO_USB_SUPPORT PAR=NO_PARPORT_SUBSYSTEM

Die im Paket enthaltene Library wird zur Entwicklung eigener Programme benötigt.

  make -C lib CC=$TOOLCHAIN/bin/i386-linux-uclibc-gcc

Das Modul findet seinen Platz in dem Root-Image von buildroot.

  install -D -m644 driver/pcan.o $ROOTFS/lib/modules/2.4.31/misc/pcan.o

Die CAN-Library wird im Dateisystem der PC104-Rechner installiert.

  install -m644 lib/libpcan.so.0.3 $ROOTFS/lib
  ln -sf libpcan.so.0.3 $ROOTFS/lib/libpcan.so

Um Programme mit CAN-Unterstützung erzeugen zu können, werden Header und Library in den Crosscompiler integriert.

  install -m644 driver/pcan.h $TOOLCHAIN/include
  install -m644 lib/libpcan.h $TOOLCHAIN/include
  install -m644 lib/libpcan.so.0.3 $TOOLCHAIN/lib
  ln -sf libpcan.so.0.3 $TOOLCHAIN/lib/libpcan.so

Schließlich enthält das Paket noch einige Testprogramme für den CAN-Bus. Sie können später zum Beispiel in das Home-Verzeichnis eines Benutzers kopiert werden.

  make -C test CC=$TOOLCHAIN/bin/i386-linux-uclibc-gcc LDLIBS=-L$TOOLCHAIN/lib
  strip test/{bitrate,receive,transmi}test

Konfiguration des Basissystems

Das von buildroot erzeugte Dateisystem muß noch für den späteren Einsatz konfiguriert werden. Dazu werden einige Dateien verändert oder hinzugefügt und das Dateisystem neu erstellt.

  cd $TMP/buildroot

Die Liste der zu erzeugenden Devices enthält zu wenig Loop-Devices sowie keinerlei Einträge für das ppdev-Interface und die CAN-Controller. Ein Patch korrigiert diese Punkte.

  patch -p0 < $SOURCE/buildroot/buildroot-devices.patch

Das Paßwort für root ist bisher leer und wird zur Sicherheit geändert.

  sed -i -e 's#^root:[^:]*:#root:$1$KGJY4wAY$y4AM4vtw/I9J2NQswkQ17.:#' \
    $ROOTFS/etc/shadow

Der in buildroot standardmäßige vorhandene Benutzer default wird nicht benötigt.

  sed -i -e '/^default:/d;' $ROOTFS/etc/{passwd,shadow,group}
  rm -rf $ROOTFS/home/default

In einem letzten Schritt werden Dateien des Systems überschrieben oder durch neue ergänzt. Zu den wichtigsten Änderungen gehören ein neues Bootskript und eine deutsche Tastaturbelegung. Damit wird ein Image für den Betrieb unabhängig vom Netzwerk erstellt.

  rm -f $ROOTFS/etc/resolv.conf
  cp -av $SOURCE/rootfs/standalone/* $ROOTFS
  rm -f $TOOLCHAIN/fakeroot.env
  touch $TOOLCHAIN/fakeroot.env
  make
  cp rootfs.i386.tar rootfs-standalone.i386.tar

Der Prozeß wiederholt sich für die Netzwerkversion mit anderen Dateien.

  rm -f $ROOTFS/etc/resolv.conf
  cp -av $SOURCE/rootfs/nfsclient/* $ROOTFS
  rm -f $TOOLCHAIN/fakeroot.env
  touch $TOOLCHAIN/fakeroot.env
  make
  cp rootfs.i386.tar rootfs-nfsclient.i386.tar

Einrichtung der Flashdisc

Jeder PC104-Rechner verfügt über eine Festplatte in Form einer Flashdisc mit einer Kapazität von 32 MB. Die Platte muß an einem Notebook, über einen Adapter an einem Desktop oder direkt an einem USB-Wechselplattenrahmen für 2.5 Zoll-Festplatten betrieben werden, um das Bootsystem des PC104-Rechners zu installieren.


Provisorischer Adapter für Flashdisc

Die Flashdisc ist das einzige bootfähige Medium, da die Rechner weder über ein Boot-ROM noch über ein Diskettenlaufwerk verfügen. Auf ihnen wird grub als Bootloader installiert. Er kann lokal gespeicherte Diskettenimages, ein System von einer lokalen Partition oder ein Image von einem Bootserver starten. Dafür werden drei Partitionen angelegt, eine große für ein Linux, das ohne Netzwerk funktioniert und zur Diagnose benutzt werden kann, eine dazugehörige Swap-Partition sowie eine kleine Partition für grub und die Bootimages. Durch die Trennung von Linux und grub ist der Bootloader vor versehentlichen Änderungen besser geschützt.

Partitionierung

Zunächst muß die Flashdisc in einen Rechner eingebaut, partitioniert und formatiert werden. Die nächsten Schritte gehen davon aus, daß sie unter /dev/sda erreichbar ist und der Benutzer als root arbeitet. Falls gewünscht, wird die Platte zuerst mit Nullbytes überschreiben.

  dd if=/dev/zero of=/dev/sda bs=65536 count=496

Anschließend wird ein Master Boot Record installiert, 0x80 ist die spätere Adresse der Platte.

  install-mbr /dev/sda -d 0x80

Falls das Programm install-mbr nicht existiert, übernimmt der folgende Befehl dessen Aufgabe.

  dd if=$SOURCE/bootimage/mbr.img of=/dev/sda bs=512 count=1

Jetzt können zum Beispiel mit fdisk die benötigten Partitionen angelegt und aktiviert werden.

  fdisk /dev/sda

Das Ergebnis muß folgendermaßen aussehen. Die Anzahl der Köpfe, Sektoren und Zylinder muß im Expertenmodus von fdisk auf die angegebenen Werte umgestellt werden, falls sie nicht stimmen sollten. Die dritte Partition wird den Bootmanager enthalten, sie muß als bootfähig gekennzeichnet und aktiviert worden sein.

  Disk /dev/sda: 32 MB, 32505856 bytes
    4 heads, 32 sectors/track, 496 cylinders
    Units = cylinders of 128 * 512 = 65536 bytes

       Device Boot      Start         End      Blocks   Id  System
    /dev/sda1               1         415       26544   83  Linux
    /dev/sda2             416         479        4096   82  Linux swap
    /dev/sda3   *         480         496        1088   83  Linux

In den Partitionen müssen noch die jeweiligen Dateisysteme erstellt werden. Um möglichst viel nutzbaren Platz übrig zu behalten, wird ext2 als Dateisystem benutzt und kein Platz für den Root-Benutzer reserviert.

  mke2fs -m0 /dev/sda1
  mkswap /dev/sda2
  mke2fs -m0 /dev/sda3

Konfigurationstool der Netzwerkkarte

Der Netzwerkchip der PC104-Rechner muß später konfiguriert werden, damit er vom Bootcode erkannt wird. Das dazu nötige DOS-Programm wird in ein Diskettenimage gepackt und auf die Flashdisc gespeichert. Die Basis bildet das Image einer 360 KB großen Bootdiskette von FreeDOS, das zunächst von allen überflüssigen Dateien befreit werden muß. Wichtig sind nur kernel.sys und command.com.

  cp $SOURCE/freedos/b9boot01.img $TMP/realtek
  mount -o loop -t msdos $TMP/realtek /mnt
  rm -i /mnt/*

Das Tool von Realtek wird in das Image kopiert und eine passende autoexec.bat angelegt.

  cp $SOURCE/realtek/rset8019.exe /mnt
  echo -en '@echo off\r\nrset8019\r\n' > /mnt/autoexec.bat
  umount /mnt

Die resultierende Datei ist auch unter $SOURCE/bootimage/realtek vorhanden.

Booten per Netzwerk

Beim Booten per Netzwerk muß auf dem Client eine entsprechende Software die Netzwerkkarte initialisieren, das Betriebssystem laden und starten. Diese Aufgabe übernimmt in der Regel das BIOS des Systems oder ein ROM-Baustein auf der Netzwerkkarte. Am leistungsfähigsten ist das aktuelle PXE, das aber für den älteren RTL8019(AS)-Chips der PC104-Rechner nicht verfügbar ist. Der Hersteller bietet nur ROMs mit dem veralteten RPL an, der dazugehörende Server rpld hat unter Linux das Entwicklungsstadium aber nie verlassen. Als einzige Alternativen bleiben noch netboot und etherboot, von denen nur letzteres noch gepflegt wird. Es war damit die einzig sinnvolle Wahl. Die Images des Projektes können in einem ROM-Baustein, auf einer Diskette, in einem Bootimage für GRUB und in einer Vielzahl anderer Formate abgelegt werden, was sehr viele Einsatzmöglichkeiten eröffnet. Als Imagedatei auf der Festplatte kann das Image einfach aktualisiert werden und es entfällt der Aufwand, für jeden Rechner ein EPROM zu brennen.

Das etherboot-Image kann auf der Seite http://rom-o-matic.net/ erstellt werden. Dazu wird auf der Startseite Version 5.0.7 ausgewählt (neuere funktionieren nicht), "ne" als NIC und "LILO bootable ROM" als Imagetyp eingestellt. Unter "Configure" werden einige Optionen geändert.

  ASK_BOOT=-1
  CONFIG_PCI_DIRECT

Der Knopf "Get ROM" erzeugt ein Image, das unter dem Namen etherboot gespeichert wird. Die fertige Datei ist unter $SOURCE/bootimage/etherboot vorhanden.

Integration aller Systeme

Im letzten Schritt werden die Partitionen der Flashdisc mit den nötigen Dateien gefüllt. Um das System bootfähig zu machen, muß auf dem Wirtsrechner grub installiert sein. Aus dessen Lieferumfang werden die Dateien stage1 und stage2 benötigt, die auch auf einem 386er lauffähig sein müssen. Das selbe gilt für memdisk auf dem syslinux-Paket, auch diese Datei wird für den Bootprozeß benötigt. Alle drei sind unter $SOURCE/bootimage vorhanden und lassen sich im Notfall auch über buildroot neu erzeugen.

Als erstes wird die Partition des Bootmanagers mit Dateien gefüllt.

  mount /dev/sda3 /mnt
  cp $SOURCE/bootimage/{stage1,stage2,memdisk,realtek,etherboot} /mnt
  cp $CONFIG/grubmenu /mnt/menu.lst
  umount /mnt

Der grub auf dieser Partition muß noch aktiviert werden, was mit der grub-Shell auf dem Host passiert. Die Parameter des install-Befehls geben die Positionen der stage-Dateien an, bestimmen in welche Partition die Installation erfolgen soll, und wo grub später seine Konfigurationsdatei findet. Der Umweg über die Datei device.map erlaubt es, alle Partitionen so zu spezifizieren, wie sie später im PC104-Rechner heißen werden.

  echo "(hd0) /dev/sda" > $TMP/device.map
  grub --device-map $TMP/device.map
  install (hd0,2)/stage1 (hd0,2) (hd0,2)/stage2 (hd0,2)/menu.lst
  quit

Das vorbereitete Linux für den Betrieb ohne Netzwerk wird in seine Partition installiert.

  mount -t ext2 /dev/sda1 /mnt
  tar -C /mnt -xf $TMP/buildroot/rootfs-standalone.i386.tar
  umount /mnt

Nach dem Einbau der Platte ist der Rechner bootfähig. Für die Installation weiterer Flashdiscs empfiehlt es sich, die Festplatte einfach zu kopieren statt alle Schritte nochmals auszuführen.

  dd if=/dev/sda of=$TMP/flashdisc.img bs=65536 count=496
  dd if=$TMP/flashdisc.img of=/dev/sda bs=65536 count=496

Vorbereitung der Clients

Der Zusammenbau der PC104-Rechner beginnt mit der Konfiguration des CAN-Controllers auf I/O-Adresse 0x240 und IRQ 10. Auf die Platine kommt das CPU-Board, in dessen Sockel die vorbereitete Flashdisc gesteckt wird. Vor dem Einschalten werden noch Tastatur und Monitor angeschlossen, der Rechner startet beim Einstecken der 5 Volt-Spannungsversorgung. Zunächst werden im BIOS einige Einstellungen durchgeführt oder überprüft. Die Festplatte sollte fest angemeldet werden, da die automatische Erkennung gelegentlich versagen kann. Es darf kein Diskettenlaufwerk aktiviert sein, das Booten muß auch ohne Tastatur und Monitor möglich sein und die seriellen Schnittstellen müssen aktiviert und als RS232 konfiguriert sein. Der Parallelport sollte im EPP/ECP-Modus arbeiten. Beim Booten von der Flashdisc wird im erscheinenden Menü das Konfigurationsprogramm der Netzwerkkarte aufgerufen. Sie muß auf "jumperless" mit I/O-Adresse 0x300 und IRQ 5 umgestellt werden, damit etherboot die Hardware richtig ansteuern kann und es unter Linux keine Ressourcenkonflikte gibt.

Installation des Bootservers

Auf einem Server sind alle Dienste installiert, die von den Rechnern im PC104-Cluster benötigt werden. Die Installation erfolgt komplett mit Root-Rechten, die benötigten Dateien sind vorher nach /tmp auf den Server zu kopieren. Alle Daten der Clients landen in einer gemeinsamen Ordnerstruktur.

  CLIENTS=/export/0/home/pc104/clients

Die Reste einer vorigen Installation müssen zunächst gelöscht werden. Die Benutzerdaten und die Userdatenbank (passwd, shadow und group) sind gegebenenfalls vorher zu sichern.

  rm -rf $CLIENTS

Die erforderliche Verzeichnisstruktur für die Knoten wird anlegegt.

  install -d -m755 -groot -oroot $CLIENTS
  for NODE in $CLIENTS/node{{0,1}{0,1,2,3,4,5,6,7,8,9},2{0,1,2,3,4}}; do \
    install -d -m755 -groot -oroot $NODE; \
  done
  install -d -m755 -groot -oroot $CLIENTS/tftpboot
  install -d -m755 -groot -oroot $CLIENTS/home

Es folgt das Auspacken der Root-Verzeichnisse für die verschiedenen Rechner.

  for DIR in $CLIENTS/node{{0,1}{0,1,2,3,4,5,6,7,8,9},2{0,1,2,3,4}}; do \
    tar -C $DIR -xf /tmp/rootfs-nfsclient.i386.tar; \
  done

Im Dateisystem jedes Rechners wird ein Swapfile von 8 MB angelegt und initialisiert.

  for DIR in $CLIENTS/node{{0,1}{0,1,2,3,4,5,6,7,8,9},2{0,1,2,3,4}}; do \
    dd if=/dev/zero of=$DIR/var/swapfile bs=1024k count=8; \
    mkswap $DIR/var/swapfile; \
  done

Etherboot kann nur Systeme starten, deren Kernel und gegebenenfalls initrd in einem speziellen Image zusammengefaßt sind. Der folgende Befehl erzeugt das Image direkt im Bootverzeichnis.

  mkelf-linux --output $CLIENTS/tftpboot/pc104.nb --ip=dhcp \
    --append "root=/dev/nfs" /tmp/bzImage

DHCP-Server

Der DHCP-Server teilt jedem Knoten basierend auf seiner MAC-Adresse die Konfiguration, den Pfad zum Bootimage und die Parameter zum Mounten des Root-Dateisystems mit. Es handelt sich um einen dhcpd3, der wie folgt konfiguriert ist.

  option domain-name "rtsys";
  option domain-name-servers jitter.rtsys;
  ddns-update-style none;
  ddns-updates off;
  authoritative;
  server-name "gate2";
  shared-network railway-net
  {
    option ntp-servers time.rtsys;
    use-host-decl-names true;
    subnet 10.6.2.128 netmask 255.255.255.128
    {
      option routers gate2-1.rtsys;
      option broadcast-address 10.6.2.255;
      filename "/pc104.nb";
      # Knoten 0
      host node00 {
        hardware ethernet 00:05:b7:02:9c:05;
        fixed-address node00.rtsys;
        option root-path "10.6.2.129:/export/0/home/pc104/clients/node00,
          v3,tcp,rsize=2048,wsize=2048";
      }
      # ...weitere Einträge für die übrigen Knoten...
    }
  }

TFTP, NFS und Zeitserver

Die Bootimages werden von dem TFTP-Server atftp ausgeliefert, der $CLIENTS/tftpboot als Root-Verzeichnis benutzt. Dort liegt in Form der Datei pc104.nb ein Linux-Kernel, der von Etherboot geladen werden kann. Die Root-Verzeichnisse der Knoten werden per NFS exportiert.

  /export/0/home/pc104/clients   10.6.2.128/25(rw,async,no_root_squash)

Beim Systemstart gleichen alle PC104-Rechner ihre Uhren per rdate mit dem Server ab. Dafür muß in der Datei /etc/xinetd.d/time-udp der Dienst aktiviert sein.