Lab 2: Hello, xv6!
Advanced Operating Systems

Zubair Nabi
zubair.nabi@itu.edu.pk

February 6, 2013
V6
•
•
•
•

Sixth Edition Unix a.k.a. Version 6 Unix
First public release of Unix out of Bell Labs
Designed for DEC PDP-11*
Original source code still available:

http://minnie.tuhs.org/cgi-bin/utree.pl
• Bible: Commentary on UNIX 6th Edition by John Lions (http:
//www.lemis.com/grog/Documentation/Lions/)
xv6

• Reimplementation of V6 in ANSI C out of MIT for x86 systems
• The entire source code can be converted to a PDF via make

print
• Textbook/commentary: xv6: a simple, Unix-like teaching
operating system
• Online: http://pdos.csail.mit.edu/6.828/2012/
xv6/book-rev7.pdf
Installation
1

Install packages
• sudo apt-get install zlib1g-dev glib2.0-dev
mpage

2

Install QEMU
• git clone
http://pdos.csail.mit.edu/6.828/qemu.git -b
6.828-0.152
• ./configure --disable-kvm
--target-list=“i386-softmmu x86_64-softmmu”
• make
• sudo make install

3

Setup xv6
• git clone
git://pdos.csail.mit.edu/xv6/xv6.git
• make
• make qemu
OS in a nutshell

1

Manages low-level hardware;

2

Multiplexes the hardware;

3

Provides controlled ways for process interaction.
xv6 structure
• Monolithic kernel which provides services to running programs,
called processes
• Processes use system calls to access kernel services
• A system call is a procedure call in the OS interface

• System calls enter kernel space, force the kernel to perform a
service, and then return
• A process alternates between user and kernel space

User-space

P1
System
Call

Kernel-space

P2
System
Call
OS protection

• CPU’s hardware protection mechanisms enable the kernel to
sandbox each process within its own memory
• Kernel executes with hardware privileges while processes do not

• On a system call, the hardware raises the privilege level and
executes a specific function in the kernel
xv6 system calls

System call

fork()
exit()
wait()
kill(pid)
getpid()
sleep(n)
exec(filename, *argv)
sbrk(n)
open(filename, flags)

Description
Create process
Terminate current process
Wait for a child process to exit
Terminate process pid
Return current process’s id
Sleep for n seconds
Load a file and execute it
Grow process’s memory by n
bytes
Open a file; flags indicate read/write
xv6 system calls (2)
System call

read(fd, buf, n)
write(fd, buf, n)
close(fd)
dup(fd)
pipe(p)
chdir(dirname)
mkdir(dirname)
mknod(name, major, minor)
fstat(fd)
link(f1, f2)
unlink(filename)

Description
Read n bytes from an open file
into buf
Write n bytes to an open file
Release open file fd
Duplicate fd
Create a pipe and return fd’s in p
Change the current directory
Create a new directory
Create a device file
Return info about an open file
Create another name (f2) for the
file f1
Remove a file
Shell

• Program for executing user commands
• Not a part of the kernel – only uses system calls to interact with it
• Replaceable!
Process

• A combination of user-space memory (instructions, data, and
stack) and per-process kernel state
• xv6 takes care of register management
• Each process can be identified through its pid, a positive integer
Process creation

• fork system call to create a new (child) process
• Same memory contents as the parent
• Fork returns the child pid in the parent and zero in the child
Process creation (2)

int pid;
pid = fork();
if(pid > 0){
printf("parent: child=%dn", pid);
pid = wait();
printf("child %d is donen", pid);
} else if(pid == 0){
printf("child: exitingn");
exit();
} else {
printf("fork errorn");
}
Process replacement

• exec system call replaces the process’s memory with a new
memory image
• exec starts executing instructions from the new memory image
• sbrk(n) to grow data memory on the fly
Process replacement (2)

char *argv[3];
argv[0] = "echo";
argv[1] = "hello";
argv[2] = 0;
exec("/bin/echo", argv);
printf("exec errorn");
File descriptor

• A small integer to index a kernel-managed object with read/write
semantics
• Obtained by opening a “file” (file, directory, device, pipe, existing
file descriptor)
• Each process has a file descriptor table indexed by file
descriptors
•
•
•
•

Standard input: File descriptor 0
Standard output: File descriptor 1
Standard error: File descriptor 2
The shell always has these open
File descriptor (2)

• read(fd, buf, n)
Reads at most n bytes from the fd;
Copies them into buf;
3 Returns the number of bytes read and advances the offset.
1
2

• write(fd, buf, n)
1
2

Writes n bytes from the buf to the fd;
Returns the number of bytes written and advances the offset.

• close(fd)
1

Closes the fd

• dup(fd)
1

Duplicates the fd
File descriptor (3)
char buf[512];
int n;
for(;;){
n = read(0, buf, sizeof buf);
if(n == 0)
break;
if(n < 0){
fprintf(2, "read errorn");
exit();
}
if(write(1, buf, n) != n){
fprintf(2, "write errorn");
exit();
}
}
Input redirection

char *argv[2];
argv[0] = "cat";
argv[1] = 0;
if(fork() == 0) {
close(0);
open("input.txt", O_RDONLY);
exec("cat", argv);
}
Pipe

• A small kernel buffer
• Exposed to processes as a pair of file descriptors
• One fd for reading, the other for writing

• pipe(p) creates a pipe and puts read/write file decriptors in the
array p
Pipe (2)
int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
exec("/bin/wc", argv);
} else {
write(p[1], "hello worldn", 12);
close(p[0]);
close(p[1]);
Filesystem

• Implemented as a tree-like structure
• Files: uninterpreted byte arrays
• Directories: references to other files and directories
• Paths are either absolute or relative
Filesystem (2)
• fstat(fd) system call retrieves information about the object
that the fd maps to
• Fills up the following struct:

#define T_DIR 1 // Directory
#define T_FILE 2 // File
#define T_DEV 3 // Device
struct stat {
short type; // Type of file
int dev; // File system’s disk device
uint ino; // Inode number
short nlink; // Number of links to file
uint size; // Size of file in bytes
};
Today’s Task

• Write C code that replaces steps 3 to 5 from your last task
• For simplicity, you can perform steps 1 and 2 manually
• C code extension: .c
• To compile: gcc test.c -o test.exe
• To run: ./test.exe
• System calls/methods (possibly) needed: printf (stdio.h),
exit() (stdlib.h), execv(), dup(), close(), pipe()
Reading

Chapter 0 from “xv6: a simple, Unix-like teaching operating system”

AOS Lab 2: Hello, xv6!

  • 1.
    Lab 2: Hello,xv6! Advanced Operating Systems Zubair Nabi zubair.nabi@itu.edu.pk February 6, 2013
  • 2.
    V6 • • • • Sixth Edition Unixa.k.a. Version 6 Unix First public release of Unix out of Bell Labs Designed for DEC PDP-11* Original source code still available: http://minnie.tuhs.org/cgi-bin/utree.pl • Bible: Commentary on UNIX 6th Edition by John Lions (http: //www.lemis.com/grog/Documentation/Lions/)
  • 3.
    xv6 • Reimplementation ofV6 in ANSI C out of MIT for x86 systems • The entire source code can be converted to a PDF via make print • Textbook/commentary: xv6: a simple, Unix-like teaching operating system • Online: http://pdos.csail.mit.edu/6.828/2012/ xv6/book-rev7.pdf
  • 4.
    Installation 1 Install packages • sudoapt-get install zlib1g-dev glib2.0-dev mpage 2 Install QEMU • git clone http://pdos.csail.mit.edu/6.828/qemu.git -b 6.828-0.152 • ./configure --disable-kvm --target-list=“i386-softmmu x86_64-softmmu” • make • sudo make install 3 Setup xv6 • git clone git://pdos.csail.mit.edu/xv6/xv6.git • make • make qemu
  • 5.
    OS in anutshell 1 Manages low-level hardware; 2 Multiplexes the hardware; 3 Provides controlled ways for process interaction.
  • 6.
    xv6 structure • Monolithickernel which provides services to running programs, called processes • Processes use system calls to access kernel services • A system call is a procedure call in the OS interface • System calls enter kernel space, force the kernel to perform a service, and then return • A process alternates between user and kernel space User-space P1 System Call Kernel-space P2 System Call
  • 7.
    OS protection • CPU’shardware protection mechanisms enable the kernel to sandbox each process within its own memory • Kernel executes with hardware privileges while processes do not • On a system call, the hardware raises the privilege level and executes a specific function in the kernel
  • 8.
    xv6 system calls Systemcall fork() exit() wait() kill(pid) getpid() sleep(n) exec(filename, *argv) sbrk(n) open(filename, flags) Description Create process Terminate current process Wait for a child process to exit Terminate process pid Return current process’s id Sleep for n seconds Load a file and execute it Grow process’s memory by n bytes Open a file; flags indicate read/write
  • 9.
    xv6 system calls(2) System call read(fd, buf, n) write(fd, buf, n) close(fd) dup(fd) pipe(p) chdir(dirname) mkdir(dirname) mknod(name, major, minor) fstat(fd) link(f1, f2) unlink(filename) Description Read n bytes from an open file into buf Write n bytes to an open file Release open file fd Duplicate fd Create a pipe and return fd’s in p Change the current directory Create a new directory Create a device file Return info about an open file Create another name (f2) for the file f1 Remove a file
  • 10.
    Shell • Program forexecuting user commands • Not a part of the kernel – only uses system calls to interact with it • Replaceable!
  • 11.
    Process • A combinationof user-space memory (instructions, data, and stack) and per-process kernel state • xv6 takes care of register management • Each process can be identified through its pid, a positive integer
  • 12.
    Process creation • forksystem call to create a new (child) process • Same memory contents as the parent • Fork returns the child pid in the parent and zero in the child
  • 13.
    Process creation (2) intpid; pid = fork(); if(pid > 0){ printf("parent: child=%dn", pid); pid = wait(); printf("child %d is donen", pid); } else if(pid == 0){ printf("child: exitingn"); exit(); } else { printf("fork errorn"); }
  • 14.
    Process replacement • execsystem call replaces the process’s memory with a new memory image • exec starts executing instructions from the new memory image • sbrk(n) to grow data memory on the fly
  • 15.
    Process replacement (2) char*argv[3]; argv[0] = "echo"; argv[1] = "hello"; argv[2] = 0; exec("/bin/echo", argv); printf("exec errorn");
  • 16.
    File descriptor • Asmall integer to index a kernel-managed object with read/write semantics • Obtained by opening a “file” (file, directory, device, pipe, existing file descriptor) • Each process has a file descriptor table indexed by file descriptors • • • • Standard input: File descriptor 0 Standard output: File descriptor 1 Standard error: File descriptor 2 The shell always has these open
  • 17.
    File descriptor (2) •read(fd, buf, n) Reads at most n bytes from the fd; Copies them into buf; 3 Returns the number of bytes read and advances the offset. 1 2 • write(fd, buf, n) 1 2 Writes n bytes from the buf to the fd; Returns the number of bytes written and advances the offset. • close(fd) 1 Closes the fd • dup(fd) 1 Duplicates the fd
  • 18.
    File descriptor (3) charbuf[512]; int n; for(;;){ n = read(0, buf, sizeof buf); if(n == 0) break; if(n < 0){ fprintf(2, "read errorn"); exit(); } if(write(1, buf, n) != n){ fprintf(2, "write errorn"); exit(); } }
  • 19.
    Input redirection char *argv[2]; argv[0]= "cat"; argv[1] = 0; if(fork() == 0) { close(0); open("input.txt", O_RDONLY); exec("cat", argv); }
  • 20.
    Pipe • A smallkernel buffer • Exposed to processes as a pair of file descriptors • One fd for reading, the other for writing • pipe(p) creates a pipe and puts read/write file decriptors in the array p
  • 21.
    Pipe (2) int p[2]; char*argv[2]; argv[0] = "wc"; argv[1] = 0; pipe(p); if(fork() == 0) { close(0); dup(p[0]); close(p[0]); close(p[1]); exec("/bin/wc", argv); } else { write(p[1], "hello worldn", 12); close(p[0]); close(p[1]);
  • 22.
    Filesystem • Implemented asa tree-like structure • Files: uninterpreted byte arrays • Directories: references to other files and directories • Paths are either absolute or relative
  • 23.
    Filesystem (2) • fstat(fd)system call retrieves information about the object that the fd maps to • Fills up the following struct: #define T_DIR 1 // Directory #define T_FILE 2 // File #define T_DEV 3 // Device struct stat { short type; // Type of file int dev; // File system’s disk device uint ino; // Inode number short nlink; // Number of links to file uint size; // Size of file in bytes };
  • 24.
    Today’s Task • WriteC code that replaces steps 3 to 5 from your last task • For simplicity, you can perform steps 1 and 2 manually • C code extension: .c • To compile: gcc test.c -o test.exe • To run: ./test.exe • System calls/methods (possibly) needed: printf (stdio.h), exit() (stdlib.h), execv(), dup(), close(), pipe()
  • 25.
    Reading Chapter 0 from“xv6: a simple, Unix-like teaching operating system”