Complete reformat
This commit is contained in:
parent
b1a34398e9
commit
d6793bf093
60 changed files with 1952 additions and 1995 deletions
27
kernel/bio.c
27
kernel/bio.c
|
@ -13,7 +13,6 @@
|
||||||
// * Only one process at a time can use a buffer,
|
// * Only one process at a time can use a buffer,
|
||||||
// so do not keep them longer than necessary.
|
// so do not keep them longer than necessary.
|
||||||
|
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "param.h"
|
#include "param.h"
|
||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
|
@ -25,7 +24,7 @@
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
struct buf buf[NBUF];
|
struct buf buf[NBUF];
|
||||||
|
|
||||||
// Linked list of all buffers, through prev/next.
|
// Linked list of all buffers, through prev/next.
|
||||||
// Sorted by how recently the buffer was used.
|
// Sorted by how recently the buffer was used.
|
||||||
|
@ -43,7 +42,7 @@ binit(void)
|
||||||
// Create linked list of buffers
|
// Create linked list of buffers
|
||||||
bcache.head.prev = &bcache.head;
|
bcache.head.prev = &bcache.head;
|
||||||
bcache.head.next = &bcache.head;
|
bcache.head.next = &bcache.head;
|
||||||
for(b = bcache.buf; b < bcache.buf+NBUF; b++){
|
for(b = bcache.buf; b < bcache.buf + NBUF; b++) {
|
||||||
b->next = bcache.head.next;
|
b->next = bcache.head.next;
|
||||||
b->prev = &bcache.head;
|
b->prev = &bcache.head;
|
||||||
initsleeplock(&b->lock, "buffer");
|
initsleeplock(&b->lock, "buffer");
|
||||||
|
@ -55,7 +54,7 @@ binit(void)
|
||||||
// Look through buffer cache for block on device dev.
|
// Look through buffer cache for block on device dev.
|
||||||
// If not found, allocate a buffer.
|
// If not found, allocate a buffer.
|
||||||
// In either case, return locked buffer.
|
// In either case, return locked buffer.
|
||||||
static struct buf*
|
static struct buf *
|
||||||
bget(u32 dev, u32 blockno)
|
bget(u32 dev, u32 blockno)
|
||||||
{
|
{
|
||||||
struct buf *b;
|
struct buf *b;
|
||||||
|
@ -63,8 +62,8 @@ bget(u32 dev, u32 blockno)
|
||||||
acquire(&bcache.lock);
|
acquire(&bcache.lock);
|
||||||
|
|
||||||
// Is the block already cached?
|
// Is the block already cached?
|
||||||
for(b = bcache.head.next; b != &bcache.head; b = b->next){
|
for(b = bcache.head.next; b != &bcache.head; b = b->next) {
|
||||||
if(b->dev == dev && b->blockno == blockno){
|
if(b->dev == dev && b->blockno == blockno) {
|
||||||
b->refcnt++;
|
b->refcnt++;
|
||||||
release(&bcache.lock);
|
release(&bcache.lock);
|
||||||
acquiresleep(&b->lock);
|
acquiresleep(&b->lock);
|
||||||
|
@ -74,7 +73,7 @@ bget(u32 dev, u32 blockno)
|
||||||
|
|
||||||
// Not cached.
|
// Not cached.
|
||||||
// Recycle the least recently used (LRU) unused buffer.
|
// Recycle the least recently used (LRU) unused buffer.
|
||||||
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
|
for(b = bcache.head.prev; b != &bcache.head; b = b->prev) {
|
||||||
if(b->refcnt == 0) {
|
if(b->refcnt == 0) {
|
||||||
b->dev = dev;
|
b->dev = dev;
|
||||||
b->blockno = blockno;
|
b->blockno = blockno;
|
||||||
|
@ -89,7 +88,7 @@ bget(u32 dev, u32 blockno)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a locked buf with the contents of the indicated block.
|
// Return a locked buf with the contents of the indicated block.
|
||||||
struct buf*
|
struct buf *
|
||||||
bread(u32 dev, u32 blockno)
|
bread(u32 dev, u32 blockno)
|
||||||
{
|
{
|
||||||
struct buf *b;
|
struct buf *b;
|
||||||
|
@ -123,7 +122,7 @@ brelse(struct buf *b)
|
||||||
|
|
||||||
acquire(&bcache.lock);
|
acquire(&bcache.lock);
|
||||||
b->refcnt--;
|
b->refcnt--;
|
||||||
if (b->refcnt == 0) {
|
if(b->refcnt == 0) {
|
||||||
// no one is waiting for it.
|
// no one is waiting for it.
|
||||||
b->next->prev = b->prev;
|
b->next->prev = b->prev;
|
||||||
b->prev->next = b->next;
|
b->prev->next = b->next;
|
||||||
|
@ -132,22 +131,22 @@ brelse(struct buf *b)
|
||||||
bcache.head.next->prev = b;
|
bcache.head.next->prev = b;
|
||||||
bcache.head.next = b;
|
bcache.head.next = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
release(&bcache.lock);
|
release(&bcache.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
bpin(struct buf *b) {
|
bpin(struct buf *b)
|
||||||
|
{
|
||||||
acquire(&bcache.lock);
|
acquire(&bcache.lock);
|
||||||
b->refcnt++;
|
b->refcnt++;
|
||||||
release(&bcache.lock);
|
release(&bcache.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
bunpin(struct buf *b) {
|
bunpin(struct buf *b)
|
||||||
|
{
|
||||||
acquire(&bcache.lock);
|
acquire(&bcache.lock);
|
||||||
b->refcnt--;
|
b->refcnt--;
|
||||||
release(&bcache.lock);
|
release(&bcache.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
17
kernel/buf.h
17
kernel/buf.h
|
@ -1,12 +1,11 @@
|
||||||
struct buf {
|
struct buf {
|
||||||
int valid; // has data been read from disk?
|
int valid; // has data been read from disk?
|
||||||
int disk; // does disk "own" buf?
|
int disk; // does disk "own" buf?
|
||||||
u32 dev;
|
u32 dev;
|
||||||
u32 blockno;
|
u32 blockno;
|
||||||
struct sleeplock lock;
|
struct sleeplock lock;
|
||||||
u32 refcnt;
|
u32 refcnt;
|
||||||
struct buf *prev; // LRU cache list
|
struct buf *prev; // LRU cache list
|
||||||
struct buf *next;
|
struct buf *next;
|
||||||
u8 data[BSIZE];
|
u8 data[BSIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
|
|
||||||
#define BACKSPACE 0x100
|
#define BACKSPACE 0x100
|
||||||
#define C(x) ((x)-'@') // Control-x
|
#define C(x) ((x) - '@') // Control-x
|
||||||
|
|
||||||
//
|
//
|
||||||
// send one character to the uart.
|
// send one character to the uart.
|
||||||
|
@ -33,9 +33,11 @@
|
||||||
void
|
void
|
||||||
consputc(int c)
|
consputc(int c)
|
||||||
{
|
{
|
||||||
if(c == BACKSPACE){
|
if(c == BACKSPACE) {
|
||||||
// if the user typed backspace, overwrite with a space.
|
// if the user typed backspace, overwrite with a space.
|
||||||
uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b');
|
uartputc_sync('\b');
|
||||||
|
uartputc_sync(' ');
|
||||||
|
uartputc_sync('\b');
|
||||||
} else {
|
} else {
|
||||||
uartputc_sync(c);
|
uartputc_sync(c);
|
||||||
}
|
}
|
||||||
|
@ -43,13 +45,13 @@ consputc(int c)
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
|
|
||||||
// input
|
// input
|
||||||
#define INPUT_BUF_SIZE 128
|
#define INPUT_BUF_SIZE 128
|
||||||
char buf[INPUT_BUF_SIZE];
|
char buf[INPUT_BUF_SIZE];
|
||||||
u32 r; // Read index
|
u32 r; // Read index
|
||||||
u32 w; // Write index
|
u32 w; // Write index
|
||||||
u32 e; // Edit index
|
u32 e; // Edit index
|
||||||
} cons;
|
} cons;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -60,9 +62,9 @@ consolewrite(int user_src, u64 src, int n)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < n; i++){
|
for(i = 0; i < n; i++) {
|
||||||
char c;
|
char c;
|
||||||
if(either_copyin(&c, user_src, src+i, 1) == -1)
|
if(either_copyin(&c, user_src, src + i, 1) == -1)
|
||||||
break;
|
break;
|
||||||
uartputc(c);
|
uartputc(c);
|
||||||
}
|
}
|
||||||
|
@ -79,17 +81,17 @@ consolewrite(int user_src, u64 src, int n)
|
||||||
int
|
int
|
||||||
consoleread(int user_dst, u64 dst, int n)
|
consoleread(int user_dst, u64 dst, int n)
|
||||||
{
|
{
|
||||||
u32 target;
|
u32 target;
|
||||||
int c;
|
int c;
|
||||||
char cbuf;
|
char cbuf;
|
||||||
|
|
||||||
target = n;
|
target = n;
|
||||||
acquire(&cons.lock);
|
acquire(&cons.lock);
|
||||||
while(n > 0){
|
while(n > 0) {
|
||||||
// wait until interrupt handler has put some
|
// wait until interrupt handler has put some
|
||||||
// input into cons.buffer.
|
// input into cons.buffer.
|
||||||
while(cons.r == cons.w){
|
while(cons.r == cons.w) {
|
||||||
if(killed(myproc())){
|
if(killed(myproc())) {
|
||||||
release(&cons.lock);
|
release(&cons.lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -98,8 +100,8 @@ consoleread(int user_dst, u64 dst, int n)
|
||||||
|
|
||||||
c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
|
c = cons.buf[cons.r++ % INPUT_BUF_SIZE];
|
||||||
|
|
||||||
if(c == C('D')){ // end-of-file
|
if(c == C('D')) { // end-of-file
|
||||||
if(n < target){
|
if(n < target) {
|
||||||
// Save ^D for next time, to make sure
|
// Save ^D for next time, to make sure
|
||||||
// caller gets a 0-byte result.
|
// caller gets a 0-byte result.
|
||||||
cons.r--;
|
cons.r--;
|
||||||
|
@ -115,7 +117,7 @@ consoleread(int user_dst, u64 dst, int n)
|
||||||
dst++;
|
dst++;
|
||||||
--n;
|
--n;
|
||||||
|
|
||||||
if(c == '\n'){
|
if(c == '\n') {
|
||||||
// a whole line has arrived, return to
|
// a whole line has arrived, return to
|
||||||
// the user-level read().
|
// the user-level read().
|
||||||
break;
|
break;
|
||||||
|
@ -137,26 +139,25 @@ consoleintr(int c)
|
||||||
{
|
{
|
||||||
acquire(&cons.lock);
|
acquire(&cons.lock);
|
||||||
|
|
||||||
switch(c){
|
switch(c) {
|
||||||
case C('P'): // Print process list.
|
case C('P'): // Print process list.
|
||||||
procdump();
|
procdump();
|
||||||
break;
|
break;
|
||||||
case C('U'): // Kill line.
|
case C('U'): // Kill line.
|
||||||
while(cons.e != cons.w &&
|
while(cons.e != cons.w && cons.buf[(cons.e - 1) % INPUT_BUF_SIZE] != '\n') {
|
||||||
cons.buf[(cons.e-1) % INPUT_BUF_SIZE] != '\n'){
|
|
||||||
cons.e--;
|
cons.e--;
|
||||||
consputc(BACKSPACE);
|
consputc(BACKSPACE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case C('H'): // Backspace
|
case C('H'): // Backspace
|
||||||
case '\x7f': // Delete key
|
case '\x7f': // Delete key
|
||||||
if(cons.e != cons.w){
|
if(cons.e != cons.w) {
|
||||||
cons.e--;
|
cons.e--;
|
||||||
consputc(BACKSPACE);
|
consputc(BACKSPACE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if(c != 0 && cons.e-cons.r < INPUT_BUF_SIZE){
|
if(c != 0 && cons.e - cons.r < INPUT_BUF_SIZE) {
|
||||||
c = (c == '\r') ? '\n' : c;
|
c = (c == '\r') ? '\n' : c;
|
||||||
|
|
||||||
// echo back to the user.
|
// echo back to the user.
|
||||||
|
@ -165,7 +166,7 @@ consoleintr(int c)
|
||||||
// store for consumption by consoleread().
|
// store for consumption by consoleread().
|
||||||
cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
|
cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
|
||||||
|
|
||||||
if(c == '\n' || c == C('D') || cons.e-cons.r == INPUT_BUF_SIZE){
|
if(c == '\n' || c == C('D') || cons.e - cons.r == INPUT_BUF_SIZE) {
|
||||||
// wake up consoleread() if a whole line (or end-of-file)
|
// wake up consoleread() if a whole line (or end-of-file)
|
||||||
// has arrived.
|
// has arrived.
|
||||||
cons.w = cons.e;
|
cons.w = cons.e;
|
||||||
|
@ -174,7 +175,7 @@ consoleintr(int c)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
release(&cons.lock);
|
release(&cons.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
268
kernel/defs.h
268
kernel/defs.h
|
@ -10,180 +10,180 @@ struct stat;
|
||||||
struct superblock;
|
struct superblock;
|
||||||
|
|
||||||
// bio.c
|
// bio.c
|
||||||
void binit(void);
|
void binit(void);
|
||||||
struct buf* bread(u32, u32);
|
struct buf *bread(u32, u32);
|
||||||
void brelse(struct buf*);
|
void brelse(struct buf *);
|
||||||
void bwrite(struct buf*);
|
void bwrite(struct buf *);
|
||||||
void bpin(struct buf*);
|
void bpin(struct buf *);
|
||||||
void bunpin(struct buf*);
|
void bunpin(struct buf *);
|
||||||
|
|
||||||
// console.c
|
// console.c
|
||||||
void consoleinit(void);
|
void consoleinit(void);
|
||||||
void consoleintr(int);
|
void consoleintr(int);
|
||||||
void consputc(int);
|
void consputc(int);
|
||||||
|
|
||||||
// exec.c
|
// exec.c
|
||||||
int exec(char*, char**);
|
int exec(char *, char **);
|
||||||
|
|
||||||
// file.c
|
// file.c
|
||||||
struct file* filealloc(void);
|
struct file *filealloc(void);
|
||||||
void fileclose(struct file*);
|
void fileclose(struct file *);
|
||||||
struct file* filedup(struct file*);
|
struct file *filedup(struct file *);
|
||||||
void fileinit(void);
|
void fileinit(void);
|
||||||
int fileread(struct file*, u64, int n);
|
int fileread(struct file *, u64, int n);
|
||||||
int filestat(struct file*, u64 addr);
|
int filestat(struct file *, u64 addr);
|
||||||
int filewrite(struct file*, u64, int n);
|
int filewrite(struct file *, u64, int n);
|
||||||
|
|
||||||
// fs.c
|
// fs.c
|
||||||
void fsinit(int);
|
void fsinit(int);
|
||||||
int dirlink(struct inode*, char*, u32);
|
int dirlink(struct inode *, char *, u32);
|
||||||
struct inode* dirlookup(struct inode*, char*, u32*);
|
struct inode *dirlookup(struct inode *, char *, u32 *);
|
||||||
struct inode* ialloc(u32, short);
|
struct inode *ialloc(u32, short);
|
||||||
struct inode* idup(struct inode*);
|
struct inode *idup(struct inode *);
|
||||||
void iinit();
|
void iinit();
|
||||||
void ilock(struct inode*);
|
void ilock(struct inode *);
|
||||||
void iput(struct inode*);
|
void iput(struct inode *);
|
||||||
void iunlock(struct inode*);
|
void iunlock(struct inode *);
|
||||||
void iunlockput(struct inode*);
|
void iunlockput(struct inode *);
|
||||||
void iupdate(struct inode*);
|
void iupdate(struct inode *);
|
||||||
int namecmp(const char*, const char*);
|
int namecmp(const char *, const char *);
|
||||||
struct inode* namei(char*);
|
struct inode *namei(char *);
|
||||||
struct inode* nameiparent(char*, char*);
|
struct inode *nameiparent(char *, char *);
|
||||||
int readi(struct inode*, int, u64, u32, u32);
|
int readi(struct inode *, int, u64, u32, u32);
|
||||||
void stati(struct inode*, struct stat*);
|
void stati(struct inode *, struct stat *);
|
||||||
int writei(struct inode*, int, u64, u32, u32);
|
int writei(struct inode *, int, u64, u32, u32);
|
||||||
void itrunc(struct inode*);
|
void itrunc(struct inode *);
|
||||||
|
|
||||||
// ramdisk.c
|
// ramdisk.c
|
||||||
void ramdiskinit(void);
|
void ramdiskinit(void);
|
||||||
void ramdiskintr(void);
|
void ramdiskintr(void);
|
||||||
void ramdiskrw(struct buf*);
|
void ramdiskrw(struct buf *);
|
||||||
|
|
||||||
// kalloc.c
|
// kalloc.c
|
||||||
void* kalloc(void);
|
void *kalloc(void);
|
||||||
void kfree(void *);
|
void kfree(void *);
|
||||||
void kinit(void);
|
void kinit(void);
|
||||||
|
|
||||||
// log.c
|
// log.c
|
||||||
void initlog(int, struct superblock*);
|
void initlog(int, struct superblock *);
|
||||||
void log_write(struct buf*);
|
void log_write(struct buf *);
|
||||||
void begin_op(void);
|
void begin_op(void);
|
||||||
void end_op(void);
|
void end_op(void);
|
||||||
|
|
||||||
// pipe.c
|
// pipe.c
|
||||||
int pipealloc(struct file**, struct file**);
|
int pipealloc(struct file **, struct file **);
|
||||||
void pipeclose(struct pipe*, int);
|
void pipeclose(struct pipe *, int);
|
||||||
int piperead(struct pipe*, u64, int);
|
int piperead(struct pipe *, u64, int);
|
||||||
int pipewrite(struct pipe*, u64, int);
|
int pipewrite(struct pipe *, u64, int);
|
||||||
|
|
||||||
// printf.c
|
// printf.c
|
||||||
void printf(char*, ...);
|
void printf(char *, ...);
|
||||||
void panic(char*) __attribute__((noreturn));
|
void panic(char *) __attribute__((noreturn));
|
||||||
void printfinit(void);
|
void printfinit(void);
|
||||||
|
|
||||||
// proc.c
|
// proc.c
|
||||||
int cpuid(void);
|
int cpuid(void);
|
||||||
void exit(int);
|
void exit(int);
|
||||||
int fork(void);
|
int fork(void);
|
||||||
int growproc(int);
|
int growproc(int);
|
||||||
void proc_mapstacks(pagetable_t);
|
void proc_mapstacks(pagetable_t);
|
||||||
pagetable_t proc_pagetable(struct proc *);
|
pagetable_t proc_pagetable(struct proc *);
|
||||||
void proc_freepagetable(pagetable_t, u64);
|
void proc_freepagetable(pagetable_t, u64);
|
||||||
int kill(int);
|
int kill(int);
|
||||||
int killed(struct proc*);
|
int killed(struct proc *);
|
||||||
void setkilled(struct proc*);
|
void setkilled(struct proc *);
|
||||||
struct cpu* mycpu(void);
|
struct cpu *mycpu(void);
|
||||||
struct cpu* getmycpu(void);
|
struct cpu *getmycpu(void);
|
||||||
struct proc* myproc();
|
struct proc *myproc();
|
||||||
void procinit(void);
|
void procinit(void);
|
||||||
void scheduler(void) __attribute__((noreturn));
|
void scheduler(void) __attribute__((noreturn));
|
||||||
void sched(void);
|
void sched(void);
|
||||||
void sleep(void*, struct spinlock*);
|
void sleep(void *, struct spinlock *);
|
||||||
void userinit(void);
|
void userinit(void);
|
||||||
int wait(u64);
|
int wait(u64);
|
||||||
void wakeup(void*);
|
void wakeup(void *);
|
||||||
void yield(void);
|
void yield(void);
|
||||||
int either_copyout(int user_dst, u64 dst, void *src, u64 len);
|
int either_copyout(int user_dst, u64 dst, void *src, u64 len);
|
||||||
int either_copyin(void *dst, int user_src, u64 src, u64 len);
|
int either_copyin(void *dst, int user_src, u64 src, u64 len);
|
||||||
void procdump(void);
|
void procdump(void);
|
||||||
|
|
||||||
// swtch.S
|
// swtch.S
|
||||||
void swtch(struct context*, struct context*);
|
void swtch(struct context *, struct context *);
|
||||||
|
|
||||||
// spinlock.c
|
// spinlock.c
|
||||||
void acquire(struct spinlock*);
|
void acquire(struct spinlock *);
|
||||||
int holding(struct spinlock*);
|
int holding(struct spinlock *);
|
||||||
void initlock(struct spinlock*, char*);
|
void initlock(struct spinlock *, char *);
|
||||||
void release(struct spinlock*);
|
void release(struct spinlock *);
|
||||||
void push_off(void);
|
void push_off(void);
|
||||||
void pop_off(void);
|
void pop_off(void);
|
||||||
|
|
||||||
// sleeplock.c
|
// sleeplock.c
|
||||||
void acquiresleep(struct sleeplock*);
|
void acquiresleep(struct sleeplock *);
|
||||||
void releasesleep(struct sleeplock*);
|
void releasesleep(struct sleeplock *);
|
||||||
int holdingsleep(struct sleeplock*);
|
int holdingsleep(struct sleeplock *);
|
||||||
void initsleeplock(struct sleeplock*, char*);
|
void initsleeplock(struct sleeplock *, char *);
|
||||||
|
|
||||||
// string.c
|
// string.c
|
||||||
int memcmp(const void*, const void*, u32);
|
int memcmp(const void *, const void *, u32);
|
||||||
void* memmove(void*, const void*, u32);
|
void *memmove(void *, const void *, u32);
|
||||||
void* memset(void*, int, u32);
|
void *memset(void *, int, u32);
|
||||||
char* safestrcpy(char*, const char*, int);
|
char *safestrcpy(char *, const char *, int);
|
||||||
int strlen(const char*);
|
int strlen(const char *);
|
||||||
int strncmp(const char*, const char*, u32);
|
int strncmp(const char *, const char *, u32);
|
||||||
char* strncpy(char*, const char*, int);
|
char *strncpy(char *, const char *, int);
|
||||||
|
|
||||||
// syscall.c
|
// syscall.c
|
||||||
void argint(int, int*);
|
void argint(int, int *);
|
||||||
int argstr(int, char*, int);
|
int argstr(int, char *, int);
|
||||||
void argaddr(int, u64 *);
|
void argaddr(int, u64 *);
|
||||||
int fetchstr(u64, char*, int);
|
int fetchstr(u64, char *, int);
|
||||||
int fetchaddr(u64, u64*);
|
int fetchaddr(u64, u64 *);
|
||||||
void syscall();
|
void syscall();
|
||||||
|
|
||||||
// trap.c
|
// trap.c
|
||||||
extern u32 ticks;
|
extern u32 ticks;
|
||||||
void trapinit(void);
|
void trapinit(void);
|
||||||
void trapinithart(void);
|
void trapinithart(void);
|
||||||
extern struct spinlock tickslock;
|
extern struct spinlock tickslock;
|
||||||
void usertrapret(void);
|
void usertrapret(void);
|
||||||
|
|
||||||
// uart.c
|
// uart.c
|
||||||
void uartinit(void);
|
void uartinit(void);
|
||||||
void uartintr(void);
|
void uartintr(void);
|
||||||
void uartputc(int);
|
void uartputc(int);
|
||||||
void uartputc_sync(int);
|
void uartputc_sync(int);
|
||||||
int uartgetc(void);
|
int uartgetc(void);
|
||||||
|
|
||||||
// vm.c
|
// vm.c
|
||||||
void kvminit(void);
|
void kvminit(void);
|
||||||
void kvminithart(void);
|
void kvminithart(void);
|
||||||
void kvmmap(pagetable_t, u64, u64, u64, int);
|
void kvmmap(pagetable_t, u64, u64, u64, int);
|
||||||
int mappages(pagetable_t, u64, u64, u64, int);
|
int mappages(pagetable_t, u64, u64, u64, int);
|
||||||
pagetable_t uvmcreate(void);
|
pagetable_t uvmcreate(void);
|
||||||
void uvmfirst(pagetable_t, u8 *, u32);
|
void uvmfirst(pagetable_t, u8 *, u32);
|
||||||
u64 uvmalloc(pagetable_t, u64, u64, int);
|
u64 uvmalloc(pagetable_t, u64, u64, int);
|
||||||
u64 uvmdealloc(pagetable_t, u64, u64);
|
u64 uvmdealloc(pagetable_t, u64, u64);
|
||||||
int uvmcopy(pagetable_t, pagetable_t, u64);
|
int uvmcopy(pagetable_t, pagetable_t, u64);
|
||||||
void uvmfree(pagetable_t, u64);
|
void uvmfree(pagetable_t, u64);
|
||||||
void uvmunmap(pagetable_t, u64, u64, int);
|
void uvmunmap(pagetable_t, u64, u64, int);
|
||||||
void uvmclear(pagetable_t, u64);
|
void uvmclear(pagetable_t, u64);
|
||||||
pte_t * walk(pagetable_t, u64, int);
|
pte_t *walk(pagetable_t, u64, int);
|
||||||
u64 walkaddr(pagetable_t, u64);
|
u64 walkaddr(pagetable_t, u64);
|
||||||
int copyout(pagetable_t, u64, char *, u64);
|
int copyout(pagetable_t, u64, char *, u64);
|
||||||
int copyin(pagetable_t, char *, u64, u64);
|
int copyin(pagetable_t, char *, u64, u64);
|
||||||
int copyinstr(pagetable_t, char *, u64, u64);
|
int copyinstr(pagetable_t, char *, u64, u64);
|
||||||
|
|
||||||
// plic.c
|
// plic.c
|
||||||
void plicinit(void);
|
void plicinit(void);
|
||||||
void plicinithart(void);
|
void plicinithart(void);
|
||||||
int plic_claim(void);
|
int plic_claim(void);
|
||||||
void plic_complete(int);
|
void plic_complete(int);
|
||||||
|
|
||||||
// virtio_disk.c
|
// virtio_disk.c
|
||||||
void virtio_disk_init(void);
|
void virtio_disk_init(void);
|
||||||
void virtio_disk_rw(struct buf *, int);
|
void virtio_disk_rw(struct buf *, int);
|
||||||
void virtio_disk_intr(void);
|
void virtio_disk_intr(void);
|
||||||
|
|
||||||
// number of elements in fixed-size array
|
// number of elements in fixed-size array
|
||||||
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
|
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
|
14
kernel/elf.h
14
kernel/elf.h
|
@ -1,11 +1,11 @@
|
||||||
// Format of an ELF executable file
|
// Format of an ELF executable file
|
||||||
|
|
||||||
#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian
|
#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian
|
||||||
|
|
||||||
// File header
|
// File header
|
||||||
struct elfhdr {
|
struct elfhdr {
|
||||||
u32 magic; // must equal ELF_MAGIC
|
u32 magic; // must equal ELF_MAGIC
|
||||||
u8 elf[12];
|
u8 elf[12];
|
||||||
u16 type;
|
u16 type;
|
||||||
u16 machine;
|
u16 machine;
|
||||||
u32 version;
|
u32 version;
|
||||||
|
@ -34,9 +34,9 @@ struct proghdr {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Values for Proghdr type
|
// Values for Proghdr type
|
||||||
#define ELF_PROG_LOAD 1
|
#define ELF_PROG_LOAD 1
|
||||||
|
|
||||||
// Flag bits for Proghdr flags
|
// Flag bits for Proghdr flags
|
||||||
#define ELF_PROG_FLAG_EXEC 1
|
#define ELF_PROG_FLAG_EXEC 1
|
||||||
#define ELF_PROG_FLAG_WRITE 2
|
#define ELF_PROG_FLAG_WRITE 2
|
||||||
#define ELF_PROG_FLAG_READ 4
|
#define ELF_PROG_FLAG_READ 4
|
||||||
|
|
|
@ -9,31 +9,32 @@
|
||||||
|
|
||||||
static int loadseg(pde_t *, u64, struct inode *, u32, u32);
|
static int loadseg(pde_t *, u64, struct inode *, u32, u32);
|
||||||
|
|
||||||
int flags2perm(int flags)
|
int
|
||||||
|
flags2perm(int flags)
|
||||||
{
|
{
|
||||||
int perm = 0;
|
int perm = 0;
|
||||||
if(flags & 0x1)
|
if(flags & 0x1)
|
||||||
perm = PTE_X;
|
perm = PTE_X;
|
||||||
if(flags & 0x2)
|
if(flags & 0x2)
|
||||||
perm |= PTE_W;
|
perm |= PTE_W;
|
||||||
return perm;
|
return perm;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
exec(char *path, char **argv)
|
exec(char *path, char **argv)
|
||||||
{
|
{
|
||||||
char *s, *last;
|
char *s, *last;
|
||||||
int i, off;
|
int i, off;
|
||||||
u64 argc, sz = 0, sp, ustack[MAXARG], stackbase;
|
u64 argc, sz = 0, sp, ustack[MAXARG], stackbase;
|
||||||
struct elfhdr elf;
|
struct elfhdr elf;
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
struct proghdr ph;
|
struct proghdr ph;
|
||||||
pagetable_t pagetable = 0, oldpagetable;
|
pagetable_t pagetable = 0, oldpagetable;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
|
|
||||||
if((ip = namei(path)) == 0){
|
if((ip = namei(path)) == 0) {
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +51,7 @@ exec(char *path, char **argv)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
// Load program into memory.
|
// Load program into memory.
|
||||||
for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
|
for(i = 0, off = elf.phoff; i < elf.phnum; i++, off += sizeof(ph)) {
|
||||||
if(readi(ip, 0, (u64)&ph, off, sizeof(ph)) != sizeof(ph))
|
if(readi(ip, 0, (u64)&ph, off, sizeof(ph)) != sizeof(ph))
|
||||||
goto bad;
|
goto bad;
|
||||||
if(ph.type != ELF_PROG_LOAD)
|
if(ph.type != ELF_PROG_LOAD)
|
||||||
|
@ -80,10 +81,10 @@ exec(char *path, char **argv)
|
||||||
// Use the second as the user stack.
|
// Use the second as the user stack.
|
||||||
sz = PGROUNDUP(sz);
|
sz = PGROUNDUP(sz);
|
||||||
u64 sz1;
|
u64 sz1;
|
||||||
if((sz1 = uvmalloc(pagetable, sz, sz + 2*PGSIZE, PTE_W)) == 0)
|
if((sz1 = uvmalloc(pagetable, sz, sz + 2 * PGSIZE, PTE_W)) == 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
sz = sz1;
|
sz = sz1;
|
||||||
uvmclear(pagetable, sz-2*PGSIZE);
|
uvmclear(pagetable, sz - 2 * PGSIZE);
|
||||||
sp = sz;
|
sp = sz;
|
||||||
stackbase = sp - PGSIZE;
|
stackbase = sp - PGSIZE;
|
||||||
|
|
||||||
|
@ -102,11 +103,11 @@ exec(char *path, char **argv)
|
||||||
ustack[argc] = 0;
|
ustack[argc] = 0;
|
||||||
|
|
||||||
// push the array of argv[] pointers.
|
// push the array of argv[] pointers.
|
||||||
sp -= (argc+1) * sizeof(u64);
|
sp -= (argc + 1) * sizeof(u64);
|
||||||
sp -= sp % 16;
|
sp -= sp % 16;
|
||||||
if(sp < stackbase)
|
if(sp < stackbase)
|
||||||
goto bad;
|
goto bad;
|
||||||
if(copyout(pagetable, sp, (char *)ustack, (argc+1)*sizeof(u64)) < 0)
|
if(copyout(pagetable, sp, (char *)ustack, (argc + 1) * sizeof(u64)) < 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
// arguments to user main(argc, argv)
|
// arguments to user main(argc, argv)
|
||||||
|
@ -115,25 +116,25 @@ exec(char *path, char **argv)
|
||||||
p->trapframe->a1 = sp;
|
p->trapframe->a1 = sp;
|
||||||
|
|
||||||
// Save program name for debugging.
|
// Save program name for debugging.
|
||||||
for(last=s=path; *s; s++)
|
for(last = s = path; *s; s++)
|
||||||
if(*s == '/')
|
if(*s == '/')
|
||||||
last = s+1;
|
last = s + 1;
|
||||||
safestrcpy(p->name, last, sizeof(p->name));
|
safestrcpy(p->name, last, sizeof(p->name));
|
||||||
|
|
||||||
// Commit to the user image.
|
// Commit to the user image.
|
||||||
oldpagetable = p->pagetable;
|
oldpagetable = p->pagetable;
|
||||||
p->pagetable = pagetable;
|
p->pagetable = pagetable;
|
||||||
p->sz = sz;
|
p->sz = sz;
|
||||||
p->trapframe->epc = elf.entry; // initial program counter = main
|
p->trapframe->epc = elf.entry; // initial program counter = main
|
||||||
p->trapframe->sp = sp; // initial stack pointer
|
p->trapframe->sp = sp; // initial stack pointer
|
||||||
proc_freepagetable(oldpagetable, oldsz);
|
proc_freepagetable(oldpagetable, oldsz);
|
||||||
|
|
||||||
return argc; // this ends up in a0, the first argument to main(argc, argv)
|
return argc; // this ends up in a0, the first argument to main(argc, argv)
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
if(pagetable)
|
if(pagetable)
|
||||||
proc_freepagetable(pagetable, sz);
|
proc_freepagetable(pagetable, sz);
|
||||||
if(ip){
|
if(ip) {
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
end_op();
|
end_op();
|
||||||
}
|
}
|
||||||
|
@ -150,7 +151,7 @@ loadseg(pagetable_t pagetable, u64 va, struct inode *ip, u32 offset, u32 sz)
|
||||||
u32 i, n;
|
u32 i, n;
|
||||||
u64 pa;
|
u64 pa;
|
||||||
|
|
||||||
for(i = 0; i < sz; i += PGSIZE){
|
for(i = 0; i < sz; i += PGSIZE) {
|
||||||
pa = walkaddr(pagetable, va + i);
|
pa = walkaddr(pagetable, va + i);
|
||||||
if(pa == 0)
|
if(pa == 0)
|
||||||
panic("loadseg: address should exist");
|
panic("loadseg: address should exist");
|
||||||
|
@ -158,9 +159,9 @@ loadseg(pagetable_t pagetable, u64 va, struct inode *ip, u32 offset, u32 sz)
|
||||||
n = sz - i;
|
n = sz - i;
|
||||||
else
|
else
|
||||||
n = PGSIZE;
|
n = PGSIZE;
|
||||||
if(readi(ip, 0, (u64)pa, offset+i, n) != n)
|
if(readi(ip, 0, (u64)pa, offset + i, n) != n)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define O_RDONLY 0x000
|
#define O_RDONLY 0x000
|
||||||
#define O_WRONLY 0x001
|
#define O_WRONLY 0x001
|
||||||
#define O_RDWR 0x002
|
#define O_RDWR 0x002
|
||||||
#define O_CREATE 0x200
|
#define O_CREATE 0x200
|
||||||
#define O_TRUNC 0x400
|
#define O_TRUNC 0x400
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
struct devsw devsw[NDEV];
|
struct devsw devsw[NDEV];
|
||||||
struct {
|
struct {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
struct file file[NFILE];
|
struct file file[NFILE];
|
||||||
} ftable;
|
} ftable;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -26,14 +26,14 @@ fileinit(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a file structure.
|
// Allocate a file structure.
|
||||||
struct file*
|
struct file *
|
||||||
filealloc(void)
|
filealloc(void)
|
||||||
{
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
|
|
||||||
acquire(&ftable.lock);
|
acquire(&ftable.lock);
|
||||||
for(f = ftable.file; f < ftable.file + NFILE; f++){
|
for(f = ftable.file; f < ftable.file + NFILE; f++) {
|
||||||
if(f->ref == 0){
|
if(f->ref == 0) {
|
||||||
f->ref = 1;
|
f->ref = 1;
|
||||||
release(&ftable.lock);
|
release(&ftable.lock);
|
||||||
return f;
|
return f;
|
||||||
|
@ -44,7 +44,7 @@ filealloc(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment ref count for file f.
|
// Increment ref count for file f.
|
||||||
struct file*
|
struct file *
|
||||||
filedup(struct file *f)
|
filedup(struct file *f)
|
||||||
{
|
{
|
||||||
acquire(&ftable.lock);
|
acquire(&ftable.lock);
|
||||||
|
@ -64,7 +64,7 @@ fileclose(struct file *f)
|
||||||
acquire(&ftable.lock);
|
acquire(&ftable.lock);
|
||||||
if(f->ref < 1)
|
if(f->ref < 1)
|
||||||
panic("fileclose");
|
panic("fileclose");
|
||||||
if(--f->ref > 0){
|
if(--f->ref > 0) {
|
||||||
release(&ftable.lock);
|
release(&ftable.lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -73,9 +73,9 @@ fileclose(struct file *f)
|
||||||
f->type = FD_NONE;
|
f->type = FD_NONE;
|
||||||
release(&ftable.lock);
|
release(&ftable.lock);
|
||||||
|
|
||||||
if(ff.type == FD_PIPE){
|
if(ff.type == FD_PIPE) {
|
||||||
pipeclose(ff.pipe, ff.writable);
|
pipeclose(ff.pipe, ff.writable);
|
||||||
} else if(ff.type == FD_INODE || ff.type == FD_DEVICE){
|
} else if(ff.type == FD_INODE || ff.type == FD_DEVICE) {
|
||||||
begin_op();
|
begin_op();
|
||||||
iput(ff.ip);
|
iput(ff.ip);
|
||||||
end_op();
|
end_op();
|
||||||
|
@ -88,9 +88,9 @@ int
|
||||||
filestat(struct file *f, u64 addr)
|
filestat(struct file *f, u64 addr)
|
||||||
{
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if(f->type == FD_INODE || f->type == FD_DEVICE){
|
if(f->type == FD_INODE || f->type == FD_DEVICE) {
|
||||||
ilock(f->ip);
|
ilock(f->ip);
|
||||||
stati(f->ip, &st);
|
stati(f->ip, &st);
|
||||||
iunlock(f->ip);
|
iunlock(f->ip);
|
||||||
|
@ -111,13 +111,13 @@ fileread(struct file *f, u64 addr, int n)
|
||||||
if(f->readable == 0)
|
if(f->readable == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(f->type == FD_PIPE){
|
if(f->type == FD_PIPE) {
|
||||||
r = piperead(f->pipe, addr, n);
|
r = piperead(f->pipe, addr, n);
|
||||||
} else if(f->type == FD_DEVICE){
|
} else if(f->type == FD_DEVICE) {
|
||||||
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
|
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
|
||||||
return -1;
|
return -1;
|
||||||
r = devsw[f->major].read(1, addr, n);
|
r = devsw[f->major].read(1, addr, n);
|
||||||
} else if(f->type == FD_INODE){
|
} else if(f->type == FD_INODE) {
|
||||||
ilock(f->ip);
|
ilock(f->ip);
|
||||||
if((r = readi(f->ip, 1, addr, f->off, n)) > 0)
|
if((r = readi(f->ip, 1, addr, f->off, n)) > 0)
|
||||||
f->off += r;
|
f->off += r;
|
||||||
|
@ -139,34 +139,34 @@ filewrite(struct file *f, u64 addr, int n)
|
||||||
if(f->writable == 0)
|
if(f->writable == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(f->type == FD_PIPE){
|
if(f->type == FD_PIPE) {
|
||||||
ret = pipewrite(f->pipe, addr, n);
|
ret = pipewrite(f->pipe, addr, n);
|
||||||
} else if(f->type == FD_DEVICE){
|
} else if(f->type == FD_DEVICE) {
|
||||||
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].write)
|
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].write)
|
||||||
return -1;
|
return -1;
|
||||||
ret = devsw[f->major].write(1, addr, n);
|
ret = devsw[f->major].write(1, addr, n);
|
||||||
} else if(f->type == FD_INODE){
|
} else if(f->type == FD_INODE) {
|
||||||
// write a few blocks at a time to avoid exceeding
|
// write a few blocks at a time to avoid exceeding
|
||||||
// the maximum log transaction size, including
|
// the maximum log transaction size, including
|
||||||
// i-node, indirect block, allocation blocks,
|
// i-node, indirect block, allocation blocks,
|
||||||
// and 2 blocks of slop for non-aligned writes.
|
// and 2 blocks of slop for non-aligned writes.
|
||||||
// this really belongs lower down, since writei()
|
// this really belongs lower down, since writei()
|
||||||
// might be writing a device like the console.
|
// might be writing a device like the console.
|
||||||
int max = ((MAXOPBLOCKS-1-1-2) / 2) * BSIZE;
|
int max = ((MAXOPBLOCKS - 1 - 1 - 2) / 2) * BSIZE;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(i < n){
|
while(i < n) {
|
||||||
int n1 = n - i;
|
int n1 = n - i;
|
||||||
if(n1 > max)
|
if(n1 > max)
|
||||||
n1 = max;
|
n1 = max;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
ilock(f->ip);
|
ilock(f->ip);
|
||||||
if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0)
|
if((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0)
|
||||||
f->off += r;
|
f->off += r;
|
||||||
iunlock(f->ip);
|
iunlock(f->ip);
|
||||||
end_op();
|
end_op();
|
||||||
|
|
||||||
if(r != n1){
|
if(r != n1) {
|
||||||
// error from writei
|
// error from writei
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -179,4 +179,3 @@ filewrite(struct file *f, u64 addr, int n)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
struct file {
|
struct file {
|
||||||
enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type;
|
enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type;
|
||||||
int ref; // reference count
|
int ref; // reference count
|
||||||
char readable;
|
char readable;
|
||||||
char writable;
|
char writable;
|
||||||
struct pipe *pipe; // FD_PIPE
|
struct pipe *pipe; // FD_PIPE
|
||||||
struct inode *ip; // FD_INODE and FD_DEVICE
|
struct inode *ip; // FD_INODE and FD_DEVICE
|
||||||
u32 off; // FD_INODE
|
u32 off; // FD_INODE
|
||||||
short major; // FD_DEVICE
|
short major; // FD_DEVICE
|
||||||
};
|
};
|
||||||
|
|
||||||
#define major(dev) ((dev) >> 16 & 0xFFFF)
|
#define major(dev) ((dev) >> 16 & 0xFFFF)
|
||||||
#define minor(dev) ((dev) & 0xFFFF)
|
#define minor(dev) ((dev) & 0xFFFF)
|
||||||
#define mkdev(m,n) ((u32)((m)<<16| (n)))
|
#define mkdev(m, n) ((u32)((m) << 16 | (n)))
|
||||||
|
|
||||||
// in-memory copy of an inode
|
// in-memory copy of an inode
|
||||||
struct inode {
|
struct inode {
|
||||||
u32 dev; // Device number
|
u32 dev; // Device number
|
||||||
u32 inum; // Inode number
|
u32 inum; // Inode number
|
||||||
int ref; // Reference count
|
int ref; // Reference count
|
||||||
struct sleeplock lock; // protects everything below here
|
struct sleeplock lock; // protects everything below here
|
||||||
int valid; // inode has been read from disk?
|
int valid; // inode has been read from disk?
|
||||||
|
|
||||||
short type; // copy of disk inode
|
short type; // copy of disk inode
|
||||||
short major;
|
short major;
|
||||||
short minor;
|
short minor;
|
||||||
short nlink;
|
short nlink;
|
||||||
u32 size;
|
u32 size;
|
||||||
u32 addrs[NDIRECT+1];
|
u32 addrs[NDIRECT + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
// map major device number to device functions.
|
// map major device number to device functions.
|
||||||
|
|
145
kernel/fs.c
145
kernel/fs.c
|
@ -24,7 +24,7 @@
|
||||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
// there should be one superblock per disk device, but we run with
|
// there should be one superblock per disk device, but we run with
|
||||||
// only one device
|
// only one device
|
||||||
struct superblock sb;
|
struct superblock sb;
|
||||||
|
|
||||||
// Read the super block.
|
// Read the super block.
|
||||||
static void
|
static void
|
||||||
|
@ -39,7 +39,8 @@ readsb(int dev, struct superblock *sb)
|
||||||
|
|
||||||
// Init fs
|
// Init fs
|
||||||
void
|
void
|
||||||
fsinit(int dev) {
|
fsinit(int dev)
|
||||||
|
{
|
||||||
readsb(dev, &sb);
|
readsb(dev, &sb);
|
||||||
if(sb.magic != FSMAGIC)
|
if(sb.magic != FSMAGIC)
|
||||||
panic("invalid file system");
|
panic("invalid file system");
|
||||||
|
@ -65,16 +66,16 @@ bzero(int dev, int bno)
|
||||||
static u32
|
static u32
|
||||||
balloc(u32 dev)
|
balloc(u32 dev)
|
||||||
{
|
{
|
||||||
int b, bi, m;
|
int b, bi, m;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
bp = 0;
|
bp = 0;
|
||||||
for(b = 0; b < sb.size; b += BPB){
|
for(b = 0; b < sb.size; b += BPB) {
|
||||||
bp = bread(dev, BBLOCK(b, sb));
|
bp = bread(dev, BBLOCK(b, sb));
|
||||||
for(bi = 0; bi < BPB && b + bi < sb.size; bi++){
|
for(bi = 0; bi < BPB && b + bi < sb.size; bi++) {
|
||||||
m = 1 << (bi % 8);
|
m = 1 << (bi % 8);
|
||||||
if((bp->data[bi/8] & m) == 0){ // Is block free?
|
if((bp->data[bi / 8] & m) == 0) { // Is block free?
|
||||||
bp->data[bi/8] |= m; // Mark block in use.
|
bp->data[bi / 8] |= m; // Mark block in use.
|
||||||
log_write(bp);
|
log_write(bp);
|
||||||
brelse(bp);
|
brelse(bp);
|
||||||
bzero(dev, b + bi);
|
bzero(dev, b + bi);
|
||||||
|
@ -92,14 +93,14 @@ static void
|
||||||
bfree(int dev, u32 b)
|
bfree(int dev, u32 b)
|
||||||
{
|
{
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
int bi, m;
|
int bi, m;
|
||||||
|
|
||||||
bp = bread(dev, BBLOCK(b, sb));
|
bp = bread(dev, BBLOCK(b, sb));
|
||||||
bi = b % BPB;
|
bi = b % BPB;
|
||||||
m = 1 << (bi % 8);
|
m = 1 << (bi % 8);
|
||||||
if((bp->data[bi/8] & m) == 0)
|
if((bp->data[bi / 8] & m) == 0)
|
||||||
panic("freeing free block");
|
panic("freeing free block");
|
||||||
bp->data[bi/8] &= ~m;
|
bp->data[bi / 8] &= ~m;
|
||||||
log_write(bp);
|
log_write(bp);
|
||||||
brelse(bp);
|
brelse(bp);
|
||||||
}
|
}
|
||||||
|
@ -175,40 +176,40 @@ bfree(int dev, u32 b)
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
struct inode inode[NINODE];
|
struct inode inode[NINODE];
|
||||||
} itable;
|
} itable;
|
||||||
|
|
||||||
void
|
void
|
||||||
iinit()
|
iinit()
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
initlock(&itable.lock, "itable");
|
initlock(&itable.lock, "itable");
|
||||||
for(i = 0; i < NINODE; i++) {
|
for(i = 0; i < NINODE; i++) {
|
||||||
initsleeplock(&itable.inode[i].lock, "inode");
|
initsleeplock(&itable.inode[i].lock, "inode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct inode* iget(u32 dev, u32 inum);
|
static struct inode *iget(u32 dev, u32 inum);
|
||||||
|
|
||||||
// Allocate an inode on device dev.
|
// Allocate an inode on device dev.
|
||||||
// Mark it as allocated by giving it type type.
|
// Mark it as allocated by giving it type type.
|
||||||
// Returns an unlocked but allocated and referenced inode,
|
// Returns an unlocked but allocated and referenced inode,
|
||||||
// or NULL if there is no free inode.
|
// or NULL if there is no free inode.
|
||||||
struct inode*
|
struct inode *
|
||||||
ialloc(u32 dev, short type)
|
ialloc(u32 dev, short type)
|
||||||
{
|
{
|
||||||
int inum;
|
int inum;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
||||||
for(inum = 1; inum < sb.ninodes; inum++){
|
for(inum = 1; inum < sb.ninodes; inum++) {
|
||||||
bp = bread(dev, IBLOCK(inum, sb));
|
bp = bread(dev, IBLOCK(inum, sb));
|
||||||
dip = (struct dinode*)bp->data + inum%IPB;
|
dip = (struct dinode *)bp->data + inum % IPB;
|
||||||
if(dip->type == 0){ // a free inode
|
if(dip->type == 0) { // a free inode
|
||||||
memset(dip, 0, sizeof(*dip));
|
memset(dip, 0, sizeof(*dip));
|
||||||
dip->type = type;
|
dip->type = type;
|
||||||
log_write(bp); // mark it allocated on the disk
|
log_write(bp); // mark it allocated on the disk
|
||||||
brelse(bp);
|
brelse(bp);
|
||||||
return iget(dev, inum);
|
return iget(dev, inum);
|
||||||
}
|
}
|
||||||
|
@ -225,11 +226,11 @@ ialloc(u32 dev, short type)
|
||||||
void
|
void
|
||||||
iupdate(struct inode *ip)
|
iupdate(struct inode *ip)
|
||||||
{
|
{
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
||||||
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
||||||
dip = (struct dinode*)bp->data + ip->inum%IPB;
|
dip = (struct dinode *)bp->data + ip->inum % IPB;
|
||||||
dip->type = ip->type;
|
dip->type = ip->type;
|
||||||
dip->major = ip->major;
|
dip->major = ip->major;
|
||||||
dip->minor = ip->minor;
|
dip->minor = ip->minor;
|
||||||
|
@ -243,7 +244,7 @@ iupdate(struct inode *ip)
|
||||||
// Find the inode with number inum on device dev
|
// Find the inode with number inum on device dev
|
||||||
// and return the in-memory copy. Does not lock
|
// and return the in-memory copy. Does not lock
|
||||||
// the inode and does not read it from disk.
|
// the inode and does not read it from disk.
|
||||||
static struct inode*
|
static struct inode *
|
||||||
iget(u32 dev, u32 inum)
|
iget(u32 dev, u32 inum)
|
||||||
{
|
{
|
||||||
struct inode *ip, *empty;
|
struct inode *ip, *empty;
|
||||||
|
@ -252,13 +253,13 @@ iget(u32 dev, u32 inum)
|
||||||
|
|
||||||
// Is the inode already in the table?
|
// Is the inode already in the table?
|
||||||
empty = 0;
|
empty = 0;
|
||||||
for(ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++){
|
for(ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++) {
|
||||||
if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
|
if(ip->ref > 0 && ip->dev == dev && ip->inum == inum) {
|
||||||
ip->ref++;
|
ip->ref++;
|
||||||
release(&itable.lock);
|
release(&itable.lock);
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
if(empty == 0 && ip->ref == 0) // Remember empty slot.
|
if(empty == 0 && ip->ref == 0) // Remember empty slot.
|
||||||
empty = ip;
|
empty = ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +279,7 @@ iget(u32 dev, u32 inum)
|
||||||
|
|
||||||
// Increment reference count for ip.
|
// Increment reference count for ip.
|
||||||
// Returns ip to enable ip = idup(ip1) idiom.
|
// Returns ip to enable ip = idup(ip1) idiom.
|
||||||
struct inode*
|
struct inode *
|
||||||
idup(struct inode *ip)
|
idup(struct inode *ip)
|
||||||
{
|
{
|
||||||
acquire(&itable.lock);
|
acquire(&itable.lock);
|
||||||
|
@ -292,7 +293,7 @@ idup(struct inode *ip)
|
||||||
void
|
void
|
||||||
ilock(struct inode *ip)
|
ilock(struct inode *ip)
|
||||||
{
|
{
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
||||||
if(ip == 0 || ip->ref < 1)
|
if(ip == 0 || ip->ref < 1)
|
||||||
|
@ -300,9 +301,9 @@ ilock(struct inode *ip)
|
||||||
|
|
||||||
acquiresleep(&ip->lock);
|
acquiresleep(&ip->lock);
|
||||||
|
|
||||||
if(ip->valid == 0){
|
if(ip->valid == 0) {
|
||||||
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
bp = bread(ip->dev, IBLOCK(ip->inum, sb));
|
||||||
dip = (struct dinode*)bp->data + ip->inum%IPB;
|
dip = (struct dinode *)bp->data + ip->inum % IPB;
|
||||||
ip->type = dip->type;
|
ip->type = dip->type;
|
||||||
ip->major = dip->major;
|
ip->major = dip->major;
|
||||||
ip->minor = dip->minor;
|
ip->minor = dip->minor;
|
||||||
|
@ -338,7 +339,7 @@ iput(struct inode *ip)
|
||||||
{
|
{
|
||||||
acquire(&itable.lock);
|
acquire(&itable.lock);
|
||||||
|
|
||||||
if(ip->ref == 1 && ip->valid && ip->nlink == 0){
|
if(ip->ref == 1 && ip->valid && ip->nlink == 0) {
|
||||||
// inode has no links and no other references: truncate and free.
|
// inode has no links and no other references: truncate and free.
|
||||||
|
|
||||||
// ip->ref == 1 means no other process can have ip locked,
|
// ip->ref == 1 means no other process can have ip locked,
|
||||||
|
@ -382,11 +383,11 @@ iunlockput(struct inode *ip)
|
||||||
static u32
|
static u32
|
||||||
bmap(struct inode *ip, u32 bn)
|
bmap(struct inode *ip, u32 bn)
|
||||||
{
|
{
|
||||||
u32 addr, *a;
|
u32 addr, *a;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
if(bn < NDIRECT){
|
if(bn < NDIRECT) {
|
||||||
if((addr = ip->addrs[bn]) == 0){
|
if((addr = ip->addrs[bn]) == 0) {
|
||||||
addr = balloc(ip->dev);
|
addr = balloc(ip->dev);
|
||||||
if(addr == 0)
|
if(addr == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -396,19 +397,19 @@ bmap(struct inode *ip, u32 bn)
|
||||||
}
|
}
|
||||||
bn -= NDIRECT;
|
bn -= NDIRECT;
|
||||||
|
|
||||||
if(bn < NINDIRECT){
|
if(bn < NINDIRECT) {
|
||||||
// Load indirect block, allocating if necessary.
|
// Load indirect block, allocating if necessary.
|
||||||
if((addr = ip->addrs[NDIRECT]) == 0){
|
if((addr = ip->addrs[NDIRECT]) == 0) {
|
||||||
addr = balloc(ip->dev);
|
addr = balloc(ip->dev);
|
||||||
if(addr == 0)
|
if(addr == 0)
|
||||||
return 0;
|
return 0;
|
||||||
ip->addrs[NDIRECT] = addr;
|
ip->addrs[NDIRECT] = addr;
|
||||||
}
|
}
|
||||||
bp = bread(ip->dev, addr);
|
bp = bread(ip->dev, addr);
|
||||||
a = (u32*)bp->data;
|
a = (u32 *)bp->data;
|
||||||
if((addr = a[bn]) == 0){
|
if((addr = a[bn]) == 0) {
|
||||||
addr = balloc(ip->dev);
|
addr = balloc(ip->dev);
|
||||||
if(addr){
|
if(addr) {
|
||||||
a[bn] = addr;
|
a[bn] = addr;
|
||||||
log_write(bp);
|
log_write(bp);
|
||||||
}
|
}
|
||||||
|
@ -425,21 +426,21 @@ bmap(struct inode *ip, u32 bn)
|
||||||
void
|
void
|
||||||
itrunc(struct inode *ip)
|
itrunc(struct inode *ip)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
u32 *a;
|
u32 *a;
|
||||||
|
|
||||||
for(i = 0; i < NDIRECT; i++){
|
for(i = 0; i < NDIRECT; i++) {
|
||||||
if(ip->addrs[i]){
|
if(ip->addrs[i]) {
|
||||||
bfree(ip->dev, ip->addrs[i]);
|
bfree(ip->dev, ip->addrs[i]);
|
||||||
ip->addrs[i] = 0;
|
ip->addrs[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ip->addrs[NDIRECT]){
|
if(ip->addrs[NDIRECT]) {
|
||||||
bp = bread(ip->dev, ip->addrs[NDIRECT]);
|
bp = bread(ip->dev, ip->addrs[NDIRECT]);
|
||||||
a = (u32*)bp->data;
|
a = (u32 *)bp->data;
|
||||||
for(j = 0; j < NINDIRECT; j++){
|
for(j = 0; j < NINDIRECT; j++) {
|
||||||
if(a[j])
|
if(a[j])
|
||||||
bfree(ip->dev, a[j]);
|
bfree(ip->dev, a[j]);
|
||||||
}
|
}
|
||||||
|
@ -471,7 +472,7 @@ stati(struct inode *ip, struct stat *st)
|
||||||
int
|
int
|
||||||
readi(struct inode *ip, int user_dst, u64 dst, u32 off, u32 n)
|
readi(struct inode *ip, int user_dst, u64 dst, u32 off, u32 n)
|
||||||
{
|
{
|
||||||
u32 tot, m;
|
u32 tot, m;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
if(off > ip->size || off + n < off)
|
if(off > ip->size || off + n < off)
|
||||||
|
@ -479,12 +480,12 @@ readi(struct inode *ip, int user_dst, u64 dst, u32 off, u32 n)
|
||||||
if(off + n > ip->size)
|
if(off + n > ip->size)
|
||||||
n = ip->size - off;
|
n = ip->size - off;
|
||||||
|
|
||||||
for(tot=0; tot<n; tot+=m, off+=m, dst+=m){
|
for(tot = 0; tot < n; tot += m, off += m, dst += m) {
|
||||||
u32 addr = bmap(ip, off/BSIZE);
|
u32 addr = bmap(ip, off / BSIZE);
|
||||||
if(addr == 0)
|
if(addr == 0)
|
||||||
break;
|
break;
|
||||||
bp = bread(ip->dev, addr);
|
bp = bread(ip->dev, addr);
|
||||||
m = min(n - tot, BSIZE - off%BSIZE);
|
m = min(n - tot, BSIZE - off % BSIZE);
|
||||||
if(either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) {
|
if(either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) {
|
||||||
brelse(bp);
|
brelse(bp);
|
||||||
tot = -1;
|
tot = -1;
|
||||||
|
@ -505,20 +506,20 @@ readi(struct inode *ip, int user_dst, u64 dst, u32 off, u32 n)
|
||||||
int
|
int
|
||||||
writei(struct inode *ip, int user_src, u64 src, u32 off, u32 n)
|
writei(struct inode *ip, int user_src, u64 src, u32 off, u32 n)
|
||||||
{
|
{
|
||||||
u32 tot, m;
|
u32 tot, m;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
if(off > ip->size || off + n < off)
|
if(off > ip->size || off + n < off)
|
||||||
return -1;
|
return -1;
|
||||||
if(off + n > MAXFILE*BSIZE)
|
if(off + n > MAXFILE * BSIZE)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for(tot=0; tot<n; tot+=m, off+=m, src+=m){
|
for(tot = 0; tot < n; tot += m, off += m, src += m) {
|
||||||
u32 addr = bmap(ip, off/BSIZE);
|
u32 addr = bmap(ip, off / BSIZE);
|
||||||
if(addr == 0)
|
if(addr == 0)
|
||||||
break;
|
break;
|
||||||
bp = bread(ip->dev, addr);
|
bp = bread(ip->dev, addr);
|
||||||
m = min(n - tot, BSIZE - off%BSIZE);
|
m = min(n - tot, BSIZE - off % BSIZE);
|
||||||
if(either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) {
|
if(either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) {
|
||||||
brelse(bp);
|
brelse(bp);
|
||||||
break;
|
break;
|
||||||
|
@ -548,21 +549,21 @@ namecmp(const char *s, const char *t)
|
||||||
|
|
||||||
// Look for a directory entry in a directory.
|
// Look for a directory entry in a directory.
|
||||||
// If found, set *poff to byte offset of entry.
|
// If found, set *poff to byte offset of entry.
|
||||||
struct inode*
|
struct inode *
|
||||||
dirlookup(struct inode *dp, char *name, u32 *poff)
|
dirlookup(struct inode *dp, char *name, u32 *poff)
|
||||||
{
|
{
|
||||||
u32 off, inum;
|
u32 off, inum;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
|
|
||||||
if(dp->type != T_DIR)
|
if(dp->type != T_DIR)
|
||||||
panic("dirlookup not DIR");
|
panic("dirlookup not DIR");
|
||||||
|
|
||||||
for(off = 0; off < dp->size; off += sizeof(de)){
|
for(off = 0; off < dp->size; off += sizeof(de)) {
|
||||||
if(readi(dp, 0, (u64)&de, off, sizeof(de)) != sizeof(de))
|
if(readi(dp, 0, (u64)&de, off, sizeof(de)) != sizeof(de))
|
||||||
panic("dirlookup read");
|
panic("dirlookup read");
|
||||||
if(de.inum == 0)
|
if(de.inum == 0)
|
||||||
continue;
|
continue;
|
||||||
if(namecmp(name, de.name) == 0){
|
if(namecmp(name, de.name) == 0) {
|
||||||
// entry matches path element
|
// entry matches path element
|
||||||
if(poff)
|
if(poff)
|
||||||
*poff = off;
|
*poff = off;
|
||||||
|
@ -579,18 +580,18 @@ dirlookup(struct inode *dp, char *name, u32 *poff)
|
||||||
int
|
int
|
||||||
dirlink(struct inode *dp, char *name, u32 inum)
|
dirlink(struct inode *dp, char *name, u32 inum)
|
||||||
{
|
{
|
||||||
int off;
|
int off;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
|
|
||||||
// Check that name is not present.
|
// Check that name is not present.
|
||||||
if((ip = dirlookup(dp, name, 0)) != 0){
|
if((ip = dirlookup(dp, name, 0)) != 0) {
|
||||||
iput(ip);
|
iput(ip);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for an empty dirent.
|
// Look for an empty dirent.
|
||||||
for(off = 0; off < dp->size; off += sizeof(de)){
|
for(off = 0; off < dp->size; off += sizeof(de)) {
|
||||||
if(readi(dp, 0, (u64)&de, off, sizeof(de)) != sizeof(de))
|
if(readi(dp, 0, (u64)&de, off, sizeof(de)) != sizeof(de))
|
||||||
panic("dirlink read");
|
panic("dirlink read");
|
||||||
if(de.inum == 0)
|
if(de.inum == 0)
|
||||||
|
@ -619,11 +620,11 @@ dirlink(struct inode *dp, char *name, u32 inum)
|
||||||
// skipelem("a", name) = "", setting name = "a"
|
// skipelem("a", name) = "", setting name = "a"
|
||||||
// skipelem("", name) = skipelem("////", name) = 0
|
// skipelem("", name) = skipelem("////", name) = 0
|
||||||
//
|
//
|
||||||
static char*
|
static char *
|
||||||
skipelem(char *path, char *name)
|
skipelem(char *path, char *name)
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
while(*path == '/')
|
while(*path == '/')
|
||||||
path++;
|
path++;
|
||||||
|
@ -648,7 +649,7 @@ skipelem(char *path, char *name)
|
||||||
// If parent != 0, return the inode for the parent and copy the final
|
// If parent != 0, return the inode for the parent and copy the final
|
||||||
// path element into name, which must have room for DIRSIZ bytes.
|
// path element into name, which must have room for DIRSIZ bytes.
|
||||||
// Must be called inside a transaction since it calls iput().
|
// Must be called inside a transaction since it calls iput().
|
||||||
static struct inode*
|
static struct inode *
|
||||||
namex(char *path, int nameiparent, char *name)
|
namex(char *path, int nameiparent, char *name)
|
||||||
{
|
{
|
||||||
struct inode *ip, *next;
|
struct inode *ip, *next;
|
||||||
|
@ -658,39 +659,39 @@ namex(char *path, int nameiparent, char *name)
|
||||||
else
|
else
|
||||||
ip = idup(myproc()->cwd);
|
ip = idup(myproc()->cwd);
|
||||||
|
|
||||||
while((path = skipelem(path, name)) != 0){
|
while((path = skipelem(path, name)) != 0) {
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
if(ip->type != T_DIR){
|
if(ip->type != T_DIR) {
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(nameiparent && *path == '\0'){
|
if(nameiparent && *path == '\0') {
|
||||||
// Stop one level early.
|
// Stop one level early.
|
||||||
iunlock(ip);
|
iunlock(ip);
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
if((next = dirlookup(ip, name, 0)) == 0){
|
if((next = dirlookup(ip, name, 0)) == 0) {
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
ip = next;
|
ip = next;
|
||||||
}
|
}
|
||||||
if(nameiparent){
|
if(nameiparent) {
|
||||||
iput(ip);
|
iput(ip);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct inode*
|
struct inode *
|
||||||
namei(char *path)
|
namei(char *path)
|
||||||
{
|
{
|
||||||
char name[DIRSIZ];
|
char name[DIRSIZ];
|
||||||
return namex(path, 0, name);
|
return namex(path, 0, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct inode*
|
struct inode *
|
||||||
nameiparent(char *path, char *name)
|
nameiparent(char *path, char *name)
|
||||||
{
|
{
|
||||||
return namex(path, 1, name);
|
return namex(path, 1, name);
|
||||||
|
|
48
kernel/fs.h
48
kernel/fs.h
|
@ -1,9 +1,8 @@
|
||||||
// On-disk file system format.
|
// On-disk file system format.
|
||||||
// Both the kernel and user programs use this header file.
|
// Both the kernel and user programs use this header file.
|
||||||
|
|
||||||
|
#define ROOTINO 1 // root i-number
|
||||||
#define ROOTINO 1 // root i-number
|
#define BSIZE 1024 // block size
|
||||||
#define BSIZE 1024 // block size
|
|
||||||
|
|
||||||
// Disk layout:
|
// Disk layout:
|
||||||
// [ boot block | super block | log | inode blocks |
|
// [ boot block | super block | log | inode blocks |
|
||||||
|
@ -12,49 +11,48 @@
|
||||||
// mkfs computes the super block and builds an initial file system. The
|
// mkfs computes the super block and builds an initial file system. The
|
||||||
// super block describes the disk layout:
|
// super block describes the disk layout:
|
||||||
struct superblock {
|
struct superblock {
|
||||||
u32 magic; // Must be FSMAGIC
|
u32 magic; // Must be FSMAGIC
|
||||||
u32 size; // Size of file system image (blocks)
|
u32 size; // Size of file system image (blocks)
|
||||||
u32 nblocks; // Number of data blocks
|
u32 nblocks; // Number of data blocks
|
||||||
u32 ninodes; // Number of inodes.
|
u32 ninodes; // Number of inodes.
|
||||||
u32 nlog; // Number of log blocks
|
u32 nlog; // Number of log blocks
|
||||||
u32 logstart; // Block number of first log block
|
u32 logstart; // Block number of first log block
|
||||||
u32 inodestart; // Block number of first inode block
|
u32 inodestart; // Block number of first inode block
|
||||||
u32 bmapstart; // Block number of first free map block
|
u32 bmapstart; // Block number of first free map block
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FSMAGIC 0x10203040
|
#define FSMAGIC 0x10203040
|
||||||
|
|
||||||
#define NDIRECT 12
|
#define NDIRECT 12
|
||||||
#define NINDIRECT (BSIZE / sizeof(u32))
|
#define NINDIRECT (BSIZE / sizeof(u32))
|
||||||
#define MAXFILE (NDIRECT + NINDIRECT)
|
#define MAXFILE (NDIRECT + NINDIRECT)
|
||||||
|
|
||||||
// On-disk inode structure
|
// On-disk inode structure
|
||||||
struct dinode {
|
struct dinode {
|
||||||
short type; // File type
|
short type; // File type
|
||||||
short major; // Major device number (T_DEVICE only)
|
short major; // Major device number (T_DEVICE only)
|
||||||
short minor; // Minor device number (T_DEVICE only)
|
short minor; // Minor device number (T_DEVICE only)
|
||||||
short nlink; // Number of links to inode in file system
|
short nlink; // Number of links to inode in file system
|
||||||
u32 size; // Size of file (bytes)
|
u32 size; // Size of file (bytes)
|
||||||
u32 addrs[NDIRECT+1]; // Data block addresses
|
u32 addrs[NDIRECT + 1]; // Data block addresses
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inodes per block.
|
// Inodes per block.
|
||||||
#define IPB (BSIZE / sizeof(struct dinode))
|
#define IPB (BSIZE / sizeof(struct dinode))
|
||||||
|
|
||||||
// Block containing inode i
|
// Block containing inode i
|
||||||
#define IBLOCK(i, sb) ((i) / IPB + sb.inodestart)
|
#define IBLOCK(i, sb) ((i) / IPB + sb.inodestart)
|
||||||
|
|
||||||
// Bitmap bits per block
|
// Bitmap bits per block
|
||||||
#define BPB (BSIZE*8)
|
#define BPB (BSIZE * 8)
|
||||||
|
|
||||||
// Block of free map containing bit for block b
|
// Block of free map containing bit for block b
|
||||||
#define BBLOCK(b, sb) ((b)/BPB + sb.bmapstart)
|
#define BBLOCK(b, sb) ((b) / BPB + sb.bmapstart)
|
||||||
|
|
||||||
// Directory is a file containing a sequence of dirent structures.
|
// Directory is a file containing a sequence of dirent structures.
|
||||||
#define DIRSIZ 14
|
#define DIRSIZ 14
|
||||||
|
|
||||||
struct dirent {
|
struct dirent {
|
||||||
u16 inum;
|
u16 inum;
|
||||||
char name[DIRSIZ];
|
char name[DIRSIZ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,22 +20,22 @@ struct run {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
struct run *freelist;
|
struct run *freelist;
|
||||||
} kmem;
|
} kmem;
|
||||||
|
|
||||||
void
|
void
|
||||||
kinit()
|
kinit()
|
||||||
{
|
{
|
||||||
initlock(&kmem.lock, "kmem");
|
initlock(&kmem.lock, "kmem");
|
||||||
freerange(end, (void*)PHYSTOP);
|
freerange(end, (void *)PHYSTOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
freerange(void *pa_start, void *pa_end)
|
freerange(void *pa_start, void *pa_end)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
p = (char*)PGROUNDUP((u64)pa_start);
|
p = (char *)PGROUNDUP((u64)pa_start);
|
||||||
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
|
for(; p + PGSIZE <= (char *)pa_end; p += PGSIZE)
|
||||||
kfree(p);
|
kfree(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,13 +48,13 @@ kfree(void *pa)
|
||||||
{
|
{
|
||||||
struct run *r;
|
struct run *r;
|
||||||
|
|
||||||
if(((u64)pa % PGSIZE) != 0 || (char*)pa < end || (u64)pa >= PHYSTOP)
|
if(((u64)pa % PGSIZE) != 0 || (char *)pa < end || (u64)pa >= PHYSTOP)
|
||||||
panic("kfree");
|
panic("kfree");
|
||||||
|
|
||||||
// Fill with junk to catch dangling refs.
|
// Fill with junk to catch dangling refs.
|
||||||
memset(pa, 1, PGSIZE);
|
memset(pa, 1, PGSIZE);
|
||||||
|
|
||||||
r = (struct run*)pa;
|
r = (struct run *)pa;
|
||||||
|
|
||||||
acquire(&kmem.lock);
|
acquire(&kmem.lock);
|
||||||
r->next = kmem.freelist;
|
r->next = kmem.freelist;
|
||||||
|
@ -77,6 +77,6 @@ kalloc(void)
|
||||||
release(&kmem.lock);
|
release(&kmem.lock);
|
||||||
|
|
||||||
if(r)
|
if(r)
|
||||||
memset((char*)r, 5, PGSIZE); // fill with junk
|
memset((char *)r, 5, PGSIZE); // fill with junk
|
||||||
return (void*)r;
|
return (void *)r;
|
||||||
}
|
}
|
||||||
|
|
75
kernel/log.c
75
kernel/log.c
|
@ -38,12 +38,12 @@ struct logheader {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct log {
|
struct log {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
int start;
|
int start;
|
||||||
int size;
|
int size;
|
||||||
int outstanding; // how many FS sys calls are executing.
|
int outstanding; // how many FS sys calls are executing.
|
||||||
int committing; // in commit(), please wait.
|
int committing; // in commit(), please wait.
|
||||||
int dev;
|
int dev;
|
||||||
struct logheader lh;
|
struct logheader lh;
|
||||||
};
|
};
|
||||||
struct log log;
|
struct log log;
|
||||||
|
@ -54,7 +54,7 @@ static void commit();
|
||||||
void
|
void
|
||||||
initlog(int dev, struct superblock *sb)
|
initlog(int dev, struct superblock *sb)
|
||||||
{
|
{
|
||||||
if (sizeof(struct logheader) >= BSIZE)
|
if(sizeof(struct logheader) >= BSIZE)
|
||||||
panic("initlog: too big logheader");
|
panic("initlog: too big logheader");
|
||||||
|
|
||||||
initlock(&log.lock, "log");
|
initlock(&log.lock, "log");
|
||||||
|
@ -70,11 +70,11 @@ install_trans(int recovering)
|
||||||
{
|
{
|
||||||
int tail;
|
int tail;
|
||||||
|
|
||||||
for (tail = 0; tail < log.lh.n; tail++) {
|
for(tail = 0; tail < log.lh.n; tail++) {
|
||||||
struct buf *lbuf = bread(log.dev, log.start+tail+1); // read log block
|
struct buf *lbuf = bread(log.dev, log.start + tail + 1); // read log block
|
||||||
struct buf *dbuf = bread(log.dev, log.lh.block[tail]); // read dst
|
struct buf *dbuf = bread(log.dev, log.lh.block[tail]); // read dst
|
||||||
memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst
|
memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst
|
||||||
bwrite(dbuf); // write dst to disk
|
bwrite(dbuf); // write dst to disk
|
||||||
if(recovering == 0)
|
if(recovering == 0)
|
||||||
bunpin(dbuf);
|
bunpin(dbuf);
|
||||||
brelse(lbuf);
|
brelse(lbuf);
|
||||||
|
@ -86,11 +86,11 @@ install_trans(int recovering)
|
||||||
static void
|
static void
|
||||||
read_head(void)
|
read_head(void)
|
||||||
{
|
{
|
||||||
struct buf *buf = bread(log.dev, log.start);
|
struct buf *buf = bread(log.dev, log.start);
|
||||||
struct logheader *lh = (struct logheader *) (buf->data);
|
struct logheader *lh = (struct logheader *)(buf->data);
|
||||||
int i;
|
int i;
|
||||||
log.lh.n = lh->n;
|
log.lh.n = lh->n;
|
||||||
for (i = 0; i < log.lh.n; i++) {
|
for(i = 0; i < log.lh.n; i++) {
|
||||||
log.lh.block[i] = lh->block[i];
|
log.lh.block[i] = lh->block[i];
|
||||||
}
|
}
|
||||||
brelse(buf);
|
brelse(buf);
|
||||||
|
@ -102,11 +102,11 @@ read_head(void)
|
||||||
static void
|
static void
|
||||||
write_head(void)
|
write_head(void)
|
||||||
{
|
{
|
||||||
struct buf *buf = bread(log.dev, log.start);
|
struct buf *buf = bread(log.dev, log.start);
|
||||||
struct logheader *hb = (struct logheader *) (buf->data);
|
struct logheader *hb = (struct logheader *)(buf->data);
|
||||||
int i;
|
int i;
|
||||||
hb->n = log.lh.n;
|
hb->n = log.lh.n;
|
||||||
for (i = 0; i < log.lh.n; i++) {
|
for(i = 0; i < log.lh.n; i++) {
|
||||||
hb->block[i] = log.lh.block[i];
|
hb->block[i] = log.lh.block[i];
|
||||||
}
|
}
|
||||||
bwrite(buf);
|
bwrite(buf);
|
||||||
|
@ -127,10 +127,10 @@ void
|
||||||
begin_op(void)
|
begin_op(void)
|
||||||
{
|
{
|
||||||
acquire(&log.lock);
|
acquire(&log.lock);
|
||||||
while(1){
|
while(1) {
|
||||||
if(log.committing){
|
if(log.committing) {
|
||||||
sleep(&log, &log.lock);
|
sleep(&log, &log.lock);
|
||||||
} else if(log.lh.n + (log.outstanding+1)*MAXOPBLOCKS > LOGSIZE){
|
} else if(log.lh.n + (log.outstanding + 1) * MAXOPBLOCKS > LOGSIZE) {
|
||||||
// this op might exhaust log space; wait for commit.
|
// this op might exhaust log space; wait for commit.
|
||||||
sleep(&log, &log.lock);
|
sleep(&log, &log.lock);
|
||||||
} else {
|
} else {
|
||||||
|
@ -152,7 +152,7 @@ end_op(void)
|
||||||
log.outstanding -= 1;
|
log.outstanding -= 1;
|
||||||
if(log.committing)
|
if(log.committing)
|
||||||
panic("log.committing");
|
panic("log.committing");
|
||||||
if(log.outstanding == 0){
|
if(log.outstanding == 0) {
|
||||||
do_commit = 1;
|
do_commit = 1;
|
||||||
log.committing = 1;
|
log.committing = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -163,7 +163,7 @@ end_op(void)
|
||||||
}
|
}
|
||||||
release(&log.lock);
|
release(&log.lock);
|
||||||
|
|
||||||
if(do_commit){
|
if(do_commit) {
|
||||||
// call commit w/o holding locks, since not allowed
|
// call commit w/o holding locks, since not allowed
|
||||||
// to sleep with locks.
|
// to sleep with locks.
|
||||||
commit();
|
commit();
|
||||||
|
@ -180,11 +180,11 @@ write_log(void)
|
||||||
{
|
{
|
||||||
int tail;
|
int tail;
|
||||||
|
|
||||||
for (tail = 0; tail < log.lh.n; tail++) {
|
for(tail = 0; tail < log.lh.n; tail++) {
|
||||||
struct buf *to = bread(log.dev, log.start+tail+1); // log block
|
struct buf *to = bread(log.dev, log.start + tail + 1); // log block
|
||||||
struct buf *from = bread(log.dev, log.lh.block[tail]); // cache block
|
struct buf *from = bread(log.dev, log.lh.block[tail]); // cache block
|
||||||
memmove(to->data, from->data, BSIZE);
|
memmove(to->data, from->data, BSIZE);
|
||||||
bwrite(to); // write the log
|
bwrite(to); // write the log
|
||||||
brelse(from);
|
brelse(from);
|
||||||
brelse(to);
|
brelse(to);
|
||||||
}
|
}
|
||||||
|
@ -193,12 +193,12 @@ write_log(void)
|
||||||
static void
|
static void
|
||||||
commit()
|
commit()
|
||||||
{
|
{
|
||||||
if (log.lh.n > 0) {
|
if(log.lh.n > 0) {
|
||||||
write_log(); // Write modified blocks from cache to log
|
write_log(); // Write modified blocks from cache to log
|
||||||
write_head(); // Write header to disk -- the real commit
|
write_head(); // Write header to disk -- the real commit
|
||||||
install_trans(0); // Now install writes to home locations
|
install_trans(0); // Now install writes to home locations
|
||||||
log.lh.n = 0;
|
log.lh.n = 0;
|
||||||
write_head(); // Erase the transaction from the log
|
write_head(); // Erase the transaction from the log
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,20 +217,19 @@ log_write(struct buf *b)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
acquire(&log.lock);
|
acquire(&log.lock);
|
||||||
if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1)
|
if(log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1)
|
||||||
panic("too big a transaction");
|
panic("too big a transaction");
|
||||||
if (log.outstanding < 1)
|
if(log.outstanding < 1)
|
||||||
panic("log_write outside of trans");
|
panic("log_write outside of trans");
|
||||||
|
|
||||||
for (i = 0; i < log.lh.n; i++) {
|
for(i = 0; i < log.lh.n; i++) {
|
||||||
if (log.lh.block[i] == b->blockno) // log absorption
|
if(log.lh.block[i] == b->blockno) // log absorption
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
log.lh.block[i] = b->blockno;
|
log.lh.block[i] = b->blockno;
|
||||||
if (i == log.lh.n) { // Add new block to log?
|
if(i == log.lh.n) { // Add new block to log?
|
||||||
bpin(b);
|
bpin(b);
|
||||||
log.lh.n++;
|
log.lh.n++;
|
||||||
}
|
}
|
||||||
release(&log.lock);
|
release(&log.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,25 +10,25 @@ volatile static int started = 0;
|
||||||
void
|
void
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
if(cpuid() == 0){
|
if(cpuid() == 0) {
|
||||||
consoleinit();
|
consoleinit();
|
||||||
printfinit();
|
printfinit();
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("xv6 kernel is booting\n");
|
printf("xv6 kernel is booting\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
kinit(); // physical page allocator
|
kinit(); // physical page allocator
|
||||||
kvminit(); // create kernel page table
|
kvminit(); // create kernel page table
|
||||||
kvminithart(); // turn on paging
|
kvminithart(); // turn on paging
|
||||||
procinit(); // process table
|
procinit(); // process table
|
||||||
trapinit(); // trap vectors
|
trapinit(); // trap vectors
|
||||||
trapinithart(); // install kernel trap vector
|
trapinithart(); // install kernel trap vector
|
||||||
plicinit(); // set up interrupt controller
|
plicinit(); // set up interrupt controller
|
||||||
plicinithart(); // ask PLIC for device interrupts
|
plicinithart(); // ask PLIC for device interrupts
|
||||||
binit(); // buffer cache
|
binit(); // buffer cache
|
||||||
iinit(); // inode table
|
iinit(); // inode table
|
||||||
fileinit(); // file table
|
fileinit(); // file table
|
||||||
virtio_disk_init(); // emulated hard disk
|
virtio_disk_init(); // emulated hard disk
|
||||||
userinit(); // first user process
|
userinit(); // first user process
|
||||||
__sync_synchronize();
|
__sync_synchronize();
|
||||||
started = 1;
|
started = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -36,10 +36,10 @@ main()
|
||||||
;
|
;
|
||||||
__sync_synchronize();
|
__sync_synchronize();
|
||||||
printf("hart %d starting\n", cpuid());
|
printf("hart %d starting\n", cpuid());
|
||||||
kvminithart(); // turn on paging
|
kvminithart(); // turn on paging
|
||||||
trapinithart(); // install kernel trap vector
|
trapinithart(); // install kernel trap vector
|
||||||
plicinithart(); // ask PLIC for device interrupts
|
plicinithart(); // ask PLIC for device interrupts
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler();
|
scheduler();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
// 00001000 -- boot ROM, provided by qemu
|
// 00001000 -- boot ROM, provided by qemu
|
||||||
// 02000000 -- CLINT
|
// 02000000 -- CLINT
|
||||||
// 0C000000 -- PLIC
|
// 0C000000 -- PLIC
|
||||||
// 10000000 -- uart0
|
// 10000000 -- uart0
|
||||||
// 10001000 -- virtio disk
|
// 10001000 -- virtio disk
|
||||||
// 80000000 -- boot ROM jumps here in machine mode
|
// 80000000 -- boot ROM jumps here in machine mode
|
||||||
// -kernel loads the kernel here
|
// -kernel loads the kernel here
|
||||||
// unused RAM after 80000000.
|
// unused RAM after 80000000.
|
||||||
|
@ -18,34 +18,34 @@
|
||||||
// PHYSTOP -- end RAM used by the kernel
|
// PHYSTOP -- end RAM used by the kernel
|
||||||
|
|
||||||
// qemu puts UART registers here in physical memory.
|
// qemu puts UART registers here in physical memory.
|
||||||
#define UART0 0x10000000L
|
#define UART0 0x10000000L
|
||||||
#define UART0_IRQ 10
|
#define UART0_IRQ 10
|
||||||
|
|
||||||
// virtio mmio interface
|
// virtio mmio interface
|
||||||
#define VIRTIO0 0x10001000
|
#define VIRTIO0 0x10001000
|
||||||
#define VIRTIO0_IRQ 1
|
#define VIRTIO0_IRQ 1
|
||||||
|
|
||||||
// core local interruptor (CLINT), which contains the timer.
|
// core local interruptor (CLINT), which contains the timer.
|
||||||
#define CLINT 0x2000000L
|
#define CLINT 0x2000000L
|
||||||
#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8*(hartid))
|
#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8 * (hartid))
|
||||||
#define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot.
|
#define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot.
|
||||||
|
|
||||||
// qemu puts platform-level interrupt controller (PLIC) here.
|
// qemu puts platform-level interrupt controller (PLIC) here.
|
||||||
#define PLIC 0x0c000000L
|
#define PLIC 0x0c000000L
|
||||||
#define PLIC_PRIORITY (PLIC + 0x0)
|
#define PLIC_PRIORITY (PLIC + 0x0)
|
||||||
#define PLIC_PENDING (PLIC + 0x1000)
|
#define PLIC_PENDING (PLIC + 0x1000)
|
||||||
#define PLIC_MENABLE(hart) (PLIC + 0x2000 + (hart)*0x100)
|
#define PLIC_MENABLE(hart) (PLIC + 0x2000 + (hart) * 0x100)
|
||||||
#define PLIC_SENABLE(hart) (PLIC + 0x2080 + (hart)*0x100)
|
#define PLIC_SENABLE(hart) (PLIC + 0x2080 + (hart) * 0x100)
|
||||||
#define PLIC_MPRIORITY(hart) (PLIC + 0x200000 + (hart)*0x2000)
|
#define PLIC_MPRIORITY(hart) (PLIC + 0x200000 + (hart) * 0x2000)
|
||||||
#define PLIC_SPRIORITY(hart) (PLIC + 0x201000 + (hart)*0x2000)
|
#define PLIC_SPRIORITY(hart) (PLIC + 0x201000 + (hart) * 0x2000)
|
||||||
#define PLIC_MCLAIM(hart) (PLIC + 0x200004 + (hart)*0x2000)
|
#define PLIC_MCLAIM(hart) (PLIC + 0x200004 + (hart) * 0x2000)
|
||||||
#define PLIC_SCLAIM(hart) (PLIC + 0x201004 + (hart)*0x2000)
|
#define PLIC_SCLAIM(hart) (PLIC + 0x201004 + (hart) * 0x2000)
|
||||||
|
|
||||||
// the kernel expects there to be RAM
|
// the kernel expects there to be RAM
|
||||||
// for use by the kernel and user pages
|
// for use by the kernel and user pages
|
||||||
// from physical address 0x80000000 to PHYSTOP.
|
// from physical address 0x80000000 to PHYSTOP.
|
||||||
#define KERNBASE 0x80000000L
|
#define KERNBASE 0x80000000L
|
||||||
#define PHYSTOP (KERNBASE + 128*1024*1024)
|
#define PHYSTOP (KERNBASE + 128 * 1024 * 1024)
|
||||||
|
|
||||||
// map the trampoline page to the highest address,
|
// map the trampoline page to the highest address,
|
||||||
// in both user and kernel space.
|
// in both user and kernel space.
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
|
|
||||||
// map kernel stacks beneath the trampoline,
|
// map kernel stacks beneath the trampoline,
|
||||||
// each surrounded by invalid guard pages.
|
// each surrounded by invalid guard pages.
|
||||||
#define KSTACK(p) (TRAMPOLINE - ((p)+1)* 2*PGSIZE)
|
#define KSTACK(p) (TRAMPOLINE - ((p) + 1) * 2 * PGSIZE)
|
||||||
|
|
||||||
// User memory layout.
|
// User memory layout.
|
||||||
// Address zero first:
|
// Address zero first:
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#define NPROC 64 // maximum number of processes
|
#define NPROC 64 // maximum number of processes
|
||||||
#define NCPU 8 // maximum number of CPUs
|
#define NCPU 8 // maximum number of CPUs
|
||||||
#define NOFILE 16 // open files per process
|
#define NOFILE 16 // open files per process
|
||||||
#define NFILE 100 // open files per system
|
#define NFILE 100 // open files per system
|
||||||
#define NINODE 50 // maximum number of active i-nodes
|
#define NINODE 50 // maximum number of active i-nodes
|
||||||
#define NDEV 10 // maximum major device number
|
#define NDEV 10 // maximum major device number
|
||||||
#define ROOTDEV 1 // device number of file system root disk
|
#define ROOTDEV 1 // device number of file system root disk
|
||||||
#define MAXARG 32 // max exec arguments
|
#define MAXARG 32 // max exec arguments
|
||||||
#define MAXOPBLOCKS 10 // max # of blocks any FS op writes
|
#define MAXOPBLOCKS 10 // max # of blocks any FS op writes
|
||||||
#define LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log
|
#define LOGSIZE (MAXOPBLOCKS * 3) // max data blocks in on-disk log
|
||||||
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
|
#define NBUF (MAXOPBLOCKS * 3) // size of disk block cache
|
||||||
#define FSSIZE 2000 // size of file system in blocks
|
#define FSSIZE 2000 // size of file system in blocks
|
||||||
#define MAXPATH 128 // maximum file path name
|
#define MAXPATH 128 // maximum file path name
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
|
|
||||||
struct pipe {
|
struct pipe {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
char data[PIPESIZE];
|
char data[PIPESIZE];
|
||||||
u32 nread; // number of bytes read
|
u32 nread; // number of bytes read
|
||||||
u32 nwrite; // number of bytes written
|
u32 nwrite; // number of bytes written
|
||||||
int readopen; // read fd is still open
|
int readopen; // read fd is still open
|
||||||
int writeopen; // write fd is still open
|
int writeopen; // write fd is still open
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -28,7 +28,7 @@ pipealloc(struct file **f0, struct file **f1)
|
||||||
*f0 = *f1 = 0;
|
*f0 = *f1 = 0;
|
||||||
if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
|
if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
if((pi = (struct pipe*)kalloc()) == 0)
|
if((pi = (struct pipe *)kalloc()) == 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
pi->readopen = 1;
|
pi->readopen = 1;
|
||||||
pi->writeopen = 1;
|
pi->writeopen = 1;
|
||||||
|
@ -45,9 +45,9 @@ pipealloc(struct file **f0, struct file **f1)
|
||||||
(*f1)->pipe = pi;
|
(*f1)->pipe = pi;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
if(pi)
|
if(pi)
|
||||||
kfree((char*)pi);
|
kfree((char *)pi);
|
||||||
if(*f0)
|
if(*f0)
|
||||||
fileclose(*f0);
|
fileclose(*f0);
|
||||||
if(*f1)
|
if(*f1)
|
||||||
|
@ -59,16 +59,16 @@ void
|
||||||
pipeclose(struct pipe *pi, int writable)
|
pipeclose(struct pipe *pi, int writable)
|
||||||
{
|
{
|
||||||
acquire(&pi->lock);
|
acquire(&pi->lock);
|
||||||
if(writable){
|
if(writable) {
|
||||||
pi->writeopen = 0;
|
pi->writeopen = 0;
|
||||||
wakeup(&pi->nread);
|
wakeup(&pi->nread);
|
||||||
} else {
|
} else {
|
||||||
pi->readopen = 0;
|
pi->readopen = 0;
|
||||||
wakeup(&pi->nwrite);
|
wakeup(&pi->nwrite);
|
||||||
}
|
}
|
||||||
if(pi->readopen == 0 && pi->writeopen == 0){
|
if(pi->readopen == 0 && pi->writeopen == 0) {
|
||||||
release(&pi->lock);
|
release(&pi->lock);
|
||||||
kfree((char*)pi);
|
kfree((char *)pi);
|
||||||
} else
|
} else
|
||||||
release(&pi->lock);
|
release(&pi->lock);
|
||||||
}
|
}
|
||||||
|
@ -76,16 +76,16 @@ pipeclose(struct pipe *pi, int writable)
|
||||||
int
|
int
|
||||||
pipewrite(struct pipe *pi, u64 addr, int n)
|
pipewrite(struct pipe *pi, u64 addr, int n)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
struct proc *pr = myproc();
|
struct proc *pr = myproc();
|
||||||
|
|
||||||
acquire(&pi->lock);
|
acquire(&pi->lock);
|
||||||
while(i < n){
|
while(i < n) {
|
||||||
if(pi->readopen == 0 || killed(pr)){
|
if(pi->readopen == 0 || killed(pr)) {
|
||||||
release(&pi->lock);
|
release(&pi->lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(pi->nwrite == pi->nread + PIPESIZE){ //DOC: pipewrite-full
|
if(pi->nwrite == pi->nread + PIPESIZE) { // DOC: pipewrite-full
|
||||||
wakeup(&pi->nread);
|
wakeup(&pi->nread);
|
||||||
sleep(&pi->nwrite, &pi->lock);
|
sleep(&pi->nwrite, &pi->lock);
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,26 +105,26 @@ pipewrite(struct pipe *pi, u64 addr, int n)
|
||||||
int
|
int
|
||||||
piperead(struct pipe *pi, u64 addr, int n)
|
piperead(struct pipe *pi, u64 addr, int n)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct proc *pr = myproc();
|
struct proc *pr = myproc();
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
acquire(&pi->lock);
|
acquire(&pi->lock);
|
||||||
while(pi->nread == pi->nwrite && pi->writeopen){ //DOC: pipe-empty
|
while(pi->nread == pi->nwrite && pi->writeopen) { // DOC: pipe-empty
|
||||||
if(killed(pr)){
|
if(killed(pr)) {
|
||||||
release(&pi->lock);
|
release(&pi->lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sleep(&pi->nread, &pi->lock); //DOC: piperead-sleep
|
sleep(&pi->nread, &pi->lock); // DOC: piperead-sleep
|
||||||
}
|
}
|
||||||
for(i = 0; i < n; i++){ //DOC: piperead-copy
|
for(i = 0; i < n; i++) { // DOC: piperead-copy
|
||||||
if(pi->nread == pi->nwrite)
|
if(pi->nread == pi->nwrite)
|
||||||
break;
|
break;
|
||||||
ch = pi->data[pi->nread++ % PIPESIZE];
|
ch = pi->data[pi->nread++ % PIPESIZE];
|
||||||
if(copyout(pr->pagetable, addr + i, &ch, 1) == -1)
|
if(copyout(pr->pagetable, addr + i, &ch, 1) == -1)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
wakeup(&pi->nwrite); //DOC: piperead-wakeup
|
wakeup(&pi->nwrite); // DOC: piperead-wakeup
|
||||||
release(&pi->lock);
|
release(&pi->lock);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,21 +12,21 @@ void
|
||||||
plicinit(void)
|
plicinit(void)
|
||||||
{
|
{
|
||||||
// set desired IRQ priorities non-zero (otherwise disabled).
|
// set desired IRQ priorities non-zero (otherwise disabled).
|
||||||
*(u32*)(PLIC + UART0_IRQ*4) = 1;
|
*(u32 *)(PLIC + UART0_IRQ * 4) = 1;
|
||||||
*(u32*)(PLIC + VIRTIO0_IRQ*4) = 1;
|
*(u32 *)(PLIC + VIRTIO0_IRQ * 4) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
plicinithart(void)
|
plicinithart(void)
|
||||||
{
|
{
|
||||||
int hart = cpuid();
|
int hart = cpuid();
|
||||||
|
|
||||||
// set enable bits for this hart's S-mode
|
// set enable bits for this hart's S-mode
|
||||||
// for the uart and virtio disk.
|
// for the uart and virtio disk.
|
||||||
*(u32*)PLIC_SENABLE(hart) = (1 << UART0_IRQ) | (1 << VIRTIO0_IRQ);
|
*(u32 *)PLIC_SENABLE(hart) = (1 << UART0_IRQ) | (1 << VIRTIO0_IRQ);
|
||||||
|
|
||||||
// set this hart's S-mode priority threshold to 0.
|
// set this hart's S-mode priority threshold to 0.
|
||||||
*(u32*)PLIC_SPRIORITY(hart) = 0;
|
*(u32 *)PLIC_SPRIORITY(hart) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ask the PLIC what interrupt we should serve.
|
// ask the PLIC what interrupt we should serve.
|
||||||
|
@ -34,7 +34,7 @@ int
|
||||||
plic_claim(void)
|
plic_claim(void)
|
||||||
{
|
{
|
||||||
int hart = cpuid();
|
int hart = cpuid();
|
||||||
int irq = *(u32*)PLIC_SCLAIM(hart);
|
int irq = *(u32 *)PLIC_SCLAIM(hart);
|
||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,5 +43,5 @@ void
|
||||||
plic_complete(int irq)
|
plic_complete(int irq)
|
||||||
{
|
{
|
||||||
int hart = cpuid();
|
int hart = cpuid();
|
||||||
*(u32*)PLIC_SCLAIM(hart) = irq;
|
*(u32 *)PLIC_SCLAIM(hart) = irq;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ volatile int panicked = 0;
|
||||||
// lock to avoid interleaving concurrent printf's.
|
// lock to avoid interleaving concurrent printf's.
|
||||||
static struct {
|
static struct {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
int locking;
|
int locking;
|
||||||
} pr;
|
} pr;
|
||||||
|
|
||||||
static char digits[] = "0123456789abcdef";
|
static char digits[] = "0123456789abcdef";
|
||||||
|
@ -29,8 +29,8 @@ static void
|
||||||
printint(int xx, int base, int sign)
|
printint(int xx, int base, int sign)
|
||||||
{
|
{
|
||||||
char buf[16];
|
char buf[16];
|
||||||
int i;
|
int i;
|
||||||
u32 x;
|
u32 x;
|
||||||
|
|
||||||
if(sign && (sign = xx < 0))
|
if(sign && (sign = xx < 0))
|
||||||
x = -xx;
|
x = -xx;
|
||||||
|
@ -55,7 +55,7 @@ printptr(u64 x)
|
||||||
int i;
|
int i;
|
||||||
consputc('0');
|
consputc('0');
|
||||||
consputc('x');
|
consputc('x');
|
||||||
for (i = 0; i < (sizeof(u64) * 2); i++, x <<= 4)
|
for(i = 0; i < (sizeof(u64) * 2); i++, x <<= 4)
|
||||||
consputc(digits[x >> (sizeof(u64) * 8 - 4)]);
|
consputc(digits[x >> (sizeof(u64) * 8 - 4)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,26 +64,26 @@ void
|
||||||
printf(char *fmt, ...)
|
printf(char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int i, c, locking;
|
int i, c, locking;
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
locking = pr.locking;
|
locking = pr.locking;
|
||||||
if(locking)
|
if(locking)
|
||||||
acquire(&pr.lock);
|
acquire(&pr.lock);
|
||||||
|
|
||||||
if (fmt == 0)
|
if(fmt == 0)
|
||||||
panic("null fmt");
|
panic("null fmt");
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
|
for(i = 0; (c = fmt[i] & 0xff) != 0; i++) {
|
||||||
if(c != '%'){
|
if(c != '%') {
|
||||||
consputc(c);
|
consputc(c);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
c = fmt[++i] & 0xff;
|
c = fmt[++i] & 0xff;
|
||||||
if(c == 0)
|
if(c == 0)
|
||||||
break;
|
break;
|
||||||
switch(c){
|
switch(c) {
|
||||||
case 'd':
|
case 'd':
|
||||||
printint(va_arg(ap, int), 10, 1);
|
printint(va_arg(ap, int), 10, 1);
|
||||||
break;
|
break;
|
||||||
|
@ -94,7 +94,7 @@ printf(char *fmt, ...)
|
||||||
printptr(va_arg(ap, u64));
|
printptr(va_arg(ap, u64));
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if((s = va_arg(ap, char*)) == 0)
|
if((s = va_arg(ap, char *)) == 0)
|
||||||
s = "(null)";
|
s = "(null)";
|
||||||
for(; *s; s++)
|
for(; *s; s++)
|
||||||
consputc(*s);
|
consputc(*s);
|
||||||
|
|
139
kernel/proc.c
139
kernel/proc.c
|
@ -12,7 +12,7 @@ struct proc proc[NPROC];
|
||||||
|
|
||||||
struct proc *initproc;
|
struct proc *initproc;
|
||||||
|
|
||||||
int nextpid = 1;
|
int nextpid = 1;
|
||||||
struct spinlock pid_lock;
|
struct spinlock pid_lock;
|
||||||
|
|
||||||
extern void forkret(void);
|
extern void forkret(void);
|
||||||
|
@ -33,12 +33,12 @@ void
|
||||||
proc_mapstacks(pagetable_t kpgtbl)
|
proc_mapstacks(pagetable_t kpgtbl)
|
||||||
{
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
for(p = proc; p < &proc[NPROC]; p++) {
|
for(p = proc; p < &proc[NPROC]; p++) {
|
||||||
char *pa = kalloc();
|
char *pa = kalloc();
|
||||||
if(pa == 0)
|
if(pa == 0)
|
||||||
panic("kalloc");
|
panic("kalloc");
|
||||||
u64 va = KSTACK((int) (p - proc));
|
u64 va = KSTACK((int)(p - proc));
|
||||||
kvmmap(kpgtbl, va, (u64)pa, PGSIZE, PTE_R | PTE_W);
|
kvmmap(kpgtbl, va, (u64)pa, PGSIZE, PTE_R | PTE_W);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,13 +48,13 @@ void
|
||||||
procinit(void)
|
procinit(void)
|
||||||
{
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
initlock(&pid_lock, "nextpid");
|
initlock(&pid_lock, "nextpid");
|
||||||
initlock(&wait_lock, "wait_lock");
|
initlock(&wait_lock, "wait_lock");
|
||||||
for(p = proc; p < &proc[NPROC]; p++) {
|
for(p = proc; p < &proc[NPROC]; p++) {
|
||||||
initlock(&p->lock, "proc");
|
initlock(&p->lock, "proc");
|
||||||
p->state = UNUSED;
|
p->state = UNUSED;
|
||||||
p->kstack = KSTACK((int) (p - proc));
|
p->kstack = KSTACK((int)(p - proc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,20 +70,20 @@ cpuid()
|
||||||
|
|
||||||
// Return this CPU's cpu struct.
|
// Return this CPU's cpu struct.
|
||||||
// Interrupts must be disabled.
|
// Interrupts must be disabled.
|
||||||
struct cpu*
|
struct cpu *
|
||||||
mycpu(void)
|
mycpu(void)
|
||||||
{
|
{
|
||||||
int id = cpuid();
|
int id = cpuid();
|
||||||
struct cpu *c = &cpus[id];
|
struct cpu *c = &cpus[id];
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the current struct proc *, or zero if none.
|
// Return the current struct proc *, or zero if none.
|
||||||
struct proc*
|
struct proc *
|
||||||
myproc(void)
|
myproc(void)
|
||||||
{
|
{
|
||||||
push_off();
|
push_off();
|
||||||
struct cpu *c = mycpu();
|
struct cpu *c = mycpu();
|
||||||
struct proc *p = c->proc;
|
struct proc *p = c->proc;
|
||||||
pop_off();
|
pop_off();
|
||||||
return p;
|
return p;
|
||||||
|
@ -93,7 +93,7 @@ int
|
||||||
allocpid()
|
allocpid()
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
acquire(&pid_lock);
|
acquire(&pid_lock);
|
||||||
pid = nextpid;
|
pid = nextpid;
|
||||||
nextpid = nextpid + 1;
|
nextpid = nextpid + 1;
|
||||||
|
@ -106,7 +106,7 @@ allocpid()
|
||||||
// If found, initialize state required to run in the kernel,
|
// If found, initialize state required to run in the kernel,
|
||||||
// and return with p->lock held.
|
// and return with p->lock held.
|
||||||
// If there are no free procs, or a memory allocation fails, return 0.
|
// If there are no free procs, or a memory allocation fails, return 0.
|
||||||
static struct proc*
|
static struct proc *
|
||||||
allocproc(void)
|
allocproc(void)
|
||||||
{
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
@ -126,7 +126,7 @@ found:
|
||||||
p->state = USED;
|
p->state = USED;
|
||||||
|
|
||||||
// Allocate a trapframe page.
|
// Allocate a trapframe page.
|
||||||
if((p->trapframe = (struct trapframe *)kalloc()) == 0){
|
if((p->trapframe = (struct trapframe *)kalloc()) == 0) {
|
||||||
freeproc(p);
|
freeproc(p);
|
||||||
release(&p->lock);
|
release(&p->lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -134,7 +134,7 @@ found:
|
||||||
|
|
||||||
// An empty user page table.
|
// An empty user page table.
|
||||||
p->pagetable = proc_pagetable(p);
|
p->pagetable = proc_pagetable(p);
|
||||||
if(p->pagetable == 0){
|
if(p->pagetable == 0) {
|
||||||
freeproc(p);
|
freeproc(p);
|
||||||
release(&p->lock);
|
release(&p->lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -156,7 +156,7 @@ static void
|
||||||
freeproc(struct proc *p)
|
freeproc(struct proc *p)
|
||||||
{
|
{
|
||||||
if(p->trapframe)
|
if(p->trapframe)
|
||||||
kfree((void*)p->trapframe);
|
kfree((void *)p->trapframe);
|
||||||
p->trapframe = 0;
|
p->trapframe = 0;
|
||||||
if(p->pagetable)
|
if(p->pagetable)
|
||||||
proc_freepagetable(p->pagetable, p->sz);
|
proc_freepagetable(p->pagetable, p->sz);
|
||||||
|
@ -187,16 +187,14 @@ proc_pagetable(struct proc *p)
|
||||||
// at the highest user virtual address.
|
// at the highest user virtual address.
|
||||||
// only the supervisor uses it, on the way
|
// only the supervisor uses it, on the way
|
||||||
// to/from user space, so not PTE_U.
|
// to/from user space, so not PTE_U.
|
||||||
if(mappages(pagetable, TRAMPOLINE, PGSIZE,
|
if(mappages(pagetable, TRAMPOLINE, PGSIZE, (u64)trampoline, PTE_R | PTE_X) < 0) {
|
||||||
(u64)trampoline, PTE_R | PTE_X) < 0){
|
|
||||||
uvmfree(pagetable, 0);
|
uvmfree(pagetable, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// map the trapframe page just below the trampoline page, for
|
// map the trapframe page just below the trampoline page, for
|
||||||
// trampoline.S.
|
// trampoline.S.
|
||||||
if(mappages(pagetable, TRAPFRAME, PGSIZE,
|
if(mappages(pagetable, TRAPFRAME, PGSIZE, (u64)(p->trapframe), PTE_R | PTE_W) < 0) {
|
||||||
(u64)(p->trapframe), PTE_R | PTE_W) < 0){
|
|
||||||
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
|
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
|
||||||
uvmfree(pagetable, 0);
|
uvmfree(pagetable, 0);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -218,15 +216,10 @@ proc_freepagetable(pagetable_t pagetable, u64 sz)
|
||||||
// a user program that calls exec("/init")
|
// a user program that calls exec("/init")
|
||||||
// assembled from ../user/initcode.S
|
// assembled from ../user/initcode.S
|
||||||
// od -t xC ../user/initcode
|
// od -t xC ../user/initcode
|
||||||
u8 initcode[] = {
|
u8 initcode[]
|
||||||
0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x02,
|
= { 0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x02, 0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x35, 0x02, 0x93, 0x08,
|
||||||
0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x35, 0x02,
|
0x70, 0x00, 0x73, 0x00, 0x00, 0x00, 0x93, 0x08, 0x20, 0x00, 0x73, 0x00, 0x00, 0x00, 0xef, 0xf0, 0x9f, 0xff,
|
||||||
0x93, 0x08, 0x70, 0x00, 0x73, 0x00, 0x00, 0x00,
|
0x2f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
0x93, 0x08, 0x20, 0x00, 0x73, 0x00, 0x00, 0x00,
|
|
||||||
0xef, 0xf0, 0x9f, 0xff, 0x2f, 0x69, 0x6e, 0x69,
|
|
||||||
0x74, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set up first user process.
|
// Set up first user process.
|
||||||
void
|
void
|
||||||
|
@ -236,15 +229,15 @@ userinit(void)
|
||||||
|
|
||||||
p = allocproc();
|
p = allocproc();
|
||||||
initproc = p;
|
initproc = p;
|
||||||
|
|
||||||
// allocate one user page and copy initcode's instructions
|
// allocate one user page and copy initcode's instructions
|
||||||
// and data into it.
|
// and data into it.
|
||||||
uvmfirst(p->pagetable, initcode, sizeof(initcode));
|
uvmfirst(p->pagetable, initcode, sizeof(initcode));
|
||||||
p->sz = PGSIZE;
|
p->sz = PGSIZE;
|
||||||
|
|
||||||
// prepare for the very first "return" from kernel to user.
|
// prepare for the very first "return" from kernel to user.
|
||||||
p->trapframe->epc = 0; // user program counter
|
p->trapframe->epc = 0; // user program counter
|
||||||
p->trapframe->sp = PGSIZE; // user stack pointer
|
p->trapframe->sp = PGSIZE; // user stack pointer
|
||||||
|
|
||||||
safestrcpy(p->name, "initcode", sizeof(p->name));
|
safestrcpy(p->name, "initcode", sizeof(p->name));
|
||||||
p->cwd = namei("/");
|
p->cwd = namei("/");
|
||||||
|
@ -259,15 +252,15 @@ userinit(void)
|
||||||
int
|
int
|
||||||
growproc(int n)
|
growproc(int n)
|
||||||
{
|
{
|
||||||
u64 sz;
|
u64 sz;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
sz = p->sz;
|
sz = p->sz;
|
||||||
if(n > 0){
|
if(n > 0) {
|
||||||
if((sz = uvmalloc(p->pagetable, sz, sz + n, PTE_W)) == 0) {
|
if((sz = uvmalloc(p->pagetable, sz, sz + n, PTE_W)) == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else if(n < 0){
|
} else if(n < 0) {
|
||||||
sz = uvmdealloc(p->pagetable, sz, sz + n);
|
sz = uvmdealloc(p->pagetable, sz, sz + n);
|
||||||
}
|
}
|
||||||
p->sz = sz;
|
p->sz = sz;
|
||||||
|
@ -279,17 +272,17 @@ growproc(int n)
|
||||||
int
|
int
|
||||||
fork(void)
|
fork(void)
|
||||||
{
|
{
|
||||||
int i, pid;
|
int i, pid;
|
||||||
struct proc *np;
|
struct proc *np;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
// Allocate process.
|
// Allocate process.
|
||||||
if((np = allocproc()) == 0){
|
if((np = allocproc()) == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy user memory from parent to child.
|
// Copy user memory from parent to child.
|
||||||
if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
|
if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0) {
|
||||||
freeproc(np);
|
freeproc(np);
|
||||||
release(&np->lock);
|
release(&np->lock);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -332,8 +325,8 @@ reparent(struct proc *p)
|
||||||
{
|
{
|
||||||
struct proc *pp;
|
struct proc *pp;
|
||||||
|
|
||||||
for(pp = proc; pp < &proc[NPROC]; pp++){
|
for(pp = proc; pp < &proc[NPROC]; pp++) {
|
||||||
if(pp->parent == p){
|
if(pp->parent == p) {
|
||||||
pp->parent = initproc;
|
pp->parent = initproc;
|
||||||
wakeup(initproc);
|
wakeup(initproc);
|
||||||
}
|
}
|
||||||
|
@ -352,8 +345,8 @@ exit(int status)
|
||||||
panic("init exiting");
|
panic("init exiting");
|
||||||
|
|
||||||
// Close all open files.
|
// Close all open files.
|
||||||
for(int fd = 0; fd < NOFILE; fd++){
|
for(int fd = 0; fd < NOFILE; fd++) {
|
||||||
if(p->ofile[fd]){
|
if(p->ofile[fd]) {
|
||||||
struct file *f = p->ofile[fd];
|
struct file *f = p->ofile[fd];
|
||||||
fileclose(f);
|
fileclose(f);
|
||||||
p->ofile[fd] = 0;
|
p->ofile[fd] = 0;
|
||||||
|
@ -372,7 +365,7 @@ exit(int status)
|
||||||
|
|
||||||
// Parent might be sleeping in wait().
|
// Parent might be sleeping in wait().
|
||||||
wakeup(p->parent);
|
wakeup(p->parent);
|
||||||
|
|
||||||
acquire(&p->lock);
|
acquire(&p->lock);
|
||||||
|
|
||||||
p->xstate = status;
|
p->xstate = status;
|
||||||
|
@ -391,25 +384,24 @@ int
|
||||||
wait(u64 addr)
|
wait(u64 addr)
|
||||||
{
|
{
|
||||||
struct proc *pp;
|
struct proc *pp;
|
||||||
int havekids, pid;
|
int havekids, pid;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
acquire(&wait_lock);
|
acquire(&wait_lock);
|
||||||
|
|
||||||
for(;;){
|
for(;;) {
|
||||||
// Scan through table looking for exited children.
|
// Scan through table looking for exited children.
|
||||||
havekids = 0;
|
havekids = 0;
|
||||||
for(pp = proc; pp < &proc[NPROC]; pp++){
|
for(pp = proc; pp < &proc[NPROC]; pp++) {
|
||||||
if(pp->parent == p){
|
if(pp->parent == p) {
|
||||||
// make sure the child isn't still in exit() or swtch().
|
// make sure the child isn't still in exit() or swtch().
|
||||||
acquire(&pp->lock);
|
acquire(&pp->lock);
|
||||||
|
|
||||||
havekids = 1;
|
havekids = 1;
|
||||||
if(pp->state == ZOMBIE){
|
if(pp->state == ZOMBIE) {
|
||||||
// Found one.
|
// Found one.
|
||||||
pid = pp->pid;
|
pid = pp->pid;
|
||||||
if(addr != 0 && copyout(p->pagetable, addr, (char *)&pp->xstate,
|
if(addr != 0 && copyout(p->pagetable, addr, (char *)&pp->xstate, sizeof(pp->xstate)) < 0) {
|
||||||
sizeof(pp->xstate)) < 0) {
|
|
||||||
release(&pp->lock);
|
release(&pp->lock);
|
||||||
release(&wait_lock);
|
release(&wait_lock);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -424,13 +416,13 @@ wait(u64 addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// No point waiting if we don't have any children.
|
// No point waiting if we don't have any children.
|
||||||
if(!havekids || killed(p)){
|
if(!havekids || killed(p)) {
|
||||||
release(&wait_lock);
|
release(&wait_lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for a child to exit.
|
// Wait for a child to exit.
|
||||||
sleep(p, &wait_lock); //DOC: wait-sleep
|
sleep(p, &wait_lock); // DOC: wait-sleep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,10 +437,10 @@ void
|
||||||
scheduler(void)
|
scheduler(void)
|
||||||
{
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
struct cpu *c = mycpu();
|
struct cpu *c = mycpu();
|
||||||
|
|
||||||
c->proc = 0;
|
c->proc = 0;
|
||||||
for(;;){
|
for(;;) {
|
||||||
// Avoid deadlock by ensuring that devices can interrupt.
|
// Avoid deadlock by ensuring that devices can interrupt.
|
||||||
intr_on();
|
intr_on();
|
||||||
|
|
||||||
|
@ -481,7 +473,7 @@ scheduler(void)
|
||||||
void
|
void
|
||||||
sched(void)
|
sched(void)
|
||||||
{
|
{
|
||||||
int intena;
|
int intena;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
if(!holding(&p->lock))
|
if(!holding(&p->lock))
|
||||||
|
@ -519,7 +511,7 @@ forkret(void)
|
||||||
// Still holding p->lock from scheduler.
|
// Still holding p->lock from scheduler.
|
||||||
release(&myproc()->lock);
|
release(&myproc()->lock);
|
||||||
|
|
||||||
if (first) {
|
if(first) {
|
||||||
// File system initialization must be run in the context of a
|
// File system initialization must be run in the context of a
|
||||||
// regular process (e.g., because it calls sleep), and thus cannot
|
// regular process (e.g., because it calls sleep), and thus cannot
|
||||||
// be run from main().
|
// be run from main().
|
||||||
|
@ -536,7 +528,7 @@ void
|
||||||
sleep(void *chan, struct spinlock *lk)
|
sleep(void *chan, struct spinlock *lk)
|
||||||
{
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
// Must acquire p->lock in order to
|
// Must acquire p->lock in order to
|
||||||
// change p->state and then call sched.
|
// change p->state and then call sched.
|
||||||
// Once we hold p->lock, we can be
|
// Once we hold p->lock, we can be
|
||||||
|
@ -544,7 +536,7 @@ sleep(void *chan, struct spinlock *lk)
|
||||||
// (wakeup locks p->lock),
|
// (wakeup locks p->lock),
|
||||||
// so it's okay to release lk.
|
// so it's okay to release lk.
|
||||||
|
|
||||||
acquire(&p->lock); //DOC: sleeplock1
|
acquire(&p->lock); // DOC: sleeplock1
|
||||||
release(lk);
|
release(lk);
|
||||||
|
|
||||||
// Go to sleep.
|
// Go to sleep.
|
||||||
|
@ -569,7 +561,7 @@ wakeup(void *chan)
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
for(p = proc; p < &proc[NPROC]; p++) {
|
for(p = proc; p < &proc[NPROC]; p++) {
|
||||||
if(p != myproc()){
|
if(p != myproc()) {
|
||||||
acquire(&p->lock);
|
acquire(&p->lock);
|
||||||
if(p->state == SLEEPING && p->chan == chan) {
|
if(p->state == SLEEPING && p->chan == chan) {
|
||||||
p->state = RUNNABLE;
|
p->state = RUNNABLE;
|
||||||
|
@ -587,11 +579,11 @@ kill(int pid)
|
||||||
{
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
for(p = proc; p < &proc[NPROC]; p++){
|
for(p = proc; p < &proc[NPROC]; p++) {
|
||||||
acquire(&p->lock);
|
acquire(&p->lock);
|
||||||
if(p->pid == pid){
|
if(p->pid == pid) {
|
||||||
p->killed = 1;
|
p->killed = 1;
|
||||||
if(p->state == SLEEPING){
|
if(p->state == SLEEPING) {
|
||||||
// Wake process from sleep().
|
// Wake process from sleep().
|
||||||
p->state = RUNNABLE;
|
p->state = RUNNABLE;
|
||||||
}
|
}
|
||||||
|
@ -615,7 +607,7 @@ int
|
||||||
killed(struct proc *p)
|
killed(struct proc *p)
|
||||||
{
|
{
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
acquire(&p->lock);
|
acquire(&p->lock);
|
||||||
k = p->killed;
|
k = p->killed;
|
||||||
release(&p->lock);
|
release(&p->lock);
|
||||||
|
@ -629,7 +621,7 @@ int
|
||||||
either_copyout(int user_dst, u64 dst, void *src, u64 len)
|
either_copyout(int user_dst, u64 dst, void *src, u64 len)
|
||||||
{
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
if(user_dst){
|
if(user_dst) {
|
||||||
return copyout(p->pagetable, dst, src, len);
|
return copyout(p->pagetable, dst, src, len);
|
||||||
} else {
|
} else {
|
||||||
memmove((char *)dst, src, len);
|
memmove((char *)dst, src, len);
|
||||||
|
@ -644,10 +636,10 @@ int
|
||||||
either_copyin(void *dst, int user_src, u64 src, u64 len)
|
either_copyin(void *dst, int user_src, u64 src, u64 len)
|
||||||
{
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
if(user_src){
|
if(user_src) {
|
||||||
return copyin(p->pagetable, dst, src, len);
|
return copyin(p->pagetable, dst, src, len);
|
||||||
} else {
|
} else {
|
||||||
memmove(dst, (char*)src, len);
|
memmove(dst, (char *)src, len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -659,18 +651,13 @@ void
|
||||||
procdump(void)
|
procdump(void)
|
||||||
{
|
{
|
||||||
static char *states[] = {
|
static char *states[] = {
|
||||||
[UNUSED] "unused",
|
[UNUSED] "unused", [USED] "used", [SLEEPING] "sleep ", [RUNNABLE] "runble", [RUNNING] "run ", [ZOMBIE] "zombie"
|
||||||
[USED] "used",
|
|
||||||
[SLEEPING] "sleep ",
|
|
||||||
[RUNNABLE] "runble",
|
|
||||||
[RUNNING] "run ",
|
|
||||||
[ZOMBIE] "zombie"
|
|
||||||
};
|
};
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
char *state;
|
char *state;
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
for(p = proc; p < &proc[NPROC]; p++){
|
for(p = proc; p < &proc[NPROC]; p++) {
|
||||||
if(p->state == UNUSED)
|
if(p->state == UNUSED)
|
||||||
continue;
|
continue;
|
||||||
if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
|
if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
|
||||||
|
|
|
@ -20,10 +20,10 @@ struct context {
|
||||||
|
|
||||||
// Per-CPU state.
|
// Per-CPU state.
|
||||||
struct cpu {
|
struct cpu {
|
||||||
struct proc *proc; // The process running on this cpu, or null.
|
struct proc *proc; // The process running on this cpu, or null.
|
||||||
struct context context; // swtch() here to enter scheduler().
|
struct context context; // swtch() here to enter scheduler().
|
||||||
int noff; // Depth of push_off() nesting.
|
int noff; // Depth of push_off() nesting.
|
||||||
int intena; // Were interrupts enabled before push_off()?
|
int intena; // Were interrupts enabled before push_off()?
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct cpu cpus[NCPU];
|
extern struct cpu cpus[NCPU];
|
||||||
|
@ -86,22 +86,22 @@ struct proc {
|
||||||
struct spinlock lock;
|
struct spinlock lock;
|
||||||
|
|
||||||
// p->lock must be held when using these:
|
// p->lock must be held when using these:
|
||||||
enum procstate state; // Process state
|
enum procstate state; // Process state
|
||||||
void *chan; // If non-zero, sleeping on chan
|
void *chan; // If non-zero, sleeping on chan
|
||||||
int killed; // If non-zero, have been killed
|
int killed; // If non-zero, have been killed
|
||||||
int xstate; // Exit status to be returned to parent's wait
|
int xstate; // Exit status to be returned to parent's wait
|
||||||
int pid; // Process ID
|
int pid; // Process ID
|
||||||
|
|
||||||
// wait_lock must be held when using this:
|
// wait_lock must be held when using this:
|
||||||
struct proc *parent; // Parent process
|
struct proc *parent; // Parent process
|
||||||
|
|
||||||
// these are private to the process, so p->lock need not be held.
|
// these are private to the process, so p->lock need not be held.
|
||||||
u64 kstack; // Virtual address of kernel stack
|
u64 kstack; // Virtual address of kernel stack
|
||||||
u64 sz; // Size of process memory (bytes)
|
u64 sz; // Size of process memory (bytes)
|
||||||
pagetable_t pagetable; // User page table
|
pagetable_t pagetable; // User page table
|
||||||
struct trapframe *trapframe; // data page for trampoline.S
|
struct trapframe *trapframe; // data page for trampoline.S
|
||||||
struct context context; // swtch() here to run process
|
struct context context; // swtch() here to run process
|
||||||
struct file *ofile[NOFILE]; // Open files
|
struct file *ofile[NOFILE]; // Open files
|
||||||
struct inode *cwd; // Current directory
|
struct inode *cwd; // Current directory
|
||||||
char name[16]; // Process name (debugging)
|
char name[16]; // Process name (debugging)
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,16 +24,16 @@ ramdiskrw(struct buf *b)
|
||||||
{
|
{
|
||||||
if(!holdingsleep(&b->lock))
|
if(!holdingsleep(&b->lock))
|
||||||
panic("ramdiskrw: buf not locked");
|
panic("ramdiskrw: buf not locked");
|
||||||
if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
|
if((b->flags & (B_VALID | B_DIRTY)) == B_VALID)
|
||||||
panic("ramdiskrw: nothing to do");
|
panic("ramdiskrw: nothing to do");
|
||||||
|
|
||||||
if(b->blockno >= FSSIZE)
|
if(b->blockno >= FSSIZE)
|
||||||
panic("ramdiskrw: blockno too big");
|
panic("ramdiskrw: blockno too big");
|
||||||
|
|
||||||
u64 diskaddr = b->blockno * BSIZE;
|
u64 diskaddr = b->blockno * BSIZE;
|
||||||
char *addr = (char *)RAMDISK + diskaddr;
|
char *addr = (char *)RAMDISK + diskaddr;
|
||||||
|
|
||||||
if(b->flags & B_DIRTY){
|
if(b->flags & B_DIRTY) {
|
||||||
// write
|
// write
|
||||||
memmove(addr, b->data, BSIZE);
|
memmove(addr, b->data, BSIZE);
|
||||||
b->flags &= ~B_DIRTY;
|
b->flags &= ~B_DIRTY;
|
||||||
|
|
130
kernel/riscv.h
130
kernel/riscv.h
|
@ -5,61 +5,61 @@ static inline u64
|
||||||
r_mhartid()
|
r_mhartid()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, mhartid" : "=r" (x) );
|
asm volatile("csrr %0, mhartid" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Machine Status Register, mstatus
|
// Machine Status Register, mstatus
|
||||||
|
|
||||||
#define MSTATUS_MPP_MASK (3L << 11) // previous mode.
|
#define MSTATUS_MPP_MASK (3L << 11) // previous mode.
|
||||||
#define MSTATUS_MPP_M (3L << 11)
|
#define MSTATUS_MPP_M (3L << 11)
|
||||||
#define MSTATUS_MPP_S (1L << 11)
|
#define MSTATUS_MPP_S (1L << 11)
|
||||||
#define MSTATUS_MPP_U (0L << 11)
|
#define MSTATUS_MPP_U (0L << 11)
|
||||||
#define MSTATUS_MIE (1L << 3) // machine-mode interrupt enable.
|
#define MSTATUS_MIE (1L << 3) // machine-mode interrupt enable.
|
||||||
|
|
||||||
static inline u64
|
static inline u64
|
||||||
r_mstatus()
|
r_mstatus()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, mstatus" : "=r" (x) );
|
asm volatile("csrr %0, mstatus" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_mstatus(u64 x)
|
w_mstatus(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw mstatus, %0" : : "r" (x));
|
asm volatile("csrw mstatus, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// machine exception program counter, holds the
|
// machine exception program counter, holds the
|
||||||
// instruction address to which a return from
|
// instruction address to which a return from
|
||||||
// exception will go.
|
// exception will go.
|
||||||
static inline void
|
static inline void
|
||||||
w_mepc(u64 x)
|
w_mepc(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw mepc, %0" : : "r" (x));
|
asm volatile("csrw mepc, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supervisor Status Register, sstatus
|
// Supervisor Status Register, sstatus
|
||||||
|
|
||||||
#define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User
|
#define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User
|
||||||
#define SSTATUS_SPIE (1L << 5) // Supervisor Previous Interrupt Enable
|
#define SSTATUS_SPIE (1L << 5) // Supervisor Previous Interrupt Enable
|
||||||
#define SSTATUS_UPIE (1L << 4) // User Previous Interrupt Enable
|
#define SSTATUS_UPIE (1L << 4) // User Previous Interrupt Enable
|
||||||
#define SSTATUS_SIE (1L << 1) // Supervisor Interrupt Enable
|
#define SSTATUS_SIE (1L << 1) // Supervisor Interrupt Enable
|
||||||
#define SSTATUS_UIE (1L << 0) // User Interrupt Enable
|
#define SSTATUS_UIE (1L << 0) // User Interrupt Enable
|
||||||
|
|
||||||
static inline u64
|
static inline u64
|
||||||
r_sstatus()
|
r_sstatus()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, sstatus" : "=r" (x) );
|
asm volatile("csrr %0, sstatus" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_sstatus(u64 x)
|
w_sstatus(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw sstatus, %0" : : "r" (x));
|
asm volatile("csrw sstatus, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supervisor Interrupt Pending
|
// Supervisor Interrupt Pending
|
||||||
|
@ -67,14 +67,14 @@ static inline u64
|
||||||
r_sip()
|
r_sip()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, sip" : "=r" (x) );
|
asm volatile("csrr %0, sip" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_sip(u64 x)
|
w_sip(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw sip, %0" : : "r" (x));
|
asm volatile("csrw sip, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supervisor Interrupt Enable
|
// Supervisor Interrupt Enable
|
||||||
|
@ -85,14 +85,14 @@ static inline u64
|
||||||
r_sie()
|
r_sie()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, sie" : "=r" (x) );
|
asm volatile("csrr %0, sie" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_sie(u64 x)
|
w_sie(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw sie, %0" : : "r" (x));
|
asm volatile("csrw sie, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Machine-mode Interrupt Enable
|
// Machine-mode Interrupt Enable
|
||||||
|
@ -103,30 +103,30 @@ static inline u64
|
||||||
r_mie()
|
r_mie()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, mie" : "=r" (x) );
|
asm volatile("csrr %0, mie" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_mie(u64 x)
|
w_mie(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw mie, %0" : : "r" (x));
|
asm volatile("csrw mie, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// supervisor exception program counter, holds the
|
// supervisor exception program counter, holds the
|
||||||
// instruction address to which a return from
|
// instruction address to which a return from
|
||||||
// exception will go.
|
// exception will go.
|
||||||
static inline void
|
static inline void
|
||||||
w_sepc(u64 x)
|
w_sepc(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw sepc, %0" : : "r" (x));
|
asm volatile("csrw sepc, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64
|
static inline u64
|
||||||
r_sepc()
|
r_sepc()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, sepc" : "=r" (x) );
|
asm volatile("csrr %0, sepc" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,14 +135,14 @@ static inline u64
|
||||||
r_medeleg()
|
r_medeleg()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, medeleg" : "=r" (x) );
|
asm volatile("csrr %0, medeleg" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_medeleg(u64 x)
|
w_medeleg(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw medeleg, %0" : : "r" (x));
|
asm volatile("csrw medeleg, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Machine Interrupt Delegation
|
// Machine Interrupt Delegation
|
||||||
|
@ -150,50 +150,50 @@ static inline u64
|
||||||
r_mideleg()
|
r_mideleg()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, mideleg" : "=r" (x) );
|
asm volatile("csrr %0, mideleg" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_mideleg(u64 x)
|
w_mideleg(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw mideleg, %0" : : "r" (x));
|
asm volatile("csrw mideleg, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supervisor Trap-Vector Base Address
|
// Supervisor Trap-Vector Base Address
|
||||||
// low two bits are mode.
|
// low two bits are mode.
|
||||||
static inline void
|
static inline void
|
||||||
w_stvec(u64 x)
|
w_stvec(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw stvec, %0" : : "r" (x));
|
asm volatile("csrw stvec, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64
|
static inline u64
|
||||||
r_stvec()
|
r_stvec()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, stvec" : "=r" (x) );
|
asm volatile("csrr %0, stvec" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Machine-mode interrupt vector
|
// Machine-mode interrupt vector
|
||||||
static inline void
|
static inline void
|
||||||
w_mtvec(u64 x)
|
w_mtvec(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw mtvec, %0" : : "r" (x));
|
asm volatile("csrw mtvec, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Physical Memory Protection
|
// Physical Memory Protection
|
||||||
static inline void
|
static inline void
|
||||||
w_pmpcfg0(u64 x)
|
w_pmpcfg0(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw pmpcfg0, %0" : : "r" (x));
|
asm volatile("csrw pmpcfg0, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_pmpaddr0(u64 x)
|
w_pmpaddr0(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw pmpaddr0, %0" : : "r" (x));
|
asm volatile("csrw pmpaddr0, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// use riscv's sv39 page table scheme.
|
// use riscv's sv39 page table scheme.
|
||||||
|
@ -203,24 +203,24 @@ w_pmpaddr0(u64 x)
|
||||||
|
|
||||||
// supervisor address translation and protection;
|
// supervisor address translation and protection;
|
||||||
// holds the address of the page table.
|
// holds the address of the page table.
|
||||||
static inline void
|
static inline void
|
||||||
w_satp(u64 x)
|
w_satp(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw satp, %0" : : "r" (x));
|
asm volatile("csrw satp, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64
|
static inline u64
|
||||||
r_satp()
|
r_satp()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, satp" : "=r" (x) );
|
asm volatile("csrr %0, satp" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_mscratch(u64 x)
|
w_mscratch(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw mscratch, %0" : : "r" (x));
|
asm volatile("csrw mscratch, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supervisor Trap Cause
|
// Supervisor Trap Cause
|
||||||
|
@ -228,7 +228,7 @@ static inline u64
|
||||||
r_scause()
|
r_scause()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, scause" : "=r" (x) );
|
asm volatile("csrr %0, scause" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,22 +237,22 @@ static inline u64
|
||||||
r_stval()
|
r_stval()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, stval" : "=r" (x) );
|
asm volatile("csrr %0, stval" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Machine-mode Counter-Enable
|
// Machine-mode Counter-Enable
|
||||||
static inline void
|
static inline void
|
||||||
w_mcounteren(u64 x)
|
w_mcounteren(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("csrw mcounteren, %0" : : "r" (x));
|
asm volatile("csrw mcounteren, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64
|
static inline u64
|
||||||
r_mcounteren()
|
r_mcounteren()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, mcounteren" : "=r" (x) );
|
asm volatile("csrr %0, mcounteren" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ static inline u64
|
||||||
r_time()
|
r_time()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("csrr %0, time" : "=r" (x) );
|
asm volatile("csrr %0, time" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ static inline u64
|
||||||
r_sp()
|
r_sp()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("mv %0, sp" : "=r" (x) );
|
asm volatile("mv %0, sp" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,21 +301,21 @@ static inline u64
|
||||||
r_tp()
|
r_tp()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("mv %0, tp" : "=r" (x) );
|
asm volatile("mv %0, tp" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
w_tp(u64 x)
|
w_tp(u64 x)
|
||||||
{
|
{
|
||||||
asm volatile("mv tp, %0" : : "r" (x));
|
asm volatile("mv tp, %0" : : "r"(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64
|
static inline u64
|
||||||
r_ra()
|
r_ra()
|
||||||
{
|
{
|
||||||
u64 x;
|
u64 x;
|
||||||
asm volatile("mv %0, ra" : "=r" (x) );
|
asm volatile("mv %0, ra" : "=r"(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,16 +327,16 @@ sfence_vma()
|
||||||
asm volatile("sfence.vma zero, zero");
|
asm volatile("sfence.vma zero, zero");
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef u64 pte_t;
|
typedef u64 pte_t;
|
||||||
typedef u64 *pagetable_t; // 512 PTEs
|
typedef u64 *pagetable_t; // 512 PTEs
|
||||||
|
|
||||||
#endif // __ASSEMBLER__
|
#endif // __ASSEMBLER__
|
||||||
|
|
||||||
#define PGSIZE 4096 // bytes per page
|
#define PGSIZE 4096 // bytes per page
|
||||||
#define PGSHIFT 12 // bits of offset within a page
|
#define PGSHIFT 12 // bits of offset within a page
|
||||||
|
|
||||||
#define PGROUNDUP(sz) (((sz)+PGSIZE-1) & ~(PGSIZE-1))
|
#define PGROUNDUP(sz) (((sz) + PGSIZE - 1) & ~(PGSIZE - 1))
|
||||||
#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1))
|
#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE - 1))
|
||||||
|
|
||||||
#define PTE_V (1L << 0) // valid
|
#define PTE_V (1L << 0) // valid
|
||||||
#define PTE_R (1L << 1)
|
#define PTE_R (1L << 1)
|
||||||
|
@ -352,9 +352,9 @@ typedef u64 *pagetable_t; // 512 PTEs
|
||||||
#define PTE_FLAGS(pte) ((pte) & 0x3FF)
|
#define PTE_FLAGS(pte) ((pte) & 0x3FF)
|
||||||
|
|
||||||
// extract the three 9-bit page table indices from a virtual address.
|
// extract the three 9-bit page table indices from a virtual address.
|
||||||
#define PXMASK 0x1FF // 9 bits
|
#define PXMASK 0x1FF // 9 bits
|
||||||
#define PXSHIFT(level) (PGSHIFT+(9*(level)))
|
#define PXSHIFT(level) (PGSHIFT + (9 * (level)))
|
||||||
#define PX(level, va) ((((u64) (va)) >> PXSHIFT(level)) & PXMASK)
|
#define PX(level, va) ((((u64)(va)) >> PXSHIFT(level)) & PXMASK)
|
||||||
|
|
||||||
// one beyond the highest possible virtual address.
|
// one beyond the highest possible virtual address.
|
||||||
// MAXVA is actually one bit less than the max allowed by
|
// MAXVA is actually one bit less than the max allowed by
|
||||||
|
|
|
@ -22,7 +22,7 @@ void
|
||||||
acquiresleep(struct sleeplock *lk)
|
acquiresleep(struct sleeplock *lk)
|
||||||
{
|
{
|
||||||
acquire(&lk->lk);
|
acquire(&lk->lk);
|
||||||
while (lk->locked) {
|
while(lk->locked) {
|
||||||
sleep(lk, &lk->lk);
|
sleep(lk, &lk->lk);
|
||||||
}
|
}
|
||||||
lk->locked = 1;
|
lk->locked = 1;
|
||||||
|
@ -44,12 +44,9 @@ int
|
||||||
holdingsleep(struct sleeplock *lk)
|
holdingsleep(struct sleeplock *lk)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
acquire(&lk->lk);
|
acquire(&lk->lk);
|
||||||
r = lk->locked && (lk->pid == myproc()->pid);
|
r = lk->locked && (lk->pid == myproc()->pid);
|
||||||
release(&lk->lk);
|
release(&lk->lk);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// Long-term locks for processes
|
// Long-term locks for processes
|
||||||
struct sleeplock {
|
struct sleeplock {
|
||||||
u32 locked; // Is the lock held?
|
u32 locked; // Is the lock held?
|
||||||
struct spinlock lk; // spinlock protecting this sleep lock
|
struct spinlock lk; // spinlock protecting this sleep lock
|
||||||
|
|
||||||
// For debugging:
|
|
||||||
char *name; // Name of lock.
|
|
||||||
int pid; // Process holding lock
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// For debugging:
|
||||||
|
char *name; // Name of lock.
|
||||||
|
int pid; // Process holding lock
|
||||||
|
};
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// Mutual exclusion lock.
|
// Mutual exclusion lock.
|
||||||
struct spinlock {
|
struct spinlock {
|
||||||
u32 locked; // Is the lock held?
|
u32 locked; // Is the lock held?
|
||||||
|
|
||||||
// For debugging:
|
// For debugging:
|
||||||
char *name; // Name of lock.
|
char *name; // Name of lock.
|
||||||
struct cpu *cpu; // The cpu holding the lock.
|
struct cpu *cpu; // The cpu holding the lock.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ void main();
|
||||||
void timerinit();
|
void timerinit();
|
||||||
|
|
||||||
// entry.S needs one stack per CPU.
|
// entry.S needs one stack per CPU.
|
||||||
__attribute__ ((aligned (16))) char stack0[4096 * NCPU];
|
__attribute__((aligned(16))) char stack0[4096 * NCPU];
|
||||||
|
|
||||||
// a scratch area per CPU for machine-mode timer interrupts.
|
// a scratch area per CPU for machine-mode timer interrupts.
|
||||||
u64 timer_scratch[NCPU][5];
|
u64 timer_scratch[NCPU][5];
|
||||||
|
@ -67,7 +67,7 @@ timerinit()
|
||||||
|
|
||||||
// ask the CLINT for a timer interrupt.
|
// ask the CLINT for a timer interrupt.
|
||||||
int interval = 1000000; // cycles; about 1/10th second in qemu.
|
int interval = 1000000; // cycles; about 1/10th second in qemu.
|
||||||
*(u64*)CLINT_MTIMECMP(id) = *(u64*)CLINT_MTIME + interval;
|
*(u64 *)CLINT_MTIMECMP(id) = *(u64 *)CLINT_MTIME + interval;
|
||||||
|
|
||||||
// prepare information in scratch[] for timervec.
|
// prepare information in scratch[] for timervec.
|
||||||
// scratch[0..2] : space for timervec to save registers.
|
// scratch[0..2] : space for timervec to save registers.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#define T_DIR 1 // Directory
|
#define T_DIR 1 // Directory
|
||||||
#define T_FILE 2 // File
|
#define T_FILE 2 // File
|
||||||
#define T_DEVICE 3 // Device
|
#define T_DEVICE 3 // Device
|
||||||
|
|
||||||
struct stat {
|
struct stat {
|
||||||
int dev; // File system's disk device
|
int dev; // File system's disk device
|
||||||
u32 ino; // Inode number
|
u32 ino; // Inode number
|
||||||
short type; // Type of file
|
short type; // Type of file
|
||||||
short nlink; // Number of links to file
|
short nlink; // Number of links to file
|
||||||
u64 size; // Size of file in bytes
|
u64 size; // Size of file in bytes
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
void*
|
void *
|
||||||
memset(void *dst, int c, u32 n)
|
memset(void *dst, int c, u32 n)
|
||||||
{
|
{
|
||||||
char *cdst = (char *) dst;
|
char *cdst = (char *)dst;
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < n; i++){
|
for(i = 0; i < n; i++) {
|
||||||
cdst[i] = c;
|
cdst[i] = c;
|
||||||
}
|
}
|
||||||
return dst;
|
return dst;
|
||||||
|
@ -18,7 +18,7 @@ memcmp(const void *v1, const void *v2, u32 n)
|
||||||
|
|
||||||
s1 = v1;
|
s1 = v1;
|
||||||
s2 = v2;
|
s2 = v2;
|
||||||
while(n-- > 0){
|
while(n-- > 0) {
|
||||||
if(*s1 != *s2)
|
if(*s1 != *s2)
|
||||||
return *s1 - *s2;
|
return *s1 - *s2;
|
||||||
s1++, s2++;
|
s1++, s2++;
|
||||||
|
@ -27,18 +27,18 @@ memcmp(const void *v1, const void *v2, u32 n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void *
|
||||||
memmove(void *dst, const void *src, u32 n)
|
memmove(void *dst, const void *src, u32 n)
|
||||||
{
|
{
|
||||||
const char *s;
|
const char *s;
|
||||||
char *d;
|
char *d;
|
||||||
|
|
||||||
if(n == 0)
|
if(n == 0)
|
||||||
return dst;
|
return dst;
|
||||||
|
|
||||||
s = src;
|
s = src;
|
||||||
d = dst;
|
d = dst;
|
||||||
if(s < d && s + n > d){
|
if(s < d && s + n > d) {
|
||||||
s += n;
|
s += n;
|
||||||
d += n;
|
d += n;
|
||||||
while(n-- > 0)
|
while(n-- > 0)
|
||||||
|
@ -51,7 +51,7 @@ memmove(void *dst, const void *src, u32 n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// memcpy exists to placate GCC. Use memmove.
|
// memcpy exists to placate GCC. Use memmove.
|
||||||
void*
|
void *
|
||||||
memcpy(void *dst, const void *src, u32 n)
|
memcpy(void *dst, const void *src, u32 n)
|
||||||
{
|
{
|
||||||
return memmove(dst, src, n);
|
return memmove(dst, src, n);
|
||||||
|
@ -67,7 +67,7 @@ strncmp(const char *p, const char *q, u32 n)
|
||||||
return (u8)*p - (u8)*q;
|
return (u8)*p - (u8)*q;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char *
|
||||||
strncpy(char *s, const char *t, int n)
|
strncpy(char *s, const char *t, int n)
|
||||||
{
|
{
|
||||||
char *os;
|
char *os;
|
||||||
|
@ -81,7 +81,7 @@ strncpy(char *s, const char *t, int n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like strncpy but guaranteed to NUL-terminate.
|
// Like strncpy but guaranteed to NUL-terminate.
|
||||||
char*
|
char *
|
||||||
safestrcpy(char *s, const char *t, int n)
|
safestrcpy(char *s, const char *t, int n)
|
||||||
{
|
{
|
||||||
char *os;
|
char *os;
|
||||||
|
@ -104,4 +104,3 @@ strlen(const char *s)
|
||||||
;
|
;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ int
|
||||||
fetchaddr(u64 addr, u64 *ip)
|
fetchaddr(u64 addr, u64 *ip)
|
||||||
{
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
if(addr >= p->sz || addr+sizeof(u64) > p->sz) // both tests needed, in case of overflow
|
if(addr >= p->sz || addr + sizeof(u64) > p->sz) // both tests needed, in case of overflow
|
||||||
return -1;
|
return -1;
|
||||||
if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
|
if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -34,7 +34,7 @@ static u64
|
||||||
argraw(int n)
|
argraw(int n)
|
||||||
{
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
switch (n) {
|
switch(n) {
|
||||||
case 0:
|
case 0:
|
||||||
return p->trapframe->a0;
|
return p->trapframe->a0;
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -105,33 +105,18 @@ extern u64 sys_close(void);
|
||||||
// An array mapping syscall numbers from syscall.h
|
// An array mapping syscall numbers from syscall.h
|
||||||
// to the function that handles the system call.
|
// to the function that handles the system call.
|
||||||
static u64 (*syscalls[])(void) = {
|
static u64 (*syscalls[])(void) = {
|
||||||
[SYS_fork] sys_fork,
|
[SYS_fork] sys_fork, [SYS_exit] sys_exit, [SYS_wait] sys_wait, [SYS_pipe] sys_pipe,
|
||||||
[SYS_exit] sys_exit,
|
[SYS_read] sys_read, [SYS_kill] sys_kill, [SYS_exec] sys_exec, [SYS_fstat] sys_fstat,
|
||||||
[SYS_wait] sys_wait,
|
[SYS_chdir] sys_chdir, [SYS_dup] sys_dup, [SYS_getpid] sys_getpid, [SYS_sbrk] sys_sbrk,
|
||||||
[SYS_pipe] sys_pipe,
|
[SYS_sleep] sys_sleep, [SYS_uptime] sys_uptime, [SYS_open] sys_open, [SYS_write] sys_write,
|
||||||
[SYS_read] sys_read,
|
[SYS_mknod] sys_mknod, [SYS_unlink] sys_unlink, [SYS_link] sys_link, [SYS_mkdir] sys_mkdir,
|
||||||
[SYS_kill] sys_kill,
|
[SYS_close] sys_close,
|
||||||
[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
|
void
|
||||||
syscall(void)
|
syscall(void)
|
||||||
{
|
{
|
||||||
int num;
|
int num;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
num = p->trapframe->a7;
|
num = p->trapframe->a7;
|
||||||
|
@ -140,8 +125,7 @@ syscall(void)
|
||||||
// and store its return value in p->trapframe->a0
|
// and store its return value in p->trapframe->a0
|
||||||
p->trapframe->a0 = syscalls[num]();
|
p->trapframe->a0 = syscalls[num]();
|
||||||
} else {
|
} else {
|
||||||
printf("%d %s: unknown sys call %d\n",
|
printf("%d %s: unknown sys call %d\n", p->pid, p->name, num);
|
||||||
p->pid, p->name, num);
|
|
||||||
p->trapframe->a0 = -1;
|
p->trapframe->a0 = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// System call numbers
|
// System call numbers
|
||||||
#define SYS_fork 1
|
#define SYS_fork 1
|
||||||
#define SYS_exit 2
|
#define SYS_exit 2
|
||||||
#define SYS_wait 3
|
#define SYS_wait 3
|
||||||
#define SYS_pipe 4
|
#define SYS_pipe 4
|
||||||
#define SYS_read 5
|
#define SYS_read 5
|
||||||
#define SYS_kill 6
|
#define SYS_kill 6
|
||||||
#define SYS_exec 7
|
#define SYS_exec 7
|
||||||
#define SYS_fstat 8
|
#define SYS_fstat 8
|
||||||
#define SYS_chdir 9
|
#define SYS_chdir 9
|
||||||
#define SYS_dup 10
|
#define SYS_dup 10
|
||||||
#define SYS_getpid 11
|
#define SYS_getpid 11
|
||||||
#define SYS_sbrk 12
|
#define SYS_sbrk 12
|
||||||
|
|
135
kernel/sysfile.c
135
kernel/sysfile.c
|
@ -21,11 +21,11 @@
|
||||||
static int
|
static int
|
||||||
argfd(int n, int *pfd, struct file **pf)
|
argfd(int n, int *pfd, struct file **pf)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
|
|
||||||
argint(n, &fd);
|
argint(n, &fd);
|
||||||
if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)
|
if(fd < 0 || fd >= NOFILE || (f = myproc()->ofile[fd]) == 0)
|
||||||
return -1;
|
return -1;
|
||||||
if(pfd)
|
if(pfd)
|
||||||
*pfd = fd;
|
*pfd = fd;
|
||||||
|
@ -39,11 +39,11 @@ argfd(int n, int *pfd, struct file **pf)
|
||||||
static int
|
static int
|
||||||
fdalloc(struct file *f)
|
fdalloc(struct file *f)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
for(fd = 0; fd < NOFILE; fd++){
|
for(fd = 0; fd < NOFILE; fd++) {
|
||||||
if(p->ofile[fd] == 0){
|
if(p->ofile[fd] == 0) {
|
||||||
p->ofile[fd] = f;
|
p->ofile[fd] = f;
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
@ -55,11 +55,11 @@ u64
|
||||||
sys_dup(void)
|
sys_dup(void)
|
||||||
{
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if(argfd(0, 0, &f) < 0)
|
if(argfd(0, 0, &f) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if((fd=fdalloc(f)) < 0)
|
if((fd = fdalloc(f)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
filedup(f);
|
filedup(f);
|
||||||
return fd;
|
return fd;
|
||||||
|
@ -69,8 +69,8 @@ u64
|
||||||
sys_read(void)
|
sys_read(void)
|
||||||
{
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int n;
|
int n;
|
||||||
u64 p;
|
u64 p;
|
||||||
|
|
||||||
argaddr(1, &p);
|
argaddr(1, &p);
|
||||||
argint(2, &n);
|
argint(2, &n);
|
||||||
|
@ -83,9 +83,9 @@ u64
|
||||||
sys_write(void)
|
sys_write(void)
|
||||||
{
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int n;
|
int n;
|
||||||
u64 p;
|
u64 p;
|
||||||
|
|
||||||
argaddr(1, &p);
|
argaddr(1, &p);
|
||||||
argint(2, &n);
|
argint(2, &n);
|
||||||
if(argfd(0, 0, &f) < 0)
|
if(argfd(0, 0, &f) < 0)
|
||||||
|
@ -97,7 +97,7 @@ sys_write(void)
|
||||||
u64
|
u64
|
||||||
sys_close(void)
|
sys_close(void)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
|
|
||||||
if(argfd(0, &fd, &f) < 0)
|
if(argfd(0, &fd, &f) < 0)
|
||||||
|
@ -111,7 +111,7 @@ u64
|
||||||
sys_fstat(void)
|
sys_fstat(void)
|
||||||
{
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
u64 st; // user pointer to struct stat
|
u64 st; // user pointer to struct stat
|
||||||
|
|
||||||
argaddr(1, &st);
|
argaddr(1, &st);
|
||||||
if(argfd(0, 0, &f) < 0)
|
if(argfd(0, 0, &f) < 0)
|
||||||
|
@ -123,20 +123,20 @@ sys_fstat(void)
|
||||||
u64
|
u64
|
||||||
sys_link(void)
|
sys_link(void)
|
||||||
{
|
{
|
||||||
char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
|
char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
|
||||||
struct inode *dp, *ip;
|
struct inode *dp, *ip;
|
||||||
|
|
||||||
if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
|
if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
if((ip = namei(old)) == 0){
|
if((ip = namei(old)) == 0) {
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
if(ip->type == T_DIR){
|
if(ip->type == T_DIR) {
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -149,7 +149,7 @@ sys_link(void)
|
||||||
if((dp = nameiparent(new, name)) == 0)
|
if((dp = nameiparent(new, name)) == 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
ilock(dp);
|
ilock(dp);
|
||||||
if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
|
if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0) {
|
||||||
iunlockput(dp);
|
iunlockput(dp);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
@ -173,10 +173,10 @@ bad:
|
||||||
static int
|
static int
|
||||||
isdirempty(struct inode *dp)
|
isdirempty(struct inode *dp)
|
||||||
{
|
{
|
||||||
int off;
|
int off;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
|
|
||||||
for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
|
for(off = 2 * sizeof(de); off < dp->size; off += sizeof(de)) {
|
||||||
if(readi(dp, 0, (u64)&de, off, sizeof(de)) != sizeof(de))
|
if(readi(dp, 0, (u64)&de, off, sizeof(de)) != sizeof(de))
|
||||||
panic("isdirempty: readi");
|
panic("isdirempty: readi");
|
||||||
if(de.inum != 0)
|
if(de.inum != 0)
|
||||||
|
@ -190,14 +190,14 @@ sys_unlink(void)
|
||||||
{
|
{
|
||||||
struct inode *ip, *dp;
|
struct inode *ip, *dp;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
char name[DIRSIZ], path[MAXPATH];
|
char name[DIRSIZ], path[MAXPATH];
|
||||||
u32 off;
|
u32 off;
|
||||||
|
|
||||||
if(argstr(0, path, MAXPATH) < 0)
|
if(argstr(0, path, MAXPATH) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
if((dp = nameiparent(path, name)) == 0){
|
if((dp = nameiparent(path, name)) == 0) {
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ sys_unlink(void)
|
||||||
|
|
||||||
if(ip->nlink < 1)
|
if(ip->nlink < 1)
|
||||||
panic("unlink: nlink < 1");
|
panic("unlink: nlink < 1");
|
||||||
if(ip->type == T_DIR && !isdirempty(ip)){
|
if(ip->type == T_DIR && !isdirempty(ip)) {
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ sys_unlink(void)
|
||||||
memset(&de, 0, sizeof(de));
|
memset(&de, 0, sizeof(de));
|
||||||
if(writei(dp, 0, (u64)&de, off, sizeof(de)) != sizeof(de))
|
if(writei(dp, 0, (u64)&de, off, sizeof(de)) != sizeof(de))
|
||||||
panic("unlink: writei");
|
panic("unlink: writei");
|
||||||
if(ip->type == T_DIR){
|
if(ip->type == T_DIR) {
|
||||||
dp->nlink--;
|
dp->nlink--;
|
||||||
iupdate(dp);
|
iupdate(dp);
|
||||||
}
|
}
|
||||||
|
@ -242,18 +242,18 @@ bad:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct inode*
|
static struct inode *
|
||||||
create(char *path, short type, short major, short minor)
|
create(char *path, short type, short major, short minor)
|
||||||
{
|
{
|
||||||
struct inode *ip, *dp;
|
struct inode *ip, *dp;
|
||||||
char name[DIRSIZ];
|
char name[DIRSIZ];
|
||||||
|
|
||||||
if((dp = nameiparent(path, name)) == 0)
|
if((dp = nameiparent(path, name)) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ilock(dp);
|
ilock(dp);
|
||||||
|
|
||||||
if((ip = dirlookup(dp, name, 0)) != 0){
|
if((ip = dirlookup(dp, name, 0)) != 0) {
|
||||||
iunlockput(dp);
|
iunlockput(dp);
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
|
if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
|
||||||
|
@ -262,7 +262,7 @@ create(char *path, short type, short major, short minor)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((ip = ialloc(dp->dev, type)) == 0){
|
if((ip = ialloc(dp->dev, type)) == 0) {
|
||||||
iunlockput(dp);
|
iunlockput(dp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ create(char *path, short type, short major, short minor)
|
||||||
ip->nlink = 1;
|
ip->nlink = 1;
|
||||||
iupdate(ip);
|
iupdate(ip);
|
||||||
|
|
||||||
if(type == T_DIR){ // Create . and .. entries.
|
if(type == T_DIR) { // Create . and .. entries.
|
||||||
// No ip->nlink++ for ".": avoid cyclic ref count.
|
// No ip->nlink++ for ".": avoid cyclic ref count.
|
||||||
if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
|
if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -282,9 +282,9 @@ create(char *path, short type, short major, short minor)
|
||||||
if(dirlink(dp, name, ip->inum) < 0)
|
if(dirlink(dp, name, ip->inum) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if(type == T_DIR){
|
if(type == T_DIR) {
|
||||||
// now that success is guaranteed:
|
// now that success is guaranteed:
|
||||||
dp->nlink++; // for ".."
|
dp->nlink++; // for ".."
|
||||||
iupdate(dp);
|
iupdate(dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ create(char *path, short type, short major, short minor)
|
||||||
|
|
||||||
return ip;
|
return ip;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
// something went wrong. de-allocate ip.
|
// something went wrong. de-allocate ip.
|
||||||
ip->nlink = 0;
|
ip->nlink = 0;
|
||||||
iupdate(ip);
|
iupdate(ip);
|
||||||
|
@ -304,11 +304,11 @@ create(char *path, short type, short major, short minor)
|
||||||
u64
|
u64
|
||||||
sys_open(void)
|
sys_open(void)
|
||||||
{
|
{
|
||||||
char path[MAXPATH];
|
char path[MAXPATH];
|
||||||
int fd, omode;
|
int fd, omode;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
argint(1, &omode);
|
argint(1, &omode);
|
||||||
if((n = argstr(0, path, MAXPATH)) < 0)
|
if((n = argstr(0, path, MAXPATH)) < 0)
|
||||||
|
@ -316,32 +316,32 @@ sys_open(void)
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
|
|
||||||
if(omode & O_CREATE){
|
if(omode & O_CREATE) {
|
||||||
ip = create(path, T_FILE, 0, 0);
|
ip = create(path, T_FILE, 0, 0);
|
||||||
if(ip == 0){
|
if(ip == 0) {
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if((ip = namei(path)) == 0){
|
if((ip = namei(path)) == 0) {
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
if(ip->type == T_DIR && omode != O_RDONLY){
|
if(ip->type == T_DIR && omode != O_RDONLY) {
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
|
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)) {
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
|
if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0) {
|
||||||
if(f)
|
if(f)
|
||||||
fileclose(f);
|
fileclose(f);
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
|
@ -349,7 +349,7 @@ sys_open(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ip->type == T_DEVICE){
|
if(ip->type == T_DEVICE) {
|
||||||
f->type = FD_DEVICE;
|
f->type = FD_DEVICE;
|
||||||
f->major = ip->major;
|
f->major = ip->major;
|
||||||
} else {
|
} else {
|
||||||
|
@ -360,7 +360,7 @@ sys_open(void)
|
||||||
f->readable = !(omode & O_WRONLY);
|
f->readable = !(omode & O_WRONLY);
|
||||||
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
|
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
|
||||||
|
|
||||||
if((omode & O_TRUNC) && ip->type == T_FILE){
|
if((omode & O_TRUNC) && ip->type == T_FILE) {
|
||||||
itrunc(ip);
|
itrunc(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,11 +373,11 @@ sys_open(void)
|
||||||
u64
|
u64
|
||||||
sys_mkdir(void)
|
sys_mkdir(void)
|
||||||
{
|
{
|
||||||
char path[MAXPATH];
|
char path[MAXPATH];
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
if(argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
|
if(argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0) {
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -390,14 +390,13 @@ u64
|
||||||
sys_mknod(void)
|
sys_mknod(void)
|
||||||
{
|
{
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
char path[MAXPATH];
|
char path[MAXPATH];
|
||||||
int major, minor;
|
int major, minor;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
argint(1, &major);
|
argint(1, &major);
|
||||||
argint(2, &minor);
|
argint(2, &minor);
|
||||||
if((argstr(0, path, MAXPATH)) < 0 ||
|
if((argstr(0, path, MAXPATH)) < 0 || (ip = create(path, T_DEVICE, major, minor)) == 0) {
|
||||||
(ip = create(path, T_DEVICE, major, minor)) == 0){
|
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -409,17 +408,17 @@ sys_mknod(void)
|
||||||
u64
|
u64
|
||||||
sys_chdir(void)
|
sys_chdir(void)
|
||||||
{
|
{
|
||||||
char path[MAXPATH];
|
char path[MAXPATH];
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0){
|
if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0) {
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ilock(ip);
|
ilock(ip);
|
||||||
if(ip->type != T_DIR){
|
if(ip->type != T_DIR) {
|
||||||
iunlockput(ip);
|
iunlockput(ip);
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -435,22 +434,22 @@ u64
|
||||||
sys_exec(void)
|
sys_exec(void)
|
||||||
{
|
{
|
||||||
char path[MAXPATH], *argv[MAXARG];
|
char path[MAXPATH], *argv[MAXARG];
|
||||||
int i;
|
int i;
|
||||||
u64 uargv, uarg;
|
u64 uargv, uarg;
|
||||||
|
|
||||||
argaddr(1, &uargv);
|
argaddr(1, &uargv);
|
||||||
if(argstr(0, path, MAXPATH) < 0) {
|
if(argstr(0, path, MAXPATH) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memset(argv, 0, sizeof(argv));
|
memset(argv, 0, sizeof(argv));
|
||||||
for(i=0;; i++){
|
for(i = 0;; i++) {
|
||||||
if(i >= NELEM(argv)){
|
if(i >= NELEM(argv)) {
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
if(fetchaddr(uargv+sizeof(u64)*i, (u64*)&uarg) < 0){
|
if(fetchaddr(uargv + sizeof(u64) * i, (u64 *)&uarg) < 0) {
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
if(uarg == 0){
|
if(uarg == 0) {
|
||||||
argv[i] = 0;
|
argv[i] = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -468,7 +467,7 @@ sys_exec(void)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
|
for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
|
||||||
kfree(argv[i]);
|
kfree(argv[i]);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -477,24 +476,24 @@ sys_exec(void)
|
||||||
u64
|
u64
|
||||||
sys_pipe(void)
|
sys_pipe(void)
|
||||||
{
|
{
|
||||||
u64 fdarray; // user pointer to array of two integers
|
u64 fdarray; // user pointer to array of two integers
|
||||||
struct file *rf, *wf;
|
struct file *rf, *wf;
|
||||||
int fd0, fd1;
|
int fd0, fd1;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
argaddr(0, &fdarray);
|
argaddr(0, &fdarray);
|
||||||
if(pipealloc(&rf, &wf) < 0)
|
if(pipealloc(&rf, &wf) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
fd0 = -1;
|
fd0 = -1;
|
||||||
if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
|
if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) {
|
||||||
if(fd0 >= 0)
|
if(fd0 >= 0)
|
||||||
p->ofile[fd0] = 0;
|
p->ofile[fd0] = 0;
|
||||||
fileclose(rf);
|
fileclose(rf);
|
||||||
fileclose(wf);
|
fileclose(wf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 ||
|
if(copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(fd0)) < 0
|
||||||
copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){
|
|| copyout(p->pagetable, fdarray + sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0) {
|
||||||
p->ofile[fd0] = 0;
|
p->ofile[fd0] = 0;
|
||||||
p->ofile[fd1] = 0;
|
p->ofile[fd1] = 0;
|
||||||
fileclose(rf);
|
fileclose(rf);
|
||||||
|
|
|
@ -12,7 +12,7 @@ sys_exit(void)
|
||||||
int n;
|
int n;
|
||||||
argint(0, &n);
|
argint(0, &n);
|
||||||
exit(n);
|
exit(n);
|
||||||
return 0; // not reached
|
return 0; // not reached
|
||||||
}
|
}
|
||||||
|
|
||||||
u64
|
u64
|
||||||
|
@ -57,8 +57,8 @@ sys_sleep(void)
|
||||||
argint(0, &n);
|
argint(0, &n);
|
||||||
acquire(&tickslock);
|
acquire(&tickslock);
|
||||||
ticks0 = ticks;
|
ticks0 = ticks;
|
||||||
while(ticks - ticks0 < n){
|
while(ticks - ticks0 < n) {
|
||||||
if(killed(myproc())){
|
if(killed(myproc())) {
|
||||||
release(&tickslock);
|
release(&tickslock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
struct spinlock tickslock;
|
struct spinlock tickslock;
|
||||||
u32 ticks;
|
u32 ticks;
|
||||||
|
|
||||||
extern char trampoline[], uservec[], userret[];
|
extern char trampoline[], uservec[], userret[];
|
||||||
|
|
||||||
|
@ -46,11 +46,11 @@ usertrap(void)
|
||||||
w_stvec((u64)kernelvec);
|
w_stvec((u64)kernelvec);
|
||||||
|
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
// save user program counter.
|
// save user program counter.
|
||||||
p->trapframe->epc = r_sepc();
|
p->trapframe->epc = r_sepc();
|
||||||
|
|
||||||
if(r_scause() == 8){
|
if(r_scause() == 8) {
|
||||||
// system call
|
// system call
|
||||||
|
|
||||||
if(killed(p))
|
if(killed(p))
|
||||||
|
@ -65,7 +65,7 @@ usertrap(void)
|
||||||
intr_on();
|
intr_on();
|
||||||
|
|
||||||
syscall();
|
syscall();
|
||||||
} else if((which_dev = devintr()) != 0){
|
} else if((which_dev = devintr()) != 0) {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
|
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
|
||||||
|
@ -105,11 +105,11 @@ usertrapret(void)
|
||||||
p->trapframe->kernel_satp = r_satp(); // kernel page table
|
p->trapframe->kernel_satp = r_satp(); // kernel page table
|
||||||
p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack
|
p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack
|
||||||
p->trapframe->kernel_trap = (u64)usertrap;
|
p->trapframe->kernel_trap = (u64)usertrap;
|
||||||
p->trapframe->kernel_hartid = r_tp(); // hartid for cpuid()
|
p->trapframe->kernel_hartid = r_tp(); // hartid for cpuid()
|
||||||
|
|
||||||
// set up the registers that trampoline.S's sret will use
|
// set up the registers that trampoline.S's sret will use
|
||||||
// to get to user space.
|
// to get to user space.
|
||||||
|
|
||||||
// set S Previous Privilege mode to User.
|
// set S Previous Privilege mode to User.
|
||||||
unsigned long x = r_sstatus();
|
unsigned long x = r_sstatus();
|
||||||
x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
|
x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode
|
||||||
|
@ -122,7 +122,7 @@ usertrapret(void)
|
||||||
// tell trampoline.S the user page table to switch to.
|
// tell trampoline.S the user page table to switch to.
|
||||||
u64 satp = MAKE_SATP(p->pagetable);
|
u64 satp = MAKE_SATP(p->pagetable);
|
||||||
|
|
||||||
// jump to userret in trampoline.S at the top of memory, which
|
// jump to userret in trampoline.S at the top of memory, which
|
||||||
// switches to the user page table, restores user registers,
|
// switches to the user page table, restores user registers,
|
||||||
// and switches to user mode with sret.
|
// and switches to user mode with sret.
|
||||||
u64 trampoline_userret = TRAMPOLINE + (userret - trampoline);
|
u64 trampoline_userret = TRAMPOLINE + (userret - trampoline);
|
||||||
|
@ -131,20 +131,20 @@ usertrapret(void)
|
||||||
|
|
||||||
// interrupts and exceptions from kernel code go here via kernelvec,
|
// interrupts and exceptions from kernel code go here via kernelvec,
|
||||||
// on whatever the current kernel stack is.
|
// on whatever the current kernel stack is.
|
||||||
void
|
void
|
||||||
kerneltrap()
|
kerneltrap()
|
||||||
{
|
{
|
||||||
int which_dev = 0;
|
int which_dev = 0;
|
||||||
u64 sepc = r_sepc();
|
u64 sepc = r_sepc();
|
||||||
u64 sstatus = r_sstatus();
|
u64 sstatus = r_sstatus();
|
||||||
u64 scause = r_scause();
|
u64 scause = r_scause();
|
||||||
|
|
||||||
if((sstatus & SSTATUS_SPP) == 0)
|
if((sstatus & SSTATUS_SPP) == 0)
|
||||||
panic("kerneltrap: not from supervisor mode");
|
panic("kerneltrap: not from supervisor mode");
|
||||||
if(intr_get() != 0)
|
if(intr_get() != 0)
|
||||||
panic("kerneltrap: interrupts enabled");
|
panic("kerneltrap: interrupts enabled");
|
||||||
|
|
||||||
if((which_dev = devintr()) == 0){
|
if((which_dev = devintr()) == 0) {
|
||||||
printf("scause %p\n", scause);
|
printf("scause %p\n", scause);
|
||||||
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
|
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
|
||||||
panic("kerneltrap");
|
panic("kerneltrap");
|
||||||
|
@ -179,18 +179,17 @@ devintr()
|
||||||
{
|
{
|
||||||
u64 scause = r_scause();
|
u64 scause = r_scause();
|
||||||
|
|
||||||
if((scause & 0x8000000000000000L) &&
|
if((scause & 0x8000000000000000L) && (scause & 0xff) == 9) {
|
||||||
(scause & 0xff) == 9){
|
|
||||||
// this is a supervisor external interrupt, via PLIC.
|
// this is a supervisor external interrupt, via PLIC.
|
||||||
|
|
||||||
// irq indicates which device interrupted.
|
// irq indicates which device interrupted.
|
||||||
int irq = plic_claim();
|
int irq = plic_claim();
|
||||||
|
|
||||||
if(irq == UART0_IRQ){
|
if(irq == UART0_IRQ) {
|
||||||
uartintr();
|
uartintr();
|
||||||
} else if(irq == VIRTIO0_IRQ){
|
} else if(irq == VIRTIO0_IRQ) {
|
||||||
virtio_disk_intr();
|
virtio_disk_intr();
|
||||||
} else if(irq){
|
} else if(irq) {
|
||||||
printf("unexpected interrupt irq=%d\n", irq);
|
printf("unexpected interrupt irq=%d\n", irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,14 +200,14 @@ devintr()
|
||||||
plic_complete(irq);
|
plic_complete(irq);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
} else if(scause == 0x8000000000000001L){
|
} else if(scause == 0x8000000000000001L) {
|
||||||
// software interrupt from a machine-mode timer interrupt,
|
// software interrupt from a machine-mode timer interrupt,
|
||||||
// forwarded by timervec in kernelvec.S.
|
// forwarded by timervec in kernelvec.S.
|
||||||
|
|
||||||
if(cpuid() == 0){
|
if(cpuid() == 0) {
|
||||||
clockintr();
|
clockintr();
|
||||||
}
|
}
|
||||||
|
|
||||||
// acknowledge the software interrupt by clearing
|
// acknowledge the software interrupt by clearing
|
||||||
// the SSIP bit in sip.
|
// the SSIP bit in sip.
|
||||||
w_sip(r_sip() & ~2);
|
w_sip(r_sip() & ~2);
|
||||||
|
@ -218,4 +217,3 @@ devintr()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
typedef unsigned char u8;
|
typedef unsigned char u8;
|
||||||
typedef unsigned short u16;
|
typedef unsigned short u16;
|
||||||
typedef unsigned int u32;
|
typedef unsigned int u32;
|
||||||
typedef unsigned long u64;
|
typedef unsigned long u64;
|
||||||
|
|
||||||
typedef u64 pde_t;
|
typedef u64 pde_t;
|
||||||
|
|
|
@ -19,31 +19,31 @@
|
||||||
// some have different meanings for
|
// some have different meanings for
|
||||||
// read vs write.
|
// read vs write.
|
||||||
// see http://byterunner.com/16550.html
|
// see http://byterunner.com/16550.html
|
||||||
#define RHR 0 // receive holding register (for input bytes)
|
#define RHR 0 // receive holding register (for input bytes)
|
||||||
#define THR 0 // transmit holding register (for output bytes)
|
#define THR 0 // transmit holding register (for output bytes)
|
||||||
#define IER 1 // interrupt enable register
|
#define IER 1 // interrupt enable register
|
||||||
#define IER_RX_ENABLE (1<<0)
|
#define IER_RX_ENABLE (1 << 0)
|
||||||
#define IER_TX_ENABLE (1<<1)
|
#define IER_TX_ENABLE (1 << 1)
|
||||||
#define FCR 2 // FIFO control register
|
#define FCR 2 // FIFO control register
|
||||||
#define FCR_FIFO_ENABLE (1<<0)
|
#define FCR_FIFO_ENABLE (1 << 0)
|
||||||
#define FCR_FIFO_CLEAR (3<<1) // clear the content of the two FIFOs
|
#define FCR_FIFO_CLEAR (3 << 1) // clear the content of the two FIFOs
|
||||||
#define ISR 2 // interrupt status register
|
#define ISR 2 // interrupt status register
|
||||||
#define LCR 3 // line control register
|
#define LCR 3 // line control register
|
||||||
#define LCR_EIGHT_BITS (3<<0)
|
#define LCR_EIGHT_BITS (3 << 0)
|
||||||
#define LCR_BAUD_LATCH (1<<7) // special mode to set baud rate
|
#define LCR_BAUD_LATCH (1 << 7) // special mode to set baud rate
|
||||||
#define LSR 5 // line status register
|
#define LSR 5 // line status register
|
||||||
#define LSR_RX_READY (1<<0) // input is waiting to be read from RHR
|
#define LSR_RX_READY (1 << 0) // input is waiting to be read from RHR
|
||||||
#define LSR_TX_IDLE (1<<5) // THR can accept another character to send
|
#define LSR_TX_IDLE (1 << 5) // THR can accept another character to send
|
||||||
|
|
||||||
#define ReadReg(reg) (*(Reg(reg)))
|
#define ReadReg(reg) (*(Reg(reg)))
|
||||||
#define WriteReg(reg, v) (*(Reg(reg)) = (v))
|
#define WriteReg(reg, v) (*(Reg(reg)) = (v))
|
||||||
|
|
||||||
// the transmit output buffer.
|
// the transmit output buffer.
|
||||||
struct spinlock uart_tx_lock;
|
struct spinlock uart_tx_lock;
|
||||||
#define UART_TX_BUF_SIZE 32
|
#define UART_TX_BUF_SIZE 32
|
||||||
char uart_tx_buf[UART_TX_BUF_SIZE];
|
char uart_tx_buf[UART_TX_BUF_SIZE];
|
||||||
u64 uart_tx_w; // write next to uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE]
|
u64 uart_tx_w; // write next to uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE]
|
||||||
u64 uart_tx_r; // read next from uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE]
|
u64 uart_tx_r; // read next from uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE]
|
||||||
|
|
||||||
extern volatile int panicked; // from printf.c
|
extern volatile int panicked; // from printf.c
|
||||||
|
|
||||||
|
@ -88,11 +88,11 @@ uartputc(int c)
|
||||||
{
|
{
|
||||||
acquire(&uart_tx_lock);
|
acquire(&uart_tx_lock);
|
||||||
|
|
||||||
if(panicked){
|
if(panicked) {
|
||||||
for(;;)
|
for(;;)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
while(uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE){
|
while(uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE) {
|
||||||
// buffer is full.
|
// buffer is full.
|
||||||
// wait for uartstart() to open up space in the buffer.
|
// wait for uartstart() to open up space in the buffer.
|
||||||
sleep(&uart_tx_r, &uart_tx_lock);
|
sleep(&uart_tx_r, &uart_tx_lock);
|
||||||
|
@ -103,8 +103,7 @@ uartputc(int c)
|
||||||
release(&uart_tx_lock);
|
release(&uart_tx_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// alternate version of uartputc() that doesn't
|
||||||
// alternate version of uartputc() that doesn't
|
|
||||||
// use interrupts, for use by kernel printf() and
|
// use interrupts, for use by kernel printf() and
|
||||||
// to echo characters. it spins waiting for the uart's
|
// to echo characters. it spins waiting for the uart's
|
||||||
// output register to be empty.
|
// output register to be empty.
|
||||||
|
@ -113,7 +112,7 @@ uartputc_sync(int c)
|
||||||
{
|
{
|
||||||
push_off();
|
push_off();
|
||||||
|
|
||||||
if(panicked){
|
if(panicked) {
|
||||||
for(;;)
|
for(;;)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -133,25 +132,25 @@ uartputc_sync(int c)
|
||||||
void
|
void
|
||||||
uartstart()
|
uartstart()
|
||||||
{
|
{
|
||||||
while(1){
|
while(1) {
|
||||||
if(uart_tx_w == uart_tx_r){
|
if(uart_tx_w == uart_tx_r) {
|
||||||
// transmit buffer is empty.
|
// transmit buffer is empty.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((ReadReg(LSR) & LSR_TX_IDLE) == 0){
|
if((ReadReg(LSR) & LSR_TX_IDLE) == 0) {
|
||||||
// the UART transmit holding register is full,
|
// the UART transmit holding register is full,
|
||||||
// so we cannot give it another byte.
|
// so we cannot give it another byte.
|
||||||
// it will interrupt when it's ready for a new byte.
|
// it will interrupt when it's ready for a new byte.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int c = uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE];
|
int c = uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE];
|
||||||
uart_tx_r += 1;
|
uart_tx_r += 1;
|
||||||
|
|
||||||
// maybe uartputc() is waiting for space in the buffer.
|
// maybe uartputc() is waiting for space in the buffer.
|
||||||
wakeup(&uart_tx_r);
|
wakeup(&uart_tx_r);
|
||||||
|
|
||||||
WriteReg(THR, c);
|
WriteReg(THR, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +160,7 @@ uartstart()
|
||||||
int
|
int
|
||||||
uartgetc(void)
|
uartgetc(void)
|
||||||
{
|
{
|
||||||
if(ReadReg(LSR) & 0x01){
|
if(ReadReg(LSR) & 0x01) {
|
||||||
// input data is ready.
|
// input data is ready.
|
||||||
return ReadReg(RHR);
|
return ReadReg(RHR);
|
||||||
} else {
|
} else {
|
||||||
|
@ -176,7 +175,7 @@ void
|
||||||
uartintr(void)
|
uartintr(void)
|
||||||
{
|
{
|
||||||
// read and process incoming characters.
|
// read and process incoming characters.
|
||||||
while(1){
|
while(1) {
|
||||||
int c = uartgetc();
|
int c = uartgetc();
|
||||||
if(c == -1)
|
if(c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -9,38 +9,38 @@
|
||||||
|
|
||||||
// virtio mmio control registers, mapped starting at 0x10001000.
|
// virtio mmio control registers, mapped starting at 0x10001000.
|
||||||
// from qemu virtio_mmio.h
|
// from qemu virtio_mmio.h
|
||||||
#define VIRTIO_MMIO_MAGIC_VALUE 0x000 // 0x74726976
|
#define VIRTIO_MMIO_MAGIC_VALUE 0x000 // 0x74726976
|
||||||
#define VIRTIO_MMIO_VERSION 0x004 // version; should be 2
|
#define VIRTIO_MMIO_VERSION 0x004 // version; should be 2
|
||||||
#define VIRTIO_MMIO_DEVICE_ID 0x008 // device type; 1 is net, 2 is disk
|
#define VIRTIO_MMIO_DEVICE_ID 0x008 // device type; 1 is net, 2 is disk
|
||||||
#define VIRTIO_MMIO_VENDOR_ID 0x00c // 0x554d4551
|
#define VIRTIO_MMIO_VENDOR_ID 0x00c // 0x554d4551
|
||||||
#define VIRTIO_MMIO_DEVICE_FEATURES 0x010
|
#define VIRTIO_MMIO_DEVICE_FEATURES 0x010
|
||||||
#define VIRTIO_MMIO_DRIVER_FEATURES 0x020
|
#define VIRTIO_MMIO_DRIVER_FEATURES 0x020
|
||||||
#define VIRTIO_MMIO_QUEUE_SEL 0x030 // select queue, write-only
|
#define VIRTIO_MMIO_QUEUE_SEL 0x030 // select queue, write-only
|
||||||
#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 // max size of current queue, read-only
|
#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 // max size of current queue, read-only
|
||||||
#define VIRTIO_MMIO_QUEUE_NUM 0x038 // size of current queue, write-only
|
#define VIRTIO_MMIO_QUEUE_NUM 0x038 // size of current queue, write-only
|
||||||
#define VIRTIO_MMIO_QUEUE_READY 0x044 // ready bit
|
#define VIRTIO_MMIO_QUEUE_READY 0x044 // ready bit
|
||||||
#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 // write-only
|
#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 // write-only
|
||||||
#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 // read-only
|
#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 // read-only
|
||||||
#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 // write-only
|
#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 // write-only
|
||||||
#define VIRTIO_MMIO_STATUS 0x070 // read/write
|
#define VIRTIO_MMIO_STATUS 0x070 // read/write
|
||||||
#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 // physical address for descriptor table, write-only
|
#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 // physical address for descriptor table, write-only
|
||||||
#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084
|
#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084
|
||||||
#define VIRTIO_MMIO_DRIVER_DESC_LOW 0x090 // physical address for available ring, write-only
|
#define VIRTIO_MMIO_DRIVER_DESC_LOW 0x090 // physical address for available ring, write-only
|
||||||
#define VIRTIO_MMIO_DRIVER_DESC_HIGH 0x094
|
#define VIRTIO_MMIO_DRIVER_DESC_HIGH 0x094
|
||||||
#define VIRTIO_MMIO_DEVICE_DESC_LOW 0x0a0 // physical address for used ring, write-only
|
#define VIRTIO_MMIO_DEVICE_DESC_LOW 0x0a0 // physical address for used ring, write-only
|
||||||
#define VIRTIO_MMIO_DEVICE_DESC_HIGH 0x0a4
|
#define VIRTIO_MMIO_DEVICE_DESC_HIGH 0x0a4
|
||||||
|
|
||||||
// status register bits, from qemu virtio_config.h
|
// status register bits, from qemu virtio_config.h
|
||||||
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
|
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
|
||||||
#define VIRTIO_CONFIG_S_DRIVER 2
|
#define VIRTIO_CONFIG_S_DRIVER 2
|
||||||
#define VIRTIO_CONFIG_S_DRIVER_OK 4
|
#define VIRTIO_CONFIG_S_DRIVER_OK 4
|
||||||
#define VIRTIO_CONFIG_S_FEATURES_OK 8
|
#define VIRTIO_CONFIG_S_FEATURES_OK 8
|
||||||
|
|
||||||
// device feature bits
|
// device feature bits
|
||||||
#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
|
#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
|
||||||
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
|
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
|
||||||
#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
|
#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
|
||||||
#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */
|
#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */
|
||||||
#define VIRTIO_F_ANY_LAYOUT 27
|
#define VIRTIO_F_ANY_LAYOUT 27
|
||||||
#define VIRTIO_RING_F_INDIRECT_DESC 28
|
#define VIRTIO_RING_F_INDIRECT_DESC 28
|
||||||
#define VIRTIO_RING_F_EVENT_IDX 29
|
#define VIRTIO_RING_F_EVENT_IDX 29
|
||||||
|
@ -61,8 +61,8 @@ struct virtq_desc {
|
||||||
|
|
||||||
// the (entire) avail ring, from the spec.
|
// the (entire) avail ring, from the spec.
|
||||||
struct virtq_avail {
|
struct virtq_avail {
|
||||||
u16 flags; // always zero
|
u16 flags; // always zero
|
||||||
u16 idx; // driver will write ring[idx] next
|
u16 idx; // driver will write ring[idx] next
|
||||||
u16 ring[NUM]; // descriptor numbers of chain heads
|
u16 ring[NUM]; // descriptor numbers of chain heads
|
||||||
u16 unused;
|
u16 unused;
|
||||||
};
|
};
|
||||||
|
@ -70,13 +70,13 @@ struct virtq_avail {
|
||||||
// one entry in the "used" ring, with which the
|
// one entry in the "used" ring, with which the
|
||||||
// device tells the driver about completed requests.
|
// device tells the driver about completed requests.
|
||||||
struct virtq_used_elem {
|
struct virtq_used_elem {
|
||||||
u32 id; // index of start of completed descriptor chain
|
u32 id; // index of start of completed descriptor chain
|
||||||
u32 len;
|
u32 len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct virtq_used {
|
struct virtq_used {
|
||||||
u16 flags; // always zero
|
u16 flags; // always zero
|
||||||
u16 idx; // device increments when it adds a ring[] entry
|
u16 idx; // device increments when it adds a ring[] entry
|
||||||
struct virtq_used_elem ring[NUM];
|
struct virtq_used_elem ring[NUM];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,23 +39,23 @@ static struct disk {
|
||||||
struct virtq_used *used;
|
struct virtq_used *used;
|
||||||
|
|
||||||
// our own book-keeping.
|
// our own book-keeping.
|
||||||
char free[NUM]; // is a descriptor free?
|
char free[NUM]; // is a descriptor free?
|
||||||
u16 used_idx; // we've looked this far in used[2..NUM].
|
u16 used_idx; // we've looked this far in used[2..NUM].
|
||||||
|
|
||||||
// track info about in-flight operations,
|
// track info about in-flight operations,
|
||||||
// for use when completion interrupt arrives.
|
// for use when completion interrupt arrives.
|
||||||
// indexed by first descriptor index of chain.
|
// indexed by first descriptor index of chain.
|
||||||
struct {
|
struct {
|
||||||
struct buf *b;
|
struct buf *b;
|
||||||
char status;
|
char status;
|
||||||
} info[NUM];
|
} info[NUM];
|
||||||
|
|
||||||
// disk command headers.
|
// disk command headers.
|
||||||
// one-for-one with descriptors, for convenience.
|
// one-for-one with descriptors, for convenience.
|
||||||
struct virtio_blk_req ops[NUM];
|
struct virtio_blk_req ops[NUM];
|
||||||
|
|
||||||
struct spinlock vdisk_lock;
|
struct spinlock vdisk_lock;
|
||||||
|
|
||||||
} disk;
|
} disk;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -65,13 +65,11 @@ virtio_disk_init(void)
|
||||||
|
|
||||||
initlock(&disk.vdisk_lock, "virtio_disk");
|
initlock(&disk.vdisk_lock, "virtio_disk");
|
||||||
|
|
||||||
if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
|
if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 || *R(VIRTIO_MMIO_VERSION) != 2 || *R(VIRTIO_MMIO_DEVICE_ID) != 2
|
||||||
*R(VIRTIO_MMIO_VERSION) != 2 ||
|
|| *R(VIRTIO_MMIO_VENDOR_ID) != 0x554d4551) {
|
||||||
*R(VIRTIO_MMIO_DEVICE_ID) != 2 ||
|
|
||||||
*R(VIRTIO_MMIO_VENDOR_ID) != 0x554d4551){
|
|
||||||
panic("could not find virtio disk");
|
panic("could not find virtio disk");
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset device
|
// reset device
|
||||||
*R(VIRTIO_MMIO_STATUS) = status;
|
*R(VIRTIO_MMIO_STATUS) = status;
|
||||||
|
|
||||||
|
@ -156,8 +154,8 @@ virtio_disk_init(void)
|
||||||
static int
|
static int
|
||||||
alloc_desc()
|
alloc_desc()
|
||||||
{
|
{
|
||||||
for(int i = 0; i < NUM; i++){
|
for(int i = 0; i < NUM; i++) {
|
||||||
if(disk.free[i]){
|
if(disk.free[i]) {
|
||||||
disk.free[i] = 0;
|
disk.free[i] = 0;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +183,7 @@ free_desc(int i)
|
||||||
static void
|
static void
|
||||||
free_chain(int i)
|
free_chain(int i)
|
||||||
{
|
{
|
||||||
while(1){
|
while(1) {
|
||||||
int flag = disk.desc[i].flags;
|
int flag = disk.desc[i].flags;
|
||||||
int nxt = disk.desc[i].next;
|
int nxt = disk.desc[i].next;
|
||||||
free_desc(i);
|
free_desc(i);
|
||||||
|
@ -201,9 +199,9 @@ free_chain(int i)
|
||||||
static int
|
static int
|
||||||
alloc3_desc(int *idx)
|
alloc3_desc(int *idx)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 3; i++){
|
for(int i = 0; i < 3; i++) {
|
||||||
idx[i] = alloc_desc();
|
idx[i] = alloc_desc();
|
||||||
if(idx[i] < 0){
|
if(idx[i] < 0) {
|
||||||
for(int j = 0; j < i; j++)
|
for(int j = 0; j < i; j++)
|
||||||
free_desc(idx[j]);
|
free_desc(idx[j]);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -225,7 +223,7 @@ virtio_disk_rw(struct buf *b, int write)
|
||||||
|
|
||||||
// allocate the three descriptors.
|
// allocate the three descriptors.
|
||||||
int idx[3];
|
int idx[3];
|
||||||
while(1){
|
while(1) {
|
||||||
if(alloc3_desc(idx) == 0) {
|
if(alloc3_desc(idx) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -244,12 +242,12 @@ virtio_disk_rw(struct buf *b, int write)
|
||||||
buf0->reserved = 0;
|
buf0->reserved = 0;
|
||||||
buf0->sector = sector;
|
buf0->sector = sector;
|
||||||
|
|
||||||
disk.desc[idx[0]].addr = (u64) buf0;
|
disk.desc[idx[0]].addr = (u64)buf0;
|
||||||
disk.desc[idx[0]].len = sizeof(struct virtio_blk_req);
|
disk.desc[idx[0]].len = sizeof(struct virtio_blk_req);
|
||||||
disk.desc[idx[0]].flags = VRING_DESC_F_NEXT;
|
disk.desc[idx[0]].flags = VRING_DESC_F_NEXT;
|
||||||
disk.desc[idx[0]].next = idx[1];
|
disk.desc[idx[0]].next = idx[1];
|
||||||
|
|
||||||
disk.desc[idx[1]].addr = (u64) b->data;
|
disk.desc[idx[1]].addr = (u64)b->data;
|
||||||
disk.desc[idx[1]].len = BSIZE;
|
disk.desc[idx[1]].len = BSIZE;
|
||||||
if(write)
|
if(write)
|
||||||
disk.desc[idx[1]].flags = 0; // device reads b->data
|
disk.desc[idx[1]].flags = 0; // device reads b->data
|
||||||
|
@ -259,7 +257,7 @@ virtio_disk_rw(struct buf *b, int write)
|
||||||
disk.desc[idx[1]].next = idx[2];
|
disk.desc[idx[1]].next = idx[2];
|
||||||
|
|
||||||
disk.info[idx[0]].status = 0xff; // device writes 0 on success
|
disk.info[idx[0]].status = 0xff; // device writes 0 on success
|
||||||
disk.desc[idx[2]].addr = (u64) &disk.info[idx[0]].status;
|
disk.desc[idx[2]].addr = (u64)&disk.info[idx[0]].status;
|
||||||
disk.desc[idx[2]].len = 1;
|
disk.desc[idx[2]].len = 1;
|
||||||
disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status
|
disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status
|
||||||
disk.desc[idx[2]].next = 0;
|
disk.desc[idx[2]].next = 0;
|
||||||
|
@ -309,7 +307,7 @@ virtio_disk_intr()
|
||||||
// the device increments disk.used->idx when it
|
// the device increments disk.used->idx when it
|
||||||
// adds an entry to the used ring.
|
// adds an entry to the used ring.
|
||||||
|
|
||||||
while(disk.used_idx != disk.used->idx){
|
while(disk.used_idx != disk.used->idx) {
|
||||||
__sync_synchronize();
|
__sync_synchronize();
|
||||||
int id = disk.used->ring[disk.used_idx % NUM].id;
|
int id = disk.used->ring[disk.used_idx % NUM].id;
|
||||||
|
|
||||||
|
@ -317,7 +315,7 @@ virtio_disk_intr()
|
||||||
panic("virtio_disk_intr status");
|
panic("virtio_disk_intr status");
|
||||||
|
|
||||||
struct buf *b = disk.info[id].b;
|
struct buf *b = disk.info[id].b;
|
||||||
b->disk = 0; // disk is done with buf
|
b->disk = 0; // disk is done with buf
|
||||||
wakeup(b);
|
wakeup(b);
|
||||||
|
|
||||||
disk.used_idx += 1;
|
disk.used_idx += 1;
|
||||||
|
|
82
kernel/vm.c
82
kernel/vm.c
|
@ -11,7 +11,7 @@
|
||||||
*/
|
*/
|
||||||
pagetable_t kernel_pagetable;
|
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
|
extern char trampoline[]; // trampoline.S
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ kvmmake(void)
|
||||||
{
|
{
|
||||||
pagetable_t kpgtbl;
|
pagetable_t kpgtbl;
|
||||||
|
|
||||||
kpgtbl = (pagetable_t) kalloc();
|
kpgtbl = (pagetable_t)kalloc();
|
||||||
memset(kpgtbl, 0, PGSIZE);
|
memset(kpgtbl, 0, PGSIZE);
|
||||||
|
|
||||||
// uart registers
|
// uart registers
|
||||||
|
@ -34,10 +34,10 @@ kvmmake(void)
|
||||||
kvmmap(kpgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W);
|
kvmmap(kpgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W);
|
||||||
|
|
||||||
// map kernel text executable and read-only.
|
// map kernel text executable and read-only.
|
||||||
kvmmap(kpgtbl, KERNBASE, KERNBASE, (u64)etext-KERNBASE, PTE_R | PTE_X);
|
kvmmap(kpgtbl, KERNBASE, KERNBASE, (u64)etext - KERNBASE, PTE_R | PTE_X);
|
||||||
|
|
||||||
// map kernel data and the physical RAM we'll make use of.
|
// map kernel data and the physical RAM we'll make use of.
|
||||||
kvmmap(kpgtbl, (u64)etext, (u64)etext, PHYSTOP-(u64)etext, PTE_R | PTE_W);
|
kvmmap(kpgtbl, (u64)etext, (u64)etext, PHYSTOP - (u64)etext, PTE_R | PTE_W);
|
||||||
|
|
||||||
// map the trampoline for trap entry/exit to
|
// map the trampoline for trap entry/exit to
|
||||||
// the highest virtual address in the kernel.
|
// the highest virtual address in the kernel.
|
||||||
|
@ -45,7 +45,7 @@ kvmmake(void)
|
||||||
|
|
||||||
// allocate and map a kernel stack for each process.
|
// allocate and map a kernel stack for each process.
|
||||||
proc_mapstacks(kpgtbl);
|
proc_mapstacks(kpgtbl);
|
||||||
|
|
||||||
return kpgtbl;
|
return kpgtbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ walk(pagetable_t pagetable, u64 va, int alloc)
|
||||||
if(*pte & PTE_V) {
|
if(*pte & PTE_V) {
|
||||||
pagetable = (pagetable_t)PTE2PA(*pte);
|
pagetable = (pagetable_t)PTE2PA(*pte);
|
||||||
} else {
|
} else {
|
||||||
if(!alloc || (pagetable = (pde_t*)kalloc()) == 0)
|
if(!alloc || (pagetable = (pde_t *)kalloc()) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
memset(pagetable, 0, PGSIZE);
|
memset(pagetable, 0, PGSIZE);
|
||||||
*pte = PA2PTE(pagetable) | PTE_V;
|
*pte = PA2PTE(pagetable) | PTE_V;
|
||||||
|
@ -109,7 +109,7 @@ u64
|
||||||
walkaddr(pagetable_t pagetable, u64 va)
|
walkaddr(pagetable_t pagetable, u64 va)
|
||||||
{
|
{
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
u64 pa;
|
u64 pa;
|
||||||
|
|
||||||
if(va >= MAXVA)
|
if(va >= MAXVA)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -142,15 +142,15 @@ kvmmap(pagetable_t kpgtbl, u64 va, u64 pa, u64 sz, int perm)
|
||||||
int
|
int
|
||||||
mappages(pagetable_t pagetable, u64 va, u64 size, u64 pa, int perm)
|
mappages(pagetable_t pagetable, u64 va, u64 size, u64 pa, int perm)
|
||||||
{
|
{
|
||||||
u64 a, last;
|
u64 a, last;
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
|
||||||
if(size == 0)
|
if(size == 0)
|
||||||
panic("mappages: size");
|
panic("mappages: size");
|
||||||
|
|
||||||
a = PGROUNDDOWN(va);
|
a = PGROUNDDOWN(va);
|
||||||
last = PGROUNDDOWN(va + size - 1);
|
last = PGROUNDDOWN(va + size - 1);
|
||||||
for(;;){
|
for(;;) {
|
||||||
if((pte = walk(pagetable, a, 1)) == 0)
|
if((pte = walk(pagetable, a, 1)) == 0)
|
||||||
return -1;
|
return -1;
|
||||||
if(*pte & PTE_V)
|
if(*pte & PTE_V)
|
||||||
|
@ -170,22 +170,22 @@ mappages(pagetable_t pagetable, u64 va, u64 size, u64 pa, int perm)
|
||||||
void
|
void
|
||||||
uvmunmap(pagetable_t pagetable, u64 va, u64 npages, int do_free)
|
uvmunmap(pagetable_t pagetable, u64 va, u64 npages, int do_free)
|
||||||
{
|
{
|
||||||
u64 a;
|
u64 a;
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
|
||||||
if((va % PGSIZE) != 0)
|
if((va % PGSIZE) != 0)
|
||||||
panic("uvmunmap: not aligned");
|
panic("uvmunmap: not aligned");
|
||||||
|
|
||||||
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
|
for(a = va; a < va + npages * PGSIZE; a += PGSIZE) {
|
||||||
if((pte = walk(pagetable, a, 0)) == 0)
|
if((pte = walk(pagetable, a, 0)) == 0)
|
||||||
panic("uvmunmap: walk");
|
panic("uvmunmap: walk");
|
||||||
if((*pte & PTE_V) == 0)
|
if((*pte & PTE_V) == 0)
|
||||||
panic("uvmunmap: not mapped");
|
panic("uvmunmap: not mapped");
|
||||||
if(PTE_FLAGS(*pte) == PTE_V)
|
if(PTE_FLAGS(*pte) == PTE_V)
|
||||||
panic("uvmunmap: not a leaf");
|
panic("uvmunmap: not a leaf");
|
||||||
if(do_free){
|
if(do_free) {
|
||||||
u64 pa = PTE2PA(*pte);
|
u64 pa = PTE2PA(*pte);
|
||||||
kfree((void*)pa);
|
kfree((void *)pa);
|
||||||
}
|
}
|
||||||
*pte = 0;
|
*pte = 0;
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ pagetable_t
|
||||||
uvmcreate()
|
uvmcreate()
|
||||||
{
|
{
|
||||||
pagetable_t pagetable;
|
pagetable_t pagetable;
|
||||||
pagetable = (pagetable_t) kalloc();
|
pagetable = (pagetable_t)kalloc();
|
||||||
if(pagetable == 0)
|
if(pagetable == 0)
|
||||||
return 0;
|
return 0;
|
||||||
memset(pagetable, 0, PGSIZE);
|
memset(pagetable, 0, PGSIZE);
|
||||||
|
@ -216,7 +216,7 @@ uvmfirst(pagetable_t pagetable, u8 *src, u32 sz)
|
||||||
panic("uvmfirst: more than a page");
|
panic("uvmfirst: more than a page");
|
||||||
mem = kalloc();
|
mem = kalloc();
|
||||||
memset(mem, 0, PGSIZE);
|
memset(mem, 0, PGSIZE);
|
||||||
mappages(pagetable, 0, PGSIZE, (u64)mem, PTE_W|PTE_R|PTE_X|PTE_U);
|
mappages(pagetable, 0, PGSIZE, (u64)mem, PTE_W | PTE_R | PTE_X | PTE_U);
|
||||||
memmove(mem, src, sz);
|
memmove(mem, src, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,20 +226,20 @@ u64
|
||||||
uvmalloc(pagetable_t pagetable, u64 oldsz, u64 newsz, int xperm)
|
uvmalloc(pagetable_t pagetable, u64 oldsz, u64 newsz, int xperm)
|
||||||
{
|
{
|
||||||
char *mem;
|
char *mem;
|
||||||
u64 a;
|
u64 a;
|
||||||
|
|
||||||
if(newsz < oldsz)
|
if(newsz < oldsz)
|
||||||
return oldsz;
|
return oldsz;
|
||||||
|
|
||||||
oldsz = PGROUNDUP(oldsz);
|
oldsz = PGROUNDUP(oldsz);
|
||||||
for(a = oldsz; a < newsz; a += PGSIZE){
|
for(a = oldsz; a < newsz; a += PGSIZE) {
|
||||||
mem = kalloc();
|
mem = kalloc();
|
||||||
if(mem == 0){
|
if(mem == 0) {
|
||||||
uvmdealloc(pagetable, a, oldsz);
|
uvmdealloc(pagetable, a, oldsz);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memset(mem, 0, PGSIZE);
|
memset(mem, 0, PGSIZE);
|
||||||
if(mappages(pagetable, a, PGSIZE, (u64)mem, PTE_R|PTE_U|xperm) != 0){
|
if(mappages(pagetable, a, PGSIZE, (u64)mem, PTE_R | PTE_U | xperm) != 0) {
|
||||||
kfree(mem);
|
kfree(mem);
|
||||||
uvmdealloc(pagetable, a, oldsz);
|
uvmdealloc(pagetable, a, oldsz);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -258,7 +258,7 @@ uvmdealloc(pagetable_t pagetable, u64 oldsz, u64 newsz)
|
||||||
if(newsz >= oldsz)
|
if(newsz >= oldsz)
|
||||||
return oldsz;
|
return oldsz;
|
||||||
|
|
||||||
if(PGROUNDUP(newsz) < PGROUNDUP(oldsz)){
|
if(PGROUNDUP(newsz) < PGROUNDUP(oldsz)) {
|
||||||
int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
|
int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE;
|
||||||
uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
|
uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1);
|
||||||
}
|
}
|
||||||
|
@ -272,18 +272,18 @@ void
|
||||||
freewalk(pagetable_t pagetable)
|
freewalk(pagetable_t pagetable)
|
||||||
{
|
{
|
||||||
// there are 2^9 = 512 PTEs in a page table.
|
// there are 2^9 = 512 PTEs in a page table.
|
||||||
for(int i = 0; i < 512; i++){
|
for(int i = 0; i < 512; i++) {
|
||||||
pte_t pte = pagetable[i];
|
pte_t pte = pagetable[i];
|
||||||
if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){
|
if((pte & PTE_V) && (pte & (PTE_R | PTE_W | PTE_X)) == 0) {
|
||||||
// this PTE points to a lower-level page table.
|
// this PTE points to a lower-level page table.
|
||||||
u64 child = PTE2PA(pte);
|
u64 child = PTE2PA(pte);
|
||||||
freewalk((pagetable_t)child);
|
freewalk((pagetable_t)child);
|
||||||
pagetable[i] = 0;
|
pagetable[i] = 0;
|
||||||
} else if(pte & PTE_V){
|
} else if(pte & PTE_V) {
|
||||||
panic("freewalk: leaf");
|
panic("freewalk: leaf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kfree((void*)pagetable);
|
kfree((void *)pagetable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free user memory pages,
|
// Free user memory pages,
|
||||||
|
@ -292,7 +292,7 @@ void
|
||||||
uvmfree(pagetable_t pagetable, u64 sz)
|
uvmfree(pagetable_t pagetable, u64 sz)
|
||||||
{
|
{
|
||||||
if(sz > 0)
|
if(sz > 0)
|
||||||
uvmunmap(pagetable, 0, PGROUNDUP(sz)/PGSIZE, 1);
|
uvmunmap(pagetable, 0, PGROUNDUP(sz) / PGSIZE, 1);
|
||||||
freewalk(pagetable);
|
freewalk(pagetable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,11 +306,11 @@ int
|
||||||
uvmcopy(pagetable_t old, pagetable_t new, u64 sz)
|
uvmcopy(pagetable_t old, pagetable_t new, u64 sz)
|
||||||
{
|
{
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
u64 pa, i;
|
u64 pa, i;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
char *mem;
|
char *mem;
|
||||||
|
|
||||||
for(i = 0; i < sz; i += PGSIZE){
|
for(i = 0; i < sz; i += PGSIZE) {
|
||||||
if((pte = walk(old, i, 0)) == 0)
|
if((pte = walk(old, i, 0)) == 0)
|
||||||
panic("uvmcopy: pte should exist");
|
panic("uvmcopy: pte should exist");
|
||||||
if((*pte & PTE_V) == 0)
|
if((*pte & PTE_V) == 0)
|
||||||
|
@ -319,15 +319,15 @@ uvmcopy(pagetable_t old, pagetable_t new, u64 sz)
|
||||||
flags = PTE_FLAGS(*pte);
|
flags = PTE_FLAGS(*pte);
|
||||||
if((mem = kalloc()) == 0)
|
if((mem = kalloc()) == 0)
|
||||||
goto err;
|
goto err;
|
||||||
memmove(mem, (char*)pa, PGSIZE);
|
memmove(mem, (char *)pa, PGSIZE);
|
||||||
if(mappages(new, i, PGSIZE, (u64)mem, flags) != 0){
|
if(mappages(new, i, PGSIZE, (u64)mem, flags) != 0) {
|
||||||
kfree(mem);
|
kfree(mem);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
uvmunmap(new, 0, i / PGSIZE, 1);
|
uvmunmap(new, 0, i / PGSIZE, 1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -338,7 +338,7 @@ void
|
||||||
uvmclear(pagetable_t pagetable, u64 va)
|
uvmclear(pagetable_t pagetable, u64 va)
|
||||||
{
|
{
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
|
||||||
pte = walk(pagetable, va, 0);
|
pte = walk(pagetable, va, 0);
|
||||||
if(pte == 0)
|
if(pte == 0)
|
||||||
panic("uvmclear");
|
panic("uvmclear");
|
||||||
|
@ -353,7 +353,7 @@ copyout(pagetable_t pagetable, u64 dstva, char *src, u64 len)
|
||||||
{
|
{
|
||||||
u64 n, va0, pa0;
|
u64 n, va0, pa0;
|
||||||
|
|
||||||
while(len > 0){
|
while(len > 0) {
|
||||||
va0 = PGROUNDDOWN(dstva);
|
va0 = PGROUNDDOWN(dstva);
|
||||||
pa0 = walkaddr(pagetable, va0);
|
pa0 = walkaddr(pagetable, va0);
|
||||||
if(pa0 == 0)
|
if(pa0 == 0)
|
||||||
|
@ -378,7 +378,7 @@ copyin(pagetable_t pagetable, char *dst, u64 srcva, u64 len)
|
||||||
{
|
{
|
||||||
u64 n, va0, pa0;
|
u64 n, va0, pa0;
|
||||||
|
|
||||||
while(len > 0){
|
while(len > 0) {
|
||||||
va0 = PGROUNDDOWN(srcva);
|
va0 = PGROUNDDOWN(srcva);
|
||||||
pa0 = walkaddr(pagetable, va0);
|
pa0 = walkaddr(pagetable, va0);
|
||||||
if(pa0 == 0)
|
if(pa0 == 0)
|
||||||
|
@ -405,7 +405,7 @@ copyinstr(pagetable_t pagetable, char *dst, u64 srcva, u64 max)
|
||||||
u64 n, va0, pa0;
|
u64 n, va0, pa0;
|
||||||
int got_null = 0;
|
int got_null = 0;
|
||||||
|
|
||||||
while(got_null == 0 && max > 0){
|
while(got_null == 0 && max > 0) {
|
||||||
va0 = PGROUNDDOWN(srcva);
|
va0 = PGROUNDDOWN(srcva);
|
||||||
pa0 = walkaddr(pagetable, va0);
|
pa0 = walkaddr(pagetable, va0);
|
||||||
if(pa0 == 0)
|
if(pa0 == 0)
|
||||||
|
@ -414,9 +414,9 @@ copyinstr(pagetable_t pagetable, char *dst, u64 srcva, u64 max)
|
||||||
if(n > max)
|
if(n > max)
|
||||||
n = max;
|
n = max;
|
||||||
|
|
||||||
char *p = (char *) (pa0 + (srcva - va0));
|
char *p = (char *)(pa0 + (srcva - va0));
|
||||||
while(n > 0){
|
while(n > 0) {
|
||||||
if(*p == '\0'){
|
if(*p == '\0') {
|
||||||
*dst = '\0';
|
*dst = '\0';
|
||||||
got_null = 1;
|
got_null = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -431,7 +431,7 @@ copyinstr(pagetable_t pagetable, char *dst, u64 srcva, u64 max)
|
||||||
|
|
||||||
srcva = va0 + PGSIZE;
|
srcva = va0 + PGSIZE;
|
||||||
}
|
}
|
||||||
if(got_null){
|
if(got_null) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
107
mkfs/mkfs.c
107
mkfs/mkfs.c
|
@ -5,14 +5,19 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <assert.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/types.h"
|
||||||
#include "kernel/fs.h"
|
#include "kernel/fs.h"
|
||||||
#include "kernel/stat.h"
|
#include "kernel/stat.h"
|
||||||
#include "kernel/param.h"
|
#include "kernel/param.h"
|
||||||
|
|
||||||
#ifndef static_assert
|
#ifndef static_assert
|
||||||
#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
|
#define static_assert(a, b) \
|
||||||
|
do { \
|
||||||
|
switch(0) \
|
||||||
|
case 0: \
|
||||||
|
case(a):; \
|
||||||
|
} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NINODES 200
|
#define NINODES 200
|
||||||
|
@ -20,22 +25,21 @@
|
||||||
// Disk layout:
|
// Disk layout:
|
||||||
// [ boot block | sb block | log | inode blocks | free bit map | data blocks ]
|
// [ boot block | sb block | log | inode blocks | free bit map | data blocks ]
|
||||||
|
|
||||||
int nbitmap = FSSIZE/(BSIZE*8) + 1;
|
int nbitmap = FSSIZE / (BSIZE * 8) + 1;
|
||||||
int ninodeblocks = NINODES / IPB + 1;
|
int ninodeblocks = NINODES / IPB + 1;
|
||||||
int nlog = LOGSIZE;
|
int nlog = LOGSIZE;
|
||||||
int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)
|
int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)
|
||||||
int nblocks; // Number of data blocks
|
int nblocks; // Number of data blocks
|
||||||
|
|
||||||
int fsfd;
|
int fsfd;
|
||||||
struct superblock sb;
|
struct superblock sb;
|
||||||
char zeroes[BSIZE];
|
char zeroes[BSIZE];
|
||||||
uint freeinode = 1;
|
uint freeinode = 1;
|
||||||
uint freeblock;
|
uint freeblock;
|
||||||
|
|
||||||
|
|
||||||
void balloc(int);
|
void balloc(int);
|
||||||
void wsect(uint, void*);
|
void wsect(uint, void *);
|
||||||
void winode(uint, struct dinode*);
|
void winode(uint, struct dinode *);
|
||||||
void rinode(uint inum, struct dinode *ip);
|
void rinode(uint inum, struct dinode *ip);
|
||||||
void rsect(uint sec, void *buf);
|
void rsect(uint sec, void *buf);
|
||||||
uint ialloc(ushort type);
|
uint ialloc(ushort type);
|
||||||
|
@ -47,7 +51,7 @@ ushort
|
||||||
xshort(ushort x)
|
xshort(ushort x)
|
||||||
{
|
{
|
||||||
ushort y;
|
ushort y;
|
||||||
u8 *a = (u8*)&y;
|
u8 *a = (u8 *)&y;
|
||||||
a[0] = x;
|
a[0] = x;
|
||||||
a[1] = x >> 8;
|
a[1] = x >> 8;
|
||||||
return y;
|
return y;
|
||||||
|
@ -57,7 +61,7 @@ uint
|
||||||
xint(uint x)
|
xint(uint x)
|
||||||
{
|
{
|
||||||
uint y;
|
uint y;
|
||||||
u8 *a = (u8*)&y;
|
u8 *a = (u8 *)&y;
|
||||||
a[0] = x;
|
a[0] = x;
|
||||||
a[1] = x >> 8;
|
a[1] = x >> 8;
|
||||||
a[2] = x >> 16;
|
a[2] = x >> 16;
|
||||||
|
@ -68,16 +72,15 @@ xint(uint x)
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i, cc, fd;
|
int i, cc, fd;
|
||||||
uint rootino, inum, off;
|
uint rootino, inum, off;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
char buf[BSIZE];
|
char buf[BSIZE];
|
||||||
struct dinode din;
|
struct dinode din;
|
||||||
|
|
||||||
|
|
||||||
static_assert(sizeof(int) == 4, "Integers must be 4 bytes!");
|
static_assert(sizeof(int) == 4, "Integers must be 4 bytes!");
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2) {
|
||||||
fprintf(stderr, "Usage: mkfs fs.img files...\n");
|
fprintf(stderr, "Usage: mkfs fs.img files...\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +88,7 @@ main(int argc, char *argv[])
|
||||||
assert((BSIZE % sizeof(struct dinode)) == 0);
|
assert((BSIZE % sizeof(struct dinode)) == 0);
|
||||||
assert((BSIZE % sizeof(struct dirent)) == 0);
|
assert((BSIZE % sizeof(struct dirent)) == 0);
|
||||||
|
|
||||||
fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
|
fsfd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||||
if(fsfd < 0)
|
if(fsfd < 0)
|
||||||
die(argv[1]);
|
die(argv[1]);
|
||||||
|
|
||||||
|
@ -99,13 +102,13 @@ main(int argc, char *argv[])
|
||||||
sb.ninodes = xint(NINODES);
|
sb.ninodes = xint(NINODES);
|
||||||
sb.nlog = xint(nlog);
|
sb.nlog = xint(nlog);
|
||||||
sb.logstart = xint(2);
|
sb.logstart = xint(2);
|
||||||
sb.inodestart = xint(2+nlog);
|
sb.inodestart = xint(2 + nlog);
|
||||||
sb.bmapstart = xint(2+nlog+ninodeblocks);
|
sb.bmapstart = xint(2 + nlog + ninodeblocks);
|
||||||
|
|
||||||
printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n",
|
printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n", nmeta, nlog,
|
||||||
nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);
|
ninodeblocks, nbitmap, nblocks, FSSIZE);
|
||||||
|
|
||||||
freeblock = nmeta; // the first free block that we can allocate
|
freeblock = nmeta; // the first free block that we can allocate
|
||||||
|
|
||||||
for(i = 0; i < FSSIZE; i++)
|
for(i = 0; i < FSSIZE; i++)
|
||||||
wsect(i, zeroes);
|
wsect(i, zeroes);
|
||||||
|
@ -127,14 +130,14 @@ main(int argc, char *argv[])
|
||||||
strcpy(de.name, "..");
|
strcpy(de.name, "..");
|
||||||
iappend(rootino, &de, sizeof(de));
|
iappend(rootino, &de, sizeof(de));
|
||||||
|
|
||||||
for(i = 2; i < argc; i++){
|
for(i = 2; i < argc; i++) {
|
||||||
// get rid of "user/"
|
// get rid of "user/"
|
||||||
char *shortname;
|
char *shortname;
|
||||||
if(strncmp(argv[i], "user/", 5) == 0)
|
if(strncmp(argv[i], "user/", 5) == 0)
|
||||||
shortname = argv[i] + 5;
|
shortname = argv[i] + 5;
|
||||||
else
|
else
|
||||||
shortname = argv[i];
|
shortname = argv[i];
|
||||||
|
|
||||||
assert(index(shortname, '/') == 0);
|
assert(index(shortname, '/') == 0);
|
||||||
|
|
||||||
if((fd = open(argv[i], 0)) < 0)
|
if((fd = open(argv[i], 0)) < 0)
|
||||||
|
@ -163,7 +166,7 @@ main(int argc, char *argv[])
|
||||||
// fix size of root inode dir
|
// fix size of root inode dir
|
||||||
rinode(rootino, &din);
|
rinode(rootino, &din);
|
||||||
off = xint(din.size);
|
off = xint(din.size);
|
||||||
off = ((off/BSIZE) + 1) * BSIZE;
|
off = ((off / BSIZE) + 1) * BSIZE;
|
||||||
din.size = xint(off);
|
din.size = xint(off);
|
||||||
winode(rootino, &din);
|
winode(rootino, &din);
|
||||||
|
|
||||||
|
@ -184,13 +187,13 @@ wsect(uint sec, void *buf)
|
||||||
void
|
void
|
||||||
winode(uint inum, struct dinode *ip)
|
winode(uint inum, struct dinode *ip)
|
||||||
{
|
{
|
||||||
char buf[BSIZE];
|
char buf[BSIZE];
|
||||||
uint bn;
|
uint bn;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
||||||
bn = IBLOCK(inum, sb);
|
bn = IBLOCK(inum, sb);
|
||||||
rsect(bn, buf);
|
rsect(bn, buf);
|
||||||
dip = ((struct dinode*)buf) + (inum % IPB);
|
dip = ((struct dinode *)buf) + (inum % IPB);
|
||||||
*dip = *ip;
|
*dip = *ip;
|
||||||
wsect(bn, buf);
|
wsect(bn, buf);
|
||||||
}
|
}
|
||||||
|
@ -198,13 +201,13 @@ winode(uint inum, struct dinode *ip)
|
||||||
void
|
void
|
||||||
rinode(uint inum, struct dinode *ip)
|
rinode(uint inum, struct dinode *ip)
|
||||||
{
|
{
|
||||||
char buf[BSIZE];
|
char buf[BSIZE];
|
||||||
uint bn;
|
uint bn;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
||||||
bn = IBLOCK(inum, sb);
|
bn = IBLOCK(inum, sb);
|
||||||
rsect(bn, buf);
|
rsect(bn, buf);
|
||||||
dip = ((struct dinode*)buf) + (inum % IPB);
|
dip = ((struct dinode *)buf) + (inum % IPB);
|
||||||
*ip = *dip;
|
*ip = *dip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +223,7 @@ rsect(uint sec, void *buf)
|
||||||
uint
|
uint
|
||||||
ialloc(ushort type)
|
ialloc(ushort type)
|
||||||
{
|
{
|
||||||
uint inum = freeinode++;
|
uint inum = freeinode++;
|
||||||
struct dinode din;
|
struct dinode din;
|
||||||
|
|
||||||
bzero(&din, sizeof(din));
|
bzero(&din, sizeof(din));
|
||||||
|
@ -234,14 +237,14 @@ ialloc(ushort type)
|
||||||
void
|
void
|
||||||
balloc(int used)
|
balloc(int used)
|
||||||
{
|
{
|
||||||
u8 buf[BSIZE];
|
u8 buf[BSIZE];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
printf("balloc: first %d blocks have been allocated\n", used);
|
printf("balloc: first %d blocks have been allocated\n", used);
|
||||||
assert(used < BSIZE*8);
|
assert(used < BSIZE * 8);
|
||||||
bzero(buf, BSIZE);
|
bzero(buf, BSIZE);
|
||||||
for(i = 0; i < used; i++){
|
for(i = 0; i < used; i++) {
|
||||||
buf[i/8] = buf[i/8] | (0x1 << (i%8));
|
buf[i / 8] = buf[i / 8] | (0x1 << (i % 8));
|
||||||
}
|
}
|
||||||
printf("balloc: write bitmap block at sector %d\n", sb.bmapstart);
|
printf("balloc: write bitmap block at sector %d\n", sb.bmapstart);
|
||||||
wsect(sb.bmapstart, buf);
|
wsect(sb.bmapstart, buf);
|
||||||
|
@ -252,34 +255,34 @@ balloc(int used)
|
||||||
void
|
void
|
||||||
iappend(uint inum, void *xp, int n)
|
iappend(uint inum, void *xp, int n)
|
||||||
{
|
{
|
||||||
char *p = (char*)xp;
|
char *p = (char *)xp;
|
||||||
uint fbn, off, n1;
|
uint fbn, off, n1;
|
||||||
struct dinode din;
|
struct dinode din;
|
||||||
char buf[BSIZE];
|
char buf[BSIZE];
|
||||||
uint indirect[NINDIRECT];
|
uint indirect[NINDIRECT];
|
||||||
uint x;
|
uint x;
|
||||||
|
|
||||||
rinode(inum, &din);
|
rinode(inum, &din);
|
||||||
off = xint(din.size);
|
off = xint(din.size);
|
||||||
// printf("append inum %d at off %d sz %d\n", inum, off, n);
|
// printf("append inum %d at off %d sz %d\n", inum, off, n);
|
||||||
while(n > 0){
|
while(n > 0) {
|
||||||
fbn = off / BSIZE;
|
fbn = off / BSIZE;
|
||||||
assert(fbn < MAXFILE);
|
assert(fbn < MAXFILE);
|
||||||
if(fbn < NDIRECT){
|
if(fbn < NDIRECT) {
|
||||||
if(xint(din.addrs[fbn]) == 0){
|
if(xint(din.addrs[fbn]) == 0) {
|
||||||
din.addrs[fbn] = xint(freeblock++);
|
din.addrs[fbn] = xint(freeblock++);
|
||||||
}
|
}
|
||||||
x = xint(din.addrs[fbn]);
|
x = xint(din.addrs[fbn]);
|
||||||
} else {
|
} else {
|
||||||
if(xint(din.addrs[NDIRECT]) == 0){
|
if(xint(din.addrs[NDIRECT]) == 0) {
|
||||||
din.addrs[NDIRECT] = xint(freeblock++);
|
din.addrs[NDIRECT] = xint(freeblock++);
|
||||||
}
|
}
|
||||||
rsect(xint(din.addrs[NDIRECT]), (char*)indirect);
|
rsect(xint(din.addrs[NDIRECT]), (char *)indirect);
|
||||||
if(indirect[fbn - NDIRECT] == 0){
|
if(indirect[fbn - NDIRECT] == 0) {
|
||||||
indirect[fbn - NDIRECT] = xint(freeblock++);
|
indirect[fbn - NDIRECT] = xint(freeblock++);
|
||||||
wsect(xint(din.addrs[NDIRECT]), (char*)indirect);
|
wsect(xint(din.addrs[NDIRECT]), (char *)indirect);
|
||||||
}
|
}
|
||||||
x = xint(indirect[fbn-NDIRECT]);
|
x = xint(indirect[fbn - NDIRECT]);
|
||||||
}
|
}
|
||||||
n1 = min(n, (fbn + 1) * BSIZE - off);
|
n1 = min(n, (fbn + 1) * BSIZE - off);
|
||||||
rsect(x, buf);
|
rsect(x, buf);
|
||||||
|
|
10
user/cat.c
10
user/cat.c
|
@ -10,12 +10,12 @@ cat(int fd)
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||||
if (write(1, buf, n) != n) {
|
if(write(1, buf, n) != n) {
|
||||||
fprintf(2, "cat: write error\n");
|
fprintf(2, "cat: write error\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(n < 0){
|
if(n < 0) {
|
||||||
fprintf(2, "cat: read error\n");
|
fprintf(2, "cat: read error\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,13 @@ main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int fd, i;
|
int fd, i;
|
||||||
|
|
||||||
if(argc <= 1){
|
if(argc <= 1) {
|
||||||
cat(0);
|
cat(0);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++) {
|
||||||
if((fd = open(argv[i], 0)) < 0){
|
if((fd = open(argv[i], 0)) < 0) {
|
||||||
fprintf(2, "cat: cannot open %s\n", argv[i]);
|
fprintf(2, "cat: cannot open %s\n", argv[i]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,9 @@ main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++) {
|
||||||
write(1, argv[i], strlen(argv[i]));
|
write(1, argv[i], strlen(argv[i]));
|
||||||
if(i + 1 < argc){
|
if(i + 1 < argc) {
|
||||||
write(1, " ", 1);
|
write(1, " ", 1);
|
||||||
} else {
|
} else {
|
||||||
write(1, "\n", 1);
|
write(1, "\n", 1);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "kernel/stat.h"
|
#include "kernel/stat.h"
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
|
|
||||||
#define N 1000
|
#define N 1000
|
||||||
|
|
||||||
void
|
void
|
||||||
print(const char *s)
|
print(const char *s)
|
||||||
|
@ -20,7 +20,7 @@ forktest(void)
|
||||||
|
|
||||||
print("fork test\n");
|
print("fork test\n");
|
||||||
|
|
||||||
for(n=0; n<N; n++){
|
for(n = 0; n < N; n++) {
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if(pid < 0)
|
if(pid < 0)
|
||||||
break;
|
break;
|
||||||
|
@ -28,19 +28,19 @@ forktest(void)
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(n == N){
|
if(n == N) {
|
||||||
print("fork claimed to work N times!\n");
|
print("fork claimed to work N times!\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(; n > 0; n--){
|
for(; n > 0; n--) {
|
||||||
if(wait(0) < 0){
|
if(wait(0) < 0) {
|
||||||
print("wait stopped early\n");
|
print("wait stopped early\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(wait(0) != -1){
|
if(wait(0) != -1) {
|
||||||
print("wait got too many\n");
|
print("wait got too many\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
53
user/grep.c
53
user/grep.c
|
@ -5,28 +5,28 @@
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
|
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int match(char*, char*);
|
int match(char *, char *);
|
||||||
|
|
||||||
void
|
void
|
||||||
grep(char *pattern, int fd)
|
grep(char *pattern, int fd)
|
||||||
{
|
{
|
||||||
int n, m;
|
int n, m;
|
||||||
char *p, *q;
|
char *p, *q;
|
||||||
|
|
||||||
m = 0;
|
m = 0;
|
||||||
while((n = read(fd, buf+m, sizeof(buf)-m-1)) > 0){
|
while((n = read(fd, buf + m, sizeof(buf) - m - 1)) > 0) {
|
||||||
m += n;
|
m += n;
|
||||||
buf[m] = '\0';
|
buf[m] = '\0';
|
||||||
p = buf;
|
p = buf;
|
||||||
while((q = strchr(p, '\n')) != 0){
|
while((q = strchr(p, '\n')) != 0) {
|
||||||
*q = 0;
|
*q = 0;
|
||||||
if(match(pattern, p)){
|
if(match(pattern, p)) {
|
||||||
*q = '\n';
|
*q = '\n';
|
||||||
write(1, p, q+1 - p);
|
write(1, p, q + 1 - p);
|
||||||
}
|
}
|
||||||
p = q+1;
|
p = q + 1;
|
||||||
}
|
}
|
||||||
if(m > 0){
|
if(m > 0) {
|
||||||
m -= p - buf;
|
m -= p - buf;
|
||||||
memmove(buf, p, m);
|
memmove(buf, p, m);
|
||||||
}
|
}
|
||||||
|
@ -36,22 +36,22 @@ grep(char *pattern, int fd)
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int fd, i;
|
int fd, i;
|
||||||
char *pattern;
|
char *pattern;
|
||||||
|
|
||||||
if(argc <= 1){
|
if(argc <= 1) {
|
||||||
fprintf(2, "usage: grep pattern [file ...]\n");
|
fprintf(2, "usage: grep pattern [file ...]\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
pattern = argv[1];
|
pattern = argv[1];
|
||||||
|
|
||||||
if(argc <= 2){
|
if(argc <= 2) {
|
||||||
grep(pattern, 0);
|
grep(pattern, 0);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 2; i < argc; i++){
|
for(i = 2; i < argc; i++) {
|
||||||
if((fd = open(argv[i], 0)) < 0){
|
if((fd = open(argv[i], 0)) < 0) {
|
||||||
printf("grep: cannot open %s\n", argv[i]);
|
printf("grep: cannot open %s\n", argv[i]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -65,42 +65,43 @@ main(int argc, char *argv[])
|
||||||
// The Practice of Programming, Chapter 9, or
|
// The Practice of Programming, Chapter 9, or
|
||||||
// https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
|
// https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
|
||||||
|
|
||||||
int matchhere(char*, char*);
|
int matchhere(char *, char *);
|
||||||
int matchstar(int, char*, char*);
|
int matchstar(int, char *, char *);
|
||||||
|
|
||||||
int
|
int
|
||||||
match(char *re, char *text)
|
match(char *re, char *text)
|
||||||
{
|
{
|
||||||
if(re[0] == '^')
|
if(re[0] == '^')
|
||||||
return matchhere(re+1, text);
|
return matchhere(re + 1, text);
|
||||||
do{ // must look at empty string
|
do { // must look at empty string
|
||||||
if(matchhere(re, text))
|
if(matchhere(re, text))
|
||||||
return 1;
|
return 1;
|
||||||
}while(*text++ != '\0');
|
} while(*text++ != '\0');
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchhere: search for re at beginning of text
|
// matchhere: search for re at beginning of text
|
||||||
int matchhere(char *re, char *text)
|
int
|
||||||
|
matchhere(char *re, char *text)
|
||||||
{
|
{
|
||||||
if(re[0] == '\0')
|
if(re[0] == '\0')
|
||||||
return 1;
|
return 1;
|
||||||
if(re[1] == '*')
|
if(re[1] == '*')
|
||||||
return matchstar(re[0], re+2, text);
|
return matchstar(re[0], re + 2, text);
|
||||||
if(re[0] == '$' && re[1] == '\0')
|
if(re[0] == '$' && re[1] == '\0')
|
||||||
return *text == '\0';
|
return *text == '\0';
|
||||||
if(*text!='\0' && (re[0]=='.' || re[0]==*text))
|
if(*text != '\0' && (re[0] == '.' || re[0] == *text))
|
||||||
return matchhere(re+1, text+1);
|
return matchhere(re + 1, text + 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchstar: search for c*re at beginning of text
|
// matchstar: search for c*re at beginning of text
|
||||||
int matchstar(int c, char *re, char *text)
|
int
|
||||||
|
matchstar(int c, char *re, char *text)
|
||||||
{
|
{
|
||||||
do{ // a * matches zero or more instances
|
do { // a * matches zero or more instances
|
||||||
if(matchhere(re, text))
|
if(matchhere(re, text))
|
||||||
return 1;
|
return 1;
|
||||||
}while(*text!='\0' && (*text++==c || c=='.'));
|
} while(*text != '\0' && (*text++ == c || c == '.'));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
202
user/grind.c
202
user/grind.c
|
@ -16,27 +16,27 @@
|
||||||
int
|
int
|
||||||
do_rand(unsigned long *ctx)
|
do_rand(unsigned long *ctx)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Compute x = (7^5 * x) mod (2^31 - 1)
|
* Compute x = (7^5 * x) mod (2^31 - 1)
|
||||||
* without overflowing 31 bits:
|
* without overflowing 31 bits:
|
||||||
* (2^31 - 1) = 127773 * (7^5) + 2836
|
* (2^31 - 1) = 127773 * (7^5) + 2836
|
||||||
* From "Random number generators: good ones are hard to find",
|
* From "Random number generators: good ones are hard to find",
|
||||||
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||||||
* October 1988, p. 1195.
|
* October 1988, p. 1195.
|
||||||
*/
|
*/
|
||||||
long hi, lo, x;
|
long hi, lo, x;
|
||||||
|
|
||||||
/* Transform to [1, 0x7ffffffe] range. */
|
/* Transform to [1, 0x7ffffffe] range. */
|
||||||
x = (*ctx % 0x7ffffffe) + 1;
|
x = (*ctx % 0x7ffffffe) + 1;
|
||||||
hi = x / 127773;
|
hi = x / 127773;
|
||||||
lo = x % 127773;
|
lo = x % 127773;
|
||||||
x = 16807 * lo - 2836 * hi;
|
x = 16807 * lo - 2836 * hi;
|
||||||
if (x < 0)
|
if(x < 0)
|
||||||
x += 0x7fffffff;
|
x += 0x7fffffff;
|
||||||
/* Transform to [0, 0x7ffffffd] range. */
|
/* Transform to [0, 0x7ffffffd] range. */
|
||||||
x--;
|
x--;
|
||||||
*ctx = x;
|
*ctx = x;
|
||||||
return (x);
|
return (x);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long rand_next = 1;
|
unsigned long rand_next = 1;
|
||||||
|
@ -44,124 +44,124 @@ unsigned long rand_next = 1;
|
||||||
int
|
int
|
||||||
rand(void)
|
rand(void)
|
||||||
{
|
{
|
||||||
return (do_rand(&rand_next));
|
return (do_rand(&rand_next));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
go(int which_child)
|
go(int which_child)
|
||||||
{
|
{
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
static char buf[999];
|
static char buf[999];
|
||||||
char *break0 = sbrk(0);
|
char *break0 = sbrk(0);
|
||||||
u64 iters = 0;
|
u64 iters = 0;
|
||||||
|
|
||||||
mkdir("grindir");
|
mkdir("grindir");
|
||||||
if(chdir("grindir") != 0){
|
if(chdir("grindir") != 0) {
|
||||||
printf("grind: chdir grindir failed\n");
|
printf("grind: chdir grindir failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
chdir("/");
|
chdir("/");
|
||||||
|
|
||||||
while(1){
|
while(1) {
|
||||||
iters++;
|
iters++;
|
||||||
if((iters % 500) == 0)
|
if((iters % 500) == 0)
|
||||||
write(1, which_child?"B":"A", 1);
|
write(1, which_child ? "B" : "A", 1);
|
||||||
int what = rand() % 23;
|
int what = rand() % 23;
|
||||||
if(what == 1){
|
if(what == 1) {
|
||||||
close(open("grindir/../a", O_CREATE|O_RDWR));
|
close(open("grindir/../a", O_CREATE | O_RDWR));
|
||||||
} else if(what == 2){
|
} else if(what == 2) {
|
||||||
close(open("grindir/../grindir/../b", O_CREATE|O_RDWR));
|
close(open("grindir/../grindir/../b", O_CREATE | O_RDWR));
|
||||||
} else if(what == 3){
|
} else if(what == 3) {
|
||||||
unlink("grindir/../a");
|
unlink("grindir/../a");
|
||||||
} else if(what == 4){
|
} else if(what == 4) {
|
||||||
if(chdir("grindir") != 0){
|
if(chdir("grindir") != 0) {
|
||||||
printf("grind: chdir grindir failed\n");
|
printf("grind: chdir grindir failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
unlink("../b");
|
unlink("../b");
|
||||||
chdir("/");
|
chdir("/");
|
||||||
} else if(what == 5){
|
} else if(what == 5) {
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = open("/grindir/../a", O_CREATE|O_RDWR);
|
fd = open("/grindir/../a", O_CREATE | O_RDWR);
|
||||||
} else if(what == 6){
|
} else if(what == 6) {
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = open("/./grindir/./../b", O_CREATE|O_RDWR);
|
fd = open("/./grindir/./../b", O_CREATE | O_RDWR);
|
||||||
} else if(what == 7){
|
} else if(what == 7) {
|
||||||
write(fd, buf, sizeof(buf));
|
write(fd, buf, sizeof(buf));
|
||||||
} else if(what == 8){
|
} else if(what == 8) {
|
||||||
read(fd, buf, sizeof(buf));
|
read(fd, buf, sizeof(buf));
|
||||||
} else if(what == 9){
|
} else if(what == 9) {
|
||||||
mkdir("grindir/../a");
|
mkdir("grindir/../a");
|
||||||
close(open("a/../a/./a", O_CREATE|O_RDWR));
|
close(open("a/../a/./a", O_CREATE | O_RDWR));
|
||||||
unlink("a/a");
|
unlink("a/a");
|
||||||
} else if(what == 10){
|
} else if(what == 10) {
|
||||||
mkdir("/../b");
|
mkdir("/../b");
|
||||||
close(open("grindir/../b/b", O_CREATE|O_RDWR));
|
close(open("grindir/../b/b", O_CREATE | O_RDWR));
|
||||||
unlink("b/b");
|
unlink("b/b");
|
||||||
} else if(what == 11){
|
} else if(what == 11) {
|
||||||
unlink("b");
|
unlink("b");
|
||||||
link("../grindir/./../a", "../b");
|
link("../grindir/./../a", "../b");
|
||||||
} else if(what == 12){
|
} else if(what == 12) {
|
||||||
unlink("../grindir/../a");
|
unlink("../grindir/../a");
|
||||||
link(".././b", "/grindir/../a");
|
link(".././b", "/grindir/../a");
|
||||||
} else if(what == 13){
|
} else if(what == 13) {
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
if(pid == 0){
|
if(pid == 0) {
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if(pid < 0){
|
} else if(pid < 0) {
|
||||||
printf("grind: fork failed\n");
|
printf("grind: fork failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
wait(0);
|
wait(0);
|
||||||
} else if(what == 14){
|
} else if(what == 14) {
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
if(pid == 0){
|
if(pid == 0) {
|
||||||
fork();
|
fork();
|
||||||
fork();
|
fork();
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if(pid < 0){
|
} else if(pid < 0) {
|
||||||
printf("grind: fork failed\n");
|
printf("grind: fork failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
wait(0);
|
wait(0);
|
||||||
} else if(what == 15){
|
} else if(what == 15) {
|
||||||
sbrk(6011);
|
sbrk(6011);
|
||||||
} else if(what == 16){
|
} else if(what == 16) {
|
||||||
if(sbrk(0) > break0)
|
if(sbrk(0) > break0)
|
||||||
sbrk(-(sbrk(0) - break0));
|
sbrk(-(sbrk(0) - break0));
|
||||||
} else if(what == 17){
|
} else if(what == 17) {
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
if(pid == 0){
|
if(pid == 0) {
|
||||||
close(open("a", O_CREATE|O_RDWR));
|
close(open("a", O_CREATE | O_RDWR));
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if(pid < 0){
|
} else if(pid < 0) {
|
||||||
printf("grind: fork failed\n");
|
printf("grind: fork failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(chdir("../grindir/..") != 0){
|
if(chdir("../grindir/..") != 0) {
|
||||||
printf("grind: chdir failed\n");
|
printf("grind: chdir failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
kill(pid);
|
kill(pid);
|
||||||
wait(0);
|
wait(0);
|
||||||
} else if(what == 18){
|
} else if(what == 18) {
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
if(pid == 0){
|
if(pid == 0) {
|
||||||
kill(getpid());
|
kill(getpid());
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if(pid < 0){
|
} else if(pid < 0) {
|
||||||
printf("grind: fork failed\n");
|
printf("grind: fork failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
wait(0);
|
wait(0);
|
||||||
} else if(what == 19){
|
} else if(what == 19) {
|
||||||
int fds[2];
|
int fds[2];
|
||||||
if(pipe(fds) < 0){
|
if(pipe(fds) < 0) {
|
||||||
printf("grind: pipe failed\n");
|
printf("grind: pipe failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
if(pid == 0){
|
if(pid == 0) {
|
||||||
fork();
|
fork();
|
||||||
fork();
|
fork();
|
||||||
if(write(fds[1], "x", 1) != 1)
|
if(write(fds[1], "x", 1) != 1)
|
||||||
|
@ -170,74 +170,74 @@ go(int which_child)
|
||||||
if(read(fds[0], &c, 1) != 1)
|
if(read(fds[0], &c, 1) != 1)
|
||||||
printf("grind: pipe read failed\n");
|
printf("grind: pipe read failed\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if(pid < 0){
|
} else if(pid < 0) {
|
||||||
printf("grind: fork failed\n");
|
printf("grind: fork failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
close(fds[0]);
|
close(fds[0]);
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
wait(0);
|
wait(0);
|
||||||
} else if(what == 20){
|
} else if(what == 20) {
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
if(pid == 0){
|
if(pid == 0) {
|
||||||
unlink("a");
|
unlink("a");
|
||||||
mkdir("a");
|
mkdir("a");
|
||||||
chdir("a");
|
chdir("a");
|
||||||
unlink("../a");
|
unlink("../a");
|
||||||
fd = open("x", O_CREATE|O_RDWR);
|
fd = open("x", O_CREATE | O_RDWR);
|
||||||
unlink("x");
|
unlink("x");
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if(pid < 0){
|
} else if(pid < 0) {
|
||||||
printf("grind: fork failed\n");
|
printf("grind: fork failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
wait(0);
|
wait(0);
|
||||||
} else if(what == 21){
|
} else if(what == 21) {
|
||||||
unlink("c");
|
unlink("c");
|
||||||
// should always succeed. check that there are free i-nodes,
|
// should always succeed. check that there are free i-nodes,
|
||||||
// file descriptors, blocks.
|
// file descriptors, blocks.
|
||||||
int fd1 = open("c", O_CREATE|O_RDWR);
|
int fd1 = open("c", O_CREATE | O_RDWR);
|
||||||
if(fd1 < 0){
|
if(fd1 < 0) {
|
||||||
printf("grind: create c failed\n");
|
printf("grind: create c failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(write(fd1, "x", 1) != 1){
|
if(write(fd1, "x", 1) != 1) {
|
||||||
printf("grind: write c failed\n");
|
printf("grind: write c failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if(fstat(fd1, &st) != 0){
|
if(fstat(fd1, &st) != 0) {
|
||||||
printf("grind: fstat failed\n");
|
printf("grind: fstat failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(st.size != 1){
|
if(st.size != 1) {
|
||||||
printf("grind: fstat reports wrong size %d\n", (int)st.size);
|
printf("grind: fstat reports wrong size %d\n", (int)st.size);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(st.ino > 200){
|
if(st.ino > 200) {
|
||||||
printf("grind: fstat reports crazy i-number %d\n", st.ino);
|
printf("grind: fstat reports crazy i-number %d\n", st.ino);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
close(fd1);
|
close(fd1);
|
||||||
unlink("c");
|
unlink("c");
|
||||||
} else if(what == 22){
|
} else if(what == 22) {
|
||||||
// echo hi | cat
|
// echo hi | cat
|
||||||
int aa[2], bb[2];
|
int aa[2], bb[2];
|
||||||
if(pipe(aa) < 0){
|
if(pipe(aa) < 0) {
|
||||||
fprintf(2, "grind: pipe failed\n");
|
fprintf(2, "grind: pipe failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(pipe(bb) < 0){
|
if(pipe(bb) < 0) {
|
||||||
fprintf(2, "grind: pipe failed\n");
|
fprintf(2, "grind: pipe failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
int pid1 = fork();
|
int pid1 = fork();
|
||||||
if(pid1 == 0){
|
if(pid1 == 0) {
|
||||||
close(bb[0]);
|
close(bb[0]);
|
||||||
close(bb[1]);
|
close(bb[1]);
|
||||||
close(aa[0]);
|
close(aa[0]);
|
||||||
close(1);
|
close(1);
|
||||||
if(dup(aa[1]) != 1){
|
if(dup(aa[1]) != 1) {
|
||||||
fprintf(2, "grind: dup failed\n");
|
fprintf(2, "grind: dup failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -246,22 +246,22 @@ go(int which_child)
|
||||||
exec("grindir/../echo", args);
|
exec("grindir/../echo", args);
|
||||||
fprintf(2, "grind: echo: not found\n");
|
fprintf(2, "grind: echo: not found\n");
|
||||||
exit(2);
|
exit(2);
|
||||||
} else if(pid1 < 0){
|
} else if(pid1 < 0) {
|
||||||
fprintf(2, "grind: fork failed\n");
|
fprintf(2, "grind: fork failed\n");
|
||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
int pid2 = fork();
|
int pid2 = fork();
|
||||||
if(pid2 == 0){
|
if(pid2 == 0) {
|
||||||
close(aa[1]);
|
close(aa[1]);
|
||||||
close(bb[0]);
|
close(bb[0]);
|
||||||
close(0);
|
close(0);
|
||||||
if(dup(aa[0]) != 0){
|
if(dup(aa[0]) != 0) {
|
||||||
fprintf(2, "grind: dup failed\n");
|
fprintf(2, "grind: dup failed\n");
|
||||||
exit(4);
|
exit(4);
|
||||||
}
|
}
|
||||||
close(aa[0]);
|
close(aa[0]);
|
||||||
close(1);
|
close(1);
|
||||||
if(dup(bb[1]) != 1){
|
if(dup(bb[1]) != 1) {
|
||||||
fprintf(2, "grind: dup failed\n");
|
fprintf(2, "grind: dup failed\n");
|
||||||
exit(5);
|
exit(5);
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,7 @@ go(int which_child)
|
||||||
exec("/cat", args);
|
exec("/cat", args);
|
||||||
fprintf(2, "grind: cat: not found\n");
|
fprintf(2, "grind: cat: not found\n");
|
||||||
exit(6);
|
exit(6);
|
||||||
} else if(pid2 < 0){
|
} else if(pid2 < 0) {
|
||||||
fprintf(2, "grind: fork failed\n");
|
fprintf(2, "grind: fork failed\n");
|
||||||
exit(7);
|
exit(7);
|
||||||
}
|
}
|
||||||
|
@ -278,14 +278,14 @@ go(int which_child)
|
||||||
close(aa[1]);
|
close(aa[1]);
|
||||||
close(bb[1]);
|
close(bb[1]);
|
||||||
char buf[4] = { 0, 0, 0, 0 };
|
char buf[4] = { 0, 0, 0, 0 };
|
||||||
read(bb[0], buf+0, 1);
|
read(bb[0], buf + 0, 1);
|
||||||
read(bb[0], buf+1, 1);
|
read(bb[0], buf + 1, 1);
|
||||||
read(bb[0], buf+2, 1);
|
read(bb[0], buf + 2, 1);
|
||||||
close(bb[0]);
|
close(bb[0]);
|
||||||
int st1, st2;
|
int st1, st2;
|
||||||
wait(&st1);
|
wait(&st1);
|
||||||
wait(&st2);
|
wait(&st2);
|
||||||
if(st1 != 0 || st2 != 0 || strcmp(buf, "hi\n") != 0){
|
if(st1 != 0 || st2 != 0 || strcmp(buf, "hi\n") != 0) {
|
||||||
printf("grind: exec pipeline failed %d %d \"%s\"\n", st1, st2, buf);
|
printf("grind: exec pipeline failed %d %d \"%s\"\n", st1, st2, buf);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -298,24 +298,24 @@ iter()
|
||||||
{
|
{
|
||||||
unlink("a");
|
unlink("a");
|
||||||
unlink("b");
|
unlink("b");
|
||||||
|
|
||||||
int pid1 = fork();
|
int pid1 = fork();
|
||||||
if(pid1 < 0){
|
if(pid1 < 0) {
|
||||||
printf("grind: fork failed\n");
|
printf("grind: fork failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(pid1 == 0){
|
if(pid1 == 0) {
|
||||||
rand_next ^= 31;
|
rand_next ^= 31;
|
||||||
go(0);
|
go(0);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pid2 = fork();
|
int pid2 = fork();
|
||||||
if(pid2 < 0){
|
if(pid2 < 0) {
|
||||||
printf("grind: fork failed\n");
|
printf("grind: fork failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(pid2 == 0){
|
if(pid2 == 0) {
|
||||||
rand_next ^= 7177;
|
rand_next ^= 7177;
|
||||||
go(1);
|
go(1);
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -323,7 +323,7 @@ iter()
|
||||||
|
|
||||||
int st1 = -1;
|
int st1 = -1;
|
||||||
wait(&st1);
|
wait(&st1);
|
||||||
if(st1 != 0){
|
if(st1 != 0) {
|
||||||
kill(pid1);
|
kill(pid1);
|
||||||
kill(pid2);
|
kill(pid2);
|
||||||
}
|
}
|
||||||
|
@ -336,13 +336,13 @@ iter()
|
||||||
int
|
int
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
while(1){
|
while(1) {
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
if(pid == 0){
|
if(pid == 0) {
|
||||||
iter();
|
iter();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
if(pid > 0){
|
if(pid > 0) {
|
||||||
wait(0);
|
wait(0);
|
||||||
}
|
}
|
||||||
sleep(20);
|
sleep(20);
|
||||||
|
|
20
user/init.c
20
user/init.c
|
@ -16,34 +16,34 @@ main(void)
|
||||||
{
|
{
|
||||||
int pid, wpid;
|
int pid, wpid;
|
||||||
|
|
||||||
if(open("console", O_RDWR) < 0){
|
if(open("console", O_RDWR) < 0) {
|
||||||
mknod("console", CONSOLE, 0);
|
mknod("console", CONSOLE, 0);
|
||||||
open("console", O_RDWR);
|
open("console", O_RDWR);
|
||||||
}
|
}
|
||||||
dup(0); // stdout
|
dup(0); // stdout
|
||||||
dup(0); // stderr
|
dup(0); // stderr
|
||||||
|
|
||||||
for(;;){
|
for(;;) {
|
||||||
printf("init: starting sh\n");
|
printf("init: starting sh\n");
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if(pid < 0){
|
if(pid < 0) {
|
||||||
printf("init: fork failed\n");
|
printf("init: fork failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(pid == 0){
|
if(pid == 0) {
|
||||||
exec("sh", argv);
|
exec("sh", argv);
|
||||||
printf("init: exec sh failed\n");
|
printf("init: exec sh failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(;;){
|
for(;;) {
|
||||||
// this call to wait() returns if the shell exits,
|
// this call to wait() returns if the shell exits,
|
||||||
// or if a parentless process exits.
|
// or if a parentless process exits.
|
||||||
wpid = wait((int *) 0);
|
wpid = wait((int *)0);
|
||||||
if(wpid == pid){
|
if(wpid == pid) {
|
||||||
// the shell exited; restart it.
|
// the shell exited; restart it.
|
||||||
break;
|
break;
|
||||||
} else if(wpid < 0){
|
} else if(wpid < 0) {
|
||||||
printf("init: wait returned an error\n");
|
printf("init: wait returned an error\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,11 +7,11 @@ main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2) {
|
||||||
fprintf(2, "usage: kill pid...\n");
|
fprintf(2, "usage: kill pid...\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
for(i=1; i<argc; i++)
|
for(i = 1; i < argc; i++)
|
||||||
kill(atoi(argv[i]));
|
kill(atoi(argv[i]));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if(argc != 3){
|
if(argc != 3) {
|
||||||
fprintf(2, "Usage: ln old new\n");
|
fprintf(2, "Usage: ln old new\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
34
user/ls.c
34
user/ls.c
|
@ -3,14 +3,14 @@
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
#include "kernel/fs.h"
|
#include "kernel/fs.h"
|
||||||
|
|
||||||
char*
|
char *
|
||||||
fmtname(char *path)
|
fmtname(char *path)
|
||||||
{
|
{
|
||||||
static char buf[DIRSIZ+1];
|
static char buf[DIRSIZ + 1];
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
// Find first character after last slash.
|
// Find first character after last slash.
|
||||||
for(p=path+strlen(path); p >= path && *p != '/'; p--)
|
for(p = path + strlen(path); p >= path && *p != '/'; p--)
|
||||||
;
|
;
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
|
@ -18,49 +18,49 @@ fmtname(char *path)
|
||||||
if(strlen(p) >= DIRSIZ)
|
if(strlen(p) >= DIRSIZ)
|
||||||
return p;
|
return p;
|
||||||
memmove(buf, p, strlen(p));
|
memmove(buf, p, strlen(p));
|
||||||
memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
|
memset(buf + strlen(p), ' ', DIRSIZ - strlen(p));
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ls(char *path)
|
ls(char *path)
|
||||||
{
|
{
|
||||||
char buf[512], *p;
|
char buf[512], *p;
|
||||||
int fd;
|
int fd;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if((fd = open(path, 0)) < 0){
|
if((fd = open(path, 0)) < 0) {
|
||||||
fprintf(2, "ls: cannot open %s\n", path);
|
fprintf(2, "ls: cannot open %s\n", path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fstat(fd, &st) < 0){
|
if(fstat(fd, &st) < 0) {
|
||||||
fprintf(2, "ls: cannot stat %s\n", path);
|
fprintf(2, "ls: cannot stat %s\n", path);
|
||||||
close(fd);
|
close(fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(st.type){
|
switch(st.type) {
|
||||||
case T_DEVICE:
|
case T_DEVICE:
|
||||||
case T_FILE:
|
case T_FILE:
|
||||||
printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);
|
printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_DIR:
|
case T_DIR:
|
||||||
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
|
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
|
||||||
printf("ls: path too long\n");
|
printf("ls: path too long\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
strcpy(buf, path);
|
strcpy(buf, path);
|
||||||
p = buf+strlen(buf);
|
p = buf + strlen(buf);
|
||||||
*p++ = '/';
|
*p++ = '/';
|
||||||
while(read(fd, &de, sizeof(de)) == sizeof(de)){
|
while(read(fd, &de, sizeof(de)) == sizeof(de)) {
|
||||||
if(de.inum == 0)
|
if(de.inum == 0)
|
||||||
continue;
|
continue;
|
||||||
memmove(p, de.name, DIRSIZ);
|
memmove(p, de.name, DIRSIZ);
|
||||||
p[DIRSIZ] = 0;
|
p[DIRSIZ] = 0;
|
||||||
if(stat(buf, &st) < 0){
|
if(stat(buf, &st) < 0) {
|
||||||
printf("ls: cannot stat %s\n", buf);
|
printf("ls: cannot stat %s\n", buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -76,11 +76,11 @@ main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2) {
|
||||||
ls(".");
|
ls(".");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
for(i=1; i<argc; i++)
|
for(i = 1; i < argc; i++)
|
||||||
ls(argv[i]);
|
ls(argv[i]);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@ main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2) {
|
||||||
fprintf(2, "Usage: mkdir files...\n");
|
fprintf(2, "Usage: mkdir files...\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++) {
|
||||||
if(mkdir(argv[i]) < 0){
|
if(mkdir(argv[i]) < 0) {
|
||||||
fprintf(2, "mkdir: %s failed to create\n", argv[i]);
|
fprintf(2, "mkdir: %s failed to create\n", argv[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,11 @@ static void
|
||||||
printint(int fd, int xx, int base, int sgn)
|
printint(int fd, int xx, int base, int sgn)
|
||||||
{
|
{
|
||||||
char buf[16];
|
char buf[16];
|
||||||
int i, neg;
|
int i, neg;
|
||||||
u32 x;
|
u32 x;
|
||||||
|
|
||||||
neg = 0;
|
neg = 0;
|
||||||
if(sgn && xx < 0){
|
if(sgn && xx < 0) {
|
||||||
neg = 1;
|
neg = 1;
|
||||||
x = -xx;
|
x = -xx;
|
||||||
} else {
|
} else {
|
||||||
|
@ -28,9 +28,9 @@ printint(int fd, int xx, int base, int sgn)
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
do{
|
do {
|
||||||
buf[i++] = digits[x % base];
|
buf[i++] = digits[x % base];
|
||||||
}while((x /= base) != 0);
|
} while((x /= base) != 0);
|
||||||
if(neg)
|
if(neg)
|
||||||
buf[i++] = '-';
|
buf[i++] = '-';
|
||||||
|
|
||||||
|
@ -39,11 +39,12 @@ printint(int fd, int xx, int base, int sgn)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
printptr(int fd, u64 x) {
|
printptr(int fd, u64 x)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
putc(fd, '0');
|
putc(fd, '0');
|
||||||
putc(fd, 'x');
|
putc(fd, 'x');
|
||||||
for (i = 0; i < (sizeof(u64) * 2); i++, x <<= 4)
|
for(i = 0; i < (sizeof(u64) * 2); i++, x <<= 4)
|
||||||
putc(fd, digits[x >> (sizeof(u64) * 8 - 4)]);
|
putc(fd, digits[x >> (sizeof(u64) * 8 - 4)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,19 +53,19 @@ void
|
||||||
vprintf(int fd, const char *fmt, va_list ap)
|
vprintf(int fd, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
int c, i, state;
|
int c, i, state;
|
||||||
|
|
||||||
state = 0;
|
state = 0;
|
||||||
for(i = 0; fmt[i]; i++){
|
for(i = 0; fmt[i]; i++) {
|
||||||
c = fmt[i] & 0xff;
|
c = fmt[i] & 0xff;
|
||||||
if(state == 0){
|
if(state == 0) {
|
||||||
if(c == '%'){
|
if(c == '%') {
|
||||||
state = '%';
|
state = '%';
|
||||||
} else {
|
} else {
|
||||||
putc(fd, c);
|
putc(fd, c);
|
||||||
}
|
}
|
||||||
} else if(state == '%'){
|
} else if(state == '%') {
|
||||||
if(c == 'd'){
|
if(c == 'd') {
|
||||||
printint(fd, va_arg(ap, int), 10, 1);
|
printint(fd, va_arg(ap, int), 10, 1);
|
||||||
} else if(c == 'l') {
|
} else if(c == 'l') {
|
||||||
printint(fd, va_arg(ap, u64), 10, 0);
|
printint(fd, va_arg(ap, u64), 10, 0);
|
||||||
|
@ -72,17 +73,17 @@ vprintf(int fd, const char *fmt, va_list ap)
|
||||||
printint(fd, va_arg(ap, int), 16, 0);
|
printint(fd, va_arg(ap, int), 16, 0);
|
||||||
} else if(c == 'p') {
|
} else if(c == 'p') {
|
||||||
printptr(fd, va_arg(ap, u64));
|
printptr(fd, va_arg(ap, u64));
|
||||||
} else if(c == 's'){
|
} else if(c == 's') {
|
||||||
s = va_arg(ap, char*);
|
s = va_arg(ap, char *);
|
||||||
if(s == 0)
|
if(s == 0)
|
||||||
s = "(null)";
|
s = "(null)";
|
||||||
while(*s != 0){
|
while(*s != 0) {
|
||||||
putc(fd, *s);
|
putc(fd, *s);
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
} else if(c == 'c'){
|
} else if(c == 'c') {
|
||||||
putc(fd, va_arg(ap, u32));
|
putc(fd, va_arg(ap, u32));
|
||||||
} else if(c == '%'){
|
} else if(c == '%') {
|
||||||
putc(fd, c);
|
putc(fd, c);
|
||||||
} else {
|
} else {
|
||||||
// Unknown % sequence. Print it to draw attention.
|
// Unknown % sequence. Print it to draw attention.
|
||||||
|
|
|
@ -7,13 +7,13 @@ main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2) {
|
||||||
fprintf(2, "Usage: rm files...\n");
|
fprintf(2, "Usage: rm files...\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++) {
|
||||||
if(unlink(argv[i]) < 0){
|
if(unlink(argv[i]) < 0) {
|
||||||
fprintf(2, "rm: %s failed to delete\n", argv[i]);
|
fprintf(2, "rm: %s failed to delete\n", argv[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
184
user/sh.c
184
user/sh.c
|
@ -18,62 +18,62 @@ struct cmd {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct execcmd {
|
struct execcmd {
|
||||||
int type;
|
int type;
|
||||||
char *argv[MAXARGS];
|
char *argv[MAXARGS];
|
||||||
char *eargv[MAXARGS];
|
char *eargv[MAXARGS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct redircmd {
|
struct redircmd {
|
||||||
int type;
|
int type;
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
char *file;
|
char *file;
|
||||||
char *efile;
|
char *efile;
|
||||||
int mode;
|
int mode;
|
||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pipecmd {
|
struct pipecmd {
|
||||||
int type;
|
int type;
|
||||||
struct cmd *left;
|
struct cmd *left;
|
||||||
struct cmd *right;
|
struct cmd *right;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct listcmd {
|
struct listcmd {
|
||||||
int type;
|
int type;
|
||||||
struct cmd *left;
|
struct cmd *left;
|
||||||
struct cmd *right;
|
struct cmd *right;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct backcmd {
|
struct backcmd {
|
||||||
int type;
|
int type;
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
};
|
};
|
||||||
|
|
||||||
int fork1(void); // Fork but panics on failure.
|
int fork1(void); // Fork but panics on failure.
|
||||||
void panic(char*);
|
void panic(char *);
|
||||||
struct cmd *parsecmd(char*);
|
struct cmd *parsecmd(char *);
|
||||||
void runcmd(struct cmd*) __attribute__((noreturn));
|
void runcmd(struct cmd *) __attribute__((noreturn));
|
||||||
|
|
||||||
// Execute cmd. Never returns.
|
// Execute cmd. Never returns.
|
||||||
void
|
void
|
||||||
runcmd(struct cmd *cmd)
|
runcmd(struct cmd *cmd)
|
||||||
{
|
{
|
||||||
int p[2];
|
int p[2];
|
||||||
struct backcmd *bcmd;
|
struct backcmd *bcmd;
|
||||||
struct execcmd *ecmd;
|
struct execcmd *ecmd;
|
||||||
struct listcmd *lcmd;
|
struct listcmd *lcmd;
|
||||||
struct pipecmd *pcmd;
|
struct pipecmd *pcmd;
|
||||||
struct redircmd *rcmd;
|
struct redircmd *rcmd;
|
||||||
|
|
||||||
if(cmd == 0)
|
if(cmd == 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
switch(cmd->type){
|
switch(cmd->type) {
|
||||||
default:
|
default:
|
||||||
panic("runcmd");
|
panic("runcmd");
|
||||||
|
|
||||||
case EXEC:
|
case EXEC:
|
||||||
ecmd = (struct execcmd*)cmd;
|
ecmd = (struct execcmd *)cmd;
|
||||||
if(ecmd->argv[0] == 0)
|
if(ecmd->argv[0] == 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
exec(ecmd->argv[0], ecmd->argv);
|
exec(ecmd->argv[0], ecmd->argv);
|
||||||
|
@ -81,9 +81,9 @@ runcmd(struct cmd *cmd)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REDIR:
|
case REDIR:
|
||||||
rcmd = (struct redircmd*)cmd;
|
rcmd = (struct redircmd *)cmd;
|
||||||
close(rcmd->fd);
|
close(rcmd->fd);
|
||||||
if(open(rcmd->file, rcmd->mode) < 0){
|
if(open(rcmd->file, rcmd->mode) < 0) {
|
||||||
fprintf(2, "open %s failed\n", rcmd->file);
|
fprintf(2, "open %s failed\n", rcmd->file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ runcmd(struct cmd *cmd)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIST:
|
case LIST:
|
||||||
lcmd = (struct listcmd*)cmd;
|
lcmd = (struct listcmd *)cmd;
|
||||||
if(fork1() == 0)
|
if(fork1() == 0)
|
||||||
runcmd(lcmd->left);
|
runcmd(lcmd->left);
|
||||||
wait(0);
|
wait(0);
|
||||||
|
@ -99,17 +99,17 @@ runcmd(struct cmd *cmd)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PIPE:
|
case PIPE:
|
||||||
pcmd = (struct pipecmd*)cmd;
|
pcmd = (struct pipecmd *)cmd;
|
||||||
if(pipe(p) < 0)
|
if(pipe(p) < 0)
|
||||||
panic("pipe");
|
panic("pipe");
|
||||||
if(fork1() == 0){
|
if(fork1() == 0) {
|
||||||
close(1);
|
close(1);
|
||||||
dup(p[1]);
|
dup(p[1]);
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
runcmd(pcmd->left);
|
runcmd(pcmd->left);
|
||||||
}
|
}
|
||||||
if(fork1() == 0){
|
if(fork1() == 0) {
|
||||||
close(0);
|
close(0);
|
||||||
dup(p[0]);
|
dup(p[0]);
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
|
@ -123,7 +123,7 @@ runcmd(struct cmd *cmd)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BACK:
|
case BACK:
|
||||||
bcmd = (struct backcmd*)cmd;
|
bcmd = (struct backcmd *)cmd;
|
||||||
if(fork1() == 0)
|
if(fork1() == 0)
|
||||||
runcmd(bcmd->cmd);
|
runcmd(bcmd->cmd);
|
||||||
break;
|
break;
|
||||||
|
@ -146,23 +146,23 @@ int
|
||||||
main(void)
|
main(void)
|
||||||
{
|
{
|
||||||
static char buf[100];
|
static char buf[100];
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
// Ensure that three file descriptors are open.
|
// Ensure that three file descriptors are open.
|
||||||
while((fd = open("console", O_RDWR)) >= 0){
|
while((fd = open("console", O_RDWR)) >= 0) {
|
||||||
if(fd >= 3){
|
if(fd >= 3) {
|
||||||
close(fd);
|
close(fd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and run input commands.
|
// Read and run input commands.
|
||||||
while(getcmd(buf, sizeof(buf)) >= 0){
|
while(getcmd(buf, sizeof(buf)) >= 0) {
|
||||||
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
|
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' ') {
|
||||||
// Chdir must be called by the parent, not the child.
|
// Chdir must be called by the parent, not the child.
|
||||||
buf[strlen(buf)-1] = 0; // chop \n
|
buf[strlen(buf) - 1] = 0; // chop \n
|
||||||
if(chdir(buf+3) < 0)
|
if(chdir(buf + 3) < 0)
|
||||||
fprintf(2, "cannot cd %s\n", buf+3);
|
fprintf(2, "cannot cd %s\n", buf + 3);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(fork1() == 0)
|
if(fork1() == 0)
|
||||||
|
@ -190,10 +190,10 @@ fork1(void)
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
//PAGEBREAK!
|
// PAGEBREAK!
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
execcmd(void)
|
execcmd(void)
|
||||||
{
|
{
|
||||||
struct execcmd *cmd;
|
struct execcmd *cmd;
|
||||||
|
@ -201,10 +201,10 @@ execcmd(void)
|
||||||
cmd = malloc(sizeof(*cmd));
|
cmd = malloc(sizeof(*cmd));
|
||||||
memset(cmd, 0, sizeof(*cmd));
|
memset(cmd, 0, sizeof(*cmd));
|
||||||
cmd->type = EXEC;
|
cmd->type = EXEC;
|
||||||
return (struct cmd*)cmd;
|
return (struct cmd *)cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
|
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
|
||||||
{
|
{
|
||||||
struct redircmd *cmd;
|
struct redircmd *cmd;
|
||||||
|
@ -217,10 +217,10 @@ redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
|
||||||
cmd->efile = efile;
|
cmd->efile = efile;
|
||||||
cmd->mode = mode;
|
cmd->mode = mode;
|
||||||
cmd->fd = fd;
|
cmd->fd = fd;
|
||||||
return (struct cmd*)cmd;
|
return (struct cmd *)cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
pipecmd(struct cmd *left, struct cmd *right)
|
pipecmd(struct cmd *left, struct cmd *right)
|
||||||
{
|
{
|
||||||
struct pipecmd *cmd;
|
struct pipecmd *cmd;
|
||||||
|
@ -230,10 +230,10 @@ pipecmd(struct cmd *left, struct cmd *right)
|
||||||
cmd->type = PIPE;
|
cmd->type = PIPE;
|
||||||
cmd->left = left;
|
cmd->left = left;
|
||||||
cmd->right = right;
|
cmd->right = right;
|
||||||
return (struct cmd*)cmd;
|
return (struct cmd *)cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
listcmd(struct cmd *left, struct cmd *right)
|
listcmd(struct cmd *left, struct cmd *right)
|
||||||
{
|
{
|
||||||
struct listcmd *cmd;
|
struct listcmd *cmd;
|
||||||
|
@ -243,10 +243,10 @@ listcmd(struct cmd *left, struct cmd *right)
|
||||||
cmd->type = LIST;
|
cmd->type = LIST;
|
||||||
cmd->left = left;
|
cmd->left = left;
|
||||||
cmd->right = right;
|
cmd->right = right;
|
||||||
return (struct cmd*)cmd;
|
return (struct cmd *)cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
backcmd(struct cmd *subcmd)
|
backcmd(struct cmd *subcmd)
|
||||||
{
|
{
|
||||||
struct backcmd *cmd;
|
struct backcmd *cmd;
|
||||||
|
@ -255,10 +255,10 @@ backcmd(struct cmd *subcmd)
|
||||||
memset(cmd, 0, sizeof(*cmd));
|
memset(cmd, 0, sizeof(*cmd));
|
||||||
cmd->type = BACK;
|
cmd->type = BACK;
|
||||||
cmd->cmd = subcmd;
|
cmd->cmd = subcmd;
|
||||||
return (struct cmd*)cmd;
|
return (struct cmd *)cmd;
|
||||||
}
|
}
|
||||||
//PAGEBREAK!
|
// PAGEBREAK!
|
||||||
// Parsing
|
// Parsing
|
||||||
|
|
||||||
char whitespace[] = " \t\r\n\v";
|
char whitespace[] = " \t\r\n\v";
|
||||||
char symbols[] = "<|>&;()";
|
char symbols[] = "<|>&;()";
|
||||||
|
@ -267,7 +267,7 @@ int
|
||||||
gettoken(char **ps, char *es, char **q, char **eq)
|
gettoken(char **ps, char *es, char **q, char **eq)
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
s = *ps;
|
s = *ps;
|
||||||
while(s < es && strchr(whitespace, *s))
|
while(s < es && strchr(whitespace, *s))
|
||||||
|
@ -275,7 +275,7 @@ gettoken(char **ps, char *es, char **q, char **eq)
|
||||||
if(q)
|
if(q)
|
||||||
*q = s;
|
*q = s;
|
||||||
ret = *s;
|
ret = *s;
|
||||||
switch(*s){
|
switch(*s) {
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
case '|':
|
case '|':
|
||||||
|
@ -288,7 +288,7 @@ gettoken(char **ps, char *es, char **q, char **eq)
|
||||||
break;
|
break;
|
||||||
case '>':
|
case '>':
|
||||||
s++;
|
s++;
|
||||||
if(*s == '>'){
|
if(*s == '>') {
|
||||||
ret = '+';
|
ret = '+';
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
@ -320,21 +320,21 @@ peek(char **ps, char *es, char *toks)
|
||||||
return *s && strchr(toks, *s);
|
return *s && strchr(toks, *s);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *parseline(char**, char*);
|
struct cmd *parseline(char **, char *);
|
||||||
struct cmd *parsepipe(char**, char*);
|
struct cmd *parsepipe(char **, char *);
|
||||||
struct cmd *parseexec(char**, char*);
|
struct cmd *parseexec(char **, char *);
|
||||||
struct cmd *nulterminate(struct cmd*);
|
struct cmd *nulterminate(struct cmd *);
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
parsecmd(char *s)
|
parsecmd(char *s)
|
||||||
{
|
{
|
||||||
char *es;
|
char *es;
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
|
||||||
es = s + strlen(s);
|
es = s + strlen(s);
|
||||||
cmd = parseline(&s, es);
|
cmd = parseline(&s, es);
|
||||||
peek(&s, es, "");
|
peek(&s, es, "");
|
||||||
if(s != es){
|
if(s != es) {
|
||||||
fprintf(2, "leftovers: %s\n", s);
|
fprintf(2, "leftovers: %s\n", s);
|
||||||
panic("syntax");
|
panic("syntax");
|
||||||
}
|
}
|
||||||
|
@ -342,62 +342,62 @@ parsecmd(char *s)
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
parseline(char **ps, char *es)
|
parseline(char **ps, char *es)
|
||||||
{
|
{
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
|
||||||
cmd = parsepipe(ps, es);
|
cmd = parsepipe(ps, es);
|
||||||
while(peek(ps, es, "&")){
|
while(peek(ps, es, "&")) {
|
||||||
gettoken(ps, es, 0, 0);
|
gettoken(ps, es, 0, 0);
|
||||||
cmd = backcmd(cmd);
|
cmd = backcmd(cmd);
|
||||||
}
|
}
|
||||||
if(peek(ps, es, ";")){
|
if(peek(ps, es, ";")) {
|
||||||
gettoken(ps, es, 0, 0);
|
gettoken(ps, es, 0, 0);
|
||||||
cmd = listcmd(cmd, parseline(ps, es));
|
cmd = listcmd(cmd, parseline(ps, es));
|
||||||
}
|
}
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
parsepipe(char **ps, char *es)
|
parsepipe(char **ps, char *es)
|
||||||
{
|
{
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
|
||||||
cmd = parseexec(ps, es);
|
cmd = parseexec(ps, es);
|
||||||
if(peek(ps, es, "|")){
|
if(peek(ps, es, "|")) {
|
||||||
gettoken(ps, es, 0, 0);
|
gettoken(ps, es, 0, 0);
|
||||||
cmd = pipecmd(cmd, parsepipe(ps, es));
|
cmd = pipecmd(cmd, parsepipe(ps, es));
|
||||||
}
|
}
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
parseredirs(struct cmd *cmd, char **ps, char *es)
|
parseredirs(struct cmd *cmd, char **ps, char *es)
|
||||||
{
|
{
|
||||||
int tok;
|
int tok;
|
||||||
char *q, *eq;
|
char *q, *eq;
|
||||||
|
|
||||||
while(peek(ps, es, "<>")){
|
while(peek(ps, es, "<>")) {
|
||||||
tok = gettoken(ps, es, 0, 0);
|
tok = gettoken(ps, es, 0, 0);
|
||||||
if(gettoken(ps, es, &q, &eq) != 'a')
|
if(gettoken(ps, es, &q, &eq) != 'a')
|
||||||
panic("missing file for redirection");
|
panic("missing file for redirection");
|
||||||
switch(tok){
|
switch(tok) {
|
||||||
case '<':
|
case '<':
|
||||||
cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
|
cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
|
||||||
break;
|
break;
|
||||||
case '>':
|
case '>':
|
||||||
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
|
cmd = redircmd(cmd, q, eq, O_WRONLY | O_CREATE | O_TRUNC, 1);
|
||||||
break;
|
break;
|
||||||
case '+': // >>
|
case '+': // >>
|
||||||
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
|
cmd = redircmd(cmd, q, eq, O_WRONLY | O_CREATE, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
parseblock(char **ps, char *es)
|
parseblock(char **ps, char *es)
|
||||||
{
|
{
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
@ -413,24 +413,24 @@ parseblock(char **ps, char *es)
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd*
|
struct cmd *
|
||||||
parseexec(char **ps, char *es)
|
parseexec(char **ps, char *es)
|
||||||
{
|
{
|
||||||
char *q, *eq;
|
char *q, *eq;
|
||||||
int tok, argc;
|
int tok, argc;
|
||||||
struct execcmd *cmd;
|
struct execcmd *cmd;
|
||||||
struct cmd *ret;
|
struct cmd *ret;
|
||||||
|
|
||||||
if(peek(ps, es, "("))
|
if(peek(ps, es, "("))
|
||||||
return parseblock(ps, es);
|
return parseblock(ps, es);
|
||||||
|
|
||||||
ret = execcmd();
|
ret = execcmd();
|
||||||
cmd = (struct execcmd*)ret;
|
cmd = (struct execcmd *)ret;
|
||||||
|
|
||||||
argc = 0;
|
argc = 0;
|
||||||
ret = parseredirs(ret, ps, es);
|
ret = parseredirs(ret, ps, es);
|
||||||
while(!peek(ps, es, "|)&;")){
|
while(!peek(ps, es, "|)&;")) {
|
||||||
if((tok=gettoken(ps, es, &q, &eq)) == 0)
|
if((tok = gettoken(ps, es, &q, &eq)) == 0)
|
||||||
break;
|
break;
|
||||||
if(tok != 'a')
|
if(tok != 'a')
|
||||||
panic("syntax");
|
panic("syntax");
|
||||||
|
@ -447,46 +447,46 @@ parseexec(char **ps, char *es)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NUL-terminate all the counted strings.
|
// NUL-terminate all the counted strings.
|
||||||
struct cmd*
|
struct cmd *
|
||||||
nulterminate(struct cmd *cmd)
|
nulterminate(struct cmd *cmd)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct backcmd *bcmd;
|
struct backcmd *bcmd;
|
||||||
struct execcmd *ecmd;
|
struct execcmd *ecmd;
|
||||||
struct listcmd *lcmd;
|
struct listcmd *lcmd;
|
||||||
struct pipecmd *pcmd;
|
struct pipecmd *pcmd;
|
||||||
struct redircmd *rcmd;
|
struct redircmd *rcmd;
|
||||||
|
|
||||||
if(cmd == 0)
|
if(cmd == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch(cmd->type){
|
switch(cmd->type) {
|
||||||
case EXEC:
|
case EXEC:
|
||||||
ecmd = (struct execcmd*)cmd;
|
ecmd = (struct execcmd *)cmd;
|
||||||
for(i=0; ecmd->argv[i]; i++)
|
for(i = 0; ecmd->argv[i]; i++)
|
||||||
*ecmd->eargv[i] = 0;
|
*ecmd->eargv[i] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REDIR:
|
case REDIR:
|
||||||
rcmd = (struct redircmd*)cmd;
|
rcmd = (struct redircmd *)cmd;
|
||||||
nulterminate(rcmd->cmd);
|
nulterminate(rcmd->cmd);
|
||||||
*rcmd->efile = 0;
|
*rcmd->efile = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PIPE:
|
case PIPE:
|
||||||
pcmd = (struct pipecmd*)cmd;
|
pcmd = (struct pipecmd *)cmd;
|
||||||
nulterminate(pcmd->left);
|
nulterminate(pcmd->left);
|
||||||
nulterminate(pcmd->right);
|
nulterminate(pcmd->right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIST:
|
case LIST:
|
||||||
lcmd = (struct listcmd*)cmd;
|
lcmd = (struct listcmd *)cmd;
|
||||||
nulterminate(lcmd->left);
|
nulterminate(lcmd->left);
|
||||||
nulterminate(lcmd->right);
|
nulterminate(lcmd->right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BACK:
|
case BACK:
|
||||||
bcmd = (struct backcmd*)cmd;
|
bcmd = (struct backcmd *)cmd;
|
||||||
nulterminate(bcmd->cmd);
|
nulterminate(bcmd->cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int fd, i;
|
int fd, i;
|
||||||
char path[] = "stressfs0";
|
char path[] = "stressfs0";
|
||||||
char data[512];
|
char data[512];
|
||||||
|
|
||||||
|
@ -32,14 +32,14 @@ main(int argc, char *argv[])
|
||||||
path[8] += i;
|
path[8] += i;
|
||||||
fd = open(path, O_CREATE | O_RDWR);
|
fd = open(path, O_CREATE | O_RDWR);
|
||||||
for(i = 0; i < 20; i++)
|
for(i = 0; i < 20; i++)
|
||||||
// printf(fd, "%d\n", i);
|
// printf(fd, "%d\n", i);
|
||||||
write(fd, data, sizeof(data));
|
write(fd, data, sizeof(data));
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
printf("read\n");
|
printf("read\n");
|
||||||
|
|
||||||
fd = open(path, O_RDONLY);
|
fd = open(path, O_RDONLY);
|
||||||
for (i = 0; i < 20; i++)
|
for(i = 0; i < 20; i++)
|
||||||
read(fd, data, sizeof(data));
|
read(fd, data, sizeof(data));
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
|
32
user/ulib.c
32
user/ulib.c
|
@ -14,7 +14,7 @@ _main()
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char *
|
||||||
strcpy(char *s, const char *t)
|
strcpy(char *s, const char *t)
|
||||||
{
|
{
|
||||||
char *os;
|
char *os;
|
||||||
|
@ -43,33 +43,33 @@ strlen(const char *s)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void *
|
||||||
memset(void *dst, int c, u32 n)
|
memset(void *dst, int c, u32 n)
|
||||||
{
|
{
|
||||||
char *cdst = (char *) dst;
|
char *cdst = (char *)dst;
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < n; i++){
|
for(i = 0; i < n; i++) {
|
||||||
cdst[i] = c;
|
cdst[i] = c;
|
||||||
}
|
}
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char *
|
||||||
strchr(const char *s, char c)
|
strchr(const char *s, char c)
|
||||||
{
|
{
|
||||||
for(; *s; s++)
|
for(; *s; s++)
|
||||||
if(*s == c)
|
if(*s == c)
|
||||||
return (char*)s;
|
return (char *)s;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char *
|
||||||
gets(char *buf, int max)
|
gets(char *buf, int max)
|
||||||
{
|
{
|
||||||
int i, cc;
|
int i, cc;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
for(i=0; i+1 < max; ){
|
for(i = 0; i + 1 < max;) {
|
||||||
cc = read(0, &c, 1);
|
cc = read(0, &c, 1);
|
||||||
if(cc < 1)
|
if(cc < 1)
|
||||||
break;
|
break;
|
||||||
|
@ -102,19 +102,19 @@ atoi(const char *s)
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
while('0' <= *s && *s <= '9')
|
while('0' <= *s && *s <= '9')
|
||||||
n = n*10 + *s++ - '0';
|
n = n * 10 + *s++ - '0';
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void *
|
||||||
memmove(void *vdst, const void *vsrc, int n)
|
memmove(void *vdst, const void *vsrc, int n)
|
||||||
{
|
{
|
||||||
char *dst;
|
char *dst;
|
||||||
const char *src;
|
const char *src;
|
||||||
|
|
||||||
dst = vdst;
|
dst = vdst;
|
||||||
src = vsrc;
|
src = vsrc;
|
||||||
if (src > dst) {
|
if(src > dst) {
|
||||||
while(n-- > 0)
|
while(n-- > 0)
|
||||||
*dst++ = *src++;
|
*dst++ = *src++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -130,8 +130,8 @@ int
|
||||||
memcmp(const void *s1, const void *s2, u32 n)
|
memcmp(const void *s1, const void *s2, u32 n)
|
||||||
{
|
{
|
||||||
const char *p1 = s1, *p2 = s2;
|
const char *p1 = s1, *p2 = s2;
|
||||||
while (n-- > 0) {
|
while(n-- > 0) {
|
||||||
if (*p1 != *p2) {
|
if(*p1 != *p2) {
|
||||||
return *p1 - *p2;
|
return *p1 - *p2;
|
||||||
}
|
}
|
||||||
p1++;
|
p1++;
|
||||||
|
|
|
@ -11,14 +11,14 @@ typedef long Align;
|
||||||
union header {
|
union header {
|
||||||
struct {
|
struct {
|
||||||
union header *ptr;
|
union header *ptr;
|
||||||
u32 size;
|
u32 size;
|
||||||
} s;
|
} s;
|
||||||
Align x;
|
Align x;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef union header Header;
|
typedef union header Header;
|
||||||
|
|
||||||
static Header base;
|
static Header base;
|
||||||
static Header *freep;
|
static Header *freep;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -26,16 +26,16 @@ free(void *ap)
|
||||||
{
|
{
|
||||||
Header *bp, *p;
|
Header *bp, *p;
|
||||||
|
|
||||||
bp = (Header*)ap - 1;
|
bp = (Header *)ap - 1;
|
||||||
for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
|
for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
|
||||||
if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
|
if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
|
||||||
break;
|
break;
|
||||||
if(bp + bp->s.size == p->s.ptr){
|
if(bp + bp->s.size == p->s.ptr) {
|
||||||
bp->s.size += p->s.ptr->s.size;
|
bp->s.size += p->s.ptr->s.size;
|
||||||
bp->s.ptr = p->s.ptr->s.ptr;
|
bp->s.ptr = p->s.ptr->s.ptr;
|
||||||
} else
|
} else
|
||||||
bp->s.ptr = p->s.ptr;
|
bp->s.ptr = p->s.ptr;
|
||||||
if(p + p->s.size == bp){
|
if(p + p->s.size == bp) {
|
||||||
p->s.size += bp->s.size;
|
p->s.size += bp->s.size;
|
||||||
p->s.ptr = bp->s.ptr;
|
p->s.ptr = bp->s.ptr;
|
||||||
} else
|
} else
|
||||||
|
@ -43,36 +43,36 @@ free(void *ap)
|
||||||
freep = p;
|
freep = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Header*
|
static Header *
|
||||||
morecore(u32 nu)
|
morecore(u32 nu)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
Header *hp;
|
Header *hp;
|
||||||
|
|
||||||
if(nu < 4096)
|
if(nu < 4096)
|
||||||
nu = 4096;
|
nu = 4096;
|
||||||
p = sbrk(nu * sizeof(Header));
|
p = sbrk(nu * sizeof(Header));
|
||||||
if(p == (char*)-1)
|
if(p == (char *)-1)
|
||||||
return 0;
|
return 0;
|
||||||
hp = (Header*)p;
|
hp = (Header *)p;
|
||||||
hp->s.size = nu;
|
hp->s.size = nu;
|
||||||
free((void*)(hp + 1));
|
free((void *)(hp + 1));
|
||||||
return freep;
|
return freep;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void *
|
||||||
malloc(u32 nbytes)
|
malloc(u32 nbytes)
|
||||||
{
|
{
|
||||||
Header *p, *prevp;
|
Header *p, *prevp;
|
||||||
u32 nunits;
|
u32 nunits;
|
||||||
|
|
||||||
nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
|
nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;
|
||||||
if((prevp = freep) == 0){
|
if((prevp = freep) == 0) {
|
||||||
base.s.ptr = freep = prevp = &base;
|
base.s.ptr = freep = prevp = &base;
|
||||||
base.s.size = 0;
|
base.s.size = 0;
|
||||||
}
|
}
|
||||||
for(p = prevp->s.ptr; ; prevp = p, p = p->s.ptr){
|
for(p = prevp->s.ptr;; prevp = p, p = p->s.ptr) {
|
||||||
if(p->s.size >= nunits){
|
if(p->s.size >= nunits) {
|
||||||
if(p->s.size == nunits)
|
if(p->s.size == nunits)
|
||||||
prevp->s.ptr = p->s.ptr;
|
prevp->s.ptr = p->s.ptr;
|
||||||
else {
|
else {
|
||||||
|
@ -81,7 +81,7 @@ malloc(u32 nbytes)
|
||||||
p->s.size = nunits;
|
p->s.size = nunits;
|
||||||
}
|
}
|
||||||
freep = prevp;
|
freep = prevp;
|
||||||
return (void*)(p + 1);
|
return (void *)(p + 1);
|
||||||
}
|
}
|
||||||
if(p == freep)
|
if(p == freep)
|
||||||
if((p = morecore(nunits)) == 0)
|
if((p = morecore(nunits)) == 0)
|
||||||
|
|
70
user/user.h
70
user/user.h
|
@ -1,41 +1,41 @@
|
||||||
struct stat;
|
struct stat;
|
||||||
|
|
||||||
// system calls
|
// system calls
|
||||||
int fork(void);
|
int fork(void);
|
||||||
int exit(int) __attribute__((noreturn));
|
int exit(int) __attribute__((noreturn));
|
||||||
int wait(int*);
|
int wait(int *);
|
||||||
int pipe(int*);
|
int pipe(int *);
|
||||||
int write(int, const void*, int);
|
int write(int, const void *, int);
|
||||||
int read(int, void*, int);
|
int read(int, void *, int);
|
||||||
int close(int);
|
int close(int);
|
||||||
int kill(int);
|
int kill(int);
|
||||||
int exec(const char*, char**);
|
int exec(const char *, char **);
|
||||||
int open(const char*, int);
|
int open(const char *, int);
|
||||||
int mknod(const char*, short, short);
|
int mknod(const char *, short, short);
|
||||||
int unlink(const char*);
|
int unlink(const char *);
|
||||||
int fstat(int fd, struct stat*);
|
int fstat(int fd, struct stat *);
|
||||||
int link(const char*, const char*);
|
int link(const char *, const char *);
|
||||||
int mkdir(const char*);
|
int mkdir(const char *);
|
||||||
int chdir(const char*);
|
int chdir(const char *);
|
||||||
int dup(int);
|
int dup(int);
|
||||||
int getpid(void);
|
int getpid(void);
|
||||||
char* sbrk(int);
|
char *sbrk(int);
|
||||||
int sleep(int);
|
int sleep(int);
|
||||||
int uptime(void);
|
int uptime(void);
|
||||||
|
|
||||||
// ulib.c
|
// ulib.c
|
||||||
int stat(const char*, struct stat*);
|
int stat(const char *, struct stat *);
|
||||||
char* strcpy(char*, const char*);
|
char *strcpy(char *, const char *);
|
||||||
void *memmove(void*, const void*, int);
|
void *memmove(void *, const void *, int);
|
||||||
char* strchr(const char*, char c);
|
char *strchr(const char *, char c);
|
||||||
int strcmp(const char*, const char*);
|
int strcmp(const char *, const char *);
|
||||||
void fprintf(int, const char*, ...);
|
void fprintf(int, const char *, ...);
|
||||||
void printf(const char*, ...);
|
void printf(const char *, ...);
|
||||||
char* gets(char*, int max);
|
char *gets(char *, int max);
|
||||||
u32 strlen(const char*);
|
u32 strlen(const char *);
|
||||||
void* memset(void*, int, u32);
|
void *memset(void *, int, u32);
|
||||||
void* malloc(u32);
|
void *malloc(u32);
|
||||||
void free(void*);
|
void free(void *);
|
||||||
int atoi(const char*);
|
int atoi(const char *);
|
||||||
int memcmp(const void *, const void *, u32);
|
int memcmp(const void *, const void *, u32);
|
||||||
void *memcpy(void *, const void *, u32);
|
void *memcpy(void *, const void *, u32);
|
||||||
|
|
1254
user/usertests.c
1254
user/usertests.c
File diff suppressed because it is too large
Load diff
14
user/wc.c
14
user/wc.c
|
@ -12,20 +12,20 @@ wc(int fd, char *name)
|
||||||
|
|
||||||
l = w = c = 0;
|
l = w = c = 0;
|
||||||
inword = 0;
|
inword = 0;
|
||||||
while((n = read(fd, buf, sizeof(buf))) > 0){
|
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||||
for(i=0; i<n; i++){
|
for(i = 0; i < n; i++) {
|
||||||
c++;
|
c++;
|
||||||
if(buf[i] == '\n')
|
if(buf[i] == '\n')
|
||||||
l++;
|
l++;
|
||||||
if(strchr(" \r\t\n\v", buf[i]))
|
if(strchr(" \r\t\n\v", buf[i]))
|
||||||
inword = 0;
|
inword = 0;
|
||||||
else if(!inword){
|
else if(!inword) {
|
||||||
w++;
|
w++;
|
||||||
inword = 1;
|
inword = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(n < 0){
|
if(n < 0) {
|
||||||
printf("wc: read error\n");
|
printf("wc: read error\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -37,13 +37,13 @@ main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int fd, i;
|
int fd, i;
|
||||||
|
|
||||||
if(argc <= 1){
|
if(argc <= 1) {
|
||||||
wc(0, "");
|
wc(0, "");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++) {
|
||||||
if((fd = open(argv[i], 0)) < 0){
|
if((fd = open(argv[i], 0)) < 0) {
|
||||||
printf("wc: cannot open %s\n", argv[i]);
|
printf("wc: cannot open %s\n", argv[i]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,6 @@ int
|
||||||
main(void)
|
main(void)
|
||||||
{
|
{
|
||||||
if(fork() > 0)
|
if(fork() > 0)
|
||||||
sleep(5); // Let child exit before parent.
|
sleep(5); // Let child exit before parent.
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue