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; + } +}