Below is a short summary of the implemented changes. There is a test file added in every folder to ensure the right behavior.
-
File systems: xv6 does not support basic access permissions like most Unix-like systems. We will implement this functionality by defining a variable
uint mode
(bit 0 represents the readability of the file, bit 1 the writability and bit 2 the executability) and adding it to the different representations of files in xv6 and the file metadata (struct dinode
,struct inode
andstruct stat
). Numerous functions in fs.c are adjusted accordingly andls
now shows the permissions of files (in a 'rwx' format). The new system callint chmod(const char*, int)
takes a path to a file as the first parameter and changes its permissions to the second parameter. We also added a new user space programchmod
so the user can manually change permissions (e.g.chmod 7 README
).exec
and theopen
syscall are adjusted so that the access permissions are enforced. -
Locks: the original
kalloc
function in xv6 causes high lock contention due to the use of only one free list of processors. We will reduce this lock contention by giving each processor its own free list and the possibility to steal free frames from other processors (kmem
is replaced by an array ofNCPU
kmem
variables in kalloc.c). An important parameter for this implementation is the number of frames that gets stolen at once. With extensive testing we found thatNFRAMES = 8
yields optimal results. During the initialization ofkalloc
all frames will be assigned to CPU 0, sincekinit
is called by main on this CPU. -
System calls: we added a new system call
void traceme(int enable)
that (ifenable
is truthy) will print every system call of the process to the console, together with thepid
of the process. The new user-space programtrace
calls the executable argument it receives with thetraceme
functionality enabled. -
Traps: the
malloc
implementation of xv6 allocates more memory than asked for to reduce the amount of syscalls. We shall now implement demand paging to prevent overuse of heap memory by makingsbrk
lazy. The newly added functionvoid pagefault(uint64 va)
in vm.c takes the virtual address that was called when the page fault occurred as an argument and serves as a page fault handler. We usekalloc
to allocate new physical frames and make the mappings viamappages
(using the struct proc::sz variable to ensure that this is only done for addresses that were previously allocated viasbrk
). Several functions in xv6 need to be adjusted since the invariant that all pages between[0, struct proc::sz)
must be mapped no longer holds true for demand paging. -
Virtual memory: the
uptime
syscall in xv6 simply returns the global variableticks
. It is particular inefficient to perform two context switches (syscall) only for the sake of reading such a variable. We will optimize this by implementing a similar mechanism as the vDSO mechanism (used in the Linux kernel) to be able to fully execute certain syscalls in the user space. We generate a linker section.vdso
with onlyticks
in it and adjust the linker script. The page with the.vdso
section is mapped at the same location in every user process by adjusting the proc_pagetable function. Lastly a user space functionfastuptime
is created to read theticks
variable in the mapped page and return it.