summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrans Kaashoek <[email protected]>2019-07-19 08:38:51 -0400
committerFrans Kaashoek <[email protected]>2019-07-19 08:38:51 -0400
commit91566327012cad2ca99df47f9321dfc012d8a7ff (patch)
treee9cb082d502a9f56857270264bea254149a3318d
parentb924e44f06c9c0882a2cffe6c9215b12c5aee2e6 (diff)
downloadxv6-labs-91566327012cad2ca99df47f9321dfc012d8a7ff.tar.gz
xv6-labs-91566327012cad2ca99df47f9321dfc012d8a7ff.tar.bz2
xv6-labs-91566327012cad2ca99df47f9321dfc012d8a7ff.zip
One way of supporting a guard page below kstack: allocate kstacks in
procinit() and map them high up (below TRAMPOLNE) with an empty mapping below each stack. Never free a kernel stack. Another way would be to allocate and map them dynamically, but then we need to reload page table when switching processes in scheduler() and/or have a kernel pagetable per proc (if we want k->stack to be the same virtual address in each process). One gotcha: kernel addresses are not equal to physical addresses for stack addresses. A stack address must be translated if we need its physical address (e.g., virtio passes a stack address to the disk).
-rw-r--r--kernel/defs.h2
-rw-r--r--kernel/memlayout.h1
-rw-r--r--kernel/proc.c20
-rw-r--r--kernel/virtio_disk.c2
-rw-r--r--kernel/vm.c31
5 files changed, 42 insertions, 14 deletions
diff --git a/kernel/defs.h b/kernel/defs.h
index bd89af0..3172cb3 100644
--- a/kernel/defs.h
+++ b/kernel/defs.h
@@ -193,6 +193,8 @@ uint64 walkaddr(pagetable_t, uint64);
int copyout(pagetable_t, uint64, char *, uint64);
int copyin(pagetable_t, char *, uint64, uint64);
int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max);
+char* map_kstack();
+uint64 kernelpa(uint64);
// plic.c
void plicinit(void);
diff --git a/kernel/memlayout.h b/kernel/memlayout.h
index 219c308..13d1705 100644
--- a/kernel/memlayout.h
+++ b/kernel/memlayout.h
@@ -53,3 +53,4 @@
// map the trampoline page to the highest address,
// in both user and kernel space.
#define TRAMPOLINE (MAXVA - PGSIZE)
+#define KSTACK(p) ((TRAMPOLINE-PGSIZE)-p*2*PGSIZE)
diff --git a/kernel/proc.c b/kernel/proc.c
index 6ba3fec..087d504 100644
--- a/kernel/proc.c
+++ b/kernel/proc.c
@@ -26,8 +26,14 @@ procinit(void)
struct proc *p;
initlock(&pid_lock, "nextpid");
- for(p = proc; p < &proc[NPROC]; p++)
+ for(p = proc; p < &proc[NPROC]; p++) {
initlock(&p->lock, "proc");
+ // Allocate a page for the kernel stack.
+ char *kstack = (char *) KSTACK((int) (p - proc));
+ if((p->kstack = map_kstack(kstack)) == 0) {
+ panic("procinit");
+ }
+ }
}
// Must be called with interrupts disabled,
@@ -94,16 +100,8 @@ allocproc(void)
found:
p->pid = allocpid();
- // Allocate a page for the kernel stack.
- if((p->kstack = kalloc()) == 0){
- release(&p->lock);
- return 0;
- }
-
// Allocate a trapframe page.
if((p->tf = (struct trapframe *)kalloc()) == 0){
- kfree(p->kstack);
- p->kstack = 0;
release(&p->lock);
return 0;
}
@@ -126,9 +124,6 @@ found:
static void
freeproc(struct proc *p)
{
- if(p->kstack)
- kfree(p->kstack);
- p->kstack = 0;
if(p->tf)
kfree((void*)p->tf);
p->tf = 0;
@@ -651,4 +646,3 @@ procdump(void)
printf("\n");
}
}
-
diff --git a/kernel/virtio_disk.c b/kernel/virtio_disk.c
index 1a29ce7..6620037 100644
--- a/kernel/virtio_disk.c
+++ b/kernel/virtio_disk.c
@@ -199,7 +199,7 @@ virtio_disk_rw(struct buf *b)
buf0.reserved = 0;
buf0.sector = sector;
- desc[idx[0]].addr = (uint64) &buf0;
+ desc[idx[0]].addr = (uint64) kernelpa((uint64) &buf0);
desc[idx[0]].len = sizeof(buf0);
desc[idx[0]].flags = VRING_DESC_F_NEXT;
desc[idx[0]].next = idx[1];
diff --git a/kernel/vm.c b/kernel/vm.c
index 412ec8c..d42e719 100644
--- a/kernel/vm.c
+++ b/kernel/vm.c
@@ -404,3 +404,34 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
return -1;
}
}
+
+char *map_kstack(uint64 kstack)
+{
+ char *k = kalloc();
+ if(k == 0) {
+ return 0;
+ }
+ if (mappages(kernel_pagetable, (uint64) kstack, PGSIZE,
+ (uint64) k, PTE_R | PTE_W) == 0) {
+ kvminithart();
+ return (char *) kstack;
+ }
+ kfree(k);
+ return 0;
+}
+
+// assumes va is page aligned
+uint64
+kernelpa(uint64 va) {
+ uint64 off = va % PGSIZE;
+ pte_t *pte;
+ uint64 pa;
+
+ pte = walk(kernel_pagetable, va, 0);
+ if(pte == 0)
+ panic("kernelpa");
+ if((*pte & PTE_V) == 0)
+ panic("kernelpa");
+ pa = PTE2PA(*pte);
+ return pa+off;
+}