Merge branch 'riscv' into uvm-perm

This commit is contained in:
Frans Kaashoek 2022-08-23 11:01:06 -04:00
commit ccb7bd14c7
14 changed files with 156 additions and 95 deletions

View file

@ -89,7 +89,7 @@ consoleread(int user_dst, uint64 dst, int n)
// wait until interrupt handler has put some // wait until interrupt handler has put some
// input into cons.buffer. // input into cons.buffer.
while(cons.r == cons.w){ while(cons.r == cons.w){
if(myproc()->killed){ if(killed(myproc())){
release(&cons.lock); release(&cons.lock);
return -1; return -1;
} }

View file

@ -90,6 +90,8 @@ void proc_mapstacks(pagetable_t);
pagetable_t proc_pagetable(struct proc *); pagetable_t proc_pagetable(struct proc *);
void proc_freepagetable(pagetable_t, uint64); void proc_freepagetable(pagetable_t, uint64);
int kill(int); int kill(int);
int killed(struct proc*);
void setkilled(struct proc*);
struct cpu* mycpu(void); struct cpu* mycpu(void);
struct cpu* getmycpu(void); struct cpu* getmycpu(void);
struct proc* myproc(); struct proc* myproc();
@ -132,9 +134,9 @@ int strncmp(const char*, const char*, uint);
char* strncpy(char*, const char*, int); char* strncpy(char*, const char*, int);
// syscall.c // syscall.c
int argint(int, int*); void argint(int, int*);
int argstr(int, char*, int); int argstr(int, char*, int);
int argaddr(int, uint64 *); void argaddr(int, uint64 *);
int fetchstr(uint64, char*, int); int fetchstr(uint64, char*, int);
int fetchaddr(uint64, uint64*); int fetchaddr(uint64, uint64*);
void syscall(); void syscall();

View file

@ -573,6 +573,7 @@ dirlookup(struct inode *dp, char *name, uint *poff)
} }
// Write a new directory entry (name, inum) into the directory dp. // Write a new directory entry (name, inum) into the directory dp.
// Returns 0 on success, -1 on failure (e.g. out of disk blocks).
int int
dirlink(struct inode *dp, char *name, uint inum) dirlink(struct inode *dp, char *name, uint inum)
{ {
@ -597,7 +598,7 @@ dirlink(struct inode *dp, char *name, uint inum)
strncpy(de.name, name, DIRSIZ); strncpy(de.name, name, DIRSIZ);
de.inum = inum; de.inum = inum;
if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
panic("dirlink"); return -1;
return 0; return 0;
} }

View file

