<div dir="ltr">Hi<div><br></div><div>Thanks for the submission. My comments are going to be very general.</div><div><br></div><div>+ Can you document which version of the FreeBSD source files this is based</div><div>up? Perhaps an svn revision/branch and a list of the exact files in their source</div><div>tree? This has been a historical problem when trying to track future changes.</div><div><br></div><div>+ What were the nature of the rtems specific changes? Are they cleanly</div><div>ifdef'ed so a diff against the original FreeBSD source shows ifdef additions</div><div>and blocks of RTEMS specific code added?</div><div><br></div><div>+ I didn't see any instructions on how to use this. What type of setup is</div><div>needed?</div><div><br></div><div>I am pretty sure I actually reviewed a conference paper on this work and </div><div>am excited to see it submitted. Let's just make it top notch on usability</div><div>and maintainability.</div><div><br></div><div>--joel</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Mar 29, 2016 at 8:47 AM, Jinhyun <span dir="ltr"><<a href="mailto:jinhyun@konkuk.ac.kr" target="_blank">jinhyun@konkuk.ac.kr</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">diff --git a/c/src/lib/libbsp/i386/pc386/Makefile.am<br>
b/c/src/lib/libbsp/i386/pc386/Makefile.am<br>
index d9af7dd..da50c67 100644<br>
--- a/c/src/lib/libbsp/i386/pc386/Makefile.am<br>
+++ b/c/src/lib/libbsp/i386/pc386/Makefile.am<br>
@@ -232,6 +232,19 @@ noinst_PROGRAMS += 3c509.rel<br>
 3c509_rel_LDFLAGS += -Wl,--undefined=ep_board<br>
 endif<br>
<br>
+if HAS_NETWORKING<br>
+vtnet_CPPFLAGS = -D__INSIDE_RTEMS_BSD_TCPIP_STACK__<br>
+noinst_PROGRAMS += vtnet.rel<br>
+vtnet_rel_SOURCES = virtio/if_vtnet.c<br>
+vtnet_rel_SOURCES += virtio/if_vtnet.h<br>
+vtnet_rel_SOURCES += virtio/virtio_pci.c<br>
+vtnet_rel_SOURCES += virtio/virtio_pci.h<br>
+vtnet_rel_SOURCES += virtio/virtio.c<br>
+vtnet_rel_SOURCES += virtio/virtio.h<br>
+vtnet_rel_CPPFLAGS = $(AM_CPPFLAGS) $(vtnet_CPPFLAGS)<br>
+vtnet_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)<br>
+endif<br>
+<br>
 libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/cache.rel<br>
 libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/page.rel<br>
 libbsp_a_LIBADD += ../../../libcpu/@RTEMS_CPU@/score.rel<br>
@@ -246,6 +259,7 @@ if HAS_NETWORKING<br>
 libbsp_a_LIBADD += ne2000.rel<br>
 libbsp_a_LIBADD += wd8003.rel<br>
 libbsp_a_LIBADD += 3c509.rel<br>
+libbsp_a_LIBADD += vtnet.rel<br>
 endif<br>
<br>
 EXTRA_DIST += HOWTO<br>
