Merge branch 'riscv' of g.csail.mit.edu:xv6-dev into riscv
This commit is contained in:
		
						commit
						b924e44f06
					
				
					 13 changed files with 190 additions and 124 deletions
				
			
		
							
								
								
									
										12
									
								
								README
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								README
									
										
									
									
									
								
							| 
						 | 
					@ -31,7 +31,7 @@ Toomey, Stephen Tu, Pablo Ventura, Xi Wang, Keiichi Watanabe, Nicolas
 | 
				
			||||||
Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng, and Zou Chang Wei.
 | 
					Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng, and Zou Chang Wei.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The code in the files that constitute xv6 is
 | 
					The code in the files that constitute xv6 is
 | 
				
			||||||
Copyright 2006-2018 Frans Kaashoek, Robert Morris, and Russ Cox.
 | 
					Copyright 2006-2019 Frans Kaashoek, Robert Morris, and Russ Cox.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ERROR REPORTS
 | 
					ERROR REPORTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,9 +42,7 @@ simplifications and clarifications than new features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BUILDING AND RUNNING XV6
 | 
					BUILDING AND RUNNING XV6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To build xv6 on an x86 ELF machine (like Linux or FreeBSD), run
 | 
					You will need a RISC-V "newlib" tool chain from
 | 
				
			||||||
"make". On non-x86 or non-ELF machines (like OS X, even on x86), you
 | 
					https://github.com/riscv/riscv-gnu-toolchain, and qemu compiled for
 | 
				
			||||||
will need to install a cross-compiler gcc suite capable of producing
 | 
					riscv64-softmmu. Once they are installed, and in your shell
 | 
				
			||||||
