Compare commits
11 Commits
96047832c6
...
4cd2466900
| Author | SHA1 | Date |
|---|---|---|
|
|
4cd2466900 | |
|
|
f33ef06498 | |
|
|
61a7340ea8 | |
|
|
8102452c7f | |
|
|
f5b93ef12f | |
|
|
3d6ce9b308 | |
|
|
ed101befee | |
|
|
581bc4cbd1 | |
|
|
29ce3161f8 | |
|
|
9c1b8a4eb0 | |
|
|
cc486ddee0 |
|
|
@ -0,0 +1,5 @@
|
|||
[build]
|
||||
target = "riscv64gc-unknown-none-elf"
|
||||
|
||||
[target.riscv64-unknown-elf]
|
||||
linker = "/opt/riscv/bin/riscv64-unknown-elf-gcc"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
SortIncludes: Never
|
||||
UseTab: Always
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
|
|
@ -4,19 +4,4 @@ root = true
|
|||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.{c,h}]
|
||||
indent_size = 2
|
||||
|
||||
[*.S]
|
||||
indent_size = 8
|
||||
|
||||
[*.ld]
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
hard_tabs = true
|
||||
14
Makefile
14
Makefile
|
|
@ -1,5 +1,8 @@
|
|||
K=kernel
|
||||
U=user
|
||||
R=rust
|
||||
|
||||
RTARGET = riscv64gc-unknown-none-elf
|
||||
|
||||
OBJS = \
|
||||
$K/entry.o \
|
||||
|
|
@ -30,6 +33,9 @@ OBJS = \
|
|||
$K/plic.o \
|
||||
$K/virtio_disk.o
|
||||
|
||||
RLIBS = \
|
||||
$R/foo/target/$(RTARGET)/release/libfoo.a
|
||||
|
||||
# riscv64-unknown-elf- or riscv64-linux-gnu-
|
||||
# perhaps in /opt/riscv/bin
|
||||
#TOOLPREFIX =
|
||||
|
|
@ -73,8 +79,8 @@ endif
|
|||
|
||||
LDFLAGS = -z max-page-size=4096
|
||||
|
||||
$K/kernel: $(OBJS) $K/kernel.ld $U/initcode
|
||||
$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS)
|
||||
$K/kernel: $(OBJS) $K/kernel.ld $U/initcode rustlibs
|
||||
$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS) $(RLIBS)
|
||||
$(OBJDUMP) -S $K/kernel > $K/kernel.asm
|
||||
$(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
|
||||
|
||||
rustlibs:
|
||||
cargo build -r --manifest-path $R/foo/Cargo.toml
|
||||
|
||||
clean:
|
||||
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
|
||||
*/*.o */*.d */*.asm */*.sym \
|
||||
|
|
@ -145,6 +154,7 @@ clean:
|
|||
mkfs/mkfs .gdbinit \
|
||||
$U/usys.S \
|
||||
$(UPROGS)
|
||||
cargo clean --manifest-path $R/foo/Cargo.toml
|
||||
|
||||
# try to generate a unique GDB port
|
||||
GDBPORT = $(shell expr `id -u` % 5000 + 25000)
|
||||
|
|
|
|||
36
README
36
README
|
|
@ -6,7 +6,7 @@ ACKNOWLEDGMENTS
|
|||
|
||||
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
|
||||
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
|
||||
2000)). See also https://pdos.csail.mit.edu/6.828/, which provides
|
||||
2000)). See also https://pdos.csail.mit.edu/6.1810/, which provides
|
||||
pointers to on-line resources for v6.
|
||||
|
||||
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.
|
||||
|
||||
We are also grateful for the bug reports and patches contributed by
|
||||
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, Ian Chen, Dan
|
||||
Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson
|
||||
Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark,
|
||||
Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry,
|
||||
jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders
|
||||
Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt,
|
||||
Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan
|
||||
Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi
|
||||
Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
|
||||
OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek,
|
||||
Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey,
|
||||
Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi
|
||||
Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy
|
||||
Zheng, ZhUyU1997, and Zou Chang Wei.
|
||||
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian
|
||||
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,
|
||||
eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel
|
||||
Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt
|
||||
Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John
|
||||
Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller,
|
||||
Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin
|
||||
Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan
|
||||
Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel
|
||||
Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude
|
||||
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
|
||||
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal,
|
||||
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe,
|
||||
Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng,
|
||||
ZhUyU1997, and Zou Chang Wei.
|
||||
|
||||
|
||||
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
|
||||
|
||||
Please send errors and suggestions to Frans Kaashoek and Robert Morris
|
||||
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
|
||||
operating system for MIT's 6.S081, so we are more interested in
|
||||
operating system for MIT's 6.1810, so we are more interested in
|
||||
simplifications and clarifications than new features.
|
||||
|
||||
BUILDING AND RUNNING XV6
|
||||
|
|
|
|||
179
kernel/bio.c
179
kernel/bio.c
|
|
@ -13,7 +13,6 @@
|
|||
// * Only one process at a time can use a buffer,
|
||||
// so do not keep them longer than necessary.
|
||||
|
||||
|
||||
#include "types.h"
|
||||
#include "param.h"
|
||||
#include "spinlock.h"
|
||||
|
|
@ -24,130 +23,116 @@
|
|||
#include "buf.h"
|
||||
|
||||
struct {
|
||||
struct spinlock lock;
|
||||
struct buf buf[NBUF];
|
||||
struct spinlock lock;
|
||||
struct buf buf[NBUF];
|
||||
|
||||
// Linked list of all buffers, through prev/next.
|
||||
// Sorted by how recently the buffer was used.
|
||||
// head.next is most recent, head.prev is least.
|
||||
struct buf head;
|
||||
// Linked list of all buffers, through prev/next.
|
||||
// Sorted by how recently the buffer was used.
|
||||
// head.next is most recent, head.prev is least.
|
||||
struct buf head;
|
||||
} bcache;
|
||||
|
||||
void
|
||||
binit(void)
|
||||
{
|
||||
struct buf *b;
|
||||
void binit(void) {
|
||||
struct buf *b;
|
||||
|
||||
initlock(&bcache.lock, "bcache");
|
||||
initlock(&bcache.lock, "bcache");
|
||||
|
||||
// Create linked list of buffers
|
||||
bcache.head.prev = &bcache.head;
|
||||
bcache.head.next = &bcache.head;
|
||||
for(b = bcache.buf; b < bcache.buf+NBUF; b++){
|
||||
b->next = bcache.head.next;
|
||||
b->prev = &bcache.head;
|
||||
initsleeplock(&b->lock, "buffer");
|
||||
bcache.head.next->prev = b;
|
||||
bcache.head.next = b;
|
||||
}
|
||||
// Create linked list of buffers
|
||||
bcache.head.prev = &bcache.head;
|
||||
bcache.head.next = &bcache.head;
|
||||
for (b = bcache.buf; b < bcache.buf + NBUF; b++) {
|
||||
b->next = bcache.head.next;
|
||||
b->prev = &bcache.head;
|
||||
initsleeplock(&b->lock, "buffer");
|
||||
bcache.head.next->prev = b;
|
||||
bcache.head.next = b;
|
||||
}
|
||||
}
|
||||
|
||||
// Look through buffer cache for block on device dev.
|
||||
// If not found, allocate a buffer.
|
||||
// In either case, return locked buffer.
|
||||
static struct buf*
|
||||
bget(uint dev, uint blockno)
|
||||
{
|
||||
struct buf *b;
|
||||
static struct buf *bget(uint dev, uint blockno) {
|
||||
struct buf *b;
|
||||
|
||||
acquire(&bcache.lock);
|
||||
acquire(&bcache.lock);
|
||||
|
||||
// Is the block already cached?
|
||||
for(b = bcache.head.next; b != &bcache.head; b = b->next){
|
||||
if(b->dev == dev && b->blockno == blockno){
|
||||
b->refcnt++;
|
||||
release(&bcache.lock);
|
||||
acquiresleep(&b->lock);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
// Is the block already cached?
|
||||
for (b = bcache.head.next; b != &bcache.head; b = b->next) {
|
||||
if (b->dev == dev && b->blockno == blockno) {
|
||||
b->refcnt++;
|
||||
release(&bcache.lock);
|
||||
acquiresleep(&b->lock);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
// Not cached.
|
||||
// Recycle the least recently used (LRU) unused buffer.
|
||||
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
|
||||
if(b->refcnt == 0) {
|
||||
b->dev = dev;
|
||||
b->blockno = blockno;
|
||||
b->valid = 0;
|
||||
b->refcnt = 1;
|
||||
release(&bcache.lock);
|
||||
acquiresleep(&b->lock);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
panic("bget: no buffers");
|
||||
// Not cached.
|
||||
// Recycle the least recently used (LRU) unused buffer.
|
||||
for (b = bcache.head.prev; b != &bcache.head; b = b->prev) {
|
||||
if (b->refcnt == 0) {
|
||||
b->dev = dev;
|
||||
b->blockno = blockno;
|
||||
b->valid = 0;
|
||||
b->refcnt = 1;
|
||||
release(&bcache.lock);
|
||||
acquiresleep(&b->lock);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
panic("bget: no buffers");
|
||||
}
|
||||
|
||||
// Return a locked buf with the contents of the indicated block.
|
||||
struct buf*
|
||||
bread(uint dev, uint blockno)
|
||||
{
|
||||
struct buf *b;
|
||||
struct buf *bread(uint dev, uint blockno) {
|
||||
struct buf *b;
|
||||
|
||||
b = bget(dev, blockno);
|
||||
if(!b->valid) {
|
||||
virtio_disk_rw(b, 0);
|
||||
b->valid = 1;
|
||||
}
|
||||
return b;
|
||||
b = bget(dev, blockno);
|
||||
if (!b->valid) {
|
||||
virtio_disk_rw(b, 0);
|
||||
b->valid = 1;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// Write b's contents to disk. Must be locked.
|
||||
void
|
||||
bwrite(struct buf *b)
|
||||
{
|
||||
if(!holdingsleep(&b->lock))
|
||||
panic("bwrite");
|
||||
virtio_disk_rw(b, 1);
|
||||
void bwrite(struct buf *b) {
|
||||
if (!holdingsleep(&b->lock))
|
||||
panic("bwrite");
|
||||
virtio_disk_rw(b, 1);
|
||||
}
|
||||
|
||||
// Release a locked buffer.
|
||||
// Move to the head of the most-recently-used list.
|
||||
void
|
||||
brelse(struct buf *b)
|
||||
{
|
||||
if(!holdingsleep(&b->lock))
|
||||
panic("brelse");
|
||||
void brelse(struct buf *b) {
|
||||
if (!holdingsleep(&b->lock))
|
||||
panic("brelse");
|
||||
|
||||
releasesleep(&b->lock);
|
||||
releasesleep(&b->lock);
|
||||
|
||||
acquire(&bcache.lock);
|
||||
b->refcnt--;
|
||||
if (b->refcnt == 0) {
|
||||
// no one is waiting for it.
|
||||
b->next->prev = b->prev;
|
||||
b->prev->next = b->next;
|
||||
b->next = bcache.head.next;
|
||||
b->prev = &bcache.head;
|
||||
bcache.head.next->prev = b;
|
||||
bcache.head.next = b;
|
||||
}
|
||||
|
||||
release(&bcache.lock);
|
||||
acquire(&bcache.lock);
|
||||
b->refcnt--;
|
||||
if (b->refcnt == 0) {
|
||||
// no one is waiting for it.
|
||||
b->next->prev = b->prev;
|
||||
b->prev->next = b->next;
|
||||
b->next = bcache.head.next;
|
||||
b->prev = &bcache.head;
|
||||
bcache.head.next->prev = b;
|
||||
bcache.head.next = b;
|
||||
}
|
||||
|
||||
release(&bcache.lock);
|
||||
}
|
||||
|
||||
void
|
||||
bpin(struct buf *b) {
|
||||
acquire(&bcache.lock);
|
||||
b->refcnt++;
|
||||
release(&bcache.lock);
|
||||
void bpin(struct buf *b) {
|
||||
acquire(&bcache.lock);
|
||||
b->refcnt++;
|
||||
release(&bcache.lock);
|
||||
}
|
||||
|
||||
void
|
||||
bunpin(struct buf *b) {
|
||||
acquire(&bcache.lock);
|
||||
b->refcnt--;
|
||||
release(&bcache.lock);
|
||||
void bunpin(struct buf *b) {
|
||||
acquire(&bcache.lock);
|
||||
b->refcnt--;
|
||||
release(&bcache.lock);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
228
kernel/console.c
228
kernel/console.c
|
|
@ -23,51 +23,49 @@
|
|||
#include "proc.h"
|
||||
|
||||
#define BACKSPACE 0x100
|
||||
#define C(x) ((x)-'@') // Control-x
|
||||
#define C(x) ((x) - '@') // Control-x
|
||||
|
||||
//
|
||||
// send one character to the uart.
|
||||
// called by printf(), and to echo input characters,
|
||||
// but not from write().
|
||||
//
|
||||
void
|
||||
consputc(int c)
|
||||
{
|
||||
if(c == BACKSPACE){
|
||||
// if the user typed backspace, overwrite with a space.
|
||||
uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b');
|
||||
} else {
|
||||
uartputc_sync(c);
|
||||
}
|
||||
void consputc(int c) {
|
||||
if (c == BACKSPACE) {
|
||||
// if the user typed backspace, overwrite with a space.
|
||||
uartputc_sync('\b');
|
||||
uartputc_sync(' ');
|
||||
uartputc_sync('\b');
|
||||
} else {
|
||||
uartputc_sync(c);
|
||||
}
|
||||
}
|
||||
|
||||
struct {
|
||||
struct spinlock lock;
|
||||
|
||||
// input
|
||||
struct spinlock lock;
|
||||
|
||||
// input
|
||||
#define INPUT_BUF_SIZE 128
|
||||
char buf[INPUT_BUF_SIZE];
|
||||
uint r; // Read index
|
||||
uint w; // Write index
|
||||
uint e; // Edit index
|
||||
char buf[INPUT_BUF_SIZE];
|
||||
uint r; // Read index
|
||||
uint w; // Write index
|
||||
uint e; // Edit index
|
||||
} cons;
|
||||
|
||||
//
|
||||
// user write()s to the console go here.
|
||||
//
|
||||
int
|
||||
consolewrite(int user_src, uint64 src, int n)
|
||||
{
|
||||
int i;
|
||||
int consolewrite(int user_src, uint64 src, int n) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < n; i++){
|
||||
char c;
|
||||
if(either_copyin(&c, user_src, src+i, 1) == -1)
|
||||
break;
|
||||
uartputc(c);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
char c;
|
||||
if (either_copyin(&c, user_src, src + i, 1) == -1)
|
||||
break;
|
||||
uartputc(c);
|
||||
}
|
||||
|
||||
return i;
|
||||
return i;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -76,54 +74,52 @@ consolewrite(int user_src, uint64 src, int n)
|
|||
// user_dist indicates whether dst is a user
|
||||
// or kernel address.
|
||||
//
|
||||
int
|
||||
consoleread(int user_dst, uint64 dst, int n)
|
||||
{
|
||||
uint target;
|
||||
int c;
|
||||
char cbuf;
|
||||
int consoleread(int user_dst, uint64 dst, int n) {
|
||||
uint target;
|
||||
int c;
|
||||
char cbuf;
|
||||
|
||||
target = n;
|
||||
acquire(&cons.lock);
|
||||
while(n > 0){
|
||||
// wait until interrupt handler has put some
|
||||
// input into cons.buffer.
|
||||
while(cons.r == cons.w){
|
||||
if(killed(myproc())){
|
||||
release(&cons.lock);
|
||||
return -1;
|
||||
}
|
||||
sleep(&cons.r, &cons.lock);
|
||||
}
|
||||
target = n;
|
||||
acquire(&cons.lock);
|
||||
while (n > 0) {
|
||||
// wait until interrupt handler has put some
|
||||
// input into cons.buffer.
|
||||
while (cons.r == cons.w) {
|
||||
if (killed(myproc())) {
|
||||
release(&cons.lock);
|
||||
return -1;
|
||||
}
|
||||
sleep(&cons.r, &cons.lock);
|
||||
}
|
||||
|
||||
c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
|
||||
c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
|
||||
|
||||
if(c == C('D')){ // end-of-file
|
||||
if(n < target){
|
||||
// Save ^D for next time, to make sure
|
||||
// caller gets a 0-byte result.
|
||||
cons.r--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c == C('D')) { // end-of-file
|
||||
if (n < target) {
|
||||
// Save ^D for next time, to make sure
|
||||
// caller gets a 0-byte result.
|
||||
cons.r--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// copy the input byte to the user-space buffer.
|
||||
cbuf = c;
|
||||
if(either_copyout(user_dst, dst, &cbuf, 1) == -1)
|
||||
break;
|
||||
// copy the input byte to the user-space buffer.
|
||||
cbuf = c;
|
||||
if (either_copyout(user_dst, dst, &cbuf, 1) == -1)
|
||||
break;
|
||||
|
||||
dst++;
|
||||
--n;
|
||||
dst++;
|
||||
--n;
|
||||
|
||||
if(c == '\n'){
|
||||
// a whole line has arrived, return to
|
||||
// the user-level read().
|
||||
break;
|
||||
}
|
||||
}
|
||||
release(&cons.lock);
|
||||
if (c == '\n') {
|
||||
// a whole line has arrived, return to
|
||||
// the user-level read().
|
||||
break;
|
||||
}
|
||||
}
|
||||
release(&cons.lock);
|
||||
|
||||
return target - n;
|
||||
return target - n;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -132,61 +128,57 @@ consoleread(int user_dst, uint64 dst, int n)
|
|||
// do erase/kill processing, append to cons.buf,
|
||||
// wake up consoleread() if a whole line has arrived.
|
||||
//
|
||||
void
|
||||
consoleintr(int c)
|
||||
{
|
||||
acquire(&cons.lock);
|
||||
void consoleintr(int c) {
|
||||
acquire(&cons.lock);
|
||||
|
||||
switch(c){
|
||||
case C('P'): // Print process list.
|
||||
procdump();
|
||||
break;
|
||||
case C('U'): // Kill line.
|
||||
while(cons.e != cons.w &&
|
||||
cons.buf[(cons.e-1) % INPUT_BUF_SIZE] != '\n'){
|
||||
cons.e--;
|
||||
consputc(BACKSPACE);
|
||||
}
|
||||
break;
|
||||
case C('H'): // Backspace
|
||||
case '\x7f': // Delete key
|
||||
if(cons.e != cons.w){
|
||||
cons.e--;
|
||||
consputc(BACKSPACE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(c != 0 && cons.e-cons.r < INPUT_BUF_SIZE){
|
||||
c = (c == '\r') ? '\n' : c;
|
||||
switch (c) {
|
||||
case C('P'): // Print process list.
|
||||
procdump();
|
||||
break;
|
||||
case C('U'): // Kill line.
|
||||
while (cons.e != cons.w &&
|
||||
cons.buf[(cons.e - 1) % INPUT_BUF_SIZE] != '\n') {
|
||||
cons.e--;
|
||||
consputc(BACKSPACE);
|
||||
}
|
||||
break;
|
||||
case C('H'): // Backspace
|
||||
case '\x7f': // Delete key
|
||||
if (cons.e != cons.w) {
|
||||
cons.e--;
|
||||
consputc(BACKSPACE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (c != 0 && cons.e - cons.r < INPUT_BUF_SIZE) {
|
||||
c = (c == '\r') ? '\n' : c;
|
||||
|
||||
// echo back to the user.
|
||||
consputc(c);
|
||||
// echo back to the user.
|
||||
consputc(c);
|
||||
|
||||
// store for consumption by consoleread().
|
||||
cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
|
||||
// store for consumption by consoleread().
|
||||
cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
|
||||
|
||||
if(c == '\n' || c == C('D') || cons.e-cons.r == INPUT_BUF_SIZE){
|
||||
// wake up consoleread() if a whole line (or end-of-file)
|
||||
// has arrived.
|
||||
cons.w = cons.e;
|
||||
wakeup(&cons.r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
release(&cons.lock);
|
||||
if (c == '\n' || c == C('D') || cons.e - cons.r == INPUT_BUF_SIZE) {
|
||||
// wake up consoleread() if a whole line (or end-of-file)
|
||||
// has arrived.
|
||||
cons.w = cons.e;
|
||||
wakeup(&cons.r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
release(&cons.lock);
|
||||
}
|
||||
|
||||
void
|
||||
consoleinit(void)
|
||||
{
|
||||
initlock(&cons.lock, "cons");
|
||||
void consoleinit(void) {
|
||||
initlock(&cons.lock, "cons");
|
||||
|
||||
uartinit();
|
||||
uartinit();
|
||||
|
||||
// connect read and write system calls
|
||||
// to consoleread and consolewrite.
|
||||
devsw[CONSOLE].read = consoleread;
|
||||
devsw[CONSOLE].write = consolewrite;
|
||||
// connect read and write system calls
|
||||
// to consoleread and consolewrite.
|
||||
devsw[CONSOLE].read = consoleread;
|
||||
devsw[CONSOLE].write = consolewrite;
|
||||
}
|
||||
|
|
|
|||
259
kernel/exec.c
259
kernel/exec.c
|
|
@ -9,158 +9,155 @@
|
|||
|
||||
static int loadseg(pde_t *, uint64, struct inode *, uint, uint);
|
||||
|
||||
int flags2perm(int flags)
|
||||
{
|
||||
int perm = 0;
|
||||
if(flags & 0x1)
|
||||
perm = PTE_X;
|
||||
if(flags & 0x2)
|
||||
perm |= PTE_W;
|
||||
return perm;
|
||||
int flags2perm(int flags) {
|
||||
int perm = 0;
|
||||
if (flags & 0x1)
|
||||
perm = PTE_X;
|
||||
if (flags & 0x2)
|
||||
perm |= PTE_W;
|
||||
return perm;
|
||||
}
|
||||
|
||||
int
|
||||
exec(char *path, char **argv)
|
||||
{
|
||||
char *s, *last;
|
||||
int i, off;
|
||||
uint64 argc, sz = 0, sp, ustack[MAXARG], stackbase;
|
||||
struct elfhdr elf;
|
||||
struct inode *ip;
|
||||
struct proghdr ph;
|
||||
pagetable_t pagetable = 0, oldpagetable;
|
||||
struct proc *p = myproc();
|
||||
int exec(char *path, char **argv) {
|
||||
char *s, *last;
|
||||
int i, off;
|
||||
uint64 argc, sz = 0, sp, ustack[MAXARG], stackbase;
|
||||
struct elfhdr elf;
|
||||
struct inode *ip;
|
||||
struct proghdr ph;
|
||||
pagetable_t pagetable = 0, oldpagetable;
|
||||
struct proc *p = myproc();
|
||||
|
||||
begin_op();
|
||||
begin_op();
|
||||
|
||||
if((ip = namei(path)) == 0){
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
ilock(ip);
|
||||
if ((ip = namei(path)) == 0) {
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
ilock(ip);
|
||||
|
||||
// Check ELF header
|
||||
if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf))
|
||||
goto bad;
|
||||
// Check ELF header
|
||||
if (readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf))
|
||||
goto bad;
|
||||
|
||||
if(elf.magic != ELF_MAGIC)
|
||||
goto bad;
|
||||
if (elf.magic != ELF_MAGIC)
|
||||
goto bad;
|
||||
|
||||
if((pagetable = proc_pagetable(p)) == 0)
|
||||
goto bad;
|
||||
if ((pagetable = proc_pagetable(p)) == 0)
|
||||
goto bad;
|
||||
|
||||
// Load program into memory.
|
||||
for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
|
||||
if(readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
|
||||
goto bad;
|
||||
if(ph.type != ELF_PROG_LOAD)
|
||||
continue;
|
||||
if(ph.memsz < ph.filesz)
|
||||
goto bad;
|
||||
if(ph.vaddr + ph.memsz < ph.vaddr)
|
||||
goto bad;
|
||||
if(ph.vaddr % PGSIZE != 0)
|
||||
goto bad;
|
||||
uint64 sz1;
|
||||
if((sz1 = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz, flags2perm(ph.flags))) == 0)
|
||||
goto bad;
|
||||
sz = sz1;
|
||||
if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0)
|
||||
goto bad;
|
||||
}
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
ip = 0;
|
||||
// Load program into memory.
|
||||
for (i = 0, off = elf.phoff; i < elf.phnum; i++, off += sizeof(ph)) {
|
||||
if (readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))
|
||||
goto bad;
|
||||
if (ph.type != ELF_PROG_LOAD)
|
||||
continue;
|
||||
if (ph.memsz < ph.filesz)
|
||||
goto bad;
|
||||
if (ph.vaddr + ph.memsz < ph.vaddr)
|
||||
goto bad;
|
||||
if (ph.vaddr % PGSIZE != 0)
|
||||
goto bad;
|
||||
uint64 sz1;
|
||||
if ((sz1 = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz,
|
||||
flags2perm(ph.flags))) == 0)
|
||||
goto bad;
|
||||
sz = sz1;
|
||||
if (loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0)
|
||||
goto bad;
|
||||
}
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
ip = 0;
|
||||
|
||||
p = myproc();
|
||||
uint64 oldsz = p->sz;
|
||||
p = myproc();
|
||||
uint64 oldsz = p->sz;
|
||||
|
||||
// Allocate two pages at the next page boundary.
|
||||
// Make the first inaccessible as a stack guard.
|
||||
// Use the second as the user stack.
|
||||
sz = PGROUNDUP(sz);
|
||||
uint64 sz1;
|
||||
if((sz1 = uvmalloc(pagetable, sz, sz + 2*PGSIZE, PTE_W)) == 0)
|
||||
goto bad;
|
||||
sz = sz1;
|
||||
uvmclear(pagetable, sz-2*PGSIZE);
|
||||
sp = sz;
|
||||
stackbase = sp - PGSIZE;
|
||||
// Allocate two pages at the next page boundary.
|
||||
// Make the first inaccessible as a stack guard.
|
||||
// Use the second as the user stack.
|
||||
sz = PGROUNDUP(sz);
|
||||
uint64 sz1;
|
||||
if ((sz1 = uvmalloc(pagetable, sz, sz + 2 * PGSIZE, PTE_W)) == 0)
|
||||
goto bad;
|
||||
sz = sz1;
|
||||
uvmclear(pagetable, sz - 2 * PGSIZE);
|
||||
sp = sz;
|
||||
stackbase = sp - PGSIZE;
|
||||
|
||||
// Push argument strings, prepare rest of stack in ustack.
|
||||
for(argc = 0; argv[argc]; argc++) {
|
||||
if(argc >= MAXARG)
|
||||
goto bad;
|
||||
sp -= strlen(argv[argc]) + 1;
|
||||
sp -= sp % 16; // riscv sp must be 16-byte aligned
|
||||
if(sp < stackbase)
|
||||
goto bad;
|
||||
if(copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
|
||||
goto bad;
|
||||
ustack[argc] = sp;
|
||||
}
|
||||
ustack[argc] = 0;
|
||||
// Push argument strings, prepare rest of stack in ustack.
|
||||
for (argc = 0; argv[argc]; argc++) {
|
||||
if (argc >= MAXARG)
|
||||
goto bad;
|
||||
sp -= strlen(argv[argc]) + 1;
|
||||
sp -= sp % 16; // riscv sp must be 16-byte aligned
|
||||
if (sp < stackbase)
|
||||
goto bad;
|
||||
if (copyout(pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
|
||||
goto bad;
|
||||
ustack[argc] = sp;
|
||||
}
|
||||
ustack[argc] = 0;
|
||||
|
||||
// push the array of argv[] pointers.
|
||||
sp -= (argc+1) * sizeof(uint64);
|
||||
sp -= sp % 16;
|
||||
if(sp < stackbase)
|
||||
goto bad;
|
||||
if(copyout(pagetable, sp, (char *)ustack, (argc+1)*sizeof(uint64)) < 0)
|
||||
goto bad;
|
||||
// push the array of argv[] pointers.
|
||||
sp -= (argc + 1) * sizeof(uint64);
|
||||
sp -= sp % 16;
|
||||
if (sp < stackbase)
|
||||
goto bad;
|
||||
if (copyout(pagetable, sp, (char *)ustack, (argc + 1) * sizeof(uint64)) < 0)
|
||||
goto bad;
|
||||
|
||||
// arguments to user main(argc, argv)
|
||||
// argc is returned via the system call return
|
||||
// value, which goes in a0.
|
||||
p->trapframe->a1 = sp;
|
||||
// arguments to user main(argc, argv)
|
||||
// argc is returned via the system call return
|
||||
// value, which goes in a0.
|
||||
p->trapframe->a1 = sp;
|
||||
|
||||
// Save program name for debugging.
|
||||
for(last=s=path; *s; s++)
|
||||
if(*s == '/')
|
||||
last = s+1;
|
||||
safestrcpy(p->name, last, sizeof(p->name));
|
||||
|
||||
// Commit to the user image.
|
||||
oldpagetable = p->pagetable;
|
||||
p->pagetable = pagetable;
|
||||
p->sz = sz;
|
||||
p->trapframe->epc = elf.entry; // initial program counter = main
|
||||
p->trapframe->sp = sp; // initial stack pointer
|
||||
proc_freepagetable(oldpagetable, oldsz);
|
||||
// Save program name for debugging.
|
||||
for (last = s = path; *s; s++)
|
||||
if (*s == '/')
|
||||
last = s + 1;
|
||||
safestrcpy(p->name, last, sizeof(p->name));
|
||||
|
||||
return argc; // this ends up in a0, the first argument to main(argc, argv)
|
||||
// Commit to the user image.
|
||||
oldpagetable = p->pagetable;
|
||||
p->pagetable = pagetable;
|
||||
p->sz = sz;
|
||||
p->trapframe->epc = elf.entry; // initial program counter = main
|
||||
p->trapframe->sp = sp; // initial stack pointer
|
||||
proc_freepagetable(oldpagetable, oldsz);
|
||||
|
||||
bad:
|
||||
if(pagetable)
|
||||
proc_freepagetable(pagetable, sz);
|
||||
if(ip){
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
}
|
||||
return -1;
|
||||
return argc; // this ends up in a0, the first argument to main(argc, argv)
|
||||
|
||||
bad:
|
||||
if (pagetable)
|
||||
proc_freepagetable(pagetable, sz);
|
||||
if (ip) {
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Load a program segment into pagetable at virtual address va.
|
||||
// va must be page-aligned
|
||||
// and the pages from va to va+sz must already be mapped.
|
||||
// Returns 0 on success, -1 on failure.
|
||||
static int
|
||||
loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz)
|
||||
{
|
||||
uint i, n;
|
||||
uint64 pa;
|
||||
static int loadseg(pagetable_t pagetable, uint64 va, struct inode *ip,
|
||||
uint offset, uint sz) {
|
||||
uint i, n;
|
||||
uint64 pa;
|
||||
|
||||
for(i = 0; i < sz; i += PGSIZE){
|
||||
pa = walkaddr(pagetable, va + i);
|
||||
if(pa == 0)
|
||||
panic("loadseg: address should exist");
|
||||
if(sz - i < PGSIZE)
|
||||
n = sz - i;
|
||||
else
|
||||
n = PGSIZE;
|
||||
if(readi(ip, 0, (uint64)pa, offset+i, n) != n)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
for (i = 0; i < sz; i += PGSIZE) {
|
||||
pa = walkaddr(pagetable, va + i);
|
||||
if (pa == 0)
|
||||
panic("loadseg: address should exist");
|
||||
if (sz - i < PGSIZE)
|
||||
n = sz - i;
|
||||
else
|
||||
n = PGSIZE;
|
||||
if (readi(ip, 0, (uint64)pa, offset + i, n) != n)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
245
kernel/file.c
245
kernel/file.c
|
|
@ -15,168 +15,151 @@
|
|||
|
||||
struct devsw devsw[NDEV];
|
||||
struct {
|
||||
struct spinlock lock;
|
||||
struct file file[NFILE];
|
||||
struct spinlock lock;
|
||||
struct file file[NFILE];
|
||||
} ftable;
|
||||
|
||||
void
|
||||
fileinit(void)
|
||||
{
|
||||
initlock(&ftable.lock, "ftable");
|
||||
}
|
||||
void fileinit(void) { initlock(&ftable.lock, "ftable"); }
|
||||
|
||||
// Allocate a file structure.
|
||||
struct file*
|
||||
filealloc(void)
|
||||
{
|
||||
struct file *f;
|
||||
struct file *filealloc(void) {
|
||||
struct file *f;
|
||||
|
||||
acquire(&ftable.lock);
|
||||
for(f = ftable.file; f < ftable.file + NFILE; f++){
|
||||
if(f->ref == 0){
|
||||
f->ref = 1;
|
||||
release(&ftable.lock);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
release(&ftable.lock);
|
||||
return 0;
|
||||
acquire(&ftable.lock);
|
||||
for (f = ftable.file; f < ftable.file + NFILE; f++) {
|
||||
if (f->ref == 0) {
|
||||
f->ref = 1;
|
||||
release(&ftable.lock);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
release(&ftable.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Increment ref count for file f.
|
||||
struct file*
|
||||
filedup(struct file *f)
|
||||
{
|
||||
acquire(&ftable.lock);
|
||||
if(f->ref < 1)
|
||||
panic("filedup");
|
||||
f->ref++;
|
||||
release(&ftable.lock);
|
||||
return f;
|
||||
struct file *filedup(struct file *f) {
|
||||
acquire(&ftable.lock);
|
||||
if (f->ref < 1)
|
||||
panic("filedup");
|
||||
f->ref++;
|
||||
release(&ftable.lock);
|
||||
return f;
|
||||
}
|
||||
|
||||
// Close file f. (Decrement ref count, close when reaches 0.)
|
||||
void
|
||||
fileclose(struct file *f)
|
||||
{
|
||||
struct file ff;
|
||||
void fileclose(struct file *f) {
|
||||
struct file ff;
|
||||
|
||||
acquire(&ftable.lock);
|
||||
if(f->ref < 1)
|
||||
panic("fileclose");
|
||||
if(--f->ref > 0){
|
||||
release(&ftable.lock);
|
||||
return;
|
||||
}
|
||||
ff = *f;
|
||||
f->ref = 0;
|
||||
f->type = FD_NONE;
|
||||
release(&ftable.lock);
|
||||
acquire(&ftable.lock);
|
||||
if (f->ref < 1)
|
||||
panic("fileclose");
|
||||
if (--f->ref > 0) {
|
||||
release(&ftable.lock);
|
||||
return;
|
||||
}
|
||||
ff = *f;
|
||||
f->ref = 0;
|
||||
f->type = FD_NONE;
|
||||
release(&ftable.lock);
|
||||
|
||||
if(ff.type == FD_PIPE){
|
||||
pipeclose(ff.pipe, ff.writable);
|
||||
} else if(ff.type == FD_INODE || ff.type == FD_DEVICE){
|
||||
begin_op();
|
||||
iput(ff.ip);
|
||||
end_op();
|
||||
}
|
||||
if (ff.type == FD_PIPE) {
|
||||
pipeclose(ff.pipe, ff.writable);
|
||||
} else if (ff.type == FD_INODE || ff.type == FD_DEVICE) {
|
||||
begin_op();
|
||||
iput(ff.ip);
|
||||
end_op();
|
||||
}
|
||||
}
|
||||
|
||||
// Get metadata about file f.
|
||||
// addr is a user virtual address, pointing to a struct stat.
|
||||
int
|
||||
filestat(struct file *f, uint64 addr)
|
||||
{
|
||||
struct proc *p = myproc();
|
||||
struct stat st;
|
||||
|
||||
if(f->type == FD_INODE || f->type == FD_DEVICE){
|
||||
ilock(f->ip);
|
||||
stati(f->ip, &st);
|
||||
iunlock(f->ip);
|
||||
if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
int filestat(struct file *f, uint64 addr) {
|
||||
struct proc *p = myproc();
|
||||
struct stat st;
|
||||
|
||||
if (f->type == FD_INODE || f->type == FD_DEVICE) {
|
||||
ilock(f->ip);
|
||||
stati(f->ip, &st);
|
||||
iunlock(f->ip);
|
||||
if (copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read from file f.
|
||||
// addr is a user virtual address.
|
||||
int
|
||||
fileread(struct file *f, uint64 addr, int n)
|
||||
{
|
||||
int r = 0;
|
||||
int fileread(struct file *f, uint64 addr, int n) {
|
||||
int r = 0;
|
||||
|
||||
if(f->readable == 0)
|
||||
return -1;
|
||||
if (f->readable == 0)
|
||||
return -1;
|
||||
|
||||
if(f->type == FD_PIPE){
|
||||
r = piperead(f->pipe, addr, n);
|
||||
} else if(f->type == FD_DEVICE){
|
||||
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
|
||||
return -1;
|
||||
r = devsw[f->major].read(1, addr, n);
|
||||
} else if(f->type == FD_INODE){
|
||||
ilock(f->ip);
|
||||
if((r = readi(f->ip, 1, addr, f->off, n)) > 0)
|
||||
f->off += r;
|
||||
iunlock(f->ip);
|
||||
} else {
|
||||
panic("fileread");
|
||||
}
|
||||
if (f->type == FD_PIPE) {
|
||||
r = piperead(f->pipe, addr, n);
|
||||
} else if (f->type == FD_DEVICE) {
|
||||
if (f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
|
||||
return -1;
|
||||
r = devsw[f->major].read(1, addr, n);
|
||||
} else if (f->type == FD_INODE) {
|
||||
ilock(f->ip);
|
||||
if ((r = readi(f->ip, 1, addr, f->off, n)) > 0)
|
||||
f->off += r;
|
||||
iunlock(f->ip);
|
||||
} else {
|
||||
panic("fileread");
|
||||
}
|
||||
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
||||
// Write to file f.
|
||||
// addr is a user virtual address.
|
||||
int
|
||||
filewrite(struct file *f, uint64 addr, int n)
|
||||
{
|
||||
int r, ret = 0;
|
||||
int filewrite(struct file *f, uint64 addr, int n) {
|
||||
int r, ret = 0;
|
||||
|
||||
if(f->writable == 0)
|
||||
return -1;
|
||||
if (f->writable == 0)
|
||||
return -1;
|
||||
|
||||
if(f->type == FD_PIPE){
|
||||
ret = pipewrite(f->pipe, addr, n);
|
||||
} else if(f->type == FD_DEVICE){
|
||||
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].write)
|
||||
return -1;
|
||||
ret = devsw[f->major].write(1, addr, n);
|
||||
} else if(f->type == FD_INODE){
|
||||
// write a few blocks at a time to avoid exceeding
|
||||
// the maximum log transaction size, including
|
||||
// i-node, indirect block, allocation blocks,
|
||||
// and 2 blocks of slop for non-aligned writes.
|
||||
// this really belongs lower down, since writei()
|
||||
// might be writing a device like the console.
|
||||
int max = ((MAXOPBLOCKS-1-1-2) / 2) * BSIZE;
|
||||
int i = 0;
|
||||
while(i < n){
|
||||
int n1 = n - i;
|
||||
if(n1 > max)
|
||||
n1 = max;
|
||||
if (f->type == FD_PIPE) {
|
||||
ret = pipewrite(f->pipe, addr, n);
|
||||
} else if (f->type == FD_DEVICE) {
|
||||
if (f->major < 0 || f->major >= NDEV || !devsw[f->major].write)
|
||||
return -1;
|
||||
ret = devsw[f->major].write(1, addr, n);
|
||||
} else if (f->type == FD_INODE) {
|
||||
// write a few blocks at a time to avoid exceeding
|
||||
// the maximum log transaction size, including
|
||||
// i-node, indirect block, allocation blocks,
|
||||
// and 2 blocks of slop for non-aligned writes.
|
||||
// this really belongs lower down, since writei()
|
||||
// might be writing a device like the console.
|
||||
int max = ((MAXOPBLOCKS - 1 - 1 - 2) / 2) * BSIZE;
|
||||
int i = 0;
|
||||
while (i < n) {
|
||||
int n1 = n - i;
|
||||
if (n1 > max)
|
||||
n1 = max;
|
||||
|
||||
begin_op();
|
||||
ilock(f->ip);
|
||||
if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0)
|
||||
f->off += r;
|
||||
iunlock(f->ip);
|
||||
end_op();
|
||||
begin_op();
|
||||
ilock(f->ip);
|
||||
if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0)
|
||||
f->off += r;
|
||||
iunlock(f->ip);
|
||||
end_op();
|
||||
|
||||
if(r != n1){
|
||||
// error from writei
|
||||
break;
|
||||
}
|
||||
i += r;
|
||||
}
|
||||
ret = (i == n ? n : -1);
|
||||
} else {
|
||||
panic("filewrite");
|
||||
}
|
||||
if (r != n1) {
|
||||
// error from writei
|
||||
break;
|
||||
}
|
||||
i += r;
|
||||
}
|
||||
ret = (i == n ? n : -1);
|
||||
} else {
|
||||
panic("filewrite");
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
791
kernel/fs.c
791
kernel/fs.c
|
|
@ -24,84 +24,75 @@
|
|||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
// there should be one superblock per disk device, but we run with
|
||||
// only one device
|
||||
struct superblock sb;
|
||||
struct superblock sb;
|
||||
|
||||
// Read the super block.
|
||||
static void
|
||||
readsb(int dev, struct superblock *sb)
|
||||
{
|
||||
struct buf *bp;
|
||||
static void readsb(int dev, struct superblock *sb) {
|
||||
struct buf *bp;
|
||||
|
||||
bp = bread(dev, 1);
|
||||
memmove(sb, bp->data, sizeof(*sb));
|
||||
brelse(bp);
|
||||
bp = bread(dev, 1);
|
||||
memmove(sb, bp->data, sizeof(*sb));
|
||||
brelse(bp);
|
||||
}
|
||||
|
||||
// Init fs
|
||||
void
|
||||
fsinit(int dev) {
|
||||
readsb(dev, &sb);
|
||||
if(sb.magic != FSMAGIC)
|
||||
panic("invalid file system");
|
||||
initlog(dev, &sb);
|
||||
void fsinit(int dev) {
|
||||
readsb(dev, &sb);
|
||||
if (sb.magic != FSMAGIC)
|
||||
panic("invalid file system");
|
||||
initlog(dev, &sb);
|
||||
}
|
||||
|
||||
// Zero a block.
|
||||
static void
|
||||
bzero(int dev, int bno)
|
||||
{
|
||||
struct buf *bp;
|
||||
static void bzero(int dev, int bno) {
|
||||
struct buf *bp;
|
||||
|
||||
bp = bread(dev, bno);
|
||||
memset(bp->data, 0, BSIZE);
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
bp = bread(dev, bno);
|
||||
memset(bp->data, 0, BSIZE);
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
}
|
||||
|
||||
// Blocks.
|
||||
|
||||
// Allocate a zeroed disk block.
|
||||
// returns 0 if out of disk space.
|
||||
static uint
|
||||
balloc(uint dev)
|
||||
{
|
||||
int b, bi, m;
|
||||
struct buf *bp;
|
||||
static uint balloc(uint dev) {
|
||||
int b, bi, m;
|
||||
struct buf *bp;
|
||||
|
||||
bp = 0;
|
||||
for(b = 0; b < sb.size; b += BPB){
|
||||
bp = bread(dev, BBLOCK(b, sb));
|
||||
for(bi = 0; bi < BPB && b + bi < sb.size; bi++){
|
||||
m = 1 << (bi % 8);
|
||||
if((bp->data[bi/8] & m) == 0){ // Is block free?
|
||||
bp->data[bi/8] |= m; // Mark block in use.
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
bzero(dev, b + bi);
|
||||
return b + bi;
|
||||
}
|
||||
}
|
||||
brelse(bp);
|
||||
}
|
||||
printf("balloc: out of blocks\n");
|
||||
return 0;
|
||||
bp = 0;
|
||||
for (b = 0; b < sb.size; b += BPB) {
|
||||
bp = bread(dev, BBLOCK(b, sb));
|
||||
for (bi = 0; bi < BPB && b + bi < sb.size; bi++) {
|
||||
m = 1 << (bi % 8);
|
||||
if ((bp->data[bi / 8] & m) == 0) { // Is block free?
|
||||
bp->data[bi / 8] |= m; // Mark block in use.
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
bzero(dev, b + bi);
|
||||
return b + bi;
|
||||
}
|
||||
}
|
||||
brelse(bp);
|
||||
}
|
||||
printf("balloc: out of blocks\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Free a disk block.
|
||||
static void
|
||||
bfree(int dev, uint b)
|
||||
{
|
||||
struct buf *bp;
|
||||
int bi, m;
|
||||
static void bfree(int dev, uint b) {
|
||||
struct buf *bp;
|
||||
int bi, m;
|
||||
|
||||
bp = bread(dev, BBLOCK(b, sb));
|
||||
bi = b % BPB;
|
||||
m = 1 << (bi % 8);
|
||||
if((bp->data[bi/8] & m) == 0)
|
||||
panic("freeing free block");
|
||||
bp->data[bi/8] &= ~m;
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
bp = bread(dev, BBLOCK(b, sb));
|
||||
bi = b % BPB;
|
||||
m = 1 << (bi % 8);
|
||||
if ((bp->data[bi / 8] & m) == 0)
|
||||
panic("freeing free block");
|
||||
bp->data[bi / 8] &= ~m;
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
}
|
||||
|
||||
// Inodes.
|
||||
|
|
@ -174,156 +165,142 @@ bfree(int dev, uint b)
|
|||
// read or write that inode's ip->valid, ip->size, ip->type, &c.
|
||||
|
||||
struct {
|
||||
struct spinlock lock;
|
||||
struct inode inode[NINODE];
|
||||
struct spinlock lock;
|
||||
struct inode inode[NINODE];
|
||||
} itable;
|
||||
|
||||
void
|
||||
iinit()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
initlock(&itable.lock, "itable");
|
||||
for(i = 0; i < NINODE; i++) {
|
||||
initsleeplock(&itable.inode[i].lock, "inode");
|
||||
}
|
||||
void iinit() {
|
||||
int i = 0;
|
||||
|
||||
initlock(&itable.lock, "itable");
|
||||
for (i = 0; i < NINODE; i++) {
|
||||
initsleeplock(&itable.inode[i].lock, "inode");
|
||||
}
|
||||
}
|
||||
|
||||
static struct inode* iget(uint dev, uint inum);
|
||||
static struct inode *iget(uint dev, uint inum);
|
||||
|
||||
// Allocate an inode on device dev.
|
||||
// Mark it as allocated by giving it type type.
|
||||
// Returns an unlocked but allocated and referenced inode,
|
||||
// or NULL if there is no free inode..
|
||||
struct inode*
|
||||
ialloc(uint dev, short type)
|
||||
{
|
||||
int inum;
|
||||
struct buf *bp;
|
||||
struct dinode *dip;
|
||||
// or NULL if there is no free inode.
|
||||
struct inode *ialloc(uint dev, short type) {
|
||||
int inum;
|
||||
struct buf *bp;
|
||||
struct dinode *dip;
|
||||
|
||||
for(inum = 1; inum < sb.ninodes; inum++){
|
||||
bp = bread(dev, IBLOCK(inum, sb));
|
||||
dip = (struct dinode*)bp->data + inum%IPB;
|
||||
if(dip->type == 0){ // a free inode
|
||||
memset(dip, 0, sizeof(*dip));
|
||||
dip->type = type;
|
||||
log_write(bp); // mark it allocated on the disk
|
||||
brelse(bp);
|
||||
return iget(dev, inum);
|
||||
}
|
||||
brelse(bp);
|
||||
}
|
||||
printf("ialloc: no inodes\n");
|
||||
return 0;
|
||||
for (inum = 1; inum < sb.ninodes; inum++) {
|
||||
bp = bread(dev, IBLOCK(inum, sb));
|
||||
dip = (struct dinode *)bp->data + inum % IPB;
|
||||
if (dip->type == 0) { // a free inode
|
||||
memset(dip, 0, sizeof(*dip));
|
||||
dip->type = type;
|
||||
log_write(bp); // mark it allocated on the disk
|
||||
brelse(bp);
|
||||
return iget(dev, inum);
|
||||
}
|
||||
brelse(bp);
|
||||
}
|
||||
printf("ialloc: no inodes\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy a modified in-memory inode to disk.
|
||||
// Must be called after every change to an ip->xxx field
|
||||
// that lives on disk.
|
||||
// Caller must hold ip->lock.
|
||||
void
|
||||
iupdate(struct inode *ip)
|
||||
{
|
||||
struct buf *bp;
|
||||
struct dinode *dip;
|
||||
void iupdate(struct inode *ip) {
|
||||
struct buf *bp;
|
||||
struct dinode *dip;
|
||||
|
||||
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
||||
dip = (struct dinode*)bp->data + ip->inum%IPB;
|
||||
dip->type = ip->type;
|
||||
dip->major = ip->major;
|
||||
dip->minor = ip->minor;
|
||||
dip->nlink = ip->nlink;
|
||||
dip->size = ip->size;
|
||||
memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
||||
dip = (struct dinode *)bp->data + ip->inum % IPB;
|
||||
dip->type = ip->type;
|
||||
dip->major = ip->major;
|
||||
dip->minor = ip->minor;
|
||||
dip->nlink = ip->nlink;
|
||||
dip->size = ip->size;
|
||||
memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
}
|
||||
|
||||
// Find the inode with number inum on device dev
|
||||
// and return the in-memory copy. Does not lock
|
||||
// the inode and does not read it from disk.
|
||||
static struct inode*
|
||||
iget(uint dev, uint inum)
|
||||
{
|
||||
struct inode *ip, *empty;
|
||||
static struct inode *iget(uint dev, uint inum) {
|
||||
struct inode *ip, *empty;
|
||||
|
||||
acquire(&itable.lock);
|
||||
acquire(&itable.lock);
|
||||
|
||||
// Is the inode already in the table?
|
||||
empty = 0;
|
||||
for(ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++){
|
||||
if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
|
||||
ip->ref++;
|
||||
release(&itable.lock);
|
||||
return ip;
|
||||
}
|
||||
if(empty == 0 && ip->ref == 0) // Remember empty slot.
|
||||
empty = ip;
|
||||
}
|
||||
// Is the inode already in the table?
|
||||
empty = 0;
|
||||
for (ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++) {
|
||||
if (ip->ref > 0 && ip->dev == dev && ip->inum == inum) {
|
||||
ip->ref++;
|
||||
release(&itable.lock);
|
||||
return ip;
|
||||
}
|
||||
if (empty == 0 && ip->ref == 0) // Remember empty slot.
|
||||
empty = ip;
|
||||
}
|
||||
|
||||
// Recycle an inode entry.
|
||||
if(empty == 0)
|
||||
panic("iget: no inodes");
|
||||
// Recycle an inode entry.
|
||||
if (empty == 0)
|
||||
panic("iget: no inodes");
|
||||
|
||||
ip = empty;
|
||||
ip->dev = dev;
|
||||
ip->inum = inum;
|
||||
ip->ref = 1;
|
||||
ip->valid = 0;
|
||||
release(&itable.lock);
|
||||
ip = empty;
|
||||
ip->dev = dev;
|
||||
ip->inum = inum;
|
||||
ip->ref = 1;
|
||||
ip->valid = 0;
|
||||
release(&itable.lock);
|
||||
|
||||
return ip;
|
||||
return ip;
|
||||
}
|
||||
|
||||
// Increment reference count for ip.
|
||||
// Returns ip to enable ip = idup(ip1) idiom.
|
||||
struct inode*
|
||||
idup(struct inode *ip)
|
||||
{
|
||||
acquire(&itable.lock);
|
||||
ip->ref++;
|
||||
release(&itable.lock);
|
||||
return ip;
|
||||
struct inode *idup(struct inode *ip) {
|
||||
acquire(&itable.lock);
|
||||
ip->ref++;
|
||||
release(&itable.lock);
|
||||
return ip;
|
||||
}
|
||||
|
||||
// Lock the given inode.
|
||||
// Reads the inode from disk if necessary.
|
||||
void
|
||||
ilock(struct inode *ip)
|
||||
{
|
||||
struct buf *bp;
|
||||
struct dinode *dip;
|
||||
void ilock(struct inode *ip) {
|
||||
struct buf *bp;
|
||||
struct dinode *dip;
|
||||
|
||||
if(ip == 0 || ip->ref < 1)
|
||||
panic("ilock");
|
||||
if (ip == 0 || ip->ref < 1)
|
||||
panic("ilock");
|
||||
|
||||
acquiresleep(&ip->lock);
|
||||
acquiresleep(&ip->lock);
|
||||
|
||||
if(ip->valid == 0){
|
||||
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
||||
dip = (struct dinode*)bp->data + ip->inum%IPB;
|
||||
ip->type = dip->type;
|
||||
ip->major = dip->major;
|
||||
ip->minor = dip->minor;
|
||||
ip->nlink = dip->nlink;
|
||||
ip->size = dip->size;
|
||||
memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
|
||||
brelse(bp);
|
||||
ip->valid = 1;
|
||||
if(ip->type == 0)
|
||||
panic("ilock: no type");
|
||||
}
|
||||
if (ip->valid == 0) {
|
||||
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
||||
dip = (struct dinode *)bp->data + ip->inum % IPB;
|
||||
ip->type = dip->type;
|
||||
ip->major = dip->major;
|
||||
ip->minor = dip->minor;
|
||||
ip->nlink = dip->nlink;
|
||||
ip->size = dip->size;
|
||||
memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
|
||||
brelse(bp);
|
||||
ip->valid = 1;
|
||||
if (ip->type == 0)
|
||||
panic("ilock: no type");
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock the given inode.
|
||||
void
|
||||
iunlock(struct inode *ip)
|
||||
{
|
||||
if(ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
|
||||
panic("iunlock");
|
||||
void iunlock(struct inode *ip) {
|
||||
if (ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
|
||||
panic("iunlock");
|
||||
|
||||
releasesleep(&ip->lock);
|
||||
releasesleep(&ip->lock);
|
||||
}
|
||||
|
||||
// Drop a reference to an in-memory inode.
|
||||
|
|
@ -333,40 +310,36 @@ iunlock(struct inode *ip)
|
|||
// to it, free the inode (and its content) on disk.
|
||||
// All calls to iput() must be inside a transaction in
|
||||
// case it has to free the inode.
|
||||
void
|
||||
iput(struct inode *ip)
|
||||
{
|
||||
acquire(&itable.lock);
|
||||
void iput(struct inode *ip) {
|
||||
acquire(&itable.lock);
|
||||
|
||||
if(ip->ref == 1 && ip->valid && ip->nlink == 0){
|
||||
// inode has no links and no other references: truncate and free.
|
||||
if (ip->ref == 1 && ip->valid && ip->nlink == 0) {
|
||||
// inode has no links and no other references: truncate and free.
|
||||
|
||||
// ip->ref == 1 means no other process can have ip locked,
|
||||
// so this acquiresleep() won't block (or deadlock).
|
||||
acquiresleep(&ip->lock);
|
||||
// ip->ref == 1 means no other process can have ip locked,
|
||||
// so this acquiresleep() won't block (or deadlock).
|
||||
acquiresleep(&ip->lock);
|
||||
|
||||
release(&itable.lock);
|
||||
release(&itable.lock);
|
||||
|
||||
itrunc(ip);
|
||||
ip->type = 0;
|
||||
iupdate(ip);
|
||||
ip->valid = 0;
|
||||
itrunc(ip);
|
||||
ip->type = 0;
|
||||
iupdate(ip);
|
||||
ip->valid = 0;
|
||||
|
||||
releasesleep(&ip->lock);
|
||||
releasesleep(&ip->lock);
|
||||
|
||||
acquire(&itable.lock);
|
||||
}
|
||||
acquire(&itable.lock);
|
||||
}
|
||||
|
||||
ip->ref--;
|
||||
release(&itable.lock);
|
||||
ip->ref--;
|
||||
release(&itable.lock);
|
||||
}
|
||||
|
||||
// Common idiom: unlock, then put.
|
||||
void
|
||||
iunlockput(struct inode *ip)
|
||||
{
|
||||
iunlock(ip);
|
||||
iput(ip);
|
||||
void iunlockput(struct inode *ip) {
|
||||
iunlock(ip);
|
||||
iput(ip);
|
||||
}
|
||||
|
||||
// Inode content
|
||||
|
|
@ -379,120 +352,112 @@ iunlockput(struct inode *ip)
|
|||
// Return the disk block address of the nth block in inode ip.
|
||||
// If there is no such block, bmap allocates one.
|
||||
// returns 0 if out of disk space.
|
||||
static uint
|
||||
bmap(struct inode *ip, uint bn)
|
||||
{
|
||||
uint addr, *a;
|
||||
struct buf *bp;
|
||||
static uint bmap(struct inode *ip, uint bn) {
|
||||
uint addr, *a;
|
||||
struct buf *bp;
|
||||
|
||||
if(bn < NDIRECT){
|
||||
if((addr = ip->addrs[bn]) == 0){
|
||||
addr = balloc(ip->dev);
|
||||
if(addr == 0)
|
||||
return 0;
|
||||
ip->addrs[bn] = addr;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
bn -= NDIRECT;
|
||||
if (bn < NDIRECT) {
|
||||
if ((addr = ip->addrs[bn]) == 0) {
|
||||
addr = balloc(ip->dev);
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
ip->addrs[bn] = addr;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
bn -= NDIRECT;
|
||||
|
||||
if(bn < NINDIRECT){
|
||||
// Load indirect block, allocating if necessary.
|
||||
if((addr = ip->addrs[NDIRECT]) == 0){
|
||||
addr = balloc(ip->dev);
|
||||
if(addr == 0)
|
||||
return 0;
|
||||
ip->addrs[NDIRECT] = addr;
|
||||
}
|
||||
bp = bread(ip->dev, addr);
|
||||
a = (uint*)bp->data;
|
||||
if((addr = a[bn]) == 0){
|
||||
addr = balloc(ip->dev);
|
||||
if(addr){
|
||||
a[bn] = addr;
|
||||
log_write(bp);
|
||||
}
|
||||
}
|
||||
brelse(bp);
|
||||
return addr;
|
||||
}
|
||||
if (bn < NINDIRECT) {
|
||||
// Load indirect block, allocating if necessary.
|
||||
if ((addr = ip->addrs[NDIRECT]) == 0) {
|
||||
addr = balloc(ip->dev);
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
ip->addrs[NDIRECT] = addr;
|
||||
}
|
||||
bp = bread(ip->dev, addr);
|
||||
a = (uint *)bp->data;
|
||||
if ((addr = a[bn]) == 0) {
|
||||
addr = balloc(ip->dev);
|
||||
if (addr) {
|
||||
a[bn] = addr;
|
||||
log_write(bp);
|
||||
}
|
||||
}
|
||||
brelse(bp);
|
||||
return addr;
|
||||
}
|
||||
|
||||
panic("bmap: out of range");
|
||||
panic("bmap: out of range");
|
||||
}
|
||||
|
||||
// Truncate inode (discard contents).
|
||||
// Caller must hold ip->lock.
|
||||
void
|
||||
itrunc(struct inode *ip)
|
||||
{
|
||||
int i, j;
|
||||
struct buf *bp;
|
||||
uint *a;
|
||||
void itrunc(struct inode *ip) {
|
||||
int i, j;
|
||||
struct buf *bp;
|
||||
uint *a;
|
||||
|
||||
for(i = 0; i < NDIRECT; i++){
|
||||
if(ip->addrs[i]){
|
||||
bfree(ip->dev, ip->addrs[i]);
|
||||
ip->addrs[i] = 0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < NDIRECT; i++) {
|
||||
if (ip->addrs[i]) {
|
||||
bfree(ip->dev, ip->addrs[i]);
|
||||
ip->addrs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(ip->addrs[NDIRECT]){
|
||||
bp = bread(ip->dev, ip->addrs[NDIRECT]);
|
||||
a = (uint*)bp->data;
|
||||
for(j = 0; j < NINDIRECT; j++){
|
||||
if(a[j])
|
||||
bfree(ip->dev, a[j]);
|
||||
}
|
||||
brelse(bp);
|
||||
bfree(ip->dev, ip->addrs[NDIRECT]);
|
||||
ip->addrs[NDIRECT] = 0;
|
||||
}
|
||||
if (ip->addrs[NDIRECT]) {
|
||||
bp = bread(ip->dev, ip->addrs[NDIRECT]);
|
||||
a = (uint *)bp->data;
|
||||
for (j = 0; j < NINDIRECT; j++) {
|
||||
if (a[j])
|
||||
bfree(ip->dev, a[j]);
|
||||
}
|
||||
brelse(bp);
|
||||
bfree(ip->dev, ip->addrs[NDIRECT]);
|
||||
ip->addrs[NDIRECT] = 0;
|
||||
}
|
||||
|
||||
ip->size = 0;
|
||||
iupdate(ip);
|
||||
ip->size = 0;
|
||||
iupdate(ip);
|
||||
}
|
||||
|
||||
// Copy stat information from inode.
|
||||
// Caller must hold ip->lock.
|
||||
void
|
||||
stati(struct inode *ip, struct stat *st)
|
||||
{
|
||||
st->dev = ip->dev;
|
||||
st->ino = ip->inum;
|
||||
st->type = ip->type;
|
||||
st->nlink = ip->nlink;
|
||||
st->size = ip->size;
|
||||
void stati(struct inode *ip, struct stat *st) {
|
||||
st->dev = ip->dev;
|
||||
st->ino = ip->inum;
|
||||
st->type = ip->type;
|
||||
st->nlink = ip->nlink;
|
||||
st->size = ip->size;
|
||||
}
|
||||
|
||||
// Read data from inode.
|
||||
// Caller must hold ip->lock.
|
||||
// If user_dst==1, then dst is a user virtual address;
|
||||
// otherwise, dst is a kernel address.
|
||||
int
|
||||
readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)
|
||||
{
|
||||
uint tot, m;
|
||||
struct buf *bp;
|
||||
int readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n) {
|
||||
uint tot, m;
|
||||
struct buf *bp;
|
||||
|
||||
if(off > ip->size || off + n < off)
|
||||
return 0;
|
||||
if(off + n > ip->size)
|
||||
n = ip->size - off;
|
||||
if (off > ip->size || off + n < off)
|
||||
return 0;
|
||||
if (off + n > ip->size)
|
||||
n = ip->size - off;
|
||||
|
||||
for(tot=0; tot<n; tot+=m, off+=m, dst+=m){
|
||||
uint addr = bmap(ip, off/BSIZE);
|
||||
if(addr == 0)
|
||||
break;
|
||||
bp = bread(ip->dev, addr);
|
||||
m = min(n - tot, BSIZE - off%BSIZE);
|
||||
if(either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) {
|
||||
brelse(bp);
|
||||
tot = -1;
|
||||
break;
|
||||
}
|
||||
brelse(bp);
|
||||
}
|
||||
return tot;
|
||||
for (tot = 0; tot < n; tot += m, off += m, dst += m) {
|
||||
uint addr = bmap(ip, off / BSIZE);
|
||||
if (addr == 0)
|
||||
break;
|
||||
bp = bread(ip->dev, addr);
|
||||
m = min(n - tot, BSIZE - off % BSIZE);
|
||||
if (either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) {
|
||||
brelse(bp);
|
||||
tot = -1;
|
||||
break;
|
||||
}
|
||||
brelse(bp);
|
||||
}
|
||||
return tot;
|
||||
}
|
||||
|
||||
// Write data to inode.
|
||||
|
|
@ -502,107 +467,97 @@ readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)
|
|||
// Returns the number of bytes successfully written.
|
||||
// If the return value is less than the requested n,
|
||||
// there was an error of some kind.
|
||||
int
|
||||
writei(struct inode *ip, int user_src, uint64 src, uint off, uint n)
|
||||
{
|
||||
uint tot, m;
|
||||
struct buf *bp;
|
||||
int writei(struct inode *ip, int user_src, uint64 src, uint off, uint n) {
|
||||
uint tot, m;
|
||||
struct buf *bp;
|
||||
|
||||
if(off > ip->size || off + n < off)
|
||||
return -1;
|
||||
if(off + n > MAXFILE*BSIZE)
|
||||
return -1;
|
||||
if (off > ip->size || off + n < off)
|
||||
return -1;
|
||||
if (off + n > MAXFILE * BSIZE)
|
||||
return -1;
|
||||
|
||||
for(tot=0; tot<n; tot+=m, off+=m, src+=m){
|
||||
uint addr = bmap(ip, off/BSIZE);
|
||||
if(addr == 0)
|
||||
break;
|
||||
bp = bread(ip->dev, addr);
|
||||
m = min(n - tot, BSIZE - off%BSIZE);
|
||||
if(either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) {
|
||||
brelse(bp);
|
||||
break;
|
||||
}
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
}
|
||||
for (tot = 0; tot < n; tot += m, off += m, src += m) {
|
||||
uint addr = bmap(ip, off / BSIZE);
|
||||
if (addr == 0)
|
||||
break;
|
||||
bp = bread(ip->dev, addr);
|
||||
m = min(n - tot, BSIZE - off % BSIZE);
|
||||
if (either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) {
|
||||
brelse(bp);
|
||||
break;
|
||||
}
|
||||
log_write(bp);
|
||||
brelse(bp);
|
||||
}
|
||||
|
||||
if(off > ip->size)
|
||||
ip->size = off;
|
||||
if (off > ip->size)
|
||||
ip->size = off;
|
||||
|
||||
// write the i-node back to disk even if the size didn't change
|
||||
// because the loop above might have called bmap() and added a new
|
||||
// block to ip->addrs[].
|
||||
iupdate(ip);
|
||||
// write the i-node back to disk even if the size didn't change
|
||||
// because the loop above might have called bmap() and added a new
|
||||
// block to ip->addrs[].
|
||||
iupdate(ip);
|
||||
|
||||
return tot;
|
||||
return tot;
|
||||
}
|
||||
|
||||
// Directories
|
||||
|
||||
int
|
||||
namecmp(const char *s, const char *t)
|
||||
{
|
||||
return strncmp(s, t, DIRSIZ);
|
||||
}
|
||||
int namecmp(const char *s, const char *t) { return strncmp(s, t, DIRSIZ); }
|
||||
|
||||
// Look for a directory entry in a directory.
|
||||
// If found, set *poff to byte offset of entry.
|
||||
struct inode*
|
||||
dirlookup(struct inode *dp, char *name, uint *poff)
|
||||
{
|
||||
uint off, inum;
|
||||
struct dirent de;
|
||||
struct inode *dirlookup(struct inode *dp, char *name, uint *poff) {
|
||||
uint off, inum;
|
||||
struct dirent de;
|
||||
|
||||
if(dp->type != T_DIR)
|
||||
panic("dirlookup not DIR");
|
||||
if (dp->type != T_DIR)
|
||||
panic("dirlookup not DIR");
|
||||
|
||||
for(off = 0; off < dp->size; off += sizeof(de)){
|
||||
if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
panic("dirlookup read");
|
||||
if(de.inum == 0)
|
||||
continue;
|
||||
if(namecmp(name, de.name) == 0){
|
||||
// entry matches path element
|
||||
if(poff)
|
||||
*poff = off;
|
||||
inum = de.inum;
|
||||
return iget(dp->dev, inum);
|
||||
}
|
||||
}
|
||||
for (off = 0; off < dp->size; off += sizeof(de)) {
|
||||
if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
panic("dirlookup read");
|
||||
if (de.inum == 0)
|
||||
continue;
|
||||
if (namecmp(name, de.name) == 0) {
|
||||
// entry matches path element
|
||||
if (poff)
|
||||
*poff = off;
|
||||
inum = de.inum;
|
||||
return iget(dp->dev, inum);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write a new directory entry (name, inum) into the directory dp.
|
||||
// Returns 0 on success, -1 on failure (e.g. out of disk blocks).
|
||||
int
|
||||
dirlink(struct inode *dp, char *name, uint inum)
|
||||
{
|
||||
int off;
|
||||
struct dirent de;
|
||||
struct inode *ip;
|
||||
int dirlink(struct inode *dp, char *name, uint inum) {
|
||||
int off;
|
||||
struct dirent de;
|
||||
struct inode *ip;
|
||||
|
||||
// Check that name is not present.
|
||||
if((ip = dirlookup(dp, name, 0)) != 0){
|
||||
iput(ip);
|
||||
return -1;
|
||||
}
|
||||
// Check that name is not present.
|
||||
if ((ip = dirlookup(dp, name, 0)) != 0) {
|
||||
iput(ip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Look for an empty dirent.
|
||||
for(off = 0; off < dp->size; off += sizeof(de)){
|
||||
if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
panic("dirlink read");
|
||||
if(de.inum == 0)
|
||||
break;
|
||||
}
|
||||
// Look for an empty dirent.
|
||||
for (off = 0; off < dp->size; off += sizeof(de)) {
|
||||
if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
panic("dirlink read");
|
||||
if (de.inum == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(de.name, name, DIRSIZ);
|
||||
de.inum = inum;
|
||||
if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
return -1;
|
||||
strncpy(de.name, name, DIRSIZ);
|
||||
de.inum = inum;
|
||||
if (writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Paths
|
||||
|
|
@ -619,79 +574,71 @@ dirlink(struct inode *dp, char *name, uint inum)
|
|||
// skipelem("a", name) = "", setting name = "a"
|
||||
// skipelem("", name) = skipelem("////", name) = 0
|
||||
//
|
||||
static char*
|
||||
skipelem(char *path, char *name)
|
||||
{
|
||||
char *s;
|
||||
int len;
|
||||
static char *skipelem(char *path, char *name) {
|
||||
char *s;
|
||||
int len;
|
||||
|
||||
while(*path == '/')
|
||||
path++;
|
||||
if(*path == 0)
|
||||
return 0;
|
||||
s = path;
|
||||
while(*path != '/' && *path != 0)
|
||||
path++;
|
||||
len = path - s;
|
||||
if(len >= DIRSIZ)
|
||||
memmove(name, s, DIRSIZ);
|
||||
else {
|
||||
memmove(name, s, len);
|
||||
name[len] = 0;
|
||||
}
|
||||
while(*path == '/')
|
||||
path++;
|
||||
return path;
|
||||
while (*path == '/')
|
||||
path++;
|
||||
if (*path == 0)
|
||||
return 0;
|
||||
s = path;
|
||||
while (*path != '/' && *path != 0)
|
||||
path++;
|
||||
len = path - s;
|
||||
if (len >= DIRSIZ)
|
||||
memmove(name, s, DIRSIZ);
|
||||
else {
|
||||
memmove(name, s, len);
|
||||
name[len] = 0;
|
||||
}
|
||||
while (*path == '/')
|
||||
path++;
|
||||
return path;
|
||||
}
|
||||
|
||||
// Look up and return the inode for a path name.
|
||||
// If parent != 0, return the inode for the parent and copy the final
|
||||
// path element into name, which must have room for DIRSIZ bytes.
|
||||
// Must be called inside a transaction since it calls iput().
|
||||
static struct inode*
|
||||
namex(char *path, int nameiparent, char *name)
|
||||
{
|
||||
struct inode *ip, *next;
|
||||
static struct inode *namex(char *path, int nameiparent, char *name) {
|
||||
struct inode *ip, *next;
|
||||
|
||||
if(*path == '/')
|
||||
ip = iget(ROOTDEV, ROOTINO);
|
||||
else
|
||||
ip = idup(myproc()->cwd);
|
||||
if (*path == '/')
|
||||
ip = iget(ROOTDEV, ROOTINO);
|
||||
else
|
||||
ip = idup(myproc()->cwd);
|
||||
|
||||
while((path = skipelem(path, name)) != 0){
|
||||
ilock(ip);
|
||||
if(ip->type != T_DIR){
|
||||
iunlockput(ip);
|
||||
return 0;
|
||||
}
|
||||
if(nameiparent && *path == '\0'){
|
||||
// Stop one level early.
|
||||
iunlock(ip);
|
||||
return ip;
|
||||
}
|
||||
if((next = dirlookup(ip, name, 0)) == 0){
|
||||
iunlockput(ip);
|
||||
return 0;
|
||||
}
|
||||
iunlockput(ip);
|
||||
ip = next;
|
||||
}
|
||||
if(nameiparent){
|
||||
iput(ip);
|
||||
return 0;
|
||||
}
|
||||
return ip;
|
||||
while ((path = skipelem(path, name)) != 0) {
|
||||
ilock(ip);
|
||||
if (ip->type != T_DIR) {
|
||||
iunlockput(ip);
|
||||
return 0;
|
||||
}
|
||||
if (nameiparent && *path == '\0') {
|
||||
// Stop one level early.
|
||||
iunlock(ip);
|
||||
return ip;
|
||||
}
|
||||
if ((next = dirlookup(ip, name, 0)) == 0) {
|
||||
iunlockput(ip);
|
||||
return 0;
|
||||
}
|
||||
iunlockput(ip);
|
||||
ip = next;
|
||||
}
|
||||
if (nameiparent) {
|
||||
iput(ip);
|
||||
return 0;
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
struct inode*
|
||||
namei(char *path)
|
||||
{
|
||||
char name[DIRSIZ];
|
||||
return namex(path, 0, name);
|
||||
struct inode *namei(char *path) {
|
||||
char name[DIRSIZ];
|
||||
return namex(path, 0, name);
|
||||
}
|
||||
|
||||
struct inode*
|
||||
nameiparent(char *path, char *name)
|
||||
{
|
||||
return namex(path, 1, name);
|
||||
struct inode *nameiparent(char *path, char *name) {
|
||||
return namex(path, 1, name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,71 +12,63 @@
|
|||
void freerange(void *pa_start, void *pa_end);
|
||||
|
||||
extern char end[]; // first address after kernel.
|
||||
// defined by kernel.ld.
|
||||
// defined by kernel.ld.
|
||||
|
||||
struct run {
|
||||
struct run *next;
|
||||
struct run *next;
|
||||
};
|
||||
|
||||
struct {
|
||||
struct spinlock lock;
|
||||
struct run *freelist;
|
||||
struct spinlock lock;
|
||||
struct run *freelist;
|
||||
} kmem;
|
||||
|
||||
void
|
||||
kinit()
|
||||
{
|
||||
initlock(&kmem.lock, "kmem");
|
||||
freerange(end, (void*)PHYSTOP);
|
||||
void kinit() {
|
||||
initlock(&kmem.lock, "kmem");
|
||||
freerange(end, (void *)PHYSTOP);
|
||||
}
|
||||
|
||||
void
|
||||
freerange(void *pa_start, void *pa_end)
|
||||
{
|
||||
char *p;
|
||||
p = (char*)PGROUNDUP((uint64)pa_start);
|
||||
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
|
||||
kfree(p);
|
||||
void freerange(void *pa_start, void *pa_end) {
|
||||
char *p;
|
||||
p = (char *)PGROUNDUP((uint64)pa_start);
|
||||
for (; p + PGSIZE <= (char *)pa_end; p += PGSIZE)
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
// Free the page of physical memory pointed at by pa,
|
||||
// which normally should have been returned by a
|
||||
// call to kalloc(). (The exception is when
|
||||
// initializing the allocator; see kinit above.)
|
||||
void
|
||||
kfree(void *pa)
|
||||
{
|
||||
struct run *r;
|
||||
void kfree(void *pa) {
|
||||
struct run *r;
|
||||
|
||||
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
|
||||
panic("kfree");
|
||||
if (((uint64)pa % PGSIZE) != 0 || (char *)pa < end || (uint64)pa >= PHYSTOP)
|
||||
panic("kfree");
|
||||
|
||||
// Fill with junk to catch dangling refs.
|
||||
memset(pa, 1, PGSIZE);
|
||||
// Fill with junk to catch dangling refs.
|
||||
memset(pa, 1, PGSIZE);
|
||||
|
||||
r = (struct run*)pa;
|
||||
r = (struct run *)pa;
|
||||
|
||||
acquire(&kmem.lock);
|
||||
r->next = kmem.freelist;
|
||||
kmem.freelist = r;
|
||||
release(&kmem.lock);
|
||||
acquire(&kmem.lock);
|
||||
r->next = kmem.freelist;
|
||||
kmem.freelist = r;
|
||||
release(&kmem.lock);
|
||||
}
|
||||
|
||||
// Allocate one 4096-byte page of physical memory.
|
||||
// Returns a pointer that the kernel can use.
|
||||
// Returns 0 if the memory cannot be allocated.
|
||||
void *
|
||||
kalloc(void)
|
||||
{
|
||||
struct run *r;
|
||||
void *kalloc(void) {
|
||||
struct run *r;
|
||||
|
||||
acquire(&kmem.lock);
|
||||
r = kmem.freelist;
|
||||
if(r)
|
||||
kmem.freelist = r->next;
|
||||
release(&kmem.lock);
|
||||
acquire(&kmem.lock);
|
||||
r = kmem.freelist;
|
||||
if (r)
|
||||
kmem.freelist = r->next;
|
||||
release(&kmem.lock);
|
||||
|
||||
if(r)
|
||||
memset((char*)r, 5, PGSIZE); // fill with junk
|
||||
return (void*)r;
|
||||
if (r)
|
||||
memset((char *)r, 5, PGSIZE); // fill with junk
|
||||
return (void *)r;
|
||||
}
|
||||
|
|
|
|||
276
kernel/log.c
276
kernel/log.c
|
|
@ -33,173 +33,156 @@
|
|||
// Contents of the header block, used for both the on-disk header block
|
||||
// and to keep track in memory of logged block# before commit.
|
||||
struct logheader {
|
||||
int n;
|
||||
int block[LOGSIZE];
|
||||
int n;
|
||||
int block[LOGSIZE];
|
||||
};
|
||||
|
||||
struct log {
|
||||
struct spinlock lock;
|
||||
int start;
|
||||
int size;
|
||||
int outstanding; // how many FS sys calls are executing.
|
||||
int committing; // in commit(), please wait.
|
||||
int dev;
|
||||
struct logheader lh;
|
||||
struct spinlock lock;
|
||||
int start;
|
||||
int size;
|
||||
int outstanding; // how many FS sys calls are executing.
|
||||
int committing; // in commit(), please wait.
|
||||
int dev;
|
||||
struct logheader lh;
|
||||
};
|
||||
struct log log;
|
||||
|
||||
static void recover_from_log(void);
|
||||
static void commit();
|
||||
|
||||
void
|
||||
initlog(int dev, struct superblock *sb)
|
||||
{
|
||||
if (sizeof(struct logheader) >= BSIZE)
|
||||
panic("initlog: too big logheader");
|
||||
void initlog(int dev, struct superblock *sb) {
|
||||
if (sizeof(struct logheader) >= BSIZE)
|
||||
panic("initlog: too big logheader");
|
||||
|
||||
initlock(&log.lock, "log");
|
||||
log.start = sb->logstart;
|
||||
log.size = sb->nlog;
|
||||
log.dev = dev;
|
||||
recover_from_log();
|
||||
initlock(&log.lock, "log");
|
||||
log.start = sb->logstart;
|
||||
log.size = sb->nlog;
|
||||
log.dev = dev;
|
||||
recover_from_log();
|
||||
}
|
||||
|
||||
// Copy committed blocks from log to their home location
|
||||
static void
|
||||
install_trans(int recovering)
|
||||
{
|
||||
int tail;
|
||||
static void install_trans(int recovering) {
|
||||
int tail;
|
||||
|
||||
for (tail = 0; tail < log.lh.n; tail++) {
|
||||
struct buf *lbuf = bread(log.dev, log.start+tail+1); // read log block
|
||||
struct buf *dbuf = bread(log.dev, log.lh.block[tail]); // read dst
|
||||
memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst
|
||||
bwrite(dbuf); // write dst to disk
|
||||
if(recovering == 0)
|
||||
bunpin(dbuf);
|
||||
brelse(lbuf);
|
||||
brelse(dbuf);
|
||||
}
|
||||
for (tail = 0; tail < log.lh.n; tail++) {
|
||||
struct buf *lbuf =
|
||||
bread(log.dev, log.start + tail + 1); // read log block
|
||||
struct buf *dbuf = bread(log.dev, log.lh.block[tail]); // read dst
|
||||
memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst
|
||||
bwrite(dbuf); // write dst to disk
|
||||
if (recovering == 0)
|
||||
bunpin(dbuf);
|
||||
brelse(lbuf);
|
||||
brelse(dbuf);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the log header from disk into the in-memory log header
|
||||
static void
|
||||
read_head(void)
|
||||
{
|
||||
struct buf *buf = bread(log.dev, log.start);
|
||||
struct logheader *lh = (struct logheader *) (buf->data);
|
||||
int i;
|
||||
log.lh.n = lh->n;
|
||||
for (i = 0; i < log.lh.n; i++) {
|
||||
log.lh.block[i] = lh->block[i];
|
||||
}
|
||||
brelse(buf);
|
||||
static void read_head(void) {
|
||||
struct buf *buf = bread(log.dev, log.start);
|
||||
struct logheader *lh = (struct logheader *)(buf->data);
|
||||
int i;
|
||||
log.lh.n = lh->n;
|
||||
for (i = 0; i < log.lh.n; i++) {
|
||||
log.lh.block[i] = lh->block[i];
|
||||
}
|
||||
brelse(buf);
|
||||
}
|
||||
|
||||
// Write in-memory log header to disk.
|
||||
// This is the true point at which the
|
||||
// current transaction commits.
|
||||
static void
|
||||
write_head(void)
|
||||
{
|
||||
struct buf *buf = bread(log.dev, log.start);
|
||||
struct logheader *hb = (struct logheader *) (buf->data);
|
||||
int i;
|
||||
hb->n = log.lh.n;
|
||||
for (i = 0; i < log.lh.n; i++) {
|
||||
hb->block[i] = log.lh.block[i];
|
||||
}
|
||||
bwrite(buf);
|
||||
brelse(buf);
|
||||
static void write_head(void) {
|
||||
struct buf *buf = bread(log.dev, log.start);
|
||||
struct logheader *hb = (struct logheader *)(buf->data);
|
||||
int i;
|
||||
hb->n = log.lh.n;
|
||||
for (i = 0; i < log.lh.n; i++) {
|
||||
hb->block[i] = log.lh.block[i];
|
||||
}
|
||||
bwrite(buf);
|
||||
brelse(buf);
|
||||
}
|
||||
|
||||
static void
|
||||
recover_from_log(void)
|
||||
{
|
||||
read_head();
|
||||
install_trans(1); // if committed, copy from log to disk
|
||||
log.lh.n = 0;
|
||||
write_head(); // clear the log
|
||||
static void recover_from_log(void) {
|
||||
read_head();
|
||||
install_trans(1); // if committed, copy from log to disk
|
||||
log.lh.n = 0;
|
||||
write_head(); // clear the log
|
||||
}
|
||||
|
||||
// called at the start of each FS system call.
|
||||
void
|
||||
begin_op(void)
|
||||
{
|
||||
acquire(&log.lock);
|
||||
while(1){
|
||||
if(log.committing){
|
||||
sleep(&log, &log.lock);
|
||||
} else if(log.lh.n + (log.outstanding+1)*MAXOPBLOCKS > LOGSIZE){
|
||||
// this op might exhaust log space; wait for commit.
|
||||
sleep(&log, &log.lock);
|
||||
} else {
|
||||
log.outstanding += 1;
|
||||
release(&log.lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void begin_op(void) {
|
||||
acquire(&log.lock);
|
||||
while (1) {
|
||||
if (log.committing) {
|
||||
sleep(&log, &log.lock);
|
||||
} else if (log.lh.n + (log.outstanding + 1) * MAXOPBLOCKS > LOGSIZE) {
|
||||
// this op might exhaust log space; wait for commit.
|
||||
sleep(&log, &log.lock);
|
||||
} else {
|
||||
log.outstanding += 1;
|
||||
release(&log.lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// called at the end of each FS system call.
|
||||
// commits if this was the last outstanding operation.
|
||||
void
|
||||
end_op(void)
|
||||
{
|
||||
int do_commit = 0;
|
||||
void end_op(void) {
|
||||
int do_commit = 0;
|
||||
|
||||
acquire(&log.lock);
|
||||
log.outstanding -= 1;
|
||||
if(log.committing)
|
||||
panic("log.committing");
|
||||
if(log.outstanding == 0){
|
||||
do_commit = 1;
|
||||
log.committing = 1;
|
||||
} else {
|
||||
// begin_op() may be waiting for log space,
|
||||
// and decrementing log.outstanding has decreased
|
||||
// the amount of reserved space.
|
||||
wakeup(&log);
|
||||
}
|
||||
release(&log.lock);
|
||||
acquire(&log.lock);
|
||||
log.outstanding -= 1;
|
||||
if (log.committing)
|
||||
panic("log.committing");
|
||||
if (log.outstanding == 0) {
|
||||
do_commit = 1;
|
||||
log.committing = 1;
|
||||
} else {
|
||||
// begin_op() may be waiting for log space,
|
||||
// and decrementing log.outstanding has decreased
|
||||
// the amount of reserved space.
|
||||
wakeup(&log);
|
||||
}
|
||||
release(&log.lock);
|
||||
|
||||
if(do_commit){
|
||||
// call commit w/o holding locks, since not allowed
|
||||
// to sleep with locks.
|
||||
commit();
|
||||
acquire(&log.lock);
|
||||
log.committing = 0;
|
||||
wakeup(&log);
|
||||
release(&log.lock);
|
||||
}
|
||||
if (do_commit) {
|
||||
// call commit w/o holding locks, since not allowed
|
||||
// to sleep with locks.
|
||||
commit();
|
||||
acquire(&log.lock);
|
||||
log.committing = 0;
|
||||
wakeup(&log);
|
||||
release(&log.lock);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy modified blocks from cache to log.
|
||||
static void
|
||||
write_log(void)
|
||||
{
|
||||
int tail;
|
||||
static void write_log(void) {
|
||||
int tail;
|
||||
|
||||
for (tail = 0; tail < log.lh.n; tail++) {
|
||||
struct buf *to = bread(log.dev, log.start+tail+1); // log block
|
||||
struct buf *from = bread(log.dev, log.lh.block[tail]); // cache block
|
||||
memmove(to->data, from->data, BSIZE);
|
||||
bwrite(to); // write the log
|
||||
brelse(from);
|
||||
brelse(to);
|
||||
}
|
||||
for (tail = 0; tail < log.lh.n; tail++) {
|
||||
struct buf *to = bread(log.dev, log.start + tail + 1); // log block
|
||||
struct buf *from = bread(log.dev, log.lh.block[tail]); // cache block
|
||||
memmove(to->data, from->data, BSIZE);
|
||||
bwrite(to); // write the log
|
||||
brelse(from);
|
||||
brelse(to);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
commit()
|
||||
{
|
||||
if (log.lh.n > 0) {
|
||||
write_log(); // Write modified blocks from cache to log
|
||||
write_head(); // Write header to disk -- the real commit
|
||||
install_trans(0); // Now install writes to home locations
|
||||
log.lh.n = 0;
|
||||
write_head(); // Erase the transaction from the log
|
||||
}
|
||||
static void commit() {
|
||||
if (log.lh.n > 0) {
|
||||
write_log(); // Write modified blocks from cache to log
|
||||
write_head(); // Write header to disk -- the real commit
|
||||
install_trans(0); // Now install writes to home locations
|
||||
log.lh.n = 0;
|
||||
write_head(); // Erase the transaction from the log
|
||||
}
|
||||
}
|
||||
|
||||
// Caller has modified b->data and is done with the buffer.
|
||||
|
|
@ -211,26 +194,23 @@ commit()
|
|||
// modify bp->data[]
|
||||
// log_write(bp)
|
||||
// brelse(bp)
|
||||
void
|
||||
log_write(struct buf *b)
|
||||
{
|
||||
int i;
|
||||
void log_write(struct buf *b) {
|
||||
int i;
|
||||
|
||||
acquire(&log.lock);
|
||||
if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1)
|
||||
panic("too big a transaction");
|
||||
if (log.outstanding < 1)
|
||||
panic("log_write outside of trans");
|
||||
acquire(&log.lock);
|
||||
if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1)
|
||||
panic("too big a transaction");
|
||||
if (log.outstanding < 1)
|
||||
panic("log_write outside of trans");
|
||||
|
||||
for (i = 0; i < log.lh.n; i++) {
|
||||
if (log.lh.block[i] == b->blockno) // log absorption
|
||||
break;
|
||||
}
|
||||
log.lh.block[i] = b->blockno;
|
||||
if (i == log.lh.n) { // Add new block to log?
|
||||
bpin(b);
|
||||
log.lh.n++;
|
||||
}
|
||||
release(&log.lock);
|
||||
for (i = 0; i < log.lh.n; i++) {
|
||||
if (log.lh.block[i] == b->blockno) // log absorption
|
||||
break;
|
||||
}
|
||||
log.lh.block[i] = b->blockno;
|
||||
if (i == log.lh.n) { // Add new block to log?
|
||||
bpin(b);
|
||||
log.lh.n++;
|
||||
}
|
||||
release(&log.lock);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,43 +3,46 @@
|
|||
#include "memlayout.h"
|
||||
#include "riscv.h"
|
||||
#include "defs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
extern int32_t add(int32_t right, int32_t left);
|
||||
|
||||
volatile static int started = 0;
|
||||
|
||||
// start() jumps here in supervisor mode on all CPUs.
|
||||
void
|
||||
main()
|
||||
{
|
||||
if(cpuid() == 0){
|
||||
consoleinit();
|
||||
printfinit();
|
||||
printf("\n");
|
||||
printf("xv6 kernel is booting\n");
|
||||
printf("\n");
|
||||
kinit(); // physical page allocator
|
||||
kvminit(); // create kernel page table
|
||||
kvminithart(); // turn on paging
|
||||
procinit(); // process table
|
||||
trapinit(); // trap vectors
|
||||
trapinithart(); // install kernel trap vector
|
||||
plicinit(); // set up interrupt controller
|
||||
plicinithart(); // ask PLIC for device interrupts
|
||||
binit(); // buffer cache
|
||||
iinit(); // inode table
|
||||
fileinit(); // file table
|
||||
virtio_disk_init(); // emulated hard disk
|
||||
userinit(); // first user process
|
||||
__sync_synchronize();
|
||||
started = 1;
|
||||
} else {
|
||||
while(started == 0)
|
||||
;
|
||||
__sync_synchronize();
|
||||
printf("hart %d starting\n", cpuid());
|
||||
kvminithart(); // turn on paging
|
||||
trapinithart(); // install kernel trap vector
|
||||
plicinithart(); // ask PLIC for device interrupts
|
||||
}
|
||||
void main() {
|
||||
if (cpuid() == 0) {
|
||||
consoleinit();
|
||||
printfinit();
|
||||
printf("\n");
|
||||
printf("xv6 kernel is booting\n");
|
||||
printf("\n");
|
||||
printf("rust library call: add(1, 2) = %d\n", add(1, 2));
|
||||
printf("\n");
|
||||
kinit(); // physical page allocator
|
||||
kvminit(); // create kernel page table
|
||||
kvminithart(); // turn on paging
|
||||
procinit(); // process table
|
||||
trapinit(); // trap vectors
|
||||
trapinithart(); // install kernel trap vector
|
||||
plicinit(); // set up interrupt controller
|
||||
plicinithart(); // ask PLIC for device interrupts
|
||||
binit(); // buffer cache
|
||||
iinit(); // inode table
|
||||
fileinit(); // file table
|
||||
virtio_disk_init(); // emulated hard disk
|
||||
userinit(); // first user process
|
||||
__sync_synchronize();
|
||||
started = 1;
|
||||
} else {
|
||||
while (started == 0)
|
||||
;
|
||||
__sync_synchronize();
|
||||
printf("hart %d starting\n", cpuid());
|
||||
kvminithart(); // turn on paging
|
||||
trapinithart(); // install kernel trap vector
|
||||
plicinithart(); // ask PLIC for device interrupts
|
||||
}
|
||||
|
||||
scheduler();
|
||||
scheduler();
|
||||
}
|
||||
|
|
|
|||
198
kernel/pipe.c
198
kernel/pipe.c
|
|
@ -11,120 +11,112 @@
|
|||
#define PIPESIZE 512
|
||||
|
||||
struct pipe {
|
||||
struct spinlock lock;
|
||||
char data[PIPESIZE];
|
||||
uint nread; // number of bytes read
|
||||
uint nwrite; // number of bytes written
|
||||
int readopen; // read fd is still open
|
||||
int writeopen; // write fd is still open
|
||||
struct spinlock lock;
|
||||
char data[PIPESIZE];
|
||||
uint nread; // number of bytes read
|
||||
uint nwrite; // number of bytes written
|
||||
int readopen; // read fd is still open
|
||||
int writeopen; // write fd is still open
|
||||
};
|
||||
|
||||
int
|
||||
pipealloc(struct file **f0, struct file **f1)
|
||||
{
|
||||
struct pipe *pi;
|
||||
int pipealloc(struct file **f0, struct file **f1) {
|
||||
struct pipe *pi;
|
||||
|
||||
pi = 0;
|
||||
*f0 = *f1 = 0;
|
||||
if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
|
||||
goto bad;
|
||||
if((pi = (struct pipe*)kalloc()) == 0)
|
||||
goto bad;
|
||||
pi->readopen = 1;
|
||||
pi->writeopen = 1;
|
||||
pi->nwrite = 0;
|
||||
pi->nread = 0;
|
||||
initlock(&pi->lock, "pipe");
|
||||
(*f0)->type = FD_PIPE;
|
||||
(*f0)->readable = 1;
|
||||
(*f0)->writable = 0;
|
||||
(*f0)->pipe = pi;
|
||||
(*f1)->type = FD_PIPE;
|
||||
(*f1)->readable = 0;
|
||||
(*f1)->writable = 1;
|
||||
(*f1)->pipe = pi;
|
||||
return 0;
|
||||
pi = 0;
|
||||
*f0 = *f1 = 0;
|
||||
if ((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
|
||||
goto bad;
|
||||
if ((pi = (struct pipe *)kalloc()) == 0)
|
||||
goto bad;
|
||||
pi->readopen = 1;
|
||||
pi->writeopen = 1;
|
||||
pi->nwrite = 0;
|
||||
pi->nread = 0;
|
||||
initlock(&pi->lock, "pipe");
|
||||
(*f0)->type = FD_PIPE;
|
||||
(*f0)->readable = 1;
|
||||
(*f0)->writable = 0;
|
||||
(*f0)->pipe = pi;
|
||||
(*f1)->type = FD_PIPE;
|
||||
(*f1)->readable = 0;
|
||||
(*f1)->writable = 1;
|
||||
(*f1)->pipe = pi;
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
if(pi)
|
||||
kfree((char*)pi);
|
||||
if(*f0)
|
||||
fileclose(*f0);
|
||||
if(*f1)
|
||||
fileclose(*f1);
|
||||
return -1;
|
||||
bad:
|
||||
if (pi)
|
||||
kfree((char *)pi);
|
||||
if (*f0)
|
||||
fileclose(*f0);
|
||||
if (*f1)
|
||||
fileclose(*f1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
pipeclose(struct pipe *pi, int writable)
|
||||
{
|
||||
acquire(&pi->lock);
|
||||
if(writable){
|
||||
pi->writeopen = 0;
|
||||
wakeup(&pi->nread);
|
||||
} else {
|
||||
pi->readopen = 0;
|
||||
wakeup(&pi->nwrite);
|
||||
}
|
||||
if(pi->readopen == 0 && pi->writeopen == 0){
|
||||
release(&pi->lock);
|
||||
kfree((char*)pi);
|
||||
} else
|
||||
release(&pi->lock);
|
||||
void pipeclose(struct pipe *pi, int writable) {
|
||||
acquire(&pi->lock);
|
||||
if (writable) {
|
||||
pi->writeopen = 0;
|
||||
wakeup(&pi->nread);
|
||||
} else {
|
||||
pi->readopen = 0;
|
||||
wakeup(&pi->nwrite);
|
||||
}
|
||||
if (pi->readopen == 0 && pi->writeopen == 0) {
|
||||
release(&pi->lock);
|
||||
kfree((char *)pi);
|
||||
} else
|
||||
release(&pi->lock);
|
||||
}
|
||||
|
||||
int
|
||||
pipewrite(struct pipe *pi, uint64 addr, int n)
|
||||
{
|
||||
int i = 0;
|
||||
struct proc *pr = myproc();
|
||||
int pipewrite(struct pipe *pi, uint64 addr, int n) {
|
||||
int i = 0;
|
||||
struct proc *pr = myproc();
|
||||
|
||||
acquire(&pi->lock);
|
||||
while(i < n){
|
||||
if(pi->readopen == 0 || killed(pr)){
|
||||
release(&pi->lock);
|
||||
return -1;
|
||||
}
|
||||
if(pi->nwrite == pi->nread + PIPESIZE){ //DOC: pipewrite-full
|
||||
wakeup(&pi->nread);
|
||||
sleep(&pi->nwrite, &pi->lock);
|
||||
} else {
|
||||
char ch;
|
||||
if(copyin(pr->pagetable, &ch, addr + i, 1) == -1)
|
||||
break;
|
||||
pi->data[pi->nwrite++ % PIPESIZE] = ch;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
wakeup(&pi->nread);
|
||||
release(&pi->lock);
|
||||
acquire(&pi->lock);
|
||||
while (i < n) {
|
||||
if (pi->readopen == 0 || killed(pr)) {
|
||||
release(&pi->lock);
|
||||
return -1;
|
||||
}
|
||||
if (pi->nwrite == pi->nread + PIPESIZE) { // DOC: pipewrite-full
|
||||
wakeup(&pi->nread);
|
||||
sleep(&pi->nwrite, &pi->lock);
|
||||
} else {
|
||||
char ch;
|
||||
if (copyin(pr->pagetable, &ch, addr + i, 1) == -1)
|
||||
break;
|
||||
pi->data[pi->nwrite++ % PIPESIZE] = ch;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
wakeup(&pi->nread);
|
||||
release(&pi->lock);
|
||||
|
||||
return i;
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
piperead(struct pipe *pi, uint64 addr, int n)
|
||||
{
|
||||
int i;
|
||||
struct proc *pr = myproc();
|
||||
char ch;
|
||||
int piperead(struct pipe *pi, uint64 addr, int n) {
|
||||
int i;
|
||||
struct proc *pr = myproc();
|
||||
char ch;
|
||||
|
||||
acquire(&pi->lock);
|
||||
while(pi->nread == pi->nwrite && pi->writeopen){ //DOC: pipe-empty
|
||||
if(killed(pr)){
|
||||
release(&pi->lock);
|
||||
return -1;
|
||||
}
|
||||
sleep(&pi->nread, &pi->lock); //DOC: piperead-sleep
|
||||
}
|
||||
for(i = 0; i < n; i++){ //DOC: piperead-copy
|
||||
if(pi->nread == pi->nwrite)
|
||||
break;
|
||||
ch = pi->data[pi->nread++ % PIPESIZE];
|
||||
if(copyout(pr->pagetable, addr + i, &ch, 1) == -1)
|
||||
break;
|
||||
}
|
||||
wakeup(&pi->nwrite); //DOC: piperead-wakeup
|
||||
release(&pi->lock);
|
||||
return i;
|
||||
acquire(&pi->lock);
|
||||
while (pi->nread == pi->nwrite && pi->writeopen) { // DOC: pipe-empty
|
||||
if (killed(pr)) {
|
||||
release(&pi->lock);
|
||||
return -1;
|
||||
}
|
||||
sleep(&pi->nread, &pi->lock); // DOC: piperead-sleep
|
||||
}
|
||||
for (i = 0; i < n; i++) { // DOC: piperead-copy
|
||||
if (pi->nread == pi->nwrite)
|
||||
break;
|
||||
ch = pi->data[pi->nread++ % PIPESIZE];
|
||||
if (copyout(pr->pagetable, addr + i, &ch, 1) == -1)
|
||||
break;
|
||||
}
|
||||
wakeup(&pi->nwrite); // DOC: piperead-wakeup
|
||||
release(&pi->lock);
|
||||
return i;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,40 +8,32 @@
|
|||
// the riscv Platform Level Interrupt Controller (PLIC).
|
||||
//
|
||||
|
||||
void
|
||||
plicinit(void)
|
||||
{
|
||||
// set desired IRQ priorities non-zero (otherwise disabled).
|
||||
*(uint32*)(PLIC + UART0_IRQ*4) = 1;
|
||||
*(uint32*)(PLIC + VIRTIO0_IRQ*4) = 1;
|
||||
void plicinit(void) {
|
||||
// set desired IRQ priorities non-zero (otherwise disabled).
|
||||
*(uint32 *)(PLIC + UART0_IRQ * 4) = 1;
|
||||
*(uint32 *)(PLIC + VIRTIO0_IRQ * 4) = 1;
|
||||
}
|
||||
|
||||
void
|
||||
plicinithart(void)
|
||||
{
|
||||
int hart = cpuid();
|
||||
|
||||
// set enable bits for this hart's S-mode
|
||||
// for the uart and virtio disk.
|
||||
*(uint32*)PLIC_SENABLE(hart) = (1 << UART0_IRQ) | (1 << VIRTIO0_IRQ);
|
||||
void plicinithart(void) {
|
||||
int hart = cpuid();
|
||||
|
||||
// set this hart's S-mode priority threshold to 0.
|
||||
*(uint32*)PLIC_SPRIORITY(hart) = 0;
|
||||
// set enable bits for this hart's S-mode
|
||||
// for the uart and virtio disk.
|
||||
*(uint32 *)PLIC_SENABLE(hart) = (1 << UART0_IRQ) | (1 << VIRTIO0_IRQ);
|
||||
|
||||
// set this hart's S-mode priority threshold to 0.
|
||||
*(uint32 *)PLIC_SPRIORITY(hart) = 0;
|
||||
}
|
||||
|
||||
// ask the PLIC what interrupt we should serve.
|
||||
int
|
||||
plic_claim(void)
|
||||
{
|
||||
int hart = cpuid();
|
||||
int irq = *(uint32*)PLIC_SCLAIM(hart);
|
||||
return irq;
|
||||
int plic_claim(void) {
|
||||
int hart = cpuid();
|
||||
int irq = *(uint32 *)PLIC_SCLAIM(hart);
|
||||
return irq;
|
||||
}
|
||||
|
||||
// tell the PLIC we've served this IRQ.
|
||||
void
|
||||
plic_complete(int irq)
|
||||
{
|
||||
int hart = cpuid();
|
||||
*(uint32*)PLIC_SCLAIM(hart) = irq;
|
||||
void plic_complete(int irq) {
|
||||
int hart = cpuid();
|
||||
*(uint32 *)PLIC_SCLAIM(hart) = irq;
|
||||
}
|
||||
|
|
|
|||
174
kernel/printf.c
174
kernel/printf.c
|
|
@ -19,117 +19,107 @@ volatile int panicked = 0;
|
|||
|
||||
// lock to avoid interleaving concurrent printf's.
|
||||
static struct {
|
||||
struct spinlock lock;
|
||||
int locking;
|
||||
struct spinlock lock;
|
||||
int locking;
|
||||
} pr;
|
||||
|
||||
static char digits[] = "0123456789abcdef";
|
||||
|
||||
static void
|
||||
printint(int xx, int base, int sign)
|
||||
{
|
||||
char buf[16];
|
||||
int i;
|
||||
uint x;
|
||||
static void printint(int xx, int base, int sign) {
|
||||
char buf[16];
|
||||
int i;
|
||||
uint x;
|
||||
|
||||
if(sign && (sign = xx < 0))
|
||||
x = -xx;
|
||||
else
|
||||
x = xx;
|
||||
if (sign && (sign = xx < 0))
|
||||
x = -xx;
|
||||
else
|
||||
x = xx;
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
buf[i++] = digits[x % base];
|
||||
} while((x /= base) != 0);
|
||||
i = 0;
|
||||
do {
|
||||
buf[i++] = digits[x % base];
|
||||
} while ((x /= base) != 0);
|
||||
|
||||
if(sign)
|
||||
buf[i++] = '-';
|
||||
if (sign)
|
||||
buf[i++] = '-';
|
||||
|
||||
while(--i >= 0)
|
||||
consputc(buf[i]);
|
||||
while (--i >= 0)
|
||||
consputc(buf[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
printptr(uint64 x)
|
||||
{
|
||||
int i;
|
||||
consputc('0');
|
||||
consputc('x');
|
||||
for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
|
||||
consputc(digits[x >> (sizeof(uint64) * 8 - 4)]);
|
||||
static void printptr(uint64 x) {
|
||||
int i;
|
||||
consputc('0');
|
||||
consputc('x');
|
||||
for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
|
||||
consputc(digits[x >> (sizeof(uint64) * 8 - 4)]);
|
||||
}
|
||||
|
||||
// Print to the console. only understands %d, %x, %p, %s.
|
||||
void
|
||||
printf(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int i, c, locking;
|
||||
char *s;
|
||||
void printf(char *fmt, ...) {
|
||||
va_list ap;
|
||||
int i, c, locking;
|
||||
char *s;
|
||||
|
||||
locking = pr.locking;
|
||||
if(locking)
|
||||
acquire(&pr.lock);
|
||||
locking = pr.locking;
|
||||
if (locking)
|
||||
acquire(&pr.lock);
|
||||
|
||||
if (fmt == 0)
|
||||
panic("null fmt");
|
||||
if (fmt == 0)
|
||||
panic("null fmt");
|
||||
|
||||
va_start(ap, fmt);
|
||||
for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
|
||||
if(c != '%'){
|
||||
consputc(c);
|
||||
continue;
|
||||
}
|
||||
c = fmt[++i] & 0xff;
|
||||
if(c == 0)
|
||||
break;
|
||||
switch(c){
|
||||
case 'd':
|
||||
printint(va_arg(ap, int), 10, 1);
|
||||
break;
|
||||
case 'x':
|
||||
printint(va_arg(ap, int), 16, 1);
|
||||
break;
|
||||
case 'p':
|
||||
printptr(va_arg(ap, uint64));
|
||||
break;
|
||||
case 's':
|
||||
if((s = va_arg(ap, char*)) == 0)
|
||||
s = "(null)";
|
||||
for(; *s; s++)
|
||||
consputc(*s);
|
||||
break;
|
||||
case '%':
|
||||
consputc('%');
|
||||
break;
|
||||
default:
|
||||
// Print unknown % sequence to draw attention.
|
||||
consputc('%');
|
||||
consputc(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
for (i = 0; (c = fmt[i] & 0xff) != 0; i++) {
|
||||
if (c != '%') {
|
||||
consputc(c);
|
||||
continue;
|
||||
}
|
||||
c = fmt[++i] & 0xff;
|
||||
if (c == 0)
|
||||
break;
|
||||
switch (c) {
|
||||
case 'd':
|
||||
printint(va_arg(ap, int), 10, 1);
|
||||
break;
|
||||
case 'x':
|
||||
printint(va_arg(ap, int), 16, 1);
|
||||
break;
|
||||
case 'p':
|
||||
printptr(va_arg(ap, uint64));
|
||||
break;
|
||||
case 's':
|
||||
if ((s = va_arg(ap, char *)) == 0)
|
||||
s = "(null)";
|
||||
for (; *s; s++)
|
||||
consputc(*s);
|
||||
break;
|
||||
case '%':
|
||||
consputc('%');
|
||||
break;
|
||||
default:
|
||||
// Print unknown % sequence to draw attention.
|
||||
consputc('%');
|
||||
consputc(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if(locking)
|
||||
release(&pr.lock);
|
||||
if (locking)
|
||||
release(&pr.lock);
|
||||
}
|
||||
|
||||
void
|
||||
panic(char *s)
|
||||
{
|
||||
pr.locking = 0;
|
||||
printf("panic: ");
|
||||
printf(s);
|
||||
printf("\n");
|
||||
panicked = 1; // freeze uart output from other CPUs
|
||||
for(;;)
|
||||
;
|
||||
void panic(char *s) {
|
||||
pr.locking = 0;
|
||||
printf("panic: ");
|
||||
printf(s);
|
||||
printf("\n");
|
||||
panicked = 1; // freeze uart output from other CPUs
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
printfinit(void)
|
||||
{
|
||||
initlock(&pr.lock, "pr");
|
||||
pr.locking = 1;
|
||||
void printfinit(void) {
|
||||
initlock(&pr.lock, "pr");
|
||||
pr.locking = 1;
|
||||
}
|
||||
|
|
|
|||
881
kernel/proc.c
881
kernel/proc.c
File diff suppressed because it is too large
Load Diff
|
|
@ -12,34 +12,29 @@
|
|||
#include "fs.h"
|
||||
#include "buf.h"
|
||||
|
||||
void
|
||||
ramdiskinit(void)
|
||||
{
|
||||
}
|
||||
void ramdiskinit(void) {}
|
||||
|
||||
// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
|
||||
// Else if B_VALID is not set, read buf from disk, set B_VALID.
|
||||
void
|
||||
ramdiskrw(struct buf *b)
|
||||
{
|
||||
if(!holdingsleep(&b->lock))
|
||||
panic("ramdiskrw: buf not locked");
|
||||
if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
|
||||
panic("ramdiskrw: nothing to do");
|
||||
void ramdiskrw(struct buf *b) {
|
||||
if (!holdingsleep(&b->lock))
|
||||
panic("ramdiskrw: buf not locked");
|
||||
if ((b->flags & (B_VALID | B_DIRTY)) == B_VALID)
|
||||
panic("ramdiskrw: nothing to do");
|
||||
|
||||
if(b->blockno >= FSSIZE)
|
||||
panic("ramdiskrw: blockno too big");
|
||||
if (b->blockno >= FSSIZE)
|
||||
panic("ramdiskrw: blockno too big");
|
||||
|
||||
uint64 diskaddr = b->blockno * BSIZE;
|
||||
char *addr = (char *)RAMDISK + diskaddr;
|
||||
uint64 diskaddr = b->blockno * BSIZE;
|
||||
char *addr = (char *)RAMDISK + diskaddr;
|
||||
|
||||
if(b->flags & B_DIRTY){
|
||||
// write
|
||||
memmove(addr, b->data, BSIZE);
|
||||
b->flags &= ~B_DIRTY;
|
||||
} else {
|
||||
// read
|
||||
memmove(b->data, addr, BSIZE);
|
||||
b->flags |= B_VALID;
|
||||
}
|
||||
if (b->flags & B_DIRTY) {
|
||||
// write
|
||||
memmove(addr, b->data, BSIZE);
|
||||
b->flags &= ~B_DIRTY;
|
||||
} else {
|
||||
// read
|
||||
memmove(b->data, addr, BSIZE);
|
||||
b->flags |= B_VALID;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,47 +9,36 @@
|
|||
#include "proc.h"
|
||||
#include "sleeplock.h"
|
||||
|
||||
void
|
||||
initsleeplock(struct sleeplock *lk, char *name)
|
||||
{
|
||||
initlock(&lk->lk, "sleep lock");
|
||||
lk->name = name;
|
||||
lk->locked = 0;
|
||||
lk->pid = 0;
|
||||
void initsleeplock(struct sleeplock *lk, char *name) {
|
||||
initlock(&lk->lk, "sleep lock");
|
||||
lk->name = name;
|
||||
lk->locked = 0;
|
||||
lk->pid = 0;
|
||||
}
|
||||
|
||||
void
|
||||
acquiresleep(struct sleeplock *lk)
|
||||
{
|
||||
acquire(&lk->lk);
|
||||
while (lk->locked) {
|
||||
sleep(lk, &lk->lk);
|
||||
}
|
||||
lk->locked = 1;
|
||||
lk->pid = myproc()->pid;
|
||||
release(&lk->lk);
|
||||
void acquiresleep(struct sleeplock *lk) {
|
||||
acquire(&lk->lk);
|
||||
while (lk->locked) {
|
||||
sleep(lk, &lk->lk);
|
||||
}
|
||||
lk->locked = 1;
|
||||
lk->pid = myproc()->pid;
|
||||
release(&lk->lk);
|
||||
}
|
||||
|
||||
void
|
||||
releasesleep(struct sleeplock *lk)
|
||||
{
|
||||
acquire(&lk->lk);
|
||||
lk->locked = 0;
|
||||
lk->pid = 0;
|
||||
wakeup(lk);
|
||||
release(&lk->lk);
|
||||
void releasesleep(struct sleeplock *lk) {
|
||||
acquire(&lk->lk);
|
||||
lk->locked = 0;
|
||||
lk->pid = 0;
|
||||
wakeup(lk);
|
||||
release(&lk->lk);
|
||||
}
|
||||
|
||||
int
|
||||
holdingsleep(struct sleeplock *lk)
|
||||
{
|
||||
int r;
|
||||
|
||||
acquire(&lk->lk);
|
||||
r = lk->locked && (lk->pid == myproc()->pid);
|
||||
release(&lk->lk);
|
||||
return r;
|
||||
int holdingsleep(struct sleeplock *lk) {
|
||||
int r;
|
||||
|
||||
acquire(&lk->lk);
|
||||
r = lk->locked && (lk->pid == myproc()->pid);
|
||||
release(&lk->lk);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,103 +8,91 @@
|
|||
#include "proc.h"
|
||||
#include "defs.h"
|
||||
|
||||
void
|
||||
initlock(struct spinlock *lk, char *name)
|
||||
{
|
||||
lk->name = name;
|
||||
lk->locked = 0;
|
||||
lk->cpu = 0;
|
||||
void initlock(struct spinlock *lk, char *name) {
|
||||
lk->name = name;
|
||||
lk->locked = 0;
|
||||
lk->cpu = 0;
|
||||
}
|
||||
|
||||
// Acquire the lock.
|
||||
// Loops (spins) until the lock is acquired.
|
||||
void
|
||||
acquire(struct spinlock *lk)
|
||||
{
|
||||
push_off(); // disable interrupts to avoid deadlock.
|
||||
if(holding(lk))
|
||||
panic("acquire");
|
||||
void acquire(struct spinlock *lk) {
|
||||
push_off(); // disable interrupts to avoid deadlock.
|
||||
if (holding(lk))
|
||||
panic("acquire");
|
||||
|
||||
// On RISC-V, sync_lock_test_and_set turns into an atomic swap:
|
||||
// a5 = 1
|
||||
// s1 = &lk->locked
|
||||
// amoswap.w.aq a5, a5, (s1)
|
||||
while(__sync_lock_test_and_set(&lk->locked, 1) != 0)
|
||||
;
|
||||
// On RISC-V, sync_lock_test_and_set turns into an atomic swap:
|
||||
// a5 = 1
|
||||
// s1 = &lk->locked
|
||||
// amoswap.w.aq a5, a5, (s1)
|
||||
while (__sync_lock_test_and_set(&lk->locked, 1) != 0)
|
||||
;
|
||||
|
||||
// Tell the C compiler and the processor to not move loads or stores
|
||||
// past this point, to ensure that the critical section's memory
|
||||
// references happen strictly after the lock is acquired.
|
||||
// On RISC-V, this emits a fence instruction.
|
||||
__sync_synchronize();
|
||||
// Tell the C compiler and the processor to not move loads or stores
|
||||
// past this point, to ensure that the critical section's memory
|
||||
// references happen strictly after the lock is acquired.
|
||||
// On RISC-V, this emits a fence instruction.
|
||||
__sync_synchronize();
|
||||
|
||||
// Record info about lock acquisition for holding() and debugging.
|
||||
lk->cpu = mycpu();
|
||||
// Record info about lock acquisition for holding() and debugging.
|
||||
lk->cpu = mycpu();
|
||||
}
|
||||
|
||||
// Release the lock.
|
||||
void
|
||||
release(struct spinlock *lk)
|
||||
{
|
||||
if(!holding(lk))
|
||||
panic("release");
|
||||
void release(struct spinlock *lk) {
|
||||
if (!holding(lk))
|
||||
panic("release");
|
||||
|
||||
lk->cpu = 0;
|
||||
lk->cpu = 0;
|
||||
|
||||
// Tell the C compiler and the CPU to not move loads or stores
|
||||
// past this point, to ensure that all the stores in the critical
|
||||
// section are visible to other CPUs before the lock is released,
|
||||
// and that loads in the critical section occur strictly before
|
||||
// the lock is released.
|
||||
// On RISC-V, this emits a fence instruction.
|
||||
__sync_synchronize();
|
||||
// Tell the C compiler and the CPU to not move loads or stores
|
||||
// past this point, to ensure that all the stores in the critical
|
||||
// section are visible to other CPUs before the lock is released,
|
||||
// and that loads in the critical section occur strictly before
|
||||
// the lock is released.
|
||||
// On RISC-V, this emits a fence instruction.
|
||||
__sync_synchronize();
|
||||
|
||||
// Release the lock, equivalent to lk->locked = 0.
|
||||
// This code doesn't use a C assignment, since the C standard
|
||||
// implies that an assignment might be implemented with
|
||||
// multiple store instructions.
|
||||
// On RISC-V, sync_lock_release turns into an atomic swap:
|
||||
// s1 = &lk->locked
|
||||
// amoswap.w zero, zero, (s1)
|
||||
__sync_lock_release(&lk->locked);
|
||||
// Release the lock, equivalent to lk->locked = 0.
|
||||
// This code doesn't use a C assignment, since the C standard
|
||||
// implies that an assignment might be implemented with
|
||||
// multiple store instructions.
|
||||
// On RISC-V, sync_lock_release turns into an atomic swap:
|
||||
// s1 = &lk->locked
|
||||
// amoswap.w zero, zero, (s1)
|
||||
__sync_lock_release(&lk->locked);
|
||||
|
||||
pop_off();
|
||||
pop_off();
|
||||
}
|
||||
|
||||
// Check whether this cpu is holding the lock.
|
||||
// Interrupts must be off.
|
||||
int
|
||||
holding(struct spinlock *lk)
|
||||
{
|
||||
int r;
|
||||
r = (lk->locked && lk->cpu == mycpu());
|
||||
return r;
|
||||
int holding(struct spinlock *lk) {
|
||||
int r;
|
||||
r = (lk->locked && lk->cpu == mycpu());
|
||||
return r;
|
||||
}
|
||||
|
||||
// push_off/pop_off are like intr_off()/intr_on() except that they are matched:
|
||||
// it takes two pop_off()s to undo two push_off()s. Also, if interrupts
|
||||
// are initially off, then push_off, pop_off leaves them off.
|
||||
|
||||
void
|
||||
push_off(void)
|
||||
{
|
||||
int old = intr_get();
|
||||
void push_off(void) {
|
||||
int old = intr_get();
|
||||
|
||||
intr_off();
|
||||
if(mycpu()->noff == 0)
|
||||
mycpu()->intena = old;
|
||||
mycpu()->noff += 1;
|
||||
intr_off();
|
||||
if (mycpu()->noff == 0)
|
||||
mycpu()->intena = old;
|
||||
mycpu()->noff += 1;
|
||||
}
|
||||
|
||||
void
|
||||
pop_off(void)
|
||||
{
|
||||
struct cpu *c = mycpu();
|
||||
if(intr_get())
|
||||
panic("pop_off - interruptible");
|
||||
if(c->noff < 1)
|
||||
panic("pop_off");
|
||||
c->noff -= 1;
|
||||
if(c->noff == 0 && c->intena)
|
||||
intr_on();
|
||||
void pop_off(void) {
|
||||
struct cpu *c = mycpu();
|
||||
if (intr_get())
|
||||
panic("pop_off - interruptible");
|
||||
if (c->noff < 1)
|
||||
panic("pop_off");
|
||||
c->noff -= 1;
|
||||
if (c->noff == 0 && c->intena)
|
||||
intr_on();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ void main();
|
|||
void timerinit();
|
||||
|
||||
// entry.S needs one stack per CPU.
|
||||
__attribute__ ((aligned (16))) char stack0[4096 * NCPU];
|
||||
__attribute__((aligned(16))) char stack0[4096 * NCPU];
|
||||
|
||||
// a scratch area per CPU for machine-mode timer interrupts.
|
||||
uint64 timer_scratch[NCPU][5];
|
||||
|
|
@ -17,41 +17,39 @@ uint64 timer_scratch[NCPU][5];
|
|||
extern void timervec();
|
||||
|
||||
// entry.S jumps here in machine mode on stack0.
|
||||
void
|
||||
start()
|
||||
{
|
||||
// set M Previous Privilege mode to Supervisor, for mret.
|
||||
unsigned long x = r_mstatus();
|
||||
x &= ~MSTATUS_MPP_MASK;
|
||||
x |= MSTATUS_MPP_S;
|
||||
w_mstatus(x);
|
||||
void start() {
|
||||
// set M Previous Privilege mode to Supervisor, for mret.
|
||||
unsigned long x = r_mstatus();
|
||||
x &= ~MSTATUS_MPP_MASK;
|
||||
x |= MSTATUS_MPP_S;
|
||||
w_mstatus(x);
|
||||
|
||||
// set M Exception Program Counter to main, for mret.
|
||||
// requires gcc -mcmodel=medany
|
||||
w_mepc((uint64)main);
|
||||
// set M Exception Program Counter to main, for mret.
|
||||
// requires gcc -mcmodel=medany
|
||||
w_mepc((uint64)main);
|
||||
|
||||
// disable paging for now.
|
||||
w_satp(0);
|
||||
// disable paging for now.
|
||||
w_satp(0);
|
||||
|
||||
// delegate all interrupts and exceptions to supervisor mode.
|
||||
w_medeleg(0xffff);
|
||||
w_mideleg(0xffff);
|
||||
w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE);
|
||||
// delegate all interrupts and exceptions to supervisor mode.
|
||||
w_medeleg(0xffff);
|
||||
w_mideleg(0xffff);
|
||||
w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE);
|
||||
|
||||
// configure Physical Memory Protection to give supervisor mode
|
||||
// access to all of physical memory.
|
||||
w_pmpaddr0(0x3fffffffffffffull);
|
||||
w_pmpcfg0(0xf);
|
||||
// configure Physical Memory Protection to give supervisor mode
|
||||
// access to all of physical memory.
|
||||
w_pmpaddr0(0x3fffffffffffffull);
|
||||
w_pmpcfg0(0xf);
|
||||
|
||||
// ask for clock interrupts.
|
||||
timerinit();
|
||||
// ask for clock interrupts.
|
||||
timerinit();
|
||||
|
||||
// keep each CPU's hartid in its tp register, for cpuid().
|
||||
int id = r_mhartid();
|
||||
w_tp(id);
|
||||
// keep each CPU's hartid in its tp register, for cpuid().
|
||||
int id = r_mhartid();
|
||||
w_tp(id);
|
||||
|
||||
// switch to supervisor mode and jump to main().
|
||||
asm volatile("mret");
|
||||
// switch to supervisor mode and jump to main().
|
||||
asm volatile("mret");
|
||||
}
|
||||
|
||||
// arrange to receive timer interrupts.
|
||||
|
|
@ -59,31 +57,29 @@ start()
|
|||
// at timervec in kernelvec.S,
|
||||
// which turns them into software interrupts for
|
||||
// devintr() in trap.c.
|
||||
void
|
||||
timerinit()
|
||||
{
|
||||
// each CPU has a separate source of timer interrupts.
|
||||
int id = r_mhartid();
|
||||
void timerinit() {
|
||||
// each CPU has a separate source of timer interrupts.
|
||||
int id = r_mhartid();
|
||||
|
||||
// ask the CLINT for a timer interrupt.
|
||||
int interval = 1000000; // cycles; about 1/10th second in qemu.
|
||||
*(uint64*)CLINT_MTIMECMP(id) = *(uint64*)CLINT_MTIME + interval;
|
||||
// ask the CLINT for a timer interrupt.
|
||||
int interval = 1000000; // cycles; about 1/10th second in qemu.
|
||||
*(uint64 *)CLINT_MTIMECMP(id) = *(uint64 *)CLINT_MTIME + interval;
|
||||
|
||||
// prepare information in scratch[] for timervec.
|
||||
// scratch[0..2] : space for timervec to save registers.
|
||||
// scratch[3] : address of CLINT MTIMECMP register.
|
||||
// scratch[4] : desired interval (in cycles) between timer interrupts.
|
||||
uint64 *scratch = &timer_scratch[id][0];
|
||||
scratch[3] = CLINT_MTIMECMP(id);
|
||||
scratch[4] = interval;
|
||||
w_mscratch((uint64)scratch);
|
||||
// prepare information in scratch[] for timervec.
|
||||
// scratch[0..2] : space for timervec to save registers.
|
||||
// scratch[3] : address of CLINT MTIMECMP register.
|
||||
// scratch[4] : desired interval (in cycles) between timer interrupts.
|
||||
uint64 *scratch = &timer_scratch[id][0];
|
||||
scratch[3] = CLINT_MTIMECMP(id);
|
||||
scratch[4] = interval;
|
||||
w_mscratch((uint64)scratch);
|
||||
|
||||
// set the machine-mode trap handler.
|
||||
w_mtvec((uint64)timervec);
|
||||
// set the machine-mode trap handler.
|
||||
w_mtvec((uint64)timervec);
|
||||
|
||||
// enable machine-mode interrupts.
|
||||
w_mstatus(r_mstatus() | MSTATUS_MIE);
|
||||
// enable machine-mode interrupts.
|
||||
w_mstatus(r_mstatus() | MSTATUS_MIE);
|
||||
|
||||
// enable machine-mode timer interrupts.
|
||||
w_mie(r_mie() | MIE_MTIE);
|
||||
// enable machine-mode timer interrupts.
|
||||
w_mie(r_mie() | MIE_MTIE);
|
||||
}
|
||||
|
|
|
|||
145
kernel/string.c
145
kernel/string.c
|
|
@ -1,107 +1,90 @@
|
|||
#include "types.h"
|
||||
|
||||
void*
|
||||
memset(void *dst, int c, uint n)
|
||||
{
|
||||
char *cdst = (char *) dst;
|
||||
int i;
|
||||
for(i = 0; i < n; i++){
|
||||
cdst[i] = c;
|
||||
}
|
||||
return dst;
|
||||
void *memset(void *dst, int c, uint n) {
|
||||
char *cdst = (char *)dst;
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
cdst[i] = c;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
int
|
||||
memcmp(const void *v1, const void *v2, uint n)
|
||||
{
|
||||
const uchar *s1, *s2;
|
||||
int memcmp(const void *v1, const void *v2, uint n) {
|
||||
const uchar *s1, *s2;
|
||||
|
||||
s1 = v1;
|
||||
s2 = v2;
|
||||
while(n-- > 0){
|
||||
if(*s1 != *s2)
|
||||
return *s1 - *s2;
|
||||
s1++, s2++;
|
||||
}
|
||||
s1 = v1;
|
||||
s2 = v2;
|
||||
while (n-- > 0) {
|
||||
if (*s1 != *s2)
|
||||
return *s1 - *s2;
|
||||
s1++, s2++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
memmove(void *dst, const void *src, uint n)
|
||||
{
|
||||
const char *s;
|
||||
char *d;
|
||||
void *memmove(void *dst, const void *src, uint n) {
|
||||
const char *s;
|
||||
char *d;
|
||||
|
||||
if(n == 0)
|
||||
return dst;
|
||||
|
||||
s = src;
|
||||
d = dst;
|
||||
if(s < d && s + n > d){
|
||||
s += n;
|
||||
d += n;
|
||||
while(n-- > 0)
|
||||
*--d = *--s;
|
||||
} else
|
||||
while(n-- > 0)
|
||||
*d++ = *s++;
|
||||
if (n == 0)
|
||||
return dst;
|
||||
|
||||
return dst;
|
||||
s = src;
|
||||
d = dst;
|
||||
if (s < d && s + n > d) {
|
||||
s += n;
|
||||
d += n;
|
||||
while (n-- > 0)
|
||||
*--d = *--s;
|
||||
} else
|
||||
while (n-- > 0)
|
||||
*d++ = *s++;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
// memcpy exists to placate GCC. Use memmove.
|
||||
void*
|
||||
memcpy(void *dst, const void *src, uint n)
|
||||
{
|
||||
return memmove(dst, src, n);
|
||||
void *memcpy(void *dst, const void *src, uint n) {
|
||||
return memmove(dst, src, n);
|
||||
}
|
||||
|
||||
int
|
||||
strncmp(const char *p, const char *q, uint n)
|
||||
{
|
||||
while(n > 0 && *p && *p == *q)
|
||||
n--, p++, q++;
|
||||
if(n == 0)
|
||||
return 0;
|
||||
return (uchar)*p - (uchar)*q;
|
||||
int strncmp(const char *p, const char *q, uint n) {
|
||||
while (n > 0 && *p && *p == *q)
|
||||
n--, p++, q++;
|
||||
if (n == 0)
|
||||
return 0;
|
||||
return (uchar)*p - (uchar)*q;
|
||||
}
|
||||
|
||||
char*
|
||||
strncpy(char *s, const char *t, int n)
|
||||
{
|
||||
char *os;
|
||||
char *strncpy(char *s, const char *t, int n) {
|
||||
char *os;
|
||||
|
||||
os = s;
|
||||
while(n-- > 0 && (*s++ = *t++) != 0)
|
||||
;
|
||||
while(n-- > 0)
|
||||
*s++ = 0;
|
||||
return os;
|
||||
os = s;
|
||||
while (n-- > 0 && (*s++ = *t++) != 0)
|
||||
;
|
||||
while (n-- > 0)
|
||||
*s++ = 0;
|
||||
return os;
|
||||
}
|
||||
|
||||
// Like strncpy but guaranteed to NUL-terminate.
|
||||
char*
|
||||
safestrcpy(char *s, const char *t, int n)
|
||||
{
|
||||
char *os;
|
||||
char *safestrcpy(char *s, const char *t, int n) {
|
||||
char *os;
|
||||
|
||||
os = s;
|
||||
if(n <= 0)
|
||||
return os;
|
||||
while(--n > 0 && (*s++ = *t++) != 0)
|
||||
;
|
||||
*s = 0;
|
||||
return os;
|
||||
os = s;
|
||||
if (n <= 0)
|
||||
return os;
|
||||
while (--n > 0 && (*s++ = *t++) != 0)
|
||||
;
|
||||
*s = 0;
|
||||
return os;
|
||||
}
|
||||
|
||||
int
|
||||
strlen(const char *s)
|
||||
{
|
||||
int n;
|
||||
int strlen(const char *s) {
|
||||
int n;
|
||||
|
||||
for(n = 0; s[n]; n++)
|
||||
;
|
||||
return n;
|
||||
for (n = 0; s[n]; n++)
|
||||
;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
|
|||
145
kernel/syscall.c
145
kernel/syscall.c
|
|
@ -8,77 +8,63 @@
|
|||
#include "defs.h"
|
||||
|
||||
// Fetch the uint64 at addr from the current process.
|
||||
int
|
||||
fetchaddr(uint64 addr, uint64 *ip)
|
||||
{
|
||||
struct proc *p = myproc();
|
||||
if(addr >= p->sz || addr+sizeof(uint64) > p->sz) // both tests needed, in case of overflow
|
||||
return -1;
|
||||
if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
int fetchaddr(uint64 addr, uint64 *ip) {
|
||||
struct proc *p = myproc();
|
||||
if (addr >= p->sz ||
|
||||
addr + sizeof(uint64) > p->sz) // both tests needed, in case of overflow
|
||||
return -1;
|
||||
if (copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fetch the nul-terminated string at addr from the current process.
|
||||
// Returns length of string, not including nul, or -1 for error.
|
||||
int
|
||||
fetchstr(uint64 addr, char *buf, int max)
|
||||
{
|
||||
struct proc *p = myproc();
|
||||
if(copyinstr(p->pagetable, buf, addr, max) < 0)
|
||||
return -1;
|
||||
return strlen(buf);
|
||||
int fetchstr(uint64 addr, char *buf, int max) {
|
||||
struct proc *p = myproc();
|
||||
if (copyinstr(p->pagetable, buf, addr, max) < 0)
|
||||
return -1;
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
static uint64
|
||||
argraw(int n)
|
||||
{
|
||||
struct proc *p = myproc();
|
||||
switch (n) {
|
||||
case 0:
|
||||
return p->trapframe->a0;
|
||||
case 1:
|
||||
return p->trapframe->a1;
|
||||
case 2:
|
||||
return p->trapframe->a2;
|
||||
case 3:
|
||||
return p->trapframe->a3;
|
||||
case 4:
|
||||
return p->trapframe->a4;
|
||||
case 5:
|
||||
return p->trapframe->a5;
|
||||
}
|
||||
panic("argraw");
|
||||
return -1;
|
||||
static uint64 argraw(int n) {
|
||||
struct proc *p = myproc();
|
||||
switch (n) {
|
||||
case 0:
|
||||
return p->trapframe->a0;
|
||||
case 1:
|
||||
return p->trapframe->a1;
|
||||
case 2:
|
||||
return p->trapframe->a2;
|
||||
case 3:
|
||||
return p->trapframe->a3;
|
||||
case 4:
|
||||
return p->trapframe->a4;
|
||||
case 5:
|
||||
return p->trapframe->a5;
|
||||
}
|
||||
panic("argraw");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fetch the nth 32-bit system call argument.
|
||||
void
|
||||
argint(int n, int *ip)
|
||||
{
|
||||
*ip = argraw(n);
|
||||
}
|
||||
void argint(int n, int *ip) { *ip = argraw(n); }
|
||||
|
||||
// Retrieve an argument as a pointer.
|
||||
// Doesn't check for legality, since
|
||||
// copyin/copyout will do that.
|
||||
void
|
||||
argaddr(int n, uint64 *ip)
|
||||
{
|
||||
*ip = argraw(n);
|
||||
}
|
||||
void argaddr(int n, uint64 *ip) { *ip = argraw(n); }
|
||||
|
||||
// Fetch the nth word-sized system call argument as a null-terminated string.
|
||||
// Copies into buf, at most max.
|
||||
// Returns string length if OK (including nul), -1 if error.
|
||||
int
|
||||
argstr(int n, char *buf, int max)
|
||||
{
|
||||
uint64 addr;
|
||||
argaddr(n, &addr);
|
||||
return fetchstr(addr, buf, max);
|
||||
int argstr(int n, char *buf, int max) {
|
||||
uint64 addr;
|
||||
argaddr(n, &addr);
|
||||
return fetchstr(addr, buf, max);
|
||||
}
|
||||
|
||||
// Prototypes for the functions that handle system calls.
|
||||
extern uint64 sys_fork(void);
|
||||
extern uint64 sys_exit(void);
|
||||
extern uint64 sys_wait(void);
|
||||
|
|
@ -101,42 +87,29 @@ extern uint64 sys_link(void);
|
|||
extern uint64 sys_mkdir(void);
|
||||
extern uint64 sys_close(void);
|
||||
|
||||
// An array mapping syscall numbers from syscall.h
|
||||
// to the function that handles the system call.
|
||||
static uint64 (*syscalls[])(void) = {
|
||||
[SYS_fork] sys_fork,
|
||||
[SYS_exit] sys_exit,
|
||||
[SYS_wait] sys_wait,
|
||||
[SYS_pipe] sys_pipe,
|
||||
[SYS_read] sys_read,
|
||||
[SYS_kill] sys_kill,
|
||||
[SYS_exec] sys_exec,
|
||||
[SYS_fstat] sys_fstat,
|
||||
[SYS_chdir] sys_chdir,
|
||||
[SYS_dup] sys_dup,
|
||||
[SYS_getpid] sys_getpid,
|
||||
[SYS_sbrk] sys_sbrk,
|
||||
[SYS_sleep] sys_sleep,
|
||||
[SYS_uptime] sys_uptime,
|
||||
[SYS_open] sys_open,
|
||||
[SYS_write] sys_write,
|
||||
[SYS_mknod] sys_mknod,
|
||||
[SYS_unlink] sys_unlink,
|
||||
[SYS_link] sys_link,
|
||||
[SYS_mkdir] sys_mkdir,
|
||||
[SYS_close] sys_close,
|
||||
[SYS_fork] sys_fork, [SYS_exit] sys_exit, [SYS_wait] sys_wait,
|
||||
[SYS_pipe] sys_pipe, [SYS_read] sys_read, [SYS_kill] sys_kill,
|
||||
[SYS_exec] sys_exec, [SYS_fstat] sys_fstat, [SYS_chdir] sys_chdir,
|
||||
[SYS_dup] sys_dup, [SYS_getpid] sys_getpid, [SYS_sbrk] sys_sbrk,
|
||||
[SYS_sleep] sys_sleep, [SYS_uptime] sys_uptime, [SYS_open] sys_open,
|
||||
[SYS_write] sys_write, [SYS_mknod] sys_mknod, [SYS_unlink] sys_unlink,
|
||||
[SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close,
|
||||
};
|
||||
|
||||
void
|
||||
syscall(void)
|
||||
{
|
||||
int num;
|
||||
struct proc *p = myproc();
|
||||
void syscall(void) {
|
||||
int num;
|
||||
struct proc *p = myproc();
|
||||
|
||||
num = p->trapframe->a7;
|
||||
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
|
||||
p->trapframe->a0 = syscalls[num]();
|
||||
} else {
|
||||
printf("%d %s: unknown sys call %d\n",
|
||||
p->pid, p->name, num);
|
||||
p->trapframe->a0 = -1;
|
||||
}
|
||||
num = p->trapframe->a7;
|
||||
if (num > 0 && num < NELEM(syscalls) && syscalls[num]) {
|
||||
// Use num to lookup the system call function for num, call it,
|
||||
// and store its return value in p->trapframe->a0
|
||||
p->trapframe->a0 = syscalls[num]();
|
||||
} else {
|
||||
printf("%d %s: unknown sys call %d\n", p->pid, p->name, num);
|
||||
p->trapframe->a0 = -1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
749
kernel/sysfile.c
749
kernel/sysfile.c
|
|
@ -18,488 +18,455 @@
|
|||
|
||||
// Fetch the nth word-sized system call argument as a file descriptor
|
||||
// and return both the descriptor and the corresponding struct file.
|
||||
static int
|
||||
argfd(int n, int *pfd, struct file **pf)
|
||||
{
|
||||
int fd;
|
||||
struct file *f;
|
||||
static int argfd(int n, int *pfd, struct file **pf) {
|
||||
int fd;
|
||||
struct file *f;
|
||||
|
||||
argint(n, &fd);
|
||||
if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)
|
||||
return -1;
|
||||
if(pfd)
|
||||
*pfd = fd;
|
||||
if(pf)
|
||||
*pf = f;
|
||||
return 0;
|
||||
argint(n, &fd);
|
||||
if (fd < 0 || fd >= NOFILE || (f = myproc()->ofile[fd]) == 0)
|
||||
return -1;
|
||||
if (pfd)
|
||||
*pfd = fd;
|
||||
if (pf)
|
||||
*pf = f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate a file descriptor for the given file.
|
||||
// Takes over file reference from caller on success.
|
||||
static int
|
||||
fdalloc(struct file *f)
|
||||
{
|
||||
int fd;
|
||||
struct proc *p = myproc();
|
||||
static int fdalloc(struct file *f) {
|
||||
int fd;
|
||||
struct proc *p = myproc();
|
||||
|
||||
for(fd = 0; fd < NOFILE; fd++){
|
||||
if(p->ofile[fd] == 0){
|
||||
p->ofile[fd] = f;
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
for (fd = 0; fd < NOFILE; fd++) {
|
||||
if (p->ofile[fd] == 0) {
|
||||
p->ofile[fd] = f;
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_dup(void)
|
||||
{
|
||||
struct file *f;
|
||||
int fd;
|
||||
uint64 sys_dup(void) {
|
||||
struct file *f;
|
||||
int fd;
|
||||
|
||||
if(argfd(0, 0, &f) < 0)
|
||||
return -1;
|
||||
if((fd=fdalloc(f)) < 0)
|
||||
return -1;
|
||||
filedup(f);
|
||||
return fd;
|
||||
if (argfd(0, 0, &f) < 0)
|
||||
return -1;
|
||||
if ((fd = fdalloc(f)) < 0)
|
||||
return -1;
|
||||
filedup(f);
|
||||
return fd;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_read(void)
|
||||
{
|
||||
struct file *f;
|
||||
int n;
|
||||
uint64 p;
|
||||
uint64 sys_read(void) {
|
||||
struct file *f;
|
||||
int n;
|
||||
uint64 p;
|
||||
|
||||
argaddr(1, &p);
|
||||
argint(2, &n);
|
||||
if(argfd(0, 0, &f) < 0)
|
||||
return -1;
|
||||
return fileread(f, p, n);
|
||||
argaddr(1, &p);
|
||||
argint(2, &n);
|
||||
if (argfd(0, 0, &f) < 0)
|
||||
return -1;
|
||||
return fileread(f, p, n);
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_write(void)
|
||||
{
|
||||
struct file *f;
|
||||
int n;
|
||||
uint64 p;
|
||||
|
||||
argaddr(1, &p);
|
||||
argint(2, &n);
|
||||
if(argfd(0, 0, &f) < 0)
|
||||
return -1;
|
||||
uint64 sys_write(void) {
|
||||
struct file *f;
|
||||
int n;
|
||||
uint64 p;
|
||||
|
||||
return filewrite(f, p, n);
|
||||
argaddr(1, &p);
|
||||
argint(2, &n);
|
||||
if (argfd(0, 0, &f) < 0)
|
||||
return -1;
|
||||
|
||||
return filewrite(f, p, n);
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_close(void)
|
||||
{
|
||||
int fd;
|
||||
struct file *f;
|
||||
uint64 sys_close(void) {
|
||||
int fd;
|
||||
struct file *f;
|
||||
|
||||
if(argfd(0, &fd, &f) < 0)
|
||||
return -1;
|
||||
myproc()->ofile[fd] = 0;
|
||||
fileclose(f);
|
||||
return 0;
|
||||
if (argfd(0, &fd, &f) < 0)
|
||||
return -1;
|
||||
myproc()->ofile[fd] = 0;
|
||||
fileclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_fstat(void)
|
||||
{
|
||||
struct file *f;
|
||||
uint64 st; // user pointer to struct stat
|
||||
uint64 sys_fstat(void) {
|
||||
struct file *f;
|
||||
uint64 st; // user pointer to struct stat
|
||||
|
||||
argaddr(1, &st);
|
||||
if(argfd(0, 0, &f) < 0)
|
||||
return -1;
|
||||
return filestat(f, st);
|
||||
argaddr(1, &st);
|
||||
if (argfd(0, 0, &f) < 0)
|
||||
return -1;
|
||||
return filestat(f, st);
|
||||
}
|
||||
|
||||
// Create the path new as a link to the same inode as old.
|
||||
uint64
|
||||
sys_link(void)
|
||||
{
|
||||
char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
|
||||
struct inode *dp, *ip;
|
||||
uint64 sys_link(void) {
|
||||
char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
|
||||
struct inode *dp, *ip;
|
||||
|
||||
if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
|
||||
return -1;
|
||||
if (argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
|
||||
return -1;
|
||||
|
||||
begin_op();
|
||||
if((ip = namei(old)) == 0){
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
begin_op();
|
||||
if ((ip = namei(old)) == 0) {
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ilock(ip);
|
||||
if(ip->type == T_DIR){
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
ilock(ip);
|
||||
if (ip->type == T_DIR) {
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ip->nlink++;
|
||||
iupdate(ip);
|
||||
iunlock(ip);
|
||||
ip->nlink++;
|
||||
iupdate(ip);
|
||||
iunlock(ip);
|
||||
|
||||
if((dp = nameiparent(new, name)) == 0)
|
||||
goto bad;
|
||||
ilock(dp);
|
||||
if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
|
||||
iunlockput(dp);
|
||||
goto bad;
|
||||
}
|
||||
iunlockput(dp);
|
||||
iput(ip);
|
||||
if ((dp = nameiparent(new, name)) == 0)
|
||||
goto bad;
|
||||
ilock(dp);
|
||||
if (dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0) {
|
||||
iunlockput(dp);
|
||||
goto bad;
|
||||
}
|
||||
iunlockput(dp);
|
||||
iput(ip);
|
||||
|
||||
end_op();
|
||||
end_op();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
ilock(ip);
|
||||
ip->nlink--;
|
||||
iupdate(ip);
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
ilock(ip);
|
||||
ip->nlink--;
|
||||
iupdate(ip);
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Is the directory dp empty except for "." and ".." ?
|
||||
static int
|
||||
isdirempty(struct inode *dp)
|
||||
{
|
||||
int off;
|
||||
struct dirent de;
|
||||
static int isdirempty(struct inode *dp) {
|
||||
int off;
|
||||
struct dirent de;
|
||||
|
||||
for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
|
||||
if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
panic("isdirempty: readi");
|
||||
if(de.inum != 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
for (off = 2 * sizeof(de); off < dp->size; off += sizeof(de)) {
|
||||
if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
panic("isdirempty: readi");
|
||||
if (de.inum != 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_unlink(void)
|
||||
{
|
||||
struct inode *ip, *dp;
|
||||
struct dirent de;
|
||||
char name[DIRSIZ], path[MAXPATH];
|
||||
uint off;
|
||||
uint64 sys_unlink(void) {
|
||||
struct inode *ip, *dp;
|
||||
struct dirent de;
|
||||
char name[DIRSIZ], path[MAXPATH];
|
||||
uint off;
|
||||
|
||||
if(argstr(0, path, MAXPATH) < 0)
|
||||
return -1;
|
||||
if (argstr(0, path, MAXPATH) < 0)
|
||||
return -1;
|
||||
|
||||
begin_op();
|
||||
if((dp = nameiparent(path, name)) == 0){
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
begin_op();
|
||||
if ((dp = nameiparent(path, name)) == 0) {
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ilock(dp);
|
||||
ilock(dp);
|
||||
|
||||
// Cannot unlink "." or "..".
|
||||
if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
|
||||
goto bad;
|
||||
// Cannot unlink "." or "..".
|
||||
if (namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
|
||||
goto bad;
|
||||
|
||||
if((ip = dirlookup(dp, name, &off)) == 0)
|
||||
goto bad;
|
||||
ilock(ip);
|
||||
if ((ip = dirlookup(dp, name, &off)) == 0)
|
||||
goto bad;
|
||||
ilock(ip);
|
||||
|
||||
if(ip->nlink < 1)
|
||||
panic("unlink: nlink < 1");
|
||||
if(ip->type == T_DIR && !isdirempty(ip)){
|
||||
iunlockput(ip);
|
||||
goto bad;
|
||||
}
|
||||
if (ip->nlink < 1)
|
||||
panic("unlink: nlink < 1");
|
||||
if (ip->type == T_DIR && !isdirempty(ip)) {
|
||||
iunlockput(ip);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
memset(&de, 0, sizeof(de));
|
||||
if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
panic("unlink: writei");
|
||||
if(ip->type == T_DIR){
|
||||
dp->nlink--;
|
||||
iupdate(dp);
|
||||
}
|
||||
iunlockput(dp);
|
||||
memset(&de, 0, sizeof(de));
|
||||
if (writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
|
||||
panic("unlink: writei");
|
||||
if (ip->type == T_DIR) {
|
||||
dp->nlink--;
|
||||
iupdate(dp);
|
||||
}
|
||||
iunlockput(dp);
|
||||
|
||||
ip->nlink--;
|
||||
iupdate(ip);
|
||||
iunlockput(ip);
|
||||
ip->nlink--;
|
||||
iupdate(ip);
|
||||
iunlockput(ip);
|
||||
|
||||
end_op();
|
||||
end_op();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
iunlockput(dp);
|
||||
end_op();
|
||||
return -1;
|
||||
iunlockput(dp);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct inode*
|
||||
create(char *path, short type, short major, short minor)
|
||||
{
|
||||
struct inode *ip, *dp;
|
||||
char name[DIRSIZ];
|
||||
static struct inode *create(char *path, short type, short major, short minor) {
|
||||
struct inode *ip, *dp;
|
||||
char name[DIRSIZ];
|
||||
|
||||
if((dp = nameiparent(path, name)) == 0)
|
||||
return 0;
|
||||
if ((dp = nameiparent(path, name)) == 0)
|
||||
return 0;
|
||||
|
||||
ilock(dp);
|
||||
ilock(dp);
|
||||
|
||||
if((ip = dirlookup(dp, name, 0)) != 0){
|
||||
iunlockput(dp);
|
||||
ilock(ip);
|
||||
if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
|
||||
return ip;
|
||||
iunlockput(ip);
|
||||
return 0;
|
||||
}
|
||||
if ((ip = dirlookup(dp, name, 0)) != 0) {
|
||||
iunlockput(dp);
|
||||
ilock(ip);
|
||||
if (type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
|
||||
return ip;
|
||||
iunlockput(ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((ip = ialloc(dp->dev, type)) == 0){
|
||||
iunlockput(dp);
|
||||
return 0;
|
||||
}
|
||||
if ((ip = ialloc(dp->dev, type)) == 0) {
|
||||
iunlockput(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ilock(ip);
|
||||
ip->major = major;
|
||||
ip->minor = minor;
|
||||
ip->nlink = 1;
|
||||
iupdate(ip);
|
||||
ilock(ip);
|
||||
ip->major = major;
|
||||
ip->minor = minor;
|
||||
ip->nlink = 1;
|
||||
iupdate(ip);
|
||||
|
||||
if(type == T_DIR){ // Create . and .. entries.
|
||||
// No ip->nlink++ for ".": avoid cyclic ref count.
|
||||
if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
|
||||
goto fail;
|
||||
}
|
||||
if (type == T_DIR) { // Create . and .. entries.
|
||||
// No ip->nlink++ for ".": avoid cyclic ref count.
|
||||
if (dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(dirlink(dp, name, ip->inum) < 0)
|
||||
goto fail;
|
||||
if (dirlink(dp, name, ip->inum) < 0)
|
||||
goto fail;
|
||||
|
||||
if(type == T_DIR){
|
||||
// now that success is guaranteed:
|
||||
dp->nlink++; // for ".."
|
||||
iupdate(dp);
|
||||
}
|
||||
if (type == T_DIR) {
|
||||
// now that success is guaranteed:
|
||||
dp->nlink++; // for ".."
|
||||
iupdate(dp);
|
||||
}
|
||||
|
||||
iunlockput(dp);
|
||||
iunlockput(dp);
|
||||
|
||||
return ip;
|
||||
return ip;
|
||||
|
||||
fail:
|
||||
// something went wrong. de-allocate ip.
|
||||
ip->nlink = 0;
|
||||
iupdate(ip);
|
||||
iunlockput(ip);
|
||||
iunlockput(dp);
|
||||
return 0;
|
||||
fail:
|
||||
// something went wrong. de-allocate ip.
|
||||
ip->nlink = 0;
|
||||
iupdate(ip);
|
||||
iunlockput(ip);
|
||||
iunlockput(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_open(void)
|
||||
{
|
||||
char path[MAXPATH];
|
||||
int fd, omode;
|
||||
struct file *f;
|
||||
struct inode *ip;
|
||||
int n;
|
||||
uint64 sys_open(void) {
|
||||
char path[MAXPATH];
|
||||
int fd, omode;
|
||||
struct file *f;
|
||||
struct inode *ip;
|
||||
int n;
|
||||
|
||||
argint(1, &omode);
|
||||
if((n = argstr(0, path, MAXPATH)) < 0)
|
||||
return -1;
|
||||
argint(1, &omode);
|
||||
if ((n = argstr(0, path, MAXPATH)) < 0)
|
||||
return -1;
|
||||
|
||||
begin_op();
|
||||
begin_op();
|
||||
|
||||
if(omode & O_CREATE){
|
||||
ip = create(path, T_FILE, 0, 0);
|
||||
if(ip == 0){
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if((ip = namei(path)) == 0){
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
ilock(ip);
|
||||
if(ip->type == T_DIR && omode != O_RDONLY){
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (omode & O_CREATE) {
|
||||
ip = create(path, T_FILE, 0, 0);
|
||||
if (ip == 0) {
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if ((ip = namei(path)) == 0) {
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
ilock(ip);
|
||||
if (ip->type == T_DIR && omode != O_RDONLY) {
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
if (ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)) {
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
|
||||
if(f)
|
||||
fileclose(f);
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
if ((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0) {
|
||||
if (f)
|
||||
fileclose(f);
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ip->type == T_DEVICE){
|
||||
f->type = FD_DEVICE;
|
||||
f->major = ip->major;
|
||||
} else {
|
||||
f->type = FD_INODE;
|
||||
f->off = 0;
|
||||
}
|
||||
f->ip = ip;
|
||||
f->readable = !(omode & O_WRONLY);
|
||||
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
|
||||
if (ip->type == T_DEVICE) {
|
||||
f->type = FD_DEVICE;
|
||||
f->major = ip->major;
|
||||
} else {
|
||||
f->type = FD_INODE;
|
||||
f->off = 0;
|
||||
}
|
||||
f->ip = ip;
|
||||
f->readable = !(omode & O_WRONLY);
|
||||
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
|
||||
|
||||
if((omode & O_TRUNC) && ip->type == T_FILE){
|
||||
itrunc(ip);
|
||||
}
|
||||
if ((omode & O_TRUNC) && ip->type == T_FILE) {
|
||||
itrunc(ip);
|
||||
}
|
||||
|
||||
iunlock(ip);
|
||||
end_op();
|
||||
iunlock(ip);
|
||||
end_op();
|
||||
|
||||
return fd;
|
||||
return fd;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_mkdir(void)
|
||||
{
|
||||
char path[MAXPATH];
|
||||
struct inode *ip;
|
||||
uint64 sys_mkdir(void) {
|
||||
char path[MAXPATH];
|
||||
struct inode *ip;
|
||||
|
||||
begin_op();
|
||||
if(argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return 0;
|
||||
begin_op();
|
||||
if (argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0) {
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_mknod(void)
|
||||
{
|
||||
struct inode *ip;
|
||||
char path[MAXPATH];
|
||||
int major, minor;
|
||||
uint64 sys_mknod(void) {
|
||||
struct inode *ip;
|
||||
char path[MAXPATH];
|
||||
int major, minor;
|
||||
|
||||
begin_op();
|
||||
argint(1, &major);
|
||||
argint(2, &minor);
|
||||
if((argstr(0, path, MAXPATH)) < 0 ||
|
||||
(ip = create(path, T_DEVICE, major, minor)) == 0){
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return 0;
|
||||
begin_op();
|
||||
argint(1, &major);
|
||||
argint(2, &minor);
|
||||
if ((argstr(0, path, MAXPATH)) < 0 ||
|
||||
(ip = create(path, T_DEVICE, major, minor)) == 0) {
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_chdir(void)
|
||||
{
|
||||
char path[MAXPATH];
|
||||
struct inode *ip;
|
||||
struct proc *p = myproc();
|
||||
|
||||
begin_op();
|
||||
if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0){
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
ilock(ip);
|
||||
if(ip->type != T_DIR){
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
iunlock(ip);
|
||||
iput(p->cwd);
|
||||
end_op();
|
||||
p->cwd = ip;
|
||||
return 0;
|
||||
uint64 sys_chdir(void) {
|
||||
char path[MAXPATH];
|
||||
struct inode *ip;
|
||||
struct proc *p = myproc();
|
||||
|
||||
begin_op();
|
||||
if (argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0) {
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
ilock(ip);
|
||||
if (ip->type != T_DIR) {
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
iunlock(ip);
|
||||
iput(p->cwd);
|
||||
end_op();
|
||||
p->cwd = ip;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_exec(void)
|
||||
{
|
||||
char path[MAXPATH], *argv[MAXARG];
|
||||
int i;
|
||||
uint64 uargv, uarg;
|
||||
uint64 sys_exec(void) {
|
||||
char path[MAXPATH], *argv[MAXARG];
|
||||
int i;
|
||||
uint64 uargv, uarg;
|
||||
|
||||
argaddr(1, &uargv);
|
||||
if(argstr(0, path, MAXPATH) < 0) {
|
||||
return -1;
|
||||
}
|
||||
memset(argv, 0, sizeof(argv));
|
||||
for(i=0;; i++){
|
||||
if(i >= NELEM(argv)){
|
||||
goto bad;
|
||||
}
|
||||
if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){
|
||||
goto bad;
|
||||
}
|
||||
if(uarg == 0){
|
||||
argv[i] = 0;
|
||||
break;
|
||||
}
|
||||
argv[i] = kalloc();
|
||||
if(argv[i] == 0)
|
||||
goto bad;
|
||||
if(fetchstr(uarg, argv[i], PGSIZE) < 0)
|
||||
goto bad;
|
||||
}
|
||||
argaddr(1, &uargv);
|
||||
if (argstr(0, path, MAXPATH) < 0) {
|
||||
return -1;
|
||||
}
|
||||
memset(argv, 0, sizeof(argv));
|
||||
for (i = 0;; i++) {
|
||||
if (i >= NELEM(argv)) {
|
||||
goto bad;
|
||||
}
|
||||
if (fetchaddr(uargv + sizeof(uint64) * i, (uint64 *)&uarg) < 0) {
|
||||
goto bad;
|
||||
}
|
||||
if (uarg == 0) {
|
||||
argv[i] = 0;
|
||||
break;
|
||||
}
|
||||
argv[i] = kalloc();
|
||||
if (argv[i] == 0)
|
||||
goto bad;
|
||||
if (fetchstr(uarg, argv[i], PGSIZE) < 0)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
int ret = exec(path, argv);
|
||||
int ret = exec(path, argv);
|
||||
|
||||
for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
|
||||
kfree(argv[i]);
|
||||
for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
|
||||
kfree(argv[i]);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
|
||||
bad:
|
||||
for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
|
||||
kfree(argv[i]);
|
||||
return -1;
|
||||
bad:
|
||||
for (i = 0; i < NELEM(argv) && argv[i] != 0; i++)
|
||||
kfree(argv[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_pipe(void)
|
||||
{
|
||||
uint64 fdarray; // user pointer to array of two integers
|
||||
struct file *rf, *wf;
|
||||
int fd0, fd1;
|
||||
struct proc *p = myproc();
|
||||
uint64 sys_pipe(void) {
|
||||
uint64 fdarray; // user pointer to array of two integers
|
||||
struct file *rf, *wf;
|
||||
int fd0, fd1;
|
||||
struct proc *p = myproc();
|
||||
|
||||
argaddr(0, &fdarray);
|
||||
if(pipealloc(&rf, &wf) < 0)
|
||||
return -1;
|
||||
fd0 = -1;
|
||||
if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
|
||||
if(fd0 >= 0)
|
||||
p->ofile[fd0] = 0;
|
||||
fileclose(rf);
|
||||
fileclose(wf);
|
||||
return -1;
|
||||
}
|
||||
if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 ||
|
||||
copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){
|
||||
p->ofile[fd0] = 0;
|
||||
p->ofile[fd1] = 0;
|
||||
fileclose(rf);
|
||||
fileclose(wf);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
argaddr(0, &fdarray);
|
||||
if (pipealloc(&rf, &wf) < 0)
|
||||
return -1;
|
||||
fd0 = -1;
|
||||
if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) {
|
||||
if (fd0 >= 0)
|
||||
p->ofile[fd0] = 0;
|
||||
fileclose(rf);
|
||||
fileclose(wf);
|
||||
return -1;
|
||||
}
|
||||
if (copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(fd0)) < 0 ||
|
||||
copyout(p->pagetable, fdarray + sizeof(fd0), (char *)&fd1,
|
||||
sizeof(fd1)) < 0) {
|
||||
p->ofile[fd0] = 0;
|
||||
p->ofile[fd1] = 0;
|
||||
fileclose(rf);
|
||||
fileclose(wf);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
116
kernel/sysproc.c
116
kernel/sysproc.c
|
|
@ -6,86 +6,66 @@
|
|||
#include "spinlock.h"
|
||||
#include "proc.h"
|
||||
|
||||
uint64
|
||||
sys_exit(void)
|
||||
{
|
||||
int n;
|
||||
argint(0, &n);
|
||||
exit(n);
|
||||
return 0; // not reached
|
||||
uint64 sys_exit(void) {
|
||||
int n;
|
||||
argint(0, &n);
|
||||
exit(n);
|
||||
return 0; // not reached
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_getpid(void)
|
||||
{
|
||||
return myproc()->pid;
|
||||
uint64 sys_getpid(void) { return myproc()->pid; }
|
||||
|
||||
uint64 sys_fork(void) { return fork(); }
|
||||
|
||||
uint64 sys_wait(void) {
|
||||
uint64 p;
|
||||
argaddr(0, &p);
|
||||
return wait(p);
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_fork(void)
|
||||
{
|
||||
return fork();
|
||||
uint64 sys_sbrk(void) {
|
||||
uint64 addr;
|
||||
int n;
|
||||
|
||||
argint(0, &n);
|
||||
addr = myproc()->sz;
|
||||
if (growproc(n) < 0)
|
||||
return -1;
|
||||
return addr;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_wait(void)
|
||||
{
|
||||
uint64 p;
|
||||
argaddr(0, &p);
|
||||
return wait(p);
|
||||
uint64 sys_sleep(void) {
|
||||
int n;
|
||||
uint ticks0;
|
||||
|
||||
argint(0, &n);
|
||||
acquire(&tickslock);
|
||||
ticks0 = ticks;
|
||||
while (ticks - ticks0 < n) {
|
||||
if (killed(myproc())) {
|
||||
release(&tickslock);
|
||||
return -1;
|
||||
}
|
||||
sleep(&ticks, &tickslock);
|
||||
}
|
||||
release(&tickslock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_sbrk(void)
|
||||
{
|
||||
uint64 addr;
|
||||
int n;
|
||||
uint64 sys_kill(void) {
|
||||
int pid;
|
||||
|
||||
argint(0, &n);
|
||||
addr = myproc()->sz;
|
||||
if(growproc(n) < 0)
|
||||
return -1;
|
||||
return addr;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_sleep(void)
|
||||
{
|
||||
int n;
|
||||
uint ticks0;
|
||||
|
||||
argint(0, &n);
|
||||
acquire(&tickslock);
|
||||
ticks0 = ticks;
|
||||
while(ticks - ticks0 < n){
|
||||
if(killed(myproc())){
|
||||
release(&tickslock);
|
||||
return -1;
|
||||
}
|
||||
sleep(&ticks, &tickslock);
|
||||
}
|
||||
release(&tickslock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_kill(void)
|
||||
{
|
||||
int pid;
|
||||
|
||||
argint(0, &pid);
|
||||
return kill(pid);
|
||||
argint(0, &pid);
|
||||
return kill(pid);
|
||||
}
|
||||
|
||||
// return how many clock tick interrupts have occurred
|
||||
// since start.
|
||||
uint64
|
||||
sys_uptime(void)
|
||||
{
|
||||
uint xticks;
|
||||
uint64 sys_uptime(void) {
|
||||
uint xticks;
|
||||
|
||||
acquire(&tickslock);
|
||||
xticks = ticks;
|
||||
release(&tickslock);
|
||||
return xticks;
|
||||
acquire(&tickslock);
|
||||
xticks = ticks;
|
||||
release(&tickslock);
|
||||
return xticks;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,9 +80,18 @@ uservec:
|
|||
# load the address of usertrap(), from p->trapframe->kernel_trap
|
||||
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)
|
||||
|
||||
# wait for any previous memory operations to complete, so that
|
||||
# they use the user page table.
|
||||
sfence.vma zero, zero
|
||||
|
||||
# install the kernel page table.
|
||||
csrw satp, t1
|
||||
|
||||
# flush now-stale user entries from the TLB.
|
||||
sfence.vma zero, zero
|
||||
|
||||
# jump to usertrap(), which does not return
|
||||
|
|
@ -96,6 +105,7 @@ userret:
|
|||
# a0: user page table, for satp.
|
||||
|
||||
# switch to the user page table.
|
||||
sfence.vma zero, zero
|
||||
csrw satp, a0
|
||||
sfence.vma zero, zero
|
||||
|
||||
|
|
|
|||
280
kernel/trap.c
280
kernel/trap.c
|
|
@ -16,157 +16,141 @@ void kernelvec();
|
|||
|
||||
extern int devintr();
|
||||
|
||||
void
|
||||
trapinit(void)
|
||||
{
|
||||
initlock(&tickslock, "time");
|
||||
}
|
||||
void trapinit(void) { initlock(&tickslock, "time"); }
|
||||
|
||||
// set up to take exceptions and traps while in the kernel.
|
||||
void
|
||||
trapinithart(void)
|
||||
{
|
||||
w_stvec((uint64)kernelvec);
|
||||
}
|
||||
void trapinithart(void) { w_stvec((uint64)kernelvec); }
|
||||
|
||||
//
|
||||
// handle an interrupt, exception, or system call from user space.
|
||||
// called from trampoline.S
|
||||
//
|
||||
void
|
||||
usertrap(void)
|
||||
{
|
||||
int which_dev = 0;
|
||||
void usertrap(void) {
|
||||
int which_dev = 0;
|
||||
|
||||
if((r_sstatus() & SSTATUS_SPP) != 0)
|
||||
panic("usertrap: not from user mode");
|
||||
if ((r_sstatus() & SSTATUS_SPP) != 0)
|
||||
panic("usertrap: not from user mode");
|
||||
|
||||
// send interrupts and exceptions to kerneltrap(),
|
||||
// since we're now in the kernel.
|
||||
w_stvec((uint64)kernelvec);
|
||||
// send interrupts and exceptions to kerneltrap(),
|
||||
// since we're now in the kernel.
|
||||
w_stvec((uint64)kernelvec);
|
||||
|
||||
struct proc *p = myproc();
|
||||
|
||||
// save user program counter.
|
||||
p->trapframe->epc = r_sepc();
|
||||
|
||||
if(r_scause() == 8){
|
||||
// system call
|
||||
struct proc *p = myproc();
|
||||
|
||||
if(killed(p))
|
||||
exit(-1);
|
||||
// save user program counter.
|
||||
p->trapframe->epc = r_sepc();
|
||||
|
||||
// sepc points to the ecall instruction,
|
||||
// but we want to return to the next instruction.
|
||||
p->trapframe->epc += 4;
|
||||
if (r_scause() == 8) {
|
||||
// system call
|
||||
|
||||
// an interrupt will change sepc, scause, and sstatus,
|
||||
// so enable only now that we're done with those registers.
|
||||
intr_on();
|
||||
if (killed(p))
|
||||
exit(-1);
|
||||
|
||||
syscall();
|
||||
} else if((which_dev = devintr()) != 0){
|
||||
// ok
|
||||
} else {
|
||||
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
|
||||
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
|
||||
setkilled(p);
|
||||
}
|
||||
// sepc points to the ecall instruction,
|
||||
// but we want to return to the next instruction.
|
||||
p->trapframe->epc += 4;
|
||||
|
||||
if(killed(p))
|
||||
exit(-1);
|
||||
// an interrupt will change sepc, scause, and sstatus,
|
||||
// so enable only now that we're done with those registers.
|
||||
intr_on();
|
||||
|
||||
// give up the CPU if this is a timer interrupt.
|
||||
if(which_dev == 2)
|
||||
yield();
|
||||
syscall();
|
||||
} else if ((which_dev = devintr()) != 0) {
|
||||
// ok
|
||||
} else {
|
||||
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
|
||||
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
|
||||
setkilled(p);
|
||||
}
|
||||
|
||||
usertrapret();
|
||||
if (killed(p))
|
||||
exit(-1);
|
||||
|
||||
// give up the CPU if this is a timer interrupt.
|
||||
if (which_dev == 2)
|
||||
yield();
|
||||
|
||||
usertrapret();
|
||||
}
|
||||
|
||||
//
|
||||
// return to user space
|
||||
//
|
||||
void
|
||||
usertrapret(void)
|
||||
{
|
||||
struct proc *p = myproc();
|
||||
void usertrapret(void) {
|
||||
struct proc *p = myproc();
|
||||
|
||||
// we're about to switch the destination of traps from
|
||||
// kerneltrap() to usertrap(), so turn off interrupts until
|
||||
// we're back in user space, where usertrap() is correct.
|
||||
intr_off();
|
||||
// we're about to switch the destination of traps from
|
||||
// kerneltrap() to usertrap(), so turn off interrupts until
|
||||
// we're back in user space, where usertrap() is correct.
|
||||
intr_off();
|
||||
|
||||
// send syscalls, interrupts, and exceptions to uservec in trampoline.S
|
||||
uint64 trampoline_uservec = TRAMPOLINE + (uservec - trampoline);
|
||||
w_stvec(trampoline_uservec);
|
||||
// send syscalls, interrupts, and exceptions to uservec in trampoline.S
|
||||
uint64 trampoline_uservec = TRAMPOLINE + (uservec - trampoline);
|
||||
w_stvec(trampoline_uservec);
|
||||
|
||||
// set up trapframe values that uservec will need when
|
||||
// the process next traps into the kernel.
|
||||
p->trapframe->kernel_satp = r_satp(); // kernel page table
|
||||
p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack
|
||||
p->trapframe->kernel_trap = (uint64)usertrap;
|
||||
p->trapframe->kernel_hartid = r_tp(); // hartid for cpuid()
|
||||
// set up trapframe values that uservec will need when
|
||||
// the process next traps into the kernel.
|
||||
p->trapframe->kernel_satp = r_satp(); // kernel page table
|
||||
p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack
|
||||
p->trapframe->kernel_trap = (uint64)usertrap;
|
||||
p->trapframe->kernel_hartid = r_tp(); // hartid for cpuid()
|
||||
|
||||
// set up the registers that trampoline.S's sret will use
|
||||
// to get to user space.
|
||||
|
||||
// set S Previous Privilege mode to User.
|
||||
unsigned long x = r_sstatus();
|
||||
x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
|
||||
x |= SSTATUS_SPIE; // enable interrupts in user mode
|
||||
w_sstatus(x);
|
||||
// set up the registers that trampoline.S's sret will use
|
||||
// to get to user space.
|
||||
|
||||
// set S Exception Program Counter to the saved user pc.
|
||||
w_sepc(p->trapframe->epc);
|
||||
// set S Previous Privilege mode to User.
|
||||
unsigned long x = r_sstatus();
|
||||
x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
|
||||
x |= SSTATUS_SPIE; // enable interrupts in user mode
|
||||
w_sstatus(x);
|
||||
|
||||
// tell trampoline.S the user page table to switch to.
|
||||
uint64 satp = MAKE_SATP(p->pagetable);
|
||||
// set S Exception Program Counter to the saved user pc.
|
||||
w_sepc(p->trapframe->epc);
|
||||
|
||||
// jump to userret in trampoline.S at the top of memory, which
|
||||
// switches to the user page table, restores user registers,
|
||||
// and switches to user mode with sret.
|
||||
uint64 trampoline_userret = TRAMPOLINE + (userret - trampoline);
|
||||
((void (*)(uint64))trampoline_userret)(satp);
|
||||
// tell trampoline.S the user page table to switch to.
|
||||
uint64 satp = MAKE_SATP(p->pagetable);
|
||||
|
||||
// jump to userret in trampoline.S at the top of memory, which
|
||||
// switches to the user page table, restores user registers,
|
||||
// and switches to user mode with sret.
|
||||
uint64 trampoline_userret = TRAMPOLINE + (userret - trampoline);
|
||||
((void (*)(uint64))trampoline_userret)(satp);
|
||||
}
|
||||
|
||||
// interrupts and exceptions from kernel code go here via kernelvec,
|
||||
// on whatever the current kernel stack is.
|
||||
void
|
||||
kerneltrap()
|
||||
{
|
||||
int which_dev = 0;
|
||||
uint64 sepc = r_sepc();
|
||||
uint64 sstatus = r_sstatus();
|
||||
uint64 scause = r_scause();
|
||||
|
||||
if((sstatus & SSTATUS_SPP) == 0)
|
||||
panic("kerneltrap: not from supervisor mode");
|
||||
if(intr_get() != 0)
|
||||
panic("kerneltrap: interrupts enabled");
|
||||
void kerneltrap() {
|
||||
int which_dev = 0;
|
||||
uint64 sepc = r_sepc();
|
||||
uint64 sstatus = r_sstatus();
|
||||
uint64 scause = r_scause();
|
||||
|
||||
if((which_dev = devintr()) == 0){
|
||||
printf("scause %p\n", scause);
|
||||
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
|
||||
panic("kerneltrap");
|
||||
}
|
||||
if ((sstatus & SSTATUS_SPP) == 0)
|
||||
panic("kerneltrap: not from supervisor mode");
|
||||
if (intr_get() != 0)
|
||||
panic("kerneltrap: interrupts enabled");
|
||||
|
||||
// give up the CPU if this is a timer interrupt.
|
||||
if(which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING)
|
||||
yield();
|
||||
if ((which_dev = devintr()) == 0) {
|
||||
printf("scause %p\n", scause);
|
||||
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
|
||||
panic("kerneltrap");
|
||||
}
|
||||
|
||||
// the yield() may have caused some traps to occur,
|
||||
// so restore trap registers for use by kernelvec.S's sepc instruction.
|
||||
w_sepc(sepc);
|
||||
w_sstatus(sstatus);
|
||||
// give up the CPU if this is a timer interrupt.
|
||||
if (which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING)
|
||||
yield();
|
||||
|
||||
// the yield() may have caused some traps to occur,
|
||||
// so restore trap registers for use by kernelvec.S's sepc instruction.
|
||||
w_sepc(sepc);
|
||||
w_sstatus(sstatus);
|
||||
}
|
||||
|
||||
void
|
||||
clockintr()
|
||||
{
|
||||
acquire(&tickslock);
|
||||
ticks++;
|
||||
wakeup(&ticks);
|
||||
release(&tickslock);
|
||||
void clockintr() {
|
||||
acquire(&tickslock);
|
||||
ticks++;
|
||||
wakeup(&ticks);
|
||||
release(&tickslock);
|
||||
}
|
||||
|
||||
// check if it's an external interrupt or software interrupt,
|
||||
|
|
@ -174,48 +158,44 @@ clockintr()
|
|||
// returns 2 if timer interrupt,
|
||||
// 1 if other device,
|
||||
// 0 if not recognized.
|
||||
int
|
||||
devintr()
|
||||
{
|
||||
uint64 scause = r_scause();
|
||||
int devintr() {
|
||||
uint64 scause = r_scause();
|
||||
|
||||
if((scause & 0x8000000000000000L) &&
|
||||
(scause & 0xff) == 9){
|
||||
// this is a supervisor external interrupt, via PLIC.
|
||||
if ((scause & 0x8000000000000000L) && (scause & 0xff) == 9) {
|
||||
// this is a supervisor external interrupt, via PLIC.
|
||||
|
||||
// irq indicates which device interrupted.
|
||||
int irq = plic_claim();
|
||||
// irq indicates which device interrupted.
|
||||
int irq = plic_claim();
|
||||
|
||||
if(irq == UART0_IRQ){
|
||||
uartintr();
|
||||
} else if(irq == VIRTIO0_IRQ){
|
||||
virtio_disk_intr();
|
||||
} else if(irq){
|
||||
printf("unexpected interrupt irq=%d\n", irq);
|
||||
}
|
||||
if (irq == UART0_IRQ) {
|
||||
uartintr();
|
||||
} else if (irq == VIRTIO0_IRQ) {
|
||||
virtio_disk_intr();
|
||||
} else if (irq) {
|
||||
printf("unexpected interrupt irq=%d\n", irq);
|
||||
}
|
||||
|
||||
// the PLIC allows each device to raise at most one
|
||||
// interrupt at a time; tell the PLIC the device is
|
||||
// now allowed to interrupt again.
|
||||
if(irq)
|
||||
plic_complete(irq);
|
||||
// the PLIC allows each device to raise at most one
|
||||
// interrupt at a time; tell the PLIC the device is
|
||||
// now allowed to interrupt again.
|
||||
if (irq)
|
||||
plic_complete(irq);
|
||||
|
||||
return 1;
|
||||
} else if(scause == 0x8000000000000001L){
|
||||
// software interrupt from a machine-mode timer interrupt,
|
||||
// forwarded by timervec in kernelvec.S.
|
||||
return 1;
|
||||
} else if (scause == 0x8000000000000001L) {
|
||||
// software interrupt from a machine-mode timer interrupt,
|
||||
// forwarded by timervec in kernelvec.S.
|
||||
|
||||
if(cpuid() == 0){
|
||||
clockintr();
|
||||
}
|
||||
|
||||
// acknowledge the software interrupt by clearing
|
||||
// the SSIP bit in sip.
|
||||
w_sip(r_sip() & ~2);
|
||||
if (cpuid() == 0) {
|
||||
clockintr();
|
||||
}
|
||||
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
// acknowledge the software interrupt by clearing
|
||||
// the SSIP bit in sip.
|
||||
w_sip(r_sip() & ~2);
|
||||
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
213
kernel/uart.c
213
kernel/uart.c
|
|
@ -19,21 +19,21 @@
|
|||
// some have different meanings for
|
||||
// read vs write.
|
||||
// see http://byterunner.com/16550.html
|
||||
#define RHR 0 // receive holding register (for input bytes)
|
||||
#define THR 0 // transmit holding register (for output bytes)
|
||||
#define IER 1 // interrupt enable register
|
||||
#define IER_RX_ENABLE (1<<0)
|
||||
#define IER_TX_ENABLE (1<<1)
|
||||
#define FCR 2 // FIFO control register
|
||||
#define FCR_FIFO_ENABLE (1<<0)
|
||||
#define FCR_FIFO_CLEAR (3<<1) // clear the content of the two FIFOs
|
||||
#define ISR 2 // interrupt status register
|
||||
#define LCR 3 // line control register
|
||||
#define LCR_EIGHT_BITS (3<<0)
|
||||
#define LCR_BAUD_LATCH (1<<7) // special mode to set baud rate
|
||||
#define LSR 5 // line status register
|
||||
#define LSR_RX_READY (1<<0) // input is waiting to be read from RHR
|
||||
#define LSR_TX_IDLE (1<<5) // THR can accept another character to send
|
||||
#define RHR 0 // receive holding register (for input bytes)
|
||||
#define THR 0 // transmit holding register (for output bytes)
|
||||
#define IER 1 // interrupt enable register
|
||||
#define IER_RX_ENABLE (1 << 0)
|
||||
#define IER_TX_ENABLE (1 << 1)
|
||||
#define FCR 2 // FIFO control register
|
||||
#define FCR_FIFO_ENABLE (1 << 0)
|
||||
#define FCR_FIFO_CLEAR (3 << 1) // clear the content of the two FIFOs
|
||||
#define ISR 2 // interrupt status register
|
||||
#define LCR 3 // line control register
|
||||
#define LCR_EIGHT_BITS (3 << 0)
|
||||
#define LCR_BAUD_LATCH (1 << 7) // special mode to set baud rate
|
||||
#define LSR 5 // line status register
|
||||
#define LSR_RX_READY (1 << 0) // input is waiting to be read from RHR
|
||||
#define LSR_TX_IDLE (1 << 5) // THR can accept another character to send
|
||||
|
||||
#define ReadReg(reg) (*(Reg(reg)))
|
||||
#define WriteReg(reg, v) (*(Reg(reg)) = (v))
|
||||
|
|
@ -49,32 +49,30 @@ extern volatile int panicked; // from printf.c
|
|||
|
||||
void uartstart();
|
||||
|
||||
void
|
||||
uartinit(void)
|
||||
{
|
||||
// disable interrupts.
|
||||
WriteReg(IER, 0x00);
|
||||
void uartinit(void) {
|
||||
// disable interrupts.
|
||||
WriteReg(IER, 0x00);
|
||||
|
||||
// special mode to set baud rate.
|
||||
WriteReg(LCR, LCR_BAUD_LATCH);
|
||||
// special mode to set baud rate.
|
||||
WriteReg(LCR, LCR_BAUD_LATCH);
|
||||
|
||||
// LSB for baud rate of 38.4K.
|
||||
WriteReg(0, 0x03);
|
||||
// LSB for baud rate of 38.4K.
|
||||
WriteReg(0, 0x03);
|
||||
|
||||
// MSB for baud rate of 38.4K.
|
||||
WriteReg(1, 0x00);
|
||||
// MSB for baud rate of 38.4K.
|
||||
WriteReg(1, 0x00);
|
||||
|
||||
// leave set-baud mode,
|
||||
// and set word length to 8 bits, no parity.
|
||||
WriteReg(LCR, LCR_EIGHT_BITS);
|
||||
// leave set-baud mode,
|
||||
// and set word length to 8 bits, no parity.
|
||||
WriteReg(LCR, LCR_EIGHT_BITS);
|
||||
|
||||
// reset and enable FIFOs.
|
||||
WriteReg(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
|
||||
// reset and enable FIFOs.
|
||||
WriteReg(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
|
||||
|
||||
// enable transmit and receive interrupts.
|
||||
WriteReg(IER, IER_TX_ENABLE | IER_RX_ENABLE);
|
||||
// enable transmit and receive interrupts.
|
||||
WriteReg(IER, IER_TX_ENABLE | IER_RX_ENABLE);
|
||||
|
||||
initlock(&uart_tx_lock, "uart");
|
||||
initlock(&uart_tx_lock, "uart");
|
||||
}
|
||||
|
||||
// add a character to the output buffer and tell the
|
||||
|
|
@ -83,108 +81,97 @@ uartinit(void)
|
|||
// because it may block, it can't be called
|
||||
// from interrupts; it's only suitable for use
|
||||
// by write().
|
||||
void
|
||||
uartputc(int c)
|
||||
{
|
||||
acquire(&uart_tx_lock);
|
||||
void uartputc(int c) {
|
||||
acquire(&uart_tx_lock);
|
||||
|
||||
if(panicked){
|
||||
for(;;)
|
||||
;
|
||||
}
|
||||
while(uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE){
|
||||
// buffer is full.
|
||||
// wait for uartstart() to open up space in the buffer.
|
||||
sleep(&uart_tx_r, &uart_tx_lock);
|
||||
}
|
||||
uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE] = c;
|
||||
uart_tx_w += 1;
|
||||
uartstart();
|
||||
release(&uart_tx_lock);
|
||||
if (panicked) {
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
while (uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE) {
|
||||
// buffer is full.
|
||||
// wait for uartstart() to open up space in the buffer.
|
||||
sleep(&uart_tx_r, &uart_tx_lock);
|
||||
}
|
||||
uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE] = c;
|
||||
uart_tx_w += 1;
|
||||
uartstart();
|
||||
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
|
||||
// to echo characters. it spins waiting for the uart's
|
||||
// output register to be empty.
|
||||
void
|
||||
uartputc_sync(int c)
|
||||
{
|
||||
push_off();
|
||||
void uartputc_sync(int c) {
|
||||
push_off();
|
||||
|
||||
if(panicked){
|
||||
for(;;)
|
||||
;
|
||||
}
|
||||
if (panicked) {
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
// wait for Transmit Holding Empty to be set in LSR.
|
||||
while((ReadReg(LSR) & LSR_TX_IDLE) == 0)
|
||||
;
|
||||
WriteReg(THR, c);
|
||||
// wait for Transmit Holding Empty to be set in LSR.
|
||||
while ((ReadReg(LSR) & LSR_TX_IDLE) == 0)
|
||||
;
|
||||
WriteReg(THR, c);
|
||||
|
||||
pop_off();
|
||||
pop_off();
|
||||
}
|
||||
|
||||
// if the UART is idle, and a character is waiting
|
||||
// in the transmit buffer, send it.
|
||||
// caller must hold uart_tx_lock.
|
||||
// called from both the top- and bottom-half.
|
||||
void
|
||||
uartstart()
|
||||
{
|
||||
while(1){
|
||||
if(uart_tx_w == uart_tx_r){
|
||||
// transmit buffer is empty.
|
||||
return;
|
||||
}
|
||||
|
||||
if((ReadReg(LSR) & LSR_TX_IDLE) == 0){
|
||||
// the UART transmit holding register is full,
|
||||
// so we cannot give it another byte.
|
||||
// it will interrupt when it's ready for a new byte.
|
||||
return;
|
||||
}
|
||||
|
||||
int c = uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE];
|
||||
uart_tx_r += 1;
|
||||
|
||||
// maybe uartputc() is waiting for space in the buffer.
|
||||
wakeup(&uart_tx_r);
|
||||
|
||||
WriteReg(THR, c);
|
||||
}
|
||||
void uartstart() {
|
||||
while (1) {
|
||||
if (uart_tx_w == uart_tx_r) {
|
||||
// transmit buffer is empty.
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ReadReg(LSR) & LSR_TX_IDLE) == 0) {
|
||||
// the UART transmit holding register is full,
|
||||
// so we cannot give it another byte.
|
||||
// it will interrupt when it's ready for a new byte.
|
||||
return;
|
||||
}
|
||||
|
||||
int c = uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE];
|
||||
uart_tx_r += 1;
|
||||
|
||||
// maybe uartputc() is waiting for space in the buffer.
|
||||
wakeup(&uart_tx_r);
|
||||
|
||||
WriteReg(THR, c);
|
||||
}
|
||||
}
|
||||
|
||||
// read one input character from the UART.
|
||||
// return -1 if none is waiting.
|
||||
int
|
||||
uartgetc(void)
|
||||
{
|
||||
if(ReadReg(LSR) & 0x01){
|
||||
// input data is ready.
|
||||
return ReadReg(RHR);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
int uartgetc(void) {
|
||||
if (ReadReg(LSR) & 0x01) {
|
||||
// input data is ready.
|
||||
return ReadReg(RHR);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// handle a uart interrupt, raised because input has
|
||||
// arrived, or the uart is ready for more output, or
|
||||
// both. called from devintr().
|
||||
void
|
||||
uartintr(void)
|
||||
{
|
||||
// read and process incoming characters.
|
||||
while(1){
|
||||
int c = uartgetc();
|
||||
if(c == -1)
|
||||
break;
|
||||
consoleintr(c);
|
||||
}
|
||||
void uartintr(void) {
|
||||
// read and process incoming characters.
|
||||
while (1) {
|
||||
int c = uartgetc();
|
||||
if (c == -1)
|
||||
break;
|
||||
consoleintr(c);
|
||||
}
|
||||
|
||||
// send buffered characters.
|
||||
acquire(&uart_tx_lock);
|
||||
uartstart();
|
||||
release(&uart_tx_lock);
|
||||
// send buffered characters.
|
||||
acquire(&uart_tx_lock);
|
||||
uartstart();
|
||||
release(&uart_tx_lock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
// driver for qemu's virtio disk device.
|
||||
// uses qemu's mmio interface to virtio.
|
||||
//
|
||||
// qemu ... -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
|
||||
// qemu ... -drive file=fs.img,if=none,format=raw,id=x0 -device
|
||||
// virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
|
||||
//
|
||||
|
||||
#include "types.h"
|
||||
|
|
@ -20,308 +21,293 @@
|
|||
#define R(r) ((volatile uint32 *)(VIRTIO0 + (r)))
|
||||
|
||||
static struct disk {
|
||||
// a set (not a ring) of DMA descriptors, with which the
|
||||
// driver tells the device where to read and write individual
|
||||
// disk operations. there are NUM descriptors.
|
||||
// most commands consist of a "chain" (a linked list) of a couple of
|
||||
// these descriptors.
|
||||
struct virtq_desc *desc;
|
||||
// a set (not a ring) of DMA descriptors, with which the
|
||||
// driver tells the device where to read and write individual
|
||||
// disk operations. there are NUM descriptors.
|
||||
// most commands consist of a "chain" (a linked list) of a couple of
|
||||
// these descriptors.
|
||||
struct virtq_desc *desc;
|
||||
|
||||
// a ring in which the driver writes descriptor numbers
|
||||
// that the driver would like the device to process. it only
|
||||
// includes the head descriptor of each chain. the ring has
|
||||
// NUM elements.
|
||||
struct virtq_avail *avail;
|
||||
// a ring in which the driver writes descriptor numbers
|
||||
// that the driver would like the device to process. it only
|
||||
// includes the head descriptor of each chain. the ring has
|
||||
// NUM elements.
|
||||
struct virtq_avail *avail;
|
||||
|
||||
// a ring in which the device writes descriptor numbers that
|
||||
// the device has finished processing (just the head of each chain).
|
||||
// there are NUM used ring entries.
|
||||
struct virtq_used *used;
|
||||
// a ring in which the device writes descriptor numbers that
|
||||
// the device has finished processing (just the head of each chain).
|
||||
// there are NUM used ring entries.
|
||||
struct virtq_used *used;
|
||||
|
||||
// our own book-keeping.
|
||||
char free[NUM]; // is a descriptor free?
|
||||
uint16 used_idx; // we've looked this far in used[2..NUM].
|
||||
// our own book-keeping.
|
||||
char free[NUM]; // is a descriptor free?
|
||||
uint16 used_idx; // we've looked this far in used[2..NUM].
|
||||
|
||||
// track info about in-flight operations,
|
||||
// for use when completion interrupt arrives.
|
||||
// indexed by first descriptor index of chain.
|
||||
struct {
|
||||
struct buf *b;
|
||||
char status;
|
||||
} info[NUM];
|
||||
// track info about in-flight operations,
|
||||
// for use when completion interrupt arrives.
|
||||
// indexed by first descriptor index of chain.
|
||||
struct {
|
||||
struct buf *b;
|
||||
char status;
|
||||
} info[NUM];
|
||||
|
||||
// disk command headers.
|
||||
// one-for-one with descriptors, for convenience.
|
||||
struct virtio_blk_req ops[NUM];
|
||||
|
||||
struct spinlock vdisk_lock;
|
||||
|
||||
// disk command headers.
|
||||
// one-for-one with descriptors, for convenience.
|
||||
struct virtio_blk_req ops[NUM];
|
||||
|
||||
struct spinlock vdisk_lock;
|
||||
|
||||
} disk;
|
||||
|
||||
void
|
||||
virtio_disk_init(void)
|
||||
{
|
||||
uint32 status = 0;
|
||||
void virtio_disk_init(void) {
|
||||
uint32 status = 0;
|
||||
|
||||
initlock(&disk.vdisk_lock, "virtio_disk");
|
||||
initlock(&disk.vdisk_lock, "virtio_disk");
|
||||
|
||||
if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
|
||||
*R(VIRTIO_MMIO_VERSION) != 2 ||
|
||||
*R(VIRTIO_MMIO_DEVICE_ID) != 2 ||
|
||||
*R(VIRTIO_MMIO_VENDOR_ID) != 0x554d4551){
|
||||
panic("could not find virtio disk");
|
||||
}
|
||||
|
||||
// reset device
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
if (*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
|
||||
*R(VIRTIO_MMIO_VERSION) != 2 || *R(VIRTIO_MMIO_DEVICE_ID) != 2 ||
|
||||
*R(VIRTIO_MMIO_VENDOR_ID) != 0x554d4551) {
|
||||
panic("could not find virtio disk");
|
||||
}
|
||||
|
||||
// set ACKNOWLEDGE status bit
|
||||
status |= VIRTIO_CONFIG_S_ACKNOWLEDGE;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
// reset device
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
|
||||
// set DRIVER status bit
|
||||
status |= VIRTIO_CONFIG_S_DRIVER;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
// set ACKNOWLEDGE status bit
|
||||
status |= VIRTIO_CONFIG_S_ACKNOWLEDGE;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
|
||||
// negotiate features
|
||||
uint64 features = *R(VIRTIO_MMIO_DEVICE_FEATURES);
|
||||
features &= ~(1 << VIRTIO_BLK_F_RO);
|
||||
features &= ~(1 << VIRTIO_BLK_F_SCSI);
|
||||
features &= ~(1 << VIRTIO_BLK_F_CONFIG_WCE);
|
||||
features &= ~(1 << VIRTIO_BLK_F_MQ);
|
||||
features &= ~(1 << VIRTIO_F_ANY_LAYOUT);
|
||||
features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
|
||||
features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
|
||||
*R(VIRTIO_MMIO_DRIVER_FEATURES) = features;
|
||||
// set DRIVER status bit
|
||||
status |= VIRTIO_CONFIG_S_DRIVER;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
|
||||
// tell device that feature negotiation is complete.
|
||||
status |= VIRTIO_CONFIG_S_FEATURES_OK;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
// negotiate features
|
||||
uint64 features = *R(VIRTIO_MMIO_DEVICE_FEATURES);
|
||||
features &= ~(1 << VIRTIO_BLK_F_RO);
|
||||
features &= ~(1 << VIRTIO_BLK_F_SCSI);
|
||||
features &= ~(1 << VIRTIO_BLK_F_CONFIG_WCE);
|
||||
features &= ~(1 << VIRTIO_BLK_F_MQ);
|
||||
features &= ~(1 << VIRTIO_F_ANY_LAYOUT);
|
||||
features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
|
||||
features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
|
||||
*R(VIRTIO_MMIO_DRIVER_FEATURES) = features;
|
||||
|
||||
// re-read status to ensure FEATURES_OK is set.
|
||||
status = *R(VIRTIO_MMIO_STATUS);
|
||||
if(!(status & VIRTIO_CONFIG_S_FEATURES_OK))
|
||||
panic("virtio disk FEATURES_OK unset");
|
||||
// tell device that feature negotiation is complete.
|
||||
status |= VIRTIO_CONFIG_S_FEATURES_OK;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
|
||||
// initialize queue 0.
|
||||
*R(VIRTIO_MMIO_QUEUE_SEL) = 0;
|
||||
// re-read status to ensure FEATURES_OK is set.
|
||||
status = *R(VIRTIO_MMIO_STATUS);
|
||||
if (!(status & VIRTIO_CONFIG_S_FEATURES_OK))
|
||||
panic("virtio disk FEATURES_OK unset");
|
||||
|
||||
// ensure queue 0 is not in use.
|
||||
if(*R(VIRTIO_MMIO_QUEUE_READY))
|
||||
panic("virtio disk should not be ready");
|
||||
// initialize queue 0.
|
||||
*R(VIRTIO_MMIO_QUEUE_SEL) = 0;
|
||||
|
||||
// check maximum queue size.
|
||||
uint32 max = *R(VIRTIO_MMIO_QUEUE_NUM_MAX);
|
||||
if(max == 0)
|
||||
panic("virtio disk has no queue 0");
|
||||
if(max < NUM)
|
||||
panic("virtio disk max queue too short");
|
||||
// ensure queue 0 is not in use.
|
||||
if (*R(VIRTIO_MMIO_QUEUE_READY))
|
||||
panic("virtio disk should not be ready");
|
||||
|
||||
// allocate and zero queue memory.
|
||||
disk.desc = kalloc();
|
||||
disk.avail = kalloc();
|
||||
disk.used = kalloc();
|
||||
if(!disk.desc || !disk.avail || !disk.used)
|
||||
panic("virtio disk kalloc");
|
||||
memset(disk.desc, 0, PGSIZE);
|
||||
memset(disk.avail, 0, PGSIZE);
|
||||
memset(disk.used, 0, PGSIZE);
|
||||
// check maximum queue size.
|
||||
uint32 max = *R(VIRTIO_MMIO_QUEUE_NUM_MAX);
|
||||
if (max == 0)
|
||||
panic("virtio disk has no queue 0");
|
||||
if (max < NUM)
|
||||
panic("virtio disk max queue too short");
|
||||
|
||||
// set queue size.
|
||||
*R(VIRTIO_MMIO_QUEUE_NUM) = NUM;
|
||||
// allocate and zero queue memory.
|
||||
disk.desc = kalloc();
|
||||
disk.avail = kalloc();
|
||||
disk.used = kalloc();
|
||||
if (!disk.desc || !disk.avail || !disk.used)
|
||||
panic("virtio disk kalloc");
|
||||
memset(disk.desc, 0, PGSIZE);
|
||||
memset(disk.avail, 0, PGSIZE);
|
||||
memset(disk.used, 0, PGSIZE);
|
||||
|
||||
// write physical addresses.
|
||||
*R(VIRTIO_MMIO_QUEUE_DESC_LOW) = (uint64)disk.desc;
|
||||
*R(VIRTIO_MMIO_QUEUE_DESC_HIGH) = (uint64)disk.desc >> 32;
|
||||
*R(VIRTIO_MMIO_DRIVER_DESC_LOW) = (uint64)disk.avail;
|
||||
*R(VIRTIO_MMIO_DRIVER_DESC_HIGH) = (uint64)disk.avail >> 32;
|
||||
*R(VIRTIO_MMIO_DEVICE_DESC_LOW) = (uint64)disk.used;
|
||||
*R(VIRTIO_MMIO_DEVICE_DESC_HIGH) = (uint64)disk.used >> 32;
|
||||
// set queue size.
|
||||
*R(VIRTIO_MMIO_QUEUE_NUM) = NUM;
|
||||
|
||||
// queue is ready.
|
||||
*R(VIRTIO_MMIO_QUEUE_READY) = 0x1;
|
||||
// write physical addresses.
|
||||
*R(VIRTIO_MMIO_QUEUE_DESC_LOW) = (uint64)disk.desc;
|
||||
*R(VIRTIO_MMIO_QUEUE_DESC_HIGH) = (uint64)disk.desc >> 32;
|
||||
*R(VIRTIO_MMIO_DRIVER_DESC_LOW) = (uint64)disk.avail;
|
||||
*R(VIRTIO_MMIO_DRIVER_DESC_HIGH) = (uint64)disk.avail >> 32;
|
||||
*R(VIRTIO_MMIO_DEVICE_DESC_LOW) = (uint64)disk.used;
|
||||
*R(VIRTIO_MMIO_DEVICE_DESC_HIGH) = (uint64)disk.used >> 32;
|
||||
|
||||
// all NUM descriptors start out unused.
|
||||
for(int i = 0; i < NUM; i++)
|
||||
disk.free[i] = 1;
|
||||
// queue is ready.
|
||||
*R(VIRTIO_MMIO_QUEUE_READY) = 0x1;
|
||||
|
||||
// tell device we're completely ready.
|
||||
status |= VIRTIO_CONFIG_S_DRIVER_OK;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
// all NUM descriptors start out unused.
|
||||
for (int i = 0; i < NUM; i++)
|
||||
disk.free[i] = 1;
|
||||
|
||||
// plic.c and trap.c arrange for interrupts from VIRTIO0_IRQ.
|
||||
// tell device we're completely ready.
|
||||
status |= VIRTIO_CONFIG_S_DRIVER_OK;
|
||||
*R(VIRTIO_MMIO_STATUS) = status;
|
||||
|
||||
// plic.c and trap.c arrange for interrupts from VIRTIO0_IRQ.
|
||||
}
|
||||
|
||||
// find a free descriptor, mark it non-free, return its index.
|
||||
static int
|
||||
alloc_desc()
|
||||
{
|
||||
for(int i = 0; i < NUM; i++){
|
||||
if(disk.free[i]){
|
||||
disk.free[i] = 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
static int alloc_desc() {
|
||||
for (int i = 0; i < NUM; i++) {
|
||||
if (disk.free[i]) {
|
||||
disk.free[i] = 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// mark a descriptor as free.
|
||||
static void
|
||||
free_desc(int i)
|
||||
{
|
||||
if(i >= NUM)
|
||||
panic("free_desc 1");
|
||||
if(disk.free[i])
|
||||
panic("free_desc 2");
|
||||
disk.desc[i].addr = 0;
|
||||
disk.desc[i].len = 0;
|
||||
disk.desc[i].flags = 0;
|
||||
disk.desc[i].next = 0;
|
||||
disk.free[i] = 1;
|
||||
wakeup(&disk.free[0]);
|
||||
static void free_desc(int i) {
|
||||
if (i >= NUM)
|
||||
panic("free_desc 1");
|
||||
if (disk.free[i])
|
||||
panic("free_desc 2");
|
||||
disk.desc[i].addr = 0;
|
||||
disk.desc[i].len = 0;
|
||||
disk.desc[i].flags = 0;
|
||||
disk.desc[i].next = 0;
|
||||
disk.free[i] = 1;
|
||||
wakeup(&disk.free[0]);
|
||||
}
|
||||
|
||||
// free a chain of descriptors.
|
||||
static void
|
||||
free_chain(int i)
|
||||
{
|
||||
while(1){
|
||||
int flag = disk.desc[i].flags;
|
||||
int nxt = disk.desc[i].next;
|
||||
free_desc(i);
|
||||
if(flag & VRING_DESC_F_NEXT)
|
||||
i = nxt;
|
||||
else
|
||||
break;
|
||||
}
|
||||
static void free_chain(int i) {
|
||||
while (1) {
|
||||
int flag = disk.desc[i].flags;
|
||||
int nxt = disk.desc[i].next;
|
||||
free_desc(i);
|
||||
if (flag & VRING_DESC_F_NEXT)
|
||||
i = nxt;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate three descriptors (they need not be contiguous).
|
||||
// disk transfers always use three descriptors.
|
||||
static int
|
||||
alloc3_desc(int *idx)
|
||||
{
|
||||
for(int i = 0; i < 3; i++){
|
||||
idx[i] = alloc_desc();
|
||||
if(idx[i] < 0){
|
||||
for(int j = 0; j < i; j++)
|
||||
free_desc(idx[j]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
static int alloc3_desc(int *idx) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
idx[i] = alloc_desc();
|
||||
if (idx[i] < 0) {
|
||||
for (int j = 0; j < i; j++)
|
||||
free_desc(idx[j]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
virtio_disk_rw(struct buf *b, int write)
|
||||
{
|
||||
uint64 sector = b->blockno * (BSIZE / 512);
|
||||
void virtio_disk_rw(struct buf *b, int write) {
|
||||
uint64 sector = b->blockno * (BSIZE / 512);
|
||||
|
||||
acquire(&disk.vdisk_lock);
|
||||
acquire(&disk.vdisk_lock);
|
||||
|
||||
// the spec's Section 5.2 says that legacy block operations use
|
||||
// three descriptors: one for type/reserved/sector, one for the
|
||||
// data, one for a 1-byte status result.
|
||||
// the spec's Section 5.2 says that legacy block operations use
|
||||
// three descriptors: one for type/reserved/sector, one for the
|
||||
// data, one for a 1-byte status result.
|
||||
|
||||
// allocate the three descriptors.
|
||||
int idx[3];
|
||||
while(1){
|
||||
if(alloc3_desc(idx) == 0) {
|
||||
break;
|
||||
}
|
||||
sleep(&disk.free[0], &disk.vdisk_lock);
|
||||
}
|
||||
// allocate the three descriptors.
|
||||
int idx[3];
|
||||
while (1) {
|
||||
if (alloc3_desc(idx) == 0) {
|
||||
break;
|
||||
}
|
||||
sleep(&disk.free[0], &disk.vdisk_lock);
|
||||
}
|
||||
|
||||
// format the three descriptors.
|
||||
// qemu's virtio-blk.c reads them.
|
||||
// format the three descriptors.
|
||||
// qemu's virtio-blk.c reads them.
|
||||
|
||||
struct virtio_blk_req *buf0 = &disk.ops[idx[0]];
|
||||
struct virtio_blk_req *buf0 = &disk.ops[idx[0]];
|
||||
|
||||
if(write)
|
||||
buf0->type = VIRTIO_BLK_T_OUT; // write the disk
|
||||
else
|
||||
buf0->type = VIRTIO_BLK_T_IN; // read the disk
|
||||
buf0->reserved = 0;
|
||||
buf0->sector = sector;
|
||||
if (write)
|
||||
buf0->type = VIRTIO_BLK_T_OUT; // write the disk
|
||||
else
|
||||
buf0->type = VIRTIO_BLK_T_IN; // read the disk
|
||||
buf0->reserved = 0;
|
||||
buf0->sector = sector;
|
||||
|
||||
disk.desc[idx[0]].addr = (uint64) buf0;
|
||||
disk.desc[idx[0]].len = sizeof(struct virtio_blk_req);
|
||||
disk.desc[idx[0]].flags = VRING_DESC_F_NEXT;
|
||||
disk.desc[idx[0]].next = idx[1];
|
||||
disk.desc[idx[0]].addr = (uint64)buf0;
|
||||
disk.desc[idx[0]].len = sizeof(struct virtio_blk_req);
|
||||
disk.desc[idx[0]].flags = VRING_DESC_F_NEXT;
|
||||
disk.desc[idx[0]].next = idx[1];
|
||||
|
||||
disk.desc[idx[1]].addr = (uint64) b->data;
|
||||
disk.desc[idx[1]].len = BSIZE;
|
||||
if(write)
|
||||
disk.desc[idx[1]].flags = 0; // device reads b->data
|
||||
else
|
||||
disk.desc[idx[1]].flags = VRING_DESC_F_WRITE; // device writes b->data
|
||||
disk.desc[idx[1]].flags |= VRING_DESC_F_NEXT;
|
||||
disk.desc[idx[1]].next = idx[2];
|
||||
disk.desc[idx[1]].addr = (uint64)b->data;
|
||||
disk.desc[idx[1]].len = BSIZE;
|
||||
if (write)
|
||||
disk.desc[idx[1]].flags = 0; // device reads b->data
|
||||
else
|
||||
disk.desc[idx[1]].flags = VRING_DESC_F_WRITE; // device writes b->data
|
||||
disk.desc[idx[1]].flags |= VRING_DESC_F_NEXT;
|
||||
disk.desc[idx[1]].next = idx[2];
|
||||
|
||||
disk.info[idx[0]].status = 0xff; // device writes 0 on success
|
||||
disk.desc[idx[2]].addr = (uint64) &disk.info[idx[0]].status;
|
||||
disk.desc[idx[2]].len = 1;
|
||||
disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status
|
||||
disk.desc[idx[2]].next = 0;
|
||||
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]].len = 1;
|
||||
disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status
|
||||
disk.desc[idx[2]].next = 0;
|
||||
|
||||
// record struct buf for virtio_disk_intr().
|
||||
b->disk = 1;
|
||||
disk.info[idx[0]].b = b;
|
||||
// record struct buf for virtio_disk_intr().
|
||||
b->disk = 1;
|
||||
disk.info[idx[0]].b = b;
|
||||
|
||||
// tell the device the first index in our chain of descriptors.
|
||||
disk.avail->ring[disk.avail->idx % NUM] = idx[0];
|
||||
// tell the device the first index in our chain of descriptors.
|
||||
disk.avail->ring[disk.avail->idx % NUM] = idx[0];
|
||||
|
||||
__sync_synchronize();
|
||||
__sync_synchronize();
|
||||
|
||||
// tell the device another avail ring entry is available.
|
||||
disk.avail->idx += 1; // not % NUM ...
|
||||
// tell the device another avail ring entry is available.
|
||||
disk.avail->idx += 1; // not % NUM ...
|
||||
|
||||
__sync_synchronize();
|
||||
__sync_synchronize();
|
||||
|
||||
*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.
|
||||
while(b->disk == 1) {
|
||||
sleep(b, &disk.vdisk_lock);
|
||||
}
|
||||
// Wait for virtio_disk_intr() to say request has finished.
|
||||
while (b->disk == 1) {
|
||||
sleep(b, &disk.vdisk_lock);
|
||||
}
|
||||
|
||||
disk.info[idx[0]].b = 0;
|
||||
free_chain(idx[0]);
|
||||
disk.info[idx[0]].b = 0;
|
||||
free_chain(idx[0]);
|
||||
|
||||
release(&disk.vdisk_lock);
|
||||
release(&disk.vdisk_lock);
|
||||
}
|
||||
|
||||
void
|
||||
virtio_disk_intr()
|
||||
{
|
||||
acquire(&disk.vdisk_lock);
|
||||
void virtio_disk_intr() {
|
||||
acquire(&disk.vdisk_lock);
|
||||
|
||||
// the device won't raise another interrupt until we tell it
|
||||
// we've seen this interrupt, which the following line does.
|
||||
// this may race with the device writing new entries to
|
||||
// the "used" ring, in which case we may process the new
|
||||
// completion entries in this interrupt, and have nothing to do
|
||||
// in the next interrupt, which is harmless.
|
||||
*R(VIRTIO_MMIO_INTERRUPT_ACK) = *R(VIRTIO_MMIO_INTERRUPT_STATUS) & 0x3;
|
||||
// the device won't raise another interrupt until we tell it
|
||||
// we've seen this interrupt, which the following line does.
|
||||
// this may race with the device writing new entries to
|
||||
// the "used" ring, in which case we may process the new
|
||||
// completion entries in this interrupt, and have nothing to do
|
||||
// in the next interrupt, which is harmless.
|
||||
*R(VIRTIO_MMIO_INTERRUPT_ACK) = *R(VIRTIO_MMIO_INTERRUPT_STATUS) & 0x3;
|
||||
|
||||
__sync_synchronize();
|
||||
__sync_synchronize();
|
||||
|
||||
// the device increments disk.used->idx when it
|
||||
// adds an entry to the used ring.
|
||||
// the device increments disk.used->idx when it
|
||||
// adds an entry to the used ring.
|
||||
|
||||
while(disk.used_idx != disk.used->idx){
|
||||
__sync_synchronize();
|
||||
int id = disk.used->ring[disk.used_idx % NUM].id;
|
||||
while (disk.used_idx != disk.used->idx) {
|
||||
__sync_synchronize();
|
||||
int id = disk.used->ring[disk.used_idx % NUM].id;
|
||||
|
||||
if(disk.info[id].status != 0)
|
||||
panic("virtio_disk_intr status");
|
||||
if (disk.info[id].status != 0)
|
||||
panic("virtio_disk_intr status");
|
||||
|
||||
struct buf *b = disk.info[id].b;
|
||||
b->disk = 0; // disk is done with buf
|
||||
wakeup(b);
|
||||
struct buf *b = disk.info[id].b;
|
||||
b->disk = 0; // disk is done with buf
|
||||
wakeup(b);
|
||||
|
||||
disk.used_idx += 1;
|
||||
}
|
||||
disk.used_idx += 1;
|
||||
}
|
||||
|
||||
release(&disk.vdisk_lock);
|
||||
release(&disk.vdisk_lock);
|
||||
}
|
||||
|
|
|
|||
552
kernel/vm.c
552
kernel/vm.c
|
|
@ -11,58 +11,56 @@
|
|||
*/
|
||||
pagetable_t kernel_pagetable;
|
||||
|
||||
extern char etext[]; // kernel.ld sets this to end of kernel code.
|
||||
extern char etext[]; // kernel.ld sets this to end of kernel code.
|
||||
|
||||
extern char trampoline[]; // trampoline.S
|
||||
|
||||
// Make a direct-map page table for the kernel.
|
||||
pagetable_t
|
||||
kvmmake(void)
|
||||
{
|
||||
pagetable_t kpgtbl;
|
||||
pagetable_t kvmmake(void) {
|
||||
pagetable_t kpgtbl;
|
||||
|
||||
kpgtbl = (pagetable_t) kalloc();
|
||||
memset(kpgtbl, 0, PGSIZE);
|
||||
kpgtbl = (pagetable_t)kalloc();
|
||||
memset(kpgtbl, 0, PGSIZE);
|
||||
|
||||
// uart registers
|
||||
kvmmap(kpgtbl, UART0, UART0, PGSIZE, PTE_R | PTE_W);
|
||||
// uart registers
|
||||
kvmmap(kpgtbl, UART0, UART0, PGSIZE, PTE_R | PTE_W);
|
||||
|
||||
// virtio mmio disk interface
|
||||
kvmmap(kpgtbl, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
|
||||
// virtio mmio disk interface
|
||||
kvmmap(kpgtbl, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
|
||||
|
||||
// PLIC
|
||||
kvmmap(kpgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W);
|
||||
// PLIC
|
||||
kvmmap(kpgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W);
|
||||
|
||||
// map kernel text executable and read-only.
|
||||
kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
|
||||
// map kernel text executable and read-only.
|
||||
kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext - KERNBASE, PTE_R | PTE_X);
|
||||
|
||||
// map kernel data and the physical RAM we'll make use of.
|
||||
kvmmap(kpgtbl, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W);
|
||||
// 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);
|
||||
|
||||
// map the trampoline for trap entry/exit to
|
||||
// the highest virtual address in the kernel.
|
||||
kvmmap(kpgtbl, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X);
|
||||
// map the trampoline for trap entry/exit to
|
||||
// the highest virtual address in the kernel.
|
||||
kvmmap(kpgtbl, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X);
|
||||
|
||||
// allocate and map a kernel stack for each process.
|
||||
proc_mapstacks(kpgtbl);
|
||||
|
||||
return kpgtbl;
|
||||
// allocate and map a kernel stack for each process.
|
||||
proc_mapstacks(kpgtbl);
|
||||
|
||||
return kpgtbl;
|
||||
}
|
||||
|
||||
// Initialize the one kernel_pagetable
|
||||
void
|
||||
kvminit(void)
|
||||
{
|
||||
kernel_pagetable = kvmmake();
|
||||
}
|
||||
void kvminit(void) { kernel_pagetable = kvmmake(); }
|
||||
|
||||
// Switch h/w page table register to the kernel's page table,
|
||||
// and enable paging.
|
||||
void
|
||||
kvminithart()
|
||||
{
|
||||
w_satp(MAKE_SATP(kernel_pagetable));
|
||||
sfence_vma();
|
||||
void kvminithart() {
|
||||
// wait for any previous writes to the page table memory to finish.
|
||||
sfence_vma();
|
||||
|
||||
w_satp(MAKE_SATP(kernel_pagetable));
|
||||
|
||||
// flush stale entries from the TLB.
|
||||
sfence_vma();
|
||||
}
|
||||
|
||||
// Return the address of the PTE in page table pagetable
|
||||
|
|
@ -77,218 +75,198 @@ kvminithart()
|
|||
// 21..29 -- 9 bits of level-1 index.
|
||||
// 12..20 -- 9 bits of level-0 index.
|
||||
// 0..11 -- 12 bits of byte offset within the page.
|
||||
pte_t *
|
||||
walk(pagetable_t pagetable, uint64 va, int alloc)
|
||||
{
|
||||
if(va >= MAXVA)
|
||||
panic("walk");
|
||||
pte_t *walk(pagetable_t pagetable, uint64 va, int alloc) {
|
||||
if (va >= MAXVA)
|
||||
panic("walk");
|
||||
|
||||
for(int level = 2; level > 0; level--) {
|
||||
pte_t *pte = &pagetable[PX(level, va)];
|
||||
if(*pte & PTE_V) {
|
||||
pagetable = (pagetable_t)PTE2PA(*pte);
|
||||
} else {
|
||||
if(!alloc || (pagetable = (pde_t*)kalloc()) == 0)
|
||||
return 0;
|
||||
memset(pagetable, 0, PGSIZE);
|
||||
*pte = PA2PTE(pagetable) | PTE_V;
|
||||
}
|
||||
}
|
||||
return &pagetable[PX(0, va)];
|
||||
for (int level = 2; level > 0; level--) {
|
||||
pte_t *pte = &pagetable[PX(level, va)];
|
||||
if (*pte & PTE_V) {
|
||||
pagetable = (pagetable_t)PTE2PA(*pte);
|
||||
} else {
|
||||
if (!alloc || (pagetable = (pde_t *)kalloc()) == 0)
|
||||
return 0;
|
||||
memset(pagetable, 0, PGSIZE);
|
||||
*pte = PA2PTE(pagetable) | PTE_V;
|
||||
}
|
||||
}
|
||||
return &pagetable[PX(0, va)];
|
||||
}
|
||||
|
||||
// Look up a virtual address, return the physical address,
|
||||
// or 0 if not mapped.
|
||||
// Can only be used to look up user pages.
|
||||
uint64
|
||||
walkaddr(pagetable_t pagetable, uint64 va)
|
||||
{
|
||||
pte_t *pte;
|
||||
uint64 pa;
|
||||
uint64 walkaddr(pagetable_t pagetable, uint64 va) {
|
||||
pte_t *pte;
|
||||
uint64 pa;
|
||||
|
||||
if(va >= MAXVA)
|
||||
return 0;
|
||||
if (va >= MAXVA)
|
||||
return 0;
|
||||
|
||||
pte = walk(pagetable, va, 0);
|
||||
if(pte == 0)
|
||||
return 0;
|
||||
if((*pte & PTE_V) == 0)
|
||||
return 0;
|
||||
if((*pte & PTE_U) == 0)
|
||||
return 0;
|
||||
pa = PTE2PA(*pte);
|
||||
return pa;
|
||||
pte = walk(pagetable, va, 0);
|
||||
if (pte == 0)
|
||||
return 0;
|
||||
if ((*pte & PTE_V) == 0)
|
||||
return 0;
|
||||
if ((*pte & PTE_U) == 0)
|
||||
return 0;
|
||||
pa = PTE2PA(*pte);
|
||||
return pa;
|
||||
}
|
||||
|
||||
// add a mapping to the kernel page table.
|
||||
// only used when booting.
|
||||
// does not flush TLB or enable paging.
|
||||
void
|
||||
kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm)
|
||||
{
|
||||
if(mappages(kpgtbl, va, sz, pa, perm) != 0)
|
||||
panic("kvmmap");
|
||||
void kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm) {
|
||||
if (mappages(kpgtbl, va, sz, pa, perm) != 0)
|
||||
panic("kvmmap");
|
||||
}
|
||||
|
||||
// Create PTEs for virtual addresses starting at va that refer to
|
||||
// physical addresses starting at pa. va and size might not
|
||||
// be page-aligned. Returns 0 on success, -1 if walk() couldn't
|
||||
// allocate a needed page-table page.
|
||||
int
|
||||
mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
|
||||
{
|
||||
uint64 a, last;
|
||||
pte_t *pte;
|
||||
int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa,
|
||||
int perm) {
|
||||
uint64 a, last;
|
||||
pte_t *pte;
|
||||
|
||||
if(size == 0)
|
||||
panic("mappages: size");
|
||||
|
||||
a = PGROUNDDOWN(va);
|
||||
last = PGROUNDDOWN(va + size - 1);
|
||||
for(;;){
|
||||
if((pte = walk(pagetable, a, 1)) == 0)
|
||||
return -1;
|
||||
if(*pte & PTE_V)
|
||||
panic("mappages: remap");
|
||||
*pte = PA2PTE(pa) | perm | PTE_V;
|
||||
if(a == last)
|
||||
break;
|
||||
a += PGSIZE;
|
||||
pa += PGSIZE;
|
||||
}
|
||||
return 0;
|
||||
if (size == 0)
|
||||
panic("mappages: size");
|
||||
|
||||
a = PGROUNDDOWN(va);
|
||||
last = PGROUNDDOWN(va + size - 1);
|
||||
for (;;) {
|
||||
if ((pte = walk(pagetable, a, 1)) == 0)
|
||||
return -1;
|
||||
if (*pte & PTE_V)
|
||||
panic("mappages: remap");
|
||||
*pte = PA2PTE(pa) | perm | PTE_V;
|
||||
if (a == last)
|
||||
break;
|
||||
a += PGSIZE;
|
||||
pa += PGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remove npages of mappings starting from va. va must be
|
||||
// page-aligned. The mappings must exist.
|
||||
// Optionally free the physical memory.
|
||||
void
|
||||
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
|
||||
{
|
||||
uint64 a;
|
||||
pte_t *pte;
|
||||
void uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free) {
|
||||
uint64 a;
|
||||
pte_t *pte;
|
||||
|
||||
if((va % PGSIZE) != 0)
|
||||
panic("uvmunmap: not aligned");
|
||||
if ((va % PGSIZE) != 0)
|
||||
panic("uvmunmap: not aligned");
|
||||
|
||||
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
|
||||
if((pte = walk(pagetable, a, 0)) == 0)
|
||||
panic("uvmunmap: walk");
|
||||
if((*pte & PTE_V) == 0)
|
||||
panic("uvmunmap: not mapped");
|
||||
if(PTE_FLAGS(*pte) == PTE_V)
|
||||
panic("uvmunmap: not a leaf");
|
||||
if(do_free){
|
||||
uint64 pa = PTE2PA(*pte);
|
||||
kfree((void*)pa);
|
||||
}
|
||||
*pte = 0;
|
||||
}
|
||||
for (a = va; a < va + npages * PGSIZE; a += PGSIZE) {
|
||||
if ((pte = walk(pagetable, a, 0)) == 0)
|
||||
panic("uvmunmap: walk");
|
||||
if ((*pte & PTE_V) == 0)
|
||||
panic("uvmunmap: not mapped");
|
||||
if (PTE_FLAGS(*pte) == PTE_V)
|
||||
panic("uvmunmap: not a leaf");
|
||||
if (do_free) {
|
||||
uint64 pa = PTE2PA(*pte);
|
||||
kfree((void *)pa);
|
||||
}
|
||||
*pte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// create an empty user page table.
|
||||
// returns 0 if out of memory.
|
||||
pagetable_t
|
||||
uvmcreate()
|
||||
{
|
||||
pagetable_t pagetable;
|
||||
pagetable = (pagetable_t) kalloc();
|
||||
if(pagetable == 0)
|
||||
return 0;
|
||||
memset(pagetable, 0, PGSIZE);
|
||||
return pagetable;
|
||||
pagetable_t uvmcreate() {
|
||||
pagetable_t pagetable;
|
||||
pagetable = (pagetable_t)kalloc();
|
||||
if (pagetable == 0)
|
||||
return 0;
|
||||
memset(pagetable, 0, PGSIZE);
|
||||
return pagetable;
|
||||
}
|
||||
|
||||
// Load the user initcode into address 0 of pagetable,
|
||||
// for the very first process.
|
||||
// sz must be less than a page.
|
||||
void
|
||||
uvmfirst(pagetable_t pagetable, uchar *src, uint sz)
|
||||
{
|
||||
char *mem;
|
||||
void uvmfirst(pagetable_t pagetable, uchar *src, uint sz) {
|
||||
char *mem;
|
||||
|
||||
if(sz >= PGSIZE)
|
||||
panic("uvmfirst: more than a page");
|
||||
mem = kalloc();
|
||||
memset(mem, 0, PGSIZE);
|
||||
mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U);
|
||||
memmove(mem, src, sz);
|
||||
if (sz >= PGSIZE)
|
||||
panic("uvmfirst: more than a page");
|
||||
mem = kalloc();
|
||||
memset(mem, 0, PGSIZE);
|
||||
mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W | PTE_R | PTE_X | PTE_U);
|
||||
memmove(mem, src, sz);
|
||||
}
|
||||
|
||||
// Allocate PTEs and physical memory to grow process from oldsz to
|
||||
// newsz, which need not be page aligned. Returns new size or 0 on error.
|
||||
uint64
|
||||
uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm)
|
||||
{
|
||||
char *mem;
|
||||
uint64 a;
|
||||
uint64 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm) {
|
||||
char *mem;
|
||||
uint64 a;
|
||||
|
||||
if(newsz < oldsz)
|
||||
return oldsz;
|
||||
if (newsz < oldsz)
|
||||
return oldsz;
|
||||
|
||||
oldsz = PGROUNDUP(oldsz);
|
||||
for(a = oldsz; a < newsz; a += PGSIZE){
|
||||
mem = kalloc();
|
||||
if(mem == 0){
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
memset(mem, 0, PGSIZE);
|
||||
if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
|
||||
kfree(mem);
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return newsz;
|
||||
oldsz = PGROUNDUP(oldsz);
|
||||
for (a = oldsz; a < newsz; a += PGSIZE) {
|
||||
mem = kalloc();
|
||||
if (mem == 0) {
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
memset(mem, 0, PGSIZE);
|
||||
if (mappages(pagetable, a, PGSIZE, (uint64)mem,
|
||||
PTE_R | PTE_U | xperm) != 0) {
|
||||
kfree(mem);
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return newsz;
|
||||
}
|
||||
|
||||
// Deallocate user pages to bring the process size from oldsz to
|
||||
// newsz. oldsz and newsz need not be page-aligned, nor does newsz
|
||||
// need to be less than oldsz. oldsz can be larger than the actual
|
||||
// process size. Returns the new process size.
|
||||
uint64
|
||||
uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
|
||||
{
|
||||
if(newsz >= oldsz)
|
||||
return oldsz;
|
||||
uint64 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) {
|
||||
if (newsz >= oldsz)
|
||||
return oldsz;
|
||||
|
||||
if(PGROUNDUP(newsz) < PGROUNDUP(oldsz)){
|
||||
int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
|
||||
uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
|
||||
}
|
||||
if (PGROUNDUP(newsz) < PGROUNDUP(oldsz)) {
|
||||
int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
|
||||
uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
|
||||
}
|
||||
|
||||
return newsz;
|
||||
return newsz;
|
||||
}
|
||||
|
||||
// Recursively free page-table pages.
|
||||
// All leaf mappings must already have been removed.
|
||||
void
|
||||
freewalk(pagetable_t pagetable)
|
||||
{
|
||||
// there are 2^9 = 512 PTEs in a page table.
|
||||
for(int i = 0; i < 512; i++){
|
||||
pte_t pte = pagetable[i];
|
||||
if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){
|
||||
// this PTE points to a lower-level page table.
|
||||
uint64 child = PTE2PA(pte);
|
||||
freewalk((pagetable_t)child);
|
||||
pagetable[i] = 0;
|
||||
} else if(pte & PTE_V){
|
||||
panic("freewalk: leaf");
|
||||
}
|
||||
}
|
||||
kfree((void*)pagetable);
|
||||
void freewalk(pagetable_t pagetable) {
|
||||
// there are 2^9 = 512 PTEs in a page table.
|
||||
for (int i = 0; i < 512; i++) {
|
||||
pte_t pte = pagetable[i];
|
||||
if ((pte & PTE_V) && (pte & (PTE_R | PTE_W | PTE_X)) == 0) {
|
||||
// this PTE points to a lower-level page table.
|
||||
uint64 child = PTE2PA(pte);
|
||||
freewalk((pagetable_t)child);
|
||||
pagetable[i] = 0;
|
||||
} else if (pte & PTE_V) {
|
||||
panic("freewalk: leaf");
|
||||
}
|
||||
}
|
||||
kfree((void *)pagetable);
|
||||
}
|
||||
|
||||
// Free user memory pages,
|
||||
// then free page-table pages.
|
||||
void
|
||||
uvmfree(pagetable_t pagetable, uint64 sz)
|
||||
{
|
||||
if(sz > 0)
|
||||
uvmunmap(pagetable, 0, PGROUNDUP(sz)/PGSIZE, 1);
|
||||
freewalk(pagetable);
|
||||
void uvmfree(pagetable_t pagetable, uint64 sz) {
|
||||
if (sz > 0)
|
||||
uvmunmap(pagetable, 0, PGROUNDUP(sz) / PGSIZE, 1);
|
||||
freewalk(pagetable);
|
||||
}
|
||||
|
||||
// Given a parent process's page table, copy
|
||||
|
|
@ -297,138 +275,128 @@ uvmfree(pagetable_t pagetable, uint64 sz)
|
|||
// physical memory.
|
||||
// returns 0 on success, -1 on failure.
|
||||
// frees any allocated pages on failure.
|
||||
int
|
||||
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||
{
|
||||
pte_t *pte;
|
||||
uint64 pa, i;
|
||||
uint flags;
|
||||
char *mem;
|
||||
int uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) {
|
||||
pte_t *pte;
|
||||
uint64 pa, i;
|
||||
uint flags;
|
||||
char *mem;
|
||||
|
||||
for(i = 0; i < sz; i += PGSIZE){
|
||||
if((pte = walk(old, i, 0)) == 0)
|
||||
panic("uvmcopy: pte should exist");
|
||||
if((*pte & PTE_V) == 0)
|
||||
panic("uvmcopy: page not present");
|
||||
pa = PTE2PA(*pte);
|
||||
flags = PTE_FLAGS(*pte);
|
||||
if((mem = kalloc()) == 0)
|
||||
goto err;
|
||||
memmove(mem, (char*)pa, PGSIZE);
|
||||
if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
|
||||
kfree(mem);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
for (i = 0; i < sz; i += PGSIZE) {
|
||||
if ((pte = walk(old, i, 0)) == 0)
|
||||
panic("uvmcopy: pte should exist");
|
||||
if ((*pte & PTE_V) == 0)
|
||||
panic("uvmcopy: page not present");
|
||||
pa = PTE2PA(*pte);
|
||||
flags = PTE_FLAGS(*pte);
|
||||
if ((mem = kalloc()) == 0)
|
||||
goto err;
|
||||
memmove(mem, (char *)pa, PGSIZE);
|
||||
if (mappages(new, i, PGSIZE, (uint64)mem, flags) != 0) {
|
||||
kfree(mem);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
uvmunmap(new, 0, i / PGSIZE, 1);
|
||||
return -1;
|
||||
err:
|
||||
uvmunmap(new, 0, i / PGSIZE, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// mark a PTE invalid for user access.
|
||||
// used by exec for the user stack guard page.
|
||||
void
|
||||
uvmclear(pagetable_t pagetable, uint64 va)
|
||||
{
|
||||
pte_t *pte;
|
||||
|
||||
pte = walk(pagetable, va, 0);
|
||||
if(pte == 0)
|
||||
panic("uvmclear");
|
||||
*pte &= ~PTE_U;
|
||||
void uvmclear(pagetable_t pagetable, uint64 va) {
|
||||
pte_t *pte;
|
||||
|
||||
pte = walk(pagetable, va, 0);
|
||||
if (pte == 0)
|
||||
panic("uvmclear");
|
||||
*pte &= ~PTE_U;
|
||||
}
|
||||
|
||||
// Copy from kernel to user.
|
||||
// Copy len bytes from src to virtual address dstva in a given page table.
|
||||
// Return 0 on success, -1 on error.
|
||||
int
|
||||
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
|
||||
{
|
||||
uint64 n, va0, pa0;
|
||||
int copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len) {
|
||||
uint64 n, va0, pa0;
|
||||
|
||||
while(len > 0){
|
||||
va0 = PGROUNDDOWN(dstva);
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if(pa0 == 0)
|
||||
return -1;
|
||||
n = PGSIZE - (dstva - va0);
|
||||
if(n > len)
|
||||
n = len;
|
||||
memmove((void *)(pa0 + (dstva - va0)), src, n);
|
||||
while (len > 0) {
|
||||
va0 = PGROUNDDOWN(dstva);
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if (pa0 == 0)
|
||||
return -1;
|
||||
n = PGSIZE - (dstva - va0);
|
||||
if (n > len)
|
||||
n = len;
|
||||
memmove((void *)(pa0 + (dstva - va0)), src, n);
|
||||
|
||||
len -= n;
|
||||
src += n;
|
||||
dstva = va0 + PGSIZE;
|
||||
}
|
||||
return 0;
|
||||
len -= n;
|
||||
src += n;
|
||||
dstva = va0 + PGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy from user to kernel.
|
||||
// Copy len bytes to dst from virtual address srcva in a given page table.
|
||||
// Return 0 on success, -1 on error.
|
||||
int
|
||||
copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
|
||||
{
|
||||
uint64 n, va0, pa0;
|
||||
int copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) {
|
||||
uint64 n, va0, pa0;
|
||||
|
||||
while(len > 0){
|
||||
va0 = PGROUNDDOWN(srcva);
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if(pa0 == 0)
|
||||
return -1;
|
||||
n = PGSIZE - (srcva - va0);
|
||||
if(n > len)
|
||||
n = len;
|
||||
memmove(dst, (void *)(pa0 + (srcva - va0)), n);
|
||||
while (len > 0) {
|
||||
va0 = PGROUNDDOWN(srcva);
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if (pa0 == 0)
|
||||
return -1;
|
||||
n = PGSIZE - (srcva - va0);
|
||||
if (n > len)
|
||||
n = len;
|
||||
memmove(dst, (void *)(pa0 + (srcva - va0)), n);
|
||||
|
||||
len -= n;
|
||||
dst += n;
|
||||
srcva = va0 + PGSIZE;
|
||||
}
|
||||
return 0;
|
||||
len -= n;
|
||||
dst += n;
|
||||
srcva = va0 + PGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy a null-terminated string from user to kernel.
|
||||
// Copy bytes to dst from virtual address srcva in a given page table,
|
||||
// until a '\0', or max.
|
||||
// Return 0 on success, -1 on error.
|
||||
int
|
||||
copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
|
||||
{
|
||||
uint64 n, va0, pa0;
|
||||
int got_null = 0;
|
||||
int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) {
|
||||
uint64 n, va0, pa0;
|
||||
int got_null = 0;
|
||||
|
||||
while(got_null == 0 && max > 0){
|
||||
va0 = PGROUNDDOWN(srcva);
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if(pa0 == 0)
|
||||
return -1;
|
||||
n = PGSIZE - (srcva - va0);
|
||||
if(n > max)
|
||||
n = max;
|
||||
while (got_null == 0 && max > 0) {
|
||||
va0 = PGROUNDDOWN(srcva);
|
||||
pa0 = walkaddr(pagetable, va0);
|
||||
if (pa0 == 0)
|
||||
return -1;
|
||||
n = PGSIZE - (srcva - va0);
|
||||
if (n > max)
|
||||
n = max;
|
||||
|
||||
char *p = (char *) (pa0 + (srcva - va0));
|
||||
while(n > 0){
|
||||
if(*p == '\0'){
|
||||
*dst = '\0';
|
||||
got_null = 1;
|
||||
break;
|
||||
} else {
|
||||
*dst = *p;
|
||||
}
|
||||
--n;
|
||||
--max;
|
||||
p++;
|
||||
dst++;
|
||||
}
|
||||
char *p = (char *)(pa0 + (srcva - va0));
|
||||
while (n > 0) {
|
||||
if (*p == '\0') {
|
||||
*dst = '\0';
|
||||
got_null = 1;
|
||||
break;
|
||||
} else {
|
||||
*dst = *p;
|
||||
}
|
||||
--n;
|
||||
--max;
|
||||
p++;
|
||||
dst++;
|
||||
}
|
||||
|
||||
srcva = va0 + PGSIZE;
|
||||
}
|
||||
if(got_null){
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
srcva = va0 + PGSIZE;
|
||||
}
|
||||
if (got_null) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
406
mkfs/mkfs.c
406
mkfs/mkfs.c
|
|
@ -5,14 +5,19 @@
|
|||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define stat xv6_stat // avoid clash with host struct stat
|
||||
#define stat xv6_stat // avoid clash with host struct stat
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/fs.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/param.h"
|
||||
|
||||
#ifndef static_assert
|
||||
#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
|
||||
#define static_assert(a, b) \
|
||||
do { \
|
||||
switch (0) \
|
||||
case 0: \
|
||||
case (a):; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define NINODES 200
|
||||
|
|
@ -20,11 +25,11 @@
|
|||
// Disk layout:
|
||||
// [ boot block | sb block | log | inode blocks | free bit map | data blocks ]
|
||||
|
||||
int nbitmap = FSSIZE/(BSIZE*8) + 1;
|
||||
int nbitmap = FSSIZE / (BSIZE * 8) + 1;
|
||||
int ninodeblocks = NINODES / IPB + 1;
|
||||
int nlog = LOGSIZE;
|
||||
int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)
|
||||
int nblocks; // Number of data blocks
|
||||
int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)
|
||||
int nblocks; // Number of data blocks
|
||||
|
||||
int fsfd;
|
||||
struct superblock sb;
|
||||
|
|
@ -32,10 +37,9 @@ char zeroes[BSIZE];
|
|||
uint freeinode = 1;
|
||||
uint freeblock;
|
||||
|
||||
|
||||
void balloc(int);
|
||||
void wsect(uint, void*);
|
||||
void winode(uint, struct dinode*);
|
||||
void wsect(uint, void *);
|
||||
void winode(uint, struct dinode *);
|
||||
void rinode(uint inum, struct dinode *ip);
|
||||
void rsect(uint sec, void *buf);
|
||||
uint ialloc(ushort type);
|
||||
|
|
@ -43,259 +47,237 @@ void iappend(uint inum, void *p, int n);
|
|||
void die(const char *);
|
||||
|
||||
// convert to riscv byte order
|
||||
ushort
|
||||
xshort(ushort x)
|
||||
{
|
||||
ushort y;
|
||||
uchar *a = (uchar*)&y;
|
||||
a[0] = x;
|
||||
a[1] = x >> 8;
|
||||
return y;
|
||||
ushort xshort(ushort x) {
|
||||
ushort y;
|
||||
uchar *a = (uchar *)&y;
|
||||
a[0] = x;
|
||||
a[1] = x >> 8;
|
||||
return y;
|
||||
}
|
||||
|
||||
uint
|
||||
xint(uint x)
|
||||
{
|
||||
uint y;
|
||||
uchar *a = (uchar*)&y;
|
||||
a[0] = x;
|
||||
a[1] = x >> 8;
|
||||
a[2] = x >> 16;
|
||||
a[3] = x >> 24;
|
||||
return y;
|
||||
uint xint(uint x) {
|
||||
uint y;
|
||||
uchar *a = (uchar *)&y;
|
||||
a[0] = x;
|
||||
a[1] = x >> 8;
|
||||
a[2] = x >> 16;
|
||||
a[3] = x >> 24;
|
||||
return y;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, cc, fd;
|
||||
uint rootino, inum, off;
|
||||
struct dirent de;
|
||||
char buf[BSIZE];
|
||||
struct dinode din;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, cc, fd;
|
||||
uint rootino, inum, off;
|
||||
struct dirent de;
|
||||
char buf[BSIZE];
|
||||
struct dinode din;
|
||||
|
||||
static_assert(sizeof(int) == 4, "Integers must be 4 bytes!");
|
||||
|
||||
static_assert(sizeof(int) == 4, "Integers must be 4 bytes!");
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: mkfs fs.img files...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(stderr, "Usage: mkfs fs.img files...\n");
|
||||
exit(1);
|
||||
}
|
||||
assert((BSIZE % sizeof(struct dinode)) == 0);
|
||||
assert((BSIZE % sizeof(struct dirent)) == 0);
|
||||
|
||||
assert((BSIZE % sizeof(struct dinode)) == 0);
|
||||
assert((BSIZE % sizeof(struct dirent)) == 0);
|
||||
fsfd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
if (fsfd < 0)
|
||||
die(argv[1]);
|
||||
|
||||
fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
|
||||
if(fsfd < 0)
|
||||
die(argv[1]);
|
||||
// 1 fs block = 1 disk sector
|
||||
nmeta = 2 + nlog + ninodeblocks + nbitmap;
|
||||
nblocks = FSSIZE - nmeta;
|
||||
|
||||
// 1 fs block = 1 disk sector
|
||||
nmeta = 2 + nlog + ninodeblocks + nbitmap;
|
||||
nblocks = FSSIZE - nmeta;
|
||||
sb.magic = FSMAGIC;
|
||||
sb.size = xint(FSSIZE);
|
||||
sb.nblocks = xint(nblocks);
|
||||
sb.ninodes = xint(NINODES);
|
||||
sb.nlog = xint(nlog);
|
||||
sb.logstart = xint(2);
|
||||
sb.inodestart = xint(2 + nlog);
|
||||
sb.bmapstart = xint(2 + nlog + ninodeblocks);
|
||||
|
||||
sb.magic = FSMAGIC;
|
||||
sb.size = xint(FSSIZE);
|
||||
sb.nblocks = xint(nblocks);
|
||||
sb.ninodes = xint(NINODES);
|
||||
sb.nlog = xint(nlog);
|
||||
sb.logstart = xint(2);
|
||||
sb.inodestart = xint(2+nlog);
|
||||
sb.bmapstart = xint(2+nlog+ninodeblocks);
|
||||
printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap "
|
||||
"blocks %u) blocks %d total %d\n",
|
||||
nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);
|
||||
|
||||
printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n",
|
||||
nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);
|
||||
freeblock = nmeta; // the first free block that we can allocate
|
||||
|
||||
freeblock = nmeta; // the first free block that we can allocate
|
||||
for (i = 0; i < FSSIZE; i++)
|
||||
wsect(i, zeroes);
|
||||
|
||||
for(i = 0; i < FSSIZE; i++)
|
||||
wsect(i, zeroes);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memmove(buf, &sb, sizeof(sb));
|
||||
wsect(1, buf);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memmove(buf, &sb, sizeof(sb));
|
||||
wsect(1, buf);
|
||||
rootino = ialloc(T_DIR);
|
||||
assert(rootino == ROOTINO);
|
||||
|
||||
rootino = ialloc(T_DIR);
|
||||
assert(rootino == ROOTINO);
|
||||
bzero(&de, sizeof(de));
|
||||
de.inum = xshort(rootino);
|
||||
strcpy(de.name, ".");
|
||||
iappend(rootino, &de, sizeof(de));
|
||||
|
||||
bzero(&de, sizeof(de));
|
||||
de.inum = xshort(rootino);
|
||||
strcpy(de.name, ".");
|
||||
iappend(rootino, &de, sizeof(de));
|
||||
bzero(&de, sizeof(de));
|
||||
de.inum = xshort(rootino);
|
||||
strcpy(de.name, "..");
|
||||
iappend(rootino, &de, sizeof(de));
|
||||
|
||||
bzero(&de, sizeof(de));
|
||||
de.inum = xshort(rootino);
|
||||
strcpy(de.name, "..");
|
||||
iappend(rootino, &de, sizeof(de));
|
||||
for (i = 2; i < argc; i++) {
|
||||
// get rid of "user/"
|
||||
char *shortname;
|
||||
if (strncmp(argv[i], "user/", 5) == 0)
|
||||
shortname = argv[i] + 5;
|
||||
else
|
||||
shortname = argv[i];
|
||||
|
||||
for(i = 2; i < argc; i++){
|
||||
// get rid of "user/"
|
||||
char *shortname;
|
||||
if(strncmp(argv[i], "user/", 5) == 0)
|
||||
shortname = argv[i] + 5;
|
||||
else
|
||||
shortname = argv[i];
|
||||
|
||||
assert(index(shortname, '/') == 0);
|
||||
assert(index(shortname, '/') == 0);
|
||||
|
||||
if((fd = open(argv[i], 0)) < 0)
|
||||
die(argv[i]);
|
||||
if ((fd = open(argv[i], 0)) < 0)
|
||||
die(argv[i]);
|
||||
|
||||
// Skip leading _ in name when writing to file system.
|
||||
// The binaries are named _rm, _cat, etc. to keep the
|
||||
// build operating system from trying to execute them
|
||||
// in place of system binaries like rm and cat.
|
||||
if(shortname[0] == '_')
|
||||
shortname += 1;
|
||||
// Skip leading _ in name when writing to file system.
|
||||
// The binaries are named _rm, _cat, etc. to keep the
|
||||
// build operating system from trying to execute them
|
||||
// in place of system binaries like rm and cat.
|
||||
if (shortname[0] == '_')
|
||||
shortname += 1;
|
||||
|
||||
inum = ialloc(T_FILE);
|
||||
inum = ialloc(T_FILE);
|
||||
|
||||
bzero(&de, sizeof(de));
|
||||
de.inum = xshort(inum);
|
||||
strncpy(de.name, shortname, DIRSIZ);
|
||||
iappend(rootino, &de, sizeof(de));
|
||||
bzero(&de, sizeof(de));
|
||||
de.inum = xshort(inum);
|
||||
strncpy(de.name, shortname, DIRSIZ);
|
||||
iappend(rootino, &de, sizeof(de));
|
||||
|
||||
while((cc = read(fd, buf, sizeof(buf))) > 0)
|
||||
iappend(inum, buf, cc);
|
||||
while ((cc = read(fd, buf, sizeof(buf))) > 0)
|
||||
iappend(inum, buf, cc);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// fix size of root inode dir
|
||||
rinode(rootino, &din);
|
||||
off = xint(din.size);
|
||||
off = ((off/BSIZE) + 1) * BSIZE;
|
||||
din.size = xint(off);
|
||||
winode(rootino, &din);
|
||||
// fix size of root inode dir
|
||||
rinode(rootino, &din);
|
||||
off = xint(din.size);
|
||||
off = ((off / BSIZE) + 1) * BSIZE;
|
||||
din.size = xint(off);
|
||||
winode(rootino, &din);
|
||||
|
||||
balloc(freeblock);
|
||||
balloc(freeblock);
|
||||
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
wsect(uint sec, void *buf)
|
||||
{
|
||||
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
|
||||
die("lseek");
|
||||
if(write(fsfd, buf, BSIZE) != BSIZE)
|
||||
die("write");
|
||||
void wsect(uint sec, void *buf) {
|
||||
if (lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
|
||||
die("lseek");
|
||||
if (write(fsfd, buf, BSIZE) != BSIZE)
|
||||
die("write");
|
||||
}
|
||||
|
||||
void
|
||||
winode(uint inum, struct dinode *ip)
|
||||
{
|
||||
char buf[BSIZE];
|
||||
uint bn;
|
||||
struct dinode *dip;
|
||||
void winode(uint inum, struct dinode *ip) {
|
||||
char buf[BSIZE];
|
||||
uint bn;
|
||||
struct dinode *dip;
|
||||
|
||||
bn = IBLOCK(inum, sb);
|
||||
rsect(bn, buf);
|
||||
dip = ((struct dinode*)buf) + (inum % IPB);
|
||||
*dip = *ip;
|
||||
wsect(bn, buf);
|
||||
bn = IBLOCK(inum, sb);
|
||||
rsect(bn, buf);
|
||||
dip = ((struct dinode *)buf) + (inum % IPB);
|
||||
*dip = *ip;
|
||||
wsect(bn, buf);
|
||||
}
|
||||
|
||||
void
|
||||
rinode(uint inum, struct dinode *ip)
|
||||
{
|
||||
char buf[BSIZE];
|
||||
uint bn;
|
||||
struct dinode *dip;
|
||||
void rinode(uint inum, struct dinode *ip) {
|
||||
char buf[BSIZE];
|
||||
uint bn;
|
||||
struct dinode *dip;
|
||||
|
||||
bn = IBLOCK(inum, sb);
|
||||
rsect(bn, buf);
|
||||
dip = ((struct dinode*)buf) + (inum % IPB);
|
||||
*ip = *dip;
|
||||
bn = IBLOCK(inum, sb);
|
||||
rsect(bn, buf);
|
||||
dip = ((struct dinode *)buf) + (inum % IPB);
|
||||
*ip = *dip;
|
||||
}
|
||||
|
||||
void
|
||||
rsect(uint sec, void *buf)
|
||||
{
|
||||
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
|
||||
die("lseek");
|
||||
if(read(fsfd, buf, BSIZE) != BSIZE)
|
||||
die("read");
|
||||
void rsect(uint sec, void *buf) {
|
||||
if (lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
|
||||
die("lseek");
|
||||
if (read(fsfd, buf, BSIZE) != BSIZE)
|
||||
die("read");
|
||||
}
|
||||
|
||||
uint
|
||||
ialloc(ushort type)
|
||||
{
|
||||
uint inum = freeinode++;
|
||||
struct dinode din;
|
||||
uint ialloc(ushort type) {
|
||||
uint inum = freeinode++;
|
||||
struct dinode din;
|
||||
|
||||
bzero(&din, sizeof(din));
|
||||
din.type = xshort(type);
|
||||
din.nlink = xshort(1);
|
||||
din.size = xint(0);
|
||||
winode(inum, &din);
|
||||
return inum;
|
||||
bzero(&din, sizeof(din));
|
||||
din.type = xshort(type);
|
||||
din.nlink = xshort(1);
|
||||
din.size = xint(0);
|
||||
winode(inum, &din);
|
||||
return inum;
|
||||
}
|
||||
|
||||
void
|
||||
balloc(int used)
|
||||
{
|
||||
uchar buf[BSIZE];
|
||||
int i;
|
||||
void balloc(int used) {
|
||||
uchar buf[BSIZE];
|
||||
int i;
|
||||
|
||||
printf("balloc: first %d blocks have been allocated\n", used);
|
||||
assert(used < BSIZE*8);
|
||||
bzero(buf, BSIZE);
|
||||
for(i = 0; i < used; i++){
|
||||
buf[i/8] = buf[i/8] | (0x1 << (i%8));
|
||||
}
|
||||
printf("balloc: write bitmap block at sector %d\n", sb.bmapstart);
|
||||
wsect(sb.bmapstart, buf);
|
||||
printf("balloc: first %d blocks have been allocated\n", used);
|
||||
assert(used < BSIZE * 8);
|
||||
bzero(buf, BSIZE);
|
||||
for (i = 0; i < used; i++) {
|
||||
buf[i / 8] = buf[i / 8] | (0x1 << (i % 8));
|
||||
}
|
||||
printf("balloc: write bitmap block at sector %d\n", sb.bmapstart);
|
||||
wsect(sb.bmapstart, buf);
|
||||
}
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
void
|
||||
iappend(uint inum, void *xp, int n)
|
||||
{
|
||||
char *p = (char*)xp;
|
||||
uint fbn, off, n1;
|
||||
struct dinode din;
|
||||
char buf[BSIZE];
|
||||
uint indirect[NINDIRECT];
|
||||
uint x;
|
||||
void iappend(uint inum, void *xp, int n) {
|
||||
char *p = (char *)xp;
|
||||
uint fbn, off, n1;
|
||||
struct dinode din;
|
||||
char buf[BSIZE];
|
||||
uint indirect[NINDIRECT];
|
||||
uint x;
|
||||
|
||||
rinode(inum, &din);
|
||||
off = xint(din.size);
|
||||
// printf("append inum %d at off %d sz %d\n", inum, off, n);
|
||||
while(n > 0){
|
||||
fbn = off / BSIZE;
|
||||
assert(fbn < MAXFILE);
|
||||
if(fbn < NDIRECT){
|
||||
if(xint(din.addrs[fbn]) == 0){
|
||||
din.addrs[fbn] = xint(freeblock++);
|
||||
}
|
||||
x = xint(din.addrs[fbn]);
|
||||
} else {
|
||||
if(xint(din.addrs[NDIRECT]) == 0){
|
||||
din.addrs[NDIRECT] = xint(freeblock++);
|
||||
}
|
||||
rsect(xint(din.addrs[NDIRECT]), (char*)indirect);
|
||||
if(indirect[fbn - NDIRECT] == 0){
|
||||
indirect[fbn - NDIRECT] = xint(freeblock++);
|
||||
wsect(xint(din.addrs[NDIRECT]), (char*)indirect);
|
||||
}
|
||||
x = xint(indirect[fbn-NDIRECT]);
|
||||
}
|
||||
n1 = min(n, (fbn + 1) * BSIZE - off);
|
||||
rsect(x, buf);
|
||||
bcopy(p, buf + off - (fbn * BSIZE), n1);
|
||||
wsect(x, buf);
|
||||
n -= n1;
|
||||
off += n1;
|
||||
p += n1;
|
||||
}
|
||||
din.size = xint(off);
|
||||
winode(inum, &din);
|
||||
rinode(inum, &din);
|
||||
off = xint(din.size);
|
||||
// printf("append inum %d at off %d sz %d\n", inum, off, n);
|
||||
while (n > 0) {
|
||||
fbn = off / BSIZE;
|
||||
assert(fbn < MAXFILE);
|
||||
if (fbn < NDIRECT) {
|
||||
if (xint(din.addrs[fbn]) == 0) {
|
||||
din.addrs[fbn] = xint(freeblock++);
|
||||
}
|
||||
x = xint(din.addrs[fbn]);
|
||||
} else {
|
||||
if (xint(din.addrs[NDIRECT]) == 0) {
|
||||
din.addrs[NDIRECT] = xint(freeblock++);
|
||||
}
|
||||
rsect(xint(din.addrs[NDIRECT]), (char *)indirect);
|
||||
if (indirect[fbn - NDIRECT] == 0) {
|
||||
indirect[fbn - NDIRECT] = xint(freeblock++);
|
||||
wsect(xint(din.addrs[NDIRECT]), (char *)indirect);
|
||||
}
|
||||
x = xint(indirect[fbn - NDIRECT]);
|
||||
}
|
||||
n1 = min(n, (fbn + 1) * BSIZE - off);
|
||||
rsect(x, buf);
|
||||
bcopy(p, buf + off - (fbn * BSIZE), n1);
|
||||
wsect(x, buf);
|
||||
n -= n1;
|
||||
off += n1;
|
||||
p += n1;
|
||||
}
|
||||
din.size = xint(off);
|
||||
winode(inum, &din);
|
||||
}
|
||||
|
||||
void
|
||||
die(const char *s)
|
||||
{
|
||||
perror(s);
|
||||
exit(1);
|
||||
void die(const char *s) {
|
||||
perror(s);
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
|
|
@ -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"
|
||||
|
|
@ -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]
|
||||
|
|
@ -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 {}
|
||||
}
|
||||
58
user/cat.c
58
user/cat.c
|
|
@ -4,40 +4,36 @@
|
|||
|
||||
char buf[512];
|
||||
|
||||
void
|
||||
cat(int fd)
|
||||
{
|
||||
int n;
|
||||
void cat(int fd) {
|
||||
int n;
|
||||
|
||||
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
if (write(1, buf, n) != n) {
|
||||
fprintf(2, "cat: write error\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if(n < 0){
|
||||
fprintf(2, "cat: read error\n");
|
||||
exit(1);
|
||||
}
|
||||
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
if (write(1, buf, n) != n) {
|
||||
fprintf(2, "cat: write error\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (n < 0) {
|
||||
fprintf(2, "cat: read error\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd, i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int fd, i;
|
||||
|
||||
if(argc <= 1){
|
||||
cat(0);
|
||||
exit(0);
|
||||
}
|
||||
if (argc <= 1) {
|
||||
cat(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
fprintf(2, "cat: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
cat(fd);
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
for (i = 1; i < argc; i++) {
|
||||
if ((fd = open(argv[i], 0)) < 0) {
|
||||
fprintf(2, "cat: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
cat(fd);
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
24
user/echo.c
24
user/echo.c
|
|
@ -2,18 +2,16 @@
|
|||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
write(1, argv[i], strlen(argv[i]));
|
||||
if(i + 1 < argc){
|
||||
write(1, " ", 1);
|
||||
} else {
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
for (i = 1; i < argc; i++) {
|
||||
write(1, argv[i], strlen(argv[i]));
|
||||
if (i + 1 < argc) {
|
||||
write(1, " ", 1);
|
||||
} else {
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,52 +5,44 @@
|
|||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
|
||||
#define N 1000
|
||||
#define N 1000
|
||||
|
||||
void
|
||||
print(const char *s)
|
||||
{
|
||||
write(1, s, strlen(s));
|
||||
void print(const char *s) { write(1, s, strlen(s)); }
|
||||
|
||||
void forktest(void) {
|
||||
int n, pid;
|
||||
|
||||
print("fork test\n");
|
||||
|
||||
for (n = 0; n < N; n++) {
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
break;
|
||||
if (pid == 0)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (n == N) {
|
||||
print("fork claimed to work N times!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (; n > 0; n--) {
|
||||
if (wait(0) < 0) {
|
||||
print("wait stopped early\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (wait(0) != -1) {
|
||||
print("wait got too many\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
print("fork test OK\n");
|
||||
}
|
||||
|
||||
void
|
||||
forktest(void)
|
||||
{
|
||||
int n, pid;
|
||||
|
||||
print("fork test\n");
|
||||
|
||||
for(n=0; n<N; n++){
|
||||
pid = fork();
|
||||
if(pid < 0)
|
||||
break;
|
||||
if(pid == 0)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(n == N){
|
||||
print("fork claimed to work N times!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(; n > 0; n--){
|
||||
if(wait(0) < 0){
|
||||
print("wait stopped early\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(wait(0) != -1){
|
||||
print("wait got too many\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
print("fork test OK\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
forktest();
|
||||
exit(0);
|
||||
int main(void) {
|
||||
forktest();
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
147
user/grep.c
147
user/grep.c
|
|
@ -5,102 +5,93 @@
|
|||
#include "user/user.h"
|
||||
|
||||
char buf[1024];
|
||||
int match(char*, char*);
|
||||
int match(char *, char *);
|
||||
|
||||
void
|
||||
grep(char *pattern, int fd)
|
||||
{
|
||||
int n, m;
|
||||
char *p, *q;
|
||||
void grep(char *pattern, int fd) {
|
||||
int n, m;
|
||||
char *p, *q;
|
||||
|
||||
m = 0;
|
||||
while((n = read(fd, buf+m, sizeof(buf)-m-1)) > 0){
|
||||
m += n;
|
||||
buf[m] = '\0';
|
||||
p = buf;
|
||||
while((q = strchr(p, '\n')) != 0){
|
||||
*q = 0;
|
||||
if(match(pattern, p)){
|
||||
*q = '\n';
|
||||
write(1, p, q+1 - p);
|
||||
}
|
||||
p = q+1;
|
||||
}
|
||||
if(m > 0){
|
||||
m -= p - buf;
|
||||
memmove(buf, p, m);
|
||||
}
|
||||
}
|
||||
m = 0;
|
||||
while ((n = read(fd, buf + m, sizeof(buf) - m - 1)) > 0) {
|
||||
m += n;
|
||||
buf[m] = '\0';
|
||||
p = buf;
|
||||
while ((q = strchr(p, '\n')) != 0) {
|
||||
*q = 0;
|
||||
if (match(pattern, p)) {
|
||||
*q = '\n';
|
||||
write(1, p, q + 1 - p);
|
||||
}
|
||||
p = q + 1;
|
||||
}
|
||||
if (m > 0) {
|
||||
m -= p - buf;
|
||||
memmove(buf, p, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd, i;
|
||||
char *pattern;
|
||||
int main(int argc, char *argv[]) {
|
||||
int fd, i;
|
||||
char *pattern;
|
||||
|
||||
if(argc <= 1){
|
||||
fprintf(2, "usage: grep pattern [file ...]\n");
|
||||
exit(1);
|
||||
}
|
||||
pattern = argv[1];
|
||||
if (argc <= 1) {
|
||||
fprintf(2, "usage: grep pattern [file ...]\n");
|
||||
exit(1);
|
||||
}
|
||||
pattern = argv[1];
|
||||
|
||||
if(argc <= 2){
|
||||
grep(pattern, 0);
|
||||
exit(0);
|
||||
}
|
||||
if (argc <= 2) {
|
||||
grep(pattern, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(i = 2; i < argc; i++){
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
printf("grep: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
grep(pattern, fd);
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
for (i = 2; i < argc; i++) {
|
||||
if ((fd = open(argv[i], 0)) < 0) {
|
||||
printf("grep: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
grep(pattern, fd);
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Regexp matcher from Kernighan & Pike,
|
||||
// The Practice of Programming, Chapter 9, or
|
||||
// https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
|
||||
|
||||
int matchhere(char*, char*);
|
||||
int matchstar(int, char*, char*);
|
||||
int matchhere(char *, char *);
|
||||
int matchstar(int, char *, char *);
|
||||
|
||||
int
|
||||
match(char *re, char *text)
|
||||
{
|
||||
if(re[0] == '^')
|
||||
return matchhere(re+1, text);
|
||||
do{ // must look at empty string
|
||||
if(matchhere(re, text))
|
||||
return 1;
|
||||
}while(*text++ != '\0');
|
||||
return 0;
|
||||
int match(char *re, char *text) {
|
||||
if (re[0] == '^')
|
||||
return matchhere(re + 1, text);
|
||||
do { // must look at empty string
|
||||
if (matchhere(re, text))
|
||||
return 1;
|
||||
} while (*text++ != '\0');
|
||||
return 0;
|
||||
}
|
||||
|
||||
// matchhere: search for re at beginning of text
|
||||
int matchhere(char *re, char *text)
|
||||
{
|
||||
if(re[0] == '\0')
|
||||
return 1;
|
||||
if(re[1] == '*')
|
||||
return matchstar(re[0], re+2, text);
|
||||
if(re[0] == '$' && re[1] == '\0')
|
||||
return *text == '\0';
|
||||
if(*text!='\0' && (re[0]=='.' || re[0]==*text))
|
||||
return matchhere(re+1, text+1);
|
||||
return 0;
|
||||
int matchhere(char *re, char *text) {
|
||||
if (re[0] == '\0')
|
||||
return 1;
|
||||
if (re[1] == '*')
|
||||
return matchstar(re[0], re + 2, text);
|
||||
if (re[0] == '$' && re[1] == '\0')
|
||||
return *text == '\0';
|
||||
if (*text != '\0' && (re[0] == '.' || re[0] == *text))
|
||||
return matchhere(re + 1, text + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// matchstar: search for c*re at beginning of text
|
||||
int matchstar(int c, char *re, char *text)
|
||||
{
|
||||
do{ // a * matches zero or more instances
|
||||
if(matchhere(re, text))
|
||||
return 1;
|
||||
}while(*text!='\0' && (*text++==c || c=='.'));
|
||||
return 0;
|
||||
int matchstar(int c, char *re, char *text) {
|
||||
do { // a * matches zero or more instances
|
||||
if (matchhere(re, text))
|
||||
return 1;
|
||||
} while (*text != '\0' && (*text++ == c || c == '.'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
638
user/grind.c
638
user/grind.c
|
|
@ -13,338 +13,328 @@
|
|||
#include "kernel/riscv.h"
|
||||
|
||||
// from FreeBSD.
|
||||
int
|
||||
do_rand(unsigned long *ctx)
|
||||
{
|
||||
/*
|
||||
* Compute x = (7^5 * x) mod (2^31 - 1)
|
||||
* without overflowing 31 bits:
|
||||
* (2^31 - 1) = 127773 * (7^5) + 2836
|
||||
* From "Random number generators: good ones are hard to find",
|
||||
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||||
* October 1988, p. 1195.
|
||||
*/
|
||||
long hi, lo, x;
|
||||
int do_rand(unsigned long *ctx) {
|
||||
/*
|
||||
* Compute x = (7^5 * x) mod (2^31 - 1)
|
||||
* without overflowing 31 bits:
|
||||
* (2^31 - 1) = 127773 * (7^5) + 2836
|
||||
* From "Random number generators: good ones are hard to find",
|
||||
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||||
* October 1988, p. 1195.
|
||||
*/
|
||||
long hi, lo, x;
|
||||
|
||||
/* Transform to [1, 0x7ffffffe] range. */
|
||||
x = (*ctx % 0x7ffffffe) + 1;
|
||||
hi = x / 127773;
|
||||
lo = x % 127773;
|
||||
x = 16807 * lo - 2836 * hi;
|
||||
if (x < 0)
|
||||
x += 0x7fffffff;
|
||||
/* Transform to [0, 0x7ffffffd] range. */
|
||||
x--;
|
||||
*ctx = x;
|
||||
return (x);
|
||||
/* Transform to [1, 0x7ffffffe] range. */
|
||||
x = (*ctx % 0x7ffffffe) + 1;
|
||||
hi = x / 127773;
|
||||
lo = x % 127773;
|
||||
x = 16807 * lo - 2836 * hi;
|
||||
if (x < 0)
|
||||
x += 0x7fffffff;
|
||||
/* Transform to [0, 0x7ffffffd] range. */
|
||||
x--;
|
||||
*ctx = x;
|
||||
return (x);
|
||||
}
|
||||
|
||||
unsigned long rand_next = 1;
|
||||
|
||||
int
|
||||
rand(void)
|
||||
{
|
||||
return (do_rand(&rand_next));
|
||||
int rand(void) { return (do_rand(&rand_next)); }
|
||||
|
||||
void go(int which_child) {
|
||||
int fd = -1;
|
||||
static char buf[999];
|
||||
char *break0 = sbrk(0);
|
||||
uint64 iters = 0;
|
||||
|
||||
mkdir("grindir");
|
||||
if (chdir("grindir") != 0) {
|
||||
printf("grind: chdir grindir failed\n");
|
||||
exit(1);
|
||||
}
|
||||
chdir("/");
|
||||
|
||||
while (1) {
|
||||
iters++;
|
||||
if ((iters % 500) == 0)
|
||||
write(1, which_child ? "B" : "A", 1);
|
||||
int what = rand() % 23;
|
||||
if (what == 1) {
|
||||
close(open("grindir/../a", O_CREATE | O_RDWR));
|
||||
} else if (what == 2) {
|
||||
close(open("grindir/../grindir/../b", O_CREATE | O_RDWR));
|
||||
} else if (what == 3) {
|
||||
unlink("grindir/../a");
|
||||
} else if (what == 4) {
|
||||
if (chdir("grindir") != 0) {
|
||||
printf("grind: chdir grindir failed\n");
|
||||
exit(1);
|
||||
}
|
||||
unlink("../b");
|
||||
chdir("/");
|
||||
} else if (what == 5) {
|
||||
close(fd);
|
||||
fd = open("/grindir/../a", O_CREATE | O_RDWR);
|
||||
} else if (what == 6) {
|
||||
close(fd);
|
||||
fd = open("/./grindir/./../b", O_CREATE | O_RDWR);
|
||||
} else if (what == 7) {
|
||||
write(fd, buf, sizeof(buf));
|
||||
} else if (what == 8) {
|
||||
read(fd, buf, sizeof(buf));
|
||||
} else if (what == 9) {
|
||||
mkdir("grindir/../a");
|
||||
close(open("a/../a/./a", O_CREATE | O_RDWR));
|
||||
unlink("a/a");
|
||||
} else if (what == 10) {
|
||||
mkdir("/../b");
|
||||
close(open("grindir/../b/b", O_CREATE | O_RDWR));
|
||||
unlink("b/b");
|
||||
} else if (what == 11) {
|
||||
unlink("b");
|
||||
link("../grindir/./../a", "../b");
|
||||
} else if (what == 12) {
|
||||
unlink("../grindir/../a");
|
||||
link(".././b", "/grindir/../a");
|
||||
} else if (what == 13) {
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
exit(0);
|
||||
} else if (pid < 0) {
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if (what == 14) {
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
fork();
|
||||
fork();
|
||||
exit(0);
|
||||
} else if (pid < 0) {
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if (what == 15) {
|
||||
sbrk(6011);
|
||||
} else if (what == 16) {
|
||||
if (sbrk(0) > break0)
|
||||
sbrk(-(sbrk(0) - break0));
|
||||
} else if (what == 17) {
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
close(open("a", O_CREATE | O_RDWR));
|
||||
exit(0);
|
||||
} else if (pid < 0) {
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (chdir("../grindir/..") != 0) {
|
||||
printf("grind: chdir failed\n");
|
||||
exit(1);
|
||||
}
|
||||
kill(pid);
|
||||
wait(0);
|
||||
} else if (what == 18) {
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
kill(getpid());
|
||||
exit(0);
|
||||
} else if (pid < 0) {
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if (what == 19) {
|
||||
int fds[2];
|
||||
if (pipe(fds) < 0) {
|
||||
printf("grind: pipe failed\n");
|
||||
exit(1);
|
||||
}
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
fork();
|
||||
fork();
|
||||
if (write(fds[1], "x", 1) != 1)
|
||||
printf("grind: pipe write failed\n");
|
||||
char c;
|
||||
if (read(fds[0], &c, 1) != 1)
|
||||
printf("grind: pipe read failed\n");
|
||||
exit(0);
|
||||
} else if (pid < 0) {
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
wait(0);
|
||||
} else if (what == 20) {
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
unlink("a");
|
||||
mkdir("a");
|
||||
chdir("a");
|
||||
unlink("../a");
|
||||
fd = open("x", O_CREATE | O_RDWR);
|
||||
unlink("x");
|
||||
exit(0);
|
||||
} else if (pid < 0) {
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if (what == 21) {
|
||||
unlink("c");
|
||||
// should always succeed. check that there are free i-nodes,
|
||||
// file descriptors, blocks.
|
||||
int fd1 = open("c", O_CREATE | O_RDWR);
|
||||
if (fd1 < 0) {
|
||||
printf("grind: create c failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (write(fd1, "x", 1) != 1) {
|
||||
printf("grind: write c failed\n");
|
||||
exit(1);
|
||||
}
|
||||
struct stat st;
|
||||
if (fstat(fd1, &st) != 0) {
|
||||
printf("grind: fstat failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (st.size != 1) {
|
||||
printf("grind: fstat reports wrong size %d\n", (int)st.size);
|
||||
exit(1);
|
||||
}
|
||||
if (st.ino > 200) {
|
||||
printf("grind: fstat reports crazy i-number %d\n", st.ino);
|
||||
exit(1);
|
||||
}
|
||||
close(fd1);
|
||||
unlink("c");
|
||||
} else if (what == 22) {
|
||||
// echo hi | cat
|
||||
int aa[2], bb[2];
|
||||
if (pipe(aa) < 0) {
|
||||
fprintf(2, "grind: pipe failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pipe(bb) < 0) {
|
||||
fprintf(2, "grind: pipe failed\n");
|
||||
exit(1);
|
||||
}
|
||||
int pid1 = fork();
|
||||
if (pid1 == 0) {
|
||||
close(bb[0]);
|
||||
close(bb[1]);
|
||||
close(aa[0]);
|
||||
close(1);
|
||||
if (dup(aa[1]) != 1) {
|
||||
fprintf(2, "grind: dup failed\n");
|
||||
exit(1);
|
||||
}
|
||||
close(aa[1]);
|
||||
char *args[3] = {"echo", "hi", 0};
|
||||
exec("grindir/../echo", args);
|
||||
fprintf(2, "grind: echo: not found\n");
|
||||
exit(2);
|
||||
} else if (pid1 < 0) {
|
||||
fprintf(2, "grind: fork failed\n");
|
||||
exit(3);
|
||||
}
|
||||
int pid2 = fork();
|
||||
if (pid2 == 0) {
|
||||
close(aa[1]);
|
||||
close(bb[0]);
|
||||
close(0);
|
||||
if (dup(aa[0]) != 0) {
|
||||
fprintf(2, "grind: dup failed\n");
|
||||
exit(4);
|
||||
}
|
||||
close(aa[0]);
|
||||
close(1);
|
||||
if (dup(bb[1]) != 1) {
|
||||
fprintf(2, "grind: dup failed\n");
|
||||
exit(5);
|
||||
}
|
||||
close(bb[1]);
|
||||
char *args[2] = {"cat", 0};
|
||||
exec("/cat", args);
|
||||
fprintf(2, "grind: cat: not found\n");
|
||||
exit(6);
|
||||
} else if (pid2 < 0) {
|
||||
fprintf(2, "grind: fork failed\n");
|
||||
exit(7);
|
||||
}
|
||||
close(aa[0]);
|
||||
close(aa[1]);
|
||||
close(bb[1]);
|
||||
char buf[4] = {0, 0, 0, 0};
|
||||
read(bb[0], buf + 0, 1);
|
||||
read(bb[0], buf + 1, 1);
|
||||
read(bb[0], buf + 2, 1);
|
||||
close(bb[0]);
|
||||
int st1, st2;
|
||||
wait(&st1);
|
||||
wait(&st2);
|
||||
if (st1 != 0 || st2 != 0 || strcmp(buf, "hi\n") != 0) {
|
||||
printf("grind: exec pipeline failed %d %d \"%s\"\n", st1, st2,
|
||||
buf);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
go(int which_child)
|
||||
{
|
||||
int fd = -1;
|
||||
static char buf[999];
|
||||
char *break0 = sbrk(0);
|
||||
uint64 iters = 0;
|
||||
void iter() {
|
||||
unlink("a");
|
||||
unlink("b");
|
||||
|
||||
mkdir("grindir");
|
||||
if(chdir("grindir") != 0){
|
||||
printf("grind: chdir grindir failed\n");
|
||||
exit(1);
|
||||
}
|
||||
chdir("/");
|
||||
|
||||
while(1){
|
||||
iters++;
|
||||
if((iters % 500) == 0)
|
||||
write(1, which_child?"B":"A", 1);
|
||||
int what = rand() % 23;
|
||||
if(what == 1){
|
||||
close(open("grindir/../a", O_CREATE|O_RDWR));
|
||||
} else if(what == 2){
|
||||
close(open("grindir/../grindir/../b", O_CREATE|O_RDWR));
|
||||
} else if(what == 3){
|
||||
unlink("grindir/../a");
|
||||
} else if(what == 4){
|
||||
if(chdir("grindir") != 0){
|
||||
printf("grind: chdir grindir failed\n");
|
||||
exit(1);
|
||||
}
|
||||
unlink("../b");
|
||||
chdir("/");
|
||||
} else if(what == 5){
|
||||
close(fd);
|
||||
fd = open("/grindir/../a", O_CREATE|O_RDWR);
|
||||
} else if(what == 6){
|
||||
close(fd);
|
||||
fd = open("/./grindir/./../b", O_CREATE|O_RDWR);
|
||||
} else if(what == 7){
|
||||
write(fd, buf, sizeof(buf));
|
||||
} else if(what == 8){
|
||||
read(fd, buf, sizeof(buf));
|
||||
} else if(what == 9){
|
||||
mkdir("grindir/../a");
|
||||
close(open("a/../a/./a", O_CREATE|O_RDWR));
|
||||
unlink("a/a");
|
||||
} else if(what == 10){
|
||||
mkdir("/../b");
|
||||
close(open("grindir/../b/b", O_CREATE|O_RDWR));
|
||||
unlink("b/b");
|
||||
} else if(what == 11){
|
||||
unlink("b");
|
||||
link("../grindir/./../a", "../b");
|
||||
} else if(what == 12){
|
||||
unlink("../grindir/../a");
|
||||
link(".././b", "/grindir/../a");
|
||||
} else if(what == 13){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if(what == 14){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
fork();
|
||||
fork();
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if(what == 15){
|
||||
sbrk(6011);
|
||||
} else if(what == 16){
|
||||
if(sbrk(0) > break0)
|
||||
sbrk(-(sbrk(0) - break0));
|
||||
} else if(what == 17){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
close(open("a", O_CREATE|O_RDWR));
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(chdir("../grindir/..") != 0){
|
||||
printf("grind: chdir failed\n");
|
||||
exit(1);
|
||||
}
|
||||
kill(pid);
|
||||
wait(0);
|
||||
} else if(what == 18){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
kill(getpid());
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if(what == 19){
|
||||
int fds[2];
|
||||
if(pipe(fds) < 0){
|
||||
printf("grind: pipe failed\n");
|
||||
exit(1);
|
||||
}
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
fork();
|
||||
fork();
|
||||
if(write(fds[1], "x", 1) != 1)
|
||||
printf("grind: pipe write failed\n");
|
||||
char c;
|
||||
if(read(fds[0], &c, 1) != 1)
|
||||
printf("grind: pipe read failed\n");
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
wait(0);
|
||||
} else if(what == 20){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
unlink("a");
|
||||
mkdir("a");
|
||||
chdir("a");
|
||||
unlink("../a");
|
||||
fd = open("x", O_CREATE|O_RDWR);
|
||||
unlink("x");
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if(what == 21){
|
||||
unlink("c");
|
||||
// should always succeed. check that there are free i-nodes,
|
||||
// file descriptors, blocks.
|
||||
int fd1 = open("c", O_CREATE|O_RDWR);
|
||||
if(fd1 < 0){
|
||||
printf("grind: create c failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(write(fd1, "x", 1) != 1){
|
||||
printf("grind: write c failed\n");
|
||||
exit(1);
|
||||
}
|
||||
struct stat st;
|
||||
if(fstat(fd1, &st) != 0){
|
||||
printf("grind: fstat failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(st.size != 1){
|
||||
printf("grind: fstat reports wrong size %d\n", (int)st.size);
|
||||
exit(1);
|
||||
}
|
||||
if(st.ino > 200){
|
||||
printf("grind: fstat reports crazy i-number %d\n", st.ino);
|
||||
exit(1);
|
||||
}
|
||||
close(fd1);
|
||||
unlink("c");
|
||||
} else if(what == 22){
|
||||
// echo hi | cat
|
||||
int aa[2], bb[2];
|
||||
if(pipe(aa) < 0){
|
||||
fprintf(2, "grind: pipe failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(pipe(bb) < 0){
|
||||
fprintf(2, "grind: pipe failed\n");
|
||||
exit(1);
|
||||
}
|
||||
int pid1 = fork();
|
||||
if(pid1 == 0){
|
||||
close(bb[0]);
|
||||
close(bb[1]);
|
||||
close(aa[0]);
|
||||
close(1);
|
||||
if(dup(aa[1]) != 1){
|
||||
fprintf(2, "grind: dup failed\n");
|
||||
exit(1);
|
||||
}
|
||||
close(aa[1]);
|
||||
char *args[3] = { "echo", "hi", 0 };
|
||||
exec("grindir/../echo", args);
|
||||
fprintf(2, "grind: echo: not found\n");
|
||||
exit(2);
|
||||
} else if(pid1 < 0){
|
||||
fprintf(2, "grind: fork failed\n");
|
||||
exit(3);
|
||||
}
|
||||
int pid2 = fork();
|
||||
if(pid2 == 0){
|
||||
close(aa[1]);
|
||||
close(bb[0]);
|
||||
close(0);
|
||||
if(dup(aa[0]) != 0){
|
||||
fprintf(2, "grind: dup failed\n");
|
||||
exit(4);
|
||||
}
|
||||
close(aa[0]);
|
||||
close(1);
|
||||
if(dup(bb[1]) != 1){
|
||||
fprintf(2, "grind: dup failed\n");
|
||||
exit(5);
|
||||
}
|
||||
close(bb[1]);
|
||||
char *args[2] = { "cat", 0 };
|
||||
exec("/cat", args);
|
||||
fprintf(2, "grind: cat: not found\n");
|
||||
exit(6);
|
||||
} else if(pid2 < 0){
|
||||
fprintf(2, "grind: fork failed\n");
|
||||
exit(7);
|
||||
}
|
||||
close(aa[0]);
|
||||
close(aa[1]);
|
||||
close(bb[1]);
|
||||
char buf[4] = { 0, 0, 0, 0 };
|
||||
read(bb[0], buf+0, 1);
|
||||
read(bb[0], buf+1, 1);
|
||||
read(bb[0], buf+2, 1);
|
||||
close(bb[0]);
|
||||
int st1, st2;
|
||||
wait(&st1);
|
||||
wait(&st2);
|
||||
if(st1 != 0 || st2 != 0 || strcmp(buf, "hi\n") != 0){
|
||||
printf("grind: exec pipeline failed %d %d \"%s\"\n", st1, st2, buf);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
int pid1 = fork();
|
||||
if (pid1 < 0) {
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pid1 == 0) {
|
||||
rand_next ^= 31;
|
||||
go(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int pid2 = fork();
|
||||
if (pid2 < 0) {
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pid2 == 0) {
|
||||
rand_next ^= 7177;
|
||||
go(1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int st1 = -1;
|
||||
wait(&st1);
|
||||
if (st1 != 0) {
|
||||
kill(pid1);
|
||||
kill(pid2);
|
||||
}
|
||||
int st2 = -1;
|
||||
wait(&st2);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
iter()
|
||||
{
|
||||
unlink("a");
|
||||
unlink("b");
|
||||
|
||||
int pid1 = fork();
|
||||
if(pid1 < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(pid1 == 0){
|
||||
rand_next = 31;
|
||||
go(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int pid2 = fork();
|
||||
if(pid2 < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(pid2 == 0){
|
||||
rand_next = 7177;
|
||||
go(1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int st1 = -1;
|
||||
wait(&st1);
|
||||
if(st1 != 0){
|
||||
kill(pid1);
|
||||
kill(pid2);
|
||||
}
|
||||
int st2 = -1;
|
||||
wait(&st2);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
while(1){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
iter();
|
||||
exit(0);
|
||||
}
|
||||
if(pid > 0){
|
||||
wait(0);
|
||||
}
|
||||
sleep(20);
|
||||
}
|
||||
int main() {
|
||||
while (1) {
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
iter();
|
||||
exit(0);
|
||||
}
|
||||
if (pid > 0) {
|
||||
wait(0);
|
||||
}
|
||||
sleep(20);
|
||||
rand_next += 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
74
user/init.c
74
user/init.c
|
|
@ -9,46 +9,44 @@
|
|||
#include "user/user.h"
|
||||
#include "kernel/fcntl.h"
|
||||
|
||||
char *argv[] = { "sh", 0 };
|
||||
char *argv[] = {"sh", 0};
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int pid, wpid;
|
||||
int main(void) {
|
||||
int pid, wpid;
|
||||
|
||||
if(open("console", O_RDWR) < 0){
|
||||
mknod("console", CONSOLE, 0);
|
||||
open("console", O_RDWR);
|
||||
}
|
||||
dup(0); // stdout
|
||||
dup(0); // stderr
|
||||
if (open("console", O_RDWR) < 0) {
|
||||
mknod("console", CONSOLE, 0);
|
||||
open("console", O_RDWR);
|
||||
}
|
||||
dup(0); // stdout
|
||||
dup(0); // stderr
|
||||
|
||||
for(;;){
|
||||
printf("init: starting sh\n");
|
||||
pid = fork();
|
||||
if(pid < 0){
|
||||
printf("init: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(pid == 0){
|
||||
exec("sh", argv);
|
||||
printf("init: exec sh failed\n");
|
||||
exit(1);
|
||||
}
|
||||
for (;;) {
|
||||
printf("init: starting sh\n");
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
printf("init: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pid == 0) {
|
||||
exec("sh", argv);
|
||||
printf("init: exec sh failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(;;){
|
||||
// this call to wait() returns if the shell exits,
|
||||
// or if a parentless process exits.
|
||||
wpid = wait((int *) 0);
|
||||
if(wpid == pid){
|
||||
// the shell exited; restart it.
|
||||
break;
|
||||
} else if(wpid < 0){
|
||||
printf("init: wait returned an error\n");
|
||||
exit(1);
|
||||
} else {
|
||||
// it was a parentless process; do nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
// this call to wait() returns if the shell exits,
|
||||
// or if a parentless process exits.
|
||||
wpid = wait((int *)0);
|
||||
if (wpid == pid) {
|
||||
// the shell exited; restart it.
|
||||
break;
|
||||
} else if (wpid < 0) {
|
||||
printf("init: wait returned an error\n");
|
||||
exit(1);
|
||||
} else {
|
||||
// it was a parentless process; do nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
user/kill.c
20
user/kill.c
|
|
@ -2,16 +2,14 @@
|
|||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(2, "usage: kill pid...\n");
|
||||
exit(1);
|
||||
}
|
||||
for(i=1; i<argc; i++)
|
||||
kill(atoi(argv[i]));
|
||||
exit(0);
|
||||
if (argc < 2) {
|
||||
fprintf(2, "usage: kill pid...\n");
|
||||
exit(1);
|
||||
}
|
||||
for (i = 1; i < argc; i++)
|
||||
kill(atoi(argv[i]));
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
18
user/ln.c
18
user/ln.c
|
|
@ -2,14 +2,12 @@
|
|||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if(argc != 3){
|
||||
fprintf(2, "Usage: ln old new\n");
|
||||
exit(1);
|
||||
}
|
||||
if(link(argv[1], argv[2]) < 0)
|
||||
fprintf(2, "link %s %s: failed\n", argv[1], argv[2]);
|
||||
exit(0);
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
fprintf(2, "Usage: ln old new\n");
|
||||
exit(1);
|
||||
}
|
||||
if (link(argv[1], argv[2]) < 0)
|
||||
fprintf(2, "link %s %s: failed\n", argv[1], argv[2]);
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
132
user/ls.c
132
user/ls.c
|
|
@ -3,84 +3,78 @@
|
|||
#include "user/user.h"
|
||||
#include "kernel/fs.h"
|
||||
|
||||
char*
|
||||
fmtname(char *path)
|
||||
{
|
||||
static char buf[DIRSIZ+1];
|
||||
char *p;
|
||||
char *fmtname(char *path) {
|
||||
static char buf[DIRSIZ + 1];
|
||||
char *p;
|
||||
|
||||
// Find first character after last slash.
|
||||
for(p=path+strlen(path); p >= path && *p != '/'; p--)
|
||||
;
|
||||
p++;
|
||||
// Find first character after last slash.
|
||||
for (p = path + strlen(path); p >= path && *p != '/'; p--)
|
||||
;
|
||||
p++;
|
||||
|
||||
// Return blank-padded name.
|
||||
if(strlen(p) >= DIRSIZ)
|
||||
return p;
|
||||
memmove(buf, p, strlen(p));
|
||||
memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
|
||||
return buf;
|
||||
// Return blank-padded name.
|
||||
if (strlen(p) >= DIRSIZ)
|
||||
return p;
|
||||
memmove(buf, p, strlen(p));
|
||||
memset(buf + strlen(p), ' ', DIRSIZ - strlen(p));
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
ls(char *path)
|
||||
{
|
||||
char buf[512], *p;
|
||||
int fd;
|
||||
struct dirent de;
|
||||
struct stat st;
|
||||
void ls(char *path) {
|
||||
char buf[512], *p;
|
||||
int fd;
|
||||
struct dirent de;
|
||||
struct stat st;
|
||||
|
||||
if((fd = open(path, 0)) < 0){
|
||||
fprintf(2, "ls: cannot open %s\n", path);
|
||||
return;
|
||||
}
|
||||
if ((fd = open(path, 0)) < 0) {
|
||||
fprintf(2, "ls: cannot open %s\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
if(fstat(fd, &st) < 0){
|
||||
fprintf(2, "ls: cannot stat %s\n", path);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if (fstat(fd, &st) < 0) {
|
||||
fprintf(2, "ls: cannot stat %s\n", path);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(st.type){
|
||||
case T_DEVICE:
|
||||
case T_FILE:
|
||||
printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);
|
||||
break;
|
||||
switch (st.type) {
|
||||
case T_DEVICE:
|
||||
case T_FILE:
|
||||
printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);
|
||||
break;
|
||||
|
||||
case T_DIR:
|
||||
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
|
||||
printf("ls: path too long\n");
|
||||
break;
|
||||
}
|
||||
strcpy(buf, path);
|
||||
p = buf+strlen(buf);
|
||||
*p++ = '/';
|
||||
while(read(fd, &de, sizeof(de)) == sizeof(de)){
|
||||
if(de.inum == 0)
|
||||
continue;
|
||||
memmove(p, de.name, DIRSIZ);
|
||||
p[DIRSIZ] = 0;
|
||||
if(stat(buf, &st) < 0){
|
||||
printf("ls: cannot stat %s\n", buf);
|
||||
continue;
|
||||
}
|
||||
printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
case T_DIR:
|
||||
if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
|
||||
printf("ls: path too long\n");
|
||||
break;
|
||||
}
|
||||
strcpy(buf, path);
|
||||
p = buf + strlen(buf);
|
||||
*p++ = '/';
|
||||
while (read(fd, &de, sizeof(de)) == sizeof(de)) {
|
||||
if (de.inum == 0)
|
||||
continue;
|
||||
memmove(p, de.name, DIRSIZ);
|
||||
p[DIRSIZ] = 0;
|
||||
if (stat(buf, &st) < 0) {
|
||||
printf("ls: cannot stat %s\n", buf);
|
||||
continue;
|
||||
}
|
||||
printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
if(argc < 2){
|
||||
ls(".");
|
||||
exit(0);
|
||||
}
|
||||
for(i=1; i<argc; i++)
|
||||
ls(argv[i]);
|
||||
exit(0);
|
||||
if (argc < 2) {
|
||||
ls(".");
|
||||
exit(0);
|
||||
}
|
||||
for (i = 1; i < argc; i++)
|
||||
ls(argv[i]);
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
28
user/mkdir.c
28
user/mkdir.c
|
|
@ -2,22 +2,20 @@
|
|||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(2, "Usage: mkdir files...\n");
|
||||
exit(1);
|
||||
}
|
||||
if (argc < 2) {
|
||||
fprintf(2, "Usage: mkdir files...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if(mkdir(argv[i]) < 0){
|
||||
fprintf(2, "mkdir: %s failed to create\n", argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (mkdir(argv[i]) < 0) {
|
||||
fprintf(2, "mkdir: %s failed to create\n", argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
171
user/printf.c
171
user/printf.c
|
|
@ -6,108 +6,95 @@
|
|||
|
||||
static char digits[] = "0123456789ABCDEF";
|
||||
|
||||
static void
|
||||
putc(int fd, char c)
|
||||
{
|
||||
write(fd, &c, 1);
|
||||
static void putc(int fd, char c) { write(fd, &c, 1); }
|
||||
|
||||
static void printint(int fd, int xx, int base, int sgn) {
|
||||
char buf[16];
|
||||
int i, neg;
|
||||
uint x;
|
||||
|
||||
neg = 0;
|
||||
if (sgn && xx < 0) {
|
||||
neg = 1;
|
||||
x = -xx;
|
||||
} else {
|
||||
x = xx;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
buf[i++] = digits[x % base];
|
||||
} while ((x /= base) != 0);
|
||||
if (neg)
|
||||
buf[i++] = '-';
|
||||
|
||||
while (--i >= 0)
|
||||
putc(fd, buf[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
printint(int fd, int xx, int base, int sgn)
|
||||
{
|
||||
char buf[16];
|
||||
int i, neg;
|
||||
uint x;
|
||||
|
||||
neg = 0;
|
||||
if(sgn && xx < 0){
|
||||
neg = 1;
|
||||
x = -xx;
|
||||
} else {
|
||||
x = xx;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
do{
|
||||
buf[i++] = digits[x % base];
|
||||
}while((x /= base) != 0);
|
||||
if(neg)
|
||||
buf[i++] = '-';
|
||||
|
||||
while(--i >= 0)
|
||||
putc(fd, buf[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
printptr(int fd, uint64 x) {
|
||||
int i;
|
||||
putc(fd, '0');
|
||||
putc(fd, 'x');
|
||||
for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
|
||||
putc(fd, digits[x >> (sizeof(uint64) * 8 - 4)]);
|
||||
static void printptr(int fd, uint64 x) {
|
||||
int i;
|
||||
putc(fd, '0');
|
||||
putc(fd, 'x');
|
||||
for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
|
||||
putc(fd, digits[x >> (sizeof(uint64) * 8 - 4)]);
|
||||
}
|
||||
|
||||
// Print to the given fd. Only understands %d, %x, %p, %s.
|
||||
void
|
||||
vprintf(int fd, const char *fmt, va_list ap)
|
||||
{
|
||||
char *s;
|
||||
int c, i, state;
|
||||
void vprintf(int fd, const char *fmt, va_list ap) {
|
||||
char *s;
|
||||
int c, i, state;
|
||||
|
||||
state = 0;
|
||||
for(i = 0; fmt[i]; i++){
|
||||
c = fmt[i] & 0xff;
|
||||
if(state == 0){
|
||||
if(c == '%'){
|
||||
state = '%';
|
||||
} else {
|
||||
putc(fd, c);
|
||||
}
|
||||
} else if(state == '%'){
|
||||
if(c == 'd'){
|
||||
printint(fd, va_arg(ap, int), 10, 1);
|
||||
} else if(c == 'l') {
|
||||
printint(fd, va_arg(ap, uint64), 10, 0);
|
||||
} else if(c == 'x') {
|
||||
printint(fd, va_arg(ap, int), 16, 0);
|
||||
} else if(c == 'p') {
|
||||
printptr(fd, va_arg(ap, uint64));
|
||||
} else if(c == 's'){
|
||||
s = va_arg(ap, char*);
|
||||
if(s == 0)
|
||||
s = "(null)";
|
||||
while(*s != 0){
|
||||
putc(fd, *s);
|
||||
s++;
|
||||
}
|
||||
} else if(c == 'c'){
|
||||
putc(fd, va_arg(ap, uint));
|
||||
} else if(c == '%'){
|
||||
putc(fd, c);
|
||||
} else {
|
||||
// Unknown % sequence. Print it to draw attention.
|
||||
putc(fd, '%');
|
||||
putc(fd, c);
|
||||
}
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
state = 0;
|
||||
for (i = 0; fmt[i]; i++) {
|
||||
c = fmt[i] & 0xff;
|
||||
if (state == 0) {
|
||||
if (c == '%') {
|
||||
state = '%';
|
||||
} else {
|
||||
putc(fd, c);
|
||||
}
|
||||
} else if (state == '%') {
|
||||
if (c == 'd') {
|
||||
printint(fd, va_arg(ap, int), 10, 1);
|
||||
} else if (c == 'l') {
|
||||
printint(fd, va_arg(ap, uint64), 10, 0);
|
||||
} else if (c == 'x') {
|
||||
printint(fd, va_arg(ap, int), 16, 0);
|
||||
} else if (c == 'p') {
|
||||
printptr(fd, va_arg(ap, uint64));
|
||||
} else if (c == 's') {
|
||||
s = va_arg(ap, char *);
|
||||
if (s == 0)
|
||||
s = "(null)";
|
||||
while (*s != 0) {
|
||||
putc(fd, *s);
|
||||
s++;
|
||||
}
|
||||
} else if (c == 'c') {
|
||||
putc(fd, va_arg(ap, uint));
|
||||
} else if (c == '%') {
|
||||
putc(fd, c);
|
||||
} else {
|
||||
// Unknown % sequence. Print it to draw attention.
|
||||
putc(fd, '%');
|
||||
putc(fd, c);
|
||||
}
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fprintf(int fd, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void fprintf(int fd, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(fd, fmt, ap);
|
||||
va_start(ap, fmt);
|
||||
vprintf(fd, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
printf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void printf(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(1, fmt, ap);
|
||||
va_start(ap, fmt);
|
||||
vprintf(1, fmt, ap);
|
||||
}
|
||||
|
|
|
|||
28
user/rm.c
28
user/rm.c
|
|
@ -2,22 +2,20 @@
|
|||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(2, "Usage: rm files...\n");
|
||||
exit(1);
|
||||
}
|
||||
if (argc < 2) {
|
||||
fprintf(2, "Usage: rm files...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if(unlink(argv[i]) < 0){
|
||||
fprintf(2, "rm: %s failed to delete\n", argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (unlink(argv[i]) < 0) {
|
||||
fprintf(2, "rm: %s failed to delete\n", argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
739
user/sh.c
739
user/sh.c
|
|
@ -5,490 +5,453 @@
|
|||
#include "kernel/fcntl.h"
|
||||
|
||||
// Parsed command representation
|
||||
#define EXEC 1
|
||||
#define EXEC 1
|
||||
#define REDIR 2
|
||||
#define PIPE 3
|
||||
#define LIST 4
|
||||
#define BACK 5
|
||||
#define PIPE 3
|
||||
#define LIST 4
|
||||
#define BACK 5
|
||||
|
||||
#define MAXARGS 10
|
||||
|
||||
struct cmd {
|
||||
int type;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct execcmd {
|
||||
int type;
|
||||
char *argv[MAXARGS];
|
||||
char *eargv[MAXARGS];
|
||||
int type;
|
||||
char *argv[MAXARGS];
|
||||
char *eargv[MAXARGS];
|
||||
};
|
||||
|
||||
struct redircmd {
|
||||
int type;
|
||||
struct cmd *cmd;
|
||||
char *file;
|
||||
char *efile;
|
||||
int mode;
|
||||
int fd;
|
||||
int type;
|
||||
struct cmd *cmd;
|
||||
char *file;
|
||||
char *efile;
|
||||
int mode;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct pipecmd {
|
||||
int type;
|
||||
struct cmd *left;
|
||||
struct cmd *right;
|
||||
int type;
|
||||
struct cmd *left;
|
||||
struct cmd *right;
|
||||
};
|
||||
|
||||
struct listcmd {
|
||||
int type;
|
||||
struct cmd *left;
|
||||
struct cmd *right;
|
||||
int type;
|
||||
struct cmd *left;
|
||||
struct cmd *right;
|
||||
};
|
||||
|
||||
struct backcmd {
|
||||
int type;
|
||||
struct cmd *cmd;
|
||||
int type;
|
||||
struct cmd *cmd;
|
||||
};
|
||||
|
||||
int fork1(void); // Fork but panics on failure.
|
||||
void panic(char*);
|
||||
struct cmd *parsecmd(char*);
|
||||
void runcmd(struct cmd*) __attribute__((noreturn));
|
||||
int fork1(void); // Fork but panics on failure.
|
||||
void panic(char *);
|
||||
struct cmd *parsecmd(char *);
|
||||
void runcmd(struct cmd *) __attribute__((noreturn));
|
||||
|
||||
// Execute cmd. Never returns.
|
||||
void
|
||||
runcmd(struct cmd *cmd)
|
||||
{
|
||||
int p[2];
|
||||
struct backcmd *bcmd;
|
||||
struct execcmd *ecmd;
|
||||
struct listcmd *lcmd;
|
||||
struct pipecmd *pcmd;
|
||||
struct redircmd *rcmd;
|
||||
void runcmd(struct cmd *cmd) {
|
||||
int p[2];
|
||||
struct backcmd *bcmd;
|
||||
struct execcmd *ecmd;
|
||||
struct listcmd *lcmd;
|
||||
struct pipecmd *pcmd;
|
||||
struct redircmd *rcmd;
|
||||
|
||||
if(cmd == 0)
|
||||
exit(1);
|
||||
if (cmd == 0)
|
||||
exit(1);
|
||||
|
||||
switch(cmd->type){
|
||||
default:
|
||||
panic("runcmd");
|
||||
switch (cmd->type) {
|
||||
default:
|
||||
panic("runcmd");
|
||||
|
||||
case EXEC:
|
||||
ecmd = (struct execcmd*)cmd;
|
||||
if(ecmd->argv[0] == 0)
|
||||
exit(1);
|
||||
exec(ecmd->argv[0], ecmd->argv);
|
||||
fprintf(2, "exec %s failed\n", ecmd->argv[0]);
|
||||
break;
|
||||
case EXEC:
|
||||
ecmd = (struct execcmd *)cmd;
|
||||
if (ecmd->argv[0] == 0)
|
||||
exit(1);
|
||||
exec(ecmd->argv[0], ecmd->argv);
|
||||
fprintf(2, "exec %s failed\n", ecmd->argv[0]);
|
||||
break;
|
||||
|
||||
case REDIR:
|
||||
rcmd = (struct redircmd*)cmd;
|
||||
close(rcmd->fd);
|
||||
if(open(rcmd->file, rcmd->mode) < 0){
|
||||
fprintf(2, "open %s failed\n", rcmd->file);
|
||||
exit(1);
|
||||
}
|
||||
runcmd(rcmd->cmd);
|
||||
break;
|
||||
case REDIR:
|
||||
rcmd = (struct redircmd *)cmd;
|
||||
close(rcmd->fd);
|
||||
if (open(rcmd->file, rcmd->mode) < 0) {
|
||||
fprintf(2, "open %s failed\n", rcmd->file);
|
||||
exit(1);
|
||||
}
|
||||
runcmd(rcmd->cmd);
|
||||
break;
|
||||
|
||||
case LIST:
|
||||
lcmd = (struct listcmd*)cmd;
|
||||
if(fork1() == 0)
|
||||
runcmd(lcmd->left);
|
||||
wait(0);
|
||||
runcmd(lcmd->right);
|
||||
break;
|
||||
case LIST:
|
||||
lcmd = (struct listcmd *)cmd;
|
||||
if (fork1() == 0)
|
||||
runcmd(lcmd->left);
|
||||
wait(0);
|
||||
runcmd(lcmd->right);
|
||||
break;
|
||||
|
||||
case PIPE:
|
||||
pcmd = (struct pipecmd*)cmd;
|
||||
if(pipe(p) < 0)
|
||||
panic("pipe");
|
||||
if(fork1() == 0){
|
||||
close(1);
|
||||
dup(p[1]);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
runcmd(pcmd->left);
|
||||
}
|
||||
if(fork1() == 0){
|
||||
close(0);
|
||||
dup(p[0]);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
runcmd(pcmd->right);
|
||||
}
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
wait(0);
|
||||
wait(0);
|
||||
break;
|
||||
case PIPE:
|
||||
pcmd = (struct pipecmd *)cmd;
|
||||
if (pipe(p) < 0)
|
||||
panic("pipe");
|
||||
if (fork1() == 0) {
|
||||
close(1);
|
||||
dup(p[1]);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
runcmd(pcmd->left);
|
||||
}
|
||||
if (fork1() == 0) {
|
||||
close(0);
|
||||
dup(p[0]);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
runcmd(pcmd->right);
|
||||
}
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
wait(0);
|
||||
wait(0);
|
||||
break;
|
||||
|
||||
case BACK:
|
||||
bcmd = (struct backcmd*)cmd;
|
||||
if(fork1() == 0)
|
||||
runcmd(bcmd->cmd);
|
||||
break;
|
||||
}
|
||||
exit(0);
|
||||
case BACK:
|
||||
bcmd = (struct backcmd *)cmd;
|
||||
if (fork1() == 0)
|
||||
runcmd(bcmd->cmd);
|
||||
break;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
getcmd(char *buf, int nbuf)
|
||||
{
|
||||
write(2, "$ ", 2);
|
||||
memset(buf, 0, nbuf);
|
||||
gets(buf, nbuf);
|
||||
if(buf[0] == 0) // EOF
|
||||
return -1;
|
||||
return 0;
|
||||
int getcmd(char *buf, int nbuf) {
|
||||
write(2, "$ ", 2);
|
||||
memset(buf, 0, nbuf);
|
||||
gets(buf, nbuf);
|
||||
if (buf[0] == 0) // EOF
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
static char buf[100];
|
||||
int fd;
|
||||
int main(void) {
|
||||
static char buf[100];
|
||||
int fd;
|
||||
|
||||
// Ensure that three file descriptors are open.
|
||||
while((fd = open("console", O_RDWR)) >= 0){
|
||||
if(fd >= 3){
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Ensure that three file descriptors are open.
|
||||
while ((fd = open("console", O_RDWR)) >= 0) {
|
||||
if (fd >= 3) {
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read and run input commands.
|
||||
while(getcmd(buf, sizeof(buf)) >= 0){
|
||||
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
|
||||
// Chdir must be called by the parent, not the child.
|
||||
buf[strlen(buf)-1] = 0; // chop \n
|
||||
if(chdir(buf+3) < 0)
|
||||
fprintf(2, "cannot cd %s\n", buf+3);
|
||||
continue;
|
||||
}
|
||||
if(fork1() == 0)
|
||||
runcmd(parsecmd(buf));
|
||||
wait(0);
|
||||
}
|
||||
exit(0);
|
||||
// Read and run input commands.
|
||||
while (getcmd(buf, sizeof(buf)) >= 0) {
|
||||
if (buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' ') {
|
||||
// Chdir must be called by the parent, not the child.
|
||||
buf[strlen(buf) - 1] = 0; // chop \n
|
||||
if (chdir(buf + 3) < 0)
|
||||
fprintf(2, "cannot cd %s\n", buf + 3);
|
||||
continue;
|
||||
}
|
||||
if (fork1() == 0)
|
||||
runcmd(parsecmd(buf));
|
||||
wait(0);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
panic(char *s)
|
||||
{
|
||||
fprintf(2, "%s\n", s);
|
||||
exit(1);
|
||||
void panic(char *s) {
|
||||
fprintf(2, "%s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
fork1(void)
|
||||
{
|
||||
int pid;
|
||||
int fork1(void) {
|
||||
int pid;
|
||||
|
||||
pid = fork();
|
||||
if(pid == -1)
|
||||
panic("fork");
|
||||
return pid;
|
||||
pid = fork();
|
||||
if (pid == -1)
|
||||
panic("fork");
|
||||
return pid;
|
||||
}
|
||||
|
||||
//PAGEBREAK!
|
||||
// Constructors
|
||||
// PAGEBREAK!
|
||||
// Constructors
|
||||
|
||||
struct cmd*
|
||||
execcmd(void)
|
||||
{
|
||||
struct execcmd *cmd;
|
||||
struct cmd *execcmd(void) {
|
||||
struct execcmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = EXEC;
|
||||
return (struct cmd*)cmd;
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = EXEC;
|
||||
return (struct cmd *)cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
|
||||
{
|
||||
struct redircmd *cmd;
|
||||
struct cmd *redircmd(struct cmd *subcmd, char *file, char *efile, int mode,
|
||||
int fd) {
|
||||
struct redircmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = REDIR;
|
||||
cmd->cmd = subcmd;
|
||||
cmd->file = file;
|
||||
cmd->efile = efile;
|
||||
cmd->mode = mode;
|
||||
cmd->fd = fd;
|
||||
return (struct cmd*)cmd;
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = REDIR;
|
||||
cmd->cmd = subcmd;
|
||||
cmd->file = file;
|
||||
cmd->efile = efile;
|
||||
cmd->mode = mode;
|
||||
cmd->fd = fd;
|
||||
return (struct cmd *)cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
pipecmd(struct cmd *left, struct cmd *right)
|
||||
{
|
||||
struct pipecmd *cmd;
|
||||
struct cmd *pipecmd(struct cmd *left, struct cmd *right) {
|
||||
struct pipecmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = PIPE;
|
||||
cmd->left = left;
|
||||
cmd->right = right;
|
||||
return (struct cmd*)cmd;
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = PIPE;
|
||||
cmd->left = left;
|
||||
cmd->right = right;
|
||||
return (struct cmd *)cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
listcmd(struct cmd *left, struct cmd *right)
|
||||
{
|
||||
struct listcmd *cmd;
|
||||
struct cmd *listcmd(struct cmd *left, struct cmd *right) {
|
||||
struct listcmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = LIST;
|
||||
cmd->left = left;
|
||||
cmd->right = right;
|
||||
return (struct cmd*)cmd;
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = LIST;
|
||||
cmd->left = left;
|
||||
cmd->right = right;
|
||||
return (struct cmd *)cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
backcmd(struct cmd *subcmd)
|
||||
{
|
||||
struct backcmd *cmd;
|
||||
struct cmd *backcmd(struct cmd *subcmd) {
|
||||
struct backcmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = BACK;
|
||||
cmd->cmd = subcmd;
|
||||
return (struct cmd*)cmd;
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = BACK;
|
||||
cmd->cmd = subcmd;
|
||||
return (struct cmd *)cmd;
|
||||
}
|
||||
//PAGEBREAK!
|
||||
// Parsing
|
||||
// PAGEBREAK!
|
||||
// Parsing
|
||||
|
||||
char whitespace[] = " \t\r\n\v";
|
||||
char symbols[] = "<|>&;()";
|
||||
|
||||
int
|
||||
gettoken(char **ps, char *es, char **q, char **eq)
|
||||
{
|
||||
char *s;
|
||||
int ret;
|
||||
int gettoken(char **ps, char *es, char **q, char **eq) {
|
||||
char *s;
|
||||
int ret;
|
||||
|
||||
s = *ps;
|
||||
while(s < es && strchr(whitespace, *s))
|
||||
s++;
|
||||
if(q)
|
||||
*q = s;
|
||||
ret = *s;
|
||||
switch(*s){
|
||||
case 0:
|
||||
break;
|
||||
case '|':
|
||||
case '(':
|
||||
case ')':
|
||||
case ';':
|
||||
case '&':
|
||||
case '<':
|
||||
s++;
|
||||
break;
|
||||
case '>':
|
||||
s++;
|
||||
if(*s == '>'){
|
||||
ret = '+';
|
||||
s++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = 'a';
|
||||
while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
if(eq)
|
||||
*eq = s;
|
||||
s = *ps;
|
||||
while (s < es && strchr(whitespace, *s))
|
||||
s++;
|
||||
if (q)
|
||||
*q = s;
|
||||
ret = *s;
|
||||
switch (*s) {
|
||||
case 0:
|
||||
break;
|
||||
case '|':
|
||||
case '(':
|
||||
case ')':
|
||||
case ';':
|
||||
case '&':
|
||||
case '<':
|
||||
s++;
|
||||
break;
|
||||
case '>':
|
||||
s++;
|
||||
if (*s == '>') {
|
||||
ret = '+';
|
||||
s++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = 'a';
|
||||
while (s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
if (eq)
|
||||
*eq = s;
|
||||
|
||||
while(s < es && strchr(whitespace, *s))
|
||||
s++;
|
||||
*ps = s;
|
||||
return ret;
|
||||
while (s < es && strchr(whitespace, *s))
|
||||
s++;
|
||||
*ps = s;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
peek(char **ps, char *es, char *toks)
|
||||
{
|
||||
char *s;
|
||||
int peek(char **ps, char *es, char *toks) {
|
||||
char *s;
|
||||
|
||||
s = *ps;
|
||||
while(s < es && strchr(whitespace, *s))
|
||||
s++;
|
||||
*ps = s;
|
||||
return *s && strchr(toks, *s);
|
||||
s = *ps;
|
||||
while (s < es && strchr(whitespace, *s))
|
||||
s++;
|
||||
*ps = s;
|
||||
return *s && strchr(toks, *s);
|
||||
}
|
||||
|
||||
struct cmd *parseline(char**, char*);
|
||||
struct cmd *parsepipe(char**, char*);
|
||||
struct cmd *parseexec(char**, char*);
|
||||
struct cmd *nulterminate(struct cmd*);
|
||||
struct cmd *parseline(char **, char *);
|
||||
struct cmd *parsepipe(char **, char *);
|
||||
struct cmd *parseexec(char **, char *);
|
||||
struct cmd *nulterminate(struct cmd *);
|
||||
|
||||
struct cmd*
|
||||
parsecmd(char *s)
|
||||
{
|
||||
char *es;
|
||||
struct cmd *cmd;
|
||||
struct cmd *parsecmd(char *s) {
|
||||
char *es;
|
||||
struct cmd *cmd;
|
||||
|
||||
es = s + strlen(s);
|
||||
cmd = parseline(&s, es);
|
||||
peek(&s, es, "");
|
||||
if(s != es){
|
||||
fprintf(2, "leftovers: %s\n", s);
|
||||
panic("syntax");
|
||||
}
|
||||
nulterminate(cmd);
|
||||
return cmd;
|
||||
es = s + strlen(s);
|
||||
cmd = parseline(&s, es);
|
||||
peek(&s, es, "");
|
||||
if (s != es) {
|
||||
fprintf(2, "leftovers: %s\n", s);
|
||||
panic("syntax");
|
||||
}
|
||||
nulterminate(cmd);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parseline(char **ps, char *es)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
struct cmd *parseline(char **ps, char *es) {
|
||||
struct cmd *cmd;
|
||||
|
||||
cmd = parsepipe(ps, es);
|
||||
while(peek(ps, es, "&")){
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = backcmd(cmd);
|
||||
}
|
||||
if(peek(ps, es, ";")){
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = listcmd(cmd, parseline(ps, es));
|
||||
}
|
||||
return cmd;
|
||||
cmd = parsepipe(ps, es);
|
||||
while (peek(ps, es, "&")) {
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = backcmd(cmd);
|
||||
}
|
||||
if (peek(ps, es, ";")) {
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = listcmd(cmd, parseline(ps, es));
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parsepipe(char **ps, char *es)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
struct cmd *parsepipe(char **ps, char *es) {
|
||||
struct cmd *cmd;
|
||||
|
||||
cmd = parseexec(ps, es);
|
||||
if(peek(ps, es, "|")){
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = pipecmd(cmd, parsepipe(ps, es));
|
||||
}
|
||||
return cmd;
|
||||
cmd = parseexec(ps, es);
|
||||
if (peek(ps, es, "|")) {
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = pipecmd(cmd, parsepipe(ps, es));
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parseredirs(struct cmd *cmd, char **ps, char *es)
|
||||
{
|
||||
int tok;
|
||||
char *q, *eq;
|
||||
struct cmd *parseredirs(struct cmd *cmd, char **ps, char *es) {
|
||||
int tok;
|
||||
char *q, *eq;
|
||||
|
||||
while(peek(ps, es, "<>")){
|
||||
tok = gettoken(ps, es, 0, 0);
|
||||
if(gettoken(ps, es, &q, &eq) != 'a')
|
||||
panic("missing file for redirection");
|
||||
switch(tok){
|
||||
case '<':
|
||||
cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
|
||||
break;
|
||||
case '>':
|
||||
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
|
||||
break;
|
||||
case '+': // >>
|
||||
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
while (peek(ps, es, "<>")) {
|
||||
tok = gettoken(ps, es, 0, 0);
|
||||
if (gettoken(ps, es, &q, &eq) != 'a')
|
||||
panic("missing file for redirection");
|
||||
switch (tok) {
|
||||
case '<':
|
||||
cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
|
||||
break;
|
||||
case '>':
|
||||
cmd = redircmd(cmd, q, eq, O_WRONLY | O_CREATE | O_TRUNC, 1);
|
||||
break;
|
||||
case '+': // >>
|
||||
cmd = redircmd(cmd, q, eq, O_WRONLY | O_CREATE, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parseblock(char **ps, char *es)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
struct cmd *parseblock(char **ps, char *es) {
|
||||
struct cmd *cmd;
|
||||
|
||||
if(!peek(ps, es, "("))
|
||||
panic("parseblock");
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = parseline(ps, es);
|
||||
if(!peek(ps, es, ")"))
|
||||
panic("syntax - missing )");
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = parseredirs(cmd, ps, es);
|
||||
return cmd;
|
||||
if (!peek(ps, es, "("))
|
||||
panic("parseblock");
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = parseline(ps, es);
|
||||
if (!peek(ps, es, ")"))
|
||||
panic("syntax - missing )");
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = parseredirs(cmd, ps, es);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parseexec(char **ps, char *es)
|
||||
{
|
||||
char *q, *eq;
|
||||
int tok, argc;
|
||||
struct execcmd *cmd;
|
||||
struct cmd *ret;
|
||||
struct cmd *parseexec(char **ps, char *es) {
|
||||
char *q, *eq;
|
||||
int tok, argc;
|
||||
struct execcmd *cmd;
|
||||
struct cmd *ret;
|
||||
|
||||
if(peek(ps, es, "("))
|
||||
return parseblock(ps, es);
|
||||
if (peek(ps, es, "("))
|
||||
return parseblock(ps, es);
|
||||
|
||||
ret = execcmd();
|
||||
cmd = (struct execcmd*)ret;
|
||||
ret = execcmd();
|
||||
cmd = (struct execcmd *)ret;
|
||||
|
||||
argc = 0;
|
||||
ret = parseredirs(ret, ps, es);
|
||||
while(!peek(ps, es, "|)&;")){
|
||||
if((tok=gettoken(ps, es, &q, &eq)) == 0)
|
||||
break;
|
||||
if(tok != 'a')
|
||||
panic("syntax");
|
||||
cmd->argv[argc] = q;
|
||||
cmd->eargv[argc] = eq;
|
||||
argc++;
|
||||
if(argc >= MAXARGS)
|
||||
panic("too many args");
|
||||
ret = parseredirs(ret, ps, es);
|
||||
}
|
||||
cmd->argv[argc] = 0;
|
||||
cmd->eargv[argc] = 0;
|
||||
return ret;
|
||||
argc = 0;
|
||||
ret = parseredirs(ret, ps, es);
|
||||
while (!peek(ps, es, "|)&;")) {
|
||||
if ((tok = gettoken(ps, es, &q, &eq)) == 0)
|
||||
break;
|
||||
if (tok != 'a')
|
||||
panic("syntax");
|
||||
cmd->argv[argc] = q;
|
||||
cmd->eargv[argc] = eq;
|
||||
argc++;
|
||||
if (argc >= MAXARGS)
|
||||
panic("too many args");
|
||||
ret = parseredirs(ret, ps, es);
|
||||
}
|
||||
cmd->argv[argc] = 0;
|
||||
cmd->eargv[argc] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// NUL-terminate all the counted strings.
|
||||
struct cmd*
|
||||
nulterminate(struct cmd *cmd)
|
||||
{
|
||||
int i;
|
||||
struct backcmd *bcmd;
|
||||
struct execcmd *ecmd;
|
||||
struct listcmd *lcmd;
|
||||
struct pipecmd *pcmd;
|
||||
struct redircmd *rcmd;
|
||||
struct cmd *nulterminate(struct cmd *cmd) {
|
||||
int i;
|
||||
struct backcmd *bcmd;
|
||||
struct execcmd *ecmd;
|
||||
struct listcmd *lcmd;
|
||||
struct pipecmd *pcmd;
|
||||
struct redircmd *rcmd;
|
||||
|
||||
if(cmd == 0)
|
||||
return 0;
|
||||
if (cmd == 0)
|
||||
return 0;
|
||||
|
||||
switch(cmd->type){
|
||||
case EXEC:
|
||||
ecmd = (struct execcmd*)cmd;
|
||||
for(i=0; ecmd->argv[i]; i++)
|
||||
*ecmd->eargv[i] = 0;
|
||||
break;
|
||||
switch (cmd->type) {
|
||||
case EXEC:
|
||||
ecmd = (struct execcmd *)cmd;
|
||||
for (i = 0; ecmd->argv[i]; i++)
|
||||
*ecmd->eargv[i] = 0;
|
||||
break;
|
||||
|
||||
case REDIR:
|
||||
rcmd = (struct redircmd*)cmd;
|
||||
nulterminate(rcmd->cmd);
|
||||
*rcmd->efile = 0;
|
||||
break;
|
||||
case REDIR:
|
||||
rcmd = (struct redircmd *)cmd;
|
||||
nulterminate(rcmd->cmd);
|
||||
*rcmd->efile = 0;
|
||||
break;
|
||||
|
||||
case PIPE:
|
||||
pcmd = (struct pipecmd*)cmd;
|
||||
nulterminate(pcmd->left);
|
||||
nulterminate(pcmd->right);
|
||||
break;
|
||||
case PIPE:
|
||||
pcmd = (struct pipecmd *)cmd;
|
||||
nulterminate(pcmd->left);
|
||||
nulterminate(pcmd->right);
|
||||
break;
|
||||
|
||||
case LIST:
|
||||
lcmd = (struct listcmd*)cmd;
|
||||
nulterminate(lcmd->left);
|
||||
nulterminate(lcmd->right);
|
||||
break;
|
||||
case LIST:
|
||||
lcmd = (struct listcmd *)cmd;
|
||||
nulterminate(lcmd->left);
|
||||
nulterminate(lcmd->right);
|
||||
break;
|
||||
|
||||
case BACK:
|
||||
bcmd = (struct backcmd*)cmd;
|
||||
nulterminate(bcmd->cmd);
|
||||
break;
|
||||
}
|
||||
return cmd;
|
||||
case BACK:
|
||||
bcmd = (struct backcmd *)cmd;
|
||||
nulterminate(bcmd->cmd);
|
||||
break;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,37 +13,35 @@
|
|||
#include "kernel/fs.h"
|
||||
#include "kernel/fcntl.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd, i;
|
||||
char path[] = "stressfs0";
|
||||
char data[512];
|
||||
int main(int argc, char *argv[]) {
|
||||
int fd, i;
|
||||
char path[] = "stressfs0";
|
||||
char data[512];
|
||||
|
||||
printf("stressfs starting\n");
|
||||
memset(data, 'a', sizeof(data));
|
||||
printf("stressfs starting\n");
|
||||
memset(data, 'a', sizeof(data));
|
||||
|
||||
for(i = 0; i < 4; i++)
|
||||
if(fork() > 0)
|
||||
break;
|
||||
for (i = 0; i < 4; i++)
|
||||
if (fork() > 0)
|
||||
break;
|
||||
|
||||
printf("write %d\n", i);
|
||||
printf("write %d\n", i);
|
||||
|
||||
path[8] += i;
|
||||
fd = open(path, O_CREATE | O_RDWR);
|
||||
for(i = 0; i < 20; i++)
|
||||
// printf(fd, "%d\n", i);
|
||||
write(fd, data, sizeof(data));
|
||||
close(fd);
|
||||
path[8] += i;
|
||||
fd = open(path, O_CREATE | O_RDWR);
|
||||
for (i = 0; i < 20; i++)
|
||||
// printf(fd, "%d\n", i);
|
||||
write(fd, data, sizeof(data));
|
||||
close(fd);
|
||||
|
||||
printf("read\n");
|
||||
printf("read\n");
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
for (i = 0; i < 20; i++)
|
||||
read(fd, data, sizeof(data));
|
||||
close(fd);
|
||||
fd = open(path, O_RDONLY);
|
||||
for (i = 0; i < 20; i++)
|
||||
read(fd, data, sizeof(data));
|
||||
close(fd);
|
||||
|
||||
wait(0);
|
||||
wait(0);
|
||||
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
196
user/ulib.c
196
user/ulib.c
|
|
@ -6,142 +6,118 @@
|
|||
//
|
||||
// wrapper so that it's OK if main() does not call exit().
|
||||
//
|
||||
void
|
||||
_main()
|
||||
{
|
||||
extern int main();
|
||||
main();
|
||||
exit(0);
|
||||
void _main() {
|
||||
extern int main();
|
||||
main();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
char*
|
||||
strcpy(char *s, const char *t)
|
||||
{
|
||||
char *os;
|
||||
char *strcpy(char *s, const char *t) {
|
||||
char *os;
|
||||
|
||||
os = s;
|
||||
while((*s++ = *t++) != 0)
|
||||
;
|
||||
return os;
|
||||
os = s;
|
||||
while ((*s++ = *t++) != 0)
|
||||
;
|
||||
return os;
|
||||
}
|
||||
|
||||
int
|
||||
strcmp(const char *p, const char *q)
|
||||
{
|
||||
while(*p && *p == *q)
|
||||
p++, q++;
|
||||
return (uchar)*p - (uchar)*q;
|
||||
int strcmp(const char *p, const char *q) {
|
||||
while (*p && *p == *q)
|
||||
p++, q++;
|
||||
return (uchar)*p - (uchar)*q;
|
||||
}
|
||||
|
||||
uint
|
||||
strlen(const char *s)
|
||||
{
|
||||
int n;
|
||||
uint strlen(const char *s) {
|
||||
int n;
|
||||
|
||||
for(n = 0; s[n]; n++)
|
||||
;
|
||||
return n;
|
||||
for (n = 0; s[n]; n++)
|
||||
;
|
||||
return n;
|
||||
}
|
||||
|
||||
void*
|
||||
memset(void *dst, int c, uint n)
|
||||
{
|
||||
char *cdst = (char *) dst;
|
||||
int i;
|
||||
for(i = 0; i < n; i++){
|
||||
cdst[i] = c;
|
||||
}
|
||||
return dst;
|
||||
void *memset(void *dst, int c, uint n) {
|
||||
char *cdst = (char *)dst;
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
cdst[i] = c;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char*
|
||||
strchr(const char *s, char c)
|
||||
{
|
||||
for(; *s; s++)
|
||||
if(*s == c)
|
||||
return (char*)s;
|
||||
return 0;
|
||||
char *strchr(const char *s, char c) {
|
||||
for (; *s; s++)
|
||||
if (*s == c)
|
||||
return (char *)s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char*
|
||||
gets(char *buf, int max)
|
||||
{
|
||||
int i, cc;
|
||||
char c;
|
||||
char *gets(char *buf, int max) {
|
||||
int i, cc;
|
||||
char c;
|
||||
|
||||
for(i=0; i+1 < max; ){
|
||||
cc = read(0, &c, 1);
|
||||
if(cc < 1)
|
||||
break;
|
||||
buf[i++] = c;
|
||||
if(c == '\n' || c == '\r')
|
||||
break;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
return buf;
|
||||
for (i = 0; i + 1 < max;) {
|
||||
cc = read(0, &c, 1);
|
||||
if (cc < 1)
|
||||
break;
|
||||
buf[i++] = c;
|
||||
if (c == '\n' || c == '\r')
|
||||
break;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
stat(const char *n, struct stat *st)
|
||||
{
|
||||
int fd;
|
||||
int r;
|
||||
int stat(const char *n, struct stat *st) {
|
||||
int fd;
|
||||
int r;
|
||||
|
||||
fd = open(n, O_RDONLY);
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
r = fstat(fd, st);
|
||||
close(fd);
|
||||
return r;
|
||||
fd = open(n, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
r = fstat(fd, st);
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
atoi(const char *s)
|
||||
{
|
||||
int n;
|
||||
int atoi(const char *s) {
|
||||
int n;
|
||||
|
||||
n = 0;
|
||||
while('0' <= *s && *s <= '9')
|
||||
n = n*10 + *s++ - '0';
|
||||
return n;
|
||||
n = 0;
|
||||
while ('0' <= *s && *s <= '9')
|
||||
n = n * 10 + *s++ - '0';
|
||||
return n;
|
||||
}
|
||||
|
||||
void*
|
||||
memmove(void *vdst, const void *vsrc, int n)
|
||||
{
|
||||
char *dst;
|
||||
const char *src;
|
||||
void *memmove(void *vdst, const void *vsrc, int n) {
|
||||
char *dst;
|
||||
const char *src;
|
||||
|
||||
dst = vdst;
|
||||
src = vsrc;
|
||||
if (src > dst) {
|
||||
while(n-- > 0)
|
||||
*dst++ = *src++;
|
||||
} else {
|
||||
dst += n;
|
||||
src += n;
|
||||
while(n-- > 0)
|
||||
*--dst = *--src;
|
||||
}
|
||||
return vdst;
|
||||
dst = vdst;
|
||||
src = vsrc;
|
||||
if (src > dst) {
|
||||
while (n-- > 0)
|
||||
*dst++ = *src++;
|
||||
} else {
|
||||
dst += n;
|
||||
src += n;
|
||||
while (n-- > 0)
|
||||
*--dst = *--src;
|
||||
}
|
||||
return vdst;
|
||||
}
|
||||
|
||||
int
|
||||
memcmp(const void *s1, const void *s2, uint n)
|
||||
{
|
||||
const char *p1 = s1, *p2 = s2;
|
||||
while (n-- > 0) {
|
||||
if (*p1 != *p2) {
|
||||
return *p1 - *p2;
|
||||
}
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
return 0;
|
||||
int memcmp(const void *s1, const void *s2, uint n) {
|
||||
const char *p1 = s1, *p2 = s2;
|
||||
while (n-- > 0) {
|
||||
if (*p1 != *p2) {
|
||||
return *p1 - *p2;
|
||||
}
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
memcpy(void *dst, const void *src, uint n)
|
||||
{
|
||||
return memmove(dst, src, n);
|
||||
void *memcpy(void *dst, const void *src, uint n) {
|
||||
return memmove(dst, src, n);
|
||||
}
|
||||
|
|
|
|||
122
user/umalloc.c
122
user/umalloc.c
|
|
@ -9,11 +9,11 @@
|
|||
typedef long Align;
|
||||
|
||||
union header {
|
||||
struct {
|
||||
union header *ptr;
|
||||
uint size;
|
||||
} s;
|
||||
Align x;
|
||||
struct {
|
||||
union header *ptr;
|
||||
uint size;
|
||||
} s;
|
||||
Align x;
|
||||
};
|
||||
|
||||
typedef union header Header;
|
||||
|
|
@ -21,70 +21,64 @@ typedef union header Header;
|
|||
static Header base;
|
||||
static Header *freep;
|
||||
|
||||
void
|
||||
free(void *ap)
|
||||
{
|
||||
Header *bp, *p;
|
||||
void free(void *ap) {
|
||||
Header *bp, *p;
|
||||
|
||||
bp = (Header*)ap - 1;
|
||||
for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
|
||||
if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
|
||||
break;
|
||||
if(bp + bp->s.size == p->s.ptr){
|
||||
bp->s.size += p->s.ptr->s.size;
|
||||
bp->s.ptr = p->s.ptr->s.ptr;
|
||||
} else
|
||||
bp->s.ptr = p->s.ptr;
|
||||
if(p + p->s.size == bp){
|
||||
p->s.size += bp->s.size;
|
||||
p->s.ptr = bp->s.ptr;
|
||||
} else
|
||||
p->s.ptr = bp;
|
||||
freep = p;
|
||||
bp = (Header *)ap - 1;
|
||||
for (p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
|
||||
if (p >= p->s.ptr && (bp > p || bp < p->s.ptr))
|
||||
break;
|
||||
if (bp + bp->s.size == p->s.ptr) {
|
||||
bp->s.size += p->s.ptr->s.size;
|
||||
bp->s.ptr = p->s.ptr->s.ptr;
|
||||
} else
|
||||
bp->s.ptr = p->s.ptr;
|
||||
if (p + p->s.size == bp) {
|
||||
p->s.size += bp->s.size;
|
||||
p->s.ptr = bp->s.ptr;
|
||||
} else
|
||||
p->s.ptr = bp;
|
||||
freep = p;
|
||||
}
|
||||
|
||||
static Header*
|
||||
morecore(uint nu)
|
||||
{
|
||||
char *p;
|
||||
Header *hp;
|
||||
static Header *morecore(uint nu) {
|
||||
char *p;
|
||||
Header *hp;
|
||||
|
||||
if(nu < 4096)
|
||||
nu = 4096;
|
||||
p = sbrk(nu * sizeof(Header));
|
||||
if(p == (char*)-1)
|
||||
return 0;
|
||||
hp = (Header*)p;
|
||||
hp->s.size = nu;
|
||||
free((void*)(hp + 1));
|
||||
return freep;
|
||||
if (nu < 4096)
|
||||
nu = 4096;
|
||||
p = sbrk(nu * sizeof(Header));
|
||||
if (p == (char *)-1)
|
||||
return 0;
|
||||
hp = (Header *)p;
|
||||
hp->s.size = nu;
|
||||
free((void *)(hp + 1));
|
||||
return freep;
|
||||
}
|
||||
|
||||
void*
|
||||
malloc(uint nbytes)
|
||||
{
|
||||
Header *p, *prevp;
|
||||
uint nunits;
|
||||
void *malloc(uint nbytes) {
|
||||
Header *p, *prevp;
|
||||
uint nunits;
|
||||
|
||||
nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
|
||||
if((prevp = freep) == 0){
|
||||
base.s.ptr = freep = prevp = &base;
|
||||
base.s.size = 0;
|
||||
}
|
||||
for(p = prevp->s.ptr; ; prevp = p, p = p->s.ptr){
|
||||
if(p->s.size >= nunits){
|
||||
if(p->s.size == nunits)
|
||||
prevp->s.ptr = p->s.ptr;
|
||||
else {
|
||||
p->s.size -= nunits;
|
||||
p += p->s.size;
|
||||
p->s.size = nunits;
|
||||
}
|
||||
freep = prevp;
|
||||
return (void*)(p + 1);
|
||||
}
|
||||
if(p == freep)
|
||||
if((p = morecore(nunits)) == 0)
|
||||
return 0;
|
||||
}
|
||||
nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;
|
||||
if ((prevp = freep) == 0) {
|
||||
base.s.ptr = freep = prevp = &base;
|
||||
base.s.size = 0;
|
||||
}
|
||||
for (p = prevp->s.ptr;; prevp = p, p = p->s.ptr) {
|
||||
if (p->s.size >= nunits) {
|
||||
if (p->s.size == nunits)
|
||||
prevp->s.ptr = p->s.ptr;
|
||||
else {
|
||||
p->s.size -= nunits;
|
||||
p += p->s.size;
|
||||
p->s.size = nunits;
|
||||
}
|
||||
freep = prevp;
|
||||
return (void *)(p + 1);
|
||||
}
|
||||
if (p == freep)
|
||||
if ((p = morecore(nunits)) == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
5170
user/usertests.c
5170
user/usertests.c
File diff suppressed because it is too large
Load Diff
80
user/wc.c
80
user/wc.c
|
|
@ -4,51 +4,47 @@
|
|||
|
||||
char buf[512];
|
||||
|
||||
void
|
||||
wc(int fd, char *name)
|
||||
{
|
||||
int i, n;
|
||||
int l, w, c, inword;
|
||||
void wc(int fd, char *name) {
|
||||
int i, n;
|
||||
int l, w, c, inword;
|
||||
|
||||
l = w = c = 0;
|
||||
inword = 0;
|
||||
while((n = read(fd, buf, sizeof(buf))) > 0){
|
||||
for(i=0; i<n; i++){
|
||||
c++;
|
||||
if(buf[i] == '\n')
|
||||
l++;
|
||||
if(strchr(" \r\t\n\v", buf[i]))
|
||||
inword = 0;
|
||||
else if(!inword){
|
||||
w++;
|
||||
inword = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(n < 0){
|
||||
printf("wc: read error\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("%d %d %d %s\n", l, w, c, name);
|
||||
l = w = c = 0;
|
||||
inword = 0;
|
||||
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
for (i = 0; i < n; i++) {
|
||||
c++;
|
||||
if (buf[i] == '\n')
|
||||
l++;
|
||||
if (strchr(" \r\t\n\v", buf[i]))
|
||||
inword = 0;
|
||||
else if (!inword) {
|
||||
w++;
|
||||
inword = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n < 0) {
|
||||
printf("wc: read error\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("%d %d %d %s\n", l, w, c, name);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd, i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int fd, i;
|
||||
|
||||
if(argc <= 1){
|
||||
wc(0, "");
|
||||
exit(0);
|
||||
}
|
||||
if (argc <= 1) {
|
||||
wc(0, "");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
printf("wc: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
wc(fd, argv[i]);
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
for (i = 1; i < argc; i++) {
|
||||
if ((fd = open(argv[i], 0)) < 0) {
|
||||
printf("wc: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
wc(fd, argv[i]);
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,8 @@
|
|||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
if(fork() > 0)
|
||||
sleep(5); // Let child exit before parent.
|
||||
exit(0);
|
||||
int main(void) {
|
||||
if (fork() > 0)
|
||||
sleep(5); // Let child exit before parent.
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue