Introduction to xv6

What the cat is xv6?

xv6 is a simple Unix-like educational (aka. toy) operating system developed by MIT. It was designed to help you understand how modern operating systems work.

xv6 File Structure

Kernel:

File / DirectoryDescription
kernel/Contains all kernel source code
kernel/defs.hGlobal function declarations
kernel/proc.cProcess creation, scheduling, and switching
kernel/syscall.cSystem call dispatch table
kernel/trap.cInterrupt and exception handling
kernel/fs.cFile system implementation
kernel/vm.cPage table and virtual memory management
kernel/exec.cHandles execution of new programs (exec)
kernel/sysproc.cImplementation of process-related system calls
kernel/syscall.hSystem call number definitions
kernel/param.hDefines global system parameters and limits (e.g., max processes, open files, path length).

User:

File / DirectoryDescription
user/Contains user-level programs (ls, sh, cat, etc.)
user/user.hDeclarations for user-space functions
user/usys.plPerl script that generates system call stubs (usys.S) for user programs
user/init.cFirst user program that runs after boot
user/echo.c, user/ls.c, etc.Built-in user programs

Other Important Files:

File / DirectoryDescription
MakefileMain build configuration
mkfs/mkfs.cTool for building xv6 filesystem image
READMEOfficial documentation

Some Basic Operations

How to run xv6?

You can run xv6 by typing make qemu in the terminal.

$ make qemu

You might need to use the following commands.

CommandDescription
make cleanRemoves compiled files.
makeCompiles xv6 and builds the disk image (no execution).
make qemuBuilds xv6 and runs it inside QEMU.
make qemu-gdbRuns xv6 and waits for a GDB connection — useful for kernel debugging.

How to exit xv6?

You can exit xv6 by pressing Ctrl-A and X.

How to add a new system call?

Suppose we want to add a new system call mycall()

1. Declare a new syscall number in kernel/syscall.h:

// ... other syscalls
#define SYS_fork     1
#define SYS_exit     2
...
#define SYS_close   21
#define SYS_mycall  22 // <-- Add your syscall here

2. Register the syscall in kernel/syscall.c:

First, add a function prototype:

// ...
extern uint64 sys_mkdir(void);
extern uint64 sys_close(void);
extern uint64 sys_mycall(void); // <-- Add this line

Then, register it in the syscalls array:

static uint64 (*syscalls[])(void) = {
  [SYS_fork]    sys_fork,
  [SYS_exit]    sys_exit,
  // ...
  [SYS_mkdir]   sys_mkdir,
  [SYS_close]   sys_close,
  [SYS_mycall]  sys_mycall, // <-- Add this line
};

3. Implement the syscall in kernel/sysproc.c:

...
uint64
sys_mycall(void)
{
  printf("Hello from the kernel!\n");
  return 0; 
}

4. Add the user-space stub in user/usys.pl:

...
entry("uptime");
entry("mycall"); # <-- Add this line

5. Add the user-space API in user/user.h:

...
int uptime(void);
int mycall(void); // <-- Add this line

And you can call this system call by mycall() in user program.

How to add a new user program?

Suppose we want to add a new user program called hello.

1. Create a new file in the user/:

Create a new file named hello.c in the user/ directory:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user.h"
    
    
int main(int argc, char *argv[]) { 
  printf("hello! your name is %s\n",argv[1]); 
  exit(0); 
} 

2. Add the program to the UPROGS list in the Makefile:

UPROGS=\
    $U/_cat\
    $U/_echo\
    $U/_grep\
    ...
    $U/_hello\  <----- <-- Add this line
    ...

3. Rebuild and run xv6

$ make clean
$ make qemu

4. Run program

Once xv6 starts, type the following in the xv6 shell:

$ hello amy

You should see:

hello! your name is amy

Modify parameters

1. Edit kernel/param.h:

System parameters are defined in kernel/param.h. For example, to change the maximum number of processes from 64 to 128:

#define NPROC        128  // maximum number of processes

2. Re-compile the kernel:

$ make clean
$ make qemu
Back to top