Formatted *.c files

feat/start
hheik 2024-04-29 22:15:43 +03:00
parent f5b93ef12f
commit 8102452c7f
45 changed files with 6910 additions and 7633 deletions

4
.clang-format Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,14 +7,13 @@
volatile static int started = 0; volatile static int started = 0;
// start() jumps here in supervisor mode on all CPUs. // start() jumps here in supervisor mode on all CPUs.
void void main() {
main() if (cpuid() == 0) {
{
if(cpuid() == 0){
consoleinit(); consoleinit();
printfinit(); printfinit();
printf("\n"); printf("\n");
printf("xv6 kernel is booting\n"); printf("xv6 kernel is booting\n");
// printf("rustlib: add(1, 2) = %d\n", add(1, 2));
printf("\n"); printf("\n");
kinit(); // physical page allocator kinit(); // physical page allocator
kvminit(); // create kernel page table kvminit(); // create kernel page table
@ -32,7 +31,7 @@ main()
__sync_synchronize(); __sync_synchronize();
started = 1; started = 1;
} else { } else {
while(started == 0) while (started == 0)
; ;
__sync_synchronize(); __sync_synchronize();
printf("hart %d starting\n", cpuid()); printf("hart %d starting\n", cpuid());

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

219
user/sh.c
View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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