Merge branch 'master' into net-dev (with code changes listed below besides normal...
authorPaul Pearce <pearce@eecs.berkeley.edu>
Fri, 28 Aug 2009 03:18:57 +0000 (20:18 -0700)
committerPaul Pearce <pearce@eecs.berkeley.edu>
Fri, 28 Aug 2009 03:18:57 +0000 (20:18 -0700)
1) Kept several kmalloc changes that need to get worked back into the master. This is page_incref and size == 0 check
2) Reworked run_binary syscall to work with the new env/proc method. Now drops into kernel instead of back to matrix (need to fix)
3) Reordered things in kfs.c to match the Makefrag (measurements out of order). Also added draw_nanwan_standalone back into kern/src/Makefrag
4) Fixed some mptable odds and ends regarding entry counts of 0 and a left over variable from a previous commit.
5) Disabled deputy in kern/src/syscall.c. Several net-dev-only syscalls use unannoated structures from the driver, which will be going away with lwip

Conflicts:
kern/arch/i386/trap.c
kern/include/kmalloc.h
kern/include/ros/syscall.h
kern/include/string.h
kern/src/Makefrag
kern/src/env.c
kern/src/init.c
kern/src/kmalloc.c
kern/src/smp.c
kern/src/syscall.c
kern/src/testing.c
user/parlib/inc/parlib.h

24 files changed:
1  2 
.gitignore
kern/arch/i386/apic.c
kern/arch/i386/apic.h
kern/arch/i386/smp_boot.c
kern/arch/i386/trap.c
kern/include/kfs.h
kern/include/ros/syscall.h
kern/include/testing.h
kern/src/Makefrag
kern/src/init.c
kern/src/kfs.c
kern/src/kmalloc.c
kern/src/manager.c
kern/src/monitor.c
kern/src/mptables.c
kern/src/ne2k.c
kern/src/syscall.c
kern/src/testing.c
user/apps/parlib/Makefrag
user/apps/parlib/file_io.c
user/apps/parlib/matrix.c
user/parlib/inc/parlib.h
user/parlib/src/i386/newlib_backend.c
user/parlib/src/syscall.c

diff --cc .gitignore
@@@ -9,9 -10,12 +10,15 @@@ run_bochs.s
  update*
  cscope.out
  hdd.img
 +hdd.vdi
  *.*~
+ ivy_errordb.sql
  Makelocal
 +.textmate*
 +.DS_*
  ros-project.tmproj
+ kern/boot
+ kern/include/arch
+ kern/src/arch
+ doc/rosdoc
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,a4f42ff..d3f12fd
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,36 +1,36 @@@
 -#define MAX_KFS_FILES 10
+ /*
+  * Copyright (c) 2009 The Regents of the University of California
+  * Barret Rhoden <brho@cs.berkeley.edu>
+  * See LICENSE for details.
+  *
+  * KFS (Kernel File System)
+  *
+  * This gives runtime access to the binary blobs (usually userspace programs)
+  * linked at the end of the kernel.  Extremely rudimentary.
+  * Also allows for process creation from file (can consider moving this).
+  *
+  * Add the files you want in KFS in kfs.c.
+  */
+ #ifndef ROS_KERN_KFS_H
+ #define ROS_KERN_KFS_H
+ #include <arch/types.h>
+ #include <process.h>
+ // zra : putting nodeputy in header files makes life difficult.
+ //#pragma nodeputy
+ struct kfs_entry {
+       char (NT name)[256];
+       uint8_t *COUNT(size) start;
+       size_t size;
+ };
++#define MAX_KFS_FILES 11
+ extern struct kfs_entry kfs[MAX_KFS_FILES];
+ ssize_t kfs_lookup_path(char*NTS path);
+ struct proc *kfs_proc_create(int kfs_inode);
+ #endif // !ROS_KERN_KFS_H
@@@ -17,13 -17,10 +17,13 @@@ enu
        SYS_getcpuid,
        SYS_serial_write,
        SYS_serial_read,
 +      SYS_eth_read,
 +      SYS_eth_write,
 +      SYS_run_binary,
+       SYS_getpid,
+       SYS_proc_destroy,
        SYS_shared_page_alloc,
        SYS_shared_page_free,
-       SYS_getenvid,
-       SYS_env_destroy,
        SYS_yield,
        SYS_proc_create,
        SYS_proc_run,
@@@ -10,8 -10,8 +10,9 @@@
  
  void test_ipi_sending(void);
  void test_pic_reception(void);
 +void test_ioapic_pit_reroute(void);
  void test_print_info(void);
+ void test_page_coloring(void);
  void test_barrier(void);
  void test_interrupts_irqsave(void);
  void test_bitmasks(void);
@@@ -35,30 -29,30 +37,33 @@@ KERN_SRCFILES := $(KERN_ARCH_SRCFILES) 
                   $(KERN_SRC_DIR)/manager.c \
                   $(KERN_SRC_DIR)/syscall.c \
                   $(KERN_SRC_DIR)/timer.c \
+                  $(KERN_SRC_DIR)/kfs.c \
+                  $(KERN_SRC_DIR)/process.c \
                   $(KERN_SRC_DIR)/kmalloc.c \
 +                 $(KERN_SRC_DIR)/rl8168.c \
 +                 $(KERN_SRC_DIR)/ne2k.c \
+                  $(KERN_SRC_DIR)/schedule.c \
                   $(KERN_SRC_DIR)/testing.c
  
  # Only build files if they exist.
  KERN_SRCFILES := $(wildcard $(KERN_SRCFILES))
  
  KERN_APPFILES := \
-                     $(USER_APPS_ROSLIB_DIR)/proctests \
-                     $(USER_APPS_ROSLIB_DIR)/fptest \
-                     $(USER_APPS_ROSLIB_DIR)/null \
-                     $(USER_APPS_ROSLIB_DIR)/hello \
-                     $(USER_APPS_PARLIB_DIR)/draw_nanwan_standalone \
-                     $(USER_APPS_PARLIB_DIR)/channel_test_client \
-                     $(USER_APPS_PARLIB_DIR)/channel_test_server \
-                     $(USER_APPS_PARLIB_DIR)/matrix \
-                     $(USER_APPS_ROSLIB_DIR)/measurements
- #                    $(USER_APPS_PARLIB_DIR)/draw_nanwan
- #                    $(USER_APPS_PARLIB_DIR)/open_read \
- #                    $(USER_APPS_PARLIB_DIR)/hello
+                  $(USER_APPS_ROSLIB_DIR)/proctests \
+                  $(USER_APPS_ROSLIB_DIR)/fptest \
+                  $(USER_APPS_ROSLIB_DIR)/null \
+                  $(USER_APPS_ROSLIB_DIR)/spawn \
+                  $(USER_APPS_ROSLIB_DIR)/hello \
++                 $(USER_APPS_ROSLIB_DIR)/measurements \
++                 $(USER_APPS_PARLIB_DIR)/draw_nanwan_standalone \
+                  $(USER_APPS_PARLIB_DIR)/channel_test_client \
+                  $(USER_APPS_PARLIB_DIR)/channel_test_server \
 -                 $(USER_APPS_ROSLIB_DIR)/measurements \
+                  $(USER_APPS_PARLIB_DIR)/hello \
+                  $(USER_APPS_PARLIB_DIR)/matrix
+ #                 $(USER_APPS_PARLIB_DIR)/open_read
  
  KERN_LDFLAGS   := $(KERN_LDFLAGS) -L$(OBJDIR)/$(KERN_DIR) \
