Compare commits
51 Commits
pull-chard
...
pull-conso
Author | SHA1 | Date | |
---|---|---|---|
|
3f9a6e852e | ||
|
aea7947c74 | ||
|
b35e3ba01a | ||
|
521a580d23 | ||
|
afff2b15e8 | ||
|
178ac111bc | ||
|
6054d883d6 | ||
|
5118dc5975 | ||
|
45e66b7beb | ||
|
65903a8b08 | ||
|
fc13d93726 | ||
|
3478881130 | ||
|
3b69595068 | ||
|
5a7733b0b7 | ||
|
770a63792b | ||
|
b30f4dfbda | ||
|
8e4e86afa5 | ||
|
76eb98d51c | ||
|
d426d9fba8 | ||
|
7bca3892cb | ||
|
03cf077ac9 | ||
|
7b35d0c44c | ||
|
61c7bbd236 | ||
|
ca8c0fab95 | ||
|
f2564d88fe | ||
|
b1fe60cd35 | ||
|
a2554a334a | ||
|
465bee1da8 | ||
|
82a402e99f | ||
|
43f35cb5e0 | ||
|
d66e5cee00 | ||
|
46485de0cb | ||
|
42eb58179b | ||
|
7159a45b2b | ||
|
ea54feff58 | ||
|
0a86cb7317 | ||
|
97a3ea5719 | ||
|
e3542c67af | ||
|
9aedd5a5d6 | ||
|
b5e51dd714 | ||
|
d530e34232 | ||
|
4ad303369c | ||
|
4993f7ea7e | ||
|
8a5eb36a1c | ||
|
9c52681277 | ||
|
26e2da7279 | ||
|
6906046169 | ||
|
395071a763 | ||
|
e88ae2264d | ||
|
91e7fcca47 | ||
|
c4ce4c4b1f |
60
block.c
60
block.c
@@ -1274,6 +1274,33 @@ out:
|
||||
g_free(tmp_filename);
|
||||
}
|
||||
|
||||
static QDict *parse_json_filename(const char *filename, Error **errp)
|
||||
{
|
||||
QObject *options_obj;
|
||||
QDict *options;
|
||||
int ret;
|
||||
|
||||
ret = strstart(filename, "json:", &filename);
|
||||
assert(ret);
|
||||
|
||||
options_obj = qobject_from_json(filename);
|
||||
if (!options_obj) {
|
||||
error_setg(errp, "Could not parse the JSON options");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qobject_type(options_obj) != QTYPE_QDICT) {
|
||||
qobject_decref(options_obj);
|
||||
error_setg(errp, "Invalid JSON object given");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
options = qobject_to_qdict(options_obj);
|
||||
qdict_flatten(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens a disk image (raw, qcow2, vmdk, ...)
|
||||
*
|
||||
@@ -1337,6 +1364,20 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
options = qdict_new();
|
||||
}
|
||||
|
||||
if (filename && g_str_has_prefix(filename, "json:")) {
|
||||
QDict *json_options = parse_json_filename(filename, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Options given in the filename have lower priority than options
|
||||
* specified directly */
|
||||
qdict_join(options, json_options, false);
|
||||
QDECREF(json_options);
|
||||
filename = NULL;
|
||||
}
|
||||
|
||||
bs->options = options;
|
||||
options = qdict_clone_shallow(options);
|
||||
|
||||
@@ -3248,6 +3289,15 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
|
||||
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||
|
||||
if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF &&
|
||||
!(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_write_zeroes &&
|
||||
qemu_iovec_is_zero(qiov)) {
|
||||
flags |= BDRV_REQ_ZERO_WRITE;
|
||||
if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) {
|
||||
flags |= BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
/* Do nothing, write notifier decided to fail this request */
|
||||
} else if (flags & BDRV_REQ_ZERO_WRITE) {
|
||||
@@ -3864,7 +3914,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
|
||||
if (!bs->drv->bdrv_co_get_block_status) {
|
||||
*pnum = nb_sectors;
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
|
||||
if (bs->drv->protocol_name) {
|
||||
ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
@@ -3883,6 +3933,10 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
*pnum, pnum);
|
||||
}
|
||||
|
||||
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
|
||||
ret |= BDRV_BLOCK_ALLOCATED;
|
||||
}
|
||||
|
||||
if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) {
|
||||
if (bdrv_unallocated_blocks_are_zero(bs)) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
@@ -3959,9 +4013,7 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return
|
||||
(ret & BDRV_BLOCK_DATA) ||
|
||||
((ret & BDRV_BLOCK_ZERO) && !bdrv_has_zero_init(bs));
|
||||
return (ret & BDRV_BLOCK_ALLOCATED);
|
||||
}
|
||||
|
||||
/*
|
||||
|
79
block/curl.c
79
block/curl.c
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
// #define DEBUG
|
||||
@@ -37,6 +38,21 @@
|
||||
#if LIBCURL_VERSION_NUM >= 0x071000
|
||||
/* The multi interface timer callback was introduced in 7.16.0 */
|
||||
#define NEED_CURL_TIMER_CALLBACK
|
||||
#define HAVE_SOCKET_ACTION
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SOCKET_ACTION
|
||||
/* If curl_multi_socket_action isn't available, define it statically here in
|
||||
* terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
|
||||
* less efficient but still safe. */
|
||||
static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
||||
curl_socket_t sockfd,
|
||||
int ev_bitmask,
|
||||
int *running_handles)
|
||||
{
|
||||
return curl_multi_socket(multi_handle, sockfd, running_handles);
|
||||
}
|
||||
#define curl_multi_socket_action __curl_multi_socket_action
|
||||
#endif
|
||||
|
||||
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
|
||||
@@ -46,12 +62,16 @@
|
||||
#define CURL_NUM_STATES 8
|
||||
#define CURL_NUM_ACB 8
|
||||
#define SECTOR_SIZE 512
|
||||
#define READ_AHEAD_SIZE (256 * 1024)
|
||||
#define READ_AHEAD_DEFAULT (256 * 1024)
|
||||
|
||||
#define FIND_RET_NONE 0
|
||||
#define FIND_RET_OK 1
|
||||
#define FIND_RET_WAIT 2
|
||||
|
||||
#define CURL_BLOCK_OPT_URL "url"
|
||||
#define CURL_BLOCK_OPT_READAHEAD "readahead"
|
||||
#define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
|
||||
|
||||
struct BDRVCURLState;
|
||||
|
||||
typedef struct CURLAIOCB {
|
||||
@@ -88,6 +108,7 @@ typedef struct BDRVCURLState {
|
||||
CURLState states[CURL_NUM_STATES];
|
||||
char *url;
|
||||
size_t readahead_size;
|
||||
bool sslverify;
|
||||
bool accept_range;
|
||||
} BDRVCURLState;
|
||||
|
||||
@@ -354,6 +375,8 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
||||
return NULL;
|
||||
}
|
||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||
curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
|
||||
(long) s->sslverify);
|
||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
|
||||
(void *)curl_read_cb);
|
||||
@@ -396,43 +419,7 @@ static void curl_clean_state(CURLState *s)
|
||||
static void curl_parse_filename(const char *filename, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
#define RA_OPTSTR ":readahead="
|
||||
char *file;
|
||||
char *ra;
|
||||
const char *ra_val;
|
||||
int parse_state = 0;
|
||||
|
||||
file = g_strdup(filename);
|
||||
|
||||
/* Parse a trailing ":readahead=#:" param, if present. */
|
||||
ra = file + strlen(file) - 1;
|
||||
while (ra >= file) {
|
||||
if (parse_state == 0) {
|
||||
if (*ra == ':') {
|
||||
parse_state++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (parse_state == 1) {
|
||||
if (*ra > '9' || *ra < '0') {
|
||||
char *opt_start = ra - strlen(RA_OPTSTR) + 1;
|
||||
if (opt_start > file &&
|
||||
strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
|
||||
ra_val = ra + 1;
|
||||
ra -= strlen(RA_OPTSTR) - 1;
|
||||
*ra = '\0';
|
||||
qdict_put(options, "readahead", qstring_from_str(ra_val));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ra--;
|
||||
}
|
||||
|
||||
qdict_put(options, "url", qstring_from_str(file));
|
||||
|
||||
g_free(file);
|
||||
qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
|
||||
}
|
||||
|
||||
static QemuOptsList runtime_opts = {
|
||||
@@ -440,15 +427,20 @@ static QemuOptsList runtime_opts = {
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "url",
|
||||
.name = CURL_BLOCK_OPT_URL,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "URL to open",
|
||||
},
|
||||
{
|
||||
.name = "readahead",
|
||||
.name = CURL_BLOCK_OPT_READAHEAD,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Readahead size",
|
||||
},
|
||||
{
|
||||
.name = CURL_BLOCK_OPT_SSLVERIFY,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Verify SSL certificate"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -477,14 +469,17 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
|
||||
s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
|
||||
READ_AHEAD_DEFAULT);
|
||||
if ((s->readahead_size & 0x1ff) != 0) {
|
||||
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
|
||||
s->readahead_size);
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
file = qemu_opt_get(opts, "url");
|
||||
s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
|
||||
|
||||
file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
|
||||
if (file == NULL) {
|
||||
error_setg(errp, "curl block driver requires an 'url' option");
|
||||
goto out_noclean;
|
||||
|
@@ -381,6 +381,7 @@ retry:
|
||||
}
|
||||
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
@@ -393,9 +394,6 @@ static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
|
||||
sector_num / iscsilun->cluster_sectors) == size);
|
||||
}
|
||||
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
|
||||
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
|
@@ -50,6 +50,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
info->backing_file_depth = bdrv_get_backing_file_depth(bs);
|
||||
info->detect_zeroes = bs->detect_zeroes;
|
||||
|
||||
if (bs->io_limits_enabled) {
|
||||
ThrottleConfig cfg;
|
||||
|
44
block/qcow.c
44
block/qcow.c
@@ -48,9 +48,10 @@ typedef struct QCowHeader {
|
||||
uint64_t size; /* in bytes */
|
||||
uint8_t cluster_bits;
|
||||
uint8_t l2_bits;
|
||||
uint16_t padding;
|
||||
uint32_t crypt_method;
|
||||
uint64_t l1_table_offset;
|
||||
} QCowHeader;
|
||||
} QEMU_PACKED QCowHeader;
|
||||
|
||||
#define L2_CACHE_SIZE 16
|
||||
|
||||
@@ -60,7 +61,7 @@ typedef struct BDRVQcowState {
|
||||
int cluster_sectors;
|
||||
int l2_bits;
|
||||
int l2_size;
|
||||
int l1_size;
|
||||
unsigned int l1_size;
|
||||
uint64_t cluster_offset_mask;
|
||||
uint64_t l1_table_offset;
|
||||
uint64_t *l1_table;
|
||||
@@ -96,7 +97,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int len, i, shift, ret;
|
||||
unsigned int len, i, shift;
|
||||
int ret;
|
||||
QCowHeader header;
|
||||
|
||||
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
||||
@@ -127,11 +129,25 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.size <= 1 || header.cluster_bits < 9) {
|
||||
error_setg(errp, "invalid value in qcow header");
|
||||
if (header.size <= 1) {
|
||||
error_setg(errp, "Image size is too small (must be at least 2 bytes)");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (header.cluster_bits < 9 || header.cluster_bits > 16) {
|
||||
error_setg(errp, "Cluster size must be between 512 and 64k");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* l2_bits specifies number of entries; storing a uint64_t in each entry,
|
||||
* so bytes = num_entries << 3. */
|
||||
if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {
|
||||
error_setg(errp, "L2 table size must be between 512 and 64k");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||
error_setg(errp, "invalid encryption method in qcow header");
|
||||
ret = -EINVAL;
|
||||
@@ -151,7 +167,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
/* read the level 1 table */
|
||||
shift = s->cluster_bits + s->l2_bits;
|
||||
s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
|
||||
if (header.size > UINT64_MAX - (1LL << shift)) {
|
||||
error_setg(errp, "Image too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else {
|
||||
uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;
|
||||
if (l1_size > INT_MAX / sizeof(uint64_t)) {
|
||||
error_setg(errp, "Image too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
s->l1_size = l1_size;
|
||||
}
|
||||
|
||||
s->l1_table_offset = header.l1_table_offset;
|
||||
s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
|
||||
@@ -175,7 +203,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (header.backing_file_offset != 0) {
|
||||
len = header.backing_file_size;
|
||||
if (len > 1023) {
|
||||
len = 1023;
|
||||
error_setg(errp, "Backing file name too long");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||
bs->backing_file, len);
|
||||
|
@@ -473,7 +473,14 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
|
||||
} else if (h2_seq > h1_seq) {
|
||||
s->curr_header = 1;
|
||||
} else {
|
||||
goto fail;
|
||||
/* The Microsoft Disk2VHD tool will create 2 identical
|
||||
* headers, with identical sequence numbers. If the headers are
|
||||
* identical, don't consider the file corrupt */
|
||||
if (!memcmp(header1, header2, sizeof(VHDXHeader))) {
|
||||
s->curr_header = 0;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
43
blockdev.c
43
blockdev.c
@@ -288,6 +288,25 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int parse_enum_option(const char *lookup[], const char *buf,
|
||||
int max, int def, Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!buf) {
|
||||
return def;
|
||||
}
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (!strcmp(buf, lookup[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
error_setg(errp, "invalid parameter value: %s", buf);
|
||||
return def;
|
||||
}
|
||||
|
||||
static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
|
||||
{
|
||||
if (throttle_conflicting(cfg)) {
|
||||
@@ -324,6 +343,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
QemuOpts *opts;
|
||||
const char *id;
|
||||
bool has_driver_specific_opts;
|
||||
BlockdevDetectZeroesOptions detect_zeroes;
|
||||
BlockDriver *drv = NULL;
|
||||
|
||||
/* Check common options by copying from bs_opts to opts, all other options
|
||||
@@ -452,6 +472,24 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
}
|
||||
|
||||
detect_zeroes =
|
||||
parse_enum_option(BlockdevDetectZeroesOptions_lookup,
|
||||
qemu_opt_get(opts, "detect-zeroes"),
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
|
||||
&error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
|
||||
!(bdrv_flags & BDRV_O_UNMAP)) {
|
||||
error_setg(errp, "setting detect-zeroes to unmap is not allowed "
|
||||
"without setting discard operation to unmap");
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
/* init */
|
||||
dinfo = g_malloc0(sizeof(*dinfo));
|
||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||
@@ -462,6 +500,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||
dinfo->bdrv->read_only = ro;
|
||||
dinfo->bdrv->detect_zeroes = detect_zeroes;
|
||||
dinfo->refcount = 1;
|
||||
if (serial != NULL) {
|
||||
dinfo->serial = g_strdup(serial);
|
||||
@@ -2455,6 +2494,10 @@ QemuOptsList qemu_common_drive_opts = {
|
||||
.name = "copy-on-read",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "copy read data from backing file into image file",
|
||||
},{
|
||||
.name = "detect-zeroes",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "try to optimize zero writes (off, on, unmap)",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
|
@@ -1,3 +1,4 @@
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_S390_FLIC=$(CONFIG_KVM)
|
||||
CONFIG_S390_FLIC=y
|
||||
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
|
||||
|
5
hmp.c
5
hmp.c
@@ -341,6 +341,11 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
|
||||
info->value->inserted->backing_file_depth);
|
||||
}
|
||||
|
||||
if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
||||
monitor_printf(mon, " Detect zeroes: %s\n",
|
||||
BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
|
||||
}
|
||||
|
||||
if (info->value->inserted->bps
|
||||
|| info->value->inserted->bps_rd
|
||||
|| info->value->inserted->bps_wr
|
||||
|
@@ -245,7 +245,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
|
||||
|
||||
/* update global status */
|
||||
if (sts & d->int_ctl) {
|
||||
sts |= (1 << 31);
|
||||
sts |= (1U << 31);
|
||||
}
|
||||
|
||||
d->int_sts = sts;
|
||||
@@ -257,7 +257,7 @@ static void intel_hda_update_irq(IntelHDAState *d)
|
||||
int level;
|
||||
|
||||
intel_hda_update_int_sts(d);
|
||||
if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
|
||||
if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) {
|
||||
level = 1;
|
||||
} else {
|
||||
level = 0;
|
||||
@@ -574,7 +574,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
|
||||
if (st->ctl & 0x01) {
|
||||
/* reset */
|
||||
dprint(d, 1, "st #%d: reset\n", reg->stream);
|
||||
st->ctl = 0;
|
||||
st->ctl = SD_STS_FIFO_READY << 24;
|
||||
}
|
||||
if ((st->ctl & 0x02) != (old & 0x02)) {
|
||||
uint32_t stnr = (st->ctl >> 20) & 0x0f;
|
||||
@@ -829,6 +829,7 @@ static const struct IntelHDAReg regtab[] = {
|
||||
.wclear = 0x1c000000, \
|
||||
.offset = offsetof(IntelHDAState, st[_i].ctl), \
|
||||
.whandler = intel_hda_set_st_ctl, \
|
||||
.reset = SD_STS_FIFO_READY << 24 \
|
||||
}, \
|
||||
[ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \
|
||||
.stream = _i, \
|
||||
|
@@ -26,3 +26,4 @@ obj-$(CONFIG_XICS) += xics.o
|
||||
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
||||
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
|
||||
obj-$(CONFIG_S390_FLIC) += s390_flic.o
|
||||
obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
|
||||
|
@@ -1,322 +1,103 @@
|
||||
/*
|
||||
* QEMU S390x KVM floating interrupt controller (flic)
|
||||
* QEMU S390x floating interrupt controller (flic)
|
||||
*
|
||||
* Copyright 2014 IBM Corp.
|
||||
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "migration/qemu-file.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define FLIC_SAVE_INITIAL_SIZE getpagesize()
|
||||
#define FLIC_FAILED (-1UL)
|
||||
#define FLIC_SAVEVM_VERSION 1
|
||||
S390FLICState *s390_get_flic(void)
|
||||
{
|
||||
S390FLICState *fs;
|
||||
|
||||
fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL));
|
||||
if (!fs) {
|
||||
fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC, NULL));
|
||||
}
|
||||
return fs;
|
||||
}
|
||||
|
||||
void s390_flic_init(void)
|
||||
{
|
||||
DeviceState *dev;
|
||||
int r;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
dev = qdev_create(NULL, "s390-flic");
|
||||
object_property_add_child(qdev_get_machine(), "s390-flic",
|
||||
OBJECT(dev), NULL);
|
||||
r = qdev_init(dev);
|
||||
if (r) {
|
||||
error_report("flic: couldn't create qdev");
|
||||
}
|
||||
dev = s390_flic_kvm_create();
|
||||
if (!dev) {
|
||||
dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC);
|
||||
object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC,
|
||||
OBJECT(dev), NULL);
|
||||
}
|
||||
r = qdev_init(dev);
|
||||
if (r) {
|
||||
error_report("flic: couldn't create qdev");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* flic_get_all_irqs - store all pending irqs in buffer
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -ENOMEM if buffer is too small,
|
||||
* -EINVAL if attr.group is invalid,
|
||||
* -EFAULT if copying to userspace failed,
|
||||
* on success return number of stored interrupts
|
||||
*/
|
||||
static int flic_get_all_irqs(KVMS390FLICState *flic,
|
||||
void *buf, int len)
|
||||
static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
|
||||
uint8_t isc, bool swap,
|
||||
bool is_maskable)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_GET_ALL_IRQS,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc == -1 ? -errno : rc;
|
||||
/* nothing to do */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flic_enable_pfault(KVMS390FLICState *flic)
|
||||
static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
|
||||
uint64_t map_addr, bool do_map)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_ENABLE,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't enable pfault\n");
|
||||
}
|
||||
/* nothing to do */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flic_disable_wait_pfault(KVMS390FLICState *flic)
|
||||
static int qemu_s390_add_adapter_routes(S390FLICState *fs,
|
||||
AdapterRoutes *routes)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't disable pfault\n");
|
||||
}
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/** flic_enqueue_irqs - returns 0 on success
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -EINVAL if attr.group is unknown
|
||||
*/
|
||||
static int flic_enqueue_irqs(void *buf, uint64_t len,
|
||||
KVMS390FLICState *flic)
|
||||
static void qemu_s390_release_adapter_routes(S390FLICState *fs,
|
||||
AdapterRoutes *routes)
|
||||
{
|
||||
int rc;
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_ENQUEUE,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc ? -errno : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __get_all_irqs - store all pending irqs in buffer
|
||||
* @flic: pointer to flic device state
|
||||
* @buf: pointer to pointer to a buffer
|
||||
* @len: length of buffer
|
||||
*
|
||||
* Returns: return value of flic_get_all_irqs
|
||||
* Note: Retry and increase buffer size until flic_get_all_irqs
|
||||
* either returns a value >= 0 or a negative error code.
|
||||
* -ENOMEM is an exception, which means the buffer is too small
|
||||
* and we should try again. Other negative error codes can be
|
||||
* -EFAULT and -EINVAL which we ignore at this point
|
||||
*/
|
||||
static int __get_all_irqs(KVMS390FLICState *flic,
|
||||
void **buf, int len)
|
||||
static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
int r;
|
||||
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
|
||||
|
||||
do {
|
||||
/* returns -ENOMEM if buffer is too small and number
|
||||
* of queued interrupts on success */
|
||||
r = flic_get_all_irqs(flic, *buf, len);
|
||||
if (r >= 0) {
|
||||
break;
|
||||
}
|
||||
len *= 2;
|
||||
*buf = g_try_realloc(*buf, len);
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
} while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
|
||||
|
||||
return r;
|
||||
fsc->register_io_adapter = qemu_s390_register_io_adapter;
|
||||
fsc->io_adapter_map = qemu_s390_io_adapter_map;
|
||||
fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
|
||||
fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_save - Save pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
*
|
||||
* Note: Pass buf and len to kernel. Start with one page and
|
||||
* increase until buffer is sufficient or maxium size is
|
||||
* reached
|
||||
*/
|
||||
static void kvm_flic_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
KVMS390FLICState *flic = opaque;
|
||||
int len = FLIC_SAVE_INITIAL_SIZE;
|
||||
void *buf;
|
||||
int count;
|
||||
|
||||
flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
error_report("flic: couldn't allocate memory");
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
count = __get_all_irqs(flic, &buf, len);
|
||||
if (count < 0) {
|
||||
error_report("flic: couldn't retrieve irqs from kernel, rc %d",
|
||||
count);
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
} else {
|
||||
qemu_put_be64(f, count);
|
||||
qemu_put_buffer(f, (uint8_t *) buf,
|
||||
count * sizeof(struct kvm_s390_irq));
|
||||
}
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_load - Load pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
* @version_id: version id for migration
|
||||
*
|
||||
* Returns: value of flic_enqueue_irqs, -EINVAL on error
|
||||
* Note: Do nothing when no interrupts where stored
|
||||
* in QEMUFile
|
||||
*/
|
||||
static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
uint64_t len = 0;
|
||||
uint64_t count = 0;
|
||||
void *buf = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (version_id != FLIC_SAVEVM_VERSION) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
flic_enable_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
count = qemu_get_be64(f);
|
||||
len = count * sizeof(struct kvm_s390_irq);
|
||||
if (count == FLIC_FAILED) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (count == 0) {
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
|
||||
r = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
|
||||
|
||||
out_free:
|
||||
g_free(buf);
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
struct kvm_create_device cd = {0};
|
||||
int ret;
|
||||
|
||||
flic_state->fd = -1;
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
|
||||
trace_flic_no_device_api(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
cd.type = KVM_DEV_TYPE_FLIC;
|
||||
ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
|
||||
if (ret < 0) {
|
||||
trace_flic_create_device(errno);
|
||||
return;
|
||||
}
|
||||
flic_state->fd = cd.fd;
|
||||
|
||||
/* Register savevm handler for floating interrupts */
|
||||
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
|
||||
kvm_flic_load, (void *) flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
|
||||
unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_reset(DeviceState *dev)
|
||||
{
|
||||
KVMS390FLICState *flic = KVM_S390_FLIC(dev);
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_CLEAR_IRQS,
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
if (flic->fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
flic_disable_wait_pfault(flic);
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
if (rc) {
|
||||
trace_flic_reset_failed(errno);
|
||||
}
|
||||
|
||||
flic_enable_pfault(flic);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = kvm_s390_flic_realize;
|
||||
dc->unrealize = kvm_s390_flic_unrealize;
|
||||
dc->reset = kvm_s390_flic_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_s390_flic_info = {
|
||||
.name = TYPE_KVM_S390_FLIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(KVMS390FLICState),
|
||||
.class_init = kvm_s390_flic_class_init,
|
||||
static const TypeInfo qemu_s390_flic_info = {
|
||||
.name = TYPE_QEMU_S390_FLIC,
|
||||
.parent = TYPE_S390_FLIC_COMMON,
|
||||
.instance_size = sizeof(QEMUS390FLICState),
|
||||
.class_init = qemu_s390_flic_class_init,
|
||||
};
|
||||
|
||||
static void kvm_s390_flic_register_types(void)
|
||||
static const TypeInfo s390_flic_common_info = {
|
||||
.name = TYPE_S390_FLIC_COMMON,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(S390FLICState),
|
||||
.class_size = sizeof(S390FLICStateClass),
|
||||
};
|
||||
|
||||
static void qemu_s390_flic_register_types(void)
|
||||
{
|
||||
type_register_static(&kvm_s390_flic_info);
|
||||
type_register_static(&s390_flic_common_info);
|
||||
type_register_static(&qemu_s390_flic_info);
|
||||
}
|
||||
|
||||
type_init(kvm_s390_flic_register_types)
|
||||
type_init(qemu_s390_flic_register_types)
|
||||
|
420
hw/intc/s390_flic_kvm.c
Normal file
420
hw/intc/s390_flic_kvm.c
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* QEMU S390x KVM floating interrupt controller (flic)
|
||||
*
|
||||
* Copyright 2014 IBM Corp.
|
||||
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "migration/qemu-file.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "hw/s390x/adapter.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define FLIC_SAVE_INITIAL_SIZE getpagesize()
|
||||
#define FLIC_FAILED (-1UL)
|
||||
#define FLIC_SAVEVM_VERSION 1
|
||||
|
||||
typedef struct KVMS390FLICState {
|
||||
S390FLICState parent_obj;
|
||||
|
||||
uint32_t fd;
|
||||
} KVMS390FLICState;
|
||||
|
||||
DeviceState *s390_flic_kvm_create(void)
|
||||
{
|
||||
DeviceState *dev = NULL;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
dev = qdev_create(NULL, TYPE_KVM_S390_FLIC);
|
||||
object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC,
|
||||
OBJECT(dev), NULL);
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* flic_get_all_irqs - store all pending irqs in buffer
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -ENOMEM if buffer is too small,
|
||||
* -EINVAL if attr.group is invalid,
|
||||
* -EFAULT if copying to userspace failed,
|
||||
* on success return number of stored interrupts
|
||||
*/
|
||||
static int flic_get_all_irqs(KVMS390FLICState *flic,
|
||||
void *buf, int len)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_GET_ALL_IRQS,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc == -1 ? -errno : rc;
|
||||
}
|
||||
|
||||
static void flic_enable_pfault(KVMS390FLICState *flic)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_ENABLE,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't enable pfault\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void flic_disable_wait_pfault(KVMS390FLICState *flic)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't disable pfault\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** flic_enqueue_irqs - returns 0 on success
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -EINVAL if attr.group is unknown
|
||||
*/
|
||||
static int flic_enqueue_irqs(void *buf, uint64_t len,
|
||||
KVMS390FLICState *flic)
|
||||
{
|
||||
int rc;
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_ENQUEUE,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc ? -errno : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __get_all_irqs - store all pending irqs in buffer
|
||||
* @flic: pointer to flic device state
|
||||
* @buf: pointer to pointer to a buffer
|
||||
* @len: length of buffer
|
||||
*
|
||||
* Returns: return value of flic_get_all_irqs
|
||||
* Note: Retry and increase buffer size until flic_get_all_irqs
|
||||
* either returns a value >= 0 or a negative error code.
|
||||
* -ENOMEM is an exception, which means the buffer is too small
|
||||
* and we should try again. Other negative error codes can be
|
||||
* -EFAULT and -EINVAL which we ignore at this point
|
||||
*/
|
||||
static int __get_all_irqs(KVMS390FLICState *flic,
|
||||
void **buf, int len)
|
||||
{
|
||||
int r;
|
||||
|
||||
do {
|
||||
/* returns -ENOMEM if buffer is too small and number
|
||||
* of queued interrupts on success */
|
||||
r = flic_get_all_irqs(flic, *buf, len);
|
||||
if (r >= 0) {
|
||||
break;
|
||||
}
|
||||
len *= 2;
|
||||
*buf = g_try_realloc(*buf, len);
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
} while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
|
||||
uint8_t isc, bool swap,
|
||||
bool is_maskable)
|
||||
{
|
||||
struct kvm_s390_io_adapter adapter = {
|
||||
.id = id,
|
||||
.isc = isc,
|
||||
.maskable = is_maskable,
|
||||
.swap = swap,
|
||||
};
|
||||
KVMS390FLICState *flic = KVM_S390_FLIC(fs);
|
||||
int r, ret;
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_ADAPTER_REGISTER,
|
||||
.addr = (uint64_t)&adapter,
|
||||
};
|
||||
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
ret = r ? -errno : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
|
||||
uint64_t map_addr, bool do_map)
|
||||
{
|
||||
struct kvm_s390_io_adapter_req req = {
|
||||
.id = id,
|
||||
.type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
|
||||
.addr = map_addr,
|
||||
};
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_ADAPTER_MODIFY,
|
||||
.addr = (uint64_t)&req,
|
||||
};
|
||||
KVMS390FLICState *flic = KVM_S390_FLIC(fs);
|
||||
int r;
|
||||
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
return r ? -errno : 0;
|
||||
}
|
||||
|
||||
static int kvm_s390_add_adapter_routes(S390FLICState *fs,
|
||||
AdapterRoutes *routes)
|
||||
{
|
||||
int ret, i;
|
||||
uint64_t ind_offset = routes->adapter.ind_offset;
|
||||
|
||||
for (i = 0; i < routes->num_routes; i++) {
|
||||
ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
|
||||
if (ret < 0) {
|
||||
goto out_undo;
|
||||
}
|
||||
routes->gsi[i] = ret;
|
||||
routes->adapter.ind_offset++;
|
||||
}
|
||||
/* Restore passed-in structure to original state. */
|
||||
routes->adapter.ind_offset = ind_offset;
|
||||
return 0;
|
||||
out_undo:
|
||||
while (--i >= 0) {
|
||||
kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
|
||||
routes->gsi[i] = -1;
|
||||
}
|
||||
routes->adapter.ind_offset = ind_offset;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kvm_s390_release_adapter_routes(S390FLICState *fs,
|
||||
AdapterRoutes *routes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < routes->num_routes; i++) {
|
||||
if (routes->gsi[i] >= 0) {
|
||||
kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
|
||||
routes->gsi[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_save - Save pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
*
|
||||
* Note: Pass buf and len to kernel. Start with one page and
|
||||
* increase until buffer is sufficient or maxium size is
|
||||
* reached
|
||||
*/
|
||||
static void kvm_flic_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
KVMS390FLICState *flic = opaque;
|
||||
int len = FLIC_SAVE_INITIAL_SIZE;
|
||||
void *buf;
|
||||
int count;
|
||||
|
||||
flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
error_report("flic: couldn't allocate memory");
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
count = __get_all_irqs(flic, &buf, len);
|
||||
if (count < 0) {
|
||||
error_report("flic: couldn't retrieve irqs from kernel, rc %d",
|
||||
count);
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
} else {
|
||||
qemu_put_be64(f, count);
|
||||
qemu_put_buffer(f, (uint8_t *) buf,
|
||||
count * sizeof(struct kvm_s390_irq));
|
||||
}
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_load - Load pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
* @version_id: version id for migration
|
||||
*
|
||||
* Returns: value of flic_enqueue_irqs, -EINVAL on error
|
||||
* Note: Do nothing when no interrupts where stored
|
||||
* in QEMUFile
|
||||
*/
|
||||
static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
uint64_t len = 0;
|
||||
uint64_t count = 0;
|
||||
void *buf = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (version_id != FLIC_SAVEVM_VERSION) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
flic_enable_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
count = qemu_get_be64(f);
|
||||
len = count * sizeof(struct kvm_s390_irq);
|
||||
if (count == FLIC_FAILED) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (count == 0) {
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
|
||||
r = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
|
||||
|
||||
out_free:
|
||||
g_free(buf);
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
struct kvm_create_device cd = {0};
|
||||
int ret;
|
||||
|
||||
flic_state->fd = -1;
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
|
||||
trace_flic_no_device_api(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
cd.type = KVM_DEV_TYPE_FLIC;
|
||||
ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
|
||||
if (ret < 0) {
|
||||
trace_flic_create_device(errno);
|
||||
return;
|
||||
}
|
||||
flic_state->fd = cd.fd;
|
||||
|
||||
/* Register savevm handler for floating interrupts */
|
||||
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
|
||||
kvm_flic_load, (void *) flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
|
||||
unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_reset(DeviceState *dev)
|
||||
{
|
||||
KVMS390FLICState *flic = KVM_S390_FLIC(dev);
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_CLEAR_IRQS,
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
if (flic->fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
flic_disable_wait_pfault(flic);
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
if (rc) {
|
||||
trace_flic_reset_failed(errno);
|
||||
}
|
||||
|
||||
flic_enable_pfault(flic);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
|
||||
|
||||
dc->realize = kvm_s390_flic_realize;
|
||||
dc->unrealize = kvm_s390_flic_unrealize;
|
||||
dc->reset = kvm_s390_flic_reset;
|
||||
fsc->register_io_adapter = kvm_s390_register_io_adapter;
|
||||
fsc->io_adapter_map = kvm_s390_io_adapter_map;
|
||||
fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
|
||||
fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_s390_flic_info = {
|
||||
.name = TYPE_KVM_S390_FLIC,
|
||||
.parent = TYPE_S390_FLIC_COMMON,
|
||||
.instance_size = sizeof(KVMS390FLICState),
|
||||
.class_init = kvm_s390_flic_class_init,
|
||||
};
|
||||
|
||||
static void kvm_s390_flic_register_types(void)
|
||||
{
|
||||
type_register_static(&kvm_s390_flic_info);
|
||||
}
|
||||
|
||||
type_init(kvm_s390_flic_register_types)
|
@@ -16,6 +16,7 @@
|
||||
#include "ioinst.h"
|
||||
#include "css.h"
|
||||
#include "trace.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
|
||||
typedef struct CrwContainer {
|
||||
CRW crw;
|
||||
@@ -39,6 +40,13 @@ typedef struct CssImage {
|
||||
ChpInfo chpids[MAX_CHPID + 1];
|
||||
} CssImage;
|
||||
|
||||
typedef struct IoAdapter {
|
||||
uint32_t id;
|
||||
uint8_t type;
|
||||
uint8_t isc;
|
||||
QTAILQ_ENTRY(IoAdapter) sibling;
|
||||
} IoAdapter;
|
||||
|
||||
typedef struct ChannelSubSys {
|
||||
QTAILQ_HEAD(, CrwContainer) pending_crws;
|
||||
bool do_crw_mchk;
|
||||
@@ -49,6 +57,7 @@ typedef struct ChannelSubSys {
|
||||
uint64_t chnmon_area;
|
||||
CssImage *css[MAX_CSSID + 1];
|
||||
uint8_t default_cssid;
|
||||
QTAILQ_HEAD(, IoAdapter) io_adapters;
|
||||
} ChannelSubSys;
|
||||
|
||||
static ChannelSubSys *channel_subsys;
|
||||
@@ -69,6 +78,46 @@ int css_create_css_image(uint8_t cssid, bool default_image)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
|
||||
bool maskable, uint32_t *id)
|
||||
{
|
||||
IoAdapter *adapter;
|
||||
bool found = false;
|
||||
int ret;
|
||||
S390FLICState *fs = s390_get_flic();
|
||||
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
|
||||
|
||||
*id = 0;
|
||||
QTAILQ_FOREACH(adapter, &channel_subsys->io_adapters, sibling) {
|
||||
if ((adapter->type == type) && (adapter->isc == isc)) {
|
||||
*id = adapter->id;
|
||||
found = true;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (adapter->id >= *id) {
|
||||
*id = adapter->id + 1;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
goto out;
|
||||
}
|
||||
adapter = g_new0(IoAdapter, 1);
|
||||
ret = fsc->register_io_adapter(fs, *id, isc, swap, maskable);
|
||||
if (ret == 0) {
|
||||
adapter->id = *id;
|
||||
adapter->isc = isc;
|
||||
adapter->type = type;
|
||||
QTAILQ_INSERT_TAIL(&channel_subsys->io_adapters, adapter, sibling);
|
||||
} else {
|
||||
g_free(adapter);
|
||||
fprintf(stderr, "Unexpected error %d when registering adapter %d\n",
|
||||
ret, *id);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t css_build_subchannel_id(SubchDev *sch)
|
||||
{
|
||||
if (channel_subsys->max_cssid > 0) {
|
||||
@@ -1235,6 +1284,7 @@ static void css_init(void)
|
||||
channel_subsys->do_crw_mchk = true;
|
||||
channel_subsys->crws_lost = false;
|
||||
channel_subsys->chnmon_active = false;
|
||||
QTAILQ_INIT(&channel_subsys->io_adapters);
|
||||
}
|
||||
machine_init(css_init);
|
||||
|
||||
|
@@ -98,4 +98,8 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
|
||||
int hotplugged, int add);
|
||||
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
|
||||
void css_adapter_interrupt(uint8_t isc);
|
||||
|
||||
#define CSS_IO_ADAPTER_VIRTIO 1
|
||||
int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
|
||||
bool maskable, uint32_t *id);
|
||||
#endif
|
||||
|
@@ -21,12 +21,77 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/s390x/adapter.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
|
||||
#include "ioinst.h"
|
||||
#include "css.h"
|
||||
#include "virtio-ccw.h"
|
||||
#include "trace.h"
|
||||
|
||||
static QTAILQ_HEAD(, IndAddr) indicator_addresses =
|
||||
QTAILQ_HEAD_INITIALIZER(indicator_addresses);
|
||||
|
||||
static IndAddr *get_indicator(hwaddr ind_addr, int len)
|
||||
{
|
||||
IndAddr *indicator;
|
||||
|
||||
QTAILQ_FOREACH(indicator, &indicator_addresses, sibling) {
|
||||
if (indicator->addr == ind_addr) {
|
||||
indicator->refcnt++;
|
||||
return indicator;
|
||||
}
|
||||
}
|
||||
indicator = g_new0(IndAddr, 1);
|
||||
indicator->addr = ind_addr;
|
||||
indicator->len = len;
|
||||
indicator->refcnt = 1;
|
||||
QTAILQ_INSERT_TAIL(&indicator_addresses, indicator, sibling);
|
||||
return indicator;
|
||||
}
|
||||
|
||||
static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr,
|
||||
bool do_map)
|
||||
{
|
||||
S390FLICState *fs = s390_get_flic();
|
||||
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
|
||||
|
||||
return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
|
||||
}
|
||||
|
||||
static void release_indicator(AdapterInfo *adapter, IndAddr *indicator)
|
||||
{
|
||||
assert(indicator->refcnt > 0);
|
||||
indicator->refcnt--;
|
||||
if (indicator->refcnt > 0) {
|
||||
return;
|
||||
}
|
||||
QTAILQ_REMOVE(&indicator_addresses, indicator, sibling);
|
||||
if (indicator->map) {
|
||||
s390_io_adapter_map(adapter, indicator->map, false);
|
||||
}
|
||||
g_free(indicator);
|
||||
}
|
||||
|
||||
static int map_indicator(AdapterInfo *adapter, IndAddr *indicator)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (indicator->map) {
|
||||
return 0; /* already mapped is not an error */
|
||||
}
|
||||
indicator->map = indicator->addr;
|
||||
ret = s390_io_adapter_map(adapter, indicator->map, true);
|
||||
if ((ret != 0) && (ret != -ENOSYS)) {
|
||||
goto out_err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
indicator->map = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
|
||||
VirtioCcwDevice *dev);
|
||||
|
||||
@@ -445,7 +510,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
indicators = ldq_phys(&address_space_memory, ccw.cda);
|
||||
dev->indicators = indicators;
|
||||
dev->indicators = get_indicator(indicators, sizeof(uint64_t));
|
||||
sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
|
||||
ret = 0;
|
||||
}
|
||||
@@ -465,7 +530,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
indicators = ldq_phys(&address_space_memory, ccw.cda);
|
||||
dev->indicators2 = indicators;
|
||||
dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));
|
||||
sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
|
||||
ret = 0;
|
||||
}
|
||||
@@ -517,13 +582,20 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
len = hw_len;
|
||||
dev->summary_indicator = thinint->summary_indicator;
|
||||
dev->indicators = thinint->device_indicator;
|
||||
dev->summary_indicator =
|
||||
get_indicator(thinint->summary_indicator, sizeof(uint8_t));
|
||||
dev->indicators = get_indicator(thinint->device_indicator,
|
||||
thinint->ind_bit / 8 + 1);
|
||||
dev->thinint_isc = thinint->isc;
|
||||
dev->ind_bit = thinint->ind_bit;
|
||||
dev->routes.adapter.ind_offset = thinint->ind_bit;
|
||||
dev->routes.adapter.summary_offset = 7;
|
||||
cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
|
||||
sch->thinint_active = ((dev->indicators != 0) &&
|
||||
(dev->summary_indicator != 0));
|
||||
ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
|
||||
dev->thinint_isc, true, false,
|
||||
&dev->routes.adapter.adapter_id);
|
||||
assert(ret == 0);
|
||||
sch->thinint_active = ((dev->indicators != NULL) &&
|
||||
(dev->summary_indicator != NULL));
|
||||
sch->curr_status.scsw.count = ccw.count - len;
|
||||
ret = 0;
|
||||
}
|
||||
@@ -554,7 +626,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
sch->driver_data = dev;
|
||||
dev->sch = sch;
|
||||
|
||||
dev->indicators = 0;
|
||||
dev->indicators = NULL;
|
||||
|
||||
/* Initialize subchannel structure. */
|
||||
sch->channel_prog = 0x0;
|
||||
@@ -693,7 +765,10 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev)
|
||||
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
|
||||
g_free(sch);
|
||||
}
|
||||
dev->indicators = 0;
|
||||
if (dev->indicators) {
|
||||
release_indicator(&dev->routes.adapter, dev->indicators);
|
||||
dev->indicators = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -950,17 +1025,19 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
|
||||
* ind_bit indicates the start of the indicators in a big
|
||||
* endian notation.
|
||||
*/
|
||||
virtio_set_ind_atomic(sch, dev->indicators +
|
||||
(dev->ind_bit + vector) / 8,
|
||||
0x80 >> ((dev->ind_bit + vector) % 8));
|
||||
if (!virtio_set_ind_atomic(sch, dev->summary_indicator,
|
||||
uint64_t ind_bit = dev->routes.adapter.ind_offset;
|
||||
|
||||
virtio_set_ind_atomic(sch, dev->indicators->addr +
|
||||
(ind_bit + vector) / 8,
|
||||
0x80 >> ((ind_bit + vector) % 8));
|
||||
if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr,
|
||||
0x01)) {
|
||||
css_adapter_interrupt(dev->thinint_isc);
|
||||
}
|
||||
} else {
|
||||
indicators = ldq_phys(&address_space_memory, dev->indicators);
|
||||
indicators = ldq_phys(&address_space_memory, dev->indicators->addr);
|
||||
indicators |= 1ULL << vector;
|
||||
stq_phys(&address_space_memory, dev->indicators, indicators);
|
||||
stq_phys(&address_space_memory, dev->indicators->addr, indicators);
|
||||
css_conditional_io_interrupt(sch);
|
||||
}
|
||||
} else {
|
||||
@@ -968,9 +1045,9 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
|
||||
return;
|
||||
}
|
||||
vector = 0;
|
||||
indicators = ldq_phys(&address_space_memory, dev->indicators2);
|
||||
indicators = ldq_phys(&address_space_memory, dev->indicators2->addr);
|
||||
indicators |= 1ULL << vector;
|
||||
stq_phys(&address_space_memory, dev->indicators2, indicators);
|
||||
stq_phys(&address_space_memory, dev->indicators2->addr, indicators);
|
||||
css_conditional_io_interrupt(sch);
|
||||
}
|
||||
}
|
||||
@@ -991,9 +1068,18 @@ static void virtio_ccw_reset(DeviceState *d)
|
||||
virtio_ccw_stop_ioeventfd(dev);
|
||||
virtio_reset(vdev);
|
||||
css_reset_sch(dev->sch);
|
||||
dev->indicators = 0;
|
||||
dev->indicators2 = 0;
|
||||
dev->summary_indicator = 0;
|
||||
if (dev->indicators) {
|
||||
release_indicator(&dev->routes.adapter, dev->indicators);
|
||||
dev->indicators = NULL;
|
||||
}
|
||||
if (dev->indicators2) {
|
||||
release_indicator(&dev->routes.adapter, dev->indicators2);
|
||||
dev->indicators2 = NULL;
|
||||
}
|
||||
if (dev->summary_indicator) {
|
||||
release_indicator(&dev->routes.adapter, dev->summary_indicator);
|
||||
dev->summary_indicator = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
|
||||
@@ -1027,6 +1113,79 @@ static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign)
|
||||
return virtio_ccw_set_guest2host_notifier(dev, n, assign, false);
|
||||
}
|
||||
|
||||
static int virtio_ccw_get_mappings(VirtioCcwDevice *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!dev->sch->thinint_active) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = map_indicator(&dev->routes.adapter, dev->summary_indicator);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
r = map_indicator(&dev->routes.adapter, dev->indicators);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
dev->routes.adapter.summary_addr = dev->summary_indicator->map;
|
||||
dev->routes.adapter.ind_addr = dev->indicators->map;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs)
|
||||
{
|
||||
int i;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
int ret;
|
||||
S390FLICState *fs = s390_get_flic();
|
||||
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
|
||||
|
||||
ret = virtio_ccw_get_mappings(dev);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
for (i = 0; i < nvqs; i++) {
|
||||
if (!virtio_queue_get_num(vdev, i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
dev->routes.num_routes = i;
|
||||
return fsc->add_adapter_routes(fs, &dev->routes);
|
||||
}
|
||||
|
||||
static void virtio_ccw_release_irqroutes(VirtioCcwDevice *dev, int nvqs)
|
||||
{
|
||||
S390FLICState *fs = s390_get_flic();
|
||||
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
|
||||
|
||||
fsc->release_adapter_routes(fs, &dev->routes);
|
||||
}
|
||||
|
||||
static int virtio_ccw_add_irqfd(VirtioCcwDevice *dev, int n)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, n);
|
||||
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
|
||||
|
||||
return kvm_irqchip_add_irqfd_notifier(kvm_state, notifier, NULL,
|
||||
dev->routes.gsi[n]);
|
||||
}
|
||||
|
||||
static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, n);
|
||||
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
|
||||
int ret;
|
||||
|
||||
ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, notifier,
|
||||
dev->routes.gsi[n]);
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
|
||||
bool assign, bool with_irqfd)
|
||||
{
|
||||
@@ -1042,11 +1201,17 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
|
||||
return r;
|
||||
}
|
||||
virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
|
||||
/* We do not support irqfd for classic I/O interrupts, because the
|
||||
* classic interrupts are intermixed with the subchannel status, that
|
||||
* is queried with test subchannel. We want to use vhost, though.
|
||||
* Lets make sure to have vhost running and wire up the irq fd to
|
||||
* land in qemu (and only the irq fd) in this code.
|
||||
if (with_irqfd) {
|
||||
r = virtio_ccw_add_irqfd(dev, n);
|
||||
if (r) {
|
||||
virtio_queue_set_guest_notifier_fd_handler(vq, false,
|
||||
with_irqfd);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* We do not support individual masking for channel devices, so we
|
||||
* need to manually trigger any guest masking callbacks here.
|
||||
*/
|
||||
if (k->guest_notifier_mask) {
|
||||
k->guest_notifier_mask(vdev, n, false);
|
||||
@@ -1060,6 +1225,9 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
|
||||
if (k->guest_notifier_mask) {
|
||||
k->guest_notifier_mask(vdev, n, true);
|
||||
}
|
||||
if (with_irqfd) {
|
||||
virtio_ccw_remove_irqfd(dev, n);
|
||||
}
|
||||
virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
|
||||
event_notifier_cleanup(notifier);
|
||||
}
|
||||
@@ -1071,24 +1239,39 @@ static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs,
|
||||
{
|
||||
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled();
|
||||
int r, n;
|
||||
|
||||
if (with_irqfd && assigned) {
|
||||
/* irq routes need to be set up before assigning irqfds */
|
||||
r = virtio_ccw_setup_irqroutes(dev, nvqs);
|
||||
if (r < 0) {
|
||||
goto irqroute_error;
|
||||
}
|
||||
}
|
||||
for (n = 0; n < nvqs; n++) {
|
||||
if (!virtio_queue_get_num(vdev, n)) {
|
||||
break;
|
||||
}
|
||||
/* false -> true, as soon as irqfd works */
|
||||
r = virtio_ccw_set_guest_notifier(dev, n, assigned, false);
|
||||
r = virtio_ccw_set_guest_notifier(dev, n, assigned, with_irqfd);
|
||||
if (r < 0) {
|
||||
goto assign_error;
|
||||
}
|
||||
}
|
||||
if (with_irqfd && !assigned) {
|
||||
/* release irq routes after irqfds have been released */
|
||||
virtio_ccw_release_irqroutes(dev, nvqs);
|
||||
}
|
||||
return 0;
|
||||
|
||||
assign_error:
|
||||
while (--n >= 0) {
|
||||
virtio_ccw_set_guest_notifier(dev, n, !assigned, false);
|
||||
}
|
||||
irqroute_error:
|
||||
if (with_irqfd && assigned) {
|
||||
virtio_ccw_release_irqroutes(dev, nvqs);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <hw/virtio/virtio-balloon.h>
|
||||
#include <hw/virtio/virtio-rng.h>
|
||||
#include <hw/virtio/virtio-bus.h>
|
||||
#include <hw/s390x/s390_flic.h>
|
||||
|
||||
#define VIRTUAL_CSSID 0xfe
|
||||
|
||||
@@ -75,6 +76,14 @@ typedef struct VirtIOCCWDeviceClass {
|
||||
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1
|
||||
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT)
|
||||
|
||||
typedef struct IndAddr {
|
||||
hwaddr addr;
|
||||
uint64_t map;
|
||||
unsigned long refcnt;
|
||||
int len;
|
||||
QTAILQ_ENTRY(IndAddr) sibling;
|
||||
} IndAddr;
|
||||
|
||||
struct VirtioCcwDevice {
|
||||
DeviceState parent_obj;
|
||||
SubchDev *sch;
|
||||
@@ -85,10 +94,11 @@ struct VirtioCcwDevice {
|
||||
bool ioeventfd_disabled;
|
||||
uint32_t flags;
|
||||
uint8_t thinint_isc;
|
||||
AdapterRoutes routes;
|
||||
/* Guest provided values: */
|
||||
hwaddr indicators;
|
||||
hwaddr indicators2;
|
||||
hwaddr summary_indicator;
|
||||
IndAddr *indicators;
|
||||
IndAddr *indicators2;
|
||||
IndAddr *summary_indicator;
|
||||
uint64_t ind_bit;
|
||||
};
|
||||
|
||||
|
@@ -728,8 +728,8 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
|
||||
snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
|
||||
memcpy(info.image_component[0].name, "APP", 3);
|
||||
memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
|
||||
memcpy(info.image_component[0].build_date, __DATE__, 11);
|
||||
memcpy(info.image_component[0].build_time, __TIME__, 8);
|
||||
memcpy(info.image_component[0].build_date, "Apr 1 2014", 11);
|
||||
memcpy(info.image_component[0].build_time, "12:34:56", 8);
|
||||
info.image_component_count = 1;
|
||||
if (pci_dev->has_rom) {
|
||||
uint8_t biosver[32];
|
||||
|
@@ -938,6 +938,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
if (cmd->xfer == 0) {
|
||||
cmd->xfer = 256;
|
||||
}
|
||||
/* fall through */
|
||||
case WRITE_10:
|
||||
case WRITE_VERIFY_10:
|
||||
case WRITE_12:
|
||||
@@ -952,6 +953,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
if (cmd->xfer == 0) {
|
||||
cmd->xfer = 256;
|
||||
}
|
||||
/* fall through */
|
||||
case READ_10:
|
||||
case RECOVER_BUFFERED_DATA:
|
||||
case READ_12:
|
||||
|
@@ -498,7 +498,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
|
||||
uint32_t event, uint32_t reason)
|
||||
{
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||
VirtIOSCSIReq *req = virtio_scsi_pop_req(s, vs->event_vq);
|
||||
VirtIOSCSIReq *req;
|
||||
VirtIOSCSIEvent *evt;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
int in_size;
|
||||
@@ -507,6 +507,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
|
||||
return;
|
||||
}
|
||||
|
||||
req = virtio_scsi_pop_req(s, vs->event_vq);
|
||||
if (!req) {
|
||||
s->events_dropped = true;
|
||||
return;
|
||||
|
@@ -120,6 +120,8 @@ typedef enum {
|
||||
/* BDRV_BLOCK_DATA: data is read from bs->file or another file
|
||||
* BDRV_BLOCK_ZERO: sectors read as zero
|
||||
* BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data
|
||||
* BDRV_BLOCK_ALLOCATED: the content of the block is determined by this
|
||||
* layer (as opposed to the backing file)
|
||||
* BDRV_BLOCK_RAW: used internally to indicate that the request
|
||||
* was answered by the raw driver and that one
|
||||
* should look in bs->file directly.
|
||||
@@ -141,10 +143,11 @@ typedef enum {
|
||||
* f t f not allocated or unknown offset, read as zero
|
||||
* f f f not allocated or unknown offset, read from backing_hd
|
||||
*/
|
||||
#define BDRV_BLOCK_DATA 1
|
||||
#define BDRV_BLOCK_ZERO 2
|
||||
#define BDRV_BLOCK_OFFSET_VALID 4
|
||||
#define BDRV_BLOCK_RAW 8
|
||||
#define BDRV_BLOCK_DATA 0x01
|
||||
#define BDRV_BLOCK_ZERO 0x02
|
||||
#define BDRV_BLOCK_OFFSET_VALID 0x04
|
||||
#define BDRV_BLOCK_RAW 0x08
|
||||
#define BDRV_BLOCK_ALLOCATED 0x10
|
||||
#define BDRV_BLOCK_OFFSET_MASK BDRV_SECTOR_MASK
|
||||
|
||||
typedef enum {
|
||||
|
@@ -364,6 +364,7 @@ struct BlockDriverState {
|
||||
BlockJob *job;
|
||||
|
||||
QDict *options;
|
||||
BlockdevDetectZeroesOptions detect_zeroes;
|
||||
};
|
||||
|
||||
int get_tmp_filename(char *filename, int size);
|
||||
|
23
include/hw/s390x/adapter.h
Normal file
23
include/hw/s390x/adapter.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* s390 adapter definitions
|
||||
*
|
||||
* Copyright 2013,2014 IBM Corp.
|
||||
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#ifndef S390X_ADAPTER_H
|
||||
#define S390X_ADAPTER_H
|
||||
|
||||
struct AdapterInfo {
|
||||
uint64_t ind_addr;
|
||||
uint64_t summary_addr;
|
||||
uint64_t ind_offset;
|
||||
uint32_t summary_offset;
|
||||
uint32_t adapter_id;
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,33 +1,76 @@
|
||||
/*
|
||||
* QEMU S390x KVM floating interrupt controller (flic)
|
||||
* QEMU S390x floating interrupt controller (flic)
|
||||
*
|
||||
* Copyright 2014 IBM Corp.
|
||||
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#ifndef __KVM_S390_FLIC_H
|
||||
#define __KVM_S390_FLIC_H
|
||||
#ifndef __HW_S390_FLIC_H
|
||||
#define __HW_S390_FLIC_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/s390x/adapter.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
|
||||
#define TYPE_KVM_S390_FLIC "s390-flic"
|
||||
typedef struct AdapterRoutes {
|
||||
AdapterInfo adapter;
|
||||
int num_routes;
|
||||
int gsi[VIRTIO_PCI_QUEUE_MAX];
|
||||
} AdapterRoutes;
|
||||
|
||||
#define TYPE_S390_FLIC_COMMON "s390-flic"
|
||||
#define S390_FLIC_COMMON(obj) \
|
||||
OBJECT_CHECK(S390FLICState, (obj), TYPE_S390_FLIC_COMMON)
|
||||
|
||||
typedef struct S390FLICState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
} S390FLICState;
|
||||
|
||||
#define S390_FLIC_COMMON_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(S390FLICStateClass, (klass), TYPE_S390_FLIC_COMMON)
|
||||
#define S390_FLIC_COMMON_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(S390FLICStateClass, (obj), TYPE_S390_FLIC_COMMON)
|
||||
|
||||
typedef struct S390FLICStateClass {
|
||||
DeviceClass parent_class;
|
||||
|
||||
int (*register_io_adapter)(S390FLICState *fs, uint32_t id, uint8_t isc,
|
||||
bool swap, bool maskable);
|
||||
int (*io_adapter_map)(S390FLICState *fs, uint32_t id, uint64_t map_addr,
|
||||
bool do_map);
|
||||
int (*add_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
|
||||
void (*release_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
|
||||
} S390FLICStateClass;
|
||||
|
||||
#define TYPE_KVM_S390_FLIC "s390-flic-kvm"
|
||||
#define KVM_S390_FLIC(obj) \
|
||||
OBJECT_CHECK(KVMS390FLICState, (obj), TYPE_KVM_S390_FLIC)
|
||||
|
||||
typedef struct KVMS390FLICState {
|
||||
SysBusDevice parent_obj;
|
||||
#define TYPE_QEMU_S390_FLIC "s390-flic-qemu"
|
||||
#define QEMU_S390_FLIC(obj) \
|
||||
OBJECT_CHECK(QEMUS390FLICState, (obj), TYPE_QEMU_S390_FLIC)
|
||||
|
||||
uint32_t fd;
|
||||
} KVMS390FLICState;
|
||||
typedef struct QEMUS390FLICState {
|
||||
S390FLICState parent_obj;
|
||||
} QEMUS390FLICState;
|
||||
|
||||
void s390_flic_init(void);
|
||||
|
||||
S390FLICState *s390_get_flic(void);
|
||||
|
||||
#ifdef CONFIG_KVM
|
||||
void s390_flic_init(void);
|
||||
DeviceState *s390_flic_kvm_create(void);
|
||||
#else
|
||||
static inline void s390_flic_init(void) { }
|
||||
static inline DeviceState *s390_flic_kvm_create(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __KVM_S390_FLIC_H */
|
||||
#endif /* __HW_S390_FLIC_H */
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "qapi/qmp/qobject.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qemu/queue.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define QDICT_BUCKET_MAX 512
|
||||
@@ -70,4 +71,6 @@ void qdict_flatten(QDict *qdict);
|
||||
void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
|
||||
void qdict_array_split(QDict *src, QList **dst);
|
||||
|
||||
void qdict_join(QDict *dest, QDict *src, bool overwrite);
|
||||
|
||||
#endif /* QDICT_H */
|
||||
|
@@ -318,6 +318,7 @@ void qemu_iovec_concat(QEMUIOVector *dst,
|
||||
void qemu_iovec_concat_iov(QEMUIOVector *dst,
|
||||
struct iovec *src_iov, unsigned int src_cnt,
|
||||
size_t soffset, size_t sbytes);
|
||||
bool qemu_iovec_is_zero(QEMUIOVector *qiov);
|
||||
void qemu_iovec_destroy(QEMUIOVector *qiov);
|
||||
void qemu_iovec_reset(QEMUIOVector *qiov);
|
||||
size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
|
||||
|
@@ -74,5 +74,6 @@ typedef struct SHPCDevice SHPCDevice;
|
||||
typedef struct FWCfgState FWCfgState;
|
||||
typedef struct PcGuestInfo PcGuestInfo;
|
||||
typedef struct Range Range;
|
||||
typedef struct AdapterInfo AdapterInfo;
|
||||
|
||||
#endif /* QEMU_TYPEDEFS_H */
|
||||
|
@@ -300,7 +300,7 @@ int kvm_check_extension(KVMState *s, unsigned int extension);
|
||||
}; \
|
||||
uint64_t args_tmp[] = { __VA_ARGS__ }; \
|
||||
int i; \
|
||||
for (i = 0; i < ARRAY_SIZE(args_tmp) && \
|
||||
for (i = 0; i < (int)ARRAY_SIZE(args_tmp) && \
|
||||
i < ARRAY_SIZE(cap.args); i++) { \
|
||||
cap.args[i] = args_tmp[i]; \
|
||||
} \
|
||||
@@ -315,7 +315,7 @@ int kvm_check_extension(KVMState *s, unsigned int extension);
|
||||
}; \
|
||||
uint64_t args_tmp[] = { __VA_ARGS__ }; \
|
||||
int i; \
|
||||
for (i = 0; i < ARRAY_SIZE(args_tmp) && \
|
||||
for (i = 0; i < (int)ARRAY_SIZE(args_tmp) && \
|
||||
i < ARRAY_SIZE(cap.args); i++) { \
|
||||
cap.args[i] = args_tmp[i]; \
|
||||
} \
|
||||
@@ -363,6 +363,8 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
|
||||
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
|
||||
void kvm_irqchip_release_virq(KVMState *s, int virq);
|
||||
|
||||
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter);
|
||||
|
||||
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
|
||||
EventNotifier *rn, int virq);
|
||||
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
|
||||
|
@@ -81,6 +81,7 @@ void do_mouse_set(Monitor *mon, const QDict *qdict);
|
||||
#define QEMU_KEY_CTRL_PAGEUP 0xe406
|
||||
#define QEMU_KEY_CTRL_PAGEDOWN 0xe407
|
||||
|
||||
void kbd_put_keysym_console(QemuConsole *s, int keysym);
|
||||
void kbd_put_keysym(int keysym);
|
||||
|
||||
/* consoles */
|
||||
|
38
kvm-all.c
38
kvm-all.c
@@ -27,6 +27,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/s390x/adapter.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "qemu/bswap.h"
|
||||
@@ -1236,6 +1237,35 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int rfd, int virq,
|
||||
return kvm_vm_ioctl(s, KVM_IRQFD, &irqfd);
|
||||
}
|
||||
|
||||
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
|
||||
{
|
||||
struct kvm_irq_routing_entry kroute;
|
||||
int virq;
|
||||
|
||||
if (!kvm_gsi_routing_enabled()) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
virq = kvm_irqchip_get_virq(s);
|
||||
if (virq < 0) {
|
||||
return virq;
|
||||
}
|
||||
|
||||
kroute.gsi = virq;
|
||||
kroute.type = KVM_IRQ_ROUTING_S390_ADAPTER;
|
||||
kroute.flags = 0;
|
||||
kroute.u.adapter.summary_addr = adapter->summary_addr;
|
||||
kroute.u.adapter.ind_addr = adapter->ind_addr;
|
||||
kroute.u.adapter.summary_offset = adapter->summary_offset;
|
||||
kroute.u.adapter.ind_offset = adapter->ind_offset;
|
||||
kroute.u.adapter.adapter_id = adapter->adapter_id;
|
||||
|
||||
kvm_add_routing_entry(s, &kroute);
|
||||
kvm_irqchip_commit_routes(s);
|
||||
|
||||
return virq;
|
||||
}
|
||||
|
||||
#else /* !KVM_CAP_IRQ_ROUTING */
|
||||
|
||||
void kvm_init_irq_routing(KVMState *s)
|
||||
@@ -1256,6 +1286,11 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
|
||||
{
|
||||
abort();
|
||||
@@ -1285,7 +1320,8 @@ static int kvm_irqchip_create(KVMState *s)
|
||||
int ret;
|
||||
|
||||
if (!qemu_opt_get_bool(qemu_get_machine_opts(), "kernel_irqchip", true) ||
|
||||
!kvm_check_extension(s, KVM_CAP_IRQCHIP)) {
|
||||
(!kvm_check_extension(s, KVM_CAP_IRQCHIP) &&
|
||||
(kvm_vm_enable_cap(s, KVM_CAP_S390_IRQCHIP, 0) < 0))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -136,6 +136,11 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
|
||||
EventNotifier *rn, int virq)
|
||||
{
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
#define __KVM_S390
|
||||
#define __KVM_HAVE_GUEST_DEBUG
|
||||
|
||||
/* Device control API: s390-specific devices */
|
||||
#define KVM_DEV_FLIC_GET_ALL_IRQS 1
|
||||
@@ -54,6 +55,13 @@ struct kvm_s390_io_adapter_req {
|
||||
__u64 addr;
|
||||
};
|
||||
|
||||
/* kvm attr_group on vm fd */
|
||||
#define KVM_S390_VM_MEM_CTRL 0
|
||||
|
||||
/* kvm attributes for mem_ctrl */
|
||||
#define KVM_S390_VM_MEM_ENABLE_CMMA 0
|
||||
#define KVM_S390_VM_MEM_CLR_CMMA 1
|
||||
|
||||
/* for KVM_GET_REGS and KVM_SET_REGS */
|
||||
struct kvm_regs {
|
||||
/* general purpose regs for s390 */
|
||||
@@ -72,11 +80,31 @@ struct kvm_fpu {
|
||||
__u64 fprs[16];
|
||||
};
|
||||
|
||||
#define KVM_GUESTDBG_USE_HW_BP 0x00010000
|
||||
|
||||
#define KVM_HW_BP 1
|
||||
#define KVM_HW_WP_WRITE 2
|
||||
#define KVM_SINGLESTEP 4
|
||||
|
||||
struct kvm_debug_exit_arch {
|
||||
__u64 addr;
|
||||
__u8 type;
|
||||
__u8 pad[7]; /* Should be set to 0 */
|
||||
};
|
||||
|
||||
struct kvm_hw_breakpoint {
|
||||
__u64 addr;
|
||||
__u64 phys_addr;
|
||||
__u64 len;
|
||||
__u8 type;
|
||||
__u8 pad[7]; /* Should be set to 0 */
|
||||
};
|
||||
|
||||
/* for KVM_SET_GUEST_DEBUG */
|
||||
struct kvm_guest_debug_arch {
|
||||
__u32 nr_hw_bp;
|
||||
__u32 pad; /* Should be set to 0 */
|
||||
struct kvm_hw_breakpoint *hw_bp;
|
||||
};
|
||||
|
||||
#define KVM_SYNC_PREFIX (1UL << 0)
|
||||
|
@@ -416,6 +416,8 @@ struct kvm_s390_psw {
|
||||
#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u
|
||||
#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u
|
||||
#define KVM_S390_MCHK 0xfffe1000u
|
||||
#define KVM_S390_INT_CLOCK_COMP 0xffff1004u
|
||||
#define KVM_S390_INT_CPU_TIMER 0xffff1005u
|
||||
#define KVM_S390_INT_VIRTIO 0xffff2603u
|
||||
#define KVM_S390_INT_SERVICE 0xffff2401u
|
||||
#define KVM_S390_INT_EMERGENCY 0xffff1201u
|
||||
@@ -515,6 +517,7 @@ enum {
|
||||
kvm_ioeventfd_flag_nr_pio,
|
||||
kvm_ioeventfd_flag_nr_deassign,
|
||||
kvm_ioeventfd_flag_nr_virtio_ccw_notify,
|
||||
kvm_ioeventfd_flag_nr_fast_mmio,
|
||||
kvm_ioeventfd_flag_nr_max,
|
||||
};
|
||||
|
||||
@@ -529,7 +532,7 @@ enum {
|
||||
struct kvm_ioeventfd {
|
||||
__u64 datamatch;
|
||||
__u64 addr; /* legal pio/mmio address */
|
||||
__u32 len; /* 1, 2, 4, or 8 bytes */
|
||||
__u32 len; /* 1, 2, 4, or 8 bytes; or 0 to ignore length */
|
||||
__s32 fd;
|
||||
__u32 flags;
|
||||
__u8 pad[36];
|
||||
@@ -743,6 +746,8 @@ struct kvm_ppc_smmu_info {
|
||||
#define KVM_CAP_IOAPIC_POLARITY_IGNORED 97
|
||||
#define KVM_CAP_ENABLE_CAP_VM 98
|
||||
#define KVM_CAP_S390_IRQCHIP 99
|
||||
#define KVM_CAP_IOEVENTFD_NO_LENGTH 100
|
||||
#define KVM_CAP_VM_ATTRIBUTES 101
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
@@ -691,7 +691,7 @@
|
||||
# Information about current migration process.
|
||||
#
|
||||
# @status: #optional string describing the current migration status.
|
||||
# As of 0.14.0 this can be 'active', 'completed', 'failed' or
|
||||
# As of 0.14.0 this can be 'setup', 'active', 'completed', 'failed' or
|
||||
# 'cancelled'. If this field is not returned, no migration process
|
||||
# has been initiated
|
||||
#
|
||||
@@ -942,6 +942,8 @@
|
||||
# @encryption_key_missing: true if the backing device is encrypted but an
|
||||
# valid encryption key is missing
|
||||
#
|
||||
# @detect_zeroes: detect and optimize zero writes (Since 2.1)
|
||||
#
|
||||
# @bps: total throughput limit in bytes per second is specified
|
||||
#
|
||||
# @bps_rd: read throughput limit in bytes per second is specified
|
||||
@@ -977,6 +979,7 @@
|
||||
'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
|
||||
'*backing_file': 'str', 'backing_file_depth': 'int',
|
||||
'encrypted': 'bool', 'encryption_key_missing': 'bool',
|
||||
'detect_zeroes': 'BlockdevDetectZeroesOptions',
|
||||
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
|
||||
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
|
||||
'image': 'ImageInfo',
|
||||
@@ -4254,6 +4257,22 @@
|
||||
{ 'enum': 'BlockdevDiscardOptions',
|
||||
'data': [ 'ignore', 'unmap' ] }
|
||||
|
||||
##
|
||||
# @BlockdevDetectZeroesOptions
|
||||
#
|
||||
# Describes the operation mode for the automatic conversion of plain
|
||||
# zero writes by the OS to driver specific optimized zero write commands.
|
||||
#
|
||||
# @off: Disabled (default)
|
||||
# @on: Enabled
|
||||
# @unmap: Enabled and even try to unmap blocks if possible. This requires
|
||||
# also that @BlockdevDiscardOptions is set to unmap for this device.
|
||||
#
|
||||
# Since: 2.1
|
||||
##
|
||||
{ 'enum': 'BlockdevDetectZeroesOptions',
|
||||
'data': [ 'off', 'on', 'unmap' ] }
|
||||
|
||||
##
|
||||
# @BlockdevAioOptions
|
||||
#
|
||||
@@ -4306,20 +4325,22 @@
|
||||
# Options that are available for all block devices, independent of the block
|
||||
# driver.
|
||||
#
|
||||
# @driver: block driver name
|
||||
# @id: #optional id by which the new block device can be referred to.
|
||||
# This is a required option on the top level of blockdev-add, and
|
||||
# currently not allowed on any other level.
|
||||
# @node-name: #optional the name of a block driver state node (Since 2.0)
|
||||
# @discard: #optional discard-related options (default: ignore)
|
||||
# @cache: #optional cache-related options
|
||||
# @aio: #optional AIO backend (default: threads)
|
||||
# @rerror: #optional how to handle read errors on the device
|
||||
# (default: report)
|
||||
# @werror: #optional how to handle write errors on the device
|
||||
# (default: enospc)
|
||||
# @read-only: #optional whether the block device should be read-only
|
||||
# (default: false)
|
||||
# @driver: block driver name
|
||||
# @id: #optional id by which the new block device can be referred to.
|
||||
# This is a required option on the top level of blockdev-add, and
|
||||
# currently not allowed on any other level.
|
||||
# @node-name: #optional the name of a block driver state node (Since 2.0)
|
||||
# @discard: #optional discard-related options (default: ignore)
|
||||
# @cache: #optional cache-related options
|
||||
# @aio: #optional AIO backend (default: threads)
|
||||
# @rerror: #optional how to handle read errors on the device
|
||||
# (default: report)
|
||||
# @werror: #optional how to handle write errors on the device
|
||||
# (default: enospc)
|
||||
# @read-only: #optional whether the block device should be read-only
|
||||
# (default: false)
|
||||
# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
|
||||
# (default: off)
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
@@ -4332,7 +4353,8 @@
|
||||
'*aio': 'BlockdevAioOptions',
|
||||
'*rerror': 'BlockdevOnError',
|
||||
'*werror': 'BlockdevOnError',
|
||||
'*read-only': 'bool' } }
|
||||
'*read-only': 'bool',
|
||||
'*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsFile
|
||||
|
@@ -70,11 +70,8 @@ static void add_format_to_seq(void *opaque, const char *fmt_name)
|
||||
{
|
||||
GSequence *seq = opaque;
|
||||
|
||||
if (!g_sequence_lookup(seq, (gpointer)fmt_name,
|
||||
compare_data, NULL)) {
|
||||
g_sequence_insert_sorted(seq, (gpointer)fmt_name,
|
||||
compare_data, NULL);
|
||||
}
|
||||
g_sequence_insert_sorted(seq, (gpointer)fmt_name,
|
||||
compare_data, NULL);
|
||||
}
|
||||
|
||||
static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
|
||||
|
@@ -414,6 +414,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
|
||||
" [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
|
||||
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
|
||||
" [,readonly=on|off][,copy-on-read=on|off]\n"
|
||||
" [,detect-zeroes=on|off|unmap]\n"
|
||||
" [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
|
||||
" [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n"
|
||||
" [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n"
|
||||
@@ -475,6 +476,11 @@ Open drive @option{file} as read-only. Guest write attempts will fail.
|
||||
@item copy-on-read=@var{copy-on-read}
|
||||
@var{copy-on-read} is "on" or "off" and enables whether to copy read backing
|
||||
file sectors into the image file.
|
||||
@item detect-zeroes=@var{detect-zeroes}
|
||||
@var{detect-zeroes} is "off", "on" or "unmap" and enables the automatic
|
||||
conversion of plain zero writes by the OS to driver specific optimized
|
||||
zero write commands. You may even choose "unmap" if @var{discard} is set
|
||||
to "unmap" to allow a zero write to be converted to an UNMAP operation.
|
||||
@end table
|
||||
|
||||
By default, the @option{cache=writeback} mode is used. It will report data
|
||||
@@ -2191,6 +2197,74 @@ qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img
|
||||
@end example
|
||||
|
||||
See also @url{http://www.gluster.org}.
|
||||
|
||||
@item HTTP/HTTPS/FTP/FTPS/TFTP
|
||||
QEMU supports read-only access to files accessed over http(s), ftp(s) and tftp.
|
||||
|
||||
Syntax using a single filename:
|
||||
@example
|
||||
<protocol>://[<username>[:<password>]@@]<host>/<path>
|
||||
@end example
|
||||
|
||||
where:
|
||||
@table @option
|
||||
@item protocol
|
||||
'http', 'https', 'ftp', 'ftps', or 'tftp'.
|
||||
|
||||
@item username
|
||||
Optional username for authentication to the remote server.
|
||||
|
||||
@item password
|
||||
Optional password for authentication to the remote server.
|
||||
|
||||
@item host
|
||||
Address of the remote server.
|
||||
|
||||
@item path
|
||||
Path on the remote server, including any query string.
|
||||
@end table
|
||||
|
||||
The following options are also supported:
|
||||
@table @option
|
||||
@item url
|
||||
The full URL when passing options to the driver explicitly.
|
||||
|
||||
@item readahead
|
||||
The amount of data to read ahead with each range request to the remote server.
|
||||
This value may optionally have the suffix 'T', 'G', 'M', 'K', 'k' or 'b'. If it
|
||||
does not have a suffix, it will be assumed to be in bytes. The value must be a
|
||||
multiple of 512 bytes. It defaults to 256k.
|
||||
|
||||
@item sslverify
|
||||
Whether to verify the remote server's certificate when connecting over SSL. It
|
||||
can have the value 'on' or 'off'. It defaults to 'on'.
|
||||
@end table
|
||||
|
||||
Note that when passing options to qemu explicitly, @option{driver} is the value
|
||||
of <protocol>.
|
||||
|
||||
Example: boot from a remote Fedora 20 live ISO image
|
||||
@example
|
||||
qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
|
||||
|
||||
qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
|
||||
@end example
|
||||
|
||||
Example: boot from a remote Fedora 20 cloud image using a local overlay for
|
||||
writes, copy-on-read, and a readahead of 64k
|
||||
@example
|
||||
qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2
|
||||
|
||||
qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on
|
||||
@end example
|
||||
|
||||
Example: boot from an image stored on a VMware vSphere server with a self-signed
|
||||
certificate using a local overlay for writes and a readahead of 64k
|
||||
@example
|
||||
qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k"@}' /tmp/test.qcow2
|
||||
|
||||
qemu-system-x86_64 -drive file=/tmp/test.qcow2
|
||||
@end example
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
|
@@ -2032,6 +2032,8 @@ Each json-object contain the following:
|
||||
- "iops_rd_max": read I/O operations max (json-int)
|
||||
- "iops_wr_max": write I/O operations max (json-int)
|
||||
- "iops_size": I/O size when limiting by iops (json-int)
|
||||
- "detect_zeroes": detect and optimize zero writing (json-string)
|
||||
- Possible values: "off", "on", "unmap"
|
||||
- "image": the detail of the image, it is a json-object containing
|
||||
the following:
|
||||
- "filename": image file name (json-string)
|
||||
@@ -2108,6 +2110,7 @@ Example:
|
||||
"iops_rd_max": 0,
|
||||
"iops_wr_max": 0,
|
||||
"iops_size": 0,
|
||||
"detect_zeroes": "on",
|
||||
"image":{
|
||||
"filename":"disks/test.qcow2",
|
||||
"format":"qcow2",
|
||||
@@ -2937,7 +2940,7 @@ block migration status.
|
||||
The main json-object contains the following:
|
||||
|
||||
- "status": migration status (json-string)
|
||||
- Possible values: "active", "completed", "failed", "cancelled"
|
||||
- Possible values: "setup", "active", "completed", "failed", "cancelled"
|
||||
- "total-time": total amount of ms since migration started. If
|
||||
migration has ended, it returns the total migration
|
||||
time (json-int)
|
||||
|
@@ -665,3 +665,35 @@ void qdict_array_split(QDict *src, QList **dst)
|
||||
qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
|
||||
* elements from src to dest.
|
||||
*
|
||||
* If an element from src has a key already present in dest, it will not be
|
||||
* moved unless overwrite is true.
|
||||
*
|
||||
* If overwrite is true, the conflicting values in dest will be discarded and
|
||||
* replaced by the corresponding values from src.
|
||||
*
|
||||
* Therefore, with overwrite being true, the src QDict will always be empty when
|
||||
* this function returns. If overwrite is false, the src QDict will be empty
|
||||
* iff there were no conflicts.
|
||||
*/
|
||||
void qdict_join(QDict *dest, QDict *src, bool overwrite)
|
||||
{
|
||||
const QDictEntry *entry, *next;
|
||||
|
||||
entry = qdict_first(src);
|
||||
while (entry) {
|
||||
next = qdict_next(src, entry);
|
||||
|
||||
if (overwrite || !qdict_haskey(dest, entry->key)) {
|
||||
qobject_incref(entry->value);
|
||||
qdict_put_obj(dest, entry->key, entry->value);
|
||||
qdict_del(src, entry->key);
|
||||
}
|
||||
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
|
@@ -111,7 +111,7 @@ bool has_%(argname)s = false;
|
||||
argname=c_var(argname), argtype=c_type(argtype))
|
||||
else:
|
||||
ret += mcgen('''
|
||||
%(argtype)s %(argname)s;
|
||||
%(argtype)s %(argname)s = {0};
|
||||
''',
|
||||
argname=c_var(argname), argtype=c_type(argtype))
|
||||
|
||||
|
@@ -116,7 +116,7 @@ class QAPISchema:
|
||||
continue
|
||||
try:
|
||||
fobj = open(include_path, 'r')
|
||||
except IOError as e:
|
||||
except IOError, e:
|
||||
raise QAPIExprError(expr_info,
|
||||
'%s: %s' % (e.strerror, include))
|
||||
exprs_include = QAPISchema(fobj, include, self.include_hist,
|
||||
|
@@ -86,6 +86,7 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
|
||||
CPUState *cpu, void *opaque);
|
||||
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
|
||||
int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
|
||||
|
@@ -489,6 +489,18 @@ hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
|
||||
return raddr;
|
||||
}
|
||||
|
||||
hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
|
||||
{
|
||||
hwaddr phys_addr;
|
||||
target_ulong page;
|
||||
|
||||
page = vaddr & TARGET_PAGE_MASK;
|
||||
phys_addr = cpu_get_phys_page_debug(cs, page);
|
||||
phys_addr += (vaddr & ~TARGET_PAGE_MASK);
|
||||
|
||||
return phys_addr;
|
||||
}
|
||||
|
||||
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
|
||||
{
|
||||
if (mask & PSW_MASK_WAIT) {
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* #define DEBUG_KVM */
|
||||
@@ -86,6 +87,14 @@
|
||||
#define ICPT_CPU_STOP 0x28
|
||||
#define ICPT_IO 0x40
|
||||
|
||||
static CPUWatchpoint hw_watchpoint;
|
||||
/*
|
||||
* We don't use a list because this structure is also used to transmit the
|
||||
* hardware breakpoints to the kernel.
|
||||
*/
|
||||
static struct kvm_hw_breakpoint *hw_breakpoints;
|
||||
static int nb_hw_breakpoints;
|
||||
|
||||
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
|
||||
KVM_CAP_LAST_INFO
|
||||
};
|
||||
@@ -320,12 +329,16 @@ static void *legacy_s390_alloc(size_t size)
|
||||
return mem == MAP_FAILED ? NULL : mem;
|
||||
}
|
||||
|
||||
/* DIAG 501 is used for sw breakpoints */
|
||||
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
|
||||
|
||||
int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
||||
{
|
||||
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
|
||||
|
||||
if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
|
||||
cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501, 4, 1)) {
|
||||
if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
|
||||
sizeof(diag_501), 0) ||
|
||||
cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501,
|
||||
sizeof(diag_501), 1)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
@@ -333,38 +346,140 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
||||
|
||||
int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
||||
{
|
||||
uint8_t t[4];
|
||||
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
|
||||
uint8_t t[sizeof(diag_501)];
|
||||
|
||||
if (cpu_memory_rw_debug(cs, bp->pc, t, 4, 0)) {
|
||||
if (cpu_memory_rw_debug(cs, bp->pc, t, sizeof(diag_501), 0)) {
|
||||
return -EINVAL;
|
||||
} else if (memcmp(t, diag_501, 4)) {
|
||||
} else if (memcmp(t, diag_501, sizeof(diag_501))) {
|
||||
return -EINVAL;
|
||||
} else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
|
||||
} else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
|
||||
sizeof(diag_501), 1)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct kvm_hw_breakpoint *find_hw_breakpoint(target_ulong addr,
|
||||
int len, int type)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < nb_hw_breakpoints; n++) {
|
||||
if (hw_breakpoints[n].addr == addr && hw_breakpoints[n].type == type &&
|
||||
(hw_breakpoints[n].len == len || len == -1)) {
|
||||
return &hw_breakpoints[n];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int insert_hw_breakpoint(target_ulong addr, int len, int type)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (find_hw_breakpoint(addr, len, type)) {
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
size = (nb_hw_breakpoints + 1) * sizeof(struct kvm_hw_breakpoint);
|
||||
|
||||
if (!hw_breakpoints) {
|
||||
nb_hw_breakpoints = 0;
|
||||
hw_breakpoints = (struct kvm_hw_breakpoint *)g_try_malloc(size);
|
||||
} else {
|
||||
hw_breakpoints =
|
||||
(struct kvm_hw_breakpoint *)g_try_realloc(hw_breakpoints, size);
|
||||
}
|
||||
|
||||
if (!hw_breakpoints) {
|
||||
nb_hw_breakpoints = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hw_breakpoints[nb_hw_breakpoints].addr = addr;
|
||||
hw_breakpoints[nb_hw_breakpoints].len = len;
|
||||
hw_breakpoints[nb_hw_breakpoints].type = type;
|
||||
|
||||
nb_hw_breakpoints++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_insert_hw_breakpoint(target_ulong addr,
|
||||
target_ulong len, int type)
|
||||
{
|
||||
return -ENOSYS;
|
||||
switch (type) {
|
||||
case GDB_BREAKPOINT_HW:
|
||||
type = KVM_HW_BP;
|
||||
break;
|
||||
case GDB_WATCHPOINT_WRITE:
|
||||
if (len < 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
type = KVM_HW_WP_WRITE;
|
||||
break;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
return insert_hw_breakpoint(addr, len, type);
|
||||
}
|
||||
|
||||
int kvm_arch_remove_hw_breakpoint(target_ulong addr,
|
||||
target_ulong len, int type)
|
||||
{
|
||||
return -ENOSYS;
|
||||
int size;
|
||||
struct kvm_hw_breakpoint *bp = find_hw_breakpoint(addr, len, type);
|
||||
|
||||
if (bp == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
nb_hw_breakpoints--;
|
||||
if (nb_hw_breakpoints > 0) {
|
||||
/*
|
||||
* In order to trim the array, move the last element to the position to
|
||||
* be removed - if necessary.
|
||||
*/
|
||||
if (bp != &hw_breakpoints[nb_hw_breakpoints]) {
|
||||
*bp = hw_breakpoints[nb_hw_breakpoints];
|
||||
}
|
||||
size = nb_hw_breakpoints * sizeof(struct kvm_hw_breakpoint);
|
||||
hw_breakpoints =
|
||||
(struct kvm_hw_breakpoint *)g_realloc(hw_breakpoints, size);
|
||||
} else {
|
||||
g_free(hw_breakpoints);
|
||||
hw_breakpoints = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_remove_all_hw_breakpoints(void)
|
||||
{
|
||||
nb_hw_breakpoints = 0;
|
||||
g_free(hw_breakpoints);
|
||||
hw_breakpoints = NULL;
|
||||
}
|
||||
|
||||
void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (nb_hw_breakpoints > 0) {
|
||||
dbg->arch.nr_hw_bp = nb_hw_breakpoints;
|
||||
dbg->arch.hw_bp = hw_breakpoints;
|
||||
|
||||
for (i = 0; i < nb_hw_breakpoints; ++i) {
|
||||
hw_breakpoints[i].phys_addr = s390_cpu_get_phys_addr_debug(cpu,
|
||||
hw_breakpoints[i].addr);
|
||||
}
|
||||
dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
|
||||
} else {
|
||||
dbg->arch.nr_hw_bp = 0;
|
||||
dbg->arch.hw_bp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
|
||||
@@ -579,6 +694,22 @@ static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
|
||||
handle_diag_308(&cpu->env, r1, r3);
|
||||
}
|
||||
|
||||
static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
|
||||
{
|
||||
CPUS390XState *env = &cpu->env;
|
||||
unsigned long pc;
|
||||
|
||||
cpu_synchronize_state(CPU(cpu));
|
||||
|
||||
pc = env->psw.addr - 4;
|
||||
if (kvm_find_sw_breakpoint(CPU(cpu), pc)) {
|
||||
env->psw.addr = pc;
|
||||
return EXCP_DEBUG;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
#define DIAG_KVM_CODE_MASK 0x000000000000ffff
|
||||
|
||||
static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
|
||||
@@ -599,7 +730,7 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
|
||||
r = handle_hypercall(cpu, run);
|
||||
break;
|
||||
case DIAG_KVM_BREAKPOINT:
|
||||
sleep(10);
|
||||
r = handle_sw_breakpoint(cpu, run);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("KVM: unknown DIAG: 0x%x\n", func_code);
|
||||
@@ -701,7 +832,7 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_instruction(S390CPU *cpu, struct kvm_run *run)
|
||||
static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
|
||||
{
|
||||
unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00);
|
||||
uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff;
|
||||
@@ -728,8 +859,11 @@ static void handle_instruction(S390CPU *cpu, struct kvm_run *run)
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
r = 0;
|
||||
enter_pgmcheck(cpu, 0x0001);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool is_special_wait_psw(CPUState *cs)
|
||||
@@ -749,7 +883,7 @@ static int handle_intercept(S390CPU *cpu)
|
||||
(long)cs->kvm_run->psw_addr);
|
||||
switch (icpt_code) {
|
||||
case ICPT_INSTRUCTION:
|
||||
handle_instruction(cpu, run);
|
||||
r = handle_instruction(cpu, run);
|
||||
break;
|
||||
case ICPT_WAITPSW:
|
||||
/* disabled wait, since enabled wait is handled in kernel */
|
||||
@@ -830,7 +964,36 @@ static int handle_tsch(S390CPU *cpu)
|
||||
|
||||
static int kvm_arch_handle_debug_exit(S390CPU *cpu)
|
||||
{
|
||||
return -ENOSYS;
|
||||
CPUState *cs = CPU(cpu);
|
||||
struct kvm_run *run = cs->kvm_run;
|
||||
|
||||
int ret = 0;
|
||||
struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
|
||||
|
||||
switch (arch_info->type) {
|
||||
case KVM_HW_WP_WRITE:
|
||||
if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
|
||||
cs->watchpoint_hit = &hw_watchpoint;
|
||||
hw_watchpoint.vaddr = arch_info->addr;
|
||||
hw_watchpoint.flags = BP_MEM_WRITE;
|
||||
ret = EXCP_DEBUG;
|
||||
}
|
||||
break;
|
||||
case KVM_HW_BP:
|
||||
if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
|
||||
ret = EXCP_DEBUG;
|
||||
}
|
||||
break;
|
||||
case KVM_SINGLESTEP:
|
||||
if (cs->singlestep_enabled) {
|
||||
ret = EXCP_DEBUG;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
|
||||
@@ -911,6 +1074,16 @@ void kvm_s390_enable_css_support(S390CPU *cpu)
|
||||
|
||||
void kvm_arch_init_irq_routing(KVMState *s)
|
||||
{
|
||||
/*
|
||||
* Note that while irqchip capabilities generally imply that cpustates
|
||||
* are handled in-kernel, it is not true for s390 (yet); therefore, we
|
||||
* have to override the common code kvm_halt_in_kernel_allowed setting.
|
||||
*/
|
||||
if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
|
||||
kvm_irqfds_allowed = true;
|
||||
kvm_gsi_routing_allowed = true;
|
||||
kvm_halt_in_kernel_allowed = false;
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
|
||||
|
@@ -444,6 +444,92 @@ static void qdict_array_split_test(void)
|
||||
QDECREF(test_dict);
|
||||
}
|
||||
|
||||
static void qdict_join_test(void)
|
||||
{
|
||||
QDict *dict1, *dict2;
|
||||
bool overwrite = false;
|
||||
int i;
|
||||
|
||||
dict1 = qdict_new();
|
||||
dict2 = qdict_new();
|
||||
|
||||
|
||||
/* Test everything once without overwrite and once with */
|
||||
do
|
||||
{
|
||||
/* Test empty dicts */
|
||||
qdict_join(dict1, dict2, overwrite);
|
||||
|
||||
g_assert(qdict_size(dict1) == 0);
|
||||
g_assert(qdict_size(dict2) == 0);
|
||||
|
||||
|
||||
/* First iteration: Test movement */
|
||||
/* Second iteration: Test empty source and non-empty destination */
|
||||
qdict_put(dict2, "foo", qint_from_int(42));
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
qdict_join(dict1, dict2, overwrite);
|
||||
|
||||
g_assert(qdict_size(dict1) == 1);
|
||||
g_assert(qdict_size(dict2) == 0);
|
||||
|
||||
g_assert(qdict_get_int(dict1, "foo") == 42);
|
||||
}
|
||||
|
||||
|
||||
/* Test non-empty source and destination without conflict */
|
||||
qdict_put(dict2, "bar", qint_from_int(23));
|
||||
|
||||
qdict_join(dict1, dict2, overwrite);
|
||||
|
||||
g_assert(qdict_size(dict1) == 2);
|
||||
g_assert(qdict_size(dict2) == 0);
|
||||
|
||||
g_assert(qdict_get_int(dict1, "foo") == 42);
|
||||
g_assert(qdict_get_int(dict1, "bar") == 23);
|
||||
|
||||
|
||||
/* Test conflict */
|
||||
qdict_put(dict2, "foo", qint_from_int(84));
|
||||
|
||||
qdict_join(dict1, dict2, overwrite);
|
||||
|
||||
g_assert(qdict_size(dict1) == 2);
|
||||
g_assert(qdict_size(dict2) == !overwrite);
|
||||
|
||||
g_assert(qdict_get_int(dict1, "foo") == overwrite ? 84 : 42);
|
||||
g_assert(qdict_get_int(dict1, "bar") == 23);
|
||||
|
||||
if (!overwrite) {
|
||||
g_assert(qdict_get_int(dict2, "foo") == 84);
|
||||
}
|
||||
|
||||
|
||||
/* Check the references */
|
||||
g_assert(qdict_get(dict1, "foo")->refcnt == 1);
|
||||
g_assert(qdict_get(dict1, "bar")->refcnt == 1);
|
||||
|
||||
if (!overwrite) {
|
||||
g_assert(qdict_get(dict2, "foo")->refcnt == 1);
|
||||
}
|
||||
|
||||
|
||||
/* Clean up */
|
||||
qdict_del(dict1, "foo");
|
||||
qdict_del(dict1, "bar");
|
||||
|
||||
if (!overwrite) {
|
||||
qdict_del(dict2, "foo");
|
||||
}
|
||||
}
|
||||
while (overwrite ^= true);
|
||||
|
||||
|
||||
QDECREF(dict1);
|
||||
QDECREF(dict2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Errors test-cases
|
||||
*/
|
||||
@@ -584,6 +670,7 @@ int main(int argc, char **argv)
|
||||
g_test_add_func("/public/iterapi", qdict_iterapi_test);
|
||||
g_test_add_func("/public/flatten", qdict_flatten_test);
|
||||
g_test_add_func("/public/array_split", qdict_array_split_test);
|
||||
g_test_add_func("/public/join", qdict_join_test);
|
||||
|
||||
g_test_add_func("/errors/put_exists", qdict_put_exists_test);
|
||||
g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
|
||||
|
@@ -35,7 +35,7 @@ class TestSingleDrive(iotests.QMPTestCase):
|
||||
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
|
||||
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
|
||||
qemu_io('-c', 'write -P 0x1 0 512', backing_img)
|
||||
self.vm = iotests.VM().add_drive(test_img)
|
||||
self.vm = iotests.VM().add_drive("blkdebug::" + test_img)
|
||||
self.vm.launch()
|
||||
|
||||
def tearDown(self):
|
||||
|
@@ -47,6 +47,11 @@ _supported_os Linux
|
||||
_default_cache_mode "writethrough"
|
||||
_supported_cache_modes "writethrough"
|
||||
|
||||
_no_dump_exec()
|
||||
{
|
||||
(ulimit -c 0; exec "$@")
|
||||
}
|
||||
|
||||
size=128M
|
||||
|
||||
echo
|
||||
@@ -67,10 +72,7 @@ echo "== Creating a dirty image file =="
|
||||
IMGOPTS="compat=1.1,lazy_refcounts=on"
|
||||
_make_test_img $size
|
||||
|
||||
old_ulimit=$(ulimit -c)
|
||||
ulimit -c 0 # do not produce a core dump on abort(3)
|
||||
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
|
||||
ulimit -c "$old_ulimit"
|
||||
_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
|
||||
|
||||
# The dirty bit must be set
|
||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||
@@ -103,10 +105,7 @@ echo "== Opening a dirty image read/write should repair it =="
|
||||
IMGOPTS="compat=1.1,lazy_refcounts=on"
|
||||
_make_test_img $size
|
||||
|
||||
old_ulimit=$(ulimit -c)
|
||||
ulimit -c 0 # do not produce a core dump on abort(3)
|
||||
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
|
||||
ulimit -c "$old_ulimit"
|
||||
_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
|
||||
|
||||
# The dirty bit must be set
|
||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||
@@ -122,10 +121,7 @@ echo "== Creating an image file with lazy_refcounts=off =="
|
||||
IMGOPTS="compat=1.1,lazy_refcounts=off"
|
||||
_make_test_img $size
|
||||
|
||||
old_ulimit=$(ulimit -c)
|
||||
ulimit -c 0 # do not produce a core dump on abort(3)
|
||||
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
|
||||
ulimit -c "$old_ulimit"
|
||||
_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
|
||||
|
||||
# The dirty bit must not be set since lazy_refcounts=off
|
||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||
|
@@ -11,6 +11,7 @@ No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./039: Aborted ( ulimit -c 0; exec "$@" )
|
||||
incompatible_features 0x1
|
||||
ERROR cluster 5 refcount=0 reference=1
|
||||
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
|
||||
@@ -42,6 +43,7 @@ read 512/512 bytes at offset 0
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./039: Aborted ( ulimit -c 0; exec "$@" )
|
||||
incompatible_features 0x1
|
||||
Repairing cluster 5 refcount=0 reference=1
|
||||
wrote 512/512 bytes at offset 0
|
||||
@@ -52,6 +54,7 @@ incompatible_features 0x0
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./039: Aborted ( ulimit -c 0; exec "$@" )
|
||||
incompatible_features 0x0
|
||||
No errors were found on the image.
|
||||
|
||||
|
@@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
|
||||
@@ -24,7 +24,7 @@ QMP_VERSION
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
@@ -44,7 +44,7 @@ Testing:
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
{"return": "OK\r\n"}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
@@ -64,14 +64,14 @@ Testing:
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
|
||||
|
@@ -72,6 +72,13 @@ echo "=== Verify open image read-only succeeds after log replay ==="
|
||||
$QEMU_IO -r -c "read -pP 0xa5 0 18M" "$TEST_IMG" 2>&1 | _filter_testdir \
|
||||
| _filter_qemu_io
|
||||
|
||||
_cleanup_test_img
|
||||
_use_sample_img test-disk2vhd.vhdx.bz2
|
||||
|
||||
echo
|
||||
echo "=== Verify image created by Disk2VHD can be opened ==="
|
||||
$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir | _filter_qemu
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
|
@@ -18,4 +18,11 @@ No errors were found on the image.
|
||||
=== Verify open image read-only succeeds after log replay ===
|
||||
read 18874368/18874368 bytes at offset 0
|
||||
18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Verify image created by Disk2VHD can be opened ===
|
||||
image: TEST_DIR/test-disk2vhd.vhdx
|
||||
file format: vhdx
|
||||
virtual size: 256M (268435456 bytes)
|
||||
disk size: 260M
|
||||
cluster_size: 2097152
|
||||
*** done
|
||||
|
130
tests/qemu-iotests/089
Executable file
130
tests/qemu-iotests/089
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test case for support of JSON filenames
|
||||
#
|
||||
# Copyright (C) 2014 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=mreitz@redhat.com
|
||||
|
||||
seq="$(basename $0)"
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here="$PWD"
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
# Using an image filename containing quotation marks will render the JSON data
|
||||
# below invalid. In that case, we have little choice but simply not to run this
|
||||
# test.
|
||||
case $TEST_IMG in
|
||||
*'"'*)
|
||||
_notrun "image filename may not contain quotation marks"
|
||||
;;
|
||||
esac
|
||||
|
||||
IMG_SIZE=64M
|
||||
|
||||
# Taken from test 072
|
||||
echo
|
||||
echo "=== Testing nested image formats ==="
|
||||
echo
|
||||
|
||||
TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
|
||||
|
||||
$QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \
|
||||
-c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io
|
||||
|
||||
$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG"
|
||||
|
||||
$QEMU_IO -c 'read -P 42 0 512' -c 'read -P 23 512 512' \
|
||||
-c 'read -P 66 1024 512' "json:{
|
||||
\"driver\": \"$IMGFMT\",
|
||||
\"file\": {
|
||||
\"driver\": \"$IMGFMT\",
|
||||
\"file\": {
|
||||
\"filename\": \"$TEST_IMG\"
|
||||
}
|
||||
}
|
||||
}" | _filter_qemu_io
|
||||
|
||||
# This should fail (see test 072)
|
||||
$QEMU_IO -c 'read -P 42 0 512' "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
|
||||
# Taken from test 071
|
||||
echo
|
||||
echo "=== Testing blkdebug ==="
|
||||
echo
|
||||
|
||||
_make_test_img $IMG_SIZE
|
||||
|
||||
$QEMU_IO -c 'write -P 42 0x38000 512' "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
# The "image.filename" part tests whether "a": { "b": "c" } and "a.b": "c" do
|
||||
# the same (which they should).
|
||||
$QEMU_IO -c 'read -P 42 0x38000 512' "json:{
|
||||
\"driver\": \"$IMGFMT\",
|
||||
\"file\": {
|
||||
\"driver\": \"blkdebug\",
|
||||
\"inject-error\": [{
|
||||
\"event\": \"l2_load\"
|
||||
}],
|
||||
\"image.filename\": \"$TEST_IMG\"
|
||||
}
|
||||
}" | _filter_qemu_io
|
||||
|
||||
|
||||
echo
|
||||
echo "=== Testing qemu-img info output ==="
|
||||
echo
|
||||
|
||||
$QEMU_IMG info "json:{\"driver\":\"qcow2\",\"file.filename\":\"$TEST_IMG\"}" \
|
||||
| _filter_testdir | _filter_imgfmt
|
||||
|
||||
|
||||
echo
|
||||
echo "=== Testing option merging ==="
|
||||
echo
|
||||
|
||||
# Both options given directly and those given in the filename should be used
|
||||
$QEMU_IO -c "open -o driver=qcow2 json:{\"file.filename\":\"$TEST_IMG\"}" \
|
||||
-c "info" 2>&1 | _filter_testdir | _filter_imgfmt
|
||||
|
||||
# Options given directly should be prioritized over those given in the filename
|
||||
$QEMU_IO -c "open -o driver=qcow2 json:{\"driver\":\"raw\",\"file.filename\":\"$TEST_IMG\"}" \
|
||||
-c "info" 2>&1 | _filter_testdir | _filter_imgfmt
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
54
tests/qemu-iotests/089.out
Normal file
54
tests/qemu-iotests/089.out
Normal file
@@ -0,0 +1,54 @@
|
||||
QA output created by 089
|
||||
|
||||
=== Testing nested image formats ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 512
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 1024
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 512
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 1024
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Pattern verification failed at offset 0, 512 bytes
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Testing blkdebug ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 512/512 bytes at offset 229376
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read failed: Input/output error
|
||||
|
||||
=== Testing qemu-img info output ===
|
||||
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64M (67108864 bytes)
|
||||
disk size: 324K
|
||||
cluster_size: 65536
|
||||
Format specific information:
|
||||
compat: 1.1
|
||||
lazy refcounts: false
|
||||
|
||||
=== Testing option merging ===
|
||||
|
||||
format name: IMGFMT
|
||||
cluster size: 64 KiB
|
||||
vm state offset: 512 MiB
|
||||
Format specific information:
|
||||
compat: 1.1
|
||||
lazy refcounts: false
|
||||
format name: IMGFMT
|
||||
cluster size: 64 KiB
|
||||
vm state offset: 512 MiB
|
||||
Format specific information:
|
||||
compat: 1.1
|
||||
lazy refcounts: false
|
||||
*** done
|
98
tests/qemu-iotests/092
Executable file
98
tests/qemu-iotests/092
Executable file
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# qcow1 format input validation tests
|
||||
#
|
||||
# Copyright (C) 2014 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=kwolf@redhat.com
|
||||
|
||||
seq=`basename $0`
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
rm -f $TEST_IMG.snap
|
||||
_cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
offset_backing_file_offset=8
|
||||
offset_backing_file_size=16
|
||||
offset_size=24
|
||||
offset_cluster_bits=32
|
||||
offset_l2_bits=33
|
||||
|
||||
echo
|
||||
echo "== Invalid cluster size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x1f"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid L2 table size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\x05"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
# 1 << 0x1b = 2^31 / L2_CACHE_SIZE
|
||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid backing file length =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\xff"
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_size" "\x7f\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
38
tests/qemu-iotests/092.out
Normal file
38
tests/qemu-iotests/092.out
Normal file
@@ -0,0 +1,38 @@
|
||||
QA output created by 092
|
||||
|
||||
== Invalid cluster size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
|
||||
== Invalid L2 table size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
|
||||
== Invalid size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Image too large
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Image too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Invalid backing file length ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
|
||||
no file open, try 'help open'
|
||||
*** done
|
@@ -150,6 +150,7 @@ _filter_win32()
|
||||
_filter_qemu_io()
|
||||
{
|
||||
_filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \
|
||||
-e "s/: line [0-9][0-9]*: *[0-9][0-9]*\( Aborted\)/:\1/" \
|
||||
-e "s/qemu-io> //g"
|
||||
}
|
||||
|
||||
|
@@ -95,5 +95,7 @@
|
||||
086 rw auto quick
|
||||
087 rw auto
|
||||
088 rw auto
|
||||
089 rw auto quick
|
||||
090 rw auto quick
|
||||
091 rw auto
|
||||
092 rw auto quick
|
||||
|
BIN
tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2
Normal file
BIN
tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2
Normal file
Binary file not shown.
233
ui/console.c
233
ui/console.c
@@ -143,8 +143,6 @@ struct QemuConsole {
|
||||
TextCell *cells;
|
||||
int text_x[2], text_y[2], cursor_invalidate;
|
||||
int echo;
|
||||
bool cursor_visible_phase;
|
||||
QEMUTimer *cursor_timer;
|
||||
|
||||
int update_x0;
|
||||
int update_y0;
|
||||
@@ -177,10 +175,14 @@ static DisplayState *display_state;
|
||||
static QemuConsole *active_console;
|
||||
static QemuConsole *consoles[MAX_CONSOLES];
|
||||
static int nb_consoles = 0;
|
||||
static bool cursor_visible_phase;
|
||||
static QEMUTimer *cursor_timer;
|
||||
|
||||
static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
|
||||
static void dpy_refresh(DisplayState *s);
|
||||
static DisplayState *get_alloc_displaystate(void);
|
||||
static void text_console_update_cursor_timer(void);
|
||||
static void text_console_update_cursor(void *opaque);
|
||||
|
||||
static void gui_update(void *opaque)
|
||||
{
|
||||
@@ -475,6 +477,9 @@ static inline void text_update_xy(QemuConsole *s, int x, int y)
|
||||
|
||||
static void invalidate_xy(QemuConsole *s, int x, int y)
|
||||
{
|
||||
if (!qemu_console_is_visible(s)) {
|
||||
return;
|
||||
}
|
||||
if (s->update_x0 > x * FONT_WIDTH)
|
||||
s->update_x0 = x * FONT_WIDTH;
|
||||
if (s->update_y0 > y * FONT_HEIGHT)
|
||||
@@ -490,25 +495,20 @@ static void update_xy(QemuConsole *s, int x, int y)
|
||||
TextCell *c;
|
||||
int y1, y2;
|
||||
|
||||
if (!qemu_console_is_visible(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->ds->have_text) {
|
||||
text_update_xy(s, x, y);
|
||||
}
|
||||
|
||||
if (s->ds->have_gfx) {
|
||||
y1 = (s->y_base + y) % s->total_height;
|
||||
y2 = y1 - s->y_displayed;
|
||||
if (y2 < 0)
|
||||
y2 += s->total_height;
|
||||
if (y2 < s->height) {
|
||||
c = &s->cells[y1 * s->width + x];
|
||||
vga_putcharxy(s, x, y2, c->ch,
|
||||
&(c->t_attrib));
|
||||
invalidate_xy(s, x, y2);
|
||||
}
|
||||
y1 = (s->y_base + y) % s->total_height;
|
||||
y2 = y1 - s->y_displayed;
|
||||
if (y2 < 0) {
|
||||
y2 += s->total_height;
|
||||
}
|
||||
if (y2 < s->height) {
|
||||
c = &s->cells[y1 * s->width + x];
|
||||
vga_putcharxy(s, x, y2, c->ch,
|
||||
&(c->t_attrib));
|
||||
invalidate_xy(s, x, y2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,33 +518,28 @@ static void console_show_cursor(QemuConsole *s, int show)
|
||||
int y, y1;
|
||||
int x = s->x;
|
||||
|
||||
if (!qemu_console_is_visible(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->ds->have_text) {
|
||||
s->cursor_invalidate = 1;
|
||||
}
|
||||
|
||||
if (s->ds->have_gfx) {
|
||||
if (x >= s->width) {
|
||||
x = s->width - 1;
|
||||
}
|
||||
y1 = (s->y_base + s->y) % s->total_height;
|
||||
y = y1 - s->y_displayed;
|
||||
if (y < 0)
|
||||
y += s->total_height;
|
||||
if (y < s->height) {
|
||||
c = &s->cells[y1 * s->width + x];
|
||||
if (show && s->cursor_visible_phase) {
|
||||
TextAttributes t_attrib = s->t_attrib_default;
|
||||
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
|
||||
vga_putcharxy(s, x, y, c->ch, &t_attrib);
|
||||
} else {
|
||||
vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
|
||||
}
|
||||
invalidate_xy(s, x, y);
|
||||
if (x >= s->width) {
|
||||
x = s->width - 1;
|
||||
}
|
||||
y1 = (s->y_base + s->y) % s->total_height;
|
||||
y = y1 - s->y_displayed;
|
||||
if (y < 0) {
|
||||
y += s->total_height;
|
||||
}
|
||||
if (y < s->height) {
|
||||
c = &s->cells[y1 * s->width + x];
|
||||
if (show && cursor_visible_phase) {
|
||||
TextAttributes t_attrib = s->t_attrib_default;
|
||||
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
|
||||
vga_putcharxy(s, x, y, c->ch, &t_attrib);
|
||||
} else {
|
||||
vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
|
||||
}
|
||||
invalidate_xy(s, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,10 +549,6 @@ static void console_refresh(QemuConsole *s)
|
||||
TextCell *c;
|
||||
int x, y, y1;
|
||||
|
||||
if (!qemu_console_is_visible(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->ds->have_text) {
|
||||
s->text_x[0] = 0;
|
||||
s->text_y[0] = 0;
|
||||
@@ -566,25 +557,23 @@ static void console_refresh(QemuConsole *s)
|
||||
s->cursor_invalidate = 1;
|
||||
}
|
||||
|
||||
if (s->ds->have_gfx) {
|
||||
vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
|
||||
color_table_rgb[0][COLOR_BLACK]);
|
||||
y1 = s->y_displayed;
|
||||
for (y = 0; y < s->height; y++) {
|
||||
c = s->cells + y1 * s->width;
|
||||
for (x = 0; x < s->width; x++) {
|
||||
vga_putcharxy(s, x, y, c->ch,
|
||||
&(c->t_attrib));
|
||||
c++;
|
||||
}
|
||||
if (++y1 == s->total_height) {
|
||||
y1 = 0;
|
||||
}
|
||||
vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
|
||||
color_table_rgb[0][COLOR_BLACK]);
|
||||
y1 = s->y_displayed;
|
||||
for (y = 0; y < s->height; y++) {
|
||||
c = s->cells + y1 * s->width;
|
||||
for (x = 0; x < s->width; x++) {
|
||||
vga_putcharxy(s, x, y, c->ch,
|
||||
&(c->t_attrib));
|
||||
c++;
|
||||
}
|
||||
if (++y1 == s->total_height) {
|
||||
y1 = 0;
|
||||
}
|
||||
console_show_cursor(s, 1);
|
||||
dpy_gfx_update(s, 0, 0,
|
||||
surface_width(surface), surface_height(surface));
|
||||
}
|
||||
console_show_cursor(s, 1);
|
||||
dpy_gfx_update(s, 0, 0,
|
||||
surface_width(surface), surface_height(surface));
|
||||
}
|
||||
|
||||
static void console_scroll(QemuConsole *s, int ydelta)
|
||||
@@ -640,7 +629,7 @@ static void console_put_lf(QemuConsole *s)
|
||||
c->t_attrib = s->t_attrib_default;
|
||||
c++;
|
||||
}
|
||||
if (qemu_console_is_visible(s) && s->y_displayed == s->y_base) {
|
||||
if (s->y_displayed == s->y_base) {
|
||||
if (s->ds->have_text) {
|
||||
s->text_x[0] = 0;
|
||||
s->text_y[0] = 0;
|
||||
@@ -648,18 +637,16 @@ static void console_put_lf(QemuConsole *s)
|
||||
s->text_y[1] = s->height - 1;
|
||||
}
|
||||
|
||||
if (s->ds->have_gfx) {
|
||||
vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
|
||||
s->width * FONT_WIDTH,
|
||||
(s->height - 1) * FONT_HEIGHT);
|
||||
vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
|
||||
s->width * FONT_WIDTH, FONT_HEIGHT,
|
||||
color_table_rgb[0][s->t_attrib_default.bgcol]);
|
||||
s->update_x0 = 0;
|
||||
s->update_y0 = 0;
|
||||
s->update_x1 = s->width * FONT_WIDTH;
|
||||
s->update_y1 = s->height * FONT_HEIGHT;
|
||||
}
|
||||
vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
|
||||
s->width * FONT_WIDTH,
|
||||
(s->height - 1) * FONT_HEIGHT);
|
||||
vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
|
||||
s->width * FONT_WIDTH, FONT_HEIGHT,
|
||||
color_table_rgb[0][s->t_attrib_default.bgcol]);
|
||||
s->update_x0 = 0;
|
||||
s->update_y0 = 0;
|
||||
s->update_x1 = s->width * FONT_WIDTH;
|
||||
s->update_y1 = s->height * FONT_HEIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1004,9 +991,6 @@ void console_select(unsigned int index)
|
||||
if (s) {
|
||||
DisplayState *ds = s->ds;
|
||||
|
||||
if (active_console && active_console->cursor_timer) {
|
||||
timer_del(active_console->cursor_timer);
|
||||
}
|
||||
active_console = s;
|
||||
if (ds->have_gfx) {
|
||||
QLIST_FOREACH(dcl, &ds->listeners, next) {
|
||||
@@ -1023,10 +1007,7 @@ void console_select(unsigned int index)
|
||||
if (ds->have_text) {
|
||||
dpy_text_resize(s, s->width, s->height);
|
||||
}
|
||||
if (s->cursor_timer) {
|
||||
timer_mod(s->cursor_timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
|
||||
}
|
||||
text_console_update_cursor(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,13 +1056,11 @@ static void kbd_send_chars(void *opaque)
|
||||
}
|
||||
|
||||
/* called when an ascii key is pressed */
|
||||
void kbd_put_keysym(int keysym)
|
||||
void kbd_put_keysym_console(QemuConsole *s, int keysym)
|
||||
{
|
||||
QemuConsole *s;
|
||||
uint8_t buf[16], *q;
|
||||
int c;
|
||||
|
||||
s = active_console;
|
||||
if (!s || (s->console_type == GRAPHIC_CONSOLE))
|
||||
return;
|
||||
|
||||
@@ -1130,6 +1109,11 @@ void kbd_put_keysym(int keysym)
|
||||
}
|
||||
}
|
||||
|
||||
void kbd_put_keysym(int keysym)
|
||||
{
|
||||
kbd_put_keysym_console(active_console, keysym);
|
||||
}
|
||||
|
||||
static void text_console_invalidate(void *opaque)
|
||||
{
|
||||
QemuConsole *s = (QemuConsole *) opaque;
|
||||
@@ -1167,9 +1151,9 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
|
||||
}
|
||||
}
|
||||
|
||||
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
|
||||
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
|
||||
uint32_t head)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
Object *obj;
|
||||
QemuConsole *s;
|
||||
int i;
|
||||
@@ -1179,13 +1163,14 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
|
||||
|
||||
obj = object_new(TYPE_QEMU_CONSOLE);
|
||||
s = QEMU_CONSOLE(obj);
|
||||
s->head = head;
|
||||
object_property_add_link(obj, "device", TYPE_DEVICE,
|
||||
(Object **)&s->device,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&local_err);
|
||||
&error_abort);
|
||||
object_property_add_uint32_ptr(obj, "head",
|
||||
&s->head, &local_err);
|
||||
&s->head, &error_abort);
|
||||
|
||||
if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
|
||||
(console_type == GRAPHIC_CONSOLE))) {
|
||||
@@ -1270,19 +1255,18 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
return surface;
|
||||
}
|
||||
|
||||
static DisplaySurface *qemu_create_dummy_surface(void)
|
||||
static DisplaySurface *qemu_create_message_surface(int w, int h,
|
||||
const char *msg)
|
||||
{
|
||||
static const char msg[] =
|
||||
"This VM has no graphic display device.";
|
||||
DisplaySurface *surface = qemu_create_displaysurface(640, 480);
|
||||
DisplaySurface *surface = qemu_create_displaysurface(w, h);
|
||||
pixman_color_t bg = color_table_rgb[0][COLOR_BLACK];
|
||||
pixman_color_t fg = color_table_rgb[0][COLOR_WHITE];
|
||||
pixman_image_t *glyph;
|
||||
int len, x, y, i;
|
||||
|
||||
len = strlen(msg);
|
||||
x = (640/FONT_WIDTH - len) / 2;
|
||||
y = (480/FONT_HEIGHT - 1) / 2;
|
||||
x = (w / FONT_WIDTH - len) / 2;
|
||||
y = (h / FONT_HEIGHT - 1) / 2;
|
||||
for (i = 0; i < len; i++) {
|
||||
glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
|
||||
qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
|
||||
@@ -1304,6 +1288,8 @@ void qemu_free_displaysurface(DisplaySurface *surface)
|
||||
|
||||
void register_displaychangelistener(DisplayChangeListener *dcl)
|
||||
{
|
||||
static const char nodev[] =
|
||||
"This VM has no graphic display device.";
|
||||
static DisplaySurface *dummy;
|
||||
QemuConsole *con;
|
||||
|
||||
@@ -1322,11 +1308,12 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
|
||||
dcl->ops->dpy_gfx_switch(dcl, con->surface);
|
||||
} else {
|
||||
if (!dummy) {
|
||||
dummy = qemu_create_dummy_surface();
|
||||
dummy = qemu_create_message_surface(640, 480, nodev);
|
||||
}
|
||||
dcl->ops->dpy_gfx_switch(dcl, dummy);
|
||||
}
|
||||
}
|
||||
text_console_update_cursor(NULL);
|
||||
}
|
||||
|
||||
void update_displaychangelistener(DisplayChangeListener *dcl,
|
||||
@@ -1550,6 +1537,8 @@ static DisplayState *get_alloc_displaystate(void)
|
||||
{
|
||||
if (!display_state) {
|
||||
display_state = g_new0(DisplayState, 1);
|
||||
cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
|
||||
text_console_update_cursor, NULL);
|
||||
}
|
||||
return display_state;
|
||||
}
|
||||
@@ -1560,7 +1549,6 @@ static DisplayState *get_alloc_displaystate(void)
|
||||
*/
|
||||
DisplayState *init_displaystate(void)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
gchar *name;
|
||||
int i;
|
||||
|
||||
@@ -1579,7 +1567,7 @@ DisplayState *init_displaystate(void)
|
||||
* doesn't change any more */
|
||||
name = g_strdup_printf("console[%d]", i);
|
||||
object_property_add_child(container_get(object_get_root(), "/backend"),
|
||||
name, OBJECT(consoles[i]), &local_err);
|
||||
name, OBJECT(consoles[i]), &error_abort);
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
@@ -1590,7 +1578,8 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
|
||||
const GraphicHwOps *hw_ops,
|
||||
void *opaque)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
static const char noinit[] =
|
||||
"Guest has not initialized the display (yet).";
|
||||
int width = 640;
|
||||
int height = 480;
|
||||
QemuConsole *s;
|
||||
@@ -1598,17 +1587,15 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
|
||||
|
||||
ds = get_alloc_displaystate();
|
||||
trace_console_gfx_new();
|
||||
s = new_console(ds, GRAPHIC_CONSOLE);
|
||||
s = new_console(ds, GRAPHIC_CONSOLE, head);
|
||||
s->hw_ops = hw_ops;
|
||||
s->hw = opaque;
|
||||
if (dev) {
|
||||
object_property_set_link(OBJECT(s), OBJECT(dev),
|
||||
"device", &local_err);
|
||||
object_property_set_int(OBJECT(s), head,
|
||||
"head", &local_err);
|
||||
object_property_set_link(OBJECT(s), OBJECT(dev), "device",
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
s->surface = qemu_create_displaysurface(width, height);
|
||||
s->surface = qemu_create_message_surface(width, height, noinit);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1622,7 +1609,6 @@ QemuConsole *qemu_console_lookup_by_index(unsigned int index)
|
||||
|
||||
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
Object *obj;
|
||||
uint32_t h;
|
||||
int i;
|
||||
@@ -1632,12 +1618,12 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
|
||||
continue;
|
||||
}
|
||||
obj = object_property_get_link(OBJECT(consoles[i]),
|
||||
"device", &local_err);
|
||||
"device", &error_abort);
|
||||
if (DEVICE(obj) != dev) {
|
||||
continue;
|
||||
}
|
||||
h = object_property_get_int(OBJECT(consoles[i]),
|
||||
"head", &local_err);
|
||||
"head", &error_abort);
|
||||
if (h != head) {
|
||||
continue;
|
||||
}
|
||||
@@ -1712,14 +1698,32 @@ static void text_console_set_echo(CharDriverState *chr, bool echo)
|
||||
s->echo = echo;
|
||||
}
|
||||
|
||||
static void text_console_update_cursor_timer(void)
|
||||
{
|
||||
timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
|
||||
+ CONSOLE_CURSOR_PERIOD / 2);
|
||||
}
|
||||
|
||||
static void text_console_update_cursor(void *opaque)
|
||||
{
|
||||
QemuConsole *s = opaque;
|
||||
QemuConsole *s;
|
||||
int i, count = 0;
|
||||
|
||||
s->cursor_visible_phase = !s->cursor_visible_phase;
|
||||
graphic_hw_invalidate(s);
|
||||
timer_mod(s->cursor_timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
|
||||
cursor_visible_phase = !cursor_visible_phase;
|
||||
|
||||
for (i = 0; i < nb_consoles; i++) {
|
||||
s = consoles[i];
|
||||
if (qemu_console_is_graphic(s) ||
|
||||
!qemu_console_is_visible(s)) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
graphic_hw_invalidate(s);
|
||||
}
|
||||
|
||||
if (count) {
|
||||
text_console_update_cursor_timer();
|
||||
}
|
||||
}
|
||||
|
||||
static const GraphicHwOps text_console_ops = {
|
||||
@@ -1755,9 +1759,6 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
|
||||
s->surface = qemu_create_displaysurface(g_width, g_height);
|
||||
}
|
||||
|
||||
s->cursor_timer =
|
||||
timer_new_ms(QEMU_CLOCK_REALTIME, text_console_update_cursor, s);
|
||||
|
||||
s->hw_ops = &text_console_ops;
|
||||
s->hw = s;
|
||||
|
||||
@@ -1811,9 +1812,9 @@ static CharDriverState *text_console_init(ChardevVC *vc)
|
||||
|
||||
trace_console_txt_new(width, height);
|
||||
if (width == 0 || height == 0) {
|
||||
s = new_console(NULL, TEXT_CONSOLE);
|
||||
s = new_console(NULL, TEXT_CONSOLE, 0);
|
||||
} else {
|
||||
s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
|
||||
s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
|
||||
s->surface = qemu_create_displaysurface(width, height);
|
||||
}
|
||||
|
||||
|
21
util/iov.c
21
util/iov.c
@@ -335,6 +335,27 @@ void qemu_iovec_concat(QEMUIOVector *dst,
|
||||
qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the contents of the iovecs are all zero
|
||||
*/
|
||||
bool qemu_iovec_is_zero(QEMUIOVector *qiov)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < qiov->niov; i++) {
|
||||
size_t offs = QEMU_ALIGN_DOWN(qiov->iov[i].iov_len, 4 * sizeof(long));
|
||||
uint8_t *ptr = qiov->iov[i].iov_base;
|
||||
if (offs && !buffer_is_zero(qiov->iov[i].iov_base, offs)) {
|
||||
return false;
|
||||
}
|
||||
for (; offs < qiov->iov[i].iov_len; offs++) {
|
||||
if (ptr[offs]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void qemu_iovec_destroy(QEMUIOVector *qiov)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
Reference in New Issue
Block a user