Exemplo n.º 1
0
// Switch to and run a specified process, which must already be locked.
void gcc_noreturn
proc_run(proc *p)
{
	// cprintf("proc_run %p\n", p);
	if(!spinlock_holding(&(p->lock))) panic("should have p->lock.\n");
	p->runcpu = cpu_cur();
	p->state = PROC_RUN;
	cpu_cur()->proc = p;
	spinlock_release(&(p->lock));

	trap_return(&(p->sv.tf));
}
Exemplo n.º 2
0
void
file_initroot(proc *root)
{
	// Only one root process may perform external I/O directly -
	// all other processes do I/O indirectly via the process hierarchy.
	assert(root == proc_root);

	// Make sure the root process's page directory is loaded,
	// so that we can write into the root process's file area directly.
	cpu_cur()->proc = root;
	lcr3(mem_phys(root->pdir));

	// Enable read/write access on the file metadata area
	pmap_setperm(root->pdir, FILESVA, ROUNDUP(sizeof(filestate), PAGESIZE),
				SYS_READ | SYS_WRITE);
	memset(files, 0, sizeof(*files));

	// Set up the standard I/O descriptors for console I/O
	files->fd[0].ino = FILEINO_CONSIN;
	files->fd[0].flags = O_RDONLY;
	files->fd[1].ino = FILEINO_CONSOUT;
	files->fd[1].flags = O_WRONLY | O_APPEND;
	files->fd[2].ino = FILEINO_CONSOUT;
	files->fd[2].flags = O_WRONLY | O_APPEND;

	// Setup the inodes for the console I/O files and root directory
	strcpy(files->fi[FILEINO_CONSIN].de.d_name, "consin");
	strcpy(files->fi[FILEINO_CONSOUT].de.d_name, "consout");
	strcpy(files->fi[FILEINO_ROOTDIR].de.d_name, "/");
	files->fi[FILEINO_CONSIN].dino = FILEINO_ROOTDIR;
	files->fi[FILEINO_CONSOUT].dino = FILEINO_ROOTDIR;
	files->fi[FILEINO_ROOTDIR].dino = FILEINO_ROOTDIR;
	files->fi[FILEINO_CONSIN].mode = S_IFREG | S_IFPART;
	files->fi[FILEINO_CONSOUT].mode = S_IFREG;
	files->fi[FILEINO_ROOTDIR].mode = S_IFDIR;

	// Set the whole console input area to be read/write,
	// so we won't have to worry about perms in cons_io().
	pmap_setperm(root->pdir, (uintptr_t)FILEDATA(FILEINO_CONSIN),
				PTSIZE, SYS_READ | SYS_WRITE);

	// Set up the initial files in the root process's file system.
	// Some script magic in kern/Makefrag creates obj/kern/initfiles.h,
	// which gets included above (twice) to create the 'initfiles' array.
	// For each initial file numbered 0 <= i < ninitfiles,
	// initfiles[i][0] is a pointer to the filename string for that file,
	// initfiles[i][1] is a pointer to the start of the file's content, and
	// initfiles[i][2] is a pointer to the end of the file's content
	// (i.e., a pointer to the first byte after the file's last byte).
	int ninitfiles = sizeof(initfiles)/sizeof(initfiles[0]);
	// Lab 4: your file system initialization code here.
	warn("file_initroot: file system initialization not done\n");

	// Set root process's current working directory
	files->cwd = FILEINO_ROOTDIR;

	// Child process state - reserve PID 0 as a "scratch" child process.
	files->child[0].state = PROC_RESERVED;
}
Exemplo n.º 3
0
// Recover from a trap that occurs during a copyin or copyout,
// by aborting the system call and reflecting the trap to the parent process,
// behaving as if the user program's INT instruction had caused the trap.
// This uses the 'recover' pointer in the current cpu struct,
// and invokes systrap() above to blame the trap on the user process.
//
// Notes:
// - Be sure the parent gets the correct trapno, err, and eip values.
// - Be sure to release any spinlocks you were holding during the copyin/out.
//
static void gcc_noreturn
sysrecover(trapframe *ktf, void *recoverdata)
{
    trapframe *utf = (trapframe*)recoverdata;
    cpu *c = cpu_cur();
    c->recover = NULL;
    systrap(utf, ktf->trapno, ktf->err);
}
Exemplo n.º 4
0
// Acquire the lock.
// 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
spinlock_acquire(struct spinlock *lk)
{
    if(spinlock_holding(lk))
        panic("Already holding lock.");
    while(xchg(&(lk->locked), 1) != 0)
        pause();
    lk->cpu = cpu_cur();
    debug_trace(read_ebp(), lk->eips);
}
Exemplo n.º 5
0
// Yield the current CPU to another ready process.
// Called while handling a timer interrupt.
void gcc_noreturn
proc_yield(trapframe *tf)
{
	proc *p;
	p = cpu_cur()->proc;
	spinlock_acquire(&(p->lock));
	proc_save(p, tf, -1);
	spinlock_release(&(p->lock));
	proc_ready(p);
	proc_sched();
}
Exemplo n.º 6
0
// Copy data to/from user space,
// using checkva() above to validate the address range
// and using sysrecover() to recover from any traps during the copy.
void usercopy(trapframe *utf, bool copyout,
			void *kva, uint32_t uva, size_t size) {
	checkva(utf, uva, size);
  cpu *c = cpu_cur();
  c->recover = sysrecover;

  if(copyout)
    memmove((void*)uva, kva, size);
  else
    memmove(kva, (void*)uva, size);

  c->recover = NULL;
}
Exemplo n.º 7
0
void spinlock_check()
{
	const int NUMLOCKS=10;
	const int NUMRUNS=5;
	int i,j,run;
	const char* file = "spinlock_check";
	spinlock locks[NUMLOCKS];

	// Initialize the locks
	for(i=0;i<NUMLOCKS;i++) spinlock_init_(&locks[i], file, 0);
	// Make sure that all locks have CPU set to NULL initially
	for(i=0;i<NUMLOCKS;i++) assert(locks[i].cpu==NULL);
	// Make sure that all locks have the correct debug info.
	for(i=0;i<NUMLOCKS;i++) assert(locks[i].file==file);

	for (run=0;run<NUMRUNS;run++) 
	{
		// Lock all locks
		for(i=0;i<NUMLOCKS;i++)
			spinlock_godeep(i, &locks[i]);

		// Make sure that all locks have the right CPU
		for(i=0;i<NUMLOCKS;i++)
			assert(locks[i].cpu == cpu_cur());
		// Make sure that all locks have holding correctly implemented.
		for(i=0;i<NUMLOCKS;i++)
			assert(spinlock_holding(&locks[i]) != 0);
		// Make sure that top i frames are somewhere in godeep.
		for(i=0;i<NUMLOCKS;i++) 
		{
			for(j=0; j<=i && j < DEBUG_TRACEFRAMES ; j++) 
			{
				assert(locks[i].eips[j] >=
					(uint32_t)spinlock_godeep);
				assert(locks[i].eips[j] <
					(uint32_t)spinlock_godeep+100);
			}
		}

		// Release all locks
		for(i=0;i<NUMLOCKS;i++) spinlock_release(&locks[i]);
		// Make sure that the CPU has been cleared
		for(i=0;i<NUMLOCKS;i++) assert(locks[i].cpu == NULL);
		for(i=0;i<NUMLOCKS;i++) assert(locks[i].eips[0]==0);
		// Make sure that all locks have holding correctly implemented.
		for(i=0;i<NUMLOCKS;i++) assert(spinlock_holding(&locks[i]) == 0);
	}
	cprintf("spinlock_check() succeeded!\n");
}
Exemplo n.º 8
0
// Switch to and run a specified process, which must already be locked.
void gcc_noreturn
proc_run(proc *p)
{
	if (!spinlock_holding(&p->lock)) panic("proc_run without lock");

	//if (p->parent) cprintf("running child\n");
	//	else cprintf("running root\n");
	
	p->state = PROC_RUN;
	p->runcpu = cpu_cur();
	cpu_cur()->proc = p;
	
	// Enable interrupts (for preemption)
	p->sv.tf.eflags |= (1 << 9);
	p->sv.tf.ds = CPU_GDT_UDATA | 3;
	p->sv.tf.es = CPU_GDT_UDATA | 3;
	p->sv.tf.cs = CPU_GDT_UCODE | 3;
	p->sv.tf.ss = CPU_GDT_UDATA | 3;
	lcr3 (mem_phys(p->pdir));
	
	spinlock_release(&p->lock);
	
	trap_return(&p->sv.tf);
}
Exemplo n.º 9
0
// Put the current process to sleep by "returning" to its parent process.
// Used both when a process calls the SYS_RET system call explicitly,
// and when a process causes an unhandled trap in user mode.
// The 'entry' parameter is as in proc_save().
void gcc_noreturn
proc_ret(trapframe *tf, int entry)
{
	proc *p;
	proc *cp;
	cp = cpu_cur()->proc;
	p = cp->parent;
	cprintf("proc_ret child=%p parent=%p\n", cp, p);
	spinlock_acquire(&(p->lock));
	spinlock_acquire(&(cp->lock));
	cp->state = PROC_STOP;
	proc_save(cp, tf, entry);
	spinlock_release(&(cp->lock));
	if(p->state == PROC_WAIT && p->waitchild == cp) {
		proc_run(p);
	}
	spinlock_release(&(p->lock));
	proc_sched();
}
Exemplo n.º 10
0
  static void
