Compare commits
No commits in common. "4cd2466900323c27937d2994b3b702266f840e46" and "96047832c62e6a172c92f9ead6715b553d4c2271" have entirely different histories.
4cd2466900
...
96047832c6
|
|
@ -1,5 +0,0 @@
|
||||||
[build]
|
|
||||||
target = "riscv64gc-unknown-none-elf"
|
|
||||||
|
|
||||||
[target.riscv64-unknown-elf]
|
|
||||||
linker = "/opt/riscv/bin/riscv64-unknown-elf-gcc"
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
SortIncludes: Never
|
|
||||||
UseTab: Always
|
|
||||||
IndentWidth: 4
|
|
||||||
TabWidth: 4
|
|
||||||
|
|
@ -4,4 +4,19 @@ root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{c,h}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.S]
|
||||||
|
indent_size = 8
|
||||||
|
|
||||||
|
[*.ld]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
indent_size = 8
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
hard_tabs = true
|
|
||||||
14
Makefile
14
Makefile
|
|
@ -1,8 +1,5 @@
|
||||||
K=kernel
|
K=kernel
|
||||||
U=user
|
U=user
|
||||||
R=rust
|
|
||||||
|
|
||||||
RTARGET = riscv64gc-unknown-none-elf
|
|
||||||
|
|
||||||
OBJS = \
|
OBJS = \
|
||||||
$K/entry.o \
|
$K/entry.o \
|
||||||
|
|
@ -33,9 +30,6 @@ OBJS = \
|
||||||
$K/plic.o \
|
$K/plic.o \
|
||||||
$K/virtio_disk.o
|
$K/virtio_disk.o
|
||||||
|
|
||||||
RLIBS = \
|
|
||||||
$R/foo/target/$(RTARGET)/release/libfoo.a
|
|
||||||
|
|
||||||
# riscv64-unknown-elf- or riscv64-linux-gnu-
|
# riscv64-unknown-elf- or riscv64-linux-gnu-
|
||||||
# perhaps in /opt/riscv/bin
|
# perhaps in /opt/riscv/bin
|
||||||
#TOOLPREFIX =
|
#TOOLPREFIX =
|
||||||
|
|
@ -79,8 +73,8 @@ endif
|
||||||
|
|
||||||
LDFLAGS = -z max-page-size=4096
|
LDFLAGS = -z max-page-size=4096
|
||||||
|
|
||||||
$K/kernel: $(OBJS) $K/kernel.ld $U/initcode rustlibs
|
$K/kernel: $(OBJS) $K/kernel.ld $U/initcode
|
||||||
$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS) $(RLIBS)
|
$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS)
|
||||||
$(OBJDUMP) -S $K/kernel > $K/kernel.asm
|
$(OBJDUMP) -S $K/kernel > $K/kernel.asm
|
||||||
$(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym
|
$(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym
|
||||||
|
|
||||||
|
|
@ -144,9 +138,6 @@ fs.img: mkfs/mkfs README $(UPROGS)
|
||||||
|
|
||||||
-include kernel/*.d user/*.d
|
-include kernel/*.d user/*.d
|
||||||
|
|
||||||
rustlibs:
|
|
||||||
cargo build -r --manifest-path $R/foo/Cargo.toml
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
|
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
|
||||||
*/*.o */*.d */*.asm */*.sym \
|
*/*.o */*.d */*.asm */*.sym \
|
||||||
|
|
@ -154,7 +145,6 @@ clean:
|
||||||
mkfs/mkfs .gdbinit \
|
mkfs/mkfs .gdbinit \
|
||||||
$U/usys.S \
|
$U/usys.S \
|
||||||
$(UPROGS)
|
$(UPROGS)
|
||||||
cargo clean --manifest-path $R/foo/Cargo.toml
|
|
||||||
|
|
||||||
# try to generate a unique GDB port
|
# try to generate a unique GDB port
|
||||||
GDBPORT = $(shell expr `id -u` % 5000 + 25000)
|
GDBPORT = $(shell expr `id -u` % 5000 + 25000)
|
||||||
|
|
|
||||||
36
README
36
README
|
|
@ -6,7 +6,7 @@ ACKNOWLEDGMENTS
|
||||||
|
|
||||||
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
|
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
|
||||||
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
|
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
|
||||||
2000)). See also https://pdos.csail.mit.edu/6.1810/, which provides
|
2000)). See also https://pdos.csail.mit.edu/6.828/, which provides
|
||||||
pointers to on-line resources for v6.
|
pointers to on-line resources for v6.
|
||||||
|
|
||||||
The following people have made contributions: Russ Cox (context switching,
|
The following people have made contributions: Russ Cox (context switching,
|
||||||
|
|
@ -14,31 +14,29 @@ locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
|
||||||
Clements.
|
Clements.
|
||||||
|
|
||||||
We are also grateful for the bug reports and patches contributed by
|
We are also grateful for the bug reports and patches contributed by
|
||||||
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian
|
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, Ian Chen, Dan
|
||||||
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,
|
Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson
|
||||||
eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel
|
Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark,
|
||||||
Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt
|
Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry,
|
||||||
Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John
|
jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders
|
||||||
Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller,
|
Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt,
|
||||||
Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin
|
Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan
|
||||||
Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan
|
Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi
|
||||||
Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel
|
Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
|
||||||
Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude
|
OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek,
|
||||||
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
|
Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey,
|
||||||
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal,
|
Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi
|
||||||
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe,
|
Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy
|
||||||
Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng,
|
Zheng, ZhUyU1997, and Zou Chang Wei.
|
||||||
ZhUyU1997, and Zou Chang Wei.
|
|
||||||
|
|
||||||
|
|
||||||
The code in the files that constitute xv6 is
|
The code in the files that constitute xv6 is
|
||||||
Copyright 2006-2022 Frans Kaashoek, Robert Morris, and Russ Cox.
|
Copyright 2006-2020 Frans Kaashoek, Robert Morris, and Russ Cox.
|
||||||
|
|
||||||
ERROR REPORTS
|
ERROR REPORTS
|
||||||
|
|
||||||
Please send errors and suggestions to Frans Kaashoek and Robert Morris
|
Please send errors and suggestions to Frans Kaashoek and Robert Morris
|
||||||
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
|
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
|
||||||
operating system for MIT's 6.1810, so we are more interested in
|
operating system for MIT's 6.S081, so we are more interested in
|
||||||
simplifications and clarifications than new features.
|
simplifications and clarifications than new features.
|
||||||
|
|
||||||
BUILDING AND RUNNING XV6
|
BUILDING AND RUNNING XV6
|
||||||
|
|
|
||||||
29
kernel/bio.c
29
kernel/bio.c
|
|
@ -13,6 +13,7 @@
|
||||||
// * 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"
|
||||||
|
|
@ -32,7 +33,9 @@ struct {
|
||||||
struct buf head;
|
struct buf head;
|
||||||
} bcache;
|
} bcache;
|
||||||
|
|
||||||
void binit(void) {
|
void
|
||||||
|
binit(void)
|
||||||
|
{
|
||||||
struct buf *b;
|
struct buf *b;
|
||||||
|
|
||||||
initlock(&bcache.lock, "bcache");
|
initlock(&bcache.lock, "bcache");
|
||||||
|
|
@ -52,7 +55,9 @@ void 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 *bget(uint dev, uint blockno) {
|
static struct buf*
|
||||||
|
bget(uint dev, uint blockno)
|
||||||
|
{
|
||||||
struct buf *b;
|
struct buf *b;
|
||||||
|
|
||||||
acquire(&bcache.lock);
|
acquire(&bcache.lock);
|
||||||
|
|
@ -84,7 +89,9 @@ static struct buf *bget(uint dev, uint blockno) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a locked buf with the contents of the indicated block.
|
// Return a locked buf with the contents of the indicated block.
|
||||||
struct buf *bread(uint dev, uint blockno) {
|
struct buf*
|
||||||
|
bread(uint dev, uint blockno)
|
||||||
|
{
|
||||||
struct buf *b;
|
struct buf *b;
|
||||||
|
|
||||||
b = bget(dev, blockno);
|
b = bget(dev, blockno);
|
||||||
|
|
@ -96,7 +103,9 @@ struct buf *bread(uint dev, uint blockno) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write b's contents to disk. Must be locked.
|
// Write b's contents to disk. Must be locked.
|
||||||
void bwrite(struct buf *b) {
|
void
|
||||||
|
bwrite(struct buf *b)
|
||||||
|
{
|
||||||
if(!holdingsleep(&b->lock))
|
if(!holdingsleep(&b->lock))
|
||||||
panic("bwrite");
|
panic("bwrite");
|
||||||
virtio_disk_rw(b, 1);
|
virtio_disk_rw(b, 1);
|
||||||
|
|
@ -104,7 +113,9 @@ void bwrite(struct buf *b) {
|
||||||
|
|
||||||
// Release a locked buffer.
|
// Release a locked buffer.
|
||||||
// Move to the head of the most-recently-used list.
|
// Move to the head of the most-recently-used list.
|
||||||
void brelse(struct buf *b) {
|
void
|
||||||
|
brelse(struct buf *b)
|
||||||
|
{
|
||||||
if(!holdingsleep(&b->lock))
|
if(!holdingsleep(&b->lock))
|
||||||
panic("brelse");
|
panic("brelse");
|
||||||
|
|
||||||
|
|
@ -125,14 +136,18 @@ void brelse(struct buf *b) {
|
||||||
release(&bcache.lock);
|
release(&bcache.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bpin(struct buf *b) {
|
void
|
||||||
|
bpin(struct buf *b) {
|
||||||
acquire(&bcache.lock);
|
acquire(&bcache.lock);
|
||||||
b->refcnt++;
|
b->refcnt++;
|
||||||
release(&bcache.lock);
|
release(&bcache.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bunpin(struct buf *b) {
|
void
|
||||||
|
bunpin(struct buf *b) {
|
||||||
acquire(&bcache.lock);
|
acquire(&bcache.lock);
|
||||||
b->refcnt--;
|
b->refcnt--;
|
||||||
release(&bcache.lock);
|
release(&bcache.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,12 @@
|
||||||
// called by printf(), and to echo input characters,
|
// called by printf(), and to echo input characters,
|
||||||
// but not from write().
|
// but not from write().
|
||||||
//
|
//
|
||||||
void consputc(int c) {
|
void
|
||||||
|
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('\b'); uartputc_sync(' '); uartputc_sync('\b');
|
||||||
uartputc_sync(' ');
|
|
||||||
uartputc_sync('\b');
|
|
||||||
} else {
|
} else {
|
||||||
uartputc_sync(c);
|
uartputc_sync(c);
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +55,9 @@ struct {
|
||||||
//
|
//
|
||||||
// user write()s to the console go here.
|
// user write()s to the console go here.
|
||||||
//
|
//
|
||||||
int consolewrite(int user_src, uint64 src, int n) {
|
int
|
||||||
|
consolewrite(int user_src, uint64 src, int n)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < n; i++){
|
for(i = 0; i < n; i++){
|
||||||
|
|
@ -74,7 +76,9 @@ int consolewrite(int user_src, uint64 src, int n) {
|
||||||
// user_dist indicates whether dst is a user
|
// user_dist indicates whether dst is a user
|
||||||
// or kernel address.
|
// or kernel address.
|
||||||
//
|
//
|
||||||
int consoleread(int user_dst, uint64 dst, int n) {
|
int
|
||||||
|
consoleread(int user_dst, uint64 dst, int n)
|
||||||
|
{
|
||||||
uint target;
|
uint target;
|
||||||
int c;
|
int c;
|
||||||
char cbuf;
|
char cbuf;
|
||||||
|
|
@ -128,7 +132,9 @@ int consoleread(int user_dst, uint64 dst, int n) {
|
||||||
// do erase/kill processing, append to cons.buf,
|
// do erase/kill processing, append to cons.buf,
|
||||||
// wake up consoleread() if a whole line has arrived.
|
// wake up consoleread() if a whole line has arrived.
|
||||||
//
|
//
|
||||||
void consoleintr(int c) {
|
void
|
||||||
|
consoleintr(int c)
|
||||||
|
{
|
||||||
acquire(&cons.lock);
|
acquire(&cons.lock);
|
||||||
|
|
||||||
switch(c){
|
switch(c){
|
||||||
|
|
@ -172,7 +178,9 @@ void consoleintr(int c) {
|
||||||
release(&cons.lock);
|
release(&cons.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void consoleinit(void) {
|
void
|
||||||
|
consoleinit(void)
|
||||||
|
{
|
||||||
initlock(&cons.lock, "cons");
|
initlock(&cons.lock, "cons");
|
||||||
|
|
||||||
uartinit();
|
uartinit();
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@
|
||||||
|
|
||||||
static int loadseg(pde_t *, uint64, struct inode *, uint, uint);
|
static int loadseg(pde_t *, uint64, struct inode *, uint, uint);
|
||||||
|
|
||||||
int flags2perm(int flags) {
|
int flags2perm(int flags)
|
||||||
|
{
|
||||||
int perm = 0;
|
int perm = 0;
|
||||||
if(flags & 0x1)
|
if(flags & 0x1)
|
||||||
perm = PTE_X;
|
perm = PTE_X;
|
||||||
|
|
@ -18,7 +19,9 @@ int flags2perm(int flags) {
|
||||||
return perm;
|
return perm;
|
||||||
}
|
}
|
||||||
|
|
||||||
int exec(char *path, char **argv) {
|
int
|
||||||
|
exec(char *path, char **argv)
|
||||||
|
{
|
||||||
char *s, *last;
|
char *s, *last;
|
||||||
int i, off;
|
int i, off;
|
||||||
uint64 argc, sz = 0, sp, ustack[MAXARG], stackbase;
|
uint64 argc, sz = 0, sp, ustack[MAXARG], stackbase;
|
||||||
|
|
@ -59,8 +62,7 @@ int exec(char *path, char **argv) {
|
||||||
if(ph.vaddr % PGSIZE != 0)
|
if(ph.vaddr % PGSIZE != 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
uint64 sz1;
|
uint64 sz1;
|
||||||
if ((sz1 = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz,
|
if((sz1 = uvmalloc(pagetable, sz, ph.vaddr + ph.memsz, flags2perm(ph.flags))) == 0)
|
||||||
flags2perm(ph.flags))) == 0)
|
|
||||||
goto bad;
|
goto bad;
|
||||||
sz = sz1;
|
sz = sz1;
|
||||||
if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0)
|
if(loadseg(pagetable, ph.vaddr, ip, ph.off, ph.filesz) < 0)
|
||||||
|
|
@ -142,8 +144,9 @@ bad:
|
||||||
// va must be page-aligned
|
// va must be page-aligned
|
||||||
// and the pages from va to va+sz must already be mapped.
|
// and the pages from va to va+sz must already be mapped.
|
||||||
// Returns 0 on success, -1 on failure.
|
// Returns 0 on success, -1 on failure.
|
||||||
static int loadseg(pagetable_t pagetable, uint64 va, struct inode *ip,
|
static int
|
||||||
uint offset, uint sz) {
|
loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz)
|
||||||
|
{
|
||||||
uint i, n;
|
uint i, n;
|
||||||
uint64 pa;
|
uint64 pa;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,16 @@ struct {
|
||||||
struct file file[NFILE];
|
struct file file[NFILE];
|
||||||
} ftable;
|
} ftable;
|
||||||
|
|
||||||
void fileinit(void) { initlock(&ftable.lock, "ftable"); }
|
void
|
||||||
|
fileinit(void)
|
||||||
|
{
|
||||||
|
initlock(&ftable.lock, "ftable");
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate a file structure.
|
// Allocate a file structure.
|
||||||
struct file *filealloc(void) {
|
struct file*
|
||||||
|
filealloc(void)
|
||||||
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
|
|
||||||
acquire(&ftable.lock);
|
acquire(&ftable.lock);
|
||||||
|
|
@ -38,7 +44,9 @@ struct file *filealloc(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment ref count for file f.
|
// Increment ref count for file f.
|
||||||
struct file *filedup(struct file *f) {
|
struct file*
|
||||||
|
filedup(struct file *f)
|
||||||
|
{
|
||||||
acquire(&ftable.lock);
|
acquire(&ftable.lock);
|
||||||
if(f->ref < 1)
|
if(f->ref < 1)
|
||||||
panic("filedup");
|
panic("filedup");
|
||||||
|
|
@ -48,7 +56,9 @@ struct file *filedup(struct file *f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close file f. (Decrement ref count, close when reaches 0.)
|
// Close file f. (Decrement ref count, close when reaches 0.)
|
||||||
void fileclose(struct file *f) {
|
void
|
||||||
|
fileclose(struct file *f)
|
||||||
|
{
|
||||||
struct file ff;
|
struct file ff;
|
||||||
|
|
||||||
acquire(&ftable.lock);
|
acquire(&ftable.lock);
|
||||||
|
|
@ -74,7 +84,9 @@ void fileclose(struct file *f) {
|
||||||
|
|
||||||
// Get metadata about file f.
|
// Get metadata about file f.
|
||||||
// addr is a user virtual address, pointing to a struct stat.
|
// addr is a user virtual address, pointing to a struct stat.
|
||||||
int filestat(struct file *f, uint64 addr) {
|
int
|
||||||
|
filestat(struct file *f, uint64 addr)
|
||||||
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
|
@ -91,7 +103,9 @@ int filestat(struct file *f, uint64 addr) {
|
||||||
|
|
||||||
// Read from file f.
|
// Read from file f.
|
||||||
// addr is a user virtual address.
|
// addr is a user virtual address.
|
||||||
int fileread(struct file *f, uint64 addr, int n) {
|
int
|
||||||
|
fileread(struct file *f, uint64 addr, int n)
|
||||||
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if(f->readable == 0)
|
if(f->readable == 0)
|
||||||
|
|
@ -117,7 +131,9 @@ int fileread(struct file *f, uint64 addr, int n) {
|
||||||
|
|
||||||
// Write to file f.
|
// Write to file f.
|
||||||
// addr is a user virtual address.
|
// addr is a user virtual address.
|
||||||
int filewrite(struct file *f, uint64 addr, int n) {
|
int
|
||||||
|
filewrite(struct file *f, uint64 addr, int n)
|
||||||
|
{
|
||||||
int r, ret = 0;
|
int r, ret = 0;
|
||||||
|
|
||||||
if(f->writable == 0)
|
if(f->writable == 0)
|
||||||
|
|
@ -163,3 +179,4 @@ int filewrite(struct file *f, uint64 addr, int n) {
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
107
kernel/fs.c
107
kernel/fs.c
|
|
@ -27,7 +27,9 @@
|
||||||
struct superblock sb;
|
struct superblock sb;
|
||||||
|
|
||||||
// Read the super block.
|
// Read the super block.
|
||||||
static void readsb(int dev, struct superblock *sb) {
|
static void
|
||||||
|
readsb(int dev, struct superblock *sb)
|
||||||
|
{
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
bp = bread(dev, 1);
|
bp = bread(dev, 1);
|
||||||
|
|
@ -36,7 +38,8 @@ static void readsb(int dev, struct superblock *sb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init fs
|
// Init fs
|
||||||
void fsinit(int dev) {
|
void
|
||||||
|
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");
|
||||||
|
|
@ -44,7 +47,9 @@ void fsinit(int dev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero a block.
|
// Zero a block.
|
||||||
static void bzero(int dev, int bno) {
|
static void
|
||||||
|
bzero(int dev, int bno)
|
||||||
|
{
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
bp = bread(dev, bno);
|
bp = bread(dev, bno);
|
||||||
|
|
@ -57,7 +62,9 @@ static void bzero(int dev, int bno) {
|
||||||
|
|
||||||
// Allocate a zeroed disk block.
|
// Allocate a zeroed disk block.
|
||||||
// returns 0 if out of disk space.
|
// returns 0 if out of disk space.
|
||||||
static uint balloc(uint dev) {
|
static uint
|
||||||
|
balloc(uint dev)
|
||||||
|
{
|
||||||
int b, bi, m;
|
int b, bi, m;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
|
|
@ -81,7 +88,9 @@ static uint balloc(uint dev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free a disk block.
|
// Free a disk block.
|
||||||
static void bfree(int dev, uint b) {
|
static void
|
||||||
|
bfree(int dev, uint b)
|
||||||
|
{
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
int bi, m;
|
int bi, m;
|
||||||
|
|
||||||
|
|
@ -169,7 +178,9 @@ struct {
|
||||||
struct inode inode[NINODE];
|
struct inode inode[NINODE];
|
||||||
} itable;
|
} itable;
|
||||||
|
|
||||||
void iinit() {
|
void
|
||||||
|
iinit()
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
initlock(&itable.lock, "itable");
|
initlock(&itable.lock, "itable");
|
||||||
|
|
@ -183,8 +194,10 @@ static struct inode *iget(uint dev, uint inum);
|
||||||
// Allocate an inode on device dev.
|
// Allocate an inode on device dev.
|
||||||
// Mark it as allocated by giving it type type.
|
// Mark it as allocated by giving it type type.
|
||||||
// Returns an unlocked but allocated and referenced inode,
|
// Returns an unlocked but allocated and referenced inode,
|
||||||
// or NULL if there is no free inode.
|
// or NULL if there is no free inode..
|
||||||
struct inode *ialloc(uint dev, short type) {
|
struct inode*
|
||||||
|
ialloc(uint dev, short type)
|
||||||
|
{
|
||||||
int inum;
|
int inum;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
@ -209,7 +222,9 @@ struct inode *ialloc(uint dev, short type) {
|
||||||
// Must be called after every change to an ip->xxx field
|
// Must be called after every change to an ip->xxx field
|
||||||
// that lives on disk.
|
// that lives on disk.
|
||||||
// Caller must hold ip->lock.
|
// Caller must hold ip->lock.
|
||||||
void iupdate(struct inode *ip) {
|
void
|
||||||
|
iupdate(struct inode *ip)
|
||||||
|
{
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
||||||
|
|
@ -228,7 +243,9 @@ void 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 *iget(uint dev, uint inum) {
|
static struct inode*
|
||||||
|
iget(uint dev, uint inum)
|
||||||
|
{
|
||||||
struct inode *ip, *empty;
|
struct inode *ip, *empty;
|
||||||
|
|
||||||
acquire(&itable.lock);
|
acquire(&itable.lock);
|
||||||
|
|
@ -261,7 +278,9 @@ static struct inode *iget(uint dev, uint inum) {
|
||||||
|
|
||||||
// Increment reference count for ip.
|
// Increment reference count for ip.
|
||||||
// Returns ip to enable ip = idup(ip1) idiom.
|
// Returns ip to enable ip = idup(ip1) idiom.
|
||||||
struct inode *idup(struct inode *ip) {
|
struct inode*
|
||||||
|
idup(struct inode *ip)
|
||||||
|
{
|
||||||
acquire(&itable.lock);
|
acquire(&itable.lock);
|
||||||
ip->ref++;
|
ip->ref++;
|
||||||
release(&itable.lock);
|
release(&itable.lock);
|
||||||
|
|
@ -270,7 +289,9 @@ struct inode *idup(struct inode *ip) {
|
||||||
|
|
||||||
// Lock the given inode.
|
// Lock the given inode.
|
||||||
// Reads the inode from disk if necessary.
|
// Reads the inode from disk if necessary.
|
||||||
void ilock(struct inode *ip) {
|
void
|
||||||
|
ilock(struct inode *ip)
|
||||||
|
{
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
||||||
|
|
@ -296,7 +317,9 @@ void ilock(struct inode *ip) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock the given inode.
|
// Unlock the given inode.
|
||||||
void iunlock(struct inode *ip) {
|
void
|
||||||
|
iunlock(struct inode *ip)
|
||||||
|
{
|
||||||
if(ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
|
if(ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
|
||||||
panic("iunlock");
|
panic("iunlock");
|
||||||
|
|
||||||
|
|
@ -310,7 +333,9 @@ void iunlock(struct inode *ip) {
|
||||||
// to it, free the inode (and its content) on disk.
|
// to it, free the inode (and its content) on disk.
|
||||||
// All calls to iput() must be inside a transaction in
|
// All calls to iput() must be inside a transaction in
|
||||||
// case it has to free the inode.
|
// case it has to free the inode.
|
||||||
void iput(struct inode *ip) {
|
void
|
||||||
|
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){
|
||||||
|
|
@ -337,7 +362,9 @@ void iput(struct inode *ip) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common idiom: unlock, then put.
|
// Common idiom: unlock, then put.
|
||||||
void iunlockput(struct inode *ip) {
|
void
|
||||||
|
iunlockput(struct inode *ip)
|
||||||
|
{
|
||||||
iunlock(ip);
|
iunlock(ip);
|
||||||
iput(ip);
|
iput(ip);
|
||||||
}
|
}
|
||||||
|
|
@ -352,7 +379,9 @@ void iunlockput(struct inode *ip) {
|
||||||
// Return the disk block address of the nth block in inode ip.
|
// Return the disk block address of the nth block in inode ip.
|
||||||
// If there is no such block, bmap allocates one.
|
// If there is no such block, bmap allocates one.
|
||||||
// returns 0 if out of disk space.
|
// returns 0 if out of disk space.
|
||||||
static uint bmap(struct inode *ip, uint bn) {
|
static uint
|
||||||
|
bmap(struct inode *ip, uint bn)
|
||||||
|
{
|
||||||
uint addr, *a;
|
uint addr, *a;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
|
|
@ -393,7 +422,9 @@ static uint bmap(struct inode *ip, uint bn) {
|
||||||
|
|
||||||
// Truncate inode (discard contents).
|
// Truncate inode (discard contents).
|
||||||
// Caller must hold ip->lock.
|
// Caller must hold ip->lock.
|
||||||
void itrunc(struct inode *ip) {
|
void
|
||||||
|
itrunc(struct inode *ip)
|
||||||
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
uint *a;
|
uint *a;
|
||||||
|
|
@ -423,7 +454,9 @@ void itrunc(struct inode *ip) {
|
||||||
|
|
||||||
// Copy stat information from inode.
|
// Copy stat information from inode.
|
||||||
// Caller must hold ip->lock.
|
// Caller must hold ip->lock.
|
||||||
void stati(struct inode *ip, struct stat *st) {
|
void
|
||||||
|
stati(struct inode *ip, struct stat *st)
|
||||||
|
{
|
||||||
st->dev = ip->dev;
|
st->dev = ip->dev;
|
||||||
st->ino = ip->inum;
|
st->ino = ip->inum;
|
||||||
st->type = ip->type;
|
st->type = ip->type;
|
||||||
|
|
@ -435,7 +468,9 @@ void stati(struct inode *ip, struct stat *st) {
|
||||||
// Caller must hold ip->lock.
|
// Caller must hold ip->lock.
|
||||||
// If user_dst==1, then dst is a user virtual address;
|
// If user_dst==1, then dst is a user virtual address;
|
||||||
// otherwise, dst is a kernel address.
|
// otherwise, dst is a kernel address.
|
||||||
int readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n) {
|
int
|
||||||
|
readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)
|
||||||
|
{
|
||||||
uint tot, m;
|
uint tot, m;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
|
|
@ -467,7 +502,9 @@ int readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n) {
|
||||||
// Returns the number of bytes successfully written.
|
// Returns the number of bytes successfully written.
|
||||||
// If the return value is less than the requested n,
|
// If the return value is less than the requested n,
|
||||||
// there was an error of some kind.
|
// there was an error of some kind.
|
||||||
int writei(struct inode *ip, int user_src, uint64 src, uint off, uint n) {
|
int
|
||||||
|
writei(struct inode *ip, int user_src, uint64 src, uint off, uint n)
|
||||||
|
{
|
||||||
uint tot, m;
|
uint tot, m;
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
|
|
@ -503,11 +540,17 @@ int writei(struct inode *ip, int user_src, uint64 src, uint off, uint n) {
|
||||||
|
|
||||||
// Directories
|
// Directories
|
||||||
|
|
||||||
int namecmp(const char *s, const char *t) { return strncmp(s, t, DIRSIZ); }
|
int
|
||||||
|
namecmp(const char *s, const char *t)
|
||||||
|
{
|
||||||
|
return strncmp(s, t, DIRSIZ);
|
||||||
|
}
|
||||||
|
|
||||||
// Look for a directory entry in a directory.
|
// 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 *dirlookup(struct inode *dp, char *name, uint *poff) {
|
struct inode*
|
||||||
|
dirlookup(struct inode *dp, char *name, uint *poff)
|
||||||
|
{
|
||||||
uint off, inum;
|
uint off, inum;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
|
|
||||||
|
|
@ -533,7 +576,9 @@ struct inode *dirlookup(struct inode *dp, char *name, uint *poff) {
|
||||||
|
|
||||||
// Write a new directory entry (name, inum) into the directory dp.
|
// Write a new directory entry (name, inum) into the directory dp.
|
||||||
// Returns 0 on success, -1 on failure (e.g. out of disk blocks).
|
// Returns 0 on success, -1 on failure (e.g. out of disk blocks).
|
||||||
int dirlink(struct inode *dp, char *name, uint inum) {
|
int
|
||||||
|
dirlink(struct inode *dp, char *name, uint inum)
|
||||||
|
{
|
||||||
int off;
|
int off;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
|
|
@ -574,7 +619,9 @@ int dirlink(struct inode *dp, char *name, uint inum) {
|
||||||
// skipelem("a", name) = "", setting name = "a"
|
// skipelem("a", name) = "", setting name = "a"
|
||||||
// skipelem("", name) = skipelem("////", name) = 0
|
// skipelem("", name) = skipelem("////", name) = 0
|
||||||
//
|
//
|
||||||
static char *skipelem(char *path, char *name) {
|
static char*
|
||||||
|
skipelem(char *path, char *name)
|
||||||
|
{
|
||||||
char *s;
|
char *s;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
|
@ -601,7 +648,9 @@ static char *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 *namex(char *path, int nameiparent, char *name) {
|
static struct inode*
|
||||||
|
namex(char *path, int nameiparent, char *name)
|
||||||
|
{
|
||||||
struct inode *ip, *next;
|
struct inode *ip, *next;
|
||||||
|
|
||||||
if(*path == '/')
|
if(*path == '/')
|
||||||
|
|
@ -634,11 +683,15 @@ static struct inode *namex(char *path, int nameiparent, char *name) {
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct inode *namei(char *path) {
|
struct inode*
|
||||||
|
namei(char *path)
|
||||||
|
{
|
||||||
char name[DIRSIZ];
|
char name[DIRSIZ];
|
||||||
return namex(path, 0, name);
|
return namex(path, 0, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct inode *nameiparent(char *path, char *name) {
|
struct inode*
|
||||||
|
nameiparent(char *path, char *name)
|
||||||
|
{
|
||||||
return namex(path, 1, name);
|
return namex(path, 1, name);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,16 @@ struct {
|
||||||
struct run *freelist;
|
struct run *freelist;
|
||||||
} kmem;
|
} kmem;
|
||||||
|
|
||||||
void kinit() {
|
void
|
||||||
|
kinit()
|
||||||
|
{
|
||||||
initlock(&kmem.lock, "kmem");
|
initlock(&kmem.lock, "kmem");
|
||||||
freerange(end, (void*)PHYSTOP);
|
freerange(end, (void*)PHYSTOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void freerange(void *pa_start, void *pa_end) {
|
void
|
||||||
|
freerange(void *pa_start, void *pa_end)
|
||||||
|
{
|
||||||
char *p;
|
char *p;
|
||||||
p = (char*)PGROUNDUP((uint64)pa_start);
|
p = (char*)PGROUNDUP((uint64)pa_start);
|
||||||
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
|
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
|
||||||
|
|
@ -39,7 +43,9 @@ void freerange(void *pa_start, void *pa_end) {
|
||||||
// which normally should have been returned by a
|
// which normally should have been returned by a
|
||||||
// call to kalloc(). (The exception is when
|
// call to kalloc(). (The exception is when
|
||||||
// initializing the allocator; see kinit above.)
|
// initializing the allocator; see kinit above.)
|
||||||
void kfree(void *pa) {
|
void
|
||||||
|
kfree(void *pa)
|
||||||
|
{
|
||||||
struct run *r;
|
struct run *r;
|
||||||
|
|
||||||
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
|
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
|
||||||
|
|
@ -59,7 +65,9 @@ void kfree(void *pa) {
|
||||||
// Allocate one 4096-byte page of physical memory.
|
// Allocate one 4096-byte page of physical memory.
|
||||||
// Returns a pointer that the kernel can use.
|
// Returns a pointer that the kernel can use.
|
||||||
// Returns 0 if the memory cannot be allocated.
|
// Returns 0 if the memory cannot be allocated.
|
||||||
void *kalloc(void) {
|
void *
|
||||||
|
kalloc(void)
|
||||||
|
{
|
||||||
struct run *r;
|
struct run *r;
|
||||||
|
|
||||||
acquire(&kmem.lock);
|
acquire(&kmem.lock);
|
||||||
|
|
|
||||||
44
kernel/log.c
44
kernel/log.c
|
|
@ -51,7 +51,9 @@ struct log log;
|
||||||
static void recover_from_log(void);
|
static void recover_from_log(void);
|
||||||
static void commit();
|
static void commit();
|
||||||
|
|
||||||
void initlog(int dev, struct superblock *sb) {
|
void
|
||||||
|
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");
|
||||||
|
|
||||||
|
|
@ -63,12 +65,13 @@ void initlog(int dev, struct superblock *sb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy committed blocks from log to their home location
|
// Copy committed blocks from log to their home location
|
||||||
static void install_trans(int recovering) {
|
static void
|
||||||
|
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 =
|
struct buf *lbuf = bread(log.dev, log.start+tail+1); // read log block
|
||||||
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
|
||||||
|
|
@ -80,7 +83,9 @@ static void install_trans(int recovering) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the log header from disk into the in-memory log header
|
// Read the log header from disk into the in-memory log header
|
||||||
static void read_head(void) {
|
static 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;
|
||||||
|
|
@ -94,7 +99,9 @@ static void read_head(void) {
|
||||||
// Write in-memory log header to disk.
|
// Write in-memory log header to disk.
|
||||||
// This is the true point at which the
|
// This is the true point at which the
|
||||||
// current transaction commits.
|
// current transaction commits.
|
||||||
static void write_head(void) {
|
static 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;
|
||||||
|
|
@ -106,7 +113,9 @@ static void write_head(void) {
|
||||||
brelse(buf);
|
brelse(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recover_from_log(void) {
|
static void
|
||||||
|
recover_from_log(void)
|
||||||
|
{
|
||||||
read_head();
|
read_head();
|
||||||
install_trans(1); // if committed, copy from log to disk
|
install_trans(1); // if committed, copy from log to disk
|
||||||
log.lh.n = 0;
|
log.lh.n = 0;
|
||||||
|
|
@ -114,7 +123,9 @@ static void recover_from_log(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// called at the start of each FS system call.
|
// called at the start of each FS system call.
|
||||||
void begin_op(void) {
|
void
|
||||||
|
begin_op(void)
|
||||||
|
{
|
||||||
acquire(&log.lock);
|
acquire(&log.lock);
|
||||||
while(1){
|
while(1){
|
||||||
if(log.committing){
|
if(log.committing){
|
||||||
|
|
@ -132,7 +143,9 @@ void begin_op(void) {
|
||||||
|
|
||||||
// called at the end of each FS system call.
|
// called at the end of each FS system call.
|
||||||
// commits if this was the last outstanding operation.
|
// commits if this was the last outstanding operation.
|
||||||
void end_op(void) {
|
void
|
||||||
|
end_op(void)
|
||||||
|
{
|
||||||
int do_commit = 0;
|
int do_commit = 0;
|
||||||
|
|
||||||
acquire(&log.lock);
|
acquire(&log.lock);
|
||||||
|
|
@ -162,7 +175,9 @@ void end_op(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy modified blocks from cache to log.
|
// Copy modified blocks from cache to log.
|
||||||
static void write_log(void) {
|
static void
|
||||||
|
write_log(void)
|
||||||
|
{
|
||||||
int tail;
|
int tail;
|
||||||
|
|
||||||
for (tail = 0; tail < log.lh.n; tail++) {
|
for (tail = 0; tail < log.lh.n; tail++) {
|
||||||
|
|
@ -175,7 +190,9 @@ static void write_log(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void commit() {
|
static void
|
||||||
|
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
|
||||||
|
|
@ -194,7 +211,9 @@ static void commit() {
|
||||||
// modify bp->data[]
|
// modify bp->data[]
|
||||||
// log_write(bp)
|
// log_write(bp)
|
||||||
// brelse(bp)
|
// brelse(bp)
|
||||||
void log_write(struct buf *b) {
|
void
|
||||||
|
log_write(struct buf *b)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
acquire(&log.lock);
|
acquire(&log.lock);
|
||||||
|
|
@ -214,3 +233,4 @@ void log_write(struct buf *b) {
|
||||||
}
|
}
|
||||||
release(&log.lock);
|
release(&log.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,19 @@
|
||||||
#include "memlayout.h"
|
#include "memlayout.h"
|
||||||
#include "riscv.h"
|
#include "riscv.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
extern int32_t add(int32_t right, int32_t left);
|
|
||||||
|
|
||||||
volatile static int started = 0;
|
volatile static int started = 0;
|
||||||
|
|
||||||
// start() jumps here in supervisor mode on all CPUs.
|
// start() jumps here in supervisor mode on all CPUs.
|
||||||
void main() {
|
void
|
||||||
|
main()
|
||||||
|
{
|
||||||
if(cpuid() == 0){
|
if(cpuid() == 0){
|
||||||
consoleinit();
|
consoleinit();
|
||||||
printfinit();
|
printfinit();
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("xv6 kernel is booting\n");
|
printf("xv6 kernel is booting\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("rust library call: add(1, 2) = %d\n", add(1, 2));
|
|
||||||
printf("\n");
|
|
||||||
kinit(); // physical page allocator
|
kinit(); // physical page allocator
|
||||||
kvminit(); // create kernel page table
|
kvminit(); // create kernel page table
|
||||||
kvminithart(); // turn on paging
|
kvminithart(); // turn on paging
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ struct pipe {
|
||||||
int writeopen; // write fd is still open
|
int writeopen; // write fd is still open
|
||||||
};
|
};
|
||||||
|
|
||||||
int pipealloc(struct file **f0, struct file **f1) {
|
int
|
||||||
|
pipealloc(struct file **f0, struct file **f1)
|
||||||
|
{
|
||||||
struct pipe *pi;
|
struct pipe *pi;
|
||||||
|
|
||||||
pi = 0;
|
pi = 0;
|
||||||
|
|
@ -53,7 +55,9 @@ bad:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pipeclose(struct pipe *pi, int writable) {
|
void
|
||||||
|
pipeclose(struct pipe *pi, int writable)
|
||||||
|
{
|
||||||
acquire(&pi->lock);
|
acquire(&pi->lock);
|
||||||
if(writable){
|
if(writable){
|
||||||
pi->writeopen = 0;
|
pi->writeopen = 0;
|
||||||
|
|
@ -69,7 +73,9 @@ void pipeclose(struct pipe *pi, int writable) {
|
||||||
release(&pi->lock);
|
release(&pi->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pipewrite(struct pipe *pi, uint64 addr, int n) {
|
int
|
||||||
|
pipewrite(struct pipe *pi, uint64 addr, int n)
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
struct proc *pr = myproc();
|
struct proc *pr = myproc();
|
||||||
|
|
||||||
|
|
@ -96,7 +102,9 @@ int pipewrite(struct pipe *pi, uint64 addr, int n) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int piperead(struct pipe *pi, uint64 addr, int n) {
|
int
|
||||||
|
piperead(struct pipe *pi, uint64 addr, int n)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
struct proc *pr = myproc();
|
struct proc *pr = myproc();
|
||||||
char ch;
|
char ch;
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,17 @@
|
||||||
// the riscv Platform Level Interrupt Controller (PLIC).
|
// the riscv Platform Level Interrupt Controller (PLIC).
|
||||||
//
|
//
|
||||||
|
|
||||||
void plicinit(void) {
|
void
|
||||||
|
plicinit(void)
|
||||||
|
{
|
||||||
// set desired IRQ priorities non-zero (otherwise disabled).
|
// set desired IRQ priorities non-zero (otherwise disabled).
|
||||||
*(uint32*)(PLIC + UART0_IRQ*4) = 1;
|
*(uint32*)(PLIC + UART0_IRQ*4) = 1;
|
||||||
*(uint32*)(PLIC + VIRTIO0_IRQ*4) = 1;
|
*(uint32*)(PLIC + VIRTIO0_IRQ*4) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void plicinithart(void) {
|
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
|
||||||
|
|
@ -26,14 +30,18 @@ void plicinithart(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ask the PLIC what interrupt we should serve.
|
// ask the PLIC what interrupt we should serve.
|
||||||
int plic_claim(void) {
|
int
|
||||||
|
plic_claim(void)
|
||||||
|
{
|
||||||
int hart = cpuid();
|
int hart = cpuid();
|
||||||
int irq = *(uint32*)PLIC_SCLAIM(hart);
|
int irq = *(uint32*)PLIC_SCLAIM(hart);
|
||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell the PLIC we've served this IRQ.
|
// tell the PLIC we've served this IRQ.
|
||||||
void plic_complete(int irq) {
|
void
|
||||||
|
plic_complete(int irq)
|
||||||
|
{
|
||||||
int hart = cpuid();
|
int hart = cpuid();
|
||||||
*(uint32*)PLIC_SCLAIM(hart) = irq;
|
*(uint32*)PLIC_SCLAIM(hart) = irq;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,9 @@ static struct {
|
||||||
|
|
||||||
static char digits[] = "0123456789abcdef";
|
static char digits[] = "0123456789abcdef";
|
||||||
|
|
||||||
static void printint(int xx, int base, int sign) {
|
static void
|
||||||
|
printint(int xx, int base, int sign)
|
||||||
|
{
|
||||||
char buf[16];
|
char buf[16];
|
||||||
int i;
|
int i;
|
||||||
uint x;
|
uint x;
|
||||||
|
|
@ -47,7 +49,9 @@ static void printint(int xx, int base, int sign) {
|
||||||
consputc(buf[i]);
|
consputc(buf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printptr(uint64 x) {
|
static void
|
||||||
|
printptr(uint64 x)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
consputc('0');
|
consputc('0');
|
||||||
consputc('x');
|
consputc('x');
|
||||||
|
|
@ -56,7 +60,9 @@ static void printptr(uint64 x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print to the console. only understands %d, %x, %p, %s.
|
// Print to the console. only understands %d, %x, %p, %s.
|
||||||
void printf(char *fmt, ...) {
|
void
|
||||||
|
printf(char *fmt, ...)
|
||||||
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int i, c, locking;
|
int i, c, locking;
|
||||||
char *s;
|
char *s;
|
||||||
|
|
@ -109,7 +115,9 @@ void printf(char *fmt, ...) {
|
||||||
release(&pr.lock);
|
release(&pr.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void panic(char *s) {
|
void
|
||||||
|
panic(char *s)
|
||||||
|
{
|
||||||
pr.locking = 0;
|
pr.locking = 0;
|
||||||
printf("panic: ");
|
printf("panic: ");
|
||||||
printf(s);
|
printf(s);
|
||||||
|
|
@ -119,7 +127,9 @@ void panic(char *s) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printfinit(void) {
|
void
|
||||||
|
printfinit(void)
|
||||||
|
{
|
||||||
initlock(&pr.lock, "pr");
|
initlock(&pr.lock, "pr");
|
||||||
pr.locking = 1;
|
pr.locking = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
147
kernel/proc.c
147
kernel/proc.c
|
|
@ -29,7 +29,9 @@ struct spinlock wait_lock;
|
||||||
// Allocate a page for each process's kernel stack.
|
// Allocate a page for each process's kernel stack.
|
||||||
// Map it high in memory, followed by an invalid
|
// Map it high in memory, followed by an invalid
|
||||||
// guard page.
|
// guard page.
|
||||||
void proc_mapstacks(pagetable_t kpgtbl) {
|
void
|
||||||
|
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++) {
|
||||||
|
|
@ -42,7 +44,9 @@ void proc_mapstacks(pagetable_t kpgtbl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the proc table.
|
// initialize the proc table.
|
||||||
void procinit(void) {
|
void
|
||||||
|
procinit(void)
|
||||||
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
initlock(&pid_lock, "nextpid");
|
initlock(&pid_lock, "nextpid");
|
||||||
|
|
@ -57,21 +61,27 @@ void procinit(void) {
|
||||||
// Must be called with interrupts disabled,
|
// Must be called with interrupts disabled,
|
||||||
// to prevent race with process being moved
|
// to prevent race with process being moved
|
||||||
// to a different CPU.
|
// to a different CPU.
|
||||||
int cpuid() {
|
int
|
||||||
|
cpuid()
|
||||||
|
{
|
||||||
int id = r_tp();
|
int id = r_tp();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return this CPU's cpu struct.
|
// Return this CPU's cpu struct.
|
||||||
// Interrupts must be disabled.
|
// Interrupts must be disabled.
|
||||||
struct cpu *mycpu(void) {
|
struct cpu*
|
||||||
|
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 *myproc(void) {
|
struct proc*
|
||||||
|
myproc(void)
|
||||||
|
{
|
||||||
push_off();
|
push_off();
|
||||||
struct cpu *c = mycpu();
|
struct cpu *c = mycpu();
|
||||||
struct proc *p = c->proc;
|
struct proc *p = c->proc;
|
||||||
|
|
@ -79,7 +89,9 @@ struct proc *myproc(void) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
int allocpid() {
|
int
|
||||||
|
allocpid()
|
||||||
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
acquire(&pid_lock);
|
acquire(&pid_lock);
|
||||||
|
|
@ -94,7 +106,9 @@ int 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 *allocproc(void) {
|
static struct proc*
|
||||||
|
allocproc(void)
|
||||||
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
for(p = proc; p < &proc[NPROC]; p++) {
|
for(p = proc; p < &proc[NPROC]; p++) {
|
||||||
|
|
@ -138,7 +152,9 @@ found:
|
||||||
// free a proc structure and the data hanging from it,
|
// free a proc structure and the data hanging from it,
|
||||||
// including user pages.
|
// including user pages.
|
||||||
// p->lock must be held.
|
// p->lock must be held.
|
||||||
static void freeproc(struct proc *p) {
|
static void
|
||||||
|
freeproc(struct proc *p)
|
||||||
|
{
|
||||||
if(p->trapframe)
|
if(p->trapframe)
|
||||||
kfree((void*)p->trapframe);
|
kfree((void*)p->trapframe);
|
||||||
p->trapframe = 0;
|
p->trapframe = 0;
|
||||||
|
|
@ -157,7 +173,9 @@ static void freeproc(struct proc *p) {
|
||||||
|
|
||||||
// Create a user page table for a given process, with no user memory,
|
// Create a user page table for a given process, with no user memory,
|
||||||
// but with trampoline and trapframe pages.
|
// but with trampoline and trapframe pages.
|
||||||
pagetable_t proc_pagetable(struct proc *p) {
|
pagetable_t
|
||||||
|
proc_pagetable(struct proc *p)
|
||||||
|
{
|
||||||
pagetable_t pagetable;
|
pagetable_t pagetable;
|
||||||
|
|
||||||
// An empty page table.
|
// An empty page table.
|
||||||
|
|
@ -169,16 +187,16 @@ pagetable_t 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, (uint64)trampoline,
|
if(mappages(pagetable, TRAMPOLINE, PGSIZE,
|
||||||
PTE_R | PTE_X) < 0) {
|
(uint64)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, (uint64)(p->trapframe),
|
if(mappages(pagetable, TRAPFRAME, PGSIZE,
|
||||||
PTE_R | PTE_W) < 0) {
|
(uint64)(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;
|
||||||
|
|
@ -189,7 +207,9 @@ pagetable_t proc_pagetable(struct proc *p) {
|
||||||
|
|
||||||
// Free a process's page table, and free the
|
// Free a process's page table, and free the
|
||||||
// physical memory it refers to.
|
// physical memory it refers to.
|
||||||
void proc_freepagetable(pagetable_t pagetable, uint64 sz) {
|
void
|
||||||
|
proc_freepagetable(pagetable_t pagetable, uint64 sz)
|
||||||
|
{
|
||||||
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
|
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
|
||||||
uvmunmap(pagetable, TRAPFRAME, 1, 0);
|
uvmunmap(pagetable, TRAPFRAME, 1, 0);
|
||||||
uvmfree(pagetable, sz);
|
uvmfree(pagetable, sz);
|
||||||
|
|
@ -198,15 +218,20 @@ void proc_freepagetable(pagetable_t pagetable, uint64 sz) {
|
||||||
// a user program that calls exec("/init")
|
// a user program that calls exec("/init")
|
||||||
// assembled from ../user/initcode.S
|
// assembled from ../user/initcode.S
|
||||||
// od -t xC ../user/initcode
|
// od -t xC ../user/initcode
|
||||||
uchar initcode[] = {0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x02, 0x97,
|
uchar initcode[] = {
|
||||||
0x05, 0x00, 0x00, 0x93, 0x85, 0x35, 0x02, 0x93, 0x08,
|
0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x02,
|
||||||
0x70, 0x00, 0x73, 0x00, 0x00, 0x00, 0x93, 0x08, 0x20,
|
0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x35, 0x02,
|
||||||
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,
|
0x93, 0x08, 0x20, 0x00, 0x73, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 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 userinit(void) {
|
void
|
||||||
|
userinit(void)
|
||||||
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
p = allocproc();
|
p = allocproc();
|
||||||
|
|
@ -231,7 +256,9 @@ void userinit(void) {
|
||||||
|
|
||||||
// Grow or shrink user memory by n bytes.
|
// Grow or shrink user memory by n bytes.
|
||||||
// Return 0 on success, -1 on failure.
|
// Return 0 on success, -1 on failure.
|
||||||
int growproc(int n) {
|
int
|
||||||
|
growproc(int n)
|
||||||
|
{
|
||||||
uint64 sz;
|
uint64 sz;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
|
|
@ -249,7 +276,9 @@ int growproc(int n) {
|
||||||
|
|
||||||
// Create a new process, copying the parent.
|
// Create a new process, copying the parent.
|
||||||
// Sets up child kernel stack to return as if from fork() system call.
|
// Sets up child kernel stack to return as if from fork() system call.
|
||||||
int fork(void) {
|
int
|
||||||
|
fork(void)
|
||||||
|
{
|
||||||
int i, pid;
|
int i, pid;
|
||||||
struct proc *np;
|
struct proc *np;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
@ -298,7 +327,9 @@ int fork(void) {
|
||||||
|
|
||||||
// Pass p's abandoned children to init.
|
// Pass p's abandoned children to init.
|
||||||
// Caller must hold wait_lock.
|
// Caller must hold wait_lock.
|
||||||
void reparent(struct proc *p) {
|
void
|
||||||
|
reparent(struct proc *p)
|
||||||
|
{
|
||||||
struct proc *pp;
|
struct proc *pp;
|
||||||
|
|
||||||
for(pp = proc; pp < &proc[NPROC]; pp++){
|
for(pp = proc; pp < &proc[NPROC]; pp++){
|
||||||
|
|
@ -312,7 +343,9 @@ void reparent(struct proc *p) {
|
||||||
// Exit the current process. Does not return.
|
// Exit the current process. Does not return.
|
||||||
// An exited process remains in the zombie state
|
// An exited process remains in the zombie state
|
||||||
// until its parent calls wait().
|
// until its parent calls wait().
|
||||||
void exit(int status) {
|
void
|
||||||
|
exit(int status)
|
||||||
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
if(p == initproc)
|
if(p == initproc)
|
||||||
|
|
@ -354,7 +387,9 @@ void exit(int status) {
|
||||||
|
|
||||||
// Wait for a child process to exit and return its pid.
|
// Wait for a child process to exit and return its pid.
|
||||||
// Return -1 if this process has no children.
|
// Return -1 if this process has no children.
|
||||||
int wait(uint64 addr) {
|
int
|
||||||
|
wait(uint64 addr)
|
||||||
|
{
|
||||||
struct proc *pp;
|
struct proc *pp;
|
||||||
int havekids, pid;
|
int havekids, pid;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
@ -373,8 +408,7 @@ int wait(uint64 addr) {
|
||||||
if(pp->state == ZOMBIE){
|
if(pp->state == ZOMBIE){
|
||||||
// Found one.
|
// Found one.
|
||||||
pid = pp->pid;
|
pid = pp->pid;
|
||||||
if (addr != 0 &&
|
if(addr != 0 && copyout(p->pagetable, addr, (char *)&pp->xstate,
|
||||||
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);
|
||||||
|
|
@ -407,7 +441,9 @@ int wait(uint64 addr) {
|
||||||
// - swtch to start running that process.
|
// - swtch to start running that process.
|
||||||
// - eventually that process transfers control
|
// - eventually that process transfers control
|
||||||
// via swtch back to the scheduler.
|
// via swtch back to the scheduler.
|
||||||
void scheduler(void) {
|
void
|
||||||
|
scheduler(void)
|
||||||
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
struct cpu *c = mycpu();
|
struct cpu *c = mycpu();
|
||||||
|
|
||||||
|
|
@ -442,7 +478,9 @@ void scheduler(void) {
|
||||||
// be proc->intena and proc->noff, but that would
|
// be proc->intena and proc->noff, but that would
|
||||||
// break in the few places where a lock is held but
|
// break in the few places where a lock is held but
|
||||||
// there's no process.
|
// there's no process.
|
||||||
void sched(void) {
|
void
|
||||||
|
sched(void)
|
||||||
|
{
|
||||||
int intena;
|
int intena;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
|
|
@ -461,7 +499,9 @@ void sched(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give up the CPU for one scheduling round.
|
// Give up the CPU for one scheduling round.
|
||||||
void yield(void) {
|
void
|
||||||
|
yield(void)
|
||||||
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
acquire(&p->lock);
|
acquire(&p->lock);
|
||||||
p->state = RUNNABLE;
|
p->state = RUNNABLE;
|
||||||
|
|
@ -471,7 +511,9 @@ void yield(void) {
|
||||||
|
|
||||||
// A fork child's very first scheduling by scheduler()
|
// A fork child's very first scheduling by scheduler()
|
||||||
// will swtch to forkret.
|
// will swtch to forkret.
|
||||||
void forkret(void) {
|
void
|
||||||
|
forkret(void)
|
||||||
|
{
|
||||||
static int first = 1;
|
static int first = 1;
|
||||||
|
|
||||||
// Still holding p->lock from scheduler.
|
// Still holding p->lock from scheduler.
|
||||||
|
|
@ -490,7 +532,9 @@ void forkret(void) {
|
||||||
|
|
||||||
// Atomically release lock and sleep on chan.
|
// Atomically release lock and sleep on chan.
|
||||||
// Reacquires lock when awakened.
|
// Reacquires lock when awakened.
|
||||||
void sleep(void *chan, struct spinlock *lk) {
|
void
|
||||||
|
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
|
||||||
|
|
@ -519,7 +563,9 @@ void sleep(void *chan, struct spinlock *lk) {
|
||||||
|
|
||||||
// Wake up all processes sleeping on chan.
|
// Wake up all processes sleeping on chan.
|
||||||
// Must be called without any p->lock.
|
// Must be called without any p->lock.
|
||||||
void wakeup(void *chan) {
|
void
|
||||||
|
wakeup(void *chan)
|
||||||
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
for(p = proc; p < &proc[NPROC]; p++) {
|
for(p = proc; p < &proc[NPROC]; p++) {
|
||||||
|
|
@ -536,7 +582,9 @@ void wakeup(void *chan) {
|
||||||
// Kill the process with the given pid.
|
// Kill the process with the given pid.
|
||||||
// The victim won't exit until it tries to return
|
// The victim won't exit until it tries to return
|
||||||
// to user space (see usertrap() in trap.c).
|
// to user space (see usertrap() in trap.c).
|
||||||
int kill(int pid) {
|
int
|
||||||
|
kill(int pid)
|
||||||
|
{
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
for(p = proc; p < &proc[NPROC]; p++){
|
for(p = proc; p < &proc[NPROC]; p++){
|
||||||
|
|
@ -555,13 +603,17 @@ int kill(int pid) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setkilled(struct proc *p) {
|
void
|
||||||
|
setkilled(struct proc *p)
|
||||||
|
{
|
||||||
acquire(&p->lock);
|
acquire(&p->lock);
|
||||||
p->killed = 1;
|
p->killed = 1;
|
||||||
release(&p->lock);
|
release(&p->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int killed(struct proc *p) {
|
int
|
||||||
|
killed(struct proc *p)
|
||||||
|
{
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
acquire(&p->lock);
|
acquire(&p->lock);
|
||||||
|
|
@ -573,7 +625,9 @@ int killed(struct proc *p) {
|
||||||
// Copy to either a user address, or kernel address,
|
// Copy to either a user address, or kernel address,
|
||||||
// depending on usr_dst.
|
// depending on usr_dst.
|
||||||
// Returns 0 on success, -1 on error.
|
// Returns 0 on success, -1 on error.
|
||||||
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len) {
|
int
|
||||||
|
either_copyout(int user_dst, uint64 dst, void *src, uint64 len)
|
||||||
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
if(user_dst){
|
if(user_dst){
|
||||||
return copyout(p->pagetable, dst, src, len);
|
return copyout(p->pagetable, dst, src, len);
|
||||||
|
|
@ -586,7 +640,9 @@ int either_copyout(int user_dst, uint64 dst, void *src, uint64 len) {
|
||||||
// Copy from either a user address, or kernel address,
|
// Copy from either a user address, or kernel address,
|
||||||
// depending on usr_src.
|
// depending on usr_src.
|
||||||
// Returns 0 on success, -1 on error.
|
// Returns 0 on success, -1 on error.
|
||||||
int either_copyin(void *dst, int user_src, uint64 src, uint64 len) {
|
int
|
||||||
|
either_copyin(void *dst, int user_src, uint64 src, uint64 len)
|
||||||
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
if(user_src){
|
if(user_src){
|
||||||
return copyin(p->pagetable, dst, src, len);
|
return copyin(p->pagetable, dst, src, len);
|
||||||
|
|
@ -599,10 +655,17 @@ int either_copyin(void *dst, int user_src, uint64 src, uint64 len) {
|
||||||
// Print a process listing to console. For debugging.
|
// Print a process listing to console. For debugging.
|
||||||
// Runs when user types ^P on console.
|
// Runs when user types ^P on console.
|
||||||
// No lock to avoid wedging a stuck machine further.
|
// No lock to avoid wedging a stuck machine further.
|
||||||
void procdump(void) {
|
void
|
||||||
|
procdump(void)
|
||||||
|
{
|
||||||
static char *states[] = {
|
static char *states[] = {
|
||||||
[UNUSED] "unused", [USED] "used", [SLEEPING] "sleep ",
|
[UNUSED] "unused",
|
||||||
[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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,16 @@
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "buf.h"
|
#include "buf.h"
|
||||||
|
|
||||||
void ramdiskinit(void) {}
|
void
|
||||||
|
ramdiskinit(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
|
// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
|
||||||
// Else if B_VALID is not set, read buf from disk, set B_VALID.
|
// Else if B_VALID is not set, read buf from disk, set B_VALID.
|
||||||
void ramdiskrw(struct buf *b) {
|
void
|
||||||
|
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)
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,18 @@
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "sleeplock.h"
|
#include "sleeplock.h"
|
||||||
|
|
||||||
void initsleeplock(struct sleeplock *lk, char *name) {
|
void
|
||||||
|
initsleeplock(struct sleeplock *lk, char *name)
|
||||||
|
{
|
||||||
initlock(&lk->lk, "sleep lock");
|
initlock(&lk->lk, "sleep lock");
|
||||||
lk->name = name;
|
lk->name = name;
|
||||||
lk->locked = 0;
|
lk->locked = 0;
|
||||||
lk->pid = 0;
|
lk->pid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void acquiresleep(struct sleeplock *lk) {
|
void
|
||||||
|
acquiresleep(struct sleeplock *lk)
|
||||||
|
{
|
||||||
acquire(&lk->lk);
|
acquire(&lk->lk);
|
||||||
while (lk->locked) {
|
while (lk->locked) {
|
||||||
sleep(lk, &lk->lk);
|
sleep(lk, &lk->lk);
|
||||||
|
|
@ -26,7 +30,9 @@ void acquiresleep(struct sleeplock *lk) {
|
||||||
release(&lk->lk);
|
release(&lk->lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void releasesleep(struct sleeplock *lk) {
|
void
|
||||||
|
releasesleep(struct sleeplock *lk)
|
||||||
|
{
|
||||||
acquire(&lk->lk);
|
acquire(&lk->lk);
|
||||||
lk->locked = 0;
|
lk->locked = 0;
|
||||||
lk->pid = 0;
|
lk->pid = 0;
|
||||||
|
|
@ -34,7 +40,9 @@ void releasesleep(struct sleeplock *lk) {
|
||||||
release(&lk->lk);
|
release(&lk->lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
int holdingsleep(struct sleeplock *lk) {
|
int
|
||||||
|
holdingsleep(struct sleeplock *lk)
|
||||||
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
acquire(&lk->lk);
|
acquire(&lk->lk);
|
||||||
|
|
@ -42,3 +50,6 @@ int holdingsleep(struct sleeplock *lk) {
|
||||||
release(&lk->lk);
|
release(&lk->lk);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
void initlock(struct spinlock *lk, char *name) {
|
void
|
||||||
|
initlock(struct spinlock *lk, char *name)
|
||||||
|
{
|
||||||
lk->name = name;
|
lk->name = name;
|
||||||
lk->locked = 0;
|
lk->locked = 0;
|
||||||
lk->cpu = 0;
|
lk->cpu = 0;
|
||||||
|
|
@ -16,7 +18,9 @@ void initlock(struct spinlock *lk, char *name) {
|
||||||
|
|
||||||
// Acquire the lock.
|
// Acquire the lock.
|
||||||
// Loops (spins) until the lock is acquired.
|
// Loops (spins) until the lock is acquired.
|
||||||
void acquire(struct spinlock *lk) {
|
void
|
||||||
|
acquire(struct spinlock *lk)
|
||||||
|
{
|
||||||
push_off(); // disable interrupts to avoid deadlock.
|
push_off(); // disable interrupts to avoid deadlock.
|
||||||
if(holding(lk))
|
if(holding(lk))
|
||||||
panic("acquire");
|
panic("acquire");
|
||||||
|
|
@ -39,7 +43,9 @@ void acquire(struct spinlock *lk) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the lock.
|
// Release the lock.
|
||||||
void release(struct spinlock *lk) {
|
void
|
||||||
|
release(struct spinlock *lk)
|
||||||
|
{
|
||||||
if(!holding(lk))
|
if(!holding(lk))
|
||||||
panic("release");
|
panic("release");
|
||||||
|
|
||||||
|
|
@ -67,7 +73,9 @@ void release(struct spinlock *lk) {
|
||||||
|
|
||||||
// Check whether this cpu is holding the lock.
|
// Check whether this cpu is holding the lock.
|
||||||
// Interrupts must be off.
|
// Interrupts must be off.
|
||||||
int holding(struct spinlock *lk) {
|
int
|
||||||
|
holding(struct spinlock *lk)
|
||||||
|
{
|
||||||
int r;
|
int r;
|
||||||
r = (lk->locked && lk->cpu == mycpu());
|
r = (lk->locked && lk->cpu == mycpu());
|
||||||
return r;
|
return r;
|
||||||
|
|
@ -77,7 +85,9 @@ int holding(struct spinlock *lk) {
|
||||||
// it takes two pop_off()s to undo two push_off()s. Also, if interrupts
|
// it takes two pop_off()s to undo two push_off()s. Also, if interrupts
|
||||||
// are initially off, then push_off, pop_off leaves them off.
|
// are initially off, then push_off, pop_off leaves them off.
|
||||||
|
|
||||||
void push_off(void) {
|
void
|
||||||
|
push_off(void)
|
||||||
|
{
|
||||||
int old = intr_get();
|
int old = intr_get();
|
||||||
|
|
||||||
intr_off();
|
intr_off();
|
||||||
|
|
@ -86,7 +96,9 @@ void push_off(void) {
|
||||||
mycpu()->noff += 1;
|
mycpu()->noff += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_off(void) {
|
void
|
||||||
|
pop_off(void)
|
||||||
|
{
|
||||||
struct cpu *c = mycpu();
|
struct cpu *c = mycpu();
|
||||||
if(intr_get())
|
if(intr_get())
|
||||||
panic("pop_off - interruptible");
|
panic("pop_off - interruptible");
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@ uint64 timer_scratch[NCPU][5];
|
||||||
extern void timervec();
|
extern void timervec();
|
||||||
|
|
||||||
// entry.S jumps here in machine mode on stack0.
|
// entry.S jumps here in machine mode on stack0.
|
||||||
void start() {
|
void
|
||||||
|
start()
|
||||||
|
{
|
||||||
// set M Previous Privilege mode to Supervisor, for mret.
|
// set M Previous Privilege mode to Supervisor, for mret.
|
||||||
unsigned long x = r_mstatus();
|
unsigned long x = r_mstatus();
|
||||||
x &= ~MSTATUS_MPP_MASK;
|
x &= ~MSTATUS_MPP_MASK;
|
||||||
|
|
@ -57,7 +59,9 @@ void start() {
|
||||||
// at timervec in kernelvec.S,
|
// at timervec in kernelvec.S,
|
||||||
// which turns them into software interrupts for
|
// which turns them into software interrupts for
|
||||||
// devintr() in trap.c.
|
// devintr() in trap.c.
|
||||||
void timerinit() {
|
void
|
||||||
|
timerinit()
|
||||||
|
{
|
||||||
// each CPU has a separate source of timer interrupts.
|
// each CPU has a separate source of timer interrupts.
|
||||||
int id = r_mhartid();
|
int id = r_mhartid();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
void *memset(void *dst, int c, uint n) {
|
void*
|
||||||
|
memset(void *dst, int c, uint n)
|
||||||
|
{
|
||||||
char *cdst = (char *) dst;
|
char *cdst = (char *) dst;
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < n; i++){
|
for(i = 0; i < n; i++){
|
||||||
|
|
@ -9,7 +11,9 @@ void *memset(void *dst, int c, uint n) {
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
int memcmp(const void *v1, const void *v2, uint n) {
|
int
|
||||||
|
memcmp(const void *v1, const void *v2, uint n)
|
||||||
|
{
|
||||||
const uchar *s1, *s2;
|
const uchar *s1, *s2;
|
||||||
|
|
||||||
s1 = v1;
|
s1 = v1;
|
||||||
|
|
@ -23,7 +27,9 @@ int memcmp(const void *v1, const void *v2, uint n) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *memmove(void *dst, const void *src, uint n) {
|
void*
|
||||||
|
memmove(void *dst, const void *src, uint n)
|
||||||
|
{
|
||||||
const char *s;
|
const char *s;
|
||||||
char *d;
|
char *d;
|
||||||
|
|
||||||
|
|
@ -45,11 +51,15 @@ void *memmove(void *dst, const void *src, uint n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// memcpy exists to placate GCC. Use memmove.
|
// memcpy exists to placate GCC. Use memmove.
|
||||||
void *memcpy(void *dst, const void *src, uint n) {
|
void*
|
||||||
|
memcpy(void *dst, const void *src, uint n)
|
||||||
|
{
|
||||||
return memmove(dst, src, n);
|
return memmove(dst, src, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
int strncmp(const char *p, const char *q, uint n) {
|
int
|
||||||
|
strncmp(const char *p, const char *q, uint n)
|
||||||
|
{
|
||||||
while(n > 0 && *p && *p == *q)
|
while(n > 0 && *p && *p == *q)
|
||||||
n--, p++, q++;
|
n--, p++, q++;
|
||||||
if(n == 0)
|
if(n == 0)
|
||||||
|
|
@ -57,7 +67,9 @@ int strncmp(const char *p, const char *q, uint n) {
|
||||||
return (uchar)*p - (uchar)*q;
|
return (uchar)*p - (uchar)*q;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *strncpy(char *s, const char *t, int n) {
|
char*
|
||||||
|
strncpy(char *s, const char *t, int n)
|
||||||
|
{
|
||||||
char *os;
|
char *os;
|
||||||
|
|
||||||
os = s;
|
os = s;
|
||||||
|
|
@ -69,7 +81,9 @@ char *strncpy(char *s, const char *t, int n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like strncpy but guaranteed to NUL-terminate.
|
// Like strncpy but guaranteed to NUL-terminate.
|
||||||
char *safestrcpy(char *s, const char *t, int n) {
|
char*
|
||||||
|
safestrcpy(char *s, const char *t, int n)
|
||||||
|
{
|
||||||
char *os;
|
char *os;
|
||||||
|
|
||||||
os = s;
|
os = s;
|
||||||
|
|
@ -81,10 +95,13 @@ char *safestrcpy(char *s, const char *t, int n) {
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
int strlen(const char *s) {
|
int
|
||||||
|
strlen(const char *s)
|
||||||
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
for(n = 0; s[n]; n++)
|
for(n = 0; s[n]; n++)
|
||||||
;
|
;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,11 @@
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
// Fetch the uint64 at addr from the current process.
|
// Fetch the uint64 at addr from the current process.
|
||||||
int fetchaddr(uint64 addr, uint64 *ip) {
|
int
|
||||||
|
fetchaddr(uint64 addr, uint64 *ip)
|
||||||
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
if (addr >= p->sz ||
|
if(addr >= p->sz || addr+sizeof(uint64) > p->sz) // both tests needed, in case of overflow
|
||||||
addr + sizeof(uint64) > p->sz) // both tests needed, in case of overflow
|
|
||||||
return -1;
|
return -1;
|
||||||
if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
|
if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -20,14 +21,18 @@ int fetchaddr(uint64 addr, uint64 *ip) {
|
||||||
|
|
||||||
// Fetch the nul-terminated string at addr from the current process.
|
// Fetch the nul-terminated string at addr from the current process.
|
||||||
// Returns length of string, not including nul, or -1 for error.
|
// Returns length of string, not including nul, or -1 for error.
|
||||||
int fetchstr(uint64 addr, char *buf, int max) {
|
int
|
||||||
|
fetchstr(uint64 addr, char *buf, int max)
|
||||||
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
if(copyinstr(p->pagetable, buf, addr, max) < 0)
|
if(copyinstr(p->pagetable, buf, addr, max) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return strlen(buf);
|
return strlen(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64 argraw(int n) {
|
static uint64
|
||||||
|
argraw(int n)
|
||||||
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
@ -48,23 +53,32 @@ static uint64 argraw(int n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the nth 32-bit system call argument.
|
// Fetch the nth 32-bit system call argument.
|
||||||
void argint(int n, int *ip) { *ip = argraw(n); }
|
void
|
||||||
|
argint(int n, int *ip)
|
||||||
|
{
|
||||||
|
*ip = argraw(n);
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve an argument as a pointer.
|
// Retrieve an argument as a pointer.
|
||||||
// Doesn't check for legality, since
|
// Doesn't check for legality, since
|
||||||
// copyin/copyout will do that.
|
// copyin/copyout will do that.
|
||||||
void argaddr(int n, uint64 *ip) { *ip = argraw(n); }
|
void
|
||||||
|
argaddr(int n, uint64 *ip)
|
||||||
|
{
|
||||||
|
*ip = argraw(n);
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch the nth word-sized system call argument as a null-terminated string.
|
// Fetch the nth word-sized system call argument as a null-terminated string.
|
||||||
// Copies into buf, at most max.
|
// Copies into buf, at most max.
|
||||||
// Returns string length if OK (including nul), -1 if error.
|
// Returns string length if OK (including nul), -1 if error.
|
||||||
int argstr(int n, char *buf, int max) {
|
int
|
||||||
|
argstr(int n, char *buf, int max)
|
||||||
|
{
|
||||||
uint64 addr;
|
uint64 addr;
|
||||||
argaddr(n, &addr);
|
argaddr(n, &addr);
|
||||||
return fetchstr(addr, buf, max);
|
return fetchstr(addr, buf, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prototypes for the functions that handle system calls.
|
|
||||||
extern uint64 sys_fork(void);
|
extern uint64 sys_fork(void);
|
||||||
extern uint64 sys_exit(void);
|
extern uint64 sys_exit(void);
|
||||||
extern uint64 sys_wait(void);
|
extern uint64 sys_wait(void);
|
||||||
|
|
@ -87,29 +101,42 @@ extern uint64 sys_link(void);
|
||||||
extern uint64 sys_mkdir(void);
|
extern uint64 sys_mkdir(void);
|
||||||
extern uint64 sys_close(void);
|
extern uint64 sys_close(void);
|
||||||
|
|
||||||
// An array mapping syscall numbers from syscall.h
|
|
||||||
// to the function that handles the system call.
|
|
||||||
static uint64 (*syscalls[])(void) = {
|
static uint64 (*syscalls[])(void) = {
|
||||||
[SYS_fork] sys_fork, [SYS_exit] sys_exit, [SYS_wait] sys_wait,
|
[SYS_fork] sys_fork,
|
||||||
[SYS_pipe] sys_pipe, [SYS_read] sys_read, [SYS_kill] sys_kill,
|
[SYS_exit] sys_exit,
|
||||||
[SYS_exec] sys_exec, [SYS_fstat] sys_fstat, [SYS_chdir] sys_chdir,
|
[SYS_wait] sys_wait,
|
||||||
[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_read] sys_read,
|
||||||
[SYS_write] sys_write, [SYS_mknod] sys_mknod, [SYS_unlink] sys_unlink,
|
[SYS_kill] sys_kill,
|
||||||
[SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [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 syscall(void) {
|
void
|
||||||
|
syscall(void)
|
||||||
|
{
|
||||||
int num;
|
int num;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
num = p->trapframe->a7;
|
num = p->trapframe->a7;
|
||||||
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
|
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
|
||||||
// Use num to lookup the system call function for num, call it,
|
|
||||||
// and store its return value in p->trapframe->a0
|
|
||||||
p->trapframe->a0 = syscalls[num]();
|
p->trapframe->a0 = syscalls[num]();
|
||||||
} else {
|
} else {
|
||||||
printf("%d %s: unknown sys call %d\n", p->pid, p->name, num);
|
printf("%d %s: unknown sys call %d\n",
|
||||||
|
p->pid, p->name, num);
|
||||||
p->trapframe->a0 = -1;
|
p->trapframe->a0 = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@
|
||||||
|
|
||||||
// Fetch the nth word-sized system call argument as a file descriptor
|
// Fetch the nth word-sized system call argument as a file descriptor
|
||||||
// and return both the descriptor and the corresponding struct file.
|
// and return both the descriptor and the corresponding struct file.
|
||||||
static int argfd(int n, int *pfd, struct file **pf) {
|
static int
|
||||||
|
argfd(int n, int *pfd, struct file **pf)
|
||||||
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
|
|
||||||
|
|
@ -34,7 +36,9 @@ static int argfd(int n, int *pfd, struct file **pf) {
|
||||||
|
|
||||||
// Allocate a file descriptor for the given file.
|
// Allocate a file descriptor for the given file.
|
||||||
// Takes over file reference from caller on success.
|
// Takes over file reference from caller on success.
|
||||||
static int fdalloc(struct file *f) {
|
static int
|
||||||
|
fdalloc(struct file *f)
|
||||||
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
|
|
@ -47,7 +51,9 @@ static int fdalloc(struct file *f) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_dup(void) {
|
uint64
|
||||||
|
sys_dup(void)
|
||||||
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
|
@ -59,7 +65,9 @@ uint64 sys_dup(void) {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_read(void) {
|
uint64
|
||||||
|
sys_read(void)
|
||||||
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int n;
|
int n;
|
||||||
uint64 p;
|
uint64 p;
|
||||||
|
|
@ -71,7 +79,9 @@ uint64 sys_read(void) {
|
||||||
return fileread(f, p, n);
|
return fileread(f, p, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_write(void) {
|
uint64
|
||||||
|
sys_write(void)
|
||||||
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int n;
|
int n;
|
||||||
uint64 p;
|
uint64 p;
|
||||||
|
|
@ -84,7 +94,9 @@ uint64 sys_write(void) {
|
||||||
return filewrite(f, p, n);
|
return filewrite(f, p, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_close(void) {
|
uint64
|
||||||
|
sys_close(void)
|
||||||
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
|
|
||||||
|
|
@ -95,7 +107,9 @@ uint64 sys_close(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_fstat(void) {
|
uint64
|
||||||
|
sys_fstat(void)
|
||||||
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
uint64 st; // user pointer to struct stat
|
uint64 st; // user pointer to struct stat
|
||||||
|
|
||||||
|
|
@ -106,7 +120,9 @@ uint64 sys_fstat(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the path new as a link to the same inode as old.
|
// Create the path new as a link to the same inode as old.
|
||||||
uint64 sys_link(void) {
|
uint64
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
@ -154,7 +170,9 @@ bad:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is the directory dp empty except for "." and ".." ?
|
// Is the directory dp empty except for "." and ".." ?
|
||||||
static int isdirempty(struct inode *dp) {
|
static int
|
||||||
|
isdirempty(struct inode *dp)
|
||||||
|
{
|
||||||
int off;
|
int off;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
|
|
||||||
|
|
@ -167,7 +185,9 @@ static int isdirempty(struct inode *dp) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_unlink(void) {
|
uint64
|
||||||
|
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];
|
||||||
|
|
@ -222,7 +242,9 @@ bad:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct inode *create(char *path, short type, short major, short minor) {
|
static struct inode*
|
||||||
|
create(char *path, short type, short major, short minor)
|
||||||
|
{
|
||||||
struct inode *ip, *dp;
|
struct inode *ip, *dp;
|
||||||
char name[DIRSIZ];
|
char name[DIRSIZ];
|
||||||
|
|
||||||
|
|
@ -279,7 +301,9 @@ fail:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_open(void) {
|
uint64
|
||||||
|
sys_open(void)
|
||||||
|
{
|
||||||
char path[MAXPATH];
|
char path[MAXPATH];
|
||||||
int fd, omode;
|
int fd, omode;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
|
|
@ -346,7 +370,9 @@ uint64 sys_open(void) {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_mkdir(void) {
|
uint64
|
||||||
|
sys_mkdir(void)
|
||||||
|
{
|
||||||
char path[MAXPATH];
|
char path[MAXPATH];
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
|
|
||||||
|
|
@ -360,7 +386,9 @@ uint64 sys_mkdir(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_mknod(void) {
|
uint64
|
||||||
|
sys_mknod(void)
|
||||||
|
{
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
char path[MAXPATH];
|
char path[MAXPATH];
|
||||||
int major, minor;
|
int major, minor;
|
||||||
|
|
@ -378,7 +406,9 @@ uint64 sys_mknod(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_chdir(void) {
|
uint64
|
||||||
|
sys_chdir(void)
|
||||||
|
{
|
||||||
char path[MAXPATH];
|
char path[MAXPATH];
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
@ -401,7 +431,9 @@ uint64 sys_chdir(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_exec(void) {
|
uint64
|
||||||
|
sys_exec(void)
|
||||||
|
{
|
||||||
char path[MAXPATH], *argv[MAXARG];
|
char path[MAXPATH], *argv[MAXARG];
|
||||||
int i;
|
int i;
|
||||||
uint64 uargv, uarg;
|
uint64 uargv, uarg;
|
||||||
|
|
@ -442,7 +474,9 @@ bad:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_pipe(void) {
|
uint64
|
||||||
|
sys_pipe(void)
|
||||||
|
{
|
||||||
uint64 fdarray; // user pointer to array of two integers
|
uint64 fdarray; // user pointer to array of two integers
|
||||||
struct file *rf, *wf;
|
struct file *rf, *wf;
|
||||||
int fd0, fd1;
|
int fd0, fd1;
|
||||||
|
|
@ -460,8 +494,7 @@ uint64 sys_pipe(void) {
|
||||||
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,
|
copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){
|
||||||
sizeof(fd1)) < 0) {
|
|
||||||
p->ofile[fd0] = 0;
|
p->ofile[fd0] = 0;
|
||||||
p->ofile[fd1] = 0;
|
p->ofile[fd1] = 0;
|
||||||
fileclose(rf);
|
fileclose(rf);
|
||||||
|
|
|
||||||
|
|
@ -6,24 +6,38 @@
|
||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
|
|
||||||
uint64 sys_exit(void) {
|
uint64
|
||||||
|
sys_exit(void)
|
||||||
|
{
|
||||||
int n;
|
int n;
|
||||||
argint(0, &n);
|
argint(0, &n);
|
||||||
exit(n);
|
exit(n);
|
||||||
return 0; // not reached
|
return 0; // not reached
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_getpid(void) { return myproc()->pid; }
|
uint64
|
||||||
|
sys_getpid(void)
|
||||||
|
{
|
||||||
|
return myproc()->pid;
|
||||||
|
}
|
||||||
|
|
||||||
uint64 sys_fork(void) { return fork(); }
|
uint64
|
||||||
|
sys_fork(void)
|
||||||
|
{
|
||||||
|
return fork();
|
||||||
|
}
|
||||||
|
|
||||||
uint64 sys_wait(void) {
|
uint64
|
||||||
|
sys_wait(void)
|
||||||
|
{
|
||||||
uint64 p;
|
uint64 p;
|
||||||
argaddr(0, &p);
|
argaddr(0, &p);
|
||||||
return wait(p);
|
return wait(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_sbrk(void) {
|
uint64
|
||||||
|
sys_sbrk(void)
|
||||||
|
{
|
||||||
uint64 addr;
|
uint64 addr;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
|
@ -34,7 +48,9 @@ uint64 sys_sbrk(void) {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_sleep(void) {
|
uint64
|
||||||
|
sys_sleep(void)
|
||||||
|
{
|
||||||
int n;
|
int n;
|
||||||
uint ticks0;
|
uint ticks0;
|
||||||
|
|
||||||
|
|
@ -52,7 +68,9 @@ uint64 sys_sleep(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 sys_kill(void) {
|
uint64
|
||||||
|
sys_kill(void)
|
||||||
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
argint(0, &pid);
|
argint(0, &pid);
|
||||||
|
|
@ -61,7 +79,9 @@ uint64 sys_kill(void) {
|
||||||
|
|
||||||
// return how many clock tick interrupts have occurred
|
// return how many clock tick interrupts have occurred
|
||||||
// since start.
|
// since start.
|
||||||
uint64 sys_uptime(void) {
|
uint64
|
||||||
|
sys_uptime(void)
|
||||||
|
{
|
||||||
uint xticks;
|
uint xticks;
|
||||||
|
|
||||||
acquire(&tickslock);
|
acquire(&tickslock);
|
||||||
|
|
|
||||||
|
|
@ -80,18 +80,9 @@ uservec:
|
||||||
# load the address of usertrap(), from p->trapframe->kernel_trap
|
# load the address of usertrap(), from p->trapframe->kernel_trap
|
||||||
ld t0, 16(a0)
|
ld t0, 16(a0)
|
||||||
|
|
||||||
|
# load the kernel page table, from p->trapframe->kernel_satp
|
||||||
# fetch the kernel page table address, from p->trapframe->kernel_satp.
|
|
||||||
ld t1, 0(a0)
|
ld t1, 0(a0)
|
||||||
|
|
||||||
# wait for any previous memory operations to complete, so that
|
|
||||||
# they use the user page table.
|
|
||||||
sfence.vma zero, zero
|
|
||||||
|
|
||||||
# install the kernel page table.
|
|
||||||
csrw satp, t1
|
csrw satp, t1
|
||||||
|
|
||||||
# flush now-stale user entries from the TLB.
|
|
||||||
sfence.vma zero, zero
|
sfence.vma zero, zero
|
||||||
|
|
||||||
# jump to usertrap(), which does not return
|
# jump to usertrap(), which does not return
|
||||||
|
|
@ -105,7 +96,6 @@ userret:
|
||||||
# a0: user page table, for satp.
|
# a0: user page table, for satp.
|
||||||
|
|
||||||
# switch to the user page table.
|
# switch to the user page table.
|
||||||
sfence.vma zero, zero
|
|
||||||
csrw satp, a0
|
csrw satp, a0
|
||||||
sfence.vma zero, zero
|
sfence.vma zero, zero
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,26 @@ void kernelvec();
|
||||||
|
|
||||||
extern int devintr();
|
extern int devintr();
|
||||||
|
|
||||||
void trapinit(void) { initlock(&tickslock, "time"); }
|
void
|
||||||
|
trapinit(void)
|
||||||
|
{
|
||||||
|
initlock(&tickslock, "time");
|
||||||
|
}
|
||||||
|
|
||||||
// set up to take exceptions and traps while in the kernel.
|
// set up to take exceptions and traps while in the kernel.
|
||||||
void trapinithart(void) { w_stvec((uint64)kernelvec); }
|
void
|
||||||
|
trapinithart(void)
|
||||||
|
{
|
||||||
|
w_stvec((uint64)kernelvec);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// handle an interrupt, exception, or system call from user space.
|
// handle an interrupt, exception, or system call from user space.
|
||||||
// called from trampoline.S
|
// called from trampoline.S
|
||||||
//
|
//
|
||||||
void usertrap(void) {
|
void
|
||||||
|
usertrap(void)
|
||||||
|
{
|
||||||
int which_dev = 0;
|
int which_dev = 0;
|
||||||
|
|
||||||
if((r_sstatus() & SSTATUS_SPP) != 0)
|
if((r_sstatus() & SSTATUS_SPP) != 0)
|
||||||
|
|
@ -76,7 +86,9 @@ void usertrap(void) {
|
||||||
//
|
//
|
||||||
// return to user space
|
// return to user space
|
||||||
//
|
//
|
||||||
void usertrapret(void) {
|
void
|
||||||
|
usertrapret(void)
|
||||||
|
{
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
// we're about to switch the destination of traps from
|
// we're about to switch the destination of traps from
|
||||||
|
|
@ -119,7 +131,9 @@ void 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 kerneltrap() {
|
void
|
||||||
|
kerneltrap()
|
||||||
|
{
|
||||||
int which_dev = 0;
|
int which_dev = 0;
|
||||||
uint64 sepc = r_sepc();
|
uint64 sepc = r_sepc();
|
||||||
uint64 sstatus = r_sstatus();
|
uint64 sstatus = r_sstatus();
|
||||||
|
|
@ -146,7 +160,9 @@ void kerneltrap() {
|
||||||
w_sstatus(sstatus);
|
w_sstatus(sstatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clockintr() {
|
void
|
||||||
|
clockintr()
|
||||||
|
{
|
||||||
acquire(&tickslock);
|
acquire(&tickslock);
|
||||||
ticks++;
|
ticks++;
|
||||||
wakeup(&ticks);
|
wakeup(&ticks);
|
||||||
|
|
@ -158,10 +174,13 @@ void clockintr() {
|
||||||
// returns 2 if timer interrupt,
|
// returns 2 if timer interrupt,
|
||||||
// 1 if other device,
|
// 1 if other device,
|
||||||
// 0 if not recognized.
|
// 0 if not recognized.
|
||||||
int devintr() {
|
int
|
||||||
|
devintr()
|
||||||
|
{
|
||||||
uint64 scause = r_scause();
|
uint64 scause = r_scause();
|
||||||
|
|
||||||
if ((scause & 0x8000000000000000L) && (scause & 0xff) == 9) {
|
if((scause & 0x8000000000000000L) &&
|
||||||
|
(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.
|
||||||
|
|
@ -199,3 +218,4 @@ int devintr() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,9 @@ extern volatile int panicked; // from printf.c
|
||||||
|
|
||||||
void uartstart();
|
void uartstart();
|
||||||
|
|
||||||
void uartinit(void) {
|
void
|
||||||
|
uartinit(void)
|
||||||
|
{
|
||||||
// disable interrupts.
|
// disable interrupts.
|
||||||
WriteReg(IER, 0x00);
|
WriteReg(IER, 0x00);
|
||||||
|
|
||||||
|
|
@ -81,7 +83,9 @@ void uartinit(void) {
|
||||||
// because it may block, it can't be called
|
// because it may block, it can't be called
|
||||||
// from interrupts; it's only suitable for use
|
// from interrupts; it's only suitable for use
|
||||||
// by write().
|
// by write().
|
||||||
void uartputc(int c) {
|
void
|
||||||
|
uartputc(int c)
|
||||||
|
{
|
||||||
acquire(&uart_tx_lock);
|
acquire(&uart_tx_lock);
|
||||||
|
|
||||||
if(panicked){
|
if(panicked){
|
||||||
|
|
@ -99,11 +103,14 @@ void uartputc(int c) {
|
||||||
release(&uart_tx_lock);
|
release(&uart_tx_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// alternate version of uartputc() that doesn't
|
// alternate version of uartputc() that doesn't
|
||||||
// use interrupts, for use by kernel printf() and
|
// use interrupts, for use by kernel printf() and
|
||||||
// to echo characters. it spins waiting for the uart's
|
// to echo characters. it spins waiting for the uart's
|
||||||
// output register to be empty.
|
// output register to be empty.
|
||||||
void uartputc_sync(int c) {
|
void
|
||||||
|
uartputc_sync(int c)
|
||||||
|
{
|
||||||
push_off();
|
push_off();
|
||||||
|
|
||||||
if(panicked){
|
if(panicked){
|
||||||
|
|
@ -123,7 +130,9 @@ void uartputc_sync(int c) {
|
||||||
// in the transmit buffer, send it.
|
// in the transmit buffer, send it.
|
||||||
// caller must hold uart_tx_lock.
|
// caller must hold uart_tx_lock.
|
||||||
// called from both the top- and bottom-half.
|
// called from both the top- and bottom-half.
|
||||||
void uartstart() {
|
void
|
||||||
|
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.
|
||||||
|
|
@ -149,7 +158,9 @@ void uartstart() {
|
||||||
|
|
||||||
// read one input character from the UART.
|
// read one input character from the UART.
|
||||||
// return -1 if none is waiting.
|
// return -1 if none is waiting.
|
||||||
int uartgetc(void) {
|
int
|
||||||
|
uartgetc(void)
|
||||||
|
{
|
||||||
if(ReadReg(LSR) & 0x01){
|
if(ReadReg(LSR) & 0x01){
|
||||||
// input data is ready.
|
// input data is ready.
|
||||||
return ReadReg(RHR);
|
return ReadReg(RHR);
|
||||||
|
|
@ -161,7 +172,9 @@ int uartgetc(void) {
|
||||||
// handle a uart interrupt, raised because input has
|
// handle a uart interrupt, raised because input has
|
||||||
// arrived, or the uart is ready for more output, or
|
// arrived, or the uart is ready for more output, or
|
||||||
// both. called from devintr().
|
// both. called from devintr().
|
||||||
void uartintr(void) {
|
void
|
||||||
|
uartintr(void)
|
||||||
|
{
|
||||||
// read and process incoming characters.
|
// read and process incoming characters.
|
||||||
while(1){
|
while(1){
|
||||||
int c = uartgetc();
|
int c = uartgetc();
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@
|
||||||
// driver for qemu's virtio disk device.
|
// driver for qemu's virtio disk device.
|
||||||
// uses qemu's mmio interface to virtio.
|
// uses qemu's mmio interface to virtio.
|
||||||
//
|
//
|
||||||
// qemu ... -drive file=fs.img,if=none,format=raw,id=x0 -device
|
// qemu ... -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
|
||||||
// virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
|
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
@ -59,13 +58,16 @@ static struct disk {
|
||||||
|
|
||||||
} disk;
|
} disk;
|
||||||
|
|
||||||
void virtio_disk_init(void) {
|
void
|
||||||
|
virtio_disk_init(void)
|
||||||
|
{
|
||||||
uint32 status = 0;
|
uint32 status = 0;
|
||||||
|
|
||||||
initlock(&disk.vdisk_lock, "virtio_disk");
|
initlock(&disk.vdisk_lock, "virtio_disk");
|
||||||
|
|
||||||
if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
|
if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
|
||||||
*R(VIRTIO_MMIO_VERSION) != 2 || *R(VIRTIO_MMIO_DEVICE_ID) != 2 ||
|
*R(VIRTIO_MMIO_VERSION) != 2 ||
|
||||||
|
*R(VIRTIO_MMIO_DEVICE_ID) != 2 ||
|
||||||
*R(VIRTIO_MMIO_VENDOR_ID) != 0x554d4551){
|
*R(VIRTIO_MMIO_VENDOR_ID) != 0x554d4551){
|
||||||
panic("could not find virtio disk");
|
panic("could not find virtio disk");
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +153,9 @@ void virtio_disk_init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// find a free descriptor, mark it non-free, return its index.
|
// find a free descriptor, mark it non-free, return its index.
|
||||||
static int alloc_desc() {
|
static int
|
||||||
|
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;
|
||||||
|
|
@ -162,7 +166,9 @@ static int alloc_desc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark a descriptor as free.
|
// mark a descriptor as free.
|
||||||
static void free_desc(int i) {
|
static void
|
||||||
|
free_desc(int i)
|
||||||
|
{
|
||||||
if(i >= NUM)
|
if(i >= NUM)
|
||||||
panic("free_desc 1");
|
panic("free_desc 1");
|
||||||
if(disk.free[i])
|
if(disk.free[i])
|
||||||
|
|
@ -176,7 +182,9 @@ static void free_desc(int i) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// free a chain of descriptors.
|
// free a chain of descriptors.
|
||||||
static void free_chain(int i) {
|
static void
|
||||||
|
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;
|
||||||
|
|
@ -190,7 +198,9 @@ static void free_chain(int i) {
|
||||||
|
|
||||||
// allocate three descriptors (they need not be contiguous).
|
// allocate three descriptors (they need not be contiguous).
|
||||||
// disk transfers always use three descriptors.
|
// disk transfers always use three descriptors.
|
||||||
static int alloc3_desc(int *idx) {
|
static int
|
||||||
|
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){
|
||||||
|
|
@ -202,7 +212,9 @@ static int alloc3_desc(int *idx) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtio_disk_rw(struct buf *b, int write) {
|
void
|
||||||
|
virtio_disk_rw(struct buf *b, int write)
|
||||||
|
{
|
||||||
uint64 sector = b->blockno * (BSIZE / 512);
|
uint64 sector = b->blockno * (BSIZE / 512);
|
||||||
|
|
||||||
acquire(&disk.vdisk_lock);
|
acquire(&disk.vdisk_lock);
|
||||||
|
|
@ -279,7 +291,9 @@ void virtio_disk_rw(struct buf *b, int write) {
|
||||||
release(&disk.vdisk_lock);
|
release(&disk.vdisk_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtio_disk_intr() {
|
void
|
||||||
|
virtio_disk_intr()
|
||||||
|
{
|
||||||
acquire(&disk.vdisk_lock);
|
acquire(&disk.vdisk_lock);
|
||||||
|
|
||||||
// the device won't raise another interrupt until we tell it
|
// the device won't raise another interrupt until we tell it
|
||||||
|
|
|
||||||
90
kernel/vm.c
90
kernel/vm.c
|
|
@ -16,7 +16,9 @@ extern char etext[]; // kernel.ld sets this to end of kernel code.
|
||||||
extern char trampoline[]; // trampoline.S
|
extern char trampoline[]; // trampoline.S
|
||||||
|
|
||||||
// Make a direct-map page table for the kernel.
|
// Make a direct-map page table for the kernel.
|
||||||
pagetable_t kvmmake(void) {
|
pagetable_t
|
||||||
|
kvmmake(void)
|
||||||
|
{
|
||||||
pagetable_t kpgtbl;
|
pagetable_t kpgtbl;
|
||||||
|
|
||||||
kpgtbl = (pagetable_t) kalloc();
|
kpgtbl = (pagetable_t) kalloc();
|
||||||
|
|
@ -35,8 +37,7 @@ pagetable_t kvmmake(void) {
|
||||||
kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
|
kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
|
||||||
|
|
||||||
// map kernel data and the physical RAM we'll make use of.
|
// map kernel data and the physical RAM we'll make use of.
|
||||||
kvmmap(kpgtbl, (uint64)etext, (uint64)etext, PHYSTOP - (uint64)etext,
|
kvmmap(kpgtbl, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W);
|
||||||
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.
|
||||||
|
|
@ -49,17 +50,18 @@ pagetable_t kvmmake(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the one kernel_pagetable
|
// Initialize the one kernel_pagetable
|
||||||
void kvminit(void) { kernel_pagetable = kvmmake(); }
|
void
|
||||||
|
kvminit(void)
|
||||||
|
{
|
||||||
|
kernel_pagetable = kvmmake();
|
||||||
|
}
|
||||||
|
|
||||||
// Switch h/w page table register to the kernel's page table,
|
// Switch h/w page table register to the kernel's page table,
|
||||||
// and enable paging.
|
// and enable paging.
|
||||||
void kvminithart() {
|
void
|
||||||
// wait for any previous writes to the page table memory to finish.
|
kvminithart()
|
||||||
sfence_vma();
|
{
|
||||||
|
|
||||||
w_satp(MAKE_SATP(kernel_pagetable));
|
w_satp(MAKE_SATP(kernel_pagetable));
|
||||||
|
|
||||||
// flush stale entries from the TLB.
|
|
||||||
sfence_vma();
|
sfence_vma();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,7 +77,9 @@ void kvminithart() {
|
||||||
// 21..29 -- 9 bits of level-1 index.
|
// 21..29 -- 9 bits of level-1 index.
|
||||||
// 12..20 -- 9 bits of level-0 index.
|
// 12..20 -- 9 bits of level-0 index.
|
||||||
// 0..11 -- 12 bits of byte offset within the page.
|
// 0..11 -- 12 bits of byte offset within the page.
|
||||||
pte_t *walk(pagetable_t pagetable, uint64 va, int alloc) {
|
pte_t *
|
||||||
|
walk(pagetable_t pagetable, uint64 va, int alloc)
|
||||||
|
{
|
||||||
if(va >= MAXVA)
|
if(va >= MAXVA)
|
||||||
panic("walk");
|
panic("walk");
|
||||||
|
|
||||||
|
|
@ -96,7 +100,9 @@ pte_t *walk(pagetable_t pagetable, uint64 va, int alloc) {
|
||||||
// Look up a virtual address, return the physical address,
|
// Look up a virtual address, return the physical address,
|
||||||
// or 0 if not mapped.
|
// or 0 if not mapped.
|
||||||
// Can only be used to look up user pages.
|
// Can only be used to look up user pages.
|
||||||
uint64 walkaddr(pagetable_t pagetable, uint64 va) {
|
uint64
|
||||||
|
walkaddr(pagetable_t pagetable, uint64 va)
|
||||||
|
{
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
uint64 pa;
|
uint64 pa;
|
||||||
|
|
||||||
|
|
@ -117,7 +123,9 @@ uint64 walkaddr(pagetable_t pagetable, uint64 va) {
|
||||||
// add a mapping to the kernel page table.
|
// add a mapping to the kernel page table.
|
||||||
// only used when booting.
|
// only used when booting.
|
||||||
// does not flush TLB or enable paging.
|
// does not flush TLB or enable paging.
|
||||||
void kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm) {
|
void
|
||||||
|
kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm)
|
||||||
|
{
|
||||||
if(mappages(kpgtbl, va, sz, pa, perm) != 0)
|
if(mappages(kpgtbl, va, sz, pa, perm) != 0)
|
||||||
panic("kvmmap");
|
panic("kvmmap");
|
||||||
}
|
}
|
||||||
|
|
@ -126,8 +134,9 @@ void kvmmap(pagetable_t kpgtbl, uint64 va, uint64 pa, uint64 sz, int perm) {
|
||||||
// physical addresses starting at pa. va and size might not
|
// physical addresses starting at pa. va and size might not
|
||||||
// be page-aligned. Returns 0 on success, -1 if walk() couldn't
|
// be page-aligned. Returns 0 on success, -1 if walk() couldn't
|
||||||
// allocate a needed page-table page.
|
// allocate a needed page-table page.
|
||||||
int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa,
|
int
|
||||||
int perm) {
|
mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
|
||||||
|
{
|
||||||
uint64 a, last;
|
uint64 a, last;
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
|
||||||
|
|
@ -153,7 +162,9 @@ int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa,
|
||||||
// Remove npages of mappings starting from va. va must be
|
// Remove npages of mappings starting from va. va must be
|
||||||
// page-aligned. The mappings must exist.
|
// page-aligned. The mappings must exist.
|
||||||
// Optionally free the physical memory.
|
// Optionally free the physical memory.
|
||||||
void uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free) {
|
void
|
||||||
|
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
|
||||||
|
{
|
||||||
uint64 a;
|
uint64 a;
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
|
||||||
|
|
@ -177,7 +188,9 @@ void uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free) {
|
||||||
|
|
||||||
// create an empty user page table.
|
// create an empty user page table.
|
||||||
// returns 0 if out of memory.
|
// returns 0 if out of memory.
|
||||||
pagetable_t uvmcreate() {
|
pagetable_t
|
||||||
|
uvmcreate()
|
||||||
|
{
|
||||||
pagetable_t pagetable;
|
pagetable_t pagetable;
|
||||||
pagetable = (pagetable_t) kalloc();
|
pagetable = (pagetable_t) kalloc();
|
||||||
if(pagetable == 0)
|
if(pagetable == 0)
|
||||||
|
|
@ -189,7 +202,9 @@ pagetable_t uvmcreate() {
|
||||||
// Load the user initcode into address 0 of pagetable,
|
// Load the user initcode into address 0 of pagetable,
|
||||||
// for the very first process.
|
// for the very first process.
|
||||||
// sz must be less than a page.
|
// sz must be less than a page.
|
||||||
void uvmfirst(pagetable_t pagetable, uchar *src, uint sz) {
|
void
|
||||||
|
uvmfirst(pagetable_t pagetable, uchar *src, uint sz)
|
||||||
|
{
|
||||||
char *mem;
|
char *mem;
|
||||||
|
|
||||||
if(sz >= PGSIZE)
|
if(sz >= PGSIZE)
|
||||||
|
|
@ -202,7 +217,9 @@ void uvmfirst(pagetable_t pagetable, uchar *src, uint sz) {
|
||||||
|
|
||||||
// Allocate PTEs and physical memory to grow process from oldsz to
|
// Allocate PTEs and physical memory to grow process from oldsz to
|
||||||
// newsz, which need not be page aligned. Returns new size or 0 on error.
|
// newsz, which need not be page aligned. Returns new size or 0 on error.
|
||||||
uint64 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm) {
|
uint64
|
||||||
|
uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm)
|
||||||
|
{
|
||||||
char *mem;
|
char *mem;
|
||||||
uint64 a;
|
uint64 a;
|
||||||
|
|
||||||
|
|
@ -217,8 +234,7 @@ uint64 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memset(mem, 0, PGSIZE);
|
memset(mem, 0, PGSIZE);
|
||||||
if (mappages(pagetable, a, PGSIZE, (uint64)mem,
|
if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R|PTE_U|xperm) != 0){
|
||||||
PTE_R | PTE_U | xperm) != 0) {
|
|
||||||
kfree(mem);
|
kfree(mem);
|
||||||
uvmdealloc(pagetable, a, oldsz);
|
uvmdealloc(pagetable, a, oldsz);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -231,7 +247,9 @@ uint64 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz, int xperm) {
|
||||||
// newsz. oldsz and newsz need not be page-aligned, nor does newsz
|
// newsz. oldsz and newsz need not be page-aligned, nor does newsz
|
||||||
// need to be less than oldsz. oldsz can be larger than the actual
|
// need to be less than oldsz. oldsz can be larger than the actual
|
||||||
// process size. Returns the new process size.
|
// process size. Returns the new process size.
|
||||||
uint64 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) {
|
uint64
|
||||||
|
uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
|
||||||
|
{
|
||||||
if(newsz >= oldsz)
|
if(newsz >= oldsz)
|
||||||
return oldsz;
|
return oldsz;
|
||||||
|
|
||||||
|
|
@ -245,7 +263,9 @@ uint64 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) {
|
||||||
|
|
||||||
// Recursively free page-table pages.
|
// Recursively free page-table pages.
|
||||||
// All leaf mappings must already have been removed.
|
// All leaf mappings must already have been removed.
|
||||||
void freewalk(pagetable_t pagetable) {
|
void
|
||||||
|
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];
|
||||||
|
|
@ -263,7 +283,9 @@ void freewalk(pagetable_t pagetable) {
|
||||||
|
|
||||||
// Free user memory pages,
|
// Free user memory pages,
|
||||||
// then free page-table pages.
|
// then free page-table pages.
|
||||||
void uvmfree(pagetable_t pagetable, uint64 sz) {
|
void
|
||||||
|
uvmfree(pagetable_t pagetable, uint64 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);
|
||||||
|
|
@ -275,7 +297,9 @@ void uvmfree(pagetable_t pagetable, uint64 sz) {
|
||||||
// physical memory.
|
// physical memory.
|
||||||
// returns 0 on success, -1 on failure.
|
// returns 0 on success, -1 on failure.
|
||||||
// frees any allocated pages on failure.
|
// frees any allocated pages on failure.
|
||||||
int uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) {
|
int
|
||||||
|
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||||
|
{
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
uint64 pa, i;
|
uint64 pa, i;
|
||||||
uint flags;
|
uint flags;
|
||||||
|
|
@ -305,7 +329,9 @@ err:
|
||||||
|
|
||||||
// mark a PTE invalid for user access.
|
// mark a PTE invalid for user access.
|
||||||
// used by exec for the user stack guard page.
|
// used by exec for the user stack guard page.
|
||||||
void uvmclear(pagetable_t pagetable, uint64 va) {
|
void
|
||||||
|
uvmclear(pagetable_t pagetable, uint64 va)
|
||||||
|
{
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
|
||||||
pte = walk(pagetable, va, 0);
|
pte = walk(pagetable, va, 0);
|
||||||
|
|
@ -317,7 +343,9 @@ void uvmclear(pagetable_t pagetable, uint64 va) {
|
||||||
// Copy from kernel to user.
|
// Copy from kernel to user.
|
||||||
// Copy len bytes from src to virtual address dstva in a given page table.
|
// Copy len bytes from src to virtual address dstva in a given page table.
|
||||||
// Return 0 on success, -1 on error.
|
// Return 0 on success, -1 on error.
|
||||||
int copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len) {
|
int
|
||||||
|
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
|
||||||
|
{
|
||||||
uint64 n, va0, pa0;
|
uint64 n, va0, pa0;
|
||||||
|
|
||||||
while(len > 0){
|
while(len > 0){
|
||||||
|
|
@ -340,7 +368,9 @@ int copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len) {
|
||||||
// Copy from user to kernel.
|
// Copy from user to kernel.
|
||||||
// Copy len bytes to dst from virtual address srcva in a given page table.
|
// Copy len bytes to dst from virtual address srcva in a given page table.
|
||||||
// Return 0 on success, -1 on error.
|
// Return 0 on success, -1 on error.
|
||||||
int copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) {
|
int
|
||||||
|
copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
|
||||||
|
{
|
||||||
uint64 n, va0, pa0;
|
uint64 n, va0, pa0;
|
||||||
|
|
||||||
while(len > 0){
|
while(len > 0){
|
||||||
|
|
@ -364,7 +394,9 @@ int copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) {
|
||||||
// Copy bytes to dst from virtual address srcva in a given page table,
|
// Copy bytes to dst from virtual address srcva in a given page table,
|
||||||
// until a '\0', or max.
|
// until a '\0', or max.
|
||||||
// Return 0 on success, -1 on error.
|
// Return 0 on success, -1 on error.
|
||||||
int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) {
|
int
|
||||||
|
copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
|
||||||
|
{
|
||||||
uint64 n, va0, pa0;
|
uint64 n, va0, pa0;
|
||||||
int got_null = 0;
|
int got_null = 0;
|
||||||
|
|
||||||
|
|
|
||||||
56
mkfs/mkfs.c
56
mkfs/mkfs.c
|
|
@ -12,12 +12,7 @@
|
||||||
#include "kernel/param.h"
|
#include "kernel/param.h"
|
||||||
|
|
||||||
#ifndef static_assert
|
#ifndef static_assert
|
||||||
#define static_assert(a, b) \
|
#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
|
||||||
do { \
|
|
||||||
switch (0) \
|
|
||||||
case 0: \
|
|
||||||
case (a):; \
|
|
||||||
} while (0)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NINODES 200
|
#define NINODES 200
|
||||||
|
|
@ -37,6 +32,7 @@ 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*);
|
||||||
|
|
@ -47,7 +43,9 @@ void iappend(uint inum, void *p, int n);
|
||||||
void die(const char *);
|
void die(const char *);
|
||||||
|
|
||||||
// convert to riscv byte order
|
// convert to riscv byte order
|
||||||
ushort xshort(ushort x) {
|
ushort
|
||||||
|
xshort(ushort x)
|
||||||
|
{
|
||||||
ushort y;
|
ushort y;
|
||||||
uchar *a = (uchar*)&y;
|
uchar *a = (uchar*)&y;
|
||||||
a[0] = x;
|
a[0] = x;
|
||||||
|
|
@ -55,7 +53,9 @@ ushort xshort(ushort x) {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint xint(uint x) {
|
uint
|
||||||
|
xint(uint x)
|
||||||
|
{
|
||||||
uint y;
|
uint y;
|
||||||
uchar *a = (uchar*)&y;
|
uchar *a = (uchar*)&y;
|
||||||
a[0] = x;
|
a[0] = x;
|
||||||
|
|
@ -65,13 +65,16 @@ uint xint(uint x) {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
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){
|
||||||
|
|
@ -99,8 +102,7 @@ int main(int argc, char *argv[]) {
|
||||||
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 "
|
printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n",
|
||||||
"blocks %u) blocks %d total %d\n",
|
|
||||||
nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);
|
nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);
|
||||||
|
|
||||||
freeblock = nmeta; // the first free block that we can allocate
|
freeblock = nmeta; // the first free block that we can allocate
|
||||||
|
|
@ -170,14 +172,18 @@ int main(int argc, char *argv[]) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wsect(uint sec, void *buf) {
|
void
|
||||||
|
wsect(uint sec, void *buf)
|
||||||
|
{
|
||||||
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
|
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
|
||||||
die("lseek");
|
die("lseek");
|
||||||
if(write(fsfd, buf, BSIZE) != BSIZE)
|
if(write(fsfd, buf, BSIZE) != BSIZE)
|
||||||
die("write");
|
die("write");
|
||||||
}
|
}
|
||||||
|
|
||||||
void winode(uint inum, struct dinode *ip) {
|
void
|
||||||
|
winode(uint inum, struct dinode *ip)
|
||||||
|
{
|
||||||
char buf[BSIZE];
|
char buf[BSIZE];
|
||||||
uint bn;
|
uint bn;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
@ -189,7 +195,9 @@ void winode(uint inum, struct dinode *ip) {
|
||||||
wsect(bn, buf);
|
wsect(bn, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rinode(uint inum, struct dinode *ip) {
|
void
|
||||||
|
rinode(uint inum, struct dinode *ip)
|
||||||
|
{
|
||||||
char buf[BSIZE];
|
char buf[BSIZE];
|
||||||
uint bn;
|
uint bn;
|
||||||
struct dinode *dip;
|
struct dinode *dip;
|
||||||
|
|
@ -200,14 +208,18 @@ void rinode(uint inum, struct dinode *ip) {
|
||||||
*ip = *dip;
|
*ip = *dip;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rsect(uint sec, void *buf) {
|
void
|
||||||
|
rsect(uint sec, void *buf)
|
||||||
|
{
|
||||||
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
|
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE)
|
||||||
die("lseek");
|
die("lseek");
|
||||||
if(read(fsfd, buf, BSIZE) != BSIZE)
|
if(read(fsfd, buf, BSIZE) != BSIZE)
|
||||||
die("read");
|
die("read");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint ialloc(ushort type) {
|
uint
|
||||||
|
ialloc(ushort type)
|
||||||
|
{
|
||||||
uint inum = freeinode++;
|
uint inum = freeinode++;
|
||||||
struct dinode din;
|
struct dinode din;
|
||||||
|
|
||||||
|
|
@ -219,7 +231,9 @@ uint ialloc(ushort type) {
|
||||||
return inum;
|
return inum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void balloc(int used) {
|
void
|
||||||
|
balloc(int used)
|
||||||
|
{
|
||||||
uchar buf[BSIZE];
|
uchar buf[BSIZE];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -235,7 +249,9 @@ void balloc(int used) {
|
||||||
|
|
||||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
void iappend(uint inum, void *xp, int n) {
|
void
|
||||||
|
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;
|
||||||
|
|
@ -277,7 +293,9 @@ void iappend(uint inum, void *xp, int n) {
|
||||||
winode(inum, &din);
|
winode(inum, &din);
|
||||||
}
|
}
|
||||||
|
|
||||||
void die(const char *s) {
|
void
|
||||||
|
die(const char *s)
|
||||||
|
{
|
||||||
perror(s);
|
perror(s);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
/target
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foo"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "foo"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
crate-type = [ "staticlib" ]
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
panic = "abort"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
#![no_std]
|
|
||||||
#![crate_type = "staticlib"]
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn add(left: i32, right: i32) -> i32 {
|
|
||||||
left + right
|
|
||||||
}
|
|
||||||
|
|
||||||
#[panic_handler]
|
|
||||||
#[no_mangle]
|
|
||||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
void cat(int fd) {
|
void
|
||||||
|
cat(int fd)
|
||||||
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||||
|
|
@ -19,7 +21,9 @@ void cat(int fd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
int fd, i;
|
int fd, i;
|
||||||
|
|
||||||
if(argc <= 1){
|
if(argc <= 1){
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
#include "kernel/stat.h"
|
#include "kernel/stat.h"
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 1; i < argc; i++){
|
for(i = 1; i < argc; i++){
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,15 @@
|
||||||
|
|
||||||
#define N 1000
|
#define N 1000
|
||||||
|
|
||||||
void print(const char *s) { write(1, s, strlen(s)); }
|
void
|
||||||
|
print(const char *s)
|
||||||
|
{
|
||||||
|
write(1, s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
void forktest(void) {
|
void
|
||||||
|
forktest(void)
|
||||||
|
{
|
||||||
int n, pid;
|
int n, pid;
|
||||||
|
|
||||||
print("fork test\n");
|
print("fork test\n");
|
||||||
|
|
@ -42,7 +48,9 @@ void forktest(void) {
|
||||||
print("fork test OK\n");
|
print("fork test OK\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
forktest();
|
forktest();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
user/grep.c
19
user/grep.c
|
|
@ -7,7 +7,9 @@
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int match(char*, char*);
|
int match(char*, char*);
|
||||||
|
|
||||||
void grep(char *pattern, int fd) {
|
void
|
||||||
|
grep(char *pattern, int fd)
|
||||||
|
{
|
||||||
int n, m;
|
int n, m;
|
||||||
char *p, *q;
|
char *p, *q;
|
||||||
|
|
||||||
|
|
@ -31,7 +33,9 @@ void grep(char *pattern, int fd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
int fd, i;
|
int fd, i;
|
||||||
char *pattern;
|
char *pattern;
|
||||||
|
|
||||||
|
|
@ -64,7 +68,9 @@ int main(int argc, char *argv[]) {
|
||||||
int matchhere(char*, char*);
|
int matchhere(char*, char*);
|
||||||
int matchstar(int, char*, char*);
|
int matchstar(int, char*, char*);
|
||||||
|
|
||||||
int match(char *re, char *text) {
|
int
|
||||||
|
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
|
||||||
|
|
@ -75,7 +81,8 @@ int match(char *re, char *text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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] == '*')
|
||||||
|
|
@ -88,10 +95,12 @@ int matchhere(char *re, char *text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
30
user/grind.c
30
user/grind.c
|
|
@ -13,7 +13,9 @@
|
||||||
#include "kernel/riscv.h"
|
#include "kernel/riscv.h"
|
||||||
|
|
||||||
// from FreeBSD.
|
// from FreeBSD.
|
||||||
int do_rand(unsigned long *ctx) {
|
int
|
||||||
|
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:
|
||||||
|
|
@ -39,9 +41,15 @@ int do_rand(unsigned long *ctx) {
|
||||||
|
|
||||||
unsigned long rand_next = 1;
|
unsigned long rand_next = 1;
|
||||||
|
|
||||||
int rand(void) { return (do_rand(&rand_next)); }
|
int
|
||||||
|
rand(void)
|
||||||
|
{
|
||||||
|
return (do_rand(&rand_next));
|
||||||
|
}
|
||||||
|
|
||||||
void go(int which_child) {
|
void
|
||||||
|
go(int which_child)
|
||||||
|
{
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
static char buf[999];
|
static char buf[999];
|
||||||
char *break0 = sbrk(0);
|
char *break0 = sbrk(0);
|
||||||
|
|
@ -278,15 +286,16 @@ void go(int which_child) {
|
||||||
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,
|
printf("grind: exec pipeline failed %d %d \"%s\"\n", st1, st2, buf);
|
||||||
buf);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void iter() {
|
void
|
||||||
|
iter()
|
||||||
|
{
|
||||||
unlink("a");
|
unlink("a");
|
||||||
unlink("b");
|
unlink("b");
|
||||||
|
|
||||||
|
|
@ -296,7 +305,7 @@ void iter() {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(pid1 == 0){
|
if(pid1 == 0){
|
||||||
rand_next ^= 31;
|
rand_next = 31;
|
||||||
go(0);
|
go(0);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
@ -307,7 +316,7 @@ void iter() {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(pid2 == 0){
|
if(pid2 == 0){
|
||||||
rand_next ^= 7177;
|
rand_next = 7177;
|
||||||
go(1);
|
go(1);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
@ -324,7 +333,9 @@ void iter() {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
while(1){
|
while(1){
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
if(pid == 0){
|
if(pid == 0){
|
||||||
|
|
@ -335,6 +346,5 @@ int main() {
|
||||||
wait(0);
|
wait(0);
|
||||||
}
|
}
|
||||||
sleep(20);
|
sleep(20);
|
||||||
rand_next += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@
|
||||||
|
|
||||||
char *argv[] = { "sh", 0 };
|
char *argv[] = { "sh", 0 };
|
||||||
|
|
||||||
int main(void) {
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
int pid, wpid;
|
int pid, wpid;
|
||||||
|
|
||||||
if(open("console", O_RDWR) < 0){
|
if(open("console", O_RDWR) < 0){
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
#include "kernel/stat.h"
|
#include "kernel/stat.h"
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
#include "kernel/stat.h"
|
#include "kernel/stat.h"
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
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);
|
||||||
|
|
|
||||||
12
user/ls.c
12
user/ls.c
|
|
@ -3,7 +3,9 @@
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
#include "kernel/fs.h"
|
#include "kernel/fs.h"
|
||||||
|
|
||||||
char *fmtname(char *path) {
|
char*
|
||||||
|
fmtname(char *path)
|
||||||
|
{
|
||||||
static char buf[DIRSIZ+1];
|
static char buf[DIRSIZ+1];
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
|
|
@ -20,7 +22,9 @@ char *fmtname(char *path) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ls(char *path) {
|
void
|
||||||
|
ls(char *path)
|
||||||
|
{
|
||||||
char buf[512], *p;
|
char buf[512], *p;
|
||||||
int fd;
|
int fd;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
|
|
@ -67,7 +71,9 @@ void ls(char *path) {
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
#include "kernel/stat.h"
|
#include "kernel/stat.h"
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,15 @@
|
||||||
|
|
||||||
static char digits[] = "0123456789ABCDEF";
|
static char digits[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
static void putc(int fd, char c) { write(fd, &c, 1); }
|
static void
|
||||||
|
putc(int fd, char c)
|
||||||
|
{
|
||||||
|
write(fd, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static void printint(int fd, int xx, int base, int sgn) {
|
static void
|
||||||
|
printint(int fd, int xx, int base, int sgn)
|
||||||
|
{
|
||||||
char buf[16];
|
char buf[16];
|
||||||
int i, neg;
|
int i, neg;
|
||||||
uint x;
|
uint x;
|
||||||
|
|
@ -32,7 +38,8 @@ static void printint(int fd, int xx, int base, int sgn) {
|
||||||
putc(fd, buf[i]);
|
putc(fd, buf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printptr(int fd, uint64 x) {
|
static void
|
||||||
|
printptr(int fd, uint64 x) {
|
||||||
int i;
|
int i;
|
||||||
putc(fd, '0');
|
putc(fd, '0');
|
||||||
putc(fd, 'x');
|
putc(fd, 'x');
|
||||||
|
|
@ -41,7 +48,9 @@ static void printptr(int fd, uint64 x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print to the given fd. Only understands %d, %x, %p, %s.
|
// Print to the given fd. Only understands %d, %x, %p, %s.
|
||||||
void vprintf(int fd, const char *fmt, va_list ap) {
|
void
|
||||||
|
vprintf(int fd, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
char *s;
|
char *s;
|
||||||
int c, i, state;
|
int c, i, state;
|
||||||
|
|
||||||
|
|
@ -85,14 +94,18 @@ void vprintf(int fd, const char *fmt, va_list ap) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fprintf(int fd, const char *fmt, ...) {
|
void
|
||||||
|
fprintf(int fd, const char *fmt, ...)
|
||||||
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vprintf(fd, fmt, ap);
|
vprintf(fd, fmt, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printf(const char *fmt, ...) {
|
void
|
||||||
|
printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
#include "kernel/stat.h"
|
#include "kernel/stat.h"
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
|
|
|
||||||
77
user/sh.c
77
user/sh.c
|
|
@ -55,7 +55,9 @@ 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 runcmd(struct cmd *cmd) {
|
void
|
||||||
|
runcmd(struct cmd *cmd)
|
||||||
|
{
|
||||||
int p[2];
|
int p[2];
|
||||||
struct backcmd *bcmd;
|
struct backcmd *bcmd;
|
||||||
struct execcmd *ecmd;
|
struct execcmd *ecmd;
|
||||||
|
|
@ -129,7 +131,9 @@ void runcmd(struct cmd *cmd) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getcmd(char *buf, int nbuf) {
|
int
|
||||||
|
getcmd(char *buf, int nbuf)
|
||||||
|
{
|
||||||
write(2, "$ ", 2);
|
write(2, "$ ", 2);
|
||||||
memset(buf, 0, nbuf);
|
memset(buf, 0, nbuf);
|
||||||
gets(buf, nbuf);
|
gets(buf, nbuf);
|
||||||
|
|
@ -138,7 +142,9 @@ int getcmd(char *buf, int nbuf) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
static char buf[100];
|
static char buf[100];
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
|
@ -166,12 +172,16 @@ int main(void) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void panic(char *s) {
|
void
|
||||||
|
panic(char *s)
|
||||||
|
{
|
||||||
fprintf(2, "%s\n", s);
|
fprintf(2, "%s\n", s);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fork1(void) {
|
int
|
||||||
|
fork1(void)
|
||||||
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
|
|
@ -183,7 +193,9 @@ int fork1(void) {
|
||||||
//PAGEBREAK!
|
//PAGEBREAK!
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
struct cmd *execcmd(void) {
|
struct cmd*
|
||||||
|
execcmd(void)
|
||||||
|
{
|
||||||
struct execcmd *cmd;
|
struct execcmd *cmd;
|
||||||
|
|
||||||
cmd = malloc(sizeof(*cmd));
|
cmd = malloc(sizeof(*cmd));
|
||||||
|
|
@ -192,8 +204,9 @@ struct cmd *execcmd(void) {
|
||||||
return (struct cmd*)cmd;
|
return (struct cmd*)cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *redircmd(struct cmd *subcmd, char *file, char *efile, int mode,
|
struct cmd*
|
||||||
int fd) {
|
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
|
||||||
|
{
|
||||||
struct redircmd *cmd;
|
struct redircmd *cmd;
|
||||||
|
|
||||||
cmd = malloc(sizeof(*cmd));
|
cmd = malloc(sizeof(*cmd));
|
||||||
|
|
@ -207,7 +220,9 @@ struct cmd *redircmd(struct cmd *subcmd, char *file, char *efile, int mode,
|
||||||
return (struct cmd*)cmd;
|
return (struct cmd*)cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *pipecmd(struct cmd *left, struct cmd *right) {
|
struct cmd*
|
||||||
|
pipecmd(struct cmd *left, struct cmd *right)
|
||||||
|
{
|
||||||
struct pipecmd *cmd;
|
struct pipecmd *cmd;
|
||||||
|
|
||||||
cmd = malloc(sizeof(*cmd));
|
cmd = malloc(sizeof(*cmd));
|
||||||
|
|
@ -218,7 +233,9 @@ struct cmd *pipecmd(struct cmd *left, struct cmd *right) {
|
||||||
return (struct cmd*)cmd;
|
return (struct cmd*)cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *listcmd(struct cmd *left, struct cmd *right) {
|
struct cmd*
|
||||||
|
listcmd(struct cmd *left, struct cmd *right)
|
||||||
|
{
|
||||||
struct listcmd *cmd;
|
struct listcmd *cmd;
|
||||||
|
|
||||||
cmd = malloc(sizeof(*cmd));
|
cmd = malloc(sizeof(*cmd));
|
||||||
|
|
@ -229,7 +246,9 @@ struct cmd *listcmd(struct cmd *left, struct cmd *right) {
|
||||||
return (struct cmd*)cmd;
|
return (struct cmd*)cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *backcmd(struct cmd *subcmd) {
|
struct cmd*
|
||||||
|
backcmd(struct cmd *subcmd)
|
||||||
|
{
|
||||||
struct backcmd *cmd;
|
struct backcmd *cmd;
|
||||||
|
|
||||||
cmd = malloc(sizeof(*cmd));
|
cmd = malloc(sizeof(*cmd));
|
||||||
|
|
@ -244,7 +263,9 @@ struct cmd *backcmd(struct cmd *subcmd) {
|
||||||
char whitespace[] = " \t\r\n\v";
|
char whitespace[] = " \t\r\n\v";
|
||||||
char symbols[] = "<|>&;()";
|
char symbols[] = "<|>&;()";
|
||||||
|
|
||||||
int gettoken(char **ps, char *es, char **q, char **eq) {
|
int
|
||||||
|
gettoken(char **ps, char *es, char **q, char **eq)
|
||||||
|
{
|
||||||
char *s;
|
char *s;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
@ -287,7 +308,9 @@ int gettoken(char **ps, char *es, char **q, char **eq) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int peek(char **ps, char *es, char *toks) {
|
int
|
||||||
|
peek(char **ps, char *es, char *toks)
|
||||||
|
{
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
s = *ps;
|
s = *ps;
|
||||||
|
|
@ -302,7 +325,9 @@ 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 *parsecmd(char *s) {
|
struct cmd*
|
||||||
|
parsecmd(char *s)
|
||||||
|
{
|
||||||
char *es;
|
char *es;
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
|
||||||
|
|
@ -317,7 +342,9 @@ struct cmd *parsecmd(char *s) {
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *parseline(char **ps, char *es) {
|
struct cmd*
|
||||||
|
parseline(char **ps, char *es)
|
||||||
|
{
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
|
||||||
cmd = parsepipe(ps, es);
|
cmd = parsepipe(ps, es);
|
||||||
|
|
@ -332,7 +359,9 @@ struct cmd *parseline(char **ps, char *es) {
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *parsepipe(char **ps, char *es) {
|
struct cmd*
|
||||||
|
parsepipe(char **ps, char *es)
|
||||||
|
{
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
|
||||||
cmd = parseexec(ps, es);
|
cmd = parseexec(ps, es);
|
||||||
|
|
@ -343,7 +372,9 @@ struct cmd *parsepipe(char **ps, char *es) {
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *parseredirs(struct cmd *cmd, char **ps, char *es) {
|
struct cmd*
|
||||||
|
parseredirs(struct cmd *cmd, char **ps, char *es)
|
||||||
|
{
|
||||||
int tok;
|
int tok;
|
||||||
char *q, *eq;
|
char *q, *eq;
|
||||||
|
|
||||||
|
|
@ -366,7 +397,9 @@ struct cmd *parseredirs(struct cmd *cmd, char **ps, char *es) {
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *parseblock(char **ps, char *es) {
|
struct cmd*
|
||||||
|
parseblock(char **ps, char *es)
|
||||||
|
{
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
|
|
||||||
if(!peek(ps, es, "("))
|
if(!peek(ps, es, "("))
|
||||||
|
|
@ -380,7 +413,9 @@ struct cmd *parseblock(char **ps, char *es) {
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd *parseexec(char **ps, char *es) {
|
struct cmd*
|
||||||
|
parseexec(char **ps, char *es)
|
||||||
|
{
|
||||||
char *q, *eq;
|
char *q, *eq;
|
||||||
int tok, argc;
|
int tok, argc;
|
||||||
struct execcmd *cmd;
|
struct execcmd *cmd;
|
||||||
|
|
@ -412,7 +447,9 @@ struct cmd *parseexec(char **ps, char *es) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NUL-terminate all the counted strings.
|
// NUL-terminate all the counted strings.
|
||||||
struct cmd *nulterminate(struct cmd *cmd) {
|
struct cmd*
|
||||||
|
nulterminate(struct cmd *cmd)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
struct backcmd *bcmd;
|
struct backcmd *bcmd;
|
||||||
struct execcmd *ecmd;
|
struct execcmd *ecmd;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@
|
||||||
#include "kernel/fs.h"
|
#include "kernel/fs.h"
|
||||||
#include "kernel/fcntl.h"
|
#include "kernel/fcntl.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
int fd, i;
|
int fd, i;
|
||||||
char path[] = "stressfs0";
|
char path[] = "stressfs0";
|
||||||
char data[512];
|
char data[512];
|
||||||
|
|
|
||||||
48
user/ulib.c
48
user/ulib.c
|
|
@ -6,13 +6,17 @@
|
||||||
//
|
//
|
||||||
// wrapper so that it's OK if main() does not call exit().
|
// wrapper so that it's OK if main() does not call exit().
|
||||||
//
|
//
|
||||||
void _main() {
|
void
|
||||||
|
_main()
|
||||||
|
{
|
||||||
extern int main();
|
extern int main();
|
||||||
main();
|
main();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *strcpy(char *s, const char *t) {
|
char*
|
||||||
|
strcpy(char *s, const char *t)
|
||||||
|
{
|
||||||
char *os;
|
char *os;
|
||||||
|
|
||||||
os = s;
|
os = s;
|
||||||
|
|
@ -21,13 +25,17 @@ char *strcpy(char *s, const char *t) {
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
int strcmp(const char *p, const char *q) {
|
int
|
||||||
|
strcmp(const char *p, const char *q)
|
||||||
|
{
|
||||||
while(*p && *p == *q)
|
while(*p && *p == *q)
|
||||||
p++, q++;
|
p++, q++;
|
||||||
return (uchar)*p - (uchar)*q;
|
return (uchar)*p - (uchar)*q;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint strlen(const char *s) {
|
uint
|
||||||
|
strlen(const char *s)
|
||||||
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
for(n = 0; s[n]; n++)
|
for(n = 0; s[n]; n++)
|
||||||
|
|
@ -35,7 +43,9 @@ uint strlen(const char *s) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *memset(void *dst, int c, uint n) {
|
void*
|
||||||
|
memset(void *dst, int c, uint n)
|
||||||
|
{
|
||||||
char *cdst = (char *) dst;
|
char *cdst = (char *) dst;
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < n; i++){
|
for(i = 0; i < n; i++){
|
||||||
|
|
@ -44,14 +54,18 @@ void *memset(void *dst, int c, uint n) {
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *strchr(const char *s, char c) {
|
char*
|
||||||
|
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 *gets(char *buf, int max) {
|
char*
|
||||||
|
gets(char *buf, int max)
|
||||||
|
{
|
||||||
int i, cc;
|
int i, cc;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
|
|
@ -67,7 +81,9 @@ char *gets(char *buf, int max) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stat(const char *n, struct stat *st) {
|
int
|
||||||
|
stat(const char *n, struct stat *st)
|
||||||
|
{
|
||||||
int fd;
|
int fd;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
|
@ -79,7 +95,9 @@ int stat(const char *n, struct stat *st) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int atoi(const char *s) {
|
int
|
||||||
|
atoi(const char *s)
|
||||||
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
|
|
@ -88,7 +106,9 @@ int atoi(const char *s) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *memmove(void *vdst, const void *vsrc, int n) {
|
void*
|
||||||
|
memmove(void *vdst, const void *vsrc, int n)
|
||||||
|
{
|
||||||
char *dst;
|
char *dst;
|
||||||
const char *src;
|
const char *src;
|
||||||
|
|
||||||
|
|
@ -106,7 +126,9 @@ void *memmove(void *vdst, const void *vsrc, int n) {
|
||||||
return vdst;
|
return vdst;
|
||||||
}
|
}
|
||||||
|
|
||||||
int memcmp(const void *s1, const void *s2, uint n) {
|
int
|
||||||
|
memcmp(const void *s1, const void *s2, uint n)
|
||||||
|
{
|
||||||
const char *p1 = s1, *p2 = s2;
|
const char *p1 = s1, *p2 = s2;
|
||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
if (*p1 != *p2) {
|
if (*p1 != *p2) {
|
||||||
|
|
@ -118,6 +140,8 @@ int memcmp(const void *s1, const void *s2, uint n) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *memcpy(void *dst, const void *src, uint n) {
|
void *
|
||||||
|
memcpy(void *dst, const void *src, uint n)
|
||||||
|
{
|
||||||
return memmove(dst, src, n);
|
return memmove(dst, src, n);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,9 @@ typedef union header Header;
|
||||||
static Header base;
|
static Header base;
|
||||||
static Header *freep;
|
static Header *freep;
|
||||||
|
|
||||||
void free(void *ap) {
|
void
|
||||||
|
free(void *ap)
|
||||||
|
{
|
||||||
Header *bp, *p;
|
Header *bp, *p;
|
||||||
|
|
||||||
bp = (Header*)ap - 1;
|
bp = (Header*)ap - 1;
|
||||||
|
|
@ -41,7 +43,9 @@ void free(void *ap) {
|
||||||
freep = p;
|
freep = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Header *morecore(uint nu) {
|
static Header*
|
||||||
|
morecore(uint nu)
|
||||||
|
{
|
||||||
char *p;
|
char *p;
|
||||||
Header *hp;
|
Header *hp;
|
||||||
|
|
||||||
|
|
@ -56,7 +60,9 @@ static Header *morecore(uint nu) {
|
||||||
return freep;
|
return freep;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *malloc(uint nbytes) {
|
void*
|
||||||
|
malloc(uint nbytes)
|
||||||
|
{
|
||||||
Header *p, *prevp;
|
Header *p, *prevp;
|
||||||
uint nunits;
|
uint nunits;
|
||||||
|
|
||||||
|
|
|
||||||
810
user/usertests.c
810
user/usertests.c
File diff suppressed because it is too large
Load Diff
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
void wc(int fd, char *name) {
|
void
|
||||||
|
wc(int fd, char *name)
|
||||||
|
{
|
||||||
int i, n;
|
int i, n;
|
||||||
int l, w, c, inword;
|
int l, w, c, inword;
|
||||||
|
|
||||||
|
|
@ -30,7 +32,9 @@ void wc(int fd, char *name) {
|
||||||
printf("%d %d %d %s\n", l, w, c, name);
|
printf("%d %d %d %s\n", l, w, c, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
int fd, i;
|
int fd, i;
|
||||||
|
|
||||||
if(argc <= 1){
|
if(argc <= 1){
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@
|
||||||
#include "kernel/stat.h"
|
#include "kernel/stat.h"
|
||||||
#include "user/user.h"
|
#include "user/user.h"
|
||||||
|
|
||||||
int main(void) {
|
int
|
||||||
|
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 New Issue