summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile20
-rw-r--r--bio.c7
-rw-r--r--defs.h8
-rw-r--r--file.c1
-rw-r--r--fs.c4
-rw-r--r--ide.c168
-rw-r--r--kalloc.c2
-rw-r--r--log.c1
-rw-r--r--main.c4
-rw-r--r--memlayout.h4
-rw-r--r--pipe.c2
-rw-r--r--proc.c27
-rw-r--r--ramdisk.c45
-rw-r--r--sleeplock.c3
-rw-r--r--trapasm.S132
-rw-r--r--ulib.c7
-rw-r--r--usertests.c32
-rw-r--r--usys.S31
-rwxr-xr-xusys.pl38
-rw-r--r--vm.c5
20 files changed, 138 insertions, 403 deletions
diff --git a/Makefile b/Makefile
index 1424d7c..6c3df2b 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,14 @@ OBJS = \
trampoline.o \
trap.o \
syscall.o \
- sysproc.o
+ sysproc.o \
+ bio.o \
+ fs.o \
+ log.o \
+ sleeplock.o \
+ file.o \
+ pipe.o \
+ ramdisk.o
XXXOBJS = \
bio.o\
@@ -83,15 +90,15 @@ endif
LDFLAGS = -z max-page-size=4096
-kernel: $(OBJS) entry.o kernel.ld
+kernel: $(OBJS) entry.o kernel.ld initcode
$(LD) $(LDFLAGS) -T kernel.ld -o kernel entry.o $(OBJS)
$(OBJDUMP) -S kernel > kernel.asm
$(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym
initcode: initcode.S
$(CC) $(CFLAGS) -nostdinc -I. -c initcode.S
- #$(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o
- #$(OBJCOPY) -S -O binary initcode.out initcode
+ $(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o
+ $(OBJCOPY) -S -O binary initcode.out initcode
$(OBJDUMP) -S initcode.o > initcode.asm
tags: $(OBJS) entryother.S _init
@@ -107,6 +114,9 @@ _%: %.o $(ULIB)
$(OBJDUMP) -S $@ > $*.asm
$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
+usys.S : usys.pl
+ perl ./usys.pl > usys.S
+
_forktest: forktest.o $(ULIB)
# forktest has less library code linked in - needs to be small
# in order to be able to max out the proc table.
@@ -171,7 +181,7 @@ ifndef CPUS
CPUS := 1
endif
QEMUOPTS = -machine virt -kernel kernel -m 3G -smp $(CPUS) -nographic
-#QEMUOPTS += -initrd fs.img
+QEMUOPTS += -initrd fs.img
qemu: kernel
$(QEMU) $(QEMUOPTS)
diff --git a/bio.c b/bio.c
index a45ff3e..90f9af9 100644
--- a/bio.c
+++ b/bio.c
@@ -19,10 +19,11 @@
// and needs to be written to disk.
#include "types.h"
-#include "defs.h"
#include "param.h"
#include "spinlock.h"
#include "sleeplock.h"
+#include "riscv.h"
+#include "defs.h"
#include "fs.h"
#include "buf.h"
@@ -100,7 +101,7 @@ bread(uint dev, uint blockno)
b = bget(dev, blockno);
if((b->flags & B_VALID) == 0) {
- iderw(b);
+ ramdiskrw(b);
}
return b;
}
@@ -112,7 +113,7 @@ bwrite(struct buf *b)
if(!holdingsleep(&b->lock))
panic("bwrite");
b->flags |= B_DIRTY;
- iderw(b);
+ ramdiskrw(b);
}
// Release a locked buffer.
diff --git a/defs.h b/defs.h
index d86e495..efffc33 100644
--- a/defs.h
+++ b/defs.h
@@ -54,10 +54,10 @@ int readi(struct inode*, char*, uint, uint);
void stati(struct inode*, struct stat*);
int writei(struct inode*, char*, uint, uint);
-// ide.c
-void ideinit(void);
-void ideintr(void);
-void iderw(struct buf*);
+// ramdisk.c
+void ramdiskinit(void);
+void ramdiskintr(void);
+void ramdiskrw(struct buf*);
// ioapic.c
void ioapicenable(int irq, int cpu);
diff --git a/file.c b/file.c
index 24b32c2..6d3ffb3 100644
--- a/file.c
+++ b/file.c
@@ -3,6 +3,7 @@
//
#include "types.h"
+#include "riscv.h"
#include "defs.h"
#include "param.h"
#include "fs.h"
diff --git a/fs.c b/fs.c
index feb59fe..ae96567 100644
--- a/fs.c
+++ b/fs.c
@@ -10,10 +10,10 @@
// are in sysfile.c.
#include "types.h"
+#include "riscv.h"
#include "defs.h"
#include "param.h"
#include "stat.h"
-#include "mmu.h"
#include "proc.h"
#include "spinlock.h"
#include "sleeplock.h"
@@ -180,7 +180,7 @@ iinit(int dev)
}
readsb(dev, &sb);
- cprintf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\
+ printf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\
inodestart %d bmap start %d\n", sb.size, sb.nblocks,
sb.ninodes, sb.nlog, sb.logstart, sb.inodestart,
sb.bmapstart);
diff --git a/ide.c b/ide.c
deleted file mode 100644
index b4c0b1f..0000000
--- a/ide.c
+++ /dev/null
@@ -1,168 +0,0 @@
-// Simple PIO-based (non-DMA) IDE driver code.
-
-#include "types.h"
-#include "defs.h"
-#include "param.h"
-#include "memlayout.h"
-#include "mmu.h"
-#include "proc.h"
-#include "x86.h"
-#include "traps.h"
-#include "spinlock.h"
-#include "sleeplock.h"
-#include "fs.h"
-#include "buf.h"
-
-#define SECTOR_SIZE 512
-#define IDE_BSY 0x80
-#define IDE_DRDY 0x40
-#define IDE_DF 0x20
-#define IDE_ERR 0x01
-
-#define IDE_CMD_READ 0x20
-#define IDE_CMD_WRITE 0x30
-#define IDE_CMD_RDMUL 0xc4
-#define IDE_CMD_WRMUL 0xc5
-
-// idequeue points to the buf now being read/written to the disk.
-// idequeue->qnext points to the next buf to be processed.
-// You must hold idelock while manipulating queue.
-
-static struct spinlock idelock;
-static struct buf *idequeue;
-
-static int havedisk1;
-static void idestart(struct buf*);
-
-// Wait for IDE disk to become ready.
-static int
-idewait(int checkerr)
-{
- int r;
-
- while(((r = inb(0x1f7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY)
- ;
- if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0)
- return -1;
- return 0;
-}
-
-void
-ideinit(void)
-{
- int i;
-
- initlock(&idelock, "ide");
- ioapicenable(IRQ_IDE, ncpu - 1);
- idewait(0);
-
- // Check if disk 1 is present
- outb(0x1f6, 0xe0 | (1<<4));
- for(i=0; i<1000; i++){
- if(inb(0x1f7) != 0){
- havedisk1 = 1;
- break;
- }
- }
-
- // Switch back to disk 0.
- outb(0x1f6, 0xe0 | (0<<4));
-}
-
-// Start the request for b. Caller must hold idelock.
-static void
-idestart(struct buf *b)
-{
- if(b == 0)
- panic("idestart");
- if(b->blockno >= FSSIZE)
- panic("incorrect blockno");
- int sector_per_block = BSIZE/SECTOR_SIZE;
- int sector = b->blockno * sector_per_block;
- int read_cmd = (sector_per_block == 1) ? IDE_CMD_READ : IDE_CMD_RDMUL;
- int write_cmd = (sector_per_block == 1) ? IDE_CMD_WRITE : IDE_CMD_WRMUL;
-
- if (sector_per_block > 7) panic("idestart");
-
- idewait(0);
- outb(0x3f6, 0); // generate interrupt
- outb(0x1f2, sector_per_block); // number of sectors
- outb(0x1f3, sector & 0xff);
- outb(0x1f4, (sector >> 8) & 0xff);
- outb(0x1f5, (sector >> 16) & 0xff);
- outb(0x1f6, 0xe0 | ((b->dev&1)<<4) | ((sector>>24)&0x0f));
- if(b->flags & B_DIRTY){
- outb(0x1f7, write_cmd);
- outsl(0x1f0, b->data, BSIZE/4);
- } else {
- outb(0x1f7, read_cmd);
- }
-}
-
-// Interrupt handler.
-void
-ideintr(void)
-{
- struct buf *b;
-
- // First queued buffer is the active request.
- acquire(&idelock);
-
- if((b = idequeue) == 0){
- release(&idelock);
- return;
- }
- idequeue = b->qnext;
-
- // Read data if needed.
- if(!(b->flags & B_DIRTY) && idewait(1) >= 0)
- insl(0x1f0, b->data, BSIZE/4);
-
- // Wake process waiting for this buf.
- b->flags |= B_VALID;
- b->flags &= ~B_DIRTY;
- wakeup(b);
-
- // Start disk on next buf in queue.
- if(idequeue != 0)
- idestart(idequeue);
-
- release(&idelock);
-}
-
-//PAGEBREAK!
-// Sync buf with disk.
-// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
-// Else if B_VALID is not set, read buf from disk, set B_VALID.
-void
-iderw(struct buf *b)
-{
- struct buf **pp;
-
- if(!holdingsleep(&b->lock))
- panic("iderw: buf not locked");
- if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
- panic("iderw: nothing to do");
- if(b->dev != 0 && !havedisk1)
- panic("iderw: ide disk 1 not present");
-
- acquire(&idelock); //DOC:acquire-lock
-
- // Append b to idequeue.
- b->qnext = 0;
- for(pp=&idequeue; *pp; pp=&(*pp)->qnext) //DOC:insert-queue
- ;
- *pp = b;
-
- // Start disk if necessary.
- if(idequeue == b)
- idestart(b);
-
- // Wait for request to finish.
- while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){
- sleep(b, &idelock);
- }
-
-
- release(&idelock);
-}
diff --git a/kalloc.c b/kalloc.c
index c943e5e..cfbbae4 100644
--- a/kalloc.c
+++ b/kalloc.c
@@ -27,6 +27,8 @@ void
kinit()
{
initlock(&kmem.lock, "kmem");
+ if(PHYSTOP > RAMDISK)
+ panic("kinit");
freerange(end, (void*)PHYSTOP);
}
diff --git a/log.c b/log.c
index a64c0f6..c8f7e62 100644
--- a/log.c
+++ b/log.c
@@ -1,4 +1,5 @@
#include "types.h"
+#include "riscv.h"
#include "defs.h"
#include "param.h"
#include "spinlock.h"
diff --git a/main.c b/main.c
index 04e822a..d4a30f0 100644
--- a/main.c
+++ b/main.c
@@ -17,11 +17,9 @@ main()
kvminit(); // kernel page table
procinit(); // process table
trapinit(); // trap vectors
-#if 0
binit(); // buffer cache
fileinit(); // file table
- ideinit(); // disk
-#endif
+ ramdiskinit(); // disk
userinit(); // first user process
scheduler();
diff --git a/memlayout.h b/memlayout.h
index 798621e..9bc9c5d 100644
--- a/memlayout.h
+++ b/memlayout.h
@@ -4,6 +4,8 @@
// 00001000 -- boot ROM, provided by qemu
// 10000000 -- uart0 registers
// 80000000 -- boot ROM jumps here in machine mode
+// -kernel loads the kernel here
+// 88000000 -- -initrd fs.img ramdisk image.
// unused RAM after 80000000.
// the kernel uses physical memory thus:
@@ -14,6 +16,8 @@
// registers start here in physical memory.
#define UART0 0x10000000L
+#define RAMDISK 0x88000000
+
// the kernel expects there to be RAM
// for use by the kernel and user pages
// from physical address 0x80000000 to PHYSTOP.
diff --git a/pipe.c b/pipe.c
index e9abe7f..1274a3a 100644
--- a/pipe.c
+++ b/pipe.c
@@ -1,7 +1,7 @@
#include "types.h"
+#include "riscv.h"
#include "defs.h"
#include "param.h"
-#include "mmu.h"
#include "proc.h"
#include "fs.h"
#include "spinlock.h"
diff --git a/proc.c b/proc.c
index e574db0..a099e98 100644
--- a/proc.c
+++ b/proc.c
@@ -116,16 +116,13 @@ found:
return p;
}
-// XXX hack because I don't know how to incorporate initcode
-// into the kernel binary. just the exec system call, no arguments.
-// manually copied from initcode.asm.
+// a user program that calls exec("/init")
+// od -t xC initcode
unsigned char initcode[] = {
- 0x85, 0x48, // li a7, 1 -- SYS_fork
- 0x73, 0x00, 0x00, 0x00, // ecall
- 0x8d, 0x48, // li a7, 3 -- SYS_wait
- 0x73, 0x00, 0x00, 0x00, // ecall
- 0x89, 0x48, // li a7, 2 -- SYS_exit
- 0x73, 0x00, 0x00, 0x00, // ecall
+ 0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x02, 0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x05, 0x02,
+ 0x9d, 0x48, 0x73, 0x00, 0x00, 0x00, 0x89, 0x48, 0x73, 0x00, 0x00, 0x00, 0xef, 0xf0, 0xbf, 0xff,
+ 0x2f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00
};
//PAGEBREAK: 32
@@ -146,8 +143,7 @@ userinit(void)
p->tf->sp = PGSIZE;
safestrcpy(p->name, "initcode", sizeof(p->name));
- // XXX riscv
- //p->cwd = namei("/");
+ p->cwd = namei("/");
// this assignment to p->state lets other cores
// run this process. the acquire forces the above
@@ -210,13 +206,11 @@ fork(void)
// Cause fork to return 0 in the child.
np->tf->a0 = 0;
-#if 0 // XXX riscv
// increment reference counts on open file descriptors.
for(i = 0; i < NOFILE; i++)
if(p->ofile[i])
np->ofile[i] = filedup(p->ofile[i]);
np->cwd = idup(p->cwd);
-#endif
safestrcpy(np->name, p->name, sizeof(p->name));
@@ -244,7 +238,6 @@ exit(void)
if(p == initproc)
panic("init exiting");
-#if 0 // XXX riscv
// Close all open files.
for(fd = 0; fd < NOFILE; fd++){
if(p->ofile[fd]){
@@ -256,7 +249,6 @@ exit(void)
begin_op();
iput(p->cwd);
end_op();
-#endif
p->cwd = 0;
acquire(&ptable.lock);
@@ -423,9 +415,8 @@ forkret(void)
// of a regular process (e.g., they call sleep), and thus cannot
// be run from main().
first = 0;
- // XXX riscv
- //iinit(ROOTDEV);
- //initlog(ROOTDEV);
+ iinit(ROOTDEV);
+ initlog(ROOTDEV);
}
usertrapret();
diff --git a/ramdisk.c b/ramdisk.c
new file mode 100644
index 0000000..9901294
--- /dev/null
+++ b/ramdisk.c
@@ -0,0 +1,45 @@
+//
+// ramdisk that uses the disk image loaded by qemu -rdinit fs.img
+//
+
+#include "types.h"
+#include "riscv.h"
+#include "defs.h"
+#include "param.h"
+#include "memlayout.h"
+#include "spinlock.h"
+#include "sleeplock.h"
+#include "fs.h"
+#include "buf.h"
+
+void
+ramdiskinit(void)
+{
+}
+
+// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
+// Else if B_VALID is not set, read buf from disk, set B_VALID.
+void
+ramdiskrw(struct buf *b)
+{
+ if(!holdingsleep(&b->lock))
+ panic("ramdiskrw: buf not locked");
+ if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
+ panic("ramdiskrw: nothing to do");
+
+ if(b->blockno >= FSSIZE)
+ panic("ramdiskrw: blockno too big");
+
+ uint64 diskaddr = b->blockno * BSIZE;
+ char *addr = (char *)RAMDISK + diskaddr;
+
+ if(b->flags & B_DIRTY){
+ // write
+ memmove(addr, b->data, BSIZE);
+ b->flags &= ~B_DIRTY;
+ } else {
+ // read
+ memmove(b->data, addr, BSIZE);
+ b->flags |= B_VALID;
+ }
+}
diff --git a/sleeplock.c b/sleeplock.c
index e0750ea..b490370 100644
--- a/sleeplock.c
+++ b/sleeplock.c
@@ -1,11 +1,10 @@
// Sleeping locks
#include "types.h"
+#include "riscv.h"
#include "defs.h"
#include "param.h"
-#include "x86.h"
#include "memlayout.h"
-#include "mmu.h"
#include "proc.h"
#include "spinlock.h"
#include "sleeplock.h"
diff --git a/trapasm.S b/trapasm.S
deleted file mode 100644
index 6b6b567..0000000
--- a/trapasm.S
+++ /dev/null
@@ -1,132 +0,0 @@
-#include "param.h"
-#include "x86.h"
-#include "mmu.h"
-
-# the offset of cs in trapframe (i.e., tf->cs - tf)
-#define CSOFF 144
-
-# vectors.S sends all traps here.
-.globl alltraps
-alltraps:
- # Build trap frame.
- push %r15
- push %r14
- push %r13
- push %r12
- push %r11
- push %r10
- push %r9
- push %r8
- push %rdi
- push %rsi
- push %rbp
- push %rdx
- push %rcx
- push %rbx
- push %rax
-
- cmpw $SEG_KCODE, CSOFF(%rsp) # compare to saved cs
- jz 1f
- swapgs
-
-1:mov %rsp, %rdi # frame in arg1
- call trap
-
-# Return falls through to trapret...
-.globl trapret
-trapret:
- cli
- cmpw $SEG_KCODE, CSOFF(%rsp) # compare to saved cs
- jz 1f
- swapgs
-
-1:pop %rax
- pop %rbx
- pop %rcx
- pop %rdx
- pop %rbp
- pop %rsi
- pop %rdi
- pop %r8
- pop %r9
- pop %r10
- pop %r11
- pop %r12
- pop %r13
- pop %r14
- pop %r15
-
- add $16, %rsp # discard trapnum and errorcode
- iretq
-
-#PAGEBREAK!
-
-# syscall jumps here after syscall instruction
-.globl sysentry
-sysentry: # Build syscall frame.
- // load kernel stack address
- swapgs
- movq %rax, %gs:0 // save %rax in syscallno of cpu entry
- movq %rsp, %gs:8 // user sp
- movq %gs:16, %rax // proc entry
-
- movq %ss:0(%rax), %rax // load kstack from proc
- addq $(KSTACKSIZE), %rax
-
- movq %rax, %rsp
- movq %gs:0, %rax // restore rax
-
- push %gs:8
- push %rcx
- push %r11
- push %rax
-
- push %rbp
- push %rbx
- push %r12
- push %r13
- push %r14
- push %r15
-
- push %r9
- push %r8
- push %r10
- push %rdx
- push %rsi
- push %rdi
-
- mov %rsp, %rdi # frame in arg1
-
- call syscall
- # fall through to sysexit
-
-.globl sysexit
-sysexit:
- # to make sure we don't get any interrupts on the user stack while in
- # supervisor mode. insufficient? (see vunerability reports for sysret)
- cli
-
- pop %rdi
- pop %rsi
- pop %rdx
- pop %r10
- pop %r8
- pop %r9
-
- pop %r15
- pop %r14
- pop %r13
- pop %r12
- pop %rbx
- pop %rbp
-
- pop %rax
- pop %r11
- pop %rcx
-
- mov (%rsp),%rsp # switch to the user stack
- # there are two more values on the stack, but we don't care about them
- swapgs
-
- sysretq
-
diff --git a/ulib.c b/ulib.c
index 8e1e1a2..532fe42 100644
--- a/ulib.c
+++ b/ulib.c
@@ -2,7 +2,6 @@
#include "stat.h"
#include "fcntl.h"
#include "user.h"
-#include "x86.h"
char*
strcpy(char *s, const char *t)
@@ -36,7 +35,11 @@ strlen(const char *s)
void*
memset(void *dst, int c, uint n)
{
- stosb(dst, c, n);
+ char *cdst = (char *) dst;
+ int i;
+ for(i = 0; i < n; i++){
+ cdst[i] = c;
+ }
return dst;
}
diff --git a/usertests.c b/usertests.c
index 3cd8b34..292319e 100644
--- a/usertests.c
+++ b/usertests.c
@@ -5,7 +5,6 @@
#include "fs.h"
#include "fcntl.h"
#include "syscall.h"
-#include "traps.h"
#include "memlayout.h"
char buf[8192];
@@ -1713,35 +1712,6 @@ fsfull()
printf(1, "fsfull test finished\n");
}
-void
-uio()
-{
- #define RTC_ADDR 0x70
- #define RTC_DATA 0x71
-
- ushort port = 0;
- uchar val = 0;
- int pid;
-
- printf(1, "uio test\n");
- pid = fork();
- if(pid == 0){
- port = RTC_ADDR;
- val = 0x09; /* year */
- /* http://wiki.osdev.org/Inline_Assembly/Examples */
- asm volatile("outb %0,%1"::"a"(val), "d" (port));
- port = RTC_DATA;
- asm volatile("inb %1,%0" : "=a" (val) : "d" (port));
- printf(1, "uio: uio succeeded; test FAILED\n");
- exit();
- } else if(pid < 0){
- printf (1, "fork failed\n");
- exit();
- }
- wait();
- printf(1, "uio test done\n");
-}
-
void argptest()
{
int fd;
@@ -1813,8 +1783,6 @@ main(int argc, char *argv[])
forktest();
bigdir(); // slow
- uio();
-
exectest();
exit();
diff --git a/usys.S b/usys.S
deleted file mode 100644
index 69935e7..0000000
--- a/usys.S
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "syscall.h"
-#include "traps.h"
-
-#define SYSCALL(name) \
- .globl name; \
- name: \
- mov $SYS_ ## name, %rax; \
- syscall; \
- ret
-
-SYSCALL(fork)
-SYSCALL(exit)
-SYSCALL(wait)
-SYSCALL(pipe)
-SYSCALL(read)
-SYSCALL(write)
-SYSCALL(close)
-SYSCALL(kill)
-SYSCALL(exec)
-SYSCALL(open)
-SYSCALL(mknod)
-SYSCALL(unlink)
-SYSCALL(fstat)
-SYSCALL(link)
-SYSCALL(mkdir)
-SYSCALL(chdir)
-SYSCALL(dup)
-SYSCALL(getpid)
-SYSCALL(sbrk)
-SYSCALL(sleep)
-SYSCALL(uptime)
diff --git a/usys.pl b/usys.pl
new file mode 100755
index 0000000..f8d47d5
--- /dev/null
+++ b/usys.pl
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+
+# Generate usys.S, the stubs for syscalls.
+
+print "# generated by usys.pl - do not edit\n";
+
+print "#include \"syscall.h\"\n";
+
+sub entry {
+ my $name = shift;
+ print ".global $name\n";
+ print "${name}:\n";
+ print " li a7, SYS_${name}\n";
+ print " ecall\n";
+ print " ret\n";
+}
+
+entry("fork");
+entry("exit");
+entry("wait");
+entry("pipe");
+entry("read");
+entry("write");
+entry("close");
+entry("kill");
+entry("exec");
+entry("open");
+entry("mknod");
+entry("unlink");
+entry("fstat");
+entry("link");
+entry("mkdir");
+entry("chdir");
+entry("dup");
+entry("getpid");
+entry("sbrk");
+entry("sleep");
+entry("uptime");
diff --git a/vm.c b/vm.c
index 8c2ccb3..a0d6569 100644
--- a/vm.c
+++ b/vm.c
@@ -4,6 +4,7 @@
#include "elf.h"
#include "riscv.h"
#include "defs.h"
+#include "fs.h"
/*
* the kernel's page table.
@@ -37,6 +38,10 @@ kvminit()
mappages(kernel_pagetable, (uint64)etext, PHYSTOP-(uint64)etext,
(uint64)etext, PTE_R | PTE_W);
+ // map the qemu -initrd fs.img ramdisk
+ mappages(kernel_pagetable, RAMDISK, FSSIZE * BSIZE,
+ RAMDISK, PTE_R | PTE_W);
+
// map the trampoline for trap entry/exit to
// the highest virtual address in the kernel.
mappages(kernel_pagetable, TRAMPOLINE, PGSIZE,