more comments
This commit is contained in:
parent
7e019461c8
commit
31085bb416
13 changed files with 151 additions and 81 deletions
6
elf.h
6
elf.h
|
@ -1,9 +1,8 @@
|
||||||
//
|
// Format of an ELF executable file
|
||||||
// format of an ELF executable file
|
|
||||||
//
|
|
||||||
|
|
||||||
#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian
|
#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian
|
||||||
|
|
||||||
|
// File header
|
||||||
struct elfhdr {
|
struct elfhdr {
|
||||||
uint magic; // must equal ELF_MAGIC
|
uint magic; // must equal ELF_MAGIC
|
||||||
uchar elf[12];
|
uchar elf[12];
|
||||||
|
@ -22,6 +21,7 @@ struct elfhdr {
|
||||||
ushort shstrndx;
|
ushort shstrndx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Program section header
|
||||||
struct proghdr {
|
struct proghdr {
|
||||||
uint type;
|
uint type;
|
||||||
uint offset;
|
uint offset;
|
||||||
|
|
49
fs.h
49
fs.h
|
@ -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
|
#define BSIZE 512 // block size
|
||||||
|
|
||||||
// sector 1 (2nd sector)
|
// File system super block
|
||||||
struct superblock{
|
struct superblock {
|
||||||
uint size;
|
uint size; // Size of file system (bytes???) xxx
|
||||||
uint nblocks;
|
uint nblocks; // Number of blocks
|
||||||
uint ninodes;
|
uint ninodes; // Number of inodes.
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NADDRS (NDIRECT+1)
|
#define NADDRS (NDIRECT+1)
|
||||||
|
@ -15,24 +20,31 @@ struct superblock{
|
||||||
#define NINDIRECT (BSIZE / sizeof(uint))
|
#define NINDIRECT (BSIZE / sizeof(uint))
|
||||||
#define MAXFILE (NDIRECT + NINDIRECT)
|
#define MAXFILE (NDIRECT + NINDIRECT)
|
||||||
|
|
||||||
|
// On-disk inode structure
|
||||||
struct dinode {
|
struct dinode {
|
||||||
short type;
|
short type; // File type
|
||||||
short major;
|
short major; // Major device number (T_DEV only)
|
||||||
short minor;
|
short minor; // Minor device number (T_DEV only)
|
||||||
short nlink;
|
short nlink; // Number of links to inode in file system
|
||||||
uint size;
|
uint size; // Size of file (bytes)
|
||||||
uint addrs[NADDRS];
|
uint addrs[NADDRS]; // Data block addresses
|
||||||
};
|
};
|
||||||
|
|
||||||
#define T_DIR 1
|
#define T_DIR 1 // Directory
|
||||||
#define T_FILE 2
|
#define T_FILE 2 // File
|
||||||
#define T_DEV 3
|
#define T_DEV 3 // Special device
|
||||||
|
|
||||||
// sector 0 is unused, sector 1 is superblock, inodes start at sector 2
|
// Inodes per block.
|
||||||
#define IPB (BSIZE / sizeof(struct dinode))
|
#define IPB (BSIZE / sizeof(struct dinode))
|
||||||
#define IBLOCK(inum) (inum / IPB + 2) // start of inode
|
|
||||||
|
// Block containing inode i
|
||||||
|
#define IBLOCK(i) ((i) / IPB + 2)
|
||||||
|
|
||||||
|
// Bitmap bits per block
|
||||||
#define BPB (BSIZE*8)
|
#define BPB (BSIZE*8)
|
||||||
#define BBLOCK(b,ninodes) (b/BPB + (ninodes/IPB) + 3) // start of bitmap
|
|
||||||
|
// Block containing bit for block b
|
||||||
|
#define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3)
|
||||||
|
|
||||||
#define DIRSIZ 14
|
#define DIRSIZ 14
|
||||||
|
|
||||||
|
@ -41,4 +53,5 @@ struct dirent {
|
||||||
char name[DIRSIZ];
|
char name[DIRSIZ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern uint rootdev; // Device number of root file system
|
||||||
|
|
||||||
|
|
4
kalloc.c
4
kalloc.c
|
@ -40,6 +40,10 @@ kinit(void)
|
||||||
kfree(start, mem * PAGE);
|
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
|
void
|
||||||
kfree(char *cp, int len)
|
kfree(char *cp, int len)
|
||||||
{
|
{
|
||||||
|
|
1
mkdir.c
1
mkdir.c
|
@ -2,6 +2,7 @@
|
||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
|
|
||||||
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
5
proc.c
5
proc.c
|
@ -136,7 +136,9 @@ copyproc(struct proc *p)
|
||||||
return np;
|
return np;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
// Grow current process's memory by n bytes.
|
||||||
|
// Return old size on success, -1 on failure.
|
||||||
|
int
|
||||||
growproc(int n)
|
growproc(int n)
|
||||||
{
|
{
|
||||||
struct proc *cp = curproc[cpu()];
|
struct proc *cp = curproc[cpu()];
|
||||||
|
@ -154,6 +156,7 @@ growproc(int n)
|
||||||
return cp->sz - n;
|
return cp->sz - n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//PAGEBREAK: 42
|
||||||
// Per-CPU process scheduler.
|
// Per-CPU process scheduler.
|
||||||
// Each CPU calls scheduler() after setting itself up.
|
// Each CPU calls scheduler() after setting itself up.
|
||||||
// Scheduler never returns. It loops, doing:
|
// Scheduler never returns. It loops, doing:
|
||||||
|
|
68
proc.h
68
proc.h
|
@ -1,4 +1,4 @@
|
||||||
// segments in proc->gdt
|
// Segments in proc->gdt
|
||||||
#define SEG_KCODE 1 // kernel code
|
#define SEG_KCODE 1 // kernel code
|
||||||
#define SEG_KDATA 2 // kernel data+stack
|
#define SEG_KDATA 2 // kernel data+stack
|
||||||
#define SEG_UCODE 3
|
#define SEG_UCODE 3
|
||||||
|
@ -6,13 +6,14 @@
|
||||||
#define SEG_TSS 5 // this process's task state
|
#define SEG_TSS 5 // this process's task state
|
||||||
#define NSEGS 6
|
#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 {
|
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 ebx;
|
||||||
int ecx;
|
int ecx;
|
||||||
int edx;
|
int edx;
|
||||||
|
@ -25,39 +26,42 @@ struct jmpbuf {
|
||||||
|
|
||||||
enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
|
enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
|
||||||
|
|
||||||
struct proc{
|
// Per-process state
|
||||||
char *mem; // start of process's memory (a kernel address)
|
struct proc {
|
||||||
// process memory is laid out contiguously:
|
char *mem; // Start of process memory (kernel address)
|
||||||
// text
|
uint sz; // Size of process memory (bytes)
|
||||||
// original data and bss
|
char *kstack; // Bottom of kernel stack for this process
|
||||||
// fixed-size stack
|
enum proc_state state; // Process state
|
||||||
// expandable heap
|
int pid; // Process ID
|
||||||
uint sz; // user memory size
|
int ppid; // Parent pid
|
||||||
char *kstack; // kernel stack
|
void *chan; // If non-zero, sleeping on chan
|
||||||
enum proc_state state;
|
int killed; // If non-zero, have been killed
|
||||||
int pid;
|
struct file *ofile[NOFILE]; // Open files
|
||||||
int ppid;
|
struct inode *cwd; // Current directory
|
||||||
void *chan; // sleep
|
struct jmpbuf jmpbuf; // Jump here to run process
|
||||||
int killed;
|
struct trapframe *tf; // Trap frame for current interrupt
|
||||||
struct file *ofile[NOFILE];
|
|
||||||
struct inode *cwd;
|
|
||||||
struct jmpbuf jmpbuf;
|
|
||||||
struct trapframe *tf; // points into kstack, used to find user regs
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Process memory is laid out contiguously:
|
||||||
|
// text
|
||||||
|
// original data and bss
|
||||||
|
// fixed-size stack
|
||||||
|
// expandable heap
|
||||||
|
|
||||||
extern struct proc proc[];
|
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
|
#define MPSTACK 512
|
||||||
|
|
||||||
|
// Per-CPU state
|
||||||
struct cpu {
|
struct cpu {
|
||||||
uchar apicid; // Local APIC ID
|
uchar apicid; // Local APIC ID
|
||||||
struct jmpbuf jmpbuf;
|
struct jmpbuf jmpbuf; // Jump here to enter scheduler
|
||||||
struct taskstate ts; // only to give cpu address of kernel stack
|
struct taskstate ts; // Used by x86 to find stack for interrupt
|
||||||
struct segdesc gdt[NSEGS];
|
struct segdesc gdt[NSEGS]; // x86 global descriptor table
|
||||||
char mpstack[MPSTACK]; // per-cpu start-up stack
|
char mpstack[MPSTACK]; // Per-CPU startup stack
|
||||||
volatile int booted;
|
volatile int booted; // Has the CPU started?
|
||||||
int nlock; // # of locks currently held
|
int nlock; // Number of locks currently held
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct cpu cpus[NCPU];
|
extern struct cpu cpus[NCPU];
|
||||||
|
|
27
setjmp.S
27
setjmp.S
|
@ -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
|
.globl setjmp
|
||||||
setjmp:
|
setjmp:
|
||||||
movl 4(%esp), %eax
|
movl 4(%esp), %eax
|
||||||
|
@ -9,10 +26,10 @@ setjmp:
|
||||||
movl %edi, 16(%eax)
|
movl %edi, 16(%eax)
|
||||||
movl %esp, 20(%eax)
|
movl %esp, 20(%eax)
|
||||||
movl %ebp, 24(%eax)
|
movl %ebp, 24(%eax)
|
||||||
pushl 0(%esp) /* %eip */
|
pushl 0(%esp) # %eip
|
||||||
popl 28(%eax)
|
popl 28(%eax)
|
||||||
|
|
||||||
movl $0, %eax /* return value */
|
movl $0, %eax # return value
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.globl longjmp
|
.globl longjmp
|
||||||
|
@ -27,8 +44,8 @@ longjmp:
|
||||||
movl 20(%eax), %esp
|
movl 20(%eax), %esp
|
||||||
movl 24(%eax), %ebp
|
movl 24(%eax), %ebp
|
||||||
|
|
||||||
addl $4, %esp /* pop %eip into thin air */
|
addl $4, %esp # pop and discard %eip
|
||||||
pushl 28(%eax) /* push new %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
|
ret
|
||||||
|
|
16
spinlock.c
16
spinlock.c
|
@ -1,3 +1,5 @@
|
||||||
|
// Mutual exclusion spin locks.
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "x86.h"
|
#include "x86.h"
|
||||||
|
@ -16,6 +18,7 @@ initlock(struct spinlock *lock, char *name)
|
||||||
lock->cpu = 0xffffffff;
|
lock->cpu = 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record the current call stack in pcs[] by following the %ebp chain.
|
||||||
void
|
void
|
||||||
getcallerpcs(void *v, uint pcs[])
|
getcallerpcs(void *v, uint pcs[])
|
||||||
{
|
{
|
||||||
|
@ -31,6 +34,10 @@ getcallerpcs(void *v, uint pcs[])
|
||||||
pcs[i] = 0;
|
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
|
void
|
||||||
acquire(struct spinlock *lock)
|
acquire(struct spinlock *lock)
|
||||||
{
|
{
|
||||||
|
@ -44,10 +51,16 @@ acquire(struct spinlock *lock)
|
||||||
while(cmpxchg(0, 1, &lock->locked) == 1)
|
while(cmpxchg(0, 1, &lock->locked) == 1)
|
||||||
;
|
;
|
||||||
cpuid(0, 0, 0, 0, 0); // memory barrier
|
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;
|
lock->cpu = cpu() + 10;
|
||||||
|
getcallerpcs(&lock, lock->pcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Release the lock.
|
||||||
void
|
void
|
||||||
release(struct spinlock *lock)
|
release(struct spinlock *lock)
|
||||||
{
|
{
|
||||||
|
@ -63,6 +76,7 @@ release(struct spinlock *lock)
|
||||||
sti();
|
sti();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether this cpu is holding the lock.
|
||||||
int
|
int
|
||||||
holding(struct spinlock *lock)
|
holding(struct spinlock *lock)
|
||||||
{
|
{
|
||||||
|
|
12
spinlock.h
12
spinlock.h
|
@ -1,6 +1,10 @@
|
||||||
|
// Mutual exclusion lock.
|
||||||
struct spinlock {
|
struct spinlock {
|
||||||
char *name;
|
uint locked; // Is the lock held?
|
||||||
uint locked;
|
|
||||||
int cpu;
|
// For debugging:
|
||||||
uint pcs[10];
|
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
10
stat.h
|
@ -1,7 +1,7 @@
|
||||||
struct stat {
|
struct stat {
|
||||||
int dev;
|
int dev; // Device number
|
||||||
uint ino;
|
uint ino; // Inode number on device
|
||||||
short type;
|
short type; // Type of file
|
||||||
short nlink;
|
short nlink; // Number of links to file
|
||||||
uint size;
|
uint size; // Size of file in bytes
|
||||||
};
|
};
|
||||||
|
|
14
trap.c
14
trap.c
|
@ -7,11 +7,11 @@
|
||||||
#include "traps.h"
|
#include "traps.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
|
||||||
|
// Interrupt descriptor table (shared by all CPUs).
|
||||||
struct gatedesc idt[256];
|
struct gatedesc idt[256];
|
||||||
|
|
||||||
extern uint vectors[]; // in vectors.S: array of 256 entry pointers
|
extern uint vectors[]; // in vectors.S: array of 256 entry pointers
|
||||||
|
|
||||||
extern void trapenter(void);
|
|
||||||
extern void trapenter1(void);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
tvinit(void)
|
tvinit(void)
|
||||||
|
@ -65,30 +65,34 @@ trap(struct trapframe *tf)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(v == (IRQ_OFFSET + IRQ_IDE)){
|
if(v == IRQ_OFFSET + IRQ_IDE){
|
||||||
ide_intr();
|
ide_intr();
|
||||||
cli(); // prevent a waiting interrupt from overflowing stack
|
cli(); // prevent a waiting interrupt from overflowing stack
|
||||||
lapic_eoi();
|
lapic_eoi();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(v == (IRQ_OFFSET + IRQ_KBD)){
|
if(v == IRQ_OFFSET + IRQ_KBD){
|
||||||
kbd_intr();
|
kbd_intr();
|
||||||
cli(); // prevent a waiting interrupt from overflowing stack
|
cli(); // prevent a waiting interrupt from overflowing stack
|
||||||
lapic_eoi();
|
lapic_eoi();
|
||||||
return;
|
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);
|
cprintf("spurious interrupt from cpu %d eip %x\n", cpu(), tf->eip);
|
||||||
return; // no eoi for this one.
|
return; // no eoi for this one.
|
||||||
}
|
}
|
||||||
|
|
||||||
if(curproc[cpu()]) {
|
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",
|
cprintf("pid %d: unhandled trap %d on cpu %d eip %x -- kill proc\n",
|
||||||
curproc[cpu()]->pid, v, cpu(), tf->eip);
|
curproc[cpu()]->pid, v, cpu(), tf->eip);
|
||||||
proc_exit();
|
proc_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// otherwise it's our mistake
|
||||||
cprintf("unexpected trap %d from cpu %d eip %x\n", v, cpu(), tf->eip);
|
cprintf("unexpected trap %d from cpu %d eip %x\n", v, cpu(), tf->eip);
|
||||||
panic("trap");
|
panic("trap");
|
||||||
}
|
}
|
||||||
|
|
4
traps.h
4
traps.h
|
@ -1,4 +1,6 @@
|
||||||
// system defined:
|
// x86 trap and interrupt constants.
|
||||||
|
|
||||||
|
// Processor-defined:
|
||||||
#define T_DIVIDE 0 // divide error
|
#define T_DIVIDE 0 // divide error
|
||||||
#define T_DEBUG 1 // debug exception
|
#define T_DEBUG 1 // debug exception
|
||||||
#define T_NMI 2 // non-maskable interrupt
|
#define T_NMI 2 // non-maskable interrupt
|
||||||
|
|
4
x86.h
4
x86.h
|
@ -1,3 +1,6 @@
|
||||||
|
// Special assembly routines to access x86-specific
|
||||||
|
// hardware instructions.
|
||||||
|
|
||||||
static __inline uchar
|
static __inline uchar
|
||||||
inb(int port)
|
inb(int port)
|
||||||
{
|
{
|
||||||
|
@ -124,6 +127,7 @@ sti(void)
|
||||||
__asm__ volatile("sti");
|
__asm__ volatile("sti");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Layout of the trap frame on the stack upon entry to trap.
|
||||||
struct trapframe {
|
struct trapframe {
|
||||||
// registers as pushed by pusha
|
// registers as pushed by pusha
|
||||||
uint edi;
|
uint edi;
|
||||||
|
|
Loading…
Reference in a new issue