Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
Peter Dinda [Wed, 2 Mar 2011 21:46:24 +0000 (15:46 -0600)]
27 files changed:
Kconfig
Kconfig.stdlibs
bios/vgabios/vgabios-qemu-0.14.bin [new file with mode: 0644]
palacios/include/palacios/vm_guest.h
palacios/include/palacios/vmm_ethernet.h
palacios/include/palacios/vmm_time.h
palacios/include/palacios/vmm_vnet.h
palacios/include/palacios/vmm_xml.h
palacios/src/devices/8254.c
palacios/src/devices/Kconfig
palacios/src/devices/Makefile
palacios/src/devices/lnx_virtio_nic.c
palacios/src/devices/lnx_virtio_vnet.c
palacios/src/devices/ne2k.c
palacios/src/devices/rtl8139.c [new file with mode: 0644]
palacios/src/devices/vnet_nic.c
palacios/src/palacios/svm.c
palacios/src/palacios/vmm.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_ctrl_regs.c
palacios/src/palacios/vmm_packet.c
palacios/src/palacios/vmm_symbiotic.c
palacios/src/palacios/vmm_time.c
palacios/src/palacios/vmm_vnet_core.c
palacios/src/palacios/vmm_xml.c
palacios/src/palacios/vmx.c
test/geekos_test_vm/build/depend.mak [deleted file]

diff --git a/Kconfig b/Kconfig
index dcee752..45a0568 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -226,14 +226,23 @@ endmenu
 
 menu "Time Management"
 
+config TIME_HIDE_VM_COST
+        bool "Hide VMM Run Cost"
+       default n
+       help
+           Offset guest time from host time sufficiently to hide the cost of
+           running in the virtual machine. This can aid the consistency of
+           time between multiple timers, but can cause the guest to run 
+           a good bit slower than the host in VM-intensive parts of the code.
+
 config TIME_VIRTUALIZE_TSC
-       bool "Virtualize guest TSC"
+       bool "Fully virtualize guest TSC"
        default n
        help
            Virtualize the processor time stamp counter in the guest, 
            generally increasing consistency between various time sources 
            but also potentially making guest time run slower than real time.
-
+        
 endmenu
 
 menu "Symbiotic Functions"
index 09e082a..4fa3315 100644 (file)
@@ -109,7 +109,6 @@ config BUILT_IN_STRNCPY
 
 config BUILT_IN_STRDUP
        bool "strdup()"
-       default n
        depends on BUILT_IN_STDLIB
        help 
          This enables Palacios' internal implementation of strdup
diff --git a/bios/vgabios/vgabios-qemu-0.14.bin b/bios/vgabios/vgabios-qemu-0.14.bin
new file mode 100644 (file)
index 0000000..892a2b5
Binary files /dev/null and b/bios/vgabios/vgabios-qemu-0.14.bin differ
index b435390..8e91634 100644 (file)
@@ -125,6 +125,9 @@ struct guest_info {
 
     /* the logical cpu on which this core runs */
     uint32_t cpu_id;
+    /* the physical cpu on which this core runs */
+    uint32_t host_cpu_id;
+       
 };
 
 
index ddd1435..06dde7b 100644 (file)
 
 #include <palacios/vmm.h>
 
+struct nic_statistics {
+    uint64_t tx_pkts;
+    uint64_t tx_bytes;
+    uint64_t tx_dropped;
+       
+    uint64_t rx_pkts;
+    uint64_t rx_bytes;
+    uint64_t rx_dropped;
+
+    uint32_t interrupts;
+};
+    
 static inline int is_multicast_ethaddr(const uint8_t * addr)
 {
     V3_ASSERT(ETH_ALEN == 6);
@@ -96,6 +108,105 @@ static inline void random_ethaddr(uint8_t * addr)
     addr [0] |= 0x02;  /* set local assignment bit (IEEE802) */
 }
 
+/*-
+ *  CRC32 code derived from work by Gary S. Brown.
+ *
+ *
+ *  First, the polynomial itself and its table of feedback terms.  The
+ *  polynomial is
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ *  Note that we take it "backwards" and put the highest-order term in
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
+ *  the MSB being 1
+ *
+ *  Note that the usual hardware shift register implementation, which
+ *  is what we're using (we're merely optimizing it by doing eight-bit
+ *  chunks at a time) shifts bits into the lowest-order term.  In our
+ *  implementation, that means shifting towards the right.  Why do we
+ *  do it this way?  Because the calculated CRC must be transmitted in
+ *  order from highest-order term to lowest-order term.  UARTs transmit
+ *  characters in order from LSB to MSB.  By storing the CRC this way
+ *  we hand it to the UART in the order low-byte to high-byte; the UART
+ *  sends each low-bit to hight-bit; and the result is transmission bit
+ *  by bit from highest- to lowest-order term without requiring any bit
+ *  shuffling on our part.  Reception works similarly
+ *
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ *
+ *      The table can be generated at runtime if desired; code to do so
+ *      is shown later.  It might not be obvious, but the feedback
+ *      terms simply represent the results of eight shift/xor opera
+ *      tions for all combinations of data and CRC register values
+ *
+ *      The values must be right-shifted by eight bits by the "updcrc
+ *      logic; the shift must be unsigned (bring in zeroes).  On some
+ *      hardware you could probably optimize the shift in assembler by
+ *      using byte-swap instructions
+ *      polynomial $edb88320
+ *
+ *
+ */
+static uint32_t crc32_tab[] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+static inline uint32_t v3_crc32(uint32_t crc, uint8_t *buf, int size)
+{
+    const uint8_t *p;
+
+    p = buf;
+    crc = crc ^ ~0U;
+
+    while (size--){
+       crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+    }
+
+    return crc ^ ~0U;
+}
 
 #endif
 
index 9f1c432..c9248b8 100644 (file)
@@ -7,11 +7,13 @@
  * and the University of New Mexico.  You can find out more at 
  * http://www.v3vee.org
  *
+ * Copyright (c) 2010, Patrick Bridges <bridges@cs.unm.edu>
  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
  * All rights reserved.
  *
  * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *         Patrick Bridges <bridges@cs.unm.edu>
  *
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
@@ -32,15 +34,16 @@ struct guest_info;
 struct vm_time {
     uint32_t host_cpu_freq;    // in kHZ 
     uint32_t guest_cpu_freq;   // can be lower than host CPU freq!
-         
+
     sint64_t guest_host_offset;// Offset of monotonic guest time from host time
     sint64_t tsc_guest_offset; // Offset of guest TSC from monotonic guest time
-    
+
     uint64_t last_update;      // Last time (in monotonic guest time) the 
                                // timers were updated
 
     uint64_t initial_time;     // Time when VMM started. 
-    
+    uint64_t enter_time;       // Host time the guest was last entered
+    uint64_t exit_time;        // Host time the the VM was exited to
     struct v3_msr tsc_aux;     // Auxilliary MSR for RDTSCP
 
     // Installed Timers slaved off of the guest monotonic TSC
@@ -67,9 +70,13 @@ int v3_init_time_vm(struct v3_vm_info * vm);
 void v3_deinit_time_core(struct guest_info * core);
 void v3_deinit_time_vm(struct v3_vm_info * vm);
 
-
 int v3_start_time(struct guest_info * core);
+
+int v3_time_enter_vm(struct guest_info * core);
+int v3_time_exit_vm(struct guest_info * core);
+
 int v3_adjust_time(struct guest_info * core);
+int v3_offset_time(struct guest_info * core, sint64_t offset);
 
 // Basic functions for attaching timers to the passage of time
 struct v3_timer * v3_add_timer(struct guest_info * info, struct v3_timer_ops * ops, void * private_data);
@@ -85,7 +92,12 @@ static inline uint64_t v3_get_host_time(struct vm_time *t) {
 
 // Returns *monotonic* guest time.
 static inline uint64_t v3_get_guest_time(struct vm_time *t) {
+#ifdef CONFIG_TIME_HIDE_VM_COST
+    V3_ASSERT(t->exit_time);
+    return t->exit_time + t->guest_host_offset;
+#else
     return v3_get_host_time(t) + t->guest_host_offset;
+#endif
 }
 
 // Returns the TSC value seen by the guest
index 03d2298..9748674 100644 (file)
 #include <palacios/vmm.h>
 #include <palacios/vmm_ethernet.h>
 
-#define MAC_ANY        0
-#define MAC_NOT        1
-#define MAC_NONE       2 
-#define MAC_ADDR       3
+#define MAC_NOSET      0
+#define MAC_ANY        11
+#define MAC_NOT        12
+#define MAC_NONE       13 
+#define MAC_ADDR       14
 
-#define LINK_INTERFACE         0
-#define LINK_EDGE      1 
-#define LINK_ANY       2
+#define LINK_NOSET     0
+#define LINK_INTERFACE         11
+#define LINK_EDGE      12 
+#define LINK_ANY       13
 
 #define VNET_HASH_SIZE         17
 
@@ -44,10 +46,10 @@ struct v3_vnet_route {
     uint8_t src_mac_qual;
     uint8_t dst_mac_qual;
 
-    uint32_t dst_id;
+    int dst_id;
     uint8_t dst_type;
  
-    uint32_t src_id;
+    int src_id;
     uint8_t src_type;
 } __attribute__((packed));
 
@@ -90,6 +92,7 @@ int v3_vnet_add_bridge(struct v3_vm_info * vm,
                void * priv_data);
 int v3_vnet_add_route(struct v3_vnet_route route);
 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data);
+int v3_vnet_find_dev(uint8_t  * mac);
 
 #ifdef __V3VEE__
 
@@ -101,9 +104,6 @@ struct v3_vnet_dev_ops {
                struct v3_vnet_pkt * pkt, 
                void * dev_data);
     void (*poll) (struct v3_vm_info * vm, void * dev_data);
-
-    void (*start_tx)(void * dev_data);
-    void (*stop_tx)(void * dev_data);
 };
 
 int v3_init_vnet(void);        
index f45f804..16a93cb 100644 (file)
@@ -76,6 +76,8 @@ struct v3_xml * v3_xml_idx(struct v3_xml * xml, int idx);
 const char *v3_xml_attr(struct v3_xml * xml, const char * attr);
 
 
+
+
 // Traverses the v3_xml sturcture to retrieve a specific subtag. Takes a
 // variable length list of tag names and indexes. The argument list must be
 // terminated by either an index of -1 or an empty string tag name. Example: 
@@ -88,4 +90,18 @@ struct v3_xml * v3_xml_get(struct v3_xml * xml, ...);
 // frees the memory allocated for an v3_xml structure
 void v3_xml_free(struct v3_xml * xml);
     
+
+
+
+
+
+char * v3_xml_tostr(struct v3_xml * xml);
+
+struct v3_xml * v3_xml_insert(struct v3_xml * xml, struct v3_xml * dest, size_t off);
+struct v3_xml *  v3_xml_set_txt(struct v3_xml * xml, const char *txt);
+
+
+struct v3_xml * v3_xml_set_attr(struct v3_xml * xml, const char * name, const char * value);
+
+
 #endif // __VMM_XML_H
index 7bf6a8c..4c3a8af 100644 (file)
@@ -299,10 +299,13 @@ static void pit_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullo
        // update counter with remainder (mod reload)
        state->pit_counter = state->pit_reload - cpu_cycles;    
 
-       //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
+       if (oscillations) {
+           PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations);
+       }
+
        if (handle_crystal_tics(state, &(state->ch_0), oscillations) == 1) {
            // raise interrupt
-           PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
+           // PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n");
            v3_raise_irq(info->vm_info, 0);
        }
 
@@ -676,7 +679,7 @@ static int pit_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     // just hardcode the core context
     struct guest_info * info = &(vm->cores[0]);
 
-    uint_t cpu_khz = V3_CPU_KHZ();
+    uint_t cpu_khz = info->time_state.guest_cpu_freq;
     ullong_t reload_val = (ullong_t)cpu_khz * 1000;
 
     pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
index 671625f..873792d 100644 (file)
@@ -3,7 +3,6 @@ menu "Virtual Devices"
 config APIC
        bool "APIC" 
        default y
-       depends on EXPERIMENTAL
        help 
          Includes the Virtual APIC device
 
@@ -19,7 +18,6 @@ config DEBUG_APIC
 
 config IO_APIC
        bool "IOAPIC"
-       depends on EXPERIMENTAL
        default y
        help 
          Includes the Virtual IO APIC
@@ -181,6 +179,19 @@ config DEBUG_NE2K
        help 
          Enable debugging for the NE2K
 
+config RTL8139
+        bool "RTL8139"
+        depends on EXPERIMENTAL
+        default n
+        help
+          Includes the Virtual RTL8139 network card
+
+config DEBUG_RTL8139
+        bool "RTL8139 debugging"
+        default n
+        depends on RTL8139 && DEBUG_ON
+        help
+          Enable debugging for the RTL8139
 
 config NIC_BRIDGE
         bool "Enable Direct Bridge to Host network"
index cdce9ea..2e4a6d6 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_DISK_MODEL) += disk_model.o
 obj-$(CONFIG_NIC_BRIDGE) += nic_bridge.o
 
 obj-$(CONFIG_NE2K) += ne2k.o
+obj-$(CONFIG_RTL8139) += rtl8139.o
 
 obj-$(CONFIG_TMPDISK) += tmpdisk.o
 obj-$(CONFIG_RAMDISK) += ramdisk.o 
index 654698f..da6644e 100644 (file)
 #define PrintDebug(fmt, args...)
 #endif
 
