aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--Makefile4
-rw-r--r--block.c11
-rw-r--r--block/blkdebug.c20
-rw-r--r--block/block-backend.c65
-rw-r--r--block/commit.c2
-rw-r--r--block/crypto.c8
-rw-r--r--block/file-posix.c79
-rw-r--r--block/file-win32.c5
-rw-r--r--block/gluster.c83
-rw-r--r--block/io.c98
-rw-r--r--block/iscsi.c164
-rw-r--r--block/mirror.c2
-rw-r--r--block/nfs.c5
-rw-r--r--block/null.c23
-rw-r--r--block/nvme.c14
-rw-r--r--block/parallels.c28
-rw-r--r--block/qcow.c32
-rw-r--r--block/qcow2-bitmap.c4
-rw-r--r--block/qcow2-cluster.c4
-rw-r--r--block/qcow2-refcount.c4
-rw-r--r--block/qcow2-snapshot.c10
-rw-r--r--block/qcow2.c60
-rw-r--r--block/qcow2.h6
-rw-r--r--block/qed.c82
-rw-r--r--block/raw-format.c21
-rw-r--r--block/rbd.c6
-rw-r--r--block/sheepdog.c36
-rw-r--r--block/ssh.c66
-rw-r--r--block/throttle.c2
-rw-r--r--block/vdi.c50
-rw-r--r--block/vhdx.c5
-rw-r--r--block/vmdk.c43
-rw-r--r--block/vpc.c50
-rw-r--r--block/vvfat.c16
-rw-r--r--chardev/char-socket.c10
-rwxr-xr-xconfigure47
-rw-r--r--cpus.c33
-rw-r--r--default-configs/ppc-softmmu.mak2
-rw-r--r--default-configs/ppcemb-softmmu.mak1
-rw-r--r--docs/interop/qcow2.txt16
-rw-r--r--docs/qcow2-cache.txt46
-rw-r--r--exec.c90
-rw-r--r--fsdev/virtfs-proxy-helper.c15
-rw-r--r--hw/display/g364fb.c1
-rw-r--r--hw/i386/multiboot.c77
-rw-r--r--hw/i386/pc.c17
-rw-r--r--hw/i386/pc_piix.c4
-rw-r--r--hw/i386/pc_q35.c3
-rw-r--r--hw/ide/core.c10
-rw-r--r--hw/input/adb-kbd.c4
-rw-r--r--hw/input/adb-mouse.c5
-rw-r--r--hw/input/trace-events5
-rw-r--r--hw/intc/heathrow_pic.c166
-rw-r--r--hw/intc/openpic.c157
-rw-r--r--hw/intc/openpic_kvm.c5
-rw-r--r--hw/intc/trace-events5
-rw-r--r--hw/misc/macio/macio.c150
-rw-r--r--hw/misc/trace-events4
-rw-r--r--hw/ppc/Makefile.objs3
-rw-r--r--hw/ppc/e500.c124
-rw-r--r--hw/ppc/mac.h10
-rw-r--r--hw/ppc/mac_newworld.c56
-rw-r--r--hw/ppc/mac_oldworld.c50
-rw-r--r--hw/ppc/ppc440_pcix.c528
-rw-r--r--hw/ppc/ppc440_uc.c3
-rw-r--r--hw/ppc/sam460ex.c603
-rw-r--r--hw/ppc/spapr.c176
-rw-r--r--hw/ppc/spapr_caps.c153
-rw-r--r--hw/ppc/spapr_hcall.c5
-rw-r--r--hw/ppc/trace-events8
-rw-r--r--hw/s390x/s390-ccw.c2
-rw-r--r--hw/scsi/lsi53c895a.c2
-rw-r--r--hw/scsi/scsi-bus.c49
-rw-r--r--hw/scsi/spapr_vscsi.c3
-rw-r--r--hw/vfio/pci.c2
-rw-r--r--hw/vfio/platform.c2
-rw-r--r--include/block/aio-wait.h116
-rw-r--r--include/block/aio.h7
-rw-r--r--include/block/block.h54
-rw-r--r--include/block/block_int.h61
-rw-r--r--include/exec/memory-internal.h13
-rw-r--r--include/exec/memory.h47
-rw-r--r--include/hw/intc/heathrow_pic.h49
-rw-r--r--include/hw/misc/macio/macio.h79
-rw-r--r--include/hw/ppc/openpic.h160
-rw-r--r--include/hw/ppc/openpic_kvm.h7
-rw-r--r--include/hw/ppc/spapr.h5
-rw-r--r--include/hw/scsi/scsi.h2
-rw-r--r--include/qemu/lockable.h2
-rw-r--r--include/qom/object.h16
-rw-r--r--memory.c30
-rw-r--r--pc-bios/canyonlands.dtbbin0 -> 9779 bytes
-rw-r--r--pc-bios/canyonlands.dts566
-rwxr-xr-xpc-bios/u-boot-sam460-20100605.binbin0 -> 524288 bytes
-rw-r--r--qapi/block-core.json6
-rw-r--r--qapi/misc.json34
-rw-r--r--qdev-monitor.c6
-rw-r--r--qemu-doc.texi33
-rw-r--r--qemu-img.c2
-rw-r--r--qemu-io.c2
-rw-r--r--qemu-options.hx11
-rw-r--r--qga/commands-posix.c4
-rw-r--r--qmp.c69
-rw-r--r--qom/object.c7
-rw-r--r--roms/Makefile7
m---------roms/u-boot-sam460ex0
-rwxr-xr-xscripts/checkpatch.pl10
-rw-r--r--target/i386/whpx-all.c70
-rw-r--r--target/ppc/kvm-stub.c2
-rw-r--r--target/ppc/kvm.c6
-rw-r--r--target/ppc/translate_init.c2
-rw-r--r--tests/Makefile.include2
-rw-r--r--tests/ahci-test.c1
-rwxr-xr-xtests/qemu-iotests/03329
-rw-r--r--tests/qemu-iotests/033.out13
-rwxr-xr-xtests/qemu-iotests/0514
-rw-r--r--tests/sdhci-test.c2
-rw-r--r--tests/test-block-backend.c82
-rw-r--r--util/Makefile.objs2
-rw-r--r--util/aio-wait.c40
-rw-r--r--vl.c20
122 files changed, 3867 insertions, 1576 deletions
diff --git a/.gitmodules b/.gitmodules
index 7a8282df46..b76fb450a4 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -43,3 +43,6 @@
[submodule "roms/seabios-hppa"]
path = roms/seabios-hppa
url = git://github.com/hdeller/seabios-hppa.git
+[submodule "roms/u-boot-sam460ex"]
+ path = roms/u-boot-sam460ex
+ url = git://github.com/zbalaton/u-boot-sam460ex
diff --git a/Makefile b/Makefile
index 4df1f67fe4..9a75c48ae0 100644
--- a/Makefile
+++ b/Makefile
@@ -779,12 +779,12 @@ efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \
efi-e1000e.rom efi-vmxnet3.rom \
qemu-icon.bmp qemu_logo_no_text.svg \
-bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
+bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin \
s390-ccw.img s390-netboot.img \
spapr-rtas.bin slof.bin skiboot.lid \
palcode-clipper \
-u-boot.e500 \
+u-boot.e500 u-boot-sam460-20100605.bin \
qemu_vga.ndrv \
hppa-firmware.img
else
diff --git a/block.c b/block.c
index c205320a50..4f76714f6b 100644
--- a/block.c
+++ b/block.c
@@ -418,7 +418,7 @@ static void coroutine_fn bdrv_create_co_entry(void *opaque)
CreateCo *cco = opaque;
assert(cco->drv);
- ret = cco->drv->bdrv_create(cco->filename, cco->opts, &local_err);
+ ret = cco->drv->bdrv_co_create_opts(cco->filename, cco->opts, &local_err);
error_propagate(&cco->err, local_err);
cco->ret = ret;
}
@@ -437,7 +437,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
.err = NULL,
};
- if (!drv->bdrv_create) {
+ if (!drv->bdrv_co_create_opts) {
error_setg(errp, "Driver '%s' does not support image creation", drv->format_name);
ret = -ENOTSUP;
goto out;
@@ -4711,7 +4711,12 @@ out:
AioContext *bdrv_get_aio_context(BlockDriverState *bs)
{
- return bs->aio_context;
+ return bs ? bs->aio_context : qemu_get_aio_context();
+}
+
+AioWait *bdrv_get_aio_wait(BlockDriverState *bs)
+{
+ return bs ? &bs->wait : NULL;
}
void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co)
diff --git a/block/blkdebug.c b/block/blkdebug.c
index d83f23febd..589712475a 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -627,15 +627,17 @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
}
-static int64_t coroutine_fn blkdebug_co_get_block_status(
- BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
- BlockDriverState **file)
+static int coroutine_fn blkdebug_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset,
+ int64_t bytes,
+ int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file)
{
- assert(QEMU_IS_ALIGNED(sector_num | nb_sectors,
- DIV_ROUND_UP(bs->bl.request_alignment,
- BDRV_SECTOR_SIZE)));
- return bdrv_co_get_block_status_from_file(bs, sector_num, nb_sectors,
- pnum, file);
+ assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
+ return bdrv_co_block_status_from_file(bs, want_zero, offset, bytes,
+ pnum, map, file);
}
static void blkdebug_close(BlockDriverState *bs)
@@ -907,7 +909,7 @@ static BlockDriver bdrv_blkdebug = {
.bdrv_co_flush_to_disk = blkdebug_co_flush,
.bdrv_co_pwrite_zeroes = blkdebug_co_pwrite_zeroes,
.bdrv_co_pdiscard = blkdebug_co_pdiscard,
- .bdrv_co_get_block_status = blkdebug_co_get_block_status,
+ .bdrv_co_block_status = blkdebug_co_block_status,
.bdrv_debug_event = blkdebug_debug_event,
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
diff --git a/block/block-backend.c b/block/block-backend.c
index 94ffbb6a60..b3c790e2bd 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -73,6 +73,14 @@ struct BlockBackend {
int quiesce_counter;
VMChangeStateEntry *vmsh;
bool force_allow_inactivate;
+
+ /* Number of in-flight aio requests. BlockDriverState also counts
+ * in-flight requests but aio requests can exist even when blk->root is
+ * NULL, so we cannot rely on its counter for that case.
+ * Accessed with atomic ops.
+ */
+ unsigned int in_flight;
+ AioWait wait;
};
typedef struct BlockBackendAIOCB {
@@ -1225,11 +1233,22 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
return bdrv_make_zero(blk->root, flags);
}
+static void blk_inc_in_flight(BlockBackend *blk)
+{
+ atomic_inc(&blk->in_flight);
+}
+
+static void blk_dec_in_flight(BlockBackend *blk)
+{
+ atomic_dec(&blk->in_flight);
+ aio_wait_kick(&blk->wait);
+}
+
static void error_callback_bh(void *opaque)
{
struct BlockBackendAIOCB *acb = opaque;
- bdrv_dec_in_flight(acb->common.bs);
+ blk_dec_in_flight(acb->blk);
acb->common.cb(acb->common.opaque, acb->ret);
qemu_aio_unref(acb);
}
@@ -1240,7 +1259,7 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
{
struct BlockBackendAIOCB *acb;
- bdrv_inc_in_flight(blk_bs(blk));
+ blk_inc_in_flight(blk);
acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque);
acb->blk = blk;
acb->ret = ret;
@@ -1263,7 +1282,7 @@ static const AIOCBInfo blk_aio_em_aiocb_info = {
static void blk_aio_complete(BlkAioEmAIOCB *acb)
{
if (acb->has_returned) {
- bdrv_dec_in_flight(acb->common.bs);
+ blk_dec_in_flight(acb->rwco.blk);
acb->common.cb(acb->common.opaque, acb->rwco.ret);
qemu_aio_unref(acb);
}
@@ -1284,7 +1303,7 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
BlkAioEmAIOCB *acb;
Coroutine *co;
- bdrv_inc_in_flight(blk_bs(blk));
+ blk_inc_in_flight(blk);
acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
acb->rwco = (BlkRwCo) {
.blk = blk,
@@ -1521,14 +1540,41 @@ int blk_flush(BlockBackend *blk)
void blk_drain(BlockBackend *blk)
{
- if (blk_bs(blk)) {
- bdrv_drain(blk_bs(blk));
+ BlockDriverState *bs = blk_bs(blk);
+
+ if (bs) {
+ bdrv_drained_begin(bs);
+ }
+
+ /* We may have -ENOMEDIUM completions in flight */
+ AIO_WAIT_WHILE(&blk->wait,
+ blk_get_aio_context(blk),
+ atomic_mb_read(&blk->in_flight) > 0);
+
+ if (bs) {
+ bdrv_drained_end(bs);
}
}
void blk_drain_all(void)
{
- bdrv_drain_all();
+ BlockBackend *blk = NULL;
+
+ bdrv_drain_all_begin();
+
+ while ((blk = blk_all_next(blk)) != NULL) {
+ AioContext *ctx = blk_get_aio_context(blk);
+
+ aio_context_acquire(ctx);
+
+ /* We may have -ENOMEDIUM completions in flight */
+ AIO_WAIT_WHILE(&blk->wait, ctx,
+ atomic_mb_read(&blk->in_flight) > 0);
+
+ aio_context_release(ctx);
+ }
+
+ bdrv_drain_all_end();
}
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
@@ -1569,10 +1615,11 @@ static void send_qmp_error_event(BlockBackend *blk,
bool is_read, int error)
{
IoOperationType optype;
+ BlockDriverState *bs = blk_bs(blk);
optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
- qapi_event_send_block_io_error(blk_name(blk),
- bdrv_get_node_name(blk_bs(blk)), optype,
+ qapi_event_send_block_io_error(blk_name(blk), !!bs,
+ bs ? bdrv_get_node_name(bs) : NULL, optype,
action, blk_iostatus_is_enabled(blk),
error == ENOSPC, strerror(error),
&error_abort);
diff --git a/block/commit.c b/block/commit.c
index bb6c904704..1943c9c3e1 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -265,7 +265,7 @@ static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c,
static BlockDriver bdrv_commit_top = {
.format_name = "commit_top",
.bdrv_co_preadv = bdrv_commit_top_preadv,
- .bdrv_co_get_block_status = bdrv_co_get_block_status_from_backing,
+ .bdrv_co_block_status = bdrv_co_block_status_from_backing,
.bdrv_refresh_filename = bdrv_commit_top_refresh_filename,
.bdrv_close = bdrv_commit_top_close,
.bdrv_child_perm = bdrv_commit_top_child_perm,
diff --git a/block/crypto.c b/block/crypto.c
index aeac482e7b..17b5c0abad 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -556,9 +556,9 @@ static int block_crypto_open_luks(BlockDriverState *bs,
bs, options, flags, errp);
}
-static int block_crypto_create_luks(const char *filename,
- QemuOpts *opts,
- Error **errp)
+static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
+ QemuOpts *opts,
+ Error **errp)
{
return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
filename, opts, errp);
@@ -617,7 +617,7 @@ BlockDriver bdrv_crypto_luks = {
.bdrv_open = block_crypto_open_luks,
.bdrv_close = block_crypto_close,
.bdrv_child_perm = bdrv_format_default_perms,
- .bdrv_create = block_crypto_create_luks,
+ .bdrv_co_create_opts = block_crypto_co_create_opts_luks,
.bdrv_truncate = block_crypto_truncate,
.create_opts = &block_crypto_create_opts_luks,
diff --git a/block/file-posix.c b/block/file-posix.c
index ca49c1a98a..7f2cc63c60 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1982,7 +1982,8 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
return (int64_t)st.st_blocks * 512;
}
-static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
int fd;
int result = 0;
@@ -2131,25 +2132,24 @@ static int find_allocation(BlockDriverState *bs, off_t start,
}
/*
- * Returns the allocation status of the specified sectors.
+ * Returns the allocation status of the specified offset.
*
- * If 'sector_num' is beyond the end of the disk image the return value is 0
- * and 'pnum' is set to 0.
+ * The block layer guarantees 'offset' and 'bytes' are within bounds.
*
- * 'pnum' is set to the number of sectors (including and immediately following
- * the specified sector) that are known to be in the same
+ * 'pnum' is set to the number of bytes (including and immediately following
+ * the specified offset) that are known to be in the same
* allocated/unallocated state.
*
- * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
- * beyond the end of the disk image it will be clamped.
+ * 'bytes' is the max value 'pnum' should be set to.
*/
-static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors, int *pnum,
- BlockDriverState **file)
-{
- off_t start, data = 0, hole = 0;
- int64_t total_size;
+static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset,
+ int64_t bytes, int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file)
+{
+ off_t data = 0, hole = 0;
int ret;
ret = fd_open(bs);
@@ -2157,39 +2157,36 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
return ret;
}
- start = sector_num * BDRV_SECTOR_SIZE;
- total_size = bdrv_getlength(bs);
- if (total_size < 0) {
- return total_size;
- } else if (start >= total_size) {
- *pnum = 0;
- return 0;
- } else if (start + nb_sectors * BDRV_SECTOR_SIZE > total_size) {
- nb_sectors = DIV_ROUND_UP(total_size - start, BDRV_SECTOR_SIZE);
+ if (!want_zero) {
+ *pnum = bytes;
+ *map = offset;
+ *file = bs;
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
}
- ret = find_allocation(bs, start, &data, &hole);
+ ret = find_allocation(bs, offset, &data, &hole);
if (ret == -ENXIO) {
/* Trailing hole */
- *pnum = nb_sectors;
+ *pnum = bytes;
ret = BDRV_BLOCK_ZERO;
} else if (ret < 0) {
/* No info available, so pretend there are no holes */
- *pnum = nb_sectors;
+ *pnum = bytes;
ret = BDRV_BLOCK_DATA;
- } else if (data == start) {
- /* On a data extent, compute sectors to the end of the extent,
+ } else if (data == offset) {
+ /* On a data extent, compute bytes to the end of the extent,
* possibly including a partial sector at EOF. */
- *pnum = MIN(nb_sectors, DIV_ROUND_UP(hole - start, BDRV_SECTOR_SIZE));
+ *pnum = MIN(bytes, hole - offset);
ret = BDRV_BLOCK_DATA;
} else {
- /* On a hole, compute sectors to the beginning of the next extent. */
- assert(hole == start);
- *pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE);
+ /* On a hole, compute bytes to the beginning of the next extent. */
+ assert(hole == offset);
+ *pnum = MIN(bytes, data - offset);
ret = BDRV_BLOCK_ZERO;
}
+ *map = offset;
*file = bs;
- return ret | BDRV_BLOCK_OFFSET_VALID | start;
+ return ret | BDRV_BLOCK_OFFSET_VALID;
}
static coroutine_fn BlockAIOCB *raw_aio_pdiscard(BlockDriverState *bs,
@@ -2280,9 +2277,9 @@ BlockDriver bdrv_file = {
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_close = raw_close,
- .bdrv_create = raw_create,
+ .bdrv_co_create_opts = raw_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_co_get_block_status = raw_co_get_block_status,
+ .bdrv_co_block_status = raw_co_block_status,
.bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes,
.bdrv_co_preadv = raw_co_preadv,
@@ -2684,8 +2681,8 @@ static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs,
return -ENOTSUP;
}
-static int hdev_create(const char *filename, QemuOpts *opts,
- Error **errp)
+static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
int fd;
int ret = 0;
@@ -2758,7 +2755,7 @@ static BlockDriver bdrv_host_device = {
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
- .bdrv_create = hdev_create,
+ .bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts,
.bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes,
@@ -2880,7 +2877,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
- .bdrv_create = hdev_create,
+ .bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts,
@@ -3011,7 +3008,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
- .bdrv_create = hdev_create,
+ .bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts,
.bdrv_co_preadv = raw_co_preadv,
diff --git a/block/file-win32.c b/block/file-win32.c
index f24c7bb92c..4a430d45f1 100644
--- a/block/file-win32.c
+++ b/block/file-win32.c
@@ -553,7 +553,8 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
return st.st_size;
}
-static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
int fd;
int64_t total_size = 0;
@@ -599,7 +600,7 @@ BlockDriver bdrv_file = {
.bdrv_file_open = raw_open,
.bdrv_refresh_limits = raw_probe_alignment,
.bdrv_close = raw_close,
- .bdrv_create = raw_create,
+ .bdrv_co_create_opts = raw_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_aio_readv = raw_aio_readv,
diff --git a/block/gluster.c b/block/gluster.c
index 3f17b7819d..79b4cfdf74 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -1021,8 +1021,9 @@ static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
return 0;
}
-static int qemu_gluster_create(const char *filename,
- QemuOpts *opts, Error **errp)
+static int coroutine_fn qemu_gluster_co_create_opts(const char *filename,
+ QemuOpts *opts,
+ Error **errp)
{
BlockdevOptionsGluster *gconf;
struct glfs *glfs;
@@ -1362,68 +1363,66 @@ exit:
}
/*
- * Returns the allocation status of the specified sectors.
+ * Returns the allocation status of the specified offset.
*
- * If 'sector_num' is beyond the end of the disk image the return value is 0
- * and 'pnum' is set to 0.
+ * The block layer guarantees 'offset' and 'bytes' are within bounds.
*
- * 'pnum' is set to the number of sectors (including and immediately following
- * the specified sector) that are known to be in the same
+ * 'pnum' is set to the number of bytes (including and immediately following
+ * the specified offset) that are known to be in the same
* allocated/unallocated state.
*
- * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
- * beyond the end of the disk image it will be clamped.
+ * 'bytes' is the max value 'pnum' should be set to.
*
- * (Based on raw_co_get_block_status() from file-posix.c.)
+ * (Based on raw_co_block_status() from file-posix.c.)
*/
-static int64_t coroutine_fn qemu_gluster_co_get_block_status(
- BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
- BlockDriverState **file)
+static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset,
+ int64_t bytes,
+ int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file)
{
BDRVGlusterState *s = bs->opaque;
- off_t start, data = 0, hole = 0;
- int64_t total_size;
+ off_t data = 0, hole = 0;
int ret = -EINVAL;
if (!s->fd) {
return ret;
}
- start = sector_num * BDRV_SECTOR_SIZE;
- total_size = bdrv_getlength(bs);
- if (total_size < 0) {
- return total_size;
- } else if (start >= total_size) {
- *pnum = 0;
- return 0;
- } else if (start + nb_sectors * BDRV_SECTOR_SIZE > total_size) {
- nb_sectors = DIV_ROUND_UP(total_size - start, BDRV_SECTOR_SIZE);
+ if (!want_zero) {
+ *pnum = bytes;
+ *map = offset;
+ *file = bs;
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
}
- ret = find_allocation(bs, start, &data, &hole);
+ ret = find_allocation(bs, offset, &data, &hole);
if (ret == -ENXIO) {
/* Trailing hole */
- *pnum = nb_sectors;
+ *pnum = bytes;
ret = BDRV_BLOCK_ZERO;
} else if (ret < 0) {
/* No info available, so pretend there are no holes */
- *pnum = nb_sectors;
+ *pnum = bytes;
ret = BDRV_BLOCK_DATA;
- } else if (data == start) {
- /* On a data extent, compute sectors to the end of the extent,
+ } else if (data == offset) {
+ /* On a data extent, compute bytes to the end of the extent,
* possibly including a partial sector at EOF. */
- *pnum = MIN(nb_sectors, DIV_ROUND_UP(hole - start, BDRV_SECTOR_SIZE));
+ *pnum = MIN(bytes, hole - offset);
ret = BDRV_BLOCK_DATA;
} else {
- /* On a hole, compute sectors to the beginning of the next extent. */
- assert(hole == start);
- *pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE);
+ /* On a hole, compute bytes to the beginning of the next extent. */
+ assert(hole == offset);
+ *pnum = MIN(bytes, data - offset);
ret = BDRV_BLOCK_ZERO;
}
+ *map = offset;
*file = bs;
- return ret | BDRV_BLOCK_OFFSET_VALID | start;
+ return ret | BDRV_BLOCK_OFFSET_VALID;
}
@@ -1437,7 +1436,7 @@ static BlockDriver bdrv_gluster = {
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
- .bdrv_create = qemu_gluster_create,
+ .bdrv_co_create_opts = qemu_gluster_co_create_opts,
.bdrv_getlength = qemu_gluster_getlength,
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
.bdrv_truncate = qemu_gluster_truncate,
@@ -1451,7 +1450,7 @@ static BlockDriver bdrv_gluster = {
#ifdef CONFIG_GLUSTERFS_ZEROFILL
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
#endif
- .bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
+ .bdrv_co_block_status = qemu_gluster_co_block_status,
.create_opts = &qemu_gluster_create_opts,
};
@@ -1465,7 +1464,7 @@ static BlockDriver bdrv_gluster_tcp = {
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
- .bdrv_create = qemu_gluster_create,
+ .bdrv_co_create_opts = qemu_gluster_co_create_opts,
.bdrv_getlength = qemu_gluster_getlength,
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
.bdrv_truncate = qemu_gluster_truncate,
@@ -1479,7 +1478,7 @@ static BlockDriver bdrv_gluster_tcp = {
#ifdef CONFIG_GLUSTERFS_ZEROFILL
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
#endif
- .bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
+ .bdrv_co_block_status = qemu_gluster_co_block_status,
.create_opts = &qemu_gluster_create_opts,
};
@@ -1493,7 +1492,7 @@ static BlockDriver bdrv_gluster_unix = {
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
- .bdrv_create = qemu_gluster_create,
+ .bdrv_co_create_opts = qemu_gluster_co_create_opts,
.bdrv_getlength = qemu_gluster_getlength,
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
.bdrv_truncate = qemu_gluster_truncate,
@@ -1507,7 +1506,7 @@ static BlockDriver bdrv_gluster_unix = {
#ifdef CONFIG_GLUSTERFS_ZEROFILL
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
#endif
- .bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
+ .bdrv_co_block_status = qemu_gluster_co_block_status,
.create_opts = &qemu_gluster_create_opts,
};
@@ -1527,7 +1526,7 @@ static BlockDriver bdrv_gluster_rdma = {
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
- .bdrv_create = qemu_gluster_create,
+ .bdrv_co_create_opts = qemu_gluster_co_create_opts,
.bdrv_getlength = qemu_gluster_getlength,
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
.bdrv_truncate = qemu_gluster_truncate,
@@ -1541,7 +1540,7 @@ static BlockDriver bdrv_gluster_rdma = {
#ifdef CONFIG_GLUSTERFS_ZEROFILL
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
#endif
- .bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
+ .bdrv_co_block_status = qemu_gluster_co_block_status,
.create_opts = &qemu_gluster_create_opts,
};
diff --git a/block/io.c b/block/io.c
index 89d0745e95..2b09c656d0 100644
--- a/block/io.c
+++ b/block/io.c
@@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "trace.h"
#include "sysemu/block-backend.h"
+#include "block/aio-wait.h"
#include "block/blockjob.h"
#include "block/blockjob_int.h"
#include "block/block_int.h"
@@ -587,16 +588,9 @@ void bdrv_inc_in_flight(BlockDriverState *bs)
atomic_inc(&bs->in_flight);
}
-static void dummy_bh_cb(void *opaque)
-{
-}
-
void bdrv_wakeup(BlockDriverState *bs)
{
- /* The barrier (or an atomic op) is in the caller. */
- if (atomic_read(&bs->wakeup)) {
- aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
- }
+ aio_wait_kick(bdrv_get_aio_wait(bs));
}
void bdrv_dec_in_flight(BlockDriverState *bs)
@@ -1701,7 +1695,7 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
*/
tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_WRITE);
- if (!qiov) {
+ if (flags & BDRV_REQ_ZERO_WRITE) {
ret = bdrv_co_do_zero_pwritev(child, offset, bytes, flags, &req);
goto out;
}
@@ -1868,30 +1862,34 @@ typedef struct BdrvCoBlockStatusData {
bool done;
} BdrvCoBlockStatusData;
-int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors,
- int *pnum,
- BlockDriverState **file)
+int coroutine_fn bdrv_co_block_status_from_file(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset,
+ int64_t bytes,
+ int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file)
{
assert(bs->file && bs->file->bs);
- *pnum = nb_sectors;
+ *pnum = bytes;
+ *map = offset;
*file = bs->file->bs;
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
- (sector_num << BDRV_SECTOR_BITS);
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID;
}
-int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors,
- int *pnum,
- BlockDriverState **file)
+int coroutine_fn bdrv_co_block_status_from_backing(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset,
+ int64_t bytes,
+ int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file)
{
assert(bs->backing && bs->backing->bs);
- *pnum = nb_sectors;
+ *pnum = bytes;
+ *map = offset;
*file = bs->backing->bs;
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
- (sector_num << BDRV_SECTOR_BITS);
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID;
}
/*
@@ -1899,10 +1897,10 @@ int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
* Drivers not implementing the functionality are assumed to not support
* backing files, hence all their sectors are reported as allocated.
*
- * If 'want_zero' is true, the caller is querying for mapping purposes,
- * and the result should include BDRV_BLOCK_OFFSET_VALID and
- * BDRV_BLOCK_ZERO where possible; otherwise, the result may omit those
- * bits particularly if it allows for a larger value in 'pnum'.
+ * If 'want_zero' is true, the caller is querying for mapping
+ * purposes, with a focus on valid BDRV_BLOCK_OFFSET_VALID, _DATA, and
+ * _ZERO where possible; otherwise, the result favors larger 'pnum',
+ * with a focus on accurate BDRV_BLOCK_ALLOCATED.
*
* If 'offset' is beyond the end of the disk image the return value is
* BDRV_BLOCK_EOF and 'pnum' is set to 0.
@@ -1959,7 +1957,7 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
/* Must be non-NULL or bdrv_getlength() would have failed */
assert(bs->drv);
- if (!bs->drv->bdrv_co_get_block_status) {
+ if (!bs->drv->bdrv_co_block_status) {
*pnum = bytes;
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
if (offset + bytes == total_size) {
@@ -1976,44 +1974,24 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
bdrv_inc_in_flight(bs);
/* Round out to request_alignment boundaries */
- /* TODO: until we have a byte-based driver callback, we also have to
- * round out to sectors, even if that is bigger than request_alignment */
- align = MAX(bs->bl.request_alignment, BDRV_SECTOR_SIZE);
+ align = bs->bl.request_alignment;
aligned_offset = QEMU_ALIGN_DOWN(offset, align);
aligned_bytes = ROUND_UP(offset + bytes, align) - aligned_offset;
- {
- int count; /* sectors */
- int64_t longret;
-
- assert(QEMU_IS_ALIGNED(aligned_offset | aligned_bytes,
- BDRV_SECTOR_SIZE));
- /*
- * The contract allows us to return pnum smaller than bytes, even
- * if the next query would see the same status; we truncate the
- * request to avoid overflowing the driver's 32-bit interface.
- */
- longret = bs->drv->bdrv_co_get_block_status(
- bs, aligned_offset >> BDRV_SECTOR_BITS,
- MIN(INT_MAX, aligned_bytes) >> BDRV_SECTOR_BITS, &count,
- &local_file);
- if (longret < 0) {
- assert(INT_MIN <= longret);
- ret = longret;
- goto out;
- }
- if (longret & BDRV_BLOCK_OFFSET_VALID) {
- local_map = longret & BDRV_BLOCK_OFFSET_MASK;
- }
- ret = longret & ~BDRV_BLOCK_OFFSET_MASK;
- *pnum = count * BDRV_SECTOR_SIZE;
+ ret = bs->drv->bdrv_co_block_status(bs, want_zero, aligned_offset,
+ aligned_bytes, pnum, &local_map,
+ &local_file);
+ if (ret < 0) {
+ *pnum = 0;
+ goto out;
}
/*
- * The driver's result must be a multiple of request_alignment.
+ * The driver's result must be a non-zero multiple of request_alignment.
* Clamp pnum and adjust map to original request.
*/
- assert(QEMU_IS_ALIGNED(*pnum, align) && align > offset - aligned_offset);
+ assert(*pnum && QEMU_IS_ALIGNED(*pnum, align) &&
+ align > offset - aligned_offset);
*pnum -= offset - aligned_offset;
if (*pnum > bytes) {
*pnum = bytes;
diff --git a/block/iscsi.c b/block/iscsi.c
index d2b320ea41..8bf0e87244 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -86,7 +86,7 @@ typedef struct IscsiLun {
unsigned long *allocmap;
unsigned long *allocmap_valid;
long allocmap_size;
- int cluster_sectors;
+ int cluster_size;
bool use_16_for_rw;
bool write_protected;
bool lbpme;
@@ -430,9 +430,10 @@ static int iscsi_allocmap_init(IscsiLun *iscsilun, int open_flags)
{
iscsi_allocmap_free(iscsilun);
+ assert(iscsilun->cluster_size);
iscsilun->allocmap_size =
- DIV_ROUND_UP(sector_lun2qemu(iscsilun->num_blocks, iscsilun),
- iscsilun->cluster_sectors);
+ DIV_ROUND_UP(iscsilun->num_blocks * iscsilun->block_size,
+ iscsilun->cluster_size);
iscsilun->allocmap = bitmap_try_new(iscsilun->allocmap_size);
if (!iscsilun->allocmap) {
@@ -440,7 +441,7 @@ static int iscsi_allocmap_init(IscsiLun *iscsilun, int open_flags)
}
if (open_flags & BDRV_O_NOCACHE) {
- /* in case that cache.direct = on all allocmap entries are
+ /* when cache.direct = on all allocmap entries are
* treated as invalid to force a relookup of the block
* status on every read request */
return 0;
@@ -457,8 +458,8 @@ static int iscsi_allocmap_init(IscsiLun *iscsilun, int open_flags)
}
static void
-iscsi_allocmap_update(IscsiLun *iscsilun, int64_t sector_num,
- int nb_sectors, bool allocated, bool valid)
+iscsi_allocmap_update(IscsiLun *iscsilun, int64_t offset,
+ int64_t bytes, bool allocated, bool valid)
{
int64_t cl_num_expanded, nb_cls_expanded, cl_num_shrunk, nb_cls_shrunk;
@@ -466,13 +467,13 @@ iscsi_allocmap_update(IscsiLun *iscsilun, int64_t sector_num,
return;
}
/* expand to entirely contain all affected clusters */
- cl_num_expanded = sector_num / iscsilun->cluster_sectors;
- nb_cls_expanded = DIV_ROUND_UP(sector_num + nb_sectors,
- iscsilun->cluster_sectors) - cl_num_expanded;
+ assert(iscsilun->cluster_size);
+ cl_num_expanded = offset / iscsilun->cluster_size;
+ nb_cls_expanded = DIV_ROUND_UP(offset + bytes,
+ iscsilun->cluster_size) - cl_num_expanded;
/* shrink to touch only completely contained clusters */
- cl_num_shrunk = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors);
- nb_cls_shrunk = (sector_num + nb_sectors) / iscsilun->cluster_sectors
- - cl_num_shrunk;
+ cl_num_shrunk = DIV_ROUND_UP(offset, iscsilun->cluster_size);
+ nb_cls_shrunk = (offset + bytes) / iscsilun->cluster_size - cl_num_shrunk;
if (allocated) {
bitmap_set(iscsilun->allocmap, cl_num_expanded, nb_cls_expanded);
} else {
@@ -495,26 +496,26 @@ iscsi_allocmap_update(IscsiLun *iscsilun, int64_t sector_num,
}
static void
-iscsi_allocmap_set_allocated(IscsiLun *iscsilun, int64_t sector_num,
- int nb_sectors)
+iscsi_allocmap_set_allocated(IscsiLun *iscsilun, int64_t offset,
+ int64_t bytes)
{
- iscsi_allocmap_update(iscsilun, sector_num, nb_sectors, true, true);
+ iscsi_allocmap_update(iscsilun, offset, bytes, true, true);
}
static void
-iscsi_allocmap_set_unallocated(IscsiLun *iscsilun, int64_t sector_num,
- int nb_sectors)
+iscsi_allocmap_set_unallocated(IscsiLun *iscsilun, int64_t offset,
+ int64_t bytes)
{
/* Note: if cache.direct=on the fifth argument to iscsi_allocmap_update
* is ignored, so this will in effect be an iscsi_allocmap_set_invalid.
*/
- iscsi_allocmap_update(iscsilun, sector_num, nb_sectors, false, true);
+ iscsi_allocmap_update(iscsilun, offset, bytes, false, true);
}
-static void iscsi_allocmap_set_invalid(IscsiLun *iscsilun, int64_t sector_num,
- int nb_sectors)
+static void iscsi_allocmap_set_invalid(IscsiLun *iscsilun, int64_t offset,
+ int64_t bytes)
{
- iscsi_allocmap_update(iscsilun, sector_num, nb_sectors, false, false);
+ iscsi_allocmap_update(iscsilun, offset, bytes, false, false);
}
static void iscsi_allocmap_invalidate(IscsiLun *iscsilun)
@@ -528,28 +529,30 @@ static void iscsi_allocmap_invalidate(IscsiLun *iscsilun)
}
static inline bool
-iscsi_allocmap_is_allocated(IscsiLun *iscsilun, int64_t sector_num,
- int nb_sectors)
+iscsi_allocmap_is_allocated(IscsiLun *iscsilun, int64_t offset,
+ int64_t bytes)
{
unsigned long size;
if (iscsilun->allocmap == NULL) {
return true;
}
- size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors);
+ assert(iscsilun->cluster_size);
+ size = DIV_ROUND_UP(offset + bytes, iscsilun->cluster_size);
return !(find_next_bit(iscsilun->allocmap, size,
- sector_num / iscsilun->cluster_sectors) == size);
+ offset / iscsilun->cluster_size) == size);
}
static inline bool iscsi_allocmap_is_valid(IscsiLun *iscsilun,
- int64_t sector_num, int nb_sectors)
+ int64_t offset, int64_t bytes)
{
unsigned long size;
if (iscsilun->allocmap_valid == NULL) {
return false;
}
- size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors);
+ assert(iscsilun->cluster_size);
+ size = DIV_ROUND_UP(offset + bytes, iscsilun->cluster_size);
return (find_next_zero_bit(iscsilun->allocmap_valid, size,
- sector_num / iscsilun->cluster_sectors) == size);
+ offset / iscsilun->cluster_size) == size);
}
static int coroutine_fn
@@ -631,14 +634,16 @@ retry:
}
if (iTask.status != SCSI_STATUS_GOOD) {
- iscsi_allocmap_set_invalid(iscsilun, sector_num, nb_sectors);
+ iscsi_allocmap_set_invalid(iscsilun, sector_num * BDRV_SECTOR_SIZE,
+ nb_sectors * BDRV_SECTOR_SIZE);
error_report("iSCSI WRITE10/16 failed at lba %" PRIu64 ": %s", lba,
iTask.err_str);
r = iTask.err_code;
goto out_unlock;
}
- iscsi_allocmap_set_allocated(iscsilun, sector_num, nb_sectors);
+ iscsi_allocmap_set_allocated(iscsilun, sector_num * BDRV_SECTOR_SIZE,
+ nb_sectors * BDRV_SECTOR_SIZE);
out_unlock:
qemu_mutex_unlock(&iscsilun->mutex);
@@ -648,36 +653,36 @@ out_unlock:
-static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors, int *pnum,
- BlockDriverState **file)
+static int coroutine_fn iscsi_co_block_status(BlockDriverState *bs,
+ bool want_zero, int64_t offset,
+ int64_t bytes, int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file)
{
IscsiLun *iscsilun = bs->opaque;
struct scsi_get_lba_status *lbas = NULL;
struct scsi_lba_status_descriptor *lbasd = NULL;
struct IscsiTask iTask;
uint64_t lba;
- int64_t ret;
+ int ret;
iscsi_co_init_iscsitask(iscsilun, &iTask);
- if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
- ret = -EINVAL;
- goto out;
- }
+ assert(QEMU_IS_ALIGNED(offset | bytes, iscsilun->block_size));
/* default to all sectors allocated */
- ret = BDRV_BLOCK_DATA;
- ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
- *pnum = nb_sectors;
+ ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
+ if (map) {
+ *map = offset;
+ }
+ *pnum = bytes;
/* LUN does not support logical block provisioning */
if (!iscsilun->lbpme) {
goto out;
}
- lba = sector_qemu2lun(sector_num, iscsilun);
+ lba = offset / iscsilun->block_size;
qemu_mutex_lock(&iscsilun->mutex);
retry:
@@ -722,12 +727,12 @@ retry:
lbasd = &lbas->descriptors[0];
- if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
+ if (lba != lbasd->lba) {
ret = -EIO;
goto out_unlock;
}
- *pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
+ *pnum = lbasd->num_blocks * iscsilun->block_size;
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
@@ -738,13 +743,13 @@ retry:
}
if (ret & BDRV_BLOCK_ZERO) {
- iscsi_allocmap_set_unallocated(iscsilun, sector_num, *pnum);
+ iscsi_allocmap_set_unallocated(iscsilun, offset, *pnum);
} else {
- iscsi_allocmap_set_allocated(iscsilun, sector_num, *pnum);
+ iscsi_allocmap_set_allocated(iscsilun, offset, *pnum);
}
- if (*pnum > nb_sectors) {
- *pnum = nb_sectors;
+ if (*pnum > bytes) {
+ *pnum = bytes;
}
out_unlock:
qemu_mutex_unlock(&iscsilun->mutex);
@@ -753,7 +758,7 @@ out:
if (iTask.task != NULL) {
scsi_free_scsi_task(iTask.task);
}
- if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID) {
+ if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID && file) {
*file = bs;
}
return ret;
@@ -780,29 +785,37 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
/* if cache.direct is off and we have a valid entry in our allocation map
* we can skip checking the block status and directly return zeroes if
* the request falls within an unallocated area */
- if (iscsi_allocmap_is_valid(iscsilun, sector_num, nb_sectors) &&
- !iscsi_allocmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
+ if (iscsi_allocmap_is_valid(iscsilun, sector_num * BDRV_SECTOR_SIZE,
+ nb_sectors * BDRV_SECTOR_SIZE) &&
+ !iscsi_allocmap_is_allocated(iscsilun, sector_num * BDRV_SECTOR_SIZE,
+ nb_sectors * BDRV_SECTOR_SIZE)) {
qemu_iovec_memset(iov, 0, 0x00, iov->size);
return 0;
}
if (nb_sectors >= ISCSI_CHECKALLOC_THRES &&
- !iscsi_allocmap_is_valid(iscsilun, sector_num, nb_sectors) &&
- !iscsi_allocmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
- int pnum;
- BlockDriverState *file;
+ !iscsi_allocmap_is_valid(iscsilun, sector_num * BDRV_SECTOR_SIZE,
+ nb_sectors * BDRV_SECTOR_SIZE) &&
+ !iscsi_allocmap_is_allocated(iscsilun, sector_num * BDRV_SECTOR_SIZE,
+ nb_sectors * BDRV_SECTOR_SIZE)) {
+ int64_t pnum;
/* check the block status from the beginning of the cluster
* containing the start sector */
- int64_t ret = iscsi_co_get_block_status(bs,
- sector_num - sector_num % iscsilun->cluster_sectors,
- BDRV_REQUEST_MAX_SECTORS, &pnum, &file);
+ int64_t head;
+ int ret;
+
+ assert(iscsilun->cluster_size);
+ head = (sector_num * BDRV_SECTOR_SIZE) % iscsilun->cluster_size;
+ ret = iscsi_co_block_status(bs, true,
+ sector_num * BDRV_SECTOR_SIZE - head,
+ BDRV_REQUEST_MAX_BYTES, &pnum, NULL, NULL);
if (ret < 0) {
return ret;
}
/* if the whole request falls into an unallocated area we can avoid
- * to read and directly return zeroes instead */
+ * reading and directly return zeroes instead */
if (ret & BDRV_BLOCK_ZERO &&
- pnum >= nb_sectors + sector_num % iscsilun->cluster_sectors) {
+ pnum >= nb_sectors * BDRV_SECTOR_SIZE + head) {
qemu_iovec_memset(iov, 0, 0x00, iov->size);
return 0;
}
@@ -1146,8 +1159,7 @@ retry:
goto retry;
}
- iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
- bytes >> BDRV_SECTOR_BITS);
+ iscsi_allocmap_set_invalid(iscsilun, offset, bytes);
if (iTask.status == SCSI_STATUS_CHECK_CONDITION) {
/* the target might fail with a check condition if it
@@ -1260,8 +1272,7 @@ retry:
}
if (iTask.status != SCSI_STATUS_GOOD) {
- iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
- bytes >> BDRV_SECTOR_BITS);
+ iscsi_allocmap_set_invalid(iscsilun, offset, bytes);
error_report("iSCSI WRITESAME10/16 failed at lba %" PRIu64 ": %s",
lba, iTask.err_str);
r = iTask.err_code;
@@ -1269,11 +1280,9 @@ retry:
}
if (flags & BDRV_REQ_MAY_UNMAP) {
- iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
- bytes >> BDRV_SECTOR_BITS);
+ iscsi_allocmap_set_invalid(iscsilun, offset, bytes);
} else {
- iscsi_allocmap_set_allocated(iscsilun, offset >> BDRV_SECTOR_BITS,
- bytes >> BDRV_SECTOR_BITS);
+ iscsi_allocmap_set_allocated(iscsilun, offset, bytes);
}
out_unlock:
@@ -1953,8 +1962,8 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
* reasonable size */
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 &&
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
- iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran *
- iscsilun->block_size) >> BDRV_SECTOR_BITS;
+ iscsilun->cluster_size = iscsilun->bl.opt_unmap_gran *
+ iscsilun->block_size;
if (iscsilun->lbprz) {
ret = iscsi_allocmap_init(iscsilun, bs->open_flags);
}
@@ -2108,7 +2117,8 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset,
return 0;
}
-static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn iscsi_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
int ret = 0;
int64_t total_size = 0;
@@ -2163,7 +2173,7 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
IscsiLun *iscsilun = bs->opaque;
bdi->unallocated_blocks_are_zero = iscsilun->lbprz;
- bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE;
+ bdi->cluster_size = iscsilun->cluster_size;
return 0;
}
@@ -2195,7 +2205,7 @@ static BlockDriver bdrv_iscsi = {
.bdrv_parse_filename = iscsi_parse_filename,
.bdrv_file_open = iscsi_open,
.bdrv_close = iscsi_close,
- .bdrv_create = iscsi_create,
+ .bdrv_co_create_opts = iscsi_co_create_opts,
.create_opts = &iscsi_create_opts,
.bdrv_reopen_prepare = iscsi_reopen_prepare,
.bdrv_reopen_commit = iscsi_reopen_commit,
@@ -2206,7 +2216,7 @@ static BlockDriver bdrv_iscsi = {
.bdrv_truncate = iscsi_truncate,
.bdrv_refresh_limits = iscsi_refresh_limits,
- .bdrv_co_get_block_status = iscsi_co_get_block_status,
+ .bdrv_co_block_status = iscsi_co_block_status,
.bdrv_co_pdiscard = iscsi_co_pdiscard,
.bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
.bdrv_co_readv = iscsi_co_readv,
@@ -2230,7 +2240,7 @@ static BlockDriver bdrv_iser = {
.bdrv_parse_filename = iscsi_parse_filename,
.bdrv_file_open = iscsi_open,
.bdrv_close = iscsi_close,
- .bdrv_create = iscsi_create,
+ .bdrv_co_create_opts = iscsi_co_create_opts,
.create_opts = &iscsi_create_opts,
.bdrv_reopen_prepare = iscsi_reopen_prepare,
.bdrv_reopen_commit = iscsi_reopen_commit,
@@ -2241,7 +2251,7 @@ static BlockDriver bdrv_iser = {
.bdrv_truncate = iscsi_truncate,
.bdrv_refresh_limits = iscsi_refresh_limits,
- .bdrv_co_get_block_status = iscsi_co_get_block_status,
+ .bdrv_co_block_status = iscsi_co_block_status,
.bdrv_co_pdiscard = iscsi_co_pdiscard,
.bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
.bdrv_co_readv = iscsi_co_readv,
diff --git a/block/mirror.c b/block/mirror.c
index c9badc1203..f5bf620942 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1094,7 +1094,7 @@ static BlockDriver bdrv_mirror_top = {
.bdrv_co_pwrite_zeroes = bdrv_mirror_top_pwrite_zeroes,
.bdrv_co_pdiscard = bdrv_mirror_top_pdiscard,
.bdrv_co_flush = bdrv_mirror_top_flush,
- .bdrv_co_get_block_status = bdrv_co_get_block_status_from_backing,
+ .bdrv_co_block_status = bdrv_co_block_status_from_backing,
.bdrv_refresh_filename = bdrv_mirror_top_refresh_filename,
.bdrv_close = bdrv_mirror_top_close,
.bdrv_child_perm = bdrv_mirror_top_child_perm,
diff --git a/block/nfs.c b/block/nfs.c
index bbdb4fadad..1d82ff5042 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -684,7 +684,8 @@ static QemuOptsList nfs_create_opts = {
}
};
-static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
+static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
+ Error **errp)
{
int64_t ret, total_size;
NFSClient *client = g_new0(NFSClient, 1);
@@ -897,7 +898,7 @@ static BlockDriver bdrv_nfs = {
.bdrv_file_open = nfs_file_open,
.bdrv_close = nfs_file_close,
- .bdrv_create = nfs_file_create,
+ .bdrv_co_create_opts = nfs_file_co_create_opts,
.bdrv_reopen_prepare = nfs_reopen_prepare,
.bdrv_co_preadv = nfs_co_preadv,
diff --git a/block/null.c b/block/null.c
index 214d394fff..806a8631e4 100644
--- a/block/null.c
+++ b/block/null.c
@@ -223,22 +223,23 @@ static int null_reopen_prepare(BDRVReopenState *reopen_state,
return 0;
}
-static int64_t coroutine_fn null_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors, int *pnum,
- BlockDriverState **file)
+static int coroutine_fn null_co_block_status(BlockDriverState *bs,
+ bool want_zero, int64_t offset,
+ int64_t bytes, int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file)
{
BDRVNullState *s = bs->opaque;
- off_t start = sector_num * BDRV_SECTOR_SIZE;
+ int ret = BDRV_BLOCK_OFFSET_VALID;
- *pnum = nb_sectors;
+ *pnum = bytes;
+ *map = offset;
*file = bs;
if (s->read_zeroes) {
- return BDRV_BLOCK_OFFSET_VALID | start | BDRV_BLOCK_ZERO;
- } else {
- return BDRV_BLOCK_OFFSET_VALID | start;
+ ret |= BDRV_BLOCK_ZERO;
}
+ return ret;
}
static void null_refresh_filename(BlockDriverState *bs, QDict *opts)
@@ -270,7 +271,7 @@ static BlockDriver bdrv_null_co = {
.bdrv_co_flush_to_disk = null_co_flush,
.bdrv_reopen_prepare = null_reopen_prepare,
- .bdrv_co_get_block_status = null_co_get_block_status,
+ .bdrv_co_block_status = null_co_block_status,
.bdrv_refresh_filename = null_refresh_filename,
};
@@ -290,7 +291,7 @@ static BlockDriver bdrv_null_aio = {
.bdrv_aio_flush = null_aio_flush,
.bdrv_reopen_prepare = null_reopen_prepare,
- .bdrv_co_get_block_status = null_co_get_block_status,
+ .bdrv_co_block_status = null_co_block_status,
.bdrv_refresh_filename = null_refresh_filename,
};
diff --git a/block/nvme.c b/block/nvme.c
index 75078022f6..8bca57aae6 100644
--- a/block/nvme.c
+++ b/block/nvme.c
@@ -1072,18 +1072,6 @@ static int nvme_reopen_prepare(BDRVReopenState *reopen_state,
return 0;
}
-static int64_t coroutine_fn nvme_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors, int *pnum,
- BlockDriverState **file)
-{
- *pnum = nb_sectors;
- *file = bs;
-
- return BDRV_BLOCK_ALLOCATED | BDRV_BLOCK_OFFSET_VALID |
- (sector_num << BDRV_SECTOR_BITS);
-}
-
static void nvme_refresh_filename(BlockDriverState *bs, QDict *opts)
{
QINCREF(opts);
@@ -1183,8 +1171,6 @@ static BlockDriver bdrv_nvme = {
.bdrv_co_flush_to_disk = nvme_co_flush,
.bdrv_reopen_prepare = nvme_reopen_prepare,
- .bdrv_co_get_block_status = nvme_co_get_block_status,
-
.bdrv_refresh_filename = nvme_refresh_filename,
.bdrv_refresh_limits = nvme_refresh_limits,
diff --git a/block/parallels.c b/block/parallels.c
index e1e3d80c88..81085795c2 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -261,23 +261,31 @@ static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
}
-static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
+static int coroutine_fn parallels_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset,
+ int64_t bytes,
+ int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file)
{
BDRVParallelsState *s = bs->opaque;
- int64_t offset;
+ int count;
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
qemu_co_mutex_lock(&s->lock);
- offset = block_status(s, sector_num, nb_sectors, pnum);
+ offset = block_status(s, offset >> BDRV_SECTOR_BITS,
+ bytes >> BDRV_SECTOR_BITS, &count);
qemu_co_mutex_unlock(&s->lock);
+ *pnum = count * BDRV_SECTOR_SIZE;
if (offset < 0) {
return 0;
}
+ *map = offset * BDRV_SECTOR_SIZE;
*file = bs->file->bs;
- return (offset << BDRV_SECTOR_BITS) |
- BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
}
static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
@@ -467,7 +475,9 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
}
-static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn parallels_co_create_opts(const char *filename,
+ QemuOpts *opts,
+ Error **errp)
{
int64_t total_size, cl_size;
uint8_t tmp[BDRV_SECTOR_SIZE];
@@ -782,13 +792,13 @@ static BlockDriver bdrv_parallels = {
.bdrv_open = parallels_open,
.bdrv_close = parallels_close,
.bdrv_child_perm = bdrv_format_default_perms,
- .bdrv_co_get_block_status = parallels_co_get_block_status,
+ .bdrv_co_block_status = parallels_co_block_status,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_co_flush_to_os = parallels_co_flush_to_os,
.bdrv_co_readv = parallels_co_readv,
.bdrv_co_writev = parallels_co_writev,
.supports_backing = true,
- .bdrv_create = parallels_create,
+ .bdrv_co_create_opts = parallels_co_create_opts,
.bdrv_check = parallels_check,
.create_opts = &parallels_create_opts,
};
diff --git a/block/qcow.c b/block/qcow.c
index 8631155ac8..47a18d9a3a 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -524,23 +524,28 @@ static int get_cluster_offset(BlockDriverState *bs,
return 1;
}
-static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
+static int coroutine_fn qcow_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset, int64_t bytes,
+ int64_t *pnum, int64_t *map,
+ BlockDriverState **file)
{
BDRVQcowState *s = bs->opaque;
- int index_in_cluster, n, ret;
+ int index_in_cluster, ret;
+ int64_t n;
uint64_t cluster_offset;
qemu_co_mutex_lock(&s->lock);
- ret = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0, &cluster_offset);
+ ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
return ret;
}
- index_in_cluster = sector_num & (s->cluster_sectors - 1);
- n = s->cluster_sectors - index_in_cluster;
- if (n > nb_sectors)
- n = nb_sectors;
+ index_in_cluster = offset & (s->cluster_size - 1);
+ n = s->cluster_size - index_in_cluster;
+ if (n > bytes) {
+ n = bytes;
+ }
*pnum = n;
if (!cluster_offset) {
return 0;
@@ -548,9 +553,9 @@ static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypto) {
return BDRV_BLOCK_DATA;
}
- cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
+ *map = cluster_offset | index_in_cluster;
*file = bs->file->bs;
- return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | cluster_offset;
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
}
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
@@ -805,7 +810,8 @@ static void qcow_close(BlockDriverState *bs)
error_free(s->migration_blocker);
}
-static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn qcow_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
int header_size, backing_filename_len, l1_size, shift, i;
QCowHeader header;
@@ -1122,13 +1128,13 @@ static BlockDriver bdrv_qcow = {
.bdrv_close = qcow_close,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_reopen_prepare = qcow_reopen_prepare,
- .bdrv_create = qcow_create,
+ .bdrv_co_create_opts = qcow_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.supports_backing = true,
.bdrv_co_readv = qcow_co_readv,
.bdrv_co_writev = qcow_co_writev,
- .bdrv_co_get_block_status = qcow_co_get_block_status,
+ .bdrv_co_block_status = qcow_co_block_status,
.bdrv_make_empty = qcow_make_empty,
.bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed,
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index 4f6fd863ea..5127276f90 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -413,8 +413,8 @@ static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry)
static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size)
{
- return align_offset(sizeof(Qcow2BitmapDirEntry) +
- name_size + extra_data_size, 8);
+ int size = sizeof(Qcow2BitmapDirEntry) + name_size + extra_data_size;
+ return ROUND_UP(size, 8);
}
static inline int dir_entry_size(Qcow2BitmapDirEntry *entry)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index e406b0f3b9..98908c4264 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -126,11 +126,11 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
new_l1_table = qemu_try_blockalign(bs->file->bs,
- align_offset(new_l1_size2, 512));
+ ROUND_UP(new_l1_size2, 512));
if (new_l1_table == NULL) {
return -ENOMEM;
}
- memset(new_l1_table, 0, align_offset(new_l1_size2, 512));
+ memset(new_l1_table, 0, ROUND_UP(new_l1_size2, 512));
if (s->l1_size) {
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index d46b69d7f3..126cca3276 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1204,7 +1204,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
* l1_table_offset when it is the current s->l1_table_offset! Be careful
* when changing this! */
if (l1_table_offset != s->l1_table_offset) {
- l1_table = g_try_malloc0(align_offset(l1_size2, 512));
+ l1_table = g_try_malloc0(ROUND_UP(l1_size2, 512));
if (l1_size2 && l1_table == NULL) {
ret = -ENOMEM;
goto fail;
@@ -2553,7 +2553,7 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
}
/* align range to test to cluster boundaries */
- size = align_offset(offset_into_cluster(s, offset) + size, s->cluster_size);
+ size = ROUND_UP(offset_into_cluster(s, offset) + size, s->cluster_size);
offset = start_of_cluster(s, offset);
if ((chk & QCOW2_OL_ACTIVE_L1) && s->l1_size) {
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 44243e0e95..cee25f582b 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -66,7 +66,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
for(i = 0; i < s->nb_snapshots; i++) {
/* Read statically sized part of the snapshot header */
- offset = align_offset(offset, 8);
+ offset = ROUND_UP(offset, 8);
ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
if (ret < 0) {
goto fail;
@@ -155,7 +155,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
offset = 0;
for(i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
- offset = align_offset(offset, 8);
+ offset = ROUND_UP(offset, 8);
offset += sizeof(h);
offset += sizeof(extra);
offset += strlen(sn->id_str);
@@ -215,7 +215,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
assert(id_str_size <= UINT16_MAX && name_size <= UINT16_MAX);
h.id_str_size = cpu_to_be16(id_str_size);
h.name_size = cpu_to_be16(name_size);
- offset = align_offset(offset, 8);
+ offset = ROUND_UP(offset, 8);
ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h));
if (ret < 0) {
@@ -441,7 +441,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
/* The VM state isn't needed any more in the active L1 table; in fact, it
* hurts by causing expensive COW for the next snapshot. */
qcow2_cluster_discard(bs, qcow2_vm_state_offset(s),
- align_offset(sn->vm_state_size, s->cluster_size),
+ ROUND_UP(sn->vm_state_size, s->cluster_size),
QCOW2_DISCARD_NEVER, false);
#ifdef DEBUG_ALLOC
@@ -710,7 +710,7 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
}
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
new_l1_table = qemu_try_blockalign(bs->file->bs,
- align_offset(new_l1_bytes, 512));
+ ROUND_UP(new_l1_bytes, 512));
if (new_l1_table == NULL) {
return -ENOMEM;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index 3dd098b74f..071dc4d608 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1377,7 +1377,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
if (s->l1_size > 0) {
s->l1_table = qemu_try_blockalign(bs->file->bs,
- align_offset(s->l1_size * sizeof(uint64_t), 512));
+ ROUND_UP(s->l1_size * sizeof(uint64_t), 512));
if (s->l1_table == NULL) {
error_setg(errp, "Could not allocate L1 table");
ret = -ENOMEM;
@@ -1668,32 +1668,34 @@ static void qcow2_join_options(QDict *options, QDict *old_options)
}
}
-static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
+static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset, int64_t count,
+ int64_t *pnum, int64_t *map,
+ BlockDriverState **file)
{
BDRVQcow2State *s = bs->opaque;
uint64_t cluster_offset;
int index_in_cluster, ret;
unsigned int bytes;
- int64_t status = 0;
+ int status = 0;
- bytes = MIN(INT_MAX, nb_sectors * BDRV_SECTOR_SIZE);
+ bytes = MIN(INT_MAX, count);
qemu_co_mutex_lock(&s->lock);
- ret = qcow2_get_cluster_offset(bs, sector_num << BDRV_SECTOR_BITS, &bytes,
- &cluster_offset);
+ ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
return ret;
}
- *pnum = bytes >> BDRV_SECTOR_BITS;
+ *pnum = bytes;
if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED &&
!s->crypto) {
- index_in_cluster = sector_num & (s->cluster_sectors - 1);
- cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
+ index_in_cluster = offset & (s->cluster_size - 1);
+ *map = cluster_offset | index_in_cluster;
*file = bs->file->bs;
- status |= BDRV_BLOCK_OFFSET_VALID | cluster_offset;
+ status |= BDRV_BLOCK_OFFSET_VALID;
}
if (ret == QCOW2_CLUSTER_ZERO_PLAIN || ret == QCOW2_CLUSTER_ZERO_ALLOC) {
status |= BDRV_BLOCK_ZERO;
@@ -2638,19 +2640,19 @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size,
{
int64_t meta_size = 0;
uint64_t nl1e, nl2e;
- int64_t aligned_total_size = align_offset(total_size, cluster_size);
+ int64_t aligned_total_size = ROUND_UP(total_size, cluster_size);
/* header: 1 cluster */
meta_size += cluster_size;
/* total size of L2 tables */
nl2e = aligned_total_size / cluster_size;
- nl2e = align_offset(nl2e, cluster_size / sizeof(uint64_t));
+ nl2e = ROUND_UP(nl2e, cluster_size / sizeof(uint64_t));
meta_size += nl2e * sizeof(uint64_t);
/* total size of L1 tables */
nl1e = nl2e * sizeof(uint64_t) / cluster_size;
- nl1e = align_offset(nl1e, cluster_size / sizeof(uint64_t));
+ nl1e = ROUND_UP(nl1e, cluster_size / sizeof(uint64_t));
meta_size += nl1e * sizeof(uint64_t);
/* total size of refcount table and blocks */
@@ -2721,11 +2723,12 @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
return refcount_bits;
}
-static int qcow2_create2(const char *filename, int64_t total_size,
- const char *backing_file, const char *backing_format,
- int flags, size_t cluster_size, PreallocMode prealloc,
- QemuOpts *opts, int version, int refcount_order,
- const char *encryptfmt, Error **errp)
+static int coroutine_fn
+qcow2_co_create2(const char *filename, int64_t total_size,
+ const char *backing_file, const char *backing_format,
+ int flags, size_t cluster_size, PreallocMode prealloc,
+ QemuOpts *opts, int version, int refcount_order,
+ const char *encryptfmt, Error **errp)
{
QDict *options;
@@ -2912,7 +2915,8 @@ out:
return ret;
}
-static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
char *backing_file = NULL;
char *backing_fmt = NULL;
@@ -2993,9 +2997,9 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
refcount_order = ctz32(refcount_bits);
- ret = qcow2_create2(filename, size, backing_file, backing_fmt, flags,
- cluster_size, prealloc, opts, version, refcount_order,
- encryptfmt, &local_err);
+ ret = qcow2_co_create2(filename, size, backing_file, backing_fmt, flags,
+ cluster_size, prealloc, opts, version, refcount_order,
+ encryptfmt, &local_err);
error_propagate(errp, local_err);
finish:
@@ -3704,8 +3708,8 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
has_backing_file = !!optstr;
g_free(optstr);
- virtual_size = align_offset(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
- cluster_size);
+ virtual_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
+ virtual_size = ROUND_UP(virtual_size, cluster_size);
/* Check that virtual disk size is valid */
l2_tables = DIV_ROUND_UP(virtual_size / cluster_size,
@@ -3725,7 +3729,7 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
goto err;
}
- virtual_size = align_offset(ssize, cluster_size);
+ virtual_size = ROUND_UP(ssize, cluster_size);
if (has_backing_file) {
/* We don't how much of the backing chain is shared by the input
@@ -4348,9 +4352,9 @@ BlockDriver bdrv_qcow2 = {
.bdrv_reopen_abort = qcow2_reopen_abort,
.bdrv_join_options = qcow2_join_options,
.bdrv_child_perm = bdrv_format_default_perms,
- .bdrv_create = qcow2_create,
+ .bdrv_co_create_opts = qcow2_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_co_get_block_status = qcow2_co_get_block_status,
+ .bdrv_co_block_status = qcow2_co_block_status,
.bdrv_co_preadv = qcow2_co_preadv,
.bdrv_co_pwritev = qcow2_co_pwritev,
diff --git a/block/qcow2.h b/block/qcow2.h
index 883802241f..1a84cc77b0 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -480,12 +480,6 @@ static inline int offset_to_l2_slice_index(BDRVQcow2State *s, int64_t offset)
return (offset >> s->cluster_bits) & (s->l2_slice_size - 1);
}
-static inline int64_t align_offset(int64_t offset, int n)
-{
- offset = (offset + n - 1) & ~(n - 1);
- return offset;
-}
-
static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
{
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
diff --git a/block/qed.c b/block/qed.c
index c6ff3ab015..72cf2f58ab 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -638,7 +638,9 @@ out:
return ret;
}
-static int bdrv_qed_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
+ QemuOpts *opts,
+ Error **errp)
{
uint64_t image_size = 0;
uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE;
@@ -688,74 +690,46 @@ finish:
return ret;
}
-typedef struct {
- BlockDriverState *bs;
- Coroutine *co;
- uint64_t pos;
- int64_t status;
- int *pnum;
- BlockDriverState **file;
-} QEDIsAllocatedCB;
-
-/* Called with table_lock held. */
-static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t len)
+static int coroutine_fn bdrv_qed_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t pos, int64_t bytes,
+ int64_t *pnum, int64_t *map,
+ BlockDriverState **file)
{
- QEDIsAllocatedCB *cb = opaque;
- BDRVQEDState *s = cb->bs->opaque;
- *cb->pnum = len / BDRV_SECTOR_SIZE;
+ BDRVQEDState *s = bs->opaque;
+ size_t len = MIN(bytes, SIZE_MAX);
+ int status;
+ QEDRequest request = { .l2_table = NULL };
+ uint64_t offset;
+ int ret;
+
+ qemu_co_mutex_lock(&s->table_lock);
+ ret = qed_find_cluster(s, &request, pos, &len, &offset);
+
+ *pnum = len;
switch (ret) {
case QED_CLUSTER_FOUND:
- offset |= qed_offset_into_cluster(s, cb->pos);
- cb->status = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset;
- *cb->file = cb->bs->file->bs;
+ *map = offset | qed_offset_into_cluster(s, pos);
+ status = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
+ *file = bs->file->bs;
break;
case QED_CLUSTER_ZERO:
- cb->status = BDRV_BLOCK_ZERO;
+ status = BDRV_BLOCK_ZERO;
break;
case QED_CLUSTER_L2:
case QED_CLUSTER_L1:
- cb->status = 0;
+ status = 0;
break;
default:
assert(ret < 0);
- cb->status = ret;
+ status = ret;
break;
}
- if (cb->co) {
- aio_co_wake(cb->co);
- }
-}
-
-static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors, int *pnum,
- BlockDriverState **file)
-{
- BDRVQEDState *s = bs->opaque;
- size_t len = (size_t)nb_sectors * BDRV_SECTOR_SIZE;
- QEDIsAllocatedCB cb = {
- .bs = bs,
- .pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE,
- .status = BDRV_BLOCK_OFFSET_MASK,
- .pnum = pnum,
- .file = file,
- };
- QEDRequest request = { .l2_table = NULL };
- uint64_t offset;
- int ret;
-
- qemu_co_mutex_lock(&s->table_lock);
- ret = qed_find_cluster(s, &request, cb.pos, &len, &offset);
- qed_is_allocated_cb(&cb, ret, offset, len);
-
- /* The callback was invoked immediately */
- assert(cb.status != BDRV_BLOCK_OFFSET_MASK);
-
qed_unref_l2_cache_entry(request.l2_table);
qemu_co_mutex_unlock(&s->table_lock);
- return cb.status;
+ return status;
}
static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
@@ -1592,9 +1566,9 @@ static BlockDriver bdrv_qed = {
.bdrv_close = bdrv_qed_close,
.bdrv_reopen_prepare = bdrv_qed_reopen_prepare,
.bdrv_child_perm = bdrv_format_default_perms,
- .bdrv_create = bdrv_qed_create,
+ .bdrv_co_create_opts = bdrv_qed_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_co_get_block_status = bdrv_qed_co_get_block_status,
+ .bdrv_co_block_status = bdrv_qed_co_block_status,
.bdrv_co_readv = bdrv_qed_co_readv,
.bdrv_co_writev = bdrv_qed_co_writev,
.bdrv_co_pwrite_zeroes = bdrv_qed_co_pwrite_zeroes,
diff --git a/block/raw-format.c b/block/raw-format.c
index ab552c0954..a378547c99 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -250,17 +250,17 @@ fail:
return ret;
}
-static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors, int *pnum,
+static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
+ bool want_zero, int64_t offset,
+ int64_t bytes, int64_t *pnum,
+ int64_t *map,
BlockDriverState **file)
{
BDRVRawState *s = bs->opaque;
- *pnum = nb_sectors;
+ *pnum = bytes;
*file = bs->file->bs;
- sector_num += s->offset / BDRV_SECTOR_SIZE;
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
- (sector_num << BDRV_SECTOR_BITS);
+ *map = offset + s->offset;
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID;
}
static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
@@ -396,7 +396,8 @@ static int raw_has_zero_init(BlockDriverState *bs)
return bdrv_has_zero_init(bs->file->bs);
}
-static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
return bdrv_create_file(filename, opts, errp);
}
@@ -491,12 +492,12 @@ BlockDriver bdrv_raw = {
.bdrv_open = &raw_open,
.bdrv_close = &raw_close,
.bdrv_child_perm = bdrv_filter_default_perms,
- .bdrv_create = &raw_create,
+ .bdrv_co_create_opts = &raw_co_create_opts,
.bdrv_co_preadv = &raw_co_preadv,
.bdrv_co_pwritev = &raw_co_pwritev,
.bdrv_co_pwrite_zeroes = &raw_co_pwrite_zeroes,
.bdrv_co_pdiscard = &raw_co_pdiscard,
- .bdrv_co_get_block_status = &raw_co_get_block_status,
+ .bdrv_co_block_status = &raw_co_block_status,
.bdrv_truncate = &raw_truncate,
.bdrv_getlength = &raw_getlength,
.has_variable_length = true,
diff --git a/block/rbd.c b/block/rbd.c
index 8474b0ba11..c7dd32e213 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -351,7 +351,9 @@ static QemuOptsList runtime_opts = {
},
};
-static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
+ QemuOpts *opts,
+ Error **errp)
{
Error *local_err = NULL;
int64_t bytes = 0;
@@ -1132,7 +1134,7 @@ static BlockDriver bdrv_rbd = {
.bdrv_file_open = qemu_rbd_open,
.bdrv_close = qemu_rbd_close,
.bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
- .bdrv_create = qemu_rbd_create,
+ .bdrv_co_create_opts = qemu_rbd_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_get_info = qemu_rbd_getinfo,
.create_opts = &qemu_rbd_create_opts,
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 215223053b..d8c10b7cac 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1959,8 +1959,8 @@ static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
return 0;
}
-static int sd_create(const char *filename, QemuOpts *opts,
- Error **errp)
+static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
Error *err = NULL;
int ret = 0;
@@ -3004,19 +3004,19 @@ static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset,
return acb.ret;
}
-static coroutine_fn int64_t
-sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
- int *pnum, BlockDriverState **file)
+static coroutine_fn int
+sd_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset,
+ int64_t bytes, int64_t *pnum, int64_t *map,
+ BlockDriverState **file)
{
BDRVSheepdogState *s = bs->opaque;
SheepdogInode *inode = &s->inode;
uint32_t object_size = (UINT32_C(1) << inode->block_size_shift);
- uint64_t offset = sector_num * BDRV_SECTOR_SIZE;
unsigned long start = offset / object_size,
- end = DIV_ROUND_UP((sector_num + nb_sectors) *
- BDRV_SECTOR_SIZE, object_size);
+ end = DIV_ROUND_UP(offset + bytes, object_size);
unsigned long idx;
- int64_t ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset;
+ *map = offset;
+ int ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
for (idx = start; idx < end; idx++) {
if (inode->data_vdi_id[idx] == 0) {
@@ -3033,9 +3033,9 @@ sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
}
}
- *pnum = (idx - start) * object_size / BDRV_SECTOR_SIZE;
- if (*pnum > nb_sectors) {
- *pnum = nb_sectors;
+ *pnum = (idx - start) * object_size;
+ if (*pnum > bytes) {
+ *pnum = bytes;
}
if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID) {
*file = bs;
@@ -3103,7 +3103,7 @@ static BlockDriver bdrv_sheepdog = {
.bdrv_reopen_commit = sd_reopen_commit,
.bdrv_reopen_abort = sd_reopen_abort,
.bdrv_close = sd_close,
- .bdrv_create = sd_create,
+ .bdrv_co_create_opts = sd_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_getlength = sd_getlength,
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
@@ -3113,7 +3113,7 @@ static BlockDriver bdrv_sheepdog = {
.bdrv_co_writev = sd_co_writev,
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
.bdrv_co_pdiscard = sd_co_pdiscard,
- .bdrv_co_get_block_status = sd_co_get_block_status,
+ .bdrv_co_block_status = sd_co_block_status,
.bdrv_snapshot_create = sd_snapshot_create,
.bdrv_snapshot_goto = sd_snapshot_goto,
@@ -3139,7 +3139,7 @@ static BlockDriver bdrv_sheepdog_tcp = {
.bdrv_reopen_commit = sd_reopen_commit,
.bdrv_reopen_abort = sd_reopen_abort,
.bdrv_close = sd_close,
- .bdrv_create = sd_create,
+ .bdrv_co_create_opts = sd_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_getlength = sd_getlength,
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
@@ -3149,7 +3149,7 @@ static BlockDriver bdrv_sheepdog_tcp = {
.bdrv_co_writev = sd_co_writev,
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
.bdrv_co_pdiscard = sd_co_pdiscard,
- .bdrv_co_get_block_status = sd_co_get_block_status,
+ .bdrv_co_block_status = sd_co_block_status,
.bdrv_snapshot_create = sd_snapshot_create,
.bdrv_snapshot_goto = sd_snapshot_goto,
@@ -3175,7 +3175,7 @@ static BlockDriver bdrv_sheepdog_unix = {
.bdrv_reopen_commit = sd_reopen_commit,
.bdrv_reopen_abort = sd_reopen_abort,
.bdrv_close = sd_close,
- .bdrv_create = sd_create,
+ .bdrv_co_create_opts = sd_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_getlength = sd_getlength,
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
@@ -3185,7 +3185,7 @@ static BlockDriver bdrv_sheepdog_unix = {
.bdrv_co_writev = sd_co_writev,
.bdrv_co_flush_to_disk = sd_co_flush_to_disk,
.bdrv_co_pdiscard = sd_co_pdiscard,
- .bdrv_co_get_block_status = sd_co_get_block_status,
+ .bdrv_co_block_status = sd_co_block_status,
.bdrv_snapshot_create = sd_snapshot_create,
.bdrv_snapshot_goto = sd_snapshot_goto,
diff --git a/block/ssh.c b/block/ssh.c
index b11d4c5e86..ff9929497d 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -803,6 +803,33 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
return ret;
}
+/* Note: This is a blocking operation */
+static int ssh_grow_file(BDRVSSHState *s, int64_t offset, Error **errp)
+{
+ ssize_t ret;
+ char c[1] = { '\0' };
+ int was_blocking = libssh2_session_get_blocking(s->session);
+
+ /* offset must be strictly greater than the current size so we do
+ * not overwrite anything */
+ assert(offset > 0 && offset > s->attrs.filesize);
+
+ libssh2_session_set_blocking(s->session, 1);
+
+ libssh2_sftp_seek64(s->sftp_handle, offset - 1);
+ ret = libssh2_sftp_write(s->sftp_handle, c, 1);
+
+ libssh2_session_set_blocking(s->session, was_blocking);
+
+ if (ret < 0) {
+ sftp_error_setg(errp, s, "Failed to grow file");
+ return -EIO;
+ }
+
+ s->attrs.filesize = offset;
+ return 0;
+}
+
static QemuOptsList ssh_create_opts = {
.name = "ssh-create-opts",
.head = QTAILQ_HEAD_INITIALIZER(ssh_create_opts.head),
@@ -816,14 +843,13 @@ static QemuOptsList ssh_create_opts = {
}
};
-static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
int r, ret;
int64_t total_size = 0;
QDict *uri_options = NULL;
BDRVSSHState s;
- ssize_t r2;
- char c[1] = { '\0' };
ssh_state_init(&s);
@@ -849,14 +875,10 @@ static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
}
if (total_size > 0) {
- libssh2_sftp_seek64(s.sftp_handle, total_size-1);
- r2 = libssh2_sftp_write(s.sftp_handle, c, 1);
- if (r2 < 0) {
- sftp_error_setg(errp, &s, "truncate failed");
- ret = -EINVAL;
+ ret = ssh_grow_file(&s, total_size, errp);
+ if (ret < 0) {
goto out;
}
- s.attrs.filesize = total_size;
}
ret = 0;
@@ -1198,18 +1220,42 @@ static int64_t ssh_getlength(BlockDriverState *bs)
return length;
}
+static int ssh_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
+{
+ BDRVSSHState *s = bs->opaque;
+
+ if (prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Unsupported preallocation mode '%s'",
+ PreallocMode_str(prealloc));
+ return -ENOTSUP;
+ }
+
+ if (offset < s->attrs.filesize) {
+ error_setg(errp, "ssh driver does not support shrinking files");
+ return -ENOTSUP;
+ }
+
+ if (offset == s->attrs.filesize) {
+ return 0;
+ }
+
+ return ssh_grow_file(s, offset, errp);
+}
+
static BlockDriver bdrv_ssh = {
.format_name = "ssh",
.protocol_name = "ssh",
.instance_size = sizeof(BDRVSSHState),
.bdrv_parse_filename = ssh_parse_filename,
.bdrv_file_open = ssh_file_open,
- .bdrv_create = ssh_create,
+ .bdrv_co_create_opts = ssh_co_create_opts,
.bdrv_close = ssh_close,
.bdrv_has_zero_init = ssh_has_zero_init,
.bdrv_co_readv = ssh_co_readv,
.bdrv_co_writev = ssh_co_writev,
.bdrv_getlength = ssh_getlength,
+ .bdrv_truncate = ssh_truncate,
.bdrv_co_flush_to_disk = ssh_co_flush,
.create_opts = &ssh_create_opts,
};
diff --git a/block/throttle.c b/block/throttle.c
index 495f88c752..5f4d43d0fc 100644
--- a/block/throttle.c
+++ b/block/throttle.c
@@ -240,7 +240,7 @@ static BlockDriver bdrv_throttle = {
.bdrv_reopen_prepare = throttle_reopen_prepare,
.bdrv_reopen_commit = throttle_reopen_commit,
.bdrv_reopen_abort = throttle_reopen_abort,
- .bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,
+ .bdrv_co_block_status = bdrv_co_block_status_from_file,
.bdrv_co_drain_begin = throttle_co_drain_begin,
.bdrv_co_drain_end = throttle_co_drain_end,
diff --git a/block/vdi.c b/block/vdi.c
index fc1c614cb1..68592cc58d 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -87,12 +87,18 @@
#define DEFAULT_CLUSTER_SIZE (1 * MiB)
#if defined(CONFIG_VDI_DEBUG)
-#define logout(fmt, ...) \
- fprintf(stderr, "vdi\t%-24s" fmt, __func__, ##__VA_ARGS__)
+#define VDI_DEBUG 1
#else
-#define logout(fmt, ...) ((void)0)
+#define VDI_DEBUG 0
#endif
+#define logout(fmt, ...) \
+ do { \
+ if (VDI_DEBUG) { \
+ fprintf(stderr, "vdi\t%-24s" fmt, __func__, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
/* Image signature. */
#define VDI_SIGNATURE 0xbeda107f
@@ -166,8 +172,6 @@ typedef struct {
uint32_t *bmap;
/* Size of block (bytes). */
uint32_t block_size;
- /* Size of block (sectors). */
- uint32_t block_sectors;
/* First sector of block map. */
uint32_t bmap_sector;
/* VDI header (converted to host endianness). */
@@ -457,7 +461,6 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
bs->total_sectors = header.disk_size / SECTOR_SIZE;
s->block_size = header.block_size;
- s->block_sectors = header.block_size / SECTOR_SIZE;
s->bmap_sector = header.offset_bmap / SECTOR_SIZE;
s->header = header;
@@ -503,33 +506,29 @@ static int vdi_reopen_prepare(BDRVReopenState *state,
return 0;
}
-static int64_t coroutine_fn vdi_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
+static int coroutine_fn vdi_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset, int64_t bytes,
+ int64_t *pnum, int64_t *map,
+ BlockDriverState **file)
{
- /* TODO: Check for too large sector_num (in bdrv_is_allocated or here). */
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
- size_t bmap_index = sector_num / s->block_sectors;
- size_t sector_in_block = sector_num % s->block_sectors;
- int n_sectors = s->block_sectors - sector_in_block;
+ size_t bmap_index = offset / s->block_size;
+ size_t index_in_block = offset % s->block_size;
uint32_t bmap_entry = le32_to_cpu(s->bmap[bmap_index]);
- uint64_t offset;
int result;
- logout("%p, %" PRId64 ", %d, %p\n", bs, sector_num, nb_sectors, pnum);
- if (n_sectors > nb_sectors) {
- n_sectors = nb_sectors;
- }
- *pnum = n_sectors;
+ logout("%p, %" PRId64 ", %" PRId64 ", %p\n", bs, offset, bytes, pnum);
+ *pnum = MIN(s->block_size - index_in_block, bytes);
result = VDI_IS_ALLOCATED(bmap_entry);
if (!result) {
return 0;
}
- offset = s->header.offset_data +
- (uint64_t)bmap_entry * s->block_size +
- sector_in_block * SECTOR_SIZE;
+ *map = s->header.offset_data + (uint64_t)bmap_entry * s->block_size +
+ index_in_block;
*file = bs->file->bs;
- return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset;
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
}
static int coroutine_fn
@@ -717,7 +716,8 @@ nonallocating_write:
return ret;
}
-static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
int ret = 0;
uint64_t bytes = 0;
@@ -895,9 +895,9 @@ static BlockDriver bdrv_vdi = {
.bdrv_close = vdi_close,
.bdrv_reopen_prepare = vdi_reopen_prepare,
.bdrv_child_perm = bdrv_format_default_perms,
- .bdrv_create = vdi_create,
+ .bdrv_co_create_opts = vdi_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_co_get_block_status = vdi_co_get_block_status,
+ .bdrv_co_block_status = vdi_co_block_status,
.bdrv_make_empty = vdi_make_empty,
.bdrv_co_preadv = vdi_co_preadv,
diff --git a/block/vhdx.c b/block/vhdx.c
index c449c5dcfd..3fbff5048b 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -1792,7 +1792,8 @@ exit:
* .---- ~ ----------- ~ ------------ ~ ---------------- ~ -----------.
* 1MB
*/
-static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn vhdx_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
int ret = 0;
uint64_t image_size = (uint64_t) 2 * GiB;
@@ -2003,7 +2004,7 @@ static BlockDriver bdrv_vhdx = {
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_co_readv = vhdx_co_readv,
.bdrv_co_writev = vhdx_co_writev,
- .bdrv_create = vhdx_create,
+ .bdrv_co_create_opts = vhdx_co_create_opts,
.bdrv_get_info = vhdx_get_info,
.bdrv_check = vhdx_check,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
diff --git a/block/vmdk.c b/block/vmdk.c
index ef15ddbfd3..67342ed69b 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1304,33 +1304,27 @@ static inline uint64_t vmdk_find_offset_in_cluster(VmdkExtent *extent,
return extent_relative_offset % cluster_size;
}
-static inline uint64_t vmdk_find_index_in_cluster(VmdkExtent *extent,
- int64_t sector_num)
-{
- uint64_t offset;
- offset = vmdk_find_offset_in_cluster(extent, sector_num * BDRV_SECTOR_SIZE);
- return offset / BDRV_SECTOR_SIZE;
-}
-
-static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
+static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset, int64_t bytes,
+ int64_t *pnum, int64_t *map,
+ BlockDriverState **file)
{
BDRVVmdkState *s = bs->opaque;
int64_t index_in_cluster, n, ret;
- uint64_t offset;
+ uint64_t cluster_offset;
VmdkExtent *extent;
- extent = find_extent(s, sector_num, NULL);
+ extent = find_extent(s, offset >> BDRV_SECTOR_BITS, NULL);
if (!extent) {
- return 0;
+ return -EIO;
}
qemu_co_mutex_lock(&s->lock);
- ret = get_cluster_offset(bs, extent, NULL,
- sector_num * 512, false, &offset,
+ ret = get_cluster_offset(bs, extent, NULL, offset, false, &cluster_offset,
0, 0);
qemu_co_mutex_unlock(&s->lock);
- index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num);
+ index_in_cluster = vmdk_find_offset_in_cluster(extent, offset);
switch (ret) {
case VMDK_ERROR:
ret = -EIO;
@@ -1345,18 +1339,14 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
ret = BDRV_BLOCK_DATA;
if (!extent->compressed) {
ret |= BDRV_BLOCK_OFFSET_VALID;
- ret |= (offset + (index_in_cluster << BDRV_SECTOR_BITS))
- & BDRV_BLOCK_OFFSET_MASK;
+ *map = cluster_offset + index_in_cluster;
}
*file = extent->file->bs;
break;
}
- n = extent->cluster_sectors - index_in_cluster;
- if (n > nb_sectors) {
- n = nb_sectors;
- }
- *pnum = n;
+ n = extent->cluster_sectors * BDRV_SECTOR_SIZE - index_in_cluster;
+ *pnum = MIN(n, bytes);
return ret;
}
@@ -1892,7 +1882,8 @@ static int filename_decompose(const char *filename, char *path, char *prefix,
return VMDK_OK;
}
-static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
int idx = 0;
BlockBackend *new_blk = NULL;
@@ -2408,9 +2399,9 @@ static BlockDriver bdrv_vmdk = {
.bdrv_co_pwritev_compressed = vmdk_co_pwritev_compressed,
.bdrv_co_pwrite_zeroes = vmdk_co_pwrite_zeroes,
.bdrv_close = vmdk_close,
- .bdrv_create = vmdk_create,
+ .bdrv_co_create_opts = vmdk_co_create_opts,
.bdrv_co_flush_to_disk = vmdk_co_flush,
- .bdrv_co_get_block_status = vmdk_co_get_block_status,
+ .bdrv_co_block_status = vmdk_co_block_status,
.bdrv_get_allocated_file_size = vmdk_get_allocated_file_size,
.bdrv_has_zero_init = vmdk_has_zero_init,
.bdrv_get_specific_info = vmdk_get_specific_info,
diff --git a/block/vpc.c b/block/vpc.c
index cfa5144e86..b2e2b9ebd4 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -706,53 +706,54 @@ fail:
return ret;
}
-static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
+static int coroutine_fn vpc_co_block_status(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset, int64_t bytes,
+ int64_t *pnum, int64_t *map,
+ BlockDriverState **file)
{
BDRVVPCState *s = bs->opaque;
VHDFooter *footer = (VHDFooter*) s->footer_buf;
- int64_t start, offset;
+ int64_t image_offset;
bool allocated;
- int64_t ret;
- int n;
+ int ret;
+ int64_t n;
if (be32_to_cpu(footer->type) == VHD_FIXED) {
- *pnum = nb_sectors;
+ *pnum = bytes;
+ *map = offset;
*file = bs->file->bs;
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
- (sector_num << BDRV_SECTOR_BITS);
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID;
}
qemu_co_mutex_lock(&s->lock);
- offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false, NULL);
- start = offset;
- allocated = (offset != -1);
+ image_offset = get_image_offset(bs, offset, false, NULL);
+ allocated = (image_offset != -1);
*pnum = 0;
ret = 0;
do {
/* All sectors in a block are contiguous (without using the bitmap) */
- n = ROUND_UP(sector_num + 1, s->block_size / BDRV_SECTOR_SIZE)
- - sector_num;
- n = MIN(n, nb_sectors);
+ n = ROUND_UP(offset + 1, s->block_size) - offset;
+ n = MIN(n, bytes);
*pnum += n;
- sector_num += n;
- nb_sectors -= n;
+ offset += n;
+ bytes -= n;
/* *pnum can't be greater than one block for allocated
* sectors since there is always a bitmap in between. */
if (allocated) {
*file = bs->file->bs;
- ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
+ *map = image_offset;
+ ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
break;
}
- if (nb_sectors == 0) {
+ if (bytes == 0) {
break;
}
- offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false,
- NULL);
- } while (offset == -1);
+ image_offset = get_image_offset(bs, offset, false, NULL);
+ } while (image_offset == -1);
qemu_co_mutex_unlock(&s->lock);
return ret;
@@ -896,7 +897,8 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
return ret;
}
-static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
+static int coroutine_fn vpc_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
{
uint8_t buf[1024];
VHDFooter *footer = (VHDFooter *) buf;
@@ -1094,11 +1096,11 @@ static BlockDriver bdrv_vpc = {
.bdrv_close = vpc_close,
.bdrv_reopen_prepare = vpc_reopen_prepare,
.bdrv_child_perm = bdrv_format_default_perms,
- .bdrv_create = vpc_create,
+ .bdrv_co_create_opts = vpc_co_create_opts,
.bdrv_co_preadv = vpc_co_preadv,
.bdrv_co_pwritev = vpc_co_pwritev,
- .bdrv_co_get_block_status = vpc_co_get_block_status,
+ .bdrv_co_block_status = vpc_co_block_status,
.bdrv_get_info = vpc_get_info,
diff --git a/block/vvfat.c b/block/vvfat.c
index 7e06ebacf6..4a17a49e12 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -3088,15 +3088,13 @@ vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
return ret;
}
-static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file)
+static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs,
+ bool want_zero, int64_t offset,
+ int64_t bytes, int64_t *n,
+ int64_t *map,
+ BlockDriverState **file)
{
- *n = bs->total_sectors - sector_num;
- if (*n > nb_sectors) {
- *n = nb_sectors;
- } else if (*n < 0) {
- return 0;
- }
+ *n = bytes;
return BDRV_BLOCK_DATA;
}
@@ -3257,7 +3255,7 @@ static BlockDriver bdrv_vvfat = {
.bdrv_co_preadv = vvfat_co_preadv,
.bdrv_co_pwritev = vvfat_co_pwritev,
- .bdrv_co_get_block_status = vvfat_co_get_block_status,
+ .bdrv_co_block_status = vvfat_co_block_status,
};
static void bdrv_vvfat_init(void)
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 58e11c6f4c..a220803c01 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -592,19 +592,23 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
ret = 0;
} else {
tcp_chr_disconnect(init->chr);
- return FALSE;
+ goto end;
}
}
init->buflen -= ret;
if (init->buflen == 0) {
tcp_chr_connect(init->chr);
- return FALSE;
+ goto end;
}
memmove(init->buf, init->buf + ret, init->buflen);
- return TRUE;
+ return G_SOURCE_CONTINUE;
+
+end:
+ g_free(init);
+ return G_SOURCE_REMOVE;
}
static void tcp_chr_telnet_init(Chardev *chr)
diff --git a/configure b/configure
index 27d3f66bd5..6f3921c02a 100755
--- a/configure
+++ b/configure
@@ -2486,20 +2486,20 @@ fi
if test "$whpx" != "no" ; then
cat > $TMPC << EOF
#include <windows.h>
-#include <winhvplatform.h>
-#include <winhvemulation.h>
+#include <WinHvPlatform.h>
+#include <WinHvEmulation.h>
int main(void) {
WHV_CAPABILITY whpx_cap;
WHvGetCapability(WHvCapabilityCodeFeatures, &whpx_cap, sizeof(whpx_cap));
return 0;
}
EOF
- if compile_prog "" "-lwinhvplatform -lwinhvemulation" ; then
- libs_softmmu="$libs_softmmu -lwinhvplatform -lwinhvemulation"
+ if compile_prog "" "-lWinHvPlatform -lWinHvEmulation" ; then
+ libs_softmmu="$libs_softmmu -lWinHvPlatform -lWinHvEmulation"
whpx="yes"
else
if test "$whpx" = "yes"; then
- feature_not_found "winhvplatform" "winhvemulation is not installed"
+ feature_not_found "WinHvPlatform" "WinHvEmulation is not installed"
fi
whpx="no"
fi
@@ -5316,25 +5316,27 @@ fi
##########################################
# checks for sanitizers
-# we could use a simple skeleton for flags checks, but this also
-# detect the static linking issue of ubsan, see also:
-# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84285
-cat > $TMPC << EOF
-#include <stdint.h>
-int main(void) {
- return INT32_MIN / -1;
-}
-EOF
-
have_asan=no
have_ubsan=no
have_asan_iface_h=no
have_asan_iface_fiber=no
if test "$sanitizers" = "yes" ; then
+ write_c_skeleton
if compile_prog "$CPU_CFLAGS -Werror -fsanitize=address" ""; then
have_asan=yes
fi
+
+ # we could use a simple skeleton for flags checks, but this also
+ # detect the static linking issue of ubsan, see also:
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84285
+ cat > $TMPC << EOF
+#include <stdlib.h>
+int main(void) {
+ void *tmp = malloc(10);
+ return *(int *)(tmp + 2);
+}
+EOF
if compile_prog "$CPU_CFLAGS -Werror -fsanitize=undefined" ""; then
have_ubsan=yes
fi
@@ -5366,19 +5368,8 @@ if test "$gcov" = "yes" ; then
LDFLAGS="-fprofile-arcs -ftest-coverage $LDFLAGS"
elif test "$fortify_source" = "yes" ; then
CFLAGS="-O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS"
-elif test "$debug" = "yes"; then
- if compile_prog "-Og" ""; then
- CFLAGS="-Og $CFLAGS"
- elif compile_prog "-O1" ""; then
- CFLAGS="-O1 $CFLAGS"
- fi
- # Workaround GCC false-positive Wuninitialized bugs with Og or O1:
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=24639
- if cc_has_warning_flag "-Wno-maybe-uninitialized"; then
- CFLAGS="-Wno-maybe-uninitialized $CFLAGS"
- fi
-else
- CFLAGS="-O2 $CFLAGS"
+elif test "$debug" = "no"; then
+ CFLAGS="-O2 $CFLAGS"
fi
if test "$have_asan" = "yes"; then
diff --git a/cpus.c b/cpus.c
index 4f5f88edba..9bcff7d63c 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1383,11 +1383,9 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
qemu_mutex_lock_iothread();
qemu_thread_get_self(cpu->thread);
- CPU_FOREACH(cpu) {
- cpu->thread_id = qemu_get_thread_id();
- cpu->created = true;
- cpu->can_do_io = 1;
- }
+ cpu->thread_id = qemu_get_thread_id();
+ cpu->created = true;
+ cpu->can_do_io = 1;
qemu_cond_signal(&qemu_cpu_cond);
/* wait for initial kick-off after machine start */
@@ -1856,13 +1854,13 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)
#ifdef _WIN32
cpu->hThread = qemu_thread_get_handle(cpu->thread);
#endif
- while (!cpu->created) {
- qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
- }
} else {
/* For non-MTTCG cases we share the thread */
cpu->thread = single_tcg_cpu_thread;
cpu->halt_cond = single_tcg_halt_cond;
+ cpu->thread_id = first_cpu->thread_id;
+ cpu->can_do_io = 1;
+ cpu->created = true;
}
}
@@ -1881,9 +1879,6 @@ static void qemu_hax_start_vcpu(CPUState *cpu)
#ifdef _WIN32
cpu->hThread = qemu_thread_get_handle(cpu->thread);
#endif
- while (!cpu->created) {
- qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
- }
}
static void qemu_kvm_start_vcpu(CPUState *cpu)
@@ -1897,9 +1892,6 @@ static void qemu_kvm_start_vcpu(CPUState *cpu)
cpu->cpu_index);
qemu_thread_create(cpu->thread, thread_name, qemu_kvm_cpu_thread_fn,
cpu, QEMU_THREAD_JOINABLE);
- while (!cpu->created) {
- qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
- }
}
static void qemu_hvf_start_vcpu(CPUState *cpu)
@@ -1918,9 +1910,6 @@ static void qemu_hvf_start_vcpu(CPUState *cpu)
cpu->cpu_index);
qemu_thread_create(cpu->thread, thread_name, qemu_hvf_cpu_thread_fn,
cpu, QEMU_THREAD_JOINABLE);
- while (!cpu->created) {
- qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
- }
}
static void qemu_whpx_start_vcpu(CPUState *cpu)
@@ -1937,9 +1926,6 @@ static void qemu_whpx_start_vcpu(CPUState *cpu)
#ifdef _WIN32
cpu->hThread = qemu_thread_get_handle(cpu->thread);
#endif
- while (!cpu->created) {
- qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
- }
}
static void qemu_dummy_start_vcpu(CPUState *cpu)
@@ -1953,9 +1939,6 @@ static void qemu_dummy_start_vcpu(CPUState *cpu)
cpu->cpu_index);
qemu_thread_create(cpu->thread, thread_name, qemu_dummy_cpu_thread_fn, cpu,
QEMU_THREAD_JOINABLE);
- while (!cpu->created) {
- qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
- }
}
void qemu_init_vcpu(CPUState *cpu)
@@ -1985,6 +1968,10 @@ void qemu_init_vcpu(CPUState *cpu)
} else {
qemu_dummy_start_vcpu(cpu);
}
+
+ while (!cpu->created) {
+ qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+ }
}
void cpu_stop_current(void)
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 76e29cfa14..4d7be45ac5 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -21,6 +21,8 @@ CONFIG_E500=y
CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM))
CONFIG_PLATFORM_BUS=y
CONFIG_ETSEC=y
+# For Sam460ex
+CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y
CONFIG_IDE_SII3112=y
CONFIG_I2C=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index bc5e1b3ffe..67d18b2e0e 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -15,6 +15,7 @@ CONFIG_PTIMER=y
CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y
+CONFIG_USB_EHCI_SYSBUS=y
CONFIG_SM501=y
CONFIG_IDE_SII3112=y
CONFIG_I2C=y
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
index d7fdb1fee3..feb711fb6a 100644
--- a/docs/interop/qcow2.txt
+++ b/docs/interop/qcow2.txt
@@ -426,10 +426,20 @@ Standard Cluster Descriptor:
Compressed Clusters Descriptor (x = 62 - (cluster_bits - 8)):
- Bit 0 - x: Host cluster offset. This is usually _not_ aligned to a
- cluster boundary!
+ Bit 0 - x-1: Host cluster offset. This is usually _not_ aligned to a
+ cluster or sector boundary!
- x+1 - 61: Compressed size of the images in sectors of 512 bytes
+ x - 61: Number of additional 512-byte sectors used for the
+ compressed data, beyond the sector containing the offset
+ in the previous field. Some of these sectors may reside
+ in the next contiguous host cluster.
+
+ Note that the compressed data does not necessarily occupy
+ all of the bytes in the final sector; rather, decompression
+ stops when it has produced a cluster of data.
+
+ Another compressed cluster may map to the tail of the final
+ sector used by this compressed cluster.
If a cluster is unallocated, read requests shall read the data from the backing
file (except if bit 0 in the Standard Cluster Descriptor is set). If there is
diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt
index b0571de4b8..170191a242 100644
--- a/docs/qcow2-cache.txt
+++ b/docs/qcow2-cache.txt
@@ -1,6 +1,6 @@
qcow2 L2/refcount cache configuration
=====================================
-Copyright (C) 2015 Igalia, S.L.
+Copyright (C) 2015, 2018 Igalia, S.L.
Author: Alberto Garcia <berto@igalia.com>
This work is licensed under the terms of the GNU GPL, version 2 or
@@ -118,8 +118,8 @@ There are three options available, and all of them take bytes:
There are two things that need to be taken into account:
- - Both caches must have a size that is a multiple of the cluster
- size.
+ - Both caches must have a size that is a multiple of the cluster size
+ (or the cache entry size: see "Using smaller cache sizes" below).
- If you only set one of the options above, QEMU will automatically
adjust the others so that the L2 cache is 4 times bigger than the
@@ -143,6 +143,46 @@ much less often than the L2 cache, so it's perfectly reasonable to
keep it small.
+Using smaller cache entries
+---------------------------
+The qcow2 L2 cache stores complete tables by default. This means that
+if QEMU needs an entry from an L2 table then the whole table is read
+from disk and is kept in the cache. If the cache is full then a
+complete table needs to be evicted first.
+
+This can be inefficient with large cluster sizes since it results in
+more disk I/O and wastes more cache memory.
+
+Since QEMU 2.12 you can change the size of the L2 cache entry and make
+it smaller than the cluster size. This can be configured using the
+"l2-cache-entry-size" parameter:
+
+ -drive file=hd.qcow2,l2-cache-size=2097152,l2-cache-entry-size=4096
+
+Some things to take into account:
+
+ - The L2 cache entry size has the same restrictions as the cluster
+ size (power of two, at least 512 bytes).
+
+ - Smaller entry sizes generally improve the cache efficiency and make
+ disk I/O faster. This is particularly true with solid state drives
+ so it's a good idea to reduce the entry size in those cases. With
+ rotating hard drives the situation is a bit more complicated so you
+ should test it first and stay with the default size if unsure.
+
+ - Try different entry sizes to see which one gives faster performance
+ in your case. The block size of the host filesystem is generally a
+ good default (usually 4096 bytes in the case of ext4).
+
+ - Only the L2 cache can be configured this way. The refcount cache
+ always uses the cluster size as the entry size.
+
+ - If the L2 cache is big enough to hold all of the image's L2 tables
+ (as explained in the "Choosing the right cache sizes" section
+ earlier in this document) then none of this is necessary and you
+ can omit the "l2-cache-entry-size" parameter altogether.
+
+
Reducing the memory usage
-------------------------
It is possible to clean unused cache entries in order to reduce the
diff --git a/exec.c b/exec.c
index 4d8addb263..604f03c535 100644
--- a/exec.c
+++ b/exec.c
@@ -2616,6 +2616,8 @@ static const MemoryRegionOps watch_mem_ops = {
},
};
+static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
+ MemTxAttrs attrs, uint8_t *buf, int len);
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
const uint8_t *buf, int len);
static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
@@ -3078,6 +3080,7 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
return result;
}
+/* Called from RCU critical section. */
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
const uint8_t *buf, int len)
{
@@ -3086,25 +3089,14 @@ static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
MemoryRegion *mr;
MemTxResult result = MEMTX_OK;
- if (len > 0) {
- rcu_read_lock();
- l = len;
- mr = flatview_translate(fv, addr, &addr1, &l, true);
- result = flatview_write_continue(fv, addr, attrs, buf, len,
- addr1, l, mr);
- rcu_read_unlock();
- }
+ l = len;
+ mr = flatview_translate(fv, addr, &addr1, &l, true);
+ result = flatview_write_continue(fv, addr, attrs, buf, len,
+ addr1, l, mr);
return result;
}
-MemTxResult address_space_write(AddressSpace *as, hwaddr addr,
- MemTxAttrs attrs,
- const uint8_t *buf, int len)
-{
- return flatview_write(address_space_to_flatview(as), addr, attrs, buf, len);
-}
-
/* Called within RCU critical section. */
MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf,
@@ -3175,42 +3167,61 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
return result;
}
-MemTxResult flatview_read_full(FlatView *fv, hwaddr addr,
- MemTxAttrs attrs, uint8_t *buf, int len)
+/* Called from RCU critical section. */
+static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
+ MemTxAttrs attrs, uint8_t *buf, int len)
{
hwaddr l;
hwaddr addr1;
MemoryRegion *mr;
+
+ l = len;
+ mr = flatview_translate(fv, addr, &addr1, &l, false);
+ return flatview_read_continue(fv, addr, attrs, buf, len,
+ addr1, l, mr);
+}
+
+MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
+ MemTxAttrs attrs, uint8_t *buf, int len)
+{
MemTxResult result = MEMTX_OK;
+ FlatView *fv;
if (len > 0) {
rcu_read_lock();
- l = len;
- mr = flatview_translate(fv, addr, &addr1, &l, false);
- result = flatview_read_continue(fv, addr, attrs, buf, len,
- addr1, l, mr);
+ fv = address_space_to_flatview(as);
+ result = flatview_read(fv, addr, attrs, buf, len);
rcu_read_unlock();
}
return result;
}
-static MemTxResult flatview_rw(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
- uint8_t *buf, int len, bool is_write)
+MemTxResult address_space_write(AddressSpace *as, hwaddr addr,
+ MemTxAttrs attrs,
+ const uint8_t *buf, int len)
{
- if (is_write) {
- return flatview_write(fv, addr, attrs, (uint8_t *)buf, len);
- } else {
- return flatview_read(fv, addr, attrs, (uint8_t *)buf, len);
+ MemTxResult result = MEMTX_OK;
+ FlatView *fv;
+
+ if (len > 0) {
+ rcu_read_lock();
+ fv = address_space_to_flatview(as);
+ result = flatview_write(fv, addr, attrs, buf, len);
+ rcu_read_unlock();
}
+
+ return result;
}
-MemTxResult address_space_rw(AddressSpace *as, hwaddr addr,
- MemTxAttrs attrs, uint8_t *buf,
- int len, bool is_write)
+MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
+ uint8_t *buf, int len, bool is_write)
{
- return flatview_rw(address_space_to_flatview(as),
- addr, attrs, buf, len, is_write);
+ if (is_write) {
+ return address_space_write(as, addr, attrs, buf, len);
+ } else {
+ return address_space_read_full(as, addr, attrs, buf, len);
+ }
}
void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
@@ -3376,7 +3387,6 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
MemoryRegion *mr;
hwaddr l, xlat;
- rcu_read_lock();
while (len > 0) {
l = len;
mr = flatview_translate(fv, addr, &xlat, &l, is_write);
@@ -3391,15 +3401,20 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
len -= l;
addr += l;
}
- rcu_read_unlock();
return true;
}
bool address_space_access_valid(AddressSpace *as, hwaddr addr,
int len, bool is_write)
{
- return flatview_access_valid(address_space_to_flatview(as),
- addr, len, is_write);
+ FlatView *fv;
+ bool result;
+
+ rcu_read_lock();
+ fv = address_space_to_flatview(as);
+ result = flatview_access_valid(fv, addr, len, is_write);
+ rcu_read_unlock();
+ return result;
}
static hwaddr
@@ -3445,7 +3460,7 @@ void *address_space_map(AddressSpace *as,
hwaddr l, xlat;
MemoryRegion *mr;
void *ptr;
- FlatView *fv = address_space_to_flatview(as);
+ FlatView *fv;
if (len == 0) {
return NULL;
@@ -3453,6 +3468,7 @@ void *address_space_map(AddressSpace *as,
l = len;
rcu_read_lock();
+ fv = address_space_to_flatview(as);
mr = flatview_translate(fv, addr, &xlat, &l, is_write);
if (!memory_access_is_direct(mr, is_write)) {
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 8e48500dd5..6f132c5ff1 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -55,6 +55,7 @@ static struct option helper_opts[] = {
static bool is_daemon;
static bool get_version; /* IOC getversion IOCTL supported */
+static char *prog_name;
static void GCC_FMT_ATTR(2, 3) do_log(int loglevel, const char *format, ...)
{
@@ -785,7 +786,7 @@ error:
return -1;
}
-static void usage(char *prog)
+static void usage(void)
{
fprintf(stderr, "usage: %s\n"
" -p|--path <path> 9p path to export\n"
@@ -795,7 +796,7 @@ static void usage(char *prog)
" access to this socket\n"
" \tNote: -s & -f can not be used together\n"
" [-n|--nodaemon] Run as a normal program\n",
- basename(prog));
+ prog_name);
}
static int process_reply(int sock, int type,
@@ -1045,6 +1046,8 @@ int main(int argc, char **argv)
struct statfs st_fs;
#endif
+ prog_name = g_path_get_basename(argv[0]);
+
is_daemon = true;
sock = -1;
own_u = own_g = -1;
@@ -1077,7 +1080,7 @@ int main(int argc, char **argv)
case '?':
case 'h':
default:
- usage(argv[0]);
+ usage();
exit(EXIT_FAILURE);
}
}
@@ -1085,13 +1088,13 @@ int main(int argc, char **argv)
/* Parameter validation */
if ((sock_name == NULL && sock == -1) || rpath == NULL) {
fprintf(stderr, "socket, socket descriptor or path not specified\n");
- usage(argv[0]);
+ usage();
return -1;
}
if (sock_name && sock != -1) {
fprintf(stderr, "both named socket and socket descriptor specified\n");
- usage(argv[0]);
+ usage();
exit(EXIT_FAILURE);
}
@@ -1099,7 +1102,7 @@ int main(int argc, char **argv)
fprintf(stderr, "owner uid:gid not specified, ");
fprintf(stderr,
"owner uid:gid specifies who can access the socket file\n");
- usage(argv[0]);
+ usage();
exit(EXIT_FAILURE);
}
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index 819f8be05d..3d75394e77 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -207,6 +207,7 @@ done:
if (xmax || ymax) {
dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
}
+ g_free(snap);
}
static void g364fb_draw_blank(G364State *s)
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
index 46d9c68bf5..b9064264d8 100644
--- a/hw/i386/multiboot.c
+++ b/hw/i386/multiboot.c
@@ -31,12 +31,13 @@
#include "hw/loader.h"
#include "elf.h"
#include "sysemu/sysemu.h"
+#include "qemu/error-report.h"
/* Show multiboot debug output */
//#define DEBUG_MULTIBOOT
#ifdef DEBUG_MULTIBOOT
-#define mb_debug(a...) fprintf(stderr, ## a)
+#define mb_debug(a...) error_report(a)
#else
#define mb_debug(a...)
#endif
@@ -137,7 +138,7 @@ static void mb_add_mod(MultibootState *s,
stl_p(p + MB_MOD_END, end);
stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
- mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n",
+ mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx,
s->mb_mods_count, start, end);
s->mb_mods_count++;
@@ -179,12 +180,12 @@ int load_multiboot(FWCfgState *fw_cfg,
if (!is_multiboot)
return 0; /* no multiboot */
- mb_debug("qemu: I believe we found a multiboot image!\n");
+ mb_debug("qemu: I believe we found a multiboot image!");
memset(bootinfo, 0, sizeof(bootinfo));
memset(&mbs, 0, sizeof(mbs));
if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
- fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
+ error_report("qemu: multiboot knows VBE. we don't.");
}
if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
uint64_t elf_entry;
@@ -193,7 +194,7 @@ int load_multiboot(FWCfgState *fw_cfg,
fclose(f);
if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
- fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
+ error_report("Cannot load x86-64 image, give a 32bit one.");
exit(1);
}
@@ -201,7 +202,7 @@ int load_multiboot(FWCfgState *fw_cfg,
&elf_low, &elf_high, 0, I386_ELF_MACHINE,
0, 0);
if (kernel_size < 0) {
- fprintf(stderr, "Error while loading elf kernel\n");
+ error_report("Error while loading elf kernel");
exit(1);
}
mh_load_addr = elf_low;
@@ -210,12 +211,13 @@ int load_multiboot(FWCfgState *fw_cfg,
mbs.mb_buf = g_malloc(mb_kernel_size);
if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) {
- fprintf(stderr, "Error while fetching elf kernel from rom\n");
+ error_report("Error while fetching elf kernel from rom");
exit(1);
}
- mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
- mb_kernel_size, (size_t)mh_entry_addr);
+ mb_debug("qemu: loading multiboot-elf kernel "
+ "(%#x bytes) with entry %#zx",
+ mb_kernel_size, (size_t)mh_entry_addr);
} else {
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
uint32_t mh_header_addr = ldl_p(header+i+12);
@@ -224,7 +226,7 @@ int load_multiboot(FWCfgState *fw_cfg,
mh_load_addr = ldl_p(header+i+16);
if (mh_header_addr < mh_load_addr) {
- fprintf(stderr, "invalid mh_load_addr address\n");
+ error_report("invalid load_addr address");
exit(1);
}
@@ -233,43 +235,39 @@ int load_multiboot(FWCfgState *fw_cfg,
mh_entry_addr = ldl_p(header+i+28);
if (mh_load_end_addr) {
- if (mh_bss_end_addr < mh_load_addr) {
- fprintf(stderr, "invalid mh_bss_end_addr address\n");
- exit(1);
- }
- mb_kernel_size = mh_bss_end_addr - mh_load_addr;
-
if (mh_load_end_addr < mh_load_addr) {
- fprintf(stderr, "invalid mh_load_end_addr address\n");
+ error_report("invalid load_end_addr address");
exit(1);
}
mb_load_size = mh_load_end_addr - mh_load_addr;
} else {
if (kernel_file_size < mb_kernel_text_offset) {
- fprintf(stderr, "invalid kernel_file_size\n");
+ error_report("invalid kernel_file_size");
exit(1);
}
- mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
- mb_load_size = mb_kernel_size;
+ mb_load_size = kernel_file_size - mb_kernel_text_offset;
+ }
+ if (mh_bss_end_addr) {
+ if (mh_bss_end_addr < (mh_load_addr + mb_load_size)) {
+ error_report("invalid bss_end_addr address");
+ exit(1);
+ }
+ mb_kernel_size = mh_bss_end_addr - mh_load_addr;
+ } else {
+ mb_kernel_size = mb_load_size;
}
- /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
- uint32_t mh_mode_type = ldl_p(header+i+32);
- uint32_t mh_width = ldl_p(header+i+36);
- uint32_t mh_height = ldl_p(header+i+40);
- uint32_t mh_depth = ldl_p(header+i+44); */
-
- mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
- mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
- mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
- mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
- mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
+ mb_debug("multiboot: header_addr = %#x", mh_header_addr);
+ mb_debug("multiboot: load_addr = %#x", mh_load_addr);
+ mb_debug("multiboot: load_end_addr = %#x", mh_load_end_addr);
+ mb_debug("multiboot: bss_end_addr = %#x", mh_bss_end_addr);
+ mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x",
mb_load_size, mh_load_addr);
mbs.mb_buf = g_malloc(mb_kernel_size);
fseek(f, mb_kernel_text_offset, SEEK_SET);
if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
- fprintf(stderr, "fread() failed\n");
+ error_report("fread() failed");
exit(1);
}
memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
@@ -323,10 +321,10 @@ int load_multiboot(FWCfgState *fw_cfg,
hwaddr c = mb_add_cmdline(&mbs, tmpbuf);
if ((next_space = strchr(tmpbuf, ' ')))
*next_space = '\0';
- mb_debug("multiboot loading module: %s\n", tmpbuf);
+ mb_debug("multiboot loading module: %s", tmpbuf);
mb_mod_length = get_image_size(tmpbuf);
if (mb_mod_length < 0) {
- fprintf(stderr, "Failed to open file '%s'\n", tmpbuf);
+ error_report("Failed to open file '%s'", tmpbuf);
exit(1);
}
@@ -337,7 +335,7 @@ int load_multiboot(FWCfgState *fw_cfg,
mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
mbs.mb_buf_phys + offs + mb_mod_length, c);
- mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx"\n",
+ mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx,
(char *)mbs.mb_buf + offs,
(char *)mbs.mb_buf + offs + mb_mod_length, c);
initrd_filename = next_initrd+1;
@@ -365,10 +363,11 @@ int load_multiboot(FWCfgState *fw_cfg,
stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
- mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
- mb_debug(" mb_buf_phys = "TARGET_FMT_plx"\n", mbs.mb_buf_phys);
- mb_debug(" mod_start = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods);
- mb_debug(" mb_mods_count = %d\n", mbs.mb_mods_count);
+ mb_debug("multiboot: entry_addr = %#x", mh_entry_addr);
+ mb_debug(" mb_buf_phys = "TARGET_FMT_plx, mbs.mb_buf_phys);
+ mb_debug(" mod_start = "TARGET_FMT_plx,
+ mbs.mb_buf_phys + mbs.offset_mods);
+ mb_debug(" mb_mods_count = %d", mbs.mb_mods_count);
/* save bootinfo off the stack */
mb_bootinfo_data = g_memdup(bootinfo, sizeof(bootinfo));
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 94cfd40ef2..35fcb6efdf 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1636,23 +1636,6 @@ void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
rom_reset_order_override();
}
-void pc_pci_device_init(PCIBus *pci_bus)
-{
- int max_bus;
- int bus;
-
- /* Note: if=scsi is deprecated with PC machine types */
- max_bus = drive_get_max_bus(IF_SCSI);
- for (bus = 0; bus <= max_bus; bus++) {
- pci_create_simple(pci_bus, -1, "lsi53c895a");
- /*
- * By not creating frontends here, we make
- * scsi_legacy_handle_cmdline() create them, and warn that
- * this usage is deprecated.
- */
- }
-}
-
void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
{
DeviceState *dev;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 456dc9e9f0..8658bcba63 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -295,10 +295,6 @@ static void pc_init1(MachineState *machine,
PC_MACHINE_ACPI_DEVICE_PROP, &error_abort);
}
- if (pcmc->pci_enabled) {
- pc_pci_device_init(pci_bus);
- }
-
if (pcms->acpi_nvdimm_state.is_enabled) {
nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
pcms->fw_cfg, OBJECT(pcms));
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index aba7541a82..0c0bc48137 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -273,9 +273,6 @@ static void pc_q35_init(MachineState *machine)
/* the rest devices to which pci devfn is automatically assigned */
pc_vga_init(isa_bus, host_bus);
pc_nic_init(isa_bus, host_bus);
- if (pcmc->pci_enabled) {
- pc_pci_device_init(host_bus);
- }
if (pcms->acpi_nvdimm_state.is_enabled) {
nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 257b429381..139c843514 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1087,15 +1087,7 @@ static void ide_flush_cache(IDEState *s)
s->status |= BUSY_STAT;
ide_set_retry(s);
block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH);
-
- if (blk_bs(s->blk)) {
- s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
- } else {
- /* XXX blk_aio_flush() crashes when blk_bs(blk) is NULL, remove this
- * temporary workaround when blk_aio_*() functions handle NULL blk_bs.
- */
- ide_flush_cb(s, 0);
- }
+ s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
}
static void ide_cfata_metadata_inquiry(IDEState *s)
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 266aed1b7b..50b62712c8 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -258,6 +258,7 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
+ trace_adb_kbd_request_change_addr(d->devaddr);
break;
default:
d->devaddr = buf[1] & 0xf;
@@ -269,6 +270,9 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
d->handler = buf[2];
}
+
+ trace_adb_kbd_request_change_addr_and_handler(d->devaddr,
+ d->handler);
break;
}
}
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
index 47e88faf25..3ba6027d33 100644
--- a/hw/input/adb-mouse.c
+++ b/hw/input/adb-mouse.c
@@ -118,6 +118,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
s->dx = 0;
s->dy = 0;
s->dz = 0;
+ trace_adb_mouse_flush();
return 0;
}
@@ -138,6 +139,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
+ trace_adb_mouse_request_change_addr(d->devaddr);
break;
default:
d->devaddr = buf[1] & 0xf;
@@ -155,6 +157,9 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
if (buf[2] == 1 || buf[2] == 2) {
d->handler = buf[2];
}
+
+ trace_adb_mouse_request_change_addr_and_handler(d->devaddr,
+ d->handler);
break;
}
}
diff --git a/hw/input/trace-events b/hw/input/trace-events
index 5affabc81d..db72484a25 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -4,10 +4,15 @@
adb_kbd_no_key(void) "Ignoring NO_KEY"
adb_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
adb_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
+adb_kbd_request_change_addr(int devaddr) "change addr to 0x%x"
+adb_kbd_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
# hw/input/adb-mouse.c
+adb_mouse_flush(void) "flush"
adb_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
adb_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
+adb_mouse_request_change_addr(int devaddr) "change addr to 0x%x"
+adb_mouse_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
# hw/input/ps2.c
ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x"
diff --git a/hw/intc/heathrow_pic.c b/hw/intc/heathrow_pic.c
index 171f5ed814..393fdd7326 100644
--- a/hw/intc/heathrow_pic.c
+++ b/hw/intc/heathrow_pic.c
@@ -25,78 +25,58 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/ppc/mac.h"
+#include "hw/intc/heathrow_pic.h"
+#include "trace.h"
-/* debug PIC */
-//#define DEBUG_PIC
-
-#ifdef DEBUG_PIC
-#define PIC_DPRINTF(fmt, ...) \
- do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define PIC_DPRINTF(fmt, ...)
-#endif
-
-typedef struct HeathrowPIC {
- uint32_t events;
- uint32_t mask;
- uint32_t levels;
- uint32_t level_triggered;
-} HeathrowPIC;
-
-typedef struct HeathrowPICS {
- MemoryRegion mem;
- HeathrowPIC pics[2];
- qemu_irq *irqs;
-} HeathrowPICS;
-
-static inline int check_irq(HeathrowPIC *pic)
+static inline int heathrow_check_irq(HeathrowPICState *pic)
{
return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
}
/* update the CPU irq state */
-static void heathrow_pic_update(HeathrowPICS *s)
+static void heathrow_update_irq(HeathrowState *s)
{
- if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
+ if (heathrow_check_irq(&s->pics[0]) ||
+ heathrow_check_irq(&s->pics[1])) {
qemu_irq_raise(s->irqs[0]);
} else {
qemu_irq_lower(s->irqs[0]);
}
}
-static void pic_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
+static void heathrow_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
+ HeathrowState *s = opaque;
+ HeathrowPICState *pic;
unsigned int n;
n = ((addr & 0xfff) - 0x10) >> 4;
- PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
+ trace_heathrow_write(addr, n, value);
if (n >= 2)
return;
pic = &s->pics[n];
switch(addr & 0xf) {
case 0x04:
pic->mask = value;
- heathrow_pic_update(s);
+ heathrow_update_irq(s);
break;
case 0x08:
/* do not reset level triggered IRQs */
value &= ~pic->level_triggered;
pic->events &= ~value;
- heathrow_pic_update(s);
+ heathrow_update_irq(s);
break;
default:
break;
}
}
-static uint64_t pic_read(void *opaque, hwaddr addr,
- unsigned size)
+static uint64_t heathrow_read(void *opaque, hwaddr addr,
+ unsigned size)
{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
+ HeathrowState *s = opaque;
+ HeathrowPICState *pic;
unsigned int n;
uint32_t value;
@@ -120,40 +100,39 @@ static uint64_t pic_read(void *opaque, hwaddr addr,
break;
}
}
- PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
+ trace_heathrow_read(addr, n, value);
return value;
}
-static const MemoryRegionOps heathrow_pic_ops = {
- .read = pic_read,
- .write = pic_write,
+static const MemoryRegionOps heathrow_ops = {
+ .read = heathrow_read,
+ .write = heathrow_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void heathrow_pic_set_irq(void *opaque, int num, int level)
+static void heathrow_set_irq(void *opaque, int num, int level)
{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
+ HeathrowState *s = opaque;
+ HeathrowPICState *pic;
unsigned int irq_bit;
+ int last_level;
-#if defined(DEBUG)
- {
- static int last_level[64];
- if (last_level[num] != level) {
- PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
- last_level[num] = level;
- }
- }
-#endif
pic = &s->pics[1 - (num >> 5)];
irq_bit = 1 << (num & 0x1f);
+ last_level = (pic->levels & irq_bit) ? 1 : 0;
+
if (level) {
pic->events |= irq_bit & ~pic->level_triggered;
pic->levels |= irq_bit;
} else {
pic->levels &= ~irq_bit;
}
- heathrow_pic_update(s);
+
+ if (last_level != level) {
+ trace_heathrow_set_irq(num, level);
+ }
+
+ heathrow_update_irq(s);
}
static const VMStateDescription vmstate_heathrow_pic_one = {
@@ -161,54 +140,81 @@ static const VMStateDescription vmstate_heathrow_pic_one = {
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
- VMSTATE_UINT32(events, HeathrowPIC),
- VMSTATE_UINT32(mask, HeathrowPIC),
- VMSTATE_UINT32(levels, HeathrowPIC),
- VMSTATE_UINT32(level_triggered, HeathrowPIC),
+ VMSTATE_UINT32(events, HeathrowPICState),
+ VMSTATE_UINT32(mask, HeathrowPICState),
+ VMSTATE_UINT32(levels, HeathrowPICState),
+ VMSTATE_UINT32(level_triggered, HeathrowPICState),
VMSTATE_END_OF_LIST()
}
};
-static const VMStateDescription vmstate_heathrow_pic = {
+static const VMStateDescription vmstate_heathrow = {
.name = "heathrow_pic",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
- vmstate_heathrow_pic_one, HeathrowPIC),
+ VMSTATE_STRUCT_ARRAY(pics, HeathrowState, 2, 1,
+ vmstate_heathrow_pic_one, HeathrowPICState),
VMSTATE_END_OF_LIST()
}
};
-static void heathrow_pic_reset_one(HeathrowPIC *s)
+static void heathrow_reset(DeviceState *d)
{
- memset(s, '\0', sizeof(HeathrowPIC));
+ HeathrowState *s = HEATHROW(d);
+
+ s->pics[0].level_triggered = 0;
+ s->pics[1].level_triggered = 0x1ff00000;
}
-static void heathrow_pic_reset(void *opaque)
+static void heathrow_init(Object *obj)
{
- HeathrowPICS *s = opaque;
-
- heathrow_pic_reset_one(&s->pics[0]);
- heathrow_pic_reset_one(&s->pics[1]);
+ HeathrowState *s = HEATHROW(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- s->pics[0].level_triggered = 0;
- s->pics[1].level_triggered = 0x1ff00000;
+ memory_region_init_io(&s->mem, OBJECT(s), &heathrow_ops, s,
+ "heathrow-pic", 0x1000);
+ sysbus_init_mmio(sbd, &s->mem);
}
-qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
- int nb_cpus, qemu_irq **irqs)
+DeviceState *heathrow_pic_init(int nb_cpus, qemu_irq **irqs,
+ qemu_irq **pic_irqs)
{
- HeathrowPICS *s;
+ DeviceState *d;
+ HeathrowState *s;
- s = g_malloc0(sizeof(HeathrowPICS));
+ d = qdev_create(NULL, TYPE_HEATHROW);
+ qdev_init_nofail(d);
+
+ s = HEATHROW(d);
/* only 1 CPU */
s->irqs = irqs[0];
- memory_region_init_io(&s->mem, NULL, &heathrow_pic_ops, s,
- "heathrow-pic", 0x1000);
- *pmem = &s->mem;
- vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
- qemu_register_reset(heathrow_pic_reset, s);
- return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
+ *pic_irqs = qemu_allocate_irqs(heathrow_set_irq, s, HEATHROW_NUM_IRQS);
+
+ return d;
+}
+
+static void heathrow_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->reset = heathrow_reset;
+ dc->vmsd = &vmstate_heathrow;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
+
+static const TypeInfo heathrow_type_info = {
+ .name = TYPE_HEATHROW,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HeathrowState),
+ .instance_init = heathrow_init,
+ .class_init = heathrow_class_init,
+};
+
+static void heathrow_register_types(void)
+{
+ type_register_static(&heathrow_type_info);
+}
+
+type_init(heathrow_register_types)
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 9159a06f07..811cee9b26 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -63,10 +63,6 @@ static int get_current_cpu(void);
} \
} while (0)
-#define MAX_CPU 32
-#define MAX_MSI 8
-#define VID 0x03 /* MPIC version ID */
-
/* OpenPIC capability flags */
#define OPENPIC_FLAG_IDR_CRIT (1 << 0)
#define OPENPIC_FLAG_ILR (2 << 0)
@@ -85,35 +81,6 @@ static int get_current_cpu(void);
#define OPENPIC_CPU_REG_START 0x20000
#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
-/* Raven */
-#define RAVEN_MAX_CPU 2
-#define RAVEN_MAX_EXT 48
-#define RAVEN_MAX_IRQ 64
-#define RAVEN_MAX_TMR OPENPIC_MAX_TMR
-#define RAVEN_MAX_IPI OPENPIC_MAX_IPI
-
-/* KeyLargo */
-#define KEYLARGO_MAX_CPU 4
-#define KEYLARGO_MAX_EXT 64
-#define KEYLARGO_MAX_IPI 4
-#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI)
-#define KEYLARGO_MAX_TMR 0
-#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */
-/* Timers don't exist but this makes the code happy... */
-#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI)
-
-/* Interrupt definitions */
-#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */
-#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */
-#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */
-#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
-/* First doorbell IRQ */
-#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
-
-typedef struct FslMpicInfo {
- int max_ext;
-} FslMpicInfo;
-
static FslMpicInfo fsl_mpic_20 = {
.max_ext = 12,
};
@@ -211,55 +178,6 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
uint32_t val, int idx);
static void openpic_reset(DeviceState *d);
-typedef enum IRQType {
- IRQ_TYPE_NORMAL = 0,
- IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
- IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
-} IRQType;
-
-/* Round up to the nearest 64 IRQs so that the queue length
- * won't change when moving between 32 and 64 bit hosts.
- */
-#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
-
-typedef struct IRQQueue {
- unsigned long *queue;
- int32_t queue_size; /* Only used for VMSTATE_BITMAP */
- int next;
- int priority;
-} IRQQueue;
-
-typedef struct IRQSource {
- uint32_t ivpr; /* IRQ vector/priority register */
- uint32_t idr; /* IRQ destination register */
- uint32_t destmask; /* bitmap of CPU destinations */
- int last_cpu;
- int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
- int pending; /* TRUE if IRQ is pending */
- IRQType type;
- bool level:1; /* level-triggered */
- bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */
-} IRQSource;
-
-#define IVPR_MASK_SHIFT 31
-#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
-#define IVPR_ACTIVITY_SHIFT 30
-#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
-#define IVPR_MODE_SHIFT 29
-#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
-#define IVPR_POLARITY_SHIFT 23
-#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
-#define IVPR_SENSE_SHIFT 22
-#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
-
-#define IVPR_PRIORITY_MASK (0xFU << 16)
-#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
-#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
-
-/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
-#define IDR_EP 0x80000000 /* external pin */
-#define IDR_CI 0x40000000 /* critical interrupt */
-
/* Convert between openpic clock ticks and nanosecs. In the hardware the clock
frequency is driven by board inputs to the PIC which the PIC would then
divide by 4 or 8. For now hard code to 25MZ.
@@ -275,81 +193,6 @@ static inline uint64_t ticks_to_ns(uint64_t ticks)
return ticks * OPENPIC_TIMER_NS_PER_TICK;
}
-typedef struct OpenPICTimer {
- uint32_t tccr; /* Global timer current count register */
- uint32_t tbcr; /* Global timer base count register */
- int n_IRQ;
- bool qemu_timer_active; /* Is the qemu_timer is running? */
- struct QEMUTimer *qemu_timer;
- struct OpenPICState *opp; /* Device timer is part of. */
- /* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last
- current_count written or read, only defined if qemu_timer_active. */
- uint64_t origin_time;
-} OpenPICTimer;
-
-typedef struct OpenPICMSI {
- uint32_t msir; /* Shared Message Signaled Interrupt Register */
-} OpenPICMSI;
-
-typedef struct IRQDest {
- int32_t ctpr; /* CPU current task priority */
- IRQQueue raised;
- IRQQueue servicing;
- qemu_irq *irqs;
-
- /* Count of IRQ sources asserting on non-INT outputs */
- uint32_t outputs_active[OPENPIC_OUTPUT_NB];
-} IRQDest;
-
-#define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC)
-
-typedef struct OpenPICState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion mem;
-
- /* Behavior control */
- FslMpicInfo *fsl;
- uint32_t model;
- uint32_t flags;
- uint32_t nb_irqs;
- uint32_t vid;
- uint32_t vir; /* Vendor identification register */
- uint32_t vector_mask;
- uint32_t tfrr_reset;
- uint32_t ivpr_reset;
- uint32_t idr_reset;
- uint32_t brr1;
- uint32_t mpic_mode_mask;
-
- /* Sub-regions */
- MemoryRegion sub_io_mem[6];
-
- /* Global registers */
- uint32_t frr; /* Feature reporting register */
- uint32_t gcr; /* Global configuration register */
- uint32_t pir; /* Processor initialization register */
- uint32_t spve; /* Spurious vector register */
- uint32_t tfrr; /* Timer frequency reporting register */
- /* Source registers */
- IRQSource src[OPENPIC_MAX_IRQ];
- /* Local registers per output pin */
- IRQDest dst[MAX_CPU];
- uint32_t nb_cpus;
- /* Timer registers */
- OpenPICTimer timers[OPENPIC_MAX_TMR];
- uint32_t max_tmr;
-
- /* Shared MSI registers */
- OpenPICMSI msi[MAX_MSI];
- uint32_t max_irq;
- uint32_t irq_ipi0;
- uint32_t irq_tim0;
- uint32_t irq_msi;
-} OpenPICState;
-
static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
{
set_bit(n_IRQ, q->queue);
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index fa83420254..928bc04a4e 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -30,6 +30,7 @@
#include "exec/address-spaces.h"
#include "hw/hw.h"
#include "hw/ppc/openpic.h"
+#include "hw/ppc/openpic_kvm.h"
#include "hw/pci/msi.h"
#include "hw/sysbus.h"
#include "sysemu/kvm.h"
@@ -124,10 +125,6 @@ static void kvm_openpic_region_add(MemoryListener *listener,
uint64_t reg_base;
int ret;
- if (section->fv != address_space_to_flatview(&address_space_memory)) {
- abort();
- }
-
/* Ignore events on regions that are not us */
if (section->mr != &opp->mem) {
return;
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 4092d2825e..55e8c2570c 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -186,3 +186,8 @@ nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)"
nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d"
nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
+
+# hw/intc/heathrow_pic.c
+heathrow_write(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
+heathrow_read(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
+heathrow_set_irq(int num, int level) "set_irq: num=0x%02x level=%d"
diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
index 024f8557ab..af1bd46b4b 100644
--- a/hw/misc/macio/macio.c
+++ b/hw/misc/macio/macio.c
@@ -30,48 +30,11 @@
#include "hw/pci/pci.h"
#include "hw/ppc/mac_dbdma.h"
#include "hw/char/escc.h"
+#include "hw/misc/macio/macio.h"
+#include "hw/intc/heathrow_pic.h"
-#define TYPE_MACIO "macio"
-#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
-
-typedef struct MacIOState
-{
- /*< private >*/
- PCIDevice parent;
- /*< public >*/
-
- MemoryRegion bar;
- CUDAState cuda;
- DBDMAState *dbdma;
- MemoryRegion *pic_mem;
- MemoryRegion *escc_mem;
- uint64_t frequency;
-} MacIOState;
-
-#define OLDWORLD_MACIO(obj) \
- OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
-
-typedef struct OldWorldMacIOState {
- /*< private >*/
- MacIOState parent_obj;
- /*< public >*/
-
- qemu_irq irqs[5];
-
- MacIONVRAMState nvram;
- MACIOIDEState ide[2];
-} OldWorldMacIOState;
-
-#define NEWWORLD_MACIO(obj) \
- OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
-
-typedef struct NewWorldMacIOState {
- /*< private >*/
- MacIOState parent_obj;
- /*< public >*/
- qemu_irq irqs[5];
- MACIOIDEState ide[2];
-} NewWorldMacIOState;
+/* Note: this code is strongly inspirated from the corresponding code
+ * in PearPC */
/*
* The mac-io has two interfaces to the ESCC. One is called "escc-legacy",
@@ -84,10 +47,12 @@ typedef struct NewWorldMacIOState {
*
* Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
*/
-static void macio_escc_legacy_setup(MacIOState *macio_state)
+static void macio_escc_legacy_setup(MacIOState *s)
{
+ ESCCState *escc = ESCC(&s->escc);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
MemoryRegion *escc_legacy = g_new(MemoryRegion, 1);
- MemoryRegion *bar = &macio_state->bar;
+ MemoryRegion *bar = &s->bar;
int i;
static const int maps[] = {
0x00, 0x00, /* Command B */
@@ -102,25 +67,26 @@ static void macio_escc_legacy_setup(MacIOState *macio_state)
0xb0, 0xb0, /* Detect AB */
};
- memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256);
+ memory_region_init(escc_legacy, OBJECT(s), "escc-legacy", 256);
for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
MemoryRegion *port = g_new(MemoryRegion, 1);
- memory_region_init_alias(port, OBJECT(macio_state), "escc-legacy-port",
- macio_state->escc_mem, maps[i+1], 0x2);
+ memory_region_init_alias(port, OBJECT(s), "escc-legacy-port",
+ sysbus_mmio_get_region(sbd, 0),
+ maps[i + 1], 0x2);
memory_region_add_subregion(escc_legacy, maps[i], port);
}
memory_region_add_subregion(bar, 0x12000, escc_legacy);
}
-static void macio_bar_setup(MacIOState *macio_state)
+static void macio_bar_setup(MacIOState *s)
{
- MemoryRegion *bar = &macio_state->bar;
+ ESCCState *escc = ESCC(&s->escc);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
+ MemoryRegion *bar = &s->bar;
- if (macio_state->escc_mem) {
- memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
- macio_escc_legacy_setup(macio_state);
- }
+ memory_region_add_subregion(bar, 0x13000, sysbus_mmio_get_region(sbd, 0));
+ macio_escc_legacy_setup(s);
}
static void macio_common_realize(PCIDevice *d, Error **errp)
@@ -129,15 +95,17 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
SysBusDevice *sysbus_dev;
Error *err = NULL;
- object_property_set_bool(OBJECT(s->dbdma), true, "realized", &err);
+ object_property_set_bool(OBJECT(&s->dbdma), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
- sysbus_dev = SYS_BUS_DEVICE(s->dbdma);
+ sysbus_dev = SYS_BUS_DEVICE(&s->dbdma);
memory_region_add_subregion(&s->bar, 0x08000,
sysbus_mmio_get_region(sysbus_dev, 0));
+ qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
+ s->frequency);
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@@ -147,6 +115,12 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
memory_region_add_subregion(&s->bar, 0x16000,
sysbus_mmio_get_region(sysbus_dev, 0));
+ object_property_set_bool(OBJECT(&s->escc), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
macio_bar_setup(s);
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
}
@@ -161,7 +135,7 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
sysbus_connect_irq(sysbus_dev, 0, irq0);
sysbus_connect_irq(sysbus_dev, 1, irq1);
qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid);
- object_property_set_link(OBJECT(ide), OBJECT(s->dbdma), "dbdma", errp);
+ object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", errp);
macio_ide_register_dma(ide);
object_property_set_bool(OBJECT(ide), true, "realized", errp);
@@ -185,6 +159,10 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp)
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
+ sysbus_dev = SYS_BUS_DEVICE(&s->escc);
+ sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
+ sysbus_connect_irq(sysbus_dev, 1, os->irqs[cur_irq++]);
+
object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@@ -195,10 +173,10 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp)
sysbus_mmio_get_region(sysbus_dev, 0));
pmac_format_nvram_partition(&os->nvram, os->nvram.size);
- if (s->pic_mem) {
- /* Heathrow PIC */
- memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem);
- }
+ /* Heathrow PIC */
+ sysbus_dev = SYS_BUS_DEVICE(os->pic);
+ memory_region_add_subregion(&s->bar, 0x0,
+ sysbus_mmio_get_region(sysbus_dev, 0));
/* IDE buses */
for (i = 0; i < ARRAY_SIZE(os->ide); i++) {
@@ -236,6 +214,11 @@ static void macio_oldworld_init(Object *obj)
qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
+ object_property_add_link(obj, "pic", TYPE_HEATHROW,
+ (Object **) &os->pic,
+ qdev_prop_allow_set_link_before_realize,
+ 0, NULL);
+
object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM);
dev = DEVICE(&os->nvram);
qdev_prop_set_uint32(dev, "size", 0x2000);
@@ -297,10 +280,14 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
- if (s->pic_mem) {
- /* OpenPIC */
- memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
- }
+ sysbus_dev = SYS_BUS_DEVICE(&s->escc);
+ sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
+ sysbus_connect_irq(sysbus_dev, 1, ns->irqs[cur_irq++]);
+
+ /* OpenPIC */
+ sysbus_dev = SYS_BUS_DEVICE(ns->pic);
+ memory_region_add_subregion(&s->bar, 0x40000,
+ sysbus_mmio_get_region(sysbus_dev, 0));
/* IDE buses */
for (i = 0; i < ARRAY_SIZE(ns->ide); i++) {
@@ -329,6 +316,11 @@ static void macio_newworld_init(Object *obj)
qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
+ object_property_add_link(obj, "pic", TYPE_OPENPIC,
+ (Object **) &ns->pic,
+ qdev_prop_allow_set_link_before_realize,
+ 0, NULL);
+
for (i = 0; i < 2; i++) {
macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
}
@@ -344,8 +336,20 @@ static void macio_instance_init(Object *obj)
qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
- s->dbdma = MAC_DBDMA(object_new(TYPE_MAC_DBDMA));
- object_property_add_child(obj, "dbdma", OBJECT(s->dbdma), NULL);
+ object_initialize(&s->dbdma, sizeof(s->dbdma), TYPE_MAC_DBDMA);
+ qdev_set_parent_bus(DEVICE(&s->dbdma), sysbus_get_default());
+ object_property_add_child(obj, "dbdma", OBJECT(&s->dbdma), NULL);
+
+ object_initialize(&s->escc, sizeof(s->escc), TYPE_ESCC);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "it_shift", 4);
+ qdev_prop_set_chr(DEVICE(&s->escc), "chrA", serial_hds[0]);
+ qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hds[1]);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial);
+ qdev_set_parent_bus(DEVICE(&s->escc), sysbus_get_default());
+ object_property_add_child(obj, "escc", OBJECT(&s->escc), NULL);
}
static const VMStateDescription vmstate_macio_oldworld = {
@@ -441,19 +445,3 @@ static void macio_register_types(void)
}
type_init(macio_register_types)
-
-void macio_init(PCIDevice *d,
- MemoryRegion *pic_mem,
- MemoryRegion *escc_mem)
-{
- MacIOState *macio_state = MACIO(d);
-
- macio_state->pic_mem = pic_mem;
- macio_state->escc_mem = escc_mem;
- /* Note: this code is strongly inspirated from the corresponding code
- in PearPC */
- qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "timebase-frequency",
- macio_state->frequency);
-
- qdev_init_nofail(DEVICE(d));
-}
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index eb5ffcc0a8..562d9ed005 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -92,8 +92,8 @@ tz_ppc_cfg_sec_resp(int level) "TZ PPC: cfg_sec_resp = %d"
tz_ppc_irq_enable(int level) "TZ PPC: int_enable = %d"
tz_ppc_irq_clear(int level) "TZ PPC: int_clear = %d"
tz_ppc_update_irq(int level) "TZ PPC: setting irq line to %d"
-tz_ppc_read_blocked(int n, hwaddr offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" HWADDR_PRIx " read (secure %d user %d) blocked"
-tz_ppc_write_blocked(int n, hwaddr offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" HWADDR_PRIx " write (secure %d user %d) blocked"
+tz_ppc_read_blocked(int n, uint64_t offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" PRIx64 " read (secure %d user %d) blocked"
+tz_ppc_write_blocked(int n, uint64_t offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" PRIx64 " write (secure %d user %d) blocked"
# hw/misc/iotkit-secctl.c
iotkit_secctl_s_read(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl S regs read: offset 0x%x data 0x%" PRIx64 " size %u"
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index ad1928c5d8..86d82a6ec3 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -13,7 +13,8 @@ endif
obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o
# PowerPC 4xx boards
obj-y += ppc4xx_devs.o ppc405_uc.o
-obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o ppc440_bamboo.o
+obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o
+obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o sam460ex.o
# PReP
obj-$(CONFIG_PREP) += prep.o
obj-$(CONFIG_PREP) += prep_systemio.o
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index a40d3ec3e3..43c15d18c4 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -29,6 +29,7 @@
#include "kvm_ppc.h"
#include "sysemu/device_tree.h"
#include "hw/ppc/openpic.h"
+#include "hw/ppc/openpic_kvm.h"
#include "hw/ppc/ppc.h"
#include "hw/loader.h"
#include "elf.h"
@@ -119,7 +120,14 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
if (defcon) {
+ /*
+ * "linux,stdout-path" and "stdout" properties are deprecated by linux
+ * kernel. New platforms should only use the "stdout-path" property. Set
+ * the new property and continue using older property to remain
+ * compatible with the existing firmware.
+ */
qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
+ qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
}
}
@@ -784,8 +792,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
int initrd_size = 0;
hwaddr cur_base = 0;
char *filename;
+ const char *payload_name;
+ bool kernel_as_payload;
hwaddr bios_entry = 0;
- target_long bios_size;
+ target_long payload_size;
struct boot_info *boot_info;
int dt_size;
int i;
@@ -913,11 +923,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
/* Register spinning region */
sysbus_create_simple("e500-spin", params->spin_base, NULL);
- if (cur_base < (32 * 1024 * 1024)) {
- /* u-boot occupies memory up to 32MB, so load blobs above */
- cur_base = (32 * 1024 * 1024);
- }
-
if (params->has_mpc8xxx_gpio) {
qemu_irq poweroff_irq;
@@ -952,8 +957,61 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
sysbus_mmio_get_region(s, 0));
}
- /* Load kernel. */
- if (machine->kernel_filename) {
+ /*
+ * Smart firmware defaults ahead!
+ *
+ * We follow the following table to select which payload we execute.
+ *
+ * -kernel | -bios | payload
+ * ---------+-------+---------
+ * N | Y | u-boot
+ * N | N | u-boot
+ * Y | Y | u-boot
+ * Y | N | kernel
+ *
+ * This ensures backwards compatibility with how we used to expose
+ * -kernel to users but allows them to run through u-boot as well.
+ */
+ kernel_as_payload = false;
+ if (bios_name == NULL) {
+ if (machine->kernel_filename) {
+ payload_name = machine->kernel_filename;
+ kernel_as_payload = true;
+ } else {
+ payload_name = "u-boot.e500";
+ }
+ } else {
+ payload_name = bios_name;
+ }
+
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
+
+ payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
+ 1, PPC_ELF_MACHINE, 0, 0);
+ if (payload_size < 0) {
+ /*
+ * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
+ * ePAPR compliant kernel
+ */
+ payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
+ NULL, NULL);
+ if (payload_size < 0) {
+ error_report("qemu: could not load firmware '%s'", filename);
+ exit(1);
+ }
+ }
+
+ g_free(filename);
+
+ if (kernel_as_payload) {
+ kernel_base = loadaddr;
+ kernel_size = payload_size;
+ }
+
+ cur_base = loadaddr + payload_size;
+
+ /* Load bare kernel only if no bios/u-boot has been provided */
+ if (machine->kernel_filename && !kernel_as_payload) {
kernel_base = cur_base;
kernel_size = load_image_targphys(machine->kernel_filename,
cur_base,
@@ -967,6 +1025,11 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
cur_base += kernel_size;
}
+ if (cur_base < (32 * 1024 * 1024)) {
+ /* u-boot occupies memory up to 32MB, so load blobs above */
+ cur_base = (32 * 1024 * 1024);
+ }
+
/* Load initrd. */
if (machine->initrd_filename) {
initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
@@ -983,47 +1046,16 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
}
/*
- * Smart firmware defaults ahead!
- *
- * We follow the following table to select which payload we execute.
- *
- * -kernel | -bios | payload
- * ---------+-------+---------
- * N | Y | u-boot
- * N | N | u-boot
- * Y | Y | u-boot
- * Y | N | kernel
- *
- * This ensures backwards compatibility with how we used to expose
- * -kernel to users but allows them to run through u-boot as well.
+ * Reserve space for dtb behind the kernel image because Linux has a bug
+ * where it can only handle the dtb if it's within the first 64MB of where
+ * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
+ * ensures enough space between kernel and initrd.
*/
- if (bios_name == NULL) {
- if (machine->kernel_filename) {
- bios_name = machine->kernel_filename;
- } else {
- bios_name = "u-boot.e500";
- }
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
- bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
- 1, PPC_ELF_MACHINE, 0, 0);
- if (bios_size < 0) {
- /*
- * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
- * ePAPR compliant kernel
- */
- kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
- NULL, NULL);
- if (kernel_size < 0) {
- error_report("could not load firmware '%s'", filename);
+ dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+ if (dt_base + DTB_MAX_SIZE > ram_size) {
+ error_report("qemu: not enough memory for device tree");
exit(1);
- }
}
- g_free(filename);
-
- /* Reserve space for dtb */
- dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
dt_size = ppce500_prep_device_tree(machine, params, dt_base,
initrd_base, initrd_size,
diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index 4702194f3f..a02f797598 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -47,9 +47,6 @@
/* MacIO */
-#define TYPE_OLDWORLD_MACIO "macio-oldworld"
-#define TYPE_NEWWORLD_MACIO "macio-newworld"
-
#define TYPE_MACIO_IDE "macio-ide"
#define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE)
@@ -76,12 +73,11 @@ void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table);
void macio_ide_register_dma(MACIOIDEState *ide);
void macio_init(PCIDevice *dev,
- MemoryRegion *pic_mem,
- MemoryRegion *escc_mem);
+ MemoryRegion *pic_mem);
/* Heathrow PIC */
-qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
- int nb_cpus, qemu_irq **irqs);
+DeviceState *heathrow_pic_init(int nb_cpus, qemu_irq **irqs,
+ qemu_irq **pic_irqs);
/* Grackle PCI */
#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost"
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 4e1298ee50..a749e2565d 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -60,6 +60,7 @@
#include "hw/boards.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h"
+#include "hw/misc/macio/macio.h"
#include "hw/ppc/openpic.h"
#include "hw/ide.h"
#include "hw/loader.h"
@@ -153,20 +154,18 @@ static void ppc_core99_init(MachineState *machine)
hwaddr kernel_base, initrd_base, cmdline_base = 0;
long kernel_size, initrd_size;
PCIBus *pci_bus;
- PCIDevice *macio;
+ NewWorldMacIOState *macio;
MACIOIDEState *macio_ide;
BusState *adb_bus;
MacIONVRAMState *nvr;
int bios_size, ndrv_size;
uint8_t *ndrv_file;
- MemoryRegion *pic_mem, *escc_mem;
- MemoryRegion *escc_bar = g_new(MemoryRegion, 1);
int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
int machine_arch;
SysBusDevice *s;
- DeviceState *dev;
+ DeviceState *dev, *pic_dev;
int *token = g_new(int, 1);
hwaddr nvram_addr = 0xFFF04000;
uint64_t tbfreq;
@@ -333,11 +332,10 @@ static void ppc_core99_init(MachineState *machine)
pic = g_new0(qemu_irq, 64);
- dev = qdev_create(NULL, TYPE_OPENPIC);
- qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_KEYLARGO);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- pic_mem = s->mmio[0].memory;
+ pic_dev = qdev_create(NULL, TYPE_OPENPIC);
+ qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO);
+ qdev_init_nofail(pic_dev);
+ s = SYS_BUS_DEVICE(pic_dev);
k = 0;
for (i = 0; i < smp_cpus; i++) {
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
@@ -346,7 +344,7 @@ static void ppc_core99_init(MachineState *machine)
}
for (i = 0; i < 64; i++) {
- pic[i] = qdev_get_gpio_in(dev, i);
+ pic[i] = qdev_get_gpio_in(pic_dev, i);
}
if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
@@ -368,36 +366,20 @@ static void ppc_core99_init(MachineState *machine)
tbfreq = TBFREQ;
}
- /* init basic PC hardware */
-
- dev = qdev_create(NULL, TYPE_ESCC);
- qdev_prop_set_uint32(dev, "disabled", 0);
- qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
- qdev_prop_set_uint32(dev, "it_shift", 4);
- qdev_prop_set_chr(dev, "chrA", serial_hds[0]);
- qdev_prop_set_chr(dev, "chrB", serial_hds[1]);
- qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
- qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
- qdev_init_nofail(dev);
-
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, pic[0x24]);
- sysbus_connect_irq(s, 1, pic[0x25]);
-
- escc_mem = &ESCC(s)->mmio;
-
- memory_region_init_alias(escc_bar, NULL, "escc-bar",
- escc_mem, 0, memory_region_size(escc_mem));
-
- macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO);
+ /* MacIO */
+ macio = NEWWORLD_MACIO(pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO));
dev = DEVICE(macio);
qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */
- qdev_connect_gpio_out(dev, 1, pic[0x0d]); /* IDE */
- qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */
- qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */
- qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */
+ qdev_connect_gpio_out(dev, 1, pic[0x24]); /* ESCC-B */
+ qdev_connect_gpio_out(dev, 2, pic[0x25]); /* ESCC-A */
+ qdev_connect_gpio_out(dev, 3, pic[0x0d]); /* IDE */
+ qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */
+ qdev_connect_gpio_out(dev, 5, pic[0x0e]); /* IDE */
+ qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE DMA */
qdev_prop_set_uint64(dev, "frequency", tbfreq);
- macio_init(macio, pic_mem, escc_bar);
+ object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
+ &error_abort);
+ qdev_init_nofail(dev);
/* We only emulate 2 out of 3 IDE controllers for now */
ide_drive_get(hd, ARRAY_SIZE(hd));
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index d0d21d2392..935493c966 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -37,6 +37,7 @@
#include "hw/boards.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h"
+#include "hw/misc/macio/macio.h"
#include "hw/ide.h"
#include "hw/loader.h"
#include "elf.h"
@@ -92,19 +93,16 @@ static void ppc_heathrow_init(MachineState *machine)
uint32_t kernel_base, initrd_base, cmdline_base = 0;
int32_t kernel_size, initrd_size;
PCIBus *pci_bus;
- PCIDevice *macio;
+ OldWorldMacIOState *macio;
MACIOIDEState *macio_ide;
- DeviceState *dev;
+ DeviceState *dev, *pic_dev;
BusState *adb_bus;
int bios_size, ndrv_size;
uint8_t *ndrv_file;
- MemoryRegion *pic_mem;
- MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1);
uint16_t ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
uint64_t tbfreq;
- SysBusDevice *s;
linux_boot = (kernel_filename != NULL);
@@ -259,46 +257,32 @@ static void ppc_heathrow_init(MachineState *machine)
error_report("Only 6xx bus is supported on heathrow machine");
exit(1);
}
- pic = heathrow_pic_init(&pic_mem, 1, heathrow_irqs);
+ pic_dev = heathrow_pic_init(1, heathrow_irqs, &pic);
pci_bus = pci_grackle_init(0xfec00000, pic,
get_system_memory(),
get_system_io());
pci_vga_init(pci_bus);
- dev = qdev_create(NULL, TYPE_ESCC);
- qdev_prop_set_uint32(dev, "disabled", 0);
- qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
- qdev_prop_set_uint32(dev, "it_shift", 4);
- qdev_prop_set_chr(dev, "chrA", serial_hds[0]);
- qdev_prop_set_chr(dev, "chrB", serial_hds[1]);
- qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
- qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
- qdev_init_nofail(dev);
-
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, pic[0x10]);
- sysbus_connect_irq(s, 1, pic[0x0f]);
-
- escc_mem = &ESCC(s)->mmio;
-
- memory_region_init_alias(escc_bar, NULL, "escc-bar",
- escc_mem, 0, memory_region_size(escc_mem));
-
- for(i = 0; i < nb_nics; i++)
+ for (i = 0; i < nb_nics; i++) {
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
-
+ }
ide_drive_get(hd, ARRAY_SIZE(hd));
- macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO);
+ /* MacIO */
+ macio = OLDWORLD_MACIO(pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO));
dev = DEVICE(macio);
qdev_connect_gpio_out(dev, 0, pic[0x12]); /* CUDA */
- qdev_connect_gpio_out(dev, 1, pic[0x0D]); /* IDE-0 */
- qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE-0 DMA */
- qdev_connect_gpio_out(dev, 3, pic[0x0E]); /* IDE-1 */
- qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE-1 DMA */
+ qdev_connect_gpio_out(dev, 1, pic[0x10]); /* ESCC-B */
+ qdev_connect_gpio_out(dev, 2, pic[0x0F]); /* ESCC-A */
+ qdev_connect_gpio_out(dev, 3, pic[0x0D]); /* IDE-0 */
+ qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE-0 DMA */
+ qdev_connect_gpio_out(dev, 5, pic[0x0E]); /* IDE-1 */
+ qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE-1 DMA */
qdev_prop_set_uint64(dev, "frequency", tbfreq);
- macio_init(macio, pic_mem, escc_bar);
+ object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
+ &error_abort);
+ qdev_init_nofail(dev);
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
"ide[0]"));
diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c
new file mode 100644
index 0000000000..ab2626a9de
--- /dev/null
+++ b/hw/ppc/ppc440_pcix.c
@@ -0,0 +1,528 @@
+/*
+ * Emulation of the ibm,plb-pcix PCI controller
+ * This is found in some 440 SoCs e.g. the 460EX.
+ *
+ * Copyright (c) 2016-2018 BALATON Zoltan
+ *
+ * Derived from ppc4xx_pci.c and pci-host/ppce500.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "hw/hw.h"
+#include "hw/ppc/ppc.h"
+#include "hw/ppc/ppc4xx.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "exec/address-spaces.h"
+#include "trace.h"
+
+struct PLBOutMap {
+ uint64_t la;
+ uint64_t pcia;
+ uint32_t sa;
+ MemoryRegion mr;
+};
+
+struct PLBInMap {
+ uint64_t sa;
+ uint64_t la;
+ MemoryRegion mr;
+};
+
+#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host"
+#define PPC440_PCIX_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PPC440PCIXState, (obj), TYPE_PPC440_PCIX_HOST_BRIDGE)
+
+#define PPC440_PCIX_NR_POMS 3
+#define PPC440_PCIX_NR_PIMS 3
+
+typedef struct PPC440PCIXState {
+ PCIHostState parent_obj;
+
+ PCIDevice *dev;
+ struct PLBOutMap pom[PPC440_PCIX_NR_POMS];
+ struct PLBInMap pim[PPC440_PCIX_NR_PIMS];
+ uint32_t sts;
+ qemu_irq irq[PCI_NUM_PINS];
+ AddressSpace bm_as;
+ MemoryRegion bm;
+
+ MemoryRegion container;
+ MemoryRegion iomem;
+ MemoryRegion busmem;
+} PPC440PCIXState;
+
+#define PPC440_REG_BASE 0x80000
+#define PPC440_REG_SIZE 0xff
+
+#define PCIC0_CFGADDR 0x0
+#define PCIC0_CFGDATA 0x4
+
+#define PCIX0_POM0LAL 0x68
+#define PCIX0_POM0LAH 0x6c
+#define PCIX0_POM0SA 0x70
+#define PCIX0_POM0PCIAL 0x74
+#define PCIX0_POM0PCIAH 0x78
+#define PCIX0_POM1LAL 0x7c
+#define PCIX0_POM1LAH 0x80
+#define PCIX0_POM1SA 0x84
+#define PCIX0_POM1PCIAL 0x88
+#define PCIX0_POM1PCIAH 0x8c
+#define PCIX0_POM2SA 0x90
+
+#define PCIX0_PIM0SAL 0x98
+#define PCIX0_PIM0LAL 0x9c
+#define PCIX0_PIM0LAH 0xa0
+#define PCIX0_PIM1SA 0xa4
+#define PCIX0_PIM1LAL 0xa8
+#define PCIX0_PIM1LAH 0xac
+#define PCIX0_PIM2SAL 0xb0
+#define PCIX0_PIM2LAL 0xb4
+#define PCIX0_PIM2LAH 0xb8
+#define PCIX0_PIM0SAH 0xf8
+#define PCIX0_PIM2SAH 0xfc
+
+#define PCIX0_STS 0xe0
+
+#define PCI_ALL_SIZE (PPC440_REG_BASE + PPC440_REG_SIZE)
+
+static void ppc440_pcix_clear_region(MemoryRegion *parent,
+ MemoryRegion *mem)
+{
+ if (memory_region_is_mapped(mem)) {
+ memory_region_del_subregion(parent, mem);
+ object_unparent(OBJECT(mem));
+ }
+}
+
+/* DMA mapping */
+static void ppc440_pcix_update_pim(PPC440PCIXState *s, int idx)
+{
+ MemoryRegion *mem = &s->pim[idx].mr;
+ char *name;
+ uint64_t size;
+
+ /* Before we modify anything, unmap and destroy the region */
+ ppc440_pcix_clear_region(&s->bm, mem);
+
+ if (!(s->pim[idx].sa & 1)) {
+ /* Not enabled, nothing to do */
+ return;
+ }
+
+ name = g_strdup_printf("PCI Inbound Window %d", idx);
+ size = ~(s->pim[idx].sa & ~7ULL) + 1;
+ memory_region_init_alias(mem, OBJECT(s), name, get_system_memory(),
+ s->pim[idx].la, size);
+ memory_region_add_subregion_overlap(&s->bm, 0, mem, -1);
+ g_free(name);
+
+ trace_ppc440_pcix_update_pim(idx, size, s->pim[idx].la);
+}
+
+/* BAR mapping */
+static void ppc440_pcix_update_pom(PPC440PCIXState *s, int idx)
+{
+ MemoryRegion *mem = &s->pom[idx].mr;
+ MemoryRegion *address_space_mem = get_system_memory();
+ char *name;
+ uint32_t size;
+
+ /* Before we modify anything, unmap and destroy the region */
+ ppc440_pcix_clear_region(address_space_mem, mem);
+
+ if (!(s->pom[idx].sa & 1)) {
+ /* Not enabled, nothing to do */
+ return;
+ }
+
+ name = g_strdup_printf("PCI Outbound Window %d", idx);
+ size = ~(s->pom[idx].sa & 0xfffffffe) + 1;
+ if (!size) {
+ size = 0xffffffff;
+ }
+ memory_region_init_alias(mem, OBJECT(s), name, &s->busmem,
+ s->pom[idx].pcia, size);
+ memory_region_add_subregion(address_space_mem, s->pom[idx].la, mem);
+ g_free(name);
+
+ trace_ppc440_pcix_update_pom(idx, size, s->pom[idx].la, s->pom[idx].pcia);
+}
+
+static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ struct PPC440PCIXState *s = opaque;
+
+ trace_ppc440_pcix_reg_read(addr, val);
+ switch (addr) {
+ case PCI_VENDOR_ID ... PCI_MAX_LAT:
+ stl_le_p(s->dev->config + addr, val);
+ break;
+
+ case PCIX0_POM0LAL:
+ s->pom[0].la &= 0xffffffff00000000ULL;
+ s->pom[0].la |= val;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM0LAH:
+ s->pom[0].la &= 0xffffffffULL;
+ s->pom[0].la |= val << 32;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM0SA:
+ s->pom[0].sa = val;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM0PCIAL:
+ s->pom[0].pcia &= 0xffffffff00000000ULL;
+ s->pom[0].pcia |= val;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM0PCIAH:
+ s->pom[0].pcia &= 0xffffffffULL;
+ s->pom[0].pcia |= val << 32;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM1LAL:
+ s->pom[1].la &= 0xffffffff00000000ULL;
+ s->pom[1].la |= val;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM1LAH:
+ s->pom[1].la &= 0xffffffffULL;
+ s->pom[1].la |= val << 32;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM1SA:
+ s->pom[1].sa = val;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM1PCIAL:
+ s->pom[1].pcia &= 0xffffffff00000000ULL;
+ s->pom[1].pcia |= val;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM1PCIAH:
+ s->pom[1].pcia &= 0xffffffffULL;
+ s->pom[1].pcia |= val << 32;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM2SA:
+ s->pom[2].sa = val;
+ break;
+
+ case PCIX0_PIM0SAL:
+ s->pim[0].sa &= 0xffffffff00000000ULL;
+ s->pim[0].sa |= val;
+ ppc440_pcix_update_pim(s, 0);
+ break;
+ case PCIX0_PIM0LAL:
+ s->pim[0].la &= 0xffffffff00000000ULL;
+ s->pim[0].la |= val;
+ ppc440_pcix_update_pim(s, 0);
+ break;
+ case PCIX0_PIM0LAH:
+ s->pim[0].la &= 0xffffffffULL;
+ s->pim[0].la |= val << 32;
+ ppc440_pcix_update_pim(s, 0);
+ break;
+ case PCIX0_PIM1SA:
+ s->pim[1].sa = val;
+ ppc440_pcix_update_pim(s, 1);
+ break;
+ case PCIX0_PIM1LAL:
+ s->pim[1].la &= 0xffffffff00000000ULL;
+ s->pim[1].la |= val;
+ ppc440_pcix_update_pim(s, 1);
+ break;
+ case PCIX0_PIM1LAH:
+ s->pim[1].la &= 0xffffffffULL;
+ s->pim[1].la |= val << 32;
+ ppc440_pcix_update_pim(s, 1);
+ break;
+ case PCIX0_PIM2SAL:
+ s->pim[2].sa &= 0xffffffff00000000ULL;
+ s->pim[2].sa = val;
+ ppc440_pcix_update_pim(s, 2);
+ break;
+ case PCIX0_PIM2LAL:
+ s->pim[2].la &= 0xffffffff00000000ULL;
+ s->pim[2].la |= val;
+ ppc440_pcix_update_pim(s, 2);
+ break;
+ case PCIX0_PIM2LAH:
+ s->pim[2].la &= 0xffffffffULL;
+ s->pim[2].la |= val << 32;
+ ppc440_pcix_update_pim(s, 2);
+ break;
+
+ case PCIX0_STS:
+ s->sts = val;
+ break;
+
+ case PCIX0_PIM0SAH:
+ s->pim[0].sa &= 0xffffffffULL;
+ s->pim[0].sa |= val << 32;
+ ppc440_pcix_update_pim(s, 0);
+ break;
+ case PCIX0_PIM2SAH:
+ s->pim[2].sa &= 0xffffffffULL;
+ s->pim[2].sa |= val << 32;
+ ppc440_pcix_update_pim(s, 2);
+ break;
+
+ default:
+ error_report("%s: unhandled PCI internal register 0x%lx", __func__,
+ (unsigned long)addr);
+ break;
+ }
+}
+
+static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ struct PPC440PCIXState *s = opaque;
+ uint32_t val;
+
+ switch (addr) {
+ case PCI_VENDOR_ID ... PCI_MAX_LAT:
+ val = ldl_le_p(s->dev->config + addr);
+ break;
+
+ case PCIX0_POM0LAL:
+ val = s->pom[0].la;
+ break;
+ case PCIX0_POM0LAH:
+ val = s->pom[0].la >> 32;
+ break;
+ case PCIX0_POM0SA:
+ val = s->pom[0].sa;
+ break;
+ case PCIX0_POM0PCIAL:
+ val = s->pom[0].pcia;
+ break;
+ case PCIX0_POM0PCIAH:
+ val = s->pom[0].pcia >> 32;
+ break;
+ case PCIX0_POM1LAL:
+ val = s->pom[1].la;
+ break;
+ case PCIX0_POM1LAH:
+ val = s->pom[1].la >> 32;
+ break;
+ case PCIX0_POM1SA:
+ val = s->pom[1].sa;
+ break;
+ case PCIX0_POM1PCIAL:
+ val = s->pom[1].pcia;
+ break;
+ case PCIX0_POM1PCIAH:
+ val = s->pom[1].pcia >> 32;
+ break;
+ case PCIX0_POM2SA:
+ val = s->pom[2].sa;
+ break;
+
+ case PCIX0_PIM0SAL:
+ val = s->pim[0].sa;
+ break;
+ case PCIX0_PIM0LAL:
+ val = s->pim[0].la;
+ break;
+ case PCIX0_PIM0LAH:
+ val = s->pim[0].la >> 32;
+ break;
+ case PCIX0_PIM1SA:
+ val = s->pim[1].sa;
+ break;
+ case PCIX0_PIM1LAL:
+ val = s->pim[1].la;
+ break;
+ case PCIX0_PIM1LAH:
+ val = s->pim[1].la >> 32;
+ break;
+ case PCIX0_PIM2SAL:
+ val = s->pim[2].sa;
+ break;
+ case PCIX0_PIM2LAL:
+ val = s->pim[2].la;
+ break;
+ case PCIX0_PIM2LAH:
+ val = s->pim[2].la >> 32;
+ break;
+
+ case PCIX0_STS:
+ val = s->sts;
+ break;
+
+ case PCIX0_PIM0SAH:
+ val = s->pim[0].sa >> 32;
+ break;
+ case PCIX0_PIM2SAH:
+ val = s->pim[2].sa >> 32;
+ break;
+
+ default:
+ error_report("%s: invalid PCI internal register 0x%lx", __func__,
+ (unsigned long)addr);
+ val = 0;
+ }
+
+ trace_ppc440_pcix_reg_read(addr, val);
+ return val;
+}
+
+static const MemoryRegionOps pci_reg_ops = {
+ .read = ppc440_pcix_reg_read4,
+ .write = ppc440_pcix_reg_write4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ppc440_pcix_reset(DeviceState *dev)
+{
+ struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev);
+ int i;
+
+ for (i = 0; i < PPC440_PCIX_NR_POMS; i++) {
+ ppc440_pcix_clear_region(get_system_memory(), &s->pom[i].mr);
+ }
+ for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
+ ppc440_pcix_clear_region(&s->bm, &s->pim[i].mr);
+ }
+ memset(s->pom, 0, sizeof(s->pom));
+ memset(s->pim, 0, sizeof(s->pim));
+ for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
+ s->pim[i].sa = 0xffffffff00000000ULL;
+ }
+ s->sts = 0;
+}
+
+/* All pins from each slot are tied to a single board IRQ.
+ * This may need further refactoring for other boards. */
+static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+ int slot = pci_dev->devfn >> 3;
+ trace_ppc440_pcix_map_irq(pci_dev->devfn, irq_num, slot);
+ return slot - 1;
+}
+
+static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level)
+{
+ qemu_irq *pci_irqs = opaque;
+
+ trace_ppc440_pcix_set_irq(irq_num);
+ if (irq_num < 0) {
+ error_report("%s: PCI irq %d", __func__, irq_num);
+ return;
+ }
+ qemu_set_irq(pci_irqs[irq_num], level);
+}
+
+static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn)
+{
+ PPC440PCIXState *s = opaque;
+
+ return &s->bm_as;
+}
+
+/* The default pci_host_data_{read,write} functions in pci/pci_host.c
+ * deny access to registers without bit 31 set but our clients want
+ * this to work so we have to override these here */
+static void pci_host_data_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned len)
+{
+ PCIHostState *s = opaque;
+ pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
+}
+
+static uint64_t pci_host_data_read(void *opaque,
+ hwaddr addr, unsigned len)
+{
+ PCIHostState *s = opaque;
+ uint32_t val;
+ val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
+ return val;
+}
+
+const MemoryRegionOps ppc440_pcix_host_data_ops = {
+ .read = pci_host_data_read,
+ .write = pci_host_data_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int ppc440_pcix_initfn(SysBusDevice *dev)
+{
+ PPC440PCIXState *s;
+ PCIHostState *h;
+ int i;
+
+ h = PCI_HOST_BRIDGE(dev);
+ s = PPC440_PCIX_HOST_BRIDGE(dev);
+
+ for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+ sysbus_init_irq(dev, &s->irq[i]);
+ }
+
+ memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX);
+ h->bus = pci_register_root_bus(DEVICE(dev), NULL, ppc440_pcix_set_irq,
+ ppc440_pcix_map_irq, s->irq, &s->busmem,
+ get_system_io(), PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
+
+ s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge");
+
+ memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX);
+ memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
+ address_space_init(&s->bm_as, &s->bm, "pci-bm");
+ pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s);
+
+ memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE);
+ memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops,
+ h, "pci-conf-idx", 4);
+ memory_region_init_io(&h->data_mem, OBJECT(s), &ppc440_pcix_host_data_ops,
+ h, "pci-conf-data", 4);
+ memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s,
+ "pci.reg", PPC440_REG_SIZE);
+ memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
+ memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
+ memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem);
+ sysbus_init_mmio(dev, &s->container);
+
+ return 0;
+}
+
+static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = ppc440_pcix_initfn;
+ dc->reset = ppc440_pcix_reset;
+}
+
+static const TypeInfo ppc440_pcix_info = {
+ .name = TYPE_PPC440_PCIX_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
+ .instance_size = sizeof(PPC440PCIXState),
+ .class_init = ppc440_pcix_class_init,
+};
+
+static void ppc440_pcix_register_types(void)
+{
+ type_register_static(&ppc440_pcix_info);
+}
+
+type_init(ppc440_pcix_register_types)
diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
index 4e2523a64f..976ab2b5d8 100644
--- a/hw/ppc/ppc440_uc.c
+++ b/hw/ppc/ppc440_uc.c
@@ -1050,6 +1050,9 @@ static void ppc460ex_pcie_realize(DeviceState *dev, Error **errp)
case DCRN_PCIE1_BASE:
id = 1;
break;
+ default:
+ error_setg(errp, "invalid PCIe DCRN base");
+ return;
}
snprintf(buf, sizeof(buf), "pcie%d-io", id);
memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX);
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
new file mode 100644
index 0000000000..70b8e76d9c
--- /dev/null
+++ b/hw/ppc/sam460ex.c
@@ -0,0 +1,603 @@
+/*
+ * QEMU aCube Sam460ex board emulation
+ *
+ * Copyright (c) 2012 François Revol
+ * Copyright (c) 2016-2018 BALATON Zoltan
+ *
+ * This file is derived from hw/ppc440_bamboo.c,
+ * the copyright for that material belongs to the original owners.
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "sysemu/blockdev.h"
+#include "hw/boards.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+#include "sysemu/device_tree.h"
+#include "sysemu/block-backend.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "hw/ppc/ppc440.h"
+#include "hw/ppc/ppc405.h"
+#include "hw/block/flash.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+#include "hw/sysbus.h"
+#include "hw/char/serial.h"
+#include "hw/i2c/ppc4xx_i2c.h"
+#include "hw/i2c/smbus.h"
+#include "hw/usb/hcd-ehci.h"
+
+#define BINARY_DEVICE_TREE_FILE "canyonlands.dtb"
+#define UBOOT_FILENAME "u-boot-sam460-20100605.bin"
+/* to extract the official U-Boot bin from the updater: */
+/* dd bs=1 skip=$(($(stat -c '%s' updater/updater-460) - 0x80000)) \
+ if=updater/updater-460 of=u-boot-sam460-20100605.bin */
+
+/* from Sam460 U-Boot include/configs/Sam460ex.h */
+#define FLASH_BASE 0xfff00000
+#define FLASH_BASE_H 0x4
+#define FLASH_SIZE (1 << 20)
+#define UBOOT_LOAD_BASE 0xfff80000
+#define UBOOT_SIZE 0x00080000
+#define UBOOT_ENTRY 0xfffffffc
+
+/* from U-Boot */
+#define EPAPR_MAGIC (0x45504150)
+#define KERNEL_ADDR 0x1000000
+#define FDT_ADDR 0x1800000
+#define RAMDISK_ADDR 0x1900000
+
+/* Sam460ex IRQ MAP:
+ IRQ0 = ETH_INT
+ IRQ1 = FPGA_INT
+ IRQ2 = PCI_INT (PCIA, PCIB, PCIC, PCIB)
+ IRQ3 = FPGA_INT2
+ IRQ11 = RTC_INT
+ IRQ12 = SM502_INT
+*/
+
+#define SDRAM_NR_BANKS 4
+
+/* FIXME: See u-boot.git 8ac41e, also fix in ppc440_uc.c */
+static const unsigned int ppc460ex_sdram_bank_sizes[] = {
+ 1024 << 20, 512 << 20, 256 << 20, 128 << 20, 64 << 20, 32 << 20, 0
+};
+
+struct boot_info {
+ uint32_t dt_base;
+ uint32_t dt_size;
+ uint32_t entry;
+};
+
+/*****************************************************************************/
+/* SPD eeprom content from mips_malta.c */
+
+struct _eeprom24c0x_t {
+ uint8_t tick;
+ uint8_t address;
+ uint8_t command;
+ uint8_t ack;
+ uint8_t scl;
+ uint8_t sda;
+ uint8_t data;
+ uint8_t contents[256];
+};
+
+typedef struct _eeprom24c0x_t eeprom24c0x_t;
+
+static eeprom24c0x_t spd_eeprom = {
+ .contents = {
+ /* 00000000: */ 0x80, 0x08, 0xFF, 0x0D, 0x0A, 0xFF, 0x40, 0x00,
+ /* 00000008: */ 0x04, 0x75, 0x54, 0x00, 0x82, 0x08, 0x00, 0x01,
+ /* 00000010: */ 0x8F, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
+ /* 00000018: */ 0x00, 0x00, 0x00, 0x14, 0x0F, 0x14, 0x2D, 0xFF,
+ /* 00000020: */ 0x15, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00,
+ /* 00000028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xD0,
+ /* 00000040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xF4,
+ },
+};
+
+static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
+{
+ enum { SDR = 0x4, DDR1 = 0x7, DDR2 = 0x8 } type;
+ uint8_t *spd = spd_eeprom.contents;
+ uint8_t nbanks = 0;
+ uint16_t density = 0;
+ int i;
+
+ /* work in terms of MB */
+ ram_size >>= 20;
+
+ while ((ram_size >= 4) && (nbanks <= 2)) {
+ int sz_log2 = MIN(31 - clz32(ram_size), 14);
+ nbanks++;
+ density |= 1 << (sz_log2 - 2);
+ ram_size -= 1 << sz_log2;
+ }
+
+ /* split to 2 banks if possible */
+ if ((nbanks == 1) && (density > 1)) {
+ nbanks++;
+ density >>= 1;
+ }
+
+ if (density & 0xff00) {
+ density = (density & 0xe0) | ((density >> 8) & 0x1f);
+ type = DDR2;
+ } else if (!(density & 0x1f)) {
+ type = DDR2;
+ } else {
+ type = SDR;
+ }
+
+ if (ram_size) {
+ warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB"
+ " of SDRAM", ram_size);
+ }
+
+ /* fill in SPD memory information */
+ spd[2] = type;
+ spd[5] = nbanks;
+ spd[31] = density;
+
+ /* XXX: this is totally random */
+ spd[9] = 0x10; /* CAS tcyc */
+ spd[18] = 0x20; /* CAS bit */
+ spd[23] = 0x10; /* CAS tcyc */
+ spd[25] = 0x10; /* CAS tcyc */
+
+ /* checksum */
+ spd[63] = 0;
+ for (i = 0; i < 63; i++) {
+ spd[63] += spd[i];
+ }
+
+ /* copy for SMBUS */
+ memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
+}
+
+static void generate_eeprom_serial(uint8_t *eeprom)
+{
+ int i, pos = 0;
+ uint8_t mac[6] = { 0x00 };
+ uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
+
+ /* version */
+ eeprom[pos++] = 0x01;
+
+ /* count */
+ eeprom[pos++] = 0x02;
+
+ /* MAC address */
+ eeprom[pos++] = 0x01; /* MAC */
+ eeprom[pos++] = 0x06; /* length */
+ memcpy(&eeprom[pos], mac, sizeof(mac));
+ pos += sizeof(mac);
+
+ /* serial number */
+ eeprom[pos++] = 0x02; /* serial */
+ eeprom[pos++] = 0x05; /* length */
+ memcpy(&eeprom[pos], sn, sizeof(sn));
+ pos += sizeof(sn);
+
+ /* checksum */
+ eeprom[pos] = 0;
+ for (i = 0; i < pos; i++) {
+ eeprom[pos] += eeprom[i];
+ }
+}
+
+/*****************************************************************************/
+
+static int sam460ex_load_uboot(void)
+{
+ DriveInfo *dinfo;
+ BlockBackend *blk = NULL;
+ hwaddr base = FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32);
+ long bios_size = FLASH_SIZE;
+ int fl_sectors;
+
+ dinfo = drive_get(IF_PFLASH, 0, 0);
+ if (dinfo) {
+ blk = blk_by_legacy_dinfo(dinfo);
+ bios_size = blk_getlength(blk);
+ }
+ fl_sectors = (bios_size + 65535) >> 16;
+
+ if (!pflash_cfi01_register(base, NULL, "sam460ex.flash", bios_size,
+ blk, (64 * 1024), fl_sectors,
+ 1, 0x89, 0x18, 0x0000, 0x0, 1)) {
+ error_report("qemu: Error registering flash memory.");
+ /* XXX: return an error instead? */
+ exit(1);
+ }
+
+ if (!blk) {
+ /*error_report("No flash image given with the 'pflash' parameter,"
+ " using default u-boot image");*/
+ base = UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32);
+ rom_add_file_fixed(UBOOT_FILENAME, base, -1);
+ }
+
+ return 0;
+}
+
+static int sam460ex_load_device_tree(hwaddr addr,
+ uint32_t ramsize,
+ hwaddr initrd_base,
+ hwaddr initrd_size,
+ const char *kernel_cmdline)
+{
+ int ret = -1;
+ uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
+ char *filename;
+ int fdt_size;
+ void *fdt;
+ uint32_t tb_freq = 50000000;
+ uint32_t clock_freq = 50000000;
+
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+ if (!filename) {
+ goto out;
+ }
+ fdt = load_device_tree(filename, &fdt_size);
+ g_free(filename);
+ if (fdt == NULL) {
+ goto out;
+ }
+
+ /* Manipulate device tree in memory. */
+
+ ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
+ sizeof(mem_reg_property));
+ if (ret < 0) {
+ error_report("couldn't set /memory/reg");
+ }
+
+ /* default FDT doesn't have a /chosen node... */
+ qemu_fdt_add_subnode(fdt, "/chosen");
+
+ ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_base);
+ if (ret < 0) {
+ error_report("couldn't set /chosen/linux,initrd-start");
+ }
+
+ ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ (initrd_base + initrd_size));
+ if (ret < 0) {
+ error_report("couldn't set /chosen/linux,initrd-end");
+ }
+
+ ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
+ kernel_cmdline);
+ if (ret < 0) {
+ error_report("couldn't set /chosen/bootargs");
+ }
+
+ /* Copy data from the host device tree into the guest. Since the guest can
+ * directly access the timebase without host involvement, we must expose
+ * the correct frequencies. */
+ if (kvm_enabled()) {
+ tb_freq = kvmppc_get_tbfreq();
+ clock_freq = kvmppc_get_clockfreq();
+ }
+
+ qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
+ clock_freq);
+ qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
+ tb_freq);
+
+ rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
+ g_free(fdt);
+ ret = fdt_size;
+
+out:
+
+ return ret;
+}
+
+/* Create reset TLB entries for BookE, mapping only the flash memory. */
+static void mmubooke_create_initial_mapping_uboot(CPUPPCState *env)
+{
+ ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+ /* on reset the flash is mapped by a shadow TLB,
+ * but since we don't implement them we need to use
+ * the same values U-Boot will use to avoid a fault.
+ */
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 0x10000000; /* up to 0xffffffff */
+ tlb->EPN = 0xf0000000 & TARGET_PAGE_MASK;
+ tlb->RPN = (0xf0000000 & TARGET_PAGE_MASK) | 0x4;
+ tlb->PID = 0;
+}
+
+/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
+static void mmubooke_create_initial_mapping(CPUPPCState *env,
+ target_ulong va,
+ hwaddr pa)
+{
+ ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 1 << 31; /* up to 0x80000000 */
+ tlb->EPN = va & TARGET_PAGE_MASK;
+ tlb->RPN = pa & TARGET_PAGE_MASK;
+ tlb->PID = 0;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ PowerPCCPU *cpu = opaque;
+ CPUPPCState *env = &cpu->env;
+ struct boot_info *bi = env->load_info;
+
+ cpu_reset(CPU(cpu));
+
+ /* either we have a kernel to boot or we jump to U-Boot */
+ if (bi->entry != UBOOT_ENTRY) {
+ env->gpr[1] = (16 << 20) - 8;
+ env->gpr[3] = FDT_ADDR;
+ env->nip = bi->entry;
+
+ /* Create a mapping for the kernel. */
+ mmubooke_create_initial_mapping(env, 0, 0);
+ env->gpr[6] = tswap32(EPAPR_MAGIC);
+ env->gpr[7] = (16 << 20) - 8; /*bi->ima_size;*/
+
+ } else {
+ env->nip = UBOOT_ENTRY;
+ mmubooke_create_initial_mapping_uboot(env);
+ }
+}
+
+static void sam460ex_init(MachineState *machine)
+{
+ MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *isa = g_new(MemoryRegion, 1);
+ MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS);
+ hwaddr ram_bases[SDRAM_NR_BANKS];
+ hwaddr ram_sizes[SDRAM_NR_BANKS];
+ MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
+ qemu_irq *irqs, *uic[4];
+ PCIBus *pci_bus;
+ PowerPCCPU *cpu;
+ CPUPPCState *env;
+ PPC4xxI2CState *i2c[2];
+ hwaddr entry = UBOOT_ENTRY;
+ hwaddr loadaddr = 0;
+ target_long initrd_size = 0;
+ DeviceState *dev;
+ SysBusDevice *sbdev;
+ int success;
+ int i;
+ struct boot_info *boot_info;
+ const size_t smbus_eeprom_size = 8 * 256;
+ uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
+
+ cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+ env = &cpu->env;
+ if (env->mmu_model != POWERPC_MMU_BOOKE) {
+ error_report("Only MMU model BookE is supported by this machine.");
+ exit(1);
+ }
+
+#ifdef TARGET_PPCEMB
+ if (!qtest_enabled()) {
+ warn_report("qemu-system-ppcemb is deprecated, "
+ "please use qemu-system-ppc instead.");
+ }
+#endif
+
+ qemu_register_reset(main_cpu_reset, cpu);
+ boot_info = g_malloc0(sizeof(*boot_info));
+ env->load_info = boot_info;
+
+ ppc_booke_timers_init(cpu, 50000000, 0);
+ ppc_dcr_init(env, NULL, NULL);
+
+ /* PLB arbitrer */
+ ppc4xx_plb_init(env);
+
+ /* interrupt controllers */
+ irqs = g_malloc0(sizeof(*irqs) * PPCUIC_OUTPUT_NB);
+ irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+ irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+ uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
+ uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
+ uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
+ uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
+
+ /* SDRAM controller */
+ memset(ram_bases, 0, sizeof(ram_bases));
+ memset(ram_sizes, 0, sizeof(ram_sizes));
+ /* put all RAM on first bank because board has one slot
+ * and firmware only checks that */
+ machine->ram_size = ppc4xx_sdram_adjust(machine->ram_size, 1,
+ ram_memories, ram_bases, ram_sizes,
+ ppc460ex_sdram_bank_sizes);
+
+ /* FIXME: does 460EX have ECC interrupts? */
+ ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories,
+ ram_bases, ram_sizes, 1);
+
+ /* generate SPD EEPROM data */
+ for (i = 0; i < SDRAM_NR_BANKS; i++) {
+ generate_eeprom_spd(&smbus_eeprom_buf[i * 256], ram_sizes[i]);
+ }
+ generate_eeprom_serial(&smbus_eeprom_buf[4 * 256]);
+ generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
+
+ /* IIC controllers */
+ dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
+ i2c[0] = PPC4xx_I2C(dev);
+ object_property_set_bool(OBJECT(dev), true, "realized", NULL);
+ smbus_eeprom_init(i2c[0]->bus, 8, smbus_eeprom_buf, smbus_eeprom_size);
+ g_free(smbus_eeprom_buf);
+
+ dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
+ i2c[1] = PPC4xx_I2C(dev);
+
+ /* External bus controller */
+ ppc405_ebc_init(env);
+
+ /* CPR */
+ ppc4xx_cpr_init(env);
+
+ /* PLB to AHB bridge */
+ ppc4xx_ahb_init(env);
+
+ /* System DCRs */
+ ppc4xx_sdr_init(env);
+
+ /* MAL */
+ ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
+
+ /* 256K of L2 cache as memory */
+ ppc4xx_l2sram_init(env);
+ /* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */
+ memory_region_init_ram(l2cache_ram, NULL, "ppc440.l2cache_ram", 256 << 10,
+ &error_abort);
+ memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
+
+ /* USB */
+ sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]);
+ dev = qdev_create(NULL, "sysbus-ohci");
+ qdev_prop_set_string(dev, "masterbus", "usb-bus.0");
+ qdev_prop_set_uint32(dev, "num-ports", 6);
+ qdev_init_nofail(dev);
+ sbdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(sbdev, 0, 0x4bffd0000);
+ sysbus_connect_irq(sbdev, 0, uic[2][30]);
+ usb_create_simple(usb_bus_find(-1), "usb-kbd");
+ usb_create_simple(usb_bus_find(-1), "usb-mouse");
+
+ /* PCI bus */
+ ppc460ex_pcie_init(env);
+ /* FIXME: is this correct? */
+ dev = sysbus_create_varargs("ppc440-pcix-host", 0xc0ec00000,
+ uic[1][0], uic[1][20], uic[1][21], uic[1][22],
+ NULL);
+ pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+ if (!pci_bus) {
+ error_report("couldn't create PCI controller!");
+ exit(1);
+ }
+ memory_region_init_alias(isa, NULL, "isa_mmio", get_system_io(),
+ 0, 0x10000);
+ memory_region_add_subregion(get_system_memory(), 0xc08000000, isa);
+
+ /* PCI devices */
+ pci_create_simple(pci_bus, PCI_DEVFN(6, 0), "sm501");
+ /* SoC has a single SATA port but we don't emulate that yet
+ * However, firmware and usual clients have driver for SiI311x
+ * so add one for convenience by default */
+ if (defaults_enabled()) {
+ pci_create_simple(pci_bus, -1, "sii3112");
+ }
+
+ /* SoC has 4 UARTs
+ * but board has only one wired and two are present in fdt */
+ if (serial_hds[0] != NULL) {
+ serial_mm_init(address_space_mem, 0x4ef600300, 0, uic[1][1],
+ PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+ DEVICE_BIG_ENDIAN);
+ }
+ if (serial_hds[1] != NULL) {
+ serial_mm_init(address_space_mem, 0x4ef600400, 0, uic[0][1],
+ PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+ DEVICE_BIG_ENDIAN);
+ }
+
+ /* Load U-Boot image. */
+ if (!machine->kernel_filename) {
+ success = sam460ex_load_uboot();
+ if (success < 0) {
+ error_report("qemu: could not load firmware");
+ exit(1);
+ }
+ }
+
+ /* Load kernel. */
+ if (machine->kernel_filename) {
+ success = load_uimage(machine->kernel_filename, &entry, &loadaddr,
+ NULL, NULL, NULL);
+ if (success < 0) {
+ uint64_t elf_entry, elf_lowaddr;
+
+ success = load_elf(machine->kernel_filename, NULL, NULL, &elf_entry,
+ &elf_lowaddr, NULL, 1, PPC_ELF_MACHINE, 0, 0);
+ entry = elf_entry;
+ loadaddr = elf_lowaddr;
+ }
+ /* XXX try again as binary */
+ if (success < 0) {
+ error_report("qemu: could not load kernel '%s'",
+ machine->kernel_filename);
+ exit(1);
+ }
+ }
+
+ /* Load initrd. */
+ if (machine->initrd_filename) {
+ initrd_size = load_image_targphys(machine->initrd_filename,
+ RAMDISK_ADDR,
+ machine->ram_size - RAMDISK_ADDR);
+ if (initrd_size < 0) {
+ error_report("qemu: could not load ram disk '%s' at %x",
+ machine->initrd_filename, RAMDISK_ADDR);
+ exit(1);
+ }
+ }
+
+ /* If we're loading a kernel directly, we must load the device tree too. */
+ if (machine->kernel_filename) {
+ int dt_size;
+
+ dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size,
+ RAMDISK_ADDR, initrd_size,
+ machine->kernel_cmdline);
+ if (dt_size < 0) {
+ error_report("couldn't load device tree");
+ exit(1);
+ }
+
+ boot_info->dt_base = FDT_ADDR;
+ boot_info->dt_size = dt_size;
+ }
+
+ boot_info->entry = entry;
+}
+
+static void sam460ex_machine_init(MachineClass *mc)
+{
+ mc->desc = "aCube Sam460ex";
+ mc->init = sam460ex_init;
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("460exb");
+ mc->default_ram_size = 512 * M_BYTE;
+}
+
+DEFINE_MACHINE("sam460ex", sam460ex_machine_init)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 83c9d66dd5..7e1c858566 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -105,12 +105,14 @@
*/
static int spapr_vcpu_id(sPAPRMachineState *spapr, int cpu_index)
{
+ assert(spapr->vsmt);
return
(cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
}
static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr,
PowerPCCPU *cpu)
{
+ assert(spapr->vsmt);
return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
}
@@ -177,13 +179,13 @@ static void pre_2_10_vmstate_unregister_dummy_icp(int i)
static int xics_max_server_number(sPAPRMachineState *spapr)
{
+ assert(spapr->vsmt);
return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
}
static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
if (kvm_enabled()) {
if (machine_kernel_irqchip_allowed(machine) &&
@@ -205,17 +207,6 @@ static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
return;
}
}
-
- if (smc->pre_2_10_has_unused_icps) {
- int i;
-
- for (i = 0; i < xics_max_server_number(spapr); i++) {
- /* Dummy entries get deregistered when real ICPState objects
- * are registered during CPU core hotplug.
- */
- pre_2_10_vmstate_register_dummy_icp(i);
- }
- }
}
static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
@@ -1062,7 +1053,14 @@ static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
}
if (!spapr->has_graphics && stdout_path) {
+ /*
+ * "linux,stdout-path" and "stdout" properties are deprecated by linux
+ * kernel. New platforms should only use the "stdout-path" property. Set
+ * the new property and continue using older property to remain
+ * compatible with the existing firmware.
+ */
_FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
+ _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
}
spapr_dt_ov5_platform_support(fdt, chosen);
@@ -2232,61 +2230,6 @@ static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
return &ms->possible_cpus->cpus[index];
}
-static void spapr_init_cpus(sPAPRMachineState *spapr)
-{
- MachineState *machine = MACHINE(spapr);
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- const char *type = spapr_get_cpu_core_type(machine->cpu_type);
- const CPUArchIdList *possible_cpus;
- int boot_cores_nr = smp_cpus / smp_threads;
- int i;
-
- possible_cpus = mc->possible_cpu_arch_ids(machine);
- if (mc->has_hotpluggable_cpus) {
- if (smp_cpus % smp_threads) {
- error_report("smp_cpus (%u) must be multiple of threads (%u)",
- smp_cpus, smp_threads);
- exit(1);
- }
- if (max_cpus % smp_threads) {
- error_report("max_cpus (%u) must be multiple of threads (%u)",
- max_cpus, smp_threads);
- exit(1);
- }
- } else {
- if (max_cpus != smp_cpus) {
- error_report("This machine version does not support CPU hotplug");
- exit(1);
- }
- boot_cores_nr = possible_cpus->len;
- }
-
- for (i = 0; i < possible_cpus->len; i++) {
- int core_id = i * smp_threads;
-
- if (mc->has_hotpluggable_cpus) {
- spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
- spapr_vcpu_id(spapr, core_id));
- }
-
- if (i < boot_cores_nr) {
- Object *core = object_new(type);
- int nr_threads = smp_threads;
-
- /* Handle the partially filled core for older machine types */
- if ((i + 1) * smp_threads >= smp_cpus) {
- nr_threads = smp_cpus - i * smp_threads;
- }
-
- object_property_set_int(core, nr_threads, "nr-threads",
- &error_fatal);
- object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
- &error_fatal);
- object_property_set_bool(core, true, "realized", &error_fatal);
- }
- }
-}
-
static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp)
{
Error *local_err = NULL;
@@ -2359,6 +2302,78 @@ out:
error_propagate(errp, local_err);
}
+static void spapr_init_cpus(sPAPRMachineState *spapr)
+{
+ MachineState *machine = MACHINE(spapr);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
+ const char *type = spapr_get_cpu_core_type(machine->cpu_type);
+ const CPUArchIdList *possible_cpus;
+ int boot_cores_nr = smp_cpus / smp_threads;
+ int i;
+
+ possible_cpus = mc->possible_cpu_arch_ids(machine);
+ if (mc->has_hotpluggable_cpus) {
+ if (smp_cpus % smp_threads) {
+ error_report("smp_cpus (%u) must be multiple of threads (%u)",
+ smp_cpus, smp_threads);
+ exit(1);
+ }
+ if (max_cpus % smp_threads) {
+ error_report("max_cpus (%u) must be multiple of threads (%u)",
+ max_cpus, smp_threads);
+ exit(1);
+ }
+ } else {
+ if (max_cpus != smp_cpus) {
+ error_report("This machine version does not support CPU hotplug");
+ exit(1);
+ }
+ boot_cores_nr = possible_cpus->len;
+ }
+
+ /* VSMT must be set in order to be able to compute VCPU ids, ie to
+ * call xics_max_server_number() or spapr_vcpu_id().
+ */
+ spapr_set_vsmt_mode(spapr, &error_fatal);
+
+ if (smc->pre_2_10_has_unused_icps) {
+ int i;
+
+ for (i = 0; i < xics_max_server_number(spapr); i++) {
+ /* Dummy entries get deregistered when real ICPState objects
+ * are registered during CPU core hotplug.
+ */
+ pre_2_10_vmstate_register_dummy_icp(i);
+ }
+ }
+
+ for (i = 0; i < possible_cpus->len; i++) {
+ int core_id = i * smp_threads;
+
+ if (mc->has_hotpluggable_cpus) {
+ spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
+ spapr_vcpu_id(spapr, core_id));
+ }
+
+ if (i < boot_cores_nr) {
+ Object *core = object_new(type);
+ int nr_threads = smp_threads;
+
+ /* Handle the partially filled core for older machine types */
+ if ((i + 1) * smp_threads >= smp_cpus) {
+ nr_threads = smp_cpus - i * smp_threads;
+ }
+
+ object_property_set_int(core, nr_threads, "nr-threads",
+ &error_fatal);
+ object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
+ &error_fatal);
+ object_property_set_bool(core, true, "realized", &error_fatal);
+ }
+ }
+}
+
/* pSeries LPAR / sPAPR hardware init */
static void spapr_machine_init(MachineState *machine)
{
@@ -2486,8 +2501,6 @@ static void spapr_machine_init(MachineState *machine)
}
/* init CPUs */
- spapr_set_vsmt_mode(spapr, &error_fatal);
-
spapr_init_cpus(spapr);
if (kvm_enabled()) {
@@ -3810,13 +3823,7 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
int spapr_get_vcpu_id(PowerPCCPU *cpu)
{
- CPUState *cs = CPU(cpu);
-
- if (kvm_enabled()) {
- return kvm_arch_vcpu_id(cs);
- } else {
- return cs->cpu_index;
- }
+ return cpu->vcpu_id;
}
void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
@@ -3983,6 +3990,23 @@ static void spapr_machine_2_12_class_options(MachineClass *mc)
DEFINE_SPAPR_MACHINE(2_12, "2.12", true);
+static void spapr_machine_2_12_sxxm_instance_options(MachineState *machine)
+{
+ spapr_machine_2_12_instance_options(machine);
+}
+
+static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
+{
+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+
+ spapr_machine_2_12_class_options(mc);
+ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
+ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
+ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
+}
+
+DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
+
/*
* pseries-2.11
*/
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 99a4b71d19..531e145114 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -32,6 +32,20 @@
#include "hw/ppc/spapr.h"
+typedef struct sPAPRCapPossible {
+ int num; /* size of vals array below */
+ const char *help; /* help text for vals */
+ /*
+ * Note:
+ * - because of the way compatibility is determined vals MUST be ordered
+ * such that later options are a superset of all preceding options.
+ * - the order of vals must be preserved, that is their index is important,
+ * however vals may be added to the end of the list so long as the above
+ * point is observed
+ */
+ const char *vals[];
+} sPAPRCapPossible;
+
typedef struct sPAPRCapabilityInfo {
const char *name;
const char *description;
@@ -41,6 +55,8 @@ typedef struct sPAPRCapabilityInfo {
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
const char *type;
+ /* Possible values if this is a custom string type */
+ sPAPRCapPossible *possible;
/* Make sure the virtual hardware can support this capability */
void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
} sPAPRCapabilityInfo;
@@ -73,41 +89,34 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
}
-static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+
+static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
sPAPRCapabilityInfo *cap = opaque;
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
char *val = NULL;
uint8_t value = spapr_get_cap(spapr, cap->index);
- switch (value) {
- case SPAPR_CAP_BROKEN:
- val = g_strdup("broken");
- break;
- case SPAPR_CAP_WORKAROUND:
- val = g_strdup("workaround");
- break;
- case SPAPR_CAP_FIXED:
- val = g_strdup("fixed");
- break;
- default:
+ if (value >= cap->possible->num) {
error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name);
return;
}
+ val = g_strdup(cap->possible->vals[value]);
+
visit_type_str(v, name, &val, errp);
g_free(val);
}
-static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
sPAPRCapabilityInfo *cap = opaque;
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
- char *val;
Error *local_err = NULL;
- uint8_t value;
+ uint8_t i;
+ char *val;
visit_type_str(v, name, &val, &local_err);
if (local_err) {
@@ -115,20 +124,20 @@ static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
return;
}
- if (!strcasecmp(val, "broken")) {
- value = SPAPR_CAP_BROKEN;
- } else if (!strcasecmp(val, "workaround")) {
- value = SPAPR_CAP_WORKAROUND;
- } else if (!strcasecmp(val, "fixed")) {
- value = SPAPR_CAP_FIXED;
- } else {
- error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
- cap->name);
+ if (!strcmp(val, "?")) {
+ error_setg(errp, "%s", cap->possible->help);
goto out;
}
+ for (i = 0; i < cap->possible->num; i++) {
+ if (!strcasecmp(val, cap->possible->vals[i])) {
+ spapr->cmd_line_caps[cap->index] = true;
+ spapr->eff.caps[cap->index] = i;
+ goto out;
+ }
+ }
- spapr->cmd_line_caps[cap->index] = true;
- spapr->eff.caps[cap->index] = value;
+ error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
+ cap->name);
out:
g_free(val);
}
@@ -180,38 +189,77 @@ static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
}
}
+sPAPRCapPossible cap_cfpc_possible = {
+ .num = 3,
+ .vals = {"broken", "workaround", "fixed"},
+ .help = "broken - no protection, workaround - workaround available,"
+ " fixed - fixed in hardware",
+};
+
static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val,
Error **errp)
{
+ uint8_t kvm_val = kvmppc_get_cap_safe_cache();
+
if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
- error_setg(errp, "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
- } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) {
- error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc");
+ error_setg(errp,
+"Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
+ } else if (kvm_enabled() && (val > kvm_val)) {
+ error_setg(errp,
+"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
+ cap_cfpc_possible.vals[kvm_val]);
}
}
+sPAPRCapPossible cap_sbbc_possible = {
+ .num = 3,
+ .vals = {"broken", "workaround", "fixed"},
+ .help = "broken - no protection, workaround - workaround available,"
+ " fixed - fixed in hardware",
+};
+
static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val,
Error **errp)
{
+ uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check();
+
if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
- error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
- } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) {
- error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc");
+ error_setg(errp,
+"Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
+ } else if (kvm_enabled() && (val > kvm_val)) {
+ error_setg(errp,
+"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s",
+ cap_sbbc_possible.vals[kvm_val]);
}
}
+sPAPRCapPossible cap_ibs_possible = {
+ .num = 4,
+ /* Note workaround only maintained for compatibility */
+ .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"},
+ .help = "broken - no protection, fixed-ibs - indirect branch serialisation,"
+ " fixed-ccd - cache count disabled",
+};
+
static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
uint8_t val, Error **errp)
{
+ uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch();
+
if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */
- error_setg(errp, "Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=fixed");
+ error_setg(errp,
+"Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s",
+ cap_ibs_possible.vals[kvm_val]);
} else if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
- error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
- } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) {
- error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs");
+ error_setg(errp,
+"Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
+ } else if (kvm_enabled() && val && (val != kvm_val)) {
+ error_setg(errp,
+"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s",
+ cap_ibs_possible.vals[kvm_val]);
}
}
@@ -249,27 +297,31 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.name = "cfpc",
.description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE,
.index = SPAPR_CAP_CFPC,
- .get = spapr_cap_get_tristate,
- .set = spapr_cap_set_tristate,
+ .get = spapr_cap_get_string,
+ .set = spapr_cap_set_string,
.type = "string",
+ .possible = &cap_cfpc_possible,
.apply = cap_safe_cache_apply,
},
[SPAPR_CAP_SBBC] = {
.name = "sbbc",
.description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE,
.index = SPAPR_CAP_SBBC,
- .get = spapr_cap_get_tristate,
- .set = spapr_cap_set_tristate,
+ .get = spapr_cap_get_string,
+ .set = spapr_cap_set_string,
.type = "string",
+ .possible = &cap_sbbc_possible,
.apply = cap_safe_bounds_check_apply,
},
[SPAPR_CAP_IBS] = {
.name = "ibs",
- .description = "Indirect Branch Serialisation (broken, fixed)",
+ .description =
+ "Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)",
.index = SPAPR_CAP_IBS,
- .get = spapr_cap_get_tristate,
- .set = spapr_cap_set_tristate,
+ .get = spapr_cap_get_string,
+ .set = spapr_cap_set_string,
.type = "string",
+ .possible = &cap_ibs_possible,
.apply = cap_safe_indirect_branch_apply,
},
};
@@ -283,15 +335,26 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
caps = smc->default_caps;
+ if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00,
+ 0, spapr->max_compat_pvr)) {
+ caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
+ }
+
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
}
+ if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS,
+ 0, spapr->max_compat_pvr)) {
+ caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
+ }
+
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
+ caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
}
return caps;
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 1986560480..16bccdd5c0 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1705,7 +1705,10 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
}
switch (safe_indirect_branch) {
- case SPAPR_CAP_FIXED:
+ case SPAPR_CAP_FIXED_CCD:
+ characteristics |= H_CPU_CHAR_CACHE_COUNT_DIS;
+ break;
+ case SPAPR_CAP_FIXED_IBS:
characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED;
break;
default: /* broken */
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index b7c3e64b5e..66ec7eda6e 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -99,3 +99,11 @@ mac99_uninorth_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"P
# hw/ppc/ppc4xx_pci.c
ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
ppc4xx_pci_set_irq(int irq_num) "PCI irq %d"
+
+# hw/ppc/ppc440_pcix.c
+ppc440_pcix_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
+ppc440_pcix_set_irq(int irq_num) "PCI irq %d"
+ppc440_pcix_update_pim(int idx, uint64_t size, uint64_t la) "Added window %d of size=0x%" PRIx64 " to CPU=0x%" PRIx64
+ppc440_pcix_update_pom(int idx, uint32_t size, uint64_t la, uint64_t pcia) "Added window %d of size=0x%x from CPU=0x%" PRIx64 " to PCI=0x%" PRIx64
+ppc440_pcix_reg_read(uint64_t addr, uint32_t val) "addr 0x%" PRIx64 " = 0x%" PRIx32
+ppc440_pcix_reg_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " = 0x%" PRIx64
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index 7fc1c603c0..214c940593 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -48,7 +48,7 @@ static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
return;
}
- cdev->mdevid = g_strdup(basename(dev_path));
+ cdev->mdevid = g_path_get_basename(dev_path);
tmp = basename(dirname(dev_path));
if (sscanf(tmp, "%2x.%1x.%4x", &cssid, &ssid, &devid) != 3) {
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 191505df5b..f3d4c4d230 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -2277,5 +2277,5 @@ void lsi53c895a_create(PCIBus *bus)
{
LSIState *s = LSI53C895A(pci_create_simple(bus, -1, "lsi53c895a"));
- scsi_bus_legacy_handle_cmdline(&s->bus, false);
+ scsi_bus_legacy_handle_cmdline(&s->bus);
}
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index b7bafbed6e..1eaeffc830 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -271,7 +271,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
return SCSI_DEVICE(dev);
}
-void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated)
+void scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
{
Location loc;
DriveInfo *dinfo;
@@ -284,59 +284,12 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated)
continue;
}
qemu_opts_loc_restore(dinfo->opts);
- if (deprecated) {
- /* Handling -drive not claimed by machine initialization */
- if (blk_get_attached_dev(blk_by_legacy_dinfo(dinfo))) {
- continue; /* claimed */
- }
- if (!dinfo->is_default) {
- warn_report("bus=%d,unit=%d is deprecated with this"
- " machine type",
- bus->busnr, unit);
- }
- }
scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo),
unit, false, -1, false, NULL, &error_fatal);
}
loc_pop(&loc);
}
-static bool is_scsi_hba_with_legacy_magic(Object *obj)
-{
- static const char *magic[] = {
- "am53c974", "dc390", "esp", "lsi53c810", "lsi53c895a",
- "megasas", "megasas-gen2", "mptsas1068", "spapr-vscsi",
- "virtio-scsi-device",
- NULL
- };
- const char *typename = object_get_typename(obj);
- int i;
-
- for (i = 0; magic[i]; i++)
- if (!strcmp(typename, magic[i])) {
- return true;
- }
-
- return false;
-}
-
-static int scsi_legacy_handle_cmdline_cb(Object *obj, void *opaque)
-{
- SCSIBus *bus = (SCSIBus *)object_dynamic_cast(obj, TYPE_SCSI_BUS);
-
- if (bus && is_scsi_hba_with_legacy_magic(OBJECT(bus->qbus.parent))) {
- scsi_bus_legacy_handle_cmdline(bus, true);
- }
-
- return 0;
-}
-
-void scsi_legacy_handle_cmdline(void)
-{
- object_child_foreach_recursive(object_get_root(),
- scsi_legacy_handle_cmdline_cb, NULL);
-}
-
static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf)
{
scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index 360db53ac8..a9e49c7cb5 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -1215,8 +1215,7 @@ void spapr_vscsi_create(VIOsPAPRBus *bus)
dev = qdev_create(&bus->bus, "spapr-vscsi");
qdev_init_nofail(dev);
- scsi_bus_legacy_handle_cmdline(&VIO_SPAPR_VSCSI_DEVICE(dev)->bus,
- false);
+ scsi_bus_legacy_handle_cmdline(&VIO_SPAPR_VSCSI_DEVICE(dev)->bus);
}
static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 033cc8dea1..3ba3cbc146 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2807,7 +2807,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
return;
}
- vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev));
+ vdev->vbasedev.name = g_path_get_basename(vdev->vbasedev.sysfsdev);
vdev->vbasedev.ops = &vfio_pci_ops;
vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI;
vdev->vbasedev.dev = &vdev->pdev.qdev;
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index 0d4bc0aae8..5c921c27ba 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -561,7 +561,7 @@ static int vfio_base_device_init(VFIODevice *vbasedev, Error **errp)
/* @sysfsdev takes precedence over @host */
if (vbasedev->sysfsdev) {
g_free(vbasedev->name);
- vbasedev->name = g_strdup(basename(vbasedev->sysfsdev));
+ vbasedev->name = g_path_get_basename(vbasedev->sysfsdev);
} else {
if (!vbasedev->name || strchr(vbasedev->name, '/')) {
error_setg(errp, "wrong host device name");
diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h
new file mode 100644
index 0000000000..a48c744fa8
--- /dev/null
+++ b/include/block/aio-wait.h
@@ -0,0 +1,116 @@
+/*
+ * AioContext wait support
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_AIO_WAIT_H
+#define QEMU_AIO_WAIT_H
+
+#include "block/aio.h"
+
+/**
+ * AioWait:
+ *
+ * An object that facilitates synchronous waiting on a condition. The main
+ * loop can wait on an operation running in an IOThread as follows:
+ *
+ * AioWait *wait = ...;
+ * AioContext *ctx = ...;
+ * MyWork work = { .done = false };
+ * schedule_my_work_in_iothread(ctx, &work);
+ * AIO_WAIT_WHILE(wait, ctx, !work.done);
+ *
+ * The IOThread must call aio_wait_kick() to notify the main loop when
+ * work.done changes:
+ *
+ * static void do_work(...)
+ * {
+ * ...
+ * work.done = true;
+ * aio_wait_kick(wait);
+ * }
+ */
+typedef struct {
+ /* Is the main loop waiting for a kick? Accessed with atomic ops. */
+ bool need_kick;
+} AioWait;
+
+/**
+ * AIO_WAIT_WHILE:
+ * @wait: the aio wait object
+ * @ctx: the aio context
+ * @cond: wait while this conditional expression is true
+ *
+ * Wait while a condition is true. Use this to implement synchronous
+ * operations that require event loop activity.
+ *
+ * The caller must be sure that something calls aio_wait_kick() when the value
+ * of @cond might have changed.
+ *
+ * The caller's thread must be the IOThread that owns @ctx or the main loop
+ * thread (with @ctx acquired exactly once). This function cannot be used to
+ * wait on conditions between two IOThreads since that could lead to deadlock,
+ * go via the main loop instead.
+ */
+#define AIO_WAIT_WHILE(wait, ctx, cond) ({ \
+ bool waited_ = false; \
+ bool busy_ = true; \
+ AioWait *wait_ = (wait); \
+ AioContext *ctx_ = (ctx); \
+ if (in_aio_context_home_thread(ctx_)) { \
+ while ((cond) || busy_) { \
+ busy_ = aio_poll(ctx_, (cond)); \
+ waited_ |= !!(cond) | busy_; \
+ } \
+ } else { \
+ assert(qemu_get_current_aio_context() == \
+ qemu_get_aio_context()); \
+ assert(!wait_->need_kick); \
+ /* Set wait_->need_kick before evaluating cond. */ \
+ atomic_mb_set(&wait_->need_kick, true); \
+ while (busy_) { \
+ if ((cond)) { \
+ waited_ = busy_ = true; \
+ aio_context_release(ctx_); \
+ aio_poll(qemu_get_aio_context(), true); \
+ aio_context_acquire(ctx_); \
+ } else { \
+ busy_ = aio_poll(ctx_, false); \
+ waited_ |= busy_; \
+ } \
+ } \
+ atomic_set(&wait_->need_kick, false); \
+ } \
+ waited_; })
+
+/**
+ * aio_wait_kick:
+ * @wait: the aio wait object that should re-evaluate its condition
+ *
+ * Wake up the main thread if it is waiting on AIO_WAIT_WHILE(). During
+ * synchronous operations performed in an IOThread, the main thread lets the
+ * IOThread's event loop run, waiting for the operation to complete. A
+ * aio_wait_kick() call will wake up the main thread.
+ */
+void aio_wait_kick(AioWait *wait);
+
+#endif /* QEMU_AIO_WAIT */
diff --git a/include/block/aio.h b/include/block/aio.h
index e9aeeaec94..a1d6b9e249 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -534,11 +534,14 @@ void aio_co_enter(AioContext *ctx, struct Coroutine *co);
AioContext *qemu_get_current_aio_context(void);
/**
+ * in_aio_context_home_thread:
* @ctx: the aio context
*
- * Return whether we are running in the I/O thread that manages @ctx.
+ * Return whether we are running in the thread that normally runs @ctx. Note
+ * that acquiring/releasing ctx does not affect the outcome, each AioContext
+ * still only has one home thread that is responsible for running it.
*/
-static inline bool aio_context_in_iothread(AioContext *ctx)
+static inline bool in_aio_context_home_thread(AioContext *ctx)
{
return ctx == qemu_get_current_aio_context();
}
diff --git a/include/block/block.h b/include/block/block.h
index fac401ba3e..8b6db952a2 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -3,6 +3,7 @@
#include "block/aio.h"
#include "qapi/qapi-types-block-core.h"
+#include "block/aio-wait.h"
#include "qemu/iov.h"
#include "qemu/coroutine.h"
#include "block/accounting.h"
@@ -115,19 +116,19 @@ typedef struct HDGeometry {
* BDRV_BLOCK_ZERO: offset reads as zero
* BDRV_BLOCK_OFFSET_VALID: an associated offset exists for accessing raw data
* BDRV_BLOCK_ALLOCATED: the content of the block is determined by this
- * layer (short for DATA || ZERO), set by block layer
- * BDRV_BLOCK_EOF: the returned pnum covers through end of file for this layer
+ * layer rather than any backing, set by block layer
+ * BDRV_BLOCK_EOF: the returned pnum covers through end of file for this
+ * layer, set by block layer
*
* Internal flag:
* BDRV_BLOCK_RAW: for use by passthrough drivers, such as raw, to request
* that the block layer recompute the answer from the returned
* BDS; must be accompanied by just BDRV_BLOCK_OFFSET_VALID.
*
- * If BDRV_BLOCK_OFFSET_VALID is set, bits 9-62 (BDRV_BLOCK_OFFSET_MASK) of
- * the return value (old interface) or the entire map parameter (new
- * interface) represent the offset in the returned BDS that is allocated for
- * the corresponding raw data. However, whether that offset actually
- * contains data also depends on BDRV_BLOCK_DATA, as follows:
+ * If BDRV_BLOCK_OFFSET_VALID is set, the map parameter represents the
+ * host offset within the returned BDS that is allocated for the
+ * corresponding raw guest data. However, whether that offset
+ * actually contains data also depends on BDRV_BLOCK_DATA, as follows:
*
* DATA ZERO OFFSET_VALID
* t t t sectors read as zero, returned file is zero at offset
@@ -367,41 +368,14 @@ void bdrv_drain_all_begin(void);
void bdrv_drain_all_end(void);
void bdrv_drain_all(void);
+/* Returns NULL when bs == NULL */
+AioWait *bdrv_get_aio_wait(BlockDriverState *bs);
+
#define BDRV_POLL_WHILE(bs, cond) ({ \
- bool waited_ = false; \
- bool busy_ = true; \
BlockDriverState *bs_ = (bs); \
- AioContext *ctx_ = bdrv_get_aio_context(bs_); \
- if (aio_context_in_iothread(ctx_)) { \
- while ((cond) || busy_) { \
- busy_ = aio_poll(ctx_, (cond)); \
- waited_ |= !!(cond) | busy_; \
- } \
- } else { \
- assert(qemu_get_current_aio_context() == \
- qemu_get_aio_context()); \
- /* Ask bdrv_dec_in_flight to wake up the main \
- * QEMU AioContext. Extra I/O threads never take \
- * other I/O threads' AioContexts (see for example \
- * block_job_defer_to_main_loop for how to do it). \
- */ \
- assert(!bs_->wakeup); \
- /* Set bs->wakeup before evaluating cond. */ \
- atomic_mb_set(&bs_->wakeup, true); \
- while (busy_) { \
- if ((cond)) { \
- waited_ = busy_ = true; \
- aio_context_release(ctx_); \
- aio_poll(qemu_get_aio_context(), true); \
- aio_context_acquire(ctx_); \
- } else { \
- busy_ = aio_poll(ctx_, false); \
- waited_ |= busy_; \
- } \
- } \
- atomic_set(&bs_->wakeup, false); \
- } \
- waited_; })
+ AIO_WAIT_WHILE(bdrv_get_aio_wait(bs_), \
+ bdrv_get_aio_context(bs_), \
+ cond); })
int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int bytes);
int bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 5ea63f8fa8..64a5700f2b 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -26,6 +26,7 @@
#include "block/accounting.h"
#include "block/block.h"
+#include "block/aio-wait.h"
#include "qemu/queue.h"
#include "qemu/coroutine.h"
#include "qemu/stats64.h"
@@ -128,7 +129,8 @@ struct BlockDriver {
int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags,
Error **errp);
void (*bdrv_close)(BlockDriverState *bs);
- int (*bdrv_create)(const char *filename, QemuOpts *opts, Error **errp);
+ int coroutine_fn (*bdrv_co_create_opts)(const char *filename, QemuOpts *opts,
+ Error **errp);
int (*bdrv_make_empty)(BlockDriverState *bs);
void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
@@ -202,15 +204,22 @@ struct BlockDriver {
/*
* Building block for bdrv_block_status[_above] and
* bdrv_is_allocated[_above]. The driver should answer only
- * according to the current layer, and should not set
- * BDRV_BLOCK_ALLOCATED, but may set BDRV_BLOCK_RAW. See block.h
- * for the meaning of _DATA, _ZERO, and _OFFSET_VALID. The block
- * layer guarantees input aligned to request_alignment, as well as
- * non-NULL pnum and file.
+ * according to the current layer, and should only need to set
+ * BDRV_BLOCK_DATA, BDRV_BLOCK_ZERO, BDRV_BLOCK_OFFSET_VALID,
+ * and/or BDRV_BLOCK_RAW; if the current layer defers to a backing
+ * layer, the result should be 0 (and not BDRV_BLOCK_ZERO). See
+ * block.h for the overall meaning of the bits. As a hint, the
+ * flag want_zero is true if the caller cares more about precise
+ * mappings (favor accurate _OFFSET_VALID/_ZERO) or false for
+ * overall allocation (favor larger *pnum, perhaps by reporting
+ * _DATA instead of _ZERO). The block layer guarantees input
+ * clamped to bdrv_getlength() and aligned to request_alignment,
+ * as well as non-NULL pnum, map, and file; in turn, the driver
+ * must return an error or set pnum to an aligned non-zero value.
*/
- int64_t coroutine_fn (*bdrv_co_get_block_status)(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, int *pnum,
- BlockDriverState **file);
+ int coroutine_fn (*bdrv_co_block_status)(BlockDriverState *bs,
+ bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
+ int64_t *map, BlockDriverState **file);
/*
* Invalidate any cached meta-data.
@@ -709,10 +718,8 @@ struct BlockDriverState {
unsigned int in_flight;
unsigned int serialising_in_flight;
- /* Internal to BDRV_POLL_WHILE and bdrv_wakeup. Accessed with atomic
- * ops.
- */
- bool wakeup;
+ /* Kicked to signal main loop when a request completes. */
+ AioWait wait;
/* counter for nested bdrv_io_plug.
* Accessed with atomic ops.
@@ -1031,23 +1038,27 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
uint64_t *nperm, uint64_t *nshared);
/*
- * Default implementation for drivers to pass bdrv_co_get_block_status() to
+ * Default implementation for drivers to pass bdrv_co_block_status() to
* their file.
*/
-int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors,
- int *pnum,
- BlockDriverState **file);
+int coroutine_fn bdrv_co_block_status_from_file(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset,
+ int64_t bytes,
+ int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file);
/*
- * Default implementation for drivers to pass bdrv_co_get_block_status() to
+ * Default implementation for drivers to pass bdrv_co_block_status() to
* their backing file.
*/
-int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors,
- int *pnum,
- BlockDriverState **file);
+int coroutine_fn bdrv_co_block_status_from_backing(BlockDriverState *bs,
+ bool want_zero,
+ int64_t offset,
+ int64_t bytes,
+ int64_t *pnum,
+ int64_t *map,
+ BlockDriverState **file);
const char *bdrv_get_parent_name(const BlockDriverState *bs);
void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp);
bool blk_dev_has_removable_media(BlockBackend *blk);
diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h
index 4162474fd5..6a5ee42d36 100644
--- a/include/exec/memory-internal.h
+++ b/include/exec/memory-internal.h
@@ -21,7 +21,15 @@
#define MEMORY_INTERNAL_H
#ifndef CONFIG_USER_ONLY
-typedef struct AddressSpaceDispatch AddressSpaceDispatch;
+static inline AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv)
+{
+ return fv->dispatch;
+}
+
+static inline AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as)
+{
+ return flatview_to_dispatch(address_space_to_flatview(as));
+}
extern const MemoryRegionOps unassigned_mem_ops;
@@ -31,9 +39,6 @@ bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr,
void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section);
AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv);
void address_space_dispatch_compact(AddressSpaceDispatch *d);
-
-AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as);
-AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv);
void address_space_dispatch_free(AddressSpaceDispatch *d);
void mtree_print_dispatch(fprintf_function mon, void *f,
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 15e81113ba..31eae0a640 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -326,7 +326,27 @@ struct AddressSpace {
QTAILQ_ENTRY(AddressSpace) address_spaces_link;
};
-FlatView *address_space_to_flatview(AddressSpace *as);
+typedef struct AddressSpaceDispatch AddressSpaceDispatch;
+typedef struct FlatRange FlatRange;
+
+/* Flattened global view of current active memory hierarchy. Kept in sorted
+ * order.
+ */
+struct FlatView {
+ struct rcu_head rcu;
+ unsigned ref;
+ FlatRange *ranges;
+ unsigned nr;
+ unsigned nr_allocated;
+ struct AddressSpaceDispatch *dispatch;
+ MemoryRegion *root;
+};
+
+static inline FlatView *address_space_to_flatview(AddressSpace *as)
+{
+ return atomic_rcu_read(&as->current_map);
+}
+
/**
* MemoryRegionSection: describes a fragment of a #MemoryRegion
@@ -1897,13 +1917,12 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
/* Internal functions, part of the implementation of address_space_read. */
+MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
+ MemTxAttrs attrs, uint8_t *buf, int len);
MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf,
int len, hwaddr addr1, hwaddr l,
MemoryRegion *mr);
-
-MemTxResult flatview_read_full(FlatView *fv, hwaddr addr,
- MemTxAttrs attrs, uint8_t *buf, int len);
void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr);
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
@@ -1922,25 +1941,28 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
*
* Return a MemTxResult indicating whether the operation succeeded
* or failed (eg unassigned memory, device rejected the transaction,
- * IOMMU fault).
+ * IOMMU fault). Called within RCU critical section.
*
- * @fv: #FlatView to be accessed
+ * @as: #AddressSpace to be accessed
* @addr: address within that address space
* @attrs: memory transaction attributes
* @buf: buffer with the data transferred
*/
static inline __attribute__((__always_inline__))
-MemTxResult flatview_read(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
- uint8_t *buf, int len)
+MemTxResult address_space_read(AddressSpace *as, hwaddr addr,
+ MemTxAttrs attrs, uint8_t *buf,
+ int len)
{
MemTxResult result = MEMTX_OK;
hwaddr l, addr1;
void *ptr;
MemoryRegion *mr;
+ FlatView *fv;
if (__builtin_constant_p(len)) {
if (len) {
rcu_read_lock();
+ fv = address_space_to_flatview(as);
l = len;
mr = flatview_translate(fv, addr, &addr1, &l, false);
if (len == l && memory_access_is_direct(mr, false)) {
@@ -1953,18 +1975,11 @@ MemTxResult flatview_read(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
rcu_read_unlock();
}
} else {
- result = flatview_read_full(fv, addr, attrs, buf, len);
+ result = address_space_read_full(as, addr, attrs, buf, len);
}
return result;
}
-static inline MemTxResult address_space_read(AddressSpace *as, hwaddr addr,
- MemTxAttrs attrs, uint8_t *buf,
- int len)
-{
- return flatview_read(address_space_to_flatview(as), addr, attrs, buf, len);
-}
-
/**
* address_space_read_cached: read from a cached RAM region
*
diff --git a/include/hw/intc/heathrow_pic.h b/include/hw/intc/heathrow_pic.h
new file mode 100644
index 0000000000..bc3ffaab87
--- /dev/null
+++ b/include/hw/intc/heathrow_pic.h
@@ -0,0 +1,49 @@
+/*
+ * Heathrow PIC support (OldWorld PowerMac)
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HEATHROW_H
+#define HEATHROW_H
+
+#define TYPE_HEATHROW "heathrow"
+#define HEATHROW(obj) OBJECT_CHECK(HeathrowState, (obj), TYPE_HEATHROW)
+
+typedef struct HeathrowPICState {
+ uint32_t events;
+ uint32_t mask;
+ uint32_t levels;
+ uint32_t level_triggered;
+} HeathrowPICState;
+
+typedef struct HeathrowState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mem;
+ HeathrowPICState pics[2];
+ qemu_irq *irqs;
+} HeathrowState;
+
+#define HEATHROW_NUM_IRQS 64
+
+#endif /* HEATHROW_H */
diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h
new file mode 100644
index 0000000000..4528282b36
--- /dev/null
+++ b/include/hw/misc/macio/macio.h
@@ -0,0 +1,79 @@
+/*
+ * PowerMac MacIO device emulation
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MACIO_H
+#define MACIO_H
+
+#include "hw/intc/heathrow_pic.h"
+#include "hw/misc/macio/cuda.h"
+#include "hw/ppc/mac_dbdma.h"
+#include "hw/ppc/openpic.h"
+
+#define TYPE_MACIO "macio"
+#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
+
+typedef struct MacIOState {
+ /*< private >*/
+ PCIDevice parent;
+ /*< public >*/
+
+ MemoryRegion bar;
+ CUDAState cuda;
+ DBDMAState dbdma;
+ ESCCState escc;
+ uint64_t frequency;
+} MacIOState;
+
+#define TYPE_OLDWORLD_MACIO "macio-oldworld"
+#define OLDWORLD_MACIO(obj) \
+ OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
+
+typedef struct OldWorldMacIOState {
+ /*< private >*/
+ MacIOState parent_obj;
+ /*< public >*/
+
+ HeathrowState *pic;
+ qemu_irq irqs[7];
+
+ MacIONVRAMState nvram;
+ MACIOIDEState ide[2];
+} OldWorldMacIOState;
+
+#define TYPE_NEWWORLD_MACIO "macio-newworld"
+#define NEWWORLD_MACIO(obj) \
+ OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
+
+typedef struct NewWorldMacIOState {
+ /*< private >*/
+ MacIOState parent_obj;
+ /*< public >*/
+
+ OpenPICState *pic;
+ qemu_irq irqs[7];
+ MACIOIDEState ide[2];
+} NewWorldMacIOState;
+
+#endif /* MACIO_H */
diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h
index e55ce546aa..5eb982197d 100644
--- a/include/hw/ppc/openpic.h
+++ b/include/hw/ppc/openpic.h
@@ -2,10 +2,13 @@
#define OPENPIC_H
#include "qemu-common.h"
+#include "hw/sysbus.h"
#include "hw/qdev-core.h"
#include "qom/cpu.h"
-#define TYPE_OPENPIC "openpic"
+#define MAX_CPU 32
+#define MAX_MSI 8
+#define VID 0x03 /* MPIC version ID */
/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
enum {
@@ -28,7 +31,158 @@ enum {
#define OPENPIC_MAX_IRQ (OPENPIC_MAX_SRC + OPENPIC_MAX_IPI + \
OPENPIC_MAX_TMR)
-#define TYPE_KVM_OPENPIC "kvm-openpic"
-int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs);
+/* Raven */
+#define RAVEN_MAX_CPU 2
+#define RAVEN_MAX_EXT 48
+#define RAVEN_MAX_IRQ 64
+#define RAVEN_MAX_TMR OPENPIC_MAX_TMR
+#define RAVEN_MAX_IPI OPENPIC_MAX_IPI
+
+/* KeyLargo */
+#define KEYLARGO_MAX_CPU 4
+#define KEYLARGO_MAX_EXT 64
+#define KEYLARGO_MAX_IPI 4
+#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI)
+#define KEYLARGO_MAX_TMR 0
+#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */
+/* Timers don't exist but this makes the code happy... */
+#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI)
+
+/* Interrupt definitions */
+#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */
+#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */
+#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */
+#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
+/* First doorbell IRQ */
+#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
+
+typedef struct FslMpicInfo {
+ int max_ext;
+} FslMpicInfo;
+
+typedef enum IRQType {
+ IRQ_TYPE_NORMAL = 0,
+ IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
+ IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
+} IRQType;
+
+/* Round up to the nearest 64 IRQs so that the queue length
+ * won't change when moving between 32 and 64 bit hosts.
+ */
+#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
+
+typedef struct IRQQueue {
+ unsigned long *queue;
+ int32_t queue_size; /* Only used for VMSTATE_BITMAP */
+ int next;
+ int priority;
+} IRQQueue;
+
+typedef struct IRQSource {
+ uint32_t ivpr; /* IRQ vector/priority register */
+ uint32_t idr; /* IRQ destination register */
+ uint32_t destmask; /* bitmap of CPU destinations */
+ int last_cpu;
+ int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
+ int pending; /* TRUE if IRQ is pending */
+ IRQType type;
+ bool level:1; /* level-triggered */
+ bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */
+} IRQSource;
+
+#define IVPR_MASK_SHIFT 31
+#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
+#define IVPR_ACTIVITY_SHIFT 30
+#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
+#define IVPR_MODE_SHIFT 29
+#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
+#define IVPR_POLARITY_SHIFT 23
+#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
+#define IVPR_SENSE_SHIFT 22
+#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
+
+#define IVPR_PRIORITY_MASK (0xFU << 16)
+#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
+#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
+
+/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
+#define IDR_EP 0x80000000 /* external pin */
+#define IDR_CI 0x40000000 /* critical interrupt */
+
+typedef struct OpenPICTimer {
+ uint32_t tccr; /* Global timer current count register */
+ uint32_t tbcr; /* Global timer base count register */
+ int n_IRQ;
+ bool qemu_timer_active; /* Is the qemu_timer is running? */
+ struct QEMUTimer *qemu_timer;
+ struct OpenPICState *opp; /* Device timer is part of. */
+ /* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last
+ current_count written or read, only defined if qemu_timer_active. */
+ uint64_t origin_time;
+} OpenPICTimer;
+
+typedef struct OpenPICMSI {
+ uint32_t msir; /* Shared Message Signaled Interrupt Register */
+} OpenPICMSI;
+
+typedef struct IRQDest {
+ int32_t ctpr; /* CPU current task priority */
+ IRQQueue raised;
+ IRQQueue servicing;
+ qemu_irq *irqs;
+
+ /* Count of IRQ sources asserting on non-INT outputs */
+ uint32_t outputs_active[OPENPIC_OUTPUT_NB];
+} IRQDest;
+
+#define TYPE_OPENPIC "openpic"
+#define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC)
+
+typedef struct OpenPICState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ MemoryRegion mem;
+
+ /* Behavior control */
+ FslMpicInfo *fsl;
+ uint32_t model;
+ uint32_t flags;
+ uint32_t nb_irqs;
+ uint32_t vid;
+ uint32_t vir; /* Vendor identification register */
+ uint32_t vector_mask;
+ uint32_t tfrr_reset;
+ uint32_t ivpr_reset;
+ uint32_t idr_reset;
+ uint32_t brr1;
+ uint32_t mpic_mode_mask;
+
+ /* Sub-regions */
+ MemoryRegion sub_io_mem[6];
+
+ /* Global registers */
+ uint32_t frr; /* Feature reporting register */
+ uint32_t gcr; /* Global configuration register */
+ uint32_t pir; /* Processor initialization register */
+ uint32_t spve; /* Spurious vector register */
+ uint32_t tfrr; /* Timer frequency reporting register */
+ /* Source registers */
+ IRQSource src[OPENPIC_MAX_IRQ];
+ /* Local registers per output pin */
+ IRQDest dst[MAX_CPU];
+ uint32_t nb_cpus;
+ /* Timer registers */
+ OpenPICTimer timers[OPENPIC_MAX_TMR];
+ uint32_t max_tmr;
+
+ /* Shared MSI registers */
+ OpenPICMSI msi[MAX_MSI];
+ uint32_t max_irq;
+ uint32_t irq_ipi0;
+ uint32_t irq_tim0;
+ uint32_t irq_msi;
+} OpenPICState;
#endif /* OPENPIC_H */
diff --git a/include/hw/ppc/openpic_kvm.h b/include/hw/ppc/openpic_kvm.h
new file mode 100644
index 0000000000..9ef4215257
--- /dev/null
+++ b/include/hw/ppc/openpic_kvm.h
@@ -0,0 +1,7 @@
+#ifndef OPENPIC_KVM_H
+#define OPENPIC_KVM_H
+
+#define TYPE_KVM_OPENPIC "kvm-openpic"
+int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs);
+
+#endif /* OPENPIC_KVM_H */
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 36942b378d..d60b7c6d7a 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -75,10 +75,12 @@ typedef enum {
/* Bool Caps */
#define SPAPR_CAP_OFF 0x00
#define SPAPR_CAP_ON 0x01
-/* Broken | Workaround | Fixed Caps */
+/* Custom Caps */
#define SPAPR_CAP_BROKEN 0x00
#define SPAPR_CAP_WORKAROUND 0x01
#define SPAPR_CAP_FIXED 0x02
+#define SPAPR_CAP_FIXED_IBS 0x02
+#define SPAPR_CAP_FIXED_CCD 0x03
typedef struct sPAPRCapabilities sPAPRCapabilities;
struct sPAPRCapabilities {
@@ -313,6 +315,7 @@ struct sPAPRMachineState {
#define H_CPU_CHAR_L1D_THREAD_PRIV PPC_BIT(4)
#define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5)
#define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6)
+#define H_CPU_CHAR_CACHE_COUNT_DIS PPC_BIT(7)
#define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0)
#define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1)
#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2)
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index 802a647cdc..7ecaddac9d 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -153,7 +153,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
int unit, bool removable, int bootindex,
bool share_rw,
const char *serial, Error **errp);
-void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated);
+void scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
void scsi_legacy_handle_cmdline(void);
SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
diff --git a/include/qemu/lockable.h b/include/qemu/lockable.h
index b6ed6c89ec..84ea794bcf 100644
--- a/include/qemu/lockable.h
+++ b/include/qemu/lockable.h
@@ -28,7 +28,7 @@ struct QemuLockable {
* to QEMU_MAKE_LOCKABLE. For optimized builds, we can rely on dead-code elimination
* from the compiler, and give the errors already at link time.
*/
-#ifdef __OPTIMIZE__
+#if defined(__OPTIMIZE__) && !defined(__SANITIZE_ADDRESS__)
void unknown_lock_type(void *);
#else
static inline void unknown_lock_type(void *unused)
diff --git a/include/qom/object.h b/include/qom/object.h
index 30db296af4..4f07090db0 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1017,6 +1017,22 @@ void object_property_iter_init(ObjectPropertyIterator *iter,
Object *obj);
/**
+ * object_class_property_iter_init:
+ * @klass: the class
+ *
+ * Initializes an iterator for traversing all properties
+ * registered against an object class and all parent classes.
+ *
+ * It is forbidden to modify the property list while iterating,
+ * whether removing or adding properties.
+ *
+ * This can be used on abstract classes as it does not create a temporary
+ * instance.
+ */
+void object_class_property_iter_init(ObjectPropertyIterator *iter,
+ ObjectClass *klass);
+
+/**
* object_property_iter_next:
* @iter: the iterator instance
*
diff --git a/memory.c b/memory.c
index 6515131ac2..e70b64b8b9 100644
--- a/memory.c
+++ b/memory.c
@@ -210,8 +210,6 @@ static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a,
&& !memory_region_ioeventfd_before(b, a);
}
-typedef struct FlatRange FlatRange;
-
/* Range of memory in the global map. Addresses are absolute. */
struct FlatRange {
MemoryRegion *mr;
@@ -222,19 +220,6 @@ struct FlatRange {
bool readonly;
};
-/* Flattened global view of current active memory hierarchy. Kept in sorted
- * order.
- */
-struct FlatView {
- struct rcu_head rcu;
- unsigned ref;
- FlatRange *ranges;
- unsigned nr;
- unsigned nr_allocated;
- struct AddressSpaceDispatch *dispatch;
- MemoryRegion *root;
-};
-
typedef struct AddressSpaceOps AddressSpaceOps;
#define FOR_EACH_FLAT_RANGE(var, view) \
@@ -322,21 +307,6 @@ static void flatview_unref(FlatView *view)
}
}
-FlatView *address_space_to_flatview(AddressSpace *as)
-{
- return atomic_rcu_read(&as->current_map);
-}
-
-AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv)
-{
- return fv->dispatch;
-}
-
-AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as)
-{
- return flatview_to_dispatch(address_space_to_flatview(as));
-}
-
static bool can_merge(FlatRange *r1, FlatRange *r2)
{
return int128_eq(addrrange_end(r1->addr), r2->addr.start)
diff --git a/pc-bios/canyonlands.dtb b/pc-bios/canyonlands.dtb
new file mode 100644
index 0000000000..9dce3443ad
--- /dev/null
+++ b/pc-bios/canyonlands.dtb
Binary files differ
diff --git a/pc-bios/canyonlands.dts b/pc-bios/canyonlands.dts
new file mode 100644
index 0000000000..0d6ac92d0f
--- /dev/null
+++ b/pc-bios/canyonlands.dts
@@ -0,0 +1,566 @@
+/*
+ * Device Tree Source for AMCC Canyonlands (460EX)
+ *
+ * Copyright 2008-2009 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ model = "amcc,canyonlands";
+ compatible = "amcc,canyonlands";
+ dcr-parent = <&{/cpus/cpu@0}>;
+
+ aliases {
+ ethernet0 = &EMAC0;
+ ethernet1 = &EMAC1;
+ serial0 = &UART0;
+ serial1 = &UART1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ model = "PowerPC,460EX";
+ reg = <0x00000000>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ timebase-frequency = <0>; /* Filled in by U-Boot */
+ i-cache-line-size = <32>;
+ d-cache-line-size = <32>;
+ i-cache-size = <32768>;
+ d-cache-size = <32768>;
+ dcr-controller;
+ dcr-access-method = "native";
+ next-level-cache = <&L2C0>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
+ };
+
+ UIC0: interrupt-controller0 {
+ compatible = "ibm,uic-460ex","ibm,uic";
+ interrupt-controller;
+ cell-index = <0>;
+ dcr-reg = <0x0c0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ };
+
+ UIC1: interrupt-controller1 {
+ compatible = "ibm,uic-460ex","ibm,uic";
+ interrupt-controller;
+ cell-index = <1>;
+ dcr-reg = <0x0d0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ UIC2: interrupt-controller2 {
+ compatible = "ibm,uic-460ex","ibm,uic";
+ interrupt-controller;
+ cell-index = <2>;
+ dcr-reg = <0x0e0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ UIC3: interrupt-controller3 {
+ compatible = "ibm,uic-460ex","ibm,uic";
+ interrupt-controller;
+ cell-index = <3>;
+ dcr-reg = <0x0f0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ SDR0: sdr {
+ compatible = "ibm,sdr-460ex";
+ dcr-reg = <0x00e 0x002>;
+ };
+
+ CPR0: cpr {
+ compatible = "ibm,cpr-460ex";
+ dcr-reg = <0x00c 0x002>;
+ };
+
+ CPM0: cpm {
+ compatible = "ibm,cpm";
+ dcr-access-method = "native";
+ dcr-reg = <0x160 0x003>;
+ unused-units = <0x00000100>;
+ idle-doze = <0x02000000>;
+ standby = <0xfeff791d>;
+ };
+
+ L2C0: l2c {
+ compatible = "ibm,l2-cache-460ex", "ibm,l2-cache";
+ dcr-reg = <0x020 0x008 /* Internal SRAM DCR's */
+ 0x030 0x008>; /* L2 cache DCR's */
+ cache-line-size = <32>; /* 32 bytes */
+ cache-size = <262144>; /* L2, 256K */
+ interrupt-parent = <&UIC1>;
+ interrupts = <11 1>;
+ };
+
+ plb {
+ compatible = "ibm,plb-460ex", "ibm,plb4";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ SDRAM0: sdram {
+ compatible = "ibm,sdram-460ex", "ibm,sdram-405gp";
+ dcr-reg = <0x010 0x002>;
+ };
+
+ CRYPTO: crypto@180000 {
+ compatible = "amcc,ppc460ex-crypto", "amcc,ppc4xx-crypto";
+ reg = <4 0x00180000 0x80400>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x1d 0x4>;
+ };
+
+ HWRNG: hwrng@110000 {
+ compatible = "amcc,ppc460ex-rng", "ppc4xx-rng";
+ reg = <4 0x00110000 0x50>;
+ };
+
+ MAL0: mcmal {
+ compatible = "ibm,mcmal-460ex", "ibm,mcmal2";
+ dcr-reg = <0x180 0x062>;
+ num-tx-chans = <2>;
+ num-rx-chans = <16>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-parent = <&UIC2>;
+ interrupts = < /*TXEOB*/ 0x6 0x4
+ /*RXEOB*/ 0x7 0x4
+ /*SERR*/ 0x3 0x4
+ /*TXDE*/ 0x4 0x4
+ /*RXDE*/ 0x5 0x4>;
+ };
+
+ USB0: ehci@bffd0400 {
+ compatible = "ibm,usb-ehci-460ex", "usb-ehci";
+ interrupt-parent = <&UIC2>;
+ interrupts = <0x1d 4>;
+ reg = <4 0xbffd0400 0x90 4 0xbffd0490 0x70>;
+ };
+
+ USB1: usb@bffd0000 {
+ compatible = "ohci-le";
+ reg = <4 0xbffd0000 0x60>;
+ interrupt-parent = <&UIC2>;
+ interrupts = <0x1e 4>;
+ };
+
+ USBOTG0: usbotg@bff80000 {
+ compatible = "amcc,dwc-otg";
+ reg = <0x4 0xbff80000 0x10000>;
+ interrupt-parent = <&USBOTG0>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x1 0x2>;
+ interrupt-map = </* USB-OTG */ 0x0 &UIC2 0x1c 0x4
+ /* HIGH-POWER */ 0x1 &UIC1 0x1a 0x8
+ /* DMA */ 0x2 &UIC0 0xc 0x4>;
+ };
+
+ AHBDMA: dma@bffd0800 {
+ compatible = "snps,dma-spear1340";
+ reg = <4 0xbffd0800 0x400>;
+ interrupt-parent = <&UIC3>;
+ interrupts = <0x5 0x4>;
+ #dma-cells = <3>;
+ };
+
+ SATA0: sata@bffd1000 {
+ compatible = "amcc,sata-460ex";
+ reg = <4 0xbffd1000 0x800>;
+ interrupt-parent = <&UIC3>;
+ interrupts = <0x0 0x4>;
+ dmas = <&AHBDMA 0 1 0>;
+ dma-names = "sata-dma";
+ };
+
+ POB0: opb {
+ compatible = "ibm,opb-460ex", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ EBC0: ebc {
+ compatible = "ibm,ebc-460ex", "ibm,ebc";
+ dcr-reg = <0x012 0x002>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ /* ranges property is supplied by U-Boot */
+ interrupts = <0x6 0x4>;
+ interrupt-parent = <&UIC1>;
+
+ nor_flash@0,0 {
+ compatible = "amd,s29gl512n", "cfi-flash";
+ bank-width = <2>;
+ reg = <0x00000000 0x00000000 0x04000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ partition@0 {
+ label = "kernel";
+ reg = <0x00000000 0x001e0000>;
+ };
+ partition@1e0000 {
+ label = "dtb";
+ reg = <0x001e0000 0x00020000>;
+ };
+ partition@200000 {
+ label = "ramdisk";
+ reg = <0x00200000 0x01400000>;
+ };
+ partition@1600000 {
+ label = "jffs2";
+ reg = <0x01600000 0x00400000>;
+ };
+ partition@1a00000 {
+ label = "user";
+ reg = <0x01a00000 0x02560000>;
+ };
+ partition@3f60000 {
+ label = "env";
+ reg = <0x03f60000 0x00040000>;
+ };
+ partition@3fa0000 {
+ label = "u-boot";
+ reg = <0x03fa0000 0x00060000>;
+ };
+ };
+
+ cpld@2,0 {
+ compatible = "amcc,ppc460ex-bcsr";
+ reg = <2 0x0 0x9>;
+ };
+
+ ndfc@3,0 {
+ compatible = "ibm,ndfc";
+ reg = <0x00000003 0x00000000 0x00002000>;
+ ccr = <0x00001000>;
+ bank-settings = <0x80002222>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x00000000 0x00100000>;
+ };
+ partition@100000 {
+ label = "user";
+ reg = <0x00000000 0x03f00000>;
+ };
+ };
+ };
+ };
+
+ UART0: serial@ef600300 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0xef600300 0x00000008>;
+ virtual-reg = <0xef600300>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>; /* Filled in by U-Boot */
+ interrupt-parent = <&UIC1>;
+ interrupts = <0x1 0x4>;
+ };
+
+ UART1: serial@ef600400 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0xef600400 0x00000008>;
+ virtual-reg = <0xef600400>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>; /* Filled in by U-Boot */
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x1 0x4>;
+ };
+
+ IIC0: i2c@ef600700 {
+ compatible = "ibm,iic-460ex", "ibm,iic";
+ reg = <0xef600700 0x00000014>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x2 0x4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ rtc@68 {
+ compatible = "st,m41t80";
+ reg = <0x68>;
+ interrupt-parent = <&UIC2>;
+ interrupts = <0x19 0x8>;
+ };
+ sttm@48 {
+ compatible = "ad,ad7414";
+ reg = <0x48>;
+ interrupt-parent = <&UIC1>;
+ interrupts = <0x14 0x8>;
+ };
+ };
+
+ IIC1: i2c@ef600800 {
+ compatible = "ibm,iic-460ex", "ibm,iic";
+ reg = <0xef600800 0x00000014>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x3 0x4>;
+ };
+
+ GPIO0: gpio@ef600b00 {
+ compatible = "ibm,ppc4xx-gpio";
+ reg = <0xef600b00 0x00000048>;
+ gpio-controller;
+ };
+
+ ZMII0: emac-zmii@ef600d00 {
+ compatible = "ibm,zmii-460ex", "ibm,zmii";
+ reg = <0xef600d00 0x0000000c>;
+ };
+
+ RGMII0: emac-rgmii@ef601500 {
+ compatible = "ibm,rgmii-460ex", "ibm,rgmii";
+ reg = <0xef601500 0x00000008>;
+ has-mdio;
+ };
+
+ TAH0: emac-tah@ef601350 {
+ compatible = "ibm,tah-460ex", "ibm,tah";
+ reg = <0xef601350 0x00000030>;
+ };
+
+ TAH1: emac-tah@ef601450 {
+ compatible = "ibm,tah-460ex", "ibm,tah";
+ reg = <0xef601450 0x00000030>;
+ };
+
+ EMAC0: ethernet@ef600e00 {
+ device_type = "network";
+ compatible = "ibm,emac-460ex", "ibm,emac4sync";
+ interrupt-parent = <&EMAC0>;
+ interrupts = <0x0 0x1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
+ /*Wake*/ 0x1 &UIC2 0x14 0x4>;
+ reg = <0xef600e00 0x000000c4>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <0>;
+ mal-rx-channel = <0>;
+ cell-index = <0>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ rx-fifo-size-gige = <16384>;
+ phy-mode = "rgmii";
+ phy-map = <0x00000000>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <0>;
+ tah-device = <&TAH0>;
+ tah-channel = <0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+
+ EMAC1: ethernet@ef600f00 {
+ device_type = "network";
+ compatible = "ibm,emac-460ex", "ibm,emac4sync";
+ interrupt-parent = <&EMAC1>;
+ interrupts = <0x0 0x1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &UIC2 0x11 0x4
+ /*Wake*/ 0x1 &UIC2 0x15 0x4>;
+ reg = <0xef600f00 0x000000c4>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <1>;
+ mal-rx-channel = <8>;
+ cell-index = <1>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ rx-fifo-size-gige = <16384>;
+ phy-mode = "rgmii";
+ phy-map = <0x00000000>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <1>;
+ tah-device = <&TAH1>;
+ tah-channel = <1>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ mdio-device = <&EMAC0>;
+ };
+ };
+
+ PCIX0: pci@c0ec00000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pcix-460ex", "ibm,plb-pcix";
+ primary;
+ large-inbound-windows;
+ enable-msi-hole;
+ reg = <0x0000000c 0x0ec00000 0x00000008 /* Config space access */
+ 0x00000000 0x00000000 0x00000000 /* no IACK cycles */
+ 0x0000000c 0x0ed00000 0x00000004 /* Special cycles */
+ 0x0000000c 0x0ec80000 0x00000100 /* Internal registers */
+ 0x0000000c 0x0ec80100 0x000000fc>; /* Internal messaging registers */
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000
+ 0x02000000 0x00000000 0x00000000 0x0000000c 0x0ee00000 0x00000000 0x00100000
+ 0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
+
+ /* This drives busses 0 to 0x3f */
+ bus-range = <0x0 0x3f>;
+
+ /* All PCI interrupts are routed to ext IRQ 2 -> UIC1-0 */
+ interrupt-map-mask = <0x0 0x0 0x0 0x0>;
+ interrupt-map = < 0x0 0x0 0x0 0x0 &UIC1 0x0 0x8 >;
+ };
+
+ PCIE0: pciex@d00000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-460ex", "ibm,plb-pciex";
+ primary;
+ port = <0x0>; /* port number */
+ reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */
+ 0x0000000c 0x08010000 0x00001000>; /* Registers */
+ dcr-reg = <0x100 0x020>;
+ sdr-base = <0x300>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
+ 0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000
+ 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
+
+ /* This drives busses 40 to 0x7f */
+ bus-range = <0x40 0x7f>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &UIC3 0xc 0x4 /* swizzled int A */
+ 0x0 0x0 0x0 0x2 &UIC3 0xd 0x4 /* swizzled int B */
+ 0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */
+ 0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>;
+ };
+
+ PCIE1: pciex@d20000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-460ex", "ibm,plb-pciex";
+ primary;
+ port = <0x1>; /* port number */
+ reg = <0x0000000d 0x20000000 0x20000000 /* Config space access */
+ 0x0000000c 0x08011000 0x00001000>; /* Registers */
+ dcr-reg = <0x120 0x020>;
+ sdr-base = <0x340>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000
+ 0x02000000 0x00000000 0x00000000 0x0000000f 0x00100000 0x00000000 0x00100000
+ 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
+
+ /* This drives busses 80 to 0xbf */
+ bus-range = <0x80 0xbf>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &UIC3 0x10 0x4 /* swizzled int A */
+ 0x0 0x0 0x0 0x2 &UIC3 0x11 0x4 /* swizzled int B */
+ 0x0 0x0 0x0 0x3 &UIC3 0x12 0x4 /* swizzled int C */
+ 0x0 0x0 0x0 0x4 &UIC3 0x13 0x4 /* swizzled int D */>;
+ };
+
+ MSI: ppc4xx-msi@C10000000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0xC 0x10000000 0x100>;
+ sdr-base = <0x36C>;
+ msi-data = <0x00000000>;
+ msi-mask = <0x44440000>;
+ interrupt-count = <3>;
+ interrupts = <0 1 2 3>;
+ interrupt-parent = <&UIC3>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <0 &UIC3 0x18 1
+ 1 &UIC3 0x19 1
+ 2 &UIC3 0x1A 1
+ 3 &UIC3 0x1B 1>;
+ };
+ };
+};
diff --git a/pc-bios/u-boot-sam460-20100605.bin b/pc-bios/u-boot-sam460-20100605.bin
new file mode 100755
index 0000000000..99408f8e95
--- /dev/null
+++ b/pc-bios/u-boot-sam460-20100605.bin
Binary files differ
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 5c5921bfb7..00475f08d4 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3676,7 +3676,8 @@
#
# @node-name: node name. Note that errors may be reported for the root node
# that is directly attached to a guest device rather than for the
-# node where the error occurred. (Since: 2.8)
+# node where the error occurred. The node name is not present if
+# the drive is empty. (Since: 2.8)
#
# @operation: I/O operation
#
@@ -3707,7 +3708,8 @@
#
##
{ 'event': 'BLOCK_IO_ERROR',
- 'data': { 'device': 'str', 'node-name': 'str', 'operation': 'IoOperationType',
+ 'data': { 'device': 'str', '*node-name': 'str',
+ 'operation': 'IoOperationType',
'action': 'BlockErrorAction', '*nospace': 'bool',
'reason': 'str' } }
diff --git a/qapi/misc.json b/qapi/misc.json
index a1702c9060..bd04469a4b 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -1285,10 +1285,12 @@
# 3) A link type in the form 'link<subtype>' where subtype is a qdev
# device type name. Link properties form the device model graph.
#
+# @description: if specified, the description of the property.
+#
# Since: 1.2
##
{ 'struct': 'ObjectPropertyInfo',
- 'data': { 'name': 'str', 'type': 'str' } }
+ 'data': { 'name': 'str', 'type': 'str', '*description': 'str' } }
##
# @qom-list:
@@ -1444,34 +1446,34 @@
'returns': [ 'ObjectTypeInfo' ] }
##
-# @DevicePropertyInfo:
+# @device-list-properties:
+#
+# List properties associated with a device.
#
-# Information about device properties.
+# @typename: the type name of a device
#
-# @name: the name of the property
-# @type: the typename of the property
-# @description: if specified, the description of the property.
-# (since 2.2)
+# Returns: a list of ObjectPropertyInfo describing a devices properties
#
# Since: 1.2
##
-{ 'struct': 'DevicePropertyInfo',
- 'data': { 'name': 'str', 'type': 'str', '*description': 'str' } }
+{ 'command': 'device-list-properties',
+ 'data': { 'typename': 'str'},
+ 'returns': [ 'ObjectPropertyInfo' ] }
##
-# @device-list-properties:
+# @qom-list-properties:
#
-# List properties associated with a device.
+# List properties associated with a QOM object.
#
-# @typename: the type name of a device
+# @typename: the type name of an object
#
-# Returns: a list of DevicePropertyInfo describing a devices properties
+# Returns: a list of ObjectPropertyInfo describing object properties
#
-# Since: 1.2
+# Since: 2.12
##
-{ 'command': 'device-list-properties',
+{ 'command': 'qom-list-properties',
'data': { 'typename': 'str'},
- 'returns': [ 'DevicePropertyInfo' ] }
+ 'returns': [ 'ObjectPropertyInfo' ] }
##
# @xen-set-global-dirty-log:
diff --git a/qdev-monitor.c b/qdev-monitor.c
index b8f6bc3f7e..b7e3291f8b 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -258,8 +258,8 @@ int qdev_device_help(QemuOpts *opts)
{
Error *local_err = NULL;
const char *driver;
- DevicePropertyInfoList *prop_list;
- DevicePropertyInfoList *prop;
+ ObjectPropertyInfoList *prop_list;
+ ObjectPropertyInfoList *prop;
driver = qemu_opt_get(opts, "driver");
if (driver && is_help_option(driver)) {
@@ -295,7 +295,7 @@ int qdev_device_help(QemuOpts *opts)
}
}
- qapi_free_DevicePropertyInfoList(prop_list);
+ qapi_free_ObjectPropertyInfoList(prop_list);
return 1;
error:
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 4fcc85acc7..39e38c87ec 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -2606,13 +2606,6 @@ which is the default.
@section System emulator command line arguments
-@subsection -tdf (since 1.3.0)
-
-The ``-tdf'' argument is ignored. The behaviour implemented
-by this argument is now the default when using the KVM PIT,
-but can be requested explicitly using
-``-global kvm-pit.lost_tick_policy=slew''.
-
@subsection -no-kvm-pit-reinjection (since 1.3.0)
The ``-no-kvm-pit-reinjection'' argument is now a
@@ -2687,11 +2680,6 @@ The ``-net vlan=NN'' argument is partially replaced with the
new ``-netdev'' argument. The remaining use cases will no
longer be directly supported in QEMU.
-@subsection -drive if=scsi (since 2.9.0)
-
-The ``-drive if=scsi'' argument is replaced by the the
-``-device BUS-TYPE'' argument combined with ``-drive if=none''.
-
@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
The drive geometry arguments are replaced by the the geometry arguments
@@ -2719,6 +2707,11 @@ enabled via the ``-machine usb=on'' argument.
The ``-nodefconfig`` argument is a synonym for ``-no-user-config``.
+@subsection -balloon (since 2.12.0)
+
+The @option{--balloon virtio} argument has been superseded by
+@option{--device virtio-balloon}.
+
@subsection -machine s390-squash-mcss=on|off (since 2.12.0)
The ``s390-squash-mcss=on`` property has been obsoleted by allowing the
@@ -2735,12 +2728,18 @@ filesystem test suite. Also it requires the CAP_DAC_READ_SEARCH capability,
which is not the recommended way to run QEMU. This backend should not be
used and it will be removed with no replacement.
-@subsection -no-frame (since 2.12.0)
+@subsection -rtc-td-hack (since 2.12.0)
+
+The @code{-rtc-td-hack} option has been replaced by
+@code{-rtc driftfix=slew}.
+
+@subsection -localtime (since 2.12.0)
+
+The @code{-localtime} option has been replaced by @code{-rtc base=localtime}.
+
+@subsection -startdate (since 2.12.0)
-The ``-no-frame'' argument works with SDL 1.2 only. SDL 2.0 lacks
-support for frameless windows, and the other user interfaces never
-implemented this in the first place. So this will be removed together
-with SDL 1.2 support.
+The @code{-startdate} option has been replaced by @code{-rtc base=@var{date}}.
@section qemu-img command line arguments
diff --git a/qemu-img.c b/qemu-img.c
index 40bf7aa7d1..088d89043e 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3469,7 +3469,7 @@ static int img_resize(int argc, char **argv)
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit("Expecting image file name and size");
}
filename = argv[optind++];
diff --git a/qemu-io.c b/qemu-io.c
index 2c00ea068e..160fb2a89f 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -504,7 +504,7 @@ int main(int argc, char **argv)
#endif
module_call_init(MODULE_INIT_TRACE);
- progname = basename(argv[0]);
+ progname = g_path_get_basename(argv[0]);
qemu_init_exec_dir(argv[0]);
qcrypto_init(&error_fatal);
diff --git a/qemu-options.hx b/qemu-options.hx
index 2a22a62f74..6585058c6c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -462,16 +462,13 @@ modprobe i810_audio clocking=48000
ETEXI
DEF("balloon", HAS_ARG, QEMU_OPTION_balloon,
- "-balloon none disable balloon device\n"
"-balloon virtio[,addr=str]\n"
- " enable virtio balloon device (default)\n", QEMU_ARCH_ALL)
+ " enable virtio balloon device (deprecated)\n", QEMU_ARCH_ALL)
STEXI
-@item -balloon none
-@findex -balloon
-Disable balloon device.
@item -balloon virtio[,addr=@var{addr}]
-Enable virtio balloon device (default), optionally with PCI address
-@var{addr}.
+@findex -balloon
+Enable virtio balloon device, optionally with PCI address @var{addr}. This
+option is deprecated, use @option{--device virtio-balloon} instead.
ETEXI
DEF("device", HAS_ARG, QEMU_OPTION_device,
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index ac17d0d6cf..0dc219dbcf 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -808,7 +808,7 @@ static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
len = readlink(dpath, buf, sizeof(buf) - 1);
if (len != -1) {
buf[len] = 0;
- driver = g_strdup(basename(buf));
+ driver = g_path_get_basename(buf);
}
g_free(dpath);
g_free(path);
@@ -1053,7 +1053,7 @@ static void build_guest_fsinfo_for_device(char const *devpath,
}
if (!fs->name) {
- fs->name = g_strdup(basename(syspath));
+ fs->name = g_path_get_basename(syspath);
}
g_debug(" parse sysfs path '%s'", syspath);
diff --git a/qmp.c b/qmp.c
index ba82e1df9f..8c7d1cc479 100644
--- a/qmp.c
+++ b/qmp.c
@@ -465,12 +465,12 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
*
* The caller must free the return value.
*/
-static DevicePropertyInfo *make_device_property_info(ObjectClass *klass,
- const char *name,
- const char *default_type,
- const char *description)
+static ObjectPropertyInfo *make_device_property_info(ObjectClass *klass,
+ const char *name,
+ const char *default_type,
+ const char *description)
{
- DevicePropertyInfo *info;
+ ObjectPropertyInfo *info;
Property *prop;
do {
@@ -510,14 +510,14 @@ static DevicePropertyInfo *make_device_property_info(ObjectClass *klass,
return info;
}
-DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
- Error **errp)
+ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
+ Error **errp)
{
ObjectClass *klass;
Object *obj;
ObjectProperty *prop;
ObjectPropertyIterator iter;
- DevicePropertyInfoList *prop_list = NULL;
+ ObjectPropertyInfoList *prop_list = NULL;
klass = object_class_by_name(typename);
if (klass == NULL) {
@@ -542,8 +542,8 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
object_property_iter_init(&iter, obj);
while ((prop = object_property_iter_next(&iter))) {
- DevicePropertyInfo *info;
- DevicePropertyInfoList *entry;
+ ObjectPropertyInfo *info;
+ ObjectPropertyInfoList *entry;
/* Skip Object and DeviceState properties */
if (strcmp(prop->name, "type") == 0 ||
@@ -578,6 +578,55 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
return prop_list;
}
+ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
+ Error **errp)
+{
+ ObjectClass *klass;
+ Object *obj = NULL;
+ ObjectProperty *prop;
+ ObjectPropertyIterator iter;
+ ObjectPropertyInfoList *prop_list = NULL;
+
+ klass = object_class_by_name(typename);
+ if (klass == NULL) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Class '%s' not found", typename);
+ return NULL;
+ }
+
+ klass = object_class_dynamic_cast(klass, TYPE_OBJECT);
+ if (klass == NULL) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_OBJECT);
+ return NULL;
+ }
+
+ if (object_class_is_abstract(klass)) {
+ object_class_property_iter_init(&iter, klass);
+ } else {
+ obj = object_new(typename);
+ object_property_iter_init(&iter, obj);
+ }
+ while ((prop = object_property_iter_next(&iter))) {
+ ObjectPropertyInfo *info;
+ ObjectPropertyInfoList *entry;
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(prop->name);
+ info->type = g_strdup(prop->type);
+ info->has_description = !!prop->description;
+ info->description = g_strdup(prop->description);
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = prop_list;
+ prop_list = entry;
+ }
+
+ object_unref(obj);
+
+ return prop_list;
+}
+
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
{
return arch_query_cpu_definitions(errp);
diff --git a/qom/object.c b/qom/object.c
index f70a75c308..755ad03819 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1037,6 +1037,13 @@ ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter)
return val;
}
+void object_class_property_iter_init(ObjectPropertyIterator *iter,
+ ObjectClass *klass)
+{
+ g_hash_table_iter_init(&iter->iter, klass->properties);
+ iter->nextclass = klass;
+}
+
ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
Error **errp)
{
diff --git a/roms/Makefile b/roms/Makefile
index b5e5a69e91..02b69fbac8 100644
--- a/roms/Makefile
+++ b/roms/Makefile
@@ -65,6 +65,7 @@ default:
@echo " slof -- update slof.bin"
@echo " skiboot -- update skiboot.lid"
@echo " u-boot.e500 -- update u-boot.e500"
+ @echo " u-boot.sam460 -- update u-boot.sam460"
bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k
cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin
@@ -147,6 +148,11 @@ u-boot.e500:
$(powerpc_cross_prefix)strip u-boot/build.e500/u-boot -o \
../pc-bios/u-boot.e500
+u-boot.sam460:
+ $(MAKE) -C u-boot-sam460ex Sam460ex_config
+ $(MAKE) -C u-boot-sam460ex CROSS_COMPILE=$(powerpc_cross_prefix)
+ cp u-boot-sam460ex/u-boot.bin ../pc-bios/u-boot-sam460-20100605.bin
+
skiboot:
$(MAKE) -C skiboot CROSS=$(powerpc64_cross_prefix)
cp skiboot/skiboot.lid ../pc-bios/skiboot.lid
@@ -160,4 +166,5 @@ clean:
$(MAKE) -C ipxe/src veryclean
$(MAKE) -C SLOF clean
rm -rf u-boot/build.e500
+ $(MAKE) -C u-boot-sam460ex distclean
$(MAKE) -C skiboot clean
diff --git a/roms/u-boot-sam460ex b/roms/u-boot-sam460ex
new file mode 160000
+Subproject 119aa277f74a4a2d3f7ab6c9471292308eba14e
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 1b4b812e28..d1fe79bcc4 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2352,8 +2352,9 @@ sub process {
}
}
-# check for missing bracing round if etc
- if ($line =~ /(^.*)\bif\b/ && $line !~ /\#\s*if/) {
+# check for missing bracing around if etc
+ if ($line =~ /(^.*)\b(?:if|while|for)\b/ &&
+ $line !~ /\#\s*if/) {
my ($level, $endln, @chunks) =
ctx_statement_full($linenr, $realcnt, 1);
if ($dbg_adv_apw) {
@@ -2584,6 +2585,11 @@ sub process {
ERROR("__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr);
}
+# recommend g_path_get_* over g_strdup(basename/dirname(...))
+ if ($line =~ /\bg_strdup\s*\(\s*(basename|dirname)\s*\(/) {
+ WARN("consider using g_path_get_$1() in preference to g_strdup($1())\n" . $herecurr);
+ }
+
# recommend qemu_strto* over strto* for numeric conversions
if ($line =~ /\b(strto[^kd].*?)\s*\(/) {
ERROR("consider using qemu_$1 in preference to $1\n" . $herecurr);
diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c
index 0015b27509..940bbe590d 100644
--- a/target/i386/whpx-all.c
+++ b/target/i386/whpx-all.c
@@ -26,13 +26,12 @@
#include "qapi/error.h"
#include "migration/blocker.h"
-#include <winhvplatform.h>
-#include <winhvemulation.h>
+#include <WinHvPlatform.h>
+#include <WinHvEmulation.h>
struct whpx_state {
uint64_t mem_quota;
WHV_PARTITION_HANDLE partition;
- uint32_t exit_ctx_size;
};
static const WHV_REGISTER_NAME whpx_register_names[] = {
@@ -364,7 +363,6 @@ static void whpx_set_registers(CPUState *cpu)
if (FAILED(hr)) {
error_report("WHPX: Failed to set virtual processor context, hr=%08lx",
hr);
- __debugbreak();
}
return;
@@ -391,7 +389,6 @@ static void whpx_get_registers(CPUState *cpu)
if (FAILED(hr)) {
error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
hr);
- __debugbreak();
}
/* Indexes for first 16 registers match between HV and QEMU definitions */
@@ -529,7 +526,7 @@ static HRESULT CALLBACK whpx_emu_ioport_callback(
return S_OK;
}
-static HRESULT CALLBACK whpx_emu_memio_callback(
+static HRESULT CALLBACK whpx_emu_mmio_callback(
void *ctx,
WHV_EMULATOR_MEMORY_ACCESS_INFO *ma)
{
@@ -554,7 +551,6 @@ static HRESULT CALLBACK whpx_emu_getreg_callback(
if (FAILED(hr)) {
error_report("WHPX: Failed to get virtual processor registers,"
" hr=%08lx", hr);
- __debugbreak();
}
return hr;
@@ -576,7 +572,6 @@ static HRESULT CALLBACK whpx_emu_setreg_callback(
if (FAILED(hr)) {
error_report("WHPX: Failed to set virtual processor registers,"
" hr=%08lx", hr);
- __debugbreak();
}
/*
@@ -604,7 +599,6 @@ static HRESULT CALLBACK whpx_emu_translate_callback(
Gva, TranslateFlags, &res, Gpa);
if (FAILED(hr)) {
error_report("WHPX: Failed to translate GVA, hr=%08lx", hr);
- __debugbreak();
} else {
*TranslationResult = res.ResultCode;
}
@@ -613,8 +607,9 @@ static HRESULT CALLBACK whpx_emu_translate_callback(
}
static const WHV_EMULATOR_CALLBACKS whpx_emu_callbacks = {
+ .Size = sizeof(WHV_EMULATOR_CALLBACKS),
.WHvEmulatorIoPortCallback = whpx_emu_ioport_callback,
- .WHvEmulatorMemoryCallback = whpx_emu_memio_callback,
+ .WHvEmulatorMemoryCallback = whpx_emu_mmio_callback,
.WHvEmulatorGetVirtualProcessorRegisters = whpx_emu_getreg_callback,
.WHvEmulatorSetVirtualProcessorRegisters = whpx_emu_setreg_callback,
.WHvEmulatorTranslateGvaPage = whpx_emu_translate_callback,
@@ -626,15 +621,15 @@ static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
WHV_EMULATOR_STATUS emu_status;
- hr = WHvEmulatorTryMmioEmulation(vcpu->emulator, cpu, ctx, &emu_status);
+ hr = WHvEmulatorTryMmioEmulation(vcpu->emulator, cpu,
+ &vcpu->exit_ctx.VpContext, ctx,
+ &emu_status);
if (FAILED(hr)) {
- __debugbreak();
error_report("WHPX: Failed to parse MMIO access, hr=%08lx", hr);
return -1;
}
if (!emu_status.EmulationSuccessful) {
- __debugbreak();
error_report("WHPX: Failed to emulate MMIO access");
return -1;
}
@@ -649,15 +644,15 @@ static int whpx_handle_portio(CPUState *cpu,
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
WHV_EMULATOR_STATUS emu_status;
- hr = WHvEmulatorTryIoEmulation(vcpu->emulator, cpu, ctx, &emu_status);
+ hr = WHvEmulatorTryIoEmulation(vcpu->emulator, cpu,
+ &vcpu->exit_ctx.VpContext, ctx,
+ &emu_status);
if (FAILED(hr)) {
- __debugbreak();
error_report("WHPX: Failed to parse PortIO access, hr=%08lx", hr);
return -1;
}
if (!emu_status.EmulationSuccessful) {
- __debugbreak();
error_report("WHPX: Failed to emulate PortMMIO access");
return -1;
}
@@ -691,6 +686,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
X86CPU *x86_cpu = X86_CPU(cpu);
int irq;
+ uint8_t tpr;
WHV_X64_PENDING_INTERRUPTION_REGISTER new_int = {0};
UINT32 reg_count = 0;
WHV_REGISTER_VALUE reg_values[3] = {0};
@@ -709,10 +705,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
new_int.InterruptionVector = 2;
}
if (cpu->interrupt_request & CPU_INTERRUPT_SMI) {
- qemu_mutex_lock_iothread();
cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
- __debugbreak();
- qemu_mutex_unlock_iothread();
}
}
@@ -753,21 +746,21 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
}
/* Sync the TPR to the CR8 if was modified during the intercept */
- reg_values[reg_count].Reg64 = cpu_get_apic_tpr(x86_cpu->apic_state);
- if (reg_values[reg_count].Reg64 != vcpu->tpr) {
- vcpu->tpr = reg_values[reg_count].Reg64;
+ tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
+ if (tpr != vcpu->tpr) {
+ vcpu->tpr = tpr;
+ reg_values[reg_count].Reg64 = tpr;
cpu->exit_request = 1;
reg_names[reg_count] = WHvX64RegisterCr8;
reg_count += 1;
}
/* Update the state of the interrupt delivery notification */
- if (cpu->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (!vcpu->window_registered &&
+ cpu->interrupt_request & CPU_INTERRUPT_HARD) {
reg_values[reg_count].DeliverabilityNotifications.InterruptNotification
= 1;
- if (vcpu->window_registered != 1) {
- vcpu->window_registered = 1;
- }
+ vcpu->window_registered = 1;
reg_names[reg_count] = WHvX64RegisterDeliverabilityNotifications;
reg_count += 1;
}
@@ -780,7 +773,6 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
if (FAILED(hr)) {
error_report("WHPX: Failed to set interrupt state registers,"
" hr=%08lx", hr);
- __debugbreak();
}
}
@@ -807,7 +799,6 @@ static void whpx_vcpu_post_run(CPUState *cpu)
if (FAILED(hr)) {
error_report("WHPX: Failed to get interrupt state regusters,"
" hr=%08lx", hr);
- __debugbreak();
vcpu->interruptable = false;
return;
}
@@ -905,18 +896,8 @@ static int whpx_vcpu_run(CPUState *cpu)
whpx_vcpu_kick(cpu);
}
- for (;;) {
- hr = WHvRunVirtualProcessor(whpx->partition, cpu->cpu_index,
- &vcpu->exit_ctx, whpx->exit_ctx_size);
-
- if (SUCCEEDED(hr) && (vcpu->exit_ctx.ExitReason ==
- WHvRunVpExitReasonAlerted)) {
- WHvCancelRunVirtualProcessor(whpx->partition, cpu->cpu_index,
- 0);
- } else {
- break;
- }
- }
+ hr = WHvRunVirtualProcessor(whpx->partition, cpu->cpu_index,
+ &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));
if (FAILED(hr)) {
error_report("WHPX: Failed to exec a virtual processor,"
@@ -956,7 +937,6 @@ static int whpx_vcpu_run(CPUState *cpu)
case WHvRunVpExitReasonX64MsrAccess:
case WHvRunVpExitReasonX64Cpuid:
case WHvRunVpExitReasonException:
- case WHvRunVpExitReasonAlerted:
default:
error_report("WHPX: Unexpected VP exit code %d",
vcpu->exit_ctx.ExitReason);
@@ -1060,15 +1040,14 @@ int whpx_init_vcpu(CPUState *cpu)
}
}
- vcpu = g_malloc0(FIELD_OFFSET(struct whpx_vcpu, exit_ctx) +
- whpx->exit_ctx_size);
+ vcpu = g_malloc0(sizeof(struct whpx_vcpu));
if (!vcpu) {
error_report("WHPX: Failed to allocte VCPU context.");
return -ENOMEM;
}
- hr = WHvEmulatorCreateEmulator(whpx_emu_callbacks, &vcpu->emulator);
+ hr = WHvEmulatorCreateEmulator(&whpx_emu_callbacks, &vcpu->emulator);
if (FAILED(hr)) {
error_report("WHPX: Failed to setup instruction completion support,"
" hr=%08lx", hr);
@@ -1318,9 +1297,6 @@ static int whpx_accel_init(MachineState *ms)
goto error;
}
- whpx->exit_ctx_size = WHvGetRunExitContextSize();
- assert(whpx->exit_ctx_size);
-
whpx_memory_init();
cpu_interrupt_handler = whpx_handle_interrupt;
diff --git a/target/ppc/kvm-stub.c b/target/ppc/kvm-stub.c
index efeafca1df..b8aa97f2d4 100644
--- a/target/ppc/kvm-stub.c
+++ b/target/ppc/kvm-stub.c
@@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
-#include "hw/ppc/openpic.h"
+#include "hw/ppc/openpic_kvm.h"
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
{
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 9842b3bb12..79a436a384 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2494,8 +2494,10 @@ static void kvmppc_get_cpu_characteristics(KVMState *s)
cap_ppc_safe_bounds_check = 1;
}
/* Parse and set cap_ppc_safe_indirect_branch */
- if (c.character & H_CPU_CHAR_BCCTRL_SERIALISED) {
- cap_ppc_safe_indirect_branch = 2;
+ if (c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) {
+ cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_CCD;
+ } else if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) {
+ cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_IBS;
}
}
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index 17a87df654..391b94b97d 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -8692,6 +8692,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
(1ull << MSR_DR) |
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
+ (1ull << MSR_TS0) |
+ (1ull << MSR_TS1) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_2_07;
#if defined(CONFIG_SOFTMMU)
diff --git a/tests/Makefile.include b/tests/Makefile.include
index fdca062591..ef9b88c369 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -92,6 +92,7 @@ gcov-files-test-hbitmap-y = blockjob.c
check-unit-y += tests/test-bdrv-drain$(EXESUF)
check-unit-y += tests/test-blockjob$(EXESUF)
check-unit-y += tests/test-blockjob-txn$(EXESUF)
+check-unit-y += tests/test-block-backend$(EXESUF)
check-unit-y += tests/test-x86-cpuid$(EXESUF)
# all code tested by test-x86-cpuid is inside topology.h
gcov-files-test-x86-cpuid-y =
@@ -622,6 +623,7 @@ tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
+tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 2342fe3099..fb3cd84d07 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -1823,6 +1823,7 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr,
if ((addr == ADDR_MODE_LBA48) && (offset == OFFSET_HIGH) &&
(mb_to_sectors(test_image_size_mb) <= 0xFFFFFFF)) {
g_test_message("%s: skipped; test image too small", name);
+ g_free(opts);
g_free(name);
return;
}
diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033
index 2cdfd1397a..a1d8357331 100755
--- a/tests/qemu-iotests/033
+++ b/tests/qemu-iotests/033
@@ -64,6 +64,9 @@ do_test()
} | $QEMU_IO $IO_EXTRA_ARGS
}
+echo
+echo "=== Test aligned and misaligned write zeroes operations ==="
+
for write_zero_cmd in "write -z" "aio_write -z"; do
for align in 512 4k; do
echo
@@ -102,7 +105,33 @@ for align in 512 4k; do
done
done
+
+# Trigger truncate that would shrink qcow2 L1 table, which is done by
+# clearing one entry (8 bytes) with bdrv_co_pwrite_zeroes()
+
+echo
+echo "=== Test misaligned write zeroes via truncate ==="
+echo
+
+# any size will do, but the smaller the size the smaller the required image
+CLUSTER_SIZE=$((4 * 1024))
+L2_COVERAGE=$(($CLUSTER_SIZE * $CLUSTER_SIZE / 8))
+_make_test_img $(($L2_COVERAGE * 2))
+
+do_test 512 "write -P 1 0 0x200" "$TEST_IMG" | _filter_qemu_io
+# next L2 table
+do_test 512 "write -P 1 $L2_COVERAGE 0x200" "$TEST_IMG" | _filter_qemu_io
+
+# only interested in qcow2 here; also other formats might respond with
+# "not supported" error message
+if [ $IMGFMT = "qcow2" ]; then
+ do_test 512 "truncate $L2_COVERAGE" "$TEST_IMG" | _filter_qemu_io
+fi
+
+do_test 512 "read -P 1 0 0x200" "$TEST_IMG" | _filter_qemu_io
+
# success, all done
+echo
echo "*** done"
rm -f $seq.full
status=0
diff --git a/tests/qemu-iotests/033.out b/tests/qemu-iotests/033.out
index 95929eff70..9683f6b290 100644
--- a/tests/qemu-iotests/033.out
+++ b/tests/qemu-iotests/033.out
@@ -1,6 +1,8 @@
QA output created by 033
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+=== Test aligned and misaligned write zeroes operations ===
+
== preparing image ==
wrote 1024/1024 bytes at offset 512
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -164,4 +166,15 @@ read 512/512 bytes at offset 512
read 3072/3072 bytes at offset 1024
3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Test misaligned write zeroes via truncate ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 512/512 bytes at offset 2097152
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
*** done
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 0c3be16489..f617e25e24 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -157,9 +157,7 @@ case "$QEMU_DEFAULT_MACHINE" in
pc)
run_qemu -drive if=floppy
run_qemu -drive if=ide,media=cdrom
- run_qemu -drive if=scsi,media=cdrom
run_qemu -drive if=ide
- run_qemu -drive if=scsi
;;
*)
;;
@@ -188,9 +186,7 @@ case "$QEMU_DEFAULT_MACHINE" in
pc)
run_qemu -drive file="$TEST_IMG",if=floppy,readonly=on
run_qemu -drive file="$TEST_IMG",if=ide,media=cdrom,readonly=on
- run_qemu -drive file="$TEST_IMG",if=scsi,media=cdrom,readonly=on
run_qemu -drive file="$TEST_IMG",if=ide,readonly=on
- run_qemu -drive file="$TEST_IMG",if=scsi,readonly=on
;;
*)
;;
diff --git a/tests/sdhci-test.c b/tests/sdhci-test.c
index 6b3a5328e0..1d825eb010 100644
--- a/tests/sdhci-test.c
+++ b/tests/sdhci-test.c
@@ -209,8 +209,10 @@ static QSDHCI *machine_start(const struct sdhci_t *test)
static void machine_stop(QSDHCI *s)
{
+ qpci_free_pc(s->pci.bus);
g_free(s->pci.dev);
qtest_quit(global_qtest);
+ g_free(s);
}
static void test_machine(const void *data)
diff --git a/tests/test-block-backend.c b/tests/test-block-backend.c
new file mode 100644
index 0000000000..fd59f02bd0
--- /dev/null
+++ b/tests/test-block-backend.c
@@ -0,0 +1,82 @@
+/*
+ * BlockBackend tests
+ *
+ * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "block/block.h"
+#include "sysemu/block-backend.h"
+#include "qapi/error.h"
+
+static void test_drain_aio_error_flush_cb(void *opaque, int ret)
+{
+ bool *completed = opaque;
+
+ g_assert(ret == -ENOMEDIUM);
+ *completed = true;
+}
+
+static void test_drain_aio_error(void)
+{
+ BlockBackend *blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
+ BlockAIOCB *acb;
+ bool completed = false;
+
+ acb = blk_aio_flush(blk, test_drain_aio_error_flush_cb, &completed);
+ g_assert(acb != NULL);
+ g_assert(completed == false);
+
+ blk_drain(blk);
+ g_assert(completed == true);
+
+ blk_unref(blk);
+}
+
+static void test_drain_all_aio_error(void)
+{
+ BlockBackend *blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
+ BlockAIOCB *acb;
+ bool completed = false;
+
+ acb = blk_aio_flush(blk, test_drain_aio_error_flush_cb, &completed);
+ g_assert(acb != NULL);
+ g_assert(completed == false);
+
+ blk_drain_all();
+ g_assert(completed == true);
+
+ blk_unref(blk);
+}
+
+int main(int argc, char **argv)
+{
+ bdrv_init();
+ qemu_init_main_loop(&error_abort);
+
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/block-backend/drain_aio_error", test_drain_aio_error);
+ g_test_add_func("/block-backend/drain_all_aio_error",
+ test_drain_all_aio_error);
+
+ return g_test_run();
+}
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 3fb611631f..ae90b9963d 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -1,7 +1,7 @@
util-obj-y = osdep.o cutils.o unicode.o qemu-timer-common.o
util-obj-y += bufferiszero.o
util-obj-y += lockcnt.o
-util-obj-y += aiocb.o async.o thread-pool.o qemu-timer.o
+util-obj-y += aiocb.o async.o aio-wait.o thread-pool.o qemu-timer.o
util-obj-y += main-loop.o iohandler.o
util-obj-$(CONFIG_POSIX) += aio-posix.o
util-obj-$(CONFIG_POSIX) += compatfd.o
diff --git a/util/aio-wait.c b/util/aio-wait.c
new file mode 100644
index 0000000000..a487cdb852
--- /dev/null
+++ b/util/aio-wait.c
@@ -0,0 +1,40 @@
+/*
+ * AioContext wait support
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "block/aio-wait.h"
+
+static void dummy_bh_cb(void *opaque)
+{
+ /* The point is to make AIO_WAIT_WHILE()'s aio_poll() return */
+}
+
+void aio_wait_kick(AioWait *wait)
+{
+ /* The barrier (or an atomic op) is in the caller. */
+ if (atomic_read(&wait->need_kick)) {
+ aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
+ }
+}
diff --git a/vl.c b/vl.c
index 6120b889ed..dae986b352 100644
--- a/vl.c
+++ b/vl.c
@@ -2209,6 +2209,9 @@ static int balloon_parse(const char *arg)
{
QemuOpts *opts;
+ warn_report("This option is deprecated. "
+ "Use '--device virtio-balloon' to enable the balloon device.");
+
if (strcmp(arg, "none") == 0) {
return 0;
}
@@ -3406,6 +3409,8 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_localtime:
rtc_utc = 0;
+ warn_report("This option is deprecated, "
+ "use '-rtc base=localtime' instead.");
break;
case QEMU_OPTION_vga:
vga_model = optarg;
@@ -3665,6 +3670,8 @@ int main(int argc, char **argv, char **envp)
};
qdev_prop_register_global(&slew_lost_ticks);
+ warn_report("This option is deprecated, "
+ "use '-rtc driftfix=slew' instead.");
break;
}
case QEMU_OPTION_acpitable:
@@ -3842,9 +3849,6 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
- case QEMU_OPTION_tdf:
- warn_report("ignoring deprecated option");
- break;
case QEMU_OPTION_name:
opts = qemu_opts_parse_noisily(qemu_find_opts("name"),
optarg, true);
@@ -3869,6 +3873,7 @@ int main(int argc, char **argv, char **envp)
*/
break;
case QEMU_OPTION_startdate:
+ warn_report("This option is deprecated, use '-rtc base=' instead.");
configure_rtc_date_offset(optarg, 1);
break;
case QEMU_OPTION_rtc:
@@ -4624,15 +4629,6 @@ int main(int argc, char **argv, char **envp)
rom_reset_order_override();
- /*
- * Create frontends for -drive if=scsi leftovers.
- * Normally, frontends for -drive get created by machine
- * initialization for onboard SCSI HBAs. However, we create a few
- * more ever since SCSI qdevification, but this is pretty much an
- * implementation accident, and deprecated.
- */
- scsi_legacy_handle_cmdline();
-
/* Did we create any drives that we failed to create a device for? */
drive_check_orphaned();