Merge branch 'net-dev'. See body of commit for details.
authorPaul Pearce <pearce@eecs.berkeley.edu>
Thu, 17 Sep 2009 00:42:04 +0000 (17:42 -0700)
committerPaul Pearce <pearce@eecs.berkeley.edu>
Thu, 17 Sep 2009 00:42:04 +0000 (17:42 -0700)
This is a merge of the mptable, ioapic, pci, ethernet, and ethernet based remote syscall code.

By default on x86, the mptable, ioapic, and pci code is enabled. Network code is not.

In order to enable the ethernet driver, you must define __NETWORK__
in your make local, and set USER_MAC_ADDRESS to the correct value
in order to communicate with your front end machine. The front end
server app now lives in tools/. Setting __NETWORK__ will cause the
driver to initialize on real hardware, or perform a series of interrupt
tests for simulation. This will also cause parlab_matrix to be the userspace
application booted, instead of the standard apps in manager.c. Network
support is x86 dependent.

Other things handled in this commit include:

Updated doxygen support. Doxygen will now strip out ivy annotations, and
be optimized for C code.

Rewritten newlib_backend. The code is now several orders of magnitude better
(no seriously, look at it).

Conflicts:
kern/arch/i386/Makefrag
kern/include/kfs.h
kern/include/ros/syscall.h
kern/src/Makefrag
kern/src/init.c
kern/src/kfs.c
kern/src/kmalloc.c
kern/src/manager.c
kern/src/syscall.c
kern/src/testing.c
user/roslib/inc/sys

40 files changed:
.gitignore
GNUmakefile
doc/include/annots.h [new file with mode: 0644]
doc/rosdoc.cfg
kern/arch/i386/Makefrag
kern/arch/i386/apic.c
kern/arch/i386/apic.h
kern/arch/i386/ioapic.c [new file with mode: 0644]
kern/arch/i386/ioapic.h [new file with mode: 0644]
kern/arch/i386/mptables.c [new file with mode: 0644]
kern/arch/i386/mptables.h [new file with mode: 0644]
kern/arch/i386/ne2k.c [new file with mode: 0644]
kern/arch/i386/ne2k.h [new file with mode: 0644]
kern/arch/i386/pci.c [new file with mode: 0644]
kern/arch/i386/pci.h [new file with mode: 0644]
kern/arch/i386/rl8168.c [new file with mode: 0644]
kern/arch/i386/rl8168.h [new file with mode: 0644]
kern/arch/i386/smp_boot.c
kern/arch/i386/trap.c
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/syscall.c
kern/src/testing.c
tools/syscall_server.c [new file with mode: 0644]
tools/syscall_server.h [new file with mode: 0644]
user/apps/parlib/Makefrag
user/apps/parlib/draw_nanwan_standalone.c [new file with mode: 0644]
user/apps/parlib/file_io.c
user/apps/parlib/matrix.c
user/apps/parlib/run_binary.c [new file with mode: 0644]
user/parlib/inc/newlib_backend.h
user/parlib/inc/parlib.h
user/parlib/src/i386/newlib_backend.c
user/parlib/src/syscall.c

index a745c80..2861b4c 100644 (file)
@@ -10,9 +10,12 @@ run_bochs.sh
 update*
 cscope.out
 hdd.img
+hdd.vdi
 *.*~
 ivy_errordb.sql
 Makelocal
+.textmate*
+.DS_*
 ros-project.tmproj
 kern/boot
 kern/include/arch
