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
|
||||
|
||||
// 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
53
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
|
||||
|
||||
// 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
|
||||
|
||||
|
|
4
kalloc.c
4
kalloc.c
|
@ -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)
|
||||
{
|
||||
|
|
1
mkdir.c
1
mkdir.c
|
@ -2,6 +2,7 @@
|
|||
#include "stat.h"
|
||||
#include "user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
|
5
proc.c
5
proc.c
|
@ -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
76
proc.h
|
@ -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];
|
||||
|
|
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
|
||||
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
|
||||
|
|
16
spinlock.c
16
spinlock.c
|
@ -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)
|
||||
{
|
||||
|
|
12
spinlock.h
12
spinlock.h
|
@ -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
10
stat.h
|
@ -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
14
trap.c
|
@ -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");
|
||||
}
|
||||
|
|
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_DEBUG 1 // debug exception
|
||||
#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
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue