/Teaching/Operating Systems/Tutorials/Allgemeines

Allgemeines

Where do I get the zsh together with an appropriate configuration?

Enter: sudo apt-get install zsh && wget -O ~/.zshrc http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc && chsh -s /usr/bin/zsh

Wo finde ich Manuals zur X86-Architektur (bzw. zur ARM-Architektur)?

Die Intel-Manuals sind direkt bei Intel als Download erhältlich.

Bei den ARM-Manuals gibt es gewisse Unterschiede je nach Version. Das ARMv5-Manual ist für SWEB Development ein guter Einstiegspunkt.

 Müssen für den erstellten Code debug oder kprintfd ausgaben erstellt werden? Oder reicht es, den Code (gut) kommentiert abzugeben?

Beachtet im Assignment den Punkt “Erforderlicher Output”. Verwendet bitte die Funktion debug(…), um den debug-output mittels debug flags zu steuern. Kommentare im code sind natuerlich auch notwendig, aber ein gut lesbarer Output wird durch keinen Kommentar ersetzt.

Kompilieren + Linken

Wenn ich Assembler Code in das Projekt einfüge, bzw. vorhandenen bearbeite, werden diese Dateien dann mit make automatisch kompiliert oder muß man das manuell machen? Wie sieht das mit C++ Dateien aus?

Sofern du deine neuen Dateien in bereits vorhandenen Verzeichnissen (mit Makefile) einfügst und dann einmal ‘cmake .’ laufen lässt, werden sie mitübersetzt. Die Erkennung der Source-Dateien findet über die Dateiendung statt: .cpp entspricht C++, .c entspricht C, .S ist Assembler mit AT&T-ähnlicher Syntax (GNU assembler)

Multithreading

Jede Instanz der Klasse Thread hat ja eine Membervariable stack_, die dem Thread einen Stack von 8 KB zur verfügung stellt. In einem vorherigen Posting wurde geschrieben dass sich der Stack eines Threads auf einer Page befindet. Wenn sich der Stack eines Threads auf einer Page befindet, was hat es dann mit dieser Membervariable stack_ auf sich bzw. wie sieht der Zusammenhang zwischen dieser Stack-Page und dieser Variable aus!?!?!

Es gibt bei einem Prozess mit nur einem Thread jeweils zwei Stacks in Sweb: Ein Stack für den Usermodus, für den extra eine Page eingebunden wird Ein Stack für den Kernelmodus, der irgendwo im Kernelspeicherbereich allokiert wird.

Multithreading: Wie bekomme ich eine neue Adresse für einen neuen UserStack und wie kann ich dafür Speicher anfordern?

Sie “bekommen” von selbst mal gar nichts. Da sich alle Threads denselben virtuellen Adressraum teilen (müssen), müssen alle Stacks aller threads da drinnen Platz haben. Wo die Stacks der neuen Thread zu liegen kommen, ist Ihre Design-Entscheidung und Sie müssen dieses Design dann an geeigneter Stelle in den Code einbauen.

Auf 32bit wurden die Funktionsparameter über den Stack übergeben, wie ist das bei 64bit?

Bei 64bit Systemen werden die (ersten) Parameter über die folgenden Register übergeben: RDI, RSI, RDX, RCX, R8, und R9 (Unix calling convention) . Sollte eine Funktion mehr Parameter haben, kommen diese auf den Stack.

Welche arten von Threads sollen von uns geforkt werden? Sollen nur UserThreads unterstützt werden oder sollen alle Arten von Threads fork unterstützen, beziehungsweise was sollte ein thread, der kein userThread ist, bei einem fork tun? → nur bei UserThreads sinnvoll!

Die stack_-Membervariable der Klasse Thread hat einfach nur den Zweck, Speicher für das Stackframe des Threads im Kernelmodus bereitzustellen.

Syscalls

Wenn ein Userprogramm einen Syscall aufruft, und ich mich dann im SyscallHandler im Kernel befinde und dort ein Yield() aufrufe, wo wacht das Userprogramm das nächste mal, wenn es vom Scheduler aufgerufen wird, wieder auf?

