static int img_convert(int argc, char **argv)

{

    int c, n, n1, bs_n, bs_i, compress, cluster_sectors, skip_create;

    int64_t ret = 0;

    int progress = 0, flags;

    const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;

    BlockDriver *drv, *proto_drv;

    BlockDriverState **bs = NULL, *out_bs = NULL;

    int64_t total_sectors, nb_sectors, sector_num, bs_offset;

    int64_t *bs_sectors = NULL;

    uint8_t * buf = NULL;

    size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE;

    const uint8_t *buf1;

    BlockDriverInfo bdi;

    QemuOpts *opts = NULL;

    QemuOptsList *create_opts = NULL;

    const char *out_baseimg_param;

    char *options = NULL;

    const char *snapshot_name = NULL;

    int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */

    bool quiet = false;

    Error *local_err = NULL;

    QemuOpts *sn_opts = NULL;

    fmt = NULL;

    out_fmt = "raw";

    cache = "unsafe";

    out_baseimg = NULL;

    compress = 0;

    skip_create = 0;

    for(;;) {

        c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:qnl:");

        if (c == -1) {

            break;

        }

        switch(c) {

        case '?':

        case 'h':

            help();

            break;

        case 'f':

            fmt = optarg;

            break;

        case 'O':

            out_fmt = optarg;

            break;

        case 'B':

            out_baseimg = optarg;

            break;

        case 'c':

            compress = 1;

            break;

        case 'e':

            error_report("option -e is deprecated, please use \'-o "

                  "encryption\' instead!");

            ret = -1;

            goto fail_getopt;

        case '6':

            error_report("option -6 is deprecated, please use \'-o "

                  "compat6\' instead!");

            ret = -1;

            goto fail_getopt;

        case 'o':

            if (!is_valid_option_list(optarg)) {

                error_report("Invalid option list: %s", optarg);

                ret = -1;

                goto fail_getopt;

            }

            if (!options) {

                options = g_strdup(optarg);

            } else {

                char *old_options = options;

                options = g_strdup_printf("%s,%s", options, optarg);

                g_free(old_options);

            }

            break;

        case 's':

            snapshot_name = optarg;

            break;

        case 'l':

            if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {

                sn_opts = qemu_opts_parse(&internal_snapshot_opts, optarg, 0);

                if (!sn_opts) {

                    error_report("Failed in parsing snapshot param '%s'",

                                 optarg);

                    ret = -1;

                    goto fail_getopt;

                }

            } else {

                snapshot_name = optarg;

            }

            break;

        case 'S':

        {

            int64_t sval;

            char *end;

            sval = strtosz_suffix(optarg, &end, STRTOSZ_DEFSUFFIX_B);

            if (sval < 0 || *end) {

                error_report("Invalid minimum zero buffer size for sparse output specified");

                ret = -1;

                goto fail_getopt;

            }

            min_sparse = sval / BDRV_SECTOR_SIZE;

            break;

        }

        case 'p':

            progress = 1;

            break;

        case 't':

            cache = optarg;

            break;

        case 'q':

            quiet = true;

            break;

        case 'n':

            skip_create = 1;

            break;

        }

    }

    /* Initialize before goto out */

    if (quiet) {

        progress = 0;

    }

    qemu_progress_init(progress, 1.0);

    bs_n = argc - optind - 1;

    out_filename = bs_n >= 1 ? argv[argc - 1] : NULL;

    if (options && has_help_option(options)) {

        ret = print_block_option_help(out_filename, out_fmt);

        goto out;

    }

    if (bs_n < 1) {

        error_exit("Must specify image file name");

    }

    if (bs_n > 1 && out_baseimg) {

        error_report("-B makes no sense when concatenating multiple input "

                     "images");

        ret = -1;

        goto out;

    }

    qemu_progress_print(0, 100);

    bs = g_new0(BlockDriverState *, bs_n);

    bs_sectors = g_new(int64_t, bs_n);

    total_sectors = 0;

    for (bs_i = 0; bs_i < bs_n; bs_i++) {

        char *id = bs_n > 1 ? g_strdup_printf("source %d", bs_i)

                            : g_strdup("source");

        bs[bs_i] = bdrv_new_open(id, argv[optind + bs_i], fmt, BDRV_O_FLAGS,

                                 true, quiet);

        g_free(id);

        if (!bs[bs_i]) {

            error_report("Could not open '%s'", argv[optind + bs_i]);

            ret = -1;

            goto out;

        }

        bs_sectors[bs_i] = bdrv_nb_sectors(bs[bs_i]);

        if (bs_sectors[bs_i] < 0) {

            error_report("Could not get size of %s: %s",

                         argv[optind + bs_i], strerror(-bs_sectors[bs_i]));

            ret = -1;

            goto out;

        }

        total_sectors += bs_sectors[bs_i];

    }

    if (sn_opts) {

        ret = bdrv_snapshot_load_tmp(bs[0],

                                     qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),

                                     qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),

                                     &local_err);

    } else if (snapshot_name != NULL) {

        if (bs_n > 1) {

            error_report("No support for concatenating multiple snapshot");

            ret = -1;

            goto out;

        }

        bdrv_snapshot_load_tmp_by_id_or_name(bs[0], snapshot_name, &local_err);

    }

    if (local_err) {

        error_report("Failed to load snapshot: %s",

                     error_get_pretty(local_err));

        error_free(local_err);

        ret = -1;

        goto out;

    }

    /* Find driver and parse its options */

    drv = bdrv_find_format(out_fmt);

    if (!drv) {

        error_report("Unknown file format '%s'", out_fmt);

        ret = -1;

        goto out;

    }

    proto_drv = bdrv_find_protocol(out_filename, true);

    if (!proto_drv) {

        error_report("Unknown protocol '%s'", out_filename);

        ret = -1;

        goto out;

    }

    create_opts = qemu_opts_append(create_opts, drv->create_opts);

    create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);

    opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);

    if (options && qemu_opts_do_parse(opts, options, NULL)) {

        error_report("Invalid options for file format '%s'", out_fmt);

        ret = -1;

        goto out;

    }

    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512);

    ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL);

    if (ret < 0) {

        goto out;

    }

    /* Get backing file name if -o backing_file was used */

    out_baseimg_param = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);

    if (out_baseimg_param) {

        out_baseimg = out_baseimg_param;

    }

    /* Check if compression is supported */

    if (compress) {

        bool encryption =

            qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false);

        const char *preallocation =

            qemu_opt_get(opts, BLOCK_OPT_PREALLOC);

        if (!drv->bdrv_write_compressed) {

            error_report("Compression not supported for this file format");

            ret = -1;

            goto out;

        }

        if (encryption) {

            error_report("Compression and encryption not supported at "

                         "the same time");

            ret = -1;

            goto out;

        }

        if (preallocation

            && strcmp(preallocation, "off"))

        {

            error_report("Compression and preallocation not supported at "

                         "the same time");

            ret = -1;

            goto out;

        }

    }

    if (!skip_create) {

        /* Create the new image */

        ret = bdrv_create(drv, out_filename, opts, &local_err);

        if (ret < 0) {

            error_report("%s: error while converting %s: %s",

                         out_filename, out_fmt, error_get_pretty(local_err));

            error_free(local_err);

            goto out;

        }

    }

    flags = min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;

    ret = bdrv_parse_cache_flags(cache, &flags);

    if (ret < 0) {

        error_report("Invalid cache option: %s", cache);

        goto out;

    }

    out_bs = bdrv_new_open("target", out_filename, out_fmt, flags, true, quiet);

    if (!out_bs) {

        ret = -1;

        goto out;

    }

    bs_i = 0;

    bs_offset = 0;

    /* increase bufsectors from the default 4096 (2M) if opt_transfer_length

     * or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)

     * as maximum. */

    bufsectors = MIN(32768,

                     MAX(bufsectors, MAX(out_bs->bl.opt_transfer_length,

                                         out_bs->bl.discard_alignment))

                    );

    buf = qemu_blockalign(out_bs, bufsectors * BDRV_SECTOR_SIZE);

    if (skip_create) {

        int64_t output_sectors = bdrv_nb_sectors(out_bs);

        if (output_sectors < 0) {

            error_report("unable to get output image length: %s\n",

                         strerror(-output_sectors));

            ret = -1;

            goto out;

        } else if (output_sectors < total_sectors) {

            error_report("output file is smaller than input file");

            ret = -1;

            goto out;

        }

    }

    cluster_sectors = 0;

    ret = bdrv_get_info(out_bs, &bdi);

    if (ret < 0) {

        if (compress) {

            error_report("could not get block driver info");

            goto out;

        }

    } else {

        compress = compress || bdi.needs_compressed_writes;

        cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;

    }

    if (compress) {

        if (cluster_sectors <= 0 || cluster_sectors > bufsectors) {

            error_report("invalid cluster size");

            ret = -1;

            goto out;

        }

        sector_num = 0;

        nb_sectors = total_sectors;

        for(;;) {

            int64_t bs_num;

            int remainder;

            uint8_t *buf2;

            nb_sectors = total_sectors - sector_num;

            if (nb_sectors <= 0)

                break;

            if (nb_sectors >= cluster_sectors)

                n = cluster_sectors;

            else

                n = nb_sectors;

            bs_num = sector_num - bs_offset;

            assert (bs_num >= 0);

            remainder = n;

            buf2 = buf;

            while (remainder > 0) {

                int nlow;

                while (bs_num == bs_sectors[bs_i]) {

                    bs_offset += bs_sectors[bs_i];

                    bs_i++;

                    assert (bs_i < bs_n);

                    bs_num = 0;

                    /* printf("changing part: sector_num=%" PRId64 ", "

                       "bs_i=%d, bs_offset=%" PRId64 ", bs_sectors=%" PRId64

                       "\n", sector_num, bs_i, bs_offset, bs_sectors[bs_i]); */

                }

                assert (bs_num < bs_sectors[bs_i]);

                nlow = remainder > bs_sectors[bs_i] - bs_num

                    ? bs_sectors[bs_i] - bs_num : remainder;

                ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);

                if (ret < 0) {

                    error_report("error while reading sector %" PRId64 ": %s",

                                 bs_num, strerror(-ret));

                    goto out;

                }

                buf2 += nlow * 512;

                bs_num += nlow;

                remainder -= nlow;

            }

            assert (remainder == 0);

            if (!buffer_is_zero(buf, n * BDRV_SECTOR_SIZE)) {

                ret = bdrv_write_compressed(out_bs, sector_num, buf, n);

                if (ret != 0) {

                    error_report("error while compressing sector %" PRId64

                                 ": %s", sector_num, strerror(-ret));

                    goto out;

                }

            }

            sector_num += n;

            qemu_progress_print(100.0 * sector_num / total_sectors, 0);

        }

        /* signal EOF to align */

        bdrv_write_compressed(out_bs, 0, NULL, 0);

    } else {

        int64_t sectors_to_read, sectors_read, sector_num_next_status;

        bool count_allocated_sectors;

        int has_zero_init = min_sparse ? bdrv_has_zero_init(out_bs) : 0;

        if (!has_zero_init && bdrv_can_write_zeroes_with_unmap(out_bs)) {

            ret = bdrv_make_zero(out_bs, BDRV_REQ_MAY_UNMAP);

            if (ret < 0) {

                goto out;

            }

            has_zero_init = 1;

        }

        sectors_to_read = total_sectors;

        count_allocated_sectors = progress && (out_baseimg || has_zero_init);

restart:

        sector_num = 0; // total number of sectors converted so far

        sectors_read = 0;

        sector_num_next_status = 0;

        for(;;) {

            nb_sectors = total_sectors - sector_num;

            if (nb_sectors <= 0) {

                if (count_allocated_sectors) {

                    sectors_to_read = sectors_read;

                    count_allocated_sectors = false;

                    goto restart;

                }

                ret = 0;

                break;

            }

            while (sector_num - bs_offset >= bs_sectors[bs_i]) {

                bs_offset += bs_sectors[bs_i];

                bs_i ++;

                assert (bs_i < bs_n);

                /* printf("changing part: sector_num=%" PRId64 ", bs_i=%d, "

                  "bs_offset=%" PRId64 ", bs_sectors=%" PRId64 "\n",

                   sector_num, bs_i, bs_offset, bs_sectors[bs_i]); */

            }

            if ((out_baseimg || has_zero_init) &&

                sector_num >= sector_num_next_status) {

                n = nb_sectors > INT_MAX ? INT_MAX : nb_sectors;

                ret = bdrv_get_block_status(bs[bs_i], sector_num - bs_offset,

                                            n, &n1);

                if (ret < 0) {

                    error_report("error while reading block status of sector %"

                                 PRId64 ": %s", sector_num - bs_offset,

                                 strerror(-ret));

                    goto out;

                }

                /* If the output image is zero initialized, we are not working

                 * on a shared base and the input is zero we can skip the next

                 * n1 sectors */

                if (has_zero_init && !out_baseimg && (ret & BDRV_BLOCK_ZERO)) {

                    sector_num += n1;

                    continue;

                }

                /* If the output image is being created as a copy on write

                 * image, assume that sectors which are unallocated in the

                 * input image are present in both the output's and input's

                 * base images (no need to copy them). */

                if (out_baseimg) {

                    if (!(ret & BDRV_BLOCK_DATA)) {

                        sector_num += n1;

                        continue;

                    }

                    /* The next 'n1' sectors are allocated in the input image.

                     * Copy only those as they may be followed by unallocated

                     * sectors. */

                    nb_sectors = n1;

                }

                /* avoid redundant callouts to get_block_status */

                sector_num_next_status = sector_num + n1;

            }

            n = MIN(nb_sectors, bufsectors);

            /* round down request length to an aligned sector, but

             * do not bother doing this on short requests. They happen

             * when we found an all-zero area, and the next sector to

             * write will not be sector_num + n. */

            if (cluster_sectors > 0 && n >= cluster_sectors) {

                int64_t next_aligned_sector = (sector_num + n);

                next_aligned_sector -= next_aligned_sector % cluster_sectors;

                if (sector_num + n > next_aligned_sector) {

                    n = next_aligned_sector - sector_num;

                }

            }

            n = MIN(n, bs_sectors[bs_i] - (sector_num - bs_offset));

            sectors_read += n;

            if (count_allocated_sectors) {

                sector_num += n;

                continue;

            }

            n1 = n;

            ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);

            if (ret < 0) {

                error_report("error while reading sector %" PRId64 ": %s",

                             sector_num - bs_offset, strerror(-ret));

                goto out;

            }

            /* NOTE: at the same time we convert, we do not write zero

               sectors to have a chance to compress the image. Ideally, we

               should add a specific call to have the info to go faster */

            buf1 = buf;

            while (n > 0) {

                if (!has_zero_init ||

                    is_allocated_sectors_min(buf1, n, &n1, min_sparse)) {

                    ret = bdrv_write(out_bs, sector_num, buf1, n1);

                    if (ret < 0) {

                        error_report("error while writing sector %" PRId64

                                     ": %s", sector_num, strerror(-ret));

                        goto out;

                    }

                }

                sector_num += n1;

                n -= n1;

                buf1 += n1 * 512;

            }

            qemu_progress_print(100.0 * sectors_read / sectors_to_read, 0);

        }

    }

