first shell prints $ prompt, though no console input yet
This commit is contained in:
parent
7fd1f1eb0a
commit
50cbc75102
80
console.c
80
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;
|
||||
}
|
||||
|
|
14
defs.h
14
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]))
|
||||
|
|
2
exec.c
2
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){
|
||||
|
|
87
file.c
87
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;
|
||||
}
|
||||
|
||||
|
|
3
fs.c
3
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);
|
||||
}
|
||||
|
||||
|
|
2
param.h
2
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
|
||||
|
|
4
proc.c
4
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,
|
||||
|
|
55
proc.h
55
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 };
|
||||
|
|
11
riscv.h
11
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
|
||||
|
||||
|
|
40
syscall.c
40
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);
|
||||
|
|
74
sysfile.c
74
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;
|
||||
}
|
||||
|
|
116
trampoline.S
116
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)
|
||||
|
|
8
trap.c
8
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");
|
||||
}
|
||||
|
|
76
vm.c
76
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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue