Vcore mapping and idle core management
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 31 Aug 2009 20:48:13 +0000 (13:48 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 1 Sep 2009 17:41:10 +0000 (10:41 -0700)
Infrastructure for tracking idle cores (needed becauses processes can
kill themselves).  In general, the vcoremap (and idlecoremap) are set
before proc_run(), and deallocated/fixed up *during* proc_destroy.

Also this makes __startcore and __death (somewhat) arch independent.
__startcore now sets the vcoreid (instead of just 1 to signal an extra
core), which is easy with active messages.

If you run it with deputy on, try backtracing or kfs_running
roslib_spawn.

16 files changed:
kern/arch/i386/env.c
kern/arch/i386/process.c
kern/arch/sparc/env.c
kern/arch/sparc/env.c.save [deleted file]
kern/arch/sparc/env.c.save.1 [deleted file]
kern/include/env.h
kern/include/monitor.h
kern/include/process.h
kern/src/env.c
kern/src/init.c
kern/src/manager.c
kern/src/monitor.c
kern/src/pmap.c
kern/src/process.c
kern/src/string.c
user/roslib/src/i386/entry.S

index 9041a7d..45132c0 100644 (file)
@@ -51,30 +51,6 @@ void env_pop_tf(trapframe_t *tf)
        }
 }
 
-void
-env_set_program_counter(env_t* e, uintptr_t pc)
-{
-       e->env_tf.tf_eip = pc;
-}
-
-void
-env_init_trapframe(trapframe_t *tf)
-{
-       // Set up appropriate initial values for the segment registers.
-       // GD_UD is the user data segment selector in the GDT, and
-       // GD_UT is the user text segment selector (see inc/memlayout.h).
-       // The low 2 bits of each segment register contains the
-       // Requestor Privilege Level (RPL); 3 means user mode.
-       tf->tf_ds = GD_UD | 3;
-       tf->tf_es = GD_UD | 3;
-       tf->tf_ss = GD_UD | 3;
-       tf->tf_esp = USTACKTOP;
-       tf->tf_cs = GD_UT | 3;
-       // You will set e->env_tf.tf_eip later.
-       // set the env's EFLAGSs to have interrupts enabled
-       tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
-}
-
 // Flush all mapped pages in the user portion of the address space
 void
 env_user_mem_free(env_t* e)
index a02d3c8..ca63f82 100644 (file)
@@ -8,46 +8,30 @@
 #include <assert.h>
 #include <stdio.h>
 
-/* Active message handler to start a process's context on this core.  Tightly
- * coupled with proc_run() */
-void __startcore(trapframe_t *tf, uint32_t srcid, uint32_t a0, uint32_t a1,
-                 uint32_t a2)
+void proc_set_program_counter(trapframe_t *tf, uintptr_t pc)
 {
-       uint32_t coreid = core_id();
-       struct proc *p_to_run = (struct proc *SAFE) TC(a0);
-       trapframe_t local_tf;
-       trapframe_t *tf_to_pop = (trapframe_t *SAFE) TC(a1);
+       tf->tf_eip = pc;
+}
 
-       printk("Startcore on core %d\n", coreid);
-       assert(p_to_run);
-       // TODO: handle silly state (HSS)
-       if (!tf_to_pop) {
-               tf_to_pop = &local_tf;
-               memset(tf_to_pop, 0, sizeof(*tf_to_pop));
-               env_init_trapframe(tf_to_pop);
-               // Note the init_tf sets tf_to_pop->tf_esp = USTACKTOP;
-               tf_to_pop->tf_regs.reg_eax = 1;
-               tf_to_pop->tf_eip = p_to_run->env_entry;
-       }
-       proc_startcore(p_to_run, tf_to_pop);
+void proc_init_trapframe(trapframe_t *tf)
+{
+       /* Set up appropriate initial values for the segment registers.
+        * GD_UD is the user data segment selector in the GDT, and
+        * GD_UT is the user text segment selector (see inc/memlayout.h).
+        * The low 2 bits of each segment register contains the
+        * Requestor Privilege Level (RPL); 3 means user mode. */
+       tf->tf_ds = GD_UD | 3;
+       tf->tf_es = GD_UD | 3;
+       tf->tf_ss = GD_UD | 3;
+       tf->tf_esp = USTACKTOP;
+       tf->tf_cs = GD_UT | 3;
+       /* set the env's EFLAGSs to have interrupts enabled */
+       tf->tf_eflags |= 0x00000200; // bit 9 is the interrupts-enabled
 }
 