out:

    if (!ret) {

        qemu_progress_print(100, 0);

    }

    qemu_progress_end();

    qemu_opts_del(opts);

    qemu_opts_free(create_opts);

    qemu_vfree(buf);

    if (sn_opts) {

        qemu_opts_del(sn_opts);

    }

    if (out_bs) {

        bdrv_unref(out_bs);

    }

    if (bs) {

        for (bs_i = 0; bs_i < bs_n; bs_i++) {

            if (bs[bs_i]) {

                bdrv_unref(bs[bs_i]);

            }

        }

        g_free(bs);

    }

    g_free(bs_sectors);

fail_getopt:

    g_free(options);

    if (ret) {

        return 1;

    }

    return 0;

}


static void musb_packet(MUSBState *s, MUSBEndPoint *ep,

                int epnum, int pid, int len, USBCallback cb, int dir)

{

    USBDevice *dev;

    int ret;

    int idx = epnum && dir;

    int ttype;

    /* ep->type[0,1] contains:

     * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow)

     * in bits 5:4 the transfer type (BULK / INT)

     * in bits 3:0 the EP num

     */

    ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0;

    ep->timeout[dir] = musb_timeout(ttype,

                    ep->type[idx] >> 6, ep->interval[idx]);

    ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;

    ep->delayed_cb[dir] = cb;

    /* A wild guess on the FADDR semantics... */

    usb_packet_setup(&ep->packey[dir].p, pid, ep->faddr[idx],

                     ep->type[idx] & 0xf);

    usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);

    ep->packey[dir].ep = ep;

    ep->packey[dir].dir = dir;

    dev = usb_find_device(&s->port, ep->packey[dir].p.devaddr);

    ret = usb_handle_packet(dev, &ep->packey[dir].p);

    if (ret == USB_RET_ASYNC) {

        ep->status[dir] = len;

        return;

    }

    ep->status[dir] = ret;

    musb_schedule_cb(&s->port, &ep->packey[dir].p);

}


