StuBS
Entwicklungsumgebung zu BSB

tl;dr:

  • SSH und X2Go auf die Pool-Rechner sind verfügbar. Zur Abgabe treffen wir uns auf l00p31.
      $ ssh ccd5802@l00p31.rz.tu-harburg.de # Rechner 00, Pool 3a
      $ source /opt/OO-MPStuBS/env.sh       # Entwicklungsumgebung einrichten
    
  • geteiltes tmux
      $ tmux -S /tmp/my-shared-tmux new                       # tmux session erstellen
      $ setfacl -m "u:xxd1234:rw" /tmp/my-shared-tmux         # xxd1234 hat zugriff
      $ tmux -S /tmp/my-shared-tmux attach                    # auf die Session verbinden (von beiden 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 in den Linux-Pools der TUHH vorinstalliert. Die Rechner sind über SSH und X2Go 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. Die Abgabe der Aufgaben findet immer in einem geteilten TMUX auf l00p31 statt.

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 Linux-Pool testen, das ist die Referenzplattform!

Benutzung der Linux-Pools aus der Ferne

Die Pool-Rechner erreicht man über SSH um eine Konsole zu bekommen. Alternativ kann man sich auch mit X2Go verbinden um eine graphische Oberfläche zu bekommen.

SSH

WICHTIG: Der Login funktioniert nur aus dem TUHH Netz. Also entweder verwendet ihr von Zuhause VPN oder nehmt den SSH Server als Jump Host.

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

$ ssh <euer_login_name>@l<Rechnernummer>p31.rz.tu-harburg.de

Das heißt, für den Nutzer xxd1234 wäre der Login für Rechner 5:

$ ssh xxd1234@l05p31.rz.tu-harburg.de

Zuhause könnt ihr ein Stück SSH Konfiguration (~/.ssh/config) verwenden, damit ihr ssh pool machen könnt:

Host pool
     User xxd1234
     Hostname l05p31.rz.tu-harburg.de
     GSSAPIAuthentication yes
     GSSAPIDelegateCredentials yes
     ForwardAgent yes

Da auf den Rechnerpools ein älteres Redhat Linux installiert ist, war es notwendig einige Tools (GCC 10, Nasm 2.15, etc.) selbst zu komplieren. Daher müsst ihr auf den Poolrechnern diese Tools in euren Pfad aufnehmen. Um dies zu tun, ruft nach dem Login folgendes auf:

$ source /opt/OO-MPStuBS/env.sh

Um dies nicht jedes mal machen zu müssen, könnt ihr diesen Befehl auch in eure ~/.bashrc aufnehmen.

Umgang mit SSH-Keys und Gitlab

Als Kollaborationsplattform verwenden wir das Gitlab der TUHH, wo wir euch entsprechende Gruppenrepositories anlegen. Allerdings verbietet Gitlab den anonymen Zugriff auf euer Repository und auch eine Anmeldung mit Login und Passwort, wie manchmal bei GitHub üblich, ist nicht erlaubt. Daher müsst ihr ein Schlüsselpaar erzeugen und dem Gitlab den öffentlichen Schlüssel zur Verfügung stellen zur Authentifizierung.

Dazu müsst ihr lokal ein Schlüsselpaar mit ssh-keygen erzeugen:

$ ssh-keygen -t rsa -b 4096

Entweder der Schlüssel wird als ~/.ssh/id_rsa also in eurem Home im versteckten Verzeichnis .ssh abgelegt, oder ihr gebt ihm einen anderen Namen. id_rsa wird standardmäßig von ssh angeboten, alle anderen Namen existieren für ssh zunächst nicht. Alle anderen Schlüsseldateien könnt ihr dem ssh-agent bekanntmachen, indem ihr:

$ eval $(ssh-agent)             # ssh-agent starten
$ ssh-add ~/.ssh/gitlab         # den Key in der Datei gitlab bekanntmachen

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

Den frisch erzeugten SSH Schlüssel müsst ihr noch in Gitlab bekannt machen: User Settings > SSH Keys.

Danach 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.

Geteiltes tmux

Für das gemeinsame Arbeiten kann man tmux verwenden, um eine TTY-Session mit einem anderen Benutzer zu teilen. 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:abc9876:rw" /tmp/my-shared-tmux

(Wobei abc9876 mit dem Usernamen des Partners ersetzt wird.)

Bitte seid bei der Erteilung der Rechte vorsichtig und verwendet dafür im Pool 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.

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 vorläufigen 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

  • Zu Aufgabe 1 gibt es je eine Vorgabe für OOStuBS (https://collaborating.tuhh.de/e-exk4/teaching/ss21/bsb-oostubs) und MPStuBS (https://collaborating.tuhh.de/e-exk4/teaching/ss21/bsb-mpstubs). Die Vorgaben sind Git Repositories im TUHH Gitlab, in die wir die Vorgaben für die einzelnen Aufgaben sukkessive 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 eurer Repository integrieren könnt.

  • Für die weiteren Aufgaben werden wir die die Vorgabenrepositories erweitern, sodass ihr euch nur die Änderungen in euer Repository ziehen müsst. Diese geänderten Vorgaben enthalten 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 unter beschriebenen 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. Anschließend stehen euch die Befehle make {kvm,qemu}{,-gdb,-ddd}{,-noopt} zum Testen und Debuggen zur Verfügung (mehr dazu im nächsten Abschnitt).
    • Einen Überblick über die möglichen make-Targets erhaltet ihr mit make help

Testen und Debuggen von OOStuBS (Make-Targets)

  • Als schnellsten und einfachsten Test eurer Implementierung könnt ihr mit make qemu-curses euer Systemimage in QEMU ausführen:\
    ccd5802@l00p35:~/oostubs$ make qemu-curses
    
    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. Leider können wir in diesem Semester im Rechnerpool noch kein KVM verwenden.
  • 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/DDD 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.

  • 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. Wir haben euch darum Targets eingerichtet, welche QEMU/KVM mit curses starten und auf von SSH aus funktionieren.
    dietrich@obelix:~/oostubs$ make qemu-curses
    dietrich@obelix:~/oostubs$ make kvm-curses
    
    Auch das GDB-Target braucht ein 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 bzw. MPStuBS im Gitlab zu finden. Wir haben dort jeder Übungsgruppe ein Repository angelegt, welches ihr zur gemeinsamen Arbeit nutzen sollt.

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.