ia64/xen-unstable

view extras/mini-os/netfront.c @ 17042:a905c582a406

Add stubdomain support. See stubdom/README for usage details.

- Move PAGE_SIZE and STACK_SIZE into __PAGE_SIZE and __STACK_SIZE in
arch_limits.h so as to permit getting them from there without
pulling all the internal Mini-OS defines.
- Setup a xen-elf cross-compilation environment in stubdom/cross-root
- Add a POSIX layer on top of Mini-OS by linking against the newlib C
library and lwIP, and implementing the Unixish part in mini-os/lib/sys.c
- Cross-compile zlib and libpci too.
- Add an xs.h-compatible layer on top of Mini-OS' xenbus.
- Cross-compile libxc with an additional xc_minios.c and a few things
disabled.
- Cross-compile ioemu with an additional block-vbd, but without sound,
tpm and other details. A few hacks are needed:
- Align ide and scsi buffers at least on sector size to permit
direct transmission to the block backend. While we are at it, just
page-align it to possibly save a segment. Also, limit the scsi
buffer size because of limitations of the block paravirtualization
protocol.
- Allocate big tables dynamically rather that letting them go to
bss: when Mini-OS gets installed in memory, bss is not lazily
allocated, and doing so during Mini-OS is unnecessarily trick while
we can simply use malloc.
- Had to change the Mini-OS compilation somehow, so as to export
Mini-OS compilation flags to the Makefiles of libxc and ioemu.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Feb 12 14:35:39 2008 +0000 (2008-02-12)
parents c9844192c965
children ea5ee63548e4
line source
1 /* Minimal network driver for Mini-OS.
2 * Copyright (c) 2006-2007 Jacob Gorm Hansen, University of Copenhagen.
3 * Based on netfront.c from Xen Linux.
4 *
5 * Does not handle fragments or extras.
6 */
8 #include <os.h>
9 #include <xenbus.h>
10 #include <events.h>
11 #include <errno.h>
12 #include <xen/io/netif.h>
13 #include <gnttab.h>
14 #include <xmalloc.h>
15 #include <time.h>
16 #include <netfront.h>
17 #include <lib.h>
18 #include <semaphore.h>
20 DECLARE_WAIT_QUEUE_HEAD(netfront_queue);
22 #ifdef HAVE_LIBC
23 #define NETIF_SELECT_RX ((void*)-1)
24 #endif
28 #define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
29 #define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
30 #define GRANT_INVALID_REF 0
33 struct net_buffer {
34 void* page;
35 grant_ref_t gref;
36 };
38 struct netfront_dev {
39 domid_t dom;
41 unsigned short tx_freelist[NET_TX_RING_SIZE];
42 struct semaphore tx_sem;
44 struct net_buffer rx_buffers[NET_RX_RING_SIZE];
45 struct net_buffer tx_buffers[NET_TX_RING_SIZE];
47 struct netif_tx_front_ring tx;
48 struct netif_rx_front_ring rx;
49 grant_ref_t tx_ring_ref;
50 grant_ref_t rx_ring_ref;
51 evtchn_port_t evtchn, local_port;
53 char *nodename;
54 char *backend;
56 #ifdef HAVE_LIBC
57 int fd;
58 unsigned char *data;
59 size_t len;
60 size_t rlen;
61 #endif
63 void (*netif_rx)(unsigned char* data, int len);
64 };
66 void init_rx_buffers(struct netfront_dev *dev);
68 static inline void add_id_to_freelist(unsigned int id,unsigned short* freelist)
69 {
70 freelist[id] = freelist[0];
71 freelist[0] = id;
72 }
74 static inline unsigned short get_id_from_freelist(unsigned short* freelist)
75 {
76 unsigned int id = freelist[0];
77 freelist[0] = freelist[id];
78 return id;
79 }
81 __attribute__((weak)) void netif_rx(unsigned char* data,int len)
82 {
83 printk("%d bytes incoming at %p\n",len,data);
84 }
86 __attribute__((weak)) void net_app_main(void*si,unsigned char*mac) {}
88 static inline int xennet_rxidx(RING_IDX idx)
89 {
90 return idx & (NET_RX_RING_SIZE - 1);
91 }
93 void network_rx(struct netfront_dev *dev)
94 {
95 RING_IDX rp,cons;
96 struct netif_rx_response *rx;
99 moretodo:
100 rp = dev->rx.sring->rsp_prod;
101 rmb(); /* Ensure we see queued responses up to 'rp'. */
102 cons = dev->rx.rsp_cons;
104 int nr_consumed=0;
105 int some = 0;
106 while ((cons != rp) && !some)
107 {
108 struct net_buffer* buf;
109 unsigned char* page;
111 rx = RING_GET_RESPONSE(&dev->rx, cons);
113 if (rx->flags & NETRXF_extra_info)
114 {
115 printk("+++++++++++++++++++++ we have extras!\n");
116 continue;
117 }
120 if (rx->status == NETIF_RSP_NULL) continue;
122 int id = rx->id;
124 buf = &dev->rx_buffers[id];
125 page = (unsigned char*)buf->page;
126 gnttab_end_access(buf->gref);
128 if(rx->status>0)
129 {
130 #ifdef HAVE_LIBC
131 if (dev->netif_rx == NETIF_SELECT_RX) {
132 int len = rx->status;
133 ASSERT(current == main_thread);
134 if (len > dev->len)
135 len = dev->len;
136 memcpy(dev->data, page+rx->offset, len);
137 dev->rlen = len;
138 some = 1;
139 } else
140 #endif
141 dev->netif_rx(page+rx->offset,rx->status);
142 }
144 nr_consumed++;
146 ++cons;
147 }
148 dev->rx.rsp_cons=cons;
150 int more;
151 RING_FINAL_CHECK_FOR_RESPONSES(&dev->rx,more);
152 if(more && !some) goto moretodo;
154 RING_IDX req_prod = dev->rx.req_prod_pvt;
156 int i;
157 netif_rx_request_t *req;
159 for(i=0; i<nr_consumed; i++)
160 {
161 int id = xennet_rxidx(req_prod + i);
162 req = RING_GET_REQUEST(&dev->rx, req_prod + i);
163 struct net_buffer* buf = &dev->rx_buffers[id];
164 void* page = buf->page;
166 /* We are sure to have free gnttab entries since they got released above */
167 buf->gref = req->gref =
168 gnttab_grant_access(dev->dom,virt_to_mfn(page),0);
170 req->id = id;
171 }
173 wmb();
175 dev->rx.req_prod_pvt = req_prod + i;
177 int notify;
178 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->rx, notify);
179 if (notify)
180 notify_remote_via_evtchn(dev->evtchn);
182 }
184 void network_tx_buf_gc(struct netfront_dev *dev)
185 {
188 RING_IDX cons, prod;
189 unsigned short id;
191 do {
192 prod = dev->tx.sring->rsp_prod;
193 rmb(); /* Ensure we see responses up to 'rp'. */
195 for (cons = dev->tx.rsp_cons; cons != prod; cons++)
196 {
197 struct netif_tx_response *txrsp;
199 txrsp = RING_GET_RESPONSE(&dev->tx, cons);
200 if (txrsp->status == NETIF_RSP_NULL)
201 continue;
203 if (txrsp->status == NETIF_RSP_ERROR)
204 printk("packet error\n");
206 id = txrsp->id;
207 struct net_buffer* buf = &dev->tx_buffers[id];
208 gnttab_end_access(buf->gref);
209 buf->gref=GRANT_INVALID_REF;
211 add_id_to_freelist(id,dev->tx_freelist);
212 up(&dev->tx_sem);
213 }
215 dev->tx.rsp_cons = prod;
217 /*
218 * Set a new event, then check for race with update of tx_cons.
219 * Note that it is essential to schedule a callback, no matter
220 * how few tx_buffers are pending. Even if there is space in the
221 * transmit ring, higher layers may be blocked because too much
222 * data is outstanding: in such cases notification from Xen is
223 * likely to be the only kick that we'll get.
224 */
225 dev->tx.sring->rsp_event =
226 prod + ((dev->tx.sring->req_prod - prod) >> 1) + 1;
227 mb();
228 } while ((cons == prod) && (prod != dev->tx.sring->rsp_prod));
231 }
233 void netfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
234 {
235 int flags;
236 struct netfront_dev *dev = data;
238 local_irq_save(flags);
240 network_tx_buf_gc(dev);
241 network_rx(dev);
243 local_irq_restore(flags);
244 }
246 #ifdef HAVE_LIBC
247 void netfront_select_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
248 {
249 int flags;
250 struct netfront_dev *dev = data;
251 int fd = dev->fd;
253 local_irq_save(flags);
254 network_tx_buf_gc(dev);
255 local_irq_restore(flags);
257 files[fd].read = 1;
258 wake_up(&netfront_queue);
259 }
260 #endif
262 struct netfront_dev *init_netfront(char *nodename, void (*thenetif_rx)(unsigned char* data, int len), unsigned char rawmac[6])
263 {
264 xenbus_transaction_t xbt;
265 char* err;
266 char* message=NULL;
267 struct netif_tx_sring *txs;
268 struct netif_rx_sring *rxs;
269 int retry=0;
270 int i;
271 char* mac;
272 char* msg;
274 struct netfront_dev *dev;
276 if (!nodename)
277 nodename = "device/vif/0";
279 char path[strlen(nodename) + 1 + 10 + 1];
281 if (!thenetif_rx)
282 thenetif_rx = netif_rx;
284 printk("************************ NETFRONT for %s **********\n\n\n", nodename);
286 dev = malloc(sizeof(*dev));
287 dev->nodename = strdup(nodename);
289 printk("net TX ring size %d\n", NET_TX_RING_SIZE);
290 printk("net RX ring size %d\n", NET_RX_RING_SIZE);
291 init_SEMAPHORE(&dev->tx_sem, NET_TX_RING_SIZE);
292 for(i=0;i<NET_TX_RING_SIZE;i++)
293 {
294 add_id_to_freelist(i,dev->tx_freelist);
295 dev->tx_buffers[i].page = NULL;
296 }
298 for(i=0;i<NET_RX_RING_SIZE;i++)
299 {
300 /* TODO: that's a lot of memory */
301 dev->rx_buffers[i].page = (char*)alloc_page();
302 }
304 evtchn_alloc_unbound_t op;
305 op.dom = DOMID_SELF;
306 snprintf(path, sizeof(path), "%s/backend-id", nodename);
307 dev->dom = op.remote_dom = xenbus_read_integer(path);
308 HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
309 clear_evtchn(op.port); /* Without, handler gets invoked now! */
310 #ifdef HAVE_LIBC
311 if (thenetif_rx == NETIF_SELECT_RX)
312 dev->local_port = bind_evtchn(op.port, netfront_select_handler, dev);
313 else
314 #endif
315 dev->local_port = bind_evtchn(op.port, netfront_handler, dev);
316 dev->evtchn=op.port;
318 txs = (struct netif_tx_sring*) alloc_page();
319 rxs = (struct netif_rx_sring *) alloc_page();
320 memset(txs,0,PAGE_SIZE);
321 memset(rxs,0,PAGE_SIZE);
324 SHARED_RING_INIT(txs);
325 SHARED_RING_INIT(rxs);
326 FRONT_RING_INIT(&dev->tx, txs, PAGE_SIZE);
327 FRONT_RING_INIT(&dev->rx, rxs, PAGE_SIZE);
329 dev->tx_ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(txs),0);
330 dev->rx_ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(rxs),0);
332 dev->netif_rx = thenetif_rx;
334 // FIXME: proper frees on failures
335 again:
336 err = xenbus_transaction_start(&xbt);
337 if (err) {
338 printk("starting transaction\n");
339 }
341 err = xenbus_printf(xbt, nodename, "tx-ring-ref","%u",
342 dev->tx_ring_ref);
343 if (err) {
344 message = "writing tx ring-ref";
345 goto abort_transaction;
346 }
347 err = xenbus_printf(xbt, nodename, "rx-ring-ref","%u",
348 dev->rx_ring_ref);
349 if (err) {
350 message = "writing rx ring-ref";
351 goto abort_transaction;
352 }
353 err = xenbus_printf(xbt, nodename,
354 "event-channel", "%u", dev->evtchn);
355 if (err) {
356 message = "writing event-channel";
357 goto abort_transaction;
358 }
360 err = xenbus_printf(xbt, nodename, "request-rx-copy", "%u", 1);
362 if (err) {
363 message = "writing request-rx-copy";
364 goto abort_transaction;
365 }
367 err = xenbus_printf(xbt, nodename, "state", "%u",
368 4); /* connected */
371 err = xenbus_transaction_end(xbt, 0, &retry);
372 if (retry) {
373 goto again;
374 printk("completing transaction\n");
375 }
377 goto done;
379 abort_transaction:
380 xenbus_transaction_end(xbt, 1, &retry);
381 return NULL;
383 done:
385 snprintf(path, sizeof(path), "%s/backend", nodename);
386 msg = xenbus_read(XBT_NIL, path, &dev->backend);
387 snprintf(path, sizeof(path), "%s/mac", nodename);
388 msg = xenbus_read(XBT_NIL, path, &mac);
390 if ((dev->backend == NULL) || (mac == NULL)) {
391 struct evtchn_close op = { dev->local_port };
392 printk("%s: backend/mac failed\n", __func__);
393 unbind_evtchn(dev->local_port);
394 HYPERVISOR_event_channel_op(EVTCHNOP_close, &op);
395 return NULL;
396 }
398 printk("backend at %s\n",dev->backend);
399 printk("mac is %s\n",mac);
401 {
402 char path[strlen(dev->backend) + 1 + 5 + 1];
403 snprintf(path, sizeof(path), "%s/state", dev->backend);
405 xenbus_watch_path(XBT_NIL, path);
407 xenbus_wait_for_value(path,"4");
409 xenbus_unwatch_path(XBT_NIL, path);
410 }
412 printk("**************************\n");
414 init_rx_buffers(dev);
416 /* Special conversion specifier 'hh' needed for __ia64__. Without
417 this mini-os panics with 'Unaligned reference'. */
418 if (rawmac)
419 sscanf(mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
420 &rawmac[0],
421 &rawmac[1],
422 &rawmac[2],
423 &rawmac[3],
424 &rawmac[4],
425 &rawmac[5]);
427 return dev;
428 }
430 #ifdef HAVE_LIBC
431 int netfront_tap_open(char *nodename) {
432 struct netfront_dev *dev;
434 dev = init_netfront(nodename, NETIF_SELECT_RX, NULL);
435 if (!dev) {
436 printk("TAP open failed\n");
437 errno = EIO;
438 return -1;
439 }
440 dev->fd = alloc_fd(FTYPE_TAP);
441 printk("tap_open(%s) -> %d\n", nodename, dev->fd);
442 files[dev->fd].tap.dev = dev;
443 return dev->fd;
444 }
445 #endif
447 void shutdown_netfront(struct netfront_dev *dev)
448 {
449 char* err;
450 char *nodename = dev->nodename;
452 char path[strlen(dev->backend) + 1 + 5 + 1];
454 printk("close network: backend at %s\n",dev->backend);
456 snprintf(path, sizeof(path), "%s/state", dev->backend);
457 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
458 xenbus_wait_for_value(path,"5");
460 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
461 xenbus_wait_for_value(path,"6");
463 unbind_evtchn(dev->local_port);
465 free(nodename);
466 free(dev->backend);
467 free(dev);
468 }
471 void init_rx_buffers(struct netfront_dev *dev)
472 {
473 int i, requeue_idx;
474 netif_rx_request_t *req;
475 int notify;
477 /* Rebuild the RX buffer freelist and the RX ring itself. */
478 for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++)
479 {
480 struct net_buffer* buf = &dev->rx_buffers[requeue_idx];
481 req = RING_GET_REQUEST(&dev->rx, requeue_idx);
483 buf->gref = req->gref =
484 gnttab_grant_access(dev->dom,virt_to_mfn(buf->page),0);
486 req->id = requeue_idx;
488 requeue_idx++;
489 }
491 dev->rx.req_prod_pvt = requeue_idx;
493 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->rx, notify);
495 if (notify)
496 notify_remote_via_evtchn(dev->evtchn);
498 dev->rx.sring->rsp_event = dev->rx.rsp_cons + 1;
499 }
502 void netfront_xmit(struct netfront_dev *dev, unsigned char* data,int len)
503 {
504 int flags;
505 struct netif_tx_request *tx;
506 RING_IDX i;
507 int notify;
508 unsigned short id;
509 struct net_buffer* buf;
510 void* page;
512 down(&dev->tx_sem);
514 local_irq_save(flags);
515 id = get_id_from_freelist(dev->tx_freelist);
516 local_irq_restore(flags);
518 buf = &dev->tx_buffers[id];
519 page = buf->page;
520 if (!page)
521 page = buf->page = (char*) alloc_page();
523 i = dev->tx.req_prod_pvt;
524 tx = RING_GET_REQUEST(&dev->tx, i);
526 memcpy(page,data,len);
528 buf->gref =
529 tx->gref = gnttab_grant_access(dev->dom,virt_to_mfn(page),1);
531 tx->offset=0;
532 tx->size = len;
533 tx->flags=0;
534 tx->id = id;
535 dev->tx.req_prod_pvt = i + 1;
537 wmb();
539 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->tx, notify);
541 if(notify) notify_remote_via_evtchn(dev->evtchn);
543 local_irq_save(flags);
544 network_tx_buf_gc(dev);
545 local_irq_restore(flags);
546 }
548 #ifdef HAVE_LIBC
549 ssize_t netfront_receive(struct netfront_dev *dev, unsigned char *data, size_t len)
550 {
551 unsigned long flags;
552 int fd = dev->fd;
553 ASSERT(current == main_thread);
555 dev->rlen = 0;
556 dev->data = data;
557 dev->len = len;
559 local_irq_save(flags);
560 network_rx(dev);
561 if (!dev->rlen)
562 /* No data for us, make select stop returning */
563 files[fd].read = 0;
564 /* Before re-enabling the interrupts, in case a packet just arrived in the
565 * meanwhile. */
566 local_irq_restore(flags);
568 dev->data = NULL;
569 dev->len = 0;
571 return dev->rlen;
572 }
573 #endif