summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--defs.h8
-rw-r--r--main.c42
-rw-r--r--memlayout.h8
-rw-r--r--proc.c5
-rw-r--r--proc.h5
-rw-r--r--spinlock.c95
-rw-r--r--spinlock.h2
-rw-r--r--start.c14
-rw-r--r--trap.c10
-rw-r--r--vm.c8
11 files changed, 95 insertions, 104 deletions
diff --git a/Makefile b/Makefile
index 38ec5c7..1e45056 100644
--- a/Makefile
+++ b/Makefile
@@ -182,7 +182,7 @@ QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \
then echo "-gdb tcp::$(GDBPORT)"; \
else echo "-s -p $(GDBPORT)"; fi)
ifndef CPUS
-CPUS := 1
+CPUS := 2
endif
QEMUOPTS = -machine virt -kernel kernel -m 3G -smp $(CPUS) -nographic
QEMUOPTS += -initrd fs.img
diff --git a/defs.h b/defs.h
index 0e8cb52..2353e4a 100644
--- a/defs.h
+++ b/defs.h
@@ -130,12 +130,11 @@ void swtch(struct context*, struct context*);
// spinlock.c
void acquire(struct spinlock*);
-void getcallerpcs(void*, uint64*);
int holding(struct spinlock*);
void initlock(struct spinlock*, char*);
void release(struct spinlock*);
-void pushcli(void);
-void popcli(void);
+void push_off(void);
+void pop_off(void);
// sleeplock.c
void acquiresleep(struct sleeplock*);
@@ -168,6 +167,7 @@ void timerinit(void);
// trap.c
extern uint ticks;
void trapinit(void);
+void trapinithart(void);
extern struct spinlock tickslock;
void usertrapret(void);
@@ -179,6 +179,7 @@ int uartgetc(void);
// vm.c
void kvminit(void);
+void kvminithart(void);
pagetable_t uvmcreate(void);
void uvminit(pagetable_t, char *, uint);
uint64 uvmalloc(pagetable_t, uint64, uint64);
@@ -194,6 +195,7 @@ int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64
// plic.c
void plicinit(void);
+void plicinithart(void);
uint64 plic_pending(void);
int plic_claim(void);
void plic_complete(int);
diff --git a/main.c b/main.c
index 24793cd..2168b9f 100644
--- a/main.c
+++ b/main.c
@@ -4,25 +4,39 @@
#include "riscv.h"
#include "defs.h"
+volatile static int started = 0;
+
// Bootstrap processor starts running C code here.
// Allocate a real stack and switch to it, first
// doing some setup required for memory allocator to work.
void
-main(int hartid)
+main()
{
- w_tp(hartid); // save hartid where cpuid() can find it
- uartinit(); // serial port
- consoleinit();
- printf("entering main() on hart %d\n", hartid);
- kinit(); // physical page allocator
- kvminit(); // kernel page table
- procinit(); // process table
- trapinit(); // trap vectors
- plicinit(); // set up interrupt controller
- binit(); // buffer cache
- fileinit(); // file table
- ramdiskinit(); // disk
- userinit(); // first user process
+ if(cpuid() == 0){
+ uartinit(); // serial port
+ consoleinit();
+ printf("hart %d starting\n", cpuid());
+ kinit(); // physical page allocator
+ kvminit(); // create kernel page table
+ kvminithart(); // turn on paging
+ procinit(); // process table
+ trapinit(); // trap vectors
+ trapinithart(); // install kernel trap vector
+ plicinit(); // set up interrupt controller
+ plicinithart(); // ask PLIC for device interrupts
+ binit(); // buffer cache
+ fileinit(); // file table
+ ramdiskinit(); // disk
+ userinit(); // first user process
+ started = 1;
+ } else {
+ while(started == 0)
+ ;
+ printf("hart %d starting\n", cpuid());
+ kvminithart(); // turn on paging
+ trapinithart(); // install kernel trap vector
+ plicinithart(); // ask PLIC for device interrupts
+ }
scheduler();
}
diff --git a/memlayout.h b/memlayout.h
index 9c9cfdb..462986c 100644
--- a/memlayout.h
+++ b/memlayout.h
@@ -28,6 +28,14 @@
// qemu puts programmable interrupt controller here.
#define PLIC 0x0c000000L
+#define PLIC_PRIORITY (PLIC + 0x0)
+#define PLIC_PENDING (PLIC + 0x1000)
+#define PLIC_MENABLE(hart) (PLIC + 0x2000 + (hart)*0x100)
+#define PLIC_SENABLE(hart) (PLIC + 0x2080 + (hart)*0x100)
+#define PLIC_MPRIORITY(hart) (PLIC + 0x200000 + (hart)*0x2000)
+#define PLIC_SPRIORITY(hart) (PLIC + 0x201000 + (hart)*0x2000)
+#define PLIC_MCLAIM(hart) (PLIC + 0x200004 + (hart)*0x2000)
+#define PLIC_SCLAIM(hart) (PLIC + 0x201004 + (hart)*0x2000)
#define RAMDISK 0x88000000L
diff --git a/proc.c b/proc.c
index 766fd93..28cac26 100644
--- a/proc.c
+++ b/proc.c
@@ -360,7 +360,7 @@ scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
-
+
c->proc = 0;
for(;;){
// Enable interrupts on this processor.
@@ -385,7 +385,6 @@ scheduler(void)
c->proc = 0;
}
release(&ptable.lock);
-
}
}
@@ -393,7 +392,7 @@ scheduler(void)
// and have changed proc->state. Saves and restores
// intena because intena is a property of this
// kernel thread, not this CPU. It should
-// be proc->intena and proc->ncli, but that would
+// be proc->intena and proc->noff, but that would
// break in the few places where a lock is held but
// there's no process.
void
diff --git a/proc.h b/proc.h
index 00a1cb9..278e4cd 100644
--- a/proc.h
+++ b/proc.h
@@ -22,9 +22,8 @@ struct context {
struct cpu {
struct proc *proc; // The process running on this cpu or null
struct context scheduler; // swtch() here to enter scheduler
- volatile uint started; // Has the CPU started?
- int ncli; // Depth of pushcli nesting.
- int intena; // Were interrupts enabled before pushcli?
+ int noff; // Depth of push_off() nesting.
+ int intena; // Were interrupts enabled before push_off()?
};
extern struct cpu cpus[NCPU];
diff --git a/spinlock.c b/spinlock.c
index 0377870..8b3c3f0 100644
--- a/spinlock.c
+++ b/spinlock.c
@@ -5,6 +5,7 @@
#include "memlayout.h"
#include "spinlock.h"
#include "riscv.h"
+#include "proc.h"
#include "defs.h"
void
@@ -15,27 +16,6 @@ initlock(struct spinlock *lk, char *name)
lk->cpu = 0;
}
-void
-acquire(struct spinlock *lk)
-{
- lk->locked = 1;
- lk->cpu = mycpu();
-}
-
-void
-release(struct spinlock *lk)
-{
- lk->locked = 0;
- lk->cpu = 0;
-}
-
-int
-holding(struct spinlock *lk)
-{
- return lk->locked && lk->cpu == mycpu();
-}
-
-#if 0
// Acquire the lock.
// Loops (spins) until the lock is acquired.
// Holding a lock for a long time may cause
@@ -43,12 +23,14 @@ holding(struct spinlock *lk)
void
acquire(struct spinlock *lk)
{
- pushcli(); // disable interrupts to avoid deadlock.
+ push_off(); // disable interrupts to avoid deadlock.
if(holding(lk))
panic("acquire");
// The xchg is atomic.
- while(xchg(&lk->locked, 1) != 0)
+ //while(xchg(&lk->locked, 1) != 0)
+ // ;
+ while(__sync_lock_test_and_set(&lk->locked, 1) != 0)
;
// Tell the C compiler and the processor to not move loads or stores
@@ -58,7 +40,6 @@ acquire(struct spinlock *lk)
// Record info about lock acquisition for holding() and debugging.
lk->cpu = mycpu();
- getcallerpcs(&lk, lk->pcs);
}
// Release the lock.
@@ -68,7 +49,6 @@ release(struct spinlock *lk)
if(!holding(lk))
panic("release");
- lk->pcs[0] = 0;
lk->cpu = 0;
// Tell the C compiler and the processor to not move loads or stores
@@ -81,27 +61,10 @@ release(struct spinlock *lk)
// Release the lock, equivalent to lk->locked = 0.
// This code can't use a C assignment, since it might
// not be atomic. A real OS would use C atomics here.
- asm volatile("movl $0, %0" : "+m" (lk->locked) : );
+ //asm volatile("movl $0, %0" : "+m" (lk->locked) : );
+ __sync_lock_release(&lk->locked);
- popcli();
-}
-
-// Record the current call stack in pcs[] by following the %ebp chain.
-void
-getcallerpcs(void *v, uint64 pcs[])
-{
- uint64 *ebp;
- int i;
-
- asm volatile("mov %%rbp, %0" : "=r" (ebp));
- for(i = 0; i < 10; i++){
- if(ebp == 0 || ebp < (uint64*)KERNBASE || ebp == (uint64*)0xffffffff)
- break;
- pcs[i] = ebp[1]; // saved %eip
- ebp = (uint64*)ebp[0]; // saved %ebp
- }
- for(; i < 10; i++)
- pcs[i] = 0;
+ pop_off();
}
// Check whether this cpu is holding the lock.
@@ -109,37 +72,37 @@ int
holding(struct spinlock *lk)
{
int r;
- pushcli();
+ push_off();
r = lk->locked && lk->cpu == mycpu();
- popcli();
+ pop_off();
return r;
}
-
-// Pushcli/popcli are like cli/sti except that they are matched:
-// it takes two popcli to undo two pushcli. Also, if interrupts
-// are off, then pushcli, popcli leaves them off.
+// 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
+// are initially off, then push_off, pop_off leaves them off.
void
-pushcli(void)
+push_off(void)
{
- int eflags;
+ struct cpu *c = mycpu();
+ int old = intr_get();
- eflags = readeflags();
- cli();
- if(mycpu()->ncli == 0)
- mycpu()->intena = eflags & FL_IF;
- mycpu()->ncli += 1;
+ intr_off();
+ if(c->noff == 0)
+ c->intena = old;
+ c->noff += 1;
}
void
-popcli(void)
+pop_off(void)
{
- if(readeflags()&FL_IF)
- panic("popcli - interruptible");
- if(--mycpu()->ncli < 0)
- panic("popcli");
- if(mycpu()->ncli == 0 && mycpu()->intena)
- sti();
+ struct cpu *c = mycpu();
+ if(intr_get())
+ panic("pop_off - interruptible");
+ c->noff -= 1;
+ if(c->noff < 0)
+ panic("pop_off");
+ if(c->noff == 0 && c->intena)
+ intr_on();
}
-#endif
diff --git a/spinlock.h b/spinlock.h
index 90bffdb..4392820 100644
--- a/spinlock.h
+++ b/spinlock.h
@@ -5,7 +5,5 @@ struct spinlock {
// For debugging:
char *name; // Name of lock.
struct cpu *cpu; // The cpu holding the lock.
- uint64 pcs[10]; // The call stack (an array of program counters)
- // that locked the lock.
};
diff --git a/start.c b/start.c
index 53edb8e..ce22be8 100644
--- a/start.c
+++ b/start.c
@@ -9,12 +9,12 @@ void main();
// entry.S needs one stack per CPU.
__attribute__ ((aligned (16))) char stack0[4096 * NCPU];
-// assembly code in kernelvec for machine-mode timer interrupt.
-extern void machinevec();
-
// scratch area for timer interrupt, one per CPU.
uint64 mscratch0[NCPU * 32];
+// assembly code in kernelvec for machine-mode timer interrupt.
+extern void machinevec();
+
// entry.S jumps here in machine mode on stack0.
void
mstart()
@@ -48,7 +48,9 @@ mstart()
w_mstatus(r_mstatus() | MSTATUS_MIE);
w_mie(r_mie() | MIE_MTIE);
- // call main(hartid) in supervisor mode.
- asm("csrr a0, mhartid ; \
- mret");
+ // keep each CPU's hartid in its tp register, for cpuid().
+ w_tp(id);
+
+ // call main() in supervisor mode.
+ asm("mret");
}
diff --git a/trap.c b/trap.c
index 693c596..929f761 100644
--- a/trap.c
+++ b/trap.c
@@ -19,12 +19,14 @@ extern int devintr();
void
trapinit(void)
{
- int i;
+ initlock(&tickslock, "time");
+}
- // set up to take exceptions and traps while in the kernel.
+// set up to take exceptions and traps while in the kernel.
+void
+trapinithart(void)
+{
w_stvec((uint64)kernelvec);
-
- initlock(&tickslock, "time");
}
//
diff --git a/vm.c b/vm.c
index b24b271..1d3887a 100644
--- a/vm.c
+++ b/vm.c
@@ -54,9 +54,13 @@ kvminit()
// the highest virtual address in the kernel.
mappages(kernel_pagetable, TRAMPOLINE, PGSIZE,
(uint64)trampout, PTE_R | PTE_X);
+}
- // Switch h/w page table register to the kernel's page table,
- // and enable paging.
+// Switch h/w page table register to the kernel's page table,
+// and enable paging.
+void
+kvminithart()
+{
w_satp(MAKE_SATP(kernel_pagetable));
}