Compare commits

...

11 Commits

Author SHA1 Message Date
hheik 4cd2466900 First successful rust library call 2024-04-30 00:23:04 +03:00
hheik f33ef06498 Added basic rust library for testing 2024-04-29 22:56:23 +03:00
hheik 61a7340ea8 Updated .editorconfig 2024-04-29 22:37:09 +03:00
hheik 8102452c7f Formatted *.c files 2024-04-29 22:17:39 +03:00
Frans Kaashoek f5b93ef12f Update acks
61810
2022-08-25 14:20:52 -04:00
Frans Kaashoek 3d6ce9b308 Separate tests in slow and quick. The slow tests run xv6 out of
memory, out of disk space, or test big directories.

Support -q option to run only the quick tests, which saves about
7mins.

Clean up driver by removing duplicated code.
2022-08-25 09:45:35 -04:00
Robert Morris ed101befee comment the sfences 2022-08-24 13:47:47 -04:00
Robert Morris 581bc4cbd1 sfence before enabling paging 2022-08-24 13:42:59 -04:00
Robert Morris 29ce3161f8 Merge branch 'riscv' of g.csail.mit.edu:xv6-dev into riscv 2022-08-24 13:24:37 -04:00
Robert Morris 9c1b8a4eb0 sfence before writing satp, as well as after 2022-08-24 13:24:24 -04:00
Frans Kaashoek cc486ddee0 Help students read this C syntax 2022-08-24 08:57:56 -04:00
55 changed files with 7050 additions and 7683 deletions

5
.cargo/config.toml Normal file
View File

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

4
.clang-format Normal file
View File

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

View File

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

1
.rustfmt.toml Normal file
View File

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

View File

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

36
README
View File

@ -6,7 +6,7 @@ ACKNOWLEDGMENTS
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14, to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
2000)). See also https://pdos.csail.mit.edu/6.828/, which provides 2000)). See also https://pdos.csail.mit.edu/6.1810/, which provides
pointers to on-line resources for v6. pointers to on-line resources for v6.
The following people have made contributions: Russ Cox (context switching, The following people have made contributions: Russ Cox (context switching,
@ -14,29 +14,31 @@ locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
Clements. Clements.
We are also grateful for the bug reports and patches contributed by We are also grateful for the bug reports and patches contributed by
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, Ian Chen, Dan Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian
Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,
Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark, eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel
Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry, Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt
jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John
Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt, Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller,
Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin
Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan
Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider, Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel
OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek, Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude
Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal,
Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe,
Zheng, ZhUyU1997, and Zou Chang Wei. Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng,
ZhUyU1997, and Zou Chang Wei.
The code in the files that constitute xv6 is The code in the files that constitute xv6 is
Copyright 2006-2020 Frans Kaashoek, Robert Morris, and Russ Cox. Copyright 2006-2022 Frans Kaashoek, Robert Morris, and Russ Cox.
ERROR REPORTS ERROR REPORTS
Please send errors and suggestions to Frans Kaashoek and Robert Morris Please send errors and suggestions to Frans Kaashoek and Robert Morris
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching (kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
operating system for MIT's 6.S081, so we are more interested in operating system for MIT's 6.1810, so we are more interested in
simplifications and clarifications than new features. simplifications and clarifications than new features.
BUILDING AND RUNNING XV6 BUILDING AND RUNNING XV6

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

@ -3,19 +3,22 @@
#include "memlayout.h" #include "memlayout.h"
#include "riscv.h" #include "riscv.h"
#include "defs.h" #include "defs.h"
#include <stdint.h>
extern int32_t add(int32_t right, int32_t left);
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("\n"); printf("\n");
printf("rust library call: add(1, 2) = %d\n", add(1, 2));
printf("\n");
kinit(); // physical page allocator kinit(); // physical page allocator
kvminit(); // create kernel page table kvminit(); // create kernel page table
kvminithart(); // turn on paging kvminithart(); // turn on paging
@ -32,7 +35,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,32 +48,23 @@ 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);
} }
// Prototypes for the functions that handle system calls.
extern uint64 sys_fork(void); extern uint64 sys_fork(void);
extern uint64 sys_exit(void); extern uint64 sys_exit(void);
extern uint64 sys_wait(void); extern uint64 sys_wait(void);
@ -101,42 +87,29 @@ extern uint64 sys_link(void);
extern uint64 sys_mkdir(void); extern uint64 sys_mkdir(void);
extern uint64 sys_close(void); extern uint64 sys_close(void);
// An array mapping syscall numbers from syscall.h
// to the function that handles the system call.
static uint64 (*syscalls[])(void) = { 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,
// 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

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

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,18 +49,17 @@ 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.
{ sfence_vma();
w_satp(MAKE_SATP(kernel_pagetable)); w_satp(MAKE_SATP(kernel_pagetable));
// flush stale entries from the TLB.
sfence_vma(); sfence_vma();
} }
@ -77,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;
@ -100,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;
@ -123,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");
} }
@ -134,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;
@ -162,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;
} }
@ -188,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;
@ -202,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;
@ -247,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);
} }
@ -263,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);
} }
@ -297,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;
} }
@ -343,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);
@ -368,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);
@ -394,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;
@ -426,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);
} }

1
rust/foo/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

7
rust/foo/Cargo.lock generated Normal file
View File

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

14
rust/foo/Cargo.toml Normal file
View File

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

13
rust/foo/src/lib.rs Normal file
View File

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

View File

@ -4,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,289 +39,282 @@ 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);
} }
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,18 +324,17 @@ 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);
rand_next += 1;
} }
} }

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);
} }