static bool net_tx_pkt_parse_headers(struct NetTxPkt *pkt)

{

    struct iovec *l2_hdr, *l3_hdr;

    size_t bytes_read;

    size_t full_ip6hdr_len;

    uint16_t l3_proto;

    assert(pkt);

    l2_hdr = &pkt->vec[NET_TX_PKT_L2HDR_FRAG];

    l3_hdr = &pkt->vec[NET_TX_PKT_L3HDR_FRAG];

    bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, 0, l2_hdr->iov_base,

                            ETH_MAX_L2_HDR_LEN);

    if (bytes_read < sizeof(struct eth_header)) {

        l2_hdr->iov_len = 0;

        return false;

    }

    l2_hdr->iov_len = sizeof(struct eth_header);

    switch (be16_to_cpu(PKT_GET_ETH_HDR(l2_hdr->iov_base)->h_proto)) {

    case ETH_P_VLAN:

        l2_hdr->iov_len += sizeof(struct vlan_header);

        break;

    case ETH_P_DVLAN:

        l2_hdr->iov_len += 2 * sizeof(struct vlan_header);

        break;

    }

    if (bytes_read < l2_hdr->iov_len) {

        l2_hdr->iov_len = 0;

        return false;

    }

    l3_proto = eth_get_l3_proto(l2_hdr->iov_base, l2_hdr->iov_len);

    switch (l3_proto) {

    case ETH_P_IP:

        l3_hdr->iov_base = g_malloc(ETH_MAX_IP4_HDR_LEN);

        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,

                                l3_hdr->iov_base, sizeof(struct ip_header));

        if (bytes_read < sizeof(struct ip_header)) {

            l3_hdr->iov_len = 0;

            return false;

        }

        l3_hdr->iov_len = IP_HDR_GET_LEN(l3_hdr->iov_base);

        pkt->l4proto = ((struct ip_header *) l3_hdr->iov_base)->ip_p;

        /* copy optional IPv4 header data */

        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags,

                                l2_hdr->iov_len + sizeof(struct ip_header),

                                l3_hdr->iov_base + sizeof(struct ip_header),

                                l3_hdr->iov_len - sizeof(struct ip_header));

        if (bytes_read < l3_hdr->iov_len - sizeof(struct ip_header)) {

            l3_hdr->iov_len = 0;

            return false;

        }

        break;

    case ETH_P_IPV6:

        if (!eth_parse_ipv6_hdr(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,

                               &pkt->l4proto, &full_ip6hdr_len)) {

            l3_hdr->iov_len = 0;

            return false;

        }

        l3_hdr->iov_base = g_malloc(full_ip6hdr_len);

        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,

                                l3_hdr->iov_base, full_ip6hdr_len);

        if (bytes_read < full_ip6hdr_len) {

            l3_hdr->iov_len = 0;

            return false;

        } else {

            l3_hdr->iov_len = full_ip6hdr_len;

        }

        break;

    default:

        l3_hdr->iov_len = 0;

        break;

    }

    net_tx_pkt_calculate_hdr_len(pkt);

    pkt->packet_type = get_eth_packet_type(l2_hdr->iov_base);

    return true;

}