-/* Active message handler to stop running whatever context is on this core and
- * to idle.  Note this leaves no trace of what was running.
- * It's okay if death comes to a core that's already idling and has no current.
- * It could happen if a process decref'd before proc_startcore could incref. */
-void __death(trapframe_t *tf, uint32_t srcid, uint32_t a0, uint32_t a1,
-             uint32_t a2)
+/* Coupled closely with userland's entry.S.  id is the vcoreid, which entry.S
+ * uses to determine what to do.  vcoreid == 0 is the main core/context. */
+void proc_set_tfcoreid(trapframe_t *tf, uint32_t id)
 {
-       /* If we are currently running an address space on our core, we need a known
-        * good pgdir before releasing the old one.  This is currently the major
-        * practical implication of the kernel caring about a processes existence
-        * (the inc and decref).  This decref corresponds to the incref in
-        * proc_startcore (though it's not the only one). */
-       if (current) {
-               lcr3(boot_cr3);
-               proc_decref(current);
-               current = NULL;
-       }
-       smp_idle();
+       tf->tf_regs.reg_eax = id;
 }
index ede1ed1..905e786 100644 (file)
@@ -81,14 +81,14 @@ void
 }
 
 void
-env_set_program_counter(env_t* e, uintptr_t pc)
+proc_set_program_counter(trapframe_t *tf, uintptr_t pc)
 {
-       e->env_tf.pc = pc;
-       e->env_tf.npc = pc+4;
+       tf->pc = pc;
+       tf->npc = pc+4;
 }
 
 void
