Compare commits
290 Commits
pull-input
...
pull-roms-
Author | SHA1 | Date | |
---|---|---|---|
|
3257fc8383 | ||
|
9bb931802e | ||
|
d7d3d6092c | ||
|
66226ffd05 | ||
|
24666baf1f | ||
|
a62f6f5600 | ||
|
ae18b28dd1 | ||
|
d2e16f2ce1 | ||
|
1695974187 | ||
|
3d9bddb30b | ||
|
e9a9a5b605 | ||
|
2c90784abf | ||
|
011209e19f | ||
|
bbb8a1b455 | ||
|
afb49896fa | ||
|
72866e823e | ||
|
a5ed2de10a | ||
|
836d6ed96e | ||
|
c017230d9b | ||
|
944eea962b | ||
|
2ef6175aa7 | ||
|
a763551ad5 | ||
|
de77914e50 | ||
|
a5f54290ce | ||
|
6b1b144019 | ||
|
a199b2b6a5 | ||
|
1d10b44546 | ||
|
13d7adf92a | ||
|
3ef9622182 | ||
|
0380aef323 | ||
|
3ee933c9d4 | ||
|
052367ba85 | ||
|
adbfc34103 | ||
|
972b09c219 | ||
|
fbab9ccbdb | ||
|
efde4b6252 | ||
|
e67c399363 | ||
|
dc83cd427b | ||
|
7d2d3e74e5 | ||
|
318df29e10 | ||
|
356b4ca2bb | ||
|
dfb12bf86e | ||
|
d11c8917b2 | ||
|
68c70af16d | ||
|
5496fb1aeb | ||
|
5f0c39e598 | ||
|
4618e658e6 | ||
|
01c2b265fc | ||
|
04bc7c0e38 | ||
|
d61563b235 | ||
|
3775ec6f5a | ||
|
b1422f2040 | ||
|
e8817e7b0e | ||
|
6815bce542 | ||
|
ce782938b8 | ||
|
826b6ca0b0 | ||
|
920beae103 | ||
|
8d24cce1e3 | ||
|
628ff68303 | ||
|
3718d8ab65 | ||
|
fbe40ff780 | ||
|
8574575f90 | ||
|
0bf7488afb | ||
|
271c0f68b4 | ||
|
bd60436936 | ||
|
4ba6fabfb4 | ||
|
7cf6376ae8 | ||
|
53651ec26b | ||
|
109519fd32 | ||
|
4aa23452e3 | ||
|
9474ab1487 | ||
|
2f21ff25c0 | ||
|
27aa948502 | ||
|
a1ba125c0c | ||
|
d42e3c26cd | ||
|
855ea66dd5 | ||
|
61d4b215d1 | ||
|
db6c3cd0e7 | ||
|
14c521d45e | ||
|
7ab6c10d00 | ||
|
81547d6630 | ||
|
3b685ba7bf | ||
|
1fe8141ed4 | ||
|
cca7c2f523 | ||
|
2a923c4dde | ||
|
28c9457df0 | ||
|
1b1742386c | ||
|
73fb3b764b | ||
|
68fdb6c5b0 | ||
|
d81c519c40 | ||
|
6947f05978 | ||
|
f79fbf39e2 | ||
|
6ce2faf43c | ||
|
c119779543 | ||
|
a99caa48d8 | ||
|
9d4c4e872e | ||
|
f0aff25570 | ||
|
fc37b7a0b0 | ||
|
9ef137cad6 | ||
|
93f94f9018 | ||
|
00d0f7cb66 | ||
|
57a740514d | ||
|
ca3164df4d | ||
|
433d33c555 | ||
|
8977bd111f | ||
|
f85d28316a | ||
|
ee8c0b622c | ||
|
6f5943cf45 | ||
|
8b84286f4c | ||
|
1ff5eedd1d | ||
|
86846bfe64 | ||
|
2386a90730 | ||
|
11c7fa7fa6 | ||
|
f5c0ab1312 | ||
|
1687a089f1 | ||
|
116d554601 | ||
|
1fba509527 | ||
|
69e995040c | ||
|
8d1bd3c901 | ||
|
56a9f18051 | ||
|
b664b80f19 | ||
|
19e8393170 | ||
|
22513a9b44 | ||
|
68206d7342 | ||
|
36084d7e31 | ||
|
f995523582 | ||
|
058fdcf52c | ||
|
463c534db5 | ||
|
6fa2769751 | ||
|
82fc18099a | ||
|
0f61a61df3 | ||
|
3158a3482b | ||
|
aa0a55d42d | ||
|
0c77a37f11 | ||
|
99623c90d1 | ||
|
2884cf5b93 | ||
|
4eeaa3a885 | ||
|
746b867030 | ||
|
4c638e2e4b | ||
|
1c856da57b | ||
|
74444bc198 | ||
|
cdeb7090ee | ||
|
d3ef575080 | ||
|
6a24ced5ca | ||
|
ed1132e41a | ||
|
e3500d1f5f | ||
|
271a25c0b6 | ||
|
832189c9b1 | ||
|
0fb20d1c39 | ||
|
ee5f31e48b | ||
|
6fe83074d7 | ||
|
3f9a6e852e | ||
|
fd07d07ba9 | ||
|
aea7947c74 | ||
|
b35e3ba01a | ||
|
521a580d23 | ||
|
afff2b15e8 | ||
|
d09b8fa161 | ||
|
25156d1061 | ||
|
4e7d30a22a | ||
|
f7bbcfb5c3 | ||
|
a946ce8020 | ||
|
b6bfeea92a | ||
|
33fac20bb2 | ||
|
3401fd259e | ||
|
1db1c4d7d9 | ||
|
9a2f0bfe32 | ||
|
c068896f7f | ||
|
fd1cf66630 | ||
|
4f048535cd | ||
|
741f117d9a | ||
|
22ee3a987d | ||
|
070603f62b | ||
|
ac0f3b1263 | ||
|
1c4182687e | ||
|
f216a35f36 | ||
|
6c530e32f4 | ||
|
418839044e | ||
|
fbef2cc80f | ||
|
ce0236cfbd | ||
|
9d8bf2d125 | ||
|
f9a716325f | ||
|
7dae901d2d | ||
|
f8c9eddb2b | ||
|
483c76e140 | ||
|
479eb12108 | ||
|
42119fa356 | ||
|
26b78f4d3c | ||
|
f33a984d51 | ||
|
fa5912a17b | ||
|
124fe7fb1b | ||
|
d357e3d9d2 | ||
|
5b9d313e3f | ||
|
8cd05ab65a | ||
|
9c132c7f64 | ||
|
0971f1bed2 | ||
|
b645000e1a | ||
|
e35f29ded3 | ||
|
1a3de8dbec | ||
|
9e04c683fc | ||
|
5672ee54d5 | ||
|
36af599417 | ||
|
aef553fdca | ||
|
78a4b8d205 | ||
|
a3abb29292 | ||
|
178ac111bc | ||
|
6054d883d6 | ||
|
5118dc5975 | ||
|
45e66b7beb | ||
|
65903a8b08 | ||
|
fc13d93726 | ||
|
3478881130 | ||
|
d2e064a73e | ||
|
3894c78764 | ||
|
0aff637e92 | ||
|
5f758366c0 | ||
|
3f9286b721 | ||
|
3b69595068 | ||
|
5a7733b0b7 | ||
|
770a63792b | ||
|
b30f4dfbda | ||
|
8e4e86afa5 | ||
|
76eb98d51c | ||
|
d426d9fba8 | ||
|
7bca3892cb | ||
|
03cf077ac9 | ||
|
7b35d0c44c | ||
|
61c7bbd236 | ||
|
ca8c0fab95 | ||
|
f2564d88fe | ||
|
b1fe60cd35 | ||
|
a2554a334a | ||
|
c5fa6c86d0 | ||
|
5bc8f026dd | ||
|
465bee1da8 | ||
|
6a23082b4e | ||
|
82a402e99f | ||
|
43f35cb5e0 | ||
|
d66e5cee00 | ||
|
46485de0cb | ||
|
42eb58179b | ||
|
7159a45b2b | ||
|
ea54feff58 | ||
|
0a86cb7317 | ||
|
97a3ea5719 | ||
|
e3542c67af | ||
|
9aedd5a5d6 | ||
|
b5e51dd714 | ||
|
d530e34232 | ||
|
4ad303369c | ||
|
4993f7ea7e | ||
|
8a5eb36a1c | ||
|
9c52681277 | ||
|
26e2da7279 | ||
|
6906046169 | ||
|
395071a763 | ||
|
e88ae2264d | ||
|
91e7fcca47 | ||
|
c4ce4c4b1f | ||
|
24fd848950 | ||
|
11b389f21e | ||
|
b162b49adc | ||
|
40d19394b7 | ||
|
13e315dada | ||
|
6297d9a279 | ||
|
29136cd8a4 | ||
|
87a560c455 | ||
|
297a3646c2 | ||
|
cdaec3808e | ||
|
2ddb16a95f | ||
|
f9f3a5ecde | ||
|
be3c771796 | ||
|
192cca60ae | ||
|
4fa953f20d | ||
|
468866b816 | ||
|
e2cd0f4fb4 | ||
|
cbc95538ed | ||
|
f9bee751be | ||
|
6e2bb3ec70 | ||
|
6a86dec619 | ||
|
3d2acaa308 | ||
|
5917af812e | ||
|
b03c38057b | ||
|
dbe5c58f2a | ||
|
d383c625e2 | ||
|
4522b69c6c | ||
|
23335f6273 | ||
|
34bb4d02e0 | ||
|
6ee143a0a4 | ||
|
4bbeb8b173 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@
|
||||
/config-host.*
|
||||
/config-target.*
|
||||
/config.status
|
||||
/config-temp
|
||||
/trace/generated-tracers.h
|
||||
/trace/generated-tracers.c
|
||||
/trace/generated-tracers-dtrace.h
|
||||
|
10
MAINTAINERS
10
MAINTAINERS
@@ -243,8 +243,8 @@ S: Maintained
|
||||
F: hw/*/exynos*
|
||||
|
||||
Calxeda Highbank
|
||||
M: Mark Langsdorf <mark.langsdorf@calxeda.com>
|
||||
S: Supported
|
||||
M: Rob Herring <robh@kernel.org>
|
||||
S: Maintained
|
||||
F: hw/arm/highbank.c
|
||||
F: hw/net/xgmac.c
|
||||
|
||||
@@ -659,6 +659,12 @@ S: Supported
|
||||
F: hw/block/nvme*
|
||||
F: tests/nvme-test.c
|
||||
|
||||
megasas
|
||||
M: Hannes Reinecke <hare@suse.de>
|
||||
S: Supported
|
||||
F: hw/scsi/megasas.c
|
||||
F: hw/scsi/mfi.h
|
||||
|
||||
Xilinx EDK
|
||||
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
|
32
arch_init.c
32
arch_init.c
@@ -975,12 +975,12 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
||||
xh_len = qemu_get_be16(f);
|
||||
|
||||
if (xh_flags != ENCODING_FLAG_XBZRLE) {
|
||||
fprintf(stderr, "Failed to load XBZRLE page - wrong compression!\n");
|
||||
error_report("Failed to load XBZRLE page - wrong compression!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xh_len > TARGET_PAGE_SIZE) {
|
||||
fprintf(stderr, "Failed to load XBZRLE page - len overflow!\n");
|
||||
error_report("Failed to load XBZRLE page - len overflow!");
|
||||
return -1;
|
||||
}
|
||||
/* load data and decode */
|
||||
@@ -989,7 +989,7 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
||||
/* decode RLE */
|
||||
if (xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
|
||||
TARGET_PAGE_SIZE) == -1) {
|
||||
fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
|
||||
error_report("Failed to load XBZRLE page - decode error!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1006,7 +1006,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
|
||||
if (flags & RAM_SAVE_FLAG_CONTINUE) {
|
||||
if (!block) {
|
||||
fprintf(stderr, "Ack, bad migration stream!\n");
|
||||
error_report("Ack, bad migration stream!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1022,7 +1022,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
return memory_region_get_ram_ptr(block->mr) + offset;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Can't find block %s!\n", id);
|
||||
error_report("Can't find block %s!", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1075,10 +1075,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (!strncmp(id, block->idstr, sizeof(id))) {
|
||||
if (block->length != length) {
|
||||
fprintf(stderr,
|
||||
"Length mismatch: %s: " RAM_ADDR_FMT
|
||||
" in != " RAM_ADDR_FMT "\n", id, length,
|
||||
block->length);
|
||||
error_report("Length mismatch: %s: " RAM_ADDR_FMT
|
||||
" in != " RAM_ADDR_FMT, id, length,
|
||||
block->length);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
@@ -1087,8 +1086,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
}
|
||||
|
||||
if (!block) {
|
||||
fprintf(stderr, "Unknown ramblock \"%s\", cannot "
|
||||
"accept migration\n", id);
|
||||
error_report("Unknown ramblock \"%s\", cannot "
|
||||
"accept migration", id);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
@@ -1243,12 +1242,11 @@ void select_soundhw(const char *optarg)
|
||||
|
||||
if (!c->name) {
|
||||
if (l > 80) {
|
||||
fprintf(stderr,
|
||||
"Unknown sound card name (too big to show)\n");
|
||||
error_report("Unknown sound card name (too big to show)");
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Unknown sound card name `%.*s'\n",
|
||||
(int) l, p);
|
||||
error_report("Unknown sound card name `%.*s'",
|
||||
(int) l, p);
|
||||
}
|
||||
bad_card = 1;
|
||||
}
|
||||
@@ -1271,13 +1269,13 @@ void audio_init(void)
|
||||
if (c->enabled) {
|
||||
if (c->isa) {
|
||||
if (!isa_bus) {
|
||||
fprintf(stderr, "ISA bus not available for %s\n", c->name);
|
||||
error_report("ISA bus not available for %s", c->name);
|
||||
exit(1);
|
||||
}
|
||||
c->init.init_isa(isa_bus);
|
||||
} else {
|
||||
if (!pci_bus) {
|
||||
fprintf(stderr, "PCI bus not available for %s\n", c->name);
|
||||
error_report("PCI bus not available for %s", c->name);
|
||||
exit(1);
|
||||
}
|
||||
c->init.init_pci(pci_bus);
|
||||
|
@@ -105,7 +105,7 @@ static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
|
||||
bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
|
||||
samples = (bytes - rate->bytes_sent) >> info->shift;
|
||||
if (samples < 0 || samples > 65536) {
|
||||
fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples);
|
||||
error_report("Resetting rate control (%" PRId64 " samples)", samples);
|
||||
rate_start (rate);
|
||||
samples = 0;
|
||||
}
|
||||
|
@@ -63,8 +63,7 @@ static void wav_destroy (void *opaque)
|
||||
}
|
||||
doclose:
|
||||
if (fclose (wav->f)) {
|
||||
fprintf (stderr, "wav_destroy: fclose failed: %s",
|
||||
strerror (errno));
|
||||
error_report("wav_destroy: fclose failed: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -59,6 +59,7 @@ typedef struct BlkMigDevState {
|
||||
unsigned long *aio_bitmap;
|
||||
int64_t completed_sectors;
|
||||
BdrvDirtyBitmap *dirty_bitmap;
|
||||
Error *blocker;
|
||||
} BlkMigDevState;
|
||||
|
||||
typedef struct BlkMigBlock {
|
||||
@@ -361,7 +362,8 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
|
||||
bmds->completed_sectors = 0;
|
||||
bmds->shared_base = block_mig_state.shared_base;
|
||||
alloc_aio_bitmap(bmds);
|
||||
bdrv_set_in_use(bs, 1);
|
||||
error_setg(&bmds->blocker, "block device is in use by migration");
|
||||
bdrv_op_block_all(bs, bmds->blocker);
|
||||
bdrv_ref(bs);
|
||||
|
||||
block_mig_state.total_sector_sum += sectors;
|
||||
@@ -599,7 +601,8 @@ static void blk_mig_cleanup(void)
|
||||
blk_mig_lock();
|
||||
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
|
||||
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
|
||||
bdrv_set_in_use(bmds->bs, 0);
|
||||
bdrv_op_unblock_all(bmds->bs, bmds->blocker);
|
||||
error_free(bmds->blocker);
|
||||
bdrv_unref(bmds->bs);
|
||||
g_free(bmds->aio_bitmap);
|
||||
g_free(bmds);
|
||||
|
212
block.c
212
block.c
@@ -335,6 +335,7 @@ void bdrv_register(BlockDriver *bdrv)
|
||||
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
int i;
|
||||
|
||||
if (bdrv_find(device_name)) {
|
||||
error_setg(errp, "Device with id '%s' already exists",
|
||||
@@ -353,6 +354,9 @@ BlockDriverState *bdrv_new(const char *device_name, Error **errp)
|
||||
if (device_name[0] != '\0') {
|
||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
|
||||
}
|
||||
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
|
||||
QLIST_INIT(&bs->op_blockers[i]);
|
||||
}
|
||||
bdrv_iostatus_disable(bs);
|
||||
notifier_list_init(&bs->close_notifiers);
|
||||
notifier_with_return_list_init(&bs->before_write_notifiers);
|
||||
@@ -1090,6 +1094,37 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
||||
{
|
||||
|
||||
if (bs->backing_hd) {
|
||||
assert(bs->backing_blocker);
|
||||
bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker);
|
||||
} else if (backing_hd) {
|
||||
error_setg(&bs->backing_blocker,
|
||||
"device is used as backing hd of '%s'",
|
||||
bs->device_name);
|
||||
}
|
||||
|
||||
bs->backing_hd = backing_hd;
|
||||
if (!backing_hd) {
|
||||
error_free(bs->backing_blocker);
|
||||
bs->backing_blocker = NULL;
|
||||
goto out;
|
||||
}
|
||||
bs->open_flags &= ~BDRV_O_NO_BACKING;
|
||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
|
||||
pstrcpy(bs->backing_format, sizeof(bs->backing_format),
|
||||
backing_hd->drv ? backing_hd->drv->format_name : "");
|
||||
|
||||
bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
|
||||
/* Otherwise we won't be able to commit due to check in bdrv_commit */
|
||||
bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT,
|
||||
bs->backing_blocker);
|
||||
out:
|
||||
bdrv_refresh_limits(bs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens the backing file for a BlockDriverState if not yet open
|
||||
*
|
||||
@@ -1103,6 +1138,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
char *backing_filename = g_malloc0(PATH_MAX);
|
||||
int ret = 0;
|
||||
BlockDriver *back_drv = NULL;
|
||||
BlockDriverState *backing_hd;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (bs->backing_hd != NULL) {
|
||||
@@ -1125,30 +1161,26 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX);
|
||||
}
|
||||
|
||||
backing_hd = bdrv_new("", errp);
|
||||
|
||||
if (bs->backing_format[0] != '\0') {
|
||||
back_drv = bdrv_find_format(bs->backing_format);
|
||||
}
|
||||
|
||||
assert(bs->backing_hd == NULL);
|
||||
ret = bdrv_open(&bs->backing_hd,
|
||||
ret = bdrv_open(&backing_hd,
|
||||
*backing_filename ? backing_filename : NULL, NULL, options,
|
||||
bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
|
||||
if (ret < 0) {
|
||||
bs->backing_hd = NULL;
|
||||
bdrv_unref(backing_hd);
|
||||
backing_hd = NULL;
|
||||
bs->open_flags |= BDRV_O_NO_BACKING;
|
||||
error_setg(errp, "Could not open backing file: %s",
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
goto free_exit;
|
||||
}
|
||||
|
||||
if (bs->backing_hd->file) {
|
||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
|
||||
bs->backing_hd->file->filename);
|
||||
}
|
||||
|
||||
/* Recalculate the BlockLimits with the backing file */
|
||||
bdrv_refresh_limits(bs);
|
||||
bdrv_set_backing_hd(bs, backing_hd);
|
||||
|
||||
free_exit:
|
||||
g_free(backing_filename);
|
||||
@@ -1274,6 +1306,33 @@ out:
|
||||
g_free(tmp_filename);
|
||||
}
|
||||
|
||||
static QDict *parse_json_filename(const char *filename, Error **errp)
|
||||
{
|
||||
QObject *options_obj;
|
||||
QDict *options;
|
||||
int ret;
|
||||
|
||||
ret = strstart(filename, "json:", &filename);
|
||||
assert(ret);
|
||||
|
||||
options_obj = qobject_from_json(filename);
|
||||
if (!options_obj) {
|
||||
error_setg(errp, "Could not parse the JSON options");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qobject_type(options_obj) != QTYPE_QDICT) {
|
||||
qobject_decref(options_obj);
|
||||
error_setg(errp, "Invalid JSON object given");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
options = qobject_to_qdict(options_obj);
|
||||
qdict_flatten(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens a disk image (raw, qcow2, vmdk, ...)
|
||||
*
|
||||
@@ -1337,6 +1396,20 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
options = qdict_new();
|
||||
}
|
||||
|
||||
if (filename && g_str_has_prefix(filename, "json:")) {
|
||||
QDict *json_options = parse_json_filename(filename, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Options given in the filename have lower priority than options
|
||||
* specified directly */
|
||||
qdict_join(options, json_options, false);
|
||||
QDECREF(json_options);
|
||||
filename = NULL;
|
||||
}
|
||||
|
||||
bs->options = options;
|
||||
options = qdict_clone_shallow(options);
|
||||
|
||||
@@ -1743,8 +1816,9 @@ void bdrv_close(BlockDriverState *bs)
|
||||
|
||||
if (bs->drv) {
|
||||
if (bs->backing_hd) {
|
||||
bdrv_unref(bs->backing_hd);
|
||||
bs->backing_hd = NULL;
|
||||
BlockDriverState *backing_hd = bs->backing_hd;
|
||||
bdrv_set_backing_hd(bs, NULL);
|
||||
bdrv_unref(backing_hd);
|
||||
}
|
||||
bs->drv->bdrv_close(bs);
|
||||
g_free(bs->opaque);
|
||||
@@ -1904,13 +1978,14 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||
bs_dest->refcnt = bs_src->refcnt;
|
||||
|
||||
/* job */
|
||||
bs_dest->in_use = bs_src->in_use;
|
||||
bs_dest->job = bs_src->job;
|
||||
|
||||
/* keep the same entry in bdrv_states */
|
||||
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
|
||||
bs_src->device_name);
|
||||
bs_dest->device_list = bs_src->device_list;
|
||||
memcpy(bs_dest->op_blockers, bs_src->op_blockers,
|
||||
sizeof(bs_dest->op_blockers));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1945,7 +2020,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
||||
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
|
||||
assert(bs_new->job == NULL);
|
||||
assert(bs_new->dev == NULL);
|
||||
assert(bs_new->in_use == 0);
|
||||
assert(bs_new->io_limits_enabled == false);
|
||||
assert(!throttle_have_timer(&bs_new->throttle_state));
|
||||
|
||||
@@ -1964,7 +2038,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
||||
/* Check a few fields that should remain attached to the device */
|
||||
assert(bs_new->dev == NULL);
|
||||
assert(bs_new->job == NULL);
|
||||
assert(bs_new->in_use == 0);
|
||||
assert(bs_new->io_limits_enabled == false);
|
||||
assert(!throttle_have_timer(&bs_new->throttle_state));
|
||||
|
||||
@@ -1997,19 +2070,14 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
|
||||
|
||||
/* The contents of 'tmp' will become bs_top, as we are
|
||||
* swapping bs_new and bs_top contents. */
|
||||
bs_top->backing_hd = bs_new;
|
||||
bs_top->open_flags &= ~BDRV_O_NO_BACKING;
|
||||
pstrcpy(bs_top->backing_file, sizeof(bs_top->backing_file),
|
||||
bs_new->filename);
|
||||
pstrcpy(bs_top->backing_format, sizeof(bs_top->backing_format),
|
||||
bs_new->drv ? bs_new->drv->format_name : "");
|
||||
bdrv_set_backing_hd(bs_top, bs_new);
|
||||
}
|
||||
|
||||
static void bdrv_delete(BlockDriverState *bs)
|
||||
{
|
||||
assert(!bs->dev);
|
||||
assert(!bs->job);
|
||||
assert(!bs->in_use);
|
||||
assert(bdrv_op_blocker_is_empty(bs));
|
||||
assert(!bs->refcnt);
|
||||
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
|
||||
|
||||
@@ -2191,7 +2259,8 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bdrv_in_use(bs) || bdrv_in_use(bs->backing_hd)) {
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, NULL) ||
|
||||
bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, NULL)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -2595,13 +2664,11 @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
|
||||
if (ret) {
|
||||
goto exit;
|
||||
}
|
||||
new_top_bs->backing_hd = base_bs;
|
||||
|
||||
bdrv_refresh_limits(new_top_bs);
|
||||
bdrv_set_backing_hd(new_top_bs, base_bs);
|
||||
|
||||
QSIMPLEQ_FOREACH_SAFE(intermediate_state, &states_to_delete, entry, next) {
|
||||
/* so that bdrv_close() does not recursively close the chain */
|
||||
intermediate_state->bs->backing_hd = NULL;
|
||||
bdrv_set_backing_hd(intermediate_state->bs, NULL);
|
||||
bdrv_unref(intermediate_state->bs);
|
||||
}
|
||||
ret = 0;
|
||||
@@ -3248,6 +3315,15 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
|
||||
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||
|
||||
if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF &&
|
||||
!(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_write_zeroes &&
|
||||
qemu_iovec_is_zero(qiov)) {
|
||||
flags |= BDRV_REQ_ZERO_WRITE;
|
||||
if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) {
|
||||
flags |= BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
/* Do nothing, write notifier decided to fail this request */
|
||||
} else if (flags & BDRV_REQ_ZERO_WRITE) {
|
||||
@@ -3444,8 +3520,9 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
|
||||
return -ENOTSUP;
|
||||
if (bs->read_only)
|
||||
return -EACCES;
|
||||
if (bdrv_in_use(bs))
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
ret = drv->bdrv_truncate(bs, offset);
|
||||
if (ret == 0) {
|
||||
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
|
||||
@@ -3864,7 +3941,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
|
||||
if (!bs->drv->bdrv_co_get_block_status) {
|
||||
*pnum = nb_sectors;
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
|
||||
if (bs->drv->protocol_name) {
|
||||
ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
@@ -3883,6 +3960,10 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
*pnum, pnum);
|
||||
}
|
||||
|
||||
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
|
||||
ret |= BDRV_BLOCK_ALLOCATED;
|
||||
}
|
||||
|
||||
if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) {
|
||||
if (bdrv_unallocated_blocks_are_zero(bs)) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
@@ -3959,9 +4040,7 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return
|
||||
(ret & BDRV_BLOCK_DATA) ||
|
||||
((ret & BDRV_BLOCK_ZERO) && !bdrv_has_zero_init(bs));
|
||||
return (ret & BDRV_BLOCK_ALLOCATED);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5273,15 +5352,74 @@ void bdrv_unref(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_set_in_use(BlockDriverState *bs, int in_use)
|
||||
struct BdrvOpBlocker {
|
||||
Error *reason;
|
||||
QLIST_ENTRY(BdrvOpBlocker) list;
|
||||
};
|
||||
|
||||
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
|
||||
{
|
||||
assert(bs->in_use != in_use);
|
||||
bs->in_use = in_use;
|
||||
BdrvOpBlocker *blocker;
|
||||
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
|
||||
if (!QLIST_EMPTY(&bs->op_blockers[op])) {
|
||||
blocker = QLIST_FIRST(&bs->op_blockers[op]);
|
||||
if (errp) {
|
||||
error_setg(errp, "Device '%s' is busy: %s",
|
||||
bs->device_name, error_get_pretty(blocker->reason));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int bdrv_in_use(BlockDriverState *bs)
|
||||
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason)
|
||||
{
|
||||
return bs->in_use;
|
||||
BdrvOpBlocker *blocker;
|
||||
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
|
||||
|
||||
blocker = g_malloc0(sizeof(BdrvOpBlocker));
|
||||
blocker->reason = reason;
|
||||
QLIST_INSERT_HEAD(&bs->op_blockers[op], blocker, list);
|
||||
}
|
||||
|
||||
void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason)
|
||||
{
|
||||
BdrvOpBlocker *blocker, *next;
|
||||
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
|
||||
QLIST_FOREACH_SAFE(blocker, &bs->op_blockers[op], list, next) {
|
||||
if (blocker->reason == reason) {
|
||||
QLIST_REMOVE(blocker, list);
|
||||
g_free(blocker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_op_block_all(BlockDriverState *bs, Error *reason)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
|
||||
bdrv_op_block(bs, i, reason);
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
|
||||
bdrv_op_unblock(bs, i, reason);
|
||||
}
|
||||
}
|
||||
|
||||
bool bdrv_op_blocker_is_empty(BlockDriverState *bs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
|
||||
if (!QLIST_EMPTY(&bs->op_blockers[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void bdrv_iostatus_enable(BlockDriverState *bs)
|
||||
|
79
block/curl.c
79
block/curl.c
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
// #define DEBUG
|
||||
@@ -37,6 +38,21 @@
|
||||
#if LIBCURL_VERSION_NUM >= 0x071000
|
||||
/* The multi interface timer callback was introduced in 7.16.0 */
|
||||
#define NEED_CURL_TIMER_CALLBACK
|
||||
#define HAVE_SOCKET_ACTION
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SOCKET_ACTION
|
||||
/* If curl_multi_socket_action isn't available, define it statically here in
|
||||
* terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
|
||||
* less efficient but still safe. */
|
||||
static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
||||
curl_socket_t sockfd,
|
||||
int ev_bitmask,
|
||||
int *running_handles)
|
||||
{
|
||||
return curl_multi_socket(multi_handle, sockfd, running_handles);
|
||||
}
|
||||
#define curl_multi_socket_action __curl_multi_socket_action
|
||||
#endif
|
||||
|
||||
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
|
||||
@@ -46,12 +62,16 @@
|
||||
#define CURL_NUM_STATES 8
|
||||
#define CURL_NUM_ACB 8
|
||||
#define SECTOR_SIZE 512
|
||||
#define READ_AHEAD_SIZE (256 * 1024)
|
||||
#define READ_AHEAD_DEFAULT (256 * 1024)
|
||||
|
||||
#define FIND_RET_NONE 0
|
||||
#define FIND_RET_OK 1
|
||||
#define FIND_RET_WAIT 2
|
||||
|
||||
#define CURL_BLOCK_OPT_URL "url"
|
||||
#define CURL_BLOCK_OPT_READAHEAD "readahead"
|
||||
#define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
|
||||
|
||||
struct BDRVCURLState;
|
||||
|
||||
typedef struct CURLAIOCB {
|
||||
@@ -88,6 +108,7 @@ typedef struct BDRVCURLState {
|
||||
CURLState states[CURL_NUM_STATES];
|
||||
char *url;
|
||||
size_t readahead_size;
|
||||
bool sslverify;
|
||||
bool accept_range;
|
||||
} BDRVCURLState;
|
||||
|
||||
@@ -354,6 +375,8 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
||||
return NULL;
|
||||
}
|
||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||
curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
|
||||
(long) s->sslverify);
|
||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
|
||||
(void *)curl_read_cb);
|
||||
@@ -396,43 +419,7 @@ static void curl_clean_state(CURLState *s)
|
||||
static void curl_parse_filename(const char *filename, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
#define RA_OPTSTR ":readahead="
|
||||
char *file;
|
||||
char *ra;
|
||||
const char *ra_val;
|
||||
int parse_state = 0;
|
||||
|
||||
file = g_strdup(filename);
|
||||
|
||||
/* Parse a trailing ":readahead=#:" param, if present. */
|
||||
ra = file + strlen(file) - 1;
|
||||
while (ra >= file) {
|
||||
if (parse_state == 0) {
|
||||
if (*ra == ':') {
|
||||
parse_state++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (parse_state == 1) {
|
||||
if (*ra > '9' || *ra < '0') {
|
||||
char *opt_start = ra - strlen(RA_OPTSTR) + 1;
|
||||
if (opt_start > file &&
|
||||
strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
|
||||
ra_val = ra + 1;
|
||||
ra -= strlen(RA_OPTSTR) - 1;
|
||||
*ra = '\0';
|
||||
qdict_put(options, "readahead", qstring_from_str(ra_val));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ra--;
|
||||
}
|
||||
|
||||
qdict_put(options, "url", qstring_from_str(file));
|
||||
|
||||
g_free(file);
|
||||
qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
|
||||
}
|
||||
|
||||
static QemuOptsList runtime_opts = {
|
||||
@@ -440,15 +427,20 @@ static QemuOptsList runtime_opts = {
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "url",
|
||||
.name = CURL_BLOCK_OPT_URL,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "URL to open",
|
||||
},
|
||||
{
|
||||
.name = "readahead",
|
||||
.name = CURL_BLOCK_OPT_READAHEAD,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Readahead size",
|
||||
},
|
||||
{
|
||||
.name = CURL_BLOCK_OPT_SSLVERIFY,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Verify SSL certificate"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -477,14 +469,17 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
|
||||
s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
|
||||
READ_AHEAD_DEFAULT);
|
||||
if ((s->readahead_size & 0x1ff) != 0) {
|
||||
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
|
||||
s->readahead_size);
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
file = qemu_opt_get(opts, "url");
|
||||
s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
|
||||
|
||||
file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
|
||||
if (file == NULL) {
|
||||
error_setg(errp, "curl block driver requires an 'url' option");
|
||||
goto out_noclean;
|
||||
|
317
block/iscsi.c
317
block/iscsi.c
@@ -30,6 +30,8 @@
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "block/block_int.h"
|
||||
#include "trace.h"
|
||||
#include "block/scsi.h"
|
||||
@@ -59,6 +61,8 @@ typedef struct IscsiLun {
|
||||
struct scsi_inquiry_logical_block_provisioning lbp;
|
||||
struct scsi_inquiry_block_limits bl;
|
||||
unsigned char *zeroblock;
|
||||
unsigned long *allocationmap;
|
||||
int cluster_sectors;
|
||||
} IscsiLun;
|
||||
|
||||
typedef struct IscsiTask {
|
||||
@@ -92,6 +96,15 @@ typedef struct IscsiAIOCB {
|
||||
#define MAX_NOP_FAILURES 3
|
||||
#define ISCSI_CMD_RETRIES 5
|
||||
|
||||
/* this threshhold is a trade-off knob to choose between
|
||||
* the potential additional overhead of an extra GET_LBA_STATUS request
|
||||
* vs. unnecessarily reading a lot of zero sectors over the wire.
|
||||
* If a read request is greater or equal than ISCSI_CHECKALLOC_THRES
|
||||
* sectors we check the allocation status of the area covered by the
|
||||
* request first if the allocationmap indicates that the area might be
|
||||
* unallocated. */
|
||||
#define ISCSI_CHECKALLOC_THRES 64
|
||||
|
||||
static void
|
||||
iscsi_bh_cb(void *p)
|
||||
{
|
||||
@@ -273,6 +286,32 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void iscsi_allocationmap_set(IscsiLun *iscsilun, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
return;
|
||||
}
|
||||
bitmap_set(iscsilun->allocationmap,
|
||||
sector_num / iscsilun->cluster_sectors,
|
||||
DIV_ROUND_UP(nb_sectors, iscsilun->cluster_sectors));
|
||||
}
|
||||
|
||||
static void iscsi_allocationmap_clear(IscsiLun *iscsilun, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
int64_t cluster_num, nb_clusters;
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
return;
|
||||
}
|
||||
cluster_num = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors);
|
||||
nb_clusters = (sector_num + nb_sectors) / iscsilun->cluster_sectors
|
||||
- cluster_num;
|
||||
if (nb_clusters > 0) {
|
||||
bitmap_clear(iscsilun->allocationmap, cluster_num, nb_clusters);
|
||||
}
|
||||
}
|
||||
|
||||
static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
@@ -336,9 +375,125 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
unsigned long size;
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
return true;
|
||||
}
|
||||
size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors);
|
||||
return !(find_next_bit(iscsilun->allocationmap, size,
|
||||
sector_num / iscsilun->cluster_sectors) == size);
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct scsi_get_lba_status *lbas = NULL;
|
||||
struct scsi_lba_status_descriptor *lbasd = NULL;
|
||||
struct IscsiTask iTask;
|
||||
int64_t ret;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* default to all sectors allocated */
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
|
||||
*pnum = nb_sectors;
|
||||
|
||||
/* LUN does not support logical block provisioning */
|
||||
if (iscsilun->lbpme == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
retry:
|
||||
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
8 + 16, iscsi_co_generic_cb,
|
||||
&iTask) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
/* in case the get_lba_status_callout fails (i.e.
|
||||
* because the device is busy or the cmd is not
|
||||
* supported) we pretend all blocks are allocated
|
||||
* for backwards compatibility */
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbas = scsi_datain_unmarshall(iTask.task);
|
||||
if (lbas == NULL) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbasd = &lbas->descriptors[0];
|
||||
|
||||
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
|
||||
|
||||
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
|
||||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
|
||||
ret &= ~BDRV_BLOCK_DATA;
|
||||
if (iscsilun->lbprz) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret & BDRV_BLOCK_ZERO) {
|
||||
iscsi_allocationmap_clear(iscsilun, sector_num, *pnum);
|
||||
} else {
|
||||
iscsi_allocationmap_set(iscsilun, sector_num, *pnum);
|
||||
}
|
||||
|
||||
if (*pnum > nb_sectors) {
|
||||
*pnum = nb_sectors;
|
||||
}
|
||||
out:
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* LIBISCSI_FEATURE_IOVECTOR */
|
||||
|
||||
|
||||
static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
@@ -355,6 +510,22 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
if (iscsilun->lbprz && nb_sectors >= ISCSI_CHECKALLOC_THRES &&
|
||||
!iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
|
||||
int64_t ret;
|
||||
int pnum;
|
||||
ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (ret & BDRV_BLOCK_ZERO && pnum >= nb_sectors) {
|
||||
qemu_iovec_memset(iov, 0, 0x00, iov->size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
|
||||
@@ -643,101 +814,6 @@ iscsi_getlength(BlockDriverState *bs)
|
||||
return len;
|
||||
}
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
|
||||
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct scsi_get_lba_status *lbas = NULL;
|
||||
struct scsi_lba_status_descriptor *lbasd = NULL;
|
||||
struct IscsiTask iTask;
|
||||
int64_t ret;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* default to all sectors allocated */
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
|
||||
*pnum = nb_sectors;
|
||||
|
||||
/* LUN does not support logical block provisioning */
|
||||
if (iscsilun->lbpme == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
retry:
|
||||
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
8 + 16, iscsi_co_generic_cb,
|
||||
&iTask) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
/* in case the get_lba_status_callout fails (i.e.
|
||||
* because the device is busy or the cmd is not
|
||||
* supported) we pretend all blocks are allocated
|
||||
* for backwards compatibility */
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbas = scsi_datain_unmarshall(iTask.task);
|
||||
if (lbas == NULL) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbasd = &lbas->descriptors[0];
|
||||
|
||||
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
|
||||
if (*pnum > nb_sectors) {
|
||||
*pnum = nb_sectors;
|
||||
}
|
||||
|
||||
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
|
||||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
|
||||
ret &= ~BDRV_BLOCK_DATA;
|
||||
if (iscsilun->lbprz) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* LIBISCSI_FEATURE_IOVECTOR */
|
||||
|
||||
static int
|
||||
coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
@@ -791,6 +867,8 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -809,13 +887,14 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
||||
/* WRITE SAME without UNMAP is not supported by the target */
|
||||
return -ENOTSUP;
|
||||
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||
/* WRITE SAME with UNMAP is not supported by the target,
|
||||
* fall back and try WRITE SAME without UNMAP */
|
||||
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
|
||||
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||
/* WRITE SAME with UNMAP is not supported by the target */
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
||||
/* WRITE SAME without UNMAP is not supported by the target */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -864,6 +943,12 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (flags & BDRV_REQ_MAY_UNMAP) {
|
||||
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
|
||||
} else {
|
||||
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1295,6 +1380,22 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
|
||||
#endif
|
||||
|
||||
/* Guess the internal cluster (page) size of the iscsi target by the means
|
||||
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
||||
* reasonable size */
|
||||
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 &&
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||
iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran *
|
||||
iscsilun->block_size) >> BDRV_SECTOR_BITS;
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) {
|
||||
iscsilun->allocationmap =
|
||||
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
||||
iscsilun->cluster_sectors));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
out:
|
||||
qemu_opts_del(opts);
|
||||
if (initiator_name != NULL) {
|
||||
@@ -1328,6 +1429,7 @@ static void iscsi_close(BlockDriverState *bs)
|
||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL);
|
||||
iscsi_destroy_context(iscsi);
|
||||
g_free(iscsilun->zeroblock);
|
||||
g_free(iscsilun->allocationmap);
|
||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||
}
|
||||
|
||||
@@ -1388,6 +1490,13 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iscsilun->allocationmap != NULL) {
|
||||
g_free(iscsilun->allocationmap);
|
||||
iscsilun->allocationmap =
|
||||
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
||||
iscsilun->cluster_sectors));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1450,13 +1559,7 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
|
||||
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
||||
/* Guess the internal cluster (page) size of the iscsi target by the means
|
||||
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
||||
* reasonable size for bdi->cluster_size */
|
||||
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 &&
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||
bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
|
||||
}
|
||||
bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -498,7 +498,7 @@ immediate_exit:
|
||||
/* drop the bs loop chain formed by the swap: break the loop then
|
||||
* trigger the unref from the top one */
|
||||
BlockDriverState *p = s->base->backing_hd;
|
||||
s->base->backing_hd = NULL;
|
||||
bdrv_set_backing_hd(s->base, NULL);
|
||||
bdrv_unref(p);
|
||||
}
|
||||
}
|
||||
|
@@ -50,6 +50,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
info->backing_file_depth = bdrv_get_backing_file_depth(bs);
|
||||
info->detect_zeroes = bs->detect_zeroes;
|
||||
|
||||
if (bs->io_limits_enabled) {
|
||||
ThrottleConfig cfg;
|
||||
|
44
block/qcow.c
44
block/qcow.c
@@ -48,9 +48,10 @@ typedef struct QCowHeader {
|
||||
uint64_t size; /* in bytes */
|
||||
uint8_t cluster_bits;
|
||||
uint8_t l2_bits;
|
||||
uint16_t padding;
|
||||
uint32_t crypt_method;
|
||||
uint64_t l1_table_offset;
|
||||
} QCowHeader;
|
||||
} QEMU_PACKED QCowHeader;
|
||||
|
||||
#define L2_CACHE_SIZE 16
|
||||
|
||||
@@ -60,7 +61,7 @@ typedef struct BDRVQcowState {
|
||||
int cluster_sectors;
|
||||
int l2_bits;
|
||||
int l2_size;
|
||||
int l1_size;
|
||||
unsigned int l1_size;
|
||||
uint64_t cluster_offset_mask;
|
||||
uint64_t l1_table_offset;
|
||||
uint64_t *l1_table;
|
||||
@@ -96,7 +97,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int len, i, shift, ret;
|
||||
unsigned int len, i, shift;
|
||||
int ret;
|
||||
QCowHeader header;
|
||||
|
||||
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
||||
@@ -127,11 +129,25 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.size <= 1 || header.cluster_bits < 9) {
|
||||
error_setg(errp, "invalid value in qcow header");
|
||||
if (header.size <= 1) {
|
||||
error_setg(errp, "Image size is too small (must be at least 2 bytes)");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (header.cluster_bits < 9 || header.cluster_bits > 16) {
|
||||
error_setg(errp, "Cluster size must be between 512 and 64k");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* l2_bits specifies number of entries; storing a uint64_t in each entry,
|
||||
* so bytes = num_entries << 3. */
|
||||
if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {
|
||||
error_setg(errp, "L2 table size must be between 512 and 64k");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||
error_setg(errp, "invalid encryption method in qcow header");
|
||||
ret = -EINVAL;
|
||||
@@ -151,7 +167,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
/* read the level 1 table */
|
||||
shift = s->cluster_bits + s->l2_bits;
|
||||
s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
|
||||
if (header.size > UINT64_MAX - (1LL << shift)) {
|
||||
error_setg(errp, "Image too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else {
|
||||
uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;
|
||||
if (l1_size > INT_MAX / sizeof(uint64_t)) {
|
||||
error_setg(errp, "Image too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
s->l1_size = l1_size;
|
||||
}
|
||||
|
||||
s->l1_table_offset = header.l1_table_offset;
|
||||
s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
|
||||
@@ -175,7 +203,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (header.backing_file_offset != 0) {
|
||||
len = header.backing_file_size;
|
||||
if (len > 1023) {
|
||||
len = 1023;
|
||||
error_setg(errp, "Backing file name too long");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||
bs->backing_file, len);
|
||||
|
@@ -379,7 +379,8 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
|
||||
|
||||
if (!bs->drv) {
|
||||
return -ENOMEDIUM;
|
||||
ret = -ENOMEDIUM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Call .bdrv_co_readv() directly instead of using the public block-layer
|
||||
|
71
block/rbd.c
71
block/rbd.c
@@ -105,7 +105,7 @@ typedef struct BDRVRBDState {
|
||||
static int qemu_rbd_next_tok(char *dst, int dst_len,
|
||||
char *src, char delim,
|
||||
const char *name,
|
||||
char **p)
|
||||
char **p, Error **errp)
|
||||
{
|
||||
int l;
|
||||
char *end;
|
||||
@@ -128,10 +128,10 @@ static int qemu_rbd_next_tok(char *dst, int dst_len,
|
||||
}
|
||||
l = strlen(src);
|
||||
if (l >= dst_len) {
|
||||
error_report("%s too long", name);
|
||||
error_setg(errp, "%s too long", name);
|
||||
return -EINVAL;
|
||||
} else if (l == 0) {
|
||||
error_report("%s too short", name);
|
||||
error_setg(errp, "%s too short", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -157,13 +157,15 @@ static int qemu_rbd_parsename(const char *filename,
|
||||
char *pool, int pool_len,
|
||||
char *snap, int snap_len,
|
||||
char *name, int name_len,
|
||||
char *conf, int conf_len)
|
||||
char *conf, int conf_len,
|
||||
Error **errp)
|
||||
{
|
||||
const char *start;
|
||||
char *p, *buf;
|
||||
int ret;
|
||||
|
||||
if (!strstart(filename, "rbd:", &start)) {
|
||||
error_setg(errp, "File name must start with 'rbd:'");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -172,7 +174,8 @@ static int qemu_rbd_parsename(const char *filename,
|
||||
*snap = '\0';
|
||||
*conf = '\0';
|
||||
|
||||
ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
|
||||
ret = qemu_rbd_next_tok(pool, pool_len, p,
|
||||
'/', "pool name", &p, errp);
|
||||
if (ret < 0 || !p) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
@@ -180,21 +183,25 @@ static int qemu_rbd_parsename(const char *filename,
|
||||
qemu_rbd_unescape(pool);
|
||||
|
||||
if (strchr(p, '@')) {
|
||||
ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
|
||||
ret = qemu_rbd_next_tok(name, name_len, p,
|
||||
'@', "object name", &p, errp);
|
||||
if (ret < 0) {
|
||||
goto done;
|
||||
}
|
||||
ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
|
||||
ret = qemu_rbd_next_tok(snap, snap_len, p,
|
||||
':', "snap name", &p, errp);
|
||||
qemu_rbd_unescape(snap);
|
||||
} else {
|
||||
ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
|
||||
ret = qemu_rbd_next_tok(name, name_len, p,
|
||||
':', "object name", &p, errp);
|
||||
}
|
||||
qemu_rbd_unescape(name);
|
||||
if (ret < 0 || !p) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = qemu_rbd_next_tok(conf, conf_len, p, '\0', "configuration", &p);
|
||||
ret = qemu_rbd_next_tok(conf, conf_len, p,
|
||||
'\0', "configuration", &p, errp);
|
||||
|
||||
done:
|
||||
g_free(buf);
|
||||
@@ -229,7 +236,7 @@ static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
|
||||
static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
||||
{
|
||||
char *p, *buf;
|
||||
char name[RBD_MAX_CONF_NAME_SIZE];
|
||||
@@ -241,20 +248,20 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
|
||||
|
||||
while (p) {
|
||||
ret = qemu_rbd_next_tok(name, sizeof(name), p,
|
||||
'=', "conf option name", &p);
|
||||
'=', "conf option name", &p, errp);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
qemu_rbd_unescape(name);
|
||||
|
||||
if (!p) {
|
||||
error_report("conf option %s has no value", name);
|
||||
error_setg(errp, "conf option %s has no value", name);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = qemu_rbd_next_tok(value, sizeof(value), p,
|
||||
':', "conf option value", &p);
|
||||
':', "conf option value", &p, errp);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
@@ -263,7 +270,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
|
||||
if (strcmp(name, "conf") == 0) {
|
||||
ret = rados_conf_read_file(cluster, value);
|
||||
if (ret < 0) {
|
||||
error_report("error reading conf file %s", value);
|
||||
error_setg(errp, "error reading conf file %s", value);
|
||||
break;
|
||||
}
|
||||
} else if (strcmp(name, "id") == 0) {
|
||||
@@ -271,7 +278,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
|
||||
} else {
|
||||
ret = rados_conf_set(cluster, name, value);
|
||||
if (ret < 0) {
|
||||
error_report("invalid conf option %s", name);
|
||||
error_setg(errp, "invalid conf option %s", name);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
@@ -285,6 +292,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
|
||||
static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int64_t bytes = 0;
|
||||
int64_t objsize;
|
||||
int obj_order = 0;
|
||||
@@ -301,7 +309,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
if (qemu_rbd_parsename(filename, pool, sizeof(pool),
|
||||
snap_buf, sizeof(snap_buf),
|
||||
name, sizeof(name),
|
||||
conf, sizeof(conf)) < 0) {
|
||||
conf, sizeof(conf), &local_err) < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -313,11 +322,11 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
if (options->value.n) {
|
||||
objsize = options->value.n;
|
||||
if ((objsize - 1) & objsize) { /* not a power of 2? */
|
||||
error_report("obj size needs to be power of 2");
|
||||
error_setg(errp, "obj size needs to be power of 2");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (objsize < 4096) {
|
||||
error_report("obj size too small");
|
||||
error_setg(errp, "obj size too small");
|
||||
return -EINVAL;
|
||||
}
|
||||
obj_order = ffs(objsize) - 1;
|
||||
@@ -328,7 +337,7 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
|
||||
clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
|
||||
if (rados_create(&cluster, clientname) < 0) {
|
||||
error_report("error initializing");
|
||||
error_setg(errp, "error initializing");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -338,20 +347,20 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
|
||||
if (conf[0] != '\0' &&
|
||||
qemu_rbd_set_conf(cluster, conf) < 0) {
|
||||
error_report("error setting config options");
|
||||
qemu_rbd_set_conf(cluster, conf, &local_err) < 0) {
|
||||
rados_shutdown(cluster);
|
||||
error_propagate(errp, local_err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (rados_connect(cluster) < 0) {
|
||||
error_report("error connecting");
|
||||
error_setg(errp, "error connecting");
|
||||
rados_shutdown(cluster);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (rados_ioctx_create(cluster, pool, &io_ctx) < 0) {
|
||||
error_report("error opening pool %s", pool);
|
||||
error_setg(errp, "error opening pool %s", pool);
|
||||
rados_shutdown(cluster);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -441,8 +450,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
qemu_opts_del(opts);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -452,7 +460,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (qemu_rbd_parsename(filename, pool, sizeof(pool),
|
||||
snap_buf, sizeof(snap_buf),
|
||||
s->name, sizeof(s->name),
|
||||
conf, sizeof(conf)) < 0) {
|
||||
conf, sizeof(conf), errp) < 0) {
|
||||
r = -EINVAL;
|
||||
goto failed_opts;
|
||||
}
|
||||
@@ -460,7 +468,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
|
||||
r = rados_create(&s->cluster, clientname);
|
||||
if (r < 0) {
|
||||
error_report("error initializing");
|
||||
error_setg(&local_err, "error initializing");
|
||||
goto failed_opts;
|
||||
}
|
||||
|
||||
@@ -488,28 +496,27 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (conf[0] != '\0') {
|
||||
r = qemu_rbd_set_conf(s->cluster, conf);
|
||||
r = qemu_rbd_set_conf(s->cluster, conf, errp);
|
||||
if (r < 0) {
|
||||
error_report("error setting config options");
|
||||
goto failed_shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
r = rados_connect(s->cluster);
|
||||
if (r < 0) {
|
||||
error_report("error connecting");
|
||||
error_setg(&local_err, "error connecting");
|
||||
goto failed_shutdown;
|
||||
}
|
||||
|
||||
r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
|
||||
if (r < 0) {
|
||||
error_report("error opening pool %s", pool);
|
||||
error_setg(&local_err, "error opening pool %s", pool);
|
||||
goto failed_shutdown;
|
||||
}
|
||||
|
||||
r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
|
||||
if (r < 0) {
|
||||
error_report("error reading header from %s", s->name);
|
||||
error_setg(&local_err, "error reading header from %s", s->name);
|
||||
goto failed_open;
|
||||
}
|
||||
|
||||
|
149
block/sheepdog.c
149
block/sheepdog.c
@@ -526,17 +526,16 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
return acb;
|
||||
}
|
||||
|
||||
static int connect_to_sdog(BDRVSheepdogState *s)
|
||||
static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
Error *err = NULL;
|
||||
|
||||
if (s->is_unix) {
|
||||
fd = unix_connect(s->host_spec, &err);
|
||||
fd = unix_connect(s->host_spec, errp);
|
||||
} else {
|
||||
fd = inet_connect(s->host_spec, &err);
|
||||
fd = inet_connect(s->host_spec, errp);
|
||||
|
||||
if (err == NULL) {
|
||||
if (fd >= 0) {
|
||||
int ret = socket_set_nodelay(fd);
|
||||
if (ret < 0) {
|
||||
error_report("%s", strerror(errno));
|
||||
@@ -544,10 +543,7 @@ static int connect_to_sdog(BDRVSheepdogState *s)
|
||||
}
|
||||
}
|
||||
|
||||
if (err != NULL) {
|
||||
qerror_report_err(err);
|
||||
error_free(err);
|
||||
} else {
|
||||
if (fd >= 0) {
|
||||
qemu_set_nonblock(fd);
|
||||
}
|
||||
|
||||
@@ -672,7 +668,7 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
enum AIOCBState aiocb_type);
|
||||
static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req);
|
||||
static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag);
|
||||
static int get_sheep_fd(BDRVSheepdogState *s);
|
||||
static int get_sheep_fd(BDRVSheepdogState *s, Error **errp);
|
||||
static void co_write_request(void *opaque);
|
||||
|
||||
static AIOReq *find_pending_req(BDRVSheepdogState *s, uint64_t oid)
|
||||
@@ -709,6 +705,7 @@ static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid)
|
||||
|
||||
static coroutine_fn void reconnect_to_sdog(void *opaque)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = opaque;
|
||||
AIOReq *aio_req, *next;
|
||||
|
||||
@@ -723,9 +720,11 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
|
||||
|
||||
/* Try to reconnect the sheepdog server every one second. */
|
||||
while (s->fd < 0) {
|
||||
s->fd = get_sheep_fd(s);
|
||||
s->fd = get_sheep_fd(s, &local_err);
|
||||
if (s->fd < 0) {
|
||||
DPRINTF("Wait for connection to be established\n");
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
co_aio_sleep_ns(bdrv_get_aio_context(s->bs), QEMU_CLOCK_REALTIME,
|
||||
1000000000ULL);
|
||||
}
|
||||
@@ -914,11 +913,11 @@ static void co_write_request(void *opaque)
|
||||
* We cannot use this descriptor for other operations because
|
||||
* the block driver may be on waiting response from the server.
|
||||
*/
|
||||
static int get_sheep_fd(BDRVSheepdogState *s)
|
||||
static int get_sheep_fd(BDRVSheepdogState *s, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, errp);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
@@ -1061,7 +1060,7 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
|
||||
|
||||
static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
||||
uint32_t snapid, const char *tag, uint32_t *vid,
|
||||
bool lock)
|
||||
bool lock, Error **errp)
|
||||
{
|
||||
int ret, fd;
|
||||
SheepdogVdiReq hdr;
|
||||
@@ -1069,7 +1068,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
||||
unsigned int wlen, rlen = 0;
|
||||
char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, errp);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
@@ -1095,12 +1094,13 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
||||
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret, "cannot get vdi info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
error_report("cannot get vdi info, %s, %s %" PRIu32 " %s",
|
||||
sd_strerror(rsp->result), filename, snapid, tag);
|
||||
error_setg(errp, "cannot get vdi info, %s, %s %" PRIu32 " %s",
|
||||
sd_strerror(rsp->result), filename, snapid, tag);
|
||||
if (rsp->result == SD_RES_NO_VDI) {
|
||||
ret = -ENOENT;
|
||||
} else {
|
||||
@@ -1263,19 +1263,24 @@ static int write_object(int fd, char *buf, uint64_t oid, uint8_t copies,
|
||||
/* update inode with the latest state */
|
||||
static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
SheepdogInode *inode;
|
||||
int ret = 0, fd;
|
||||
uint32_t vid = 0;
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
inode = g_malloc(sizeof(s->inode));
|
||||
|
||||
ret = find_vdi_name(s, s->name, snapid, tag, &vid, false);
|
||||
ret = find_vdi_name(s, s->name, snapid, tag, &vid, false, &local_err);
|
||||
if (ret) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1386,8 +1391,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1408,15 +1412,16 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
ret = parse_vdiname(s, filename, vdi, &snapid, tag);
|
||||
}
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Can't parse filename");
|
||||
goto out;
|
||||
}
|
||||
s->fd = get_sheep_fd(s);
|
||||
s->fd = get_sheep_fd(s, errp);
|
||||
if (s->fd < 0) {
|
||||
ret = s->fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = find_vdi_name(s, vdi, snapid, tag, &vid, true);
|
||||
ret = find_vdi_name(s, vdi, snapid, tag, &vid, true, errp);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
@@ -1436,7 +1441,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->is_snapshot = true;
|
||||
}
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, errp);
|
||||
if (fd < 0) {
|
||||
ret = fd;
|
||||
goto out;
|
||||
@@ -1449,6 +1454,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
closesocket(fd);
|
||||
|
||||
if (ret) {
|
||||
error_setg(errp, "Can't read snapshot inode");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1472,7 +1478,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
||||
static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
|
||||
Error **errp)
|
||||
{
|
||||
SheepdogVdiReq hdr;
|
||||
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
|
||||
@@ -1480,7 +1487,7 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
||||
unsigned int wlen, rlen = 0;
|
||||
char buf[SD_MAX_VDI_LEN];
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, errp);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
@@ -1510,11 +1517,12 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
||||
closesocket(fd);
|
||||
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret, "create failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
error_report("%s, %s", sd_strerror(rsp->result), s->inode.name);
|
||||
error_setg(errp, "%s, %s", sd_strerror(rsp->result), s->inode.name);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -1525,21 +1533,18 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_prealloc(const char *filename)
|
||||
static int sd_prealloc(const char *filename, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
uint32_t idx, max_idx;
|
||||
int64_t vdi_size;
|
||||
void *buf = g_malloc0(SD_DATA_OBJ_SIZE);
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
|
||||
NULL, &local_err);
|
||||
NULL, errp);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
goto out_with_err_set;
|
||||
}
|
||||
|
||||
vdi_size = bdrv_getlength(bs);
|
||||
@@ -1563,7 +1568,12 @@ static int sd_prealloc(const char *filename)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Can't pre-allocate");
|
||||
}
|
||||
out_with_err_set:
|
||||
if (bs) {
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
@@ -1636,7 +1646,6 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
char tag[SD_MAX_VDI_TAG_LEN];
|
||||
uint32_t snapid;
|
||||
bool prealloc = false;
|
||||
Error *local_err = NULL;
|
||||
|
||||
s = g_malloc0(sizeof(BDRVSheepdogState));
|
||||
|
||||
@@ -1647,6 +1656,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
ret = parse_vdiname(s, filename, s->name, &snapid, tag);
|
||||
}
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Can't parse filename");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1661,8 +1671,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
} else if (!strcmp(options->value.s, "full")) {
|
||||
prealloc = true;
|
||||
} else {
|
||||
error_report("Invalid preallocation mode: '%s'",
|
||||
options->value.s);
|
||||
error_setg(errp, "Invalid preallocation mode: '%s'",
|
||||
options->value.s);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1670,6 +1680,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
if (options->value.s) {
|
||||
ret = parse_redundancy(s, options->value.s);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Invalid redundancy mode: '%s'",
|
||||
options->value.s);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1678,7 +1690,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
|
||||
if (s->inode.vdi_size > SD_MAX_VDI_SIZE) {
|
||||
error_report("too big image size");
|
||||
error_setg(errp, "too big image size");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1691,24 +1703,22 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
/* Currently, only Sheepdog backing image is supported. */
|
||||
drv = bdrv_find_protocol(backing_file, true);
|
||||
if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
|
||||
error_report("backing_file must be a sheepdog image");
|
||||
error_setg(errp, "backing_file must be a sheepdog image");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_PROTOCOL, NULL,
|
||||
&local_err);
|
||||
errp);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
base = bs->opaque;
|
||||
|
||||
if (!is_snapshot(&base->inode)) {
|
||||
error_report("cannot clone from a non snapshot vdi");
|
||||
error_setg(errp, "cannot clone from a non snapshot vdi");
|
||||
bdrv_unref(bs);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@@ -1717,12 +1727,14 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
|
||||
ret = do_sd_create(s, &vid, 0);
|
||||
if (!prealloc || ret) {
|
||||
ret = do_sd_create(s, &vid, 0, errp);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = sd_prealloc(filename);
|
||||
if (prealloc) {
|
||||
ret = sd_prealloc(filename, errp);
|
||||
}
|
||||
out:
|
||||
g_free(s);
|
||||
return ret;
|
||||
@@ -1730,6 +1742,7 @@ out:
|
||||
|
||||
static void sd_close(BlockDriverState *bs)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
SheepdogVdiReq hdr;
|
||||
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
|
||||
@@ -1738,8 +1751,10 @@ static void sd_close(BlockDriverState *bs)
|
||||
|
||||
DPRINTF("%s\n", s->name);
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1774,6 +1789,7 @@ static int64_t sd_getlength(BlockDriverState *bs)
|
||||
|
||||
static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
int ret, fd;
|
||||
unsigned int datalen;
|
||||
@@ -1786,8 +1802,10 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -1846,6 +1864,7 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
|
||||
/* Delete current working VDI on the snapshot chain */
|
||||
static bool sd_delete(BDRVSheepdogState *s)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
unsigned int wlen = SD_MAX_VDI_LEN, rlen = 0;
|
||||
SheepdogVdiReq hdr = {
|
||||
.opcode = SD_OP_DEL_VDI,
|
||||
@@ -1856,8 +1875,10 @@ static bool sd_delete(BDRVSheepdogState *s)
|
||||
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
|
||||
int fd, ret;
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1885,6 +1906,7 @@ static bool sd_delete(BDRVSheepdogState *s)
|
||||
*/
|
||||
static int sd_create_branch(BDRVSheepdogState *s)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int ret, fd;
|
||||
uint32_t vid;
|
||||
char *buf;
|
||||
@@ -1900,15 +1922,19 @@ static int sd_create_branch(BDRVSheepdogState *s)
|
||||
* false bail out.
|
||||
*/
|
||||
deleted = sd_delete(s);
|
||||
ret = do_sd_create(s, &vid, !deleted);
|
||||
ret = do_sd_create(s, &vid, !deleted, &local_err);
|
||||
if (ret) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
DPRINTF("%" PRIx32 " is created.\n", vid);
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
@@ -2122,6 +2148,7 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
|
||||
|
||||
static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
int ret, fd;
|
||||
uint32_t new_vid;
|
||||
@@ -2151,8 +2178,10 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
|
||||
|
||||
/* refresh inode. */
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
ret = fd;
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -2164,8 +2193,10 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = do_sd_create(s, &new_vid, 1);
|
||||
ret = do_sd_create(s, &new_vid, 1, &local_err);
|
||||
if (ret < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
error_report("failed to create inode for snapshot. %s",
|
||||
strerror(errno));
|
||||
goto cleanup;
|
||||
@@ -2249,6 +2280,7 @@ static int sd_snapshot_delete(BlockDriverState *bs,
|
||||
|
||||
static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
SheepdogReq req;
|
||||
int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
|
||||
@@ -2263,8 +2295,10 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
|
||||
vdi_inuse = g_malloc(max);
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
@@ -2290,8 +2324,10 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
hval = fnv_64a_buf(s->name, strlen(s->name), FNV1A_64_INIT);
|
||||
start_nr = hval & (SD_NR_VDIS - 1);
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
@@ -2341,6 +2377,7 @@ out:
|
||||
static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
int64_t pos, int size, int load)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
bool create;
|
||||
int fd, ret = 0, remaining = size;
|
||||
unsigned int data_len;
|
||||
@@ -2349,8 +2386,10 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
uint32_t vdi_index;
|
||||
uint32_t vdi_id = load ? s->inode.parent_vdi_id : s->inode.vdi_id;
|
||||
|
||||
fd = connect_to_sdog(s);
|
||||
fd = connect_to_sdog(s, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("%s", error_get_pretty(local_err));;
|
||||
error_free(local_err);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
151
block/ssh.c
151
block/ssh.c
@@ -106,30 +106,59 @@ static void ssh_state_free(BDRVSSHState *s)
|
||||
}
|
||||
}
|
||||
|
||||
/* Wrappers around error_report which make sure to dump as much
|
||||
* information from libssh2 as possible.
|
||||
*/
|
||||
static void GCC_FMT_ATTR(2, 3)
|
||||
session_error_report(BDRVSSHState *s, const char *fs, ...)
|
||||
static void GCC_FMT_ATTR(3, 4)
|
||||
session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *msg;
|
||||
|
||||
va_start(args, fs);
|
||||
error_vprintf(fs, args);
|
||||
msg = g_strdup_vprintf(fs, args);
|
||||
va_end(args);
|
||||
|
||||
if ((s)->session) {
|
||||
if (s->session) {
|
||||
char *ssh_err;
|
||||
int ssh_err_code;
|
||||
|
||||
libssh2_session_last_error((s)->session, &ssh_err, NULL, 0);
|
||||
/* This is not an errno. See <libssh2.h>. */
|
||||
ssh_err_code = libssh2_session_last_errno((s)->session);
|
||||
|
||||
error_printf(": %s (libssh2 error code: %d)", ssh_err, ssh_err_code);
|
||||
ssh_err_code = libssh2_session_last_error(s->session,
|
||||
&ssh_err, NULL, 0);
|
||||
error_setg(errp, "%s: %s (libssh2 error code: %d)",
|
||||
msg, ssh_err, ssh_err_code);
|
||||
} else {
|
||||
error_setg(errp, "%s", msg);
|
||||
}
|
||||
g_free(msg);
|
||||
}
|
||||
|
||||
static void GCC_FMT_ATTR(3, 4)
|
||||
sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *msg;
|
||||
|
||||
va_start(args, fs);
|
||||
msg = g_strdup_vprintf(fs, args);
|
||||
va_end(args);
|
||||
error_printf("\n");
|
||||
|
||||
if (s->sftp) {
|
||||
char *ssh_err;
|
||||
int ssh_err_code;
|
||||
unsigned long sftp_err_code;
|
||||
|
||||
/* This is not an errno. See <libssh2.h>. */
|
||||
ssh_err_code = libssh2_session_last_error(s->session,
|
||||
&ssh_err, NULL, 0);
|
||||
/* See <libssh2_sftp.h>. */
|
||||
sftp_err_code = libssh2_sftp_last_error((s)->sftp);
|
||||
|
||||
error_setg(errp,
|
||||
"%s: %s (libssh2 error code: %d, sftp error code: %lu)",
|
||||
msg, ssh_err, ssh_err_code, sftp_err_code);
|
||||
} else {
|
||||
error_setg(errp, "%s", msg);
|
||||
}
|
||||
g_free(msg);
|
||||
}
|
||||
|
||||
static void GCC_FMT_ATTR(2, 3)
|
||||
@@ -145,9 +174,9 @@ sftp_error_report(BDRVSSHState *s, const char *fs, ...)
|
||||
int ssh_err_code;
|
||||
unsigned long sftp_err_code;
|
||||
|
||||
libssh2_session_last_error((s)->session, &ssh_err, NULL, 0);
|
||||
/* This is not an errno. See <libssh2.h>. */
|
||||
ssh_err_code = libssh2_session_last_errno((s)->session);
|
||||
ssh_err_code = libssh2_session_last_error(s->session,
|
||||
&ssh_err, NULL, 0);
|
||||
/* See <libssh2_sftp.h>. */
|
||||
sftp_err_code = libssh2_sftp_last_error((s)->sftp);
|
||||
|
||||
@@ -243,7 +272,7 @@ static void ssh_parse_filename(const char *filename, QDict *options,
|
||||
}
|
||||
|
||||
static int check_host_key_knownhosts(BDRVSSHState *s,
|
||||
const char *host, int port)
|
||||
const char *host, int port, Error **errp)
|
||||
{
|
||||
const char *home;
|
||||
char *knh_file = NULL;
|
||||
@@ -257,14 +286,15 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
|
||||
hostkey = libssh2_session_hostkey(s->session, &len, &type);
|
||||
if (!hostkey) {
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "failed to read remote host key");
|
||||
session_error_setg(errp, s, "failed to read remote host key");
|
||||
goto out;
|
||||
}
|
||||
|
||||
knh = libssh2_knownhost_init(s->session);
|
||||
if (!knh) {
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "failed to initialize known hosts support");
|
||||
session_error_setg(errp, s,
|
||||
"failed to initialize known hosts support");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -289,21 +319,23 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
|
||||
break;
|
||||
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "host key does not match the one in known_hosts (found key %s)",
|
||||
found->key);
|
||||
session_error_setg(errp, s,
|
||||
"host key does not match the one in known_hosts"
|
||||
" (found key %s)", found->key);
|
||||
goto out;
|
||||
case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "no host key was found in known_hosts");
|
||||
session_error_setg(errp, s, "no host key was found in known_hosts");
|
||||
goto out;
|
||||
case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "failure matching the host key with known_hosts");
|
||||
session_error_setg(errp, s,
|
||||
"failure matching the host key with known_hosts");
|
||||
goto out;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "unknown error matching the host key with known_hosts (%d)",
|
||||
r);
|
||||
session_error_setg(errp, s, "unknown error matching the host key"
|
||||
" with known_hosts (%d)", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -358,20 +390,20 @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
|
||||
|
||||
static int
|
||||
check_host_key_hash(BDRVSSHState *s, const char *hash,
|
||||
int hash_type, size_t fingerprint_len)
|
||||
int hash_type, size_t fingerprint_len, Error **errp)
|
||||
{
|
||||
const char *fingerprint;
|
||||
|
||||
fingerprint = libssh2_hostkey_hash(s->session, hash_type);
|
||||
if (!fingerprint) {
|
||||
session_error_report(s, "failed to read remote host key");
|
||||
session_error_setg(errp, s, "failed to read remote host key");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
|
||||
hash) != 0) {
|
||||
error_report("remote host key does not match host_key_check '%s'",
|
||||
hash);
|
||||
error_setg(errp, "remote host key does not match host_key_check '%s'",
|
||||
hash);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -379,7 +411,7 @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
|
||||
}
|
||||
|
||||
static int check_host_key(BDRVSSHState *s, const char *host, int port,
|
||||
const char *host_key_check)
|
||||
const char *host_key_check, Error **errp)
|
||||
{
|
||||
/* host_key_check=no */
|
||||
if (strcmp(host_key_check, "no") == 0) {
|
||||
@@ -389,25 +421,25 @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
|
||||
/* host_key_check=md5:xx:yy:zz:... */
|
||||
if (strncmp(host_key_check, "md5:", 4) == 0) {
|
||||
return check_host_key_hash(s, &host_key_check[4],
|
||||
LIBSSH2_HOSTKEY_HASH_MD5, 16);
|
||||
LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
|
||||
}
|
||||
|
||||
/* host_key_check=sha1:xx:yy:zz:... */
|
||||
if (strncmp(host_key_check, "sha1:", 5) == 0) {
|
||||
return check_host_key_hash(s, &host_key_check[5],
|
||||
LIBSSH2_HOSTKEY_HASH_SHA1, 20);
|
||||
LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
|
||||
}
|
||||
|
||||
/* host_key_check=yes */
|
||||
if (strcmp(host_key_check, "yes") == 0) {
|
||||
return check_host_key_knownhosts(s, host, port);
|
||||
return check_host_key_knownhosts(s, host, port, errp);
|
||||
}
|
||||
|
||||
error_report("unknown host_key_check setting (%s)", host_key_check);
|
||||
error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int authenticate(BDRVSSHState *s, const char *user)
|
||||
static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
|
||||
{
|
||||
int r, ret;
|
||||
const char *userauthlist;
|
||||
@@ -418,7 +450,8 @@ static int authenticate(BDRVSSHState *s, const char *user)
|
||||
userauthlist = libssh2_userauth_list(s->session, user, strlen(user));
|
||||
if (strstr(userauthlist, "publickey") == NULL) {
|
||||
ret = -EPERM;
|
||||
error_report("remote server does not support \"publickey\" authentication");
|
||||
error_setg(errp,
|
||||
"remote server does not support \"publickey\" authentication");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -426,17 +459,18 @@ static int authenticate(BDRVSSHState *s, const char *user)
|
||||
agent = libssh2_agent_init(s->session);
|
||||
if (!agent) {
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "failed to initialize ssh-agent support");
|
||||
session_error_setg(errp, s, "failed to initialize ssh-agent support");
|
||||
goto out;
|
||||
}
|
||||
if (libssh2_agent_connect(agent)) {
|
||||
ret = -ECONNREFUSED;
|
||||
session_error_report(s, "failed to connect to ssh-agent");
|
||||
session_error_setg(errp, s, "failed to connect to ssh-agent");
|
||||
goto out;
|
||||
}
|
||||
if (libssh2_agent_list_identities(agent)) {
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "failed requesting identities from ssh-agent");
|
||||
session_error_setg(errp, s,
|
||||
"failed requesting identities from ssh-agent");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -447,7 +481,8 @@ static int authenticate(BDRVSSHState *s, const char *user)
|
||||
}
|
||||
if (r < 0) {
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "failed to obtain identity from ssh-agent");
|
||||
session_error_setg(errp, s,
|
||||
"failed to obtain identity from ssh-agent");
|
||||
goto out;
|
||||
}
|
||||
r = libssh2_agent_userauth(agent, user, identity);
|
||||
@@ -461,8 +496,8 @@ static int authenticate(BDRVSSHState *s, const char *user)
|
||||
}
|
||||
|
||||
ret = -EPERM;
|
||||
error_report("failed to authenticate using publickey authentication "
|
||||
"and the identities held by your ssh-agent");
|
||||
error_setg(errp, "failed to authenticate using publickey authentication "
|
||||
"and the identities held by your ssh-agent");
|
||||
|
||||
out:
|
||||
if (agent != NULL) {
|
||||
@@ -476,10 +511,9 @@ static int authenticate(BDRVSSHState *s, const char *user)
|
||||
}
|
||||
|
||||
static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
int ssh_flags, int creat_mode)
|
||||
int ssh_flags, int creat_mode, Error **errp)
|
||||
{
|
||||
int r, ret;
|
||||
Error *err = NULL;
|
||||
const char *host, *user, *path, *host_key_check;
|
||||
int port;
|
||||
|
||||
@@ -498,6 +532,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
} else {
|
||||
user = g_get_user_name();
|
||||
if (!user) {
|
||||
error_setg_errno(errp, errno, "Can't get user name");
|
||||
ret = -errno;
|
||||
goto err;
|
||||
}
|
||||
@@ -514,11 +549,9 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
s->hostport = g_strdup_printf("%s:%d", host, port);
|
||||
|
||||
/* Open the socket and connect. */
|
||||
s->sock = inet_connect(s->hostport, &err);
|
||||
if (err != NULL) {
|
||||
s->sock = inet_connect(s->hostport, errp);
|
||||
if (s->sock < 0) {
|
||||
ret = -errno;
|
||||
qerror_report_err(err);
|
||||
error_free(err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -526,7 +559,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
s->session = libssh2_session_init();
|
||||
if (!s->session) {
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "failed to initialize libssh2 session");
|
||||
session_error_setg(errp, s, "failed to initialize libssh2 session");
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -537,18 +570,18 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
r = libssh2_session_handshake(s->session, s->sock);
|
||||
if (r != 0) {
|
||||
ret = -EINVAL;
|
||||
session_error_report(s, "failed to establish SSH session");
|
||||
session_error_setg(errp, s, "failed to establish SSH session");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Check the remote host's key against known_hosts. */
|
||||
ret = check_host_key(s, host, port, host_key_check);
|
||||
ret = check_host_key(s, host, port, host_key_check, errp);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Authenticate. */
|
||||
ret = authenticate(s, user);
|
||||
ret = authenticate(s, user, errp);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
@@ -556,7 +589,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
/* Start SFTP. */
|
||||
s->sftp = libssh2_sftp_init(s->session);
|
||||
if (!s->sftp) {
|
||||
session_error_report(s, "failed to initialize sftp handle");
|
||||
session_error_setg(errp, s, "failed to initialize sftp handle");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
@@ -566,14 +599,14 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
path, ssh_flags, creat_mode);
|
||||
s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode);
|
||||
if (!s->sftp_handle) {
|
||||
session_error_report(s, "failed to open remote file '%s'", path);
|
||||
session_error_setg(errp, s, "failed to open remote file '%s'", path);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
|
||||
if (r < 0) {
|
||||
sftp_error_report(s, "failed to read file attributes");
|
||||
sftp_error_setg(errp, s, "failed to read file attributes");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -623,7 +656,7 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
|
||||
}
|
||||
|
||||
/* Start up SSH. */
|
||||
ret = connect_to_ssh(s, options, ssh_flags, 0);
|
||||
ret = connect_to_ssh(s, options, ssh_flags, 0, errp);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
@@ -655,7 +688,6 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options,
|
||||
Error **errp)
|
||||
{
|
||||
int r, ret;
|
||||
Error *local_err = NULL;
|
||||
int64_t total_size = 0;
|
||||
QDict *uri_options = NULL;
|
||||
BDRVSSHState s;
|
||||
@@ -674,17 +706,16 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options,
|
||||
DPRINTF("total_size=%" PRIi64, total_size);
|
||||
|
||||
uri_options = qdict_new();
|
||||
r = parse_uri(filename, uri_options, &local_err);
|
||||
r = parse_uri(filename, uri_options, errp);
|
||||
if (r < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
ret = r;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = connect_to_ssh(&s, uri_options,
|
||||
LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
|
||||
LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, 0644);
|
||||
LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
|
||||
0644, errp);
|
||||
if (r < 0) {
|
||||
ret = r;
|
||||
goto out;
|
||||
@@ -694,7 +725,7 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options,
|
||||
libssh2_sftp_seek64(s.sftp_handle, total_size-1);
|
||||
r2 = libssh2_sftp_write(s.sftp_handle, c, 1);
|
||||
if (r2 < 0) {
|
||||
sftp_error_report(&s, "truncate failed");
|
||||
sftp_error_setg(errp, &s, "truncate failed");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@@ -60,7 +60,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
|
||||
/* Must assign before bdrv_delete() to prevent traversing dangling pointer
|
||||
* while we delete backing image instances.
|
||||
*/
|
||||
top->backing_hd = base;
|
||||
bdrv_set_backing_hd(top, base);
|
||||
|
||||
while (intermediate) {
|
||||
BlockDriverState *unused;
|
||||
@@ -72,7 +72,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
|
||||
|
||||
unused = intermediate;
|
||||
intermediate = intermediate->backing_hd;
|
||||
unused->backing_hd = NULL;
|
||||
bdrv_set_backing_hd(unused, NULL);
|
||||
bdrv_unref(unused);
|
||||
}
|
||||
|
||||
|
@@ -473,7 +473,14 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
|
||||
} else if (h2_seq > h1_seq) {
|
||||
s->curr_header = 1;
|
||||
} else {
|
||||
goto fail;
|
||||
/* The Microsoft Disk2VHD tool will create 2 identical
|
||||
* headers, with identical sequence numbers. If the headers are
|
||||
* identical, don't consider the file corrupt */
|
||||
if (!memcmp(header1, header2, sizeof(VHDXHeader))) {
|
||||
s->curr_header = 0;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -831,7 +831,8 @@ static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
|
||||
}
|
||||
|
||||
static int init_directories(BDRVVVFATState* s,
|
||||
const char *dirname, int heads, int secs)
|
||||
const char *dirname, int heads, int secs,
|
||||
Error **errp)
|
||||
{
|
||||
bootsector_t* bootsector;
|
||||
mapping_t* mapping;
|
||||
@@ -892,8 +893,8 @@ static int init_directories(BDRVVVFATState* s,
|
||||
if (mapping->mode & MODE_DIRECTORY) {
|
||||
mapping->begin = cluster;
|
||||
if(read_directory(s, i)) {
|
||||
fprintf(stderr, "Could not read directory %s\n",
|
||||
mapping->path);
|
||||
error_setg(errp, "Could not read directory %s",
|
||||
mapping->path);
|
||||
return -1;
|
||||
}
|
||||
mapping = array_get(&(s->mapping), i);
|
||||
@@ -919,9 +920,10 @@ static int init_directories(BDRVVVFATState* s,
|
||||
cluster = mapping->end;
|
||||
|
||||
if(cluster > s->cluster_count) {
|
||||
fprintf(stderr,"Directory does not fit in FAT%d (capacity %.2f MB)\n",
|
||||
s->fat_type, s->sector_count / 2000.0);
|
||||
return -EINVAL;
|
||||
error_setg(errp,
|
||||
"Directory does not fit in FAT%d (capacity %.2f MB)",
|
||||
s->fat_type, s->sector_count / 2000.0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* fix fat for entry */
|
||||
@@ -979,7 +981,7 @@ static int init_directories(BDRVVVFATState* s,
|
||||
static BDRVVVFATState *vvv = NULL;
|
||||
#endif
|
||||
|
||||
static int enable_write_target(BDRVVVFATState *s);
|
||||
static int enable_write_target(BDRVVVFATState *s, Error **errp);
|
||||
static int is_consistent(BDRVVVFATState *s);
|
||||
|
||||
static void vvfat_rebind(BlockDriverState *bs)
|
||||
@@ -1160,7 +1162,7 @@ DLOG(if (stderr == NULL) {
|
||||
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
|
||||
|
||||
if (qemu_opt_get_bool(opts, "rw", false)) {
|
||||
ret = enable_write_target(s);
|
||||
ret = enable_write_target(s, errp);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -1169,7 +1171,7 @@ DLOG(if (stderr == NULL) {
|
||||
|
||||
bs->total_sectors = cyls * heads * secs;
|
||||
|
||||
if (init_directories(s, dirname, heads, secs)) {
|
||||
if (init_directories(s, dirname, heads, secs, errp)) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
@@ -2904,11 +2906,10 @@ static BlockDriver vvfat_write_target = {
|
||||
.bdrv_close = write_target_close,
|
||||
};
|
||||
|
||||
static int enable_write_target(BDRVVVFATState *s)
|
||||
static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
||||
{
|
||||
BlockDriver *bdrv_qcow;
|
||||
QEMUOptionParameter *options;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
int size = sector2cluster(s, s->sector_count);
|
||||
s->used_clusters = calloc(size, 1);
|
||||
@@ -2918,6 +2919,7 @@ static int enable_write_target(BDRVVVFATState *s)
|
||||
s->qcow_filename = g_malloc(1024);
|
||||
ret = get_tmp_filename(s->qcow_filename, 1024);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "can't create temporary file");
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -2926,20 +2928,16 @@ static int enable_write_target(BDRVVVFATState *s)
|
||||
set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
|
||||
set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
|
||||
|
||||
ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, &local_err);
|
||||
ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, errp);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
s->qcow = NULL;
|
||||
ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow,
|
||||
&local_err);
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
|
||||
bdrv_qcow, errp);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -2947,7 +2945,7 @@ static int enable_write_target(BDRVVVFATState *s)
|
||||
unlink(s->qcow_filename);
|
||||
#endif
|
||||
|
||||
s->bs->backing_hd = bdrv_new("", &error_abort);
|
||||
bdrv_set_backing_hd(s->bs, bdrv_new("", &error_abort));
|
||||
s->bs->backing_hd->drv = &vvfat_write_target;
|
||||
s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
|
||||
*(void**)s->bs->backing_hd->opaque = s;
|
||||
|
@@ -27,8 +27,8 @@ static void nbd_accept(void *opaque)
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
|
||||
int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
|
||||
if (fd >= 0) {
|
||||
nbd_client_new(NULL, fd, nbd_client_put);
|
||||
if (fd >= 0 && !nbd_client_new(NULL, fd, nbd_client_put)) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
77
blockdev.c
77
blockdev.c
@@ -34,7 +34,6 @@
|
||||
#include "hw/block/block.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
@@ -288,6 +287,25 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int parse_enum_option(const char *lookup[], const char *buf,
|
||||
int max, int def, Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!buf) {
|
||||
return def;
|
||||
}
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (!strcmp(buf, lookup[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
error_setg(errp, "invalid parameter value: %s", buf);
|
||||
return def;
|
||||
}
|
||||
|
||||
static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
|
||||
{
|
||||
if (throttle_conflicting(cfg)) {
|
||||
@@ -324,6 +342,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
QemuOpts *opts;
|
||||
const char *id;
|
||||
bool has_driver_specific_opts;
|
||||
BlockdevDetectZeroesOptions detect_zeroes;
|
||||
BlockDriver *drv = NULL;
|
||||
|
||||
/* Check common options by copying from bs_opts to opts, all other options
|
||||
@@ -452,6 +471,24 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
}
|
||||
|
||||
detect_zeroes =
|
||||
parse_enum_option(BlockdevDetectZeroesOptions_lookup,
|
||||
qemu_opt_get(opts, "detect-zeroes"),
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
|
||||
&error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
|
||||
!(bdrv_flags & BDRV_O_UNMAP)) {
|
||||
error_setg(errp, "setting detect-zeroes to unmap is not allowed "
|
||||
"without setting discard operation to unmap");
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
/* init */
|
||||
dinfo = g_malloc0(sizeof(*dinfo));
|
||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||
@@ -462,6 +499,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||
dinfo->bdrv->read_only = ro;
|
||||
dinfo->bdrv->detect_zeroes = detect_zeroes;
|
||||
dinfo->refcount = 1;
|
||||
if (serial != NULL) {
|
||||
dinfo->serial = g_strdup(serial);
|
||||
@@ -691,7 +729,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
&error_abort);
|
||||
qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err);
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
goto fail;
|
||||
}
|
||||
@@ -903,7 +941,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
dinfo = blockdev_init(filename, bs_opts, &local_err);
|
||||
if (dinfo == NULL) {
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
}
|
||||
goto fail;
|
||||
@@ -1295,8 +1333,8 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_in_use(state->old_bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, device);
|
||||
if (bdrv_op_is_blocked(state->old_bs,
|
||||
BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1518,8 +1556,7 @@ exit:
|
||||
|
||||
static void eject_device(BlockDriverState *bs, int force, Error **errp)
|
||||
{
|
||||
if (bdrv_in_use(bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
|
||||
return;
|
||||
}
|
||||
if (!bdrv_dev_has_removable_media(bs)) {
|
||||
@@ -1721,14 +1758,16 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *id = qdict_get_str(qdict, "id");
|
||||
BlockDriverState *bs;
|
||||
Error *local_err = NULL;
|
||||
|
||||
bs = bdrv_find(id);
|
||||
if (!bs) {
|
||||
qerror_report(QERR_DEVICE_NOT_FOUND, id);
|
||||
error_report("Device '%s' not found", id);
|
||||
return -1;
|
||||
}
|
||||
if (bdrv_in_use(bs)) {
|
||||
qerror_report(QERR_DEVICE_IN_USE, id);
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1849,6 +1888,10 @@ void qmp_block_stream(const char *device, bool has_base,
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (base) {
|
||||
base_bs = bdrv_find_backing_image(bs, base);
|
||||
if (base_bs == NULL) {
|
||||
@@ -1893,6 +1936,10 @@ void qmp_block_commit(const char *device,
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* default top_bs is the active layer */
|
||||
top_bs = bs;
|
||||
|
||||
@@ -1984,8 +2031,7 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
}
|
||||
}
|
||||
|
||||
if (bdrv_in_use(bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, device);
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2118,8 +2164,7 @@ void qmp_drive_mirror(const char *device, const char *target,
|
||||
}
|
||||
}
|
||||
|
||||
if (bdrv_in_use(bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, device);
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2455,6 +2500,10 @@ QemuOptsList qemu_common_drive_opts = {
|
||||
.name = "copy-on-read",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "copy read data from backing file into image file",
|
||||
},{
|
||||
.name = "detect-zeroes",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "try to optimize zero writes (off, on, unmap)",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
|
14
blockjob.c
14
blockjob.c
@@ -41,14 +41,16 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
||||
{
|
||||
BlockJob *job;
|
||||
|
||||
if (bs->job || bdrv_in_use(bs)) {
|
||||
if (bs->job) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
|
||||
return NULL;
|
||||
}
|
||||
bdrv_ref(bs);
|
||||
bdrv_set_in_use(bs, 1);
|
||||
|
||||
job = g_malloc0(driver->instance_size);
|
||||
error_setg(&job->blocker, "block device is in use by block job: %s",
|
||||
BlockJobType_lookup[driver->job_type]);
|
||||
bdrv_op_block_all(bs, job->blocker);
|
||||
|
||||
job->driver = driver;
|
||||
job->bs = bs;
|
||||
job->cb = cb;
|
||||
@@ -63,8 +65,9 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
||||
block_job_set_speed(job, speed, &local_err);
|
||||
if (local_err) {
|
||||
bs->job = NULL;
|
||||
bdrv_op_unblock_all(bs, job->blocker);
|
||||
error_free(job->blocker);
|
||||
g_free(job);
|
||||
bdrv_set_in_use(bs, 0);
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
@@ -79,8 +82,9 @@ void block_job_completed(BlockJob *job, int ret)
|
||||
assert(bs->job == job);
|
||||
job->cb(job->opaque, ret);
|
||||
bs->job = NULL;
|
||||
bdrv_op_unblock_all(bs, job->blocker);
|
||||
error_free(job->blocker);
|
||||
g_free(job);
|
||||
bdrv_set_in_use(bs, 0);
|
||||
}
|
||||
|
||||
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
|
58
configure
vendored
58
configure
vendored
@@ -2,26 +2,28 @@
|
||||
#
|
||||
# qemu configure script (c) 2003 Fabrice Bellard
|
||||
#
|
||||
# set temporary file name
|
||||
if test ! -z "$TMPDIR" ; then
|
||||
TMPDIR1="${TMPDIR}"
|
||||
elif test ! -z "$TEMPDIR" ; then
|
||||
TMPDIR1="${TEMPDIR}"
|
||||
else
|
||||
TMPDIR1="/tmp"
|
||||
|
||||
# Temporary directory used for files created while
|
||||
# configure runs. Since it is in the build directory
|
||||
# we can safely blow away any previous version of it
|
||||
# (and we need not jump through hoops to try to delete
|
||||
# it when configure exits.)
|
||||
TMPDIR1="config-temp"
|
||||
rm -rf "${TMPDIR1}"
|
||||
mkdir -p "${TMPDIR1}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: failed to create temporary directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
|
||||
TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}"
|
||||
TMPB="qemu-conf"
|
||||
TMPC="${TMPDIR1}/${TMPB}.c"
|
||||
TMPO="${TMPDIR1}/${TMPB}.o"
|
||||
TMPCXX="${TMPDIR1}/${TMPB}.cxx"
|
||||
TMPL="${TMPDIR1}/${TMPB}.lo"
|
||||
TMPA="${TMPDIR1}/lib${TMPB}.la"
|
||||
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
|
||||
TMPE="${TMPDIR1}/${TMPB}.exe"
|
||||
|
||||
# NB: do not call "exit" in the trap handler; this is buggy with some shells;
|
||||
# see <1285349658-3122-1-git-send-email-loic.minier@linaro.org>
|
||||
trap "rm -f $TMPC $TMPO $TMPCXX $TMPE" EXIT INT QUIT TERM
|
||||
rm -f config.log
|
||||
|
||||
# Print a helpful header at the top of config.log
|
||||
@@ -317,7 +319,7 @@ glusterfs_discard="no"
|
||||
glusterfs_zerofill="no"
|
||||
virtio_blk_data_plane=""
|
||||
gtk=""
|
||||
gtkabi="2.0"
|
||||
gtkabi=""
|
||||
vte=""
|
||||
tpm="no"
|
||||
libssh2=""
|
||||
@@ -1970,6 +1972,18 @@ fi
|
||||
##########################################
|
||||
# GTK probe
|
||||
|
||||
if test "$gtkabi" = ""; then
|
||||
# The GTK ABI was not specified explicitly, so try whether 2.0 is available.
|
||||
# Use 3.0 as a fallback if that is available.
|
||||
if $pkg_config --exists "gtk+-2.0 >= 2.18.0"; then
|
||||
gtkabi=2.0
|
||||
elif $pkg_config --exists "gtk+-3.0 >= 3.0.0"; then
|
||||
gtkabi=3.0
|
||||
else
|
||||
gtkabi=2.0
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$gtk" != "no"; then
|
||||
gtkpackage="gtk+-$gtkabi"
|
||||
if test "$gtkabi" = "3.0" ; then
|
||||
@@ -1983,7 +1997,7 @@ if test "$gtk" != "no"; then
|
||||
libs_softmmu="$gtk_libs $libs_softmmu"
|
||||
gtk="yes"
|
||||
elif test "$gtk" = "yes"; then
|
||||
feature_not_found "gtk" "Install gtk2 or gtk3 (requires --with-gtkabi=3.0 option to configure) devel"
|
||||
feature_not_found "gtk" "Install gtk2 or gtk3 devel"
|
||||
else
|
||||
gtk="no"
|
||||
fi
|
||||
@@ -2006,7 +2020,11 @@ if test "$vte" != "no"; then
|
||||
libs_softmmu="$vte_libs $libs_softmmu"
|
||||
vte="yes"
|
||||
elif test "$vte" = "yes"; then
|
||||
feature_not_found "vte" "Install libvte or libvte-2.90 (requires --with-gtkabi=3.0 option to configure) devel"
|
||||
if test "$gtkabi" = "3.0"; then
|
||||
feature_not_found "vte" "Install libvte-2.90 devel"
|
||||
else
|
||||
feature_not_found "vte" "Install libvte devel"
|
||||
fi
|
||||
else
|
||||
vte="no"
|
||||
fi
|
||||
@@ -4029,11 +4047,14 @@ fi
|
||||
if test "$pie" = "no" ; then
|
||||
textseg_addr=
|
||||
case "$cpu" in
|
||||
arm | hppa | i386 | m68k | ppc | ppc64 | s390* | sparc | sparc64 | x86_64 | x32)
|
||||
arm | i386 | ppc* | s390* | sparc* | x86_64 | x32)
|
||||
# ??? Rationale for choosing this address
|
||||
textseg_addr=0x60000000
|
||||
;;
|
||||
mips)
|
||||
textseg_addr=0x400000
|
||||
# A 256M aligned address, high in the address space, with enough
|
||||
# room for the code_gen_buffer above it before the stack.
|
||||
textseg_addr=0x60000000
|
||||
;;
|
||||
esac
|
||||
if [ -n "$textseg_addr" ]; then
|
||||
@@ -5219,3 +5240,4 @@ printf " '%s'" "$0" "$@" >>config.status
|
||||
echo >>config.status
|
||||
chmod +x config.status
|
||||
|
||||
rm -r "$TMPDIR1"
|
||||
|
@@ -1,3 +1,4 @@
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_S390_FLIC=$(CONFIG_KVM)
|
||||
CONFIG_S390_FLIC=y
|
||||
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
|
||||
|
@@ -143,12 +143,12 @@ static void dma_bdrv_cb(void *opaque, int ret)
|
||||
|
||||
dbs->acb = NULL;
|
||||
dbs->sector_num += dbs->iov.size / 512;
|
||||
dma_bdrv_unmap(dbs);
|
||||
|
||||
if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
|
||||
dma_complete(dbs, ret);
|
||||
return;
|
||||
}
|
||||
dma_bdrv_unmap(dbs);
|
||||
|
||||
while (dbs->sg_cur_index < dbs->sg->nsg) {
|
||||
cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
|
||||
|
76
docs/multiseat.txt
Normal file
76
docs/multiseat.txt
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
multiseat howto (with some multihead coverage)
|
||||
==============================================
|
||||
|
||||
host side
|
||||
---------
|
||||
|
||||
First you must compile qemu with a user interface supporting
|
||||
multihead/multiseat and input event routing. Right now this list is
|
||||
pretty short: sdl2.
|
||||
|
||||
./configure --enable-sdl --with-sdlabi=2.0
|
||||
|
||||
|
||||
Next put together the qemu command line:
|
||||
|
||||
qemu -enable-kvm -usb $memory $disk $whatever \
|
||||
-display sdl \
|
||||
-vga std \
|
||||
-device usb-tablet
|
||||
|
||||
That is it for the first head, which will use the standard vga, the
|
||||
standard ps/2 keyboard (implicitly there) and the usb-tablet. Now the
|
||||
additional switches for the second head:
|
||||
|
||||
-device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
|
||||
-device secondary-vga,bus=head.2,addr=02.0,id=video.2 \
|
||||
-device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \
|
||||
-device usb-kbd,bus=usb.2.0,port=1,display=video.2 \
|
||||
-device usb-tablet,bus=usb.2.0,port=2,display=video.2
|
||||
|
||||
This places a pci bridge in slot 12, connects a display adapter and
|
||||
xhci (usb) controller to the bridge. Then it adds a usb keyboard and
|
||||
usb mouse, both connected to the xhci and linked to the display.
|
||||
|
||||
The "display=video2" sets up the input routing. Any input coming from
|
||||
the window which belongs to the video.2 display adapter will be routed
|
||||
to these input devices.
|
||||
|
||||
|
||||
guest side
|
||||
----------
|
||||
|
||||
You need a pretty recent linux guest. systemd with loginctl. kernel
|
||||
3.14+ with CONFIG_DRM_BOCHS enabled. Fedora 20 will do. Must be
|
||||
fully updated for the new kernel though, i.e. the live iso doesn't cut
|
||||
it.
|
||||
|
||||
Now we'll have to configure the guest. Boot and login. By default
|
||||
all devices belong to seat0. You can use "loginctl seat-status seat0"
|
||||
to list them all (and to get the sysfs paths for cut+paste). Now
|
||||
we'll go assign all pci devices connected the pci bridge in slot 12 to
|
||||
a new head:
|
||||
|
||||
loginctl attach seat-qemu \
|
||||
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/drm/card1
|
||||
loginctl attach seat-qemu \
|
||||
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/graphics/fb1
|
||||
loginctl attach seat-qemu \
|
||||
/sys/devices/pci0000:00/0000:00:12.0/0000:01:0f.0/usb2
|
||||
|
||||
Use "loginctl seat-status seat-qemu" to check the result. It isn't
|
||||
needed to assign the usb devices to the head individually, assigning a
|
||||
usb (root) hub will automatically assign all usb devices connected to
|
||||
it too.
|
||||
|
||||
BTW: loginctl writes udev rules to /etc/udev/rules.d to make these
|
||||
device assignments permanent, so you need to do this only once.
|
||||
|
||||
Now simply restart gdm (rebooting will do too), and a login screen
|
||||
should show up on the second head.
|
||||
|
||||
Enjoy!
|
||||
|
||||
--
|
||||
Gerd Hoffmann <kraxel@redhat.com>
|
@@ -48,7 +48,7 @@ The QAPI schema definitions can be modularized using the 'include' directive:
|
||||
{ 'include': 'path/to/file.json'}
|
||||
|
||||
The directive is evaluated recursively, and include paths are relative to the
|
||||
file using the directive.
|
||||
file using the directive. Multiple includes of the same file are safe.
|
||||
|
||||
|
||||
=== Complex types ===
|
||||
@@ -230,14 +230,13 @@ node structure that can be used to chain together a list of such types in
|
||||
case we want to accept/return a list of this type with a command), and a
|
||||
command which takes that type as a parameter and returns the same type:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
|
||||
$ cat example-schema.json
|
||||
{ 'type': 'UserDefOne',
|
||||
'data': { 'integer': 'int', 'string': 'str' } }
|
||||
|
||||
{ 'command': 'my-command',
|
||||
'data': {'arg1': 'UserDefOne'},
|
||||
'returns': 'UserDefOne' }
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
||||
=== scripts/qapi-types.py ===
|
||||
|
||||
@@ -255,14 +254,25 @@ created code.
|
||||
|
||||
Example:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
|
||||
--output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ python scripts/qapi-types.py --output-dir="qapi-generated" \
|
||||
--prefix="example-" --input-file=example-schema.json
|
||||
$ cat qapi-generated/example-qapi-types.c
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#include "qapi/qapi-dealloc-visitor.h"
|
||||
#include "example-qapi-types.h"
|
||||
#include "example-qapi-visit.h"
|
||||
void qapi_free_UserDefOneList(UserDefOneList * obj)
|
||||
{
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOneList(v, &obj, NULL, NULL);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
|
||||
void qapi_free_UserDefOne(UserDefOne * obj)
|
||||
{
|
||||
@@ -279,32 +289,38 @@ Example:
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
||||
#define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
||||
$ cat qapi-generated/example-qapi-types.h
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#include "qapi/qapi-types-core.h"
|
||||
#ifndef EXAMPLE_QAPI_TYPES_H
|
||||
#define EXAMPLE_QAPI_TYPES_H
|
||||
|
||||
[Builtin types omitted...]
|
||||
|
||||
typedef struct UserDefOne UserDefOne;
|
||||
|
||||
typedef struct UserDefOneList
|
||||
{
|
||||
UserDefOne *value;
|
||||
union {
|
||||
UserDefOne *value;
|
||||
uint64_t padding;
|
||||
};
|
||||
struct UserDefOneList *next;
|
||||
} UserDefOneList;
|
||||
|
||||
[Functions on builtin types omitted...]
|
||||
|
||||
struct UserDefOne
|
||||
{
|
||||
int64_t integer;
|
||||
char * string;
|
||||
};
|
||||
|
||||
void qapi_free_UserDefOneList(UserDefOneList * obj);
|
||||
void qapi_free_UserDefOne(UserDefOne * obj);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
=== scripts/qapi-visit.py ===
|
||||
|
||||
Used to generate the visitor functions used to walk through and convert
|
||||
@@ -325,51 +341,78 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor
|
||||
|
||||
Example:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
|
||||
--output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ python scripts/qapi-visit.py --output-dir="qapi-generated"
|
||||
--prefix="example-" --input-file=example-schema.json
|
||||
$ cat qapi-generated/example-qapi-visit.c
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#include "example-qapi-visit.h"
|
||||
static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne ** obj, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
visit_type_int(m, &(*obj)->integer, "integer", &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
visit_type_str(m, &(*obj)->string, "string", &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
|
||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
|
||||
{
|
||||
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
|
||||
visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
|
||||
visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
|
||||
visit_end_struct(m, errp);
|
||||
Error *err = NULL;
|
||||
|
||||
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err);
|
||||
if (!err) {
|
||||
if (*obj) {
|
||||
visit_type_UserDefOne_fields(m, obj, errp);
|
||||
}
|
||||
visit_end_struct(m, &err);
|
||||
}
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
|
||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
|
||||
{
|
||||
GenericList *i, **prev = (GenericList **)obj;
|
||||
Error *err = NULL;
|
||||
GenericList *i, **prev;
|
||||
|
||||
visit_start_list(m, name, errp);
|
||||
|
||||
for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
|
||||
UserDefOneList *native_i = (UserDefOneList *)i;
|
||||
visit_type_UserDefOne(m, &native_i->value, NULL, errp);
|
||||
visit_start_list(m, name, &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
visit_end_list(m, errp);
|
||||
for (prev = (GenericList **)obj;
|
||||
!err && (i = visit_next_list(m, prev, &err)) != NULL;
|
||||
prev = &i) {
|
||||
UserDefOneList *native_i = (UserDefOneList *)i;
|
||||
visit_type_UserDefOne(m, &native_i->value, NULL, &err);
|
||||
}
|
||||
|
||||
error_propagate(errp, err);
|
||||
err = NULL;
|
||||
visit_end_list(m, &err);
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ python scripts/qapi-commands.py --output-dir="qapi-generated" \
|
||||
--prefix="example-" --input-file=example-schema.json
|
||||
$ cat qapi-generated/example-qapi-visit.h
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
||||
#define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
||||
#ifndef EXAMPLE_QAPI_VISIT_H
|
||||
#define EXAMPLE_QAPI_VISIT_H
|
||||
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "example-qapi-types.h"
|
||||
[Visitors for builtin types omitted...]
|
||||
|
||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
|
||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
|
||||
|
||||
#endif
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
||||
(The actual structure of the visit_type_* functions is a bit more complex
|
||||
in order to propagate errors correctly and avoid leaking memory).
|
||||
|
||||
=== scripts/qapi-commands.py ===
|
||||
|
||||
@@ -390,77 +433,80 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands
|
||||
|
||||
Example:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ cat qapi-generated/example-qmp-marshal.c
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#include "qemu-objects.h"
|
||||
#include "qapi/qmp-core.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi/qapi-dealloc-visitor.h"
|
||||
#include "example-qapi-types.h"
|
||||
#include "example-qapi-visit.h"
|
||||
|
||||
#include "example-qmp-commands.h"
|
||||
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
|
||||
{
|
||||
QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
|
||||
Error *local_err = NULL;
|
||||
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
|
||||
v = qmp_output_get_visitor(mo);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
|
||||
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
*ret_out = qmp_output_get_qobject(mo);
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
qmp_output_visitor_cleanup(mo);
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", NULL);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
|
||||
static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
|
||||
static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
UserDefOne * retval = NULL;
|
||||
QmpInputVisitor *mi;
|
||||
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
UserDefOne * arg1 = NULL;
|
||||
|
||||
mi = qmp_input_visitor_new(QOBJECT(args));
|
||||
v = qmp_input_get_visitor(mi);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
||||
|
||||
if (error_is_set(errp)) {
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
retval = qmp_my_command(arg1, errp);
|
||||
qmp_marshal_output_my_command(retval, ret, errp);
|
||||
|
||||
retval = qmp_my_command(arg1, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
qmp_marshal_output_my_command(retval, ret, &local_err);
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
qmp_input_visitor_cleanup(mi);
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", NULL);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
return;
|
||||
}
|
||||
|
||||
static void qmp_init_marshal(void)
|
||||
{
|
||||
qmp_register_command("my-command", qmp_marshal_input_my_command);
|
||||
qmp_register_command("my-command", qmp_marshal_input_my_command, QCO_NO_OPTIONS);
|
||||
}
|
||||
|
||||
qapi_init(qmp_init_marshal);
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ cat qapi-generated/example-qmp-commands.h
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
||||
#define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
||||
#ifndef EXAMPLE_QMP_COMMANDS_H
|
||||
#define EXAMPLE_QMP_COMMANDS_H
|
||||
|
||||
#include "example-qapi-types.h"
|
||||
#include "error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
|
||||
|
||||
#endif
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
@@ -107,8 +107,9 @@ in the description of a field.
|
||||
|
||||
96 - 99: refcount_order
|
||||
Describes the width of a reference count block entry (width
|
||||
in bits = 1 << refcount_order). For version 2 images, the
|
||||
order is always assumed to be 4 (i.e. the width is 16 bits).
|
||||
in bits: refcount_bits = 1 << refcount_order). For version 2
|
||||
images, the order is always assumed to be 4
|
||||
(i.e. refcount_bits = 16).
|
||||
|
||||
100 - 103: header_length
|
||||
Length of the header structure in bytes. For version 2
|
||||
|
@@ -556,6 +556,7 @@ ETEXI
|
||||
.params = "keys [hold_ms]",
|
||||
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
|
||||
.mhandler.cmd = hmp_send_key,
|
||||
.command_completion = sendkey_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1233,9 +1234,10 @@ ETEXI
|
||||
{
|
||||
.name = "netdev_add",
|
||||
.args_type = "netdev:O",
|
||||
.params = "[user|tap|socket|hubport|netmap],id=str[,prop=value][,...]",
|
||||
.params = "[user|tap|socket|vde|bridge|hubport|netmap],id=str[,prop=value][,...]",
|
||||
.help = "add host network device",
|
||||
.mhandler.cmd = hmp_netdev_add,
|
||||
.command_completion = netdev_add_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1250,6 +1252,7 @@ ETEXI
|
||||
.params = "id",
|
||||
.help = "remove host network device",
|
||||
.mhandler.cmd = hmp_netdev_del,
|
||||
.command_completion = netdev_del_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1339,6 +1342,7 @@ ETEXI
|
||||
.params = "name on|off",
|
||||
.help = "change the link status of a network adapter",
|
||||
.mhandler.cmd = hmp_set_link,
|
||||
.command_completion = set_link_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1622,6 +1626,7 @@ ETEXI
|
||||
.params = "args",
|
||||
.help = "add chardev",
|
||||
.mhandler.cmd = hmp_chardev_add,
|
||||
.command_completion = chardev_add_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1638,6 +1643,7 @@ ETEXI
|
||||
.params = "id",
|
||||
.help = "remove chardev",
|
||||
.mhandler.cmd = hmp_chardev_remove,
|
||||
.command_completion = chardev_remove_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
|
21
hmp.c
21
hmp.c
@@ -341,6 +341,11 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
|
||||
info->value->inserted->backing_file_depth);
|
||||
}
|
||||
|
||||
if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
||||
monitor_printf(mon, " Detect zeroes: %s\n",
|
||||
BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
|
||||
}
|
||||
|
||||
if (info->value->inserted->bps
|
||||
|| info->value->inserted->bps_rd
|
||||
|| info->value->inserted->bps_wr
|
||||
@@ -1388,6 +1393,7 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
|
||||
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
Error *err_end = NULL;
|
||||
QemuOpts *opts;
|
||||
char *type = NULL;
|
||||
char *id = NULL;
|
||||
@@ -1411,24 +1417,23 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||
qdict_del(pdict, "qom-type");
|
||||
visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
|
||||
if (err) {
|
||||
goto out_clean;
|
||||
goto out_end;
|
||||
}
|
||||
|
||||
qdict_del(pdict, "id");
|
||||
visit_type_str(opts_get_visitor(ov), &id, "id", &err);
|
||||
if (err) {
|
||||
goto out_clean;
|
||||
goto out_end;
|
||||
}
|
||||
|
||||
object_add(type, id, pdict, opts_get_visitor(ov), &err);
|
||||
if (err) {
|
||||
goto out_clean;
|
||||
}
|
||||
visit_end_struct(opts_get_visitor(ov), &err);
|
||||
if (err) {
|
||||
|
||||
out_end:
|
||||
visit_end_struct(opts_get_visitor(ov), &err_end);
|
||||
if (!err && err_end) {
|
||||
qmp_object_del(id, NULL);
|
||||
}
|
||||
|
||||
error_propagate(&err, err_end);
|
||||
out_clean:
|
||||
opts_visitor_cleanup(ov);
|
||||
|
||||
|
6
hmp.h
6
hmp.h
@@ -97,5 +97,11 @@ void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
|
||||
#endif
|
||||
|
@@ -43,13 +43,13 @@ static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
|
||||
return (slot + 1) * 4 + irq_num;
|
||||
}
|
||||
|
||||
static void clipper_init(QEMUMachineInitArgs *args)
|
||||
static void clipper_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
AlphaCPU *cpus[4];
|
||||
PCIBus *pci_bus;
|
||||
ISABus *isa_bus;
|
||||
|
@@ -23,12 +23,12 @@ static struct arm_boot_info collie_binfo = {
|
||||
.ram_size = 0x20000000,
|
||||
};
|
||||
|
||||
static void collie_init(QEMUMachineInitArgs *args)
|
||||
static void collie_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
StrongARMState *s;
|
||||
DriveInfo *dinfo;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
|
@@ -30,7 +30,7 @@ typedef struct CubieBoardState {
|
||||
MemoryRegion sdram;
|
||||
} CubieBoardState;
|
||||
|
||||
static void cubieboard_init(QEMUMachineInitArgs *args)
|
||||
static void cubieboard_init(MachineState *machine)
|
||||
{
|
||||
CubieBoardState *s = g_new(CubieBoardState, 1);
|
||||
Error *err = NULL;
|
||||
@@ -63,14 +63,15 @@ static void cubieboard_init(QEMUMachineInitArgs *args)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram", args->ram_size);
|
||||
memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram",
|
||||
machine->ram_size);
|
||||
vmstate_register_ram_global(&s->sdram);
|
||||
memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE,
|
||||
&s->sdram);
|
||||
|
||||
cubieboard_binfo.ram_size = args->ram_size;
|
||||
cubieboard_binfo.kernel_filename = args->kernel_filename;
|
||||
cubieboard_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
cubieboard_binfo.ram_size = machine->ram_size;
|
||||
cubieboard_binfo.kernel_filename = machine->kernel_filename;
|
||||
cubieboard_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
arm_load_kernel(&s->a10->cpu, &cubieboard_binfo);
|
||||
}
|
||||
|
||||
|
@@ -143,7 +143,7 @@ static DigicBoard digic4_board_canon_a1100 = {
|
||||
.rom1_def_filename = "canon-a1100-rom1.bin",
|
||||
};
|
||||
|
||||
static void canon_a1100_init(QEMUMachineInitArgs *args)
|
||||
static void canon_a1100_init(MachineState *machine)
|
||||
{
|
||||
digic4_board_init(&digic4_board_canon_a1100);
|
||||
}
|
||||
|
@@ -94,7 +94,7 @@ static void lan9215_init(uint32_t base, qemu_irq irq)
|
||||
}
|
||||
}
|
||||
|
||||
static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
|
||||
static Exynos4210State *exynos4_boards_init_common(MachineState *machine,
|
||||
Exynos4BoardType board_type)
|
||||
{
|
||||
if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) {
|
||||
@@ -108,9 +108,9 @@ static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
|
||||
exynos4_board_binfo.board_id = exynos4_board_id[board_type];
|
||||
exynos4_board_binfo.smp_bootreg_addr =
|
||||
exynos4_board_smp_bootreg_addr[board_type];
|
||||
exynos4_board_binfo.kernel_filename = args->kernel_filename;
|
||||
exynos4_board_binfo.initrd_filename = args->initrd_filename;
|
||||
exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
exynos4_board_binfo.kernel_filename = machine->kernel_filename;
|
||||
exynos4_board_binfo.initrd_filename = machine->initrd_filename;
|
||||
exynos4_board_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
exynos4_board_binfo.gic_cpu_if_addr =
|
||||
EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
|
||||
|
||||
@@ -120,24 +120,24 @@ static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
|
||||
" initrd_filename: %s\n",
|
||||
exynos4_board_ram_size[board_type] / 1048576,
|
||||
exynos4_board_ram_size[board_type],
|
||||
args->kernel_filename,
|
||||
args->kernel_cmdline,
|
||||
args->initrd_filename);
|
||||
machine->kernel_filename,
|
||||
machine->kernel_cmdline,
|
||||
machine->initrd_filename);
|
||||
|
||||
return exynos4210_init(get_system_memory(),
|
||||
exynos4_board_ram_size[board_type]);
|
||||
}
|
||||
|
||||
static void nuri_init(QEMUMachineInitArgs *args)
|
||||
static void nuri_init(MachineState *machine)
|
||||
{
|
||||
exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI);
|
||||
exynos4_boards_init_common(machine, EXYNOS4_BOARD_NURI);
|
||||
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo);
|
||||
}
|
||||
|
||||
static void smdkc210_init(QEMUMachineInitArgs *args)
|
||||
static void smdkc210_init(MachineState *machine)
|
||||
{
|
||||
Exynos4210State *s = exynos4_boards_init_common(args,
|
||||
Exynos4210State *s = exynos4_boards_init_common(machine,
|
||||
EXYNOS4_BOARD_SMDKC210);
|
||||
|
||||
lan9215_init(SMDK_LAN9118_BASE_ADDR,
|
||||
|
@@ -46,7 +46,7 @@
|
||||
|
||||
static const int sector_len = 128 * 1024;
|
||||
|
||||
static void connex_init(QEMUMachineInitArgs *args)
|
||||
static void connex_init(MachineState *machine)
|
||||
{
|
||||
PXA2xxState *cpu;
|
||||
DriveInfo *dinfo;
|
||||
@@ -83,9 +83,9 @@ static void connex_init(QEMUMachineInitArgs *args)
|
||||
qdev_get_gpio_in(cpu->gpio, 36));
|
||||
}
|
||||
|
||||
static void verdex_init(QEMUMachineInitArgs *args)
|
||||
static void verdex_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
PXA2xxState *cpu;
|
||||
DriveInfo *dinfo;
|
||||
int be;
|
||||
|
@@ -199,13 +199,13 @@ enum cxmachines {
|
||||
* 32-bit host, set the reg value of memory to 0xf7ff00000 in the
|
||||
* device tree and pass -m 2047 to QEMU.
|
||||
*/
|
||||
static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
|
||||
static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
DeviceState *dev = NULL;
|
||||
SysBusDevice *busdev;
|
||||
qemu_irq pic[128];
|
||||
@@ -217,7 +217,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
|
||||
char *sysboot_filename;
|
||||
|
||||
if (!cpu_model) {
|
||||
switch (machine) {
|
||||
switch (machine_id) {
|
||||
case CALXEDA_HIGHBANK:
|
||||
cpu_model = "cortex-a9";
|
||||
break;
|
||||
@@ -274,7 +274,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
|
||||
}
|
||||
}
|
||||
|
||||
switch (machine) {
|
||||
switch (machine_id) {
|
||||
case CALXEDA_HIGHBANK:
|
||||
dev = qdev_create(NULL, "l2x0");
|
||||
qdev_init_nofail(dev);
|
||||
@@ -359,14 +359,14 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo);
|
||||
}
|
||||
|
||||
static void highbank_init(QEMUMachineInitArgs *args)
|
||||
static void highbank_init(MachineState *machine)
|
||||
{
|
||||
calxeda_init(args, CALXEDA_HIGHBANK);
|
||||
calxeda_init(machine, CALXEDA_HIGHBANK);
|
||||
}
|
||||
|
||||
static void midway_init(QEMUMachineInitArgs *args)
|
||||
static void midway_init(MachineState *machine)
|
||||
{
|
||||
calxeda_init(args, CALXEDA_MIDWAY);
|
||||
calxeda_init(machine, CALXEDA_MIDWAY);
|
||||
}
|
||||
|
||||
static QEMUMachine highbank_machine = {
|
||||
|
@@ -461,13 +461,13 @@ static struct arm_boot_info integrator_binfo = {
|
||||
.board_id = 0x113,
|
||||
};
|
||||
|
||||
static void integratorcp_init(QEMUMachineInitArgs *args)
|
||||
static void integratorcp_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
|
12
hw/arm/kzm.c
12
hw/arm/kzm.c
@@ -70,13 +70,13 @@ static struct arm_boot_info kzm_binfo = {
|
||||
.board_id = 1722,
|
||||
};
|
||||
|
||||
static void kzm_init(QEMUMachineInitArgs *args)
|
||||
static void kzm_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
|
@@ -105,7 +105,7 @@ static struct arm_boot_info mainstone_binfo = {
|
||||
};
|
||||
|
||||
static void mainstone_common_init(MemoryRegion *address_space_mem,
|
||||
QEMUMachineInitArgs *args,
|
||||
MachineState *machine,
|
||||
enum mainstone_model_e model, int arm_id)
|
||||
{
|
||||
uint32_t sector_len = 256 * 1024;
|
||||
@@ -116,7 +116,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
|
||||
int i;
|
||||
int be;
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
|
||||
if (!cpu_model)
|
||||
cpu_model = "pxa270-c5";
|
||||
@@ -175,16 +175,16 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
|
||||
smc91c111_init(&nd_table[0], MST_ETH_PHYS,
|
||||
qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
|
||||
|
||||
mainstone_binfo.kernel_filename = args->kernel_filename;
|
||||
mainstone_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
mainstone_binfo.initrd_filename = args->initrd_filename;
|
||||
mainstone_binfo.kernel_filename = machine->kernel_filename;
|
||||
mainstone_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
mainstone_binfo.initrd_filename = machine->initrd_filename;
|
||||
mainstone_binfo.board_id = arm_id;
|
||||
arm_load_kernel(mpu->cpu, &mainstone_binfo);
|
||||
}
|
||||
|
||||
static void mainstone_init(QEMUMachineInitArgs *args)
|
||||
static void mainstone_init(MachineState *machine)
|
||||
{
|
||||
mainstone_common_init(get_system_memory(), args, mainstone, 0x196);
|
||||
mainstone_common_init(get_system_memory(), machine, mainstone, 0x196);
|
||||
}
|
||||
|
||||
static QEMUMachine mainstone2_machine = {
|
||||
|
@@ -1569,12 +1569,12 @@ static struct arm_boot_info musicpal_binfo = {
|
||||
.board_id = 0x20e,
|
||||
};
|
||||
|
||||
static void musicpal_init(QEMUMachineInitArgs *args)
|
||||
static void musicpal_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
ARMCPU *cpu;
|
||||
qemu_irq pic[32];
|
||||
DeviceState *dev;
|
||||
|
@@ -1278,14 +1278,14 @@ static int n810_atag_setup(const struct arm_boot_info *info, void *p)
|
||||
return n8x0_atag_setup(p, 810);
|
||||
}
|
||||
|
||||
static void n8x0_init(QEMUMachineInitArgs *args,
|
||||
static void n8x0_init(MachineState *machine,
|
||||
struct arm_boot_info *binfo, int model)
|
||||
{
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
|
||||
int sdram_size = binfo->ram_size;
|
||||
|
||||
s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model);
|
||||
s->mpu = omap2420_mpu_init(sysmem, sdram_size, machine->cpu_model);
|
||||
|
||||
/* Setup peripherals
|
||||
*
|
||||
@@ -1329,18 +1329,18 @@ static void n8x0_init(QEMUMachineInitArgs *args,
|
||||
n8x0_usb_setup(s);
|
||||
}
|
||||
|
||||
if (args->kernel_filename) {
|
||||
if (machine->kernel_filename) {
|
||||
/* Or at the linux loader. */
|
||||
binfo->kernel_filename = args->kernel_filename;
|
||||
binfo->kernel_cmdline = args->kernel_cmdline;
|
||||
binfo->initrd_filename = args->initrd_filename;
|
||||
binfo->kernel_filename = machine->kernel_filename;
|
||||
binfo->kernel_cmdline = machine->kernel_cmdline;
|
||||
binfo->initrd_filename = machine->initrd_filename;
|
||||
arm_load_kernel(s->mpu->cpu, binfo);
|
||||
|
||||
qemu_register_reset(n8x0_boot_init, s);
|
||||
}
|
||||
|
||||
if (option_rom[0].name &&
|
||||
(args->boot_order[0] == 'n' || !args->kernel_filename)) {
|
||||
(machine->boot_order[0] == 'n' || !machine->kernel_filename)) {
|
||||
uint8_t nolo_tags[0x10000];
|
||||
/* No, wait, better start at the ROM. */
|
||||
s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
|
||||
@@ -1382,14 +1382,14 @@ static struct arm_boot_info n810_binfo = {
|
||||
.atag_board = n810_atag_setup,
|
||||
};
|
||||
|
||||
static void n800_init(QEMUMachineInitArgs *args)
|
||||
static void n800_init(MachineState *machine)
|
||||
{
|
||||
return n8x0_init(args, &n800_binfo, 800);
|
||||
return n8x0_init(machine, &n800_binfo, 800);
|
||||
}
|
||||
|
||||
static void n810_init(QEMUMachineInitArgs *args)
|
||||
static void n810_init(MachineState *machine)
|
||||
{
|
||||
return n8x0_init(args, &n810_binfo, 810);
|
||||
return n8x0_init(machine, &n810_binfo, 810);
|
||||
}
|
||||
|
||||
static QEMUMachine n800_machine = {
|
||||
|
@@ -98,7 +98,7 @@ static struct arm_boot_info sx1_binfo = {
|
||||
.board_id = 0x265,
|
||||
};
|
||||
|
||||
static void sx1_init(QEMUMachineInitArgs *args, const int version)
|
||||
static void sx1_init(MachineState *machine, const int version)
|
||||
{
|
||||
struct omap_mpu_state_s *mpu;
|
||||
MemoryRegion *address_space = get_system_memory();
|
||||
@@ -118,7 +118,8 @@ static void sx1_init(QEMUMachineInitArgs *args, const int version)
|
||||
flash_size = flash2_size;
|
||||
}
|
||||
|
||||
mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model);
|
||||
mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size,
|
||||
machine->cpu_model);
|
||||
|
||||
/* External Flash (EMIFS) */
|
||||
memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size);
|
||||
@@ -189,29 +190,29 @@ static void sx1_init(QEMUMachineInitArgs *args, const int version)
|
||||
OMAP_CS1_BASE, &cs[1]);
|
||||
}
|
||||
|
||||
if (!args->kernel_filename && !fl_idx && !qtest_enabled()) {
|
||||
if (!machine->kernel_filename && !fl_idx && !qtest_enabled()) {
|
||||
fprintf(stderr, "Kernel or Flash image must be specified\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Load the kernel. */
|
||||
sx1_binfo.kernel_filename = args->kernel_filename;
|
||||
sx1_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
sx1_binfo.initrd_filename = args->initrd_filename;
|
||||
sx1_binfo.kernel_filename = machine->kernel_filename;
|
||||
sx1_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
sx1_binfo.initrd_filename = machine->initrd_filename;
|
||||
arm_load_kernel(mpu->cpu, &sx1_binfo);
|
||||
|
||||
/* TODO: fix next line */
|
||||
//~ qemu_console_resize(ds, 640, 480);
|
||||
}
|
||||
|
||||
static void sx1_init_v1(QEMUMachineInitArgs *args)
|
||||
static void sx1_init_v1(MachineState *machine)
|
||||
{
|
||||
sx1_init(args, 1);
|
||||
sx1_init(machine, 1);
|
||||
}
|
||||
|
||||
static void sx1_init_v2(QEMUMachineInitArgs *args)
|
||||
static void sx1_init_v2(MachineState *machine)
|
||||
{
|
||||
sx1_init(args, 2);
|
||||
sx1_init(machine, 2);
|
||||
}
|
||||
|
||||
static QEMUMachine sx1_machine_v2 = {
|
||||
|
@@ -191,12 +191,12 @@ static struct arm_boot_info palmte_binfo = {
|
||||
.board_id = 0x331,
|
||||
};
|
||||
|
||||
static void palmte_init(QEMUMachineInitArgs *args)
|
||||
static void palmte_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
struct omap_mpu_state_s *mpu;
|
||||
int flash_size = 0x00800000;
|
||||
|
@@ -45,7 +45,7 @@ static const int realview_board_id[] = {
|
||||
0x76d
|
||||
};
|
||||
|
||||
static void realview_init(QEMUMachineInitArgs *args,
|
||||
static void realview_init(MachineState *machine,
|
||||
enum realview_board_type board_type)
|
||||
{
|
||||
ARMCPU *cpu = NULL;
|
||||
@@ -71,7 +71,7 @@ static void realview_init(QEMUMachineInitArgs *args,
|
||||
uint32_t proc_id = 0;
|
||||
uint32_t sys_id;
|
||||
ram_addr_t low_ram_size;
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
hwaddr periphbase = 0;
|
||||
|
||||
switch (board_type) {
|
||||
@@ -91,7 +91,7 @@ static void realview_init(QEMUMachineInitArgs *args,
|
||||
break;
|
||||
}
|
||||
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, args->cpu_model);
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
|
||||
if (!cpu_oc) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
@@ -342,45 +342,45 @@ static void realview_init(QEMUMachineInitArgs *args,
|
||||
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
|
||||
|
||||
realview_binfo.ram_size = ram_size;
|
||||
realview_binfo.kernel_filename = args->kernel_filename;
|
||||
realview_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
realview_binfo.initrd_filename = args->initrd_filename;
|
||||
realview_binfo.kernel_filename = machine->kernel_filename;
|
||||
realview_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
realview_binfo.initrd_filename = machine->initrd_filename;
|
||||
realview_binfo.nb_cpus = smp_cpus;
|
||||
realview_binfo.board_id = realview_board_id[board_type];
|
||||
realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &realview_binfo);
|
||||
}
|
||||
|
||||
static void realview_eb_init(QEMUMachineInitArgs *args)
|
||||
static void realview_eb_init(MachineState *machine)
|
||||
{
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "arm926";
|
||||
if (!machine->cpu_model) {
|
||||
machine->cpu_model = "arm926";
|
||||
}
|
||||
realview_init(args, BOARD_EB);
|
||||
realview_init(machine, BOARD_EB);
|
||||
}
|
||||
|
||||
static void realview_eb_mpcore_init(QEMUMachineInitArgs *args)
|
||||
static void realview_eb_mpcore_init(MachineState *machine)
|
||||
{
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "arm11mpcore";
|
||||
if (!machine->cpu_model) {
|
||||
machine->cpu_model = "arm11mpcore";
|
||||
}
|
||||
realview_init(args, BOARD_EB_MPCORE);
|
||||
realview_init(machine, BOARD_EB_MPCORE);
|
||||
}
|
||||
|
||||
static void realview_pb_a8_init(QEMUMachineInitArgs *args)
|
||||
static void realview_pb_a8_init(MachineState *machine)
|
||||
{
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "cortex-a8";
|
||||
if (!machine->cpu_model) {
|
||||
machine->cpu_model = "cortex-a8";
|
||||
}
|
||||
realview_init(args, BOARD_PB_A8);
|
||||
realview_init(machine, BOARD_PB_A8);
|
||||
}
|
||||
|
||||
static void realview_pbx_a9_init(QEMUMachineInitArgs *args)
|
||||
static void realview_pbx_a9_init(MachineState *machine)
|
||||
{
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "cortex-a9";
|
||||
if (!machine->cpu_model) {
|
||||
machine->cpu_model = "cortex-a9";
|
||||
}
|
||||
realview_init(args, BOARD_PBX_A9);
|
||||
realview_init(machine, BOARD_PBX_A9);
|
||||
}
|
||||
|
||||
static QEMUMachine realview_eb_machine = {
|
||||
|
@@ -887,14 +887,14 @@ static struct arm_boot_info spitz_binfo = {
|
||||
.ram_size = 0x04000000,
|
||||
};
|
||||
|
||||
static void spitz_common_init(QEMUMachineInitArgs *args,
|
||||
static void spitz_common_init(MachineState *machine,
|
||||
enum spitz_model_e model, int arm_id)
|
||||
{
|
||||
PXA2xxState *mpu;
|
||||
DeviceState *scp0, *scp1 = NULL;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
|
||||
if (!cpu_model)
|
||||
cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
|
||||
@@ -935,32 +935,32 @@ static void spitz_common_init(QEMUMachineInitArgs *args,
|
||||
/* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
|
||||
spitz_microdrive_attach(mpu, 0);
|
||||
|
||||
spitz_binfo.kernel_filename = args->kernel_filename;
|
||||
spitz_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
spitz_binfo.initrd_filename = args->initrd_filename;
|
||||
spitz_binfo.kernel_filename = machine->kernel_filename;
|
||||
spitz_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
spitz_binfo.initrd_filename = machine->initrd_filename;
|
||||
spitz_binfo.board_id = arm_id;
|
||||
arm_load_kernel(mpu->cpu, &spitz_binfo);
|
||||
sl_bootparam_write(SL_PXA_PARAM_BASE);
|
||||
}
|
||||
|
||||
static void spitz_init(QEMUMachineInitArgs *args)
|
||||
static void spitz_init(MachineState *machine)
|
||||
{
|
||||
spitz_common_init(args, spitz, 0x2c9);
|
||||
spitz_common_init(machine, spitz, 0x2c9);
|
||||
}
|
||||
|
||||
static void borzoi_init(QEMUMachineInitArgs *args)
|
||||
static void borzoi_init(MachineState *machine)
|
||||
{
|
||||
spitz_common_init(args, borzoi, 0x33f);
|
||||
spitz_common_init(machine, borzoi, 0x33f);
|
||||
}
|
||||
|
||||
static void akita_init(QEMUMachineInitArgs *args)
|
||||
static void akita_init(MachineState *machine)
|
||||
{
|
||||
spitz_common_init(args, akita, 0x2e8);
|
||||
spitz_common_init(machine, akita, 0x2e8);
|
||||
}
|
||||
|
||||
static void terrier_init(QEMUMachineInitArgs *args)
|
||||
static void terrier_init(MachineState *machine)
|
||||
{
|
||||
spitz_common_init(args, terrier, 0x33f);
|
||||
spitz_common_init(machine, terrier, 0x33f);
|
||||
}
|
||||
|
||||
static QEMUMachine akitapda_machine = {
|
||||
|
@@ -1290,9 +1290,10 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
|
||||
|
||||
sddev = ssi_create_slave(bus, "ssi-sd");
|
||||
ssddev = ssi_create_slave(bus, "ssd0323");
|
||||
gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0),
|
||||
qdev_get_gpio_in(ssddev, 0));
|
||||
gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1);
|
||||
gpio_out[GPIO_D][0] = qemu_irq_split(
|
||||
qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0),
|
||||
qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0));
|
||||
gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0);
|
||||
|
||||
/* Make sure the select pin is high. */
|
||||
qemu_irq_raise(gpio_out[GPIO_D][0]);
|
||||
@@ -1333,17 +1334,17 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
|
||||
}
|
||||
|
||||
/* FIXME: Figure out how to generate these from stellaris_boards. */
|
||||
static void lm3s811evb_init(QEMUMachineInitArgs *args)
|
||||
static void lm3s811evb_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
|
||||
}
|
||||
|
||||
static void lm3s6965evb_init(QEMUMachineInitArgs *args)
|
||||
static void lm3s6965evb_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
|
||||
}
|
||||
|
||||
|
@@ -211,12 +211,12 @@ static struct arm_boot_info tosa_binfo = {
|
||||
.ram_size = 0x04000000,
|
||||
};
|
||||
|
||||
static void tosa_init(QEMUMachineInitArgs *args)
|
||||
static void tosa_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
PXA2xxState *mpu;
|
||||
|
@@ -173,7 +173,7 @@ static int vpb_sic_init(SysBusDevice *sbd)
|
||||
|
||||
static struct arm_boot_info versatile_binfo;
|
||||
|
||||
static void versatile_init(QEMUMachineInitArgs *args, int board_id)
|
||||
static void versatile_init(MachineState *machine, int board_id)
|
||||
{
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
@@ -190,15 +190,15 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id)
|
||||
int done_smc = 0;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "arm926";
|
||||
if (!machine->cpu_model) {
|
||||
machine->cpu_model = "arm926";
|
||||
}
|
||||
cpu = cpu_arm_init(args->cpu_model);
|
||||
cpu = cpu_arm_init(machine->cpu_model);
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
memory_region_init_ram(ram, NULL, "versatile.ram", args->ram_size);
|
||||
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size);
|
||||
vmstate_register_ram_global(ram);
|
||||
/* ??? RAM should repeat to fill physical memory space. */
|
||||
/* SDRAM at address zero. */
|
||||
@@ -344,22 +344,22 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id)
|
||||
fprintf(stderr, "qemu: Error registering flash memory.\n");
|
||||
}
|
||||
|
||||
versatile_binfo.ram_size = args->ram_size;
|
||||
versatile_binfo.kernel_filename = args->kernel_filename;
|
||||
versatile_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
versatile_binfo.initrd_filename = args->initrd_filename;
|
||||
versatile_binfo.ram_size = machine->ram_size;
|
||||
versatile_binfo.kernel_filename = machine->kernel_filename;
|
||||
versatile_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
versatile_binfo.initrd_filename = machine->initrd_filename;
|
||||
versatile_binfo.board_id = board_id;
|
||||
arm_load_kernel(cpu, &versatile_binfo);
|
||||
}
|
||||
|
||||
static void vpb_init(QEMUMachineInitArgs *args)
|
||||
static void vpb_init(MachineState *machine)
|
||||
{
|
||||
versatile_init(args, 0x183);
|
||||
versatile_init(machine, 0x183);
|
||||
}
|
||||
|
||||
static void vab_init(QEMUMachineInitArgs *args)
|
||||
static void vab_init(MachineState *machine)
|
||||
{
|
||||
versatile_init(args, 0x25e);
|
||||
versatile_init(machine, 0x25e);
|
||||
}
|
||||
|
||||
static QEMUMachine versatilepb_machine = {
|
||||
|
@@ -509,7 +509,7 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
|
||||
}
|
||||
|
||||
static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
QEMUMachineInitArgs *args)
|
||||
MachineState *machine)
|
||||
{
|
||||
DeviceState *dev, *sysctl, *pl041;
|
||||
qemu_irq pic[64];
|
||||
@@ -525,7 +525,8 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
const hwaddr *map = daughterboard->motherboard_map;
|
||||
int i;
|
||||
|
||||
daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic);
|
||||
daughterboard->init(daughterboard, machine->ram_size, machine->cpu_model,
|
||||
pic);
|
||||
|
||||
/* Motherboard peripherals: the wiring is the same but the
|
||||
* addresses vary between the legacy and A-Series memory maps.
|
||||
@@ -639,10 +640,10 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
pic[40 + i]);
|
||||
}
|
||||
|
||||
daughterboard->bootinfo.ram_size = args->ram_size;
|
||||
daughterboard->bootinfo.kernel_filename = args->kernel_filename;
|
||||
daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline;
|
||||
daughterboard->bootinfo.initrd_filename = args->initrd_filename;
|
||||
daughterboard->bootinfo.ram_size = machine->ram_size;
|
||||
daughterboard->bootinfo.kernel_filename = machine->kernel_filename;
|
||||
daughterboard->bootinfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
daughterboard->bootinfo.initrd_filename = machine->initrd_filename;
|
||||
daughterboard->bootinfo.nb_cpus = smp_cpus;
|
||||
daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID;
|
||||
daughterboard->bootinfo.loader_start = daughterboard->loader_start;
|
||||
@@ -653,14 +654,14 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
|
||||
}
|
||||
|
||||
static void vexpress_a9_init(QEMUMachineInitArgs *args)
|
||||
static void vexpress_a9_init(MachineState *machine)
|
||||
{
|
||||
vexpress_common_init(&a9_daughterboard, args);
|
||||
vexpress_common_init(&a9_daughterboard, machine);
|
||||
}
|
||||
|
||||
static void vexpress_a15_init(QEMUMachineInitArgs *args)
|
||||
static void vexpress_a15_init(MachineState *machine)
|
||||
{
|
||||
vexpress_common_init(&a15_daughterboard, args);
|
||||
vexpress_common_init(&a15_daughterboard, machine);
|
||||
}
|
||||
|
||||
static QEMUMachine vexpress_a9_machine = {
|
||||
|
@@ -383,13 +383,13 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||
return board->fdt;
|
||||
}
|
||||
|
||||
static void machvirt_init(QEMUMachineInitArgs *args)
|
||||
static void machvirt_init(MachineState *machine)
|
||||
{
|
||||
qemu_irq pic[NUM_IRQS];
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
int n;
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
VirtBoardInfo *vbi;
|
||||
|
||||
if (!cpu_model) {
|
||||
@@ -415,7 +415,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (args->ram_size > vbi->memmap[VIRT_MEM].size) {
|
||||
if (machine->ram_size > vbi->memmap[VIRT_MEM].size) {
|
||||
error_report("mach-virt: cannot model more than 30GB RAM");
|
||||
exit(1);
|
||||
}
|
||||
@@ -447,7 +447,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
||||
}
|
||||
fdt_add_cpu_nodes(vbi);
|
||||
|
||||
memory_region_init_ram(ram, NULL, "mach-virt.ram", args->ram_size);
|
||||
memory_region_init_ram(ram, NULL, "mach-virt.ram", machine->ram_size);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
||||
|
||||
@@ -461,10 +461,10 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
||||
*/
|
||||
create_virtio_devices(vbi, pic);
|
||||
|
||||
vbi->bootinfo.ram_size = args->ram_size;
|
||||
vbi->bootinfo.kernel_filename = args->kernel_filename;
|
||||
vbi->bootinfo.kernel_cmdline = args->kernel_cmdline;
|
||||
vbi->bootinfo.initrd_filename = args->initrd_filename;
|
||||
vbi->bootinfo.ram_size = machine->ram_size;
|
||||
vbi->bootinfo.kernel_filename = machine->kernel_filename;
|
||||
vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
vbi->bootinfo.initrd_filename = machine->initrd_filename;
|
||||
vbi->bootinfo.nb_cpus = smp_cpus;
|
||||
vbi->bootinfo.board_id = -1;
|
||||
vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
|
||||
|
@@ -94,20 +94,20 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
|
||||
for (j = 0; j < num_ss; ++j) {
|
||||
flash_dev = ssi_create_slave(spi, "n25q128");
|
||||
|
||||
cs_line = qdev_get_gpio_in(flash_dev, 0);
|
||||
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void zynq_init(QEMUMachineInitArgs *args)
|
||||
static void zynq_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
ObjectClass *cpu_oc;
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
|
10
hw/arm/z2.c
10
hw/arm/z2.c
@@ -300,12 +300,12 @@ static const TypeInfo aer915_info = {
|
||||
.class_init = aer915_class_init,
|
||||
};
|
||||
|
||||
static void z2_init(QEMUMachineInitArgs *args)
|
||||
static void z2_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
uint32_t sector_len = 0x10000;
|
||||
PXA2xxState *mpu;
|
||||
|
@@ -245,7 +245,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
|
||||
|
||||
/* update global status */
|
||||
if (sts & d->int_ctl) {
|
||||
sts |= (1 << 31);
|
||||
sts |= (1U << 31);
|
||||
}
|
||||
|
||||
d->int_sts = sts;
|
||||
@@ -257,7 +257,7 @@ static void intel_hda_update_irq(IntelHDAState *d)
|
||||
int level;
|
||||
|
||||
intel_hda_update_int_sts(d);
|
||||
if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
|
||||
if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) {
|
||||
level = 1;
|
||||
} else {
|
||||
level = 0;
|
||||
@@ -574,7 +574,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
|
||||
if (st->ctl & 0x01) {
|
||||
/* reset */
|
||||
dprint(d, 1, "st #%d: reset\n", reg->stream);
|
||||
st->ctl = 0;
|
||||
st->ctl = SD_STS_FIFO_READY << 24;
|
||||
}
|
||||
if ((st->ctl & 0x02) != (old & 0x02)) {
|
||||
uint32_t stnr = (st->ctl >> 20) & 0x0f;
|
||||
@@ -829,6 +829,7 @@ static const struct IntelHDAReg regtab[] = {
|
||||
.wclear = 0x1c000000, \
|
||||
.offset = offsetof(IntelHDAState, st[_i].ctl), \
|
||||
.whandler = intel_hda_set_st_ctl, \
|
||||
.reset = SD_STS_FIFO_READY << 24 \
|
||||
}, \
|
||||
[ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \
|
||||
.stream = _i, \
|
||||
|
@@ -70,6 +70,9 @@ struct VirtIOBlockDataPlane {
|
||||
queue */
|
||||
|
||||
unsigned int num_reqs;
|
||||
|
||||
/* Operation blocker on BDS */
|
||||
Error *blocker;
|
||||
};
|
||||
|
||||
/* Raise an interrupt to signal guest, if necessary */
|
||||
@@ -350,6 +353,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
{
|
||||
VirtIOBlockDataPlane *s;
|
||||
int fd;
|
||||
Error *local_err = NULL;
|
||||
|
||||
*dataplane = NULL;
|
||||
|
||||
@@ -372,9 +376,10 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
/* If dataplane is (re-)enabled while the guest is running there could be
|
||||
* block jobs that can conflict.
|
||||
*/
|
||||
if (bdrv_in_use(blk->conf.bs)) {
|
||||
error_setg(errp,
|
||||
"cannot start dataplane thread while device is in use");
|
||||
if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) {
|
||||
error_report("cannot start dataplane thread: %s",
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -406,8 +411,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
}
|
||||
s->ctx = iothread_get_aio_context(s->iothread);
|
||||
|
||||
/* Prevent block operations that conflict with data plane thread */
|
||||
bdrv_set_in_use(blk->conf.bs, 1);
|
||||
error_setg(&s->blocker, "block device is in use by data plane");
|
||||
bdrv_op_block_all(blk->conf.bs, s->blocker);
|
||||
|
||||
*dataplane = s;
|
||||
}
|
||||
@@ -420,7 +425,8 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
|
||||
}
|
||||
|
||||
virtio_blk_data_plane_stop(s);
|
||||
bdrv_set_in_use(s->blk->conf.bs, 0);
|
||||
bdrv_op_unblock_all(s->blk->conf.bs, s->blocker);
|
||||
error_free(s->blocker);
|
||||
object_unref(OBJECT(s->iothread));
|
||||
g_free(s);
|
||||
}
|
||||
|
@@ -11,6 +11,284 @@
|
||||
*/
|
||||
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/visitor.h"
|
||||
|
||||
static char *machine_get_accel(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return g_strdup(ms->accel);
|
||||
}
|
||||
|
||||
static void machine_set_accel(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->accel = g_strdup(value);
|
||||
}
|
||||
|
||||
static bool machine_get_kernel_irqchip(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return ms->kernel_irqchip;
|
||||
}
|
||||
|
||||
static void machine_set_kernel_irqchip(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->kernel_irqchip = value;
|
||||
}
|
||||
|
||||
static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v,
|
||||
void *opaque, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
int64_t value = ms->kvm_shadow_mem;
|
||||
|
||||
visit_type_int(v, &value, name, errp);
|
||||
}
|
||||
|
||||
static void machine_set_kvm_shadow_mem(Object *obj, Visitor *v,
|
||||
void *opaque, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
Error *error = NULL;
|
||||
int64_t value;
|
||||
|
||||
visit_type_int(v, &value, name, &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return;
|
||||
}
|
||||
|
||||
ms->kvm_shadow_mem = value;
|
||||
}
|
||||
|
||||
static char *machine_get_kernel(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return g_strdup(ms->kernel_filename);
|
||||
}
|
||||
|
||||
static void machine_set_kernel(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->kernel_filename = g_strdup(value);
|
||||
}
|
||||
|
||||
static char *machine_get_initrd(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return g_strdup(ms->initrd_filename);
|
||||
}
|
||||
|
||||
static void machine_set_initrd(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->initrd_filename = g_strdup(value);
|
||||
}
|
||||
|
||||
static char *machine_get_append(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return g_strdup(ms->kernel_cmdline);
|
||||
}
|
||||
|
||||
static void machine_set_append(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->kernel_cmdline = g_strdup(value);
|
||||
}
|
||||
|
||||
static char *machine_get_dtb(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return g_strdup(ms->dtb);
|
||||
}
|
||||
|
||||
static void machine_set_dtb(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->dtb = g_strdup(value);
|
||||
}
|
||||
|
||||
static char *machine_get_dumpdtb(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return g_strdup(ms->dumpdtb);
|
||||
}
|
||||
|
||||
static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->dumpdtb = g_strdup(value);
|
||||
}
|
||||
|
||||
static void machine_get_phandle_start(Object *obj, Visitor *v,
|
||||
void *opaque, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
int64_t value = ms->phandle_start;
|
||||
|
||||
visit_type_int(v, &value, name, errp);
|
||||
}
|
||||
|
||||
static void machine_set_phandle_start(Object *obj, Visitor *v,
|
||||
void *opaque, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
Error *error = NULL;
|
||||
int64_t value;
|
||||
|
||||
visit_type_int(v, &value, name, &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return;
|
||||
}
|
||||
|
||||
ms->phandle_start = value;
|
||||
}
|
||||
|
||||
static char *machine_get_dt_compatible(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return g_strdup(ms->dt_compatible);
|
||||
}
|
||||
|
||||
static void machine_set_dt_compatible(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->dt_compatible = g_strdup(value);
|
||||
}
|
||||
|
||||
static bool machine_get_dump_guest_core(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return ms->dump_guest_core;
|
||||
}
|
||||
|
||||
static void machine_set_dump_guest_core(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->dump_guest_core = value;
|
||||
}
|
||||
|
||||
static bool machine_get_mem_merge(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return ms->mem_merge;
|
||||
}
|
||||
|
||||
static void machine_set_mem_merge(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->mem_merge = value;
|
||||
}
|
||||
|
||||
static bool machine_get_usb(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return ms->usb;
|
||||
}
|
||||
|
||||
static void machine_set_usb(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->usb = value;
|
||||
}
|
||||
|
||||
static char *machine_get_firmware(Object *obj, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
return g_strdup(ms->firmware);
|
||||
}
|
||||
|
||||
static void machine_set_firmware(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
ms->firmware = g_strdup(value);
|
||||
}
|
||||
|
||||
static void machine_initfn(Object *obj)
|
||||
{
|
||||
object_property_add_str(obj, "accel",
|
||||
machine_get_accel, machine_set_accel, NULL);
|
||||
object_property_add_bool(obj, "kernel_irqchip",
|
||||
machine_get_kernel_irqchip,
|
||||
machine_set_kernel_irqchip,
|
||||
NULL);
|
||||
object_property_add(obj, "kvm_shadow_mem", "int",
|
||||
machine_get_kvm_shadow_mem,
|
||||
machine_set_kvm_shadow_mem,
|
||||
NULL, NULL, NULL);
|
||||
object_property_add_str(obj, "kernel",
|
||||
machine_get_kernel, machine_set_kernel, NULL);
|
||||
object_property_add_str(obj, "initrd",
|
||||
machine_get_initrd, machine_set_initrd, NULL);
|
||||
object_property_add_str(obj, "append",
|
||||
machine_get_append, machine_set_append, NULL);
|
||||
object_property_add_str(obj, "dtb",
|
||||
machine_get_dtb, machine_set_dtb, NULL);
|
||||
object_property_add_str(obj, "dumpdtb",
|
||||
machine_get_dumpdtb, machine_set_dumpdtb, NULL);
|
||||
object_property_add(obj, "phandle_start", "int",
|
||||
machine_get_phandle_start,
|
||||
machine_set_phandle_start,
|
||||
NULL, NULL, NULL);
|
||||
object_property_add_str(obj, "dt_compatible",
|
||||
machine_get_dt_compatible,
|
||||
machine_set_dt_compatible,
|
||||
NULL);
|
||||
object_property_add_bool(obj, "dump-guest-core",
|
||||
machine_get_dump_guest_core,
|
||||
machine_set_dump_guest_core,
|
||||
NULL);
|
||||
object_property_add_bool(obj, "mem-merge",
|
||||
machine_get_mem_merge, machine_set_mem_merge, NULL);
|
||||
object_property_add_bool(obj, "usb", machine_get_usb, machine_set_usb, NULL);
|
||||
object_property_add_str(obj, "firmware",
|
||||
machine_get_firmware, machine_set_firmware, NULL);
|
||||
}
|
||||
|
||||
static void machine_finalize(Object *obj)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
g_free(ms->accel);
|
||||
g_free(ms->kernel_filename);
|
||||
g_free(ms->initrd_filename);
|
||||
g_free(ms->kernel_cmdline);
|
||||
g_free(ms->dtb);
|
||||
g_free(ms->dumpdtb);
|
||||
g_free(ms->dt_compatible);
|
||||
g_free(ms->firmware);
|
||||
}
|
||||
|
||||
static const TypeInfo machine_info = {
|
||||
.name = TYPE_MACHINE,
|
||||
@@ -18,6 +296,8 @@ static const TypeInfo machine_info = {
|
||||
.abstract = true,
|
||||
.class_size = sizeof(MachineClass),
|
||||
.instance_size = sizeof(MachineState),
|
||||
.instance_init = machine_initfn,
|
||||
.instance_finalize = machine_finalize,
|
||||
};
|
||||
|
||||
static void machine_register_types(void)
|
||||
|
@@ -15,7 +15,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
static void machine_none_init(QEMUMachineInitArgs *args)
|
||||
static void machine_none_init(MachineState *machine)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -312,30 +312,82 @@ BusState *qdev_get_parent_bus(DeviceState *dev)
|
||||
return dev->parent_bus;
|
||||
}
|
||||
|
||||
static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
|
||||
const char *name)
|
||||
{
|
||||
NamedGPIOList *ngl;
|
||||
|
||||
QLIST_FOREACH(ngl, &dev->gpios, node) {
|
||||
/* NULL is a valid and matchable name, otherwise do a normal
|
||||
* strcmp match.
|
||||
*/
|
||||
if ((!ngl->name && !name) ||
|
||||
(name && ngl->name && strcmp(name, ngl->name) == 0)) {
|
||||
return ngl;
|
||||
}
|
||||
}
|
||||
|
||||
ngl = g_malloc0(sizeof(*ngl));
|
||||
ngl->name = g_strdup(name);
|
||||
QLIST_INSERT_HEAD(&dev->gpios, ngl, node);
|
||||
return ngl;
|
||||
}
|
||||
|
||||
void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler,
|
||||
const char *name, int n)
|
||||
{
|
||||
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
|
||||
|
||||
gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
|
||||
dev, n);
|
||||
gpio_list->num_in += n;
|
||||
}
|
||||
|
||||
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
|
||||
{
|
||||
dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler,
|
||||
dev, n);
|
||||
dev->num_gpio_in += n;
|
||||
qdev_init_gpio_in_named(dev, handler, NULL, n);
|
||||
}
|
||||
|
||||
void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
|
||||
const char *name, int n)
|
||||
{
|
||||
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
|
||||
|
||||
assert(gpio_list->num_out == 0);
|
||||
gpio_list->num_out = n;
|
||||
gpio_list->out = pins;
|
||||
}
|
||||
|
||||
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
|
||||
{
|
||||
assert(dev->num_gpio_out == 0);
|
||||
dev->num_gpio_out = n;
|
||||
dev->gpio_out = pins;
|
||||
qdev_init_gpio_out_named(dev, pins, NULL, n);
|
||||
}
|
||||
|
||||
qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n)
|
||||
{
|
||||
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
|
||||
|
||||
assert(n >= 0 && n < gpio_list->num_in);
|
||||
return gpio_list->in[n];
|
||||
}
|
||||
|
||||
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
|
||||
{
|
||||
assert(n >= 0 && n < dev->num_gpio_in);
|
||||
return dev->gpio_in[n];
|
||||
return qdev_get_gpio_in_named(dev, NULL, n);
|
||||
}
|
||||
|
||||
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
||||
qemu_irq pin)
|
||||
{
|
||||
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
|
||||
|
||||
assert(n >= 0 && n < gpio_list->num_out);
|
||||
gpio_list->out[n] = pin;
|
||||
}
|
||||
|
||||
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
|
||||
{
|
||||
assert(n >= 0 && n < dev->num_gpio_out);
|
||||
dev->gpio_out[n] = pin;
|
||||
qdev_connect_gpio_out_named(dev, NULL, n, pin);
|
||||
}
|
||||
|
||||
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
|
||||
@@ -844,6 +896,7 @@ static void device_initfn(Object *obj)
|
||||
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
|
||||
(Object **)&dev->parent_bus, NULL, 0,
|
||||
&error_abort);
|
||||
QLIST_INIT(&dev->gpios);
|
||||
}
|
||||
|
||||
static void device_post_init(Object *obj)
|
||||
@@ -854,10 +907,22 @@ static void device_post_init(Object *obj)
|
||||
/* Unlink device from bus and free the structure. */
|
||||
static void device_finalize(Object *obj)
|
||||
{
|
||||
NamedGPIOList *ngl, *next;
|
||||
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
if (dev->opts) {
|
||||
qemu_opts_del(dev->opts);
|
||||
}
|
||||
|
||||
QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) {
|
||||
QLIST_REMOVE(ngl, node);
|
||||
qemu_free_irqs(ngl->in);
|
||||
g_free(ngl->name);
|
||||
g_free(ngl);
|
||||
/* ngl->out irqs are owned by the other end and should not be freed
|
||||
* here
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
static void device_class_base_init(ObjectClass *class, void *data)
|
||||
|
@@ -243,12 +243,12 @@ static const MemoryRegionOps gpio_ops = {
|
||||
static struct cris_load_info li;
|
||||
|
||||
static
|
||||
void axisdev88_init(QEMUMachineInitArgs *args)
|
||||
void axisdev88_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
CRISCPU *cpu;
|
||||
CPUCRISState *env;
|
||||
DeviceState *dev;
|
||||
|
@@ -173,6 +173,7 @@ static void jazz_led_update_display(void *opaque)
|
||||
case 16:
|
||||
color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
|
||||
color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
|
||||
break;
|
||||
case 24:
|
||||
color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
|
||||
color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
|
||||
|
@@ -620,17 +620,6 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
|
||||
src += 2;
|
||||
break;
|
||||
case 1: /* 16 bpp plus transparency */
|
||||
alpha = *(uint16_t *) src & (1 << 24);
|
||||
if (s->control[0] & LCCR0_CMS)
|
||||
r = g = b = *(uint16_t *) src & 0xff;
|
||||
else {
|
||||
r = (*(uint16_t *) src & 0xf800) >> 8;
|
||||
g = (*(uint16_t *) src & 0x07e0) >> 3;
|
||||
b = (*(uint16_t *) src & 0x001f) << 3;
|
||||
}
|
||||
src += 2;
|
||||
break;
|
||||
case 2: /* 18 bpp plus transparency */
|
||||
alpha = *(uint32_t *) src & (1 << 24);
|
||||
if (s->control[0] & LCCR0_CMS)
|
||||
r = g = b = *(uint32_t *) src & 0xff;
|
||||
@@ -641,6 +630,17 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
|
||||
}
|
||||
src += 4;
|
||||
break;
|
||||
case 2: /* 18 bpp plus transparency */
|
||||
alpha = *(uint32_t *) src & (1 << 24);
|
||||
if (s->control[0] & LCCR0_CMS)
|
||||
r = g = b = *(uint32_t *) src & 0xff;
|
||||
else {
|
||||
r = (*(uint32_t *) src & 0xfc0000) >> 16;
|
||||
g = (*(uint32_t *) src & 0x00fc00) >> 8;
|
||||
b = (*(uint32_t *) src & 0x0000fc);
|
||||
}
|
||||
src += 4;
|
||||
break;
|
||||
case 3: /* 24 bpp plus transparency */
|
||||
alpha = *(uint32_t *) src & (1 << 24);
|
||||
if (s->control[0] & LCCR0_CMS)
|
||||
|
@@ -69,7 +69,7 @@ static bool smbios_legacy_mode;
|
||||
static bool gigabyte_align = true;
|
||||
|
||||
/* PC hardware initialisation */
|
||||
static void pc_init1(QEMUMachineInitArgs *args,
|
||||
static void pc_init1(MachineState *machine,
|
||||
int pci_enabled,
|
||||
int kvmclock_enabled)
|
||||
{
|
||||
@@ -106,7 +106,7 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
object_property_add_child(qdev_get_machine(), "icc-bridge",
|
||||
OBJECT(icc_bridge), NULL);
|
||||
|
||||
pc_cpus_init(args->cpu_model, icc_bridge);
|
||||
pc_cpus_init(machine->cpu_model, icc_bridge);
|
||||
|
||||
if (kvm_enabled() && kvmclock_enabled) {
|
||||
kvmclock_create();
|
||||
@@ -119,13 +119,13 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
* For old machine types, use whatever split we used historically to avoid
|
||||
* breaking migration.
|
||||
*/
|
||||
if (args->ram_size >= 0xe0000000) {
|
||||
if (machine->ram_size >= 0xe0000000) {
|
||||
ram_addr_t lowmem = gigabyte_align ? 0xc0000000 : 0xe0000000;
|
||||
above_4g_mem_size = args->ram_size - lowmem;
|
||||
above_4g_mem_size = machine->ram_size - lowmem;
|
||||
below_4g_mem_size = lowmem;
|
||||
} else {
|
||||
above_4g_mem_size = 0;
|
||||
below_4g_mem_size = args->ram_size;
|
||||
below_4g_mem_size = machine->ram_size;
|
||||
}
|
||||
|
||||
if (pci_enabled) {
|
||||
@@ -145,16 +145,17 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
guest_info->isapc_ram_fw = !pci_enabled;
|
||||
|
||||
if (smbios_defaults) {
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
|
||||
args->machine->name, smbios_legacy_mode);
|
||||
mc->name, smbios_legacy_mode);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
if (!xen_enabled()) {
|
||||
fw_cfg = pc_memory_init(system_memory,
|
||||
args->kernel_filename, args->kernel_cmdline,
|
||||
args->initrd_filename,
|
||||
machine->kernel_filename, machine->kernel_cmdline,
|
||||
machine->initrd_filename,
|
||||
below_4g_mem_size, above_4g_mem_size,
|
||||
rom_memory, &ram_memory, guest_info);
|
||||
}
|
||||
@@ -170,7 +171,7 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
|
||||
if (pci_enabled) {
|
||||
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
|
||||
system_memory, system_io, args->ram_size,
|
||||
system_memory, system_io, machine->ram_size,
|
||||
below_4g_mem_size,
|
||||
above_4g_mem_size,
|
||||
pci_memory, ram_memory);
|
||||
@@ -235,7 +236,7 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
}
|
||||
}
|
||||
|
||||
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_order,
|
||||
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
|
||||
floppy, idebus[0], idebus[1], rtc_state);
|
||||
|
||||
if (pci_enabled && usb_enabled(false)) {
|
||||
@@ -258,131 +259,131 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
}
|
||||
}
|
||||
|
||||
static void pc_init_pci(QEMUMachineInitArgs *args)
|
||||
static void pc_init_pci(MachineState *machine)
|
||||
{
|
||||
pc_init1(args, 1, 1);
|
||||
pc_init1(machine, 1, 1);
|
||||
}
|
||||
|
||||
static void pc_compat_2_0(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_2_0(MachineState *machine)
|
||||
{
|
||||
smbios_legacy_mode = true;
|
||||
}
|
||||
|
||||
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_7(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_0(args);
|
||||
pc_compat_2_0(machine);
|
||||
smbios_defaults = false;
|
||||
gigabyte_align = false;
|
||||
option_rom_has_mr = true;
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
|
||||
}
|
||||
|
||||
static void pc_compat_1_6(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_6(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
pc_compat_1_7(machine);
|
||||
has_pci_info = false;
|
||||
rom_file_has_mr = false;
|
||||
has_acpi_build = false;
|
||||
}
|
||||
|
||||
static void pc_compat_1_5(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_5(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_6(args);
|
||||
pc_compat_1_6(machine);
|
||||
}
|
||||
|
||||
static void pc_compat_1_4(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_4(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_5(args);
|
||||
pc_compat_1_5(machine);
|
||||
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
|
||||
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
|
||||
}
|
||||
|
||||
static void pc_compat_1_3(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_3(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_4(args);
|
||||
pc_compat_1_4(machine);
|
||||
enable_compat_apic_id_mode();
|
||||
}
|
||||
|
||||
/* PC compat function for pc-0.14 to pc-1.2 */
|
||||
static void pc_compat_1_2(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_2(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_3(args);
|
||||
pc_compat_1_3(machine);
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||
}
|
||||
|
||||
static void pc_init_pci_2_0(QEMUMachineInitArgs *args)
|
||||
static void pc_init_pci_2_0(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_0(args);
|
||||
pc_init_pci(args);
|
||||
pc_compat_2_0(machine);
|
||||
pc_init_pci(machine);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_7(QEMUMachineInitArgs *args)
|
||||
static void pc_init_pci_1_7(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
pc_init_pci(args);
|
||||
pc_compat_1_7(machine);
|
||||
pc_init_pci(machine);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_6(QEMUMachineInitArgs *args)
|
||||
static void pc_init_pci_1_6(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_6(args);
|
||||
pc_init_pci(args);
|
||||
pc_compat_1_6(machine);
|
||||
pc_init_pci(machine);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
|
||||
static void pc_init_pci_1_5(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_5(args);
|
||||
pc_init_pci(args);
|
||||
pc_compat_1_5(machine);
|
||||
pc_init_pci(machine);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
|
||||
static void pc_init_pci_1_4(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_4(args);
|
||||
pc_init_pci(args);
|
||||
pc_compat_1_4(machine);
|
||||
pc_init_pci(machine);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
|
||||
static void pc_init_pci_1_3(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_3(args);
|
||||
pc_init_pci(args);
|
||||
pc_compat_1_3(machine);
|
||||
pc_init_pci(machine);
|
||||
}
|
||||
|
||||
/* PC machine init function for pc-0.14 to pc-1.2 */
|
||||
static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
|
||||
static void pc_init_pci_1_2(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_2(args);
|
||||
pc_init_pci(args);
|
||||
pc_compat_1_2(machine);
|
||||
pc_init_pci(machine);
|
||||
}
|
||||
|
||||
/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
|
||||
static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
|
||||
static void pc_init_pci_no_kvmclock(MachineState *machine)
|
||||
{
|
||||
has_pci_info = false;
|
||||
has_acpi_build = false;
|
||||
smbios_defaults = false;
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||
enable_compat_apic_id_mode();
|
||||
pc_init1(args, 1, 0);
|
||||
pc_init1(machine, 1, 0);
|
||||
}
|
||||
|
||||
static void pc_init_isa(QEMUMachineInitArgs *args)
|
||||
static void pc_init_isa(MachineState *machine)
|
||||
{
|
||||
has_pci_info = false;
|
||||
has_acpi_build = false;
|
||||
smbios_defaults = false;
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "486";
|
||||
if (!machine->cpu_model) {
|
||||
machine->cpu_model = "486";
|
||||
}
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||
enable_compat_apic_id_mode();
|
||||
pc_init1(args, 0, 1);
|
||||
pc_init1(machine, 0, 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
|
||||
static void pc_xen_hvm_init(MachineState *machine)
|
||||
{
|
||||
PCIBus *bus;
|
||||
|
||||
pc_init_pci(args);
|
||||
pc_init_pci(machine);
|
||||
|
||||
bus = pci_find_primary_bus();
|
||||
if (bus != NULL) {
|
||||
|
@@ -59,7 +59,7 @@ static bool smbios_legacy_mode;
|
||||
static bool gigabyte_align = true;
|
||||
|
||||
/* PC hardware initialisation */
|
||||
static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
static void pc_q35_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t below_4g_mem_size, above_4g_mem_size;
|
||||
Q35PCIHost *q35_host;
|
||||
@@ -93,7 +93,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
object_property_add_child(qdev_get_machine(), "icc-bridge",
|
||||
OBJECT(icc_bridge), NULL);
|
||||
|
||||
pc_cpus_init(args->cpu_model, icc_bridge);
|
||||
pc_cpus_init(machine->cpu_model, icc_bridge);
|
||||
pc_acpi_init("q35-acpi-dsdt.aml");
|
||||
|
||||
kvmclock_create();
|
||||
@@ -107,13 +107,13 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
* For old machine types, use whatever split we used historically to avoid
|
||||
* breaking migration.
|
||||
*/
|
||||
if (args->ram_size >= 0xb0000000) {
|
||||
if (machine->ram_size >= 0xb0000000) {
|
||||
ram_addr_t lowmem = gigabyte_align ? 0x80000000 : 0xb0000000;
|
||||
above_4g_mem_size = args->ram_size - lowmem;
|
||||
above_4g_mem_size = machine->ram_size - lowmem;
|
||||
below_4g_mem_size = lowmem;
|
||||
} else {
|
||||
above_4g_mem_size = 0;
|
||||
below_4g_mem_size = args->ram_size;
|
||||
below_4g_mem_size = machine->ram_size;
|
||||
}
|
||||
|
||||
/* pci enabled */
|
||||
@@ -132,16 +132,17 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
guest_info->has_acpi_build = has_acpi_build;
|
||||
|
||||
if (smbios_defaults) {
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
||||
args->machine->name, smbios_legacy_mode);
|
||||
mc->name, smbios_legacy_mode);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
if (!xen_enabled()) {
|
||||
pc_memory_init(get_system_memory(),
|
||||
args->kernel_filename, args->kernel_cmdline,
|
||||
args->initrd_filename,
|
||||
machine->kernel_filename, machine->kernel_cmdline,
|
||||
machine->initrd_filename,
|
||||
below_4g_mem_size, above_4g_mem_size,
|
||||
rom_memory, &ram_memory, guest_info);
|
||||
}
|
||||
@@ -230,7 +231,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
0xb100),
|
||||
8, NULL, 0);
|
||||
|
||||
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_order,
|
||||
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
|
||||
floppy, idebus[0], idebus[1], rtc_state);
|
||||
|
||||
/* the rest devices to which pci devfn is automatically assigned */
|
||||
@@ -241,68 +242,68 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
}
|
||||
}
|
||||
|
||||
static void pc_compat_2_0(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_2_0(MachineState *machine)
|
||||
{
|
||||
smbios_legacy_mode = true;
|
||||
}
|
||||
|
||||
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_7(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_0(args);
|
||||
pc_compat_2_0(machine);
|
||||
smbios_defaults = false;
|
||||
gigabyte_align = false;
|
||||
option_rom_has_mr = true;
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
|
||||
}
|
||||
|
||||
static void pc_compat_1_6(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_6(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
pc_compat_1_7(machine);
|
||||
has_pci_info = false;
|
||||
rom_file_has_mr = false;
|
||||
has_acpi_build = false;
|
||||
}
|
||||
|
||||
static void pc_compat_1_5(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_5(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_6(args);
|
||||
pc_compat_1_6(machine);
|
||||
}
|
||||
|
||||
static void pc_compat_1_4(QEMUMachineInitArgs *args)
|
||||
static void pc_compat_1_4(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_5(args);
|
||||
pc_compat_1_5(machine);
|
||||
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
|
||||
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
|
||||
}
|
||||
|
||||
static void pc_q35_init_2_0(QEMUMachineInitArgs *args)
|
||||
static void pc_q35_init_2_0(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_0(args);
|
||||
pc_q35_init(args);
|
||||
pc_compat_2_0(machine);
|
||||
pc_q35_init(machine);
|
||||
}
|
||||
|
||||
static void pc_q35_init_1_7(QEMUMachineInitArgs *args)
|
||||
static void pc_q35_init_1_7(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
pc_q35_init(args);
|
||||
pc_compat_1_7(machine);
|
||||
pc_q35_init(machine);
|
||||
}
|
||||
|
||||
static void pc_q35_init_1_6(QEMUMachineInitArgs *args)
|
||||
static void pc_q35_init_1_6(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_6(args);
|
||||
pc_q35_init(args);
|
||||
pc_compat_1_6(machine);
|
||||
pc_q35_init(machine);
|
||||
}
|
||||
|
||||
static void pc_q35_init_1_5(QEMUMachineInitArgs *args)
|
||||
static void pc_q35_init_1_5(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_5(args);
|
||||
pc_q35_init(args);
|
||||
pc_compat_1_5(machine);
|
||||
pc_q35_init(machine);
|
||||
}
|
||||
|
||||
static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
|
||||
static void pc_q35_init_1_4(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_4(args);
|
||||
pc_q35_init(args);
|
||||
pc_compat_1_4(machine);
|
||||
pc_q35_init(machine);
|
||||
}
|
||||
|
||||
#define PC_Q35_MACHINE_OPTIONS \
|
||||
|
222
hw/input/hid.c
222
hw/input/hid.c
@@ -105,70 +105,135 @@ void hid_set_next_idle(HIDState *hs)
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
|
||||
static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
|
||||
InputEvent *evt)
|
||||
{
|
||||
e->xdx = e->ydy = e->dz = 0;
|
||||
e->buttons_state = buttons;
|
||||
static const int bmap[INPUT_BUTTON_MAX] = {
|
||||
[INPUT_BUTTON_LEFT] = 0x01,
|
||||
[INPUT_BUTTON_RIGHT] = 0x02,
|
||||
[INPUT_BUTTON_MIDDLE] = 0x04,
|
||||
};
|
||||
HIDState *hs = (HIDState *)dev;
|
||||
HIDPointerEvent *e;
|
||||
|
||||
assert(hs->n < QUEUE_LENGTH);
|
||||
e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
|
||||
|
||||
switch (evt->kind) {
|
||||
case INPUT_EVENT_KIND_REL:
|
||||
if (evt->rel->axis == INPUT_AXIS_X) {
|
||||
e->xdx += evt->rel->value;
|
||||
} else if (evt->rel->axis == INPUT_AXIS_Y) {
|
||||
e->ydy -= evt->rel->value;
|
||||
}
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_ABS:
|
||||
if (evt->rel->axis == INPUT_AXIS_X) {
|
||||
e->xdx = evt->rel->value;
|
||||
} else if (evt->rel->axis == INPUT_AXIS_Y) {
|
||||
e->ydy = evt->rel->value;
|
||||
}
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_BTN:
|
||||
if (evt->btn->down) {
|
||||
e->buttons_state |= bmap[evt->btn->button];
|
||||
if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
|
||||
e->dz--;
|
||||
} else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
|
||||
e->dz++;
|
||||
}
|
||||
} else {
|
||||
e->buttons_state &= ~bmap[evt->btn->button];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* keep gcc happy */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
|
||||
int x1, int y1, int z1) {
|
||||
if (xyrel) {
|
||||
e->xdx += x1;
|
||||
e->ydy += y1;
|
||||
} else {
|
||||
e->xdx = x1;
|
||||
e->ydy = y1;
|
||||
/* Windows drivers do not like the 0/0 position and ignore such
|
||||
* events. */
|
||||
if (!(x1 | y1)) {
|
||||
e->xdx = 1;
|
||||
static void hid_pointer_sync(DeviceState *dev)
|
||||
{
|
||||
HIDState *hs = (HIDState *)dev;
|
||||
HIDPointerEvent *prev, *curr, *next;
|
||||
bool event_compression = false;
|
||||
|
||||
if (hs->n == QUEUE_LENGTH-1) {
|
||||
/*
|
||||
* Queue full. We are loosing information, but we at least
|
||||
* keep track of most recent button state.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
|
||||
curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
|
||||
next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
|
||||
|
||||
if (hs->n > 0) {
|
||||
/*
|
||||
* No button state change between previous and current event
|
||||
* (and previous wasn't seen by the guest yet), so there is
|
||||
* motion information only and we can combine the two event
|
||||
* into one.
|
||||
*/
|
||||
if (curr->buttons_state == prev->buttons_state) {
|
||||
event_compression = true;
|
||||
}
|
||||
}
|
||||
e->dz += z1;
|
||||
}
|
||||
|
||||
static void hid_pointer_event(void *opaque,
|
||||
int x1, int y1, int z1, int buttons_state)
|
||||
{
|
||||
HIDState *hs = opaque;
|
||||
unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
|
||||
unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
|
||||
|
||||
/* We combine events where feasible to keep the queue small. We shouldn't
|
||||
* combine anything with the first event of a particular button state, as
|
||||
* that would change the location of the button state change. When the
|
||||
* queue is empty, a second event is needed because we don't know if
|
||||
* the first event changed the button state. */
|
||||
if (hs->n == QUEUE_LENGTH) {
|
||||
/* Queue full. Discard old button state, combine motion normally. */
|
||||
hs->ptr.queue[use_slot].buttons_state = buttons_state;
|
||||
} else if (hs->n < 2 ||
|
||||
hs->ptr.queue[use_slot].buttons_state != buttons_state ||
|
||||
hs->ptr.queue[previous_slot].buttons_state !=
|
||||
hs->ptr.queue[use_slot].buttons_state) {
|
||||
/* Cannot or should not combine, so add an empty item to the queue. */
|
||||
QUEUE_INCR(use_slot);
|
||||
if (event_compression) {
|
||||
/* add current motion to previous, clear current */
|
||||
if (hs->kind == HID_MOUSE) {
|
||||
prev->xdx += curr->xdx;
|
||||
curr->xdx = 0;
|
||||
prev->ydy -= curr->ydy;
|
||||
curr->ydy = 0;
|
||||
} else {
|
||||
prev->xdx = curr->xdx;
|
||||
prev->ydy = curr->ydy;
|
||||
}
|
||||
prev->dz += curr->dz;
|
||||
curr->dz = 0;
|
||||
} else {
|
||||
/* prepate next (clear rel, copy abs + btns) */
|
||||
if (hs->kind == HID_MOUSE) {
|
||||
next->xdx = 0;
|
||||
next->ydy = 0;
|
||||
} else {
|
||||
next->xdx = curr->xdx;
|
||||
next->ydy = curr->ydy;
|
||||
}
|
||||
next->dz = 0;
|
||||
next->buttons_state = curr->buttons_state;
|
||||
/* make current guest visible, notify guest */
|
||||
hs->n++;
|
||||
hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
|
||||
hs->event(hs);
|
||||
}
|
||||
hid_pointer_event_combine(&hs->ptr.queue[use_slot],
|
||||
hs->kind == HID_MOUSE,
|
||||
x1, y1, z1);
|
||||
hs->event(hs);
|
||||
}
|
||||
|
||||
static void hid_keyboard_event(void *opaque, int keycode)
|
||||
static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
|
||||
InputEvent *evt)
|
||||
{
|
||||
HIDState *hs = opaque;
|
||||
HIDState *hs = (HIDState *)dev;
|
||||
int scancodes[3], i, count;
|
||||
int slot;
|
||||
|
||||
if (hs->n == QUEUE_LENGTH) {
|
||||
count = qemu_input_key_value_to_scancode(evt->key->key,
|
||||
evt->key->down,
|
||||
scancodes);
|
||||
if (hs->n + count > QUEUE_LENGTH) {
|
||||
fprintf(stderr, "usb-kbd: warning: key event queue full\n");
|
||||
return;
|
||||
}
|
||||
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
|
||||
hs->kbd.keycodes[slot] = keycode;
|
||||
for (i = 0; i < count; i++) {
|
||||
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
|
||||
hs->kbd.keycodes[slot] = scancodes[i];
|
||||
}
|
||||
hs->event(hs);
|
||||
}
|
||||
|
||||
@@ -247,14 +312,14 @@ static inline int int_clamp(int val, int vmin, int vmax)
|
||||
void hid_pointer_activate(HIDState *hs)
|
||||
{
|
||||
if (!hs->ptr.mouse_grabbed) {
|
||||
qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
|
||||
qemu_input_handler_activate(hs->s);
|
||||
hs->ptr.mouse_grabbed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
||||
{
|
||||
int dx, dy, dz, b, l;
|
||||
int dx, dy, dz, l;
|
||||
int index;
|
||||
HIDPointerEvent *e;
|
||||
|
||||
@@ -279,17 +344,6 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
||||
dz = int_clamp(e->dz, -127, 127);
|
||||
e->dz -= dz;
|
||||
|
||||
b = 0;
|
||||
if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
|
||||
b |= 0x01;
|
||||
}
|
||||
if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
|
||||
b |= 0x02;
|
||||
}
|
||||
if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
|
||||
b |= 0x04;
|
||||
}
|
||||
|
||||
if (hs->n &&
|
||||
!e->dz &&
|
||||
(hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
|
||||
@@ -304,7 +358,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
||||
switch (hs->kind) {
|
||||
case HID_MOUSE:
|
||||
if (len > l) {
|
||||
buf[l++] = b;
|
||||
buf[l++] = e->buttons_state;
|
||||
}
|
||||
if (len > l) {
|
||||
buf[l++] = dx;
|
||||
@@ -319,7 +373,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
||||
|
||||
case HID_TABLET:
|
||||
if (len > l) {
|
||||
buf[l++] = b;
|
||||
buf[l++] = e->buttons_state;
|
||||
}
|
||||
if (len > l) {
|
||||
buf[l++] = dx & 0xff;
|
||||
@@ -413,31 +467,45 @@ void hid_reset(HIDState *hs)
|
||||
|
||||
void hid_free(HIDState *hs)
|
||||
{
|
||||
switch (hs->kind) {
|
||||
case HID_KEYBOARD:
|
||||
qemu_remove_kbd_event_handler(hs->kbd.eh_entry);
|
||||
break;
|
||||
case HID_MOUSE:
|
||||
case HID_TABLET:
|
||||
qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
|
||||
break;
|
||||
}
|
||||
qemu_input_handler_unregister(hs->s);
|
||||
hid_del_idle_timer(hs);
|
||||
}
|
||||
|
||||
static QemuInputHandler hid_keyboard_handler = {
|
||||
.name = "QEMU HID Keyboard",
|
||||
.mask = INPUT_EVENT_MASK_KEY,
|
||||
.event = hid_keyboard_event,
|
||||
};
|
||||
|
||||
static QemuInputHandler hid_mouse_handler = {
|
||||
.name = "QEMU HID Mouse",
|
||||
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
|
||||
.event = hid_pointer_event,
|
||||
.sync = hid_pointer_sync,
|
||||
};
|
||||
|
||||
static QemuInputHandler hid_tablet_handler = {
|
||||
.name = "QEMU HID Tablet",
|
||||
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
|
||||
.event = hid_pointer_event,
|
||||
.sync = hid_pointer_sync,
|
||||
};
|
||||
|
||||
void hid_init(HIDState *hs, int kind, HIDEventFunc event)
|
||||
{
|
||||
hs->kind = kind;
|
||||
hs->event = event;
|
||||
|
||||
if (hs->kind == HID_KEYBOARD) {
|
||||
hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs);
|
||||
hs->s = qemu_input_handler_register((DeviceState *)hs,
|
||||
&hid_keyboard_handler);
|
||||
qemu_input_handler_activate(hs->s);
|
||||
} else if (hs->kind == HID_MOUSE) {
|
||||
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
|
||||
0, "QEMU HID Mouse");
|
||||
hs->s = qemu_input_handler_register((DeviceState *)hs,
|
||||
&hid_mouse_handler);
|
||||
} else if (hs->kind == HID_TABLET) {
|
||||
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
|
||||
1, "QEMU HID Tablet");
|
||||
hs->s = qemu_input_handler_register((DeviceState *)hs,
|
||||
&hid_tablet_handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,3 +26,4 @@ obj-$(CONFIG_XICS) += xics.o
|
||||
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
||||
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
|
||||
obj-$(CONFIG_S390_FLIC) += s390_flic.o
|
||||
obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
|
||||
|
@@ -1,322 +1,103 @@
|
||||
/*
|
||||
* QEMU S390x KVM floating interrupt controller (flic)
|
||||
* QEMU S390x floating interrupt controller (flic)
|
||||
*
|
||||
* Copyright 2014 IBM Corp.
|
||||
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "migration/qemu-file.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define FLIC_SAVE_INITIAL_SIZE getpagesize()
|
||||
#define FLIC_FAILED (-1UL)
|
||||
#define FLIC_SAVEVM_VERSION 1
|
||||
S390FLICState *s390_get_flic(void)
|
||||
{
|
||||
S390FLICState *fs;
|
||||
|
||||
fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL));
|
||||
if (!fs) {
|
||||
fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC, NULL));
|
||||
}
|
||||
return fs;
|
||||
}
|
||||
|
||||
void s390_flic_init(void)
|
||||
{
|
||||
DeviceState *dev;
|
||||
int r;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
dev = qdev_create(NULL, "s390-flic");
|
||||
object_property_add_child(qdev_get_machine(), "s390-flic",
|
||||
OBJECT(dev), NULL);
|
||||
r = qdev_init(dev);
|
||||
if (r) {
|
||||
error_report("flic: couldn't create qdev");
|
||||
}
|
||||
dev = s390_flic_kvm_create();
|
||||
if (!dev) {
|
||||
dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC);
|
||||
object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC,
|
||||
OBJECT(dev), NULL);
|
||||
}
|
||||
r = qdev_init(dev);
|
||||
if (r) {
|
||||
error_report("flic: couldn't create qdev");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* flic_get_all_irqs - store all pending irqs in buffer
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -ENOMEM if buffer is too small,
|
||||
* -EINVAL if attr.group is invalid,
|
||||
* -EFAULT if copying to userspace failed,
|
||||
* on success return number of stored interrupts
|
||||
*/
|
||||
static int flic_get_all_irqs(KVMS390FLICState *flic,
|
||||
void *buf, int len)
|
||||
static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
|
||||
uint8_t isc, bool swap,
|
||||
bool is_maskable)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_GET_ALL_IRQS,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc == -1 ? -errno : rc;
|
||||
/* nothing to do */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flic_enable_pfault(KVMS390FLICState *flic)
|
||||
static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
|
||||
uint64_t map_addr, bool do_map)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_ENABLE,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't enable pfault\n");
|
||||
}
|
||||
/* nothing to do */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flic_disable_wait_pfault(KVMS390FLICState *flic)
|
||||
static int qemu_s390_add_adapter_routes(S390FLICState *fs,
|
||||
AdapterRoutes *routes)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't disable pfault\n");
|
||||
}
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/** flic_enqueue_irqs - returns 0 on success
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -EINVAL if attr.group is unknown
|
||||
*/
|
||||
static int flic_enqueue_irqs(void *buf, uint64_t len,
|
||||
KVMS390FLICState *flic)
|
||||
static void qemu_s390_release_adapter_routes(S390FLICState *fs,
|
||||
AdapterRoutes *routes)
|
||||
{
|
||||
int rc;
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_ENQUEUE,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc ? -errno : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __get_all_irqs - store all pending irqs in buffer
|
||||
* @flic: pointer to flic device state
|
||||
* @buf: pointer to pointer to a buffer
|
||||
* @len: length of buffer
|
||||
*
|
||||
* Returns: return value of flic_get_all_irqs
|
||||
* Note: Retry and increase buffer size until flic_get_all_irqs
|
||||
* either returns a value >= 0 or a negative error code.
|
||||
* -ENOMEM is an exception, which means the buffer is too small
|
||||
* and we should try again. Other negative error codes can be
|
||||
* -EFAULT and -EINVAL which we ignore at this point
|
||||
*/
|
||||
static int __get_all_irqs(KVMS390FLICState *flic,
|
||||
void **buf, int len)
|
||||
static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
int r;
|
||||
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
|
||||
|
||||
do {
|
||||
/* returns -ENOMEM if buffer is too small and number
|
||||
* of queued interrupts on success */
|
||||
r = flic_get_all_irqs(flic, *buf, len);
|
||||
if (r >= 0) {
|
||||
break;
|
||||
}
|
||||
len *= 2;
|
||||
*buf = g_try_realloc(*buf, len);
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
} while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
|
||||
|
||||
return r;
|
||||
fsc->register_io_adapter = qemu_s390_register_io_adapter;
|
||||
fsc->io_adapter_map = qemu_s390_io_adapter_map;
|
||||
fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
|
||||
fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_save - Save pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
*
|
||||
* Note: Pass buf and len to kernel. Start with one page and
|
||||
* increase until buffer is sufficient or maxium size is
|
||||
* reached
|
||||
*/
|
||||
static void kvm_flic_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
KVMS390FLICState *flic = opaque;
|
||||
int len = FLIC_SAVE_INITIAL_SIZE;
|
||||
void *buf;
|
||||
int count;
|
||||
|
||||
flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
error_report("flic: couldn't allocate memory");
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
count = __get_all_irqs(flic, &buf, len);
|
||||
if (count < 0) {
|
||||
error_report("flic: couldn't retrieve irqs from kernel, rc %d",
|
||||
count);
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
} else {
|
||||
qemu_put_be64(f, count);
|
||||
qemu_put_buffer(f, (uint8_t *) buf,
|
||||
count * sizeof(struct kvm_s390_irq));
|
||||
}
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_load - Load pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
* @version_id: version id for migration
|
||||
*
|
||||
* Returns: value of flic_enqueue_irqs, -EINVAL on error
|
||||
* Note: Do nothing when no interrupts where stored
|
||||
* in QEMUFile
|
||||
*/
|
||||
static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
uint64_t len = 0;
|
||||
uint64_t count = 0;
|
||||
void *buf = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (version_id != FLIC_SAVEVM_VERSION) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
flic_enable_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
count = qemu_get_be64(f);
|
||||
len = count * sizeof(struct kvm_s390_irq);
|
||||
if (count == FLIC_FAILED) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (count == 0) {
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
|
||||
r = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
|
||||
|
||||
out_free:
|
||||
g_free(buf);
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
struct kvm_create_device cd = {0};
|
||||
int ret;
|
||||
|
||||
flic_state->fd = -1;
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
|
||||
trace_flic_no_device_api(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
cd.type = KVM_DEV_TYPE_FLIC;
|
||||
ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
|
||||
if (ret < 0) {
|
||||
trace_flic_create_device(errno);
|
||||
return;
|
||||
}
|
||||
flic_state->fd = cd.fd;
|
||||
|
||||
/* Register savevm handler for floating interrupts */
|
||||
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
|
||||
kvm_flic_load, (void *) flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
|
||||
unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_reset(DeviceState *dev)
|
||||
{
|
||||
KVMS390FLICState *flic = KVM_S390_FLIC(dev);
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_CLEAR_IRQS,
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
if (flic->fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
flic_disable_wait_pfault(flic);
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
if (rc) {
|
||||
trace_flic_reset_failed(errno);
|
||||
}
|
||||
|
||||
flic_enable_pfault(flic);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = kvm_s390_flic_realize;
|
||||
dc->unrealize = kvm_s390_flic_unrealize;
|
||||
dc->reset = kvm_s390_flic_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_s390_flic_info = {
|
||||
.name = TYPE_KVM_S390_FLIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(KVMS390FLICState),
|
||||
.class_init = kvm_s390_flic_class_init,
|
||||
static const TypeInfo qemu_s390_flic_info = {
|
||||
.name = TYPE_QEMU_S390_FLIC,
|
||||
.parent = TYPE_S390_FLIC_COMMON,
|
||||
.instance_size = sizeof(QEMUS390FLICState),
|
||||
.class_init = qemu_s390_flic_class_init,
|
||||
};
|
||||
|
||||
static void kvm_s390_flic_register_types(void)
|
||||
static const TypeInfo s390_flic_common_info = {
|
||||
.name = TYPE_S390_FLIC_COMMON,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(S390FLICState),
|
||||
.class_size = sizeof(S390FLICStateClass),
|
||||
};
|
||||
|
||||
static void qemu_s390_flic_register_types(void)
|
||||
{
|
||||
type_register_static(&kvm_s390_flic_info);
|
||||
type_register_static(&s390_flic_common_info);
|
||||
type_register_static(&qemu_s390_flic_info);
|
||||
}
|
||||
|
||||
type_init(kvm_s390_flic_register_types)
|
||||
type_init(qemu_s390_flic_register_types)
|
||||
|
420
hw/intc/s390_flic_kvm.c
Normal file
420
hw/intc/s390_flic_kvm.c
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* QEMU S390x KVM floating interrupt controller (flic)
|
||||
*
|
||||
* Copyright 2014 IBM Corp.
|
||||
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "migration/qemu-file.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "hw/s390x/adapter.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define FLIC_SAVE_INITIAL_SIZE getpagesize()
|
||||
#define FLIC_FAILED (-1UL)
|
||||
#define FLIC_SAVEVM_VERSION 1
|
||||
|
||||
typedef struct KVMS390FLICState {
|
||||
S390FLICState parent_obj;
|
||||
|
||||
uint32_t fd;
|
||||
} KVMS390FLICState;
|
||||
|
||||
DeviceState *s390_flic_kvm_create(void)
|
||||
{
|
||||
DeviceState *dev = NULL;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
dev = qdev_create(NULL, TYPE_KVM_S390_FLIC);
|
||||
object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC,
|
||||
OBJECT(dev), NULL);
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* flic_get_all_irqs - store all pending irqs in buffer
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -ENOMEM if buffer is too small,
|
||||
* -EINVAL if attr.group is invalid,
|
||||
* -EFAULT if copying to userspace failed,
|
||||
* on success return number of stored interrupts
|
||||
*/
|
||||
static int flic_get_all_irqs(KVMS390FLICState *flic,
|
||||
void *buf, int len)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_GET_ALL_IRQS,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc == -1 ? -errno : rc;
|
||||
}
|
||||
|
||||
static void flic_enable_pfault(KVMS390FLICState *flic)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_ENABLE,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't enable pfault\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void flic_disable_wait_pfault(KVMS390FLICState *flic)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't disable pfault\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** flic_enqueue_irqs - returns 0 on success
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -EINVAL if attr.group is unknown
|
||||
*/
|
||||
static int flic_enqueue_irqs(void *buf, uint64_t len,
|
||||
KVMS390FLICState *flic)
|
||||
{
|
||||
int rc;
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_ENQUEUE,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc ? -errno : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __get_all_irqs - store all pending irqs in buffer
|
||||
* @flic: pointer to flic device state
|
||||
* @buf: pointer to pointer to a buffer
|
||||
* @len: length of buffer
|
||||
*
|
||||
* Returns: return value of flic_get_all_irqs
|
||||
* Note: Retry and increase buffer size until flic_get_all_irqs
|
||||
* either returns a value >= 0 or a negative error code.
|
||||
* -ENOMEM is an exception, which means the buffer is too small
|
||||
* and we should try again. Other negative error codes can be
|
||||
* -EFAULT and -EINVAL which we ignore at this point
|
||||
*/
|
||||
static int __get_all_irqs(KVMS390FLICState *flic,
|
||||
void **buf, int len)
|
||||
{
|
||||
int r;
|
||||
|
||||
do {
|
||||
/* returns -ENOMEM if buffer is too small and number
|
||||
* of queued interrupts on success */
|
||||
r = flic_get_all_irqs(flic, *buf, len);
|
||||
if (r >= 0) {
|
||||
break;
|
||||
}
|
||||
len *= 2;
|
||||
*buf = g_try_realloc(*buf, len);
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
} while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
|
||||
uint8_t isc, bool swap,
|
||||
bool is_maskable)
|
||||
{
|
||||
struct kvm_s390_io_adapter adapter = {
|
||||
.id = id,
|
||||
.isc = isc,
|
||||
.maskable = is_maskable,
|
||||
.swap = swap,
|
||||
};
|
||||
KVMS390FLICState *flic = KVM_S390_FLIC(fs);
|
||||
int r, ret;
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_ADAPTER_REGISTER,
|
||||
.addr = (uint64_t)&adapter,
|
||||
};
|
||||
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
ret = r ? -errno : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
|
||||
uint64_t map_addr, bool do_map)
|
||||
{
|
||||
struct kvm_s390_io_adapter_req req = {
|
||||
.id = id,
|
||||
.type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
|
||||
.addr = map_addr,
|
||||
};
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_ADAPTER_MODIFY,
|
||||
.addr = (uint64_t)&req,
|
||||
};
|
||||
KVMS390FLICState *flic = KVM_S390_FLIC(fs);
|
||||
int r;
|
||||
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
return r ? -errno : 0;
|
||||
}
|
||||
|
||||
static int kvm_s390_add_adapter_routes(S390FLICState *fs,
|
||||
AdapterRoutes *routes)
|
||||
{
|
||||
int ret, i;
|
||||
uint64_t ind_offset = routes->adapter.ind_offset;
|
||||
|
||||
for (i = 0; i < routes->num_routes; i++) {
|
||||
ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
|
||||
if (ret < 0) {
|
||||
goto out_undo;
|
||||
}
|
||||
routes->gsi[i] = ret;
|
||||
routes->adapter.ind_offset++;
|
||||
}
|
||||
/* Restore passed-in structure to original state. */
|
||||
routes->adapter.ind_offset = ind_offset;
|
||||
return 0;
|
||||
out_undo:
|
||||
while (--i >= 0) {
|
||||
kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
|
||||
routes->gsi[i] = -1;
|
||||
}
|
||||
routes->adapter.ind_offset = ind_offset;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kvm_s390_release_adapter_routes(S390FLICState *fs,
|
||||
AdapterRoutes *routes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < routes->num_routes; i++) {
|
||||
if (routes->gsi[i] >= 0) {
|
||||
kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
|
||||
routes->gsi[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_save - Save pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
*
|
||||
* Note: Pass buf and len to kernel. Start with one page and
|
||||
* increase until buffer is sufficient or maxium size is
|
||||
* reached
|
||||
*/
|
||||
static void kvm_flic_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
KVMS390FLICState *flic = opaque;
|
||||
int len = FLIC_SAVE_INITIAL_SIZE;
|
||||
void *buf;
|
||||
int count;
|
||||
|
||||
flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
error_report("flic: couldn't allocate memory");
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
count = __get_all_irqs(flic, &buf, len);
|
||||
if (count < 0) {
|
||||
error_report("flic: couldn't retrieve irqs from kernel, rc %d",
|
||||
count);
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
} else {
|
||||
qemu_put_be64(f, count);
|
||||
qemu_put_buffer(f, (uint8_t *) buf,
|
||||
count * sizeof(struct kvm_s390_irq));
|
||||
}
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_load - Load pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
* @version_id: version id for migration
|
||||
*
|
||||
* Returns: value of flic_enqueue_irqs, -EINVAL on error
|
||||
* Note: Do nothing when no interrupts where stored
|
||||
* in QEMUFile
|
||||
*/
|
||||
static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
uint64_t len = 0;
|
||||
uint64_t count = 0;
|
||||
void *buf = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (version_id != FLIC_SAVEVM_VERSION) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
flic_enable_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
count = qemu_get_be64(f);
|
||||
len = count * sizeof(struct kvm_s390_irq);
|
||||
if (count == FLIC_FAILED) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (count == 0) {
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
|
||||
r = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
|
||||
|
||||
out_free:
|
||||
g_free(buf);
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
struct kvm_create_device cd = {0};
|
||||
int ret;
|
||||
|
||||
flic_state->fd = -1;
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
|
||||
trace_flic_no_device_api(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
cd.type = KVM_DEV_TYPE_FLIC;
|
||||
ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
|
||||
if (ret < 0) {
|
||||
trace_flic_create_device(errno);
|
||||
return;
|
||||
}
|
||||
flic_state->fd = cd.fd;
|
||||
|
||||
/* Register savevm handler for floating interrupts */
|
||||
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
|
||||
kvm_flic_load, (void *) flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
|
||||
unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_reset(DeviceState *dev)
|
||||
{
|
||||
KVMS390FLICState *flic = KVM_S390_FLIC(dev);
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_CLEAR_IRQS,
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
if (flic->fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
flic_disable_wait_pfault(flic);
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
if (rc) {
|
||||
trace_flic_reset_failed(errno);
|
||||
}
|
||||
|
||||
flic_enable_pfault(flic);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
|
||||
|
||||
dc->realize = kvm_s390_flic_realize;
|
||||
dc->unrealize = kvm_s390_flic_unrealize;
|
||||
dc->reset = kvm_s390_flic_reset;
|
||||
fsc->register_io_adapter = kvm_s390_register_io_adapter;
|
||||
fsc->io_adapter_map = kvm_s390_io_adapter_map;
|
||||
fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
|
||||
fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_s390_flic_info = {
|
||||
.name = TYPE_KVM_S390_FLIC,
|
||||
.parent = TYPE_S390_FLIC_COMMON,
|
||||
.instance_size = sizeof(KVMS390FLICState),
|
||||
.class_init = kvm_s390_flic_class_init,
|
||||
};
|
||||
|
||||
static void kvm_s390_flic_register_types(void)
|
||||
{
|
||||
type_register_static(&kvm_s390_flic_info);
|
||||
}
|
||||
|
||||
type_init(kvm_s390_flic_register_types)
|
@@ -69,10 +69,10 @@ static void main_cpu_reset(void *opaque)
|
||||
env->deba = reset_info->flash_base;
|
||||
}
|
||||
|
||||
static void lm32_evr_init(QEMUMachineInitArgs *args)
|
||||
static void lm32_evr_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
LM32CPU *cpu;
|
||||
CPULM32State *env;
|
||||
DriveInfo *dinfo;
|
||||
@@ -162,12 +162,12 @@ static void lm32_evr_init(QEMUMachineInitArgs *args)
|
||||
qemu_register_reset(main_cpu_reset, reset_info);
|
||||
}
|
||||
|
||||
static void lm32_uclinux_init(QEMUMachineInitArgs *args)
|
||||
static void lm32_uclinux_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
LM32CPU *cpu;
|
||||
CPULM32State *env;
|
||||
DriveInfo *dinfo;
|
||||
|
@@ -74,12 +74,12 @@ static void main_cpu_reset(void *opaque)
|
||||
}
|
||||
|
||||
static void
|
||||
milkymist_init(QEMUMachineInitArgs *args)
|
||||
milkymist_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
LM32CPU *cpu;
|
||||
CPULM32State *env;
|
||||
int kernel_size;
|
||||
|
@@ -20,11 +20,11 @@
|
||||
|
||||
/* Board init. */
|
||||
|
||||
static void an5206_init(QEMUMachineInitArgs *args)
|
||||
static void an5206_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
M68kCPU *cpu;
|
||||
CPUM68KState *env;
|
||||
int kernel_size;
|
||||
|
@@ -16,11 +16,11 @@
|
||||
|
||||
/* Board init. */
|
||||
|
||||
static void dummy_m68k_init(QEMUMachineInitArgs *args)
|
||||
static void dummy_m68k_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
CPUM68KState *env;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
|
@@ -188,11 +188,11 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
|
||||
}
|
||||
}
|
||||
|
||||
static void mcf5208evb_init(QEMUMachineInitArgs *args)
|
||||
static void mcf5208evb_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
M68kCPU *cpu;
|
||||
CPUM68KState *env;
|
||||
int kernel_size;
|
||||
|
@@ -79,9 +79,9 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu)
|
||||
}
|
||||
|
||||
static void
|
||||
petalogix_ml605_init(QEMUMachineInitArgs *args)
|
||||
petalogix_ml605_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
DeviceState *dev, *dma, *eth0;
|
||||
Object *ds, *cs;
|
||||
@@ -196,13 +196,13 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)
|
||||
qemu_irq cs_line;
|
||||
|
||||
dev = ssi_create_slave(spi, "n25q128");
|
||||
cs_line = qdev_get_gpio_in(dev, 0);
|
||||
cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(busdev, i+1, cs_line);
|
||||
}
|
||||
}
|
||||
|
||||
microblaze_load_kernel(cpu, ddr_base, ram_size,
|
||||
args->initrd_filename,
|
||||
machine->initrd_filename,
|
||||
BINARY_DEVICE_TREE_FILE,
|
||||
machine_cpu_reset);
|
||||
|
||||
|
@@ -59,10 +59,10 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu)
|
||||
}
|
||||
|
||||
static void
|
||||
petalogix_s3adsp1800_init(QEMUMachineInitArgs *args)
|
||||
petalogix_s3adsp1800_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
DeviceState *dev;
|
||||
MicroBlazeCPU *cpu;
|
||||
DriveInfo *dinfo;
|
||||
@@ -128,7 +128,7 @@ petalogix_s3adsp1800_init(QEMUMachineInitArgs *args)
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]);
|
||||
|
||||
microblaze_load_kernel(cpu, ddr_base, ram_size,
|
||||
args->initrd_filename,
|
||||
machine->initrd_filename,
|
||||
BINARY_DEVICE_TREE_FILE,
|
||||
machine_cpu_reset);
|
||||
}
|
||||
|
@@ -259,13 +259,13 @@ static void cpu_request_exit(void *opaque, int irq, int level)
|
||||
}
|
||||
}
|
||||
|
||||
static void mips_fulong2e_init(QEMUMachineInitArgs *args)
|
||||
static void mips_fulong2e_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
char *filename;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
|
@@ -329,19 +329,19 @@ static void mips_jazz_init(MemoryRegion *address_space,
|
||||
}
|
||||
|
||||
static
|
||||
void mips_magnum_init(QEMUMachineInitArgs *args)
|
||||
void mips_magnum_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
mips_jazz_init(get_system_memory(), get_system_io(),
|
||||
ram_size, cpu_model, JAZZ_MAGNUM);
|
||||
}
|
||||
|
||||
static
|
||||
void mips_pica61_init(QEMUMachineInitArgs *args)
|
||||
void mips_pica61_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
mips_jazz_init(get_system_memory(), get_system_io(),
|
||||
ram_size, cpu_model, JAZZ_PICA61);
|
||||
}
|
||||
|
@@ -875,13 +875,13 @@ static void cpu_request_exit(void *opaque, int irq, int level)
|
||||
}
|
||||
|
||||
static
|
||||
void mips_malta_init(QEMUMachineInitArgs *args)
|
||||
void mips_malta_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
char *filename;
|
||||
pflash_t *fl;
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
|
@@ -133,13 +133,13 @@ static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
|
||||
}
|
||||
|
||||
static void
|
||||
mips_mipssim_init(QEMUMachineInitArgs *args)
|
||||
mips_mipssim_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
char *filename;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *isa = g_new(MemoryRegion, 1);
|
||||
|
@@ -153,13 +153,13 @@ static void main_cpu_reset(void *opaque)
|
||||
|
||||
static const int sector_len = 32 * 1024;
|
||||
static
|
||||
void mips_r4k_init(QEMUMachineInitArgs *args)
|
||||
void mips_r4k_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
char *filename;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
|
@@ -29,7 +29,6 @@ obj-$(CONFIG_NSERIES) += cbus.o
|
||||
obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
|
||||
obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
|
||||
obj-$(CONFIG_IMX) += imx_ccm.o
|
||||
obj-$(CONFIG_LM32) += lm32_sys.o
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
|
||||
obj-$(CONFIG_MAINSTONE) += mst_fpga.o
|
||||
|
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* QEMU model of the LatticeMico32 system control block.
|
||||
*
|
||||
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This model is mainly intended for testing purposes and doesn't fit to any
|
||||
* real hardware. On the one hand it provides a control register (R_CTRL) on
|
||||
* the other hand it supports the lm32 tests.
|
||||
*
|
||||
* A write to the control register causes a system shutdown.
|
||||
* Tests first write the pointer to a test name to the test name register
|
||||
* (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if
|
||||
* the test is passed or any non-zero value to it if the test is failed.
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
enum {
|
||||
R_CTRL = 0,
|
||||
R_PASSFAIL,
|
||||
R_TESTNAME,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
#define MAX_TESTNAME_LEN 32
|
||||
|
||||
#define TYPE_LM32_SYS "lm32-sys"
|
||||
#define LM32_SYS(obj) OBJECT_CHECK(LM32SysState, (obj), TYPE_LM32_SYS)
|
||||
|
||||
struct LM32SysState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
uint32_t base;
|
||||
uint32_t regs[R_MAX];
|
||||
uint8_t testname[MAX_TESTNAME_LEN];
|
||||
};
|
||||
typedef struct LM32SysState LM32SysState;
|
||||
|
||||
static void copy_testname(LM32SysState *s)
|
||||
{
|
||||
cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname,
|
||||
MAX_TESTNAME_LEN);
|
||||
s->testname[MAX_TESTNAME_LEN - 1] = '\0';
|
||||
}
|
||||
|
||||
static void sys_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
LM32SysState *s = opaque;
|
||||
char *testname;
|
||||
|
||||
trace_lm32_sys_memory_write(addr, value);
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_CTRL:
|
||||
qemu_system_shutdown_request();
|
||||
break;
|
||||
case R_PASSFAIL:
|
||||
s->regs[addr] = value;
|
||||
testname = (char *)s->testname;
|
||||
fprintf(stderr, "TC %-*s %s\n", MAX_TESTNAME_LEN,
|
||||
testname, (value) ? "FAILED" : "OK");
|
||||
if (value) {
|
||||
cpu_dump_state(qemu_get_cpu(0), stderr, fprintf, 0);
|
||||
}
|
||||
break;
|
||||
case R_TESTNAME:
|
||||
s->regs[addr] = value;
|
||||
copy_testname(s);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("lm32_sys: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool sys_ops_accepts(void *opaque, hwaddr addr,
|
||||
unsigned size, bool is_write)
|
||||
{
|
||||
return is_write && size == 4;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sys_ops = {
|
||||
.write = sys_write,
|
||||
.valid.accepts = sys_ops_accepts,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void sys_reset(DeviceState *d)
|
||||
{
|
||||
LM32SysState *s = LM32_SYS(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
memset(s->testname, 0, MAX_TESTNAME_LEN);
|
||||
}
|
||||
|
||||
static int lm32_sys_init(SysBusDevice *dev)
|
||||
{
|
||||
LM32SysState *s = LM32_SYS(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev), &sys_ops , s,
|
||||
"sys", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
/* Note: This device is not created in the board initialization,
|
||||
* instead it has to be added with the -device parameter. Therefore,
|
||||
* the device maps itself. */
|
||||
sysbus_mmio_map(dev, 0, s->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_lm32_sys = {
|
||||
.name = "lm32-sys",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX),
|
||||
VMSTATE_BUFFER(testname, LM32SysState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property lm32_sys_properties[] = {
|
||||
DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void lm32_sys_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = lm32_sys_init;
|
||||
dc->reset = sys_reset;
|
||||
dc->vmsd = &vmstate_lm32_sys;
|
||||
dc->props = lm32_sys_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_sys_info = {
|
||||
.name = TYPE_LM32_SYS,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LM32SysState),
|
||||
.class_init = lm32_sys_class_init,
|
||||
};
|
||||
|
||||
static void lm32_sys_register_types(void)
|
||||
{
|
||||
type_register_static(&lm32_sys_info);
|
||||
}
|
||||
|
||||
type_init(lm32_sys_register_types)
|
@@ -107,14 +107,14 @@ moxie_intc_create(hwaddr base, qemu_irq irq, int kind_of_intr)
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void moxiesim_init(QEMUMachineInitArgs *args)
|
||||
static void moxiesim_init(MachineState *machine)
|
||||
{
|
||||
MoxieCPU *cpu = NULL;
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
CPUMoxieState *env;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* QEMU Xilinx GEM emulation
|
||||
* QEMU Cadence GEM emulation
|
||||
*
|
||||
* Copyright (c) 2011 Xilinx, Inc.
|
||||
*
|
||||
|
@@ -90,11 +90,11 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size,
|
||||
}
|
||||
}
|
||||
|
||||
static void openrisc_sim_init(QEMUMachineInitArgs *args)
|
||||
static void openrisc_sim_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
OpenRISCCPU *cpu = NULL;
|
||||
MemoryRegion *ram;
|
||||
int n;
|
||||
|
@@ -605,13 +605,13 @@ PCIBus *pci_get_bus_devfn(int *devfnp, PCIBus *root, const char *devaddr)
|
||||
int dom, bus;
|
||||
unsigned slot;
|
||||
|
||||
assert(!root->parent_dev);
|
||||
|
||||
if (!root) {
|
||||
fprintf(stderr, "No primary PCI bus\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(!root->parent_dev);
|
||||
|
||||
if (!devaddr) {
|
||||
*devfnp = -1;
|
||||
return pci_find_bus_nr(root, 0);
|
||||
|
@@ -123,7 +123,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
|
||||
}
|
||||
}
|
||||
|
||||
static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
|
||||
static int ppce500_load_device_tree(MachineState *machine,
|
||||
PPCE500Params *params,
|
||||
hwaddr addr,
|
||||
hwaddr initrd_base,
|
||||
@@ -132,7 +132,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
|
||||
{
|
||||
CPUPPCState *env = first_cpu->env_ptr;
|
||||
int ret = -1;
|
||||
uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) };
|
||||
uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
|
||||
int fdt_size;
|
||||
void *fdt;
|
||||
uint8_t hypercall[16];
|
||||
@@ -207,7 +207,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
|
||||
}
|
||||
|
||||
ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
|
||||
args->kernel_cmdline);
|
||||
machine->kernel_cmdline);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "couldn't set /chosen/bootargs\n");
|
||||
|
||||
@@ -387,7 +387,7 @@ out:
|
||||
}
|
||||
|
||||
typedef struct DeviceTreeParams {
|
||||
QEMUMachineInitArgs args;
|
||||
MachineState *machine;
|
||||
PPCE500Params params;
|
||||
hwaddr addr;
|
||||
hwaddr initrd_base;
|
||||
@@ -397,18 +397,18 @@ typedef struct DeviceTreeParams {
|
||||
static void ppce500_reset_device_tree(void *opaque)
|
||||
{
|
||||
DeviceTreeParams *p = opaque;
|
||||
ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base,
|
||||
ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
|
||||
p->initrd_size, false);
|
||||
}
|
||||
|
||||
static int ppce500_prep_device_tree(QEMUMachineInitArgs *args,
|
||||
static int ppce500_prep_device_tree(MachineState *machine,
|
||||
PPCE500Params *params,
|
||||
hwaddr addr,
|
||||
hwaddr initrd_base,
|
||||
hwaddr initrd_size)
|
||||
{
|
||||
DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
|
||||
p->args = *args;
|
||||
p->machine = machine;
|
||||
p->params = *params;
|
||||
p->addr = addr;
|
||||
p->initrd_base = initrd_base;
|
||||
@@ -417,7 +417,7 @@ static int ppce500_prep_device_tree(QEMUMachineInitArgs *args,
|
||||
qemu_register_reset(ppce500_reset_device_tree, p);
|
||||
|
||||
/* Issue the device tree loader once, so that we get the size of the blob */
|
||||
return ppce500_load_device_tree(args, params, addr, initrd_base,
|
||||
return ppce500_load_device_tree(machine, params, addr, initrd_base,
|
||||
initrd_size, true);
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
|
||||
return mpic;
|
||||
}
|
||||
|
||||
void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||
{
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
@@ -622,8 +622,8 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
PPCE500CCSRState *ccsr;
|
||||
|
||||
/* Setup CPUs */
|
||||
if (args->cpu_model == NULL) {
|
||||
args->cpu_model = "e500v2_v30";
|
||||
if (machine->cpu_model == NULL) {
|
||||
machine->cpu_model = "e500v2_v30";
|
||||
}
|
||||
|
||||
irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
|
||||
@@ -633,7 +633,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
CPUState *cs;
|
||||
qemu_irq *input;
|
||||
|
||||
cpu = cpu_ppc_init(args->cpu_model);
|
||||
cpu = cpu_ppc_init(machine->cpu_model);
|
||||
if (cpu == NULL) {
|
||||
fprintf(stderr, "Unable to initialize CPU!\n");
|
||||
exit(1);
|
||||
@@ -672,7 +672,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
|
||||
/* Fixup Memory size on a alignment boundary */
|
||||
ram_size &= ~(RAM_SIZES_ALIGN - 1);
|
||||
args->ram_size = ram_size;
|
||||
machine->ram_size = ram_size;
|
||||
|
||||
/* Register Memory */
|
||||
memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size);
|
||||
@@ -739,11 +739,11 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
|
||||
|
||||
/* Load kernel. */
|
||||
if (args->kernel_filename) {
|
||||
kernel_size = load_uimage(args->kernel_filename, &entry,
|
||||
if (machine->kernel_filename) {
|
||||
kernel_size = load_uimage(machine->kernel_filename, &entry,
|
||||
&loadaddr, NULL);
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_elf(args->kernel_filename, NULL, NULL,
|
||||
kernel_size = load_elf(machine->kernel_filename, NULL, NULL,
|
||||
&elf_entry, &elf_lowaddr, NULL, 1,
|
||||
ELF_MACHINE, 0);
|
||||
entry = elf_entry;
|
||||
@@ -752,7 +752,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
/* XXX try again as binary */
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
args->kernel_filename);
|
||||
machine->kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -764,14 +764,14 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
}
|
||||
|
||||
/* Load initrd. */
|
||||
if (args->initrd_filename) {
|
||||
if (machine->initrd_filename) {
|
||||
initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
|
||||
initrd_size = load_image_targphys(args->initrd_filename, initrd_base,
|
||||
initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
|
||||
ram_size - initrd_base);
|
||||
|
||||
if (initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
args->initrd_filename);
|
||||
machine->initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -779,11 +779,11 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
}
|
||||
|
||||
/* If we're loading a kernel directly, we must load the device tree too. */
|
||||
if (args->kernel_filename) {
|
||||
if (machine->kernel_filename) {
|
||||
struct boot_info *boot_info;
|
||||
int dt_size;
|
||||
|
||||
dt_size = ppce500_prep_device_tree(args, params, dt_base,
|
||||
dt_size = ppce500_prep_device_tree(machine, params, dt_base,
|
||||
initrd_base, initrd_size);
|
||||
if (dt_size < 0) {
|
||||
fprintf(stderr, "couldn't load device tree\n");
|
||||
|
@@ -13,6 +13,6 @@ typedef struct PPCE500Params {
|
||||
int mpic_version;
|
||||
} PPCE500Params;
|
||||
|
||||
void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params);
|
||||
void ppce500_init(MachineState *machine, PPCE500Params *params);
|
||||
|
||||
#endif
|
||||
|
@@ -28,7 +28,7 @@ static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
|
||||
sizeof(compatible));
|
||||
}
|
||||
|
||||
static void e500plat_init(QEMUMachineInitArgs *args)
|
||||
static void e500plat_init(MachineState *machine)
|
||||
{
|
||||
PPCE500Params params = {
|
||||
.pci_first_slot = 0x1,
|
||||
@@ -43,7 +43,7 @@ static void e500plat_init(QEMUMachineInitArgs *args)
|
||||
params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20;
|
||||
}
|
||||
|
||||
ppce500_init(args, ¶ms);
|
||||
ppce500_init(machine, ¶ms);
|
||||
}
|
||||
|
||||
static QEMUMachine e500plat_machine = {
|
||||
|
@@ -140,14 +140,14 @@ static void ppc_core99_reset(void *opaque)
|
||||
}
|
||||
|
||||
/* PowerPC Mac99 hardware initialisation */
|
||||
static void ppc_core99_init(QEMUMachineInitArgs *args)
|
||||
static void ppc_core99_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_order;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
const char *boot_device = machine->boot_order;
|
||||
PowerPCCPU *cpu = NULL;
|
||||
CPUPPCState *env = NULL;
|
||||
char *filename;
|
||||
|
@@ -71,14 +71,14 @@ static void ppc_heathrow_reset(void *opaque)
|
||||
cpu_reset(CPU(cpu));
|
||||
}
|
||||
|
||||
static void ppc_heathrow_init(QEMUMachineInitArgs *args)
|
||||
static void ppc_heathrow_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_order;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
const char *boot_device = machine->boot_order;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
PowerPCCPU *cpu = NULL;
|
||||
CPUPPCState *env = NULL;
|
||||
|
@@ -26,7 +26,7 @@ static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
|
||||
sizeof(compatible));
|
||||
}
|
||||
|
||||
static void mpc8544ds_init(QEMUMachineInitArgs *args)
|
||||
static void mpc8544ds_init(MachineState *machine)
|
||||
{
|
||||
PPCE500Params params = {
|
||||
.pci_first_slot = 0x11,
|
||||
@@ -35,7 +35,7 @@ static void mpc8544ds_init(QEMUMachineInitArgs *args)
|
||||
.mpic_version = OPENPIC_MODEL_FSL_MPIC_20,
|
||||
};
|
||||
|
||||
ppce500_init(args, ¶ms);
|
||||
ppce500_init(machine, ¶ms);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -172,12 +172,12 @@ static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base)
|
||||
qemu_register_reset(&ref405ep_fpga_reset, fpga);
|
||||
}
|
||||
|
||||
static void ref405ep_init(QEMUMachineInitArgs *args)
|
||||
static void ref405ep_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
char *filename;
|
||||
ppc4xx_bd_info_t bd;
|
||||
CPUPPCState *env;
|
||||
@@ -499,11 +499,11 @@ static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base)
|
||||
qemu_register_reset(&taihu_cpld_reset, cpld);
|
||||
}
|
||||
|
||||
static void taihu_405ep_init(QEMUMachineInitArgs *args)
|
||||
static void taihu_405ep_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
char *filename;
|
||||
qemu_irq *pic;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
|
@@ -156,13 +156,13 @@ static void main_cpu_reset(void *opaque)
|
||||
mmubooke_create_initial_mapping(env, 0, 0);
|
||||
}
|
||||
|
||||
static void bamboo_init(QEMUMachineInitArgs *args)
|
||||
static void bamboo_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *isa = g_new(MemoryRegion, 1);
|
||||
|
@@ -364,14 +364,14 @@ static const MemoryRegionPortio prep_portio_list[] = {
|
||||
static PortioList prep_port_list;
|
||||
|
||||
/* PowerPC PREP hardware initialisation */
|
||||
static void ppc_prep_init(QEMUMachineInitArgs *args)
|
||||
static void ppc_prep_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_order;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
const char *boot_device = machine->boot_order;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
PowerPCCPU *cpu = NULL;
|
||||
CPUPPCState *env = NULL;
|
||||
|
@@ -1140,14 +1140,14 @@ static SaveVMHandlers savevm_htab_handlers = {
|
||||
};
|
||||
|
||||
/* pSeries LPAR / sPAPR hardware init */
|
||||
static void ppc_spapr_init(QEMUMachineInitArgs *args)
|
||||
static void ppc_spapr_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_order;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
const char *boot_device = machine->boot_order;
|
||||
PowerPCCPU *cpu;
|
||||
CPUPPCState *env;
|
||||
PCIHostState *phb;
|
||||
|
@@ -194,12 +194,12 @@ static int xilinx_load_device_tree(hwaddr addr,
|
||||
return fdt_size;
|
||||
}
|
||||
|
||||
static void virtex_init(QEMUMachineInitArgs *args)
|
||||
static void virtex_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
hwaddr initrd_base = 0;
|
||||
int initrd_size = 0;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
@@ -275,14 +275,14 @@ static void virtex_init(QEMUMachineInitArgs *args)
|
||||
boot_info.ima_size = kernel_size;
|
||||
|
||||
/* Load initrd. */
|
||||
if (args->initrd_filename) {
|
||||
if (machine->initrd_filename) {
|
||||
initrd_base = high = ROUND_UP(high, 4);
|
||||
initrd_size = load_image_targphys(args->initrd_filename,
|
||||
initrd_size = load_image_targphys(machine->initrd_filename,
|
||||
high, ram_size - high);
|
||||
|
||||
if (initrd_size < 0) {
|
||||
error_report("couldn't load ram disk '%s'",
|
||||
args->initrd_filename);
|
||||
machine->initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
high = ROUND_UP(high + initrd_size, 4);
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "ioinst.h"
|
||||
#include "css.h"
|
||||
#include "trace.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
|
||||
typedef struct CrwContainer {
|
||||
CRW crw;
|
||||
@@ -39,6 +40,13 @@ typedef struct CssImage {
|
||||
ChpInfo chpids[MAX_CHPID + 1];
|
||||
} CssImage;
|
||||
|
||||
typedef struct IoAdapter {
|
||||
uint32_t id;
|
||||
uint8_t type;
|
||||
uint8_t isc;
|
||||
QTAILQ_ENTRY(IoAdapter) sibling;
|
||||
} IoAdapter;
|
||||
|
||||
typedef struct ChannelSubSys {
|
||||
QTAILQ_HEAD(, CrwContainer) pending_crws;
|
||||
bool do_crw_mchk;
|
||||
@@ -49,6 +57,7 @@ typedef struct ChannelSubSys {
|
||||
uint64_t chnmon_area;
|
||||
CssImage *css[MAX_CSSID + 1];
|
||||
uint8_t default_cssid;
|
||||
QTAILQ_HEAD(, IoAdapter) io_adapters;
|
||||
} ChannelSubSys;
|
||||
|
||||
static ChannelSubSys *channel_subsys;
|
||||
@@ -69,6 +78,46 @@ int css_create_css_image(uint8_t cssid, bool default_image)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
|
||||
bool maskable, uint32_t *id)
|
||||
{
|
||||
IoAdapter *adapter;
|
||||
bool found = false;
|
||||
int ret;
|
||||
S390FLICState *fs = s390_get_flic();
|
||||
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
|
||||
|
||||
*id = 0;
|
||||
QTAILQ_FOREACH(adapter, &channel_subsys->io_adapters, sibling) {
|
||||
if ((adapter->type == type) && (adapter->isc == isc)) {
|
||||
*id = adapter->id;
|
||||
found = true;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (adapter->id >= *id) {
|
||||
*id = adapter->id + 1;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
goto out;
|
||||
}
|
||||
adapter = g_new0(IoAdapter, 1);
|
||||
ret = fsc->register_io_adapter(fs, *id, isc, swap, maskable);
|
||||
if (ret == 0) {
|
||||
adapter->id = *id;
|
||||
adapter->isc = isc;
|
||||
adapter->type = type;
|
||||
QTAILQ_INSERT_TAIL(&channel_subsys->io_adapters, adapter, sibling);
|
||||
} else {
|
||||
g_free(adapter);
|
||||
fprintf(stderr, "Unexpected error %d when registering adapter %d\n",
|
||||
ret, *id);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t css_build_subchannel_id(SubchDev *sch)
|
||||
{
|
||||
if (channel_subsys->max_cssid > 0) {
|
||||
@@ -1235,6 +1284,7 @@ static void css_init(void)
|
||||
channel_subsys->do_crw_mchk = true;
|
||||
channel_subsys->crws_lost = false;
|
||||
channel_subsys->chnmon_active = false;
|
||||
QTAILQ_INIT(&channel_subsys->io_adapters);
|
||||
}
|
||||
machine_init(css_init);
|
||||
|
||||
|
@@ -98,4 +98,8 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
|
||||
int hotplugged, int add);
|
||||
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
|
||||
void css_adapter_interrupt(uint8_t isc);
|
||||
|
||||
#define CSS_IO_ADAPTER_VIRTIO 1
|
||||
int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
|
||||
bool maskable, uint32_t *id);
|
||||
#endif
|
||||
|
@@ -79,9 +79,9 @@ static void virtio_ccw_register_hcalls(void)
|
||||
virtio_ccw_hcall_early_printk);
|
||||
}
|
||||
|
||||
static void ccw_init(QEMUMachineInitArgs *args)
|
||||
static void ccw_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t my_ram_size = args->ram_size;
|
||||
ram_addr_t my_ram_size = machine->ram_size;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
int shift = 0;
|
||||
@@ -102,8 +102,8 @@ static void ccw_init(QEMUMachineInitArgs *args)
|
||||
/* get a BUS */
|
||||
css_bus = virtual_css_bus_init();
|
||||
s390_sclp_init();
|
||||
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
|
||||
args->initrd_filename, "s390-ccw.img");
|
||||
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
|
||||
machine->initrd_filename, "s390-ccw.img");
|
||||
s390_flic_init();
|
||||
|
||||
/* register hypercalls */
|
||||
@@ -118,7 +118,7 @@ static void ccw_init(QEMUMachineInitArgs *args)
|
||||
storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
|
||||
|
||||
/* init CPUs */
|
||||
s390_init_cpus(args->cpu_model, storage_keys);
|
||||
s390_init_cpus(machine->cpu_model, storage_keys);
|
||||
|
||||
if (kvm_enabled()) {
|
||||
kvm_s390_enable_css_support(s390_cpu_addr2state(0));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user