swtch saves callee-saved registers

swtch idles on per-CPU stack, not on calling process's stack
fix pipe bugs
usertest.c tests pipes, fork, exit, close
This commit is contained in:
rtm 2006-07-01 21:26:01 +00:00
parent f7cea12b38
commit 8b4e2a08fe
14 changed files with 220 additions and 63 deletions

View File

@ -5,7 +5,7 @@ CC = i386-jos-elf-gcc
LD = i386-jos-elf-ld
OBJCOPY = i386-jos-elf-objcopy
OBJDUMP = i386-jos-elf-objdump
CFLAGS = -nostdinc -I. -O -Wall -MD
CFLAGS = -nostdinc -I. -O2 -Wall -MD
xv6.img : bootblock kernel
dd if=/dev/zero of=xv6.img count=10000

30
fd.c
View File

@ -37,19 +37,6 @@ fd_alloc()
return 0;
}
void
fd_close(struct fd *fd)
{
if(fd->type == FD_CLOSED || fd->count <= 0)
panic("fd_close");
fd->count -= 1;
if(fd->count == 0){
if(fd->type == FD_PIPE)
pipe_close(fd->pipe, fd->writeable);
fd->type = FD_CLOSED;
}
}
/*
* addr is a kernel address, pointing into some process's p->mem.
*/
@ -78,3 +65,20 @@ fd_read(struct fd *fd, char *addr, int n)
return -1;
}
}
void
fd_close(struct fd *fd)
{
if(fd->count < 1 || fd->type == FD_CLOSED)
panic("fd_close");
fd->count -= 1;
if(fd->count == 0){
if(fd->type == FD_PIPE){
pipe_close(fd->pipe, fd->writeable);
} else {
panic("fd_close");
}
fd->type = FD_CLOSED;
}
}

View File

@ -45,10 +45,15 @@ kfree(char *cp, int len)
struct run **rr;
struct run *p = (struct run *) cp;
struct run *pend = (struct run *) (cp + len);
int i;
if(len % PAGE)
panic("kfree");
// XXX fill with junk to help debug
for(i = 0; i < len; i++)
cp[i] = 1;
rr = &freelist;
while(*rr){
struct run *rend = (struct run *) ((char *)(*rr) + (*rr)->len);

2
main.c
View File

@ -46,7 +46,7 @@ main()
p = &proc[0];
curproc[cpu()] = p;
p->state = WAITING;
p->sz = PAGE;
p->sz = 4 * PAGE;
p->mem = kalloc(p->sz);
memset(p->mem, 0, p->sz);
p->kstack = kalloc(KSTACKSIZE);

12
mp.c
View File

@ -6,6 +6,7 @@
#include "x86.h"
#include "traps.h"
#include "mmu.h"
#include "proc.h"
/*
* Credit: Plan 9 sources, Intel MP spec, and Cliff Frey
@ -92,16 +93,11 @@ enum { /* LAPIC_TDCR */
};
#define APBOOTCODE 0x7000 // XXX hack
#define MPSTACK 512
static struct MP* mp; // The MP floating point structure
static uint32_t *lapicaddr;
static struct cpu {
uint8_t apicid; // Local APIC ID
int lintr[2]; // Local APIC
char mpstack[MPSTACK]; // per-cpu start-up stack, only used to get into main()
} cpus[NCPU];
static int ncpu;
struct cpu cpus[NCPU];
int ncpu;
static struct cpu *bcpu;
static int
@ -130,7 +126,7 @@ lapic_timerinit()
void
lapic_timerintr()
{
cprintf("%d: timer interrupt!\n", cpu());
// cprintf("%d: timer interrupt!\n", cpu());
lapic_write (LAPIC_EOI, 0);
}

14
pipe.c
View File