-env_init_trapframe(trapframe_t *tf)
+proc_init_trapframe(trapframe_t *tf)
 {
        extern char trap_table;
 
diff --git a/kern/arch/sparc/env.c.save b/kern/arch/sparc/env.c.save
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/kern/arch/sparc/env.c.save.1 b/kern/arch/sparc/env.c.save.1
deleted file mode 100644 (file)
index 62228f1..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/* See COPYRIGHT for copyright information. */
-#ifdef __DEPUTY__
-#pragma noasync
-#endif
-
-#include <arch/trap.h>
-#include <env.h>
-#include <assert.h>
-#include <arch/arch.h>
-#include <pmap.h>
-
-void
-(IN_HANDLER env_push_ancillary_state)(env_t* e)
-{
-       static_assert(offsetof(ancillary_state_t,fpr) % 8 == 0);
-
-       #define push_two_fp_regs(pdest,n) \
-           __asm__ __volatile__ ("std  %%f" XSTR(n) ",[%0+4*" XSTR(n) "]" \
-                             : : "r"(pdest) : "memory");
-
-       // do I need to save FP regs?
-       if(e->env_tf.psr & PSR_EF)
-       {
-               // temporarily turn on FP in the kernel
-               write_psr(read_psr() | PSR_EF);
-
-               e->env_ancillary_state.fsr = read_fsr();
-
-               push_two_fp_regs(e->env_ancillary_state.fpr,0);
-               push_two_fp_regs(e->env_ancillary_state.fpr,2);
-               push_two_fp_regs(e->env_ancillary_state.fpr,4);
-               push_two_fp_regs(e->env_ancillary_state.fpr,6);
-               push_two_fp_regs(e->env_ancillary_state.fpr,8);
-               push_two_fp_regs(e->env_ancillary_state.fpr,10);
-               push_two_fp_regs(e->env_ancillary_state.fpr,12);
-               push_two_fp_regs(e->env_ancillary_state.fpr,14);
-               push_two_fp_regs(e->env_ancillary_state.fpr,16);
-               push_two_fp_regs(e->env_ancillary_state.fpr,18);
-               push_two_fp_regs(e->env_ancillary_state.fpr,20);
-               push_two_fp_regs(e->env_ancillary_state.fpr,22);
-               push_two_fp_regs(e->env_ancillary_state.fpr,24);
-               push_two_fp_regs(e->env_ancillary_state.fpr,26);
-               push_two_fp_regs(e->env_ancillary_state.fpr,28);
-               push_two_fp_regs(e->env_ancillary_state.fpr,30);
-
-               write_psr(read_psr() & ~PSR_EF);
-       }
-}
-
-void
-(IN_HANDLER env_pop_ancillary_state)(env_t* e)
-{ 
-
-       #define pop_two_fp_regs(pdest,n) \
-           __asm__ __volatile__ ("ldd  [%0+4*" XSTR(n) "], %%f" XSTR(n) \
-                             : : "r"(pdest) : "memory");
-
-       if(e->env_tf.psr & PSR_EF)
-       {
-               write_psr(read_psr() | PSR_EF);
-
-               pop_two_fp_regs(e->env_ancillary_state.fpr,0);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,2);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,4);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,6);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,8);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,10);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,12);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,14);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,16);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,18);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,20);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,22);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,24);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,26);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,28);
-               pop_two_fp_regs(e->env_ancillary_state.fpr,30);
-
-               write_fsr(e->env_ancillary_state.fsr);
-
-               write_psr(read_psr() & ~PSR_EF);
-       }
-}
-
-void
-env_set_program_counter(env_t* e, uintptr_t pc)
-{
-       e->env_tf.pc = pc;
-       e->env_tf.npc = pc+4;
-}
-
-void
-env_init_trapframe(env_t* e)
-{
-       extern char trap_table;
-
-       e->env_tf.gpr[14] = USTACKTOP-64;
-       e->env_tf.psr = PSR_S; // but PS = 0
-       e->env_tf.wim = 0;
-       e->env_tf.tbr = (uint32_t)&trap_table;
-}
-
-// Flush all mapped pages in the user portion of the address space
-// TODO: only supports L3 user pages
-void
-env_user_mem_free(env_t* e)
-{
-       pte_t *l1pt = e->env_pgdir, *l2pt, *l3pt;
-       uint32_t l1x,l2x,l3x;
-       physaddr_t l2ptpa,l3ptpa,page_pa;
-       uint32_t l2_tables_per_page,l3_tables_per_page;
-
-       l2_tables_per_page = PGSIZE/(sizeof(pte_t)*NL2ENTRIES);
-       l3_tables_per_page = PGSIZE/(sizeof(pte_t)*NL3ENTRIES);
-
-       static_assert(L2X(UTOP) == 0 && L3X(UTOP) == 0);
-       for(l1x = 0; l1x < L1X(UTOP); l1x++)
-       {
-               if(!(l1pt[l1x] & PTE_PTD))
-                       continue;
-
-               l2ptpa = PTD_ADDR(l1pt[l1x]);
-               l2pt = (pte_t*COUNT(NL2ENTRIES)) KADDR(l2ptpa);
-
-               for(l2x = 0; l2x < NL2ENTRIES; l2x++)
-               {
-                       if(!(l2pt[l2x] & PTE_PTD))
-                               continue;
-
-                       l3ptpa = PTD_ADDR(l2pt[l2x]);
-                       l3pt = (pte_t*COUNT(NL3ENTRIES)) KADDR(l3ptpa);
-
-                       for(l3x = 0; l3x < NL3ENTRIES; l3x++)
-                       {
-                               if(l3pt[l3x] & PTE_PTE)
-                               {
-                                       page_pa = PTE_ADDR(l3pt[l3x]);
-                                       l3pt[l3x] = 0;
-                                       page_decref(pa2page(page_pa));
-                               }
-                       }
-
-                       l2pt[l2x] = 0;
-
-                       // free the L3 PT itself
-                       page_decref(pa2page(l2ptpa));
-               }
-
-               l1pt[l1x] = 0;
-
-               // free the L2 PT itself
-               page_decref(pa2page(l2ptpa));
-       }
-
-       tlbflush();
-}
index d5e1048..2cd6147 100644 (file)
@@ -93,8 +93,6 @@ extern env_t* curenvs[MAX_NUM_CPUS];
 
 void   env_init(void);
 int            env_alloc(env_t *SAFE*SAFE e, envid_t parent_id);