index 2ace0e3..2976206 100644 (file)
@@ -125,7 +125,7 @@ $(OBJDIR)/.deps: $(foreach dir, $(OBJDIRS), $(wildcard $(OBJDIR)/$(dir)/*.d))
 -include $(OBJDIR)/.deps
 
 # Use doxygen to make documentation for ROS
-docs: all
+docs: 
        @doxygen doc/rosdoc.cfg
        @if [ ! -d doc/rosdoc/html/img ];          \
         then                                      \
diff --git a/doc/include/annots.h b/doc/include/annots.h
new file mode 100644 (file)
index 0000000..7c49bae
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef ANNOT_H
+#define ANNOT_H
+
+#define BOUND(lo, hi)   
+#define COUNT(n)        
+#define SIZE(n)         
+#define SAFE            
+#define SNT             
+#define DANGEROUS       
+
+/* Begin Experimental attributes */
+#define META(p)            
+#define HANDLER_ATOMIC              
+#define LOCK_HANDLER_ATOMIC(...)   
+#define IN_HANDLER_ATOMIC  
+#define IN_HANDLER         
+#define ASYNC              
+#define NORACE             
+#define SYNCHRONOUS        
+#define REGION(r)          
+#define NOREGION           
+#define SOMEREGION         
+#define SAMEREGION         
+#define DELETES_REGION(r)  
+#define GROUP(g)           
+#define NOGROUP            
+#define SOMEGROUP          
+#define SAMEGROUP          
+#define UNIQUE             
+#define NOALIAS            
+#define PAIRED_WITH(c)     
+#define PAIRED(c1,c2)      
+#define ARGPAIRED(c1,c2,arg) 
+#define FNPTRCALLER(fn)    
+#define INITSTRUCT(s)      
+#define NOINIT             
+#define WRITES(...)        
+#define RPROTECT           
+#define WPROTECT           
+#define RWPROTECT          
+#define R_PERMITTED(...) 
+#define W_PERMITTED(...) 
+#define RW_PERMITTED(...) 
+/* End Experimental attributes */
+
+#define BND(lo, hi)     
+#define CT(n)           
+#define SZ(n)           
+
+#define EFAT            
+#define FAT             
+
+#define NULLTERM        
+#define NT              
+#define NTS             
+#define NTC(n)          
+
+#define NTDROPATTR      
+#define NTEXPANDATTR    
+
+#define NULLABLE
+#define OPT             
+#define NONNULL         
+
+#define TRUSTED         
+#define TRUSTEDBLOCK    
+
+#define POLY           
+
+#define COPYTYPE        
+
+//specifies that Deputy's typechecker (but not optimizer) should assume
+//that this lvalue is constant. (unsound)
+#define ASSUMECONST     
+
+#define WHEN(e)         
+
+#define DMEMCPY(x, y, z) 
+#define DMEMSET(x, y, z) 
+#define DMEMCMP(x, y, z)
+
+#define DALLOC(x)       
+#define DREALLOC(x, y)  
+#define DFREE(x)        
+
+#define DVARARG(x)      
+#define DPRINTF(x)      
+
+#define NTDROP(x)       (x)
+#define NTEXPAND(x)     (x)
+#define TC(x)           (x)
+
+#define TVATTR(x)       
+#define TPATTR(x)       
+
+#define TV(x)           void * (x)
+#define TP(x)           
+
+#endif // ANNOT_H
index 02ace14..ef297b2 100644 (file)
@@ -186,7 +186,7 @@ ALIASES                =
 # For instance, some of the names that are used will be different. The list 
 # of all members will be omitted, etc.
 
-OPTIMIZE_OUTPUT_FOR_C  = NO
+OPTIMIZE_OUTPUT_FOR_C  = YES
 
 # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
 # sources only. Doxygen will then generate output that is more tailored for 
@@ -332,7 +332,7 @@ HIDE_UNDOC_MEMBERS     = NO
 # If set to NO (the default) these classes will be included in the various 
 # overviews. This option has no effect if EXTRACT_ALL is enabled.
 
-HIDE_UNDOC_CLASSES     = NO
+HIDE_UNDOC_CLASSES     = YES
 
 # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
 # friend (class|struct|union) declarations. 
@@ -1169,13 +1169,13 @@ ENABLE_PREPROCESSING   = YES
 # compilation will be performed. Macro expansion can be done in a controlled 
 # way by setting EXPAND_ONLY_PREDEF to YES.
 
-MACRO_EXPANSION        = NO
+MACRO_EXPANSION        = YES
 
 # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
 # then the macro expansion is limited to the macros specified with the 
 # PREDEFINED and EXPAND_AS_DEFINED tags.
 
-EXPAND_ONLY_PREDEF     = NO
+EXPAND_ONLY_PREDEF     = YES
 
 # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
 # in the INCLUDE_PATH (see below) will be search if a #include is found.
@@ -1186,7 +1186,7 @@ SEARCH_INCLUDES        = YES
 # contain include files that are not input files but should be processed by 
 # the preprocessor.
 
-INCLUDE_PATH           = 
+INCLUDE_PATH           = doc/include/
 
 # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
 # patterns (like *.h and *.hpp) to filter out the header-files in the 
@@ -1203,14 +1203,14 @@ INCLUDE_FILE_PATTERNS  =
 # undefined via #undef or recursively expanded use the := operator 
 # instead of the = operator.
 
-PREDEFINED             = 
+PREDEFINED             =
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
 # this tag can be used to specify a list of macro names that should be expanded. 
 # The macro definition that is found in the sources will be used. 
 # Use the PREDEFINED tag if you want to use a different macro definition.
 
-EXPAND_AS_DEFINED      = 
+EXPAND_AS_DEFINED      = BOUND COUNT SIZE SAFE SNT DANGEROUS META HANDLER_ATOMIC LOCK_HANDLER_ATOMIC IN_HANDLER_ATOMIC IN_HANDLER ASYNC NORACE SYNCHRONOUS REGION NOREGION SOMEREGION SAMEREGION DELETES_REGION GROUP NOGROUP SOMEGROUP SAMEGROUP UNIQUE NOALIAS PAIRED_WITH PAIRED ARGPAIRED FNPTRCALLER INITSTRUCT NOINIT WRITES RPROTECT WPROTECT RWPROTECT R_PERMITTED W_PERMITTED RW_PERMITTED BND CT SZ EFAT FAT NULLTERM NT NTS NTC NTDROPATTR NTEXPANDATTR NULLABLE OPT NONNULL TRUSTED TRUSTEDBLOCK POLY COPYTYPE ASSUMECONST WHEN DMEMCPY DMEMSET DMEMCMP DALLOC DREALLOC DFREE DVARARG DPRINTF NTDROP NTEXPAND TC TVATTR TPATTR TV TP
 
 # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
 # doxygen's preprocessor will remove all function-like macros that are alone 
index d3c918a..ba6fc6f 100644 (file)
@@ -26,4 +26,9 @@ KERN_ARCH_SRCFILES := $(KERN_ARCH_SRC_DIR)/entry.S \
                       $(KERN_ARCH_SRC_DIR)/apic.c \
                       $(KERN_ARCH_SRC_DIR)/kdebug.c \
                       $(KERN_ARCH_SRC_DIR)/process.c \
+                      $(KERN_ARCH_SRC_DIR)/mptables.c \
+                      $(KERN_ARCH_SRC_DIR)/pci.c \
+                      $(KERN_ARCH_SRC_DIR)/ioapic.c \
+                      $(KERN_ARCH_SRC_DIR)/rl8168.c \
+                      $(KERN_ARCH_SRC_DIR)/ne2k.c \
                       $(KERN_ARCH_SRC_DIR)/env.c
index 3e73726..35620ed 100644 (file)
@@ -62,7 +62,6 @@ void pic_unmask_irq(uint8_t irq)
                outb(PIC1_DATA, inb(PIC1_DATA) & ~(1 << irq));
 }
 
-
 /*
  * Sets the LAPIC timer to go off after a certain number of ticks.  The primary
  * clock freq is actually the bus clock, which we figure out during timer_init
index 8a03c7c..615950f 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <arch/mmu.h>
 #include <arch/x86.h>
+#include <arch/ioapic.h>
 
 // PIC
 #define PIC1_CMD                                       0x20
@@ -51,9 +52,6 @@
 #define LAPIC_IPI_ICR_LOWER                    (LAPIC_BASE + 0x300)
 #define LAPIC_IPI_ICR_UPPER                    (LAPIC_BASE + 0x310)
 
-// IOAPIC
-#define IOAPIC_BASE                                    0xfec00000 // this is the default, can be changed
-
 // PIT (Programmable Interval Timer)
 #define        TIMER_REG_CNTR0 0       /* timer 0 counter port */
 #define        TIMER_REG_CNTR1 1       /* timer 1 counter port */
diff --git a/kern/arch/i386/ioapic.c b/kern/arch/i386/ioapic.c
new file mode 100644 (file)
index 0000000..483f32b
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2009 The Regents of the University of California
+ * See LICENSE for details.
+ */
+
+#ifdef __SHARC__
+#pragma nosharc
+#endif
+// Not currently sharc complient.
+
+/** @file
+ * @brief Basic IOAPIC Driver.
+ *
+ * This file is responsible for the initalization of the Intel x58 IOAPIC(s)
+ * Once the IOAPIC is setup, the function ioapic_route_irq() can be used
+ * to route
+ *
+ * See Ch 17.5.26 in Intel X58 Express Chipset Datasheet
+ *
+ * @author Paul Pearce <pearce@eecs.berkeley.edu>
+ *
+ * @todo Come up with an impliment a concurrency model for use of the route/unroute functions
+ * @todo Once we begin using logical core ID's for groups, adjust route/unroute to utilize this (adjust high word)
+ * @todo Some notion of a 'initalized' flag we can check to ensure bootup call order.
+ */
+
+#include <arch/mmu.h>
+#include <arch/x86.h>
+#include <arch/apic.h>
+#include <arch/mptables.h>
+#include <arch/pci.h>
+
+ioapic_redirect_t ioapic_redirects[NUM_IRQS];
+
+/**
+ * @brief Parse the entries from the mptables relevant to the IOAPIC and initalize the IOAPIC and its data structures
+ *
+ * This function will loop over the data structures created by MPTables to represent ISA and PCI interrupts
+ * and then setup the ioapic_redirects array to map IRQs->IOAPIC/Flags
+ * 
+ * This function must be called during bootup, before interrupts are rerouted, and after the PCI/MPTable initilization.
+ */
+void ioapic_init() {
+       
+       // Set all entires invalid.
+       // We define a entry to be invalid by having an ioapic_address of NULL (0x0)
+       memset(ioapic_redirects, 0x0, sizeof(ioapic_redirects));
+       
+       extern uint8_t num_cpus;
+       uint32_t num_inconsistent_pci_mappings = 0;     // Increment if we find inconsistent mappings between
+                                                                                               //  mptables and the pci bus.
+       
+       // Pull in all the stuff we need from mptables and the pci parsing. These are all stack allocated (cant be null)
+       extern pci_irq_entry_t irq_pci_map[NUM_IRQS];
+       extern pci_int_device_t pci_int_devices[PCI_MAX_BUS][PCI_MAX_DEV];
+       extern ioapic_entry_t ioapic_entries[IOAPIC_MAX_ID];
+       extern isa_int_entry_t isa_int_entries[NUM_IRQS];
+       
+       // Setup the PCI entries
+       for (int i = 0; i < NUM_IRQS; i++) {
+               // Bus is 16 bits as we use a sential BUS value (INVALID_BUS) to denote an invalid bus
+               //  and this valid is out of the range 0->2^8-1
+               uint16_t bus = irq_pci_map[i].bus;
+               uint8_t dev = irq_pci_map[i].dev;
+               uint8_t line = irq_pci_map[i].line;
+               
+               if (bus == INVALID_BUS)
+                       continue;
+
+               // We do the same trick with the dest apic ID as we do with the PCI Bus, so its wider.
+               uint16_t dst_apic_id = pci_int_devices[bus][dev].line[line].dst_apic_id;
+               uint8_t dst_apic_int = pci_int_devices[bus][dev].line[line].dst_apic_int;
+               
+               // Check if this entry has been set
+               if (dst_apic_id == INVALID_DEST_APIC) {
+                       // If we have a valid bus in the irq->pci map, and the pic->int entry doesnt exist, we have a (probably VM) problem
+                       if (num_inconsistent_pci_mappings == 0)
+                               printk("WARNING: INCONSISTENT IRQ->PCI AND PCI->IOAPIC MAPPINGS. Trying to cope...\n");
+                       num_inconsistent_pci_mappings++;
+                       continue;
+               }
+               
+               // If the lowest bit of the apic flags is set to 0, it means the ioapic is not usable (by MP Spec)
+               // We also use this to denote non-existent ioapics in our map
+               if ((ioapic_entries[dst_apic_id].apic_flags & 0x1) == 0) 
+                       panic("IRQ SAYS ITS GOING TO AN IOAPIC LISTED AS INVALID, THATS BAD.");
+                                       
+               ioapic_redirects[i].ioapic_address = ioapic_entries[dst_apic_id].apic_address;
+               ioapic_redirects[i].ioapic_int = dst_apic_int;
+               ioapic_redirects[i].ioapic_flags = IOAPIC_PCI_FLAGS;
+       }
+       
+       // Setup the ISA entries
+       for (int i = 0; i < NUM_IRQS; i++) {
+               
+               uint16_t dst_apic_id = isa_int_entries[i].dst_apic_id;
+               uint8_t dst_apic_int = isa_int_entries[i].dst_apic_int;
+               
+               
+               // Skip invalid entries
+               if (dst_apic_id == INVALID_DEST_APIC)
+                       continue;
+                       
+               if (ioapic_redirects[i].ioapic_address != NULL) {
+                       // This is technically a lie. We could in theory handle this, so long as
+                       //  everything agrees.... however this shouldnt ever really happen
+                       //  as this means we have both PCI and ISA claiming an interrupt
+                       panic("BOTH PCI AND ISA CLAIM TO SHARE AN IRQ. BAD");
+               }
+               
+               // Code to check if this isa irq entry claims to be pci
+               uint16_t pci_bus = irq_pci_map[i].bus;
+               if (pci_bus != INVALID_BUS) {
+                       // PCI bus had an entry for this irq, but we didn't set it during our pci run
+                       //  This means it is likely a broken mptable implimentation. this happens on bochs and kvm
+                       //  lets just set the flags as if its broken, and move on. Hopefully it will work out.
+                       ioapic_redirects[i].ioapic_flags = IOAPIC_BROKEN_PCI_FLAGS;
+                       num_inconsistent_pci_mappings--;
+               }
+               else {
+                       ioapic_redirects[i].ioapic_flags = IOAPIC_ISA_FLAGS;
+               }
+               
+
+               ioapic_redirects[i].ioapic_address = ioapic_entries[dst_apic_id].apic_address;
+               ioapic_redirects[i].ioapic_int = dst_apic_int;
+       }
+       
+       // Things didn't balance out when we scanned the isa bus for the missing pci devices. Die.
+       if (num_inconsistent_pci_mappings != 0) 
+               panic("FAILED TO COPE WITH INCONSISTENT IRQ->PCI AND PCI->IOAPIC MAPPINGS!");
+       
+       // Support for other type of IRQ's goes here.
+       
+       /* Note: We do not technically ever do anything to initalize the IOAPIC
+       *   According to the x58 chipset spec, this is done for us. It starts up
+       *   usable and with everything masked, so there isn't really anything to do
+       *   besides setup our structures.
+       */
+}
+
+
+/** @brief Reconfigure the correct IOAPIC to route a given irq to a given dest
+  * 
+  * This function will take an irq given by 'irq' and using the interal IOAPIC
+  * strucures will adjust the IOAPIC to properly route that IRQ to a core 
+  * (or in the future group of cores) specified by the 'dest' bits.
+  *
+  * This function must be called after ioapic_init() is called.
+  *
+  * There is no notion of success besides invalid data, which casues a panic.
+  *
+  * @todo Logical partition support
+  * @todo Decide on a synchronization mechinism
+  *
+  * @param[in] irq     The IRQ we are trying to route. This is non-kernal-offseted. EX: Pit is IRQ 0, not 32.
+  * @param[in] dest    The core id we want to route irq to
+  */
+
+void ioapic_route_irq(uint8_t irq, uint8_t dest) {
+       
+       if (((irq + KERNEL_IRQ_OFFSET) >= NUM_IRQS) || (ioapic_redirects[irq].ioapic_address == NULL)) {
+               panic("TRYING TO REROUTE AN INVALID IRQ!");
+       }
+
+       // THIS IS A TEMP CHECK. IF WE USE LOGICAL PARTITIONS THIS MUST BE REMOVED
+        extern uint8_t num_cpus;
+       if (dest >= num_cpus)
+               panic("TRYING TO REROUTE TO AN INVALID DESTINATION!");
+       
+       if (irq == 0 && dest != 0)
+               cprintf("WARNING: Rerouting IRQ to core != 0 may cause undefined behavior!\n");
+
+       // Bit pack our redirection entry. This is black magic based on the spec. See the x58 spec.
+       uint32_t redirect_low = KERNEL_IRQ_OFFSET + irq;
+       redirect_low = redirect_low | (ioapic_redirects[irq].ioapic_flags << 8);
+       uint32_t redirect_high = dest << 24;
+       
+       // YOU MUST MUST MUST MUST MUST MUST MUST write the high bits first. If you don't, you get interrupts going to crazy places
+       // Ask Paul about that afternoon of his life.
+       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int + 1);
+       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, redirect_high);
+       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int);
+       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, redirect_low);
+}
+
+/** @brief Reconfigure the correct IOAPIC to no longer route a given irq to any core
+  * 
+  * This function will take an irq given by 'irq' and using the interal IOAPIC
+  * strucures will adjust the IOAPIC to no longer route that irq to any destination
+  *
+  * This function must be called after ioapic_init() is called, but need not be called after a matching ioapic_route_irq()
+  *
+  * There is no notion of success besides invalid data, which casues a panic.
+  *
+  * @todo Decide on a synchronization mechinism
+  * 
+  * @param[in] irq     The IRQ we are trying to unroute. This is non-kernal-offseted. EX: Pit is IRQ 0, not 32.
+  */
+void ioapic_unroute_irq(uint8_t irq) {
+
+       if (((irq + KERNEL_IRQ_OFFSET) >= NUM_IRQS) || (ioapic_redirects[irq].ioapic_address == NULL)) {
+               panic("TRYING TO REROUTE AN INVALID IRQ!");
+       }
+       
+       // Must write low first, else we will reroute to a wrong core for a split before turning off
+       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int);
+       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, IOAPIC_UNROUTE_LOW);
+       
+       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int + 1);
+       write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address  + IOAPIC_WRITE_WINDOW_OFFSET, IOAPIC_UNROUTE_HIGH);
+
+}
diff --git a/kern/arch/i386/ioapic.h b/kern/arch/i386/ioapic.h
new file mode 100644 (file)
index 0000000..157407f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009 The Regents of the University of California
+ * See LICENSE for details.
+ */
+
+#ifndef ROS_KERN_IOAPIC_H
+#define ROS_KERN_IOAPIC_H
+
+#include <ros/common.h>
+
+/* IOAPIC_BASE really go away. This is NOT required by the spec as far as I know.
+ * This was originally in apic.h, but Paul moved it here. This is NOT used by
+ * anything in the IOAPIC, just some other kernel stuff which uses it for
+ * size calculations. It should be called something else and moved.
+ */
+#define IOAPIC_BASE                                    0xfec00000 // this is the default, can be changed
+
+/* These are things like level sensitive, edge triggered, fixed, nmi, extint, etc
+ * This is based on the x58 chipset spec. There are only 2 combinations so
+ * Paul didn't bother to spell them out bit by bit and or them together.
+ */
+#define IOAPIC_PCI_FLAGS                       0xa0
+#define IOAPIC_ISA_FLAGS                       0x00
+/* This says how we should treat PCI interrupts that are listed as ISA by mptables.
+ * This was determined by trial and error in the VM's. All current VMs that have this
+ * 'feature' use ISA style flags. 
+ * Author's note: Paul really hates whoever wrote the bochs bios (which is
+ * the source of this problem for bochs/kvm/qemu).
+ */
+#define IOAPIC_BROKEN_PCI_FLAGS                IOAPIC_ISA_FLAGS 
+
+// Obvious
+#define IOAPIC_MAX_ID                          256
+
+// The magic bits we write to kill unroute an irq. The 16th bit is the important one, being set to 1. 
+// Other bits are just to restore it to a clean boot-like state.
+#define IOAPIC_UNROUTE_LOW                     0x00010000
+#define IOAPIC_UNROUTE_HIGH                    0x00000000
+
+// Mem mapped register magic numbers. Oo magic!
+#define IOAPIC_REDIRECT_OFFSET         0x10
+#define IOAPIC_WRITE_WINDOW_OFFSET     0x10
+
+/* Structure used to define an interrupt redirection entry. 
+ * This structure encapsulates:
+ *             An IRQ
+ *             The flags used for rerouting (edge sensitive, level triggered, etc)
+ *             Ioapic ADDR (physical Addr)
+ */
+typedef struct IOAPICREDIRECT {
+    void*                      ioapic_address; // NULL means invalid
+       uint8_t                 ioapic_flags;
+       uint8_t                 ioapic_int;
+} ioapic_redirect_t;
+
+// Everyone loves a protoype.
+void ioapic_init();
+void ioapic_route_irq(uint8_t irq, uint8_t dest);
+void ioapic_unroute_irq(uint8_t irq);
+
+#endif /* ROS_KERN_IOAPIC_H */
diff --git a/kern/arch/i386/mptables.c b/kern/arch/i386/mptables.c
new file mode 100644 (file)
index 0000000..4cc6a62
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2009 The Regents of the University of California
+ * See LICENSE for details.
+ */
+
+#ifdef __SHARC__
+#pragma nosharc
+#endif
+// Not currently sharc complient. However
+// we should never be modifying these structures post smp_boot().
+
+#include <arch/ioapic.h>
+#include <arch/pci.h>
+#include <arch/mptables.h>
+
+#include <ros/common.h>
+#include <stdio.h>
+#include <string.h>
+#include <kmalloc.h>
+#include <arch/x86.h>
+
+/** @file
+ * @brief Basic MP Tables Parser
+ *
+ * This file is responsible for locating, checksuming, and parsing the 
+ * MultiProcessor Specification Tables.
+ *
+ * See Intel Multiprocessor Specification for more info
+ *
+ * @author Paul Pearce <pearce@eecs.berkeley.edu>
+ *
+ * @todo Extended table support (why?)
+ * @todo Expanded error checking?
+ * @todo virtaddr_t to match physaddr_t support?
+ */
+
+// Important global items
+enum interrupt_modes current_interrupt_mode;
+
+proc_entry_t   *COUNT(mp_entries_count[PROC])   mp_proc_entries = NULL;
+bus_entry_t            *COUNT(mp_entries_count[BUS])    mp_bus_entries = NULL;
+ioapic_entry_t *COUNT(mp_entries_count[IOAPIC]) mp_ioapic_entries = NULL;
+int_entry_t            *COUNT(mp_entries_count[INT])    mp_int_entries = NULL;
+int_entry_t            *COUNT(mp_entries_count[LINT])   mp_lint_entries = NULL; 
+// ^ Not a typo. lint entries == int entries, so We just use that.
+
+
+int mp_entries_count[NUM_ENTRY_TYPES]; // How large each array is.
+
+pci_int_device_t pci_int_devices[PCI_MAX_BUS][PCI_MAX_DEV];
+isa_int_entry_t isa_int_entries[NUM_IRQS];
+ioapic_entry_t ioapic_entries[IOAPIC_MAX_ID];
+
+
+/** @brief Entry function to the mptable parser. Calling this function results in the parsing of the tables and setup of all structures
+ *
+ * This function does the following:
+ *     - Search various locations in memory for the MP Floating Structure 
+ *  - Checkum the floating structure to make sure its valid
+ *  - Locate the MP Configuration Header, and checksum it
+ *  - Locate all entries of type proc, bus, ioapic, int, lint
+ *  - Parse the above entries and form the data structures that the rest of the system relies upon
+ */
+void mptables_parse() {
+       
+       // Before we do anything. We didn't pack our structs because BSD didnt. Make sure we're sane.
+       if (    (sizeof(proc_entry_t)   != entry_types[PROC].length) || 
+                       (sizeof(bus_entry_t)    != entry_types[BUS].length) || 
+                       (sizeof(ioapic_entry_t) != entry_types[IOAPIC].length) || 
+                       (sizeof(int_entry_t)    != entry_types[INT].length) || 
+                       (sizeof(mpfps_t)                != MPFPS_SIZE) ||
+                       (sizeof(mpcth_t)                != MPCTH_SIZE) )
+                               panic("MPTable structure sizes out of sync with spec");
+                       
+                       
+       mpfps_t *mpfps;
+       
+       // Memsets to initalize all our structures to invalid entries
+       
+       /* Setup the indexable ioapic array.
+        * YOU MUST check the flag field to see if its 0. If 0, unusable.
+        * This is defined by MPTables, and I leaverage this with the memset below to set invalid
+        */
+       memset(ioapic_entries, 0, sizeof(ioapic_entries));
+       
+       // We define an IOAPIC DEST ID of 0xFF (>=256) to be invalid. Pack with all 1's.
+       memset(pci_int_devices, 0xFF, sizeof(pci_int_devices));
+       memset(isa_int_entries, 0xFF, sizeof(isa_int_entries));
+       
+       
+       mptables_info("Starting MPTables Parsing...\n");
+       
+       /*  Basic procedure:
+        *      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.
+        *
+        *
+        * 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, haven't found something that uses this.
+                *
+                * First, we have to find the EBDA Addr.
+                * This USSUALLY works (based on third hand info). May be some cases where it doesnt.
+                * See osdev x86 mem-map for more information
+                */
+               physaddr_t ebda_base = READ_FROM_STORED_PHYSADDR32(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_FROM_STORED_PHYSADDR32(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.
+                * This IS tested. Thanks VirtualBox!
+                */
+                               
+               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");
+               // TODO: Do SOMETHING here. We've never found such a system (they are generally ancient). Should we just panic?
+       }
+       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();
+       
+}
+
+
+/** @brief Take the given memory range and search for the MP Floating Structure
+ * 
+ * This function will look at every sizeof(mpfps_t) chunch of memory for a given 4byte value (_MP_)
+ * until bound is reached (inclusive).
+ *
+ * Note: Doesn't ensure bounds are sane. This shouldnt be an issue as this function should be priviate to mptables_parse()
+ *
+ * @param[in] base     The base (kernel virtual) address we start looking at
+ * @param[in] bound The bound (inclusive kernel virtual) address we stop looking at
+ * 
+ * @return MPFPS The virtual address of the base of the floating point structure
+ * @return NULL No floating point structure exists in this range
+ */
+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_FROM_STORED_VIRTADDR32(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;
+}
+
+/** @brief Perform the mptable checksum on the memory given by addr and len
+ *
+ * This function will take len bytes of memory starting at the (kernel virtual)
+ * address addr and sum them together. If the result is 0, the checksum is valid. 
+ *
+ * @param[in] addr     The base (kernel virtual) address we start checking 
+ * @param[in] len      How many bytes to look at
+ * 
+ * @return TRUE Valid checksum
+ * @return FALSE Invalid checksum
+ */
+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);
+}
+
+/** @brief Parse the configuration MP Table given a valid address to the base of the table
+ *
+ * This function begin examining a given (kernel virtual) address assuming it is the base 
+ * of the configuration table. It will determine the size of the table, and then loop over
+ * each entry in the table, loading all entires into the correct corresponding data structures
+ *
+ * @param[in] conf_addr                The base (kernel virtual) address of the configuration table
+ */    
+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.
+       // Note: Length here means length in bytes. This is from the mp spec.
+       uint16_t num_entries = mpcth->entry_count;
+       uint16_t mpct_length = mpcth->base_table_length;
+       uint16_t entries_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(entries_length) entry_base = (uint8_t* COUNT(entries_length)) TC(mpcth + 1);
+       uint8_t * BND(entry_base, entry_base + entries_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 += entry_types[current_type].length;
+       }
+       
+       // Allocate the correct space in the arrays (unrolled for ivy reasons)
+       if (mp_entries_count[PROC] != 0) {
+               mp_proc_entries = kmalloc(mp_entries_count[PROC] * entry_types[PROC].length , 0);
+               if (mp_proc_entries == NULL)
+                       panic("Failed to allocate space for mp_proc_entires");
+       }
+
+       if (mp_entries_count[BUS] != 0) {
+               mp_bus_entries = kmalloc(mp_entries_count[BUS] * entry_types[BUS].length , 0);
+               if (mp_bus_entries == NULL)
+                       panic("Failed to allocate space for mp_bus_entires");
+       }
+
+       if (mp_entries_count[IOAPIC] != 0) {
+               mp_ioapic_entries = kmalloc(mp_entries_count[IOAPIC] * entry_types[IOAPIC].length , 0);
+               if (mp_ioapic_entries == NULL)
+                       panic("Failed to allocate space for mp_ioapic_entires");
+       }
+       
+       if (mp_entries_count[INT] != 0) {
+               mp_int_entries = kmalloc(mp_entries_count[INT] * entry_types[INT].length , 0);
+               if (mp_int_entries == NULL)
+                       panic("Failed to allocate space for mp_int_entires");
+       }
+
+       if (mp_entries_count[LINT] != 0) {
+               mp_lint_entries = kmalloc(mp_entries_count[LINT] * entry_types[LINT].length , 0);
+               if (mp_lint_entries == NULL)
+                       panic("Failed to allocate space for mp_lint_entires");
+       }
+       
+       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,  
+                                               entry_types[PROC].length);
+                               break;
+                       
+                       case BUS:
+                               memcpy( &mp_bus_entries[num_processed[BUS]], 
+                                               current_addr,  
+                                               entry_types[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_t* COUNT(1)) TC(current_addr),  
+                                               entry_types[IOAPIC].length);
+                               break;
+                       case INT:
+                               memcpy( &mp_int_entries[num_processed[INT]], 
+                                               current_addr,  
+                                               entry_types[INT].length);
+                               break;
+                       case LINT:
+                               memcpy( &mp_lint_entries[num_processed[LINT]], 
+                                               (void*)current_addr,  
+                                               entry_types[LINT].length);
+                               break;
+                                               
+                       default: panic("UNKNOWN ENTRY TYPE");
+               }
+
+               num_processed[current_type]++;
+               current_addr += entry_types[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.
+}
+
+/** @brief Parse all processor mptable entires
+ *
+ * This function will loop over the raw proc entry structure and parse it into a usable form.
+ * This currently just prints stuff if dumping is enabled.
+ */
+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("-->apic ID: %x\n", mp_proc_entires[i].apic_id);
+               mptables_dump("-->apic Version: %x\n", mp_proc_entires[i].apic_version);
+               mptables_dump("-->cpu Flags: %x\n", mp_proc_entires[i].cpu_flags);
+               mptables_dump("-->cpu Signaure: %x\n", mp_proc_entires[i].cpu_signature);
+               mptables_dump("-->feature Flags: %x\n", mp_proc_entires[i].feature_flags);
+       }
+       
+       mptables_dump("\n");
+}
+
+/** @brief Parse all bus mptable entires
+ *
+ * This function will loop over the raw bus entry structure and parse it into a usable form
+ * This currently just prints stuff if dumping is enabled. (With a basic sanity check).
+ */
+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].bus_id) 
+                       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("-->Bus ID: %x\n", mp_bus_entries[i].bus_id);
+               mptables_dump("-->Bus: %c%c%c\n", mp_bus_entries[i].bus_type[0], mp_bus_entries[i].bus_type[1], mp_bus_entries[i].bus_type[2]);
+       
+       }
+       
+       mptables_dump("\n");
+}
+
+/** @brief Parse all ioapic mptable entires
+ *
+ * This function will loop over the raw ioapic entry structure and parse it into a usable form.
+ * ioapic_entires[] contains all found ioapics after this function.
+ */
+void ioapic_parse() {
+
+       // Note: We don't check if the apicFlags is 0. If zero, unusable
+       // This should be done elsewhere.
+       
+       // mp_entries_count[IOAPIC] contains the number of ioapics on this system
+       
+       for (int i = 0; i < mp_entries_count[IOAPIC]; i++){
+               
+               memcpy((void*)(ioapic_entries + mp_ioapic_entries[i].apic_id), (void*)(mp_ioapic_entries + i), sizeof(ioapic_entry_t));
+               
+               mptables_dump("IOAPIC entry %u\n", i);
+               mptables_dump("-->type: %x\n", mp_ioapic_entries[i].type);
+               mptables_dump("-->apic_id: %x\n", mp_ioapic_entries[i].apic_id);
+               mptables_dump("-->apic_version: %x\n", mp_ioapic_entries[i].apic_version);
+               mptables_dump("-->apic_flags: %x\n", mp_ioapic_entries[i].apic_flags);
+               mptables_dump("-->apic_address: %p\n", mp_ioapic_entries[i].apic_address);
+               
+       }
+       mptables_dump("\n");
+}
+
+/** @brief Parse all interrupt mptable entires
+ *
+ * This function will loop over the raw interrupt entry structure and parse it into a usable form.
+ * pci_int_devices[] and isa_int_entries[] will be populated after this function is called.
+ */
+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("-->int Type: %x\n", mp_int_entries[i].int_type);
+               mptables_dump("-->int Flags: %x\n", mp_int_entries[i].int_flags);
+               mptables_dump("-->src Bus ID: %u\n", mp_int_entries[i].src_bus_id);
+               mptables_dump("-->src Device: %u (PCI ONLY)\n", (mp_int_entries[i].src_bus_irq >> 2) & 0x1F);
+               mptables_dump("-->src Bus IRQ: %x\n", mp_int_entries[i].src_bus_irq);
+               mptables_dump("-->dst Apic ID: %u\n", mp_int_entries[i].dst_apic_id);
+               mptables_dump("-->dst Apic INT: %u\n", mp_int_entries[i].dst_apic_int);
+                                       
+       }
+       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].src_bus_id].bus_type, "PCI", 3) == 0) {
+                       int bus_idx, dev_idx, line_idx;
+                       bus_idx = mp_int_entries[i].src_bus_id;
+                       dev_idx = (mp_int_entries[i].src_bus_irq >> 2) & 0x1F;
+                       line_idx = mp_int_entries[i].src_bus_irq & 0x3;
+                       pci_int_devices[bus_idx][dev_idx].line[line_idx].dst_apic_id = mp_int_entries[i].dst_apic_id;
+                       pci_int_devices[bus_idx][dev_idx].line[line_idx].dst_apic_int = mp_int_entries[i].dst_apic_int;
+               }
+               
+               if (strncmp(mp_bus_entries[mp_int_entries[i].src_bus_id].bus_type, "ISA", 3) == 0) {
+                       int irq = mp_int_entries[i].src_bus_irq;
+                       int int_type = mp_int_entries[i].int_type;
+                       
+                       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].dst_apic_id != 0xFFFF) && 
+                                ((isa_int_entries[irq].dst_apic_id != mp_int_entries[i].dst_apic_id) 
+                                  || (isa_int_entries[irq].dst_apic_int != mp_int_entries[i].dst_apic_int)))
+                               panic("SAME IRQ MAPS TO DIFFERENT IOAPIC/INTN'S. THIS DEFIES LOGIC.");
+                       
+                       isa_int_entries[irq].dst_apic_id = mp_int_entries[i].dst_apic_id;
+                       isa_int_entries[irq].dst_apic_int = mp_int_entries[i].dst_apic_int;
+               }                       
+       }
+}
+
+/** @brief Parse all local interrupt mptable entires
+ *
+ * This function will loop over the raw local interrupt entry structure and parse it into a usable form.
+ * This currently just prints stuff if dumping is enabled.
+ */
+
+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("-->int Type: %x\n", mp_lint_entries[i].int_type);
+               mptables_dump("-->src Bus ID: %x\n", mp_lint_entries[i].src_bus_id);
+               mptables_dump("-->src Bus IRQ: %x\n", mp_lint_entries[i].src_bus_irq);
+               mptables_dump("-->dst Apic ID: %p\n", mp_lint_entries[i].dst_apic_id);
+               mptables_dump("-->dst Apic INT: %p\n", mp_lint_entries[i].dst_apic_int);
+               
+       }
+}
diff --git a/kern/arch/i386/mptables.h b/kern/arch/i386/mptables.h
new file mode 100644 (file)
index 0000000..afee595
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2009 The Regents of the University of California
+ * See LICENSE for details.
+ */
+
+#ifndef ROS_INC_MPTABLES_H
+#define ROS_INC_MPTABLES_H
+
+#include <ros/common.h>
+#include <pmap.h>
+
+/* 
+ * LICENCE NOTE: Most of these structures and some constants
+ * were blatently ripped out of BSD with <3. Only the camel 
+ * casing has been changed to protect the innocent.
+ */
+
+// OBSCENELY IMPORTANT NOTE: None of this is packed. I didn't do it because BSD didnt. This may need to change
+
+#define mptables_info(...)  printk(__VA_ARGS__)  
+#define mptables_dump(...)  //printk(__VA_ARGS__)  
+
+// The HEX representation of the ascii string _MP_ we search for
+#define MP_SIG                         0x5f504d5f      /* _MP_ */
+
+// Base and (inclusive bound) of the BIOS region to check
+#define BIOS_ROM_BASE          0xf0000
+#define BIOS_ROM_BOUND                 0xffff0 
+
+// Where to look for the EBDA pointer
+// Bound is dynamic. In first KB
+#define EBDA_POINTER           0x040e 
+#define EBDA_SIZE                      1024
+
+/* BIOS: base memory size */
+#define TOPOFMEM_POINTER       0x0413          
+#define IMCRP_MASK                     0x80
+
+// Sometimes the BIOS is a lying pain in my ass
+// so don't believe it and assume this top of memory and check it
+#define DEFAULT_TOPOFMEM       0xa0000
+
+// How many entry types exist? Won't ever change
+#define NUM_ENTRY_TYPES        5
+
+#define INVALID_DEST_APIC      0xffff
+
+#define MPFPS_SIZE                     16 // For ivy
+#define MPCTH_SIZE                     44
+
+// Sorry Zach, this has to be done.
+#define READ_FROM_STORED_PHYSADDR32(addr)  READ_FROM_STORED_VIRTADDR32(KADDR(addr))
+#define READ_FROM_STORED_VIRTADDR32(addr)  *((uint32_t* SAFE)addr)
+
+
+enum interrupt_modes {
+       PIC, // PIC Mode 
+       VW,  // Virtural Wire Mode (Dev Boxes)
+       SIO  // Once we fix up the ioapic, shift to this mode (not currently used)
+};
+
+// Start BSDs lovingly barrowed structs/etc
+
+enum entry_types {
+       PROC =          0,
+       BUS  =          1,
+       IOAPIC =        2,
+       INT =           3,
+       LINT =          4
+};
+
+enum bus_types {
+    CBUS = 1,
+    CBUSII = 2,
+    EISA = 3,
+    ISA = 6,
+    PCI = 13,
+    XPRESS = 18,
+    MAX_BUSTYPE = 18,
+    UNKNOWN_BUSTYPE = 0xff
+};
+
+typedef struct BUSTYPENAME {
+    uint8_t    type;
+    char       name[ 7 ];
+} bus_type_name_t;
+
+static bus_type_name_t bus_type_table[] =
+{
+    { CBUS,            "CBUS"   },
+    { CBUSII,          "CBUSII" },
+    { EISA,            "EISA"   },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { ISA,             "ISA"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { PCI,             "PCI"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    },
+    { UNKNOWN_BUSTYPE, "---"    }
+};
+
+
+
+typedef struct TABLE_ENTRY {
+    uint8_t    type;
+    uint8_t    length;
+    char       name[ 32 ];
+} table_entry_t;
+
+static table_entry_t entry_types[] =
+{
+    { 0, 20, "Processor" },
+    { 1,  8, "Bus" },
+    { 2,  8, "I/O APIC" },
+    { 3,  8, "I/O INT" },
+    { 4,  8, "Local INT" }
+};
+
+/* MP Floating Pointer Structure */
+typedef struct MPFPS {
+    char       signature[ 4 ];
+    void*      pap;
+    uint8_t    length;
+    uint8_t    spec_rev;
+    uint8_t    checksum;
+    uint8_t    mpfb1;
+    uint8_t    mpfb2;
+    uint8_t    mpfb3;
+    uint8_t    mpfb4;
+    uint8_t    mpfb5;
+} mpfps_t;
+
+
+/* MP Configuration Table Header */
+typedef struct MPCTH {
+    char       signature[ 4 ];
+    uint16_t   base_table_length;
+    uint8_t            spec_rev;
+    uint8_t            checksum;
+    uint8_t            oem_id[ 8 ];
+    uint8_t            product_id[ 12 ];
+    void*              oem_table_pointer;
+    uint16_t   oem_table_size;
+    uint16_t   entry_count;
+    void*              apic_address;
+    uint16_t   extended_table_length;
+    uint8_t            extended_table_checksum;
+    uint8_t            reserved;
+} mpcth_t;
+
+typedef struct PROCENTRY {
+    uint8_t            type;
+    uint8_t            apic_id;
+    uint8_t            apic_version;
+    uint8_t            cpu_flags;
+    uint32_t   cpu_signature;
+    uint32_t   feature_flags;
+    uint32_t   reserved1;
+    uint32_t   reserved2;
+} proc_entry_t;
+
+typedef struct BUSENTRY {
+    uint8_t    type;
+    uint8_t    bus_id;
+    char (NT bus_type)[ 6 ];
+} bus_entry_t;
+
+typedef struct IOAPICENTRY {
+    uint8_t    type;
+    uint8_t    apic_id;
+    uint8_t    apic_version;
+    uint8_t    apic_flags;
+    void*      apic_address;
+} ioapic_entry_t;
+
+typedef struct INTENTRY {
+    uint8_t            type;
+    uint8_t            int_type;
+    uint16_t   int_flags;
+    uint8_t            src_bus_id;
+    uint8_t            src_bus_irq;
+    uint8_t            dst_apic_id;
+    uint8_t            dst_apic_int;
+} int_entry_t;
+
+typedef struct PCIINTENTRY {
+    uint16_t   dst_apic_id; // A value of INVALID_DEST_APIC means invalid (>=256)
+    uint8_t            dst_apic_int;
+} pci_int_entry_t;
+
+typedef pci_int_entry_t isa_int_entry_t;
+
+typedef struct PCIINTDEVICE {
+       pci_int_entry_t line[4];
+} pci_int_device_t;
+
+// Prototypes
+void mptables_parse();
+mpfps_t * COUNT(MPFPS_SIZE) find_floating_pointer(physaddr_t base, physaddr_t bound);
+bool checksum(physaddr_t addr, uint32_t len);
+void configuration_parse(physaddr_t conf_addr);
+
+void proc_parse();
+void bus_parse();
+void ioapic_parse();
+void int_parse();
+void lint_parse();
+
+#endif /* !ROS_INC_MPTABLES_H */
diff --git a/kern/arch/i386/ne2k.c b/kern/arch/i386/ne2k.c
new file mode 100644 (file)
index 0000000..911c30f
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2009 The Regents of the University of California
+ * See LICENSE for details.
+ */
+
+#ifdef __DEPUTY__
+#pragma nodeputy
+#endif
+
+#ifdef __SHARC__
+#pragma nosharc
+#endif
+
+#include <arch/mmu.h>
+#include <arch/x86.h>
+#include <arch/smp.h>
+#include <arch/apic.h>
+#include <arch/pci.h>
+#include <arch/ne2k.h>
+
+#include <ros/memlayout.h>
+
+#include <atomic.h>
+#include <stdio.h>
+#include <string.h>
+#include <trap.h>
+#include <kmalloc.h>
+
+#include <pmap.h>
+#include <timing.h>
+
+/** @file
+ * @brief NE2K Driver Sketch
+ *
+ * EXPERIMENTAL. DO NOT USE IF YOU DONT KNOW WHAT YOU ARE DOING
+ *
+ * This driver will attempt to detect a ne2k device and run some interrupt
+ * tests. This is used for ioapic debugging in simulation
+ *
+ * @author Paul Pearce <pearce@eecs.berkeley.edu>
+ *
+ * @todo Everything
+ */
+
+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_t 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;                         
+}
diff --git a/kern/arch/i386/ne2k.h b/kern/arch/i386/ne2k.h
new file mode 100644 (file)
index 0000000..8a4b9e5
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef ROS_INC_NE2K_H
+#define ROS_INC_NE2K_H
+
+#include <ros/common.h>
+#include <trap.h>
+#include <pmap.h>
+
+#define ne2k_debug(...)  cprintf(__VA_ARGS__)  
+#define ne2k_interrupt_debug(...) //cprintf(__VA_ARGS__)  
+#define ne2k_frame_debug(...)  cprintf(__VA_ARGS__)  
+
+#define NIC_IRQ_CPU                    5
+
+// Macro for formatting PCI Configuration Address queries
+#define MK_CONFIG_ADDR(BUS, DEV, FUNC, REG) (unsigned long)( (BUS << 16) | (DEV << 11) | \
+                                                             (FUNC << 8) | REG  | \
+                                                             ((uint32_t)0x80000000))
+#define NE2K_VENDOR_ID 0x10EC
+#define NE2K_DEV_ID 0x8029
+
+void ne2k_init();
+int ne2k_scan_pci();
+void ne2k_configure_nic();
+void ne2k_setup_interrupts();
+void ne2k_interrupt_handler(trapframe_t *tf, void* data);
+
+
+
+#endif /* !ROS_INC_NE2K_H */
diff --git a/kern/arch/i386/pci.c b/kern/arch/i386/pci.c
new file mode 100644 (file)
index 0000000..7276444
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2009 The Regents of the University of California
+ * See LICENSE for details.
+ */
+
+#ifdef __SHARC__
+#pragma nosharc
+#endif
+// Not currently sharc complient. 
+
+/** @file
+ * @brief Basic PCI Driver.
+ *
+ * This file is responsible for the scanning the PCI bus and recording
+ * all the information needed for ouR OS to function. 
+ *
+ * No PCI Specifications (or even consulted) were harmed in the making of this file.
+ *
+ * @author Paul Pearce <pearce@eecs.berkeley.edu>
+ *
+ * @todo Build an entire useful PCI subsystem, not this hack with a few data structures laying around
+ *
+ */
+
+#include <arch/x86.h>
+#include <stdio.h>
+#include <string.h>
+#include <arch/pci.h>
+
+// A value of INVALID_IRQ (something 256 or larger) means invalid
+uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
+
+pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
+
+// NOTE: If we care about ALL devices associated with an IRQ, not just the last device, this needs to be some sort of linked structure
+pci_irq_entry_t irq_pci_map[NUM_IRQS];
+
+/**
+ * @brief Perform the actual PCI bus parsing
+ *
+ * See file description.
+ * 
+ * This function must be called during bootup, before ioapic_init().
+ */
+void pci_init() {
+       
+       // Initalize the irq->pci table (pci->irq below)
+       // Setting all 1's forces an invalid entry, as bus = INVALID_BUS = 0xFFFF.
+       memset(irq_pci_map, 0xFF, sizeof(irq_pci_map));
+       
+       uint32_t address;
+       uint32_t bus = 0;
+       uint32_t dev = 0;
+       uint32_t func = 0;
+       uint32_t reg = 0; 
+       uint32_t result  = 0;
+       pci_debug("Scanning PCI Bus....\n");
+
+       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++) {
+
+                               bus = i;
+                               dev = j;
+                               func = k;
+                               reg = 0; // PCI REGISTER 0
+                               
+                               // Set the fields invalid.
+                               pci_irq_map[i][j][k] = INVALID_IRQ;
+                               pci_dev_map[i][j][k].dev_id = INVALID_VENDOR_ID;
+
+                               address = MK_CONFIG_ADDR(bus, dev, func, reg); 
+
+                               // Probe current bus/dev
+                               outl(PCI_CONFIG_ADDR, address);
+                               result = inl(PCI_CONFIG_DATA);
+       
+                               uint16_t dev_id = result >> PCI_DEVICE_OFFSET;
+                               uint16_t ven_id = result & PCI_VENDOR_MASK;
+
+                               // Vender DNE
+                               if (ven_id == INVALID_VENDOR_ID) 
+                                       continue;
+
+                               pci_debug("Found device on BUS %x DEV %x FUNC %x: DEV_ID: %x VEN_ID: %x\n", i, j, k, dev_id, ven_id);
+
+                               // Find the IRQ
+                               address = MK_CONFIG_ADDR(bus, dev, func, PCI_IRQ_REG);
+                               outl(PCI_CONFIG_ADDR, address);
+                               uint16_t irq = inl(PCI_CONFIG_DATA) & PCI_IRQ_MASK;
+                               pci_debug("-->IRQ: %u\n", irq);
+                               
+                               // Find the line (a-d)
+                               address = MK_CONFIG_ADDR(bus, dev, func, PCI_IRQ_REG);
+                               outl(PCI_CONFIG_ADDR, address);
+                               uint8_t line = (inl(PCI_CONFIG_DATA) & PCI_LINE_MASK) >> PCI_LINE_SHFT;
+                               
+                               // If intn == 0, no interrupts used.
+                               if (line != INVALID_LINE) {
+                                       
+                                       // Now shift A to 0, B to 1, etc.
+                                       // This starts off as A 1, B 2 (grr)
+                                       line--;
+                               
+                                       pci_irq_map[i][j][k] = irq;
+                                       pci_dev_map[i][j][k].dev_id = dev_id;
+                                       pci_dev_map[i][j][k].ven_id = ven_id;
+                                       irq_pci_map[irq].bus = i;
+                                       irq_pci_map[irq].dev = j;
+                                       irq_pci_map[irq].func = k;
+                                       irq_pci_map[irq].line = line;
+                                       
+                                       // @todo We may want to perform some check to make sure we arent overwriting some current irq entry and maintain that info
+                               }
+                               
+
+                               /* Loop over the BARs
+                                * Right now we don't do anything useful with this data. 
+                                * This is legacy code in which I pulled data from the BARS during NIC development
+                                * At some point we will have to use this, so the code is still here.
+                                */
+                               
+                               // Note: These magic numbers are from the PCI spec (according to OSDev).
+                               #ifdef CHECK_BARS
+                               for (int k = 0; k <= 5; k++) {
+                                       reg = 4 + k;
+                                       address = MK_CONFIG_ADDR(bus, dev, func, reg << 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;
+                                               pci_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
+                                       } else {
+                                               result = result & PCI_MEM_MASK;
+                                               pci_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
+                                       }                                       
+                               }
+                               #endif
+                               
+                               pci_debug("\n");
+                       }               
+}
diff --git a/kern/arch/i386/pci.h b/kern/arch/i386/pci.h
new file mode 100644 (file)
index 0000000..ce35923
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009 The Regents of the University of California
+ * See LICENSE for details.
+ */
+
+#ifndef ROS_INC_PCI_H
+#define ROS_INC_PCI_H
+
+#define pci_debug(...) // printk(__VA_ARGS__)  
+
+// Macro for creating the address fed to the PCI config register 
+// Several generations away from OSDev inline code.
+#define MK_CONFIG_ADDR(BUS, DEV, FUNC, REG) (unsigned long)( (BUS << 16) | (DEV << 11) | \
+                                                             (FUNC << 8) | REG  | \
+                                                             ((uint32_t)0x80000000))
+
+// General PCI Magic numbers yanked from OSDev / BSD. Yay magic!
+#define PCI_CONFIG_ADDR     0xCF8
+#define PCI_CONFIG_DATA     0xCFC
+#define INVALID_VENDOR_ID   0xFFFF
+
+#define INVALID_IRQ                    0xFFFF
+#define INVALID_BUS                    0xFFFF
+#define INVALID_LINE           0x0000
+
+#define PCI_IO_MASK         0xFFF8
+#define PCI_MEM_MASK        0xFFFFFFF0
+#define PCI_IRQ_MASK           0xFF
+#define PCI_LINE_MASK          0xFF00
+#define PCI_LINE_SHFT          0x8
+#define PCI_VENDOR_MASK                0xFFFF
+#define PCI_DEVICE_OFFSET      0x10
+#define PCI_IRQ_REG                    0x3c
+
+#define PCI_MAX_BUS                    256
+#define PCI_MAX_DEV                    32
+#define PCI_MAX_FUNC           8
+#define PCI_BAR_IO_MASK                0x1
+#define NUM_IRQS                       256
+
+// Offset used for indexing IRQs. Why isnt this defined elsewhere?
+#define KERNEL_IRQ_OFFSET      32
+
+// Run the PCI Code to loop over the PCI BARs. For now we don't use the BARs, dont check em.
+#define CHECK_BARS                     0
+
+typedef struct PCIIRQENTRY {
+       uint16_t bus; // Bus larger than 255 denotes invalid entry.
+                                 // This is why bus is 16 bits not 8.
+       uint8_t dev;
+       uint8_t func;
+       uint8_t line;
+} pci_irq_entry_t;
+
+typedef struct PCIDEVENTRY {
+       uint16_t dev_id; 
+       uint16_t ven_id;
+} pci_dev_entry_t;
+
+void pci_init();
+
+#endif /* !ROS_INC_PCI_H */
diff --git a/kern/arch/i386/rl8168.c b/kern/arch/i386/rl8168.c
new file mode 100644 (file)
index 0000000..4ffc499
--- /dev/null
@@ -0,0 +1,754 @@
+/** @file
+ * @brief NE2K Driver Sketch       
+ *
+ * EXPERIMENTAL. DO NOT USE IF YOU DONT KNOW WHAT YOU ARE DOING
+ *
+ * This driver will attempt to detect a ne2k device and run some interrupt
+ * tests. This is used for ioapic debugging in simulation
+ *
+ * @author Paul Pearce <pearce@eecs.berkeley.edu>
+ *
+ * @todo Everything                   
+ */
+
+#ifdef __SHARC__
+#pragma nosharc
+#endif
+
+#ifdef __DEPUTY__
+#pragma nodeputy
+#endif
+
+#include <arch/mmu.h>
+#include <arch/x86.h>
+#include <arch/smp.h>
+#include <arch/apic.h>
+#include <arch/pci.h>
+#include <arch/rl8168.h>
+
+#include <ros/memlayout.h>
+
+#include <atomic.h>
+#include <stdio.h>
+#include <string.h>
+#include <trap.h>
+#include <kmalloc.h>
+
+#include <pmap.h>
+
+/** @file
+ * @brief Realtek RL8168 Driver
+ *
+ * EXPERIMENTAL. DO NOT USE IF YOU DONT KNOW WHAT YOU ARE DOING
+ *
+ * This is a function rl8168 driver, that uses some really ugly hacks to achieve
+ * UDP communication with a remote syscall server, without a network stack.
+ *
+ * To enable use, define __NETWORK__ in your Makelocal
+ *
+ * @author Paul Pearce <pearce@eecs.berkeley.edu>
+ *
+ * @todo Move documention below into doxygen format.
+ * @todo See list in code
+ */
+
+
+/* RealTek 8168d (8111d) NIC Driver
+ *
+ * Written by Paul Pearce.
+ *
+ * This is a really rough "driver". Really, its not a driver, just a kernel hack to give
+ * the kernel a way to receive and send packets. The basis of the init code is the OSDEV
+ * page on the 8169 chipset, which is a varient of this chipset (most 8169 drivers work 
+ * on the 8168d). http://wiki.osdev.org/RTL8169
+ * 
+ * Basic ideas (although no direct code) were gleamed from the OpenBSD re(4) driver,
+ * which can be found in sys/dev/ic/re.c. sys/dev/ic/rtl81x9reg.h is needed to make
+ * sense of the constants used in re.c.
+ *
+ * This is an ongoing work in progress. Main thing is we need a kernel interface for PCI
+ * devices and network devices, that we can hook into, instead of providing arbitary functions
+ * 
+ * TODO: Remove hacky syscall hack stuff (once we get a real stack).
+ * TODO: Jumbo frame support
+ * TODO: Use high priority transmit ring for syscall stuff.
+ * TODO: Discuss panic conditions.
+ * TODO: Shutdown cleanup kfrees()
+ * TODO: Use onboard timer interrupt to check for packets, instead of writing a bit each time we have a packet.
+ * TODO: CONCURRENCY!
+ */
+
+#ifndef USER_MAC_ADDRESS
+#define USER_MAC_ADDRESS {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+#endif
+
+struct Descriptor
+{
+    unsigned int command,  /* command/status dword */
+                 vlan,     /* currently unused */
+                 low_buf,  /* low 32-bits of physical buffer address */
+                 high_buf; /* high 32-bits of physical buffer address */
+};
+
+
+uint32_t rl8168_io_base_addr = 0;
+uint32_t rl8168_irq = 0;
+char device_mac[6];
+
+struct Descriptor *rx_des_kva;
+struct Descriptor *rx_des_pa;
+
+struct Descriptor *tx_des_kva;
+struct Descriptor *tx_des_pa;
+
+uint32_t rx_des_cur = 0;
+uint32_t tx_des_cur = 0;
+
+uint8_t eth_up = 0; // TODO: This needs to be somewhere global.
+
+// Hacky stuff for syscall hack. Go away.
+int packet_waiting;
+int packet_buffer_size;
+char* packet_buffer;
+char* packet_buffer_orig;
+int packet_buffer_pos = 0;
+// End hacky stuff
+
+void rl8168_init() {
+       
+       if (rl8168_scan_pci() < 0) return;
+       rl8168_read_mac();
+       rl8168_setup_descriptors();
+       rl8168_configure();
+       rl8168_setup_interrupts();
+       eth_up = 1;
+       
+       //Trigger sw based nic interrupt
+/*     cprintf("Generating interrupt...\n");
+       outb(rl8168_io_base_addr + 0x38, 0x1);
+       cprintf("sleeping\n");
+       udelay(3000000);
+       cprintf("done\n");
+*/
+       return;
+}
+
+
+int rl8168_scan_pci() {
+       
+       extern pci_dev_entry_t 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 RealTek 8168 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 bus = i;
+                               uint32_t dev = j;
+                               uint32_t func = k;
+                               uint32_t reg = 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 != REALTEK_VENDOR_ID || dev_id != REALTEK_DEV_ID)
+                                       continue;
+                               cprintf(" found on BUS %x DEV %x\n", i, j);
+
+                               // Find the IRQ
+                               rl8168_irq = pci_irq_map[i][j][k];
+                               rl8168_debug("-->IRQ: %u\n", rl8168_irq);
+
+                               // Loop over the BARs
+                               for (int k = 0; k <= 5; k++) {
+                                       reg = 4 + k;
+                                       address = MK_CONFIG_ADDR(bus, dev, func, reg << 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;
+                                               rl8168_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
+                                       } else {
+                                               result = result & PCI_MEM_MASK;
+                                               rl8168_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
+                                               rl8168_io_base_addr = result;                                           
+                               }
+               
+               rl8168_debug("-->hwrev: %x\n", inl(rl8168_io_base_addr + RL_HWREV_REG) & RL_HWREV_MASK);
+               
+               return 0;
+       }
+       cprintf(" not found. No device configured.\n");
+       
+       return -1;
+}
+
+void rl8168_read_mac() {
+       
+       for (int i = 0; i < 6; i++)
+          device_mac[i] = inb(rl8168_io_base_addr + RL_MAC_OFFSET + i); 
+       
+       rl8168_debug("-->DEVICE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & device_mac[0], 0xFF & device_mac[1],      
+                                                                   0xFF & device_mac[2], 0xFF & device_mac[3], 
+                                                                0xFF & device_mac[4], 0xFF & device_mac[5]);
+       return;
+}
+
+void rl8168_setup_descriptors() {
+       
+       rl8168_debug("-->Setting up tx/rx descriptors.\n");
+                       
+       // Allocate room for the buffers. Include an extra ALIGN space.
+       // Buffers need to be on 256 byte boundries.
+       // Note: Buffers are alligned by kmalloc automatically to powers of 2 less than the size requested
+       // We request more than 256, thus they are aligned on 256 byte boundries
+       rx_des_kva = kmalloc(NUM_RX_DESCRIPTORS * sizeof(struct Descriptor), 0);
+       tx_des_kva = kmalloc(NUM_TX_DESCRIPTORS * sizeof(struct Descriptor), 0);
+       
+       if (rx_des_kva == NULL) panic("Can't allocate page for RX Ring");
+       if (tx_des_kva == NULL) panic("Can't allocate page for TX Ring");
+       
+       rx_des_pa = (struct Descriptor *)PADDR(rx_des_kva);
+       tx_des_pa = (struct Descriptor *)PADDR(tx_des_kva);
+       
+    for (int i = 0; i < NUM_RX_DESCRIPTORS; i++) 
+               rl8168_set_rx_descriptor(i, TRUE); // Allocate memory for the descriptor
+               
+       for (int i = 0; i < NUM_TX_DESCRIPTORS; i++) 
+               rl8168_set_tx_descriptor(i);
+               
+       return;
+}
+
+
+void rl8168_set_rx_descriptor(uint32_t des_num, uint8_t reset_buffer) {
+       
+       // Set the OWN bit on all descriptors. Also set the buffer size.
+       rx_des_kva[des_num].command = (DES_OWN_MASK | (RL_RX_MAX_BUFFER_SIZE & DES_RX_SIZE_MASK));
+       
+       if (des_num == (NUM_RX_DESCRIPTORS - 1)) 
+               rx_des_kva[des_num].command = rx_des_kva[des_num].command | DES_EOR_MASK;
+       
+       if (reset_buffer) {
+               // Must be aligned on 8 byte boundries. Taken care of by kmalloc.
+               char *rx_buffer = kmalloc(RL_RX_MAX_BUFFER_SIZE, 0);
+       
+               if (rx_buffer == NULL) panic ("Can't allocate page for RX Buffer");
+
+               rx_des_kva[des_num].low_buf = PADDR(rx_buffer);
+               //.high_buf used if we do 64bit.
+       }
+       
+       return;
+}
+
+void rl8168_set_tx_descriptor(uint32_t des_num) {
+       
+       // Clear the command bits.
+       tx_des_kva[des_num].command = 0;
+       
+       // Set EOR bit on last descriptor
+       if (des_num == (NUM_TX_DESCRIPTORS - 1))
+               tx_des_kva[des_num].command = DES_EOR_MASK;     
+               
+       char *tx_buffer = kmalloc(RL_TX_MAX_BUFFER_SIZE, 0);
+
+       if (tx_buffer == NULL) panic ("Can't allocate page for TX Buffer");
+
+       tx_des_kva[des_num].low_buf = PADDR(tx_buffer);
+       //.high_buf used if we do 64bit.
+               
+       return;
+}
+
+void rl8168_configure() {
+       
+       // TODO: Weigh resetting the nic. Not really needed. Remove?
+       // TODO Check ordering of what we set.
+       // TODO Remove C+ register setting?
+       
+       rl8168_debug("-->Configuring Device.\n");
+       rl8168_reset();
+
+       // Magic to handle the C+ register. Completely undocumented, ripped from the BSE RE driver.
+       outl(rl8168_io_base_addr + RL_CP_CTRL_REG, RL_CP_MAGIC_MASK);
+
+       // Unlock EPPROM CTRL REG
+       outb(rl8168_io_base_addr + RL_EP_CTRL_REG, RL_EP_CTRL_UL_MASK);         
+       
+       // Set max RX Packet Size
+    outw(rl8168_io_base_addr + RL_RX_MXPKT_REG, RL_RX_MAX_SIZE);       
+               
+       // Set max TX Packet Size
+    outb(rl8168_io_base_addr + RL_TX_MXPKT_REG, RL_TX_MAX_SIZE);                       
+
+       // Set TX Des Ring Start Addr
+    outl(rl8168_io_base_addr + RL_TX_DES_REG, (unsigned long)tx_des_pa); 
+       
+       // Set RX Des Ring Start Addr
+    outl(rl8168_io_base_addr + RL_RX_DES_REG, (unsigned long)rx_des_pa);       
+
+       // Configure TX
+       outl(rl8168_io_base_addr + RL_TX_CFG_REG, RL_TX_CFG_MASK); 
+       
+       // Configure RX
+       outl(rl8168_io_base_addr + RL_TX_CFG_REG, RL_RX_CFG_MASK);                      
+
+       // Enable RX and TX in the CTRL Reg
+       outb(rl8168_io_base_addr + RL_CTRL_REG, RL_CTRL_RXTX_MASK);                     
+
+       // Lock the EPPROM Ctrl REG
+    outl(rl8168_io_base_addr + RL_EP_CTRL_REG, RL_EP_CTRL_L_MASK);             
+       
+       return;
+}
+
+void rl8168_reset() {
+       
+       rl8168_debug("-->Resetting device..... ");
+       outb(rl8168_io_base_addr + RL_CTRL_REG, RL_CTRL_RESET_MASK);
+       
+       // Wait for NIC to answer "done resetting" before continuing on
+       while (inb(rl8168_io_base_addr + RL_CTRL_REG) & RL_CTRL_RESET_MASK);
+       rl8168_debug(" done.\n");
+       
+       return;
+}
+
+void rl8168_setup_interrupts() {
+       
+       extern handler_t interrupt_handlers[];
+       
+       rl8168_debug("-->Setting interrupts.\n");
+       
+       // Enable NIC interrupts
+       outw(rl8168_io_base_addr + RL_IM_REG, RL_INTERRUPT_MASK);
+       
+       //Clear the current interrupts.
+       outw(rl8168_io_base_addr + RL_IS_REG, RL_INTRRUPT_CLEAR);
+       
+       // Kernel based interrupt stuff
+       register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + rl8168_irq, rl8168_interrupt_handler, 0);
+       ioapic_route_irq(rl8168_irq, NE2K_IRQ_CPU);     
+       
+       return;
+}
+
+// We need to evaluate this routine in terms of concurrency.
+// We also need to figure out whats up with different core interrupts
+void rl8168_interrupt_handler(trapframe_t *tf, void* data) {
+       
+       rl8168_interrupt_debug("\nNic interrupt on core %u!\n", lapic_get_id());
+                               
+       // Read the offending interrupt(s)
+       uint16_t interrupt_status = inw(rl8168_io_base_addr + RL_IS_REG);
+
+       // Clear interrupts immediately so we can get the flag raised again.
+       outw(rl8168_io_base_addr + RL_IS_REG, interrupt_status);
+       
+       // Loop to deal with TOCTOU 
+       while (interrupt_status != 0x0000) {
+               // We can have multiple interrupts fire at once. I've personally seen this.
+               // This means we need to handle this as a series of independent if's
+               if (interrupt_status & RL_INT_ROK) {
+                       rl8168_interrupt_debug("-->RX OK\n");
+                       rl8168_handle_rx_packet();
+               }       
+       
+               if (interrupt_status & RL_INT_RERR) {
+                       rl8168_interrupt_debug("-->RX ERR\n");                  
+               }
+       
+               if (interrupt_status & RL_INT_TOK) {
+                       rl8168_interrupt_debug("-->TX OK\n");
+               }
+       
+               if (interrupt_status & RL_INT_TERR) {
+                       rl8168_interrupt_debug("-->TX ERR\n");                  
+               }
+       
+               if (interrupt_status & RL_INT_RDU) {
+                       rl8168_interrupt_debug("-->RX Descriptor Unavailable\n");                       
+               }
+       
+               if (interrupt_status & RL_INT_LINKCHG) {
+                       rl8168_interrupt_debug("-->Link Status Changed\n");                     
+               }
+       
+               if (interrupt_status & RL_INT_FOVW) {
+                       rl8168_interrupt_debug("-->RX Fifo Overflow\n");                        
+               }
+       
+               if (interrupt_status & RL_INT_TDU) {
+                       rl8168_interrupt_debug("-->TX Descriptor Unavailable\n");                       
+               }
+       
+               if (interrupt_status & RL_INT_SWINT) {
+                       rl8168_interrupt_debug("-->Software Generated Interrupt\n");
+               }
+       
+               if (interrupt_status & RL_INT_TIMEOUT) {
+                       rl8168_interrupt_debug("-->Timer Expired\n");
+               }
+       
+               if (interrupt_status & RL_INT_SERR) {
+                       rl8168_interrupt_debug("-->PCI Bus System Error\n");                    
+               }
+       
+               rl8168_interrupt_debug("\n");
+               
+               // Clear interrupts     
+               interrupt_status = inw(rl8168_io_base_addr + RL_IS_REG);
+               outw(rl8168_io_base_addr + RL_IS_REG, interrupt_status);
+       }
+       
+       // In the event that we got really unlucky and more data arrived after we set 
+       //  set the bit last, try one more check
+       rl8168_handle_rx_packet();
+       return;
+}
+
+// TODO: Does a packet too large get dropped or just set the error bits in the descriptor? Find out.
+// TODO: Should we move on to look for the next descriptor? is it safe? TOCTOU
+void rl8168_handle_rx_packet() {
+       
+       uint32_t current_command = rx_des_kva[rx_des_cur].command;
+       uint16_t packet_size;
+       
+       if (current_command & DES_OWN_MASK) {
+               rl8168_frame_debug("-->Nothing to process. Returning.");
+               return;
+       }
+               
+       rl8168_frame_debug("-->RX Des: %u\n", rx_des_cur);
+       
+       // Make sure we are processing from the start of a packet segment
+       if (!(current_command & DES_FS_MASK)) {
+               rl8168_frame_debug("-->ERR: Current RX descriptor not marked with FS mask. Panic!");
+               panic("RX Descriptor Ring FS out of sync");
+       }
+       
+       // NOTE: We are currently configured that the max packet size is large enough to fit inside 1 descriptor buffer,
+       // So we should never be in a situation where a packet spans multiple descriptors.
+       // When we change this, this should operate in a loop until the LS mask is found
+       // Loop would begin here.
+       
+       uint32_t rx_des_loop_cur = rx_des_cur;
+       uint32_t frame_size = 0;
+       uint32_t fragment_size = 0;
+       uint32_t num_frags = 0;
+       
+       char *rx_buffer = kmalloc(MAX_FRAME_SIZE, 0);
+       
+       if (rx_buffer == NULL) panic ("Can't allocate page for incoming packet.");
+       
+       do {
+               current_command =  rx_des_kva[rx_des_loop_cur].command;
+               fragment_size = rx_des_kva[rx_des_loop_cur].command & DES_RX_SIZE_MASK;
+               
+               // If we've looped through the entire ring and not found a terminating packet, bad nic state.
+               // Panic or clear all descriptors? This is a nic hardware error. 
+               if (num_frags && (rx_des_loop_cur == rx_des_cur)) {
+                       //for (int i = 0; i < NUM_RX_DESCRIPTORS; i++) 
+                       //      set_rx_descriptor(i, FALSE); // Dont reallocate memory for the descriptor
+                       // rx_des_cur = 0;
+                       // return;
+                       rl8168_frame_debug("-->ERR: No ending segment found in RX buffer.\n");
+                       panic("RX Descriptor Ring out of sync.");
+               }
+               
+               num_frags++;
+               
+               
+               // Make sure we own the current packet. Kernel ownership is denoted by a 0. Nic by a 1.
+               if (current_command & DES_OWN_MASK) {
+                       rl8168_frame_debug("-->ERR: Current RX descriptor not owned by kernel. Panic!");
+                       panic("RX Descriptor Ring OWN out of sync");
+               }
+               
+               // Make sure if we are at the end of the buffer, the des is marked as end
+               if ((rx_des_loop_cur == (NUM_RX_DESCRIPTORS - 1)) && !(current_command & DES_EOR_MASK)) {
+                       rl8168_frame_debug("-->ERR: Last RX descriptor not marked with EOR mask. Panic!\n");
+                       panic("RX Descriptor Ring EOR Missing");
+               }
+               
+               // We set a max frame size and the nic violated that. 
+               // Panic or clear all desriptors?
+               if ((frame_size + fragment_size) > MAX_FRAME_SIZE) {
+                       //for (int i = 0; i < NUM_RX_DESCRIPTORS; i++) 
+                       //      set_rx_descriptor(i, FALSE); // Dont reallocate memory for the descriptor
+                       // rx_des_cur = 0;
+                       // return;
+                       rl8168_frame_debug("-->ERR: Nic sent %u byte packet. Max is %u\n", frame_size, MAX_FRAME_SIZE);
+                       panic("NIC Sent packets larger than configured.");
+               }
+               
+               // Move the fragment data into the buffer
+               memcpy(rx_buffer + frame_size, KADDR(rx_des_kva[rx_des_loop_cur].low_buf), fragment_size);
+               
+               // Reset the descriptor. No reuse buffer.
+               rl8168_set_rx_descriptor(rx_des_loop_cur, FALSE);
+               
+               // Note: We mask out fragment sizes at 0x3FFFF. There can be at most 1024 of them.
+               // This can not overflow the uint32_t we allocated for frame size, so
+               // we dont need to worry about mallocing too little then overflowing when we read.
+               frame_size = frame_size + fragment_size;
+               
+               // Advance to the next descriptor
+               rx_des_loop_cur = (rx_des_loop_cur + 1) % NUM_RX_DESCRIPTORS;
+               
+       } while (!(current_command & DES_LS_MASK));
+       
+       // Hack for UDP syscall hack. 
+       // This is a quick hack to let us deal with where to put packets coming in. This is not concurrency friendly
+       // In the event that we get 2 incoming frames for our syscall test (shouldnt happen)
+       // We cant process more until another packet comes in. This is ugly, but this code goes away as soon as we integrate a real stack.
+       // This keys off the source port, fix it for dest port. 
+       // Also this may access packet regions that are wrong. If someone addresses empty packet for our interface
+       // and the bits that happened to be in memory before are the right port, this will trigger. this is bad
+       // but since syscalls are a hack for only 1 machine connected, we dont care for now.
+       
+       if ((current_command & DES_PAM_MASK) && (*((uint16_t*)(rx_buffer + 36)) == 0x9bad)) {
+               
+               if (packet_waiting) return;
+
+               packet_buffer = rx_buffer + PACKET_HEADER_SIZE;
+               
+               // So ugly I want to cry
+               packet_buffer_size = *((uint16_t*)(rx_buffer + 38)); 
+               packet_buffer_size = (((uint16_t)packet_buffer_size & 0xff00) >> 8) |  (((uint16_t)packet_buffer_size & 0x00ff) << 8);          
+               packet_buffer_size = packet_buffer_size - 8;
+
+               packet_buffer_orig = rx_buffer;
+               packet_buffer_pos = 0;
+               
+               packet_waiting = 1;
+               
+               rl8168_process_frame(rx_buffer, frame_size, current_command);
+               
+               rx_des_cur = rx_des_loop_cur;
+               
+               return;
+       }
+       
+       // END HACKY STUFF
+       
+       // Chew on the frame data. Command bits should be the same for all frags.
+       rl8168_process_frame(rx_buffer, frame_size, current_command);
+
+       rx_des_cur = rx_des_loop_cur;
+       
+       kfree(rx_buffer);
+       
+       return;
+}
+
+// This is really more of a debug level function. Will probably go away once we get a stack going.
+void rl8168_process_frame(char *frame_buffer, uint32_t frame_size, uint32_t command) {
+               
+       rl8168_frame_debug("-->Command: %x\n", command);
+       rl8168_frame_debug("-->Size: %u\n", frame_size);
+       
+       if (frame_buffer == NULL)
+               return;
+       
+       // This is hacky. Once we know what our stack will look like, change this.
+       // Once remove check for 0 size.
+       if (frame_size < MINIMUM_PACKET_SIZE) {
+               rl8168_frame_debug("-->Packet too small. Discarding.\n");
+               return;
+       }
+       
+       char dest_mac[6];
+       char source_mac[6];
+       char eth_type[2];
+       
+       for (int i = 0; i < 6; i++) {
+               dest_mac[i] = frame_buffer[i];
+       }
+       
+       for (int i = 0; i < 6; i++) {
+               source_mac[i] = frame_buffer[i+6];
+       }
+       
+       eth_type[0] = frame_buffer[12];
+       eth_type[1] = frame_buffer[13];
+       
+       if (command & DES_MAR_MASK) {
+               rl8168_frame_debug("-->Multicast Packet.\n");
+       }
+       
+       if (command & DES_PAM_MASK) {
+               rl8168_frame_debug("-->Physical Address Matched.\n");
+       }
+       
+       if (command & DES_BAR_MASK) {
+               rl8168_frame_debug("-->Broadcast Packet.\n");
+       }
+       
+       // Note: DEST comes before SRC in the ethernet frame, but that 
+       
+       rl8168_frame_debug("-->DEST   MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & dest_mac[0], 0xFF & dest_mac[1],    
+                                                                            0xFF & dest_mac[2], 0xFF & dest_mac[3],    
+                                                                             0xFF & dest_mac[4], 0xFF & dest_mac[5]);
+       
+       rl8168_frame_debug("-->SOURCE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & source_mac[0], 0xFF & source_mac[1],        
+                                                                            0xFF & source_mac[2], 0xFF & source_mac[3],        
+                                                                             0xFF & source_mac[4], 0xFF & source_mac[5]);
+
+       rl8168_frame_debug("-->ETHR MODE: %02x%02x\n", 0xFF & eth_type[0], 0xFF & eth_type[1]);
+               
+       return;
+}
+
+// Main routine to send a frame. Just sends it and goes.
+// Card supports sending across multiple fragments.
+// Would we want to write a function that takes a larger packet and generates fragments?
+// This seems like the stacks responsibility. Leave this for now. may in future
+// Remove the max size cap and generate multiple packets.
+int rl8168_send_frame(const char *data, size_t len) {
+
+       if (data == NULL)
+               return -1;
+       if (len == 0)
+               return 0;
+
+       if (tx_des_kva[tx_des_cur].command & DES_OWN_MASK) {
+               rl8168_frame_debug("-->TX Ring Buffer Full!\n");
+               return -1;
+       }
+       
+       if (len > MAX_FRAME_SIZE) {
+               rl8168_frame_debug("-->Frame Too Large!\n");
+               return -1;
+       }
+       
+       memcpy(KADDR(tx_des_kva[tx_des_cur].low_buf), data, len);
+
+       tx_des_kva[tx_des_cur].command = tx_des_kva[tx_des_cur].command | len | DES_OWN_MASK | DES_FS_MASK | DES_LS_MASK;
+
+       // For this revision of the NIC, the checksum bits get set in the vlan field not the command field.
+       // THIS IS A HACK: Need to reach inside the frame we are sending and detect if its of type ip/udp/tcp and set right flag
+       // For now, for the syscall hack, force ip checksum on. (we dont care about udp checksum).
+       // Add an argument to function to specify packet type?
+       tx_des_kva[tx_des_cur].vlan = DES_TX_IP_CHK_MASK;
+       
+       tx_des_cur = (tx_des_cur + 1) % NUM_TX_DESCRIPTORS;
+       
+       //rl8168_frame_debug("-->Sent packet.\n");
+       
+       outb(rl8168_io_base_addr + RL_TX_CTRL_REG, RL_TX_SEND_MASK);
+       
+       return len;
+}
+
+// This function is a complete hack for syscalls until we get a stack.
+// the day I delete this monstrosity of code I will be a happy man --Paul
+char *rl8168_packet_wrap(const char* data, size_t len) {
+       
+       #define htons(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
+                           (((uint16_t)(A) & 0x00ff) << 8))
+       #define htonl(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \
+                           (((uint32_t)(A) & 0x00ff0000) >> 8)  | \
+                           (((uint32_t)(A) & 0x0000ff00) << 8)  | \
+                           (((uint32_t)(A) & 0x000000ff) << 24))
+
+       #define ntohs  htons
+       #define ntohl  htohl
+
+       if ((len == 0) || (data == NULL))
+               return NULL;
+       
+       struct ETH_Header
+       {
+               char dest_mac[6];
+               char source_mac[6];
+               uint16_t eth_type;
+       };
+
+       
+       struct IP_Header
+       {
+               uint32_t ip_opts0;
+               uint32_t ip_opts1;
+               uint32_t ip_opts2;
+               uint32_t source_ip;
+               uint32_t dest_ip;
+       };
+       
+       struct UDP_Header
+       {
+               uint16_t source_port;
+               uint16_t dest_port;
+               uint16_t length;
+               uint16_t checksum;
+       };      
+       
+       // Hard coded to paul's laptop's mac
+       //Format for Makelocal file: -DUSER_MAC_ADDRESS="{0x00, 0x23, 0x32, 0xd5, 0xae, 0x82}"
+       char dest_mac_address[6] = USER_MAC_ADDRESS;
+       
+       
+       uint32_t source_ip = 0xC0A8000A; // 192.168.0.10
+       uint32_t dest_ip   = 0xC0A8000B; // 192.168.0.11
+       
+       if (len > MAX_PACKET_DATA) {
+               rl8168_frame_debug("Bad packet size for packet wrapping");
+               return NULL;
+       }
+       
+       char* wrap_buffer = kmalloc(MAX_PACKET_SIZE, 0);
+       
+       if (wrap_buffer == NULL) {
+               rl8168_frame_debug("Can't allocate page for packet wrapping");
+               return NULL;
+       }
+       
+       struct ETH_Header *eth_header = (struct ETH_Header*) wrap_buffer;
+       struct IP_Header *ip_header = (struct IP_Header*) (wrap_buffer + sizeof(struct ETH_Header));
+       struct UDP_Header *udp_header = (struct UDP_Header*) (wrap_buffer + sizeof(struct ETH_Header) + sizeof(struct IP_Header));
+       
+       // Setup eth data
+       for (int i = 0; i < 6; i++) 
+               eth_header->dest_mac[i] = dest_mac_address[i];
+               
+       for (int i = 0; i < 6; i++) 
+               eth_header->source_mac[i] = device_mac[i];
+               
+       eth_header->eth_type = htons(0x0800);
+       
+       // Setup IP data
+       ip_header->ip_opts0 = htonl((4<<28) | (5 << 24) | (len + 28));
+       ip_header->ip_opts1 = 0;
+       ip_header->ip_opts2 = 0x00110a;
+       ip_header->source_ip = htonl(source_ip);
+       ip_header->dest_ip = htonl(dest_ip);
+       
+       // Setup UDP Data
+       udp_header->source_port = htons(44443);
+       udp_header->dest_port = htons(44444);
+       udp_header->length = htons(8 + len);
+       udp_header->checksum = 0;
+       
+       memcpy (wrap_buffer + PACKET_HEADER_SIZE, data, len);
+       
+       return wrap_buffer;     
+}
diff --git a/kern/arch/i386/rl8168.h b/kern/arch/i386/rl8168.h
new file mode 100644 (file)
index 0000000..03b2365
--- /dev/null
@@ -0,0 +1,149 @@
+#ifndef ROS_INC_REALTEK_H
+#define ROS_INC_REALTEK_H
+
+#include <ros/common.h>
+#include <trap.h>
+#include <pmap.h>
+
+#define rl8168_debug(...)  //cprintf(__VA_ARGS__)  
+#define rl8168_interrupt_debug(...) //cprintf(__VA_ARGS__)  
+#define rl8168_frame_debug(...)  //cprintf(__VA_ARGS__)  
+
+// We need to provide some global interface for sending and receiving packets to a generic interface
+//  for now, that is this set of Macros! They aren't in caps since the final inteface shoudn't be.
+#define packet_wrap rl8168_packet_wrap
+#define send_frame rl8168_send_frame
+
+#define NE2K_IRQ_CPU           5
+
+#define REALTEK_VENDOR_ID   0x10ec
+#define REALTEK_DEV_ID      0x8168
+
+// Realtek Offsets
+#define RL_HWREV_REG           0x40
+#define RL_MAC_OFFSET          0x00
+#define RL_CTRL_REG         0x37
+#define RL_IM_REG                      0x3c
+#define RL_IS_REG                      0x3E
+#define RL_EP_CTRL_REG         0x50
+#define RL_RX_CFG_REG          0x44
+#define RL_TX_CFG_REG          0x40
+#define RL_RX_MXPKT_REG     0xDA
+#define RL_TX_MXPKT_REG     0xEC
+#define RL_RX_DES_REG       0xE4
+#define RL_TX_DES_REG       0x20
+#define RL_TX_CTRL_REG         0x38    
+#define RL_CP_CTRL_REG         0xE0            
+
+// Realtek masks
+#define RL_HWREV_MASK          0x7C800000
+#define RL_CTRL_RXTX_MASK      0x0C
+#define RL_CTRL_RESET_MASK  0x10
+
+#define RL_EP_CTRL_UL_MASK     0xC0
+#define RL_EP_CTRL_L_MASK      0x00
+#define RL_TX_SEND_MASK                0x40
+#define RL_CP_MAGIC_MASK       0x002B // Magic bits pulled from the BSD driver.
+                                                                  // Are listed as needed for TX/RX checksumming
+
+// NOTE: THESE SHOULD BE BROKEN DOWN INTO A SERIES OF BITS TO REPERSENT THE VARIOUS OPTIONS
+// AND THEN THE MASK SHOULD BE DEFINED TO BE AN OR OF THOSE BITS. THIS IS A QUICK HACK JOB.
+// See interrupts below for how this should be done
+#define RL_RX_CFG_MASK         0x0000E70F  // RXFTH: unlimited, MXDMA: unlimited, AAP: set (promisc. mode set)
+#define RL_TX_CFG_MASK         0x3000700  // IFG: normal, MXDMA: unlimited.  crc appended
+
+// Realtek interrupt bits
+#define RL_INT_SERR                    0x8000
+#define RL_INT_TIMEOUT         0x4000
+#define RL_INT_SWINT           0x0100
+#define RL_INT_TDU                     0x0080
+#define RL_INT_FOVW                    0x0040
+#define RL_INT_LINKCHG         0x0020
+#define RL_INT_RDU                     0x0010
+#define RL_INT_TERR                    0x0008
+#define RL_INT_TOK                     0x0004
+#define RL_INT_RERR                    0x0002
+#define RL_INT_ROK                     0x0001
+
+#define RL_INTERRUPT_MASK      RL_INT_LINKCHG | RL_INT_TOK | RL_INT_ROK | RL_INT_SWINT
+#define RL_INTRRUPT_CLEAR      0xFFFF
+
+// Realtek descriptor command bits
+#define DES_OWN_MASK           0x80000000
+#define DES_EOR_MASK           0x40000000
+#define DES_RX_SIZE_MASK       0x3FFF
+#define DES_FS_MASK                    0x20000000
+#define DES_LS_MASK                    0x10000000
+#define DES_MAR_MASK           0x08000000
+#define DES_PAM_MASK           0x04000000
+#define DES_BAR_MASK           0x02000000
+
+// TFor some reaosn the bits are in an undocumented position for our NIC
+// They should be part of the command field, at the commented addrs below. instead
+// they are part of the vlan field as stated below.
+//#define DES_TX_IP_CHK_MASK  0x40000
+//#define DES_TX_UDP_CHK_MASK 0x20000
+//#define DES_TX_TCP_CHK_MASK 0x10000
+#define DES_TX_IP_CHK_MASK  0x20000000
+#define DES_TX_UDP_CHK_MASK 0x80000000
+#define DES_TX_TCP_CHK_MASK 0x40000000
+
+// Offset used for indexing IRQs
+#define KERNEL_IRQ_OFFSET      32
+
+// Basic packet sizing
+// TODO handle jumbo packets
+#define ETHERNET_ENCAP_SIZE    18
+#define MTU                                    1500    
+#define MAX_FRAME_SIZE         ETHERNET_ENCAP_SIZE + MTU       
+       
+// Realtek Descriptor Related Sizing
+#define NUM_TX_DESCRIPTORS     1024
+#define NUM_RX_DESCRIPTORS     1024
+
+// !!!!!!!!! need to verify the 128byte nature of this field. Spec says it could be 32 for some chips.
+
+#define RL_TX_MAX_BUFFER_SIZE  ROUNDUP(MAX_FRAME_SIZE, 128)
+#define RL_RX_MAX_BUFFER_SIZE  ROUNDUP(MAX_FRAME_SIZE, 8)    // Might be able to be 4 less. Does it strip out the crc flag?
+
+#define RL_TX_MAX_SIZE         RL_TX_MAX_BUFFER_SIZE / 128
+#define RL_RX_MAX_SIZE         RL_RX_MAX_BUFFER_SIZE
+
+#define RL_DES_ALIGN   256
+#define RL_BUF_ALIGN   8
+
+// ^----- Good line ------^
+
+// v----- Evil line ------v
+// Hacky stuff for syscalls go away.
+
+#define MINIMUM_PACKET_SIZE 14 // kinda evil. probably evil.
+#define MAX_PACKET_SIZE                MTU
+
+#define PACKET_HEADER_SIZE  20 + 8 + 14 //IP UDP ETH
+#define MAX_PACKET_DATA                MAX_FRAME_SIZE - PACKET_HEADER_SIZE
+// This number needs verification! Also, this is a huge hack, as the driver shouldnt care about UDP/IP etc.
+
+char *rl8168_packet_wrap(const char* data, size_t len);
+
+
+// ^----- Evil line ------^
+
+// v----- Good line ------v
+
+
+void rl8168_init(void);
+void rl8168_reset(void);
+void rl8168_interrupt_handler(trapframe_t *tf, void* data);
+int rl8168_scan_pci(void);
+void rl8168_read_mac(void);
+void rl8168_setup_interrupts(void);
+void rl8168_setup_descriptors(void);
+void rl8168_configure(void);
+void rl8168_handle_rx_packet(void);
+void rl8168_set_rx_descriptor(uint32_t des_num, uint8_t reset_buffer);
+void rl8168_set_tx_descriptor(uint32_t des_num);
+void rl8168_process_frame(char *frame_buffer, uint32_t frame_size, uint32_t command);
+int rl8168_send_frame(const char *data, size_t len);
+
+#endif /* !ROS_INC_REALTEK_H */
index 184640f..f5163be 100644 (file)
@@ -114,7 +114,7 @@ void smp_boot(void)
        udelay(200);
        send_startup_ipi(0x01);
        */
