Kernel stack get/put interface
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 2 Oct 2013 21:52:43 +0000 (14:52 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 16 Jan 2014 02:14:47 +0000 (18:14 -0800)
Also cleans up the poison/canary, and if you need to, you should be able
to get larger stacks (change the KSTKSHIFT).

kern/arch/x86/smp_boot.c
kern/arch/x86/trap.c
kern/include/kthread.h
kern/src/kthread.c

index 54935c5..3e32007 100644 (file)
@@ -236,11 +236,7 @@ uintptr_t smp_main(void)
        hw_coreid_lookup[my_hw_id] = my_hw_id;
 
        // Get a per-core kernel stack
-       page_t *my_stack;
-       if (kpage_alloc(&my_stack))
-               panic("Unable to alloc a per-core stack!");
-       memset(page2kva(my_stack), 0, PGSIZE);
-       uintptr_t my_stack_top = (uintptr_t)page2kva(my_stack) + PGSIZE;
+       uintptr_t my_stack_top = get_kstack();
 
        /* This blob is the GDT, the GDT PD, and the TSS. */
        unsigned int blob_size = sizeof(segdesc_t) * SEG_COUNT +
@@ -254,7 +250,7 @@ uintptr_t smp_main(void)
         * to smp_percpu_init(), but we can't trust our coreid (since they haven't
         * been remapped yet (so we can't write it directly to per_cpu_info)).  So
         * we use the bottom of the stack page... */
-       *(uintptr_t*)page2kva(my_stack) = (uintptr_t)gdt_etc;
+       *kstack_bottom_addr(my_stack_top) = (uintptr_t)gdt_etc;
 
        // Build and load the gdt / gdt_pd
        memcpy(my_gdt, gdt, sizeof(segdesc_t)*SEG_COUNT);
index 61f0d65..dd1ac6b 100644 (file)
@@ -85,6 +85,8 @@ uintptr_t get_stack_top(void)
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        uintptr_t stacktop;
        /* so we can check this in interrupt handlers (before smp_boot()) */
+       /* TODO: These are dangerous - it assumes we're on a one-page stack.  If we
+        * change it to KSTKSIZE, then we assume stacks are KSTKSIZE-aligned */
        if (!pcpui->tss)
                return ROUNDUP(read_sp(), PGSIZE);
        stacktop = x86_get_stacktop_tss(pcpui->tss);
@@ -136,10 +138,7 @@ void idt_init(void)
        x86_sysenter_init((uintptr_t)bootstacktop);
 
 #ifdef CONFIG_KTHREAD_POISON
-       /* TODO: KTHR-STACK */
-       uintptr_t *poison = (uintptr_t*)ROUNDDOWN((uintptr_t)bootstacktop - 1,
-                                                 PGSIZE);
-       *poison = 0xdeadbeef;
+       *kstack_bottom_addr((uintptr_t)bootstacktop) = 0xdeadbeef;
 #endif /* CONFIG_KTHREAD_POISON */
 
        /* Initialize the TSS field of the gdt.  The size of the TSS desc differs
index 542ece7..9c2032b 100644 (file)
@@ -58,6 +58,9 @@ struct semaphore_entry {
        LIST_ENTRY(semaphore_entry) link;
 };
 
+uintptr_t get_kstack(void);
+void put_kstack(uintptr_t stacktop);
+uintptr_t *kstack_bottom_addr(uintptr_t stacktop);
 void kthread_init(void);
 void restart_kthread(struct kthread *kthread);
 void kthread_runnable(struct kthread *kthread);
index 462f1ef..07ec61a 100644 (file)
 #include <smp.h>
 #include <schedule.h>
 
+uintptr_t get_kstack(void)
+{
+       uintptr_t stackbot;
+       if (KSTKSIZE == PGSIZE)
+               stackbot = (uintptr_t)kpage_alloc_addr();
+       else
+               stackbot = (uintptr_t)get_cont_pages(KSTKSHIFT >> PGSHIFT, 0);
+       assert(stackbot);
+       return stackbot + KSTKSIZE;
+}
+
+void put_kstack(uintptr_t stacktop)
+{
+       uintptr_t stackbot = stacktop - KSTKSIZE;
+       if (KSTKSIZE == PGSIZE)
+               page_decref(kva2page((void*)stackbot));
+       else
+               free_cont_pages((void*)stackbot, KSTKSHIFT >> PGSHIFT);
+}
+
+uintptr_t *kstack_bottom_addr(uintptr_t stacktop)
+{
+       /* canary at the bottom of the stack */
+       assert(!PGOFF(stacktop));
+       return (uintptr_t*)(stacktop - KSTKSIZE);
+}
+
 struct kmem_cache *kthread_kcache;
 
 void kthread_init(void)
@@ -34,24 +61,19 @@ void restart_kthread(struct kthread *kthread)
         * free our current kthread *before* popping it, nor can we free the current
         * stack until we pop to the kthread's stack). */
        if (pcpui->spare) {
-               /* assumes the stack is a page, and that stacktop is somewhere in
-                * (pg_bottom, pg_bottom + PGSIZE].  Normally, it ought to be pg_bottom
-                * + PGSIZE (on x86).  kva2page can take any kva, not just a page
-                * aligned addr. */
-               page_decref(kva2page((void*)pcpui->spare->stacktop - 1));
+               put_kstack(pcpui->spare->stacktop);
                kmem_cache_free(kthread_kcache, pcpui->spare);
        }
        current_stacktop = get_stack_top();
        /* When a kthread runs, its stack is the default kernel stack */
        set_stack_top(kthread->stacktop);
 #ifdef CONFIG_KTHREAD_POISON
-       /* TODO: KTHR-STACK */
        /* Assert and switch to cur stack not in use, kthr stack in use */
        uintptr_t *cur_stack_poison, *kth_stack_poison;
-       cur_stack_poison = (uintptr_t*)ROUNDDOWN(current_stacktop - 1, PGSIZE);
+       cur_stack_poison = kstack_bottom_addr(current_stacktop);
        assert(*cur_stack_poison == 0xdeadbeef);
        *cur_stack_poison = 0;
-       kth_stack_poison = (uintptr_t*)ROUNDDOWN(kthread->stacktop - 1, PGSIZE);
+       kth_stack_poison = kstack_bottom_addr(kthread->stacktop);
        assert(!*kth_stack_poison);
        *kth_stack_poison = 0xdeadbeef;
 #endif /* CONFIG_KTHREAD_POISON */
@@ -150,7 +172,7 @@ void kthread_yield(void)
 void check_poison(char *msg)
 {
 #ifdef CONFIG_KTHREAD_POISON
-       if (*(uintptr_t*)ROUNDDOWN(get_stack_top() - 1, PGSIZE) != 0xdeadbeef) {
+       if (*kstack_bottom_addr(get_stack_top()) != 0xdeadbeef) {
                printk("\nBad kthread canary, msg: %s\n", msg);
                panic("");
        }
@@ -181,7 +203,6 @@ void sem_down(struct semaphore *sem)
 {
        volatile bool blocking = TRUE;  /* signal to short circuit when restarting*/
        struct kthread *kthread;
-       struct page *page;                              /* assumption here that stacks are PGSIZE */
        register uintptr_t new_stacktop;
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
 
@@ -205,18 +226,16 @@ void sem_down(struct semaphore *sem)
         * concurrent modifications). */
        if (pcpui->spare) {
                kthread = pcpui->spare;
-               /* we're using the spare, so we use the page the spare held */
+               /* we're using the spare, so we use the stack the spare held */
                new_stacktop = kthread->stacktop;
                pcpui->spare = 0;
        } else {
                kthread = kmem_cache_alloc(kthread_kcache, 0);
                assert(kthread);
-               assert(!kpage_alloc(&page));    /* decref'd when the kthread is freed */
+               new_stacktop = get_kstack();
 #ifdef CONFIG_KTHREAD_POISON
-               /* TODO: KTHR-STACK don't poison like this */
-               *(uintptr_t*)page2kva(page) = 0;
+               *kstack_bottom_addr(new_stacktop) = 0;
 #endif /* CONFIG_KTHREAD_POISON */
-               new_stacktop = (uintptr_t)page2kva(page) + PGSIZE;
        }
        /* This is the stacktop we are currently on and wish to save */
        kthread->stacktop = get_stack_top();
@@ -224,12 +243,11 @@ void sem_down(struct semaphore *sem)
        set_stack_top(new_stacktop);
 #ifdef CONFIG_KTHREAD_POISON
        /* Mark the new stack as in-use, and unmark the current kthread */
-       /* TODO: KTHR-STACK don't poison like this */
        uintptr_t *new_stack_poison, *kth_stack_poison;
-       new_stack_poison = (uintptr_t*)ROUNDDOWN(new_stacktop - 1, PGSIZE);
+       new_stack_poison = kstack_bottom_addr(new_stacktop);
        assert(!*new_stack_poison);
        *new_stack_poison = 0xdeadbeef;
-       kth_stack_poison = (uintptr_t*)ROUNDDOWN(kthread->stacktop - 1, PGSIZE);
+       kth_stack_poison = kstack_bottom_addr(kthread->stacktop);
        assert(*kth_stack_poison == 0xdeadbeef);
        *kth_stack_poison = 0;
 #endif /* CONFIG_KTHREAD_POISON */