-void   env_init_trapframe(trapframe_t *SAFE tf);
-void   env_set_program_counter(env_t* e, uintptr_t pc);
 void   env_push_ancillary_state(env_t* e);
 void   env_pop_ancillary_state(env_t* e);
 void   env_free(env_t *SAFE e);
index f705e87..4013aa8 100644 (file)
@@ -21,5 +21,6 @@ int mon_nanwan(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 int mon_kfs_ls(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 int mon_kfs_run(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 int mon_manager(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
+int mon_procinfo(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 
 #endif // !ROS_KERN_MONITOR_H
index 095e7c7..28df555 100644 (file)
@@ -36,6 +36,10 @@ extern spinlock_t freelist_lock;
 extern struct proc_list proc_runnablelist;
 extern spinlock_t runnablelist_lock;
 
+extern spinlock_t idle_lock;
+extern uint32_t idlecoremap[MAX_NUM_CPUS];
+extern uint32_t num_idlecores;
+
 int proc_set_state(struct proc *p, uint32_t state) WRITES(p->state);
 struct proc *get_proc(unsigned pid);
 bool proc_controls(struct proc *SAFE actor, struct proc *SAFE target);
@@ -44,6 +48,10 @@ void proc_run(struct proc *SAFE p);
 void (proc_startcore)(struct proc *SAFE p, trapframe_t *SAFE tf)
      __attribute__((noreturn));
 void (proc_destroy)(struct proc *SAFE p);
+void proc_destroy(struct proc *SAFE p);
+void proc_init_trapframe(trapframe_t *SAFE tf);
+void proc_set_program_counter(trapframe_t *SAFE tf, uintptr_t pc);
+void proc_set_tfcoreid(trapframe_t *SAFE tf, uint32_t id);
 
 /* The reference counts are mostly to track how many cores loaded the cr3 */
 error_t proc_incref(struct proc *SAFE p);
@@ -55,4 +63,7 @@ void __startcore(trapframe_t *tf, uint32_t srcid, uint32_t a0, uint32_t a1,
 void __death(trapframe_t *tf, uint32_t srcid, uint32_t a0, uint32_t a1,
              uint32_t a2);
 
+/* Degubbing */
+void print_idlecoremap(void);
+
 #endif // !ROS_KERN_PROCESS_H
index b6ad69b..4ad9677 100644 (file)
@@ -91,6 +91,12 @@ env_init(void)
        int i;
 
        schedule_init();
+       // core 0 is not idle, all others are (for now)
+       spin_lock(&idle_lock);
+       num_idlecores = num_cpus - 1;
+       for (i = 0; i < num_idlecores; i++)
+               idlecoremap[i] = i + 1;
+       spin_unlock(&idle_lock);
        atomic_init(&num_envs, 0);
        TAILQ_INIT(&proc_freelist);
        assert(envs != NULL);
@@ -282,7 +288,7 @@ env_alloc(env_t **newenv_store, envid_t parent_id)
 
        memset(&e->env_ancillary_state, 0, sizeof(e->env_ancillary_state));
        memset(&e->env_tf, 0, sizeof(e->env_tf));
-       env_init_trapframe(&e->env_tf);
+       proc_init_trapframe(&e->env_tf);
 
        /*
         * Initialize the contents of the e->env_procinfo structure
@@ -414,7 +420,7 @@ load_icode(env_t *SAFE e, uint8_t *COUNT(size) binary, size_t size)
                memset((void*)phdr.p_va + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz);
        }}
 
-       env_set_program_counter(e, elfhdr.e_entry);
+       proc_set_program_counter(&e->env_tf, elfhdr.e_entry);
        e->env_entry = elfhdr.e_entry;
 
        // Now map one page for the program's initial stack
index 91b73aa..a3dd45d 100644 (file)
@@ -58,14 +58,13 @@ void kernel_init(multiboot_info_t *mboot_info)
        page_init();
        page_check();
 
-       env_init();
-
        idt_init();
        sysenter_init();
        timer_init();
 
        // this returns when all other cores are done and ready to receive IPIs
        smp_boot();
+       env_init();
 
        manager();
 }
index 8df76cc..2e9bcde 100644 (file)
@@ -31,44 +31,52 @@ void manager(void)
 {
        static uint8_t progress = 0;
        struct proc *envs[256];
-
-struct proc *p = kfs_proc_create(kfs_lookup_path("roslib_mhello"));
-// being proper and all:
-proc_set_state(p, PROC_RUNNABLE_S);
-proc_set_state(p, PROC_RUNNING_S);
-proc_set_state(p, PROC_RUNNABLE_M);
-// set vcoremap with dispatch plan.  usually done by schedule()
-spin_lock_irqsave(&p->proc_lock);
-p->num_vcores = 5;
-for (int i = 0; i < 5; i++)
-       p->vcoremap[i] = i + 1; // vcore0 -> pcore1, etc, for 3 cores
-spin_unlock_irqsave(&p->proc_lock);
-proc_run(p);
-udelay(5000000);
-printk("Killing p\n");
-proc_destroy(p);
-printk("Killed p\n");
-udelay(5000000);
-panic("This is okay");
+       struct proc *p ;
 
        switch (progress++) {
                case 0:
+                       // Here's how to do a multicored/parallel process:
+                       p = kfs_proc_create(kfs_lookup_path("roslib_mhello"));
+                       // being proper and all:
+                       proc_set_state(p, PROC_RUNNABLE_S);
+                       proc_set_state(p, PROC_RUNNING_S);
+                       proc_set_state(p, PROC_RUNNABLE_M);
+       
+                       // set vcoremap with dispatch plan.  usually done by schedule()
+                       spin_lock_irqsave(&p->proc_lock);
+                       p->num_vcores = 5; // assuming 5 are free, this is just an example
+                       spin_lock(&idle_lock); // need to grab the cores
+                       for (int i = 0; i < 5; i++) {
+                               // grab the last one on the list
+                               p->vcoremap[i] = idlecoremap[num_idlecores-1];
+                               num_idlecores--;
+                       }
+                       spin_unlock(&idle_lock);
+                       spin_unlock_irqsave(&p->proc_lock);
+                       proc_run(p);
+                       udelay(5000000);
+                       printk("Killing p\n");
+                       proc_destroy(p);
+                       printk("Killed p\n");
+                       udelay(1000000);
+                       panic("This is okay");
+                       break;
+               case 1:
                        envs[0] = kfs_proc_create(kfs_lookup_path("roslib_hello"));
                        proc_set_state(envs[0], PROC_RUNNABLE_S);
                        proc_run(envs[0]);
                        break;
        #ifdef __i386__
-               case 1:
+               case 2:
                        panic("Do not panic");
                        envs[0] = kfs_proc_create(kfs_lookup_path("parlib_channel_test_client"));
                        envs[1] = kfs_proc_create(kfs_lookup_path("parlib_channel_test_server"));
                        smp_call_function_single(1, run_env_handler, envs[0], 0);
                        smp_call_function_single(2, run_env_handler, envs[1], 0);
                        break;
-               case 2:
                case 3:
        #else // sparc
-               case 1:
+               case 2:
                        panic("Do not panic");
                        envs[0] = kfs_proc_create(kfs_lookup_path("roslib_proctests"));
                        envs[1] = kfs_proc_create(kfs_lookup_path("roslib_proctests"));
@@ -80,7 +88,7 @@ panic("This is okay");
                        envs[6] = kfs_proc_create(kfs_lookup_path("roslib_null"));
                        proc_run(envs[0]);
                        break;
-               case 2:
+               case 3:
                        #if 0
                        // reminder of how to spawn remotely
                        for (int i = 0; i < 8; i++) {
@@ -90,7 +98,6 @@ panic("This is okay");
                        }
                        process_workqueue();
                        #endif
-               case 3:
        #endif
 
                #if 0
index f664e47..7556b63 100644 (file)
@@ -45,6 +45,7 @@ static command_t commands[] = {
        { "kfs_ls", "List files in KFS", mon_kfs_ls},
        { "kfs_run", "Create and run a program from KFS", mon_kfs_run},
        { "manager", "Run the manager", mon_manager},
+       { "procinfo", "Show information about processes", mon_procinfo},
 };
 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
 
@@ -265,6 +266,23 @@ int mon_kfs_run(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
        return 0;
 }
 
+int mon_procinfo(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
+{
+       if (argc != 2) {
+               printk("Usage: procinfo OPTION\n");
+               printk("\tidle_cores: show idle core map\n");
+               printk("\trunnable: show proc_runnablelist\n");
+               return 1;
+       }
+       if (!strcmp(argv[1], "idle_cores"))
+               print_idlecoremap();
+       else if (!strcmp(argv[1], "runnable"))
+               dump_proclist(&proc_runnablelist);
+       else
+               printk("Bad option\n");
+       return 0;
+}
+
 /***** Kernel monitor command interpreter *****/
 
 #define WHITESPACE "\t\r\n "
index 4b4c304..4b38b4f 100644 (file)
@@ -322,10 +322,12 @@ user_mem_strlcpy(env_t *env, char *dst, const char *DANGEROUS va,
        if (len > 0) {
                while (1) {
                        char *c;
+                       // what if len was 1?
                        if (--len <= 0) break;
                        c = user_mem_check(env, src, 1, perm);
                        if (!c) break;
                        if (*c == '\0') break;
+                       // TODO: ivy bitches about this
                        *dst++ = *c;
                        src++;
                }
index ad87f7e..bd2f394 100644 (file)
@@ -26,6 +26,12 @@ spinlock_t freelist_lock = 0;
 struct proc_list proc_runnablelist = TAILQ_HEAD_INITIALIZER(proc_runnablelist);
 spinlock_t runnablelist_lock = 0;
 
+/* Tracks which cores are idle, similar to the vcoremap.  Each value is the
+ * physical coreid of an unallocated core. */
+spinlock_t idle_lock = 0;
+uint32_t idlecoremap[MAX_NUM_CPUS];
+uint32_t num_idlecores = 0;
+
 /*
  * While this could be done with just an assignment, this gives us the
  * opportunity to check for bad transitions.  Might compile these out later, so
@@ -148,7 +154,7 @@ void proc_run(struct proc *p)
                                 * there is a free active message slot, which could lock up the
                                 * system.  think about this. (TODO) */
                                for (int i = 1; i < p->num_vcores; i++)
-                                       send_active_msg_sync(p->vcoremap[i], __startcore, p, 0, 0);
+                                       send_active_msg_sync(p->vcoremap[i], __startcore, p, 0, i);
                        }
                        /* There a subtle (attempted) race avoidance here.  proc_startcore
                         * can handle a death message, but we can't have the startcore come
@@ -286,13 +292,28 @@ void proc_destroy(struct proc *p)
                        }
                        #endif
                        send_active_msg_sync(p->vcoremap[0], __death, 0, 0, 0);
+                       #if 0
+                       /* right now, RUNNING_S only runs on a mgmt core (0), not cores
+                        * managed by the idlecoremap.  so don't do this yet. */
+                       spin_lock(&idle_lock);
+                       idlecoremap[num_idlecores++] = p->vcoremap[0];
+                       spin_unlock(&idle_lock);
+                       #endif
                        break;
                case PROC_RUNNING_M:
-                       /* Send the DEATH message to every core running this process. */
-                       for (int i = 0; i < p->num_vcores; i++)
+                       /* Send the DEATH message to every core running this process, and
+                        * deallocate the cores.
+                        * The rule is that the vcoremap is set before proc_run, and reset
+                        * within proc_destroy */
+                       spin_lock(&idle_lock);
+                       for (int i = 0; i < p->num_vcores; i++) {
                                send_active_msg_sync(p->vcoremap[i], __death, 0, 0, 0);
-                       /* TODO: might need to update the pcoremap that's currently in
-                        * schedule, though probably not. */
+                               // give the pcore back to the idlecoremap
+                               assert(num_idlecores < num_cpus); // sanity
+                               idlecoremap[num_idlecores++] = p->vcoremap[i];
+                               p->vcoremap[i] = 0; // TODO: might need a better signal
+                       }
+                       spin_unlock(&idle_lock);
                        break;
                default:
                        panic("Weird state in proc_destroy");
@@ -383,3 +404,55 @@ void proc_decref(struct proc *p)
        if (!refcnt)
                env_free(p);
 }
+
+/* Active message handler to start a process's context on this core.  Tightly
+ * coupled with proc_run() */
+void __startcore(trapframe_t *tf, uint32_t srcid, uint32_t a0, uint32_t a1,
+                 uint32_t a2)
+{
+       uint32_t coreid = core_id();
+       struct proc *p_to_run = (struct proc *SAFE) TC(a0);
+       trapframe_t local_tf;
+       trapframe_t *tf_to_pop = (trapframe_t *SAFE) TC(a1);
+
+       printk("Startcore on core %d\n", coreid);
+       assert(p_to_run);
+       // TODO: handle silly state (HSS)
+       if (!tf_to_pop) {
+               tf_to_pop = &local_tf;
+               memset(tf_to_pop, 0, sizeof(*tf_to_pop));
+               proc_init_trapframe(tf_to_pop);
+               // Note the init_tf sets tf_to_pop->tf_esp = USTACKTOP;
+               proc_set_tfcoreid(tf_to_pop, a2);
+               proc_set_program_counter(tf_to_pop, p_to_run->env_entry);
+       }
+       proc_startcore(p_to_run, tf_to_pop);
+}
+
+/* Active message handler to stop running whatever context is on this core and
+ * to idle.  Note this leaves no trace of what was running.
+ * It's okay if death comes to a core that's already idling and has no current.
+ * It could happen if a process decref'd before proc_startcore could incref. */
+void __death(trapframe_t *tf, uint32_t srcid, uint32_t a0, uint32_t a1,
+             uint32_t a2)
+{
+       /* If we are currently running an address space on our core, we need a known
+        * good pgdir before releasing the old one.  This is currently the major
+        * practical implication of the kernel caring about a processes existence
+        * (the inc and decref).  This decref corresponds to the incref in
+        * proc_startcore (though it's not the only one). */
+       if (current) {
+               lcr3(boot_cr3);
+               proc_decref(current);
+               current = NULL;
+       }
+       smp_idle();
+}
+
+void print_idlecoremap(void)
+{
+       spin_lock(&idle_lock);
+       for (int i = 0; i < num_idlecores; i++)
+               printk("idlecoremap[%d] = %d\n", i, idlecoremap[i]);
+       spin_unlock(&idle_lock);
+}
index 8d3a8ca..5c2e53b 100644 (file)
@@ -53,6 +53,7 @@ strncpy(char *dst, const char *src, size_t size) {
 
        ret = dst;
        for (i = 0; i < size; i++) {
+               // TODO: ivy bitches about this
                *dst++ = *src;
                // If strlen(src) < size, null-pad 'dst' out to 'size' chars
                if (*src != '\0')
index 9be10bb..6088904 100644 (file)
@@ -26,8 +26,8 @@ vpd:
 .globl _start
 _start:
        // See if we are a new core
-       cmpl $1, %eax
-       je new_core
+       cmpl $0, %eax
+       jne new_core
 
        // See if we were started with arguments on the stack
        cmpl $USTACKTOP, %esp