Initial version of single-cpu xv6 with page tables
This commit is contained in:
parent
b7a517f227
commit
40889627ba
22 changed files with 307 additions and 152 deletions
5
Makefile
5
Makefile
|
@ -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
22
defs.h
|
@ -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
88
exec.c
|
@ -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
1
file.c
|
@ -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);
|
||||||
|
|
|
@ -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
3
ide.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
36
kalloc.c
36
kalloc.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
lapic.c
1
lapic.c
|
@ -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
24
main.c
|
@ -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
88
mmu.h
|
@ -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
1
mp.c
|
@ -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)
|
||||||
|
|
2
param.h
2
param.h
|
@ -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
72
proc.c
|
@ -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
2
proc.h
|
@ -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
1
sh.c
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
8
swtch.S
8
swtch.S
|
@ -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
|
||||||
|
|
16
syscall.c
16
syscall.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
9
trap.c
|
@ -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
55
x86.h
|
@ -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().
|
||||||
|
|
Loading…
Reference in a new issue