first shell prints $ prompt, though no console input yet

This commit is contained in:
Robert Morris 2019-06-01 05:33:38 -04:00
parent 7fd1f1eb0a
commit 50cbc75102
14 changed files with 408 additions and 164 deletions

View file

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

14
defs.h
View file

@ -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]))

2
exec.c
View file

@ -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){

87
file.c
View file

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

3
fs.c
View file

@ -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);
}

View file

@ -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

4
proc.c
View file

@ -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,

55
proc.h
View file

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

11
riscv.h
View file

@ -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

View file

@ -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);

View file

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

View file

@ -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)

8
trap.c
View file

@ -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");
}

76
vm.c
View file

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