StuBS
Entwicklungsumgebung zu BS

tl;dr:

  • SSH und VNC in unseren Laborrechner ist verfügbar
      $ ssh and.tanenbaum@lab.sra.uni-hannover.de -p 2205 # für Lab-PC 5
    
  • geteiltes tmux
      $ tmux -S /tmp/my-shared-tmux new                       # tmux session erstellen
      $ setfacl -m "u:and.tanenbaum:rw" /tmp/my-shared-tmux   # Andrew Tanenbaum Zugriff geben
    
      $ tmux -S /tmp/my-shared-tmux attach                    # auf die Session verbinden (vom anderen auszuführen)
    
  • Für den eigenen PC:
      $ apt install nasm qemu qemu-system-x86 qemu-kvm build-essential binutils gcc-multilib g++ g++-multilib
    
    • QEMU (qemu, qemu-system-x86, qemu-kvm)
    • GCC (build-essentials, binutils, gcc-multilibs, g++)
    • nasm

Einleitung

Für die Bearbeitung der Rechnerübungsaufgaben (und damit für die Entwicklung von OOStuBS und MPStuBS) sind alle benötigten Werkzeuge im Labor vorinstalliert. Die Laborrechner sind über SSH und VNC erreichbar. Die Einrichtungsdetails finden sich weiter unten. Ihr könnt die Aufgaben natürlich auch zu Hause bearbeiten, wir empfehlen hierzu den Einsatz von Linux. Weiter unten finden sich einige Hinweise, wie ihr euren Linux-Rechner entsprechend konfigurieren könnt.

Attention
Wer die Software bei sich zu Hause installieren möchte, trägt natürlich die volle Verantwortung für eventuelle Probleme. Fehlgeschlagene Installationen werden von uns auch nicht als Entschuldigung für verspätete Programmabgaben akzeptiert.

Da sich bei der Betriebssystementwicklung ab und zu auch Fehler einschleichen können, müsst ihr eure Lösungen testen, bevor ihr sie abgebt. Wir benutzen hierzu einen Emulator (QEMU bzw. KVM). Bei der Abgabe benutzen wir immer das QEMU und KVM auf dem Labor, um eure Lösung zu kontrollieren. Ihr solltet deshalb immer auch zumindest einmal im Labor testen, das ist die Referenzplattform!

Benutzung der Laborrechner aus der Ferne

Die Laborrechner erreicht man über SSH. VNC kann dann als zweiter Schritt über SSH getunnelt werden.

In jedem Fall benötigt ihr einen Account in unserem Labor, welchen ihr über die SRAccount Website erstellen könnt.

SSH

Um SSH zu verwenden, braucht ihr eine Rechnernummer. Nehmt dazu eure Gruppennummer modulo 10 (um ein bisschen Loadbalancing hinzubekommen). Geht dann auf

$ ssh <euer_login_name>@lab.sra.uni-hannover.de -p 22<rechnernummer>

D.h., für Andrew Tanenbaum wäre der Login für Rechner 5:

$ ssh and.tanenbaum@lab.sra.uni-hannover.de -p 2205

Umgang mit SSH-Keys

Gitlab verbietet den anonymen Zugriff auf euer Repository. Auch eine normale Anmeldung, wie manchmal bei GitHub üblich, ist auf den Repositories nicht möglich. Daher müsst ihr ein Schlüsselpaar erzeugen und Gitlab zur Authentifizierung den öffentlichen Schlüssel zur Verfügung stellen.

Dazu erzeugt ihr am besten lokal per ssh-keygen einen Schlüssel:

$ ssh-keygen -t ed25519

Entweder der Schlüssel wird als ~/.ssh/id_ed25519 also in eurem Home im versteckten Verzeichnis .ssh abgelegt, oder ihr gebt ihm einen anderen Namen. id_ed25519 wird standardmäßig von ssh benutzt, alle anderen Namen existieren für ssh zunächst nicht. Andere Namen müsst ihr z.B. dem ssh-agent bekanntmachen, indem ihr folgendes ausführt:

