blocks and inodes have ad-hoc sleep-locks
provide a single mechanism?
-test 14-character file names
-and file arguments longer than 14
-
kalloc() can return 0; do callers handle this right?
-OH! recursive interrupts will use up any amount of cpu[].stack!
- underflow and wrecks *previous* cpu's struct
-
-disk scheduling
-mkdir
-sh arguments
-sh redirection
-indirect blocks
-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: one process opens a file while another deletes it
-test: mkdir. deadlock d/.. vs ../d, two processes.
+test: deadlock d/.. vs ../d, two processes.
test: dup() shared fd->off
test: sbrk
test: does echo foo > x truncate x?
-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 *)
-
-why do we get 0 characters from keyboard?
-are the locks in the right place in keyboardintr?
-
sh: support pipes? leave it for the class?
sh: dynamic memory allocation?
sh: should sh support ; () & --- need malloc
really should have bdwrite() for file content
and make some inode updates async
so soft updates make sense
+
+disk scheduling
+echo foo > bar should truncate bar
+ so O_CREATE should not truncate
+ but O_TRUNC should
+
+make it work on one cpu
+make it work on amsterdam
int panicked = 0;
int use_console_lock = 0;
-// per-cpu copy of output to help panic/lock debugging
-char obuf[NCPU][1024];
-uint obufi[NCPU];
-
/*
* copy console output to parallel port, which you can tell
* .bochsrc to copy to the stdout:
ushort *crt = (ushort *) 0xB8000; // base of CGA memory
int ind;
- obuf[rcr4()][obufi[rcr4()]++] = c;
- if(obufi[rcr4()] >= 1024)
- obufi[rcr4()] = 0;
-
if(panicked){
cli();
for(;;)
void setupsegs(struct proc *);
struct proc * copyproc(struct proc*);
struct spinlock;
-char *growproc(int);
+int growproc(int);
void sleep(void *, struct spinlock *);
void wakeup(void *);
void scheduler(void);
int i;
struct proc *p;
- lcr4(0); // xxx copy of cpu #
-
// clear BSS
memset(edata, 0, end - edata);
void
mpmain(void)
{
- lcr4(1); // xxx copy of cpu #
-
cprintf("cpu%d: starting\n", cpu());
idtinit(); // CPU's idt
if(cpu() == 0)
-#define NPROC 64
-#define PAGE 4096
-#define KSTACKSIZE PAGE
-#define NCPU 8
-#define NOFILE 16 // file descriptors per process
-#define NFD 100 // file descriptors per system
-#define NREQUEST 100 // outstanding disk requests
-#define NBUF 10
-#define NINODE 100
-#define NDEV 10
+#define NPROC 64 // maximum number of processes
+#define PAGE 4096 // granularity of user-space memory allocation
+#define KSTACKSIZE PAGE // size of per-process kernel stack
+#define NCPU 8 // maximum number of CPUs
+#define NOFILE 16 // file descriptors per process
+#define NFD 100 // file descriptors per system
+#define NREQUEST 100 // outstanding disk requests
+#define NBUF 10 // size of disk block cache
+#define NINODE 100 // maximum number of active i-nodes
+#define NDEV 10 // maximum major device number
return np;
}
-char *
+int
growproc(int n)
{
struct proc *cp = curproc[cpu()];
char *newmem, *oldmem;
newmem = kalloc(cp->sz + n);
- if(newmem == 0) return (char *) -1;
+ if(newmem == 0)
+ return -1;
memmove(newmem, cp->mem, cp->sz);
memset(newmem + cp->sz, 0, n);
oldmem = cp->mem;
cp->mem = newmem;
kfree(oldmem, cp->sz);
- cprintf("growproc: added %d bytes to %d bytes\n", n, cp->sz);
cp->sz += n;
- return cp->sz - n;
+ return 0;
}
// Per-CPU process scheduler.
#include "proc.h"
#include "spinlock.h"
-// Can't call cprintf from inside these routines,
-// because cprintf uses them itself.
-//#define cprintf dont_use_cprintf
-
-#define LOCKMAGIC 0x6673ffea
-
extern int use_console_lock;
void
initlock(struct spinlock *lock, char *name)
{
- lock->magic = LOCKMAGIC;
lock->name = name;
lock->locked = 0;
lock->cpu = 0xffffffff;
void
acquire(struct spinlock * lock)
{
- if(lock->magic != LOCKMAGIC)
- panic("weird lock magic");
if(holding(lock))
panic("acquire");
cli();
cpus[cpu()].nlock++;
- while(cmpxchg(0, 1, &lock->locked) == 1)
- ;
- cpuid(0, 0, 0, 0, 0); // memory barrier
- getcallerpcs(&lock, lock->pcs);
- lock->cpu = cpu() + 10;
- cpus[cpu()].lastacquire = lock;
+ while(cmpxchg(0, 1, &lock->locked) == 1)
+ ;
+ cpuid(0, 0, 0, 0, 0); // memory barrier
+ getcallerpcs(&lock, lock->pcs);
+ lock->cpu = cpu() + 10;
+ cpus[cpu()].lastacquire = lock;
}
void
release(struct spinlock * lock)
{
- if(lock->magic != LOCKMAGIC)
- panic("weird lock magic");
- if(!holding(lock))
- panic("release");
+ if(!holding(lock))
+ panic("release");
- cpus[cpu()].lastrelease = lock;
- lock->pcs[0] = 0;
- lock->cpu = 0xffffffff;
- cpuid(0, 0, 0, 0, 0); // memory barrier
- lock->locked = 0;
- if(--cpus[cpu()].nlock == 0)
- sti();
+ cpus[cpu()].lastrelease = lock;
+ lock->pcs[0] = 0;
+ lock->cpu = 0xffffffff;
+ cpuid(0, 0, 0, 0, 0); // memory barrier
+ lock->locked = 0;
+ if(--cpus[cpu()].nlock == 0)
+ sti();
}
int
holding(struct spinlock *lock)
{
- return lock->locked && lock->cpu == cpu() + 10;
+ return lock->locked && lock->cpu == cpu() + 10;
}
struct spinlock {
- uint magic;
char *name;
uint locked;
int cpu;
int
sys_sbrk(void)
{
- char *r;
int n;
struct proc *cp = curproc[cpu()];
if(fetcharg(0, &n) < 0)
return -1;
- r = growproc(n);
+ if(growproc(n) != 0)
+ return -1;
setupsegs(cp);
- return (int) r;
+ return 0;
}
int
trap(struct trapframe *tf)
{
int v = tf->trapno;
-
- if(cpus[cpu()].nlock){
- cprintf("trap v %d eip %x cpu %d nlock %d\n",
- v, tf->eip, cpu(), cpus[cpu()].nlock);
- panic("interrupt while holding a lock");
- }
-
- 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");
- }
- } else if(curproc[cpu()]){
- if(&tf < curproc[cpu()]->kstack){
- panic("trap kstack");
- }
- }
if(v == T_SYSCALL){
struct proc *cp = curproc[cpu()];
int num = cp->tf->eax;
- if((read_eflags() & FL_IF) == 0)
- panic("syscall but interrupts now disabled");
- if(cp == 0)
- panic("syscall with no proc");
if(cp->killed)
proc_exit();
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(cpus[cpu()].nlock){
- cprintf("num=%d\n", num);
- panic("syscall returning locks held");
- }
- if((read_eflags() & FL_IF) == 0)
- panic("syscall returning but FL_IF clear");
- if(read_esp() < (uint)cp->kstack ||
- read_esp() >= (uint)cp->kstack + KSTACKSIZE)
- panic("trap ret esp wrong");
if(cp->killed)
proc_exit();
- // XXX probably ought to lgdt on trap return
return;
}
- //if(read_eflags() & FL_IF)
- //panic("interrupt but interrupts enabled");
-
if(v == (IRQ_OFFSET + IRQ_TIMER)){
struct proc *cp = curproc[cpu()];
lapic_timerintr();
if(v == (IRQ_OFFSET + IRQ_IDE)){
ide_intr();
- if(cpus[cpu()].nlock)
- panic("ide_intr returned while holding a lock");
cli(); // prevent a waiting interrupt from overflowing stack
lapic_eoi();
return;
if(v == (IRQ_OFFSET + IRQ_KBD)){
kbd_intr();
- if(cpus[cpu()].nlock){
- panic("kbd_intr returned while holding a lock");
- }
cli(); // prevent a waiting interrupt from overflowing stack
lapic_eoi();
return;
-static __inline void breakpoint(void) __attribute__((always_inline));
-static __inline uchar inb(int port) __attribute__((always_inline));
-static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
-static __inline ushort inw(int port) __attribute__((always_inline));
-static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline));
-static __inline uint inl(int port) __attribute__((always_inline));
-static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline));
-static __inline void outb(int port, uchar data) __attribute__((always_inline));
-static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline));
-static __inline void outw(int port, ushort data) __attribute__((always_inline));
-static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline));
-static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline));
-static __inline void outl(int port, uint data) __attribute__((always_inline));
-static __inline void invlpg(void *addr) __attribute__((always_inline));
-struct segdesc;
-static __inline void lgdt(struct segdesc *p, int) __attribute__((always_inline));
-struct gatedesc;
-static __inline void lidt(struct gatedesc *p, int) __attribute__((always_inline));
-static __inline void lldt(ushort sel) __attribute__((always_inline));
-static __inline void ltr(ushort sel) __attribute__((always_inline));
-static __inline void lcr0(uint val) __attribute__((always_inline));
-static __inline uint rcr0(void) __attribute__((always_inline));
-static __inline uint rcr2(void) __attribute__((always_inline));
-static __inline void lcr3(uint val) __attribute__((always_inline));
-static __inline uint rcr3(void) __attribute__((always_inline));
-static __inline void lcr4(uint val) __attribute__((always_inline));
-static __inline uint rcr4(void) __attribute__((always_inline));
-static __inline void tlbflush(void) __attribute__((always_inline));
-static __inline uint read_eflags(void) __attribute__((always_inline));
-static __inline void write_eflags(uint eflags) __attribute__((always_inline));
-static __inline uint read_ebp(void) __attribute__((always_inline));
-static __inline uint read_esp(void) __attribute__((always_inline));
-static __inline void cpuid(uint info, uint *eaxp, uint *ebxp, uint *ecxp, uint *edxp);
-static __inline void cli(void) __attribute__((always_inline));
-static __inline void sti(void) __attribute__((always_inline));
-
-static __inline void
-breakpoint(void)
-{
- __asm __volatile("int3");
-}
-
static __inline uchar
inb(int port)
{
return data;
}
-static __inline void
-insb(int port, void *addr, int cnt)
-{
- __asm __volatile("cld\n\trepne\n\tinsb" :
- "=D" (addr), "=c" (cnt) :
- "d" (port), "0" (addr), "1" (cnt) :
- "memory", "cc");
-}
-
-static __inline ushort
-inw(int port)
-{
- ushort data;
- __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
- return data;
-}
-
-static __inline void
-insw(int port, void *addr, int cnt)
-{
- __asm __volatile("cld\n\trepne\n\tinsw" :
- "=D" (addr), "=c" (cnt) :
- "d" (port), "0" (addr), "1" (cnt) :
- "memory", "cc");
-}
-
-static __inline uint
-inl(int port)
-{
- uint data;
- __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
- return data;
-}
-
static __inline void
insl(int port, void *addr, int cnt)
{
__asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
}
-static __inline void
-outsb(int port, const void *addr, int cnt)
-{
- __asm __volatile("cld\n\trepne\n\toutsb" :
- "=S" (addr), "=c" (cnt) :
- "d" (port), "0" (addr), "1" (cnt) :
- "cc");
-}
-
static __inline void
outw(int port, ushort data)
{
__asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
}
-static __inline void
-outsw(int port, const void *addr, int cnt)
-{
- __asm __volatile("cld\n\trepne\n\toutsw" :
- "=S" (addr), "=c" (cnt) :
- "d" (port), "0" (addr), "1" (cnt) :
- "cc");
-}
-
static __inline void
outsl(int port, const void *addr, int cnt)
{
"cc");
}
-static __inline void
-outl(int port, uint data)
-{
- __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
-}
-
-static __inline void
-invlpg(void *addr)
-{
- __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
-}
+struct segdesc;
static __inline void
lgdt(struct segdesc *p, int size)
asm volatile("lgdt (%0)" : : "g" (pd));
}
+struct gatedesc;
+
static __inline void
lidt(struct gatedesc *p, int size)
{
asm volatile("lidt (%0)" : : "g" (pd));
}
-static __inline void
-lldt(ushort sel)
-{
- __asm __volatile("lldt %0" : : "r" (sel));
-}
-
static __inline void
ltr(ushort sel)
{
__asm __volatile("ltr %0" : : "r" (sel));
}
-static __inline void
-lcr0(uint val)
-{
- __asm __volatile("movl %0,%%cr0" : : "r" (val));
-}
-
-static __inline uint
-rcr0(void)
-{
- uint val;
- __asm __volatile("movl %%cr0,%0" : "=r" (val));
- return val;
-}
-
-static __inline uint
-rcr2(void)
-{
- uint val;
- __asm __volatile("movl %%cr2,%0" : "=r" (val));
- return val;
-}
-
-static __inline void
-lcr3(uint val)
-{
- __asm __volatile("movl %0,%%cr3" : : "r" (val));
-}
-
-static __inline uint
-rcr3(void)
-{
- uint val;
- __asm __volatile("movl %%cr3,%0" : "=r" (val));
- return val;
-}
-
-static __inline void
-lcr4(uint val)
-{
- __asm __volatile("movl %0,%%cr4" : : "r" (val));
-}
-
-static __inline uint
-rcr4(void)
-{
- uint cr4;
- __asm __volatile("movl %%cr4,%0" : "=r" (cr4));
- return cr4;
-}
-
-static __inline void
-tlbflush(void)
-{
- uint cr3;
- __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
- __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
-}
-
static __inline uint
read_eflags(void)
{
__asm __volatile("pushl %0; popfl" : : "r" (eflags));
}
-static __inline uint
-read_ebp(void)
-{
- uint ebp;
- __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
- return ebp;
-}
-
-static __inline uint
-read_esp(void)
-{
- uint esp;
- __asm __volatile("movl %%esp,%0" : "=r" (esp));
- return esp;
-}
-
-static __inline uint
-read_esi(void)
-{
- uint esi;
- __asm __volatile("movl %%esi,%0" : "=r" (esi));
- return esi;
-}
-
-static __inline uint
-read_edi(void)
-{
- uint edi;
- __asm __volatile("movl %%edi,%0" : "=r" (edi));
- return edi;
-}
-
-static __inline uint
-read_ebx(void)
-{
- uint ebx;
- __asm __volatile("movl %%ebx,%0" : "=r" (ebx));
- return ebx;
-}
-
static __inline void
cpuid(uint info, uint *eaxp, uint *ebxp, uint *ecxp, uint *edxp)
{