Initial version of single-cpu xv6 with page tables

This commit is contained in:
Frans Kaashoek 2010-07-02 14:51:53 -04:00
parent b7a517f227
commit 40889627ba
22 changed files with 307 additions and 152 deletions

View file

@ -25,12 +25,13 @@ OBJS = \
trap.o\ trap.o\
uart.o\ uart.o\
vectors.o\ vectors.o\
vm.o\
# Cross-compiling (e.g., on Mac OS X) # Cross-compiling (e.g., on Mac OS X)
#TOOLPREFIX = i386-jos-elf- TOOLPREFIX = i386-jos-elf-
# Using native tools (e.g., on X86 Linux) # Using native tools (e.g., on X86 Linux)
TOOLPREFIX = #TOOLPREFIX =
CC = $(TOOLPREFIX)gcc CC = $(TOOLPREFIX)gcc
AS = $(TOOLPREFIX)gas AS = $(TOOLPREFIX)gas

22
defs.h
View file

@ -60,9 +60,10 @@ extern uchar ioapicid;
void ioapicinit(void); void ioapicinit(void);
// kalloc.c // kalloc.c
extern int nfreemem;
char* kalloc(int); char* kalloc(int);
void kfree(char*, int); void kfree(char*, int);
void kinit(void); void kinit(char*,uint);
// kbd.c // kbd.c
void kbdintr(void); void kbdintr(void);
@ -101,8 +102,6 @@ int kill(int);
void pinit(void); void pinit(void);
void procdump(void); void procdump(void);
void scheduler(void) __attribute__((noreturn)); void scheduler(void) __attribute__((noreturn));
void ksegment(void);
void usegment(void);
void sleep(void*, struct spinlock*); void sleep(void*, struct spinlock*);
void userinit(void); void userinit(void);
int wait(void); int wait(void);
@ -111,6 +110,7 @@ void yield(void);
// swtch.S // swtch.S
void swtch(struct context**, struct context*); void swtch(struct context**, struct context*);
void jstack(uint);
// spinlock.c // spinlock.c
void acquire(struct spinlock*); void acquire(struct spinlock*);
@ -152,6 +152,22 @@ void uartinit(void);
void uartintr(void); void uartintr(void);
void uartputc(int); void uartputc(int);
// vm.c
#define PGROUNDUP(sz) ((sz+PGSIZE-1) & ~(PGSIZE-1))
void pminit(void);
void swkstack(void);
void vminit(void);
void printpgdir(uint*);
uint* setupkvm(void); // XXX need pde_t*
char* uva2ka(uint*, char*);
int allocuvm(uint*, char*, uint); // XXX need pde_t*
void freevm(uint*);
void inituvm(uint*, char*, char*, uint);
int loaduvm(uint*, char*, struct inode *ip, uint, uint);
uint* copyuvm(uint*,uint);
void ksegment(void);
void loadvm(struct proc*);
// number of elements in fixed-size array // number of elements in fixed-size array
#define NELEM(x) (sizeof(x)/sizeof((x)[0])) #define NELEM(x) (sizeof(x)/sizeof((x)[0]))

88
exec.c
View file

@ -11,12 +11,13 @@ exec(char *path, char **argv)
{ {
char *mem, *s, *last; char *mem, *s, *last;
int i, argc, arglen, len, off; int i, argc, arglen, len, off;
uint sz, sp, argp; uint sz, sp, spoffset, argp;
struct elfhdr elf; struct elfhdr elf;
struct inode *ip; struct inode *ip;
struct proghdr ph; struct proghdr ph;
pde_t *pgdir, *oldpgdir;
mem = 0; pgdir = 0;
sz = 0; sz = 0;
if((ip = namei(path)) == 0) if((ip = namei(path)) == 0)
@ -29,37 +30,8 @@ exec(char *path, char **argv)
if(elf.magic != ELF_MAGIC) if(elf.magic != ELF_MAGIC)
goto bad; goto bad;
// Compute memory size of new process. if (!(pgdir = setupkvm()))
// Program segments.
for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))
goto bad; goto bad;
if(ph.type != ELF_PROG_LOAD)
continue;
if(ph.memsz < ph.filesz)
goto bad;
sz += ph.memsz;
}
// Arguments.
arglen = 0;
for(argc=0; argv[argc]; argc++)
arglen += strlen(argv[argc]) + 1;
arglen = (arglen+3) & ~3;
sz += arglen;
sz += 4*(argc+1); // argv data
sz += 4; // argv
sz += 4; // argc
// Stack.
sz += PAGE;
// Allocate program memory.
sz = (sz+PAGE-1) & ~(PAGE-1);
mem = kalloc(sz);
if(mem == 0)
goto bad;
memset(mem, 0, sz);
// Load program into memory. // Load program into memory.
for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
@ -67,37 +39,48 @@ exec(char *path, char **argv)
goto bad; goto bad;
if(ph.type != ELF_PROG_LOAD) if(ph.type != ELF_PROG_LOAD)
continue; continue;
if(ph.va + ph.memsz < ph.va || ph.va + ph.memsz > sz)
goto bad;
if(ph.memsz < ph.filesz) if(ph.memsz < ph.filesz)
goto bad; goto bad;
if(readi(ip, mem + ph.va, ph.offset, ph.filesz) != ph.filesz) if (!allocuvm(pgdir, (char *)ph.va, ph.memsz))
goto bad;
sz += PGROUNDUP(ph.memsz);
if (!loaduvm(pgdir, (char *)ph.va, ip, ph.offset, ph.filesz))
goto bad; goto bad;
memset(mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
} }
iunlockput(ip); iunlockput(ip);
// Initialize stack. // Allocate and initialize stack at sz
if (!allocuvm(pgdir, (char *)sz, PGSIZE))
goto bad;
mem = uva2ka(pgdir, (char *)sz);
spoffset = sz;
sz += PGSIZE;
arglen = 0;
for(argc=0; argv[argc]; argc++)
arglen += strlen(argv[argc]) + 1;
arglen = (arglen+3) & ~3;
sp = sz; sp = sz;
argp = sz - arglen - 4*(argc+1); argp = sz - arglen - 4*(argc+1);
// Copy argv strings and pointers to stack. // Copy argv strings and pointers to stack.
*(uint*)(mem+argp + 4*argc) = 0; // argv[argc] *(uint*)(mem+argp-spoffset + 4*argc) = 0; // argv[argc]
for(i=argc-1; i>=0; i--){ for(i=argc-1; i>=0; i--){
len = strlen(argv[i]) + 1; len = strlen(argv[i]) + 1;
sp -= len; sp -= len;
memmove(mem+sp, argv[i], len); memmove(mem+sp-spoffset, argv[i], len);
*(uint*)(mem+argp + 4*i) = sp; // argv[i] *(uint*)(mem+argp-spoffset + 4*i) = sp; // argv[i]
} }
// Stack frame for main(argc, argv), below arguments. // Stack frame for main(argc, argv), below arguments.
sp = argp; sp = argp;
sp -= 4; sp -= 4;
*(uint*)(mem+sp) = argp; *(uint*)(mem+sp-spoffset) = argp;
sp -= 4; sp -= 4;
*(uint*)(mem+sp) = argc; *(uint*)(mem+sp-spoffset) = argc;
sp -= 4; sp -= 4;
*(uint*)(mem+sp) = 0xffffffff; // fake return pc *(uint*)(mem+sp-spoffset) = 0xffffffff; // fake return pc
// Save program name for debugging. // Save program name for debugging.
for(last=s=path; *s; s++) for(last=s=path; *s; s++)
@ -105,18 +88,25 @@ exec(char *path, char **argv)
last = s+1; last = s+1;
safestrcpy(proc->name, last, sizeof(proc->name)); safestrcpy(proc->name, last, sizeof(proc->name));
// Commit to the new image. // Commit to the user image.
kfree(proc->mem, proc->sz); oldpgdir = proc->pgdir;
proc->mem = mem; proc->pgdir = pgdir;
proc->sz = sz; proc->sz = sz;
proc->tf->eip = elf.entry; // main proc->tf->eip = elf.entry; // main
proc->tf->esp = sp; proc->tf->esp = sp;
usegment();
// printstack();
loadvm(proc);
freevm(oldpgdir);
// printstack();
return 0; return 0;
bad: bad:
if(mem) freevm(pgdir);
kfree(mem, sz);
iunlockput(ip); iunlockput(ip);
return -1; return -1;
} }

1
file.c
View file