static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr)

{

    PCIBonitoState *s = opaque;

    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);

    uint32_t cfgaddr;

    uint32_t idsel;

    uint32_t devno;

    uint32_t funno;

    uint32_t regno;

    uint32_t pciaddr;

    /* support type0 pci config */

    if ((s->regs[BONITO_PCIMAP_CFG] & 0x10000) != 0x0) {

        return 0xffffffff;

    }

    cfgaddr = addr & 0xffff;

    cfgaddr |= (s->regs[BONITO_PCIMAP_CFG] & 0xffff) << 16;

    idsel = (cfgaddr & BONITO_PCICONF_IDSEL_MASK) >> BONITO_PCICONF_IDSEL_OFFSET;

    devno = ffs(idsel) - 1;

    funno = (cfgaddr & BONITO_PCICONF_FUN_MASK) >> BONITO_PCICONF_FUN_OFFSET;

    regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET;

    if (idsel == 0) {

        fprintf(stderr, "error in bonito pci config address " TARGET_FMT_plx

            ",pcimap_cfg=%x\n", addr, s->regs[BONITO_PCIMAP_CFG]);

        exit(1);

    }

    pciaddr = PCI_ADDR(pci_bus_num(phb->bus), devno, funno, regno);

    DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n",

        cfgaddr, pciaddr, pci_bus_num(phb->bus), devno, funno, regno);

    return pciaddr;

}


static void ide_init1(IDEBus *bus, int unit)

{

    static int drive_serial = 1;

    IDEState *s = &bus->ifs[unit];

    s->bus = bus;

    s->unit = unit;

    s->drive_serial = drive_serial++;

    /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */

    s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;

    s->io_buffer = qemu_memalign(2048, s->io_buffer_total_len);

    memset(s->io_buffer, 0, s->io_buffer_total_len);

    s->smart_selftest_data = qemu_blockalign(s->bs, 512);

    memset(s->smart_selftest_data, 0, 512);

    s->sector_write_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,

                                           ide_sector_write_timer_cb, s);

}


int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,

                        bool exact_size)

{

    BDRVQcowState *s = bs->opaque;

    int new_l1_size2, ret, i;

    uint64_t *new_l1_table;

    int64_t new_l1_table_offset, new_l1_size;

    uint8_t data[12];

    if (min_size <= s->l1_size)

        return 0;

    if (exact_size) {

        new_l1_size = min_size;

    } else {

        /* Bump size up to reduce the number of times we have to grow */

        new_l1_size = s->l1_size;

        if (new_l1_size == 0) {

            new_l1_size = 1;

        }

        while (min_size > new_l1_size) {

            new_l1_size = (new_l1_size * 3 + 1) / 2;

        }

    }

    if (new_l1_size > INT_MAX) {

        return -EFBIG;

    }

#ifdef DEBUG_ALLOC2

    fprintf(stderr, "grow l1_table from %d to %" PRId64 "\n",

            s->l1_size, new_l1_size);

#endif

    new_l1_size2 = sizeof(uint64_t) * new_l1_size;

    new_l1_table = g_malloc0(align_offset(new_l1_size2, 512));

    memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));

    /* write new table (align to cluster) */

    BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE);

    new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);

    if (new_l1_table_offset < 0) {

        g_free(new_l1_table);

        return new_l1_table_offset;

    }

    ret = qcow2_cache_flush(bs, s->refcount_block_cache);

    if (ret < 0) {

        goto fail;

    }

    /* the L1 position has not yet been updated, so these clusters must

     * indeed be completely free */

    ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,

                                        new_l1_table_offset, new_l1_size2);

    if (ret < 0) {

        goto fail;

    }

    BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);

    for(i = 0; i < s->l1_size; i++)

        new_l1_table[i] = cpu_to_be64(new_l1_table[i]);

    ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset, new_l1_table, new_l1_size2);

    if (ret < 0)

        goto fail;

    for(i = 0; i < s->l1_size; i++)

        new_l1_table[i] = be64_to_cpu(new_l1_table[i]);

    /* set new table */

    BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);

    cpu_to_be32w((uint32_t*)data, new_l1_size);

    cpu_to_be64wu((uint64_t*)(data + 4), new_l1_table_offset);

    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data));

    if (ret < 0) {

        goto fail;

    }

    g_free(s->l1_table);

    qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t),

                        QCOW2_DISCARD_OTHER);

    s->l1_table_offset = new_l1_table_offset;

    s->l1_table = new_l1_table;

    s->l1_size = new_l1_size;

    return 0;

 fail:

    g_free(new_l1_table);

    qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2,

                        QCOW2_DISCARD_OTHER);

    return ret;

}


static uint64_t bw_io_read(void *opaque, target_phys_addr_t addr, unsigned size)

{

    switch (size) {

    case 1:

        return cpu_inb(addr);

    case 2:

        return cpu_inw(addr);

    case 4:

        return cpu_inl(addr);

    }

    abort();

}


static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)