-                   -T $(ARCH_DIR)/$(TARGET_ARCH)/kernel.ld
+                   -T $(KERN_ARCH_SRC_DIR)/kernel.ld
  
  KERN_OBJFILES  := $(patsubst $(KERN_DIR)/%.c, \
                               $(OBJDIR)/$(KERN_DIR)/%.o, \
diff --cc kern/src/init.c
@@@ -60,26 -55,9 +61,14 @@@ void kernel_init(multiboot_info_t *mboo
        idt_init();
        sysenter_init();
        timer_init();
 -
 +      mptables_parse();
 +      pci_init();
 +      ioapic_init(); // MUST BE AFTER PCI/ISA INIT!
        // this returns when all other cores are done and ready to receive IPIs
        smp_boot();
-       /*
-       // this returns when all other cores are done and ready to receive IPIs
-       smp_boot();
-       test_smp_call_functions();
-       test_checklists();
-       test_barrier();
-       test_print_info();
-       test_lapic_status_bit();
-       test_ipi_sending();
-       test_pit();
-       */
 +      
 +      rl8168_init();          
 +      ne2k_init();
  
        manager();
  }
diff --cc kern/src/kfs.c
index 0000000,72a3f3b..b177b25
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,66 +1,68 @@@
 -DECL_PROG(parlib_matrix);
+ /*
+  * Copyright (c) 2009 The Regents of the University of California
+  * Barret Rhoden <brho@cs.berkeley.edu>
+  * See LICENSE for details.
+  */
+ #include <kfs.h>
+ #include <string.h>
+ #include <assert.h>
+ #include <ros/error.h>
+ #define DECL_PROG(x) \
+     extern uint8_t (COUNT(sizeof(size_t)) _binary_obj_user_apps_##x##_size)[],\
+         (COUNT(_binary_obj_user_apps_##x##_size)_binary_obj_user_apps_##x##_start)[];
+ #define KFS_ENTRY(x) {#x, _binary_obj_user_apps_##x##_start, (size_t) _binary_obj_user_apps_##x##_size},
+ /*
+  * Hardcode the files included in the KFS.  This needs to be in sync with the
+  * userapps in kern/src/Makefrag.
+  * Make sure to declare it, and add an entry.  Keep MAX_KFS_FILES big enough too
+  */
+ DECL_PROG(roslib_proctests);
+ DECL_PROG(roslib_fptest);
+ DECL_PROG(roslib_null);
+ DECL_PROG(roslib_spawn);
+ DECL_PROG(roslib_hello);
+ DECL_PROG(roslib_measurements);
++DECL_PROG(parlib_draw_nanwan_standalone);
+ DECL_PROG(parlib_channel_test_client);
+ DECL_PROG(parlib_channel_test_server);
 -      KFS_ENTRY(roslib_measurements)
+ DECL_PROG(parlib_hello);
++DECL_PROG(parlib_matrix);
+ struct kfs_entry kfs[MAX_KFS_FILES] = {
+       KFS_ENTRY(roslib_proctests)
+       KFS_ENTRY(roslib_fptest)
+       KFS_ENTRY(roslib_null)
+       KFS_ENTRY(roslib_spawn)
+       KFS_ENTRY(roslib_hello)
 -      KFS_ENTRY(parlib_matrix)
++        KFS_ENTRY(roslib_measurements)
++      KFS_ENTRY(parlib_draw_nanwan_standalone)
+       KFS_ENTRY(parlib_channel_test_client)
+       KFS_ENTRY(parlib_channel_test_server)
+       KFS_ENTRY(parlib_hello)
++      KFS_ENTRY(parlib_matrix)
+ };
+ ssize_t kfs_lookup_path(char* path)
+ {
+       for (int i = 0; i < MAX_KFS_FILES; i++)
+               // need to think about how to copy-in something of unknown length
+               if (!strncmp(kfs[i].name, path, strlen(path)))
+                       return i;
+       return -EINVAL;
+ }
+ /*
+  * Creates a process from the file pointed to by the KFS inode (index)
+  * This should take a real inode or something to point to the real location,
+  * and env_create shouldn't assume everything is contiguous
+  */
+ struct proc *kfs_proc_create(size_t kfs_inode)
+ {
+       if (kfs_inode < 0 || kfs_inode >= MAX_KFS_FILES)
+               panic("Invalid kfs_inode.  Check you error codes!");
+       return env_create(kfs[kfs_inode].start, kfs[kfs_inode].size);
+ }
  #include <ros/error.h>
  #include <pmap.h>
  #include <kmalloc.h>
+ #include <stdio.h>
  
 -#define kmallocdebug(args...)  printk(args)
 +#define kmallocdebug(args...)  //printk(args)
  
+ char*BND(end, maxaddrpa_ptr + IVY_KERNBASE) boot_freemem;
  static page_list_t pages_list;        //List of physical pages used by kmalloc
- extern size_t naddrpage;
  
- void kmalloc_init() {
+ /*
+  * Allocate n bytes of physical memory aligned on an 
+  * align-byte boundary.  Align must be a power of two.
+  * Return kernel virtual address.  Returned memory is uninitialized.
+  *
+  * If we're out of memory, boot_alloc should panic.
+  * This function may ONLY be used during initialization,
+  * before the page_free_list has been set up.
+  */
+ void* boot_alloc(uint32_t n, uint32_t align)
+ {
+       extern char (SNT end)[];
+       void *v;
+       // Initialize boot_freemem if this is the first time.
+       // 'end' is a magic symbol automatically generated by the linker,
+       // which points to the end of the kernel's bss segment -
+       // i.e., the first virtual address that the linker
+       // did _not_ assign to any kernel code or global variables.
+       if (boot_freemem == 0) {
+               boot_freemem = TC(end);
+       }
+       //      Step 1: round boot_freemem up to be aligned properly
+       boot_freemem = PTRROUNDUP(boot_freemem, align);
+       //      Step 2: save current value of boot_freemem as allocated chunk
+       v = boot_freemem;
+       //  Step 2.5: check if we can alloc
+       if (PADDR(boot_freemem + n) > maxaddrpa)
+               panic("Out of memory in boot alloc, you fool!\n");
+       //      Step 3: increase boot_freemem to record allocation
+       boot_freemem += n;      
+       //      Step 4: return allocated chunk
+       return v;
+ }
+ void* boot_calloc(uint32_t _n, size_t sz, uint32_t align)
+ {
+       extern char (SNT end)[];
+       uint32_t n = _n *sz;
+       void *v;
+       // Initialize boot_freemem if this is the first time.
+       // 'end' is a magic symbol automatically generated by the linker,
+       // which points to the end of the kernel's bss segment -
+       // i.e., the first virtual address that the linker
+       // did _not_ assign to any kernel code or global variables.
+       if (boot_freemem == 0)
+               boot_freemem = TC(end);
+       //      Step 1: round boot_freemem up to be aligned properly
+       boot_freemem = PTRROUNDUP(boot_freemem, align);
+       //      Step 2: save current value of boot_freemem as allocated chunk
+       v = boot_freemem;
+       //  Step 2.5: check if we can alloc
+       if (PADDR(boot_freemem + n) > maxaddrpa)
+               panic("Out of memory in boot alloc, you fool!\n");
+       //      Step 3: increase boot_freemem to record allocation
+       boot_freemem += n;
+       //  Step 4: zero allocated chunk
+       memset(v,0,n);
+       //      Step 5: return allocated chunk
+       return v;
+ }
+ void kmalloc_init() 
+ {
        LIST_INIT(&pages_list);
  }
  
- void *(DALLOC(size) kmalloc)(size_t size, int flags) {
-       
-       if(size == 0)
+ void* kmalloc(size_t size, int flags) 
+ {
++      // ****** NEXT CONDITION MUST BE MERGED INTO MASTER!!! -PAUL *******
++      if (size == 0)
 +              return NULL;
++
        int npages = ROUNDUP(size, PGSIZE) / PGSIZE;
        
        // Find 'npages' free consecutive pages
        int first = -1;
-       kmallocdebug("naddrpage: %u\n", naddrpage);
+       kmallocdebug("naddrpages: %u\n", naddrpages);
        kmallocdebug("npages: %u\n", npages);
-       for(int i=(naddrpage-1); i>=(npages-1); i--) {
+       for(int i=(naddrpages-1); i>=(npages-1); i--) {
                int j;
 -              for(j=i; j>=i-(npages-1); j--) {
 +              for(j=i; j>=(i-(npages-1)); j--) {
                        if( !page_is_free(j) )
                                break;
                }
        for(int i=0; i<npages; i++) {
                page_t* page;
                page_alloc_specific(&page, first+i);
-               page->pp_ref++; // Kevin doesnt like this.
++              // NEXT LINE MUST BE MERGED INTO MASTER (Also, Kevin doesn't like.)
++              page_incref(page); 
                page->num_cons_links = npages-i;
-               LIST_INSERT_HEAD(&pages_list, page, pp_link);
+               LIST_INSERT_HEAD(&pages_list, page, global_link);
                kmallocdebug("mallocing page: %u\n", first+i);
                kmallocdebug("at addr: %p\n", ppn2kva(first+i));
        }
@@@ -26,9 -26,6 +26,7 @@@ void manager(void
  {
        static uint8_t progress = 0;
        env_t *envs[256];
-       env_run(ENV_CREATE(parlib_matrix));
-       
 +      
  
        switch (progress++) {
                case 0:
Simple merge
index c0e3522,0000000..c4817cd
mode 100644,000000..100644
--- /dev/null
@@@ -1,445 -1,0 +1,452 @@@
-       mp_proc_entries = kmalloc(mp_entries_count[PROC] * basetableEntryTypes[PROC].length , 0);
-       mp_bus_entries = kmalloc(mp_entries_count[BUS] * basetableEntryTypes[BUS].length , 0);
-       mp_ioapic_entries = kmalloc(mp_entries_count[IOAPIC] * basetableEntryTypes[IOAPIC].length , 0);
-       mp_int_entries = kmalloc(mp_entries_count[INT] * basetableEntryTypes[INT].length , 0);
-       mp_lint_entries = kmalloc(mp_entries_count[LINT] * basetableEntryTypes[LINT].length , 0);
 +#include <arch/mmu.h>
 +#include <arch/x86.h>
 +#include <arch/smp.h>
 +#include <arch/apic.h>
 +#include <arch/ioapic.h>
 +
 +
 +#include <ros/memlayout.h>
 +
 +#include <stdio.h>
 +#include <string.h>
 +#include <pmap.h>
 +#include <kmalloc.h>
 +
 +#include <mptables.h>
 +#include <pci.h>
 +
 +/* Basic MP Tables Parser
 + *
 + * Memory Locations and table structs taken from FreeBSD's mptable.c and modified.
 + *
 + * Put cool text here
 + * 
 + * TODO: Extended table support
 + * TODO: KMALLOC null checks
 + * TODO: Error checking, pci device not found, etc.
 + */
 +
 +
 +tableEntry basetableEntryTypes[] =
 +{
 +    { 0, 20, "Processor" },
 +    { 1,  8, "Bus" },
 +    { 2,  8, "I/O APIC" },
 +    { 3,  8, "I/O INT" },
 +    { 4,  8, "Local INT" }
 +};
 +
 +// Important global items
 +enum interrupt_modes current_interrupt_mode;
 +
 +proc_entry *COUNT(mp_entries_count[PROC]) mp_proc_entries;
 +bus_entry *COUNT(mp_entries_count[BUS]) mp_bus_entries;
 +ioapic_entry *COUNT(mp_entries_count[IOAPIC]) mp_ioapic_entries;
 +int_entry *COUNT(mp_entries_count[INT]) mp_int_entries;
 +int_entry *COUNT(mp_entries_count[LINT]) mp_lint_entries; // Not a type. lint entries == int entries
 +
 +
 +int mp_entries_count[NUM_ENTRY_TYPES]; // How large each array is.
 +
 +pci_int_group pci_int_groups[PCI_MAX_BUS][PCI_MAX_DEV];
 +isa_int_entry isa_int_entries[NUM_IRQS];
 +ioapic_entry ioapic_entries[IOAPIC_MAX_ID];
 +
 +void mptables_parse() {
 +      
 +      mpfps_t *mpfps;
 +      
 +      // Memsets.
 +      // Setup the indexable ioapic array.
 +      // YOU MUST check the flag field to see if its 0. If 0, unusable.
 +      // Ths is defined by MPTables, and I leaverage this with the memset below.
 +      memset(ioapic_entries, 0, sizeof(ioapic_entries));
 +      
 +      // We define an IOAPIC ID over 255 to be invalid.
 +      memset(pci_int_groups, 0xFF, sizeof(pci_int_groups));
 +      memset(isa_int_entries, 0xFF, sizeof(isa_int_entries));
 +      
 +      
 +      mptables_info("Starting MPTables Parsing...\n");
 +      
 +      // Basic struct:
 +      //      1) Find floating pointer
 +      //      2) Go to addr referenced by floating pointer
 +      //      3) Read table header info
 +      
 +      // We now have to search through 3 address regions searching for a magic string.
 +      
 +      // I unrolled this loop because I thought it was easier to read. This can be 
 +      // easily packed into a for loop on an array.
 +      
 +      // Note: The pointer can actually be elsewhere. See the FBSD MPTables implimentation for more info
 +      // Just doesn't make sense right now to check more places.
 +      
 +      // Search the BIOS ROM Address Space (MOST LIKELY)
 +      mptables_dump("-->Searching BIOS ROM Area...\n");
 +      mpfps = find_floating_pointer((physaddr_t)KADDR(BIOS_ROM_BASE), (physaddr_t)KADDR(BIOS_ROM_BOUND));
 +      
 +      if (mpfps == NULL) {
 +              
 +              // Search the EBDA UNTESTED
 +              
 +              // First, we have to find the darn EBDA Addr.
 +              // This USSUALLY works. May be some cases where it doesnt.
 +              // See osdev x86 mem-map for more information
 +              physaddr_t ebda_base = read_mmreg32((uint32_t)KADDR(EBDA_POINTER));
 +              
 +              if (ebda_base) {
 +                      ebda_base = ebda_base << 4;
 +                      ebda_base = (physaddr_t)KADDR(ebda_base);
 +                      physaddr_t ebda_bound = ebda_base + EBDA_SIZE - sizeof(mpfps_t);
 +                      
 +                      mptables_dump("-->Searching EBDA...\n");
 +                      mpfps = find_floating_pointer(ebda_base, ebda_bound);
 +              }
 +      }
 +
 +      if (mpfps == NULL) {
 +              // Search the last KB of system memory UNTESTED
 +              // Note: Will only be there if it not in the EBDA. So this must be called after the EBDA check.
 +              // This logic is ripped from mptables without much understanding. No machine to test it on.
 +              
 +              physaddr_t top_of_mem = read_mmreg32((uint32_t)KADDR(TOPOFMEM_POINTER));
 +              
 +              if (top_of_mem) {
 +                      --top_of_mem;
 +                      top_of_mem = top_of_mem * 1024;
 +                      
 +                      top_of_mem = (physaddr_t)KADDR(top_of_mem);
 +              
 +              mptables_dump("-->Searching top of (real mode) Ram...\n");
 +                      mpfps = find_floating_pointer(top_of_mem, top_of_mem + 1024 - sizeof(mpfps_t));
 +              }
 +      }
 +      
 +      if (mpfps == NULL) {
 +              // Search the last KB of system memory based on a 640K limited, due to CMOS lying
 +              // Note: Will only be there if it not in the EBDA. So this must be called after the EBDA check.
 +                              
 +              physaddr_t top_of_mem = DEFAULT_TOPOFMEM;
 +              
 +              if (top_of_mem) {
 +                              
 +                      top_of_mem = top_of_mem - 1024;
 +                      
 +                      top_of_mem = (physaddr_t)KADDR(top_of_mem);
 +              
 +              mptables_dump("-->Searching top of (real mode) Ram 640K cap, incase CMOS lied...\n");
 +                      mpfps = find_floating_pointer(top_of_mem, top_of_mem + 1024 - sizeof(mpfps_t));
 +              }
 +      }
 +
 +      // If we can't find the pointer, it means we are running on a non-mp compliant machine.
 +      // This is bad. We can't do interrupts the way we want.
 +      // We could have this trigger a MODE in which we operate using the standard PIC, if we really wanted.
 +      if (mpfps == NULL) {
 +              panic("MPTABLES Not found. IOAPIC and interrupts will not function properly. <Insert whale held up by smaller birds here>");
 +      }
 +      
 +      mptables_info("-->MPTables Floating Pointer Structure found @ KVA 0x%p.\n", mpfps);
 +      
 +      mptables_info("-->Current Interrupt Mode: ");
 +      // Identify our interrupt mode
 +      if (mpfps->mpfb2 & IMCRP_MASK) {
 +              current_interrupt_mode = PIC;
 +              mptables_info("PIC\n");
 +      }
 +      else {
 +              current_interrupt_mode = VW;
 +              mptables_info("Virtual Wire\n");
 +      }
 +      
 +      configuration_parse((physaddr_t)KADDR((uint32_t)(mpfps->pap)));
 +      
 +      proc_parse();
 +      bus_parse();
 +      ioapic_parse();
 +      int_parse();
 +      lint_parse();
 +      
 +}
 +
 +// Searches the given address range, starting at addr first, to (including) last, for the mptables pointer.
 +// Does not esure base/bounds are sane.
 +mpfps_t *find_floating_pointer(physaddr_t base, physaddr_t bound) {
 +
 +      uint32_t count = (bound - base + sizeof(mpfps_t))/sizeof(mpfps_t);
 +
 +      // This trusted count was authorized with the blessing of Zach.
 +      // Blame Intel and the MP Spec for making me do this cast.
 +      mpfps_t* mpfps = (mpfps_t* COUNT(count)) TC(base);
 +
 +      // Loop over the entire range looking for the signature. The signature is ascii _MP_, which is
 +      //  stored in the given MP_SIG
 +      while ( ((physaddr_t)mpfps <= bound) && (read_mmreg32((uint32_t)(mpfps->signature)) != MP_SIG)) {
 +              mpfps++;
 +      }
 +      
 +      if ((physaddr_t)mpfps > bound) 
 +              return NULL;
 +      
 +      // Now perform a checksum on the float
 +      if (checksum((physaddr_t)mpfps, sizeof(mpfps_t) * mpfps->length) == FALSE) {
 +              mptables_dump("-->Failed a MPTables Floating Pointer Structure checksum @ KVA 0x%p.\n", mpfps);
 +              
 +              // If we fail we need to keep checking. But if we are on the last addr
 +              //      we just fail.
 +              if ((physaddr_t)mpfps == bound)
 +                      return NULL;
 +              
 +              return find_floating_pointer((physaddr_t)(mpfps + 1), bound);
 +      }
 +      
 +      return mpfps;
 +}
 +
 +bool checksum(physaddr_t addr, uint32_t len) {
 +      // MP Table checksums must add up to 0.
 +      uint8_t checksum = 0;
 +      
 +      // Yet another trusted cast. 
 +      // See comment at start of find_floating_pointer
 +      uint8_t *addr_p = (uint8_t* COUNT(len)) TC(addr);
 +
 +      for (int i = 0; i < len; i++)
 +              checksum += *(addr_p + i);
 +
 +      return (checksum == 0);
 +}
 +
 +// Go over the configuration table and parse / load the data into the global variables
 +// NOTE: This uses kmalloc. Might be cleaner (but less flexable) to allocate fixed amounts
 +//    set to high numbers.
 +void configuration_parse(physaddr_t conf_addr) {
 +      
 +      int num_processed[NUM_ENTRY_TYPES];
 +      
 +      // Another. See comment at start of find_floating_pointer
 +      mpcth_t *mpcth = (mpcth_t* COUNT(1)) TC(conf_addr);
 +      
 +      for (int i = 0; i < NUM_ENTRY_TYPES; i++) {
 +              mp_entries_count[i] = num_processed[i] = 0;
 +      }
 +              
 +      // Do 1 pass to figure out how much space to allocate.
 +      uint16_t num_entries = mpcth->entry_count;
 +      uint16_t mpct_length = mpcth->base_table_length;
 +      uint16_t entry_length = mpct_length - sizeof(mpcth);
 +      
 +      // Now perform a checksum on the configuration table
 +      if (checksum((physaddr_t)mpcth, mpct_length) == FALSE) {
 +              panic("FAILED MP CONFIGURATION CHECKSUM.");
 +      }
 +      
 +      uint8_t * COUNT(entry_length) entry_base = (uint8_t* COUNT(entry_length)) TC(mpcth + 1);
 +      uint8_t * BND(entry_base, entry_base + entry_length) current_addr = entry_base;
 +      
 +      for (int i = 0; i < num_entries; i++) {
 +              uint8_t current_type = *current_addr;
 +              if (current_type >= NUM_ENTRY_TYPES)
 +                      panic("CORRUPT MPTABLES CONFIGURATION ENTRY");
 +                      
 +              mp_entries_count[current_type]++;
 +              current_addr += basetableEntryTypes[current_type].length;
 +      }
 +      
 +      // Allocate the correct space in the arrays (unrolled for ivy reasons)
-       num_ioapics = mp_entries_count[IOAPIC];
++      if (mp_entries_count[PROC] != 0)
++              mp_proc_entries = kmalloc(mp_entries_count[PROC] * basetableEntryTypes[PROC].length , 0);
++
++      if (mp_entries_count[BUS] != 0)
++              mp_bus_entries = kmalloc(mp_entries_count[BUS] * basetableEntryTypes[BUS].length , 0);
++
++      if (mp_entries_count[IOAPIC] != 0)
++              mp_ioapic_entries = kmalloc(mp_entries_count[IOAPIC] * basetableEntryTypes[IOAPIC].length , 0);
++      
++      if (mp_entries_count[INT] != 0)
++              mp_int_entries = kmalloc(mp_entries_count[INT] * basetableEntryTypes[INT].length , 0);
++
++      if (mp_entries_count[LINT] != 0)
++              mp_lint_entries = kmalloc(mp_entries_count[LINT] * basetableEntryTypes[LINT].length , 0);
 +      
 +      current_addr = entry_base;
 +      
 +      for (int i = 0; i < num_entries; i++) {
 +              uint8_t current_type = *((uint8_t*)current_addr);
 +              if (current_type >= NUM_ENTRY_TYPES)
 +                      panic("CORRUPT MPTABLES CONFIGURATION ENTRY.. after we already checked? Huh.");
 +              
 +              if (num_processed[current_type] >= mp_entries_count[current_type])
 +                      panic("MPTABLES LIED ABOUT NUMBER OF ENTRIES. NO IDEA WHAT TO DO!");
 +              
 +              switch (current_type) {
 +                      case PROC:
 +                              memcpy( &mp_proc_entries[num_processed[PROC]], 
 +                                              current_addr,  
 +                                              basetableEntryTypes[PROC].length);
 +                              break;
 +                      
 +                      case BUS:
 +                              memcpy( &mp_bus_entries[num_processed[BUS]], 
 +                                              current_addr,  
 +                                              basetableEntryTypes[BUS].length);
 +                              break;
 +                      case IOAPIC:
 +                              memcpy( &mp_ioapic_entries[num_processed[IOAPIC]], 
 +                                              // This is needed due to the void* in the entry
 +                                              //  no clean way of doing this. Sorry Zach.
 +                                              (ioapic_entry* COUNT(1)) TC(current_addr),  
 +                                              basetableEntryTypes[IOAPIC].length);
 +                              break;
 +                      case INT:
 +                              memcpy( &mp_int_entries[num_processed[INT]], 
 +                                              current_addr,  
 +                                              basetableEntryTypes[INT].length);
 +                              break;
 +                      case LINT:
 +                              memcpy( &mp_lint_entries[num_processed[LINT]], 
 +                                              (void*)current_addr,  
 +                                              basetableEntryTypes[LINT].length);
 +                              break;
 +                                              
 +                      default: panic("UNKNOWN ENTRY TYPE");
 +              }
 +
 +              num_processed[current_type]++;
 +              current_addr += basetableEntryTypes[current_type].length;
 +      }
 +      
 +      // We'd do extended table support stuff here (or alter the loop above)
 +      
 +      // We now have all of our entries copied into a single structure we can index into. Yay.
 +}
 +
 +void proc_parse() {
 +      // For now, we don't do anything with the processor entries. Just print them.
 +      
 +      for (int i = 0; i < mp_entries_count[PROC]; i++){
 +              mptables_dump("Proc entry %u\n", i);
 +              mptables_dump("-->type: %x\n", mp_proc_entires[i].type);
 +              mptables_dump("-->apicID: %x\n", mp_proc_entires[i].apicID);
 +              mptables_dump("-->apicVersion: %x\n", mp_proc_entires[i].apicVersion);
 +              mptables_dump("-->cpuFlags: %x\n", mp_proc_entires[i].cpuFlags);
 +              mptables_dump("-->cpuSignaure: %x\n", mp_proc_entires[i].cpuSignature);
 +              mptables_dump("-->featureFlags: %x\n", mp_proc_entires[i].featureFlags);
 +      }
 +      
 +      mptables_dump("\n");
 +}
 +
 +void bus_parse() {
 +      // Do we need to sort this?
 +      // For now, don't. We assume the index into this structure matches the type.
 +      // This seems to be implied from the configuration
 +      
 +      for (int i = 0; i < mp_entries_count[BUS]; i++){
 +              if (i != mp_bus_entries[i].busID) 
 +                      panic("Oh noes! We need to sort entries. The MP Spec lied! Ok lied is too strong a word, it implied.");
 +                      
 +              mptables_dump("Bus entry %u\n", i);
 +              mptables_dump("-->type: %x\n", mp_bus_entries[i].type);
 +              mptables_dump("-->BusID: %x\n", mp_bus_entries[i].busID);
 +              mptables_dump("-->Bus: %c%c%c\n", mp_bus_entries[i].busType[0], mp_bus_entries[i].busType[1], mp_bus_entries[i].busType[2]);
 +      
 +      }
 +      
 +      mptables_dump("\n");
 +}
 +
 +void ioapic_parse() {
 +
 +      // Note: We don't check if the apicFlags is 0. If zero, unusable
 +      // This should be done elsewhere.
 +      
-               if (mp_ioapic_entries[i].apicID > max_ioapic_id)
-                       max_ioapic_id = mp_ioapic_entries[i].apicID;
++      // mp_entries_count[IOAPIC] contains the number of ioapics on this system
 +      
 +      for (int i = 0; i < mp_entries_count[IOAPIC]; i++){
 +              mptables_dump("IOAPIC entry %u\n", i);
 +              mptables_dump("-->type: %x\n", mp_ioapic_entries[i].type);
 +              mptables_dump("-->apicID: %x\n", mp_ioapic_entries[i].apicID);
 +              mptables_dump("-->apicVersion: %x\n", mp_ioapic_entries[i].apicVersion);
 +              mptables_dump("-->apicFlags: %x\n", mp_ioapic_entries[i].apicFlags);
 +              mptables_dump("-->apicAddress: %p\n", mp_ioapic_entries[i].apicAddress);
 +              
 +      }
 +      mptables_dump("\n");
 +      
 +      for (int i = 0; i < mp_entries_count[IOAPIC]; i++) {
 +              memcpy((void*)(ioapic_entries + mp_ioapic_entries[i].apicID), (void*)(mp_ioapic_entries + i), sizeof(ioapic_entry));
 +      }
 +}
 +
 +void int_parse() {
 +      // create a massive array, tied together with bus/dev, for indexing
 +      
 +      for (int i = 0; i < mp_entries_count[INT]; i++){
 +              mptables_dump("Interrupt entry %u\n", i);
 +              mptables_dump("-->type: %x\n", mp_int_entries[i].type);
 +              mptables_dump("-->intType: %x\n", mp_int_entries[i].intType);
 +              mptables_dump("-->intFlags: %x\n", mp_int_entries[i].intFlags);
 +              mptables_dump("-->srcBusID: %u\n", mp_int_entries[i].srcBusID);
 +              mptables_dump("-->srcDevice: %u (PCI ONLY)\n", (mp_int_entries[i].srcBusIRQ >> 2) & 0x1F);
 +              mptables_dump("-->srcBusIRQ: %x\n", mp_int_entries[i].srcBusIRQ);
 +              mptables_dump("-->dstApicID: %u\n", mp_int_entries[i].dstApicID);
 +              mptables_dump("-->dstApicINT: %u\n", mp_int_entries[i].dstApicINT);
 +                                      
 +      }
 +      mptables_dump("\n");
 +
 +      // Populate the PCI/ISA structure with the interrupt entries.
 +      for (int i = 0; i < mp_entries_count[INT]; i++) {
 +              if (strncmp(mp_bus_entries[mp_int_entries[i].srcBusID].busType, "PCI", 3) == 0) {
 +                      int bus_idx, dev_idx, int_idx;
 +                      bus_idx = mp_int_entries[i].srcBusID;
 +                      dev_idx = (mp_int_entries[i].srcBusIRQ >> 2) & 0x1F;
 +                      int_idx = mp_int_entries[i].srcBusIRQ & 0x3;
 +                      pci_int_groups[bus_idx][dev_idx].intn[int_idx].dstApicID = mp_int_entries[i].dstApicID;
 +                      pci_int_groups[bus_idx][dev_idx].intn[int_idx].dstApicINT = mp_int_entries[i].dstApicINT;
 +              }
 +              
 +              if (strncmp(mp_bus_entries[mp_int_entries[i].srcBusID].busType, "ISA", 3) == 0) {
 +                      int irq = mp_int_entries[i].srcBusIRQ;
 +                      int int_type = mp_int_entries[i].intType;
 +                      
 +                      if (int_type == 3) {
 +                              // THIS IS WHERE THE PIC CONNECTS TO THE IOAPIC
 +                              // WE DON'T CURRENTLY DO ANYTHING WITH THIS, BUT SHOULD WE NEED TO
 +                              // HERES WHERE TO LOOK!
 +                              // WE MUST NOT PLACE THIS INTO OUR TABLE AS IRQ HAS NO REAL MEANING AFAPK
 +                              continue;
 +                              
 +                              // Note. On the dev boxes the pit and pic both claim to be on irq 0
 +                              // However the pit and the pic are on different ioapic entries.
 +                              // Seems odd. Not sure whats up with this. Paul assumes the IRQ has no meaning
 +                              // in regards to the pic... which makes sense.
 +                      }
 +                                              
 +                      if ((isa_int_entries[irq].dstApicID != 0xFFFF) && 
 +                               ((isa_int_entries[irq].dstApicID != mp_int_entries[i].dstApicID) 
 +                                 || (isa_int_entries[irq].dstApicINT != mp_int_entries[i].dstApicINT)))
 +                              panic("SAME IRQ MAPS TO DIFFERENT IOAPIC/INTN'S. THIS DEFIES LOGIC.");
 +                      
 +                      isa_int_entries[irq].dstApicID = mp_int_entries[i].dstApicID;
 +                      isa_int_entries[irq].dstApicINT = mp_int_entries[i].dstApicINT;
 +              }                       
 +      }
 +}
 +
 +void lint_parse() {
 +      // For now, we don't do anything with the local interrupt entries
 +      
 +      for (int i = 0; i < mp_entries_count[LINT]; i++){
 +              mptables_dump("Local Interrupt entry %u\n", i);
 +              mptables_dump("-->type: %x\n", mp_lint_entries[i].type);
 +              mptables_dump("-->intType: %x\n", mp_lint_entries[i].intType);
 +              mptables_dump("-->srcBusID: %x\n", mp_lint_entries[i].srcBusID);
 +              mptables_dump("-->srcBusIRQ: %x\n", mp_lint_entries[i].srcBusIRQ);
 +              mptables_dump("-->dstApicID: %p\n", mp_lint_entries[i].dstApicID);
 +              mptables_dump("-->dstApicINT: %p\n", mp_lint_entries[i].dstApicINT);
 +              
 +      }
 +}
diff --cc kern/src/ne2k.c
index a80ed68,0000000..d657291
mode 100644,000000..100644
--- /dev/null
@@@ -1,163 -1,0 +1,164 @@@
 +#ifdef __DEPUTY__
 +#pragma nodeputy
 +#endif
 +
 +#include <arch/mmu.h>
 +#include <arch/x86.h>
 +#include <arch/smp.h>
 +#include <arch/apic.h>
 +
 +#include <ros/memlayout.h>
 +
 +#include <atomic.h>
 +#include <stdio.h>
 +#include <string.h>
 +#include <trap.h>
 +#include <kmalloc.h>
 +
 +#include <pmap.h>
 +#include <pci.h>
 +#include <ne2k.h>
++#include <timing.h>
 +
 +/* NE2000 NIC Driver Sketch
 + *
 + * Written by Paul Pearce.
 + *
 + */
 +
 +extern uint32_t eth_up; // Fix this                               
 +uint32_t ne2k_irq;      // And this
 +uint32_t ne2k_io_base_addr;
 +
 +
 +void ne2k_init() {
 +      
 +      if (ne2k_scan_pci() < 0) return;
 +      ne2k_setup_interrupts();
 +      ne2k_configure_nic();
 +      eth_up = 1;
 +      
 +      return;
 +}
 +
 +
 +int ne2k_scan_pci() {
 +      
 +      extern pci_dev_entry pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
 +      extern uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
 +
 +      cprintf("Searching for NE2000 Network device...");
 +
 +      for (int i = 0; i < PCI_MAX_BUS; i++)
 +              for (int j = 0; j < PCI_MAX_DEV; j++)
 +                      for (int k = 0; k < PCI_MAX_FUNC; k++) {
 +                              uint32_t address;
 +                              uint32_t lbus = i;
 +                              uint32_t ldev = j;
 +                              uint32_t lfunc = k;
 +                              uint32_t lreg = 0; 
 +                              uint32_t result  = 0;
 +      
 +                              uint16_t dev_id = pci_dev_map[i][j][k].dev_id;
 +                              uint16_t ven_id = pci_dev_map[i][j][k].ven_id;
 +
 +                              // Vender DNE
 +                              if (ven_id == INVALID_VENDOR_ID) 
 +                                      continue;
 +
 +                              // Ignore non RealTek 8168 Devices
 +                              if (ven_id != NE2K_VENDOR_ID || dev_id != NE2K_DEV_ID)
 +                                      continue;
 +                              cprintf(" found on BUS %x DEV %x\n", i, j);
 +
 +                              // Find the IRQ
 +                              ne2k_irq = pci_irq_map[i][j][k];
 +                              ne2k_debug("-->IRQ: %u\n", ne2k_irq);
 +
 +                              // Loop over the BARs
 +                              for (int k = 0; k <= 5; k++) {
 +                                      lreg = 4 + k;
 +                                      address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg << 2); 
 +                              outl(PCI_CONFIG_ADDR, address);
 +                              result = inl(PCI_CONFIG_DATA);
 +                                      
 +                                      if (result == 0) // (0 denotes no valid data)
 +                                              continue;
 +
 +                                      // Read the bottom bit of the BAR. 
 +                                      if (result & PCI_BAR_IO_MASK) {
 +                                              result = result & PCI_IO_MASK;
 +                                              ne2k_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
 +                                      } else {
 +                                              result = result & PCI_MEM_MASK;
 +                                              ne2k_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
 +                                      }
 +                      
 +                                      // TODO Switch to memory mapped instead of IO?
 +                                      if (k == 0) // BAR0 denotes the IO Addr for the device
 +                                              ne2k_io_base_addr = result;                                             
 +                              }
 +                              
 +              return 0;
 +      }
 +      cprintf(" not found. No device configured.\n");
 +      
 +      return -1;
 +}
 +
 +void ne2k_configure_nic() {
 +      
 +      ne2k_debug("-->Configuring Device.\n");
 +
 +        // Reset
 +      inb(ne2k_io_base_addr + 0x1f);
 +
 +      // Configure
 +        outb(ne2k_io_base_addr + 0x00, 0x22);
 +        outb(ne2k_io_base_addr + 0x07, 0xFF);
 +      outb(ne2k_io_base_addr + 0x0F, 0xFF);
 +
 +        uint8_t isr = inb(ne2k_io_base_addr + 0x07);
 +        //cprintf("isr: %x\n", isr);
 +
 +
 +      cprintf("Generating Interrupt...\n");
 +      outb(ne2k_io_base_addr + 0x0A, 0x00);
 +      outb(ne2k_io_base_addr + 0x0B, 0x00);
 +      outb(ne2k_io_base_addr + 0x00, 0x0A);
 +      udelay(10000000);
 +
 +        cprintf("Generating Interrupt again...\n");
 +        outb(ne2k_io_base_addr + 0x0A, 0x00);
 +        outb(ne2k_io_base_addr + 0x0B, 0x00);
 +        outb(ne2k_io_base_addr + 0x00, 0x0A);
 +        udelay(10000000);
 +      
 +      return;
 +}
 +
 +void ne2k_setup_interrupts() {
 +      
 +      extern handler_t interrupt_handlers[];
 +      
 +      ne2k_debug("-->Setting interrupts.\n");
 +      
 +      // Kernel based interrupt stuff
 +      register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + ne2k_irq, ne2k_interrupt_handler, 0);
 +      
 +      ioapic_route_irq(ne2k_irq, 6);  
 +      
 +      return;
 +}
 +
 +// We need to evaluate this routine in terms of concurrency.
 +// We also need to figure out whats up with different core interrupts
 +void ne2k_interrupt_handler(trapframe_t *tf, void* data) {
 +      
 +      cprintf("\nNE2K interrupt on core %u!\n", lapic_get_id());
 +      uint8_t isr= inb(ne2k_io_base_addr + 0x07);
 +      cprintf("isr: %x\n", isr);
 +      outb(ne2k_io_base_addr + 0x07, isr);
 +
 +      return;                         
 +}
@@@ -1,8 -1,5 +1,10 @@@
  /* See COPYRIGHT for copyright information. */
 +#ifdef __DEPUTY__
 +#pragma nodeputy
 +#endif
 +
++
  #include <arch/types.h>
  #include <arch/arch.h>
  #include <arch/mmu.h>
  #include <ros/timer.h>
  #include <ros/error.h>
  
 +#include <rl8168.h>
  #include <string.h>
  #include <assert.h>
- #include <env.h>
+ #include <process.h>
+ #include <schedule.h>
  #include <pmap.h>
  #include <trap.h>
  #include <syscall.h>
 +#include <kmalloc.h>
+ #include <stdio.h>
+ #include <kfs.h> // eventually replace this with vfs.h
  
  //Do absolutely nothing.  Used for profiling.
  static void sys_null(void)
@@@ -55,107 -53,16 +60,109 @@@ static ssize_t sys_serial_read(env_t* e
        #endif
  }
  
- static ssize_t sys_run_binary(env_t* e, void* binary_buf, void* arg, size_t len) {
++static ssize_t sys_run_binary(env_t* e, void *binary_buf, void* arg, size_t len) {
 +      uint8_t* new_binary = kmalloc(len, 0);
 +      if(new_binary == NULL)
 +              return -ENOMEM;
 +      memcpy(new_binary, binary_buf, len);
 +
-       env_t* env = env_create((uint8_t*)new_binary, len);
++        env_t* env = env_create((uint8_t*)new_binary, len);
 +      kfree(new_binary);
-       
-       e->env_status = ENV_RUNNABLE;
-       env_run(env);
++      proc_set_state(env, PROC_RUNNABLE_S);
++        proc_run(env);
++
 +      return 0;
 +}
 +
 +// This is probably 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) 
 +{ 
 +      extern int eth_up;
 +      
 +      if (eth_up) {
 +              
 +              char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
 +              int total_sent = 0;
 +              int just_sent = 0;
 +              int cur_packet_len = 0;
 +              while (total_sent != 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;
 +}
 +/*
 +static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len) 
 +{ 
 +      extern int eth_up;
 +      
 +      if (eth_up) {
 +              
 +              char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
 +              
 +              return(send_frame(buf, len));
 +      }
 +      return -EINVAL;
 +}
 +*/
 +
 +
 +// This is probably 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) 
 +{
 +      extern int eth_up;
 +      
 +      if (eth_up) {
 +              extern int packet_waiting;
 +              extern int packet_buffer_size;
 +              extern char* packet_buffer;
 +              extern char* packet_buffer_orig;
 +              extern int packet_buffer_pos;
 +                      
 +              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
 +              return -EINVAL;
 +}
 +
- static ssize_t sys_shared_page_alloc(env_t* p1, 
-                                      void** addr, envid_t p2_id, 
+ static ssize_t sys_shared_page_alloc(env_t* p1,
+                                      void**DANGEROUS _addr, envid_t p2_id,
                                       int p1_flags, int p2_flags
-                                     ) 
+                                     )
  {
-       if (!VALID_USER_PERMS(p1_flags)) return -EPERM;
-       if (!VALID_USER_PERMS(p2_flags)) return -EPERM;
+       //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 *), 
+                                                       PTE_USER_RW);
        page_t* page;
        env_t* p2 = &(envs[ENVX(p2_id)]);
        error_t e = page_alloc(&page);
  #include <string.h>
  #include <testing.h>
  #include <trap.h>
- #include <env.h>
+ #include <process.h>
  #include <syscall.h>
+ #include <timing.h>
+ #include <kfs.h>
+ #include <multiboot.h>
+ #include <pmap.h>
+ #include <page_alloc.h>
  
 +#include <pmap.h>
 +
  #define test_vector 0xeb
  
- #if 0
+ #ifdef __i386__
  
  void test_ipi_sending(void)
  {
@@@ -75,25 -75,9 +77,26 @@@ void test_pic_reception(void
        enable_irq();
        while(1);
  }
- #endif
  
-       extern handler_t interrupt_handlers[];
-       register_interrupt_handler(interrupt_handlers, 0x20, test_hello_world_handler, 0);
 +void test_ioapic_pit_reroute(void) 
 +{
++      register_interrupt_handler(interrupt_handlers, 0x20, test_hello_world_handler, NULL);
 +      ioapic_route_irq(0, 3); 
 +
 +      cprintf("Starting pit on core 3....\n");
 +      udelay(3000000);
 +      pit_set_timer(0xFFFE,TIMER_RATEGEN); // totally arbitrary time
 +      
 +      udelay(3000000);
 +      ioapic_unroute_irq(0);
 +      udelay(300000);
 +      cprintf("Masked pit. Waiting before return...\n");
 +      udelay(3000000);
 +}
 +
+ #endif // __i386__
++
  void test_print_info(void)
  {
        cprintf("\nCORE 0 asking all cores to print info:\n");
Simple merge
Simple merge
Simple merge
@@@ -33,14 -30,11 +30,14 @@@ ssize_t     sys_cputs(const uint8_t *s
  uint16_t    sys_cgetc(void);
  ssize_t     sys_serial_write(void* buf, size_t len); 
  ssize_t     sys_serial_read(void* buf, size_t len);
- ssize_t     sys_shared_page_alloc(void *COUNT(PGSIZE) *addr, envid_t p2, 
 +ssize_t     sys_eth_write(void* buf, size_t len); 
 +ssize_t     sys_eth_read(void* buf, size_t len);
 +ssize_t     sys_run_binary(void* binary_buf, void* arg, size_t len);
+ int         sys_getpid(void);
+ size_t      sys_getcpuid(void);
+ error_t     sys_proc_destroy(int pid);
+ ssize_t     sys_shared_page_alloc(void *COUNT(PGSIZE) *addr, pid_t p2, 
                                    int p1_flags, int p2_flags);
- ssize_t     sys_shared_page_free(void *COUNT(PGSIZE) addr, envid_t p2);
- envid_t     sys_getenvid(void);
- envid_t     sys_getcpuid(void);
- void        sys_env_destroy(envid_t);
+ ssize_t     sys_shared_page_free(void *COUNT(PGSIZE) addr, pid_t p2);
  
  #endif        // !ROS_INC_LIB_H
index 0000000,1011086..ddc6267
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,789 +1,793 @@@
 -#define debug_in_out(...) // debug(__VA_ARGS__)  
+ /* See COPYRIGHT for copyright information. */
+ /* Kevin Klues <klueska@cs.berkeley.edu>      */
+ #ifdef __DEPUTY__
+ #pragma nodeputy
+ #endif
+ #include <parlib.h>
+ #include <unistd.h>
+ #include <newlib_backend.h>
+ #include <string.h>
+ #include <malloc.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <debug.h>
 -      int just_read = sys_serial_read(buf, len);
++#define debug_in_out(...)  //debug(__VA_ARGS__)  
+ #define debug_write_check(fmt, ...) // debug(fmt, __VA_ARGS__)
+ /* environ
+  * A pointer to a list of environment variables and their values. 
+  * For a minimal environment, this empty list is adequate.
+  */
+ char *__env[1] = { 0 };
+ char **environ = __env;
+ /* _exit()
+  * Exit a program without cleaning up files. 
+  * If your system doesn't provide this, it is best to avoid linking 
+  * with subroutines that require it (exit, system).
+  */
+ void _exit(int __status) _ATTRIBUTE ((noreturn))
+ {
+       sys_proc_destroy(sys_getpid()); // TODO: can run getpid and cache it
+       while(1); //Should never get here...
+ }
+     
+ /* close()
+  * Close a file. 
+  */
+ int close(int file) {
+       debug_in_out("CLOSE\n");
+       // If trying to close stdin/out/err just return
+       if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
+                                    || (file == STDOUT_FILENO))
+               return 0;
+       // Allocate a new buffer of proper size
+       char *out_msg = malloc(CLOSE_MESSAGE_FIXED_SIZE);
+       if (out_msg == NULL)
+               return -1;
+       char *out_msg_pos = out_msg;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = CLOSE_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int*)out_msg_pos) = file;
+       out_msg_pos += sizeof(int);
+       // Send message
+       char *result = send_message(out_msg, CLOSE_MESSAGE_FIXED_SIZE);
+       free(out_msg);
+       int return_val;
+       if (result != NULL) {
+               // Read result
+               return_val = *((int *) result);
+               if (return_val == -1) errno = *(((int *)result) + 1);
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = -1;
+       }
+       
+       return return_val;
+ }
+ /* execve()
+  * Transfer control to a new process. 
+  * Minimal implementation (for a system without processes).
+  */
+ int execve(char *name, char **argv, char **env) 
+ {
+       debug_in_out("EXECVE\n");
+       errno = ENOMEM;
+       return -1;
+ }
+ /* fork()
+  * Create a new process. 
+  * Minimal implementation (for a system without processes).
+  */
+ int fork(void) 
+ {
+       debug_in_out("FORK\n");
+       errno = EAGAIN;
+     return -1;
+ }
+ /* fstat()
+  * Status of an open file. 
+  * For consistency with other minimal implementations in these stubs, 
+  * all files are regarded as character special devices. 
+  * The sys/stat.h header file required is distributed in the include 
+  * subdirectory for the newlib C library.
+  */
+ int fstat(int file, struct stat *st) 
+ {
+       debug_in_out("FSTAT\n");        
+       st->st_mode = S_IFCHR;
+       
+       // stdout hack
+       if (file == 1)
+               st->st_mode = 8592;
+       return 0;
+       // Allocate a new buffer of proper size
+       char *out_msg = malloc(FSTAT_MESSAGE_FIXED_SIZE);
+       if(out_msg == NULL)
+               return -1;
+       char *out_msg_pos = out_msg;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = FSTAT_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int*)out_msg_pos) = file;
+       out_msg_pos += sizeof(int);
+       // Send message
+       char *result = send_message(out_msg, FSTAT_MESSAGE_FIXED_SIZE);
+       free(out_msg);
+       // Read result
+       int return_val;
+       if (result != NULL) {
+               return_val = *((int *)result);
+               if (return_val == -1)
+                       errno = *(((char *)result) + 
+                                        sizeof(int) + sizeof(struct stat));
+               else
+                       memcpy(st, ((int *)result) + 1, sizeof(struct stat));
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = -1;
+       }
+       return return_val;
+ }
+ /* getpid()
+  * Process-ID; this is sometimes used to generate strings unlikely to 
+  * conflict with other processes. Minimal implementation, for a system 
+  * without processes.
+  */
+ int getpid(void) 
+ {
+       return sys_getpid(); // TODO: can run getpid and cache it
+ }
+ /* isatty()
+  * Query whether output stream is a terminal. 
+  * For consistency with the other minimal implementations, 
+  * which only support output to stdout, this minimal 
+  * implementation is suggested.
+  */
+ int isatty(int file) 
+ {
+       debug_in_out("ISATTY\n");
+       // Cheap hack to avoid sending serial comm for stuff we know
+       if ((STDIN_FILENO == file) || (STDOUT_FILENO == file) 
+                                || (STDERR_FILENO == file))
+               return 1;
+       
+       // Allocate a new buffer of proper size
+       char *out_msg = malloc(ISATTY_MESSAGE_FIXED_SIZE);
+       if(out_msg == NULL)
+               return -1;
+       char *out_msg_pos = out_msg;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = ISATTY_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int*)out_msg_pos) = file;
+       out_msg_pos += sizeof(int);
+       // Send message
+       char *result = send_message(out_msg, ISATTY_MESSAGE_FIXED_SIZE);
+       free(out_msg);
+       int return_val;
+       if (result != NULL) {
+               // Read result
+               return_val = *((int *) result);
+               if (return_val == 0) errno = *(((int *)result) + 1);
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = 0;
+       }
+       
+       return return_val;
+ }
+ /* kill()
+  * Send a signal. 
+  * Minimal implementation.
+  */
+ int kill(int pid, int sig) 
+ {
+       debug_in_out("KILL\n");
+       errno = EINVAL;
+     return -1;
+ }
+ /* link()
+  * Establish a new name for an existing file. 
+  * Minimal implementation.
+  */
+ int link(char *old, char *new) 
+ {
+       debug_in_out("LINK\n");
+       
+       int s_len_old = strlen(old) + 1; // Null terminator
+       int s_len_new = strlen(new) + 1; // Null terminator
+       int out_msg_len = LINK_MESSAGE_FIXED_SIZE + s_len_old + s_len_new;
+       // Allocate a new buffer of proper size
+       char *out_msg = malloc(out_msg_len);
+       char *out_msg_pos = out_msg;
+       if (out_msg == NULL)
+               return -1;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = LINK_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int*)out_msg_pos) = s_len_old;
+       out_msg_pos += sizeof(int);
+       *((int*)out_msg_pos) = s_len_new;
+       out_msg_pos += sizeof(int);
+       memcpy(out_msg_pos, old, s_len_old);
+       out_msg_pos += s_len_old;
+       memcpy(out_msg_pos, new, s_len_new);
+       // Send message
+       char *result = send_message(out_msg, out_msg_len);
+       free(out_msg);
+       // Read result
+       int return_val;
+       if (result != NULL) {
+               return_val = *((int *)result);
+               if (return_val == -1) errno = *(((int *)result) + 1);
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = -1;
+       }
+       return return_val;
+ }
+ /* lseek()
+  * Set position in a file. 
+  * Minimal implementation.
+  */
+ off_t lseek(int file, off_t ptr, int dir) 
+ {
+       debug_in_out("LSEEK\n");        
+       
+       // Allocate a new buffer of proper size
+       char *out_msg = malloc(LSEEK_MESSAGE_FIXED_SIZE);
+       if(out_msg == NULL)
+               return -1;
+       char *out_msg_pos = out_msg;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = LSEEK_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int*)out_msg_pos) = file;
+       out_msg_pos += sizeof(int);
+       *((int*)out_msg_pos) = ptr;
+       out_msg_pos += sizeof(int);
+       *((int*)out_msg_pos) = dir;
+       out_msg_pos += sizeof(int);
+       // Send message
+       char *result = send_message(out_msg, LSEEK_MESSAGE_FIXED_SIZE);
+       free(out_msg);
+       int return_val;
+       if (result != NULL) {
+               // Read result
+               return_val = *((int *) result);
+               if (return_val == -1) errno = *(((int *)result) + 1);
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = -1;
+       }
+       return return_val;
+ }
+ /* open()
+  * Open a file. 
+  */
+ int open(const char *name, int flags, int mode) 
+ {
+       debug_in_out("OPEN\n");
+       int s_len = strlen(name) + 1; // Null terminator
+       int out_msg_len = OPEN_MESSAGE_FIXED_SIZE + s_len;
+       // Allocate a new buffer of proper size
+       char *out_msg = malloc(out_msg_len);
+       char *out_msg_pos = out_msg;
+       if (out_msg == NULL)
+               return -1;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = OPEN_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int*)out_msg_pos) = flags;
+       out_msg_pos += sizeof(int);
+       *((int*)out_msg_pos) = mode;
+       out_msg_pos += sizeof(int);
+       *((int*)out_msg_pos) = s_len;
+       out_msg_pos += sizeof(int);
+       memcpy(out_msg_pos, name, s_len);
+       // Send message
+       char *result = send_message(out_msg, out_msg_len);
+       free(out_msg);
+       // Read result
+       int return_val;
+       if (result != NULL) {
+               return_val = *((int *)result);
+               if (return_val == -1) errno = *(((int *)result) + 1);
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = -1;
+       }
+       return return_val;
+ }
+ /* read()
+  * Read from a file. 
+  */
+ ssize_t read(int file, void *ptr, size_t len) 
+ {
+       debug_in_out("READ\n");
+       if (file == STDIN_FILENO) {
+               for(int i=0; i<len; i++)        
+                       ((uint8_t*)ptr)[i] = sys_cgetc();
+               return len;
+       }
+       // Allocate a new buffer of proper size
+       char *out_msg = (char*)malloc(READ_MESSAGE_FIXED_SIZE);
+       if (out_msg == NULL)
+               return -1;
+       char *out_msg_pos = out_msg;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = READ_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int *)out_msg_pos) = file;
+       out_msg_pos += sizeof(int);
+       *((int *)out_msg_pos) = len;
+       out_msg_pos += sizeof(int);
+       // Send message
+       char *result = send_message(out_msg, READ_MESSAGE_FIXED_SIZE);
+       free(out_msg);
+       // Read result
+       int return_val;
+       if (result != NULL) {
+               return_val = *((int *)result);
+               if (return_val > 0)
+                       memcpy(ptr, ((int *)result) + 1, return_val);
+               else 
+                       errno = *(((int *)result) + 1);
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = -1;
+       }
+       return return_val;
+ }
+ /* Read len bytes from the given channel to the buffer.
+  * If peek is NO_PEEK, will wait indefinitely until that much data is read.
+  * If peek is PEEK, if no data is available, will return immediately.
+  *            However once some data is available, 
+  *                      will block until the entire amount is available.
+  */
+ int read_from_channel(char * buf, int len, int peek)
+ {
+       // TODO: NEED TO IMPLIMENT A TIMEOUT
+       //                      Also, watch out for CONNECTION TERMINATED
+       int total_read = 0;
 -              just_read = sys_serial_read(buf + total_read, len - total_read);
 -
++      //int just_read = sys_serial_read(buf, len);
++      int just_read = sys_eth_read(buf, len);
+       if (just_read < 0) return just_read;
+       if (just_read == 0 && peek) return just_read;
+       total_read += just_read;
+       while (total_read != len) {
 -      #define HEAP_SIZE 8192
++              //just_read = sys_serial_read(buf + total_read, len - total_read);
++              just_read = sys_eth_read(buf + total_read, len - total_read);
++              
+               if (just_read == -1) return -1;
+               total_read += just_read;
+       }
+       return total_read;
+ }
+ /* sbrk()
+  * Increase program data space. 
+  * As malloc and related functions depend on this, it is 
+  * useful to have a working implementation. 
+  * The following suffices for a standalone system; it exploits the 
+  * symbol _end automatically defined by the GNU linker.
+  */
+ void* sbrk(ptrdiff_t incr) 
+ {
+       debug_in_out("SBRK\n");
+       debug_in_out("\tincr: %u\n", incr);     
 -      return sys_serial_write((char*)msg, len);
++      #define HEAP_SIZE (1<<18)
+       static uint8_t array[HEAP_SIZE];
+       static uint8_t* heap_end = array;
+       static uint8_t* stack_ptr = &(array[HEAP_SIZE-1]);
+       uint8_t* prev_heap_end; 
+       prev_heap_end = heap_end;
+       if (heap_end + incr > stack_ptr) {
+               errno = ENOMEM;
+               return (void*)-1;
+       }
+      
+       heap_end += incr;
+       debug_in_out("\treturning: %u\n", prev_heap_end);
+       return (caddr_t) prev_heap_end;
+ }
+ /* send_message()
+  * Write the message in buffer out on the channel, and wait for a response.
+  * Caller is responsible for management of buffer passed in and buffer returned.
+  */
+ char *send_message(char *message, int len)
+ {
+       syscall_id_t this_call_id = *((syscall_id_t*)message);
+       if (write_to_channel(message, len) != len)
+               return NULL;
+       int response_value;
+       // Pull the response from the server out of the channel.
+       if (read_from_channel( (char*)&response_value, 
+                                sizeof(int), 
+                                NO_PEEK) == -1) 
+               return NULL;
+       char* return_msg = NULL;
+       char* errno_pos = NULL;
+       int extra_space = (response_value == -1) ? sizeof(int) : 0;
+       // TODO: Make these sizes an array we index into, and only have this code once.
+       // TODO: Will have a flag that tells us we have a variable length response (right now only for read case)
+       // TODO: Default clause with error handling.
+       switch (this_call_id) {
+               case ISATTY_ID:
+                       // This case must be at the top! Else extra space will be wrong at times 
+                       // ISATTY is special, 0 signifies error, not -1. Annoying.
+                       extra_space = (response_value == 0) ? sizeof(int) : 0;
+               case OPEN_ID:           
+               case CLOSE_ID:
+               case WRITE_ID:  
+               case LSEEK_ID:
+               case UNLINK_ID:
+               case LINK_ID:
+                         return_msg = (char*)malloc(sizeof(int) + extra_space);
+                       if (return_msg == NULL)
+                                 return NULL;
+                       errno_pos = return_msg + sizeof(int);
+                         if (extra_space && (-1 == read_from_channel(errno_pos,
+                                                                     sizeof(int), 
+                                                                     NO_PEEK))) {
+                               free(return_msg);
+                                 return NULL;
+                       }
+                         break;
+                 case STAT_ID:
+               case FSTAT_ID:
+                       return_msg = (char*)malloc(sizeof(int) 
+                                                     + sizeof(struct stat)
+                                                     + extra_space);
+                         if (return_msg == NULL)
+                                 return NULL;
+                       if (-1 == read_from_channel(return_msg + sizeof(int),
+                                                     sizeof(struct stat), 
+                                                     NO_PEEK)) {
+                               free(return_msg);
+                                 return NULL;
+                       }
+                         errno_pos = return_msg + sizeof(int) 
+                                                + sizeof(struct stat);
+                         if (extra_space && (-1 == read_from_channel(errno_pos,
+                                                                     sizeof(int), 
+                                                                     NO_PEEK))) {
+                               free(return_msg);
+                               return NULL;
+                       }
+                       break;
+               
+               case READ_ID:
+                       if (response_value > 0)
+                               extra_space = response_value;
+                       else
+                               extra_space = extra_space;
+                       return_msg = (char*)malloc(sizeof(int) + extra_space);
+                       if (return_msg == NULL)
+                               return NULL;
+                       if (-1 == read_from_channel(return_msg + sizeof(int),
+                                                     extra_space,
+                                                     NO_PEEK)) {
+                                 free(return_msg);
+                                 return NULL;
+                         }
+                       break;
+       }
+       // Copy response value in place
+       memcpy(return_msg, &response_value, sizeof(int));
+       return return_msg;
+ }
+ /* stat()
+  * Status of a file (by name). 
+  * Minimal implementation.
+  */
+ int stat(char *file, struct stat *st) 
+ {
+       debug_in_out("STAT\n");
+       
+       int s_len = strlen(file) + 1; // Null terminator
+       int out_msg_len = STAT_MESSAGE_FIXED_SIZE + s_len;
+       // Allocate a new buffer of proper size
+       char *out_msg = malloc(out_msg_len);
+       char *out_msg_pos = out_msg;
+       if (out_msg == NULL)
+               return -1;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = STAT_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int*)out_msg_pos) = s_len;
+       out_msg_pos += sizeof(int);
+       memcpy(out_msg_pos, file, s_len);
+       // Send message
+       char *result = send_message(out_msg, out_msg_len);
+       free(out_msg);
+       // Read result
+       int return_val;
+       if (result != NULL) {
+               return_val = *((int *)result);
+               if (return_val == -1)
+                       errno = *(((char *)result) + sizeof(int) 
+                                                    + sizeof(struct stat));
+               else
+                       memcpy(st, ((int *)result) + 1, sizeof(struct stat));
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = -1;
+       }
+       return return_val;
+ }
+ /* times()
+  * Timing information for current process. 
+  * Minimal implementation.
+  */
+ int times(struct tms *buf) 
+ {
+       debug_in_out("TIMES");
+       return -1;
+ }
+ /* unlink()
+  * Remove a file's directory entry. 
+  * Minimal implementation.
+  */
+ int unlink(char *name) 
+ {
+       debug_in_out("UNLINK\n");
+       
+       int s_len = strlen(name) + 1; // Null terminator
+       int out_msg_len = UNLINK_MESSAGE_FIXED_SIZE + s_len;
+       // Allocate a new buffer of proper size
+       char *out_msg = malloc(out_msg_len);
+       char *out_msg_pos = out_msg;
+       if (out_msg == NULL)
+               return -1;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = UNLINK_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int*)out_msg_pos) = s_len;
+       out_msg_pos += sizeof(int);
+       memcpy(out_msg_pos, name, s_len);
+       // Send message
+       char *result = send_message(out_msg, out_msg_len);
+       free(out_msg);
+       // Read result
+       int return_val;
+       if (result != NULL) {
+               return_val = *((int *)result);
+               if (return_val == -1) errno = *(((int *)result) + 1);
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = -1;
+       }
+       return return_val;
+ }
+ /* wait()
+  * Wait for a child process. 
+  * Minimal implementation.
+  */
+ int wait(int *status) 
+ {
+       debug_in_out("WAIT\n");
+       errno = ECHILD;
+       return -1;
+ }
+ /* write()
+  * Write to a file. 
+  */
+ ssize_t write(int file, void *ptr, size_t len) {
+       
+       debug_in_out("WRITE\n");        
+       debug_in_out("\tFILE: %u\n", file);
+       debug_write_check("Writing len: %d\n", len);
+       if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
+                                    || (file == STDOUT_FILENO))
+               return sys_cputs(ptr, len);
+       
+       int out_msg_len = WRITE_MESSAGE_FIXED_SIZE + len;
+       // Allocate a new buffer of proper size
+       char *out_msg = malloc(out_msg_len);
+       char *out_msg_pos = out_msg;
+       // Fill the buffer
+       *((syscall_id_t *)out_msg_pos) = WRITE_ID;
+       out_msg_pos += sizeof(syscall_id_t);
+       *((int*)out_msg_pos) = file;
+       out_msg_pos += sizeof(int);
+       *((int*)out_msg_pos) = len;
+       out_msg_pos += sizeof(int);
+       memcpy(out_msg_pos, ptr, len);
+       // Send message
+       char *result = send_message(out_msg, out_msg_len);
+       free(out_msg);
+       // Read result
+       int return_val;
+       if (result != NULL) {
+               return_val = *((int *)result);
+               if (return_val == -1) errno = *(((int *)result) + 1);
+               free(result);
+       } else {
+               errno = ECHANNEL;
+               return_val = -1;
+       }
+       return return_val;
+ }
+ /* write_to_channel()
+  * Send a message out over the channel, defined by msg, of length len
+  */
+ int write_to_channel(char * msg, int len)
+ {
++      //return sys_serial_write((char*)msg, len);
++      return sys_eth_write((char*)msg, len);
++      
+ }
Simple merge