x86 ELF binaries (see https://pdos.csail.mit.edu/6.828/).
 | 
					search path, you can run "make qemu".
 | 
				
			||||||
Then run "make TOOLPREFIX=i386-jos-elf-". Now install the QEMU PC
 | 
					 | 
				
			||||||
simulator and run "make qemu".
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,8 +55,9 @@ kfree(void *pa)
 | 
				
			||||||
  // Fill with junk to catch dangling refs.
 | 
					  // Fill with junk to catch dangling refs.
 | 
				
			||||||
  memset(pa, 1, PGSIZE);
 | 
					  memset(pa, 1, PGSIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  acquire(&kmem.lock);
 | 
					 | 
				
			||||||
  r = (struct run*)pa;
 | 
					  r = (struct run*)pa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  acquire(&kmem.lock);
 | 
				
			||||||
  r->next = kmem.freelist;
 | 
					  r->next = kmem.freelist;
 | 
				
			||||||
  kmem.freelist = r;
 | 
					  kmem.freelist = r;
 | 
				
			||||||
  release(&kmem.lock);
 | 
					  release(&kmem.lock);
 | 
				
			||||||
| 
						 | 
					@ -75,6 +76,7 @@ kalloc(void)
 | 
				
			||||||
  if(r)
 | 
					  if(r)
 | 
				
			||||||
    kmem.freelist = r->next;
 | 
					    kmem.freelist = r->next;
 | 
				
			||||||
  release(&kmem.lock);
 | 
					  release(&kmem.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if(r)
 | 
					  if(r)
 | 
				
			||||||
    memset((char*)r, 5, PGSIZE); // fill with junk
 | 
					    memset((char*)r, 5, PGSIZE); // fill with junk
 | 
				
			||||||
  return (void*)r;
 | 
					  return (void*)r;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										103
									
								
								kernel/proc.c
									
										
									
									
									
								
							
							
						
						
									
										103
									
								
								kernel/proc.c
									
										
									
									
									
								
							| 
						 | 
					@ -6,20 +6,16 @@
 | 
				
			||||||
#include "proc.h"
 | 
					#include "proc.h"
 | 
				
			||||||
#include "defs.h"
 | 
					#include "defs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct proc proc[NPROC];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct cpu cpus[NCPU];
 | 
					struct cpu cpus[NCPU];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct proc proc[NPROC];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct proc *initproc;
 | 
					struct proc *initproc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct spinlock pid_lock;
 | 
					 | 
				
			||||||
int nextpid = 1;
 | 
					int nextpid = 1;
 | 
				
			||||||
 | 
					struct spinlock pid_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void forkret(void);
 | 
					extern void forkret(void);
 | 
				
			||||||
 | 
					 | 
				
			||||||
// for returning  out of the kernel
 | 
					 | 
				
			||||||
extern void sysexit(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wakeup1(struct proc *chan);
 | 
					static void wakeup1(struct proc *chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern char trampout[]; // trampoline.S
 | 
					extern char trampout[]; // trampoline.S
 | 
				
			||||||
| 
						 | 
					@ -68,8 +64,10 @@ allocpid() {
 | 
				
			||||||
  int pid;
 | 
					  int pid;
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  acquire(&pid_lock);
 | 
					  acquire(&pid_lock);
 | 
				
			||||||
  pid = nextpid++;
 | 
					  pid = nextpid;
 | 
				
			||||||
 | 
					  nextpid = nextpid + 1;
 | 
				
			||||||
  release(&pid_lock);
 | 
					  release(&pid_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return pid;
 | 
					  return pid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,7 +75,7 @@ allocpid() {
 | 
				
			||||||
// Look in the process table for an UNUSED proc.
 | 
					// Look in the process table for an UNUSED proc.
 | 
				
			||||||
// If found, initialize state required to run in the kernel,
 | 
					// If found, initialize state required to run in the kernel,
 | 
				
			||||||
// and return with p->lock held.
 | 
					// and return with p->lock held.
 | 
				
			||||||
// Otherwise return 0.
 | 
					// If there are no free procs, return 0.
 | 
				
			||||||
static struct proc*
 | 
					static struct proc*
 | 
				
			||||||
allocproc(void)
 | 
					allocproc(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -98,6 +96,7 @@ found:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Allocate a page for the kernel stack.
 | 
					  // Allocate a page for the kernel stack.
 | 
				
			||||||
  if((p->kstack = kalloc()) == 0){
 | 
					  if((p->kstack = kalloc()) == 0){
 | 
				
			||||||
 | 
					    release(&p->lock);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,6 +104,7 @@ found:
 | 
				
			||||||
  if((p->tf = (struct trapframe *)kalloc()) == 0){
 | 
					  if((p->tf = (struct trapframe *)kalloc()) == 0){
 | 
				
			||||||
    kfree(p->kstack);
 | 
					    kfree(p->kstack);
 | 
				
			||||||
    p->kstack = 0;
 | 
					    p->kstack = 0;
 | 
				
			||||||
 | 
					    release(&p->lock);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -145,16 +145,13 @@ freeproc(struct proc *p)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create a page table for a given process,
 | 
					// Create a page table for a given process,
 | 
				
			||||||
// with no users pages, but with trampoline pages.
 | 
					// with no user pages, but with trampoline pages.
 | 
				
			||||||
// Called both when creating a process, and
 | 
					 | 
				
			||||||
// by exec() when building tentative new memory image,
 | 
					 | 
				
			||||||
// which might fail.
 | 
					 | 
				
			||||||
pagetable_t
 | 
					pagetable_t
 | 
				
			||||||
proc_pagetable(struct proc *p)
 | 
					proc_pagetable(struct proc *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  pagetable_t pagetable;
 | 
					  pagetable_t pagetable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // An empty user page table.
 | 
					  // An empty page table.
 | 
				
			||||||
  pagetable = uvmcreate();
 | 
					  pagetable = uvmcreate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // map the trampoline code (for system call return)
 | 
					  // map the trampoline code (for system call return)
 | 
				
			||||||
| 
						 | 
					@ -172,9 +169,7 @@ proc_pagetable(struct proc *p)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Free a process's page table, and free the
 | 
					// Free a process's page table, and free the
 | 
				
			||||||
// physical memory the page table refers to.
 | 
					// physical memory it refers to.
 | 
				
			||||||
// Called both when a process exits and from
 | 
					 | 
				
			||||||
// exec() if it fails.
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
proc_freepagetable(pagetable_t pagetable, uint64 sz)
 | 
					proc_freepagetable(pagetable_t pagetable, uint64 sz)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -187,9 +182,12 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz)
 | 
				
			||||||
// a user program that calls exec("/init")
 | 
					// a user program that calls exec("/init")
 | 
				
			||||||
// od -t xC initcode
 | 
					// od -t xC initcode
 | 
				
			||||||
uchar initcode[] = {
 | 
					uchar initcode[] = {
 | 
				
			||||||
  0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x02, 0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x05, 0x02,
 | 
					  0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x02,
 | 
				
			||||||
  0x9d, 0x48, 0x73, 0x00, 0x00, 0x00, 0x89, 0x48, 0x73, 0x00, 0x00, 0x00, 0xef, 0xf0, 0xbf, 0xff,
 | 
					  0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x05, 0x02,
 | 
				
			||||||
  0x2f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
					  0x9d, 0x48, 0x73, 0x00, 0x00, 0x00, 0x89, 0x48,
 | 
				
			||||||
 | 
					  0x73, 0x00, 0x00, 0x00, 0xef, 0xf0, 0xbf, 0xff,
 | 
				
			||||||
 | 
					  0x2f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x00, 0x01,
 | 
				
			||||||
 | 
					  0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
				
			||||||
  0x00, 0x00, 0x00
 | 
					  0x00, 0x00, 0x00
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,12 +201,14 @@ userinit(void)
 | 
				
			||||||
  p = allocproc();
 | 
					  p = allocproc();
 | 
				
			||||||
  initproc = p;
 | 
					  initproc = p;
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					  // allocate one user page and copy init's instructions
 | 
				
			||||||
 | 
					  // and data into it.
 | 
				
			||||||
  uvminit(p->pagetable, initcode, sizeof(initcode));
 | 
					  uvminit(p->pagetable, initcode, sizeof(initcode));
 | 
				
			||||||
  p->sz = PGSIZE;
 | 
					  p->sz = PGSIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // prepare for the very first "return" from kernel to user.
 | 
					  // prepare for the very first "return" from kernel to user.
 | 
				
			||||||
  p->tf->epc = 0;
 | 
					  p->tf->epc = 0;      // user program counter
 | 
				
			||||||
  p->tf->sp = PGSIZE;
 | 
					  p->tf->sp = PGSIZE;  // user stack pointer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  safestrcpy(p->name, "initcode", sizeof(p->name));
 | 
					  safestrcpy(p->name, "initcode", sizeof(p->name));
 | 
				
			||||||
  p->cwd = namei("/");
 | 
					  p->cwd = namei("/");
 | 
				
			||||||
| 
						 | 
					@ -218,7 +218,7 @@ userinit(void)
 | 
				
			||||||
  release(&p->lock);
 | 
					  release(&p->lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Grow current process's memory by n bytes.
 | 
					// Grow or shrink user memory by n bytes.
 | 
				
			||||||
// Return 0 on success, -1 on failure.
 | 
					// Return 0 on success, -1 on failure.
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
growproc(int n)
 | 
					growproc(int n)
 | 
				
			||||||
| 
						 | 
					@ -240,8 +240,8 @@ growproc(int n)
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create a new process, copying p as the parent.
 | 
					// Create a new process, copying the parent.
 | 
				
			||||||
// Sets up child kernel stack to return as if from system call.
 | 
					// Sets up child kernel stack to return as if from fork() system call.
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
fork(void)
 | 
					fork(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -287,8 +287,8 @@ fork(void)
 | 
				
			||||||
  return pid;
 | 
					  return pid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Pass p's abandoned children to init. p and p's parent
 | 
					// Pass p's abandoned children to init.
 | 
				
			||||||
// are locked.
 | 
					// Caller must hold p->lock and parent->lock.
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
reparent(struct proc *p, struct proc *parent) {
 | 
					reparent(struct proc *p, struct proc *parent) {
 | 
				
			||||||
  struct proc *pp;
 | 
					  struct proc *pp;
 | 
				
			||||||
| 
						 | 
					@ -312,7 +312,6 @@ reparent(struct proc *p, struct proc *parent) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
// Exit the current process.  Does not return.
 | 
					// Exit the current process.  Does not return.
 | 
				
			||||||
// An exited process remains in the zombie state
 | 
					// An exited process remains in the zombie state
 | 
				
			||||||
// until its parent calls wait().
 | 
					// until its parent calls wait().
 | 
				
			||||||
| 
						 | 
					@ -343,6 +342,7 @@ exit(void)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
  acquire(&p->lock);
 | 
					  acquire(&p->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Give our children to init.
 | 
				
			||||||
  reparent(p, p->parent);
 | 
					  reparent(p, p->parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  p->state = ZOMBIE;
 | 
					  p->state = ZOMBIE;
 | 
				
			||||||
| 
						 | 
					@ -366,13 +366,20 @@ wait(void)
 | 
				
			||||||
  int havekids, pid;
 | 
					  int havekids, pid;
 | 
				
			||||||
  struct proc *p = myproc();
 | 
					  struct proc *p = myproc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // hold p->lock for the whole time to avoid lost
 | 
				
			||||||
 | 
					  // wakeups from a child's exit().
 | 
				
			||||||
  acquire(&p->lock);
 | 
					  acquire(&p->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  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(np = proc; np < &proc[NPROC]; np++){
 | 
				
			||||||
      if(np->parent != p)
 | 
					      // this code uses np->parent without holding np->lock.
 | 
				
			||||||
        continue;
 | 
					      // acquiring the lock first would cause a deadlock,
 | 
				
			||||||
 | 
					      // since np might be an ancestor, and we already hold p->lock.
 | 
				
			||||||
 | 
					      if(np->parent == p){
 | 
				
			||||||
 | 
					        // np->parent can't change between the check and the acquire()
 | 
				
			||||||
 | 
					        // because only the parent changes it, and we're the parent.
 | 
				
			||||||
        acquire(&np->lock);
 | 
					        acquire(&np->lock);
 | 
				
			||||||
        havekids = 1;
 | 
					        havekids = 1;
 | 
				
			||||||
        if(np->state == ZOMBIE){
 | 
					        if(np->state == ZOMBIE){
 | 
				
			||||||
| 
						 | 
					@ -385,6 +392,7 @@ wait(void)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        release(&np->lock);
 | 
					        release(&np->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 || p->killed){
 | 
				
			||||||
| 
						 | 
					@ -392,7 +400,7 @@ wait(void)
 | 
				
			||||||
      return -1;
 | 
					      return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Wait for children to exit.  (See wakeup1 call in reparent.)
 | 
					    // Wait for a child to exit.
 | 
				
			||||||
    sleep(p, &p->lock);  //DOC: wait-sleep
 | 
					    sleep(p, &p->lock);  //DOC: wait-sleep
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -401,8 +409,8 @@ wait(void)
 | 
				
			||||||
// Per-CPU process scheduler.
 | 
					// Per-CPU process scheduler.
 | 
				
			||||||
// Each CPU calls scheduler() after setting itself up.
 | 
					// Each CPU calls scheduler() after setting itself up.
 | 
				
			||||||
// Scheduler never returns.  It loops, doing:
 | 
					// Scheduler never returns.  It loops, doing:
 | 
				
			||||||
//  - choose a process to run
 | 
					//  - choose a process to run.
 | 
				
			||||||
//  - swtch to start running that process
 | 
					//  - swtch to start running that process.
 | 
				
			||||||
//  - eventually that process transfers control
 | 
					//  - eventually that process transfers control
 | 
				
			||||||
//    via swtch back to the scheduler.
 | 
					//    via swtch back to the scheduler.
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
| 
						 | 
					@ -413,7 +421,7 @@ scheduler(void)
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  c->proc = 0;
 | 
					  c->proc = 0;
 | 
				
			||||||
  for(;;){
 | 
					  for(;;){
 | 
				
			||||||
    // Enable interrupts on this processor.
 | 
					    // Give devices a brief chance to interrupt.
 | 
				
			||||||
    intr_on();
 | 
					    intr_on();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for(p = proc; p < &proc[NPROC]; p++) {
 | 
					    for(p = proc; p < &proc[NPROC]; p++) {
 | 
				
			||||||
| 
						 | 
					@ -435,7 +443,7 @@ scheduler(void)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Enter scheduler.  Must hold only p->lock
 | 
					// Switch to scheduler.  Must hold only p->lock
 | 
				
			||||||
// and have changed proc->state. Saves and restores
 | 
					// and have changed proc->state. Saves and restores
 | 
				
			||||||
// intena because intena is a property of this
 | 
					// intena because intena is a property of this
 | 
				
			||||||
// kernel thread, not this CPU. It should
 | 
					// kernel thread, not this CPU. It should
 | 
				
			||||||
| 
						 | 
					@ -512,12 +520,13 @@ sleep(void *chan, struct spinlock *lk)
 | 
				
			||||||
  // change p->state and then call sched.
 | 
					  // change p->state and then call sched.
 | 
				
			||||||
  // Once we hold p->lock, we can be
 | 
					  // Once we hold p->lock, we can be
 | 
				
			||||||
  // guaranteed that we won't miss any wakeup
 | 
					  // guaranteed that we won't miss any wakeup
 | 
				
			||||||
  // (wakeup runs with p->lock locked),
 | 
					  // (wakeup locks p->lock),
 | 
				
			||||||
  // so it's okay to release lk.
 | 
					  // so it's okay to release lk.
 | 
				
			||||||
  if(lk != &p->lock){  //DOC: sleeplock0
 | 
					  if(lk != &p->lock){  //DOC: sleeplock0
 | 
				
			||||||
    acquire(&p->lock);  //DOC: sleeplock1
 | 
					    acquire(&p->lock);  //DOC: sleeplock1
 | 
				
			||||||
    release(lk);
 | 
					    release(lk);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Go to sleep.
 | 
					  // Go to sleep.
 | 
				
			||||||
  p->chan = chan;
 | 
					  p->chan = chan;
 | 
				
			||||||
  p->state = SLEEPING;
 | 
					  p->state = SLEEPING;
 | 
				
			||||||
| 
						 | 
					@ -535,8 +544,8 @@ sleep(void *chan, struct spinlock *lk)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//PAGEBREAK!
 | 
					//PAGEBREAK!
 | 
				
			||||||
// Wake up p, used by exit()
 | 
					// Wake up p if it is sleeping in wait(); used by exit().
 | 
				
			||||||
// Caller should lock p.
 | 
					// Caller must hold p->lock.
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
wakeup1(struct proc *p)
 | 
					wakeup1(struct proc *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -545,8 +554,8 @@ wakeup1(struct proc *p)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Wake up all processes sleeping on chan. Never
 | 
					// Wake up all processes sleeping on chan.
 | 
				
			||||||
// called when holding a p->lock
 | 
					// Must be called without any p->lock.
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
wakeup(void *chan)
 | 
					wakeup(void *chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -562,25 +571,25 @@ wakeup(void *chan)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Kill the process with the given pid.
 | 
					// Kill the process with the given pid.
 | 
				
			||||||
// Process won't exit until it returns
 | 
					// The victim won't exit until it tries to return
 | 
				
			||||||
// to user space (see trap in trap.c).
 | 
					// to user space (see usertrap() in trap.c).
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
kill(int pid)
 | 
					kill(int pid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  struct proc *p;
 | 
					  struct proc *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for(p = proc; p < &proc[NPROC]; p++){
 | 
					  for(p = proc; p < &proc[NPROC]; p++){
 | 
				
			||||||
    if(p->pid == pid){
 | 
					 | 
				
			||||||
    acquire(&p->lock);
 | 
					    acquire(&p->lock);
 | 
				
			||||||
      if(p->pid != pid)
 | 
					    if(p->pid == pid){
 | 
				
			||||||
        panic("kill");
 | 
					 | 
				
			||||||
      p->killed = 1;
 | 
					      p->killed = 1;
 | 
				
			||||||
      // Wake process from sleep if necessary.
 | 
					      if(p->state == SLEEPING){
 | 
				
			||||||
      if(p->state == SLEEPING)
 | 
					        // Wake process from sleep().
 | 
				
			||||||
        p->state = RUNNABLE;
 | 
					        p->state = RUNNABLE;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      release(&p->lock);
 | 
					      release(&p->lock);
 | 
				
			||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    release(&p->lock);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return -1;
 | 
					  return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,10 +18,10 @@ struct context {
 | 
				
			||||||
  uint64 s11;
 | 
					  uint64 s11;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Per-CPU state
 | 
					// Per-CPU state.
 | 
				
			||||||
struct cpu {
 | 
					struct cpu {
 | 
				
			||||||
  struct proc *proc;           // The process running on this cpu or null
 | 
					  struct proc *proc;          // The process running on this cpu, or null.
 | 
				
			||||||
  struct context scheduler;   // swtch() here to enter scheduler
 | 
					  struct context scheduler;   // swtch() here to enter scheduler().
 | 
				
			||||||
  int noff;                   // Depth of push_off() nesting.
 | 
					  int noff;                   // Depth of push_off() nesting.
 | 
				
			||||||
  int intena;                 // Were interrupts enabled before push_off()?
 | 
					  int intena;                 // Were interrupts enabled before push_off()?
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -30,21 +30,25 @@ extern struct cpu cpus[NCPU];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//PAGEBREAK: 17
 | 
					//PAGEBREAK: 17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// per-process data for the early trap handling code in trampoline.S.
 | 
					// per-process data for the trap handling code in trampoline.S.
 | 
				
			||||||
// sits in a page by itself just under the trampoline page in the
 | 
					// sits in a page by itself just under the trampoline page in the
 | 
				
			||||||
// user page table. not specially mapped in the kernel page table.
 | 
					// user page table. not specially mapped in the kernel page table.
 | 
				
			||||||
// the sscratch register points here.
 | 
					// the sscratch register points here.
 | 
				
			||||||
// trampoline.S saves user registers, then restores kernel_sp and
 | 
					// trampin in trampoline.S saves user registers in the trapframe,
 | 
				
			||||||
// kernel_satp.
 | 
					// then initializes registers from the trapframe's
 | 
				
			||||||
// includes callee-saved registers like s0-s11 because the
 | 
					// kernel_sp, kernel_hartid, kernel_satp, and jumps to kernel_trap.
 | 
				
			||||||
 | 
					// usertrapret() and trampout in trampoline.S set up
 | 
				
			||||||
 | 
					// the trapframe's kernel_*, restore user registers from the
 | 
				
			||||||
 | 
					// trapframe, switch to the user page table, and enter user space.
 | 
				
			||||||
 | 
					// the trapframe includes callee-saved user registers like s0-s11 because the
 | 
				
			||||||
// return-to-user path via usertrapret() doesn't return through
 | 
					// return-to-user path via usertrapret() doesn't return through
 | 
				
			||||||
// the entire kernel call stack.
 | 
					// the entire kernel call stack.
 | 
				
			||||||
struct trapframe {
 | 
					struct trapframe {
 | 
				
			||||||
  /*   0 */ uint64 kernel_satp;
 | 
					  /*   0 */ uint64 kernel_satp;   // kernel page table
 | 
				
			||||||
  /*   8 */ uint64 kernel_sp;
 | 
					  /*   8 */ uint64 kernel_sp;     // top of process's kernel stack
 | 
				
			||||||
  /*  16 */ uint64 kernel_trap;   // usertrap()
 | 
					  /*  16 */ uint64 kernel_trap;   // usertrap()
 | 
				
			||||||
  /*  24 */ uint64 epc;           // saved user program counter
 | 
					  /*  24 */ uint64 epc;           // saved user program counter
 | 
				
			||||||
  /*  32 */ uint64 hartid;
 | 
					  /*  32 */ uint64 kernel_hartid; // saved kernel tp
 | 
				
			||||||
  /*  40 */ uint64 ra;
 | 
					  /*  40 */ uint64 ra;
 | 
				
			||||||
  /*  48 */ uint64 sp;
 | 
					  /*  48 */ uint64 sp;
 | 
				
			||||||
  /*  56 */ uint64 gp;
 | 
					  /*  56 */ uint64 gp;
 | 
				
			||||||
| 
						 | 
					@ -83,16 +87,20 @@ enum procstate { UNUSED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
 | 
				
			||||||
// Per-process state
 | 
					// Per-process state
 | 
				
			||||||
struct proc {
 | 
					struct proc {
 | 
				
			||||||
  struct spinlock lock;
 | 
					  struct spinlock lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // p->lock must be held when using these:
 | 
				
			||||||
 | 
					  enum procstate state;        // Process state
 | 
				
			||||||
 | 
					  struct proc *parent;         // Parent process
 | 
				
			||||||
 | 
					  void *chan;                  // If non-zero, sleeping on chan
 | 
				
			||||||
 | 
					  int killed;                  // If non-zero, have been killed
 | 
				
			||||||
 | 
					  int pid;                     // Process ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // these are private to the process, so p->lock need not be held.
 | 
				
			||||||
  char *kstack;                // Bottom of kernel stack for this process
 | 
					  char *kstack;                // Bottom of kernel stack for this process
 | 
				
			||||||
  uint64 sz;                   // Size of process memory (bytes)
 | 
					  uint64 sz;                   // Size of process memory (bytes)
 | 
				
			||||||
  pagetable_t pagetable;       // Page table
 | 
					  pagetable_t pagetable;       // Page table
 | 
				
			||||||
  enum procstate state;        // Process state
 | 
					 | 
				
			||||||
  int pid;                     // Process ID
 | 
					 | 
				
			||||||
  struct proc *parent;         // Parent process
 | 
					 | 
				
			||||||
  struct trapframe *tf;        // data page for trampoline.S
 | 
					  struct trapframe *tf;        // data page for trampoline.S
 | 
				
			||||||
  struct context context;      // swtch() here to run process
 | 
					  struct context context;      // swtch() here to run process
 | 
				
			||||||
  void *chan;                  // If non-zero, sleeping on chan
 | 
					 | 
				
			||||||
  int killed;                  // If non-zero, have been killed
 | 
					 | 
				
			||||||
  struct file *ofile[NOFILE];  // Open files
 | 
					  struct file *ofile[NOFILE];  // Open files
 | 
				
			||||||
  struct inode *cwd;           // Current directory
 | 
					  struct inode *cwd;           // Current directory
 | 
				
			||||||
  char name[16];               // Process name (debugging)
 | 
					  char name[16];               // Process name (debugging)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -312,6 +312,17 @@ r_ra()
 | 
				
			||||||
  return x;
 | 
					  return x;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// tell the machine to finish any previous writes to
 | 
				
			||||||
 | 
					// PTEs, so that a subsequent use of a virtual
 | 
				
			||||||
 | 
					// address or load of the SATP will see those writes.
 | 
				
			||||||
 | 
					// perhaps this also flushes the TLB.
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					sfence_vma()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  // the zero, zero means flush all TLB entries.
 | 
				
			||||||
 | 
					  asm volatile("sfence.vma zero, zero");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,8 +18,6 @@ initlock(struct spinlock *lk, char *name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Acquire the lock.
 | 
					// Acquire the lock.
 | 
				
			||||||
// Loops (spins) until the lock is acquired.
 | 
					// Loops (spins) until the lock is acquired.
 | 
				
			||||||
// Holding a lock for a long time may cause
 | 
					 | 
				
			||||||
// other CPUs to waste time spinning to acquire it.
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
acquire(struct spinlock *lk)
 | 
					acquire(struct spinlock *lk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -27,7 +25,7 @@ acquire(struct spinlock *lk)
 | 
				
			||||||
  if(holding(lk))
 | 
					  if(holding(lk))
 | 
				
			||||||
    panic("acquire");
 | 
					    panic("acquire");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // On RISC-V, this turns into an atomic swap:
 | 
					  // On RISC-V, sync_lock_test_and_set turns into an atomic swap:
 | 
				
			||||||
  //   a5 = 1
 | 
					  //   a5 = 1
 | 
				
			||||||
  //   s1 = &lk->locked
 | 
					  //   s1 = &lk->locked
 | 
				
			||||||
  //   amoswap.w.aq a5, a5, (s1)
 | 
					  //   amoswap.w.aq a5, a5, (s1)
 | 
				
			||||||
| 
						 | 
					@ -59,9 +57,10 @@ release(struct spinlock *lk)
 | 
				
			||||||
  __sync_synchronize();
 | 
					  __sync_synchronize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Release the lock, equivalent to lk->locked = 0.
 | 
					  // Release the lock, equivalent to lk->locked = 0.
 | 
				
			||||||
  // This code can't use a C assignment, since it might
 | 
					  // This code doesn't use a C assignment, since the C standard
 | 
				
			||||||
  // not be atomic.
 | 
					  // implies that an assignment might be implemented with
 | 
				
			||||||
  // On RISC-V, this turns into an atomic swap:
 | 
					  // multiple store instructions.
 | 
				
			||||||
 | 
					  // On RISC-V, sync_lock_release turns into an atomic swap:
 | 
				
			||||||
  //   s1 = &lk->locked
 | 
					  //   s1 = &lk->locked
 | 
				
			||||||
  //   amoswap.w zero, zero, (s1)
 | 
					  //   amoswap.w zero, zero, (s1)
 | 
				
			||||||
  __sync_lock_release(&lk->locked);
 | 
					  __sync_lock_release(&lk->locked);
 | 
				
			||||||
| 
						 | 
					@ -81,7 +80,7 @@ holding(struct spinlock *lk)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// push_off/pop_off are like intr_off()/intr_on() except that they are matched:
 | 
					// push_off/pop_off are like intr_off()/intr_on() except that they are matched:
 | 
				
			||||||
// it takes two pop_off to undo two push_off.  Also, if interrupts
 | 
					// it takes two pop_off()s to undo two push_off()s.  Also, if interrupts
 | 
				
			||||||
// are initially off, then push_off, pop_off leaves them off.
 | 
					// are initially off, then push_off, pop_off leaves them off.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,5 @@ struct spinlock {
 | 
				
			||||||
  // For debugging:
 | 
					  // For debugging:
 | 
				
			||||||
  char *name;        // Name of lock.
 | 
					  char *name;        // Name of lock.
 | 
				
			||||||
  struct cpu *cpu;   // The cpu holding the lock.
 | 
					  struct cpu *cpu;   // The cpu holding the lock.
 | 
				
			||||||
  struct cpu *last_release;
 | 
					 | 
				
			||||||
  uint64 last_pc;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -157,8 +157,8 @@ static uint64 (*syscalls[])(void) = {
 | 
				
			||||||
[SYS_close]   sys_close,
 | 
					[SYS_close]   sys_close,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					void
 | 
				
			||||||
dosyscall(void)
 | 
					syscall(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int num;
 | 
					  int num;
 | 
				
			||||||
  struct proc *p = myproc();
 | 
					  struct proc *p = myproc();
 | 
				
			||||||
| 
						 | 
					@ -174,15 +174,3 @@ dosyscall(void)
 | 
				
			||||||
    p->tf->a0 = -1;
 | 
					    p->tf->a0 = -1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
syscall()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(myproc()->killed)
 | 
					 | 
				
			||||||
      exit();
 | 
					 | 
				
			||||||
    dosyscall();
 | 
					 | 
				
			||||||
    if(myproc()->killed)
 | 
					 | 
				
			||||||
      exit();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,8 @@ trampout:
 | 
				
			||||||
	# 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # switch to user page table
 | 
						# switch to user page table.
 | 
				
			||||||
 | 
						sfence.vma zero, zero
 | 
				
			||||||
        csrw satp, a1
 | 
					        csrw satp, a1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # put the saved user a0 in sscratch, so we
 | 
					        # put the saved user a0 in sscratch, so we
 | 
				
			||||||
| 
						 | 
					@ -120,7 +121,7 @@ trampin:
 | 
				
			||||||
        # 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # make tp hold the current hartid, from p->tf->hartid
 | 
					        # make tp hold the current hartid, from p->tf->kernel_hartid
 | 
				
			||||||
        ld tp, 32(a0)
 | 
					        ld tp, 32(a0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # remember the address of usertrap(), p->tf->kernel_trap
 | 
					        # remember the address of usertrap(), p->tf->kernel_trap
 | 
				
			||||||
| 
						 | 
					@ -128,6 +129,7 @@ trampin:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # restore kernel page table from p->tf->kernel_satp
 | 
					        # restore kernel page table from p->tf->kernel_satp
 | 
				
			||||||
        ld t1, 0(a0)
 | 
					        ld t1, 0(a0)
 | 
				
			||||||
 | 
						sfence.vma zero, zero
 | 
				
			||||||
        csrw satp, t1
 | 
					        csrw satp, t1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # a0 is no longer valid, since the kernel page
 | 
					        # a0 is no longer valid, since the kernel page
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,6 +53,9 @@ usertrap(void)
 | 
				
			||||||
  if(r_scause() == 8){
 | 
					  if(r_scause() == 8){
 | 
				
			||||||
    // system call
 | 
					    // system call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(p->killed)
 | 
				
			||||||
 | 
					      exit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 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->tf->epc += 4;
 | 
					    p->tf->epc += 4;
 | 
				
			||||||
| 
						 | 
					@ -100,7 +103,7 @@ usertrapret(void)
 | 
				
			||||||
  p->tf->kernel_satp = r_satp();
 | 
					  p->tf->kernel_satp = r_satp();
 | 
				
			||||||
  p->tf->kernel_sp = (uint64)p->kstack + PGSIZE;
 | 
					  p->tf->kernel_sp = (uint64)p->kstack + PGSIZE;
 | 
				
			||||||
  p->tf->kernel_trap = (uint64)usertrap;
 | 
					  p->tf->kernel_trap = (uint64)usertrap;
 | 
				
			||||||
  p->tf->hartid = r_tp();
 | 
					  p->tf->kernel_hartid = r_tp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // set up the registers that trampoline.S's sret will use
 | 
					  // set up the registers that trampoline.S's sret will use
 | 
				
			||||||
  // to get to user space.
 | 
					  // to get to user space.
 | 
				
			||||||
| 
						 | 
					@ -155,6 +158,15 @@ kerneltrap()
 | 
				
			||||||
  w_sstatus(sstatus);
 | 
					  w_sstatus(sstatus);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					clockintr()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  acquire(&tickslock);
 | 
				
			||||||
 | 
					  ticks++;
 | 
				
			||||||
 | 
					  wakeup(&ticks);
 | 
				
			||||||
 | 
					  release(&tickslock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// check if it's an external interrupt or software interrupt,
 | 
					// check if it's an external interrupt or software interrupt,
 | 
				
			||||||
// and handle it.
 | 
					// and handle it.
 | 
				
			||||||
// returns 2 if timer interrupt,
 | 
					// returns 2 if timer interrupt,
 | 
				
			||||||
| 
						 | 
					@ -179,16 +191,15 @@ devintr()
 | 
				
			||||||
    plic_complete(irq);
 | 
					    plic_complete(irq);
 | 
				
			||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
  } else if(scause == 0x8000000000000001){
 | 
					  } else if(scause == 0x8000000000000001){
 | 
				
			||||||
    // software interrupt from a machine-mode timer interrupt.
 | 
					    // software interrupt from a machine-mode timer interrupt,
 | 
				
			||||||
 | 
					    // forwarded by machinevec in kernelvec.S.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(cpuid() == 0){
 | 
					    if(cpuid() == 0){
 | 
				
			||||||
      acquire(&tickslock);
 | 
					      clockintr();
 | 
				
			||||||
      ticks++;
 | 
					 | 
				
			||||||
      wakeup(&ticks);
 | 
					 | 
				
			||||||
      release(&tickslock);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // acknowledge.
 | 
					    // acknowledge the software interrupt by clearing
 | 
				
			||||||
 | 
					    // the SSIP bit in sip.
 | 
				
			||||||
    w_sip(r_sip() & ~2);
 | 
					    w_sip(r_sip() & ~2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 2;
 | 
					    return 2;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@
 | 
				
			||||||
// the address of virtio mmio register r.
 | 
					// the address of virtio mmio register r.
 | 
				
			||||||
#define R(r) ((volatile uint32 *)(VIRTIO0 + (r)))
 | 
					#define R(r) ((volatile uint32 *)(VIRTIO0 + (r)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct spinlock virtio_disk_lock;
 | 
					struct spinlock vdisk_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// memory for virtio descriptors &c for queue 0.
 | 
					// memory for virtio descriptors &c for queue 0.
 | 
				
			||||||
// this is a global instead of allocated because it has
 | 
					// this is a global instead of allocated because it has
 | 
				
			||||||
| 
						 | 
					@ -49,7 +49,7 @@ virtio_disk_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  uint32 status = 0;
 | 
					  uint32 status = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  initlock(&virtio_disk_lock, "virtio_disk");
 | 
					  initlock(&vdisk_lock, "virtio_disk");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
 | 
					  if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||
 | 
				
			||||||
     *R(VIRTIO_MMIO_VERSION) != 1 ||
 | 
					     *R(VIRTIO_MMIO_VERSION) != 1 ||
 | 
				
			||||||
| 
						 | 
					@ -168,7 +168,7 @@ virtio_disk_rw(struct buf *b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  uint64 sector = b->blockno * (BSIZE / 512);
 | 
					  uint64 sector = b->blockno * (BSIZE / 512);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  acquire(&virtio_disk_lock);
 | 
					  acquire(&vdisk_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // the spec says that legacy block operations use three
 | 
					  // the spec says that legacy block operations use three
 | 
				
			||||||
  // descriptors: one for type/reserved/sector, one for
 | 
					  // descriptors: one for type/reserved/sector, one for
 | 
				
			||||||
| 
						 | 
					@ -180,7 +180,7 @@ virtio_disk_rw(struct buf *b)
 | 
				
			||||||
    if(alloc3_desc(idx) == 0) {
 | 
					    if(alloc3_desc(idx) == 0) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    sleep(&free[0], &virtio_disk_lock);
 | 
					    sleep(&free[0], &vdisk_lock);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  // format the three descriptors.
 | 
					  // format the three descriptors.
 | 
				
			||||||
| 
						 | 
					@ -234,16 +234,16 @@ virtio_disk_rw(struct buf *b)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Wait for virtio_disk_intr() to say request has finished.
 | 
					  // Wait for virtio_disk_intr() to say request has finished.
 | 
				
			||||||
  while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){
 | 
					  while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){
 | 
				
			||||||
    sleep(b, &virtio_disk_lock);
 | 
					    sleep(b, &vdisk_lock);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  release(&virtio_disk_lock);
 | 
					  release(&vdisk_lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
virtio_disk_intr()
 | 
					virtio_disk_intr()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  acquire(&virtio_disk_lock);
 | 
					  acquire(&vdisk_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while((used_idx % NUM) != (used->id % NUM)){
 | 
					  while((used_idx % NUM) != (used->id % NUM)){
 | 
				
			||||||
    int id = used->elems[used_idx].id;
 | 
					    int id = used->elems[used_idx].id;
 | 
				
			||||||
| 
						 | 
					@ -262,5 +262,5 @@ virtio_disk_intr()
 | 
				
			||||||
    used_idx = (used_idx + 1) % NUM;
 | 
					    used_idx = (used_idx + 1) % NUM;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  release(&virtio_disk_lock);
 | 
					  release(&vdisk_lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,6 +61,7 @@ kvminit()
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
kvminithart()
 | 
					kvminithart()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  sfence_vma();
 | 
				
			||||||
  w_satp(MAKE_SATP(kernel_pagetable));
 | 
					  w_satp(MAKE_SATP(kernel_pagetable));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -506,6 +506,44 @@ twochildren(void)
 | 
				
			||||||
  printf(1, "twochildren ok\n");
 | 
					  printf(1, "twochildren ok\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// concurrent forks to try to expose locking bugs.
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					forkfork(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  int ppid = getpid();
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  printf(1, "forkfork test\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for(int i = 0; i < 2; i++){
 | 
				
			||||||
 | 
					    int pid = fork();
 | 
				
			||||||
 | 
					    if(pid < 0){
 | 
				
			||||||
 | 
					      printf(1, "fork failed");
 | 
				
			||||||
 | 
					      exit();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(pid == 0){
 | 
				
			||||||
 | 
					      for(int j = 0; j < 200; j++){
 | 
				
			||||||
 | 
					        int pid1 = fork();
 | 
				
			||||||
 | 
					        if(pid1 < 0){
 | 
				
			||||||
 | 
					          printf(1, "fork failed\n");
 | 
				
			||||||
 | 
					          kill(ppid);
 | 
				
			||||||
 | 
					          exit();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(pid1 == 0){
 | 
				
			||||||
 | 
					          exit();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        wait();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      exit();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for(int i = 0; i < 2; i++){
 | 
				
			||||||
 | 
					    wait();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  printf(1, "forkfork ok\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
forkforkfork(void)
 | 
					forkforkfork(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1858,6 +1896,7 @@ main(int argc, char *argv[])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  reparent();
 | 
					  reparent();
 | 
				
			||||||
  twochildren();
 | 
					  twochildren();
 | 
				
			||||||
 | 
					  forkfork();
 | 
				
			||||||
  forkforkfork();
 | 
					  forkforkfork();
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  argptest();
 | 
					  argptest();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue