summaryrefslogtreecommitdiff
path: root/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'proc.c')
-rw-r--r--proc.c285
1 files changed, 149 insertions, 136 deletions
diff --git a/proc.c b/proc.c
index 3c0acbd..e574db0 100644
--- a/proc.c
+++ b/proc.c
@@ -1,18 +1,20 @@
#include "types.h"
-#include "defs.h"
#include "param.h"
#include "memlayout.h"
-#include "mmu.h"
-#include "x86.h"
+#include "riscv.h"
#include "proc.h"
#include "spinlock.h"
+#include "defs.h"
struct {
struct spinlock lock;
struct proc proc[NPROC];
} ptable;
-static struct proc *initproc;
+// XXX riscv move somewhere else
+struct cpu cpus[NCPU];
+
+struct proc *initproc;
int nextpid = 1;
extern void forkret(void);
@@ -22,57 +24,36 @@ extern void sysexit(void);
static void wakeup1(void *chan);
+extern char trampstart[]; // trampoline.S
+
void
-pinit(void)
+procinit(void)
{
initlock(&ptable.lock, "ptable");
}
-// Must be called with interrupts disabled
+// Must be called with interrupts disabled.
+// XXX riscv
int
cpuid() {
- return mycpu()-cpus;
-}
-
-// Must be called with interrupts disabled to avoid the caller being
-// rescheduled between reading lapicid and running through the loop.
-struct cpu*
-getmycpu(void)
-{
- int apicid, i;
-
- if(readeflags()&FL_IF)
- panic("getmycpu called with interrupts enabled\n");
-
- apicid = lapicid();
- // APIC IDs are not guaranteed to be contiguous.
- for (i = 0; i < ncpu; ++i) {
- if (cpus[i].apicid == apicid)
- return &cpus[i];
- }
- panic("unknown apicid\n");
+ return 0;
}
-// Return this core's cpu struct using %gs. %gs points this core's struct
-// cpu. Offet 24 in struct cpu is cpu.
+// Return this core's cpu struct.
+// XXX riscv
struct cpu*
mycpu(void) {
struct cpu *c;
- asm volatile("mov %%gs:24, %0" : "=r" (c));
+ c = &cpus[0];
return c;
}
// Disable interrupts so that we are not rescheduled
// while reading proc from the cpu structure
+// XXX riscv
struct proc*
myproc(void) {
- struct cpu *c;
- struct proc *p;
- pushcli();
- c = mycpu();
- p = c->proc;
- popcli();
- return p;
+ return cpus[0].proc;
}
//PAGEBREAK: 32
@@ -84,7 +65,6 @@ static struct proc*
allocproc(void)
{
struct proc *p;
- char *sp;
acquire(&ptable.lock);
@@ -101,56 +81,73 @@ found:
release(&ptable.lock);
- // Allocate kernel stack.
+ // Allocate a page for the kernel stack.
if((p->kstack = kalloc()) == 0){
p->state = UNUSED;
return 0;
}
- sp = p->kstack + KSTACKSIZE;
- // Leave room for syscall frame.
- sp -= sizeof *p->sf;
+ // Allocate a trapframe page.
+ if((p->tf = (struct trapframe *)kalloc()) == 0){
+ p->state = UNUSED;
+ return 0;
+ }
- if ((uint64) sp % 16)
- panic("misaligned sp");
+ // An empty user page table.
+ p->pagetable = uvmcreate();
- p->sf = (struct sysframe*)sp;
+ // map the trampoline code (for system call return)
+ // at the highest user virtual address.
+ // only the supervisor uses it, on the way
+ // to/from user space, so not PTE_U.
+ mappages(p->pagetable, TRAMPOLINE, PGSIZE,
+ (uint64)trampstart, PTE_R | PTE_X);
- // Set up new context to start executing at forkret,
- // which returns to sysexit.
- sp -= sizeof(uint64);
- *(uint64*)sp = (uint64)sysexit;
+ // map the trapframe, for trampoline.S.
+ mappages(p->pagetable, (TRAMPOLINE - PGSIZE), PGSIZE,
+ (uint64)(p->tf), PTE_R | PTE_W);
- sp -= sizeof *p->context;
- p->context = (struct context*)sp;
- memset(p->context, 0, sizeof *p->context);
- p->context->rip = (uint64)forkret;
+ // Set up new context to start executing at forkret,
+ // which returns to user space.
+ memset(&p->context, 0, sizeof p->context);
+ p->context.ra = (uint64)forkret;
+ p->context.sp = (uint64)p->kstack + PGSIZE;
return p;
}
+// XXX hack because I don't know how to incorporate initcode
+// into the kernel binary. just the exec system call, no arguments.
+// manually copied from initcode.asm.
+unsigned char initcode[] = {
+ 0x85, 0x48, // li a7, 1 -- SYS_fork
+ 0x73, 0x00, 0x00, 0x00, // ecall
+ 0x8d, 0x48, // li a7, 3 -- SYS_wait
+ 0x73, 0x00, 0x00, 0x00, // ecall
+ 0x89, 0x48, // li a7, 2 -- SYS_exit
+ 0x73, 0x00, 0x00, 0x00, // ecall
+};
+
//PAGEBREAK: 32
// Set up first user process.
void
userinit(void)
{
struct proc *p;
- extern char _binary_initcode_start[], _binary_initcode_size[];
p = allocproc();
-
initproc = p;
- if((p->pgdir = setupkvm()) == 0)
- panic("userinit: out of memory?");
- inituvm(p->pgdir, _binary_initcode_start, (uint64)_binary_initcode_size);
+
+ uvminit(p->pagetable, initcode, sizeof(initcode));
p->sz = PGSIZE;
- memset(p->sf, 0, sizeof(*p->sf));
- p->sf->r11 = FL_IF;
- p->sf->rsp = PGSIZE;
- p->sf->rcx = 0; // beginning of initcode.S
+
+ // prepare for the very first kernel->user.
+ p->tf->epc = 0;
+ p->tf->sp = PGSIZE;
safestrcpy(p->name, "initcode", sizeof(p->name));
- p->cwd = namei("/");
+ // XXX riscv
+ //p->cwd = namei("/");
// this assignment to p->state lets other cores
// run this process. the acquire forces the above
@@ -163,62 +160,65 @@ userinit(void)
release(&ptable.lock);
}
+#if 0
+
// Grow current process's memory by n bytes.
// Return 0 on success, -1 on failure.
int
growproc(int n)
{
uint sz;
- struct proc *curproc = myproc();
+ struct proc *p = myproc();
- sz = curproc->sz;
+ sz = p->sz;
if(n > 0){
- if((sz = allocuvm(curproc->pgdir, sz, sz + n)) == 0)
+ if((sz = allocuvm(p->pagetable, sz, sz + n)) == 0)
return -1;
} else if(n < 0){
- if((sz = deallocuvm(curproc->pgdir, sz, sz + n)) == 0)
+ if((sz = uvmdealloc(p->pagetable, sz, sz + n)) == 0)
return -1;
}
- curproc->sz = sz;
- switchuvm(curproc);
+ p->sz = sz;
+ switchuvm(p);
return 0;
}
+#endif
-// Create a new process copying p as the parent.
-// Sets up stack to return as if from system call.
-// Caller must set state of returned proc to RUNNABLE.
+// Create a new process, copying p as the parent.
+// Sets up child kernel stack to return as if from system call.
int
fork(void)
{
int i, pid;
struct proc *np;
- struct proc *curproc = myproc();
+ struct proc *p = myproc();
// Allocate process.
if((np = allocproc()) == 0){
return -1;
}
- // Copy process state from proc.
- if((np->pgdir = copyuvm(curproc->pgdir, curproc->sz)) == 0){
- kfree(np->kstack);
- np->kstack = 0;
- np->state = UNUSED;
- return -1;
- }
- np->sz = curproc->sz;
- np->parent = curproc;
- *np->sf = *curproc->sf;
+ // Copy user memory from parent to child.
+ uvmcopy(p->pagetable, np->pagetable, p->sz);
+ np->sz = p->sz;
- // Clear %eax so that fork returns 0 in the child.
- np->sf->rax = 0;
+ np->parent = p;
+ // copy saved user registers.
+ *(np->tf) = *(p->tf);
+
+ // Cause fork to return 0 in the child.
+ np->tf->a0 = 0;
+
+#if 0 // XXX riscv
+ // increment reference counts on open file descriptors.
for(i = 0; i < NOFILE; i++)
- if(curproc->ofile[i])
- np->ofile[i] = filedup(curproc->ofile[i]);
- np->cwd = idup(curproc->cwd);
+ if(p->ofile[i])
+ np->ofile[i] = filedup(p->ofile[i]);
+ np->cwd = idup(p->cwd);
+#endif
- safestrcpy(np->name, curproc->name, sizeof(curproc->name));
+ safestrcpy(np->name, p->name, sizeof(p->name));
pid = np->pid;
@@ -233,46 +233,48 @@ fork(void)
// Exit the current process. Does not return.
// An exited process remains in the zombie state
-// until its parent calls wait() to find out it exited.
+// until its parent calls wait().
void
exit(void)
{
- struct proc *curproc = myproc();
- struct proc *p;
+ struct proc *p = myproc();
+ struct proc *pp;
int fd;
- if(curproc == initproc)
+ if(p == initproc)
panic("init exiting");
+#if 0 // XXX riscv
// Close all open files.
for(fd = 0; fd < NOFILE; fd++){
- if(curproc->ofile[fd]){
- fileclose(curproc->ofile[fd]);
- curproc->ofile[fd] = 0;
+ if(p->ofile[fd]){
+ fileclose(p->ofile[fd]);
+ p->ofile[fd] = 0;
}
}
begin_op();
- iput(curproc->cwd);
+ iput(p->cwd);
end_op();
- curproc->cwd = 0;
+#endif
+ p->cwd = 0;
acquire(&ptable.lock);
// Parent might be sleeping in wait().
- wakeup1(curproc->parent);
+ wakeup1(p->parent);
// Pass abandoned children to init.
- for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
- if(p->parent == curproc){
- p->parent = initproc;
- if(p->state == ZOMBIE)
+ for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){
+ if(pp->parent == p){
+ pp->parent = initproc;
+ if(pp->state == ZOMBIE)
wakeup1(initproc);
}
}
// Jump into the scheduler, never to return.
- curproc->state = ZOMBIE;
+ p->state = ZOMBIE;
sched();
panic("zombie exit");
}
@@ -282,42 +284,47 @@ exit(void)
int
wait(void)
{
- struct proc *p;
+ struct proc *np;
int havekids, pid;
- struct proc *curproc = myproc();
+ struct proc *p = myproc();
acquire(&ptable.lock);
for(;;){
// Scan through table looking for exited children.
havekids = 0;
- for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
- if(p->parent != curproc)
+ for(np = ptable.proc; np < &ptable.proc[NPROC]; np++){
+ if(np->parent != p)
continue;
havekids = 1;
- if(p->state == ZOMBIE){
+ if(np->state == ZOMBIE){
// Found one.
- pid = p->pid;
- kfree(p->kstack);
- p->kstack = 0;
- freevm(p->pgdir, p->sz);
- p->pid = 0;
- p->parent = 0;
- p->name[0] = 0;
- p->killed = 0;
- p->state = UNUSED;
+ pid = np->pid;
+ kfree(np->kstack);
+ np->kstack = 0;
+ kfree((void*)np->tf);
+ np->tf = 0;
+ unmappages(np->pagetable, TRAMPOLINE, PGSIZE, 0);
+ unmappages(np->pagetable, TRAMPOLINE-PGSIZE, PGSIZE, 0);
+ uvmfree(np->pagetable, np->sz);
+ np->pagetable = 0;
+ np->pid = 0;
+ np->parent = 0;
+ np->name[0] = 0;
+ np->killed = 0;
+ np->state = UNUSED;
release(&ptable.lock);
return pid;
}
}
// No point waiting if we don't have any children.
- if(!havekids || curproc->killed){
+ if(!havekids || p->killed){
release(&ptable.lock);
return -1;
}
// Wait for children to exit. (See wakeup1 call in proc_exit.)
- sleep(curproc, &ptable.lock); //DOC: wait-sleep
+ sleep(p, &ptable.lock); //DOC: wait-sleep
}
}
@@ -338,7 +345,8 @@ scheduler(void)
c->proc = 0;
for(;;){
// Enable interrupts on this processor.
- sti();
+ // XXX riscv
+ //sti();
// Loop over process table looking for process to run.
acquire(&ptable.lock);
@@ -350,11 +358,11 @@ scheduler(void)
// to release ptable.lock and then reacquire it
// before jumping back to us.
c->proc = p;
- switchuvm(p);
p->state = RUNNING;
- swtch(&(c->scheduler), p->context);
- switchkvm();
+ printf("switch...\n");
+ swtch(&c->scheduler, &p->context);
+ printf("switch returned\n");
// Process is done running for now.
// It should have changed its p->state before coming back.
@@ -380,14 +388,10 @@ sched(void)
if(!holding(&ptable.lock))
panic("sched ptable.lock");
- if(mycpu()->ncli != 1)
- panic("sched locks");
if(p->state == RUNNING)
panic("sched running");
- if(readeflags()&FL_IF)
- panic("sched interruptible");
intena = mycpu()->intena;
- swtch(&p->context, mycpu()->scheduler);
+ swtch(&p->context, &mycpu()->scheduler);
mycpu()->intena = intena;
}
@@ -402,24 +406,29 @@ yield(void)
}
// A fork child's very first scheduling by scheduler()
-// will swtch here. "Return" to user space.
+// will swtch to forkret.
void
forkret(void)
{
+ struct proc *p = myproc();
+
static int first = 1;
// Still holding ptable.lock from scheduler.
release(&ptable.lock);
+ printf("entering forkret\n");
+
if (first) {
// Some initialization functions must be run in the context
// of a regular process (e.g., they call sleep), and thus cannot
// be run from main().
first = 0;
- iinit(ROOTDEV);
- initlog(ROOTDEV);
+ // XXX riscv
+ //iinit(ROOTDEV);
+ //initlog(ROOTDEV);
}
-
- // Return to "caller", actually trapret (see allocproc).
+
+ usertrapret();
}
// Atomically release lock and sleep on chan.
@@ -483,6 +492,8 @@ wakeup(void *chan)
release(&ptable.lock);
}
+#if 0
+
// Kill the process with the given pid.
// Process won't exit until it returns
// to user space (see trap in trap.c).
@@ -533,12 +544,14 @@ procdump(void)
state = states[p->state];
else
state = "???";
- cprintf("%d %s %s", p->pid, state, p->name);
+ printf("%d %s %s", p->pid, state, p->name);
if(p->state == SLEEPING){
getcallerpcs((uint64*)p->context->rbp+2, pc);
for(i=0; i<10 && pc[i] != 0; i++)
- cprintf(" %p", pc[i]);
+ printf(" %p", pc[i]);
}
- cprintf("\n");
+ printf("\n");
}
}
+
+#endif