-#define VIRTIO_NET_S_LINK_UP   1       /* Link is up */
 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
 
 
 struct virtio_net_hdr {
        uint8_t flags;
-
-#define VIRTIO_NET_HDR_GSO_NONE                0       /* Not a GSO frame */
+       
        uint8_t gso_type;
        uint16_t hdr_len;               /* Ethernet + IP + tcp/udp hdrs */
        uint16_t gso_size;              /* Bytes to append to hdr_len per frame */
@@ -53,8 +51,6 @@ struct virtio_net_hdr {
 }__attribute__((packed));
 
 
-/* This is the version of the header to use when the MRG_RXBUF
- * feature has been negotiated. */
 struct virtio_net_hdr_mrg_rxbuf {
        struct virtio_net_hdr hdr;
        uint16_t num_buffers;   /* Number of merged rx buffers */
@@ -70,13 +66,8 @@ struct virtio_net_hdr_mrg_rxbuf {
 #define VIRTIO_NET_F_GSO       6       /* Host handles pkts w/ any GSO type */
 #define VIRTIO_NET_F_HOST_TSO4 11      /* Host can handle TSOv4 in. */
 
-/* this is not how virtio supposed to be,
- * we may need a separately implemented virtio_pci
- * In order to make guest to get virtio MAC from host
- * I added it here  -- Lei
- */
- #define VIRTIO_NET_CONFIG 20  
-
+/* Port to get virtio config */
+#define VIRTIO_NET_CONFIG 20  
 
 struct virtio_net_config
 {
@@ -100,14 +91,11 @@ struct virtio_net_state {
     struct pci_device * pci_dev; 
     int io_range_size;
     
-    struct virtio_queue rx_vq;         /* idx 0, pkts to guest */
-    struct virtio_queue tx_vq;         /* idx 1, pkts from guest */
-    struct virtio_queue ctrl_vq;       /* idx 2 */
+    struct virtio_queue rx_vq;         /* idx 0*/
+    struct virtio_queue tx_vq;         /* idx 1*/
+    struct virtio_queue ctrl_vq;       /* idx 2*/
 
-    int buffed_rx;
-    int tx_disabled;                   /* stop TX pkts from guest */
-
-    uint64_t pkt_sent, pkt_recv, pkt_drop;
+    struct nic_statistics statistics;
 
     struct v3_dev_net_ops * net_ops;
     v3_lock_t rx_lock, tx_lock;
@@ -117,16 +105,6 @@ struct virtio_net_state {
     struct list_head dev_link;
 };
 
-/* virtio nic error type */
-#define ERR_VIRTIO_OTHER  1
-#define ERR_VIRTIO_RXQ_FULL  2
-#define ERR_VIRTIO_RXQ_NOSET  3
-#define ERR_VIRTIO_TXQ_NOSET 4
-#define ERR_VIRTIO_TXQ_FULL 5
-#define ERR_VIRTIO_TXQ_DISABLED 6
-
-
-
 
 static int virtio_init_state(struct virtio_net_state * virtio) 
 {
@@ -161,14 +139,10 @@ static int virtio_init_state(struct virtio_net_state * virtio)
         PrintError("Virtio NIC: Failure to init locks for net_state\n");
     }
 
-    virtio->pkt_sent = virtio->pkt_recv = virtio->pkt_drop = 0;
-    virtio->buffed_rx = 0;
-
     return 0;
 }
 
-static int 
-pkt_tx(struct guest_info * core, 
+static int tx_one_pkt(struct guest_info * core, 
        struct virtio_net_state * virtio, 
        struct vring_desc * buf_desc) 
 {
@@ -176,11 +150,20 @@ pkt_tx(struct guest_info * core,
     uint32_t len = buf_desc->length;
 
     if (v3_gpa_to_hva(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
-       PrintError("Could not translate buffer address\n");
-       return -ERR_VIRTIO_OTHER;
+       PrintDebug("Could not translate buffer address\n");
+       return -1;
+    }
+
+    if(virtio->net_ops->send(buf, len, virtio->backend_data) >= 0){
+       virtio->statistics.tx_pkts ++;
+       virtio->statistics.tx_bytes += len;
+
+       return 0;
     }
 
-    return virtio->net_ops->send(buf, len, virtio->backend_data);
+    virtio->statistics.tx_dropped ++;
+
+    return -1;
 }
 
 
@@ -227,52 +210,37 @@ static inline void disable_cb(struct virtio_queue *queue) {
 }
 
 
-/* interrupt the guest, so the guest core get EXIT to Palacios
- * this happens when there are either incoming pkts for the guest
- * or the guest can start TX pkts again */
+/* interrupt the guest, so the guest core get EXIT to Palacios */
 static inline void notify_guest(struct virtio_net_state * virtio){
     v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].cpu_id, 0);
 }
 
 
-/* guest free some pkts from rx queue */
-static int handle_rx_kick(struct guest_info *core, 
+/* guest free some pkts for rx queue */
+static int handle_rx_queue_kick(struct guest_info * core, 
                          struct virtio_net_state * virtio) 
 {
-    unsigned long flags;
-
-    flags = v3_lock_irqsave(virtio->rx_lock);
-
-    if(virtio->net_ops->start_rx != NULL){
-       virtio->net_ops->start_rx(virtio->backend_data);
-    }
-       //disable_cb(&virtio->rx_vq);
-
-    v3_unlock_irqrestore(virtio->rx_lock, flags);
-       
     return 0;
 }
 
 
-static int handle_ctrl(struct guest_info *core, 
+static int handle_ctrl(struct guest_info * core, 
                       struct virtio_net_state * virtio) {
        
     return 0;
 }
 
-static int handle_pkt_tx(struct guest_info *core, 
+static int handle_pkt_tx(struct guest_info * core, 
                         struct virtio_net_state * virtio_state) 
 {
-    struct virtio_queue * q = &(virtio_state->tx_vq);
-    struct virtio_net_hdr * hdr = NULL;
-    int recved = 0;
+    struct virtio_queue *q = &(virtio_state->tx_vq);
+    struct virtio_net_hdr *hdr = NULL;
+    int txed = 0;
     unsigned long flags;
 
-    if (!q->ring_avail_addr) 
-       return -ERR_VIRTIO_TXQ_NOSET;
-
-    if(virtio_state->tx_disabled)
-       return -ERR_VIRTIO_TXQ_DISABLED;
+    if (!q->ring_avail_addr) {
+       return -1;
+    }
 
     flags = v3_lock_irqsave(virtio_state->tx_lock);
     while (q->cur_avail_idx != q->avail->index) {
@@ -289,7 +257,7 @@ static int handle_pkt_tx(struct guest_info *core,
            goto exit_error;
        }
 
-       hdr = (struct virtio_net_hdr*)hdr_addr;
+       hdr = (struct virtio_net_hdr *)hdr_addr;
        desc_idx = hdr_desc->next;
 
        if(desc_cnt > 2){
@@ -300,7 +268,7 @@ static int handle_pkt_tx(struct guest_info *core,
        /* here we assumed that one ethernet pkt is not splitted into multiple virtio buffer */
        for (i = 0; i < desc_cnt - 1; i++) {    
            struct vring_desc * buf_desc = &(q->desc[desc_idx]);
-           if (pkt_tx(core, virtio_state, buf_desc) == -1) {
+           if (tx_one_pkt(core, virtio_state, buf_desc) == -1) {
                PrintError("Error handling nic operation\n");
                goto exit_error;
            }
@@ -308,24 +276,23 @@ static int handle_pkt_tx(struct guest_info *core,
            req_len += buf_desc->length;
            desc_idx = buf_desc->next;
        }
-       virtio_state->pkt_sent ++;
-       recved ++;
 
        q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
-       q->used->ring[q->used->index % q->queue_size].length = req_len; // What do we set this to????
+       q->used->ring[q->used->index % q->queue_size].length = req_len; /* What do we set this to???? */
        q->used->index ++;
        
        q->cur_avail_idx ++;
+
+       txed ++;
     }
 
     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
-
-    if(!recved)
-       return 0;
        
-    if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
+    if (txed && !(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 0, virtio_state->pci_dev);
        virtio_state->virtio_cfg.pci_isr = 0x1;
+
+       virtio_state->statistics.interrupts ++;
     }
 
     return 0;
@@ -333,7 +300,7 @@ static int handle_pkt_tx(struct guest_info *core,
 exit_error:
        
     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
-    return -ERR_VIRTIO_OTHER;
+    return -1;
 }
 
 
@@ -407,11 +374,9 @@ static int virtio_io_write(struct guest_info *core,
            switch (queue_idx) {
                case 0:
                    virtio_setup_queue(core, virtio, &virtio->rx_vq, pfn, page_addr);
-                   //disable_cb(&virtio->rx_vq);
                    break;
                case 1:
                    virtio_setup_queue(core, virtio, &virtio->tx_vq, pfn, page_addr);
-                   //disable_cb(&virtio->tx_vq);
                    break;
                case 2:
                    virtio_setup_queue(core, virtio, &virtio->ctrl_vq, pfn, page_addr);
@@ -434,15 +399,18 @@ static int virtio_io_write(struct guest_info *core,
            {
                uint16_t queue_idx = *(uint16_t *)src;                  
                if (queue_idx == 0){
-                   handle_rx_kick(core, virtio);
+                   if(handle_rx_queue_kick(core, virtio) == -1){
+                       PrintError("Could not handle Virtio NIC rx kick\n");
+                       return -1;
+                   }
                } else if (queue_idx == 1){
                    if (handle_pkt_tx(core, virtio) == -1) {
-                       PrintError("Could not handle NIC Notification\n");
+                       PrintError("Could not handle Virtio NIC tx kick\n");
                        return -1;
                    }
                } else if (queue_idx == 2){
                    if (handle_ctrl(core, virtio) == -1) {
-                       PrintError("Could not handle NIC Notification\n");
+                       PrintError("Could not handle Virtio NIC ctrl kick\n");
                        return -1;
                    }
                } else {
@@ -454,7 +422,6 @@ static int virtio_io_write(struct guest_info *core,
        case VIRTIO_STATUS_PORT:
            virtio->virtio_cfg.status = *(uint8_t *)src;
            if (virtio->virtio_cfg.status == 0) {
-               PrintDebug("Resetting device\n");
                virtio_init_state(virtio);
            }
            break;
@@ -558,39 +525,29 @@ static int virtio_io_read(struct guest_info *core,
 }
 
 
+/* receiving raw ethernet pkt from backend */
 static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
     struct virtio_queue * q = &(virtio->rx_vq);
     struct virtio_net_hdr_mrg_rxbuf hdr;
     uint32_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
-    uint32_t data_len = size;
+    uint32_t data_len;
     uint32_t offset = 0;
     unsigned long flags;
-    int ret_val = -ERR_VIRTIO_OTHER;
-    int raw = 1;
 
 #ifndef CONFIG_DEBUG_VIRTIO_NET
-   {
-       PrintDebug("Virtio-NIC: virtio_rx: size: %d\n", size);  
-       //v3_hexdump(buf, size, NULL, 0);
-   }
+    PrintDebug("Virtio-NIC: virtio_rx: size: %d\n", size);     
+    v3_hexdump(buf, size, NULL, 0);
 #endif
 
     flags = v3_lock_irqsave(virtio->rx_lock);
 
-    virtio->pkt_recv ++;
-    if (!raw)
-       data_len -= hdr_len;
-
-    if (!raw)
-        memcpy(&hdr, buf, sizeof(struct virtio_net_hdr_mrg_rxbuf));
-    else
-        memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf));
+    data_len = size;
+    memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf));
 
     if (q->ring_avail_addr == 0) {
-       PrintError("Queue is not set\n");
-       ret_val = -ERR_VIRTIO_RXQ_NOSET;
-       goto exit;
+       PrintDebug("Queue is not set\n");
+       goto err_exit;
     }
 
     if (q->cur_avail_idx != q->avail->index){
@@ -601,8 +558,8 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
 
        hdr_desc = &(q->desc[hdr_idx]);
        if (v3_gpa_to_hva(&(virtio->virtio_dev->vm->cores[0]), hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
-           PrintError("Could not translate receive buffer address\n");
-           goto exit;
+           PrintDebug("Could not translate receive buffer address\n");
+           goto err_exit;
        }
        hdr.num_buffers = 1;
        memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr_mrg_rxbuf));
@@ -629,39 +586,31 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
        q->used->index++;
        q->cur_avail_idx++;
 
-       /* if there are certain num of pkts in the RX queue, notify guest 
-         * so guest will exit to palacios
-         * when it returns, guest gets the virtio rx interrupt */
-       if((++virtio->buffed_rx > q->queue_size/5) &&
-           (q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
-           if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
-                 notify_guest(virtio);
-           }
-           virtio->buffed_rx = 0;
-       }
+       virtio->statistics.rx_pkts ++;
+       virtio->statistics.rx_bytes += size;
     } else {
-       virtio->pkt_drop++;
-       /* RX queue is full,  tell backend to stop RX on this device */
-       virtio->net_ops->stop_rx(virtio->backend_data);
-       enable_cb(&virtio->rx_vq);
+       virtio->statistics.rx_dropped ++;
        
-       ret_val = -ERR_VIRTIO_RXQ_FULL;
-       goto exit;
+       goto err_exit;
     }
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
+       
        v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
        virtio->virtio_cfg.pci_isr = 0x1;
+       virtio->statistics.interrupts ++;
     }
 
-    ret_val = offset;
+    v3_unlock_irqrestore(virtio->rx_lock, flags);
+
+    return 0;
 
-exit:
+err_exit:
 
     v3_unlock_irqrestore(virtio->rx_lock, flags);
  
-    return ret_val;
+    return -1;
 }
 
 static int virtio_free(struct virtio_dev_state * virtio) {
@@ -687,45 +636,12 @@ static struct v3_device_ops dev_ops = {
 };
 
 
-/* TODO: Issue here: which vm info it needs? calling VM or the device's own VM? */
 static void virtio_nic_poll(struct v3_vm_info * vm, void * data){
     struct virtio_net_state * virtio = (struct virtio_net_state *)data;
        
     handle_pkt_tx(&(vm->cores[0]), virtio);
 }
 
-static void virtio_start_tx(void * data){
-    struct virtio_net_state * virtio = (struct virtio_net_state *)data;
-    unsigned long flags;
-
-    flags = v3_lock_irqsave(virtio->tx_lock);
-    virtio->tx_disabled = 0;
-
-    /* notify the device's guest to start sending pkt */
-    if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
-       notify_guest(virtio);
-    }
-    v3_unlock_irqrestore(virtio->tx_lock, flags);      
-}
-
-static void virtio_stop_tx(void * data){
-    struct virtio_net_state * virtio = (struct virtio_net_state *)data;
-    unsigned long flags;
-
-    flags = v3_lock_irqsave(virtio->tx_lock);
-    virtio->tx_disabled = 1;
-
-    /* stop the guest to exit to palacios for sending pkt? */
-    if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
-       disable_cb(&virtio->tx_vq);
-    }
-
-    v3_unlock_irqrestore(virtio->tx_lock, flags);
-}
-
-       
-
-
 static int register_dev(struct virtio_dev_state * virtio, 
                        struct virtio_net_state * net_state) 
 {
@@ -742,8 +658,9 @@ static int register_dev(struct virtio_dev_state * virtio,
        net_state->io_range_size <<= 1;
     }
        
-    // this is to account for any low order bits being set in num_ports
-    // if there are none, then num_ports was already a power of 2 so we shift right to reset it
+    /* this is to account for any low order bits being set in num_ports
+      * if there are none, then num_ports was already a power of 2 so we shift right to reset it
+      */
     if ((num_ports & ((net_state->io_range_size >> 1) - 1)) == 0) {
        net_state->io_range_size >>= 1;
     }
@@ -815,8 +732,6 @@ static int connect_fn(struct v3_vm_info * info,
 
     ops->recv = virtio_rx;
     ops->poll = virtio_nic_poll;
-    ops->start_tx = virtio_start_tx;
-    ops->stop_tx = virtio_stop_tx;
     ops->frontend_data = net_state;
     memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN);
 
index 9e10784..b4b7342 100644 (file)
@@ -75,7 +75,6 @@ struct virtio_vnet_state {
 #define VNET_ADD_LINK 21
 #define VNET_DEL_LINK 22
 
-// structure of the vnet command header
 struct vnet_ctrl_hdr {
     uint8_t cmd_type;
     uint32_t num_cmds;
@@ -123,8 +122,6 @@ static int get_desc_count(struct virtio_queue * q, int index) {
 }
 
 
-
-
 static int handle_cmd_kick(struct guest_info * core, 
                           struct virtio_vnet_state * vnet_state) {
     struct virtio_queue * q = &(vnet_state->queue[0]);
@@ -143,7 +140,6 @@ static int handle_cmd_kick(struct guest_info * core,
        uint8_t * status_ptr = NULL;
        uint8_t status = 0;
 
-
        PrintDebug("VNET Bridge: CMD: Descriptor Count=%d, index=%d, desc_idx=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE, desc_idx);
 
        if (desc_cnt < 3) {
@@ -160,8 +156,7 @@ static int handle_cmd_kick(struct guest_info * core,
 
        desc_idx = hdr_desc->next;
        
-       if (hdr->cmd_type == VNET_ADD_ROUTE) {
-           
+       if (hdr->cmd_type == VNET_ADD_ROUTE) {   
            for (i = 0; i < hdr->num_cmds; i++) {
                uint8_t tmp_status = 0;
                struct v3_vnet_route * route = NULL;
@@ -173,26 +168,21 @@ static int handle_cmd_kick(struct guest_info * core,
                    return -1;
                }
 
-               // add route
-               PrintDebug("VNET Bridge: Adding VNET Route\n");
-
                tmp_status = v3_vnet_add_route(*route);
-
-               PrintDebug("VNET Route Added\n");
-
                if (tmp_status != 0) {
                    PrintError("Error adding VNET ROUTE\n");
+                       
                    status = tmp_status;
                }
 
+               PrintDebug("VNET Route Added\n");
+
                xfer_len += buf_desc->length;
                desc_idx = buf_desc->next;
            }
 
        } 
 
-
-
        status_desc = &(q->desc[desc_idx]);
 
        if (v3_gpa_to_hva(core, status_desc->addr_gpa, (addr_t *)&status_ptr) == -1) {
@@ -235,6 +225,7 @@ static int vnet_pkt_input_cb(struct v3_vm_info * vm,
        
     if (q->ring_avail_addr == 0) {
        PrintError("Queue is not set\n");
+       
        goto exit;
     }
 
@@ -244,7 +235,6 @@ static int vnet_pkt_input_cb(struct v3_vm_info * vm,
        struct vnet_bridge_pkt * virtio_pkt = NULL;
 
        pkt_desc = &(q->desc[pkt_idx]);
-       PrintDebug("VNET Bridge RX: buffer desc len: %d\n", pkt_desc->length);
 
        if (v3_gpa_to_hva(&(vm->cores[0]), pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
            PrintError("Could not translate buffer address\n");
@@ -282,7 +272,7 @@ exit:
     return ret_val;
 }
 
-static int handle_pkt_kick(struct guest_info * core, 
+static int do_tx_pkts(struct guest_info * core, 
                           struct virtio_vnet_state * vnet_state) 
 {
     struct virtio_queue * q = &(vnet_state->queue[XMIT_QUEUE]);
@@ -298,8 +288,6 @@ static int handle_pkt_kick(struct guest_info * core,
        struct vnet_bridge_pkt * virtio_pkt = NULL;
 
        pkt_desc = &(q->desc[desc_idx]);
-
-       PrintDebug("VNET Bridge: Handle TX desc buf_len: %d\n", pkt_desc->length);
        
        if (v3_gpa_to_hva(core, pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
            PrintError("Could not translate buffer address\n");
@@ -343,15 +331,13 @@ static void vnet_virtio_poll(struct v3_vm_info * vm, void * private_data){
     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
 
     if(vm == vnet_state->vm){  
-       handle_pkt_kick(&(vm->cores[0]), vnet_state);
+       do_tx_pkts(&(vm->cores[0]), vnet_state);
     }
 }
 
-static int handle_rx_kick(struct guest_info *core, 
+static int handle_rx_queue_kick(struct guest_info *core, 
                          struct virtio_vnet_state * vnet_state) 
-{
-    //v3_vnet_enable_bridge();
-       
+{      
     return 0;
 }
 
@@ -451,13 +437,13 @@ static int vnet_virtio_io_write(struct guest_info * core,
                    return -1;
                }
            } else if (queue_idx == 1) {
-               if (handle_pkt_kick(core, vnet_state) == -1){
+               if (do_tx_pkts(core, vnet_state) == -1){
                    PrintError("Could not handle Virtio VNET TX\n");
                    return -1;
                }
                PrintError("Notify on TX\n");
            } else if (queue_idx == 2) {
-               if (handle_rx_kick(core, vnet_state) == -1){
+               if (handle_rx_queue_kick(core, vnet_state) == -1){
                    PrintError("Could not handle Virtio RX buffer refills Kick\n");
                    return -1;
                }
index 46594c3..939bd28 100644 (file)
 #define NE2K_MEM_SIZE           NE2K_PMEM_END
 
 #define NIC_REG_BASE_PORT       0xc100         /* Command register (for all pages) */
-#define NIC_DATA_PORT          0xc110          /* Data read/write port */
-#define NIC_RESET_PORT                 0xc11f          /* Reset port */
+
+#define NE2K_CMD_OFFSET        0x00
+#define NE2K_DATA_OFFSET       0x10
+#define NE2K_RESET_OFFSET      0x1f
 
 /* Page 0 registers */
 #define EN0_CLDALO             0x01    /* Low byte of current local dma addr  RD */
@@ -319,6 +321,8 @@ struct ne2k_state {
     uint8_t mcast_addr[8];
     uint8_t mac[ETH_ALEN];
 
+    struct nic_statistics statistics;
+
     struct v3_dev_net_ops *net_ops;
     void * backend_data;
 };
@@ -333,20 +337,31 @@ static int ne2k_update_irq(struct ne2k_state * nic_state) {
            v3_pci_raise_irq(nic_state->pci_bus, 0, nic_state->pci_dev);
        }
 
+       nic_state->statistics.interrupts ++;
+
        PrintDebug("NE2000: Raise IRQ\n");
     }
 
     return 0;
 }
 
-static int ne2k_send_packet(struct ne2k_state * nic_state, uchar_t *pkt, uint32_t length) {
+static int tx_one_pkt(struct ne2k_state * nic_state, uchar_t *pkt, uint32_t length) {
        
 #ifdef CONFIG_DEBUG_NE2K
     PrintDebug("NE2000: Send Packet:\n");
     v3_hexdump(pkt, length, NULL, 0);
 #endif    
 
-    return nic_state->net_ops->send(pkt, length, nic_state->backend_data);
+    if(nic_state->net_ops->send(pkt, length, nic_state->backend_data) >= 0){
+       nic_state->statistics.tx_pkts ++;
+       nic_state->statistics.tx_bytes += length;
+
+       return 0;
+    }
+       
+    nic_state->statistics.tx_dropped ++;
+
+    return -1;
 }
 
 static int ne2k_rxbuf_full(struct ne2k_registers * regs) {
@@ -475,9 +490,14 @@ static int ne2k_rx(uint8_t * buf, uint32_t size, void * private_data){
 #endif    
 
     if(!rx_one_pkt(nic_state, buf, size)){
+       nic_state->statistics.rx_pkts ++;
+       nic_state->statistics.rx_bytes += size;
+       
        return 0;
     }
-    
+
+    nic_state->statistics.rx_dropped ++;
+       
     return -1;
 }
 
@@ -717,7 +737,7 @@ static int ne2k_cmd_write(struct guest_info * core,
            }
 
            if (offset + regs->tbcr <= NE2K_PMEM_END) {
-               ne2k_send_packet(nic_state, nic_state->mem + offset, regs->tbcr);
+               tx_one_pkt(nic_state, nic_state->mem + offset, regs->tbcr);
            }
 
            regs->tsr.val = 0;        /* clear the tx status reg */
@@ -1015,16 +1035,16 @@ static int ne2k_pci_write(struct guest_info * core,
     int ret;
 
     switch (idx) {
-       case NIC_REG_BASE_PORT:
+       case NE2K_CMD_OFFSET:
            ret =  ne2k_cmd_write(core, port, src, length, private_data);
            break;
-       case NIC_REG_BASE_PORT+1 ... NIC_REG_BASE_PORT+15:
+       case NE2K_CMD_OFFSET+1 ... NE2K_CMD_OFFSET+15:
            ret = ne2k_std_write(core, port, src, length, private_data);
            break;
-       case NIC_DATA_PORT:
+       case NE2K_DATA_OFFSET:
            ret = ne2k_data_write(core, port, src, length, private_data);
            break;
-       case NIC_RESET_PORT:
+       case NE2K_RESET_OFFSET:
            ret = ne2k_reset_port_write(core, port, src, length, private_data);
            break;
 
@@ -1045,16 +1065,16 @@ static int ne2k_pci_read(struct guest_info * core,
     int ret;
 
     switch (idx) {
-       case NIC_REG_BASE_PORT:
+       case NE2K_CMD_OFFSET:
            ret =  ne2k_cmd_read(core, port, dst, length, private_data);
            break;
-       case NIC_REG_BASE_PORT+1 ... NIC_REG_BASE_PORT+15:
+       case NE2K_CMD_OFFSET+1 ... NE2K_CMD_OFFSET+15:
            ret = ne2k_std_read(core, port, dst, length, private_data);
            break;
-       case NIC_DATA_PORT:
+       case NE2K_DATA_OFFSET:
            ret = ne2k_data_read(core, port, dst, length, private_data);
            break;
-       case NIC_RESET_PORT:
+       case NE2K_RESET_OFFSET:
            ret = ne2k_reset_port_read(core, port, dst, length, private_data);
            break;
 
@@ -1133,8 +1153,8 @@ static int register_dev(struct ne2k_state * nic_state)
            v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT + i, &ne2k_std_read, &ne2k_std_write);
        }
 
-       v3_dev_hook_io(nic_state->dev, NIC_DATA_PORT, &ne2k_data_read, &ne2k_data_write);
-       v3_dev_hook_io(nic_state->dev, NIC_RESET_PORT, &ne2k_reset_port_read, &ne2k_reset_port_write);
+       v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT + NE2K_DATA_OFFSET, &ne2k_data_read, &ne2k_data_write);
+       v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT + NE2K_RESET_OFFSET, &ne2k_reset_port_read, &ne2k_reset_port_write);
     }
 
 
@@ -1175,13 +1195,11 @@ static int ne2k_free(struct ne2k_state * nic_state) {
            v3_dev_unhook_io(nic_state->dev, NIC_REG_BASE_PORT + i);
        }
     
-       v3_dev_unhook_io(nic_state->dev, NIC_DATA_PORT);
-       v3_dev_unhook_io(nic_state->dev, NIC_RESET_PORT);
+       v3_dev_unhook_io(nic_state->dev, NIC_REG_BASE_PORT + NE2K_DATA_OFFSET);
+       v3_dev_unhook_io(nic_state->dev, NIC_REG_BASE_PORT + NE2K_RESET_OFFSET);
     }else {
        /* unregistered from PCI? */
     }
-  
-    return 0;
 
     V3_Free(nic_state);
        
diff --git a/palacios/src/devices/rtl8139.c b/palacios/src/devices/rtl8139.c
new file mode 100644 (file)
index 0000000..199d0d7
--- /dev/null
@@ -0,0 +1,1843 @@
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2011, Lei Xia <lxia@northwestern.edu> 
+ * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author:  Lei Xia <lxia@northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <devices/pci.h>
+#include <palacios/vmm.h>
+#include <palacios/vmm_types.h>
+#include <palacios/vmm_io.h>
+#include <palacios/vmm_debug.h>
+#include <palacios/vm_guest_mem.h>
+#include <palacios/vmm_ethernet.h>
+#include <palacios/vmm_sprintf.h>
+
+
+
+#ifndef CONFIG_DEBUG_RTL8139
+#undef PrintDebug
+#define PrintDebug(fmts, args...)
+#endif
+
+#define RTL8139_IDR0    (0x00) /* ID Registers start, len 6*1bytes */
+#define RTL8139_MAR0    (0x08) /* Mulicast Registers start, len 8*1bytes */
+
+#define RTL8139_TSD0    (0x10) /* Tx Status of Descriptors */
+#define RTL8139_TSD1    (0x14)
+#define RTL8139_TSD2    (0x18)
+#define RTL8139_TSD3    (0x1c)
+
+#define RTL8139_TSAD0   (0x20) /* Tx Start Address of Descriptors */
+#define RTL8139_TSAD1   (0x24)
+#define RTL8139_TSAD2   (0x28)
+#define RTL8139_TSAD3   (0x2c)
+
+#define RTL8139_RBSTART (0x30) /* Rx Buffer Start Address */
+#define RTL8139_ERBCR   (0x34) /* Early Rx Byte Count Register */
+#define RTL8139_ERSR    (0x36) /* Early Rx Status Register */
+#define RTL8139_CR      (0x37) /* Command Register */
+#define RTL8139_CAPR    (0x38) /* Current Address of Pkt Read */
+#define RTL8139_CBR     (0x3a) /* Current Buffer Address */
+#define RTL8139_IMR     (0x3c) /* Intrpt Mask Reg */
+#define RTL8139_ISR     (0x3e) /* Intrpt Status Reg */
+#define RTL8139_TCR     (0x40) /* Tx Config Reg */
+#define RTL8139_RCR     (0x44) /* Rx Config Reg */
+#define RTL8139_TCTR    (0x48) /* Timer Count Reg */
+#define RTL8139_MPC     (0x4c) /* Missed Pkt Counter */
+#define RTL8139_9346CR  (0x50) /* 9346 Command Reg */
+#define RTL8139_CONFIG0 (0x51) /* Config Reg */
+#define RTL8139_CONFIG1 (0x52)
+#define RTL8139_TimerInt    (0x54)     /* Timer Intrpt Reg */
+#define RTL8139_MSR     (0x58) /* Media Status Reg */
+#define RTL8139_CONFIG3 (0x59) 
+#define RTL8139_CONFIG4 (0x5a)
+#define RTL8139_MULINT  (0x5c) /* Multiple Intrpt Select */
+#define RTL8139_RERID   (0x5e) 
+#define RTL8139_TXSAD    (0x60)        /* Tx Status of All Descriptors */
+#define RTL8139_BMCR    (0x62) /* Basic Mode Control Register */
+#define RTL8139_BMSR    (0x64) /* Basic Mode Status Register */
+#define RTL8139_ANAR    (0x66) /* Auto-Negotiation Advertisement Register */
+#define RTL8139_ANLPAR  (0x68) /* Auto-Negotiation Link Partner Register */
+#define RTL8139_ANER    (0x6a) /* Auto-Negotiation Expansion Register */
+#define RTL8139_DIS     (0x6c) /* Disconnect Counter */
+#define RTL8139_FCSC    (0x6e) /* False Carrier Sense Counter */
+#define RTL8139_NWAYTR  (0x70) /* N-way Test Register */
+#define RTL8139_REC     (0x72) /* RX ER Counter */
+#define RTL8139_CSCR    (0x74) /* CS Config Register */
+#define RTL8139_PHY1_PARM   (0x78)     /* PHY parameter */
+#define RTL8139_TW_PARM (0x7c) /* Twister parameter */
+#define RTL8139_PHY2_PARM   (0x80)
+
+#define RTL8139_CRC0    (0x84) /* Power Management CRC Reg for wakeup frame 8*1bytes */
+
+#define RTL8139_Wakeup0        (0x8c)  /* Power Management wakeup frame */
+#define RTL8139_Wakeup1        (0x94)
+#define RTL8139_Wakeup2        (0x9c)
+#define RTL8139_Wakeup3        (0xa4)
+#define RTL8139_Wakeup4        (0xac)
+#define RTL8139_Wakeup5        (0xb4)
+#define RTL8139_Wakeup6        (0xbc)
+#define RTL8139_Wakeup7        (0xc4)
+
+#define RTL8139_LSBCRO0 (0xcc) /* LSB of the mask byte of wakeup frame */
+#define RTL8139_LSBCRO1 (0xcd)
+#define RTL8139_LSBCRO2 (0xce)
+#define RTL8139_LSBCRO3 (0xcf)
+#define RTL8139_LSBCRO4 (0xd0)
+#define RTL8139_LSBCRO5 (0xd1)
+#define RTL8139_LSBCRO6 (0xd2)
+#define RTL8139_LSBCRO7 (0xd3)
+
+#define RTL8139_Config5 (0xd8)
+
+/* Interrupts */
+#define PKT_RX      0x0001
+#define RX_ERR      0x0002
+#define TX_OK       0x0004
+#define TX_ERR      0x0008
+#define RX_BUFF_OF  0x0010
+#define RX_UNDERRUN 0x0020
+#define RX_FIFO_OF  0x0040
+#define CABLE_LEN_CHNG  0x2000
+#define TIME_OUT    0x4000
+#define SERR        0x8000
+
+#define DESC_SIZE 2048
+#define TX_FIFO_SIZE (DESC_SIZE * 4)
+#define RX_FIFO_SIZE (DESC_SIZE * 4)
+
+typedef enum {NIC_READY, NIC_REG_POSTED} nic_state_t;
+
+enum TxStatusBits {
+    TSD_Own = 1<<13,
+    TSD_Tun = 1<<14,
+    TSD_Tok = 1<<15,
+    TSD_Cdh = 1<<28,
+    TSD_Owc = 1<<29,
+    TSD_Tabt = 1<<30,
+    TSD_Crs = 1<<31,
+};
+
+/* Transmit Status Register (TSD0-3) Offset: 0x10-0x1F */
+struct tx_status_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint16_t size     : 13;
+           uint8_t own     : 1;
+           uint8_t tun     : 1;
+           uint8_t tok     : 1;        
+           uint8_t er_tx_th   : 6;
+           uint8_t reserved    : 2;
+           uint8_t ncc            : 4;
+           uint8_t cdh : 1;
+           uint8_t owc : 1;
+           uint8_t tabt        : 1;
+           uint8_t crs : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+enum RxStatusBits {
+    Rx_Multicast = 1<<15,
+    Rx_Physical = 1<<14,
+    Rx_Broadcast = 1<<13,
+    Rx_BadSymbol = 1<<5,
+    Rx_Runt = 1<<4,
+    Rx_TooLong = 1<<3,
+    Rx_CRCErr = 1<<2,
+    Rx_BadAlign = 1<<1,
+    Rx_OK = 1<<0,
+};
+
+
+/* Receive Status Register in RX Packet Header */
+struct rx_status_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t rx_ok     : 1;
+           uint8_t rx_bad_align     : 1;
+           uint8_t rx_crc_err     : 1;
+           uint8_t rx_too_long     : 1;        
+           uint8_t rx_runt     : 1;
+           uint8_t rx_bad_sym  : 1;
+           uint8_t reserved    : 7;
+           uint8_t rx_brdcast  : 1;
+           uint8_t rx_phys     : 1;
+           uint8_t rx_multi    : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+/* ERSR - Early Rx Status Register Offset: 0x36*/
+struct errx_status_reg{
+    union {
+       uint8_t val;
+       struct {
+           uint8_t er_rx_ok     : 1;
+           uint8_t er_rx_ovw     : 1;
+           uint8_t er_rx_bad_pkt     : 1;
+           uint8_t er_rx_good     : 1; 
+           uint8_t reserved    : 4;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+/* Transmit Status of All Descriptors (TSAD) Register */
+enum TSAD_bits {
+    TSAD_TOK3 = 1<<15, /* TOK bits of Descriptors*/
+    TSAD_TOK2 = 1<<14, 
+    TSAD_TOK1 = 1<<13, 
+    TSAD_TOK0 = 1<<12, 
+    TSAD_TUN3 = 1<<11, /* TUN bits of Descriptors */
+    TSAD_TUN2 = 1<<10, 
+    TSAD_TUN1 = 1<<9, 
+    TSAD_TUN0 = 1<<8,
+    TSAD_TABT3 = 1<<7, /* TABT bits of Descriptors */
+    TSAD_TABT2 = 1<<6,
+    TSAD_TABT1 = 1<<5,
+    TSAD_TABT0 = 1<<4,
+    TSAD_OWN3 = 1<<3, /* OWN bits of Descriptors */
+    TSAD_OWN2 = 1<<2,
+    TSAD_OWN1 = 1<<1, 
+    TSAD_OWN0 = 1<<0,
+};
+
+
+/* Transmit Status of All Descriptors (TSAD) Register Offset: 0x60-0x61*/
+struct txsad_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t own0     : 1;
+           uint8_t own1     : 1;
+           uint8_t own2     : 1;
+           uint8_t own3     : 1;       
+           uint8_t tabt0       : 1;
+           uint8_t tabt1       : 1;
+           uint8_t tabt2       : 1;
+           uint8_t tabt3       : 1;
+           uint8_t tun0        : 1;
+           uint8_t tun1        : 1;
+           uint8_t tun2        : 1;
+           uint8_t tun3        : 1;
+           uint8_t tok0        : 1;
+           uint8_t tok1        : 1;
+           uint8_t tok2        : 1;
+           uint8_t tok3        : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+enum ISRBits {
+    ISR_Rok = 1<<0,
+    ISR_Rer = 1<<1,
+    ISR_Tok = 1<<2,
+    ISR_Ter = 1<<3,
+    ISR_Rxovw = 1<<4,
+    ISR_Pun = 1<<5,
+    ISR_Fovw = 1<<6,
+    ISR_Lenchg = 1<<13,
+    ISR_Timeout = 1<<14,
+    ISR_Serr = 1<<15,
+};
+
+/* 
+ * Interrupt Status Register (ISR) Offset: ox3e-0x3f
+ * Interrupt Mask Register (IMR 0x3c-0x3d) shares the same structure
+ */
+struct isr_imr_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t rx_ok       :1;
+           uint8_t rx_err     : 1;
+           uint8_t tx_ok        : 1;
+           uint8_t tx_err          : 1;
+           uint8_t rx_ovw          : 1;
+           uint8_t pun_linkchg          : 1;
+           uint8_t rx_fifo_ovw  : 1;
+           uint8_t reservd:     6;
+           uint8_t lenchg  :1;
+           uint8_t timeout   :1;
+           uint8_t syserr  :1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+enum CMDBits {
+    CMD_Bufe = 1<<0,
+    CMD_Te = 1<<2,
+    CMD_Re = 1<<3,
+    CMD_Rst = 1<<4,
+};
+
+
+/* Commmand Register Offset: 0x37 */
+struct cmd_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t cmd_bufe      : 1;
+           uint8_t reservd_1        : 1;
+           uint8_t cmd_te          : 1;
+           uint8_t cmd_re          : 1;
+           uint8_t cmd_rst          : 1;
+           uint8_t reservd_2  : 3;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
+enum CMD9346Bits {
+    CMD9346_Lock = 0x00,
+    CMD9346_Unlock = 0xC0,
+};
+
+
+
+/* 93C46 Commmand Register Offset: 0x50 */
+struct cmd9346_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t eedo      : 1;
+           uint8_t eedi        : 1;
+           uint8_t eesk          : 1;
+           uint8_t eecs          : 1;
+           uint8_t reserved    : 2;
+           uint8_t eem  : 2;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+// Bits in TxConfig.
+enum TXConfig_bits{
+
+        /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
+    TxIFGShift = 24,
+    TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
+    TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
+    TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
+    TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
+
+    TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+    TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
+    TxClearAbt = (1 << 0),     /* Clear abort (WO) */
+    TxDMAShift = 8,            /* DMA burst value (0-7) is shifted this many bits */
+    TxRetryShift = 4,  /* TXRR value (0-15) is shifted this many bits */
+
+    TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+};
+
+
+/* Transmit Configuration Register (TCR) Offset: 0x40-0x43 */
+struct tx_config_reg {
+    union {
+       uint32_t val;
+       struct {
+           uint8_t clr_abort   :1;
+           uint8_t reserved_1     : 3;
+           uint8_t tx_retry_cnt        : 4;
+           uint8_t max_dma          : 3;
+           uint8_t reserved_2          : 5;
+           uint8_t tx_crc          : 1;
+           uint8_t loop_test  : 2;
+           uint8_t reservd_3:     3;
+           uint8_t hw_verid_b  :2;
+           uint8_t ifg   :2;
+           uint8_t hw_verid_a  :5;
+           uint8_t reservd_4  :1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
+enum CSCRBits {
+    CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
+    CSCR_LD  = 1<<9,  /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
+    CSCR_HEART_BIT = 1<<8,  /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/
+    CSCR_JBEN = 1<<7,  /* 1 = enable jabber function. 0 = disable jabber function, def 1*/
+    CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
+    CSCR_F_Connect  = 1<<5,  /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/
+    CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/
+    CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/
+    CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/
+};
+
+
+/* CS Configuration Register (CSCR) Offset: 0x74-0x75 */
+struct cscr_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t pass_scr    :1;
+           uint8_t reserved_1     : 1;
+           uint8_t con_status_en        : 1;
+           uint8_t con_status          : 1;
+           uint8_t reserved_2          : 1;
+           uint8_t f_connect          : 1;
+           uint8_t f_link_100  : 1;
+           uint8_t jben:     1;
+           uint8_t heart_beat  :1;
+           uint8_t ld   :1;
+           uint8_t reservd_3  :5;
+           uint8_t test_fun  :1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+    AcceptErr = 0x20,
+    AcceptRunt = 0x10,
+    AcceptBroadcast = 0x08,
+    AcceptMulticast = 0x04,
+    AcceptMyPhys = 0x02,
+    AcceptAllPhys = 0x01,
+};
+
+
+/* Receive Configuration Register (RCR) Offset: 0x44-0x47 */
+struct rx_config_reg {
+    union {
+       uint32_t val;
+       struct {
+           uint8_t all_phy   : 1;
+           uint8_t my_phy      : 1;
+           uint8_t all_multi     : 1;
+           uint8_t all_brdcast        : 1;
+           uint8_t acpt_runt          : 1;
+           uint8_t acpt_err          : 1;
+           uint8_t reserved_1          : 1;
+           uint8_t wrap  : 1;
+           uint8_t max_dma:     3;
+           uint8_t rx_buf_len  :2;
+           uint8_t rx_fifo_thresd   :3;
+           uint8_t rer8  :1;
+           uint8_t mul_er_intr  :1;
+           uint8_t reserved_2          : 6;
+           uint8_t eraly_rx_thresd   :4;
+           uint8_t reserved_3          : 4;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
+#define RTL8139_PCI_REVID_8139      0x10
+
+#define SET_MASKED(input, mask, curr) \
+    (((input) & ~(mask)) | ((curr) & (mask)))
+
+/* arg % size for size which is a power of 2 */
+#define MOD2(input, size) \
+    ((input) & (size - 1))
+
+
+/* Size is 64 * 16bit words */
+#define EEPROM_9346_ADDR_BITS 6
+#define EEPROM_9346_SIZE  (1 << EEPROM_9346_ADDR_BITS)
+#define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1)
+
+enum Chip9346Operation
+{
+    Chip9346_op_mask = 0xc0,          /* 10 zzzzzz */
+    Chip9346_op_read = 0x80,          /* 10 AAAAAA */
+    Chip9346_op_write = 0x40,         /* 01 AAAAAA D(15)..D(0) */
+    Chip9346_op_ext_mask = 0xf0,      /* 11 zzzzzz */
+    Chip9346_op_write_enable = 0x30,  /* 00 11zzzz */
+    Chip9346_op_write_all = 0x10,     /* 00 01zzzz */
+    Chip9346_op_write_disable = 0x00, /* 00 00zzzz */
+};
+
+enum Chip9346Mode {
+    Chip9346_none = 0,
+    Chip9346_enter_command_mode,
+    Chip9346_read_command,
+    Chip9346_data_read,      /* from output register */
+    Chip9346_data_write,     /* to input register, then to contents at specified address */
+    Chip9346_data_write_all, /* to input register, then filling contents */
+};
+
+struct EEprom9346 {
+    uint16_t contents[EEPROM_9346_SIZE];
+    int      mode;
+    uint32_t tick;
+    uint8_t  address;
+    uint16_t input;
+    uint16_t output;
+
+    uint8_t eecs;
+    uint8_t eesk;
+    uint8_t eedi;
+    uint8_t eedo;
+};
+
+struct rtl8139_regs {
+  union{
+       uint8_t mem[256];
+       
+       struct {
+           uint8_t id[6];
+           uint8_t reserved;
+           uint8_t mult[8];
+           uint32_t tsd[4];
+           uint32_t tsad[4];
+           uint32_t rbstart;
+           uint16_t erbcr;
+           uint8_t ersr;
+           uint8_t cmd;
+           uint16_t capr;
+           uint16_t cbr;
+           uint16_t imr;
+           uint16_t isr;
+           uint32_t tcr;
+           uint32_t rcr;
+           uint32_t tctr;
+           uint16_t mpc;
+           uint8_t cmd9346;
+           uint8_t config[2];
+           uint32_t timer_int;
+           uint8_t msr;
+           uint8_t config3[2];
+           uint16_t mulint;
+           uint16_t rerid;
+           uint16_t txsad;
+           uint16_t bmcr;
+           uint16_t bmsr;
+           uint16_t anar;
+           uint16_t anlpar;
+           uint16_t aner;
+           uint16_t dis;
+           uint16_t fcsc;
+           uint16_t nwaytr;
+           uint16_t rec;
+           uint32_t cscr;
+           uint32_t phy1_parm;
+           uint16_t tw_parm;
+           uint32_t  phy2_parm;
+           uint8_t crc[8];
+           uint32_t wakeup[16];
+           uint8_t isbcr[8];
+           uint8_t config5;
+       }__attribute__((packed));
+   }__attribute__((packed));
+};
+
+
+
+struct rtl8139_state { 
+    nic_state_t dev_state;
+
+    struct v3_vm_info * vm;
+    struct pci_device * pci_dev;
+    struct vm_device * pci_bus;
+    struct vm_device * dev;
+
+    struct nic_statistics statistic;
+
+    struct rtl8139_regs regs;
+    struct EEprom9346 eeprom; 
+
+    uint8_t tx_fifo[TX_FIFO_SIZE];
+    uint8_t rx_fifo[RX_FIFO_SIZE];
+    uint32_t rx_bufsize;
+
+    uint8_t mac[ETH_ALEN];
+
+    struct v3_dev_net_ops *net_ops;
+    void * backend_data;
+};
+
+static inline void rtl8139_update_irq(struct rtl8139_state * nic_state) {
+    int isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0xffff);
+
+    if(isr & 0xffff){
+       v3_pci_raise_irq(nic_state->pci_bus, 0, nic_state->pci_dev);
+       nic_state->statistic.interrupts ++;
+    }
+}
+
+static void prom9346_decode_command(struct EEprom9346 * eeprom, uint8_t command) {
+    PrintDebug("RTL8139: eeprom command 0x%02x\n", command);
+
+    switch (command & Chip9346_op_mask) {
+        case Chip9346_op_read:
+       {
+            eeprom->address = command & EEPROM_9346_ADDR_MASK;
+            eeprom->output = eeprom->contents[eeprom->address];
+            eeprom->eedo = 0;
+            eeprom->tick = 0;
+            eeprom->mode = Chip9346_data_read;
+            PrintDebug("RTL8139: eeprom read from address 0x%02x data=0x%04x\n",
+                   eeprom->address, eeprom->output);
+        }
+        break;
+
+        case Chip9346_op_write:
+        {
+            eeprom->address = command & EEPROM_9346_ADDR_MASK;
+            eeprom->input = 0;
+            eeprom->tick = 0;
+            eeprom->mode = Chip9346_none; /* Chip9346_data_write */
+            PrintDebug("RTL8139: eeprom begin write to address 0x%02x\n",
+                   eeprom->address);
+        }
+        break;
+        default:
+            eeprom->mode = Chip9346_none;
+            switch (command & Chip9346_op_ext_mask) {
+                case Chip9346_op_write_enable:
+                    PrintDebug("RTL8139: eeprom write enabled\n");
+                    break;
+                case Chip9346_op_write_all:
+                    PrintDebug("RTL8139: eeprom begin write all\n");
+                    break;
+                case Chip9346_op_write_disable:
+                    PrintDebug("RTL8139: eeprom write disabled\n");
+                    break;
+            }
+        break;
+    }
+}
+
+static void prom9346_shift_clock(struct EEprom9346 * eeprom) {
+    int bit = eeprom->eedi?1:0;
+
+    ++ eeprom->tick;
+
+    PrintDebug("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo);
+
+    switch (eeprom->mode) {
+        case Chip9346_enter_command_mode:
+            if (bit) {
+                eeprom->mode = Chip9346_read_command;
+                eeprom->tick = 0;
+                eeprom->input = 0;
+                PrintDebug("eeprom: +++ synchronized, begin command read\n");
+            }
+            break;
+
+        case Chip9346_read_command:
+            eeprom->input = (eeprom->input << 1) | (bit & 1);
+            if (eeprom->tick == 8) {
+                prom9346_decode_command(eeprom, eeprom->input & 0xff);
+            }
+            break;
+
+        case Chip9346_data_read:
+            eeprom->eedo = (eeprom->output & 0x8000)?1:0;
+            eeprom->output <<= 1;
+            if (eeprom->tick == 16){
+#if 1
+        // the FreeBSD drivers (rl and re) don't explicitly toggle
+        // CS between reads (or does setting Cfg9346 to 0 count too?),
+        // so we need to enter wait-for-command state here
+                eeprom->mode = Chip9346_enter_command_mode;
+                eeprom->input = 0;
+                eeprom->tick = 0;
+
+                PrintDebug("eeprom: +++ end of read, awaiting next command\n");
+#else
+        // original behaviour
+                ++eeprom->address;
+                eeprom->address &= EEPROM_9346_ADDR_MASK;
+                eeprom->output = eeprom->contents[eeprom->address];
+                eeprom->tick = 0;
+
+                DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n",
+                       eeprom->address, eeprom->output));
+#endif
+            }
+            break;
+
+        case Chip9346_data_write:
+            eeprom->input = (eeprom->input << 1) | (bit & 1);
+            if (eeprom->tick == 16) {
+                PrintDebug("RTL8139: eeprom write to address 0x%02x data=0x%04x\n",
+                       eeprom->address, eeprom->input);
+
+                eeprom->contents[eeprom->address] = eeprom->input;
+                eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */
+                eeprom->tick = 0;
+                eeprom->input = 0;
+            }
+            break;
+
+        case Chip9346_data_write_all:
+            eeprom->input = (eeprom->input << 1) | (bit & 1);
+            if (eeprom->tick == 16) {
+                int i;
+                for (i = 0; i < EEPROM_9346_SIZE; i++)
+                {
+                    eeprom->contents[i] = eeprom->input;
+                }
+                PrintDebug("RTL8139: eeprom filled with data=0x%04x\n",
+                       eeprom->input);
+
+                eeprom->mode = Chip9346_enter_command_mode;
+                eeprom->tick = 0;
+                eeprom->input = 0;
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+static int prom9346_get_wire(struct rtl8139_state * nic_state) {
+    struct EEprom9346 *eeprom = &(nic_state->eeprom);
+
+    if (eeprom->eecs == 0)
+        return 0;
+
+    return eeprom->eedo;
+}
+
+static void prom9346_set_wire(struct rtl8139_state * nic_state, 
+                             int eecs, 
+                             int eesk, 
+                             int eedi) {
+    struct EEprom9346 *eeprom = &(nic_state->eeprom);
+    uint8_t old_eecs = eeprom->eecs;
+    uint8_t old_eesk = eeprom->eesk;
+
+    eeprom->eecs = eecs;
+    eeprom->eesk = eesk;
+    eeprom->eedi = eedi;
+
+    PrintDebug("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n",
+                 eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo);
+
+    if (old_eecs == 0 && eecs) {
+        /* Synchronize start */
+        eeprom->tick = 0;
+        eeprom->input = 0;
+        eeprom->output = 0;
+        eeprom->mode = Chip9346_enter_command_mode;
+
+        PrintDebug("=== eeprom: begin access, enter command mode\n");
+    }
+
+    if (eecs == 0) {
+        PrintDebug("=== eeprom: end access\n");
+        return;
+    }
+
+    if (!old_eesk && eesk) {
+        /* SK front rules */
+        prom9346_shift_clock(eeprom);
+    }
+}
+
+
+static inline void rtl8139_reset_rxbuf(struct rtl8139_state * nic_state, uint32_t bufsize) {
+    nic_state->rx_bufsize = bufsize;
+    nic_state->regs.capr = 0;
+    nic_state->regs.cbr = 0;
+}
+
+
+static void rtl8139_reset(struct rtl8139_state *nic_state) {
+    struct rtl8139_regs *regs = &(nic_state->regs);
+    int i;
+
+    PrintDebug("Rtl8139: Reset\n");
+
+    /* restore MAC address */
+    memcpy(regs->id, nic_state->mac, ETH_ALEN);
+    memset(regs->mult, 0xff, 8);
+
+    rtl8139_update_irq(nic_state);
+
+    // prepare eeprom
+    nic_state->eeprom.contents[0] = 0x8129;
+       
+    // PCI vendor and device ID
+    nic_state->eeprom.contents[1] = 0x10ec;
+    nic_state->eeprom.contents[2] = 0x8139;
+    //Mac address
+    nic_state->eeprom.contents[7] = nic_state->mac[0] | nic_state->mac[1] << 8;
+    nic_state->eeprom.contents[8] = nic_state->mac[2] | nic_state->mac[3] << 8;
+    nic_state->eeprom.contents[9] = nic_state->mac[4] | nic_state->mac[5] << 8;
+
+    for (i = 0; i < 4; ++i) {
+        regs->tsd[i] = TSD_Own;
+    }
+
+    rtl8139_reset_rxbuf(nic_state, 1024*8);
+
+    /* ACK the reset */
+    regs->tcr = 0;
+
+    regs->tcr |= ((0x1d << 26) | (0x1 << 22)); // RTL-8139D
+    regs->rerid = RTL8139_PCI_REVID_8139;
+
+    regs->cmd = CMD_Rst; //RxBufEmpty bit is calculated on read from ChipCmd 
+
+    regs->config[0] = 0x0 | (1 << 4); // No boot ROM 
+    regs->config[1] = 0xC; //IO mapped and MEM mapped registers available
+    //regs->config[1] = 0x4; //Only IO mapped registers available
+    regs->config3[0] = 0x1; // fast back-to-back compatible
+    regs->config3[1] = 0x0;
+    regs->config5 = 0x0;
+       
+    regs->cscr = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
+
+    //0x3100 : 100Mbps, full duplex, autonegotiation.  0x2100 : 100Mbps, full duplex
+    regs->bmcr = 0x1000; // autonegotiation
+
+    regs->bmsr  = 0x7809;
+    regs->bmsr |= 0x0020; // autonegotiation completed
+    regs->bmsr |= 0x0004; // link is up
+
+    regs->anar = 0x05e1;     // all modes, full duplex
+    regs->anlpar = 0x05e1;   // all modes, full duplex
+    regs->aner = 0x0001;     // autonegotiation supported
+
+    // reset timer and disable timer interrupt
+    regs->tctr = 0;
+    regs->timer_int = 0;
+}
+
+
+
+static void rtl8139_9346cr_write(struct rtl8139_state * nic_state, uint32_t val) {
+    val &= 0xff;
+
+    PrintDebug("RTL8139: 9346CR write val=0x%02x\n", val);
+
+    /* mask unwriteable bits */
+    val = SET_MASKED(val, 0x31, nic_state->regs.cmd9346);
+
+    uint32_t opmode = val & 0xc0;
+    uint32_t eeprom_val = val & 0xf;
+
+    if (opmode == 0x80) {
+        /* eeprom access */
+        int eecs = (eeprom_val & 0x08)?1:0;
+        int eesk = (eeprom_val & 0x04)?1:0;
+        int eedi = (eeprom_val & 0x02)?1:0;
+        prom9346_set_wire(nic_state, eecs, eesk, eedi);
+    } else if (opmode == 0x40) {
+        /* Reset.  */
+        val = 0;
+        rtl8139_reset(nic_state);
+    }
+
+    nic_state->regs.cmd9346 = val;
+}
+
+static uint32_t rtl8139_9346cr_read(struct rtl8139_state * nic_state) {
+    uint32_t ret = nic_state->regs.cmd9346;
+    uint32_t opmode = ret & 0xc0;
+
+    if (opmode == 0x80) {
+        /* eeprom access */
+        int eedo = prom9346_get_wire(nic_state);
+        if (eedo){
+            ret |=  0x01;
+        } else {
+            ret &= ~0x01;
+        }
+    }
+
+    PrintDebug("RTL8139: 9346CR read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+
+static inline int rtl8139_receiver_enabled(struct rtl8139_state * nic_state) {
+    return nic_state->regs.cmd & CMD_Re;
+}
+
+static inline int rtl8139_rxwrap(struct rtl8139_state * nic_state) {
+    // wrapping enabled; assume 1.5k more buffer space if size < 64K
+    return (nic_state->regs.rcr & (1 << 7));
+}
+
+static void rtl8139_rxbuf_write(struct rtl8139_state * nic_state, 
+                               const void * buf, 
+                               int size) {
+    struct rtl8139_regs *regs = &(nic_state->regs);
+    int wrap;
+    addr_t guestpa, host_rxbuf;
+
+    guestpa = (addr_t)regs->rbstart;
+    v3_gpa_to_hva(&(nic_state->vm->cores[0]), guestpa, &host_rxbuf);   
+
+    //wrap to the front of rx buffer
+    if (regs->cbr + size > nic_state->rx_bufsize){
+        wrap = MOD2(regs->cbr + size, nic_state->rx_bufsize);
+
+        if (wrap && !(nic_state->rx_bufsize < 64*1024 && rtl8139_rxwrap(nic_state))){
+            PrintDebug("RTL8139: rx packet wrapped in buffer at %d\n", size-wrap);
+
+            if (size > wrap){
+                memcpy((void *)(host_rxbuf + regs->cbr), buf, size-wrap);
+            }
+
+            // reset buffer pointer
+            regs->cbr = 0;
+
+            memcpy((void *)(host_rxbuf + regs->cbr), buf + (size-wrap), wrap);
+
+            regs->cbr = wrap;
+
+            return;
+        }
+    }
+
+    memcpy((void *)(host_rxbuf + regs->cbr), buf, size);
+
+    regs->cbr += size;
+}
+
+#define POLYNOMIAL 0x04c11db6
+
+/* From FreeBSD */
+static inline int compute_mcast_idx(const uint8_t *ep) {
+    uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = *ep++;
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry){
+                crc = ((crc ^ POLYNOMIAL) | carry);
+           }
+        }
+    }
+    return (crc >> 26);
+}
+
+
+static int rx_one_pkt(struct rtl8139_state * nic_state, 
+                     uint8_t * pkt, 
+                     uint32_t len){
+    struct rtl8139_regs *regs = &(nic_state->regs);
+    uint_t rxbufsize = nic_state->rx_bufsize;
+    uint32_t header, val;
+    uint8_t bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+    if (regs->rcr & AcceptAllPhys) {
+       PrintDebug("RTL8139: packet received in promiscuous mode\n");
+    } else {
+       if (!memcmp(pkt,  bcast_addr, 6)) {
+           if (!(regs->rcr & AcceptBroadcast)){
+               PrintDebug("RTL8139: broadcast packet rejected\n");
+               return -1;
+           }
+           header |= Rx_Broadcast;
+           PrintDebug("RTL8139: broadcast packet received\n");
+       } else if (pkt[0] & 0x01) {
+            // multicast
+            if (!(regs->rcr & AcceptMulticast)){
+                PrintDebug("RTL8139: multicast packet rejected\n");
+                return -1;
+            }
+
+            int mcast_idx = compute_mcast_idx(pkt);
+
+            if (!(regs->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))){
+                PrintDebug("RTL8139: multicast address mismatch\n");
+                return -1;
+            }
+            header |= Rx_Multicast;
+            PrintDebug("RTL8139: multicast packet received\n");
+        } else if (!compare_ethaddr(regs->id, pkt)){
+            if (!(regs->rcr & AcceptMyPhys)){
+                PrintDebug("RTL8139: rejecting physical address matching packet\n");
+                return -1;
+            }
+
+            header |= Rx_Physical;
+            PrintDebug("RTL8139: physical address matching packet received\n");
+        } else {
+            PrintDebug("RTL8139: unknown packet\n");
+            return -1;
+        }
+    }
+
+    if(1){
+       PrintDebug("RTL8139: in ring Rx mode\n");
+
+       int avail = MOD2(rxbufsize + regs->capr - regs->cbr, rxbufsize);
+
+        if (avail != 0 && len + 8 >= avail){
+            PrintError("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n",
+                   rxbufsize, regs->cbr, regs->capr, avail, len + 8);
+
+            regs->isr |= ISR_Rxovw;
+            ++ regs->mpc;
+            rtl8139_update_irq(nic_state);
+            return -1;
+        }
+
+        header |= Rx_OK;
+        header |= ((len << 16) & 0xffff0000);
+
+        rtl8139_rxbuf_write(nic_state, (uint8_t *)&header, 4);
+
+        rtl8139_rxbuf_write(nic_state, pkt, len);
+
+        /* CRC checksum */
+        val = v3_crc32(0, pkt, len);
+
+        rtl8139_rxbuf_write(nic_state, (uint8_t *)&val, 4);
+
+        // correct buffer write pointer 
+        regs->cbr = MOD2((regs->cbr + 3) & ~0x3, rxbufsize);
+
+        PrintDebug("RTL8139: received: rx buffer length %d CBR: 0x%04x CAPR: 0x%04x\n",
+                               rxbufsize, regs->cbr, regs->capr);
+    }
+
+    regs->isr |= ISR_Rok;
+
+    nic_state->statistic.rx_pkts ++;
+    nic_state->statistic.rx_bytes += len;
+       
+    rtl8139_update_irq(nic_state);   
+
+    return 0;
+}
+
+static int rtl8139_rx(uint8_t * pkt, uint32_t len, void * private_data) {
+    struct rtl8139_state *nic_state = (struct rtl8139_state *)private_data;
+
+    if (!rtl8139_receiver_enabled(nic_state)){
+       PrintDebug("RTL8139: receiver disabled\n");
+       nic_state->statistic.rx_dropped ++;
+               
+       return 0;
+    }
+       
+    if(rx_one_pkt(nic_state, pkt, len) >= 0){
+       nic_state->statistic.rx_pkts ++;
+       nic_state->statistic.rx_bytes += len;
+    }else {
+       nic_state->statistic.rx_dropped ++;
+    }
+
+    return 0;
+}
+
+static void rtl8139_rcr_write(struct rtl8139_state * nic_state, uint32_t val) {
+    PrintDebug("RTL8139: RCR write val=0x%08x\n", val);
+
+    val = SET_MASKED(val, 0xf0fc0040, nic_state->regs.rcr);
+    nic_state->regs.rcr = val;
+
+#if 0
+    uchar_t rblen = (regs->rcr >> 11) & 0x3;
+    switch(rblen) {
+        case 0x0:
+            rxbufsize = 1024 * 8 + 16;
+            break;
+        case 0x1:
+            rxbufsize = 1024 * 16 + 16;
+            break;
+        case 0x2:
+            rxbufsize = 1024 * 32 + 16;
+            break;
+        default:
+            rxbufsize = 1024 * 64 + 16;
+            break;
+    }
+#endif
+
+    // reset buffer size and read/write pointers
+    rtl8139_reset_rxbuf(nic_state, 8192 << ((nic_state->regs.rcr >> 11) & 0x3));
+
+    PrintDebug("RTL8139: RCR write reset buffer size to %d\n", nic_state->rx_bufsize);
+}
+
+
+#if 0
+
+static int rtl8139_config_writeable(struct vm_device *dev)
+{
+    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
+       
+    if (nic_state->regs.cmd9346 & CMD9346_Unlock)
+    {
+        return 1;
+    }
+
+    PrintDebug("RTL8139: Configuration registers are unwriteable\n");
+
+    return 0;
+}
+
+#endif
+
+static inline int transmitter_enabled(struct rtl8139_state * nic_state){
+    return nic_state->regs.cmd & CMD_Te;
+}
+
+static int rxbufempty(struct rtl8139_state * nic_state){
+    struct rtl8139_regs *regs = &(nic_state->regs);
+    int unread;
+
+    unread = MOD2(regs->cbr + nic_state->rx_bufsize - regs->capr, nic_state->rx_bufsize);
+   
+    if (unread != 0){
+        PrintDebug("RTL8139: receiver buffer data available 0x%04x\n", unread);
+        return 0;
+    }
+
+    PrintDebug("RTL8139: receiver buffer is empty\n");
+
+    return 1;
+}
+
+static void rtl8139_cmd_write(struct rtl8139_state * nic_state, uint32_t val){
+    val &= 0xff;
+
+    PrintDebug("RTL8139: Cmd write val=0x%08x\n", val);
+
+    if (val & CMD_Rst){
+        PrintDebug("RTL8139: Cmd reset\n");
+        rtl8139_reset(nic_state);
+    }
+    if (val & CMD_Re){
+        PrintDebug("RTL8139: Cmd enable receiver\n");
+    }
+    if (val & CMD_Te){
+        PrintDebug("RTL8139: Cmd enable transmitter\n");
+    }
+
+    val = SET_MASKED(val, 0xe3, nic_state->regs.cmd);
+    val &= ~CMD_Rst;
+
+    nic_state->regs.cmd = val;
+}
+
+static int tx_one_packet(struct rtl8139_state * nic_state, int descriptor){
+    struct rtl8139_regs *regs = &(nic_state->regs);
+    int txsize;
+    uint8_t *pkt;
+    addr_t pkt_gpa = 0, hostva = 0;
+
+    if (!transmitter_enabled(nic_state)){
+        PrintError("RTL8139: fail to send from descriptor %d: transmitter disabled\n", descriptor);
+        return 0;
+    }
+
+    if (regs->tsd[descriptor] & TSD_Own){
+        PrintError("RTL8139: fail to send from descriptor %d: owned by host\n", descriptor);
+        return 0;
+    }
+
+    txsize = regs->tsd[descriptor] & 0x1fff;
+    pkt_gpa = (addr_t) regs->tsad[descriptor];
+
+    PrintDebug("RTL8139: sending %d bytes from guest memory at 0x%08x\n", txsize, regs->tsad[descriptor]);
+       
+    v3_gpa_to_hva(&(nic_state->vm->cores[0]), (addr_t)pkt_gpa, &hostva);
+    pkt = (uchar_t *)hostva;
+
+#ifdef CONFIG_DEBUG_RTL8139
+    v3_hexdump(pkt, txsize, NULL, 0);
+#endif
+
+    if (TxLoopBack == (regs->tcr & TxLoopBack)){ /* loopback test */
+        PrintDebug(("RTL8139: transmit loopback mode\n"));
+        rx_one_pkt(nic_state, pkt, txsize);
+    } else{       
+        if (nic_state->net_ops->send(pkt, txsize, nic_state->backend_data) == 0){
+           PrintDebug("RTL8139: Sent %d bytes from descriptor %d\n", txsize, descriptor);
+           nic_state->statistic.tx_pkts ++;
+           nic_state->statistic.tx_bytes += txsize;
+       } else {
+           PrintError("Rtl8139: Sending packet error: 0x%p\n", pkt);
+           nic_state->statistic.tx_dropped ++;
+       }
+    }
+
+    regs->tsd[descriptor] |= TSD_Tok;
+    regs->tsd[descriptor] |= TSD_Own;
+
+    nic_state->regs.isr |= ISR_Tok;
+    rtl8139_update_irq(nic_state);
+
+    return 0;
+}
+
+/*transmit status registers*/
+static void rtl8139_tsd_write(struct rtl8139_state * nic_state, 
+                             uint8_t descriptor, 
+                             uint32_t val){ 
+    if (!transmitter_enabled(nic_state)){
+        PrintDebug("RTL8139: TxStatus write val=0x%08x descriptor=%d, Transmitter not enabled\n", val, descriptor);
+               
+        return;
+    }
+
+    PrintDebug("RTL8139: TSD write val=0x%08x descriptor=%d\n", val, descriptor);
+
+    // mask read-only bits
+    val &= ~0xff00c000;
+    val = SET_MASKED(val, 0x00c00000,  nic_state->regs.tsd[descriptor]);
+
+    nic_state->regs.tsd[descriptor] = val;
+
+    tx_one_packet(nic_state, descriptor);
+}
+
+/* transmit status of all descriptors */
+static uint16_t rtl8139_txsad_read(struct rtl8139_state * nic_state){
+    uint16_t ret = 0;
+    struct rtl8139_regs *regs = &(nic_state->regs);
+
+    ret = ((regs->tsd[3] & TSD_Tok)?TSAD_TOK3:0)
+         |((regs->tsd[2] & TSD_Tok)?TSAD_TOK2:0)
+         |((regs->tsd[1] & TSD_Tok)?TSAD_TOK1:0)
+         |((regs->tsd[0] & TSD_Tok)?TSAD_TOK0:0)
+
+         |((regs->tsd[3] & TSD_Tun)?TSAD_TUN3:0)
+         |((regs->tsd[2] & TSD_Tun)?TSAD_TUN2:0)
+         |((regs->tsd[1] & TSD_Tun)?TSAD_TUN1:0)
+         |((regs->tsd[0] & TSD_Tun)?TSAD_TUN0:0)
+
+         |((regs->tsd[3] & TSD_Tabt)?TSAD_TABT3:0)
+         |((regs->tsd[2] & TSD_Tabt)?TSAD_TABT2:0)
+         |((regs->tsd[1] & TSD_Tabt)?TSAD_TABT1:0)
+         |((regs->tsd[0] & TSD_Tabt)?TSAD_TABT0:0)
+
+         |((regs->tsd[3] & TSD_Own)?TSAD_OWN3:0)
+         |((regs->tsd[2] & TSD_Own)?TSAD_OWN2:0)
+         |((regs->tsd[1] & TSD_Own)?TSAD_OWN1:0)
+         |((regs->tsd[0] & TSD_Own)?TSAD_OWN0:0) ;
+
+    PrintDebug("RTL8139: txsad read val=0x%04x\n", (int)ret);
+
+    return ret;
+}
+
+static inline void rtl8139_isr_write(struct rtl8139_state * nic_state, uint32_t val) {
+    struct rtl8139_regs *regs = &(nic_state->regs);
+
+    PrintDebug("RTL8139: ISR write val=0x%04x\n", val);
+
+    uint16_t newisr = regs->isr & ~val;
+
+    /* mask unwriteable bits */
+    newisr = SET_MASKED(newisr, 0x1e00, regs->isr);
+
+    /* writing 1 to interrupt status register bit clears it */
+    regs->isr = 0;
+    rtl8139_update_irq(nic_state);
+
+    regs->isr = newisr;
+    rtl8139_update_irq(nic_state);
+}
+
+static int rtl8139_mmio_write(struct guest_info * core, 
+                             addr_t guest_addr, 
+                             void * src,
+                             uint_t length, 
+                             void * priv_data) {
+    int idx;
+    uint32_t val;
+    struct rtl8139_state *nic_state = (struct rtl8139_state *)(priv_data);
+
+    idx = guest_addr & 0xff;
+
+    memcpy(&val, src, length);
+
+    PrintDebug("rtl8139 mmio write: addr:0x%x (%u bytes): 0x%x\n", (int)guest_addr, length, val);
+       
+    switch(idx) {
+       case RTL8139_IDR0 ... RTL8139_IDR0 + 5:
+           nic_state->regs.id[idx - RTL8139_IDR0] = val & 0xff;
+           break;
+
+       case RTL8139_MAR0 ... RTL8139_MAR0 + 7:
+           nic_state->regs.mult[idx - RTL8139_MAR0] = val & 0xff;
+           break;
+
+       case RTL8139_TSD0:
+       case RTL8139_TSD1:
+       case RTL8139_TSD2:
+       case RTL8139_TSD3:
+           rtl8139_tsd_write(nic_state, (idx - RTL8139_TSD0)/4, val);
+           break;
+               
+       case RTL8139_TSAD0:
+       case RTL8139_TSAD1:
+       case RTL8139_TSAD2:
+       case RTL8139_TSAD3:
+           nic_state->regs.tsad[(idx - RTL8139_TSAD0)/4] = val;
+           break;
+               
+       case RTL8139_RBSTART:
+           nic_state->regs.rbstart = val;
+           break;
+       case RTL8139_ERBCR:
+           nic_state->regs.erbcr = val & 0xffff;
+           break;
+       case RTL8139_ERSR:
+           //nic_state->regs.ersr = val & 0xff;
+           nic_state->regs.ersr &= (~val) & 0x0c;
+           break;
+       case RTL8139_CR:
+           rtl8139_cmd_write(nic_state, val);
+           break;
+       case RTL8139_CAPR:
+       {
+           val &= 0xffff;
+           /* this value is off by 16 */
+           nic_state->regs.capr = MOD2(val + 0x10, nic_state->rx_bufsize);
+
+           PrintDebug("RTL 8139: CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
+           nic_state->rx_bufsize, nic_state->regs.cbr, nic_state->regs.capr);  
+       }
+           break;
+       case RTL8139_CBR: /* read only */
+           //nic_state->regs.cbr = val & 0xffff;
+           break;
+       case RTL8139_IMR:
+       {
+           PrintDebug("RTL8139: IMR write val=0x%04x\n", val);
+
+           /* mask unwriteable bits */
+           val = SET_MASKED(val, 0x1e00, nic_state->regs.imr);
+           nic_state->regs.imr = val;
+           rtl8139_update_irq(nic_state);
+       }
+           break;
+       case RTL8139_ISR:
+           rtl8139_isr_write(nic_state, val);
+           break;
+       case RTL8139_TCR:
+           nic_state->regs.tcr = val;
+           break;
+       case RTL8139_RCR:
+           rtl8139_rcr_write(nic_state, val);
+           break;
+       case RTL8139_TCTR:
+           nic_state->regs.tctr = 0; /* write clear current tick */
+           break;
+       case RTL8139_MPC:
+           nic_state->regs.mpc = 0; /* clear on write */
+           break;
+       case RTL8139_9346CR:
+           rtl8139_9346cr_write(nic_state, val);
+           break;
+       case RTL8139_CONFIG0:
+           nic_state->regs.config[0] = val & 0xff;
+           break;
+       case RTL8139_CONFIG1:
+           nic_state->regs.config[1] = val & 0xff;
+           break;
+       case RTL8139_TimerInt:
+           nic_state->regs.timer_int = val;
+           break;
+       case RTL8139_MSR:
+           nic_state->regs.msr = val & 0xff;
+           break;
+       case RTL8139_CONFIG3:
+           nic_state->regs.config3[0] = val & 0xff;
+           break;
+       case RTL8139_CONFIG4:
+           nic_state->regs.config3[1] = val & 0xff;
+           break;
+               
+       case RTL8139_MULINT:
+           nic_state->regs.mulint = val & 0xffff;
+           break;
+       case RTL8139_RERID:
+           nic_state->regs.rerid = val & 0xffff;
+           break;
+       case RTL8139_TXSAD:
+           nic_state->regs.txsad = val & 0xffff;
+           break;
+       case RTL8139_BMCR:
+           nic_state->regs.bmcr = val & 0xffff;
+           break;
+       case RTL8139_BMSR:
+           nic_state->regs.bmsr = val & 0xffff;
+           break;
+       case RTL8139_ANAR:
+           nic_state->regs.anar = val & 0xffff;
+           break;
+       case RTL8139_ANLPAR:
+           nic_state->regs.anlpar = val & 0xffff;
+           break;
+       case RTL8139_ANER:
+           nic_state->regs.aner = val & 0xffff;
+           break;
+       case RTL8139_DIS:
+           nic_state->regs.dis = val & 0xffff;
+           break;
+       case RTL8139_FCSC:
+           nic_state->regs.fcsc = val & 0xffff;
+           break;
+       case RTL8139_NWAYTR:
+           nic_state->regs.nwaytr = val & 0xffff;
+           break;
+       case RTL8139_REC:
+           nic_state->regs.rec = val & 0xffff;
+           break;
+
+       case RTL8139_CSCR:
+           nic_state->regs.cscr = val;
+           break;
+       case RTL8139_PHY1_PARM:
+           nic_state->regs.phy1_parm = val;
+           break;
+       case RTL8139_TW_PARM:
+           nic_state->regs.tw_parm = val & 0xffff;
+           break;
+       case RTL8139_PHY2_PARM:
+           nic_state->regs.phy2_parm = val;
+           break;
+       case RTL8139_CRC0 ... RTL8139_CRC0 + 7:
+           nic_state->regs.crc[idx - RTL8139_CRC0] = val & 0xff;
+           break;
+
+       case RTL8139_Config5:
+           nic_state->regs.config5 = val & 0xff;
+           break;
+       default:
+           PrintDebug("rtl8139 write error: invalid port: 0x%x\n", idx);
+       }
+        
+    return length;
+}
+
+static int rtl8139_mmio_read(struct guest_info * core, 
+                            addr_t guest_addr, 
+                            void * dst, 
+                            uint_t length, 
+                            void * priv_data) {
+    uint16_t idx;
+    uint32_t val;
+    struct rtl8139_state *nic_state = (struct rtl8139_state *)priv_data;
+
+    idx = guest_addr & 0xff;
+
+    switch(idx) {
+       case RTL8139_IDR0 ... RTL8139_IDR0 + 5:
+           val = nic_state->regs.id[idx - RTL8139_IDR0];
+           break;
+               
+       case RTL8139_MAR0 ... RTL8139_MAR0 + 7:
+           val = nic_state->regs.mult[idx - RTL8139_MAR0];
+           break;
+
+       case RTL8139_TSD0:
+       case RTL8139_TSD1:
+       case RTL8139_TSD2:
+       case RTL8139_TSD3:
+           val = nic_state->regs.tsd[(idx - RTL8139_TSD0)/4];
+           break;
+
+       case RTL8139_TSAD0:
+       case RTL8139_TSAD1:
+       case RTL8139_TSAD2:
+       case RTL8139_TSAD3:
+           val = nic_state->regs.tsad[(idx - RTL8139_TSAD0)/4];
+           break;
+
+       case RTL8139_RBSTART:
+           val = nic_state->regs.rbstart;
+           break;
+       case RTL8139_ERBCR:
+           val = nic_state->regs.erbcr;
+           break;
+       case RTL8139_ERSR:
+           val = nic_state->regs.ersr;
+           break;
+       case RTL8139_CR:
+       {
+           val = nic_state->regs.cmd;
+           if (rxbufempty(nic_state)){
+               val |= CMD_Bufe;
+           }
+       }
+           break;
+       case RTL8139_CAPR:
+           /* this value is off by 16 -- don't know why - Lei*/
+           val = nic_state->regs.capr - 0x10;
+           break;
+       case RTL8139_CBR:
+           val = nic_state->regs.cbr;
+           break;
+       case RTL8139_IMR:
+           val = nic_state->regs.imr;
+           break;
+       case RTL8139_ISR:
+           val = (uint32_t)nic_state->regs.isr;
+           break;
+       case RTL8139_TCR:
+           val = nic_state->regs.tcr;
+           break;
+       case RTL8139_RCR:
+           val = nic_state->regs.rcr;
+           break;
+       case RTL8139_TCTR:
+           val = nic_state->regs.tctr;
+           break;
+       case RTL8139_MPC:
+           val = nic_state->regs.mpc;
+           break;
+       case RTL8139_9346CR:
+           val = rtl8139_9346cr_read(nic_state);
+           break;
+       case RTL8139_CONFIG0:
+           val = nic_state->regs.config[0];
+           break;
+       case RTL8139_CONFIG1:
+           val = nic_state->regs.config[1];
+           break;
+       case RTL8139_TimerInt:
+           val = nic_state->regs.timer_int;
+           break;
+       case RTL8139_MSR:
+           val = nic_state->regs.msr;
+           break;
+       case RTL8139_CONFIG3:
+           val = nic_state->regs.config3[0];
+           break;
+       case RTL8139_CONFIG4:
+           val = nic_state->regs.config3[1];
+           break;
+       case RTL8139_MULINT:
+           val = nic_state->regs.mulint;
+           break;
+       case RTL8139_RERID:
+           val = nic_state->regs.rerid;
+           break;
+       case RTL8139_TXSAD: 
+           val = rtl8139_txsad_read(nic_state);
+           break;
+       case RTL8139_BMCR:
+           val = nic_state->regs.bmcr;
+           break;
+       case RTL8139_BMSR:
+           val = nic_state->regs.bmsr;
+           break;
+       case RTL8139_ANAR:
+           val = nic_state->regs.anar;
+           break;
+       case RTL8139_ANLPAR:
+           val = nic_state->regs.anlpar;
+           break;
+       case RTL8139_ANER:
+           val = nic_state->regs.aner;
+           break;
+       case RTL8139_DIS:
+           val = nic_state->regs.dis;
+           break;
+       case RTL8139_FCSC:
+           val = nic_state->regs.fcsc;
+           break;
+       case RTL8139_NWAYTR:
+           val = nic_state->regs.nwaytr;
+           break;
+       case RTL8139_REC:
+           val = nic_state->regs.rec;
+           break;
+       case RTL8139_CSCR:
+           val = nic_state->regs.cscr;
+           break;
+       case RTL8139_PHY1_PARM:
+           val = nic_state->regs.phy1_parm;
+           break;
+       case RTL8139_TW_PARM:
+           val = nic_state->regs.tw_parm;
+           break;
+       case RTL8139_PHY2_PARM:
+           val = nic_state->regs.phy2_parm;
+           break;
+       case RTL8139_CRC0 ... RTL8139_CRC0 + 7:
+           val = nic_state->regs.crc[idx - RTL8139_CRC0];
+           break;
+       case RTL8139_Config5:
+           val = nic_state->regs.config5;
+           break;
+       default:
+           val = 0x0;
+           break;
+    }
+
+    memcpy(dst, &val, length);
+       
+    PrintDebug("rtl8139 mmio read: port:0x%x (%u bytes): 0x%x\n", (int)guest_addr, length, val);
+
+    return length;
+}
+
+
+static int rtl8139_ioport_write(struct guest_info * core,
+                               uint16_t port, 
+                               void *src, 
+                               uint_t length, 
+                               void * private_data) {
+    return rtl8139_mmio_write(core, (addr_t)port, 
+                             src, length, private_data);
+}
+
+static int rtl8139_ioport_read(struct guest_info * core, 
+                              uint16_t port, 
+                              void *dst, 
+                              uint_t length, 
+                              void * private_data) {
+    return rtl8139_mmio_read(core, (addr_t)port, 
+                            dst, length, private_data);
+}
+
+
+static int rtl8139_init_state(struct rtl8139_state *nic_state) {
+    PrintDebug("rtl8139: init_state\n");
+       
+    nic_state->regs.tsd[0] = nic_state->regs.tsd[1] = nic_state->regs.tsd[2] = nic_state->regs.tsd[3] = TSD_Own;
+
+    nic_state->regs.rerid = RTL8139_PCI_REVID_8139;
+    nic_state->regs.tcr |= ((0x1d << 26) | (0x1 << 22));
+
+    rtl8139_reset(nic_state);
+
+    return 0;
+}
+
+
+#if 0
+static inline int rtl8139_reset_device(struct rtl8139_state * nic_state) {
+    nic_state->regs.cmd |= CMD_Rst;
+    rtl8139_init_state(nic_state);
+    nic_state->regs.cmd &= ~CMD_Rst;
+       
+    return 0;
+}
+
+static inline int rtl8139_start_device(struct rtl8139_state * nic_state) {
+    nic_state->regs.cmd |= CMD_Re | CMD_Te;
+       
+    return 0;
+}
+
+static int rtl8139_stop_device(struct rtl8139_state * nic_state) {
+    PrintDebug("rtl8139: stop device\n");
+
+    nic_state->regs.cmd &= ~(CMD_Re | CMD_Te);
+       
+    return 0;
+}
+
+static int rtl8139_hook_iospace(struct rtl8139_state * nic_state, 
+                               addr_t base_addr, 
+                               int size, 
+                               int type, 
+                               void *data) {
+    int i;
+
+    if (base_addr <= 0){
+       PrintError("In RTL8139: Fail to Hook IO Space, base address 0x%x\n", (int) base_addr);
+       return -1;
+    }
+
+    if (type == PCI_BAR_IO){
+       PrintDebug("In RTL8139: Hook IO ports starting from %x, size %d\n", (int) base_addr, size);
+
+       for (i = 0; i < 0xff; i++){     
+           v3_dev_hook_io(nic_state->dev, base_addr + i, &rtl8139_ioport_read, &rtl8139_ioport_write);
+       }
+    } else if (type == PCI_BAR_MEM32) {
+       PrintDebug("In RTL8139: Hook memory space starting from %x, size %d\n", (int) base_addr, size);
+       
+       //hook memory mapped I/O        
+       v3_hook_full_mem(nic_state->vm, nic_state->vm->cores[0].cpu_id, base_addr, base_addr + 0xff,
+                                     &rtl8139_mmio_read, &rtl8139_mmio_write, nic_state);
+    } else {
+       PrintError("In RTL8139: unknown memory type: start %x, size %d\n", (int) base_addr, size);
+    }
+       
+    return 0;
+}
+#endif
+
+static int register_dev(struct rtl8139_state * nic_state)  {
+    int i;
+
+    if (nic_state->pci_bus == NULL) {
+       PrintError("RTL8139: Not attached to any PCI bus\n");
+
+       return -1;
+    }
+
+    struct v3_pci_bar bars[6];
+    struct pci_device * pci_dev = NULL;
+
+    for (i = 0; i < 6; i++) {
+       bars[i].type = PCI_BAR_NONE;
+    }
+
+    bars[0].type = PCI_BAR_IO;
+    bars[0].default_base_port = 0xc100;
+    bars[0].num_ports = 0x100;
+
+    bars[0].io_read = rtl8139_ioport_read;
+    bars[0].io_write = rtl8139_ioport_write;
+    bars[0].private_data = nic_state;
+
+/*
+    bars[1].type = PCI_BAR_MEM32;
+    bars[1].default_base_addr = -1;
+    bars[1].num_pages = 1;
+
+    bars[1].mem_read = rtl8139_mmio_read;
+    bars[1].mem_write = rtl8139_mmio_write;
+    bars[1].private_data = nic_state;
+*/
+
+    pci_dev = v3_pci_register_device(nic_state->pci_bus, PCI_STD_DEVICE, 0, -1, 0, 
+                                        "RTL8139", bars,
+                                        NULL, NULL, NULL, nic_state);
+
+
+    if (pci_dev == NULL) {
+       PrintError("RTL8139: Could not register PCI Device\n");
+       return -1;
+    }
+       
+    pci_dev->config_header.vendor_id = 0x10ec;
+    pci_dev->config_header.device_id = 0x8139;
+    pci_dev->config_header.command = 0x05;
+       
+    pci_dev->config_header.revision = RTL8139_PCI_REVID_8139;
+
+    pci_dev->config_header.subclass = 0x00;
+    pci_dev->config_header.class = 0x02;
+    pci_dev->config_header.header_type = 0x00;
+
+    pci_dev->config_header.intr_line = 12;
+    pci_dev->config_header.intr_pin = 1;
+    pci_dev->config_space[0x34] = 0xdc;
+
+    nic_state->pci_dev = pci_dev;
+       
+    return 0;
+}
+
+static int connect_fn(struct v3_vm_info * info, 
+                     void * frontend_data, 
+                     struct v3_dev_net_ops * ops, 
+                     v3_cfg_tree_t * cfg, 
+                     void * private_data) {
+    struct rtl8139_state * nic_state = (struct rtl8139_state *)frontend_data;
+
+    rtl8139_init_state(nic_state);
+    register_dev(nic_state);
+
+    nic_state->net_ops = ops;
+    nic_state->backend_data = private_data;    
+
+    ops->recv = rtl8139_rx;
+    ops->poll = NULL;
+    ops->start_tx = NULL;
+    ops->stop_tx = NULL;
+    ops->frontend_data = nic_state;
+    memcpy(ops->fnt_mac, nic_state->mac, ETH_ALEN);
+
+    return 0;
+}
+
+
+static int rtl8139_free(void * private_data) {
+    struct rtl8139_state * nic_state = (struct rtl8139_state *)private_data;
+
+    /* dettached from backend */
+
+    /* unregistered from PCI? */
+
+    V3_Free(nic_state);
+       
+    return 0;
+}
+
+
+static struct v3_device_ops dev_ops = {
+    .free = rtl8139_free,
+};
+
+
+static int rtl8139_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+    struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
+    struct rtl8139_state * nic_state = NULL;
+    char * dev_id = v3_cfg_val(cfg, "ID");
+    char * macstr = v3_cfg_val(cfg, "mac");
+
+    nic_state  = (struct rtl8139_state *)V3_Malloc(sizeof(struct rtl8139_state));
+    memset(nic_state, 0, sizeof(struct rtl8139_state));
+
+    nic_state->pci_bus = pci_bus;
+    nic_state->vm = vm;
+
+    if (macstr != NULL && !str2mac(macstr, nic_state->mac)) {
+       PrintDebug("RTL8139: Mac specified %s\n", macstr);
+    }else {
+       PrintDebug("RTL8139: MAC not specified\n");
+       random_ethaddr(nic_state->mac);
+    }
+
+    struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, nic_state);
+
+    if (dev == NULL) {
+       PrintError("RTL8139: Could not attach device %s\n", dev_id);
+       V3_Free(nic_state);
+       return -1;
+    }
+
+    nic_state->dev = dev;
+
+    if (v3_dev_add_net_frontend(vm, dev_id, connect_fn, (void *)nic_state) == -1) {
+       PrintError("RTL8139: Could not register %s as net frontend\n", dev_id);
+       v3_remove_device(dev);
+       V3_Free(nic_state);
+       return -1;
+    }
+           
+    return 0;
+}
+
+device_register("RTL8139", rtl8139_init)
index 6a6406c..1831270 100644 (file)
 #define PrintDebug(fmt, args...)
 #endif
 
-
 struct vnet_nic_state {
     struct v3_vm_info * vm;
     struct v3_dev_net_ops net_ops;
     int vnet_dev_id;
 };
 
-/* called by frontend device, 
-  * tell the VNET can start sending pkt to it */
-static void start_rx(void * private_data){
-    //struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
-
-    //v3_vnet_enable_device(vnetnic->vnet_dev_id);
-}
-
-/* called by frontend device, 
-  * tell the VNET stop sending pkt to it */
-static void stop_rx(void * private_data){
-    //struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
-
-    //v3_vnet_disable_device(vnetnic->vnet_dev_id);
-}
 
 /* called by frontend, send pkt to VNET */
 static int vnet_nic_send(uint8_t * buf, uint32_t len, 
@@ -93,7 +77,7 @@ static int virtio_input(struct v3_vm_info * info,
                                 vnetnic->net_ops.frontend_data);
 }
 
-/* tell frontend device to poll data from guest */
+/* poll data from front-end */
 static void virtio_poll(struct v3_vm_info * info, 
                        void * private_data){
     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
@@ -102,21 +86,6 @@ static void virtio_poll(struct v3_vm_info * info,
 }
 
 
-/* notify the frontend to start sending pkt to VNET*/
-static void start_tx(void * private_data){
-    struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
-
-    vnetnic->net_ops.start_tx(vnetnic->net_ops.frontend_data);
-}
-
-/* notify the frontend device to stop sending pkt to VNET*/
-static void stop_tx(void * private_data){
-    struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
-
-    vnetnic->net_ops.stop_tx(vnetnic->net_ops.frontend_data);
-}
-
-
 static int vnet_nic_free(struct vnet_nic_state * vnetnic) {
 
     v3_vnet_del_dev(vnetnic->vnet_dev_id);
@@ -133,8 +102,6 @@ static struct v3_device_ops dev_ops = {
 static struct v3_vnet_dev_ops vnet_dev_ops = {
     .input = virtio_input,
     .poll = virtio_poll,
-    .start_tx = start_tx,
-    .stop_tx = stop_tx,
 };
 
 
@@ -156,8 +123,6 @@ static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     }
 
     vnetnic->net_ops.send = vnet_nic_send;
-    vnetnic->net_ops.start_rx = start_rx;
-    vnetnic->net_ops.stop_rx = stop_rx;
     vnetnic->vm = vm;
        
     if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"), 
@@ -173,13 +138,12 @@ static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     if ((vnet_dev_id = v3_vnet_add_dev(vm, vnetnic->net_ops.fnt_mac, &vnet_dev_ops, (void *)vnetnic)) == -1) {
        PrintError("Vnet-nic device %s fails to registered to VNET\n", dev_id);
+       
        v3_remove_device(dev);
        return 0;
     }
     vnetnic->vnet_dev_id = vnet_dev_id;
 
-    PrintDebug("Vnet-nic device %s registered to VNET\n", dev_id);
-
     return 0;
 }
 
index fe2727e..72a1b58 100644 (file)
@@ -218,6 +218,11 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
     ctrl_area->instrs.INTR = 1;
 
 
+    v3_hook_msr(core->vm_info, EFER_MSR, 
+               &v3_handle_efer_read,
+               &v3_handle_efer_write, 
+               core);
+
     if (core->shdw_pg_mode == SHADOW_PAGING) {
        PrintDebug("Creating initial shadow page table\n");
        
@@ -246,10 +251,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
        ctrl_area->cr_reads.cr3 = 1;
        ctrl_area->cr_writes.cr3 = 1;
 
-       v3_hook_msr(core->vm_info, EFER_MSR, 
-                   &v3_handle_efer_read,
-                   &v3_handle_efer_write, 
-                   core);
+
 
        ctrl_area->instrs.INVLPG = 1;
 
@@ -451,11 +453,15 @@ int v3_svm_enter(struct guest_info * info) {
     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); 
     addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0;
 
-    v3_adjust_time(info);
-
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
 
+    // Perform any additional yielding needed for time adjustment
+    v3_adjust_time(info);
+
+    // Update timer devices prior to entering VM.
+    v3_update_timers(info);
+
     // disable global interrupts for vm state transition
     v3_clgi();
 
@@ -503,19 +509,20 @@ int v3_svm_enter(struct guest_info * info) {
     }
 #endif
 
-    v3_update_timers(info);
+    v3_time_enter_vm(info);
     guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
 
     //V3_Print("Calling v3_svm_launch\n");
 
-    v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->cpu_id]);
+    v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->host_cpu_id]);
 
     //V3_Print("SVM Returned: Exit Code: %x, guest_rip=%lx\n", (uint32_t)(guest_ctrl->exit_code), (unsigned long)guest_state->rip);
 
     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
 
-    //PrintDebug("SVM Returned\n");
-    
+    // Immediate exit from VM time bookkeeping
+    v3_time_exit_vm(info);
+
     info->num_exits++;
 
     // Save Guest state from VMCB
index dca1018..9acfbd0 100644 (file)
@@ -204,12 +204,12 @@ static int start_core(void * p)
     struct guest_info * core = (struct guest_info *)p;
 
 
-    PrintDebug("core %u: in start_core (RIP=%p)\n", 
-              core->cpu_id, (void *)(addr_t)core->rip);
+    PrintDebug("virtual core %u/physical core %u: in start_core (RIP=%p)\n", 
+              core->cpu_id, core->host_cpu_id, (void *)(addr_t)core->rip);
 
 
     // JRL: Whoa WTF? cpu_types are tied to the vcoreID????
-    switch (v3_cpu_types[core->cpu_id]) {
+    switch (v3_cpu_types[core->host_cpu_id]) {
 #ifdef CONFIG_SVM
        case V3_SVM_CPU:
        case V3_SVM_REV3_CPU:
@@ -241,73 +241,54 @@ static int start_core(void * p)
 
 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
     uint32_t i;
-#ifdef CONFIG_MULTITHREAD_OS
-    int vcore_id = 0;
-#endif
     uint8_t * core_mask = (uint8_t *)&cpu_mask; // This is to make future expansion easier
     uint32_t avail_cores = 0;
 
-
-
     /// CHECK IF WE ARE MULTICORE ENABLED....
 
     V3_Print("V3 --  Starting VM (%u cores)\n", vm->num_cores);
     V3_Print("CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
 
-    // Check that enough cores are present in the mask to handle vcores
-    for (i = 0; i < MAX_CORES; i++) {
-       int major = i / 8;
-       int minor = i % 8;
-
-       if (core_mask[major] & (0x1 << minor)) {
-           avail_cores++;
-       }
-       
-    }
-    
-    if (vm->num_cores > avail_cores) {
+    if (vm->num_cores > MAX_CORES ) {
        PrintError("Attempted to start a VM with too many cores (vm->num_cores = %d, avail_cores = %d, MAX=%d)\n", vm->num_cores, avail_cores, MAX_CORES);
        return -1;
     }
 
+    if (vm->cores[0].host_cpu_id != 0) {
+       PrintError("First virtual core must run on host core 0.\n");
+       return -1;
+    }
 
 #ifdef CONFIG_MULTITHREAD_OS
     // spawn off new threads, for other cores
-    for (i = 0, vcore_id = 1; (i < MAX_CORES) && (vcore_id < vm->num_cores); i++) {
-       int major = i / 8;
-       int minor = i % 8;
+    for (i = 1; i < vm->num_cores; i++) {
+       struct guest_info *core = &(vm->cores[i]);
+       int major = core->host_cpu_id / 8;
+       int minor = core->host_cpu_id % 8;
        void * core_thread = NULL;
-       struct guest_info * core = &(vm->cores[vcore_id]);
-
-       /* This assumes that the core 0 thread has been mapped to physical core 0 */
-       if (i == V3_Get_CPU()) {
-           // We skip the local CPU, because it is reserved for vcore 0
-           continue;
-       }
-
 
        if ((core_mask[major] & (0x1 << minor)) == 0) {
-           // cpuid not set in cpu_mask
+           PrintError("Host CPU %d not available for virtual core %d; not started\n",
+                      core->host_cpu_id, i);
            continue;
        } 
 
        PrintDebug("Starting virtual core %u on logical core %u\n", 
-                  vcore_id, i);
+                  i, core->host_cpu_id);
        
-       sprintf(core->exec_name, "%s-%u", vm->name, vcore_id);
+       sprintf(core->exec_name, "%s-%u", vm->name, i);
 
        PrintDebug("run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
-                  i, start_core, core, core->exec_name);
+                  core->host_cpu_id, start_core, core, core->exec_name);
 
        // TODO: actually manage these threads instead of just launching them
-       core_thread = V3_CREATE_THREAD_ON_CPU(i, start_core, core, core->exec_name);
+       core_thread = V3_CREATE_THREAD_ON_CPU(core->host_cpu_id, start_core,
+                                             core, core->exec_name);
 
        if (core_thread == NULL) {
            PrintError("Thread launch failed\n");
            return -1;
        }
-
-       vcore_id++;
     }
 #endif
 
@@ -479,7 +460,7 @@ void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
 
 
 int v3_vm_enter(struct guest_info * info) {
-    switch (v3_cpu_types[info->cpu_id]) {
+    switch (v3_cpu_types[info->host_cpu_id]) {
 #ifdef CONFIG_SVM
        case V3_SVM_CPU:
        case V3_SVM_REV3_CPU:
index 50e3b1c..8844dee 100644 (file)
@@ -237,6 +237,7 @@ static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
     vm->mem_size = (addr_t)atoi(memory_str) * 1024 * 1024;
     vm->mem_align = get_alignment(align_str);
 
+
     PrintDebug("Alignment for %lu bytes of memory computed as 0x%x\n", vm->mem_size, vm->mem_align);
 
     if (strcasecmp(vm_class, "PC") == 0) {
@@ -291,7 +292,7 @@ static int determine_paging_mode(struct guest_info * info, v3_cfg_tree_t * core_
 
     if (pg_mode) {
        if ((strcasecmp(pg_mode, "nested") == 0)) {
-           if (v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU) {
+           if (v3_cpu_types[info->host_cpu_id] == V3_SVM_REV3_CPU) {
                info->shdw_pg_mode = NESTED_PAGING;
            } else {
                PrintError("Nested paging not supported on this hardware. Defaulting to shadow paging\n");
@@ -337,10 +338,22 @@ static int determine_paging_mode(struct guest_info * info, v3_cfg_tree_t * core_
 }
 
 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
-
+    char *hcpu;
     if (determine_paging_mode(info, core_cfg))
        return -1;
 
+    hcpu = v3_cfg_val(core_cfg, "hostcpu");
+    if (hcpu) {
+       int req_id = atoi(hcpu);
+       if (req_id < 0) {
+           PrintError("Invalid host core %d requested by"
+                      " virtual cpu %d - ignored.\n", req_id, info->cpu_id);
+       } else {
+               PrintDebug("Assigned host core %d to virtual core %d.\n", info->cpu_id, req_id);
+           info->host_cpu_id = req_id;
+       }
+    } 
+
     v3_init_core(info);
 
     if (info->vm_info->vm_class == V3_PC_VM) {
@@ -457,7 +470,6 @@ struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
     }
 
     num_cores = atoi(v3_cfg_val(cores_cfg, "count"));
-
     if (num_cores == 0) {
        PrintError("No cores specified in configuration\n");
        return NULL;
@@ -483,7 +495,6 @@ struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
        return NULL;
     }
 
-
     V3_Print("Per core configuration\n");
     per_core_cfg = v3_cfg_subtree(cores_cfg, "core");
 
@@ -494,12 +505,14 @@ struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
        info->cpu_id = i;
        info->vm_info = vm;
        info->core_cfg_data = per_core_cfg;
+       info->host_cpu_id = i; // may be overriden by core config
 
        if (pre_config_core(info, per_core_cfg) == -1) {
            PrintError("Error in core %d preconfiguration\n", i);
            return NULL;
        }
 
+
        per_core_cfg = v3_cfg_next_branch(per_core_cfg);
     }
 
index 7d6e381..b27df4b 100644 (file)
@@ -566,15 +566,19 @@ int v3_handle_efer_write(struct guest_info * core, uint_t msr, struct v3_msr src
     
     PrintDebug("EFER Write\n");
     PrintDebug("EFER Write Values: HI=%x LO=%x\n", src.hi, src.lo);
+
     //PrintDebug("Old EFER=%p\n", (void *)*(addr_t*)(shadow_efer));
     
     // We virtualize the guests efer to hide the SVME and LMA bits
     guest_efer->value = src.value;
     
-    
-    // Enable/Disable Syscall
-    shadow_efer->sce = src.value & 0x1;
-    
+    if (core->shdw_pg_mode == SHADOW_PAGING) {
+       // Enable/Disable Syscall
+       shadow_efer->sce = src.value & 0x1;
+    } else if (core->shdw_pg_mode == NESTED_PAGING) {
+       *(uint64_t *)shadow_efer = src.value;
+       shadow_efer->svme = 1;
+    }
     return 0;
 }
 
index bda3b1f..7d90d3e 100644 (file)
 static struct v3_packet_hooks * packet_hooks = 0;
 
 int V3_send_raw(const char * pkt, uint32_t len) {
-    V3_ASSERT(packet_hooks);
-    V3_ASSERT(packet_hooks->send);
+    if(packet_hooks != NULL && packet_hooks->send != NULL){
+       return packet_hooks->send(pkt, len, NULL);
+    }
 
-    return packet_hooks->send(pkt, len, NULL);
+    return -1;
 }
 
 
 int V3_packet_add_recver(const char * mac, struct v3_vm_info * vm){
+    if(packet_hooks != NULL && packet_hooks->add_recver != NULL){
+        return packet_hooks->add_recver(mac, vm);
+    }
 
-    return packet_hooks->add_recver(mac, vm);
+    return -1;
 }
 
 
 int V3_packet_del_recver(const char * mac, struct v3_vm_info * vm){
+    if(packet_hooks != NULL && packet_hooks->del_recver != NULL){
+        return packet_hooks->del_recver(mac, vm);
+    }
 
-    return packet_hooks->del_recver(mac, vm);
+    return -1;
 }
 
 void V3_Init_Packet(struct v3_packet_hooks * hooks) {
index 7d9ea4c..3b41305 100644 (file)
@@ -32,11 +32,11 @@ static int cpuid_fn(struct guest_info * core, uint32_t cpuid,
 
     *eax = *(uint32_t *)"V3V";
 
-    if ((v3_cpu_types[core->cpu_id] == V3_SVM_CPU) || 
-       (v3_cpu_types[core->cpu_id] == V3_SVM_REV3_CPU)) {
+    if ((v3_cpu_types[core->host_cpu_id] == V3_SVM_CPU) || 
+       (v3_cpu_types[core->host_cpu_id] == V3_SVM_REV3_CPU)) {
        *ebx = *(uint32_t *)"SVM";
-    } else if ((v3_cpu_types[core->cpu_id] == V3_VMX_CPU) || 
-              (v3_cpu_types[core->cpu_id] == V3_VMX_EPT_CPU)) {
+    } else if ((v3_cpu_types[core->host_cpu_id] == V3_VMX_CPU) || 
+              (v3_cpu_types[core->host_cpu_id] == V3_VMX_EPT_CPU)) {
        *ebx = *(uint32_t *)"VMX";
     }
 
index 51fbba7..dea7cdb 100644 (file)
@@ -18,8 +18,8 @@
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#include <palacios/vmm_time.h>
 #include <palacios/vmm.h>
+#include <palacios/vmm_time.h>
 #include <palacios/vm_guest.h>
 
 #ifndef CONFIG_DEBUG_TIME
@@ -86,44 +86,112 @@ int v3_start_time(struct guest_info * info) {
     uint64_t t = v3_get_host_time(&info->time_state); 
 
     PrintDebug("Starting initial guest time as %llu\n", t);
+    info->time_state.enter_time = 0;
+    info->time_state.exit_time = t; 
     info->time_state.last_update = t;
     info->time_state.initial_time = t;
     info->yield_start_cycle = t;
     return 0;
 }
 
-// If the guest is supposed to run slower than the host, yield out until
-// the host time is appropriately far along;
+// Control guest time in relation to host time so that the two stay 
+// appropriately synchronized to the extent possible. 
 int v3_adjust_time(struct guest_info * info) {
     struct vm_time * time_state = &(info->time_state);
+    uint64_t host_time, target_host_time;
+    uint64_t guest_time, target_guest_time, old_guest_time;
+    uint64_t guest_elapsed, host_elapsed, desired_elapsed;
 
-    if (time_state->host_cpu_freq == time_state->guest_cpu_freq) {
-       time_state->guest_host_offset = 0;
-    } else {
-       uint64_t guest_time, guest_elapsed, desired_elapsed;
-       uint64_t host_time, target_host_time;
+    /* Compute the target host time given how much time has *already*
+     * passed in the guest */
+    guest_time = v3_get_guest_time(time_state);
+    guest_elapsed = (guest_time - time_state->initial_time);
+    desired_elapsed = (guest_elapsed * time_state->host_cpu_freq) / time_state->guest_cpu_freq;
+    target_host_time = time_state->initial_time + desired_elapsed;
+
+    /* Now, let the host run while the guest is stopped to make the two
+     * sync up. */
+    host_time = v3_get_host_time(time_state);
+    old_guest_time = v3_get_guest_time(time_state);
+    while (target_host_time > host_time) {
+       v3_yield(info);
+       host_time = v3_get_host_time(time_state);
+    }
+    guest_time = v3_get_guest_time(time_state);
+    // We do *not* assume the guest timer was paused in the VM. If it was
+    // this offseting is 0. If it wasn't we need this.
+    v3_offset_time(info, (sint64_t)old_guest_time - (sint64_t)guest_time);
+
+    /* Now the host may have gotten ahead of the guest because
+     * yielding is a coarse grained thing. Figure out what guest time
+     * we want to be at, and use the use the offsetting mechanism in 
+     * the VMM to make the guest run forward. We limit *how* much we skew 
+     * it forward to prevent the guest time making large jumps, 
+     * however. */
+    host_elapsed = host_time - time_state->initial_time;
+    desired_elapsed = (host_elapsed * time_state->guest_cpu_freq) / time_state->host_cpu_freq;
+    target_guest_time = time_state->initial_time + desired_elapsed;
+
+    if (guest_time < target_guest_time) {
+       uint64_t max_skew, desired_skew, skew;
+
+       if (time_state->enter_time) {
+           max_skew = (time_state->exit_time - time_state->enter_time)/10;
+       } else {
+           max_skew = 0;
+       }
+       desired_skew = target_guest_time - guest_time;
+       skew = desired_skew > max_skew ? max_skew : desired_skew;
+/*     PrintDebug("Guest %llu cycles behind where it should be.\n",
+                  desired_skew);
+       PrintDebug("Limit on forward skew is %llu. Skewing forward %llu.\n",
+                  max_skew, skew); */
+       
+       v3_offset_time(info, skew);
+    }
+    
+    return 0;
+}
 
-       guest_time = v3_get_guest_time(time_state);
+/* Called immediately upon entry in the the VMM */
+int 
+v3_time_exit_vm( struct guest_info * info ) 
+{
+    struct vm_time * time_state = &(info->time_state);
+    
+    time_state->exit_time = v3_get_host_time(time_state);
 
-       /* Compute what host time this guest time should correspond to. */
-       guest_elapsed = (guest_time - time_state->initial_time);
-       desired_elapsed = (guest_elapsed * time_state->host_cpu_freq) / time_state->guest_cpu_freq;
-       target_host_time = time_state->initial_time + desired_elapsed;
+    return 0;
+}
 
-       /* Yield until that host time is reached */
-       host_time = v3_get_host_time(time_state);
+/* Called immediately prior to entry to the VM */
+int 
+v3_time_enter_vm( struct guest_info * info )
+{
+    struct vm_time * time_state = &(info->time_state);
+    uint64_t guest_time, host_time;
 
-       while (host_time < target_host_time) {
-           v3_yield(info);
-           host_time = v3_get_host_time(time_state);
-       }
+    guest_time = v3_get_guest_time(time_state);
+    host_time = v3_get_host_time(time_state);
+    time_state->enter_time = host_time;
+    time_state->guest_host_offset = guest_time - host_time;
 
-       time_state->guest_host_offset = (sint64_t)guest_time - (sint64_t)host_time;
-    }
+    // Because we just modified the offset - shouldn't matter as this should be 
+    // the last time-related call prior to entering the VMM, but worth it 
+    // just in case.
+    time_state->exit_time = host_time; 
 
     return 0;
 }
-
+       
+int v3_offset_time( struct guest_info * info, sint64_t offset )
+{
+    struct vm_time * time_state = &(info->time_state);
+//    PrintDebug("Adding additional offset of %lld to guest time.\n", offset);
+    time_state->guest_host_offset += offset;
+    return 0;
+}
+          
 struct v3_timer * v3_add_timer(struct guest_info * info, 
                               struct v3_timer_ops * ops, 
                               void * private_data) {
@@ -149,15 +217,16 @@ int v3_remove_timer(struct guest_info * info, struct v3_timer * timer) {
 }
 
 void v3_update_timers(struct guest_info * info) {
+    struct vm_time *time_state = &info->time_state;
     struct v3_timer * tmp_timer;
     uint64_t old_time = info->time_state.last_update;
-    uint64_t cycles;
+    sint64_t cycles;
 
-    info->time_state.last_update = v3_get_guest_time(&info->time_state);
-    cycles = info->time_state.last_update - old_time;
+    time_state->last_update = v3_get_guest_time(time_state);
+    cycles = time_state->last_update - old_time;
 
-    list_for_each_entry(tmp_timer, &(info->time_state.timers), timer_link) {
-       tmp_timer->ops->update_timer(info, cycles, info->time_state.guest_cpu_freq, tmp_timer->private_data);
+    list_for_each_entry(tmp_timer, &(time_state->timers), timer_link) {
+       tmp_timer->ops->update_timer(info, cycles, time_state->guest_cpu_freq, tmp_timer->private_data);
     }
 }
 
@@ -213,9 +282,10 @@ int v3_rdtscp(struct guest_info * info) {
 
 
 int v3_handle_rdtscp(struct guest_info * info) {
+  PrintDebug("Handling virtual RDTSCP call.\n");
 
     v3_rdtscp(info);
-    
+
     info->vm_regs.rax &= 0x00000000ffffffffLL;
     info->vm_regs.rcx &= 0x00000000ffffffffLL;
     info->vm_regs.rdx &= 0x00000000ffffffffLL;
@@ -321,9 +391,10 @@ void v3_init_time_core(struct guest_info * info) {
        time_state->guest_cpu_freq = atoi(khz);
        PrintDebug("Core %d CPU frequency requested at %d khz.\n", 
                   info->cpu_id, time_state->guest_cpu_freq);
-    }
+    } 
     
-    if ((khz == NULL) || (time_state->guest_cpu_freq > time_state->host_cpu_freq)) {
+    if ((khz == NULL) || (time_state->guest_cpu_freq <= 0) 
+       || (time_state->guest_cpu_freq > time_state->host_cpu_freq)) {
        time_state->guest_cpu_freq = time_state->host_cpu_freq;
     }
 
index 6baef5a..4ce9b04 100644 (file)
@@ -101,46 +101,47 @@ static struct {
 
 #ifdef CONFIG_DEBUG_VNET
 static inline void mac_to_string(uint8_t * mac, char * buf) {
-    snprintf(buf, 100, "%d:%d:%d:%d:%d:%d", 
+    snprintf(buf, 100, "%2x:%2x:%2x:%2x:%2x:%2x", 
             mac[0], mac[1], mac[2],
             mac[3], mac[4], mac[5]);
 }
 
-static void print_route(struct vnet_route_info * route){
+static void print_route(struct v3_vnet_route * route){
     char str[50];
 
-    mac_to_string(route->route_def.src_mac, str);
+    mac_to_string(route->src_mac, str);
     PrintDebug("Src Mac (%s),  src_qual (%d)\n", 
-              str, route->route_def.src_mac_qual);
-    mac_to_string(route->route_def.dst_mac, str);
+              str, route->src_mac_qual);
+    mac_to_string(route->dst_mac, str);
     PrintDebug("Dst Mac (%s),  dst_qual (%d)\n", 
-              str, route->route_def.dst_mac_qual);
+              str, route->dst_mac_qual);
     PrintDebug("Src dev id (%d), src type (%d)", 
-              route->route_def.src_id, 
-              route->route_def.src_type);
+              route->src_id, 
+              route->src_type);
     PrintDebug("Dst dev id (%d), dst type (%d)\n", 
-              route->route_def.dst_id, 
-              route->route_def.dst_type);
-    if (route->route_def.dst_type == LINK_INTERFACE) {
-       PrintDebug("dst_dev (%p), dst_dev_id (%d), dst_dev_ops(%p), dst_dev_data (%p)\n",
-              route->dst_dev,
-              route->dst_dev->dev_id,
-              (void *)&(route->dst_dev->dev_ops),
-              route->dst_dev->private_data);
-    }
+              route->dst_id, 
+              route->dst_type);
 }
 
 static void dump_routes(){
-       struct vnet_route_info *route;
+    struct vnet_route_info *route;
 
-       int i = 0;
-       PrintDebug("\n========Dump routes starts ============\n");
-       list_for_each_entry(route, &(vnet_state.routes), node) {
-           PrintDebug("\nroute %d:\n", i++);
+    int i = 0;
+    PrintDebug("\n========Dump routes starts ============\n");
+    list_for_each_entry(route, &(vnet_state.routes), node) {
+       PrintDebug("\nroute %d:\n", i++);
                
-           print_route(route);
+       print_route(&(route->route_def));
+       if (route->route_def.dst_type == LINK_INTERFACE) {
+           PrintDebug("dst_dev (%p), dst_dev_id (%d), dst_dev_ops(%p), dst_dev_data (%p)\n",
+               route->dst_dev,
+               route->dst_dev->dev_id,
+               (void *)&(route->dst_dev->dev_ops),
+               route->dst_dev->private_data);
        }
-       PrintDebug("\n========Dump routes end ============\n");
+    }
+
+    PrintDebug("\n========Dump routes end ============\n");
 }
 
 #endif
@@ -202,14 +203,33 @@ static struct vnet_dev * dev_by_mac(uint8_t * mac) {
     struct vnet_dev * dev = NULL; 
     
     list_for_each_entry(dev, &(vnet_state.devs), node) {
-       if (!memcmp(dev->mac_addr, mac, ETH_ALEN))
+       if (!compare_ethaddr(dev->mac_addr, mac)){
            return dev;
+       }
+
+       char *dmac = dev->mac_addr;
+       PrintDebug("device %d: %2x:%2x:%2x:%2x:%2x:%2x\n", dev->dev_id, dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]);
     }
 
     return NULL;
 }
 
 
+int v3_vnet_find_dev(uint8_t  * mac) {
+    struct vnet_dev * dev = NULL;
+
+    PrintDebug("find_dev: %2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+    dev = dev_by_mac(mac);
+
+    if(dev != NULL) {
+       return dev->dev_id;
+    }
+
+    return -1;
+}
+
+
 int v3_vnet_add_route(struct v3_vnet_route route) {
     struct vnet_route_info * new_route = NULL;
     unsigned long flags; 
@@ -217,8 +237,8 @@ int v3_vnet_add_route(struct v3_vnet_route route) {
     new_route = (struct vnet_route_info *)V3_Malloc(sizeof(struct vnet_route_info));
     memset(new_route, 0, sizeof(struct vnet_route_info));
 
-    PrintDebug("VNET/P Core: add_route_entry: dst_id: %d, dst_type: %d\n",
-              route.dst_id, route.dst_type);   
+    PrintDebug("VNET/P Core: add_route_entry:\n");
+    print_route(&route);
     
     memcpy(new_route->route_def.src_mac, route.src_mac, ETH_ALEN);
     memcpy(new_route->route_def.dst_mac, route.dst_mac, ETH_ALEN);
@@ -226,31 +246,18 @@ int v3_vnet_add_route(struct v3_vnet_route route) {
     new_route->route_def.dst_mac_qual = route.dst_mac_qual;
     new_route->route_def.dst_type = route.dst_type;
     new_route->route_def.src_type = route.src_type;
-       
-    if(route.dst_id == -1){
-       if (new_route->route_def.dst_type == LINK_INTERFACE) {
-           new_route->dst_dev = dev_by_mac(route.dst_mac);
-       }
-       new_route->route_def.dst_id = new_route->dst_dev->dev_id;
-    } else {
-       new_route->route_def.dst_id = route.dst_id;
-       if (new_route->route_def.dst_type == LINK_INTERFACE) {
-           new_route->dst_dev = dev_by_id(new_route->route_def.dst_id);
-       }
+    new_route->route_def.src_id = route.src_id;
+    new_route->route_def.dst_id = route.dst_id;
+
+    if (new_route->route_def.dst_type == LINK_INTERFACE) {
+       new_route->dst_dev = dev_by_id(new_route->route_def.dst_id);
     }
 
-    if(route.src_id == -1){
-       if (new_route->route_def.src_type == LINK_INTERFACE) {
-           new_route->src_dev = dev_by_mac(route.src_mac);
-       }
-       new_route->route_def.src_id = new_route->src_dev->dev_id;
-    } else {
-       new_route->route_def.src_id = route.src_id;
-       if (new_route->route_def.src_type == LINK_INTERFACE) {
-           new_route->src_dev = dev_by_id(new_route->route_def.src_id);
-       }
+    if (new_route->route_def.src_type == LINK_INTERFACE) {
+       new_route->src_dev = dev_by_id(new_route->route_def.src_id);
     }
 
+
     flags = v3_lock_irqsave(vnet_state.lock);
 
     list_add(&(new_route->node), &(vnet_state.routes));
@@ -299,8 +306,8 @@ static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
     int max_rank = 0;
     struct list_head match_list;
     struct eth_hdr * hdr = (struct eth_hdr *)(pkt->data);
-    uint8_t src_type = pkt->src_type;
-    uint32_t src_link = pkt->src_id;
+ //   uint8_t src_type = pkt->src_type;
+ //   uint32_t src_link = pkt->src_id;
 
 #ifdef CONFIG_DEBUG_VNET
     {
@@ -332,14 +339,15 @@ static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
     list_for_each_entry(route, &(vnet_state.routes), node) {
        struct v3_vnet_route * route_def = &(route->route_def);
 
+/*
        // CHECK SOURCE TYPE HERE
        if ( (route_def->src_type != LINK_ANY) && 
             ( (route_def->src_type != src_type) || 
               ( (route_def->src_id != src_link) &&
-                (route_def->src_id != (uint32_t)-1)))) {
+                (route_def->src_id != -1)))) {
            continue;
        }
-
+*/
 
        if ((route_def->dst_mac_qual == MAC_ANY) &&
            (route_def->src_mac_qual == MAC_ANY)) {      
@@ -573,29 +581,6 @@ static void free_routes(){
     }
 }
 
-/* TODO: Round-bin or ?? */
-void  v3_vnet_poll(struct v3_vm_info * vm){
-    struct vnet_dev * dev = NULL; 
-    struct vnet_brg_dev *bridge = vnet_state.bridge;
-
-    list_for_each_entry(dev, &(vnet_state.devs), node) {
-       if(dev->mode == VMM_DRIVERN && 
-           dev->active && 
-           dev->vm == vm){
-           
-           dev->dev_ops.poll(vm, dev->private_data);
-       }
-    }
-
-    if (bridge != NULL && 
-         bridge->active && 
-         bridge->mode == VMM_DRIVERN) {
-       
-       bridge->brg_ops.poll(bridge->vm, bridge->private_data);
-    }
-       
-}
-
 int v3_vnet_add_bridge(struct v3_vm_info * vm,
                       struct v3_vnet_bridge_ops * ops,
                       uint8_t type,
index f3641be..4b4a8f6 100644 (file)
@@ -41,6 +41,8 @@
 #define V3_XML_DUP     0x20 // attribute name and value are strduped
 //
 
+static char * V3_XML_NIL[] = { NULL }; // empty, null terminated array of strings
+
 
 #define V3_XML_WS   "\t\r\n "  // whitespace
 #define V3_XML_ERRL 128        // maximum error string length
@@ -201,7 +203,9 @@ struct v3_xml * v3_xml_get(struct v3_xml * xml, ...) {
 // sets a flag for the given tag and returns the tag
 static struct v3_xml * v3_xml_set_flag(struct v3_xml * xml, short flag)
 {
-    if (xml) xml->flags |= flag;
+    if (xml) {
+       xml->flags |= flag;
+    }
     return xml;
 }
 
@@ -454,7 +458,7 @@ static struct v3_xml * v3_xml_new(const char * name) {
 }
 
 // inserts an existing tag into an v3_xml structure
-static struct v3_xml * v3_xml_insert(struct v3_xml * xml, struct v3_xml * dest, size_t off) {
+struct v3_xml * v3_xml_insert(struct v3_xml * xml, struct v3_xml * dest, size_t off) {
     struct v3_xml * cur, * prev, * head;
 
     xml->next = NULL;
@@ -900,3 +904,294 @@ void v3_xml_free(struct v3_xml * xml) {
     V3_Free(xml);
 }
 
+
+
+
+
+
+
+// sets the character content for the given tag and returns the tag
+struct v3_xml *  v3_xml_set_txt(struct v3_xml * xml, const char *txt) {
+    if (! xml) {
+       return NULL;
+    }
+
+    if (xml->flags & V3_XML_TXTM) {
+       // existing txt was malloced
+       V3_Free(xml->txt); 
+    }
+
+    xml->flags &= ~V3_XML_TXTM;
+    xml->txt = (char *)txt;
+    return xml;
+}
+
+// Sets the given tag attribute or adds a new attribute if not found. A value
+// of NULL will remove the specified attribute. Returns the tag given.
+struct v3_xml * v3_xml_set_attr(struct v3_xml * xml, const char * name, const char * value) {
+    int l = 0;
+    int c;
+
+    if (! xml) {
+       return NULL;
+    }
+
+    while (xml->attr[l] && strcmp(xml->attr[l], name)) {
+       l += 2;
+    }
+
+    if (! xml->attr[l]) { 
+       // not found, add as new attribute
+        
+       if (! value) {
+           // nothing to do
+           return xml;
+       }
+       
+       if (xml->attr == V3_XML_NIL) { 
+           // first attribute
+            xml->attr = V3_Malloc(4 * sizeof(char *));
+
+           // empty list of malloced names/vals
+            xml->attr[1] = strdup(""); 
+        } else {
+           xml->attr = tmp_realloc(xml->attr, l * sizeof(char *), (l + 4) * sizeof(char *));
+       }
+
+       // set attribute name
+        xml->attr[l] = (char *)name; 
+
+       // null terminate attribute list
+        xml->attr[l + 2] = NULL; 
+
+        xml->attr[l + 3] = tmp_realloc(xml->attr[l + 1],
+                                      strlen(xml->attr[l + 1]),
+                                      (c = strlen(xml->attr[l + 1])) + 2);
+
+       // set name/value as not malloced
+        strcpy(xml->attr[l + 3] + c, " "); 
+
+        if (xml->flags & V3_XML_DUP) {
+           xml->attr[l + 3][c] = V3_XML_NAMEM;
+       }
+    } else if (xml->flags & V3_XML_DUP) {
+       // name was strduped
+       V3_Free((char *)name); 
+    }
+
+
+    // find end of attribute list
+    for (c = l; xml->attr[c]; c += 2); 
+
+    if (xml->attr[c + 1][l / 2] & V3_XML_TXTM) {
+       //old val
+       V3_Free(xml->attr[l + 1]); 
+    }
+
+    if (xml->flags & V3_XML_DUP) {
+       xml->attr[c + 1][l / 2] |= V3_XML_TXTM;
+    } else {
+       xml->attr[c + 1][l / 2] &= ~V3_XML_TXTM;
+    }
+
+
+    if (value) {
+       // set attribute value
+       xml->attr[l + 1] = (char *)value; 
+    } else { 
+       // remove attribute
+        
+       if (xml->attr[c + 1][l / 2] & V3_XML_NAMEM) {
+           V3_Free(xml->attr[l]);
+       }
+
+        memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*));
+
+        xml->attr = tmp_realloc(xml->attr, c * sizeof(char *), (c + 2) * sizeof(char *));
+
+       // fix list of which name/vals are malloced
+        memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1,
+                (c / 2) - (l / 2)); 
+    }
+
+    // clear strdup() flag
+    xml->flags &= ~V3_XML_DUP; 
+
+    return xml;
+}
+
+// removes a tag along with its subtags without freeing its memory
+struct v3_xml * v3_xml_cut(struct v3_xml * xml) {
+    struct v3_xml * cur;
+
+    if (! xml) {
+       // nothing to do
+       return NULL; 
+    }
+
+    if (xml->next) {
+       // patch sibling list
+       xml->next->sibling = xml->sibling; 
+    }
+
+
+    if (xml->parent) { 
+       // not root tag
+
+       // find head of subtag list
+        cur = xml->parent->child; 
+
+        if (cur == xml) {
+           // first subtag
+           xml->parent->child = xml->ordered; 
+       } else { 
+       // not first subtag
+
+            while (cur->ordered != xml) {
+               cur = cur->ordered;
+           }
+
+           // patch ordered list
+            cur->ordered = cur->ordered->ordered; 
+
+           // go back to head of subtag list
+            cur = xml->parent->child; 
+
+            if (strcmp(cur->name, xml->name)) {
+               // not in first sibling list
+
+                while (strcmp(cur->sibling->name, xml->name)) {
+                    cur = cur->sibling;
+               }
+
+                if (cur->sibling == xml) { 
+                   // first of a sibling list
+                    cur->sibling = (xml->next) ? xml->next
+                                               : cur->sibling->sibling;
+                } else {
+                   // not first of a sibling list
+                   cur = cur->sibling;
+               }
+            }
+
+            while (cur->next && cur->next != xml) {
+               cur = cur->next;
+           }
+
+            if (cur->next) {
+               // patch next list
+               cur->next = cur->next->next; 
+           }
+        } 
+   }
+    xml->ordered = xml->sibling = xml->next = NULL;
+    return xml;
+}
+
+
+
+
+/* ************************** */
+/* *** XML ENCODING       *** */
+/* ************************** */
+
+// Encodes ampersand sequences appending the results to *dst, reallocating *dst
+// if length excedes max. a is non-zero for attribute encoding. Returns *dst
+static char *ampencode(const char *s, size_t len, char **dst, size_t *dlen,
+                      size_t * max, short a)
+{
+    const char * e;
+    
+    for (e = s + len; s != e; s++) {
+        while (*dlen + 10 > *max) *dst = tmp_realloc(*dst, *max, *max += V3_XML_BUFSIZE);
+
+        switch (*s) {
+        case '\0': return *dst;
+        case '&': *dlen += sprintf(*dst + *dlen, "&amp;"); break;
+        case '<': *dlen += sprintf(*dst + *dlen, "&lt;"); break;
+        case '>': *dlen += sprintf(*dst + *dlen, "&gt;"); break;
+        case '"': *dlen += sprintf(*dst + *dlen, (a) ? "&quot;" : "\""); break;
+        case '\n': *dlen += sprintf(*dst + *dlen, (a) ? "&#xA;" : "\n"); break;
+        case '\t': *dlen += sprintf(*dst + *dlen, (a) ? "&#x9;" : "\t"); break;
+        case '\r': *dlen += sprintf(*dst + *dlen, "&#xD;"); break;
+        default: (*dst)[(*dlen)++] = *s;
+        }
+    }
+    return *dst;
+}
+
+
+
+// Recursively converts each tag to xml appending it to *s. Reallocates *s if
+// its length excedes max. start is the location of the previous tag in the
+// parent tag's character content. Returns *s.
+static char *toxml_r(struct v3_xml * xml, char **s, size_t *len, size_t *max,
+                    size_t start, char ***attr) {
+    int i, j;
+    char *txt = (xml->parent) ? xml->parent->txt : "";
+    size_t off = 0;
+
+    // parent character content up to this tag
+    *s = ampencode(txt + start, xml->off - start, s, len, max, 0);
+
+    while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+        *s = tmp_realloc(*s, *max, *max += V3_XML_BUFSIZE);
+
+    *len += sprintf(*s + *len, "<%s", xml->name); // open tag
+    for (i = 0; xml->attr[i]; i += 2) { // tag attributes
+        if (v3_xml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue;
+        while (*len + strlen(xml->attr[i]) + 7 > *max) // reallocate s
+            *s = tmp_realloc(*s, *max, *max += V3_XML_BUFSIZE);
+
+        *len += sprintf(*s + *len, " %s=\"", xml->attr[i]);
+        ampencode(xml->attr[i + 1], -1, s, len, max, 1);
+        *len += sprintf(*s + *len, "\"");
+    }
+
+    for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++);
+    for (j = 1; attr[i] && attr[i][j]; j += 3) { // default attributes
+        if (! attr[i][j + 1] || v3_xml_attr(xml, attr[i][j]) != attr[i][j + 1])
+            continue; // skip duplicates and non-values
+        while (*len + strlen(attr[i][j]) + 7 > *max) // reallocate s
+            *s = tmp_realloc(*s, *max, *max += V3_XML_BUFSIZE);
+
+        *len += sprintf(*s + *len, " %s=\"", attr[i][j]);
+        ampencode(attr[i][j + 1], -1, s, len, max, 1);
+        *len += sprintf(*s + *len, "\"");
+    }
+    *len += sprintf(*s + *len, ">");
+
+    *s = (xml->child) ? toxml_r(xml->child, s, len, max, 0, attr) //child
+                      : ampencode(xml->txt, -1, s, len, max, 0);  //data
+    
+    while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+        *s = tmp_realloc(*s, *max, *max += V3_XML_BUFSIZE);
+
+    *len += sprintf(*s + *len, "</%s>", xml->name); // close tag
+
+    while (txt[off] && off < xml->off) off++; // make sure off is within bounds
+    return (xml->ordered) ? toxml_r(xml->ordered, s, len, max, off, attr)
+                          : ampencode(txt + off, -1, s, len, max, 0);
+}
+
+// Converts an xml structure back to xml. Returns a string of xml data that
+// must be freed.
+char * v3_xml_tostr(struct v3_xml * xml) {
+    struct v3_xml * p = (xml) ? xml->parent : NULL;
+    struct v3_xml * o = (xml) ? xml->ordered : NULL;
+    struct v3_xml_root * root = (struct v3_xml_root *)xml;
+    size_t len = 0, max = V3_XML_BUFSIZE;
+    char *s = strcpy(V3_Malloc(max), "");
+
+    if (! xml || ! xml->name) return tmp_realloc(s, max, len + 1);
+    while (root->xml.parent) root = (struct v3_xml_root *)root->xml.parent; // root tag
+
+
+    xml->parent = xml->ordered = NULL;
+    s = toxml_r(xml, &s, &len, &max, 0, root->attr);
+    xml->parent = p;
+    xml->ordered = o;
+
+
+    return tmp_realloc(s, max, len + 1);
+}
index f71df0a..ef0f614 100644 (file)
@@ -28,6 +28,7 @@
 #include <palacios/vmm_lowlevel.h>
 #include <palacios/vmm_ctrl_regs.h>
 #include <palacios/vmm_config.h>
+#include <palacios/vmm_time.h>
 #include <palacios/vm_guest_mem.h>
 #include <palacios/vmm_direct_paging.h>
 #include <palacios/vmx_io.h>
@@ -662,11 +663,11 @@ int v3_vmx_enter(struct guest_info * info) {
     // Conditionally yield the CPU if the timeslice has expired
     v3_yield_cond(info);
 
-    /* If this guest is frequency-lagged behind host time, wait 
-     * for the appropriate host time before resuming the guest. */
+    // Perform any additional yielding needed for time adjustment
     v3_adjust_time(info);
 
-    // v3_print_guest_state(info);
+    // Update timer devices prior to entering VM.
+    v3_update_timers(info);
 
     // disable global interrupts for vm state transition
     v3_disable_ints();
@@ -688,7 +689,8 @@ int v3_vmx_enter(struct guest_info * info) {
        vmcs_write(VMCS_GUEST_CR3, guest_cr3);
     }
 
-    v3_update_timers(info);
+    // Perform last-minute time bookkeeping prior to entering the VM
+    v3_time_enter_vm(info);
 
     tsc_offset_high = (uint32_t)((v3_tsc_host_offset(&info->time_state) >> 32) & 0xffffffff);
     tsc_offset_low = (uint32_t)(v3_tsc_host_offset(&info->time_state) & 0xffffffff);
@@ -713,6 +715,9 @@ int v3_vmx_enter(struct guest_info * info) {
        return -1;
     }
 
+    // Immediate exit from VM time bookkeeping
+    v3_time_exit_vm(info);
+
     info->num_exits++;
 
     /* Update guest state */
diff --git a/test/geekos_test_vm/build/depend.mak b/test/geekos_test_vm/build/depend.mak
deleted file mode 100644 (file)
index e69de29..0000000