Compare commits
153 Commits
v2.5.0-rc0
...
v2.1.3
Author | SHA1 | Date | |
---|---|---|---|
|
c2b0926634 | ||
|
b316937d38 | ||
|
5b5c7bf8e5 | ||
|
6df8cd2e27 | ||
|
ff2fff6211 | ||
|
83a66746c0 | ||
|
39639d81e3 | ||
|
6e64c4e6f1 | ||
|
73c1527f96 | ||
|
b466e1731b | ||
|
6a47ae2d41 | ||
|
5f0681e1c3 | ||
|
75eb0f5dbb | ||
|
b495764ae8 | ||
|
21640bf6e0 | ||
|
6bbb939a80 | ||
|
178ed9aad3 | ||
|
0505d48c83 | ||
|
0073781fea | ||
|
175117c159 | ||
|
aa58eedb35 | ||
|
e6c172ad9e | ||
|
07ede68671 | ||
|
2fbad1f944 | ||
|
dee284885a | ||
|
ad0983b5d1 | ||
|
b3729b2ec2 | ||
|
1b9ea8961a | ||
|
cdeb85cf24 | ||
|
b28d7b585a | ||
|
cd2f44cc3e | ||
|
844470158c | ||
|
05c5febf8c | ||
|
de98dc9539 | ||
|
0c80570170 | ||
|
14b51b6718 | ||
|
ea227e222b | ||
|
aae114b7ed | ||
|
cfa86bcb7d | ||
|
b57b7ec340 | ||
|
f8c61ebdd2 | ||
|
c448fb7651 | ||
|
8239a583c1 | ||
|
cb91dce13e | ||
|
b2f1d90530 | ||
|
5a6af97243 | ||
|
90de7a03bb | ||
|
57248587af | ||
|
ff830f9d88 | ||
|
82e8913341 | ||
|
38e6e1c6a3 | ||
|
4bcf40b288 | ||
|
8bf7738ff2 | ||
|
8100812711 | ||
|
cf0276b7c0 | ||
|
b5ad76a709 | ||
|
20dc758b7f | ||
|
0077793a00 | ||
|
c4164eae39 | ||
|
8c64b47eeb | ||
|
aa383e9a83 | ||
|
f06c87b119 | ||
|
eb5388e260 | ||
|
83f81f344f | ||
|
b6bd501d6a | ||
|
0369529b37 | ||
|
c29bf825ee | ||
|
e2d402d0a1 | ||
|
4d492e8909 | ||
|
45c46f20c6 | ||
|
c4379ce8ef | ||
|
a95569d24f | ||
|
15905fde7b | ||
|
f1a842948a | ||
|
09d552b40f | ||
|
d754428b9b | ||
|
5d350980f6 | ||
|
ff1f973003 | ||
|
0b2d2e094a | ||
|
4a58f3c2d8 | ||
|
96c6cf6d30 | ||
|
b5fc105016 | ||
|
e1cf5a23d1 | ||
|
490a0f887e | ||
|
e4fb3debc3 | ||
|
7fb768ea30 | ||
|
2151206778 | ||
|
c35ba0d9e4 | ||
|
61048e1942 | ||
|
a9ed61533f | ||
|
3807aeb1d4 | ||
|
ff3bd5e4bb | ||
|
d6af26d6ce | ||
|
8bb90ee80a | ||
|
562d6b4f7f | ||
|
9a72433843 | ||
|
00dd2b22f6 | ||
|
80f4d021f0 | ||
|
074e347138 | ||
|
9e8d994111 | ||
|
a56b9cfd86 | ||
|
07178559a9 | ||
|
3cb451edb2 | ||
|
82d80e1f0b | ||
|
5dd076a9f8 | ||
|
257e9cfce2 | ||
|
1aa87d3689 | ||
|
7fe5418d9f | ||
|
c5042f04f7 | ||
|
cf29a88391 | ||
|
08743db463 | ||
|
d9c06c0d79 | ||
|
f321710cd4 | ||
|
ec48bfd57b | ||
|
eb36f79d59 | ||
|
34d41c1a20 | ||
|
6f8d05a8f8 | ||
|
5e83dae44e | ||
|
ff34ca00fd | ||
|
e685d2abf7 | ||
|
67cfda8776 | ||
|
4fd144f8f5 | ||
|
ea774b8dd0 | ||
|
3e8966df02 | ||
|
ba8576f338 | ||
|
07f8c97f84 | ||
|
72c9c9a05e | ||
|
3d8cc86e4f | ||
|
0824ca6bd1 | ||
|
feb633411f | ||
|
75ada6b763 | ||
|
be3af755ac | ||
|
bfe3e6f5e3 | ||
|
cd4acff8d0 | ||
|
4b59161253 | ||
|
fab7560c35 | ||
|
16c92cd629 | ||
|
dea6efe883 | ||
|
8c4edd743c | ||
|
504e2a7139 | ||
|
2f6d5e1c9c | ||
|
20463dc874 | ||
|
2a575c450e | ||
|
1ad9dcec47 | ||
|
ba1bc81991 | ||
|
948574e0d2 | ||
|
044af98ea8 | ||
|
7c68c5402a | ||
|
bd4740621c | ||
|
e22d5dc073 | ||
|
dfd4808222 | ||
|
5f26e63b17 | ||
|
42f7a13178 |
@@ -191,9 +191,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
|
|||||||
audio_detach_capture (hw);
|
audio_detach_capture (hw);
|
||||||
#endif
|
#endif
|
||||||
QLIST_REMOVE (hw, entries);
|
QLIST_REMOVE (hw, entries);
|
||||||
|
glue (hw->pcm_ops->fini_, TYPE) (hw);
|
||||||
glue (s->nb_hw_voices_, TYPE) += 1;
|
glue (s->nb_hw_voices_, TYPE) += 1;
|
||||||
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
|
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
|
||||||
glue (hw->pcm_ops->fini_, TYPE) (hw);
|
|
||||||
g_free (hw);
|
g_free (hw);
|
||||||
*hwp = NULL;
|
*hwp = NULL;
|
||||||
}
|
}
|
||||||
|
@@ -304,7 +304,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
|
|||||||
/* ensure policy won't be ignored in case memory is preallocated
|
/* ensure policy won't be ignored in case memory is preallocated
|
||||||
* before mbind(). note: MPOL_MF_STRICT is ignored on hugepages so
|
* before mbind(). note: MPOL_MF_STRICT is ignored on hugepages so
|
||||||
* this doesn't catch hugepage case. */
|
* this doesn't catch hugepage case. */
|
||||||
unsigned flags = MPOL_MF_STRICT;
|
unsigned flags = MPOL_MF_STRICT | MPOL_MF_MOVE;
|
||||||
|
|
||||||
/* check for invalid host-nodes and policies and give more verbose
|
/* check for invalid host-nodes and policies and give more verbose
|
||||||
* error messages than mbind(). */
|
* error messages than mbind(). */
|
||||||
|
@@ -169,6 +169,7 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
|
|||||||
if (b->opened) {
|
if (b->opened) {
|
||||||
error_set(errp, QERR_PERMISSION_DENIED);
|
error_set(errp, QERR_PERMISSION_DENIED);
|
||||||
} else {
|
} else {
|
||||||
|
g_free(s->chr_name);
|
||||||
s->chr_name = g_strdup(value);
|
s->chr_name = g_strdup(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -652,6 +652,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int64_t last_ftell = qemu_ftell(f);
|
int64_t last_ftell = qemu_ftell(f);
|
||||||
|
int64_t delta_ftell;
|
||||||
|
|
||||||
DPRINTF("Enter save live iterate submitted %d transferred %d\n",
|
DPRINTF("Enter save live iterate submitted %d transferred %d\n",
|
||||||
block_mig_state.submitted, block_mig_state.transferred);
|
block_mig_state.submitted, block_mig_state.transferred);
|
||||||
@@ -701,7 +702,14 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
|
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
|
||||||
return qemu_ftell(f) - last_ftell;
|
delta_ftell = qemu_ftell(f) - last_ftell;
|
||||||
|
if (delta_ftell > 0) {
|
||||||
|
return 1;
|
||||||
|
} else if (delta_ftell < 0) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called with iothread lock taken. */
|
/* Called with iothread lock taken. */
|
||||||
@@ -756,8 +764,8 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
|
|||||||
block_mig_state.read_done * BLOCK_SIZE;
|
block_mig_state.read_done * BLOCK_SIZE;
|
||||||
|
|
||||||
/* Report at least one block pending during bulk phase */
|
/* Report at least one block pending during bulk phase */
|
||||||
if (pending == 0 && !block_mig_state.bulk_completed) {
|
if (pending <= max_size && !block_mig_state.bulk_completed) {
|
||||||
pending = BLOCK_SIZE;
|
pending = max_size + BLOCK_SIZE;
|
||||||
}
|
}
|
||||||
blk_mig_unlock();
|
blk_mig_unlock();
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
|
36
block.c
36
block.c
@@ -633,7 +633,7 @@ BlockDriver *bdrv_find_protocol(const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!path_has_protocol(filename) || !allow_protocol_prefix) {
|
if (!path_has_protocol(filename) || !allow_protocol_prefix) {
|
||||||
return bdrv_find_format("file");
|
return &bdrv_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = strchr(filename, ':');
|
p = strchr(filename, ':');
|
||||||
@@ -662,12 +662,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
|
|||||||
|
|
||||||
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
|
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
|
||||||
if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
|
if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
|
||||||
drv = bdrv_find_format("raw");
|
*pdrv = &bdrv_raw;
|
||||||
if (!drv) {
|
|
||||||
error_setg(errp, "Could not find raw image format");
|
|
||||||
ret = -ENOENT;
|
|
||||||
}
|
|
||||||
*pdrv = drv;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1182,7 +1177,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
|||||||
{
|
{
|
||||||
char *backing_filename = g_malloc0(PATH_MAX);
|
char *backing_filename = g_malloc0(PATH_MAX);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
BlockDriver *back_drv = NULL;
|
|
||||||
BlockDriverState *backing_hd;
|
BlockDriverState *backing_hd;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
@@ -1215,14 +1209,14 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
|||||||
|
|
||||||
backing_hd = bdrv_new("", errp);
|
backing_hd = bdrv_new("", errp);
|
||||||
|
|
||||||
if (bs->backing_format[0] != '\0') {
|
if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
|
||||||
back_drv = bdrv_find_format(bs->backing_format);
|
qdict_put(options, "driver", qstring_from_str(bs->backing_format));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(bs->backing_hd == NULL);
|
assert(bs->backing_hd == NULL);
|
||||||
ret = bdrv_open(&backing_hd,
|
ret = bdrv_open(&backing_hd,
|
||||||
*backing_filename ? backing_filename : NULL, NULL, options,
|
*backing_filename ? backing_filename : NULL, NULL, options,
|
||||||
bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
|
bdrv_backing_flags(bs->open_flags), NULL, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bdrv_unref(backing_hd);
|
bdrv_unref(backing_hd);
|
||||||
backing_hd = NULL;
|
backing_hd = NULL;
|
||||||
@@ -1296,7 +1290,6 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
|||||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||||
char *tmp_filename = g_malloc0(PATH_MAX + 1);
|
char *tmp_filename = g_malloc0(PATH_MAX + 1);
|
||||||
int64_t total_size;
|
int64_t total_size;
|
||||||
BlockDriver *bdrv_qcow2;
|
|
||||||
QemuOpts *opts = NULL;
|
QemuOpts *opts = NULL;
|
||||||
QDict *snapshot_options;
|
QDict *snapshot_options;
|
||||||
BlockDriverState *bs_snapshot;
|
BlockDriverState *bs_snapshot;
|
||||||
@@ -1322,11 +1315,10 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_qcow2 = bdrv_find_format("qcow2");
|
opts = qemu_opts_create(bdrv_qcow2.create_opts, NULL, 0,
|
||||||
opts = qemu_opts_create(bdrv_qcow2->create_opts, NULL, 0,
|
|
||||||
&error_abort);
|
&error_abort);
|
||||||
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size);
|
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size);
|
||||||
ret = bdrv_create(bdrv_qcow2, tmp_filename, opts, &local_err);
|
ret = bdrv_create(&bdrv_qcow2, tmp_filename, opts, &local_err);
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not create temporary overlay "
|
error_setg_errno(errp, -ret, "Could not create temporary overlay "
|
||||||
@@ -1346,7 +1338,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
|||||||
bs_snapshot = bdrv_new("", &error_abort);
|
bs_snapshot = bdrv_new("", &error_abort);
|
||||||
|
|
||||||
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||||
flags, bdrv_qcow2, &local_err);
|
flags, &bdrv_qcow2, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -5535,6 +5527,18 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!drv->create_opts) {
|
||||||
|
error_setg(errp, "Format driver '%s' does not support image creation",
|
||||||
|
drv->format_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!proto_drv->create_opts) {
|
||||||
|
error_setg(errp, "Protocol driver '%s' does not support image creation",
|
||||||
|
proto_drv->format_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
create_opts = qemu_opts_append(create_opts, drv->create_opts);
|
create_opts = qemu_opts_append(create_opts, drv->create_opts);
|
||||||
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
|
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
|
||||||
|
|
||||||
|
@@ -449,6 +449,10 @@ static void error_callback_bh(void *opaque)
|
|||||||
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
|
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||||
{
|
{
|
||||||
BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
|
BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
|
||||||
|
if (acb->bh) {
|
||||||
|
qemu_bh_delete(acb->bh);
|
||||||
|
acb->bh = NULL;
|
||||||
|
}
|
||||||
qemu_aio_release(acb);
|
qemu_aio_release(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,6 +526,25 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
|||||||
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
|
||||||
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
|
{
|
||||||
|
BDRVBlkdebugState *s = bs->opaque;
|
||||||
|
BlkdebugRule *rule = NULL;
|
||||||
|
|
||||||
|
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
|
||||||
|
if (rule->options.inject.sector == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule && rule->options.inject.error) {
|
||||||
|
return inject_error(bs, cb, opaque, rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bdrv_aio_flush(bs->file, cb, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void blkdebug_close(BlockDriverState *bs)
|
static void blkdebug_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
@@ -699,6 +722,7 @@ static BlockDriver bdrv_blkdebug = {
|
|||||||
|
|
||||||
.bdrv_aio_readv = blkdebug_aio_readv,
|
.bdrv_aio_readv = blkdebug_aio_readv,
|
||||||
.bdrv_aio_writev = blkdebug_aio_writev,
|
.bdrv_aio_writev = blkdebug_aio_writev,
|
||||||
|
.bdrv_aio_flush = blkdebug_aio_flush,
|
||||||
|
|
||||||
.bdrv_debug_event = blkdebug_debug_event,
|
.bdrv_debug_event = blkdebug_debug_event,
|
||||||
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
|
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
|
||||||
|
@@ -1509,7 +1509,8 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
|||||||
if (iscsilun->allocationmap != NULL) {
|
if (iscsilun->allocationmap != NULL) {
|
||||||
g_free(iscsilun->allocationmap);
|
g_free(iscsilun->allocationmap);
|
||||||
iscsilun->allocationmap =
|
iscsilun->allocationmap =
|
||||||
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
bitmap_new(DIV_ROUND_UP(sector_lun2qemu(iscsilun->num_blocks,
|
||||||
|
iscsilun),
|
||||||
iscsilun->cluster_sectors));
|
iscsilun->cluster_sectors));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
block/nfs.c
15
block/nfs.c
@@ -401,6 +401,19 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QemuOptsList nfs_create_opts = {
|
||||||
|
.name = "nfs-create-opts",
|
||||||
|
.head = QTAILQ_HEAD_INITIALIZER(nfs_create_opts.head),
|
||||||
|
.desc = {
|
||||||
|
{
|
||||||
|
.name = BLOCK_OPT_SIZE,
|
||||||
|
.type = QEMU_OPT_SIZE,
|
||||||
|
.help = "Virtual disk size"
|
||||||
|
},
|
||||||
|
{ /* end of list */ }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
|
static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -461,6 +474,8 @@ static BlockDriver bdrv_nfs = {
|
|||||||
|
|
||||||
.instance_size = sizeof(NFSClient),
|
.instance_size = sizeof(NFSClient),
|
||||||
.bdrv_needs_filename = true,
|
.bdrv_needs_filename = true,
|
||||||
|
.create_opts = &nfs_create_opts,
|
||||||
|
|
||||||
.bdrv_has_zero_init = nfs_has_zero_init,
|
.bdrv_has_zero_init = nfs_has_zero_init,
|
||||||
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
|
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
|
||||||
.bdrv_truncate = nfs_file_truncate,
|
.bdrv_truncate = nfs_file_truncate,
|
||||||
|
@@ -158,12 +158,14 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
|
|||||||
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t buf[L1_ENTRIES_PER_SECTOR];
|
uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 };
|
||||||
int l1_start_index;
|
int l1_start_index;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
|
l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
|
||||||
for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
|
for (i = 0; i < L1_ENTRIES_PER_SECTOR && l1_start_index + i < s->l1_size;
|
||||||
|
i++)
|
||||||
|
{
|
||||||
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
|
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1200,7 +1202,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
|||||||
|
|
||||||
again:
|
again:
|
||||||
start = offset;
|
start = offset;
|
||||||
remaining = *num << BDRV_SECTOR_BITS;
|
remaining = (uint64_t)*num << BDRV_SECTOR_BITS;
|
||||||
cluster_offset = 0;
|
cluster_offset = 0;
|
||||||
*host_offset = 0;
|
*host_offset = 0;
|
||||||
cur_bytes = 0;
|
cur_bytes = 0;
|
||||||
|
@@ -114,7 +114,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
|||||||
#ifdef DEBUG_EXT
|
#ifdef DEBUG_EXT
|
||||||
printf("ext.magic = 0x%x\n", ext.magic);
|
printf("ext.magic = 0x%x\n", ext.magic);
|
||||||
#endif
|
#endif
|
||||||
if (ext.len > end_offset - offset) {
|
if (offset > end_offset || ext.len > end_offset - offset) {
|
||||||
error_setg(errp, "Header extension too large");
|
error_setg(errp, "Header extension too large");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -1275,10 +1275,23 @@ static void qcow2_close(BlockDriverState *bs)
|
|||||||
s->l1_table = NULL;
|
s->l1_table = NULL;
|
||||||
|
|
||||||
if (!(bs->open_flags & BDRV_O_INCOMING)) {
|
if (!(bs->open_flags & BDRV_O_INCOMING)) {
|
||||||
qcow2_cache_flush(bs, s->l2_table_cache);
|
int ret1, ret2;
|
||||||
qcow2_cache_flush(bs, s->refcount_block_cache);
|
|
||||||
|
|
||||||
qcow2_mark_clean(bs);
|
ret1 = qcow2_cache_flush(bs, s->l2_table_cache);
|
||||||
|
ret2 = qcow2_cache_flush(bs, s->refcount_block_cache);
|
||||||
|
|
||||||
|
if (ret1) {
|
||||||
|
error_report("Failed to flush the L2 table cache: %s",
|
||||||
|
strerror(-ret1));
|
||||||
|
}
|
||||||
|
if (ret2) {
|
||||||
|
error_report("Failed to flush the refcount block cache: %s",
|
||||||
|
strerror(-ret2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret1 && !ret2) {
|
||||||
|
qcow2_mark_clean(bs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||||
@@ -1712,10 +1725,9 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
* refcount of the cluster that is occupied by the header and the refcount
|
* refcount of the cluster that is occupied by the header and the refcount
|
||||||
* table)
|
* table)
|
||||||
*/
|
*/
|
||||||
BlockDriver* drv = bdrv_find_format("qcow2");
|
|
||||||
assert(drv != NULL);
|
|
||||||
ret = bdrv_open(&bs, filename, NULL, NULL,
|
ret = bdrv_open(&bs, filename, NULL, NULL,
|
||||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, &local_err);
|
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
|
||||||
|
&bdrv_qcow2, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1767,7 +1779,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
/* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
|
/* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
|
||||||
ret = bdrv_open(&bs, filename, NULL, NULL,
|
ret = bdrv_open(&bs, filename, NULL, NULL,
|
||||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
|
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
|
||||||
drv, &local_err);
|
&bdrv_qcow2, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1948,8 +1960,7 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||||||
sector based I/Os */
|
sector based I/Os */
|
||||||
cluster_offset = bdrv_getlength(bs->file);
|
cluster_offset = bdrv_getlength(bs->file);
|
||||||
cluster_offset = (cluster_offset + 511) & ~511;
|
cluster_offset = (cluster_offset + 511) & ~511;
|
||||||
bdrv_truncate(bs->file, cluster_offset);
|
return bdrv_truncate(bs->file, cluster_offset);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nb_sectors != s->cluster_sectors) {
|
if (nb_sectors != s->cluster_sectors) {
|
||||||
@@ -2404,7 +2415,7 @@ static QemuOptsList qcow2_create_opts = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static BlockDriver bdrv_qcow2 = {
|
BlockDriver bdrv_qcow2 = {
|
||||||
.format_name = "qcow2",
|
.format_name = "qcow2",
|
||||||
.instance_size = sizeof(BDRVQcowState),
|
.instance_size = sizeof(BDRVQcowState),
|
||||||
.bdrv_probe = qcow2_probe,
|
.bdrv_probe = qcow2_probe,
|
||||||
|
@@ -447,6 +447,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
s->has_write_zeroes = true;
|
s->has_write_zeroes = true;
|
||||||
|
|
||||||
if (fstat(s->fd, &st) < 0) {
|
if (fstat(s->fd, &st) < 0) {
|
||||||
|
ret = -errno;
|
||||||
error_setg_errno(errp, errno, "Could not stat file");
|
error_setg_errno(errp, errno, "Could not stat file");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -747,6 +748,15 @@ static ssize_t handle_aiocb_rw_linear(RawPosixAIOData *aiocb, char *buf)
|
|||||||
}
|
}
|
||||||
if (len == -1 && errno == EINTR) {
|
if (len == -1 && errno == EINTR) {
|
||||||
continue;
|
continue;
|
||||||
|
} else if (len == -1 && errno == EINVAL &&
|
||||||
|
(aiocb->bs->open_flags & BDRV_O_NOCACHE) &&
|
||||||
|
!(aiocb->aio_type & QEMU_AIO_WRITE) &&
|
||||||
|
offset > 0) {
|
||||||
|
/* O_DIRECT pread() may fail with EINVAL when offset is unaligned
|
||||||
|
* after a short read. Assume that O_DIRECT short reads only occur
|
||||||
|
* at EOF. Therefore this is a short read, not an I/O error.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
} else if (len == -1) {
|
} else if (len == -1) {
|
||||||
offset = -errno;
|
offset = -errno;
|
||||||
break;
|
break;
|
||||||
@@ -1576,7 +1586,7 @@ static QemuOptsList raw_create_opts = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static BlockDriver bdrv_file = {
|
BlockDriver bdrv_file = {
|
||||||
.format_name = "file",
|
.format_name = "file",
|
||||||
.protocol_name = "file",
|
.protocol_name = "file",
|
||||||
.instance_size = sizeof(BDRVRawState),
|
.instance_size = sizeof(BDRVRawState),
|
||||||
|
@@ -540,7 +540,7 @@ static QemuOptsList raw_create_opts = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static BlockDriver bdrv_file = {
|
BlockDriver bdrv_file = {
|
||||||
.format_name = "file",
|
.format_name = "file",
|
||||||
.protocol_name = "file",
|
.protocol_name = "file",
|
||||||
.instance_size = sizeof(BDRVRawState),
|
.instance_size = sizeof(BDRVRawState),
|
||||||
|
@@ -173,7 +173,7 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriver bdrv_raw = {
|
BlockDriver bdrv_raw = {
|
||||||
.format_name = "raw",
|
.format_name = "raw",
|
||||||
.bdrv_probe = &raw_probe,
|
.bdrv_probe = &raw_probe,
|
||||||
.bdrv_reopen_prepare = &raw_reopen_prepare,
|
.bdrv_reopen_prepare = &raw_reopen_prepare,
|
||||||
|
@@ -236,6 +236,10 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
|
|||||||
error_setg(errp, "snapshot_id and name are both NULL");
|
error_setg(errp, "snapshot_id and name are both NULL");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* drain all pending i/o before deleting snapshot */
|
||||||
|
bdrv_drain_all();
|
||||||
|
|
||||||
if (drv->bdrv_snapshot_delete) {
|
if (drv->bdrv_snapshot_delete) {
|
||||||
return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
|
return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
|
||||||
}
|
}
|
||||||
|
@@ -2926,6 +2926,12 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bdrv_qcow = bdrv_find_format("qcow");
|
bdrv_qcow = bdrv_find_format("qcow");
|
||||||
|
if (!bdrv_qcow) {
|
||||||
|
error_setg(errp, "Failed to locate qcow driver");
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
|
||||||
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512);
|
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512);
|
||||||
qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:");
|
qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:");
|
||||||
|
1
configure
vendored
1
configure
vendored
@@ -1723,6 +1723,7 @@ fi
|
|||||||
|
|
||||||
cat > $TMPC <<EOF
|
cat > $TMPC <<EOF
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
int main(void) { return sizeof(struct mmsghdr); }
|
int main(void) { return sizeof(struct mmsghdr); }
|
||||||
EOF
|
EOF
|
||||||
if compile_prog "" "" ; then
|
if compile_prog "" "" ; then
|
||||||
|
9
cpus.c
9
cpus.c
@@ -523,6 +523,15 @@ void cpu_synchronize_all_post_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpu_clean_all_dirty(void)
|
||||||
|
{
|
||||||
|
CPUState *cpu;
|
||||||
|
|
||||||
|
CPU_FOREACH(cpu) {
|
||||||
|
cpu_clean_state(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int do_vm_stop(RunState state)
|
static int do_vm_stop(RunState state)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
42
exec.c
42
exec.c
@@ -430,15 +430,50 @@ static int cpu_common_post_load(void *opaque, int version_id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cpu_common_pre_load(void *opaque)
|
||||||
|
{
|
||||||
|
CPUState *cpu = opaque;
|
||||||
|
|
||||||
|
cpu->exception_index = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cpu_common_exception_index_needed(void *opaque)
|
||||||
|
{
|
||||||
|
CPUState *cpu = opaque;
|
||||||
|
|
||||||
|
return cpu->exception_index != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_cpu_common_exception_index = {
|
||||||
|
.name = "cpu_common/exception_index",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_INT32(exception_index, CPUState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_cpu_common = {
|
const VMStateDescription vmstate_cpu_common = {
|
||||||
.name = "cpu_common",
|
.name = "cpu_common",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
|
.pre_load = cpu_common_pre_load,
|
||||||
.post_load = cpu_common_post_load,
|
.post_load = cpu_common_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(halted, CPUState),
|
VMSTATE_UINT32(halted, CPUState),
|
||||||
VMSTATE_UINT32(interrupt_request, CPUState),
|
VMSTATE_UINT32(interrupt_request, CPUState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
.subsections = (VMStateSubsection[]) {
|
||||||
|
{
|
||||||
|
.vmsd = &vmstate_cpu_common_exception_index,
|
||||||
|
.needed = cpu_common_exception_index_needed,
|
||||||
|
} , {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1095,6 +1130,7 @@ static void *file_ram_alloc(RAMBlock *block,
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
if (mem_prealloc) {
|
if (mem_prealloc) {
|
||||||
|
error_report("%s\n", error_get_pretty(*errp));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1973,10 +2009,8 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
|
|||||||
static void invalidate_and_set_dirty(hwaddr addr,
|
static void invalidate_and_set_dirty(hwaddr addr,
|
||||||
hwaddr length)
|
hwaddr length)
|
||||||
{
|
{
|
||||||
if (cpu_physical_memory_is_clean(addr)) {
|
if (cpu_physical_memory_range_includes_clean(addr, length)) {
|
||||||
/* invalidate code */
|
tb_invalidate_phys_range(addr, addr + length, 0);
|
||||||
tb_invalidate_phys_page_range(addr, addr + length, 0);
|
|
||||||
/* set dirty bit */
|
|
||||||
cpu_physical_memory_set_dirty_range_nocode(addr, length);
|
cpu_physical_memory_set_dirty_range_nocode(addr, length);
|
||||||
}
|
}
|
||||||
xen_modified_memory(addr, length);
|
xen_modified_memory(addr, length);
|
||||||
|
@@ -1707,7 +1707,7 @@ int gdbserver_start(const char *device)
|
|||||||
qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
|
qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
|
||||||
|
|
||||||
/* Initialize a monitor terminal for gdb */
|
/* Initialize a monitor terminal for gdb */
|
||||||
mon_chr = g_malloc0(sizeof(*mon_chr));
|
mon_chr = qemu_chr_alloc();
|
||||||
mon_chr->chr_write = gdb_monitor_write;
|
mon_chr->chr_write = gdb_monitor_write;
|
||||||
monitor_init(mon_chr, 0);
|
monitor_init(mon_chr, 0);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -231,7 +231,7 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
|
|||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
int bsel = s->hotplug_select;
|
int bsel = s->hotplug_select;
|
||||||
|
|
||||||
if (bsel < 0 || bsel > ACPI_PCIHP_MAX_HOTPLUG_BUS) {
|
if (bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -508,7 +508,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
entry = elf_entry;
|
entry = elf_entry;
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
|
kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
|
||||||
&is_linux);
|
&is_linux, NULL, NULL);
|
||||||
}
|
}
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
entry = info->loader_start + kernel_load_offset;
|
entry = info->loader_start + kernel_load_offset;
|
||||||
|
@@ -194,20 +194,41 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi)
|
|||||||
|
|
||||||
/* No PSCI for TCG yet */
|
/* No PSCI for TCG yet */
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
|
uint32_t cpu_suspend_fn;
|
||||||
|
uint32_t cpu_off_fn;
|
||||||
|
uint32_t cpu_on_fn;
|
||||||
|
uint32_t migrate_fn;
|
||||||
|
|
||||||
qemu_fdt_add_subnode(fdt, "/psci");
|
qemu_fdt_add_subnode(fdt, "/psci");
|
||||||
if (armcpu->psci_version == 2) {
|
if (armcpu->psci_version == 2) {
|
||||||
const char comp[] = "arm,psci-0.2\0arm,psci";
|
const char comp[] = "arm,psci-0.2\0arm,psci";
|
||||||
qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
|
qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
|
||||||
|
|
||||||
|
cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF;
|
||||||
|
if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) {
|
||||||
|
cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND;
|
||||||
|
cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON;
|
||||||
|
migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE;
|
||||||
|
} else {
|
||||||
|
cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND;
|
||||||
|
cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON;
|
||||||
|
migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci");
|
qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci");
|
||||||
|
|
||||||
|
cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND;
|
||||||
|
cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF;
|
||||||
|
cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON;
|
||||||
|
migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
|
qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
|
||||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend",
|
|
||||||
PSCI_FN_CPU_SUSPEND);
|
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
|
||||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", PSCI_FN_CPU_OFF);
|
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
|
||||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", PSCI_FN_CPU_ON);
|
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn);
|
||||||
qemu_fdt_setprop_cell(fdt, "/psci", "migrate", PSCI_FN_MIGRATE);
|
qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +371,7 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
|||||||
2, base, 2, size);
|
2, base, 2, size);
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
|
||||||
GIC_FDT_IRQ_TYPE_SPI, irq,
|
GIC_FDT_IRQ_TYPE_SPI, irq,
|
||||||
GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
|
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks",
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks",
|
||||||
vbi->clock_phandle, vbi->clock_phandle);
|
vbi->clock_phandle, vbi->clock_phandle);
|
||||||
qemu_fdt_setprop(vbi->fdt, nodename, "clock-names",
|
qemu_fdt_setprop(vbi->fdt, nodename, "clock-names",
|
||||||
@@ -375,7 +396,7 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
|
|||||||
2, base, 2, size);
|
2, base, 2, size);
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
|
||||||
GIC_FDT_IRQ_TYPE_SPI, irq,
|
GIC_FDT_IRQ_TYPE_SPI, irq,
|
||||||
GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
|
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
|
qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
|
||||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
|
qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
|
||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
|
@@ -469,8 +469,9 @@ static void virtio_blk_dma_restart_bh(void *opaque)
|
|||||||
s->rq = NULL;
|
s->rq = NULL;
|
||||||
|
|
||||||
while (req) {
|
while (req) {
|
||||||
|
VirtIOBlockReq *next = req->next;
|
||||||
virtio_blk_handle_request(req, &mrb);
|
virtio_blk_handle_request(req, &mrb);
|
||||||
req = req->next;
|
req = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtio_submit_multiwrite(s->bs, &mrb);
|
virtio_submit_multiwrite(s->bs, &mrb);
|
||||||
|
@@ -456,7 +456,9 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
|
|||||||
|
|
||||||
/* Load a U-Boot image. */
|
/* Load a U-Boot image. */
|
||||||
static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
|
static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
|
||||||
int *is_linux, uint8_t image_type)
|
int *is_linux, uint8_t image_type,
|
||||||
|
uint64_t (*translate_fn)(void *, uint64_t),
|
||||||
|
void *translate_opaque)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
int size;
|
int size;
|
||||||
@@ -490,6 +492,9 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
|
|||||||
switch (hdr->ih_type) {
|
switch (hdr->ih_type) {
|
||||||
case IH_TYPE_KERNEL:
|
case IH_TYPE_KERNEL:
|
||||||
address = hdr->ih_load;
|
address = hdr->ih_load;
|
||||||
|
if (translate_fn) {
|
||||||
|
address = translate_fn(translate_opaque, address);
|
||||||
|
}
|
||||||
if (loadaddr) {
|
if (loadaddr) {
|
||||||
*loadaddr = hdr->ih_load;
|
*loadaddr = hdr->ih_load;
|
||||||
}
|
}
|
||||||
@@ -566,15 +571,19 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
|
int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
|
||||||
int *is_linux)
|
int *is_linux,
|
||||||
|
uint64_t (*translate_fn)(void *, uint64_t),
|
||||||
|
void *translate_opaque)
|
||||||
{
|
{
|
||||||
return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL);
|
return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL,
|
||||||
|
translate_fn, translate_opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load a ramdisk. */
|
/* Load a ramdisk. */
|
||||||
int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
|
int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||||
{
|
{
|
||||||
return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK);
|
return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK,
|
||||||
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -24,6 +24,7 @@ static void machine_set_accel(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->accel);
|
||||||
ms->accel = g_strdup(value);
|
ms->accel = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ static void machine_set_kernel(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->kernel_filename);
|
||||||
ms->kernel_filename = g_strdup(value);
|
ms->kernel_filename = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +95,7 @@ static void machine_set_initrd(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->initrd_filename);
|
||||||
ms->initrd_filename = g_strdup(value);
|
ms->initrd_filename = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +110,7 @@ static void machine_set_append(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->kernel_cmdline);
|
||||||
ms->kernel_cmdline = g_strdup(value);
|
ms->kernel_cmdline = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +125,7 @@ static void machine_set_dtb(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->dtb);
|
||||||
ms->dtb = g_strdup(value);
|
ms->dtb = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +140,7 @@ static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->dumpdtb);
|
||||||
ms->dumpdtb = g_strdup(value);
|
ms->dumpdtb = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +182,7 @@ static void machine_set_dt_compatible(Object *obj, const char *value, Error **er
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->dt_compatible);
|
||||||
ms->dt_compatible = g_strdup(value);
|
ms->dt_compatible = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,6 +239,7 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->firmware);
|
||||||
ms->firmware = g_strdup(value);
|
ms->firmware = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -834,12 +834,14 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
|
|||||||
dc->realize(dev, &local_err);
|
dc->realize(dev, &local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->parent_bus && dev->parent_bus->hotplug_handler &&
|
if (local_err != NULL) {
|
||||||
local_err == NULL) {
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->parent_bus && dev->parent_bus->hotplug_handler) {
|
||||||
hotplug_handler_plug(dev->parent_bus->hotplug_handler,
|
hotplug_handler_plug(dev->parent_bus->hotplug_handler,
|
||||||
dev, &local_err);
|
dev, &local_err);
|
||||||
} else if (local_err == NULL &&
|
} else if (object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
|
||||||
object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
|
|
||||||
HotplugHandler *hotplug_ctrl;
|
HotplugHandler *hotplug_ctrl;
|
||||||
MachineState *machine = MACHINE(qdev_get_machine());
|
MachineState *machine = MACHINE(qdev_get_machine());
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||||
@@ -852,47 +854,69 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qdev_get_vmsd(dev) && local_err == NULL) {
|
if (local_err != NULL) {
|
||||||
|
goto post_realize_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qdev_get_vmsd(dev)) {
|
||||||
vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
|
vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
|
||||||
dev->instance_id_alias,
|
dev->instance_id_alias,
|
||||||
dev->alias_required_for_version);
|
dev->alias_required_for_version);
|
||||||
}
|
}
|
||||||
if (local_err == NULL) {
|
|
||||||
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
|
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
|
||||||
object_property_set_bool(OBJECT(bus), true, "realized",
|
object_property_set_bool(OBJECT(bus), true, "realized",
|
||||||
&local_err);
|
&local_err);
|
||||||
if (local_err != NULL) {
|
if (local_err != NULL) {
|
||||||
break;
|
goto child_realize_fail;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dev->hotplugged && local_err == NULL) {
|
if (dev->hotplugged) {
|
||||||
device_reset(dev);
|
device_reset(dev);
|
||||||
}
|
}
|
||||||
dev->pending_deleted_event = false;
|
dev->pending_deleted_event = false;
|
||||||
} else if (!value && dev->realized) {
|
} else if (!value && dev->realized) {
|
||||||
|
Error **local_errp = NULL;
|
||||||
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
|
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
|
||||||
|
local_errp = local_err ? NULL : &local_err;
|
||||||
object_property_set_bool(OBJECT(bus), false, "realized",
|
object_property_set_bool(OBJECT(bus), false, "realized",
|
||||||
&local_err);
|
local_errp);
|
||||||
if (local_err != NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (qdev_get_vmsd(dev) && local_err == NULL) {
|
if (qdev_get_vmsd(dev)) {
|
||||||
vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
|
vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
|
||||||
}
|
}
|
||||||
if (dc->unrealize && local_err == NULL) {
|
if (dc->unrealize) {
|
||||||
dc->unrealize(dev, &local_err);
|
local_errp = local_err ? NULL : &local_err;
|
||||||
|
dc->unrealize(dev, local_errp);
|
||||||
}
|
}
|
||||||
dev->pending_deleted_event = true;
|
dev->pending_deleted_event = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local_err != NULL) {
|
if (local_err != NULL) {
|
||||||
error_propagate(errp, local_err);
|
goto fail;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->realized = value;
|
dev->realized = value;
|
||||||
|
return;
|
||||||
|
|
||||||
|
child_realize_fail:
|
||||||
|
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
|
||||||
|
object_property_set_bool(OBJECT(bus), false, "realized",
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qdev_get_vmsd(dev)) {
|
||||||
|
vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
post_realize_fail:
|
||||||
|
if (dc->unrealize) {
|
||||||
|
dc->unrealize(dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool device_get_hotpluggable(Object *obj, Error **errp)
|
static bool device_get_hotpluggable(Object *obj, Error **errp)
|
||||||
|
@@ -138,7 +138,9 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
|||||||
if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
|
if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (qxl->dirty[i].left > qxl->dirty[i].right ||
|
if (qxl->dirty[i].left < 0 ||
|
||||||
|
qxl->dirty[i].top < 0 ||
|
||||||
|
qxl->dirty[i].left > qxl->dirty[i].right ||
|
||||||
qxl->dirty[i].top > qxl->dirty[i].bottom ||
|
qxl->dirty[i].top > qxl->dirty[i].bottom ||
|
||||||
qxl->dirty[i].right > qxl->guest_primary.surface.width ||
|
qxl->dirty[i].right > qxl->guest_primary.surface.width ||
|
||||||
qxl->dirty[i].bottom > qxl->guest_primary.surface.height) {
|
qxl->dirty[i].bottom > qxl->guest_primary.surface.height) {
|
||||||
|
@@ -2063,6 +2063,7 @@ static int qxl_init_primary(PCIDevice *dev)
|
|||||||
|
|
||||||
qxl->id = 0;
|
qxl->id = 0;
|
||||||
qxl_init_ramsize(qxl);
|
qxl_init_ramsize(qxl);
|
||||||
|
vga->vbe_size = qxl->vgamem_size;
|
||||||
vga->vram_size_mb = qxl->vga.vram_size >> 20;
|
vga->vram_size_mb = qxl->vga.vram_size >> 20;
|
||||||
vga_common_init(vga, OBJECT(dev), true);
|
vga_common_init(vga, OBJECT(dev), true);
|
||||||
vga_init(vga, OBJECT(dev),
|
vga_init(vga, OBJECT(dev),
|
||||||
|
159
hw/display/vga.c
159
hw/display/vga.c
@@ -580,6 +580,93 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity check vbe register writes.
|
||||||
|
*
|
||||||
|
* As we don't have a way to signal errors to the guest in the bochs
|
||||||
|
* dispi interface we'll go adjust the registers to the closest valid
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
static void vbe_fixup_regs(VGACommonState *s)
|
||||||
|
{
|
||||||
|
uint16_t *r = s->vbe_regs;
|
||||||
|
uint32_t bits, linelength, maxy, offset;
|
||||||
|
|
||||||
|
if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
|
||||||
|
/* vbe is turned off -- nothing to do */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check depth */
|
||||||
|
switch (r[VBE_DISPI_INDEX_BPP]) {
|
||||||
|
case 4:
|
||||||
|
case 8:
|
||||||
|
case 16:
|
||||||
|
case 24:
|
||||||
|
case 32:
|
||||||
|
bits = r[VBE_DISPI_INDEX_BPP];
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
bits = 16;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bits = r[VBE_DISPI_INDEX_BPP] = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check width */
|
||||||
|
r[VBE_DISPI_INDEX_XRES] &= ~7u;
|
||||||
|
if (r[VBE_DISPI_INDEX_XRES] == 0) {
|
||||||
|
r[VBE_DISPI_INDEX_XRES] = 8;
|
||||||
|
}
|
||||||
|
if (r[VBE_DISPI_INDEX_XRES] > VBE_DISPI_MAX_XRES) {
|
||||||
|
r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES;
|
||||||
|
}
|
||||||
|
r[VBE_DISPI_INDEX_VIRT_WIDTH] &= ~7u;
|
||||||
|
if (r[VBE_DISPI_INDEX_VIRT_WIDTH] > VBE_DISPI_MAX_XRES) {
|
||||||
|
r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES;
|
||||||
|
}
|
||||||
|
if (r[VBE_DISPI_INDEX_VIRT_WIDTH] < r[VBE_DISPI_INDEX_XRES]) {
|
||||||
|
r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check height */
|
||||||
|
linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8;
|
||||||
|
maxy = s->vbe_size / linelength;
|
||||||
|
if (r[VBE_DISPI_INDEX_YRES] == 0) {
|
||||||
|
r[VBE_DISPI_INDEX_YRES] = 1;
|
||||||
|
}
|
||||||
|
if (r[VBE_DISPI_INDEX_YRES] > VBE_DISPI_MAX_YRES) {
|
||||||
|
r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES;
|
||||||
|
}
|
||||||
|
if (r[VBE_DISPI_INDEX_YRES] > maxy) {
|
||||||
|
r[VBE_DISPI_INDEX_YRES] = maxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check offset */
|
||||||
|
if (r[VBE_DISPI_INDEX_X_OFFSET] > VBE_DISPI_MAX_XRES) {
|
||||||
|
r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES;
|
||||||
|
}
|
||||||
|
if (r[VBE_DISPI_INDEX_Y_OFFSET] > VBE_DISPI_MAX_YRES) {
|
||||||
|
r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES;
|
||||||
|
}
|
||||||
|
offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
|
||||||
|
offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength;
|
||||||
|
if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
|
||||||
|
r[VBE_DISPI_INDEX_Y_OFFSET] = 0;
|
||||||
|
offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
|
||||||
|
if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
|
||||||
|
r[VBE_DISPI_INDEX_X_OFFSET] = 0;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update vga state */
|
||||||
|
r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy;
|
||||||
|
s->vbe_line_offset = linelength;
|
||||||
|
s->vbe_start_addr = offset / 4;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
|
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
|
||||||
{
|
{
|
||||||
VGACommonState *s = opaque;
|
VGACommonState *s = opaque;
|
||||||
@@ -614,7 +701,7 @@ uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
|
|||||||
val = s->vbe_regs[s->vbe_index];
|
val = s->vbe_regs[s->vbe_index];
|
||||||
}
|
}
|
||||||
} else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
|
} else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
|
||||||
val = s->vram_size / (64 * 1024);
|
val = s->vbe_size / (64 * 1024);
|
||||||
} else {
|
} else {
|
||||||
val = 0;
|
val = 0;
|
||||||
}
|
}
|
||||||
@@ -649,22 +736,13 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VBE_DISPI_INDEX_XRES:
|
case VBE_DISPI_INDEX_XRES:
|
||||||
if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
|
|
||||||
s->vbe_regs[s->vbe_index] = val;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VBE_DISPI_INDEX_YRES:
|
case VBE_DISPI_INDEX_YRES:
|
||||||
if (val <= VBE_DISPI_MAX_YRES) {
|
|
||||||
s->vbe_regs[s->vbe_index] = val;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VBE_DISPI_INDEX_BPP:
|
case VBE_DISPI_INDEX_BPP:
|
||||||
if (val == 0)
|
case VBE_DISPI_INDEX_VIRT_WIDTH:
|
||||||
val = 8;
|
case VBE_DISPI_INDEX_X_OFFSET:
|
||||||
if (val == 4 || val == 8 || val == 15 ||
|
case VBE_DISPI_INDEX_Y_OFFSET:
|
||||||
val == 16 || val == 24 || val == 32) {
|
s->vbe_regs[s->vbe_index] = val;
|
||||||
s->vbe_regs[s->vbe_index] = val;
|
vbe_fixup_regs(s);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case VBE_DISPI_INDEX_BANK:
|
case VBE_DISPI_INDEX_BANK:
|
||||||
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
|
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
|
||||||
@@ -681,19 +759,11 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
|
!(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
|
||||||
int h, shift_control;
|
int h, shift_control;
|
||||||
|
|
||||||
s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
|
s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
|
||||||
s->vbe_regs[VBE_DISPI_INDEX_XRES];
|
|
||||||
s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
|
|
||||||
s->vbe_regs[VBE_DISPI_INDEX_YRES];
|
|
||||||
s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
|
s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
|
||||||
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
|
s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
|
||||||
|
s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
|
||||||
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
|
vbe_fixup_regs(s);
|
||||||
s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
|
|
||||||
else
|
|
||||||
s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
|
|
||||||
((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
|
|
||||||
s->vbe_start_addr = 0;
|
|
||||||
|
|
||||||
/* clear the screen (should be done in BIOS) */
|
/* clear the screen (should be done in BIOS) */
|
||||||
if (!(val & VBE_DISPI_NOCLEARMEM)) {
|
if (!(val & VBE_DISPI_NOCLEARMEM)) {
|
||||||
@@ -742,40 +812,6 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
s->vbe_regs[s->vbe_index] = val;
|
s->vbe_regs[s->vbe_index] = val;
|
||||||
vga_update_memory_access(s);
|
vga_update_memory_access(s);
|
||||||
break;
|
break;
|
||||||
case VBE_DISPI_INDEX_VIRT_WIDTH:
|
|
||||||
{
|
|
||||||
int w, h, line_offset;
|
|
||||||
|
|
||||||
if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
|
|
||||||
return;
|
|
||||||
w = val;
|
|
||||||
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
|
|
||||||
line_offset = w >> 1;
|
|
||||||
else
|
|
||||||
line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
|
|
||||||
h = s->vram_size / line_offset;
|
|
||||||
/* XXX: support weird bochs semantics ? */
|
|
||||||
if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
|
|
||||||
return;
|
|
||||||
s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
|
|
||||||
s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
|
|
||||||
s->vbe_line_offset = line_offset;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VBE_DISPI_INDEX_X_OFFSET:
|
|
||||||
case VBE_DISPI_INDEX_Y_OFFSET:
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
s->vbe_regs[s->vbe_index] = val;
|
|
||||||
s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
|
|
||||||
x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
|
|
||||||
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
|
|
||||||
s->vbe_start_addr += x >> 1;
|
|
||||||
else
|
|
||||||
s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
|
|
||||||
s->vbe_start_addr >>= 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2289,6 +2325,9 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
|
|||||||
s->vram_size <<= 1;
|
s->vram_size <<= 1;
|
||||||
}
|
}
|
||||||
s->vram_size_mb = s->vram_size >> 20;
|
s->vram_size_mb = s->vram_size >> 20;
|
||||||
|
if (!s->vbe_size) {
|
||||||
|
s->vbe_size = s->vram_size;
|
||||||
|
}
|
||||||
|
|
||||||
s->is_vbe_vmstate = 1;
|
s->is_vbe_vmstate = 1;
|
||||||
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size);
|
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size);
|
||||||
|
@@ -93,6 +93,7 @@ typedef struct VGACommonState {
|
|||||||
MemoryRegion vram_vbe;
|
MemoryRegion vram_vbe;
|
||||||
uint32_t vram_size;
|
uint32_t vram_size;
|
||||||
uint32_t vram_size_mb; /* property */
|
uint32_t vram_size_mb; /* property */
|
||||||
|
uint32_t vbe_size;
|
||||||
uint32_t latch;
|
uint32_t latch;
|
||||||
MemoryRegion *chain4_alias;
|
MemoryRegion *chain4_alias;
|
||||||
uint8_t sr_index;
|
uint8_t sr_index;
|
||||||
|
@@ -292,8 +292,59 @@ enum {
|
|||||||
SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
|
SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline bool vmsvga_verify_rect(DisplaySurface *surface,
|
||||||
|
const char *name,
|
||||||
|
int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
if (x < 0) {
|
||||||
|
fprintf(stderr, "%s: x was < 0 (%d)\n", name, x);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (x > SVGA_MAX_WIDTH) {
|
||||||
|
fprintf(stderr, "%s: x was > %d (%d)\n", name, SVGA_MAX_WIDTH, x);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (w < 0) {
|
||||||
|
fprintf(stderr, "%s: w was < 0 (%d)\n", name, w);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (w > SVGA_MAX_WIDTH) {
|
||||||
|
fprintf(stderr, "%s: w was > %d (%d)\n", name, SVGA_MAX_WIDTH, w);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (x + w > surface_width(surface)) {
|
||||||
|
fprintf(stderr, "%s: width was > %d (x: %d, w: %d)\n",
|
||||||
|
name, surface_width(surface), x, w);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0) {
|
||||||
|
fprintf(stderr, "%s: y was < 0 (%d)\n", name, y);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (y > SVGA_MAX_HEIGHT) {
|
||||||
|
fprintf(stderr, "%s: y was > %d (%d)\n", name, SVGA_MAX_HEIGHT, y);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (h < 0) {
|
||||||
|
fprintf(stderr, "%s: h was < 0 (%d)\n", name, h);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (h > SVGA_MAX_HEIGHT) {
|
||||||
|
fprintf(stderr, "%s: h was > %d (%d)\n", name, SVGA_MAX_HEIGHT, h);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (y + h > surface_height(surface)) {
|
||||||
|
fprintf(stderr, "%s: update height > %d (y: %d, h: %d)\n",
|
||||||
|
name, surface_height(surface), y, h);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
|
static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
|
||||||
int x, int y, int w, int h)
|
int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
DisplaySurface *surface = qemu_console_surface(s->vga.con);
|
DisplaySurface *surface = qemu_console_surface(s->vga.con);
|
||||||
int line;
|
int line;
|
||||||
@@ -303,36 +354,12 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
|
|||||||
uint8_t *src;
|
uint8_t *src;
|
||||||
uint8_t *dst;
|
uint8_t *dst;
|
||||||
|
|
||||||
if (x < 0) {
|
if (!vmsvga_verify_rect(surface, __func__, x, y, w, h)) {
|
||||||
fprintf(stderr, "%s: update x was < 0 (%d)\n", __func__, x);
|
/* go for a fullscreen update as fallback */
|
||||||
w += x;
|
|
||||||
x = 0;
|
x = 0;
|
||||||
}
|
|
||||||
if (w < 0) {
|
|
||||||
fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w);
|
|
||||||
w = 0;
|
|
||||||
}
|
|
||||||
if (x + w > surface_width(surface)) {
|
|
||||||
fprintf(stderr, "%s: update width too large x: %d, w: %d\n",
|
|
||||||
__func__, x, w);
|
|
||||||
x = MIN(x, surface_width(surface));
|
|
||||||
w = surface_width(surface) - x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y < 0) {
|
|
||||||
fprintf(stderr, "%s: update y was < 0 (%d)\n", __func__, y);
|
|
||||||
h += y;
|
|
||||||
y = 0;
|
y = 0;
|
||||||
}
|
w = surface_width(surface);
|
||||||
if (h < 0) {
|
h = surface_height(surface);
|
||||||
fprintf(stderr, "%s: update h was < 0 (%d)\n", __func__, h);
|
|
||||||
h = 0;
|
|
||||||
}
|
|
||||||
if (y + h > surface_height(surface)) {
|
|
||||||
fprintf(stderr, "%s: update height too large y: %d, h: %d\n",
|
|
||||||
__func__, y, h);
|
|
||||||
y = MIN(y, surface_height(surface));
|
|
||||||
h = surface_height(surface) - y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bypl = surface_stride(surface);
|
bypl = surface_stride(surface);
|
||||||
@@ -377,7 +404,7 @@ static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HW_RECT_ACCEL
|
#ifdef HW_RECT_ACCEL
|
||||||
static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
|
static inline int vmsvga_copy_rect(struct vmsvga_state_s *s,
|
||||||
int x0, int y0, int x1, int y1, int w, int h)
|
int x0, int y0, int x1, int y1, int w, int h)
|
||||||
{
|
{
|
||||||
DisplaySurface *surface = qemu_console_surface(s->vga.con);
|
DisplaySurface *surface = qemu_console_surface(s->vga.con);
|
||||||
@@ -388,6 +415,13 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
|
|||||||
int line = h;
|
int line = h;
|
||||||
uint8_t *ptr[2];
|
uint8_t *ptr[2];
|
||||||
|
|
||||||
|
if (!vmsvga_verify_rect(surface, "vmsvga_copy_rect/src", x0, y0, w, h)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!vmsvga_verify_rect(surface, "vmsvga_copy_rect/dst", x1, y1, w, h)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (y1 > y0) {
|
if (y1 > y0) {
|
||||||
ptr[0] = vram + bypp * x0 + bypl * (y0 + h - 1);
|
ptr[0] = vram + bypp * x0 + bypl * (y0 + h - 1);
|
||||||
ptr[1] = vram + bypp * x1 + bypl * (y1 + h - 1);
|
ptr[1] = vram + bypp * x1 + bypl * (y1 + h - 1);
|
||||||
@@ -403,11 +437,12 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
vmsvga_update_rect_delayed(s, x1, y1, w, h);
|
vmsvga_update_rect_delayed(s, x1, y1, w, h);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HW_FILL_ACCEL
|
#ifdef HW_FILL_ACCEL
|
||||||
static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
|
static inline int vmsvga_fill_rect(struct vmsvga_state_s *s,
|
||||||
uint32_t c, int x, int y, int w, int h)
|
uint32_t c, int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
DisplaySurface *surface = qemu_console_surface(s->vga.con);
|
DisplaySurface *surface = qemu_console_surface(s->vga.con);
|
||||||
@@ -420,6 +455,10 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
|
|||||||
uint8_t *src;
|
uint8_t *src;
|
||||||
uint8_t col[4];
|
uint8_t col[4];
|
||||||
|
|
||||||
|
if (!vmsvga_verify_rect(surface, __func__, x, y, w, h)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
col[0] = c;
|
col[0] = c;
|
||||||
col[1] = c >> 8;
|
col[1] = c >> 8;
|
||||||
col[2] = c >> 16;
|
col[2] = c >> 16;
|
||||||
@@ -444,6 +483,7 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
vmsvga_update_rect_delayed(s, x, y, w, h);
|
vmsvga_update_rect_delayed(s, x, y, w, h);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -576,12 +616,12 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
|
|||||||
width = vmsvga_fifo_read(s);
|
width = vmsvga_fifo_read(s);
|
||||||
height = vmsvga_fifo_read(s);
|
height = vmsvga_fifo_read(s);
|
||||||
#ifdef HW_FILL_ACCEL
|
#ifdef HW_FILL_ACCEL
|
||||||
vmsvga_fill_rect(s, colour, x, y, width, height);
|
if (vmsvga_fill_rect(s, colour, x, y, width, height) == 0) {
|
||||||
break;
|
break;
|
||||||
#else
|
}
|
||||||
|
#endif
|
||||||
args = 0;
|
args = 0;
|
||||||
goto badcmd;
|
goto badcmd;
|
||||||
#endif
|
|
||||||
|
|
||||||
case SVGA_CMD_RECT_COPY:
|
case SVGA_CMD_RECT_COPY:
|
||||||
len -= 7;
|
len -= 7;
|
||||||
@@ -596,12 +636,12 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
|
|||||||
width = vmsvga_fifo_read(s);
|
width = vmsvga_fifo_read(s);
|
||||||
height = vmsvga_fifo_read(s);
|
height = vmsvga_fifo_read(s);
|
||||||
#ifdef HW_RECT_ACCEL
|
#ifdef HW_RECT_ACCEL
|
||||||
vmsvga_copy_rect(s, x, y, dx, dy, width, height);
|
if (vmsvga_copy_rect(s, x, y, dx, dy, width, height) == 0) {
|
||||||
break;
|
break;
|
||||||
#else
|
}
|
||||||
|
#endif
|
||||||
args = 0;
|
args = 0;
|
||||||
goto badcmd;
|
goto badcmd;
|
||||||
#endif
|
|
||||||
|
|
||||||
case SVGA_CMD_DEFINE_CURSOR:
|
case SVGA_CMD_DEFINE_CURSOR:
|
||||||
len -= 8;
|
len -= 8;
|
||||||
|
@@ -546,6 +546,12 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm)
|
|||||||
(1 << ACPI_FADT_F_SLP_BUTTON) |
|
(1 << ACPI_FADT_F_SLP_BUTTON) |
|
||||||
(1 << ACPI_FADT_F_RTC_S4));
|
(1 << ACPI_FADT_F_RTC_S4));
|
||||||
fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_USE_PLATFORM_CLOCK);
|
fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_USE_PLATFORM_CLOCK);
|
||||||
|
/* APIC destination mode ("Flat Logical") has an upper limit of 8 CPUs
|
||||||
|
* For more than 8 CPUs, "Clustered Logical" mode has to be used
|
||||||
|
*/
|
||||||
|
if (max_cpus > 8) {
|
||||||
|
fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1222,8 +1228,7 @@ acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
build_srat(GArray *table_data, GArray *linker,
|
build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
|
||||||
AcpiCpuInfo *cpu, PcGuestInfo *guest_info)
|
|
||||||
{
|
{
|
||||||
AcpiSystemResourceAffinityTable *srat;
|
AcpiSystemResourceAffinityTable *srat;
|
||||||
AcpiSratProcessorAffinity *core;
|
AcpiSratProcessorAffinity *core;
|
||||||
@@ -1253,11 +1258,7 @@ build_srat(GArray *table_data, GArray *linker,
|
|||||||
core->proximity_lo = curnode;
|
core->proximity_lo = curnode;
|
||||||
memset(core->proximity_hi, 0, 3);
|
memset(core->proximity_hi, 0, 3);
|
||||||
core->local_sapic_eid = 0;
|
core->local_sapic_eid = 0;
|
||||||
if (test_bit(i, cpu->found_cpus)) {
|
core->flags = cpu_to_le32(1);
|
||||||
core->flags = cpu_to_le32(1);
|
|
||||||
} else {
|
|
||||||
core->flags = cpu_to_le32(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1393,7 +1394,7 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
|
|||||||
{
|
{
|
||||||
AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
|
AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
|
||||||
|
|
||||||
bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 1,
|
bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16,
|
||||||
true /* fseg memory */);
|
true /* fseg memory */);
|
||||||
|
|
||||||
memcpy(&rsdp->signature, "RSD PTR ", 8);
|
memcpy(&rsdp->signature, "RSD PTR ", 8);
|
||||||
@@ -1533,7 +1534,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
|
|||||||
}
|
}
|
||||||
if (guest_info->numa_nodes) {
|
if (guest_info->numa_nodes) {
|
||||||
acpi_add_table(table_offsets, tables->table_data);
|
acpi_add_table(table_offsets, tables->table_data);
|
||||||
build_srat(tables->table_data, tables->linker, &cpu, guest_info);
|
build_srat(tables->table_data, tables->linker, guest_info);
|
||||||
}
|
}
|
||||||
if (acpi_get_mcfg(&mcfg)) {
|
if (acpi_get_mcfg(&mcfg)) {
|
||||||
acpi_add_table(table_offsets, tables->table_data);
|
acpi_add_table(table_offsets, tables->table_data);
|
||||||
|
@@ -302,7 +302,7 @@ DefinitionBlock (
|
|||||||
/****************************************************************
|
/****************************************************************
|
||||||
* General purpose events
|
* General purpose events
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
|
External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
|
||||||
|
|
||||||
Scope(\_GPE) {
|
Scope(\_GPE) {
|
||||||
Name(_HID, "ACPI0006")
|
Name(_HID, "ACPI0006")
|
||||||
@@ -321,7 +321,7 @@ DefinitionBlock (
|
|||||||
}
|
}
|
||||||
Method(_E03) {
|
Method(_E03) {
|
||||||
// Memory hotplug event
|
// Memory hotplug event
|
||||||
\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
|
\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
|
||||||
}
|
}
|
||||||
Method(_L04) {
|
Method(_L04) {
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x0,
|
0x0,
|
||||||
0x0,
|
0x0,
|
||||||
0x1,
|
0x1,
|
||||||
0x2e,
|
0x1f,
|
||||||
0x42,
|
0x42,
|
||||||
0x58,
|
0x58,
|
||||||
0x50,
|
0x50,
|
||||||
@@ -31,9 +31,9 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x4e,
|
0x4e,
|
||||||
0x54,
|
0x54,
|
||||||
0x4c,
|
0x4c,
|
||||||
0x13,
|
0x28,
|
||||||
0x9,
|
0x5,
|
||||||
0x12,
|
0x10,
|
||||||
0x20,
|
0x20,
|
||||||
0x10,
|
0x10,
|
||||||
0x49,
|
0x49,
|
||||||
|
@@ -14,8 +14,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
|
#include "qemu/host-utils.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
|
#include "sysemu/cpus.h"
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "hw/kvm/clock.h"
|
#include "hw/kvm/clock.h"
|
||||||
|
|
||||||
@@ -34,6 +36,48 @@ typedef struct KVMClockState {
|
|||||||
bool clock_valid;
|
bool clock_valid;
|
||||||
} KVMClockState;
|
} KVMClockState;
|
||||||
|
|
||||||
|
struct pvclock_vcpu_time_info {
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t pad0;
|
||||||
|
uint64_t tsc_timestamp;
|
||||||
|
uint64_t system_time;
|
||||||
|
uint32_t tsc_to_system_mul;
|
||||||
|
int8_t tsc_shift;
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t pad[2];
|
||||||
|
} __attribute__((__packed__)); /* 32 bytes */
|
||||||
|
|
||||||
|
static uint64_t kvmclock_current_nsec(KVMClockState *s)
|
||||||
|
{
|
||||||
|
CPUState *cpu = first_cpu;
|
||||||
|
CPUX86State *env = cpu->env_ptr;
|
||||||
|
hwaddr kvmclock_struct_pa = env->system_time_msr & ~1ULL;
|
||||||
|
uint64_t migration_tsc = env->tsc;
|
||||||
|
struct pvclock_vcpu_time_info time;
|
||||||
|
uint64_t delta;
|
||||||
|
uint64_t nsec_lo;
|
||||||
|
uint64_t nsec_hi;
|
||||||
|
uint64_t nsec;
|
||||||
|
|
||||||
|
if (!(env->system_time_msr & 1ULL)) {
|
||||||
|
/* KVM clock not active */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_physical_memory_read(kvmclock_struct_pa, &time, sizeof(time));
|
||||||
|
|
||||||
|
assert(time.tsc_timestamp <= migration_tsc);
|
||||||
|
delta = migration_tsc - time.tsc_timestamp;
|
||||||
|
if (time.tsc_shift < 0) {
|
||||||
|
delta >>= -time.tsc_shift;
|
||||||
|
} else {
|
||||||
|
delta <<= time.tsc_shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
mulu64(&nsec_lo, &nsec_hi, delta, time.tsc_to_system_mul);
|
||||||
|
nsec = (nsec_lo >> 32) | (nsec_hi << 32);
|
||||||
|
return nsec + time.system_time;
|
||||||
|
}
|
||||||
|
|
||||||
static void kvmclock_vm_state_change(void *opaque, int running,
|
static void kvmclock_vm_state_change(void *opaque, int running,
|
||||||
RunState state)
|
RunState state)
|
||||||
@@ -45,9 +89,15 @@ static void kvmclock_vm_state_change(void *opaque, int running,
|
|||||||
|
|
||||||
if (running) {
|
if (running) {
|
||||||
struct kvm_clock_data data;
|
struct kvm_clock_data data;
|
||||||
|
uint64_t time_at_migration = kvmclock_current_nsec(s);
|
||||||
|
|
||||||
s->clock_valid = false;
|
s->clock_valid = false;
|
||||||
|
|
||||||
|
/* We can't rely on the migrated clock value, just discard it */
|
||||||
|
if (time_at_migration) {
|
||||||
|
s->clock = time_at_migration;
|
||||||
|
}
|
||||||
|
|
||||||
data.clock = s->clock;
|
data.clock = s->clock;
|
||||||
data.flags = 0;
|
data.flags = 0;
|
||||||
ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
|
ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
|
||||||
@@ -75,6 +125,23 @@ static void kvmclock_vm_state_change(void *opaque, int running,
|
|||||||
if (s->clock_valid) {
|
if (s->clock_valid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu_synchronize_all_states();
|
||||||
|
/* In theory, the cpu_synchronize_all_states() call above wouldn't
|
||||||
|
* affect the rest of the code, as the VCPU state inside CPUState
|
||||||
|
* is supposed to always match the VCPU state on the kernel side.
|
||||||
|
*
|
||||||
|
* In practice, calling cpu_synchronize_state() too soon will load the
|
||||||
|
* kernel-side APIC state into X86CPU.apic_state too early, APIC state
|
||||||
|
* won't be reloaded later because CPUState.vcpu_dirty==true, and
|
||||||
|
* outdated APIC state may be migrated to another host.
|
||||||
|
*
|
||||||
|
* The real fix would be to make sure outdated APIC state is read
|
||||||
|
* from the kernel again when necessary. While this is not fixed, we
|
||||||
|
* need the cpu_clean_all_dirty() call below.
|
||||||
|
*/
|
||||||
|
cpu_clean_all_dirty();
|
||||||
|
|
||||||
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
|
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
|
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
|
||||||
|
16
hw/i386/pc.c
16
hw/i386/pc.c
@@ -72,8 +72,15 @@
|
|||||||
#define DPRINTF(fmt, ...)
|
#define DPRINTF(fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
|
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables
|
||||||
#define ACPI_DATA_SIZE 0x10000
|
* (128K) and other BIOS datastructures (less than 4K reported to be used at
|
||||||
|
* the moment, 32K should be enough for a while). */
|
||||||
|
unsigned acpi_data_size = 0x20000 + 0x8000;
|
||||||
|
void pc_set_legacy_acpi_data_size(void)
|
||||||
|
{
|
||||||
|
acpi_data_size = 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
#define BIOS_CFG_IOPORT 0x510
|
#define BIOS_CFG_IOPORT 0x510
|
||||||
#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
|
#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
|
||||||
#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
|
#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
|
||||||
@@ -811,8 +818,9 @@ static void load_linux(FWCfgState *fw_cfg,
|
|||||||
initrd_max = 0x37ffffff;
|
initrd_max = 0x37ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initrd_max >= max_ram_size-ACPI_DATA_SIZE)
|
if (initrd_max >= max_ram_size - acpi_data_size) {
|
||||||
initrd_max = max_ram_size-ACPI_DATA_SIZE-1;
|
initrd_max = max_ram_size - acpi_data_size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
|
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
|
||||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
|
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
|
||||||
|
@@ -318,6 +318,7 @@ static void pc_compat_2_0(MachineState *machine)
|
|||||||
legacy_acpi_table_size = 6652;
|
legacy_acpi_table_size = 6652;
|
||||||
smbios_legacy_mode = true;
|
smbios_legacy_mode = true;
|
||||||
has_reserved_memory = false;
|
has_reserved_memory = false;
|
||||||
|
pc_set_legacy_acpi_data_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_compat_1_7(MachineState *machine)
|
static void pc_compat_1_7(MachineState *machine)
|
||||||
@@ -645,7 +646,7 @@ static QEMUMachine pc_machine_v1_1 = {
|
|||||||
.property = "class",\
|
.property = "class",\
|
||||||
.value = stringify(PCI_CLASS_MEMORY_RAM),\
|
.value = stringify(PCI_CLASS_MEMORY_RAM),\
|
||||||
},{\
|
},{\
|
||||||
.driver = "apic",\
|
.driver = "apic-common",\
|
||||||
.property = "vapic",\
|
.property = "vapic",\
|
||||||
.value = "off",\
|
.value = "off",\
|
||||||
},{\
|
},{\
|
||||||
|
@@ -282,6 +282,7 @@ static void pc_compat_2_0(MachineState *machine)
|
|||||||
{
|
{
|
||||||
smbios_legacy_mode = true;
|
smbios_legacy_mode = true;
|
||||||
has_reserved_memory = false;
|
has_reserved_memory = false;
|
||||||
|
pc_set_legacy_acpi_data_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_compat_1_7(MachineState *machine)
|
static void pc_compat_1_7(MachineState *machine)
|
||||||
|
@@ -410,7 +410,7 @@ DefinitionBlock (
|
|||||||
/****************************************************************
|
/****************************************************************
|
||||||
* General purpose events
|
* General purpose events
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
|
External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
|
||||||
|
|
||||||
Scope(\_GPE) {
|
Scope(\_GPE) {
|
||||||
Name(_HID, "ACPI0006")
|
Name(_HID, "ACPI0006")
|
||||||
@@ -425,7 +425,7 @@ DefinitionBlock (
|
|||||||
}
|
}
|
||||||
Method(_E03) {
|
Method(_E03) {
|
||||||
// Memory hotplug event
|
// Memory hotplug event
|
||||||
\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
|
\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
|
||||||
}
|
}
|
||||||
Method(_L04) {
|
Method(_L04) {
|
||||||
}
|
}
|
||||||
|
@@ -821,7 +821,7 @@ void smbios_get_tables(uint8_t **tables, size_t *tables_len,
|
|||||||
smbios_build_type_2_table();
|
smbios_build_type_2_table();
|
||||||
smbios_build_type_3_table();
|
smbios_build_type_3_table();
|
||||||
|
|
||||||
smbios_smp_sockets = smp_cpus / (smp_cores * smp_threads);
|
smbios_smp_sockets = DIV_ROUND_UP(smp_cpus, smp_cores * smp_threads);
|
||||||
assert(smbios_smp_sockets >= 1);
|
assert(smbios_smp_sockets >= 1);
|
||||||
|
|
||||||
for (i = 0; i < smbios_smp_sockets; i++) {
|
for (i = 0; i < smbios_smp_sockets; i++) {
|
||||||
|
@@ -39,10 +39,10 @@ ACPI_EXTRACT_ALL_CODE ssdm_mem_aml
|
|||||||
DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1)
|
DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1)
|
||||||
{
|
{
|
||||||
|
|
||||||
External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_CRS_METHOD, MethodObj)
|
External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_CRS_METHOD, MethodObj)
|
||||||
External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD, MethodObj)
|
External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD, MethodObj)
|
||||||
External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_OST_METHOD, MethodObj)
|
External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_OST_METHOD, MethodObj)
|
||||||
External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD, MethodObj)
|
External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD, MethodObj)
|
||||||
|
|
||||||
Scope(\_SB) {
|
Scope(\_SB) {
|
||||||
/* v------------------ DO NOT EDIT ------------------v */
|
/* v------------------ DO NOT EDIT ------------------v */
|
||||||
@@ -58,19 +58,19 @@ DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1)
|
|||||||
Name(_HID, EISAID("PNP0C80"))
|
Name(_HID, EISAID("PNP0C80"))
|
||||||
|
|
||||||
Method(_CRS, 0) {
|
Method(_CRS, 0) {
|
||||||
Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_CRS_METHOD(_UID))
|
Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_CRS_METHOD(_UID))
|
||||||
}
|
}
|
||||||
|
|
||||||
Method(_STA, 0) {
|
Method(_STA, 0) {
|
||||||
Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD(_UID))
|
Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD(_UID))
|
||||||
}
|
}
|
||||||
|
|
||||||
Method(_PXM, 0) {
|
Method(_PXM, 0) {
|
||||||
Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD(_UID))
|
Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD(_UID))
|
||||||
}
|
}
|
||||||
|
|
||||||
Method(_OST, 3) {
|
Method(_OST, 3) {
|
||||||
\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_OST_METHOD(_UID, Arg0, Arg1, Arg2)
|
\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_OST_METHOD(_UID, Arg0, Arg1, Arg2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -120,7 +120,7 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1)
|
|||||||
|
|
||||||
External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj)
|
External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj)
|
||||||
Scope(\_SB.PCI0) {
|
Scope(\_SB.PCI0) {
|
||||||
Device(MEMORY_HOPTLUG_DEVICE) {
|
Device(MEMORY_HOTPLUG_DEVICE) {
|
||||||
Name(_HID, "PNP0A06")
|
Name(_HID, "PNP0A06")
|
||||||
Name(_UID, "Memory hotplug resources")
|
Name(_UID, "Memory hotplug resources")
|
||||||
|
|
||||||
|
@@ -688,7 +688,8 @@ void ide_dma_cb(void *opaque, int ret)
|
|||||||
sector_num, n, s->dma_cmd);
|
sector_num, n, s->dma_cmd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!ide_sect_range_ok(s, sector_num, n)) {
|
if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
|
||||||
|
!ide_sect_range_ok(s, sector_num, n)) {
|
||||||
dma_buf_commit(s);
|
dma_buf_commit(s);
|
||||||
ide_dma_error(s);
|
ide_dma_error(s);
|
||||||
return;
|
return;
|
||||||
@@ -2298,7 +2299,7 @@ static int ide_drive_post_load(void *opaque, int version_id)
|
|||||||
{
|
{
|
||||||
IDEState *s = opaque;
|
IDEState *s = opaque;
|
||||||
|
|
||||||
if (s->identify_set) {
|
if (s->bs && s->identify_set) {
|
||||||
bdrv_set_enable_write_cache(s->bs, !!(s->identify_data[85] & (1 << 5)));
|
bdrv_set_enable_write_cache(s->bs, !!(s->identify_data[85] & (1 << 5)));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -74,7 +74,8 @@ static void an5206_init(MachineState *machine)
|
|||||||
NULL, NULL, 1, ELF_MACHINE, 0);
|
NULL, NULL, 1, ELF_MACHINE, 0);
|
||||||
entry = elf_entry;
|
entry = elf_entry;
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
|
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
|
||||||
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
|
kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
|
||||||
|
@@ -50,7 +50,8 @@ static void dummy_m68k_init(MachineState *machine)
|
|||||||
NULL, NULL, 1, ELF_MACHINE, 0);
|
NULL, NULL, 1, ELF_MACHINE, 0);
|
||||||
entry = elf_entry;
|
entry = elf_entry;
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
|
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
|
||||||
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_image_targphys(kernel_filename,
|
kernel_size = load_image_targphys(kernel_filename,
|
||||||
|
@@ -279,7 +279,8 @@ static void mcf5208evb_init(MachineState *machine)
|
|||||||
NULL, NULL, 1, ELF_MACHINE, 0);
|
NULL, NULL, 1, ELF_MACHINE, 0);
|
||||||
entry = elf_entry;
|
entry = elf_entry;
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
|
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
|
||||||
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_image_targphys(kernel_filename, 0x40000000,
|
kernel_size = load_image_targphys(kernel_filename, 0x40000000,
|
||||||
|
@@ -252,6 +252,12 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
|
|||||||
error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
|
error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) {
|
||||||
|
error_setg(errp, "'DIMM property " PC_DIMM_NODE_PROP " has value %"
|
||||||
|
PRIu32 "' which exceeds the number of numa nodes: %d",
|
||||||
|
dimm->node, nb_numa_nodes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm)
|
static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm)
|
||||||
|
@@ -154,7 +154,8 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
|
|||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
hwaddr uentry, loadaddr;
|
hwaddr uentry, loadaddr;
|
||||||
|
|
||||||
kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
|
kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
|
||||||
|
NULL, NULL);
|
||||||
boot_info.bootstrap_pc = uentry;
|
boot_info.bootstrap_pc = uentry;
|
||||||
high = (loadaddr + kernel_size + 3) & ~3;
|
high = (loadaddr + kernel_size + 3) & ~3;
|
||||||
}
|
}
|
||||||
|
@@ -24,10 +24,12 @@
|
|||||||
#include "migration/migration.h"
|
#include "migration/migration.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "qemu/event_notifier.h"
|
#include "qemu/event_notifier.h"
|
||||||
|
#include "qemu/fifo8.h"
|
||||||
#include "sysemu/char.h"
|
#include "sysemu/char.h"
|
||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET
|
#define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET
|
||||||
#define PCI_DEVICE_ID_IVSHMEM 0x1110
|
#define PCI_DEVICE_ID_IVSHMEM 0x1110
|
||||||
@@ -73,6 +75,7 @@ typedef struct IVShmemState {
|
|||||||
|
|
||||||
CharDriverState **eventfd_chr;
|
CharDriverState **eventfd_chr;
|
||||||
CharDriverState *server_chr;
|
CharDriverState *server_chr;
|
||||||
|
Fifo8 incoming_fifo;
|
||||||
MemoryRegion ivshmem_mmio;
|
MemoryRegion ivshmem_mmio;
|
||||||
|
|
||||||
/* We might need to register the BAR before we actually have the memory.
|
/* We might need to register the BAR before we actually have the memory.
|
||||||
@@ -383,6 +386,9 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
|
|||||||
if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
|
if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (posn < 0 || posn >= s->nb_peers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
guest_curr_max = s->peers[posn].nb_eventfds;
|
guest_curr_max = s->peers[posn].nb_eventfds;
|
||||||
|
|
||||||
@@ -401,14 +407,24 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
|
|||||||
|
|
||||||
/* this function increase the dynamic storage need to store data about other
|
/* this function increase the dynamic storage need to store data about other
|
||||||
* guests */
|
* guests */
|
||||||
static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
|
static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
|
||||||
|
{
|
||||||
|
|
||||||
int j, old_nb_alloc;
|
int j, old_nb_alloc;
|
||||||
|
|
||||||
|
/* check for integer overflow */
|
||||||
|
if (new_min_size >= INT_MAX / sizeof(Peer) - 1 || new_min_size <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
old_nb_alloc = s->nb_peers;
|
old_nb_alloc = s->nb_peers;
|
||||||
|
|
||||||
while (new_min_size >= s->nb_peers)
|
if (new_min_size >= s->nb_peers) {
|
||||||
s->nb_peers = s->nb_peers * 2;
|
/* +1 because #new_min_size is used as last array index */
|
||||||
|
s->nb_peers = new_min_size + 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
|
IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
|
||||||
s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
|
s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
|
||||||
@@ -418,23 +434,57 @@ static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
|
|||||||
s->peers[j].eventfds = NULL;
|
s->peers[j].eventfds = NULL;
|
||||||
s->peers[j].nb_eventfds = 0;
|
s->peers[j].nb_eventfds = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
|
static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
|
||||||
{
|
{
|
||||||
IVShmemState *s = opaque;
|
IVShmemState *s = opaque;
|
||||||
int incoming_fd, tmp_fd;
|
int incoming_fd, tmp_fd;
|
||||||
int guest_max_eventfd;
|
int guest_max_eventfd;
|
||||||
long incoming_posn;
|
long incoming_posn;
|
||||||
|
|
||||||
memcpy(&incoming_posn, buf, sizeof(long));
|
if (fifo8_is_empty(&s->incoming_fifo) && size == sizeof(incoming_posn)) {
|
||||||
|
memcpy(&incoming_posn, buf, size);
|
||||||
|
} else {
|
||||||
|
const uint8_t *p;
|
||||||
|
uint32_t num;
|
||||||
|
|
||||||
|
IVSHMEM_DPRINTF("short read of %d bytes\n", size);
|
||||||
|
num = MAX(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
|
||||||
|
fifo8_push_all(&s->incoming_fifo, buf, num);
|
||||||
|
if (fifo8_num_used(&s->incoming_fifo) < sizeof(incoming_posn)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size -= num;
|
||||||
|
buf += num;
|
||||||
|
p = fifo8_pop_buf(&s->incoming_fifo, sizeof(incoming_posn), &num);
|
||||||
|
g_assert(num == sizeof(incoming_posn));
|
||||||
|
memcpy(&incoming_posn, p, sizeof(incoming_posn));
|
||||||
|
if (size > 0) {
|
||||||
|
fifo8_push_all(&s->incoming_fifo, buf, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (incoming_posn < -1) {
|
||||||
|
IVSHMEM_DPRINTF("invalid incoming_posn %ld\n", incoming_posn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* pick off s->server_chr->msgfd and store it, posn should accompany msg */
|
/* pick off s->server_chr->msgfd and store it, posn should accompany msg */
|
||||||
tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
|
tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
|
||||||
IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
|
IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
|
||||||
|
|
||||||
/* make sure we have enough space for this guest */
|
/* make sure we have enough space for this guest */
|
||||||
if (incoming_posn >= s->nb_peers) {
|
if (incoming_posn >= s->nb_peers) {
|
||||||
increase_dynamic_storage(s, incoming_posn);
|
if (increase_dynamic_storage(s, incoming_posn) < 0) {
|
||||||
|
error_report("increase_dynamic_storage() failed");
|
||||||
|
if (tmp_fd != -1) {
|
||||||
|
close(tmp_fd);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp_fd == -1) {
|
if (tmp_fd == -1) {
|
||||||
@@ -458,6 +508,7 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
|
|||||||
if (incoming_fd == -1) {
|
if (incoming_fd == -1) {
|
||||||
fprintf(stderr, "could not allocate file descriptor %s\n",
|
fprintf(stderr, "could not allocate file descriptor %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
close(tmp_fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,6 +710,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
|
|||||||
s->ivshmem_size = ivshmem_get_size(s);
|
s->ivshmem_size = ivshmem_get_size(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fifo8_create(&s->incoming_fifo, sizeof(long));
|
||||||
|
|
||||||
register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
|
register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
|
||||||
dev);
|
dev);
|
||||||
|
|
||||||
@@ -795,6 +848,7 @@ static void pci_ivshmem_uninit(PCIDevice *dev)
|
|||||||
memory_region_destroy(&s->ivshmem);
|
memory_region_destroy(&s->ivshmem);
|
||||||
memory_region_destroy(&s->bar);
|
memory_region_destroy(&s->bar);
|
||||||
unregister_savevm(DEVICE(dev), "ivshmem", s);
|
unregister_savevm(DEVICE(dev), "ivshmem", s);
|
||||||
|
fifo8_destroy(&s->incoming_fifo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property ivshmem_properties[] = {
|
static Property ivshmem_properties[] = {
|
||||||
|
@@ -120,11 +120,20 @@ typedef struct VFIOINTx {
|
|||||||
} VFIOINTx;
|
} VFIOINTx;
|
||||||
|
|
||||||
typedef struct VFIOMSIVector {
|
typedef struct VFIOMSIVector {
|
||||||
EventNotifier interrupt; /* eventfd triggered on interrupt */
|
/*
|
||||||
EventNotifier kvm_interrupt; /* eventfd triggered for KVM irqfd bypass */
|
* Two interrupt paths are configured per vector. The first, is only used
|
||||||
|
* for interrupts injected via QEMU. This is typically the non-accel path,
|
||||||
|
* but may also be used when we want QEMU to handle masking and pending
|
||||||
|
* bits. The KVM path bypasses QEMU and is therefore higher performance,
|
||||||
|
* but requires masking at the device. virq is used to track the MSI route
|
||||||
|
* through KVM, thus kvm_interrupt is only available when virq is set to a
|
||||||
|
* valid (>= 0) value.
|
||||||
|
*/
|
||||||
|
EventNotifier interrupt;
|
||||||
|
EventNotifier kvm_interrupt;
|
||||||
struct VFIODevice *vdev; /* back pointer to device */
|
struct VFIODevice *vdev; /* back pointer to device */
|
||||||
MSIMessage msg; /* cache the MSI message so we know when it changes */
|
MSIMessage msg; /* cache the MSI message so we know when it changes */
|
||||||
int virq; /* KVM irqchip route for QEMU bypass */
|
int virq;
|
||||||
bool use;
|
bool use;
|
||||||
} VFIOMSIVector;
|
} VFIOMSIVector;
|
||||||
|
|
||||||
@@ -681,13 +690,24 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
|
|||||||
fds = (int32_t *)&irq_set->data;
|
fds = (int32_t *)&irq_set->data;
|
||||||
|
|
||||||
for (i = 0; i < vdev->nr_vectors; i++) {
|
for (i = 0; i < vdev->nr_vectors; i++) {
|
||||||
if (!vdev->msi_vectors[i].use) {
|
int fd = -1;
|
||||||
fds[i] = -1;
|
|
||||||
} else if (vdev->msi_vectors[i].virq >= 0) {
|
/*
|
||||||
fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
|
* MSI vs MSI-X - The guest has direct access to MSI mask and pending
|
||||||
} else {
|
* bits, therefore we always use the KVM signaling path when setup.
|
||||||
fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
|
* MSI-X mask and pending bits are emulated, so we want to use the
|
||||||
|
* KVM signaling path only when configured and unmasked.
|
||||||
|
*/
|
||||||
|
if (vdev->msi_vectors[i].use) {
|
||||||
|
if (vdev->msi_vectors[i].virq < 0 ||
|
||||||
|
(msix && msix_is_masked(&vdev->pdev, i))) {
|
||||||
|
fd = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
|
||||||
|
} else {
|
||||||
|
fd = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fds[i] = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
|
ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
|
||||||
|
@@ -115,6 +115,7 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
|
|||||||
|
|
||||||
void vhost_net_ack_features(struct vhost_net *net, unsigned features)
|
void vhost_net_ack_features(struct vhost_net *net, unsigned features)
|
||||||
{
|
{
|
||||||
|
net->dev.acked_features = net->dev.backend_features;
|
||||||
vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
|
vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,11 +163,11 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (!qemu_has_vnet_hdr_len(options->net_backend,
|
|
||||||
sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
|
|
||||||
net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
|
|
||||||
}
|
|
||||||
if (backend_kernel) {
|
if (backend_kernel) {
|
||||||
|
if (!qemu_has_vnet_hdr_len(options->net_backend,
|
||||||
|
sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
|
||||||
|
net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
|
||||||
|
}
|
||||||
if (~net->dev.features & net->dev.backend_features) {
|
if (~net->dev.features & net->dev.backend_features) {
|
||||||
fprintf(stderr, "vhost lacks feature mask %" PRIu64
|
fprintf(stderr, "vhost lacks feature mask %" PRIu64
|
||||||
" for backend\n",
|
" for backend\n",
|
||||||
@@ -188,9 +189,13 @@ bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
|
|||||||
return vhost_dev_query(&net->dev, dev);
|
return vhost_dev_query(&net->dev, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
|
||||||
|
{
|
||||||
|
net->dev.vq_index = vq_index;
|
||||||
|
}
|
||||||
|
|
||||||
static int vhost_net_start_one(struct vhost_net *net,
|
static int vhost_net_start_one(struct vhost_net *net,
|
||||||
VirtIODevice *dev,
|
VirtIODevice *dev)
|
||||||
int vq_index)
|
|
||||||
{
|
{
|
||||||
struct vhost_vring_file file = { };
|
struct vhost_vring_file file = { };
|
||||||
int r;
|
int r;
|
||||||
@@ -201,7 +206,6 @@ static int vhost_net_start_one(struct vhost_net *net,
|
|||||||
|
|
||||||
net->dev.nvqs = 2;
|
net->dev.nvqs = 2;
|
||||||
net->dev.vqs = net->vqs;
|
net->dev.vqs = net->vqs;
|
||||||
net->dev.vq_index = vq_index;
|
|
||||||
|
|
||||||
r = vhost_dev_enable_notifiers(&net->dev, dev);
|
r = vhost_dev_enable_notifiers(&net->dev, dev);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@@ -294,7 +298,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
|||||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
|
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
|
||||||
VirtioBusState *vbus = VIRTIO_BUS(qbus);
|
VirtioBusState *vbus = VIRTIO_BUS(qbus);
|
||||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
|
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
|
||||||
int r, i = 0;
|
int r, e, i;
|
||||||
|
|
||||||
if (!vhost_net_device_endian_ok(dev)) {
|
if (!vhost_net_device_endian_ok(dev)) {
|
||||||
error_report("vhost-net does not support cross-endian");
|
error_report("vhost-net does not support cross-endian");
|
||||||
@@ -309,11 +313,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < total_queues; i++) {
|
for (i = 0; i < total_queues; i++) {
|
||||||
r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev, i * 2);
|
vhost_net_set_vq_index(get_vhost_net(ncs[i].peer), i * 2);
|
||||||
|
|
||||||
if (r < 0) {
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
|
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
|
||||||
@@ -322,12 +322,26 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < total_queues; i++) {
|
||||||
|
r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev);
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
goto err_start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err_start:
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
|
vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
|
||||||
}
|
}
|
||||||
|
e = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
|
||||||
|
if (e < 0) {
|
||||||
|
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
err:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,16 +353,16 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
|
|||||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
|
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
|
for (i = 0; i < total_queues; i++) {
|
||||||
|
vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
|
||||||
|
}
|
||||||
|
|
||||||
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
|
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
|
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
}
|
}
|
||||||
assert(r >= 0);
|
assert(r >= 0);
|
||||||
|
|
||||||
for (i = 0; i < total_queues; i++) {
|
|
||||||
vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vhost_net_cleanup(struct vhost_net *net)
|
void vhost_net_cleanup(struct vhost_net *net)
|
||||||
|
@@ -125,10 +125,23 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!n->vhost_started) {
|
if (!n->vhost_started) {
|
||||||
int r;
|
int r, i;
|
||||||
|
|
||||||
if (!vhost_net_query(get_vhost_net(nc->peer), vdev)) {
|
if (!vhost_net_query(get_vhost_net(nc->peer), vdev)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Any packets outstanding? Purge them to avoid touching rings
|
||||||
|
* when vhost is running.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < queues; i++) {
|
||||||
|
NetClientState *qnc = qemu_get_subqueue(n->nic, i);
|
||||||
|
|
||||||
|
/* Purge both directions: TX and RX. */
|
||||||
|
qemu_net_queue_purge(qnc->peer->incoming_queue, qnc);
|
||||||
|
qemu_net_queue_purge(qnc->incoming_queue, qnc->peer);
|
||||||
|
}
|
||||||
|
|
||||||
n->vhost_started = 1;
|
n->vhost_started = 1;
|
||||||
r = vhost_net_start(vdev, n->nic->ncs, queues);
|
r = vhost_net_start(vdev, n->nic->ncs, queues);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@@ -785,7 +798,7 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
|
virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
|
||||||
VirtQueueElement elem;
|
VirtQueueElement elem;
|
||||||
size_t s;
|
size_t s;
|
||||||
struct iovec *iov;
|
struct iovec *iov, *iov2;
|
||||||
unsigned int iov_cnt;
|
unsigned int iov_cnt;
|
||||||
|
|
||||||
while (virtqueue_pop(vq, &elem)) {
|
while (virtqueue_pop(vq, &elem)) {
|
||||||
@@ -795,8 +808,8 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
iov = elem.out_sg;
|
|
||||||
iov_cnt = elem.out_num;
|
iov_cnt = elem.out_num;
|
||||||
|
iov2 = iov = g_memdup(elem.out_sg, sizeof(struct iovec) * elem.out_num);
|
||||||
s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
|
s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
|
||||||
iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
|
iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
|
||||||
if (s != sizeof(ctrl)) {
|
if (s != sizeof(ctrl)) {
|
||||||
@@ -820,6 +833,7 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
|
|
||||||
virtqueue_push(vq, &elem, sizeof(status));
|
virtqueue_push(vq, &elem, sizeof(status));
|
||||||
virtio_notify(vdev, vq);
|
virtio_notify(vdev, vq);
|
||||||
|
g_free(iov2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1112,8 +1126,6 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
|||||||
return num_packets;
|
return num_packets;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(vdev->vm_running);
|
|
||||||
|
|
||||||
if (q->async_tx.elem.out_num) {
|
if (q->async_tx.elem.out_num) {
|
||||||
virtio_queue_set_notification(q->tx_vq, 0);
|
virtio_queue_set_notification(q->tx_vq, 0);
|
||||||
return num_packets;
|
return num_packets;
|
||||||
@@ -1224,7 +1236,12 @@ static void virtio_net_tx_timer(void *opaque)
|
|||||||
VirtIONetQueue *q = opaque;
|
VirtIONetQueue *q = opaque;
|
||||||
VirtIONet *n = q->n;
|
VirtIONet *n = q->n;
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
||||||
assert(vdev->vm_running);
|
/* This happens when device was stopped but BH wasn't. */
|
||||||
|
if (!vdev->vm_running) {
|
||||||
|
/* Make sure tx waiting is set, so we'll run when restarted. */
|
||||||
|
assert(q->tx_waiting);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
q->tx_waiting = 0;
|
q->tx_waiting = 0;
|
||||||
|
|
||||||
@@ -1244,7 +1261,12 @@ static void virtio_net_tx_bh(void *opaque)
|
|||||||
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
|
|
||||||
assert(vdev->vm_running);
|
/* This happens when device was stopped but BH wasn't. */
|
||||||
|
if (!vdev->vm_running) {
|
||||||
|
/* Make sure tx waiting is set, so we'll run when restarted. */
|
||||||
|
assert(q->tx_waiting);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
q->tx_waiting = 0;
|
q->tx_waiting = 0;
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1
|
#define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1
|
||||||
#define VMXNET3_MSIX_BAR_SIZE 0x2000
|
#define VMXNET3_MSIX_BAR_SIZE 0x2000
|
||||||
|
#define MIN_BUF_SIZE 60
|
||||||
|
|
||||||
#define VMXNET3_BAR0_IDX (0)
|
#define VMXNET3_BAR0_IDX (0)
|
||||||
#define VMXNET3_BAR1_IDX (1)
|
#define VMXNET3_BAR1_IDX (1)
|
||||||
@@ -1871,12 +1872,21 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||||||
{
|
{
|
||||||
VMXNET3State *s = qemu_get_nic_opaque(nc);
|
VMXNET3State *s = qemu_get_nic_opaque(nc);
|
||||||
size_t bytes_indicated;
|
size_t bytes_indicated;
|
||||||
|
uint8_t min_buf[MIN_BUF_SIZE];
|
||||||
|
|
||||||
if (!vmxnet3_can_receive(nc)) {
|
if (!vmxnet3_can_receive(nc)) {
|
||||||
VMW_PKPRN("Cannot receive now");
|
VMW_PKPRN("Cannot receive now");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pad to minimum Ethernet frame length */
|
||||||
|
if (size < sizeof(min_buf)) {
|
||||||
|
memcpy(min_buf, buf, size);
|
||||||
|
memset(&min_buf[size], 0, sizeof(min_buf) - size);
|
||||||
|
buf = min_buf;
|
||||||
|
size = sizeof(min_buf);
|
||||||
|
}
|
||||||
|
|
||||||
if (s->peer_has_vhdr) {
|
if (s->peer_has_vhdr) {
|
||||||
vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf);
|
vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf);
|
||||||
buf += sizeof(struct virtio_net_hdr);
|
buf += sizeof(struct virtio_net_hdr);
|
||||||
|
@@ -72,7 +72,7 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size,
|
|||||||
entry = elf_entry;
|
entry = elf_entry;
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_uimage(kernel_filename,
|
kernel_size = load_uimage(kernel_filename,
|
||||||
&entry, NULL, NULL);
|
&entry, NULL, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_image_targphys(kernel_filename,
|
kernel_size = load_image_targphys(kernel_filename,
|
||||||
|
@@ -291,7 +291,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
|
|||||||
"notify vector 0x%x"
|
"notify vector 0x%x"
|
||||||
" address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
|
" address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
|
||||||
vector, msg.address, msg.data);
|
vector, msg.address, msg.data);
|
||||||
stl_le_phys(&address_space_memory, msg.address, msg.data);
|
stl_le_phys(&dev->bus_master_as, msg.address, msg.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Normally called by pci_default_write_config(). */
|
/* Normally called by pci_default_write_config(). */
|
||||||
|
@@ -439,7 +439,7 @@ void msix_notify(PCIDevice *dev, unsigned vector)
|
|||||||
|
|
||||||
msg = msix_get_message(dev, vector);
|
msg = msix_get_message(dev, vector);
|
||||||
|
|
||||||
stl_le_phys(&address_space_memory, msg.address, msg.data);
|
stl_le_phys(&dev->bus_master_as, msg.address, msg.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void msix_reset(PCIDevice *dev)
|
void msix_reset(PCIDevice *dev)
|
||||||
|
@@ -1147,9 +1147,10 @@ uint32_t pci_default_read_config(PCIDevice *d,
|
|||||||
return le32_to_cpu(val);
|
return le32_to_cpu(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
|
void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int l)
|
||||||
{
|
{
|
||||||
int i, was_irq_disabled = pci_irq_disabled(d);
|
int i, was_irq_disabled = pci_irq_disabled(d);
|
||||||
|
uint32_t val = val_in;
|
||||||
|
|
||||||
for (i = 0; i < l; val >>= 8, ++i) {
|
for (i = 0; i < l; val >>= 8, ++i) {
|
||||||
uint8_t wmask = d->wmask[addr + i];
|
uint8_t wmask = d->wmask[addr + i];
|
||||||
@@ -1171,8 +1172,8 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
|
|||||||
& PCI_COMMAND_MASTER);
|
& PCI_COMMAND_MASTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
msi_write_config(d, addr, val, l);
|
msi_write_config(d, addr, val_in, l);
|
||||||
msix_write_config(d, addr, val, l);
|
msix_write_config(d, addr, val_in, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
|
@@ -830,7 +830,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
|||||||
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
|
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
|
||||||
* ePAPR compliant kernel
|
* ePAPR compliant kernel
|
||||||
*/
|
*/
|
||||||
kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL);
|
kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
|
||||||
|
NULL, NULL);
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
|
fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@@ -253,7 +253,8 @@ static void bamboo_init(MachineState *machine)
|
|||||||
|
|
||||||
/* Load kernel. */
|
/* Load kernel. */
|
||||||
if (kernel_filename) {
|
if (kernel_filename) {
|
||||||
success = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
|
success = load_uimage(kernel_filename, &entry, &loadaddr, NULL,
|
||||||
|
NULL, NULL);
|
||||||
if (success < 0) {
|
if (success < 0) {
|
||||||
success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
|
success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
|
||||||
&elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
|
&elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
|
||||||
|
@@ -1377,7 +1377,6 @@ static void ppc_spapr_init(MachineState *machine)
|
|||||||
spapr_create_nvram(spapr);
|
spapr_create_nvram(spapr);
|
||||||
|
|
||||||
/* Set up PCI */
|
/* Set up PCI */
|
||||||
spapr_pci_msi_init(spapr, SPAPR_PCI_MSI_WINDOW);
|
|
||||||
spapr_pci_rtas_init();
|
spapr_pci_rtas_init();
|
||||||
|
|
||||||
phb = spapr_create_phb(spapr, 0);
|
phb = spapr_create_phb(spapr, 0);
|
||||||
|
@@ -172,9 +172,9 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
|
|||||||
return tcet;
|
return tcet;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_tce_table_finalize(Object *obj)
|
static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(obj);
|
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
|
||||||
|
|
||||||
QLIST_REMOVE(tcet, list);
|
QLIST_REMOVE(tcet, list);
|
||||||
|
|
||||||
@@ -419,6 +419,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
|
|||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
dc->init = spapr_tce_table_realize;
|
dc->init = spapr_tce_table_realize;
|
||||||
dc->reset = spapr_tce_reset;
|
dc->reset = spapr_tce_reset;
|
||||||
|
dc->unrealize = spapr_tce_table_unrealize;
|
||||||
|
|
||||||
QLIST_INIT(&spapr_tce_tables);
|
QLIST_INIT(&spapr_tce_tables);
|
||||||
|
|
||||||
@@ -434,7 +435,6 @@ static TypeInfo spapr_tce_table_info = {
|
|||||||
.parent = TYPE_DEVICE,
|
.parent = TYPE_DEVICE,
|
||||||
.instance_size = sizeof(sPAPRTCETable),
|
.instance_size = sizeof(sPAPRTCETable),
|
||||||
.class_init = spapr_tce_table_class_init,
|
.class_init = spapr_tce_table_class_init,
|
||||||
.instance_finalize = spapr_tce_table_finalize,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
|
@@ -341,7 +341,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
|
/* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
|
||||||
spapr_msi_setmsg(pdev, spapr->msi_win_addr, ret_intr_type == RTAS_TYPE_MSIX,
|
spapr_msi_setmsg(pdev, SPAPR_PCI_MSI_WINDOW, ret_intr_type == RTAS_TYPE_MSIX,
|
||||||
irq, req_num);
|
irq, req_num);
|
||||||
|
|
||||||
/* Add MSI device to cache */
|
/* Add MSI device to cache */
|
||||||
@@ -465,34 +465,6 @@ static const MemoryRegionOps spapr_msi_ops = {
|
|||||||
.endianness = DEVICE_LITTLE_ENDIAN
|
.endianness = DEVICE_LITTLE_ENDIAN
|
||||||
};
|
};
|
||||||
|
|
||||||
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
|
|
||||||
{
|
|
||||||
uint64_t window_size = 4096;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
|
|
||||||
* we need to allocate some memory to catch those writes coming
|
|
||||||
* from msi_notify()/msix_notify().
|
|
||||||
* As MSIMessage:addr is going to be the same and MSIMessage:data
|
|
||||||
* is going to be a VIRQ number, 4 bytes of the MSI MR will only
|
|
||||||
* be used.
|
|
||||||
*
|
|
||||||
* For KVM we want to ensure that this memory is a full page so that
|
|
||||||
* our memory slot is of page size granularity.
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_KVM
|
|
||||||
if (kvm_enabled()) {
|
|
||||||
window_size = getpagesize();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
spapr->msi_win_addr = addr;
|
|
||||||
memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
|
|
||||||
"msi", window_size);
|
|
||||||
memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
|
|
||||||
&spapr->msiwindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PHB PCI device
|
* PHB PCI device
|
||||||
*/
|
*/
|
||||||
@@ -512,6 +484,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
|||||||
char *namebuf;
|
char *namebuf;
|
||||||
int i;
|
int i;
|
||||||
PCIBus *bus;
|
PCIBus *bus;
|
||||||
|
uint64_t msi_window_size = 4096;
|
||||||
|
|
||||||
if (sphb->index != -1) {
|
if (sphb->index != -1) {
|
||||||
hwaddr windows_base;
|
hwaddr windows_base;
|
||||||
@@ -604,6 +577,28 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
|||||||
address_space_init(&sphb->iommu_as, &sphb->iommu_root,
|
address_space_init(&sphb->iommu_as, &sphb->iommu_root,
|
||||||
sphb->dtbusname);
|
sphb->dtbusname);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
|
||||||
|
* we need to allocate some memory to catch those writes coming
|
||||||
|
* from msi_notify()/msix_notify().
|
||||||
|
* As MSIMessage:addr is going to be the same and MSIMessage:data
|
||||||
|
* is going to be a VIRQ number, 4 bytes of the MSI MR will only
|
||||||
|
* be used.
|
||||||
|
*
|
||||||
|
* For KVM we want to ensure that this memory is a full page so that
|
||||||
|
* our memory slot is of page size granularity.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_KVM
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
msi_window_size = getpagesize();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memory_region_init_io(&sphb->msiwindow, NULL, &spapr_msi_ops, spapr,
|
||||||
|
"msi", msi_window_size);
|
||||||
|
memory_region_add_subregion(&sphb->iommu_root, SPAPR_PCI_MSI_WINDOW,
|
||||||
|
&sphb->msiwindow);
|
||||||
|
|
||||||
pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb);
|
pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb);
|
||||||
|
|
||||||
pci_bus_set_route_irq_fn(bus, spapr_route_intx_pin_to_irq);
|
pci_bus_set_route_irq_fn(bus, spapr_route_intx_pin_to_irq);
|
||||||
@@ -705,28 +700,34 @@ static const VMStateDescription vmstate_spapr_pci_msi = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void spapr_pci_fill_msi_devs(gpointer key, gpointer value,
|
||||||
|
gpointer opaque)
|
||||||
|
{
|
||||||
|
sPAPRPHBState *sphb = opaque;
|
||||||
|
|
||||||
|
sphb->msi_devs[sphb->msi_devs_num].key = *(uint32_t *)key;
|
||||||
|
sphb->msi_devs[sphb->msi_devs_num].value = *(spapr_pci_msi *)value;
|
||||||
|
sphb->msi_devs_num++;
|
||||||
|
}
|
||||||
|
|
||||||
static void spapr_pci_pre_save(void *opaque)
|
static void spapr_pci_pre_save(void *opaque)
|
||||||
{
|
{
|
||||||
sPAPRPHBState *sphb = opaque;
|
sPAPRPHBState *sphb = opaque;
|
||||||
GHashTableIter iter;
|
int msi_devs_num;
|
||||||
gpointer key, value;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (sphb->msi_devs) {
|
if (sphb->msi_devs) {
|
||||||
g_free(sphb->msi_devs);
|
g_free(sphb->msi_devs);
|
||||||
sphb->msi_devs = NULL;
|
sphb->msi_devs = NULL;
|
||||||
}
|
}
|
||||||
sphb->msi_devs_num = g_hash_table_size(sphb->msi);
|
sphb->msi_devs_num = 0;
|
||||||
if (!sphb->msi_devs_num) {
|
msi_devs_num = g_hash_table_size(sphb->msi);
|
||||||
|
if (!msi_devs_num) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sphb->msi_devs = g_malloc(sphb->msi_devs_num * sizeof(spapr_pci_msi_mig));
|
sphb->msi_devs = g_malloc(msi_devs_num * sizeof(spapr_pci_msi_mig));
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, sphb->msi);
|
g_hash_table_foreach(sphb->msi, spapr_pci_fill_msi_devs, sphb);
|
||||||
for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
|
assert(sphb->msi_devs_num == msi_devs_num);
|
||||||
sphb->msi_devs[i].key = *(uint32_t *) key;
|
|
||||||
sphb->msi_devs[i].value = *(spapr_pci_msi *) value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spapr_pci_post_load(void *opaque, int version_id)
|
static int spapr_pci_post_load(void *opaque, int version_id)
|
||||||
|
@@ -161,6 +161,8 @@ static void s390_virtio_net_instance_init(Object *obj)
|
|||||||
VirtIONetS390 *dev = VIRTIO_NET_S390(obj);
|
VirtIONetS390 *dev = VIRTIO_NET_S390(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s390_virtio_blk_init(VirtIOS390Device *s390_dev)
|
static int s390_virtio_blk_init(VirtIOS390Device *s390_dev)
|
||||||
@@ -224,6 +226,8 @@ static void s390_virtio_serial_instance_init(Object *obj)
|
|||||||
VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(obj);
|
VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev)
|
static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev)
|
||||||
@@ -256,6 +260,8 @@ static void s390_virtio_scsi_instance_init(Object *obj)
|
|||||||
VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(obj);
|
VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_VHOST_SCSI
|
#ifdef CONFIG_VHOST_SCSI
|
||||||
@@ -277,6 +283,8 @@ static void s390_vhost_scsi_instance_init(Object *obj)
|
|||||||
VHostSCSIS390 *dev = VHOST_SCSI_S390(obj);
|
VHostSCSIS390 *dev = VHOST_SCSI_S390(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -303,6 +311,8 @@ static void s390_virtio_rng_instance_init(Object *obj)
|
|||||||
VirtIORNGS390 *dev = VIRTIO_RNG_S390(obj);
|
VirtIORNGS390 *dev = VIRTIO_RNG_S390(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||||
(Object **)&dev->vdev.conf.rng,
|
(Object **)&dev->vdev.conf.rng,
|
||||||
qdev_prop_allow_set_link_before_realize,
|
qdev_prop_allow_set_link_before_realize,
|
||||||
@@ -493,10 +503,8 @@ static unsigned virtio_s390_get_features(DeviceState *d)
|
|||||||
/**************** S390 Virtio Bus Device Descriptions *******************/
|
/**************** S390 Virtio Bus Device Descriptions *******************/
|
||||||
|
|
||||||
static Property s390_virtio_net_properties[] = {
|
static Property s390_virtio_net_properties[] = {
|
||||||
DEFINE_NIC_PROPERTIES(VirtIONetS390, vdev.nic_conf),
|
|
||||||
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
|
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
|
||||||
DEFINE_VIRTIO_NET_FEATURES(VirtIOS390Device, host_features),
|
DEFINE_VIRTIO_NET_FEATURES(VirtIOS390Device, host_features),
|
||||||
DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetS390, vdev.net_conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -533,7 +541,6 @@ static const TypeInfo s390_virtio_blk = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static Property s390_virtio_serial_properties[] = {
|
static Property s390_virtio_serial_properties[] = {
|
||||||
DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerialS390, vdev.serial),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -556,7 +563,6 @@ static const TypeInfo s390_virtio_serial = {
|
|||||||
|
|
||||||
static Property s390_virtio_rng_properties[] = {
|
static Property s390_virtio_rng_properties[] = {
|
||||||
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
|
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
|
||||||
DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGS390, vdev.conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -614,7 +620,6 @@ static const TypeInfo virtio_s390_device_info = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static Property s390_virtio_scsi_properties[] = {
|
static Property s390_virtio_scsi_properties[] = {
|
||||||
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIS390, vdev.parent_obj.conf),
|
|
||||||
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
|
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
|
||||||
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOS390Device, host_features),
|
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOS390Device, host_features),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
@@ -640,7 +645,6 @@ static const TypeInfo s390_virtio_scsi = {
|
|||||||
#ifdef CONFIG_VHOST_SCSI
|
#ifdef CONFIG_VHOST_SCSI
|
||||||
static Property s390_vhost_scsi_properties[] = {
|
static Property s390_vhost_scsi_properties[] = {
|
||||||
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
|
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
|
||||||
DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSIS390, vdev.parent_obj.conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -794,6 +794,8 @@ static void virtio_ccw_net_instance_init(Object *obj)
|
|||||||
VirtIONetCcw *dev = VIRTIO_NET_CCW(obj);
|
VirtIONetCcw *dev = VIRTIO_NET_CCW(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev)
|
static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev)
|
||||||
@@ -850,6 +852,8 @@ static void virtio_ccw_serial_instance_init(Object *obj)
|
|||||||
VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj);
|
VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev)
|
static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev)
|
||||||
@@ -896,7 +900,7 @@ static void virtio_ccw_balloon_instance_init(Object *obj)
|
|||||||
VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj);
|
VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
object_property_add(obj, "guest-stats", "guest statistics",
|
object_property_add(obj, "guest-stats", "guest statistics",
|
||||||
balloon_ccw_stats_get_all, NULL, NULL, dev, NULL);
|
balloon_ccw_stats_get_all, NULL, NULL, dev, NULL);
|
||||||
|
|
||||||
@@ -936,6 +940,8 @@ static void virtio_ccw_scsi_instance_init(Object *obj)
|
|||||||
VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj);
|
VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_VHOST_SCSI
|
#ifdef CONFIG_VHOST_SCSI
|
||||||
@@ -957,6 +963,8 @@ static void vhost_ccw_scsi_instance_init(Object *obj)
|
|||||||
VHostSCSICcw *dev = VHOST_SCSI_CCW(obj);
|
VHostSCSICcw *dev = VHOST_SCSI_CCW(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1374,8 +1382,6 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
|
|||||||
static Property virtio_ccw_net_properties[] = {
|
static Property virtio_ccw_net_properties[] = {
|
||||||
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
||||||
DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
|
DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
|
||||||
DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetCcw, vdev.net_conf),
|
|
||||||
DEFINE_NIC_PROPERTIES(VirtIONetCcw, vdev.nic_conf),
|
|
||||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
@@ -1428,7 +1434,6 @@ static const TypeInfo virtio_ccw_blk = {
|
|||||||
|
|
||||||
static Property virtio_ccw_serial_properties[] = {
|
static Property virtio_ccw_serial_properties[] = {
|
||||||
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
||||||
DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtioSerialCcw, vdev.serial),
|
|
||||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
@@ -1481,7 +1486,6 @@ static const TypeInfo virtio_ccw_balloon = {
|
|||||||
|
|
||||||
static Property virtio_ccw_scsi_properties[] = {
|
static Property virtio_ccw_scsi_properties[] = {
|
||||||
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
||||||
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
|
|
||||||
DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
|
DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
|
||||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||||
@@ -1510,7 +1514,6 @@ static const TypeInfo virtio_ccw_scsi = {
|
|||||||
#ifdef CONFIG_VHOST_SCSI
|
#ifdef CONFIG_VHOST_SCSI
|
||||||
static Property vhost_ccw_scsi_properties[] = {
|
static Property vhost_ccw_scsi_properties[] = {
|
||||||
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
||||||
DEFINE_VHOST_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1539,6 +1542,8 @@ static void virtio_ccw_rng_instance_init(Object *obj)
|
|||||||
VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj);
|
VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||||
(Object **)&dev->vdev.conf.rng,
|
(Object **)&dev->vdev.conf.rng,
|
||||||
qdev_prop_allow_set_link_before_realize,
|
qdev_prop_allow_set_link_before_realize,
|
||||||
@@ -1547,7 +1552,6 @@ static void virtio_ccw_rng_instance_init(Object *obj)
|
|||||||
|
|
||||||
static Property virtio_ccw_rng_properties[] = {
|
static Property virtio_ccw_rng_properties[] = {
|
||||||
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
|
||||||
DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGCcw, vdev.conf),
|
|
||||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
@@ -268,6 +268,8 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
|
|||||||
/* update status registers */
|
/* update status registers */
|
||||||
pci->dma_regs[DMA_WBC] -= len;
|
pci->dma_regs[DMA_WBC] -= len;
|
||||||
pci->dma_regs[DMA_WAC] += len;
|
pci->dma_regs[DMA_WAC] += len;
|
||||||
|
if (pci->dma_regs[DMA_WBC] == 0)
|
||||||
|
pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
|
static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
#include "hw/virtio/vhost.h"
|
#include "hw/virtio/vhost.h"
|
||||||
#include "hw/virtio/virtio-scsi.h"
|
#include "hw/virtio/virtio-scsi.h"
|
||||||
#include "hw/virtio/virtio-bus.h"
|
#include "hw/virtio/virtio-bus.h"
|
||||||
|
#include "hw/virtio/virtio-access.h"
|
||||||
|
|
||||||
/* Features supported by host kernel. */
|
/* Features supported by host kernel. */
|
||||||
static const int kernel_feature_bits[] = {
|
static const int kernel_feature_bits[] = {
|
||||||
@@ -163,8 +164,8 @@ static void vhost_scsi_set_config(VirtIODevice *vdev,
|
|||||||
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
|
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
|
||||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
||||||
|
|
||||||
if ((uint32_t) ldl_p(&scsiconf->sense_size) != vs->sense_size ||
|
if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size ||
|
||||||
(uint32_t) ldl_p(&scsiconf->cdb_size) != vs->cdb_size) {
|
(uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) {
|
||||||
error_report("vhost-scsi does not support changing the sense data and CDB sizes");
|
error_report("vhost-scsi does not support changing the sense data and CDB sizes");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -238,6 +239,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
|||||||
s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
|
s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
|
||||||
s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
|
s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
|
||||||
s->dev.vq_index = 0;
|
s->dev.vq_index = 0;
|
||||||
|
s->dev.backend_features = 0;
|
||||||
|
|
||||||
ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
|
ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
|
||||||
VHOST_BACKEND_TYPE_KERNEL, true);
|
VHOST_BACKEND_TYPE_KERNEL, true);
|
||||||
@@ -246,7 +248,6 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
|||||||
strerror(-ret));
|
strerror(-ret));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s->dev.backend_features = 0;
|
|
||||||
|
|
||||||
error_setg(&s->migration_blocker,
|
error_setg(&s->migration_blocker,
|
||||||
"vhost-scsi does not support migration");
|
"vhost-scsi does not support migration");
|
||||||
|
@@ -135,6 +135,7 @@ static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov,
|
|||||||
static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
|
static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
|
||||||
unsigned req_size, unsigned resp_size)
|
unsigned req_size, unsigned resp_size)
|
||||||
{
|
{
|
||||||
|
VirtIODevice *vdev = (VirtIODevice *) req->dev;
|
||||||
size_t in_size, out_size;
|
size_t in_size, out_size;
|
||||||
|
|
||||||
if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
|
if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
|
||||||
@@ -147,8 +148,24 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
|
|||||||
resp_size) < resp_size) {
|
resp_size) < resp_size) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
req->resp_size = resp_size;
|
req->resp_size = resp_size;
|
||||||
|
|
||||||
|
/* Old BIOSes left some padding by mistake after the req_size/resp_size.
|
||||||
|
* As a workaround, always consider the first buffer as the virtio-scsi
|
||||||
|
* request/response, making the payload start at the second element
|
||||||
|
* of the iovec.
|
||||||
|
*
|
||||||
|
* The actual length of the response header, stored in req->resp_size,
|
||||||
|
* does not change.
|
||||||
|
*
|
||||||
|
* TODO: always disable this workaround for virtio 1.0 devices.
|
||||||
|
*/
|
||||||
|
if ((vdev->guest_features & VIRTIO_F_ANY_LAYOUT) == 0) {
|
||||||
|
req_size = req->elem.out_sg[0].iov_len;
|
||||||
|
resp_size = req->elem.in_sg[0].iov_len;
|
||||||
|
}
|
||||||
|
|
||||||
out_size = qemu_sgl_concat(req, req->elem.out_sg,
|
out_size = qemu_sgl_concat(req, req->elem.out_sg,
|
||||||
&req->elem.out_addr[0], req->elem.out_num,
|
&req->elem.out_addr[0], req->elem.out_num,
|
||||||
req_size);
|
req_size);
|
||||||
@@ -400,7 +417,7 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
|||||||
sense_len = scsi_req_get_sense(r, sense, sizeof(sense));
|
sense_len = scsi_req_get_sense(r, sense, sizeof(sense));
|
||||||
sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd));
|
sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd));
|
||||||
qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd),
|
qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd),
|
||||||
&req->resp, sense_len);
|
sense, sense_len);
|
||||||
req->resp.cmd.sense_len = virtio_tswap32(vdev, sense_len);
|
req->resp.cmd.sense_len = virtio_tswap32(vdev, sense_len);
|
||||||
}
|
}
|
||||||
virtio_scsi_complete_cmd_req(req);
|
virtio_scsi_complete_cmd_req(req);
|
||||||
|
@@ -499,6 +499,7 @@ enum xhci_flags {
|
|||||||
XHCI_FLAG_USE_MSI = 1,
|
XHCI_FLAG_USE_MSI = 1,
|
||||||
XHCI_FLAG_USE_MSI_X,
|
XHCI_FLAG_USE_MSI_X,
|
||||||
XHCI_FLAG_SS_FIRST,
|
XHCI_FLAG_SS_FIRST,
|
||||||
|
XHCI_FLAG_FORCE_PCIE_ENDCAP,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||||
@@ -3626,7 +3627,8 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
|
|||||||
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
|
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
|
||||||
&xhci->mem);
|
&xhci->mem);
|
||||||
|
|
||||||
if (pci_bus_is_express(dev->bus)) {
|
if (pci_bus_is_express(dev->bus) ||
|
||||||
|
xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) {
|
||||||
ret = pcie_endpoint_cap_init(dev, 0xa0);
|
ret = pcie_endpoint_cap_init(dev, 0xa0);
|
||||||
assert(ret >= 0);
|
assert(ret >= 0);
|
||||||
}
|
}
|
||||||
@@ -3818,6 +3820,8 @@ static Property xhci_properties[] = {
|
|||||||
DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
|
DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
|
||||||
DEFINE_PROP_BIT("superspeed-ports-first",
|
DEFINE_PROP_BIT("superspeed-ports-first",
|
||||||
XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
|
XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
|
||||||
|
DEFINE_PROP_BIT("force-pcie-endcap", XHCIState, flags,
|
||||||
|
XHCI_FLAG_FORCE_PCIE_ENDCAP, false),
|
||||||
DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
|
DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
|
||||||
DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
|
DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
|
||||||
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
|
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
|
||||||
|
@@ -976,7 +976,6 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||||||
bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n)
|
bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n)
|
||||||
{
|
{
|
||||||
struct vhost_virtqueue *vq = hdev->vqs + n - hdev->vq_index;
|
struct vhost_virtqueue *vq = hdev->vqs + n - hdev->vq_index;
|
||||||
assert(hdev->started);
|
|
||||||
assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
|
assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
|
||||||
return event_notifier_test_and_clear(&vq->masked_notifier);
|
return event_notifier_test_and_clear(&vq->masked_notifier);
|
||||||
}
|
}
|
||||||
@@ -988,7 +987,6 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
|
|||||||
struct VirtQueue *vvq = virtio_get_queue(vdev, n);
|
struct VirtQueue *vvq = virtio_get_queue(vdev, n);
|
||||||
int r, index = n - hdev->vq_index;
|
int r, index = n - hdev->vq_index;
|
||||||
|
|
||||||
assert(hdev->started);
|
|
||||||
assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
|
assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
|
||||||
|
|
||||||
struct vhost_vring_file file = {
|
struct vhost_vring_file file = {
|
||||||
|
@@ -87,7 +87,7 @@ static void balloon_stats_destroy_timer(VirtIOBalloon *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void balloon_stats_change_timer(VirtIOBalloon *s, int secs)
|
static void balloon_stats_change_timer(VirtIOBalloon *s, int64_t secs)
|
||||||
{
|
{
|
||||||
timer_mod(s->stats_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + secs * 1000);
|
timer_mod(s->stats_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + secs * 1000);
|
||||||
}
|
}
|
||||||
@@ -170,6 +170,11 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value > UINT_MAX) {
|
||||||
|
error_setg(errp, "timer value is too big");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (value == s->stats_poll_interval) {
|
if (value == s->stats_poll_interval) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -314,6 +314,16 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Linux before 2.6.34 drives the device without enabling
|
||||||
|
the PCI device bus master bit. Enable it automatically
|
||||||
|
for the guest. This is a PCI spec violation but so is
|
||||||
|
initiating DMA with bus master bit clear. */
|
||||||
|
if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
|
||||||
|
pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
|
||||||
|
proxy->pci_dev.config[PCI_COMMAND] |
|
||||||
|
PCI_COMMAND_MASTER, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Linux before 2.6.34 sets the device as OK without enabling
|
/* Linux before 2.6.34 sets the device as OK without enabling
|
||||||
the PCI device bus master bit. In this case we need to disable
|
the PCI device bus master bit. In this case we need to disable
|
||||||
some safety checks. */
|
some safety checks. */
|
||||||
@@ -914,7 +924,6 @@ static Property virtio_9p_pci_properties[] = {
|
|||||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
||||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||||
DEFINE_VIRTIO_9P_PROPERTIES(V9fsPCIState, vdev.fsconf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -938,6 +947,8 @@ static void virtio_9p_pci_instance_init(Object *obj)
|
|||||||
V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
|
V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_9P);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_9P);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo virtio_9p_pci_info = {
|
static const TypeInfo virtio_9p_pci_info = {
|
||||||
@@ -1127,7 +1138,6 @@ static Property virtio_scsi_pci_properties[] = {
|
|||||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
||||||
DEV_NVECTORS_UNSPECIFIED),
|
DEV_NVECTORS_UNSPECIFIED),
|
||||||
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
|
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
|
||||||
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.parent_obj.conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1179,6 +1189,8 @@ static void virtio_scsi_pci_instance_init(Object *obj)
|
|||||||
VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
|
VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo virtio_scsi_pci_info = {
|
static const TypeInfo virtio_scsi_pci_info = {
|
||||||
@@ -1195,7 +1207,6 @@ static const TypeInfo virtio_scsi_pci_info = {
|
|||||||
static Property vhost_scsi_pci_properties[] = {
|
static Property vhost_scsi_pci_properties[] = {
|
||||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
||||||
DEV_NVECTORS_UNSPECIFIED),
|
DEV_NVECTORS_UNSPECIFIED),
|
||||||
DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSIPCI, vdev.parent_obj.conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1235,6 +1246,8 @@ static void vhost_scsi_pci_instance_init(Object *obj)
|
|||||||
VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
|
VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo vhost_scsi_pci_info = {
|
static const TypeInfo vhost_scsi_pci_info = {
|
||||||
@@ -1315,7 +1328,7 @@ static void virtio_balloon_pci_instance_init(Object *obj)
|
|||||||
VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
|
VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
object_property_add(obj, "guest-stats", "guest statistics",
|
object_property_add(obj, "guest-stats", "guest statistics",
|
||||||
balloon_pci_stats_get_all, NULL, NULL, dev,
|
balloon_pci_stats_get_all, NULL, NULL, dev,
|
||||||
NULL);
|
NULL);
|
||||||
@@ -1377,7 +1390,6 @@ static Property virtio_serial_pci_properties[] = {
|
|||||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||||
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
|
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
|
||||||
DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerialPCI, vdev.serial),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1400,6 +1412,8 @@ static void virtio_serial_pci_instance_init(Object *obj)
|
|||||||
VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
|
VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo virtio_serial_pci_info = {
|
static const TypeInfo virtio_serial_pci_info = {
|
||||||
@@ -1417,8 +1431,6 @@ static Property virtio_net_properties[] = {
|
|||||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
|
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
|
||||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
|
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
|
||||||
DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
|
DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
|
||||||
DEFINE_NIC_PROPERTIES(VirtIONetPCI, vdev.nic_conf),
|
|
||||||
DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetPCI, vdev.net_conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1459,6 +1471,8 @@ static void virtio_net_pci_instance_init(Object *obj)
|
|||||||
VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
|
VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo virtio_net_pci_info = {
|
static const TypeInfo virtio_net_pci_info = {
|
||||||
@@ -1472,7 +1486,6 @@ static const TypeInfo virtio_net_pci_info = {
|
|||||||
/* virtio-rng-pci */
|
/* virtio-rng-pci */
|
||||||
|
|
||||||
static Property virtio_rng_pci_properties[] = {
|
static Property virtio_rng_pci_properties[] = {
|
||||||
DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORngPCI, vdev.conf),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1514,6 +1527,8 @@ static void virtio_rng_initfn(Object *obj)
|
|||||||
VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
|
VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
|
qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
|
||||||
|
object_unref(OBJECT(&dev->vdev));
|
||||||
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||||
(Object **)&dev->vdev.conf.rng,
|
(Object **)&dev->vdev.conf.rng,
|
||||||
qdev_prop_allow_set_link_before_realize,
|
qdev_prop_allow_set_link_before_realize,
|
||||||
|
@@ -325,7 +325,8 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine)
|
|||||||
} else {
|
} else {
|
||||||
hwaddr ep;
|
hwaddr ep;
|
||||||
int is_linux;
|
int is_linux;
|
||||||
success = load_uimage(kernel_filename, &ep, NULL, &is_linux);
|
success = load_uimage(kernel_filename, &ep, NULL, &is_linux,
|
||||||
|
translate_phys_addr, cpu);
|
||||||
if (success > 0 && is_linux) {
|
if (success > 0 && is_linux) {
|
||||||
entry_point = ep;
|
entry_point = ep;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -395,6 +395,14 @@ struct BlockDriverState {
|
|||||||
Error *backing_blocker;
|
Error *backing_blocker;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Essential block drivers which must always be statically linked into qemu, and
|
||||||
|
* which therefore can be accessed without using bdrv_find_format() */
|
||||||
|
extern BlockDriver bdrv_file;
|
||||||
|
extern BlockDriver bdrv_raw;
|
||||||
|
extern BlockDriver bdrv_qcow2;
|
||||||
|
|
||||||
|
|
||||||
int get_tmp_filename(char *filename, int size);
|
int get_tmp_filename(char *filename, int size);
|
||||||
|
|
||||||
void bdrv_set_io_limits(BlockDriverState *bs,
|
void bdrv_set_io_limits(BlockDriverState *bs,
|
||||||
|
@@ -49,6 +49,21 @@ static inline bool cpu_physical_memory_get_dirty(ram_addr_t start,
|
|||||||
return next < end;
|
return next < end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool cpu_physical_memory_get_clean(ram_addr_t start,
|
||||||
|
ram_addr_t length,
|
||||||
|
unsigned client)
|
||||||
|
{
|
||||||
|
unsigned long end, page, next;
|
||||||
|
|
||||||
|
assert(client < DIRTY_MEMORY_NUM);
|
||||||
|
|
||||||
|
end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
|
||||||
|
page = start >> TARGET_PAGE_BITS;
|
||||||
|
next = find_next_zero_bit(ram_list.dirty_memory[client], end, page);
|
||||||
|
|
||||||
|
return next < end;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool cpu_physical_memory_get_dirty_flag(ram_addr_t addr,
|
static inline bool cpu_physical_memory_get_dirty_flag(ram_addr_t addr,
|
||||||
unsigned client)
|
unsigned client)
|
||||||
{
|
{
|
||||||
@@ -64,6 +79,16 @@ static inline bool cpu_physical_memory_is_clean(ram_addr_t addr)
|
|||||||
return !(vga && code && migration);
|
return !(vga && code && migration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool cpu_physical_memory_range_includes_clean(ram_addr_t start,
|
||||||
|
ram_addr_t length)
|
||||||
|
{
|
||||||
|
bool vga = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA);
|
||||||
|
bool code = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE);
|
||||||
|
bool migration =
|
||||||
|
cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION);
|
||||||
|
return vga || code || migration;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
|
static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
|
||||||
unsigned client)
|
unsigned client)
|
||||||
{
|
{
|
||||||
|
@@ -32,7 +32,7 @@
|
|||||||
#define ACPI_MEMORY_HOTPLUG_IO_LEN 24
|
#define ACPI_MEMORY_HOTPLUG_IO_LEN 24
|
||||||
#define ACPI_MEMORY_HOTPLUG_BASE 0x0a00
|
#define ACPI_MEMORY_HOTPLUG_BASE 0x0a00
|
||||||
|
|
||||||
#define MEMORY_HOPTLUG_DEVICE MHPD
|
#define MEMORY_HOTPLUG_DEVICE MHPD
|
||||||
#define MEMORY_SLOTS_NUMBER MDNR
|
#define MEMORY_SLOTS_NUMBER MDNR
|
||||||
#define MEMORY_HOTPLUG_IO_REGION HPMR
|
#define MEMORY_HOTPLUG_IO_REGION HPMR
|
||||||
#define MEMORY_SLOT_ADDR_LOW MRBL
|
#define MEMORY_SLOT_ADDR_LOW MRBL
|
||||||
|
@@ -177,6 +177,8 @@ void pc_acpi_init(const char *default_dsdt);
|
|||||||
PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
|
PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
|
||||||
ram_addr_t above_4g_mem_size);
|
ram_addr_t above_4g_mem_size);
|
||||||
|
|
||||||
|
void pc_set_legacy_acpi_data_size(void);
|
||||||
|
|
||||||
#define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start"
|
#define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start"
|
||||||
#define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end"
|
#define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end"
|
||||||
#define PCI_HOST_PROP_PCI_HOLE64_START "pci-hole64-start"
|
#define PCI_HOST_PROP_PCI_HOLE64_START "pci-hole64-start"
|
||||||
@@ -315,6 +317,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
|
|||||||
.property = "superspeed-ports-first",\
|
.property = "superspeed-ports-first",\
|
||||||
.value = "off",\
|
.value = "off",\
|
||||||
},\
|
},\
|
||||||
|
{\
|
||||||
|
.driver = "nec-usb-xhci",\
|
||||||
|
.property = "force-pcie-endcap",\
|
||||||
|
.value = "on",\
|
||||||
|
},\
|
||||||
{\
|
{\
|
||||||
.driver = "pci-serial",\
|
.driver = "pci-serial",\
|
||||||
.property = "prog_if",\
|
.property = "prog_if",\
|
||||||
|
@@ -28,7 +28,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
|||||||
int load_aout(const char *filename, hwaddr addr, int max_sz,
|
int load_aout(const char *filename, hwaddr addr, int max_sz,
|
||||||
int bswap_needed, hwaddr target_page_size);
|
int bswap_needed, hwaddr target_page_size);
|
||||||
int load_uimage(const char *filename, hwaddr *ep,
|
int load_uimage(const char *filename, hwaddr *ep,
|
||||||
hwaddr *loadaddr, int *is_linux);
|
hwaddr *loadaddr, int *is_linux,
|
||||||
|
uint64_t (*translate_fn)(void *, uint64_t),
|
||||||
|
void *translate_opaque);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* load_ramdisk:
|
* load_ramdisk:
|
||||||
|
@@ -70,7 +70,7 @@ struct sPAPRPHBState {
|
|||||||
|
|
||||||
MemoryRegion memspace, iospace;
|
MemoryRegion memspace, iospace;
|
||||||
hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
|
hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
|
||||||
MemoryRegion memwindow, iowindow;
|
MemoryRegion memwindow, iowindow, msiwindow;
|
||||||
|
|
||||||
uint32_t dma_liobn;
|
uint32_t dma_liobn;
|
||||||
AddressSpace iommu_as;
|
AddressSpace iommu_as;
|
||||||
|
@@ -13,8 +13,6 @@ struct sPAPRNVRAM;
|
|||||||
typedef struct sPAPREnvironment {
|
typedef struct sPAPREnvironment {
|
||||||
struct VIOsPAPRBus *vio_bus;
|
struct VIOsPAPRBus *vio_bus;
|
||||||
QLIST_HEAD(, sPAPRPHBState) phbs;
|
QLIST_HEAD(, sPAPRPHBState) phbs;
|
||||||
hwaddr msi_win_addr;
|
|
||||||
MemoryRegion msiwindow;
|
|
||||||
struct sPAPRNVRAM *nvram;
|
struct sPAPRNVRAM *nvram;
|
||||||
XICSState *icp;
|
XICSState *icp;
|
||||||
|
|
||||||
|
@@ -55,6 +55,8 @@ struct Visitor
|
|||||||
void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp);
|
void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp);
|
||||||
/* visit_type_size() falls back to (*type_uint64)() if type_size is unset */
|
/* visit_type_size() falls back to (*type_uint64)() if type_size is unset */
|
||||||
void (*type_size)(Visitor *v, uint64_t *obj, const char *name, Error **errp);
|
void (*type_size)(Visitor *v, uint64_t *obj, const char *name, Error **errp);
|
||||||
|
bool (*start_union)(Visitor *v, bool data_present, Error **errp);
|
||||||
|
void (*end_union)(Visitor *v, bool data_present, Error **errp);
|
||||||
};
|
};
|
||||||
|
|
||||||
void input_type_enum(Visitor *v, int *obj, const char *strings[],
|
void input_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||||
|
@@ -58,5 +58,7 @@ void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp);
|
|||||||
void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
|
void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
|
||||||
void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
|
void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
|
||||||
void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
|
void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
|
||||||
|
bool visit_start_union(Visitor *v, bool data_present, Error **errp);
|
||||||
|
void visit_end_union(Visitor *v, bool data_present, Error **errp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -122,11 +122,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef atomic_read
|
#ifndef atomic_read
|
||||||
#define atomic_read(ptr) (*(__typeof__(*ptr) *volatile) (ptr))
|
#define atomic_read(ptr) (*(__typeof__(*ptr) volatile*) (ptr))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef atomic_set
|
#ifndef atomic_set
|
||||||
#define atomic_set(ptr, i) ((*(__typeof__(*ptr) *volatile) (ptr)) = (i))
|
#define atomic_set(ptr, i) ((*(__typeof__(*ptr) volatile*) (ptr)) = (i))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* These have the same semantics as Java volatile variables.
|
/* These have the same semantics as Java volatile variables.
|
||||||
|
@@ -10,6 +10,7 @@ void cpu_stop_current(void);
|
|||||||
void cpu_synchronize_all_states(void);
|
void cpu_synchronize_all_states(void);
|
||||||
void cpu_synchronize_all_post_reset(void);
|
void cpu_synchronize_all_post_reset(void);
|
||||||
void cpu_synchronize_all_post_init(void);
|
void cpu_synchronize_all_post_init(void);
|
||||||
|
void cpu_clean_all_dirty(void);
|
||||||
|
|
||||||
void qtest_clock_warp(int64_t dest);
|
void qtest_clock_warp(int64_t dest);
|
||||||
|
|
||||||
|
@@ -348,6 +348,7 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr,
|
|||||||
void kvm_cpu_synchronize_state(CPUState *cpu);
|
void kvm_cpu_synchronize_state(CPUState *cpu);
|
||||||
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
|
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
|
||||||
void kvm_cpu_synchronize_post_init(CPUState *cpu);
|
void kvm_cpu_synchronize_post_init(CPUState *cpu);
|
||||||
|
void kvm_cpu_clean_state(CPUState *cpu);
|
||||||
|
|
||||||
/* generic hooks - to be moved/refactored once there are more users */
|
/* generic hooks - to be moved/refactored once there are more users */
|
||||||
|
|
||||||
@@ -372,6 +373,13 @@ static inline void cpu_synchronize_post_init(CPUState *cpu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void cpu_clean_state(CPUState *cpu)
|
||||||
|
{
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
kvm_cpu_clean_state(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
|
int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
|
||||||
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
|
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
|
||||||
void kvm_irqchip_release_virq(KVMState *s, int virq);
|
void kvm_irqchip_release_virq(KVMState *s, int virq);
|
||||||
|
11
kvm-all.c
11
kvm-all.c
@@ -617,8 +617,10 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add)
|
|||||||
unsigned delta;
|
unsigned delta;
|
||||||
|
|
||||||
/* kvm works in page size chunks, but the function may be called
|
/* kvm works in page size chunks, but the function may be called
|
||||||
with sub-page size and unaligned start address. */
|
with sub-page size and unaligned start address. Pad the start
|
||||||
delta = TARGET_PAGE_ALIGN(size) - size;
|
address to next and truncate size to previous page boundary. */
|
||||||
|
delta = (TARGET_PAGE_SIZE - (start_addr & ~TARGET_PAGE_MASK));
|
||||||
|
delta &= ~TARGET_PAGE_MASK;
|
||||||
if (delta > size) {
|
if (delta > size) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1681,6 +1683,11 @@ void kvm_cpu_synchronize_post_init(CPUState *cpu)
|
|||||||
cpu->kvm_vcpu_dirty = false;
|
cpu->kvm_vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kvm_cpu_clean_state(CPUState *cpu)
|
||||||
|
{
|
||||||
|
cpu->kvm_vcpu_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
int kvm_cpu_exec(CPUState *cpu)
|
int kvm_cpu_exec(CPUState *cpu)
|
||||||
{
|
{
|
||||||
struct kvm_run *run = cpu->kvm_run;
|
struct kvm_run *run = cpu->kvm_run;
|
||||||
|
@@ -115,6 +115,7 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
|
|||||||
VCardAppletPrivate *applet_private;
|
VCardAppletPrivate *applet_private;
|
||||||
int size, next;
|
int size, next;
|
||||||
unsigned char *sign_buffer;
|
unsigned char *sign_buffer;
|
||||||
|
bool retain_sign_buffer = FALSE;
|
||||||
vcard_7816_status_t status;
|
vcard_7816_status_t status;
|
||||||
VCardStatus ret = VCARD_FAIL;
|
VCardStatus ret = VCARD_FAIL;
|
||||||
|
|
||||||
@@ -178,6 +179,7 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
|
|||||||
pki_applet->sign_buffer = sign_buffer;
|
pki_applet->sign_buffer = sign_buffer;
|
||||||
pki_applet->sign_buffer_len = size;
|
pki_applet->sign_buffer_len = size;
|
||||||
*response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
|
*response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
|
||||||
|
retain_sign_buffer = TRUE;
|
||||||
break;
|
break;
|
||||||
case 0x00:
|
case 0x00:
|
||||||
/* we now have the whole buffer, do the operation, result will be
|
/* we now have the whole buffer, do the operation, result will be
|
||||||
@@ -200,9 +202,11 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
|
|||||||
VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
|
VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
g_free(sign_buffer);
|
if (!retain_sign_buffer) {
|
||||||
pki_applet->sign_buffer = NULL;
|
g_free(sign_buffer);
|
||||||
pki_applet->sign_buffer_len = 0;
|
pki_applet->sign_buffer = NULL;
|
||||||
|
pki_applet->sign_buffer_len = 0;
|
||||||
|
}
|
||||||
ret = VCARD_DONE;
|
ret = VCARD_DONE;
|
||||||
break;
|
break;
|
||||||
case CAC_READ_BUFFER:
|
case CAC_READ_BUFFER:
|
||||||
|
@@ -597,7 +597,7 @@ connect_to_qemu(
|
|||||||
const char *port
|
const char *port
|
||||||
) {
|
) {
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
struct addrinfo *server;
|
struct addrinfo *server = NULL;
|
||||||
int ret, sock;
|
int ret, sock;
|
||||||
|
|
||||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
@@ -629,9 +629,14 @@ connect_to_qemu(
|
|||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader));
|
printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(server);
|
||||||
return sock;
|
return sock;
|
||||||
|
|
||||||
cleanup_socket:
|
cleanup_socket:
|
||||||
|
if (server) {
|
||||||
|
freeaddrinfo(server);
|
||||||
|
}
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@@ -5243,6 +5243,7 @@ static void monitor_event(void *opaque, int event)
|
|||||||
monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
|
monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
|
||||||
"information\n", QEMU_VERSION);
|
"information\n", QEMU_VERSION);
|
||||||
if (!mon->mux_out) {
|
if (!mon->mux_out) {
|
||||||
|
readline_restart(mon->rs);
|
||||||
readline_show_prompt(mon->rs);
|
readline_show_prompt(mon->rs);
|
||||||
}
|
}
|
||||||
mon->reset_seen = 1;
|
mon->reset_seen = 1;
|
||||||
|
@@ -660,7 +660,6 @@ int net_init_l2tpv3(const NetClientOptions *opts,
|
|||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
fd = -errno;
|
fd = -errno;
|
||||||
error_report("l2tpv3_open : socket creation failed, errno = %d", -fd);
|
error_report("l2tpv3_open : socket creation failed, errno = %d", -fd);
|
||||||
freeaddrinfo(result);
|
|
||||||
goto outerr;
|
goto outerr;
|
||||||
}
|
}
|
||||||
if (bind(fd, (struct sockaddr *) result->ai_addr, result->ai_addrlen)) {
|
if (bind(fd, (struct sockaddr *) result->ai_addr, result->ai_addrlen)) {
|
||||||
|
40
net/net.c
40
net/net.c
@@ -41,12 +41,14 @@
|
|||||||
#include "qapi-visit.h"
|
#include "qapi-visit.h"
|
||||||
#include "qapi/opts-visitor.h"
|
#include "qapi/opts-visitor.h"
|
||||||
#include "qapi/dealloc-visitor.h"
|
#include "qapi/dealloc-visitor.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
|
||||||
/* Net bridge is currently not supported for W32. */
|
/* Net bridge is currently not supported for W32. */
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
# define CONFIG_NET_BRIDGE
|
# define CONFIG_NET_BRIDGE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static VMChangeStateEntry *net_change_state_entry;
|
||||||
static QTAILQ_HEAD(, NetClientState) net_clients;
|
static QTAILQ_HEAD(, NetClientState) net_clients;
|
||||||
|
|
||||||
const char *host_net_devices[] = {
|
const char *host_net_devices[] = {
|
||||||
@@ -452,6 +454,12 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
|
|||||||
|
|
||||||
int qemu_can_send_packet(NetClientState *sender)
|
int qemu_can_send_packet(NetClientState *sender)
|
||||||
{
|
{
|
||||||
|
int vm_running = runstate_is_running();
|
||||||
|
|
||||||
|
if (!vm_running) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sender->peer) {
|
if (!sender->peer) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -504,7 +512,8 @@ void qemu_purge_queued_packets(NetClientState *nc)
|
|||||||
qemu_net_queue_purge(nc->peer->incoming_queue, nc);
|
qemu_net_queue_purge(nc->peer->incoming_queue, nc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_flush_queued_packets(NetClientState *nc)
|
static
|
||||||
|
void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge)
|
||||||
{
|
{
|
||||||
nc->receive_disabled = 0;
|
nc->receive_disabled = 0;
|
||||||
|
|
||||||
@@ -518,9 +527,17 @@ void qemu_flush_queued_packets(NetClientState *nc)
|
|||||||
* the file descriptor (for tap, for example).
|
* the file descriptor (for tap, for example).
|
||||||
*/
|
*/
|
||||||
qemu_notify_event();
|
qemu_notify_event();
|
||||||
|
} else if (purge) {
|
||||||
|
/* Unable to empty the queue, purge remaining packets */
|
||||||
|
qemu_net_queue_purge(nc->incoming_queue, nc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qemu_flush_queued_packets(NetClientState *nc)
|
||||||
|
{
|
||||||
|
qemu_flush_or_purge_queued_packets(nc, false);
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
|
static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
|
||||||
unsigned flags,
|
unsigned flags,
|
||||||
const uint8_t *buf, int size,
|
const uint8_t *buf, int size,
|
||||||
@@ -1168,6 +1185,22 @@ void qmp_set_link(const char *name, bool up, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void net_vm_change_state_handler(void *opaque, int running,
|
||||||
|
RunState state)
|
||||||
|
{
|
||||||
|
/* Complete all queued packets, to guarantee we don't modify
|
||||||
|
* state later when VM is not running.
|
||||||
|
*/
|
||||||
|
if (!running) {
|
||||||
|
NetClientState *nc;
|
||||||
|
NetClientState *tmp;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) {
|
||||||
|
qemu_flush_or_purge_queued_packets(nc, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void net_cleanup(void)
|
void net_cleanup(void)
|
||||||
{
|
{
|
||||||
NetClientState *nc;
|
NetClientState *nc;
|
||||||
@@ -1183,6 +1216,8 @@ void net_cleanup(void)
|
|||||||
qemu_del_net_client(nc);
|
qemu_del_net_client(nc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_del_vm_change_state_handler(net_change_state_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void net_check_clients(void)
|
void net_check_clients(void)
|
||||||
@@ -1268,6 +1303,9 @@ int net_init_clients(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
net_change_state_entry =
|
||||||
|
qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL);
|
||||||
|
|
||||||
QTAILQ_INIT(&net_clients);
|
QTAILQ_INIT(&net_clients);
|
||||||
|
|
||||||
if (qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1) == -1)
|
if (qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1) == -1)
|
||||||
|
@@ -233,6 +233,9 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
|
|||||||
if (packet->sender == from) {
|
if (packet->sender == from) {
|
||||||
QTAILQ_REMOVE(&queue->packets, packet, entry);
|
QTAILQ_REMOVE(&queue->packets, packet, entry);
|
||||||
queue->nq_count--;
|
queue->nq_count--;
|
||||||
|
if (packet->sent_cb) {
|
||||||
|
packet->sent_cb(packet->sender, 0);
|
||||||
|
}
|
||||||
g_free(packet);
|
g_free(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
numa.c
4
numa.c
@@ -210,8 +210,8 @@ void set_numa_nodes(void)
|
|||||||
numa_total += numa_info[i].node_mem;
|
numa_total += numa_info[i].node_mem;
|
||||||
}
|
}
|
||||||
if (numa_total != ram_size) {
|
if (numa_total != ram_size) {
|
||||||
error_report("total memory for NUMA nodes (%" PRIu64 ")"
|
error_report("total memory for NUMA nodes (0x%" PRIx64 ")"
|
||||||
" should equal RAM size (" RAM_ADDR_FMT ")",
|
" should equal RAM size (0x" RAM_ADDR_FMT ")",
|
||||||
numa_total, ram_size);
|
numa_total, ram_size);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@@ -76,14 +76,71 @@ boot_kernel:
|
|||||||
|
|
||||||
|
|
||||||
copy_kernel:
|
copy_kernel:
|
||||||
|
/* Read info block in low memory (0x10000 or 0x90000) */
|
||||||
|
read_fw FW_CFG_SETUP_ADDR
|
||||||
|
shr $4, %eax
|
||||||
|
mov %eax, %es
|
||||||
|
xor %edi, %edi
|
||||||
|
read_fw_blob_addr32_edi(FW_CFG_SETUP)
|
||||||
|
|
||||||
|
cmpw $0x203, %es:0x206 // if protocol >= 0x203
|
||||||
|
jae 1f // have initrd_max
|
||||||
|
movl $0x37ffffff, %es:0x22c // else assume 0x37ffffff
|
||||||
|
1:
|
||||||
|
|
||||||
|
/* Check if using kernel-specified initrd address */
|
||||||
|
read_fw FW_CFG_INITRD_ADDR
|
||||||
|
mov %eax, %edi // (load_kernel wants it in %edi)
|
||||||
|
read_fw FW_CFG_INITRD_SIZE // find end of initrd
|
||||||
|
add %edi, %eax
|
||||||
|
xor %es:0x22c, %eax // if it matches es:0x22c
|
||||||
|
and $-4096, %eax // (apart from padding for page)
|
||||||
|
jz load_kernel // then initrd is not at top
|
||||||
|
// of memory
|
||||||
|
|
||||||
|
/* pc.c placed the initrd at end of memory. Compute a better
|
||||||
|
* initrd address based on e801 data.
|
||||||
|
*/
|
||||||
|
mov $0xe801, %ax
|
||||||
|
xor %cx, %cx
|
||||||
|
xor %dx, %dx
|
||||||
|
int $0x15
|
||||||
|
|
||||||
|
/* Output could be in AX/BX or CX/DX */
|
||||||
|
or %cx, %cx
|
||||||
|
jnz 1f
|
||||||
|
or %dx, %dx
|
||||||
|
jnz 1f
|
||||||
|
mov %ax, %cx
|
||||||
|
mov %bx, %dx
|
||||||
|
1:
|
||||||
|
|
||||||
|
or %dx, %dx
|
||||||
|
jnz 2f
|
||||||
|
addw $1024, %cx /* add 1 MB */
|
||||||
|
movzwl %cx, %edi
|
||||||
|
shll $10, %edi /* convert to bytes */
|
||||||
|
jmp 3f
|
||||||
|
|
||||||
|
2:
|
||||||
|
addw $16777216 >> 16, %dx /* add 16 MB */
|
||||||
|
movzwl %dx, %edi
|
||||||
|
shll $16, %edi /* convert to bytes */
|
||||||
|
|
||||||
|
3:
|
||||||
|
read_fw FW_CFG_INITRD_SIZE
|
||||||
|
subl %eax, %edi
|
||||||
|
andl $-4096, %edi /* EDI = start of initrd */
|
||||||
|
movl %edi, %es:0x218 /* put it in the header */
|
||||||
|
|
||||||
|
load_kernel:
|
||||||
/* We need to load the kernel into memory we can't access in 16 bit
|
/* We need to load the kernel into memory we can't access in 16 bit
|
||||||
mode, so let's get into 32 bit mode, write the kernel and jump
|
mode, so let's get into 32 bit mode, write the kernel and jump
|
||||||
back again. */
|
back again. */
|
||||||
|
|
||||||
/* Reserve space on the stack for our GDT descriptor. */
|
/* Reserve space on the stack for our GDT descriptor. */
|
||||||
mov %esp, %ebp
|
mov %esp, %ebp
|
||||||
sub $16, %esp
|
sub $16, %esp
|
||||||
|
|
||||||
/* Now create the GDT descriptor */
|
/* Now create the GDT descriptor */
|
||||||
movw $((3 * 8) - 1), -16(%bp)
|
movw $((3 * 8) - 1), -16(%bp)
|
||||||
@@ -108,10 +165,9 @@ copy_kernel:
|
|||||||
/* We're now running in 16-bit CS, but 32-bit ES! */
|
/* We're now running in 16-bit CS, but 32-bit ES! */
|
||||||
|
|
||||||
/* Load kernel and initrd */
|
/* Load kernel and initrd */
|
||||||
|
read_fw_blob_addr32_edi(FW_CFG_INITRD)
|
||||||
read_fw_blob_addr32(FW_CFG_KERNEL)
|
read_fw_blob_addr32(FW_CFG_KERNEL)
|
||||||
read_fw_blob_addr32(FW_CFG_INITRD)
|
|
||||||
read_fw_blob_addr32(FW_CFG_CMDLINE)
|
read_fw_blob_addr32(FW_CFG_CMDLINE)
|
||||||
read_fw_blob_addr32(FW_CFG_SETUP)
|
|
||||||
|
|
||||||
/* And now jump into Linux! */
|
/* And now jump into Linux! */
|
||||||
mov $0, %eax
|
mov $0, %eax
|
||||||
|
@@ -51,8 +51,6 @@
|
|||||||
.endm
|
.endm
|
||||||
|
|
||||||
#define read_fw_blob_pre(var) \
|
#define read_fw_blob_pre(var) \
|
||||||
read_fw var ## _ADDR; \
|
|
||||||
mov %eax, %edi; \
|
|
||||||
read_fw var ## _SIZE; \
|
read_fw var ## _SIZE; \
|
||||||
mov %eax, %ecx; \
|
mov %eax, %ecx; \
|
||||||
mov $var ## _DATA, %ax; \
|
mov $var ## _DATA, %ax; \
|
||||||
@@ -68,6 +66,8 @@
|
|||||||
* Clobbers: %eax, %edx, %es, %ecx, %edi
|
* Clobbers: %eax, %edx, %es, %ecx, %edi
|
||||||
*/
|
*/
|
||||||
#define read_fw_blob(var) \
|
#define read_fw_blob(var) \
|
||||||
|
read_fw var ## _ADDR; \
|
||||||
|
mov %eax, %edi; \
|
||||||
read_fw_blob_pre(var); \
|
read_fw_blob_pre(var); \
|
||||||
/* old as(1) doesn't like this insn so emit the bytes instead: \
|
/* old as(1) doesn't like this insn so emit the bytes instead: \
|
||||||
rep insb (%dx), %es:(%edi); \
|
rep insb (%dx), %es:(%edi); \
|
||||||
@@ -80,7 +80,22 @@
|
|||||||
*
|
*
|
||||||
* Clobbers: %eax, %edx, %es, %ecx, %edi
|
* Clobbers: %eax, %edx, %es, %ecx, %edi
|
||||||
*/
|
*/
|
||||||
#define read_fw_blob_addr32(var) \
|
#define read_fw_blob_addr32(var) \
|
||||||
|
read_fw var ## _ADDR; \
|
||||||
|
mov %eax, %edi; \
|
||||||
|
read_fw_blob_pre(var); \
|
||||||
|
/* old as(1) doesn't like this insn so emit the bytes instead: \
|
||||||
|
addr32 rep insb (%dx), %es:(%edi); \
|
||||||
|
*/ \
|
||||||
|
.dc.b 0x67,0xf3,0x6c
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a blob from the fw_cfg device in forced addr32 mode, address is in %edi.
|
||||||
|
* Requires _SIZE and _DATA values for the parameter.
|
||||||
|
*
|
||||||
|
* Clobbers: %eax, %edx, %edi, %es, %ecx
|
||||||
|
*/
|
||||||
|
#define read_fw_blob_addr32_edi(var) \
|
||||||
read_fw_blob_pre(var); \
|
read_fw_blob_pre(var); \
|
||||||
/* old as(1) doesn't like this insn so emit the bytes instead: \
|
/* old as(1) doesn't like this insn so emit the bytes instead: \
|
||||||
addr32 rep insb (%dx), %es:(%edi); \
|
addr32 rep insb (%dx), %es:(%edi); \
|
||||||
|
@@ -162,6 +162,31 @@ static void qapi_dealloc_type_enum(Visitor *v, int *obj, const char *strings[],
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If there's no data present, the dealloc visitor has nothing to free.
|
||||||
|
* Thus, indicate to visitor code that the subsequent union fields can
|
||||||
|
* be skipped. This is not an error condition, since the cleanup of the
|
||||||
|
* rest of an object can continue unhindered, so leave errp unset in
|
||||||
|
* these cases.
|
||||||
|
*
|
||||||
|
* NOTE: In cases where we're attempting to deallocate an object that
|
||||||
|
* may have missing fields, the field indicating the union type may
|
||||||
|
* be missing. In such a case, it's possible we don't have enough
|
||||||
|
* information to differentiate data_present == false from a case where
|
||||||
|
* data *is* present but happens to be a scalar with a value of 0.
|
||||||
|
* This is okay, since in the case of the dealloc visitor there's no
|
||||||
|
* work that needs to done in either situation.
|
||||||
|
*
|
||||||
|
* The current inability in QAPI code to more thoroughly verify a union
|
||||||
|
* type in such cases will likely need to be addressed if we wish to
|
||||||
|
* implement this interface for other types of visitors in the future,
|
||||||
|
* however.
|
||||||
|
*/
|
||||||
|
static bool qapi_dealloc_start_union(Visitor *v, bool data_present,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return data_present;
|
||||||
|
}
|
||||||
|
|
||||||
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
|
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
|
||||||
{
|
{
|
||||||
return &v->visitor;
|
return &v->visitor;
|
||||||
@@ -191,6 +216,7 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
|
|||||||
v->visitor.type_str = qapi_dealloc_type_str;
|
v->visitor.type_str = qapi_dealloc_type_str;
|
||||||
v->visitor.type_number = qapi_dealloc_type_number;
|
v->visitor.type_number = qapi_dealloc_type_number;
|
||||||
v->visitor.type_size = qapi_dealloc_type_size;
|
v->visitor.type_size = qapi_dealloc_type_size;
|
||||||
|
v->visitor.start_union = qapi_dealloc_start_union;
|
||||||
|
|
||||||
QTAILQ_INIT(&v->stack);
|
QTAILQ_INIT(&v->stack);
|
||||||
|
|
||||||
|
@@ -58,6 +58,21 @@ void visit_end_list(Visitor *v, Error **errp)
|
|||||||
v->end_list(v, errp);
|
v->end_list(v, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool visit_start_union(Visitor *v, bool data_present, Error **errp)
|
||||||
|
{
|
||||||
|
if (v->start_union) {
|
||||||
|
return v->start_union(v, data_present, errp);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_end_union(Visitor *v, bool data_present, Error **errp)
|
||||||
|
{
|
||||||
|
if (v->end_union) {
|
||||||
|
v->end_union(v, data_present, errp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void visit_optional(Visitor *v, bool *present, const char *name,
|
void visit_optional(Visitor *v, bool *present, const char *name,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
@@ -182,9 +182,10 @@ static const char *find_typename_by_alias(const char *alias)
|
|||||||
|
|
||||||
int qdev_device_help(QemuOpts *opts)
|
int qdev_device_help(QemuOpts *opts)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
const char *driver;
|
const char *driver;
|
||||||
Property *prop;
|
DevicePropertyInfoList *prop_list;
|
||||||
ObjectClass *klass;
|
DevicePropertyInfoList *prop;
|
||||||
|
|
||||||
driver = qemu_opt_get(opts, "driver");
|
driver = qemu_opt_get(opts, "driver");
|
||||||
if (driver && is_help_option(driver)) {
|
if (driver && is_help_option(driver)) {
|
||||||
@@ -196,35 +197,28 @@ int qdev_device_help(QemuOpts *opts)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
klass = object_class_by_name(driver);
|
if (!object_class_by_name(driver)) {
|
||||||
if (!klass) {
|
|
||||||
const char *typename = find_typename_by_alias(driver);
|
const char *typename = find_typename_by_alias(driver);
|
||||||
|
|
||||||
if (typename) {
|
if (typename) {
|
||||||
driver = typename;
|
driver = typename;
|
||||||
klass = object_class_by_name(driver);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!object_class_dynamic_cast(klass, TYPE_DEVICE)) {
|
prop_list = qmp_device_list_properties(driver, &local_err);
|
||||||
return 0;
|
if (!prop_list) {
|
||||||
|
error_printf("%s\n", error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
do {
|
|
||||||
for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
|
for (prop = prop_list; prop; prop = prop->next) {
|
||||||
/*
|
error_printf("%s.%s=%s\n", driver,
|
||||||
* TODO Properties without a parser are just for dirty hacks.
|
prop->value->name,
|
||||||
* qdev_prop_ptr is the only such PropertyInfo. It's marked
|
prop->value->type);
|
||||||
* for removal. This conditional should be removed along with
|
}
|
||||||
* it.
|
|
||||||
*/
|
qapi_free_DevicePropertyInfoList(prop_list);
|
||||||
if (!prop->info->set) {
|
|
||||||
continue; /* no way to set it, don't show */
|
|
||||||
}
|
|
||||||
error_printf("%s.%s=%s\n", driver, prop->name,
|
|
||||||
prop->info->legacy_name ?: prop->info->name);
|
|
||||||
}
|
|
||||||
klass = object_class_get_parent(klass);
|
|
||||||
} while (klass != object_class_by_name(TYPE_DEVICE));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1160,7 +1160,9 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
|||||||
if (!s->connected) {
|
if (!s->connected) {
|
||||||
/* guest sends data, check for (re-)connect */
|
/* guest sends data, check for (re-)connect */
|
||||||
pty_chr_update_read_handler_locked(chr);
|
pty_chr_update_read_handler_locked(chr);
|
||||||
return 0;
|
if (!s->connected) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return io_channel_send(s->fd, buf, len);
|
return io_channel_send(s->fd, buf, len);
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user