@ -81,7 +81,7 @@ pipewrite(struct pipe *pi, uint64 addr, int n)
acquire(&pi->lock); acquire(&pi->lock);
while(i < n){ while(i < n){
if(pi->readopen == 0 || pr->killed){ if(pi->readopen == 0 || killed(pr)){
release(&pi->lock); release(&pi->lock);
return -1; return -1;
} }
@ -111,7 +111,7 @@ piperead(struct pipe *pi, uint64 addr, int n)
acquire(&pi->lock); acquire(&pi->lock);
while(pi->nread == pi->nwrite && pi->writeopen){ //DOC: pipe-empty while(pi->nread == pi->nwrite && pi->writeopen){ //DOC: pipe-empty
if(pr->killed){ if(killed(pr)){
release(&pi->lock); release(&pi->lock);
return -1; return -1;
} }

View file

@ -259,7 +259,7 @@ userinit(void)
int int
growproc(int n) growproc(int n)
{ {
uint sz; uint64 sz;
struct proc *p = myproc(); struct proc *p = myproc();
sz = p->sz; sz = p->sz;
@ -390,7 +390,7 @@ exit(int status)
int int
wait(uint64 addr) wait(uint64 addr)
{ {
struct proc *np; struct proc *pp;
int havekids, pid; int havekids, pid;
struct proc *p = myproc(); struct proc *p = myproc();
@ -399,32 +399,32 @@ wait(uint64 addr)
for(;;){ for(;;){
// Scan through table looking for exited children. // Scan through table looking for exited children.
havekids = 0; havekids = 0;
for(np = proc; np < &proc[NPROC]; np++){ for(pp = proc; pp < &proc[NPROC]; pp++){
if(np->parent == p){ if(pp->parent == p){
// make sure the child isn't still in exit() or swtch(). // make sure the child isn't still in exit() or swtch().
acquire(&np->lock); acquire(&pp->lock);
havekids = 1; havekids = 1;
if(np->state == ZOMBIE){ if(pp->state == ZOMBIE){
// Found one. // Found one.
pid = np->pid; pid = pp->pid;
if(addr != 0 && copyout(p->pagetable, addr, (char *)&np->xstate, if(addr != 0 && copyout(p->pagetable, addr, (char *)&pp->xstate,
sizeof(np->xstate)) < 0) { sizeof(pp->xstate)) < 0) {
release(&np->lock); release(&pp->lock);
release(&wait_lock); release(&wait_lock);
return -1; return -1;
} }
freeproc(np); freeproc(pp);
release(&np->lock); release(&pp->lock);
release(&wait_lock); release(&wait_lock);
return pid; return pid;
} }
release(&np->lock); release(&pp->lock);
} }
} }
// No point waiting if we don't have any children. // No point waiting if we don't have any children.
if(!havekids || p->killed){ if(!havekids || killed(p)){
release(&wait_lock); release(&wait_lock);
return -1; return -1;
} }
@ -603,6 +603,25 @@ kill(int pid)
return -1; return -1;
} }
void
setkilled(struct proc *p)
{
acquire(&p->lock);
p->killed = 1;
release(&p->lock);
}
int
killed(struct proc *p)
{
int k;
acquire(&p->lock);
k = p->killed;
release(&p->lock);
return k;
}
// Copy to either a user address, or kernel address, // Copy to either a user address, or kernel address,
// depending on usr_dst. // depending on usr_dst.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.

View file

@ -12,7 +12,7 @@ int
fetchaddr(uint64 addr, uint64 *ip) 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) // both tests needed, in case of overflow
return -1; return -1;
if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0) if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0)
return -1; return -1;
@ -25,9 +25,8 @@ int
fetchstr(uint64 addr, char *buf, int max) fetchstr(uint64 addr, char *buf, int max)
{ {
struct proc *p = myproc(); struct proc *p = myproc();
int err = copyinstr(p->pagetable, buf, addr, max); if(copyinstr(p->pagetable, buf, addr, max) < 0)
if(err < 0) return -1;
return err;
return strlen(buf); return strlen(buf);
} }
@ -54,21 +53,19 @@ argraw(int n)
} }
// Fetch the nth 32-bit system call argument. // Fetch the nth 32-bit system call argument.
int void
argint(int n, int *ip) argint(int n, int *ip)
{ {
*ip = argraw(n); *ip = argraw(n);
return 0;
} }
// Retrieve an argument as a pointer. // Retrieve an argument as a pointer.
// Doesn't check for legality, since // Doesn't check for legality, since
// copyin/copyout will do that. // copyin/copyout will do that.
int void
argaddr(int n, uint64 *ip) argaddr(int n, uint64 *ip)
{ {
*ip = argraw(n); *ip = argraw(n);
return 0;
} }
// Fetch the nth word-sized system call argument as a null-terminated string. // Fetch the nth word-sized system call argument as a null-terminated string.
@ -78,8 +75,7 @@ int
argstr(int n, char *buf, int max) argstr(int n, char *buf, int max)
{ {
uint64 addr; uint64 addr;
if(argaddr(n, &addr) < 0) argaddr(n, &addr);
return -1;
return fetchstr(addr, buf, max); return fetchstr(addr, buf, max);
} }

View file

@ -24,8 +24,7 @@ argfd(int n, int *pfd, struct file **pf)
int fd; int fd;
struct file *f; struct file *f;
if(argint(n, &fd) < 0) argint(n, &fd);
return -1;
if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0) if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)
return -1; return -1;
if(pfd) if(pfd)
@ -73,7 +72,9 @@ sys_read(void)
int n; int n;
uint64 p; uint64 p;
if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argaddr(1, &p) < 0) argaddr(1, &p);
argint(2, &n);
if(argfd(0, 0, &f) < 0)
return -1; return -1;
return fileread(f, p, n); return fileread(f, p, n);
} }
@ -84,8 +85,10 @@ sys_write(void)
struct file *f; struct file *f;
int n; int n;
uint64 p; uint64 p;
if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argaddr(1, &p) < 0) argaddr(1, &p);
argint(2, &n);
if(argfd(0, 0, &f) < 0)
return -1; return -1;
return filewrite(f, p, n); return filewrite(f, p, n);
@ -110,7 +113,8 @@ sys_fstat(void)
struct file *f; struct file *f;
uint64 st; // user pointer to struct stat uint64 st; // user pointer to struct stat
if(argfd(0, 0, &f) < 0 || argaddr(1, &st) < 0) argaddr(1, &st);
if(argfd(0, 0, &f) < 0)
return -1; return -1;
return filestat(f, st); return filestat(f, st);
} }
@ -268,19 +272,31 @@ create(char *path, short type, short major, short minor)
iupdate(ip); iupdate(ip);
if(type == T_DIR){ // Create . and .. entries. if(type == T_DIR){ // Create . and .. entries.
dp->nlink++; // for ".."
iupdate(dp);
// No ip->nlink++ for ".": avoid cyclic ref count. // No ip->nlink++ for ".": avoid cyclic ref count.
if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
panic("create dots"); goto fail;
} }
if(dirlink(dp, name, ip->inum) < 0) if(dirlink(dp, name, ip->inum) < 0)
panic("create: dirlink"); goto fail;
if(type == T_DIR){
// now that success is guaranteed:
dp->nlink++; // for ".."
iupdate(dp);
}
iunlockput(dp); iunlockput(dp);
return ip; return ip;
fail:
// something went wrong. de-allocate ip.
ip->nlink = 0;
iupdate(ip);
iunlockput(ip);
iunlockput(dp);
return 0;
} }
uint64 uint64
@ -292,7 +308,8 @@ sys_open(void)
struct inode *ip; struct inode *ip;
int n; int n;
if((n = argstr(0, path, MAXPATH)) < 0 || argint(1, &omode) < 0) argint(1, &omode);
if((n = argstr(0, path, MAXPATH)) < 0)
return -1; return -1;
begin_op(); begin_op();
@ -375,9 +392,9 @@ sys_mknod(void)
int major, minor; int major, minor;
begin_op(); begin_op();
argint(1, &major);
argint(2, &minor);
if((argstr(0, path, MAXPATH)) < 0 || if((argstr(0, path, MAXPATH)) < 0 ||
argint(1, &major) < 0 ||
argint(2, &minor) < 0 ||
(ip = create(path, T_DEVICE, major, minor)) == 0){ (ip = create(path, T_DEVICE, major, minor)) == 0){
end_op(); end_op();
return -1; return -1;
@ -419,7 +436,8 @@ sys_exec(void)
int i; int i;
uint64 uargv, uarg; uint64 uargv, uarg;
if(argstr(0, path, MAXPATH) < 0 || argaddr(1, &uargv) < 0){ argaddr(1, &uargv);
if(argstr(0, path, MAXPATH) < 0) {
return -1; return -1;
} }
memset(argv, 0, sizeof(argv)); memset(argv, 0, sizeof(argv));
@ -462,8 +480,7 @@ sys_pipe(void)
int fd0, fd1; int fd0, fd1;
struct proc *p = myproc(); struct proc *p = myproc();
if(argaddr(0, &fdarray) < 0) argaddr(0, &fdarray);
return -1;
if(pipealloc(&rf, &wf) < 0) if(pipealloc(&rf, &wf) < 0)
return -1; return -1;
fd0 = -1; fd0 = -1;

View file

@ -10,8 +10,7 @@ uint64
sys_exit(void) sys_exit(void)
{ {
int n; int n;
if(argint(0, &n) < 0) argint(0, &n);
return -1;
exit(n); exit(n);
return 0; // not reached return 0; // not reached
} }
@ -32,19 +31,17 @@ uint64
sys_wait(void) sys_wait(void)
{ {
uint64 p; uint64 p;
if(argaddr(0, &p) < 0) argaddr(0, &p);
return -1;
return wait(p); return wait(p);
} }
uint64 uint64
sys_sbrk(void) sys_sbrk(void)
{ {
int addr; uint64 addr;
int n; int n;
if(argint(0, &n) < 0) argint(0, &n);
return -1;
addr = myproc()->sz; addr = myproc()->sz;
if(growproc(n) < 0) if(growproc(n) < 0)
return -1; return -1;
@ -57,12 +54,11 @@ sys_sleep(void)
int n; int n;
uint ticks0; uint ticks0;
if(argint(0, &n) < 0) argint(0, &n);
return -1;
acquire(&tickslock); acquire(&tickslock);
ticks0 = ticks; ticks0 = ticks;
while(ticks - ticks0 < n){ while(ticks - ticks0 < n){
if(myproc()->killed){ if(killed(myproc())){
release(&tickslock); release(&tickslock);
return -1; return -1;
} }
@ -77,8 +73,7 @@ sys_kill(void)
{ {
int pid; int pid;
if(argint(0, &pid) < 0) argint(0, &pid);
return -1;
return kill(pid); return kill(pid);
} }

View file

@ -1,18 +1,19 @@
#
# code to switch between user and kernel space.
# #
# this code is mapped at the same virtual address # low-level code to handle traps from user space into
# (TRAMPOLINE) in user and kernel space so that # the kernel, and returns from kernel to user.
# it continues to work when it switches page tables. #
# # the kernel maps the page holding this code
# kernel.ld causes this to be aligned # at the same virtual address (TRAMPOLINE)
# to a page boundary. # in user and kernel space so that it continues
# to work when it switches page tables.
# kernel.ld causes this code to start at
# a page boundary.
# #
#include "riscv.h" #include "riscv.h"
#include "memlayout.h" #include "memlayout.h"
.section trampsec .section trampsec
.globl trampoline .globl trampoline
trampoline: trampoline:
.align 4 .align 4
@ -31,7 +32,7 @@ uservec:
# each process has a separate p->trapframe memory area, # each process has a separate p->trapframe memory area,
# but it's mapped to the same virtual address # but it's mapped to the same virtual address
# (TRAPFRAME) in every process. # (TRAPFRAME) in every process's user page table.
li a0, TRAPFRAME li a0, TRAPFRAME
# save the user registers in TRAPFRAME # save the user registers in TRAPFRAME
@ -70,29 +71,27 @@ uservec:
csrr t0, sscratch csrr t0, sscratch
sd t0, 112(a0) sd t0, 112(a0)
# restore kernel stack pointer from p->trapframe->kernel_sp # initialize kernel stack pointer, from p->trapframe->kernel_sp
ld sp, 8(a0) ld sp, 8(a0)
# make tp hold the current hartid, from p->trapframe->kernel_hartid # make tp hold the current hartid, from p->trapframe->kernel_hartid
ld tp, 32(a0) ld tp, 32(a0)
# load the address of usertrap(), p->trapframe->kernel_trap # load the address of usertrap(), from p->trapframe->kernel_trap
ld t0, 16(a0) ld t0, 16(a0)
# restore kernel page table from p->trapframe->kernel_satp # load the kernel page table, from p->trapframe->kernel_satp
ld t1, 0(a0) ld t1, 0(a0)
csrw satp, t1 csrw satp, t1
sfence.vma zero, zero sfence.vma zero, zero
# a0 is no longer valid, since the kernel page
# table does not specially map p->tf.
# jump to usertrap(), which does not return # jump to usertrap(), which does not return
jr t0 jr t0
.globl userret .globl userret
userret: userret:
# userret(pagetable) # userret(pagetable)
# called by usertrapret() in trap.c to
# switch from kernel to user. # switch from kernel to user.
# a0: user page table, for satp. # a0: user page table, for satp.

View file

@ -53,15 +53,15 @@ usertrap(void)
if(r_scause() == 8){ if(r_scause() == 8){
// system call // system call
if(p->killed) if(killed(p))
exit(-1); exit(-1);
// sepc points to the ecall instruction, // sepc points to the ecall instruction,
// but we want to return to the next instruction. // but we want to return to the next instruction.
p->trapframe->epc += 4; p->trapframe->epc += 4;
// an interrupt will change sstatus &c registers, // an interrupt will change sepc, scause, and sstatus,
// so don't enable until done with those registers. // so enable only now that we're done with those registers.
intr_on(); intr_on();
syscall(); syscall();
@ -70,10 +70,10 @@ usertrap(void)
} else { } else {
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid); printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval()); printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
p->killed = 1; setkilled(p);
} }
if(p->killed) if(killed(p))
exit(-1); exit(-1);
// give up the CPU if this is a timer interrupt. // give up the CPU if this is a timer interrupt.
@ -101,7 +101,7 @@ usertrapret(void)
w_stvec(trampoline_uservec); w_stvec(trampoline_uservec);
// set up trapframe values that uservec will need when // set up trapframe values that uservec will need when
// the process next re-enters the kernel. // the process next traps into the kernel.
p->trapframe->kernel_satp = r_satp(); // kernel page table p->trapframe->kernel_satp = r_satp(); // kernel page table
p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack
p->trapframe->kernel_trap = (uint64)usertrap; p->trapframe->kernel_trap = (uint64)usertrap;

View file

@ -92,22 +92,18 @@ uartputc(int c)
for(;;) for(;;)
; ;
} }
while(uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE){
while(1){ // buffer is full.
if(uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE){ // wait for uartstart() to open up space in the buffer.
// buffer is full. sleep(&uart_tx_r, &uart_tx_lock);
// wait for uartstart() to open up space in the buffer.
sleep(&uart_tx_r, &uart_tx_lock);
} else {
uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE] = c;
uart_tx_w += 1;
uartstart();
release(&uart_tx_lock);
return;
}
} }
uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE] = c;
uart_tx_w += 1;
uartstart();
release(&uart_tx_lock);
} }
// alternate version of uartputc() that doesn't // alternate version of uartputc() that doesn't
// use interrupts, for use by kernel printf() and // use interrupts, for use by kernel printf() and
// to echo characters. it spins waiting for the uart's // to echo characters. it spins waiting for the uart's

View file

@ -62,7 +62,8 @@ main(int argc, char *argv[])
} }
// Regexp matcher from Kernighan & Pike, // Regexp matcher from Kernighan & Pike,
// The Practice of Programming, Chapter 9. // The Practice of Programming, Chapter 9, or
// https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
int matchhere(char*, char*); int matchhere(char*, char*);
int matchstar(int, char*, char*); int matchstar(int, char*, char*);

View file

@ -9,7 +9,7 @@ int write(int, const void*, int);
int read(int, void*, int); int read(int, void*, int);
int close(int); int close(int);
int kill(int); int kill(int);
int exec(char*, char**); int exec(const char*, char**);
int open(const char*, int); int open(const char*, int);
int mknod(const char*, short, short); int mknod(const char*, short, short);
int unlink(const char*); int unlink(const char*);

View file

@ -2737,6 +2737,8 @@ diskfull(char *s)
{ {
int fi; int fi;
int done = 0; int done = 0;
unlink("diskfulldir");
for(fi = 0; done == 0; fi++){ for(fi = 0; done == 0; fi++){
char name[32]; char name[32];
@ -2763,6 +2765,39 @@ diskfull(char *s)
close(fd); close(fd);
} }
// now that there are no free blocks, test that dirlink()
// merely fails (doesn't panic) if it can't extend
// directory content.
int nzz = 128;
for(int i = 0; i < nzz; i++){
char name[32];
name[0] = 'z';
name[1] = 'z';
name[2] = '0' + (i / 32);
name[3] = '0' + (i % 32);
name[4] = '\0';
unlink(name);
int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
if(fd < 0){
printf("%s: could not create file %s\n", s, name);
break;
}
close(fd);
}
mkdir("diskfulldir");
unlink("diskfulldir");
for(int i = 0; i < nzz; i++){
char name[32];
name[0] = 'z';
name[1] = 'z';
name[2] = '0' + (i / 32);
name[3] = '0' + (i % 32);
name[4] = '\0';
unlink(name);
}
for(int i = 0; i < fi; i++){ for(int i = 0; i < fi; i++){
char name[32]; char name[32];
name[0] = 'b'; name[0] = 'b';