-       udelay(100000);
+       udelay(500000);
 
        // Each core will also increment smp_semaphore, and decrement when it is done,
        // all in smp_entry.  It's purpose is to keep Core0 from competing for the
index 37279ef..899b479 100644 (file)
@@ -275,10 +275,17 @@ irq_handler(trapframe_t *tf)
        // All others are LAPIC (timer, IPIs, perf, non-ExtINT LINTS, etc)
        // For now, only 235-255 are available
        assert(tf->tf_trapno >= 32); // slows us down, but we should never have this
+       
+       lapic_send_eoi();
+       
+       /*
+       //Old PIC relatd code. Should be gone for good, but leaving it just incase.
        if (tf->tf_trapno < 48)
                pic_send_eoi(tf->tf_trapno - PIC1_OFFSET);
        else
                lapic_send_eoi();
+       */
+
 }
 
 void
index fdec8ab..1b40e25 100644 (file)
@@ -15,6 +15,17 @@ enum
        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,
index c058af1..7b83224 100644 (file)
@@ -10,6 +10,7 @@
 
 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);
index bebaa3a..48ca3e4 100644 (file)
@@ -15,6 +15,11 @@ KERN_SRCFILES := $(KERN_ARCH_SRCFILES) \
                  $(KERN_SRC_DIR)/init.c \
                  $(KERN_SRC_DIR)/monitor.c \
                  $(KERN_SRC_DIR)/printf.c \