{

    int i;

    static int inited;

    if (!inited) {

        inited = 1;

        for(i = 0;i < 256; i++)

            rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */

        rop_to_index[CIRRUS_ROP_0] = 0;

        rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1;

        rop_to_index[CIRRUS_ROP_NOP] = 2;

        rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3;

        rop_to_index[CIRRUS_ROP_NOTDST] = 4;

        rop_to_index[CIRRUS_ROP_SRC] = 5;

        rop_to_index[CIRRUS_ROP_1] = 6;

        rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7;

        rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8;

        rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9;

        rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10;

        rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11;

        rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12;

        rop_to_index[CIRRUS_ROP_NOTSRC] = 13;

        rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14;

        rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15;

        s->device_id = device_id;

        if (is_pci)

            s->bustype = CIRRUS_BUSTYPE_PCI;

        else

            s->bustype = CIRRUS_BUSTYPE_ISA;

    }

    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);

    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);

    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);

    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);

    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);

    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);

    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);

    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);

    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);

    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);

    s->vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read,

                                           cirrus_vga_mem_write, s);

    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,

                                 s->vga_io_memory);

    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);

    /* I/O handler for LFB */

    s->cirrus_linear_io_addr =

        cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write, s);

    s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr);

    /* I/O handler for LFB */

    s->cirrus_linear_bitblt_io_addr =

        cpu_register_io_memory(0, cirrus_linear_bitblt_read,

                               cirrus_linear_bitblt_write, s);

    /* I/O handler for memory-mapped I/O */

    s->cirrus_mmio_io_addr =

        cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s);

    s->real_vram_size =

        (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;

    /* XXX: s->vram_size must be a power of two */

    s->cirrus_addr_mask = s->real_vram_size - 1;

    s->linear_mmio_mask = s->real_vram_size - 256;

    s->get_bpp = cirrus_get_bpp;

    s->get_offsets = cirrus_get_offsets;

    s->get_resolution = cirrus_get_resolution;

    s->cursor_invalidate = cirrus_cursor_invalidate;

    s->cursor_draw_line = cirrus_cursor_draw_line;

    qemu_register_reset(cirrus_reset, s);

    cirrus_reset(s);

    register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s);

}


static void translate_priority(GICState *s, int irq, int cpu,

                               uint32_t *field, bool to_kernel)

{

    if (to_kernel) {

        *field = GIC_GET_PRIORITY(irq, cpu) & 0xff;

    } else {

        gic_set_priority(s, cpu, irq, *field & 0xff);

    }

}


static void FUNC(transquant_bypass32x32)(uint8_t *_dst, int16_t *coeffs,

                                         ptrdiff_t stride)

{

    int x, y;

    pixel *dst = (pixel *)_dst;

    stride /= sizeof(pixel);

    for (y = 0; y < 32; y++) {

        for (x = 0; x < 32; x++) {

            dst[x] += *coeffs;

            coeffs++;

        }

        dst += stride;

    }

}


static void ppc_heathrow_init (ram_addr_t ram_size,

                               const char *boot_device,

                               const char *kernel_filename,

                               const char *kernel_cmdline,

                               const char *initrd_filename,

                               const char *cpu_model)

{

    CPUState *env = NULL;

    char *filename;

    qemu_irq *pic, **heathrow_irqs;

    int linux_boot, i;

    ram_addr_t ram_offset, bios_offset;

    uint32_t kernel_base, initrd_base, cmdline_base = 0;

    int32_t kernel_size, initrd_size;

    PCIBus *pci_bus;

    MacIONVRAMState *nvr;

    int bios_size;

    MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem;

    MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1), *ide_mem[2];

    uint16_t ppc_boot_device;

    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];

    void *fw_cfg;

    void *dbdma;

    linux_boot = (kernel_filename != NULL);

    /* init CPUs */

    if (cpu_model == NULL)

        cpu_model = "G3";

    for (i = 0; i < smp_cpus; i++) {

        env = cpu_init(cpu_model);

        if (!env) {

            fprintf(stderr, "Unable to find PowerPC CPU definition\n");

            exit(1);

        }

        /* Set time-base frequency to 16.6 Mhz */

        cpu_ppc_tb_init(env,  16600000UL);

        qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);

    }

    /* allocate RAM */

    if (ram_size > (2047 << 20)) {

        fprintf(stderr,

                "qemu: Too much memory for this machine: %d MB, maximum 2047 MB\n",

                ((unsigned int)ram_size / (1 << 20)));

        exit(1);

    }

    ram_offset = qemu_ram_alloc(NULL, "ppc_heathrow.ram", ram_size);

    cpu_register_physical_memory(0, ram_size, ram_offset);

    /* allocate and load BIOS */

    bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.bios", BIOS_SIZE);

    if (bios_name == NULL)

        bios_name = PROM_FILENAME;

    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);

    cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE, bios_offset | IO_MEM_ROM);

    /* Load OpenBIOS (ELF) */

    if (filename) {

        bios_size = load_elf(filename, 0, NULL, NULL, NULL, NULL,

                             1, ELF_MACHINE, 0);

        g_free(filename);

    } else {

        bios_size = -1;

    }

    if (bios_size < 0 || bios_size > BIOS_SIZE) {

        hw_error("qemu: could not load PowerPC bios '%s'\n", bios_name);

        exit(1);

    }

    if (linux_boot) {

        uint64_t lowaddr = 0;

        int bswap_needed;

#ifdef BSWAP_NEEDED

        bswap_needed = 1;

#else

        bswap_needed = 0;

#endif

        kernel_base = KERNEL_LOAD_ADDR;

        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,

                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);

        if (kernel_size < 0)

            kernel_size = load_aout(kernel_filename, kernel_base,

                                    ram_size - kernel_base, bswap_needed,

                                    TARGET_PAGE_SIZE);

        if (kernel_size < 0)

            kernel_size = load_image_targphys(kernel_filename,

                                              kernel_base,

                                              ram_size - kernel_base);

        if (kernel_size < 0) {

            hw_error("qemu: could not load kernel '%s'\n",

                      kernel_filename);

            exit(1);

        }

        /* load initrd */

        if (initrd_filename) {

            initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);

            initrd_size = load_image_targphys(initrd_filename, initrd_base,

                                              ram_size - initrd_base);

            if (initrd_size < 0) {

                hw_error("qemu: could not load initial ram disk '%s'\n",

                         initrd_filename);

                exit(1);

            }

            cmdline_base = round_page(initrd_base + initrd_size);

        } else {

            initrd_base = 0;

            initrd_size = 0;

            cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);

        }

        ppc_boot_device = 'm';

    } else {

        kernel_base = 0;

        kernel_size = 0;

        initrd_base = 0;

        initrd_size = 0;

        ppc_boot_device = '\0';

        for (i = 0; boot_device[i] != '\0'; i++) {

            /* TOFIX: for now, the second IDE channel is not properly

             *        used by OHW. The Mac floppy disk are not emulated.

             *        For now, OHW cannot boot from the network.

             */

#if 0

            if (boot_device[i] >= 'a' && boot_device[i] <= 'f') {

                ppc_boot_device = boot_device[i];

                break;

            }

#else

            if (boot_device[i] >= 'c' && boot_device[i] <= 'd') {

                ppc_boot_device = boot_device[i];

                break;

            }

#endif

        }

        if (ppc_boot_device == '\0') {

            fprintf(stderr, "No valid boot device for G3 Beige machine\n");

            exit(1);

        }

    }

    /* Register 2 MB of ISA IO space */

    isa_mmio_init(0xfe000000, 0x00200000);

    /* XXX: we register only 1 output pin for heathrow PIC */

    heathrow_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));

    heathrow_irqs[0] =

        g_malloc0(smp_cpus * sizeof(qemu_irq) * 1);

    /* Connect the heathrow PIC outputs to the 6xx bus */

    for (i = 0; i < smp_cpus; i++) {

        switch (PPC_INPUT(env)) {

        case PPC_FLAGS_INPUT_6xx:

            heathrow_irqs[i] = heathrow_irqs[0] + (i * 1);

            heathrow_irqs[i][0] =

                ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];

            break;

        default:

            hw_error("Bus model not supported on OldWorld Mac machine\n");

        }

    }

    /* init basic PC hardware */

    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {

        hw_error("Only 6xx bus is supported on heathrow machine\n");

    }

    pic = heathrow_pic_init(&pic_mem, 1, heathrow_irqs);

    pci_bus = pci_grackle_init(0xfec00000, pic,

                               get_system_memory(),

                               get_system_io());

    pci_vga_init(pci_bus);

    escc_mem = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],

                               serial_hds[1], ESCC_CLOCK, 4);

    memory_region_init_alias(escc_bar, "escc-bar",

                             escc_mem, 0, memory_region_size(escc_mem));

    for(i = 0; i < nb_nics; i++)

        pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);

    ide_drive_get(hd, MAX_IDE_BUS);

    /* First IDE channel is a MAC IDE on the MacIO bus */

    dbdma = DBDMA_init(&dbdma_mem);

    ide_mem[0] = NULL;

    ide_mem[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]);

    /* Second IDE channel is a CMD646 on the PCI bus */

    hd[0] = hd[MAX_IDE_DEVS];

    hd[1] = hd[MAX_IDE_DEVS + 1];

    hd[3] = hd[2] = NULL;

    pci_cmd646_ide_init(pci_bus, hd, 0);

    /* cuda also initialize ADB */

    cuda_init(&cuda_mem, pic[0x12]);

    adb_kbd_init(&adb_bus);

    adb_mouse_init(&adb_bus);

    nvr = macio_nvram_init(0x2000, 4);

    pmac_format_nvram_partition(nvr, 0x2000);

    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem,

               dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_bar);

    if (usb_enabled) {

        usb_ohci_init_pci(pci_bus, -1);

    }

    if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)

        graphic_depth = 15;

    /* No PCI init: the BIOS will do it */

    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);

    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);

    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);

    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_HEATHROW);

    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);

    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);

    if (kernel_cmdline) {

        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);

        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);

    } else {

        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);

    }

    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_base);

    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);

    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ppc_boot_device);

    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_WIDTH, graphic_width);

    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);

    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);

    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());

    if (kvm_enabled()) {

#ifdef CONFIG_KVM

        uint8_t *hypercall;

        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());

        hypercall = g_malloc(16);

        kvmppc_get_hypercall(env, hypercall, 16);

        fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);

        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());

