diff options
| -rw-r--r-- | console.c | 80 | ||||
| -rw-r--r-- | defs.h | 14 | ||||
| -rw-r--r-- | exec.c | 2 | ||||
| -rw-r--r-- | file.c | 87 | ||||
| -rw-r--r-- | fs.c | 3 | ||||
| -rw-r--r-- | param.h | 2 | ||||
| -rw-r--r-- | proc.c | 4 | ||||
| -rw-r--r-- | proc.h | 55 | ||||
| -rw-r--r-- | riscv.h | 11 | ||||
| -rw-r--r-- | syscall.c | 40 | ||||
| -rw-r--r-- | sysfile.c | 74 | ||||
| -rw-r--r-- | trampoline.S | 116 | ||||
| -rw-r--r-- | trap.c | 8 | ||||
| -rw-r--r-- | vm.c | 76 | 
14 files changed, 408 insertions, 164 deletions
| @@ -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; +} @@ -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])) @@ -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){ @@ -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;  } @@ -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);    } @@ -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 @@ -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, @@ -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 }; @@ -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 @@ -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); @@ -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) @@ -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");  } @@ -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; +  } +} | 