+                 $(KERN_SRC_DIR)/trap.c \
+                 $(KERN_SRC_DIR)/trapentry.S \
+                 $(KERN_SRC_DIR)/sched.c \
+                 $(KERN_SRC_DIR)/kdebug.c \
+                 $(KERN_SRC_DIR)/apic.c \
                  $(KERN_SRC_DIR)/printfmt.c \
                  $(KERN_SRC_DIR)/smp.c \
                  $(KERN_SRC_DIR)/multiboot.c \
@@ -45,9 +50,10 @@ KERN_APPFILES := \
                  $(USER_APPS_ROSLIB_DIR)/spawn \
                  $(USER_APPS_ROSLIB_DIR)/hello \
                  $(USER_APPS_ROSLIB_DIR)/mhello \
+                 $(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
index d0b94b8..04b009d 100644 (file)
 #include <manager.h>
 #include <testing.h>
 
+#include <arch/rl8168.h>
+#include <arch/ne2k.h>
+#include <arch/mptables.h>
+#include <arch/pci.h>
+#include <arch/ioapic.h>
+
 void kernel_init(multiboot_info_t *mboot_info)
 {
        extern char (BND(__this, end) edata)[], (SNT end)[];
@@ -63,10 +69,34 @@ void kernel_init(multiboot_info_t *mboot_info)
        idt_init();
        sysenter_init();
        timer_init();
-
+       
+       // @todo: Add an arch specific init? This is ugly
+       #ifdef __i386__
+       mptables_parse();
+       pci_init();
+       ioapic_init(); // MUST BE AFTER PCI/ISA INIT!
+       #endif // __i386__
+               
        // this returns when all other cores are done and ready to receive IPIs
        smp_boot();
        env_init();
+       
+
+       /* EXPERIMENTAL NETWORK FUNCTIONALITY
+        * To enable, define __NETWORK__ in your Makelocal
+        * If enabled, will load the rl8168 driver (if device exists)
+        * and will a boot into userland matrix, so remote syscalls can be performed.
+        * If in simulation, will do some debugging information with the ne2k device
+        *
+        * Note: If you use this, you should also define the mac address of the 
+        * teathered machine via USER_MAC_ADDRESS in Makelocal.
+        *
+        * Additionally, you should have a look at the syscall server in the tools directory
+        */
+       #ifdef __NETWORK__
+       rl8168_init();          
+       ne2k_init();
+       #endif // __NETWORK__
 
        manager();
 }
index 7e19a90..16629b7 100644 (file)
@@ -31,10 +31,11 @@ DECL_PROG(roslib_spawn);
 DECL_PROG(roslib_hello);
 DECL_PROG(roslib_mhello);
 DECL_PROG(roslib_measurements);
+DECL_PROG(parlib_draw_nanwan_standalone);
 DECL_PROG(parlib_channel_test_client);
 DECL_PROG(parlib_channel_test_server);
-DECL_PROG(parlib_matrix);
 DECL_PROG(parlib_hello);
+DECL_PROG(parlib_matrix);
 
 struct kfs_entry kfs[MAX_KFS_FILES] = {
        KFS_ENTRY(roslib_proctests)
@@ -44,10 +45,11 @@ struct kfs_entry kfs[MAX_KFS_FILES] = {
        KFS_ENTRY(roslib_hello)
        KFS_ENTRY(roslib_mhello)
        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_matrix)
        KFS_ENTRY(parlib_hello)
+       KFS_ENTRY(parlib_matrix)
 };
 
 ssize_t kfs_lookup_path(char* path)
index 30ad21b..ccb6227 100644 (file)
@@ -105,11 +105,11 @@ void* kmalloc(size_t size, int flags)
        kmallocdebug("npages: %u\n", npages);
        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;
                }
