Compare commits
50 Commits
pull-docs-
...
v2.5.1
Author | SHA1 | Date | |
---|---|---|---|
|
a58047f7fb | ||
|
5f409b108f | ||
|
078de11898 | ||
|
acea76c162 | ||
|
80b6e5723f | ||
|
9bddb45dbc | ||
|
e3a2cdfcb5 | ||
|
4dcd2f13b1 | ||
|
38e09211b6 | ||
|
d0ee85b4e4 | ||
|
4f046a6ba1 | ||
|
b47809c6b3 | ||
|
24fe899c3c | ||
|
aaf4fb6afb | ||
|
a2ae168821 | ||
|
bad094d524 | ||
|
4b0b1ec8e0 | ||
|
cab1cc7245 | ||
|
9ae02175b4 | ||
|
30929793b0 | ||
|
c5c9841ce8 | ||
|
6b62303eb8 | ||
|
c06f342009 | ||
|
cb873eaa6d | ||
|
4853a5a80f | ||
|
a375e0b03e | ||
|
a38a283fc7 | ||
|
225d50fbb1 | ||
|
020282d3e6 | ||
|
091af18104 | ||
|
d98392379a | ||
|
643c8d8ec1 | ||
|
3ede27db32 | ||
|
9849b1912f | ||
|
fe90bdc25b | ||
|
aaa5271327 | ||
|
abda95cb01 | ||
|
6a49a71cc6 | ||
|
e1a8a09124 | ||
|
7a2c1c8e66 | ||
|
702a8d165c | ||
|
3e96d5dcf2 | ||
|
16a2875735 | ||
|
4588b0d856 | ||
|
ff083d3c3b | ||
|
4d59e78dfe | ||
|
52a7b27947 | ||
|
d4aed70099 | ||
|
42ae4a3c61 | ||
|
0d335804e3 |
24
block.c
24
block.c
@@ -1976,21 +1976,25 @@ void bdrv_close_all(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that bs->device_list.tqe_prev is initially null,
|
||||
* and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish
|
||||
* the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
|
||||
* resetting it to null on remove. */
|
||||
void bdrv_device_remove(BlockDriverState *bs)
|
||||
{
|
||||
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
|
||||
bs->device_list.tqe_prev = NULL;
|
||||
}
|
||||
|
||||
/* make a BlockDriverState anonymous by removing from bdrv_state and
|
||||
* graph_bdrv_state list.
|
||||
Also, NULL terminate the device_name to prevent double remove */
|
||||
void bdrv_make_anon(BlockDriverState *bs)
|
||||
{
|
||||
/*
|
||||
* Take care to remove bs from bdrv_states only when it's actually
|
||||
* in it. Note that bs->device_list.tqe_prev is initially null,
|
||||
* and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish
|
||||
* the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
|
||||
* resetting it to null on remove.
|
||||
*/
|
||||
/* Take care to remove bs from bdrv_states only when it's actually
|
||||
* in it. */
|
||||
if (bs->device_list.tqe_prev) {
|
||||
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
|
||||
bs->device_list.tqe_prev = NULL;
|
||||
bdrv_device_remove(bs);
|
||||
}
|
||||
if (bs->node_name[0] != '\0') {
|
||||
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
|
||||
@@ -2031,7 +2035,7 @@ static void change_parent_backing_link(BlockDriverState *from,
|
||||
if (!to->device_list.tqe_prev) {
|
||||
QTAILQ_INSERT_BEFORE(from, to, device_list);
|
||||
}
|
||||
QTAILQ_REMOVE(&bdrv_states, from, device_list);
|
||||
bdrv_device_remove(from);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -457,6 +457,14 @@ bool blk_dev_has_removable_media(BlockBackend *blk)
|
||||
return !blk->dev || (blk->dev_ops && blk->dev_ops->change_media_cb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Does @blk's attached device model have a tray?
|
||||
*/
|
||||
bool blk_dev_has_tray(BlockBackend *blk)
|
||||
{
|
||||
return blk->dev_ops && blk->dev_ops->is_tray_open;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify @blk's attached device model of a media eject request.
|
||||
* If @force is true, the medium is about to be yanked out forcefully.
|
||||
@@ -473,7 +481,7 @@ void blk_dev_eject_request(BlockBackend *blk, bool force)
|
||||
*/
|
||||
bool blk_dev_is_tray_open(BlockBackend *blk)
|
||||
{
|
||||
if (blk->dev_ops && blk->dev_ops->is_tray_open) {
|
||||
if (blk_dev_has_tray(blk)) {
|
||||
return blk->dev_ops->is_tray_open(blk->dev_opaque);
|
||||
}
|
||||
return false;
|
||||
|
@@ -646,8 +646,9 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
|
||||
}
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bdrv_aio_readv(s->children[i]->bs, acb->sector_num, &acb->qcrs[i].qiov,
|
||||
acb->nb_sectors, quorum_aio_cb, &acb->qcrs[i]);
|
||||
acb->qcrs[i].aiocb = bdrv_aio_readv(s->children[i]->bs, acb->sector_num,
|
||||
&acb->qcrs[i].qiov, acb->nb_sectors,
|
||||
quorum_aio_cb, &acb->qcrs[i]);
|
||||
}
|
||||
|
||||
return &acb->common;
|
||||
@@ -662,9 +663,10 @@ static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb)
|
||||
qemu_iovec_init(&acb->qcrs[acb->child_iter].qiov, acb->qiov->niov);
|
||||
qemu_iovec_clone(&acb->qcrs[acb->child_iter].qiov, acb->qiov,
|
||||
acb->qcrs[acb->child_iter].buf);
|
||||
bdrv_aio_readv(s->children[acb->child_iter]->bs, acb->sector_num,
|
||||
&acb->qcrs[acb->child_iter].qiov, acb->nb_sectors,
|
||||
quorum_aio_cb, &acb->qcrs[acb->child_iter]);
|
||||
acb->qcrs[acb->child_iter].aiocb =
|
||||
bdrv_aio_readv(s->children[acb->child_iter]->bs, acb->sector_num,
|
||||
&acb->qcrs[acb->child_iter].qiov, acb->nb_sectors,
|
||||
quorum_aio_cb, &acb->qcrs[acb->child_iter]);
|
||||
|
||||
return &acb->common;
|
||||
}
|
||||
|
@@ -783,7 +783,6 @@ static int hdev_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
struct hd_geometry ioctl_geo = {0};
|
||||
uint32_t blksize;
|
||||
|
||||
/* If DASD, get its geometry */
|
||||
if (check_for_dasd(s->fd) < 0) {
|
||||
@@ -803,12 +802,6 @@ static int hdev_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
|
||||
}
|
||||
geo->heads = ioctl_geo.heads;
|
||||
geo->sectors = ioctl_geo.sectors;
|
||||
if (!probe_physical_blocksize(s->fd, &blksize)) {
|
||||
/* overwrite cyls: HDIO_GETGEO result is incorrect for big drives */
|
||||
geo->cylinders = bdrv_nb_sectors(bs) / (blksize / BDRV_SECTOR_SIZE)
|
||||
/ (geo->heads * geo->sectors);
|
||||
return 0;
|
||||
}
|
||||
geo->cylinders = ioctl_geo.cylinders;
|
||||
|
||||
return 0;
|
||||
|
14
block/vmdk.c
14
block/vmdk.c
@@ -570,6 +570,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
VmdkExtent *extent;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int64_t l1_backup_offset = 0;
|
||||
bool compressed;
|
||||
|
||||
ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header));
|
||||
if (ret < 0) {
|
||||
@@ -644,6 +645,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
header = footer.header;
|
||||
}
|
||||
|
||||
compressed =
|
||||
le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
|
||||
if (le32_to_cpu(header.version) > 3) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
|
||||
@@ -651,7 +654,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_or_node_name(bs), "vmdk", buf);
|
||||
return -ENOTSUP;
|
||||
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) {
|
||||
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR) &&
|
||||
!compressed) {
|
||||
/* VMware KB 2064959 explains that version 3 added support for
|
||||
* persistent changed block tracking (CBT), and backup software can
|
||||
* read it as version=1 if it doesn't care about the changed area
|
||||
@@ -1654,7 +1658,13 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
}
|
||||
magic = cpu_to_be32(VMDK4_MAGIC);
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.version = zeroed_grain ? 2 : 1;
|
||||
if (compress) {
|
||||
header.version = 3;
|
||||
} else if (zeroed_grain) {
|
||||
header.version = 2;
|
||||
} else {
|
||||
header.version = 1;
|
||||
}
|
||||
header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT
|
||||
| (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0)
|
||||
| (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0);
|
||||
|
34
blockdev.c
34
blockdev.c
@@ -2306,6 +2306,11 @@ void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* Ignore this command on tray-less devices */
|
||||
return;
|
||||
}
|
||||
|
||||
if (blk_dev_is_tray_open(blk)) {
|
||||
return;
|
||||
}
|
||||
@@ -2336,6 +2341,11 @@ void qmp_blockdev_close_tray(const char *device, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* Ignore this command on tray-less devices */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_is_tray_open(blk)) {
|
||||
return;
|
||||
}
|
||||
@@ -2365,7 +2375,7 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_device && !blk_dev_is_tray_open(blk)) {
|
||||
if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
|
||||
error_setg(errp, "Tray of device '%s' is not open", device);
|
||||
return;
|
||||
}
|
||||
@@ -2384,12 +2394,19 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp)
|
||||
|
||||
/* This follows the convention established by bdrv_make_anon() */
|
||||
if (bs->device_list.tqe_prev) {
|
||||
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
|
||||
bs->device_list.tqe_prev = NULL;
|
||||
bdrv_device_remove(bs);
|
||||
}
|
||||
|
||||
blk_remove_bs(blk);
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* For tray-less devices, blockdev-open-tray is a no-op (or may not be
|
||||
* called at all); therefore, the medium needs to be ejected here.
|
||||
* Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
|
||||
* value passed here (i.e. false). */
|
||||
blk_dev_change_media_cb(blk, false);
|
||||
}
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
@@ -2415,7 +2432,7 @@ static void qmp_blockdev_insert_anon_medium(const char *device,
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_device && !blk_dev_is_tray_open(blk)) {
|
||||
if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
|
||||
error_setg(errp, "Tray of device '%s' is not open", device);
|
||||
return;
|
||||
}
|
||||
@@ -2428,6 +2445,15 @@ static void qmp_blockdev_insert_anon_medium(const char *device,
|
||||
blk_insert_bs(blk, bs);
|
||||
|
||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* For tray-less devices, blockdev-close-tray is a no-op (or may not be
|
||||
* called at all); therefore, the medium needs to be pushed into the
|
||||
* slot here.
|
||||
* Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
|
||||
* value passed here (i.e. true). */
|
||||
blk_dev_change_media_cb(blk, true);
|
||||
}
|
||||
}
|
||||
|
||||
void qmp_x_blockdev_insert_medium(const char *device, const char *node_name,
|
||||
|
6
configure
vendored
6
configure
vendored
@@ -4758,7 +4758,11 @@ echo "GTK GL support $gtk_gl"
|
||||
echo "GNUTLS support $gnutls"
|
||||
echo "GNUTLS hash $gnutls_hash"
|
||||
echo "libgcrypt $gcrypt"
|
||||
echo "nettle $nettle ${nettle+($nettle_version)}"
|
||||
if test "$nettle" = "yes"; then
|
||||
echo "nettle $nettle ($nettle_version)"
|
||||
else
|
||||
echo "nettle $nettle"
|
||||
fi
|
||||
echo "libtasn1 $tasn1"
|
||||
echo "VTE support $vte"
|
||||
echo "curses support $curses"
|
||||
|
4
cpus.c
4
cpus.c
@@ -986,7 +986,7 @@ static void qemu_wait_io_event_common(CPUState *cpu)
|
||||
if (cpu->stop) {
|
||||
cpu->stop = false;
|
||||
cpu->stopped = true;
|
||||
qemu_cond_signal(&qemu_pause_cond);
|
||||
qemu_cond_broadcast(&qemu_pause_cond);
|
||||
}
|
||||
flush_queued_work(cpu);
|
||||
cpu->thread_kicked = false;
|
||||
@@ -1387,7 +1387,7 @@ void cpu_stop_current(void)
|
||||
current_cpu->stop = false;
|
||||
current_cpu->stopped = true;
|
||||
cpu_exit(current_cpu);
|
||||
qemu_cond_signal(&qemu_pause_cond);
|
||||
qemu_cond_broadcast(&qemu_pause_cond);
|
||||
}
|
||||
}
|
||||
|
||||
|
18
hmp.c
18
hmp.c
@@ -1734,21 +1734,18 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict)
|
||||
int has_hold_time = qdict_haskey(qdict, "hold-time");
|
||||
int hold_time = qdict_get_try_int(qdict, "hold-time", -1);
|
||||
Error *err = NULL;
|
||||
char keyname_buf[16];
|
||||
char *separator;
|
||||
int keyname_len;
|
||||
|
||||
while (1) {
|
||||
separator = strchr(keys, '-');
|
||||
keyname_len = separator ? separator - keys : strlen(keys);
|
||||
pstrcpy(keyname_buf, sizeof(keyname_buf), keys);
|
||||
|
||||
/* Be compatible with old interface, convert user inputted "<" */
|
||||
if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) {
|
||||
pstrcpy(keyname_buf, sizeof(keyname_buf), "less");
|
||||
if (keys[0] == '<' && keyname_len == 1) {
|
||||
keys = "less";
|
||||
keyname_len = 4;
|
||||
}
|
||||
keyname_buf[keyname_len] = 0;
|
||||
|
||||
keylist = g_malloc0(sizeof(*keylist));
|
||||
keylist->value = g_malloc0(sizeof(*keylist->value));
|
||||
@@ -1761,16 +1758,17 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict)
|
||||
}
|
||||
tmp = keylist;
|
||||
|
||||
if (strstart(keyname_buf, "0x", NULL)) {
|
||||
if (strstart(keys, "0x", NULL)) {
|
||||
char *endp;
|
||||
int value = strtoul(keyname_buf, &endp, 0);
|
||||
if (*endp != '\0') {
|
||||
int value = strtoul(keys, &endp, 0);
|
||||
assert(endp <= keys + keyname_len);
|
||||
if (endp != keys + keyname_len) {
|
||||
goto err_out;
|
||||
}
|
||||
keylist->value->type = KEY_VALUE_KIND_NUMBER;
|
||||
keylist->value->u.number = value;
|
||||
} else {
|
||||
int idx = index_from_key(keyname_buf);
|
||||
int idx = index_from_key(keys, keyname_len);
|
||||
if (idx == Q_KEY_CODE_MAX) {
|
||||
goto err_out;
|
||||
}
|
||||
@@ -1792,7 +1790,7 @@ out:
|
||||
return;
|
||||
|
||||
err_out:
|
||||
monitor_printf(mon, "invalid parameter: %s\n", keyname_buf);
|
||||
monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@@ -36,6 +36,6 @@ static int coroutine_enter_func(void *arg)
|
||||
void co_run_in_worker_bh(void *opaque)
|
||||
{
|
||||
Coroutine *co = opaque;
|
||||
thread_pool_submit_aio(qemu_get_aio_context()->thread_pool,
|
||||
thread_pool_submit_aio(aio_get_thread_pool(qemu_get_aio_context()),
|
||||
coroutine_enter_func, co, coroutine_enter_cb, co);
|
||||
}
|
||||
|
@@ -85,8 +85,10 @@ static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_reque
|
||||
d->nr_sectors = s->nr_sectors;
|
||||
return;
|
||||
}
|
||||
if (n > src->nr_segments)
|
||||
n = src->nr_segments;
|
||||
/* prevent the compiler from optimizing the code and using src->nr_segments instead */
|
||||
barrier();
|
||||
if (n > dst->nr_segments)
|
||||
n = dst->nr_segments;
|
||||
for (i = 0; i < n; i++)
|
||||
dst->seg[i] = src->seg[i];
|
||||
}
|
||||
@@ -106,8 +108,10 @@ static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_reque
|
||||
d->nr_sectors = s->nr_sectors;
|
||||
return;
|
||||
}
|
||||
if (n > src->nr_segments)
|
||||
n = src->nr_segments;
|
||||
/* prevent the compiler from optimizing the code and using src->nr_segments instead */
|
||||
barrier();
|
||||
if (n > dst->nr_segments)
|
||||
n = dst->nr_segments;
|
||||
for (i = 0; i < n; i++)
|
||||
dst->seg[i] = src->seg[i];
|
||||
}
|
||||
|
@@ -283,6 +283,21 @@ static bool machine_get_suppress_vmdesc(Object *obj, Error **errp)
|
||||
return ms->suppress_vmdesc;
|
||||
}
|
||||
|
||||
static void machine_set_enforce_config_section(Object *obj, bool value,
|
||||
Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->enforce_config_section = value;
|
||||
}
|
||||
|
||||
static bool machine_get_enforce_config_section(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return ms->enforce_config_section;
|
||||
}
|
||||
|
||||
static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
||||
{
|
||||
error_report("Option '-device %s' cannot be handled by this machine",
|
||||
@@ -437,6 +452,12 @@ static void machine_initfn(Object *obj)
|
||||
object_property_set_description(obj, "suppress-vmdesc",
|
||||
"Set on to disable self-describing migration",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "enforce-config-section",
|
||||
machine_get_enforce_config_section,
|
||||
machine_set_enforce_config_section, NULL);
|
||||
object_property_set_description(obj, "enforce-config-section",
|
||||
"Set on to enforce configuration section migration",
|
||||
NULL);
|
||||
|
||||
/* Register notifier when init is done for sysbus sanity checks */
|
||||
ms->sysbus_notifier.notify = machine_init_notify;
|
||||
|
@@ -784,18 +784,20 @@ static void xenfb_invalidate(void *opaque)
|
||||
|
||||
static void xenfb_handle_events(struct XenFB *xenfb)
|
||||
{
|
||||
uint32_t prod, cons;
|
||||
uint32_t prod, cons, out_cons;
|
||||
struct xenfb_page *page = xenfb->c.page;
|
||||
|
||||
prod = page->out_prod;
|
||||
if (prod == page->out_cons)
|
||||
out_cons = page->out_cons;
|
||||
if (prod == out_cons)
|
||||
return;
|
||||
xen_rmb(); /* ensure we see ring contents up to prod */
|
||||
for (cons = page->out_cons; cons != prod; cons++) {
|
||||
for (cons = out_cons; cons != prod; cons++) {
|
||||
union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
|
||||
uint8_t type = event->type;
|
||||
int x, y, w, h;
|
||||
|
||||
switch (event->type) {
|
||||
switch (type) {
|
||||
case XENFB_TYPE_UPDATE:
|
||||
if (xenfb->up_count == UP_QUEUE)
|
||||
xenfb->up_fullscreen = 1;
|
||||
|
@@ -634,13 +634,18 @@ static int vapic_prepare(VAPICROMState *s)
|
||||
static void vapic_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
{
|
||||
CPUState *cs = current_cpu;
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
CPUX86State *env = &cpu->env;
|
||||
hwaddr rom_paddr;
|
||||
VAPICROMState *s = opaque;
|
||||
X86CPU *cpu;
|
||||
CPUX86State *env;
|
||||
hwaddr rom_paddr;
|
||||
|
||||
cpu_synchronize_state(cs);
|
||||
if (!current_cpu) {
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_synchronize_state(current_cpu);
|
||||
cpu = X86_CPU(current_cpu);
|
||||
env = &cpu->env;
|
||||
|
||||
/*
|
||||
* The VAPIC supports two PIO-based hypercalls, both via port 0x7E.
|
||||
|
@@ -661,6 +661,10 @@ static bool ahci_map_fis_address(AHCIDevice *ad)
|
||||
|
||||
static void ahci_unmap_fis_address(AHCIDevice *ad)
|
||||
{
|
||||
if (ad->res_fis == NULL) {
|
||||
DPRINTF(ad->port_no, "Attempt to unmap NULL FIS address\n");
|
||||
return;
|
||||
}
|
||||
dma_memory_unmap(ad->hba->as, ad->res_fis, 256,
|
||||
DMA_DIRECTION_FROM_DEVICE, 256);
|
||||
ad->res_fis = NULL;
|
||||
@@ -677,6 +681,10 @@ static bool ahci_map_clb_address(AHCIDevice *ad)
|
||||
|
||||
static void ahci_unmap_clb_address(AHCIDevice *ad)
|
||||
{
|
||||
if (ad->lst == NULL) {
|
||||
DPRINTF(ad->port_no, "Attempt to unmap NULL CLB address\n");
|
||||
return;
|
||||
}
|
||||
dma_memory_unmap(ad->hba->as, ad->lst, 1024,
|
||||
DMA_DIRECTION_FROM_DEVICE, 1024);
|
||||
ad->lst = NULL;
|
||||
@@ -910,6 +918,7 @@ static void ncq_err(NCQTransferState *ncq_tfs)
|
||||
ide_state->error = ABRT_ERR;
|
||||
ide_state->status = READY_STAT | ERR_STAT;
|
||||
ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
|
||||
ncq_tfs->used = 0;
|
||||
}
|
||||
|
||||
static void ncq_finish(NCQTransferState *ncq_tfs)
|
||||
|
@@ -350,17 +350,14 @@ static void ivshmem_vector_poll(PCIDevice *dev,
|
||||
}
|
||||
}
|
||||
|
||||
static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n,
|
||||
static CharDriverState* create_eventfd_chr_device(IVShmemState *s,
|
||||
EventNotifier *n,
|
||||
int vector)
|
||||
{
|
||||
/* create a event character device based on the passed eventfd */
|
||||
IVShmemState *s = opaque;
|
||||
PCIDevice *pdev = PCI_DEVICE(s);
|
||||
int eventfd = event_notifier_get_fd(n);
|
||||
CharDriverState *chr;
|
||||
|
||||
s->msi_vectors[vector].pdev = pdev;
|
||||
|
||||
chr = qemu_chr_open_eventfd(eventfd);
|
||||
|
||||
if (chr == NULL) {
|
||||
|
@@ -908,7 +908,8 @@ start_xmit(E1000State *s)
|
||||
* bogus values to TDT/TDLEN.
|
||||
* there's nothing too intelligent we could do about this.
|
||||
*/
|
||||
if (s->mac_reg[TDH] == tdh_start) {
|
||||
if (s->mac_reg[TDH] == tdh_start ||
|
||||
tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) {
|
||||
DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
|
||||
tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
|
||||
break;
|
||||
@@ -1165,7 +1166,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
||||
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
|
||||
s->mac_reg[RDH] = 0;
|
||||
/* see comment in start_xmit; same here */
|
||||
if (s->mac_reg[RDH] == rdh_start) {
|
||||
if (s->mac_reg[RDH] == rdh_start ||
|
||||
rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) {
|
||||
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
|
||||
rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
|
||||
set_ics(s, 0, E1000_ICS_RXO);
|
||||
|
@@ -154,6 +154,10 @@ static int ne2000_buffer_full(NE2000State *s)
|
||||
{
|
||||
int avail, index, boundary;
|
||||
|
||||
if (s->stop <= s->start) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
index = s->curpag << 8;
|
||||
boundary = s->boundary << 8;
|
||||
if (index < boundary)
|
||||
@@ -467,8 +471,9 @@ static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
addr &= ~1; /* XXX: check exact behaviour if not even */
|
||||
if (addr < 32 ||
|
||||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
|
||||
if (addr < 32
|
||||
|| (addr >= NE2000_PMEM_START
|
||||
&& addr + sizeof(uint32_t) <= NE2000_MEM_SIZE)) {
|
||||
stl_le_p(s->mem + addr, val);
|
||||
}
|
||||
}
|
||||
@@ -497,8 +502,9 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
|
||||
static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
|
||||
{
|
||||
addr &= ~1; /* XXX: check exact behaviour if not even */
|
||||
if (addr < 32 ||
|
||||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
|
||||
if (addr < 32
|
||||
|| (addr >= NE2000_PMEM_START
|
||||
&& addr + sizeof(uint32_t) <= NE2000_MEM_SIZE)) {
|
||||
return ldl_le_p(s->mem + addr);
|
||||
} else {
|
||||
return 0xffffffff;
|
||||
|
@@ -232,6 +232,9 @@ static int tx_consume(Rocker *r, DescInfo *info)
|
||||
frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]);
|
||||
frag_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]);
|
||||
|
||||
if (iovcnt >= ROCKER_TX_FRAGS_MAX) {
|
||||
goto err_too_many_frags;
|
||||
}
|
||||
iov[iovcnt].iov_len = frag_len;
|
||||
iov[iovcnt].iov_base = g_malloc(frag_len);
|
||||
if (!iov[iovcnt].iov_base) {
|
||||
@@ -244,10 +247,7 @@ static int tx_consume(Rocker *r, DescInfo *info)
|
||||
err = -ROCKER_ENXIO;
|
||||
goto err_bad_io;
|
||||
}
|
||||
|
||||
if (++iovcnt > ROCKER_TX_FRAGS_MAX) {
|
||||
goto err_too_many_frags;
|
||||
}
|
||||
iovcnt++;
|
||||
}
|
||||
|
||||
if (iovcnt) {
|
||||
|
@@ -300,21 +300,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
|
||||
VirtioBusState *vbus = VIRTIO_BUS(qbus);
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
|
||||
int r, e, i;
|
||||
int r, e, i, j;
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
error_report("binding does not support guest notifiers");
|
||||
r = -ENOSYS;
|
||||
goto err;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
r = vhost_net_set_vnet_endian(dev, ncs[0].peer, true);
|
||||
if (r < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < total_queues; i++) {
|
||||
vhost_net_set_vq_index(get_vhost_net(ncs[i].peer), i * 2);
|
||||
for (j = 0; j < total_queues; j++) {
|
||||
r = vhost_net_set_vnet_endian(dev, ncs[j].peer, true);
|
||||
if (r < 0) {
|
||||
goto err_endian;
|
||||
}
|
||||
vhost_net_set_vq_index(get_vhost_net(ncs[j].peer), j * 2);
|
||||
}
|
||||
|
||||
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
|
||||
@@ -343,8 +341,9 @@ err_start:
|
||||
fflush(stderr);
|
||||
}
|
||||
err_endian:
|
||||
vhost_net_set_vnet_endian(dev, ncs[0].peer, false);
|
||||
err:
|
||||
while (--j >= 0) {
|
||||
vhost_net_set_vnet_endian(dev, ncs[j].peer, false);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@@ -1194,8 +1194,13 @@ static void vmxnet3_reset_mac(VMXNET3State *s)
|
||||
|
||||
static void vmxnet3_deactivate_device(VMXNET3State *s)
|
||||
{
|
||||
VMW_CBPRN("Deactivating vmxnet3...");
|
||||
s->device_active = false;
|
||||
if (s->device_active) {
|
||||
VMW_CBPRN("Deactivating vmxnet3...");
|
||||
vmxnet_tx_pkt_reset(s->tx_pkt);
|
||||
vmxnet_tx_pkt_uninit(s->tx_pkt);
|
||||
vmxnet_rx_pkt_uninit(s->rx_pkt);
|
||||
s->device_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void vmxnet3_reset(VMXNET3State *s)
|
||||
@@ -1204,7 +1209,6 @@ static void vmxnet3_reset(VMXNET3State *s)
|
||||
|
||||
vmxnet3_deactivate_device(s);
|
||||
vmxnet3_reset_interrupt_states(s);
|
||||
vmxnet_tx_pkt_reset(s->tx_pkt);
|
||||
s->drv_shmem = 0;
|
||||
s->tx_sop = true;
|
||||
s->skip_current_tx_pkt = false;
|
||||
@@ -1431,6 +1435,12 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify if device is active */
|
||||
if (s->device_active) {
|
||||
VMW_CFPRN("Vmxnet3 device is active");
|
||||
return;
|
||||
}
|
||||
|
||||
vmxnet3_adjust_by_guest_type(s);
|
||||
vmxnet3_update_features(s);
|
||||
vmxnet3_update_pm_state(s);
|
||||
@@ -1627,7 +1637,7 @@ static void vmxnet3_handle_command(VMXNET3State *s, uint64_t cmd)
|
||||
break;
|
||||
|
||||
case VMXNET3_CMD_QUIESCE_DEV:
|
||||
VMW_CBPRN("Set: VMXNET3_CMD_QUIESCE_DEV - pause the device");
|
||||
VMW_CBPRN("Set: VMXNET3_CMD_QUIESCE_DEV - deactivate the device");
|
||||
vmxnet3_deactivate_device(s);
|
||||
break;
|
||||
|
||||
@@ -1741,7 +1751,7 @@ vmxnet3_io_bar1_write(void *opaque,
|
||||
* shared address only after we get the high part
|
||||
*/
|
||||
if (val == 0) {
|
||||
s->device_active = false;
|
||||
vmxnet3_deactivate_device(s);
|
||||
}
|
||||
s->temp_shared_guest_driver_memory = val;
|
||||
s->drv_shmem = 0;
|
||||
@@ -2021,9 +2031,7 @@ static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s)
|
||||
static void vmxnet3_net_uninit(VMXNET3State *s)
|
||||
{
|
||||
g_free(s->mcast_list);
|
||||
vmxnet_tx_pkt_reset(s->tx_pkt);
|
||||
vmxnet_tx_pkt_uninit(s->tx_pkt);
|
||||
vmxnet_rx_pkt_uninit(s->rx_pkt);
|
||||
vmxnet3_deactivate_device(s);
|
||||
qemu_del_nic(s->nic);
|
||||
}
|
||||
|
||||
|
@@ -270,7 +270,8 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key)
|
||||
static uint8_t fw_cfg_read(FWCfgState *s)
|
||||
{
|
||||
int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
|
||||
FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
|
||||
&s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
uint8_t ret;
|
||||
|
||||
if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
|
||||
@@ -338,7 +339,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
|
||||
}
|
||||
|
||||
arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
|
||||
e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
|
||||
&s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
|
||||
if (dma.control & FW_CFG_DMA_CTL_READ) {
|
||||
read = 1;
|
||||
@@ -780,17 +782,19 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
|
||||
DeviceState *dev;
|
||||
FWCfgState *s;
|
||||
uint32_t version = FW_CFG_VERSION;
|
||||
bool dma_enabled = dma_iobase && dma_as;
|
||||
bool dma_requested = dma_iobase && dma_as;
|
||||
|
||||
dev = qdev_create(NULL, TYPE_FW_CFG_IO);
|
||||
qdev_prop_set_uint32(dev, "iobase", iobase);
|
||||
qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase);
|
||||
qdev_prop_set_bit(dev, "dma_enabled", dma_enabled);
|
||||
if (!dma_requested) {
|
||||
qdev_prop_set_bit(dev, "dma_enabled", false);
|
||||
}
|
||||
|
||||
fw_cfg_init1(dev);
|
||||
s = FW_CFG(dev);
|
||||
|
||||
if (dma_enabled) {
|
||||
if (s->dma_enabled) {
|
||||
/* 64 bits for the address field */
|
||||
s->dma_as = dma_as;
|
||||
s->dma_addr = 0;
|
||||
@@ -816,11 +820,13 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
|
||||
SysBusDevice *sbd;
|
||||
FWCfgState *s;
|
||||
uint32_t version = FW_CFG_VERSION;
|
||||
bool dma_enabled = dma_addr && dma_as;
|
||||
bool dma_requested = dma_addr && dma_as;
|
||||
|
||||
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
|
||||
qdev_prop_set_uint32(dev, "data_width", data_width);
|
||||
qdev_prop_set_bit(dev, "dma_enabled", dma_enabled);
|
||||
if (!dma_requested) {
|
||||
qdev_prop_set_bit(dev, "dma_enabled", false);
|
||||
}
|
||||
|
||||
fw_cfg_init1(dev);
|
||||
|
||||
@@ -830,7 +836,7 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
|
||||
|
||||
s = FW_CFG(dev);
|
||||
|
||||
if (dma_enabled) {
|
||||
if (s->dma_enabled) {
|
||||
s->dma_as = dma_as;
|
||||
s->dma_addr = 0;
|
||||
sysbus_mmio_map(sbd, 2, dma_addr);
|
||||
@@ -875,7 +881,7 @@ static Property fw_cfg_io_properties[] = {
|
||||
DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1),
|
||||
DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1),
|
||||
DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled,
|
||||
false),
|
||||
true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -915,7 +921,7 @@ static const TypeInfo fw_cfg_io_info = {
|
||||
static Property fw_cfg_mem_properties[] = {
|
||||
DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1),
|
||||
DEFINE_PROP_BOOL("dma_enabled", FWCfgMemState, parent_obj.dma_enabled,
|
||||
false),
|
||||
true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@@ -2327,6 +2327,7 @@ static void spapr_compat_2_3(Object *obj)
|
||||
{
|
||||
savevm_skip_section_footers();
|
||||
global_state_set_optional();
|
||||
savevm_skip_configuration();
|
||||
}
|
||||
|
||||
static void spapr_compat_2_2(Object *obj)
|
||||
|
@@ -701,7 +701,7 @@ int css_do_csch(SubchDev *sch)
|
||||
|
||||
/* Trigger the clear function. */
|
||||
s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL);
|
||||
s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_CLEAR_FUNC;
|
||||
s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND;
|
||||
|
||||
do_subchannel_work(sch, NULL);
|
||||
ret = 0;
|
||||
|
@@ -718,7 +718,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
|
||||
BusChild *kid;
|
||||
int num_pd_disks = 0;
|
||||
|
||||
memset(&info, 0x0, cmd->iov_size);
|
||||
memset(&info, 0x0, dcmd_size);
|
||||
if (cmd->iov_size < dcmd_size) {
|
||||
trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
|
||||
dcmd_size);
|
||||
|
@@ -128,9 +128,16 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
||||
}
|
||||
|
||||
usb_packet_copy(p, s->setup_buf, p->iov.size);
|
||||
s->setup_index = 0;
|
||||
p->actual_length = 0;
|
||||
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
||||
s->setup_index = 0;
|
||||
if (s->setup_len > sizeof(s->data_buf)) {
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
s->setup_len, sizeof(s->data_buf));
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
|
||||
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
||||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||
@@ -151,13 +158,6 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
||||
}
|
||||
s->setup_state = SETUP_STATE_DATA;
|
||||
} else {
|
||||
if (s->setup_len > sizeof(s->data_buf)) {
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
s->setup_len, sizeof(s->data_buf));
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
if (s->setup_len == 0)
|
||||
s->setup_state = SETUP_STATE_ACK;
|
||||
else
|
||||
@@ -176,7 +176,7 @@ static void do_token_in(USBDevice *s, USBPacket *p)
|
||||
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
||||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
||||
|
||||
|
||||
switch(s->setup_state) {
|
||||
case SETUP_STATE_ACK:
|
||||
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
||||
|
@@ -653,7 +653,8 @@ typedef struct USBNetState {
|
||||
|
||||
static int is_rndis(USBNetState *s)
|
||||
{
|
||||
return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE;
|
||||
return s->dev.config ?
|
||||
s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE : 0;
|
||||
}
|
||||
|
||||
static int ndis_query(USBNetState *s, uint32_t oid,
|
||||
@@ -914,8 +915,9 @@ static int rndis_query_response(USBNetState *s,
|
||||
|
||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||
if (bufoffs + buflen > length)
|
||||
if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||
return USB_RET_STALL;
|
||||
}
|
||||
|
||||
infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
|
||||
bufoffs + (uint8_t *) buf, buflen, infobuf,
|
||||
@@ -960,8 +962,9 @@ static int rndis_set_response(USBNetState *s,
|
||||
|
||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||
if (bufoffs + buflen > length)
|
||||
if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||
return USB_RET_STALL;
|
||||
}
|
||||
|
||||
ret = ndis_set(s, le32_to_cpu(buf->OID),
|
||||
bufoffs + (uint8_t *) buf, buflen);
|
||||
@@ -1211,8 +1214,9 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
||||
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
|
||||
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
|
||||
uint32_t size = le32_to_cpu(msg->DataLength);
|
||||
if (offs + size <= len)
|
||||
if (offs < len && size < len && offs + size <= len) {
|
||||
qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size);
|
||||
}
|
||||
}
|
||||
s->out_ptr -= len;
|
||||
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
|
||||
|
@@ -865,6 +865,7 @@ void ehci_reset(void *opaque)
|
||||
s->usbsts = USBSTS_HALT;
|
||||
s->usbsts_pending = 0;
|
||||
s->usbsts_frindex = 0;
|
||||
ehci_update_irq(s);
|
||||
|
||||
s->astate = EST_INACTIVE;
|
||||
s->pstate = EST_INACTIVE;
|
||||
@@ -1389,7 +1390,7 @@ static int ehci_process_itd(EHCIState *ehci,
|
||||
{
|
||||
USBDevice *dev;
|
||||
USBEndpoint *ep;
|
||||
uint32_t i, len, pid, dir, devaddr, endp;
|
||||
uint32_t i, len, pid, dir, devaddr, endp, xfers = 0;
|
||||
uint32_t pg, off, ptr1, ptr2, max, mult;
|
||||
|
||||
ehci->periodic_sched_active = PERIODIC_ACTIVE;
|
||||
@@ -1404,21 +1405,23 @@ static int ehci_process_itd(EHCIState *ehci,
|
||||
if (itd->transact[i] & ITD_XACT_ACTIVE) {
|
||||
pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
|
||||
off = itd->transact[i] & ITD_XACT_OFFSET_MASK;
|
||||
ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
|
||||
ptr2 = (itd->bufptr[pg+1] & ITD_BUFPTR_MASK);
|
||||
len = get_field(itd->transact[i], ITD_XACT_LENGTH);
|
||||
|
||||
if (len > max * mult) {
|
||||
len = max * mult;
|
||||
}
|
||||
|
||||
if (len > BUFF_SIZE) {
|
||||
if (len > BUFF_SIZE || pg > 6) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
|
||||
qemu_sglist_init(&ehci->isgl, ehci->device, 2, ehci->as);
|
||||
if (off + len > 4096) {
|
||||
/* transfer crosses page border */
|
||||
if (pg == 6) {
|
||||
return -1; /* avoid page pg + 1 */
|
||||
}
|
||||
ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK);
|
||||
uint32_t len2 = off + len - 4096;
|
||||
uint32_t len1 = len - len2;
|
||||
qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
|
||||
@@ -1479,9 +1482,10 @@ static int ehci_process_itd(EHCIState *ehci,
|
||||
ehci_raise_irq(ehci, USBSTS_INT);
|
||||
}
|
||||
itd->transact[i] &= ~ITD_XACT_ACTIVE;
|
||||
xfers++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return xfers ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -612,6 +612,25 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool vhost_user_can_merge(struct vhost_dev *dev,
|
||||
uint64_t start1, uint64_t size1,
|
||||
uint64_t start2, uint64_t size2)
|
||||
{
|
||||
ram_addr_t ram_addr;
|
||||
int mfd, rfd;
|
||||
MemoryRegion *mr;
|
||||
|
||||
mr = qemu_ram_addr_from_host((void *)(uintptr_t)start1, &ram_addr);
|
||||
assert(mr);
|
||||
mfd = qemu_get_ram_fd(ram_addr);
|
||||
|
||||
mr = qemu_ram_addr_from_host((void *)(uintptr_t)start2, &ram_addr);
|
||||
assert(mr);
|
||||
rfd = qemu_get_ram_fd(ram_addr);
|
||||
|
||||
return mfd == rfd;
|
||||
}
|
||||
|
||||
const VhostOps user_ops = {
|
||||
.backend_type = VHOST_BACKEND_TYPE_USER,
|
||||
.vhost_backend_init = vhost_user_init,
|
||||
@@ -634,4 +653,5 @@ const VhostOps user_ops = {
|
||||
.vhost_set_vring_enable = vhost_user_set_vring_enable,
|
||||
.vhost_requires_shm_log = vhost_user_requires_shm_log,
|
||||
.vhost_migration_done = vhost_user_migration_done,
|
||||
.vhost_backend_can_merge = vhost_user_can_merge,
|
||||
};
|
||||
|
@@ -259,6 +259,13 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dev->vhost_ops->vhost_backend_can_merge &&
|
||||
!dev->vhost_ops->vhost_backend_can_merge(dev, uaddr, size,
|
||||
reg->userspace_addr,
|
||||
reg->memory_size)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (merged) {
|
||||
--to;
|
||||
assert(to >= 0);
|
||||
|
@@ -59,30 +59,33 @@ typedef struct VirtioBusClass VirtioPCIBusClass;
|
||||
#define VIRTIO_PCI_BUS_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(VirtioPCIBusClass, klass, TYPE_VIRTIO_PCI_BUS)
|
||||
|
||||
enum {
|
||||
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT,
|
||||
VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT,
|
||||
VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT,
|
||||
VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT,
|
||||
VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT,
|
||||
VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT,
|
||||
};
|
||||
|
||||
/* Need to activate work-arounds for buggy guests at vmstate load. */
|
||||
#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT 0
|
||||
#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION \
|
||||
(1 << VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT)
|
||||
|
||||
/* Performance improves when virtqueue kick processing is decoupled from the
|
||||
* vcpu thread using ioeventfd for some devices. */
|
||||
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
|
||||
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
|
||||
|
||||
/* virtio version flags */
|
||||
#define VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT 2
|
||||
#define VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT 3
|
||||
#define VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT 4
|
||||
#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT)
|
||||
#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT)
|
||||
#define VIRTIO_PCI_FLAG_DISABLE_PCIE (1 << VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT)
|
||||
|
||||
/* migrate extra state */
|
||||
#define VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT 4
|
||||
#define VIRTIO_PCI_FLAG_MIGRATE_EXTRA (1 << VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT)
|
||||
|
||||
/* have pio notification for modern device ? */
|
||||
#define VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT 5
|
||||
#define VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY \
|
||||
(1 << VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT)
|
||||
|
||||
|
@@ -196,6 +196,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
|
||||
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
|
||||
BlockDriverState *bdrv_new_root(void);
|
||||
BlockDriverState *bdrv_new(void);
|
||||
void bdrv_device_remove(BlockDriverState *bs);
|
||||
void bdrv_make_anon(BlockDriverState *bs);
|
||||
void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
|
||||
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
|
||||
|
@@ -686,6 +686,7 @@ void blk_set_bs(BlockBackend *blk, BlockDriverState *bs);
|
||||
|
||||
void blk_dev_change_media_cb(BlockBackend *blk, bool load);
|
||||
bool blk_dev_has_removable_media(BlockBackend *blk);
|
||||
bool blk_dev_has_tray(BlockBackend *blk);
|
||||
void blk_dev_eject_request(BlockBackend *blk, bool force);
|
||||
bool blk_dev_is_tray_open(BlockBackend *blk);
|
||||
bool blk_dev_is_medium_locked(BlockBackend *blk);
|
||||
|
@@ -124,6 +124,7 @@ struct MachineState {
|
||||
char *firmware;
|
||||
bool iommu;
|
||||
bool suppress_vmdesc;
|
||||
bool enforce_config_section;
|
||||
|
||||
ram_addr_t ram_size;
|
||||
ram_addr_t maxram_size;
|
||||
|
@@ -18,6 +18,14 @@
|
||||
.driver = "virtio-pci",\
|
||||
.property = "migrate-extra",\
|
||||
.value = "off",\
|
||||
},{\
|
||||
.driver = "fw_cfg_mem",\
|
||||
.property = "dma_enabled",\
|
||||
.value = "off",\
|
||||
},{\
|
||||
.driver = "fw_cfg_io",\
|
||||
.property = "dma_enabled",\
|
||||
.value = "off",\
|
||||
},
|
||||
|
||||
#define HW_COMPAT_2_3 \
|
||||
|
@@ -70,6 +70,9 @@ typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
|
||||
typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev);
|
||||
typedef int (*vhost_migration_done_op)(struct vhost_dev *dev,
|
||||
char *mac_addr);
|
||||
typedef bool (*vhost_backend_can_merge_op)(struct vhost_dev *dev,
|
||||
uint64_t start1, uint64_t size1,
|
||||
uint64_t start2, uint64_t size2);
|
||||
|
||||
typedef struct VhostOps {
|
||||
VhostBackendType backend_type;
|
||||
@@ -97,6 +100,7 @@ typedef struct VhostOps {
|
||||
vhost_set_vring_enable_op vhost_set_vring_enable;
|
||||
vhost_requires_shm_log_op vhost_requires_shm_log;
|
||||
vhost_migration_done_op vhost_migration_done;
|
||||
vhost_backend_can_merge_op vhost_backend_can_merge;
|
||||
} VhostOps;
|
||||
|
||||
extern const VhostOps user_ops;
|
||||
|
@@ -433,7 +433,7 @@ static inline int vnc_display_pw_expire(const char *id, time_t expires)
|
||||
void curses_display_init(DisplayState *ds, int full_screen);
|
||||
|
||||
/* input.c */
|
||||
int index_from_key(const char *key);
|
||||
int index_from_key(const char *key, size_t key_length);
|
||||
|
||||
/* gtk.c */
|
||||
void early_gtk_display_init(int opengl);
|
||||
|
@@ -878,13 +878,19 @@ bool qemu_savevm_state_blocked(Error **errp)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool enforce_config_section(void)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
return machine->enforce_config_section;
|
||||
}
|
||||
|
||||
void qemu_savevm_state_header(QEMUFile *f)
|
||||
{
|
||||
trace_savevm_state_header();
|
||||
qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
|
||||
qemu_put_be32(f, QEMU_VM_FILE_VERSION);
|
||||
|
||||
if (!savevm_state.skip_configuration) {
|
||||
if (!savevm_state.skip_configuration || enforce_config_section()) {
|
||||
qemu_put_byte(f, QEMU_VM_CONFIGURATION);
|
||||
vmstate_save_state(f, &vmstate_configuration, &savevm_state, 0);
|
||||
}
|
||||
@@ -1839,7 +1845,7 @@ int qemu_loadvm_state(QEMUFile *f)
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!savevm_state.skip_configuration) {
|
||||
if (!savevm_state.skip_configuration || enforce_config_section()) {
|
||||
if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) {
|
||||
error_report("Configuration section missing");
|
||||
return -EINVAL;
|
||||
|
@@ -59,6 +59,11 @@ void net_checksum_calculate(uint8_t *data, int length)
|
||||
int hlen, plen, proto, csum_offset;
|
||||
uint16_t csum;
|
||||
|
||||
/* Ensure data has complete L2 & L3 headers. */
|
||||
if (length < 14 + 20) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((data[14] & 0xf0) != 0x40)
|
||||
return; /* not IPv4 */
|
||||
hlen = (data[14] & 0x0f) * 4;
|
||||
@@ -76,8 +81,9 @@ void net_checksum_calculate(uint8_t *data, int length)
|
||||
return;
|
||||
}
|
||||
|
||||
if (plen < csum_offset+2)
|
||||
return;
|
||||
if (plen < csum_offset + 2 || 14 + hlen + plen > length) {
|
||||
return;
|
||||
}
|
||||
|
||||
data[14+hlen+csum_offset] = 0;
|
||||
data[14+hlen+csum_offset+1] = 0;
|
||||
|
@@ -329,6 +329,13 @@ static void filter_dump_instance_init(Object *obj)
|
||||
file_dump_set_filename, NULL);
|
||||
}
|
||||
|
||||
static void filter_dump_instance_finalize(Object *obj)
|
||||
{
|
||||
NetFilterDumpState *nfds = FILTER_DUMP(obj);
|
||||
|
||||
g_free(nfds->filename);
|
||||
}
|
||||
|
||||
static void filter_dump_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
NetFilterClass *nfc = NETFILTER_CLASS(oc);
|
||||
@@ -343,6 +350,7 @@ static const TypeInfo filter_dump_info = {
|
||||
.parent = TYPE_NETFILTER,
|
||||
.class_init = filter_dump_class_init,
|
||||
.instance_init = filter_dump_instance_init,
|
||||
.instance_finalize = filter_dump_instance_finalize,
|
||||
.instance_size = sizeof(NetFilterDumpState),
|
||||
};
|
||||
|
||||
|
@@ -204,6 +204,7 @@ static void netfilter_finalize(Object *obj)
|
||||
if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters)) {
|
||||
QTAILQ_REMOVE(&nf->netdev->filters, nf, next);
|
||||
}
|
||||
g_free(nf->netdev_id);
|
||||
}
|
||||
|
||||
static void netfilter_class_init(ObjectClass *oc, void *data)
|
||||
|
@@ -2048,8 +2048,7 @@
|
||||
# respond to the eject request
|
||||
# - if the BlockBackend denoted by @device does not have a guest device attached
|
||||
# to it
|
||||
# - if the guest device does not have an actual tray and is empty, for instance
|
||||
# for floppy disk drives
|
||||
# - if the guest device does not have an actual tray
|
||||
#
|
||||
# @device: block device name
|
||||
#
|
||||
|
@@ -29,6 +29,15 @@ typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
|
||||
struct QmpOutputVisitor
|
||||
{
|
||||
Visitor visitor;
|
||||
/* FIXME: we are abusing stack to hold two separate pieces of
|
||||
* information: the current root object in slot 0, and the stack
|
||||
* of N objects still being built in slots 1 through N (for N+1
|
||||
* slots in use). Worse, our behavior is inconsistent:
|
||||
* qmp_output_add_obj() visiting two top-level scalars in a row
|
||||
* discards the first in favor of the second, but visiting two
|
||||
* top-level objects in a row tries to append the second object
|
||||
* into the first (since the first object was placed in the stack
|
||||
* in both slot 0 and 1, but only popped from slot 1). */
|
||||
QStack stack;
|
||||
};
|
||||
|
||||
@@ -41,10 +50,12 @@ static QmpOutputVisitor *to_qov(Visitor *v)
|
||||
return container_of(v, QmpOutputVisitor, visitor);
|
||||
}
|
||||
|
||||
/* Push @value onto the stack of current QObjects being built */
|
||||
static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
|
||||
{
|
||||
QStackEntry *e = g_malloc0(sizeof(*e));
|
||||
|
||||
assert(value);
|
||||
e->value = value;
|
||||
if (qobject_type(e->value) == QTYPE_QLIST) {
|
||||
e->is_list_head = true;
|
||||
@@ -52,44 +63,53 @@ static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
|
||||
QTAILQ_INSERT_HEAD(&qov->stack, e, node);
|
||||
}
|
||||
|
||||
/* Pop a value off the stack of QObjects being built, and return it. */
|
||||
static QObject *qmp_output_pop(QmpOutputVisitor *qov)
|
||||
{
|
||||
QStackEntry *e = QTAILQ_FIRST(&qov->stack);
|
||||
QObject *value;
|
||||
|
||||
assert(e);
|
||||
QTAILQ_REMOVE(&qov->stack, e, node);
|
||||
value = e->value;
|
||||
assert(value);
|
||||
g_free(e);
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Grab the root QObject, if any */
|
||||
static QObject *qmp_output_first(QmpOutputVisitor *qov)
|
||||
{
|
||||
QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
|
||||
|
||||
/*
|
||||
* FIXME Wrong, because qmp_output_get_qobject() will increment
|
||||
* the refcnt *again*. We need to think through how visitors
|
||||
* handle null.
|
||||
*/
|
||||
if (!e) {
|
||||
return qnull();
|
||||
/* No root */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(e->value);
|
||||
return e->value;
|
||||
}
|
||||
|
||||
/* Peek at the top of the stack of QObjects being built.
|
||||
* The stack must not be empty. */
|
||||
static QObject *qmp_output_last(QmpOutputVisitor *qov)
|
||||
{
|
||||
QStackEntry *e = QTAILQ_FIRST(&qov->stack);
|
||||
|
||||
assert(e && e->value);
|
||||
return e->value;
|
||||
}
|
||||
|
||||
/* Add @value to the current QObject being built.
|
||||
* If the stack is visiting a dictionary or list, @value is now owned
|
||||
* by that container. Otherwise, @value is now the root. */
|
||||
static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
|
||||
QObject *value)
|
||||
{
|
||||
QObject *cur;
|
||||
|
||||
if (QTAILQ_EMPTY(&qov->stack)) {
|
||||
/* Stack was empty, track this object as root */
|
||||
qmp_output_push_obj(qov, value);
|
||||
return;
|
||||
}
|
||||
@@ -98,13 +118,17 @@ static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
|
||||
|
||||
switch (qobject_type(cur)) {
|
||||
case QTYPE_QDICT:
|
||||
assert(name);
|
||||
qdict_put_obj(qobject_to_qdict(cur), name, value);
|
||||
break;
|
||||
case QTYPE_QLIST:
|
||||
qlist_append_obj(qobject_to_qlist(cur), value);
|
||||
break;
|
||||
default:
|
||||
/* The previous root was a scalar, replace it with a new root */
|
||||
/* FIXME this is abusing the stack; see comment above */
|
||||
qobject_decref(qmp_output_pop(qov));
|
||||
assert(QTAILQ_EMPTY(&qov->stack));
|
||||
qmp_output_push_obj(qov, value);
|
||||
break;
|
||||
}
|
||||
@@ -198,11 +222,14 @@ static void qmp_output_type_any(Visitor *v, QObject **obj, const char *name,
|
||||
qmp_output_add_obj(qov, name, *obj);
|
||||
}
|
||||
|
||||
/* Finish building, and return the root object. Will not be NULL. */
|
||||
QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
|
||||
{
|
||||
QObject *obj = qmp_output_first(qov);
|
||||
if (obj) {
|
||||
qobject_incref(obj);
|
||||
} else {
|
||||
obj = qnull();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
@@ -41,7 +41,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
|
||||
" igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n"
|
||||
" aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n"
|
||||
" dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n"
|
||||
" suppress-vmdesc=on|off disables self-describing migration (default=off)\n",
|
||||
" suppress-vmdesc=on|off disables self-describing migration (default=off)\n"
|
||||
" enforce-config-section=on|off enforce configuration section migration (default=off)\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -machine [type=]@var{name}[,prop=@var{value}[,...]]
|
||||
|
@@ -150,6 +150,7 @@ typedef struct ARMCPU {
|
||||
uint32_t id_mmfr1;
|
||||
uint32_t id_mmfr2;
|
||||
uint32_t id_mmfr3;
|
||||
uint32_t id_mmfr4;
|
||||
uint32_t id_isar0;
|
||||
uint32_t id_isar1;
|
||||
uint32_t id_isar2;
|
||||
|
@@ -4092,12 +4092,14 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 5,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = cpu->id_isar5 },
|
||||
/* 6..7 are as yet unallocated and must RAZ */
|
||||
{ .name = "ID_ISAR6", .cp = 15, .crn = 0, .crm = 2,
|
||||
.opc1 = 0, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_ISAR7", .cp = 15, .crn = 0, .crm = 2,
|
||||
.opc1 = 0, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST,
|
||||
{ .name = "ID_MMFR4", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 6,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = cpu->id_mmfr4 },
|
||||
/* 7 is as yet unallocated and must RAZ */
|
||||
{ .name = "ID_ISAR7_RESERVED", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 7,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
@@ -4151,7 +4153,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
define_arm_cp_regs(cpu, not_v7_cp_reginfo);
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
/* AArch64 ID registers, which all have impdef reset values */
|
||||
/* AArch64 ID registers, which all have impdef reset values.
|
||||
* Note that within the ID register ranges the unused slots
|
||||
* must all RAZ, not UNDEF; future architecture versions may
|
||||
* define new registers here.
|
||||
*/
|
||||
ARMCPRegInfo v8_idregs[] = {
|
||||
{ .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0,
|
||||
@@ -4161,6 +4167,30 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = cpu->id_aa64pfr1},
|
||||
{ .name = "ID_AA64PFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 2,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64PFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 3,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64PFR4_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 4,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64PFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 5,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64PFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 6,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64PFR7_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 7,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
@@ -4174,6 +4204,14 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = cpu->id_aa64dfr1 },
|
||||
{ .name = "ID_AA64DFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 2,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64DFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 3,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64AFR0_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 4,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
@@ -4182,6 +4220,14 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 5,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = cpu->id_aa64afr1 },
|
||||
{ .name = "ID_AA64AFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 6,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64AFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 7,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
@@ -4190,6 +4236,30 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = cpu->id_aa64isar1 },
|
||||
{ .name = "ID_AA64ISAR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64ISAR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 3,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64ISAR4_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 4,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64ISAR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 5,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64ISAR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 6,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64ISAR7_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 7,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64MMFR0_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
@@ -4198,6 +4268,30 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = cpu->id_aa64mmfr1 },
|
||||
{ .name = "ID_AA64MMFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64MMFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 3,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64MMFR4_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 4,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64MMFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 5,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64MMFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 6,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "ID_AA64MMFR7_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 7,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "MVFR0_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 0,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
@@ -4210,6 +4304,26 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = cpu->mvfr2 },
|
||||
{ .name = "MVFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 3,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "MVFR4_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 4,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "MVFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 5,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "MVFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 6,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "MVFR7_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 7,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
/* RVBAR_EL1 is only implemented if EL1 is the highest EL */
|
||||
|
@@ -601,6 +601,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
||||
if (cpu->hyperv_crash && has_msr_hv_crash) {
|
||||
c->edx |= HV_X64_GUEST_CRASH_MSR_AVAILABLE;
|
||||
}
|
||||
c->edx |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE;
|
||||
if (cpu->hyperv_reset && has_msr_hv_reset) {
|
||||
c->eax |= HV_X64_MSR_RESET_AVAILABLE;
|
||||
}
|
||||
|
@@ -650,8 +650,13 @@ static int kvm_put_fp(CPUState *cs)
|
||||
for (i = 0; i < 32; i++) {
|
||||
uint64_t vsr[2];
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
vsr[0] = float64_val(env->fpr[i]);
|
||||
vsr[1] = env->vsr[i];
|
||||
#else
|
||||
vsr[0] = env->vsr[i];
|
||||
vsr[1] = float64_val(env->fpr[i]);
|
||||
#endif
|
||||
reg.addr = (uintptr_t) &vsr;
|
||||
reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i);
|
||||
|
||||
@@ -721,10 +726,17 @@ static int kvm_get_fp(CPUState *cs)
|
||||
vsx ? "VSR" : "FPR", i, strerror(errno));
|
||||
return ret;
|
||||
} else {
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
env->fpr[i] = vsr[0];
|
||||
if (vsx) {
|
||||
env->vsr[i] = vsr[1];
|
||||
}
|
||||
#else
|
||||
env->fpr[i] = vsr[1];
|
||||
if (vsx) {
|
||||
env->vsr[i] = vsr[0];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -616,7 +616,8 @@ static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res)
|
||||
(*res_flags) &= ~0x80;
|
||||
}
|
||||
} else {
|
||||
res->code = cpu_to_be16(0x0004);
|
||||
res->code = cpu_to_be16(0x0005);
|
||||
res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
114
tests/qemu-iotests/144
Executable file
114
tests/qemu-iotests/144
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/bin/bash
|
||||
# Check live snapshot, followed by active commit, and another snapshot.
|
||||
#
|
||||
# This test is to catch the error case of BZ #1300209:
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1300209
|
||||
#
|
||||
# Copyright (C) 2016 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=jcody@redhat.com
|
||||
|
||||
seq=`basename $0`
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
status=1 # failure is the default!
|
||||
|
||||
TMP_SNAP1=${TEST_DIR}/tmp.qcow2
|
||||
TMP_SNAP2=${TEST_DIR}/tmp2.qcow2
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_qemu
|
||||
rm -f "${TEST_IMG}" "${TMP_SNAP1}" "${TMP_SNAP2}"
|
||||
}
|
||||
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.qemu
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
size=512M
|
||||
|
||||
_make_test_img $size
|
||||
|
||||
echo
|
||||
echo === Launching QEMU ===
|
||||
echo
|
||||
|
||||
qemu_comm_method="qmp"
|
||||
_launch_qemu -drive file="${TEST_IMG}",if=virtio
|
||||
h=$QEMU_HANDLE
|
||||
|
||||
|
||||
echo
|
||||
echo === Performing Live Snapshot 1 ===
|
||||
echo
|
||||
|
||||
_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return"
|
||||
|
||||
|
||||
# First live snapshot, new overlay as active layer
|
||||
_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync',
|
||||
'arguments': {
|
||||
'device': 'virtio0',
|
||||
'snapshot-file':'${TMP_SNAP1}',
|
||||
'format': 'qcow2'
|
||||
}
|
||||
}" "return"
|
||||
|
||||
echo
|
||||
echo === Performing block-commit on active layer ===
|
||||
echo
|
||||
|
||||
# Block commit on active layer, push the new overlay into base
|
||||
_send_qemu_cmd $h "{ 'execute': 'block-commit',
|
||||
'arguments': {
|
||||
'device': 'virtio0'
|
||||
}
|
||||
}" "READY"
|
||||
|
||||
_send_qemu_cmd $h "{ 'execute': 'block-job-complete',
|
||||
'arguments': {
|
||||
'device': 'virtio0'
|
||||
}
|
||||
}" "COMPLETED"
|
||||
|
||||
echo
|
||||
echo === Performing Live Snapshot 2 ===
|
||||
echo
|
||||
|
||||
# New live snapshot, new overlays as active layer
|
||||
_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync',
|
||||
'arguments': {
|
||||
'device': 'virtio0',
|
||||
'snapshot-file':'${TMP_SNAP2}',
|
||||
'format': 'qcow2'
|
||||
}
|
||||
}" "return"
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
24
tests/qemu-iotests/144.out
Normal file
24
tests/qemu-iotests/144.out
Normal file
@@ -0,0 +1,24 @@
|
||||
QA output created by 144
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912
|
||||
|
||||
=== Launching QEMU ===
|
||||
|
||||
|
||||
=== Performing Live Snapshot 1 ===
|
||||
|
||||
{"return": {}}
|
||||
Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
|
||||
{"return": {}}
|
||||
|
||||
=== Performing block-commit on active layer ===
|
||||
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
|
||||
|
||||
=== Performing Live Snapshot 2 ===
|
||||
|
||||
Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
|
||||
{"return": {}}
|
||||
*** done
|
@@ -140,3 +140,4 @@
|
||||
137 rw auto
|
||||
138 rw auto quick
|
||||
139 rw auto quick
|
||||
144 rw auto quick
|
||||
|
@@ -461,6 +461,8 @@ static void test_visitor_out_empty(TestOutputVisitorData *data,
|
||||
|
||||
arg = qmp_output_get_qobject(data->qov);
|
||||
g_assert(qobject_type(arg) == QTYPE_QNULL);
|
||||
/* Check that qnull reference counting is sane */
|
||||
g_assert(arg->refcnt == 2);
|
||||
qobject_decref(arg);
|
||||
}
|
||||
|
||||
|
@@ -57,12 +57,13 @@ struct QEMUPutLEDEntry {
|
||||
static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
|
||||
QTAILQ_HEAD_INITIALIZER(led_handlers);
|
||||
|
||||
int index_from_key(const char *key)
|
||||
int index_from_key(const char *key, size_t key_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; QKeyCode_lookup[i] != NULL; i++) {
|
||||
if (!strcmp(key, QKeyCode_lookup[i])) {
|
||||
if (!strncmp(key, QKeyCode_lookup[i], key_length) &&
|
||||
!QKeyCode_lookup[i][key_length]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
37
vl.c
37
vl.c
@@ -2757,6 +2757,31 @@ static const QEMUOption *lookup_opt(int argc, char **argv,
|
||||
return popt;
|
||||
}
|
||||
|
||||
static void set_machine_options(MachineClass **machine_class)
|
||||
{
|
||||
const char *optarg;
|
||||
QemuOpts *opts;
|
||||
Location loc;
|
||||
|
||||
loc_push_none(&loc);
|
||||
|
||||
opts = qemu_get_machine_opts();
|
||||
qemu_opts_loc_restore(opts);
|
||||
|
||||
optarg = qemu_opt_get(opts, "type");
|
||||
if (optarg) {
|
||||
*machine_class = machine_parse(optarg);
|
||||
}
|
||||
|
||||
if (*machine_class == NULL) {
|
||||
error_report("No machine specified, and there is no default");
|
||||
error_printf("Use -machine help to list supported machines\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
loc_pop(&loc);
|
||||
}
|
||||
|
||||
static int machine_set_property(void *opaque,
|
||||
const char *name, const char *value,
|
||||
Error **errp)
|
||||
@@ -4025,17 +4050,7 @@ int main(int argc, char **argv, char **envp)
|
||||
|
||||
replay_configure(icount_opts);
|
||||
|
||||
opts = qemu_get_machine_opts();
|
||||
optarg = qemu_opt_get(opts, "type");
|
||||
if (optarg) {
|
||||
machine_class = machine_parse(optarg);
|
||||
}
|
||||
|
||||
if (machine_class == NULL) {
|
||||
error_report("No machine specified, and there is no default");
|
||||
error_printf("Use -machine help to list supported machines\n");
|
||||
exit(1);
|
||||
}
|
||||
set_machine_options(&machine_class);
|
||||
|
||||
set_memory_options(&ram_slots, &maxram_size, machine_class);
|
||||
|
||||
|
Reference in New Issue
Block a user