@ -28,6 +28,10 @@ pipe_alloc(struct fd **fd1, struct fd **fd2)
goto oops;
if((p = (struct pipe *) kalloc(PAGE)) == 0)
goto oops;
p->readopen = 1;
p->writeopen = 1;
p->writep = 0;
p->readp = 0;
(*fd1)->type = FD_PIPE;
(*fd1)->readable = 1;
(*fd1)->writeable = 0;
@ -54,10 +58,13 @@ pipe_alloc(struct fd **fd1, struct fd **fd2)
void
pipe_close(struct pipe *p, int writeable)
{
if(writeable)
if(writeable){
p->writeopen = 0;
else
wakeup(&p->readp);
} else {
p->readopen = 0;
wakeup(&p->writep);
}
if(p->readopen == 0 && p->writeopen == 0)
kfree((char *) p, PAGE);
}
@ -71,11 +78,13 @@ pipe_write(struct pipe *p, char *addr, int n)
while(((p->writep + 1) % PIPESIZE) == p->readp){
if(p->readopen == 0)
return -1;
wakeup(&p->readp);
sleep(&p->writep);
}
p->data[p->writep] = addr[i];
p->writep = (p->writep + 1) % PIPESIZE;
}
wakeup(&p->readp);
return i;
}
@ -96,5 +105,6 @@ pipe_read(struct pipe *p, char *addr, int n)
addr[i] = p->data[p->readp];
p->readp = (p->readp + 1) % PIPESIZE;
}
wakeup(&p->writep);
return i;
}

58
proc.c
View File

@ -104,37 +104,47 @@ swtch()
{
struct proc *np;
struct proc *op = curproc[cpu()];
while(1){
np = op + 1;
while(np != op){
if(np->state == RUNNABLE)
break;
np++;
if(np == &proc[NPROC])
np = &proc[0];
}
if(np->state == RUNNABLE)
break;
// cprintf("swtch: nothing to run\n");
release_spinlock(&kernel_lock);
acquire_spinlock(&kernel_lock);
}
// XXX this may be too late, should probably save on the way
// in, in case some other CPU decided to run curproc
// before we got here. in fact setting state=WAITING and
// setting these variables had better be atomic w.r.t. other CPUs.
unsigned sp;
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();
cprintf("cpu %d swtch %x -> %x\n", cpu(), op, np);
// 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;
while(1){
for(i = 0; i < NPROC; i++){
if(np >= &proc[NPROC])
np = &proc[0];
if(np->state == RUNNABLE)
break;
np++;
}
if(i < NPROC)
break;
// cprintf("swtch %d: nothing to run %d %d\n",
// cpu(), proc[1].state, proc[2].state);
release_spinlock(&kernel_lock);
acquire_spinlock(&kernel_lock);
np = &proc[0];
}
cprintf("cpu %d swtch %x -> %x\n", cpu(), curproc[cpu()], np);
curproc[cpu()] = np;
np->state = RUNNING;
// XXX callee-saved registers?
// 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;

11
proc.h
View File

@ -37,3 +37,14 @@ struct proc{
extern struct proc proc[];
extern struct proc *curproc[NCPU];
#define MPSTACK 512
struct cpu {
uint8_t apicid; // Local APIC ID
int lintr[2]; // Local APIC
char mpstack[MPSTACK]; // per-cpu start-up stack, only used to get into main()
};
extern struct cpu cpus[NCPU];
extern int ncpu;

View File

@ -91,7 +91,7 @@ sys_pipe()
int
sys_write()
{
int fd, n;
int fd, n, ret;
unsigned addr;
struct proc *p = curproc[cpu()];
@ -103,13 +103,14 @@ sys_write()
return -1;
if(addr + n > p->sz)
return -1;
return fd_write(p->fds[fd], p->mem + addr, n);
ret = fd_write(p->fds[fd], p->mem + addr, n);
return ret;
}
int
sys_read()
{
int fd, n;
int fd, n, ret;
unsigned addr;
struct proc *p = curproc[cpu()];
@ -121,7 +122,25 @@ sys_read()
return -1;
if(addr + n > p->sz)
return -1;
return fd_read(p->fds[fd], p->mem + addr, n);
ret = fd_read(p->fds[fd], p->mem + addr, n);
return ret;
}
int
sys_close()
{
int fd;
struct proc *p = curproc[cpu()];
if(fetcharg(0, &fd) < 0)
return -1;
if(fd < 0 || fd >= NOFILE)
return -1;
if(p->fds[fd] == 0)
return -1;
fd_close(p->fds[fd]);
p->fds[fd] = 0;
return 0;
}
int
@ -138,6 +157,14 @@ sys_exit()
{
struct proc *p;
struct proc *cp = curproc[cpu()];
int fd;
for(fd = 0; fd < NOFILE; fd++){
if(cp->fds[fd]){
fd_close(cp->fds[fd]);
cp->fds[fd] = 0;
}
}
cp->state = ZOMBIE;
@ -227,6 +254,9 @@ syscall()
case SYS_read:
ret = sys_read();
break;
case SYS_close:
ret = sys_close();
break;
default:
cprintf("unknown sys call %d\n", num);
// XXX fault

View File

@ -5,3 +5,4 @@
#define SYS_pipe 5
#define SYS_write 6
#define SYS_read 7
#define SYS_close 8

16
trap.c
View File

@ -35,16 +35,28 @@ 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);
acquire_spinlock(&kernel_lock); // released in trapret in trapasm.S
if(v == T_SYSCALL){
curproc[cpu()]->tf = tf;
struct proc *cp = curproc[cpu()];
cp->tf = tf;
syscall();
if(cp != curproc[cpu()])
panic("trap ret wrong curproc");
if(cp->state != RUNNING)
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)
panic("trap ret esp wrong");
return;
}
if(v == (IRQ_OFFSET + IRQ_TIMER)){
curproc[cpu()]->tf = tf;
lapic_timerintr();
return;
}

14
ulib.c
View File

@ -5,6 +5,13 @@ fork()
asm("int $48");
}
int
exit()
{
asm("mov $2, %eax");
asm("int $48");
}
void
cons_putc(int c)
{
@ -42,3 +49,10 @@ 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");
}

