Skip to content

Commit

Permalink
Initial version of single-cpu xv6 with page tables
Browse files Browse the repository at this point in the history
  • Loading branch information
Frans Kaashoek committed Jul 2, 2010
1 parent b7a517f commit 4088962
Show file tree
Hide file tree
Showing 22 changed files with 307 additions and 152 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ OBJS = \
trap.o\
uart.o\
vectors.o\
vm.o\

# Cross-compiling (e.g., on Mac OS X)
#TOOLPREFIX = i386-jos-elf-
TOOLPREFIX = i386-jos-elf-

# Using native tools (e.g., on X86 Linux)
TOOLPREFIX =
#TOOLPREFIX =

CC = $(TOOLPREFIX)gcc
AS = $(TOOLPREFIX)gas
Expand Down
2 changes: 1 addition & 1 deletion bootasm.S
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,5 @@ gdt:
SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg

gdtdesc:
.word (gdtdesc - gdt - 1) # sizeof(gdt) - 1
.word (gdtdesc - gdt - 1) # sizeof(gdt) - 1
.long gdt # address gdt
22 changes: 19 additions & 3 deletions defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ extern uchar ioapicid;
void ioapicinit(void);

// kalloc.c
extern int nfreemem;
char* kalloc(int);
void kfree(char*, int);
void kinit(void);
void kinit(char*,uint);

// kbd.c
void kbdintr(void);
Expand Down Expand Up @@ -101,8 +102,6 @@ int kill(int);
void pinit(void);
void procdump(void);
void scheduler(void) __attribute__((noreturn));
void ksegment(void);
void usegment(void);
void sleep(void*, struct spinlock*);
void userinit(void);
int wait(void);
Expand All @@ -111,6 +110,7 @@ void yield(void);

// swtch.S
void swtch(struct context**, struct context*);
void jstack(uint);

// spinlock.c
void acquire(struct spinlock*);
Expand Down Expand Up @@ -152,6 +152,22 @@ void uartinit(void);
void uartintr(void);
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
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))

90 changes: 40 additions & 50 deletions exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ exec(char *path, char **argv)
{
char *mem, *s, *last;
int i, argc, arglen, len, off;
uint sz, sp, argp;
uint sz, sp, spoffset, argp;
struct elfhdr elf;
struct inode *ip;
struct proghdr ph;
pde_t *pgdir, *oldpgdir;

mem = 0;
pgdir = 0;
sz = 0;

if((ip = namei(path)) == 0)
Expand All @@ -29,94 +30,83 @@ exec(char *path, char **argv)
if(elf.magic != ELF_MAGIC)
goto bad;

// Compute memory size of new process.
// 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;
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)
if (!(pgdir = setupkvm()))
goto bad;
memset(mem, 0, sz);

// Load program into memory.
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;
if(ph.type != ELF_PROG_LOAD)
continue;
if(ph.va + ph.memsz < ph.va || ph.va + ph.memsz > sz)
goto bad;
if(ph.memsz < ph.filesz)
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;
memset(mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
}
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;
argp = sz - arglen - 4*(argc+1);

// 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--){
len = strlen(argv[i]) + 1;
sp -= len;
memmove(mem+sp, argv[i], len);
*(uint*)(mem+argp + 4*i) = sp; // argv[i]
memmove(mem+sp-spoffset, argv[i], len);
*(uint*)(mem+argp-spoffset + 4*i) = sp; // argv[i]
}

// Stack frame for main(argc, argv), below arguments.
sp = argp;
sp -= 4;
*(uint*)(mem+sp) = argp;
*(uint*)(mem+sp-spoffset) = argp;
sp -= 4;
*(uint*)(mem+sp) = argc;
*(uint*)(mem+sp-spoffset) = argc;
sp -= 4;
*(uint*)(mem+sp) = 0xffffffff; // fake return pc
*(uint*)(mem+sp-spoffset) = 0xffffffff; // fake return pc

// Save program name for debugging.
for(last=s=path; *s; s++)
if(*s == '/')
last = s+1;
safestrcpy(proc->name, last, sizeof(proc->name));