do_get(trapframe *tf, uint32_t cmd)
{
  proc *p = proc_cur();
  assert(p->state == PROC_RUN && p->runcpu == cpu_cur());
  //cprintf("GET proc %x eip %x esp %x cmd %x\n", p, tf->eip, tf->esp, cmd);

  spinlock_acquire(&p->lock);

  // Find the named child process; DON'T create if it doesn't exist
  uint32_t cn = tf->regs.edx & 0xff;
  proc *cp = p->child[cn];
  if (!cp)
    cp = &proc_null;

  // Synchronize with child if necessary.
  if (cp->state != PROC_STOP)
    proc_wait(p, cp, tf);

  // Since the child is now stopped, it's ours to control;
  // we no longer need our process lock -
  // and we don't want to be holding it if usercopy() below aborts.
  spinlock_release(&p->lock);

  // Get child's general register state
  if (cmd & SYS_REGS) {
    int len = offsetof(procstate, fx);  // just integer regs
    if (cmd & SYS_FPU) len = sizeof(procstate); // whole shebang
usercopy(tf, 1, &cp->sv, tf->regs.ebx, len);
    // Copy child process's trapframe into user space
    procstate *cs = (procstate*) tf->regs.ebx;
    memcpy(cs, &cp->sv, len);
  }
uint32_t sva = tf->regs.esi;
	uint32_t dva = tf->regs.edi;
	uint32_t size = tf->regs.ecx;
	switch (cmd & SYS_MEMOP) {
	case 0:	// no memory operation
		break;
	case SYS_COPY:
	case SYS_MERGE:
		// validate source region
		if (PTOFF(sva) || PTOFF(size)
				|| sva < VM_USERLO || sva > VM_USERHI
				|| size > VM_USERHI-sva)
			systrap(tf, T_GPFLT, 0);
		// fall thru...
	case SYS_ZERO:
		// validate destination region
		if (PTOFF(dva) || PTOFF(size)
				|| dva < VM_USERLO || dva > VM_USERHI
				|| size > VM_USERHI-dva)
			systrap(tf, T_GPFLT, 0);

		switch (cmd & SYS_MEMOP) {
		case SYS_ZERO:	// zero memory and clear permissions
			pmap_remove(p->pdir, dva, size);
			break;
		case SYS_COPY:	// copy from local src to dest in child
			pmap_copy(cp->pdir, sva, p->pdir, dva, size);
			break;
		case SYS_MERGE:	// merge from local src to dest in child
			pmap_merge(cp->rpdir, cp->pdir, sva,
					p->pdir, dva, size);
			break;
		}
		break;
	default:
		systrap(tf, T_GPFLT, 0);
	}

	if (cmd & SYS_PERM) {
		// validate destination region
		if (PGOFF(dva) || PGOFF(size)
				|| dva < VM_USERLO || dva > VM_USERHI
				|| size > VM_USERHI-dva)
			systrap(tf, T_GPFLT, 0);
		if (!pmap_setperm(p->pdir, dva, size, cmd & SYS_RW))
			panic("pmap_get: no memory to set permissions");
	}

	if (cmd & SYS_SNAP)
		systrap(tf, T_GPFLT, 0);	// only valid for PUT
  trap_return(tf);  // syscall completed
}
Exemplo n.º 11
0
static void
do_put(trapframe *tf, uint32_t cmd)
{
  proc *p = proc_cur();
  assert(p->state == PROC_RUN && p->runcpu == cpu_cur());
  cprintf("PUT proc %x eip %x esp %x cmd %x\n", p, tf->eip, tf->esp, cmd);

  spinlock_acquire(&p->lock);

  // Find the named child process; create if it doesn't exist
  uint32_t cn = tf->regs.edx & 0xff;
  proc *cp = p->child[cn];
  if (!cp) {
    cp = proc_alloc(p, cn);
    if (!cp)  // XX handle more gracefully
      panic("sys_put: no memory for child");
  }

  // Synchronize with child if necessary.
  if (cp->state != PROC_STOP)
    proc_wait(p, cp, tf);

  // Since the child is now stopped, it's ours to control;
  // we no longer need our process lock -
  // and we don't want to be holding it if usercopy() below aborts.
  spinlock_release(&p->lock);

  // Put child's general register state
  if (cmd & SYS_REGS) {
    int len = offsetof(procstate, fx);  // just integer regs
    if (cmd & SYS_FPU) len = sizeof(procstate); // whole shebang

  usercopy(tf,0,&cp->sv, tf->regs.ebx, len);
    // Copy user's trapframe into child process
    procstate *cs = (procstate*) tf->regs.ebx;
    memcpy(&cp->sv, cs, len);

    // Make sure process uses user-mode segments and eflag settings
    cp->sv.tf.ds = CPU_GDT_UDATA | 3;
    cp->sv.tf.es = CPU_GDT_UDATA | 3;
    cp->sv.tf.cs = CPU_GDT_UCODE | 3;
    cp->sv.tf.ss = CPU_GDT_UDATA | 3;
    cp->sv.tf.eflags &= FL_USER;
    cp->sv.tf.eflags |= FL_IF;  // enable interrupts
  }
	uint32_t sva = tf->regs.esi;
	uint32_t dva = tf->regs.edi;
	uint32_t size = tf->regs.ecx;
	switch (cmd & SYS_MEMOP) {
	case 0:	// no memory operation
		break;
	case SYS_COPY:
		// validate source region
		if (PTOFF(sva) || PTOFF(size)
				|| sva < VM_USERLO || sva > VM_USERHI
				|| size > VM_USERHI-sva)
			systrap(tf, T_GPFLT, 0);
		// fall thru...
	case SYS_ZERO:
		// validate destination region
		if (PTOFF(dva) || PTOFF(size)
				|| dva < VM_USERLO || dva > VM_USERHI
				|| size > VM_USERHI-dva)
			systrap(tf, T_GPFLT, 0);

		switch (cmd & SYS_MEMOP) {
		case SYS_ZERO:	// zero memory and clear permissions
			pmap_remove(cp->pdir, dva, size);
			break;
		case SYS_COPY:	// copy from local src to dest in child
			pmap_copy(p->pdir, sva, cp->pdir, dva, size);
			break;
		}
		break;
	default:
		systrap(tf, T_GPFLT, 0);
	}

	if (cmd & SYS_PERM) {
		// validate destination region
		if (PGOFF(dva) || PGOFF(size)
				|| dva < VM_USERLO || dva > VM_USERHI
				|| size > VM_USERHI-dva)
			systrap(tf, T_GPFLT, 0);
		if (!pmap_setperm(cp->pdir, dva, size, cmd & SYS_RW))
			panic("pmap_put: no memory to set permissions");
	}

	if (cmd & SYS_SNAP)	// Snapshot child's state
		pmap_copy(cp->pdir, VM_USERLO, cp->rpdir, VM_USERLO,
				VM_USERHI-VM_USERLO);

  // Start the child if requested
  if (cmd & SYS_START)
    proc_ready(cp);

  trap_return(tf);  // syscall completed
}
Exemplo n.º 12
0
// Check whether this cpu is holding the lock.
int
spinlock_holding(spinlock *lock)
{
    return lock->cpu == cpu_cur() 
        && lock->locked;
}