$ eval $(ssh-agent)        # ssh-agent starten
$ ssh-add ~/.ssh/gitlab    # den Key für Gitlab bekanntmachen

Beim zweiten Schritt werdet ihr u.U. nach dem Passwort gefragt, was ihr bei der Key-Erzeugung angegeben habt.

Ab dem Zeitpunkt (wenn ihr den öffentlichen Schlüssel im Gitlab bekannt gemacht habt), könnt ihr einfach alle git-Kommandos ausführen. Die Authentifizierung läuft ab dann implizit über die Schlüssel und ihr müsst keine Passworte (mehr) eingeben.

SSH-Config

Wir empfehlen die Eintragung der Laborrechner in die lokalen SSH-Config. Dazu muss in der Datei ~/.ssh/config dieser Eintrag hinzugefügt werden:

host lab-pc01
hostName lab.sra.uni-hannover.de
User and.tanenbaum
Port 2201
ForwardX11 yes
ServerAliveInterval 30

Bitte dabei Rechnernamen und Portnummer für den speziellen Rechner anpassen.

Wenn Key und SSH-Config eingerichtet sind, kann man sich einfach per ssh lab-pc01 zum SRA-Rechner verbinden.

VNC

VNC ist eine Technik, um eine Desktopoberfläche über Fernzugriff zu benutzen. Das könnt ihr benutzen, um die X11-Fenster von Qemu zu nutzen oder einen der grafischen Editoren im Labor zu nutzen.

Attention
VNC braucht eine stabile hohe Datenrate. Wir empfehlen daher die reine Konsolen-Benutzung über SSH.

VNC greift im Normalfall auf eine laufende Session zu. Diese ist im Labor für euren Nutzer aber nicht vorhanden. Folglich müsst ihr zusätzlich zu dem VNC-Server auch noch eine Session starten. Dazu legt ihr ein Shellscript ~/.vnc/xstartup an (über die Kommandozeile geht das z.B. mit dem Editor nano gut). In dem Shellscript startet ihr eure Session, z.B. (nur eine der Zeilen sollte einkommentiert sein!):

#!/bin/sh
/usr/bin/startkde &          # KDE
#/usr/bin/gnome-session &    # GNOME
#/usr/bin/startxfce4 &       # XFCE4

Der VNC-Server wird dann diese Datei benutzen, um eine neue Session zu starten. Anschließend könnt ihr auch schon direkt den VNC-Server starten:

$ tigervncserver -useold -localhost

Der Server fragt dann nach einem Passwort (das schützt eure Session) und gibt nach dem Start eine Desktopnummer aus, die ihr später zum Verbinden braucht. Um die Session wieder zu schließen, reicht der Befehl:

$ tigervncserver -kill :<desktopnummer>

Bitte geht dabei verantwortungsbewusst mit den Ressourcen um. Unter Linux ist die Verbindung mit dem VNC-Servier z.B. mit dem VNCViewer möglich:

$ xtigervncviewer -passwd <password-file> -via <ssh-kennung> localhost:<bildschirmnummer>

<ssh-kennung> muss dabei ein Eintrag aus der SSH-Config sein. Technisch müsst ihr einen SSH-Tunnel zum VNC-Port aufbauen und euch dann mit dem Server verbinden. Dieser VNC-Port unterscheidet sich pro gestarteter Instanz. Ihr könnt ihn per netstat -tulpen nachschauen (Der standard ist 5900). Das -via Argument macht das alles implizit. Die Passwort-Datei (.vnc/passwd) muss dabei auf den Client-PC kopiert werden. Unter manchen Distributionen wird der xtigervncviewer auch als vncviewer ausgeliefert. Bspw.:

$ xtigervncviewer -SecurityTypes VncAuth -passwd /home/and.tanenbaum/.vnc/passwd -via lab-pc01 localhost:2

Damit die Kennung lab-pc01 funktioniert, muss eine entsprechende SSH-Config angelegt werden (siehe oben).

Geteiltes tmux

Für das gemeinsame Arbeiten kann man tmux verwenden, um eine TTY-Session mit einem anderen Benutzer zu teilen. Wir verwenden diesen Mechanismus zudem für die gemeinsame Abgabe. Die beiden Benutzer können dann erst einmal dasselbe Terminal sehen und bearbeiten. Außerdem arbeitet tmux sessionbasiert, d.h. man teilt nicht nur ein Terminal, sondern eine ganze Session, konkret beliebig viele Terminals und ihren Zustand und Layout.

Zur Einrichtung erstellt man eine tmux -Session unter Angabe eines Sockets (-S / -L):

$ tmux -S /tmp/my-shared-tmux new

Damit wird ein tmux-Server erzeugt, falls noch keiner auf dem Socket lauscht. (Der Socket-Name my-shared-tmux sollte durch einen eigenen Namen ersetzt werden)

Mit der Option -s session-name (hinter new) kann der Session auch noch ein eigener Name zugewiesen werden (Standard: „0“).

Nun können weitere Nutzer bzw. tmux-Instanzen mit der Session verbunden werden:

$ tmux -S /tmp/my-shared-tmux attach

Gegebenenfalls muss mit der Option -t session-name die Session identifiziert werden. Ein detach wird mit der Tastenfolge Ctrl-b d gemacht.

Damit ein anderer Benutzer ein attach durchführen kann, muss er entsprechende Rechte am Socket haben, was mittels ACLs bewerkstelligt werden kann:

$ setfacl -m "u:and.tanenbaum:rw" /tmp/my-shared-tmux

(Wobei other.user mit dem Usernamen des Partners ersetzt wird.)

Bitte seid bei der Erteilung der Rechte vorsichtig und verwendet dafür im Labor keine UNIX-Gruppenberechtigungen. Bedenkt, dass jeder in einer solchen Gruppe dann vollen Zugriff auf eure tmux-Session hat.

Für weitere Informationen siehe die offizielle tmux-Doku oder die Manpage von tmux.

SSHFS

Wenn ihr (lokal) einen grafischen Editor benutzen wollt, aber trotzdem die make-Targets auf den Laborrechner nutzen wollt, bietet es sich an, das Labor per SSHFS lokal zu mounten. Damit könnt ihr euern Code ganz normal lokal bearbeiten und trotzdem die Targets remote ausführen.

Prinzipiell reicht es dazu, so etwas auszuführen:

$ mkdir sra-mount
$ sshfs lab-pc01: sra-mount
$ cd sra-mount; ls

Benötigte Software für eine eigene Installation

Zum Kompilieren wird wie im Makefile vorgegeben g++ verwendet, zum Assemblieren des Startup-Codes und der hardwarenahen Teilprogramme der Netwide Assembler (nasm). Der x86-Emulator QEMU eignet sich zum Testen und, durch einen eingebauten GDB-Stub, auch zum Debuggen mit dem GNU Debugger. Im Laborraum ist die entsprechende Umgebung vorhanden; wer das Ganze zu Hause machen will, muss sich die genannte Software entsprechend einrichten. Bei Problemen könnt ihr uns gerne fragen.

*StuBS-Vorgabe bauen

  • Ab Aufgabe 1 gibt es je eine Vorgabe für OOStuBS und MPStuBS. Die Vorgaben sind Git Repositories auf dem Uni Gitlab, in die wir die Vorgaben für die einzelnen Aufgaben sukzessive einchecken.

    Wir werden für eure Gruppen Repositories im Gitlab anlegen und ihr könnt euch beim Übungsleiter zu diesen Gruppen zuweisen lassen. In der Beschreibung des Gruppenrepositories ist beschrieben, wie ihr die Vorlage (entweder OOStuBS oder MPStuBS) in euer Repository integrieren könnt.

  • Für die weiteren Aufgaben werden wir die Vorgabenrepositories erweitern, sodass ihr euch nur die Änderungen in euer Repository ziehen müsst. Diese geänderten Vorgaben enthalten die für die jeweilige Aufgabe neu hinzukommenden Dateien.
  • Alle Vorgaben, die ihr von uns erhaltet, lassen sich korrekt übersetzen, enthalten aber nur unvollständigen Code. Ihr müsst also für jede Aufgabe den Code in den entsprechend markierten Funktionen und Klassen vervollständigen.
  • Das eigentliche Kompilieren von OOStuBS erfolgt durch den Aufruf von make im Lösungsverzeichnis. Alle .cc- und .asm-Dateien im Lösungsverzeichnis werden daraufhin mit den entsprechenden Tools (Compiler bzw. Assembler) übersetzt und als bootbares Systemimage zusammengebunden. Das Makefile stellt außerdem Befehle bereit, um das System mithilfe von QEMU zu testen oder zu debuggen. Die genauen Befehle liefert make help.

Testen und Debuggen von OOStuBS (Make-Targets)

  • Als schnellsten und einfachsten Test eurer Implementierung könnt ihr mit make kvm euer Systemimage in QEMU mit Hardware-Virtualisierung ausführen:\
    dietrich@obelix:~/oostubs$ make kvm
    
    Dabei wird QEMU standardmäßig so konfiguriert, dass er ein System mit vier Prozessoren emuliert. Für die Entwicklung von OOStuBS stört dies nicht weiter, da die zusätzlichen CPUs ohne weiteres Zutun einfach „links liegen“ gelassen werden. Für die MPStuBS-Bastler gilt: durch den KVM-Modus wird euer System echt parallel auf mehreren Kernen ausgeführt. Dieser Test kommt daher im Hinblick auf Race-Conditions und fehlerhafter Synchronisation dem Test auf der echten Hardware schon relativ nahe.
