Logo  

CS471/571 - Operating Systems

Lesson 4

Xv6

Xv6 is a bare-bones re-implementation of 6th edition Unix, originally for educational use at MIT. It is a very stripped down version of Unix, providing only a simple round-robin scheduler, statically compiled binaries that use a single contiguous memory region with no demand paging support, and almost nothing in the way of drivers (VGA and IDE only.)

It does support SMP and a simplified file-system with transaction and crash recovery support.

To install xv6, use git to clone the repository:

git clone https://github.com/mit-pdos/xv6-public.git

You will likely need to patch it to work with newer gcc installations. Add 'objcopy --remove-section .note.gnu.property' commands to the Makefile at the following locations:

...

initcode: initcode.S
    $(CC) $(CFLAGS) -nostdinc -I. -c initcode.S
    objcopy --remove-section .note.gnu.property initcode.o
    $(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o
    $(OBJCOPY) -S -O binary initcode.out initcode
    $(OBJDUMP) -S initcode.o > initcode.asm

...


and:

...

ULIB = ulib.o usys.o printf.o umalloc.o

_%: %.o $(ULIB)
    objcopy --remove-section .note.gnu.property ulib.o
    $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^
    $(OBJDUMP) -S $@ > $*.asm
    $(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym

...


Or use the patched copy at:

tar xf ~sbaker/public_html/cs471/code/xv6-public.tgz

You should then have a xv6-public directory, which you may rename or move wherever.

To build xv6, simply type 'make' while inside of the xv6-public directory. To run xv6 in the QEMU virtual machine, run:

make qemu To run it under the X version of qemu (supports VGA graphics.)
make qemu-nox To run it w/o X windows support.

QEMU short-cut keys for X-windows:

Ctrl-Alt-g Grab/release mouse cursor
Ctrl-Alt-q Quit QEMU
Ctrl-a x Quit QEMU if not using X-windows


Creating a "Hello, world!" program for XV6

In the xv6-public directory we create the following C file:

#include "types.h"
#include "stat.h"
#include "user.h"

int main(void)
{
  printf(1, "Hello, world!\n");

  exit();
}


Notice:

  1. user.h has the prototypes for all the user-space functions and system calls available to our programs. The file user.h also requires that we #include types.h and stat.h as those types and structures are referenced in the user.h header file.

  2. Notice that printf() takes an integer argument before the format string. The first parameter is the file descriptor to output to, 1 being standard output.

  3. The exit() call at the end is required to end our program. Exit in XV6 does not take a parameter and just ends the program. Programs do not therefore have a exit status.

To compile the hello world example, we add in the Makefile the build target _hello\ (note the underscore) to the UPROGS variable:

...
UPROGS=\
        _cat\
        _echo\
        _forktest\
        _grep\
        _init\
        _kill\
        _ln\
        _ls\
        _mkdir\
        _rm\
        _sh\
        _stressfs\
        _usertests\
        _wc\
        _zombie\
        _hello\

...


Then run the 'make qemu' or 'make qemu-nox' commands to compile the user-space and start Xv6. Then you can run the hello program at the XV6 shell prompt. Use Ctrl-Alt-Q (X version) or Ctrl-a followed by 'x' (nox version) to exit back to your prompt.

Available User-space and System calls:

system calls

int fork(void);
int exit(void) __attribute__((noreturn));
int wait(void);
int pipe(int*);
int write(int, const void*, int);
int read(int, void*, int);
int close(int);
int kill(int);
int exec(char*, char**);
int open(const char*, int);
int mknod(const char*, short, short);
int unlink(const char*);
int fstat(int fd, struct stat*);
int link(const char*, const char*);
int mkdir(const char*);
int chdir(const char*);
int dup(int);
int getpid(void);
char* sbrk(int);
int sleep(int);
int uptime(void);

ulib.c (User-space Library)

int stat(const char*, struct stat*);
char* strcpy(char*, const char*);
void *memmove(void*, const void*, int);
char* strchr(const char*, char c);
int strcmp(const char*, const char*);
void printf(int, const char*, ...);
char* gets(char*, int max);
uint strlen(const char*);
void* memset(void*, int, uint);
void* malloc(uint);
void free(void*);
int atoi(const char*);