#endif

    } else {

        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());

    }

    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);

}


static void *qesd_thread_out (void *arg)

{

    ESDVoiceOut *esd = arg;

    HWVoiceOut *hw = &esd->hw;

    int threshold;

    threshold = conf.divisor ? hw->samples / conf.divisor : 0;

    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {

        return NULL;

    }

    for (;;) {

        int decr, to_mix, rpos;

        for (;;) {

            if (esd->done) {

                goto exit;

            }

            if (esd->live > threshold) {

                break;

            }

            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {

                goto exit;

            }

        }

        decr = to_mix = esd->live;

        rpos = hw->rpos;

        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {

            return NULL;

        }

        while (to_mix) {

            ssize_t written;

            int chunk = audio_MIN (to_mix, hw->samples - rpos);

            st_sample_t *src = hw->mix_buf + rpos;

            hw->clip (esd->pcm_buf, src, chunk);

        again:

            written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);

            if (written == -1) {

                if (errno == EINTR || errno == EAGAIN) {

                    goto again;

                }

                qesd_logerr (errno, "write failed\n");

                return NULL;

            }

            if (written != chunk << hw->info.shift) {

                int wsamples = written >> hw->info.shift;

                int wbytes = wsamples << hw->info.shift;

                if (wbytes != written) {

                    dolog ("warning: Misaligned write %d (requested %d), "

                           "alignment %d\n",

                           wbytes, written, hw->info.align + 1);

                }

                to_mix -= wsamples;

                rpos = (rpos + wsamples) % hw->samples;

                break;

            }

            rpos = (rpos + chunk) % hw->samples;

            to_mix -= chunk;

        }

        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {

            return NULL;

        }

        esd->rpos = rpos;

        esd->live -= decr;

        esd->decr += decr;

    }

 exit:

    audio_pt_unlock (&esd->pt, AUDIO_FUNC);

    return NULL;

}


static void v9fs_mkdir(void *opaque)

{

    V9fsPDU *pdu = opaque;

    size_t offset = 7;

    int32_t fid;

    struct stat stbuf;

    V9fsQID qid;

    V9fsString name;

    V9fsFidState *fidp;

    gid_t gid;

    int mode;

    int err = 0;

    pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);

    trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);

    fidp = get_fid(pdu, fid);

    if (fidp == NULL) {

        err = -ENOENT;

        goto out_nofid;

    }

    err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);

    if (err < 0) {

        goto out;

    }

    stat_to_qid(&stbuf, &qid);

    offset += pdu_marshal(pdu, offset, "Q", &qid);

    err = offset;

    trace_v9fs_mkdir_return(pdu->tag, pdu->id,

                            qid.type, qid.version, qid.path, err);

out:

    put_fid(pdu, fidp);

out_nofid:

    complete_pdu(pdu->s, pdu, err);

    v9fs_string_free(&name);

}


static void peer_test_vnet_hdr(VirtIONet *n)

{

    NetClientState *nc = qemu_get_queue(n->nic);

    if (!nc->peer) {

        return;

    }

    n->has_vnet_hdr = qemu_peer_has_vnet_hdr(nc);

}


static void tpm_tis_receive_bh(void *opaque)

