more comments

This commit is contained in:
rsc 2006-09-07 14:12:30 +00:00
parent 7e019461c8
commit 31085bb416
13 changed files with 151 additions and 81 deletions

6
elf.h
View file

@ -1,9 +1,8 @@
//
// format of an ELF executable file
//
// Format of an ELF executable file
#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian
// File header
struct elfhdr {
uint magic; // must equal ELF_MAGIC
uchar elf[12];
@ -22,6 +21,7 @@ struct elfhdr {
ushort shstrndx;
};
// Program section header
struct proghdr {
uint type;
uint offset;

53
fs.h
View file

@ -1,12 +1,17 @@
// on-disk file system format
// On-disk file system format.
// This header is shared between kernel and user space.
// Block 0 is unused.
// Block 1 is super block.
// Inodes start at block 2.
#define BSIZE 512 // block size
// sector 1 (2nd sector)
struct superblock{
uint size;
uint nblocks;
uint ninodes;
// File system super block
struct superblock {
uint size; // Size of file system (bytes???) xxx
uint nblocks; // Number of blocks
uint ninodes; // Number of inodes.
};
#define NADDRS (NDIRECT+1)
@ -15,24 +20,31 @@ struct superblock{
#define NINDIRECT (BSIZE / sizeof(uint))
#define MAXFILE (NDIRECT + NINDIRECT)
// On-disk inode structure
struct dinode {
short type;
short major;
short minor;
short nlink;
uint size;
uint addrs[NADDRS];
short type; // File type
short major; // Major device number (T_DEV only)
short minor; // Minor device number (T_DEV only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NADDRS]; // Data block addresses
};
#define T_DIR 1
#define T_FILE 2
#define T_DEV 3
#define T_DIR 1 // Directory
#define T_FILE 2 // File
#define T_DEV 3 // Special device
// sector 0 is unused, sector 1 is superblock, inodes start at sector 2
#define IPB (BSIZE / sizeof(struct dinode))
#define IBLOCK(inum) (inum / IPB + 2) // start of inode
#define BPB (BSIZE*8)
#define BBLOCK(b,ninodes) (b/BPB + (ninodes/IPB) + 3) // start of bitmap
// Inodes per block.
#define IPB (BSIZE / sizeof(struct dinode))
// Block containing inode i
#define IBLOCK(i) ((i) / IPB + 2)
// Bitmap bits per block
#define BPB (BSIZE*8)
// Block containing bit for block b
#define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3)
#define DIRSIZ 14
@ -41,4 +53,5 @@ struct dirent {
char name[DIRSIZ];
};
extern uint rootdev; // Device number of root file system

View file

@ -40,6 +40,10 @@ kinit(void)
kfree(start, mem * PAGE);
}
// Free the len bytes of memory pointed at by cp,
// which normally should have been returned by a
// call to kalloc(cp). (The exception is when
// initializing the allocator; see kinit above.)
void
kfree(char *cp, int len)
{

View file

@ -2,6 +2,7 @@
#include "stat.h"
#include "user.h"
int
main(int argc, char *argv[])
{
int i;

5
proc.c
View file

@ -136,7 +136,9 @@ copyproc(struct proc *p)
return np;
}
uint
// Grow current process's memory by n bytes.
// Return old size on success, -1 on failure.
int
growproc(int n)
{
struct proc *cp = curproc[cpu()];
@ -154,6 +156,7 @@ growproc(int n)
return cp->sz - n;
}
//PAGEBREAK: 42
// Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up.
// Scheduler never returns. It loops, doing:

76
proc.h
View file

@ -1,18 +1,19 @@
// segments in proc->gdt
#define SEG_KCODE 1 // kernel code
#define SEG_KDATA 2 // kernel data+stack
// Segments in proc->gdt
#define SEG_KCODE 1 // kernel code
#define SEG_KDATA 2 // kernel data+stack
#define SEG_UCODE 3
#define SEG_UDATA 4
#define SEG_TSS 5 // this process's task state
#define SEG_TSS 5 // this process's task state
#define NSEGS 6
// Saved registers for kernel context switches.
// Don't need to save all the %fs etc. segment registers,
// because they are constant across kernel contexts.
// Save all the regular registers so we don't need to care
// which are caller save.
// Don't save %eax, because that's the return register.
// The layout of jmpbuf is known to setjmp.S.
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 setjmp.S
int ebx;
int ecx;
int edx;
@ -25,39 +26,42 @@ struct jmpbuf {
enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
struct proc{
char *mem; // start of process's memory (a kernel address)
// process memory is laid out contiguously:
// text
// original data and bss
// fixed-size stack
// expandable heap
uint sz; // user memory size
char *kstack; // kernel stack
enum proc_state state;
int pid;
int ppid;
void *chan; // sleep
int killed;
struct file *ofile[NOFILE];
struct inode *cwd;
struct jmpbuf jmpbuf;
struct trapframe *tf; // points into kstack, used to find user regs
// Per-process state
struct proc {
char *mem; // Start of process memory (kernel address)
uint sz; // Size of process memory (bytes)
char *kstack; // Bottom of kernel stack for this process
enum proc_state state; // Process state
int pid; // Process ID
int ppid; // Parent pid
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
struct jmpbuf jmpbuf; // Jump here to run process
struct trapframe *tf; // Trap frame for current interrupt
};
// Process memory is laid out contiguously:
// text
// original data and bss
// fixed-size stack
// expandable heap
extern struct proc proc[];
extern struct proc *curproc[NCPU]; // can be NULL if no proc running.
extern struct proc *curproc[NCPU]; // Current (running) process per CPU
#define MPSTACK 512
// Per-CPU state
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];
char mpstack[MPSTACK]; // per-cpu start-up stack
volatile int booted;
int nlock; // # of locks currently held
uchar apicid; // Local APIC ID
struct jmpbuf jmpbuf; // Jump here to enter scheduler
struct taskstate ts; // Used by x86 to find stack for interrupt
struct segdesc gdt[NSEGS]; // x86 global descriptor table
char mpstack[MPSTACK]; // Per-CPU startup stack
volatile int booted; // Has the CPU started?
int nlock; // Number of locks currently held
};
extern struct cpu cpus[NCPU];

View file

@ -1,3 +1,20 @@
# int setjmp(struct jmpbuf *jmp);
# void longjmp(struct jmpbuf *jmp);
#
# Setjmp saves its stack environment in jmp
# for later use by longjmp. It returns 0.
#
# Longjmp restores the environment saved by
# the last call of setjmp. It then causes
# execution to continue as if the call of setjmp
# had just returned 1.
#
# The caller of setjmp must not itself have
# returned in the interim. All accessible data
# have values as of the time longjmp was called.
#
# [Description, but not code, borrowed from Plan 9.]
.globl setjmp
setjmp:
movl 4(%esp), %eax
@ -9,10 +26,10 @@ setjmp:
movl %edi, 16(%eax)
movl %esp, 20(%eax)
movl %ebp, 24(%eax)
pushl 0(%esp) /* %eip */
pushl 0(%esp) # %eip
popl 28(%eax)
movl $0, %eax /* return value */
movl $0, %eax # return value
ret
.globl longjmp
@ -27,8 +44,8 @@ longjmp:
movl 20(%eax), %esp
movl 24(%eax), %ebp
addl $4, %esp /* pop %eip into thin air */
pushl 28(%eax) /* push new %eip */
addl $4, %esp # pop and discard %eip
pushl 28(%eax) # push new %eip
movl $1, %eax /* return value (appears to come from setjmp!) */
movl $1, %eax # return value (appears to come from setjmp!)
ret

View file

@ -1,3 +1,5 @@
// Mutual exclusion spin locks.
#include "types.h"
#include "defs.h"
#include "x86.h"
@ -16,6 +18,7 @@ initlock(struct spinlock *lock, char *name)
lock->cpu = 0xffffffff;
}
// Record the current call stack in pcs[] by following the %ebp chain.
void
getcallerpcs(void *v, uint pcs[])
{
@ -31,6 +34,10 @@ getcallerpcs(void *v, uint pcs[])
pcs[i] = 0;
}
// Acquire the lock.
// Loops (spins) until the lock is acquired.
// (Because contention is handled by spinning, must not
// go to sleep holding any locks.)
void
acquire(struct spinlock *lock)
{
@ -44,10 +51,16 @@ acquire(struct spinlock *lock)
while(cmpxchg(0, 1, &lock->locked) == 1)
;
cpuid(0, 0, 0, 0, 0); // memory barrier
getcallerpcs(&lock, lock->pcs);
// Record info about lock acquisition for debugging.
// The +10 is only so that we can tell the difference
// between forgetting to initialize lock->cpu
// and holding a lock on cpu 0.
lock->cpu = cpu() + 10;
getcallerpcs(&lock, lock->pcs);
}
// Release the lock.
void
release(struct spinlock *lock)
{
@ -63,6 +76,7 @@ release(struct spinlock *lock)
sti();
}
// Check whether this cpu is holding the lock.
int
holding(struct spinlock *lock)
{

View file

@ -1,6 +1,10 @@
// Mutual exclusion lock.
struct spinlock {
char *name;
uint locked;
int cpu;
uint pcs[10];
uint locked; // Is the lock held?
// For debugging:
char *name; // Name of lock.
int cpu; // The number of the cpu holding the lock.
uint pcs[10]; // The call stack (an array of program counters)
// that locked the lock.
};

10
stat.h
View file

@ -1,7 +1,7 @@
struct stat {
int dev;
uint ino;
short type;
short nlink;
uint size;
int dev; // Device number
uint ino; // Inode number on device
short type; // Type of file
short nlink; // Number of links to file
uint size; // Size of file in bytes
};

14
trap.c
View file

@ -7,11 +7,11 @@
#include "traps.h"
#include "syscall.h"
// Interrupt descriptor table (shared by all CPUs).
struct gatedesc idt[256];
extern uint vectors[]; // in vectors.S: array of 256 entry pointers
extern void trapenter(void);
extern void trapenter1(void);
void
tvinit(void)
@ -65,30 +65,34 @@ trap(struct trapframe *tf)
return;
}
if(v == (IRQ_OFFSET + IRQ_IDE)){
if(v == IRQ_OFFSET + IRQ_IDE){
ide_intr();
cli(); // prevent a waiting interrupt from overflowing stack
lapic_eoi();
return;
}
if(v == (IRQ_OFFSET + IRQ_KBD)){
if(v == IRQ_OFFSET + IRQ_KBD){
kbd_intr();
cli(); // prevent a waiting interrupt from overflowing stack
lapic_eoi();
return;
}
if(v == (IRQ_OFFSET + IRQ_SPURIOUS)){
if(v == IRQ_OFFSET + IRQ_SPURIOUS){
cprintf("spurious interrupt from cpu %d eip %x\n", cpu(), tf->eip);
return; // no eoi for this one.
}
if(curproc[cpu()]) {
// assume process caused unexpected trap,
// for example by dividing by zero or dereferencing a bad pointer
cprintf("pid %d: unhandled trap %d on cpu %d eip %x -- kill proc\n",
curproc[cpu()]->pid, v, cpu(), tf->eip);
proc_exit();
}
// otherwise it's our mistake
cprintf("unexpected trap %d from cpu %d eip %x\n", v, cpu(), tf->eip);
panic("trap");
}

View file

@ -1,4 +1,6 @@
// system defined:
// x86 trap and interrupt constants.
// Processor-defined:
#define T_DIVIDE 0 // divide error
#define T_DEBUG 1 // debug exception
#define T_NMI 2 // non-maskable interrupt

4
x86.h
View file

@ -1,3 +1,6 @@
// Special assembly routines to access x86-specific
// hardware instructions.
static __inline uchar
inb(int port)
{
@ -124,6 +127,7 @@ sti(void)
__asm__ volatile("sti");
}
// Layout of the trap frame on the stack upon entry to trap.
struct trapframe {
// registers as pushed by pusha
uint edi;