Xv6 Kernel Sub-systems

Xv6 is a UNIX-like operating system, built for learning purposes. The operating system kernel is implemented in ANSI C and has support for virtual memory, multi-level page tables, interrrupts, multiple processes, networking etc.

Various sub-systems are implemented/augmented in the plain vanilla operating system present at repo. This was done as part of the MIT Operating Systems Engineering course. This targets the RISCV64 instruction set.

Repository: https://github.com/rajkumar-p/MIT.6.S081

The details of the various changes are given below.

[CSP using Pipes]

This is a ‘heavy’ implementation of sequential communicating process (CSP) using OS processes. We concurrently generate primes and pass them to each process created. This is based on the idea by Doug McIlroy, inventor of Unix pipes. This is described in detail here.

Code - https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab1-Unix-Utilities/user/primes.c


[Tracing System Calls]

This is a ptrace like program that traces the system calls done by the child. You pass as input the mask that represents what calls to trace along with the child command to be run. E.g. - trace 32 grep hello README. This command then prints out calls made to the stdout.

Code - https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab2-System-Calls/user/trace.c, https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab2-System-Calls/kernel/sysproc.c#L100, https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab2-System-Calls/kernel/syscall.c#L166


[Marking Pages for Automatic Garbage collection]

A new system call — pgacess() is introduced to get which pages are read/written over a virtual address range. The starting address along with the number of the pages is passed to the system call. Additionally, the buffer where the results are stored are also passed from user space. This result is stored as a bit set and the bit is on if the page was read or written.

Code – https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab3-Page-Tables/kernel/sysproc.c#L81

[CPU Preemption Handler]

This introduces a new system call – sigalarm() that takes in an interval and a function to be called when the CPU is to be preempted, after some interval. Each time this interval is reached, the user function would be called.

Code - https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab4-Traps/kernel/sysproc.c#L103, https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab4-Traps/kernel/trap.c#L82

[Copy-on-Write (COW) Fork]

The goal of copy-on-write (COW) fork() is to defer allocating and copying physical memory pages for the child until the copies are actually needed, if ever. COW fork() marks all the user PTEs in both parent and child as not writable. When either process tries to write one of these COW pages, the CPU will force a page fault. The kernel page-fault handler detects this case, allocates a page of physical memory for the faulting process, copies the original page into the new page, and modifies the relevant PTE in the faulting process to refer to the new page, this time with the PTE marked writeable. The deallocation of pages becomes a bit tricky though, due to this.

Code: https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab5-Cow-Fork/kernel/kalloc.c, https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab5-Cow-Fork/kernel/vm.c, https://github.com/rajkumar-p/MIT.6.S081/blob/main/Lab5-Cow-Fork/kernel/trap.c

And many others - find files (userspace util), xargs (userspace util), system info (userspace util), print page tables (userspace util), backtrace (userspace util)