{

    TPMState *s = opaque;

    TPMTISEmuState *tis = &s->s.tis;

    uint8_t locty = s->locty_number;

    tis->loc[locty].sts = TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE;

    tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;

    tis->loc[locty].r_offset = 0;

    tis->loc[locty].w_offset = 0;

    if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {

        tpm_tis_abort(s, locty);

    }

#ifndef RAISE_STS_IRQ

    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE);

#else

    tpm_tis_raise_irq(s, locty,

                      TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);

#endif

}


static int omap_validate_imif_addr(struct omap_mpu_state_s *s,

                target_phys_addr_t addr)

{

    return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr);

}


static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,

                               uint32_t token, uint32_t nargs,

                               target_ulong args, uint32_t nret,

                               target_ulong rets)

{

    uint32_t sensor_type;

    uint32_t sensor_index;

    uint32_t sensor_state;

    uint32_t ret = RTAS_OUT_SUCCESS;

    sPAPRDRConnector *drc;

    sPAPRDRConnectorClass *drck;

    if (nargs != 3 || nret != 1) {

        ret = RTAS_OUT_PARAM_ERROR;

        goto out;

    }

    sensor_type = rtas_ld(args, 0);

    sensor_index = rtas_ld(args, 1);

    sensor_state = rtas_ld(args, 2);

    if (!sensor_type_is_dr(sensor_type)) {

        goto out_unimplemented;

    }

    /* if this is a DR sensor we can assume sensor_index == drc_index */

    drc = spapr_drc_by_index(sensor_index);

    if (!drc) {

        trace_spapr_rtas_set_indicator_invalid(sensor_index);

        ret = RTAS_OUT_PARAM_ERROR;

        goto out;

    }

    drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);

    switch (sensor_type) {

    case RTAS_SENSOR_TYPE_ISOLATION_STATE:

        ret = drck->set_isolation_state(drc, sensor_state);

        break;

    case RTAS_SENSOR_TYPE_DR:

        ret = drck->set_indicator_state(drc, sensor_state);

        break;

    case RTAS_SENSOR_TYPE_ALLOCATION_STATE:

        ret = drck->set_allocation_state(drc, sensor_state);

        break;

    default:

        goto out_unimplemented;

    }

out:

    rtas_st(rets, 0, ret);

    return;

out_unimplemented:

    /* currently only DR-related sensors are implemented */

    trace_spapr_rtas_set_indicator_not_supported(sensor_index, sensor_type);

    rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);

}


static int g2m_decode_frame(AVCodecContext *avctx, void *data,

                            int *got_picture_ptr, AVPacket *avpkt)

{

    const uint8_t *buf = avpkt->data;

    int buf_size = avpkt->size;

    G2MContext *c = avctx->priv_data;

    AVFrame *pic = data;

    GetByteContext bc, tbc;

    int magic;

    int got_header = 0;

    uint32_t chunk_size, cur_size;

    int chunk_type;

    int i;

    int ret;

    if (buf_size < 12) {

        av_log(avctx, AV_LOG_ERROR,

               "Frame should have at least 12 bytes, got %d instead\n",

               buf_size);

        return AVERROR_INVALIDDATA;

    }

    bytestream2_init(&bc, buf, buf_size);

    magic = bytestream2_get_be32(&bc);

    if ((magic & ~0xF) != MKBETAG('G', '2', 'M', '0') ||

        (magic & 0xF) < 2 || (magic & 0xF) > 4) {

        av_log(avctx, AV_LOG_ERROR, "Wrong magic %08X\n", magic);

        return AVERROR_INVALIDDATA;

    }

    if ((magic & 0xF) != 4) {

        av_log(avctx, AV_LOG_ERROR, "G2M2 and G2M3 are not yet supported\n");

        return AVERROR(ENOSYS);

    }

    while (bytestream2_get_bytes_left(&bc) > 5) {

        chunk_size = bytestream2_get_le32(&bc) - 1;

        chunk_type = bytestream2_get_byte(&bc);

        if (chunk_size > bytestream2_get_bytes_left(&bc)) {

            av_log(avctx, AV_LOG_ERROR, "Invalid chunk size %d type %02X\n",

                   chunk_size, chunk_type);

            break;

        }

        switch (chunk_type) {

        case FRAME_INFO:

            c->got_header = 0;

            if (chunk_size < 21) {

                av_log(avctx, AV_LOG_ERROR, "Invalid frame info size %d\n",

                       chunk_size);

                break;

            }

            c->width  = bytestream2_get_be32(&bc);

            c->height = bytestream2_get_be32(&bc);

            if (c->width  < 16 || c->width  > avctx->width ||

                c->height < 16 || c->height > avctx->height) {

                av_log(avctx, AV_LOG_ERROR,

                       "Invalid frame dimensions %dx%d\n",

                       c->width, c->height);

                c->width = c->height = 0;

                bytestream2_skip(&bc, bytestream2_get_bytes_left(&bc));

            }

            if (c->width != avctx->width || c->height != avctx->height)

                avcodec_set_dimensions(avctx, c->width, c->height);

            c->compression = bytestream2_get_be32(&bc);

            if (c->compression != 2 && c->compression != 3) {

                av_log(avctx, AV_LOG_ERROR,

                       "Unknown compression method %d\n",

                       c->compression);

                return AVERROR_PATCHWELCOME;

            }

            c->tile_width  = bytestream2_get_be32(&bc);

            c->tile_height = bytestream2_get_be32(&bc);

            if (!c->tile_width || !c->tile_height) {

                av_log(avctx, AV_LOG_ERROR,

                       "Invalid tile dimensions %dx%d\n",

                       c->tile_width, c->tile_height);

                return AVERROR_INVALIDDATA;

            }

            c->tiles_x = (c->width  + c->tile_width  - 1) / c->tile_width;

            c->tiles_y = (c->height + c->tile_height - 1) / c->tile_height;

            c->bpp = bytestream2_get_byte(&bc);

            chunk_size -= 21;

            bytestream2_skip(&bc, chunk_size);

            if (g2m_init_buffers(c))

                return AVERROR(ENOMEM);

            got_header = 1;

            break;

        case TILE_DATA:

            if (!c->tiles_x || !c->tiles_y) {

                av_log(avctx, AV_LOG_WARNING,

                       "No frame header - skipping tile\n");

                bytestream2_skip(&bc, bytestream2_get_bytes_left(&bc));

                break;

            }

            if (chunk_size < 2) {

                av_log(avctx, AV_LOG_ERROR, "Invalid tile data size %d\n",

                       chunk_size);

                break;

            }

            c->tile_x = bytestream2_get_byte(&bc);

            c->tile_y = bytestream2_get_byte(&bc);

            if (c->tile_x >= c->tiles_x || c->tile_y >= c->tiles_y) {

                av_log(avctx, AV_LOG_ERROR,

                       "Invalid tile pos %d,%d (in %dx%d grid)\n",

                       c->tile_x, c->tile_y, c->tiles_x, c->tiles_y);

                break;

            }

            chunk_size -= 2;

            ret = 0;

            switch (c->compression) {

            case COMPR_EPIC_J_B:

                av_log(avctx, AV_LOG_ERROR,

                       "ePIC j-b compression is not implemented yet\n");

                return AVERROR(ENOSYS);

            case COMPR_KEMPF_J_B:

                ret = kempf_decode_tile(c, c->tile_x, c->tile_y,

                                        buf + bytestream2_tell(&bc),

                                        chunk_size);

                break;

            }

            if (ret && c->framebuf)

                av_log(avctx, AV_LOG_ERROR, "Error decoding tile %d,%d\n",

                       c->tile_x, c->tile_y);

            bytestream2_skip(&bc, chunk_size);

            break;

        case CURSOR_POS:

            if (chunk_size < 5) {

                av_log(avctx, AV_LOG_ERROR, "Invalid cursor pos size %d\n",

                       chunk_size);

                break;

            }

            c->cursor_x = bytestream2_get_be16(&bc);

            c->cursor_y = bytestream2_get_be16(&bc);

            bytestream2_skip(&bc, chunk_size - 4);

            break;

        case CURSOR_SHAPE:

            if (chunk_size < 8) {

                av_log(avctx, AV_LOG_ERROR, "Invalid cursor data size %d\n",

                       chunk_size);

                break;

            }

            bytestream2_init(&tbc, buf + bytestream2_tell(&bc),

                             chunk_size - 4);

            cur_size        = bytestream2_get_be32(&tbc);

            c->cursor_w     = bytestream2_get_byte(&tbc);

            c->cursor_h     = bytestream2_get_byte(&tbc);

            c->cursor_hot_x = bytestream2_get_byte(&tbc);

            c->cursor_hot_y = bytestream2_get_byte(&tbc);

            c->cursor_fmt   = bytestream2_get_byte(&tbc);

            if (cur_size >= chunk_size ||

                c->cursor_w * c->cursor_h / 4 > cur_size) {

                av_log(avctx, AV_LOG_ERROR, "Invalid cursor data size %d\n",

                       chunk_size);

                break;

            }

            g2m_load_cursor(c, &tbc);

            bytestream2_skip(&bc, chunk_size);

            break;

        case CHUNK_CC:

        case CHUNK_CD:

            bytestream2_skip(&bc, chunk_size);

            break;

        default:

            av_log(avctx, AV_LOG_WARNING, "Skipping chunk type %02X\n",

                   chunk_type);

            bytestream2_skip(&bc, chunk_size);

        }

    }

    if (got_header)

        c->got_header = 1;

    if (c->width && c->height && c->framebuf) {

        if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) {

            av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");

            return ret;

        }

        pic->key_frame = got_header;

        pic->pict_type = got_header ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;

        for (i = 0; i < avctx->height; i++)

            memcpy(pic->data[0] + i * pic->linesize[0],

                   c->framebuf  + i * c->framebuf_stride,

                   c->width * 3);

        g2m_paint_cursor(c, pic->data[0], pic->linesize[0]);

        *got_picture_ptr = 1;

    }

    return buf_size;

}