Im Kernel, und zwar nach dem Yield().

Wenn ein Programm am Ende seines Codes angelangt ist, dann wird dieses ja ohne den Syscall Exit beendet.

exit wird in jedem Fall aufgerufen: Wenn du dir das File start.s ansiehst, bemerkst du, dass er zuerst deine main-funktion, und danach immer syscall exit aufruft.

Kernel (in general)

We need a system time!

IRQ0 is issued periodically. You can count how many IRQ0s occured (we call that ticks). Based on the frequency of the IRQ0 you get your system time. Sometimes you need more accurate timing. You can use the timestamp counter (rdtsc) for that or the RealTimeClock if you need the bios set date and time.

What is the frequency of the IRQ0 (timer interrupt)?

The default frequency is 18.2065Hz (that is approximately 54,9254ms between each IRQ0).

Userprogramme

In der Posix-Norm wird für Zeiger void* verwendet. Dürfen (Sollen) wir stattdessen den Typ “pointer” verwenden, der in SWEB definiert wurde.

arch/x86/include/types.h wird in der Userspace-libc an sich nicht, sondern mehr im Kernel verwendet. Am Einfachsten ist es sicherlich, wenn man im libc-Teil (Interface für die Userprogramme) die gegebenen Typen verwendet und sich hier an POSIX hält. Auf der Kernelseite könnt ihr natürlich gern die vordefinierten Typen bzw. eigene verwenden, solange das mit der libc-Seite zusammenpasst und dokumentiert wird.

Kann man im Userspace keine Klassen anlegen?

Nein, es gibt momentan nur reines C im Userspace!

Wo erfolgt im MemoryManagement die Unterteilung in Data, Text, Stack und Heap? Ich hab mir den PageManager genau durchgeschaut – aber finde da nirgends eine Unterscheidung

Der PageManager macht nur eines: Er verwaltet die freien physikalischen Seiten. Das hat erstmal nichts mit den Sections eines Executables bzw dem ELF Format zu tun. Im Executable steht dann welche Section (Data, Text, BSS) an welche linearen Adressen kommen soll. Der Loader liest diese Infos aus, holt sich vom PageManager eine freie physikalische Seite, erstellt ein Mapping von der gewünschten linearen Page auf die gerade geholte physikalische Page und schreibt den ByteCode dann auf auf den spezifizierten linearen Adressebereich

Userspace Locks

Wann dürfen wir bei Userspace Locks Syscalls verwenden?

Userspace Locks sollen mit so wenig Syscalls wie möglich implementiert werden – insbesondere dürfen außer yield keine Syscalls ausgeführt werden. Ob ein Thread schlafen gelegt werden muss soll ohne Syscall bereits im Userspace entschieden werden. Ob ein Thread aufgeweckt werden muss soll ebenfalls ohne Syscall bereits im Userspace entschieden werden.

Paging

Die MMU übernimmt ja die Adress-Übersetzung. Dazu braucht sie ja diese Seitentabelle. Wo diese ist weiß sie, indem man die Startadresse von der Tabelle in das Register schreibt. Aber woher kennt sie die Struktur?

Stimmt, das Register heißt CR3. Dieses verweist allerdings nicht sofort auf die pageTABLE sondern zuerst auf das pageDIRECTORY, dessen Einträge wiederum erst auf pageTABLEs verweisen. Die Struktur gibt die CPU vor, daher kennt sie sie auch. Das Betriebssystem muss die Struktur einhalten, welche die CPU vorgibt. ein paar structs für diese Strukturen findest du in der paging-definitions.h in arch/x86/include/…

Ich habe mittlerweile verstanden, dass der vierte GB des virtuellen Speichers ein 1:1 Mapping des physikalischen Speichers ist. Man verwendet also ‘get3GBAddress’, um direkt auf den physikalischen Speicher zuzugreifen. Aber: Bietet die MMU dieses Mapping von Haus aus an?

die Umsetzung der linearen Adressen in physikalische Adressen macht natürlich schon der Prozessor. SWEB kümmert sich nur darum, dass alle neuen page Directories so initialisiert werden, dass der Bereich zwischen 3 und 4 GB auf die physikalischen Seiten zwischen 0 und 1 GB zeigen.

Angenommen 5 Prozesse verwenden eine gemeinsame physical page. sobald diese Page modifiziert wird, wird das dirty flag im PTE des aktiven Prozesses gesetzt, richtig? die anderen 4 kriegen also nichts von der modifikation mit.

Genau!

Wie wird festgestellt, dass es sich um einen PageFault handelt?

Alle Speicherzugriffe werden über die MMU abgewickelt, die im PD und im PT die physikalische Adresse der Seite raussucht. Wenn im PDE (page-dir-entry) schon das present-Bit 0 ist, dann ist die PT nicht im physikalischen Speicher vorhanden. Wenn die PT aber vorhanden ist, dann wird erst im PTE nachgeschaut, ob das present-Bit gesetzt ist. Für das Auslösen eines PageFaults ist es egal, ob im PDE oder im PTE das present-Bit 0 ist.

Wo wird auf eine Page zugegriffen, die bereits geladen ist? Und wird genau dort dann das Accessed Bit gesetzt?

Bei jedem Zugriff (read or write) wird das accessed bit in der zugehörigen PTE automatisch von der HardWare (CPU/MMU) gesetzt.

Swapping

Wo ist die Größe des Blockdevices, das wir zum swapen verwenden sollen einzustellen? Ist es möglich die Devicegröße eines Blockdevices in sweb abzufragen?

Dazu gibt es die beiden BDRequest Typen BD_GET_BLK_SIZE und BD_GET_NUM_BLOCKS. Wenn du diese Requests an das Device schickst und die Ergebnisse multiplizierst hast du die Groesse des Devices in Bytes.

Dürfen wir am Page Manager was ändern, bzw wie erweitern wir die Klasse um neue Members ohne daß uns was um die Ohren fliegt ?

Im Prinzip könnt ihr ganz normal neue Members adden. Allerdings ist es imho besser, swap-Management, PageTable, Inverse PageTable usw in eine eigene oder mehrere eigene Klassen zu packen. So müsst ihr im PM nur ein wenig Code hinzufügen/ändern was problemlos möglich ist. (bei den meisten wird das heißen 1-2 Zeilen hinzufügen)

Kann die PageTable der ausgelagerten Seite auch ausgelagert sein? (bei Behandlung im PageFaultHandler)

Die PT auszulagern macht sowieso nur Sinn, wenn alle PageFrames dahinter auch ausgelagert sind (du greifst auf die PT mindestens genauso oft zu wie auf die dahinterliegenden PageFrames). Also ja, sie KANN ausgelagert sein, wenn ihr das Auslagern von PageTables implementiert habt. Dann müsst ihr halt PT UND PageFrame einlagern.

There are many descriptions of WorkingSet-*-algorithm on the internet, which one shall we implement?

All descriptions have something in common:

    • Each process has a working set size N (defined by a number or by time)
    • Each process has a number of mapped pages M
    • Each page has a process internal timestamp (process time(!), not real time) T
    • The N youngest pages are in the working set, the remaining M-N pages are not
    • Any page in no working set can be swapped
    • The working set size for all processes is decreased upon certain occasions (for example: when the number of free pages reaches zero)
    • The working set size for a process is increased upon certain occasions (for example: when a pagefault for this process occurs)

Apart from that, implement it as you like.

File System

Do I have to care for locking? For example one or more threads have a file open and another threads write to the same file.

No, you don’t. This is already implemented.

I’ve created a new test program, but actually I can not run it. It seems that the program is not even copied to the SWEB image.

Does your test-program have a long filename? Minix, the used file-system, restricts filenames to max 30 chars. So if your file has a name longer than 30 chars (including the extension!) it can not be copied to the image.