Attention
Um ein QEMU, dass im Curses Modus gestartet wurde, wieder zu beenden, muss man auf die Monitoransicht wechseln (Alt-2) und dort quit eingeben. Um von der Monitoransicht wieder auf die CGA Ansicht zu kommen muss man Alt-1 drücken. Auf einem anderen virtuellen QEMU-Fenster (Alt-3) ist übrigens die serielle Schnittstelle angezeigt.
  • Zur leichteren Fehlersuche kann die Hardware-Virtualisierung auch deaktiviert werden, indem man stattdessen den Befehl make qemu verwendet. In diesem Modus wird das Gastsystem lediglich pseudo-parallel emuliert, was bei schwerwiegenderen Bugs die Suche erleichtert, aber andererseits auch vorhandene maskieren kann, die sonst nur mit make kvm oder auf echter Hardware auftreten.
  • Wer bei der Fehlersuche mit einfachem „printf-Debugging“ nicht weiterkommt, der kann den in QEMU integrierten GDB-Stub verwenden, um sich mit einem Debugger (gdb) zu der Emulation zu verbinden. Auf diese Weise könnt ihr euren Betriebssystemcode bequem schrittweise ausführen, um den Grund etwaiger Abstürze oder ungewünschten Verhaltens herauszufinden. Dafür stellen wir im Makefile das Target gdb bereit:

    dietrich@obelix:~/oostubs$ make gdb
    

    In dieser Konfiguration wartet der GDB-Stub im Emulator auf eine Socket-Verbindung, über die sich ein gdb mit dem Emulator verbinden kann, um das System zu debuggen. Der Start des Debuggers wird bereits im Makefile erledigt, so dass der gdb-Prompt unmittelbar nach dem Start von QEMU im Terminal erscheint.

    Eine knappe Referenz der GDB-Funktionen könnt ihr hier finden. Wollt ihr detailierte Hinweise, wie ein bestimmter GDB-Befehl zu verwenden ist, so könnt ihr die in GDB eingebaute Hilfefunktion nutzen:

    (gdb) help <Befehlsname>
    

    Hinweis: Da durch den Emulator QEMU bei Verwendung des GDB-Stubs das Betriebssystem pausiert wird, darf man im GDB die Programmausführung nicht mit run neu anstoßen, sondern muss sie stattdessen mit continue fortführen.

    Für einen schnelleren Überblick der Register- und Stackinhalte empfiehlt sich außerdem, diese gdbinit-Datei unter dem Namen .gdbinit im eigenen Home-Verzeichnis abzulegen. Diverse Ansichtsoptionen am Anfang der Datei können ganz nach dem eigenen Geschmack geändert werden.

    GDB kann überdies mithilfe von monitor Befehle an QEMU übermitteln. Praktisch ist hier z.B.: monitor info registers (Register zeigen), monitor system_reset System neustarten, ohne GDB neuzustarten.

  • Das Arbeiten von Zuhause geht am einfachsten über eine SSH-Verbindung. Von alleine könnt ihr auf dieser Verbindung aber kein Fenster starten. QEMU ist aber in der Lage, den CGA-Screen im Textmodus vollständig mit NCurses auf ein Terminal zu mappen. Die Makefile-Targets sind daher so eingerichtet, dass sie automatisch den NCurses-Modus, wenn kein Display vorhanden ist.

    Das GDB-Target braucht allerdings ein X11-Fenster. Es ist aber möglich, GDB separat zu starten und QEMU anzuweisen, auf GDB zu warten. Letzeres geht, wenn ihr die vorhanden Targets mit dem -gdb-Suffix startet. Ersteres geht, wenn ihr das spezielle Target connect-gdb verwendet. D.h., um einen QEMU mit eurem System zu starten und zu debuggen, öffnet ihr zwei Terminals über SSH und gebt in dem einen ein:

    dietrich@obelix:~/oostubs$ make qemu-curses-gdb
    

    und in dem anderem:

    dietrich@obelix:~/oostubs$ make connect-gdb
    
  • Hinweis zu Compileroptimierungen: Das Standardverhalten des vorgegebenen Buildsystems ist, das Optimierungslevel -O3 zu verwenden. Bei hartnäckigen Bugs kann der daraus entstehende Maschinencode das Debugging deutlich erschweren. Für diese Fälle gibt es alle oben genannten Makefile-Targets auch als Variante mit dem Suffix -noopt, welches die Compileroptimierungen deaktiviert. GDB-Debugging ohne Optimierungen ist beispielsweise mit diesem Aufruf möglich:
    dietrich@obelix:~/oostubs$ make gdb-noopt
    
  • Eine Übersicht über die verfügbaren Kommandos gibt (neben dem Lesen des Makefiles) auch
    dietrich@obelix:~/oostubs$ make help
    

Quellcodeverwaltung in einem gemeinsamen Git für die ganze Gruppe

Wie bereits erwähnt, ist die Vorlage zu OOStuBS/MPStuBS/StuBSmI im Uni-Gitlab zu finden. Wir haben dort jeder Übungsgruppe ein Repository angelegt, welches ihr zur gemeinsamen Arbeit nutzen sollt. Per git clone <url> könnt ihr euer individuelles Repository klonen. Es empfiehlt sich, einen SSH-Key zu generieren und den öffentlichen Schlüssel im Uni-Gitlab zu hinterlegen.

Um das Vorlagenrepo eurem Repo hinzuzufügen, benutzt folgende Befehle:

# Vorlage für Single-Core
git remote add vorlage git@gitlab.uni-hannover.de:sra/vbsb2022/oostubs.git
# oder
# Vorlage für Multi-Core
git remote add vorlage git@gitlab.uni-hannover.de:sra/vbsb2022/mpstubs.git
# Aktualisieren des lokalen Repositories mit dem Stand der Vorlage
git pull vorlage main

Eine kurze Übersicht der Git-Befehle findet ihr hier. Als tieferen Einstieg in die verteilte Quellcodeverwaltung empfehlen wir das Pro Git Buch, welches als Creative Commons verfügbar ist.