Compare commits
209 Commits
pull-input
...
pull-ui-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c9209e7bf | ||
|
|
761d0f97a4 | ||
|
|
bb1599b64c | ||
|
|
bc8c946f72 | ||
|
|
151c8e608e | ||
|
|
e1913dbb58 | ||
|
|
9f728c7940 | ||
|
|
c19f4fbce1 | ||
|
|
d755defd5d | ||
|
|
9cfa7ab939 | ||
|
|
76d20ea0f1 | ||
|
|
dcd3b25d65 | ||
|
|
b13d2ff3de | ||
|
|
daa5a72eba | ||
|
|
c5e397df9e | ||
|
|
aa3b167f21 | ||
|
|
8b2e41d733 | ||
|
|
ed0ba0f47e | ||
|
|
6c02258e14 | ||
|
|
10e37839ed | ||
|
|
0c099fa7e9 | ||
|
|
bd269ebc82 | ||
|
|
62cf396b5d | ||
|
|
dfd100f242 | ||
|
|
4626a19c86 | ||
|
|
0785bd7a7c | ||
|
|
4db5c619a2 | ||
|
|
5229564b83 | ||
|
|
ccb61bdd73 | ||
|
|
28934e0c75 | ||
|
|
ff6ed7141d | ||
|
|
46f5ac205a | ||
|
|
a92c21591b | ||
|
|
de6e7951fe | ||
|
|
a2f3453ebc | ||
|
|
8f16de18f6 | ||
|
|
9edd5338a2 | ||
|
|
cb69166bb8 | ||
|
|
de4598f0c5 | ||
|
|
7ed57b6622 | ||
|
|
1c5d506101 | ||
|
|
2fd463854c | ||
|
|
6225820136 | ||
|
|
32543dbb67 | ||
|
|
f3fddaf60b | ||
|
|
4bf43122db | ||
|
|
2f5a5f5774 | ||
|
|
dd1559bb26 | ||
|
|
f03f9f0c10 | ||
|
|
4aee86c60a | ||
|
|
bc56fd3a23 | ||
|
|
dd76c10f9f | ||
|
|
317134bb54 | ||
|
|
4f3652b3aa | ||
|
|
4f225f343a | ||
|
|
95615ce5a1 | ||
|
|
eae0f54334 | ||
|
|
622e42a71f | ||
|
|
9ff3a5e677 | ||
|
|
7a6ae2cffc | ||
|
|
6668a2af21 | ||
|
|
fdf6fab4df | ||
|
|
bde4d9205e | ||
|
|
6796b4008b | ||
|
|
8a3c3d996e | ||
|
|
6e9389563e | ||
|
|
31f5a726b5 | ||
|
|
f68826989c | ||
|
|
c8c33fca88 | ||
|
|
24dfa9fa2f | ||
|
|
aab9e87e7a | ||
|
|
49e00a1870 | ||
|
|
00fcd100c3 | ||
|
|
8eb57ae3f9 | ||
|
|
b290f3b12e | ||
|
|
12a95f320a | ||
|
|
79c8db5a13 | ||
|
|
bb1490486d | ||
|
|
d47fb5d17c | ||
|
|
9dbaa4ce58 | ||
|
|
a86c83d704 | ||
|
|
e24ef0db4f | ||
|
|
e0b6767b6c | ||
|
|
da2d19b080 | ||
|
|
123676e989 | ||
|
|
bc763d7144 | ||
|
|
bbcde969b2 | ||
|
|
e1f98fe48a | ||
|
|
1e13edf355 | ||
|
|
c5749f7c0b | ||
|
|
6061162e52 | ||
|
|
474628e837 | ||
|
|
2f5d45a150 | ||
|
|
f8df5f9221 | ||
|
|
315dd72d75 | ||
|
|
bed3bb9b7e | ||
|
|
6361813527 | ||
|
|
1db9d8e501 | ||
|
|
be07b0ace8 | ||
|
|
9e8b3009b7 | ||
|
|
e65a27209c | ||
|
|
4996241a4a | ||
|
|
2dc95b4cac | ||
|
|
b847620540 | ||
|
|
ff20b0a3d8 | ||
|
|
6c15e9bfb6 | ||
|
|
ae92cbd542 | ||
|
|
6683061873 | ||
|
|
d905bb7b74 | ||
|
|
d9c7d137c8 | ||
|
|
52b2620512 | ||
|
|
c34c2f3701 | ||
|
|
fd4144d413 | ||
|
|
062d81f0e9 | ||
|
|
6b6712efcc | ||
|
|
9ea5ada76f | ||
|
|
d52ccc0eca | ||
|
|
3fab7b675a | ||
|
|
b3b40917c7 | ||
|
|
e14e09c945 | ||
|
|
ade339896b | ||
|
|
17a1694a56 | ||
|
|
135f5ae197 | ||
|
|
4bf7792aae | ||
|
|
1c742f2b8e | ||
|
|
222e0356fa | ||
|
|
0af81c56bf | ||
|
|
9887e22155 | ||
|
|
8f7e2c2cb7 | ||
|
|
7852b53acc | ||
|
|
8ec734d027 | ||
|
|
7f643fb53a | ||
|
|
7bf10b1de2 | ||
|
|
d2a4a01fa4 | ||
|
|
3795f18095 | ||
|
|
d8586afd8b | ||
|
|
4a796e979e | ||
|
|
882ab9d615 | ||
|
|
2004429e9b | ||
|
|
b6c6919e21 | ||
|
|
68883a4078 | ||
|
|
7bdfd907e7 | ||
|
|
3268a845f4 | ||
|
|
5eaa8e1e0f | ||
|
|
8ac5535145 | ||
|
|
f4d1414a93 | ||
|
|
48a1b62baa | ||
|
|
acf57591c0 | ||
|
|
b75c958d88 | ||
|
|
d89e71e873 | ||
|
|
4597992f62 | ||
|
|
ef3f5b9e7f | ||
|
|
461a4b944f | ||
|
|
6e4e6f0d40 | ||
|
|
38d49e8c15 | ||
|
|
15126cba86 | ||
|
|
b19456dd0e | ||
|
|
6103451aeb | ||
|
|
77af8a2b95 | ||
|
|
99efaa2696 | ||
|
|
c55144ec32 | ||
|
|
7a9762bf89 | ||
|
|
82ca394194 | ||
|
|
9dd7823b70 | ||
|
|
95fa1af854 | ||
|
|
9a22473c70 | ||
|
|
cfe2124a7f | ||
|
|
5559716c98 | ||
|
|
b038411d85 | ||
|
|
bd1badf457 | ||
|
|
7104bae9de | ||
|
|
5fc0fe383f | ||
|
|
262fbae692 | ||
|
|
cc02e89eb4 | ||
|
|
4f38497b0f | ||
|
|
db933fbe06 | ||
|
|
9f1b92add2 | ||
|
|
504c205a0d | ||
|
|
d4a7f45ec9 | ||
|
|
048c5fd1bf | ||
|
|
f59adb3256 | ||
|
|
4bff28b81a | ||
|
|
ed3d2ec98a | ||
|
|
55b9392b98 | ||
|
|
2b4c0a20fb | ||
|
|
48758a8473 | ||
|
|
3258b91141 | ||
|
|
f13ce1be35 | ||
|
|
de234897b6 | ||
|
|
24dfdfd0ff | ||
|
|
8248169497 | ||
|
|
fea41826db | ||
|
|
03a0aa37d2 | ||
|
|
e914404efb | ||
|
|
242e496b39 | ||
|
|
1ea88d359f | ||
|
|
42dc10f17a | ||
|
|
4a0082401a | ||
|
|
312758e237 | ||
|
|
69404d9e47 | ||
|
|
0042fd3663 | ||
|
|
9fd77f9972 | ||
|
|
362b3786eb | ||
|
|
0d5e0bb2f7 | ||
|
|
ad02b7af0c | ||
|
|
0731a50feb | ||
|
|
3fee028d1e | ||
|
|
356a2db3c6 | ||
|
|
1d7cf18d79 |
19
MAINTAINERS
19
MAINTAINERS
@@ -12,6 +12,8 @@ consult qemu-devel and not any specific individual privately.
|
||||
Descriptions of section entries:
|
||||
|
||||
M: Mail patches to: FullName <address@domain>
|
||||
R: Designated reviewer: FullName <address@domain>
|
||||
These reviewers should be CCed on patches.
|
||||
L: Mailing list that is relevant to this area
|
||||
W: Web-page with status/info
|
||||
Q: Patchwork web based patch tracking system site
|
||||
@@ -196,8 +198,8 @@ F: hw/nios2/
|
||||
F: disas/nios2.c
|
||||
|
||||
OpenRISC
|
||||
M: Jia Liu <proljc@gmail.com>
|
||||
S: Maintained
|
||||
M: Stafford Horne <shorne@gmail.com>
|
||||
S: Odd Fixes
|
||||
F: target/openrisc/
|
||||
F: hw/openrisc/
|
||||
F: tests/tcg/openrisc/
|
||||
@@ -1393,6 +1395,7 @@ S: Supported
|
||||
F: qobject/
|
||||
F: include/qapi/qmp/
|
||||
X: include/qapi/qmp/dispatch.h
|
||||
F: scripts/coccinelle/qobject.cocci
|
||||
F: tests/check-qdict.c
|
||||
F: tests/check-qfloat.c
|
||||
F: tests/check-qint.c
|
||||
@@ -1546,6 +1549,18 @@ F: net/colo*
|
||||
F: net/filter-rewriter.c
|
||||
F: net/filter-mirror.c
|
||||
|
||||
Record/replay
|
||||
M: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
|
||||
R: Paolo Bonzini <pbonzini@redhat.com>
|
||||
W: http://wiki.qemu.org/Features/record-replay
|
||||
S: Supported
|
||||
F: replay/*
|
||||
F: block/blkreplay.c
|
||||
F: net/filter-replay.c
|
||||
F: include/sysemu/replay.h
|
||||
F: docs/replay.txt
|
||||
F: stubs/replay.c
|
||||
|
||||
Usermode Emulation
|
||||
------------------
|
||||
Overall
|
||||
|
||||
@@ -2028,6 +2028,8 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
|
||||
sw = sw1;
|
||||
}
|
||||
QLIST_REMOVE (cap, entries);
|
||||
g_free (cap->hw.mix_buf);
|
||||
g_free (cap->buf);
|
||||
g_free (cap);
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -88,6 +88,7 @@ static void wav_capture_destroy (void *opaque)
|
||||
WAVState *wav = opaque;
|
||||
|
||||
AUD_del_capture (wav->cap, wav);
|
||||
g_free (wav);
|
||||
}
|
||||
|
||||
static void wav_capture_info (void *opaque)
|
||||
|
||||
94
block.c
94
block.c
@@ -974,16 +974,14 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
|
||||
static void update_options_from_flags(QDict *options, int flags)
|
||||
{
|
||||
if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) {
|
||||
qdict_put(options, BDRV_OPT_CACHE_DIRECT,
|
||||
qbool_from_bool(flags & BDRV_O_NOCACHE));
|
||||
qdict_put_bool(options, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE);
|
||||
}
|
||||
if (!qdict_haskey(options, BDRV_OPT_CACHE_NO_FLUSH)) {
|
||||
qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
|
||||
qbool_from_bool(flags & BDRV_O_NO_FLUSH));
|
||||
qdict_put_bool(options, BDRV_OPT_CACHE_NO_FLUSH,
|
||||
flags & BDRV_O_NO_FLUSH);
|
||||
}
|
||||
if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
|
||||
qdict_put(options, BDRV_OPT_READ_ONLY,
|
||||
qbool_from_bool(!(flags & BDRV_O_RDWR)));
|
||||
qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1204,7 +1202,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
|
||||
filename = qdict_get_try_str(options, "filename");
|
||||
}
|
||||
|
||||
if (drv->bdrv_needs_filename && !filename) {
|
||||
if (drv->bdrv_needs_filename && (!filename || !filename[0])) {
|
||||
error_setg(errp, "The '%s' block driver requires a file name",
|
||||
drv->format_name);
|
||||
ret = -EINVAL;
|
||||
@@ -1399,7 +1397,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
|
||||
/* Fetch the file name from the options QDict if necessary */
|
||||
if (protocol && filename) {
|
||||
if (!qdict_haskey(*options, "filename")) {
|
||||
qdict_put(*options, "filename", qstring_from_str(filename));
|
||||
qdict_put_str(*options, "filename", filename);
|
||||
parse_filename = true;
|
||||
} else {
|
||||
error_setg(errp, "Can't specify 'file' and 'filename' options at "
|
||||
@@ -1420,7 +1418,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
|
||||
}
|
||||
|
||||
drvname = drv->format_name;
|
||||
qdict_put(*options, "driver", qstring_from_str(drvname));
|
||||
qdict_put_str(*options, "driver", drvname);
|
||||
} else {
|
||||
error_setg(errp, "Must specify either driver or file");
|
||||
return -EINVAL;
|
||||
@@ -2075,7 +2073,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
|
||||
}
|
||||
|
||||
if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
|
||||
qdict_put(options, "driver", qstring_from_str(bs->backing_format));
|
||||
qdict_put_str(options, "driver", bs->backing_format);
|
||||
}
|
||||
|
||||
backing_hd = bdrv_open_inherit(*backing_filename ? backing_filename : NULL,
|
||||
@@ -2197,7 +2195,7 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
|
||||
char *tmp_filename = g_malloc0(PATH_MAX + 1);
|
||||
int64_t total_size;
|
||||
QemuOpts *opts = NULL;
|
||||
BlockDriverState *bs_snapshot;
|
||||
BlockDriverState *bs_snapshot = NULL;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
@@ -2230,38 +2228,32 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
/* Prepare options QDict for the temporary file */
|
||||
qdict_put(snapshot_options, "file.driver",
|
||||
qstring_from_str("file"));
|
||||
qdict_put(snapshot_options, "file.filename",
|
||||
qstring_from_str(tmp_filename));
|
||||
qdict_put(snapshot_options, "driver",
|
||||
qstring_from_str("qcow2"));
|
||||
qdict_put_str(snapshot_options, "file.driver", "file");
|
||||
qdict_put_str(snapshot_options, "file.filename", tmp_filename);
|
||||
qdict_put_str(snapshot_options, "driver", "qcow2");
|
||||
|
||||
bs_snapshot = bdrv_open(NULL, NULL, snapshot_options, flags, errp);
|
||||
snapshot_options = NULL;
|
||||
if (!bs_snapshot) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* bdrv_append() consumes a strong reference to bs_snapshot (i.e. it will
|
||||
* call bdrv_unref() on it), so in order to be able to return one, we have
|
||||
* to increase bs_snapshot's refcount here */
|
||||
/* bdrv_append() consumes a strong reference to bs_snapshot
|
||||
* (i.e. it will call bdrv_unref() on it) even on error, so in
|
||||
* order to be able to return one, we have to increase
|
||||
* bs_snapshot's refcount here */
|
||||
bdrv_ref(bs_snapshot);
|
||||
bdrv_append(bs_snapshot, bs, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
bs_snapshot = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_free(tmp_filename);
|
||||
return bs_snapshot;
|
||||
|
||||
out:
|
||||
QDECREF(snapshot_options);
|
||||
g_free(tmp_filename);
|
||||
return NULL;
|
||||
return bs_snapshot;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2410,8 +2402,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
qdict_put(options, "file",
|
||||
qstring_from_str(bdrv_get_node_name(file_bs)));
|
||||
qdict_put_str(options, "file", bdrv_get_node_name(file_bs));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2433,8 +2424,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||
* sure to update both bs->options (which has the full effective
|
||||
* options for bs) and options (which has file.* already removed).
|
||||
*/
|
||||
qdict_put(bs->options, "driver", qstring_from_str(drv->format_name));
|
||||
qdict_put(options, "driver", qstring_from_str(drv->format_name));
|
||||
qdict_put_str(bs->options, "driver", drv->format_name);
|
||||
qdict_put_str(options, "driver", drv->format_name);
|
||||
} else if (!drv) {
|
||||
error_setg(errp, "Must specify either driver or file");
|
||||
goto fail;
|
||||
@@ -2810,12 +2801,12 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
|
||||
* that they are checked at the end of this function. */
|
||||
value = qemu_opt_get(opts, "node-name");
|
||||
if (value) {
|
||||
qdict_put(reopen_state->options, "node-name", qstring_from_str(value));
|
||||
qdict_put_str(reopen_state->options, "node-name", value);
|
||||
}
|
||||
|
||||
value = qemu_opt_get(opts, "driver");
|
||||
if (value) {
|
||||
qdict_put(reopen_state->options, "driver", qstring_from_str(value));
|
||||
qdict_put_str(reopen_state->options, "driver", value);
|
||||
}
|
||||
|
||||
/* If we are to stay read-only, do not allow permission change
|
||||
@@ -3307,26 +3298,30 @@ exit:
|
||||
/**
|
||||
* Truncate file to 'offset' bytes (needed only for file protocols)
|
||||
*/
|
||||
int bdrv_truncate(BdrvChild *child, int64_t offset)
|
||||
int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = child->bs;
|
||||
BlockDriver *drv = bs->drv;
|
||||
int ret;
|
||||
|
||||
/* FIXME: Some format block drivers use this function instead of implicitly
|
||||
* growing their file by writing beyond its end.
|
||||
* See bdrv_aligned_pwritev() for an explanation why we currently
|
||||
* cannot assert this permission in that case. */
|
||||
// assert(child->perm & BLK_PERM_RESIZE);
|
||||
assert(child->perm & BLK_PERM_RESIZE);
|
||||
|
||||
if (!drv)
|
||||
if (!drv) {
|
||||
error_setg(errp, "No medium inserted");
|
||||
return -ENOMEDIUM;
|
||||
if (!drv->bdrv_truncate)
|
||||
}
|
||||
if (!drv->bdrv_truncate) {
|
||||
error_setg(errp, "Image format driver does not support resize");
|
||||
return -ENOTSUP;
|
||||
if (bs->read_only)
|
||||
}
|
||||
if (bs->read_only) {
|
||||
error_setg(errp, "Image is read-only");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
ret = drv->bdrv_truncate(bs, offset);
|
||||
assert(!(bs->open_flags & BDRV_O_INACTIVE));
|
||||
|
||||
ret = drv->bdrv_truncate(bs, offset, errp);
|
||||
if (ret == 0) {
|
||||
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
|
||||
bdrv_dirty_bitmap_truncate(bs);
|
||||
@@ -4302,8 +4297,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
|
||||
if (backing_fmt) {
|
||||
backing_options = qdict_new();
|
||||
qdict_put(backing_options, "driver",
|
||||
qstring_from_str(backing_fmt));
|
||||
qdict_put_str(backing_options, "driver", backing_fmt);
|
||||
}
|
||||
|
||||
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
|
||||
@@ -4708,11 +4702,9 @@ void bdrv_refresh_filename(BlockDriverState *bs)
|
||||
* contain a representation of the filename, therefore the following
|
||||
* suffices without querying the (exact_)filename of this BDS. */
|
||||
if (bs->file->bs->full_open_options) {
|
||||
qdict_put_obj(opts, "driver",
|
||||
QOBJECT(qstring_from_str(drv->format_name)));
|
||||
qdict_put_str(opts, "driver", drv->format_name);
|
||||
QINCREF(bs->file->bs->full_open_options);
|
||||
qdict_put_obj(opts, "file",
|
||||
QOBJECT(bs->file->bs->full_open_options));
|
||||
qdict_put(opts, "file", bs->file->bs->full_open_options);
|
||||
|
||||
bs->full_open_options = opts;
|
||||
} else {
|
||||
@@ -4728,8 +4720,7 @@ void bdrv_refresh_filename(BlockDriverState *bs)
|
||||
|
||||
opts = qdict_new();
|
||||
append_open_options(opts, bs);
|
||||
qdict_put_obj(opts, "driver",
|
||||
QOBJECT(qstring_from_str(drv->format_name)));
|
||||
qdict_put_str(opts, "driver", drv->format_name);
|
||||
|
||||
if (bs->exact_filename[0]) {
|
||||
/* This may not work for all block protocol drivers (some may
|
||||
@@ -4739,8 +4730,7 @@ void bdrv_refresh_filename(BlockDriverState *bs)
|
||||
* needs some special format of the options QDict, it needs to
|
||||
* implement the driver-specific bdrv_refresh_filename() function.
|
||||
*/
|
||||
qdict_put_obj(opts, "filename",
|
||||
QOBJECT(qstring_from_str(bs->exact_filename)));
|
||||
qdict_put_str(opts, "filename", bs->exact_filename);
|
||||
}
|
||||
|
||||
bs->full_open_options = opts;
|
||||
|
||||
@@ -301,7 +301,7 @@ static void blkdebug_parse_filename(const char *filename, QDict *options,
|
||||
if (!strstart(filename, "blkdebug:", &filename)) {
|
||||
/* There was no prefix; therefore, all options have to be already
|
||||
present in the QDict (except for the filename) */
|
||||
qdict_put(options, "x-image", qstring_from_str(filename));
|
||||
qdict_put_str(options, "x-image", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ static void blkdebug_parse_filename(const char *filename, QDict *options,
|
||||
|
||||
/* TODO Allow multi-level nesting and set file.filename here */
|
||||
filename = c + 1;
|
||||
qdict_put(options, "x-image", qstring_from_str(filename));
|
||||
qdict_put_str(options, "x-image", filename);
|
||||
}
|
||||
|
||||
static QemuOptsList runtime_opts = {
|
||||
@@ -389,14 +389,12 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
} else if (align) {
|
||||
error_setg(errp, "Invalid alignment");
|
||||
ret = -EINVAL;
|
||||
goto fail_unref;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
goto out;
|
||||
|
||||
fail_unref:
|
||||
bdrv_unref_child(bs, bs->file);
|
||||
out:
|
||||
if (ret < 0) {
|
||||
g_free(s->config_file);
|
||||
@@ -661,9 +659,9 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
|
||||
return bdrv_getlength(bs->file->bs);
|
||||
}
|
||||
|
||||
static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
return bdrv_truncate(bs->file, offset);
|
||||
return bdrv_truncate(bs->file, offset, errp);
|
||||
}
|
||||
|
||||
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
@@ -695,10 +693,10 @@ static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
}
|
||||
|
||||
opts = qdict_new();
|
||||
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
|
||||
qdict_put_str(opts, "driver", "blkdebug");
|
||||
|
||||
QINCREF(bs->file->bs->full_open_options);
|
||||
qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options));
|
||||
qdict_put(opts, "image", bs->file->bs->full_open_options);
|
||||
|
||||
for (e = qdict_first(options); e; e = qdict_next(options, e)) {
|
||||
if (strcmp(qdict_entry_key(e), "x-image")) {
|
||||
|
||||
@@ -37,9 +37,6 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
if (ret < 0) {
|
||||
bdrv_unref_child(bs, bs->file);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ static void blkverify_parse_filename(const char *filename, QDict *options,
|
||||
if (!strstart(filename, "blkverify:", &filename)) {
|
||||
/* There was no prefix; therefore, all options have to be already
|
||||
present in the QDict (except for the filename) */
|
||||
qdict_put(options, "x-image", qstring_from_str(filename));
|
||||
qdict_put_str(options, "x-image", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ static void blkverify_parse_filename(const char *filename, QDict *options,
|
||||
|
||||
/* TODO Allow multi-level nesting and set file.filename here */
|
||||
filename = c + 1;
|
||||
qdict_put(options, "x-image", qstring_from_str(filename));
|
||||
qdict_put_str(options, "x-image", filename);
|
||||
}
|
||||
|
||||
static QemuOptsList runtime_opts = {
|
||||
@@ -142,9 +142,6 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
if (ret < 0) {
|
||||
bdrv_unref_child(bs, bs->file);
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
@@ -291,13 +288,12 @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
&& s->test_file->bs->full_open_options)
|
||||
{
|
||||
QDict *opts = qdict_new();
|
||||
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkverify")));
|
||||
qdict_put_str(opts, "driver", "blkverify");
|
||||
|
||||
QINCREF(bs->file->bs->full_open_options);
|
||||
qdict_put_obj(opts, "raw", QOBJECT(bs->file->bs->full_open_options));
|
||||
qdict_put(opts, "raw", bs->file->bs->full_open_options);
|
||||
QINCREF(s->test_file->bs->full_open_options);
|
||||
qdict_put_obj(opts, "test",
|
||||
QOBJECT(s->test_file->bs->full_open_options));
|
||||
qdict_put(opts, "test", s->test_file->bs->full_open_options);
|
||||
|
||||
bs->full_open_options = opts;
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ void monitor_remove_blk(BlockBackend *blk)
|
||||
* Return @blk's name, a non-null string.
|
||||
* Returns an empty string iff @blk is not referenced by the monitor.
|
||||
*/
|
||||
const char *blk_name(BlockBackend *blk)
|
||||
const char *blk_name(const BlockBackend *blk)
|
||||
{
|
||||
return blk->name ?: "";
|
||||
}
|
||||
@@ -1746,13 +1746,14 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
|
||||
BDRV_REQ_WRITE_COMPRESSED);
|
||||
}
|
||||
|
||||
int blk_truncate(BlockBackend *blk, int64_t offset)
|
||||
int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp)
|
||||
{
|
||||
if (!blk_is_available(blk)) {
|
||||
error_setg(errp, "No medium inserted");
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
return bdrv_truncate(blk->root, offset);
|
||||
return bdrv_truncate(blk->root, offset, errp);
|
||||
}
|
||||
|
||||
static void blk_pdiscard_entry(void *opaque)
|
||||
|
||||
@@ -151,7 +151,7 @@ static void coroutine_fn commit_run(void *opaque)
|
||||
}
|
||||
|
||||
if (base_len < s->common.len) {
|
||||
ret = blk_truncate(s->base, s->common.len);
|
||||
ret = blk_truncate(s->base, s->common.len, NULL);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
@@ -511,8 +511,9 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
* grow the backing file image if possible. If not possible,
|
||||
* we must return an error */
|
||||
if (length > backing_length) {
|
||||
ret = blk_truncate(backing, length);
|
||||
ret = blk_truncate(backing, length, &local_err);
|
||||
if (ret < 0) {
|
||||
error_report_err(local_err);
|
||||
goto ro_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +381,8 @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
|
||||
Error **errp)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
size_t payload_offset =
|
||||
@@ -389,7 +390,7 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
|
||||
|
||||
offset += payload_offset;
|
||||
|
||||
return bdrv_truncate(bs->file, offset);
|
||||
return bdrv_truncate(bs->file, offset, errp);
|
||||
}
|
||||
|
||||
static void block_crypto_close(BlockDriverState *bs)
|
||||
|
||||
@@ -548,7 +548,7 @@ static void curl_clean_state(CURLState *s)
|
||||
static void curl_parse_filename(const char *filename, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
|
||||
qdict_put_str(options, CURL_BLOCK_OPT_URL, filename);
|
||||
}
|
||||
|
||||
static void curl_detach_aio_context(BlockDriverState *bs)
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/log.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "trace.h"
|
||||
@@ -377,7 +375,7 @@ static void raw_parse_filename(const char *filename, QDict *options,
|
||||
* function call can be ignored. */
|
||||
strstart(filename, "file:", &filename);
|
||||
|
||||
qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
|
||||
qdict_put_str(options, "filename", filename);
|
||||
}
|
||||
|
||||
static QemuOptsList raw_runtime_opts = {
|
||||
@@ -1409,24 +1407,31 @@ static void raw_close(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
if (fstat(s->fd, &st)) {
|
||||
return -errno;
|
||||
ret = -errno;
|
||||
error_setg_errno(errp, -ret, "Failed to fstat() the file");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
if (ftruncate(s->fd, offset) < 0) {
|
||||
return -errno;
|
||||
ret = -errno;
|
||||
error_setg_errno(errp, -ret, "Failed to resize the file");
|
||||
return ret;
|
||||
}
|
||||
} else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
|
||||
if (offset > raw_getlength(bs)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (offset > raw_getlength(bs)) {
|
||||
error_setg(errp, "Cannot grow device files");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
error_setg(errp, "Resizing this file is not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -2150,7 +2155,7 @@ static void hdev_parse_filename(const char *filename, QDict *options,
|
||||
/* The prefix is optional, just as for "file". */
|
||||
strstart(filename, "host_device:", &filename);
|
||||
|
||||
qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
|
||||
qdict_put_str(options, "filename", filename);
|
||||
}
|
||||
|
||||
static bool hdev_is_sg(BlockDriverState *bs)
|
||||
@@ -2239,7 +2244,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto hdev_open_Mac_error;
|
||||
}
|
||||
|
||||
qdict_put(options, "filename", qstring_from_str(bsd_path));
|
||||
qdict_put_str(options, "filename", bsd_path);
|
||||
|
||||
hdev_open_Mac_error:
|
||||
g_free(mediaType);
|
||||
@@ -2449,7 +2454,7 @@ static void cdrom_parse_filename(const char *filename, QDict *options,
|
||||
/* The prefix is optional, just as for "file". */
|
||||
strstart(filename, "host_cdrom:", &filename);
|
||||
|
||||
qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
|
||||
qdict_put_str(options, "filename", filename);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "block/raw-aio.h"
|
||||
@@ -282,7 +281,7 @@ static void raw_parse_filename(const char *filename, QDict *options,
|
||||
* function call can be ignored. */
|
||||
strstart(filename, "file:", &filename);
|
||||
|
||||
qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
|
||||
qdict_put_str(options, "filename", filename);
|
||||
}
|
||||
|
||||
static QemuOptsList raw_runtime_opts = {
|
||||
@@ -461,7 +460,7 @@ static void raw_close(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
LONG low, high;
|
||||
@@ -476,11 +475,11 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
*/
|
||||
dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN);
|
||||
if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
|
||||
fprintf(stderr, "SetFilePointer error: %lu\n", GetLastError());
|
||||
error_setg_win32(errp, GetLastError(), "SetFilePointer error");
|
||||
return -EIO;
|
||||
}
|
||||
if (SetEndOfFile(s->hfile) == 0) {
|
||||
fprintf(stderr, "SetEndOfFile error: %lu\n", GetLastError());
|
||||
error_setg_win32(errp, GetLastError(), "SetEndOfFile error");
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
@@ -669,7 +668,7 @@ static void hdev_parse_filename(const char *filename, QDict *options,
|
||||
/* The prefix is optional, just as for "file". */
|
||||
strstart(filename, "host_device:", &filename);
|
||||
|
||||
qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
|
||||
qdict_put_str(options, "filename", filename);
|
||||
}
|
||||
|
||||
static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
@@ -321,7 +321,7 @@ static int parse_volume_options(BlockdevOptionsGluster *gconf, char *path)
|
||||
static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
|
||||
const char *filename)
|
||||
{
|
||||
SocketAddressFlat *gsconf;
|
||||
SocketAddress *gsconf;
|
||||
URI *uri;
|
||||
QueryParams *qp = NULL;
|
||||
bool is_unix = false;
|
||||
@@ -332,19 +332,19 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gconf->server = g_new0(SocketAddressFlatList, 1);
|
||||
gconf->server->value = gsconf = g_new0(SocketAddressFlat, 1);
|
||||
gconf->server = g_new0(SocketAddressList, 1);
|
||||
gconf->server->value = gsconf = g_new0(SocketAddress, 1);
|
||||
|
||||
/* transport */
|
||||
if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
|
||||
gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
|
||||
gsconf->type = SOCKET_ADDRESS_TYPE_INET;
|
||||
} else if (!strcmp(uri->scheme, "gluster+tcp")) {
|
||||
gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
|
||||
gsconf->type = SOCKET_ADDRESS_TYPE_INET;
|
||||
} else if (!strcmp(uri->scheme, "gluster+unix")) {
|
||||
gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_UNIX;
|
||||
gsconf->type = SOCKET_ADDRESS_TYPE_UNIX;
|
||||
is_unix = true;
|
||||
} else if (!strcmp(uri->scheme, "gluster+rdma")) {
|
||||
gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
|
||||
gsconf->type = SOCKET_ADDRESS_TYPE_INET;
|
||||
error_report("Warning: rdma feature is not supported, falling "
|
||||
"back to tcp");
|
||||
} else {
|
||||
@@ -396,7 +396,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
struct glfs *glfs;
|
||||
int ret;
|
||||
int old_errno;
|
||||
SocketAddressFlatList *server;
|
||||
SocketAddressList *server;
|
||||
unsigned long long port;
|
||||
|
||||
glfs = glfs_find_preopened(gconf->volume);
|
||||
@@ -413,11 +413,11 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
|
||||
for (server = gconf->server; server; server = server->next) {
|
||||
switch (server->value->type) {
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_UNIX:
|
||||
case SOCKET_ADDRESS_TYPE_UNIX:
|
||||
ret = glfs_set_volfile_server(glfs, "unix",
|
||||
server->value->u.q_unix.path, 0);
|
||||
break;
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_INET:
|
||||
case SOCKET_ADDRESS_TYPE_INET:
|
||||
if (parse_uint_full(server->value->u.inet.port, &port, 10) < 0 ||
|
||||
port > 65535) {
|
||||
error_setg(errp, "'%s' is not a valid port number",
|
||||
@@ -429,8 +429,8 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
server->value->u.inet.host,
|
||||
(int)port);
|
||||
break;
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_VSOCK:
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_FD:
|
||||
case SOCKET_ADDRESS_TYPE_VSOCK:
|
||||
case SOCKET_ADDRESS_TYPE_FD:
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@@ -450,7 +450,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
error_setg(errp, "Gluster connection for volume %s, path %s failed"
|
||||
" to connect", gconf->volume, gconf->path);
|
||||
for (server = gconf->server; server; server = server->next) {
|
||||
if (server->value->type == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
|
||||
if (server->value->type == SOCKET_ADDRESS_TYPE_UNIX) {
|
||||
error_append_hint(errp, "hint: failed on socket %s ",
|
||||
server->value->u.q_unix.path);
|
||||
} else {
|
||||
@@ -487,8 +487,8 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
|
||||
QDict *options, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
SocketAddressFlat *gsconf = NULL;
|
||||
SocketAddressFlatList *curr = NULL;
|
||||
SocketAddress *gsconf = NULL;
|
||||
SocketAddressList *curr = NULL;
|
||||
QDict *backing_options = NULL;
|
||||
Error *local_err = NULL;
|
||||
char *str = NULL;
|
||||
@@ -542,14 +542,14 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
|
||||
goto out;
|
||||
|
||||
}
|
||||
gsconf = g_new0(SocketAddressFlat, 1);
|
||||
gsconf = g_new0(SocketAddress, 1);
|
||||
if (!strcmp(ptr, "tcp")) {
|
||||
ptr = "inet"; /* accept legacy "tcp" */
|
||||
}
|
||||
type = qapi_enum_parse(SocketAddressFlatType_lookup, ptr,
|
||||
SOCKET_ADDRESS_FLAT_TYPE__MAX, -1, NULL);
|
||||
if (type != SOCKET_ADDRESS_FLAT_TYPE_INET
|
||||
&& type != SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
|
||||
type = qapi_enum_parse(SocketAddressType_lookup, ptr,
|
||||
SOCKET_ADDRESS_TYPE__MAX, -1, NULL);
|
||||
if (type != SOCKET_ADDRESS_TYPE_INET
|
||||
&& type != SOCKET_ADDRESS_TYPE_UNIX) {
|
||||
error_setg(&local_err,
|
||||
"Parameter '%s' may be 'inet' or 'unix'",
|
||||
GLUSTER_OPT_TYPE);
|
||||
@@ -559,7 +559,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
|
||||
gsconf->type = type;
|
||||
qemu_opts_del(opts);
|
||||
|
||||
if (gsconf->type == SOCKET_ADDRESS_FLAT_TYPE_INET) {
|
||||
if (gsconf->type == SOCKET_ADDRESS_TYPE_INET) {
|
||||
/* create opts info from runtime_inet_opts list */
|
||||
opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, backing_options, &local_err);
|
||||
@@ -628,11 +628,11 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
|
||||
}
|
||||
|
||||
if (gconf->server == NULL) {
|
||||
gconf->server = g_new0(SocketAddressFlatList, 1);
|
||||
gconf->server = g_new0(SocketAddressList, 1);
|
||||
gconf->server->value = gsconf;
|
||||
curr = gconf->server;
|
||||
} else {
|
||||
curr->next = g_new0(SocketAddressFlatList, 1);
|
||||
curr->next = g_new0(SocketAddressList, 1);
|
||||
curr->next->value = gsconf;
|
||||
curr = curr->next;
|
||||
}
|
||||
@@ -648,7 +648,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
qapi_free_SocketAddressFlat(gsconf);
|
||||
qapi_free_SocketAddress(gsconf);
|
||||
qemu_opts_del(opts);
|
||||
g_free(str);
|
||||
QDECREF(backing_options);
|
||||
@@ -1092,14 +1092,17 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
|
||||
return acb.ret;
|
||||
}
|
||||
|
||||
static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
BDRVGlusterState *s = bs->opaque;
|
||||
|
||||
ret = glfs_ftruncate(s->fd, offset);
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
ret = -errno;
|
||||
error_setg_errno(errp, -ret, "Failed to truncate file");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
16
block/io.c
16
block/io.c
@@ -1362,16 +1362,8 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
||||
assert(!waited || !req->serialising);
|
||||
assert(req->overlap_offset <= offset);
|
||||
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
|
||||
/* FIXME: Block migration uses the BlockBackend of the guest device at a
|
||||
* point when it has not yet taken write permissions. This will be
|
||||
* fixed by a future patch, but for now we have to bypass this
|
||||
* assertion for block migration to work. */
|
||||
// assert(child->perm & BLK_PERM_WRITE);
|
||||
/* FIXME: Because of the above, we also cannot guarantee that all format
|
||||
* BDS take the BLK_PERM_RESIZE permission on their file BDS, since
|
||||
* they are not obligated to do so if they do not have any parent
|
||||
* that has taken the permission to write to them. */
|
||||
// assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
|
||||
assert(child->perm & BLK_PERM_WRITE);
|
||||
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
|
||||
|
||||
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||
|
||||
@@ -1452,7 +1444,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
|
||||
int ret = 0;
|
||||
|
||||
head_padding_bytes = offset & (align - 1);
|
||||
tail_padding_bytes = align - ((offset + bytes) & (align - 1));
|
||||
tail_padding_bytes = (align - (offset + bytes)) & (align - 1);
|
||||
|
||||
|
||||
assert(flags & BDRV_REQ_ZERO_WRITE);
|
||||
@@ -2308,7 +2300,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
|
||||
|
||||
bdrv_inc_in_flight(bs);
|
||||
|
||||
if (!bs || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs) ||
|
||||
if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs) ||
|
||||
bdrv_is_sg(bs)) {
|
||||
goto early_exit;
|
||||
}
|
||||
|
||||
@@ -2059,22 +2059,24 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
|
||||
}
|
||||
}
|
||||
|
||||
static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int iscsi_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (iscsilun->type != TYPE_DISK) {
|
||||
error_setg(errp, "Cannot resize non-disk iSCSI devices");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
iscsi_readcapacity_sync(iscsilun, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (offset > iscsi_getlength(bs)) {
|
||||
error_setg(errp, "Cannot grow iSCSI devices");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -724,7 +724,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
}
|
||||
|
||||
if (s->bdev_length > base_length) {
|
||||
ret = blk_truncate(s->target, s->bdev_length);
|
||||
ret = blk_truncate(s->target, s->bdev_length, NULL);
|
||||
if (ret < 0) {
|
||||
goto immediate_exit;
|
||||
}
|
||||
|
||||
77
block/nbd.c
77
block/nbd.c
@@ -47,7 +47,7 @@ typedef struct BDRVNBDState {
|
||||
NBDClientSession client;
|
||||
|
||||
/* For nbd_refresh_filename() */
|
||||
SocketAddressFlat *saddr;
|
||||
SocketAddress *saddr;
|
||||
char *export, *tlscredsid;
|
||||
} BDRVNBDState;
|
||||
|
||||
@@ -79,7 +79,7 @@ static int nbd_parse_uri(const char *filename, QDict *options)
|
||||
p = uri->path ? uri->path : "/";
|
||||
p += strspn(p, "/");
|
||||
if (p[0]) {
|
||||
qdict_put(options, "export", qstring_from_str(p));
|
||||
qdict_put_str(options, "export", p);
|
||||
}
|
||||
|
||||
qp = query_params_parse(uri->query);
|
||||
@@ -94,9 +94,8 @@ static int nbd_parse_uri(const char *filename, QDict *options)
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
qdict_put(options, "server.type", qstring_from_str("unix"));
|
||||
qdict_put(options, "server.path",
|
||||
qstring_from_str(qp->p[0].value));
|
||||
qdict_put_str(options, "server.type", "unix");
|
||||
qdict_put_str(options, "server.path", qp->p[0].value);
|
||||
} else {
|
||||
QString *host;
|
||||
char *port_str;
|
||||
@@ -115,11 +114,11 @@ static int nbd_parse_uri(const char *filename, QDict *options)
|
||||
host = qstring_from_str(uri->server);
|
||||
}
|
||||
|
||||
qdict_put(options, "server.type", qstring_from_str("inet"));
|
||||
qdict_put_str(options, "server.type", "inet");
|
||||
qdict_put(options, "server.host", host);
|
||||
|
||||
port_str = g_strdup_printf("%d", uri->port ?: NBD_DEFAULT_PORT);
|
||||
qdict_put(options, "server.port", qstring_from_str(port_str));
|
||||
qdict_put_str(options, "server.port", port_str);
|
||||
g_free(port_str);
|
||||
}
|
||||
|
||||
@@ -181,7 +180,7 @@ static void nbd_parse_filename(const char *filename, QDict *options,
|
||||
export_name[0] = 0; /* truncate 'file' */
|
||||
export_name += strlen(EN_OPTSTR);
|
||||
|
||||
qdict_put(options, "export", qstring_from_str(export_name));
|
||||
qdict_put_str(options, "export", export_name);
|
||||
}
|
||||
|
||||
/* extract the host_spec - fail if it's not nbd:... */
|
||||
@@ -196,19 +195,19 @@ static void nbd_parse_filename(const char *filename, QDict *options,
|
||||
|
||||
/* are we a UNIX or TCP socket? */
|
||||
if (strstart(host_spec, "unix:", &unixpath)) {
|
||||
qdict_put(options, "server.type", qstring_from_str("unix"));
|
||||
qdict_put(options, "server.path", qstring_from_str(unixpath));
|
||||
qdict_put_str(options, "server.type", "unix");
|
||||
qdict_put_str(options, "server.path", unixpath);
|
||||
} else {
|
||||
InetSocketAddress *addr = NULL;
|
||||
InetSocketAddress *addr = g_new(InetSocketAddress, 1);
|
||||
|
||||
addr = inet_parse(host_spec, errp);
|
||||
if (!addr) {
|
||||
goto out;
|
||||
if (inet_parse(addr, host_spec, errp)) {
|
||||
goto out_inet;
|
||||
}
|
||||
|
||||
qdict_put(options, "server.type", qstring_from_str("inet"));
|
||||
qdict_put(options, "server.host", qstring_from_str(addr->host));
|
||||
qdict_put(options, "server.port", qstring_from_str(addr->port));
|
||||
qdict_put_str(options, "server.type", "inet");
|
||||
qdict_put_str(options, "server.host", addr->host);
|
||||
qdict_put_str(options, "server.port", addr->port);
|
||||
out_inet:
|
||||
qapi_free_InetSocketAddress(addr);
|
||||
}
|
||||
|
||||
@@ -247,22 +246,22 @@ static bool nbd_process_legacy_socket_options(QDict *output_options,
|
||||
return false;
|
||||
}
|
||||
|
||||
qdict_put(output_options, "server.type", qstring_from_str("unix"));
|
||||
qdict_put(output_options, "server.path", qstring_from_str(path));
|
||||
qdict_put_str(output_options, "server.type", "unix");
|
||||
qdict_put_str(output_options, "server.path", path);
|
||||
} else if (host) {
|
||||
qdict_put(output_options, "server.type", qstring_from_str("inet"));
|
||||
qdict_put(output_options, "server.host", qstring_from_str(host));
|
||||
qdict_put(output_options, "server.port",
|
||||
qstring_from_str(port ?: stringify(NBD_DEFAULT_PORT)));
|
||||
qdict_put_str(output_options, "server.type", "inet");
|
||||
qdict_put_str(output_options, "server.host", host);
|
||||
qdict_put_str(output_options, "server.port",
|
||||
port ?: stringify(NBD_DEFAULT_PORT));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static SocketAddressFlat *nbd_config(BDRVNBDState *s, QDict *options,
|
||||
Error **errp)
|
||||
static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
SocketAddressFlat *saddr = NULL;
|
||||
SocketAddress *saddr = NULL;
|
||||
QDict *addr = NULL;
|
||||
QObject *crumpled_addr = NULL;
|
||||
Visitor *iv = NULL;
|
||||
@@ -288,7 +287,7 @@ static SocketAddressFlat *nbd_config(BDRVNBDState *s, QDict *options,
|
||||
* visitor expects the former.
|
||||
*/
|
||||
iv = qobject_input_visitor_new(crumpled_addr);
|
||||
visit_type_SocketAddressFlat(iv, NULL, &saddr, &local_err);
|
||||
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto done;
|
||||
@@ -307,10 +306,9 @@ NBDClientSession *nbd_get_client_session(BlockDriverState *bs)
|
||||
return &s->client;
|
||||
}
|
||||
|
||||
static QIOChannelSocket *nbd_establish_connection(SocketAddressFlat *saddr_flat,
|
||||
static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
|
||||
Error **errp)
|
||||
{
|
||||
SocketAddress *saddr = socket_address_crumple(saddr_flat);
|
||||
QIOChannelSocket *sioc;
|
||||
Error *local_err = NULL;
|
||||
|
||||
@@ -320,7 +318,6 @@ static QIOChannelSocket *nbd_establish_connection(SocketAddressFlat *saddr_flat,
|
||||
qio_channel_socket_connect_sync(sioc,
|
||||
saddr,
|
||||
&local_err);
|
||||
qapi_free_SocketAddress(saddr);
|
||||
if (local_err) {
|
||||
object_unref(OBJECT(sioc));
|
||||
error_propagate(errp, local_err);
|
||||
@@ -413,7 +410,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Translate @host, @port, and @path to a SocketAddressFlat */
|
||||
/* Translate @host, @port, and @path to a SocketAddress */
|
||||
if (!nbd_process_legacy_socket_options(options, opts, errp)) {
|
||||
goto error;
|
||||
}
|
||||
@@ -434,7 +431,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
/* TODO SOCKET_ADDRESS_KIND_FD where fd has AF_INET or AF_INET6 */
|
||||
if (s->saddr->type != SOCKET_ADDRESS_FLAT_TYPE_INET) {
|
||||
if (s->saddr->type != SOCKET_ADDRESS_TYPE_INET) {
|
||||
error_setg(errp, "TLS only supported over IP sockets");
|
||||
goto error;
|
||||
}
|
||||
@@ -461,7 +458,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
object_unref(OBJECT(tlscreds));
|
||||
}
|
||||
if (ret < 0) {
|
||||
qapi_free_SocketAddressFlat(s->saddr);
|
||||
qapi_free_SocketAddress(s->saddr);
|
||||
g_free(s->export);
|
||||
g_free(s->tlscredsid);
|
||||
}
|
||||
@@ -487,7 +484,7 @@ static void nbd_close(BlockDriverState *bs)
|
||||
|
||||
nbd_client_close(bs);
|
||||
|
||||
qapi_free_SocketAddressFlat(s->saddr);
|
||||
qapi_free_SocketAddress(s->saddr);
|
||||
g_free(s->export);
|
||||
g_free(s->tlscredsid);
|
||||
}
|
||||
@@ -518,17 +515,17 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
Visitor *ov;
|
||||
const char *host = NULL, *port = NULL, *path = NULL;
|
||||
|
||||
if (s->saddr->type == SOCKET_ADDRESS_FLAT_TYPE_INET) {
|
||||
if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) {
|
||||
const InetSocketAddress *inet = &s->saddr->u.inet;
|
||||
if (!inet->has_ipv4 && !inet->has_ipv6 && !inet->has_to) {
|
||||
host = inet->host;
|
||||
port = inet->port;
|
||||
}
|
||||
} else if (s->saddr->type == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
|
||||
} else if (s->saddr->type == SOCKET_ADDRESS_TYPE_UNIX) {
|
||||
path = s->saddr->u.q_unix.path;
|
||||
} /* else can't represent as pseudo-filename */
|
||||
|
||||
qdict_put(opts, "driver", qstring_from_str("nbd"));
|
||||
qdict_put_str(opts, "driver", "nbd");
|
||||
|
||||
if (path && s->export) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
@@ -545,16 +542,16 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
}
|
||||
|
||||
ov = qobject_output_visitor_new(&saddr_qdict);
|
||||
visit_type_SocketAddressFlat(ov, NULL, &s->saddr, &error_abort);
|
||||
visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort);
|
||||
visit_complete(ov, &saddr_qdict);
|
||||
visit_free(ov);
|
||||
qdict_put_obj(opts, "server", saddr_qdict);
|
||||
|
||||
if (s->export) {
|
||||
qdict_put(opts, "export", qstring_from_str(s->export));
|
||||
qdict_put_str(opts, "export", s->export);
|
||||
}
|
||||
if (s->tlscredsid) {
|
||||
qdict_put(opts, "tls-creds", qstring_from_str(s->tlscredsid));
|
||||
qdict_put_str(opts, "tls-creds", s->tlscredsid);
|
||||
}
|
||||
|
||||
qdict_flatten(opts);
|
||||
|
||||
55
block/nfs.c
55
block/nfs.c
@@ -104,9 +104,9 @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
qdict_put(options, "server.host", qstring_from_str(uri->server));
|
||||
qdict_put(options, "server.type", qstring_from_str("inet"));
|
||||
qdict_put(options, "path", qstring_from_str(uri->path));
|
||||
qdict_put_str(options, "server.host", uri->server);
|
||||
qdict_put_str(options, "server.type", "inet");
|
||||
qdict_put_str(options, "path", uri->path);
|
||||
|
||||
for (i = 0; i < qp->n; i++) {
|
||||
unsigned long long val;
|
||||
@@ -121,23 +121,17 @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
if (!strcmp(qp->p[i].name, "uid")) {
|
||||
qdict_put(options, "user",
|
||||
qstring_from_str(qp->p[i].value));
|
||||
qdict_put_str(options, "user", qp->p[i].value);
|
||||
} else if (!strcmp(qp->p[i].name, "gid")) {
|
||||
qdict_put(options, "group",
|
||||
qstring_from_str(qp->p[i].value));
|
||||
qdict_put_str(options, "group", qp->p[i].value);
|
||||
} else if (!strcmp(qp->p[i].name, "tcp-syncnt")) {
|
||||
qdict_put(options, "tcp-syn-count",
|
||||
qstring_from_str(qp->p[i].value));
|
||||
qdict_put_str(options, "tcp-syn-count", qp->p[i].value);
|
||||
} else if (!strcmp(qp->p[i].name, "readahead")) {
|
||||
qdict_put(options, "readahead-size",
|
||||
qstring_from_str(qp->p[i].value));
|
||||
qdict_put_str(options, "readahead-size", qp->p[i].value);
|
||||
} else if (!strcmp(qp->p[i].name, "pagecache")) {
|
||||
qdict_put(options, "page-cache-size",
|
||||
qstring_from_str(qp->p[i].value));
|
||||
qdict_put_str(options, "page-cache-size", qp->p[i].value);
|
||||
} else if (!strcmp(qp->p[i].name, "debug")) {
|
||||
qdict_put(options, "debug",
|
||||
qstring_from_str(qp->p[i].value));
|
||||
qdict_put_str(options, "debug", qp->p[i].value);
|
||||
} else {
|
||||
error_setg(errp, "Unknown NFS parameter name: %s",
|
||||
qp->p[i].name);
|
||||
@@ -764,10 +758,18 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
|
||||
return (task.ret < 0 ? task.ret : st.st_blocks * 512);
|
||||
}
|
||||
|
||||
static int nfs_file_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int nfs_file_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
return nfs_ftruncate(client->context, client->fh, offset);
|
||||
int ret;
|
||||
|
||||
ret = nfs_ftruncate(client->context, client->fh, offset);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to truncate file");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note that this will not re-establish a connection with the NFS server
|
||||
@@ -811,7 +813,7 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
QObject *server_qdict;
|
||||
Visitor *ov;
|
||||
|
||||
qdict_put(opts, "driver", qstring_from_str("nfs"));
|
||||
qdict_put_str(opts, "driver", "nfs");
|
||||
|
||||
if (client->uid && !client->gid) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
@@ -834,28 +836,25 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
visit_type_NFSServer(ov, NULL, &client->server, &error_abort);
|
||||
visit_complete(ov, &server_qdict);
|
||||
qdict_put_obj(opts, "server", server_qdict);
|
||||
qdict_put(opts, "path", qstring_from_str(client->path));
|
||||
qdict_put_str(opts, "path", client->path);
|
||||
|
||||
if (client->uid) {
|
||||
qdict_put(opts, "user", qint_from_int(client->uid));
|
||||
qdict_put_int(opts, "user", client->uid);
|
||||
}
|
||||
if (client->gid) {
|
||||
qdict_put(opts, "group", qint_from_int(client->gid));
|
||||
qdict_put_int(opts, "group", client->gid);
|
||||
}
|
||||
if (client->tcp_syncnt) {
|
||||
qdict_put(opts, "tcp-syn-cnt",
|
||||
qint_from_int(client->tcp_syncnt));
|
||||
qdict_put_int(opts, "tcp-syn-cnt", client->tcp_syncnt);
|
||||
}
|
||||
if (client->readahead) {
|
||||
qdict_put(opts, "readahead-size",
|
||||
qint_from_int(client->readahead));
|
||||
qdict_put_int(opts, "readahead-size", client->readahead);
|
||||
}
|
||||
if (client->pagecache) {
|
||||
qdict_put(opts, "page-cache-size",
|
||||
qint_from_int(client->pagecache));
|
||||
qdict_put_int(opts, "page-cache-size", client->pagecache);
|
||||
}
|
||||
if (client->debug) {
|
||||
qdict_put(opts, "debug", qint_from_int(client->debug));
|
||||
qdict_put_int(opts, "debug", client->debug);
|
||||
}
|
||||
|
||||
visit_free(ov);
|
||||
|
||||
@@ -232,7 +232,7 @@ static void null_refresh_filename(BlockDriverState *bs, QDict *opts)
|
||||
bs->drv->format_name);
|
||||
}
|
||||
|
||||
qdict_put(opts, "driver", qstring_from_str(bs->drv->format_name));
|
||||
qdict_put_str(opts, "driver", bs->drv->format_name);
|
||||
bs->full_open_options = opts;
|
||||
}
|
||||
|
||||
|
||||
@@ -223,7 +223,8 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
|
||||
space << BDRV_SECTOR_BITS, 0);
|
||||
} else {
|
||||
ret = bdrv_truncate(bs->file,
|
||||
(s->data_end + space) << BDRV_SECTOR_BITS);
|
||||
(s->data_end + space) << BDRV_SECTOR_BITS,
|
||||
NULL);
|
||||
}
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@@ -456,8 +457,10 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
size - res->image_end_offset);
|
||||
res->leaks += count;
|
||||
if (fix & BDRV_FIX_LEAKS) {
|
||||
ret = bdrv_truncate(bs->file, res->image_end_offset);
|
||||
Error *local_err = NULL;
|
||||
ret = bdrv_truncate(bs->file, res->image_end_offset, &local_err);
|
||||
if (ret < 0) {
|
||||
error_report_err(local_err);
|
||||
res->check_errors++;
|
||||
return ret;
|
||||
}
|
||||
@@ -504,7 +507,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
|
||||
blk_set_allow_write_beyond_eof(file, true);
|
||||
|
||||
ret = blk_truncate(file, 0);
|
||||
ret = blk_truncate(file, 0, errp);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
@@ -696,7 +699,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (!(flags & BDRV_O_RESIZE) || !bdrv_has_zero_init(bs->file->bs) ||
|
||||
bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs)) != 0) {
|
||||
bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs), NULL) != 0) {
|
||||
s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
|
||||
}
|
||||
|
||||
@@ -739,7 +742,7 @@ static void parallels_close(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
if (bs->open_flags & BDRV_O_RDWR) {
|
||||
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS);
|
||||
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, NULL);
|
||||
}
|
||||
|
||||
g_free(s->bat_dirty_bmap);
|
||||
|
||||
@@ -473,7 +473,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
/* round to cluster size */
|
||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||
~(s->cluster_size - 1);
|
||||
bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
|
||||
bdrv_truncate(bs->file, cluster_offset + s->cluster_size, NULL);
|
||||
/* if encrypted, we must initialize the cluster
|
||||
content which won't be written */
|
||||
if (bs->encrypted &&
|
||||
@@ -833,7 +833,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
|
||||
blk_set_allow_write_beyond_eof(qcow_blk, true);
|
||||
|
||||
ret = blk_truncate(qcow_blk, 0);
|
||||
ret = blk_truncate(qcow_blk, 0, errp);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
@@ -916,7 +916,7 @@ static int qcow_make_empty(BlockDriverState *bs)
|
||||
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
|
||||
l1_length) < 0)
|
||||
return -1;
|
||||
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
|
||||
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -1728,14 +1728,17 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
|
||||
if (fix & BDRV_FIX_ERRORS) {
|
||||
int64_t new_nb_clusters;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (offset > INT64_MAX - s->cluster_size) {
|
||||
ret = -EINVAL;
|
||||
goto resize_fail;
|
||||
}
|
||||
|
||||
ret = bdrv_truncate(bs->file, offset + s->cluster_size);
|
||||
ret = bdrv_truncate(bs->file, offset + s->cluster_size,
|
||||
&local_err);
|
||||
if (ret < 0) {
|
||||
error_report_err(local_err);
|
||||
goto resize_fail;
|
||||
}
|
||||
size = bdrv_getlength(bs->file->bs);
|
||||
|
||||
@@ -2265,7 +2265,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
* table)
|
||||
*/
|
||||
options = qdict_new();
|
||||
qdict_put(options, "driver", qstring_from_str("qcow2"));
|
||||
qdict_put_str(options, "driver", "qcow2");
|
||||
blk = blk_new_open(filename, NULL, options,
|
||||
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH,
|
||||
&local_err);
|
||||
@@ -2294,9 +2294,9 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
}
|
||||
|
||||
/* Okay, now that we have a valid image, let's give it the right size */
|
||||
ret = blk_truncate(blk, total_size);
|
||||
ret = blk_truncate(blk, total_size, errp);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not resize image");
|
||||
error_prepend(errp, "Could not resize image: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2327,7 +2327,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
|
||||
/* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
|
||||
options = qdict_new();
|
||||
qdict_put(options, "driver", qstring_from_str("qcow2"));
|
||||
qdict_put_str(options, "driver", "qcow2");
|
||||
blk = blk_new_open(filename, NULL, options,
|
||||
BDRV_O_RDWR | BDRV_O_NO_BACKING, &local_err);
|
||||
if (blk == NULL) {
|
||||
@@ -2515,7 +2515,12 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
|
||||
|
||||
if (!QEMU_IS_ALIGNED(offset | count, s->cluster_size)) {
|
||||
assert(count < s->cluster_size);
|
||||
return -ENOTSUP;
|
||||
/* Ignore partial clusters, except for the special case of the
|
||||
* complete partial cluster at the end of an unaligned file */
|
||||
if (!QEMU_IS_ALIGNED(offset, s->cluster_size) ||
|
||||
offset + count != bs->total_sectors * BDRV_SECTOR_SIZE) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
@@ -2525,32 +2530,33 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int64_t new_l1_size;
|
||||
int ret;
|
||||
|
||||
if (offset & 511) {
|
||||
error_report("The new size must be a multiple of 512");
|
||||
error_setg(errp, "The new size must be a multiple of 512");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* cannot proceed if image has snapshots */
|
||||
if (s->nb_snapshots) {
|
||||
error_report("Can't resize an image which has snapshots");
|
||||
error_setg(errp, "Can't resize an image which has snapshots");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* shrinking is currently not supported */
|
||||
if (offset < bs->total_sectors * 512) {
|
||||
error_report("qcow2 doesn't support shrinking images yet");
|
||||
error_setg(errp, "qcow2 doesn't support shrinking images yet");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
new_l1_size = size_to_l1(s, offset);
|
||||
ret = qcow2_grow_l1_table(bs, new_l1_size, true);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to grow the L1 table");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2559,6 +2565,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
|
||||
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
|
||||
&offset, sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to update the image size");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2584,7 +2591,7 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||
/* align end of file to a sector boundary to ease reading with
|
||||
sector based I/Os */
|
||||
cluster_offset = bdrv_getlength(bs->file->bs);
|
||||
return bdrv_truncate(bs->file, cluster_offset);
|
||||
return bdrv_truncate(bs->file, cluster_offset, NULL);
|
||||
}
|
||||
|
||||
buf = qemu_blockalign(bs, s->cluster_size);
|
||||
@@ -2674,6 +2681,7 @@ fail:
|
||||
static int make_completely_empty(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
Error *local_err = NULL;
|
||||
int ret, l1_clusters;
|
||||
int64_t offset;
|
||||
uint64_t *new_reftable = NULL;
|
||||
@@ -2798,8 +2806,10 @@ static int make_completely_empty(BlockDriverState *bs)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size);
|
||||
ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size,
|
||||
&local_err);
|
||||
if (ret < 0) {
|
||||
error_report_err(local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -3273,9 +3283,10 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = blk_truncate(blk, new_size);
|
||||
ret = blk_truncate(blk, new_size, &local_err);
|
||||
blk_unref(blk);
|
||||
if (ret < 0) {
|
||||
error_report_err(local_err);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,7 +635,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
|
||||
blk_set_allow_write_beyond_eof(blk, true);
|
||||
|
||||
/* File must start empty and grow, check truncate is supported */
|
||||
ret = blk_truncate(blk, 0);
|
||||
ret = blk_truncate(blk, 0, errp);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
@@ -1518,7 +1518,7 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
return cb.ret;
|
||||
}
|
||||
|
||||
static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
uint64_t old_image_size;
|
||||
@@ -1526,11 +1526,12 @@ static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
|
||||
|
||||
if (!qed_is_image_size_valid(offset, s->header.cluster_size,
|
||||
s->header.table_size)) {
|
||||
error_setg(errp, "Invalid image size specified");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Shrinking is currently not supported */
|
||||
if ((uint64_t)offset < s->header.image_size) {
|
||||
error_setg(errp, "Shrinking images is currently not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -1539,6 +1540,7 @@ static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
|
||||
ret = qed_write_header_sync(s);
|
||||
if (ret < 0) {
|
||||
s->header.image_size = old_image_size;
|
||||
error_setg_errno(errp, -ret, "Failed to update the image size");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1096,19 +1096,15 @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
children = qlist_new();
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
QINCREF(s->children[i]->bs->full_open_options);
|
||||
qlist_append_obj(children,
|
||||
QOBJECT(s->children[i]->bs->full_open_options));
|
||||
qlist_append(children, s->children[i]->bs->full_open_options);
|
||||
}
|
||||
|
||||
opts = qdict_new();
|
||||
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("quorum")));
|
||||
qdict_put_obj(opts, QUORUM_OPT_VOTE_THRESHOLD,
|
||||
QOBJECT(qint_from_int(s->threshold)));
|
||||
qdict_put_obj(opts, QUORUM_OPT_BLKVERIFY,
|
||||
QOBJECT(qbool_from_bool(s->is_blkverify)));
|
||||
qdict_put_obj(opts, QUORUM_OPT_REWRITE,
|
||||
QOBJECT(qbool_from_bool(s->rewrite_corrupted)));
|
||||
qdict_put_obj(opts, "children", QOBJECT(children));
|
||||
qdict_put_str(opts, "driver", "quorum");
|
||||
qdict_put_int(opts, QUORUM_OPT_VOTE_THRESHOLD, s->threshold);
|
||||
qdict_put_bool(opts, QUORUM_OPT_BLKVERIFY, s->is_blkverify);
|
||||
qdict_put_bool(opts, QUORUM_OPT_REWRITE, s->rewrite_corrupted);
|
||||
qdict_put(opts, "children", children);
|
||||
|
||||
bs->full_open_options = opts;
|
||||
}
|
||||
|
||||
@@ -327,21 +327,23 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
if (s->has_size) {
|
||||
error_setg(errp, "Cannot resize fixed-size raw disks");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (INT64_MAX - offset < s->offset) {
|
||||
error_setg(errp, "Disk size too large for the chosen offset");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s->size = offset;
|
||||
offset += s->offset;
|
||||
return bdrv_truncate(bs->file, offset);
|
||||
return bdrv_truncate(bs->file, offset, errp);
|
||||
}
|
||||
|
||||
static int raw_media_changed(BlockDriverState *bs)
|
||||
|
||||
19
block/rbd.c
19
block/rbd.c
@@ -154,20 +154,20 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
|
||||
goto done;
|
||||
}
|
||||
qemu_rbd_unescape(found_str);
|
||||
qdict_put(options, "pool", qstring_from_str(found_str));
|
||||
qdict_put_str(options, "pool", found_str);
|
||||
|
||||
if (strchr(p, '@')) {
|
||||
found_str = qemu_rbd_next_tok(p, '@', &p);
|
||||
qemu_rbd_unescape(found_str);
|
||||
qdict_put(options, "image", qstring_from_str(found_str));
|
||||
qdict_put_str(options, "image", found_str);
|
||||
|
||||
found_str = qemu_rbd_next_tok(p, ':', &p);
|
||||
qemu_rbd_unescape(found_str);
|
||||
qdict_put(options, "snapshot", qstring_from_str(found_str));
|
||||
qdict_put_str(options, "snapshot", found_str);
|
||||
} else {
|
||||
found_str = qemu_rbd_next_tok(p, ':', &p);
|
||||
qemu_rbd_unescape(found_str);
|
||||
qdict_put(options, "image", qstring_from_str(found_str));
|
||||
qdict_put_str(options, "image", found_str);
|
||||
}
|
||||
if (!p) {
|
||||
goto done;
|
||||
@@ -189,9 +189,9 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
|
||||
qemu_rbd_unescape(value);
|
||||
|
||||
if (!strcmp(name, "conf")) {
|
||||
qdict_put(options, "conf", qstring_from_str(value));
|
||||
qdict_put_str(options, "conf", value);
|
||||
} else if (!strcmp(name, "id")) {
|
||||
qdict_put(options, "user" , qstring_from_str(value));
|
||||
qdict_put_str(options, "user", value);
|
||||
} else {
|
||||
/*
|
||||
* We pass these internally to qemu_rbd_set_keypairs(), so
|
||||
@@ -204,8 +204,8 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
|
||||
if (!keypairs) {
|
||||
keypairs = qlist_new();
|
||||
}
|
||||
qlist_append(keypairs, qstring_from_str(name));
|
||||
qlist_append(keypairs, qstring_from_str(value));
|
||||
qlist_append_str(keypairs, name);
|
||||
qlist_append_str(keypairs, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -916,13 +916,14 @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs)
|
||||
return info.size;
|
||||
}
|
||||
|
||||
static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
int r;
|
||||
|
||||
r = rbd_resize(s->image, offset);
|
||||
if (r < 0) {
|
||||
error_setg_errno(errp, -r, "Failed to resize file");
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -536,14 +536,12 @@ static SocketAddress *sd_socket_address(const char *path,
|
||||
SocketAddress *addr = g_new0(SocketAddress, 1);
|
||||
|
||||
if (path) {
|
||||
addr->type = SOCKET_ADDRESS_KIND_UNIX;
|
||||
addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
||||
addr->u.q_unix.data->path = g_strdup(path);
|
||||
addr->type = SOCKET_ADDRESS_TYPE_UNIX;
|
||||
addr->u.q_unix.path = g_strdup(path);
|
||||
} else {
|
||||
addr->type = SOCKET_ADDRESS_KIND_INET;
|
||||
addr->u.inet.data = g_new0(InetSocketAddress, 1);
|
||||
addr->u.inet.data->host = g_strdup(host ?: SD_DEFAULT_ADDR);
|
||||
addr->u.inet.data->port = g_strdup(port ?: stringify(SD_DEFAULT_PORT));
|
||||
addr->type = SOCKET_ADDRESS_TYPE_INET;
|
||||
addr->u.inet.host = g_strdup(host ?: SD_DEFAULT_ADDR);
|
||||
addr->u.inet.port = g_strdup(port ?: stringify(SD_DEFAULT_PORT));
|
||||
}
|
||||
|
||||
return addr;
|
||||
@@ -554,7 +552,6 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
|
||||
QDict *server = NULL;
|
||||
QObject *crumpled_server = NULL;
|
||||
Visitor *iv = NULL;
|
||||
SocketAddressFlat *saddr_flat = NULL;
|
||||
SocketAddress *saddr = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
@@ -574,16 +571,13 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
|
||||
* visitor expects the former.
|
||||
*/
|
||||
iv = qobject_input_visitor_new(crumpled_server);
|
||||
visit_type_SocketAddressFlat(iv, NULL, &saddr_flat, &local_err);
|
||||
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
saddr = socket_address_crumple(saddr_flat);
|
||||
|
||||
done:
|
||||
qapi_free_SocketAddressFlat(saddr_flat);
|
||||
visit_free(iv);
|
||||
qobject_decref(crumpled_server);
|
||||
QDECREF(server);
|
||||
@@ -597,7 +591,7 @@ static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
|
||||
|
||||
fd = socket_connect(s->addr, NULL, NULL, errp);
|
||||
|
||||
if (s->addr->type == SOCKET_ADDRESS_KIND_INET && fd >= 0) {
|
||||
if (s->addr->type == SOCKET_ADDRESS_TYPE_INET && fd >= 0) {
|
||||
int ret = socket_set_nodelay(fd);
|
||||
if (ret < 0) {
|
||||
error_report("%s", strerror(errno));
|
||||
@@ -2159,9 +2153,8 @@ static int64_t sd_getlength(BlockDriverState *bs)
|
||||
return s->inode.vdi_size;
|
||||
}
|
||||
|
||||
static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
static int sd_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
int ret, fd;
|
||||
unsigned int datalen;
|
||||
@@ -2169,16 +2162,15 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
|
||||
max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
|
||||
if (offset < s->inode.vdi_size) {
|
||||
error_report("shrinking is not supported");
|
||||
error_setg(errp, "shrinking is not supported");
|
||||
return -EINVAL;
|
||||
} else if (offset > max_vdi_size) {
|
||||
error_report("too big image size");
|
||||
error_setg(errp, "too big image size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
fd = connect_to_sdog(s, errp);
|
||||
if (fd < 0) {
|
||||
error_report_err(local_err);
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -2191,7 +2183,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
close(fd);
|
||||
|
||||
if (ret < 0) {
|
||||
error_report("failed to update an inode.");
|
||||
error_setg_errno(errp, -ret, "failed to update an inode");
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -2456,7 +2448,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
|
||||
if (offset > s->inode.vdi_size) {
|
||||
ret = sd_truncate(bs, offset);
|
||||
ret = sd_truncate(bs, offset, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
|
||||
qdict_extract_subqdict(options, &file_options, "file.");
|
||||
QDECREF(file_options);
|
||||
qdict_put(options, "file", qstring_from_str(bdrv_get_node_name(file)));
|
||||
qdict_put_str(options, "file", bdrv_get_node_name(file));
|
||||
|
||||
drv->bdrv_close(bs);
|
||||
bdrv_unref_child(bs, bs->file);
|
||||
|
||||
16
block/ssh.c
16
block/ssh.c
@@ -227,24 +227,23 @@ static int parse_uri(const char *filename, QDict *options, Error **errp)
|
||||
}
|
||||
|
||||
if(uri->user && strcmp(uri->user, "") != 0) {
|
||||
qdict_put(options, "user", qstring_from_str(uri->user));
|
||||
qdict_put_str(options, "user", uri->user);
|
||||
}
|
||||
|
||||
qdict_put(options, "server.host", qstring_from_str(uri->server));
|
||||
qdict_put_str(options, "server.host", uri->server);
|
||||
|
||||
port_str = g_strdup_printf("%d", uri->port ?: 22);
|
||||
qdict_put(options, "server.port", qstring_from_str(port_str));
|
||||
qdict_put_str(options, "server.port", port_str);
|
||||
g_free(port_str);
|
||||
|
||||
qdict_put(options, "path", qstring_from_str(uri->path));
|
||||
qdict_put_str(options, "path", uri->path);
|
||||
|
||||
/* Pick out any query parameters that we understand, and ignore
|
||||
* the rest.
|
||||
*/
|
||||
for (i = 0; i < qp->n; ++i) {
|
||||
if (strcmp(qp->p[i].name, "host_key_check") == 0) {
|
||||
qdict_put(options, "host_key_check",
|
||||
qstring_from_str(qp->p[i].value));
|
||||
qdict_put_str(options, "host_key_check", qp->p[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,9 +573,8 @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
|
||||
}
|
||||
|
||||
if (host) {
|
||||
qdict_put(output_opts, "server.host", qstring_from_str(host));
|
||||
qdict_put(output_opts, "server.port",
|
||||
qstring_from_str(port ?: stringify(22)));
|
||||
qdict_put_str(output_opts, "server.host", host);
|
||||
qdict_put_str(output_opts, "server.port", port ?: stringify(22));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -832,9 +832,9 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
if (image_type == VDI_TYPE_STATIC) {
|
||||
ret = blk_truncate(blk, offset + blocks * block_size);
|
||||
ret = blk_truncate(blk, offset + blocks * block_size, errp);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Failed to statically allocate %s", filename);
|
||||
error_prepend(errp, "Failed to statically allocate %s", filename);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,7 +548,7 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
|
||||
if (new_file_size % (1024*1024)) {
|
||||
/* round up to nearest 1MB boundary */
|
||||
new_file_size = ((new_file_size >> 20) + 1) << 20;
|
||||
bdrv_truncate(bs->file, new_file_size);
|
||||
bdrv_truncate(bs->file, new_file_size, NULL);
|
||||
}
|
||||
}
|
||||
qemu_vfree(desc_entries);
|
||||
|
||||
25
block/vhdx.c
25
block/vhdx.c
@@ -1171,7 +1171,7 @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
|
||||
/* per the spec, the address for a block is in units of 1MB */
|
||||
*new_offset = ROUND_UP(*new_offset, 1024 * 1024);
|
||||
|
||||
return bdrv_truncate(bs->file, *new_offset + s->block_size);
|
||||
return bdrv_truncate(bs->file, *new_offset + s->block_size, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1586,7 +1586,7 @@ exit:
|
||||
static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
|
||||
uint64_t image_size, VHDXImageType type,
|
||||
bool use_zero_blocks, uint64_t file_offset,
|
||||
uint32_t length)
|
||||
uint32_t length, Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t data_file_offset;
|
||||
@@ -1607,16 +1607,17 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
|
||||
if (type == VHDX_TYPE_DYNAMIC) {
|
||||
/* All zeroes, so we can just extend the file - the end of the BAT
|
||||
* is the furthest thing we have written yet */
|
||||
ret = blk_truncate(blk, data_file_offset);
|
||||
ret = blk_truncate(blk, data_file_offset, errp);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
} else if (type == VHDX_TYPE_FIXED) {
|
||||
ret = blk_truncate(blk, data_file_offset + image_size);
|
||||
ret = blk_truncate(blk, data_file_offset + image_size, errp);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
error_setg(errp, "Unsupported image type");
|
||||
ret = -ENOTSUP;
|
||||
goto exit;
|
||||
}
|
||||
@@ -1627,6 +1628,7 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
|
||||
/* for a fixed file, the default BAT entry is not zero */
|
||||
s->bat = g_try_malloc0(length);
|
||||
if (length && s->bat == NULL) {
|
||||
error_setg(errp, "Failed to allocate memory for the BAT");
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
@@ -1646,6 +1648,7 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
|
||||
}
|
||||
ret = blk_pwrite(blk, file_offset, s->bat, length, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to write the BAT");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@@ -1671,7 +1674,8 @@ static int vhdx_create_new_region_table(BlockBackend *blk,
|
||||
uint32_t log_size,
|
||||
bool use_zero_blocks,
|
||||
VHDXImageType type,
|
||||
uint64_t *metadata_offset)
|
||||
uint64_t *metadata_offset,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t offset = 0;
|
||||
@@ -1740,7 +1744,7 @@ static int vhdx_create_new_region_table(BlockBackend *blk,
|
||||
/* The region table gives us the data we need to create the BAT,
|
||||
* so do that now */
|
||||
ret = vhdx_create_bat(blk, s, image_size, type, use_zero_blocks,
|
||||
bat_file_offset, bat_length);
|
||||
bat_file_offset, bat_length, errp);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
@@ -1749,12 +1753,14 @@ static int vhdx_create_new_region_table(BlockBackend *blk,
|
||||
ret = blk_pwrite(blk, VHDX_REGION_TABLE_OFFSET, buffer,
|
||||
VHDX_HEADER_BLOCK_SIZE, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to write first region table");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = blk_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, buffer,
|
||||
VHDX_HEADER_BLOCK_SIZE, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to write second region table");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -1825,6 +1831,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
ret = -ENOTSUP;
|
||||
goto exit;
|
||||
} else {
|
||||
error_setg(errp, "Invalid subformat '%s'", type);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
@@ -1879,12 +1886,14 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature),
|
||||
0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to write file signature");
|
||||
goto delete_and_exit;
|
||||
}
|
||||
if (creator) {
|
||||
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature),
|
||||
creator, creator_items * sizeof(gunichar2), 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to write creator field");
|
||||
goto delete_and_exit;
|
||||
}
|
||||
}
|
||||
@@ -1893,13 +1902,14 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
/* Creates (B),(C) */
|
||||
ret = vhdx_create_new_headers(blk, image_size, log_size);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to write image headers");
|
||||
goto delete_and_exit;
|
||||
}
|
||||
|
||||
/* Creates (D),(E),(G) explicitly. (F) created as by-product */
|
||||
ret = vhdx_create_new_region_table(blk, image_size, block_size, 512,
|
||||
log_size, use_zero_blocks, image_type,
|
||||
&metadata_offset);
|
||||
&metadata_offset, errp);
|
||||
if (ret < 0) {
|
||||
goto delete_and_exit;
|
||||
}
|
||||
@@ -1908,6 +1918,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
ret = vhdx_create_new_metadata(blk, image_size, block_size, 512,
|
||||
metadata_offset, image_type);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to initialize metadata");
|
||||
goto delete_and_exit;
|
||||
}
|
||||
|
||||
|
||||
13
block/vmdk.c
13
block/vmdk.c
@@ -1714,10 +1714,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
blk_set_allow_write_beyond_eof(blk, true);
|
||||
|
||||
if (flat) {
|
||||
ret = blk_truncate(blk, filesize);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not truncate file");
|
||||
}
|
||||
ret = blk_truncate(blk, filesize, errp);
|
||||
goto exit;
|
||||
}
|
||||
magic = cpu_to_be32(VMDK4_MAGIC);
|
||||
@@ -1780,9 +1777,8 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9);
|
||||
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, errp);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not truncate file");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -2090,10 +2086,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
/* bdrv_pwrite write padding zeros to align to sector, we don't need that
|
||||
* for description file */
|
||||
if (desc_offset == 0) {
|
||||
ret = blk_truncate(new_blk, desc_len);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not truncate file");
|
||||
}
|
||||
ret = blk_truncate(new_blk, desc_len, errp);
|
||||
}
|
||||
exit:
|
||||
if (new_blk) {
|
||||
|
||||
13
block/vpc.c
13
block/vpc.c
@@ -851,20 +851,21 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
|
||||
}
|
||||
|
||||
static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
|
||||
int64_t total_size)
|
||||
int64_t total_size, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Add footer to total size */
|
||||
total_size += HEADER_SIZE;
|
||||
|
||||
ret = blk_truncate(blk, total_size);
|
||||
ret = blk_truncate(blk, total_size, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = blk_pwrite(blk, total_size - HEADER_SIZE, buf, HEADER_SIZE, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Unable to write VHD header");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -996,11 +997,11 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
|
||||
if (disk_type == VHD_DYNAMIC) {
|
||||
ret = create_dynamic_disk(blk, buf, total_sectors);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to create or write VHD header");
|
||||
}
|
||||
} else {
|
||||
ret = create_fixed_disk(blk, buf, total_size);
|
||||
}
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to create or write VHD header");
|
||||
ret = create_fixed_disk(blk, buf, total_size, errp);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
@@ -1057,10 +1057,10 @@ static void vvfat_parse_filename(const char *filename, QDict *options,
|
||||
}
|
||||
|
||||
/* Fill in the options QDict */
|
||||
qdict_put(options, "dir", qstring_from_str(filename));
|
||||
qdict_put(options, "fat-type", qint_from_int(fat_type));
|
||||
qdict_put(options, "floppy", qbool_from_bool(floppy));
|
||||
qdict_put(options, "rw", qbool_from_bool(rw));
|
||||
qdict_put_str(options, "dir", filename);
|
||||
qdict_put_int(options, "fat-type", fat_type);
|
||||
qdict_put_bool(options, "floppy", floppy);
|
||||
qdict_put_bool(options, "rw", rw);
|
||||
}
|
||||
|
||||
static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
@@ -3051,7 +3051,7 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
|
||||
}
|
||||
|
||||
options = qdict_new();
|
||||
qdict_put(options, "write-target.driver", qstring_from_str("qcow"));
|
||||
qdict_put_str(options, "write-target.driver", "qcow");
|
||||
s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
|
||||
&child_vvfat_qcow, false, errp);
|
||||
QDECREF(options);
|
||||
|
||||
@@ -182,15 +182,15 @@ static int vxhs_parse_uri(const char *filename, QDict *options)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qdict_put(options, VXHS_OPT_SERVER".host", qstring_from_str(uri->server));
|
||||
qdict_put_str(options, VXHS_OPT_SERVER ".host", uri->server);
|
||||
|
||||
if (uri->port) {
|
||||
port = g_strdup_printf("%d", uri->port);
|
||||
qdict_put(options, VXHS_OPT_SERVER".port", qstring_from_str(port));
|
||||
qdict_put_str(options, VXHS_OPT_SERVER ".port", port);
|
||||
g_free(port);
|
||||
}
|
||||
|
||||
qdict_put(options, "vdisk-id", qstring_from_str(uri->path));
|
||||
qdict_put_str(options, "vdisk-id", uri->path);
|
||||
|
||||
trace_vxhs_parse_uri_hostinfo(uri->server, uri->port);
|
||||
uri_free(uri);
|
||||
|
||||
@@ -99,9 +99,8 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
|
||||
}
|
||||
|
||||
|
||||
void qmp_nbd_server_start(SocketAddress *addr,
|
||||
bool has_tls_creds, const char *tls_creds,
|
||||
Error **errp)
|
||||
void nbd_server_start(SocketAddress *addr, const char *tls_creds,
|
||||
Error **errp)
|
||||
{
|
||||
if (nbd_server) {
|
||||
error_setg(errp, "NBD server already running");
|
||||
@@ -118,14 +117,14 @@ void qmp_nbd_server_start(SocketAddress *addr,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (has_tls_creds) {
|
||||
if (tls_creds) {
|
||||
nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp);
|
||||
if (!nbd_server->tlscreds) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* TODO SOCKET_ADDRESS_KIND_FD where fd has AF_INET or AF_INET6 */
|
||||
if (addr->type != SOCKET_ADDRESS_KIND_INET) {
|
||||
/* TODO SOCKET_ADDRESS_TYPE_FD where fd has AF_INET or AF_INET6 */
|
||||
if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
|
||||
error_setg(errp, "TLS is only supported with IPv4/IPv6");
|
||||
goto error;
|
||||
}
|
||||
@@ -145,6 +144,16 @@ void qmp_nbd_server_start(SocketAddress *addr,
|
||||
nbd_server = NULL;
|
||||
}
|
||||
|
||||
void qmp_nbd_server_start(SocketAddressLegacy *addr,
|
||||
bool has_tls_creds, const char *tls_creds,
|
||||
Error **errp)
|
||||
{
|
||||
SocketAddress *addr_flat = socket_address_flatten(addr);
|
||||
|
||||
nbd_server_start(addr_flat, tls_creds, errp);
|
||||
qapi_free_SocketAddress(addr_flat);
|
||||
}
|
||||
|
||||
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
51
blockdev.c
51
blockdev.c
@@ -527,7 +527,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
error_setg(errp, "Cannot specify both 'driver' and 'format'");
|
||||
goto early_err;
|
||||
}
|
||||
qdict_put(bs_opts, "driver", qstring_from_str(buf));
|
||||
qdict_put_str(bs_opts, "driver", buf);
|
||||
}
|
||||
|
||||
on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
|
||||
@@ -903,10 +903,8 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
copy_on_read = false;
|
||||
}
|
||||
|
||||
qdict_put(bs_opts, BDRV_OPT_READ_ONLY,
|
||||
qstring_from_str(read_only ? "on" : "off"));
|
||||
qdict_put(bs_opts, "copy-on-read",
|
||||
qstring_from_str(copy_on_read ? "on" :"off"));
|
||||
qdict_put_str(bs_opts, BDRV_OPT_READ_ONLY, read_only ? "on" : "off");
|
||||
qdict_put_str(bs_opts, "copy-on-read", copy_on_read ? "on" : "off");
|
||||
|
||||
/* Controller type */
|
||||
value = qemu_opt_get(legacy_opts, "if");
|
||||
@@ -1030,7 +1028,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
new_id = g_strdup_printf("%s%s%i", if_name[type],
|
||||
mediastr, unit_id);
|
||||
}
|
||||
qdict_put(bs_opts, "id", qstring_from_str(new_id));
|
||||
qdict_put_str(bs_opts, "id", new_id);
|
||||
g_free(new_id);
|
||||
}
|
||||
|
||||
@@ -1067,7 +1065,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
error_report("werror is not supported by this bus type");
|
||||
goto fail;
|
||||
}
|
||||
qdict_put(bs_opts, "werror", qstring_from_str(werror));
|
||||
qdict_put_str(bs_opts, "werror", werror);
|
||||
}
|
||||
|
||||
rerror = qemu_opt_get(legacy_opts, "rerror");
|
||||
@@ -1077,7 +1075,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
error_report("rerror is not supported by this bus type");
|
||||
goto fail;
|
||||
}
|
||||
qdict_put(bs_opts, "rerror", qstring_from_str(rerror));
|
||||
qdict_put_str(bs_opts, "rerror", rerror);
|
||||
}
|
||||
|
||||
/* Actual block device init: Functionality shared with blockdev-add */
|
||||
@@ -1737,10 +1735,9 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
|
||||
options = qdict_new();
|
||||
if (s->has_snapshot_node_name) {
|
||||
qdict_put(options, "node-name",
|
||||
qstring_from_str(snapshot_node_name));
|
||||
qdict_put_str(options, "node-name", snapshot_node_name);
|
||||
}
|
||||
qdict_put(options, "driver", qstring_from_str(format));
|
||||
qdict_put_str(options, "driver", format);
|
||||
|
||||
flags |= BDRV_O_NO_BACKING;
|
||||
}
|
||||
@@ -2579,11 +2576,10 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
|
||||
|
||||
options = qdict_new();
|
||||
detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
|
||||
qdict_put(options, "detect-zeroes",
|
||||
qstring_from_str(detect_zeroes ? "on" : "off"));
|
||||
qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
|
||||
|
||||
if (has_format) {
|
||||
qdict_put(options, "driver", qstring_from_str(format));
|
||||
qdict_put_str(options, "driver", format);
|
||||
}
|
||||
|
||||
medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
|
||||
@@ -2930,26 +2926,7 @@ void qmp_block_resize(bool has_device, const char *device,
|
||||
/* complete all in-flight operations before resizing the device */
|
||||
bdrv_drain_all();
|
||||
|
||||
ret = blk_truncate(blk, size);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
break;
|
||||
case -ENOMEDIUM:
|
||||
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
break;
|
||||
case -ENOTSUP:
|
||||
error_setg(errp, QERR_UNSUPPORTED);
|
||||
break;
|
||||
case -EACCES:
|
||||
error_setg(errp, "Device '%s' is read only", device);
|
||||
break;
|
||||
case -EBUSY:
|
||||
error_setg(errp, QERR_DEVICE_IN_USE, device);
|
||||
break;
|
||||
default:
|
||||
error_setg_errno(errp, -ret, "Could not resize");
|
||||
break;
|
||||
}
|
||||
ret = blk_truncate(blk, size, errp);
|
||||
|
||||
out:
|
||||
blk_unref(blk);
|
||||
@@ -3251,7 +3228,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
|
||||
|
||||
if (backup->format) {
|
||||
options = qdict_new();
|
||||
qdict_put(options, "driver", qstring_from_str(backup->format));
|
||||
qdict_put_str(options, "driver", backup->format);
|
||||
}
|
||||
|
||||
target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
|
||||
@@ -3555,10 +3532,10 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
|
||||
|
||||
options = qdict_new();
|
||||
if (arg->has_node_name) {
|
||||
qdict_put(options, "node-name", qstring_from_str(arg->node_name));
|
||||
qdict_put_str(options, "node-name", arg->node_name);
|
||||
}
|
||||
if (format) {
|
||||
qdict_put(options, "driver", qstring_from_str(format));
|
||||
qdict_put_str(options, "driver", format);
|
||||
}
|
||||
|
||||
/* Mirroring takes care of copy-on-write using the source's backing
|
||||
|
||||
@@ -58,7 +58,7 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
ret = qio_channel_read(
|
||||
chan, (gchar *)buf, len, NULL);
|
||||
if (ret == 0) {
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
remove_fd_in_watch(chr);
|
||||
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -89,9 +89,9 @@ static void fd_chr_update_read_handler(Chardev *chr,
|
||||
{
|
||||
FDChardev *s = FD_CHARDEV(chr);
|
||||
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
remove_fd_in_watch(chr);
|
||||
if (s->ioc_in) {
|
||||
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc_in,
|
||||
fd_chr_read_poll,
|
||||
fd_chr_read, chr,
|
||||
context);
|
||||
@@ -103,7 +103,7 @@ static void char_fd_finalize(Object *obj)
|
||||
Chardev *chr = CHARDEV(obj);
|
||||
FDChardev *s = FD_CHARDEV(obj);
|
||||
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
remove_fd_in_watch(chr);
|
||||
if (s->ioc_in) {
|
||||
object_unref(OBJECT(s->ioc_in));
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ static GSourceFuncs io_watch_poll_funcs = {
|
||||
.finalize = io_watch_poll_finalize,
|
||||
};
|
||||
|
||||
guint io_add_watch_poll(Chardev *chr,
|
||||
GSource *io_add_watch_poll(Chardev *chr,
|
||||
QIOChannel *ioc,
|
||||
IOCanReadHandler *fd_can_read,
|
||||
QIOChannelFunc fd_read,
|
||||
@@ -106,7 +106,6 @@ guint io_add_watch_poll(Chardev *chr,
|
||||
GMainContext *context)
|
||||
{
|
||||
IOWatchPoll *iwp;
|
||||
int tag;
|
||||
char *name;
|
||||
|
||||
iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs,
|
||||
@@ -122,21 +121,15 @@ guint io_add_watch_poll(Chardev *chr,
|
||||
g_source_set_name((GSource *)iwp, name);
|
||||
g_free(name);
|
||||
|
||||
tag = g_source_attach(&iwp->parent, context);
|
||||
g_source_attach(&iwp->parent, context);
|
||||
g_source_unref(&iwp->parent);
|
||||
return tag;
|
||||
return (GSource *)iwp;
|
||||
}
|
||||
|
||||
static void io_remove_watch_poll(guint tag, GMainContext *context)
|
||||
static void io_remove_watch_poll(GSource *source)
|
||||
{
|
||||
GSource *source;
|
||||
IOWatchPoll *iwp;
|
||||
|
||||
g_return_if_fail(tag > 0);
|
||||
|
||||
source = g_main_context_find_source_by_id(context, tag);
|
||||
g_return_if_fail(source != NULL);
|
||||
|
||||
iwp = io_watch_poll_from_source(source);
|
||||
if (iwp->src) {
|
||||
g_source_destroy(iwp->src);
|
||||
@@ -146,11 +139,11 @@ static void io_remove_watch_poll(guint tag, GMainContext *context)
|
||||
g_source_destroy(&iwp->parent);
|
||||
}
|
||||
|
||||
void remove_fd_in_watch(Chardev *chr, GMainContext *context)
|
||||
void remove_fd_in_watch(Chardev *chr)
|
||||
{
|
||||
if (chr->fd_in_tag) {
|
||||
io_remove_watch_poll(chr->fd_in_tag, context);
|
||||
chr->fd_in_tag = 0;
|
||||
if (chr->gsource) {
|
||||
io_remove_watch_poll(chr->gsource);
|
||||
chr->gsource = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
#include "sysemu/char.h"
|
||||
|
||||
/* Can only be used for read */
|
||||
guint io_add_watch_poll(Chardev *chr,
|
||||
GSource *io_add_watch_poll(Chardev *chr,
|
||||
QIOChannel *ioc,
|
||||
IOCanReadHandler *fd_can_read,
|
||||
QIOChannelFunc fd_read,
|
||||
gpointer user_data,
|
||||
GMainContext *context);
|
||||
|
||||
void remove_fd_in_watch(Chardev *chr, GMainContext *context);
|
||||
void remove_fd_in_watch(Chardev *chr);
|
||||
|
||||
int io_channel_send(QIOChannel *ioc, const void *buf, size_t len);
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ static void mux_print_help(Chardev *chr)
|
||||
}
|
||||
}
|
||||
|
||||
void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
|
||||
static void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
|
||||
{
|
||||
CharBackend *be = d->backends[mux_nr];
|
||||
|
||||
@@ -222,9 +222,9 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
|
||||
|
||||
bool muxes_realized;
|
||||
|
||||
static void mux_chr_event(void *opaque, int event)
|
||||
void mux_chr_send_all_event(Chardev *chr, int event)
|
||||
{
|
||||
MuxChardev *d = MUX_CHARDEV(opaque);
|
||||
MuxChardev *d = MUX_CHARDEV(chr);
|
||||
int i;
|
||||
|
||||
if (!muxes_realized) {
|
||||
@@ -237,6 +237,11 @@ static void mux_chr_event(void *opaque, int event)
|
||||
}
|
||||
}
|
||||
|
||||
static void mux_chr_event(void *opaque, int event)
|
||||
{
|
||||
mux_chr_send_all_event(CHARDEV(opaque), event);
|
||||
}
|
||||
|
||||
static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
|
||||
{
|
||||
MuxChardev *d = MUX_CHARDEV(s);
|
||||
|
||||
@@ -58,6 +58,6 @@ typedef struct MuxChardev {
|
||||
|
||||
void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
|
||||
void mux_set_focus(Chardev *chr, int focus);
|
||||
void mux_chr_send_event(MuxChardev *d, int mux_nr, int event);
|
||||
void mux_chr_send_all_event(Chardev *chr, int event);
|
||||
|
||||
#endif /* CHAR_MUX_H */
|
||||
|
||||
@@ -185,7 +185,7 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
|
||||
PtyChardev *s = PTY_CHARDEV(opaque);
|
||||
|
||||
s->open_tag = 0;
|
||||
qemu_chr_be_generic_open(chr);
|
||||
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ static void pty_chr_state(Chardev *chr, int connected)
|
||||
g_source_remove(s->open_tag);
|
||||
s->open_tag = 0;
|
||||
}
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
remove_fd_in_watch(chr);
|
||||
s->connected = 0;
|
||||
/* (re-)connect poll interval for idle guests: once per second.
|
||||
* We check more frequently in case the guests sends data to
|
||||
@@ -215,8 +215,8 @@ static void pty_chr_state(Chardev *chr, int connected)
|
||||
s->connected = 1;
|
||||
s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr);
|
||||
}
|
||||
if (!chr->fd_in_tag) {
|
||||
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
|
||||
if (!chr->gsource) {
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
pty_chr_read_poll,
|
||||
pty_chr_read,
|
||||
chr, NULL);
|
||||
|
||||
@@ -55,6 +55,7 @@ typedef struct {
|
||||
SocketAddress *addr;
|
||||
bool is_listen;
|
||||
bool is_telnet;
|
||||
bool is_tn3270;
|
||||
|
||||
guint reconnect_timer;
|
||||
int64_t reconnect_time;
|
||||
@@ -141,19 +142,25 @@ static int tcp_chr_read_poll(void *opaque)
|
||||
return s->max_size;
|
||||
}
|
||||
|
||||
#define IAC 255
|
||||
#define IAC_BREAK 243
|
||||
static void tcp_chr_process_IAC_bytes(Chardev *chr,
|
||||
SocketChardev *s,
|
||||
uint8_t *buf, int *size)
|
||||
{
|
||||
/* Handle any telnet client's basic IAC options to satisfy char by
|
||||
* char mode with no echo. All IAC options will be removed from
|
||||
* the buf and the do_telnetopt variable will be used to track the
|
||||
* state of the width of the IAC information.
|
||||
/* Handle any telnet or tn3270 client's basic IAC options.
|
||||
* For telnet options, it satisfies char by char mode with no echo.
|
||||
* For tn3270 options, it satisfies binary mode with EOR.
|
||||
* All IAC options will be removed from the buf and the do_opt
|
||||
* pointer will be used to track the state of the width of the
|
||||
* IAC information.
|
||||
*
|
||||
* IAC commands come in sets of 3 bytes with the exception of the
|
||||
* "IAC BREAK" command and the double IAC.
|
||||
* RFC854: "All TELNET commands consist of at least a two byte sequence.
|
||||
* The commands dealing with option negotiation are three byte sequences,
|
||||
* the third byte being the code for the option referenced."
|
||||
* "IAC BREAK", "IAC IP", "IAC NOP" and the double IAC are two bytes.
|
||||
* "IAC SB", "IAC SE" and "IAC EOR" are saved to split up data boundary
|
||||
* for tn3270.
|
||||
* NOP, Break and Interrupt Process(IP) might be encountered during a TN3270
|
||||
* session, and NOP and IP need to be done later.
|
||||
*/
|
||||
|
||||
int i;
|
||||
@@ -174,6 +181,18 @@ static void tcp_chr_process_IAC_bytes(Chardev *chr,
|
||||
/* Handle IAC break commands by sending a serial break */
|
||||
qemu_chr_be_event(chr, CHR_EVENT_BREAK);
|
||||
s->do_telnetopt++;
|
||||
} else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_EOR
|
||||
|| (unsigned char)buf[i] == IAC_SB
|
||||
|| (unsigned char)buf[i] == IAC_SE)
|
||||
&& s->do_telnetopt == 2) {
|
||||
buf[j++] = IAC;
|
||||
buf[j++] = buf[i];
|
||||
s->do_telnetopt++;
|
||||
} else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_IP
|
||||
|| (unsigned char)buf[i] == IAC_NOP)
|
||||
&& s->do_telnetopt == 2) {
|
||||
/* TODO: IP and NOP need to be implemented later. */
|
||||
s->do_telnetopt++;
|
||||
}
|
||||
s->do_telnetopt++;
|
||||
}
|
||||
@@ -327,7 +346,7 @@ static void tcp_chr_free_connection(Chardev *chr)
|
||||
}
|
||||
|
||||
tcp_set_msgfds(chr, NULL, 0);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
remove_fd_in_watch(chr);
|
||||
object_unref(OBJECT(s->sioc));
|
||||
s->sioc = NULL;
|
||||
object_unref(OBJECT(s->ioc));
|
||||
@@ -341,31 +360,40 @@ static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr,
|
||||
bool is_listen, bool is_telnet)
|
||||
{
|
||||
switch (addr->type) {
|
||||
case SOCKET_ADDRESS_KIND_INET:
|
||||
case SOCKET_ADDRESS_TYPE_INET:
|
||||
return g_strdup_printf("%s%s:%s:%s%s", prefix,
|
||||
is_telnet ? "telnet" : "tcp",
|
||||
addr->u.inet.data->host,
|
||||
addr->u.inet.data->port,
|
||||
addr->u.inet.host,
|
||||
addr->u.inet.port,
|
||||
is_listen ? ",server" : "");
|
||||
break;
|
||||
case SOCKET_ADDRESS_KIND_UNIX:
|
||||
case SOCKET_ADDRESS_TYPE_UNIX:
|
||||
return g_strdup_printf("%sunix:%s%s", prefix,
|
||||
addr->u.q_unix.data->path,
|
||||
addr->u.q_unix.path,
|
||||
is_listen ? ",server" : "");
|
||||
break;
|
||||
case SOCKET_ADDRESS_KIND_FD:
|
||||
return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.data->str,
|
||||
case SOCKET_ADDRESS_TYPE_FD:
|
||||
return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.str,
|
||||
is_listen ? ",server" : "");
|
||||
break;
|
||||
case SOCKET_ADDRESS_KIND_VSOCK:
|
||||
case SOCKET_ADDRESS_TYPE_VSOCK:
|
||||
return g_strdup_printf("%svsock:%s:%s", prefix,
|
||||
addr->u.vsock.data->cid,
|
||||
addr->u.vsock.data->port);
|
||||
addr->u.vsock.cid,
|
||||
addr->u.vsock.port);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void update_disconnected_filename(SocketChardev *s)
|
||||
{
|
||||
Chardev *chr = CHARDEV(s);
|
||||
|
||||
g_free(chr->filename);
|
||||
chr->filename = SocketAddress_to_str("disconnected:", s->addr,
|
||||
s->is_listen, s->is_telnet);
|
||||
}
|
||||
|
||||
static void tcp_chr_disconnect(Chardev *chr)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
@@ -380,8 +408,7 @@ static void tcp_chr_disconnect(Chardev *chr)
|
||||
s->listen_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
|
||||
}
|
||||
chr->filename = SocketAddress_to_str("disconnected:", s->addr,
|
||||
s->is_listen, s->is_telnet);
|
||||
update_disconnected_filename(s);
|
||||
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||
if (s->reconnect_time) {
|
||||
qemu_chr_socket_restart_timer(chr);
|
||||
@@ -484,12 +511,12 @@ static void tcp_chr_connect(void *opaque)
|
||||
|
||||
s->connected = 1;
|
||||
if (s->ioc) {
|
||||
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
tcp_chr_read,
|
||||
chr, NULL);
|
||||
}
|
||||
qemu_chr_be_generic_open(chr);
|
||||
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
|
||||
}
|
||||
|
||||
static void tcp_chr_update_read_handler(Chardev *chr,
|
||||
@@ -501,9 +528,9 @@ static void tcp_chr_update_read_handler(Chardev *chr,
|
||||
return;
|
||||
}
|
||||
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
remove_fd_in_watch(chr);
|
||||
if (s->ioc) {
|
||||
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
tcp_chr_read, chr,
|
||||
context);
|
||||
@@ -512,7 +539,7 @@ static void tcp_chr_update_read_handler(Chardev *chr,
|
||||
|
||||
typedef struct {
|
||||
Chardev *chr;
|
||||
char buf[12];
|
||||
char buf[21];
|
||||
size_t buflen;
|
||||
} TCPChardevTelnetInit;
|
||||
|
||||
@@ -550,9 +577,6 @@ static void tcp_chr_telnet_init(Chardev *chr)
|
||||
TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
|
||||
size_t n = 0;
|
||||
|
||||
init->chr = chr;
|
||||
init->buflen = 12;
|
||||
|
||||
#define IACSET(x, a, b, c) \
|
||||
do { \
|
||||
x[n++] = a; \
|
||||
@@ -560,12 +584,26 @@ static void tcp_chr_telnet_init(Chardev *chr)
|
||||
x[n++] = c; \
|
||||
} while (0)
|
||||
|
||||
/* Prep the telnet negotion to put telnet in binary,
|
||||
* no echo, single char mode */
|
||||
IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
|
||||
IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
|
||||
IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
|
||||
IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
|
||||
init->chr = chr;
|
||||
if (!s->is_tn3270) {
|
||||
init->buflen = 12;
|
||||
/* Prep the telnet negotion to put telnet in binary,
|
||||
* no echo, single char mode */
|
||||
IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
|
||||
IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
|
||||
IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
|
||||
IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
|
||||
} else {
|
||||
init->buflen = 21;
|
||||
/* Prep the TN3270 negotion based on RFC1576 */
|
||||
IACSET(init->buf, 0xff, 0xfd, 0x19); /* IAC DO EOR */
|
||||
IACSET(init->buf, 0xff, 0xfb, 0x19); /* IAC WILL EOR */
|
||||
IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO BINARY */
|
||||
IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL BINARY */
|
||||
IACSET(init->buf, 0xff, 0xfd, 0x18); /* IAC DO TERMINAL TYPE */
|
||||
IACSET(init->buf, 0xff, 0xfa, 0x18); /* IAC SB TERMINAL TYPE */
|
||||
IACSET(init->buf, 0x01, 0xff, 0xf0); /* SEND IAC SE */
|
||||
}
|
||||
|
||||
#undef IACSET
|
||||
|
||||
@@ -585,7 +623,8 @@ static void tcp_chr_tls_handshake(QIOTask *task,
|
||||
if (qio_task_propagate_error(task, NULL)) {
|
||||
tcp_chr_disconnect(chr);
|
||||
} else {
|
||||
if (s->do_telnetopt) {
|
||||
/* tn3270 does not support TLS yet */
|
||||
if (s->do_telnetopt && !s->is_tn3270) {
|
||||
tcp_chr_telnet_init(chr);
|
||||
} else {
|
||||
tcp_chr_connect(chr);
|
||||
@@ -609,7 +648,7 @@ static void tcp_chr_tls_init(Chardev *chr)
|
||||
} else {
|
||||
tioc = qio_channel_tls_new_client(
|
||||
s->ioc, s->tls_creds,
|
||||
s->addr->u.inet.data->host,
|
||||
s->addr->u.inet.host,
|
||||
&err);
|
||||
}
|
||||
if (tioc == NULL) {
|
||||
@@ -820,16 +859,18 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
ChardevSocket *sock = backend->u.socket.data;
|
||||
SocketAddress *addr = sock->addr;
|
||||
bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
|
||||
bool is_listen = sock->has_server ? sock->server : true;
|
||||
bool is_telnet = sock->has_telnet ? sock->telnet : false;
|
||||
bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false;
|
||||
bool is_waitconnect = sock->has_wait ? sock->wait : false;
|
||||
int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
|
||||
QIOChannelSocket *sioc = NULL;
|
||||
SocketAddress *addr;
|
||||
|
||||
s->is_listen = is_listen;
|
||||
s->is_telnet = is_telnet;
|
||||
s->is_tn3270 = is_tn3270;
|
||||
s->do_nodelay = do_nodelay;
|
||||
if (sock->tls_creds) {
|
||||
Object *creds;
|
||||
@@ -864,22 +905,21 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
||||
}
|
||||
}
|
||||
|
||||
s->addr = QAPI_CLONE(SocketAddress, sock->addr);
|
||||
s->addr = addr = socket_address_flatten(sock->addr);
|
||||
|
||||
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
|
||||
/* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */
|
||||
if (addr->type == SOCKET_ADDRESS_KIND_UNIX) {
|
||||
if (addr->type == SOCKET_ADDRESS_TYPE_UNIX) {
|
||||
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
|
||||
}
|
||||
|
||||
/* be isn't opened until we get a connection */
|
||||
*be_opened = false;
|
||||
|
||||
chr->filename = SocketAddress_to_str("disconnected:",
|
||||
addr, is_listen, is_telnet);
|
||||
update_disconnected_filename(s);
|
||||
|
||||
if (is_listen) {
|
||||
if (is_telnet) {
|
||||
if (is_telnet || is_tn3270) {
|
||||
s->do_telnetopt = 1;
|
||||
}
|
||||
} else if (reconnect > 0) {
|
||||
@@ -904,6 +944,11 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
||||
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
qapi_free_SocketAddress(s->addr);
|
||||
s->addr = socket_local_address(sioc->fd, errp);
|
||||
update_disconnected_filename(s);
|
||||
|
||||
s->listen_ioc = sioc;
|
||||
if (is_waitconnect &&
|
||||
qemu_chr_wait_connected(chr, errp) < 0) {
|
||||
@@ -933,13 +978,14 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
|
||||
bool is_listen = qemu_opt_get_bool(opts, "server", false);
|
||||
bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true);
|
||||
bool is_telnet = qemu_opt_get_bool(opts, "telnet", false);
|
||||
bool is_tn3270 = qemu_opt_get_bool(opts, "tn3270", false);
|
||||
bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true);
|
||||
int64_t reconnect = qemu_opt_get_number(opts, "reconnect", 0);
|
||||
const char *path = qemu_opt_get(opts, "path");
|
||||
const char *host = qemu_opt_get(opts, "host");
|
||||
const char *port = qemu_opt_get(opts, "port");
|
||||
const char *tls_creds = qemu_opt_get(opts, "tls-creds");
|
||||
SocketAddress *addr;
|
||||
SocketAddressLegacy *addr;
|
||||
ChardevSocket *sock;
|
||||
|
||||
backend->type = CHARDEV_BACKEND_KIND_SOCKET;
|
||||
@@ -968,20 +1014,22 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
|
||||
sock->server = is_listen;
|
||||
sock->has_telnet = true;
|
||||
sock->telnet = is_telnet;
|
||||
sock->has_tn3270 = true;
|
||||
sock->tn3270 = is_tn3270;
|
||||
sock->has_wait = true;
|
||||
sock->wait = is_waitconnect;
|
||||
sock->has_reconnect = true;
|
||||
sock->reconnect = reconnect;
|
||||
sock->tls_creds = g_strdup(tls_creds);
|
||||
|
||||
addr = g_new0(SocketAddress, 1);
|
||||
addr = g_new0(SocketAddressLegacy, 1);
|
||||
if (path) {
|
||||
UnixSocketAddress *q_unix;
|
||||
addr->type = SOCKET_ADDRESS_KIND_UNIX;
|
||||
addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX;
|
||||
q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
||||
q_unix->path = g_strdup(path);
|
||||
} else {
|
||||
addr->type = SOCKET_ADDRESS_KIND_INET;
|
||||
addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
|
||||
addr->u.inet.data = g_new(InetSocketAddress, 1);
|
||||
*addr->u.inet.data = (InetSocketAddress) {
|
||||
.host = g_strdup(host),
|
||||
@@ -997,6 +1045,23 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
|
||||
sock->addr = addr;
|
||||
}
|
||||
|
||||
static void
|
||||
char_socket_get_addr(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(obj);
|
||||
|
||||
visit_type_SocketAddress(v, name, &s->addr, errp);
|
||||
}
|
||||
|
||||
static bool
|
||||
char_socket_get_connected(Object *obj, Error **errp)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(obj);
|
||||
|
||||
return s->connected;
|
||||
}
|
||||
|
||||
static void char_socket_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||
@@ -1012,6 +1077,13 @@ static void char_socket_class_init(ObjectClass *oc, void *data)
|
||||
cc->chr_add_client = tcp_chr_add_client;
|
||||
cc->chr_add_watch = tcp_chr_add_watch;
|
||||
cc->chr_update_read_handler = tcp_chr_update_read_handler;
|
||||
|
||||
object_class_property_add(oc, "addr", "SocketAddress",
|
||||
char_socket_get_addr, NULL,
|
||||
NULL, NULL, &error_abort);
|
||||
|
||||
object_class_property_add_bool(oc, "connected", char_socket_get_connected,
|
||||
NULL, &error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo char_socket_type_info = {
|
||||
|
||||
@@ -51,6 +51,18 @@ static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||
s->ioc, (const char *)buf, len, NULL);
|
||||
}
|
||||
|
||||
static void udp_chr_flush_buffer(UdpChardev *s)
|
||||
{
|
||||
Chardev *chr = CHARDEV(s);
|
||||
|
||||
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
|
||||
int n = MIN(s->max_size, s->bufcnt - s->bufptr);
|
||||
qemu_chr_be_write(chr, &s->buf[s->bufptr], n);
|
||||
s->bufptr += n;
|
||||
s->max_size = qemu_chr_be_can_write(chr);
|
||||
}
|
||||
}
|
||||
|
||||
static int udp_chr_read_poll(void *opaque)
|
||||
{
|
||||
Chardev *chr = CHARDEV(opaque);
|
||||
@@ -61,11 +73,8 @@ static int udp_chr_read_poll(void *opaque)
|
||||
/* If there were any stray characters in the queue process them
|
||||
* first
|
||||
*/
|
||||
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
|
||||
qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
|
||||
s->bufptr++;
|
||||
s->max_size = qemu_chr_be_can_write(chr);
|
||||
}
|
||||
udp_chr_flush_buffer(s);
|
||||
|
||||
return s->max_size;
|
||||
}
|
||||
|
||||
@@ -81,17 +90,12 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
ret = qio_channel_read(
|
||||
s->ioc, (char *)s->buf, sizeof(s->buf), NULL);
|
||||
if (ret <= 0) {
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
remove_fd_in_watch(chr);
|
||||
return FALSE;
|
||||
}
|
||||
s->bufcnt = ret;
|
||||
|
||||
s->bufptr = 0;
|
||||
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
|
||||
qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
|
||||
s->bufptr++;
|
||||
s->max_size = qemu_chr_be_can_write(chr);
|
||||
}
|
||||
udp_chr_flush_buffer(s);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -101,9 +105,9 @@ static void udp_chr_update_read_handler(Chardev *chr,
|
||||
{
|
||||
UdpChardev *s = UDP_CHARDEV(chr);
|
||||
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
remove_fd_in_watch(chr);
|
||||
if (s->ioc) {
|
||||
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
udp_chr_read_poll,
|
||||
udp_chr_read, chr,
|
||||
context);
|
||||
@@ -115,7 +119,7 @@ static void char_udp_finalize(Object *obj)
|
||||
Chardev *chr = CHARDEV(obj);
|
||||
UdpChardev *s = UDP_CHARDEV(obj);
|
||||
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
remove_fd_in_watch(chr);
|
||||
if (s->ioc) {
|
||||
object_unref(OBJECT(s->ioc));
|
||||
}
|
||||
@@ -130,7 +134,7 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
|
||||
const char *localaddr = qemu_opt_get(opts, "localaddr");
|
||||
const char *localport = qemu_opt_get(opts, "localport");
|
||||
bool has_local = false;
|
||||
SocketAddress *addr;
|
||||
SocketAddressLegacy *addr;
|
||||
ChardevUdp *udp;
|
||||
|
||||
backend->type = CHARDEV_BACKEND_KIND_UDP;
|
||||
@@ -155,8 +159,8 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
|
||||
udp = backend->u.udp.data = g_new0(ChardevUdp, 1);
|
||||
qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp));
|
||||
|
||||
addr = g_new0(SocketAddress, 1);
|
||||
addr->type = SOCKET_ADDRESS_KIND_INET;
|
||||
addr = g_new0(SocketAddressLegacy, 1);
|
||||
addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
|
||||
addr->u.inet.data = g_new(InetSocketAddress, 1);
|
||||
*addr->u.inet.data = (InetSocketAddress) {
|
||||
.host = g_strdup(host),
|
||||
@@ -170,8 +174,8 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
|
||||
|
||||
if (has_local) {
|
||||
udp->has_local = true;
|
||||
addr = g_new0(SocketAddress, 1);
|
||||
addr->type = SOCKET_ADDRESS_KIND_INET;
|
||||
addr = g_new0(SocketAddressLegacy, 1);
|
||||
addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
|
||||
addr->u.inet.data = g_new(InetSocketAddress, 1);
|
||||
*addr->u.inet.data = (InetSocketAddress) {
|
||||
.host = g_strdup(localaddr),
|
||||
@@ -187,13 +191,17 @@ static void qmp_chardev_open_udp(Chardev *chr,
|
||||
Error **errp)
|
||||
{
|
||||
ChardevUdp *udp = backend->u.udp.data;
|
||||
SocketAddress *local_addr = socket_address_flatten(udp->local);
|
||||
SocketAddress *remote_addr = socket_address_flatten(udp->remote);
|
||||
QIOChannelSocket *sioc = qio_channel_socket_new();
|
||||
char *name;
|
||||
UdpChardev *s = UDP_CHARDEV(chr);
|
||||
int ret;
|
||||
|
||||
if (qio_channel_socket_dgram_sync(sioc,
|
||||
udp->local, udp->remote,
|
||||
errp) < 0) {
|
||||
ret = qio_channel_socket_dgram_sync(sioc, local_addr, remote_addr, errp);
|
||||
qapi_free_SocketAddress(local_addr);
|
||||
qapi_free_SocketAddress(remote_addr);
|
||||
if (ret < 0) {
|
||||
object_unref(OBJECT(sioc));
|
||||
return;
|
||||
}
|
||||
|
||||
163
chardev/char.c
163
chardev/char.c
@@ -42,8 +42,10 @@
|
||||
/***********************************************************/
|
||||
/* character device */
|
||||
|
||||
static QTAILQ_HEAD(ChardevHead, Chardev) chardevs =
|
||||
QTAILQ_HEAD_INITIALIZER(chardevs);
|
||||
static Object *get_chardevs_root(void)
|
||||
{
|
||||
return container_get(object_get_root(), "/chardevs");
|
||||
}
|
||||
|
||||
void qemu_chr_be_event(Chardev *s, int event)
|
||||
{
|
||||
@@ -66,12 +68,6 @@ void qemu_chr_be_event(Chardev *s, int event)
|
||||
be->chr_event(be->opaque, event);
|
||||
}
|
||||
|
||||
void qemu_chr_be_generic_open(Chardev *s)
|
||||
{
|
||||
qemu_chr_be_event(s, CHR_EVENT_OPENED);
|
||||
}
|
||||
|
||||
|
||||
/* Not reporting errors from writing to logfile, as logs are
|
||||
* defined to be "best effort" only */
|
||||
static void qemu_chr_fe_write_log(Chardev *s,
|
||||
@@ -453,26 +449,24 @@ static const TypeInfo char_type_info = {
|
||||
* mux will receive CHR_EVENT_OPENED notifications for the BE
|
||||
* immediately.
|
||||
*/
|
||||
static int open_muxes(Object *child, void *opaque)
|
||||
{
|
||||
if (CHARDEV_IS_MUX(child)) {
|
||||
/* send OPENED to all already-attached FEs */
|
||||
mux_chr_send_all_event(CHARDEV(child), CHR_EVENT_OPENED);
|
||||
/* mark mux as OPENED so any new FEs will immediately receive
|
||||
* OPENED event
|
||||
*/
|
||||
qemu_chr_be_event(CHARDEV(child), CHR_EVENT_OPENED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void muxes_realize_done(Notifier *notifier, void *unused)
|
||||
{
|
||||
Chardev *chr;
|
||||
|
||||
QTAILQ_FOREACH(chr, &chardevs, next) {
|
||||
if (CHARDEV_IS_MUX(chr)) {
|
||||
MuxChardev *d = MUX_CHARDEV(chr);
|
||||
int i;
|
||||
|
||||
/* send OPENED to all already-attached FEs */
|
||||
for (i = 0; i < d->mux_cnt; i++) {
|
||||
mux_chr_send_event(d, i, CHR_EVENT_OPENED);
|
||||
}
|
||||
/* mark mux as OPENED so any new FEs will immediately receive
|
||||
* OPENED event
|
||||
*/
|
||||
qemu_chr_be_generic_open(chr);
|
||||
}
|
||||
}
|
||||
muxes_realized = true;
|
||||
object_child_foreach(get_chardevs_root(), open_muxes, NULL);
|
||||
}
|
||||
|
||||
static Notifier muxes_realize_notify = {
|
||||
@@ -560,7 +554,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
cc = CHARDEV_GET_CLASS(s);
|
||||
if (!opaque && !fd_can_read && !fd_read && !fd_event) {
|
||||
fe_open = 0;
|
||||
remove_fd_in_watch(s, context);
|
||||
remove_fd_in_watch(s);
|
||||
} else {
|
||||
fe_open = 1;
|
||||
}
|
||||
@@ -581,7 +575,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
/* We're connecting to an already opened device, so let's make sure we
|
||||
also get the open event */
|
||||
if (s->be_open) {
|
||||
qemu_chr_be_generic_open(s);
|
||||
qemu_chr_be_event(s, CHR_EVENT_OPENED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,7 +690,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
|
||||
return opts;
|
||||
}
|
||||
if (strstart(filename, "tcp:", &p) ||
|
||||
strstart(filename, "telnet:", &p)) {
|
||||
strstart(filename, "telnet:", &p) ||
|
||||
strstart(filename, "tn3270:", &p)) {
|
||||
if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
|
||||
host[0] = 0;
|
||||
if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
|
||||
@@ -712,8 +707,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (strstart(filename, "telnet:", &p))
|
||||
if (strstart(filename, "telnet:", &p)) {
|
||||
qemu_opt_set(opts, "telnet", "on", &error_abort);
|
||||
} else if (strstart(filename, "tn3270:", &p)) {
|
||||
qemu_opt_set(opts, "tn3270", "on", &error_abort);
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
if (strstart(filename, "udp:", &p)) {
|
||||
@@ -770,7 +768,7 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
|
||||
const char *logfile = qemu_opt_get(opts, "logfile");
|
||||
|
||||
backend->has_logfile = logfile != NULL;
|
||||
backend->logfile = logfile ? g_strdup(logfile) : NULL;
|
||||
backend->logfile = g_strdup(logfile);
|
||||
|
||||
backend->has_logappend = true;
|
||||
backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
|
||||
@@ -805,26 +803,6 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
|
||||
return cc;
|
||||
}
|
||||
|
||||
static Chardev *qemu_chardev_add(const char *id, const char *typename,
|
||||
ChardevBackend *backend, Error **errp)
|
||||
{
|
||||
Chardev *chr;
|
||||
|
||||
chr = qemu_chr_find(id);
|
||||
if (chr) {
|
||||
error_setg(errp, "Chardev '%s' already exists", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chr = qemu_chardev_new(id, typename, backend, errp);
|
||||
if (!chr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QTAILQ_INSERT_TAIL(&chardevs, chr, next);
|
||||
return chr;
|
||||
}
|
||||
|
||||
static const struct ChardevAlias {
|
||||
const char *typename;
|
||||
const char *alias;
|
||||
@@ -941,9 +919,10 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
|
||||
backend->u.null.data = ccom; /* Any ChardevCommon member would work */
|
||||
}
|
||||
|
||||
chr = qemu_chardev_add(bid ? bid : id,
|
||||
chr = qemu_chardev_new(bid ? bid : id,
|
||||
object_class_get_name(OBJECT_CLASS(cc)),
|
||||
backend, errp);
|
||||
|
||||
if (chr == NULL) {
|
||||
goto out;
|
||||
}
|
||||
@@ -955,9 +934,9 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
|
||||
backend->type = CHARDEV_BACKEND_KIND_MUX;
|
||||
backend->u.mux.data = g_new0(ChardevMux, 1);
|
||||
backend->u.mux.data->chardev = g_strdup(bid);
|
||||
mux = qemu_chardev_add(id, TYPE_CHARDEV_MUX, backend, errp);
|
||||
mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, errp);
|
||||
if (mux == NULL) {
|
||||
qemu_chr_delete(chr);
|
||||
object_unparent(OBJECT(chr));
|
||||
chr = NULL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1071,27 +1050,29 @@ void qemu_chr_fe_disconnect(CharBackend *be)
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_chr_delete(Chardev *chr)
|
||||
static int qmp_query_chardev_foreach(Object *obj, void *data)
|
||||
{
|
||||
QTAILQ_REMOVE(&chardevs, chr, next);
|
||||
object_unref(OBJECT(chr));
|
||||
Chardev *chr = CHARDEV(obj);
|
||||
ChardevInfoList **list = data;
|
||||
ChardevInfoList *info = g_malloc0(sizeof(*info));
|
||||
|
||||
info->value = g_malloc0(sizeof(*info->value));
|
||||
info->value->label = g_strdup(chr->label);
|
||||
info->value->filename = g_strdup(chr->filename);
|
||||
info->value->frontend_open = chr->be && chr->be->fe_open;
|
||||
|
||||
info->next = *list;
|
||||
*list = info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ChardevInfoList *qmp_query_chardev(Error **errp)
|
||||
{
|
||||
ChardevInfoList *chr_list = NULL;
|
||||
Chardev *chr;
|
||||
|
||||
QTAILQ_FOREACH(chr, &chardevs, next) {
|
||||
ChardevInfoList *info = g_malloc0(sizeof(*info));
|
||||
info->value = g_malloc0(sizeof(*info->value));
|
||||
info->value->label = g_strdup(chr->label);
|
||||
info->value->filename = g_strdup(chr->filename);
|
||||
info->value->frontend_open = chr->be && chr->be->fe_open;
|
||||
|
||||
info->next = chr_list;
|
||||
chr_list = info;
|
||||
}
|
||||
object_child_foreach(get_chardevs_root(),
|
||||
qmp_query_chardev_foreach, &chr_list);
|
||||
|
||||
return chr_list;
|
||||
}
|
||||
@@ -1119,14 +1100,9 @@ ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
|
||||
|
||||
Chardev *qemu_chr_find(const char *name)
|
||||
{
|
||||
Chardev *chr;
|
||||
Object *obj = object_resolve_path_component(get_chardevs_root(), name);
|
||||
|
||||
QTAILQ_FOREACH(chr, &chardevs, next) {
|
||||
if (strcmp(chr->label, name) != 0)
|
||||
continue;
|
||||
return chr;
|
||||
}
|
||||
return NULL;
|
||||
return obj ? CHARDEV(obj) : NULL;
|
||||
}
|
||||
|
||||
QemuOptsList qemu_chardev_opts = {
|
||||
@@ -1176,6 +1152,9 @@ QemuOptsList qemu_chardev_opts = {
|
||||
},{
|
||||
.name = "telnet",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},{
|
||||
.name = "tn3270",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},{
|
||||
.name = "tls-creds",
|
||||
.type = QEMU_OPT_STRING,
|
||||
@@ -1236,22 +1215,23 @@ void qemu_chr_set_feature(Chardev *chr,
|
||||
}
|
||||
|
||||
Chardev *qemu_chardev_new(const char *id, const char *typename,
|
||||
ChardevBackend *backend, Error **errp)
|
||||
ChardevBackend *backend,
|
||||
Error **errp)
|
||||
{
|
||||
Object *obj;
|
||||
Chardev *chr = NULL;
|
||||
Error *local_err = NULL;
|
||||
bool be_opened = true;
|
||||
|
||||
assert(g_str_has_prefix(typename, "chardev-"));
|
||||
|
||||
chr = CHARDEV(object_new(typename));
|
||||
obj = object_new(typename);
|
||||
chr = CHARDEV(obj);
|
||||
chr->label = g_strdup(id);
|
||||
|
||||
qemu_char_open(chr, backend, &be_opened, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
object_unref(OBJECT(chr));
|
||||
return NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!chr->filename) {
|
||||
@@ -1261,6 +1241,21 @@ Chardev *qemu_chardev_new(const char *id, const char *typename,
|
||||
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
|
||||
}
|
||||
|
||||
if (id) {
|
||||
object_property_add_child(get_chardevs_root(), id, obj, &local_err);
|
||||
if (local_err) {
|
||||
goto end;
|
||||
}
|
||||
object_unref(obj);
|
||||
}
|
||||
|
||||
end:
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
object_unref(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return chr;
|
||||
}
|
||||
|
||||
@@ -1276,7 +1271,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chr = qemu_chardev_add(id, object_class_get_name(OBJECT_CLASS(cc)),
|
||||
chr = qemu_chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
|
||||
backend, errp);
|
||||
if (!chr) {
|
||||
return NULL;
|
||||
@@ -1309,16 +1304,12 @@ void qmp_chardev_remove(const char *id, Error **errp)
|
||||
"Chardev '%s' cannot be unplugged in record/replay mode", id);
|
||||
return;
|
||||
}
|
||||
qemu_chr_delete(chr);
|
||||
object_unparent(OBJECT(chr));
|
||||
}
|
||||
|
||||
void qemu_chr_cleanup(void)
|
||||
{
|
||||
Chardev *chr, *tmp;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(chr, &chardevs, next, tmp) {
|
||||
qemu_chr_delete(chr);
|
||||
}
|
||||
object_unparent(get_chardevs_root());
|
||||
}
|
||||
|
||||
static void register_types(void)
|
||||
|
||||
20
configure
vendored
20
configure
vendored
@@ -4852,6 +4852,20 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# check for _Static_assert()
|
||||
|
||||
have_static_assert=no
|
||||
cat > $TMPC << EOF
|
||||
_Static_assert(1, "success");
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
have_static_assert=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# End of CC checks
|
||||
# After here, no more $cc or $ld runs
|
||||
@@ -5848,6 +5862,10 @@ if test "$have_sysmacros" = "yes" ; then
|
||||
echo "CONFIG_SYSMACROS=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$have_static_assert" = "yes" ; then
|
||||
echo "CONFIG_STATIC_ASSERT=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
# Hold two types of flag:
|
||||
# CONFIG_THREAD_SETNAME_BYTHREAD - we've got a way of setting the name on
|
||||
# a thread we have a handle to
|
||||
@@ -6023,9 +6041,11 @@ TARGET_ABI_DIR=""
|
||||
|
||||
case "$target_name" in
|
||||
i386)
|
||||
gdb_xml_files="i386-32bit-core.xml"
|
||||
;;
|
||||
x86_64)
|
||||
TARGET_BASE_ARCH=i386
|
||||
gdb_xml_files="i386-64bit-core.xml"
|
||||
;;
|
||||
alpha)
|
||||
mttcg="yes"
|
||||
|
||||
@@ -81,7 +81,7 @@ vu_panic(VuDev *dev, const char *msg, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, msg);
|
||||
(void)vasprintf(&buf, msg, ap);
|
||||
buf = g_strdup_vprintf(msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
dev->broken = true;
|
||||
|
||||
@@ -2,6 +2,7 @@ CONFIG_PCI=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_TERMINAL3270=y
|
||||
CONFIG_S390_FLIC=y
|
||||
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
|
||||
CONFIG_WDT_DIAG288=y
|
||||
|
||||
7
dump.c
7
dump.c
@@ -77,7 +77,13 @@ static int dump_cleanup(DumpState *s)
|
||||
memory_mapping_list_free(&s->list);
|
||||
close(s->fd);
|
||||
if (s->resume) {
|
||||
if (s->detached) {
|
||||
qemu_mutex_lock_iothread();
|
||||
}
|
||||
vm_start();
|
||||
if (s->detached) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1804,6 +1810,7 @@ void qmp_dump_guest_memory(bool paging, const char *file,
|
||||
|
||||
if (detach_p) {
|
||||
/* detached dump */
|
||||
s->detached = true;
|
||||
qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread,
|
||||
s, QEMU_THREAD_DETACHED);
|
||||
} else {
|
||||
|
||||
65
gdb-xml/i386-32bit-core.xml
Normal file
65
gdb-xml/i386-32bit-core.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2010-2015 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.i386.core">
|
||||
<flags id="i386_eflags" size="4">
|
||||
<field name="CF" start="0" end="0"/>
|
||||
<field name="" start="1" end="1"/>
|
||||
<field name="PF" start="2" end="2"/>
|
||||
<field name="AF" start="4" end="4"/>
|
||||
<field name="ZF" start="6" end="6"/>
|
||||
<field name="SF" start="7" end="7"/>
|
||||
<field name="TF" start="8" end="8"/>
|
||||
<field name="IF" start="9" end="9"/>
|
||||
<field name="DF" start="10" end="10"/>
|
||||
<field name="OF" start="11" end="11"/>
|
||||
<field name="NT" start="14" end="14"/>
|
||||
<field name="RF" start="16" end="16"/>
|
||||
<field name="VM" start="17" end="17"/>
|
||||
<field name="AC" start="18" end="18"/>
|
||||
<field name="VIF" start="19" end="19"/>
|
||||
<field name="VIP" start="20" end="20"/>
|
||||
<field name="ID" start="21" end="21"/>
|
||||
</flags>
|
||||
|
||||
<reg name="eax" bitsize="32" type="int32"/>
|
||||
<reg name="ecx" bitsize="32" type="int32"/>
|
||||
<reg name="edx" bitsize="32" type="int32"/>
|
||||
<reg name="ebx" bitsize="32" type="int32"/>
|
||||
<reg name="esp" bitsize="32" type="data_ptr"/>
|
||||
<reg name="ebp" bitsize="32" type="data_ptr"/>
|
||||
<reg name="esi" bitsize="32" type="int32"/>
|
||||
<reg name="edi" bitsize="32" type="int32"/>
|
||||
|
||||
<reg name="eip" bitsize="32" type="code_ptr"/>
|
||||
<reg name="eflags" bitsize="32" type="i386_eflags"/>
|
||||
<reg name="cs" bitsize="32" type="int32"/>
|
||||
<reg name="ss" bitsize="32" type="int32"/>
|
||||
<reg name="ds" bitsize="32" type="int32"/>
|
||||
<reg name="es" bitsize="32" type="int32"/>
|
||||
<reg name="fs" bitsize="32" type="int32"/>
|
||||
<reg name="gs" bitsize="32" type="int32"/>
|
||||
|
||||
<reg name="st0" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st1" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st2" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st3" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st4" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st5" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st6" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st7" bitsize="80" type="i387_ext"/>
|
||||
|
||||
<reg name="fctrl" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fstat" bitsize="32" type="int" group="float"/>
|
||||
<reg name="ftag" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fiseg" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fioff" bitsize="32" type="int" group="float"/>
|
||||
<reg name="foseg" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fooff" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fop" bitsize="32" type="int" group="float"/>
|
||||
</feature>
|
||||
73
gdb-xml/i386-64bit-core.xml
Normal file
73
gdb-xml/i386-64bit-core.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2010-2015 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.i386.core">
|
||||
<flags id="i386_eflags" size="4">
|
||||
<field name="CF" start="0" end="0"/>
|
||||
<field name="" start="1" end="1"/>
|
||||
<field name="PF" start="2" end="2"/>
|
||||
<field name="AF" start="4" end="4"/>
|
||||
<field name="ZF" start="6" end="6"/>
|
||||
<field name="SF" start="7" end="7"/>
|
||||
<field name="TF" start="8" end="8"/>
|
||||
<field name="IF" start="9" end="9"/>
|
||||
<field name="DF" start="10" end="10"/>
|
||||
<field name="OF" start="11" end="11"/>
|
||||
<field name="NT" start="14" end="14"/>
|
||||
<field name="RF" start="16" end="16"/>
|
||||
<field name="VM" start="17" end="17"/>
|
||||
<field name="AC" start="18" end="18"/>
|
||||
<field name="VIF" start="19" end="19"/>
|
||||
<field name="VIP" start="20" end="20"/>
|
||||
<field name="ID" start="21" end="21"/>
|
||||
</flags>
|
||||
|
||||
<reg name="rax" bitsize="64" type="int64"/>
|
||||
<reg name="rbx" bitsize="64" type="int64"/>
|
||||
<reg name="rcx" bitsize="64" type="int64"/>
|
||||
<reg name="rdx" bitsize="64" type="int64"/>
|
||||
<reg name="rsi" bitsize="64" type="int64"/>
|
||||
<reg name="rdi" bitsize="64" type="int64"/>
|
||||
<reg name="rbp" bitsize="64" type="data_ptr"/>
|
||||
<reg name="rsp" bitsize="64" type="data_ptr"/>
|
||||
<reg name="r8" bitsize="64" type="int64"/>
|
||||
<reg name="r9" bitsize="64" type="int64"/>
|
||||
<reg name="r10" bitsize="64" type="int64"/>
|
||||
<reg name="r11" bitsize="64" type="int64"/>
|
||||
<reg name="r12" bitsize="64" type="int64"/>
|
||||
<reg name="r13" bitsize="64" type="int64"/>
|
||||
<reg name="r14" bitsize="64" type="int64"/>
|
||||
<reg name="r15" bitsize="64" type="int64"/>
|
||||
|
||||
<reg name="rip" bitsize="64" type="code_ptr"/>
|
||||
<reg name="eflags" bitsize="32" type="i386_eflags"/>
|
||||
<reg name="cs" bitsize="32" type="int32"/>
|
||||
<reg name="ss" bitsize="32" type="int32"/>
|
||||
<reg name="ds" bitsize="32" type="int32"/>
|
||||
<reg name="es" bitsize="32" type="int32"/>
|
||||
<reg name="fs" bitsize="32" type="int32"/>
|
||||
<reg name="gs" bitsize="32" type="int32"/>
|
||||
|
||||
<reg name="st0" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st1" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st2" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st3" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st4" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st5" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st6" bitsize="80" type="i387_ext"/>
|
||||
<reg name="st7" bitsize="80" type="i387_ext"/>
|
||||
|
||||
<reg name="fctrl" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fstat" bitsize="32" type="int" group="float"/>
|
||||
<reg name="ftag" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fiseg" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fioff" bitsize="32" type="int" group="float"/>
|
||||
<reg name="foseg" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fooff" bitsize="32" type="int" group="float"/>
|
||||
<reg name="fop" bitsize="32" type="int" group="float"/>
|
||||
</feature>
|
||||
114
gdbstub.c
114
gdbstub.c
@@ -286,6 +286,8 @@ enum RSState {
|
||||
RS_INACTIVE,
|
||||
RS_IDLE,
|
||||
RS_GETLINE,
|
||||
RS_GETLINE_ESC,
|
||||
RS_GETLINE_RLE,
|
||||
RS_CHKSUM1,
|
||||
RS_CHKSUM2,
|
||||
};
|
||||
@@ -296,7 +298,8 @@ typedef struct GDBState {
|
||||
enum RSState state; /* parsing state */
|
||||
char line_buf[MAX_PACKET_LENGTH];
|
||||
int line_buf_index;
|
||||
int line_csum;
|
||||
int line_sum; /* running checksum */
|
||||
int line_csum; /* checksum at the end of the packet */
|
||||
uint8_t last_packet[MAX_PACKET_LENGTH + 4];
|
||||
int last_packet_len;
|
||||
int signal;
|
||||
@@ -1508,7 +1511,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
|
||||
|
||||
static void gdb_read_byte(GDBState *s, int ch)
|
||||
{
|
||||
int i, csum;
|
||||
uint8_t reply;
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
@@ -1542,35 +1544,123 @@ static void gdb_read_byte(GDBState *s, int ch)
|
||||
switch(s->state) {
|
||||
case RS_IDLE:
|
||||
if (ch == '$') {
|
||||
/* start of command packet */
|
||||
s->line_buf_index = 0;
|
||||
s->line_sum = 0;
|
||||
s->state = RS_GETLINE;
|
||||
} else {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub received garbage between packets: 0x%x\n", ch);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case RS_GETLINE:
|
||||
if (ch == '#') {
|
||||
s->state = RS_CHKSUM1;
|
||||
if (ch == '}') {
|
||||
/* start escape sequence */
|
||||
s->state = RS_GETLINE_ESC;
|
||||
s->line_sum += ch;
|
||||
} else if (ch == '*') {
|
||||
/* start run length encoding sequence */
|
||||
s->state = RS_GETLINE_RLE;
|
||||
s->line_sum += ch;
|
||||
} else if (ch == '#') {
|
||||
/* end of command, start of checksum*/
|
||||
s->state = RS_CHKSUM1;
|
||||
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub command buffer overrun, dropping command\n");
|
||||
#endif
|
||||
s->state = RS_IDLE;
|
||||
} else {
|
||||
s->line_buf[s->line_buf_index++] = ch;
|
||||
/* unescaped command character */
|
||||
s->line_buf[s->line_buf_index++] = ch;
|
||||
s->line_sum += ch;
|
||||
}
|
||||
break;
|
||||
case RS_GETLINE_ESC:
|
||||
if (ch == '#') {
|
||||
/* unexpected end of command in escape sequence */
|
||||
s->state = RS_CHKSUM1;
|
||||
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
|
||||
/* command buffer overrun */
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub command buffer overrun, dropping command\n");
|
||||
#endif
|
||||
s->state = RS_IDLE;
|
||||
} else {
|
||||
/* parse escaped character and leave escape state */
|
||||
s->line_buf[s->line_buf_index++] = ch ^ 0x20;
|
||||
s->line_sum += ch;
|
||||
s->state = RS_GETLINE;
|
||||
}
|
||||
break;
|
||||
case RS_GETLINE_RLE:
|
||||
if (ch < ' ') {
|
||||
/* invalid RLE count encoding */
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got invalid RLE count: 0x%x\n", ch);
|
||||
#endif
|
||||
s->state = RS_GETLINE;
|
||||
} else {
|
||||
/* decode repeat length */
|
||||
int repeat = (unsigned char)ch - ' ' + 3;
|
||||
if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
|
||||
/* that many repeats would overrun the command buffer */
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub command buffer overrun,"
|
||||
" dropping command\n");
|
||||
#endif
|
||||
s->state = RS_IDLE;
|
||||
} else if (s->line_buf_index < 1) {
|
||||
/* got a repeat but we have nothing to repeat */
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got invalid RLE sequence\n");
|
||||
#endif
|
||||
s->state = RS_GETLINE;
|
||||
} else {
|
||||
/* repeat the last character */
|
||||
memset(s->line_buf + s->line_buf_index,
|
||||
s->line_buf[s->line_buf_index - 1], repeat);
|
||||
s->line_buf_index += repeat;
|
||||
s->line_sum += ch;
|
||||
s->state = RS_GETLINE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RS_CHKSUM1:
|
||||
/* get high hex digit of checksum */
|
||||
if (!isxdigit(ch)) {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got invalid command checksum digit\n");
|
||||
#endif
|
||||
s->state = RS_GETLINE;
|
||||
break;
|
||||
}
|
||||
s->line_buf[s->line_buf_index] = '\0';
|
||||
s->line_csum = fromhex(ch) << 4;
|
||||
s->state = RS_CHKSUM2;
|
||||
break;
|
||||
case RS_CHKSUM2:
|
||||
s->line_csum |= fromhex(ch);
|
||||
csum = 0;
|
||||
for(i = 0; i < s->line_buf_index; i++) {
|
||||
csum += s->line_buf[i];
|
||||
/* get low hex digit of checksum */
|
||||
if (!isxdigit(ch)) {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got invalid command checksum digit\n");
|
||||
#endif
|
||||
s->state = RS_GETLINE;
|
||||
break;
|
||||
}
|
||||
if (s->line_csum != (csum & 0xff)) {
|
||||
s->line_csum |= fromhex(ch);
|
||||
|
||||
if (s->line_csum != (s->line_sum & 0xff)) {
|
||||
/* send NAK reply */
|
||||
reply = '-';
|
||||
put_buffer(s, &reply, 1);
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got command packet with incorrect checksum\n");
|
||||
#endif
|
||||
s->state = RS_IDLE;
|
||||
} else {
|
||||
/* send ACK reply */
|
||||
reply = '+';
|
||||
put_buffer(s, &reply, 1);
|
||||
s->state = gdb_handle_packet(s, s->line_buf);
|
||||
@@ -1611,7 +1701,7 @@ void gdb_exit(CPUArchState *env, int code)
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
qemu_chr_fe_deinit(&s->chr);
|
||||
qemu_chr_delete(chr);
|
||||
object_unparent(OBJECT(chr));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1912,7 +2002,7 @@ int gdbserver_start(const char *device)
|
||||
monitor_init(mon_chr, 0);
|
||||
} else {
|
||||
if (qemu_chr_fe_get_driver(&s->chr)) {
|
||||
qemu_chr_delete(qemu_chr_fe_get_driver(&s->chr));
|
||||
object_unparent(OBJECT(qemu_chr_fe_get_driver(&s->chr)));
|
||||
}
|
||||
mon_chr = s->mon_chr;
|
||||
memset(s, 0, sizeof(GDBState));
|
||||
|
||||
177
hmp.c
177
hmp.c
@@ -19,6 +19,7 @@
|
||||
#include "net/eth.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/timer.h"
|
||||
@@ -33,6 +34,7 @@
|
||||
#include "qapi-visit.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "ui/console.h"
|
||||
#include "block/nbd.h"
|
||||
#include "block/qapi.h"
|
||||
#include "qemu-io.h"
|
||||
#include "qemu/cutils.h"
|
||||
@@ -1268,6 +1270,179 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
void hmp_loadvm(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
int saved_vm_running = runstate_is_running();
|
||||
const char *name = qdict_get_str(qdict, "name");
|
||||
|
||||
vm_stop(RUN_STATE_RESTORE_VM);
|
||||
|
||||
if (load_vmstate(name) == 0 && saved_vm_running) {
|
||||
vm_start();
|
||||
}
|
||||
}
|
||||
|
||||
void hmp_savevm(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
save_vmstate(qdict_get_try_str(qdict, "name"));
|
||||
}
|
||||
|
||||
void hmp_delvm(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
Error *err;
|
||||
const char *name = qdict_get_str(qdict, "name");
|
||||
|
||||
if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
|
||||
error_reportf_err(err,
|
||||
"Error while deleting snapshot on device '%s': ",
|
||||
bdrv_get_device_name(bs));
|
||||
}
|
||||
}
|
||||
|
||||
void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
BlockDriverState *bs, *bs1;
|
||||
BdrvNextIterator it1;
|
||||
QEMUSnapshotInfo *sn_tab, *sn;
|
||||
bool no_snapshot = true;
|
||||
int nb_sns, i;
|
||||
int total;
|
||||
int *global_snapshots;
|
||||
AioContext *aio_context;
|
||||
|
||||
typedef struct SnapshotEntry {
|
||||
QEMUSnapshotInfo sn;
|
||||
QTAILQ_ENTRY(SnapshotEntry) next;
|
||||
} SnapshotEntry;
|
||||
|
||||
typedef struct ImageEntry {
|
||||
const char *imagename;
|
||||
QTAILQ_ENTRY(ImageEntry) next;
|
||||
QTAILQ_HEAD(, SnapshotEntry) snapshots;
|
||||
} ImageEntry;
|
||||
|
||||
QTAILQ_HEAD(, ImageEntry) image_list =
|
||||
QTAILQ_HEAD_INITIALIZER(image_list);
|
||||
|
||||
ImageEntry *image_entry, *next_ie;
|
||||
SnapshotEntry *snapshot_entry;
|
||||
|
||||
bs = bdrv_all_find_vmstate_bs();
|
||||
if (!bs) {
|
||||
monitor_printf(mon, "No available block device supports snapshots\n");
|
||||
return;
|
||||
}
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
nb_sns = bdrv_snapshot_list(bs, &sn_tab);
|
||||
aio_context_release(aio_context);
|
||||
|
||||
if (nb_sns < 0) {
|
||||
monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
|
||||
return;
|
||||
}
|
||||
|
||||
for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
|
||||
int bs1_nb_sns = 0;
|
||||
ImageEntry *ie;
|
||||
SnapshotEntry *se;
|
||||
AioContext *ctx = bdrv_get_aio_context(bs1);
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
if (bdrv_can_snapshot(bs1)) {
|
||||
sn = NULL;
|
||||
bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
|
||||
if (bs1_nb_sns > 0) {
|
||||
no_snapshot = false;
|
||||
ie = g_new0(ImageEntry, 1);
|
||||
ie->imagename = bdrv_get_device_name(bs1);
|
||||
QTAILQ_INIT(&ie->snapshots);
|
||||
QTAILQ_INSERT_TAIL(&image_list, ie, next);
|
||||
for (i = 0; i < bs1_nb_sns; i++) {
|
||||
se = g_new0(SnapshotEntry, 1);
|
||||
se->sn = sn[i];
|
||||
QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
|
||||
}
|
||||
}
|
||||
g_free(sn);
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
|
||||
if (no_snapshot) {
|
||||
monitor_printf(mon, "There is no snapshot available.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
global_snapshots = g_new0(int, nb_sns);
|
||||
total = 0;
|
||||
for (i = 0; i < nb_sns; i++) {
|
||||
SnapshotEntry *next_sn;
|
||||
if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) {
|
||||
global_snapshots[total] = i;
|
||||
total++;
|
||||
QTAILQ_FOREACH(image_entry, &image_list, next) {
|
||||
QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
|
||||
next, next_sn) {
|
||||
if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
|
||||
QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
|
||||
next);
|
||||
g_free(snapshot_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monitor_printf(mon, "List of snapshots present on all disks:\n");
|
||||
|
||||
if (total > 0) {
|
||||
bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
|
||||
monitor_printf(mon, "\n");
|
||||
for (i = 0; i < total; i++) {
|
||||
sn = &sn_tab[global_snapshots[i]];
|
||||
/* The ID is not guaranteed to be the same on all images, so
|
||||
* overwrite it.
|
||||
*/
|
||||
pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
|
||||
bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, sn);
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
} else {
|
||||
monitor_printf(mon, "None\n");
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(image_entry, &image_list, next) {
|
||||
if (QTAILQ_EMPTY(&image_entry->snapshots)) {
|
||||
continue;
|
||||
}
|
||||
monitor_printf(mon,
|
||||
"\nList of partial (non-loadable) snapshots on '%s':\n",
|
||||
image_entry->imagename);
|
||||
bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
|
||||
monitor_printf(mon, "\n");
|
||||
QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
|
||||
bdrv_snapshot_dump((fprintf_function)monitor_printf, mon,
|
||||
&snapshot_entry->sn);
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
|
||||
SnapshotEntry *next_sn;
|
||||
QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
|
||||
next_sn) {
|
||||
g_free(snapshot_entry);
|
||||
}
|
||||
g_free(image_entry);
|
||||
}
|
||||
g_free(sn_tab);
|
||||
g_free(global_snapshots);
|
||||
|
||||
}
|
||||
|
||||
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
qmp_migrate_cancel(NULL);
|
||||
@@ -1947,7 +2122,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
qmp_nbd_server_start(addr, false, NULL, &local_err);
|
||||
nbd_server_start(addr, NULL, &local_err);
|
||||
qapi_free_SocketAddress(addr);
|
||||
if (local_err != NULL) {
|
||||
goto exit;
|
||||
|
||||
4
hmp.h
4
hmp.h
@@ -63,6 +63,10 @@ void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict);
|
||||
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict);
|
||||
void hmp_drive_mirror(Monitor *mon, const QDict *qdict);
|
||||
void hmp_drive_backup(Monitor *mon, const QDict *qdict);
|
||||
void hmp_loadvm(Monitor *mon, const QDict *qdict);
|
||||
void hmp_savevm(Monitor *mon, const QDict *qdict);
|
||||
void hmp_delvm(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
|
||||
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
|
||||
void hmp_migrate_incoming(Monitor *mon, const QDict *qdict);
|
||||
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
|
||||
|
||||
@@ -14,5 +14,3 @@ common-obj-$(CONFIG_PL041) += pl041.o lm4549.o
|
||||
common-obj-$(CONFIG_CS4231) += cs4231.o
|
||||
common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o
|
||||
common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o
|
||||
|
||||
$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
|
||||
|
||||
@@ -33,11 +33,7 @@
|
||||
|
||||
#define ADLIB_KILL_TIMERS 1
|
||||
|
||||
#ifdef HAS_YMF262
|
||||
#define ADLIB_DESC "Yamaha YMF262 (OPL3)"
|
||||
#else
|
||||
#define ADLIB_DESC "Yamaha YM3812 (OPL2)"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "qemu/timer.h"
|
||||
@@ -50,14 +46,8 @@
|
||||
#define ldebug(...)
|
||||
#endif
|
||||
|
||||
#ifdef HAS_YMF262
|
||||
#include "ymf262.h"
|
||||
void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
|
||||
#define SHIFT 2
|
||||
#else
|
||||
#include "fmopl.h"
|
||||
#define SHIFT 1
|
||||
#endif
|
||||
|
||||
#define TYPE_ADLIB "adlib"
|
||||
#define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB)
|
||||
@@ -80,9 +70,7 @@ typedef struct {
|
||||
SWVoiceOut *voice;
|
||||
int left, pos, samples;
|
||||
QEMUAudioTimeStamp ats;
|
||||
#ifndef HAS_YMF262
|
||||
FM_OPL *opl;
|
||||
#endif
|
||||
PortioList port_list;
|
||||
} AdlibState;
|
||||
|
||||
@@ -90,11 +78,7 @@ static AdlibState *glob_adlib;
|
||||
|
||||
static void adlib_stop_opl_timer (AdlibState *s, size_t n)
|
||||
{
|
||||
#ifdef HAS_YMF262
|
||||
YMF262TimerOver (0, n);
|
||||
#else
|
||||
OPLTimerOver (s->opl, n);
|
||||
#endif
|
||||
s->ticking[n] = 0;
|
||||
}
|
||||
|
||||
@@ -131,11 +115,7 @@ static void adlib_write(void *opaque, uint32_t nport, uint32_t val)
|
||||
|
||||
adlib_kill_timers (s);
|
||||
|
||||
#ifdef HAS_YMF262
|
||||
YMF262Write (0, a, val);
|
||||
#else
|
||||
OPLWrite (s->opl, a, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t adlib_read(void *opaque, uint32_t nport)
|
||||
@@ -145,12 +125,8 @@ static uint32_t adlib_read(void *opaque, uint32_t nport)
|
||||
int a = nport & 3;
|
||||
|
||||
adlib_kill_timers (s);
|
||||
|
||||
#ifdef HAS_YMF262
|
||||
data = YMF262Read (0, a);
|
||||
#else
|
||||
data = OPLRead (s->opl, a);
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -240,11 +216,7 @@ static void adlib_callback (void *opaque, int free)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAS_YMF262
|
||||
YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
|
||||
#else
|
||||
YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
|
||||
#endif
|
||||
|
||||
while (samples) {
|
||||
written = write_audio (s, samples);
|
||||
@@ -263,14 +235,10 @@ static void adlib_callback (void *opaque, int free)
|
||||
|
||||
static void Adlib_fini (AdlibState *s)
|
||||
{
|
||||
#ifdef HAS_YMF262
|
||||
YMF262Shutdown ();
|
||||
#else
|
||||
if (s->opl) {
|
||||
OPLDestroy (s->opl);
|
||||
s->opl = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_free(s->mixbuf);
|
||||
|
||||
@@ -297,17 +265,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
|
||||
}
|
||||
glob_adlib = s;
|
||||
|
||||
#ifdef HAS_YMF262
|
||||
if (YMF262Init (1, 14318180, s->freq)) {
|
||||
error_setg (errp, "YMF262Init %d failed", s->freq);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
YMF262SetTimerHandler (0, timer_handler, 0);
|
||||
s->enabled = 1;
|
||||
}
|
||||
#else
|
||||
s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, s->freq);
|
||||
s->opl = OPLCreate (3579545, s->freq);
|
||||
if (!s->opl) {
|
||||
error_setg (errp, "OPLCreate %d failed", s->freq);
|
||||
return;
|
||||
@@ -316,7 +274,6 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
|
||||
OPLSetTimerHandler (s->opl, timer_handler, 0);
|
||||
s->enabled = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
as.freq = s->freq;
|
||||
as.nchannels = SHIFT;
|
||||
|
||||
277
hw/audio/fmopl.c
277
hw/audio/fmopl.c
@@ -30,21 +30,15 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define HAS_YM3812 1
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <math.h>
|
||||
//#include "driver.h" /* use M.A.M.E. */
|
||||
#include "fmopl.h"
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#ifndef PI
|
||||
#define PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
/* -------------------- for debug --------------------- */
|
||||
/* #define OPL_OUTPUT_LOG */
|
||||
#ifdef OPL_OUTPUT_LOG
|
||||
@@ -124,7 +118,7 @@ static const int slot_array[32]=
|
||||
/* key scale level */
|
||||
/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
|
||||
#define DV (EG_STEP/2)
|
||||
static const UINT32 KSL_TABLE[8*16]=
|
||||
static const uint32_t KSL_TABLE[8*16]=
|
||||
{
|
||||
/* OCT 0 */
|
||||
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
|
||||
@@ -172,7 +166,7 @@ static const UINT32 KSL_TABLE[8*16]=
|
||||
/* sustain lebel table (3db per step) */
|
||||
/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
|
||||
#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
|
||||
static const INT32 SL_TABLE[16]={
|
||||
static const int32_t SL_TABLE[16]={
|
||||
SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
|
||||
SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
|
||||
};
|
||||
@@ -182,22 +176,22 @@ static const INT32 SL_TABLE[16]={
|
||||
/* TotalLevel : 48 24 12 6 3 1.5 0.75 (dB) */
|
||||
/* TL_TABLE[ 0 to TL_MAX ] : plus section */
|
||||
/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
|
||||
static INT32 *TL_TABLE;
|
||||
static int32_t *TL_TABLE;
|
||||
|
||||
/* pointers to TL_TABLE with sinwave output offset */
|
||||
static INT32 **SIN_TABLE;
|
||||
static int32_t **SIN_TABLE;
|
||||
|
||||
/* LFO table */
|
||||
static INT32 *AMS_TABLE;
|
||||
static INT32 *VIB_TABLE;
|
||||
static int32_t *AMS_TABLE;
|
||||
static int32_t *VIB_TABLE;
|
||||
|
||||
/* envelope output curve table */
|
||||
/* attack + decay + OFF */
|
||||
static INT32 ENV_CURVE[2*EG_ENT+1];
|
||||
static int32_t ENV_CURVE[2*EG_ENT+1];
|
||||
|
||||
/* multiple table */
|
||||
#define ML 2
|
||||
static const UINT32 MUL_TABLE[16]= {
|
||||
static const uint32_t MUL_TABLE[16]= {
|
||||
/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
|
||||
0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
|
||||
8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
|
||||
@@ -205,7 +199,7 @@ static const UINT32 MUL_TABLE[16]= {
|
||||
#undef ML
|
||||
|
||||
/* dummy attack / decay rate ( when rate == 0 ) */
|
||||
static INT32 RATE_0[16]=
|
||||
static int32_t RATE_0[16]=
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
/* -------------------- static state --------------------- */
|
||||
@@ -221,14 +215,14 @@ static OPL_CH *S_CH;
|
||||
static OPL_CH *E_CH;
|
||||
static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2;
|
||||
|
||||
static INT32 outd[1];
|
||||
static INT32 ams;
|
||||
static INT32 vib;
|
||||
static INT32 *ams_table;
|
||||
static INT32 *vib_table;
|
||||
static INT32 amsIncr;
|
||||
static INT32 vibIncr;
|
||||
static INT32 feedback2; /* connect for SLOT 2 */
|
||||
static int32_t outd[1];
|
||||
static int32_t ams;
|
||||
static int32_t vib;
|
||||
static int32_t *ams_table;
|
||||
static int32_t *vib_table;
|
||||
static int32_t amsIncr;
|
||||
static int32_t vibIncr;
|
||||
static int32_t feedback2; /* connect for SLOT 2 */
|
||||
|
||||
/* log output level */
|
||||
#define LOG_ERR 3 /* ERROR */
|
||||
@@ -262,8 +256,6 @@ static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag)
|
||||
if(OPL->status & OPL->statusmask)
|
||||
{ /* IRQ on */
|
||||
OPL->status |= 0x80;
|
||||
/* callback user interrupt handler (IRQ is OFF to ON) */
|
||||
if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,8 +270,6 @@ static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
|
||||
if (!(OPL->status & OPL->statusmask) )
|
||||
{
|
||||
OPL->status &= 0x7f;
|
||||
/* callback user interrupt handler (IRQ is ON to OFF) */
|
||||
if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,7 +311,7 @@ static inline void OPL_KEYOFF(OPL_SLOT *SLOT)
|
||||
|
||||
/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
|
||||
/* return : envelope output */
|
||||
static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
|
||||
static inline uint32_t OPL_CALC_SLOT( OPL_SLOT *SLOT )
|
||||
{
|
||||
/* calcrate envelope generator */
|
||||
if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
|
||||
@@ -361,7 +351,7 @@ static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
|
||||
/* set algorithm connection */
|
||||
static void set_algorithm( OPL_CH *CH)
|
||||
{
|
||||
INT32 *carrier = &outd[0];
|
||||
int32_t *carrier = &outd[0];
|
||||
CH->connect1 = CH->CON ? carrier : &feedback2;
|
||||
CH->connect2 = carrier;
|
||||
}
|
||||
@@ -453,7 +443,7 @@ static inline void set_sl_rr(FM_OPL *OPL,int slot,int v)
|
||||
/* ---------- calcrate one of channel ---------- */
|
||||
static inline void OPL_CALC_CH( OPL_CH *CH )
|
||||
{
|
||||
UINT32 env_out;
|
||||
uint32_t env_out;
|
||||
OPL_SLOT *SLOT;
|
||||
|
||||
feedback2 = 0;
|
||||
@@ -498,9 +488,9 @@ static inline void OPL_CALC_CH( OPL_CH *CH )
|
||||
#define WHITE_NOISE_db 6.0
|
||||
static inline void OPL_CALC_RH( OPL_CH *CH )
|
||||
{
|
||||
UINT32 env_tam,env_sd,env_top,env_hh;
|
||||
uint32_t env_tam,env_sd,env_top,env_hh;
|
||||
int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
|
||||
INT32 tone8;
|
||||
int32_t tone8;
|
||||
|
||||
OPL_SLOT *SLOT;
|
||||
int env_out;
|
||||
@@ -618,20 +608,20 @@ static int OPLOpenTable( void )
|
||||
double pom;
|
||||
|
||||
/* allocate dynamic tables */
|
||||
if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
|
||||
if( (TL_TABLE = malloc(TL_MAX*2*sizeof(int32_t))) == NULL)
|
||||
return 0;
|
||||
if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
|
||||
if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(int32_t *))) == NULL)
|
||||
{
|
||||
free(TL_TABLE);
|
||||
return 0;
|
||||
}
|
||||
if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
|
||||
if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(int32_t))) == NULL)
|
||||
{
|
||||
free(TL_TABLE);
|
||||
free(SIN_TABLE);
|
||||
return 0;
|
||||
}
|
||||
if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
|
||||
if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(int32_t))) == NULL)
|
||||
{
|
||||
free(TL_TABLE);
|
||||
free(SIN_TABLE);
|
||||
@@ -763,18 +753,15 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
||||
{
|
||||
case 0x01:
|
||||
/* wave selector enable */
|
||||
if(OPL->type&OPL_TYPE_WAVESEL)
|
||||
OPL->wavesel = v&0x20;
|
||||
if(!OPL->wavesel)
|
||||
{
|
||||
OPL->wavesel = v&0x20;
|
||||
if(!OPL->wavesel)
|
||||
/* preset compatible mode */
|
||||
int c;
|
||||
for(c=0;c<OPL->max_ch;c++)
|
||||
{
|
||||
/* preset compatible mode */
|
||||
int c;
|
||||
for(c=0;c<OPL->max_ch;c++)
|
||||
{
|
||||
OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
|
||||
OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
|
||||
}
|
||||
OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
|
||||
OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -791,8 +778,8 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
||||
}
|
||||
else
|
||||
{ /* set IRQ mask ,timer enable*/
|
||||
UINT8 st1 = v&1;
|
||||
UINT8 st2 = (v>>1)&1;
|
||||
uint8_t st1 = v&1;
|
||||
uint8_t st2 = (v>>1)&1;
|
||||
/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
|
||||
OPL_STATUS_RESET(OPL,v&0x78);
|
||||
OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
|
||||
@@ -812,57 +799,6 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
||||
}
|
||||
}
|
||||
return;
|
||||
#if BUILD_Y8950
|
||||
case 0x06: /* Key Board OUT */
|
||||
if(OPL->type&OPL_TYPE_KEYBOARD)
|
||||
{
|
||||
if(OPL->keyboardhandler_w)
|
||||
OPL->keyboardhandler_w(OPL->keyboard_param,v);
|
||||
else
|
||||
LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
|
||||
}
|
||||
return;
|
||||
case 0x07: /* DELTA-T control : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
|
||||
if(OPL->type&OPL_TYPE_ADPCM)
|
||||
YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
|
||||
return;
|
||||
case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
|
||||
OPL->mode = v;
|
||||
v&=0x1f; /* for DELTA-T unit */
|
||||
case 0x09: /* START ADD */
|
||||
case 0x0a:
|
||||
case 0x0b: /* STOP ADD */
|
||||
case 0x0c:
|
||||
case 0x0d: /* PRESCALE */
|
||||
case 0x0e:
|
||||
case 0x0f: /* ADPCM data */
|
||||
case 0x10: /* DELTA-N */
|
||||
case 0x11: /* DELTA-N */
|
||||
case 0x12: /* EG-CTRL */
|
||||
if(OPL->type&OPL_TYPE_ADPCM)
|
||||
YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
|
||||
return;
|
||||
#if 0
|
||||
case 0x15: /* DAC data */
|
||||
case 0x16:
|
||||
case 0x17: /* SHIFT */
|
||||
return;
|
||||
case 0x18: /* I/O CTRL (Direction) */
|
||||
if(OPL->type&OPL_TYPE_IO)
|
||||
OPL->portDirection = v&0x0f;
|
||||
return;
|
||||
case 0x19: /* I/O DATA */
|
||||
if(OPL->type&OPL_TYPE_IO)
|
||||
{
|
||||
OPL->portLatch = v;
|
||||
if(OPL->porthandler_w)
|
||||
OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
|
||||
}
|
||||
return;
|
||||
case 0x1a: /* PCM data */
|
||||
return;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 0x20: /* am,vib,ksr,eg type,mul */
|
||||
@@ -891,7 +827,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
||||
case 0xbd:
|
||||
/* amsep,vibdep,r,bd,sd,tom,tc,hh */
|
||||
{
|
||||
UINT8 rkey = OPL->rhythm^v;
|
||||
uint8_t rkey = OPL->rhythm^v;
|
||||
OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
|
||||
OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
|
||||
OPL->rhythm = v&0x3f;
|
||||
@@ -1032,20 +968,19 @@ static void OPL_UnLockTable(void)
|
||||
OPLCloseTable();
|
||||
}
|
||||
|
||||
#if (BUILD_YM3812 || BUILD_YM3526)
|
||||
/*******************************************************************************/
|
||||
/* YM3812 local section */
|
||||
/*******************************************************************************/
|
||||
|
||||
/* ---------- update one of chip ----------- */
|
||||
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
|
||||
void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length)
|
||||
{
|
||||
int i;
|
||||
int data;
|
||||
OPLSAMPLE *buf = buffer;
|
||||
UINT32 amsCnt = OPL->amsCnt;
|
||||
UINT32 vibCnt = OPL->vibCnt;
|
||||
UINT8 rhythm = OPL->rhythm&0x20;
|
||||
int16_t *buf = buffer;
|
||||
uint32_t amsCnt = OPL->amsCnt;
|
||||
uint32_t vibCnt = OPL->vibCnt;
|
||||
uint8_t rhythm = OPL->rhythm&0x20;
|
||||
OPL_CH *CH,*R_CH;
|
||||
|
||||
if( (void *)OPL != cur_chip ){
|
||||
@@ -1095,72 +1030,9 @@ void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* (BUILD_YM3812 || BUILD_YM3526) */
|
||||
|
||||
#if BUILD_Y8950
|
||||
|
||||
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
|
||||
{
|
||||
int i;
|
||||
int data;
|
||||
OPLSAMPLE *buf = buffer;
|
||||
UINT32 amsCnt = OPL->amsCnt;
|
||||
UINT32 vibCnt = OPL->vibCnt;
|
||||
UINT8 rhythm = OPL->rhythm&0x20;
|
||||
OPL_CH *CH,*R_CH;
|
||||
YM_DELTAT *DELTAT = OPL->deltat;
|
||||
|
||||
/* setup DELTA-T unit */
|
||||
YM_DELTAT_DECODE_PRESET(DELTAT);
|
||||
|
||||
if( (void *)OPL != cur_chip ){
|
||||
cur_chip = (void *)OPL;
|
||||
/* channel pointers */
|
||||
S_CH = OPL->P_CH;
|
||||
E_CH = &S_CH[9];
|
||||
/* rhythm slot */
|
||||
SLOT7_1 = &S_CH[7].SLOT[SLOT1];
|
||||
SLOT7_2 = &S_CH[7].SLOT[SLOT2];
|
||||
SLOT8_1 = &S_CH[8].SLOT[SLOT1];
|
||||
SLOT8_2 = &S_CH[8].SLOT[SLOT2];
|
||||
/* LFO state */
|
||||
amsIncr = OPL->amsIncr;
|
||||
vibIncr = OPL->vibIncr;
|
||||
ams_table = OPL->ams_table;
|
||||
vib_table = OPL->vib_table;
|
||||
}
|
||||
R_CH = rhythm ? &S_CH[6] : E_CH;
|
||||
for( i=0; i < length ; i++ )
|
||||
{
|
||||
/* channel A channel B channel C */
|
||||
/* LFO */
|
||||
ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
|
||||
vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
|
||||
outd[0] = 0;
|
||||
/* deltaT ADPCM */
|
||||
if( DELTAT->portstate )
|
||||
YM_DELTAT_ADPCM_CALC(DELTAT);
|
||||
/* FM part */
|
||||
for(CH=S_CH ; CH < R_CH ; CH++)
|
||||
OPL_CALC_CH(CH);
|
||||
/* Rythn part */
|
||||
if(rhythm)
|
||||
OPL_CALC_RH(S_CH);
|
||||
/* limit check */
|
||||
data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
|
||||
/* store to sound buffer */
|
||||
buf[i] = data >> OPL_OUTSB;
|
||||
}
|
||||
OPL->amsCnt = amsCnt;
|
||||
OPL->vibCnt = vibCnt;
|
||||
/* deltaT START flag */
|
||||
if( !DELTAT->portstate )
|
||||
OPL->status &= 0xfe;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---------- reset one of chip ---------- */
|
||||
void OPLResetChip(FM_OPL *OPL)
|
||||
static void OPLResetChip(FM_OPL *OPL)
|
||||
{
|
||||
int c,s;
|
||||
int i;
|
||||
@@ -1189,23 +1061,11 @@ void OPLResetChip(FM_OPL *OPL)
|
||||
CH->SLOT[s].evs = 0;
|
||||
}
|
||||
}
|
||||
#if BUILD_Y8950
|
||||
if(OPL->type&OPL_TYPE_ADPCM)
|
||||
{
|
||||
YM_DELTAT *DELTAT = OPL->deltat;
|
||||
|
||||
DELTAT->freqbase = OPL->freqbase;
|
||||
DELTAT->output_pointer = outd;
|
||||
DELTAT->portshift = 5;
|
||||
DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
|
||||
YM_DELTAT_ADPCM_Reset(DELTAT,0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---------- Create one of vietual YM3812 ---------- */
|
||||
/* 'rate' is sampling rate and 'bufsiz' is the size of the */
|
||||
FM_OPL *OPLCreate(int type, int clock, int rate)
|
||||
FM_OPL *OPLCreate(int clock, int rate)
|
||||
{
|
||||
char *ptr;
|
||||
FM_OPL *OPL;
|
||||
@@ -1216,9 +1076,6 @@ FM_OPL *OPLCreate(int type, int clock, int rate)
|
||||
/* allocate OPL state space */
|
||||
state_size = sizeof(FM_OPL);
|
||||
state_size += sizeof(OPL_CH)*max_ch;
|
||||
#if BUILD_Y8950
|
||||
if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
|
||||
#endif
|
||||
/* allocate memory block */
|
||||
ptr = malloc(state_size);
|
||||
if(ptr==NULL) return NULL;
|
||||
@@ -1226,11 +1083,7 @@ FM_OPL *OPLCreate(int type, int clock, int rate)
|
||||
memset(ptr,0,state_size);
|
||||
OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
|
||||
OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
|
||||
#if BUILD_Y8950
|
||||
if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
|
||||
#endif
|
||||
/* set channel state pointer */
|
||||
OPL->type = type;
|
||||
OPL->clock = clock;
|
||||
OPL->rate = rate;
|
||||
OPL->max_ch = max_ch;
|
||||
@@ -1280,31 +1133,7 @@ void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOff
|
||||
OPL->TimerHandler = TimerHandler;
|
||||
OPL->TimerParam = channelOffset;
|
||||
}
|
||||
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
|
||||
{
|
||||
OPL->IRQHandler = IRQHandler;
|
||||
OPL->IRQParam = param;
|
||||
}
|
||||
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
|
||||
{
|
||||
OPL->UpdateHandler = UpdateHandler;
|
||||
OPL->UpdateParam = param;
|
||||
}
|
||||
#if BUILD_Y8950
|
||||
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
|
||||
{
|
||||
OPL->porthandler_w = PortHandler_w;
|
||||
OPL->porthandler_r = PortHandler_r;
|
||||
OPL->port_param = param;
|
||||
}
|
||||
|
||||
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
|
||||
{
|
||||
OPL->keyboardhandler_w = KeyboardHandler_w;
|
||||
OPL->keyboardhandler_r = KeyboardHandler_r;
|
||||
OPL->keyboard_param = param;
|
||||
}
|
||||
#endif
|
||||
/* ---------- YM3812 I/O interface ---------- */
|
||||
int OPLWrite(FM_OPL *OPL,int a,int v)
|
||||
{
|
||||
@@ -1314,7 +1143,6 @@ int OPLWrite(FM_OPL *OPL,int a,int v)
|
||||
}
|
||||
else
|
||||
{ /* data port */
|
||||
if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
|
||||
#ifdef OPL_OUTPUT_LOG
|
||||
if(opl_dbg_fp)
|
||||
{
|
||||
@@ -1338,28 +1166,12 @@ unsigned char OPLRead(FM_OPL *OPL,int a)
|
||||
switch(OPL->address)
|
||||
{
|
||||
case 0x05: /* KeyBoard IN */
|
||||
if(OPL->type&OPL_TYPE_KEYBOARD)
|
||||
{
|
||||
if(OPL->keyboardhandler_r)
|
||||
return OPL->keyboardhandler_r(OPL->keyboard_param);
|
||||
else {
|
||||
LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#if 0
|
||||
case 0x0f: /* ADPCM-DATA */
|
||||
return 0;
|
||||
#endif
|
||||
case 0x19: /* I/O DATA */
|
||||
if(OPL->type&OPL_TYPE_IO)
|
||||
{
|
||||
if(OPL->porthandler_r)
|
||||
return OPL->porthandler_r(OPL->port_param);
|
||||
else {
|
||||
LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case 0x1a: /* PCM-DATA */
|
||||
return 0;
|
||||
@@ -1380,7 +1192,6 @@ int OPLTimerOver(FM_OPL *OPL,int c)
|
||||
if( OPL->mode & 0x80 )
|
||||
{ /* CSM mode total level latch and auto key on */
|
||||
int ch;
|
||||
if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
|
||||
for(ch=0;ch<9;ch++)
|
||||
CSMKeyControll( &OPL->P_CH[ch] );
|
||||
}
|
||||
|
||||
175
hw/audio/fmopl.h
175
hw/audio/fmopl.h
@@ -1,174 +1,103 @@
|
||||
#ifndef FMOPL_H
|
||||
#define FMOPL_H
|
||||
|
||||
/* --- select emulation chips --- */
|
||||
#define BUILD_YM3812 (HAS_YM3812)
|
||||
//#define BUILD_YM3526 (HAS_YM3526)
|
||||
//#define BUILD_Y8950 (HAS_Y8950)
|
||||
|
||||
/* --- system optimize --- */
|
||||
/* select bit size of output : 8 or 16 */
|
||||
#define OPL_OUTPUT_BIT 16
|
||||
|
||||
/* compiler dependence */
|
||||
#ifndef OSD_CPU_H
|
||||
#define OSD_CPU_H
|
||||
typedef unsigned char UINT8; /* unsigned 8bit */
|
||||
typedef unsigned short UINT16; /* unsigned 16bit */
|
||||
typedef unsigned int UINT32; /* unsigned 32bit */
|
||||
typedef signed char INT8; /* signed 8bit */
|
||||
typedef signed short INT16; /* signed 16bit */
|
||||
typedef signed int INT32; /* signed 32bit */
|
||||
#endif
|
||||
|
||||
#if (OPL_OUTPUT_BIT==16)
|
||||
typedef INT16 OPLSAMPLE;
|
||||
#endif
|
||||
#if (OPL_OUTPUT_BIT==8)
|
||||
typedef unsigned char OPLSAMPLE;
|
||||
#endif
|
||||
|
||||
|
||||
#if BUILD_Y8950
|
||||
#include "ymdeltat.h"
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
|
||||
typedef void (*OPL_IRQHANDLER)(int param,int irq);
|
||||
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
|
||||
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
|
||||
typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
|
||||
|
||||
/* !!!!! here is private section , do not access there member direct !!!!! */
|
||||
|
||||
#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
|
||||
#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
|
||||
#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
|
||||
#define OPL_TYPE_IO 0x08 /* I/O port */
|
||||
|
||||
/* Saving is necessary for member of the 'R' mark for suspend/resume */
|
||||
/* ---------- OPL one of slot ---------- */
|
||||
typedef struct fm_opl_slot {
|
||||
INT32 TL; /* total level :TL << 8 */
|
||||
INT32 TLL; /* adjusted now TL */
|
||||
UINT8 KSR; /* key scale rate :(shift down bit) */
|
||||
INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
|
||||
INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
|
||||
INT32 SL; /* sustin level :SL_TALBE[SL] */
|
||||
INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
|
||||
UINT8 ksl; /* keyscale level :(shift down bits) */
|
||||
UINT8 ksr; /* key scale rate :kcode>>KSR */
|
||||
UINT32 mul; /* multiple :ML_TABLE[ML] */
|
||||
UINT32 Cnt; /* frequency count : */
|
||||
UINT32 Incr; /* frequency step : */
|
||||
int32_t TL; /* total level :TL << 8 */
|
||||
int32_t TLL; /* adjusted now TL */
|
||||
uint8_t KSR; /* key scale rate :(shift down bit) */
|
||||
int32_t *AR; /* attack rate :&AR_TABLE[AR<<2] */
|
||||
int32_t *DR; /* decay rate :&DR_TALBE[DR<<2] */
|
||||
int32_t SL; /* sustin level :SL_TALBE[SL] */
|
||||
int32_t *RR; /* release rate :&DR_TABLE[RR<<2] */
|
||||
uint8_t ksl; /* keyscale level :(shift down bits) */
|
||||
uint8_t ksr; /* key scale rate :kcode>>KSR */
|
||||
uint32_t mul; /* multiple :ML_TABLE[ML] */
|
||||
uint32_t Cnt; /* frequency count : */
|
||||
uint32_t Incr; /* frequency step : */
|
||||
/* envelope generator state */
|
||||
UINT8 eg_typ; /* envelope type flag */
|
||||
UINT8 evm; /* envelope phase */
|
||||
INT32 evc; /* envelope counter */
|
||||
INT32 eve; /* envelope counter end point */
|
||||
INT32 evs; /* envelope counter step */
|
||||
INT32 evsa; /* envelope step for AR :AR[ksr] */
|
||||
INT32 evsd; /* envelope step for DR :DR[ksr] */
|
||||
INT32 evsr; /* envelope step for RR :RR[ksr] */
|
||||
uint8_t eg_typ; /* envelope type flag */
|
||||
uint8_t evm; /* envelope phase */
|
||||
int32_t evc; /* envelope counter */
|
||||
int32_t eve; /* envelope counter end point */
|
||||
int32_t evs; /* envelope counter step */
|
||||
int32_t evsa; /* envelope step for AR :AR[ksr] */
|
||||
int32_t evsd; /* envelope step for DR :DR[ksr] */
|
||||
int32_t evsr; /* envelope step for RR :RR[ksr] */
|
||||
/* LFO */
|
||||
UINT8 ams; /* ams flag */
|
||||
UINT8 vib; /* vibrate flag */
|
||||
uint8_t ams; /* ams flag */
|
||||
uint8_t vib; /* vibrate flag */
|
||||
/* wave selector */
|
||||
INT32 **wavetable;
|
||||
int32_t **wavetable;
|
||||
}OPL_SLOT;
|
||||
|
||||
/* ---------- OPL one of channel ---------- */
|
||||
typedef struct fm_opl_channel {
|
||||
OPL_SLOT SLOT[2];
|
||||
UINT8 CON; /* connection type */
|
||||
UINT8 FB; /* feed back :(shift down bit) */
|
||||
INT32 *connect1; /* slot1 output pointer */
|
||||
INT32 *connect2; /* slot2 output pointer */
|
||||
INT32 op1_out[2]; /* slot1 output for selfeedback */
|
||||
uint8_t CON; /* connection type */
|
||||
uint8_t FB; /* feed back :(shift down bit) */
|
||||
int32_t *connect1; /* slot1 output pointer */
|
||||
int32_t *connect2; /* slot2 output pointer */
|
||||
int32_t op1_out[2]; /* slot1 output for selfeedback */
|
||||
/* phase generator state */
|
||||
UINT32 block_fnum; /* block+fnum : */
|
||||
UINT8 kcode; /* key code : KeyScaleCode */
|
||||
UINT32 fc; /* Freq. Increment base */
|
||||
UINT32 ksl_base; /* KeyScaleLevel Base step */
|
||||
UINT8 keyon; /* key on/off flag */
|
||||
uint32_t block_fnum; /* block+fnum : */
|
||||
uint8_t kcode; /* key code : KeyScaleCode */
|
||||
uint32_t fc; /* Freq. Increment base */
|
||||
uint32_t ksl_base; /* KeyScaleLevel Base step */
|
||||
uint8_t keyon; /* key on/off flag */
|
||||
} OPL_CH;
|
||||
|
||||
/* OPL state */
|
||||
typedef struct fm_opl_f {
|
||||
UINT8 type; /* chip type */
|
||||
int clock; /* master clock (Hz) */
|
||||
int rate; /* sampling rate (Hz) */
|
||||
double freqbase; /* frequency base */
|
||||
double TimerBase; /* Timer base time (==sampling time) */
|
||||
UINT8 address; /* address register */
|
||||
UINT8 status; /* status flag */
|
||||
UINT8 statusmask; /* status mask */
|
||||
UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
|
||||
uint8_t address; /* address register */
|
||||
uint8_t status; /* status flag */
|
||||
uint8_t statusmask; /* status mask */
|
||||
uint32_t mode; /* Reg.08 : CSM , notesel,etc. */
|
||||
/* Timer */
|
||||
int T[2]; /* timer counter */
|
||||
UINT8 st[2]; /* timer enable */
|
||||
uint8_t st[2]; /* timer enable */
|
||||
/* FM channel slots */
|
||||
OPL_CH *P_CH; /* pointer of CH */
|
||||
int max_ch; /* maximum channel */
|
||||
/* Rhythm sention */
|
||||
UINT8 rhythm; /* Rhythm mode , key flag */
|
||||
#if BUILD_Y8950
|
||||
/* Delta-T ADPCM unit (Y8950) */
|
||||
YM_DELTAT *deltat; /* DELTA-T ADPCM */
|
||||
#endif
|
||||
/* Keyboard / I/O interface unit (Y8950) */
|
||||
UINT8 portDirection;
|
||||
UINT8 portLatch;
|
||||
OPL_PORTHANDLER_R porthandler_r;
|
||||
OPL_PORTHANDLER_W porthandler_w;
|
||||
int port_param;
|
||||
OPL_PORTHANDLER_R keyboardhandler_r;
|
||||
OPL_PORTHANDLER_W keyboardhandler_w;
|
||||
int keyboard_param;
|
||||
uint8_t rhythm; /* Rhythm mode , key flag */
|
||||
/* time tables */
|
||||
INT32 AR_TABLE[75]; /* atttack rate tables */
|
||||
INT32 DR_TABLE[75]; /* decay rate tables */
|
||||
UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
|
||||
int32_t AR_TABLE[75]; /* atttack rate tables */
|
||||
int32_t DR_TABLE[75]; /* decay rate tables */
|
||||
uint32_t FN_TABLE[1024]; /* fnumber -> increment counter */
|
||||
/* LFO */
|
||||
INT32 *ams_table;
|
||||
INT32 *vib_table;
|
||||
INT32 amsCnt;
|
||||
INT32 amsIncr;
|
||||
INT32 vibCnt;
|
||||
INT32 vibIncr;
|
||||
int32_t *ams_table;
|
||||
int32_t *vib_table;
|
||||
int32_t amsCnt;
|
||||
int32_t amsIncr;
|
||||
int32_t vibCnt;
|
||||
int32_t vibIncr;
|
||||
/* wave selector enable flag */
|
||||
UINT8 wavesel;
|
||||
uint8_t wavesel;
|
||||
/* external event callback handler */
|
||||
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
|
||||
int TimerParam; /* TIMER parameter */
|
||||
OPL_IRQHANDLER IRQHandler; /* IRQ handler */
|
||||
int IRQParam; /* IRQ parameter */
|
||||
OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
|
||||
int UpdateParam; /* stream update parameter */
|
||||
} FM_OPL;
|
||||
|
||||
/* ---------- Generic interface section ---------- */
|
||||
#define OPL_TYPE_YM3526 (0)
|
||||
#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
|
||||
#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
|
||||
|
||||
FM_OPL *OPLCreate(int type, int clock, int rate);
|
||||
FM_OPL *OPLCreate(int clock, int rate);
|
||||
void OPLDestroy(FM_OPL *OPL);
|
||||
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
|
||||
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
|
||||
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
|
||||
/* Y8950 port handlers */
|
||||
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
|
||||
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
|
||||
|
||||
void OPLResetChip(FM_OPL *OPL);
|
||||
int OPLWrite(FM_OPL *OPL,int a,int v);
|
||||
unsigned char OPLRead(FM_OPL *OPL,int a);
|
||||
int OPLTimerOver(FM_OPL *OPL,int c);
|
||||
|
||||
/* YM3626/YM3812 local section */
|
||||
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
|
||||
|
||||
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
|
||||
|
||||
void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length);
|
||||
#endif
|
||||
|
||||
@@ -53,7 +53,7 @@ typedef struct GUSState {
|
||||
uint32_t freq;
|
||||
uint32_t port;
|
||||
int pos, left, shift, irqs;
|
||||
GUSsample *mixbuf;
|
||||
int16_t *mixbuf;
|
||||
uint8_t himem[1024 * 1024 + 32 + 4096];
|
||||
int samples;
|
||||
SWVoiceOut *voice;
|
||||
|
||||
@@ -25,26 +25,10 @@
|
||||
#ifndef GUSEMU_H
|
||||
#define GUSEMU_H
|
||||
|
||||
/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
|
||||
|
||||
#if defined _WIN32 && defined _MSC_VER /* doesn't support other win32 compilers yet, do it yourself... */
|
||||
typedef unsigned char GUSbyte;
|
||||
typedef unsigned short GUSword;
|
||||
typedef unsigned int GUSdword;
|
||||
typedef signed char GUSchar;
|
||||
typedef signed short GUSsample;
|
||||
#else
|
||||
typedef int8_t GUSchar;
|
||||
typedef uint8_t GUSbyte;
|
||||
typedef uint16_t GUSword;
|
||||
typedef uint32_t GUSdword;
|
||||
typedef int16_t GUSsample;
|
||||
#endif
|
||||
|
||||
typedef struct _GUSEmuState
|
||||
{
|
||||
GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
|
||||
GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
|
||||
uint8_t *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
|
||||
uint8_t *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
|
||||
uint32_t gusirq;
|
||||
uint32_t gusdma;
|
||||
unsigned int timer1fraction;
|
||||
@@ -92,7 +76,7 @@ void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count
|
||||
/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
|
||||
/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
|
||||
|
||||
void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos);
|
||||
void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, int16_t *bufferpos);
|
||||
/* recommended range: 10 < numsamples < 100 */
|
||||
/* lower values may result in increased rounding error, higher values often cause audible timing delays */
|
||||
|
||||
|
||||
@@ -31,15 +31,15 @@
|
||||
#include "gusemu.h"
|
||||
|
||||
#define GUSregb(position) (* (gusptr+(position)))
|
||||
#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
|
||||
#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
|
||||
#define GUSregw(position) (*(uint16_t *) (gusptr+(position)))
|
||||
#define GUSregd(position) (*(uint16_t *)(gusptr+(position)))
|
||||
|
||||
/* size given in bytes */
|
||||
unsigned int gus_read(GUSEmuState * state, int port, int size)
|
||||
{
|
||||
int value_read = 0;
|
||||
|
||||
GUSbyte *gusptr;
|
||||
uint8_t *gusptr;
|
||||
gusptr = state->gusdatapos;
|
||||
GUSregd(portaccesses)++;
|
||||
|
||||
@@ -125,7 +125,7 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
|
||||
if (!GUSregb(IRQStatReg2x6))
|
||||
GUS_irqclear(state, state->gusirq);
|
||||
}
|
||||
return (GUSbyte) value_read;
|
||||
return (uint8_t) value_read;
|
||||
/* DramDMAmemPosReg */
|
||||
/* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
|
||||
/* 43h+44h write only */
|
||||
@@ -173,12 +173,12 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
|
||||
value_read = value_read >> 8;
|
||||
value_read &= 0xff;
|
||||
}
|
||||
return (GUSword) value_read;
|
||||
return (uint16_t) value_read;
|
||||
/* case 0x306: */ /* Mixer/Version info */
|
||||
/* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
|
||||
case 0x307: /* DRAMaccess */
|
||||
{
|
||||
GUSbyte *adr;
|
||||
uint8_t *adr;
|
||||
adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
|
||||
return *adr;
|
||||
}
|
||||
@@ -189,14 +189,14 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
|
||||
|
||||
void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
{
|
||||
GUSbyte *gusptr;
|
||||
uint8_t *gusptr;
|
||||
gusptr = state->gusdatapos;
|
||||
GUSregd(portaccesses)++;
|
||||
|
||||
switch (port & 0xff0f)
|
||||
{
|
||||
case 0x200: /* MixerCtrlReg */
|
||||
GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
|
||||
GUSregb(MixerCtrlReg2x0) = (uint8_t) data;
|
||||
break;
|
||||
case 0x206: /* IRQstatReg / SB2x6IRQ */
|
||||
if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
|
||||
@@ -208,7 +208,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
break;
|
||||
case 0x308: /* AdLib 388h */
|
||||
case 0x208: /* AdLibCommandReg */
|
||||
GUSregb(AdLibCommand2xA) = (GUSbyte) data;
|
||||
GUSregb(AdLibCommand2xA) = (uint8_t) data;
|
||||
break;
|
||||
case 0x309: /* AdLib 389h */
|
||||
case 0x209: /* AdLibDataReg */
|
||||
@@ -217,11 +217,11 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
if (data & 0x80)
|
||||
GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
|
||||
else
|
||||
GUSregb(TimerDataReg2x9) = (GUSbyte) data;
|
||||
GUSregb(TimerDataReg2x9) = (uint8_t) data;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUSregb(AdLibData2x9) = (GUSbyte) data;
|
||||
GUSregb(AdLibData2x9) = (uint8_t) data;
|
||||
if (GUSregb(GUS45TimerCtrl) & 0x02)
|
||||
{
|
||||
GUSregb(TimerStatus2x8) |= 0x01;
|
||||
@@ -231,16 +231,16 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
}
|
||||
break;
|
||||
case 0x20A:
|
||||
GUSregb(AdLibStatus2x8) = (GUSbyte) data;
|
||||
GUSregb(AdLibStatus2x8) = (uint8_t) data;
|
||||
break; /* AdLibStatus2x8 */
|
||||
case 0x20B: /* GUS hidden registers */
|
||||
switch (GUSregb(RegCtrl_2xF) & 0x7)
|
||||
{
|
||||
case 0:
|
||||
if (GUSregb(MixerCtrlReg2x0) & 0x40)
|
||||
GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
|
||||
GUSregb(IRQ_2xB) = (uint8_t) data; /* control register select bit */
|
||||
else
|
||||
GUSregb(DMA_2xB) = (GUSbyte) data;
|
||||
GUSregb(DMA_2xB) = (uint8_t) data;
|
||||
break;
|
||||
/* case 1-4: general purpose emulation regs */
|
||||
case 5: /* clear stat reg 2xF */
|
||||
@@ -249,7 +249,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
GUS_irqclear(state, state->gusirq);
|
||||
break;
|
||||
case 6: /* Jumper reg (Joystick/MIDI enable) */
|
||||
GUSregb(Jumper_2xB) = (GUSbyte) data;
|
||||
GUSregb(Jumper_2xB) = (uint8_t) data;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
@@ -262,20 +262,20 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
GUS_irqrequest(state, state->gusirq, 1);
|
||||
}
|
||||
case 0x20D: /* SB2xCd no IRQ */
|
||||
GUSregb(SB2xCd) = (GUSbyte) data;
|
||||
GUSregb(SB2xCd) = (uint8_t) data;
|
||||
break;
|
||||
case 0x20E: /* SB2xE */
|
||||
GUSregb(SB2xE) = (GUSbyte) data;
|
||||
GUSregb(SB2xE) = (uint8_t) data;
|
||||
break;
|
||||
case 0x20F:
|
||||
GUSregb(RegCtrl_2xF) = (GUSbyte) data;
|
||||
GUSregb(RegCtrl_2xF) = (uint8_t) data;
|
||||
break; /* CtrlReg2xF */
|
||||
case 0x302: /* VoiceSelReg */
|
||||
GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
|
||||
GUSregb(VoiceSelReg3x2) = (uint8_t) data;
|
||||
break;
|
||||
case 0x303: /* FunkSelReg */
|
||||
GUSregb(FunkSelReg3x3) = (GUSbyte) data;
|
||||
if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
|
||||
GUSregb(FunkSelReg3x3) = (uint8_t) data;
|
||||
if ((uint8_t) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
|
||||
{
|
||||
int voice;
|
||||
if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
|
||||
@@ -318,15 +318,15 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
case 0x304:
|
||||
case 0x305:
|
||||
{
|
||||
GUSword writedata = (GUSword) data;
|
||||
GUSword readmask = 0x0000;
|
||||
uint16_t writedata = (uint16_t) data;
|
||||
uint16_t readmask = 0x0000;
|
||||
if (size == 1)
|
||||
{
|
||||
readmask = 0xff00;
|
||||
writedata &= 0xff;
|
||||
if ((port & 0xff0f) == 0x305)
|
||||
{
|
||||
writedata = (GUSword) (writedata << 8);
|
||||
writedata = (uint16_t) (writedata << 8);
|
||||
readmask = 0x00ff;
|
||||
}
|
||||
}
|
||||
@@ -353,17 +353,17 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
break; /* reset flag active? */
|
||||
offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
|
||||
offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
|
||||
GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
|
||||
GUSregw(offset) = (uint16_t) ((GUSregw(offset) & readmask) | writedata);
|
||||
}
|
||||
break;
|
||||
/* voice unspecific functions */
|
||||
case 0x0e: /* NumVoices */
|
||||
GUSregb(NumVoices) = (GUSbyte) data;
|
||||
GUSregb(NumVoices) = (uint8_t) data;
|
||||
break;
|
||||
/* case 0x0f: */ /* read only */
|
||||
/* common functions */
|
||||
case 0x41: /* DramDMAContrReg */
|
||||
GUSregb(GUS41DMACtrl) = (GUSbyte) data;
|
||||
GUSregb(GUS41DMACtrl) = (uint8_t) data;
|
||||
if (data & 0x01)
|
||||
GUS_dmarequest(state);
|
||||
break;
|
||||
@@ -380,7 +380,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
(GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
|
||||
break;
|
||||
case 0x45: /* TCtrlReg */
|
||||
GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
|
||||
GUSregb(GUS45TimerCtrl) = (uint8_t) data;
|
||||
if (!(data & 0x20))
|
||||
GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
|
||||
if (!(data & 0x02))
|
||||
@@ -434,18 +434,18 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
GUS_irqclear(state, state->gusirq);
|
||||
break;
|
||||
case 0x46: /* Counter1 */
|
||||
GUSregb(GUS46Counter1) = (GUSbyte) data;
|
||||
GUSregb(GUS46Counter1) = (uint8_t) data;
|
||||
break;
|
||||
case 0x47: /* Counter2 */
|
||||
GUSregb(GUS47Counter2) = (GUSbyte) data;
|
||||
GUSregb(GUS47Counter2) = (uint8_t) data;
|
||||
break;
|
||||
/* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */
|
||||
case 0x49: /* SampCtrlReg */
|
||||
GUSregb(GUS49SampCtrl) = (GUSbyte) data;
|
||||
GUSregb(GUS49SampCtrl) = (uint8_t) data;
|
||||
break;
|
||||
/* case 0x4b: */ /* joystick trim not emulated */
|
||||
case 0x4c: /* GUSreset */
|
||||
GUSregb(GUS4cReset) = (GUSbyte) data;
|
||||
GUSregb(GUS4cReset) = (uint8_t) data;
|
||||
if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
|
||||
{
|
||||
GUSregd(voicewavetableirq) = 0;
|
||||
@@ -471,9 +471,9 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
|
||||
break;
|
||||
case 0x307: /* DRAMaccess */
|
||||
{
|
||||
GUSbyte *adr;
|
||||
uint8_t *adr;
|
||||
adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
|
||||
*adr = (GUSbyte) data;
|
||||
*adr = (uint8_t) data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -510,7 +510,7 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun
|
||||
char *srcaddr;
|
||||
char *destaddr;
|
||||
char msbmask = 0;
|
||||
GUSbyte *gusptr;
|
||||
uint8_t *gusptr;
|
||||
gusptr = state->gusdatapos;
|
||||
|
||||
srcaddr = dma_addr; /* system memory address */
|
||||
@@ -521,8 +521,8 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun
|
||||
destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */
|
||||
}
|
||||
|
||||
GUSregw(GUS42DMAStart) += (GUSword) (count >> 4); /* ToDo: add 16bit GUS page limit? */
|
||||
GUSregb(GUS50DMAHigh) = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
|
||||
GUSregw(GUS42DMAStart) += (uint16_t) (count >> 4); /* ToDo: add 16bit GUS page limit? */
|
||||
GUSregb(GUS50DMAHigh) = (uint8_t) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
|
||||
|
||||
if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */
|
||||
{
|
||||
|
||||
@@ -27,26 +27,26 @@
|
||||
#include "gustate.h"
|
||||
|
||||
#define GUSregb(position) (* (gusptr+(position)))
|
||||
#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
|
||||
#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
|
||||
#define GUSregw(position) (*(uint16_t *) (gusptr+(position)))
|
||||
#define GUSregd(position) (*(uint16_t *)(gusptr+(position)))
|
||||
|
||||
#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
|
||||
#define GUSvoice(position) (*(uint16_t *)(voiceptr+(position)))
|
||||
|
||||
/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
|
||||
void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
|
||||
GUSsample *bufferpos)
|
||||
int16_t *bufferpos)
|
||||
{
|
||||
/* note that byte registers are stored in the upper half of each voice register! */
|
||||
GUSbyte *gusptr;
|
||||
uint8_t *gusptr;
|
||||
int Voice;
|
||||
GUSword *voiceptr;
|
||||
uint16_t *voiceptr;
|
||||
|
||||
unsigned int count;
|
||||
for (count = 0; count < numsamples * 2; count++)
|
||||
*(bufferpos + count) = 0; /* clear */
|
||||
|
||||
gusptr = state->gusdatapos;
|
||||
voiceptr = (GUSword *) gusptr;
|
||||
voiceptr = (uint16_t *) gusptr;
|
||||
if (!(GUSregb(GUS4cReset) & 0x01)) /* reset flag active? */
|
||||
return;
|
||||
|
||||
@@ -85,16 +85,16 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int
|
||||
if (GUSvoice(wVSRControl) & 0x400) /* 16bit */
|
||||
{
|
||||
int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
|
||||
GUSchar *adr;
|
||||
adr = (GUSchar *) state->himemaddr + offset;
|
||||
int8_t *adr;
|
||||
adr = (int8_t *) state->himemaddr + offset;
|
||||
sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
|
||||
sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
|
||||
}
|
||||
else /* 8bit */
|
||||
{
|
||||
int offset = (CurrPos >> 9) & 0xfffff;
|
||||
GUSchar *adr;
|
||||
adr = (GUSchar *) state->himemaddr + offset;
|
||||
int8_t *adr;
|
||||
adr = (int8_t *) state->himemaddr + offset;
|
||||
sample1 = (*adr) * 256;
|
||||
sample2 = (*(adr + 1)) * 256;
|
||||
}
|
||||
@@ -171,8 +171,8 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int
|
||||
}
|
||||
|
||||
/* mix samples into buffer */
|
||||
*(bufferpos + 2 * sample) += (GUSsample) ((sample1 * PanningPos) >> 4); /* right */
|
||||
*(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */
|
||||
*(bufferpos + 2 * sample) += (int16_t) ((sample1 * PanningPos) >> 4); /* right */
|
||||
*(bufferpos + 2 * sample + 1) += (int16_t) ((sample1 * (15 - PanningPos)) >> 4); /* left */
|
||||
}
|
||||
/* write back voice and volume */
|
||||
GUSvoice(wVSRCurrVol) = Volume32 / 32;
|
||||
@@ -187,7 +187,7 @@ void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
|
||||
/* time given in microseconds */
|
||||
{
|
||||
int requestedIRQs = 0;
|
||||
GUSbyte *gusptr;
|
||||
uint8_t *gusptr;
|
||||
gusptr = state->gusdatapos;
|
||||
if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
|
||||
{
|
||||
|
||||
@@ -520,7 +520,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hda_audio_exit(HDACodecDevice *hda)
|
||||
static void hda_audio_exit(HDACodecDevice *hda)
|
||||
{
|
||||
HDAAudioState *a = HDA_AUDIO(hda);
|
||||
HDAAudioStream *st;
|
||||
@@ -539,7 +539,6 @@ static int hda_audio_exit(HDACodecDevice *hda)
|
||||
}
|
||||
}
|
||||
AUD_remove_card(&a->card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hda_audio_post_load(void *opaque, int version)
|
||||
|
||||
@@ -70,7 +70,7 @@ static void hda_codec_dev_realize(DeviceState *qdev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static int hda_codec_dev_exit(DeviceState *qdev)
|
||||
static void hda_codec_dev_unrealize(DeviceState *qdev, Error **errp)
|
||||
{
|
||||
HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
|
||||
HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
|
||||
@@ -78,7 +78,6 @@ static int hda_codec_dev_exit(DeviceState *qdev)
|
||||
if (cdc->exit) {
|
||||
cdc->exit(dev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
|
||||
@@ -1318,7 +1317,7 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *k = DEVICE_CLASS(klass);
|
||||
k->realize = hda_codec_dev_realize;
|
||||
k->exit = hda_codec_dev_exit;
|
||||
k->unrealize = hda_codec_dev_unrealize;
|
||||
set_bit(DEVICE_CATEGORY_SOUND, k->categories);
|
||||
k->bus_type = TYPE_HDA_BUS;
|
||||
k->props = hda_props;
|
||||
|
||||
@@ -38,7 +38,7 @@ typedef struct HDACodecDeviceClass
|
||||
DeviceClass parent_class;
|
||||
|
||||
int (*init)(HDACodecDevice *dev);
|
||||
int (*exit)(HDACodecDevice *dev);
|
||||
void (*exit)(HDACodecDevice *dev);
|
||||
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
|
||||
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
|
||||
} HDACodecDeviceClass;
|
||||
|
||||
@@ -1082,7 +1082,7 @@ static int blk_connect(struct XenDevice *xendev)
|
||||
|
||||
if (strcmp(blkdev->fileproto, "<unset>")) {
|
||||
options = qdict_new();
|
||||
qdict_put(options, "driver", qstring_from_str(blkdev->fileproto));
|
||||
qdict_put_str(options, "driver", blkdev->fileproto);
|
||||
}
|
||||
|
||||
/* setup via xenbus -> create new block driver instance */
|
||||
|
||||
@@ -29,3 +29,4 @@ common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o
|
||||
common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o
|
||||
|
||||
obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o
|
||||
obj-$(CONFIG_TERMINAL3270) += terminal3270.o
|
||||
|
||||
293
hw/char/terminal3270.c
Normal file
293
hw/char/terminal3270.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Terminal 3270 implementation
|
||||
*
|
||||
* Copyright 2017 IBM Corp.
|
||||
*
|
||||
* Authors: Yang Chen <bjcyang@linux.vnet.ibm.com>
|
||||
* Jing Liu <liujbjl@linux.vnet.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 "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "hw/s390x/3270-ccw.h"
|
||||
|
||||
/* Enough spaces for different window sizes. */
|
||||
#define INPUT_BUFFER_SIZE 1000
|
||||
/*
|
||||
* 1 for header, 1024*2 for datastream, 2 for tail
|
||||
* Reserve enough spaces for telnet IAC escape.
|
||||
*/
|
||||
#define OUTPUT_BUFFER_SIZE 2051
|
||||
|
||||
typedef struct Terminal3270 {
|
||||
EmulatedCcw3270Device cdev;
|
||||
CharBackend chr;
|
||||
uint8_t inv[INPUT_BUFFER_SIZE];
|
||||
uint8_t outv[OUTPUT_BUFFER_SIZE];
|
||||
int in_len;
|
||||
int out_len;
|
||||
bool handshake_done;
|
||||
guint timer_tag;
|
||||
} Terminal3270;
|
||||
|
||||
#define TYPE_TERMINAL_3270 "x-terminal3270"
|
||||
#define TERMINAL_3270(obj) \
|
||||
OBJECT_CHECK(Terminal3270, (obj), TYPE_TERMINAL_3270)
|
||||
|
||||
static int terminal_can_read(void *opaque)
|
||||
{
|
||||
Terminal3270 *t = opaque;
|
||||
|
||||
return INPUT_BUFFER_SIZE - t->in_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol handshake done,
|
||||
* signal guest by an unsolicited DE irq.
|
||||
*/
|
||||
static void TN3270_handshake_done(Terminal3270 *t)
|
||||
{
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(t);
|
||||
SubchDev *sch = ccw_dev->sch;
|
||||
|
||||
t->handshake_done = true;
|
||||
sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END;
|
||||
css_conditional_io_interrupt(sch);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when the interval is timeout to detect
|
||||
* if the client is still alive by Timing Mark.
|
||||
*/
|
||||
static gboolean send_timing_mark_cb(gpointer opaque)
|
||||
{
|
||||
Terminal3270 *t = opaque;
|
||||
const uint8_t timing[] = {0xff, 0xfd, 0x06};
|
||||
|
||||
qemu_chr_fe_write_all(&t->chr, timing, sizeof(timing));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive inbound data from socket.
|
||||
* For data given to guest, drop the data boundary IAC, IAC_EOR.
|
||||
* TODO:
|
||||
* Using "Reset" key on x3270 may result multiple commands in one packet.
|
||||
* This usually happens when the user meets a poor traffic of the network.
|
||||
* As of now, for such case, we simply terminate the connection,
|
||||
* and we should come back here later with a better solution.
|
||||
*/
|
||||
static void terminal_read(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
Terminal3270 *t = opaque;
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(t);
|
||||
SubchDev *sch = ccw_dev->sch;
|
||||
int end;
|
||||
|
||||
assert(size <= (INPUT_BUFFER_SIZE - t->in_len));
|
||||
|
||||
if (t->timer_tag) {
|
||||
g_source_remove(t->timer_tag);
|
||||
t->timer_tag = 0;
|
||||
}
|
||||
t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t);
|
||||
|
||||
memcpy(&t->inv[t->in_len], buf, size);
|
||||
t->in_len += size;
|
||||
if (t->in_len < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t->handshake_done) {
|
||||
/*
|
||||
* Receiving Terminal Type is the last step of handshake.
|
||||
* The data format: IAC SB Terminal-Type IS <terminal type> IAC SE
|
||||
* The code for Terminal-Type is 0x18, for IS is 0.
|
||||
* Simply check the data format and mark handshake_done.
|
||||
*/
|
||||
if (t->in_len > 6 && t->inv[2] == 0x18 && t->inv[3] == 0x0 &&
|
||||
t->inv[t->in_len - 2] == IAC && t->inv[t->in_len - 1] == IAC_SE) {
|
||||
TN3270_handshake_done(t);
|
||||
t->in_len = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (end = 0; end < t->in_len - 1; end++) {
|
||||
if (t->inv[end] == IAC && t->inv[end + 1] == IAC_EOR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (end == t->in_len - 2) {
|
||||
/* Data is valid for consuming. */
|
||||
t->in_len -= 2;
|
||||
sch->curr_status.scsw.dstat = SCSW_DSTAT_ATTENTION;
|
||||
css_conditional_io_interrupt(sch);
|
||||
} else if (end < t->in_len - 2) {
|
||||
/* "Reset" key is used. */
|
||||
qemu_chr_fe_disconnect(&t->chr);
|
||||
} else {
|
||||
/* Gathering data. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void chr_event(void *opaque, int event)
|
||||
{
|
||||
Terminal3270 *t = opaque;
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(t);
|
||||
SubchDev *sch = ccw_dev->sch;
|
||||
|
||||
/* Ensure the initial status correct, always reset them. */
|
||||
t->in_len = 0;
|
||||
t->out_len = 0;
|
||||
t->handshake_done = false;
|
||||
if (t->timer_tag) {
|
||||
g_source_remove(t->timer_tag);
|
||||
t->timer_tag = 0;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case CHR_EVENT_OPENED:
|
||||
/*
|
||||
* 3270 does handshake firstly by the negotiate options in
|
||||
* char-socket.c. Once qemu receives the terminal-type of the
|
||||
* client, mark handshake done and trigger everything rolling again.
|
||||
*/
|
||||
t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t);
|
||||
break;
|
||||
case CHR_EVENT_CLOSED:
|
||||
sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END;
|
||||
css_conditional_io_interrupt(sch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_init(EmulatedCcw3270Device *dev, Error **errp)
|
||||
{
|
||||
Terminal3270 *t = TERMINAL_3270(dev);
|
||||
static bool terminal_available;
|
||||
|
||||
if (terminal_available) {
|
||||
error_setg(errp, "Multiple 3270 terminals are not supported.");
|
||||
return;
|
||||
}
|
||||
terminal_available = true;
|
||||
qemu_chr_fe_set_handlers(&t->chr, terminal_can_read,
|
||||
terminal_read, chr_event, t, NULL, true);
|
||||
}
|
||||
|
||||
static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda,
|
||||
uint16_t count)
|
||||
{
|
||||
Terminal3270 *t = TERMINAL_3270(dev);
|
||||
int len;
|
||||
|
||||
len = MIN(count, t->in_len);
|
||||
cpu_physical_memory_write(cda, t->inv, len);
|
||||
t->in_len -= len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* TN3270 uses binary transmission, which needs escape IAC to IAC IAC */
|
||||
static int insert_IAC_escape_char(uint8_t *outv, int out_len)
|
||||
{
|
||||
int IAC_num = 0, new_out_len, i, j;
|
||||
|
||||
for (i = 0; i < out_len; i++) {
|
||||
if (outv[i] == IAC) {
|
||||
IAC_num++;
|
||||
}
|
||||
}
|
||||
if (IAC_num == 0) {
|
||||
return out_len;
|
||||
}
|
||||
new_out_len = out_len + IAC_num;
|
||||
for (i = out_len - 1, j = new_out_len - 1; j > i && i >= 0; i--, j--) {
|
||||
outv[j] = outv[i];
|
||||
if (outv[i] == IAC) {
|
||||
outv[--j] = IAC;
|
||||
}
|
||||
}
|
||||
return new_out_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write 3270 outbound to socket.
|
||||
* Return the count of 3270 data field if succeeded, zero if failed.
|
||||
*/
|
||||
static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd,
|
||||
uint32_t cda, uint16_t count)
|
||||
{
|
||||
Terminal3270 *t = TERMINAL_3270(dev);
|
||||
int retval = 0;
|
||||
|
||||
assert(count <= (OUTPUT_BUFFER_SIZE - 3) / 2);
|
||||
|
||||
if (!t->handshake_done) {
|
||||
if (!(t->outv[0] == IAC && t->outv[1] != IAC)) {
|
||||
/*
|
||||
* Before having finished 3270 negotiation,
|
||||
* sending outbound data except protocol options is prohibited.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!qemu_chr_fe_get_driver(&t->chr)) {
|
||||
/* We just say we consumed all data if there's no backend. */
|
||||
return count;
|
||||
}
|
||||
t->outv[0] = cmd;
|
||||
cpu_physical_memory_read(cda, &t->outv[1], count);
|
||||
t->out_len = count + 1;
|
||||
|
||||
t->out_len = insert_IAC_escape_char(t->outv, t->out_len);
|
||||
t->outv[t->out_len++] = IAC;
|
||||
t->outv[t->out_len++] = IAC_EOR;
|
||||
|
||||
retval = qemu_chr_fe_write_all(&t->chr, t->outv, t->out_len);
|
||||
return (retval <= 0) ? 0 : (retval - 3);
|
||||
}
|
||||
|
||||
static Property terminal_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", Terminal3270, chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const VMStateDescription terminal3270_vmstate = {
|
||||
.name = TYPE_TERMINAL_3270,
|
||||
.unmigratable = 1,
|
||||
};
|
||||
|
||||
static void terminal_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_CLASS(klass);
|
||||
|
||||
dc->props = terminal_properties;
|
||||
dc->vmsd = &terminal3270_vmstate;
|
||||
ck->init = terminal_init;
|
||||
ck->read_payload_3270 = read_payload_3270;
|
||||
ck->write_payload_3270 = write_payload_3270;
|
||||
}
|
||||
|
||||
static const TypeInfo ccw_terminal_info = {
|
||||
.name = TYPE_TERMINAL_3270,
|
||||
.parent = TYPE_EMULATED_CCW_3270,
|
||||
.instance_size = sizeof(Terminal3270),
|
||||
.class_init = terminal_class_init,
|
||||
.class_size = sizeof(EmulatedCcw3270Class),
|
||||
};
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
type_register_static(&ccw_terminal_info);
|
||||
}
|
||||
|
||||
type_init(register_types)
|
||||
@@ -113,7 +113,7 @@ static void cg3_update_display(void *opaque)
|
||||
for (y = 0; y < height; y++) {
|
||||
int update = s->full_update;
|
||||
|
||||
page = y * width;
|
||||
page = (ram_addr_t)y * width;
|
||||
update |= memory_region_get_dirty(&s->vram_mem, page, width,
|
||||
DIRTY_MEMORY_VGA);
|
||||
if (update) {
|
||||
|
||||
@@ -145,7 +145,6 @@ static void update_palette_entries(TCXState *s, int start, int end)
|
||||
} else {
|
||||
s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem));
|
||||
}
|
||||
|
||||
@@ -600,6 +600,22 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g)
|
||||
}
|
||||
}
|
||||
|
||||
void virtio_gpu_gl_block(void *opaque, bool block)
|
||||
{
|
||||
VirtIOGPU *g = opaque;
|
||||
|
||||
if (block) {
|
||||
g->renderer_blocked++;
|
||||
} else {
|
||||
g->renderer_blocked--;
|
||||
}
|
||||
assert(g->renderer_blocked >= 0);
|
||||
|
||||
if (g->renderer_blocked == 0) {
|
||||
virtio_gpu_process_cmdq(g);
|
||||
}
|
||||
}
|
||||
|
||||
int virtio_gpu_virgl_init(VirtIOGPU *g)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -929,28 +929,14 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtio_gpu_gl_block(void *opaque, bool block)
|
||||
{
|
||||
VirtIOGPU *g = opaque;
|
||||
|
||||
if (block) {
|
||||
g->renderer_blocked++;
|
||||
} else {
|
||||
g->renderer_blocked--;
|
||||
}
|
||||
assert(g->renderer_blocked >= 0);
|
||||
|
||||
if (g->renderer_blocked == 0) {
|
||||
virtio_gpu_process_cmdq(g);
|
||||
}
|
||||
}
|
||||
|
||||
const GraphicHwOps virtio_gpu_ops = {
|
||||
.invalidate = virtio_gpu_invalidate_display,
|
||||
.gfx_update = virtio_gpu_update_display,
|
||||
.text_update = virtio_gpu_text_update,
|
||||
.ui_info = virtio_gpu_ui_info,
|
||||
#ifdef CONFIG_VIRGL
|
||||
.gl_block = virtio_gpu_gl_block,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_virtio_gpu_scanout = {
|
||||
|
||||
@@ -272,7 +272,7 @@ build_facs(GArray *table_data, BIOSLinker *linker)
|
||||
}
|
||||
|
||||
/* Load chipset information in FADT */
|
||||
static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm)
|
||||
static void fadt_setup(AcpiFadtDescriptorRev3 *fadt, AcpiPmInfo *pm)
|
||||
{
|
||||
fadt->model = 1;
|
||||
fadt->reserved1 = 0;
|
||||
@@ -304,6 +304,31 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm)
|
||||
fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL);
|
||||
}
|
||||
fadt->century = RTC_CENTURY;
|
||||
|
||||
fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_RESET_REG_SUP);
|
||||
fadt->reset_value = 0xf;
|
||||
fadt->reset_register.space_id = AML_SYSTEM_IO;
|
||||
fadt->reset_register.bit_width = 8;
|
||||
fadt->reset_register.address = cpu_to_le64(ICH9_RST_CNT_IOPORT);
|
||||
/* The above need not be conditional on machine type because the reset port
|
||||
* happens to be the same on PIIX (pc) and ICH9 (q35). */
|
||||
QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != RCR_IOPORT);
|
||||
|
||||
fadt->xpm1a_event_block.space_id = AML_SYSTEM_IO;
|
||||
fadt->xpm1a_event_block.bit_width = fadt->pm1_evt_len * 8;
|
||||
fadt->xpm1a_event_block.address = cpu_to_le64(pm->io_base);
|
||||
|
||||
fadt->xpm1a_control_block.space_id = AML_SYSTEM_IO;
|
||||
fadt->xpm1a_control_block.bit_width = fadt->pm1_cnt_len * 8;
|
||||
fadt->xpm1a_control_block.address = cpu_to_le64(pm->io_base + 0x4);
|
||||
|
||||
fadt->xpm_timer_block.space_id = AML_SYSTEM_IO;
|
||||
fadt->xpm_timer_block.bit_width = fadt->pm_tmr_len * 8;
|
||||
fadt->xpm_timer_block.address = cpu_to_le64(pm->io_base + 0x8);
|
||||
|
||||
fadt->xgpe0_block.space_id = AML_SYSTEM_IO;
|
||||
fadt->xgpe0_block.bit_width = pm->gpe0_blk_len * 8;
|
||||
fadt->xgpe0_block.address = cpu_to_le64(pm->gpe0_blk);
|
||||
}
|
||||
|
||||
|
||||
@@ -313,9 +338,10 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm,
|
||||
unsigned facs_tbl_offset, unsigned dsdt_tbl_offset,
|
||||
const char *oem_id, const char *oem_table_id)
|
||||
{
|
||||
AcpiFadtDescriptorRev1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
|
||||
AcpiFadtDescriptorRev3 *fadt = acpi_data_push(table_data, sizeof(*fadt));
|
||||
unsigned fw_ctrl_offset = (char *)&fadt->firmware_ctrl - table_data->data;
|
||||
unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data;
|
||||
unsigned xdsdt_entry_offset = (char *)&fadt->Xdsdt - table_data->data;
|
||||
|
||||
/* FACS address to be filled by Guest linker */
|
||||
bios_linker_loader_add_pointer(linker,
|
||||
@@ -327,9 +353,12 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm,
|
||||
bios_linker_loader_add_pointer(linker,
|
||||
ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt),
|
||||
ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
|
||||
bios_linker_loader_add_pointer(linker,
|
||||
ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->Xdsdt),
|
||||
ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
|
||||
|
||||
build_header(linker, table_data,
|
||||
(void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id);
|
||||
(void *)fadt, "FACP", sizeof(*fadt), 3, oem_id, oem_table_id);
|
||||
}
|
||||
|
||||
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
|
||||
|
||||
@@ -484,12 +484,14 @@ static struct virtio_input_config virtio_tablet_config[] = {
|
||||
.select = VIRTIO_INPUT_CFG_ABS_INFO,
|
||||
.subsel = ABS_X,
|
||||
.size = sizeof(virtio_input_absinfo),
|
||||
.u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1),
|
||||
.u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
|
||||
.u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
|
||||
},{
|
||||
.select = VIRTIO_INPUT_CFG_ABS_INFO,
|
||||
.subsel = ABS_Y,
|
||||
.size = sizeof(virtio_input_absinfo),
|
||||
.u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1),
|
||||
.u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
|
||||
.u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
|
||||
},
|
||||
{ /* end of list */ },
|
||||
};
|
||||
|
||||
@@ -61,6 +61,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu)
|
||||
}
|
||||
next = now + (uint64_t)wait * TIMER_PERIOD;
|
||||
timer_mod(cpu->env.timer, next);
|
||||
qemu_cpu_kick(CPU(cpu));
|
||||
}
|
||||
|
||||
void cpu_openrisc_count_start(OpenRISCCPU *cpu)
|
||||
|
||||
@@ -58,12 +58,6 @@ typedef struct I440FXState {
|
||||
#define XEN_PIIX_NUM_PIRQS 128ULL
|
||||
#define PIIX_PIRQC 0x60
|
||||
|
||||
/*
|
||||
* Reset Control Register: PCI-accessible ISA-Compatible Register at address
|
||||
* 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
|
||||
*/
|
||||
#define RCR_IOPORT 0xcf9
|
||||
|
||||
typedef struct PIIX3State {
|
||||
PCIDevice dev;
|
||||
|
||||
|
||||
@@ -44,6 +44,13 @@
|
||||
#define PCI_ERR_SRC_COR_OFFS 0
|
||||
#define PCI_ERR_SRC_UNCOR_OFFS 2
|
||||
|
||||
typedef struct PCIEErrorDetails {
|
||||
const char *id;
|
||||
const char *root_bus;
|
||||
int bus;
|
||||
int devfn;
|
||||
} PCIEErrorDetails;
|
||||
|
||||
/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
|
||||
static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
|
||||
{
|
||||
@@ -369,7 +376,7 @@ static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
|
||||
*
|
||||
* Walk up the bus tree from the device, propagate the error message.
|
||||
*/
|
||||
void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
|
||||
static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
|
||||
{
|
||||
uint8_t type;
|
||||
|
||||
@@ -624,7 +631,7 @@ static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal)
|
||||
* Figure 6-2: Flowchart Showing Sequence of Device Error Signaling and Logging
|
||||
* Operations
|
||||
*/
|
||||
int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
|
||||
static int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
|
||||
{
|
||||
uint8_t *aer_cap = NULL;
|
||||
uint16_t devctl = 0;
|
||||
@@ -942,8 +949,14 @@ static int pcie_aer_parse_error_string(const char *error_name,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inject an error described by @qdict.
|
||||
* On success, set @details to show where error was sent.
|
||||
* Return negative errno if injection failed and a message was emitted.
|
||||
*/
|
||||
static int do_pcie_aer_inject_error(Monitor *mon,
|
||||
const QDict *qdict, QObject **ret_data)
|
||||
const QDict *qdict,
|
||||
PCIEErrorDetails *details)
|
||||
{
|
||||
const char *id = qdict_get_str(qdict, "id");
|
||||
const char *error_name;
|
||||
@@ -1005,33 +1018,28 @@ static int do_pcie_aer_inject_error(Monitor *mon,
|
||||
err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0);
|
||||
|
||||
ret = pcie_aer_inject_error(dev, &err);
|
||||
*ret_data = qobject_from_jsonf("{'id': %s, "
|
||||
"'root_bus': %s, 'bus': %d, 'devfn': %d, "
|
||||
"'ret': %d}",
|
||||
id, pci_root_bus_path(dev),
|
||||
pci_bus_num(dev->bus), dev->devfn,
|
||||
ret);
|
||||
assert(*ret_data);
|
||||
if (ret < 0) {
|
||||
monitor_printf(mon, "failed to inject error: %s\n",
|
||||
strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
details->id = id;
|
||||
details->root_bus = pci_root_bus_path(dev);
|
||||
details->bus = pci_bus_num(dev->bus);
|
||||
details->devfn = dev->devfn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
QObject *data;
|
||||
int devfn;
|
||||
PCIEErrorDetails data;
|
||||
|
||||
if (do_pcie_aer_inject_error(mon, qdict, &data) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
qdict = qobject_to_qdict(data);
|
||||
assert(qdict);
|
||||
|
||||
devfn = (int)qdict_get_int(qdict, "devfn");
|
||||
monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n",
|
||||
qdict_get_str(qdict, "id"),
|
||||
qdict_get_str(qdict, "root_bus"),
|
||||
(int) qdict_get_int(qdict, "bus"),
|
||||
PCI_SLOT(devfn), PCI_FUNC(devfn));
|
||||
data.id, data.root_bus, data.bus,
|
||||
PCI_SLOT(data.devfn), PCI_FUNC(data.devfn));
|
||||
}
|
||||
|
||||
174
hw/s390x/3270-ccw.c
Normal file
174
hw/s390x/3270-ccw.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Emulated ccw-attached 3270 implementation
|
||||
*
|
||||
* Copyright 2017 IBM Corp.
|
||||
* Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com>
|
||||
* Jing Liu <liujbjl@linux.vnet.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 "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/s390x/css.h"
|
||||
#include "hw/s390x/css-bridge.h"
|
||||
#include "hw/s390x/3270-ccw.h"
|
||||
|
||||
/* Handle READ ccw commands from guest */
|
||||
static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw)
|
||||
{
|
||||
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(dev);
|
||||
int len;
|
||||
|
||||
if (!ccw->cda) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
len = ck->read_payload_3270(dev, ccw->cda, ccw->count);
|
||||
ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle WRITE ccw commands to write data to client */
|
||||
static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw)
|
||||
{
|
||||
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(dev);
|
||||
int len;
|
||||
|
||||
if (!ccw->cda) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
len = ck->write_payload_3270(dev, ccw->cmd_code, ccw->cda, ccw->count);
|
||||
|
||||
if (len <= 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emulated_ccw_3270_cb(SubchDev *sch, CCW1 ccw)
|
||||
{
|
||||
int rc = 0;
|
||||
EmulatedCcw3270Device *dev = sch->driver_data;
|
||||
|
||||
switch (ccw.cmd_code) {
|
||||
case TC_WRITESF:
|
||||
case TC_WRITE:
|
||||
case TC_EWRITE:
|
||||
case TC_EWRITEA:
|
||||
rc = handle_payload_3270_write(dev, &ccw);
|
||||
break;
|
||||
case TC_RDBUF:
|
||||
case TC_READMOD:
|
||||
rc = handle_payload_3270_read(dev, &ccw);
|
||||
break;
|
||||
default:
|
||||
rc = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == -EIO) {
|
||||
/* I/O error, specific devices generate specific conditions */
|
||||
SCSW *s = &sch->curr_status.scsw;
|
||||
|
||||
sch->curr_status.scsw.dstat = SCSW_DSTAT_UNIT_CHECK;
|
||||
sch->sense_data[0] = 0x40; /* intervention-req */
|
||||
s->ctrl &= ~SCSW_ACTL_START_PEND;
|
||||
s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
|
||||
s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
|
||||
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
|
||||
{
|
||||
uint16_t chpid;
|
||||
EmulatedCcw3270Device *dev = EMULATED_CCW_3270(ds);
|
||||
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
|
||||
CcwDevice *cdev = CCW_DEVICE(ds);
|
||||
CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev);
|
||||
SubchDev *sch = css_create_virtual_sch(cdev->devno, errp);
|
||||
Error *err = NULL;
|
||||
|
||||
if (!sch) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ck->init) {
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
sch->driver_data = dev;
|
||||
cdev->sch = sch;
|
||||
chpid = css_find_free_chpid(sch->cssid);
|
||||
|
||||
if (chpid > MAX_CHPID) {
|
||||
error_setg(&err, "No available chpid to use.");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
sch->id.reserved = 0xff;
|
||||
sch->id.cu_type = EMULATED_CCW_3270_CU_TYPE;
|
||||
css_sch_build_virtual_schib(sch, (uint8_t)chpid,
|
||||
EMULATED_CCW_3270_CHPID_TYPE);
|
||||
sch->ccw_cb = emulated_ccw_3270_cb;
|
||||
|
||||
ck->init(dev, &err);
|
||||
if (err) {
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
cdk->realize(cdev, &err);
|
||||
if (err) {
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
out_err:
|
||||
error_propagate(errp, err);
|
||||
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
|
||||
cdev->sch = NULL;
|
||||
g_free(sch);
|
||||
}
|
||||
|
||||
static Property emulated_ccw_3270_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = emulated_ccw_3270_properties;
|
||||
dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
|
||||
dc->realize = emulated_ccw_3270_realize;
|
||||
dc->hotpluggable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo emulated_ccw_3270_info = {
|
||||
.name = TYPE_EMULATED_CCW_3270,
|
||||
.parent = TYPE_CCW_DEVICE,
|
||||
.instance_size = sizeof(EmulatedCcw3270Device),
|
||||
.class_init = emulated_ccw_3270_class_init,
|
||||
.class_size = sizeof(EmulatedCcw3270Class),
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void emulated_ccw_register(void)
|
||||
{
|
||||
type_register_static(&emulated_ccw_3270_info);
|
||||
}
|
||||
|
||||
type_init(emulated_ccw_register)
|
||||
@@ -7,6 +7,7 @@ obj-y += sclpcpu.o
|
||||
obj-y += ipl.o
|
||||
obj-y += css.o
|
||||
obj-y += s390-virtio-ccw.o
|
||||
obj-y += 3270-ccw.o
|
||||
obj-y += virtio-ccw.o
|
||||
obj-y += css-bridge.o
|
||||
obj-y += ccw-device.o
|
||||
|
||||
@@ -576,6 +576,9 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
|
||||
s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END;
|
||||
s->cpa = sch->channel_prog + 8;
|
||||
break;
|
||||
case -EIO:
|
||||
/* I/O errors, status depends on specific devices */
|
||||
break;
|
||||
case -ENOSYS:
|
||||
/* unsupported command, generate unit check (command reject) */
|
||||
s->ctrl &= ~SCSW_ACTL_START_PEND;
|
||||
@@ -1302,6 +1305,27 @@ bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid)
|
||||
(MAX_SCHID + 1) / sizeof(unsigned long));
|
||||
}
|
||||
|
||||
unsigned int css_find_free_chpid(uint8_t cssid)
|
||||
{
|
||||
CssImage *css = channel_subsys.css[cssid];
|
||||
unsigned int chpid;
|
||||
|
||||
if (!css) {
|
||||
return MAX_CHPID + 1;
|
||||
}
|
||||
|
||||
for (chpid = 0; chpid <= MAX_CHPID; chpid++) {
|
||||
/* skip reserved chpid */
|
||||
if (chpid == VIRTIO_CCW_CHPID) {
|
||||
continue;
|
||||
}
|
||||
if (!css->chpids[chpid].in_use) {
|
||||
return chpid;
|
||||
}
|
||||
}
|
||||
return MAX_CHPID + 1;
|
||||
}
|
||||
|
||||
static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
|
||||
{
|
||||
CssImage *css;
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
#include "cpu.h"
|
||||
#include "elf.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/s390x/virtio-ccw.h"
|
||||
#include "hw/s390x/css.h"
|
||||
#include "hw/s390x/ebcdic.h"
|
||||
#include "ipl.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
@@ -243,12 +245,17 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
|
||||
ipl->iplb.pbt = S390_IPL_TYPE_CCW;
|
||||
ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||
ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
|
||||
return true;
|
||||
} else if (sd) {
|
||||
SCSIBus *bus = scsi_bus_from_device(sd);
|
||||
VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
|
||||
VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev);
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw);
|
||||
CcwDevice *ccw_dev;
|
||||
|
||||
ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
|
||||
TYPE_CCW_DEVICE);
|
||||
if (!ccw_dev) { /* It might be a PCI device instead */
|
||||
return false;
|
||||
}
|
||||
|
||||
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
|
||||
ipl->iplb.blk0_len =
|
||||
@@ -259,13 +266,39 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
|
||||
ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
|
||||
ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
|
||||
ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
|
||||
return true;
|
||||
} else {
|
||||
return false; /* unknown device */
|
||||
}
|
||||
|
||||
if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
|
||||
ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int s390_ipl_set_loadparm(uint8_t *loadparm)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
|
||||
|
||||
if (lp) {
|
||||
int i;
|
||||
|
||||
/* lp is an uppercase string without leading/embedded spaces */
|
||||
for (i = 0; i < 8 && lp[i]; i++) {
|
||||
loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
|
||||
}
|
||||
|
||||
g_free(lp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int load_netboot_image(Error **errp)
|
||||
{
|
||||
S390IPLState *ipl = get_ipl_device();
|
||||
|
||||
@@ -57,6 +57,8 @@ struct IplBlockQemuScsi {
|
||||
} QEMU_PACKED;
|
||||
typedef struct IplBlockQemuScsi IplBlockQemuScsi;
|
||||
|
||||
#define DIAG308_FLAGS_LP_VALID 0x80
|
||||
|
||||
union IplParameterBlock {
|
||||
struct {
|
||||
uint32_t len;
|
||||
@@ -82,6 +84,7 @@ union IplParameterBlock {
|
||||
} QEMU_PACKED;
|
||||
typedef union IplParameterBlock IplParameterBlock;
|
||||
|
||||
int s390_ipl_set_loadparm(uint8_t *loadparm);
|
||||
void s390_ipl_update_diag308(IplParameterBlock *iplb);
|
||||
void s390_ipl_prepare_cpu(S390CPU *cpu);
|
||||
IplParameterBlock *s390_ipl_get_iplb(void);
|
||||
|
||||
@@ -274,6 +274,36 @@ bool cpu_model_allowed(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *machine_get_loadparm(Object *obj, Error **errp)
|
||||
{
|
||||
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
|
||||
|
||||
return g_memdup(ms->loadparm, sizeof(ms->loadparm));
|
||||
}
|
||||
|
||||
static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
|
||||
{
|
||||
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
|
||||
uint8_t c = toupper(val[i]); /* mimic HMC */
|
||||
|
||||
if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
|
||||
(c == ' ')) {
|
||||
ms->loadparm[i] = c;
|
||||
} else {
|
||||
error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
|
||||
c, c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < sizeof(ms->loadparm); i++) {
|
||||
ms->loadparm[i] = ' '; /* pad right with spaces */
|
||||
}
|
||||
}
|
||||
|
||||
static inline void s390_machine_initfn(Object *obj)
|
||||
{
|
||||
object_property_add_bool(obj, "aes-key-wrap",
|
||||
@@ -291,6 +321,13 @@ static inline void s390_machine_initfn(Object *obj)
|
||||
"enable/disable DEA key wrapping using the CPACF wrapping key",
|
||||
NULL);
|
||||
object_property_set_bool(obj, true, "dea-key-wrap", NULL);
|
||||
object_property_add_str(obj, "loadparm",
|
||||
machine_get_loadparm, machine_set_loadparm, NULL);
|
||||
object_property_set_description(obj, "loadparm",
|
||||
"Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted"
|
||||
" to upper case) to pass to machine loader, boot manager,"
|
||||
" and guest kernel",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo ccw_machine_info = {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "hw/s390x/sclp.h"
|
||||
#include "hw/s390x/event-facility.h"
|
||||
#include "hw/s390x/s390-pci-bus.h"
|
||||
#include "hw/s390x/ipl.h"
|
||||
|
||||
static inline SCLPDevice *get_sclp_device(void)
|
||||
{
|
||||
@@ -57,6 +58,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
|
||||
int cpu_count = 0;
|
||||
int rnsize, rnmax;
|
||||
int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
|
||||
IplParameterBlock *ipib = s390_ipl_get_iplb();
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu_count++;
|
||||
@@ -129,6 +131,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
|
||||
read_info->rnmax2 = cpu_to_be64(rnmax);
|
||||
}
|
||||
|
||||
if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
|
||||
memcpy(&read_info->loadparm, &ipib->loadparm,
|
||||
sizeof(read_info->loadparm));
|
||||
} else {
|
||||
s390_ipl_set_loadparm(read_info->loadparm);
|
||||
}
|
||||
|
||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,5 +10,5 @@ obj-$(CONFIG_PSERIES) += spapr_vscsi.o
|
||||
|
||||
ifeq ($(CONFIG_VIRTIO),y)
|
||||
obj-y += virtio-scsi.o virtio-scsi-dataplane.o
|
||||
obj-$(CONFIG_VHOST_SCSI) += vhost-scsi.o
|
||||
obj-$(CONFIG_VHOST_SCSI) += vhost-scsi-common.o vhost-scsi.o
|
||||
endif
|
||||
|
||||
@@ -2138,15 +2138,15 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
|
||||
case MFI_SEQ:
|
||||
trace_megasas_mmio_writel("MFI_SEQ", val);
|
||||
/* Magic sequence to start ADP reset */
|
||||
if (adp_reset_seq[s->adp_reset] == val) {
|
||||
s->adp_reset++;
|
||||
if (adp_reset_seq[s->adp_reset++] == val) {
|
||||
if (s->adp_reset == 6) {
|
||||
s->adp_reset = 0;
|
||||
s->diag = MFI_DIAG_WRITE_ENABLE;
|
||||
}
|
||||
} else {
|
||||
s->adp_reset = 0;
|
||||
s->diag = 0;
|
||||
}
|
||||
if (s->adp_reset == 6) {
|
||||
s->diag = MFI_DIAG_WRITE_ENABLE;
|
||||
}
|
||||
break;
|
||||
case MFI_DIAG:
|
||||
trace_megasas_mmio_writel("MFI_DIAG", val);
|
||||
|
||||
143
hw/scsi/vhost-scsi-common.c
Normal file
143
hw/scsi/vhost-scsi-common.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* vhost-scsi-common
|
||||
*
|
||||
* Copyright (c) 2016 Nutanix Inc. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Felipe Franciosi <felipe@nutanix.com>
|
||||
*
|
||||
* This work is largely based on the "vhost-scsi" implementation by:
|
||||
* Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
||||
* Nicholas Bellinger <nab@risingtidesystems.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <linux/vhost.h>
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "migration/migration.h"
|
||||
#include "hw/virtio/vhost.h"
|
||||
#include "hw/virtio/vhost-scsi-common.h"
|
||||
#include "hw/virtio/virtio-scsi.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "hw/fw-path-provider.h"
|
||||
|
||||
int vhost_scsi_common_start(VHostSCSICommon *vsc)
|
||||
{
|
||||
int ret, i;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(vsc);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
error_report("binding does not support guest notifiers");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ret = vhost_dev_enable_notifiers(&vsc->dev, vdev);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, true);
|
||||
if (ret < 0) {
|
||||
error_report("Error binding guest notifier");
|
||||
goto err_host_notifiers;
|
||||
}
|
||||
|
||||
vsc->dev.acked_features = vdev->guest_features;
|
||||
ret = vhost_dev_start(&vsc->dev, vdev);
|
||||
if (ret < 0) {
|
||||
error_report("Error start vhost dev");
|
||||
goto err_guest_notifiers;
|
||||
}
|
||||
|
||||
/* guest_notifier_mask/pending not used yet, so just unmask
|
||||
* everything here. virtio-pci will do the right thing by
|
||||
* enabling/disabling irqfd.
|
||||
*/
|
||||
for (i = 0; i < vsc->dev.nvqs; i++) {
|
||||
vhost_virtqueue_mask(&vsc->dev, vdev, vsc->dev.vq_index + i, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_guest_notifiers:
|
||||
k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false);
|
||||
err_host_notifiers:
|
||||
vhost_dev_disable_notifiers(&vsc->dev, vdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void vhost_scsi_common_stop(VHostSCSICommon *vsc)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(vsc);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
int ret = 0;
|
||||
|
||||
vhost_dev_stop(&vsc->dev, vdev);
|
||||
|
||||
if (k->set_guest_notifiers) {
|
||||
ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false);
|
||||
if (ret < 0) {
|
||||
error_report("vhost guest notifier cleanup failed: %d", ret);
|
||||
}
|
||||
}
|
||||
assert(ret >= 0);
|
||||
|
||||
vhost_dev_disable_notifiers(&vsc->dev, vdev);
|
||||
}
|
||||
|
||||
uint64_t vhost_scsi_common_get_features(VirtIODevice *vdev, uint64_t features,
|
||||
Error **errp)
|
||||
{
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev);
|
||||
|
||||
return vhost_get_features(&vsc->dev, vsc->feature_bits, features);
|
||||
}
|
||||
|
||||
void vhost_scsi_common_set_config(VirtIODevice *vdev, const uint8_t *config)
|
||||
{
|
||||
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
||||
|
||||
if ((uint32_t)virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size ||
|
||||
(uint32_t)virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) {
|
||||
error_report("vhost-scsi does not support changing the sense data and "
|
||||
"CDB sizes");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Implementation of an interface to adjust firmware path
|
||||
* for the bootindex property handling.
|
||||
*/
|
||||
char *vhost_scsi_common_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
||||
DeviceState *dev)
|
||||
{
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
|
||||
/* format: /channel@channel/vhost-scsi@target,lun */
|
||||
return g_strdup_printf("/channel@%x/%s@%x,%x", vsc->channel,
|
||||
qdev_fw_name(dev), vsc->target, vsc->lun);
|
||||
}
|
||||
|
||||
static const TypeInfo vhost_scsi_common_info = {
|
||||
.name = TYPE_VHOST_SCSI_COMMON,
|
||||
.parent = TYPE_VIRTIO_SCSI_COMMON,
|
||||
.instance_size = sizeof(VHostSCSICommon),
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void virtio_register_types(void)
|
||||
{
|
||||
type_register_static(&vhost_scsi_common_info);
|
||||
}
|
||||
|
||||
type_init(virtio_register_types)
|
||||
@@ -42,13 +42,14 @@ static const int kernel_feature_bits[] = {
|
||||
static int vhost_scsi_set_endpoint(VHostSCSI *s)
|
||||
{
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||
const VhostOps *vhost_ops = s->dev.vhost_ops;
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
|
||||
const VhostOps *vhost_ops = vsc->dev.vhost_ops;
|
||||
struct vhost_scsi_target backend;
|
||||
int ret;
|
||||
|
||||
memset(&backend, 0, sizeof(backend));
|
||||
pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
|
||||
ret = vhost_ops->vhost_scsi_set_endpoint(&s->dev, &backend);
|
||||
ret = vhost_ops->vhost_scsi_set_endpoint(&vsc->dev, &backend);
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
}
|
||||
@@ -58,130 +59,62 @@ static int vhost_scsi_set_endpoint(VHostSCSI *s)
|
||||
static void vhost_scsi_clear_endpoint(VHostSCSI *s)
|
||||
{
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
|
||||
struct vhost_scsi_target backend;
|
||||
const VhostOps *vhost_ops = s->dev.vhost_ops;
|
||||
const VhostOps *vhost_ops = vsc->dev.vhost_ops;
|
||||
|
||||
memset(&backend, 0, sizeof(backend));
|
||||
pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
|
||||
vhost_ops->vhost_scsi_clear_endpoint(&s->dev, &backend);
|
||||
vhost_ops->vhost_scsi_clear_endpoint(&vsc->dev, &backend);
|
||||
}
|
||||
|
||||
static int vhost_scsi_start(VHostSCSI *s)
|
||||
{
|
||||
int ret, abi_version, i;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
const VhostOps *vhost_ops = s->dev.vhost_ops;
|
||||
int ret, abi_version;
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
|
||||
const VhostOps *vhost_ops = vsc->dev.vhost_ops;
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
error_report("binding does not support guest notifiers");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ret = vhost_ops->vhost_scsi_get_abi_version(&s->dev, &abi_version);
|
||||
ret = vhost_ops->vhost_scsi_get_abi_version(&vsc->dev, &abi_version);
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
}
|
||||
if (abi_version > VHOST_SCSI_ABI_VERSION) {
|
||||
error_report("vhost-scsi: The running tcm_vhost kernel abi_version:"
|
||||
" %d is greater than vhost_scsi userspace supports: %d, please"
|
||||
" upgrade your version of QEMU", abi_version,
|
||||
" %d is greater than vhost_scsi userspace supports: %d,"
|
||||
" please upgrade your version of QEMU", abi_version,
|
||||
VHOST_SCSI_ABI_VERSION);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ret = vhost_dev_enable_notifiers(&s->dev, vdev);
|
||||
ret = vhost_scsi_common_start(vsc);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->dev.acked_features = vdev->guest_features;
|
||||
ret = vhost_dev_start(&s->dev, vdev);
|
||||
if (ret < 0) {
|
||||
error_report("Error start vhost dev");
|
||||
goto err_notifiers;
|
||||
}
|
||||
|
||||
ret = vhost_scsi_set_endpoint(s);
|
||||
if (ret < 0) {
|
||||
error_report("Error set vhost-scsi endpoint");
|
||||
goto err_vhost_stop;
|
||||
error_report("Error setting vhost-scsi endpoint");
|
||||
vhost_scsi_common_stop(vsc);
|
||||
}
|
||||
|
||||
ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
|
||||
if (ret < 0) {
|
||||
error_report("Error binding guest notifier");
|
||||
goto err_endpoint;
|
||||
}
|
||||
|
||||
/* guest_notifier_mask/pending not used yet, so just unmask
|
||||
* everything here. virtio-pci will do the right thing by
|
||||
* enabling/disabling irqfd.
|
||||
*/
|
||||
for (i = 0; i < s->dev.nvqs; i++) {
|
||||
vhost_virtqueue_mask(&s->dev, vdev, s->dev.vq_index + i, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_endpoint:
|
||||
vhost_scsi_clear_endpoint(s);
|
||||
err_vhost_stop:
|
||||
vhost_dev_stop(&s->dev, vdev);
|
||||
err_notifiers:
|
||||
vhost_dev_disable_notifiers(&s->dev, vdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vhost_scsi_stop(VHostSCSI *s)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
int ret = 0;
|
||||
|
||||
if (k->set_guest_notifiers) {
|
||||
ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
|
||||
if (ret < 0) {
|
||||
error_report("vhost guest notifier cleanup failed: %d", ret);
|
||||
}
|
||||
}
|
||||
assert(ret >= 0);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
|
||||
|
||||
vhost_scsi_clear_endpoint(s);
|
||||
vhost_dev_stop(&s->dev, vdev);
|
||||
vhost_dev_disable_notifiers(&s->dev, vdev);
|
||||
}
|
||||
|
||||
static uint64_t vhost_scsi_get_features(VirtIODevice *vdev,
|
||||
uint64_t features,
|
||||
Error **errp)
|
||||
{
|
||||
VHostSCSI *s = VHOST_SCSI(vdev);
|
||||
|
||||
return vhost_get_features(&s->dev, kernel_feature_bits, features);
|
||||
}
|
||||
|
||||
static void vhost_scsi_set_config(VirtIODevice *vdev,
|
||||
const uint8_t *config)
|
||||
{
|
||||
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
||||
|
||||
if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size ||
|
||||
(uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) {
|
||||
error_report("vhost-scsi does not support changing the sense data and CDB sizes");
|
||||
exit(1);
|
||||
}
|
||||
vhost_scsi_common_stop(vsc);
|
||||
}
|
||||
|
||||
static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
|
||||
{
|
||||
VHostSCSI *s = (VHostSCSI *)vdev;
|
||||
VHostSCSI *s = VHOST_SCSI(vdev);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
|
||||
bool start = (val & VIRTIO_CONFIG_S_DRIVER_OK);
|
||||
|
||||
if (s->dev.started == start) {
|
||||
if (vsc->dev.started == start) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,10 +123,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
|
||||
|
||||
ret = vhost_scsi_start(s);
|
||||
if (ret < 0) {
|
||||
error_report("virtio-scsi: unable to start vhost: %s",
|
||||
strerror(-ret));
|
||||
|
||||
/* There is no userspace virtio-scsi fallback so exit */
|
||||
error_report("unable to start vhost-scsi: %s", strerror(-ret));
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
@@ -208,7 +138,7 @@ static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
|
||||
VHostSCSI *s = VHOST_SCSI(dev);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
|
||||
Error *err = NULL;
|
||||
int vhostfd = -1;
|
||||
int ret;
|
||||
@@ -243,21 +173,21 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
goto close_fd;
|
||||
}
|
||||
|
||||
error_setg(&s->migration_blocker,
|
||||
error_setg(&vsc->migration_blocker,
|
||||
"vhost-scsi does not support migration");
|
||||
migrate_add_blocker(s->migration_blocker, &err);
|
||||
migrate_add_blocker(vsc->migration_blocker, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
error_free(s->migration_blocker);
|
||||
error_free(vsc->migration_blocker);
|
||||
goto close_fd;
|
||||
}
|
||||
|
||||
s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
|
||||
s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
|
||||
s->dev.vq_index = 0;
|
||||
s->dev.backend_features = 0;
|
||||
vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
|
||||
vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs);
|
||||
vsc->dev.vq_index = 0;
|
||||
vsc->dev.backend_features = 0;
|
||||
|
||||
ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
|
||||
ret = vhost_dev_init(&vsc->dev, (void *)(uintptr_t)vhostfd,
|
||||
VHOST_BACKEND_TYPE_KERNEL, 0);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
|
||||
@@ -266,16 +196,16 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
/* At present, channel and lun both are 0 for bootable vhost-scsi disk */
|
||||
s->channel = 0;
|
||||
s->lun = 0;
|
||||
vsc->channel = 0;
|
||||
vsc->lun = 0;
|
||||
/* Note: we can also get the minimum tpgt from kernel */
|
||||
s->target = vs->conf.boot_tpgt;
|
||||
vsc->target = vs->conf.boot_tpgt;
|
||||
|
||||
return;
|
||||
|
||||
free_vqs:
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
g_free(s->dev.vqs);
|
||||
migrate_del_blocker(vsc->migration_blocker);
|
||||
g_free(vsc->dev.vqs);
|
||||
close_fd:
|
||||
close(vhostfd);
|
||||
return;
|
||||
@@ -284,42 +214,28 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostSCSI *s = VHOST_SCSI(dev);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
|
||||
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
error_free(s->migration_blocker);
|
||||
migrate_del_blocker(vsc->migration_blocker);
|
||||
error_free(vsc->migration_blocker);
|
||||
|
||||
/* This will stop vhost backend. */
|
||||
vhost_scsi_set_status(vdev, 0);
|
||||
|
||||
vhost_dev_cleanup(&s->dev);
|
||||
g_free(s->dev.vqs);
|
||||
vhost_dev_cleanup(&vsc->dev);
|
||||
g_free(vsc->dev.vqs);
|
||||
|
||||
virtio_scsi_common_unrealize(dev, errp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implementation of an interface to adjust firmware path
|
||||
* for the bootindex property handling.
|
||||
*/
|
||||
static char *vhost_scsi_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
||||
DeviceState *dev)
|
||||
{
|
||||
VHostSCSI *s = VHOST_SCSI(dev);
|
||||
/* format: channel@channel/vhost-scsi@target,lun */
|
||||
return g_strdup_printf("/channel@%x/%s@%x,%x", s->channel,
|
||||
qdev_fw_name(dev), s->target, s->lun);
|
||||
}
|
||||
|
||||
static Property vhost_scsi_properties[] = {
|
||||
DEFINE_PROP_STRING("vhostfd", VHostSCSI, parent_obj.conf.vhostfd),
|
||||
DEFINE_PROP_STRING("wwpn", VHostSCSI, parent_obj.conf.wwpn),
|
||||
DEFINE_PROP_UINT32("boot_tpgt", VHostSCSI, parent_obj.conf.boot_tpgt, 0),
|
||||
DEFINE_PROP_UINT32("num_queues", VHostSCSI, parent_obj.conf.num_queues, 1),
|
||||
DEFINE_PROP_UINT32("max_sectors", VHostSCSI, parent_obj.conf.max_sectors,
|
||||
0xFFFF),
|
||||
DEFINE_PROP_UINT32("cmd_per_lun", VHostSCSI, parent_obj.conf.cmd_per_lun,
|
||||
128),
|
||||
DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd),
|
||||
DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn),
|
||||
DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
|
||||
DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1),
|
||||
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
|
||||
0xFFFF),
|
||||
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -333,23 +249,25 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data)
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
vdc->realize = vhost_scsi_realize;
|
||||
vdc->unrealize = vhost_scsi_unrealize;
|
||||
vdc->get_features = vhost_scsi_get_features;
|
||||
vdc->set_config = vhost_scsi_set_config;
|
||||
vdc->get_features = vhost_scsi_common_get_features;
|
||||
vdc->set_config = vhost_scsi_common_set_config;
|
||||
vdc->set_status = vhost_scsi_set_status;
|
||||
fwc->get_dev_path = vhost_scsi_get_fw_dev_path;
|
||||
fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
|
||||
}
|
||||
|
||||
static void vhost_scsi_instance_init(Object *obj)
|
||||
{
|
||||
VHostSCSI *dev = VHOST_SCSI(obj);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj);
|
||||
|
||||
device_add_bootindex_property(obj, &dev->bootindex, "bootindex", NULL,
|
||||
DEVICE(dev), NULL);
|
||||
vsc->feature_bits = kernel_feature_bits;
|
||||
|
||||
device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL,
|
||||
DEVICE(vsc), NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo vhost_scsi_info = {
|
||||
.name = TYPE_VHOST_SCSI,
|
||||
.parent = TYPE_VIRTIO_SCSI_COMMON,
|
||||
.parent = TYPE_VHOST_SCSI_COMMON,
|
||||
.instance_size = sizeof(VHostSCSI),
|
||||
.class_init = vhost_scsi_class_init,
|
||||
.instance_init = vhost_scsi_instance_init,
|
||||
|
||||
@@ -202,7 +202,7 @@ pvscsi_ring_init_msg(PVSCSIRingInfo *m, PVSCSICmdDescSetupMsgRing *ri)
|
||||
uint32_t len_log2;
|
||||
uint32_t ring_size;
|
||||
|
||||
if (ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) {
|
||||
if (!ri->numPages || ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) {
|
||||
return -1;
|
||||
}
|
||||
ring_size = ri->numPages * PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE;
|
||||
|
||||
@@ -267,7 +267,7 @@ static void ccid_card_vscard_drop_connection(PassthruState *card)
|
||||
Chardev *chr = qemu_chr_fe_get_driver(&card->cs);
|
||||
|
||||
qemu_chr_fe_deinit(&card->cs);
|
||||
qemu_chr_delete(chr);
|
||||
object_unparent(OBJECT(chr));
|
||||
card->vscard_in_pos = card->vscard_in_hdr = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1433,7 +1433,7 @@ static void usbredir_unrealize(USBDevice *udev, Error **errp)
|
||||
Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
|
||||
|
||||
qemu_chr_fe_deinit(&dev->cs);
|
||||
qemu_chr_delete(chr);
|
||||
object_unparent(OBJECT(chr));
|
||||
|
||||
/* Note must be done after qemu_chr_close, as that causes a close event */
|
||||
qemu_bh_delete(dev->chardev_close_bh);
|
||||
|
||||
@@ -746,16 +746,16 @@ static void usbback_portid_add(struct usbback_info *usbif, unsigned port,
|
||||
portname++;
|
||||
|
||||
qdict = qdict_new();
|
||||
qdict_put(qdict, "driver", qstring_from_str("usb-host"));
|
||||
qdict_put_str(qdict, "driver", "usb-host");
|
||||
tmp = g_strdup_printf("%s.0", usbif->xendev.qdev.id);
|
||||
qdict_put(qdict, "bus", qstring_from_str(tmp));
|
||||
qdict_put_str(qdict, "bus", tmp);
|
||||
g_free(tmp);
|
||||
tmp = g_strdup_printf("%s-%u", usbif->xendev.qdev.id, port);
|
||||
qdict_put(qdict, "id", qstring_from_str(tmp));
|
||||
qdict_put_str(qdict, "id", tmp);
|
||||
g_free(tmp);
|
||||
qdict_put(qdict, "port", qint_from_int(port));
|
||||
qdict_put(qdict, "hostbus", qint_from_int(atoi(busid)));
|
||||
qdict_put(qdict, "hostport", qstring_from_str(portname));
|
||||
qdict_put_int(qdict, "port", port);
|
||||
qdict_put_int(qdict, "hostbus", atoi(busid));
|
||||
qdict_put_str(qdict, "hostport", portname);
|
||||
opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err);
|
||||
if (local_err) {
|
||||
goto err;
|
||||
|
||||
@@ -119,6 +119,9 @@ void vfio_region_write(void *opaque, hwaddr addr,
|
||||
case 4:
|
||||
buf.dword = cpu_to_le32(data);
|
||||
break;
|
||||
case 8:
|
||||
buf.qword = cpu_to_le64(data);
|
||||
break;
|
||||
default:
|
||||
hw_error("vfio: unsupported write size, %d bytes", size);
|
||||
break;
|
||||
@@ -173,6 +176,9 @@ uint64_t vfio_region_read(void *opaque,
|
||||
case 4:
|
||||
data = le32_to_cpu(buf.dword);
|
||||
break;
|
||||
case 8:
|
||||
data = le64_to_cpu(buf.qword);
|
||||
break;
|
||||
default:
|
||||
hw_error("vfio: unsupported read size, %d bytes", size);
|
||||
break;
|
||||
@@ -190,6 +196,14 @@ const MemoryRegionOps vfio_region_ops = {
|
||||
.read = vfio_region_read,
|
||||
.write = vfio_region_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -2625,8 +2625,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
||||
if (!(~vdev->host.domain || ~vdev->host.bus ||
|
||||
~vdev->host.slot || ~vdev->host.function)) {
|
||||
error_setg(errp, "No provided host device");
|
||||
error_append_hint(errp, "Use -vfio-pci,host=DDDD:BB:DD.F "
|
||||
"or -vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
|
||||
error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
|
||||
"or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
|
||||
return;
|
||||
}
|
||||
vdev->vbasedev.sysfsdev =
|
||||
|
||||
@@ -38,7 +38,7 @@ static int store_dev_info(int domid, Chardev *cs, const char *string)
|
||||
int ret = -1;
|
||||
|
||||
/* Only continue if we're talking to a pty. */
|
||||
if (strncmp(cs->filename, "pty:", 4)) {
|
||||
if (!CHARDEV_IS_PTY(cs)) {
|
||||
return 0;
|
||||
}
|
||||
pts = cs->filename + 4;
|
||||
|
||||
@@ -294,7 +294,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
|
||||
const char *backing_file);
|
||||
int bdrv_get_backing_file_depth(BlockDriverState *bs);
|
||||
void bdrv_refresh_filename(BlockDriverState *bs);
|
||||
int bdrv_truncate(BdrvChild *child, int64_t offset);
|
||||
int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp);
|
||||
int64_t bdrv_nb_sectors(BlockDriverState *bs);
|
||||
int64_t bdrv_getlength(BlockDriverState *bs);
|
||||
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user