diff --git a/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.c<br>
b/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.c<br>
new file mode 100644<br>
index 0000000..4fcd92c<br>
--- /dev/null<br>
+++ b/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.c<br>
@@ -0,0 +1,1032 @@<br>
+/**<br>
+ * @file if_vtnet.c<br>
+ * @brief Driver for virtio network devices<br>
+ */<br>
+<br>
+/*<br>
+ * Copyright (c) 2016 Jin-Hyun Kim <<a href="mailto:jinhyun@konkuk.ac.kr">jinhyun@konkuk.ac.kr</a>><br>
+ *   and Hyun-Wook Jin <<a href="mailto:jinh@konkuk.ac.kr">jinh@konkuk.ac.kr</a>><br>
+ * Ported from FreeBSD to RTEMS March 16, <a href="http://sslab.konkuk.ac.kr" rel="noreferrer" target="_blank">http://sslab.konkuk.ac.kr</a><br>
+ *<br>
+ * The license and distribution terms for this file may be<br>
+ * found in the file LICENSE in this distribution or at<br>
+ * <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
+ */<br>
+<br>
+/*-<br>
+ * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org><br>
+ * All rights reserved.<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice unmodified, this list of conditions, and the following<br>
+ *    disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR<br>
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED<br>
WARRANTIES<br>
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.<br>
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,<br>
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT<br>
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF<br>
USE,<br>
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY<br>
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF<br>
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br>
+ *<br>
+ */<br>
+<br>
+#include <rtems.h><br>
+#include <rtems/rtems_bsdnet.h><br>
+<br>
+#include <bsp.h><br>
+#include <bsp/irq.h><br>
+<br>
+#include <sys/mbuf.h><br>
+#include <sys/param.h><br>
+#include <sys/socket.h><br>
+#include <sys/sockio.h><br>
+#include <sys/systm.h><br>
+<br>
+#include <net/if.h><br>
+<br>
+#include <netinet/in.h><br>
+#include <netinet/if_ether.h><br>
+<br>
+#include <pcibios.h><br>
+<br>
+#include "virtio.h"<br>
+#include "virtio_pci.h"<br>
+#include "if_vtnet.h"<br>
+<br>
+static struct vtnet_softc vtnet_softc;<br>
+static rtems_interval     vtnet_ticksPerSecond;<br>
+<br>
+int rtems_vtnet_driver_attach(<br>
+  struct rtems_bsdnet_ifconfig *config,<br>
+  int                           attaching<br>
+)<br>
+{<br>
+  struct vtnet_softc *sc;<br>
+  int                 ret;<br>
+<br>
+  printk( "rtems_vtnet_driver_attach start\n" );<br>
+<br>
+  sc = &vtnet_softc;<br>
+  memset( sc, 0, sizeof( struct vtnet_softc ) );<br>
+<br>
+  /* Set up timing values */<br>
+  vtnet_ticksPerSecond = rtems_clock_get_ticks_per_second();<br>
+<br>
+  printk( "\tAttaching virtio pci...\n" );<br>
+  ret = vtpci_attach( config, &sc->vtpci_softc );<br>
+<br>
+  if ( ret ) {<br>
+    printk( "vtpci_attach fail...\n" );<br>
+  }<br>
+<br>
+  /* Alloc virtqueues */<br>
+  printk( "\tAllocating virtqueues...\n" );<br>
+  ret = vtnet_alloc_virtqueues( sc );<br>
+<br>
+  if ( ret ) {<br>
+    printk( "vtnet_alloc_virtqueues fail...\n" );<br>
+  }<br>
+<br>
+  /* Setup interrupt */<br>
+  printk( "\tSetup interrupt...\n" );<br>
+  ret = vtnet_setup_intr( &sc->vtpci_softc );<br>
+<br>
+  if ( ret ) {<br>
+    printk( "vtpci_setup_intr fail...\n" );<br>
+  }<br>
+<br>
+  /* Setup interface */<br>
+  printk( "\tSetup interface...\n" );<br>
+  ret = vtnet_setup_interface( sc, config );<br>
+<br>
+  if ( ret ) {<br>
+    printk( "vtnet_setup_interface fail...\n" );<br>
+  }<br>
+<br>
+  printk( "rtems_vtnet_driver_attach end\n" );<br>
+<br>
+  return 0;<br>
+}<br>
+<br>
+static int vtnet_alloc_virtqueues( struct vtnet_softc *sc )<br>
+{<br>
+  uint16_t val16;<br>
+  int      size, error;<br>
+<br>
+  /* Init virtio_net_hdr */<br>
+  memset( &sc->vtnet_net_hdr, 0, sizeof( struct virtio_net_hdr ) );<br>
+<br>
+  /* Select virtqueue 0 */<br>
+  vtpci_io_write_2( &sc->vtpci_softc,<br>
+    VIRTIO_PCI_QUEUE_SEL,<br>
+    VIRTIO_PCI_QUEUE_SEL_RX );<br>
+  val16 = vtpci_io_read_2( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_NUM );<br>
+<br>
+  /* Alloc memory & continuous memory for vring */<br>
+  sc->vtnet_rxvq_size = val16;<br>
+  size = sizeof( struct virtqueue ) + val16 * sizeof( struct vq_desc_extra<br>
);<br>
+  sc->vtnet_rxvq = malloc( size, M_DEVBUF, M_NOWAIT );<br>
+  memset( sc->vtnet_rxvq, 0, size );<br>
+<br>
+  error =<br>
+    vtnet_alloc_virtqueue( sc->vtnet_rxvq, VIRTIO_PCI_QUEUE_SEL_RX, val16<br>
);<br>
+<br>
+  if ( error ) {<br>
+    return error;<br>
+  }<br>
+<br>
+  /* Select virtqueue 1 */<br>
+  vtpci_io_write_2( &sc->vtpci_softc,<br>
+    VIRTIO_PCI_QUEUE_SEL,<br>
+    VIRTIO_PCI_QUEUE_SEL_TX );<br>
+  val16 = vtpci_io_read_2( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_NUM );<br>
+<br>
+  /* Alloc memory & continuous memory for vring */<br>
+  sc->vtnet_txvq_size = val16;<br>
+  size = sizeof( struct virtqueue ) + val16 * sizeof( struct vq_desc_extra<br>
);<br>
+  sc->vtnet_txvq = malloc( size, M_DEVBUF, M_NOWAIT );<br>
+  memset( sc->vtnet_txvq, 0, size );<br>
+<br>
+  error =<br>
+    vtnet_alloc_virtqueue( sc->vtnet_txvq, VIRTIO_PCI_QUEUE_SEL_TX, val16<br>
);<br>
+<br>
+  if ( error ) {<br>
+    return error;<br>
+  }<br>
+<br>
+  return 0;<br>
+}<br>
+<br>
+static int vtnet_alloc_virtqueue(<br>
+  struct virtqueue *vq,<br>
+  uint16_t          queue_num,<br>
+  uint16_t          queue_size<br>
+)<br>
+{<br>
+  unsigned long align;<br>
+  void         *mem;<br>
+  int           size;<br>
+<br>
+  vq->vq_queue_index = queue_num;<br>
+  vq->vq_alignment = VIRTIO_PCI_VRING_ALIGN;<br>
+  vq->vq_nentries = queue_size;<br>
+  vq->vq_free_cnt = queue_size;<br>
+  vq->vq_max_indirect_size = VTNET_RX_MIN_SEGS;<br>
+<br>
+  align = vq->vq_alignment;<br>
+  size = queue_size * sizeof( struct vring_desc );<br>
+  size += sizeof( struct vring_avail ) + ( queue_size * sizeof( uint16_t )<br>
) +<br>
+          sizeof( uint16_t );<br>
+<br>
+  size = ( size + align - 1 ) & ~( vq->vq_alignment - 1 );<br>
+  size += sizeof( struct vring_used ) +<br>
+          ( queue_size * sizeof( struct vring_used_elem ) ) +<br>
+          sizeof( uint16_t );<br>
+<br>
+  mem = (void *) malloc( size + align, M_DEVBUF, M_NOWAIT );<br>
+<br>
+  if ( ( (unsigned long) mem % align ) > 0 ) {<br>
+    mem =<br>
+      (void *) ( (unsigned long) mem +<br>
+                 ( align - ( (unsigned long) mem % align ) ) );<br>
+  }<br>
+<br>
+  vq->vq_ring_size = size;<br>
+  vq->vq_ring_mem = mem;<br>
+  memset( vq->vq_ring_mem, 0, size );<br>
+<br>
+  virtqueue_disable_intr( vq );<br>
+<br>
+  return 0;<br>
+}<br>
+<br>
+int vtnet_setup_intr( struct vtpci_softc *sc )<br>
+{<br>
+  uint8_t val8;<br>
+  int     ret;<br>
+<br>
+  /* Get intrrupt level */<br>
+  pcib_conf_read8( sc->pci_signature, PCI_INTERRUPT_LINE, &val8 );<br>
+  ret = rtems_interrupt_handler_install(<br>
+    val8,<br>
+    NULL,<br>
+    RTEMS_INTERRUPT_SHARED,<br>
+    (rtems_interrupt_handler) vtnet_intr,<br>
+    NULL );<br>
+<br>
+  return ret;<br>
+}<br>
+<br>
+static int vtnet_setup_interface(<br>
+  struct vtnet_softc           *sc,<br>
+  struct rtems_bsdnet_ifconfig *config<br>
+)<br>
+{<br>
+  struct ifnet *ifp;<br>
+  int           mtu;<br>
+<br>
+  ifp = &sc->arpcom.ac_if;<br>
+  ifp->if_softc = (void *) &vtnet_softc;<br>
+<br>
+  if ( config->mtu ) {<br>
+    mtu = config->mtu;<br>
+  } else {<br>
+    mtu = ETHERMTU;<br>
+  }<br>
+<br>
+  sc->arpcom.ac_enaddr[ 0 ] = 0x08;<br>
+  sc->arpcom.ac_enaddr[ 1 ] = 0x00;<br>
+  sc->arpcom.ac_enaddr[ 2 ] = 0x27;<br>
+  sc->arpcom.ac_enaddr[ 3 ] = 0x98;<br>
+  sc->arpcom.ac_enaddr[ 4 ] = 0xe7;<br>
+  sc->arpcom.ac_enaddr[ 5 ] = 0x0f;<br>
+<br>
+  ifp->if_softc = sc;<br>
+  ifp->if_unit = sc->vtpci_softc.unit_number;<br>
+  ifp->if_name = sc->vtpci_softc.unit_name;<br>
+  ifp->if_mtu = mtu;<br>
+  ifp->if_init = vtnet_init;<br>
+  ifp->if_ioctl = vtnet_ioctl;<br>
+  ifp->if_start = vtnet_start;<br>
+  ifp->if_output = ether_output;<br>
+  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;<br>
+  ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;<br>
+<br>
+  if_attach( ifp );<br>
+  ether_ifattach( ifp );<br>
+<br>
+  return 0;<br>
+}<br>
+<br>
+static void vtnet_init( void *xsc )<br>
+{<br>
+  rtems_interrupt_level level;<br>
+  struct vtnet_softc   *sc;<br>
+  struct ifnet         *ifp;<br>
+  struct mbuf          *m;<br>
+  uint32_t              val32;<br>
+  uint16_t              val16;<br>
+  uint8_t               val8;<br>
+  int                   last;<br>
+<br>
+  sc = xsc;<br>
+  ifp = &sc->arpcom.ac_if;<br>
+<br>
+  rtems_interrupt_disable( level );<br>
+<br>
+  if ( ifp->if_flags & IFF_RUNNING ) {<br>
+    return;<br>
+  }<br>
+<br>
+  printk( "vtnet_init start\n" );<br>
+<br>
+  /* vtnet_stop */<br>
+  ifp->if_flags &= ~IFF_RUNNING;<br>
+  sc->vtnet_link_active = 0;<br>
+  vtnet_callout_stop( sc );<br>
+<br>
+  /* vtnet_disable_interrupts */<br>
+  virtqueue_disable_intr( sc->vtnet_rxvq );<br>
+  virtqueue_disable_intr( sc->vtnet_txvq );<br>
+<br>
+  /* vtpci_stop */<br>
+  vtpci_io_write_1( &sc->vtpci_softc,<br>
+    VIRTIO_PCI_STATUS,<br>
+    VIRTIO_CONFIG_STATUS_RESET );<br>
+<br>
+  /* vtnet_drain_rxtx_queues */<br>
+  last = 0;<br>
+<br>
+  while ( ( m = virtqueue_drain( sc->vtnet_rxvq, &last ) ) != NULL ) {<br>
+    m_freem( m );<br>
+  }<br>
+<br>
+  last = 0;<br>
+<br>
+  while ( ( m = virtqueue_drain( sc->vtnet_txvq, &last ) ) != NULL ) {<br>
+    m_freem( m );<br>
+  }<br>
+<br>
+  /* vtpci_reinit */<br>
+  val8 = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS );<br>
+<br>
+  if ( val8 != VIRTIO_CONFIG_STATUS_RESET ) {<br>
+    /* vtpci_stop */<br>
+    vtpci_io_write_1( &sc->vtpci_softc,<br>
+      VIRTIO_PCI_STATUS,<br>
+      VIRTIO_CONFIG_STATUS_RESET );<br>
+  }<br>
+<br>
+  /* Set status bit as acknowlege & driver */<br>
+  val8 = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS );<br>
+  val8 |= VIRTIO_CONFIG_STATUS_ACK;<br>
+  vtpci_io_write_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS, val8 );<br>
+  val8 = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS );<br>
+  val8 |= VIRTIO_CONFIG_STATUS_DRIVER;<br>
+  vtpci_io_write_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS, val8 );<br>
+<br>
+  vtnet_negotiate_features( sc );<br>
+<br>
+  /* vtpci_init_virtqueue */<br>
+  vtnet_init_virtqueue( sc, sc->vtnet_rxvq );<br>
+  vtnet_init_virtqueue( sc, sc->vtnet_txvq );<br>
+<br>
+  vtpci_io_write_2( &sc->vtpci_softc,<br>
+    VIRTIO_PCI_QUEUE_SEL,<br>
+    VIRTIO_PCI_QUEUE_SEL_RX );<br>
+  val16 = vtpci_io_read_2( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_NUM );<br>
+<br>
+  if ( !val16 || vtpci_io_read_4( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_PFN )<br>
) {<br>
+    printk( "\tRXQ already exists!\n" );<br>
+  }<br>
+<br>
+  vtpci_io_write_4( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_PFN,<br>
+    ( (uint32_t) sc->vtnet_rxvq->vq_ring_mem >><br>
+      VIRTIO_PCI_QUEUE_ADDR_SHIFT ) );<br>
+<br>
+  vtpci_io_write_2( &sc->vtpci_softc,<br>
+    VIRTIO_PCI_QUEUE_SEL,<br>
+    VIRTIO_PCI_QUEUE_SEL_TX );<br>
+  val16 = vtpci_io_read_2( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_NUM );<br>
+<br>
+  if ( !val16 || vtpci_io_read_4( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_PFN )<br>
) {<br>
+    printk( "\tTXQ already exists!\n" );<br>
+  }<br>
+<br>
+  vtpci_io_write_4( &sc->vtpci_softc, VIRTIO_PCI_QUEUE_PFN,<br>
+    ( (uint32_t) sc->vtnet_txvq->vq_ring_mem >><br>
+      VIRTIO_PCI_QUEUE_ADDR_SHIFT ) );<br>
+<br>
+  /* vtnet_init_rx_queues */<br>
+  sc->vtnet_rx_clsize = MCLBYTES;<br>
+  vtnet_rxq_populate( sc );<br>
+<br>
+  /* vtnet_init_tx_queues */<br>
+  sc->vtnet_tx_watchdog = 0;<br>
+<br>
+  vq_ring_enable_interrupt( sc->vtnet_rxvq, 0 );<br>
+  vq_ring_enable_interrupt( sc->vtnet_txvq, 0 );<br>
+  ifp->if_flags |= IFF_RUNNING;<br>
+<br>
+  /* virtio_reinit_complete */<br>
+  val8 = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS );<br>
+  val8 |= VIRTIO_CONFIG_STATUS_DRIVER_OK;<br>
+  vtpci_io_write_1( &sc->vtpci_softc, VIRTIO_PCI_STATUS, val8 );<br>
+<br>
+  /* vtnet_update_link_status; */<br>
+  sc->vtnet_link_active = 1;<br>
+<br>
+  /* start vtnet_daemon */<br>
+  if ( sc->daemonTid == 0 ) {<br>
+    sc->daemonTid = rtems_bsdnet_newproc( "VTNd",<br>
+      VTNET_DAEMON_STKSIZE,<br>
+      vtnet_daemon,<br>
+      sc );<br>
+  }<br>
+<br>
+  /* start vtnet_tick */<br>
+  sc->stat_ch = vtnet_timeout_running;<br>
+  /* TODO: timeout routine is not working */<br>
+  /* timeout(vtnet_tick, sc, hz); */<br>
+<br>
+  printk( "vtnet_init end\n" );<br>
+<br>
+  rtems_interrupt_enable( level );<br>
+}<br>
+<br>
+static int vtnet_rxq_eof( struct vtnet_softc *sc )<br>
+{<br>
+  struct virtqueue    *vq;<br>
+  struct ifnet        *ifp;<br>
+  struct mbuf         *m;<br>
+  struct ether_header *eh;<br>
+  uint32_t             len;<br>
+  int                  deq, count;<br>
+<br>
+  vq = sc->vtnet_rxvq;<br>
+  ifp = &sc->arpcom.ac_if;<br>
+  len = 0;<br>
+  deq = 0;<br>
+  count = VTNET_RX_PROCESS_LIMIT;<br>
+<br>
+  while ( count-- > 0 ) {<br>
+    m = virtqueue_dequeue( vq, &len );<br>
+<br>
+    if ( m == NULL ) {<br>
+      break;<br>
+    }<br>
+<br>
+    deq++;<br>
+<br>
+    if ( len < sc->vtnet_hdr_size ) {<br>
+      vtnet_rxq_enqueue( sc, m );<br>
+      continue;<br>
+    }<br>
+<br>
+    if ( vtnet_rxq_replace( sc, m, len ) != 0 ) {<br>
+      vtnet_rxq_enqueue( sc, m );<br>
+      continue;<br>
+    }<br>
+<br>
+    m->m_pkthdr.len = len;<br>
+    m->m_pkthdr.rcvif = ifp;<br>
+    m_adj( m, sizeof( struct virtio_net_hdr ) );<br>
+<br>
+    /* vtnet_rxq_input */<br>
+    eh = mtod( m, struct ether_header * );<br>
+    m_adj( m, sizeof( struct ether_header ) );<br>
+    m->m_pkthdr.len = m->m_len;<br>
+<br>
+    ether_input( ifp, eh, m );<br>
+<br>
+    if ( ( ifp->if_flags & IFF_RUNNING ) == 0 ) {<br>
+      break;<br>
+    }<br>
+  }<br>
+<br>
+  if ( deq > 0 ) {<br>
+    vtpci_notify( &sc->vtpci_softc, vq );<br>
+  }<br>
+<br>
+  return ( count > 0 ? 0 : EAGAIN );<br>
+}<br>
+<br>
+static int vtnet_rxq_enqueue(<br>
+  struct vtnet_softc *sc,<br>
+  struct mbuf        *m_head<br>
+)<br>
+{<br>
+  struct virtqueue     *vq;<br>
+  struct vring_desc    *desc, *dp;<br>
+  struct vq_desc_extra *dxp;<br>
+  struct mbuf          *m;<br>
+  uint16_t              head_idx, idx;<br>
+  uint8_t               segs;<br>
+<br>
+  vq = sc->vtnet_rxvq;<br>
+  desc = vq->vq_ring.desc;<br>
+<br>
+  if ( vq->vq_free_cnt == 0 ) {<br>
+    return ENOSPC;<br>
+  }<br>
+<br>
+  segs = 0;<br>
+<br>
+  for ( m = m_head; m != NULL; m = m->m_next ) {<br>
+    segs++;<br>
+  }<br>
+<br>
+  if ( segs == 0 ) {<br>
+    return EINVAL;<br>
+  }<br>
+<br>
+  if ( vq->vq_free_cnt < segs ) {<br>
+    return EMSGSIZE;<br>
+  }<br>
+<br>
+  head_idx = vq->vq_desc_head_idx;<br>
+  dxp = &vq->vq_descx[ head_idx ];<br>
+  dxp->cookie = m_head;<br>
+  dxp->ndescs = segs;<br>
+<br>
+  for ( m = m_head, idx = head_idx; m != NULL;<br>
+        m = m->m_next, idx = dp->next ) {<br>
+    dp = &desc[ idx ];<br>
+    dp->addr = (uint32_t) m->m_data;<br>
+    dp->len = m->m_len;<br>
+    dp->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;<br>
+  }<br>
+<br>
+  dp->flags &= ~( VRING_DESC_F_NEXT );<br>
+<br>
+  vq->vq_desc_head_idx = idx;<br>
+  vq->vq_free_cnt -= segs;<br>
+<br>
+  vq_ring_update_avail( vq, head_idx );<br>
+<br>
+  return 0;<br>
+}<br>
+<br>
+static int vtnet_rxq_replace(<br>
+  struct vtnet_softc *sc,<br>
+  struct mbuf        *m,<br>
+  int                 len<br>
+)<br>
+{<br>
+  struct mbuf *m_new;<br>
+  int          error;<br>
+<br>
+  if ( m->m_next == NULL ) {<br>
+    if ( m->m_len < len ) {<br>
+      return EINVAL;<br>
+    }<br>
+<br>
+    m_new = vtnet_rxq_alloc_mbuf( sc, 1, NULL );<br>
+<br>
+    if ( m_new == NULL ) {<br>
+      return ENOBUFS;<br>
+    }<br>
+<br>
+    error = vtnet_rxq_enqueue( sc, m_new );<br>
+<br>
+    if ( error ) {<br>
+      m_freem( m_new );<br>
+    } else {<br>
+      m->m_len = len;<br>
+    }<br>
+  } else {<br>
+    error = vtnet_rxq_replace_nomgr( sc, m, len );<br>
+  }<br>
+<br>
+  return error;<br>
+}<br>
+<br>
+static struct mbuf *vtnet_rxq_alloc_mbuf(<br>
+  struct vtnet_softc *sc,<br>
+  int                 nbufs,<br>
+  struct mbuf       **m_tailp<br>
+)<br>
+{<br>
+  struct mbuf *m_head, *m_tail, *m;<br>
+  int          i;<br>
+<br>
+  MGETHDR( m_head, M_DONTWAIT, MT_DATA );<br>
+<br>
+  if ( m_head == NULL ) {<br>
+    m_freem( m_head );<br>
+<br>
+    return NULL;<br>
+  }<br>
+<br>
+  MCLGET( m_head, M_DONTWAIT );<br>
+<br>
+  if ( ( m_head->m_flags & M_EXT ) == 0 ) {<br>
+    m_freem( m_head );<br>
+<br>
+    return NULL;<br>
+  }<br>
+<br>
+  m_head->m_len = sc->vtnet_rx_clsize;<br>
+  m_tail = m_head;<br>
+<br>
+  for ( i = 1; i < nbufs; i++ ) {<br>
+    MGETHDR( m, M_DONTWAIT, MT_DATA );<br>
+<br>
+    if ( m == NULL ) {<br>
+      m_freem( m_head );<br>
+<br>
+      return NULL;<br>
+    }<br>
+<br>
+    MCLGET( m, M_DONTWAIT );<br>
+<br>
+    if ( ( m->m_flags & M_EXT ) == 0 ) {<br>
+      m_freem( m_head );<br>
+      m_freem( m );<br>
+<br>
+      return NULL;<br>
+    }<br>
+<br>
+    m->m_len = sc->vtnet_rx_clsize;<br>
+    m_tail->m_next = m;<br>
+    m_tail = m;<br>
+  }<br>
+<br>
+  if ( m_tailp != NULL ) {<br>
+    *m_tailp = m_tail;<br>
+  }<br>
+<br>
+  return m_head;<br>
+}<br>
+<br>
+static int vtnet_rxq_replace_nomgr(<br>
+  struct vtnet_softc *sc,<br>
+  struct mbuf        *m0,<br>
+  int                 len0<br>
+)<br>
+{<br>
+  struct mbuf *m, *m_prev, *m_new, *m_tail;<br>
+  int          len, clsize, nreplace, error;<br>
+<br>
+  clsize = sc->vtnet_rx_clsize;<br>
+  m_prev = NULL;<br>
+  m_tail = NULL;<br>
+  nreplace = 0;<br>
+  m = m0;<br>
+  len = len0;<br>
+<br>
+  while ( len > 0 ) {<br>
+    if ( m == NULL ) {<br>
+      return EMSGSIZE;<br>
+    }<br>
+<br>
+    m->m_len = ( m->m_len > len ) ? len : m->m_len;<br>
+    len -= m->m_len;<br>
+<br>
+    m_prev = m;<br>
+    m = m->m_next;<br>
+    nreplace++;<br>
+  }<br>
+<br>
+  m_new = vtnet_rxq_alloc_mbuf( sc, nreplace, &m_tail );<br>
+<br>
+  if ( m_new == NULL ) {<br>
+    m_prev->m_len = clsize;<br>
+<br>
+    return ENOBUFS;<br>
+  }<br>
+<br>
+  if ( m_prev->m_next != NULL ) {<br>
+    m_tail->m_next = m_prev->m_next;<br>
+    m_prev->m_next = NULL;<br>
+  }<br>
+<br>
+  error = vtnet_rxq_enqueue( sc, m_new );<br>
+<br>
+  if ( error ) {<br>
+    if ( m_tail->m_next != NULL ) {<br>
+      m_prev->m_next = m_tail->m_next;<br>
+      m_tail->m_next = NULL;<br>
+    }<br>
+<br>
+    m_prev->m_len = clsize;<br>
+    m_freem( m_new );<br>
+  }<br>
+<br>
+  return error;<br>
+}<br>
+<br>
+static void vtnet_start( struct ifnet *ifp )<br>
+{<br>
+  rtems_interrupt_level level;<br>
+  struct vtnet_softc   *sc;<br>
+  struct virtqueue     *vq;<br>
+  struct mbuf          *m;<br>
+  int                   enq, error;<br>
+<br>
+  sc = &vtnet_softc;<br>
+  vq = sc->vtnet_txvq;<br>
+  enq = 0;<br>
+<br>
+  rtems_interrupt_disable( level );<br>
+<br>
+  if ( ( ifp->if_flags & IFF_RUNNING ) == 0 || sc->vtnet_link_active == 0 )<br>
{<br>
+    rtems_interrupt_enable( level );<br>
+<br>
+    return;<br>
+  }<br>
+<br>
+  vtnet_txq_eof( sc );<br>
+<br>
+  while ( ifp->if_snd.ifq_head != NULL ) {<br>
+    IF_DEQUEUE( &ifp->if_snd, m );<br>
+<br>
+    if ( m == NULL ) {<br>
+      break;<br>
+    }<br>
+<br>
+    if ( ( error = vtnet_txq_enqueue( sc, m ) ) != 0 ) {<br>
+      if ( m != NULL ) {<br>
+        IF_PREPEND( &ifp->if_snd, m );<br>
+      }<br>
+<br>
+      break;<br>
+    }<br>
+<br>
+    enq++;<br>
+  }<br>
+<br>
+  if ( enq > 0 ) {<br>
+    vtpci_notify( &sc->vtpci_softc, vq );<br>
+    sc->vtnet_tx_watchdog = VTNET_TX_TIMEOUT;<br>
+  }<br>
+<br>
+  rtems_interrupt_enable( level );<br>
+}<br>
+<br>
+static void vtnet_txq_eof( struct vtnet_softc *sc )<br>
+{<br>
+  struct virtqueue *vq;<br>
+  struct mbuf      *m;<br>
+<br>
+  vq = sc->vtnet_txvq;<br>
+<br>
+  while ( ( m = virtqueue_dequeue( vq, NULL ) ) != NULL ) {<br>
+    m_freem( m );<br>
+  }<br>
+<br>
+  if ( vq->vq_nentries == vq->vq_free_cnt ) {<br>
+    sc->vtnet_tx_watchdog = 0;<br>
+  }<br>
+}<br>
+<br>
+static int vtnet_txq_enqueue(<br>
+  struct vtnet_softc *sc,<br>
+  struct mbuf        *m_head<br>
+)<br>
+{<br>
+  struct virtqueue     *vq;<br>
+  struct vring_desc    *desc, *dp;<br>
+  struct vq_desc_extra *dxp;<br>
+  struct mbuf          *m;<br>
+  uint16_t              head_idx;<br>
+  uint8_t               segs;<br>
+<br>
+  vq = sc->vtnet_txvq;<br>
+  desc = vq->vq_ring.desc;<br>
+<br>
+  if ( vq->vq_free_cnt == 0 ) {<br>
+    return ENOSPC;<br>
+  }<br>
+<br>
+  segs = 1;<br>
+<br>
+  for ( m = m_head; m != NULL; m = m->m_next ) {<br>
+    segs++;<br>
+  }<br>
+<br>
+  if ( segs == 1 ) {<br>
+    return EINVAL;<br>
+  }<br>
+<br>
+  if ( vq->vq_free_cnt < segs ) {<br>
+    return EMSGSIZE;<br>
+  }<br>
+<br>
+  head_idx = vq->vq_desc_head_idx;<br>
+  dxp = &vq->vq_descx[ head_idx ];<br>
+  dxp->cookie = m_head;<br>
+  dxp->ndescs = segs;<br>
+<br>
+  /* First desc of chain must be vtnet tx hdr */<br>
+  dp = &desc[ head_idx ];<br>
+  dp->addr = (uint32_t) &sc->vtnet_net_hdr;<br>
+  dp->len = sizeof( struct virtio_net_hdr );<br>
+  dp->flags |= VRING_DESC_F_NEXT;<br>
+<br>
+  /* Link rest mbuf to chain */<br>
+  for ( m = m_head; m != NULL; m = m->m_next ) {<br>
+    dp = &desc[ dp->next ];<br>
+    dp->addr = mtod( m, uint32_t );<br>
+    dp->len = m->m_len;<br>
+    dp->flags |= VRING_DESC_F_NEXT;<br>
+  }<br>
+<br>
+  dp->flags &= ~( VRING_DESC_F_NEXT );<br>
+<br>
+  vq->vq_desc_head_idx = dp->next;<br>
+  vq->vq_free_cnt -= segs;<br>
+<br>
+  vq_ring_update_avail( vq, head_idx );<br>
+<br>
+  return 0;<br>
+}<br>
+<br>
+static void vtnet_negotiate_features( struct vtnet_softc *sc )<br>
+{<br>
+  uint32_t host_features;<br>
+  uint32_t guest_features;<br>
+<br>
+  host_features =<br>
+    vtpci_io_read_4( &sc->vtpci_softc, VIRTIO_PCI_HOST_FEATURES );<br>
+  guest_features = host_features & 0xfffff;<br>
+  guest_features &= VTNET_FEATURES;<br>
+<br>
+  vtpci_io_write_4( &sc->vtpci_softc, VIRTIO_PCI_GUEST_FEATURES,<br>
+    guest_features );<br>
+  guest_features =<br>
+    vtpci_io_read_4( &sc->vtpci_softc, VIRTIO_PCI_GUEST_FEATURES );<br>
+<br>
+  printk( "\tHost_features:\t0x%08x\n", host_features );<br>
+  printk( "\tGuest_features:\t0x%08x\n", guest_features );<br>
+<br>
+  sc->vtnet_hdr_size = sizeof( struct virtio_net_hdr ) + ETHER_HDR_LEN;<br>
+}<br>
+<br>
+static void vtnet_callout_stop( struct vtnet_softc *sc )<br>
+{<br>
+  if ( sc->stat_ch == vtnet_timeout_running ) {<br>
+    sc->stat_ch = vtnet_timeout_stop_rq;<br>
+<br>
+    while ( sc->stat_ch != vtnet_timeout_stopped ) {<br>
+      rtems_bsdnet_semaphore_release();<br>
+      rtems_task_wake_after( vtnet_ticksPerSecond );<br>
+      rtems_bsdnet_semaphore_obtain();<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+static void vtnet_callout_reset( struct vtnet_softc *sc )<br>
+{<br>
+  if ( sc->stat_ch == vtnet_timeout_running ) {<br>
+    timeout( vtnet_tick, sc, hz );<br>
+  } else if ( sc->stat_ch == vtnet_timeout_stop_rq ) {<br>
+    sc->stat_ch = vtnet_timeout_stopped;<br>
+  }<br>
+}<br>
+<br>
+static int vtnet_init_virtqueue(<br>
+  struct vtnet_softc *sc,<br>
+  struct virtqueue   *vq<br>
+)<br>
+{<br>
+  struct vq_desc_extra *dxp;<br>
+  int                   i;<br>
+<br>
+  vq->vq_desc_head_idx = 0;<br>
+  vq->vq_used_cons_idx = 0;<br>
+  vq->vq_queued_cnt = 0;<br>
+  vq->vq_free_cnt = vq->vq_nentries;<br>
+<br>
+  memset( vq->vq_ring_mem, 0, vq->vq_ring_size );<br>
+<br>
+  for ( i = 0; i < vq->vq_nentries; i++ ) {<br>
+    dxp = &vq->vq_descx[ i ];<br>
+    dxp->cookie = NULL;<br>
+    dxp->ndescs = 0;<br>
+    dxp->indirect = NULL;<br>
+  }<br>
+<br>
+  vq_ring_init( vq );<br>
+  virtqueue_disable_intr( vq );<br>
+<br>
+  return 0;<br>
+}<br>
+<br>
+static int vtnet_rxq_populate( struct vtnet_softc *sc )<br>
+{<br>
+  struct virtqueue *rxvq;<br>
+  struct mbuf      *m;<br>
+  int               nbufs, error;<br>
+<br>
+  rxvq = sc->vtnet_rxvq;<br>
+<br>
+  for ( nbufs = 0; rxvq->vq_free_cnt; nbufs++ ) {<br>
+    m = vtnet_rxq_alloc_mbuf( sc, 1, NULL );<br>
+<br>
+    if ( m == NULL ) {<br>
+      return ENOBUFS;<br>
+    }<br>
+<br>
+    error = vtnet_rxq_enqueue( sc, m );<br>
+<br>
+    if ( error ) {<br>
+      m_freem( m );<br>
+    }<br>
+  }<br>
+<br>
+  if ( nbufs > 0 ) {<br>
+    vtpci_notify( &sc->vtpci_softc, rxvq );<br>
+<br>
+    if ( error == EMSGSIZE ) {<br>
+      error = 0;<br>
+    }<br>
+  }<br>
+<br>
+  return error;<br>
+}<br>
+<br>
+static int vtnet_ioctl(<br>
+  struct ifnet   *ifp,<br>
+  ioctl_command_t cmd,<br>
+  caddr_t         data<br>
+)<br>
+{<br>
+  int error;<br>
+<br>
+  error = 0;<br>
+<br>
+  switch ( cmd ) {<br>
+    case SIOCSIFMTU:<br>
+      /* TODO: vtnet_change_mtu */<br>
+      break;<br>
+    case SIOCSIFFLAGS:<br>
+      vtnet_init( ifp->if_softc );<br>
+      break;<br>
+    case SIOCADDMULTI:<br>
+    case SIOCDELMULTI:<br>
+      /* TODO: vtnet_rx_filter_mac */<br>
+      break;<br>
+    default:<br>
+      error = ether_ioctl( ifp, cmd, data );<br>
+      break;<br>
+  }<br>
+<br>
+  return error;<br>
+}<br>
+<br>
+static void vtnet_tick( void *xsc )<br>
+{<br>
+  struct vtnet_softc *sc;<br>
+  struct ifnet       *ifp;<br>
+  int                 timedout;<br>
+<br>
+  sc = &vtnet_softc;<br>
+  ifp = &sc->arpcom.ac_if;<br>
+<br>
+  timedout = vtnet_watchdog( sc );<br>
+<br>
+  if ( timedout != 0 ) {<br>
+    ifp->if_flags &= ~IFF_RUNNING;<br>
+    vtnet_init( sc );<br>
+  } else {<br>
+    vtnet_callout_reset( sc );<br>
+  }<br>
+}<br>
+<br>
+static int vtnet_watchdog( struct vtnet_softc *sc )<br>
+{<br>
+  if ( sc->vtnet_tx_watchdog == 0 || --sc->vtnet_tx_watchdog ) {<br>
+    return 0;<br>
+  }<br>
+<br>
+  return 1;<br>
+}<br>
+<br>
+static rtems_isr vtnet_intr( rtems_vector_number v )<br>
+{<br>
+  struct vtnet_softc *sc;<br>
+  struct ifnet       *ifp;<br>
+  uint8_t             isr;<br>
+<br>
+  sc = &vtnet_softc;<br>
+  ifp = &sc->arpcom.ac_if;<br>
+<br>
+  isr = vtpci_io_read_1( &sc->vtpci_softc, VIRTIO_PCI_ISR );<br>
+<br>
+  if ( isr & VIRTIO_PCI_ISR_INTR ) {<br>
+    if ( ( ifp->if_flags & IFF_RUNNING ) == 0 ) {<br>
+      return;<br>
+    }<br>
+<br>
+    rtems_bsdnet_event_send( sc->daemonTid, RTEMS_EVENT_1 );<br>
+  } else if ( isr & VIRTIO_PCI_ISR_CONFIG ) {<br>
+    /*<br>
+     * TODO: Handling of config interrupt<br>
+     */<br>
+  }<br>
+}<br>
+<br>
+static void vtnet_daemon( void *xsc )<br>
+{<br>
+  struct vtnet_softc *sc;<br>
+  struct ifnet       *ifp;<br>
+  struct virtqueue   *rxvq;<br>
+  struct virtqueue   *txvq;<br>
+  int                 more, tries;<br>
+  rtems_event_set     events;<br>
+<br>
+  sc = &vtnet_softc;<br>
+  ifp = &sc->arpcom.ac_if;<br>
+  rxvq = sc->vtnet_rxvq;<br>
+  txvq = sc->vtnet_txvq;<br>
+<br>
+  while ( 1 ) {<br>
+    rtems_bsdnet_event_receive( RTEMS_EVENT_1,<br>
+      RTEMS_WAIT | RTEMS_EVENT_ANY,<br>
+      RTEMS_NO_TIMEOUT,<br>
+      &events );<br>
+<br>
+    /* tx intr */<br>
+    tries = 0;<br>
+againtx:<br>
+    vtnet_txq_eof( sc );<br>
+<br>
+    if ( ifp->if_snd.ifq_head != NULL ) {<br>
+      vtnet_start( ifp );<br>
+    }<br>
+<br>
+    if ( virtqueue_postpone_intr( txvq, VQ_POSTPONE_LONG ) != 0 ) {<br>
+      virtqueue_disable_intr( txvq );<br>
+<br>
+      if ( tries++ < VTNET_INTR_DISABLE_RETRIES ) {<br>
+        goto againtx;<br>
+      }<br>
+    }<br>
+<br>
+    /* rx intr */<br>
+    tries = 0;<br>
+againrx:<br>
+    more = vtnet_rxq_eof( sc );<br>
+<br>
+    if ( more || vq_ring_enable_interrupt( rxvq, 0 ) != 0 ) {<br>
+      if ( !more ) {<br>
+        virtqueue_disable_intr( rxvq );<br>
+      }<br>
+<br>
+      if ( tries++ < VTNET_INTR_DISABLE_RETRIES ) {<br>
+        goto againrx;<br>
+      }<br>
+    }<br>
+  }<br>
+}<br>
diff --git a/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.h<br>
b/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.h<br>
new file mode 100644<br>
index 0000000..7f81bad<br>
--- /dev/null<br>
+++ b/c/src/lib/libbsp/i386/pc386/virtio/if_vtnet.h<br>
@@ -0,0 +1,181 @@<br>
+/**<br>
+ * @file if_vtnet.h<br>
+ * @brief Header for if_vtnet.c<br>
+ */<br>
+<br>
+/*<br>
+ * Copyright (c) 2016 Jin-Hyun Kim <<a href="mailto:jinhyun@konkuk.ac.kr">jinhyun@konkuk.ac.kr</a>><br>
+ *   and Hyun-Wook Jin <<a href="mailto:jinh@konkuk.ac.kr">jinh@konkuk.ac.kr</a>><br>
+ * Ported from FreeBSD to RTEMS March 16, <a href="http://sslab.konkuk.ac.kr" rel="noreferrer" target="_blank">http://sslab.konkuk.ac.kr</a><br>
+ *<br>
+ * The license and distribution terms for this file may be<br>
+ * found in the file LICENSE in this distribution or at<br>
+ * <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
+ */<br>
+<br>
+/*-<br>
+ * This header is BSD licensed so anyone can use the definitions to<br>
implement<br>
+ * compatible drivers/servers.<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>
+ * 3. Neither the name of IBM nor the names of its contributors<br>
+ *    may be used to endorse or promote products derived from this software<br>
+ *    without specific prior written permission.<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS<br>
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT<br>
LIMITED<br>
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A<br>
PARTICULAR<br>
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE<br>
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
CONSEQUENTIAL<br>
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,<br>
STRICT<br>
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY<br>
WAY<br>
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>
+ * SUCH DAMAGE.<br>
+ *<br>
+ * $FreeBSD: release/10.0.0/sys/dev/virtio/network/virtio_net.h 255111<br>
2013-09-01 04:23:54Z bryanv $<br>
+ */<br>
+<br>
+#ifndef _IF_VTNET_H_<br>
+#define _IF_VTNET_H_<br>
+<br>
+/* The feature bitmap for virtio net */<br>
+#define VIRTIO_NET_F_CSUM 0x00001       /* Host handles pkts w/ partial<br>
csum */<br>
+#define VIRTIO_NET_F_GUEST_CSUM 0x00002 /* Guest handles pkts w/ partial<br>
csum*/<br>
+#define VIRTIO_NET_F_MAC 0x00020        /* Host has given MAC address. */<br>
+#define VIRTIO_NET_F_GSO 0x00040        /* Host handles pkts w/ any GSO<br>
type */<br>
+#define VIRTIO_NET_F_GUEST_TSO4 0x00080 /* Guest can handle TSOv4 in. */<br>
+#define VIRTIO_NET_F_GUEST_TSO6 0x00100 /* Guest can handle TSOv6 in. */<br>
+#define VIRTIO_NET_F_GUEST_ECN 0x00200  /* Guest can handle TSO[6] w/ ECN<br>
in.*/<br>
+#define VIRTIO_NET_F_GUEST_UFO 0x00400  /* Guest can handle UFO in. */<br>
+#define VIRTIO_NET_F_HOST_TSO4 0x00800  /* Host can handle TSOv4 in. */<br>
+#define VIRTIO_NET_F_HOST_TSO6 0x01000  /* Host can handle TSOv6 in. */<br>
+#define VIRTIO_NET_F_HOST_ECN 0x02000   /* Host can handle TSO[6] w/ ECN<br>
in. */<br>
+#define VIRTIO_NET_F_HOST_UFO 0x04000   /* Host can handle UFO in. */<br>
+#define VIRTIO_NET_F_MRG_RXBUF 0x08000  /* Host can merge receive buffers.<br>
*/<br>
+#define VIRTIO_NET_F_STATUS 0x10000     /* virtio_net_config.status<br>
available*/<br>
+#define VIRTIO_NET_F_CTRL_VQ 0x20000    /* Control channel available */<br>
+#define VIRTIO_NET_F_CTRL_RX 0x40000    /* Control channel RX mode support<br>
*/<br>
+#define VIRTIO_NET_F_CTRL_VLAN 0x80000  /* Control channel VLAN filtering<br>
*/<br>
+<br>
+#define VTNET_FEATURES \<br>
+  ( VIRTIO_NET_F_CSUM | \<br>
+    VIRTIO_NET_F_MAC | \<br>
+    VIRTIO_NET_F_GSO | \<br>
+    VIRTIO_NET_F_HOST_TSO4 | \<br>
+    VIRTIO_NET_F_HOST_TSO6 | \<br>
+    VIRTIO_NET_F_HOST_ECN | \<br>
+    VIRTIO_NET_F_HOST_UFO )<br>
+<br>
+#define VTNET_RX_MIN_SEGS 2<br>
+#define VTNET_RX_PROCESS_LIMIT 512<br>
+#define VTNET_TX_TIMEOUT 5<br>
+#define VTNET_INTR_DISABLE_RETRIES 4<br>
+<br>
+#define VTNET_DAEMON_STKSIZE 4096<br>
+<br>
+struct virtio_net_hdr {<br>
+  uint8_t flags;<br>
+  uint8_t gso_type;<br>
+  uint16_t hdr_len;<br>
+  uint16_t gso_size;<br>
+  uint16_t csum_start;<br>
+  uint16_t csum_offset;<br>
+};<br>
+<br>
+struct vtnet_tx_header {<br>
+  struct virtio_net_hdr hdr;<br>
+  struct mbuf *vth_mbuf;<br>
+};<br>
+<br>
+struct vtnet_softc {<br>
+  struct arpcom arpcom;<br>
+<br>
+  struct vtpci_softc vtpci_softc;<br>
+  struct virtqueue *vtnet_rxvq;<br>
+  struct virtqueue *vtnet_txvq;<br>
+<br>
+  rtems_id daemonTid;<br>
+<br>
+  struct virtio_net_hdr vtnet_net_hdr;<br>
+  int vtnet_rxvq_size;<br>
+  int vtnet_txvq_size;<br>
+<br>
+  int vtnet_link_active;<br>
+  int vtnet_hdr_size;<br>
+  int vtnet_rx_clsize;<br>
+  int vtnet_tx_watchdog;<br>
+<br>
+  enum { vtnet_timeout_stopped, vtnet_timeout_running,<br>
vtnet_timeout_stop_rq }<br>
+  stat_ch;<br>
+};<br>
+<br>
+static int vtnet_alloc_virtqueues( struct vtnet_softc *sc );<br>
+static int vtnet_alloc_virtqueue(<br>
+  struct virtqueue *vq,<br>
+  uint16_t          num,<br>
+  uint16_t          queue_size<br>
+);<br>
+<br>
+static int vtnet_setup_interface(<br>
+  struct vtnet_softc           *sc,<br>
+  struct rtems_bsdnet_ifconfig *config<br>
+);<br>
+static void vtnet_init( void *xsc );<br>
+static void vtnet_negotiate_features( struct vtnet_softc *sc );<br>
+static int vtnet_init_virtqueue(<br>
+  struct vtnet_softc *sc,<br>
+  struct virtqueue   *vq<br>
+);<br>
+static void vtnet_start( struct ifnet *ifp );<br>
+static int vtnet_ioctl(<br>
+  struct ifnet   *ifp,<br>
+  ioctl_command_t cmd,<br>
+  caddr_t         data<br>
+);<br>
+<br>
+static int vtnet_setup_intr( struct vtpci_softc *sc );<br>
+static rtems_isr vtnet_intr( rtems_vector_number v );<br>
+static void vtnet_daemon( void *xsc );<br>
+<br>
+static void vtnet_tick( void *xsc );<br>
+static int vtnet_watchdog( struct vtnet_softc *sc );<br>
+static void vtnet_callout_stop( struct vtnet_softc *sc );<br>
+static void vtnet_callout_reset( struct vtnet_softc *sc );<br>
+<br>
+static int vtnet_rxq_populate( struct vtnet_softc *sc );<br>
+static int vtnet_rxq_eof( struct vtnet_softc *sc );<br>
+static int vtnet_rxq_enqueue(<br>
+  struct vtnet_softc *sc,<br>
+  struct mbuf        *m_head<br>
+);<br>
+static int vtnet_rxq_replace(<br>
+  struct vtnet_softc *sc,<br>
+  struct mbuf        *m,<br>
+  int                 len<br>
+);<br>
+static struct mbuf *vtnet_rxq_alloc_mbuf(<br>
+  struct vtnet_softc *sc,<br>
+  int                 nbufs,<br>
+  struct mbuf       **m_tailp<br>
+);<br>
+static int vtnet_rxq_replace_nomgr(<br>
+  struct vtnet_softc *sc,<br>
+  struct mbuf        *m0,<br>
+  int                 len0<br>
+);<br>
+<br>
+static void vtnet_txq_eof( struct vtnet_softc *sc );<br>
+static int vtnet_txq_enqueue(<br>
+  struct vtnet_softc *sc,<br>
+  struct mbuf        *m_head<br>
+);<br>
+<br>
+#endif /* _IF_VTNET_H_ */<br>
diff --git a/c/src/lib/libbsp/i386/pc386/virtio/virtio.c<br>
b/c/src/lib/libbsp/i386/pc386/virtio/virtio.c<br>
new file mode 100644<br>
index 0000000..85251fa<br>
--- /dev/null<br>
+++ b/c/src/lib/libbsp/i386/pc386/virtio/virtio.c<br>
@@ -0,0 +1,220 @@<br>
+/**<br>
+ * @file virtio.c<br>
+ * @brief Functions for virtqueue, vring<br>
+ */<br>
+<br>
+/*<br>
+ * Copyright (c) 2016 Jin-Hyun Kim <<a href="mailto:jinhyun@konkuk.ac.kr">jinhyun@konkuk.ac.kr</a>><br>
+ *   and Hyun-Wook Jin <<a href="mailto:jinh@konkuk.ac.kr">jinh@konkuk.ac.kr</a>><br>
+ * Ported from FreeBSD to RTEMS March 16, <a href="http://sslab.konkuk.ac.kr" rel="noreferrer" target="_blank">http://sslab.konkuk.ac.kr</a><br>
+ *<br>
+ * The license and distribution terms for this file may be<br>
+ * found in the file LICENSE in this distribution or at<br>
+ * <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
+ */<br>
+<br>
+/*-<br>
+ * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org><br>
+ * All rights reserved.<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice unmodified, this list of conditions, and the following<br>
+ *    disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR<br>
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED<br>
WARRANTIES<br>
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.<br>
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,<br>
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT<br>
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF<br>
USE,<br>
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY<br>
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF<br>
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br>
+ */<br>
+<br>
+#include <rtems.h><br>
+<br>
+#include "virtio.h"<br>
+<br>
+void *virtqueue_dequeue(<br>
+  struct virtqueue *vq,<br>
+  uint32_t         *len<br>
+)<br>
+{<br>
+  struct vring_used_elem *uep;<br>
+  void                   *cookie;<br>
+  uint16_t                used_idx, desc_idx;<br>
+<br>
+  if ( vq->vq_used_cons_idx == vq->vq_ring.used->idx ) {<br>
+    return NULL;<br>
+  }<br>
+<br>
+  used_idx = vq->vq_used_cons_idx++ & ( vq->vq_nentries - 1 );<br>
+  uep = &vq->vq_ring.used->ring[ used_idx ];<br>
+<br>
+  rmb();<br>
+<br>
+  desc_idx = (uint16_t) uep->id;<br>
+<br>
+  if ( len != NULL ) {<br>
+    *len = uep->len;<br>
+  }<br>
+<br>
+  vq_ring_free_chain( vq, desc_idx );<br>
+<br>
+  cookie = vq->vq_descx[ desc_idx ].cookie;<br>
+  vq->vq_descx[ desc_idx ].cookie = NULL;<br>
+<br>
+  return cookie;<br>
+}<br>
+<br>
+void *virtqueue_drain(<br>
+  struct virtqueue *vq,<br>
+  int              *last<br>
+)<br>
+{<br>
+  void *cookie;<br>
+  int   idx;<br>
+<br>
+  cookie = NULL;<br>
+  idx = *last;<br>
+<br>
+  while ( idx < vq->vq_nentries && cookie == NULL ) {<br>
+    if ( ( cookie = vq->vq_descx[ idx ].cookie ) != NULL ) {<br>
+      vq->vq_descx[ idx ].cookie = NULL;<br>
+      vq_ring_free_chain( vq, idx );<br>
+    }<br>
+<br>
+    idx++;<br>
+  }<br>
+<br>
+  *last = idx;<br>
+<br>
+  return cookie;<br>
+}<br>
+<br>
+void virtqueue_disable_intr( struct virtqueue *vq )<br>
+{<br>
+  vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;<br>
+}<br>
+<br>
+int virtqueue_postpone_intr(<br>
+  struct virtqueue *vq,<br>
+  vq_postpone_t     hint<br>
+)<br>
+{<br>
+  uint16_t ndesc, avail_idx;<br>
+<br>
+  avail_idx = vq->vq_ring.avail->idx;<br>
+  ndesc = (uint16_t) ( avail_idx - vq->vq_used_cons_idx );<br>
+<br>
+  switch ( hint ) {<br>
+    case VQ_POSTPONE_SHORT:<br>
+      ndesc = ndesc / 4;<br>
+      break;<br>
+    case VQ_POSTPONE_LONG:<br>
+      ndesc = ( ndesc * 3 ) / 4;<br>
+      break;<br>
+    case VQ_POSTPONE_EMPTIED:<br>
+      break;<br>
+  }<br>
+<br>
+  return vq_ring_enable_interrupt( vq, ndesc );<br>
+}<br>
+<br>
+void vq_ring_init( struct virtqueue *vq )<br>
+{<br>
+  struct vring *vr;<br>
+  uint8_t      *ring_mem;<br>
+  int           i, size;<br>
+<br>
+  ring_mem = vq->vq_ring_mem;<br>
+  size = vq->vq_nentries;<br>
+  vr = &vq->vq_ring;<br>
+<br>
+  vr->num = size;<br>
+  vr->desc = (struct vring_desc *) ring_mem;<br>
+  vr->avail =<br>
+    (struct vring_avail *) ( ring_mem + size * sizeof( struct vring_desc )<br>
);<br>
+  vr->used = (void *)<br>
+             ( ( (unsigned long) &vr->avail->ring[ size ] +<br>
vq->vq_alignment -<br>
+                 1 ) & ~( vq->vq_alignment - 1 ) );<br>
+<br>
+  for ( i = 0; i < size - 1; i++ ) {<br>
+    vr->desc[ i ].next = i + 1;<br>
+  }<br>
+<br>
+  vr->desc[ i ].next = VQ_RING_DESC_CHAIN_END;<br>
+}<br>
+<br>
+void vq_ring_free_chain(<br>
+  struct virtqueue *vq,<br>
+  uint16_t          desc_idx<br>
+)<br>
+{<br>
+  struct vring_desc    *dp;<br>
+  struct vq_desc_extra *dxp;<br>
+<br>
+  dp = &vq->vq_ring.desc[ desc_idx ];<br>
+  dxp = &vq->vq_descx[ desc_idx ];<br>
+<br>
+  vq->vq_free_cnt += dxp->ndescs;<br>
+  dxp->ndescs--;<br>
+<br>
+  while ( dp->flags & VRING_DESC_F_NEXT ) {<br>
+    dp = &vq->vq_ring.desc[ dp->next ];<br>
+    dxp->ndescs--;<br>
+  }<br>
+<br>
+  dp->next = vq->vq_desc_head_idx;<br>
+  vq->vq_desc_head_idx = desc_idx;<br>
+}<br>
+<br>
+void vq_ring_update_avail(<br>
+  struct virtqueue *vq,<br>
+  uint16_t          desc_idx<br>
+)<br>
+{<br>
+  uint16_t avail_idx;<br>
+<br>
+  avail_idx = vq->vq_ring.avail->idx & ( vq->vq_nentries - 1 );<br>
+  vq->vq_ring.avail->ring[ avail_idx ] = desc_idx;<br>
+<br>
+  wmb();<br>
+<br>
+  vq->vq_ring.avail->idx++;<br>
+  vq->vq_queued_cnt++;<br>
+}<br>
+<br>
+int vq_ring_must_notify_host( struct virtqueue *vq )<br>
+{<br>
+  return ( ( vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY ) == 0 );<br>
+}<br>
+<br>
+int vq_ring_enable_interrupt(<br>
+  struct virtqueue *vq,<br>
+  uint16_t          ndesc<br>
+)<br>
+{<br>
+  uint16_t used_idx, nused;<br>
+<br>
+  vq->vq_ring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;<br>
+<br>
+  mb();<br>
+<br>
+  used_idx = vq->vq_ring.used->idx;<br>
+  nused = (uint16_t) ( used_idx - vq->vq_used_cons_idx );<br>
+<br>
+  if ( nused > ndesc ) {<br>
+    return 1;<br>
+  }<br>
+<br>
+  return 0;<br>
+}<br>
diff --git a/c/src/lib/libbsp/i386/pc386/virtio/virtio.h<br>
b/c/src/lib/libbsp/i386/pc386/virtio/virtio.h<br>
new file mode 100644<br>
index 0000000..47a61e8<br>
--- /dev/null<br>
+++ b/c/src/lib/libbsp/i386/pc386/virtio/virtio.h<br>
@@ -0,0 +1,167 @@<br>
+/**<br>
+ * @file virtio.h<br>
+ * @brief Header for virtio.c<br>
+ */<br>
+<br>
+/*<br>
+ * Copyright (c) 2016 Jin-Hyun Kim <<a href="mailto:jinhyun@konkuk.ac.kr">jinhyun@konkuk.ac.kr</a>><br>
+ *   and Hyun-Wook Jin <<a href="mailto:jinh@konkuk.ac.kr">jinh@konkuk.ac.kr</a>><br>
+ * Ported from FreeBSD to RTEMS March 16, <a href="http://sslab.konkuk.ac.kr" rel="noreferrer" target="_blank">http://sslab.konkuk.ac.kr</a><br>
+ *<br>
+ * The license and distribution terms for this file may be<br>
+ * found in the file LICENSE in this distribution or at<br>
+ * <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
+ */<br>
+<br>
+/*-<br>
+ * This header is BSD licensed so anyone can use the definitions to<br>
implement<br>
+ * compatible drivers/servers.<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>
+ * 3. Neither the name of IBM nor the names of its contributors<br>
+ *    may be used to endorse or promote products derived from this software<br>
+ *    without specific prior written permission.<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS<br>
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT<br>
LIMITED<br>
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A<br>
PARTICULAR<br>
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE<br>
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
CONSEQUENTIAL<br>
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,<br>
STRICT<br>
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY<br>
WAY<br>
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>
+ * SUCH DAMAGE.<br>
+ *<br>
+ * $FreeBSD: release/10.0.0/sys/dev/virtio/virtio.h 252708 2013-07-04<br>
17:59:09Z bryanv $<br>
+ */<br>
+<br>
+#ifndef _VIRTIO_H_<br>
+#define _VIRTIO_H_<br>
+<br>
+#define mb() asm volatile ( "lock; addl $0,0(%%esp) " ::: "memory" );<br>
+#define rmb() mb()<br>
+#define wmb() asm volatile ( "lock; addl $0, (%%esp)" ::: "memory", "cc" )<br>
+<br>
+#define vring_used_event( vr ) ( ( vr )->avail->ring[ ( vr )->num ] )<br>
+#define vring_avail_event( vr ) ( *(uint16_t *) &( vr )->used->ring[ ( vr<br>
)-> \<br>
+                                                                     num ]<br>
)<br>
+#define vring_need_event( event_idx, new_idx, old ) \<br>
+  ( (uint16_t) ( new_idx - event_idx - 1 ) < (uint16_t) ( new_idx - old ) )<br>
+<br>
+/* VirtIO PCI vendor/device ID. */<br>
+#define VIRTIO_VENDOR_ID 0x1AF4<br>
+#define VIRTIO_DEVICE_ID_MIN 0x1000<br>
+#define VIRTIO_DEVICE_ID_MAX 0x1040<br>
+<br>
+#define VRING_DESC_F_NEXT 1<br>
+#define VRING_DESC_F_WRITE 2<br>
+#define VRING_DESC_F_INDIRECT 4<br>
+#define VRING_USED_F_NO_NOTIFY 1<br>
+#define VRING_AVAIL_F_NO_INTERRUPT 1<br>
+<br>
+#define VQ_RING_DESC_CHAIN_END 32768<br>
+<br>
+typedef enum {<br>
+  VQ_POSTPONE_SHORT,<br>
+  VQ_POSTPONE_LONG,<br>
+  VQ_POSTPONE_EMPTIED<br>
+} vq_postpone_t;<br>
+<br>
+struct vring_desc {<br>
+  uint64_t addr;<br>
+  uint32_t len;<br>
+  uint16_t flags;<br>
+  uint16_t next;<br>
+};<br>
+<br>
+struct vring_avail {<br>
+  uint16_t flags;<br>
+  uint16_t idx;<br>
+  uint16_t ring[];<br>
+};<br>
+<br>
+struct vring_used_elem {<br>
+  uint32_t id;<br>
+  uint32_t len;<br>
+};<br>
+<br>
+struct vring_used {<br>
+  uint16_t flags;<br>
+  uint16_t idx;<br>
+  struct vring_used_elem ring[];<br>
+};<br>
+<br>
+struct vring {<br>
+  unsigned int num;<br>
+  struct vring_desc *desc;<br>
+  struct vring_avail *avail;<br>
+  struct vring_used *used;<br>
+};<br>
+<br>
+struct vq_desc_extra {<br>
+  void *cookie;<br>
+  struct vring_desc *indirect;<br>
+  uint32_t indirect_paddr;<br>
+  uint16_t ndescs;<br>
+};<br>
+<br>
+struct virtqueue {<br>
+  uint16_t vq_queue_index;<br>
+  uint16_t vq_nentries;<br>
+  uint32_t vq_flags;<br>
+<br>
+  uint16_t vq_free_cnt;<br>
+  uint16_t vq_queued_cnt;<br>
+<br>
+  int vq_alignment;<br>
+  int vq_ring_size;<br>
+<br>
+  struct vring vq_ring;<br>
+  void *vq_ring_mem;<br>
+  int vq_max_indirect_size;<br>
+  int vq_indirect_mem_size;<br>
+<br>
+  uint16_t vq_desc_head_idx;<br>
+  uint16_t vq_used_cons_idx;<br>
+<br>
+  struct vq_desc_extra vq_descx[ 0 ];<br>
+};<br>
+<br>
+void *virtqueue_dequeue(<br>
+  struct virtqueue *vq,<br>
+  uint32_t         *len<br>
+);<br>
+void *virtqueue_drain(<br>
+  struct virtqueue *vq,<br>
+  int              *last<br>
+);<br>
+void virtqueue_disable_intr( struct virtqueue *vq );<br>
+int virtqueue_postpone_intr(<br>
+  struct virtqueue *vq,<br>
+  vq_postpone_t     hint<br>
+);<br>
+<br>
+void vq_ring_init( struct virtqueue *vq );<br>
+void vq_ring_free_chain(<br>
+  struct virtqueue *vq,<br>
+  uint16_t          desc_idx<br>
+);<br>
+void vq_ring_update_avail(<br>
+  struct virtqueue *vq,<br>
+  uint16_t          desc_idx<br>
+);<br>
+int vq_ring_must_notify_host( struct virtqueue *vq );<br>
+int vq_ring_enable_interrupt(<br>
+  struct virtqueue *vq,<br>
+  uint16_t          ndesc<br>
+);<br>
+<br>
+#endif /* _VIRTIO_H_ */<br>
diff --git a/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.c<br>
b/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.c<br>
new file mode 100644<br>
index 0000000..8ba9365<br>
--- /dev/null<br>
+++ b/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.c<br>
@@ -0,0 +1,176 @@<br>
+/**<br>
+ * @file virtio_pci.c<br>
+ * @brief Driver for the virtio PCI interface<br>
+ */<br>
+<br>
+/*<br>
+ * Copyright (c) 2016 Jin-Hyun Kim <<a href="mailto:jinhyun@konkuk.ac.kr">jinhyun@konkuk.ac.kr</a>><br>
+ *   and Hyun-Wook Jin <<a href="mailto:jinh@konkuk.ac.kr">jinh@konkuk.ac.kr</a>><br>
+ * Ported from FreeBSD to RTEMS March 16, <a href="http://sslab.konkuk.ac.kr" rel="noreferrer" target="_blank">http://sslab.konkuk.ac.kr</a><br>
+ *<br>
+ * The license and distribution terms for this file may be<br>
+ * found in the file LICENSE in this distribution or at<br>
+ * <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
+ */<br>
+<br>
+/*-<br>
+ * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org><br>
+ * All rights reserved.<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice unmodified, this list of conditions, and the following<br>
+ *    disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR<br>
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED<br>
WARRANTIES<br>
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.<br>
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,<br>
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT<br>
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF<br>
USE,<br>
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY<br>
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF<br>
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br>
+ */<br>
+<br>
+/* Driver for the VirtIO PCI interface. */<br>
+<br>
+#ifdef __i386__<br>
+<br>
+#include <rtems.h><br>
+#include <rtems/rtems_bsdnet.h><br>
+#include <bsp.h><br>
+<br>
+#include <pcibios.h><br>
+<br>
+#include "virtio.h"<br>
+#include "virtio_pci.h"<br>
+<br>
+__inline uint8_t vtpci_io_read_1(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg<br>
+)<br>
+{<br>
+  uint8_t val;<br>
+<br>
+  inport_byte( sc->pci_io_base + reg, val );<br>
+<br>
+  return val;<br>
+}<br>
+__inline uint16_t vtpci_io_read_2(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg<br>
+)<br>
+{<br>
+  uint16_t val;<br>
+<br>
+  inport_word( sc->pci_io_base + reg, val );<br>
+<br>
+  return val;<br>
+}<br>
+__inline uint32_t vtpci_io_read_4(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg<br>
+)<br>
+{<br>
+  uint32_t val;<br>
+<br>
+  inport_long( sc->pci_io_base + reg, val );<br>
+<br>
+  return val;<br>
+}<br>
+__inline void vtpci_io_write_1(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg,<br>
+  uint8_t             val<br>
+)<br>
+{<br>
+  outport_byte( sc->pci_io_base + reg, val );<br>
+}<br>
+__inline void vtpci_io_write_2(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg,<br>
+  uint16_t            val<br>
+)<br>
+{<br>
+  outport_word( sc->pci_io_base + reg, val );<br>
+}<br>
+__inline void vtpci_io_write_4(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg,<br>
+  uint32_t            val<br>
+)<br>
+{<br>
+  outport_long( sc->pci_io_base + reg, val );<br>
+}<br>
+<br>
+int vtpci_attach(<br>
+  struct rtems_bsdnet_ifconfig *config,<br>
+  struct vtpci_softc           *sc<br>
+)<br>
+{<br>
+  int      i, ret;<br>
+  uint8_t  val8;<br>
+  uint16_t val16;<br>
+  uint32_t val32;<br>
+<br>
+  /* Parse NIC_NAME & Init structures */<br>
+  if ( ( sc->unit_number =<br>
+           rtems_bsdnet_parse_driver_name( config, &sc->unit_name ) ) < 0 )<br>
{<br>
+    return 0;<br>
+  }<br>
+<br>
+  /* Find device on pci bus */<br>
+  {<br>
+    int pbus, pdev, pfun;<br>
+<br>
+    for ( i = VIRTIO_DEVICE_ID_MIN; i < VIRTIO_DEVICE_ID_MAX; i++ ) {<br>
+      ret = pci_find_device( VIRTIO_VENDOR_ID, i, sc->unit_number,<br>
+        &pbus, &pdev, &pfun );<br>
+<br>
+      if ( ret == PCIB_ERR_SUCCESS ) {<br>
+        sc->pci_signature = PCIB_DEVSIG_MAKE( pbus, pdev, pfun );<br>
+        break;<br>
+      }<br>
+    }<br>
+  }<br>
+<br>
+  /* Enable bus matering */<br>
+  pcib_conf_read16( sc->pci_signature, PCI_COMMAND, &val16 );<br>
+  val16 |= PCI_COMMAND_MASTER;<br>
+  pcib_conf_write16( sc->pci_signature, PCI_COMMAND, val16 );<br>
+<br>
+  /* Set latency timer */<br>
+  pcib_conf_read8( sc->pci_signature, PCI_LATENCY_TIMER, &val8 );<br>
+  val8 |= 0x00;<br>
+  pcib_conf_write8( sc->pci_signature, PCI_LATENCY_TIMER, val8 );<br>
+<br>
+  /* Get IO Address */<br>
+  pcib_conf_read32( sc->pci_signature, PCI_BASE_ADDRESS_0, &val32 );<br>
+  val32 &= PCI_BASE_ADDRESS_IO_MASK;<br>
+  sc->pci_io_base = val32;<br>
+<br>
+  return 0;<br>
+}<br>
+<br>
+void vtpci_notify(<br>
+  struct vtpci_softc *sc,<br>
+  struct virtqueue   *vq<br>
+)<br>
+{<br>
+  mb();<br>
+<br>
+  if ( vq_ring_must_notify_host( vq ) ) {<br>
+    vtpci_io_write_2( sc, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index );<br>
+  }<br>
+<br>
+  vq->vq_queued_cnt = 0;<br>
+}<br>
+<br>
+#endif /* __i386__ */<br>
diff --git a/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.h<br>
b/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.h<br>
new file mode 100644<br>
index 0000000..7d0db9e<br>
--- /dev/null<br>
+++ b/c/src/lib/libbsp/i386/pc386/virtio/virtio_pci.h<br>
@@ -0,0 +1,131 @@<br>
+/**<br>
+ * @file virtio_pci.h<br>
+ * @brief Header for virtio_pci.c<br>
+ */<br>
+<br>
+/*<br>
+ * Copyright (c) 2016 Jin-Hyun Kim <<a href="mailto:jinhyun@konkuk.ac.kr">jinhyun@konkuk.ac.kr</a>><br>
+ *   and Hyun-Wook Jin <<a href="mailto:jinh@konkuk.ac.kr">jinh@konkuk.ac.kr</a>><br>
+ * Ported from FreeBSD to RTEMS March 16, <a href="http://sslab.konkuk.ac.kr" rel="noreferrer" target="_blank">http://sslab.konkuk.ac.kr</a><br>
+ *<br>
+ * The license and distribution terms for this file may be<br>
+ * found in the file LICENSE in this distribution or at<br>
+ * <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
+ */<br>
+<br>
+/*-<br>
+ * Copyright IBM Corp. 2007<br>
+ *<br>
+ * Authors:<br>
+ *  Anthony Liguori  <<a href="mailto:aliguori@us.ibm.com">aliguori@us.ibm.com</a>><br>
+ *<br>
+ * This header is BSD licensed so anyone can use the definitions to<br>
implement<br>
+ * compatible drivers/servers.<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>
+ * 3. Neither the name of IBM nor the names of its contributors<br>
+ *    may be used to endorse or promote products derived from this software<br>
+ *    without specific prior written permission.<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS<br>
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT<br>
LIMITED<br>
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A<br>
PARTICULAR<br>
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE<br>
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
CONSEQUENTIAL<br>
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,<br>
STRICT<br>
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY `<br>
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>
+ * SUCH DAMAGE.<br>
+ *<br>
+ * $FreeBSD: release/10.0.0/sys/dev/virtio/pci/virtio_pci.h 238360<br>
2012-07-11 02:57:19Z grehan $<br>
+ */<br>
+<br>
+#ifndef _VIRTIO_PCI_H_<br>
+#define _VIRTIO_PCI_H_<br>
+<br>
+/* VirtIO Header, located in BAR 0. */<br>
+#define VIRTIO_PCI_HOST_FEATURES 0   /* host's supported features (32bit,<br>
RO)*/<br>
+#define VIRTIO_PCI_GUEST_FEATURES 4  /* guest's supported features (32, RW)<br>
*/<br>
+#define VIRTIO_PCI_QUEUE_PFN 8       /* physical address of VQ (32, RW) */<br>
+#define VIRTIO_PCI_QUEUE_NUM 12      /* number of ring entries (16, RO) */<br>
+#define VIRTIO_PCI_QUEUE_SEL 14      /* current VQ selection (16, RW) */<br>
+#define VIRTIO_PCI_QUEUE_NOTIFY 16   /* notify host regarding VQ (16, RW)<br>
*/<br>
+#define VIRTIO_PCI_STATUS 18         /* device status register (8, RW) */<br>
+#define VIRTIO_PCI_ISR 19            /* interrupt status register, reading<br>
*/<br>
+#define VIRTIO_MSI_CONFIG_VECTOR 20<br>
+#define VIRTIO_MSI_QUEUE_VECTOR 22<br>
+<br>
+#define VIRTIO_PCI_QUEUE_SEL_RX 0<br>
+#define VIRTIO_PCI_QUEUE_SEL_TX 1<br>
+<br>
+#define VIRTIO_PCI_ISR_INTR 0x1<br>
+#define VIRTIO_PCI_ISR_CONFIG 0x2<br>
+<br>
+#define VIRTIO_MSI_NO_VECTOR 0xFFFF<br>
+<br>
+/* How many bits to shift physical queue address written to QUEUE_PFN */<br>
+#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12<br>
+<br>
+/* The alignment to use between consumer and producer parts of vring */<br>
+#define VIRTIO_PCI_VRING_ALIGN 4096<br>
+<br>
+/* Status byte for guest to report progress. */<br>
+#define VIRTIO_CONFIG_STATUS_RESET 0x00<br>
+#define VIRTIO_CONFIG_STATUS_ACK 0x01<br>
+#define VIRTIO_CONFIG_STATUS_DRIVER 0x02<br>
+#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04<br>
+#define VIRTIO_CONFIG_STATUS_FAILED 0x80<br>
+<br>
+struct vtpci_softc {<br>
+  int unit_number;<br>
+  char *unit_name;<br>
+<br>
+  int pci_signature;<br>
+  uint32_t pci_io_base;<br>
+};<br>
+<br>
+__inline uint8_t vtpci_io_read_1(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg<br>
+);<br>
+__inline uint16_t vtpci_io_read_2(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg<br>
+);<br>
+__inline uint32_t vtpci_io_read_4(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg<br>
+);<br>
+__inline void vtpci_io_write_1(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg,<br>
+  uint8_t             val<br>
+);<br>
+__inline void vtpci_io_write_2(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg,<br>
+  uint16_t            val<br>
+);<br>
+__inline void vtpci_io_write_4(<br>
+  struct vtpci_softc *sc,<br>
+  int                 reg,<br>
+  uint32_t            val<br>
+);<br>
+int vtpci_attach(<br>
+  struct rtems_bsdnet_ifconfig *config,<br>
+  struct vtpci_softc           *sc<br>
+);<br>
+void vtpci_notify(<br>
+  struct vtpci_softc *sc,<br>
+  struct virtqueue   *vq<br>
+);<br>
+<br>
+#endif /* _VIRTIO_PCI_H_ */<br>
<br>
<br>
<br>
_______________________________________________<br>
devel mailing list<br>
<a href="mailto:devel@rtems.org">devel@rtems.org</a><br>
<a href="http://lists.rtems.org/mailman/listinfo/devel" rel="noreferrer" target="_blank">http://lists.rtems.org/mailman/listinfo/devel</a><br>
</blockquote></div><br></div>