Compare commits

..

No commits in common. "4cd2466900323c27937d2994b3b702266f840e46" and "96047832c62e6a172c92f9ead6715b553d4c2271" have entirely different histories.

55 changed files with 7683 additions and 7050 deletions

View File

@ -1,5 +0,0 @@
[build]
target = "riscv64gc-unknown-none-elf"
[target.riscv64-unknown-elf]
linker = "/opt/riscv/bin/riscv64-unknown-elf-gcc"

View File

@ -1,4 +0,0 @@
SortIncludes: Never
UseTab: Always
IndentWidth: 4
TabWidth: 4

View File

@ -4,4 +4,19 @@ root = true
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
[*.{c,h}]
indent_size = 2
[*.S]
indent_size = 8
[*.ld]
indent_size = 2
[Makefile]
indent_style = tab
indent_size = 8

View File

@ -1 +0,0 @@
hard_tabs = true

View File

@ -1,8 +1,5 @@
K=kernel
U=user
R=rust
RTARGET = riscv64gc-unknown-none-elf
OBJS = \
$K/entry.o \
@ -33,9 +30,6 @@ OBJS = \
$K/plic.o \
$K/virtio_disk.o
RLIBS = \
$R/foo/target/$(RTARGET)/release/libfoo.a
# riscv64-unknown-elf- or riscv64-linux-gnu-
# perhaps in /opt/riscv/bin
#TOOLPREFIX =
@ -79,8 +73,8 @@ endif
LDFLAGS = -z max-page-size=4096
$K/kernel: $(OBJS) $K/kernel.ld $U/initcode rustlibs
$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS) $(RLIBS)
$K/kernel: $(OBJS) $K/kernel.ld $U/initcode
$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS)
$(OBJDUMP) -S $K/kernel > $K/kernel.asm
$(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym
@ -144,9 +138,6 @@ fs.img: mkfs/mkfs README $(UPROGS)
-include kernel/*.d user/*.d
rustlibs:
cargo build -r --manifest-path $R/foo/Cargo.toml
clean:
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
*/*.o */*.d */*.asm */*.sym \
@ -154,7 +145,6 @@ clean:
mkfs/mkfs .gdbinit \
$U/usys.S \
$(UPROGS)
cargo clean --manifest-path $R/foo/Cargo.toml
# try to generate a unique GDB port
GDBPORT = $(shell expr `id -u` % 5000 + 25000)

36
README
View File

@ -6,7 +6,7 @@ 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.1810/, which provides
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,
@ -14,31 +14,29 @@ locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
Clements.
We are also grateful for the bug reports and patches contributed by
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,
eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel
Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt
Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John
Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller,
Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin
Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan
Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel
Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal,
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe,
Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng,
ZhUyU1997, and Zou Chang Wei.
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, Ian Chen, Dan
Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson
Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark,
Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry,
jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders
Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt,
Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan
Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi
Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek,
Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey,
Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi
Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy
Zheng, ZhUyU1997, and Zou Chang Wei.
The code in the files that constitute xv6 is
Copyright 2006-2022 Frans Kaashoek, Robert Morris, and Russ Cox.
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.1810, so we are more interested in
operating system for MIT's 6.S081, so we are more interested in
simplifications and clarifications than new features.
BUILDING AND RUNNING XV6

View File

@ -13,6 +13,7 @@
// * Only one process at a time can use a buffer,
// so do not keep them longer than necessary.
#include "types.h"
#include "param.h"
#include "spinlock.h"
@ -32,7 +33,9 @@ struct {
struct buf head;
} bcache;
void binit(void) {
void
binit(void)
{
struct buf *b;
initlock(&bcache.lock, "bcache");
@ -40,7 +43,7 @@ void binit(void) {
// Create linked list of buffers
bcache.head.prev = &bcache.head;
bcache.head.next = &bcache.head;
for (b = bcache.buf; b < bcache.buf + NBUF; b++) {
for(b = bcache.buf; b < bcache.buf+NBUF; b++){
b->next = bcache.head.next;
b->prev = &bcache.head;
initsleeplock(&b->lock, "buffer");
@ -52,14 +55,16 @@ void binit(void) {
// Look through buffer cache for block on device dev.
// If not found, allocate a buffer.
// In either case, return locked buffer.
static struct buf *bget(uint dev, uint blockno) {
static struct buf*
bget(uint dev, uint blockno)
{
struct buf *b;
acquire(&bcache.lock);
// Is the block already cached?
for (b = bcache.head.next; b != &bcache.head; b = b->next) {
if (b->dev == dev && b->blockno == blockno) {
for(b = bcache.head.next; b != &bcache.head; b = b->next){
if(b->dev == dev && b->blockno == blockno){
b->refcnt++;
release(&bcache.lock);
acquiresleep(&b->lock);
@ -69,8 +74,8 @@ static struct buf *bget(uint dev, uint blockno) {
// Not cached.
// Recycle the least recently used (LRU) unused buffer.
for (b = bcache.head.prev; b != &bcache.head; b = b->prev) {
if (b->refcnt == 0) {
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
if(b->refcnt == 0) {
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
@ -84,11 +89,13 @@ static struct buf *bget(uint dev, uint blockno) {
}
// Return a locked buf with the contents of the indicated block.
struct buf *bread(uint dev, uint blockno) {
struct buf*
bread(uint dev, uint blockno)
{
struct buf *b;
b = bget(dev, blockno);
if (!b->valid) {
if(!b->valid) {
virtio_disk_rw(b, 0);
b->valid = 1;
}
@ -96,16 +103,20 @@ struct buf *bread(uint dev, uint blockno) {
}
// Write b's contents to disk. Must be locked.
void bwrite(struct buf *b) {
if (!holdingsleep(&b->lock))
void
bwrite(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("bwrite");
virtio_disk_rw(b, 1);
}
// Release a locked buffer.
// Move to the head of the most-recently-used list.
void brelse(struct buf *b) {
if (!holdingsleep(&b->lock))
void
brelse(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("brelse");
releasesleep(&b->lock);
@ -125,14 +136,18 @@ void brelse(struct buf *b) {
release(&bcache.lock);
}
void bpin(struct buf *b) {
void
bpin(struct buf *b) {
acquire(&bcache.lock);
b->refcnt++;
release(&bcache.lock);
}
void bunpin(struct buf *b) {
void
bunpin(struct buf *b) {
acquire(&bcache.lock);
b->refcnt--;
release(&bcache.lock);
}

View File

@ -23,19 +23,19 @@
#include "proc.h"
#define BACKSPACE 0x100
#define C(x) ((x) - '@') // Control-x
#define C(x) ((x)-'@') // Control-x
//
// send one character to the uart.
// called by printf(), and to echo input characters,
// but not from write().
//
void consputc(int c) {
if (c == BACKSPACE) {
void
consputc(int c)
{
if(c == BACKSPACE){
// if the user typed backspace, overwrite with a space.
uartputc_sync('\b');
uartputc_sync(' ');
uartputc_sync('\b');
uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b');
} else {
uartputc_sync(c);
}
@ -55,12 +55,14 @@ struct {
//
// user write()s to the console go here.
//
int consolewrite(int user_src, uint64 src, int n) {
int
consolewrite(int user_src, uint64 src, int n)
{
int i;
for (i = 0; i < n; i++) {
for(i = 0; i < n; i++){
char c;
if (either_copyin(&c, user_src, src + i, 1) == -1)
if(either_copyin(&c, user_src, src+i, 1) == -1)
break;
uartputc(c);
}
@ -74,18 +76,20 @@ int consolewrite(int user_src, uint64 src, int n) {
// user_dist indicates whether dst is a user
// or kernel address.
//
int consoleread(int user_dst, uint64 dst, int n) {
int
consoleread(int user_dst, uint64 dst, int n)
{
uint target;
int c;
char cbuf;
target = n;
acquire(&cons.lock);
while (n > 0) {
while(n > 0){
// wait until interrupt handler has put some
// input into cons.buffer.
while (cons.r == cons.w) {
if (killed(myproc())) {
while(cons.r == cons.w){
if(killed(myproc())){
release(&cons.lock);
return -1;
}
@ -94,8 +98,8 @@ int consoleread(int user_dst, uint64 dst, int n) {
c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
if (c == C('D')) { // end-of-file
if (n < target) {
if(c == C('D')){ // end-of-file
if(n < target){
// Save ^D for next time, to make sure
// caller gets a 0-byte result.
cons.r--;
@ -105,13 +109,13 @@ int consoleread(int user_dst, uint64 dst, int n) {
// copy the input byte to the user-space buffer.
cbuf = c;
if (either_copyout(user_dst, dst, &cbuf, 1) == -1)
if(either_copyout(user_dst, dst, &cbuf, 1) == -1)
break;
dst++;
--n;
if (c == '\n') {
if(c == '\n'){
// a whole line has arrived, return to
// the user-level read().
break;
@ -128,29 +132,31 @@ int consoleread(int user_dst, uint64 dst, int n) {
// do erase/kill processing, append to cons.buf,
// wake up consoleread() if a whole line has arrived.
//
void consoleintr(int c) {
void
consoleintr(int c)
{
acquire(&cons.lock);
switch (c) {
switch(c){
case C('P'): // Print process list.
procdump();
break;
case C('U'): // Kill line.
while (cons.e != cons.w &&
cons.buf[(cons.e - 1) % INPUT_BUF_SIZE] != '\n') {
while(cons.e != cons.w &&
cons.buf[(cons.e-1) % INPUT_BUF_SIZE] != '\n'){
cons.e--;
consputc(BACKSPACE);
}
break;
case C('H'): // Backspace
case '\x7f': // Delete key
if (cons.e != cons.w) {
if(cons.e != cons.w){
cons.e--;
consputc(BACKSPACE);
}
break;
default:
if (c != 0 && cons.e - cons.r < INPUT_BUF_SIZE) {
if(c != 0 && cons.e-cons.r < INPUT_BUF_SIZE){
c = (c == '\r') ? '\n' : c;
// echo back to the user.
@ -159,7 +165,7 @@ void consoleintr(int c) {
// store for consumption by consoleread().
cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
if (c == '\n' || c == C('D') || cons.e - cons.r == INPUT_BUF_SIZE) {
if(c == '\n' || c == C('D') || cons.e-cons.r == INPUT_BUF_SIZE){
// wake up consoleread() if a whole line (or end-of-file)
// has arrived.
cons.w = cons.e;
@ -172,7 +178,9 @@ void consoleintr(int c) {
release(&cons.lock);
}
void consoleinit(void) {
void
consoleinit(void)
{
initlock(&cons.lock, "cons");
uartinit();

View File

@ -9,16 +9,19 @@
static int loadseg(pde_t *, uint64, struct inode *, uint, uint);
int flags2perm(int flags) {
int flags2perm(int flags)
{
int perm = 0;
if (flags & 0x1)
if(flags & 0x1)
perm = PTE_X;
if (flags & 0x2)
if(flags & 0x2)
perm |= PTE_W;
return perm;
}
int exec(char *path, char **argv) {
int
exec(char *path, char **argv)
{
char *s, *last;
int i, off;
uint64 argc, sz = 0, sp, ustack[MAXARG], stackbase;
@ -30,40 +33,39 @@ int exec(char *path, char **argv) {
begin_op();
if ((ip = namei(path)) == 0) {
if((ip = namei(path)) == 0){
end_op();
return -1;
}
ilock(ip);
// Check ELF header
if (readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf))
if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf))
goto bad;
if (elf.magic != ELF_MAGIC)
if(elf.magic != ELF_MAGIC)
goto bad;
if ((pagetable = proc_pagetable(p)) == 0)
if((pagetable = proc_pagetable(p)) == 0)
goto bad;
// Load program into memory.
for (i = 0, off = elf.phoff; i < elf.phnum; i++, off += sizeof(ph)) {
if (readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
if(readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
goto bad;
if (ph.type != ELF_PROG_LOAD)
if(ph.type != ELF_PROG_LOAD)
continue;
if (ph.memsz < ph.filesz)
if(ph.memsz < ph.filesz)
goto bad;
if (ph.vaddr + ph.memsz < ph.vaddr)
if(ph.vaddr + ph.memsz < ph.vaddr)
goto bad;
if (ph.vaddr % PGSIZE != 0)
if(ph.vaddr % PGSIZE != 0)
goto bad;
uint64 sz1;
if ((sz1 = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz,
flags2perm(ph.flags))) == 0)
if((sz1 = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz, flags2perm(ph.flags))) == 0)
goto bad;
sz = sz1;
if (loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0)
if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0)
goto bad;
}
iunlockput(ip);
@ -78,33 +80,33 @@ int exec(char *path, char **argv) {
// Use the second as the user stack.
sz = PGROUNDUP(sz);
uint64 sz1;
if ((sz1 = uvmalloc(pagetable, sz, sz + 2 * PGSIZE, PTE_W)) == 0)
if((sz1 = uvmalloc(pagetable, sz, sz + 2*PGSIZE, PTE_W)) == 0)
goto bad;
sz = sz1;
uvmclear(pagetable, sz - 2 * PGSIZE);
uvmclear(pagetable, sz-2*PGSIZE);
sp = sz;
stackbase = sp - PGSIZE;
// Push argument strings, prepare rest of stack in ustack.
for (argc = 0; argv[argc]; argc++) {
if (argc >= MAXARG)
for(argc = 0; argv[argc]; argc++) {
if(argc >= MAXARG)
goto bad;
sp -= strlen(argv[argc]) + 1;
sp -= sp % 16; // riscv sp must be 16-byte aligned
if (sp < stackbase)
if(sp < stackbase)
goto bad;
if (copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
if(copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
goto bad;
ustack[argc] = sp;
}
ustack[argc] = 0;
// push the array of argv[] pointers.
sp -= (argc + 1) * sizeof(uint64);
sp -= (argc+1) * sizeof(uint64);
sp -= sp % 16;
if (sp < stackbase)
if(sp < stackbase)
goto bad;
if (copyout(pagetable, sp, (char *)ustack, (argc + 1) * sizeof(uint64)) < 0)
if(copyout(pagetable, sp, (char *)ustack, (argc+1)*sizeof(uint64)) < 0)
goto bad;
// arguments to user main(argc, argv)
@ -113,9 +115,9 @@ int exec(char *path, char **argv) {
p->trapframe->a1 = sp;
// Save program name for debugging.
for (last = s = path; *s; s++)
if (*s == '/')
last = s + 1;
for(last=s=path; *s; s++)
if(*s == '/')
last = s+1;
safestrcpy(p->name, last, sizeof(p->name));
// Commit to the user image.
@ -128,10 +130,10 @@ int exec(char *path, char **argv) {
return argc; // this ends up in a0, the first argument to main(argc, argv)
bad:
if (pagetable)
bad:
if(pagetable)
proc_freepagetable(pagetable, sz);
if (ip) {
if(ip){
iunlockput(ip);
end_op();
}
@ -142,20 +144,21 @@ bad:
// va must be page-aligned
// and the pages from va to va+sz must already be mapped.
// Returns 0 on success, -1 on failure.
static int loadseg(pagetable_t pagetable, uint64 va, struct inode *ip,
uint offset, uint sz) {
static int
loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz)
{
uint i, n;
uint64 pa;
for (i = 0; i < sz; i += PGSIZE) {
for(i = 0; i < sz; i += PGSIZE){
pa = walkaddr(pagetable, va + i);
if (pa == 0)
if(pa == 0)
panic("loadseg: address should exist");
if (sz - i < PGSIZE)
if(sz - i < PGSIZE)
n = sz - i;
else
n = PGSIZE;
if (readi(ip, 0, (uint64)pa, offset + i, n) != n)
if(readi(ip, 0, (uint64)pa, offset+i, n) != n)
return -1;
}

View File

@ -19,15 +19,21 @@ struct {
struct file file[NFILE];
} ftable;
void fileinit(void) { initlock(&ftable.lock, "ftable"); }
void
fileinit(void)
{
initlock(&ftable.lock, "ftable");
}
// Allocate a file structure.
struct file *filealloc(void) {
struct file*
filealloc(void)
{
struct file *f;
acquire(&ftable.lock);
for (f = ftable.file; f < ftable.file + NFILE; f++) {
if (f->ref == 0) {
for(f = ftable.file; f < ftable.file + NFILE; f++){
if(f->ref == 0){
f->ref = 1;
release(&ftable.lock);
return f;
@ -38,9 +44,11 @@ struct file *filealloc(void) {
}
// Increment ref count for file f.
struct file *filedup(struct file *f) {
struct file*
filedup(struct file *f)
{
acquire(&ftable.lock);
if (f->ref < 1)
if(f->ref < 1)
panic("filedup");
f->ref++;
release(&ftable.lock);
@ -48,13 +56,15 @@ struct file *filedup(struct file *f) {
}
// Close file f. (Decrement ref count, close when reaches 0.)
void fileclose(struct file *f) {
void
fileclose(struct file *f)
{
struct file ff;
acquire(&ftable.lock);
if (f->ref < 1)
if(f->ref < 1)
panic("fileclose");
if (--f->ref > 0) {
if(--f->ref > 0){
release(&ftable.lock);
return;
}
@ -63,9 +73,9 @@ void fileclose(struct file *f) {
f->type = FD_NONE;
release(&ftable.lock);
if (ff.type == FD_PIPE) {
if(ff.type == FD_PIPE){
pipeclose(ff.pipe, ff.writable);
} else if (ff.type == FD_INODE || ff.type == FD_DEVICE) {
} else if(ff.type == FD_INODE || ff.type == FD_DEVICE){
begin_op();
iput(ff.ip);
end_op();
@ -74,15 +84,17 @@ void fileclose(struct file *f) {
// Get metadata about file f.
// addr is a user virtual address, pointing to a struct stat.
int filestat(struct file *f, uint64 addr) {
int
filestat(struct file *f, uint64 addr)
{
struct proc *p = myproc();
struct stat st;
if (f->type == FD_INODE || f->type == FD_DEVICE) {
if(f->type == FD_INODE || f->type == FD_DEVICE){
ilock(f->ip);
stati(f->ip, &st);
iunlock(f->ip);
if (copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
return -1;
return 0;
}
@ -91,21 +103,23 @@ int filestat(struct file *f, uint64 addr) {
// Read from file f.
// addr is a user virtual address.
int fileread(struct file *f, uint64 addr, int n) {
int
fileread(struct file *f, uint64 addr, int n)
{
int r = 0;
if (f->readable == 0)
if(f->readable == 0)
return -1;
if (f->type == FD_PIPE) {
if(f->type == FD_PIPE){
r = piperead(f->pipe, addr, n);
} else if (f->type == FD_DEVICE) {
if (f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
} else if(f->type == FD_DEVICE){
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
return -1;
r = devsw[f->major].read(1, addr, n);
} else if (f->type == FD_INODE) {
} else if(f->type == FD_INODE){
ilock(f->ip);
if ((r = readi(f->ip, 1, addr, f->off, n)) > 0)
if((r = readi(f->ip, 1, addr, f->off, n)) > 0)
f->off += r;
iunlock(f->ip);
} else {
@ -117,30 +131,32 @@ int fileread(struct file *f, uint64 addr, int n) {
// Write to file f.
// addr is a user virtual address.
int filewrite(struct file *f, uint64 addr, int n) {
int
filewrite(struct file *f, uint64 addr, int n)
{
int r, ret = 0;
if (f->writable == 0)
if(f->writable == 0)
return -1;
if (f->type == FD_PIPE) {
if(f->type == FD_PIPE){
ret = pipewrite(f->pipe, addr, n);
} else if (f->type == FD_DEVICE) {
if (f->major < 0 || f->major >= NDEV || !devsw[f->major].write)
} else if(f->type == FD_DEVICE){
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].write)
return -1;
ret = devsw[f->major].write(1, addr, n);
} else if (f->type == FD_INODE) {
} else if(f->type == FD_INODE){
// write a few blocks at a time to avoid exceeding
// the maximum log transaction size, including
// i-node, indirect block, allocation blocks,
// and 2 blocks of slop for non-aligned writes.
// this really belongs lower down, since writei()
// might be writing a device like the console.
int max = ((MAXOPBLOCKS - 1 - 1 - 2) / 2) * BSIZE;
int max = ((MAXOPBLOCKS-1-1-2) / 2) * BSIZE;
int i = 0;
while (i < n) {
while(i < n){
int n1 = n - i;
if (n1 > max)
if(n1 > max)
n1 = max;
begin_op();
@ -150,7 +166,7 @@ int filewrite(struct file *f, uint64 addr, int n) {
iunlock(f->ip);
end_op();
if (r != n1) {
if(r != n1){
// error from writei
break;
}
@ -163,3 +179,4 @@ int filewrite(struct file *f, uint64 addr, int n) {
return ret;
}

View File

@ -27,7 +27,9 @@
struct superblock sb;
// Read the super block.
static void readsb(int dev, struct superblock *sb) {
static void
readsb(int dev, struct superblock *sb)
{
struct buf *bp;
bp = bread(dev, 1);
@ -36,15 +38,18 @@ static void readsb(int dev, struct superblock *sb) {
}
// Init fs
void fsinit(int dev) {
void
fsinit(int dev) {
readsb(dev, &sb);
if (sb.magic != FSMAGIC)
if(sb.magic != FSMAGIC)
panic("invalid file system");
initlog(dev, &sb);
}
// Zero a block.
static void bzero(int dev, int bno) {
static void
bzero(int dev, int bno)
{
struct buf *bp;
bp = bread(dev, bno);
@ -57,17 +62,19 @@ static void bzero(int dev, int bno) {
// Allocate a zeroed disk block.
// returns 0 if out of disk space.
static uint balloc(uint dev) {
static uint
balloc(uint dev)
{
int b, bi, m;
struct buf *bp;
bp = 0;
for (b = 0; b < sb.size; b += BPB) {
for(b = 0; b < sb.size; b += BPB){
bp = bread(dev, BBLOCK(b, sb));
for (bi = 0; bi < BPB && b + bi < sb.size; bi++) {
for(bi = 0; bi < BPB && b + bi < sb.size; bi++){
m = 1 << (bi % 8);
if ((bp->data[bi / 8] & m) == 0) { // Is block free?
bp->data[bi / 8] |= m; // Mark block in use.
if((bp->data[bi/8] & m) == 0){ // Is block free?
bp->data[bi/8] |= m; // Mark block in use.
log_write(bp);
brelse(bp);
bzero(dev, b + bi);
@ -81,16 +88,18 @@ static uint balloc(uint dev) {
}
// Free a disk block.
static void bfree(int dev, uint b) {
static void
bfree(int dev, uint b)
{
struct buf *bp;
int bi, m;
bp = bread(dev, BBLOCK(b, sb));
bi = b % BPB;
m = 1 << (bi % 8);
if ((bp->data[bi / 8] & m) == 0)
if((bp->data[bi/8] & m) == 0)
panic("freeing free block");
bp->data[bi / 8] &= ~m;
bp->data[bi/8] &= ~m;
log_write(bp);
brelse(bp);
}
@ -169,30 +178,34 @@ struct {
struct inode inode[NINODE];
} itable;
void iinit() {
void
iinit()
{
int i = 0;
initlock(&itable.lock, "itable");
for (i = 0; i < NINODE; i++) {
for(i = 0; i < NINODE; i++) {
initsleeplock(&itable.inode[i].lock, "inode");
}
}
static struct inode *iget(uint dev, uint inum);
static struct inode* iget(uint dev, uint inum);
// Allocate an inode on device dev.
// Mark it as allocated by giving it type type.
// Returns an unlocked but allocated and referenced inode,
// or NULL if there is no free inode.
struct inode *ialloc(uint dev, short type) {
// or NULL if there is no free inode..
struct inode*
ialloc(uint dev, short type)
{
int inum;
struct buf *bp;
struct dinode *dip;
for (inum = 1; inum < sb.ninodes; inum++) {
for(inum = 1; inum < sb.ninodes; inum++){
bp = bread(dev, IBLOCK(inum, sb));
dip = (struct dinode *)bp->data + inum % IPB;
if (dip->type == 0) { // a free inode
dip = (struct dinode*)bp->data + inum%IPB;
if(dip->type == 0){ // a free inode
memset(dip, 0, sizeof(*dip));
dip->type = type;
log_write(bp); // mark it allocated on the disk
@ -209,12 +222,14 @@ struct inode *ialloc(uint dev, short type) {
// Must be called after every change to an ip->xxx field
// that lives on disk.
// Caller must hold ip->lock.
void iupdate(struct inode *ip) {
void
iupdate(struct inode *ip)
{
struct buf *bp;
struct dinode *dip;
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
dip = (struct dinode *)bp->data + ip->inum % IPB;
dip = (struct dinode*)bp->data + ip->inum%IPB;
dip->type = ip->type;
dip->major = ip->major;
dip->minor = ip->minor;
@ -228,25 +243,27 @@ void iupdate(struct inode *ip) {
// Find the inode with number inum on device dev
// and return the in-memory copy. Does not lock
// the inode and does not read it from disk.
static struct inode *iget(uint dev, uint inum) {
static struct inode*
iget(uint dev, uint inum)
{
struct inode *ip, *empty;
acquire(&itable.lock);
// Is the inode already in the table?
empty = 0;
for (ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++) {
if (ip->ref > 0 && ip->dev == dev && ip->inum == inum) {
for(ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++){
if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
ip->ref++;
release(&itable.lock);
return ip;
}
if (empty == 0 && ip->ref == 0) // Remember empty slot.
if(empty == 0 && ip->ref == 0) // Remember empty slot.
empty = ip;
}
// Recycle an inode entry.
if (empty == 0)
if(empty == 0)
panic("iget: no inodes");
ip = empty;
@ -261,7 +278,9 @@ static struct inode *iget(uint dev, uint inum) {
// Increment reference count for ip.
// Returns ip to enable ip = idup(ip1) idiom.
struct inode *idup(struct inode *ip) {
struct inode*
idup(struct inode *ip)
{
acquire(&itable.lock);
ip->ref++;
release(&itable.lock);
@ -270,18 +289,20 @@ struct inode *idup(struct inode *ip) {
// Lock the given inode.
// Reads the inode from disk if necessary.
void ilock(struct inode *ip) {
void
ilock(struct inode *ip)
{
struct buf *bp;
struct dinode *dip;
if (ip == 0 || ip->ref < 1)
if(ip == 0 || ip->ref < 1)
panic("ilock");
acquiresleep(&ip->lock);
if (ip->valid == 0) {
if(ip->valid == 0){
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
dip = (struct dinode *)bp->data + ip->inum % IPB;
dip = (struct dinode*)bp->data + ip->inum%IPB;
ip->type = dip->type;
ip->major = dip->major;
ip->minor = dip->minor;
@ -290,14 +311,16 @@ void ilock(struct inode *ip) {
memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
brelse(bp);
ip->valid = 1;
if (ip->type == 0)
if(ip->type == 0)
panic("ilock: no type");
}
}
// Unlock the given inode.
void iunlock(struct inode *ip) {
if (ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
void
iunlock(struct inode *ip)
{
if(ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
panic("iunlock");
releasesleep(&ip->lock);
@ -310,10 +333,12 @@ void iunlock(struct inode *ip) {
// to it, free the inode (and its content) on disk.
// All calls to iput() must be inside a transaction in
// case it has to free the inode.
void iput(struct inode *ip) {
void
iput(struct inode *ip)
{
acquire(&itable.lock);
if (ip->ref == 1 && ip->valid && ip->nlink == 0) {
if(ip->ref == 1 && ip->valid && ip->nlink == 0){
// inode has no links and no other references: truncate and free.
// ip->ref == 1 means no other process can have ip locked,
@ -337,7 +362,9 @@ void iput(struct inode *ip) {
}
// Common idiom: unlock, then put.
void iunlockput(struct inode *ip) {
void
iunlockput(struct inode *ip)
{
iunlock(ip);
iput(ip);
}
@ -352,14 +379,16 @@ void iunlockput(struct inode *ip) {
// Return the disk block address of the nth block in inode ip.
// If there is no such block, bmap allocates one.
// returns 0 if out of disk space.
static uint bmap(struct inode *ip, uint bn) {
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;
if (bn < NDIRECT) {
if ((addr = ip->addrs[bn]) == 0) {
if(bn < NDIRECT){
if((addr = ip->addrs[bn]) == 0){
addr = balloc(ip->dev);
if (addr == 0)
if(addr == 0)
return 0;
ip->addrs[bn] = addr;
}
@ -367,19 +396,19 @@ static uint bmap(struct inode *ip, uint bn) {
}
bn -= NDIRECT;
if (bn < NINDIRECT) {
if(bn < NINDIRECT){
// Load indirect block, allocating if necessary.
if ((addr = ip->addrs[NDIRECT]) == 0) {
if((addr = ip->addrs[NDIRECT]) == 0){
addr = balloc(ip->dev);
if (addr == 0)
if(addr == 0)
return 0;
ip->addrs[NDIRECT] = addr;
}
bp = bread(ip->dev, addr);
a = (uint *)bp->data;
if ((addr = a[bn]) == 0) {
a = (uint*)bp->data;
if((addr = a[bn]) == 0){
addr = balloc(ip->dev);
if (addr) {
if(addr){
a[bn] = addr;
log_write(bp);
}
@ -393,23 +422,25 @@ static uint bmap(struct inode *ip, uint bn) {
// Truncate inode (discard contents).
// Caller must hold ip->lock.
void itrunc(struct inode *ip) {
void
itrunc(struct inode *ip)
{
int i, j;
struct buf *bp;
uint *a;
for (i = 0; i < NDIRECT; i++) {
if (ip->addrs[i]) {
for(i = 0; i < NDIRECT; i++){
if(ip->addrs[i]){
bfree(ip->dev, ip->addrs[i]);
ip->addrs[i] = 0;
}
}
if (ip->addrs[NDIRECT]) {
if(ip->addrs[NDIRECT]){
bp = bread(ip->dev, ip->addrs[NDIRECT]);
a = (uint *)bp->data;
for (j = 0; j < NINDIRECT; j++) {
if (a[j])
a = (uint*)bp->data;
for(j = 0; j < NINDIRECT; j++){
if(a[j])
bfree(ip->dev, a[j]);
}
brelse(bp);
@ -423,7 +454,9 @@ void itrunc(struct inode *ip) {
// Copy stat information from inode.
// Caller must hold ip->lock.
void stati(struct inode *ip, struct stat *st) {
void
stati(struct inode *ip, struct stat *st)
{
st->dev = ip->dev;
st->ino = ip->inum;
st->type = ip->type;
@ -435,22 +468,24 @@ void stati(struct inode *ip, struct stat *st) {
// Caller must hold ip->lock.
// If user_dst==1, then dst is a user virtual address;
// otherwise, dst is a kernel address.
int readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n) {
int
readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)
{
uint tot, m;
struct buf *bp;
if (off > ip->size || off + n < off)
if(off > ip->size || off + n < off)
return 0;
if (off + n > ip->size)
if(off + n > ip->size)
n = ip->size - off;
for (tot = 0; tot < n; tot += m, off += m, dst += m) {
uint addr = bmap(ip, off / BSIZE);
if (addr == 0)
for(tot=0; tot<n; tot+=m, off+=m, dst+=m){
uint addr = bmap(ip, off/BSIZE);
if(addr == 0)
break;
bp = bread(ip->dev, addr);
m = min(n - tot, BSIZE - off % BSIZE);
if (either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) {
m = min(n - tot, BSIZE - off%BSIZE);
if(either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) {
brelse(bp);
tot = -1;
break;
@ -467,22 +502,24 @@ int readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n) {
// Returns the number of bytes successfully written.
// If the return value is less than the requested n,
// there was an error of some kind.
int writei(struct inode *ip, int user_src, uint64 src, uint off, uint n) {
int
writei(struct inode *ip, int user_src, uint64 src, uint off, uint n)
{
uint tot, m;
struct buf *bp;
if (off > ip->size || off + n < off)
if(off > ip->size || off + n < off)
return -1;
if (off + n > MAXFILE * BSIZE)
if(off + n > MAXFILE*BSIZE)
return -1;
for (tot = 0; tot < n; tot += m, off += m, src += m) {
uint addr = bmap(ip, off / BSIZE);
if (addr == 0)
for(tot=0; tot<n; tot+=m, off+=m, src+=m){
uint addr = bmap(ip, off/BSIZE);
if(addr == 0)
break;
bp = bread(ip->dev, addr);
m = min(n - tot, BSIZE - off % BSIZE);
if (either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) {
m = min(n - tot, BSIZE - off%BSIZE);
if(either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) {
brelse(bp);
break;
}
@ -490,7 +527,7 @@ int writei(struct inode *ip, int user_src, uint64 src, uint off, uint n) {
brelse(bp);
}
if (off > ip->size)
if(off > ip->size)
ip->size = off;
// write the i-node back to disk even if the size didn't change
@ -503,25 +540,31 @@ int writei(struct inode *ip, int user_src, uint64 src, uint off, uint n) {
// Directories
int namecmp(const char *s, const char *t) { return strncmp(s, t, DIRSIZ); }
int
namecmp(const char *s, const char *t)
{
return strncmp(s, t, DIRSIZ);
}
// Look for a directory entry in a directory.
// If found, set *poff to byte offset of entry.
struct inode *dirlookup(struct inode *dp, char *name, uint *poff) {
struct inode*
dirlookup(struct inode *dp, char *name, uint *poff)
{
uint off, inum;
struct dirent de;
if (dp->type != T_DIR)
if(dp->type != T_DIR)
panic("dirlookup not DIR");
for (off = 0; off < dp->size; off += sizeof(de)) {
if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
for(off = 0; off < dp->size; off += sizeof(de)){
if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
panic("dirlookup read");
if (de.inum == 0)
if(de.inum == 0)
continue;
if (namecmp(name, de.name) == 0) {
if(namecmp(name, de.name) == 0){
// entry matches path element
if (poff)
if(poff)
*poff = off;
inum = de.inum;
return iget(dp->dev, inum);
@ -533,28 +576,30 @@ struct inode *dirlookup(struct inode *dp, char *name, uint *poff) {
// Write a new directory entry (name, inum) into the directory dp.
// Returns 0 on success, -1 on failure (e.g. out of disk blocks).
int dirlink(struct inode *dp, char *name, uint inum) {
int
dirlink(struct inode *dp, char *name, uint inum)
{
int off;
struct dirent de;
struct inode *ip;
// Check that name is not present.
if ((ip = dirlookup(dp, name, 0)) != 0) {
if((ip = dirlookup(dp, name, 0)) != 0){
iput(ip);
return -1;
}
// Look for an empty dirent.
for (off = 0; off < dp->size; off += sizeof(de)) {
if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
for(off = 0; off < dp->size; off += sizeof(de)){
if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
panic("dirlink read");
if (de.inum == 0)
if(de.inum == 0)
break;
}
strncpy(de.name, name, DIRSIZ);
de.inum = inum;
if (writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
return -1;
return 0;
@ -574,25 +619,27 @@ int dirlink(struct inode *dp, char *name, uint inum) {
// skipelem("a", name) = "", setting name = "a"
// skipelem("", name) = skipelem("////", name) = 0
//
static char *skipelem(char *path, char *name) {
static char*
skipelem(char *path, char *name)
{
char *s;
int len;
while (*path == '/')
while(*path == '/')
path++;
if (*path == 0)
if(*path == 0)
return 0;
s = path;
while (*path != '/' && *path != 0)
while(*path != '/' && *path != 0)
path++;
len = path - s;
if (len >= DIRSIZ)
if(len >= DIRSIZ)
memmove(name, s, DIRSIZ);
else {
memmove(name, s, len);
name[len] = 0;
}
while (*path == '/')
while(*path == '/')
path++;
return path;
}
@ -601,44 +648,50 @@ static char *skipelem(char *path, char *name) {
// If parent != 0, return the inode for the parent and copy the final
// path element into name, which must have room for DIRSIZ bytes.
// Must be called inside a transaction since it calls iput().
static struct inode *namex(char *path, int nameiparent, char *name) {
static struct inode*
namex(char *path, int nameiparent, char *name)
{
struct inode *ip, *next;
if (*path == '/')
if(*path == '/')
ip = iget(ROOTDEV, ROOTINO);
else
ip = idup(myproc()->cwd);
while ((path = skipelem(path, name)) != 0) {
while((path = skipelem(path, name)) != 0){
ilock(ip);
if (ip->type != T_DIR) {
if(ip->type != T_DIR){
iunlockput(ip);
return 0;
}
if (nameiparent && *path == '\0') {
if(nameiparent && *path == '\0'){
// Stop one level early.
iunlock(ip);
return ip;
}
if ((next = dirlookup(ip, name, 0)) == 0) {
if((next = dirlookup(ip, name, 0)) == 0){
iunlockput(ip);
return 0;
}
iunlockput(ip);
ip = next;
}
if (nameiparent) {
if(nameiparent){
iput(ip);
return 0;
}
return ip;
}
struct inode *namei(char *path) {
struct inode*
namei(char *path)
{
char name[DIRSIZ];
return namex(path, 0, name);
}
struct inode *nameiparent(char *path, char *name) {
struct inode*
nameiparent(char *path, char *name)
{
return namex(path, 1, name);
}

View File

@ -23,15 +23,19 @@ struct {
struct run *freelist;
} kmem;
void kinit() {
void
kinit()
{
initlock(&kmem.lock, "kmem");
freerange(end, (void *)PHYSTOP);
freerange(end, (void*)PHYSTOP);
}
void freerange(void *pa_start, void *pa_end) {
void
freerange(void *pa_start, void *pa_end)
{
char *p;
p = (char *)PGROUNDUP((uint64)pa_start);
for (; p + PGSIZE <= (char *)pa_end; p += PGSIZE)
p = (char*)PGROUNDUP((uint64)pa_start);
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
kfree(p);
}
@ -39,16 +43,18 @@ void freerange(void *pa_start, void *pa_end) {
// which normally should have been returned by a
// call to kalloc(). (The exception is when
// initializing the allocator; see kinit above.)
void kfree(void *pa) {
void
kfree(void *pa)
{
struct run *r;
if (((uint64)pa % PGSIZE) != 0 || (char *)pa < end || (uint64)pa >= PHYSTOP)
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct run *)pa;
r = (struct run*)pa;
acquire(&kmem.lock);
r->next = kmem.freelist;
@ -59,16 +65,18 @@ void kfree(void *pa) {
// Allocate one 4096-byte page of physical memory.
// Returns a pointer that the kernel can use.
// Returns 0 if the memory cannot be allocated.
void *kalloc(void) {
void *
kalloc(void)
{
struct run *r;
acquire(&kmem.lock);
r = kmem.freelist;
if (r)
if(r)
kmem.freelist = r->next;
release(&kmem.lock);
if (r)
memset((char *)r, 5, PGSIZE); // fill with junk
return (void *)r;
if(r)
memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r;
}

View File

@ -51,7 +51,9 @@ struct log log;
static void recover_from_log(void);
static void commit();
void initlog(int dev, struct superblock *sb) {
void
initlog(int dev, struct superblock *sb)
{
if (sizeof(struct logheader) >= BSIZE)
panic("initlog: too big logheader");
@ -63,16 +65,17 @@ void initlog(int dev, struct superblock *sb) {
}
// Copy committed blocks from log to their home location
static void install_trans(int recovering) {
static void
install_trans(int recovering)
{
int tail;
for (tail = 0; tail < log.lh.n; tail++) {
struct buf *lbuf =
bread(log.dev, log.start + tail + 1); // read log block
struct buf *lbuf = bread(log.dev, log.start+tail+1); // read log block
struct buf *dbuf = bread(log.dev, log.lh.block[tail]); // read dst
memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst
bwrite(dbuf); // write dst to disk
if (recovering == 0)
if(recovering == 0)
bunpin(dbuf);
brelse(lbuf);
brelse(dbuf);
@ -80,9 +83,11 @@ static void install_trans(int recovering) {
}
// Read the log header from disk into the in-memory log header
static void read_head(void) {
static void
read_head(void)
{
struct buf *buf = bread(log.dev, log.start);
struct logheader *lh = (struct logheader *)(buf->data);
struct logheader *lh = (struct logheader *) (buf->data);
int i;
log.lh.n = lh->n;
for (i = 0; i < log.lh.n; i++) {
@ -94,9 +99,11 @@ static void read_head(void) {
// Write in-memory log header to disk.
// This is the true point at which the
// current transaction commits.
static void write_head(void) {
static void
write_head(void)
{
struct buf *buf = bread(log.dev, log.start);
struct logheader *hb = (struct logheader *)(buf->data);
struct logheader *hb = (struct logheader *) (buf->data);
int i;
hb->n = log.lh.n;
for (i = 0; i < log.lh.n; i++) {
@ -106,7 +113,9 @@ static void write_head(void) {
brelse(buf);
}
static void recover_from_log(void) {
static void
recover_from_log(void)
{
read_head();
install_trans(1); // if committed, copy from log to disk
log.lh.n = 0;
@ -114,12 +123,14 @@ static void recover_from_log(void) {
}
// called at the start of each FS system call.
void begin_op(void) {
void
begin_op(void)
{
acquire(&log.lock);
while (1) {
if (log.committing) {
while(1){
if(log.committing){
sleep(&log, &log.lock);
} else if (log.lh.n + (log.outstanding + 1) * MAXOPBLOCKS > LOGSIZE) {
} else if(log.lh.n + (log.outstanding+1)*MAXOPBLOCKS > LOGSIZE){
// this op might exhaust log space; wait for commit.
sleep(&log, &log.lock);
} else {
@ -132,14 +143,16 @@ void begin_op(void) {
// called at the end of each FS system call.
// commits if this was the last outstanding operation.
void end_op(void) {
void
end_op(void)
{
int do_commit = 0;
acquire(&log.lock);
log.outstanding -= 1;
if (log.committing)
if(log.committing)
panic("log.committing");
if (log.outstanding == 0) {
if(log.outstanding == 0){
do_commit = 1;
log.committing = 1;
} else {
@ -150,7 +163,7 @@ void end_op(void) {
}
release(&log.lock);
if (do_commit) {
if(do_commit){
// call commit w/o holding locks, since not allowed
// to sleep with locks.
commit();
@ -162,11 +175,13 @@ void end_op(void) {
}
// Copy modified blocks from cache to log.
static void write_log(void) {
static void
write_log(void)
{
int tail;
for (tail = 0; tail < log.lh.n; tail++) {
struct buf *to = bread(log.dev, log.start + tail + 1); // log block
struct buf *to = bread(log.dev, log.start+tail+1); // log block
struct buf *from = bread(log.dev, log.lh.block[tail]); // cache block
memmove(to->data, from->data, BSIZE);
bwrite(to); // write the log
@ -175,7 +190,9 @@ static void write_log(void) {
}
}
static void commit() {
static void
commit()
{
if (log.lh.n > 0) {
write_log(); // Write modified blocks from cache to log
write_head(); // Write header to disk -- the real commit
@ -194,7 +211,9 @@ static void commit() {
// modify bp->data[]
// log_write(bp)
// brelse(bp)
void log_write(struct buf *b) {
void
log_write(struct buf *b)
{
int i;
acquire(&log.lock);
@ -214,3 +233,4 @@ void log_write(struct buf *b) {
}
release(&log.lock);
}

View File

@ -3,22 +3,19 @@
#include "memlayout.h"
#include "riscv.h"
#include "defs.h"
#include <stdint.h>
extern int32_t add(int32_t right, int32_t left);
volatile static int started = 0;
// start() jumps here in supervisor mode on all CPUs.
void main() {
if (cpuid() == 0) {
void
main()
{
if(cpuid() == 0){
consoleinit();
printfinit();
printf("\n");
printf("xv6 kernel is booting\n");
printf("\n");
printf("rust library call: add(1, 2) = %d\n", add(1, 2));
printf("\n");
kinit(); // physical page allocator
kvminit(); // create kernel page table
kvminithart(); // turn on paging
@ -35,7 +32,7 @@ void main() {
__sync_synchronize();
started = 1;
} else {
while (started == 0)
while(started == 0)
;
__sync_synchronize();
printf("hart %d starting\n", cpuid());

View File

@ -19,14 +19,16 @@ struct pipe {
int writeopen; // write fd is still open
};
int pipealloc(struct file **f0, struct file **f1) {
int
pipealloc(struct file **f0, struct file **f1)
{
struct pipe *pi;
pi = 0;
*f0 = *f1 = 0;
if ((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
goto bad;
if ((pi = (struct pipe *)kalloc()) == 0)
if((pi = (struct pipe*)kalloc()) == 0)
goto bad;
pi->readopen = 1;
pi->writeopen = 1;
@ -43,48 +45,52 @@ int pipealloc(struct file **f0, struct file **f1) {
(*f1)->pipe = pi;
return 0;
bad:
if (pi)
kfree((char *)pi);
if (*f0)
bad:
if(pi)
kfree((char*)pi);
if(*f0)
fileclose(*f0);
if (*f1)
if(*f1)
fileclose(*f1);
return -1;
}
void pipeclose(struct pipe *pi, int writable) {
void
pipeclose(struct pipe *pi, int writable)
{
acquire(&pi->lock);
if (writable) {
if(writable){
pi->writeopen = 0;
wakeup(&pi->nread);
} else {
pi->readopen = 0;
wakeup(&pi->nwrite);
}
if (pi->readopen == 0 && pi->writeopen == 0) {
if(pi->readopen == 0 && pi->writeopen == 0){
release(&pi->lock);
kfree((char *)pi);
kfree((char*)pi);
} else
release(&pi->lock);
}
int pipewrite(struct pipe *pi, uint64 addr, int n) {
int
pipewrite(struct pipe *pi, uint64 addr, int n)
{
int i = 0;
struct proc *pr = myproc();
acquire(&pi->lock);
while (i < n) {
if (pi->readopen == 0 || killed(pr)) {
while(i < n){
if(pi->readopen == 0 || killed(pr)){
release(&pi->lock);
return -1;
}
if (pi->nwrite == pi->nread + PIPESIZE) { // DOC: pipewrite-full
if(pi->nwrite == pi->nread + PIPESIZE){ //DOC: pipewrite-full
wakeup(&pi->nread);
sleep(&pi->nwrite, &pi->lock);
} else {
char ch;
if (copyin(pr->pagetable, &ch, addr + i, 1) == -1)
if(copyin(pr->pagetable, &ch, addr + i, 1) == -1)
break;
pi->data[pi->nwrite++ % PIPESIZE] = ch;
i++;
@ -96,27 +102,29 @@ int pipewrite(struct pipe *pi, uint64 addr, int n) {
return i;
}
int piperead(struct pipe *pi, uint64 addr, int n) {
int
piperead(struct pipe *pi, uint64 addr, int n)
{
int i;
struct proc *pr = myproc();
char ch;
acquire(&pi->lock);
while (pi->nread == pi->nwrite && pi->writeopen) { // DOC: pipe-empty
if (killed(pr)) {
while(pi->nread == pi->nwrite && pi->writeopen){ //DOC: pipe-empty
if(killed(pr)){
release(&pi->lock);
return -1;
}
sleep(&pi->nread, &pi->lock); // DOC: piperead-sleep
sleep(&pi->nread, &pi->lock); //DOC: piperead-sleep
}
for (i = 0; i < n; i++) { // DOC: piperead-copy
if (pi->nread == pi->nwrite)
for(i = 0; i < n; i++){ //DOC: piperead-copy
if(pi->nread == pi->nwrite)
break;
ch = pi->data[pi->nread++ % PIPESIZE];
if (copyout(pr->pagetable, addr + i, &ch, 1) == -1)
if(copyout(pr->pagetable, addr + i, &ch, 1) == -1)
break;
}
wakeup(&pi->nwrite); // DOC: piperead-wakeup
wakeup(&pi->nwrite); //DOC: piperead-wakeup
release(&pi->lock);
return i;
}

View File

@ -8,32 +8,40 @@
// the riscv Platform Level Interrupt Controller (PLIC).
//
void plicinit(void) {
void
plicinit(void)
{
// set desired IRQ priorities non-zero (otherwise disabled).
*(uint32 *)(PLIC + UART0_IRQ * 4) = 1;
*(uint32 *)(PLIC + VIRTIO0_IRQ * 4) = 1;
*(uint32*)(PLIC + UART0_IRQ*4) = 1;
*(uint32*)(PLIC + VIRTIO0_IRQ*4) = 1;
}
void plicinithart(void) {
void
plicinithart(void)
{
int hart = cpuid();
// set enable bits for this hart's S-mode
// for the uart and virtio disk.
*(uint32 *)PLIC_SENABLE(hart) = (1 << UART0_IRQ) | (1 << VIRTIO0_IRQ);
*(uint32*)PLIC_SENABLE(hart) = (1 << UART0_IRQ) | (1 << VIRTIO0_IRQ);
// set this hart's S-mode priority threshold to 0.
*(uint32 *)PLIC_SPRIORITY(hart) = 0;
*(uint32*)PLIC_SPRIORITY(hart) = 0;
}
// ask the PLIC what interrupt we should serve.
int plic_claim(void) {
int
plic_claim(void)
{
int hart = cpuid();
int irq = *(uint32 *)PLIC_SCLAIM(hart);
int irq = *(uint32*)PLIC_SCLAIM(hart);
return irq;
}
// tell the PLIC we've served this IRQ.
void plic_complete(int irq) {
void
plic_complete(int irq)
{
int hart = cpuid();
*(uint32 *)PLIC_SCLAIM(hart) = irq;
*(uint32*)PLIC_SCLAIM(hart) = irq;
}

View File

@ -25,12 +25,14 @@ static struct {
static char digits[] = "0123456789abcdef";
static void printint(int xx, int base, int sign) {
static void
printint(int xx, int base, int sign)
{
char buf[16];
int i;
uint x;
if (sign && (sign = xx < 0))
if(sign && (sign = xx < 0))
x = -xx;
else
x = xx;
@ -38,16 +40,18 @@ static void printint(int xx, int base, int sign) {
i = 0;
do {
buf[i++] = digits[x % base];
} while ((x /= base) != 0);
} while((x /= base) != 0);
if (sign)
if(sign)
buf[i++] = '-';
while (--i >= 0)
while(--i >= 0)
consputc(buf[i]);
}
static void printptr(uint64 x) {
static void
printptr(uint64 x)
{
int i;
consputc('0');
consputc('x');
@ -56,28 +60,30 @@ static void printptr(uint64 x) {
}
// Print to the console. only understands %d, %x, %p, %s.
void printf(char *fmt, ...) {
void
printf(char *fmt, ...)
{
va_list ap;
int i, c, locking;
char *s;
locking = pr.locking;
if (locking)
if(locking)
acquire(&pr.lock);
if (fmt == 0)
panic("null fmt");
va_start(ap, fmt);
for (i = 0; (c = fmt[i] & 0xff) != 0; i++) {
if (c != '%') {
for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
if(c != '%'){
consputc(c);
continue;
}
c = fmt[++i] & 0xff;
if (c == 0)
if(c == 0)
break;
switch (c) {
switch(c){
case 'd':
printint(va_arg(ap, int), 10, 1);
break;
@ -88,9 +94,9 @@ void printf(char *fmt, ...) {
printptr(va_arg(ap, uint64));
break;
case 's':
if ((s = va_arg(ap, char *)) == 0)
if((s = va_arg(ap, char*)) == 0)
s = "(null)";
for (; *s; s++)
for(; *s; s++)
consputc(*s);
break;
case '%':
@ -105,21 +111,25 @@ void printf(char *fmt, ...) {
}
va_end(ap);
if (locking)
if(locking)
release(&pr.lock);
}
void panic(char *s) {
void
panic(char *s)
{
pr.locking = 0;
printf("panic: ");
printf(s);
printf("\n");
panicked = 1; // freeze uart output from other CPUs
for (;;)
for(;;)
;
}
void printfinit(void) {
void
printfinit(void)
{
initlock(&pr.lock, "pr");
pr.locking = 1;
}

View File

@ -29,49 +29,59 @@ struct spinlock wait_lock;
// Allocate a page for each process's kernel stack.
// Map it high in memory, followed by an invalid
// guard page.
void proc_mapstacks(pagetable_t kpgtbl) {
void
proc_mapstacks(pagetable_t kpgtbl)
{
struct proc *p;
for (p = proc; p < &proc[NPROC]; p++) {
for(p = proc; p < &proc[NPROC]; p++) {
char *pa = kalloc();
if (pa == 0)
if(pa == 0)
panic("kalloc");
uint64 va = KSTACK((int)(p - proc));
uint64 va = KSTACK((int) (p - proc));
kvmmap(kpgtbl, va, (uint64)pa, PGSIZE, PTE_R | PTE_W);
}
}
// initialize the proc table.
void procinit(void) {
void
procinit(void)
{
struct proc *p;
initlock(&pid_lock, "nextpid");
initlock(&wait_lock, "wait_lock");
for (p = proc; p < &proc[NPROC]; p++) {
for(p = proc; p < &proc[NPROC]; p++) {
initlock(&p->lock, "proc");
p->state = UNUSED;
p->kstack = KSTACK((int)(p - proc));
p->kstack = KSTACK((int) (p - proc));
}
}
// Must be called with interrupts disabled,
// to prevent race with process being moved
// to a different CPU.
int cpuid() {
int
cpuid()
{
int id = r_tp();
return id;
}
// Return this CPU's cpu struct.
// Interrupts must be disabled.
struct cpu *mycpu(void) {
struct cpu*
mycpu(void)
{
int id = cpuid();
struct cpu *c = &cpus[id];
return c;
}
// Return the current struct proc *, or zero if none.
struct proc *myproc(void) {
struct proc*
myproc(void)
{
push_off();
struct cpu *c = mycpu();
struct proc *p = c->proc;
@ -79,7 +89,9 @@ struct proc *myproc(void) {
return p;
}
int allocpid() {
int
allocpid()
{
int pid;
acquire(&pid_lock);
@ -94,12 +106,14 @@ int allocpid() {
// If found, initialize state required to run in the kernel,
// and return with p->lock held.
// If there are no free procs, or a memory allocation fails, return 0.
static struct proc *allocproc(void) {
static struct proc*
allocproc(void)
{
struct proc *p;
for (p = proc; p < &proc[NPROC]; p++) {
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if (p->state == UNUSED) {
if(p->state == UNUSED) {
goto found;
} else {
release(&p->lock);
@ -112,7 +126,7 @@ found:
p->state = USED;
// Allocate a trapframe page.
if ((p->trapframe = (struct trapframe *)kalloc()) == 0) {
if((p->trapframe = (struct trapframe *)kalloc()) == 0){
freeproc(p);
release(&p->lock);
return 0;
@ -120,7 +134,7 @@ found:
// An empty user page table.
p->pagetable = proc_pagetable(p);
if (p->pagetable == 0) {
if(p->pagetable == 0){
freeproc(p);
release(&p->lock);
return 0;
@ -138,11 +152,13 @@ found:
// free a proc structure and the data hanging from it,
// including user pages.
// p->lock must be held.
static void freeproc(struct proc *p) {
if (p->trapframe)
kfree((void *)p->trapframe);
static void
freeproc(struct proc *p)
{
if(p->trapframe)
kfree((void*)p->trapframe);
p->trapframe = 0;
if (p->pagetable)
if(p->pagetable)
proc_freepagetable(p->pagetable, p->sz);
p->pagetable = 0;
p->sz = 0;
@ -157,28 +173,30 @@ static void freeproc(struct proc *p) {
// Create a user page table for a given process, with no user memory,
// but with trampoline and trapframe pages.
pagetable_t proc_pagetable(struct proc *p) {
pagetable_t
proc_pagetable(struct proc *p)
{
pagetable_t pagetable;
// An empty page table.
pagetable = uvmcreate();
if (pagetable == 0)
if(pagetable == 0)
return 0;
// map the trampoline code (for system call return)
// at the highest user virtual address.
// only the supervisor uses it, on the way
// to/from user space, so not PTE_U.
if (mappages(pagetable, TRAMPOLINE, PGSIZE, (uint64)trampoline,
PTE_R | PTE_X) < 0) {
if(mappages(pagetable, TRAMPOLINE, PGSIZE,
(uint64)trampoline, PTE_R | PTE_X) < 0){
uvmfree(pagetable, 0);
return 0;
}
// map the trapframe page just below the trampoline page, for
// trampoline.S.
if (mappages(pagetable, TRAPFRAME, PGSIZE, (uint64)(p->trapframe),
PTE_R | PTE_W) < 0) {
if(mappages(pagetable, TRAPFRAME, PGSIZE,
(uint64)(p->trapframe), PTE_R | PTE_W) < 0){
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
uvmfree(pagetable, 0);
return 0;
@ -189,7 +207,9 @@ pagetable_t proc_pagetable(struct proc *p) {
// Free a process's page table, and free the
// physical memory it refers to.
void proc_freepagetable(pagetable_t pagetable, uint64 sz) {
void
proc_freepagetable(pagetable_t pagetable, uint64 sz)
{
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
uvmunmap(pagetable, TRAPFRAME, 1, 0);
uvmfree(pagetable, sz);
@ -198,15 +218,20 @@ void proc_freepagetable(pagetable_t pagetable, uint64 sz) {
// a user program that calls exec("/init")
// assembled from ../user/initcode.S
// od -t xC ../user/initcode
uchar initcode[] = {0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x02, 0x97,
0x05, 0x00, 0x00, 0x93, 0x85, 0x35, 0x02, 0x93, 0x08,
0x70, 0x00, 0x73, 0x00, 0x00, 0x00, 0x93, 0x08, 0x20,
0x00, 0x73, 0x00, 0x00, 0x00, 0xef, 0xf0, 0x9f, 0xff,
0x2f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x00, 0x24, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uchar initcode[] = {
0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x02,
0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x35, 0x02,
0x93, 0x08, 0x70, 0x00, 0x73, 0x00, 0x00, 0x00,
0x93, 0x08, 0x20, 0x00, 0x73, 0x00, 0x00, 0x00,
0xef, 0xf0, 0x9f, 0xff, 0x2f, 0x69, 0x6e, 0x69,
0x74, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
// Set up first user process.
void userinit(void) {
void
userinit(void)
{
struct proc *p;
p = allocproc();
@ -231,16 +256,18 @@ void userinit(void) {
// Grow or shrink user memory by n bytes.
// Return 0 on success, -1 on failure.
int growproc(int n) {
int
growproc(int n)
{
uint64 sz;
struct proc *p = myproc();
sz = p->sz;
if (n > 0) {
if ((sz = uvmalloc(p->pagetable, sz, sz + n, PTE_W)) == 0) {
if(n > 0){
if((sz = uvmalloc(p->pagetable, sz, sz + n, PTE_W)) == 0) {
return -1;
}
} else if (n < 0) {
} else if(n < 0){
sz = uvmdealloc(p->pagetable, sz, sz + n);
}
p->sz = sz;
@ -249,18 +276,20 @@ int growproc(int n) {
// Create a new process, copying the parent.
// Sets up child kernel stack to return as if from fork() system call.
int fork(void) {
int
fork(void)
{
int i, pid;
struct proc *np;
struct proc *p = myproc();
// Allocate process.
if ((np = allocproc()) == 0) {
if((np = allocproc()) == 0){
return -1;
}
// Copy user memory from parent to child.
if (uvmcopy(p->pagetable, np->pagetable, p->sz) < 0) {
if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
freeproc(np);
release(&np->lock);
return -1;
@ -274,8 +303,8 @@ int fork(void) {
np->trapframe->a0 = 0;
// increment reference counts on open file descriptors.
for (i = 0; i < NOFILE; i++)
if (p->ofile[i])
for(i = 0; i < NOFILE; i++)
if(p->ofile[i])
np->ofile[i] = filedup(p->ofile[i]);
np->cwd = idup(p->cwd);
@ -298,11 +327,13 @@ int fork(void) {
// Pass p's abandoned children to init.
// Caller must hold wait_lock.
void reparent(struct proc *p) {
void
reparent(struct proc *p)
{
struct proc *pp;
for (pp = proc; pp < &proc[NPROC]; pp++) {
if (pp->parent == p) {
for(pp = proc; pp < &proc[NPROC]; pp++){
if(pp->parent == p){
pp->parent = initproc;
wakeup(initproc);
}
@ -312,15 +343,17 @@ void reparent(struct proc *p) {
// Exit the current process. Does not return.
// An exited process remains in the zombie state
// until its parent calls wait().
void exit(int status) {
void
exit(int status)
{
struct proc *p = myproc();
if (p == initproc)
if(p == initproc)
panic("init exiting");
// Close all open files.
for (int fd = 0; fd < NOFILE; fd++) {
if (p->ofile[fd]) {
for(int fd = 0; fd < NOFILE; fd++){
if(p->ofile[fd]){
struct file *f = p->ofile[fd];
fileclose(f);
p->ofile[fd] = 0;
@ -354,27 +387,28 @@ void exit(int status) {
// Wait for a child process to exit and return its pid.
// Return -1 if this process has no children.
int wait(uint64 addr) {
int
wait(uint64 addr)
{
struct proc *pp;
int havekids, pid;
struct proc *p = myproc();
acquire(&wait_lock);
for (;;) {
for(;;){
// Scan through table looking for exited children.
havekids = 0;
for (pp = proc; pp < &proc[NPROC]; pp++) {
if (pp->parent == p) {
for(pp = proc; pp < &proc[NPROC]; pp++){
if(pp->parent == p){
// make sure the child isn't still in exit() or swtch().
acquire(&pp->lock);
havekids = 1;
if (pp->state == ZOMBIE) {
if(pp->state == ZOMBIE){
// Found one.
pid = pp->pid;
if (addr != 0 &&
copyout(p->pagetable, addr, (char *)&pp->xstate,
if(addr != 0 && copyout(p->pagetable, addr, (char *)&pp->xstate,
sizeof(pp->xstate)) < 0) {
release(&pp->lock);
release(&wait_lock);
@ -390,13 +424,13 @@ int wait(uint64 addr) {
}
// No point waiting if we don't have any children.
if (!havekids || killed(p)) {
if(!havekids || killed(p)){
release(&wait_lock);
return -1;
}
// Wait for a child to exit.
sleep(p, &wait_lock); // DOC: wait-sleep
sleep(p, &wait_lock); //DOC: wait-sleep
}
}
@ -407,18 +441,20 @@ int wait(uint64 addr) {
// - swtch to start running that process.
// - eventually that process transfers control
// via swtch back to the scheduler.
void scheduler(void) {
void
scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
c->proc = 0;
for (;;) {
for(;;){
// Avoid deadlock by ensuring that devices can interrupt.
intr_on();
for (p = proc; p < &proc[NPROC]; p++) {
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if (p->state == RUNNABLE) {
if(p->state == RUNNABLE) {
// Switch to chosen process. It is the process's job
// to release its lock and then reacquire it
// before jumping back to us.
@ -442,17 +478,19 @@ void scheduler(void) {
// be proc->intena and proc->noff, but that would
// break in the few places where a lock is held but
// there's no process.
void sched(void) {
void
sched(void)
{
int intena;
struct proc *p = myproc();
if (!holding(&p->lock))
if(!holding(&p->lock))
panic("sched p->lock");
if (mycpu()->noff != 1)
if(mycpu()->noff != 1)
panic("sched locks");
if (p->state == RUNNING)
if(p->state == RUNNING)
panic("sched running");
if (intr_get())
if(intr_get())
panic("sched interruptible");
intena = mycpu()->intena;
@ -461,7 +499,9 @@ void sched(void) {
}
// Give up the CPU for one scheduling round.
void yield(void) {
void
yield(void)
{
struct proc *p = myproc();
acquire(&p->lock);
p->state = RUNNABLE;
@ -471,7 +511,9 @@ void yield(void) {
// A fork child's very first scheduling by scheduler()
// will swtch to forkret.
void forkret(void) {
void
forkret(void)
{
static int first = 1;
// Still holding p->lock from scheduler.
@ -490,7 +532,9 @@ void forkret(void) {
// Atomically release lock and sleep on chan.
// Reacquires lock when awakened.
void sleep(void *chan, struct spinlock *lk) {
void
sleep(void *chan, struct spinlock *lk)
{
struct proc *p = myproc();
// Must acquire p->lock in order to
@ -500,7 +544,7 @@ void sleep(void *chan, struct spinlock *lk) {
// (wakeup locks p->lock),
// so it's okay to release lk.
acquire(&p->lock); // DOC: sleeplock1
acquire(&p->lock); //DOC: sleeplock1
release(lk);
// Go to sleep.
@ -519,13 +563,15 @@ void sleep(void *chan, struct spinlock *lk) {
// Wake up all processes sleeping on chan.
// Must be called without any p->lock.
void wakeup(void *chan) {
void
wakeup(void *chan)
{
struct proc *p;
for (p = proc; p < &proc[NPROC]; p++) {
if (p != myproc()) {
for(p = proc; p < &proc[NPROC]; p++) {
if(p != myproc()){
acquire(&p->lock);
if (p->state == SLEEPING && p->chan == chan) {
if(p->state == SLEEPING && p->chan == chan) {
p->state = RUNNABLE;
}
release(&p->lock);
@ -536,14 +582,16 @@ void wakeup(void *chan) {
// Kill the process with the given pid.
// The victim won't exit until it tries to return
// to user space (see usertrap() in trap.c).
int kill(int pid) {
int
kill(int pid)
{
struct proc *p;
for (p = proc; p < &proc[NPROC]; p++) {
for(p = proc; p < &proc[NPROC]; p++){
acquire(&p->lock);
if (p->pid == pid) {
if(p->pid == pid){
p->killed = 1;
if (p->state == SLEEPING) {
if(p->state == SLEEPING){
// Wake process from sleep().
p->state = RUNNABLE;
}
@ -555,13 +603,17 @@ int kill(int pid) {
return -1;
}
void setkilled(struct proc *p) {
void
setkilled(struct proc *p)
{
acquire(&p->lock);
p->killed = 1;
release(&p->lock);
}
int killed(struct proc *p) {
int
killed(struct proc *p)
{
int k;
acquire(&p->lock);
@ -573,9 +625,11 @@ int killed(struct proc *p) {
// Copy to either a user address, or kernel address,
// depending on usr_dst.
// Returns 0 on success, -1 on error.
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len) {
int
either_copyout(int user_dst, uint64 dst, void *src, uint64 len)
{
struct proc *p = myproc();
if (user_dst) {
if(user_dst){
return copyout(p->pagetable, dst, src, len);
} else {
memmove((char *)dst, src, len);
@ -586,12 +640,14 @@ int either_copyout(int user_dst, uint64 dst, void *src, uint64 len) {
// Copy from either a user address, or kernel address,
// depending on usr_src.
// Returns 0 on success, -1 on error.
int either_copyin(void *dst, int user_src, uint64 src, uint64 len) {
int
either_copyin(void *dst, int user_src, uint64 src, uint64 len)
{
struct proc *p = myproc();
if (user_src) {
if(user_src){
return copyin(p->pagetable, dst, src, len);
} else {
memmove(dst, (char *)src, len);
memmove(dst, (char*)src, len);
return 0;
}
}
@ -599,18 +655,25 @@ int either_copyin(void *dst, int user_src, uint64 src, uint64 len) {
// Print a process listing to console. For debugging.
// Runs when user types ^P on console.
// No lock to avoid wedging a stuck machine further.
void procdump(void) {
void
procdump(void)
{
static char *states[] = {
[UNUSED] "unused", [USED] "used", [SLEEPING] "sleep ",
[RUNNABLE] "runble", [RUNNING] "run ", [ZOMBIE] "zombie"};
[UNUSED] "unused",
[USED] "used",
[SLEEPING] "sleep ",
[RUNNABLE] "runble",
[RUNNING] "run ",
[ZOMBIE] "zombie"
};
struct proc *p;
char *state;
printf("\n");
for (p = proc; p < &proc[NPROC]; p++) {
if (p->state == UNUSED)
for(p = proc; p < &proc[NPROC]; p++){
if(p->state == UNUSED)
continue;
if (p->state >= 0 && p->state < NELEM(states) && states[p->state])
if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
state = states[p->state];
else
state = "???";

View File

@ -12,23 +12,28 @@
#include "fs.h"
#include "buf.h"
void ramdiskinit(void) {}
void
ramdiskinit(void)
{
}
// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
// Else if B_VALID is not set, read buf from disk, set B_VALID.
void ramdiskrw(struct buf *b) {
if (!holdingsleep(&b->lock))
void
ramdiskrw(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("ramdiskrw: buf not locked");
if ((b->flags & (B_VALID | B_DIRTY)) == B_VALID)
if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
panic("ramdiskrw: nothing to do");
if (b->blockno >= FSSIZE)
if(b->blockno >= FSSIZE)
panic("ramdiskrw: blockno too big");
uint64 diskaddr = b->blockno * BSIZE;
char *addr = (char *)RAMDISK + diskaddr;
if (b->flags & B_DIRTY) {
if(b->flags & B_DIRTY){
// write
memmove(addr, b->data, BSIZE);
b->flags &= ~B_DIRTY;

View File

@ -9,14 +9,18 @@
#include "proc.h"
#include "sleeplock.h"
void initsleeplock(struct sleeplock *lk, char *name) {
void
initsleeplock(struct sleeplock *lk, char *name)
{
initlock(&lk->lk, "sleep lock");
lk->name = name;
lk->locked = 0;
lk->pid = 0;
}
void acquiresleep(struct sleeplock *lk) {
void
acquiresleep(struct sleeplock *lk)
{
acquire(&lk->lk);
while (lk->locked) {
sleep(lk, &lk->lk);
@ -26,7 +30,9 @@ void acquiresleep(struct sleeplock *lk) {
release(&lk->lk);
}
void releasesleep(struct sleeplock *lk) {
void
releasesleep(struct sleeplock *lk)
{
acquire(&lk->lk);
lk->locked = 0;
lk->pid = 0;
@ -34,7 +40,9 @@ void releasesleep(struct sleeplock *lk) {
release(&lk->lk);
}
int holdingsleep(struct sleeplock *lk) {
int
holdingsleep(struct sleeplock *lk)
{
int r;
acquire(&lk->lk);
@ -42,3 +50,6 @@ int holdingsleep(struct sleeplock *lk) {
release(&lk->lk);
return r;
}

View File

@ -8,7 +8,9 @@
#include "proc.h"
#include "defs.h"
void initlock(struct spinlock *lk, char *name) {
void
initlock(struct spinlock *lk, char *name)
{
lk->name = name;
lk->locked = 0;
lk->cpu = 0;
@ -16,16 +18,18 @@ void initlock(struct spinlock *lk, char *name) {
// Acquire the lock.
// Loops (spins) until the lock is acquired.
void acquire(struct spinlock *lk) {
void
acquire(struct spinlock *lk)
{
push_off(); // disable interrupts to avoid deadlock.
if (holding(lk))
if(holding(lk))
panic("acquire");
// On RISC-V, sync_lock_test_and_set turns into an atomic swap:
// a5 = 1
// s1 = &lk->locked
// amoswap.w.aq a5, a5, (s1)
while (__sync_lock_test_and_set(&lk->locked, 1) != 0)
while(__sync_lock_test_and_set(&lk->locked, 1) != 0)
;
// Tell the C compiler and the processor to not move loads or stores
@ -39,8 +43,10 @@ void acquire(struct spinlock *lk) {
}
// Release the lock.
void release(struct spinlock *lk) {
if (!holding(lk))
void
release(struct spinlock *lk)
{
if(!holding(lk))
panic("release");
lk->cpu = 0;
@ -67,7 +73,9 @@ void release(struct spinlock *lk) {
// Check whether this cpu is holding the lock.
// Interrupts must be off.
int holding(struct spinlock *lk) {
int
holding(struct spinlock *lk)
{
int r;
r = (lk->locked && lk->cpu == mycpu());
return r;
@ -77,22 +85,26 @@ int holding(struct spinlock *lk) {
// it takes two pop_off()s to undo two push_off()s. Also, if interrupts
// are initially off, then push_off, pop_off leaves them off.
void push_off(void) {
void
push_off(void)
{
int old = intr_get();
intr_off();
if (mycpu()->noff == 0)
if(mycpu()->noff == 0)
mycpu()->intena = old;
mycpu()->noff += 1;
}
void pop_off(void) {
void
pop_off(void)
{
struct cpu *c = mycpu();
if (intr_get())
if(intr_get())
panic("pop_off - interruptible");
if (c->noff < 1)
if(c->noff < 1)
panic("pop_off");
c->noff -= 1;
if (c->noff == 0 && c->intena)
if(c->noff == 0 && c->intena)
intr_on();
}

View File

@ -8,7 +8,7 @@ void main();
void timerinit();
// entry.S needs one stack per CPU.
__attribute__((aligned(16))) char stack0[4096 * NCPU];
__attribute__ ((aligned (16))) char stack0[4096 * NCPU];
// a scratch area per CPU for machine-mode timer interrupts.
uint64 timer_scratch[NCPU][5];
@ -17,7 +17,9 @@ uint64 timer_scratch[NCPU][5];
extern void timervec();
// entry.S jumps here in machine mode on stack0.
void start() {
void
start()
{
// set M Previous Privilege mode to Supervisor, for mret.
unsigned long x = r_mstatus();
x &= ~MSTATUS_MPP_MASK;
@ -57,13 +59,15 @@ void start() {
// at timervec in kernelvec.S,
// which turns them into software interrupts for
// devintr() in trap.c.
void timerinit() {
void
timerinit()
{
// each CPU has a separate source of timer interrupts.
int id = r_mhartid();
// ask the CLINT for a timer interrupt.
int interval = 1000000; // cycles; about 1/10th second in qemu.
*(uint64 *)CLINT_MTIMECMP(id) = *(uint64 *)CLINT_MTIME + interval;
*(uint64*)CLINT_MTIMECMP(id) = *(uint64*)CLINT_MTIME + interval;
// prepare information in scratch[] for timervec.
// scratch[0..2] : space for timervec to save registers.

View File

@ -1,21 +1,25 @@
#include "types.h"
void *memset(void *dst, int c, uint n) {
char *cdst = (char *)dst;
void*
memset(void *dst, int c, uint n)
{
char *cdst = (char *) dst;
int i;
for (i = 0; i < n; i++) {
for(i = 0; i < n; i++){
cdst[i] = c;
}
return dst;
}
int memcmp(const void *v1, const void *v2, uint n) {
int
memcmp(const void *v1, const void *v2, uint n)
{
const uchar *s1, *s2;
s1 = v1;
s2 = v2;
while (n-- > 0) {
if (*s1 != *s2)
while(n-- > 0){
if(*s1 != *s2)
return *s1 - *s2;
s1++, s2++;
}
@ -23,68 +27,81 @@ int memcmp(const void *v1, const void *v2, uint n) {
return 0;
}
void *memmove(void *dst, const void *src, uint n) {
void*
memmove(void *dst, const void *src, uint n)
{
const char *s;
char *d;
if (n == 0)
if(n == 0)
return dst;
s = src;
d = dst;
if (s < d && s + n > d) {
if(s < d && s + n > d){
s += n;
d += n;
while (n-- > 0)
while(n-- > 0)
*--d = *--s;
} else
while (n-- > 0)
while(n-- > 0)
*d++ = *s++;
return dst;
}
// memcpy exists to placate GCC. Use memmove.
void *memcpy(void *dst, const void *src, uint n) {
void*
memcpy(void *dst, const void *src, uint n)
{
return memmove(dst, src, n);
}
int strncmp(const char *p, const char *q, uint n) {
while (n > 0 && *p && *p == *q)
int
strncmp(const char *p, const char *q, uint n)
{
while(n > 0 && *p && *p == *q)
n--, p++, q++;
if (n == 0)
if(n == 0)
return 0;
return (uchar)*p - (uchar)*q;
}
char *strncpy(char *s, const char *t, int n) {
char*
strncpy(char *s, const char *t, int n)
{
char *os;
os = s;
while (n-- > 0 && (*s++ = *t++) != 0)
while(n-- > 0 && (*s++ = *t++) != 0)
;
while (n-- > 0)
while(n-- > 0)
*s++ = 0;
return os;
}
// Like strncpy but guaranteed to NUL-terminate.
char *safestrcpy(char *s, const char *t, int n) {
char*
safestrcpy(char *s, const char *t, int n)
{
char *os;
os = s;
if (n <= 0)
if(n <= 0)
return os;
while (--n > 0 && (*s++ = *t++) != 0)
while(--n > 0 && (*s++ = *t++) != 0)
;
*s = 0;
return os;
}
int strlen(const char *s) {
int
strlen(const char *s)
{
int n;
for (n = 0; s[n]; n++)
for(n = 0; s[n]; n++)
;
return n;
}

View File

@ -8,26 +8,31 @@
#include "defs.h"
// Fetch the uint64 at addr from the current process.
int fetchaddr(uint64 addr, uint64 *ip) {
int
fetchaddr(uint64 addr, uint64 *ip)
{
struct proc *p = myproc();
if (addr >= p->sz ||
addr + sizeof(uint64) > p->sz) // both tests needed, in case of overflow
if(addr >= p->sz || addr+sizeof(uint64) > p->sz) // both tests needed, in case of overflow
return -1;
if (copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
return -1;
return 0;
}
// Fetch the nul-terminated string at addr from the current process.
// Returns length of string, not including nul, or -1 for error.
int fetchstr(uint64 addr, char *buf, int max) {
int
fetchstr(uint64 addr, char *buf, int max)
{
struct proc *p = myproc();
if (copyinstr(p->pagetable, buf, addr, max) < 0)
if(copyinstr(p->pagetable, buf, addr, max) < 0)
return -1;
return strlen(buf);
}
static uint64 argraw(int n) {
static uint64
argraw(int n)
{
struct proc *p = myproc();
switch (n) {
case 0:
@ -48,23 +53,32 @@ static uint64 argraw(int n) {
}
// Fetch the nth 32-bit system call argument.
void argint(int n, int *ip) { *ip = argraw(n); }
void
argint(int n, int *ip)
{
*ip = argraw(n);
}
// Retrieve an argument as a pointer.
// Doesn't check for legality, since
// copyin/copyout will do that.
void argaddr(int n, uint64 *ip) { *ip = argraw(n); }
void
argaddr(int n, uint64 *ip)
{
*ip = argraw(n);
}
// Fetch the nth word-sized system call argument as a null-terminated string.
// Copies into buf, at most max.
// Returns string length if OK (including nul), -1 if error.
int argstr(int n, char *buf, int max) {
int
argstr(int n, char *buf, int max)
{
uint64 addr;
argaddr(n, &addr);
return fetchstr(addr, buf, max);
}
// Prototypes for the functions that handle system calls.
extern uint64 sys_fork(void);
extern uint64 sys_exit(void);
extern uint64 sys_wait(void);
@ -87,29 +101,42 @@ extern uint64 sys_link(void);
extern uint64 sys_mkdir(void);
extern uint64 sys_close(void);
// An array mapping syscall numbers from syscall.h
// to the function that handles the system call.
static uint64 (*syscalls[])(void) = {
[SYS_fork] sys_fork, [SYS_exit] sys_exit, [SYS_wait] sys_wait,
[SYS_pipe] sys_pipe, [SYS_read] sys_read, [SYS_kill] sys_kill,
[SYS_exec] sys_exec, [SYS_fstat] sys_fstat, [SYS_chdir] sys_chdir,
[SYS_dup] sys_dup, [SYS_getpid] sys_getpid, [SYS_sbrk] sys_sbrk,
[SYS_sleep] sys_sleep, [SYS_uptime] sys_uptime, [SYS_open] sys_open,
[SYS_write] sys_write, [SYS_mknod] sys_mknod, [SYS_unlink] sys_unlink,
[SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close,
[SYS_fork] sys_fork,
[SYS_exit] sys_exit,
[SYS_wait] sys_wait,
[SYS_pipe] sys_pipe,
[SYS_read] sys_read,
[SYS_kill] sys_kill,
[SYS_exec] sys_exec,
[SYS_fstat] sys_fstat,
[SYS_chdir] sys_chdir,
[SYS_dup] sys_dup,
[SYS_getpid] sys_getpid,
[SYS_sbrk] sys_sbrk,
[SYS_sleep] sys_sleep,
[SYS_uptime] sys_uptime,
[SYS_open] sys_open,
[SYS_write] sys_write,
[SYS_mknod] sys_mknod,
[SYS_unlink] sys_unlink,
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
};
void syscall(void) {
void
syscall(void)
{
int num;
struct proc *p = myproc();
num = p->trapframe->a7;
if (num > 0 && num < NELEM(syscalls) && syscalls[num]) {
// Use num to lookup the system call function for num, call it,
// and store its return value in p->trapframe->a0
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
p->trapframe->a0 = syscalls[num]();
} else {
printf("%d %s: unknown sys call %d\n", p->pid, p->name, num);
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}

View File

@ -18,28 +18,32 @@
// Fetch the nth word-sized system call argument as a file descriptor
// and return both the descriptor and the corresponding struct file.
static int argfd(int n, int *pfd, struct file **pf) {
static int
argfd(int n, int *pfd, struct file **pf)
{
int fd;
struct file *f;
argint(n, &fd);
if (fd < 0 || fd >= NOFILE || (f = myproc()->ofile[fd]) == 0)
if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)
return -1;
if (pfd)
if(pfd)
*pfd = fd;
if (pf)
if(pf)
*pf = f;
return 0;
}
// Allocate a file descriptor for the given file.
// Takes over file reference from caller on success.
static int fdalloc(struct file *f) {
static int
fdalloc(struct file *f)
{
int fd;
struct proc *p = myproc();
for (fd = 0; fd < NOFILE; fd++) {
if (p->ofile[fd] == 0) {
for(fd = 0; fd < NOFILE; fd++){
if(p->ofile[fd] == 0){
p->ofile[fd] = f;
return fd;
}
@ -47,80 +51,92 @@ static int fdalloc(struct file *f) {
return -1;
}
uint64 sys_dup(void) {
uint64
sys_dup(void)
{
struct file *f;
int fd;
if (argfd(0, 0, &f) < 0)
if(argfd(0, 0, &f) < 0)
return -1;
if ((fd = fdalloc(f)) < 0)
if((fd=fdalloc(f)) < 0)
return -1;
filedup(f);
return fd;
}
uint64 sys_read(void) {
uint64
sys_read(void)
{
struct file *f;
int n;
uint64 p;
argaddr(1, &p);
argint(2, &n);
if (argfd(0, 0, &f) < 0)
if(argfd(0, 0, &f) < 0)
return -1;
return fileread(f, p, n);
}
uint64 sys_write(void) {
uint64
sys_write(void)
{
struct file *f;
int n;
uint64 p;
argaddr(1, &p);
argint(2, &n);
if (argfd(0, 0, &f) < 0)
if(argfd(0, 0, &f) < 0)
return -1;
return filewrite(f, p, n);
}
uint64 sys_close(void) {
uint64
sys_close(void)
{
int fd;
struct file *f;
if (argfd(0, &fd, &f) < 0)
if(argfd(0, &fd, &f) < 0)
return -1;
myproc()->ofile[fd] = 0;
fileclose(f);
return 0;
}
uint64 sys_fstat(void) {
uint64
sys_fstat(void)
{
struct file *f;
uint64 st; // user pointer to struct stat
argaddr(1, &st);
if (argfd(0, 0, &f) < 0)
if(argfd(0, 0, &f) < 0)
return -1;
return filestat(f, st);
}
// Create the path new as a link to the same inode as old.
uint64 sys_link(void) {
uint64
sys_link(void)
{
char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
struct inode *dp, *ip;
if (argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
return -1;
begin_op();
if ((ip = namei(old)) == 0) {
if((ip = namei(old)) == 0){
end_op();
return -1;
}
ilock(ip);
if (ip->type == T_DIR) {
if(ip->type == T_DIR){
iunlockput(ip);
end_op();
return -1;
@ -130,10 +146,10 @@ uint64 sys_link(void) {
iupdate(ip);
iunlock(ip);
if ((dp = nameiparent(new, name)) == 0)
if((dp = nameiparent(new, name)) == 0)
goto bad;
ilock(dp);
if (dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0) {
if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
iunlockput(dp);
goto bad;
}
@ -154,30 +170,34 @@ bad:
}
// Is the directory dp empty except for "." and ".." ?
static int isdirempty(struct inode *dp) {
static int
isdirempty(struct inode *dp)
{
int off;
struct dirent de;
for (off = 2 * sizeof(de); off < dp->size; off += sizeof(de)) {
if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
panic("isdirempty: readi");
if (de.inum != 0)
if(de.inum != 0)
return 0;
}
return 1;
}
uint64 sys_unlink(void) {
uint64
sys_unlink(void)
{
struct inode *ip, *dp;
struct dirent de;
char name[DIRSIZ], path[MAXPATH];
uint off;
if (argstr(0, path, MAXPATH) < 0)
if(argstr(0, path, MAXPATH) < 0)
return -1;
begin_op();
if ((dp = nameiparent(path, name)) == 0) {
if((dp = nameiparent(path, name)) == 0){
end_op();
return -1;
}
@ -185,24 +205,24 @@ uint64 sys_unlink(void) {
ilock(dp);
// Cannot unlink "." or "..".
if (namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
goto bad;
if ((ip = dirlookup(dp, name, &off)) == 0)
if((ip = dirlookup(dp, name, &off)) == 0)
goto bad;
ilock(ip);
if (ip->nlink < 1)
if(ip->nlink < 1)
panic("unlink: nlink < 1");
if (ip->type == T_DIR && !isdirempty(ip)) {
if(ip->type == T_DIR && !isdirempty(ip)){
iunlockput(ip);
goto bad;
}
memset(&de, 0, sizeof(de));
if (writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
panic("unlink: writei");
if (ip->type == T_DIR) {
if(ip->type == T_DIR){
dp->nlink--;
iupdate(dp);
}
@ -222,25 +242,27 @@ bad:
return -1;
}
static struct inode *create(char *path, short type, short major, short minor) {
static struct inode*
create(char *path, short type, short major, short minor)
{
struct inode *ip, *dp;
char name[DIRSIZ];
if ((dp = nameiparent(path, name)) == 0)
if((dp = nameiparent(path, name)) == 0)
return 0;
ilock(dp);
if ((ip = dirlookup(dp, name, 0)) != 0) {
if((ip = dirlookup(dp, name, 0)) != 0){
iunlockput(dp);
ilock(ip);
if (type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
return ip;
iunlockput(ip);
return 0;
}
if ((ip = ialloc(dp->dev, type)) == 0) {
if((ip = ialloc(dp->dev, type)) == 0){
iunlockput(dp);
return 0;
}
@ -251,16 +273,16 @@ static struct inode *create(char *path, short type, short major, short minor) {
ip->nlink = 1;
iupdate(ip);
if (type == T_DIR) { // Create . and .. entries.
if(type == T_DIR){ // Create . and .. entries.
// No ip->nlink++ for ".": avoid cyclic ref count.
if (dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
goto fail;
}
if (dirlink(dp, name, ip->inum) < 0)
if(dirlink(dp, name, ip->inum) < 0)
goto fail;
if (type == T_DIR) {
if(type == T_DIR){
// now that success is guaranteed:
dp->nlink++; // for ".."
iupdate(dp);
@ -270,7 +292,7 @@ static struct inode *create(char *path, short type, short major, short minor) {
return ip;
fail:
fail:
// something went wrong. de-allocate ip.
ip->nlink = 0;
iupdate(ip);
@ -279,7 +301,9 @@ fail:
return 0;
}
uint64 sys_open(void) {
uint64
sys_open(void)
{
char path[MAXPATH];
int fd, omode;
struct file *f;
@ -287,45 +311,45 @@ uint64 sys_open(void) {
int n;
argint(1, &omode);
if ((n = argstr(0, path, MAXPATH)) < 0)
if((n = argstr(0, path, MAXPATH)) < 0)
return -1;
begin_op();
if (omode & O_CREATE) {
if(omode & O_CREATE){
ip = create(path, T_FILE, 0, 0);
if (ip == 0) {
if(ip == 0){
end_op();
return -1;
}
} else {
if ((ip = namei(path)) == 0) {
if((ip = namei(path)) == 0){
end_op();
return -1;
}
ilock(ip);
if (ip->type == T_DIR && omode != O_RDONLY) {
if(ip->type == T_DIR && omode != O_RDONLY){
iunlockput(ip);
end_op();
return -1;
}
}
if (ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)) {
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
iunlockput(ip);
end_op();
return -1;
}
if ((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0) {
if (f)
if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
if(f)
fileclose(f);
iunlockput(ip);
end_op();
return -1;
}
if (ip->type == T_DEVICE) {
if(ip->type == T_DEVICE){
f->type = FD_DEVICE;
f->major = ip->major;
} else {
@ -336,7 +360,7 @@ uint64 sys_open(void) {
f->readable = !(omode & O_WRONLY);
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
if ((omode & O_TRUNC) && ip->type == T_FILE) {
if((omode & O_TRUNC) && ip->type == T_FILE){
itrunc(ip);
}
@ -346,12 +370,14 @@ uint64 sys_open(void) {
return fd;
}
uint64 sys_mkdir(void) {
uint64
sys_mkdir(void)
{
char path[MAXPATH];
struct inode *ip;
begin_op();
if (argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0) {
if(argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
end_op();
return -1;
}
@ -360,7 +386,9 @@ uint64 sys_mkdir(void) {
return 0;
}
uint64 sys_mknod(void) {
uint64
sys_mknod(void)
{
struct inode *ip;
char path[MAXPATH];
int major, minor;
@ -368,8 +396,8 @@ uint64 sys_mknod(void) {
begin_op();
argint(1, &major);
argint(2, &minor);
if ((argstr(0, path, MAXPATH)) < 0 ||
(ip = create(path, T_DEVICE, major, minor)) == 0) {
if((argstr(0, path, MAXPATH)) < 0 ||
(ip = create(path, T_DEVICE, major, minor)) == 0){
end_op();
return -1;
}
@ -378,18 +406,20 @@ uint64 sys_mknod(void) {
return 0;
}
uint64 sys_chdir(void) {
uint64
sys_chdir(void)
{
char path[MAXPATH];
struct inode *ip;
struct proc *p = myproc();
begin_op();
if (argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0) {
if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0){
end_op();
return -1;
}
ilock(ip);
if (ip->type != T_DIR) {
if(ip->type != T_DIR){
iunlockput(ip);
end_op();
return -1;
@ -401,67 +431,70 @@ uint64 sys_chdir(void) {
return 0;
}
uint64 sys_exec(void) {
uint64
sys_exec(void)
{
char path[MAXPATH], *argv[MAXARG];
int i;
uint64 uargv, uarg;
argaddr(1, &uargv);
if (argstr(0, path, MAXPATH) < 0) {
if(argstr(0, path, MAXPATH) < 0) {
return -1;
}
memset(argv, 0, sizeof(argv));
for (i = 0;; i++) {
if (i >= NELEM(argv)) {
for(i=0;; i++){
if(i >= NELEM(argv)){
goto bad;
}
if (fetchaddr(uargv + sizeof(uint64) * i, (uint64 *)&uarg) < 0) {
if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){
goto bad;
}
if (uarg == 0) {
if(uarg == 0){
argv[i] = 0;
break;
}
argv[i] = kalloc();
if (argv[i] == 0)
if(argv[i] == 0)
goto bad;
if (fetchstr(uarg, argv[i], PGSIZE) < 0)
if(fetchstr(uarg, argv[i], PGSIZE) < 0)
goto bad;
}
int ret = exec(path, argv);
for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
kfree(argv[i]);
return ret;
bad:
for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
bad:
for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
kfree(argv[i]);
return -1;
}
uint64 sys_pipe(void) {
uint64
sys_pipe(void)
{
uint64 fdarray; // user pointer to array of two integers
struct file *rf, *wf;
int fd0, fd1;
struct proc *p = myproc();
argaddr(0, &fdarray);
if (pipealloc(&rf, &wf) < 0)
if(pipealloc(&rf, &wf) < 0)
return -1;
fd0 = -1;
if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) {
if (fd0 >= 0)
if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
if(fd0 >= 0)
p->ofile[fd0] = 0;
fileclose(rf);
fileclose(wf);
return -1;
}
if (copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(fd0)) < 0 ||
copyout(p->pagetable, fdarray + sizeof(fd0), (char *)&fd1,
sizeof(fd1)) < 0) {
if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 ||
copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){
p->ofile[fd0] = 0;
p->ofile[fd1] = 0;
fileclose(rf);

View File

@ -6,43 +6,59 @@
#include "spinlock.h"
#include "proc.h"
uint64 sys_exit(void) {
uint64
sys_exit(void)
{
int n;
argint(0, &n);
exit(n);
return 0; // not reached
}
uint64 sys_getpid(void) { return myproc()->pid; }
uint64
sys_getpid(void)
{
return myproc()->pid;
}
uint64 sys_fork(void) { return fork(); }
uint64
sys_fork(void)
{
return fork();
}
uint64 sys_wait(void) {
uint64
sys_wait(void)
{
uint64 p;
argaddr(0, &p);
return wait(p);
}
uint64 sys_sbrk(void) {
uint64
sys_sbrk(void)
{
uint64 addr;
int n;
argint(0, &n);
addr = myproc()->sz;
if (growproc(n) < 0)
if(growproc(n) < 0)
return -1;
return addr;
}
uint64 sys_sleep(void) {
uint64
sys_sleep(void)
{
int n;
uint ticks0;
argint(0, &n);
acquire(&tickslock);
ticks0 = ticks;
while (ticks - ticks0 < n) {
if (killed(myproc())) {
while(ticks - ticks0 < n){
if(killed(myproc())){
release(&tickslock);
return -1;
}
@ -52,7 +68,9 @@ uint64 sys_sleep(void) {
return 0;
}
uint64 sys_kill(void) {
uint64
sys_kill(void)
{
int pid;
argint(0, &pid);
@ -61,7 +79,9 @@ uint64 sys_kill(void) {
// return how many clock tick interrupts have occurred
// since start.
uint64 sys_uptime(void) {
uint64
sys_uptime(void)
{
uint xticks;
acquire(&tickslock);

View File

@ -80,18 +80,9 @@ uservec:
# load the address of usertrap(), from p->trapframe->kernel_trap
ld t0, 16(a0)
# fetch the kernel page table address, from p->trapframe->kernel_satp.
# load the kernel page table, from p->trapframe->kernel_satp
ld t1, 0(a0)
# wait for any previous memory operations to complete, so that
# they use the user page table.
sfence.vma zero, zero
# install the kernel page table.
csrw satp, t1
# flush now-stale user entries from the TLB.
sfence.vma zero, zero
# jump to usertrap(), which does not return
@ -105,7 +96,6 @@ userret:
# a0: user page table, for satp.
# switch to the user page table.
sfence.vma zero, zero
csrw satp, a0
sfence.vma zero, zero

View File

@ -16,19 +16,29 @@ void kernelvec();
extern int devintr();
void trapinit(void) { initlock(&tickslock, "time"); }
void
trapinit(void)
{
initlock(&tickslock, "time");
}
// set up to take exceptions and traps while in the kernel.
void trapinithart(void) { w_stvec((uint64)kernelvec); }
void
trapinithart(void)
{
w_stvec((uint64)kernelvec);
}
//
// handle an interrupt, exception, or system call from user space.
// called from trampoline.S
//
void usertrap(void) {
void
usertrap(void)
{
int which_dev = 0;
if ((r_sstatus() & SSTATUS_SPP) != 0)
if((r_sstatus() & SSTATUS_SPP) != 0)
panic("usertrap: not from user mode");
// send interrupts and exceptions to kerneltrap(),
@ -40,10 +50,10 @@ void usertrap(void) {
// save user program counter.
p->trapframe->epc = r_sepc();
if (r_scause() == 8) {
if(r_scause() == 8){
// system call
if (killed(p))
if(killed(p))
exit(-1);
// sepc points to the ecall instruction,
@ -55,7 +65,7 @@ void usertrap(void) {
intr_on();
syscall();
} else if ((which_dev = devintr()) != 0) {
} else if((which_dev = devintr()) != 0){
// ok
} else {
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
@ -63,11 +73,11 @@ void usertrap(void) {
setkilled(p);
}
if (killed(p))
if(killed(p))
exit(-1);
// give up the CPU if this is a timer interrupt.
if (which_dev == 2)
if(which_dev == 2)
yield();
usertrapret();
@ -76,7 +86,9 @@ void usertrap(void) {
//
// return to user space
//
void usertrapret(void) {
void
usertrapret(void)
{
struct proc *p = myproc();
// we're about to switch the destination of traps from
@ -119,25 +131,27 @@ void usertrapret(void) {
// interrupts and exceptions from kernel code go here via kernelvec,
// on whatever the current kernel stack is.
void kerneltrap() {
void
kerneltrap()
{
int which_dev = 0;
uint64 sepc = r_sepc();
uint64 sstatus = r_sstatus();
uint64 scause = r_scause();
if ((sstatus & SSTATUS_SPP) == 0)
if((sstatus & SSTATUS_SPP) == 0)
panic("kerneltrap: not from supervisor mode");
if (intr_get() != 0)
if(intr_get() != 0)
panic("kerneltrap: interrupts enabled");
if ((which_dev = devintr()) == 0) {
if((which_dev = devintr()) == 0){
printf("scause %p\n", scause);
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
panic("kerneltrap");
}
// give up the CPU if this is a timer interrupt.
if (which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING)
if(which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING)
yield();
// the yield() may have caused some traps to occur,
@ -146,7 +160,9 @@ void kerneltrap() {
w_sstatus(sstatus);
}
void clockintr() {
void
clockintr()
{
acquire(&tickslock);
ticks++;
wakeup(&ticks);
@ -158,35 +174,38 @@ void clockintr() {
// returns 2 if timer interrupt,
// 1 if other device,
// 0 if not recognized.
int devintr() {
int
devintr()
{
uint64 scause = r_scause();
if ((scause & 0x8000000000000000L) && (scause & 0xff) == 9) {
if((scause & 0x8000000000000000L) &&
(scause & 0xff) == 9){
// this is a supervisor external interrupt, via PLIC.
// irq indicates which device interrupted.
int irq = plic_claim();
if (irq == UART0_IRQ) {
if(irq == UART0_IRQ){
uartintr();
} else if (irq == VIRTIO0_IRQ) {
} else if(irq == VIRTIO0_IRQ){
virtio_disk_intr();
} else if (irq) {
} else if(irq){
printf("unexpected interrupt irq=%d\n", irq);
}
// the PLIC allows each device to raise at most one
// interrupt at a time; tell the PLIC the device is
// now allowed to interrupt again.
if (irq)
if(irq)
plic_complete(irq);
return 1;
} else if (scause == 0x8000000000000001L) {
} else if(scause == 0x8000000000000001L){
// software interrupt from a machine-mode timer interrupt,
// forwarded by timervec in kernelvec.S.
if (cpuid() == 0) {
if(cpuid() == 0){
clockintr();
}
@ -199,3 +218,4 @@ int devintr() {
return 0;
}
}

View File

@ -22,18 +22,18 @@
#define RHR 0 // receive holding register (for input bytes)
#define THR 0 // transmit holding register (for output bytes)
#define IER 1 // interrupt enable register
#define IER_RX_ENABLE (1 << 0)
#define IER_TX_ENABLE (1 << 1)
#define IER_RX_ENABLE (1<<0)
#define IER_TX_ENABLE (1<<1)
#define FCR 2 // FIFO control register
#define FCR_FIFO_ENABLE (1 << 0)
#define FCR_FIFO_CLEAR (3 << 1) // clear the content of the two FIFOs
#define FCR_FIFO_ENABLE (1<<0)
#define FCR_FIFO_CLEAR (3<<1) // clear the content of the two FIFOs
#define ISR 2 // interrupt status register
#define LCR 3 // line control register
#define LCR_EIGHT_BITS (3 << 0)
#define LCR_BAUD_LATCH (1 << 7) // special mode to set baud rate
#define LCR_EIGHT_BITS (3<<0)
#define LCR_BAUD_LATCH (1<<7) // special mode to set baud rate
#define LSR 5 // line status register
#define LSR_RX_READY (1 << 0) // input is waiting to be read from RHR
#define LSR_TX_IDLE (1 << 5) // THR can accept another character to send
#define LSR_RX_READY (1<<0) // input is waiting to be read from RHR
#define LSR_TX_IDLE (1<<5) // THR can accept another character to send
#define ReadReg(reg) (*(Reg(reg)))
#define WriteReg(reg, v) (*(Reg(reg)) = (v))
@ -49,7 +49,9 @@ extern volatile int panicked; // from printf.c
void uartstart();
void uartinit(void) {
void
uartinit(void)
{
// disable interrupts.
WriteReg(IER, 0x00);
@ -81,14 +83,16 @@ void uartinit(void) {
// because it may block, it can't be called
// from interrupts; it's only suitable for use
// by write().
void uartputc(int c) {
void
uartputc(int c)
{
acquire(&uart_tx_lock);
if (panicked) {
for (;;)
if(panicked){
for(;;)
;
}
while (uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE) {
while(uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE){
// buffer is full.
// wait for uartstart() to open up space in the buffer.
sleep(&uart_tx_r, &uart_tx_lock);
@ -99,20 +103,23 @@ void uartputc(int c) {
release(&uart_tx_lock);
}
// alternate version of uartputc() that doesn't
// use interrupts, for use by kernel printf() and
// to echo characters. it spins waiting for the uart's
// output register to be empty.
void uartputc_sync(int c) {
void
uartputc_sync(int c)
{
push_off();
if (panicked) {
for (;;)
if(panicked){
for(;;)
;
}
// wait for Transmit Holding Empty to be set in LSR.
while ((ReadReg(LSR) & LSR_TX_IDLE) == 0)
while((ReadReg(LSR) & LSR_TX_IDLE) == 0)
;
WriteReg(THR, c);
@ -123,14 +130,16 @@ void uartputc_sync(int c) {
// in the transmit buffer, send it.
// caller must hold uart_tx_lock.
// called from both the top- and bottom-half.
void uartstart() {
while (1) {
if (uart_tx_w == uart_tx_r) {
void
uartstart()
{
while(1){
if(uart_tx_w == uart_tx_r){
// transmit buffer is empty.
return;
}
if ((ReadReg(LSR) & LSR_TX_IDLE) == 0) {
if((ReadReg(LSR) & LSR_TX_IDLE) == 0){
// the UART transmit holding register is full,
// so we cannot give it another byte.
// it will interrupt when it's ready for a new byte.
@ -149,8 +158,10 @@ void uartstart() {
// read one input character from the UART.
// return -1 if none is waiting.
int uartgetc(void) {
if (ReadReg(LSR) & 0x01) {
int
uartgetc(void)
{
if(ReadReg(LSR) & 0x01){
// input data is ready.
return ReadReg(RHR);
} else {
@ -161,11 +172,13 @@ int uartgetc(void) {
// handle a uart interrupt, raised because input has
// arrived, or the uart is ready for more output, or
// both. called from devintr().
void uartintr(void) {
void
uartintr(void)
{
// read and process incoming characters.
while (1) {
while(1){
int c = uartgetc();
if (c == -1)
if(c == -1)
break;
consoleintr(c);
}

View File

@ -2,8 +2,7 @@
// driver for qemu's virtio disk device.
// uses qemu's mmio interface to virtio.
//
// qemu ... -drive file=fs.img,if=none,format=raw,id=x0 -device
// virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
// qemu ... -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
//
#include "types.h"
@ -59,14 +58,17 @@ static struct disk {
} disk;
void virtio_disk_init(void) {
void
virtio_disk_init(void)
{
uint32 status = 0;
initlock(&disk.vdisk_lock, "virtio_disk");
if (*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
*R(VIRTIO_MMIO_VERSION) != 2 || *R(VIRTIO_MMIO_DEVICE_ID) != 2 ||
*R(VIRTIO_MMIO_VENDOR_ID) != 0x554d4551) {
if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
*R(VIRTIO_MMIO_VERSION) != 2 ||
*R(VIRTIO_MMIO_DEVICE_ID) != 2 ||
*R(VIRTIO_MMIO_VENDOR_ID) != 0x554d4551){
panic("could not find virtio disk");
}
@ -98,28 +100,28 @@ void virtio_disk_init(void) {
// re-read status to ensure FEATURES_OK is set.
status = *R(VIRTIO_MMIO_STATUS);
if (!(status & VIRTIO_CONFIG_S_FEATURES_OK))
if(!(status & VIRTIO_CONFIG_S_FEATURES_OK))
panic("virtio disk FEATURES_OK unset");
// initialize queue 0.
*R(VIRTIO_MMIO_QUEUE_SEL) = 0;
// ensure queue 0 is not in use.
if (*R(VIRTIO_MMIO_QUEUE_READY))
if(*R(VIRTIO_MMIO_QUEUE_READY))
panic("virtio disk should not be ready");
// check maximum queue size.
uint32 max = *R(VIRTIO_MMIO_QUEUE_NUM_MAX);
if (max == 0)
if(max == 0)
panic("virtio disk has no queue 0");
if (max < NUM)
if(max < NUM)
panic("virtio disk max queue too short");
// allocate and zero queue memory.
disk.desc = kalloc();
disk.avail = kalloc();
disk.used = kalloc();
if (!disk.desc || !disk.avail || !disk.used)
if(!disk.desc || !disk.avail || !disk.used)
panic("virtio disk kalloc");
memset(disk.desc, 0, PGSIZE);
memset(disk.avail, 0, PGSIZE);
@ -140,7 +142,7 @@ void virtio_disk_init(void) {
*R(VIRTIO_MMIO_QUEUE_READY) = 0x1;
// all NUM descriptors start out unused.
for (int i = 0; i < NUM; i++)
for(int i = 0; i < NUM; i++)
disk.free[i] = 1;
// tell device we're completely ready.
@ -151,9 +153,11 @@ void virtio_disk_init(void) {
}
// find a free descriptor, mark it non-free, return its index.
static int alloc_desc() {
for (int i = 0; i < NUM; i++) {
if (disk.free[i]) {
static int
alloc_desc()
{
for(int i = 0; i < NUM; i++){
if(disk.free[i]){
disk.free[i] = 0;
return i;
}
@ -162,10 +166,12 @@ static int alloc_desc() {
}
// mark a descriptor as free.
static void free_desc(int i) {
if (i >= NUM)
static void
free_desc(int i)
{
if(i >= NUM)
panic("free_desc 1");
if (disk.free[i])
if(disk.free[i])
panic("free_desc 2");
disk.desc[i].addr = 0;
disk.desc[i].len = 0;
@ -176,12 +182,14 @@ static void free_desc(int i) {
}
// free a chain of descriptors.
static void free_chain(int i) {
while (1) {
static void
free_chain(int i)
{
while(1){
int flag = disk.desc[i].flags;
int nxt = disk.desc[i].next;
free_desc(i);
if (flag & VRING_DESC_F_NEXT)
if(flag & VRING_DESC_F_NEXT)
i = nxt;
else
break;
@ -190,11 +198,13 @@ static void free_chain(int i) {
// allocate three descriptors (they need not be contiguous).
// disk transfers always use three descriptors.
static int alloc3_desc(int *idx) {
for (int i = 0; i < 3; i++) {
static int
alloc3_desc(int *idx)
{
for(int i = 0; i < 3; i++){
idx[i] = alloc_desc();
if (idx[i] < 0) {
for (int j = 0; j < i; j++)
if(idx[i] < 0){
for(int j = 0; j < i; j++)
free_desc(idx[j]);
return -1;
}
@ -202,7 +212,9 @@ static int alloc3_desc(int *idx) {
return 0;
}
void virtio_disk_rw(struct buf *b, int write) {
void
virtio_disk_rw(struct buf *b, int write)
{
uint64 sector = b->blockno * (BSIZE / 512);
acquire(&disk.vdisk_lock);
@ -213,8 +225,8 @@ void virtio_disk_rw(struct buf *b, int write) {
// allocate the three descriptors.
int idx[3];
while (1) {
if (alloc3_desc(idx) == 0) {
while(1){
if(alloc3_desc(idx) == 0) {
break;
}
sleep(&disk.free[0], &disk.vdisk_lock);
@ -225,21 +237,21 @@ void virtio_disk_rw(struct buf *b, int write) {
struct virtio_blk_req *buf0 = &disk.ops[idx[0]];
if (write)
if(write)
buf0->type = VIRTIO_BLK_T_OUT; // write the disk
else
buf0->type = VIRTIO_BLK_T_IN; // read the disk
buf0->reserved = 0;
buf0->sector = sector;
disk.desc[idx[0]].addr = (uint64)buf0;
disk.desc[idx[0]].addr = (uint64) buf0;
disk.desc[idx[0]].len = sizeof(struct virtio_blk_req);
disk.desc[idx[0]].flags = VRING_DESC_F_NEXT;
disk.desc[idx[0]].next = idx[1];
disk.desc[idx[1]].addr = (uint64)b->data;
disk.desc[idx[1]].addr = (uint64) b->data;
disk.desc[idx[1]].len = BSIZE;
if (write)
if(write)
disk.desc[idx[1]].flags = 0; // device reads b->data
else
disk.desc[idx[1]].flags = VRING_DESC_F_WRITE; // device writes b->data
@ -247,7 +259,7 @@ void virtio_disk_rw(struct buf *b, int write) {
disk.desc[idx[1]].next = idx[2];
disk.info[idx[0]].status = 0xff; // device writes 0 on success
disk.desc[idx[2]].addr = (uint64)&disk.info[idx[0]].status;
disk.desc[idx[2]].addr = (uint64) &disk.info[idx[0]].status;
disk.desc[idx[2]].len = 1;
disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status
disk.desc[idx[2]].next = 0;
@ -269,7 +281,7 @@ void virtio_disk_rw(struct buf *b, int write) {
*R(VIRTIO_MMIO_QUEUE_NOTIFY) = 0; // value is queue number
// Wait for virtio_disk_intr() to say request has finished.
while (b->disk == 1) {
while(b->disk == 1) {
sleep(b, &disk.vdisk_lock);
}
@ -279,7 +291,9 @@ void virtio_disk_rw(struct buf *b, int write) {
release(&disk.vdisk_lock);
}
void virtio_disk_intr() {
void
virtio_disk_intr()
{
acquire(&disk.vdisk_lock);
// the device won't raise another interrupt until we tell it
@ -295,11 +309,11 @@ void virtio_disk_intr() {
// the device increments disk.used->idx when it
// adds an entry to the used ring.
while (disk.used_idx != disk.used->idx) {
while(disk.used_idx != disk.used->idx){
__sync_synchronize();
int id = disk.used->ring[disk.used_idx % NUM].id;
if (disk.info[id].status != 0)
if(disk.info[id].status != 0)
panic("virtio_disk_intr status");
struct buf *b = disk.info[id].b;

View File

@ -16,10 +16,12 @@ extern char etext[]; // kernel.ld sets this to end of kernel code.
extern char trampoline[]; // trampoline.S
// Make a direct-map page table for the kernel.
pagetable_t kvmmake(void) {
pagetable_t
kvmmake(void)
{
pagetable_t kpgtbl;
kpgtbl = (pagetable_t)kalloc();
kpgtbl = (pagetable_t) kalloc();
memset(kpgtbl, 0, PGSIZE);
// uart registers
@ -32,11 +34,10 @@ pagetable_t kvmmake(void) {
kvmmap(kpgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W);
// map kernel text executable and read-only.
kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext - KERNBASE, PTE_R | PTE_X);
kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
// map kernel data and the physical RAM we'll make use of.
kvmmap(kpgtbl, (uint64)etext, (uint64)etext, PHYSTOP - (uint64)etext,
PTE_R | PTE_W);
kvmmap(kpgtbl, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W);
// map the trampoline for trap entry/exit to
// the highest virtual address in the kernel.
@ -49,17 +50,18 @@ pagetable_t kvmmake(void) {
}
// Initialize the one kernel_pagetable
void kvminit(void) { kernel_pagetable = kvmmake(); }
void
kvminit(void)
{
kernel_pagetable = kvmmake();
}
// Switch h/w page table register to the kernel's page table,
// and enable paging.
void kvminithart() {
// wait for any previous writes to the page table memory to finish.
sfence_vma();
void
kvminithart()
{
w_satp(MAKE_SATP(kernel_pagetable));
// flush stale entries from the TLB.
sfence_vma();
}
@ -75,16 +77,18 @@ void kvminithart() {
// 21..29 -- 9 bits of level-1 index.
// 12..20 -- 9 bits of level-0 index.
// 0..11 -- 12 bits of byte offset within the page.
pte_t *walk(pagetable_t pagetable, uint64 va, int alloc) {
if (va >= MAXVA)
pte_t *
walk(pagetable_t pagetable, uint64 va, int alloc)
{
if(va >= MAXVA)
panic("walk");
for (int level = 2; level > 0; level--) {
for(int level = 2; level > 0; level--) {
pte_t *pte = &pagetable[PX(level, va)];
if (*pte & PTE_V) {
if(*pte & PTE_V) {
pagetable = (pagetable_t)PTE2PA(*pte);
} else {
if (!alloc || (pagetable = (pde_t *)kalloc()) == 0)
if(!alloc || (pagetable = (pde_t*)kalloc()) == 0)
return 0;
memset(pagetable, 0, PGSIZE);
*pte = PA2PTE(pagetable) | PTE_V;
@ -96,19 +100,21 @@ pte_t *walk(pagetable_t pagetable, uint64 va, int alloc) {
// Look up a virtual address, return the physical address,
// or 0 if not mapped.
// Can only be used to look up user pages.
uint64 walkaddr(pagetable_t pagetable, uint64 va) {
uint64
walkaddr(pagetable_t pagetable, uint64 va)
{
pte_t *pte;
uint64 pa;
if (va >= MAXVA)
if(va >= MAXVA)
return 0;
pte = walk(pagetable, va, 0);
if (pte == 0)
if(pte == 0)
return 0;
if ((*pte & PTE_V) == 0)
if((*pte & PTE_V) == 0)
return 0;
if ((*pte & PTE_U) == 0)
if((*pte & PTE_U) == 0)
return 0;
pa = PTE2PA(*pte);
return pa;
@ -117,8 +123,10 @@ uint64 walkaddr(pagetable_t pagetable, uint64 va) {
// add a mapping to the kernel page table.
// only used when booting.
// does not flush TLB or enable paging.
void kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm) {
if (mappages(kpgtbl, va, sz, pa, perm) != 0)
void
kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm)
{
if(mappages(kpgtbl, va, sz, pa, perm) != 0)
panic("kvmmap");
}
@ -126,23 +134,24 @@ void kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm) {
// physical addresses starting at pa. va and size might not
// be page-aligned. Returns 0 on success, -1 if walk() couldn't
// allocate a needed page-table page.
int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa,
int perm) {
int
mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
{
uint64 a, last;
pte_t *pte;
if (size == 0)
if(size == 0)
panic("mappages: size");
a = PGROUNDDOWN(va);
last = PGROUNDDOWN(va + size - 1);
for (;;) {
if ((pte = walk(pagetable, a, 1)) == 0)
for(;;){
if((pte = walk(pagetable, a, 1)) == 0)
return -1;
if (*pte & PTE_V)
if(*pte & PTE_V)
panic("mappages: remap");
*pte = PA2PTE(pa) | perm | PTE_V;
if (a == last)
if(a == last)
break;
a += PGSIZE;
pa += PGSIZE;
@ -153,23 +162,25 @@ int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa,
// Remove npages of mappings starting from va. va must be
// page-aligned. The mappings must exist.
// Optionally free the physical memory.
void uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free) {
void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{
uint64 a;
pte_t *pte;
if ((va % PGSIZE) != 0)
if((va % PGSIZE) != 0)
panic("uvmunmap: not aligned");
for (a = va; a < va + npages * PGSIZE; a += PGSIZE) {
if ((pte = walk(pagetable, a, 0)) == 0)
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
if((pte = walk(pagetable, a, 0)) == 0)
panic("uvmunmap: walk");
if ((*pte & PTE_V) == 0)
if((*pte & PTE_V) == 0)
panic("uvmunmap: not mapped");
if (PTE_FLAGS(*pte) == PTE_V)
if(PTE_FLAGS(*pte) == PTE_V)
panic("uvmunmap: not a leaf");
if (do_free) {
if(do_free){
uint64 pa = PTE2PA(*pte);
kfree((void *)pa);
kfree((void*)pa);
}
*pte = 0;
}
@ -177,10 +188,12 @@ void uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free) {
// create an empty user page table.
// returns 0 if out of memory.
pagetable_t uvmcreate() {
pagetable_t
uvmcreate()
{
pagetable_t pagetable;
pagetable = (pagetable_t)kalloc();
if (pagetable == 0)
pagetable = (pagetable_t) kalloc();
if(pagetable == 0)
return 0;
memset(pagetable, 0, PGSIZE);
return pagetable;
@ -189,36 +202,39 @@ pagetable_t uvmcreate() {
// Load the user initcode into address 0 of pagetable,
// for the very first process.
// sz must be less than a page.
void uvmfirst(pagetable_t pagetable, uchar *src, uint sz) {
void
uvmfirst(pagetable_t pagetable, uchar *src, uint sz)
{
char *mem;
if (sz >= PGSIZE)
if(sz >= PGSIZE)
panic("uvmfirst: more than a page");
mem = kalloc();
memset(mem, 0, PGSIZE);
mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W | PTE_R | PTE_X | PTE_U);
mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U);
memmove(mem, src, sz);
}
// Allocate PTEs and physical memory to grow process from oldsz to
// newsz, which need not be page aligned. Returns new size or 0 on error.
uint64 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm) {
uint64
uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm)
{
char *mem;
uint64 a;
if (newsz < oldsz)
if(newsz < oldsz)
return oldsz;
oldsz = PGROUNDUP(oldsz);
for (a = oldsz; a < newsz; a += PGSIZE) {
for(a = oldsz; a < newsz; a += PGSIZE){
mem = kalloc();
if (mem == 0) {
if(mem == 0){
uvmdealloc(pagetable, a, oldsz);
return 0;
}
memset(mem, 0, PGSIZE);
if (mappages(pagetable, a, PGSIZE, (uint64)mem,
PTE_R | PTE_U | xperm) != 0) {
if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
kfree(mem);
uvmdealloc(pagetable, a, oldsz);
return 0;
@ -231,11 +247,13 @@ uint64 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm) {
// newsz. oldsz and newsz need not be page-aligned, nor does newsz
// need to be less than oldsz. oldsz can be larger than the actual
// process size. Returns the new process size.
uint64 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) {
if (newsz >= oldsz)
uint64
uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
{
if(newsz >= oldsz)
return oldsz;
if (PGROUNDUP(newsz) < PGROUNDUP(oldsz)) {
if(PGROUNDUP(newsz) < PGROUNDUP(oldsz)){
int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
}
@ -245,27 +263,31 @@ uint64 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) {
// Recursively free page-table pages.
// All leaf mappings must already have been removed.
void freewalk(pagetable_t pagetable) {
void
freewalk(pagetable_t pagetable)
{
// there are 2^9 = 512 PTEs in a page table.
for (int i = 0; i < 512; i++) {
for(int i = 0; i < 512; i++){
pte_t pte = pagetable[i];
if ((pte & PTE_V) && (pte & (PTE_R | PTE_W | PTE_X)) == 0) {
if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){
// this PTE points to a lower-level page table.
uint64 child = PTE2PA(pte);
freewalk((pagetable_t)child);
pagetable[i] = 0;
} else if (pte & PTE_V) {
} else if(pte & PTE_V){
panic("freewalk: leaf");
}
}
kfree((void *)pagetable);
kfree((void*)pagetable);
}
// Free user memory pages,
// then free page-table pages.
void uvmfree(pagetable_t pagetable, uint64 sz) {
if (sz > 0)
uvmunmap(pagetable, 0, PGROUNDUP(sz) / PGSIZE, 1);
void
uvmfree(pagetable_t pagetable, uint64 sz)
{
if(sz > 0)
uvmunmap(pagetable, 0, PGROUNDUP(sz)/PGSIZE, 1);
freewalk(pagetable);
}
@ -275,41 +297,45 @@ void uvmfree(pagetable_t pagetable, uint64 sz) {
// physical memory.
// returns 0 on success, -1 on failure.
// frees any allocated pages on failure.
int uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) {
int
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
{
pte_t *pte;
uint64 pa, i;
uint flags;
char *mem;
for (i = 0; i < sz; i += PGSIZE) {
if ((pte = walk(old, i, 0)) == 0)
for(i = 0; i < sz; i += PGSIZE){
if((pte = walk(old, i, 0)) == 0)
panic("uvmcopy: pte should exist");
if ((*pte & PTE_V) == 0)
if((*pte & PTE_V) == 0)
panic("uvmcopy: page not present");
pa = PTE2PA(*pte);
flags = PTE_FLAGS(*pte);
if ((mem = kalloc()) == 0)
if((mem = kalloc()) == 0)
goto err;
memmove(mem, (char *)pa, PGSIZE);
if (mappages(new, i, PGSIZE, (uint64)mem, flags) != 0) {
memmove(mem, (char*)pa, PGSIZE);
if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
kfree(mem);
goto err;
}
}
return 0;
err:
err:
uvmunmap(new, 0, i / PGSIZE, 1);
return -1;
}
// mark a PTE invalid for user access.
// used by exec for the user stack guard page.
void uvmclear(pagetable_t pagetable, uint64 va) {
void
uvmclear(pagetable_t pagetable, uint64 va)
{
pte_t *pte;
pte = walk(pagetable, va, 0);
if (pte == 0)
if(pte == 0)
panic("uvmclear");
*pte &= ~PTE_U;
}
@ -317,16 +343,18 @@ void uvmclear(pagetable_t pagetable, uint64 va) {
// Copy from kernel to user.
// Copy len bytes from src to virtual address dstva in a given page table.
// Return 0 on success, -1 on error.
int copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len) {
int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
{
uint64 n, va0, pa0;
while (len > 0) {
while(len > 0){
va0 = PGROUNDDOWN(dstva);
pa0 = walkaddr(pagetable, va0);
if (pa0 == 0)
if(pa0 == 0)
return -1;
n = PGSIZE - (dstva - va0);
if (n > len)
if(n > len)
n = len;
memmove((void *)(pa0 + (dstva - va0)), src, n);
@ -340,16 +368,18 @@ int copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len) {
// Copy from user to kernel.
// Copy len bytes to dst from virtual address srcva in a given page table.
// Return 0 on success, -1 on error.
int copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) {
int
copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
{
uint64 n, va0, pa0;
while (len > 0) {
while(len > 0){
va0 = PGROUNDDOWN(srcva);
pa0 = walkaddr(pagetable, va0);
if (pa0 == 0)
if(pa0 == 0)
return -1;
n = PGSIZE - (srcva - va0);
if (n > len)
if(n > len)
n = len;
memmove(dst, (void *)(pa0 + (srcva - va0)), n);
@ -364,22 +394,24 @@ int copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) {
// Copy bytes to dst from virtual address srcva in a given page table,
// until a '\0', or max.
// Return 0 on success, -1 on error.
int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) {
int
copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
{
uint64 n, va0, pa0;
int got_null = 0;
while (got_null == 0 && max > 0) {
while(got_null == 0 && max > 0){
va0 = PGROUNDDOWN(srcva);
pa0 = walkaddr(pagetable, va0);
if (pa0 == 0)
if(pa0 == 0)
return -1;
n = PGSIZE - (srcva - va0);
if (n > max)
if(n > max)
n = max;
char *p = (char *)(pa0 + (srcva - va0));
while (n > 0) {
if (*p == '\0') {
char *p = (char *) (pa0 + (srcva - va0));
while(n > 0){
if(*p == '\0'){
*dst = '\0';
got_null = 1;
break;
@ -394,7 +426,7 @@ int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) {
srcva = va0 + PGSIZE;
}
if (got_null) {
if(got_null){
return 0;
} else {
return -1;

View File

@ -12,12 +12,7 @@
#include "kernel/param.h"
#ifndef static_assert
#define static_assert(a, b) \
do { \
switch (0) \
case 0: \
case (a):; \
} while (0)
#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
#endif
#define NINODES 200
@ -25,7 +20,7 @@
// Disk layout:
// [ boot block | sb block | log | inode blocks | free bit map | data blocks ]
int nbitmap = FSSIZE / (BSIZE * 8) + 1;
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)
@ -37,9 +32,10 @@ char zeroes[BSIZE];
uint freeinode = 1;
uint freeblock;
void balloc(int);
void wsect(uint, void *);
void winode(uint, struct dinode *);
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);
@ -47,17 +43,21 @@ void iappend(uint inum, void *p, int n);
void die(const char *);
// convert to riscv byte order
ushort xshort(ushort x) {
ushort
xshort(ushort x)
{
ushort y;
uchar *a = (uchar *)&y;
uchar *a = (uchar*)&y;
a[0] = x;
a[1] = x >> 8;
return y;
}
uint xint(uint x) {
uint
xint(uint x)
{
uint y;
uchar *a = (uchar *)&y;
uchar *a = (uchar*)&y;
a[0] = x;
a[1] = x >> 8;
a[2] = x >> 16;
@ -65,16 +65,19 @@ uint xint(uint x) {
return y;
}
int main(int argc, char *argv[]) {
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) {
if(argc < 2){
fprintf(stderr, "Usage: mkfs fs.img files...\n");
exit(1);
}
@ -82,8 +85,8 @@ int main(int argc, char *argv[]) {
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)
fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
if(fsfd < 0)
die(argv[1]);
// 1 fs block = 1 disk sector
@ -96,16 +99,15 @@ int main(int argc, char *argv[]) {
sb.ninodes = xint(NINODES);
sb.nlog = xint(nlog);
sb.logstart = xint(2);
sb.inodestart = xint(2 + nlog);
sb.bmapstart = xint(2 + nlog + ninodeblocks);
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",
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++)
for(i = 0; i < FSSIZE; i++)
wsect(i, zeroes);
memset(buf, 0, sizeof(buf));
@ -125,24 +127,24 @@ int main(int argc, char *argv[]) {
strcpy(de.name, "..");
iappend(rootino, &de, sizeof(de));
for (i = 2; i < argc; i++) {
for(i = 2; i < argc; i++){
// get rid of "user/"
char *shortname;
if (strncmp(argv[i], "user/", 5) == 0)
if(strncmp(argv[i], "user/", 5) == 0)
shortname = argv[i] + 5;
else
shortname = argv[i];
assert(index(shortname, '/') == 0);
if ((fd = open(argv[i], 0)) < 0)
if((fd = open(argv[i], 0)) < 0)
die(argv[i]);
// 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] == '_')
if(shortname[0] == '_')
shortname += 1;
inum = ialloc(T_FILE);
@ -152,7 +154,7 @@ int main(int argc, char *argv[]) {
strncpy(de.name, shortname, DIRSIZ);
iappend(rootino, &de, sizeof(de));
while ((cc = read(fd, buf, sizeof(buf))) > 0)
while((cc = read(fd, buf, sizeof(buf))) > 0)
iappend(inum, buf, cc);
close(fd);
@ -161,7 +163,7 @@ int main(int argc, char *argv[]) {
// fix size of root inode dir
rinode(rootino, &din);
off = xint(din.size);
off = ((off / BSIZE) + 1) * BSIZE;
off = ((off/BSIZE) + 1) * BSIZE;
din.size = xint(off);
winode(rootino, &din);
@ -170,44 +172,54 @@ int main(int argc, char *argv[]) {
exit(0);
}
void wsect(uint sec, void *buf) {
if (lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
void
wsect(uint sec, void *buf)
{
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
die("lseek");
if (write(fsfd, buf, BSIZE) != BSIZE)
if(write(fsfd, buf, BSIZE) != BSIZE)
die("write");
}
void winode(uint inum, struct dinode *ip) {
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 = ((struct dinode*)buf) + (inum % IPB);
*dip = *ip;
wsect(bn, buf);
}
void rinode(uint inum, struct dinode *ip) {
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);
dip = ((struct dinode*)buf) + (inum % IPB);
*ip = *dip;
}
void rsect(uint sec, void *buf) {
if (lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
void
rsect(uint sec, void *buf)
{
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
die("lseek");
if (read(fsfd, buf, BSIZE) != BSIZE)
if(read(fsfd, buf, BSIZE) != BSIZE)
die("read");
}
uint ialloc(ushort type) {
uint
ialloc(ushort type)
{
uint inum = freeinode++;
struct dinode din;
@ -219,15 +231,17 @@ uint ialloc(ushort type) {
return inum;
}
void balloc(int used) {
void
balloc(int used)
{
uchar buf[BSIZE];
int i;
printf("balloc: first %d blocks have been allocated\n", used);
assert(used < BSIZE * 8);
assert(used < BSIZE*8);
bzero(buf, BSIZE);
for (i = 0; i < used; i++) {
buf[i / 8] = buf[i / 8] | (0x1 << (i % 8));
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);
@ -235,8 +249,10 @@ void balloc(int used) {
#define min(a, b) ((a) < (b) ? (a) : (b))
void iappend(uint inum, void *xp, int n) {
char *p = (char *)xp;
void
iappend(uint inum, void *xp, int n)
{
char *p = (char*)xp;
uint fbn, off, n1;
struct dinode din;
char buf[BSIZE];
@ -246,24 +262,24 @@ void iappend(uint inum, void *xp, int n) {
rinode(inum, &din);
off = xint(din.size);
// printf("append inum %d at off %d sz %d\n", inum, off, n);
while (n > 0) {
while(n > 0){
fbn = off / BSIZE;
assert(fbn < MAXFILE);
if (fbn < NDIRECT) {
if (xint(din.addrs[fbn]) == 0) {
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) {
if(xint(din.addrs[NDIRECT]) == 0){
din.addrs[NDIRECT] = xint(freeblock++);
}
rsect(xint(din.addrs[NDIRECT]), (char *)indirect);
if (indirect[fbn - NDIRECT] == 0) {
rsect(xint(din.addrs[NDIRECT]), (char*)indirect);
if(indirect[fbn - NDIRECT] == 0){
indirect[fbn - NDIRECT] = xint(freeblock++);
wsect(xint(din.addrs[NDIRECT]), (char *)indirect);
wsect(xint(din.addrs[NDIRECT]), (char*)indirect);
}
x = xint(indirect[fbn - NDIRECT]);
x = xint(indirect[fbn-NDIRECT]);
}
n1 = min(n, (fbn + 1) * BSIZE - off);
rsect(x, buf);
@ -277,7 +293,9 @@ void iappend(uint inum, void *xp, int n) {
winode(inum, &din);
}
void die(const char *s) {
void
die(const char *s)
{
perror(s);
exit(1);
}

1
rust/foo/.gitignore vendored
View File

@ -1 +0,0 @@
/target

7
rust/foo/Cargo.lock generated
View File

@ -1,7 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "foo"
version = "0.1.0"

View File

@ -1,14 +0,0 @@
[package]
name = "foo"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = [ "staticlib" ]
[profile.release]
panic = "abort"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -1,13 +0,0 @@
#![no_std]
#![crate_type = "staticlib"]
#[no_mangle]
pub extern "C" fn add(left: i32, right: i32) -> i32 {
left + right
}
#[panic_handler]
#[no_mangle]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}

View File

@ -4,31 +4,35 @@
char buf[512];
void cat(int fd) {
void
cat(int fd)
{
int n;
while ((n = read(fd, buf, sizeof(buf))) > 0) {
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) {
if(n < 0){
fprintf(2, "cat: read error\n");
exit(1);
}
}
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[])
{
int fd, i;
if (argc <= 1) {
if(argc <= 1){
cat(0);
exit(0);
}
for (i = 1; i < argc; i++) {
if ((fd = open(argv[i], 0)) < 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);
}

View File

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

View File

@ -7,34 +7,40 @@
#define N 1000
void print(const char *s) { write(1, s, strlen(s)); }
void
print(const char *s)
{
write(1, s, strlen(s));
}
void forktest(void) {
void
forktest(void)
{
int n, pid;
print("fork test\n");
for (n = 0; n < N; n++) {
for(n=0; n<N; n++){
pid = fork();
if (pid < 0)
if(pid < 0)
break;
if (pid == 0)
if(pid == 0)
exit(0);
}
if (n == N) {
if(n == N){
print("fork claimed to work N times!\n");
exit(1);
}
for (; n > 0; n--) {
if (wait(0) < 0) {
for(; n > 0; n--){
if(wait(0) < 0){
print("wait stopped early\n");
exit(1);
}
}
if (wait(0) != -1) {
if(wait(0) != -1){
print("wait got too many\n");
exit(1);
}
@ -42,7 +48,9 @@ void forktest(void) {
print("fork test OK\n");
}
int main(void) {
int
main(void)
{
forktest();
exit(0);
}

View File

@ -5,49 +5,53 @@
#include "user/user.h"
char buf[1024];
int match(char *, char *);
int match(char*, char*);
void grep(char *pattern, int fd) {
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) {
while((n = read(fd, buf+m, sizeof(buf)-m-1)) > 0){
m += n;
buf[m] = '\0';
p = buf;
while ((q = strchr(p, '\n')) != 0) {
while((q = strchr(p, '\n')) != 0){
*q = 0;
if (match(pattern, p)) {
if(match(pattern, p)){
*q = '\n';
write(1, p, q + 1 - p);
write(1, p, q+1 - p);
}
p = q + 1;
p = q+1;
}
if (m > 0) {
if(m > 0){
m -= p - buf;
memmove(buf, p, m);
}
}
}
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[])
{
int fd, i;
char *pattern;
if (argc <= 1) {
if(argc <= 1){
fprintf(2, "usage: grep pattern [file ...]\n");
exit(1);
}
pattern = argv[1];
if (argc <= 2) {
if(argc <= 2){
grep(pattern, 0);
exit(0);
}
for (i = 2; i < argc; i++) {
if ((fd = open(argv[i], 0)) < 0) {
for(i = 2; i < argc; i++){
if((fd = open(argv[i], 0)) < 0){
printf("grep: cannot open %s\n", argv[i]);
exit(1);
}
@ -61,37 +65,42 @@ int main(int argc, char *argv[]) {
// The Practice of Programming, Chapter 9, or
// https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
int matchhere(char *, char *);
int matchstar(int, char *, char *);
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))
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');
}while(*text++ != '\0');
return 0;
}
// matchhere: search for re at beginning of text
int matchhere(char *re, char *text) {
if (re[0] == '\0')
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')
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);
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))
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 == '.'));
}while(*text!='\0' && (*text++==c || c=='.'));
return 0;
}

View File

@ -13,8 +13,10 @@
#include "kernel/riscv.h"
// from FreeBSD.
int do_rand(unsigned long *ctx) {
/*
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
@ -39,282 +41,289 @@ int do_rand(unsigned long *ctx) {
unsigned long rand_next = 1;
int rand(void) { return (do_rand(&rand_next)); }
int
rand(void)
{
return (do_rand(&rand_next));
}
void go(int which_child) {
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) {
if(chdir("grindir") != 0){
printf("grind: chdir grindir failed\n");
exit(1);
}
chdir("/");
while (1) {
while(1){
iters++;
if ((iters % 500) == 0)
write(1, which_child ? "B" : "A", 1);
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) {
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) {
} else if(what == 4){
if(chdir("grindir") != 0){
printf("grind: chdir grindir failed\n");
exit(1);
}
unlink("../b");
chdir("/");
} else if (what == 5) {
} else if(what == 5){
close(fd);
fd = open("/grindir/../a", O_CREATE | O_RDWR);
} else if (what == 6) {
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) {
fd = open("/./grindir/./../b", O_CREATE|O_RDWR);
} else if(what == 7){
write(fd, buf, sizeof(buf));
} else if (what == 8) {
} else if(what == 8){
read(fd, buf, sizeof(buf));
} else if (what == 9) {
} else if(what == 9){
mkdir("grindir/../a");
close(open("a/../a/./a", O_CREATE | O_RDWR));
close(open("a/../a/./a", O_CREATE|O_RDWR));
unlink("a/a");
} else if (what == 10) {
} else if(what == 10){
mkdir("/../b");
close(open("grindir/../b/b", O_CREATE | O_RDWR));
close(open("grindir/../b/b", O_CREATE|O_RDWR));
unlink("b/b");
} else if (what == 11) {
} else if(what == 11){
unlink("b");
link("../grindir/./../a", "../b");
} else if (what == 12) {
} else if(what == 12){
unlink("../grindir/../a");
link(".././b", "/grindir/../a");
} else if (what == 13) {
} else if(what == 13){
int pid = fork();
if (pid == 0) {
if(pid == 0){
exit(0);
} else if (pid < 0) {
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if (what == 14) {
} else if(what == 14){
int pid = fork();
if (pid == 0) {
if(pid == 0){
fork();
fork();
exit(0);
} else if (pid < 0) {
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if (what == 15) {
} else if(what == 15){
sbrk(6011);
} else if (what == 16) {
if (sbrk(0) > break0)
} else if(what == 16){
if(sbrk(0) > break0)
sbrk(-(sbrk(0) - break0));
} else if (what == 17) {
} else if(what == 17){
int pid = fork();
if (pid == 0) {
close(open("a", O_CREATE | O_RDWR));
if(pid == 0){
close(open("a", O_CREATE|O_RDWR));
exit(0);
} else if (pid < 0) {
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
if (chdir("../grindir/..") != 0) {
if(chdir("../grindir/..") != 0){
printf("grind: chdir failed\n");
exit(1);
}
kill(pid);
wait(0);
} else if (what == 18) {
} else if(what == 18){
int pid = fork();
if (pid == 0) {
if(pid == 0){
kill(getpid());
exit(0);
} else if (pid < 0) {
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if (what == 19) {
} else if(what == 19){
int fds[2];
if (pipe(fds) < 0) {
if(pipe(fds) < 0){
printf("grind: pipe failed\n");
exit(1);
}
int pid = fork();
if (pid == 0) {
if(pid == 0){
fork();
fork();
if (write(fds[1], "x", 1) != 1)
if(write(fds[1], "x", 1) != 1)
printf("grind: pipe write failed\n");
char c;
if (read(fds[0], &c, 1) != 1)
if(read(fds[0], &c, 1) != 1)
printf("grind: pipe read failed\n");
exit(0);
} else if (pid < 0) {
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
close(fds[0]);
close(fds[1]);
wait(0);
} else if (what == 20) {
} else if(what == 20){
int pid = fork();
if (pid == 0) {
if(pid == 0){
unlink("a");
mkdir("a");
chdir("a");
unlink("../a");
fd = open("x", O_CREATE | O_RDWR);
fd = open("x", O_CREATE|O_RDWR);
unlink("x");
exit(0);
} else if (pid < 0) {
} else if(pid < 0){
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if (what == 21) {
} 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) {
int fd1 = open("c", O_CREATE|O_RDWR);
if(fd1 < 0){
printf("grind: create c failed\n");
exit(1);
}
if (write(fd1, "x", 1) != 1) {
if(write(fd1, "x", 1) != 1){
printf("grind: write c failed\n");
exit(1);
}
struct stat st;
if (fstat(fd1, &st) != 0) {
if(fstat(fd1, &st) != 0){
printf("grind: fstat failed\n");
exit(1);
}
if (st.size != 1) {
if(st.size != 1){
printf("grind: fstat reports wrong size %d\n", (int)st.size);
exit(1);
}
if (st.ino > 200) {
if(st.ino > 200){
printf("grind: fstat reports crazy i-number %d\n", st.ino);
exit(1);
}
close(fd1);
unlink("c");
} else if (what == 22) {
} else if(what == 22){
// echo hi | cat
int aa[2], bb[2];
if (pipe(aa) < 0) {
if(pipe(aa) < 0){
fprintf(2, "grind: pipe failed\n");
exit(1);
}
if (pipe(bb) < 0) {
if(pipe(bb) < 0){
fprintf(2, "grind: pipe failed\n");
exit(1);
}
int pid1 = fork();
if (pid1 == 0) {
if(pid1 == 0){
close(bb[0]);
close(bb[1]);
close(aa[0]);
close(1);
if (dup(aa[1]) != 1) {
if(dup(aa[1]) != 1){
fprintf(2, "grind: dup failed\n");
exit(1);
}
close(aa[1]);
char *args[3] = {"echo", "hi", 0};
char *args[3] = { "echo", "hi", 0 };
exec("grindir/../echo", args);
fprintf(2, "grind: echo: not found\n");
exit(2);
} else if (pid1 < 0) {
} else if(pid1 < 0){
fprintf(2, "grind: fork failed\n");
exit(3);
}
int pid2 = fork();
if (pid2 == 0) {
if(pid2 == 0){
close(aa[1]);
close(bb[0]);
close(0);
if (dup(aa[0]) != 0) {
if(dup(aa[0]) != 0){
fprintf(2, "grind: dup failed\n");
exit(4);
}
close(aa[0]);
close(1);
if (dup(bb[1]) != 1) {
if(dup(bb[1]) != 1){
fprintf(2, "grind: dup failed\n");
exit(5);
}
close(bb[1]);
char *args[2] = {"cat", 0};
char *args[2] = { "cat", 0 };
exec("/cat", args);
fprintf(2, "grind: cat: not found\n");
exit(6);
} else if (pid2 < 0) {
} else if(pid2 < 0){
fprintf(2, "grind: fork failed\n");
exit(7);
}
close(aa[0]);
close(aa[1]);
close(bb[1]);
char buf[4] = {0, 0, 0, 0};
read(bb[0], buf + 0, 1);
read(bb[0], buf + 1, 1);
read(bb[0], buf + 2, 1);
char buf[4] = { 0, 0, 0, 0 };
read(bb[0], buf+0, 1);
read(bb[0], buf+1, 1);
read(bb[0], buf+2, 1);
close(bb[0]);
int st1, st2;
wait(&st1);
wait(&st2);
if (st1 != 0 || st2 != 0 || strcmp(buf, "hi\n") != 0) {
printf("grind: exec pipeline failed %d %d \"%s\"\n", st1, st2,
buf);
if(st1 != 0 || st2 != 0 || strcmp(buf, "hi\n") != 0){
printf("grind: exec pipeline failed %d %d \"%s\"\n", st1, st2, buf);
exit(1);
}
}
}
}
void iter() {
void
iter()
{
unlink("a");
unlink("b");
int pid1 = fork();
if (pid1 < 0) {
if(pid1 < 0){
printf("grind: fork failed\n");
exit(1);
}
if (pid1 == 0) {
rand_next ^= 31;
if(pid1 == 0){
rand_next = 31;
go(0);
exit(0);
}
int pid2 = fork();
if (pid2 < 0) {
if(pid2 < 0){
printf("grind: fork failed\n");
exit(1);
}
if (pid2 == 0) {
rand_next ^= 7177;
if(pid2 == 0){
rand_next = 7177;
go(1);
exit(0);
}
int st1 = -1;
wait(&st1);
if (st1 != 0) {
if(st1 != 0){
kill(pid1);
kill(pid2);
}
@ -324,17 +333,18 @@ void iter() {
exit(0);
}
int main() {
while (1) {
int
main()
{
while(1){
int pid = fork();
if (pid == 0) {
if(pid == 0){
iter();
exit(0);
}
if (pid > 0) {
if(pid > 0){
wait(0);
}
sleep(20);
rand_next += 1;
}
}

View File

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

View File

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

View File

@ -2,12 +2,14 @@
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
if (argc != 3) {
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)
if(link(argv[1], argv[2]) < 0)
fprintf(2, "link %s %s: failed\n", argv[1], argv[2]);
exit(0);
}

View File

@ -3,60 +3,64 @@
#include "user/user.h"
#include "kernel/fs.h"
char *fmtname(char *path) {
static char buf[DIRSIZ + 1];
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--)
for(p=path+strlen(path); p >= path && *p != '/'; p--)
;
p++;
// Return blank-padded name.
if (strlen(p) >= DIRSIZ)
if(strlen(p) >= DIRSIZ)
return p;
memmove(buf, p, strlen(p));
memset(buf + strlen(p), ' ', DIRSIZ - strlen(p));
memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
return buf;
}
void ls(char *path) {
void
ls(char *path)
{
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if ((fd = open(path, 0)) < 0) {
if((fd = open(path, 0)) < 0){
fprintf(2, "ls: cannot open %s\n", path);
return;
}
if (fstat(fd, &st) < 0) {
if(fstat(fd, &st) < 0){
fprintf(2, "ls: cannot stat %s\n", path);
close(fd);
return;
}
switch (st.type) {
switch(st.type){
case T_DEVICE:
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) {
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
printf("ls: path too long\n");
break;
}
strcpy(buf, path);
p = buf + strlen(buf);
p = buf+strlen(buf);
*p++ = '/';
while (read(fd, &de, sizeof(de)) == sizeof(de)) {
if (de.inum == 0)
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) {
if(stat(buf, &st) < 0){
printf("ls: cannot stat %s\n", buf);
continue;
}
@ -67,14 +71,16 @@ void ls(char *path) {
close(fd);
}
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[])
{
int i;
if (argc < 2) {
if(argc < 2){
ls(".");
exit(0);
}
for (i = 1; i < argc; i++)
for(i=1; i<argc; i++)
ls(argv[i]);
exit(0);
}

View File

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

View File

@ -6,15 +6,21 @@
static char digits[] = "0123456789ABCDEF";
static void putc(int fd, char c) { write(fd, &c, 1); }
static void
putc(int fd, char c)
{
write(fd, &c, 1);
}
static void printint(int fd, int xx, int base, int sgn) {
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) {
if(sgn && xx < 0){
neg = 1;
x = -xx;
} else {
@ -22,17 +28,18 @@ static void printint(int fd, int xx, int base, int sgn) {
}
i = 0;
do {
do{
buf[i++] = digits[x % base];
} while ((x /= base) != 0);
if (neg)
}while((x /= base) != 0);
if(neg)
buf[i++] = '-';
while (--i >= 0)
while(--i >= 0)
putc(fd, buf[i]);
}
static void printptr(int fd, uint64 x) {
static void
printptr(int fd, uint64 x) {
int i;
putc(fd, '0');
putc(fd, 'x');
@ -41,39 +48,41 @@ static void printptr(int fd, uint64 x) {
}
// Print to the given fd. Only understands %d, %x, %p, %s.
void vprintf(int fd, const char *fmt, va_list ap) {
void
vprintf(int fd, const char *fmt, va_list ap)
{
char *s;
int c, i, state;
state = 0;
for (i = 0; fmt[i]; i++) {
for(i = 0; fmt[i]; i++){
c = fmt[i] & 0xff;
if (state == 0) {
if (c == '%') {
if(state == 0){
if(c == '%'){
state = '%';
} else {
putc(fd, c);
}
} else if (state == '%') {
if (c == 'd') {
} else if(state == '%'){
if(c == 'd'){
printint(fd, va_arg(ap, int), 10, 1);
} else if (c == 'l') {
} else if(c == 'l') {
printint(fd, va_arg(ap, uint64), 10, 0);
} else if (c == 'x') {
} else if(c == 'x') {
printint(fd, va_arg(ap, int), 16, 0);
} else if (c == 'p') {
} else if(c == 'p') {
printptr(fd, va_arg(ap, uint64));
} else if (c == 's') {
s = va_arg(ap, char *);
if (s == 0)
} else if(c == 's'){
s = va_arg(ap, char*);
if(s == 0)
s = "(null)";
while (*s != 0) {
while(*s != 0){
putc(fd, *s);
s++;
}
} else if (c == 'c') {
} else if(c == 'c'){
putc(fd, va_arg(ap, uint));
} else if (c == '%') {
} else if(c == '%'){
putc(fd, c);
} else {
// Unknown % sequence. Print it to draw attention.
@ -85,14 +94,18 @@ void vprintf(int fd, const char *fmt, va_list ap) {
}
}
void fprintf(int fd, const char *fmt, ...) {
void
fprintf(int fd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fd, fmt, ap);
}
void printf(const char *fmt, ...) {
void
printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);

View File

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

219
user/sh.c
View File

@ -50,12 +50,14 @@ struct backcmd {
};
int fork1(void); // Fork but panics on failure.
void panic(char *);
struct cmd *parsecmd(char *);
void runcmd(struct cmd *) __attribute__((noreturn));
void panic(char*);
struct cmd *parsecmd(char*);
void runcmd(struct cmd*) __attribute__((noreturn));
// Execute cmd. Never returns.
void runcmd(struct cmd *cmd) {
void
runcmd(struct cmd *cmd)
{
int p[2];
struct backcmd *bcmd;
struct execcmd *ecmd;
@ -63,25 +65,25 @@ void runcmd(struct cmd *cmd) {
struct pipecmd *pcmd;
struct redircmd *rcmd;
if (cmd == 0)
if(cmd == 0)
exit(1);
switch (cmd->type) {
switch(cmd->type){
default:
panic("runcmd");
case EXEC:
ecmd = (struct execcmd *)cmd;
if (ecmd->argv[0] == 0)
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;
rcmd = (struct redircmd*)cmd;
close(rcmd->fd);
if (open(rcmd->file, rcmd->mode) < 0) {
if(open(rcmd->file, rcmd->mode) < 0){
fprintf(2, "open %s failed\n", rcmd->file);
exit(1);
}
@ -89,25 +91,25 @@ void runcmd(struct cmd *cmd) {
break;
case LIST:
lcmd = (struct listcmd *)cmd;
if (fork1() == 0)
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)
pcmd = (struct pipecmd*)cmd;
if(pipe(p) < 0)
panic("pipe");
if (fork1() == 0) {
if(fork1() == 0){
close(1);
dup(p[1]);
close(p[0]);
close(p[1]);
runcmd(pcmd->left);
}
if (fork1() == 0) {
if(fork1() == 0){
close(0);
dup(p[0]);
close(p[0]);
@ -121,79 +123,90 @@ void runcmd(struct cmd *cmd) {
break;
case BACK:
bcmd = (struct backcmd *)cmd;
if (fork1() == 0)
bcmd = (struct backcmd*)cmd;
if(fork1() == 0)
runcmd(bcmd->cmd);
break;
}
exit(0);
}
int getcmd(char *buf, int nbuf) {
int
getcmd(char *buf, int nbuf)
{
write(2, "$ ", 2);
memset(buf, 0, nbuf);
gets(buf, nbuf);
if (buf[0] == 0) // EOF
if(buf[0] == 0) // EOF
return -1;
return 0;
}
int main(void) {
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) {
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] == ' ') {
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);
buf[strlen(buf)-1] = 0; // chop \n
if(chdir(buf+3) < 0)
fprintf(2, "cannot cd %s\n", buf+3);
continue;
}
if (fork1() == 0)
if(fork1() == 0)
runcmd(parsecmd(buf));
wait(0);
}
exit(0);
}
void panic(char *s) {
void
panic(char *s)
{
fprintf(2, "%s\n", s);
exit(1);
}
int fork1(void) {
int
fork1(void)
{
int pid;
pid = fork();
if (pid == -1)
if(pid == -1)
panic("fork");
return pid;
}
// PAGEBREAK!
//PAGEBREAK!
// Constructors
struct cmd *execcmd(void) {
struct cmd*
execcmd(void)
{
struct execcmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = EXEC;
return (struct cmd *)cmd;
return (struct cmd*)cmd;
}
struct cmd *redircmd(struct cmd *subcmd, char *file, char *efile, int mode,
int fd) {
struct cmd*
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
{
struct redircmd *cmd;
cmd = malloc(sizeof(*cmd));
@ -204,10 +217,12 @@ struct cmd *redircmd(struct cmd *subcmd, char *file, char *efile, int mode,
cmd->efile = efile;
cmd->mode = mode;
cmd->fd = fd;
return (struct cmd *)cmd;
return (struct cmd*)cmd;
}
struct cmd *pipecmd(struct cmd *left, struct cmd *right) {
struct cmd*
pipecmd(struct cmd *left, struct cmd *right)
{
struct pipecmd *cmd;
cmd = malloc(sizeof(*cmd));
@ -215,10 +230,12 @@ struct cmd *pipecmd(struct cmd *left, struct cmd *right) {
cmd->type = PIPE;
cmd->left = left;
cmd->right = right;
return (struct cmd *)cmd;
return (struct cmd*)cmd;
}
struct cmd *listcmd(struct cmd *left, struct cmd *right) {
struct cmd*
listcmd(struct cmd *left, struct cmd *right)
{
struct listcmd *cmd;
cmd = malloc(sizeof(*cmd));
@ -226,35 +243,39 @@ struct cmd *listcmd(struct cmd *left, struct cmd *right) {
cmd->type = LIST;
cmd->left = left;
cmd->right = right;
return (struct cmd *)cmd;
return (struct cmd*)cmd;
}
struct cmd *backcmd(struct cmd *subcmd) {
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;
return (struct cmd*)cmd;
}
// PAGEBREAK!
//PAGEBREAK!
// Parsing
char whitespace[] = " \t\r\n\v";
char symbols[] = "<|>&;()";
int gettoken(char **ps, char *es, char **q, char **eq) {
int
gettoken(char **ps, char *es, char **q, char **eq)
{
char *s;
int ret;
s = *ps;
while (s < es && strchr(whitespace, *s))
while(s < es && strchr(whitespace, *s))
s++;
if (q)
if(q)
*q = s;
ret = *s;
switch (*s) {
switch(*s){
case 0:
break;
case '|':
@ -267,49 +288,53 @@ int gettoken(char **ps, char *es, char **q, char **eq) {
break;
case '>':
s++;
if (*s == '>') {
if(*s == '>'){
ret = '+';
s++;
}
break;
default:
ret = 'a';
while (s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
s++;
break;
}
if (eq)
if(eq)
*eq = s;
while (s < es && strchr(whitespace, *s))
while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return ret;
}
int peek(char **ps, char *es, char *toks) {
int
peek(char **ps, char *es, char *toks)
{
char *s;
s = *ps;
while (s < es && strchr(whitespace, *s))
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 *parseline(char**, char*);
struct cmd *parsepipe(char**, char*);
struct cmd *parseexec(char**, char*);
struct cmd *nulterminate(struct cmd*);
struct cmd *parsecmd(char *s) {
struct cmd*
parsecmd(char *s)
{
char *es;
struct cmd *cmd;
es = s + strlen(s);
cmd = parseline(&s, es);
peek(&s, es, "");
if (s != es) {
if(s != es){
fprintf(2, "leftovers: %s\n", s);
panic("syntax");
}
@ -317,92 +342,102 @@ struct cmd *parsecmd(char *s) {
return cmd;
}
struct cmd *parseline(char **ps, char *es) {
struct cmd*
parseline(char **ps, char *es)
{
struct cmd *cmd;
cmd = parsepipe(ps, es);
while (peek(ps, es, "&")) {
while(peek(ps, es, "&")){
gettoken(ps, es, 0, 0);
cmd = backcmd(cmd);
}
if (peek(ps, es, ";")) {
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*
parsepipe(char **ps, char *es)
{
struct cmd *cmd;
cmd = parseexec(ps, es);
if (peek(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) {
struct cmd*
parseredirs(struct cmd *cmd, char **ps, char *es)
{
int tok;
char *q, *eq;
while (peek(ps, es, "<>")) {
while(peek(ps, es, "<>")){
tok = gettoken(ps, es, 0, 0);
if (gettoken(ps, es, &q, &eq) != 'a')
if(gettoken(ps, es, &q, &eq) != 'a')
panic("missing file for redirection");
switch (tok) {
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);
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
break;
case '+': // >>
cmd = redircmd(cmd, q, eq, O_WRONLY | O_CREATE, 1);
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
break;
}
}
return cmd;
}
struct cmd *parseblock(char **ps, char *es) {
struct cmd*
parseblock(char **ps, char *es)
{
struct cmd *cmd;
if (!peek(ps, es, "("))
if(!peek(ps, es, "("))
panic("parseblock");
gettoken(ps, es, 0, 0);
cmd = parseline(ps, es);
if (!peek(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) {
struct cmd*
parseexec(char **ps, char *es)
{
char *q, *eq;
int tok, argc;
struct execcmd *cmd;
struct cmd *ret;
if (peek(ps, es, "("))
if(peek(ps, es, "("))
return parseblock(ps, es);
ret = execcmd();
cmd = (struct execcmd *)ret;
cmd = (struct execcmd*)ret;
argc = 0;
ret = parseredirs(ret, ps, es);
while (!peek(ps, es, "|)&;")) {
if ((tok = gettoken(ps, es, &q, &eq)) == 0)
while(!peek(ps, es, "|)&;")){
if((tok=gettoken(ps, es, &q, &eq)) == 0)
break;
if (tok != 'a')
if(tok != 'a')
panic("syntax");
cmd->argv[argc] = q;
cmd->eargv[argc] = eq;
argc++;
if (argc >= MAXARGS)
if(argc >= MAXARGS)
panic("too many args");
ret = parseredirs(ret, ps, es);
}
@ -412,7 +447,9 @@ struct cmd *parseexec(char **ps, char *es) {
}
// NUL-terminate all the counted strings.
struct cmd *nulterminate(struct cmd *cmd) {
struct cmd*
nulterminate(struct cmd *cmd)
{
int i;
struct backcmd *bcmd;
struct execcmd *ecmd;
@ -420,36 +457,36 @@ struct cmd *nulterminate(struct cmd *cmd) {
struct pipecmd *pcmd;
struct redircmd *rcmd;
if (cmd == 0)
if(cmd == 0)
return 0;
switch (cmd->type) {
switch(cmd->type){
case EXEC:
ecmd = (struct execcmd *)cmd;
for (i = 0; ecmd->argv[i]; i++)
ecmd = (struct execcmd*)cmd;
for(i=0; ecmd->argv[i]; i++)
*ecmd->eargv[i] = 0;
break;
case REDIR:
rcmd = (struct redircmd *)cmd;
rcmd = (struct redircmd*)cmd;
nulterminate(rcmd->cmd);
*rcmd->efile = 0;
break;
case PIPE:
pcmd = (struct pipecmd *)cmd;
pcmd = (struct pipecmd*)cmd;
nulterminate(pcmd->left);
nulterminate(pcmd->right);
break;
case LIST:
lcmd = (struct listcmd *)cmd;
lcmd = (struct listcmd*)cmd;
nulterminate(lcmd->left);
nulterminate(lcmd->right);
break;
case BACK:
bcmd = (struct backcmd *)cmd;
bcmd = (struct backcmd*)cmd;
nulterminate(bcmd->cmd);
break;
}

View File

@ -13,7 +13,9 @@
#include "kernel/fs.h"
#include "kernel/fcntl.h"
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[])
{
int fd, i;
char path[] = "stressfs0";
char data[512];
@ -21,16 +23,16 @@ int main(int argc, char *argv[]) {
printf("stressfs starting\n");
memset(data, 'a', sizeof(data));
for (i = 0; i < 4; i++)
if (fork() > 0)
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);
for(i = 0; i < 20; i++)
// printf(fd, "%d\n", i);
write(fd, data, sizeof(data));
close(fd);

View File

@ -6,107 +6,129 @@
//
// wrapper so that it's OK if main() does not call exit().
//
void _main() {
void
_main()
{
extern int main();
main();
exit(0);
}
char *strcpy(char *s, const char *t) {
char*
strcpy(char *s, const char *t)
{
char *os;
os = s;
while ((*s++ = *t++) != 0)
while((*s++ = *t++) != 0)
;
return os;
}
int strcmp(const char *p, const char *q) {
while (*p && *p == *q)
int
strcmp(const char *p, const char *q)
{
while(*p && *p == *q)
p++, q++;
return (uchar)*p - (uchar)*q;
}
uint strlen(const char *s) {
uint
strlen(const char *s)
{
int n;
for (n = 0; s[n]; n++)
for(n = 0; s[n]; n++)
;
return n;
}
void *memset(void *dst, int c, uint n) {
char *cdst = (char *)dst;
void*
memset(void *dst, int c, uint n)
{
char *cdst = (char *) dst;
int i;
for (i = 0; i < n; 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;
char*
strchr(const char *s, char c)
{
for(; *s; s++)
if(*s == c)
return (char*)s;
return 0;
}
char *gets(char *buf, int max) {
char*
gets(char *buf, int max)
{
int i, cc;
char c;
for (i = 0; i + 1 < max;) {
for(i=0; i+1 < max; ){
cc = read(0, &c, 1);
if (cc < 1)
if(cc < 1)
break;
buf[i++] = c;
if (c == '\n' || c == '\r')
if(c == '\n' || c == '\r')
break;
}
buf[i] = '\0';
return buf;
}
int stat(const char *n, struct stat *st) {
int
stat(const char *n, struct stat *st)
{
int fd;
int r;
fd = open(n, O_RDONLY);
if (fd < 0)
if(fd < 0)
return -1;
r = fstat(fd, st);
close(fd);
return r;
}
int atoi(const char *s) {
int
atoi(const char *s)
{
int n;
n = 0;
while ('0' <= *s && *s <= '9')
n = n * 10 + *s++ - '0';
while('0' <= *s && *s <= '9')
n = n*10 + *s++ - '0';
return n;
}
void *memmove(void *vdst, const void *vsrc, int 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)
while(n-- > 0)
*dst++ = *src++;
} else {
dst += n;
src += n;
while (n-- > 0)
while(n-- > 0)
*--dst = *--src;
}
return vdst;
}
int memcmp(const void *s1, const void *s2, uint n) {
int
memcmp(const void *s1, const void *s2, uint n)
{
const char *p1 = s1, *p2 = s2;
while (n-- > 0) {
if (*p1 != *p2) {
@ -118,6 +140,8 @@ int memcmp(const void *s1, const void *s2, uint n) {
return 0;
}
void *memcpy(void *dst, const void *src, uint n) {
void *
memcpy(void *dst, const void *src, uint n)
{
return memmove(dst, src, n);
}

View File

@ -21,19 +21,21 @@ typedef union header Header;
static Header base;
static Header *freep;
void free(void *ap) {
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))
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) {
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) {
if(p + p->s.size == bp){
p->s.size += bp->s.size;
p->s.ptr = bp->s.ptr;
} else
@ -41,33 +43,37 @@ void free(void *ap) {
freep = p;
}
static Header *morecore(uint nu) {
static Header*
morecore(uint nu)
{
char *p;
Header *hp;
if (nu < 4096)
if(nu < 4096)
nu = 4096;
p = sbrk(nu * sizeof(Header));
if (p == (char *)-1)
if(p == (char*)-1)
return 0;
hp = (Header *)p;
hp = (Header*)p;
hp->s.size = nu;
free((void *)(hp + 1));
free((void*)(hp + 1));
return freep;
}
void *malloc(uint nbytes) {
void*
malloc(uint nbytes)
{
Header *p, *prevp;
uint nunits;
nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;
if ((prevp = freep) == 0) {
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)
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;
@ -75,10 +81,10 @@ void *malloc(uint nbytes) {
p->s.size = nunits;
}
freep = prevp;
return (void *)(p + 1);
return (void*)(p + 1);
}
if (p == freep)
if ((p = morecore(nunits)) == 0)
if(p == freep)
if((p = morecore(nunits)) == 0)
return 0;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -4,42 +4,46 @@
char buf[512];
void wc(int fd, char *name) {
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++) {
while((n = read(fd, buf, sizeof(buf))) > 0){
for(i=0; i<n; i++){
c++;
if (buf[i] == '\n')
if(buf[i] == '\n')
l++;
if (strchr(" \r\t\n\v", buf[i]))
if(strchr(" \r\t\n\v", buf[i]))
inword = 0;
else if (!inword) {
else if(!inword){
w++;
inword = 1;
}
}
}
if (n < 0) {
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
main(int argc, char *argv[])
{
int fd, i;
if (argc <= 1) {
if(argc <= 1){
wc(0, "");
exit(0);
}
for (i = 1; i < argc; i++) {
if ((fd = open(argv[i], 0)) < 0) {
for(i = 1; i < argc; i++){
if((fd = open(argv[i], 0)) < 0){
printf("wc: cannot open %s\n", argv[i]);
exit(1);
}

View File

@ -5,8 +5,10 @@
#include "kernel/stat.h"
#include "user/user.h"
int main(void) {
if (fork() > 0)
int
main(void)
{
if(fork() > 0)
sleep(5); // Let child exit before parent.
exit(0);
}