Compare commits
199 Commits
vfio-updat
...
pull-ui-20
Author | SHA1 | Date | |
---|---|---|---|
|
e220656ce1 | ||
|
438528a3e7 | ||
|
9f5c6d06ad | ||
|
6e378dd214 | ||
|
aa53d5bfc3 | ||
|
ea6a55bcc0 | ||
|
0aa6aefc9c | ||
|
e20d84c140 | ||
|
d44ec15630 | ||
|
0a7ac9f9e7 | ||
|
5c1bc9a234 | ||
|
ed0db8663a | ||
|
a55b53a2f4 | ||
|
09aa3bf382 | ||
|
1fce1ba985 | ||
|
a8d64e7351 | ||
|
10eacda787 | ||
|
af393ffc6d | ||
|
81907a5829 | ||
|
58ae2d1f03 | ||
|
e6c8fc07b4 | ||
|
52ff951b4f | ||
|
cb01d3912c | ||
|
ae08792301 | ||
|
f8c88bbcda | ||
|
50866ba5a2 | ||
|
235ea1f5c8 | ||
|
8da5ef579f | ||
|
a609ad8b69 | ||
|
4d1e324b22 | ||
|
a88a5cd2e8 | ||
|
2d4846bd7b | ||
|
d8b9d7719c | ||
|
bdf46d6478 | ||
|
01bc435b44 | ||
|
bee62662a3 | ||
|
152db36ae6 | ||
|
d319f83fe9 | ||
|
0759487b56 | ||
|
03cbfd7b5c | ||
|
461a1582f0 | ||
|
c489e5591f | ||
|
67ef811ed1 | ||
|
e55eb806db | ||
|
0c6940d086 | ||
|
8021de1013 | ||
|
25d943b957 | ||
|
6c6916dac8 | ||
|
6771197dff | ||
|
02506e2d54 | ||
|
a7a173624e | ||
|
01fdadde80 | ||
|
0b4b49387c | ||
|
586fc27e6a | ||
|
cfc3b074de | ||
|
21a933ea33 | ||
|
d61524486c | ||
|
3655cb9c73 | ||
|
58eaa2174e | ||
|
774ae4254d | ||
|
df215b59d9 | ||
|
828066c78a | ||
|
f678f671ba | ||
|
3292b4477f | ||
|
518d7fd2a0 | ||
|
5dc1fbae70 | ||
|
723733575b | ||
|
8283f6f821 | ||
|
533e8bbb55 | ||
|
75fb3d286e | ||
|
18d6abae3e | ||
|
d6b304ba92 | ||
|
86165b499e | ||
|
5602b39ff3 | ||
|
fee089e4e2 | ||
|
e24a47c5b7 | ||
|
03de2f5274 | ||
|
2906cddfec | ||
|
adb3feda8d | ||
|
a1afb6062e | ||
|
8b1fe1cedf | ||
|
ef0716df7f | ||
|
9ae91bc43f | ||
|
3dbc01ae87 | ||
|
2b75f84823 | ||
|
e8dc06d225 | ||
|
d159148b63 | ||
|
388e47c75b | ||
|
072ed5f260 | ||
|
9897e46264 | ||
|
3240dd9a69 | ||
|
4f7ab0cdbc | ||
|
f894efd199 | ||
|
93a92d3bd6 | ||
|
13756fb008 | ||
|
7c73d2a3fa | ||
|
b6e17875f2 | ||
|
de3f1b9841 | ||
|
460c579f3d | ||
|
5089c7ce82 | ||
|
7bd57b5150 | ||
|
c3b7f66800 | ||
|
f8e1f5d6a2 | ||
|
ce15110981 | ||
|
d2dc4069e0 | ||
|
1b1624092d | ||
|
0ea63844c2 | ||
|
91478cefaa | ||
|
b3915dbbdc | ||
|
869938ae2a | ||
|
3174c64bb7 | ||
|
90ce6e2644 | ||
|
974dc73d77 | ||
|
30456d5ba3 | ||
|
b1e34d1c3a | ||
|
d57106a4b6 | ||
|
fd3e39a40c | ||
|
e78490c44c | ||
|
79f56d82f8 | ||
|
1ef26b1f30 | ||
|
b82fc321bf | ||
|
22672a3798 | ||
|
8e388e907b | ||
|
474114b730 | ||
|
58c7b618f3 | ||
|
1e3165980c | ||
|
014cb152b8 | ||
|
b5e751b51f | ||
|
ea6e4981bf | ||
|
39de99843e | ||
|
ffe42cc14c | ||
|
b54ca0c3df | ||
|
fa1298c2d6 | ||
|
5f77e06baa | ||
|
fe3c546c5f | ||
|
64c9bc181f | ||
|
14ec7b2c5b | ||
|
80eecda8e5 | ||
|
96c33a4523 | ||
|
d42a0d1484 | ||
|
4a6b52d67e | ||
|
39ba2ea61f | ||
|
2264c2c96e | ||
|
1fbeff72c2 | ||
|
63e27f28f2 | ||
|
ca1fc8c97e | ||
|
65d64f3623 | ||
|
baf28f57e2 | ||
|
228de9cf1d | ||
|
e3517a5299 | ||
|
cf7ea1e60c | ||
|
8eb779e422 | ||
|
fe243e4881 | ||
|
43e15ed4fd | ||
|
4b84fc70ce | ||
|
f436c94102 | ||
|
156abc2f90 | ||
|
d310d85bf4 | ||
|
1ffad77cde | ||
|
f5a845fdb4 | ||
|
a90cade023 | ||
|
f9d058852c | ||
|
eb8a1a1cbd | ||
|
398befdf50 | ||
|
dce13204a0 | ||
|
8a0fc18d88 | ||
|
100f8f2608 | ||
|
1588ab5d0b | ||
|
d5851089a8 | ||
|
6f9b6d57ae | ||
|
03ba36c83d | ||
|
45b2d418e0 | ||
|
6921b18095 | ||
|
3c9242f5ae | ||
|
a02dabe10a | ||
|
9bd9c7f5b5 | ||
|
a513416ecf | ||
|
aa6e546c5a | ||
|
fa8b7ce2c6 | ||
|
eb769f7420 | ||
|
77c9aaefd7 | ||
|
499afa2512 | ||
|
3babeb153c | ||
|
9ba371b634 | ||
|
12d5ee3a7e | ||
|
bca5a8f462 | ||
|
f38738e212 | ||
|
2875645b65 | ||
|
327d83ba71 | ||
|
c3bce9d5f9 | ||
|
586d1a99ff | ||
|
a40db1b36b | ||
|
3ba32c100a | ||
|
1badb58698 | ||
|
50fe4df8ee | ||
|
0c48262d47 | ||
|
07d792d2b0 | ||
|
0bb721d721 | ||
|
d783f78933 |
23
MAINTAINERS
23
MAINTAINERS
@@ -84,6 +84,13 @@ F: include/exec/exec-all.h
|
||||
F: include/exec/helper*.h
|
||||
F: include/exec/tb-hash.h
|
||||
|
||||
FPU emulation
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
S: Odd Fixes
|
||||
F: fpu/
|
||||
F: include/fpu/
|
||||
|
||||
Alpha
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
S: Maintained
|
||||
@@ -356,6 +363,7 @@ M: Dmitry Solodkiy <d.solodkiy@samsung.com>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/*/exynos*
|
||||
F: include/hw/arm/exynos4210.h
|
||||
|
||||
Calxeda Highbank
|
||||
M: Rob Herring <robh@kernel.org>
|
||||
@@ -383,6 +391,7 @@ L: qemu-arm@nongnu.org
|
||||
S: Odd fixes
|
||||
F: hw/*/imx*
|
||||
F: hw/arm/kzm.c
|
||||
F: include/hw/arm/fsl-imx31.h
|
||||
|
||||
Integrator CP
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
@@ -425,6 +434,7 @@ F: hw/arm/spitz.c
|
||||
F: hw/arm/tosa.c
|
||||
F: hw/arm/z2.c
|
||||
F: hw/*/pxa2xx*
|
||||
F: include/hw/arm/pxa.h
|
||||
|
||||
Stellaris
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
@@ -761,6 +771,7 @@ OMAP
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
S: Maintained
|
||||
F: hw/*/omap*
|
||||
F: include/hw/arm/omap.h
|
||||
|
||||
IPack
|
||||
M: Alberto Garcia <berto@igalia.com>
|
||||
@@ -1076,6 +1087,7 @@ SPICE
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Supported
|
||||
F: include/ui/qemu-spice.h
|
||||
F: include/ui/spice-display.h
|
||||
F: ui/spice-*.c
|
||||
F: audio/spiceaudio.c
|
||||
F: hw/display/qxl*
|
||||
@@ -1084,6 +1096,7 @@ Graphics
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: ui/
|
||||
F: include/ui/
|
||||
|
||||
Cocoa graphics
|
||||
M: Andreas Färber <andreas.faerber@web.de>
|
||||
@@ -1234,6 +1247,7 @@ F: include/migration/
|
||||
F: migration/
|
||||
F: scripts/vmstate-static-checker.py
|
||||
F: tests/vmstate-static-checker-data/
|
||||
F: docs/migration.txt
|
||||
|
||||
Seccomp
|
||||
M: Eduardo Otubo <eduardo.otubo@profitbricks.com>
|
||||
@@ -1276,6 +1290,15 @@ S: Maintained
|
||||
F: include/qemu/sockets.h
|
||||
F: util/qemu-sockets.c
|
||||
|
||||
Throttling infrastructure
|
||||
M: Alberto Garcia <berto@igalia.com>
|
||||
S: Supported
|
||||
F: block/throttle-groups.c
|
||||
F: include/block/throttle-groups.h
|
||||
F: include/qemu/throttle.h
|
||||
F: util/throttle.c
|
||||
L: qemu-block@nongnu.org
|
||||
|
||||
Usermode Emulation
|
||||
------------------
|
||||
Overall
|
||||
|
2
Makefile
2
Makefile
@@ -391,7 +391,7 @@ bepo cz
|
||||
ifdef INSTALL_BLOBS
|
||||
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
|
||||
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \
|
||||
acpi-dsdt.aml q35-acpi-dsdt.aml \
|
||||
acpi-dsdt.aml \
|
||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
|
||||
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
|
||||
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
|
||||
|
@@ -24,7 +24,6 @@
|
||||
#ifndef QEMU_AUDIO_H
|
||||
#define QEMU_AUDIO_H
|
||||
|
||||
#include "config-host.h"
|
||||
#include "qemu/queue.h"
|
||||
|
||||
typedef void (*audio_callback_fn) (void *opaque, int avail);
|
||||
|
4
block.c
4
block.c
@@ -1191,10 +1191,6 @@ static int bdrv_fill_options(QDict **options, const char *filename,
|
||||
}
|
||||
}
|
||||
|
||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||
*flags |= BDRV_O_INACTIVE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
20
block/qapi.c
20
block/qapi.c
@@ -92,6 +92,26 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs, Error **errp)
|
||||
info->has_iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max;
|
||||
info->iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max;
|
||||
|
||||
info->has_bps_max_length = info->has_bps_max;
|
||||
info->bps_max_length =
|
||||
cfg.buckets[THROTTLE_BPS_TOTAL].burst_length;
|
||||
info->has_bps_rd_max_length = info->has_bps_rd_max;
|
||||
info->bps_rd_max_length =
|
||||
cfg.buckets[THROTTLE_BPS_READ].burst_length;
|
||||
info->has_bps_wr_max_length = info->has_bps_wr_max;
|
||||
info->bps_wr_max_length =
|
||||
cfg.buckets[THROTTLE_BPS_WRITE].burst_length;
|
||||
|
||||
info->has_iops_max_length = info->has_iops_max;
|
||||
info->iops_max_length =
|
||||
cfg.buckets[THROTTLE_OPS_TOTAL].burst_length;
|
||||
info->has_iops_rd_max_length = info->has_iops_rd_max;
|
||||
info->iops_rd_max_length =
|
||||
cfg.buckets[THROTTLE_OPS_READ].burst_length;
|
||||
info->has_iops_wr_max_length = info->has_iops_wr_max;
|
||||
info->iops_wr_max_length =
|
||||
cfg.buckets[THROTTLE_OPS_WRITE].burst_length;
|
||||
|
||||
info->has_iops_size = cfg.op_size;
|
||||
info->iops_size = cfg.op_size;
|
||||
|
||||
|
@@ -286,7 +286,8 @@ static void quorum_aio_cb(void *opaque, int ret)
|
||||
|
||||
if (acb->is_read && s->read_pattern == QUORUM_READ_PATTERN_FIFO) {
|
||||
/* We try to read next child in FIFO order if we fail to read */
|
||||
if (ret < 0 && ++acb->child_iter < s->num_children) {
|
||||
if (ret < 0 && (acb->child_iter + 1) < s->num_children) {
|
||||
acb->child_iter++;
|
||||
read_fifo_child(acb);
|
||||
return;
|
||||
}
|
||||
|
109
blockdev.c
109
blockdev.c
@@ -343,29 +343,6 @@ static bool parse_stats_intervals(BlockAcctStats *stats, QList *intervals,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
|
||||
{
|
||||
if (throttle_conflicting(cfg)) {
|
||||
error_setg(errp, "bps/iops/max total values and read/write values"
|
||||
" cannot be used at the same time");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!throttle_is_valid(cfg)) {
|
||||
error_setg(errp, "bps/iops/max values must be within [0, %lld]",
|
||||
THROTTLE_VALUE_MAX);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (throttle_max_is_missing_limit(cfg)) {
|
||||
error_setg(errp, "bps_max/iops_max require corresponding"
|
||||
" bps/iops values");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
|
||||
|
||||
/* All parameters but @opts are optional and may be set to NULL. */
|
||||
@@ -410,7 +387,7 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
|
||||
}
|
||||
|
||||
if (throttle_cfg) {
|
||||
memset(throttle_cfg, 0, sizeof(*throttle_cfg));
|
||||
throttle_config_init(throttle_cfg);
|
||||
throttle_cfg->buckets[THROTTLE_BPS_TOTAL].avg =
|
||||
qemu_opt_get_number(opts, "throttling.bps-total", 0);
|
||||
throttle_cfg->buckets[THROTTLE_BPS_READ].avg =
|
||||
@@ -437,10 +414,23 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
|
||||
throttle_cfg->buckets[THROTTLE_OPS_WRITE].max =
|
||||
qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
|
||||
|
||||
throttle_cfg->buckets[THROTTLE_BPS_TOTAL].burst_length =
|
||||
qemu_opt_get_number(opts, "throttling.bps-total-max-length", 1);
|
||||
throttle_cfg->buckets[THROTTLE_BPS_READ].burst_length =
|
||||
qemu_opt_get_number(opts, "throttling.bps-read-max-length", 1);
|
||||
throttle_cfg->buckets[THROTTLE_BPS_WRITE].burst_length =
|
||||
qemu_opt_get_number(opts, "throttling.bps-write-max-length", 1);
|
||||
throttle_cfg->buckets[THROTTLE_OPS_TOTAL].burst_length =
|
||||
qemu_opt_get_number(opts, "throttling.iops-total-max-length", 1);
|
||||
throttle_cfg->buckets[THROTTLE_OPS_READ].burst_length =
|
||||
qemu_opt_get_number(opts, "throttling.iops-read-max-length", 1);
|
||||
throttle_cfg->buckets[THROTTLE_OPS_WRITE].burst_length =
|
||||
qemu_opt_get_number(opts, "throttling.iops-write-max-length", 1);
|
||||
|
||||
throttle_cfg->op_size =
|
||||
qemu_opt_get_number(opts, "throttling.iops-size", 0);
|
||||
|
||||
if (!check_throttle_config(throttle_cfg, errp)) {
|
||||
if (!throttle_is_valid(throttle_cfg, errp)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -610,6 +600,10 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
qdict_put(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, qstring_from_str("on"));
|
||||
}
|
||||
|
||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||
bdrv_flags |= BDRV_O_INACTIVE;
|
||||
}
|
||||
|
||||
blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags,
|
||||
errp);
|
||||
if (!blk) {
|
||||
@@ -688,6 +682,10 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||
bdrv_flags |= BDRV_O_INACTIVE;
|
||||
}
|
||||
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, NULL, NULL, bs_opts, bdrv_flags, errp);
|
||||
if (ret < 0) {
|
||||
@@ -2515,6 +2513,8 @@ void qmp_blockdev_change_medium(const char *device, const char *filename,
|
||||
}
|
||||
|
||||
bdrv_flags = blk_get_open_flags_from_root_state(blk);
|
||||
bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
|
||||
BDRV_O_PROTOCOL);
|
||||
|
||||
if (!has_read_only) {
|
||||
read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
|
||||
@@ -2600,6 +2600,18 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
|
||||
int64_t iops_rd_max,
|
||||
bool has_iops_wr_max,
|
||||
int64_t iops_wr_max,
|
||||
bool has_bps_max_length,
|
||||
int64_t bps_max_length,
|
||||
bool has_bps_rd_max_length,
|
||||
int64_t bps_rd_max_length,
|
||||
bool has_bps_wr_max_length,
|
||||
int64_t bps_wr_max_length,
|
||||
bool has_iops_max_length,
|
||||
int64_t iops_max_length,
|
||||
bool has_iops_rd_max_length,
|
||||
int64_t iops_rd_max_length,
|
||||
bool has_iops_wr_max_length,
|
||||
int64_t iops_wr_max_length,
|
||||
bool has_iops_size,
|
||||
int64_t iops_size,
|
||||
bool has_group,
|
||||
@@ -2626,7 +2638,7 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
throttle_config_init(&cfg);
|
||||
cfg.buckets[THROTTLE_BPS_TOTAL].avg = bps;
|
||||
cfg.buckets[THROTTLE_BPS_READ].avg = bps_rd;
|
||||
cfg.buckets[THROTTLE_BPS_WRITE].avg = bps_wr;
|
||||
@@ -2654,11 +2666,30 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
|
||||
cfg.buckets[THROTTLE_OPS_WRITE].max = iops_wr_max;
|
||||
}
|
||||
|
||||
if (has_bps_max_length) {
|
||||
cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = bps_max_length;
|
||||
}
|
||||
if (has_bps_rd_max_length) {
|
||||
cfg.buckets[THROTTLE_BPS_READ].burst_length = bps_rd_max_length;
|
||||
}
|
||||
if (has_bps_wr_max_length) {
|
||||
cfg.buckets[THROTTLE_BPS_WRITE].burst_length = bps_wr_max_length;
|
||||
}
|
||||
if (has_iops_max_length) {
|
||||
cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = iops_max_length;
|
||||
}
|
||||
if (has_iops_rd_max_length) {
|
||||
cfg.buckets[THROTTLE_OPS_READ].burst_length = iops_rd_max_length;
|
||||
}
|
||||
if (has_iops_wr_max_length) {
|
||||
cfg.buckets[THROTTLE_OPS_WRITE].burst_length = iops_wr_max_length;
|
||||
}
|
||||
|
||||
if (has_iops_size) {
|
||||
cfg.op_size = iops_size;
|
||||
}
|
||||
|
||||
if (!check_throttle_config(&cfg, errp)) {
|
||||
if (!throttle_is_valid(&cfg, errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -4086,6 +4117,30 @@ QemuOptsList qemu_common_drive_opts = {
|
||||
.name = "throttling.bps-write-max",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "total bytes write burst",
|
||||
},{
|
||||
.name = "throttling.iops-total-max-length",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "length of the iops-total-max burst period, in seconds",
|
||||
},{
|
||||
.name = "throttling.iops-read-max-length",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "length of the iops-read-max burst period, in seconds",
|
||||
},{
|
||||
.name = "throttling.iops-write-max-length",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "length of the iops-write-max burst period, in seconds",
|
||||
},{
|
||||
.name = "throttling.bps-total-max-length",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "length of the bps-total-max burst period, in seconds",
|
||||
},{
|
||||
.name = "throttling.bps-read-max-length",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "length of the bps-read-max burst period, in seconds",
|
||||
},{
|
||||
.name = "throttling.bps-write-max-length",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "length of the bps-write-max burst period, in seconds",
|
||||
},{
|
||||
.name = "throttling.iops-size",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
|
@@ -1,3 +1,6 @@
|
||||
#ifndef TARGET_SYSCALL_H
|
||||
#define TARGET_SYSCALL_H
|
||||
|
||||
/* default linux values for the selectors */
|
||||
#define __USER_CS (0x23)
|
||||
#define __USER_DS (0x2B)
|
||||
@@ -159,3 +162,4 @@ struct target_vm86plus_struct {
|
||||
|
||||
#define UNAME_MACHINE "i386"
|
||||
|
||||
#endif /* TARGET_SYSCALL_H */
|
@@ -17,15 +17,12 @@
|
||||
#ifndef QEMU_H
|
||||
#define QEMU_H
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
||||
#undef DEBUG_REMAP
|
||||
#ifdef DEBUG_REMAP
|
||||
#include <stdlib.h>
|
||||
#endif /* DEBUG_REMAP */
|
||||
|
||||
#include "exec/user/abitypes.h"
|
||||
@@ -38,7 +35,7 @@ enum BSDType {
|
||||
extern enum BSDType bsd_type;
|
||||
|
||||
#include "syscall_defs.h"
|
||||
#include "syscall.h"
|
||||
#include "target_syscall.h"
|
||||
#include "target_signal.h"
|
||||
#include "exec/gdbstub.h"
|
||||
|
||||
|
@@ -1,3 +1,6 @@
|
||||
#ifndef TARGET_SYSCALL_H
|
||||
#define TARGET_SYSCALL_H
|
||||
|
||||
struct target_pt_regs {
|
||||
abi_ulong psr;
|
||||
abi_ulong pc;
|
||||
@@ -7,3 +10,5 @@ struct target_pt_regs {
|
||||
};
|
||||
|
||||
#define UNAME_MACHINE "sun4"
|
||||
|
||||
#endif /* TARGET_SYSCALL_H */
|
@@ -1,3 +1,6 @@
|
||||
#ifndef TARGET_SYSCALL_H
|
||||
#define TARGET_SYSCALL_H
|
||||
|
||||
struct target_pt_regs {
|
||||
abi_ulong u_regs[16];
|
||||
abi_ulong tstate;
|
||||
@@ -8,3 +11,5 @@ struct target_pt_regs {
|
||||
};
|
||||
|
||||
#define UNAME_MACHINE "sun4u"
|
||||
|
||||
#endif /* TARGET_SYSCALL_H */
|
@@ -1,3 +1,6 @@
|
||||
#ifndef TARGET_SYSCALL_H
|
||||
#define TARGET_SYSCALL_H
|
||||
|
||||
#define __USER_CS (0x33)
|
||||
#define __USER_DS (0x2B)
|
||||
|
||||
@@ -114,3 +117,5 @@ struct target_msqid64_ds {
|
||||
#define TARGET_ARCH_SET_FS 0x1002
|
||||
#define TARGET_ARCH_GET_FS 0x1003
|
||||
#define TARGET_ARCH_GET_GS 0x1004
|
||||
|
||||
#endif /* TARGET_SYSCALL_H */
|
20
configure
vendored
20
configure
vendored
@@ -279,6 +279,7 @@ smartcard=""
|
||||
libusb=""
|
||||
usb_redir=""
|
||||
opengl=""
|
||||
opengl_dmabuf="no"
|
||||
zlib="yes"
|
||||
lzo=""
|
||||
snappy=""
|
||||
@@ -3274,7 +3275,7 @@ libs_softmmu="$libs_softmmu $fdt_libs"
|
||||
# opengl probe (for sdl2, gtk, milkymist-tmu2)
|
||||
|
||||
if test "$opengl" != "no" ; then
|
||||
opengl_pkgs="epoxy"
|
||||
opengl_pkgs="epoxy libdrm gbm"
|
||||
if $pkg_config $opengl_pkgs x11; then
|
||||
opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags"
|
||||
opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs"
|
||||
@@ -3292,6 +3293,18 @@ if test "$opengl" != "no" ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$opengl" = "yes"; then
|
||||
cat > $TMPC << EOF
|
||||
#include <epoxy/egl.h>
|
||||
#ifndef EGL_MESA_image_dma_buf_export
|
||||
# error mesa/epoxy lacks support for dmabufs (mesa 10.6+)
|
||||
#endif
|
||||
int main(void) { return 0; }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
opengl_dmabuf=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# archipelago probe
|
||||
@@ -4752,6 +4765,7 @@ echo "smartcard support $smartcard"
|
||||
echo "libusb $libusb"
|
||||
echo "usb net redir $usb_redir"
|
||||
echo "OpenGL support $opengl"
|
||||
echo "OpenGL dmabufs $opengl_dmabuf"
|
||||
echo "libiscsi support $libiscsi"
|
||||
echo "libnfs support $libnfs"
|
||||
echo "build guest agent $guest_agent"
|
||||
@@ -5050,6 +5064,7 @@ if test "$gtk" = "yes" ; then
|
||||
echo "CONFIG_GTK=y" >> $config_host_mak
|
||||
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
|
||||
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
||||
echo "GTK_LIBS=$gtk_libs" >> $config_host_mak
|
||||
if test "$gtk_gl" = "yes" ; then
|
||||
echo "CONFIG_GTK_GL=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -5158,6 +5173,9 @@ if test "$opengl" = "yes" ; then
|
||||
echo "CONFIG_OPENGL=y" >> $config_host_mak
|
||||
echo "OPENGL_CFLAGS=$opengl_cflags" >> $config_host_mak
|
||||
echo "OPENGL_LIBS=$opengl_libs" >> $config_host_mak
|
||||
if test "$opengl_dmabuf" = "yes" ; then
|
||||
echo "CONFIG_OPENGL_DMABUF=y" >> $config_host_mak
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$lzo" = "yes" ; then
|
||||
|
@@ -19,7 +19,6 @@
|
||||
* purposes.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "qemu/queue.h"
|
||||
|
@@ -26,10 +26,7 @@
|
||||
* associated to the ivshmem shared memory.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "qemu/event_notifier.h"
|
||||
#include "qemu/queue.h"
|
||||
|
@@ -17,12 +17,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "vixl/a64/disasm-a64.h"
|
||||
|
||||
extern "C" {
|
||||
#include "qemu/osdep.h"
|
||||
#include "disas/bfd.h"
|
||||
}
|
||||
|
||||
#include "vixl/a64/disasm-a64.h"
|
||||
|
||||
using namespace vixl;
|
||||
|
||||
static Decoder *vixl_decoder = NULL;
|
||||
|
@@ -1405,6 +1405,10 @@ const struct mips_opcode mips_builtin_opcodes[] =
|
||||
{"cmp.sor.d", "D,S,T", 0x46a00019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sune.d", "D,S,T", 0x46a0001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sne.d", "D,S,T", 0x46a0001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"dvp", "", 0x41600024, 0xffffffff, TRAP, 0, I32R6},
|
||||
{"dvp", "t", 0x41600024, 0xffe0ffff, TRAP|WR_t, 0, I32R6},
|
||||
{"evp", "", 0x41600004, 0xffffffff, TRAP, 0, I32R6},
|
||||
{"evp", "t", 0x41600004, 0xffe0ffff, TRAP|WR_t, 0, I32R6},
|
||||
|
||||
/* MSA */
|
||||
{"sll.b", "+d,+e,+f", 0x7800000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
|
@@ -220,6 +220,24 @@ Data:
|
||||
},
|
||||
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||
|
||||
DUMP_COMPLETED
|
||||
--------------
|
||||
|
||||
Emitted when the guest has finished one memory dump.
|
||||
|
||||
Data:
|
||||
|
||||
- "result": DumpQueryResult type described in qapi-schema.json
|
||||
- "error": Error message when dump failed. This is only a
|
||||
human-readable string provided when dump failed. It should not be
|
||||
parsed in any way (json-string, optional)
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "DUMP_COMPLETED",
|
||||
"data": {"result": {"total": 1090650112, "status": "completed",
|
||||
"completed": 1090650112} } }
|
||||
|
||||
GUEST_PANICKED
|
||||
--------------
|
||||
|
||||
|
@@ -103,7 +103,18 @@ in the description of a field.
|
||||
write to an image with unknown auto-clear features if it
|
||||
clears the respective bits from this field first.
|
||||
|
||||
Bits 0-63: Reserved (set to 0)
|
||||
Bit 0: Bitmaps extension bit
|
||||
This bit indicates consistency for the bitmaps
|
||||
extension data.
|
||||
|
||||
It is an error if this bit is set without the
|
||||
bitmaps extension present.
|
||||
|
||||
If the bitmaps extension is present but this
|
||||
bit is unset, the bitmaps extension data must be
|
||||
considered inconsistent.
|
||||
|
||||
Bits 1-63: Reserved (set to 0)
|
||||
|
||||
96 - 99: refcount_order
|
||||
Describes the width of a reference count block entry (width
|
||||
@@ -123,6 +134,7 @@ be stored. Each extension has a structure like the following:
|
||||
0x00000000 - End of the header extension area
|
||||
0xE2792ACA - Backing file format name
|
||||
0x6803f857 - Feature name table
|
||||
0x23852875 - Bitmaps extension
|
||||
other - Unknown header extension, can be safely
|
||||
ignored
|
||||
|
||||
@@ -166,6 +178,36 @@ the header extension data. Each entry look like this:
|
||||
terminated if it has full length)
|
||||
|
||||
|
||||
== Bitmaps extension ==
|
||||
|
||||
The bitmaps extension is an optional header extension. It provides the ability
|
||||
to store bitmaps related to a virtual disk. For now, there is only one bitmap
|
||||
type: the dirty tracking bitmap, which tracks virtual disk changes from some
|
||||
point in time.
|
||||
|
||||
The data of the extension should be considered consistent only if the
|
||||
corresponding auto-clear feature bit is set, see autoclear_features above.
|
||||
|
||||
The fields of the bitmaps extension are:
|
||||
|
||||
Byte 0 - 3: nb_bitmaps
|
||||
The number of bitmaps contained in the image. Must be
|
||||
greater than or equal to 1.
|
||||
|
||||
Note: Qemu currently only supports up to 65535 bitmaps per
|
||||
image.
|
||||
|
||||
4 - 7: Reserved, must be zero.
|
||||
|
||||
8 - 15: bitmap_directory_size
|
||||
Size of the bitmap directory in bytes. It is the cumulative
|
||||
size of all (nb_bitmaps) bitmap headers.
|
||||
|
||||
16 - 23: bitmap_directory_offset
|
||||
Offset into the image file at which the bitmap directory
|
||||
starts. Must be aligned to a cluster boundary.
|
||||
|
||||
|
||||
== Host cluster management ==
|
||||
|
||||
qcow2 manages the allocation of host clusters by maintaining a reference count
|
||||
@@ -360,3 +402,180 @@ Snapshot table entry:
|
||||
|
||||
variable: Padding to round up the snapshot table entry size to the
|
||||
next multiple of 8.
|
||||
|
||||
|
||||
== Bitmaps ==
|
||||
|
||||
As mentioned above, the bitmaps extension provides the ability to store bitmaps
|
||||
related to a virtual disk. This section describes how these bitmaps are stored.
|
||||
|
||||
All stored bitmaps are related to the virtual disk stored in the same image, so
|
||||
each bitmap size is equal to the virtual disk size.
|
||||
|
||||
Each bit of the bitmap is responsible for strictly defined range of the virtual
|
||||
disk. For bit number bit_nr the corresponding range (in bytes) will be:
|
||||
|
||||
[bit_nr * bitmap_granularity .. (bit_nr + 1) * bitmap_granularity - 1]
|
||||
|
||||
Granularity is a property of the concrete bitmap, see below.
|
||||
|
||||
|
||||
=== Bitmap directory ===
|
||||
|
||||
Each bitmap saved in the image is described in a bitmap directory entry. The
|
||||
bitmap directory is a contiguous area in the image file, whose starting offset
|
||||
and length are given by the header extension fields bitmap_directory_offset and
|
||||
bitmap_directory_size. The entries of the bitmap directory have variable
|
||||
length, depending on the lengths of the bitmap name and extra data. These
|
||||
entries are also called bitmap headers.
|
||||
|
||||
Structure of a bitmap directory entry:
|
||||
|
||||
Byte 0 - 7: bitmap_table_offset
|
||||
Offset into the image file at which the bitmap table
|
||||
(described below) for the bitmap starts. Must be aligned to
|
||||
a cluster boundary.
|
||||
|
||||
8 - 11: bitmap_table_size
|
||||
Number of entries in the bitmap table of the bitmap.
|
||||
|
||||
12 - 15: flags
|
||||
Bit
|
||||
0: in_use
|
||||
The bitmap was not saved correctly and may be
|
||||
inconsistent.
|
||||
|
||||
1: auto
|
||||
The bitmap must reflect all changes of the virtual
|
||||
disk by any application that would write to this qcow2
|
||||
file (including writes, snapshot switching, etc.). The
|
||||
type of this bitmap must be 'dirty tracking bitmap'.
|
||||
|
||||
2: extra_data_compatible
|
||||
This flags is meaningful when the extra data is
|
||||
unknown to the software (currently any extra data is
|
||||
unknown to Qemu).
|
||||
If it is set, the bitmap may be used as expected, extra
|
||||
data must be left as is.
|
||||
If it is not set, the bitmap must not be used, but
|
||||
both it and its extra data be left as is.
|
||||
|
||||
Bits 3 - 31 are reserved and must be 0.
|
||||
|
||||
16: type
|
||||
This field describes the sort of the bitmap.
|
||||
Values:
|
||||
1: Dirty tracking bitmap
|
||||
|
||||
Values 0, 2 - 255 are reserved.
|
||||
|
||||
17: granularity_bits
|
||||
Granularity bits. Valid values: 0 - 63.
|
||||
|
||||
Note: Qemu currently doesn't support granularity_bits
|
||||
greater than 31.
|
||||
|
||||
Granularity is calculated as
|
||||
granularity = 1 << granularity_bits
|
||||
|
||||
A bitmap's granularity is how many bytes of the image
|
||||
accounts for one bit of the bitmap.
|
||||
|
||||
18 - 19: name_size
|
||||
Size of the bitmap name. Must be non-zero.
|
||||
|
||||
Note: Qemu currently doesn't support values greater than
|
||||
1023.
|
||||
|
||||
20 - 23: extra_data_size
|
||||
Size of type-specific extra data.
|
||||
|
||||
For now, as no extra data is defined, extra_data_size is
|
||||
reserved and should be zero. If it is non-zero the
|
||||
behavior is defined by extra_data_compatible flag.
|
||||
|
||||
variable: extra_data
|
||||
Extra data for the bitmap, occupying extra_data_size bytes.
|
||||
Extra data must never contain references to clusters or in
|
||||
some other way allocate additional clusters.
|
||||
|
||||
variable: name
|
||||
The name of the bitmap (not null terminated), occupying
|
||||
name_size bytes. Must be unique among all bitmap names
|
||||
within the bitmaps extension.
|
||||
|
||||
variable: Padding to round up the bitmap directory entry size to the
|
||||
next multiple of 8. All bytes of the padding must be zero.
|
||||
|
||||
|
||||
=== Bitmap table ===
|
||||
|
||||
Each bitmap is stored using a one-level structure (as opposed to two-level
|
||||
structures like for refcounts and guest clusters mapping) for the mapping of
|
||||
bitmap data to host clusters. This structure is called the bitmap table.
|
||||
|
||||
Each bitmap table has a variable size (stored in the bitmap directory entry)
|
||||
and may use multiple clusters, however, it must be contiguous in the image
|
||||
file.
|
||||
|
||||
Structure of a bitmap table entry:
|
||||
|
||||
Bit 0: Reserved and must be zero if bits 9 - 55 are non-zero.
|
||||
If bits 9 - 55 are zero:
|
||||
0: Cluster should be read as all zeros.
|
||||
1: Cluster should be read as all ones.
|
||||
|
||||
1 - 8: Reserved and must be zero.
|
||||
|
||||
9 - 55: Bits 9 - 55 of the host cluster offset. Must be aligned to
|
||||
a cluster boundary. If the offset is 0, the cluster is
|
||||
unallocated; in that case, bit 0 determines how this
|
||||
cluster should be treated during reads.
|
||||
|
||||
56 - 63: Reserved and must be zero.
|
||||
|
||||
|
||||
=== Bitmap data ===
|
||||
|
||||
As noted above, bitmap data is stored in separate clusters, described by the
|
||||
bitmap table. Given an offset (in bytes) into the bitmap data, the offset into
|
||||
the image file can be obtained as follows:
|
||||
|
||||
image_offset(bitmap_data_offset) =
|
||||
bitmap_table[bitmap_data_offset / cluster_size] +
|
||||
(bitmap_data_offset % cluster_size)
|
||||
|
||||
This offset is not defined if bits 9 - 55 of bitmap table entry are zero (see
|
||||
above).
|
||||
|
||||
Given an offset byte_nr into the virtual disk and the bitmap's granularity, the
|
||||
bit offset into the image file to the corresponding bit of the bitmap can be
|
||||
calculated like this:
|
||||
|
||||
bit_offset(byte_nr) =
|
||||
image_offset(byte_nr / granularity / 8) * 8 +
|
||||
(byte_nr / granularity) % 8
|
||||
|
||||
If the size of the bitmap data is not a multiple of the cluster size then the
|
||||
last cluster of the bitmap data contains some unused tail bits. These bits must
|
||||
be zero.
|
||||
|
||||
|
||||
=== Dirty tracking bitmaps ===
|
||||
|
||||
Bitmaps with 'type' field equal to one are dirty tracking bitmaps.
|
||||
|
||||
When the virtual disk is in use dirty tracking bitmap may be 'enabled' or
|
||||
'disabled'. While the bitmap is 'enabled', all writes to the virtual disk
|
||||
should be reflected in the bitmap. A set bit in the bitmap means that the
|
||||
corresponding range of the virtual disk (see above) was written to while the
|
||||
bitmap was 'enabled'. An unset bit means that this range was not written to.
|
||||
|
||||
The software doesn't have to sync the bitmap in the image file with its
|
||||
representation in RAM after each write. Flag 'in_use' should be set while the
|
||||
bitmap is not synced.
|
||||
|
||||
In the image file the 'enabled' state is reflected by the 'auto' flag. If this
|
||||
flag is set, the software must consider the bitmap as 'enabled' and start
|
||||
tracking virtual disk changes to this bitmap from the first write to the
|
||||
virtual disk. If this flag is not set then the bitmap is disabled.
|
||||
|
252
docs/throttle.txt
Normal file
252
docs/throttle.txt
Normal file
@@ -0,0 +1,252 @@
|
||||
The QEMU throttling infrastructure
|
||||
==================================
|
||||
Copyright (C) 2016 Igalia, S.L.
|
||||
Author: Alberto Garcia <berto@igalia.com>
|
||||
|
||||
This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
later. See the COPYING file in the top-level directory.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
QEMU includes a throttling module that can be used to set limits to
|
||||
I/O operations. The code itself is generic and independent of the I/O
|
||||
units, but it is currenly used to limit the number of bytes per second
|
||||
and operations per second (IOPS) when performing disk I/O.
|
||||
|
||||
This document explains how to use the throttling code in QEMU, and how
|
||||
it works internally. The implementation is in throttle.c.
|
||||
|
||||
|
||||
Using throttling to limit disk I/O
|
||||
----------------------------------
|
||||
Two aspects of the disk I/O can be limited: the number of bytes per
|
||||
second and the number of operations per second (IOPS). For each one of
|
||||
them the user can set a global limit or separate limits for read and
|
||||
write operations. This gives us a total of six different parameters.
|
||||
|
||||
I/O limits can be set using the throttling.* parameters of -drive, or
|
||||
using the QMP 'block_set_io_throttle' command. These are the names of
|
||||
the parameters for both cases:
|
||||
|
||||
|-----------------------+-----------------------|
|
||||
| -drive | block_set_io_throttle |
|
||||
|-----------------------+-----------------------|
|
||||
| throttling.iops-total | iops |
|
||||
| throttling.iops-read | iops_rd |
|
||||
| throttling.iops-write | iops_wr |
|
||||
| throttling.bps-total | bps |
|
||||
| throttling.bps-read | bps_rd |
|
||||
| throttling.bps-write | bps_wr |
|
||||
|-----------------------+-----------------------|
|
||||
|
||||
It is possible to set limits for both IOPS and bps and the same time,
|
||||
and for each case we can decide whether to have separate read and
|
||||
write limits or not, but note that if iops-total is set then neither
|
||||
iops-read nor iops-write can be set. The same applies to bps-total and
|
||||
bps-read/write.
|
||||
|
||||
The default value of these parameters is 0, and it means 'unlimited'.
|
||||
|
||||
In its most basic usage, the user can add a drive to QEMU with a limit
|
||||
of 100 IOPS with the following -drive line:
|
||||
|
||||
-drive file=hd0.qcow2,throttling.iops-total=100
|
||||
|
||||
We can do the same using QMP. In this case all these parameters are
|
||||
mandatory, so we must set to 0 the ones that we don't want to limit:
|
||||
|
||||
{ "execute": "block_set_io_throttle",
|
||||
"arguments": {
|
||||
"device": "virtio0",
|
||||
"iops": 100,
|
||||
"iops_rd": 0,
|
||||
"iops_wr": 0,
|
||||
"bps": 0,
|
||||
"bps_rd": 0,
|
||||
"bps_wr": 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
I/O bursts
|
||||
----------
|
||||
In addition to the basic limits we have just seen, QEMU allows the
|
||||
user to do bursts of I/O for a configurable amount of time. A burst is
|
||||
an amount of I/O that can exceed the basic limit. Bursts are useful to
|
||||
allow better performance when there are peaks of activity (the OS
|
||||
boots, a service needs to be restarted) while keeping the average
|
||||
limits lower the rest of the time.
|
||||
|
||||
Two parameters control bursts: their length and the maximum amount of
|
||||
I/O they allow. These two can be configured separately for each one of
|
||||
the six basic parameters described in the previous section, but in
|
||||
this section we'll use 'iops-total' as an example.
|
||||
|
||||
The I/O limit during bursts is set using 'iops-total-max', and the
|
||||
maximum length (in seconds) is set with 'iops-total-max-length'. So if
|
||||
we want to configure a drive with a basic limit of 100 IOPS and allow
|
||||
bursts of 2000 IOPS for 60 seconds, we would do it like this (the line
|
||||
is split for clarity):
|
||||
|
||||
-drive file=hd0.qcow2,
|
||||
throttling.iops-total=100,
|
||||
throttling.iops-total-max=2000,
|
||||
throttling.iops-total-max-length=60
|
||||
|
||||
Or, with QMP:
|
||||
|
||||
{ "execute": "block_set_io_throttle",
|
||||
"arguments": {
|
||||
"device": "virtio0",
|
||||
"iops": 100,
|
||||
"iops_rd": 0,
|
||||
"iops_wr": 0,
|
||||
"bps": 0,
|
||||
"bps_rd": 0,
|
||||
"bps_wr": 0,
|
||||
"iops_max": 2000,
|
||||
"iops_max_length": 60,
|
||||
}
|
||||
}
|
||||
|
||||
With this, the user can perform I/O on hd0.qcow2 at a rate of 2000
|
||||
IOPS for 1 minute before it's throttled down to 100 IOPS.
|
||||
|
||||
The user will be able to do bursts again if there's a sufficiently
|
||||
long period of time with unused I/O (see below for details).
|
||||
|
||||
The default value for 'iops-total-max' is 0 and it means that bursts
|
||||
are not allowed. 'iops-total-max-length' can only be set if
|
||||
'iops-total-max' is set as well, and its default value is 1 second.
|
||||
|
||||
Here's the complete list of parameters for configuring bursts:
|
||||
|
||||
|----------------------------------+-----------------------|
|
||||
| -drive | block_set_io_throttle |
|
||||
|----------------------------------+-----------------------|
|
||||
| throttling.iops-total-max | iops_max |
|
||||
| throttling.iops-total-max-length | iops_max_length |
|
||||
| throttling.iops-read-max | iops_rd_max |
|
||||
| throttling.iops-read-max-length | iops_rd_max_length |
|
||||
| throttling.iops-write-max | iops_wr_max |
|
||||
| throttling.iops-write-max-length | iops_wr_max_length |
|
||||
| throttling.bps-total-max | bps_max |
|
||||
| throttling.bps-total-max-length | bps_max_length |
|
||||
| throttling.bps-read-max | bps_rd_max |
|
||||
| throttling.bps-read-max-length | bps_rd_max_length |
|
||||
| throttling.bps-write-max | bps_wr_max |
|
||||
| throttling.bps-write-max-length | bps_wr_max_length |
|
||||
|----------------------------------+-----------------------|
|
||||
|
||||
|
||||
Controlling the size of I/O operations
|
||||
--------------------------------------
|
||||
When applying IOPS limits all I/O operations are treated equally
|
||||
regardless of their size. This means that the user can take advantage
|
||||
of this in order to circumvent the limits and submit one huge I/O
|
||||
request instead of several smaller ones.
|
||||
|
||||
QEMU provides a setting called throttling.iops-size to prevent this
|
||||
from happening. This setting specifies the size (in bytes) of an I/O
|
||||
request for accounting purposes. Larger requests will be counted
|
||||
proportionally to this size.
|
||||
|
||||
For example, if iops-size is set to 4096 then an 8KB request will be
|
||||
counted as two, and a 6KB request will be counted as one and a
|
||||
half. This only applies to requests larger than iops-size: smaller
|
||||
requests will be always counted as one, no matter their size.
|
||||
|
||||
The default value of iops-size is 0 and it means that the size of the
|
||||
requests is never taken into account when applying IOPS limits.
|
||||
|
||||
|
||||
Applying I/O limits to groups of disks
|
||||
--------------------------------------
|
||||
In all the examples so far we have seen how to apply limits to the I/O
|
||||
performed on individual drives, but QEMU allows grouping drives so
|
||||
they all share the same limits.
|
||||
|
||||
The way it works is that each drive with I/O limits is assigned to a
|
||||
group named using the throttling.group parameter. If this parameter is
|
||||
not specified, then the device name (i.e. 'virtio0', 'ide0-hd0') will
|
||||
be used as the group name.
|
||||
|
||||
Limits set using the throttling.* parameters discussed earlier in this
|
||||
document apply to the combined I/O of all members of a group.
|
||||
|
||||
Consider this example:
|
||||
|
||||
-drive file=hd1.qcow2,throttling.iops-total=6000,throttling.group=foo
|
||||
-drive file=hd2.qcow2,throttling.iops-total=6000,throttling.group=foo
|
||||
-drive file=hd3.qcow2,throttling.iops-total=3000,throttling.group=bar
|
||||
-drive file=hd4.qcow2,throttling.iops-total=6000,throttling.group=foo
|
||||
-drive file=hd5.qcow2,throttling.iops-total=3000,throttling.group=bar
|
||||
-drive file=hd6.qcow2,throttling.iops-total=5000
|
||||
|
||||
Here hd1, hd2 and hd4 are all members of a group named 'foo' with a
|
||||
combined IOPS limit of 6000, and hd3 and hd5 are members of 'bar'. hd6
|
||||
is left alone (technically it is part of a 1-member group).
|
||||
|
||||
Limits are applied in a round-robin fashion so if there are concurrent
|
||||
I/O requests on several drives of the same group they will be
|
||||
distributed evenly.
|
||||
|
||||
When I/O limits are applied to an existing drive using the QMP command
|
||||
'block_set_io_throttle', the following things need to be taken into
|
||||
account:
|
||||
|
||||
- I/O limits are shared within the same group, so new values will
|
||||
affect all members and overwrite the previous settings. In other
|
||||
words: if different limits are applied to members of the same
|
||||
group, the last one wins.
|
||||
|
||||
- If 'group' is unset it is assumed to be the current group of that
|
||||
drive. If the drive is not in a group yet, it will be added to a
|
||||
group named after the device name.
|
||||
|
||||
- If 'group' is set then the drive will be moved to that group if
|
||||
it was member of a different one. In this case the limits
|
||||
specified in the parameters will be applied to the new group
|
||||
only.
|
||||
|
||||
- I/O limits can be disabled by setting all of them to 0. In this
|
||||
case the device will be removed from its group and the rest of
|
||||
its members will not be affected. The 'group' parameter is
|
||||
ignored.
|
||||
|
||||
|
||||
The Leaky Bucket algorithm
|
||||
--------------------------
|
||||
I/O limits in QEMU are implemented using the leaky bucket algorithm
|
||||
(specifically the "Leaky bucket as a meter" variant).
|
||||
|
||||
This algorithm uses the analogy of a bucket that leaks water
|
||||
constantly. The water that gets into the bucket represents the I/O
|
||||
that has been performed, and no more I/O is allowed once the bucket is
|
||||
full.
|
||||
|
||||
To see the way this corresponds to the throttling parameters in QEMU,
|
||||
consider the following values:
|
||||
|
||||
iops-total=100
|
||||
iops-total-max=2000
|
||||
iops-total-max-length=60
|
||||
|
||||
- Water leaks from the bucket at a rate of 100 IOPS.
|
||||
- Water can be added to the bucket at a rate of 2000 IOPS.
|
||||
- The size of the bucket is 2000 x 60 = 120000
|
||||
- If 'iops-total-max-length' is unset then the bucket size is 100.
|
||||
|
||||
The bucket is initially empty, therefore water can be added until it's
|
||||
full at a rate of 2000 IOPS (the burst rate). Once the bucket is full
|
||||
we can only add as much water as it leaks, therefore the I/O rate is
|
||||
reduced to 100 IOPS. If we add less water than it leaks then the
|
||||
bucket will start to empty, allowing for bursts again.
|
||||
|
||||
Note that since water is leaking from the bucket even during bursts,
|
||||
it will take a bit more than 60 seconds at 2000 IOPS to fill it
|
||||
up. After those 60 seconds the bucket will have leaked 60 x 100 =
|
||||
6000, allowing for 3 more seconds of I/O at 2000 IOPS.
|
||||
|
||||
Also, due to the way the algorithm works, longer burst can be done at
|
||||
a lower I/O rate, e.g. 1000 IOPS during 120 seconds.
|
215
dump.c
215
dump.c
@@ -25,6 +25,7 @@
|
||||
#include "sysemu/cpus.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qapi-event.h"
|
||||
|
||||
#include <zlib.h>
|
||||
#ifdef CONFIG_LZO
|
||||
@@ -82,12 +83,6 @@ static int dump_cleanup(DumpState *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_error(DumpState *s, const char *reason, Error **errp)
|
||||
{
|
||||
dump_cleanup(s);
|
||||
error_setg(errp, "%s", reason);
|
||||
}
|
||||
|
||||
static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
|
||||
{
|
||||
DumpState *s = opaque;
|
||||
@@ -128,7 +123,7 @@ static void write_elf64_header(DumpState *s, Error **errp)
|
||||
|
||||
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write elf header", errp);
|
||||
error_setg(errp, "dump: failed to write elf header");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +154,7 @@ static void write_elf32_header(DumpState *s, Error **errp)
|
||||
|
||||
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write elf header", errp);
|
||||
error_setg(errp, "dump: failed to write elf header");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +177,7 @@ static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||
|
||||
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write program header table", errp);
|
||||
error_setg(errp, "dump: failed to write program header table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +200,7 @@ static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||
|
||||
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write program header table", errp);
|
||||
error_setg(errp, "dump: failed to write program header table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +220,7 @@ static void write_elf64_note(DumpState *s, Error **errp)
|
||||
|
||||
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write program header table", errp);
|
||||
error_setg(errp, "dump: failed to write program header table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +240,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
|
||||
id = cpu_index(cpu);
|
||||
ret = cpu_write_elf64_note(f, cpu, id, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write elf notes", errp);
|
||||
error_setg(errp, "dump: failed to write elf notes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -253,7 +248,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
|
||||
CPU_FOREACH(cpu) {
|
||||
ret = cpu_write_elf64_qemunote(f, cpu, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write CPU status", errp);
|
||||
error_setg(errp, "dump: failed to write CPU status");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -275,7 +270,7 @@ static void write_elf32_note(DumpState *s, Error **errp)
|
||||
|
||||
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write program header table", errp);
|
||||
error_setg(errp, "dump: failed to write program header table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +285,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
|
||||
id = cpu_index(cpu);
|
||||
ret = cpu_write_elf32_note(f, cpu, id, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write elf notes", errp);
|
||||
error_setg(errp, "dump: failed to write elf notes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -298,7 +293,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
|
||||
CPU_FOREACH(cpu) {
|
||||
ret = cpu_write_elf32_qemunote(f, cpu, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write CPU status", errp);
|
||||
error_setg(errp, "dump: failed to write CPU status");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -326,7 +321,7 @@ static void write_elf_section(DumpState *s, int type, Error **errp)
|
||||
|
||||
ret = fd_write_vmcore(&shdr, shdr_size, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write section header table", errp);
|
||||
error_setg(errp, "dump: failed to write section header table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +331,9 @@ static void write_data(DumpState *s, void *buf, int length, Error **errp)
|
||||
|
||||
ret = fd_write_vmcore(buf, length, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to save memory", errp);
|
||||
error_setg(errp, "dump: failed to save memory");
|
||||
} else {
|
||||
s->written_size += length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,11 +565,6 @@ static void dump_begin(DumpState *s, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_completed(DumpState *s)
|
||||
{
|
||||
dump_cleanup(s);
|
||||
}
|
||||
|
||||
static int get_next_block(DumpState *s, GuestPhysBlock *block)
|
||||
{
|
||||
while (1) {
|
||||
@@ -624,8 +616,6 @@ static void dump_iterate(DumpState *s, Error **errp)
|
||||
}
|
||||
|
||||
} while (!get_next_block(s, block));
|
||||
|
||||
dump_completed(s);
|
||||
}
|
||||
|
||||
static void create_vmcore(DumpState *s, Error **errp)
|
||||
@@ -765,7 +755,7 @@ static void create_header32(DumpState *s, Error **errp)
|
||||
dh->status = cpu_to_dump32(s, status);
|
||||
|
||||
if (write_buffer(s->fd, 0, dh, size) < 0) {
|
||||
dump_error(s, "dump: failed to write disk dump header", errp);
|
||||
error_setg(errp, "dump: failed to write disk dump header");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -784,7 +774,7 @@ static void create_header32(DumpState *s, Error **errp)
|
||||
|
||||
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
|
||||
block_size, kh, size) < 0) {
|
||||
dump_error(s, "dump: failed to write kdump sub header", errp);
|
||||
error_setg(errp, "dump: failed to write kdump sub header");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -800,7 +790,7 @@ static void create_header32(DumpState *s, Error **errp)
|
||||
}
|
||||
if (write_buffer(s->fd, offset_note, s->note_buf,
|
||||
s->note_size) < 0) {
|
||||
dump_error(s, "dump: failed to write notes", errp);
|
||||
error_setg(errp, "dump: failed to write notes");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -865,7 +855,7 @@ static void create_header64(DumpState *s, Error **errp)
|
||||
dh->status = cpu_to_dump32(s, status);
|
||||
|
||||
if (write_buffer(s->fd, 0, dh, size) < 0) {
|
||||
dump_error(s, "dump: failed to write disk dump header", errp);
|
||||
error_setg(errp, "dump: failed to write disk dump header");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -884,7 +874,7 @@ static void create_header64(DumpState *s, Error **errp)
|
||||
|
||||
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
|
||||
block_size, kh, size) < 0) {
|
||||
dump_error(s, "dump: failed to write kdump sub header", errp);
|
||||
error_setg(errp, "dump: failed to write kdump sub header");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -901,7 +891,7 @@ static void create_header64(DumpState *s, Error **errp)
|
||||
|
||||
if (write_buffer(s->fd, offset_note, s->note_buf,
|
||||
s->note_size) < 0) {
|
||||
dump_error(s, "dump: failed to write notes", errp);
|
||||
error_setg(errp, "dump: failed to write notes");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1087,7 +1077,7 @@ static void write_dump_bitmap(DumpState *s, Error **errp)
|
||||
while (get_next_page(&block_iter, &pfn, NULL, s)) {
|
||||
ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to set dump_bitmap", errp);
|
||||
error_setg(errp, "dump: failed to set dump_bitmap");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1104,7 +1094,7 @@ static void write_dump_bitmap(DumpState *s, Error **errp)
|
||||
ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false,
|
||||
dump_bitmap_buf, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to sync dump_bitmap", errp);
|
||||
error_setg(errp, "dump: failed to sync dump_bitmap");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1237,7 +1227,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
||||
ret = write_cache(&page_data, buf, s->dump_info.page_size, false);
|
||||
g_free(buf);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data (zero page)", errp);
|
||||
error_setg(errp, "dump: failed to write page data (zero page)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1253,7 +1243,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
||||
ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
|
||||
false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page desc", errp);
|
||||
error_setg(errp, "dump: failed to write page desc");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
@@ -1278,7 +1268,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
||||
|
||||
ret = write_cache(&page_data, buf_out, size_out, false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data", errp);
|
||||
error_setg(errp, "dump: failed to write page data");
|
||||
goto out;
|
||||
}
|
||||
#ifdef CONFIG_LZO
|
||||
@@ -1291,7 +1281,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
||||
|
||||
ret = write_cache(&page_data, buf_out, size_out, false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data", errp);
|
||||
error_setg(errp, "dump: failed to write page data");
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
@@ -1305,7 +1295,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
||||
|
||||
ret = write_cache(&page_data, buf_out, size_out, false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data", errp);
|
||||
error_setg(errp, "dump: failed to write page data");
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
@@ -1321,7 +1311,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
||||
ret = write_cache(&page_data, buf,
|
||||
s->dump_info.page_size, false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data", errp);
|
||||
error_setg(errp, "dump: failed to write page data");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1333,20 +1323,21 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
||||
|
||||
ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page desc", errp);
|
||||
error_setg(errp, "dump: failed to write page desc");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
s->written_size += s->dump_info.page_size;
|
||||
}
|
||||
|
||||
ret = write_cache(&page_desc, NULL, 0, true);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to sync cache for page_desc", errp);
|
||||
error_setg(errp, "dump: failed to sync cache for page_desc");
|
||||
goto out;
|
||||
}
|
||||
ret = write_cache(&page_data, NULL, 0, true);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to sync cache for page_data", errp);
|
||||
error_setg(errp, "dump: failed to sync cache for page_data");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1390,7 +1381,7 @@ static void create_kdump_vmcore(DumpState *s, Error **errp)
|
||||
|
||||
ret = write_start_flat_header(s->fd);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write start flat header", errp);
|
||||
error_setg(errp, "dump: failed to write start flat header");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1414,11 +1405,9 @@ static void create_kdump_vmcore(DumpState *s, Error **errp)
|
||||
|
||||
ret = write_end_flat_header(s->fd);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write end flat header", errp);
|
||||
error_setg(errp, "dump: failed to write end flat header");
|
||||
return;
|
||||
}
|
||||
|
||||
dump_completed(s);
|
||||
}
|
||||
|
||||
static ram_addr_t get_start_block(DumpState *s)
|
||||
@@ -1457,6 +1446,44 @@ static void get_max_mapnr(DumpState *s)
|
||||
s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end);
|
||||
}
|
||||
|
||||
static DumpState dump_state_global = { .status = DUMP_STATUS_NONE };
|
||||
|
||||
static void dump_state_prepare(DumpState *s)
|
||||
{
|
||||
/* zero the struct, setting status to active */
|
||||
*s = (DumpState) { .status = DUMP_STATUS_ACTIVE };
|
||||
}
|
||||
|
||||
bool dump_in_progress(void)
|
||||
{
|
||||
DumpState *state = &dump_state_global;
|
||||
return (atomic_read(&state->status) == DUMP_STATUS_ACTIVE);
|
||||
}
|
||||
|
||||
/* calculate total size of memory to be dumped (taking filter into
|
||||
* acoount.) */
|
||||
static int64_t dump_calculate_size(DumpState *s)
|
||||
{
|
||||
GuestPhysBlock *block;
|
||||
int64_t size = 0, total = 0, left = 0, right = 0;
|
||||
|
||||
QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
|
||||
if (s->has_filter) {
|
||||
/* calculate the overlapped region. */
|
||||
left = MAX(s->begin, block->target_start);
|
||||
right = MIN(s->begin + s->length, block->target_end);
|
||||
size = right - left;
|
||||
size = size > 0 ? size : 0;
|
||||
} else {
|
||||
/* count the whole region in */
|
||||
size = (block->target_end - block->target_start);
|
||||
}
|
||||
total += size;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static void dump_init(DumpState *s, int fd, bool has_format,
|
||||
DumpGuestMemoryFormat format, bool paging, bool has_filter,
|
||||
int64_t begin, int64_t length, Error **errp)
|
||||
@@ -1466,6 +1493,10 @@ static void dump_init(DumpState *s, int fd, bool has_format,
|
||||
Error *err = NULL;
|
||||
int ret;
|
||||
|
||||
s->has_format = has_format;
|
||||
s->format = format;
|
||||
s->written_size = 0;
|
||||
|
||||
/* kdump-compressed is conflict with paging and filter */
|
||||
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
|
||||
assert(!paging && !has_filter);
|
||||
@@ -1496,6 +1527,10 @@ static void dump_init(DumpState *s, int fd, bool has_format,
|
||||
|
||||
guest_phys_blocks_init(&s->guest_phys_blocks);
|
||||
guest_phys_blocks_append(&s->guest_phys_blocks);
|
||||
s->total_size = dump_calculate_size(s);
|
||||
#ifdef DEBUG_DUMP_GUEST_MEMORY
|
||||
fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size);
|
||||
#endif
|
||||
|
||||
s->start = get_start_block(s);
|
||||
if (s->start == -1) {
|
||||
@@ -1624,8 +1659,60 @@ cleanup:
|
||||
dump_cleanup(s);
|
||||
}
|
||||
|
||||
void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
|
||||
int64_t begin, bool has_length,
|
||||
/* this operation might be time consuming. */
|
||||
static void dump_process(DumpState *s, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
DumpQueryResult *result = NULL;
|
||||
|
||||
if (s->has_format && s->format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
|
||||
create_kdump_vmcore(s, &local_err);
|
||||
} else {
|
||||
create_vmcore(s, &local_err);
|
||||
}
|
||||
|
||||
/* make sure status is written after written_size updates */
|
||||
smp_wmb();
|
||||
atomic_set(&s->status,
|
||||
(local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED));
|
||||
|
||||
/* send DUMP_COMPLETED message (unconditionally) */
|
||||
result = qmp_query_dump(NULL);
|
||||
/* should never fail */
|
||||
assert(result);
|
||||
qapi_event_send_dump_completed(result, !!local_err, (local_err ? \
|
||||
error_get_pretty(local_err) : NULL),
|
||||
&error_abort);
|
||||
qapi_free_DumpQueryResult(result);
|
||||
|
||||
error_propagate(errp, local_err);
|
||||
dump_cleanup(s);
|
||||
}
|
||||
|
||||
static void *dump_thread(void *data)
|
||||
{
|
||||
Error *err = NULL;
|
||||
DumpState *s = (DumpState *)data;
|
||||
dump_process(s, &err);
|
||||
error_free(err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DumpQueryResult *qmp_query_dump(Error **errp)
|
||||
{
|
||||
DumpQueryResult *result = g_new(DumpQueryResult, 1);
|
||||
DumpState *state = &dump_state_global;
|
||||
result->status = atomic_read(&state->status);
|
||||
/* make sure we are reading status and written_size in order */
|
||||
smp_rmb();
|
||||
result->completed = state->written_size;
|
||||
result->total = state->total_size;
|
||||
return result;
|
||||
}
|
||||
|
||||
void qmp_dump_guest_memory(bool paging, const char *file,
|
||||
bool has_detach, bool detach,
|
||||
bool has_begin, int64_t begin, bool has_length,
|
||||
int64_t length, bool has_format,
|
||||
DumpGuestMemoryFormat format, Error **errp)
|
||||
{
|
||||
@@ -1633,6 +1720,19 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
|
||||
int fd = -1;
|
||||
DumpState *s;
|
||||
Error *local_err = NULL;
|
||||
bool detach_p = false;
|
||||
|
||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||
error_setg(errp, "Dump not allowed during incoming migration.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* if there is a dump in background, we should wait until the dump
|
||||
* finished */
|
||||
if (dump_in_progress()) {
|
||||
error_setg(errp, "There is a dump in process, please wait.");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* kdump-compressed format need the whole memory dumped, so paging or
|
||||
@@ -1652,6 +1752,9 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
|
||||
error_setg(errp, QERR_MISSING_PARAMETER, "begin");
|
||||
return;
|
||||
}
|
||||
if (has_detach) {
|
||||
detach_p = detach;
|
||||
}
|
||||
|
||||
/* check whether lzo/snappy is supported */
|
||||
#ifndef CONFIG_LZO
|
||||
@@ -1690,23 +1793,25 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
|
||||
return;
|
||||
}
|
||||
|
||||
s = g_malloc0(sizeof(DumpState));
|
||||
s = &dump_state_global;
|
||||
dump_state_prepare(s);
|
||||
|
||||
dump_init(s, fd, has_format, format, paging, has_begin,
|
||||
begin, length, &local_err);
|
||||
if (local_err) {
|
||||
g_free(s);
|
||||
error_propagate(errp, local_err);
|
||||
atomic_set(&s->status, DUMP_STATUS_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
|
||||
create_kdump_vmcore(s, errp);
|
||||
if (detach_p) {
|
||||
/* detached dump */
|
||||
qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread,
|
||||
s, QEMU_THREAD_DETACHED);
|
||||
} else {
|
||||
create_vmcore(s, errp);
|
||||
/* sync dump */
|
||||
dump_process(s, errp);
|
||||
}
|
||||
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp)
|
||||
|
48
exec.c
48
exec.c
@@ -1717,6 +1717,8 @@ ram_addr_t qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
|
||||
error_propagate(errp, local_err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mr->ram_block = new_block;
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -1866,9 +1868,13 @@ void *qemu_get_ram_block_host_ptr(ram_addr_t addr)
|
||||
*
|
||||
* Called within RCU critical section.
|
||||
*/
|
||||
void *qemu_get_ram_ptr(ram_addr_t addr)
|
||||
void *qemu_get_ram_ptr(RAMBlock *ram_block, ram_addr_t addr)
|
||||
{
|
||||
RAMBlock *block = qemu_get_ram_block(addr);
|
||||
RAMBlock *block = ram_block;
|
||||
|
||||
if (block == NULL) {
|
||||
block = qemu_get_ram_block(addr);
|
||||
}
|
||||
|
||||
if (xen_enabled() && block->host == NULL) {
|
||||
/* We need to check if the requested address is in the RAM
|
||||
@@ -1889,15 +1895,18 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
|
||||
*
|
||||
* Called within RCU critical section.
|
||||
*/
|
||||
static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size)
|
||||
static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,
|
||||
hwaddr *size)
|
||||
{
|
||||
RAMBlock *block;
|
||||
RAMBlock *block = ram_block;
|
||||
ram_addr_t offset_inside_block;
|
||||
if (*size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block = qemu_get_ram_block(addr);
|
||||
if (block == NULL) {
|
||||
block = qemu_get_ram_block(addr);
|
||||
}
|
||||
offset_inside_block = addr - block->offset;
|
||||
*size = MIN(*size, block->max_length - offset_inside_block);
|
||||
|
||||
@@ -2025,13 +2034,13 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
stb_p(qemu_get_ram_ptr(ram_addr), val);
|
||||
stb_p(qemu_get_ram_ptr(NULL, ram_addr), val);
|
||||
break;
|
||||
case 2:
|
||||
stw_p(qemu_get_ram_ptr(ram_addr), val);
|
||||
stw_p(qemu_get_ram_ptr(NULL, ram_addr), val);
|
||||
break;
|
||||
case 4:
|
||||
stl_p(qemu_get_ram_ptr(ram_addr), val);
|
||||
stl_p(qemu_get_ram_ptr(NULL, ram_addr), val);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@@ -2607,7 +2616,7 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
|
||||
} else {
|
||||
addr1 += memory_region_get_ram_addr(mr);
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
|
||||
memcpy(ptr, buf, l);
|
||||
invalidate_and_set_dirty(mr, addr1, l);
|
||||
}
|
||||
@@ -2698,7 +2707,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
|
||||
}
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(mr->ram_addr + addr1);
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block, mr->ram_addr + addr1);
|
||||
memcpy(buf, ptr, l);
|
||||
}
|
||||
|
||||
@@ -2783,7 +2792,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
|
||||
} else {
|
||||
addr1 += memory_region_get_ram_addr(mr);
|
||||
/* ROM/RAM case */
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
|
||||
switch (type) {
|
||||
case WRITE_DATA:
|
||||
memcpy(ptr, buf, l);
|
||||
@@ -2995,7 +3004,7 @@ void *address_space_map(AddressSpace *as,
|
||||
|
||||
memory_region_ref(mr);
|
||||
*plen = done;
|
||||
ptr = qemu_ram_ptr_length(raddr + base, plen);
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, raddr + base, plen);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ptr;
|
||||
@@ -3079,7 +3088,8 @@ static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr)
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block,
|
||||
(memory_region_get_ram_addr(mr)
|
||||
& TARGET_PAGE_MASK)
|
||||
+ addr1);
|
||||
switch (endian) {
|
||||
@@ -3174,7 +3184,8 @@ static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr)
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block,
|
||||
(memory_region_get_ram_addr(mr)
|
||||
& TARGET_PAGE_MASK)
|
||||
+ addr1);
|
||||
switch (endian) {
|
||||
@@ -3289,7 +3300,8 @@ static inline uint32_t address_space_lduw_internal(AddressSpace *as,
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr)
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block,
|
||||
(memory_region_get_ram_addr(mr)
|
||||
& TARGET_PAGE_MASK)
|
||||
+ addr1);
|
||||
switch (endian) {
|
||||
@@ -3374,7 +3386,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
|
||||
} else {
|
||||
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
|
||||
stl_p(ptr, val);
|
||||
|
||||
dirty_log_mask = memory_region_get_dirty_log_mask(mr);
|
||||
@@ -3429,7 +3441,7 @@ static inline void address_space_stl_internal(AddressSpace *as,
|
||||
} else {
|
||||
/* RAM case */
|
||||
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
stl_le_p(ptr, val);
|
||||
@@ -3539,7 +3551,7 @@ static inline void address_space_stw_internal(AddressSpace *as,
|
||||
} else {
|
||||
/* RAM case */
|
||||
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
stw_le_p(ptr, val);
|
||||
|
@@ -99,7 +99,7 @@ this code that are retained.
|
||||
| The result is stored in the location pointed to by `zPtr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t *zPtr)
|
||||
static inline void shift32RightJamming(uint32_t a, int count, uint32_t *zPtr)
|
||||
{
|
||||
uint32_t z;
|
||||
|
||||
@@ -125,7 +125,7 @@ static inline void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t
|
||||
| The result is stored in the location pointed to by `zPtr'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t *zPtr)
|
||||
static inline void shift64RightJamming(uint64_t a, int count, uint64_t *zPtr)
|
||||
{
|
||||
uint64_t z;
|
||||
|
||||
@@ -161,7 +161,7 @@ static inline void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t
|
||||
|
||||
static inline void
|
||||
shift64ExtraRightJamming(
|
||||
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
{
|
||||
uint64_t z0, z1;
|
||||
int8_t negCount = ( - count ) & 63;
|
||||
@@ -198,7 +198,7 @@ static inline void
|
||||
|
||||
static inline void
|
||||
shift128Right(
|
||||
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
{
|
||||
uint64_t z0, z1;
|
||||
int8_t negCount = ( - count ) & 63;
|
||||
@@ -233,7 +233,7 @@ static inline void
|
||||
|
||||
static inline void
|
||||
shift128RightJamming(
|
||||
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
{
|
||||
uint64_t z0, z1;
|
||||
int8_t negCount = ( - count ) & 63;
|
||||
@@ -287,7 +287,7 @@ static inline void
|
||||
uint64_t a0,
|
||||
uint64_t a1,
|
||||
uint64_t a2,
|
||||
int_fast16_t count,
|
||||
int count,
|
||||
uint64_t *z0Ptr,
|
||||
uint64_t *z1Ptr,
|
||||
uint64_t *z2Ptr
|
||||
@@ -342,7 +342,7 @@ static inline void
|
||||
|
||||
static inline void
|
||||
shortShift128Left(
|
||||
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr)
|
||||
{
|
||||
|
||||
*z1Ptr = a1<<count;
|
||||
@@ -364,7 +364,7 @@ static inline void
|
||||
uint64_t a0,
|
||||
uint64_t a1,
|
||||
uint64_t a2,
|
||||
int_fast16_t count,
|
||||
int count,
|
||||
uint64_t *z0Ptr,
|
||||
uint64_t *z1Ptr,
|
||||
uint64_t *z2Ptr
|
||||
@@ -635,7 +635,7 @@ static uint64_t estimateDiv128To64( uint64_t a0, uint64_t a1, uint64_t b )
|
||||
| value.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static uint32_t estimateSqrt32(int_fast16_t aExp, uint32_t a)
|
||||
static uint32_t estimateSqrt32(int aExp, uint32_t a)
|
||||
{
|
||||
static const uint16_t sqrtOddAdjustments[] = {
|
||||
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
|
||||
|
162
fpu/softfloat.c
162
fpu/softfloat.c
@@ -118,7 +118,7 @@ static inline uint32_t extractFloat16Frac(float16 a)
|
||||
| Returns the exponent bits of the half-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline int_fast16_t extractFloat16Exp(float16 a)
|
||||
static inline int extractFloat16Exp(float16 a)
|
||||
{
|
||||
return (float16_val(a) >> 10) & 0x1f;
|
||||
}
|
||||
@@ -314,7 +314,7 @@ static inline uint32_t extractFloat32Frac( float32 a )
|
||||
| Returns the exponent bits of the single-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline int_fast16_t extractFloat32Exp(float32 a)
|
||||
static inline int extractFloat32Exp(float32 a)
|
||||
{
|
||||
|
||||
return ( float32_val(a)>>23 ) & 0xFF;
|
||||
@@ -355,7 +355,7 @@ float32 float32_squash_input_denormal(float32 a, float_status *status)
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
normalizeFloat32Subnormal(uint32_t aSig, int_fast16_t *zExpPtr, uint32_t *zSigPtr)
|
||||
normalizeFloat32Subnormal(uint32_t aSig, int *zExpPtr, uint32_t *zSigPtr)
|
||||
{
|
||||
int8_t shiftCount;
|
||||
|
||||
@@ -376,7 +376,7 @@ static void
|
||||
| significand.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline float32 packFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig)
|
||||
static inline float32 packFloat32(flag zSign, int zExp, uint32_t zSig)
|
||||
{
|
||||
|
||||
return make_float32(
|
||||
@@ -406,7 +406,7 @@ static inline float32 packFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig)
|
||||
| Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float32 roundAndPackFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig,
|
||||
static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
|
||||
float_status *status)
|
||||
{
|
||||
int8_t roundingMode;
|
||||
@@ -481,7 +481,7 @@ static float32 roundAndPackFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig,
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float32
|
||||
normalizeRoundAndPackFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig,
|
||||
normalizeRoundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
|
||||
float_status *status)
|
||||
{
|
||||
int8_t shiftCount;
|
||||
@@ -507,7 +507,7 @@ static inline uint64_t extractFloat64Frac( float64 a )
|
||||
| Returns the exponent bits of the double-precision floating-point value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline int_fast16_t extractFloat64Exp(float64 a)
|
||||
static inline int extractFloat64Exp(float64 a)
|
||||
{
|
||||
|
||||
return ( float64_val(a)>>52 ) & 0x7FF;
|
||||
@@ -548,7 +548,7 @@ float64 float64_squash_input_denormal(float64 a, float_status *status)
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
normalizeFloat64Subnormal(uint64_t aSig, int_fast16_t *zExpPtr, uint64_t *zSigPtr)
|
||||
normalizeFloat64Subnormal(uint64_t aSig, int *zExpPtr, uint64_t *zSigPtr)
|
||||
{
|
||||
int8_t shiftCount;
|
||||
|
||||
@@ -569,7 +569,7 @@ static void
|
||||
| significand.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline float64 packFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig)
|
||||
static inline float64 packFloat64(flag zSign, int zExp, uint64_t zSig)
|
||||
{
|
||||
|
||||
return make_float64(
|
||||
@@ -599,12 +599,12 @@ static inline float64 packFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig)
|
||||
| Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float64 roundAndPackFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig,
|
||||
static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig,
|
||||
float_status *status)
|
||||
{
|
||||
int8_t roundingMode;
|
||||
flag roundNearestEven;
|
||||
int_fast16_t roundIncrement, roundBits;
|
||||
int roundIncrement, roundBits;
|
||||
flag isTiny;
|
||||
|
||||
roundingMode = status->float_rounding_mode;
|
||||
@@ -673,7 +673,7 @@ static float64 roundAndPackFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig,
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float64
|
||||
normalizeRoundAndPackFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig,
|
||||
normalizeRoundAndPackFloat64(flag zSign, int zExp, uint64_t zSig,
|
||||
float_status *status)
|
||||
{
|
||||
int8_t shiftCount;
|
||||
@@ -1543,7 +1543,8 @@ float128 uint64_to_float128(uint64_t a, float_status *status)
|
||||
int32_t float32_to_int32(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint32_t aSig;
|
||||
uint64_t aSig64;
|
||||
|
||||
@@ -1574,7 +1575,8 @@ int32_t float32_to_int32(float32 a, float_status *status)
|
||||
int32_t float32_to_int32_round_to_zero(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint32_t aSig;
|
||||
int32_t z;
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
@@ -1616,10 +1618,11 @@ int32_t float32_to_int32_round_to_zero(float32 a, float_status *status)
|
||||
| returned.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int_fast16_t float32_to_int16_round_to_zero(float32 a, float_status *status)
|
||||
int16_t float32_to_int16_round_to_zero(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint32_t aSig;
|
||||
int32_t z;
|
||||
|
||||
@@ -1668,7 +1671,8 @@ int_fast16_t float32_to_int16_round_to_zero(float32 a, float_status *status)
|
||||
int64_t float32_to_int64(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint32_t aSig;
|
||||
uint64_t aSig64, aSigExtra;
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
@@ -1707,7 +1711,8 @@ int64_t float32_to_int64(float32 a, float_status *status)
|
||||
uint64_t float32_to_uint64(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint32_t aSig;
|
||||
uint64_t aSig64, aSigExtra;
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
@@ -1771,7 +1776,8 @@ uint64_t float32_to_uint64_round_to_zero(float32 a, float_status *status)
|
||||
int64_t float32_to_int64_round_to_zero(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint32_t aSig;
|
||||
uint64_t aSig64;
|
||||
int64_t z;
|
||||
@@ -1817,7 +1823,7 @@ int64_t float32_to_int64_round_to_zero(float32 a, float_status *status)
|
||||
float64 float32_to_float64(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint32_t aSig;
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
|
||||
@@ -1849,7 +1855,7 @@ float64 float32_to_float64(float32 a, float_status *status)
|
||||
floatx80 float32_to_floatx80(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint32_t aSig;
|
||||
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
@@ -1881,7 +1887,7 @@ floatx80 float32_to_floatx80(float32 a, float_status *status)
|
||||
float128 float32_to_float128(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint32_t aSig;
|
||||
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
@@ -1913,7 +1919,7 @@ float128 float32_to_float128(float32 a, float_status *status)
|
||||
float32 float32_round_to_int(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint32_t lastBitMask, roundBitsMask;
|
||||
uint32_t z;
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
@@ -1995,9 +2001,9 @@ float32 float32_round_to_int(float32 a, float_status *status)
|
||||
static float32 addFloat32Sigs(float32 a, float32 b, flag zSign,
|
||||
float_status *status)
|
||||
{
|
||||
int_fast16_t aExp, bExp, zExp;
|
||||
int aExp, bExp, zExp;
|
||||
uint32_t aSig, bSig, zSig;
|
||||
int_fast16_t expDiff;
|
||||
int expDiff;
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@@ -2081,9 +2087,9 @@ static float32 addFloat32Sigs(float32 a, float32 b, flag zSign,
|
||||
static float32 subFloat32Sigs(float32 a, float32 b, flag zSign,
|
||||
float_status *status)
|
||||
{
|
||||
int_fast16_t aExp, bExp, zExp;
|
||||
int aExp, bExp, zExp;
|
||||
uint32_t aSig, bSig, zSig;
|
||||
int_fast16_t expDiff;
|
||||
int expDiff;
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@@ -2207,7 +2213,7 @@ float32 float32_sub(float32 a, float32 b, float_status *status)
|
||||
float32 float32_mul(float32 a, float32 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign, zSign;
|
||||
int_fast16_t aExp, bExp, zExp;
|
||||
int aExp, bExp, zExp;
|
||||
uint32_t aSig, bSig;
|
||||
uint64_t zSig64;
|
||||
uint32_t zSig;
|
||||
@@ -2272,7 +2278,7 @@ float32 float32_mul(float32 a, float32 b, float_status *status)
|
||||
float32 float32_div(float32 a, float32 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign, zSign;
|
||||
int_fast16_t aExp, bExp, zExp;
|
||||
int aExp, bExp, zExp;
|
||||
uint32_t aSig, bSig, zSig;
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
b = float32_squash_input_denormal(b, status);
|
||||
@@ -2342,7 +2348,7 @@ float32 float32_div(float32 a, float32 b, float_status *status)
|
||||
float32 float32_rem(float32 a, float32 b, float_status *status)
|
||||
{
|
||||
flag aSign, zSign;
|
||||
int_fast16_t aExp, bExp, expDiff;
|
||||
int aExp, bExp, expDiff;
|
||||
uint32_t aSig, bSig;
|
||||
uint32_t q;
|
||||
uint64_t aSig64, bSig64, q64;
|
||||
@@ -2450,7 +2456,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags,
|
||||
float_status *status)
|
||||
{
|
||||
flag aSign, bSign, cSign, zSign;
|
||||
int_fast16_t aExp, bExp, cExp, pExp, zExp, expDiff;
|
||||
int aExp, bExp, cExp, pExp, zExp, expDiff;
|
||||
uint32_t aSig, bSig, cSig;
|
||||
flag pInf, pZero, pSign;
|
||||
uint64_t pSig64, cSig64, zSig64;
|
||||
@@ -2670,7 +2676,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags,
|
||||
float32 float32_sqrt(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, zExp;
|
||||
int aExp, zExp;
|
||||
uint32_t aSig, zSig;
|
||||
uint64_t rem, term;
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
@@ -2758,7 +2764,7 @@ static const float64 float32_exp2_coefficients[15] =
|
||||
float32 float32_exp2(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint32_t aSig;
|
||||
float64 r, x, xn;
|
||||
int i;
|
||||
@@ -2808,7 +2814,7 @@ float32 float32_exp2(float32 a, float_status *status)
|
||||
float32 float32_log2(float32 a, float_status *status)
|
||||
{
|
||||
flag aSign, zSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint32_t aSig, zSig, i;
|
||||
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
@@ -3075,7 +3081,8 @@ int float32_unordered_quiet(float32 a, float32 b, float_status *status)
|
||||
int32_t float64_to_int32(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint64_t aSig;
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
|
||||
@@ -3103,7 +3110,8 @@ int32_t float64_to_int32(float64 a, float_status *status)
|
||||
int32_t float64_to_int32_round_to_zero(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint64_t aSig, savedASig;
|
||||
int32_t z;
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
@@ -3149,10 +3157,11 @@ int32_t float64_to_int32_round_to_zero(float64 a, float_status *status)
|
||||
| returned.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int_fast16_t float64_to_int16_round_to_zero(float64 a, float_status *status)
|
||||
int16_t float64_to_int16_round_to_zero(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint64_t aSig, savedASig;
|
||||
int32_t z;
|
||||
|
||||
@@ -3203,7 +3212,8 @@ int_fast16_t float64_to_int16_round_to_zero(float64 a, float_status *status)
|
||||
int64_t float64_to_int64(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint64_t aSig, aSigExtra;
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
|
||||
@@ -3246,7 +3256,8 @@ int64_t float64_to_int64(float64 a, float_status *status)
|
||||
int64_t float64_to_int64_round_to_zero(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint64_t aSig;
|
||||
int64_t z;
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
@@ -3298,7 +3309,7 @@ int64_t float64_to_int64_round_to_zero(float64 a, float_status *status)
|
||||
float32 float64_to_float32(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint64_t aSig;
|
||||
uint32_t zSig;
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
@@ -3333,7 +3344,7 @@ float32 float64_to_float32(float64 a, float_status *status)
|
||||
| than the desired result exponent whenever `zSig' is a complete, normalized
|
||||
| significand.
|
||||
*----------------------------------------------------------------------------*/
|
||||
static float16 packFloat16(flag zSign, int_fast16_t zExp, uint16_t zSig)
|
||||
static float16 packFloat16(flag zSign, int zExp, uint16_t zSig)
|
||||
{
|
||||
return make_float16(
|
||||
(((uint32_t)zSign) << 15) + (((uint32_t)zExp) << 10) + zSig);
|
||||
@@ -3367,7 +3378,7 @@ static float16 packFloat16(flag zSign, int_fast16_t zExp, uint16_t zSig)
|
||||
| Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float16 roundAndPackFloat16(flag zSign, int_fast16_t zExp,
|
||||
static float16 roundAndPackFloat16(flag zSign, int zExp,
|
||||
uint32_t zSig, flag ieee,
|
||||
float_status *status)
|
||||
{
|
||||
@@ -3454,7 +3465,7 @@ static float16 roundAndPackFloat16(flag zSign, int_fast16_t zExp,
|
||||
return packFloat16(zSign, zExp, zSig >> 13);
|
||||
}
|
||||
|
||||
static void normalizeFloat16Subnormal(uint32_t aSig, int_fast16_t *zExpPtr,
|
||||
static void normalizeFloat16Subnormal(uint32_t aSig, int *zExpPtr,
|
||||
uint32_t *zSigPtr)
|
||||
{
|
||||
int8_t shiftCount = countLeadingZeros32(aSig) - 21;
|
||||
@@ -3468,7 +3479,7 @@ static void normalizeFloat16Subnormal(uint32_t aSig, int_fast16_t *zExpPtr,
|
||||
float32 float16_to_float32(float16 a, flag ieee, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint32_t aSig;
|
||||
|
||||
aSign = extractFloat16Sign(a);
|
||||
@@ -3495,7 +3506,7 @@ float32 float16_to_float32(float16 a, flag ieee, float_status *status)
|
||||
float16 float32_to_float16(float32 a, flag ieee, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint32_t aSig;
|
||||
|
||||
a = float32_squash_input_denormal(a, status);
|
||||
@@ -3539,7 +3550,7 @@ float16 float32_to_float16(float32 a, flag ieee, float_status *status)
|
||||
float64 float16_to_float64(float16 a, flag ieee, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint32_t aSig;
|
||||
|
||||
aSign = extractFloat16Sign(a);
|
||||
@@ -3567,7 +3578,7 @@ float64 float16_to_float64(float16 a, flag ieee, float_status *status)
|
||||
float16 float64_to_float16(float64 a, flag ieee, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint64_t aSig;
|
||||
uint32_t zSig;
|
||||
|
||||
@@ -3621,7 +3632,7 @@ float16 float64_to_float16(float64 a, flag ieee, float_status *status)
|
||||
floatx80 float64_to_floatx80(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint64_t aSig;
|
||||
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
@@ -3654,7 +3665,7 @@ floatx80 float64_to_floatx80(float64 a, float_status *status)
|
||||
float128 float64_to_float128(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint64_t aSig, zSig0, zSig1;
|
||||
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
@@ -3687,7 +3698,7 @@ float128 float64_to_float128(float64 a, float_status *status)
|
||||
float64 float64_round_to_int(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint64_t lastBitMask, roundBitsMask;
|
||||
uint64_t z;
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
@@ -3781,9 +3792,9 @@ float64 float64_trunc_to_int(float64 a, float_status *status)
|
||||
static float64 addFloat64Sigs(float64 a, float64 b, flag zSign,
|
||||
float_status *status)
|
||||
{
|
||||
int_fast16_t aExp, bExp, zExp;
|
||||
int aExp, bExp, zExp;
|
||||
uint64_t aSig, bSig, zSig;
|
||||
int_fast16_t expDiff;
|
||||
int expDiff;
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@@ -3867,9 +3878,9 @@ static float64 addFloat64Sigs(float64 a, float64 b, flag zSign,
|
||||
static float64 subFloat64Sigs(float64 a, float64 b, flag zSign,
|
||||
float_status *status)
|
||||
{
|
||||
int_fast16_t aExp, bExp, zExp;
|
||||
int aExp, bExp, zExp;
|
||||
uint64_t aSig, bSig, zSig;
|
||||
int_fast16_t expDiff;
|
||||
int expDiff;
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@@ -3993,7 +4004,7 @@ float64 float64_sub(float64 a, float64 b, float_status *status)
|
||||
float64 float64_mul(float64 a, float64 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign, zSign;
|
||||
int_fast16_t aExp, bExp, zExp;
|
||||
int aExp, bExp, zExp;
|
||||
uint64_t aSig, bSig, zSig0, zSig1;
|
||||
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
@@ -4056,7 +4067,7 @@ float64 float64_mul(float64 a, float64 b, float_status *status)
|
||||
float64 float64_div(float64 a, float64 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign, zSign;
|
||||
int_fast16_t aExp, bExp, zExp;
|
||||
int aExp, bExp, zExp;
|
||||
uint64_t aSig, bSig, zSig;
|
||||
uint64_t rem0, rem1;
|
||||
uint64_t term0, term1;
|
||||
@@ -4134,7 +4145,7 @@ float64 float64_div(float64 a, float64 b, float_status *status)
|
||||
float64 float64_rem(float64 a, float64 b, float_status *status)
|
||||
{
|
||||
flag aSign, zSign;
|
||||
int_fast16_t aExp, bExp, expDiff;
|
||||
int aExp, bExp, expDiff;
|
||||
uint64_t aSig, bSig;
|
||||
uint64_t q, alternateASig;
|
||||
int64_t sigMean;
|
||||
@@ -4228,7 +4239,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags,
|
||||
float_status *status)
|
||||
{
|
||||
flag aSign, bSign, cSign, zSign;
|
||||
int_fast16_t aExp, bExp, cExp, pExp, zExp, expDiff;
|
||||
int aExp, bExp, cExp, pExp, zExp, expDiff;
|
||||
uint64_t aSig, bSig, cSig;
|
||||
flag pInf, pZero, pSign;
|
||||
uint64_t pSig0, pSig1, cSig0, cSig1, zSig0, zSig1;
|
||||
@@ -4469,7 +4480,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags,
|
||||
float64 float64_sqrt(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, zExp;
|
||||
int aExp, zExp;
|
||||
uint64_t aSig, zSig, doubleZSig;
|
||||
uint64_t rem0, rem1, term0, term1;
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
@@ -4522,7 +4533,7 @@ float64 float64_sqrt(float64 a, float_status *status)
|
||||
float64 float64_log2(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign, zSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint64_t aSig, aSig0, aSig1, zSig, i;
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
|
||||
@@ -5005,7 +5016,7 @@ float64 floatx80_to_float64(floatx80 a, float_status *status)
|
||||
float128 floatx80_to_float128(floatx80 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp;
|
||||
int aExp;
|
||||
uint64_t aSig, zSig0, zSig1;
|
||||
|
||||
aSig = extractFloatx80Frac( a );
|
||||
@@ -7117,10 +7128,10 @@ uint32_t float32_to_uint32_round_to_zero(float32 a, float_status *status)
|
||||
return res;
|
||||
}
|
||||
|
||||
int_fast16_t float32_to_int16(float32 a, float_status *status)
|
||||
int16_t float32_to_int16(float32 a, float_status *status)
|
||||
{
|
||||
int32_t v;
|
||||
int_fast16_t res;
|
||||
int16_t res;
|
||||
int old_exc_flags = get_float_exception_flags(status);
|
||||
|
||||
v = float32_to_int32(a, status);
|
||||
@@ -7137,10 +7148,10 @@ int_fast16_t float32_to_int16(float32 a, float_status *status)
|
||||
return res;
|
||||
}
|
||||
|
||||
uint_fast16_t float32_to_uint16(float32 a, float_status *status)
|
||||
uint16_t float32_to_uint16(float32 a, float_status *status)
|
||||
{
|
||||
int32_t v;
|
||||
uint_fast16_t res;
|
||||
uint16_t res;
|
||||
int old_exc_flags = get_float_exception_flags(status);
|
||||
|
||||
v = float32_to_int32(a, status);
|
||||
@@ -7157,10 +7168,10 @@ uint_fast16_t float32_to_uint16(float32 a, float_status *status)
|
||||
return res;
|
||||
}
|
||||
|
||||
uint_fast16_t float32_to_uint16_round_to_zero(float32 a, float_status *status)
|
||||
uint16_t float32_to_uint16_round_to_zero(float32 a, float_status *status)
|
||||
{
|
||||
int64_t v;
|
||||
uint_fast16_t res;
|
||||
uint16_t res;
|
||||
int old_exc_flags = get_float_exception_flags(status);
|
||||
|
||||
v = float32_to_int64_round_to_zero(a, status);
|
||||
@@ -7210,10 +7221,10 @@ uint32_t float64_to_uint32_round_to_zero(float64 a, float_status *status)
|
||||
return res;
|
||||
}
|
||||
|
||||
int_fast16_t float64_to_int16(float64 a, float_status *status)
|
||||
int16_t float64_to_int16(float64 a, float_status *status)
|
||||
{
|
||||
int64_t v;
|
||||
int_fast16_t res;
|
||||
int16_t res;
|
||||
int old_exc_flags = get_float_exception_flags(status);
|
||||
|
||||
v = float64_to_int32(a, status);
|
||||
@@ -7230,10 +7241,10 @@ int_fast16_t float64_to_int16(float64 a, float_status *status)
|
||||
return res;
|
||||
}
|
||||
|
||||
uint_fast16_t float64_to_uint16(float64 a, float_status *status)
|
||||
uint16_t float64_to_uint16(float64 a, float_status *status)
|
||||
{
|
||||
int64_t v;
|
||||
uint_fast16_t res;
|
||||
uint16_t res;
|
||||
int old_exc_flags = get_float_exception_flags(status);
|
||||
|
||||
v = float64_to_int32(a, status);
|
||||
@@ -7250,10 +7261,10 @@ uint_fast16_t float64_to_uint16(float64 a, float_status *status)
|
||||
return res;
|
||||
}
|
||||
|
||||
uint_fast16_t float64_to_uint16_round_to_zero(float64 a, float_status *status)
|
||||
uint16_t float64_to_uint16_round_to_zero(float64 a, float_status *status)
|
||||
{
|
||||
int64_t v;
|
||||
uint_fast16_t res;
|
||||
uint16_t res;
|
||||
int old_exc_flags = get_float_exception_flags(status);
|
||||
|
||||
v = float64_to_int64_round_to_zero(a, status);
|
||||
@@ -7284,7 +7295,8 @@ uint_fast16_t float64_to_uint16_round_to_zero(float64 a, float_status *status)
|
||||
uint64_t float64_to_uint64(float64 a, float_status *status)
|
||||
{
|
||||
flag aSign;
|
||||
int_fast16_t aExp, shiftCount;
|
||||
int aExp;
|
||||
int shiftCount;
|
||||
uint64_t aSig, aSigExtra;
|
||||
a = float64_squash_input_denormal(a, status);
|
||||
|
||||
|
@@ -12,11 +12,8 @@
|
||||
*/
|
||||
#ifndef _FILEOP_H
|
||||
#define _FILEOP_H
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/vfs.h>
|
||||
|
||||
|
@@ -784,6 +784,20 @@ STEXI
|
||||
@item info skeys @var{address}
|
||||
@findex skeys
|
||||
Display the value of a storage key (s390 only)
|
||||
ETEXI
|
||||
|
||||
{
|
||||
.name = "dump",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "Display the latest dump status",
|
||||
.mhandler.cmd = hmp_info_dump,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@item info dump
|
||||
@findex dump
|
||||
Display the latest dump status.
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
|
@@ -1056,10 +1056,11 @@ ETEXI
|
||||
|
||||
{
|
||||
.name = "dump-guest-memory",
|
||||
.args_type = "paging:-p,zlib:-z,lzo:-l,snappy:-s,filename:F,begin:i?,length:i?",
|
||||
.params = "[-p] [-z|-l|-s] filename [begin length]",
|
||||
.args_type = "paging:-p,detach:-d,zlib:-z,lzo:-l,snappy:-s,filename:F,begin:i?,length:i?",
|
||||
.params = "[-p] [-d] [-z|-l|-s] filename [begin length]",
|
||||
.help = "dump guest memory into file 'filename'.\n\t\t\t"
|
||||
"-p: do paging to get guest's memory mapping.\n\t\t\t"
|
||||
"-d: return immediately (do not wait for completion).\n\t\t\t"
|
||||
"-z: dump in kdump-compressed format, with zlib compression.\n\t\t\t"
|
||||
"-l: dump in kdump-compressed format, with lzo compression.\n\t\t\t"
|
||||
"-s: dump in kdump-compressed format, with snappy compression.\n\t\t\t"
|
||||
|
38
hmp.c
38
hmp.c
@@ -1414,6 +1414,18 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
false, /* no burst length via HMP */
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
false, /* No default I/O size */
|
||||
0,
|
||||
false,
|
||||
@@ -1587,8 +1599,10 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
||||
const char *file = qdict_get_str(qdict, "filename");
|
||||
bool has_begin = qdict_haskey(qdict, "begin");
|
||||
bool has_length = qdict_haskey(qdict, "length");
|
||||
bool has_detach = qdict_haskey(qdict, "detach");
|
||||
int64_t begin = 0;
|
||||
int64_t length = 0;
|
||||
bool detach = false;
|
||||
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
||||
char *prot;
|
||||
|
||||
@@ -1616,11 +1630,14 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
||||
if (has_length) {
|
||||
length = qdict_get_int(qdict, "length");
|
||||
}
|
||||
if (has_detach) {
|
||||
detach = qdict_get_bool(qdict, "detach");
|
||||
}
|
||||
|
||||
prot = g_strconcat("file:", file, NULL);
|
||||
|
||||
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
||||
true, dump_format, &err);
|
||||
qmp_dump_guest_memory(paging, prot, true, detach, has_begin, begin,
|
||||
has_length, length, true, dump_format, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
g_free(prot);
|
||||
}
|
||||
@@ -2346,3 +2363,20 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict)
|
||||
|
||||
qapi_free_RockerOfDpaGroupList(list);
|
||||
}
|
||||
|
||||
void hmp_info_dump(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
DumpQueryResult *result = qmp_query_dump(NULL);
|
||||
|
||||
assert(result && result->status < DUMP_STATUS__MAX);
|
||||
monitor_printf(mon, "Status: %s\n", DumpStatus_lookup[result->status]);
|
||||
|
||||
if (result->status == DUMP_STATUS_ACTIVE) {
|
||||
float percent = 0;
|
||||
assert(result->total != 0);
|
||||
percent = 100.0 * result->completed / result->total;
|
||||
monitor_printf(mon, "Finished: %.2f %%\n", percent);
|
||||
}
|
||||
|
||||
qapi_free_DumpQueryResult(result);
|
||||
}
|
||||
|
1
hmp.h
1
hmp.h
@@ -131,5 +131,6 @@ void hmp_rocker(Monitor *mon, const QDict *qdict);
|
||||
void hmp_rocker_ports(Monitor *mon, const QDict *qdict);
|
||||
void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict);
|
||||
void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_dump(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif
|
||||
|
@@ -13,9 +13,6 @@
|
||||
#ifndef HW_9PFS_SYNTH_H
|
||||
#define HW_9PFS_SYNTH_H 1
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
|
||||
typedef struct V9fsSynthNode V9fsSynthNode;
|
||||
typedef ssize_t (*v9fs_synth_read)(void *buf, int len, off_t offset,
|
||||
|
@@ -1,9 +1,7 @@
|
||||
#ifndef _QEMU_9P_H
|
||||
#define _QEMU_9P_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
#include <sys/resource.h>
|
||||
#include <glib.h>
|
||||
|
@@ -1451,7 +1451,7 @@ build_header(GArray *linker, GArray *table_data,
|
||||
h->checksum = 0;
|
||||
/* Checksum to be filled in by Guest linker */
|
||||
bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
|
||||
table_data->data, h, len, &h->checksum);
|
||||
table_data, h, len, &h->checksum);
|
||||
}
|
||||
|
||||
void *acpi_data_push(GArray *table_data, unsigned size)
|
||||
|
@@ -25,6 +25,13 @@
|
||||
|
||||
#include "qemu/bswap.h"
|
||||
|
||||
/*
|
||||
* Linker/loader is a paravirtualized interface that passes commands to guest.
|
||||
* The commands can be used to request guest to
|
||||
* - allocate memory chunks and initialize them from QEMU FW CFG files
|
||||
* - link allocated chunks by storing pointer to one chunk into another
|
||||
* - calculate ACPI checksum of part of the chunk and store into same chunk
|
||||
*/
|
||||
#define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH
|
||||
|
||||
struct BiosLinkerLoaderEntry {
|
||||
@@ -88,6 +95,12 @@ enum {
|
||||
BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2,
|
||||
};
|
||||
|
||||
/*
|
||||
* bios_linker_loader_init: allocate a new linker file blob array.
|
||||
*
|
||||
* After initialization, linker commands can be added, and will
|
||||
* be stored in the array.
|
||||
*/
|
||||
GArray *bios_linker_loader_init(void)
|
||||
{
|
||||
return g_array_new(false, true /* clear */, 1);
|
||||
@@ -99,6 +112,16 @@ void *bios_linker_loader_cleanup(GArray *linker)
|
||||
return g_array_free(linker, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* bios_linker_loader_alloc: ask guest to load file into guest memory.
|
||||
*
|
||||
* @linker: linker file blob array
|
||||
* @file: file to be loaded
|
||||
* @alloc_align: required minimal alignment in bytes. Must be a power of 2.
|
||||
* @alloc_fseg: request allocation in FSEG zone (useful for the RSDP ACPI table)
|
||||
*
|
||||
* Note: this command must precede any other linker command using this file.
|
||||
*/
|
||||
void bios_linker_loader_alloc(GArray *linker,
|
||||
const char *file,
|
||||
uint32_t alloc_align,
|
||||
@@ -106,6 +129,8 @@ void bios_linker_loader_alloc(GArray *linker,
|
||||
{
|
||||
BiosLinkerLoaderEntry entry;
|
||||
|
||||
assert(!(alloc_align & (alloc_align - 1)));
|
||||
|
||||
memset(&entry, 0, sizeof entry);
|
||||
strncpy(entry.alloc.file, file, sizeof entry.alloc.file - 1);
|
||||
entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ALLOCATE);
|
||||
@@ -118,23 +143,77 @@ void bios_linker_loader_alloc(GArray *linker,
|
||||
g_array_prepend_vals(linker, &entry, sizeof entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* bios_linker_loader_add_checksum: ask guest to add checksum of file data
|
||||
* into (same) file at the specified pointer.
|
||||
*
|
||||
* Checksum calculation simply sums -X for each byte X in the range
|
||||
* using 8-bit math (i.e. ACPI checksum).
|
||||
*
|
||||
* @linker: linker file blob array
|
||||
* @file: file that includes the checksum to be calculated
|
||||
* and the data to be checksummed
|
||||
* @table: @file blob contents
|
||||
* @start, @size: range of data to checksum
|
||||
* @checksum: location of the checksum to be patched within file blob
|
||||
*
|
||||
* Notes:
|
||||
* - checksum byte initial value must have been pushed into @table
|
||||
* and reside at address @checksum.
|
||||
* - @size bytes must have been pushed into @table and reside at address
|
||||
* @start.
|
||||
* - Guest calculates checksum of specified range of data, result is added to
|
||||
* initial value at @checksum into copy of @file in Guest memory.
|
||||
* - Range might include the checksum itself.
|
||||
* - To avoid confusion, caller must always put 0x0 at @checksum.
|
||||
* - @file must be loaded into Guest memory using bios_linker_loader_alloc
|
||||
*/
|
||||
void bios_linker_loader_add_checksum(GArray *linker, const char *file,
|
||||
void *table,
|
||||
GArray *table,
|
||||
void *start, unsigned size,
|
||||
uint8_t *checksum)
|
||||
{
|
||||
BiosLinkerLoaderEntry entry;
|
||||
ptrdiff_t checksum_offset = (gchar *)checksum - table->data;
|
||||
ptrdiff_t start_offset = (gchar *)start - table->data;
|
||||
|
||||
assert(checksum_offset >= 0);
|
||||
assert(start_offset >= 0);
|
||||
assert(checksum_offset + 1 <= table->len);
|
||||
assert(start_offset + size <= table->len);
|
||||
assert(*checksum == 0x0);
|
||||
|
||||
memset(&entry, 0, sizeof entry);
|
||||
strncpy(entry.cksum.file, file, sizeof entry.cksum.file - 1);
|
||||
entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM);
|
||||
entry.cksum.offset = cpu_to_le32(checksum - (uint8_t *)table);
|
||||
entry.cksum.start = cpu_to_le32((uint8_t *)start - (uint8_t *)table);
|
||||
entry.cksum.offset = cpu_to_le32(checksum_offset);
|
||||
entry.cksum.start = cpu_to_le32(start_offset);
|
||||
entry.cksum.length = cpu_to_le32(size);
|
||||
|
||||
g_array_append_vals(linker, &entry, sizeof entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* bios_linker_loader_add_pointer: ask guest to add address of source file
|
||||
* into destination file at the specified pointer.
|
||||
*
|
||||
* @linker: linker file blob array
|
||||
* @dest_file: destination file that must be changed
|
||||
* @src_file: source file who's address must be taken
|
||||
* @table: @dest_file blob contents array
|
||||
* @pointer: location of the pointer to be patched within destination file blob
|
||||
* @pointer_size: size of pointer to be patched, in bytes
|
||||
*
|
||||
* Notes:
|
||||
* - @pointer_size bytes must have been pushed into @table
|
||||
* and reside at address @pointer.
|
||||
* - Guest address is added to initial value at @pointer
|
||||
* into copy of @dest_file in Guest memory.
|
||||
* e.g. to get start of src_file in guest memory, put 0x0 there
|
||||
* to get address of a field at offset 0x10 in src_file, put 0x10 there
|
||||
* - Both @dest_file and @src_file must be
|
||||
* loaded into Guest memory using bios_linker_loader_alloc
|
||||
*/
|
||||
void bios_linker_loader_add_pointer(GArray *linker,
|
||||
const char *dest_file,
|
||||
const char *src_file,
|
||||
@@ -142,7 +221,10 @@ void bios_linker_loader_add_pointer(GArray *linker,
|
||||
uint8_t pointer_size)
|
||||
{
|
||||
BiosLinkerLoaderEntry entry;
|
||||
size_t offset = (gchar *)pointer - table->data;
|
||||
ptrdiff_t offset = (gchar *)pointer - table->data;
|
||||
|
||||
assert(offset >= 0);
|
||||
assert(offset + pointer_size <= table->len);
|
||||
|
||||
memset(&entry, 0, sizeof entry);
|
||||
strncpy(entry.pointer.dest_file, dest_file,
|
||||
@@ -150,7 +232,6 @@ void bios_linker_loader_add_pointer(GArray *linker,
|
||||
strncpy(entry.pointer.src_file, src_file,
|
||||
sizeof entry.pointer.src_file - 1);
|
||||
entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);
|
||||
assert(table->len >= offset + pointer_size);
|
||||
entry.pointer.offset = cpu_to_le32(offset);
|
||||
entry.pointer.size = pointer_size;
|
||||
assert(pointer_size == 1 || pointer_size == 2 ||
|
||||
|
@@ -240,7 +240,7 @@ static void pm_powerdown_req(Notifier *n, void *opaque)
|
||||
}
|
||||
|
||||
void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
||||
bool smm_enabled, bool enable_tco,
|
||||
bool smm_enabled,
|
||||
qemu_irq sci_irq)
|
||||
{
|
||||
memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
|
||||
@@ -264,10 +264,8 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
||||
|
||||
pm->smm_enabled = smm_enabled;
|
||||
|
||||
pm->enable_tco = enable_tco;
|
||||
if (pm->enable_tco) {
|
||||
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
|
||||
}
|
||||
pm->enable_tco = true;
|
||||
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
|
||||
|
||||
pm->irq = sci_irq;
|
||||
qemu_register_reset(pm_reset, pm);
|
||||
|
@@ -182,6 +182,13 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
|
||||
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
|
||||
INTERRUPT_ARASANSDIO));
|
||||
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->sdhci), "sd-bus",
|
||||
&err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
|
||||
|
@@ -73,6 +73,13 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
|
||||
"sd-bus", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
|
||||
BCM2836_PERI_BASE, 1);
|
||||
|
||||
|
@@ -113,6 +113,10 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size)
|
||||
static void raspi2_init(MachineState *machine)
|
||||
{
|
||||
RasPiState *s = g_new0(RasPiState, 1);
|
||||
DriveInfo *di;
|
||||
BlockBackend *blk;
|
||||
BusState *bus;
|
||||
DeviceState *carddev;
|
||||
|
||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_BCM2836);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
|
||||
@@ -133,6 +137,18 @@ static void raspi2_init(MachineState *machine)
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort);
|
||||
|
||||
/* Create and plug in the SD cards */
|
||||
di = drive_get_next(IF_SD);
|
||||
blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
bus = qdev_get_child_bus(DEVICE(&s->soc), "sd-bus");
|
||||
if (bus == NULL) {
|
||||
error_report("No SD bus found in SOC object");
|
||||
exit(1);
|
||||
}
|
||||
carddev = qdev_create(bus, TYPE_SD_CARD);
|
||||
qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
|
||||
object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
|
||||
|
||||
setup_boot(machine, 2, machine->ram_size);
|
||||
}
|
||||
|
||||
|
@@ -359,7 +359,8 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
|
||||
rsdp->checksum = 0;
|
||||
/* Checksum to be filled by Guest linker */
|
||||
bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
|
||||
rsdp, rsdp, sizeof *rsdp, &rsdp->checksum);
|
||||
rsdp_table, rsdp, sizeof *rsdp,
|
||||
&rsdp->checksum);
|
||||
|
||||
return rsdp_table;
|
||||
}
|
||||
|
@@ -34,7 +34,6 @@
|
||||
typedef signed char GUSchar;
|
||||
typedef signed short GUSsample;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
typedef int8_t GUSchar;
|
||||
typedef uint8_t GUSbyte;
|
||||
typedef uint16_t GUSword;
|
||||
|
@@ -18,8 +18,6 @@
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "hw/virtio/dataplane/vring.h"
|
||||
#include "hw/virtio/dataplane/vring-accessors.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/virtio/virtio-blk.h"
|
||||
#include "virtio-blk.h"
|
||||
@@ -28,7 +26,6 @@
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
struct VirtIOBlockDataPlane {
|
||||
bool started;
|
||||
bool starting;
|
||||
bool stopping;
|
||||
bool disabled;
|
||||
@@ -36,7 +33,7 @@ struct VirtIOBlockDataPlane {
|
||||
VirtIOBlkConf *conf;
|
||||
|
||||
VirtIODevice *vdev;
|
||||
Vring vring; /* virtqueue vring */
|
||||
VirtQueue *vq; /* virtqueue vring */
|
||||
EventNotifier *guest_notifier; /* irq */
|
||||
QEMUBH *bh; /* bh for guest notification */
|
||||
|
||||
@@ -49,93 +46,26 @@ struct VirtIOBlockDataPlane {
|
||||
*/
|
||||
IOThread *iothread;
|
||||
AioContext *ctx;
|
||||
EventNotifier host_notifier; /* doorbell */
|
||||
|
||||
/* Operation blocker on BDS */
|
||||
Error *blocker;
|
||||
void (*saved_complete_request)(struct VirtIOBlockReq *req,
|
||||
unsigned char status);
|
||||
};
|
||||
|
||||
/* Raise an interrupt to signal guest, if necessary */
|
||||
static void notify_guest(VirtIOBlockDataPlane *s)
|
||||
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s)
|
||||
{
|
||||
if (!vring_should_notify(s->vdev, &s->vring)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event_notifier_set(s->guest_notifier);
|
||||
qemu_bh_schedule(s->bh);
|
||||
}
|
||||
|
||||
static void notify_guest_bh(void *opaque)
|
||||
{
|
||||
VirtIOBlockDataPlane *s = opaque;
|
||||
|
||||
notify_guest(s);
|
||||
}
|
||||
|
||||
static void complete_request_vring(VirtIOBlockReq *req, unsigned char status)
|
||||
{
|
||||
VirtIOBlockDataPlane *s = req->dev->dataplane;
|
||||
stb_p(&req->in->status, status);
|
||||
|
||||
vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, req->in_len);
|
||||
|
||||
/* Suppress notification to guest by BH and its scheduled
|
||||
* flag because requests are completed as a batch after io
|
||||
* plug & unplug is introduced, and the BH can still be
|
||||
* executed in dataplane aio context even after it is
|
||||
* stopped, so needn't worry about notification loss with BH.
|
||||
*/
|
||||
qemu_bh_schedule(s->bh);
|
||||
}
|
||||
|
||||
static void handle_notify(EventNotifier *e)
|
||||
{
|
||||
VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane,
|
||||
host_notifier);
|
||||
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
|
||||
|
||||
event_notifier_test_and_clear(&s->host_notifier);
|
||||
blk_io_plug(s->conf->conf.blk);
|
||||
for (;;) {
|
||||
MultiReqBuffer mrb = {};
|
||||
|
||||
/* Disable guest->host notifies to avoid unnecessary vmexits */
|
||||
vring_disable_notification(s->vdev, &s->vring);
|
||||
|
||||
for (;;) {
|
||||
VirtIOBlockReq *req = vring_pop(s->vdev, &s->vring,
|
||||
sizeof(VirtIOBlockReq));
|
||||
|
||||
if (req == NULL) {
|
||||
break; /* no more requests */
|
||||
}
|
||||
|
||||
virtio_blk_init_request(vblk, req);
|
||||
trace_virtio_blk_data_plane_process_request(s, req->elem.out_num,
|
||||
req->elem.in_num,
|
||||
req->elem.index);
|
||||
|
||||
virtio_blk_handle_request(req, &mrb);
|
||||
}
|
||||
|
||||
if (mrb.num_reqs) {
|
||||
virtio_blk_submit_multireq(s->conf->conf.blk, &mrb);
|
||||
}
|
||||
|
||||
if (likely(!vring_more_avail(s->vdev, &s->vring))) { /* vring emptied */
|
||||
/* Re-enable guest->host notifies and stop processing the vring.
|
||||
* But if the guest has snuck in more descriptors, keep processing.
|
||||
*/
|
||||
if (vring_enable_notification(s->vdev, &s->vring)) {
|
||||
break;
|
||||
}
|
||||
} else { /* fatal error */
|
||||
break;
|
||||
}
|
||||
if (!virtio_should_notify(s->vdev, s->vq)) {
|
||||
return;
|
||||
}
|
||||
blk_io_unplug(s->conf->conf.blk);
|
||||
|
||||
event_notifier_set(s->guest_notifier);
|
||||
}
|
||||
|
||||
static void data_plane_set_up_op_blockers(VirtIOBlockDataPlane *s)
|
||||
@@ -260,23 +190,14 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
|
||||
VirtQueue *vq;
|
||||
int r;
|
||||
|
||||
if (s->started || s->disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->starting) {
|
||||
if (vblk->dataplane_started || s->starting) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->starting = true;
|
||||
|
||||
vq = virtio_get_queue(s->vdev, 0);
|
||||
if (!vring_setup(&s->vring, s->vdev, 0)) {
|
||||
goto fail_vring;
|
||||
}
|
||||
s->vq = virtio_get_queue(s->vdev, 0);
|
||||
|
||||
/* Set up guest notifier (irq) */
|
||||
r = k->set_guest_notifiers(qbus->parent, 1, true);
|
||||
@@ -285,7 +206,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
|
||||
"ensure -enable-kvm is set\n", r);
|
||||
goto fail_guest_notifiers;
|
||||
}
|
||||
s->guest_notifier = virtio_queue_get_guest_notifier(vq);
|
||||
s->guest_notifier = virtio_queue_get_guest_notifier(s->vq);
|
||||
|
||||
/* Set up virtqueue notify */
|
||||
r = k->set_host_notifier(qbus->parent, 0, true);
|
||||
@@ -293,34 +214,28 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
|
||||
fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
|
||||
goto fail_host_notifier;
|
||||
}
|
||||
s->host_notifier = *virtio_queue_get_host_notifier(vq);
|
||||
|
||||
s->saved_complete_request = vblk->complete_request;
|
||||
vblk->complete_request = complete_request_vring;
|
||||
|
||||
s->starting = false;
|
||||
s->started = true;
|
||||
vblk->dataplane_started = true;
|
||||
trace_virtio_blk_data_plane_start(s);
|
||||
|
||||
blk_set_aio_context(s->conf->conf.blk, s->ctx);
|
||||
|
||||
/* Kick right away to begin processing requests already in vring */
|
||||
event_notifier_set(virtio_queue_get_host_notifier(vq));
|
||||
event_notifier_set(virtio_queue_get_host_notifier(s->vq));
|
||||
|
||||
/* Get this show started by hooking up our callbacks */
|
||||
aio_context_acquire(s->ctx);
|
||||
aio_set_event_notifier(s->ctx, &s->host_notifier, true,
|
||||
handle_notify);
|
||||
virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, true, true);
|
||||
aio_context_release(s->ctx);
|
||||
return;
|
||||
|
||||
fail_host_notifier:
|
||||
k->set_guest_notifiers(qbus->parent, 1, false);
|
||||
fail_guest_notifiers:
|
||||
vring_teardown(&s->vring, s->vdev, 0);
|
||||
s->disabled = true;
|
||||
fail_vring:
|
||||
s->starting = false;
|
||||
vblk->dataplane_started = true;
|
||||
}
|
||||
|
||||
/* Context: QEMU global mutex held */
|
||||
@@ -330,39 +245,34 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
|
||||
|
||||
if (!vblk->dataplane_started || s->stopping) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Better luck next time. */
|
||||
if (s->disabled) {
|
||||
s->disabled = false;
|
||||
return;
|
||||
}
|
||||
if (!s->started || s->stopping) {
|
||||
vblk->dataplane_started = false;
|
||||
return;
|
||||
}
|
||||
s->stopping = true;
|
||||
vblk->complete_request = s->saved_complete_request;
|
||||
trace_virtio_blk_data_plane_stop(s);
|
||||
|
||||
aio_context_acquire(s->ctx);
|
||||
|
||||
/* Stop notifications for new requests from guest */
|
||||
aio_set_event_notifier(s->ctx, &s->host_notifier, true, NULL);
|
||||
virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, false, false);
|
||||
|
||||
/* Drain and switch bs back to the QEMU main loop */
|
||||
blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
|
||||
|
||||
aio_context_release(s->ctx);
|
||||
|
||||
/* Sync vring state back to virtqueue so that non-dataplane request
|
||||
* processing can continue when we disable the host notifier below.
|
||||
*/
|
||||
vring_teardown(&s->vring, s->vdev, 0);
|
||||
|
||||
k->set_host_notifier(qbus->parent, 0, false);
|
||||
|
||||
/* Clean up guest notifier (irq) */
|
||||
k->set_guest_notifiers(qbus->parent, 1, false);
|
||||
|
||||
s->started = false;
|
||||
vblk->dataplane_started = false;
|
||||
s->stopping = false;
|
||||
}
|
||||
|
@@ -26,5 +26,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);
|
||||
void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s);
|
||||
void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s);
|
||||
void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s);
|
||||
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s);
|
||||
|
||||
#endif /* HW_DATAPLANE_VIRTIO_BLK_H */
|
||||
|
@@ -21,7 +21,6 @@
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/virtio/virtio-blk.h"
|
||||
#include "dataplane/virtio-blk.h"
|
||||
#include "migration/migration.h"
|
||||
#include "block/scsi.h"
|
||||
#ifdef __linux__
|
||||
# include <scsi/sg.h>
|
||||
@@ -45,8 +44,7 @@ void virtio_blk_free_request(VirtIOBlockReq *req)
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_blk_complete_request(VirtIOBlockReq *req,
|
||||
unsigned char status)
|
||||
static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
|
||||
{
|
||||
VirtIOBlock *s = req->dev;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
@@ -55,12 +53,11 @@ static void virtio_blk_complete_request(VirtIOBlockReq *req,
|
||||
|
||||
stb_p(&req->in->status, status);
|
||||
virtqueue_push(s->vq, &req->elem, req->in_len);
|
||||
virtio_notify(vdev, s->vq);
|
||||
}
|
||||
|
||||
static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
|
||||
{
|
||||
req->dev->complete_request(req, status);
|
||||
if (s->dataplane) {
|
||||
virtio_blk_data_plane_notify(s->dataplane);
|
||||
} else {
|
||||
virtio_notify(vdev, s->vq);
|
||||
}
|
||||
}
|
||||
|
||||
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
|
||||
@@ -589,7 +586,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
/* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
|
||||
* dataplane here instead of waiting for .set_status().
|
||||
*/
|
||||
if (s->dataplane) {
|
||||
if (s->dataplane && !s->dataplane_started) {
|
||||
virtio_blk_data_plane_start(s->dataplane);
|
||||
return;
|
||||
}
|
||||
@@ -852,36 +849,6 @@ static const BlockDevOps virtio_block_ops = {
|
||||
.resize_cb = virtio_blk_resize,
|
||||
};
|
||||
|
||||
/* Disable dataplane thread during live migration since it does not
|
||||
* update the dirty memory bitmap yet.
|
||||
*/
|
||||
static void virtio_blk_migration_state_changed(Notifier *notifier, void *data)
|
||||
{
|
||||
VirtIOBlock *s = container_of(notifier, VirtIOBlock,
|
||||
migration_state_notifier);
|
||||
MigrationState *mig = data;
|
||||
Error *err = NULL;
|
||||
|
||||
if (migration_in_setup(mig)) {
|
||||
if (!s->dataplane) {
|
||||
return;
|
||||
}
|
||||
virtio_blk_data_plane_destroy(s->dataplane);
|
||||
s->dataplane = NULL;
|
||||
} else if (migration_has_finished(mig) ||
|
||||
migration_has_failed(mig)) {
|
||||
if (s->dataplane) {
|
||||
return;
|
||||
}
|
||||
blk_drain_all(); /* complete in-flight non-dataplane requests */
|
||||
virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->conf,
|
||||
&s->dataplane, &err);
|
||||
if (err != NULL) {
|
||||
error_report_err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
@@ -916,15 +883,12 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
||||
s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1;
|
||||
|
||||
s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
|
||||
s->complete_request = virtio_blk_complete_request;
|
||||
virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
virtio_cleanup(vdev);
|
||||
return;
|
||||
}
|
||||
s->migration_state_notifier.notify = virtio_blk_migration_state_changed;
|
||||
add_migration_state_change_notifier(&s->migration_state_notifier);
|
||||
|
||||
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
|
||||
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
|
||||
@@ -940,7 +904,6 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VirtIOBlock *s = VIRTIO_BLK(dev);
|
||||
|
||||
remove_migration_state_change_notifier(&s->migration_state_notifier);
|
||||
virtio_blk_data_plane_destroy(s->dataplane);
|
||||
s->dataplane = NULL;
|
||||
qemu_del_vm_change_state_handler(s->change);
|
||||
|
@@ -25,7 +25,6 @@
|
||||
#define HW_VGA_INT_H 1
|
||||
|
||||
#include <hw/hw.h>
|
||||
#include "qapi/error.h"
|
||||
#include "exec/memory.h"
|
||||
|
||||
#define ST01_V_RETRACE 0x08
|
||||
|
@@ -440,13 +440,16 @@ static int channel_out_run(struct fs_dma_ctrl *ctrl, int c)
|
||||
D(printf("channel %d pushes %x %u bytes eop=%u\n", c,
|
||||
saved_data_buf, len, out_eop));
|
||||
|
||||
if (ctrl->channels[c].client->client.push)
|
||||
ctrl->channels[c].client->client.push(
|
||||
ctrl->channels[c].client->client.opaque,
|
||||
buf, len, out_eop);
|
||||
else
|
||||
if (ctrl->channels[c].client->client.push) {
|
||||
if (len > 0) {
|
||||
ctrl->channels[c].client->client.push(
|
||||
ctrl->channels[c].client->client.opaque,
|
||||
buf, len, out_eop);
|
||||
}
|
||||
} else {
|
||||
printf("WARNING: DMA ch%d dataloss,"
|
||||
" no attached client.\n", c);
|
||||
}
|
||||
|
||||
saved_data_buf += len;
|
||||
|
||||
|
@@ -60,6 +60,7 @@ typedef struct PL061State {
|
||||
qemu_irq irq;
|
||||
qemu_irq out[8];
|
||||
const unsigned char *id;
|
||||
uint32_t rsvd_start; /* reserved area: [rsvd_start, 0xfcc] */
|
||||
} PL061State;
|
||||
|
||||
static const VMStateDescription vmstate_pl061 = {
|
||||
@@ -152,12 +153,15 @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
|
||||
{
|
||||
PL061State *s = (PL061State *)opaque;
|
||||
|
||||
if (offset >= 0xfd0 && offset < 0x1000) {
|
||||
return s->id[(offset - 0xfd0) >> 2];
|
||||
}
|
||||
if (offset < 0x400) {
|
||||
return s->data & (offset >> 2);
|
||||
}
|
||||
if (offset >= s->rsvd_start && offset <= 0xfcc) {
|
||||
goto err_out;
|
||||
}
|
||||
if (offset >= 0xfd0 && offset < 0x1000) {
|
||||
return s->id[(offset - 0xfd0) >> 2];
|
||||
}
|
||||
switch (offset) {
|
||||
case 0x400: /* Direction */
|
||||
return s->dir;
|
||||
@@ -198,10 +202,12 @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
|
||||
case 0x528: /* Analog mode select */
|
||||
return s->amsel;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl061_read: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
err_out:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl061_read: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pl061_write(void *opaque, hwaddr offset,
|
||||
@@ -216,6 +222,9 @@ static void pl061_write(void *opaque, hwaddr offset,
|
||||
pl061_update(s);
|
||||
return;
|
||||
}
|
||||
if (offset >= s->rsvd_start) {
|
||||
goto err_out;
|
||||
}
|
||||
switch (offset) {
|
||||
case 0x400: /* Direction */
|
||||
s->dir = value & 0xff;
|
||||
@@ -274,10 +283,13 @@ static void pl061_write(void *opaque, hwaddr offset,
|
||||
s->amsel = value & 0xff;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl061_write: Bad offset %x\n", (int)offset);
|
||||
goto err_out;
|
||||
}
|
||||
pl061_update(s);
|
||||
return;
|
||||
err_out:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl061_write: Bad offset %x\n", (int)offset);
|
||||
}
|
||||
|
||||
static void pl061_reset(DeviceState *dev)
|
||||
@@ -347,6 +359,7 @@ static void pl061_luminary_init(Object *obj)
|
||||
PL061State *s = PL061(obj);
|
||||
|
||||
s->id = pl061_id_luminary;
|
||||
s->rsvd_start = 0x52c;
|
||||
}
|
||||
|
||||
static void pl061_init(Object *obj)
|
||||
@@ -354,6 +367,7 @@ static void pl061_init(Object *obj)
|
||||
PL061State *s = PL061(obj);
|
||||
|
||||
s->id = pl061_id;
|
||||
s->rsvd_start = 0x424;
|
||||
}
|
||||
|
||||
static void pl061_class_init(ObjectClass *klass, void *data)
|
||||
|
@@ -2532,7 +2532,8 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
|
||||
rsdp->checksum = 0;
|
||||
/* Checksum to be filled by Guest linker */
|
||||
bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
|
||||
rsdp, rsdp, sizeof *rsdp, &rsdp->checksum);
|
||||
rsdp_table, rsdp, sizeof *rsdp,
|
||||
&rsdp->checksum);
|
||||
|
||||
return rsdp_table;
|
||||
}
|
||||
|
176
hw/i386/pc_q35.c
176
hw/i386/pc_q35.c
@@ -81,11 +81,9 @@ static void pc_q35_init(MachineState *machine)
|
||||
* If it doesn't, we need to split it in chunks below and above 4G.
|
||||
* In any case, try to make sure that guest addresses aligned at
|
||||
* 1G boundaries get mapped to host addresses aligned at 1G boundaries.
|
||||
* For old machine types, use whatever split we used historically to avoid
|
||||
* breaking migration.
|
||||
*/
|
||||
if (machine->ram_size >= 0xb0000000) {
|
||||
lowmem = pcmc->gigabyte_align ? 0x80000000 : 0xb0000000;
|
||||
lowmem = 0x80000000;
|
||||
} else {
|
||||
lowmem = 0xb0000000;
|
||||
}
|
||||
@@ -116,10 +114,6 @@ static void pc_q35_init(MachineState *machine)
|
||||
}
|
||||
|
||||
pc_cpus_init(pcms);
|
||||
if (!pcmc->has_acpi_build) {
|
||||
/* only machine types 1.7 & older need this */
|
||||
pc_acpi_init("q35-acpi-dsdt.aml");
|
||||
}
|
||||
|
||||
kvmclock_create();
|
||||
|
||||
@@ -225,7 +219,7 @@ static void pc_q35_init(MachineState *machine)
|
||||
(pcms->vmport != ON_OFF_AUTO_ON), 0xff0104);
|
||||
|
||||
/* connect pm stuff to lpc */
|
||||
ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), !mc->no_tco);
|
||||
ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
|
||||
|
||||
/* ahci and SATA device, for q35 1 ahci controller is built-in */
|
||||
ahci = pci_create_simple_multifunction(host_bus,
|
||||
@@ -259,62 +253,6 @@ static void pc_q35_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
/* Looking for a pc_compat_2_4() function? It doesn't exist.
|
||||
* pc_compat_*() functions that run on machine-init time and
|
||||
* change global QEMU state are deprecated. Please don't create
|
||||
* one, and implement any pc-*-2.4 (and newer) compat code in
|
||||
* HW_COMPAT_*, PC_COMPAT_*, or * pc_*_machine_options().
|
||||
*/
|
||||
|
||||
static void pc_compat_2_3(MachineState *machine)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(machine);
|
||||
savevm_skip_section_footers();
|
||||
if (kvm_enabled()) {
|
||||
pcms->smm = ON_OFF_AUTO_OFF;
|
||||
}
|
||||
global_state_set_optional();
|
||||
savevm_skip_configuration();
|
||||
}
|
||||
|
||||
static void pc_compat_2_2(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_3(machine);
|
||||
machine->suppress_vmdesc = true;
|
||||
}
|
||||
|
||||
static void pc_compat_2_1(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_2(machine);
|
||||
x86_cpu_change_kvm_default("svm", NULL);
|
||||
}
|
||||
|
||||
static void pc_compat_2_0(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_1(machine);
|
||||
}
|
||||
|
||||
static void pc_compat_1_7(MachineState *machine)
|
||||
{
|
||||
pc_compat_2_0(machine);
|
||||
x86_cpu_change_kvm_default("x2apic", NULL);
|
||||
}
|
||||
|
||||
static void pc_compat_1_6(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_7(machine);
|
||||
}
|
||||
|
||||
static void pc_compat_1_5(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_6(machine);
|
||||
}
|
||||
|
||||
static void pc_compat_1_4(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_5(machine);
|
||||
}
|
||||
|
||||
#define DEFINE_Q35_MACHINE(suffix, name, compatfn, optionfn) \
|
||||
static void pc_init_##suffix(MachineState *machine) \
|
||||
{ \
|
||||
@@ -336,7 +274,6 @@ static void pc_q35_machine_options(MachineClass *m)
|
||||
m->default_machine_opts = "firmware=bios-256k.bin";
|
||||
m->default_display = "std";
|
||||
m->no_floppy = 1;
|
||||
m->no_tco = 0;
|
||||
}
|
||||
|
||||
static void pc_q35_2_6_machine_options(MachineClass *m)
|
||||
@@ -371,112 +308,3 @@ static void pc_q35_2_4_machine_options(MachineClass *m)
|
||||
|
||||
DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL,
|
||||
pc_q35_2_4_machine_options);
|
||||
|
||||
|
||||
static void pc_q35_2_3_machine_options(MachineClass *m)
|
||||
{
|
||||
pc_q35_2_4_machine_options(m);
|
||||
m->hw_version = "2.3.0";
|
||||
m->no_floppy = 0;
|
||||
m->no_tco = 1;
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v2_3, "pc-q35-2.3", pc_compat_2_3,
|
||||
pc_q35_2_3_machine_options);
|
||||
|
||||
|
||||
static void pc_q35_2_2_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_q35_2_3_machine_options(m);
|
||||
m->hw_version = "2.2.0";
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
|
||||
pcmc->rsdp_in_ram = false;
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v2_2, "pc-q35-2.2", pc_compat_2_2,
|
||||
pc_q35_2_2_machine_options);
|
||||
|
||||
|
||||
static void pc_q35_2_1_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_q35_2_2_machine_options(m);
|
||||
m->hw_version = "2.1.0";
|
||||
m->default_display = NULL;
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
|
||||
pcmc->smbios_uuid_encoded = false;
|
||||
pcmc->enforce_aligned_dimm = false;
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v2_1, "pc-q35-2.1", pc_compat_2_1,
|
||||
pc_q35_2_1_machine_options);
|
||||
|
||||
|
||||
static void pc_q35_2_0_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_q35_2_1_machine_options(m);
|
||||
m->hw_version = "2.0.0";
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
|
||||
pcmc->has_reserved_memory = false;
|
||||
pcmc->smbios_legacy_mode = true;
|
||||
pcmc->acpi_data_size = 0x10000;
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v2_0, "pc-q35-2.0", pc_compat_2_0,
|
||||
pc_q35_2_0_machine_options);
|
||||
|
||||
|
||||
static void pc_q35_1_7_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_q35_2_0_machine_options(m);
|
||||
m->hw_version = "1.7.0";
|
||||
m->default_machine_opts = NULL;
|
||||
m->option_rom_has_mr = true;
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
|
||||
pcmc->smbios_defaults = false;
|
||||
pcmc->gigabyte_align = false;
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v1_7, "pc-q35-1.7", pc_compat_1_7,
|
||||
pc_q35_1_7_machine_options);
|
||||
|
||||
|
||||
static void pc_q35_1_6_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_q35_machine_options(m);
|
||||
m->hw_version = "1.6.0";
|
||||
m->rom_file_has_mr = false;
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
|
||||
pcmc->has_acpi_build = false;
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v1_6, "pc-q35-1.6", pc_compat_1_6,
|
||||
pc_q35_1_6_machine_options);
|
||||
|
||||
|
||||
static void pc_q35_1_5_machine_options(MachineClass *m)
|
||||
{
|
||||
pc_q35_1_6_machine_options(m);
|
||||
m->hw_version = "1.5.0";
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v1_5, "pc-q35-1.5", pc_compat_1_5,
|
||||
pc_q35_1_5_machine_options);
|
||||
|
||||
|
||||
static void pc_q35_1_4_machine_options(MachineClass *m)
|
||||
{
|
||||
pc_q35_1_5_machine_options(m);
|
||||
m->hw_version = "1.4.0";
|
||||
m->hot_add_cpu = NULL;
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v1_4, "pc-q35-1.4", pc_compat_1_4,
|
||||
pc_q35_1_4_machine_options);
|
||||
|
@@ -369,13 +369,13 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
|
||||
}
|
||||
}
|
||||
|
||||
void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled, bool enable_tco)
|
||||
void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
|
||||
{
|
||||
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
|
||||
qemu_irq sci_irq;
|
||||
|
||||
sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0);
|
||||
ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, enable_tco, sci_irq);
|
||||
ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, sci_irq);
|
||||
ich9_lpc_reset(&lpc->d.qdev);
|
||||
}
|
||||
|
||||
|
@@ -192,32 +192,6 @@ int qmp_pc_dimm_device_list(Object *obj, void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ram_addr_t get_current_ram_size(void)
|
||||
{
|
||||
MemoryDeviceInfoList *info_list = NULL;
|
||||
MemoryDeviceInfoList **prev = &info_list;
|
||||
MemoryDeviceInfoList *info;
|
||||
ram_addr_t size = ram_size;
|
||||
|
||||
qmp_pc_dimm_device_list(qdev_get_machine(), &prev);
|
||||
for (info = info_list; info; info = info->next) {
|
||||
MemoryDeviceInfo *value = info->value;
|
||||
|
||||
if (value) {
|
||||
switch (value->type) {
|
||||
case MEMORY_DEVICE_INFO_KIND_DIMM:
|
||||
size += value->u.dimm->size;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
qapi_free_MemoryDeviceInfoList(info_list);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int pc_dimm_slot2bitmap(Object *obj, void *opaque)
|
||||
{
|
||||
unsigned long *bitmap = opaque;
|
||||
|
@@ -24,7 +24,6 @@
|
||||
#ifndef _ETSEC_REGISTERS_H_
|
||||
#define _ETSEC_REGISTERS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum eTSEC_Register_Access_Type {
|
||||
ACC_RW = 1, /* Read/Write */
|
||||
|
13
hw/pci/pci.c
13
hw/pci/pci.c
@@ -278,9 +278,9 @@ static void pcibus_reset(BusState *qbus)
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_host_bus_register(PCIBus *bus, DeviceState *parent)
|
||||
static void pci_host_bus_register(DeviceState *host)
|
||||
{
|
||||
PCIHostState *host_bridge = PCI_HOST_BRIDGE(parent);
|
||||
PCIHostState *host_bridge = PCI_HOST_BRIDGE(host);
|
||||
|
||||
QLIST_INSERT_HEAD(&pci_host_bridges, host_bridge, next);
|
||||
}
|
||||
@@ -331,7 +331,6 @@ const char *pci_root_bus_path(PCIDevice *dev)
|
||||
}
|
||||
|
||||
static void pci_bus_init(PCIBus *bus, DeviceState *parent,
|
||||
const char *name,
|
||||
MemoryRegion *address_space_mem,
|
||||
MemoryRegion *address_space_io,
|
||||
uint8_t devfn_min)
|
||||
@@ -344,7 +343,7 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent,
|
||||
/* host bridge */
|
||||
QLIST_INIT(&bus->child);
|
||||
|
||||
pci_host_bus_register(bus, parent);
|
||||
pci_host_bus_register(parent);
|
||||
}
|
||||
|
||||
bool pci_bus_is_express(PCIBus *bus)
|
||||
@@ -364,8 +363,7 @@ void pci_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent,
|
||||
uint8_t devfn_min, const char *typename)
|
||||
{
|
||||
qbus_create_inplace(bus, bus_size, typename, parent, name);
|
||||
pci_bus_init(bus, parent, name, address_space_mem,
|
||||
address_space_io, devfn_min);
|
||||
pci_bus_init(bus, parent, address_space_mem, address_space_io, devfn_min);
|
||||
}
|
||||
|
||||
PCIBus *pci_bus_new(DeviceState *parent, const char *name,
|
||||
@@ -376,8 +374,7 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name,
|
||||
PCIBus *bus;
|
||||
|
||||
bus = PCI_BUS(qbus_create(typename, parent, name));
|
||||
pci_bus_init(bus, parent, name, address_space_mem,
|
||||
address_space_io, devfn_min);
|
||||
pci_bus_init(bus, parent, address_space_mem, address_space_io, devfn_min);
|
||||
return bus;
|
||||
}
|
||||
|
||||
|
@@ -1528,7 +1528,7 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id)
|
||||
section_hdr = qemu_get_be32(f);
|
||||
|
||||
if (section_hdr) {
|
||||
Error *local_err;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* First section gives the htab size */
|
||||
spapr_reallocate_hpt(spapr, section_hdr, &local_err);
|
||||
|
@@ -386,6 +386,65 @@ static target_ulong h_set_xdabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_page_init(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong flags = args[0];
|
||||
hwaddr dst = args[1];
|
||||
hwaddr src = args[2];
|
||||
hwaddr len = TARGET_PAGE_SIZE;
|
||||
uint8_t *pdst, *psrc;
|
||||
target_long ret = H_SUCCESS;
|
||||
|
||||
if (flags & ~(H_ICACHE_SYNCHRONIZE | H_ICACHE_INVALIDATE
|
||||
| H_COPY_PAGE | H_ZERO_PAGE)) {
|
||||
qemu_log_mask(LOG_UNIMP, "h_page_init: Bad flags (" TARGET_FMT_lx "\n",
|
||||
flags);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
/* Map-in destination */
|
||||
if (!is_ram_address(spapr, dst) || (dst & ~TARGET_PAGE_MASK) != 0) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
pdst = cpu_physical_memory_map(dst, &len, 1);
|
||||
if (!pdst || len != TARGET_PAGE_SIZE) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
if (flags & H_COPY_PAGE) {
|
||||
/* Map-in source, copy to destination, and unmap source again */
|
||||
if (!is_ram_address(spapr, src) || (src & ~TARGET_PAGE_MASK) != 0) {
|
||||
ret = H_PARAMETER;
|
||||
goto unmap_out;
|
||||
}
|
||||
psrc = cpu_physical_memory_map(src, &len, 0);
|
||||
if (!psrc || len != TARGET_PAGE_SIZE) {
|
||||
ret = H_PARAMETER;
|
||||
goto unmap_out;
|
||||
}
|
||||
memcpy(pdst, psrc, len);
|
||||
cpu_physical_memory_unmap(psrc, len, 0, len);
|
||||
} else if (flags & H_ZERO_PAGE) {
|
||||
memset(pdst, 0, len); /* Just clear the destination page */
|
||||
}
|
||||
|
||||
if (kvm_enabled() && (flags & H_ICACHE_SYNCHRONIZE) != 0) {
|
||||
kvmppc_dcbst_range(cpu, pdst, len);
|
||||
}
|
||||
if (flags & (H_ICACHE_SYNCHRONIZE | H_ICACHE_INVALIDATE)) {
|
||||
if (kvm_enabled()) {
|
||||
kvmppc_icbi_range(cpu, pdst, len);
|
||||
} else {
|
||||
tb_flush(CPU(cpu));
|
||||
}
|
||||
}
|
||||
|
||||
unmap_out:
|
||||
cpu_physical_memory_unmap(pdst, TARGET_PAGE_SIZE, 1, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define FLAGS_REGISTER_VPA 0x0000200000000000ULL
|
||||
#define FLAGS_REGISTER_DTL 0x0000400000000000ULL
|
||||
#define FLAGS_REGISTER_SLBSHADOW 0x0000600000000000ULL
|
||||
@@ -1045,6 +1104,7 @@ static void hypercall_register_types(void)
|
||||
spapr_register_hypercall(H_SET_SPRG0, h_set_sprg0);
|
||||
spapr_register_hypercall(H_SET_DABR, h_set_dabr);
|
||||
spapr_register_hypercall(H_SET_XDABR, h_set_xdabr);
|
||||
spapr_register_hypercall(H_PAGE_INIT, h_page_init);
|
||||
spapr_register_hypercall(H_SET_MODE, h_set_mode);
|
||||
|
||||
/* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
|
||||
|
@@ -39,14 +39,10 @@ void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread)
|
||||
}
|
||||
}
|
||||
|
||||
static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s,
|
||||
VirtQueue *vq,
|
||||
EventNotifierHandler *handler,
|
||||
int n)
|
||||
static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n)
|
||||
{
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
VirtIOSCSIVring *r;
|
||||
int rc;
|
||||
|
||||
/* Set up virtqueue notify */
|
||||
@@ -55,105 +51,17 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s,
|
||||
fprintf(stderr, "virtio-scsi: Failed to set host notifier (%d)\n",
|
||||
rc);
|
||||
s->dataplane_fenced = true;
|
||||
return NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
r = g_new(VirtIOSCSIVring, 1);
|
||||
r->host_notifier = *virtio_queue_get_host_notifier(vq);
|
||||
r->guest_notifier = *virtio_queue_get_guest_notifier(vq);
|
||||
aio_set_event_notifier(s->ctx, &r->host_notifier, true, handler);
|
||||
|
||||
r->parent = s;
|
||||
|
||||
if (!vring_setup(&r->vring, VIRTIO_DEVICE(s), n)) {
|
||||
fprintf(stderr, "virtio-scsi: VRing setup failed\n");
|
||||
goto fail_vring;
|
||||
}
|
||||
return r;
|
||||
|
||||
fail_vring:
|
||||
aio_set_event_notifier(s->ctx, &r->host_notifier, true, NULL);
|
||||
k->set_host_notifier(qbus->parent, n, false);
|
||||
g_free(r);
|
||||
return NULL;
|
||||
virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, true, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s,
|
||||
VirtIOSCSIVring *vring)
|
||||
void virtio_scsi_dataplane_notify(VirtIODevice *vdev, VirtIOSCSIReq *req)
|
||||
{
|
||||
VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
|
||||
VirtIOSCSIReq *req;
|
||||
|
||||
req = vring_pop((VirtIODevice *)s, &vring->vring,
|
||||
sizeof(VirtIOSCSIReq) + vs->cdb_size);
|
||||
if (!req) {
|
||||
return NULL;
|
||||
}
|
||||
virtio_scsi_init_req(s, NULL, req);
|
||||
req->vring = vring;
|
||||
return req;
|
||||
}
|
||||
|
||||
void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(req->vring->parent);
|
||||
|
||||
vring_push(vdev, &req->vring->vring, &req->elem,
|
||||
req->qsgl.size + req->resp_iov.size);
|
||||
|
||||
if (vring_should_notify(vdev, &req->vring->vring)) {
|
||||
event_notifier_set(&req->vring->guest_notifier);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier)
|
||||
{
|
||||
VirtIOSCSIVring *vring = container_of(notifier,
|
||||
VirtIOSCSIVring, host_notifier);
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(vring->parent);
|
||||
VirtIOSCSIReq *req;
|
||||
|
||||
event_notifier_test_and_clear(notifier);
|
||||
while ((req = virtio_scsi_pop_req_vring(s, vring))) {
|
||||
virtio_scsi_handle_ctrl_req(s, req);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_scsi_iothread_handle_event(EventNotifier *notifier)
|
||||
{
|
||||
VirtIOSCSIVring *vring = container_of(notifier,
|
||||
VirtIOSCSIVring, host_notifier);
|
||||
VirtIOSCSI *s = vring->parent;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
|
||||
event_notifier_test_and_clear(notifier);
|
||||
|
||||
if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->events_dropped) {
|
||||
virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_scsi_iothread_handle_cmd(EventNotifier *notifier)
|
||||
{
|
||||
VirtIOSCSIVring *vring = container_of(notifier,
|
||||
VirtIOSCSIVring, host_notifier);
|
||||
VirtIOSCSI *s = (VirtIOSCSI *)vring->parent;
|
||||
VirtIOSCSIReq *req, *next;
|
||||
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
|
||||
|
||||
event_notifier_test_and_clear(notifier);
|
||||
while ((req = virtio_scsi_pop_req_vring(s, vring))) {
|
||||
if (virtio_scsi_handle_cmd_req_prepare(s, req)) {
|
||||
QTAILQ_INSERT_TAIL(&reqs, req, next);
|
||||
}
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
|
||||
virtio_scsi_handle_cmd_req_submit(s, req);
|
||||
if (virtio_should_notify(vdev, req->vq)) {
|
||||
event_notifier_set(virtio_queue_get_guest_notifier(req->vq));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,46 +71,10 @@ static void virtio_scsi_clear_aio(VirtIOSCSI *s)
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||
int i;
|
||||
|
||||
if (s->ctrl_vring) {
|
||||
aio_set_event_notifier(s->ctx, &s->ctrl_vring->host_notifier,
|
||||
true, NULL);
|
||||
}
|
||||
if (s->event_vring) {
|
||||
aio_set_event_notifier(s->ctx, &s->event_vring->host_notifier,
|
||||
true, NULL);
|
||||
}
|
||||
if (s->cmd_vrings) {
|
||||
for (i = 0; i < vs->conf.num_queues && s->cmd_vrings[i]; i++) {
|
||||
aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier,
|
||||
true, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_scsi_vring_teardown(VirtIOSCSI *s)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||
int i;
|
||||
|
||||
if (s->ctrl_vring) {
|
||||
vring_teardown(&s->ctrl_vring->vring, vdev, 0);
|
||||
g_free(s->ctrl_vring);
|
||||
s->ctrl_vring = NULL;
|
||||
}
|
||||
if (s->event_vring) {
|
||||
vring_teardown(&s->event_vring->vring, vdev, 1);
|
||||
g_free(s->event_vring);
|
||||
s->event_vring = NULL;
|
||||
}
|
||||
if (s->cmd_vrings) {
|
||||
for (i = 0; i < vs->conf.num_queues && s->cmd_vrings[i]; i++) {
|
||||
vring_teardown(&s->cmd_vrings[i]->vring, vdev, 2 + i);
|
||||
g_free(s->cmd_vrings[i]);
|
||||
s->cmd_vrings[i] = NULL;
|
||||
}
|
||||
free(s->cmd_vrings);
|
||||
s->cmd_vrings = NULL;
|
||||
virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, false, false);
|
||||
virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, false, false);
|
||||
for (i = 0; i < vs->conf.num_queues; i++) {
|
||||
virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,30 +101,21 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s)
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "virtio-scsi: Failed to set guest notifiers (%d), "
|
||||
"ensure -enable-kvm is set\n", rc);
|
||||
s->dataplane_fenced = true;
|
||||
goto fail_guest_notifiers;
|
||||
}
|
||||
|
||||
aio_context_acquire(s->ctx);
|
||||
s->ctrl_vring = virtio_scsi_vring_init(s, vs->ctrl_vq,
|
||||
virtio_scsi_iothread_handle_ctrl,
|
||||
0);
|
||||
if (!s->ctrl_vring) {
|
||||
rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0);
|
||||
if (rc) {
|
||||
goto fail_vrings;
|
||||
}
|
||||
s->event_vring = virtio_scsi_vring_init(s, vs->event_vq,
|
||||
virtio_scsi_iothread_handle_event,
|
||||
1);
|
||||
if (!s->event_vring) {
|
||||
rc = virtio_scsi_vring_init(s, vs->event_vq, 1);
|
||||
if (rc) {
|
||||
goto fail_vrings;
|
||||
}
|
||||
s->cmd_vrings = g_new(VirtIOSCSIVring *, vs->conf.num_queues);
|
||||
for (i = 0; i < vs->conf.num_queues; i++) {
|
||||
s->cmd_vrings[i] =
|
||||
virtio_scsi_vring_init(s, vs->cmd_vqs[i],
|
||||
virtio_scsi_iothread_handle_cmd,
|
||||
i + 2);
|
||||
if (!s->cmd_vrings[i]) {
|
||||
rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2);
|
||||
if (rc) {
|
||||
goto fail_vrings;
|
||||
}
|
||||
}
|
||||
@@ -265,13 +128,14 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s)
|
||||
fail_vrings:
|
||||
virtio_scsi_clear_aio(s);
|
||||
aio_context_release(s->ctx);
|
||||
virtio_scsi_vring_teardown(s);
|
||||
for (i = 0; i < vs->conf.num_queues + 2; i++) {
|
||||
k->set_host_notifier(qbus->parent, i, false);
|
||||
}
|
||||
k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
|
||||
fail_guest_notifiers:
|
||||
s->dataplane_fenced = true;
|
||||
s->dataplane_starting = false;
|
||||
s->dataplane_started = true;
|
||||
}
|
||||
|
||||
/* Context: QEMU global mutex held */
|
||||
@@ -282,12 +146,14 @@ void virtio_scsi_dataplane_stop(VirtIOSCSI *s)
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||
int i;
|
||||
|
||||
if (!s->dataplane_started || s->dataplane_stopping) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Better luck next time. */
|
||||
if (s->dataplane_fenced) {
|
||||
s->dataplane_fenced = false;
|
||||
return;
|
||||
}
|
||||
if (!s->dataplane_started || s->dataplane_stopping) {
|
||||
s->dataplane_started = false;
|
||||
return;
|
||||
}
|
||||
s->dataplane_stopping = true;
|
||||
@@ -295,24 +161,12 @@ void virtio_scsi_dataplane_stop(VirtIOSCSI *s)
|
||||
|
||||
aio_context_acquire(s->ctx);
|
||||
|
||||
aio_set_event_notifier(s->ctx, &s->ctrl_vring->host_notifier,
|
||||
true, NULL);
|
||||
aio_set_event_notifier(s->ctx, &s->event_vring->host_notifier,
|
||||
true, NULL);
|
||||
for (i = 0; i < vs->conf.num_queues; i++) {
|
||||
aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier,
|
||||
true, NULL);
|
||||
}
|
||||
virtio_scsi_clear_aio(s);
|
||||
|
||||
blk_drain_all(); /* ensure there are no in-flight requests */
|
||||
|
||||
aio_context_release(s->ctx);
|
||||
|
||||
/* Sync vring state back to virtqueue so that non-dataplane request
|
||||
* processing can continue when we disable the host notifier below.
|
||||
*/
|
||||
virtio_scsi_vring_teardown(s);
|
||||
|
||||
for (i = 0; i < vs->conf.num_queues + 2; i++) {
|
||||
k->set_host_notifier(qbus->parent, i, false);
|
||||
}
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#include <block/scsi.h>
|
||||
#include <hw/virtio/virtio-bus.h>
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "migration/migration.h"
|
||||
|
||||
static inline int virtio_scsi_get_lun(uint8_t *lun)
|
||||
{
|
||||
@@ -43,7 +42,8 @@ static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun)
|
||||
|
||||
void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req)
|
||||
{
|
||||
const size_t zero_skip = offsetof(VirtIOSCSIReq, vring);
|
||||
const size_t zero_skip =
|
||||
offsetof(VirtIOSCSIReq, resp_iov) + sizeof(req->resp_iov);
|
||||
|
||||
req->vq = vq;
|
||||
req->dev = s;
|
||||
@@ -66,11 +66,10 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
|
||||
qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size);
|
||||
if (req->vring) {
|
||||
assert(req->vq == NULL);
|
||||
virtio_scsi_vring_push_notify(req);
|
||||
virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size);
|
||||
if (s->dataplane_started) {
|
||||
virtio_scsi_dataplane_notify(vdev, req);
|
||||
} else {
|
||||
virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size);
|
||||
virtio_notify(vdev, vq);
|
||||
}
|
||||
|
||||
@@ -417,7 +416,7 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
|
||||
VirtIOSCSIReq *req;
|
||||
|
||||
if (s->ctx && !s->dataplane_disabled) {
|
||||
if (s->ctx && !s->dataplane_started) {
|
||||
virtio_scsi_dataplane_start(s);
|
||||
return;
|
||||
}
|
||||
@@ -567,7 +566,7 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
|
||||
VirtIOSCSIReq *req, *next;
|
||||
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
|
||||
|
||||
if (s->ctx && !s->dataplane_disabled) {
|
||||
if (s->ctx && !s->dataplane_started) {
|
||||
virtio_scsi_dataplane_start(s);
|
||||
return;
|
||||
}
|
||||
@@ -687,11 +686,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
|
||||
aio_context_acquire(s->ctx);
|
||||
}
|
||||
|
||||
if (s->dataplane_started) {
|
||||
req = virtio_scsi_pop_req_vring(s, s->event_vring);
|
||||
} else {
|
||||
req = virtio_scsi_pop_req(s, vs->event_vq);
|
||||
}
|
||||
req = virtio_scsi_pop_req(s, vs->event_vq);
|
||||
if (!req) {
|
||||
s->events_dropped = true;
|
||||
goto out;
|
||||
@@ -733,7 +728,7 @@ static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
||||
|
||||
if (s->ctx && !s->dataplane_disabled) {
|
||||
if (s->ctx && !s->dataplane_started) {
|
||||
virtio_scsi_dataplane_start(s);
|
||||
return;
|
||||
}
|
||||
@@ -901,31 +896,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable dataplane thread during live migration since it does not
|
||||
* update the dirty memory bitmap yet.
|
||||
*/
|
||||
static void virtio_scsi_migration_state_changed(Notifier *notifier, void *data)
|
||||
{
|
||||
VirtIOSCSI *s = container_of(notifier, VirtIOSCSI,
|
||||
migration_state_notifier);
|
||||
MigrationState *mig = data;
|
||||
|
||||
if (migration_in_setup(mig)) {
|
||||
if (!s->dataplane_started) {
|
||||
return;
|
||||
}
|
||||
virtio_scsi_dataplane_stop(s);
|
||||
s->dataplane_disabled = true;
|
||||
} else if (migration_has_finished(mig) ||
|
||||
migration_has_failed(mig)) {
|
||||
if (s->dataplane_started) {
|
||||
return;
|
||||
}
|
||||
blk_drain_all(); /* complete in-flight non-dataplane requests */
|
||||
s->dataplane_disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
@@ -956,8 +926,6 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1,
|
||||
virtio_scsi_save, virtio_scsi_load, s);
|
||||
s->migration_state_notifier.notify = virtio_scsi_migration_state_changed;
|
||||
add_migration_state_change_notifier(&s->migration_state_notifier);
|
||||
|
||||
error_setg(&s->blocker, "block device is in use by data plane");
|
||||
|
||||
@@ -991,8 +959,6 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
|
||||
error_free(s->blocker);
|
||||
|
||||
unregister_savevm(dev, "virtio-scsi", s);
|
||||
remove_migration_state_change_notifier(&s->migration_state_notifier);
|
||||
|
||||
virtio_scsi_common_unrealize(dev, errp);
|
||||
}
|
||||
|
||||
|
@@ -198,14 +198,13 @@ static void sdhci_reset(SDHCIState *s)
|
||||
* initialization */
|
||||
memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad);
|
||||
|
||||
if (!s->noeject_quirk) {
|
||||
/* Reset other state based on current card insertion/readonly status */
|
||||
sdhci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
|
||||
sdhci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
|
||||
}
|
||||
/* Reset other state based on current card insertion/readonly status */
|
||||
sdhci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
|
||||
sdhci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
|
||||
|
||||
s->data_count = 0;
|
||||
s->stopped_state = sdhc_not_stopped;
|
||||
s->pending_insert_state = false;
|
||||
}
|
||||
|
||||
static void sdhci_data_transfer(void *opaque);
|
||||
@@ -1097,6 +1096,13 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
|
||||
} else {
|
||||
s->norintsts &= ~SDHC_NIS_ERR;
|
||||
}
|
||||
/* Quirk for Raspberry Pi: pending card insert interrupt
|
||||
* appears when first enabled after power on */
|
||||
if ((s->norintstsen & SDHC_NISEN_INSERT) && s->pending_insert_state) {
|
||||
assert(s->pending_insert_quirk);
|
||||
s->norintsts |= SDHC_NIS_INSERT;
|
||||
s->pending_insert_state = false;
|
||||
}
|
||||
sdhci_update_irq(s);
|
||||
break;
|
||||
case SDHC_NORINTSIGEN:
|
||||
@@ -1183,6 +1189,24 @@ static void sdhci_uninitfn(SDHCIState *s)
|
||||
s->fifo_buffer = NULL;
|
||||
}
|
||||
|
||||
static bool sdhci_pending_insert_vmstate_needed(void *opaque)
|
||||
{
|
||||
SDHCIState *s = opaque;
|
||||
|
||||
return s->pending_insert_state;
|
||||
}
|
||||
|
||||
static const VMStateDescription sdhci_pending_insert_vmstate = {
|
||||
.name = "sdhci/pending-insert",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = sdhci_pending_insert_vmstate_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(pending_insert_state, SDHCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
const VMStateDescription sdhci_vmstate = {
|
||||
.name = "sdhci",
|
||||
.version_id = 1,
|
||||
@@ -1217,7 +1241,11 @@ const VMStateDescription sdhci_vmstate = {
|
||||
VMSTATE_TIMER_PTR(insert_timer, SDHCIState),
|
||||
VMSTATE_TIMER_PTR(transfer_timer, SDHCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
},
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
&sdhci_pending_insert_vmstate,
|
||||
NULL
|
||||
},
|
||||
};
|
||||
|
||||
/* Capabilities registers provide information on supported features of this
|
||||
@@ -1275,7 +1303,8 @@ static Property sdhci_sysbus_properties[] = {
|
||||
DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
|
||||
SDHC_CAPAB_REG_DEFAULT),
|
||||
DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
|
||||
DEFINE_PROP_BOOL("noeject-quirk", SDHCIState, noeject_quirk, false),
|
||||
DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk,
|
||||
false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -1303,6 +1332,10 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp)
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
|
||||
SDHC_REGISTERS_MAP_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
if (s->pending_insert_quirk) {
|
||||
s->pending_insert_state = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
|
@@ -25,7 +25,6 @@ obj-$(CONFIG_OMAP) += omap_gptimer.o
|
||||
obj-$(CONFIG_OMAP) += omap_synctimer.o
|
||||
obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o
|
||||
obj-$(CONFIG_SH4) += sh_timer.o
|
||||
obj-$(CONFIG_TUSB6010) += tusb6010.o
|
||||
obj-$(CONFIG_DIGIC) += digic-timer.o
|
||||
|
||||
obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
|
||||
|
@@ -10,6 +10,8 @@ common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci-sysbus.o
|
||||
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
|
||||
common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o
|
||||
|
||||
obj-$(CONFIG_TUSB6010) += tusb6010.o
|
||||
|
||||
# emulated usb devices
|
||||
common-obj-$(CONFIG_USB) += dev-hub.o
|
||||
common-obj-$(CONFIG_USB) += dev-hid.o
|
||||
|
@@ -129,9 +129,16 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
||||
}
|
||||
|
||||
usb_packet_copy(p, s->setup_buf, p->iov.size);
|
||||
s->setup_index = 0;
|
||||
p->actual_length = 0;
|
||||
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
||||
s->setup_index = 0;
|
||||
if (s->setup_len > sizeof(s->data_buf)) {
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
s->setup_len, sizeof(s->data_buf));
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
|
||||
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
||||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||
@@ -152,13 +159,6 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
||||
}
|
||||
s->setup_state = SETUP_STATE_DATA;
|
||||
} else {
|
||||
if (s->setup_len > sizeof(s->data_buf)) {
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
s->setup_len, sizeof(s->data_buf));
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
if (s->setup_len == 0)
|
||||
s->setup_state = SETUP_STATE_ACK;
|
||||
else
|
||||
@@ -177,7 +177,7 @@ static void do_token_in(USBDevice *s, USBPacket *p)
|
||||
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
||||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
||||
|
||||
|
||||
switch(s->setup_state) {
|
||||
case SETUP_STATE_ACK:
|
||||
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#ifndef QEMU_HW_USB_DESC_H
|
||||
#define QEMU_HW_USB_DESC_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <wchar.h>
|
||||
|
||||
/* binary representation */
|
||||
|
@@ -654,7 +654,8 @@ typedef struct USBNetState {
|
||||
|
||||
static int is_rndis(USBNetState *s)
|
||||
{
|
||||
return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE;
|
||||
return s->dev.config ?
|
||||
s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE : 0;
|
||||
}
|
||||
|
||||
static int ndis_query(USBNetState *s, uint32_t oid,
|
||||
@@ -915,8 +916,9 @@ static int rndis_query_response(USBNetState *s,
|
||||
|
||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||
if (bufoffs + buflen > length)
|
||||
if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||
return USB_RET_STALL;
|
||||
}
|
||||
|
||||
infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
|
||||
bufoffs + (uint8_t *) buf, buflen, infobuf,
|
||||
@@ -961,8 +963,9 @@ static int rndis_set_response(USBNetState *s,
|
||||
|
||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||
if (bufoffs + buflen > length)
|
||||
if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||
return USB_RET_STALL;
|
||||
}
|
||||
|
||||
ret = ndis_set(s, le32_to_cpu(buf->OID),
|
||||
bufoffs + (uint8_t *) buf, buflen);
|
||||
@@ -1212,8 +1215,9 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
||||
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
|
||||
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
|
||||
uint32_t size = le32_to_cpu(msg->DataLength);
|
||||
if (offs + size <= len)
|
||||
if (offs < len && size < len && offs + size <= len) {
|
||||
qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size);
|
||||
}
|
||||
}
|
||||
s->out_ptr -= len;
|
||||
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
|
||||
|
@@ -1347,16 +1347,6 @@ static void ohci_frame_boundary(void *opaque)
|
||||
*/
|
||||
static int ohci_bus_start(OHCIState *ohci)
|
||||
{
|
||||
ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
ohci_frame_boundary,
|
||||
ohci);
|
||||
|
||||
if (ohci->eof_timer == NULL) {
|
||||
trace_usb_ohci_bus_eof_timer_failed(ohci->name);
|
||||
ohci_die(ohci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
trace_usb_ohci_start(ohci->name);
|
||||
|
||||
/* Delay the first SOF event by one frame time as
|
||||
@@ -1373,11 +1363,7 @@ static int ohci_bus_start(OHCIState *ohci)
|
||||
static void ohci_bus_stop(OHCIState *ohci)
|
||||
{
|
||||
trace_usb_ohci_stop(ohci->name);
|
||||
if (ohci->eof_timer) {
|
||||
timer_del(ohci->eof_timer);
|
||||
timer_free(ohci->eof_timer);
|
||||
}
|
||||
ohci->eof_timer = NULL;
|
||||
timer_del(ohci->eof_timer);
|
||||
}
|
||||
|
||||
/* Sets a flag in a port status register but only set it if the port is
|
||||
@@ -1907,6 +1893,9 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
|
||||
usb_packet_init(&ohci->usb_packet);
|
||||
|
||||
ohci->async_td = 0;
|
||||
|
||||
ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
ohci_frame_boundary, ohci);
|
||||
}
|
||||
|
||||
#define TYPE_PCI_OHCI "pci-ohci"
|
||||
@@ -1976,6 +1965,9 @@ static void usb_ohci_exit(PCIDevice *dev)
|
||||
if (!ohci->masterbus) {
|
||||
usb_bus_release(&s->bus);
|
||||
}
|
||||
|
||||
timer_del(s->eof_timer);
|
||||
timer_free(s->eof_timer);
|
||||
}
|
||||
|
||||
static void usb_ohci_reset_pci(DeviceState *d)
|
||||
@@ -2041,23 +2033,13 @@ static bool ohci_eof_timer_needed(void *opaque)
|
||||
{
|
||||
OHCIState *ohci = opaque;
|
||||
|
||||
return ohci->eof_timer != NULL;
|
||||
}
|
||||
|
||||
static int ohci_eof_timer_pre_load(void *opaque)
|
||||
{
|
||||
OHCIState *ohci = opaque;
|
||||
|
||||
ohci_bus_start(ohci);
|
||||
|
||||
return 0;
|
||||
return timer_pending(ohci->eof_timer);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ohci_eof_timer = {
|
||||
.name = "ohci-core/eof-timer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_load = ohci_eof_timer_pre_load,
|
||||
.needed = ohci_eof_timer_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_TIMER_PTR(eof_timer, OHCIState),
|
||||
|
@@ -773,8 +773,22 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
|
||||
bool spd;
|
||||
bool queuing = (q != NULL);
|
||||
uint8_t pid = td->token & 0xff;
|
||||
UHCIAsync *async = uhci_async_find_td(s, td_addr);
|
||||
UHCIAsync *async;
|
||||
|
||||
switch (pid) {
|
||||
case USB_TOKEN_OUT:
|
||||
case USB_TOKEN_SETUP:
|
||||
case USB_TOKEN_IN:
|
||||
break;
|
||||
default:
|
||||
/* invalid pid : frame interrupted */
|
||||
s->status |= UHCI_STS_HCPERR;
|
||||
s->cmd &= ~UHCI_CMD_RS;
|
||||
uhci_update_irq(s);
|
||||
return TD_RESULT_STOP_FRAME;
|
||||
}
|
||||
|
||||
async = uhci_async_find_td(s, td_addr);
|
||||
if (async) {
|
||||
if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
|
||||
assert(q == NULL || q == async->queue);
|
||||
@@ -880,11 +894,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
|
||||
break;
|
||||
|
||||
default:
|
||||
/* invalid pid : frame interrupted */
|
||||
uhci_async_free(async);
|
||||
s->status |= UHCI_STS_HCPERR;
|
||||
uhci_update_irq(s);
|
||||
return TD_RESULT_STOP_FRAME;
|
||||
abort(); /* Never to execute */
|
||||
}
|
||||
|
||||
if (async->packet.status == USB_RET_ASYNC) {
|
||||
|
@@ -11,6 +11,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/vfio/vfio-amd-xgbe.h"
|
||||
|
||||
static void amd_xgbe_realize(DeviceState *dev, Error **errp)
|
||||
|
@@ -2,7 +2,6 @@ common-obj-y += virtio-rng.o
|
||||
common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
|
||||
common-obj-y += virtio-bus.o
|
||||
common-obj-y += virtio-mmio.o
|
||||
obj-$(CONFIG_VIRTIO) += dataplane/
|
||||
|
||||
obj-y += virtio.o virtio-balloon.o
|
||||
obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
|
||||
|
@@ -1 +0,0 @@
|
||||
obj-y += vring.o
|
@@ -1,549 +0,0 @@
|
||||
/* Copyright 2012 Red Hat, Inc.
|
||||
* Copyright IBM, Corp. 2012
|
||||
*
|
||||
* Based on Linux 2.6.39 vhost code:
|
||||
* Copyright (C) 2009 Red Hat, Inc.
|
||||
* Copyright (C) 2006 Rusty Russell IBM Corporation
|
||||
*
|
||||
* Author: Michael S. Tsirkin <mst@redhat.com>
|
||||
* Stefan Hajnoczi <stefanha@redhat.com>
|
||||
*
|
||||
* Inspiration, some code, and most witty comments come from
|
||||
* Documentation/virtual/lguest/lguest.c, by Rusty Russell
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "trace.h"
|
||||
#include "hw/hw.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "hw/virtio/dataplane/vring.h"
|
||||
#include "hw/virtio/dataplane/vring-accessors.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
/* vring_map can be coupled with vring_unmap or (if you still have the
|
||||
* value returned in *mr) memory_region_unref.
|
||||
* Returns NULL on failure.
|
||||
* Callers that can handle a partial mapping must supply mapped_len pointer to
|
||||
* get the actual length mapped.
|
||||
* Passing mapped_len == NULL requires either a full mapping or a failure.
|
||||
*/
|
||||
static void *vring_map(MemoryRegion **mr, hwaddr phys,
|
||||
hwaddr len, hwaddr *mapped_len,
|
||||
bool is_write)
|
||||
{
|
||||
MemoryRegionSection section = memory_region_find(get_system_memory(), phys, len);
|
||||
uint64_t size;
|
||||
|
||||
if (!section.mr) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
size = int128_get64(section.size);
|
||||
assert(size);
|
||||
|
||||
/* Passing mapped_len == NULL requires either a full mapping or a failure. */
|
||||
if (!mapped_len && size < len) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_write && section.readonly) {
|
||||
goto out;
|
||||
}
|
||||
if (!memory_region_is_ram(section.mr)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Ignore regions with dirty logging, we cannot mark them dirty */
|
||||
if (memory_region_get_dirty_log_mask(section.mr)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mapped_len) {
|
||||
*mapped_len = MIN(size, len);
|
||||
}
|
||||
|
||||
*mr = section.mr;
|
||||
return memory_region_get_ram_ptr(section.mr) + section.offset_within_region;
|
||||
|
||||
out:
|
||||
memory_region_unref(section.mr);
|
||||
*mr = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void vring_unmap(void *buffer, bool is_write)
|
||||
{
|
||||
ram_addr_t addr;
|
||||
MemoryRegion *mr;
|
||||
|
||||
mr = qemu_ram_addr_from_host(buffer, &addr);
|
||||
memory_region_unref(mr);
|
||||
}
|
||||
|
||||
/* Map the guest's vring to host memory */
|
||||
bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
|
||||
{
|
||||
struct vring *vr = &vring->vr;
|
||||
hwaddr addr;
|
||||
hwaddr size;
|
||||
void *ptr;
|
||||
|
||||
vring->broken = false;
|
||||
vr->num = virtio_queue_get_num(vdev, n);
|
||||
|
||||
addr = virtio_queue_get_desc_addr(vdev, n);
|
||||
size = virtio_queue_get_desc_size(vdev, n);
|
||||
/* Map the descriptor area as read only */
|
||||
ptr = vring_map(&vring->mr_desc, addr, size, NULL, false);
|
||||
if (!ptr) {
|
||||
error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring desc "
|
||||
"at 0x%" HWADDR_PRIx,
|
||||
size, addr);
|
||||
goto out_err_desc;
|
||||
}
|
||||
vr->desc = ptr;
|
||||
|
||||
addr = virtio_queue_get_avail_addr(vdev, n);
|
||||
size = virtio_queue_get_avail_size(vdev, n);
|
||||
/* Add the size of the used_event_idx */
|
||||
size += sizeof(uint16_t);
|
||||
/* Map the driver area as read only */
|
||||
ptr = vring_map(&vring->mr_avail, addr, size, NULL, false);
|
||||
if (!ptr) {
|
||||
error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring avail "
|
||||
"at 0x%" HWADDR_PRIx,
|
||||
size, addr);
|
||||
goto out_err_avail;
|
||||
}
|
||||
vr->avail = ptr;
|
||||
|
||||
addr = virtio_queue_get_used_addr(vdev, n);
|
||||
size = virtio_queue_get_used_size(vdev, n);
|
||||
/* Add the size of the avail_event_idx */
|
||||
size += sizeof(uint16_t);
|
||||
/* Map the device area as read-write */
|
||||
ptr = vring_map(&vring->mr_used, addr, size, NULL, true);
|
||||
if (!ptr) {
|
||||
error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring used "
|
||||
"at 0x%" HWADDR_PRIx,
|
||||
size, addr);
|
||||
goto out_err_used;
|
||||
}
|
||||
vr->used = ptr;
|
||||
|
||||
vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n);
|
||||
vring->last_used_idx = vring_get_used_idx(vdev, vring);
|
||||
vring->signalled_used = 0;
|
||||
vring->signalled_used_valid = false;
|
||||
|
||||
trace_vring_setup(virtio_queue_get_ring_addr(vdev, n),
|
||||
vring->vr.desc, vring->vr.avail, vring->vr.used);
|
||||
return true;
|
||||
|
||||
out_err_used:
|
||||
memory_region_unref(vring->mr_avail);
|
||||
out_err_avail:
|
||||
memory_region_unref(vring->mr_desc);
|
||||
out_err_desc:
|
||||
vring->broken = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
|
||||
{
|
||||
virtio_queue_set_last_avail_idx(vdev, n, vring->last_avail_idx);
|
||||
virtio_queue_invalidate_signalled_used(vdev, n);
|
||||
|
||||
memory_region_unref(vring->mr_desc);
|
||||
memory_region_unref(vring->mr_avail);
|
||||
memory_region_unref(vring->mr_used);
|
||||
}
|
||||
|
||||
/* Disable guest->host notifies */
|
||||
void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
|
||||
{
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
vring_set_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable guest->host notifies
|
||||
*
|
||||
* Return true if the vring is empty, false if there are more requests.
|
||||
*/
|
||||
bool vring_enable_notification(VirtIODevice *vdev, Vring *vring)
|
||||
{
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
vring_avail_event(&vring->vr) = vring->vr.avail->idx;
|
||||
} else {
|
||||
vring_clear_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY);
|
||||
}
|
||||
smp_mb(); /* ensure update is seen before reading avail_idx */
|
||||
return !vring_more_avail(vdev, vring);
|
||||
}
|
||||
|
||||
/* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */
|
||||
bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
|
||||
{
|
||||
uint16_t old, new;
|
||||
bool v;
|
||||
/* Flush out used index updates. This is paired
|
||||
* with the barrier that the Guest executes when enabling
|
||||
* interrupts. */
|
||||
smp_mb();
|
||||
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
|
||||
unlikely(!vring_more_avail(vdev, vring))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
return !(vring_get_avail_flags(vdev, vring) &
|
||||
VRING_AVAIL_F_NO_INTERRUPT);
|
||||
}
|
||||
old = vring->signalled_used;
|
||||
v = vring->signalled_used_valid;
|
||||
new = vring->signalled_used = vring->last_used_idx;
|
||||
vring->signalled_used_valid = true;
|
||||
|
||||
if (unlikely(!v)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return vring_need_event(virtio_tswap16(vdev, vring_used_event(&vring->vr)),
|
||||
new, old);
|
||||
}
|
||||
|
||||
typedef struct VirtQueueCurrentElement {
|
||||
unsigned in_num;
|
||||
unsigned out_num;
|
||||
hwaddr addr[VIRTQUEUE_MAX_SIZE];
|
||||
struct iovec iov[VIRTQUEUE_MAX_SIZE];
|
||||
} VirtQueueCurrentElement;
|
||||
|
||||
static int get_desc(Vring *vring, VirtQueueCurrentElement *elem,
|
||||
struct vring_desc *desc)
|
||||
{
|
||||
unsigned *num;
|
||||
struct iovec *iov;
|
||||
hwaddr *addr;
|
||||
MemoryRegion *mr;
|
||||
hwaddr len;
|
||||
|
||||
if (desc->flags & VRING_DESC_F_WRITE) {
|
||||
num = &elem->in_num;
|
||||
iov = &elem->iov[elem->out_num + *num];
|
||||
addr = &elem->addr[elem->out_num + *num];
|
||||
} else {
|
||||
num = &elem->out_num;
|
||||
iov = &elem->iov[*num];
|
||||
addr = &elem->addr[*num];
|
||||
|
||||
/* If it's an output descriptor, they're all supposed
|
||||
* to come before any input descriptors. */
|
||||
if (unlikely(elem->in_num)) {
|
||||
error_report("Descriptor has out after in");
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
while (desc->len) {
|
||||
/* Stop for now if there are not enough iovecs available. */
|
||||
if (*num >= VIRTQUEUE_MAX_SIZE) {
|
||||
error_report("Invalid SG num: %u", *num);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
iov->iov_base = vring_map(&mr, desc->addr, desc->len, &len,
|
||||
desc->flags & VRING_DESC_F_WRITE);
|
||||
if (!iov->iov_base) {
|
||||
error_report("Failed to map descriptor addr %#" PRIx64 " len %u",
|
||||
(uint64_t)desc->addr, desc->len);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* The MemoryRegion is looked up again and unref'ed later, leave the
|
||||
* ref in place. */
|
||||
(iov++)->iov_len = len;
|
||||
*addr++ = desc->addr;
|
||||
desc->len -= len;
|
||||
desc->addr += len;
|
||||
*num += 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void copy_in_vring_desc(VirtIODevice *vdev,
|
||||
const struct vring_desc *guest,
|
||||
struct vring_desc *host)
|
||||
{
|
||||
host->addr = virtio_ldq_p(vdev, &guest->addr);
|
||||
host->len = virtio_ldl_p(vdev, &guest->len);
|
||||
host->flags = virtio_lduw_p(vdev, &guest->flags);
|
||||
host->next = virtio_lduw_p(vdev, &guest->next);
|
||||
}
|
||||
|
||||
static bool read_vring_desc(VirtIODevice *vdev,
|
||||
hwaddr guest,
|
||||
struct vring_desc *host)
|
||||
{
|
||||
if (address_space_read(&address_space_memory, guest, MEMTXATTRS_UNSPECIFIED,
|
||||
(uint8_t *)host, sizeof *host)) {
|
||||
return false;
|
||||
}
|
||||
host->addr = virtio_tswap64(vdev, host->addr);
|
||||
host->len = virtio_tswap32(vdev, host->len);
|
||||
host->flags = virtio_tswap16(vdev, host->flags);
|
||||
host->next = virtio_tswap16(vdev, host->next);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This is stolen from linux/drivers/vhost/vhost.c. */
|
||||
static int get_indirect(VirtIODevice *vdev, Vring *vring,
|
||||
VirtQueueCurrentElement *cur_elem,
|
||||
struct vring_desc *indirect)
|
||||
{
|
||||
struct vring_desc desc;
|
||||
unsigned int i = 0, count, found = 0;
|
||||
int ret;
|
||||
|
||||
/* Sanity check */
|
||||
if (unlikely(indirect->len % sizeof(desc))) {
|
||||
error_report("Invalid length in indirect descriptor: "
|
||||
"len %#x not multiple of %#zx",
|
||||
indirect->len, sizeof(desc));
|
||||
vring->broken = true;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
count = indirect->len / sizeof(desc);
|
||||
/* Buffers are chained via a 16 bit next field, so
|
||||
* we can have at most 2^16 of these. */
|
||||
if (unlikely(count > USHRT_MAX + 1)) {
|
||||
error_report("Indirect buffer length too big: %d", indirect->len);
|
||||
vring->broken = true;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
do {
|
||||
/* Translate indirect descriptor */
|
||||
if (!read_vring_desc(vdev, indirect->addr + found * sizeof(desc),
|
||||
&desc)) {
|
||||
error_report("Failed to read indirect descriptor "
|
||||
"addr %#" PRIx64 " len %zu",
|
||||
(uint64_t)indirect->addr + found * sizeof(desc),
|
||||
sizeof(desc));
|
||||
vring->broken = true;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Ensure descriptor has been loaded before accessing fields */
|
||||
barrier(); /* read_barrier_depends(); */
|
||||
|
||||
if (unlikely(++found > count)) {
|
||||
error_report("Loop detected: last one at %u "
|
||||
"indirect size %u", i, count);
|
||||
vring->broken = true;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) {
|
||||
error_report("Nested indirect descriptor");
|
||||
vring->broken = true;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ret = get_desc(vring, cur_elem, &desc);
|
||||
if (ret < 0) {
|
||||
vring->broken |= (ret == -EFAULT);
|
||||
return ret;
|
||||
}
|
||||
i = desc.next;
|
||||
} while (desc.flags & VRING_DESC_F_NEXT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vring_unmap_element(VirtQueueElement *elem)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* This assumes that the iovecs, if changed, are never moved past
|
||||
* the end of the valid area. This is true if iovec manipulations
|
||||
* are done with iov_discard_front and iov_discard_back.
|
||||
*/
|
||||
for (i = 0; i < elem->out_num; i++) {
|
||||
vring_unmap(elem->out_sg[i].iov_base, false);
|
||||
}
|
||||
|
||||
for (i = 0; i < elem->in_num; i++) {
|
||||
vring_unmap(elem->in_sg[i].iov_base, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* This looks in the virtqueue and for the first available buffer, and converts
|
||||
* it to an iovec for convenient access. Since descriptors consist of some
|
||||
* number of output then some number of input descriptors, it's actually two
|
||||
* iovecs, but we pack them into one and note how many of each there were.
|
||||
*
|
||||
* This function returns the descriptor number found, or vq->num (which is
|
||||
* never a valid descriptor number) if none was found. A negative code is
|
||||
* returned on error.
|
||||
*
|
||||
* Stolen from linux/drivers/vhost/vhost.c.
|
||||
*/
|
||||
void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz)
|
||||
{
|
||||
struct vring_desc desc;
|
||||
unsigned int i, head, found = 0, num = vring->vr.num;
|
||||
uint16_t avail_idx, last_avail_idx;
|
||||
VirtQueueCurrentElement cur_elem;
|
||||
VirtQueueElement *elem = NULL;
|
||||
int ret;
|
||||
|
||||
/* If there was a fatal error then refuse operation */
|
||||
if (vring->broken) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cur_elem.in_num = cur_elem.out_num = 0;
|
||||
|
||||
/* Check it isn't doing very strange things with descriptor numbers. */
|
||||
last_avail_idx = vring->last_avail_idx;
|
||||
avail_idx = vring_get_avail_idx(vdev, vring);
|
||||
barrier(); /* load indices now and not again later */
|
||||
|
||||
if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) {
|
||||
error_report("Guest moved used index from %u to %u",
|
||||
last_avail_idx, avail_idx);
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If there's nothing new since last we looked. */
|
||||
if (avail_idx == last_avail_idx) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Only get avail ring entries after they have been exposed by guest. */
|
||||
smp_rmb();
|
||||
|
||||
/* Grab the next descriptor number they're advertising, and increment
|
||||
* the index we've seen. */
|
||||
head = vring_get_avail_ring(vdev, vring, last_avail_idx % num);
|
||||
|
||||
/* If their number is silly, that's an error. */
|
||||
if (unlikely(head >= num)) {
|
||||
error_report("Guest says index %u > %u is available", head, num);
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = head;
|
||||
do {
|
||||
if (unlikely(i >= num)) {
|
||||
error_report("Desc index is %u > %u, head = %u", i, num, head);
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (unlikely(++found > num)) {
|
||||
error_report("Loop detected: last one at %u vq size %u head %u",
|
||||
i, num, head);
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
copy_in_vring_desc(vdev, &vring->vr.desc[i], &desc);
|
||||
|
||||
/* Ensure descriptor is loaded before accessing fields */
|
||||
barrier();
|
||||
|
||||
if (desc.flags & VRING_DESC_F_INDIRECT) {
|
||||
ret = get_indirect(vdev, vring, &cur_elem, &desc);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = get_desc(vring, &cur_elem, &desc);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = desc.next;
|
||||
} while (desc.flags & VRING_DESC_F_NEXT);
|
||||
|
||||
/* On success, increment avail index. */
|
||||
vring->last_avail_idx++;
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
vring_avail_event(&vring->vr) =
|
||||
virtio_tswap16(vdev, vring->last_avail_idx);
|
||||
}
|
||||
|
||||
/* Now copy what we have collected and mapped */
|
||||
elem = virtqueue_alloc_element(sz, cur_elem.out_num, cur_elem.in_num);
|
||||
elem->index = head;
|
||||
for (i = 0; i < cur_elem.out_num; i++) {
|
||||
elem->out_addr[i] = cur_elem.addr[i];
|
||||
elem->out_sg[i] = cur_elem.iov[i];
|
||||
}
|
||||
for (i = 0; i < cur_elem.in_num; i++) {
|
||||
elem->in_addr[i] = cur_elem.addr[cur_elem.out_num + i];
|
||||
elem->in_sg[i] = cur_elem.iov[cur_elem.out_num + i];
|
||||
}
|
||||
|
||||
return elem;
|
||||
|
||||
out:
|
||||
assert(ret < 0);
|
||||
if (ret == -EFAULT) {
|
||||
vring->broken = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < cur_elem.out_num + cur_elem.in_num; i++) {
|
||||
vring_unmap(cur_elem.iov[i].iov_base, false);
|
||||
}
|
||||
|
||||
g_free(elem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* After we've used one of their buffers, we tell them about it.
|
||||
*
|
||||
* Stolen from linux/drivers/vhost/vhost.c.
|
||||
*/
|
||||
void vring_push(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem,
|
||||
int len)
|
||||
{
|
||||
unsigned int head = elem->index;
|
||||
uint16_t new;
|
||||
|
||||
vring_unmap_element(elem);
|
||||
|
||||
/* Don't touch vring if a fatal error occurred */
|
||||
if (vring->broken) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* The virtqueue contains a ring of used buffers. Get a pointer to the
|
||||
* next entry in that used ring. */
|
||||
vring_set_used_ring_id(vdev, vring, vring->last_used_idx % vring->vr.num,
|
||||
head);
|
||||
vring_set_used_ring_len(vdev, vring, vring->last_used_idx % vring->vr.num,
|
||||
len);
|
||||
|
||||
/* Make sure buffer is written before we update index. */
|
||||
smp_wmb();
|
||||
|
||||
new = ++vring->last_used_idx;
|
||||
vring_set_used_idx(vdev, vring, new);
|
||||
if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)) {
|
||||
vring->signalled_used_valid = false;
|
||||
}
|
||||
}
|
@@ -611,6 +611,25 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool vhost_user_can_merge(struct vhost_dev *dev,
|
||||
uint64_t start1, uint64_t size1,
|
||||
uint64_t start2, uint64_t size2)
|
||||
{
|
||||
ram_addr_t ram_addr;
|
||||
int mfd, rfd;
|
||||
MemoryRegion *mr;
|
||||
|
||||
mr = qemu_ram_addr_from_host((void *)(uintptr_t)start1, &ram_addr);
|
||||
assert(mr);
|
||||
mfd = qemu_get_ram_fd(ram_addr);
|
||||
|
||||
mr = qemu_ram_addr_from_host((void *)(uintptr_t)start2, &ram_addr);
|
||||
assert(mr);
|
||||
rfd = qemu_get_ram_fd(ram_addr);
|
||||
|
||||
return mfd == rfd;
|
||||
}
|
||||
|
||||
const VhostOps user_ops = {
|
||||
.backend_type = VHOST_BACKEND_TYPE_USER,
|
||||
.vhost_backend_init = vhost_user_init,
|
||||
@@ -633,4 +652,5 @@ const VhostOps user_ops = {
|
||||
.vhost_set_vring_enable = vhost_user_set_vring_enable,
|
||||
.vhost_requires_shm_log = vhost_user_requires_shm_log,
|
||||
.vhost_migration_done = vhost_user_migration_done,
|
||||
.vhost_backend_can_merge = vhost_user_can_merge,
|
||||
};
|
||||
|
@@ -260,6 +260,13 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dev->vhost_ops->vhost_backend_can_merge &&
|
||||
!dev->vhost_ops->vhost_backend_can_merge(dev, uaddr, size,
|
||||
reg->userspace_addr,
|
||||
reg->memory_size)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (merged) {
|
||||
--to;
|
||||
assert(to >= 0);
|
||||
|
@@ -305,6 +305,39 @@ static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
|
||||
memcpy(config_data, &config, sizeof(struct virtio_balloon_config));
|
||||
}
|
||||
|
||||
static int build_dimm_list(Object *obj, void *opaque)
|
||||
{
|
||||
GSList **list = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
if (dev->realized) { /* only realized DIMMs matter */
|
||||
*list = g_slist_prepend(*list, dev);
|
||||
}
|
||||
}
|
||||
|
||||
object_child_foreach(obj, build_dimm_list, opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ram_addr_t get_current_ram_size(void)
|
||||
{
|
||||
GSList *list = NULL, *item;
|
||||
ram_addr_t size = ram_size;
|
||||
|
||||
build_dimm_list(qdev_get_machine(), &list);
|
||||
for (item = list; item; item = g_slist_next(item)) {
|
||||
Object *obj = OBJECT(item->data);
|
||||
if (!strcmp(object_get_typename(obj), TYPE_PC_DIMM)) {
|
||||
size += object_property_get_int(obj, PC_DIMM_SIZE_PROP,
|
||||
&error_abort);
|
||||
}
|
||||
}
|
||||
g_slist_free(list);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void virtio_balloon_set_config(VirtIODevice *vdev,
|
||||
const uint8_t *config_data)
|
||||
{
|
||||
|
@@ -1162,7 +1162,7 @@ void virtio_irq(VirtQueue *vq)
|
||||
virtio_notify_vector(vq->vdev, vq->vector);
|
||||
}
|
||||
|
||||
static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
uint16_t old, new;
|
||||
bool v;
|
||||
@@ -1187,7 +1187,7 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
|
||||
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
if (!vring_notify(vdev, vq)) {
|
||||
if (!virtio_should_notify(vdev, vq)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1786,6 +1786,22 @@ static void virtio_queue_host_notifier_read(EventNotifier *n)
|
||||
}
|
||||
}
|
||||
|
||||
void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
|
||||
bool assign, bool set_handler)
|
||||
{
|
||||
if (assign && set_handler) {
|
||||
aio_set_event_notifier(ctx, &vq->host_notifier, true,
|
||||
virtio_queue_host_notifier_read);
|
||||
} else {
|
||||
aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL);
|
||||
}
|
||||
if (!assign) {
|
||||
/* Test and clear notifier before after disabling event,
|
||||
* in case poll callback didn't have time to run. */
|
||||
virtio_queue_host_notifier_read(&vq->host_notifier);
|
||||
}
|
||||
}
|
||||
|
||||
void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
|
||||
bool set_handler)
|
||||
{
|
||||
|
@@ -25,8 +25,6 @@
|
||||
#ifndef BLOCK_ACCOUNTING_H
|
||||
#define BLOCK_ACCOUNTING_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "qemu/typedefs.h"
|
||||
#include "qemu/timed-average.h"
|
||||
|
@@ -19,7 +19,6 @@
|
||||
#ifndef NBD_H
|
||||
#define NBD_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/option.h"
|
||||
|
@@ -26,7 +26,6 @@
|
||||
#define SNAPSHOT_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/option.h"
|
||||
|
||||
|
||||
|
@@ -12,7 +12,6 @@
|
||||
#ifndef BLOCK_WRITE_THRESHOLD_H
|
||||
#define BLOCK_WRITE_THRESHOLD_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "qemu/typedefs.h"
|
||||
#include "qemu-common.h"
|
||||
|
@@ -1,2 +1 @@
|
||||
#include "config-host.h"
|
||||
#include "config-target.h"
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#define QCRYPTO_CIPHER_H__
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
typedef struct QCryptoCipher QCryptoCipher;
|
||||
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#define QCRYPTO_HASH_H__
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
/* See also "QCryptoHashAlgorithm" defined in qapi/crypto.json */
|
||||
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#define QCRYPTO_INIT_H__
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
int qcrypto_init(Error **errp);
|
||||
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#define QCRYPTO_SECRET_H__
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_QCRYPTO_SECRET "secret"
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#define QCRYPTO_TLSCRED_H__
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#ifdef CONFIG_GNUTLS
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#ifndef _QEMU_ELF_H
|
||||
#define _QEMU_ELF_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* 32-bit ELF base types. */
|
||||
typedef uint32_t Elf32_Addr;
|
||||
|
@@ -154,7 +154,6 @@ static inline void tswap64s(uint64_t *s)
|
||||
/* MMU memory access macros */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#include <assert.h>
|
||||
#include "exec/user/abitypes.h"
|
||||
|
||||
/* On some host systems the guest address space is reserved on the host.
|
||||
|
@@ -54,7 +54,6 @@ typedef uintptr_t ram_addr_t;
|
||||
#endif
|
||||
|
||||
extern ram_addr_t ram_size;
|
||||
ram_addr_t get_current_ram_size(void);
|
||||
|
||||
/* memory API */
|
||||
|
||||
|
@@ -23,9 +23,6 @@
|
||||
#error cpu.h included from common code
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <inttypes.h>
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "tcg-target.h"
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
@@ -18,7 +18,6 @@
|
||||
#ifndef DEF_HELPER_H
|
||||
#define DEF_HELPER_H 1
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#define HELPER(name) glue(helper_, name)
|
||||
|
||||
|
@@ -21,8 +21,6 @@
|
||||
#define DIRTY_MEMORY_MIGRATION 2
|
||||
#define DIRTY_MEMORY_NUM 3 /* num of dirty bits */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "exec/cpu-common.h"
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#include "exec/hwaddr.h"
|
||||
@@ -31,9 +29,9 @@
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/int128.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "qemu/typedefs.h"
|
||||
|
||||
#define MAX_PHYS_ADDR_SPACE_BITS 62
|
||||
#define MAX_PHYS_ADDR (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) - 1)
|
||||
@@ -172,6 +170,7 @@ struct MemoryRegion {
|
||||
bool global_locking;
|
||||
uint8_t dirty_log_mask;
|
||||
ram_addr_t ram_addr;
|
||||
RAMBlock *ram_block;
|
||||
Object *owner;
|
||||
const MemoryRegionIOMMUOps *iommu_ops;
|
||||
|
||||
@@ -1389,7 +1388,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
|
||||
MemoryRegion *mr);
|
||||
MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf, int len);
|
||||
void *qemu_get_ram_ptr(ram_addr_t addr);
|
||||
void *qemu_get_ram_ptr(RAMBlock *ram_block, ram_addr_t addr);
|
||||
|
||||
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||
{
|
||||
@@ -1398,8 +1397,6 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||
} else {
|
||||
return memory_region_is_ram(mr) || memory_region_is_romd(mr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1430,7 +1427,7 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||
if (len == l && memory_access_is_direct(mr, false)) {
|
||||
addr1 += memory_region_get_ram_addr(mr);
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
|
||||
memcpy(buf, ptr, len);
|
||||
} else {
|
||||
result = address_space_read_continue(as, addr, attrs, buf, len,
|
||||
|
@@ -19,7 +19,6 @@
|
||||
#ifndef THUNK_H
|
||||
#define THUNK_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "cpu.h"
|
||||
|
||||
/* types enums definitions */
|
||||
|
@@ -86,9 +86,6 @@ this code that are retained.
|
||||
#include <sunmath.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "config-host.h"
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
/* This 'flag' type must be able to hold at least 0 and 1. It should
|
||||
* probably be replaced with 'bool' but the uses would need to be audited
|
||||
@@ -362,10 +359,10 @@ extern const float16 float16_default_nan;
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE single-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int_fast16_t float32_to_int16(float32, float_status *status);
|
||||
uint_fast16_t float32_to_uint16(float32, float_status *status);
|
||||
int_fast16_t float32_to_int16_round_to_zero(float32, float_status *status);
|
||||
uint_fast16_t float32_to_uint16_round_to_zero(float32, float_status *status);
|
||||
int16_t float32_to_int16(float32, float_status *status);
|
||||
uint16_t float32_to_uint16(float32, float_status *status);
|
||||
int16_t float32_to_int16_round_to_zero(float32, float_status *status);
|
||||
uint16_t float32_to_uint16_round_to_zero(float32, float_status *status);
|
||||
int32_t float32_to_int32(float32, float_status *status);
|
||||
int32_t float32_to_int32_round_to_zero(float32, float_status *status);
|
||||
uint32_t float32_to_uint32(float32, float_status *status);
|
||||
@@ -474,10 +471,10 @@ extern const float32 float32_default_nan;
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE double-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int_fast16_t float64_to_int16(float64, float_status *status);
|
||||
uint_fast16_t float64_to_uint16(float64, float_status *status);
|
||||
int_fast16_t float64_to_int16_round_to_zero(float64, float_status *status);
|
||||
uint_fast16_t float64_to_uint16_round_to_zero(float64, float_status *status);
|
||||
int16_t float64_to_int16(float64, float_status *status);
|
||||
uint16_t float64_to_uint16(float64, float_status *status);
|
||||
int16_t float64_to_int16_round_to_zero(float64, float_status *status);
|
||||
uint16_t float64_to_uint16_round_to_zero(float64, float_status *status);
|
||||
int32_t float64_to_int32(float64, float_status *status);
|
||||
int32_t float64_to_int32_round_to_zero(float64, float_status *status);
|
||||
uint32_t float64_to_uint32(float64, float_status *status);
|
||||
|
@@ -19,7 +19,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/typedefs.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "qemu/option.h"
|
||||
|
@@ -1,9 +1,7 @@
|
||||
#ifndef HW_ACPI_GEN_UTILS_H
|
||||
#define HW_ACPI_GEN_UTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <glib.h>
|
||||
#include "qemu/compiler.h"
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
|
||||
/* Reserve RAM space for tables: add another order of magnitude. */
|
||||
|
@@ -2,8 +2,6 @@
|
||||
#define BIOS_LINKER_LOADER_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
GArray *bios_linker_loader_init(void);
|
||||
|
||||
@@ -13,7 +11,7 @@ void bios_linker_loader_alloc(GArray *linker,
|
||||
bool alloc_fseg);
|
||||
|
||||
void bios_linker_loader_add_checksum(GArray *linker, const char *file,
|
||||
void *table,
|
||||
GArray *table,
|
||||
void *start, unsigned size,
|
||||
uint8_t *checksum);
|
||||
|
||||
|
@@ -62,7 +62,6 @@ typedef struct ICH9LPCPMRegs {
|
||||
|
||||
void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
||||
bool smm_enabled,
|
||||
bool enable_tco,
|
||||
qemu_irq sci_irq);
|
||||
|
||||
void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base);
|
||||
|
@@ -27,7 +27,6 @@
|
||||
#ifndef HW_ACPI_PCIHP_H
|
||||
#define HW_ACPI_PCIHP_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <qemu/typedefs.h>
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
@@ -12,7 +12,6 @@
|
||||
#define HW_BLOCK_COMMON_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
/* Configuration */
|
||||
|
||||
|
@@ -84,7 +84,6 @@ struct MachineClass {
|
||||
no_cdrom:1,
|
||||
no_sdcard:1,
|
||||
has_dynamic_sysbus:1,
|
||||
no_tco:1,
|
||||
pci_allow_0_address:1;
|
||||
int is_default;
|
||||
const char *default_machine_opts;
|
||||
|
@@ -17,7 +17,7 @@
|
||||
void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
|
||||
int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
|
||||
PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
|
||||
void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled, bool enable_tco);
|
||||
void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled);
|
||||
I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
|
||||
|
||||
void ich9_generate_smi(void);
|
||||
|
@@ -38,8 +38,6 @@
|
||||
* CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width().
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qemu/bitops.h"
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#ifndef APM_H
|
||||
#define APM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "qemu-common.h"
|
||||
#include "hw/hw.h"
|
||||
#include "exec/memory.h"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user