Stacks and syscall support for parallel processes
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 10 Sep 2009 21:15:17 +0000 (14:15 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 19 Oct 2009 00:20:02 +0000 (17:20 -0700)
Userspace creates stacks via a primitive sys_mmap() in entry.S.  Tweak
as needed (such as bigger stacks, room for a guard page, etc).  The
kernel trap and systenter paths can now handle concurrent "trappers".
Blocking syscalls are still difficult (and not done).

x86 specific: sparc needs to make some functions and do similar things
in its entry.S and libmain.c.

12 files changed:
kern/arch/i386/trap.c
kern/include/ros/syscall.h
kern/include/syscall.h
kern/src/manager.c
kern/src/mm.c
kern/src/syscall.c
user/apps/roslib/mhello.c
user/roslib/inc/lib.h
user/roslib/src/i386/Makefrag
user/roslib/src/i386/entry.S
user/roslib/src/i386/libmain.c [new file with mode: 0644]
user/roslib/src/libmain.c

index 899b479..b8b51e1 100644 (file)
@@ -179,8 +179,9 @@ trap_dispatch(trapframe_t *tf)
                case T_SYSCALL:
                        // check for userspace, for now
                        assert(tf->tf_cs != GD_KT);
+                       // Note we pass the tf ptr along, in case syscall needs to block
                        tf->tf_regs.reg_eax =
-                               syscall(current, tf->tf_regs.reg_eax, tf->tf_regs.reg_edx,
+                               syscall(current, tf, tf->tf_regs.reg_eax, tf->tf_regs.reg_edx,
                                        tf->tf_regs.reg_ecx, tf->tf_regs.reg_ebx,
                                        tf->tf_regs.reg_edi, tf->tf_regs.reg_esi);
                        proc_startcore(current, tf); // Note the comment in syscall.c
@@ -214,10 +215,11 @@ env_pop_ancillary_state(env_t* e)
 void
 trap(trapframe_t *tf)
 {
-       //cprintf("Incoming TRAP frame at %p\n", tf);
+       //printk("Incoming TRAP frame on core %d at %p\n", core_id(), tf);
 
        // TODO: do this once we know we are are not returning to the current
        // context.  doing it now is safe. (HSS)
+       // we also need to sort this wrt multiple contexts
        env_push_ancillary_state(current);
 
        if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
@@ -225,18 +227,6 @@ trap(trapframe_t *tf)
                panic("Trapframe with invalid CS!");
        }
 
-       if ((tf->tf_cs & 3) == 3) {
-               // Trapped from user mode.
-               // TODO: this will change when an env has more than one context
-               // Copy trap frame (which is currently on the stack)
-               // into 'current->env_tf', so that running the environment
-               // will restart at the trap point.
-               assert(current);
-               current->env_tf = *tf;
-               // The trapframe on the stack should be ignored from here on.
-               tf = &current->env_tf;
-       }
-
        // Dispatch based on what type of trap occurred
        trap_dispatch(tf);
 
@@ -359,11 +349,8 @@ void sysenter_init(void)
 /* This is called from sysenter's asm, with the tf on the kernel stack. */
 void sysenter_callwrapper(struct Trapframe *tf)
 {
-       current->env_tf = *tf;
-
-       // The trapframe on the stack should be ignored from here on.
-       tf = &current->env_tf;
-       tf->tf_regs.reg_eax = (intreg_t) syscall(current,
+       // Note we pass the tf ptr along, in case syscall needs to block
+       tf->tf_regs.reg_eax = (intreg_t) syscall(current, tf,
                                                 tf->tf_regs.reg_eax,
                                                 tf->tf_regs.reg_edx,
                                                 tf->tf_regs.reg_ecx,
index 1b40e25..bbcb352 100644 (file)
@@ -1,57 +1,43 @@
 #ifndef ROS_INCLUDE_SYSCALL_H
 #define ROS_INCLUDE_SYSCALL_H
 
-#include <ros/common.h>
-#include <ros/ring_buffer.h>
-
-/* system call numbers */
-enum
-{
-       SYS_begofcalls, //Should always be first
-
-       SYS_null,
-       SYS_cache_buster,
-       SYS_cache_invalidate,
-       SYS_cputs,
-       SYS_cgetc,
-       SYS_getcpuid,
-
-       // The next 3 syscalls go with the experimental network
-       // driver. These syscalls are used by newlib_backend /
-       // our remote binary loader to pull data from / put data
-       // into a buffer managed by the network driver.
-       // These should go away as things mature. 
-       SYS_eth_read,
-       SYS_eth_write,
-       SYS_run_binary,
-       // End of extra network syscalls
-
-       SYS_getpid,
-       SYS_proc_destroy,
-       SYS_shared_page_alloc,
-       SYS_shared_page_free,
-       SYS_yield,
-       SYS_proc_create,
-       SYS_proc_run,
-
-       SYS_mmap,
-       SYS_brk,
-       /*
-       SYS_mprotect,
-       SYS_mremap,
-       SYS_mincore, // can read page tables instead
-       SYS_madvise,
-       SYS_mlock,
-       SYS_msync,
-       */
-
-       SYS_serial_write,
-       SYS_serial_read,
-       SYS_frontend,           // forward a syscall to front-end machine
-
-       SYS_endofcalls //Should always be last
-};
-#define NSYSCALLS (SYS_endofcalls -1)
+/* system call numbers.  need to #def them for use in assembly. */
+#define SYS_null                                        1
+#define SYS_cache_buster                        2
+#define SYS_cache_invalidate            3
+#define SYS_cputs                                       4
+#define SYS_cgetc                                       5
+#define SYS_getcpuid                            6
+#define SYS_getpid                                      7
+#define SYS_proc_destroy                        8
+#define SYS_shared_page_alloc           9
+#define SYS_shared_page_free           10
+#define SYS_yield                                      11
+#define SYS_proc_create                                12
+#define SYS_proc_run                           13
+#define SYS_mmap                                       14
+#define SYS_brk                                                15
+/*
+#define SYS_mprotect
+#define SYS_mremap
+#define SYS_mincore // can read page tables instead
+#define SYS_madvise
+#define SYS_mlock
+#define SYS_msync
+*/
+#define SYS_serial_write                       16
+#define SYS_serial_read                                17
+/* The next 3 syscalls go with the experimental network driver. These syscalls
+ * are used by newlib_backend / our remote binary loader to pull data from /
+ * put data into a buffer managed by the network driver.  These should go away
+ * as things mature. */
+#define SYS_eth_read                           18
+#define SYS_eth_write                          19
+#define SYS_run_binary                         20
+// forward a syscall to front-end machine
+#define SYS_frontend                           21
+// Keep this in sync with the last syscall number
+#define NSYSCALLS                                      21
 // syscall number starts at 1 and goes up to NSYSCALLS, without holes.
 #define INVALID_SYSCALL(syscallno) ((syscallno) > NSYSCALLS)
 
@@ -62,6 +48,11 @@ enum
 #define BUSTER_PRINT_TICKS             0x0008
 #define BUSTER_JUST_LOCKS              0x0010 // unimplemented
 
+#ifndef __ASSEMBLER__
+
+#include <ros/common.h>
+#include <ros/ring_buffer.h>
+
 #define NUM_SYSCALL_ARGS 6
 typedef struct syscall_req {
        uint32_t num;
@@ -78,4 +69,5 @@ typedef struct syscall_rsp {
 //DEFINE_RING_TYPES_WITH_SIZE(syscall, syscall_req_t, syscall_rsp_t, SYSCALLRINGSIZE);
 DEFINE_RING_TYPES(syscall, syscall_req_t, syscall_rsp_t);
 
+#endif /* __ASSEMBLER__ */
 #endif /* !ROS_INCLUDE_SYSCALL_H */
index 80ba8bc..0c2ac93 100644 (file)
@@ -7,8 +7,8 @@
 #include <ros/syscall.h>
 #include <process.h>
 
-intreg_t (syscall)(env_t* e, uintreg_t num, uintreg_t a1, uintreg_t a2,
-                   uintreg_t a3, uintreg_t a4, uintreg_t a5);
+intreg_t syscall(struct proc *p, trapframe_t *tf, uintreg_t num, uintreg_t a1,
+                 uintreg_t a2, uintreg_t a3, uintreg_t a4, uintreg_t a5);
 intreg_t syscall_async(env_t* e, syscall_req_t *syscall);
 intreg_t process_generic_syscalls(env_t* e, size_t max);
 #endif /* !ROS_KERN_SYSCALL_H */
index 8639de2..0317ce3 100644 (file)
@@ -68,9 +68,9 @@ void manager(void)
                        spin_unlock_irqsave(&p->proc_lock);
                        proc_run(p);
                        udelay(5000000);
-                       printk("Killing p\n");
-                       proc_destroy(p);
-                       printk("Killed p\n");
+       //              printk("Killing p\n");
+       //              proc_destroy(p);
+       //              printk("Killed p\n");
                        udelay(1000000);
                        panic("This is okay");
                        break;
index c2192e7..ce96409 100644 (file)
@@ -20,9 +20,6 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
                printk("[kernel] mmap() does not support files yet.\n");
                return (void*SAFE)TC(-1);
        }
-       if (flags != MAP_ANONYMOUS)
-               printk("[kernel] mmap() only supports MAP_ANONYMOUS for now, other"
-                      "flags ignored.\n");
        /* TODO: make this work, instead of a ghetto hack
         * Find a valid range, make sure it doesn't run into the kernel
         * make sure there's enough memory (not exceeding quotas)
@@ -44,6 +41,7 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        int num_pages = ROUNDUP(len, PGSIZE) / PGSIZE;
        pte_t *a_pte;
        // TODO: grab the appropriate mm_lock
+       spin_lock_irqsave(&p->proc_lock);
        // make sure all pages are available, and in a reasonable range
        // TODO: can probably do this better with vm_regions.
        for (int i = 0; i < num_pages; i++) {
@@ -65,6 +63,7 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
                }
        }
        // TODO: release the appropriate mm_lock
+       spin_unlock_irqsave(&p->proc_lock);
        return (void*SAFE)TC(addr);
 
        // TODO: if there's a failure, we should go back through the addr+len range
@@ -72,6 +71,7 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        // out of memory.
        mmap_abort:
                // TODO: release the appropriate mm_lock
+               spin_unlock_irqsave(&p->proc_lock);
                printk("[kernel] mmap() aborted!\n");
                // mmap's semantics.  we need a better error propagation system
                return (void*SAFE)TC(-1); // this is also ridiculous
index d83dd64..ebd80ec 100644 (file)
@@ -92,21 +92,21 @@ static ssize_t sys_run_binary(env_t* e, void *DANGEROUS binary_buf,
        proc_set_state(env, PROC_RUNNABLE_S);
        schedule_proc(env);
        sys_yield(e);
-       
+
        return 0;
 }
 
 #ifdef __NETWORK__
 // This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
-static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len) 
-{ 
+static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len)
+{
        extern int eth_up;
-       
+
        if (eth_up) {
-               
+
                if (len == 0)
                        return 0;
-               
+
                char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
                int total_sent = 0;
                int just_sent = 0;
@@ -115,25 +115,25 @@ static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len)
                        cur_packet_len = ((len - total_sent) > MAX_PACKET_DATA) ? MAX_PACKET_DATA : (len - total_sent);
                        char* wrap_buffer = packet_wrap(_buf + total_sent, cur_packet_len);
                        just_sent = send_frame(wrap_buffer, cur_packet_len + PACKET_HEADER_SIZE);
-                       
+
                        if (just_sent < 0)
                                return 0; // This should be an error code of its own
-                               
+
                        if (wrap_buffer)
                                kfree(wrap_buffer);
-                               
+
                        total_sent += cur_packet_len;
                }
-               
+
                return (ssize_t)len;
-               
+
        }
        else
                return -EINVAL;
 }
 
 // This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
-static ssize_t sys_eth_read(env_t* e, char *DANGEROUS buf, size_t len) 
+static ssize_t sys_eth_read(env_t* e, char *DANGEROUS buf, size_t len)
 {
        extern int eth_up;
 
@@ -148,21 +148,21 @@ static ssize_t sys_eth_read(env_t* e, char *DANGEROUS buf, size_t len)
                        return 0;
 
                char *CT(len) _buf = user_mem_assert(e, buf,len, PTE_U);
-                       
+
                if (packet_waiting == 0)
                        return 0;
-                       
+
                int read_len = ((packet_buffer_pos + len) > packet_buffer_size) ? packet_buffer_size - packet_buffer_pos : len;
 
                memcpy(_buf, packet_buffer + packet_buffer_pos, read_len);
-       
+
                packet_buffer_pos = packet_buffer_pos + read_len;
-       
+
                if (packet_buffer_pos == packet_buffer_size) {
                        kfree(packet_buffer_orig);
                        packet_waiting = 0;
                }
-       
+
                return read_len;
        }
        else
@@ -182,7 +182,7 @@ static ssize_t sys_shared_page_alloc(env_t* p1,
        //if (!VALID_USER_PERMS(p1_flags)) return -EPERM;
        //if (!VALID_USER_PERMS(p2_flags)) return -EPERM;
 
-       void * COUNT(1) * COUNT(1) addr = user_mem_assert(p1, _addr, sizeof(void *), 
+       void * COUNT(1) * COUNT(1) addr = user_mem_assert(p1, _addr, sizeof(void *),
                                                       PTE_USER_RW);
        page_t* page;
        env_t* p2 = &(envs[ENVX(p2_id)]);
@@ -432,22 +432,30 @@ static error_t sys_proc_run(struct proc *p, unsigned pid)
        return retval;
 }
 
-// TODO: Build a dispatch table instead of switching on the syscallno
-// Dispatches to the correct kernel function, passing the arguments.
-intreg_t syscall(env_t* e, uintreg_t syscallno, uintreg_t a1, uintreg_t a2,
-                 uintreg_t a3, uintreg_t a4, uintreg_t a5)
+/* Executes the given syscall.
+ *
+ * Note tf is passed in, which points to the tf of the context on the kernel
+ * stack.  If any syscall needs to block, it needs to save this info, as well as
+ * any silly state.
+ *
+ * TODO: Build a dispatch table instead of switching on the syscallno
+ * Dispatches to the correct kernel function, passing the arguments.
+ */
+intreg_t syscall(struct proc *p, trapframe_t *tf, uintreg_t syscallno,
+                 uintreg_t a1, uintreg_t a2, uintreg_t a3, uintreg_t a4,
+                                uintreg_t a5)
 {
        // Call the function corresponding to the 'syscallno' parameter.
        // Return any appropriate return value.
 
-       //cprintf("Incoming syscall number: %d\n    a1: %x\n   "
-       //        " a2: %x\n    a3: %x\n    a4: %x\n    a5: %x\n",
+       //cprintf("Incoming syscall on core: %d number: %d\n    a1: %x\n   "
+       //        " a2: %x\n    a3: %x\n    a4: %x\n    a5: %x\n", core_id(),
        //        syscallno, a1, a2, a3, a4, a5);
 
        // used if we need more args, like in mmap
        int32_t _a4, _a5, _a6, *COUNT(3) args;
 
-       assert(e); // should always have an env for every syscall
+       assert(p); // should always have an env for every syscall
        //printk("Running syscall: %d\n", syscallno);
        if (INVALID_SYSCALL(syscallno))
                return -EINVAL;
@@ -457,61 +465,61 @@ intreg_t syscall(env_t* e, uintreg_t syscallno, uintreg_t a1, uintreg_t a2,
                        sys_null();
                        return ESUCCESS;
                case SYS_cache_buster:
-                       sys_cache_buster(e, a1, a2, a3);
+                       sys_cache_buster(p, a1, a2, a3);
                        return 0;
                case SYS_cache_invalidate:
                        sys_cache_invalidate();
                        return 0;
                case SYS_shared_page_alloc:
-                       return sys_shared_page_alloc(e, (void** DANGEROUS) a1,
+                       return sys_shared_page_alloc(p, (void** DANGEROUS) a1,
                                                 a2, (int) a3, (int) a4);
                case SYS_shared_page_free:
-                       sys_shared_page_free(e, (void* DANGEROUS) a1, a2);
+                       sys_shared_page_free(p, (void* DANGEROUS) a1, a2);
                    return ESUCCESS;
                case SYS_cputs:
-                       return sys_cputs(e, (char *DANGEROUS)a1, (size_t)a2);
+                       return sys_cputs(p, (char *DANGEROUS)a1, (size_t)a2);
                case SYS_cgetc:
-                       return sys_cgetc(e);
+                       return sys_cgetc(p); // this will need to block
                case SYS_getcpuid:
                        return sys_getcpuid();
                case SYS_getpid:
-                       return sys_getenvid(e);
+                       return sys_getenvid(p);
                case SYS_proc_destroy:
-                       return sys_env_destroy(e, (envid_t)a1);
+                       return sys_env_destroy(p, (envid_t)a1);
                case SYS_yield:
-                       sys_yield(e);
+                       sys_yield(p);
                        return ESUCCESS;
                case SYS_proc_create:
-                       return sys_proc_create(e, (char *DANGEROUS)a1);
+                       return sys_proc_create(p, (char *DANGEROUS)a1);
                case SYS_proc_run:
-                       return sys_proc_run(e, (size_t)a1);
+                       return sys_proc_run(p, (size_t)a1);
                case SYS_mmap:
                        // we only have 4 parameters from sysenter currently, need to copy
                        // in the others.  if we stick with this, we can make a func for it.
-               args = user_mem_assert(e, (void*DANGEROUS)a4,
+                       args = user_mem_assert(p, (void*DANGEROUS)a4,
                                               3*sizeof(_a4), PTE_USER_RW);
                        _a4 = args[0];
                        _a5 = args[1];
                        _a6 = args[2];
-                       return (intreg_t) mmap(e, a1, a2, a3, _a4, _a5, _a6);
+                       return (intreg_t) mmap(p, a1, a2, a3, _a4, _a5, _a6);
                case SYS_brk:
                        printk("brk not implemented yet\n");
                        return -EINVAL;
 
        #ifdef __i386__
                case SYS_serial_write:
-                       return sys_serial_write(e, (char *DANGEROUS)a1, (size_t)a2);
+                       return sys_serial_write(p, (char *DANGEROUS)a1, (size_t)a2);
                case SYS_serial_read:
-                       return sys_serial_read(e, (char *DANGEROUS)a1, (size_t)a2);
+                       return sys_serial_read(p, (char *DANGEROUS)a1, (size_t)a2);
                case SYS_run_binary:
-                       return sys_run_binary(e, (char *DANGEROUS)a1,
+                       return sys_run_binary(p, (char *DANGEROUS)a1,
                                              (char* DANGEROUS)a2, (size_t)a3);
        #endif
        #ifdef __NETWORK__
                case SYS_eth_write:
-                       return sys_eth_write(e, (char *DANGEROUS)a1, (size_t)a2);
+                       return sys_eth_write(p, (char *DANGEROUS)a1, (size_t)a2);
                case SYS_eth_read:
-                       return sys_eth_read(e, (char *DANGEROUS)a1, (size_t)a2);
+                       return sys_eth_read(p, (char *DANGEROUS)a1, (size_t)a2);
        #endif
        #ifdef __sparc_v8__
                case SYS_frontend:
@@ -520,14 +528,14 @@ intreg_t syscall(env_t* e, uintreg_t syscallno, uintreg_t a1, uintreg_t a2,
 
                default:
                        // or just return -EINVAL
-                       panic("Invalid syscall number %d for env %x!", syscallno, *e);
+                       panic("Invalid syscall number %d for env %x!", syscallno, *p);
        }
        return 0xdeadbeef;
 }
 
 intreg_t syscall_async(env_t* e, syscall_req_t *call)
 {
-       return syscall(e, call->num, call->args[0], call->args[1],
+       return syscall(e, NULL, call->num, call->args[0], call->args[1],
                       call->args[2], call->args[3], call->args[4]);
 }
 
index 8b2dc7e..16e0e12 100644 (file)
@@ -18,21 +18,34 @@ void udelay(uint64_t usec, uint64_t tsc_freq)
        return;
 }
 
+#include <arch/atomic.h>
+
 int main(int argc, char** argv)
 {
-       void* addr;
-       cprintf("Multi-Goodbye, world, from PID: %d!\n", sys_getpid());
-       addr = sys_mmap((void*)USTACKTOP - 20*PGSIZE, 8*PGSIZE, 3, MAP_FIXED, 0, 0);
-       cprintf("got addr = 0x%08x\n", addr);
-       *(int*)addr = 0xdeadbeef;
-       *(int*)(addr + 3*PGSIZE) = 0xcafebabe;
-       // these should work
-       cprintf("reading addr: 0x%08x\n", *(int*)addr);
-       cprintf("reading addr+3pg: 0x%08x\n", *(int*)(addr + 3*PGSIZE));
-       // this should fault
-       //*(int*)(addr - 3*PGSIZE) = 0xdeadbeef;
-       while(1);
+       uint32_t vcoreid;
+       if ((vcoreid = newcore())) {
+               cprintf("Hello from vcore %d\n", vcoreid);
+       } else {
+               cprintf("Hello from else vcore 0\n");
+               void* addr;
+               cprintf("Multi-Goodbye, world, from PID: %d!\n", sys_getpid());
+               addr = sys_mmap((void*SNT)USTACKTOP - 20*PGSIZE, 8*PGSIZE, 3, MAP_FIXED, 0, 0);
+               cprintf("got addr = 0x%08x\n", addr);
+               *(int*)addr = 0xdeadbeef;
+               *(int*)(addr + 3*PGSIZE) = 0xcafebabe;
+               // these should work
+               cprintf("reading addr: 0x%08x\n", *(int*)addr);
+               cprintf("reading addr+3pg: 0x%08x\n", *(int*)(addr + 3*PGSIZE));
+               // this should fault
+               //*(int*)(addr - 3*PGSIZE) = 0xdeadbeef;
+       }
+       for (int i = 0; i < 10; i++) {
+               for (int j = 0; j < 10; j++)
+                       sys_null();
+               cprintf("Hello from vcore %d, iteration %d\n", vcoreid, i);
+       }
+       cprintf("Vcore %d Done!\n", vcoreid);
+       while (1);
        udelay(5000000, 1995014570); // KVM's freq.  Whatever.
-
        return 0;
 }
index f5ae3ec..b44cb70 100644 (file)
@@ -110,6 +110,11 @@ async_desc_t*COUNT(1) get_async_desc(void);
 syscall_desc_t* get_sys_desc(async_desc_t* desc);
 error_t get_all_desc(async_desc_t** a_desc, syscall_desc_t** s_desc);
 
+// Arch specific, in roslib/ARCH/libmain.c
+// Can move these to a inc/arch/lib.h when we don't maintain that symlink to the
+// kernel's arch folder
+uint32_t newcore(void);
+void setvcore0(void);
 
 /* File open modes */
 #define        O_RDONLY        0x0000          /* open for reading only */
index e7baf20..8000ea2 100644 (file)
@@ -10,5 +10,6 @@ OBJDIRS += $(USER_ROSLIB_ARCH_SRC_DIR)
 # We also snatch the use of a couple handy source files
 # from the lib directory, to avoid gratuitous code duplication.
 USER_ROSLIB_ARCH_SRCFILES := $(USER_ROSLIB_ARCH_SRC_DIR)/syscall.c \
+                             $(USER_ROSLIB_ARCH_SRC_DIR)/libmain.c \
                              $(USER_ROSLIB_ARCH_SRC_DIR)/entry.S
 
index 6088904..8e036ee 100644 (file)
@@ -1,5 +1,8 @@
 #include <arch/mmu.h>
+#include <arch/trap.h>
 #include <ros/memlayout.h>
+#include <ros/mman.h>
+#include <ros/syscall.h>
 
 .section .data
 
@@ -44,4 +47,32 @@ args_exist:
 1:      jmp 1b
 
 new_core:
+       movl %eax, %esi // save the vcoreid in esi
+
+       // compute USTACKTOP - PGSIZE*(%eax+1) (which is vcore_id+1), put in %edx
+       incl %eax;
+       movl $PGSIZE, %ebx
+       mull %ebx
+       movl $USTACKTOP, %edx
+       subl %eax, %edx
+       
+       // syscall, a1: edx, a2: ecx, a3: ebx, a4: edi
+       movl $PGSIZE, %ecx
+       movl $(PROT_READ|PROT_WRITE), %ebx
+       // the kernel uses arg4 of mmap to find the real arg4, 5 and 6
+       // WARNING!  keep this in sync!!
+       movl $mmap_args, %edi
+       mov $SYS_mmap, %eax
+       int $T_SYSCALL
+       addl $PGSIZE, %eax
+       movl %eax, %esp
+       movl %esi, %eax // restore the vcoreid
+       call main // main will check to see if it came from here or not
+       // spin when we return.  ought to yield before this ever happens
 2:             jmp 2b
+
+.data
+mmap_args:
+       .long MAP_ANONYMOUS|MAP_FIXED|MAP_STACK|MAP_POPULATE|MAP_GROWSDOWN // arg4
+       .long 0              // arg5
+       .long 0              // arg6
diff --git a/user/roslib/src/i386/libmain.c b/user/roslib/src/i386/libmain.c
new file mode 100644 (file)
index 0000000..941a73c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2009 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Arch specific implementations of lib.h functions.
+ */
+
+#include <lib.h>
+
+/* Return the vcoreid, which is set in entry.S right before calling libmain.
+ * This should only be used in libmain() and main(), before any code that might
+ * use a register.  It just returns eax. */
+uint32_t newcore(void)
+{
+    uint32_t eax;
+       asm volatile ("movl %%eax,%0" : "=a"(eax));
+    return eax;
+}
+
+/* This should only be used in libmain(), to reset eax before calling main from
+ * vcore0 (which is the only one calling libmain). */
+void setvcore0(void)
+{
+       asm volatile ("movl $0,%eax");
+}
index db5d508..9df8b6a 100644 (file)
@@ -37,6 +37,8 @@ void libmain(int argc, char * NTS * NT COUNT(argc) argv)
        if (argc > 0)
                binaryname = argv[0];
 
+       // signal main this is vcore0
+       setvcore0();
        // call user main routine
        main(argc, argv);