This commit is contained in:
hustccc 2020-11-01 00:15:28 +09:00
parent be6dd22181
commit 01ec2b3896
27 changed files with 5029 additions and 5 deletions

View File

@ -1,7 +1,7 @@
# Compile xv6 for porting on k210 # Compile xv6 for porting on k210
K=kernel K=kernel
U=user U=xv6-user
T=target T=target
OBJS = \ OBJS = \
@ -94,6 +94,82 @@ run-k210: k210
@sudo chmod 777 $(k210-serialport) @sudo chmod 777 $(k210-serialport)
python3 ./tools/kflash.py -p $(k210-serialport) -b 1500000 -t $(k210) python3 ./tools/kflash.py -p $(k210-serialport) -b 1500000 -t $(k210)
clean:
rm -f $K/*.o $K/*.d $U/initcode: $U/initcode.S
rm -rf $T/* $(CC) $(CFLAGS) -march=rv64g -nostdinc -I. -Ikernel -c $U/initcode.S -o $U/initcode.o
$(LD) $(LDFLAGS) -N -e start -Ttext 0 -o $U/initcode.out $U/initcode.o
$(OBJCOPY) -S -O binary $U/initcode.out $U/initcode
$(OBJDUMP) -S $U/initcode.o > $U/initcode.asm
tags: $(OBJS) _init
@etags *.S *.c
ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/umalloc.o
_%: %.o $(ULIB)
$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^
$(OBJDUMP) -S $@ > $*.asm
$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
$U/usys.S : $U/usys.pl
@perl $U/usys.pl > $U/usys.S
$U/usys.o : $U/usys.S
$(CC) $(CFLAGS) -c -o $U/usys.o $U/usys.S
$U/_forktest: $U/forktest.o $(ULIB)
# forktest has less library code linked in - needs to be small
# in order to be able to max out the proc table.
$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $U/_forktest $U/forktest.o $U/ulib.o $U/usys.o
$(OBJDUMP) -S $U/_forktest > $U/forktest.asm
mkfs/mkfs: mkfs/mkfs.c $K/fs.h $K/param.h
@gcc -Werror -Wall -I. -o mkfs/mkfs mkfs/mkfs.c
# Prevent deletion of intermediate files, e.g. cat.o, after first build, so
# that disk image changes after first build are persistent until clean. More
# details:
# http://www.gnu.org/software/make/manual/html_node/Chained-Rules.html
.PRECIOUS: %.o
UPROGS=\
$U/_cat\
$U/_echo\
$U/_forktest\
$U/_grep\
$U/_init\
$U/_kill\
$U/_ln\
$U/_ls\
$U/_mkdir\
$U/_rm\
$U/_sh\
$U/_stressfs\
$U/_usertests\
$U/_grind\
$U/_wc\
$U/_zombie\
UEXTRA = $U/xargstest.sh
fs.img: mkfs/mkfs README $(UEXTRA) $(UPROGS)
@mkfs/mkfs fs.img README $(UEXTRA) $(UPROGS)
-include kernel/*.d user/*.d
SDCARD ?= /dev/sdb
sdcard: fs.img
@echo "flashing into sd card..."
@sudo dd if=/dev/zero of=$(SDCARD) bs=1M count=50
@sudo dd if=fs.img of=$(SDCARD)
clean:
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
*/*.o */*.d */*.asm */*.sym \
$U/initcode $U/initcode.out $K/kernel fs.img \
mkfs/mkfs .gdbinit \
$U/usys.S \
$(UPROGS)

45
README Normal file
View File

@ -0,0 +1,45 @@
xv6 is a re-implementation of Dennis Ritchie's and Ken Thompson's Unix
Version 6 (v6). xv6 loosely follows the structure and style of v6,
but is implemented for a modern RISC-V multiprocessor using ANSI C.
ACKNOWLEDGMENTS
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
2000)). See also https://pdos.csail.mit.edu/6.828/, which
provides pointers to on-line resources for v6.
The following people have made contributions: Russ Cox (context switching,
locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
Clements.
We are also grateful for the bug reports and patches contributed by
Silas Boyd-Wickizer, Anton Burtsev, Dan Cross, Cody Cutler, Mike CAT,
Tej Chajed, Asami Doi, eyalz800, , Nelson Elhage, Saar Ettinger, Alice
Ferrazzi, Nathaniel Filardo, Peter Froehlich, Yakir Goaron,Shivam
Handa, Bryan Henry, jaichenhengjie, Jim Huang, Alexander Kapshuk,
Anders Kaseorg, kehao95, Wolfgang Keller, Jonathan Kimmitt, Eddie
Kohler, Austin Liew, Imbar Marinescu, Yandong Mao, Matan Shabtay,
Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
Greg Price, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
Shigemitsu, Takahiro, Cam Tenny, tyfkda, Rafael Ubal, Warren Toomey,
Stephen Tu, Pablo Ventura, Xi Wang, Keiichi Watanabe, Nicolas
Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng, and Zou Chang
Wei.
The code in the files that constitute xv6 is
Copyright 2006-2020 Frans Kaashoek, Robert Morris, and Russ Cox.
ERROR REPORTS
Please send errors and suggestions to Frans Kaashoek and Robert Morris
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
operating system for MIT's 6.S081, so we are more interested in
simplifications and clarifications than new features.
BUILDING AND RUNNING XV6
You will need a RISC-V "newlib" tool chain from
https://github.com/riscv/riscv-gnu-toolchain, and qemu compiled for
riscv64-softmmu. Once they are installed, and in your shell
search path, you can run "make qemu".

View File

@ -46,7 +46,7 @@ main(unsigned long hartid, unsigned long dtb_pa)
__sync_synchronize(); __sync_synchronize();
started = 1; started = 1;
scheduler(); // scheduler();
} else } else
{ {

305
mkfs/mkfs.c Normal file
View File

@ -0,0 +1,305 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#define stat xv6_stat // avoid clash with host struct stat
#include "kernel/types.h"
#include "kernel/fs.h"
#include "kernel/stat.h"
#include "kernel/param.h"
#ifndef static_assert
#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
#endif
#define NINODES 200
// Disk layout:
// [ boot block | sb block | log | inode blocks | free bit map | data blocks ]
int nbitmap = FSSIZE/(BSIZE*8) + 1;
int ninodeblocks = NINODES / IPB + 1;
int nlog = LOGSIZE;
int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)
int nblocks; // Number of data blocks
int fsfd;
struct superblock sb;
char zeroes[BSIZE];
uint freeinode = 1;
uint freeblock;
void balloc(int);
void wsect(uint, void*);
void winode(uint, struct dinode*);
void rinode(uint inum, struct dinode *ip);
void rsect(uint sec, void *buf);
uint ialloc(ushort type);
void iappend(uint inum, void *p, int n);
// convert to intel byte order
ushort
xshort(ushort x)
{
ushort y;
uchar *a = (uchar*)&y;
a[0] = x;
a[1] = x >> 8;
return y;
}
uint
xint(uint x)
{
uint y;
uchar *a = (uchar*)&y;
a[0] = x;
a[1] = x >> 8;
a[2] = x >> 16;
a[3] = x >> 24;
return y;
}
int
main(int argc, char *argv[])
{
int i, cc, fd;
uint rootino, inum, off;
struct dirent de;
char buf[BSIZE];
struct dinode din;
static_assert(sizeof(int) == 4, "Integers must be 4 bytes!");
if(argc < 2){
fprintf(stderr, "Usage: mkfs fs.img files...\n");
exit(1);
}
assert((BSIZE % sizeof(struct dinode)) == 0);
assert((BSIZE % sizeof(struct dirent)) == 0);
fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
if(fsfd < 0){
perror(argv[1]);
exit(1);
}
// 1 fs block = 1 disk sector
nmeta = 2 + nlog + ninodeblocks + nbitmap;
nblocks = FSSIZE - nmeta;
sb.magic = FSMAGIC;
sb.size = xint(FSSIZE);
sb.nblocks = xint(nblocks);
sb.ninodes = xint(NINODES);
sb.nlog = xint(nlog);
sb.logstart = xint(2);
sb.inodestart = xint(2+nlog);
sb.bmapstart = xint(2+nlog+ninodeblocks);
printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n",
nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);
freeblock = nmeta; // the first free block that we can allocate
for(i = 0; i < FSSIZE; i++)
wsect(i, zeroes);
memset(buf, 0, sizeof(buf));
memmove(buf, &sb, sizeof(sb));
wsect(1, buf);
rootino = ialloc(T_DIR);
assert(rootino == ROOTINO);
bzero(&de, sizeof(de));
de.inum = xshort(rootino);
strcpy(de.name, ".");
iappend(rootino, &de, sizeof(de));
bzero(&de, sizeof(de));
de.inum = xshort(rootino);
strcpy(de.name, "..");
iappend(rootino, &de, sizeof(de));
for(i = 2; i < argc; i++){
// get rid of "user/"
char *shortname;
if(strncmp(argv[i], "xv6-user/", 9) == 0)
shortname = argv[i] + 9;
else
shortname = argv[i];
assert(index(shortname, '/') == 0);
if((fd = open(argv[i], 0)) < 0){
perror(argv[i]);
exit(1);
}
// Skip leading _ in name when writing to file system.
// The binaries are named _rm, _cat, etc. to keep the
// build operating system from trying to execute them
// in place of system binaries like rm and cat.
if(shortname[0] == '_')
shortname += 1;
inum = ialloc(T_FILE);
bzero(&de, sizeof(de));
de.inum = xshort(inum);
strncpy(de.name, shortname, DIRSIZ);
iappend(rootino, &de, sizeof(de));
while((cc = read(fd, buf, sizeof(buf))) > 0)
iappend(inum, buf, cc);
close(fd);
}
// fix size of root inode dir
rinode(rootino, &din);
off = xint(din.size);
off = ((off/BSIZE) + 1) * BSIZE;
din.size = xint(off);
winode(rootino, &din);
balloc(freeblock);
exit(0);
}
void
wsect(uint sec, void *buf)
{
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){
perror("lseek");
exit(1);
}
if(write(fsfd, buf, BSIZE) != BSIZE){
perror("write");
exit(1);
}
}
void
winode(uint inum, struct dinode *ip)
{
char buf[BSIZE];
uint bn;
struct dinode *dip;
bn = IBLOCK(inum, sb);
rsect(bn, buf);
dip = ((struct dinode*)buf) + (inum % IPB);
*dip = *ip;
wsect(bn, buf);
}
void
rinode(uint inum, struct dinode *ip)
{
char buf[BSIZE];
uint bn;
struct dinode *dip;
bn = IBLOCK(inum, sb);
rsect(bn, buf);
dip = ((struct dinode*)buf) + (inum % IPB);
*ip = *dip;
}
void
rsect(uint sec, void *buf)
{
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){
perror("lseek");
exit(1);
}
if(read(fsfd, buf, BSIZE) != BSIZE){
perror("read");
exit(1);
}
}
uint
ialloc(ushort type)
{
uint inum = freeinode++;
struct dinode din;
bzero(&din, sizeof(din));
din.type = xshort(type);
din.nlink = xshort(1);
din.size = xint(0);
winode(inum, &din);
return inum;
}
void
balloc(int used)
{
uchar buf[BSIZE];
int i;
printf("balloc: first %d blocks have been allocated\n", used);
assert(used < BSIZE*8);
bzero(buf, BSIZE);
for(i = 0; i < used; i++){
buf[i/8] = buf[i/8] | (0x1 << (i%8));
}
printf("balloc: write bitmap block at sector %d\n", sb.bmapstart);
wsect(sb.bmapstart, buf);
}
#define min(a, b) ((a) < (b) ? (a) : (b))
void
iappend(uint inum, void *xp, int n)
{
char *p = (char*)xp;
uint fbn, off, n1;
struct dinode din;
char buf[BSIZE];
uint indirect[NINDIRECT];
uint x;
rinode(inum, &din);
off = xint(din.size);
// printf("append inum %d at off %d sz %d\n", inum, off, n);
while(n > 0){
fbn = off / BSIZE;
assert(fbn < MAXFILE);
if(fbn < NDIRECT){
if(xint(din.addrs[fbn]) == 0){
din.addrs[fbn] = xint(freeblock++);
}
x = xint(din.addrs[fbn]);
} else {
if(xint(din.addrs[NDIRECT]) == 0){
din.addrs[NDIRECT] = xint(freeblock++);
}
rsect(xint(din.addrs[NDIRECT]), (char*)indirect);
if(indirect[fbn - NDIRECT] == 0){
indirect[fbn - NDIRECT] = xint(freeblock++);
wsect(xint(din.addrs[NDIRECT]), (char*)indirect);
}
x = xint(indirect[fbn-NDIRECT]);
}
n1 = min(n, (fbn + 1) * BSIZE - off);
rsect(x, buf);
bcopy(p, buf + off - (fbn * BSIZE), n1);
wsect(x, buf);
n -= n1;
off += n1;
p += n1;
}
din.size = xint(off);
winode(inum, &din);
}

43
xv6-user/cat.c Normal file
View File

@ -0,0 +1,43 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
char buf[512];
void
cat(int fd)
{
int n;
while((n = read(fd, buf, sizeof(buf))) > 0) {
if (write(1, buf, n) != n) {
fprintf(2, "cat: write error\n");
exit(1);
}
}
if(n < 0){
fprintf(2, "cat: read error\n");
exit(1);
}
}
int
main(int argc, char *argv[])
{
int fd, i;
if(argc <= 1){
cat(0);
exit(0);
}
for(i = 1; i < argc; i++){
if((fd = open(argv[i], 0)) < 0){
fprintf(2, "cat: cannot open %s\n", argv[i]);
exit(1);
}
cat(fd);
close(fd);
}
exit(0);
}

19
xv6-user/echo.c Normal file
View File

@ -0,0 +1,19 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
int
main(int argc, char *argv[])
{
int i;
for(i = 1; i < argc; i++){
write(1, argv[i], strlen(argv[i]));
if(i + 1 < argc){
write(1, " ", 1);
} else {
write(1, "\n", 1);
}
}
exit(0);
}

56
xv6-user/forktest.c Normal file
View File

@ -0,0 +1,56 @@
// Test that fork fails gracefully.
// Tiny executable so that the limit can be filling the proc table.
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
#define N 1000
void
print(const char *s)
{
write(1, s, strlen(s));
}
void
forktest(void)
{
int n, pid;
print("fork test\n");
for(n=0; n<N; n++){
pid = fork();
if(pid < 0)
break;
if(pid == 0)
exit(0);
}
if(n == N){
print("fork claimed to work N times!\n");
exit(1);
}
for(; n > 0; n--){
if(wait(0) < 0){
print("wait stopped early\n");
exit(1);
}
}
if(wait(0) != -1){
print("wait got too many\n");
exit(1);
}
print("fork test OK\n");
}
int
main(void)
{
forktest();
exit(0);
}

105
xv6-user/grep.c Normal file
View File

@ -0,0 +1,105 @@
// Simple grep. Only supports ^ . * $ operators.
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
char buf[1024];
int match(char*, char*);
void
grep(char *pattern, int fd)
{
int n, m;
char *p, *q;
m = 0;
while((n = read(fd, buf+m, sizeof(buf)-m-1)) > 0){
m += n;
buf[m] = '\0';
p = buf;
while((q = strchr(p, '\n')) != 0){
*q = 0;
if(match(pattern, p)){
*q = '\n';
write(1, p, q+1 - p);
}
p = q+1;
}
if(m > 0){
m -= p - buf;
memmove(buf, p, m);
}
}
}
int
main(int argc, char *argv[])
{
int fd, i;
char *pattern;
if(argc <= 1){
fprintf(2, "usage: grep pattern [file ...]\n");
exit(1);
}
pattern = argv[1];
if(argc <= 2){
grep(pattern, 0);
exit(0);
}
for(i = 2; i < argc; i++){
if((fd = open(argv[i], 0)) < 0){
printf("grep: cannot open %s\n", argv[i]);
exit(1);
}
grep(pattern, fd);
close(fd);
}
exit(0);
}
// Regexp matcher from Kernighan & Pike,
// The Practice of Programming, Chapter 9.
int matchhere(char*, char*);
int matchstar(int, char*, char*);
int
match(char *re, char *text)
{
if(re[0] == '^')
return matchhere(re+1, text);
do{ // must look at empty string
if(matchhere(re, text))
return 1;
}while(*text++ != '\0');
return 0;
}
// matchhere: search for re at beginning of text
int matchhere(char *re, char *text)
{
if(re[0] == '\0')
return 1;
if(re[1] == '*')
return matchstar(re[0], re+2, text);
if(re[0] == '$' && re[1] == '\0')
return *text == '\0';
if(*text!='\0' && (re[0]=='.' || re[0]==*text))
return matchhere(re+1, text+1);
return 0;
}
// matchstar: search for c*re at beginning of text
int matchstar(int c, char *re, char *text)
{
do{ // a * matches zero or more instances
if(matchhere(re, text))
return 1;
}while(*text!='\0' && (*text++==c || c=='.'));
return 0;
}

349
xv6-user/grind.c Normal file
View File

@ -0,0 +1,349 @@
//
// run random system calls in parallel forever.
//
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
#include "kernel/fs.h"
#include "kernel/fcntl.h"
#include "kernel/syscall.h"
#include "kernel/memlayout.h"
#include "kernel/riscv.h"
// from FreeBSD.
int
do_rand(unsigned long *ctx)
{
/*
* Compute x = (7^5 * x) mod (2^31 - 1)
* without overflowing 31 bits:
* (2^31 - 1) = 127773 * (7^5) + 2836
* From "Random number generators: good ones are hard to find",
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
* October 1988, p. 1195.
*/
long hi, lo, x;
/* Transform to [1, 0x7ffffffe] range. */
x = (*ctx % 0x7ffffffe) + 1;
hi = x / 127773;
lo = x % 127773;
x = 16807 * lo - 2836 * hi;
if (x < 0)
x += 0x7fffffff;
/* Transform to [0, 0x7ffffffd] range. */
x--;
*ctx = x;
return (x);
}
unsigned long rand_next = 1;
int
rand(void)
{
return (do_rand(&rand_next));
}
void
go(int which_child)
{
int fd = -1;
static char buf[999];
char *break0 = sbrk(0);
uint64 iters = 0;
mkdir("grindir");
if(chdir("grindir") != 0){
printf("chdir grindir failed\n");
exit(1);
}
chdir("/");
while(1){
iters++;
if((iters % 500) == 0)
write(1, which_child?"B":"A", 1);
int what = rand() % 23;
if(what == 1){
close(open("grindir/../a", O_CREATE|O_RDWR));
} else if(what == 2){
close(open("grindir/../grindir/../b", O_CREATE|O_RDWR));
} else if(what == 3){
unlink("grindir/../a");
} else if(what == 4){
if(chdir("grindir") != 0){
printf("chdir grindir failed\n");
exit(1);
}
unlink("../b");
chdir("/");
} else if(what == 5){
close(fd);
fd = open("/grindir/../a", O_CREATE|O_RDWR);
} else if(what == 6){
close(fd);
fd = open("/./grindir/./../b", O_CREATE|O_RDWR);
} else if(what == 7){
write(fd, buf, sizeof(buf));
} else if(what == 8){
read(fd, buf, sizeof(buf));
} else if(what == 9){
mkdir("grindir/../a");
close(open("a/../a/./a", O_CREATE|O_RDWR));
unlink("a/a");
} else if(what == 10){
mkdir("/../b");
close(open("grindir/../b/b", O_CREATE|O_RDWR));
unlink("b/b");
} else if(what == 11){
unlink("b");
link("../grindir/./../a", "../b");
} else if(what == 12){
unlink("../grindir/../a");
link(".././b", "/grindir/../a");
} else if(what == 13){
int pid = fork();
if(pid == 0){
exit(0);
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if(what == 14){
int pid = fork();
if(pid == 0){
fork();
fork();
exit(0);
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if(what == 15){
sbrk(6011);
} else if(what == 16){
if(sbrk(0) > break0)
sbrk(-(sbrk(0) - break0));
} else if(what == 17){
int pid = fork();
if(pid == 0){
close(open("a", O_CREATE|O_RDWR));
exit(0);
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
if(chdir("../grindir/..") != 0){
printf("chdir failed\n");
exit(1);
}
kill(pid);
wait(0);
} else if(what == 18){
int pid = fork();
if(pid == 0){
kill(getpid());
exit(0);
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if(what == 19){
int fds[2];
if(pipe(fds) < 0){
printf("grind: pipe failed\n");
exit(1);
}
int pid = fork();
if(pid == 0){
fork();
fork();
if(write(fds[1], "x", 1) != 1)
printf("grind: pipe write failed\n");
char c;
if(read(fds[0], &c, 1) != 1)
printf("grind: pipe read failed\n");
exit(0);
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
close(fds[0]);
close(fds[1]);
wait(0);
} else if(what == 20){
int pid = fork();
if(pid == 0){
unlink("a");
mkdir("a");
chdir("a");
unlink("../a");
fd = open("x", O_CREATE|O_RDWR);
unlink("x");
exit(0);
} else if(pid < 0){
printf("fork failed\n");
exit(1);
}
wait(0);
} else if(what == 21){
unlink("c");
// should always succeed. check that there are free i-nodes,
// file descriptors, blocks.
int fd1 = open("c", O_CREATE|O_RDWR);
if(fd1 < 0){
printf("create c failed\n");
exit(1);
}
if(write(fd1, "x", 1) != 1){
printf("write c failed\n");
exit(1);
}
struct stat st;
if(fstat(fd1, &st) != 0){
printf("fstat failed\n");
exit(1);
}
if(st.size != 1){
printf("fstat reports wrong size %d\n", (int)st.size);
exit(1);
}
if(st.ino > 200){
printf("fstat reports crazy i-number %d\n", st.ino);
exit(1);
}
close(fd1);
unlink("c");
} else if(what == 22){
// echo hi | cat
int aa[2], bb[2];
if(pipe(aa) < 0){
fprintf(2, "pipe failed\n");
exit(1);
}
if(pipe(bb) < 0){
fprintf(2, "pipe failed\n");
exit(1);
}
int pid1 = fork();
if(pid1 == 0){
close(bb[0]);
close(bb[1]);
close(aa[0]);
close(1);
if(dup(aa[1]) != 1){
fprintf(2, "dup failed\n");
exit(1);
}
close(aa[1]);
char *args[3] = { "echo", "hi", 0 };
exec("grindir/../echo", args);
fprintf(2, "echo: not found\n");
exit(2);
} else if(pid1 < 0){
fprintf(2, "fork failed\n");
exit(3);
}
int pid2 = fork();
if(pid2 == 0){
close(aa[1]);
close(bb[0]);
close(0);
if(dup(aa[0]) != 0){
fprintf(2, "dup failed\n");
exit(4);
}
close(aa[0]);
close(1);
if(dup(bb[1]) != 1){
fprintf(2, "dup failed\n");
exit(5);
}
close(bb[1]);
char *args[2] = { "cat", 0 };
exec("/cat", args);
fprintf(2, "cat: not found\n");
exit(6);
} else if(pid2 < 0){
fprintf(2, "fork failed\n");
exit(7);
}
close(aa[0]);
close(aa[1]);
close(bb[1]);
char buf[3] = { 0, 0, 0 };
read(bb[0], buf+0, 1);
read(bb[0], buf+1, 1);
close(bb[0]);
int st1, st2;
wait(&st1);
wait(&st2);
if(st1 != 0 || st2 != 0 || strcmp(buf, "hi") != 0){
printf("exec pipeline failed %d %d \"%s\"\n", st1, st2, buf);
exit(1);
}
}
}
}
void
iter()
{
unlink("a");
unlink("b");
int pid1 = fork();
if(pid1 < 0){
printf("grind: fork failed\n");
exit(1);
}
if(pid1 == 0){
rand_next = 31;
go(0);
exit(0);
}
int pid2 = fork();
if(pid2 < 0){
printf("grind: fork failed\n");
exit(1);
}
if(pid2 == 0){
rand_next = 7177;
go(1);
exit(0);
}
int st1 = -1;
wait(&st1);
if(st1 != 0){
kill(pid1);
kill(pid2);
}
int st2 = -1;
wait(&st2);
exit(0);
}
int
main()
{
while(1){
int pid = fork();
if(pid == 0){
iter();
exit(0);
}
if(pid > 0){
wait(0);
}
sleep(20);
}
}

54
xv6-user/init.c Normal file
View File

@ -0,0 +1,54 @@
// init: The initial user-level program
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/spinlock.h"
#include "kernel/sleeplock.h"
#include "kernel/fs.h"
#include "kernel/file.h"
#include "xv6-user/user.h"
#include "kernel/fcntl.h"
char *argv[] = { "sh", 0 };
int
main(void)
{
int pid, wpid;
if(open("console", O_RDWR) < 0){
mknod("console", CONSOLE, 0);
open("console", O_RDWR);
}
dup(0); // stdout
dup(0); // stderr
for(;;){
printf("init: starting sh\n");
pid = fork();
if(pid < 0){
printf("init: fork failed\n");
exit(1);
}
if(pid == 0){
exec("sh", argv);
printf("init: exec sh failed\n");
exit(1);
}
for(;;){
// this call to wait() returns if the shell exits,
// or if a parentless process exits.
wpid = wait((int *) 0);
if(wpid == pid){
// the shell exited; restart it.
break;
} else if(wpid < 0){
printf("init: wait returned an error\n");
exit(1);
} else {
// it was a parentless process; do nothing.
}
}
}
}

28
xv6-user/initcode.S Normal file
View File

@ -0,0 +1,28 @@
# Initial process that execs /init.
# This code runs in user space.
#include "syscall.h"
# exec(init, argv)
.globl start
start:
la a0, init
la a1, argv
li a7, SYS_exec
ecall
# for(;;) exit();
exit:
li a7, SYS_exit
ecall
jal exit
# char init[] = "/init\0";
init:
.string "/init\0"
# char *argv[] = { init, 0 };
.p2align 2
argv:
.long init
.long 0

17
xv6-user/kill.c Normal file
View File

@ -0,0 +1,17 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
int
main(int argc, char **argv)
{
int i;
if(argc < 2){
fprintf(2, "usage: kill pid...\n");
exit(1);
}
for(i=1; i<argc; i++)
kill(atoi(argv[i]));
exit(0);
}

15
xv6-user/ln.c Normal file
View File

@ -0,0 +1,15 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
int
main(int argc, char *argv[])
{
if(argc != 3){
fprintf(2, "Usage: ln old new\n");
exit(1);
}
if(link(argv[1], argv[2]) < 0)
fprintf(2, "link %s %s: failed\n", argv[1], argv[2]);
exit(0);
}

85
xv6-user/ls.c Normal file
View File

@ -0,0 +1,85 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
#include "kernel/fs.h"
char*
fmtname(char *path)
{
static char buf[DIRSIZ+1];
char *p;
// Find first character after last slash.
for(p=path+strlen(path); p >= path && *p != '/'; p--)
;
p++;
// Return blank-padded name.
if(strlen(p) >= DIRSIZ)
return p;
memmove(buf, p, strlen(p));
memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
return buf;
}
void
ls(char *path)
{
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if((fd = open(path, 0)) < 0){
fprintf(2, "ls: cannot open %s\n", path);
return;
}
if(fstat(fd, &st) < 0){
fprintf(2, "ls: cannot stat %s\n", path);
close(fd);
return;
}
switch(st.type){
case T_FILE:
printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);
break;
case T_DIR:
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
printf("ls: path too long\n");
break;
}
strcpy(buf, path);
p = buf+strlen(buf);
*p++ = '/';
while(read(fd, &de, sizeof(de)) == sizeof(de)){
if(de.inum == 0)
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if(stat(buf, &st) < 0){
printf("ls: cannot stat %s\n", buf);
continue;
}
printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);
}
break;
}
close(fd);
}
int
main(int argc, char *argv[])
{
int i;
if(argc < 2){
ls(".");
exit(0);
}
for(i=1; i<argc; i++)
ls(argv[i]);
exit(0);
}

23
xv6-user/mkdir.c Normal file
View File

@ -0,0 +1,23 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
int
main(int argc, char *argv[])
{
int i;
if(argc < 2){
fprintf(2, "Usage: mkdir files...\n");
exit(1);
}
for(i = 1; i < argc; i++){
if(mkdir(argv[i]) < 0){
fprintf(2, "mkdir: %s failed to create\n", argv[i]);
break;
}
}
exit(0);
}

113
xv6-user/printf.c Normal file
View File

@ -0,0 +1,113 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
#include <stdarg.h>
static char digits[] = "0123456789ABCDEF";
static void
putc(int fd, char c)
{
write(fd, &c, 1);
}
static void
printint(int fd, int xx, int base, int sgn)
{
char buf[16];
int i, neg;
uint x;
neg = 0;
if(sgn && xx < 0){
neg = 1;
x = -xx;
} else {
x = xx;
}
i = 0;
do{
buf[i++] = digits[x % base];
}while((x /= base) != 0);
if(neg)
buf[i++] = '-';
while(--i >= 0)
putc(fd, buf[i]);
}
static void
printptr(int fd, uint64 x) {
int i;
putc(fd, '0');
putc(fd, 'x');
for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
putc(fd, digits[x >> (sizeof(uint64) * 8 - 4)]);
}
// Print to the given fd. Only understands %d, %x, %p, %s.
void
vprintf(int fd, const char *fmt, va_list ap)
{
char *s;
int c, i, state;
state = 0;
for(i = 0; fmt[i]; i++){
c = fmt[i] & 0xff;
if(state == 0){
if(c == '%'){
state = '%';
} else {
putc(fd, c);
}
} else if(state == '%'){
if(c == 'd'){
printint(fd, va_arg(ap, int), 10, 1);
} else if(c == 'l') {
printint(fd, va_arg(ap, uint64), 10, 0);
} else if(c == 'x') {
printint(fd, va_arg(ap, int), 16, 0);
} else if(c == 'p') {
printptr(fd, va_arg(ap, uint64));
} else if(c == 's'){
s = va_arg(ap, char*);
if(s == 0)
s = "(null)";
while(*s != 0){
putc(fd, *s);
s++;
}
} else if(c == 'c'){
putc(fd, va_arg(ap, uint));
} else if(c == '%'){
putc(fd, c);
} else {
// Unknown % sequence. Print it to draw attention.
putc(fd, '%');
putc(fd, c);
}
state = 0;
}
}
}
void
fprintf(int fd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fd, fmt, ap);
}
void
printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(1, fmt, ap);
}

23
xv6-user/rm.c Normal file
View File

@ -0,0 +1,23 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
int
main(int argc, char *argv[])
{
int i;
if(argc < 2){
fprintf(2, "Usage: rm files...\n");
exit(1);
}
for(i = 1; i < argc; i++){
if(unlink(argv[i]) < 0){
fprintf(2, "rm: %s failed to delete\n", argv[i]);
break;
}
}
exit(0);
}

493
xv6-user/sh.c Normal file
View File

@ -0,0 +1,493 @@
// Shell.
#include "kernel/types.h"
#include "xv6-user/user.h"
#include "kernel/fcntl.h"
// Parsed command representation
#define EXEC 1
#define REDIR 2
#define PIPE 3
#define LIST 4
#define BACK 5
#define MAXARGS 10
struct cmd {
int type;
};
struct execcmd {
int type;
char *argv[MAXARGS];
char *eargv[MAXARGS];
};
struct redircmd {
int type;
struct cmd *cmd;
char *file;
char *efile;
int mode;
int fd;
};
struct pipecmd {
int type;
struct cmd *left;
struct cmd *right;
};
struct listcmd {
int type;
struct cmd *left;
struct cmd *right;
};
struct backcmd {
int type;
struct cmd *cmd;
};
int fork1(void); // Fork but panics on failure.
void panic(char*);
struct cmd *parsecmd(char*);
// Execute cmd. Never returns.
void
runcmd(struct cmd *cmd)
{
int p[2];
struct backcmd *bcmd;
struct execcmd *ecmd;
struct listcmd *lcmd;
struct pipecmd *pcmd;
struct redircmd *rcmd;
if(cmd == 0)
exit(1);
switch(cmd->type){
default:
panic("runcmd");
case EXEC:
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[0] == 0)
exit(1);
exec(ecmd->argv[0], ecmd->argv);
fprintf(2, "exec %s failed\n", ecmd->argv[0]);
break;
case REDIR:
rcmd = (struct redircmd*)cmd;
close(rcmd->fd);
if(open(rcmd->file, rcmd->mode) < 0){
fprintf(2, "open %s failed\n", rcmd->file);
exit(1);
}
runcmd(rcmd->cmd);
break;
case LIST:
lcmd = (struct listcmd*)cmd;
if(fork1() == 0)
runcmd(lcmd->left);
wait(0);
runcmd(lcmd->right);
break;
case PIPE:
pcmd = (struct pipecmd*)cmd;
if(pipe(p) < 0)
panic("pipe");
if(fork1() == 0){
close(1);
dup(p[1]);
close(p[0]);
close(p[1]);
runcmd(pcmd->left);
}
if(fork1() == 0){
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
runcmd(pcmd->right);
}
close(p[0]);
close(p[1]);
wait(0);
wait(0);
break;
case BACK:
bcmd = (struct backcmd*)cmd;
if(fork1() == 0)
runcmd(bcmd->cmd);
break;
}
exit(0);
}
int
getcmd(char *buf, int nbuf)
{
fprintf(2, "$ ");
memset(buf, 0, nbuf);
gets(buf, nbuf);
if(buf[0] == 0) // EOF
return -1;
return 0;
}
int
main(void)
{
static char buf[100];
int fd;
// Ensure that three file descriptors are open.
while((fd = open("console", O_RDWR)) >= 0){
if(fd >= 3){
close(fd);
break;
}
}
// Read and run input commands.
while(getcmd(buf, sizeof(buf)) >= 0){
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
// Chdir must be called by the parent, not the child.
buf[strlen(buf)-1] = 0; // chop \n
if(chdir(buf+3) < 0)
fprintf(2, "cannot cd %s\n", buf+3);
continue;
}
if(fork1() == 0)
runcmd(parsecmd(buf));
wait(0);
}
exit(0);
}
void
panic(char *s)
{
fprintf(2, "%s\n", s);
exit(1);
}
int
fork1(void)
{
int pid;
pid = fork();
if(pid == -1)
panic("fork");
return pid;
}
//PAGEBREAK!
// Constructors
struct cmd*
execcmd(void)
{
struct execcmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = EXEC;
return (struct cmd*)cmd;
}
struct cmd*
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
{
struct redircmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = REDIR;
cmd->cmd = subcmd;
cmd->file = file;
cmd->efile = efile;
cmd->mode = mode;
cmd->fd = fd;
return (struct cmd*)cmd;
}
struct cmd*
pipecmd(struct cmd *left, struct cmd *right)
{
struct pipecmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = PIPE;
cmd->left = left;
cmd->right = right;
return (struct cmd*)cmd;
}
struct cmd*
listcmd(struct cmd *left, struct cmd *right)
{
struct listcmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = LIST;
cmd->left = left;
cmd->right = right;
return (struct cmd*)cmd;
}
struct cmd*
backcmd(struct cmd *subcmd)
{
struct backcmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = BACK;
cmd->cmd = subcmd;
return (struct cmd*)cmd;
}
//PAGEBREAK!
// Parsing
char whitespace[] = " \t\r\n\v";
char symbols[] = "<|>&;()";
int
gettoken(char **ps, char *es, char **q, char **eq)
{
char *s;
int ret;
s = *ps;
while(s < es && strchr(whitespace, *s))
s++;
if(q)
*q = s;
ret = *s;
switch(*s){
case 0:
break;
case '|':
case '(':
case ')':
case ';':
case '&':
case '<':
s++;
break;
case '>':
s++;
if(*s == '>'){
ret = '+';
s++;
}
break;
default:
ret = 'a';
while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
s++;
break;
}
if(eq)
*eq = s;
while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return ret;
}
int
peek(char **ps, char *es, char *toks)
{
char *s;
s = *ps;
while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return *s && strchr(toks, *s);
}
struct cmd *parseline(char**, char*);
struct cmd *parsepipe(char**, char*);
struct cmd *parseexec(char**, char*);
struct cmd *nulterminate(struct cmd*);
struct cmd*
parsecmd(char *s)
{
char *es;
struct cmd *cmd;
es = s + strlen(s);
cmd = parseline(&s, es);
peek(&s, es, "");
if(s != es){
fprintf(2, "leftovers: %s\n", s);
panic("syntax");
}
nulterminate(cmd);
return cmd;
}
struct cmd*
parseline(char **ps, char *es)
{
struct cmd *cmd;
cmd = parsepipe(ps, es);
while(peek(ps, es, "&")){
gettoken(ps, es, 0, 0);
cmd = backcmd(cmd);
}
if(peek(ps, es, ";")){
gettoken(ps, es, 0, 0);
cmd = listcmd(cmd, parseline(ps, es));
}
return cmd;
}
struct cmd*
parsepipe(char **ps, char *es)
{
struct cmd *cmd;
cmd = parseexec(ps, es);
if(peek(ps, es, "|")){
gettoken(ps, es, 0, 0);
cmd = pipecmd(cmd, parsepipe(ps, es));
}
return cmd;
}
struct cmd*
parseredirs(struct cmd *cmd, char **ps, char *es)
{
int tok;
char *q, *eq;
while(peek(ps, es, "<>")){
tok = gettoken(ps, es, 0, 0);
if(gettoken(ps, es, &q, &eq) != 'a')
panic("missing file for redirection");
switch(tok){
case '<':
cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
break;
case '>':
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
break;
case '+': // >>
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
break;
}
}
return cmd;
}
struct cmd*
parseblock(char **ps, char *es)
{
struct cmd *cmd;
if(!peek(ps, es, "("))
panic("parseblock");
gettoken(ps, es, 0, 0);
cmd = parseline(ps, es);
if(!peek(ps, es, ")"))
panic("syntax - missing )");
gettoken(ps, es, 0, 0);
cmd = parseredirs(cmd, ps, es);
return cmd;
}
struct cmd*
parseexec(char **ps, char *es)
{
char *q, *eq;
int tok, argc;
struct execcmd *cmd;
struct cmd *ret;
if(peek(ps, es, "("))
return parseblock(ps, es);
ret = execcmd();
cmd = (struct execcmd*)ret;
argc = 0;
ret = parseredirs(ret, ps, es);
while(!peek(ps, es, "|)&;")){
if((tok=gettoken(ps, es, &q, &eq)) == 0)
break;
if(tok != 'a')
panic("syntax");
cmd->argv[argc] = q;
cmd->eargv[argc] = eq;
argc++;
if(argc >= MAXARGS)
panic("too many args");
ret = parseredirs(ret, ps, es);
}
cmd->argv[argc] = 0;
cmd->eargv[argc] = 0;
return ret;
}
// NUL-terminate all the counted strings.
struct cmd*
nulterminate(struct cmd *cmd)
{
int i;
struct backcmd *bcmd;
struct execcmd *ecmd;
struct listcmd *lcmd;
struct pipecmd *pcmd;
struct redircmd *rcmd;
if(cmd == 0)
return 0;
switch(cmd->type){
case EXEC:
ecmd = (struct execcmd*)cmd;
for(i=0; ecmd->argv[i]; i++)
*ecmd->eargv[i] = 0;
break;
case REDIR:
rcmd = (struct redircmd*)cmd;
nulterminate(rcmd->cmd);
*rcmd->efile = 0;
break;
case PIPE:
pcmd = (struct pipecmd*)cmd;
nulterminate(pcmd->left);
nulterminate(pcmd->right);
break;
case LIST:
lcmd = (struct listcmd*)cmd;
nulterminate(lcmd->left);
nulterminate(lcmd->right);
break;
case BACK:
bcmd = (struct backcmd*)cmd;
nulterminate(bcmd->cmd);
break;
}
return cmd;
}

49
xv6-user/stressfs.c Normal file
View File

@ -0,0 +1,49 @@
// Demonstrate that moving the "acquire" in iderw after the loop that
// appends to the idequeue results in a race.
// For this to work, you should also add a spin within iderw's
// idequeue traversal loop. Adding the following demonstrated a panic
// after about 5 runs of stressfs in QEMU on a 2.1GHz CPU:
// for (i = 0; i < 40000; i++)
// asm volatile("");
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
#include "kernel/fs.h"
#include "kernel/fcntl.h"
int
main(int argc, char *argv[])
{
int fd, i;
char path[] = "stressfs0";
char data[512];
printf("stressfs starting\n");
memset(data, 'a', sizeof(data));
for(i = 0; i < 4; i++)
if(fork() > 0)
break;
printf("write %d\n", i);
path[8] += i;
fd = open(path, O_CREATE | O_RDWR);
for(i = 0; i < 20; i++)
// printf(fd, "%d\n", i);
write(fd, data, sizeof(data));
close(fd);
printf("read\n");
fd = open(path, O_RDONLY);
for (i = 0; i < 20; i++)
read(fd, data, sizeof(data));
close(fd);
wait(0);
exit(0);
}

136
xv6-user/ulib.c Normal file
View File

@ -0,0 +1,136 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "xv6-user/user.h"
char*
strcpy(char *s, const char *t)
{
char *os;
os = s;
while((*s++ = *t++) != 0)
;
return os;
}
int
strcmp(const char *p, const char *q)
{
while(*p && *p == *q)
p++, q++;
return (uchar)*p - (uchar)*q;
}
uint
strlen(const char *s)
{
int n;
for(n = 0; s[n]; n++)
;
return n;
}
void*
memset(void *dst, int c, uint n)
{
char *cdst = (char *) dst;
int i;
for(i = 0; i < n; i++){
cdst[i] = c;
}
return dst;
}
char*
strchr(const char *s, char c)
{
for(; *s; s++)
if(*s == c)
return (char*)s;
return 0;
}
char*
gets(char *buf, int max)
{
int i, cc;
char c;
for(i=0; i+1 < max; ){
cc = read(0, &c, 1);
if(cc < 1)
break;
buf[i++] = c;
if(c == '\n' || c == '\r')
break;
}
buf[i] = '\0';
return buf;
}
int
stat(const char *n, struct stat *st)
{
int fd;
int r;
fd = open(n, O_RDONLY);
if(fd < 0)
return -1;
r = fstat(fd, st);
close(fd);
return r;
}
int
atoi(const char *s)
{
int n;
n = 0;
while('0' <= *s && *s <= '9')
n = n*10 + *s++ - '0';
return n;
}
void*
memmove(void *vdst, const void *vsrc, int n)
{
char *dst;
const char *src;
dst = vdst;
src = vsrc;
if (src > dst) {
while(n-- > 0)
*dst++ = *src++;
} else {
dst += n;
src += n;
while(n-- > 0)
*--dst = *--src;
}
return vdst;
}
int
memcmp(const void *s1, const void *s2, uint n)
{
const char *p1 = s1, *p2 = s2;
while (n-- > 0) {
if (*p1 != *p2) {
return *p1 - *p2;
}
p1++;
p2++;
}
return 0;
}
void *
memcpy(void *dst, const void *src, uint n)
{
return memmove(dst, src, n);
}

90
xv6-user/umalloc.c Normal file
View File

@ -0,0 +1,90 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
#include "kernel/param.h"
// Memory allocator by Kernighan and Ritchie,
// The C programming Language, 2nd ed. Section 8.7.
typedef long Align;
union header {
struct {
union header *ptr;
uint size;
} s;
Align x;
};
typedef union header Header;
static Header base;
static Header *freep;
void
free(void *ap)
{
Header *bp, *p;
bp = (Header*)ap - 1;
for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
break;
if(bp + bp->s.size == p->s.ptr){
bp->s.size += p->s.ptr->s.size;
bp->s.ptr = p->s.ptr->s.ptr;
} else
bp->s.ptr = p->s.ptr;
if(p + p->s.size == bp){
p->s.size += bp->s.size;
p->s.ptr = bp->s.ptr;
} else
p->s.ptr = bp;
freep = p;
}
static Header*
morecore(uint nu)
{
char *p;
Header *hp;
if(nu < 4096)
nu = 4096;
p = sbrk(nu * sizeof(Header));
if(p == (char*)-1)
return 0;
hp = (Header*)p;
hp->s.size = nu;
free((void*)(hp + 1));
return freep;
}
void*
malloc(uint nbytes)
{
Header *p, *prevp;
uint nunits;
nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
if((prevp = freep) == 0){
base.s.ptr = freep = prevp = &base;
base.s.size = 0;
}
for(p = prevp->s.ptr; ; prevp = p, p = p->s.ptr){
if(p->s.size >= nunits){
if(p->s.size == nunits)
prevp->s.ptr = p->s.ptr;
else {
p->s.size -= nunits;
p += p->s.size;
p->s.size = nunits;
}
freep = prevp;
return (void*)(p + 1);
}
if(p == freep)
if((p = morecore(nunits)) == 0)
return 0;
}
}

42
xv6-user/user.h Normal file
View File

@ -0,0 +1,42 @@
struct stat;
struct rtcdate;
// system calls
int fork(void);
int exit(int) __attribute__((noreturn));
int wait(int*);
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
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 fprintf(int, const char*, ...);
void printf(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*);
int memcmp(const void *, const void *, uint);
void *memcpy(void *, const void *, uint);

2746
xv6-user/usertests.c Normal file

File diff suppressed because it is too large Load Diff

38
xv6-user/usys.pl Executable file
View File

@ -0,0 +1,38 @@
#!/usr/bin/perl -w
# Generate usys.S, the stubs for syscalls.
print "# generated by usys.pl - do not edit\n";
print "#include \"kernel/syscall.h\"\n";
sub entry {
my $name = shift;
print ".global $name\n";
print "${name}:\n";
print " li a7, SYS_${name}\n";
print " ecall\n";
print " ret\n";
}
entry("fork");
entry("exit");
entry("wait");
entry("pipe");
entry("read");
entry("write");
entry("close");
entry("kill");
entry("exec");
entry("open");
entry("mknod");
entry("unlink");
entry("fstat");
entry("link");
entry("mkdir");
entry("chdir");
entry("dup");
entry("getpid");
entry("sbrk");
entry("sleep");
entry("uptime");

54
xv6-user/wc.c Normal file
View File

@ -0,0 +1,54 @@
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
char buf[512];
void
wc(int fd, char *name)
{
int i, n;
int l, w, c, inword;
l = w = c = 0;
inword = 0;
while((n = read(fd, buf, sizeof(buf))) > 0){
for(i=0; i<n; i++){
c++;
if(buf[i] == '\n')
l++;
if(strchr(" \r\t\n\v", buf[i]))
inword = 0;
else if(!inword){
w++;
inword = 1;
}
}
}
if(n < 0){
printf("wc: read error\n");
exit(1);
}
printf("%d %d %d %s\n", l, w, c, name);
}
int
main(int argc, char *argv[])
{
int fd, i;
if(argc <= 1){
wc(0, "");
exit(0);
}
for(i = 1; i < argc; i++){
if((fd = open(argv[i], 0)) < 0){
printf("wc: cannot open %s\n", argv[i]);
exit(1);
}
wc(fd, argv[i]);
close(fd);
}
exit(0);
}

6
xv6-user/xargstest.sh Normal file
View File

@ -0,0 +1,6 @@
mkdir a
echo hello > a/b
mkdir c
echo hello > c/b
echo hello > b
find . b | xargs grep hello

14
xv6-user/zombie.c Normal file
View File

@ -0,0 +1,14 @@
// Create a zombie process that
// must be reparented at exit.
#include "kernel/types.h"
#include "kernel/stat.h"
#include "xv6-user/user.h"
int
main(void)
{
if(fork() > 0)
sleep(5); // Let child exit before parent.
exit(0);
}