Signed-off-by: Jacob Gorm Hansen diff -r 52ae8dd4bc75 extras/mini-os/kernel.c --- a/extras/mini-os/kernel.c Tue Oct 17 22:09:52 2006 +0100 +++ b/extras/mini-os/kernel.c Thu Jan 04 18:16:30 2007 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -66,11 +67,18 @@ void xenbus_tester(void *p) /* test_xenbus(); */ } +void netfront_thread(void *p) +{ + init_netfront(&start_info); +} + + /* This should be overridden by the application we are linked against. */ __attribute__((weak)) int app_main(start_info_t *si) { printk("Dummy main: start_info=%p\n", si); create_thread("xenbus_tester", xenbus_tester, si); + create_thread("netfront", netfront_thread, si); return 0; } diff -r 52ae8dd4bc75 extras/mini-os/include/netfront.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/include/netfront.h Thu Jan 04 18:16:30 2007 +0100 @@ -0,0 +1,2 @@ +void init_netfront(void*); +void netfront_xmit(unsigned char* data,int len); diff -r 52ae8dd4bc75 extras/mini-os/netfront.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/netfront.c Thu Jan 04 18:16:30 2007 +0100 @@ -0,0 +1,455 @@ +/* Minimal network driver for Mini-OS. + * Copyright (c) 2006-2007 Jacob Gorm Hansen, University of Copenhagen. + * Based on netfront.c from Xen Linux. + * + * Does not handle fragments or extras. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +void init_rx_buffers(void); + +struct net_info { + struct netif_tx_front_ring tx; + struct netif_rx_front_ring rx; + int tx_ring_ref; + int rx_ring_ref; + unsigned int evtchn, local_port; + +} net_info; + + +char* xenbus_printf(xenbus_transaction_t xbt, + char* node,char* path, + char* fmt,unsigned int arg) +{ + char fullpath[256]; + char val[256]; + + sprintf(fullpath,"%s/%s",node,path); + sprintf(val,fmt,arg); + xenbus_write(xbt,fullpath,val); + + return NULL; +} + + +#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE) +#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE) +#define GRANT_INVALID_REF 0 + + +unsigned short rx_freelist[NET_RX_RING_SIZE]; +unsigned short tx_freelist[NET_TX_RING_SIZE]; + +struct net_buffer { + void* page; + int gref; +}; +struct net_buffer rx_buffers[NET_RX_RING_SIZE]; +struct net_buffer tx_buffers[NET_TX_RING_SIZE]; + +static inline void add_id_to_freelist(unsigned int id,unsigned short* freelist) +{ + freelist[id] = freelist[0]; + freelist[0] = id; +} + +static inline unsigned short get_id_from_freelist(unsigned short* freelist) +{ + unsigned int id = freelist[0]; + freelist[0] = freelist[id]; + return id; +} + +__attribute__((weak)) void netif_rx(unsigned char* data,int len) +{ + printk("%d bytes incoming at %p\n",len,data); +} + +__attribute__((weak)) void net_app_main(void*si,unsigned char*mac) {} + +static inline int xennet_rxidx(RING_IDX idx) +{ + return idx & (NET_RX_RING_SIZE - 1); +} + +void network_rx(void) +{ + struct net_info *np = &net_info; + RING_IDX rp,cons; + struct netif_rx_response *rx; + + +moretodo: + rp = np->rx.sring->rsp_prod; + rmb(); /* Ensure we see queued responses up to 'rp'. */ + cons = np->rx.rsp_cons; + + int nr_consumed=0; + while ((cons != rp)) + { + struct net_buffer* buf; + unsigned char* page; + + rx = RING_GET_RESPONSE(&np->rx, cons); + + if (rx->flags & NETRXF_extra_info) + { + printk("+++++++++++++++++++++ we have extras!\n"); + continue; + } + + + if (rx->status == NETIF_RSP_NULL) continue; + + int id = rx->id; + + buf = &rx_buffers[id]; + page = (unsigned char*)buf->page; + gnttab_end_access(buf->gref); + + if(rx->status>0) + { + netif_rx(page+rx->offset,rx->status); + } + + add_id_to_freelist(id,rx_freelist); + + nr_consumed++; + + ++cons; + } + np->rx.rsp_cons=rp; + + int more; + RING_FINAL_CHECK_FOR_RESPONSES(&np->rx,more); + if(more) goto moretodo; + + RING_IDX req_prod = np->rx.req_prod_pvt; + + int i; + netif_rx_request_t *req; + + for(i=0; irx, req_prod + i); + struct net_buffer* buf = &rx_buffers[id]; + void* page = buf->page; + + buf->gref = req->gref = + gnttab_grant_access(0,virt_to_mfn(page),0); + + req->id = id; + } + + wmb(); + + np->rx.req_prod_pvt = req_prod + i; + + int notify; + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify); + if (notify) + notify_remote_via_evtchn(np->evtchn); + +} + +void network_tx_buf_gc(void) +{ + + + RING_IDX cons, prod; + unsigned short id; + struct net_info *np = &net_info; + + do { + prod = np->tx.sring->rsp_prod; + rmb(); /* Ensure we see responses up to 'rp'. */ + + for (cons = np->tx.rsp_cons; cons != prod; cons++) + { + struct netif_tx_response *txrsp; + + txrsp = RING_GET_RESPONSE(&np->tx, cons); + if (txrsp->status == NETIF_RSP_NULL) + continue; + + id = txrsp->id; + struct net_buffer* buf = &tx_buffers[id]; + gnttab_end_access(buf->gref); + buf->gref=GRANT_INVALID_REF; + + add_id_to_freelist(id,tx_freelist); + } + + np->tx.rsp_cons = prod; + + /* + * Set a new event, then check for race with update of tx_cons. + * Note that it is essential to schedule a callback, no matter + * how few tx_buffers are pending. Even if there is space in the + * transmit ring, higher layers may be blocked because too much + * data is outstanding: in such cases notification from Xen is + * likely to be the only kick that we'll get. + */ + np->tx.sring->rsp_event = + prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; + mb(); + } while ((cons == prod) && (prod != np->tx.sring->rsp_prod)); + + +} + +void netfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data) +{ + int flags; + + local_irq_save(flags); + + network_tx_buf_gc(); + network_rx(); + + local_irq_restore(flags); +} + +char* backend; + +void init_netfront(void* si) +{ + xenbus_transaction_t xbt; + struct net_info* info = &net_info; + char* err; + char* message=NULL; + char nodename[] = "device/vif/0"; + struct netif_tx_sring *txs; + struct netif_rx_sring *rxs; + int retry=0; + int i; + char* mac; + char* msg; + + printk("************************ NETFRONT **********\n\n\n"); + + for(i=0;itx, txs, PAGE_SIZE); + FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); + + info->tx_ring_ref = gnttab_grant_access(0,virt_to_mfn(txs),0); + info->rx_ring_ref = gnttab_grant_access(0,virt_to_mfn(rxs),0); + + evtchn_alloc_unbound_t op; + op.dom = DOMID_SELF; + op.remote_dom = 0; + HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op); + clear_evtchn(op.port); /* Without, handler gets invoked now! */ + info->local_port = bind_evtchn(op.port, netfront_handler, NULL); + info->evtchn=op.port; + +again: + err = xenbus_transaction_start(&xbt); + if (err) { + printk("starting transaction\n"); + } + + err = xenbus_printf(xbt, nodename, "tx-ring-ref","%u", + info->tx_ring_ref); + if (err) { + message = "writing tx ring-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, nodename, "rx-ring-ref","%u", + info->rx_ring_ref); + if (err) { + message = "writing rx ring-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, nodename, + "event-channel", "%u", info->evtchn); + if (err) { + message = "writing event-channel"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, nodename, "request-rx-copy", "%u", 1); + + if (err) { + message = "writing request-rx-copy"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, nodename, "state", "%u", + 4); /* connected */ + + + err = xenbus_transaction_end(xbt, 0, &retry); + if (retry) { + goto again; + printk("completing transaction\n"); + } + + goto done; + +abort_transaction: + xenbus_transaction_end(xbt, 1, &retry); + +done: + + msg = xenbus_read(XBT_NIL, "device/vif/0/backend", &backend); + msg = xenbus_read(XBT_NIL, "device/vif/0/mac", &mac); + + printk("backend at %s\n",backend); + printk("mac is %s\n",mac); + + char *res; + char path[256]; + sprintf(path,"%s/state",backend); + + xenbus_watch_path(XBT_NIL, path); + + xenbus_wait_for_value(path,"4"); + + //free(backend); + free(res); + + printk("**************************\n"); + + init_rx_buffers(); + + unsigned char rawmac[6]; + sscanf(mac,"%x:%x:%x:%x:%x:%x", + &rawmac[0], + &rawmac[1], + &rawmac[2], + &rawmac[3], + &rawmac[4], + &rawmac[5]); + + net_app_main(si,rawmac); +} + +void shutdown_netfront(void) +{ + //xenbus_transaction_t xbt; + char* err; + char nodename[] = "device/vif/0"; + + char path[256]; + + printk("close network: backend at %s\n",backend); + + err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6); /* closing */ + sprintf(path,"%s/state",backend); + + xenbus_wait_for_value(path,"6"); + + err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1); + + xenbus_wait_for_value(path,"2"); + + unbind_all_ports(); + +} + + +void init_rx_buffers(void) +{ + struct net_info* np = &net_info; + int i, requeue_idx; + netif_rx_request_t *req; + int notify; + + np->rx.req_prod_pvt = requeue_idx; + + + /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ + for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) + { + struct net_buffer* buf = &rx_buffers[requeue_idx]; + req = RING_GET_REQUEST(&np->rx, requeue_idx); + + buf->gref = req->gref = + gnttab_grant_access(0,virt_to_mfn(buf->page),0); + + req->id = requeue_idx; + + requeue_idx++; + } + + np->rx.req_prod_pvt = requeue_idx; + + + + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify); + + if(notify) + notify_remote_via_evtchn(np->evtchn); + + np->rx.sring->rsp_event = np->rx.rsp_cons + 1; + + +} + + +void netfront_xmit(unsigned char* data,int len) +{ + int flags; + local_irq_save(flags); + + struct net_info* info = &net_info; + struct netif_tx_request *tx; + RING_IDX i = info->tx.req_prod_pvt; + int notify; + int id = get_id_from_freelist(tx_freelist); + struct net_buffer* buf = &tx_buffers[id]; + void* page = buf->page; + + tx = RING_GET_REQUEST(&info->tx, i); + + memcpy(page,data,len); + + buf->gref = + tx->gref = gnttab_grant_access(0,virt_to_mfn(page),0); + + tx->offset=0; + tx->size = len; + tx->flags=0; + tx->id = id; + info->tx.req_prod_pvt = i + 1; + + wmb(); + + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->tx, notify); + + if(notify) notify_remote_via_evtchn(info->evtchn); + + network_tx_buf_gc(); + + local_irq_restore(flags); +}