summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore13
-rw-r--r--Makefile31
-rw-r--r--Notes2
-rw-r--r--console.c2
-rw-r--r--defs.h7
-rwxr-xr-xdot-bochsrc2
-rw-r--r--main.c11
-rw-r--r--mp.c4
-rw-r--r--proc.c83
-rw-r--r--proc.h24
-rw-r--r--spinlock.c21
-rw-r--r--swtch.S37
-rw-r--r--syscall.c3
-rw-r--r--trap.c8
-rw-r--r--trapasm.S5
-rw-r--r--ulib.c56
-rw-r--r--userfs.c1
-rw-r--r--usys.S18
-rw-r--r--x86.h1
19 files changed, 199 insertions, 130 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 0000000..bc713b6
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,13 @@
+*.asm
+*.d
+kernel
+user1
+userfs
+usertests
+xv6.img
+vectors.S
+bochsout.txt
+bootblock
+bootother
+bootother.out
+parport.out
diff --git a/Makefile b/Makefile
index 9221ded..1b2b827 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,18 @@
OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o trap.o vectors.o \
- syscall.o ide.o picirq.o mp.o spinlock.o fd.o pipe.o
+ syscall.o ide.o picirq.o mp.o spinlock.o fd.o pipe.o swtch.o
-CC = i386-jos-elf-gcc
-LD = i386-jos-elf-ld
-OBJCOPY = i386-jos-elf-objcopy
-OBJDUMP = i386-jos-elf-objdump
+# Cross-compiling (e.g., on Mac OS X)
+TOOLPREFIX = i386-jos-elf-
+
+# Using native tools (e.g., on X86 Linux)
+# TOOLPREFIX =
+
+CC = $(TOOLPREFIX)gcc
+LD = $(TOOLPREFIX)ld
+OBJCOPY = $(TOOLPREFIX)objcopy
+OBJDUMP = $(TOOLPREFIX)objdump
CFLAGS = -nostdinc -I. -O2 -Wall -MD
+AS = $(TOOLPREFIX)gas
xv6.img : bootblock kernel
dd if=/dev/zero of=xv6.img count=10000
@@ -31,19 +38,21 @@ kernel : $(OBJS) bootother.S user1 usertests userfs
vectors.S : vectors.pl
perl vectors.pl > vectors.S
-user1 : user1.c ulib.o
+ULIB = ulib.o usys.o
+
+user1 : user1.c $(ULIB)
$(CC) -nostdinc -I. -c user1.c
- $(LD) -N -e main -Ttext 0 -o user1 user1.o ulib.o
+ $(LD) -N -e main -Ttext 0 -o user1 user1.o $(ULIB)
$(OBJDUMP) -S user1 > user1.asm
-usertests : usertests.c ulib.o
+usertests : usertests.c $(ULIB)
$(CC) -nostdinc -I. -c usertests.c
- $(LD) -N -e main -Ttext 0 -o usertests usertests.o ulib.o
+ $(LD) -N -e main -Ttext 0 -o usertests usertests.o $(ULIB)
$(OBJDUMP) -S usertests > usertests.asm
-userfs : userfs.c ulib.o
+userfs : userfs.c $(ULIB)
$(CC) -nostdinc -I. -c userfs.c
- $(LD) -N -e main -Ttext 0 -o userfs userfs.o ulib.o
+ $(LD) -N -e main -Ttext 0 -o userfs userfs.o $(ULIB)
$(OBJDUMP) -S userfs > userfs.asm
ulib.o : ulib.c
diff --git a/Notes b/Notes
index 350d929..63eb0c7 100644
--- a/Notes
+++ b/Notes
@@ -1,5 +1,7 @@
bochs 2.2.6:
./configure --enable-smp --enable-disasm --enable-debugger --enable-all-optimizations --enable-4meg-pages --enable-global-pages --enable-pae --disable-reset-on-triple-fault
+bochs CVS after 2.2.6:
+./configure --enable-smp --enable-disasm --enable-debugger --enable-all-optimizations --enable-4meg-pages --enable-global-pages --enable-pae
bootmain.c doesn't work right if the ELF sections aren't
sector-aligned. so you can't use ld -N. and the sections may also need
diff --git a/console.c b/console.c
index e6203e2..97de59e 100644
--- a/console.c
+++ b/console.c
@@ -106,7 +106,7 @@ cprintf(char *fmt, ...)
if(c == 'd'){
printint(*ap, 10, 1);
ap++;
- } else if(c == 'x'){
+ } else if(c == 'x' || c == 'p'){
printint(*ap, 16, 0);
ap++;
} else if(c == '%'){
diff --git a/defs.h b/defs.h
index f271b59..9e10bee 100644
--- a/defs.h
+++ b/defs.h
@@ -10,11 +10,18 @@ void cons_putc(int);
// proc.c
struct proc;
+struct jmpbuf;
void setupsegs(struct proc *);
struct proc * newproc(void);
void swtch(void);
void sleep(void *);
void wakeup(void *);
+void scheduler(void);
+
+// swtch.S
+struct jmpbuf;
+int setjmp(struct jmpbuf*);
+void longjmp(struct jmpbuf*);
// trap.c
void tvinit(void);
diff --git a/dot-bochsrc b/dot-bochsrc
index 25f24fb..d8afbd6 100755
--- a/dot-bochsrc
+++ b/dot-bochsrc
@@ -107,7 +107,7 @@ romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xf0000
# 650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66 2 to 2.5 Mips
# 400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3 1 to 1.8 Mips
#=======================================================================
-cpu: count=1, ips=10000000
+cpu: count=2, ips=10000000
#=======================================================================
# MEGS
diff --git a/main.c b/main.c
index 563f216..b711640 100644
--- a/main.c
+++ b/main.c
@@ -28,8 +28,7 @@ main()
acquire_spinlock(&kernel_lock);
idtinit(); // CPU's idt
lapic_init(cpu());
- curproc[cpu()] = &proc[0]; // XXX
- swtch();
+ scheduler();
}
acpu = 1;
// clear BSS
@@ -45,7 +44,7 @@ main()
// create fake process zero
p = &proc[0];
- curproc[cpu()] = p;
+ memset(p, 0, sizeof *p);
p->state = WAITING;
p->sz = 4 * PAGE;
p->mem = kalloc(p->sz);
@@ -70,10 +69,10 @@ main()
write_eflags(read_eflags() | FL_IF);
p = newproc();
- // load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size);
+ // load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size);
load_icode(p, _binary_userfs_start, (unsigned) _binary_userfs_size);
-
- swtch();
+ cprintf("loaded userfs\n");
+ scheduler();
return 0;
}
diff --git a/mp.c b/mp.c
index a0d51bf..2b2a612 100644
--- a/mp.c
+++ b/mp.c
@@ -141,8 +141,8 @@ lapic_timerinit()
cprintf("%d: init timer\n", cpu());
lapic_write(LAPIC_TDCR, LAPIC_X1);
lapic_write(LAPIC_TIMER, LAPIC_CLKIN | LAPIC_PERIODIC | (IRQ_OFFSET + IRQ_TIMER));
- lapic_write(LAPIC_TCCR, 1000000);
- lapic_write(LAPIC_TICR, 1000000);
+ lapic_write(LAPIC_TCCR, 10000000);
+ lapic_write(LAPIC_TICR, 10000000);
}
void
diff --git a/proc.c b/proc.c
index 8ad6a23..bdff377 100644
--- a/proc.c
+++ b/proc.c
@@ -48,8 +48,7 @@ struct proc *
newproc()
{
struct proc *np;
- struct proc *op = curproc[cpu()];
- unsigned *sp;
+ struct proc *op;
int fd;
for(np = &proc[1]; np < &proc[NPROC]; np++)
@@ -58,6 +57,11 @@ newproc()
if(np >= &proc[NPROC])
return 0;
+ // copy from proc[0] if we're bootstrapping
+ op = curproc[cpu()];
+ if(op == 0)
+ op = &proc[0];
+
np->pid = next_pid++;
np->ppid = op->pid;
np->sz = op->sz;
@@ -76,11 +80,12 @@ newproc()
np->tf = (struct Trapframe *) (np->kstack + KSTACKSIZE - sizeof(struct Trapframe));
*(np->tf) = *(op->tf);
np->tf->tf_regs.reg_eax = 0; // so fork() returns 0 in child
- sp = (unsigned *) np->tf;
- *(--sp) = (unsigned) &trapret; // for return from swtch()
- *(--sp) = 0; // previous bp for leave in swtch()
- np->esp = (unsigned) sp;
- np->ebp = (unsigned) sp;
+ cprintf("newproc pid=%d return to %x:%x tf-%p\n", np->pid, np->tf->tf_cs, np->tf->tf_eip, np->tf);
+
+ // set up new jmpbuf to start executing at trapret with esp pointing at tf
+ memset(&np->jmpbuf, 0, sizeof np->jmpbuf);
+ np->jmpbuf.jb_eip = (unsigned) trapret;
+ np->jmpbuf.jb_esp = (unsigned) np->tf - 4; // -4 for the %eip that isn't actually there
// copy file descriptors
for(fd = 0; fd < NOFILE; fd++){
@@ -96,33 +101,20 @@ newproc()
return np;
}
-/*
- * find a runnable process and switch to it.
- */
void
-swtch()
+scheduler(void)
{
- struct proc *np;
- struct proc *op = curproc[cpu()];
- unsigned sp;
+ struct proc *op, *np;
int i;
- // force push of callee-saved registers
- asm volatile("nop" : : : "%edi", "%esi", "%ebx");
-
- // save calling process's stack pointers
- op->ebp = read_ebp();
- op->esp = read_esp();
-
- // don't execute on calling process's stack
- sp = (unsigned) cpus[cpu()].mpstack + MPSTACK - 32;
- asm volatile("movl %0, %%esp" : : "g" (sp));
- asm volatile("movl %0, %%ebp" : : "g" (sp));
-
- // gcc might store op on the stack
- np = curproc[cpu()];
- np = np + 1;
+ cprintf("start scheduler on cpu %d jmpbuf %p\n", cpu(), &cpus[cpu()].jmpbuf);
+ cpus[cpu()].lastproc = &proc[0];
+ setjmp(&cpus[cpu()].jmpbuf);
+
+ // find a runnable process and switch to it
+ curproc[cpu()] = 0;
+ np = cpus[cpu()].lastproc + 1;
while(1){
for(i = 0; i < NPROC; i++){
if(np >= &proc[NPROC])
@@ -139,34 +131,47 @@ swtch()
acquire_spinlock(&kernel_lock);
np = &proc[0];
}
-
- cprintf("cpu %d swtch %x -> %x\n", cpu(), curproc[cpu()], np);
+ cpus[cpu()].lastproc = np;
curproc[cpu()] = np;
+
np->state = RUNNING;
// h/w sets busy bit in TSS descriptor sometimes, and faults
// if it's set in LTR. so clear tss descriptor busy bit.
np->gdt[SEG_TSS].sd_type = STS_T32A;
+ // XXX should probably have an lgdt() function in x86.h
+ // to confine all the inline assembly.
// XXX probably ought to lgdt on trap return too, in case
// a system call has moved a program or changed its size.
-
asm volatile("lgdt %0" : : "g" (np->gdt_pd.pd_lim));
ltr(SEG_TSS << 3);
- // this happens to work, but probably isn't safe:
- // it's not clear that np->ebp is guaranteed to evaluate
- // correctly after changing the stack pointer.
- asm volatile("movl %0, %%esp" : : "g" (np->esp));
- asm volatile("movl %0, %%ebp" : : "g" (np->ebp));
+ if(0) cprintf("cpu%d: run %d esp=%p callerpc=%p\n", cpu(), np-proc);
+ longjmp(&np->jmpbuf);
+}
+
+// give up the cpu by switching to the scheduler,
+// which runs on the per-cpu stack.
+void
+swtch(void)
+{
+ struct proc *p = curproc[cpu()];
+ if(p == 0)
+ panic("swtch");
+ if(setjmp(&p->jmpbuf) == 0)
+ longjmp(&cpus[cpu()].jmpbuf);
}
void
sleep(void *chan)
{
- curproc[cpu()]->chan = chan;
- curproc[cpu()]->state = WAITING;
+ struct proc *p = curproc[cpu()];
+ if(p == 0)
+ panic("sleep");
+ p->chan = chan;
+ p->state = WAITING;
swtch();
}
diff --git a/proc.h b/proc.h
index 0c748aa..b5cf015 100644
--- a/proc.h
+++ b/proc.h
@@ -16,6 +16,23 @@
#define SEG_TSS 5 // this process's task state
#define NSEGS 6
+struct jmpbuf {
+ // saved registers for kernel context switches
+ // don't need to save all the fs etc. registers because
+ // they are constant across kernel contexts
+ // save all the regular registers so we don't care which are caller save
+ // don't save eax because that's the return register
+ // layout known to swtch.S
+ int jb_ebx;
+ int jb_ecx;
+ int jb_edx;
+ int jb_esi;
+ int jb_edi;
+ int jb_esp;
+ int jb_ebp;
+ int jb_eip;
+};
+
struct proc{
char *mem; // start of process's physical memory
unsigned sz; // total size of mem, including kernel stack
@@ -32,17 +49,22 @@ struct proc{
unsigned esp; // kernel stack pointer
unsigned ebp; // kernel frame pointer
+ struct jmpbuf jmpbuf;
+
struct Trapframe *tf; // points into kstack, used to find user regs
};
extern struct proc proc[];
-extern struct proc *curproc[NCPU];
+extern struct proc *curproc[NCPU]; // can be NULL if no proc running.
+ // XXX move curproc into cpu structure?
#define MPSTACK 512
struct cpu {
uint8_t apicid; // Local APIC ID
+ struct jmpbuf jmpbuf;
char mpstack[MPSTACK]; // per-cpu start-up stack, only used to get into main()
+ struct proc *lastproc; // last proc scheduled on this cpu (never NULL)
};
extern struct cpu cpus[NCPU];
diff --git a/spinlock.c b/spinlock.c
index 2d64044..8d40258 100644
--- a/spinlock.c
+++ b/spinlock.c
@@ -4,31 +4,39 @@
#include "mmu.h"
#define LOCK_FREE -1
+#define DEBUG 0
uint32_t kernel_lock = LOCK_FREE;
+int getcallerpc(void *v) {
+ return ((int*)v)[-1];
+}
+
// lock = LOCK_FREE if free, else = cpu_id of owner CPU
-void
+void
acquire_spinlock(uint32_t* lock)
{
int cpu_id = cpu();
+ // on a real machine there would be a memory barrier here
+ if(DEBUG) cprintf("cpu%d: acquiring at %x\n", cpu_id, getcallerpc(&lock));
+ write_eflags(read_eflags() & ~FL_IF);
if (*lock == cpu_id)
- return;
+ panic("recursive lock");
- write_eflags(read_eflags() & ~FL_IF);
while ( cmpxchg(LOCK_FREE, cpu_id, lock) != cpu_id ) { ; }
- // cprintf ("acquired: %d\n", cpu_id);
+ if(DEBUG) cprintf("cpu%d: acquired at %x\n", cpu_id, getcallerpc(&lock));
}
void
release_spinlock(uint32_t* lock)
{
int cpu_id = cpu();
- // cprintf ("release: %d\n", cpu_id);
+ if(DEBUG) cprintf ("cpu%d: releasing at %x\n", cpu_id, getcallerpc(&lock));
if (*lock != cpu_id)
panic("release_spinlock: releasing a lock that i don't own\n");
*lock = LOCK_FREE;
+ // on a real machine there would be a memory barrier here
write_eflags(read_eflags() | FL_IF);
}
@@ -36,8 +44,9 @@ void
release_grant_spinlock(uint32_t* lock, int c)
{
int cpu_id = cpu();
- // cprintf ("release_grant: %d -> %d\n", cpu_id, c);
+ if(DEBUG) cprintf ("cpu%d: release_grant to %d at %x\n", cpu_id, c, getcallerpc(&lock));
if (*lock != cpu_id)
panic("release_spinlock: releasing a lock that i don't own\n");
*lock = c;
}
+
diff --git a/swtch.S b/swtch.S
new file mode 100644
index 0000000..7b42dc7
--- /dev/null
+++ b/swtch.S
@@ -0,0 +1,37 @@
+.globl setjmp
+setjmp:
+ movl 4(%esp), %eax
+
+ movl %ebx, 0(%eax)
+ movl %ecx, 4(%eax)
+ movl %edx, 8(%eax)
+ movl %esi, 12(%eax)
+ movl %edi, 16(%eax)
+ movl %esp, 20(%eax)
+ movl %ebp, 24(%eax)
+ pushl 0(%esp) /* %eip */
+ popl 28(%eax)
+
+ movl $0, %eax /* return value */
+ ret
+
+.globl longjmp
+longjmp:
+ movl 4(%esp), %eax
+
+ movl 0(%eax), %ebx
+ movl 4(%eax), %ecx
+ movl 8(%eax), %edx
+ movl 12(%eax), %esi
+ movl 16(%eax), %edi
+ movl 20(%eax), %esp
+ movl 24(%eax), %ebp
+
+ addl $4, %esp /* pop %eip into thin air */
+ pushl 28(%eax) /* push new %eip */
+
+ movl $1, %eax /* return value (appears to come from setjmp!) */
+ ret
+
+
+
diff --git a/syscall.c b/syscall.c
index 787eb64..03fe608 100644
--- a/syscall.c
+++ b/syscall.c
@@ -39,7 +39,7 @@ fetcharg(int argno, int *ip)
unsigned esp;
esp = (unsigned) curproc[cpu()]->tf->tf_esp;
- return fetchint(curproc[cpu()], esp + 8 + 4*argno, ip);
+ return fetchint(curproc[cpu()], esp + 4 + 4*argno, ip);
}
int
@@ -178,6 +178,7 @@ sys_exit()
if(p->ppid == cp->pid)
p->pid = 1;
+ // switch into scheduler
swtch();
return 0;
diff --git a/trap.c b/trap.c
index 6b490b1..d177d04 100644
--- a/trap.c
+++ b/trap.c
@@ -36,13 +36,15 @@ trap(struct Trapframe *tf)
int v = tf->tf_trapno;
if(tf->tf_cs == 0x8 && kernel_lock == cpu())
- cprintf("cpu %d: trap from %x:%x with lock=%d\n",
- cpu(), tf->tf_cs, tf->tf_eip, kernel_lock);
+ cprintf("cpu %d: trap %d from %x:%x with lock=%d\n",
+ cpu(), v, tf->tf_cs, tf->tf_eip, kernel_lock);
acquire_spinlock(&kernel_lock); // released in trapret in trapasm.S
if(v == T_SYSCALL){
struct proc *cp = curproc[cpu()];
+ if(cp == 0)
+ panic("syscall with no proc");
cp->tf = tf;
syscall();
if(cp != curproc[cpu()])
@@ -51,7 +53,7 @@ trap(struct Trapframe *tf)
panic("trap ret but not RUNNING");
if(tf != cp->tf)
panic("trap ret wrong tf");
- if(read_esp() < cp->kstack || read_esp() >= cp->kstack + KSTACKSIZE)
+ if(read_esp() < (unsigned)cp->kstack || read_esp() >= (unsigned)cp->kstack + KSTACKSIZE)
panic("trap ret esp wrong");
return;
}
diff --git a/trapasm.S b/trapasm.S
index 4ae023d..4494642 100644
--- a/trapasm.S
+++ b/trapasm.S
@@ -22,9 +22,10 @@ alltraps:
* expects ESP to point to a Trapframe
*/
trapret:
- push $kernel_lock
+ pushl $kernel_lock
call release_spinlock
- addl $4, %esp
+ addl $0x4, %esp
+
popal
popl %es
popl %ds
diff --git a/ulib.c b/ulib.c
index 5061732..543323c 100644
--- a/ulib.c
+++ b/ulib.c
@@ -1,25 +1,4 @@
int
-fork()
-{
- asm("mov $1, %eax");
- asm("int $48");
-}
-
-int
-exit()
-{
- asm("mov $2, %eax");
- asm("int $48");
-}
-
-void
-cons_putc(int c)
-{
- asm("mov $4, %eax");
- asm("int $48");
-}
-
-int
puts(char *s)
{
int i;
@@ -29,38 +8,3 @@ puts(char *s)
return i;
}
-int
-pipe(int fds[])
-{
- asm("mov $5, %eax");
- asm("int $48");
-}
-
-int
-read(int fd, char *buf, int n)
-{
- asm("mov $7, %eax");
- asm("int $48");
-}
-
-int
-write(int fd, char *buf, int n)
-{
- asm("mov $6, %eax");
- asm("int $48");
-}
-
-int
-close(int fd)
-{
- asm("mov $8, %eax");
- asm("int $48");
-}
-
-int
-block(void)
-{
- asm("mov $9, %eax");
- asm("int $48");
-}
-
diff --git a/userfs.c b/userfs.c
index 93e42df..5de90e6 100644
--- a/userfs.c
+++ b/userfs.c
@@ -4,5 +4,6 @@ char buf[1024];
main()
{
+ puts("userfs running\n");
block();
}
diff --git a/usys.S b/usys.S
new file mode 100644
index 0000000..c399d62
--- /dev/null
+++ b/usys.S
@@ -0,0 +1,18 @@
+#include "syscall.h"
+#include "traps.h"
+
+#define STUB(name) \
+ .globl name; \
+ name: \
+ movl $SYS_ ## name, %eax; \
+ int $T_SYSCALL; \
+ ret
+
+STUB(fork)
+STUB(exit)
+STUB(cons_putc)
+STUB(pipe)
+STUB(read)
+STUB(write)
+STUB(close)
+STUB(block)
diff --git a/x86.h b/x86.h
index 451f789..80a4130 100644
--- a/x86.h
+++ b/x86.h
@@ -349,7 +349,6 @@ struct Trapframe {
uint16_t tf_padding4;
};
-
#define MAX_IRQS 16 // Number of IRQs
#define IRQ_OFFSET 32 // IRQ 0 corresponds to int IRQ_OFFSET