summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--console.c80
-rw-r--r--defs.h14
-rw-r--r--exec.c2
-rw-r--r--file.c87
-rw-r--r--fs.c3
-rw-r--r--param.h2
-rw-r--r--proc.c4
-rw-r--r--proc.h55
-rw-r--r--riscv.h11
-rw-r--r--syscall.c40
-rw-r--r--sysfile.c74
-rw-r--r--trampoline.S116
-rw-r--r--trap.c8
-rw-r--r--vm.c76
14 files changed, 408 insertions, 164 deletions
diff --git a/console.c b/console.c
index 25a621a..41f53e9 100644
--- a/console.c
+++ b/console.c
@@ -13,6 +13,7 @@
#include "memlayout.h"
#include "riscv.h"
#include "defs.h"
+#include "proc.h"
static void consputc(int);
@@ -25,12 +26,6 @@ static struct {
static char digits[] = "0123456789abcdef";
-void
-consoleinit(void)
-{
- initlock(&cons.lock, "console");
-}
-
static void
printint(int xx, int base, int sign)
{
@@ -148,3 +143,76 @@ consputc(int c)
} else
uartputc(c);
}
+
+#define INPUT_BUF 128
+struct {
+ char buf[INPUT_BUF];
+ uint r; // Read index
+ uint w; // Write index
+ uint e; // Edit index
+} input;
+
+#define C(x) ((x)-'@') // Contro
+
+int
+consoleread(struct inode *ip, char *dst, int n)
+{
+ uint target;
+ int c;
+
+ iunlock(ip);
+ target = n;
+ acquire(&cons.lock);
+ while(n > 0){
+ while(input.r == input.w){
+ if(myproc()->killed){
+ release(&cons.lock);
+ ilock(ip);
+ return -1;
+ }
+ sleep(&input.r, &cons.lock);
+ }
+ c = input.buf[input.r++ % INPUT_BUF];
+ if(c == C('D')){ // EOF
+ if(n < target){
+ // Save ^D for next time, to make sure
+ // caller gets a 0-byte result.
+ input.r--;
+ }
+ break;
+ }
+ *dst++ = c;
+ --n;
+ if(c == '\n')
+ break;
+ }
+ release(&cons.lock);
+ ilock(ip);
+
+ return target - n;
+}
+
+int
+consolewrite(struct inode *ip, char *buf, int n)
+{
+ int i;
+
+ iunlock(ip);
+ acquire(&cons.lock);
+ for(i = 0; i < n; i++)
+ consputc(buf[i] & 0xff);
+ release(&cons.lock);
+ ilock(ip);
+
+ return n;
+}
+
+void
+consoleinit(void)
+{
+ initlock(&cons.lock, "console");
+
+ devsw[CONSOLE].write = consolewrite;
+ devsw[CONSOLE].read = consoleread;
+ cons.locking = 1;
+}
diff --git a/defs.h b/defs.h
index 26205ac..91a997d 100644
--- a/defs.h
+++ b/defs.h
@@ -31,9 +31,9 @@ struct file* filealloc(void);
void fileclose(struct file*);
struct file* filedup(struct file*);
void fileinit(void);
-int fileread(struct file*, char*, int n);
-int filestat(struct file*, struct stat*);
-int filewrite(struct file*, char*, int n);
+int fileread(struct file*, uint64, int n);
+int filestat(struct file*, uint64 addr);
+int filewrite(struct file*, uint64, int n);
// fs.c
void readsb(int dev, struct superblock *sb);
@@ -153,11 +153,11 @@ char* strncpy(char*, const char*, int);
// syscall.c
int argint(int, int*);
-int argptr(int, char**, int);
-int argstr(int, char**);
+int argptr(int, uint64*, int);
+int argstr(int, char*, int);
int argaddr(int, uint64 *);
int fetchint(uint64, int*);
-int fetchstr(uint64, char**);
+int fetchstr(uint64, char*, int);
int fetchaddr(uint64, uint64*);
void syscall();
@@ -188,6 +188,8 @@ void mappages(pagetable_t, uint64, uint64, uint64, int);
void unmappages(pagetable_t, uint64, uint64, int);
uint64 walkaddr(pagetable_t, uint64);
int copyout(pagetable_t, uint64, char *, uint64);
+int copyin(pagetable_t, char *, uint64, uint64);
+int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max);
// number of elements in fixed-size array
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
diff --git a/exec.c b/exec.c
index a9776bc..e6a0809 100644
--- a/exec.c
+++ b/exec.c
@@ -21,8 +21,6 @@ exec(char *path, char **argv)
struct proc *p = myproc();
uint64 oldsz = p->sz;
- printf("EXEC\n");
-
begin_op();
if((ip = namei(path)) == 0){
diff --git a/file.c b/file.c
index 6d3ffb3..44dd538 100644
--- a/file.c
+++ b/file.c
@@ -1,5 +1,5 @@
//
-// File descriptors
+// Support functions for system calls that involve file descriptors.
//
#include "types.h"
@@ -10,6 +10,8 @@
#include "spinlock.h"
#include "sleeplock.h"
#include "file.h"
+#include "stat.h"
+#include "proc.h"
struct devsw devsw[NDEV];
struct {
@@ -81,50 +83,92 @@ fileclose(struct file *f)
}
// Get metadata about file f.
+// addr is a user virtual address, pointing to a struct stat.
int
-filestat(struct file *f, struct stat *st)
+filestat(struct file *f, uint64 addr)
{
+ struct proc *p = myproc();
+ struct stat st;
+
if(f->type == FD_INODE){
ilock(f->ip);
- stati(f->ip, st);
+ stati(f->ip, &st);
iunlock(f->ip);
+ if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
+ return -1;
return 0;
}
return -1;
}
// Read from file f.
+// addr is a user virtual address.
int
-fileread(struct file *f, char *addr, int n)
+fileread(struct file *f, uint64 addr, int n)
{
- int r;
+ struct proc *p = myproc();
+ int r = 0;
+ char *buf;
if(f->readable == 0)
return -1;
- if(f->type == FD_PIPE)
- return piperead(f->pipe, addr, n);
- if(f->type == FD_INODE){
+
+ // XXX break into page-size pieces.
+ if(n > PGSIZE)
+ panic("fileread PGSIZE");
+
+ buf = kalloc();
+ if(buf == 0)
+ panic("fileread kalloc");
+
+ if(f->type == FD_PIPE){
+ r = piperead(f->pipe, buf, n);
+ } else if(f->type == FD_INODE){
ilock(f->ip);
- if((r = readi(f->ip, addr, f->off, n)) > 0)
+ if((r = readi(f->ip, buf, f->off, n)) > 0)
f->off += r;
iunlock(f->ip);
- return r;
+ } else {
+ panic("fileread");
}
- panic("fileread");
+
+ if(r > 0){
+ if(copyout(p->pagetable, addr, buf, n) < 0){
+ r = -1;
+ }
+ }
+
+ kfree(buf);
+
+ return r;
}
//PAGEBREAK!
// Write to file f.
+// addr is a user virtual address.
int
-filewrite(struct file *f, char *addr, int n)
+filewrite(struct file *f, uint64 addr, int n)
{
- int r;
+ struct proc *p = myproc();
+ int r, ret = 0;
+ char *buf;
if(f->writable == 0)
return -1;
- if(f->type == FD_PIPE)
- return pipewrite(f->pipe, addr, n);
- if(f->type == FD_INODE){
+
+ // XXX break into pieces
+ if(n > PGSIZE)
+ panic("filewrite PGSIZE");
+
+ buf = kalloc();
+ if(copyin(p->pagetable, buf, addr, n) < 0){
+ kfree(buf);
+ return -1;
+ }
+
+ if(f->type == FD_PIPE){
+ ret = pipewrite(f->pipe, buf, n);
+ } else if(f->type == FD_INODE){
// write a few blocks at a time to avoid exceeding
// the maximum log transaction size, including
// i-node, indirect block, allocation blocks,
@@ -140,7 +184,7 @@ filewrite(struct file *f, char *addr, int n)
begin_op();
ilock(f->ip);
- if ((r = writei(f->ip, addr + i, f->off, n1)) > 0)
+ if ((r = writei(f->ip, buf + i, f->off, n1)) > 0)
f->off += r;
iunlock(f->ip);
end_op();
@@ -151,8 +195,13 @@ filewrite(struct file *f, char *addr, int n)
panic("short filewrite");
i += r;
}
- return i == n ? n : -1;
+ ret = (i == n ? n : -1);
+ } else {
+ panic("filewrite");
}
- panic("filewrite");
+
+ kfree(buf);
+
+ return ret;
}
diff --git a/fs.c b/fs.c
index ae96567..beea46d 100644
--- a/fs.c
+++ b/fs.c
@@ -486,8 +486,9 @@ writei(struct inode *ip, char *src, uint off, uint n)
struct buf *bp;
if(ip->type == T_DEV){
- if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write)
+ if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write){
return -1;
+ }
return devsw[ip->major].write(ip, src, n);
}
diff --git a/param.h b/param.h
index 24f8c8f..b5fdcb2 100644
--- a/param.h
+++ b/param.h
@@ -10,4 +10,4 @@
#define LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
#define FSSIZE 1000 // size of file system in blocks
-
+#define MAXPATH 128 // maximum file path name
diff --git a/proc.c b/proc.c
index f0120c2..909b88d 100644
--- a/proc.c
+++ b/proc.c
@@ -24,7 +24,7 @@ extern void sysexit(void);
static void wakeup1(void *chan);
-extern char trampstart[]; // trampoline.S
+extern char trampout[]; // trampoline.S
void
procinit(void)
@@ -123,7 +123,7 @@ proc_pagetable(struct proc *p)
// only the supervisor uses it, on the way
// to/from user space, so not PTE_U.
mappages(pagetable, TRAMPOLINE, PGSIZE,
- (uint64)trampstart, PTE_R | PTE_X);
+ (uint64)trampout, PTE_R | PTE_X);
// map the trapframe, for trampoline.S.
mappages(pagetable, (TRAMPOLINE - PGSIZE), PGSIZE,
diff --git a/proc.h b/proc.h
index 1e2238c..7e1149f 100644
--- a/proc.h
+++ b/proc.h
@@ -41,31 +41,46 @@ extern int ncpu;
// the sscratch register points here.
// trampoline.S saves user registers, then restores kernel_sp and
// kernel_satp.
-// no need to save s0-s11 (callee-saved) since C code and swtch() save them.
+// includes callee-saved registers like s0-s11 because the
+// return-to-user path via usertrapret() doesn't return through
+// the entire kernel call stack.
struct trapframe {
/* 0 */ uint64 kernel_satp;
/* 8 */ uint64 kernel_sp;
/* 16 */ uint64 kernel_trap; // address of trap()
/* 24 */ uint64 epc; // saved user program counter
- /* 32 */ uint64 ra;
- /* 40 */ uint64 sp;
- /* 48 */ uint64 gp;
- /* 56 */ uint64 tp;
- /* 64 */ uint64 t0;
- /* 72 */ uint64 t1;
- /* 80 */ uint64 t2;
- /* 88 */ uint64 a0;
- /* 96 */ uint64 a1;
- /* 104 */ uint64 a2;
- /* 112 */ uint64 a3;
- /* 120 */ uint64 a4;
- /* 128 */ uint64 a5;
- /* 136 */ uint64 a6;
- /* 144 */ uint64 a7;
- /* 152 */ uint64 t3;
- /* 160 */ uint64 t4;
- /* 168 */ uint64 t5;
- /* 176 */ uint64 t6;
+ /* 32 */ uint64 unused;
+ /* 40 */ uint64 ra;
+ /* 48 */ uint64 sp;
+ /* 56 */ uint64 gp;
+ /* 64 */ uint64 tp;
+ /* 72 */ uint64 t0;
+ /* 80 */ uint64 t1;
+ /* 88 */ uint64 t2;
+ /* 96 */ uint64 s0;
+ /* 104 */ uint64 s1;
+ /* 112 */ uint64 a0;
+ /* 120 */ uint64 a1;
+ /* 128 */ uint64 a2;
+ /* 136 */ uint64 a3;
+ /* 144 */ uint64 a4;
+ /* 152 */ uint64 a5;
+ /* 160 */ uint64 a6;
+ /* 168 */ uint64 a7;
+ /* 176 */ uint64 s2;
+ /* 184 */ uint64 s3;
+ /* 192 */ uint64 s4;
+ /* 200 */ uint64 s5;
+ /* 208 */ uint64 s6;
+ /* 216 */ uint64 s7;
+ /* 224 */ uint64 s8;
+ /* 232 */ uint64 s9;
+ /* 240 */ uint64 s10;
+ /* 248 */ uint64 s11;
+ /* 256 */ uint64 t3;
+ /* 264 */ uint64 t4;
+ /* 272 */ uint64 t5;
+ /* 280 */ uint64 t6;
};
enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
diff --git a/riscv.h b/riscv.h
index 92fa6e3..5e54935 100644
--- a/riscv.h
+++ b/riscv.h
@@ -129,7 +129,7 @@ w_sscratch(uint64 x)
asm("csrw sscratch, %0" : : "r" (x));
}
-// Supervisor trap cause
+// Supervisor Trap Cause
static inline uint64
r_scause()
{
@@ -138,6 +138,15 @@ r_scause()
return x;
}
+// Supervisor Trap Value
+static inline uint64
+r_stval()
+{
+ uint64 x;
+ asm("csrr %0, stval" : "=r" (x) );
+ return x;
+}
+
#define PGSIZE 4096 // bytes per page
#define PGSHIFT 12 // bits of offset within a page
diff --git a/syscall.c b/syscall.c
index b0ab16d..bcfdcf8 100644
--- a/syscall.c
+++ b/syscall.c
@@ -20,7 +20,8 @@ fetchint(uint64 addr, int *ip)
if(addr >= p->sz || addr+4 > p->sz)
return -1;
- *ip = *(uint64*)(addr);
+ if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
+ return -1;
return 0;
}
@@ -31,28 +32,22 @@ fetchaddr(uint64 addr, uint64 *ip)
struct proc *p = myproc();
if(addr >= p->sz || addr+sizeof(uint64) > p->sz)
return -1;
- *ip = *(uint64*)(addr);
+ if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
+ return -1;
return 0;
}
// Fetch the nul-terminated string at addr from the current process.
// Doesn't actually copy the string - just sets *pp to point at it.
-// Returns length of string, not including nul.
+// Returns length of string, not including nul, or -1 for error.
int
-fetchstr(uint64 addr, char **pp)
+fetchstr(uint64 addr, char *buf, int max)
{
- char *s, *ep;
struct proc *p = myproc();
-
- if(addr >= p->sz)
- return -1;
- *pp = (char*)addr;
- ep = (char*)p->sz;
- for(s = *pp; s < ep; s++){
- if(*s == 0)
- return s - *pp;
- }
- return -1;
+ int err = copyinstr(p->pagetable, buf, addr, max);
+ if(err < 0)
+ return err;
+ return strlen(buf);
}
static uint64
@@ -96,7 +91,7 @@ argaddr(int n, uint64 *ip)
// to a block of memory of size bytes. Check that the pointer
// lies within the process address space.
int
-argptr(int n, char **pp, int size)
+argptr(int n, uint64 *pp, int size)
{
uint64 i;
struct proc *p = myproc();
@@ -105,21 +100,20 @@ argptr(int n, char **pp, int size)
return -1;
if(size < 0 || (uint)i >= p->sz || (uint)i+size > p->sz)
return -1;
- *pp = (char*)i;
+ *pp = i;
return 0;
}
-// Fetch the nth word-sized system call argument as a string pointer.
-// Check that the pointer is valid and the string is nul-terminated.
-// (There is no shared writable memory, so the string can't change
-// between this check and being used by the kernel.)
+// Fetch the nth word-sized system call argument as a null-terminated string.
+// Copies into buf, at most max.
+// Returns string length if OK (including nul), -1 if error.
int
-argstr(int n, char **pp)
+argstr(int n, char *buf, int max)
{
uint64 addr;
if(argaddr(n, &addr) < 0)
return -1;
- return fetchstr(addr, pp);
+ return fetchstr(addr, buf, max);
}
extern int sys_chdir(void);
diff --git a/sysfile.c b/sysfile.c
index 5194d35..86e734a 100644
--- a/sysfile.c
+++ b/sysfile.c
@@ -71,7 +71,7 @@ sys_read(void)
{
struct file *f;
int n;
- char *p;
+ uint64 p;
if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
return -1;
@@ -83,10 +83,11 @@ sys_write(void)
{
struct file *f;
int n;
- char *p;
+ uint64 p;
if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
return -1;
+
return filewrite(f, p, n);
}
@@ -107,9 +108,9 @@ int
sys_fstat(void)
{
struct file *f;
- struct stat *st;
+ uint64 st; // user pointer to struct stat
- if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
+ if(argfd(0, 0, &f) < 0 || argptr(1, &st, sizeof(struct stat)) < 0)
return -1;
return filestat(f, st);
}
@@ -118,10 +119,10 @@ sys_fstat(void)
int
sys_link(void)
{
- char name[DIRSIZ], *new, *old;
+ char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
struct inode *dp, *ip;
- if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
+ if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
return -1;
begin_op();
@@ -186,10 +187,10 @@ sys_unlink(void)
{
struct inode *ip, *dp;
struct dirent de;
- char name[DIRSIZ], *path;
+ char name[DIRSIZ], path[MAXPATH];
uint off;
- if(argstr(0, &path) < 0)
+ if(argstr(0, path, MAXPATH) < 0)
return -1;
begin_op();
@@ -286,12 +287,12 @@ create(char *path, short type, short major, short minor)
int
sys_open(void)
{
- char *path;
+ char path[MAXPATH];
int fd, omode;
struct file *f;
struct inode *ip;
- if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
+ if(argstr(0, path, MAXPATH) < 0 || argint(1, &omode) < 0)
return -1;
begin_op();
@@ -336,11 +337,11 @@ sys_open(void)
int
sys_mkdir(void)
{
- char *path;
+ char path[MAXPATH];
struct inode *ip;
begin_op();
- if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
+ if(argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
end_op();
return -1;
}
@@ -353,11 +354,11 @@ int
sys_mknod(void)
{
struct inode *ip;
- char *path;
+ char path[MAXPATH];
int major, minor;
begin_op();
- if((argstr(0, &path)) < 0 ||
+ if((argstr(0, path, MAXPATH)) < 0 ||
argint(1, &major) < 0 ||
argint(2, &minor) < 0 ||
(ip = create(path, T_DEV, major, minor)) == 0){
@@ -372,12 +373,12 @@ sys_mknod(void)
int
sys_chdir(void)
{
- char *path;
+ char path[MAXPATH];
struct inode *ip;
struct proc *p = myproc();
begin_op();
- if(argstr(0, &path) < 0 || (ip = namei(path)) == 0){
+ if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0){
end_op();
return -1;
}
@@ -397,59 +398,68 @@ sys_chdir(void)
int
sys_exec(void)
{
- char *path, *argv[MAXARG];
+ char path[MAXPATH], *argv[MAXARG];
int i;
uint64 uargv, uarg;
- printf("sys_exec\n");
-
- if(argstr(0, &path) < 0 || argaddr(1, &uargv) < 0){
- printf("error 1\n");
+ if(argstr(0, path, MAXPATH) < 0 || argaddr(1, &uargv) < 0){
return -1;
}
memset(argv, 0, sizeof(argv));
for(i=0;; i++){
if(i >= NELEM(argv)){
- printf("error 2\n");
return -1;
}
if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){
- printf("error 3\n");
return -1;
}
if(uarg == 0){
argv[i] = 0;
break;
}
- if(fetchstr(uarg, &argv[i]) < 0){
- printf("error 4\n");
+ argv[i] = kalloc();
+ if(argv[i] == 0)
+ panic("sys_exec kalloc");
+ if(fetchstr(uarg, argv[i], PGSIZE) < 0){
return -1;
}
}
- printf("calling exec\n");
- return exec(path, argv);
+
+ int ret = exec(path, argv);
+
+ for(i = 0; i < NELEM(argv) && argv[i] != 0; i++)
+ kfree(argv[i]);
+
+ return ret;
}
int
sys_pipe(void)
{
- int *fd;
+ uint64 fdarray; // user pointer to array of two integers
struct file *rf, *wf;
int fd0, fd1;
+ struct proc *p = myproc();
- if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
+ if(argptr(0, &fdarray, 2*sizeof(int)) < 0)
return -1;
if(pipealloc(&rf, &wf) < 0)
return -1;
fd0 = -1;
if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
if(fd0 >= 0)
- myproc()->ofile[fd0] = 0;
+ p->ofile[fd0] = 0;
+ fileclose(rf);
+ fileclose(wf);
+ return -1;
+ }
+ if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 ||
+ copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){
+ p->ofile[fd0] = 0;
+ p->ofile[fd1] = 0;
fileclose(rf);
fileclose(wf);
return -1;
}
- fd[0] = fd0;
- fd[1] = fd1;
return 0;
}
diff --git a/trampoline.S b/trampoline.S
index 109dd93..5886942 100644
--- a/trampoline.S
+++ b/trampoline.S
@@ -5,14 +5,15 @@
# in user and kernel space so that it can switch
# page tables.
#
- # kernel.ld causes trampstart to be aligned
+ # kernel.ld causes trampout to be aligned
# to a page boundary.
#
.globl usertrap
.section trampoline
-.globl trampstart
-trampstart:
+.globl trampout
+trampout:
# switch from kernel to user.
+ # usertrapret() calls here.
# a0: p->tf in user page table
# a1: new value for satp, for user page table
@@ -21,28 +22,40 @@ trampstart:
# put the saved user a0 in sscratch, so we
# can swap it with our a0 (p->tf) in the last step.
- ld t0, 80(a0)
+ ld t0, 112(a0)
csrw sscratch, t0
# restore all but a0 from p->tf
- ld ra, 32(a0)
- ld sp, 40(a0)
- ld gp, 48(a0)
- ld tp, 56(a0)
- ld t0, 64(a0)
- ld t1, 72(a0)
- ld t2, 80(a0)
- ld a1, 96(a0)
- ld a2, 104(a0)
- ld a3, 112(a0)
- ld a4, 120(a0)
- ld a5, 128(a0)
- ld a6, 136(a0)
- ld a7, 144(a0)
- ld t3, 152(a0)
- ld t4, 160(a0)
- ld t5, 168(a0)
- ld t6, 176(a0)
+ ld ra, 40(a0)
+ ld sp, 48(a0)
+ ld gp, 56(a0)
+ ld tp, 64(a0)
+ ld t0, 72(a0)
+ ld t1, 80(a0)
+ ld t2, 88(a0)
+ ld s0, 96(a0)
+ ld s1, 104(a0)
+ ld a1, 120(a0)
+ ld a2, 128(a0)
+ ld a3, 136(a0)
+ ld a4, 144(a0)
+ ld a5, 152(a0)
+ ld a6, 160(a0)
+ ld a7, 168(a0)
+ ld s2, 176(a0)
+ ld s3, 184(a0)
+ ld s4, 192(a0)
+ ld s5, 200(a0)
+ ld s6, 208(a0)
+ ld s7, 216(a0)
+ ld s8, 224(a0)
+ ld s9, 232(a0)
+ ld s10, 240(a0)
+ ld s11, 248(a0)
+ ld t3, 256(a0)
+ ld t4, 264(a0)
+ ld t5, 272(a0)
+ ld t6, 280(a0)
# restore user a0, and save p->tf
csrrw a0, sscratch, a0
@@ -51,45 +64,58 @@ trampstart:
# caller has set up sstatus and sepc.
sret
+.align 4
+.globl trampin
+trampin:
#
# trap.c set stvec to point here, so
- # interrupts and exceptions start here,
+ # user interrupts and exceptions start here,
# in supervisor mode, but with a
# user page table.
#
# sscratch points to where the process's p->tf is
# mapped into user space (TRAMPOLINE - 4096).
#
-.align 4
-.globl trampvec
-trampvec:
+
# swap a0 and sscratch
# so that a0 is p->tf
csrrw a0, sscratch, a0
# save the user registers in p->tf
- sd ra, 32(a0)
- sd sp, 40(a0)
- sd gp, 48(a0)
- sd tp, 56(a0)
- sd t0, 64(a0)
- sd t1, 72(a0)
- sd t2, 80(a0)
- sd a1, 96(a0)
- sd a2, 104(a0)
- sd a3, 112(a0)
- sd a4, 120(a0)
- sd a5, 128(a0)
- sd a6, 136(a0)
- sd a7, 144(a0)
- sd t3, 152(a0)
- sd t4, 160(a0)
- sd t5, 168(a0)
- sd t6, 176(a0)
+ sd ra, 40(a0)
+ sd sp, 48(a0)
+ sd gp, 56(a0)
+ sd tp, 64(a0)
+ sd t0, 72(a0)
+ sd t1, 80(a0)
+ sd t2, 88(a0)
+ sd s0, 96(a0)
+ sd s1, 104(a0)
+ sd a1, 120(a0)
+ sd a2, 128(a0)
+ sd a3, 136(a0)
+ sd a4, 144(a0)
+ sd a5, 152(a0)
+ sd a6, 160(a0)
+ sd a7, 168(a0)
+ sd s2, 176(a0)
+ sd s3, 184(a0)
+ sd s4, 192(a0)
+ sd s5, 200(a0)
+ sd s6, 208(a0)
+ sd s7, 216(a0)
+ sd s8, 224(a0)
+ sd s9, 232(a0)
+ sd s10, 240(a0)
+ sd s11, 248(a0)
+ sd t3, 256(a0)
+ sd t4, 264(a0)
+ sd t5, 272(a0)
+ sd t6, 280(a0)
# save the user a0 in p->tf->a0
csrr t0, sscratch
- sd t0, 80(a0)
+ sd t0, 112(a0)
# restore kernel stack pointer from p->tf->kernel_sp
ld sp, 8(a0)
diff --git a/trap.c b/trap.c
index 6d4854e..74f3456 100644
--- a/trap.c
+++ b/trap.c
@@ -9,7 +9,7 @@
struct spinlock tickslock;
uint ticks;
-extern char trampstart[], trampvec[];
+extern char trampout[], trampin[];
void kerneltrap();
@@ -53,6 +53,7 @@ usertrap(void)
syscall();
} else {
printf("usertrap(): unexpected scause 0x%x pid=%d\n", r_scause(), p->pid);
+ printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
panic("usertrap");
}
@@ -71,7 +72,7 @@ usertrapret(void)
// now from kerneltrap() to usertrap().
// send interrupts and exceptions to trampoline.S
- w_stvec(TRAMPOLINE + (trampvec - trampstart));
+ w_stvec(TRAMPOLINE + (trampin - trampout));
// set up values that trampoline.S will need when
// the process next re-enters the kernel.
@@ -108,5 +109,8 @@ kerneltrap()
if((r_sstatus() & SSTATUS_SPP) == 0)
panic("kerneltrap: not from supervisor mode");
+ printf("scause 0x%x\n", r_scause());
+ printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
+
panic("kerneltrap");
}
diff --git a/vm.c b/vm.c
index 27fb690..791f78f 100644
--- a/vm.c
+++ b/vm.c
@@ -13,7 +13,7 @@ pagetable_t kernel_pagetable;
extern char etext[]; // kernel.ld sets this to end of kernel code.
-extern char trampstart[]; // trampoline.S
+extern char trampout[]; // trampoline.S
/*
* create a direct-map page table for the kernel and
@@ -45,7 +45,7 @@ kvminit()
// map the trampoline for trap entry/exit to
// the highest virtual address in the kernel.
mappages(kernel_pagetable, TRAMPOLINE, PGSIZE,
- (uint64)trampstart, PTE_R | PTE_X);
+ (uint64)trampout, PTE_R | PTE_X);
kvmswitch();
}
@@ -213,7 +213,7 @@ uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
return 0;
}
memset(mem, 0, PGSIZE);
- mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R);
+ mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U);
}
return newsz;
}
@@ -287,8 +287,8 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
}
}
+// Copy from kernel to user.
// Copy len bytes from src to virtual address dstva in a given page table.
-// Most useful when pagetable is not the current page table.
// Return 0 on success, -1 on error.
int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
@@ -311,3 +311,71 @@ copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
}
return 0;
}
+
+// Copy from user to kernel.
+// Copy len bytes to dst from virtual address srcva in a given page table.
+// Return 0 on success, -1 on error.
+int
+copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
+{
+ uint64 n, va0, pa0;
+
+ while(len > 0){
+ va0 = (uint)PGROUNDDOWN(srcva);
+ pa0 = walkaddr(pagetable, va0);
+ if(pa0 == 0)
+ return -1;
+ n = PGSIZE - (srcva - va0);
+ if(n > len)
+ n = len;
+ memmove(dst, (void *)(pa0 + (srcva - va0)), n);
+
+ len -= n;
+ dst += n;
+ srcva = va0 + PGSIZE;
+ }
+ return 0;
+}
+
+// Copy a null-terminated from user to kernel.
+// Copy bytes to dst from virtual address srcva in a given page table,
+// until a '\0', or max.
+// Return 0 on success, -1 on error.
+int
+copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
+{
+ uint64 n, va0, pa0;
+ int got_null = 0;
+
+ while(got_null == 0 && max > 0){
+ va0 = (uint)PGROUNDDOWN(srcva);
+ pa0 = walkaddr(pagetable, va0);
+ if(pa0 == 0)
+ return -1;
+ n = PGSIZE - (srcva - va0);
+ if(n > max)
+ n = max;
+
+ char *p = (char *) (pa0 + (srcva - va0));
+ while(n > 0){
+ if(*p == '\0'){
+ *dst = '\0';
+ got_null = 1;
+ break;
+ } else {
+ *dst = *p;
+ }
+ --n;
+ --max;
+ p++;
+ dst++;
+ }
+
+ srcva = va0 + PGSIZE;
+ }
+ if(got_null){
+ return 0;
+ } else {
+ return -1;
+ }
+}