Initial version of single-cpu xv6 with page tables
This commit is contained in:
parent
b7a517f227
commit
40889627ba
5
Makefile
5
Makefile
|
@ -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
|
||||
|
|
|
@ -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
defs.h
22
defs.h
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -111,6 +110,7 @@ void yield(void);
|
|||
|
||||
// swtch.S
|
||||
void swtch(struct context**, struct context*);
|
||||
void jstack(uint);
|
||||
|
||||
// spinlock.c
|
||||
void acquire(struct spinlock*);
|
||||
|
@ -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
exec.c
90
exec.c
|
@ -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)
|
||||
|
@ -29,37 +30,8 @@ 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)){
|
||||
|
@ -67,37 +39,48 @@ exec(char *path, char **argv)
|
|||
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++)
|
||||
|
@ -105,18 +88,25 @@ exec(char *path, char **argv)
|
|||
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
file.c
1
file.c
|
@ -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);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "stat.h"
|
||||
#include "user.h"
|
||||
|
||||
#define N 1000
|
||||
|
||||
void
|
||||
printf(int fd, char *s, ...)
|
||||
{
|
||||
|
@ -18,7 +20,7 @@ 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;
|
||||
|
@ -26,8 +28,8 @@ forktest(void)
|
|||
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();
|
||||
}
|
||||
|
||||
|
|
3
ide.c
3
ide.c
|
@ -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
kalloc.c
36
kalloc.c
|
@ -8,6 +8,7 @@
|
|||
#include "types.h"
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "mmu.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
struct run {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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?
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -112,3 +125,4 @@ kalloc(int n)
|
|||
cprintf("kalloc: out of memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
1
lapic.c
1
lapic.c
|
@ -48,6 +48,7 @@ lapicw(int index, int value)
|
|||
void
|
||||
lapicinit(int c)
|
||||
{
|
||||
cprintf("lapicinit: %d 0x%x\n", c, lapic);
|
||||
if(!lapic)
|
||||
return;
|
||||
|
||||
|
|
26
main.c
26
main.c
|
@ -19,20 +19,27 @@ main(void)
|
|||
ioapicinit(); // another interrupt controller
|
||||
consoleinit(); // I/O devices & their interrupts
|
||||
uartinit(); // serial port
|
||||
cprintf("cpus %p cpu %p\n", cpus, cpu);
|
||||
cprintf("\ncpu%d: starting xv6\n\n", cpu->id);
|
||||
pminit(); // physical memory for kernel
|
||||
jkstack(); // Jump to mainc on a proper-allocated kernel stack
|
||||
}
|
||||
|
||||
kinit(); // physical memory allocator
|
||||
void
|
||||
mainc(void)
|
||||
{
|
||||
cprintf("cpus %p cpu %p\n", cpus, cpu);
|
||||
cprintf("\ncpu%d: starting xv6\n\n", cpu->id);
|
||||
vminit(); // virtual memory
|
||||
pinit(); // process table
|
||||
tvinit(); // trap vectors
|
||||
binit(); // buffer cache
|
||||
fileinit(); // file table
|
||||
iinit(); // inode cache
|
||||
ideinit(); // disk
|
||||
cprintf("ismp: %d\n", ismp);
|
||||
if(!ismp)
|
||||
timerinit(); // uniprocessor timer
|
||||
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.
|
||||
mpmain();
|
||||
|
@ -43,9 +50,12 @@ cprintf("cpus %p cpu %p\n", cpus, cpu);
|
|||
static void
|
||||
mpmain(void)
|
||||
{
|
||||
if(cpunum() != mpbcpu())
|
||||
if(cpunum() != mpbcpu()) {
|
||||
ksegment();
|
||||
cprintf("other cpu\n");
|
||||
vminit();
|
||||
lapicinit(cpunum());
|
||||
ksegment();
|
||||
}
|
||||
cprintf("cpu%d: mpmain\n", cpu->id);
|
||||
idtinit();
|
||||
xchg(&cpu->booted, 1);
|
||||
|
@ -74,11 +84,15 @@ bootothers(void)
|
|||
stack = kalloc(KSTACKSIZE);
|
||||
*(void**)(code-4) = stack + KSTACKSIZE;
|
||||
*(void**)(code-8) = mpmain;
|
||||
cprintf("lapicstartap\n");
|
||||
lapicstartap(c->id, (uint)code);
|
||||
cprintf("lapicstartap done\n");
|
||||
|
||||
// Wait for cpu to get through bootstrap.
|
||||
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_A 0x1 // Accessed
|
||||
|
||||
//
|
||||
|
||||
// System segment type bits
|
||||
#define STS_T16A 0x1 // Available 16-bit TSS
|
||||
#define STS_LDT 0x2 // Local Descriptor Table
|
||||
|
@ -76,6 +78,92 @@ struct segdesc {
|
|||
#define STS_IG32 0xE // 32-bit Interrupt 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
|
||||
// Task state segment format
|
||||
struct taskstate {
|
||||
|
|
1
mp.c
1
mp.c
|
@ -39,6 +39,7 @@ mpsearch1(uchar *addr, int len)
|
|||
{
|
||||
uchar *e, *p;
|
||||
|
||||
cprintf("mpsearch1 0x%x %d\n", addr, len);
|
||||
e = addr+len;
|
||||
for(p = addr; p < e; p += sizeof(struct mp))
|
||||
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 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 NCPU 8 // maximum number of CPUs
|
||||
#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
|
||||
// Look in the process table for an UNUSED proc.
|
||||
|
@ -149,20 +116,19 @@ userinit(void)
|
|||
|
||||
p = allocproc();
|
||||
initproc = p;
|
||||
|
||||
// Initialize memory from initcode.S
|
||||
p->sz = PAGE;
|
||||
p->mem = kalloc(p->sz);
|
||||
memset(p->mem, 0, p->sz);
|
||||
memmove(p->mem, _binary_initcode_start, (int)_binary_initcode_size);
|
||||
|
||||
if (!(p->pgdir = setupkvm()))
|
||||
panic("userinit: out of memory?");
|
||||
if (!allocuvm(p->pgdir, 0x0, (int)_binary_initcode_size))
|
||||
panic("userinit: out of memory?");
|
||||
inituvm(p->pgdir, 0x0, _binary_initcode_start, (int)_binary_initcode_size);
|
||||
p->sz = PGROUNDUP((int)_binary_initcode_size);
|
||||
memset(p->tf, 0, sizeof(*p->tf));
|
||||
p->tf->cs = (SEG_UCODE << 3) | DPL_USER;
|
||||
p->tf->ds = (SEG_UDATA << 3) | DPL_USER;
|
||||
p->tf->es = p->tf->ds;
|
||||
p->tf->ss = p->tf->ds;
|
||||
p->tf->eflags = FL_IF;
|
||||
p->tf->esp = p->sz;
|
||||
p->tf->esp = PGSIZE;
|
||||
p->tf->eip = 0; // beginning of initcode.S
|
||||
|
||||
safestrcpy(p->name, "initcode", sizeof(p->name));
|
||||
|
@ -176,17 +142,10 @@ userinit(void)
|
|||
int
|
||||
growproc(int n)
|
||||
{
|
||||
char *newmem;
|
||||
|
||||
newmem = kalloc(proc->sz + n);
|
||||
if(newmem == 0)
|
||||
if (!allocuvm(proc->pgdir, (char *)proc->sz, n))
|
||||
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;
|
||||
usegment();
|
||||
loadvm(proc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -204,14 +163,13 @@ fork(void)
|
|||
return -1;
|
||||
|
||||
// Copy process state from p.
|
||||
np->sz = proc->sz;
|
||||
if((np->mem = kalloc(np->sz)) == 0){
|
||||
if (!(np->pgdir = copyuvm(proc->pgdir, proc->sz))) {
|
||||
kfree(np->kstack, KSTACKSIZE);
|
||||
np->kstack = 0;
|
||||
np->state = UNUSED;
|
||||
return -1;
|
||||
}
|
||||
memmove(np->mem, proc->mem, np->sz);
|
||||
np->sz = proc->sz;
|
||||
np->parent = proc;
|
||||
*np->tf = *proc->tf;
|
||||
|
||||
|
@ -225,7 +183,7 @@ fork(void)
|
|||
|
||||
pid = np->pid;
|
||||
np->state = RUNNABLE;
|
||||
|
||||
safestrcpy(np->name, proc->name, sizeof(proc->name));
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
@ -256,7 +214,7 @@ scheduler(void)
|
|||
// to release ptable.lock and then reacquire it
|
||||
// before jumping back to us.
|
||||
proc = p;
|
||||
usegment();
|
||||
loadvm(p);
|
||||
p->state = RUNNING;
|
||||
swtch(&cpu->scheduler, proc->context);
|
||||
|
||||
|
@ -284,7 +242,6 @@ sched(void)
|
|||
panic("sched running");
|
||||
if(readeflags()&FL_IF)
|
||||
panic("sched interruptible");
|
||||
|
||||
intena = cpu->intena;
|
||||
swtch(&proc->context, cpu->scheduler);
|
||||
cpu->intena = intena;
|
||||
|
@ -455,9 +412,10 @@ wait(void)
|
|||
if(p->state == ZOMBIE){
|
||||
// Found one.
|
||||
pid = p->pid;
|
||||
kfree(p->mem, p->sz);
|
||||
kfree(p->kstack, KSTACKSIZE);
|
||||
freevm(p->pgdir);
|
||||
p->state = UNUSED;
|
||||
p->kstack = 0;
|
||||
p->pid = 0;
|
||||
p->parent = 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
|
||||
struct proc {
|
||||
char *mem; // Start of process memory (kernel address)
|
||||
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
|
||||
enum procstate state; // Process state
|
||||
volatile int pid; // Process ID
|
||||
|
|
5
sh.c
5
sh.c
|
@ -330,7 +330,7 @@ parsecmd(char *s)
|
|||
{
|
||||
char *es;
|
||||
struct cmd *cmd;
|
||||
|
||||
|
||||
es = s + strlen(s);
|
||||
cmd = parseline(&s, es);
|
||||
peek(&s, es, "");
|
||||
|
@ -363,7 +363,7 @@ struct cmd*
|
|||
parsepipe(char **ps, char *es)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
|
||||
cmd = parseexec(ps, es);
|
||||
if(peek(ps, es, "|")){
|
||||
gettoken(ps, es, 0, 0);
|
||||
|
@ -420,6 +420,7 @@ parseexec(char **ps, char *es)
|
|||
int tok, argc;
|
||||
struct execcmd *cmd;
|
||||
struct cmd *ret;
|
||||
int *x = (int *) peek;
|
||||
|
||||
if(peek(ps, es, "("))
|
||||
return parseblock(ps, es);
|
||||
|
|
|
@ -71,7 +71,7 @@ getcallerpcs(void *v, uint pcs[])
|
|||
|
||||
ebp = (uint*)v - 2;
|
||||
for(i = 0; i < 10; i++){
|
||||
if(ebp == 0 || ebp == (uint*)0xffffffff)
|
||||
if(ebp == 0 || ebp < 0x100000 || ebp == (uint*)0xffffffff)
|
||||
break;
|
||||
pcs[i] = ebp[1]; // saved %eip
|
||||
ebp = (uint*)ebp[0]; // saved %ebp
|
||||
|
|
8
swtch.S
8
swtch.S
|
@ -26,3 +26,11 @@ swtch:
|
|||
popl %ebx
|
||||
popl %ebp
|
||||
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)
|
||||
return -1;
|
||||
*ip = *(int*)(p->mem + addr);
|
||||
*ip = *(int*)(addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// XXX should we copy the string?
|
||||
|
||||
// Fetch the nul-terminated string at addr from process p.
|
||||
// Doesn't actually copy the string - just sets *pp to point at it.
|
||||
// Returns length of string, not including nul.
|
||||
|
@ -32,8 +34,10 @@ fetchstr(struct proc *p, uint addr, char **pp)
|
|||
|
||||
if(addr >= p->sz)
|
||||
return -1;
|
||||
*pp = p->mem + addr;
|
||||
ep = p->mem + p->sz;
|
||||
// *pp = p->mem + addr;
|
||||
// ep = p->mem + p->sz;
|
||||
*pp = (char **) addr;
|
||||
ep = p->sz;
|
||||
for(s = *pp; s < ep; s++)
|
||||
if(*s == 0)
|
||||
return s - *pp;
|
||||
|
@ -44,7 +48,8 @@ fetchstr(struct proc *p, uint addr, char **pp)
|
|||
int
|
||||
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
|
||||
|
@ -59,7 +64,8 @@ argptr(int n, char **pp, int size)
|
|||
return -1;
|
||||
if((uint)i >= proc->sz || (uint)i+size >= proc->sz)
|
||||
return -1;
|
||||
*pp = proc->mem + i;
|
||||
// *pp = proc->mem + i; // XXXXX
|
||||
*pp = (char *) i; // XXXXX
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -264,7 +264,6 @@ sys_open(void)
|
|||
|
||||
if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
|
||||
return -1;
|
||||
|
||||
if(omode & O_CREATE){
|
||||
if((ip = create(path, T_FILE, 0, 0)) == 0)
|
||||
return -1;
|
||||
|
@ -291,7 +290,6 @@ sys_open(void)
|
|||
f->off = 0;
|
||||
f->readable = !(omode & O_WRONLY);
|
||||
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -350,8 +348,9 @@ sys_exec(void)
|
|||
int i;
|
||||
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;
|
||||
}
|
||||
memset(argv, 0, sizeof(argv));
|
||||
for(i=0;; i++){
|
||||
if(i >= NELEM(argv))
|
||||
|
|
9
trap.c
9
trap.c
|
@ -78,13 +78,14 @@ trap(struct trapframe *tf)
|
|||
default:
|
||||
if(proc == 0 || (tf->cs&3) == 0){
|
||||
// In kernel, it must be our mistake.
|
||||
cprintf("unexpected trap %d from cpu %d eip %x\n",
|
||||
tf->trapno, cpu->id, tf->eip);
|
||||
cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n",
|
||||
tf->trapno, cpu->id, tf->eip, rcr2());
|
||||
panic("trap");
|
||||
}
|
||||
// In user space, assume process misbehaved.
|
||||
cprintf("pid %d %s: trap %d err %d on cpu %d eip %x -- kill proc\n",
|
||||
proc->pid, proc->name, tf->trapno, tf->err, cpu->id, tf->eip);
|
||||
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,
|
||||
rcr2());
|
||||
proc->killed = 1;
|
||||
}
|
||||
|
||||
|
|
55
x86.h
55
x86.h
|
@ -121,6 +121,61 @@ sti(void)
|
|||
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
|
||||
// Layout of the trap frame built on the stack by the
|
||||
// hardware and by trapasm.S, and passed to trap().
|
||||
|
|
Loading…
Reference in a new issue