static inline void chroma_4mv_motion_lowres(MpegEncContext *s,

                                            uint8_t *dest_cb, uint8_t *dest_cr,

                                            uint8_t **ref_picture,

                                            h264_chroma_mc_func * pix_op,

                                            int mx, int my)

{

    const int lowres     = s->avctx->lowres;

    const int op_index   = FFMIN(lowres, 2);

    const int block_s    = 8 >> lowres;

    const int s_mask     = (2 << lowres) - 1;

    const int h_edge_pos = s->h_edge_pos >> lowres + 1;

    const int v_edge_pos = s->v_edge_pos >> lowres + 1;

    int emu = 0, src_x, src_y, offset, sx, sy;

    uint8_t *ptr;

    if (s->quarter_sample) {

        mx /= 2;

        my /= 2;

    }

    /* In case of 8X8, we construct a single chroma motion vector

       with a special rounding */

    mx = ff_h263_round_chroma(mx);

    my = ff_h263_round_chroma(my);

    sx = mx & s_mask;

    sy = my & s_mask;

    src_x = s->mb_x * block_s + (mx >> lowres + 1);

    src_y = s->mb_y * block_s + (my >> lowres + 1);

    offset = src_y * s->uvlinesize + src_x;

    ptr = ref_picture[1] + offset;

    if (s->flags & CODEC_FLAG_EMU_EDGE) {

        if ((unsigned) src_x > FFMAX(h_edge_pos - (!!sx) - block_s, 0) ||

            (unsigned) src_y > FFMAX(v_edge_pos - (!!sy) - block_s, 0)) {

            s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize,

                                    9, 9, src_x, src_y, h_edge_pos, v_edge_pos);

            ptr = s->edge_emu_buffer;

            emu = 1;

        }

    }

    sx = (sx << 2) >> lowres;

    sy = (sy << 2) >> lowres;

    pix_op[op_index](dest_cb, ptr, s->uvlinesize, block_s, sx, sy);

    ptr = ref_picture[2] + offset;

    if (emu) {

        s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize, 9, 9,

                                src_x, src_y, h_edge_pos, v_edge_pos);

        ptr = s->edge_emu_buffer;

    }

    pix_op[op_index](dest_cr, ptr, s->uvlinesize, block_s, sx, sy);

}


static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)

{

    int num;

    if (!s->config || !s->enable) {

        return 0;

    }

    /* Check range and alignment.  */

    if ((CMD(min) | CMD(max) | CMD(next_cmd) | CMD(stop)) & 3) {

        return 0;

    }

    if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) {

        return 0;

    }

    if (CMD(max) > SVGA_FIFO_SIZE ||

        CMD(min) >= SVGA_FIFO_SIZE ||

        CMD(stop) >= SVGA_FIFO_SIZE ||

        CMD(next_cmd) >= SVGA_FIFO_SIZE) {

        return 0;

    }

    if (CMD(max) < CMD(min) + 10 * 1024) {

        return 0;

    }

    num = CMD(next_cmd) - CMD(stop);

    if (num < 0) {

        num += CMD(max) - CMD(min);

    }

    return num >> 2;

}