// Commit to the new image.
kfree(proc->mem, proc->sz);
proc->mem = mem;
// Commit to the user image.
oldpgdir = proc->pgdir;
proc->pgdir = pgdir;
proc->sz = sz;
proc->tf->eip = elf.entry; // main
proc->tf->esp = sp;
usegment();

// printstack();

loadvm(proc);

freevm(oldpgdir);

// printstack();

return 0;

bad:
if(mem)
kfree(mem, sz);
freevm(pgdir);
iunlockput(ip);
return -1;
}
1 change: 0 additions & 1 deletion file.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ filewrite(struct file *f, char *addr, int n)
return pipewrite(f->pipe, addr, n);
if(f->type == FD_INODE){
ilock(f->ip);
cprintf("filewrite: %d\n", n);
if((r = writei(f->ip, addr, f->off, n)) > 0)
f->off += r;
iunlock(f->ip);
Expand Down
8 changes: 5 additions & 3 deletions forktest.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "stat.h"
#include "user.h"

#define N 1000

void
printf(int fd, char *s, ...)
{
Expand All @@ -18,16 +20,16 @@ forktest(void)

printf(1, "fork test\n");

for(n=0; n<1000; n++){
for(n=0; n<N; n++){
pid = fork();
if(pid < 0)
break;
if(pid == 0)
exit();
}

if(n == 1000){
printf(1, "fork claimed to work 1000 times!\n");
if(n == N){
printf(1, "fork claimed to work N times!\n", N);
exit();
}

Expand Down
3 changes: 2 additions & 1 deletion ide.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,9 @@ iderw(struct buf *b)

// Wait for request to finish.
// 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);
}

release(&idelock);
}
36 changes: 25 additions & 11 deletions kalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "types.h"
#include "defs.h"
#include "param.h"
#include "mmu.h"
#include "spinlock.h"

struct run {
Expand All @@ -20,21 +21,28 @@ struct {
struct run *freelist;
} 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.
// This code cheats by just considering one megabyte of
// pages after end. Real systems would determine the
// amount of memory available in the system and use it all.
void
kinit(void)
kinit(char *p, uint len)
{
extern char end[];
uint len;
char *p;

initlock(&kmem.lock, "kmem");
p = (char*)(((uint)end + PAGE) & ~(PAGE-1));
len = 256*PAGE; // assume computer has 256 pages of RAM, 1 MB
cprintf("mem = %d\n", len);
cprintf("end 0x%x free = %d(0x%x)\n", p, len);
nfreemem = 0;
kfree(p, len);
}

Expand All @@ -47,19 +55,23 @@ kfree(char *v, int len)
{
struct run *r, *rend, **rp, *p, *pend;

if(len <= 0 || len % PAGE)
if(len <= 0 || len % PGSIZE)
panic("kfree");

// Fill with junk to catch dangling refs.
memset(v, 1, len);

acquire(&kmem.lock);
nfreemem += len;
p = (struct run*)v;
pend = (struct run*)(v + len);
for(rp=&kmem.freelist; (r=*rp) != 0 && r <= pend; rp=&r->next){
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");
}
if(rend == p){ // r before p: expand r to include p
r->len += len;
if(r->next && r->next == pend){ // r now next to r->next?
Expand Down Expand Up @@ -93,7 +105,7 @@ kalloc(int n)
char *p;
struct run *r, **rp;

if(n % PAGE || n <= 0)
if(n % PGSIZE || n <= 0)
panic("kalloc");

acquire(&kmem.lock);
Expand All @@ -103,6 +115,7 @@ kalloc(int n)
p = (char*)r + r->len;
if(r->len == 0)
*rp = r->next;
nfreemem -= n;
release(&kmem.lock);
return p;
}
Expand All @@ -112,3 +125,4 @@ kalloc(int n)
cprintf("kalloc: out of memory\n");
return 0;
}

1 change: 1 addition & 0 deletions lapic.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ lapicw(int index, int value)
void
lapicinit(int c)
{
cprintf("lapicinit: %d 0x%x\n", c, lapic);
if(!lapic)
return;

Expand Down
Loading

0 comments on commit 4088962

Please sign in to comment.