View File

@ -1,22 +1,48 @@
// simple fork and pipe read/write
char buf[32];
char buf[2048];
void
pipe1()
{
int fds[2], pid;
int seq = 0, i, n, cc, total;
pipe(fds);
pid = pipe();
pid = fork();
if(pid == 0){
write(fds[1], "xyz", 4);
} else {
read(fds[0], buf, sizeof(buf));
if(buf[0] != 'x' || buf[1] != 'y'){
puts("pipe1 oops\n");
return;
close(fds[0]);
for(n = 0; n < 5; n++){
for(i = 0; i < 1033; i++)
buf[i] = seq++;
if(write(fds[1], buf, 1033) != 1033){
puts("pipe1 oops 1\n");
exit(1);
}
}
exit(0);
} else {
close(fds[1]);
total = 0;
cc = 1;
while(1){
n = read(fds[0], buf, cc);
if(n < 1)
break;
for(i = 0; i < n; i++){
if((buf[i] & 0xff) != (seq++ & 0xff)){
puts("pipe1 oops 2\n");
return;
}
}
total += n;
cc = cc * 2;
if(cc > sizeof(buf))
cc = sizeof(buf);
}
if(total != 5 * 1033)
puts("pipe1 oops 3\n");
close(fds[0]);
}
puts("pipe1 ok\n");
}

38
x86.h
View File

@ -244,6 +244,30 @@ read_esp(void)
return esp;
}
static __inline uint32_t
read_esi(void)
{
uint32_t esi;
__asm __volatile("movl %%esi,%0" : "=r" (esi));
return esi;
}
static __inline uint32_t
read_edi(void)
{
uint32_t edi;
__asm __volatile("movl %%edi,%0" : "=r" (edi));
return edi;
}
static __inline uint32_t
read_ebx(void)
{
uint32_t ebx;
__asm __volatile("movl %%ebx,%0" : "=r" (ebx));
return ebx;
}
static __inline void
cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
{
@ -280,6 +304,20 @@ read_tsc(void)
return tsc;
}
// disable interrupts
static __inline void
cli(void)
{
__asm __volatile("cli");
}
// enable interrupts
static __inline void
sti(void)
{
__asm __volatile("sti");
}
struct PushRegs {
/* registers as pushed by pusha */
uint32_t reg_edi;