diff options
| author | rtm <rtm> | 2006-08-15 22:18:20 +0000 | 
|---|---|---|
| committer | rtm <rtm> | 2006-08-15 22:18:20 +0000 | 
| commit | 350e63f7a9b1be695c0cf69e380bd96733524f25 (patch) | |
| tree | 782259566c4596eef115590ff3e054fc7c5f3718 | |
| parent | 69332d1918fda38b25fc3ec8c786d16bb17e9e68 (diff) | |
| download | xv6-labs-350e63f7a9b1be695c0cf69e380bd96733524f25.tar.gz xv6-labs-350e63f7a9b1be695c0cf69e380bd96733524f25.tar.bz2 xv6-labs-350e63f7a9b1be695c0cf69e380bd96733524f25.zip | |
no more proc[] entry per cpu for idle loop
each cpu[] has its own gdt and tss
no per-proc gdt or tss, re-write cpu's in scheduler (you win, cliff)
main0() switches to cpu[0].mpstack
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | Notes | 285 | ||||
| -rw-r--r-- | fstests.c | 380 | ||||
| -rw-r--r-- | main.c | 23 | ||||
| -rw-r--r-- | proc.c | 69 | ||||
| -rw-r--r-- | proc.h | 4 | ||||
| -rw-r--r-- | trap.c | 7 | ||||
| -rw-r--r-- | usertests.c | 294 | 
8 files changed, 456 insertions, 616 deletions
| @@ -67,6 +67,10 @@ usertests : usertests.o $(ULIB)  	$(LD) -N -e main -Ttext 0 -o usertests usertests.o $(ULIB)  	$(OBJDUMP) -S usertests > usertests.asm +fstests : fstests.o $(ULIB) +	$(LD) -N -e main -Ttext 0 -o fstests fstests.o $(ULIB) +	$(OBJDUMP) -S fstests > fstests.asm +  echo : echo.o $(ULIB)  	$(LD) -N -e main -Ttext 0 -o echo echo.o $(ULIB)  	$(OBJDUMP) -S echo > echo.asm @@ -102,12 +106,12 @@ rm : rm.o $(ULIB)  mkfs : mkfs.c fs.h  	cc -o mkfs mkfs.c -fs.img : mkfs userfs usertests echo cat readme init sh ls mkdir rm -	./mkfs fs.img userfs usertests echo cat readme init sh ls mkdir rm +fs.img : mkfs userfs usertests echo cat readme init sh ls mkdir rm fstests +	./mkfs fs.img userfs usertests echo cat readme init sh ls mkdir rm fstests  -include *.d  clean :   	rm -f *.o *.d *.asm vectors.S parport.out \  		bootblock kernel xv6.img user1 userfs usertests \ -		fs.img mkfs echo init +		fs.img mkfs echo init fstests @@ -22,32 +22,14 @@ no kernel malloc(), just kalloc() for user core  user pointers aren't valid in the kernel -setting up first process -  we do want a process zero, as template -    but not runnable -  just set up return-from-trap frame on new kernel stack -  fake user program that calls exec - -map text read-only? -shared text? - -what's on the stack during a trap or sys call? -  PUSHA before scheduler switch? for callee-saved registers. -  segment contents? -  what does iret need to get out of the kernel? -  how does INT know what kernel stack to use? -  -are interrupts turned on in the kernel? probably. - -per-cpu curproc -one tss per process, or one per cpu? -one segment array per cpu, or per process? +are interrupts turned on in the kernel? yes.  pass curproc explicitly, or implicit from cpu #?    e.g. argument to newproc()?    hmm, you need a global curproc[cpu] for trap() &c -test stack expansion +no stack expansion +  test running out of memory, process slots  we can't really use a separate stack segment, since stack addresses @@ -56,16 +38,6 @@ data vs text. how can we have a gap between data and stack, so that  both can grow, without committing 4GB of physical memory? does this  mean we need paging? -what's the simplest way to add the paging we need? -  one page table, re-write it each time we leave the kernel? -  page table per process? -  probably need to use 0-0xffffffff segments, so that -    both data and stack pointers always work -  so is it now worth it to make a process's phys mem contiguous? -  or could use segment limits and 4 meg pages? -    but limits would prevent using stack pointers as data pointers -  how to write-protect text? not important? -  perhaps have fixed-size stack, put it in the data segment?  oops, if kernel stack is in contiguous user phys mem, then moving @@ -87,19 +59,6 @@ test children being inherited by grandparent &c  some sleep()s should be interruptible by kill() -cli/sti in acquire/release should nest! -  in case you acquire two locks - -what would need fixing if we got rid of kernel_lock? -  console output -  proc_exit() needs lock on proc *array* to deallocate -  kill() needs lock on proc *array* -  allocator's free list -  global fd table (really free-ness) -  sys_close() on fd table -  fork on proc list, also next pid -    hold lock until public slots in proc struct initialized -  locks    init_lock      sequences CPU startup @@ -110,37 +69,17 @@ locks    memory allocator    printf -wakeup needs proc_table_lock -  so we need recursive locks? -  or you must hold the lock to call wakeup? -  in general, the table locks protect both free-ness and    public variables of table elements    in many cases you can use table elements w/o a lock    e.g. if you are the process, or you are using an fd -lock code shouldn't call cprintf... - -nasty hack to allow locks before first process, -  and to allow them in interrupts when curproc may be zero - -race between release and sleep in sys_wait() -race between sys_exit waking up parent and setting state=ZOMBIE -race in pipe code when full/empty -  lock order    per-pipe lock    proc_table_lock fd_table_lock kalloc_lock    console_lock -condition variable + mutex that protects it -  proc * (for wait()), proc_table_lock -  pipe structure, pipe lock - -systematic way to test sleep races? -  print something at the start of sleep? - -do you have to be holding the mutex in order to call wakeup()? +do you have to be holding the mutex in order to call wakeup()? yes  device interrupts don't clear FL_IF    so a recursive timer interrupt is possible @@ -156,202 +95,11 @@ inode->count counts in-memory pointers to the struct  blocks and inodes have ad-hoc sleep-locks    provide a single mechanism? -need to lock bufs in bio between bread and brelse -  test 14-character file names  and file arguments longer than 14 -and directories longer than one sector  kalloc() can return 0; do callers handle this right? -why directing interrupts to cpu 1 causes trouble -  cpu 1 turns on interrupts with no tss! -    and perhaps a stale gdt (from boot) -  since it has never run a process, never called setupsegs() -  but does cpu really need the tss? -    not switching stacks -  fake process per cpu, just for tss? -    seems like a waste -  move tss to cpu[]? -    but tss points to per-process kernel stack -    would also give us a gdt -  OOPS that wasn't the problem - -wait for other cpu to finish starting before enabling interrupts? -  some kind of crash in ide_init ioapic_enable cprintf -move ide_init before mp_start? -  didn't do any good -  maybe cpu0 taking ide interrupt, cpu1 getting a nested lock error - -cprintfs are screwed up if locking is off -  often loops forever -  hah, just use lpt alone - -looks like cpu0 took the ide interrupt and was the last to hold -the lock, but cpu1 thinks it is nested -cpu0 is in load_icode / printf / cons_putc -  probably b/c cpu1 cleared use_console_lock -cpu1 is in scheduler() / printf / acquire - -  1: init timer -  0: init timer -  cpu 1 initial nlock 1 -  ne0s:t iidd el_occnkt rc -  onsole cpu 1 old caller stack 1001A5 10071D 104DFF 1049FE -  panic: acquire -  ^CNext at t=33002418 -  (0) [0x00100091] 0008:0x00100091 (unk. ctxt): jmp .+0xfffffffe          ; ebfe -  (1) [0x00100332] 0008:0x00100332 (unk. ctxt): jmp .+0xfffffffe           -   -why is output interleaved even before panic? - -does release turn on interrupts even inside an interrupt handler? - -overflowing cpu[] stack? -  probably not, change from 512 to 4096 didn't do anything - - -  1: init timer -  0: init timer -  cnpeus te11  linnitki aclo nnoolleek  cp1u -   ss  oarltd  sccahleldeul esrt aocnk  cpu 0111 Ej6  buf1 01A3140 C5118  -  0 -  la anic1::7 0a0c0  uuirr e -  ^CNext at t=31691050 -  (0) [0x00100373] 0008:0x00100373 (unk. ctxt): jmp .+0xfffffffe          ; ebfe -  (1) [0x00100091] 0008:0x00100091 (unk. ctxt): jmp .+0xfffffffe          ; ebfe - -cpu0: - -0: init timer -nested lock console cpu 0 old caller stack 1001e6 101a34 1 0 -  (that's mpmain) -panic: acquire - -cpu1: - -1: init timer -cpu 1 initial nlock 1 -start scheduler on cpu 1 jmpbuf ... -la 107000 lr ... -  that is, nlock != 0 - -maybe a race; acquire does -  locked = 1 -  cpu = cpu() -what if another acquire calls holding w/ locked = 1 but -  before cpu is set? - -if I type a lot (kbd), i get a panic -cpu1 in scheduler: panic "holding locks in scheduler" -cpu0 also in the same panic! -recursive interrupt? -  FL_IF is probably set during interrupt... is that correct? -again: -  olding locks in scheduler -  trap v 33 eip 100ED3 c (that is, interrupt while holding a lock) -  100ed3 is in lapic_write -again: -  trap v 33 eip 102A3C cpu 1 nlock 1 (in acquire) -  panic: interrupt while holding a lock -again: -  trap v 33 eip 102A3C cpu 1 nlock 1 -  panic: interrupt while holding a lock -OR is it the cprintf("kbd overflow")? -  no, get panic even w/o that cprintf -OR a release() at interrupt time turns interrupts back on? -  of course i don't think they were off... -OK, fixing trap.c to make interrupts turn off FL_IF -  that makes it take longer, but still panics -  (maybe b/c release sets FL_IF) - -shouldn't something (PIC?) prevent recursive interrupts of same IRQ? -  or should FL_IF be clear during all interrupts? - -maybe acquire should remember old FL_IF value, release should restore -  if acquire did cli() - -DUH the increment of nlock in acquire() happens before the cli! -  so the panic is probably not a real problem -  test nlock, cli(), then increment? - -BUT now userfs doesn't do the final cat README - -AND w/ cprintf("kbd overflow"), panic holding locks in scheduler -  maybe also simulataneous panic("interrupt while holding a lock") - -again (holding down x key): -  kbd overflow -  kbd oaaniicloowh -  olding locks in scheduler -  trap v 33 eip 100F5F c^CNext at t=32166285 -  (0) [0x0010033e] 0008:0010033e (unk. ctxt): jmp .+0xfffffffe (0x0010033e) ; ebfe -  (1) [0x0010005c] 0008:0010005c (unk. ctxt): jmp .+0xfffffffe (0x0010005c) ; ebfe -cpu0 paniced due to holding locks in scheduler -cpu1 got panic("interrupt while holding a lock") -  again in lapic_write. -  while re-enabling an IRQ? - -again: -cpu 0 panic("holding locks in scheduler") -  but didn't trigger related panics earlier in scheduler or sched() -  of course the panic is right after release() and thus sti() -  so we may be seeing an interrupt that left locks held -cpu 1 unknown panic -why does it happen to both cpus at the same time? - -again: -cpu 0 panic("holding locks in scheduler") -  but trap() didn't see any held locks on return -cpu 1 no apparent panic - -again: -cpu 0 panic: holding too many locks in scheduler -cpu 1 panic: kbd_intr returned while holding a lock - -again: -cpu 0 panic: holding too man -  la 10d70c lr 10027b -  those don't seem to be locks... -  only place non-constant lock is used is sleep()'s 2nd arg -  maybe register not preserved across context switch? -  it's in %esi... -  sched() doesn't touch %esi -  %esi is evidently callee-saved -  something to do with interrupts? since ordinarily it works -cpu 1 panic: kbd_int returned while holding a lock -  la 107340 lr 107300 -  console_lock and kbd_lock - -maybe console_lock is often not released due to change -  in use_console_lock (panic on other cpu) - -again: -cpu 0: panic: h... -  la 10D78C lr 102CA0 -cpu 1: panic: acquire FL_IF (later than cpu 0) - -but if sleep() were acquiring random locks, we'd see panics -in release, after sleep() returned. -actually when system is idle, maybe no-one sleeps at all. -  just scheduler() and interrupts - -questions: -  does userfs use pipes? or fork? -    no -  does anything bad happen if process 1 exits? eg exit() in cat.c -    looks ok -  are there really no processes left? -  lock_init() so we can have a magic number? - -HMM maybe the variables at the end of struct cpu are being overwritten -  nlocks, lastacquire, lastrelease -  by cpu->stack? -  adding junk buffers maybe causes crash to take longer... -  when do we run on cpu stack? -  just in scheduler()? -    and interrupts from scheduler() -   OH! recursive interrupts will use up any amount of cpu[].stack!    underflow and wrecks *previous* cpu's struct @@ -360,15 +108,26 @@ mkdir  sh arguments  sh redirection  indirect blocks -two bugs in unlink: don't just return if nlink > 0, -  and search for name, not inum  is there a create/create race for same file name?    resulting in two entries w/ same name in directory? +why does shell often ignore first line of input?  test: one process unlinks a file while another links to it -test: simultaneous create of same file  test: one process opens a file while another deletes it - -wdir should use writei, to avoid special-case block allocation -  also readi -  is dir locked? probably +test: mkdir. deadlock d/.. vs ../d + +make proc[0] runnable +cpu early tss and gdt +how do we get cpu0 scheduler() to use mpstack, not proc[0].kstack? +when iget() first sleeps, where does it longjmp to? +maybe set up proc[0] to be runnable, with entry proc0main(), then +  have main() call scheduler()? +  perhaps so proc[0] uses right kstack? +  and scheduler() uses mpstack? +ltr sets the busy bit in the TSS, faults if already set +  so gdt and TSS per cpu? +  we don't want to be using some random process's gdt when it changes it. +maybe get rid of per-proc gdt and ts +  one per cpu +  refresh it when needed +  setupsegs(proc *) diff --git a/fstests.c b/fstests.c new file mode 100644 index 0000000..d6f630e --- /dev/null +++ b/fstests.c @@ -0,0 +1,380 @@ +#include "user.h" +#include "fcntl.h" + +char buf[512]; + +// two processes write to the same file descriptor +// is the offset shared? does inode locking work? +void +sharedfd() +{ +  int fd, pid, i, n, nc, np; +  char buf[10]; + +  unlink("sharedfd"); +  fd = open("sharedfd", O_CREATE|O_RDWR); +  if(fd < 0){ +    printf(1, "fstests: cannot open sharedfd for writing"); +    return; +  } +  pid = fork(); +  memset(buf, pid==0?'c':'p', sizeof(buf)); +  for(i = 0; i < 100; i++){ +    if(write(fd, buf, sizeof(buf)) != sizeof(buf)){ +      printf(1, "fstests: write sharedfd failed\n"); +      break; +    } +  } +  if(pid == 0) +    exit(); +  else +    wait(); +  close(fd); +  fd = open("sharedfd", 0); +  if(fd < 0){ +    printf(1, "fstests: cannot open sharedfd for reading\n"); +    return; +  } +  nc = np = 0; +  while((n = read(fd, buf, sizeof(buf))) > 0){ +    for(i = 0; i < sizeof(buf); i++){ +      if(buf[i] == 'c') +        nc++; +      if(buf[i] == 'p') +        np++; +    } +  } +  close(fd); +  unlink("sharedfd"); +  if(nc == 1000 && np == 1000) +    printf(1, "sharedfd ok\n"); +  else +    printf(1, "sharedfd oops %d %d\n", nc, np); +} + +// two processes write two different files at the same +// time, to test block allocation. +void +twofiles() +{ +  int fd, pid, i, j, n, total; +  char *fname; + +  unlink("f1"); +  unlink("f2"); + +  pid = fork(); +  if(pid < 0){ +    puts("fork failed\n"); +    return; +  } + +  fname = pid ? "f1" : "f2"; +  fd = open(fname, O_CREATE | O_RDWR); +  if(fd < 0){ +    puts("create failed\n"); +    exit(); +  } + +  memset(buf, pid?'p':'c', 512); +  for(i = 0; i < 12; i++){ +    if((n = write(fd, buf, 500)) != 500){ +      printf(1, "write failed %d\n", n); +      exit(); +    } +  } +  close(fd); +  if(pid) +    wait(); +  else +    exit(); + +  for(i = 0; i < 2; i++){ +    fd = open(i?"f1":"f2", 0); +    total = 0; +    while((n = read(fd, buf, sizeof(buf))) > 0){ +      for(j = 0; j < n; j++){ +        if(buf[j] != (i?'p':'c')){ +          puts("wrong char\n"); +          exit(); +        } +      } +      total += n; +    } +    close(fd); +    if(total != 12*500){ +      printf(1, "wrong length %d\n", total); +      exit(); +    } +  } + +  unlink("f1"); +  unlink("f2"); + +  puts("twofiles ok\n"); +} + +// two processes create and delete files in same directory +void +createdelete() +{ +  int pid, i, fd; +  int n = 20; +  char name[32]; + +  pid = fork(); +  if(pid < 0){ +    puts("fork failed\n"); +    exit(); +  } + +  name[0] = pid ? 'p' : 'c'; +  name[2] = '\0'; +  for(i = 0; i < n; i++){ +    name[1] = '0' + i; +    fd = open(name, O_CREATE | O_RDWR); +    if(fd < 0){ +      puts("create failed\n"); +      exit(); +    } +    close(fd); +    if(i > 0 && (i % 2 ) == 0){ +      name[1] = '0' + (i / 2); +      if(unlink(name) < 0){ +        puts("unlink failed\n"); +        exit(); +      } +    } +  } + +  if(pid) +    wait(); +  else +    exit(); + +  for(i = 0; i < n; i++){ +    name[0] = 'p'; +    name[1] = '0' + i; +    fd = open(name, 0); +    if((i == 0 || i >= n/2) && fd < 0){ +      printf(1, "oops createdelete %s didn't exist\n", name); +    } else if((i >= 1 && i < n/2) && fd >= 0){ +      printf(1, "oops createdelete %s did exist\n", name); +    } +    if(fd >= 0) +      close(fd); + +    name[0] = 'c'; +    name[1] = '0' + i; +    fd = open(name, 0); +    if((i == 0 || i >= n/2) && fd < 0){ +      printf(1, "oops createdelete %s didn't exist\n", name); +    } else if((i >= 1 && i < n/2) && fd >= 0){ +      printf(1, "oops createdelete %s did exist\n", name); +    } +    if(fd >= 0) +      close(fd); +  } + +  for(i = 0; i < n; i++){ +    name[0] = 'p'; +    name[1] = '0' + i; +    unlink(name); +    name[0] = 'c'; +    unlink(name); +  } + +  printf(1, "createdelete ok\n"); +} + +// can I unlink a file and still read it? +void +unlinkread() +{ +  int fd, fd1; +   +  fd = open("unlinkread", O_CREATE | O_RDWR); +  if(fd < 0){ +    puts("create unlinkread failed\n"); +    exit(); +  } +  write(fd, "hello", 5); +  close(fd); + +  fd = open("unlinkread", O_RDWR); +  if(fd < 0){ +    puts("open unlinkread failed\n"); +    exit(); +  } +  if(unlink("unlinkread") != 0){ +    puts("unlink unlinkread failed\n"); +    exit(); +  } + +  fd1 = open("xxx", O_CREATE | O_RDWR); +  write(fd1, "yyy", 3); +  close(fd1); + +  if(read(fd, buf, sizeof(buf)) != 5){ +    puts("unlinkread read failed"); +    exit(); +  } +  if(buf[0] != 'h'){ +    puts("unlinkread wrong data\n"); +    exit(); +  } +  if(write(fd, buf, 10) != 10){ +    puts("unlinkread write failed\n"); +    exit(); +  } +  close(fd); +  unlink("xxx"); +  puts("unlinkread ok\n"); +} + +void +linktest() +{ +  int fd; + +  unlink("lf1"); +  unlink("lf2"); + +  fd = open("lf1", O_CREATE|O_RDWR); +  if(fd < 0){ +    puts("create lf1 failed\n"); +    exit(); +  } +  if(write(fd, "hello", 5) != 5){ +    puts("write lf1 failed\n"); +    exit(); +  } +  close(fd); + +  if(link("lf1", "lf2") < 0){ +    puts("link lf1 lf2 failed\n"); +    exit(); +  } +  unlink("lf1"); + +  if(open("lf1", 0) >= 0){ +    puts("unlinked lf1 but it is still there!\n"); +    exit(); +  } + +  fd = open("lf2", 0); +  if(fd < 0){ +    puts("open lf2 failed\n"); +    exit(); +  } +  if(read(fd, buf, sizeof(buf)) != 5){ +    puts("read lf2 failed\n"); +    exit(); +  } +  close(fd); +     +  if(link("lf2", "lf2") >= 0){ +    puts("link lf2 lf2 succeeded! oops\n"); +    exit(); +  } + +  unlink("lf2"); +  if(link("lf2", "lf1") >= 0){ +    puts("link non-existant succeeded! oops\n"); +    exit(); +  } + +  if(link(".", "lf1") >= 0){ +    puts("link . lf1 succeeded! oops\n"); +    exit(); +  } + +  puts("linktest ok\n"); +} + +// test concurrent create of the same file +void +concreate() +{ +  char file[3]; +  int i, pid, n, fd; +  char fa[40]; +  struct { +    unsigned short inum; +    char name[14]; +  } de; + +  file[0] = 'C'; +  file[2] = '\0'; +  for(i = 0; i < 40; i++){ +    file[1] = '0' + i; +    unlink(file); +    pid = fork(); +    if(pid && (i % 3) == 1){ +      link("C0", file); +    } else if(pid == 0 && (i % 5) == 1){ +      link("C0", file); +    } else { +      fd = open(file, O_CREATE | O_RDWR); +      if(fd < 0){ +        puts("concreate create failed\n"); +        exit(); +      } +      close(fd); +    } +    if(pid == 0) +      exit(); +    else +      wait(); +  } + +  memset(fa, 0, sizeof(fa)); +  fd = open(".", 0); +  n = 0; +  while(read(fd, &de, sizeof(de)) > 0){ +    if(de.inum == 0) +      continue; +    if(de.name[0] == 'C' && de.name[2] == '\0'){ +      i = de.name[1] - '0'; +      if(i < 0 || i >= sizeof(fa)){ +        printf(1, "concreate weird file %s\n", de.name); +        exit(); +      } +      if(fa[i]){ +        printf(1, "concreate duplicate file %s\n", de.name); +        exit(); +      } +      fa[i] = 1; +      n++; +    } +  } +  close(fd); + +  if(n != 40){ +    puts("concreate not enough files in directory listing\n"); +    exit(); +  } + +  for(i = 0; i < 40; i++){ +    file[1] = '0' + i; +    unlink(file); +  } + +  puts("concreate ok\n"); +} + +int +main(int argc, char *argv[]) +{ +  puts("fstests starting\n"); + +  concreate(); +  linktest(); +  unlinkread(); +  createdelete(); +  twofiles(); +  sharedfd(); + +  puts("fstests finished\n"); +  exit(); +} @@ -29,10 +29,14 @@ main0(void)    // clear BSS    memset(edata, 0, end - edata); +  // switch to cpu0's cpu stack +  asm volatile("movl %0, %%esp" : : "r" (cpus[0].mpstack + MPSTACK - 32)); +  asm volatile("movl %0, %%ebp" : : "r" (cpus[0].mpstack + MPSTACK)); +    // Make sure interrupts stay disabled on all processors    // until each signals it is ready, by pretending to hold    // an extra lock. -  // xxx maybe replace w/ acquire remembering if FL_IF +  // xxx maybe replace w/ acquire remembering if FL_IF was already clear    for(i=0; i<NCPU; i++){      cpus[i].nlock++;      cpus[i].guard1 = 0xdeadbeef; @@ -55,16 +59,9 @@ main0(void)    fd_init();    iinit(); -  // create a fake process per CPU -  // so each CPU always has a tss and a gdt -  for(p = &proc[0]; p < &proc[NCPU]; p++){ -    p->state = IDLEPROC; -    p->kstack = cpus[p-proc].mpstack; -    p->pid = p - proc; -  } -    // fix process 0 so that copyproc() will work    p = &proc[0]; +  p->state = IDLEPROC;    p->sz = 4 * PAGE;    p->mem = kalloc(p->sz);    memset(p->mem, 0, p->sz); @@ -74,8 +71,9 @@ main0(void)    p->tf->es = p->tf->ds = p->tf->ss = (SEG_UDATA << 3) | 3;    p->tf->cs = (SEG_UCODE << 3) | 3;    p->tf->eflags = FL_IF; -  setupsegs(p); -  // curproc[cpu()] = p; + +  // make sure there's a TSS +  setupsegs(0);    // initialize I/O devices, let them enable interrupts    console_init(); @@ -117,7 +115,8 @@ mpmain(void)    lapic_timerinit();    lapic_enableintr(); -  setupsegs(&proc[cpu()]); +  // make sure there's a TSS +  setupsegs(0);    cpuid(0, 0, 0, 0, 0);	// memory barrier    cpus[cpu()].booted = 1; @@ -11,7 +11,7 @@ struct spinlock proc_table_lock;  struct proc proc[NPROC];  struct proc *curproc[NCPU]; -int next_pid = NCPU; +int next_pid = 1;  extern void forkret(void);  extern void forkret1(struct trapframe*); @@ -22,28 +22,39 @@ pinit(void)  }  /* - * set up a process's task state and segment descriptors - * correctly, given its current size and address in memory. - * this should be called whenever the latter change. - * doesn't change the cpu's current segmentation setup. + * set up CPU's segment descriptors and task state for a + * given process. If p==0, set up for "idle" state for + * when scheduler() isn't running any process.   */  void  setupsegs(struct proc *p)  { -  memset(&p->ts, 0, sizeof(struct taskstate)); -  p->ts.ss0 = SEG_KDATA << 3; -  p->ts.esp0 = (uint)(p->kstack + KSTACKSIZE); +  struct cpu *c = &cpus[cpu()]; + +  c->ts.ss0 = SEG_KDATA << 3; +  if(p){ +    c->ts.esp0 = (uint)(p->kstack + KSTACKSIZE); +  } else { +    c->ts.esp0 = 0xffffffff; +  }    // XXX it may be wrong to modify the current segment table! -  p->gdt[0] = SEG_NULL; -  p->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0x100000 + 64*1024, 0); // xxx -  p->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0); -  p->gdt[SEG_TSS] = SEG16(STS_T32A, (uint) &p->ts, -                                sizeof(p->ts), 0); -  p->gdt[SEG_TSS].s = 0; -  p->gdt[SEG_UCODE] = SEG(STA_X|STA_R, (uint)p->mem, p->sz, 3); -  p->gdt[SEG_UDATA] = SEG(STA_W, (uint)p->mem, p->sz, 3); +  c->gdt[0] = SEG_NULL; +  c->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0x100000 + 64*1024, 0); // xxx +  c->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0); +  c->gdt[SEG_TSS] = SEG16(STS_T32A, (uint) &c->ts, sizeof(c->ts), 0); +  c->gdt[SEG_TSS].s = 0; +  if(p){ +    c->gdt[SEG_UCODE] = SEG(STA_X|STA_R, (uint)p->mem, p->sz, 3); +    c->gdt[SEG_UDATA] = SEG(STA_W, (uint)p->mem, p->sz, 3); +  } else { +    c->gdt[SEG_UCODE] = SEG_NULL; +    c->gdt[SEG_UDATA] = SEG_NULL; +  } + +  lgdt(c->gdt, sizeof c->gdt); +  ltr(SEG_TSS << 3);  }  // Look in the process table for an UNUSED proc. @@ -101,9 +112,6 @@ copyproc(struct proc* p)      np->state = UNUSED;      return 0;    } -   -  // Initialize segment table. -  setupsegs(np);    // Copy trapframe registers from parent.    np->tf = (struct trapframe*)(np->kstack + KSTACKSIZE) - 1; @@ -159,26 +167,11 @@ scheduler(void)        if(p->state != RUNNABLE)          continue; -      // Run this process. -      // XXX move this into swtch or trapret or something. -      // It can run on the other stack. -      // h/w sets busy bit in TSS descriptor sometimes, and faults -      // if it's set in LTR. so clear tss descriptor busy bit. -      p->gdt[SEG_TSS].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. -      lgdt(p->gdt, sizeof p->gdt); -    // asm volatile("lgdt %0" : : "g" (p->gdt_pd.lim)); - -      ltr(SEG_TSS << 3); -        // Switch to chosen process.  It is the process's job         // to release proc_table_lock and then reacquire it        // before jumping back to us. -      if(0) cprintf("cpu%d: run %d\n", cpu(), p-proc); + +      setupsegs(p);        curproc[cpu()] = p;        p->state = RUNNING;        if(setjmp(&cpus[cpu()].jmpbuf) == 0) @@ -199,9 +192,7 @@ scheduler(void)          panic("scheduler lock");        } -      setupsegs(&proc[cpu()]); - -      // XXX if not holding proc_table_lock panic. +      setupsegs(0);      }      release(&proc_table_lock); @@ -48,8 +48,6 @@ struct proc{    struct fd *fds[NOFILE];    struct inode *cwd; -  struct taskstate ts;  // only to give cpu address of kernel stack -  struct segdesc gdt[NSEGS];    uint esp; // kernel stack pointer    uint ebp; // kernel frame pointer @@ -67,6 +65,8 @@ extern struct proc *curproc[NCPU];  // can be NULL if no proc running.  struct cpu {    uchar apicid;       // Local APIC ID    struct jmpbuf jmpbuf; +  struct taskstate ts;  // only to give cpu address of kernel stack +  struct segdesc gdt[NSEGS];    int guard1;    char mpstack[MPSTACK]; // per-cpu start-up stack    int guard2; @@ -41,8 +41,8 @@ trap(struct trapframe *tf)      panic("interrupt while holding a lock");    } -  if(cpu() == 1 && curproc[cpu()] == 0){ -    if(&tf < cpus[cpu()].mpstack || &tf > cpus[cpu()].mpstack + 512){ +  if(curproc[cpu()] == 0){ +    if(&tf < cpus[cpu()].mpstack || &tf > cpus[cpu()].mpstack + MPSTACK){        cprintf("&tf %x mpstack %x\n", &tf, cpus[cpu()].mpstack);        panic("trap cpu stack");      } @@ -125,7 +125,8 @@ trap(struct trapframe *tf)      return;    } -  cprintf("trap %d\n", v); +  cprintf("trap %d from cpu %d eip %x\n", v, cpu(), tf->eip); +  panic("trap");    return;  } diff --git a/usertests.c b/usertests.c index c3e9113..20155c2 100644 --- a/usertests.c +++ b/usertests.c @@ -115,305 +115,11 @@ exitwait(void)    puts("exitwait ok\n");  } -// two processes write to the same file descriptor -// is the offset shared? does inode locking work? -void -sharedfd() -{ -  int fd, pid, i, n, nc, np; -  char buf[10]; - -  unlink("sharedfd"); -  fd = open("sharedfd", O_CREATE|O_RDWR); -  if(fd < 0){ -    printf(1, "usertests: cannot open sharedfd for writing"); -    return; -  } -  pid = fork(); -  memset(buf, pid==0?'c':'p', sizeof(buf)); -  for(i = 0; i < 100; i++){ -    if(write(fd, buf, sizeof(buf)) != sizeof(buf)){ -      printf(1, "usertests: write sharedfd failed\n"); -      break; -    } -  } -  if(pid == 0) -    exit(); -  else -    wait(); -  close(fd); -  fd = open("sharedfd", 0); -  if(fd < 0){ -    printf(1, "usertests: cannot open sharedfd for reading\n"); -    return; -  } -  nc = np = 0; -  while((n = read(fd, buf, sizeof(buf))) > 0){ -    for(i = 0; i < sizeof(buf); i++){ -      if(buf[i] == 'c') -        nc++; -      if(buf[i] == 'p') -        np++; -    } -  } -  close(fd); -  unlink("sharedfd"); -  if(nc == 1000 && np == 1000) -    printf(1, "sharedfd ok\n"); -  else -    printf(1, "sharedfd oops %d %d\n", nc, np); -} - -// two processes write two different files at the same -// time, to test block allocation. -void -twofiles() -{ -  int fd, pid, i, j, n, total; -  char *fname; - -  unlink("f1"); -  unlink("f2"); - -  pid = fork(); -  if(pid < 0){ -    puts("fork failed\n"); -    return; -  } - -  fname = pid ? "f1" : "f2"; -  fd = open(fname, O_CREATE | O_RDWR); -  if(fd < 0){ -    puts("create failed\n"); -    exit(); -  } - -  memset(buf, pid?'p':'c', 512); -  for(i = 0; i < 12; i++){ -    if((n = write(fd, buf, 500)) != 500){ -      printf(1, "write failed %d\n", n); -      exit(); -    } -  } -  close(fd); -  if(pid) -    wait(); -  else -    exit(); - -  for(i = 0; i < 2; i++){ -    fd = open(i?"f1":"f2", 0); -    total = 0; -    while((n = read(fd, buf, sizeof(buf))) > 0){ -      for(j = 0; j < n; j++){ -        if(buf[j] != (i?'p':'c')){ -          puts("wrong char\n"); -          exit(); -        } -      } -      total += n; -    } -    close(fd); -    if(total != 12*500){ -      printf(1, "wrong length %d\n", total); -      exit(); -    } -  } - -  unlink("f1"); -  unlink("f2"); - -  puts("twofiles ok\n"); -} - -// two processes create and delete files in same directory -void -createdelete() -{ -  int pid, i, fd; -  int n = 20; -  char name[32]; - -  pid = fork(); -  if(pid < 0){ -    puts("fork failed\n"); -    exit(); -  } - -  name[0] = pid ? 'p' : 'c'; -  name[2] = '\0'; -  for(i = 0; i < n; i++){ -    name[1] = '0' + i; -    fd = open(name, O_CREATE | O_RDWR); -    if(fd < 0){ -      puts("create failed\n"); -      exit(); -    } -    close(fd); -    if(i > 0 && (i % 2 ) == 0){ -      name[1] = '0' + (i / 2); -      if(unlink(name) < 0){ -        puts("unlink failed\n"); -        exit(); -      } -    } -  } - -  if(pid) -    wait(); -  else -    exit(); - -  for(i = 0; i < n; i++){ -    name[0] = 'p'; -    name[1] = '0' + i; -    fd = open(name, 0); -    if((i == 0 || i >= n/2) && fd < 0){ -      printf(1, "oops createdelete %s didn't exist\n", name); -    } else if((i >= 1 && i < n/2) && fd >= 0){ -      printf(1, "oops createdelete %s did exist\n", name); -    } -    if(fd >= 0) -      close(fd); - -    name[0] = 'c'; -    name[1] = '0' + i; -    fd = open(name, 0); -    if((i == 0 || i >= n/2) && fd < 0){ -      printf(1, "oops createdelete %s didn't exist\n", name); -    } else if((i >= 1 && i < n/2) && fd >= 0){ -      printf(1, "oops createdelete %s did exist\n", name); -    } -    if(fd >= 0) -      close(fd); -  } - -  for(i = 0; i < n; i++){ -    name[0] = 'p'; -    name[1] = '0' + i; -    unlink(name); -    name[0] = 'c'; -    unlink(name); -  } - -  printf(1, "createdelete ok\n"); -} - -// can I unlink a file and still read it? -void -unlinkread() -{ -  int fd, fd1; -   -  fd = open("unlinkread", O_CREATE | O_RDWR); -  if(fd < 0){ -    puts("create unlinkread failed\n"); -    exit(); -  } -  write(fd, "hello", 5); -  close(fd); - -  fd = open("unlinkread", O_RDWR); -  if(fd < 0){ -    puts("open unlinkread failed\n"); -    exit(); -  } -  if(unlink("unlinkread") != 0){ -    puts("unlink unlinkread failed\n"); -    exit(); -  } - -  fd1 = open("xxx", O_CREATE | O_RDWR); -  write(fd1, "yyy", 3); -  close(fd1); - -  if(read(fd, buf, sizeof(buf)) != 5){ -    puts("unlinkread read failed"); -    exit(); -  } -  if(buf[0] != 'h'){ -    puts("unlinkread wrong data\n"); -    exit(); -  } -  if(write(fd, buf, 10) != 10){ -    puts("unlinkread write failed\n"); -    exit(); -  } -  close(fd); -  unlink("xxx"); -  puts("unlinkread ok\n"); -} - -void -linktest() -{ -  int fd; - -  unlink("lf1"); -  unlink("lf2"); - -  fd = open("lf1", O_CREATE|O_RDWR); -  if(fd < 0){ -    puts("create lf1 failed\n"); -    exit(); -  } -  if(write(fd, "hello", 5) != 5){ -    puts("write lf1 failed\n"); -    exit(); -  } -  close(fd); - -  if(link("lf1", "lf2") < 0){ -    puts("link lf1 lf2 failed\n"); -    exit(); -  } -  unlink("lf1"); - -  if(open("lf1", 0) >= 0){ -    puts("unlinked lf1 but it is still there!\n"); -    exit(); -  } - -  fd = open("lf2", 0); -  if(fd < 0){ -    puts("open lf2 failed\n"); -    exit(); -  } -  if(read(fd, buf, sizeof(buf)) != 5){ -    puts("read lf2 failed\n"); -    exit(); -  } -  close(fd); -     -  if(link("lf2", "lf2") >= 0){ -    puts("link lf2 lf2 succeeded! oops\n"); -    exit(); -  } - -  unlink("lf2"); -  if(link("lf2", "lf1") >= 0){ -    puts("link non-existant succeeded! oops\n"); -    exit(); -  } - -  if(link(".", "lf1") >= 0){ -    puts("link . lf1 succeeded! oops\n"); -    exit(); -  } - -  puts("linktest ok\n"); -} -  int  main(int argc, char *argv[])  {    puts("usertests starting\n"); -  linktest(); -  unlinkread(); -  createdelete(); -  twofiles(); -  sharedfd();    pipe1();    preempt();    exitwait(); | 