@ -116,7 +116,6 @@ filewrite(struct file *f, char *addr, int n)
return pipewrite(f->pipe, addr, n); return pipewrite(f->pipe, addr, n);
if(f->type == FD_INODE){ if(f->type == FD_INODE){
ilock(f->ip); ilock(f->ip);
cprintf("filewrite: %d\n", n);
if((r = writei(f->ip, addr, f->off, n)) > 0) if((r = writei(f->ip, addr, f->off, n)) > 0)
f->off += r; f->off += r;
iunlock(f->ip); iunlock(f->ip);

View file

@ -5,6 +5,8 @@
#include "stat.h" #include "stat.h"
#include "user.h" #include "user.h"
#define N 1000
void void
printf(int fd, char *s, ...) printf(int fd, char *s, ...)
{ {
@ -18,7 +20,7 @@ forktest(void)
printf(1, "fork test\n"); printf(1, "fork test\n");
for(n=0; n<1000; n++){ for(n=0; n<N; n++){
pid = fork(); pid = fork();
if(pid < 0) if(pid < 0)
break; break;
@ -26,8 +28,8 @@ forktest(void)
exit(); exit();
} }
if(n == 1000){ if(n == N){
printf(1, "fork claimed to work 1000 times!\n"); printf(1, "fork claimed to work N times!\n", N);
exit(); exit();
} }

3
ide.c
View file

@ -147,8 +147,9 @@ iderw(struct buf *b)
// Wait for request to finish. // Wait for request to finish.
// Assuming will not sleep too long: ignore proc->killed. // Assuming will not sleep too long: ignore proc->killed.
while((b->flags & (B_VALID|B_DIRTY)) != B_VALID) while((b->flags & (B_VALID|B_DIRTY)) != B_VALID) {
sleep(b, &idelock); sleep(b, &idelock);
}
release(&idelock); release(&idelock);
} }

View file

@ -8,6 +8,7 @@
#include "types.h" #include "types.h"
#include "defs.h" #include "defs.h"
#include "param.h" #include "param.h"
#include "mmu.h"
#include "spinlock.h" #include "spinlock.h"
struct run { struct run {
@ -20,21 +21,28 @@ struct {
struct run *freelist; struct run *freelist;
} kmem; } kmem;
int nfreemem;
static void
printfreelist(void)
{
struct run *r, **rp;
cprintf("freelist:\n");
for(rp=&kmem.freelist; (r=*rp) != 0; rp=&r->next){
cprintf("0x%x %d=0x%x\n", r, r->len, r->len);
}
}
// Initialize free list of physical pages. // Initialize free list of physical pages.
// This code cheats by just considering one megabyte of // This code cheats by just considering one megabyte of
// pages after end. Real systems would determine the // pages after end. Real systems would determine the
// amount of memory available in the system and use it all. // amount of memory available in the system and use it all.
void void
kinit(void) kinit(char *p, uint len)
{ {
extern char end[];
uint len;
char *p;
initlock(&kmem.lock, "kmem"); initlock(&kmem.lock, "kmem");
p = (char*)(((uint)end + PAGE) & ~(PAGE-1)); cprintf("end 0x%x free = %d(0x%x)\n", p, len);
len = 256*PAGE; // assume computer has 256 pages of RAM, 1 MB nfreemem = 0;
cprintf("mem = %d\n", len);
kfree(p, len); kfree(p, len);
} }
@ -47,19 +55,23 @@ kfree(char *v, int len)
{ {
struct run *r, *rend, **rp, *p, *pend; struct run *r, *rend, **rp, *p, *pend;
if(len <= 0 || len % PAGE) if(len <= 0 || len % PGSIZE)
panic("kfree"); panic("kfree");
// Fill with junk to catch dangling refs. // Fill with junk to catch dangling refs.
memset(v, 1, len); memset(v, 1, len);
acquire(&kmem.lock); acquire(&kmem.lock);
nfreemem += len;
p = (struct run*)v; p = (struct run*)v;
pend = (struct run*)(v + len); pend = (struct run*)(v + len);
for(rp=&kmem.freelist; (r=*rp) != 0 && r <= pend; rp=&r->next){ for(rp=&kmem.freelist; (r=*rp) != 0 && r <= pend; rp=&r->next){
rend = (struct run*)((char*)r + r->len); rend = (struct run*)((char*)r + r->len);
if(r <= p && p < rend) if(r <= p && p < rend) {
cprintf("freeing a free page: r = 0x%x p = 0x%x rend = 0x%x\n",
r, p, rend);
panic("freeing free page"); panic("freeing free page");
}
if(rend == p){ // r before p: expand r to include p if(rend == p){ // r before p: expand r to include p
r->len += len; r->len += len;
if(r->next && r->next == pend){ // r now next to r->next? if(r->next && r->next == pend){ // r now next to r->next?
@ -93,7 +105,7 @@ kalloc(int n)
char *p; char *p;
struct run *r, **rp; struct run *r, **rp;
if(n % PAGE || n <= 0) if(n % PGSIZE || n <= 0)
panic("kalloc"); panic("kalloc");
acquire(&kmem.lock); acquire(&kmem.lock);
@ -103,6 +115,7 @@ kalloc(int n)
p = (char*)r + r->len; p = (char*)r + r->len;
if(r->len == 0) if(r->len == 0)
*rp = r->next; *rp = r->next;
nfreemem -= n;
release(&kmem.lock); release(&kmem.lock);
return p; return p;
} }
@ -112,3 +125,4 @@ kalloc(int n)
cprintf("kalloc: out of memory\n"); cprintf("kalloc: out of memory\n");
return 0; return 0;
} }

View file

@ -48,6 +48,7 @@ lapicw(int index, int value)
void void
lapicinit(int c) lapicinit(int c)
{ {
cprintf("lapicinit: %d 0x%x\n", c, lapic);
if(!lapic) if(!lapic)
return; return;

24
main.c
View file

@ -19,20 +19,27 @@ main(void)
ioapicinit(); // another interrupt controller ioapicinit(); // another interrupt controller
consoleinit(); // I/O devices & their interrupts consoleinit(); // I/O devices & their interrupts
uartinit(); // serial port uartinit(); // serial port
pminit(); // physical memory for kernel
jkstack(); // Jump to mainc on a proper-allocated kernel stack
}
void
mainc(void)
{
cprintf("cpus %p cpu %p\n", cpus, cpu); cprintf("cpus %p cpu %p\n", cpus, cpu);
cprintf("\ncpu%d: starting xv6\n\n", cpu->id); cprintf("\ncpu%d: starting xv6\n\n", cpu->id);
vminit(); // virtual memory
kinit(); // physical memory allocator
pinit(); // process table pinit(); // process table
tvinit(); // trap vectors tvinit(); // trap vectors
binit(); // buffer cache binit(); // buffer cache
fileinit(); // file table fileinit(); // file table
iinit(); // inode cache iinit(); // inode cache
ideinit(); // disk ideinit(); // disk
cprintf("ismp: %d\n", ismp);
if(!ismp) if(!ismp)
timerinit(); // uniprocessor timer timerinit(); // uniprocessor timer
userinit(); // first user process userinit(); // first user process
bootothers(); // start other processors // bootothers(); // start other processors XXX fix where to boot from
// Finish setting up this processor in mpmain. // Finish setting up this processor in mpmain.
mpmain(); mpmain();
@ -43,9 +50,12 @@ cprintf("cpus %p cpu %p\n", cpus, cpu);
static void static void
mpmain(void) mpmain(void)
{ {
if(cpunum() != mpbcpu()) if(cpunum() != mpbcpu()) {
lapicinit(cpunum());
ksegment(); ksegment();
cprintf("other cpu\n");
vminit();
lapicinit(cpunum());
}
cprintf("cpu%d: mpmain\n", cpu->id); cprintf("cpu%d: mpmain\n", cpu->id);
idtinit(); idtinit();
xchg(&cpu->booted, 1); xchg(&cpu->booted, 1);
@ -74,11 +84,15 @@ bootothers(void)
stack = kalloc(KSTACKSIZE); stack = kalloc(KSTACKSIZE);
*(void**)(code-4) = stack + KSTACKSIZE; *(void**)(code-4) = stack + KSTACKSIZE;
*(void**)(code-8) = mpmain; *(void**)(code-8) = mpmain;
cprintf("lapicstartap\n");
lapicstartap(c->id, (uint)code); lapicstartap(c->id, (uint)code);
cprintf("lapicstartap done\n");
// Wait for cpu to get through bootstrap. // Wait for cpu to get through bootstrap.
while(c->booted == 0) while(c->booted == 0)
; ;
cprintf("lapicstartap booted\n");
} }
} }

88
mmu.h
View file

@ -62,6 +62,8 @@ struct segdesc {
#define STA_R 0x2 // Readable (executable segments) #define STA_R 0x2 // Readable (executable segments)
#define STA_A 0x1 // Accessed #define STA_A 0x1 // Accessed
//
// System segment type bits // System segment type bits
#define STS_T16A 0x1 // Available 16-bit TSS #define STS_T16A 0x1 // Available 16-bit TSS
#define STS_LDT 0x2 // Local Descriptor Table #define STS_LDT 0x2 // Local Descriptor Table
@ -76,6 +78,92 @@ struct segdesc {
#define STS_IG32 0xE // 32-bit Interrupt Gate #define STS_IG32 0xE // 32-bit Interrupt Gate
#define STS_TG32 0xF // 32-bit Trap Gate #define STS_TG32 0xF // 32-bit Trap Gate
// A linear address 'la' has a three-part structure as follows:
//
// +--------10------+-------10-------+---------12----------+
// | Page Directory | Page Table | Offset within Page |
// | Index | Index | |
// +----------------+----------------+---------------------+
// \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/
// \----------- PPN(la) -----------/
//
// The PDX, PTX, PGOFF, and PPN macros decompose linear addresses as shown.
// To construct a linear address la from PDX(la), PTX(la), and PGOFF(la),
// use PGADDR(PDX(la), PTX(la), PGOFF(la)).
// page number field of address
#define PPN(la) (((uint) (la)) >> PTXSHIFT)
#define VPN(la) PPN(la) // used to index into vpt[]
// page directory index
#define PDX(la) ((((uint) (la)) >> PDXSHIFT) & 0x3FF)
#define VPD(la) PDX(la) // used to index into vpd[]
// page table index
#define PTX(la) ((((uint) (la)) >> PTXSHIFT) & 0x3FF)
// offset in page
#define PGOFF(la) (((uint) (la)) & 0xFFF)
// construct linear address from indexes and offset
#define PGADDR(d, t, o) ((uint) ((d) << PDXSHIFT | (t) << PTXSHIFT | (o)))
// mapping from physical addresses to virtual addresses is the identity one
// (really linear addresses, but we map linear to physical also directly)
#define PADDR(a) ((uint) a)
// Page directory and page table constants.
#define NPDENTRIES 1024 // page directory entries per page directory
#define NPTENTRIES 1024 // page table entries per page table
#define PGSIZE 4096 // bytes mapped by a page
#define PGSHIFT 12 // log2(PGSIZE)
#define PTSIZE (PGSIZE*NPTENTRIES) // bytes mapped by a page directory entry
#define PTSHIFT 22 // log2(PTSIZE)
#define PTXSHIFT 12 // offset of PTX in a linear address
#define PDXSHIFT 22 // offset of PDX in a linear address
// Page table/directory entry flags.
#define PTE_P 0x001 // Present
#define PTE_W 0x002 // Writeable
#define PTE_U 0x004 // User
#define PTE_PWT 0x008 // Write-Through
#define PTE_PCD 0x010 // Cache-Disable
#define PTE_A 0x020 // Accessed
#define PTE_D 0x040 // Dirty
#define PTE_PS 0x080 // Page Size
#define PTE_MBZ 0x180 // Bits must be zero
// The PTE_AVAIL bits aren't used by the kernel or interpreted by the
// hardware, so user processes are allowed to set them arbitrarily.
#define PTE_AVAIL 0xE00 // Available for software use
// Only flags in PTE_USER may be used in system calls.
#define PTE_USER (PTE_AVAIL | PTE_P | PTE_W | PTE_U)
// Address in page table or page directory entry
#define PTE_ADDR(pte) ((uint) (pte) & ~0xFFF)
typedef uint pte_t;
typedef uint pde_t;
// Control Register flags
#define CR0_PE 0x00000001 // Protection Enable
#define CR0_MP 0x00000002 // Monitor coProcessor
#define CR0_EM 0x00000004 // Emulation
#define CR0_TS 0x00000008 // Task Switched
#define CR0_ET 0x00000010 // Extension Type
#define CR0_NE 0x00000020 // Numeric Errror
#define CR0_WP 0x00010000 // Write Protect
#define CR0_AM 0x00040000 // Alignment Mask
#define CR0_NW 0x20000000 // Not Writethrough
#define CR0_CD 0x40000000 // Cache Disable
#define CR0_PG 0x80000000 // Paging
// PAGEBREAK: 40 // PAGEBREAK: 40
// Task state segment format // Task state segment format
struct taskstate { struct taskstate {

1
mp.c
View file

@ -39,6 +39,7 @@ mpsearch1(uchar *addr, int len)
{ {
uchar *e, *p; uchar *e, *p;
cprintf("mpsearch1 0x%x %d\n", addr, len);
e = addr+len; e = addr+len;
for(p = addr; p < e; p += sizeof(struct mp)) for(p = addr; p < e; p += sizeof(struct mp))
if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0) if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)

View file

@ -1,5 +1,5 @@
#define NPROC 64 // maximum number of processes #define NPROC 64 // maximum number of processes
#define PAGE 4096 // granularity of user-space memory allocation #define PAGE 4096 // conveniently chosen to be equal to PGSIZE
#define KSTACKSIZE PAGE // size of per-process kernel stack #define KSTACKSIZE PAGE // size of per-process kernel stack
#define NCPU 8 // maximum number of CPUs #define NCPU 8 // maximum number of CPUs
#define NOFILE 16 // open files per process #define NOFILE 16 // open files per process

72
proc.c
View file

@ -60,39 +60,6 @@ procdump(void)
} }
} }
// Set up CPU's kernel segment descriptors.
// Run once at boot time on each CPU.
void
ksegment(void)
{
struct cpu *c;
c = &cpus[cpunum()];
c->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0x100000 + 64*1024-1, 0);
c->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0);
c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 8, 0);
lgdt(c->gdt, sizeof(c->gdt));
loadgs(SEG_KCPU << 3);
// Initialize cpu-local storage.
cpu = c;
proc = 0;
}
// Set up CPU's segment descriptors and current process task state.
void
usegment(void)
{
pushcli();
cpu->gdt[SEG_UCODE] = SEG(STA_X|STA_R, proc->mem, proc->sz-1, DPL_USER);
cpu->gdt[SEG_UDATA] = SEG(STA_W, proc->mem, proc->sz-1, DPL_USER);
cpu->gdt[SEG_TSS] = SEG16(STS_T32A, &cpu->ts, sizeof(cpu->ts)-1, 0);
cpu->gdt[SEG_TSS].s = 0;
cpu->ts.ss0 = SEG_KDATA << 3;
cpu->ts.esp0 = (uint)proc->kstack + KSTACKSIZE;
ltr(SEG_TSS << 3);
popcli();
}
//PAGEBREAK: 32 //PAGEBREAK: 32
// Look in the process table for an UNUSED proc. // Look in the process table for an UNUSED proc.
@ -149,20 +116,19 @@ userinit(void)
p = allocproc(); p = allocproc();
initproc = p; initproc = p;
if (!(p->pgdir = setupkvm()))
// Initialize memory from initcode.S panic("userinit: out of memory?");
p->sz = PAGE; if (!allocuvm(p->pgdir, 0x0, (int)_binary_initcode_size))
p->mem = kalloc(p->sz); panic("userinit: out of memory?");
memset(p->mem, 0, p->sz); inituvm(p->pgdir, 0x0, _binary_initcode_start, (int)_binary_initcode_size);
memmove(p->mem, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PGROUNDUP((int)_binary_initcode_size);
memset(p->tf, 0, sizeof(*p->tf)); memset(p->tf, 0, sizeof(*p->tf));
p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->cs = (SEG_UCODE << 3) | DPL_USER;
p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER;
p->tf->es = p->tf->ds; p->tf->es = p->tf->ds;
p->tf->ss = p->tf->ds; p->tf->ss = p->tf->ds;
p->tf->eflags = FL_IF; p->tf->eflags = FL_IF;
p->tf->esp = p->sz; p->tf->esp = PGSIZE;
p->tf->eip = 0; // beginning of initcode.S p->tf->eip = 0; // beginning of initcode.S
safestrcpy(p->name, "initcode", sizeof(p->name)); safestrcpy(p->name, "initcode", sizeof(p->name));
@ -176,17 +142,10 @@ userinit(void)
int int
growproc(int n) growproc(int n)
{ {
char *newmem; if (!allocuvm(proc->pgdir, (char *)proc->sz, n))
newmem = kalloc(proc->sz + n);
if(newmem == 0)
return -1; return -1;
memmove(newmem, proc->mem, proc->sz);
memset(newmem + proc->sz, 0, n);
kfree(proc->mem, proc->sz);
proc->mem = newmem;
proc->sz += n; proc->sz += n;
usegment(); loadvm(proc);
return 0; return 0;
} }
@ -204,14 +163,13 @@ fork(void)
return -1; return -1;
// Copy process state from p. // Copy process state from p.
np->sz = proc->sz; if (!(np->pgdir = copyuvm(proc->pgdir, proc->sz))) {
if((np->mem = kalloc(np->sz)) == 0){
kfree(np->kstack, KSTACKSIZE); kfree(np->kstack, KSTACKSIZE);
np->kstack = 0; np->kstack = 0;
np->state = UNUSED; np->state = UNUSED;
return -1; return -1;
} }
memmove(np->mem, proc->mem, np->sz); np->sz = proc->sz;
np->parent = proc; np->parent = proc;
*np->tf = *proc->tf; *np->tf = *proc->tf;
@ -225,7 +183,7 @@ fork(void)
pid = np->pid; pid = np->pid;
np->state = RUNNABLE; np->state = RUNNABLE;
safestrcpy(np->name, proc->name, sizeof(proc->name));
return pid; return pid;
} }
@ -256,7 +214,7 @@ scheduler(void)
// to release ptable.lock and then reacquire it // to release ptable.lock and then reacquire it
// before jumping back to us. // before jumping back to us.
proc = p; proc = p;
usegment(); loadvm(p);
p->state = RUNNING; p->state = RUNNING;
swtch(&cpu->scheduler, proc->context); swtch(&cpu->scheduler, proc->context);
@ -284,7 +242,6 @@ sched(void)
panic("sched running"); panic("sched running");
if(readeflags()&FL_IF) if(readeflags()&FL_IF)
panic("sched interruptible"); panic("sched interruptible");
intena = cpu->intena; intena = cpu->intena;
swtch(&proc->context, cpu->scheduler); swtch(&proc->context, cpu->scheduler);
cpu->intena = intena; cpu->intena = intena;
@ -455,9 +412,10 @@ wait(void)
if(p->state == ZOMBIE){ if(p->state == ZOMBIE){
// Found one. // Found one.
pid = p->pid; pid = p->pid;
kfree(p->mem, p->sz);
kfree(p->kstack, KSTACKSIZE); kfree(p->kstack, KSTACKSIZE);
freevm(p->pgdir);
p->state = UNUSED; p->state = UNUSED;
p->kstack = 0;
p->pid = 0; p->pid = 0;
p->parent = 0; p->parent = 0;
p->name[0] = 0; p->name[0] = 0;

2
proc.h
View file

@ -30,8 +30,8 @@ enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
// Per-process state // Per-process state
struct proc { struct proc {
char *mem; // Start of process memory (kernel address)
uint sz; // Size of process memory (bytes) uint sz; // Size of process memory (bytes)
pde_t* pgdir; // linear address of proc's pgdir
char *kstack; // Bottom of kernel stack for this process char *kstack; // Bottom of kernel stack for this process
enum procstate state; // Process state enum procstate state; // Process state
volatile int pid; // Process ID volatile int pid; // Process ID

1
sh.c
View file

@ -420,6 +420,7 @@ parseexec(char **ps, char *es)
int tok, argc; int tok, argc;
struct execcmd *cmd; struct execcmd *cmd;
struct cmd *ret; struct cmd *ret;
int *x = (int *) peek;
if(peek(ps, es, "(")) if(peek(ps, es, "("))
return parseblock(ps, es); return parseblock(ps, es);

View file

@ -71,7 +71,7 @@ getcallerpcs(void *v, uint pcs[])
ebp = (uint*)v - 2; ebp = (uint*)v - 2;
for(i = 0; i < 10; i++){ for(i = 0; i < 10; i++){
if(ebp == 0 || ebp == (uint*)0xffffffff) if(ebp == 0 || ebp < 0x100000 || ebp == (uint*)0xffffffff)
break; break;
pcs[i] = ebp[1]; // saved %eip pcs[i] = ebp[1]; // saved %eip
ebp = (uint*)ebp[0]; // saved %ebp ebp = (uint*)ebp[0]; // saved %ebp

View file

@ -26,3 +26,11 @@ swtch:
popl %ebx popl %ebx
popl %ebp popl %ebp
ret ret
# Jump on a new stack, fake C calling conventions
.globl jstack
jstack:
movl 4(%esp), %esp
subl $16, %esp # space for arguments
movl $0, %ebp # terminate functions that follow ebp's
call mainc # continue at mainc

View file

@ -18,10 +18,12 @@ fetchint(struct proc *p, uint addr, int *ip)
{ {
if(addr >= p->sz || addr+4 > p->sz) if(addr >= p->sz || addr+4 > p->sz)
return -1; return -1;
*ip = *(int*)(p->mem + addr); *ip = *(int*)(addr);
return 0; return 0;
} }
// XXX should we copy the string?
// Fetch the nul-terminated string at addr from process p. // Fetch the nul-terminated string at addr from process p.
// Doesn't actually copy the string - just sets *pp to point at it. // Doesn't actually copy the string - just sets *pp to point at it.
// Returns length of string, not including nul. // Returns length of string, not including nul.
@ -32,8 +34,10 @@ fetchstr(struct proc *p, uint addr, char **pp)
if(addr >= p->sz) if(addr >= p->sz)
return -1; return -1;
*pp = p->mem + addr; // *pp = p->mem + addr;
ep = p->mem + p->sz; // ep = p->mem + p->sz;
*pp = (char **) addr;
ep = p->sz;
for(s = *pp; s < ep; s++) for(s = *pp; s < ep; s++)
if(*s == 0) if(*s == 0)
return s - *pp; return s - *pp;
@ -44,7 +48,8 @@ fetchstr(struct proc *p, uint addr, char **pp)
int int
argint(int n, int *ip) argint(int n, int *ip)
{ {
return fetchint(proc, proc->tf->esp + 4 + 4*n, ip); int x = fetchint(proc, proc->tf->esp + 4 + 4*n, ip);
return x;
} }
// Fetch the nth word-sized system call argument as a pointer // Fetch the nth word-sized system call argument as a pointer
@ -59,7 +64,8 @@ argptr(int n, char **pp, int size)
return -1; return -1;
if((uint)i >= proc->sz || (uint)i+size >= proc->sz) if((uint)i >= proc->sz || (uint)i+size >= proc->sz)
return -1; return -1;
*pp = proc->mem + i; // *pp = proc->mem + i; // XXXXX
*pp = (char *) i; // XXXXX
return 0; return 0;
} }

View file

@ -264,7 +264,6 @@ sys_open(void)
if(argstr(0, &path) < 0 || argint(1, &omode) < 0) if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
return -1; return -1;
if(omode & O_CREATE){ if(omode & O_CREATE){
if((ip = create(path, T_FILE, 0, 0)) == 0) if((ip = create(path, T_FILE, 0, 0)) == 0)
return -1; return -1;
@ -291,7 +290,6 @@ sys_open(void)
f->off = 0; f->off = 0;
f->readable = !(omode & O_WRONLY); f->readable = !(omode & O_WRONLY);
f->writable = (omode & O_WRONLY) || (omode & O_RDWR); f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
return fd; return fd;
} }
@ -350,8 +348,9 @@ sys_exec(void)
int i; int i;
uint uargv, uarg; uint uargv, uarg;
if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0) if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0) {
return -1; return -1;
}
memset(argv, 0, sizeof(argv)); memset(argv, 0, sizeof(argv));
for(i=0;; i++){ for(i=0;; i++){
if(i >= NELEM(argv)) if(i >= NELEM(argv))

9
trap.c
View file

@ -78,13 +78,14 @@ trap(struct trapframe *tf)
default: default:
if(proc == 0 || (tf->cs&3) == 0){ if(proc == 0 || (tf->cs&3) == 0){
// In kernel, it must be our mistake. // In kernel, it must be our mistake.
cprintf("unexpected trap %d from cpu %d eip %x\n", cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n",
tf->trapno, cpu->id, tf->eip); tf->trapno, cpu->id, tf->eip, rcr2());
panic("trap"); panic("trap");
} }
// In user space, assume process misbehaved. // In user space, assume process misbehaved.
cprintf("pid %d %s: trap %d err %d on cpu %d eip %x -- kill proc\n", cprintf("pid %d %s: trap %d err %d on cpu %d eip 0x%x addr 0x%x--kill proc\n",
proc->pid, proc->name, tf->trapno, tf->err, cpu->id, tf->eip); proc->pid, proc->name, tf->trapno, tf->err, cpu->id, tf->eip,
rcr2());
proc->killed = 1; proc->killed = 1;
} }

55
x86.h
View file

@ -121,6 +121,61 @@ sti(void)
asm volatile("sti"); asm volatile("sti");
} }
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 lebp(uint val)
{
asm volatile("movl %0,%%ebp" : : "r" (val));
}
static inline uint rebp(void)
{
uint val;
asm volatile("movl %%ebp,%0" : "=r" (val));
return val;
}
static inline void lesp(uint val)
{
asm volatile("movl %0,%%esp" : : "r" (val));
}
static inline uint resp(void)
{
uint val;
asm volatile("movl %%esp,%0" : "=r" (val));
return val;
}
//PAGEBREAK: 36 //PAGEBREAK: 36
// Layout of the trap frame built on the stack by the // Layout of the trap frame built on the stack by the
// hardware and by trapasm.S, and passed to trap(). // hardware and by trapasm.S, and passed to trap().