Skip to content

Commit

Permalink
Lab pgtbl: kpagetable
Browse files Browse the repository at this point in the history
  • Loading branch information
foyoodo committed Mar 17, 2021
1 parent 5d14570 commit 758490d
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 1 deletion.
4 changes: 4 additions & 0 deletions kernel/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ int fork(void);
int growproc(int);
pagetable_t proc_pagetable(struct proc *);
void proc_freepagetable(pagetable_t, uint64);
void proc_freekpagetable(pagetable_t);
int kill(int);
struct cpu* mycpu(void);
struct cpu* getmycpu(void);
Expand Down Expand Up @@ -159,9 +160,11 @@ int uartgetc(void);

// vm.c
void kvminit(void);
void ukvminit(struct proc *);
void kvminithart(void);
uint64 kvmpa(uint64);
void kvmmap(uint64, uint64, uint64, int);
void ukvmmap(struct proc *, uint64, uint64, uint64, int);
int mappages(pagetable_t, uint64, uint64, uint64, int);
pagetable_t uvmcreate(void);
void uvminit(pagetable_t, uchar *, uint);
Expand All @@ -174,6 +177,7 @@ int uvmcopy(pagetable_t, pagetable_t, uint64);
void uvmfree(pagetable_t, uint64);
void uvmunmap(pagetable_t, uint64, uint64, int);
void uvmclear(pagetable_t, uint64);
pte_t* walk(pagetable_t, uint64, int);
uint64 walkaddr(pagetable_t, uint64);
int copyout(pagetable_t, uint64, char *, uint64);
int copyin(pagetable_t, char *, uint64, uint64);
Expand Down
54 changes: 54 additions & 0 deletions kernel/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,24 @@ allocproc(void)
return 0;
}

// create a direct-map page table for the process's kernel page.
ukvminit(p);
if (p->pagetable == 0) {
freeproc(p);
release(&p->lock);
return 0;
}

// Allocate a page for the process's kernel stack.
// Map it high in memory, followed by an invalid
// guard page.
char *pa = kalloc();
if (pa == 0)
panic("kalloc");
uint64 va = KSTACK((int)(p - proc));
ukvmmap(p, va, (uint64)pa, PGSIZE, PTE_R | PTE_W);
p->kstack = va;

// Set up new context to start executing at forkret,
// which returns to user space.
memset(&p->context, 0, sizeof(p->context));
Expand All @@ -142,6 +160,15 @@ freeproc(struct proc *p)
if(p->pagetable)
proc_freepagetable(p->pagetable, p->sz);
p->pagetable = 0;
if (p->kstack) {
pte_t *pte = walk(p->kpagetable, p->kstack, 0);
if (pte == 0) return;
kfree((void*)PTE2PA(*pte));
}
p->kstack = 0;
if (p->kpagetable)
proc_freekpagetable(p->kpagetable);
p->kpagetable = 0;
p->sz = 0;
p->pid = 0;
p->parent = 0;
Expand Down Expand Up @@ -195,6 +222,26 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz)
uvmfree(pagetable, sz);
}

// Free a process's kernel page table, without also
// freeing the leaf physical memory pages.
void
proc_freekpagetable(pagetable_t kpagetable)
{
// there are 2^9 = 512 PTEs in a page table.
for (int i = 0; i < 512; i++) {
pte_t pte = kpagetable[i];
if (pte & PTE_V) {
kpagetable[i] = 0;
if ((pte & (PTE_R | PTE_W | PTE_X)) == 0) {
// this PTE points to a lower-level page table.
uint64 child = PTE2PA(pte);
proc_freekpagetable((pagetable_t)child);
}
}
}
kfree((void*)kpagetable);
}

// a user program that calls exec("/init")
// od -t xC initcode
uchar initcode[] = {
Expand Down Expand Up @@ -473,6 +520,11 @@ scheduler(void)
// before jumping back to us.
p->state = RUNNING;
c->proc = p;

// Load process's kernel page table into the core's satp register
w_satp(MAKE_SATP(p->kpagetable));
sfence_vma();

swtch(&c->context, &p->context);

// Process is done running for now.
Expand All @@ -486,6 +538,8 @@ scheduler(void)
#if !defined (LAB_FS)
if(found == 0) {
intr_on();
// Use kernel_pagetable when no process is running
kvminithart();
asm volatile("wfi");
}
#else
Expand Down
1 change: 1 addition & 0 deletions kernel/proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct proc {
uint64 kstack; // Virtual address of kernel stack
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // User page table
pagetable_t kpagetable; // Process's kernel page table
struct trapframe *trapframe; // data page for trampoline.S
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
Expand Down
26 changes: 25 additions & 1 deletion kernel/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "riscv.h"
#include "defs.h"
#include "fs.h"
#include "spinlock.h"
#include "proc.h"

/*
* the kernel's page table.
Expand Down Expand Up @@ -47,6 +49,21 @@ kvminit()
kvmmap(TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X);
}

void
ukvminit(struct proc *p)
{
p->kpagetable = (pagetable_t) kalloc();
memset(p->kpagetable, 0, PGSIZE);

ukvmmap(p, UART0, UART0, PGSIZE, PTE_R | PTE_W);
ukvmmap(p, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
ukvmmap(p, CLINT, CLINT, 0x10000, PTE_R | PTE_W);
ukvmmap(p, PLIC, PLIC, 0x400000, PTE_R | PTE_W);
ukvmmap(p, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
ukvmmap(p, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W);
ukvmmap(p, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X);
}

// Switch h/w page table register to the kernel's page table,
// and enable paging.
void
Expand Down Expand Up @@ -121,6 +138,13 @@ kvmmap(uint64 va, uint64 pa, uint64 sz, int perm)
panic("kvmmap");
}

void
ukvmmap(struct proc *p, uint64 va, uint64 pa, uint64 sz, int perm)
{
if(mappages(p->kpagetable, va, sz, pa, perm) != 0)
panic("ukvmmap");
}

// translate a kernel virtual address to
// a physical address. only needed for
// addresses on the stack.
Expand All @@ -132,7 +156,7 @@ kvmpa(uint64 va)
pte_t *pte;
uint64 pa;

pte = walk(kernel_pagetable, va, 0);
pte = walk(myproc()->kpagetable, va, 0);
if(pte == 0)
panic("kvmpa");
if((*pte & PTE_V) == 0)
Expand Down

0 comments on commit 758490d

Please sign in to comment.