-               if( j == i-(npages-1)-1 ) {
+               if( j == (i-(npages-1)-1)) {
                        first = j+1;
                        break;
                }
@@ -117,12 +117,13 @@ void* kmalloc(size_t size, int flags)
        //If we couldn't find them, return NULL
        if( first == -1 )
                return NULL;
-       
+               
        //Otherwise go ahead and allocate them to ourselves now
        for(int i=0; i<npages; i++) {
                page_t* page;
                page_alloc_specific(&page, first+i);
-               page_incref(page);
+               // Kevin doesn't like this next line 
+               page_incref(page); 
                page->num_cons_links = npages-i;
                LIST_INSERT_HEAD(&pages_list, page, page_link);
                kmallocdebug("mallocing page: %u\n", first+i);
index 3dbf9ce..2c89a9e 100644 (file)
 void manager(void)
 {
        static uint8_t progress = 0;
+
        struct proc *envs[256];
        struct proc *p ;
 
+       // This is a bypass of the standard manager structure, for network use
+       // If enabled, this spawns parlib_matrix, and allows the execution
+       // of a remote binary to function correctly (schedule() call below)
+       #ifdef __NETWORK__      
+       if (progress++ == 0) {
+               envs[0] = kfs_proc_create(kfs_lookup_path("parlib_matrix"));
+               proc_set_state(envs[0], PROC_RUNNABLE_S);
+               proc_run(envs[0]);
+       }
+       schedule();
+       #endif 
+
        switch (progress++) {
                case 0:
                        // Here's how to do a multicored/parallel process:
index dfe8add..b1edbcd 100644 (file)
@@ -118,7 +118,7 @@ int mon_showmapping(int argc, char **argv, trapframe_t *tf)
 {
        if (argc < 2) {
                cprintf("Shows virtual -> physical mappings for a virtual address range.\n");
-               cprintf("Usage: showmappings START_ADDR [END_ADDR]\n");
+               cprintf("Usage: showmapping START_ADDR [END_ADDR]\n");
                return 1;
        }
        pde_t* pgdir = (pde_t*)vpd;
index c29d02e..e5b270d 100644 (file)
@@ -4,13 +4,19 @@
 #pragma nosharc
 #endif
 
+#ifdef __DEPUTY__
+#pragma nodeputy
+#endif
+
 #include <ros/common.h>
+#include <arch/types.h>
 #include <arch/arch.h>
 #include <arch/mmu.h>
 #include <arch/console.h>
 #include <ros/timer.h>
 #include <ros/error.h>
 
+#include <arch/rl8168.h>
 #include <string.h>
 #include <assert.h>
 #include <process.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
 
+static void sys_yield(struct proc *p);
+
 //Do absolutely nothing.  Used for profiling.
 static void sys_null(void)
 {
@@ -57,6 +66,94 @@ static ssize_t sys_serial_read(env_t* e, char *DANGEROUS _buf, size_t len)
        #endif
 }
 
+//
+/* START OF REMOTE SYSTEMCALL SUPPORT SYSCALLS. THESE WILL GO AWAY AS THINGS MATURE */
+//
+
+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);
+       kfree(new_binary);
+       proc_set_state(env, PROC_RUNNABLE_S);
+       schedule_proc(env);
+       sys_yield(e);
+       
+       return 0;
+}
+
+
+// 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) 
+{ 
+       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;
+}
+
+// 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) 
+{
+       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;
+}
+
+//
+/* END OF REMOTE SYSTEMCALL SUPPORT SYSCALLS. */
+//
+
 static ssize_t sys_shared_page_alloc(env_t* p1,
                                      void**DANGEROUS _addr, envid_t p2_id,
                                      int p1_flags, int p2_flags
@@ -385,6 +482,14 @@ intreg_t syscall(env_t* e, uintreg_t syscallno, uintreg_t a1, uintreg_t a2,
                        return sys_serial_write(e, (char *DANGEROUS)a1, (size_t)a2);
                case SYS_serial_read:
                        return sys_serial_read(e, (char *DANGEROUS)a1, (size_t)a2);
+                case SYS_run_binary:
+                        return sys_run_binary(e, (char *DANGEROUS)a1,
+                                              (char* DANGEROUS)a2, (size_t)a3);
+                case SYS_eth_write:
+                        return sys_eth_write(e, (char *DANGEROUS)a1, (size_t)a2);
+                case SYS_eth_read:
+                        return sys_eth_read(e, (char *DANGEROUS)a1, (size_t)a2);
+
        #endif
 
        #ifdef __sparc_v8__
index 75d98d7..55bf00d 100644 (file)
@@ -24,6 +24,7 @@
 #include <multiboot.h>
 #include <pmap.h>
 #include <page_alloc.h>
+#include <pmap.h>
 
 #ifdef __i386__
 
@@ -80,8 +81,25 @@ void test_pic_reception(void)
        while(1);
 }
 
+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");
diff --git a/tools/syscall_server.c b/tools/syscall_server.c
new file mode 100644 (file)
index 0000000..f584eb8
--- /dev/null
@@ -0,0 +1,656 @@
+#include "syscall_server.h"
+#include <sys/ioctl.h>
+#include <termios.h>
+
+/* Remote Syscall Server app. 
+   Written by Paul Pearce.
+   This is an UGLY HACK to avoid sockets to work with the 
+   ugly hack that is the current tesselaton udp wrapping.
+
+   If you search for the comment UDP you can see how to revert this back
+   to socket niceness.
+
+   Note: The server.h has a shared structure with the newlib_backend.h. These must be kept in sync
+         The only difference is Paul's GCC won't allow unions without names, so the 'subheader' name was added
+*/
+
+// UDP BRANCH
+#include <netdb.h>
+char udp_arr[4096];
+int udp_arr_size = 0;
+int udp_cur_pos = 0;
+// END UDP BRANCH
+
+// TODO: A syscall_id_t that says close the link, and deal with that in the main switch statement.
+int main()
+{
+       // Listen for connections.
+       int data_port = listen_for_connections();
+
+       // Once here, we are inside of new processes, setup the new port.
+       int data_fd = setup_data_connection(data_port);
+
+       // Begin processing data from the connection
+       process_connections(data_fd);
+}
+
+// Bind to LISTEN_PORT and listen for connections on the specified port.
+// If a client requests a connection, spawn off a new process, then continue.
+// In new process, return with the port we are going to listen for data on
+int listen_for_connections()
+{
+       //UDP BRANCH. Do nothing, as this is UDP
+       return -1;
+       // END UDP BRANCH
+
+       // Sockets
+       int listen_socket, data_socket;
+
+       // Address structures
+       struct sockaddr_in server_addr, client_addr;
+
+       // Self explanatory
+       int num_connections, response_msg;
+
+       // Size of our address structure
+       unsigned int addr_len = sizeof(struct sockaddr_in);
+
+       // Fork response for determining if child or parent
+       int child;
+
+       // Create socket
+       if ((listen_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+       {
+               printf("Error: Could not create socket.\n");
+               exit(1);
+       }
+
+       // Setup sockaddr_in
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_port = htons(LISTEN_PORT);
+       server_addr.sin_addr.s_addr = INADDR_ANY;
+       bzero(&(server_addr.sin_zero), 8);      // This is apparently a source of bugs? Who knew.
+
+       // Bind to the given port.
+       if (bind(listen_socket, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)))
+       {
+               printf("Error: Could not bind to port: %i\n", LISTEN_PORT);
+               exit(1);
+       }
+
+       // Listen on the socket
+    if (listen(listen_socket, BACKLOG_LEN) < 0)
+    {
+       printf("Error: Could not listen on socket.\n");
+       exit(1);
+    }
+
+       printf("Server started.\n");
+
+       // Main loop to listen for connections.
+       while(1)
+       {
+               printf("Waiting for connections on port: %i\n", LISTEN_PORT);
+
+               if ((data_socket = accept(listen_socket, (struct sockaddr *)&client_addr,  &addr_len)) < 0)
+               {
+                       printf("Error: Could not accept a new connection.\n");
+               }
+
+               num_connections++;
+               response_msg = num_connections + LISTEN_PORT;
+
+               printf("New connection detected. Assigning port: %i\n", response_msg);
+               if (send(data_socket, (char*)(&response_msg), sizeof(int), 0) < 0)
+               {
+                       printf("Error: Could not send response. New client may not have received port. Continuing.\n");
+                       close(data_socket);
+                       continue;
+               }
+               close(data_socket);
+
+               // Spawn a new process for the connection and offload further communications to that process.
+               if ((child = fork()) == -1)
+               {
+                       printf("Error: Fork failed. Client responses will be ignored. Continuing.\n");
+                       continue;
+               }
+               else if (child)
+               {
+                       // Spawned Process, break out of loop for cleanup and initialization of the listen function.
+                       break;
+               }
+               else
+               {
+                       // Original Process
+                       // Nothing to do. Continue loop.
+               }
+       }
+
+       // Only reach here inside of new process, after spawning. Clean up.
+       close(listen_socket);
+
+       return response_msg;
+}
+
+
+// Perform socket setup on the new port
+int setup_data_connection(int port)
+{
+       // UDP BRANCH
+       port = 44444;
+       // END UDP BRANCH
+
+       // Sockets
+       int listen_socket, data_socket;
+
+       // Address structures
+       struct sockaddr_in server_addr, client_addr;
+
+       // Size of our address structure
+       unsigned int addr_len = sizeof(struct sockaddr_in);
+
+       // Create socket
+       // UDP BRANCH
+       // if ((listen_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+       if ((listen_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+       {
+               printf("Error: Spawned Process, PORT: %i. Could not create socket.\n", port);
+               exit(1);
+       }
+
+       // Setup sockaddr_in
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_port = htons(port);
+       server_addr.sin_addr.s_addr=INADDR_ANY;
+       bzero(&(server_addr.sin_zero), 8);      // This is apparently a source of bugs? Who knew.
+
+       // Bind to the given port.
+       if (bind(listen_socket, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)))
+       {
+               printf("Error: Spawned Process, PORT: %i. Could not bind to port.\n", port);
+               exit(1);
+       }
+
+       //UDP BRANCH
+       data_socket = listen_socket;
+
+       // UDP BRANCH COMMENTED
+       /*
+
+       // Listen on the socket
+    if (listen(listen_socket, BACKLOG_LEN) < 0)
+    {
+       printf("Error: Spawned Process, PORT: %i. Could not listen on socket.\n", port);
+       exit(1);
+    }
+
+       if ((data_socket = accept(listen_socket, (struct sockaddr *)&client_addr,  &addr_len)) < 0)
+       {
+               printf("Error:  Spawned Process, PORT: %i. Could not accept a new connection.\n", port);
+       }
+
+       */ // UDP BRANCH END COMMENT
+
+       printf("Spawned Process, PORT: %i. FD: %i. Established.\n", port, data_socket);
+
+       // END SOCKET SETUP
+
+       return data_socket;
+}
+
+// Poll for a message, return a pointer to message. Caller is required to manage memory of the buffer
+// Called by the server to get data
+void process_connections(int fd) {
+
+       // Variables for the fixed filds.
+       syscall_id_t id;
+
+       int just_read;
+       
+       msg_t temp_msg;
+
+       // TODO: Better msg cleanup on close. Channel cleanup in general
+       while(1)
+       {
+               // Read data from the socket.
+               // Peek == 1, thus if no data is avaiable, return. Else, wait until full syscall_id_t is avaiable
+               just_read = read_header_from_socket(&temp_msg, fd);
+
+               if (just_read == 0)
+               {
+                       //sleep(1);
+                       continue;
+               }
+               
+               id = temp_msg.id;
+
+               // If we couldnt read data, or the ID we got is bad, terminate process.
+               if ((just_read == -1) || (id < 0) || (id > NUM_CALLS))
+               {
+                       printf("error on id: %d\n", id);
+                       send_error(fd);
+
+                       return;
+               }
+
+               msg_t * msg = NULL;
+               response_t * return_msg = NULL;
+               int return_len = -1;
+
+               switch (id) {
+                       case OPEN_ID:
+                               msg = malloc(sizeof(msg_t) + temp_msg.subheader.open.len);
+                               if (msg == NULL) {
+                                       send_error(fd);
+                                       return;
+                               }
+                               
+                               *msg = temp_msg;
+                               just_read = read_buffer_from_socket(msg->subheader.open.buf, fd, msg->subheader.open.len);
+                               
+                               if (just_read != msg->subheader.open.len) {
+                                       free(msg);
+                                       send_error(fd);
+                                       return;
+                               }
+
+                               return_msg = handle_open(msg);
+                               free(msg);
+                               return_len = sizeof(response_t);
+                               break;
+
+                       case CLOSE_ID:
+                               return_msg = handle_close(&temp_msg);
+                               return_len = sizeof(response_t);
+                               break;
+
+                       case READ_ID:
+                               return_msg = handle_read(&temp_msg);
+                               if (return_msg != NULL)
+                                       return_len = sizeof(response_t) + ((return_msg->ret >= 0)  ? return_msg->ret : 0);
+                               break;
+
+                       case WRITE_ID:
+
+                               msg = malloc(sizeof(msg_t) + temp_msg.subheader.write.len);
+                               if (msg == NULL) {
+                                       send_error(fd);
+                                       return;
+                               }
+                               
+                               *msg = temp_msg;
+                               just_read = read_buffer_from_socket(msg->subheader.write.buf, fd, msg->subheader.write.len);
+
+                               if (just_read != msg->subheader.write.len) {
+                                       free(msg);
+                                       send_error(fd);
+                                       return;
+                               }
+
+                               return_msg = handle_write(msg);
+                               free(msg);
+
+                               return_len = sizeof(response_t);
+                               break;
+
+                       case LSEEK_ID:
+
+                               return_msg = handle_lseek(&temp_msg);
+                               return_len = sizeof(response_t);
+                               break;
+
+                       case ISATTY_ID:
+                               return_msg = handle_isatty(&temp_msg);
+                               return_len = sizeof(response_t);
+                               break;
+
+                       case UNLINK_ID:
+                               msg = malloc(sizeof(msg_t) + temp_msg.subheader.unlink.len);
+                               if (msg == NULL) {
+                                       send_error(fd);
+                                       return;
+                               }
+                               
+                               *msg = temp_msg;
+                               just_read = read_buffer_from_socket(msg->subheader.unlink.buf, fd, msg->subheader.unlink.len);
+                               
+                               if (just_read != msg->subheader.unlink.len) {
+                                       free(msg);
+                                       send_error(fd);
+                                       return;
+                               }
+                       
+                               return_msg = handle_unlink(msg);
+                               free(msg);
+                               return_len = sizeof(response_t);
+                               break;
+
+                       case LINK_ID:
+                       
+                               msg = malloc(sizeof(msg_t) + temp_msg.subheader.link.old_len + temp_msg.subheader.link.new_len);
+                               if (msg == NULL) {
+                                       send_error(fd);
+                                       return;
+                               }
+                               
+                               *msg = temp_msg;
+                               just_read = read_buffer_from_socket(msg->subheader.link.buf, fd, temp_msg.subheader.link.old_len + temp_msg.subheader.link.new_len);
+                               
+                               if (just_read != (temp_msg.subheader.link.old_len + temp_msg.subheader.link.new_len)) {
+                                       free(msg);
+                                       send_error(fd);
+                                       return;
+                               }
+                       
+                               return_msg = handle_link(msg);
+                               free(msg);
+                               return_len = sizeof(response_t);
+                               break;
+
+                       case FSTAT_ID:
+                               return_msg = handle_fstat(&temp_msg);
+                               return_len = sizeof(response_t);
+
+                               break;
+
+                       case STAT_ID:
+                               msg = malloc(sizeof(msg_t) + temp_msg.subheader.stat.len);
+                               if (msg == NULL) {
+                                       send_error(fd);
+                                       return;
+                               }
+                       
+                               *msg = temp_msg;
+                               just_read = read_buffer_from_socket(msg->subheader.stat.buf, fd, msg->subheader.stat.len);
+                       
+                               if (just_read != msg->subheader.stat.len) {
+                                       free(msg);
+                                       send_error(fd);
+                                       return;
+                               }
+
+                               return_msg = handle_stat(msg);
+                               free(msg);
+                               return_len = sizeof(response_t);
+
+                               break;
+                       default:
+                               send_error(fd);
+                               return;
+               }
+
+               if (return_msg == NULL)
+               {
+                       send_error(fd);
+                       return;
+               }
+
+               // UDP BRANCH. 
+               struct hostent *hp;
+               hp = gethostbyname("192.168.0.10");
+               struct sockaddr_in addr;
+               memset(&addr, 0, sizeof(addr));
+               addr.sin_family = AF_INET;
+               memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
+               addr.sin_port = htons(44443);
+               // END UDP BRANCH
+
+               if ( sendto(fd, return_msg, return_len, 0, (struct sockaddr *)&addr, sizeof(addr)) != return_len)
+               //if (write(fd, return_msg, return_len) != return_len)
+               {
+                       free(return_msg);
+                       // If we cant write to the socket, cant send CONNECTION_TERMINATED. Just die.
+                       printf("Error: Spawned Process, FD: %i. Could not send data out. Dying.\n", fd);
+                       return;
+               }
+
+               free(return_msg);
+       }
+}
+
+int read_header_from_socket(msg_t* msg, int socket) {
+       return read_from_socket((char*)msg, socket, sizeof(msg_t), PEEK);
+}
+
+int read_buffer_from_socket(char* buf, int socket, int len) {
+       return read_from_socket(buf, socket, len, NO_PEEK);
+}
+
+// UDP HACK VERSION
+// Read len bytes from the given socket 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, it will block until the entire amount is available.
+// Return values are:
+// -1 if error
+// 0 if peek and nothing avaiable
+// else len
+int read_from_socket(char* buf, int socket, int len, int peek) {
+
+       // This function is now super hacked to deal with UDP uglyness. Do not use this to revert once we get tcpip online!
+
+       int total_read = 0;
+
+       if (udp_arr_size == 0) {
+               udp_arr_size = recvfrom(socket, udp_arr, 4096, 0, 0, 0);
+
+               if (udp_arr_size == 0)
+                       return -1;
+       }
+
+       if ((udp_cur_pos + len) > udp_arr_size)
+               return -1;
+
+       memcpy(buf, udp_arr + udp_cur_pos, len);
+
+       udp_cur_pos = udp_cur_pos + len;
+
+       if (udp_cur_pos == udp_arr_size) {
+               udp_cur_pos = 0;
+               udp_arr_size = 0;
+       }
+
+       return len;
+
+       // UDP BRANCH
+       //int just_read = read(socket, buf, len);
+       int just_read = recvfrom(socket, buf, len, 0, 0, 0);
+
+       if (just_read < 0) return just_read;
+       if (just_read == 0 && peek) return just_read;
+
+       total_read += just_read;
+
+       while (total_read != len) {
+               // UDP BRANCH
+               //just_read = read(socket, buf + total_read, len - total_read);
+               just_read = recvfrom(socket, buf + total_read, len - total_read, 0, 0, 0);
+
+               if (just_read == -1) return -1;
+
+               total_read += just_read;
+       }
+
+       return total_read;
+}
+
+// Non hacky UDP version
+/*
+int read_from_socket(char* buf, int socket, int len, int peek) {
+        int total_read = 0;
+        //printf("\t\treading %i bytes on socket %i with peek %i\n", len, socket, peek);
+        int just_read = read(socket, buf, len);
+        //printf("\t\tread    %i bytes on socket %i with peek %i\n", just_read, socket, peek);
+                                        
+        if (just_read < 0) return just_read;
+        if (just_read == 0 && peek) return just_read;
+                                
+        total_read += just_read;
+                                
+        while (total_read != len) {
+                just_read = read(socket, buf + total_read, len - total_read);
+                if (just_read == -1) return -1;
+                total_read += just_read;
+        }                       
+                
+        return total_read;
+}*/
+
+
+// Send CONNECTION_TERMINATED over the FD (if possible)
+// Not fully functional.
+void send_error(int fd)
+{
+       printf("Error: Spawned Process, FD: %i. Could not read from from socket. Sending CONNECTION_TERMINATED.... ", fd);
+
+       int error_msg = CONNECTION_TERMINATED;
+
+       /*if (write(fd, (char*)(&error_msg) , sizeof(int)) != sizeof(int))
+       {
+               printf("Could not send CONNECTION_TERMINATED.\n");
+       }
+       else
+       {
+               printf("Sent.\n");
+
+       }*/
+
+       close(fd);
+}
+
+
+response_t* handle_open(msg_t *msg)
+{
+       printf("opening: %s\n", msg->subheader.open.buf);
+       
+       response_t * response = malloc(sizeof(response_t));
+       if (response == NULL) return NULL;
+
+
+       response->ret = open(msg->subheader.open.buf, msg->subheader.open.flags, msg->subheader.open.mode);
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+
+       return response;
+}
+
+response_t* handle_close(msg_t *msg)
+{              
+       response_t * response = malloc(sizeof(response_t));
+       if (response == NULL) return NULL;
+
+
+       response->ret = close(msg->subheader.close.fd);
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+
+       return response;
+}
+
+response_t* handle_read(msg_t * msg) 
+{      
+       response_t * response = malloc(sizeof(response_t) + msg->subheader.read.len);
+       if (response == NULL) return NULL;
+
+       response->ret = read(msg->subheader.read.fd, response->buf, msg->subheader.read.len);
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+
+       return response;
+}
+
+response_t* handle_write(msg_t * msg) 
+{
+       response_t * response = malloc(sizeof(response_t));
+       if (response == NULL) return NULL;
+
+       response->ret = write(msg->subheader.write.fd, msg->subheader.write.buf, msg->subheader.write.len);
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+
+       return response;
+}
+
+response_t* handle_lseek(msg_t * msg)
+{
+       response_t * response = malloc(sizeof(response_t));
+       if (response == NULL) return NULL;
+
+       response->ret = lseek(msg->subheader.lseek.fd, msg->subheader.lseek.ptr, msg->subheader.lseek.dir);
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+}
+
+response_t* handle_isatty(msg_t * msg) 
+{
+       response_t * response = malloc(sizeof(response_t));
+       if (response == NULL) return NULL;
+       
+       response->ret = isatty(msg->subheader.isatty.fd);
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+
+       return response;
+}
+
+response_t* handle_unlink(msg_t * msg)
+{
+       response_t * response = malloc(sizeof(response_t));
+       if (response == NULL) return NULL;
+
+
+       response->ret = unlink(msg->subheader.unlink.buf);
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+
+       return response;
+}
+
+response_t* handle_link(msg_t * msg) 
+{
+       response_t * response = malloc(sizeof(response_t));
+       if (response == NULL) return NULL;
+
+
+       response->ret = link(msg->subheader.link.buf, msg->subheader.link.buf + msg->subheader.link.old_len);
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+
+       return response;
+}
+
+response_t* handle_stat(msg_t * msg) {
+       response_t * response = malloc(sizeof(response_t));
+       if (response == NULL) return NULL;
+
+
+       response->ret = stat(msg->subheader.stat.buf, &(response->st));
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+
+       return response;
+}
+
+response_t* handle_fstat(msg_t *msg) {
+       
+       response_t * response = malloc(sizeof(response_t));
+       if (response == NULL) return NULL;
+
+       response->ret = fstat(msg->subheader.fstat.fd, &(response->st));
+       
+       if (response->ret == -1) {
+               response->err = errno;
+       }
+
+       return response;
+}
diff --git a/tools/syscall_server.h b/tools/syscall_server.h
new file mode 100644 (file)
index 0000000..7ff316e
--- /dev/null
@@ -0,0 +1,157 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+// Todo: review the laundry list of includes.
+
+// Backlog for the listen() call.
+#define BACKLOG_LEN 16
+
+#define LISTEN_PORT 12345
+#define SERVER_IP "128.32.35.43"
+
+#define OPEN_ID                0
+#define CLOSE_ID       1
+#define READ_ID                2
+#define WRITE_ID       3
+#define LINK_ID                4
+#define UNLINK_ID      5
+#define LSEEK_ID       6
+#define FSTAT_ID       7
+#define ISATTY_ID      8
+#define STAT_ID                9
+#define NUM_CALLS      10
+
+// New errno we want to define if a channel error occurs
+// Not yet fully implimented
+#define ECHANNEL -999
+
+// Value to send across the channel as a function return value in the event of server side termination
+// Note yet fully implimented
+#define CONNECTION_TERMINATED -2
+
+// Macros for the read_from_channel function
+#define PEEK    1
+#define NO_PEEK 0
+
+// Should refactor this next typedef. Just leave it as type int.
+typedef int syscall_id_t;
+
+// ALL STRUCTS MUST BE PADDED TO THE SAME SIZE.
+// Basically, to make IVY annotation possible with as few TC's as possible
+// We do some ugly things with unions, which results in us needing this padding
+typedef struct open_subheader {
+       uint32_t flags;
+       uint32_t mode;
+       uint32_t len;
+       char buf[0];
+} open_subheader_t;
+
+typedef struct close_subheader {
+       uint32_t fd;
+       uint32_t FILL1;
+       uint32_t FILL2;
+} close_subheader_t;
+
+typedef struct read_subheader {
+       uint32_t fd;
+       uint32_t len;
+       uint32_t FILL1;
+} read_subheader_t;
+
+typedef struct write_subheader {
+       uint32_t fd;
+       uint32_t len;
+       uint32_t FILL1;
+       char buf[0];
+} write_subheader_t;
+
+typedef struct lseek_subheader {
+       uint32_t fd;
+       uint32_t ptr;
+       uint32_t dir;
+} lseek_subheader_t;
+
+typedef struct isatty_subheader {
+       uint32_t fd;
+       uint32_t FILL1;
+       uint32_t FILL2;
+} isatty_subheader_t;
+
+typedef struct link_subheader {
+       uint32_t old_len;
+       uint32_t new_len;
+       uint32_t FILL1;
+       char buf[0];
+} link_subheader_t;
+
+typedef struct unlink_subheader {
+       uint32_t len;
+       uint32_t FILL1;
+       uint32_t FILL2;
+       char buf[0];
+} unlink_subheader_t;
+
+typedef struct fstat_subheader {
+       uint32_t fd;
+       uint32_t FILL1;
+       uint32_t FILL2;
+} fstat_subheader_t;
+
+typedef struct stat_subheader {
+       uint32_t len;
+       uint32_t FILL1;
+       uint32_t FILL2;
+       char buf[0];
+} stat_subheader_t;
+
+typedef struct backend_msg {
+       syscall_id_t id;
+       union {
+               open_subheader_t open;
+               close_subheader_t close;
+               read_subheader_t read;
+               write_subheader_t write;
+               lseek_subheader_t lseek;
+               isatty_subheader_t isatty;
+               link_subheader_t link;
+               unlink_subheader_t unlink;
+               fstat_subheader_t fstat;
+               stat_subheader_t stat;  
+       } subheader;
+} msg_t;
+
+typedef struct response {
+       int32_t ret;
+       uint32_t err;
+       struct stat st;
+       char buf[0];
+} response_t;
+
+#undef errno
+extern int errno;
+
+response_t* handle_open(msg_t * msg);
+response_t* handle_close(msg_t * msg);
+response_t* handle_read(msg_t * msg);
+response_t* handle_write(msg_t * msg);
+response_t* handle_lseek(msg_t * msg);
+response_t* handle_isatty(msg_t * msg);
+response_t* handle_unlink(msg_t * msg);
+response_t* handle_link(msg_t * msg);
+response_t* handle_stat(msg_t * msg);
+response_t* handle_fstat(msg_t * msg);
+
+int listen_for_connections();
+int setup_data_connection(int data_port);
+void process_connections(int fd);
+int read_from_socket(char* buf, int socket, int len, int peek);
+int read_header_from_socket(msg_t* msg, int socket);
+int read_buffer_from_socket(char* buf, int socket, int len);
+void send_error(int fd);
index 1c01964..a8d20a4 100644 (file)
@@ -24,6 +24,7 @@ USER_APPS_PARLIB_LDOBJS    := $(OBJDIR)/$(USER_PARLIB_ARCH_SRC_DIR)/entry.o \
                               $(OBJDIR)/$(USER_APPS_PARLIB_DIR)/file_error.o \
                               $(OBJDIR)/$(USER_APPS_PARLIB_DIR)/clrscrn.o \
                               $(OBJDIR)/$(USER_APPS_PARLIB_DIR)/draw_nanwan.o \
+                              $(OBJDIR)/$(USER_APPS_PARLIB_DIR)/run_binary.o \
                               $(OBJDIR)/$(USER_APPS_PARLIB_DIR)/change_user.o  
 
 
diff --git a/user/apps/parlib/draw_nanwan_standalone.c b/user/apps/parlib/draw_nanwan_standalone.c
new file mode 100644 (file)
index 0000000..16f6663
--- /dev/null
@@ -0,0 +1,34 @@
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+       /* Borrowed with love from http://www.geocities.com/SoHo/7373/zoo.htm
+        * (http://www.ascii-art.com/).  Slightly modified to make it 25 lines tall.
+        */
+       printf("\n");
+       printf("             .-.  .-.\n");
+       printf("             |  \\/  |\n");
+       printf("            /,   ,_  `'-.\n");
+       printf("          .-|\\   /`\\     '. \n");
+       printf("        .'  0/   | 0\\  \\_  `\".  \n");
+       printf("     .-'  _,/    '--'.'|#''---'\n");
+       printf("      `--'  |       /   \\#\n");
+       printf("            |      /     \\#\n");
+       printf("            \\     ;|\\    .\\#\n");
+       printf("            |' ' //  \\   ::\\# \n");
+       printf("            \\   /`    \\   ':\\#\n");
+       printf("             `\"`       \\..   \\#\n");
+       printf("                        \\::.  \\#\n");
+       printf("                         \\::   \\#\n");
+       printf("                          \\'  .:\\#\n");
+       printf("                           \\  :::\\#\n");
+       printf("                            \\  '::\\#\n");
+       printf("                             \\     \\#\n");
+       printf("                              \\:.   \\#\n");
+       printf("                               \\::   \\#\n");
+       printf("                                \\'   .\\#\n");
+       printf("                             jgs \\   ::\\#\n");
+       printf("                                  \\      \n");
+       return 0;
+}
+
index c590248..63b3486 100644 (file)
@@ -12,13 +12,13 @@ extern char * readline(const char *prompt);
 
 void file_io()
 {      
-       printf("Beginning Serial Based File IO Test...\n\n");
+       printf("Beginning Ethernet Based File IO Test...\n\n");
        int in_fd = open("./test/input", O_RDWR, 0);
+       printf("Opened:       input\n");
+       printf("FD:           %d\n", in_fd);
        char buf[IN_BUF_SIZE];
        int read_amt = read(in_fd, buf, IN_BUF_SIZE - 1);
        buf[read_amt] = '\0';
-       printf("Opened:       input\n");
-       printf("FD:           %d\n", in_fd);
        printf("Read:         %d bytes\n", read_amt);
        printf("Data read:    %s", buf);
 
index 7cb7ff0..1aa741f 100644 (file)
@@ -11,6 +11,7 @@ extern void change_user();
 extern void set_default_user();
 extern void file_io();
 extern void file_error();
+extern void run_binary();
 extern char prompt[256];
 
 void help() {
@@ -18,8 +19,9 @@ void help() {
               "  draw_nanwan:      Draw a picture of Nanwan, our mascot giraffe\n"
               "  clear_screen:     Clear the Screen\n"
               "  change_user:      Change Username\n"
-               "  file_io:          Run File Related IO Tests\n"
-               "  file_error:       Run File Error Related Tests\n"
+           "  file_io:          Run File Related IO Tests\n"
+           "  file_error:       Run File Error Related Tests\n"
+           "  run_binary:       Load and run a binary located on the remote server\n"
              );
 }
 
@@ -45,6 +47,8 @@ int main(int argc, char** argv)
                        file_io();
                else if (strcmp(s, "file_error") == 0)
                        file_error();
+               else if (strcmp(s, "run_binary") == 0)
+                       run_binary();
                else
                        help(); 
 
diff --git a/user/apps/parlib/run_binary.c b/user/apps/parlib/run_binary.c
new file mode 100644 (file)
index 0000000..5efbbdb
--- /dev/null
@@ -0,0 +1,74 @@
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <parlib.h>
+
+extern char * readline(const char *prompt);
+
+#define READ_SIZE       1024
+uint8_t* binary_buf;
+
+static void fd_error() {
+       fprintf(stderr, "Error: Unable to run remote binary: %s\n", strerror(errno));
+}
+
+static void malloc_error() {
+       fprintf(stderr, "Error: Unable to run remote binary: No more memory avaialable!\n");
+}
+
+static void read_error(void* buf, int fd) {
+       free(binary_buf);
+       close(fd);
+       fprintf(stderr, "Error: Unable to run remote binary: %s\n", strerror(errno));
+}
+
+static void realloc_error(void* buf, int fd) {
+       free(binary_buf);
+       close(fd);
+       fprintf(stderr, "Error: Unable to run remote binary: No more memory available!\n");
+}
+
+void run_binary()
+{      
+       char * readline_result = readline("\nEnter name of binary to execute: ");
+       if (readline_result == NULL) {
+               printf("Error reading from console.\n");
+               return;
+       }
+
+       char * file_name = malloc(strlen(readline_result) + 8);
+       sprintf(file_name, "./test/%s", readline_result);
+       int fd = open(file_name, O_RDONLY, 0);
+       if(fd < 0) { fd_error(); return; };
+       
+       int iters = 1;
+       binary_buf = malloc(READ_SIZE);
+       if(binary_buf == NULL) { malloc_error(); return; }
+       
+       int total_bytes_read = 0;
+       int bytes_read = read(fd, binary_buf, READ_SIZE);
+       if(bytes_read < 0) { read_error(binary_buf, fd); return; }
+       
+       while(bytes_read > 0) {
+               total_bytes_read += bytes_read; 
+               void* temp_buf = realloc(binary_buf, READ_SIZE*(++iters));
+               if(temp_buf == NULL) { realloc_error(binary_buf, fd); return; } 
+               binary_buf = temp_buf;
+               bytes_read = read(fd, binary_buf+total_bytes_read, READ_SIZE);
+               if(bytes_read < 0) { read_error(binary_buf, fd); return; }
+       }
+       printf("Loading Binary: %s, ROMSIZE: %d\n", readline_result, total_bytes_read);
+       ssize_t error = sys_run_binary(binary_buf, NULL, total_bytes_read);
+       if(error < 0) {
+               fprintf(stderr, "Error: Unable to run remote binary\n");
+       }
+       free(binary_buf);
+       close(fd);
+
+}
+
index 0c312ed..2ee9e4d 100644 (file)
 #define STAT_ID                9
 #define NUM_CALLS      10
 
+#define debug_in_out(...) // debug(__VA_ARGS__)  
+#define debug_write_check(fmt, ...)  //debug(fmt, __VA_ARGS__)
+
+typedef uint32_t syscall_id_t;
+
+// ALL STRUCTS MUST BE PADDED TO THE SAME SIZE.
+// Basically, to make IVY annotation possible with as few TC's as possible
+// We do some ugly things with unions, which results in us needing this padding
+typedef struct open_subheader {
+       uint32_t flags;
+       uint32_t mode;
+       uint32_t len;
+       char buf[0];
+} open_subheader_t;
+
+typedef struct close_subheader {
+       uint32_t fd;
+       uint32_t FILL1;
+       uint32_t FILL2;
+} close_subheader_t;
+
+typedef struct read_subheader {
+       uint32_t fd;
+       uint32_t len;
+       uint32_t FILL1;
+} read_subheader_t;
+
+typedef struct write_subheader {
+       uint32_t fd;
+       uint32_t len;
+       uint32_t FILL1;
+       char buf[0];
+} write_subheader_t;
+
+typedef struct lseek_subheader {
+       uint32_t fd;
+       uint32_t ptr;
+       uint32_t dir;
+} lseek_subheader_t;
+
+typedef struct isatty_subheader {
+       uint32_t fd;
+       uint32_t FILL1;
+       uint32_t FILL2;
+} isatty_subheader_t;
+
+typedef struct link_subheader {
+       uint32_t old_len;
+       uint32_t new_len;
+       uint32_t FILL1;
+       char buf[0];
+} link_subheader_t;
+
+typedef struct unlink_subheader {
+       uint32_t len;
+       uint32_t FILL1;
+       uint32_t FILL2;
+       char buf[0];
+} unlink_subheader_t;
+
+typedef struct fstat_subheader {
+       uint32_t fd;
+       uint32_t FILL1;
+       uint32_t FILL2;
+} fstat_subheader_t;
+
+typedef struct stat_subheader {
+       uint32_t len;
+       uint32_t FILL1;
+       uint32_t FILL2;
+       char buf[0];
+} stat_subheader_t;
+
+typedef struct backend_msg {
+       syscall_id_t id;
+       union {
+               open_subheader_t open;
+               close_subheader_t close;
+               read_subheader_t read;
+               write_subheader_t write;
+               lseek_subheader_t lseek;
+               isatty_subheader_t isatty;
+               link_subheader_t link;
+               unlink_subheader_t unlink;
+               fstat_subheader_t fstat;
+               stat_subheader_t stat;  
+       };
+} msg_t;
+
+typedef struct response {
+       int32_t ret;
+       uint32_t err;
+       struct stat st;
+       char buf[0];
+} response_t;
 
-// Fixed size of the client->server msgs for the various calls.
-#define OPEN_MESSAGE_FIXED_SIZE       sizeof(syscall_id_t) + 3*sizeof(int)
-#define CLOSE_MESSAGE_FIXED_SIZE      sizeof(syscall_id_t) + sizeof(int)
-#define READ_MESSAGE_FIXED_SIZE       sizeof(syscall_id_t) + 2*sizeof(int)
-#define WRITE_MESSAGE_FIXED_SIZE      sizeof(syscall_id_t) + 2*sizeof(int)
-#define LSEEK_MESSAGE_FIXED_SIZE      sizeof(syscall_id_t) + 3*sizeof(int)
-#define ISATTY_MESSAGE_FIXED_SIZE     sizeof(syscall_id_t) + sizeof(int)
-#define LINK_MESSAGE_FIXED_SIZE       sizeof(syscall_id_t) + 2*sizeof(int)
-#define UNLINK_MESSAGE_FIXED_SIZE     sizeof(syscall_id_t) + sizeof(int)
-#define FSTAT_MESSAGE_FIXED_SIZE      sizeof(syscall_id_t) + sizeof(int)
-#define STAT_MESSAGE_FIXED_SIZE       sizeof(syscall_id_t) + sizeof(int)
-
-// What is the max number of arguments (besides the syscall_id_t) we can have.
-// This should be the max of the above sizes.
-// This exists so we can  allocate a fixed amount of memory to process all incoming msgs
-// TODO: This makes the implicit assumption when referenced in server.c that each argument is of type int.
-//             If we change the above defs to no longer be sizeof(int) this will break in server.c
-#define MAX_FIXED_ARG_COUNT 3
 
 // New errno we want to define if a channel error occurs
 // Not yet fully implimented
 #define PEEK    1
 #define NO_PEEK 0
 
-typedef uint32_t syscall_id_t;
 
 /* Read len bytes from the given channel to the buffer.
  * If peek is NO_PEEK, will wait indefinitely until that much data is read.
@@ -61,16 +137,20 @@ typedef uint32_t syscall_id_t;
  */
 int read_from_channel(char * buf, int len, int peek);
 
+int read_response_from_channel(response_t *response);
+int read_buffer_from_channel(char *buf, int len);
+
+
 /* send_message()
  * Write the message defined in buffer out across the channel, and wait for a response.
  * Caller is responsible for management of both the buffer passed in and the buffer ptr returned.
  */
-char *send_message(char *message, int len);
+response_t *send_message(msg_t *msg, int len);
 
 /* write_to_channel()
  * Send a message out over the channel, defined by msg, of length len
  */
-int write_to_channel(char *msg, int len);
+int write_to_channel(msg_t *msg, int len);
 
 #endif //_NEWLIB_LIBC_WRAPPERS_H_
 
index b5a03a2..1e6a4d2 100644 (file)
@@ -12,7 +12,7 @@
 #include <ros/syscall.h>
 #include <ros/error.h>
 #include <ros/procdata.h>
-#include <newlib_backend.h>
+#include <errno.h>
 
 enum {
        PG_RDONLY = 4,
@@ -30,6 +30,9 @@ ssize_t     sys_cputs(const uint8_t *s, size_t len);
 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_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);
index b460bb9..324bc9e 100644 (file)
@@ -1,5 +1,15 @@
 /* See COPYRIGHT for copyright information. */
-/* Kevin Klues <klueska@cs.berkeley.edu>       */
+
+/** @file
+ * @brief Backend file for newlib functionality
+ *
+ * This file is responsible for defining the syscalls needed by newlib to 
+ * impliment the newlib library
+ * *
+ * @author Paul Pearce <pearce@eecs.berkeley.edu>
+ * @author Kevin Klues <klueska@cs.berkeley.edu>
+ *
+ */
 
 #ifdef __DEPUTY__
 #pragma nodeputy
@@ -15,9 +25,6 @@
 #include <debug.h>
 #include <sys/times.h>
 
-#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.
@@ -48,35 +55,28 @@ int close(int file) {
                return 0;
 
        // Allocate a new buffer of proper size
-       char *out_msg = malloc(CLOSE_MESSAGE_FIXED_SIZE);
-       if (out_msg == NULL)
+       msg_t *msg = malloc(sizeof(msg_t));
+       if (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);
-
-
+       
+       msg->id = CLOSE_ID;
+       msg->close.fd = file;
+       
        // Send message
-       char *result = send_message(out_msg, CLOSE_MESSAGE_FIXED_SIZE);
+       response_t *result = send_message(msg, sizeof(msg_t));
 
-       free(out_msg);
+       free(msg);
 
        int return_val;
 
-       if (result != NULL) {
-               // Read result
-               return_val = *((int *) result);
-               if (return_val == -1) errno = *(((int *)result) + 1);
-               free(result);
-       } else {
+       if (result == NULL) {
                errno = ECHANNEL;
                return_val = -1;
+       } else {
+               // Read result
+               return_val = result->ret;
+               if (return_val == -1) errno = result->err;
+               free(result);
        }
        
        return return_val;
@@ -109,53 +109,51 @@ pid_t fork(void)
  * 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 
+ * The sys/stat.h msg 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;
+       // Kevin added this. I believe its needed for the serial branch
+       // Not used with the stdout hack. Review for removing stdout hack.
+       //st->st_mode = S_IFCHR;
        
        // stdout hack
-       if (file == 1)
+       if (file == 1) {
                st->st_mode = 8592;
-       return 0;
+               return 0;
+       }
 
 
-       // Allocate a new buffer of proper size
-       char *out_msg = malloc(FSTAT_MESSAGE_FIXED_SIZE);
-       if(out_msg == NULL)
+       // Allocate a new buffer of proper size 
+       msg_t *msg = malloc(sizeof(msg_t));
+       if (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);
+       
+       msg->id = FSTAT_ID;
+       msg->fstat.fd = file;
 
        // Send message
-       char *result = send_message(out_msg, FSTAT_MESSAGE_FIXED_SIZE);
+       response_t *result = send_message(msg, sizeof(msg_t));
 
-       free(out_msg);
+       free(msg);
 
        // Read result
        int return_val;
 
-       if (result != NULL) {
-               return_val = *((int *)result);
+       if (result == NULL) {
+               errno = ECHANNEL;
+               return_val = -1;
+       } else {
+               return_val = result->ret;
                if (return_val == -1)
-                       errno = *(((char *)result) + 
-                                       sizeof(int) + sizeof(struct stat));
+                       errno = result->err;
                else
-                       memcpy(st, ((int *)result) + 1, sizeof(struct stat));
+                       memcpy(st, (&result->st), sizeof(struct stat));
+                       
                free(result);
-       } else {
-               errno = ECHANNEL;
-               return_val = -1;
        }
 
        return return_val;
@@ -185,37 +183,32 @@ int isatty(int file)
        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)
+       msg_t *msg = malloc(sizeof(msg_t));
+       if (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);
+       
+       msg->id = ISATTY_ID;
+       msg->isatty.fd = file;
 
        // Send message
-       char *result = send_message(out_msg, ISATTY_MESSAGE_FIXED_SIZE);
+       response_t *result = send_message(msg, sizeof(msg_t));
 
-       free(out_msg);
+       free(msg);
 
-       int return_val;
+       int return_val; 
 
-       if (result != NULL) {
-               // Read result
-               return_val = *((int *) result);
-               if (return_val == 0) errno = *(((int *)result) + 1);
-               free(result);
-       } else {
+       // Note: Ret val of 0 defined to be an error, not < 0. Go figure.
+       if (result == NULL) {
                errno = ECHANNEL;
                return_val = 0;
-       }
+       } else {
+               // Read result
+               return_val = result->ret;
+               if (return_val == 0) errno = result->err;
+               free(result);
+       } 
        
        return return_val;
 }
@@ -242,45 +235,32 @@ int link(const char *old, const char *new)
        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)
+       msg_t *msg = malloc(sizeof(msg_t) + s_len_old + s_len_new);
+       if (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);
+       
+       msg->id = LINK_ID;
+       msg->link.old_len = s_len_old;
+       msg->link.new_len = s_len_new;
+       
+       memcpy(msg->link.buf, old, s_len_old);
+       memcpy(msg->link.buf + s_len_old, new, s_len_new);
 
        // Send message
-       char *result = send_message(out_msg, out_msg_len);
+       response_t *result = send_message(msg, sizeof(msg_t) + s_len_old + s_len_new);
 
-       free(out_msg);
+       free(msg);
 
        // Read result
        int return_val;
 
-       if (result != NULL) {
-               return_val = *((int *)result);
-               if (return_val == -1) errno = *(((int *)result) + 1);
-               free(result);
-       } else {
+       if (result == NULL) {
                errno = ECHANNEL;
                return_val = -1;
+       } else {
+               return_val = result->ret;
+               if (return_val == -1) errno = result->err;
+               free(result);
        }
 
        return return_val;
@@ -294,40 +274,31 @@ 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)
+       // Allocate a new buffer of proper size and pack
+       msg_t *msg = malloc(sizeof(msg_t));
+       if (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);
+       
+       msg->id = LSEEK_ID;
+       msg->lseek.fd = file;
+       msg->lseek.ptr = ptr;
+       msg->lseek.dir = dir;
 
        // Send message
-       char *result = send_message(out_msg, LSEEK_MESSAGE_FIXED_SIZE);
+       response_t *result = send_message(msg, sizeof(msg_t));
 
-       free(out_msg);
+       free(msg);
 
        int return_val;
 
-       if (result != NULL) {
-               // Read result
-               return_val = *((int *) result);
-               if (return_val == -1) errno = *(((int *)result) + 1);
-               free(result);
-       } else {
+       if (result == NULL) {
                errno = ECHANNEL;
                return_val = -1;
+       } else {
+               // Read result
+               return_val = result->ret;
+               if (return_val == -1) errno = result->err;
+               free(result);
        }
 
        return return_val;
@@ -341,46 +312,34 @@ 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)
+       msg_t *msg = malloc(sizeof(msg_t) + s_len);
+       if (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);
+       msg->id = OPEN_ID;
+       msg->open.flags = flags;
+       msg->open.mode = mode;
+       msg->open.len = s_len;
 
-       *((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);
+       memcpy(msg->open.buf, name, s_len);
 
        // Send message
-       char *result = send_message(out_msg, out_msg_len);
+       response_t *result = send_message(msg, sizeof(msg_t) + s_len);
 
-       free(out_msg);
+       free(msg);
 
        // Read result
        int return_val;
 
-       if (result != NULL) {
-               return_val = *((int *)result);
-               if (return_val == -1) errno = *(((int *)result) + 1);
-               free(result);
-       } else {
+       if (result == NULL) {
                errno = ECHANNEL;
                return_val = -1;
-       }
+       } else {
+               return_val = result->ret;
+               if (return_val == -1) errno = result->err;
+               free(result);
+       } 
 
        return return_val;
 }
@@ -392,48 +351,41 @@ ssize_t read(int file, void *ptr, size_t len)
 {
        debug_in_out("READ\n");
 
+       // Console hack.
        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)
+       // Allocate a new buffer of proper size and pack
+       msg_t *msg = malloc(sizeof(msg_t));
+       if (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);
-
+       
+       msg->id = READ_ID;
+       msg->read.fd = file;
+       msg->read.len = len;
+       
        // Send message
-       char *result = send_message(out_msg, READ_MESSAGE_FIXED_SIZE);
+       response_t *result = send_message(msg, sizeof(msg_t));
 
-       free(out_msg);
+       free(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 {
+       if (result == NULL) {
                errno = ECHANNEL;
                return_val = -1;
+       } else {
+               return_val = result->ret;
+               if (return_val < 0)
+                       errno = result->err;
+               else
+                       memcpy(ptr, result->buf, return_val);
+
+               free(result);
        }
 
        return return_val;
@@ -451,7 +403,8 @@ int read_from_channel(char * buf, int len, int peek)
        //                      Also, watch out for CONNECTION TERMINATED
        int total_read = 0;
 
-       int just_read = sys_serial_read(buf, len);
+       //int just_read = sys_serial_read(buf, len);
+       int just_read = sys_eth_read(buf, len);
 
 
        if (just_read < 0) return just_read;
@@ -460,8 +413,9 @@ int read_from_channel(char * buf, int len, int peek)
        total_read += just_read;
 
        while (total_read != len) {
-               just_read = sys_serial_read(buf + total_read, len - total_read);
-
+               //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;
        }
@@ -469,6 +423,20 @@ int read_from_channel(char * buf, int len, int peek)
        return total_read;
 }
 
+int read_response_from_channel(response_t *response) 
+{
+       return read_from_channel(       (char*) response, 
+                                                       sizeof(response_t), 
+                                                               NO_PEEK);
+}
+
+int read_buffer_from_channel(char *buf, int len) 
+{
+       return read_from_channel(       buf, 
+                                                       len, 
+                                                               NO_PEEK);
+}
+
 /* sbrk()
  * Increase program data space. 
  * As malloc and related functions depend on this, it is 
@@ -481,7 +449,7 @@ void* sbrk(ptrdiff_t incr)
        debug_in_out("SBRK\n");
        debug_in_out("\tincr: %u\n", incr);     
 
-       #define HEAP_SIZE 8192
+       #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]);
@@ -503,106 +471,54 @@ void* sbrk(ptrdiff_t incr)
  * 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)
+response_t *send_message(msg_t *msg, int len)
 {
-       syscall_id_t this_call_id = *((syscall_id_t*)message);
+       syscall_id_t this_call_id = msg->id;
 
-       if (write_to_channel(message, len) != len)
+       if (write_to_channel(msg, len) != len)
                return NULL;
 
-       int response_value;
+       int ret_value, buffer_size;
+       
+       response_t temp_response;
+       response_t *return_response = NULL;
 
        // Pull the response from the server out of the channel.
-       if (read_from_channel( (char*)&response_value, 
-                               sizeof(int), 
-                               NO_PEEK) == -1) 
+       if (read_response_from_channel( &temp_response ) == -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;
-                        }
+       ret_value = temp_response.ret;
+       
+       char* buffer = NULL;
 
-                       break;
+       if (this_call_id == READ_ID) 
+       {
+               if (ret_value < 0)
+                       buffer_size = 0;
+               else
+                       buffer_size = ret_value;
+                       
+               return_response = malloc(sizeof(response_t) + buffer_size);
 
+               if (return_response == NULL)
+                       return NULL;
+               
+               if (read_buffer_from_channel(return_response->buf, buffer_size) == -1)
+                       return NULL;
+
+       } 
+       else 
+       {
+                       
+               return_response = malloc(sizeof(response_t));
+               
+               if (return_response == NULL)
+                       return NULL;
        }
 
-       // Copy response value in place
-       memcpy(return_msg, &response_value, sizeof(int));
+       *return_response = temp_response;
 
-       return return_msg;
+       return return_response;
 }
 
 
@@ -615,46 +531,38 @@ int stat(const 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)
+       // Allocate a new buffer of proper size and pack
+       msg_t *msg = malloc(sizeof(msg_t) + s_len);
+       if (msg == NULL)
                return -1;
+       
+       msg->id = STAT_ID;
+       msg->stat.len = s_len;
 
-       // 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);
+       memcpy(msg->stat.buf, file, s_len);
 
        // Send message
-       char *result = send_message(out_msg, out_msg_len);
+       response_t *result = send_message(msg, sizeof(msg_t) + s_len);
 
-       free(out_msg);
+       free(msg);
 
        // Read result
        int return_val;
 
-       if (result != NULL) {
-               return_val = *((int *)result);
+       if (result == NULL) {
+               errno = ECHANNEL;
+               return_val = -1;
+       } else {
+               return_val = result->ret;
 
                if (return_val == -1)
-                       errno = *(((char *)result) + sizeof(int) 
-                                                   + sizeof(struct stat));
+                       errno = result->err;
                else
-                       memcpy(st, ((int *)result) + 1, sizeof(struct stat));
+                       memcpy(st, &(result->st), sizeof(struct stat));
 
                free(result);
 
-       } else {
-               errno = ECHANNEL;
-               return_val = -1;
        }
 
        return return_val;
@@ -679,40 +587,34 @@ int unlink(const 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)
+       // Allocate a new buffer of proper size and pack
+       msg_t *msg = malloc(sizeof(msg_t) + s_len);
+       if (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);
+       
+       msg->id = UNLINK_ID;
+       msg->unlink.len = s_len;
+       
+       memcpy(msg->unlink.buf, name, s_len);
 
        // Send message
-       char *result = send_message(out_msg, out_msg_len);
+       response_t *result = send_message(msg, sizeof(msg_t) + s_len);
 
-       free(out_msg);
+       free(msg);
 
        // Read result
        int return_val;
 
-       if (result != NULL) {
-               return_val = *((int *)result);
-               if (return_val == -1) errno = *(((int *)result) + 1);
-               free(result);
-       } else {
+       if (result == NULL) {
                errno = ECHANNEL;
                return_val = -1;
-       }
+       } else {
+               return_val = result->ret;
+               if (return_val == -1) errno = result->err;
+               free(result);
+       } 
+       
        return return_val;
 }
 
@@ -741,40 +643,33 @@ ssize_t write(int file, const void *ptr, size_t len) {
                                    || (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);
+       // Allocate a new buffer of proper size and pack
+       msg_t *msg = malloc(sizeof(msg_t) + len);
+       if (msg == NULL)
+               return -1;
+       
+       msg->id = WRITE_ID;
+       msg->write.fd = file;
+       msg->write.len = len;
 
-       memcpy(out_msg_pos, ptr, len);
+       memcpy(msg->write.buf, ptr, len);
 
        // Send message
-       char *result = send_message(out_msg, out_msg_len);
+       response_t *result = send_message(msg, sizeof(msg_t) + len);
 
-       free(out_msg);
+       free(msg);
 
        // Read result
        int return_val;
 
-       if (result != NULL) {
-               return_val = *((int *)result);
-               if (return_val == -1) errno = *(((int *)result) + 1);
-               free(result);
-       } else {
+       if (result == NULL) {
                errno = ECHANNEL;
                return_val = -1;
-       }
+       } else {
+               return_val = result->ret;
+               if (return_val == -1) errno = result->err;
+               free(result);
+       } 
 
        return return_val;
 }
@@ -783,8 +678,9 @@ ssize_t write(int file, const void *ptr, size_t len) {
 /* write_to_channel()
  * Send a message out over the channel, defined by msg, of length len
  */
-int write_to_channel(char * msg, int len)
+int write_to_channel(msg_t * msg, int len)
 {
-       return sys_serial_write((char*)msg, len);
+       //return sys_serial_write((char*)msg, len);
+       return sys_eth_write((char*)msg, len);
+       
 }
-
index 05142dd..6edf53e 100644 (file)
@@ -51,3 +51,21 @@ ssize_t sys_serial_read(void* buf, size_t len)
 {
        return syscall(SYS_serial_read, (intreg_t)buf, len, 0, 0, 0);
 }
+
+//Run a binary loaded at the specificed address with the specified arguments
+ssize_t sys_run_binary(void* binary_buf, void* arg, size_t len) 
+{
+       return syscall(SYS_run_binary, (intreg_t)binary_buf, (intreg_t)arg, len, 0, 0);
+}
+
+//Write a buffer over ethernet
+ssize_t sys_eth_write(void* buf, size_t len) 
+{
+       return syscall(SYS_eth_write, (intreg_t)buf, len, 0, 0, 0);
+}
+
+//Read a buffer via ethernet
+ssize_t sys_eth_read(void* buf, size_t len) 
+{
+       return syscall(SYS_eth_read, (intreg_t)buf, len, 0, 0, 0);
+}