static int common_bind(struct common *c) { int mfn; if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1) return -1; if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1) return -1; c->page = xc_map_foreign_range(xen_xc, c->xendev.dom, XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn); if (c->page == NULL) return -1; xen_be_bind_evtchn(&c->xendev); xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n", mfn, c->xendev.remote_port, c->xendev.local_port); return 0; }
static void qemu_aio_complete(void *opaque, int ret) { struct ioreq *ioreq = opaque; if (ret != 0) { xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n", ioreq->req.operation == BLKIF_OP_READ ? "read" : "write"); ioreq->aio_errors++; } ioreq->aio_inflight--; if (ioreq->aio_inflight > 0) return; if (ioreq->postsync) bdrv_flush(ioreq->blkdev->bs); ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; ioreq_unmap(ioreq); ioreq_finish(ioreq); qemu_bh_schedule(ioreq->blkdev->bh); }
static void fb_disconnect(struct XenDevice *xendev) { struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev); /* * FIXME: qemu can't un-init gfx display (yet?). * Replacing the framebuffer with anonymous shared memory * instead. This releases the guest pages and keeps qemu happy. */ fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if (fb->pixels == MAP_FAILED) { xen_be_printf(xendev, 0, "Couldn't replace the framebuffer with anonymous memory errno=%d\n", errno); } common_unbind(&fb->c); fb->feature_update = 0; fb->bug_trigger = 0; }
static int con_init(struct XenDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); char *type, *dom, label[32]; int ret = 0; const char *output; /* setup */ dom = xs_get_domain_path(xenstore, con->xendev.dom); if (!xendev->dev) { snprintf(con->console, sizeof(con->console), "%s/console", dom); } else { snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev); } free(dom); type = xenstore_read_str(con->console, "type"); if (!type || strcmp(type, "ioemu") != 0) { xen_be_printf(xendev, 1, "not for me (type=%s)\n", type); ret = -1; goto out; } output = xenstore_read_str(con->console, "output"); /* no Xen override, use qemu output device */ if (output == NULL) { con->chr = serial_hds[con->xendev.dev]; } else { snprintf(label, sizeof(label), "xencons%d", con->xendev.dev); con->chr = qemu_chr_new(label, output, NULL); } xenstore_store_pv_console_info(con->xendev.dev, con->chr); out: g_free(type); return ret; }
/* * This copies data from the guest framebuffer region, into QEMU's * displaysurface. qemu uses 16 or 32 bpp. In case the pv framebuffer * uses something else we must convert and copy, otherwise we can * supply the buffer directly and no thing here. */ static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h) { DisplaySurface *surface = qemu_console_surface(xenfb->c.con); int line, oops = 0; int bpp = surface_bits_per_pixel(surface); int linesize = surface_stride(surface); uint8_t *data = surface_data(surface); if (!is_buffer_shared(surface)) { switch (xenfb->depth) { case 8: if (bpp == 16) { BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5); } else if (bpp == 32) { BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8); } else { oops = 1; } break; case 24: if (bpp == 16) { BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5); } else if (bpp == 32) { BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8); } else { oops = 1; } break; default: oops = 1; } } if (oops) /* should not happen */ xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n", __FUNCTION__, xenfb->depth, bpp); dpy_gfx_update(xenfb->c.con, x, y, w, h); }
/* * FIXME/TODO: Kill this. * Temporary needed while DisplayState reorganization is in flight. */ void xen_init_display(int domid) { struct XenDevice *xfb, *xin; struct XenFB *fb; struct XenInput *in; int i = 0; wait_more: i++; main_loop_wait(true); xfb = xen_be_find_xendev("vfb", domid, 0); xin = xen_be_find_xendev("vkbd", domid, 0); if (!xfb || !xin) { if (i < 256) { usleep(10000); goto wait_more; } xen_be_printf(NULL, 1, "displaystate setup failed\n"); return; } /* vfb */ fb = container_of(xfb, struct XenFB, c.xendev); fb->c.ds = graphic_console_init(xenfb_update, xenfb_invalidate, NULL, NULL, fb); fb->have_console = 1; /* vkbd */ in = container_of(xin, struct XenInput, c.xendev); in->c.ds = fb->c.ds; /* retry ->init() */ xen_be_check_state(xin); xen_be_check_state(xfb); }
static int con_initialise(struct XenDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); int limit; if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1) return -1; if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1) return -1; if (xenstore_read_int(con->console, "limit", &limit) == 0) con->buffer.max_capacity = limit; if (!xendev->dev) { con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom, XC_PAGE_SIZE, PROT_READ|PROT_WRITE, con->ring_ref); } else { con->sring = xc_gnttab_map_grant_ref(xendev->gnttabdev, con->xendev.dom, con->ring_ref, PROT_READ|PROT_WRITE); } if (!con->sring) return -1; xen_be_bind_evtchn(&con->xendev); if (con->chr) qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive, NULL, con); xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n", con->ring_ref, con->xendev.remote_port, con->xendev.local_port, con->buffer.max_capacity); return 0; }
static int common_bind(struct common *c) { uint64_t val; xen_pfn_t mfn; if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &val) == -1) return -1; mfn = (xen_pfn_t)val; assert(val == mfn); if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1) return -1; c->page = xenforeignmemory_map(xen_fmem, c->xendev.dom, PROT_READ | PROT_WRITE, 1, &mfn, NULL); if (c->page == NULL) return -1; xen_be_bind_evtchn(&c->xendev); xen_be_printf(&c->xendev, 1, "ring mfn %"PRI_xen_pfn", remote-port %d, local-port %d\n", mfn, c->xendev.remote_port, c->xendev.local_port); return 0; }
static int input_initialise(struct XenDevice *xendev) { struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); int rc; if (!in->c.ds) { char *vfb = xenstore_read_str(NULL, "device/vfb"); if (vfb == NULL) { /* there is no vfb, run vkbd on its own */ in->c.ds = get_displaystate(); } else { g_free(vfb); xen_be_printf(xendev, 1, "ds not set (yet)\n"); return -1; } } rc = common_bind(&in->c); if (rc != 0) return rc; qemu_add_kbd_event_handler(xenfb_key_event, in); return 0; }
int xen_config_dev_nic(NICInfo *nic) { char fe[256], be[256]; char mac[20]; int vlan_id = -1; net_hub_id_for_client(nic->netdev, &vlan_id); snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x", nic->macaddr.a[0], nic->macaddr.a[1], nic->macaddr.a[2], nic->macaddr.a[3], nic->macaddr.a[4], nic->macaddr.a[5]); xen_be_printf(NULL, 1, "config nic %d: mac=\"%s\"\n", vlan_id, mac); xen_config_dev_dirs("vif", "qnic", vlan_id, fe, be, sizeof(fe)); /* frontend */ xenstore_write_int(fe, "handle", vlan_id); xenstore_write_str(fe, "mac", mac); /* backend */ xenstore_write_int(be, "handle", vlan_id); xenstore_write_str(be, "mac", mac); /* common stuff */ return xen_config_dev_all(fe, be); }
/* * translate request into iovec + start offset * do sanity checks along the way */ static int ioreq_parse(struct ioreq *ioreq) { struct XenBlkDev *blkdev = ioreq->blkdev; uintptr_t mem; size_t len; int i; xen_be_printf(&blkdev->xendev, 3, "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n", ioreq->req.operation, ioreq->req.nr_segments, ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number); switch (ioreq->req.operation) { case BLKIF_OP_READ: ioreq->prot = PROT_WRITE; /* to memory */ break; case BLKIF_OP_WRITE_BARRIER: if (!ioreq->req.nr_segments) { ioreq->presync = 1; return 0; } if (!syncwrite) ioreq->presync = ioreq->postsync = 1; /* fall through */ case BLKIF_OP_WRITE: ioreq->prot = PROT_READ; /* from memory */ if (syncwrite) ioreq->postsync = 1; break; default: xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n", ioreq->req.operation); goto err; }; if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') { xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n"); goto err; } ioreq->start = ioreq->req.sector_number * blkdev->file_blk; for (i = 0; i < ioreq->req.nr_segments; i++) { if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) { xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n"); goto err; } if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) { xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n"); goto err; } if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) { xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n"); goto err; } ioreq->domids[i] = blkdev->xendev.dom; ioreq->refs[i] = ioreq->req.seg[i].gref; mem = ioreq->req.seg[i].first_sect * blkdev->file_blk; len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk; qemu_iovec_add(&ioreq->v, (void*)mem, len); } if (ioreq->start + ioreq->v.size > blkdev->file_size) { xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n"); goto err; } return 0; err: ioreq->status = BLKIF_RSP_ERROR; return -1; }
static int blk_connect(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) { return -1; } if (xenstore_read_fe_int(&blkdev->xendev, "event-channel", &blkdev->xendev.remote_port) == -1) { return -1; } blkdev->protocol = BLKIF_PROTOCOL_NATIVE; if (blkdev->xendev.protocol) { if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0) { blkdev->protocol = BLKIF_PROTOCOL_X86_32; } if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0) { blkdev->protocol = BLKIF_PROTOCOL_X86_64; } } blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev, blkdev->xendev.dom, blkdev->ring_ref, PROT_READ | PROT_WRITE); if (!blkdev->sring) { return -1; } blkdev->cnt_map++; switch (blkdev->protocol) { case BLKIF_PROTOCOL_NATIVE: { blkif_sring_t *sring_native = blkdev->sring; BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE); break; } case BLKIF_PROTOCOL_X86_32: { blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring; BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, XC_PAGE_SIZE); break; } case BLKIF_PROTOCOL_X86_64: { blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring; BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, XC_PAGE_SIZE); break; } } xen_be_bind_evtchn(&blkdev->xendev); xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, " "remote port %d, local port %d\n", blkdev->xendev.protocol, blkdev->ring_ref, blkdev->xendev.remote_port, blkdev->xendev.local_port); return 0; }
static void xenfb_handle_events(struct XenFB *xenfb) { uint32_t prod, cons; struct xenfb_page *page = xenfb->c.page; prod = page->out_prod; if (prod == page->out_cons) return; xen_rmb(); /* ensure we see ring contents up to prod */ for (cons = page->out_cons; cons != prod; cons++) { union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); int x, y, w, h; switch (event->type) { case XENFB_TYPE_UPDATE: if (xenfb->up_count == UP_QUEUE) xenfb->up_fullscreen = 1; if (xenfb->up_fullscreen) break; x = MAX(event->update.x, 0); y = MAX(event->update.y, 0); w = MIN(event->update.width, xenfb->width - x); h = MIN(event->update.height, xenfb->height - y); if (w < 0 || h < 0) { xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n"); break; } if (x != event->update.x || y != event->update.y || w != event->update.width || h != event->update.height) { xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n"); } if (w == xenfb->width && h > xenfb->height / 2) { /* scroll detector: updated more than 50% of the lines, * don't bother keeping track of the rectangles then */ xenfb->up_fullscreen = 1; } else { xenfb->up_rects[xenfb->up_count].x = x; xenfb->up_rects[xenfb->up_count].y = y; xenfb->up_rects[xenfb->up_count].w = w; xenfb->up_rects[xenfb->up_count].h = h; xenfb->up_count++; } break; #ifdef XENFB_TYPE_RESIZE case XENFB_TYPE_RESIZE: if (xenfb_configure_fb(xenfb, xenfb->fb_len, event->resize.width, event->resize.height, event->resize.depth, xenfb->fb_len, event->resize.offset, event->resize.stride) < 0) break; xenfb_invalidate(xenfb); break; #endif } } xen_mb(); /* ensure we're done with ring contents */ page->out_cons = cons; }
/* * Periodic update of display. * Also transmit the refresh interval to the frontend. * * Never ever do any qemu display operations * (resize, screen update) outside this function. * Our screen might be inactive. When asked for * an update we know it is active. */ static void xenfb_update(void *opaque) { struct XenFB *xenfb = opaque; struct DisplayChangeListener *l; int i; if (xenfb->c.xendev.be_state != XenbusStateConnected) return; if (xenfb->feature_update) { #ifdef XENFB_TYPE_REFRESH_PERIOD int period = 99999999; int idle = 1; if (xenfb_queue_full(xenfb)) return; for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) { if (l->idle) continue; idle = 0; if (!l->gui_timer_interval) { if (period > GUI_REFRESH_INTERVAL) period = GUI_REFRESH_INTERVAL; } else { if (period > l->gui_timer_interval) period = l->gui_timer_interval; } } if (idle) period = XENFB_NO_REFRESH; if (xenfb->refresh_period != period) { xenfb_send_refresh_period(xenfb, period); xenfb->refresh_period = period; xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period); } #else ; /* nothing */ #endif } else { /* we don't get update notifications, thus use the * sledge hammer approach ... */ xenfb->up_fullscreen = 1; } /* resize if needed */ if (xenfb->do_resize) { xenfb->do_resize = 0; switch (xenfb->depth) { case 16: case 32: /* console.c supported depth -> buffer can be used directly */ qemu_free_displaysurface(xenfb->c.ds); xenfb->c.ds->surface = qemu_create_displaysurface_from (xenfb->width, xenfb->height, xenfb->depth, xenfb->row_stride, xenfb->pixels + xenfb->offset); break; default: /* we must convert stuff */ qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height); break; } xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n", xenfb->width, xenfb->height, xenfb->depth, is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : ""); dpy_resize(xenfb->c.ds); xenfb->up_fullscreen = 1; } /* run queued updates */ if (xenfb->up_fullscreen) { xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n"); xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); } else if (xenfb->up_count) { xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count); for (i = 0; i < xenfb->up_count; i++) xenfb_guest_copy(xenfb, xenfb->up_rects[i].x, xenfb->up_rects[i].y, xenfb->up_rects[i].w, xenfb->up_rects[i].h); } else { xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n"); } xenfb->up_count = 0; xenfb->up_fullscreen = 0; }
static int ioreq_runio_qemu_sync(struct ioreq *ioreq) { struct XenBlkDev *blkdev = ioreq->blkdev; int i, rc, len = 0; off_t pos; if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) goto err; if (ioreq->presync) bdrv_flush(blkdev->bs); switch (ioreq->req.operation) { case BLKIF_OP_READ: pos = ioreq->start; for (i = 0; i < ioreq->v.niov; i++) { rc = bdrv_read(blkdev->bs, pos / BLOCK_SIZE, ioreq->v.iov[i].iov_base, ioreq->v.iov[i].iov_len / BLOCK_SIZE); if (rc != 0) { xen_be_printf(&blkdev->xendev, 0, "rd I/O error (%p, len %zd)\n", ioreq->v.iov[i].iov_base, ioreq->v.iov[i].iov_len); goto err; } len += ioreq->v.iov[i].iov_len; pos += ioreq->v.iov[i].iov_len; } break; case BLKIF_OP_WRITE: case BLKIF_OP_WRITE_BARRIER: if (!ioreq->req.nr_segments) break; pos = ioreq->start; for (i = 0; i < ioreq->v.niov; i++) { rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE, ioreq->v.iov[i].iov_base, ioreq->v.iov[i].iov_len / BLOCK_SIZE); if (rc != 0) { xen_be_printf(&blkdev->xendev, 0, "wr I/O error (%p, len %zd)\n", ioreq->v.iov[i].iov_base, ioreq->v.iov[i].iov_len); goto err; } len += ioreq->v.iov[i].iov_len; pos += ioreq->v.iov[i].iov_len; } break; default: /* unknown operation (shouldn't happen -- parse catches this) */ goto err; } if (ioreq->postsync) bdrv_flush(blkdev->bs); ioreq->status = BLKIF_RSP_OKAY; ioreq_unmap(ioreq); ioreq_finish(ioreq); return 0; err: ioreq->status = BLKIF_RSP_ERROR; return -1; }
static int blk_init(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); int index, qflags, have_barriers, info = 0; char *h; /* read xenstore entries */ if (blkdev->params == NULL) { blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params"); h = strchr(blkdev->params, ':'); if (h != NULL) { blkdev->fileproto = blkdev->params; blkdev->filename = h+1; *h = 0; } else { blkdev->fileproto = "<unset>"; blkdev->filename = blkdev->params; } } if (blkdev->mode == NULL) blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode"); if (blkdev->type == NULL) blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type"); if (blkdev->dev == NULL) blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev"); if (blkdev->devtype == NULL) blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type"); /* do we have all we need? */ if (blkdev->params == NULL || blkdev->mode == NULL || blkdev->type == NULL || blkdev->dev == NULL) return -1; /* read-only ? */ if (strcmp(blkdev->mode, "w") == 0) { qflags = BDRV_O_RDWR; } else { qflags = 0; info |= VDISK_READONLY; } /* cdrom ? */ if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) info |= VDISK_CDROM; /* init qemu block driver */ index = (blkdev->xendev.dev - 202 * 256) / 16; blkdev->dinfo = drive_get(IF_XEN, 0, index); if (!blkdev->dinfo) { /* setup via xenbus -> create new block driver instance */ xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n"); blkdev->bs = bdrv_new(blkdev->dev); if (bdrv_open(blkdev->bs, blkdev->filename, qflags, bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) { bdrv_delete(blkdev->bs); return -1; } } else { /* setup via qemu cmdline -> already setup for us */ xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n"); blkdev->bs = blkdev->dinfo->bdrv; } blkdev->file_blk = BLOCK_SIZE; blkdev->file_size = bdrv_getlength(blkdev->bs); if (blkdev->file_size < 0) { xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n", (int)blkdev->file_size, strerror(-blkdev->file_size), blkdev->bs->drv ? blkdev->bs->drv->format_name : "-"); blkdev->file_size = 0; } have_barriers = blkdev->bs->drv && blkdev->bs->drv->bdrv_flush ? 1 : 0; xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\"," " size %" PRId64 " (%" PRId64 " MB)\n", blkdev->type, blkdev->fileproto, blkdev->filename, blkdev->file_size, blkdev->file_size >> 20); /* fill info */ xenstore_write_be_int(&blkdev->xendev, "feature-barrier", have_barriers); xenstore_write_be_int(&blkdev->xendev, "info", info); xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk); xenstore_write_be_int(&blkdev->xendev, "sectors", blkdev->file_size / blkdev->file_blk); return 0; }
static void net_tx_packets(struct XenNetDev *netdev) { netif_tx_request_t txreq; RING_IDX rc, rp; void *page; void *tmpbuf = NULL; for (;;) { rc = netdev->tx_ring.req_cons; rp = netdev->tx_ring.sring->req_prod; xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ while ((rc != rp)) { if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc)) { break; } memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq)); netdev->tx_ring.req_cons = ++rc; #if 1 /* should not happen in theory, we don't announce the * * feature-{sg,gso,whatelse} flags in xenstore (yet?) */ if (txreq.flags & NETTXF_extra_info) { xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n"); net_tx_error(netdev, &txreq, rc); continue; } if (txreq.flags & NETTXF_more_data) { xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n"); net_tx_error(netdev, &txreq, rc); continue; } #endif if (txreq.size < 14) { xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size); net_tx_error(netdev, &txreq, rc); continue; } if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) { xen_be_printf(&netdev->xendev, 0, "error: page crossing\n"); net_tx_error(netdev, &txreq, rc); continue; } xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n", txreq.gref, txreq.offset, txreq.size, txreq.flags, (txreq.flags & NETTXF_csum_blank) ? " csum_blank" : "", (txreq.flags & NETTXF_data_validated) ? " data_validated" : "", (txreq.flags & NETTXF_more_data) ? " more_data" : "", (txreq.flags & NETTXF_extra_info) ? " extra_info" : ""); page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev, netdev->xendev.dom, txreq.gref, PROT_READ); if (page == NULL) { xen_be_printf(&netdev->xendev, 0, "error: tx gref dereference failed (%d)\n", txreq.gref); net_tx_error(netdev, &txreq, rc); continue; } if (txreq.flags & NETTXF_csum_blank) { /* have read-only mapping -> can't fill checksum in-place */ if (!tmpbuf) { tmpbuf = g_malloc(XC_PAGE_SIZE); } memcpy(tmpbuf, page + txreq.offset, txreq.size); net_checksum_calculate(tmpbuf, txreq.size); qemu_send_packet(&netdev->nic->nc, tmpbuf, txreq.size); } else { qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size); } xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); net_tx_response(netdev, &txreq, NETIF_RSP_OKAY); } if (!netdev->tx_work) { break; } netdev->tx_work = 0; } g_free(tmpbuf); }