simplify kernel mapping calls
This commit is contained in:
parent
55bc96d419
commit
54178ad94d
|
@ -193,7 +193,7 @@ uint64 walkaddr(pagetable_t, uint64);
|
||||||
int copyout(pagetable_t, uint64, char *, uint64);
|
int copyout(pagetable_t, uint64, char *, uint64);
|
||||||
int copyin(pagetable_t, char *, uint64, uint64);
|
int copyin(pagetable_t, char *, uint64, uint64);
|
||||||
int copyinstr(pagetable_t, char *, uint64, uint64);
|
int copyinstr(pagetable_t, char *, uint64, uint64);
|
||||||
char* mapkstack(uint64);
|
void kmap(uint64, uint64, uint64, int);
|
||||||
uint64 kernelpa(uint64);
|
uint64 kernelpa(uint64);
|
||||||
void clearpteu(pagetable_t, uint64);
|
void clearpteu(pagetable_t, uint64);
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,9 @@
|
||||||
// map the trampoline page to the highest address,
|
// map the trampoline page to the highest address,
|
||||||
// in both user and kernel space.
|
// in both user and kernel space.
|
||||||
#define TRAMPOLINE (MAXVA - PGSIZE)
|
#define TRAMPOLINE (MAXVA - PGSIZE)
|
||||||
|
|
||||||
|
// map kernel stacks beneath the trampoline,
|
||||||
|
// each surrounded by invalid guard pages.
|
||||||
#define KSTACK(p) (TRAMPOLINE - ((p)+1)* 2*PGSIZE)
|
#define KSTACK(p) (TRAMPOLINE - ((p)+1)* 2*PGSIZE)
|
||||||
|
|
||||||
// User memory layout.
|
// User memory layout.
|
||||||
|
|
|
@ -28,12 +28,18 @@ procinit(void)
|
||||||
initlock(&pid_lock, "nextpid");
|
initlock(&pid_lock, "nextpid");
|
||||||
for(p = proc; p < &proc[NPROC]; p++) {
|
for(p = proc; p < &proc[NPROC]; p++) {
|
||||||
initlock(&p->lock, "proc");
|
initlock(&p->lock, "proc");
|
||||||
// Allocate a page for the kernel stack.
|
|
||||||
uint64 kstack = KSTACK((int) (p - proc));
|
// Allocate a page for the process's kernel stack.
|
||||||
if((p->kstack = mapkstack(kstack)) == 0) {
|
// Map it high in memory, followed by an invalid
|
||||||
panic("procinit");
|
// guard page.
|
||||||
}
|
char *pa = kalloc();
|
||||||
|
if(pa == 0)
|
||||||
|
panic("kalloc");
|
||||||
|
uint64 va = KSTACK((int) (p - proc));
|
||||||
|
kmap(va, (uint64)pa, PGSIZE, PTE_R | PTE_W);
|
||||||
|
p->kstack = va;
|
||||||
}
|
}
|
||||||
|
kvminithart();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be called with interrupts disabled,
|
// Must be called with interrupts disabled,
|
||||||
|
@ -113,7 +119,7 @@ found:
|
||||||
// which returns to user space.
|
// which returns to user space.
|
||||||
memset(&p->context, 0, sizeof p->context);
|
memset(&p->context, 0, sizeof p->context);
|
||||||
p->context.ra = (uint64)forkret;
|
p->context.ra = (uint64)forkret;
|
||||||
p->context.sp = (uint64)p->kstack + PGSIZE;
|
p->context.sp = p->kstack + PGSIZE;
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ struct proc {
|
||||||
int pid; // Process ID
|
int pid; // Process ID
|
||||||
|
|
||||||
// these are private to the process, so p->lock need not be held.
|
// these are private to the process, so p->lock need not be held.
|
||||||
char *kstack; // Bottom of kernel stack for this process
|
uint64 kstack; // Bottom of kernel stack for this process
|
||||||
uint64 sz; // Size of process memory (bytes)
|
uint64 sz; // Size of process memory (bytes)
|
||||||
pagetable_t pagetable; // Page table
|
pagetable_t pagetable; // Page table
|
||||||
struct trapframe *tf; // data page for trampoline.S
|
struct trapframe *tf; // data page for trampoline.S
|
||||||
|
|
|
@ -101,7 +101,7 @@ usertrapret(void)
|
||||||
// set up values that trampoline.S will need when
|
// set up values that trampoline.S will need when
|
||||||
// the process next re-enters the kernel.
|
// the process next re-enters the kernel.
|
||||||
p->tf->kernel_satp = r_satp();
|
p->tf->kernel_satp = r_satp();
|
||||||
p->tf->kernel_sp = (uint64)p->kstack + PGSIZE;
|
p->tf->kernel_sp = p->kstack + PGSIZE;
|
||||||
p->tf->kernel_trap = (uint64)usertrap;
|
p->tf->kernel_trap = (uint64)usertrap;
|
||||||
p->tf->kernel_hartid = r_tp();
|
p->tf->kernel_hartid = r_tp();
|
||||||
|
|
||||||
|
|
|
@ -199,6 +199,8 @@ virtio_disk_rw(struct buf *b)
|
||||||
buf0.reserved = 0;
|
buf0.reserved = 0;
|
||||||
buf0.sector = sector;
|
buf0.sector = sector;
|
||||||
|
|
||||||
|
// buf0 is on a kernel stack, which is not direct mapped,
|
||||||
|
// thus the call to kernelpa().
|
||||||
desc[idx[0]].addr = (uint64) kernelpa((uint64) &buf0);
|
desc[idx[0]].addr = (uint64) kernelpa((uint64) &buf0);
|
||||||
desc[idx[0]].len = sizeof(buf0);
|
desc[idx[0]].len = sizeof(buf0);
|
||||||
desc[idx[0]].flags = VRING_DESC_F_NEXT;
|
desc[idx[0]].flags = VRING_DESC_F_NEXT;
|
||||||
|
|
59
kernel/vm.c
59
kernel/vm.c
|
@ -27,33 +27,26 @@ kvminit()
|
||||||
memset(kernel_pagetable, 0, PGSIZE);
|
memset(kernel_pagetable, 0, PGSIZE);
|
||||||
|
|
||||||
// uart registers
|
// uart registers
|
||||||
mappages(kernel_pagetable, UART0, PGSIZE,
|
kmap(UART0, UART0, PGSIZE, PTE_R | PTE_W);
|
||||||
UART0, PTE_R | PTE_W);
|
|
||||||
|
|
||||||
// virtio mmio disk interface
|
// virtio mmio disk interface
|
||||||
mappages(kernel_pagetable, VIRTIO0, PGSIZE,
|
kmap(VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
|
||||||
VIRTIO0, PTE_R | PTE_W);
|
|
||||||
|
|
||||||
// CLINT
|
// CLINT
|
||||||
mappages(kernel_pagetable, CLINT, 0x10000,
|
kmap(CLINT, CLINT, 0x10000, PTE_R | PTE_W);
|
||||||
CLINT, PTE_R | PTE_W);
|
|
||||||
|
|
||||||
// PLIC
|
// PLIC
|
||||||
mappages(kernel_pagetable, PLIC, 0x4000000,
|
kmap(PLIC, PLIC, 0x400000, PTE_R | PTE_W);
|
||||||
PLIC, PTE_R | PTE_W);
|
|
||||||
|
|
||||||
// map kernel text executable and read-only.
|
// map kernel text executable and read-only.
|
||||||
mappages(kernel_pagetable, KERNBASE, (uint64)etext-KERNBASE,
|
kmap(KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
|
||||||
KERNBASE, PTE_R | PTE_X);
|
|
||||||
|
|
||||||
// map kernel data and the physical RAM we'll make use of.
|
// map kernel data and the physical RAM we'll make use of.
|
||||||
mappages(kernel_pagetable, (uint64)etext, PHYSTOP-(uint64)etext,
|
kmap((uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W);
|
||||||
(uint64)etext, PTE_R | PTE_W);
|
|
||||||
|
|
||||||
// map the trampoline for trap entry/exit to
|
// map the trampoline for trap entry/exit to
|
||||||
// the highest virtual address in the kernel.
|
// the highest virtual address in the kernel.
|
||||||
mappages(kernel_pagetable, TRAMPOLINE, PGSIZE,
|
kmap(TRAMPOLINE, (uint64)trampout, PGSIZE, PTE_R | PTE_X);
|
||||||
(uint64)trampout, PTE_R | PTE_X);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch h/w page table register to the kernel's page table,
|
// Switch h/w page table register to the kernel's page table,
|
||||||
|
@ -117,6 +110,15 @@ walkaddr(pagetable_t pagetable, uint64 va)
|
||||||
return pa;
|
return pa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add a mapping to the kernel page table.
|
||||||
|
// only used when booting.
|
||||||
|
// does not flush TLB or enable paging.
|
||||||
|
void
|
||||||
|
kmap(uint64 va, uint64 pa, uint64 sz, int perm)
|
||||||
|
{
|
||||||
|
if(mappages(kernel_pagetable, va, sz, pa, perm) != 0)
|
||||||
|
panic("kmap");
|
||||||
|
}
|
||||||
|
|
||||||
// Create PTEs for virtual addresses starting at va that refer to
|
// Create PTEs for virtual addresses starting at va that refer to
|
||||||
// physical addresses starting at pa. va and size might not
|
// physical addresses starting at pa. va and size might not
|
||||||
|
@ -405,25 +407,13 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
// translate a kernel virtual address to
|
||||||
mapkstack(uint64 kstack)
|
// a physical address. only needed for
|
||||||
{
|
// addresses on the stack.
|
||||||
char *k = kalloc();
|
// assumes va is page aligned.
|
||||||
if(k == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (mappages(kernel_pagetable, kstack, PGSIZE,
|
|
||||||
(uint64) k, PTE_R | PTE_W) == 0) {
|
|
||||||
kvminithart();
|
|
||||||
return (char *) kstack;
|
|
||||||
}
|
|
||||||
kfree(k);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// assumes va is page aligned
|
|
||||||
uint64
|
uint64
|
||||||
kernelpa(uint64 va) {
|
kernelpa(uint64 va)
|
||||||
|
{
|
||||||
uint64 off = va % PGSIZE;
|
uint64 off = va % PGSIZE;
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
uint64 pa;
|
uint64 pa;
|
||||||
|
@ -437,8 +427,11 @@ kernelpa(uint64 va) {
|
||||||
return pa+off;
|
return pa+off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark a PTE invalid for user access.
|
||||||
|
// used by exec for the user stack guard page.
|
||||||
void
|
void
|
||||||
clearpteu(pagetable_t pagetable, uint64 va) {
|
clearpteu(pagetable_t pagetable, uint64 va)
|
||||||
|
{
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
|
||||||
pte = walk(pagetable, va, 0);
|
pte = walk(pagetable, va, 0);
|
||||||
|
|
|
@ -1884,26 +1884,30 @@ rand()
|
||||||
return randstate;
|
return randstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check that there's an invalid page beneath
|
||||||
|
// the user stack, to catch stack overflow.
|
||||||
void
|
void
|
||||||
stacktest()
|
stacktest()
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
int ppid = getpid();
|
||||||
|
|
||||||
printf(1, "stack test\n");
|
printf(1, "stack guard test\n");
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if(pid == 0) {
|
if(pid == 0) {
|
||||||
char *sp = (char *) r_sp();
|
char *sp = (char *) r_sp();
|
||||||
printf(1, "%p\n", sp);
|
|
||||||
sp -= 4096;
|
sp -= 4096;
|
||||||
|
// the *sp should cause a trap.
|
||||||
printf(1, "stacktest: read below stack %p\n", *sp);
|
printf(1, "stacktest: read below stack %p\n", *sp);
|
||||||
printf(1, "stacktest: test FAILED\n");
|
printf(1, "stacktest: test FAILED\n");
|
||||||
|
kill(ppid);
|
||||||
exit();
|
exit();
|
||||||
} else if(pid < 0){
|
} else if(pid < 0){
|
||||||
printf (1, "fork failed\n");
|
printf (1, "fork failed\n");
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
wait();
|
wait();
|
||||||
printf(1, "stack test done\n");
|
printf(1, "stack guard test ok\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
Loading…
Reference in a new issue