first shell prints $ prompt, though no console input yet
This commit is contained in:
parent
7fd1f1eb0a
commit
50cbc75102
14 changed files with 408 additions and 164 deletions
80
console.c
80
console.c
|
@ -13,6 +13,7 @@
|
||||||
#include "memlayout.h"
|
#include "memlayout.h"
|
||||||
#include "riscv.h"
|
#include "riscv.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
#include "proc.h"
|
||||||
|
|
||||||
static void consputc(int);
|
static void consputc(int);
|
||||||
|
|
||||||
|
@ -25,12 +26,6 @@ static struct {
|
||||||
|
|
||||||
static char digits[] = "0123456789abcdef";
|
static char digits[] = "0123456789abcdef";
|
||||||
|
|
||||||
void
|
|
||||||
consoleinit(void)
|
|
||||||
{
|
|
||||||
initlock(&cons.lock, "console");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
printint(int xx, int base, int sign)
|
printint(int xx, int base, int sign)
|
||||||
{
|
{
|
||||||
|
@ -148,3 +143,76 @@ consputc(int c)
|
||||||
} else
|
} else
|
||||||
uartputc(c);
|
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*);
|
void fileclose(struct file*);
|
||||||
struct file* filedup(struct file*);
|
struct file* filedup(struct file*);
|
||||||
void fileinit(void);
|
void fileinit(void);
|
||||||
int fileread(struct file*, char*, int n);
|
int fileread(struct file*, uint64, int n);
|
||||||
int filestat(struct file*, struct stat*);
|
int filestat(struct file*, uint64 addr);
|
||||||
int filewrite(struct file*, char*, int n);
|
int filewrite(struct file*, uint64, int n);
|
||||||
|
|
||||||
// fs.c
|
// fs.c
|
||||||
void readsb(int dev, struct superblock *sb);
|
void readsb(int dev, struct superblock *sb);
|
||||||
|
@ -153,11 +153,11 @@ char* strncpy(char*, const char*, int);
|
||||||
|
|
||||||
// syscall.c
|
// syscall.c
|
||||||
int argint(int, int*);
|
int argint(int, int*);
|
||||||
int argptr(int, char**, int);
|
int argptr(int, uint64*, int);
|
||||||
int argstr(int, char**);
|
int argstr(int, char*, int);
|
||||||
int argaddr(int, uint64 *);
|
int argaddr(int, uint64 *);
|
||||||
int fetchint(uint64, int*);
|
int fetchint(uint64, int*);
|
||||||
int fetchstr(uint64, char**);
|
int fetchstr(uint64, char*, int);
|
||||||
int fetchaddr(uint64, uint64*);
|
int fetchaddr(uint64, uint64*);
|
||||||
void syscall();
|
void syscall();
|
||||||
|
|
||||||
|
@ -188,6 +188,8 @@ void mappages(pagetable_t, uint64, uint64, uint64, int);
|
||||||
void unmappages(pagetable_t, uint64, uint64, int);
|
void unmappages(pagetable_t, uint64, uint64, int);
|
||||||
uint64 walkaddr(pagetable_t, uint64);
|
uint64 walkaddr(pagetable_t, uint64);
|
||||||
int copyout(pagetable_t, uint64, char *, 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
|
// number of elements in fixed-size array
|
||||||
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
|
#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();
|
struct proc *p = myproc();
|
||||||
uint64 oldsz = p->sz;
|
uint64 oldsz = p->sz;
|
||||||
|
|
||||||
printf("EXEC\n");
|
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
|
|
||||||
if((ip = namei(path)) == 0){
|
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"
|
#include "types.h"
|
||||||
|
@ -10,6 +10,8 @@
|
||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
#include "sleeplock.h"
|
#include "sleeplock.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
#include "stat.h"
|
||||||
|
#include "proc.h"
|
||||||
|
|
||||||
struct devsw devsw[NDEV];
|
struct devsw devsw[NDEV];
|
||||||
struct {
|
struct {
|
||||||
|
@ -81,50 +83,92 @@ fileclose(struct file *f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get metadata about file f.
|
// Get metadata about file f.
|
||||||
|
// addr is a user virtual address, pointing to a struct stat.
|
||||||
int
|
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){
|
if(f->type == FD_INODE){
|
||||||
ilock(f->ip);
|
ilock(f->ip);
|
||||||
stati(f->ip, st);
|
stati(f->ip, &st);
|
||||||
iunlock(f->ip);
|
iunlock(f->ip);
|
||||||
|
if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
|
||||||
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read from file f.
|
// Read from file f.
|
||||||
|
// addr is a user virtual address.
|
||||||
int
|
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)
|
if(f->readable == 0)
|
||||||
return -1;
|
return -1;
|
||||||
if(f->type == FD_PIPE)
|
|
||||||
return piperead(f->pipe, addr, n);
|
// XXX break into page-size pieces.
|
||||||
if(f->type == FD_INODE){
|
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);
|
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;
|
f->off += r;
|
||||||
iunlock(f->ip);
|
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!
|
//PAGEBREAK!
|
||||||
// Write to file f.
|
// Write to file f.
|
||||||
|
// addr is a user virtual address.
|
||||||
int
|
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)
|
if(f->writable == 0)
|
||||||
return -1;
|
return -1;
|
||||||
if(f->type == FD_PIPE)
|
|
||||||
return pipewrite(f->pipe, addr, n);
|
// XXX break into pieces
|
||||||
if(f->type == FD_INODE){
|
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
|
// write a few blocks at a time to avoid exceeding
|
||||||
// the maximum log transaction size, including
|
// the maximum log transaction size, including
|
||||||
// i-node, indirect block, allocation blocks,
|
// i-node, indirect block, allocation blocks,
|
||||||
|
@ -140,7 +184,7 @@ filewrite(struct file *f, char *addr, int n)
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
ilock(f->ip);
|
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;
|
f->off += r;
|
||||||
iunlock(f->ip);
|
iunlock(f->ip);
|
||||||
end_op();
|
end_op();
|
||||||
|
@ -151,8 +195,13 @@ filewrite(struct file *f, char *addr, int n)
|
||||||
panic("short filewrite");
|
panic("short filewrite");
|
||||||
i += r;
|
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;
|
struct buf *bp;
|
||||||
|
|
||||||
if(ip->type == T_DEV){
|
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 -1;
|
||||||
|
}
|
||||||
return devsw[ip->major].write(ip, src, n);
|
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 LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log
|
||||||
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
|
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
|
||||||
#define FSSIZE 1000 // size of file system in blocks
|
#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);
|
static void wakeup1(void *chan);
|
||||||
|
|
||||||
extern char trampstart[]; // trampoline.S
|
extern char trampout[]; // trampoline.S
|
||||||
|
|
||||||
void
|
void
|
||||||
procinit(void)
|
procinit(void)
|
||||||
|
@ -123,7 +123,7 @@ proc_pagetable(struct proc *p)
|
||||||
// only the supervisor uses it, on the way
|
// only the supervisor uses it, on the way
|
||||||
// to/from user space, so not PTE_U.
|
// to/from user space, so not PTE_U.
|
||||||
mappages(pagetable, TRAMPOLINE, PGSIZE,
|
mappages(pagetable, TRAMPOLINE, PGSIZE,
|
||||||
(uint64)trampstart, PTE_R | PTE_X);
|
(uint64)trampout, PTE_R | PTE_X);
|
||||||
|
|
||||||
// map the trapframe, for trampoline.S.
|
// map the trapframe, for trampoline.S.
|
||||||
mappages(pagetable, (TRAMPOLINE - PGSIZE), PGSIZE,
|
mappages(pagetable, (TRAMPOLINE - PGSIZE), PGSIZE,
|
||||||
|
|
55
proc.h
55
proc.h
|
@ -41,31 +41,46 @@ extern int ncpu;
|
||||||
// the sscratch register points here.
|
// the sscratch register points here.
|
||||||
// trampoline.S saves user registers, then restores kernel_sp and
|
// trampoline.S saves user registers, then restores kernel_sp and
|
||||||
// kernel_satp.
|
// 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 {
|
struct trapframe {
|
||||||
/* 0 */ uint64 kernel_satp;
|
/* 0 */ uint64 kernel_satp;
|
||||||
/* 8 */ uint64 kernel_sp;
|
/* 8 */ uint64 kernel_sp;
|
||||||
/* 16 */ uint64 kernel_trap; // address of trap()
|
/* 16 */ uint64 kernel_trap; // address of trap()
|
||||||
/* 24 */ uint64 epc; // saved user program counter
|
/* 24 */ uint64 epc; // saved user program counter
|
||||||
/* 32 */ uint64 ra;
|
/* 32 */ uint64 unused;
|
||||||
/* 40 */ uint64 sp;
|
/* 40 */ uint64 ra;
|
||||||
/* 48 */ uint64 gp;
|
/* 48 */ uint64 sp;
|
||||||
/* 56 */ uint64 tp;
|
/* 56 */ uint64 gp;
|
||||||
/* 64 */ uint64 t0;
|
/* 64 */ uint64 tp;
|
||||||
/* 72 */ uint64 t1;
|
/* 72 */ uint64 t0;
|
||||||
/* 80 */ uint64 t2;
|
/* 80 */ uint64 t1;
|
||||||
/* 88 */ uint64 a0;
|
/* 88 */ uint64 t2;
|
||||||
/* 96 */ uint64 a1;
|
/* 96 */ uint64 s0;
|
||||||
/* 104 */ uint64 a2;
|
/* 104 */ uint64 s1;
|
||||||
/* 112 */ uint64 a3;
|
/* 112 */ uint64 a0;
|
||||||
/* 120 */ uint64 a4;
|
/* 120 */ uint64 a1;
|
||||||
/* 128 */ uint64 a5;
|
/* 128 */ uint64 a2;
|
||||||
/* 136 */ uint64 a6;
|
/* 136 */ uint64 a3;
|
||||||
/* 144 */ uint64 a7;
|
/* 144 */ uint64 a4;
|
||||||
/* 152 */ uint64 t3;
|
/* 152 */ uint64 a5;
|
||||||
/* 160 */ uint64 t4;
|
/* 160 */ uint64 a6;
|
||||||
/* 168 */ uint64 t5;
|
/* 168 */ uint64 a7;
|
||||||
/* 176 */ uint64 t6;
|
/* 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 };
|
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));
|
asm("csrw sscratch, %0" : : "r" (x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supervisor trap cause
|
// Supervisor Trap Cause
|
||||||
static inline uint64
|
static inline uint64
|
||||||
r_scause()
|
r_scause()
|
||||||
{
|
{
|
||||||
|
@ -138,6 +138,15 @@ r_scause()
|
||||||
return x;
|
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 PGSIZE 4096 // bytes per page
|
||||||
#define PGSHIFT 12 // bits of offset within a 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)
|
if(addr >= p->sz || addr+4 > p->sz)
|
||||||
return -1;
|
return -1;
|
||||||
*ip = *(uint64*)(addr);
|
if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
|
||||||
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,28 +32,22 @@ fetchaddr(uint64 addr, uint64 *ip)
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
if(addr >= p->sz || addr+sizeof(uint64) > p->sz)
|
if(addr >= p->sz || addr+sizeof(uint64) > p->sz)
|
||||||
return -1;
|
return -1;
|
||||||
*ip = *(uint64*)(addr);
|
if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
|
||||||
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the nul-terminated string at addr from the current process.
|
// Fetch the nul-terminated string at addr from the current process.
|
||||||
// Doesn't actually copy the string - just sets *pp to point at it.
|
// 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
|
int
|
||||||
fetchstr(uint64 addr, char **pp)
|
fetchstr(uint64 addr, char *buf, int max)
|
||||||
{
|
{
|
||||||
char *s, *ep;
|
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
int err = copyinstr(p->pagetable, buf, addr, max);
|
||||||
if(addr >= p->sz)
|
if(err < 0)
|
||||||
return -1;
|
return err;
|
||||||
*pp = (char*)addr;
|
return strlen(buf);
|
||||||
ep = (char*)p->sz;
|
|
||||||
for(s = *pp; s < ep; s++){
|
|
||||||
if(*s == 0)
|
|
||||||
return s - *pp;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64
|
static uint64
|
||||||
|
@ -96,7 +91,7 @@ argaddr(int n, uint64 *ip)
|
||||||
// to a block of memory of size bytes. Check that the pointer
|
// to a block of memory of size bytes. Check that the pointer
|
||||||
// lies within the process address space.
|
// lies within the process address space.
|
||||||
int
|
int
|
||||||
argptr(int n, char **pp, int size)
|
argptr(int n, uint64 *pp, int size)
|
||||||
{
|
{
|
||||||
uint64 i;
|
uint64 i;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
@ -105,21 +100,20 @@ argptr(int n, char **pp, int size)
|
||||||
return -1;
|
return -1;
|
||||||
if(size < 0 || (uint)i >= p->sz || (uint)i+size > p->sz)
|
if(size < 0 || (uint)i >= p->sz || (uint)i+size > p->sz)
|
||||||
return -1;
|
return -1;
|
||||||
*pp = (char*)i;
|
*pp = i;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the nth word-sized system call argument as a string pointer.
|
// Fetch the nth word-sized system call argument as a null-terminated string.
|
||||||
// Check that the pointer is valid and the string is nul-terminated.
|
// Copies into buf, at most max.
|
||||||
// (There is no shared writable memory, so the string can't change
|
// Returns string length if OK (including nul), -1 if error.
|
||||||
// between this check and being used by the kernel.)
|
|
||||||
int
|
int
|
||||||
argstr(int n, char **pp)
|
argstr(int n, char *buf, int max)
|
||||||
{
|
{
|
||||||
uint64 addr;
|
uint64 addr;
|
||||||
if(argaddr(n, &addr) < 0)
|
if(argaddr(n, &addr) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return fetchstr(addr, pp);
|
return fetchstr(addr, buf, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int sys_chdir(void);
|
extern int sys_chdir(void);
|
||||||
|
|
74
sysfile.c
74
sysfile.c
|
@ -71,7 +71,7 @@ sys_read(void)
|
||||||
{
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int n;
|
int n;
|
||||||
char *p;
|
uint64 p;
|
||||||
|
|
||||||
if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
|
if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -83,10 +83,11 @@ sys_write(void)
|
||||||
{
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int n;
|
int n;
|
||||||
char *p;
|
uint64 p;
|
||||||
|
|
||||||
if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
|
if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return filewrite(f, p, n);
|
return filewrite(f, p, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,9 +108,9 @@ int
|
||||||
sys_fstat(void)
|
sys_fstat(void)
|
||||||
{
|
{
|
||||||
struct file *f;
|
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 -1;
|
||||||
return filestat(f, st);
|
return filestat(f, st);
|
||||||
}
|
}
|
||||||
|
@ -118,10 +119,10 @@ sys_fstat(void)
|
||||||
int
|
int
|
||||||
sys_link(void)
|
sys_link(void)
|
||||||
{
|
{
|
||||||
char name[DIRSIZ], *new, *old;
|
char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
|
||||||
struct inode *dp, *ip;
|
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;
|
return -1;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
|
@ -186,10 +187,10 @@ sys_unlink(void)
|
||||||
{
|
{
|
||||||
struct inode *ip, *dp;
|
struct inode *ip, *dp;
|
||||||
struct dirent de;
|
struct dirent de;
|
||||||
char name[DIRSIZ], *path;
|
char name[DIRSIZ], path[MAXPATH];
|
||||||
uint off;
|
uint off;
|
||||||
|
|
||||||
if(argstr(0, &path) < 0)
|
if(argstr(0, path, MAXPATH) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
|
@ -286,12 +287,12 @@ create(char *path, short type, short major, short minor)
|
||||||
int
|
int
|
||||||
sys_open(void)
|
sys_open(void)
|
||||||
{
|
{
|
||||||
char *path;
|
char path[MAXPATH];
|
||||||
int fd, omode;
|
int fd, omode;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
|
|
||||||
if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
|
if(argstr(0, path, MAXPATH) < 0 || argint(1, &omode) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
|
@ -336,11 +337,11 @@ sys_open(void)
|
||||||
int
|
int
|
||||||
sys_mkdir(void)
|
sys_mkdir(void)
|
||||||
{
|
{
|
||||||
char *path;
|
char path[MAXPATH];
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
|
|
||||||
begin_op();
|
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();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -353,11 +354,11 @@ int
|
||||||
sys_mknod(void)
|
sys_mknod(void)
|
||||||
{
|
{
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
char *path;
|
char path[MAXPATH];
|
||||||
int major, minor;
|
int major, minor;
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
if((argstr(0, &path)) < 0 ||
|
if((argstr(0, path, MAXPATH)) < 0 ||
|
||||||
argint(1, &major) < 0 ||
|
argint(1, &major) < 0 ||
|
||||||
argint(2, &minor) < 0 ||
|
argint(2, &minor) < 0 ||
|
||||||
(ip = create(path, T_DEV, major, minor)) == 0){
|
(ip = create(path, T_DEV, major, minor)) == 0){
|
||||||
|
@ -372,12 +373,12 @@ sys_mknod(void)
|
||||||
int
|
int
|
||||||
sys_chdir(void)
|
sys_chdir(void)
|
||||||
{
|
{
|
||||||
char *path;
|
char path[MAXPATH];
|
||||||
struct inode *ip;
|
struct inode *ip;
|
||||||
struct proc *p = myproc();
|
struct proc *p = myproc();
|
||||||
|
|
||||||
begin_op();
|
begin_op();
|
||||||
if(argstr(0, &path) < 0 || (ip = namei(path)) == 0){
|
if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0){
|
||||||
end_op();
|
end_op();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -397,59 +398,68 @@ sys_chdir(void)
|
||||||
int
|
int
|
||||||
sys_exec(void)
|
sys_exec(void)
|
||||||
{
|
{
|
||||||
char *path, *argv[MAXARG];
|
char path[MAXPATH], *argv[MAXARG];
|
||||||
int i;
|
int i;
|
||||||
uint64 uargv, uarg;
|
uint64 uargv, uarg;
|
||||||
|
|
||||||
printf("sys_exec\n");
|
if(argstr(0, path, MAXPATH) < 0 || argaddr(1, &uargv) < 0){
|
||||||
|
|
||||||
if(argstr(0, &path) < 0 || argaddr(1, &uargv) < 0){
|
|
||||||
printf("error 1\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memset(argv, 0, sizeof(argv));
|
memset(argv, 0, sizeof(argv));
|
||||||
for(i=0;; i++){
|
for(i=0;; i++){
|
||||||
if(i >= NELEM(argv)){
|
if(i >= NELEM(argv)){
|
||||||
printf("error 2\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){
|
if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){
|
||||||
printf("error 3\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(uarg == 0){
|
if(uarg == 0){
|
||||||
argv[i] = 0;
|
argv[i] = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(fetchstr(uarg, &argv[i]) < 0){
|
argv[i] = kalloc();
|
||||||
printf("error 4\n");
|
if(argv[i] == 0)
|
||||||
|
panic("sys_exec kalloc");
|
||||||
|
if(fetchstr(uarg, argv[i], PGSIZE) < 0){
|
||||||
return -1;
|
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
|
int
|
||||||
sys_pipe(void)
|
sys_pipe(void)
|
||||||
{
|
{
|
||||||
int *fd;
|
uint64 fdarray; // user pointer to array of two integers
|
||||||
struct file *rf, *wf;
|
struct file *rf, *wf;
|
||||||
int fd0, fd1;
|
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;
|
return -1;
|
||||||
if(pipealloc(&rf, &wf) < 0)
|
if(pipealloc(&rf, &wf) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
fd0 = -1;
|
fd0 = -1;
|
||||||
if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
|
if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
|
||||||
if(fd0 >= 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(rf);
|
||||||
fileclose(wf);
|
fileclose(wf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fd[0] = fd0;
|
|
||||||
fd[1] = fd1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
116
trampoline.S
116
trampoline.S
|
@ -5,14 +5,15 @@
|
||||||
# in user and kernel space so that it can switch
|
# in user and kernel space so that it can switch
|
||||||
# page tables.
|
# page tables.
|
||||||
#
|
#
|
||||||
# kernel.ld causes trampstart to be aligned
|
# kernel.ld causes trampout to be aligned
|
||||||
# to a page boundary.
|
# to a page boundary.
|
||||||
#
|
#
|
||||||
.globl usertrap
|
.globl usertrap
|
||||||
.section trampoline
|
.section trampoline
|
||||||
.globl trampstart
|
.globl trampout
|
||||||
trampstart:
|
trampout:
|
||||||
# switch from kernel to user.
|
# switch from kernel to user.
|
||||||
|
# usertrapret() calls here.
|
||||||
# a0: p->tf in user page table
|
# a0: p->tf in user page table
|
||||||
# a1: new value for satp, for 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
|
# put the saved user a0 in sscratch, so we
|
||||||
# can swap it with our a0 (p->tf) in the last step.
|
# can swap it with our a0 (p->tf) in the last step.
|
||||||
ld t0, 80(a0)
|
ld t0, 112(a0)
|
||||||
csrw sscratch, t0
|
csrw sscratch, t0
|
||||||
|
|
||||||
# restore all but a0 from p->tf
|
# restore all but a0 from p->tf
|
||||||
ld ra, 32(a0)
|
ld ra, 40(a0)
|
||||||
ld sp, 40(a0)
|
ld sp, 48(a0)
|
||||||
ld gp, 48(a0)
|
ld gp, 56(a0)
|
||||||
ld tp, 56(a0)
|
ld tp, 64(a0)
|
||||||
ld t0, 64(a0)
|
ld t0, 72(a0)
|
||||||
ld t1, 72(a0)
|
ld t1, 80(a0)
|
||||||
ld t2, 80(a0)
|
ld t2, 88(a0)
|
||||||
ld a1, 96(a0)
|
ld s0, 96(a0)
|
||||||
ld a2, 104(a0)
|
ld s1, 104(a0)
|
||||||
ld a3, 112(a0)
|
ld a1, 120(a0)
|
||||||
ld a4, 120(a0)
|
ld a2, 128(a0)
|
||||||
ld a5, 128(a0)
|
ld a3, 136(a0)
|
||||||
ld a6, 136(a0)
|
ld a4, 144(a0)
|
||||||
ld a7, 144(a0)
|
ld a5, 152(a0)
|
||||||
ld t3, 152(a0)
|
ld a6, 160(a0)
|
||||||
ld t4, 160(a0)
|
ld a7, 168(a0)
|
||||||
ld t5, 168(a0)
|
ld s2, 176(a0)
|
||||||
ld t6, 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
|
# restore user a0, and save p->tf
|
||||||
csrrw a0, sscratch, a0
|
csrrw a0, sscratch, a0
|
||||||
|
@ -51,45 +64,58 @@ trampstart:
|
||||||
# caller has set up sstatus and sepc.
|
# caller has set up sstatus and sepc.
|
||||||
sret
|
sret
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.globl trampin
|
||||||
|
trampin:
|
||||||
#
|
#
|
||||||
# trap.c set stvec to point here, so
|
# 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
|
# in supervisor mode, but with a
|
||||||
# user page table.
|
# user page table.
|
||||||
#
|
#
|
||||||
# sscratch points to where the process's p->tf is
|
# sscratch points to where the process's p->tf is
|
||||||
# mapped into user space (TRAMPOLINE - 4096).
|
# mapped into user space (TRAMPOLINE - 4096).
|
||||||
#
|
#
|
||||||
.align 4
|
|
||||||
.globl trampvec
|
|
||||||
trampvec:
|
|
||||||
# swap a0 and sscratch
|
# swap a0 and sscratch
|
||||||
# so that a0 is p->tf
|
# so that a0 is p->tf
|
||||||
csrrw a0, sscratch, a0
|
csrrw a0, sscratch, a0
|
||||||
|
|
||||||
# save the user registers in p->tf
|
# save the user registers in p->tf
|
||||||
sd ra, 32(a0)
|
sd ra, 40(a0)
|
||||||
sd sp, 40(a0)
|
sd sp, 48(a0)
|
||||||
sd gp, 48(a0)
|
sd gp, 56(a0)
|
||||||
sd tp, 56(a0)
|
sd tp, 64(a0)
|
||||||
sd t0, 64(a0)
|
sd t0, 72(a0)
|
||||||
sd t1, 72(a0)
|
sd t1, 80(a0)
|
||||||
sd t2, 80(a0)
|
sd t2, 88(a0)
|
||||||
sd a1, 96(a0)
|
sd s0, 96(a0)
|
||||||
sd a2, 104(a0)
|
sd s1, 104(a0)
|
||||||
sd a3, 112(a0)
|
sd a1, 120(a0)
|
||||||
sd a4, 120(a0)
|
sd a2, 128(a0)
|
||||||
sd a5, 128(a0)
|
sd a3, 136(a0)
|
||||||
sd a6, 136(a0)
|
sd a4, 144(a0)
|
||||||
sd a7, 144(a0)
|
sd a5, 152(a0)
|
||||||
sd t3, 152(a0)
|
sd a6, 160(a0)
|
||||||
sd t4, 160(a0)
|
sd a7, 168(a0)
|
||||||
sd t5, 168(a0)
|
sd s2, 176(a0)
|
||||||
sd t6, 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
|
# save the user a0 in p->tf->a0
|
||||||
csrr t0, sscratch
|
csrr t0, sscratch
|
||||||
sd t0, 80(a0)
|
sd t0, 112(a0)
|
||||||
|
|
||||||
# restore kernel stack pointer from p->tf->kernel_sp
|
# restore kernel stack pointer from p->tf->kernel_sp
|
||||||
ld sp, 8(a0)
|
ld sp, 8(a0)
|
||||||
|
|
8
trap.c
8
trap.c
|
@ -9,7 +9,7 @@
|
||||||
struct spinlock tickslock;
|
struct spinlock tickslock;
|
||||||
uint ticks;
|
uint ticks;
|
||||||
|
|
||||||
extern char trampstart[], trampvec[];
|
extern char trampout[], trampin[];
|
||||||
|
|
||||||
void kerneltrap();
|
void kerneltrap();
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ usertrap(void)
|
||||||
syscall();
|
syscall();
|
||||||
} else {
|
} else {
|
||||||
printf("usertrap(): unexpected scause 0x%x pid=%d\n", r_scause(), p->pid);
|
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");
|
panic("usertrap");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ usertrapret(void)
|
||||||
// now from kerneltrap() to usertrap().
|
// now from kerneltrap() to usertrap().
|
||||||
|
|
||||||
// send interrupts and exceptions to trampoline.S
|
// 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
|
// set up values that trampoline.S will need when
|
||||||
// the process next re-enters the kernel.
|
// the process next re-enters the kernel.
|
||||||
|
@ -108,5 +109,8 @@ kerneltrap()
|
||||||
if((r_sstatus() & SSTATUS_SPP) == 0)
|
if((r_sstatus() & SSTATUS_SPP) == 0)
|
||||||
panic("kerneltrap: not from supervisor mode");
|
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");
|
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 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
|
* create a direct-map page table for the kernel and
|
||||||
|
@ -45,7 +45,7 @@ kvminit()
|
||||||
// map the trampoline for trap entry/exit to
|
// map the trampoline for trap entry/exit to
|
||||||
// the highest virtual address in the kernel.
|
// the highest virtual address in the kernel.
|
||||||
mappages(kernel_pagetable, TRAMPOLINE, PGSIZE,
|
mappages(kernel_pagetable, TRAMPOLINE, PGSIZE,
|
||||||
(uint64)trampstart, PTE_R | PTE_X);
|
(uint64)trampout, PTE_R | PTE_X);
|
||||||
|
|
||||||
kvmswitch();
|
kvmswitch();
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memset(mem, 0, PGSIZE);
|
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;
|
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.
|
// 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.
|
// Return 0 on success, -1 on error.
|
||||||
int
|
int
|
||||||
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
|
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;
|
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