Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4c53d94d2 | ||
|
|
159fe82dea | ||
|
|
a8f2299d1b | ||
|
|
68fc5d1d27 | ||
|
|
3e1954cb4a | ||
|
|
14bdf978ef | ||
|
|
806d996789 | ||
|
|
d893e56f72 | ||
|
|
240f68ce5b | ||
|
|
ee0999b16a | ||
|
|
57f8a4c507 | ||
|
|
b83465006d | ||
|
|
d80210efbc | ||
|
|
513cdda198 | ||
|
|
eea54caab0 | ||
|
|
78fd27b3b6 | ||
|
|
d4413913e1 | ||
|
|
61dea8e914 | ||
|
|
a2aad5fdc4 | ||
|
|
5730401442 | ||
|
|
f3e9893078 | ||
|
|
4d0fcc1968 | ||
|
|
2b9a5aca51 | ||
|
|
96d90d32ac | ||
|
|
3c980e22ac | ||
|
|
907a34c9d7 | ||
|
|
b79ba45af1 | ||
|
|
75a44ae297 | ||
|
|
ff498e4a0d | ||
|
|
394a2f28cb | ||
|
|
60088e5b83 | ||
|
|
ae06193d73 | ||
|
|
e8ca4a8ac7 | ||
|
|
68958c31b5 | ||
|
|
584717a39a | ||
|
|
85368b79a0 | ||
|
|
36d7fb299a | ||
|
|
3412955066 | ||
|
|
b52c8f78f2 | ||
|
|
668194d5a5 | ||
|
|
8484fead29 | ||
|
|
57683d6354 | ||
|
|
5d6ad6262b | ||
|
|
a63eb7a227 | ||
|
|
a638498f51 | ||
|
|
9d72a090b2 | ||
|
|
ab52df7712 | ||
|
|
5c8240c09c | ||
|
|
d8f4811880 | ||
|
|
2747a3eee3 | ||
|
|
aa69dd05ce | ||
|
|
a9d8f7b1c4 | ||
|
|
0d91cd5aa7 | ||
|
|
bfa23099aa | ||
|
|
65a2f8e27c | ||
|
|
7575a6d2f2 | ||
|
|
8e9fdc4a88 | ||
|
|
ca54dc1e75 | ||
|
|
a78cedc09e | ||
|
|
59a01f73c3 | ||
|
|
c6553fee81 | ||
|
|
a0d718a395 | ||
|
|
34173da021 | ||
|
|
c23314334d | ||
|
|
b83f395ba1 | ||
|
|
34f7e690c3 | ||
|
|
6116adbc0e | ||
|
|
3ed791b42d | ||
|
|
2ee160f8e1 | ||
|
|
981e213cf7 | ||
|
|
d56d7e6ef8 | ||
|
|
ad2cea3878 | ||
|
|
d28ed2ffbb | ||
|
|
bffb221775 | ||
|
|
9cf4af689b | ||
|
|
f9f552e80b | ||
|
|
7cf7e305cc | ||
|
|
84a2ca9f90 | ||
|
|
1c224f0ab3 | ||
|
|
1e32a1651a | ||
|
|
3900d1d992 | ||
|
|
1fce4135f3 | ||
|
|
349b4e9070 | ||
|
|
29ecaa26a8 | ||
|
|
1f97f6c9fe | ||
|
|
9a5a94de58 | ||
|
|
462ff6fda1 | ||
|
|
b26859ab18 | ||
|
|
03c0342cb8 | ||
|
|
23ba9d4838 | ||
|
|
640bda8df5 | ||
|
|
64022e9d58 | ||
|
|
3e3750e10a | ||
|
|
fbcb89ddc9 | ||
|
|
22ba7a7488 | ||
|
|
636071de92 | ||
|
|
55a2f465b9 | ||
|
|
aa57b628e0 | ||
|
|
57eae744d4 | ||
|
|
14ecfb09fa | ||
|
|
1d5ba9a6a8 | ||
|
|
77c3d59256 | ||
|
|
e2ab86fe2d | ||
|
|
2f7ba4731b | ||
|
|
0154d330c7 | ||
|
|
d294ad6323 | ||
|
|
62fc5e6983 | ||
|
|
4a6cdb4807 | ||
|
|
a8cf10d5d6 | ||
|
|
307fea863a | ||
|
|
c15d61b252 | ||
|
|
712fc762a6 | ||
|
|
a37d5e521a | ||
|
|
d6e508d3a5 | ||
|
|
d780116ab0 | ||
|
|
597330bd8d | ||
|
|
4ebbf3229a | ||
|
|
b5701820f8 | ||
|
|
5af6b07ab0 | ||
|
|
82645b9e93 | ||
|
|
b750d22466 | ||
|
|
bd4dba6658 | ||
|
|
7566759fd5 | ||
|
|
47b11da1e9 | ||
|
|
2ecd8831e0 | ||
|
|
27aae39fa0 | ||
|
|
635cc81bf9 | ||
|
|
4de6467cbc | ||
|
|
4382057785 | ||
|
|
6ac46e3216 | ||
|
|
3aec24d195 | ||
|
|
122b92d90a | ||
|
|
23086b2054 | ||
|
|
ea4c86551d | ||
|
|
b75c710575 | ||
|
|
5b7582af06 | ||
|
|
615198836c | ||
|
|
7908e4a388 | ||
|
|
38a01d68c6 | ||
|
|
986b9a1a2a | ||
|
|
25bc2251eb | ||
|
|
fc24f3bd2e | ||
|
|
3c82758f04 | ||
|
|
7fd494086b | ||
|
|
e46258fb50 | ||
|
|
c90a8840b4 | ||
|
|
e1312991ed | ||
|
|
6c975d03a2 | ||
|
|
df6502fac5 | ||
|
|
fef28a4336 | ||
|
|
38df9027ce | ||
|
|
ba8b16fac5 | ||
|
|
39cbcb4b45 | ||
|
|
db0cfd14ba | ||
|
|
5c7199f164 | ||
|
|
60db655378 | ||
|
|
757ee3f9e2 | ||
|
|
e85ec822e9 | ||
|
|
181dd0b27c | ||
|
|
e1784a4cbd | ||
|
|
e183eb99fa | ||
|
|
ee13de2853 | ||
|
|
6164c1274e | ||
|
|
a48028b8e9 | ||
|
|
5096a7c7d8 | ||
|
|
2e1d09263b | ||
|
|
ffc1c56815 | ||
|
|
cfca711212 | ||
|
|
26adaf07da | ||
|
|
f4643451e9 | ||
|
|
d3b9fb75c6 | ||
|
|
6599e3faae | ||
|
|
a17f24e08d | ||
|
|
a4c701ee76 | ||
|
|
ad797145ae | ||
|
|
7ef9bee924 | ||
|
|
6d82e71b6a | ||
|
|
a8067da5d1 | ||
|
|
3b63392482 | ||
|
|
86b4f7ca05 | ||
|
|
adf89e7483 | ||
|
|
8193cdd0d0 | ||
|
|
f25f0d7751 | ||
|
|
b7505cfd52 | ||
|
|
df3e097e21 | ||
|
|
707eee12fd | ||
|
|
fb1d48edb6 | ||
|
|
4c8f62d388 | ||
|
|
15658ad01b | ||
|
|
1d465a94ad | ||
|
|
b5b6bb16b9 | ||
|
|
52080f688b | ||
|
|
72bdbb7f46 | ||
|
|
6314cc0c73 | ||
|
|
cc10061717 | ||
|
|
44219e7df2 | ||
|
|
5b681fffe4 | ||
|
|
447f11b945 | ||
|
|
fe07dcf262 | ||
|
|
d25c2359de | ||
|
|
4f17bc1e89 | ||
|
|
d39d648846 | ||
|
|
ea15fd7c1a | ||
|
|
a0969d7a46 | ||
|
|
0c4b3c0198 | ||
|
|
ca75e56821 | ||
|
|
c383331e9d | ||
|
|
d36ae16dd4 | ||
|
|
c9b89e8224 | ||
|
|
40b1f8a804 | ||
|
|
883864650e | ||
|
|
6178b83f35 | ||
|
|
af411212ce | ||
|
|
e67d4921fd | ||
|
|
3654ef451e | ||
|
|
7a5311f64f | ||
|
|
1ada516f0e | ||
|
|
578c758200 | ||
|
|
97c012c76a | ||
|
|
2108a786ba | ||
|
|
decddd9021 | ||
|
|
52173babad | ||
|
|
f66f1dab29 | ||
|
|
6c9785fb4b | ||
|
|
d969307261 | ||
|
|
62cdb0fdd3 | ||
|
|
3bc7da7cd7 | ||
|
|
265434460e | ||
|
|
71742e6c68 | ||
|
|
719a60ddb3 | ||
|
|
1f983b49f7 | ||
|
|
313e38b4a1 | ||
|
|
1a392c8957 | ||
|
|
84dde20eea | ||
|
|
7dc581be44 | ||
|
|
f7c50726dd | ||
|
|
4bae8a0a90 | ||
|
|
b05900a761 | ||
|
|
b16148e1c6 | ||
|
|
dafd8866be | ||
|
|
631287933e | ||
|
|
814395979e |
+12
@@ -398,6 +398,12 @@ M: Blue Swirl <blauwirbel@gmail.com>
|
||||
S: Maintained
|
||||
F: hw/sun4u.c
|
||||
|
||||
Leon3
|
||||
M: Fabien Chouteau <chouteau@adacore.com>
|
||||
S: Maintained
|
||||
F: hw/leon3.c
|
||||
F: hw/grlib*
|
||||
|
||||
S390 Machines
|
||||
-------------
|
||||
S390 Virtio
|
||||
@@ -525,6 +531,12 @@ M: Anthony Liguori <aliguori@us.ibm.com>
|
||||
S: Maintained
|
||||
F: qemu-char.c
|
||||
|
||||
CPU
|
||||
M: Andreas Färber <afaerber@suse.de>
|
||||
S: Supported
|
||||
F: qom/cpu.c
|
||||
F: include/qemu/cpu.h
|
||||
|
||||
Device Tree
|
||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
|
||||
@@ -52,8 +52,13 @@ SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
|
||||
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
|
||||
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
|
||||
|
||||
ifeq ($(SUBDIR_DEVICES_MAK),)
|
||||
config-all-devices.mak:
|
||||
$(call quiet-command,echo '# no devices' > $@," GEN $@")
|
||||
else
|
||||
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
|
||||
$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@")
|
||||
endif
|
||||
|
||||
-include $(SUBDIR_DEVICES_MAK_DEP)
|
||||
|
||||
|
||||
@@ -80,14 +80,6 @@ obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
|
||||
|
||||
tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci
|
||||
|
||||
# HELPER_CFLAGS is used for all the legacy code compiled with static register
|
||||
# variables
|
||||
user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
|
||||
|
||||
# Note: this is a workaround. The real fix is to avoid compiling
|
||||
# cpu_signal_handler() in user-exec.c.
|
||||
%/signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
|
||||
|
||||
#########################################################
|
||||
# Linux user emulator target
|
||||
|
||||
|
||||
+9
-4
@@ -562,7 +562,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
||||
if ((i & 63) == 0) {
|
||||
uint64_t t1 = (qemu_get_clock_ns(rt_clock) - bwidth) / 1000000;
|
||||
if (t1 > MAX_WAIT) {
|
||||
DPRINTF("big wait: " PRIu64 " milliseconds, %d iterations\n",
|
||||
DPRINTF("big wait: %" PRIu64 " milliseconds, %d iterations\n",
|
||||
t1, i);
|
||||
break;
|
||||
}
|
||||
@@ -587,7 +587,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
||||
|
||||
expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
|
||||
|
||||
DPRINTF("ram_save_live: expected(" PRIu64 ") <= max(" PRIu64 ")?\n",
|
||||
DPRINTF("ram_save_live: expected(%" PRIu64 ") <= max(%" PRIu64 ")?\n",
|
||||
expected_time, migrate_max_downtime());
|
||||
|
||||
if (expected_time <= migrate_max_downtime()) {
|
||||
@@ -799,8 +799,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
} while (!(flags & RAM_SAVE_FLAG_EOS));
|
||||
|
||||
done:
|
||||
DPRINTF("Completed load of VM with exit code %d seq iteration " PRIu64 "\n",
|
||||
ret, seq_iter);
|
||||
DPRINTF("Completed load of VM with exit code %d seq iteration "
|
||||
"%" PRIu64 "\n", ret, seq_iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -922,11 +922,16 @@ void select_soundhw(const char *optarg)
|
||||
if (is_help_option(optarg)) {
|
||||
show_valid_cards:
|
||||
|
||||
#ifdef HAS_AUDIO_CHOICE
|
||||
printf("Valid sound card names (comma separated):\n");
|
||||
for (c = soundhw; c->name; ++c) {
|
||||
printf ("%-11s %s\n", c->name, c->descr);
|
||||
}
|
||||
printf("\n-soundhw all will enable all of the above\n");
|
||||
#else
|
||||
printf("Machine has no user-selectable audio hardware "
|
||||
"(it may or may not have always-present audio hardware).\n");
|
||||
#endif
|
||||
exit(!is_help_option(optarg));
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -410,15 +410,15 @@ SW *glue (AUD_open_, TYPE) (
|
||||
SW *old_sw = NULL;
|
||||
#endif
|
||||
|
||||
ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
|
||||
name, as->freq, as->nchannels, as->fmt);
|
||||
|
||||
if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
|
||||
dolog ("card=%p name=%p callback_fn=%p as=%p\n",
|
||||
card, name, callback_fn, as);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
|
||||
name, as->freq, as->nchannels, as->fmt);
|
||||
|
||||
if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
|
||||
audio_print_settings (as);
|
||||
goto fail;
|
||||
|
||||
@@ -433,7 +433,11 @@ int get_tmp_filename(char *filename, int size)
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
fd = mkstemp(filename);
|
||||
if (fd < 0 || close(fd)) {
|
||||
if (fd < 0) {
|
||||
return -errno;
|
||||
}
|
||||
if (close(fd) != 0) {
|
||||
unlink(filename);
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
@@ -664,7 +668,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
|
||||
open_flags |= BDRV_O_RDWR;
|
||||
}
|
||||
|
||||
bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
|
||||
bs->read_only = !(open_flags & BDRV_O_RDWR);
|
||||
|
||||
/* Open the image, either directly or using a protocol */
|
||||
if (drv->bdrv_file_open) {
|
||||
@@ -804,6 +808,12 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
||||
goto unlink_and_fail;
|
||||
}
|
||||
|
||||
if (flags & BDRV_O_RDWR) {
|
||||
flags |= BDRV_O_ALLOW_RDWR;
|
||||
}
|
||||
|
||||
bs->keep_read_only = !(flags & BDRV_O_ALLOW_RDWR);
|
||||
|
||||
/* Open the image */
|
||||
ret = bdrv_open_common(bs, filename, flags, drv);
|
||||
if (ret < 0) {
|
||||
@@ -833,12 +843,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
||||
bdrv_close(bs);
|
||||
return ret;
|
||||
}
|
||||
if (bs->is_temporary) {
|
||||
bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR);
|
||||
} else {
|
||||
/* base image inherits from "parent" */
|
||||
bs->backing_hd->keep_read_only = bs->keep_read_only;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bdrv_key_required(bs)) {
|
||||
@@ -897,10 +901,10 @@ void bdrv_close(BlockDriverState *bs)
|
||||
bdrv_delete(bs->file);
|
||||
bs->file = NULL;
|
||||
}
|
||||
|
||||
bdrv_dev_change_media_cb(bs, false);
|
||||
}
|
||||
|
||||
bdrv_dev_change_media_cb(bs, false);
|
||||
|
||||
/*throttling disk I/O limits*/
|
||||
if (bs->io_limits_enabled) {
|
||||
bdrv_io_limits_disable(bs);
|
||||
|
||||
@@ -80,6 +80,7 @@ typedef struct BlockDevOps {
|
||||
#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */
|
||||
#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */
|
||||
#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */
|
||||
#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */
|
||||
|
||||
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
|
||||
|
||||
|
||||
+1
-2
@@ -542,8 +542,7 @@ static void curl_close(BlockDriverState *bs)
|
||||
}
|
||||
if (s->multi)
|
||||
curl_multi_cleanup(s->multi);
|
||||
if (s->url)
|
||||
free(s->url);
|
||||
g_free(s->url);
|
||||
}
|
||||
|
||||
static int64_t curl_getlength(BlockDriverState *bs)
|
||||
|
||||
+17
-6
@@ -167,12 +167,6 @@ iscsi_set_events(IscsiLun *iscsilun)
|
||||
|
||||
}
|
||||
|
||||
/* If we just added an event, the callback might be delayed
|
||||
* unless we call qemu_notify_event().
|
||||
*/
|
||||
if (ev & ~iscsilun->events) {
|
||||
qemu_notify_event();
|
||||
}
|
||||
iscsilun->events = ev;
|
||||
}
|
||||
|
||||
@@ -628,9 +622,17 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
|
||||
static void ioctl_cb(void *opaque, int status)
|
||||
{
|
||||
int *p_status = opaque;
|
||||
*p_status = status;
|
||||
}
|
||||
|
||||
static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
int status;
|
||||
|
||||
switch (req) {
|
||||
case SG_GET_VERSION_NUM:
|
||||
@@ -639,6 +641,15 @@ static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
case SG_GET_SCSI_ID:
|
||||
((struct sg_scsi_id *)buf)->scsi_type = iscsilun->type;
|
||||
break;
|
||||
case SG_IO:
|
||||
status = -EINPROGRESS;
|
||||
iscsi_aio_ioctl(bs, req, buf, ioctl_cb, &status);
|
||||
|
||||
while (status == -EINPROGRESS) {
|
||||
qemu_aio_wait();
|
||||
}
|
||||
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
+2
-1
@@ -1986,7 +1986,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
vdi_index = pos / SD_DATA_OBJ_SIZE;
|
||||
offset = pos % SD_DATA_OBJ_SIZE;
|
||||
|
||||
data_len = MIN(remaining, SD_DATA_OBJ_SIZE);
|
||||
data_len = MIN(remaining, SD_DATA_OBJ_SIZE - offset);
|
||||
|
||||
vmstate_oid = vid_to_vmstate_oid(s->inode.vdi_id, vdi_index);
|
||||
|
||||
@@ -2007,6 +2007,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
}
|
||||
|
||||
pos += data_len;
|
||||
data += data_len;
|
||||
remaining -= data_len;
|
||||
}
|
||||
ret = size;
|
||||
|
||||
+12
-13
@@ -628,7 +628,6 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
||||
VdiHeader header;
|
||||
size_t i;
|
||||
size_t bmap_size;
|
||||
uint32_t *bmap;
|
||||
|
||||
logout("\n");
|
||||
|
||||
@@ -693,21 +692,21 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
||||
result = -errno;
|
||||
}
|
||||
|
||||
bmap = NULL;
|
||||
if (bmap_size > 0) {
|
||||
bmap = (uint32_t *)g_malloc0(bmap_size);
|
||||
}
|
||||
for (i = 0; i < blocks; i++) {
|
||||
if (image_type == VDI_TYPE_STATIC) {
|
||||
bmap[i] = i;
|
||||
} else {
|
||||
bmap[i] = VDI_UNALLOCATED;
|
||||
uint32_t *bmap = g_malloc0(bmap_size);
|
||||
for (i = 0; i < blocks; i++) {
|
||||
if (image_type == VDI_TYPE_STATIC) {
|
||||
bmap[i] = i;
|
||||
} else {
|
||||
bmap[i] = VDI_UNALLOCATED;
|
||||
}
|
||||
}
|
||||
if (write(fd, bmap, bmap_size) < 0) {
|
||||
result = -errno;
|
||||
}
|
||||
g_free(bmap);
|
||||
}
|
||||
if (write(fd, bmap, bmap_size) < 0) {
|
||||
result = -errno;
|
||||
}
|
||||
g_free(bmap);
|
||||
|
||||
if (image_type == VDI_TYPE_STATIC) {
|
||||
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
||||
result = -errno;
|
||||
|
||||
@@ -527,6 +527,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
||||
if_name[type], mediastr, unit_id);
|
||||
}
|
||||
dinfo->bdrv = bdrv_new(dinfo->id);
|
||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||
dinfo->bdrv->read_only = ro;
|
||||
dinfo->devaddr = devaddr;
|
||||
dinfo->type = type;
|
||||
dinfo->bus = bus_id;
|
||||
|
||||
@@ -44,6 +44,11 @@
|
||||
/* Use gnu_printf when supported (qemu uses standard format strings). */
|
||||
# define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
|
||||
# define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m)))
|
||||
# if defined(_WIN32)
|
||||
/* Map __printf__ to __gnu_printf__ because we want standard format strings
|
||||
* even when MinGW or GLib include files use __printf__. */
|
||||
# define __printf__ __gnu_printf__
|
||||
# endif
|
||||
# endif
|
||||
#if defined(_WIN32)
|
||||
#define GCC_WEAK __attribute__((weak))
|
||||
|
||||
@@ -111,14 +111,12 @@ source_path=`dirname "$0"`
|
||||
cpu=""
|
||||
interp_prefix="/usr/gnemul/qemu-%M"
|
||||
static="no"
|
||||
sparc_cpu=""
|
||||
cross_prefix=""
|
||||
audio_drv_list=""
|
||||
audio_card_list="ac97 es1370 sb16 hda"
|
||||
audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus hda"
|
||||
block_drv_whitelist=""
|
||||
host_cc="gcc"
|
||||
helper_cflags=""
|
||||
libs_softmmu=""
|
||||
libs_tools=""
|
||||
audio_pt_int=""
|
||||
@@ -183,6 +181,7 @@ datadir="\${prefix}/share"
|
||||
qemu_docdir="\${prefix}/share/doc/qemu"
|
||||
bindir="\${prefix}/bin"
|
||||
libdir="\${prefix}/lib"
|
||||
libexecdir="\${prefix}/libexec"
|
||||
includedir="\${prefix}/include"
|
||||
sysconfdir="\${prefix}/etc"
|
||||
confsuffix="/qemu"
|
||||
@@ -216,6 +215,7 @@ usb_redir=""
|
||||
opengl=""
|
||||
zlib="yes"
|
||||
guest_agent="yes"
|
||||
want_tools="yes"
|
||||
libiscsi=""
|
||||
coroutine=""
|
||||
seccomp=""
|
||||
@@ -240,21 +240,6 @@ for opt do
|
||||
;;
|
||||
--disable-debug-info) debug_info="no"
|
||||
;;
|
||||
--sparc_cpu=*)
|
||||
sparc_cpu="$optarg"
|
||||
case $sparc_cpu in
|
||||
v7|v8|v8plus|v8plusa)
|
||||
cpu="sparc"
|
||||
;;
|
||||
v9)
|
||||
cpu="sparc64"
|
||||
;;
|
||||
*)
|
||||
echo "undefined SPARC architecture. Exiting";
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# OS specific
|
||||
@@ -342,8 +327,6 @@ elif check_define __i386__ ; then
|
||||
elif check_define __x86_64__ ; then
|
||||
cpu="x86_64"
|
||||
elif check_define __sparc__ ; then
|
||||
# We can't check for 64 bit (when gcc is biarch) or V8PLUSA
|
||||
# They must be specified using --sparc_cpu
|
||||
if check_define __arch64__ ; then
|
||||
cpu="sparc64"
|
||||
else
|
||||
@@ -633,6 +616,8 @@ for opt do
|
||||
;;
|
||||
--libdir=*) libdir="$optarg"
|
||||
;;
|
||||
--libexecdir=*) libexecdir="$optarg"
|
||||
;;
|
||||
--includedir=*) includedir="$optarg"
|
||||
;;
|
||||
--datadir=*) datadir="$optarg"
|
||||
@@ -643,7 +628,7 @@ for opt do
|
||||
;;
|
||||
--sysconfdir=*) sysconfdir="$optarg"
|
||||
;;
|
||||
--sbindir=*|--libexecdir=*|--sharedstatedir=*|--localstatedir=*|\
|
||||
--sbindir=*|--sharedstatedir=*|--localstatedir=*|\
|
||||
--oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\
|
||||
--htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*)
|
||||
# These switches are silently ignored, for compatibility with
|
||||
@@ -789,8 +774,6 @@ for opt do
|
||||
;;
|
||||
--enable-uname-release=*) uname_release="$optarg"
|
||||
;;
|
||||
--sparc_cpu=*)
|
||||
;;
|
||||
--enable-werror) werror="yes"
|
||||
;;
|
||||
--disable-werror) werror="no"
|
||||
@@ -865,6 +848,10 @@ for opt do
|
||||
;;
|
||||
--disable-guest-agent) guest_agent="no"
|
||||
;;
|
||||
--enable-tools) want_tools="yes"
|
||||
;;
|
||||
--disable-tools) want_tools="no"
|
||||
;;
|
||||
--enable-seccomp) seccomp="yes"
|
||||
;;
|
||||
--disable-seccomp) seccomp="no"
|
||||
@@ -874,36 +861,17 @@ for opt do
|
||||
esac
|
||||
done
|
||||
|
||||
#
|
||||
# If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right
|
||||
# QEMU_CFLAGS/LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit)
|
||||
#
|
||||
host_guest_base="no"
|
||||
case "$cpu" in
|
||||
sparc) case $sparc_cpu in
|
||||
v7|v8)
|
||||
QEMU_CFLAGS="-mcpu=${sparc_cpu} -D__sparc_${sparc_cpu}__ $QEMU_CFLAGS"
|
||||
;;
|
||||
v8plus|v8plusa)
|
||||
QEMU_CFLAGS="-mcpu=ultrasparc -D__sparc_${sparc_cpu}__ $QEMU_CFLAGS"
|
||||
;;
|
||||
*) # sparc_cpu not defined in the command line
|
||||
QEMU_CFLAGS="-mcpu=ultrasparc -D__sparc_v8plus__ $QEMU_CFLAGS"
|
||||
esac
|
||||
sparc)
|
||||
LDFLAGS="-m32 $LDFLAGS"
|
||||
QEMU_CFLAGS="-m32 -ffixed-g2 -ffixed-g3 $QEMU_CFLAGS"
|
||||
if test "$solaris" = "no" ; then
|
||||
QEMU_CFLAGS="-ffixed-g1 -ffixed-g6 $QEMU_CFLAGS"
|
||||
helper_cflags="-ffixed-i0"
|
||||
fi
|
||||
QEMU_CFLAGS="-m32 -mcpu=ultrasparc $QEMU_CFLAGS"
|
||||
host_guest_base="yes"
|
||||
;;
|
||||
sparc64)
|
||||
QEMU_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__ $QEMU_CFLAGS"
|
||||
LDFLAGS="-m64 $LDFLAGS"
|
||||
QEMU_CFLAGS="-ffixed-g5 -ffixed-g6 -ffixed-g7 $QEMU_CFLAGS"
|
||||
if test "$solaris" != "no" ; then
|
||||
QEMU_CFLAGS="-ffixed-g1 $QEMU_CFLAGS"
|
||||
fi
|
||||
QEMU_CFLAGS="-m64 -mcpu=ultrasparc $QEMU_CFLAGS"
|
||||
host_guest_base="yes"
|
||||
;;
|
||||
s390)
|
||||
QEMU_CFLAGS="-m31 -march=z990 $QEMU_CFLAGS"
|
||||
@@ -919,7 +887,6 @@ case "$cpu" in
|
||||
QEMU_CFLAGS="-m32 $QEMU_CFLAGS"
|
||||
LDFLAGS="-m32 $LDFLAGS"
|
||||
cc_i386='$(CC) -m32'
|
||||
helper_cflags="-fomit-frame-pointer"
|
||||
host_guest_base="yes"
|
||||
;;
|
||||
x86_64)
|
||||
@@ -1319,10 +1286,6 @@ if test -z "$target_list" ; then
|
||||
else
|
||||
target_list=`echo "$target_list" | sed -e 's/,/ /g'`
|
||||
fi
|
||||
if test -z "$target_list" ; then
|
||||
echo "No targets enabled"
|
||||
exit 1
|
||||
fi
|
||||
# see if system emulation was really requested
|
||||
case " $target_list " in
|
||||
*"-softmmu "*) softmmu=yes
|
||||
@@ -1428,10 +1391,10 @@ if test "$seccomp" != "no" ; then
|
||||
LIBS=`$pkg_config --libs libseccomp`
|
||||
seccomp="yes"
|
||||
else
|
||||
seccomp="no"
|
||||
if test "$seccomp" = "yes"; then
|
||||
feature_not_found "libseccomp"
|
||||
fi
|
||||
seccomp="no"
|
||||
fi
|
||||
fi
|
||||
##########################################
|
||||
@@ -2667,18 +2630,45 @@ EOF
|
||||
fi
|
||||
|
||||
|
||||
##########################################
|
||||
# Do we need libm
|
||||
cat > $TMPC << EOF
|
||||
#include <math.h>
|
||||
int main(void) { return isnan(sin(0.0)); }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
:
|
||||
elif compile_prog "" "-lm" ; then
|
||||
LIBS="-lm $LIBS"
|
||||
libs_qga="-lm $libs_qga"
|
||||
else
|
||||
echo
|
||||
echo "Error: libm check failed"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# Do we need librt
|
||||
# uClibc provides 2 versions of clock_gettime(), one with realtime
|
||||
# support and one without. This means that the clock_gettime() don't
|
||||
# need -lrt. We still need it for timer_create() so we check for this
|
||||
# function in addition.
|
||||
cat > $TMPC <<EOF
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
int main(void) { return clock_gettime(CLOCK_REALTIME, NULL); }
|
||||
int main(void) {
|
||||
timer_create(CLOCK_REALTIME, NULL, NULL);
|
||||
return clock_gettime(CLOCK_REALTIME, NULL);
|
||||
}
|
||||
EOF
|
||||
|
||||
if compile_prog "" "" ; then
|
||||
:
|
||||
elif compile_prog "" "-lrt" ; then
|
||||
# we need pthread for static linking. use previous pthread test result
|
||||
elif compile_prog "" "-lrt $pthread_lib" ; then
|
||||
LIBS="-lrt $LIBS"
|
||||
libs_qga="-lrt $libs_qga"
|
||||
fi
|
||||
|
||||
if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \
|
||||
@@ -2701,6 +2691,11 @@ EOF
|
||||
spice="yes"
|
||||
libs_softmmu="$libs_softmmu $spice_libs"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags"
|
||||
spice_protocol_version=$($pkg_config --modversion spice-protocol)
|
||||
spice_server_version=$($pkg_config --modversion spice-server)
|
||||
if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then
|
||||
spice_qxl_io_monitors_config_async="yes"
|
||||
fi
|
||||
else
|
||||
if test "$spice" = "yes" ; then
|
||||
feature_not_found "spice"
|
||||
@@ -2755,7 +2750,7 @@ if test "$usb_redir" != "no" ; then
|
||||
usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
|
||||
usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
|
||||
LIBS="$LIBS $usb_redir_libs"
|
||||
libs_softmmu="$libs_softmmu $usb_redir_libs"
|
||||
else
|
||||
if test "$usb_redir" = "yes"; then
|
||||
feature_not_found "usb-redir"
|
||||
@@ -2963,11 +2958,12 @@ if compile_prog "-Werror" "" ; then
|
||||
fi
|
||||
|
||||
########################################
|
||||
# check if we have valgrind/valgrind.h
|
||||
# check if we have valgrind/valgrind.h and valgrind/memcheck.h
|
||||
|
||||
valgrind_h=no
|
||||
cat > $TMPC << EOF
|
||||
#include <valgrind/valgrind.h>
|
||||
#include <valgrind/memcheck.h>
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
@@ -3039,9 +3035,14 @@ fi
|
||||
qemu_confdir=$sysconfdir$confsuffix
|
||||
qemu_datadir=$datadir$confsuffix
|
||||
|
||||
tools=
|
||||
if test "$softmmu" = yes ; then
|
||||
tools=""
|
||||
if test "$want_tools" = "yes" ; then
|
||||
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
|
||||
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
|
||||
tools="qemu-nbd\$(EXESUF) $tools"
|
||||
fi
|
||||
fi
|
||||
if test "$softmmu" = yes ; then
|
||||
if test "$virtfs" != no ; then
|
||||
if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
|
||||
virtfs=yes
|
||||
@@ -3055,14 +3056,13 @@ if test "$softmmu" = yes ; then
|
||||
fi
|
||||
fi
|
||||
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
|
||||
tools="qemu-nbd\$(EXESUF) $tools"
|
||||
if [ "$guest_agent" = "yes" ]; then
|
||||
tools="qemu-ga\$(EXESUF) $tools"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test "$smartcard_nss" = "yes" ; then
|
||||
tools="vscclient\$(EXESUF) $tools"
|
||||
if test "$smartcard_nss" = "yes" ; then
|
||||
tools="vscclient\$(EXESUF) $tools"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Mac OS X ships with a broken assembler
|
||||
@@ -3080,6 +3080,7 @@ echo "Install prefix $prefix"
|
||||
echo "BIOS directory `eval echo $qemu_datadir`"
|
||||
echo "binary directory `eval echo $bindir`"
|
||||
echo "library directory `eval echo $libdir`"
|
||||
echo "libexec directory `eval echo $libexecdir`"
|
||||
echo "include directory `eval echo $includedir`"
|
||||
echo "config directory `eval echo $sysconfdir`"
|
||||
if test "$mingw32" = "no" ; then
|
||||
@@ -3156,7 +3157,7 @@ echo "libcap-ng support $cap_ng"
|
||||
echo "vhost-net support $vhost_net"
|
||||
echo "Trace backend $trace_backend"
|
||||
echo "Trace output file $trace_file-<pid>"
|
||||
echo "spice support $spice"
|
||||
echo "spice support $spice ($spice_protocol_version/$spice_server_version)"
|
||||
echo "rbd support $rbd"
|
||||
echo "xfsctl support $xfs"
|
||||
echo "nss used $smartcard_nss"
|
||||
@@ -3183,14 +3184,14 @@ echo all: >> $config_host_mak
|
||||
echo "prefix=$prefix" >> $config_host_mak
|
||||
echo "bindir=$bindir" >> $config_host_mak
|
||||
echo "libdir=$libdir" >> $config_host_mak
|
||||
echo "libexecdir=$libexecdir" >> $config_host_mak
|
||||
echo "includedir=$includedir" >> $config_host_mak
|
||||
echo "mandir=$mandir" >> $config_host_mak
|
||||
echo "sysconfdir=$sysconfdir" >> $config_host_mak
|
||||
echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
|
||||
echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
|
||||
echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
|
||||
echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
|
||||
echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
|
||||
echo "CONFIG_QEMU_HELPERDIR=\"$libexecdir\"" >> $config_host_mak
|
||||
|
||||
echo "ARCH=$ARCH" >> $config_host_mak
|
||||
if test "$debug_tcg" = "yes" ; then
|
||||
@@ -3438,6 +3439,10 @@ if test "$spice" = "yes" ; then
|
||||
echo "CONFIG_SPICE=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$spice_qxl_io_monitors_config_async" = "yes" ; then
|
||||
echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$smartcard" = "yes" ; then
|
||||
echo "CONFIG_SMARTCARD=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -3572,7 +3577,6 @@ if test "$sparse" = "yes" ; then
|
||||
echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak
|
||||
echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak
|
||||
fi
|
||||
echo "HELPER_CFLAGS=$helper_cflags" >> $config_host_mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
|
||||
echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak
|
||||
echo "ARLIBS_END=$arlibs_end" >> $config_host_mak
|
||||
@@ -3827,13 +3831,6 @@ fi
|
||||
|
||||
symlink "$source_path/Makefile.target" "$target_dir/Makefile"
|
||||
|
||||
|
||||
case "$target_arch2" in
|
||||
alpha | i386 | or32 | sparc* | x86_64 | xtensa* | ppc*)
|
||||
echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak
|
||||
;;
|
||||
esac
|
||||
|
||||
upper() {
|
||||
echo "$@"| LC_ALL=C tr '[a-z]' '[A-Z]'
|
||||
}
|
||||
@@ -4085,10 +4082,6 @@ fi
|
||||
|
||||
if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then
|
||||
case "$ARCH" in
|
||||
sparc)
|
||||
# -static is used to avoid g1/g3 usage by the dynamic linker
|
||||
ldflags="$linker_script -static $ldflags"
|
||||
;;
|
||||
alpha | s390x)
|
||||
# The default placement of the application is fine.
|
||||
;;
|
||||
|
||||
@@ -937,8 +937,11 @@ static void console_putchar(TextConsole *s, int ch)
|
||||
case TTY_STATE_CSI: /* handle escape sequence parameters */
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
if (s->nb_esc_params < MAX_ESC_PARAMS) {
|
||||
s->esc_params[s->nb_esc_params] =
|
||||
s->esc_params[s->nb_esc_params] * 10 + ch - '0';
|
||||
int *param = &s->esc_params[s->nb_esc_params];
|
||||
int digit = (ch - '0');
|
||||
|
||||
*param = (*param <= (INT_MAX - digit) / 10) ?
|
||||
*param * 10 + digit : INT_MAX;
|
||||
}
|
||||
} else {
|
||||
if (s->nb_esc_params < MAX_ESC_PARAMS)
|
||||
@@ -1611,7 +1614,7 @@ PixelFormat qemu_different_endianness_pixelformat(int bpp)
|
||||
memset(&pf, 0x00, sizeof(PixelFormat));
|
||||
|
||||
pf.bits_per_pixel = bpp;
|
||||
pf.bytes_per_pixel = bpp / 8;
|
||||
pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
|
||||
pf.depth = bpp == 32 ? 24 : bpp;
|
||||
|
||||
switch (bpp) {
|
||||
@@ -1660,13 +1663,12 @@ PixelFormat qemu_default_pixelformat(int bpp)
|
||||
memset(&pf, 0x00, sizeof(PixelFormat));
|
||||
|
||||
pf.bits_per_pixel = bpp;
|
||||
pf.bytes_per_pixel = bpp / 8;
|
||||
pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
|
||||
pf.depth = bpp == 32 ? 24 : bpp;
|
||||
|
||||
switch (bpp) {
|
||||
case 15:
|
||||
pf.bits_per_pixel = 16;
|
||||
pf.bytes_per_pixel = 2;
|
||||
pf.rmask = 0x00007c00;
|
||||
pf.gmask = 0x000003E0;
|
||||
pf.bmask = 0x0000001F;
|
||||
|
||||
@@ -260,14 +260,6 @@ extern unsigned long reserved_va;
|
||||
#define stfl(p, v) stfl_raw(p, v)
|
||||
#define stfq(p, v) stfq_raw(p, v)
|
||||
|
||||
#ifndef CONFIG_TCG_PASS_AREG0
|
||||
#define ldub_code(p) ldub_raw(p)
|
||||
#define ldsb_code(p) ldsb_raw(p)
|
||||
#define lduw_code(p) lduw_raw(p)
|
||||
#define ldsw_code(p) ldsw_raw(p)
|
||||
#define ldl_code(p) ldl_raw(p)
|
||||
#define ldq_code(p) ldq_raw(p)
|
||||
#else
|
||||
#define cpu_ldub_code(env1, p) ldub_raw(p)
|
||||
#define cpu_ldsb_code(env1, p) ldsb_raw(p)
|
||||
#define cpu_lduw_code(env1, p) lduw_raw(p)
|
||||
@@ -296,7 +288,6 @@ extern unsigned long reserved_va;
|
||||
#define cpu_stw_kernel(env, addr, data) stw_raw(addr, data)
|
||||
#define cpu_stl_kernel(env, addr, data) stl_raw(addr, data)
|
||||
#define cpu_stq_kernel(env, addr, data) stq_raw(addr, data)
|
||||
#endif
|
||||
|
||||
#define ldub_kernel(p) ldub_raw(p)
|
||||
#define ldsb_kernel(p) ldsb_raw(p)
|
||||
@@ -313,7 +304,6 @@ extern unsigned long reserved_va;
|
||||
#define stfl_kernel(p, v) stfl_raw(p, v)
|
||||
#define stfq_kernel(p, vt) stfq_raw(p, v)
|
||||
|
||||
#ifdef CONFIG_TCG_PASS_AREG0
|
||||
#define cpu_ldub_data(env, addr) ldub_raw(addr)
|
||||
#define cpu_lduw_data(env, addr) lduw_raw(addr)
|
||||
#define cpu_ldl_data(env, addr) ldl_raw(addr)
|
||||
@@ -321,7 +311,6 @@ extern unsigned long reserved_va;
|
||||
#define cpu_stb_data(env, addr, data) stb_raw(addr, data)
|
||||
#define cpu_stw_data(env, addr, data) stw_raw(addr, data)
|
||||
#define cpu_stl_data(env, addr, data) stl_raw(addr, data)
|
||||
#endif
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
||||
/* page related stuff */
|
||||
|
||||
@@ -325,11 +325,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
||||
mmu_idx = cpu_mmu_index(env1);
|
||||
if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
|
||||
(addr & TARGET_PAGE_MASK))) {
|
||||
#ifdef CONFIG_TCG_PASS_AREG0
|
||||
cpu_ldub_code(env1, addr);
|
||||
#else
|
||||
ldub_code(addr);
|
||||
#endif
|
||||
}
|
||||
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
|
||||
mr = iotlb_to_region(pd);
|
||||
@@ -348,7 +344,6 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
||||
#define MMUSUFFIX _cmmu
|
||||
#undef GETPC
|
||||
#define GETPC() ((uintptr_t)0)
|
||||
#define env cpu_single_env
|
||||
#define SOFTMMU_CODE_ACCESS
|
||||
|
||||
#define SHIFT 0
|
||||
|
||||
@@ -128,6 +128,8 @@
|
||||
#define DEF_HELPER_5(name, ret, t1, t2, t3, t4, t5) \
|
||||
DEF_HELPER_FLAGS_5(name, 0, ret, t1, t2, t3, t4, t5)
|
||||
|
||||
/* MAX_OPC_PARAM_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */
|
||||
|
||||
#endif /* DEF_HELPER_H */
|
||||
|
||||
#ifndef GEN_HELPER
|
||||
|
||||
@@ -316,9 +316,7 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
print_insn = print_insn_alpha;
|
||||
#elif defined(__sparc__)
|
||||
print_insn = print_insn_sparc;
|
||||
#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
#elif defined(__arm__)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(__MIPSEB__)
|
||||
|
||||
@@ -31,7 +31,7 @@ Arguments:
|
||||
|
||||
Returns:
|
||||
|
||||
H_SUCCESS : Successully called the RTAS function (RTAS result
|
||||
H_SUCCESS : Successfully called the RTAS function (RTAS result
|
||||
will have been stored in the parameter block)
|
||||
H_PARAMETER : Unknown token
|
||||
|
||||
|
||||
+2
-2
@@ -58,11 +58,11 @@ try ...
|
||||
xhci controller support
|
||||
-----------------------
|
||||
|
||||
There also is xhci host controller support available. It got alot
|
||||
There is also xhci host controller support available. It got a lot
|
||||
less testing than ehci and there are a bunch of known limitations, so
|
||||
ehci may work better for you. On the other hand the xhci hardware
|
||||
design is much more virtualization-friendly, thus xhci emulation uses
|
||||
less ressources (especially cpu). If you wanna give xhci a try
|
||||
less resources (especially cpu). If you want to give xhci a try
|
||||
use this to add the host controller ...
|
||||
|
||||
qemu -device nec-usb-xhci,id=xhci
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* dyngen defines for micro operation code
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if !defined(__DYNGEN_EXEC_H__)
|
||||
#define __DYNGEN_EXEC_H__
|
||||
|
||||
#if defined(CONFIG_TCG_INTERPRETER)
|
||||
/* The TCG interpreter does not need a special register AREG0,
|
||||
* but it is possible to use one by defining AREG0.
|
||||
* On i386, register edi seems to work. */
|
||||
/* Run without special register AREG0 or use a value defined elsewhere. */
|
||||
#elif defined(__i386__)
|
||||
#define AREG0 "ebp"
|
||||
#elif defined(__x86_64__)
|
||||
#define AREG0 "r14"
|
||||
#elif defined(_ARCH_PPC)
|
||||
#define AREG0 "r27"
|
||||
#elif defined(__arm__)
|
||||
#define AREG0 "r6"
|
||||
#elif defined(__hppa__)
|
||||
#define AREG0 "r17"
|
||||
#elif defined(__mips__)
|
||||
#define AREG0 "s0"
|
||||
#elif defined(__sparc__)
|
||||
#ifdef CONFIG_SOLARIS
|
||||
#define AREG0 "g2"
|
||||
#else
|
||||
#ifdef __sparc_v9__
|
||||
#define AREG0 "g5"
|
||||
#else
|
||||
#define AREG0 "g6"
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__s390__)
|
||||
#define AREG0 "r10"
|
||||
#elif defined(__alpha__)
|
||||
/* Note $15 is the frame pointer, so anything in op-i386.c that would
|
||||
require a frame pointer, like alloca, would probably loose. */
|
||||
#define AREG0 "$15"
|
||||
#elif defined(__mc68000)
|
||||
#define AREG0 "%a5"
|
||||
#elif defined(__ia64__)
|
||||
#define AREG0 "r7"
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
||||
#if defined(AREG0)
|
||||
register CPUArchState *env asm(AREG0);
|
||||
#else
|
||||
/* TODO: Try env = cpu_single_env. */
|
||||
extern CPUArchState *env;
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__DYNGEN_EXEC_H__) */
|
||||
+7
-8
@@ -51,7 +51,7 @@ typedef struct TranslationBlock TranslationBlock;
|
||||
#else
|
||||
#define MAX_OPC_PARAM_PER_ARG 1
|
||||
#endif
|
||||
#define MAX_OPC_PARAM_IARGS 4
|
||||
#define MAX_OPC_PARAM_IARGS 5
|
||||
#define MAX_OPC_PARAM_OARGS 1
|
||||
#define MAX_OPC_PARAM_ARGS (MAX_OPC_PARAM_IARGS + MAX_OPC_PARAM_OARGS)
|
||||
|
||||
@@ -132,9 +132,10 @@ static inline void tlb_flush(CPUArchState *env, int flush_global)
|
||||
#define CODE_GEN_AVG_BLOCK_SIZE 64
|
||||
#endif
|
||||
|
||||
#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__)
|
||||
#define USE_DIRECT_JUMP
|
||||
#elif defined(CONFIG_TCG_INTERPRETER)
|
||||
#if defined(__arm__) || defined(_ARCH_PPC) \
|
||||
|| defined(__x86_64__) || defined(__i386__) \
|
||||
|| defined(__sparc__) \
|
||||
|| defined(CONFIG_TCG_INTERPRETER)
|
||||
#define USE_DIRECT_JUMP
|
||||
#endif
|
||||
|
||||
@@ -244,6 +245,8 @@ static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
|
||||
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
|
||||
#endif
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr);
|
||||
#else
|
||||
#error tb_set_jmp_target1 is missing
|
||||
#endif
|
||||
@@ -323,9 +326,6 @@ void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx,
|
||||
|
||||
#define ACCESS_TYPE (NB_MMU_MODES + 1)
|
||||
#define MEMSUFFIX _code
|
||||
#ifndef CONFIG_TCG_PASS_AREG0
|
||||
#define env cpu_single_env
|
||||
#endif
|
||||
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
@@ -341,7 +341,6 @@ void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx,
|
||||
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
#undef env
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ static int nb_tbs;
|
||||
/* any access to the tbs or the page table must use this lock */
|
||||
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
#if defined(__arm__) || defined(__sparc_v9__)
|
||||
#if defined(__arm__) || defined(__sparc__)
|
||||
/* The prologue must be reachable with a direct jump. ARM and Sparc64
|
||||
have limited branch ranges (possibly also PPC) so place it in a
|
||||
section close to code segment. */
|
||||
@@ -541,10 +541,9 @@ static void code_gen_alloc(unsigned long tb_size)
|
||||
/* Cannot map more than that */
|
||||
if (code_gen_buffer_size > (800 * 1024 * 1024))
|
||||
code_gen_buffer_size = (800 * 1024 * 1024);
|
||||
#elif defined(__sparc_v9__)
|
||||
#elif defined(__sparc__) && HOST_LONG_BITS == 64
|
||||
// Map the buffer below 2G, so we can use direct calls and branches
|
||||
flags |= MAP_FIXED;
|
||||
start = (void *) 0x60000000UL;
|
||||
start = (void *) 0x40000000UL;
|
||||
if (code_gen_buffer_size > (512 * 1024 * 1024))
|
||||
code_gen_buffer_size = (512 * 1024 * 1024);
|
||||
#elif defined(__arm__)
|
||||
@@ -582,10 +581,9 @@ static void code_gen_alloc(unsigned long tb_size)
|
||||
/* Cannot map more than that */
|
||||
if (code_gen_buffer_size > (800 * 1024 * 1024))
|
||||
code_gen_buffer_size = (800 * 1024 * 1024);
|
||||
#elif defined(__sparc_v9__)
|
||||
#elif defined(__sparc__) && HOST_LONG_BITS == 64
|
||||
// Map the buffer below 2G, so we can use direct calls and branches
|
||||
flags |= MAP_FIXED;
|
||||
addr = (void *) 0x60000000UL;
|
||||
addr = (void *) 0x40000000UL;
|
||||
if (code_gen_buffer_size > (512 * 1024 * 1024)) {
|
||||
code_gen_buffer_size = (512 * 1024 * 1024);
|
||||
}
|
||||
@@ -3523,6 +3521,13 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr,
|
||||
/* ROM/RAM case */
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
memcpy(ptr, buf, l);
|
||||
if (!cpu_physical_memory_is_dirty(addr1)) {
|
||||
/* invalidate code */
|
||||
tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
|
||||
/* set dirty bit */
|
||||
cpu_physical_memory_set_dirty_flags(
|
||||
addr1, (0xff & ~CODE_DIRTY_FLAG));
|
||||
}
|
||||
qemu_put_ram_ptr(ptr);
|
||||
}
|
||||
len -= l;
|
||||
|
||||
+2
-2
@@ -1238,7 +1238,7 @@ float32 uint64_to_float32( uint64 a STATUS_PARAM )
|
||||
if ( a == 0 ) return float32_zero;
|
||||
shiftCount = countLeadingZeros64( a ) - 40;
|
||||
if ( 0 <= shiftCount ) {
|
||||
return packFloat32( 1 > 0, 0x95 - shiftCount, a<<shiftCount );
|
||||
return packFloat32(0, 0x95 - shiftCount, a<<shiftCount);
|
||||
}
|
||||
else {
|
||||
shiftCount += 7;
|
||||
@@ -1248,7 +1248,7 @@ float32 uint64_to_float32( uint64 a STATUS_PARAM )
|
||||
else {
|
||||
a <<= shiftCount;
|
||||
}
|
||||
return roundAndPackFloat32( 1 > 0, 0x9C - shiftCount, a STATUS_VAR );
|
||||
return roundAndPackFloat32(0, 0x9C - shiftCount, a STATUS_VAR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1226,33 +1226,48 @@ static int cpu_gdb_write_register(CPUOpenRISCState *env,
|
||||
|
||||
static int cpu_gdb_read_register(CPUSH4State *env, uint8_t *mem_buf, int n)
|
||||
{
|
||||
if (n < 8) {
|
||||
switch (n) {
|
||||
case 0 ... 7:
|
||||
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
|
||||
GET_REGL(env->gregs[n + 16]);
|
||||
} else {
|
||||
GET_REGL(env->gregs[n]);
|
||||
}
|
||||
} else if (n < 16) {
|
||||
case 8 ... 15:
|
||||
GET_REGL(env->gregs[n]);
|
||||
} else if (n >= 25 && n < 41) {
|
||||
GET_REGL(env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)]);
|
||||
} else if (n >= 43 && n < 51) {
|
||||
GET_REGL(env->gregs[n - 43]);
|
||||
} else if (n >= 51 && n < 59) {
|
||||
GET_REGL(env->gregs[n - (51 - 16)]);
|
||||
}
|
||||
switch (n) {
|
||||
case 16: GET_REGL(env->pc);
|
||||
case 17: GET_REGL(env->pr);
|
||||
case 18: GET_REGL(env->gbr);
|
||||
case 19: GET_REGL(env->vbr);
|
||||
case 20: GET_REGL(env->mach);
|
||||
case 21: GET_REGL(env->macl);
|
||||
case 22: GET_REGL(env->sr);
|
||||
case 23: GET_REGL(env->fpul);
|
||||
case 24: GET_REGL(env->fpscr);
|
||||
case 41: GET_REGL(env->ssr);
|
||||
case 42: GET_REGL(env->spc);
|
||||
case 16:
|
||||
GET_REGL(env->pc);
|
||||
case 17:
|
||||
GET_REGL(env->pr);
|
||||
case 18:
|
||||
GET_REGL(env->gbr);
|
||||
case 19:
|
||||
GET_REGL(env->vbr);
|
||||
case 20:
|
||||
GET_REGL(env->mach);
|
||||
case 21:
|
||||
GET_REGL(env->macl);
|
||||
case 22:
|
||||
GET_REGL(env->sr);
|
||||
case 23:
|
||||
GET_REGL(env->fpul);
|
||||
case 24:
|
||||
GET_REGL(env->fpscr);
|
||||
case 25 ... 40:
|
||||
if (env->fpscr & FPSCR_FR) {
|
||||
stfl_p(mem_buf, env->fregs[n - 9]);
|
||||
} else {
|
||||
stfl_p(mem_buf, env->fregs[n - 25]);
|
||||
}
|
||||
return 4;
|
||||
case 41:
|
||||
GET_REGL(env->ssr);
|
||||
case 42:
|
||||
GET_REGL(env->spc);
|
||||
case 43 ... 50:
|
||||
GET_REGL(env->gregs[n - 43]);
|
||||
case 51 ... 58:
|
||||
GET_REGL(env->gregs[n - (51 - 16)]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1260,42 +1275,63 @@ static int cpu_gdb_read_register(CPUSH4State *env, uint8_t *mem_buf, int n)
|
||||
|
||||
static int cpu_gdb_write_register(CPUSH4State *env, uint8_t *mem_buf, int n)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = ldl_p(mem_buf);
|
||||
|
||||
if (n < 8) {
|
||||
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
|
||||
env->gregs[n + 16] = tmp;
|
||||
} else {
|
||||
env->gregs[n] = tmp;
|
||||
}
|
||||
return 4;
|
||||
} else if (n < 16) {
|
||||
env->gregs[n] = tmp;
|
||||
return 4;
|
||||
} else if (n >= 25 && n < 41) {
|
||||
env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)] = tmp;
|
||||
return 4;
|
||||
} else if (n >= 43 && n < 51) {
|
||||
env->gregs[n - 43] = tmp;
|
||||
return 4;
|
||||
} else if (n >= 51 && n < 59) {
|
||||
env->gregs[n - (51 - 16)] = tmp;
|
||||
return 4;
|
||||
}
|
||||
switch (n) {
|
||||
case 16: env->pc = tmp; break;
|
||||
case 17: env->pr = tmp; break;
|
||||
case 18: env->gbr = tmp; break;
|
||||
case 19: env->vbr = tmp; break;
|
||||
case 20: env->mach = tmp; break;
|
||||
case 21: env->macl = tmp; break;
|
||||
case 22: env->sr = tmp; break;
|
||||
case 23: env->fpul = tmp; break;
|
||||
case 24: env->fpscr = tmp; break;
|
||||
case 41: env->ssr = tmp; break;
|
||||
case 42: env->spc = tmp; break;
|
||||
case 0 ... 7:
|
||||
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
|
||||
env->gregs[n + 16] = ldl_p(mem_buf);
|
||||
} else {
|
||||
env->gregs[n] = ldl_p(mem_buf);
|
||||
}
|
||||
break;
|
||||
case 8 ... 15:
|
||||
env->gregs[n] = ldl_p(mem_buf);
|
||||
break;
|
||||
case 16:
|
||||
env->pc = ldl_p(mem_buf);
|
||||
break;
|
||||
case 17:
|
||||
env->pr = ldl_p(mem_buf);
|
||||
break;
|
||||
case 18:
|
||||
env->gbr = ldl_p(mem_buf);
|
||||
break;
|
||||
case 19:
|
||||
env->vbr = ldl_p(mem_buf);
|
||||
break;
|
||||
case 20:
|
||||
env->mach = ldl_p(mem_buf);
|
||||
break;
|
||||
case 21:
|
||||
env->macl = ldl_p(mem_buf);
|
||||
break;
|
||||
case 22:
|
||||
env->sr = ldl_p(mem_buf);
|
||||
break;
|
||||
case 23:
|
||||
env->fpul = ldl_p(mem_buf);
|
||||
break;
|
||||
case 24:
|
||||
env->fpscr = ldl_p(mem_buf);
|
||||
break;
|
||||
case 25 ... 40:
|
||||
if (env->fpscr & FPSCR_FR) {
|
||||
env->fregs[n - 9] = ldfl_p(mem_buf);
|
||||
} else {
|
||||
env->fregs[n - 25] = ldfl_p(mem_buf);
|
||||
}
|
||||
break;
|
||||
case 41:
|
||||
env->ssr = ldl_p(mem_buf);
|
||||
break;
|
||||
case 42:
|
||||
env->spc = ldl_p(mem_buf);
|
||||
break;
|
||||
case 43 ... 50:
|
||||
env->gregs[n - 43] = ldl_p(mem_buf);
|
||||
break;
|
||||
case 51 ... 58:
|
||||
env->gregs[n - (51 - 16)] = ldl_p(mem_buf);
|
||||
break;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -512,9 +512,9 @@ STEXI
|
||||
@item sendkey @var{keys}
|
||||
@findex sendkey
|
||||
|
||||
Send @var{keys} to the emulator. @var{keys} could be the name of the
|
||||
key or @code{#} followed by the raw value in either decimal or hexadecimal
|
||||
format. Use @code{-} to press several keys simultaneously. Example:
|
||||
Send @var{keys} to the guest. @var{keys} could be the name of the
|
||||
key or the raw value in hexadecimal format. Use @code{-} to press
|
||||
several keys simultaneously. Example:
|
||||
@example
|
||||
sendkey ctrl-alt-f1
|
||||
@end example
|
||||
|
||||
@@ -413,6 +413,8 @@ void hmp_info_spice(Monitor *mon)
|
||||
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
|
||||
info->host, info->tls_port);
|
||||
}
|
||||
monitor_printf(mon, " migrated: %s\n",
|
||||
info->migrated ? "true" : "false");
|
||||
monitor_printf(mon, " auth: %s\n", info->auth);
|
||||
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
||||
monitor_printf(mon, " mouse-mode: %s\n",
|
||||
|
||||
+2
-1
@@ -489,7 +489,8 @@ static int armv7m_nvic_init(SysBusDevice *dev)
|
||||
*/
|
||||
memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem,
|
||||
0x100, 0xc00);
|
||||
memory_region_add_subregion_overlap(&s->container, 0x100, &s->gic.iomem, 1);
|
||||
memory_region_add_subregion_overlap(&s->container, 0x100,
|
||||
&s->gic_iomem_alias, 1);
|
||||
/* Map the whole thing into system memory at the location required
|
||||
* by the v7M architecture.
|
||||
*/
|
||||
|
||||
+1
-1
@@ -404,7 +404,7 @@ static uint64_t uart_read(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t c = 0;
|
||||
|
||||
offset >>= 2;
|
||||
if (offset > R_MAX) {
|
||||
if (offset >= R_MAX) {
|
||||
return 0;
|
||||
} else if (offset == R_TX_RX) {
|
||||
uart_read_rx_fifo(s, &c);
|
||||
|
||||
@@ -295,6 +295,7 @@ set_rx_control(E1000State *s, int index, uint32_t val)
|
||||
s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
|
||||
DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
|
||||
s->mac_reg[RCTL]);
|
||||
qemu_flush_queued_packets(&s->nic->nc);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -926,6 +927,9 @@ set_rdt(E1000State *s, int index, uint32_t val)
|
||||
{
|
||||
s->check_rxov = 0;
|
||||
s->mac_reg[index] = val & 0xffff;
|
||||
if (e1000_has_rxbufs(s, 1)) {
|
||||
qemu_flush_queued_packets(&s->nic->nc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+3
-1
@@ -1036,6 +1036,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
|
||||
}
|
||||
set_ru_state(s, ru_ready);
|
||||
s->ru_offset = e100_read_reg4(s, SCBPointer);
|
||||
qemu_flush_queued_packets(&s->nic->nc);
|
||||
TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
|
||||
break;
|
||||
case RX_RESUME:
|
||||
@@ -1770,7 +1771,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
||||
if (rfd_command & COMMAND_EL) {
|
||||
/* EL bit is set, so this was the last frame. */
|
||||
logout("receive: Running out of frames\n");
|
||||
set_ru_state(s, ru_suspended);
|
||||
set_ru_state(s, ru_no_resources);
|
||||
eepro100_rnr_interrupt(s);
|
||||
}
|
||||
if (rfd_command & COMMAND_S) {
|
||||
/* S bit is set. */
|
||||
|
||||
@@ -269,6 +269,17 @@ static int glue(load_elf, SZ)(const char *name, int fd,
|
||||
addr = ph->p_paddr;
|
||||
}
|
||||
|
||||
/* the entry pointer in the ELF header is a virtual
|
||||
* address, if the text segments paddr and vaddr differ
|
||||
* we need to adjust the entry */
|
||||
if (pentry && !translate_fn &&
|
||||
ph->p_vaddr != ph->p_paddr &&
|
||||
ehdr.e_entry >= ph->p_vaddr &&
|
||||
ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
|
||||
ph->p_flags & PF_X) {
|
||||
*pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
|
||||
}
|
||||
|
||||
snprintf(label, sizeof(label), "phdr #%d: %s", i, name);
|
||||
rom_add_blob_fixed(label, data, mem_size, addr);
|
||||
|
||||
|
||||
+1
-1
@@ -1175,7 +1175,6 @@ void ahci_init(AHCIState *s, DeviceState *qdev, DMAContext *dma, int ports)
|
||||
ad->port_no = i;
|
||||
ad->port.dma = &ad->dma;
|
||||
ad->port.dma->ops = &ahci_dma_ops;
|
||||
ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1199,6 +1198,7 @@ void ahci_reset(AHCIState *s)
|
||||
pr->irq_stat = 0;
|
||||
pr->irq_mask = 0;
|
||||
pr->scr_ctl = 0;
|
||||
pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
|
||||
ahci_reset_port(s, i);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-9
@@ -53,8 +53,6 @@ static const int smart_attributes[][12] = {
|
||||
{ 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
/* airflow-temperature-celsius */
|
||||
{ 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
|
||||
/* end of list */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
};
|
||||
|
||||
static int ide_handle_rw_error(IDEState *s, int error, int op);
|
||||
@@ -1468,9 +1466,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
|
||||
case SMART_READ_THRESH:
|
||||
memset(s->io_buffer, 0, 0x200);
|
||||
s->io_buffer[0] = 0x01; /* smart struct version */
|
||||
for (n=0; n<30; n++) {
|
||||
if (smart_attributes[n][0] == 0)
|
||||
break;
|
||||
for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
|
||||
s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
|
||||
s->io_buffer[2+1+(n*12)] = smart_attributes[n][11];
|
||||
}
|
||||
@@ -1484,10 +1480,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
|
||||
case SMART_READ_DATA:
|
||||
memset(s->io_buffer, 0, 0x200);
|
||||
s->io_buffer[0] = 0x01; /* smart struct version */
|
||||
for (n=0; n<30; n++) {
|
||||
if (smart_attributes[n][0] == 0) {
|
||||
break;
|
||||
}
|
||||
for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
|
||||
int i;
|
||||
for(i = 0; i < 11; i++) {
|
||||
s->io_buffer[2+i+(n*12)] = smart_attributes[n][i];
|
||||
|
||||
@@ -125,7 +125,6 @@ static int ioh3420_initfn(PCIDevice *d)
|
||||
rc = pcie_chassis_add_slot(s);
|
||||
if (rc < 0) {
|
||||
goto err_pcie_cap;
|
||||
return rc;
|
||||
}
|
||||
pcie_cap_root_init(d);
|
||||
rc = pcie_aer_init(d, IOH_EP_AER_OFFSET);
|
||||
|
||||
+1
-1
@@ -500,7 +500,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr)
|
||||
}
|
||||
} else {
|
||||
/* Hash matching */
|
||||
hash = (crc32(~0, addr, 6) >> 26);
|
||||
hash = compute_mcast_idx(addr);
|
||||
if (hash & 0x20) {
|
||||
return (s->mac_hashh >> (hash & 0x1f)) & 1;
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -224,7 +224,7 @@ uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right)
|
||||
This model supports 16-bit playback.
|
||||
*/
|
||||
|
||||
if (s->buffer_level >= LM4549_BUFFER_SIZE) {
|
||||
if (s->buffer_level > LM4549_BUFFER_SIZE - 2) {
|
||||
DPRINTF("write_sample Buffer full\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
+6
-6
@@ -378,7 +378,7 @@ static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
|
||||
{
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
if (offset >= 0x200) {
|
||||
hw_error("Bad MBAR read offset 0x%x", (int)offset);
|
||||
}
|
||||
if (m5206_mbar_width[offset >> 2] > 1) {
|
||||
@@ -397,7 +397,7 @@ static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
if (offset >= 0x200) {
|
||||
hw_error("Bad MBAR read offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
@@ -421,7 +421,7 @@ static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
if (offset >= 0x200) {
|
||||
hw_error("Bad MBAR read offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
@@ -445,7 +445,7 @@ static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset,
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
if (offset >= 0x200) {
|
||||
hw_error("Bad MBAR write offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
@@ -469,7 +469,7 @@ static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
if (offset >= 0x200) {
|
||||
hw_error("Bad MBAR write offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
@@ -497,7 +497,7 @@ static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
|
||||
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||
int width;
|
||||
offset &= 0x3ff;
|
||||
if (offset > 0x200) {
|
||||
if (offset >= 0x200) {
|
||||
hw_error("Bad MBAR write offset 0x%x", (int)offset);
|
||||
}
|
||||
width = m5206_mbar_width[offset >> 2];
|
||||
|
||||
+2
-2
@@ -1583,7 +1583,7 @@ static void musicpal_init(ram_addr_t ram_size,
|
||||
* image is smaller than 32 MB.
|
||||
*/
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL,
|
||||
pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
|
||||
"musicpal.flash", flash_size,
|
||||
dinfo->bdrv, 0x10000,
|
||||
(flash_size + 0xffff) >> 16,
|
||||
@@ -1591,7 +1591,7 @@ static void musicpal_init(ram_addr_t ram_size,
|
||||
2, 0x00BF, 0x236D, 0x0000, 0x0000,
|
||||
0x5555, 0x2AAA, 1);
|
||||
#else
|
||||
pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL,
|
||||
pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
|
||||
"musicpal.flash", flash_size,
|
||||
dinfo->bdrv, 0x10000,
|
||||
(flash_size + 0xffff) >> 16,
|
||||
|
||||
@@ -439,7 +439,7 @@ const VMStateDescription vmstate_pci_device = {
|
||||
};
|
||||
|
||||
const VMStateDescription vmstate_pcie_device = {
|
||||
.name = "PCIDevice",
|
||||
.name = "PCIEDevice",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
|
||||
@@ -133,7 +133,6 @@ extern const VMStateDescription vmstate_pcie_device;
|
||||
|
||||
#define VMSTATE_PCIE_DEVICE(_field, _state) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = 2, \
|
||||
.size = sizeof(PCIDevice), \
|
||||
.vmsd = &vmstate_pcie_device, \
|
||||
.flags = VMS_STRUCT, \
|
||||
|
||||
@@ -738,6 +738,11 @@ void pcie_aer_root_init(PCIDevice *dev)
|
||||
PCI_ERR_ROOT_CMD_EN_MASK);
|
||||
pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS,
|
||||
PCI_ERR_ROOT_STATUS_REPORT_MASK);
|
||||
/* PCI_ERR_ROOT_IRQ is RO but devices change it using a
|
||||
* device-specific method.
|
||||
*/
|
||||
pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS,
|
||||
~PCI_ERR_ROOT_IRQ);
|
||||
}
|
||||
|
||||
void pcie_aer_root_reset(PCIDevice *dev)
|
||||
|
||||
+7
-5
@@ -320,7 +320,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
|
||||
}
|
||||
pfl->wcycle++;
|
||||
pfl->cmd = cmd;
|
||||
return;
|
||||
break;
|
||||
case 1:
|
||||
switch (pfl->cmd) {
|
||||
case 0x10: /* Single Byte Program */
|
||||
@@ -375,7 +375,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
|
||||
default:
|
||||
goto error_flash;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case 2:
|
||||
switch (pfl->cmd) {
|
||||
case 0xe8: /* Block write */
|
||||
@@ -406,7 +406,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
|
||||
default:
|
||||
goto error_flash;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case 3: /* Confirm mode */
|
||||
switch (pfl->cmd) {
|
||||
case 0xe8: /* Block write */
|
||||
@@ -422,7 +422,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
|
||||
default:
|
||||
goto error_flash;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
/* Should never happen */
|
||||
DPRINTF("%s: invalid write state\n", __func__);
|
||||
@@ -711,7 +711,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base,
|
||||
pfl->cfi_table[0x33] = 'I';
|
||||
|
||||
pfl->cfi_table[0x34] = '1';
|
||||
pfl->cfi_table[0x35] = '1';
|
||||
pfl->cfi_table[0x35] = '0';
|
||||
|
||||
pfl->cfi_table[0x36] = 0x00;
|
||||
pfl->cfi_table[0x37] = 0x00;
|
||||
@@ -723,6 +723,8 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base,
|
||||
pfl->cfi_table[0x3b] = 0x00;
|
||||
pfl->cfi_table[0x3c] = 0x00;
|
||||
|
||||
pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
|
||||
|
||||
return pfl;
|
||||
}
|
||||
|
||||
|
||||
+12
-6
@@ -117,12 +117,18 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t offset,
|
||||
return s->protected;
|
||||
case 12: /* VECTADDR */
|
||||
/* Read vector address at the start of an ISR. Increases the
|
||||
current priority level to that of the current interrupt. */
|
||||
for (i = 0; i < s->priority; i++)
|
||||
{
|
||||
if ((s->level | s->soft_level) & s->prio_mask[i])
|
||||
break;
|
||||
}
|
||||
* current priority level to that of the current interrupt.
|
||||
*
|
||||
* Since an enabled interrupt X at priority P causes prio_mask[Y]
|
||||
* to have bit X set for all Y > P, this loop will stop with
|
||||
* i == the priority of the highest priority set interrupt.
|
||||
*/
|
||||
for (i = 0; i < s->priority; i++) {
|
||||
if ((s->level | s->soft_level) & s->prio_mask[i + 1]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reading this value with no pending interrupts is undefined.
|
||||
We return the default address. */
|
||||
if (i == PL190_NUM_PRIO)
|
||||
|
||||
@@ -27,6 +27,11 @@
|
||||
|
||||
#include "qxl.h"
|
||||
|
||||
#ifndef CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC
|
||||
/* spice-protocol is too old, add missing definitions */
|
||||
#define QXL_IO_MONITORS_CONFIG_ASYNC (QXL_IO_FLUSH_RELEASE + 1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as
|
||||
* such can be changed by the guest, so to avoid a guest trigerrable
|
||||
@@ -136,6 +141,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
|
||||
|
||||
void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
|
||||
{
|
||||
trace_qxl_set_guest_bug(qxl->id);
|
||||
qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
|
||||
qxl->guest_bug = 1;
|
||||
if (qxl->guestdebug) {
|
||||
@@ -196,6 +202,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
|
||||
spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie);
|
||||
} else {
|
||||
qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
|
||||
qxl_spice_destroy_surface_wait_complete(qxl, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,6 +256,39 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
|
||||
}
|
||||
}
|
||||
|
||||
static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
|
||||
{
|
||||
trace_qxl_spice_monitors_config(qxl->id);
|
||||
/* 0x000b01 == 0.11.1 */
|
||||
#if SPICE_SERVER_VERSION >= 0x000b01 && \
|
||||
defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC)
|
||||
if (replay) {
|
||||
/*
|
||||
* don't use QXL_COOKIE_TYPE_IO:
|
||||
* - we are not running yet (post_load), we will assert
|
||||
* in send_events
|
||||
* - this is not a guest io, but a reply, so async_io isn't set.
|
||||
*/
|
||||
spice_qxl_monitors_config_async(&qxl->ssd.qxl,
|
||||
qxl->guest_monitors_config,
|
||||
MEMSLOT_GROUP_GUEST,
|
||||
(uintptr_t)qxl_cookie_new(
|
||||
QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
|
||||
0));
|
||||
} else {
|
||||
qxl->guest_monitors_config = qxl->ram->monitors_config;
|
||||
spice_qxl_monitors_config_async(&qxl->ssd.qxl,
|
||||
qxl->ram->monitors_config,
|
||||
MEMSLOT_GROUP_GUEST,
|
||||
(uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
|
||||
QXL_IO_MONITORS_CONFIG_ASYNC));
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "qxl: too old spice-protocol/spice-server for "
|
||||
"QXL_IO_MONITORS_CONFIG_ASYNC\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
|
||||
{
|
||||
trace_qxl_spice_reset_image_cache(qxl->id);
|
||||
@@ -538,6 +578,7 @@ static const char *io_port_to_string(uint32_t io_port)
|
||||
= "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
|
||||
[QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC",
|
||||
[QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE",
|
||||
[QXL_IO_MONITORS_CONFIG_ASYNC] = "QXL_IO_MONITORS_CONFIG_ASYNC",
|
||||
};
|
||||
return io_port_to_string[io_port];
|
||||
}
|
||||
@@ -819,6 +860,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
|
||||
case QXL_IO_DESTROY_PRIMARY_ASYNC:
|
||||
case QXL_IO_UPDATE_AREA_ASYNC:
|
||||
case QXL_IO_FLUSH_SURFACES_ASYNC:
|
||||
case QXL_IO_MONITORS_CONFIG_ASYNC:
|
||||
break;
|
||||
case QXL_IO_CREATE_PRIMARY_ASYNC:
|
||||
qxl_create_guest_primary_complete(qxl);
|
||||
@@ -894,6 +936,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
|
||||
case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA:
|
||||
qxl_render_update_area_done(qxl, cookie);
|
||||
break;
|
||||
case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
|
||||
__func__, cookie->type);
|
||||
@@ -958,9 +1002,10 @@ static void qxl_update_irq(PCIQXLDevice *d)
|
||||
static void qxl_check_state(PCIQXLDevice *d)
|
||||
{
|
||||
QXLRam *ram = d->ram;
|
||||
int spice_display_running = qemu_spice_display_is_running(&d->ssd);
|
||||
|
||||
assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
|
||||
assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
|
||||
assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
|
||||
assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
|
||||
}
|
||||
|
||||
static void qxl_reset_state(PCIQXLDevice *d)
|
||||
@@ -1314,6 +1359,13 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->revision <= QXL_REVISION_STABLE_V10 &&
|
||||
io_port >= QXL_IO_FLUSH_SURFACES_ASYNC) {
|
||||
qxl_set_guest_bug(d, "unsupported io %d for revision %d\n",
|
||||
io_port, d->revision);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (io_port) {
|
||||
case QXL_IO_RESET:
|
||||
case QXL_IO_SET_MODE:
|
||||
@@ -1330,10 +1382,10 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
|
||||
break;
|
||||
}
|
||||
trace_qxl_io_unexpected_vga_mode(d->id,
|
||||
io_port, io_port_to_string(io_port));
|
||||
addr, val, io_port_to_string(io_port));
|
||||
/* be nice to buggy guest drivers */
|
||||
if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
|
||||
io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
|
||||
io_port < QXL_IO_RANGE_SIZE) {
|
||||
qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
|
||||
}
|
||||
return;
|
||||
@@ -1361,6 +1413,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
|
||||
io_port = QXL_IO_DESTROY_ALL_SURFACES;
|
||||
goto async_common;
|
||||
case QXL_IO_FLUSH_SURFACES_ASYNC:
|
||||
case QXL_IO_MONITORS_CONFIG_ASYNC:
|
||||
async_common:
|
||||
async = QXL_ASYNC;
|
||||
qemu_mutex_lock(&d->async_lock);
|
||||
@@ -1385,6 +1438,25 @@ async_common:
|
||||
QXLCookie *cookie = NULL;
|
||||
QXLRect update = d->ram->update_area;
|
||||
|
||||
if (d->ram->update_surface > NUM_SURFACES) {
|
||||
qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n",
|
||||
d->ram->update_surface);
|
||||
return;
|
||||
}
|
||||
if (update.left >= update.right || update.top >= update.bottom) {
|
||||
qxl_set_guest_bug(d,
|
||||
"QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n",
|
||||
update.left, update.top, update.right, update.bottom);
|
||||
return;
|
||||
}
|
||||
|
||||
if (update.left < 0 || update.top < 0 || update.left >= update.right ||
|
||||
update.top >= update.bottom) {
|
||||
qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: "
|
||||
"invalid area(%d,%d,%d,%d)\n", update.left,
|
||||
update.right, update.top, update.bottom);
|
||||
break;
|
||||
}
|
||||
if (async == QXL_ASYNC) {
|
||||
cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
|
||||
QXL_IO_UPDATE_AREA_ASYNC);
|
||||
@@ -1490,6 +1562,9 @@ async_common:
|
||||
d->mode = QXL_MODE_UNDEFINED;
|
||||
qxl_spice_destroy_surfaces(d, async);
|
||||
break;
|
||||
case QXL_IO_MONITORS_CONFIG_ASYNC:
|
||||
qxl_spice_monitors_config_async(d, 0);
|
||||
break;
|
||||
default:
|
||||
qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
|
||||
}
|
||||
@@ -1506,9 +1581,9 @@ cancel_async:
|
||||
static uint64_t ioport_read(void *opaque, target_phys_addr_t addr,
|
||||
unsigned size)
|
||||
{
|
||||
PCIQXLDevice *d = opaque;
|
||||
PCIQXLDevice *qxl = opaque;
|
||||
|
||||
trace_qxl_io_read_unexpected(d->id);
|
||||
trace_qxl_io_read_unexpected(qxl->id);
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
@@ -1538,7 +1613,8 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
|
||||
uint32_t old_pending;
|
||||
uint32_t le_events = cpu_to_le32(events);
|
||||
|
||||
assert(d->ssd.running);
|
||||
trace_qxl_send_events(d->id, events);
|
||||
assert(qemu_spice_display_is_running(&d->ssd));
|
||||
old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
|
||||
if ((old_pending & le_events) == le_events) {
|
||||
return;
|
||||
@@ -1785,6 +1861,17 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
||||
io_size = 16;
|
||||
break;
|
||||
case 3: /* qxl-3 */
|
||||
pci_device_rev = QXL_REVISION_STABLE_V10;
|
||||
io_size = 32; /* PCI region size must be pow2 */
|
||||
break;
|
||||
/* 0x000b01 == 0.11.1 */
|
||||
#if SPICE_SERVER_VERSION >= 0x000b01 && \
|
||||
defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC)
|
||||
case 4: /* qxl-4 */
|
||||
pci_device_rev = QXL_REVISION_STABLE_V12;
|
||||
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
pci_device_rev = QXL_DEFAULT_REVISION;
|
||||
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
|
||||
@@ -1983,7 +2070,9 @@ static int qxl_post_load(void *opaque, int version)
|
||||
}
|
||||
qxl_spice_loadvm_commands(d, cmds, out);
|
||||
g_free(cmds);
|
||||
|
||||
if (d->guest_monitors_config) {
|
||||
qxl_spice_monitors_config_async(d, 1);
|
||||
}
|
||||
break;
|
||||
case QXL_MODE_COMPAT:
|
||||
/* note: no need to call qxl_create_memslots, qxl_set_mode
|
||||
@@ -1996,6 +2085,14 @@ static int qxl_post_load(void *opaque, int version)
|
||||
|
||||
#define QXL_SAVE_VERSION 21
|
||||
|
||||
static bool qxl_monitors_config_needed(void *opaque)
|
||||
{
|
||||
PCIQXLDevice *qxl = opaque;
|
||||
|
||||
return qxl->guest_monitors_config != 0;
|
||||
}
|
||||
|
||||
|
||||
static VMStateDescription qxl_memslot = {
|
||||
.name = "qxl-memslot",
|
||||
.version_id = QXL_SAVE_VERSION,
|
||||
@@ -2026,6 +2123,16 @@ static VMStateDescription qxl_surface = {
|
||||
}
|
||||
};
|
||||
|
||||
static VMStateDescription qxl_vmstate_monitors_config = {
|
||||
.name = "qxl/monitors-config",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static VMStateDescription qxl_vmstate = {
|
||||
.name = "qxl",
|
||||
.version_id = QXL_SAVE_VERSION,
|
||||
@@ -2033,7 +2140,7 @@ static VMStateDescription qxl_vmstate = {
|
||||
.pre_save = qxl_pre_save,
|
||||
.pre_load = qxl_pre_load,
|
||||
.post_load = qxl_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
|
||||
VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
|
||||
VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
|
||||
@@ -2052,6 +2159,14 @@ static VMStateDescription qxl_vmstate = {
|
||||
VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (VMStateSubsection[]) {
|
||||
{
|
||||
.vmsd = &qxl_vmstate_monitors_config,
|
||||
.needed = qxl_monitors_config_needed,
|
||||
}, {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static Property qxl_properties[] = {
|
||||
|
||||
@@ -71,6 +71,8 @@ typedef struct PCIQXLDevice {
|
||||
} guest_surfaces;
|
||||
QXLPHYSICAL guest_cursor;
|
||||
|
||||
QXLPHYSICAL guest_monitors_config;
|
||||
|
||||
QemuMutex track_lock;
|
||||
|
||||
/* thread signaling */
|
||||
@@ -128,7 +130,12 @@ typedef struct PCIQXLDevice {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if 0
|
||||
/* spice-server 0.12 is still in development */
|
||||
#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
|
||||
#else
|
||||
#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
|
||||
#endif
|
||||
|
||||
/* qxl.c */
|
||||
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
|
||||
|
||||
+21
-9
@@ -678,7 +678,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
||||
* is actually implemented, but we're good enough.
|
||||
*/
|
||||
outbuf[2] = 5;
|
||||
outbuf[3] = 2; /* Format 2 */
|
||||
outbuf[3] = 2 | 0x10; /* Format 2, HiSup */
|
||||
|
||||
if (buflen > 36) {
|
||||
outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
|
||||
@@ -1449,6 +1449,22 @@ invalid_field:
|
||||
return;
|
||||
}
|
||||
|
||||
static inline bool check_lba_range(SCSIDiskState *s,
|
||||
uint64_t sector_num, uint32_t nb_sectors)
|
||||
{
|
||||
/*
|
||||
* The first line tests that no overflow happens when computing the last
|
||||
* sector. The second line tests that the last accessed sector is in
|
||||
* range.
|
||||
*
|
||||
* Careful, the computations should not underflow for nb_sectors == 0,
|
||||
* and a 0-block read to the first LBA beyond the end of device is
|
||||
* valid.
|
||||
*/
|
||||
return (sector_num <= sector_num + nb_sectors &&
|
||||
sector_num + nb_sectors <= s->qdev.max_lba + 1);
|
||||
}
|
||||
|
||||
typedef struct UnmapCBData {
|
||||
SCSIDiskReq *r;
|
||||
uint8_t *inbuf;
|
||||
@@ -1473,8 +1489,7 @@ static void scsi_unmap_complete(void *opaque, int ret)
|
||||
if (data->count > 0 && !r->req.io_canceled) {
|
||||
sector_num = ldq_be_p(&data->inbuf[0]);
|
||||
nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
|
||||
if (sector_num > sector_num + nb_sectors ||
|
||||
sector_num + nb_sectors - 1 > s->qdev.max_lba) {
|
||||
if (!check_lba_range(s, sector_num, nb_sectors)) {
|
||||
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
||||
goto done;
|
||||
}
|
||||
@@ -1802,8 +1817,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
||||
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
||||
return 0;
|
||||
}
|
||||
if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors ||
|
||||
r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) {
|
||||
if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
|
||||
goto illegal_lba;
|
||||
}
|
||||
|
||||
@@ -1878,8 +1892,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
|
||||
if (r->req.cmd.buf[1] & 0xe0) {
|
||||
goto illegal_request;
|
||||
}
|
||||
if (r->req.cmd.lba > r->req.cmd.lba + len ||
|
||||
r->req.cmd.lba + len - 1 > s->qdev.max_lba) {
|
||||
if (!check_lba_range(s, r->req.cmd.lba, len)) {
|
||||
goto illegal_lba;
|
||||
}
|
||||
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
|
||||
@@ -1907,8 +1920,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
|
||||
if (r->req.cmd.buf[1] & 0xe0) {
|
||||
goto illegal_request;
|
||||
}
|
||||
if (r->req.cmd.lba > r->req.cmd.lba + len ||
|
||||
r->req.cmd.lba + len - 1 > s->qdev.max_lba) {
|
||||
if (!check_lba_range(s, r->req.cmd.lba, len)) {
|
||||
goto illegal_lba;
|
||||
}
|
||||
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
|
||||
|
||||
+6
-1
@@ -556,7 +556,12 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
|
||||
|
||||
static void emulate_spapr_hypercall(CPUPPCState *env)
|
||||
{
|
||||
env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]);
|
||||
if (msr_pr) {
|
||||
hcall_dprintf("Hypercall made with MSR[PR]=1\n");
|
||||
env->gpr[3] = H_PRIVILEGE;
|
||||
} else {
|
||||
env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]);
|
||||
}
|
||||
}
|
||||
|
||||
static void spapr_reset(void *opaque)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "sysemu.h"
|
||||
#include "cpu.h"
|
||||
#include "dyngen-exec.h"
|
||||
#include "qemu-char.h"
|
||||
#include "sysemu.h"
|
||||
#include "qemu-char.h"
|
||||
@@ -714,11 +713,6 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
|
||||
target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode,
|
||||
target_ulong *args)
|
||||
{
|
||||
if (msr_pr) {
|
||||
hcall_dprintf("Hypercall made with MSR[PR]=1\n");
|
||||
return H_PRIVILEGE;
|
||||
}
|
||||
|
||||
if ((opcode <= MAX_HCALL_OPCODE)
|
||||
&& ((opcode & 0x3) == 0)) {
|
||||
spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
|
||||
|
||||
@@ -177,13 +177,13 @@ struct srp_tsk_mgmt {
|
||||
uint8_t reserved1[6];
|
||||
uint64_t tag;
|
||||
uint8_t reserved2[4];
|
||||
uint64_t lun QEMU_PACKED;
|
||||
uint64_t lun;
|
||||
uint8_t reserved3[2];
|
||||
uint8_t tsk_mgmt_func;
|
||||
uint8_t reserved4;
|
||||
uint64_t task_tag;
|
||||
uint8_t reserved5[8];
|
||||
};
|
||||
} QEMU_PACKED;
|
||||
|
||||
/*
|
||||
* We need the packed attribute because the SRP spec only aligns the
|
||||
@@ -198,14 +198,14 @@ struct srp_cmd {
|
||||
uint8_t data_in_desc_cnt;
|
||||
uint64_t tag;
|
||||
uint8_t reserved2[4];
|
||||
uint64_t lun QEMU_PACKED;
|
||||
uint64_t lun;
|
||||
uint8_t reserved3;
|
||||
uint8_t task_attr;
|
||||
uint8_t reserved4;
|
||||
uint8_t add_cdb_len;
|
||||
uint8_t cdb[16];
|
||||
uint8_t add_data[0];
|
||||
};
|
||||
} QEMU_PACKED;
|
||||
|
||||
enum {
|
||||
SRP_RSP_FLAG_RSPVALID = 1 << 0,
|
||||
|
||||
@@ -377,6 +377,8 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
|
||||
uint16_t raw);
|
||||
int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
|
||||
void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled);
|
||||
USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
|
||||
uint64_t id);
|
||||
|
||||
void usb_attach(USBPort *port);
|
||||
void usb_detach(USBPort *port);
|
||||
|
||||
+20
-3
@@ -398,9 +398,11 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
|
||||
* When pipelining is enabled usb-devices must always return async,
|
||||
* otherwise packets can complete out of order!
|
||||
*/
|
||||
assert(!p->ep->pipeline);
|
||||
p->result = ret;
|
||||
usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||
assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue));
|
||||
if (ret != USB_RET_NAK) {
|
||||
p->result = ret;
|
||||
usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = USB_RET_ASYNC;
|
||||
@@ -724,3 +726,18 @@ void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled)
|
||||
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
|
||||
uep->pipeline = enabled;
|
||||
}
|
||||
|
||||
USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
|
||||
uint64_t id)
|
||||
{
|
||||
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
|
||||
USBPacket *p;
|
||||
|
||||
while ((p = QTAILQ_FIRST(&uep->queue)) != NULL) {
|
||||
if (p->id == id) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+1
-1
@@ -217,7 +217,7 @@ static const USBDescIface desc_iface[] = {
|
||||
};
|
||||
|
||||
static const USBDescDevice desc_device = {
|
||||
.bcdUSB = 0x0200,
|
||||
.bcdUSB = 0x0100,
|
||||
.bMaxPacketSize0 = 64,
|
||||
.bNumConfigurations = 1,
|
||||
.confs = (USBDescConfig[]) {
|
||||
|
||||
+33
-16
@@ -1001,6 +1001,13 @@ static int rndis_keepalive_response(USBNetState *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prepare to receive the next packet */
|
||||
static void usb_net_reset_in_buf(USBNetState *s)
|
||||
{
|
||||
s->in_ptr = s->in_len = 0;
|
||||
qemu_flush_queued_packets(&s->nic->nc);
|
||||
}
|
||||
|
||||
static int rndis_parse(USBNetState *s, uint8_t *data, int length)
|
||||
{
|
||||
uint32_t msg_type;
|
||||
@@ -1025,7 +1032,8 @@ static int rndis_parse(USBNetState *s, uint8_t *data, int length)
|
||||
|
||||
case RNDIS_RESET_MSG:
|
||||
rndis_clear_responsequeue(s);
|
||||
s->out_ptr = s->in_ptr = s->in_len = 0;
|
||||
s->out_ptr = 0;
|
||||
usb_net_reset_in_buf(s);
|
||||
return rndis_reset_response(s, (rndis_reset_msg_type *) data);
|
||||
|
||||
case RNDIS_KEEPALIVE_MSG:
|
||||
@@ -1135,7 +1143,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
|
||||
int ret = USB_RET_NAK;
|
||||
|
||||
if (s->in_ptr > s->in_len) {
|
||||
s->in_ptr = s->in_len = 0;
|
||||
usb_net_reset_in_buf(s);
|
||||
ret = USB_RET_NAK;
|
||||
return ret;
|
||||
}
|
||||
@@ -1152,7 +1160,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
|
||||
if (s->in_ptr >= s->in_len &&
|
||||
(is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
|
||||
/* no short packet necessary */
|
||||
s->in_ptr = s->in_len = 0;
|
||||
usb_net_reset_in_buf(s);
|
||||
}
|
||||
|
||||
#ifdef TRAFFIC_DEBUG
|
||||
@@ -1250,20 +1258,32 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
|
||||
static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
{
|
||||
USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
|
||||
struct rndis_packet_msg_type *msg;
|
||||
uint8_t *in_buf = s->in_buf;
|
||||
size_t total_size = size;
|
||||
|
||||
if (is_rndis(s)) {
|
||||
msg = (struct rndis_packet_msg_type *) s->in_buf;
|
||||
if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
|
||||
return -1;
|
||||
}
|
||||
if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf))
|
||||
return -1;
|
||||
total_size += sizeof(struct rndis_packet_msg_type);
|
||||
}
|
||||
if (total_size > sizeof(s->in_buf)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Only accept packet if input buffer is empty */
|
||||
if (s->in_len > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_rndis(s)) {
|
||||
struct rndis_packet_msg_type *msg;
|
||||
|
||||
msg = (struct rndis_packet_msg_type *)in_buf;
|
||||
memset(msg, 0, sizeof(struct rndis_packet_msg_type));
|
||||
msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
|
||||
msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type));
|
||||
msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8);
|
||||
msg->MessageLength = cpu_to_le32(size + sizeof(*msg));
|
||||
msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8);
|
||||
msg->DataLength = cpu_to_le32(size);
|
||||
/* msg->OOBDataOffset;
|
||||
* msg->OOBDataLength;
|
||||
@@ -1273,14 +1293,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz
|
||||
* msg->VcHandle;
|
||||
* msg->Reserved;
|
||||
*/
|
||||
memcpy(msg + 1, buf, size);
|
||||
s->in_len = size + sizeof(struct rndis_packet_msg_type);
|
||||
} else {
|
||||
if (size > sizeof(s->in_buf))
|
||||
return -1;
|
||||
memcpy(s->in_buf, buf, size);
|
||||
s->in_len = size;
|
||||
in_buf += sizeof(*msg);
|
||||
}
|
||||
|
||||
memcpy(in_buf, buf, size);
|
||||
s->in_len = total_size;
|
||||
s->in_ptr = 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ enum {
|
||||
static const USBDescStrings desc_strings = {
|
||||
[STR_MANUFACTURER] = "QEMU",
|
||||
[STR_PRODUCT_SERIAL] = "QEMU USB SERIAL",
|
||||
[STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE",
|
||||
[STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE",
|
||||
[STR_SERIALNUMBER] = "1",
|
||||
};
|
||||
|
||||
|
||||
+256
-153
@@ -2,6 +2,11 @@
|
||||
* QEMU USB EHCI Emulation
|
||||
*
|
||||
* Copyright(c) 2008 Emutex Ltd. (address@hidden)
|
||||
* Copyright(c) 2011-2012 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat Authors:
|
||||
* Gerd Hoffmann <kraxel@redhat.com>
|
||||
* Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* EHCI project was started by Mark Burkley, with contributions by
|
||||
* Niels de Vos. David S. Ahern continued working on it. Kevin Wolf,
|
||||
@@ -29,6 +34,7 @@
|
||||
#include "monitor.h"
|
||||
#include "trace.h"
|
||||
#include "dma.h"
|
||||
#include "sysemu.h"
|
||||
|
||||
#define EHCI_DEBUG 0
|
||||
|
||||
@@ -134,6 +140,7 @@
|
||||
#define NB_PORTS 6 // Number of downstream ports
|
||||
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
|
||||
#define MAX_QH 100 // Max allowable queue heads in a chain
|
||||
#define MIN_FR_PER_TICK 3 // Min frames to process when catching up
|
||||
|
||||
/* Internal periodic / asynchronous schedule state machine states
|
||||
*/
|
||||
@@ -340,6 +347,7 @@ typedef struct EHCIState EHCIState;
|
||||
|
||||
enum async_state {
|
||||
EHCI_ASYNC_NONE = 0,
|
||||
EHCI_ASYNC_INITIALIZED,
|
||||
EHCI_ASYNC_INFLIGHT,
|
||||
EHCI_ASYNC_FINISHED,
|
||||
};
|
||||
@@ -365,7 +373,6 @@ struct EHCIQueue {
|
||||
uint32_t seen;
|
||||
uint64_t ts;
|
||||
int async;
|
||||
int revalidate;
|
||||
|
||||
/* cached data from guest - needs to be flushed
|
||||
* when guest removes an entry (doorbell, handshake sequence)
|
||||
@@ -384,6 +391,9 @@ struct EHCIState {
|
||||
USBBus bus;
|
||||
qemu_irq irq;
|
||||
MemoryRegion mem;
|
||||
MemoryRegion mem_caps;
|
||||
MemoryRegion mem_opreg;
|
||||
MemoryRegion mem_ports;
|
||||
int companion_count;
|
||||
|
||||
/* properties */
|
||||
@@ -393,10 +403,10 @@ struct EHCIState {
|
||||
* EHCI spec version 1.0 Section 2.3
|
||||
* Host Controller Operational Registers
|
||||
*/
|
||||
uint8_t caps[OPREGBASE];
|
||||
union {
|
||||
uint8_t mmio[MMIO_SIZE];
|
||||
uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)];
|
||||
struct {
|
||||
uint8_t cap[OPREGBASE];
|
||||
uint32_t usbcmd;
|
||||
uint32_t usbsts;
|
||||
uint32_t usbintr;
|
||||
@@ -406,9 +416,9 @@ struct EHCIState {
|
||||
uint32_t asynclistaddr;
|
||||
uint32_t notused[9];
|
||||
uint32_t configflag;
|
||||
uint32_t portsc[NB_PORTS];
|
||||
};
|
||||
};
|
||||
uint32_t portsc[NB_PORTS];
|
||||
|
||||
/*
|
||||
* Internal states, shadow registers, etc
|
||||
@@ -466,25 +476,18 @@ static const char *ehci_state_names[] = {
|
||||
};
|
||||
|
||||
static const char *ehci_mmio_names[] = {
|
||||
[CAPLENGTH] = "CAPLENGTH",
|
||||
[HCIVERSION] = "HCIVERSION",
|
||||
[HCSPARAMS] = "HCSPARAMS",
|
||||
[HCCPARAMS] = "HCCPARAMS",
|
||||
[USBCMD] = "USBCMD",
|
||||
[USBSTS] = "USBSTS",
|
||||
[USBINTR] = "USBINTR",
|
||||
[FRINDEX] = "FRINDEX",
|
||||
[PERIODICLISTBASE] = "P-LIST BASE",
|
||||
[ASYNCLISTADDR] = "A-LIST ADDR",
|
||||
[PORTSC_BEGIN] = "PORTSC #0",
|
||||
[PORTSC_BEGIN + 4] = "PORTSC #1",
|
||||
[PORTSC_BEGIN + 8] = "PORTSC #2",
|
||||
[PORTSC_BEGIN + 12] = "PORTSC #3",
|
||||
[PORTSC_BEGIN + 16] = "PORTSC #4",
|
||||
[PORTSC_BEGIN + 20] = "PORTSC #5",
|
||||
[CONFIGFLAG] = "CONFIGFLAG",
|
||||
};
|
||||
|
||||
static int ehci_state_executing(EHCIQueue *q);
|
||||
static int ehci_state_writeback(EHCIQueue *q);
|
||||
|
||||
static const char *nr2str(const char **n, size_t len, uint32_t nr)
|
||||
{
|
||||
if (nr < len && n[nr] != NULL) {
|
||||
@@ -501,7 +504,8 @@ static const char *state2str(uint32_t state)
|
||||
|
||||
static const char *addr2str(target_phys_addr_t addr)
|
||||
{
|
||||
return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
|
||||
return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names),
|
||||
addr + OPREGBASE);
|
||||
}
|
||||
|
||||
static void ehci_trace_usbsts(uint32_t mask, int state)
|
||||
@@ -709,6 +713,12 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr,
|
||||
(bool)(sitd->results & SITD_RESULTS_ACTIVE));
|
||||
}
|
||||
|
||||
static void ehci_trace_guest_bug(EHCIState *s, const char *message)
|
||||
{
|
||||
trace_usb_ehci_guest_bug(message);
|
||||
fprintf(stderr, "ehci warning: %s\n", message);
|
||||
}
|
||||
|
||||
static inline bool ehci_enabled(EHCIState *s)
|
||||
{
|
||||
return s->usbcmd & USBCMD_RUNSTOP;
|
||||
@@ -740,9 +750,25 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
|
||||
|
||||
static void ehci_free_packet(EHCIPacket *p)
|
||||
{
|
||||
if (p->async == EHCI_ASYNC_FINISHED) {
|
||||
int state = ehci_get_state(p->queue->ehci, p->queue->async);
|
||||
/* This is a normal, but rare condition (cancel racing completion) */
|
||||
fprintf(stderr, "EHCI: Warning packet completed but not processed\n");
|
||||
ehci_state_executing(p->queue);
|
||||
ehci_state_writeback(p->queue);
|
||||
ehci_set_state(p->queue->ehci, p->queue->async, state);
|
||||
/* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */
|
||||
return;
|
||||
}
|
||||
trace_usb_ehci_packet_action(p->queue, p, "free");
|
||||
if (p->async == EHCI_ASYNC_INITIALIZED) {
|
||||
usb_packet_unmap(&p->packet, &p->sgl);
|
||||
qemu_sglist_destroy(&p->sgl);
|
||||
}
|
||||
if (p->async == EHCI_ASYNC_INFLIGHT) {
|
||||
usb_cancel_packet(&p->packet);
|
||||
usb_packet_unmap(&p->packet, &p->sgl);
|
||||
qemu_sglist_destroy(&p->sgl);
|
||||
}
|
||||
QTAILQ_REMOVE(&p->queue->packets, p, next);
|
||||
usb_packet_cleanup(&p->packet);
|
||||
@@ -766,27 +792,45 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
|
||||
return q;
|
||||
}
|
||||
|
||||
static void ehci_cancel_queue(EHCIQueue *q)
|
||||
static int ehci_cancel_queue(EHCIQueue *q)
|
||||
{
|
||||
EHCIPacket *p;
|
||||
int packets = 0;
|
||||
|
||||
p = QTAILQ_FIRST(&q->packets);
|
||||
if (p == NULL) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
trace_usb_ehci_queue_action(q, "cancel");
|
||||
do {
|
||||
ehci_free_packet(p);
|
||||
packets++;
|
||||
} while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
|
||||
return packets;
|
||||
}
|
||||
|
||||
static void ehci_free_queue(EHCIQueue *q)
|
||||
static int ehci_reset_queue(EHCIQueue *q)
|
||||
{
|
||||
int packets;
|
||||
|
||||
trace_usb_ehci_queue_action(q, "reset");
|
||||
packets = ehci_cancel_queue(q);
|
||||
q->dev = NULL;
|
||||
q->qtdaddr = 0;
|
||||
return packets;
|
||||
}
|
||||
|
||||
static void ehci_free_queue(EHCIQueue *q, const char *warn)
|
||||
{
|
||||
EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
|
||||
int cancelled;
|
||||
|
||||
trace_usb_ehci_queue_action(q, "free");
|
||||
ehci_cancel_queue(q);
|
||||
cancelled = ehci_cancel_queue(q);
|
||||
if (warn && cancelled > 0) {
|
||||
ehci_trace_guest_bug(q->ehci, warn);
|
||||
}
|
||||
QTAILQ_REMOVE(head, q, next);
|
||||
g_free(q);
|
||||
}
|
||||
@@ -805,20 +849,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ehci_queues_tag_unused_async(EHCIState *ehci)
|
||||
{
|
||||
EHCIQueue *q;
|
||||
|
||||
QTAILQ_FOREACH(q, &ehci->aqueues, next) {
|
||||
if (!q->seen) {
|
||||
q->revalidate = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ehci_queues_rip_unused(EHCIState *ehci, int async)
|
||||
{
|
||||
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
||||
const char *warn = async ? "guest unlinked busy QH" : NULL;
|
||||
uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
|
||||
EHCIQueue *q, *tmp;
|
||||
|
||||
@@ -831,7 +865,19 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async)
|
||||
if (ehci->last_run_ns < q->ts + maxage) {
|
||||
continue;
|
||||
}
|
||||
ehci_free_queue(q);
|
||||
ehci_free_queue(q, warn);
|
||||
}
|
||||
}
|
||||
|
||||
static void ehci_queues_rip_unseen(EHCIState *ehci, int async)
|
||||
{
|
||||
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
||||
EHCIQueue *q, *tmp;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
|
||||
if (!q->seen) {
|
||||
ehci_free_queue(q, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,17 +890,18 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async)
|
||||
if (q->dev != dev) {
|
||||
continue;
|
||||
}
|
||||
ehci_free_queue(q);
|
||||
ehci_free_queue(q, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ehci_queues_rip_all(EHCIState *ehci, int async)
|
||||
{
|
||||
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
||||
const char *warn = async ? "guest stopped busy async schedule" : NULL;
|
||||
EHCIQueue *q, *tmp;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
|
||||
ehci_free_queue(q);
|
||||
ehci_free_queue(q, warn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -979,7 +1026,7 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
|
||||
}
|
||||
|
||||
s->companion_count++;
|
||||
s->mmio[0x05] = (s->companion_count << 4) | portcount;
|
||||
s->caps[0x05] = (s->companion_count << 4) | portcount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1024,7 +1071,8 @@ static void ehci_reset(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
|
||||
memset(&s->opreg, 0x00, sizeof(s->opreg));
|
||||
memset(&s->portsc, 0x00, sizeof(s->portsc));
|
||||
|
||||
s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
|
||||
s->usbsts = USBSTS_HALT;
|
||||
@@ -1051,50 +1099,35 @@ static void ehci_reset(void *opaque)
|
||||
qemu_bh_cancel(s->async_bh);
|
||||
}
|
||||
|
||||
static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
|
||||
static uint64_t ehci_caps_read(void *ptr, target_phys_addr_t addr,
|
||||
unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
return s->caps[addr];
|
||||
}
|
||||
|
||||
static uint64_t ehci_opreg_read(void *ptr, target_phys_addr_t addr,
|
||||
unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
uint32_t val;
|
||||
|
||||
val = s->mmio[addr];
|
||||
|
||||
val = s->opreg[addr >> 2];
|
||||
trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr)
|
||||
static uint64_t ehci_port_read(void *ptr, target_phys_addr_t addr,
|
||||
unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
uint32_t val;
|
||||
|
||||
val = s->mmio[addr] | (s->mmio[addr+1] << 8);
|
||||
|
||||
val = s->portsc[addr >> 2];
|
||||
trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
uint32_t val;
|
||||
|
||||
val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
|
||||
(s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);
|
||||
|
||||
trace_usb_ehci_mmio_readl(addr, addr2str(addr), val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
|
||||
{
|
||||
USBDevice *dev = s->ports[port].dev;
|
||||
@@ -1123,11 +1156,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
|
||||
static void ehci_port_write(void *ptr, target_phys_addr_t addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
int port = addr >> 2;
|
||||
uint32_t *portsc = &s->portsc[port];
|
||||
uint32_t old = *portsc;
|
||||
USBDevice *dev = s->ports[port].dev;
|
||||
|
||||
trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val);
|
||||
|
||||
/* Clear rwc bits */
|
||||
*portsc &= ~(val & PORTSC_RWC_MASK);
|
||||
/* The guest may clear, but not set the PED bit */
|
||||
@@ -1159,39 +1198,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
|
||||
|
||||
*portsc &= ~PORTSC_RO_MASK;
|
||||
*portsc |= val;
|
||||
trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old);
|
||||
}
|
||||
|
||||
static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
static void ehci_opreg_write(void *ptr, target_phys_addr_t addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);
|
||||
uint32_t *mmio = s->opreg + (addr >> 2);
|
||||
uint32_t old = *mmio;
|
||||
int i;
|
||||
|
||||
trace_usb_ehci_mmio_writel(addr, addr2str(addr), val);
|
||||
trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val);
|
||||
|
||||
/* Only aligned reads are allowed on OHCI */
|
||||
if (addr & 3) {
|
||||
fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x"
|
||||
TARGET_FMT_plx "\n", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {
|
||||
handle_port_status_write(s, (addr-PORTSC)/4, val);
|
||||
trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr < OPREGBASE) {
|
||||
fprintf(stderr, "usb-ehci: write attempt to read-only register"
|
||||
TARGET_FMT_plx "\n", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Do any register specific pre-write processing here. */
|
||||
switch(addr) {
|
||||
switch (addr + OPREGBASE) {
|
||||
case USBCMD:
|
||||
if (val & USBCMD_HCRESET) {
|
||||
ehci_reset(s);
|
||||
@@ -1202,7 +1222,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
/* not supporting dynamic frame list size at the moment */
|
||||
if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
|
||||
fprintf(stderr, "attempt to set frame list size -- value %d\n",
|
||||
val & USBCMD_FLS);
|
||||
(int)val & USBCMD_FLS);
|
||||
val &= ~USBCMD_FLS;
|
||||
}
|
||||
|
||||
@@ -1213,6 +1233,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
*/
|
||||
s->async_stepdown = 0;
|
||||
qemu_bh_schedule(s->async_bh);
|
||||
trace_usb_ehci_doorbell_ring();
|
||||
}
|
||||
|
||||
if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) !=
|
||||
@@ -1268,7 +1289,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
}
|
||||
|
||||
*mmio = val;
|
||||
trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
|
||||
trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old);
|
||||
}
|
||||
|
||||
|
||||
@@ -1450,8 +1471,8 @@ static void ehci_execute_complete(EHCIQueue *q)
|
||||
|
||||
assert(p != NULL);
|
||||
assert(p->qtdaddr == q->qtdaddr);
|
||||
assert(p->async != EHCI_ASYNC_INFLIGHT);
|
||||
p->async = EHCI_ASYNC_NONE;
|
||||
assert(p->async == EHCI_ASYNC_INITIALIZED ||
|
||||
p->async == EHCI_ASYNC_FINISHED);
|
||||
|
||||
DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
|
||||
q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
|
||||
@@ -1481,10 +1502,6 @@ static void ehci_execute_complete(EHCIQueue *q)
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
} else if ((p->usb_status > p->tbytes) && (p->pid == USB_TOKEN_IN)) {
|
||||
p->usb_status = USB_RET_BABBLE;
|
||||
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
|
||||
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
|
||||
} else {
|
||||
// TODO check 4.12 for splits
|
||||
|
||||
@@ -1500,6 +1517,7 @@ static void ehci_execute_complete(EHCIQueue *q)
|
||||
ehci_finish_transfer(q, p->usb_status);
|
||||
usb_packet_unmap(&p->packet, &p->sgl);
|
||||
qemu_sglist_destroy(&p->sgl);
|
||||
p->async = EHCI_ASYNC_NONE;
|
||||
|
||||
q->qh.token ^= QTD_TOKEN_DTOGGLE;
|
||||
q->qh.token &= ~QTD_TOKEN_ACTIVE;
|
||||
@@ -1517,6 +1535,9 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
int ret;
|
||||
int endp;
|
||||
|
||||
assert(p->async == EHCI_ASYNC_NONE ||
|
||||
p->async == EHCI_ASYNC_INITIALIZED);
|
||||
|
||||
if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
|
||||
fprintf(stderr, "Attempting to execute inactive qtd\n");
|
||||
return USB_RET_PROCERR;
|
||||
@@ -1524,7 +1545,8 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
|
||||
p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
|
||||
if (p->tbytes > BUFF_SIZE) {
|
||||
fprintf(stderr, "Request for more bytes than allowed\n");
|
||||
ehci_trace_guest_bug(p->queue->ehci,
|
||||
"guest requested more bytes than allowed");
|
||||
return USB_RET_PROCERR;
|
||||
}
|
||||
|
||||
@@ -1544,15 +1566,18 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ehci_init_transfer(p) != 0) {
|
||||
return USB_RET_PROCERR;
|
||||
}
|
||||
|
||||
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
|
||||
ep = usb_ep_get(p->queue->dev, p->pid, endp);
|
||||
|
||||
usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
|
||||
usb_packet_map(&p->packet, &p->sgl);
|
||||
if (p->async == EHCI_ASYNC_NONE) {
|
||||
if (ehci_init_transfer(p) != 0) {
|
||||
return USB_RET_PROCERR;
|
||||
}
|
||||
|
||||
usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
|
||||
usb_packet_map(&p->packet, &p->sgl);
|
||||
p->async = EHCI_ASYNC_INITIALIZED;
|
||||
}
|
||||
|
||||
trace_usb_ehci_packet_action(p->queue, p, action);
|
||||
ret = usb_handle_packet(p->queue->dev, &p->packet);
|
||||
@@ -1771,7 +1796,7 @@ out:
|
||||
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||
{
|
||||
EHCIPacket *p;
|
||||
uint32_t entry, devaddr;
|
||||
uint32_t entry, devaddr, endp;
|
||||
EHCIQueue *q;
|
||||
EHCIqh qh;
|
||||
|
||||
@@ -1792,26 +1817,26 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||
|
||||
get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
||||
(uint32_t *) &qh, sizeof(EHCIqh) >> 2);
|
||||
if (q->revalidate && (q->qh.epchar != qh.epchar ||
|
||||
q->qh.epcap != qh.epcap ||
|
||||
q->qh.current_qtd != qh.current_qtd)) {
|
||||
ehci_free_queue(q);
|
||||
q = ehci_alloc_queue(ehci, entry, async);
|
||||
q->seen++;
|
||||
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh);
|
||||
|
||||
/*
|
||||
* The overlay area of the qh should never be changed by the guest,
|
||||
* except when idle, in which case the reset is a nop.
|
||||
*/
|
||||
devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR);
|
||||
endp = get_field(qh.epchar, QH_EPCHAR_EP);
|
||||
if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
|
||||
(endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
|
||||
(memcmp(&qh.current_qtd, &q->qh.current_qtd,
|
||||
9 * sizeof(uint32_t)) != 0) ||
|
||||
(q->dev != NULL && q->dev->addr != devaddr)) {
|
||||
if (ehci_reset_queue(q) > 0) {
|
||||
ehci_trace_guest_bug(ehci, "guest updated active QH");
|
||||
}
|
||||
p = NULL;
|
||||
}
|
||||
q->qh = qh;
|
||||
q->revalidate = 0;
|
||||
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
|
||||
|
||||
devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
|
||||
if (q->dev != NULL && q->dev->addr != devaddr) {
|
||||
if (!QTAILQ_EMPTY(&q->packets)) {
|
||||
/* should not happen (guest bug) */
|
||||
ehci_cancel_queue(q);
|
||||
}
|
||||
q->dev = NULL;
|
||||
}
|
||||
if (q->dev == NULL) {
|
||||
q->dev = ehci_find_device(q->ehci, devaddr);
|
||||
}
|
||||
@@ -1969,8 +1994,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
|
||||
(!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) ||
|
||||
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
|
||||
p->qtd.bufptr[0] != qtd.bufptr[0]) {
|
||||
/* guest bug: guest updated active QH or qTD underneath us */
|
||||
ehci_cancel_queue(q);
|
||||
ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD");
|
||||
p = NULL;
|
||||
} else {
|
||||
p->qtd = qtd;
|
||||
@@ -1989,15 +2014,22 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
|
||||
} else if (p != NULL) {
|
||||
switch (p->async) {
|
||||
case EHCI_ASYNC_NONE:
|
||||
/* Should never happen packet should at least be initialized */
|
||||
assert(0);
|
||||
break;
|
||||
case EHCI_ASYNC_INITIALIZED:
|
||||
/* Previously nacked packet (likely interrupt ep) */
|
||||
ehci_set_state(q->ehci, q->async, EST_EXECUTE);
|
||||
break;
|
||||
ehci_set_state(q->ehci, q->async, EST_EXECUTE);
|
||||
break;
|
||||
case EHCI_ASYNC_INFLIGHT:
|
||||
/* Unfinyshed async handled packet, go horizontal */
|
||||
/* Unfinished async handled packet, go horizontal */
|
||||
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
||||
break;
|
||||
case EHCI_ASYNC_FINISHED:
|
||||
/* Should never happen, as this case is caught by fetchqh */
|
||||
/*
|
||||
* We get here when advqueue moves to a packet which is already
|
||||
* finished, which can happen with packets queued up by fill_queue
|
||||
*/
|
||||
ehci_set_state(q->ehci, q->async, EST_EXECUTING);
|
||||
break;
|
||||
}
|
||||
@@ -2028,7 +2060,7 @@ static int ehci_state_horizqh(EHCIQueue *q)
|
||||
return again;
|
||||
}
|
||||
|
||||
static void ehci_fill_queue(EHCIPacket *p)
|
||||
static int ehci_fill_queue(EHCIPacket *p)
|
||||
{
|
||||
EHCIQueue *q = p->queue;
|
||||
EHCIqtd qtd = p->qtd;
|
||||
@@ -2052,9 +2084,13 @@ static void ehci_fill_queue(EHCIPacket *p)
|
||||
p->qtdaddr = qtdaddr;
|
||||
p->qtd = qtd;
|
||||
p->usb_status = ehci_execute(p, "queue");
|
||||
if (p->usb_status == USB_RET_PROCERR) {
|
||||
break;
|
||||
}
|
||||
assert(p->usb_status == USB_RET_ASYNC);
|
||||
p->async = EHCI_ASYNC_INFLIGHT;
|
||||
}
|
||||
return p->usb_status;
|
||||
}
|
||||
|
||||
static int ehci_state_execute(EHCIQueue *q)
|
||||
@@ -2096,8 +2132,7 @@ static int ehci_state_execute(EHCIQueue *q)
|
||||
trace_usb_ehci_packet_action(p->queue, p, "async");
|
||||
p->async = EHCI_ASYNC_INFLIGHT;
|
||||
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
||||
again = 1;
|
||||
ehci_fill_queue(p);
|
||||
again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2310,8 +2345,8 @@ static void ehci_advance_async_state(EHCIState *ehci)
|
||||
*/
|
||||
if (ehci->usbcmd & USBCMD_IAAD) {
|
||||
/* Remove all unseen qhs from the async qhs queue */
|
||||
ehci_queues_tag_unused_async(ehci);
|
||||
DPRINTF("ASYNC: doorbell request acknowledged\n");
|
||||
ehci_queues_rip_unseen(ehci, async);
|
||||
trace_usb_ehci_doorbell_ack();
|
||||
ehci->usbcmd &= ~USBCMD_IAAD;
|
||||
ehci_raise_irq(ehci, USBSTS_IAA);
|
||||
}
|
||||
@@ -2392,7 +2427,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames)
|
||||
if (ehci->frindex == 0x00004000) {
|
||||
ehci_raise_irq(ehci, USBSTS_FLR);
|
||||
ehci->frindex = 0;
|
||||
if (ehci->usbsts_frindex > 0x00004000) {
|
||||
if (ehci->usbsts_frindex >= 0x00004000) {
|
||||
ehci->usbsts_frindex -= 0x00004000;
|
||||
} else {
|
||||
ehci->usbsts_frindex = 0;
|
||||
@@ -2427,6 +2462,19 @@ static void ehci_frame_timer(void *opaque)
|
||||
}
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
/*
|
||||
* If we're running behind schedule, we should not catch up
|
||||
* too fast, as that will make some guests unhappy:
|
||||
* 1) We must process a minimum of MIN_FR_PER_TICK frames,
|
||||
* otherwise we will never catch up
|
||||
* 2) Process frames until the guest has requested an irq (IOC)
|
||||
*/
|
||||
if (i >= MIN_FR_PER_TICK) {
|
||||
ehci_commit_irq(ehci);
|
||||
if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ehci_update_frindex(ehci, 1);
|
||||
ehci_advance_periodic_state(ehci);
|
||||
ehci->last_run_ns += FRAME_TIMER_NS;
|
||||
@@ -2466,11 +2514,28 @@ static void ehci_async_bh(void *opaque)
|
||||
ehci_advance_async_state(ehci);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ehci_mem_ops = {
|
||||
.old_mmio = {
|
||||
.read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl },
|
||||
.write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel },
|
||||
},
|
||||
static const MemoryRegionOps ehci_mmio_caps_ops = {
|
||||
.read = ehci_caps_read,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 1,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps ehci_mmio_opreg_ops = {
|
||||
.read = ehci_opreg_read,
|
||||
.write = ehci_opreg_write,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps ehci_mmio_port_ops = {
|
||||
.read = ehci_port_read,
|
||||
.write = ehci_port_write,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
@@ -2508,6 +2573,32 @@ static int usb_ehci_post_load(void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
|
||||
{
|
||||
EHCIState *ehci = opaque;
|
||||
|
||||
/*
|
||||
* We don't migrate the EHCIQueue-s, instead we rebuild them for the
|
||||
* schedule in guest memory. We must do the rebuilt ASAP, so that
|
||||
* USB-devices which have async handled packages have a packet in the
|
||||
* ep queue to match the completion with.
|
||||
*/
|
||||
if (state == RUN_STATE_RUNNING) {
|
||||
ehci_advance_async_state(ehci);
|
||||
}
|
||||
|
||||
/*
|
||||
* The schedule rebuilt from guest memory could cause the migration dest
|
||||
* to miss a QH unlink, and fail to cancel packets, since the unlinked QH
|
||||
* will never have existed on the destination. Therefor we must flush the
|
||||
* async schedule on savevm to catch any not yet noticed unlinks.
|
||||
*/
|
||||
if (state == RUN_STATE_SAVE_VM) {
|
||||
ehci_advance_async_state(ehci);
|
||||
ehci_queues_rip_unseen(ehci, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ehci = {
|
||||
.name = "ehci",
|
||||
.version_id = 2,
|
||||
@@ -2627,19 +2718,19 @@ static int usb_ehci_initfn(PCIDevice *dev)
|
||||
pci_conf[0x6e] = 0x00;
|
||||
pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS
|
||||
|
||||
// 2.2 host controller interface version
|
||||
s->mmio[0x00] = (uint8_t) OPREGBASE;
|
||||
s->mmio[0x01] = 0x00;
|
||||
s->mmio[0x02] = 0x00;
|
||||
s->mmio[0x03] = 0x01; // HC version
|
||||
s->mmio[0x04] = NB_PORTS; // Number of downstream ports
|
||||
s->mmio[0x05] = 0x00; // No companion ports at present
|
||||
s->mmio[0x06] = 0x00;
|
||||
s->mmio[0x07] = 0x00;
|
||||
s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable
|
||||
s->mmio[0x09] = 0x68; // EECP
|
||||
s->mmio[0x0a] = 0x00;
|
||||
s->mmio[0x0b] = 0x00;
|
||||
/* 2.2 host controller interface version */
|
||||
s->caps[0x00] = (uint8_t) OPREGBASE;
|
||||
s->caps[0x01] = 0x00;
|
||||
s->caps[0x02] = 0x00;
|
||||
s->caps[0x03] = 0x01; /* HC version */
|
||||
s->caps[0x04] = NB_PORTS; /* Number of downstream ports */
|
||||
s->caps[0x05] = 0x00; /* No companion ports at present */
|
||||
s->caps[0x06] = 0x00;
|
||||
s->caps[0x07] = 0x00;
|
||||
s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */
|
||||
s->caps[0x09] = 0x68; /* EECP */
|
||||
s->caps[0x0a] = 0x00;
|
||||
s->caps[0x0b] = 0x00;
|
||||
|
||||
s->irq = s->dev.irq[3];
|
||||
|
||||
@@ -2657,8 +2748,20 @@ static int usb_ehci_initfn(PCIDevice *dev)
|
||||
usb_packet_init(&s->ipacket);
|
||||
|
||||
qemu_register_reset(ehci_reset, s);
|
||||
qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
|
||||
|
||||
memory_region_init(&s->mem, "ehci", MMIO_SIZE);
|
||||
memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s,
|
||||
"capabilities", OPREGBASE);
|
||||
memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s,
|
||||
"operational", PORTSC_BEGIN - OPREGBASE);
|
||||
memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s,
|
||||
"ports", PORTSC_END - PORTSC_BEGIN);
|
||||
|
||||
memory_region_add_subregion(&s->mem, 0, &s->mem_caps);
|
||||
memory_region_add_subregion(&s->mem, OPREGBASE, &s->mem_opreg);
|
||||
memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports);
|
||||
|
||||
memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE);
|
||||
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
|
||||
|
||||
return 0;
|
||||
|
||||
+4
-6
@@ -729,11 +729,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
|
||||
*int_mask |= 0x01;
|
||||
|
||||
if (pid == USB_TOKEN_IN) {
|
||||
if (len > max_len) {
|
||||
ret = USB_RET_BABBLE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
|
||||
*int_mask |= 0x02;
|
||||
/* short packet: do not update QH */
|
||||
@@ -1005,6 +1000,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
|
||||
}
|
||||
assert(ret == TD_RESULT_ASYNC_START);
|
||||
assert(int_mask == 0);
|
||||
if (ptd.ctrl & TD_CTRL_SPD) {
|
||||
break;
|
||||
}
|
||||
plink = ptd.link;
|
||||
}
|
||||
}
|
||||
@@ -1102,7 +1100,7 @@ static void uhci_process_frame(UHCIState *s)
|
||||
|
||||
case TD_RESULT_ASYNC_START:
|
||||
trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
|
||||
if (is_valid(td.link)) {
|
||||
if (is_valid(td.link) && !(td.ctrl & TD_CTRL_SPD)) {
|
||||
uhci_fill_queue(s, &td);
|
||||
}
|
||||
link = curr_qh ? qh.link : td.link;
|
||||
|
||||
+78
-334
@@ -45,8 +45,6 @@
|
||||
#define MAXPORTS (USB2_PORTS+USB3_PORTS)
|
||||
|
||||
#define TD_QUEUE 24
|
||||
#define BG_XFERS 8
|
||||
#define BG_PKTS 8
|
||||
|
||||
/* Very pessimistic, let's hope it's enough for all cases */
|
||||
#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS)
|
||||
@@ -307,26 +305,21 @@ typedef struct XHCIState XHCIState;
|
||||
typedef struct XHCITransfer {
|
||||
XHCIState *xhci;
|
||||
USBPacket packet;
|
||||
QEMUSGList sgl;
|
||||
bool running_async;
|
||||
bool running_retry;
|
||||
bool cancelled;
|
||||
bool complete;
|
||||
bool backgrounded;
|
||||
unsigned int iso_pkts;
|
||||
unsigned int slotid;
|
||||
unsigned int epid;
|
||||
bool in_xfer;
|
||||
bool iso_xfer;
|
||||
bool bg_xfer;
|
||||
|
||||
unsigned int trb_count;
|
||||
unsigned int trb_alloced;
|
||||
XHCITRB *trbs;
|
||||
|
||||
unsigned int data_length;
|
||||
unsigned int data_alloced;
|
||||
uint8_t *data;
|
||||
|
||||
TRBCCode status;
|
||||
|
||||
unsigned int pkts;
|
||||
@@ -340,14 +333,9 @@ typedef struct XHCIEPContext {
|
||||
unsigned int comp_xfer;
|
||||
XHCITransfer transfers[TD_QUEUE];
|
||||
XHCITransfer *retry;
|
||||
bool bg_running;
|
||||
bool bg_updating;
|
||||
unsigned int next_bg;
|
||||
XHCITransfer bg_transfers[BG_XFERS];
|
||||
EPType type;
|
||||
dma_addr_t pctx;
|
||||
unsigned int max_psize;
|
||||
bool has_bg;
|
||||
uint32_t state;
|
||||
} XHCIEPContext;
|
||||
|
||||
@@ -866,10 +854,6 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
|
||||
epctx->pctx = pctx;
|
||||
epctx->max_psize = ctx[1]>>16;
|
||||
epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
|
||||
epctx->has_bg = false;
|
||||
if (epctx->type == ET_ISO_IN) {
|
||||
epctx->has_bg = true;
|
||||
}
|
||||
DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
|
||||
epid/2, epid%2, epctx->max_psize);
|
||||
for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
|
||||
@@ -916,41 +900,14 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
|
||||
t->running_retry = 0;
|
||||
epctx->retry = NULL;
|
||||
}
|
||||
if (t->backgrounded) {
|
||||
t->backgrounded = 0;
|
||||
}
|
||||
if (t->trbs) {
|
||||
g_free(t->trbs);
|
||||
}
|
||||
if (t->data) {
|
||||
g_free(t->data);
|
||||
}
|
||||
|
||||
t->trbs = NULL;
|
||||
t->data = NULL;
|
||||
t->trb_count = t->trb_alloced = 0;
|
||||
t->data_length = t->data_alloced = 0;
|
||||
xferi = (xferi + 1) % TD_QUEUE;
|
||||
}
|
||||
if (epctx->has_bg) {
|
||||
xferi = epctx->next_bg;
|
||||
for (i = 0; i < BG_XFERS; i++) {
|
||||
XHCITransfer *t = &epctx->bg_transfers[xferi];
|
||||
if (t->running_async) {
|
||||
usb_cancel_packet(&t->packet);
|
||||
t->running_async = 0;
|
||||
t->cancelled = 1;
|
||||
DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i);
|
||||
killed++;
|
||||
}
|
||||
if (t->data) {
|
||||
g_free(t->data);
|
||||
}
|
||||
|
||||
t->data = NULL;
|
||||
xferi = (xferi + 1) % BG_XFERS;
|
||||
}
|
||||
}
|
||||
return killed;
|
||||
}
|
||||
|
||||
@@ -1107,24 +1064,13 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
|
||||
return CC_SUCCESS;
|
||||
}
|
||||
|
||||
static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
||||
unsigned int length, bool in_xfer, bool out_xfer,
|
||||
bool report)
|
||||
static int xhci_xfer_map(XHCITransfer *xfer)
|
||||
{
|
||||
int i;
|
||||
uint32_t edtla = 0;
|
||||
unsigned int transferred = 0;
|
||||
unsigned int left = length;
|
||||
bool reported = 0;
|
||||
bool shortpkt = 0;
|
||||
XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
|
||||
int in_xfer = (xfer->packet.pid == USB_TOKEN_IN);
|
||||
XHCIState *xhci = xfer->xhci;
|
||||
int i;
|
||||
|
||||
DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n",
|
||||
length, in_xfer, out_xfer, report);
|
||||
|
||||
assert(!(in_xfer && out_xfer));
|
||||
|
||||
pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count);
|
||||
for (i = 0; i < xfer->trb_count; i++) {
|
||||
XHCITRB *trb = &xfer->trbs[i];
|
||||
dma_addr_t addr;
|
||||
@@ -1134,54 +1080,70 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
||||
case TR_DATA:
|
||||
if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
|
||||
fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n");
|
||||
xhci_die(xhci);
|
||||
return transferred;
|
||||
goto err;
|
||||
}
|
||||
/* fallthrough */
|
||||
case TR_NORMAL:
|
||||
case TR_ISOCH:
|
||||
addr = xhci_mask64(trb->parameter);
|
||||
chunk = trb->status & 0x1ffff;
|
||||
if (trb->control & TRB_TR_IDT) {
|
||||
if (chunk > 8 || in_xfer) {
|
||||
fprintf(stderr, "xhci: invalid immediate data TRB\n");
|
||||
goto err;
|
||||
}
|
||||
qemu_sglist_add(&xfer->sgl, trb->addr, chunk);
|
||||
} else {
|
||||
qemu_sglist_add(&xfer->sgl, addr, chunk);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
usb_packet_map(&xfer->packet, &xfer->sgl);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
qemu_sglist_destroy(&xfer->sgl);
|
||||
xhci_die(xhci);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void xhci_xfer_unmap(XHCITransfer *xfer)
|
||||
{
|
||||
usb_packet_unmap(&xfer->packet, &xfer->sgl);
|
||||
qemu_sglist_destroy(&xfer->sgl);
|
||||
}
|
||||
|
||||
static void xhci_xfer_report(XHCITransfer *xfer)
|
||||
{
|
||||
uint32_t edtla = 0;
|
||||
unsigned int left;
|
||||
bool reported = 0;
|
||||
bool shortpkt = 0;
|
||||
XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
|
||||
XHCIState *xhci = xfer->xhci;
|
||||
int i;
|
||||
|
||||
left = xfer->packet.result < 0 ? 0 : xfer->packet.result;
|
||||
|
||||
for (i = 0; i < xfer->trb_count; i++) {
|
||||
XHCITRB *trb = &xfer->trbs[i];
|
||||
unsigned int chunk = 0;
|
||||
|
||||
switch (TRB_TYPE(*trb)) {
|
||||
case TR_DATA:
|
||||
case TR_NORMAL:
|
||||
case TR_ISOCH:
|
||||
chunk = trb->status & 0x1ffff;
|
||||
if (chunk > left) {
|
||||
chunk = left;
|
||||
shortpkt = 1;
|
||||
}
|
||||
if (in_xfer || out_xfer) {
|
||||
if (trb->control & TRB_TR_IDT) {
|
||||
uint64_t idata;
|
||||
if (chunk > 8 || in_xfer) {
|
||||
fprintf(stderr, "xhci: invalid immediate data TRB\n");
|
||||
xhci_die(xhci);
|
||||
return transferred;
|
||||
}
|
||||
idata = le64_to_cpu(trb->parameter);
|
||||
memcpy(data, &idata, chunk);
|
||||
} else {
|
||||
DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at "
|
||||
DMA_ADDR_FMT "\n", in_xfer, chunk, addr);
|
||||
if (in_xfer) {
|
||||
pci_dma_write(&xhci->pci_dev, addr, data, chunk);
|
||||
} else {
|
||||
pci_dma_read(&xhci->pci_dev, addr, data, chunk);
|
||||
}
|
||||
#ifdef DEBUG_DATA
|
||||
unsigned int count = chunk;
|
||||
int i;
|
||||
if (count > 16) {
|
||||
count = 16;
|
||||
}
|
||||
DPRINTF(" ::");
|
||||
for (i = 0; i < count; i++) {
|
||||
DPRINTF(" %02x", data[i]);
|
||||
}
|
||||
DPRINTF("\n");
|
||||
#endif
|
||||
if (xfer->status == CC_SUCCESS) {
|
||||
shortpkt = 1;
|
||||
}
|
||||
}
|
||||
left -= chunk;
|
||||
data += chunk;
|
||||
edtla += chunk;
|
||||
transferred += chunk;
|
||||
break;
|
||||
case TR_STATUS:
|
||||
reported = 0;
|
||||
@@ -1189,8 +1151,9 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
||||
break;
|
||||
}
|
||||
|
||||
if (report && !reported && (trb->control & TRB_TR_IOC ||
|
||||
(shortpkt && (trb->control & TRB_TR_ISP)))) {
|
||||
if (!reported && ((trb->control & TRB_TR_IOC) ||
|
||||
(shortpkt && (trb->control & TRB_TR_ISP)) ||
|
||||
(xfer->status != CC_SUCCESS))) {
|
||||
event.slotid = xfer->slotid;
|
||||
event.epid = xfer->epid;
|
||||
event.length = (trb->status & 0x1ffff) - chunk;
|
||||
@@ -1210,9 +1173,11 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
||||
}
|
||||
xhci_event(xhci, &event);
|
||||
reported = 1;
|
||||
if (xfer->status != CC_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return transferred;
|
||||
}
|
||||
|
||||
static void xhci_stall_ep(XHCITransfer *xfer)
|
||||
@@ -1231,160 +1196,6 @@ static void xhci_stall_ep(XHCITransfer *xfer)
|
||||
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
|
||||
XHCIEPContext *epctx);
|
||||
|
||||
static void xhci_bg_update(XHCIState *xhci, XHCIEPContext *epctx)
|
||||
{
|
||||
if (epctx->bg_updating) {
|
||||
return;
|
||||
}
|
||||
DPRINTF("xhci_bg_update(%p, %p)\n", xhci, epctx);
|
||||
assert(epctx->has_bg);
|
||||
DPRINTF("xhci: fg=%d bg=%d\n", epctx->comp_xfer, epctx->next_bg);
|
||||
epctx->bg_updating = 1;
|
||||
while (epctx->transfers[epctx->comp_xfer].backgrounded &&
|
||||
epctx->bg_transfers[epctx->next_bg].complete) {
|
||||
XHCITransfer *fg = &epctx->transfers[epctx->comp_xfer];
|
||||
XHCITransfer *bg = &epctx->bg_transfers[epctx->next_bg];
|
||||
#if 0
|
||||
DPRINTF("xhci: completing fg %d from bg %d.%d (stat: %d)\n",
|
||||
epctx->comp_xfer, epctx->next_bg, bg->cur_pkt,
|
||||
bg->usbxfer->iso_packet_desc[bg->cur_pkt].status
|
||||
);
|
||||
#endif
|
||||
assert(epctx->type == ET_ISO_IN);
|
||||
assert(bg->iso_xfer);
|
||||
assert(bg->in_xfer);
|
||||
uint8_t *p = bg->data + bg->cur_pkt * bg->pktsize;
|
||||
#if 0
|
||||
int len = bg->usbxfer->iso_packet_desc[bg->cur_pkt].actual_length;
|
||||
fg->status = libusb_to_ccode(bg->usbxfer->iso_packet_desc[bg->cur_pkt].status);
|
||||
#else
|
||||
int len = 0;
|
||||
FIXME();
|
||||
#endif
|
||||
fg->complete = 1;
|
||||
fg->backgrounded = 0;
|
||||
|
||||
if (fg->status == CC_STALL_ERROR) {
|
||||
xhci_stall_ep(fg);
|
||||
}
|
||||
|
||||
xhci_xfer_data(fg, p, len, 1, 0, 1);
|
||||
|
||||
epctx->comp_xfer++;
|
||||
if (epctx->comp_xfer == TD_QUEUE) {
|
||||
epctx->comp_xfer = 0;
|
||||
}
|
||||
DPRINTF("next fg xfer: %d\n", epctx->comp_xfer);
|
||||
bg->cur_pkt++;
|
||||
if (bg->cur_pkt == bg->pkts) {
|
||||
bg->complete = 0;
|
||||
if (xhci_submit(xhci, bg, epctx) < 0) {
|
||||
fprintf(stderr, "xhci: bg resubmit failed\n");
|
||||
}
|
||||
epctx->next_bg++;
|
||||
if (epctx->next_bg == BG_XFERS) {
|
||||
epctx->next_bg = 0;
|
||||
}
|
||||
DPRINTF("next bg xfer: %d\n", epctx->next_bg);
|
||||
|
||||
xhci_kick_ep(xhci, fg->slotid, fg->epid);
|
||||
}
|
||||
}
|
||||
epctx->bg_updating = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void xhci_xfer_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
XHCIState *xhci;
|
||||
XHCITransfer *xfer;
|
||||
|
||||
xfer = (XHCITransfer *)transfer->user_data;
|
||||
xhci = xfer->xhci;
|
||||
|
||||
DPRINTF("xhci_xfer_cb(slot=%d, ep=%d, status=%d)\n", xfer->slotid,
|
||||
xfer->epid, transfer->status);
|
||||
|
||||
assert(xfer->slotid >= 1 && xfer->slotid <= MAXSLOTS);
|
||||
assert(xfer->epid >= 1 && xfer->epid <= 31);
|
||||
|
||||
if (xfer->cancelled) {
|
||||
DPRINTF("xhci: transfer cancelled, not reporting anything\n");
|
||||
xfer->running = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
XHCIEPContext *epctx;
|
||||
XHCISlot *slot;
|
||||
slot = &xhci->slots[xfer->slotid-1];
|
||||
assert(slot->eps[xfer->epid-1]);
|
||||
epctx = slot->eps[xfer->epid-1];
|
||||
|
||||
if (xfer->bg_xfer) {
|
||||
DPRINTF("xhci: background transfer, updating\n");
|
||||
xfer->complete = 1;
|
||||
xfer->running = 0;
|
||||
xhci_bg_update(xhci, epctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xfer->iso_xfer) {
|
||||
transfer->status = transfer->iso_packet_desc[0].status;
|
||||
transfer->actual_length = transfer->iso_packet_desc[0].actual_length;
|
||||
}
|
||||
|
||||
xfer->status = libusb_to_ccode(transfer->status);
|
||||
|
||||
xfer->complete = 1;
|
||||
xfer->running = 0;
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_STALL)
|
||||
xhci_stall_ep(xhci, epctx, xfer);
|
||||
|
||||
DPRINTF("xhci: transfer actual length = %d\n", transfer->actual_length);
|
||||
|
||||
if (xfer->in_xfer) {
|
||||
if (xfer->epid == 1) {
|
||||
xhci_xfer_data(xhci, xfer, xfer->data + 8,
|
||||
transfer->actual_length, 1, 0, 1);
|
||||
} else {
|
||||
xhci_xfer_data(xhci, xfer, xfer->data,
|
||||
transfer->actual_length, 1, 0, 1);
|
||||
}
|
||||
} else {
|
||||
xhci_xfer_data(xhci, xfer, NULL, transfer->actual_length, 0, 0, 1);
|
||||
}
|
||||
|
||||
xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
|
||||
}
|
||||
|
||||
static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer,
|
||||
uint8_t bmRequestType, uint8_t bRequest,
|
||||
uint16_t wValue, uint16_t wIndex, uint16_t wLength)
|
||||
{
|
||||
uint16_t type_req = (bmRequestType << 8) | bRequest;
|
||||
|
||||
switch (type_req) {
|
||||
case 0x0000 | USB_REQ_SET_CONFIGURATION:
|
||||
DPRINTF("xhci: HLE switch configuration\n");
|
||||
return xhci_switch_config(xhci, xfer->slotid, wValue) == 0;
|
||||
case 0x0100 | USB_REQ_SET_INTERFACE:
|
||||
DPRINTF("xhci: HLE set interface altsetting\n");
|
||||
return xhci_set_iface_alt(xhci, xfer->slotid, wIndex, wValue) == 0;
|
||||
case 0x0200 | USB_REQ_CLEAR_FEATURE:
|
||||
if (wValue == 0) { // endpoint halt
|
||||
DPRINTF("xhci: HLE clear halt\n");
|
||||
return xhci_clear_halt(xhci, xfer->slotid, wIndex);
|
||||
}
|
||||
case 0x0000 | USB_REQ_SET_ADDRESS:
|
||||
fprintf(stderr, "xhci: warn: illegal SET_ADDRESS request\n");
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
|
||||
{
|
||||
USBEndpoint *ep;
|
||||
@@ -1393,7 +1204,7 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
|
||||
dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
|
||||
ep = usb_ep_get(dev, dir, xfer->epid >> 1);
|
||||
usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr);
|
||||
usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length);
|
||||
xhci_xfer_map(xfer);
|
||||
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
|
||||
xfer->packet.pid, dev->addr, ep->nr);
|
||||
return 0;
|
||||
@@ -1419,12 +1230,13 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
|
||||
xfer->running_async = 0;
|
||||
xfer->running_retry = 0;
|
||||
xfer->complete = 1;
|
||||
xhci_xfer_unmap(xfer);
|
||||
}
|
||||
|
||||
if (ret >= 0) {
|
||||
xfer->status = CC_SUCCESS;
|
||||
xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1);
|
||||
trace_usb_xhci_xfer_success(xfer, ret);
|
||||
xfer->status = CC_SUCCESS;
|
||||
xhci_xfer_report(xfer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1433,12 +1245,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
|
||||
switch (ret) {
|
||||
case USB_RET_NODEV:
|
||||
xfer->status = CC_USB_TRANSACTION_ERROR;
|
||||
xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
|
||||
xhci_xfer_report(xfer);
|
||||
xhci_stall_ep(xfer);
|
||||
break;
|
||||
case USB_RET_STALL:
|
||||
xfer->status = CC_STALL_ERROR;
|
||||
xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
|
||||
xhci_xfer_report(xfer);
|
||||
xhci_stall_ep(xfer);
|
||||
break;
|
||||
default:
|
||||
@@ -1460,7 +1272,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
|
||||
{
|
||||
XHCITRB *trb_setup, *trb_status;
|
||||
uint8_t bmRequestType;
|
||||
uint16_t wLength;
|
||||
XHCIPort *port;
|
||||
USBDevice *dev;
|
||||
int ret;
|
||||
@@ -1468,8 +1279,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
|
||||
trb_setup = &xfer->trbs[0];
|
||||
trb_status = &xfer->trbs[xfer->trb_count-1];
|
||||
|
||||
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid,
|
||||
trb_setup->parameter >> 48);
|
||||
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
|
||||
|
||||
/* at most one Event Data TRB allowed after STATUS */
|
||||
if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
|
||||
@@ -1498,19 +1308,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
|
||||
}
|
||||
|
||||
bmRequestType = trb_setup->parameter;
|
||||
wLength = trb_setup->parameter >> 48;
|
||||
|
||||
if (xfer->data && xfer->data_alloced < wLength) {
|
||||
xfer->data_alloced = 0;
|
||||
g_free(xfer->data);
|
||||
xfer->data = NULL;
|
||||
}
|
||||
if (!xfer->data) {
|
||||
DPRINTF("xhci: alloc %d bytes data\n", wLength);
|
||||
xfer->data = g_malloc(wLength+1);
|
||||
xfer->data_alloced = wLength;
|
||||
}
|
||||
xfer->data_length = wLength;
|
||||
|
||||
port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
|
||||
dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
|
||||
@@ -1525,9 +1322,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
|
||||
|
||||
xhci_setup_packet(xfer, dev);
|
||||
xfer->packet.parameter = trb_setup->parameter;
|
||||
if (!xfer->in_xfer) {
|
||||
xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
|
||||
}
|
||||
|
||||
ret = usb_handle_packet(dev, &xfer->packet);
|
||||
|
||||
@@ -1548,20 +1342,8 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
|
||||
|
||||
xfer->in_xfer = epctx->type>>2;
|
||||
|
||||
if (xfer->data && xfer->data_alloced < xfer->data_length) {
|
||||
xfer->data_alloced = 0;
|
||||
g_free(xfer->data);
|
||||
xfer->data = NULL;
|
||||
}
|
||||
if (!xfer->data && xfer->data_length) {
|
||||
DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length);
|
||||
xfer->data = g_malloc(xfer->data_length);
|
||||
xfer->data_alloced = xfer->data_length;
|
||||
}
|
||||
if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
|
||||
if (!xfer->bg_xfer) {
|
||||
xfer->pkts = 1;
|
||||
}
|
||||
xfer->pkts = 1;
|
||||
} else {
|
||||
xfer->pkts = 0;
|
||||
}
|
||||
@@ -1593,9 +1375,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!xfer->in_xfer) {
|
||||
xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0);
|
||||
}
|
||||
ret = usb_handle_packet(dev, &xfer->packet);
|
||||
|
||||
xhci_complete_packet(xfer, ret);
|
||||
@@ -1607,45 +1386,8 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
|
||||
|
||||
static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
|
||||
{
|
||||
int i;
|
||||
unsigned int length = 0;
|
||||
XHCITRB *trb;
|
||||
|
||||
for (i = 0; i < xfer->trb_count; i++) {
|
||||
trb = &xfer->trbs[i];
|
||||
if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) {
|
||||
length += trb->status & 0x1ffff;
|
||||
}
|
||||
}
|
||||
|
||||
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length);
|
||||
|
||||
if (!epctx->has_bg) {
|
||||
xfer->data_length = length;
|
||||
xfer->backgrounded = 0;
|
||||
return xhci_submit(xhci, xfer, epctx);
|
||||
} else {
|
||||
if (!epctx->bg_running) {
|
||||
for (i = 0; i < BG_XFERS; i++) {
|
||||
XHCITransfer *t = &epctx->bg_transfers[i];
|
||||
t->xhci = xhci;
|
||||
t->epid = xfer->epid;
|
||||
t->slotid = xfer->slotid;
|
||||
t->pkts = BG_PKTS;
|
||||
t->pktsize = epctx->max_psize;
|
||||
t->data_length = t->pkts * t->pktsize;
|
||||
t->bg_xfer = 1;
|
||||
if (xhci_submit(xhci, t, epctx) < 0) {
|
||||
fprintf(stderr, "xhci: bg submit failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
epctx->bg_running = 1;
|
||||
}
|
||||
xfer->backgrounded = 1;
|
||||
xhci_bg_update(xhci, epctx);
|
||||
return 0;
|
||||
}
|
||||
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
|
||||
return xhci_submit(xhci, xfer, epctx);
|
||||
}
|
||||
|
||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
|
||||
@@ -1695,7 +1437,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
|
||||
|
||||
while (1) {
|
||||
XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
|
||||
if (xfer->running_async || xfer->running_retry || xfer->backgrounded) {
|
||||
if (xfer->running_async || xfer->running_retry) {
|
||||
break;
|
||||
}
|
||||
length = xhci_ring_chain_length(xhci, &epctx->ring);
|
||||
@@ -2606,7 +2348,7 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
|
||||
|
||||
static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
|
||||
{
|
||||
trace_usb_xhci_runtime_read(reg, val);
|
||||
trace_usb_xhci_runtime_write(reg, val);
|
||||
|
||||
switch (reg) {
|
||||
case 0x20: /* IMAN */
|
||||
@@ -2732,8 +2474,10 @@ static void xhci_mem_write(void *ptr, target_phys_addr_t addr,
|
||||
static const MemoryRegionOps xhci_mem_ops = {
|
||||
.read = xhci_mem_read,
|
||||
.write = xhci_mem_write,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.impl.min_access_size = 4,
|
||||
.impl.max_access_size = 4,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -1045,7 +1045,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
|
||||
|
||||
/* Note request is (bRequestType << 8) | bRequest */
|
||||
trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
|
||||
assert(p->result == 0);
|
||||
|
||||
switch (request) {
|
||||
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
||||
@@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
|
||||
}
|
||||
|
||||
/* The rest are asynchronous */
|
||||
assert(p && p->result == 0);
|
||||
|
||||
if (length > sizeof(dev->data_buf)) {
|
||||
fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
|
||||
|
||||
+163
-229
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* USB redirector usb-guest
|
||||
*
|
||||
* Copyright (c) 2011 Red Hat, Inc.
|
||||
* Copyright (c) 2011-2012 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat Authors:
|
||||
* Hans de Goede <hdegoede@redhat.com>
|
||||
@@ -43,7 +43,7 @@
|
||||
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
|
||||
#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
|
||||
|
||||
typedef struct AsyncURB AsyncURB;
|
||||
typedef struct Cancelled Cancelled;
|
||||
typedef struct USBRedirDevice USBRedirDevice;
|
||||
|
||||
/* Struct to hold buffered packets (iso or int input packets) */
|
||||
@@ -79,15 +79,14 @@ struct USBRedirDevice {
|
||||
/* Data passed from chardev the fd_read cb to the usbredirparser read cb */
|
||||
const uint8_t *read_buf;
|
||||
int read_buf_size;
|
||||
/* For async handling of open/close */
|
||||
QEMUBH *open_close_bh;
|
||||
/* For async handling of close */
|
||||
QEMUBH *chardev_close_bh;
|
||||
/* To delay the usb attach in case of quick chardev close + open */
|
||||
QEMUTimer *attach_timer;
|
||||
int64_t next_attach_time;
|
||||
struct usbredirparser *parser;
|
||||
struct endp_data endpoint[MAX_ENDPOINTS];
|
||||
uint32_t packet_id;
|
||||
QTAILQ_HEAD(, AsyncURB) asyncq;
|
||||
QTAILQ_HEAD(, Cancelled) cancelled;
|
||||
/* Data for device filtering */
|
||||
struct usb_redir_device_connect_header device_info;
|
||||
struct usb_redir_interface_info_header interface_info;
|
||||
@@ -95,17 +94,9 @@ struct USBRedirDevice {
|
||||
int filter_rules_count;
|
||||
};
|
||||
|
||||
struct AsyncURB {
|
||||
USBRedirDevice *dev;
|
||||
USBPacket *packet;
|
||||
uint32_t packet_id;
|
||||
int get;
|
||||
union {
|
||||
struct usb_redir_control_packet_header control_packet;
|
||||
struct usb_redir_bulk_packet_header bulk_packet;
|
||||
struct usb_redir_interrupt_packet_header interrupt_packet;
|
||||
};
|
||||
QTAILQ_ENTRY(AsyncURB)next;
|
||||
struct Cancelled {
|
||||
uint64_t id;
|
||||
QTAILQ_ENTRY(Cancelled)next;
|
||||
};
|
||||
|
||||
static void usbredir_hello(void *priv, struct usb_redir_hello_header *h);
|
||||
@@ -143,6 +134,8 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
|
||||
static int usbredir_handle_status(USBRedirDevice *dev,
|
||||
int status, int actual_len);
|
||||
|
||||
#define VERSION "qemu usb-redir guest " QEMU_VERSION
|
||||
|
||||
/*
|
||||
* Logging stuff
|
||||
*/
|
||||
@@ -245,58 +238,58 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
|
||||
}
|
||||
|
||||
/*
|
||||
* Async and buffered packets helpers
|
||||
* Cancelled and buffered packets helpers
|
||||
*/
|
||||
|
||||
static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p)
|
||||
{
|
||||
AsyncURB *aurb = (AsyncURB *) g_malloc0(sizeof(AsyncURB));
|
||||
aurb->dev = dev;
|
||||
aurb->packet = p;
|
||||
aurb->packet_id = dev->packet_id;
|
||||
QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next);
|
||||
dev->packet_id++;
|
||||
|
||||
return aurb;
|
||||
}
|
||||
|
||||
static void async_free(USBRedirDevice *dev, AsyncURB *aurb)
|
||||
{
|
||||
QTAILQ_REMOVE(&dev->asyncq, aurb, next);
|
||||
g_free(aurb);
|
||||
}
|
||||
|
||||
static AsyncURB *async_find(USBRedirDevice *dev, uint32_t packet_id)
|
||||
{
|
||||
AsyncURB *aurb;
|
||||
|
||||
QTAILQ_FOREACH(aurb, &dev->asyncq, next) {
|
||||
if (aurb->packet_id == packet_id) {
|
||||
return aurb;
|
||||
}
|
||||
}
|
||||
DPRINTF("could not find async urb for packet_id %u\n", packet_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
|
||||
{
|
||||
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
||||
AsyncURB *aurb;
|
||||
Cancelled *c;
|
||||
|
||||
QTAILQ_FOREACH(aurb, &dev->asyncq, next) {
|
||||
if (p != aurb->packet) {
|
||||
continue;
|
||||
}
|
||||
DPRINTF("cancel packet id %"PRIu64"\n", p->id);
|
||||
|
||||
DPRINTF("async cancel id %u\n", aurb->packet_id);
|
||||
usbredirparser_send_cancel_data_packet(dev->parser, aurb->packet_id);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
c = g_malloc0(sizeof(Cancelled));
|
||||
c->id = p->id;
|
||||
QTAILQ_INSERT_TAIL(&dev->cancelled, c, next);
|
||||
|
||||
/* Mark it as dead */
|
||||
aurb->packet = NULL;
|
||||
break;
|
||||
usbredirparser_send_cancel_data_packet(dev->parser, p->id);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
}
|
||||
|
||||
static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id)
|
||||
{
|
||||
Cancelled *c;
|
||||
|
||||
if (!dev->dev.attached) {
|
||||
return 1; /* Treat everything as cancelled after a disconnect */
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(c, &dev->cancelled, next) {
|
||||
if (c->id == id) {
|
||||
QTAILQ_REMOVE(&dev->cancelled, c, next);
|
||||
g_free(c);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev,
|
||||
uint8_t ep, uint64_t id)
|
||||
{
|
||||
USBPacket *p;
|
||||
|
||||
if (usbredir_is_cancelled(dev, id)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = usb_ep_find_packet_by_id(&dev->dev,
|
||||
(ep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT,
|
||||
ep & 0x0f, id);
|
||||
if (p == NULL) {
|
||||
ERROR("could not find packet with id %"PRIu64"\n", id);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void bufp_alloc(USBRedirDevice *dev,
|
||||
@@ -492,25 +485,22 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
|
||||
static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
|
||||
uint8_t ep)
|
||||
{
|
||||
AsyncURB *aurb = async_alloc(dev, p);
|
||||
struct usb_redir_bulk_packet_header bulk_packet;
|
||||
|
||||
DPRINTF("bulk-out ep %02X len %zd id %u\n", ep,
|
||||
p->iov.size, aurb->packet_id);
|
||||
DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id);
|
||||
|
||||
bulk_packet.endpoint = ep;
|
||||
bulk_packet.length = p->iov.size;
|
||||
bulk_packet.stream_id = 0;
|
||||
aurb->bulk_packet = bulk_packet;
|
||||
|
||||
if (ep & USB_DIR_IN) {
|
||||
usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
|
||||
usbredirparser_send_bulk_packet(dev->parser, p->id,
|
||||
&bulk_packet, NULL, 0);
|
||||
} else {
|
||||
uint8_t buf[p->iov.size];
|
||||
usb_packet_copy(p, buf, p->iov.size);
|
||||
usbredir_log_data(dev, "bulk data out:", buf, p->iov.size);
|
||||
usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
|
||||
usbredirparser_send_bulk_packet(dev->parser, p->id,
|
||||
&bulk_packet, buf, p->iov.size);
|
||||
}
|
||||
usbredirparser_do_write(dev->parser);
|
||||
@@ -573,20 +563,18 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
|
||||
return len;
|
||||
} else {
|
||||
/* Output interrupt endpoint, normal async operation */
|
||||
AsyncURB *aurb = async_alloc(dev, p);
|
||||
struct usb_redir_interrupt_packet_header interrupt_packet;
|
||||
uint8_t buf[p->iov.size];
|
||||
|
||||
DPRINTF("interrupt-out ep %02X len %zd id %u\n", ep, p->iov.size,
|
||||
aurb->packet_id);
|
||||
DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
|
||||
p->iov.size, p->id);
|
||||
|
||||
interrupt_packet.endpoint = ep;
|
||||
interrupt_packet.length = p->iov.size;
|
||||
aurb->interrupt_packet = interrupt_packet;
|
||||
|
||||
usb_packet_copy(p, buf, p->iov.size);
|
||||
usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
|
||||
usbredirparser_send_interrupt_packet(dev->parser, aurb->packet_id,
|
||||
usbredirparser_send_interrupt_packet(dev->parser, p->id,
|
||||
&interrupt_packet, buf, p->iov.size);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
@@ -640,10 +628,9 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
|
||||
int config)
|
||||
{
|
||||
struct usb_redir_set_configuration_header set_config;
|
||||
AsyncURB *aurb = async_alloc(dev, p);
|
||||
int i;
|
||||
|
||||
DPRINTF("set config %d id %u\n", config, aurb->packet_id);
|
||||
DPRINTF("set config %d id %"PRIu64"\n", config, p->id);
|
||||
|
||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||
switch (dev->endpoint[i].type) {
|
||||
@@ -660,20 +647,16 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
|
||||
}
|
||||
|
||||
set_config.configuration = config;
|
||||
usbredirparser_send_set_configuration(dev->parser, aurb->packet_id,
|
||||
&set_config);
|
||||
usbredirparser_send_set_configuration(dev->parser, p->id, &set_config);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
}
|
||||
|
||||
static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
|
||||
{
|
||||
AsyncURB *aurb = async_alloc(dev, p);
|
||||
DPRINTF("get config id %"PRIu64"\n", p->id);
|
||||
|
||||
DPRINTF("get config id %u\n", aurb->packet_id);
|
||||
|
||||
aurb->get = 1;
|
||||
usbredirparser_send_get_configuration(dev->parser, aurb->packet_id);
|
||||
usbredirparser_send_get_configuration(dev->parser, p->id);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
}
|
||||
@@ -682,11 +665,9 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
|
||||
int interface, int alt)
|
||||
{
|
||||
struct usb_redir_set_alt_setting_header set_alt;
|
||||
AsyncURB *aurb = async_alloc(dev, p);
|
||||
int i;
|
||||
|
||||
DPRINTF("set interface %d alt %d id %u\n", interface, alt,
|
||||
aurb->packet_id);
|
||||
DPRINTF("set interface %d alt %d id %"PRIu64"\n", interface, alt, p->id);
|
||||
|
||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||
if (dev->endpoint[i].interface == interface) {
|
||||
@@ -706,8 +687,7 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
|
||||
|
||||
set_alt.interface = interface;
|
||||
set_alt.alt = alt;
|
||||
usbredirparser_send_set_alt_setting(dev->parser, aurb->packet_id,
|
||||
&set_alt);
|
||||
usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
}
|
||||
@@ -716,14 +696,11 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
|
||||
int interface)
|
||||
{
|
||||
struct usb_redir_get_alt_setting_header get_alt;
|
||||
AsyncURB *aurb = async_alloc(dev, p);
|
||||
|
||||
DPRINTF("get interface %d id %u\n", interface, aurb->packet_id);
|
||||
DPRINTF("get interface %d id %"PRIu64"\n", interface, p->id);
|
||||
|
||||
get_alt.interface = interface;
|
||||
aurb->get = 1;
|
||||
usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id,
|
||||
&get_alt);
|
||||
usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
return USB_RET_ASYNC;
|
||||
}
|
||||
@@ -733,7 +710,6 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
||||
{
|
||||
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
||||
struct usb_redir_control_packet_header control_packet;
|
||||
AsyncURB *aurb;
|
||||
|
||||
/* Special cases for certain standard device requests */
|
||||
switch (request) {
|
||||
@@ -751,13 +727,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
||||
return usbredir_get_interface(dev, p, index);
|
||||
}
|
||||
|
||||
/* "Normal" ctrl requests */
|
||||
aurb = async_alloc(dev, p);
|
||||
|
||||
/* Note request is (bRequestType << 8) | bRequest */
|
||||
DPRINTF("ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %u\n",
|
||||
request >> 8, request & 0xff, value, index, length,
|
||||
aurb->packet_id);
|
||||
/* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */
|
||||
DPRINTF(
|
||||
"ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %"PRIu64"\n",
|
||||
request >> 8, request & 0xff, value, index, length, p->id);
|
||||
|
||||
control_packet.request = request & 0xFF;
|
||||
control_packet.requesttype = request >> 8;
|
||||
@@ -765,14 +738,13 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
||||
control_packet.value = value;
|
||||
control_packet.index = index;
|
||||
control_packet.length = length;
|
||||
aurb->control_packet = control_packet;
|
||||
|
||||
if (control_packet.requesttype & USB_DIR_IN) {
|
||||
usbredirparser_send_control_packet(dev->parser, aurb->packet_id,
|
||||
usbredirparser_send_control_packet(dev->parser, p->id,
|
||||
&control_packet, NULL, 0);
|
||||
} else {
|
||||
usbredir_log_data(dev, "ctrl data out:", data, length);
|
||||
usbredirparser_send_control_packet(dev->parser, aurb->packet_id,
|
||||
usbredirparser_send_control_packet(dev->parser, p->id,
|
||||
&control_packet, data, length);
|
||||
}
|
||||
usbredirparser_do_write(dev->parser);
|
||||
@@ -784,18 +756,11 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
||||
* from within the USBDevice data / control packet callbacks and doing a
|
||||
* usb_detach from within these callbacks is not a good idea.
|
||||
*
|
||||
* So we use a bh handler to take care of close events. We also handle
|
||||
* open events from this callback to make sure that a close directly followed
|
||||
* by an open gets handled in the right order.
|
||||
* So we use a bh handler to take care of close events.
|
||||
*/
|
||||
static void usbredir_open_close_bh(void *opaque)
|
||||
static void usbredir_chardev_close_bh(void *opaque)
|
||||
{
|
||||
USBRedirDevice *dev = opaque;
|
||||
uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
|
||||
char version[32];
|
||||
|
||||
strcpy(version, "qemu usb-redir guest ");
|
||||
pstrcat(version, sizeof(version), qemu_get_version());
|
||||
|
||||
usbredir_device_disconnect(dev);
|
||||
|
||||
@@ -803,36 +768,44 @@ static void usbredir_open_close_bh(void *opaque)
|
||||
usbredirparser_destroy(dev->parser);
|
||||
dev->parser = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->cs->opened) {
|
||||
dev->parser = qemu_oom_check(usbredirparser_create());
|
||||
dev->parser->priv = dev;
|
||||
dev->parser->log_func = usbredir_log;
|
||||
dev->parser->read_func = usbredir_read;
|
||||
dev->parser->write_func = usbredir_write;
|
||||
dev->parser->hello_func = usbredir_hello;
|
||||
dev->parser->device_connect_func = usbredir_device_connect;
|
||||
dev->parser->device_disconnect_func = usbredir_device_disconnect;
|
||||
dev->parser->interface_info_func = usbredir_interface_info;
|
||||
dev->parser->ep_info_func = usbredir_ep_info;
|
||||
dev->parser->configuration_status_func = usbredir_configuration_status;
|
||||
dev->parser->alt_setting_status_func = usbredir_alt_setting_status;
|
||||
dev->parser->iso_stream_status_func = usbredir_iso_stream_status;
|
||||
dev->parser->interrupt_receiving_status_func =
|
||||
usbredir_interrupt_receiving_status;
|
||||
dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status;
|
||||
dev->parser->control_packet_func = usbredir_control_packet;
|
||||
dev->parser->bulk_packet_func = usbredir_bulk_packet;
|
||||
dev->parser->iso_packet_func = usbredir_iso_packet;
|
||||
dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
|
||||
dev->read_buf = NULL;
|
||||
dev->read_buf_size = 0;
|
||||
static void usbredir_chardev_open(USBRedirDevice *dev)
|
||||
{
|
||||
uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
|
||||
char version[32];
|
||||
|
||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
|
||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
|
||||
usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
}
|
||||
/* Make sure any pending closes are handled (no-op if none pending) */
|
||||
usbredir_chardev_close_bh(dev);
|
||||
qemu_bh_cancel(dev->chardev_close_bh);
|
||||
|
||||
dev->parser = qemu_oom_check(usbredirparser_create());
|
||||
dev->parser->priv = dev;
|
||||
dev->parser->log_func = usbredir_log;
|
||||
dev->parser->read_func = usbredir_read;
|
||||
dev->parser->write_func = usbredir_write;
|
||||
dev->parser->hello_func = usbredir_hello;
|
||||
dev->parser->device_connect_func = usbredir_device_connect;
|
||||
dev->parser->device_disconnect_func = usbredir_device_disconnect;
|
||||
dev->parser->interface_info_func = usbredir_interface_info;
|
||||
dev->parser->ep_info_func = usbredir_ep_info;
|
||||
dev->parser->configuration_status_func = usbredir_configuration_status;
|
||||
dev->parser->alt_setting_status_func = usbredir_alt_setting_status;
|
||||
dev->parser->iso_stream_status_func = usbredir_iso_stream_status;
|
||||
dev->parser->interrupt_receiving_status_func =
|
||||
usbredir_interrupt_receiving_status;
|
||||
dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status;
|
||||
dev->parser->control_packet_func = usbredir_control_packet;
|
||||
dev->parser->bulk_packet_func = usbredir_bulk_packet;
|
||||
dev->parser->iso_packet_func = usbredir_iso_packet;
|
||||
dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
|
||||
dev->read_buf = NULL;
|
||||
dev->read_buf_size = 0;
|
||||
|
||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
|
||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
|
||||
usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0);
|
||||
usbredirparser_do_write(dev->parser);
|
||||
}
|
||||
|
||||
static void usbredir_do_attach(void *opaque)
|
||||
@@ -856,13 +829,13 @@ static int usbredir_chardev_can_read(void *opaque)
|
||||
{
|
||||
USBRedirDevice *dev = opaque;
|
||||
|
||||
if (dev->parser) {
|
||||
/* usbredir_parser_do_read will consume *all* data we give it */
|
||||
return 1024 * 1024;
|
||||
} else {
|
||||
/* usbredir_open_close_bh hasn't handled the open event yet */
|
||||
if (!dev->parser) {
|
||||
WARNING("chardev_can_read called on non open chardev!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* usbredir_parser_do_read will consume *all* data we give it */
|
||||
return 1024 * 1024;
|
||||
}
|
||||
|
||||
static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size)
|
||||
@@ -886,8 +859,10 @@ static void usbredir_chardev_event(void *opaque, int event)
|
||||
|
||||
switch (event) {
|
||||
case CHR_EVENT_OPENED:
|
||||
usbredir_chardev_open(dev);
|
||||
break;
|
||||
case CHR_EVENT_CLOSED:
|
||||
qemu_bh_schedule(dev->open_close_bh);
|
||||
qemu_bh_schedule(dev->chardev_close_bh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -917,10 +892,10 @@ static int usbredir_initfn(USBDevice *udev)
|
||||
}
|
||||
}
|
||||
|
||||
dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev);
|
||||
dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev);
|
||||
dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev);
|
||||
|
||||
QTAILQ_INIT(&dev->asyncq);
|
||||
QTAILQ_INIT(&dev->cancelled);
|
||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||
QTAILQ_INIT(&dev->endpoint[i].bufpq);
|
||||
}
|
||||
@@ -939,11 +914,12 @@ static int usbredir_initfn(USBDevice *udev)
|
||||
|
||||
static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
|
||||
{
|
||||
AsyncURB *aurb, *next_aurb;
|
||||
Cancelled *c, *next_c;
|
||||
int i;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(aurb, &dev->asyncq, next, next_aurb) {
|
||||
async_free(dev, aurb);
|
||||
QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) {
|
||||
QTAILQ_REMOVE(&dev->cancelled, c, next);
|
||||
g_free(c);
|
||||
}
|
||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||
usbredir_free_bufpq(dev, I2EP(i));
|
||||
@@ -957,7 +933,7 @@ static void usbredir_handle_destroy(USBDevice *udev)
|
||||
qemu_chr_fe_close(dev->cs);
|
||||
qemu_chr_delete(dev->cs);
|
||||
/* Note must be done after qemu_chr_close, as that causes a close event */
|
||||
qemu_bh_delete(dev->open_close_bh);
|
||||
qemu_bh_delete(dev->chardev_close_bh);
|
||||
|
||||
qemu_del_timer(dev->attach_timer);
|
||||
qemu_free_timer(dev->attach_timer);
|
||||
@@ -1028,11 +1004,14 @@ static int usbredir_handle_status(USBRedirDevice *dev,
|
||||
case usb_redir_stall:
|
||||
return USB_RET_STALL;
|
||||
case usb_redir_cancelled:
|
||||
WARNING("returning cancelled packet to HC?\n");
|
||||
return USB_RET_NAK;
|
||||
/*
|
||||
* When the usbredir-host unredirects a device, it will report a status
|
||||
* of cancelled for all pending packets, followed by a disconnect msg.
|
||||
*/
|
||||
return USB_RET_IOERROR;
|
||||
case usb_redir_inval:
|
||||
WARNING("got invalid param error from usb-host?\n");
|
||||
return USB_RET_NAK;
|
||||
return USB_RET_IOERROR;
|
||||
case usb_redir_babble:
|
||||
return USB_RET_BABBLE;
|
||||
case usb_redir_ioerror:
|
||||
@@ -1206,33 +1185,28 @@ static void usbredir_configuration_status(void *priv, uint32_t id,
|
||||
struct usb_redir_configuration_status_header *config_status)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
AsyncURB *aurb;
|
||||
USBPacket *p;
|
||||
int len = 0;
|
||||
|
||||
DPRINTF("set config status %d config %d id %u\n", config_status->status,
|
||||
config_status->configuration, id);
|
||||
|
||||
aurb = async_find(dev, id);
|
||||
if (!aurb) {
|
||||
return;
|
||||
}
|
||||
if (aurb->packet) {
|
||||
if (aurb->get) {
|
||||
p = usbredir_find_packet_by_id(dev, 0, id);
|
||||
if (p) {
|
||||
if (dev->dev.setup_buf[0] & USB_DIR_IN) {
|
||||
dev->dev.data_buf[0] = config_status->configuration;
|
||||
len = 1;
|
||||
}
|
||||
aurb->packet->result =
|
||||
usbredir_handle_status(dev, config_status->status, len);
|
||||
usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
|
||||
p->result = usbredir_handle_status(dev, config_status->status, len);
|
||||
usb_generic_async_ctrl_complete(&dev->dev, p);
|
||||
}
|
||||
async_free(dev, aurb);
|
||||
}
|
||||
|
||||
static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
||||
struct usb_redir_alt_setting_status_header *alt_setting_status)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
AsyncURB *aurb;
|
||||
USBPacket *p;
|
||||
int len = 0;
|
||||
|
||||
DPRINTF("alt status %d intf %d alt %d id: %u\n",
|
||||
@@ -1240,20 +1214,16 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
||||
alt_setting_status->interface,
|
||||
alt_setting_status->alt, id);
|
||||
|
||||
aurb = async_find(dev, id);
|
||||
if (!aurb) {
|
||||
return;
|
||||
}
|
||||
if (aurb->packet) {
|
||||
if (aurb->get) {
|
||||
p = usbredir_find_packet_by_id(dev, 0, id);
|
||||
if (p) {
|
||||
if (dev->dev.setup_buf[0] & USB_DIR_IN) {
|
||||
dev->dev.data_buf[0] = alt_setting_status->alt;
|
||||
len = 1;
|
||||
}
|
||||
aurb->packet->result =
|
||||
p->result =
|
||||
usbredir_handle_status(dev, alt_setting_status->status, len);
|
||||
usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
|
||||
usb_generic_async_ctrl_complete(&dev->dev, p);
|
||||
}
|
||||
async_free(dev, aurb);
|
||||
}
|
||||
|
||||
static void usbredir_iso_stream_status(void *priv, uint32_t id,
|
||||
@@ -1308,27 +1278,14 @@ static void usbredir_control_packet(void *priv, uint32_t id,
|
||||
uint8_t *data, int data_len)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
USBPacket *p;
|
||||
int len = control_packet->length;
|
||||
AsyncURB *aurb;
|
||||
|
||||
DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status,
|
||||
len, id);
|
||||
|
||||
aurb = async_find(dev, id);
|
||||
if (!aurb) {
|
||||
free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
aurb->control_packet.status = control_packet->status;
|
||||
aurb->control_packet.length = control_packet->length;
|
||||
if (memcmp(&aurb->control_packet, control_packet,
|
||||
sizeof(*control_packet))) {
|
||||
ERROR("return control packet mismatch, please report this!\n");
|
||||
len = USB_RET_NAK;
|
||||
}
|
||||
|
||||
if (aurb->packet) {
|
||||
p = usbredir_find_packet_by_id(dev, 0, id);
|
||||
if (p) {
|
||||
len = usbredir_handle_status(dev, control_packet->status, len);
|
||||
if (len > 0) {
|
||||
usbredir_log_data(dev, "ctrl data in:", data, data_len);
|
||||
@@ -1340,10 +1297,9 @@ static void usbredir_control_packet(void *priv, uint32_t id,
|
||||
len = USB_RET_STALL;
|
||||
}
|
||||
}
|
||||
aurb->packet->result = len;
|
||||
usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
|
||||
p->result = len;
|
||||
usb_generic_async_ctrl_complete(&dev->dev, p);
|
||||
}
|
||||
async_free(dev, aurb);
|
||||
free(data);
|
||||
}
|
||||
|
||||
@@ -1354,39 +1310,27 @@ static void usbredir_bulk_packet(void *priv, uint32_t id,
|
||||
USBRedirDevice *dev = priv;
|
||||
uint8_t ep = bulk_packet->endpoint;
|
||||
int len = bulk_packet->length;
|
||||
AsyncURB *aurb;
|
||||
USBPacket *p;
|
||||
|
||||
DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status,
|
||||
ep, len, id);
|
||||
|
||||
aurb = async_find(dev, id);
|
||||
if (!aurb) {
|
||||
free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aurb->bulk_packet.endpoint != bulk_packet->endpoint ||
|
||||
aurb->bulk_packet.stream_id != bulk_packet->stream_id) {
|
||||
ERROR("return bulk packet mismatch, please report this!\n");
|
||||
len = USB_RET_NAK;
|
||||
}
|
||||
|
||||
if (aurb->packet) {
|
||||
p = usbredir_find_packet_by_id(dev, ep, id);
|
||||
if (p) {
|
||||
len = usbredir_handle_status(dev, bulk_packet->status, len);
|
||||
if (len > 0) {
|
||||
usbredir_log_data(dev, "bulk data in:", data, data_len);
|
||||
if (data_len <= aurb->packet->iov.size) {
|
||||
usb_packet_copy(aurb->packet, data, data_len);
|
||||
if (data_len <= p->iov.size) {
|
||||
usb_packet_copy(p, data, data_len);
|
||||
} else {
|
||||
ERROR("bulk buffer too small (%d > %zd)\n", data_len,
|
||||
aurb->packet->iov.size);
|
||||
len = USB_RET_STALL;
|
||||
ERROR("bulk got more data then requested (%d > %zd)\n",
|
||||
data_len, p->iov.size);
|
||||
len = USB_RET_BABBLE;
|
||||
}
|
||||
}
|
||||
aurb->packet->result = len;
|
||||
usb_packet_complete(&dev->dev, aurb->packet);
|
||||
p->result = len;
|
||||
usb_packet_complete(&dev->dev, p);
|
||||
}
|
||||
async_free(dev, aurb);
|
||||
free(data);
|
||||
}
|
||||
|
||||
@@ -1444,22 +1388,12 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
|
||||
} else {
|
||||
int len = interrupt_packet->length;
|
||||
|
||||
AsyncURB *aurb = async_find(dev, id);
|
||||
if (!aurb) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aurb->interrupt_packet.endpoint != interrupt_packet->endpoint) {
|
||||
ERROR("return int packet mismatch, please report this!\n");
|
||||
len = USB_RET_NAK;
|
||||
}
|
||||
|
||||
if (aurb->packet) {
|
||||
aurb->packet->result = usbredir_handle_status(dev,
|
||||
USBPacket *p = usbredir_find_packet_by_id(dev, ep, id);
|
||||
if (p) {
|
||||
p->result = usbredir_handle_status(dev,
|
||||
interrupt_packet->status, len);
|
||||
usb_packet_complete(&dev->dev, aurb->packet);
|
||||
usb_packet_complete(&dev->dev, p);
|
||||
}
|
||||
async_free(dev, aurb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -62,7 +62,6 @@ enum {
|
||||
VE_COMPACTFLASH,
|
||||
VE_CLCD,
|
||||
VE_NORFLASH0,
|
||||
VE_NORFLASH0ALIAS,
|
||||
VE_NORFLASH1,
|
||||
VE_SRAM,
|
||||
VE_VIDEORAM,
|
||||
@@ -104,9 +103,8 @@ static target_phys_addr_t motherboard_legacy_map[] = {
|
||||
};
|
||||
|
||||
static target_phys_addr_t motherboard_aseries_map[] = {
|
||||
/* CS0: 0x00000000 .. 0x0c000000 */
|
||||
[VE_NORFLASH0] = 0x00000000,
|
||||
[VE_NORFLASH0ALIAS] = 0x08000000,
|
||||
/* CS0: 0x08000000 .. 0x0c000000 */
|
||||
[VE_NORFLASH0] = 0x08000000,
|
||||
/* CS4: 0x0c000000 .. 0x10000000 */
|
||||
[VE_NORFLASH1] = 0x0c000000,
|
||||
/* CS5: 0x10000000 .. 0x14000000 */
|
||||
@@ -413,7 +411,6 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
|
||||
sysbus_create_simple("pl111", map[VE_CLCD], pic[14]);
|
||||
|
||||
/* VE_NORFLASH0: not modelled */
|
||||
/* VE_NORFLASH0ALIAS: not modelled */
|
||||
/* VE_NORFLASH1: not modelled */
|
||||
|
||||
sram_size = 0x2000000;
|
||||
|
||||
@@ -447,10 +447,6 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
|
||||
VirtIONet *n = to_virtio_net(vdev);
|
||||
|
||||
qemu_flush_queued_packets(&n->nic->nc);
|
||||
|
||||
/* We now have RX buffers, signal to the IO thread to break out of the
|
||||
* select to re-poll the tap file descriptor */
|
||||
qemu_notify_event();
|
||||
}
|
||||
|
||||
static int virtio_net_can_receive(NetClientState *nc)
|
||||
|
||||
+2
-2
@@ -361,10 +361,10 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data)
|
||||
uint16_t value;
|
||||
|
||||
if (s->i2c_len >= 2) {
|
||||
printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
|
||||
#ifdef VERBOSE
|
||||
return 1;
|
||||
printf("%s: long message (%i bytes)\n", __func__, s->i2c_len);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
s->i2c_data[s->i2c_len ++] = data;
|
||||
if (s->i2c_len != 2)
|
||||
|
||||
@@ -415,6 +415,7 @@ static void net_event(struct XenDevice *xendev)
|
||||
{
|
||||
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
|
||||
net_tx_packets(netdev);
|
||||
qemu_flush_queued_packets(&netdev->nic->nc);
|
||||
}
|
||||
|
||||
static int net_free(struct XenDevice *xendev)
|
||||
|
||||
+2
-2
@@ -96,7 +96,7 @@ typedef struct XenPTRegion {
|
||||
* - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
|
||||
*/
|
||||
|
||||
/* emulated register infomation */
|
||||
/* emulated register information */
|
||||
struct XenPTRegInfo {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
@@ -140,7 +140,7 @@ typedef int (*xen_pt_reg_size_init_fn)
|
||||
(XenPCIPassthroughState *, const XenPTRegGroupInfo *,
|
||||
uint32_t base_offset, uint8_t *size);
|
||||
|
||||
/* emulated register group infomation */
|
||||
/* emulated register group information */
|
||||
struct XenPTRegGroupInfo {
|
||||
uint8_t grp_id;
|
||||
XenPTRegisterGroupType grp_type;
|
||||
|
||||
@@ -562,7 +562,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Header Type0 reg static infomation table */
|
||||
/* Header Type0 reg static information table */
|
||||
static XenPTRegInfo xen_pt_emu_reg_header0[] = {
|
||||
/* Vendor ID reg */
|
||||
{
|
||||
@@ -753,7 +753,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = {
|
||||
* Vital Product Data Capability
|
||||
*/
|
||||
|
||||
/* Vital Product Data Capability Structure reg static infomation table */
|
||||
/* Vital Product Data Capability Structure reg static information table */
|
||||
static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
|
||||
{
|
||||
.offset = PCI_CAP_LIST_NEXT,
|
||||
@@ -775,7 +775,7 @@ static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
|
||||
* Vendor Specific Capability
|
||||
*/
|
||||
|
||||
/* Vendor Specific Capability Structure reg static infomation table */
|
||||
/* Vendor Specific Capability Structure reg static information table */
|
||||
static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
|
||||
{
|
||||
.offset = PCI_CAP_LIST_NEXT,
|
||||
@@ -866,7 +866,7 @@ static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PCI Express Capability Structure reg static infomation table */
|
||||
/* PCI Express Capability Structure reg static information table */
|
||||
static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
|
||||
/* Next Pointer reg */
|
||||
{
|
||||
@@ -981,7 +981,7 @@ static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Power Management Capability reg static infomation table */
|
||||
/* Power Management Capability reg static information table */
|
||||
static XenPTRegInfo xen_pt_emu_reg_pm[] = {
|
||||
/* Next Pointer reg */
|
||||
{
|
||||
@@ -1259,7 +1259,7 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MSI Capability Structure reg static infomation table */
|
||||
/* MSI Capability Structure reg static information table */
|
||||
static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||
/* Next Pointer reg */
|
||||
{
|
||||
@@ -1396,7 +1396,7 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MSI-X Capability Structure reg static infomation table */
|
||||
/* MSI-X Capability Structure reg static information table */
|
||||
static XenPTRegInfo xen_pt_emu_reg_msix[] = {
|
||||
/* Next Pointer reg */
|
||||
{
|
||||
|
||||
+9
-3
@@ -21,7 +21,7 @@ xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int oto, int freq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_create(NULL, "xlnx,xps-timer");
|
||||
dev = qdev_create(NULL, "xlnx.xps-timer");
|
||||
qdev_prop_set_uint32(dev, "one-timer-only", oto);
|
||||
qdev_prop_set_uint32(dev, "frequency", freq);
|
||||
qdev_init_nofail(dev);
|
||||
@@ -55,13 +55,16 @@ xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer,
|
||||
int txmem, int rxmem)
|
||||
{
|
||||
DeviceState *dev;
|
||||
Error *errp = NULL;
|
||||
|
||||
qemu_check_nic_model(nd, "xlnx.axi-ethernet");
|
||||
|
||||
dev = qdev_create(NULL, "xlnx.axi-ethernet");
|
||||
qdev_set_nic_properties(dev, nd);
|
||||
qdev_prop_set_uint32(dev, "rxmem", rxmem);
|
||||
qdev_prop_set_uint32(dev, "txmem", txmem);
|
||||
object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
|
||||
object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", &errp);
|
||||
assert_no_error(errp);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
|
||||
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
|
||||
@@ -74,8 +77,11 @@ xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer,
|
||||
target_phys_addr_t base, qemu_irq irq,
|
||||
qemu_irq irq2, int freqhz)
|
||||
{
|
||||
Error *errp = NULL;
|
||||
|
||||
qdev_prop_set_uint32(dev, "freqhz", freqhz);
|
||||
object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
|
||||
object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", &errp);
|
||||
assert_no_error(errp);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
|
||||
|
||||
+7
-6
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "sysbus.h"
|
||||
#include "ptimer.h"
|
||||
#include "qemu-log.h"
|
||||
|
||||
#define D(x)
|
||||
|
||||
@@ -119,7 +120,7 @@ timer_read(void *opaque, target_phys_addr_t addr, unsigned int size)
|
||||
break;
|
||||
|
||||
}
|
||||
D(printf("%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
|
||||
D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -127,7 +128,7 @@ static void timer_enable(struct xlx_timer *xt)
|
||||
{
|
||||
uint64_t count;
|
||||
|
||||
D(printf("%s timer=%d down=%d\n", __func__,
|
||||
D(fprintf(stderr, "%s timer=%d down=%d\n", __func__,
|
||||
xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
|
||||
|
||||
ptimer_stop(xt->ptimer);
|
||||
@@ -152,7 +153,7 @@ timer_write(void *opaque, target_phys_addr_t addr,
|
||||
addr >>= 2;
|
||||
timer = timer_from_addr(addr);
|
||||
xt = &t->timers[timer];
|
||||
D(printf("%s addr=%x val=%x (timer=%d off=%d)\n",
|
||||
D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n",
|
||||
__func__, addr * 4, value, timer, addr & 3));
|
||||
/* Further decoding to address a specific timers reg. */
|
||||
addr &= 3;
|
||||
@@ -189,7 +190,7 @@ static void timer_hit(void *opaque)
|
||||
{
|
||||
struct xlx_timer *xt = opaque;
|
||||
struct timerblock *t = xt->parent;
|
||||
D(printf("%s %d\n", __func__, timer));
|
||||
D(fprintf(stderr, "%s %d\n", __func__, xt->nr));
|
||||
xt->regs[R_TCSR] |= TCSR_TINT;
|
||||
|
||||
if (xt->regs[R_TCSR] & TCSR_ARHT)
|
||||
@@ -217,7 +218,7 @@ static int xilinx_timer_init(SysBusDevice *dev)
|
||||
ptimer_set_freq(xt->ptimer, t->freq_hz);
|
||||
}
|
||||
|
||||
memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx,xps-timer",
|
||||
memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx.xps-timer",
|
||||
R_MAX * 4 * num_timers(t));
|
||||
sysbus_init_mmio(dev, &t->mmio);
|
||||
return 0;
|
||||
@@ -239,7 +240,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data)
|
||||
}
|
||||
|
||||
static TypeInfo xilinx_timer_info = {
|
||||
.name = "xlnx,xps-timer",
|
||||
.name = "xlnx.xps-timer",
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(struct timerblock),
|
||||
.class_init = xilinx_timer_class_init,
|
||||
|
||||
@@ -56,6 +56,8 @@ int qemu_set_fd_handler2(int fd,
|
||||
{
|
||||
IOHandlerRecord *ioh;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (!fd_read && !fd_write) {
|
||||
QLIST_FOREACH(ioh, &io_handlers, next) {
|
||||
if (ioh->fd == fd) {
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_VALGRIND_H
|
||||
#include <valgrind/memcheck.h>
|
||||
#endif
|
||||
|
||||
/* KVM uses PAGE_SIZE in its definition of COALESCED_MMIO_MAX */
|
||||
#define PAGE_SIZE TARGET_PAGE_SIZE
|
||||
|
||||
@@ -1370,13 +1374,11 @@ int kvm_init(void)
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (s) {
|
||||
if (s->vmfd >= 0) {
|
||||
close(s->vmfd);
|
||||
}
|
||||
if (s->fd != -1) {
|
||||
close(s->fd);
|
||||
}
|
||||
if (s->vmfd >= 0) {
|
||||
close(s->vmfd);
|
||||
}
|
||||
if (s->fd != -1) {
|
||||
close(s->fd);
|
||||
}
|
||||
g_free(s);
|
||||
|
||||
@@ -1719,6 +1721,9 @@ void *kvm_vmalloc(ram_addr_t size)
|
||||
|
||||
void kvm_setup_guest_memory(void *start, size_t size)
|
||||
{
|
||||
#ifdef CONFIG_VALGRIND_H
|
||||
VALGRIND_MAKE_MEM_DEFINED(start, size);
|
||||
#endif
|
||||
if (!kvm_has_sync_mmu()) {
|
||||
int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK);
|
||||
|
||||
|
||||
@@ -3628,9 +3628,7 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
|
||||
unlock_user(argptr, arg, target_size);
|
||||
}
|
||||
out:
|
||||
if (big_buf) {
|
||||
free(big_buf);
|
||||
}
|
||||
g_free(big_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+9
-28
@@ -53,54 +53,35 @@ static int tcp_close(MigrationState *s)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void tcp_wait_for_connect(void *opaque)
|
||||
static void tcp_wait_for_connect(int fd, void *opaque)
|
||||
{
|
||||
MigrationState *s = opaque;
|
||||
int val, ret;
|
||||
socklen_t valsize = sizeof(val);
|
||||
|
||||
DPRINTF("connect completed\n");
|
||||
do {
|
||||
ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
|
||||
} while (ret == -1 && (socket_error()) == EINTR);
|
||||
|
||||
if (ret < 0) {
|
||||
if (fd < 0) {
|
||||
DPRINTF("migrate connect error\n");
|
||||
s->fd = -1;
|
||||
migrate_fd_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (val == 0)
|
||||
} else {
|
||||
DPRINTF("migrate connect success\n");
|
||||
s->fd = fd;
|
||||
migrate_fd_connect(s);
|
||||
else {
|
||||
DPRINTF("error connecting %d\n", val);
|
||||
migrate_fd_error(s);
|
||||
}
|
||||
}
|
||||
|
||||
int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
|
||||
Error **errp)
|
||||
{
|
||||
bool in_progress;
|
||||
|
||||
s->get_error = socket_errno;
|
||||
s->write = socket_write;
|
||||
s->close = tcp_close;
|
||||
|
||||
s->fd = inet_connect(host_port, false, &in_progress, errp);
|
||||
s->fd = inet_nonblocking_connect(host_port, tcp_wait_for_connect, s,
|
||||
errp);
|
||||
if (error_is_set(errp)) {
|
||||
migrate_fd_error(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (in_progress) {
|
||||
DPRINTF("connect in progress\n");
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
|
||||
} else {
|
||||
migrate_fd_connect(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -240,7 +240,9 @@ static int migrate_fd_cleanup(MigrationState *s)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
|
||||
if (s->fd != -1) {
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (s->file) {
|
||||
DPRINTF("closing file\n");
|
||||
|
||||
@@ -455,6 +455,7 @@ static const char *monitor_event_names[] = {
|
||||
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
|
||||
[QEVENT_WAKEUP] = "WAKEUP",
|
||||
[QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
|
||||
[QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED",
|
||||
};
|
||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ typedef enum MonitorEvent {
|
||||
QEVENT_SUSPEND_DISK,
|
||||
QEVENT_WAKEUP,
|
||||
QEVENT_BALLOON_CHANGE,
|
||||
QEVENT_SPICE_MIGRATE_COMPLETED,
|
||||
|
||||
/* Add to 'monitor_event_names' array in monitor.c when
|
||||
* defining new events here */
|
||||
|
||||
@@ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port)
|
||||
|
||||
int tcp_socket_outgoing_spec(const char *address_and_port)
|
||||
{
|
||||
return inet_connect(address_and_port, true, NULL, NULL);
|
||||
return inet_connect(address_and_port, NULL);
|
||||
}
|
||||
|
||||
int tcp_socket_incoming(const char *address, uint16_t port)
|
||||
|
||||
@@ -357,7 +357,12 @@ void qemu_flush_queued_packets(NetClientState *nc)
|
||||
{
|
||||
nc->receive_disabled = 0;
|
||||
|
||||
qemu_net_queue_flush(nc->send_queue);
|
||||
if (qemu_net_queue_flush(nc->send_queue)) {
|
||||
/* We emptied the queue successfully, signal to the IO thread to repoll
|
||||
* the file descriptor (for tap, for example).
|
||||
*/
|
||||
qemu_notify_event();
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
|
||||
@@ -418,16 +423,27 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender,
|
||||
void *opaque)
|
||||
{
|
||||
NetClientState *nc = opaque;
|
||||
int ret;
|
||||
|
||||
if (nc->link_down) {
|
||||
return iov_size(iov, iovcnt);
|
||||
}
|
||||
|
||||
if (nc->info->receive_iov) {
|
||||
return nc->info->receive_iov(nc, iov, iovcnt);
|
||||
} else {
|
||||
return nc_sendv_compat(nc, iov, iovcnt);
|
||||
if (nc->receive_disabled) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nc->info->receive_iov) {
|
||||
ret = nc->info->receive_iov(nc, iov, iovcnt);
|
||||
} else {
|
||||
ret = nc_sendv_compat(nc, iov, iovcnt);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
nc->receive_disabled = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t qemu_sendv_packet_async(NetClientState *sender,
|
||||
|
||||
@@ -97,12 +97,12 @@ static int net_hub_port_can_receive(NetClientState *nc)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!qemu_can_send_packet(&port->nc)) {
|
||||
return 0;
|
||||
if (qemu_can_send_packet(&port->nc)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t net_hub_port_receive(NetClientState *nc,
|
||||
|
||||
+19
-21
@@ -83,12 +83,12 @@ void qemu_del_net_queue(NetQueue *queue)
|
||||
g_free(queue);
|
||||
}
|
||||
|
||||
static ssize_t qemu_net_queue_append(NetQueue *queue,
|
||||
NetClientState *sender,
|
||||
unsigned flags,
|
||||
const uint8_t *buf,
|
||||
size_t size,
|
||||
NetPacketSent *sent_cb)
|
||||
static void qemu_net_queue_append(NetQueue *queue,
|
||||
NetClientState *sender,
|
||||
unsigned flags,
|
||||
const uint8_t *buf,
|
||||
size_t size,
|
||||
NetPacketSent *sent_cb)
|
||||
{
|
||||
NetPacket *packet;
|
||||
|
||||
@@ -100,16 +100,14 @@ static ssize_t qemu_net_queue_append(NetQueue *queue,
|
||||
memcpy(packet->data, buf, size);
|
||||
|
||||
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
|
||||
NetClientState *sender,
|
||||
unsigned flags,
|
||||
const struct iovec *iov,
|
||||
int iovcnt,
|
||||
NetPacketSent *sent_cb)
|
||||
static void qemu_net_queue_append_iov(NetQueue *queue,
|
||||
NetClientState *sender,
|
||||
unsigned flags,
|
||||
const struct iovec *iov,
|
||||
int iovcnt,
|
||||
NetPacketSent *sent_cb)
|
||||
{
|
||||
NetPacket *packet;
|
||||
size_t max_len = 0;
|
||||
@@ -133,8 +131,6 @@ static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
|
||||
}
|
||||
|
||||
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
|
||||
|
||||
return packet->size;
|
||||
}
|
||||
|
||||
static ssize_t qemu_net_queue_deliver(NetQueue *queue,
|
||||
@@ -177,7 +173,8 @@ ssize_t qemu_net_queue_send(NetQueue *queue,
|
||||
ssize_t ret;
|
||||
|
||||
if (queue->delivering || !qemu_can_send_packet(sender)) {
|
||||
return qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
|
||||
qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = qemu_net_queue_deliver(queue, sender, flags, data, size);
|
||||
@@ -201,8 +198,8 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue,
|
||||
ssize_t ret;
|
||||
|
||||
if (queue->delivering || !qemu_can_send_packet(sender)) {
|
||||
return qemu_net_queue_append_iov(queue, sender, flags,
|
||||
iov, iovcnt, sent_cb);
|
||||
qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt);
|
||||
@@ -228,7 +225,7 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_net_queue_flush(NetQueue *queue)
|
||||
bool qemu_net_queue_flush(NetQueue *queue)
|
||||
{
|
||||
while (!QTAILQ_EMPTY(&queue->packets)) {
|
||||
NetPacket *packet;
|
||||
@@ -244,7 +241,7 @@ void qemu_net_queue_flush(NetQueue *queue)
|
||||
packet->size);
|
||||
if (ret == 0) {
|
||||
QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packet->sent_cb) {
|
||||
@@ -253,4 +250,5 @@ void qemu_net_queue_flush(NetQueue *queue)
|
||||
|
||||
g_free(packet);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+1
-1
@@ -53,6 +53,6 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue,
|
||||
NetPacketSent *sent_cb);
|
||||
|
||||
void qemu_net_queue_purge(NetQueue *queue, NetClientState *from);
|
||||
void qemu_net_queue_flush(NetQueue *queue);
|
||||
bool qemu_net_queue_flush(NetQueue *queue);
|
||||
|
||||
#endif /* QEMU_NET_QUEUE_H */
|
||||
|
||||
+95
-13
@@ -32,6 +32,7 @@
|
||||
#include "qemu-error.h"
|
||||
#include "qemu-option.h"
|
||||
#include "qemu_socket.h"
|
||||
#include "iov.h"
|
||||
|
||||
typedef struct NetSocketState {
|
||||
NetClientState nc;
|
||||
@@ -40,29 +41,106 @@ typedef struct NetSocketState {
|
||||
int state; /* 0 = getting length, 1 = getting data */
|
||||
unsigned int index;
|
||||
unsigned int packet_len;
|
||||
unsigned int send_index; /* number of bytes sent (only SOCK_STREAM) */
|
||||
uint8_t buf[4096];
|
||||
struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
|
||||
IOHandler *send_fn; /* differs between SOCK_STREAM/SOCK_DGRAM */
|
||||
bool read_poll; /* waiting to receive data? */
|
||||
bool write_poll; /* waiting to transmit data? */
|
||||
} NetSocketState;
|
||||
|
||||
static void net_socket_accept(void *opaque);
|
||||
static void net_socket_writable(void *opaque);
|
||||
|
||||
/* Only read packets from socket when peer can receive them */
|
||||
static int net_socket_can_send(void *opaque)
|
||||
{
|
||||
NetSocketState *s = opaque;
|
||||
|
||||
return qemu_can_send_packet(&s->nc);
|
||||
}
|
||||
|
||||
static void net_socket_update_fd_handler(NetSocketState *s)
|
||||
{
|
||||
qemu_set_fd_handler2(s->fd,
|
||||
s->read_poll ? net_socket_can_send : NULL,
|
||||
s->read_poll ? s->send_fn : NULL,
|
||||
s->write_poll ? net_socket_writable : NULL,
|
||||
s);
|
||||
}
|
||||
|
||||
static void net_socket_read_poll(NetSocketState *s, bool enable)
|
||||
{
|
||||
s->read_poll = enable;
|
||||
net_socket_update_fd_handler(s);
|
||||
}
|
||||
|
||||
static void net_socket_write_poll(NetSocketState *s, bool enable)
|
||||
{
|
||||
s->write_poll = enable;
|
||||
net_socket_update_fd_handler(s);
|
||||
}
|
||||
|
||||
static void net_socket_writable(void *opaque)
|
||||
{
|
||||
NetSocketState *s = opaque;
|
||||
|
||||
net_socket_write_poll(s, false);
|
||||
|
||||
qemu_flush_queued_packets(&s->nc);
|
||||
}
|
||||
|
||||
/* XXX: we consider we can send the whole packet without blocking */
|
||||
static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
{
|
||||
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
||||
uint32_t len;
|
||||
len = htonl(size);
|
||||
uint32_t len = htonl(size);
|
||||
struct iovec iov[] = {
|
||||
{
|
||||
.iov_base = &len,
|
||||
.iov_len = sizeof(len),
|
||||
}, {
|
||||
.iov_base = (void *)buf,
|
||||
.iov_len = size,
|
||||
},
|
||||
};
|
||||
size_t remaining;
|
||||
ssize_t ret;
|
||||
|
||||
send_all(s->fd, (const uint8_t *)&len, sizeof(len));
|
||||
return send_all(s->fd, buf, size);
|
||||
remaining = iov_size(iov, 2) - s->send_index;
|
||||
ret = iov_send(s->fd, iov, 2, s->send_index, remaining);
|
||||
|
||||
if (ret == -1 && errno == EAGAIN) {
|
||||
ret = 0; /* handled further down */
|
||||
}
|
||||
if (ret == -1) {
|
||||
s->send_index = 0;
|
||||
return -errno;
|
||||
}
|
||||
if (ret < (ssize_t)remaining) {
|
||||
s->send_index += ret;
|
||||
net_socket_write_poll(s, true);
|
||||
return 0;
|
||||
}
|
||||
s->send_index = 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
{
|
||||
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
||||
ssize_t ret;
|
||||
|
||||
return sendto(s->fd, (const void *)buf, size, 0,
|
||||
(struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
|
||||
do {
|
||||
ret = qemu_sendto(s->fd, buf, size, 0,
|
||||
(struct sockaddr *)&s->dgram_dst,
|
||||
sizeof(s->dgram_dst));
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret == -1 && errno == EAGAIN) {
|
||||
net_socket_write_poll(s, true);
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void net_socket_send(void *opaque)
|
||||
@@ -81,7 +159,8 @@ static void net_socket_send(void *opaque)
|
||||
} else if (size == 0) {
|
||||
/* end of connection */
|
||||
eoc:
|
||||
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||
net_socket_read_poll(s, false);
|
||||
net_socket_write_poll(s, false);
|
||||
if (s->listen_fd != -1) {
|
||||
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
|
||||
}
|
||||
@@ -152,7 +231,8 @@ static void net_socket_send_dgram(void *opaque)
|
||||
return;
|
||||
if (size == 0) {
|
||||
/* end of connection */
|
||||
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||
net_socket_read_poll(s, false);
|
||||
net_socket_write_poll(s, false);
|
||||
return;
|
||||
}
|
||||
qemu_send_packet(&s->nc, s->buf, size);
|
||||
@@ -243,7 +323,8 @@ static void net_socket_cleanup(NetClientState *nc)
|
||||
{
|
||||
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
||||
if (s->fd != -1) {
|
||||
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||
net_socket_read_poll(s, false);
|
||||
net_socket_write_poll(s, false);
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
}
|
||||
@@ -314,8 +395,8 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
|
||||
|
||||
s->fd = fd;
|
||||
s->listen_fd = -1;
|
||||
|
||||
qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
|
||||
s->send_fn = net_socket_send_dgram;
|
||||
net_socket_read_poll(s, true);
|
||||
|
||||
/* mcast: save bound address as dst */
|
||||
if (is_connected) {
|
||||
@@ -332,7 +413,8 @@ err:
|
||||
static void net_socket_connect(void *opaque)
|
||||
{
|
||||
NetSocketState *s = opaque;
|
||||
qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
|
||||
s->send_fn = net_socket_send;
|
||||
net_socket_read_poll(s, true);
|
||||
}
|
||||
|
||||
static NetClientInfo net_socket_info = {
|
||||
|
||||
@@ -360,3 +360,8 @@ int qemu_create_pidfile(const char *filename)
|
||||
/* keep pidfile open & locked forever */
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool is_daemonized(void)
|
||||
{
|
||||
return daemonize;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,30 @@ void qemu_vfree(void *ptr)
|
||||
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
/* FIXME: add proper locking */
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
struct tm *p = gmtime(timep);
|
||||
memset(result, 0, sizeof(*result));
|
||||
if (p) {
|
||||
*result = *p;
|
||||
p = result;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* FIXME: add proper locking */
|
||||
struct tm *localtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
struct tm *p = localtime(timep);
|
||||
memset(result, 0, sizeof(*result));
|
||||
if (p) {
|
||||
*result = *p;
|
||||
p = result;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void socket_set_block(int fd)
|
||||
{
|
||||
unsigned long opt = 0;
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
##
|
||||
# @GuestFsFreezeStatus
|
||||
#
|
||||
# An enumation of filesystem freeze states
|
||||
# An enumeration of filesystem freeze states
|
||||
#
|
||||
# @thawed: filesystems thawed/unfrozen
|
||||
#
|
||||
|
||||
+6
-3
@@ -118,7 +118,7 @@
|
||||
##
|
||||
# @RunState
|
||||
#
|
||||
# An enumation of VM run states.
|
||||
# An enumeration of VM run states.
|
||||
#
|
||||
# @debug: QEMU is running on a debugger
|
||||
#
|
||||
@@ -785,7 +785,7 @@
|
||||
##
|
||||
# @SpiceQueryMouseMode
|
||||
#
|
||||
# An enumation of Spice mouse states.
|
||||
# An enumeration of Spice mouse states.
|
||||
#
|
||||
# @client: Mouse cursor position is determined by the client.
|
||||
#
|
||||
@@ -808,6 +808,9 @@
|
||||
#
|
||||
# @enabled: true if the SPICE server is enabled, false otherwise
|
||||
#
|
||||
# @migrated: true if the last guest migration completed and spice
|
||||
# migration had completed as well. false otherwise.
|
||||
#
|
||||
# @host: #optional The hostname the SPICE server is bound to. This depends on
|
||||
# the name resolution on the host and may be an IP address.
|
||||
#
|
||||
@@ -833,7 +836,7 @@
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'type': 'SpiceInfo',
|
||||
'data': {'enabled': 'bool', '*host': 'str', '*port': 'int',
|
||||
'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int',
|
||||
'*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
|
||||
'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} }
|
||||
|
||||
|
||||
+7
-8
@@ -2141,17 +2141,14 @@ typedef struct {
|
||||
|
||||
static void tcp_chr_accept(void *opaque);
|
||||
|
||||
static void tcp_chr_connect(void *opaque);
|
||||
|
||||
static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
{
|
||||
TCPCharDriver *s = chr->opaque;
|
||||
if (s->connected) {
|
||||
return send_all(s->fd, buf, len);
|
||||
} else {
|
||||
/* (Re-)connect for unconnected writing */
|
||||
tcp_chr_connect(chr);
|
||||
return 0;
|
||||
/* XXX: indicate an error ? */
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2332,8 +2329,10 @@ static void tcp_chr_connect(void *opaque)
|
||||
TCPCharDriver *s = chr->opaque;
|
||||
|
||||
s->connected = 1;
|
||||
qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
|
||||
tcp_chr_read, NULL, chr);
|
||||
if (s->fd >= 0) {
|
||||
qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
|
||||
tcp_chr_read, NULL, chr);
|
||||
}
|
||||
qemu_chr_generic_open(chr);
|
||||
}
|
||||
|
||||
@@ -2457,7 +2456,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
|
||||
if (is_listen) {
|
||||
fd = inet_listen_opts(opts, 0, NULL);
|
||||
} else {
|
||||
fd = inet_connect_opts(opts, NULL, NULL);
|
||||
fd = inet_connect_opts(opts, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
|
||||
@@ -223,9 +223,14 @@ int qemu_pipe(int pipefd[2]);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* MinGW needs a type cast for the 'buf' argument. */
|
||||
#define qemu_recv(sockfd, buf, len, flags) recv(sockfd, (void *)buf, len, flags)
|
||||
#define qemu_sendto(sockfd, buf, len, flags, destaddr, addrlen) \
|
||||
sendto(sockfd, (const void *)buf, len, flags, destaddr, addrlen)
|
||||
#else
|
||||
#define qemu_recv(sockfd, buf, len, flags) recv(sockfd, buf, len, flags)
|
||||
#define qemu_sendto(sockfd, buf, len, flags, destaddr, addrlen) \
|
||||
sendto(sockfd, buf, len, flags, destaddr, addrlen)
|
||||
#endif
|
||||
|
||||
/* Error handling. */
|
||||
|
||||
@@ -537,6 +537,9 @@ QemuOptsList qemu_spice_opts = {
|
||||
},{
|
||||
.name = "playback-compression",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
}, {
|
||||
.name = "seamless-migration",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
|
||||
@@ -114,12 +114,10 @@ static gboolean register_signal_handlers(void)
|
||||
ret = sigaction(SIGINT, &sigact, NULL);
|
||||
if (ret == -1) {
|
||||
g_error("error configuring signal handler: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
ret = sigaction(SIGTERM, &sigact, NULL);
|
||||
if (ret == -1) {
|
||||
g_error("error configuring signal handler: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+12
-11
@@ -89,7 +89,7 @@ static void help(void)
|
||||
" '-r' tries to repair any inconsistencies that are found during the check.\n"
|
||||
" '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all\n"
|
||||
" kinds of errors, with a higher risk of choosing the wrong fix or\n"
|
||||
" hiding corruption that has already occured.\n"
|
||||
" hiding corruption that has already occurred.\n"
|
||||
"\n"
|
||||
"Parameters to snapshot subcommand:\n"
|
||||
" 'snapshot' is the name of the snapshot to create, apply or delete\n"
|
||||
@@ -221,7 +221,8 @@ static int print_block_option_help(const char *filename, const char *fmt)
|
||||
|
||||
static BlockDriverState *bdrv_new_open(const char *filename,
|
||||
const char *fmt,
|
||||
int flags)
|
||||
int flags,
|
||||
bool require_io)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriver *drv;
|
||||
@@ -246,7 +247,7 @@ static BlockDriverState *bdrv_new_open(const char *filename,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (bdrv_is_encrypted(bs)) {
|
||||
if (bdrv_is_encrypted(bs) && require_io) {
|
||||
printf("Disk image '%s' is encrypted.\n", filename);
|
||||
if (read_password(password, sizeof(password)) < 0) {
|
||||
error_report("No password given");
|
||||
@@ -413,7 +414,7 @@ static int img_check(int argc, char **argv)
|
||||
}
|
||||
filename = argv[optind++];
|
||||
|
||||
bs = bdrv_new_open(filename, fmt, flags);
|
||||
bs = bdrv_new_open(filename, fmt, flags, true);
|
||||
if (!bs) {
|
||||
return 1;
|
||||
}
|
||||
@@ -520,7 +521,7 @@ static int img_commit(int argc, char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bs = bdrv_new_open(filename, fmt, flags);
|
||||
bs = bdrv_new_open(filename, fmt, flags, true);
|
||||
if (!bs) {
|
||||
return 1;
|
||||
}
|
||||
@@ -762,7 +763,7 @@ static int img_convert(int argc, char **argv)
|
||||
|
||||
total_sectors = 0;
|
||||
for (bs_i = 0; bs_i < bs_n; bs_i++) {
|
||||
bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS);
|
||||
bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true);
|
||||
if (!bs[bs_i]) {
|
||||
error_report("Could not open '%s'", argv[optind + bs_i]);
|
||||
ret = -1;
|
||||
@@ -881,7 +882,7 @@ static int img_convert(int argc, char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
out_bs = bdrv_new_open(out_filename, out_fmt, flags);
|
||||
out_bs = bdrv_new_open(out_filename, out_fmt, flags, true);
|
||||
if (!out_bs) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
@@ -1135,7 +1136,7 @@ static int img_info(int argc, char **argv)
|
||||
}
|
||||
filename = argv[optind++];
|
||||
|
||||
bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING);
|
||||
bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING, false);
|
||||
if (!bs) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1248,7 +1249,7 @@ static int img_snapshot(int argc, char **argv)
|
||||
filename = argv[optind++];
|
||||
|
||||
/* Open the image */
|
||||
bs = bdrv_new_open(filename, NULL, bdrv_oflags);
|
||||
bs = bdrv_new_open(filename, NULL, bdrv_oflags, true);
|
||||
if (!bs) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1366,7 +1367,7 @@ static int img_rebase(int argc, char **argv)
|
||||
* Ignore the old backing file for unsafe rebase in case we want to correct
|
||||
* the reference to a renamed or moved backing file.
|
||||
*/
|
||||
bs = bdrv_new_open(filename, fmt, flags);
|
||||
bs = bdrv_new_open(filename, fmt, flags, true);
|
||||
if (!bs) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1639,7 +1640,7 @@ static int img_resize(int argc, char **argv)
|
||||
n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0);
|
||||
qemu_opts_del(param);
|
||||
|
||||
bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
|
||||
bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true);
|
||||
if (!bs) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ Perform a consistency check on the disk image @var{filename}.
|
||||
If @code{-r} is specified, qemu-img tries to repair any inconsistencies found
|
||||
during the check. @code{-r leaks} repairs only cluster leaks, whereas
|
||||
@code{-r all} fixes all kinds of errors, with a higher risk of choosing the
|
||||
wrong fix or hiding corruption that has already occured.
|
||||
wrong fix or hiding corruption that has already occurred.
|
||||
|
||||
Only the formats @code{qcow2}, @code{qed} and @code{vdi} support
|
||||
consistency checks.
|
||||
|
||||
+27
-1
@@ -838,7 +838,23 @@ Enable SDL.
|
||||
ETEXI
|
||||
|
||||
DEF("spice", HAS_ARG, QEMU_OPTION_spice,
|
||||
"-spice <args> enable spice\n", QEMU_ARCH_ALL)
|
||||
"-spice [port=port][,tls-port=secured-port][,x509-dir=<dir>]\n"
|
||||
" [,x509-key-file=<file>][,x509-key-password=<file>]\n"
|
||||
" [,x509-cert-file=<file>][,x509-cacert-file=<file>]\n"
|
||||
" [,x509-dh-key-file=<file>][,addr=addr][,ipv4|ipv6]\n"
|
||||
" [,tls-ciphers=<list>]\n"
|
||||
" [,tls-channel=[main|display|cursor|inputs|record|playback]]\n"
|
||||
" [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n"
|
||||
" [,sasl][,password=<secret>][,disable-ticketing]\n"
|
||||
" [,image-compression=[auto_glz|auto_lz|quic|glz|lz|off]]\n"
|
||||
" [,jpeg-wan-compression=[auto|never|always]]\n"
|
||||
" [,zlib-glz-wan-compression=[auto|never|always]]\n"
|
||||
" [,streaming-video=[off|all|filter]][,disable-copy-paste]\n"
|
||||
" [,agent-mouse=[on|off]][,playback-compression=[on|off]]\n"
|
||||
" [,seamless-migration=[on|off]]\n"
|
||||
" enable spice\n"
|
||||
" at least one of {port, tls-port} is mandatory\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -spice @var{option}[,@var{option}[,...]]
|
||||
@findex -spice
|
||||
@@ -920,6 +936,9 @@ Enable/disable passing mouse events via vdagent. Default is on.
|
||||
@item playback-compression=[on|off]
|
||||
Enable/disable audio stream compression (using celt 0.5.1). Default is on.
|
||||
|
||||
@item seamless-migration=[on|off]
|
||||
Enable/disable spice seamless migration. Default is off.
|
||||
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
@@ -1338,6 +1357,7 @@ Valid values for @var{type} are
|
||||
Not all devices are supported on all targets. Use -net nic,model=?
|
||||
for a list of available devices for your target.
|
||||
|
||||
@item -netdev user,id=@var{id}[,@var{option}][,@var{option}][,...]
|
||||
@item -net user[,@var{option}][,@var{option}][,...]
|
||||
Use the user mode network stack which requires no administrator
|
||||
privilege to run. Valid options are:
|
||||
@@ -1346,6 +1366,7 @@ privilege to run. Valid options are:
|
||||
@item vlan=@var{n}
|
||||
Connect user mode stack to VLAN @var{n} (@var{n} = 0 is the default).
|
||||
|
||||
@item id=@var{id}
|
||||
@item name=@var{name}
|
||||
Assign symbolic name for use in monitor commands.
|
||||
|
||||
@@ -1471,6 +1492,7 @@ processed and applied to -net user. Mixing them with the new configuration
|
||||
syntax gives undefined results. Their use for new applications is discouraged
|
||||
as they will be removed from future versions.
|
||||
|
||||
@item -netdev tap,id=@var{id}[,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}]
|
||||
@item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}]
|
||||
Connect the host TAP network interface @var{name} to VLAN @var{n}.
|
||||
|
||||
@@ -1510,6 +1532,7 @@ qemu-system-i386 linux.img \
|
||||
-net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper"
|
||||
@end example
|
||||
|
||||
@item -netdev bridge,id=@var{id}[,br=@var{bridge}][,helper=@var{helper}]
|
||||
@item -net bridge[,vlan=@var{n}][,name=@var{name}][,br=@var{bridge}][,helper=@var{helper}]
|
||||
Connect a host TAP network interface to a host bridge device.
|
||||
|
||||
@@ -1532,6 +1555,7 @@ qemu-system-i386 linux.img -net bridge -net nic,model=virtio
|
||||
qemu-system-i386 linux.img -net bridge,br=qemubr0 -net nic,model=virtio
|
||||
@end example
|
||||
|
||||
@item -netdev socket,id=@var{id}[,fd=@var{h}][,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
|
||||
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
|
||||
|
||||
Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual
|
||||
@@ -1554,6 +1578,7 @@ qemu-system-i386 linux.img \
|
||||
-net socket,connect=127.0.0.1:1234
|
||||
@end example
|
||||
|
||||
@item -netdev socket,id=@var{id}[,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]]
|
||||
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]]
|
||||
|
||||
Create a VLAN @var{n} shared with another QEMU virtual
|
||||
@@ -1605,6 +1630,7 @@ qemu-system-i386 linux.img \
|
||||
-net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4
|
||||
@end example
|
||||
|
||||
@item -netdev vde,id=@var{id}[,sock=@var{socketpath}][,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}]
|
||||
@item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}] [,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}]
|
||||
Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and
|
||||
listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname}
|
||||
|
||||
@@ -46,4 +46,6 @@ typedef struct timeval qemu_timeval;
|
||||
typedef struct timespec qemu_timespec;
|
||||
int qemu_utimens(const char *path, const qemu_timespec *times);
|
||||
|
||||
bool is_daemonized(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -68,6 +68,12 @@
|
||||
/* Declaration of ffs() is missing in MinGW's strings.h. */
|
||||
int ffs(int i);
|
||||
|
||||
/* Missing POSIX functions. Don't use MinGW-w64 macros. */
|
||||
#undef gmtime_r
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result);
|
||||
#undef localtime_r
|
||||
struct tm *localtime_r(const time_t *timep, struct tm *result);
|
||||
|
||||
static inline void os_setup_signal_handling(void) {}
|
||||
static inline void os_daemonize(void) {}
|
||||
static inline void os_setup_post(void) {}
|
||||
@@ -86,4 +92,9 @@ typedef struct {
|
||||
} qemu_timeval;
|
||||
int qemu_gettimeofday(qemu_timeval *tp);
|
||||
|
||||
static inline bool is_daemonized(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+216
-75
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "qemu_socket.h"
|
||||
#include "qemu-common.h" /* for qemu_isdigit */
|
||||
#include "main-loop.h"
|
||||
|
||||
#ifndef AI_ADDRCONFIG
|
||||
# define AI_ADDRCONFIG 0
|
||||
@@ -54,9 +55,6 @@ static QemuOptsList dummy_opts = {
|
||||
},{
|
||||
.name = "ipv6",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},{
|
||||
.name = "block",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{ /* end if list */ }
|
||||
},
|
||||
@@ -209,95 +207,201 @@ listen:
|
||||
return slisten;
|
||||
}
|
||||
|
||||
int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
|
||||
#ifdef _WIN32
|
||||
#define QEMU_SOCKET_RC_INPROGRESS(rc) \
|
||||
((rc) == -EINPROGRESS || (rc) == -EWOULDBLOCK || (rc) == -WSAEALREADY)
|
||||
#else
|
||||
#define QEMU_SOCKET_RC_INPROGRESS(rc) \
|
||||
((rc) == -EINPROGRESS)
|
||||
#endif
|
||||
|
||||
/* Struct to store connect state for non blocking connect */
|
||||
typedef struct ConnectState {
|
||||
int fd;
|
||||
struct addrinfo *addr_list;
|
||||
struct addrinfo *current_addr;
|
||||
NonBlockingConnectHandler *callback;
|
||||
void *opaque;
|
||||
} ConnectState;
|
||||
|
||||
static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
|
||||
ConnectState *connect_state);
|
||||
|
||||
static void wait_for_connect(void *opaque)
|
||||
{
|
||||
struct addrinfo ai,*res,*e;
|
||||
ConnectState *s = opaque;
|
||||
int val = 0, rc = 0;
|
||||
socklen_t valsize = sizeof(val);
|
||||
bool in_progress;
|
||||
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
|
||||
|
||||
do {
|
||||
rc = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
|
||||
} while (rc == -1 && socket_error() == EINTR);
|
||||
|
||||
/* update rc to contain error */
|
||||
if (!rc && val) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
/* connect error */
|
||||
if (rc < 0) {
|
||||
closesocket(s->fd);
|
||||
s->fd = rc;
|
||||
}
|
||||
|
||||
/* try to connect to the next address on the list */
|
||||
while (s->current_addr->ai_next != NULL && s->fd < 0) {
|
||||
s->current_addr = s->current_addr->ai_next;
|
||||
s->fd = inet_connect_addr(s->current_addr, &in_progress, s);
|
||||
/* connect in progress */
|
||||
if (in_progress) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(s->addr_list);
|
||||
if (s->callback) {
|
||||
s->callback(s->fd, s->opaque);
|
||||
}
|
||||
g_free(s);
|
||||
return;
|
||||
}
|
||||
|
||||
static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
|
||||
ConnectState *connect_state)
|
||||
{
|
||||
int sock, rc;
|
||||
|
||||
*in_progress = false;
|
||||
|
||||
sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (sock < 0) {
|
||||
fprintf(stderr, "%s: socket(%s): %s\n", __func__,
|
||||
inet_strfamily(addr->ai_family), strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
if (connect_state != NULL) {
|
||||
socket_set_nonblock(sock);
|
||||
}
|
||||
/* connect to peer */
|
||||
do {
|
||||
rc = 0;
|
||||
if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
|
||||
rc = -socket_error();
|
||||
}
|
||||
} while (rc == -EINTR);
|
||||
|
||||
if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) {
|
||||
connect_state->fd = sock;
|
||||
qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect,
|
||||
connect_state);
|
||||
*in_progress = true;
|
||||
} else if (rc < 0) {
|
||||
closesocket(sock);
|
||||
return -1;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
struct addrinfo ai, *res;
|
||||
int rc;
|
||||
const char *addr;
|
||||
const char *port;
|
||||
char uaddr[INET6_ADDRSTRLEN+1];
|
||||
char uport[33];
|
||||
int sock,rc;
|
||||
bool block;
|
||||
|
||||
memset(&ai,0, sizeof(ai));
|
||||
memset(&ai, 0, sizeof(ai));
|
||||
|
||||
ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
|
||||
ai.ai_family = PF_UNSPEC;
|
||||
ai.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (in_progress) {
|
||||
*in_progress = false;
|
||||
}
|
||||
|
||||
addr = qemu_opt_get(opts, "host");
|
||||
port = qemu_opt_get(opts, "port");
|
||||
block = qemu_opt_get_bool(opts, "block", 0);
|
||||
if (addr == NULL || port == NULL) {
|
||||
fprintf(stderr, "inet_connect: host and/or port not specified\n");
|
||||
fprintf(stderr,
|
||||
"inet_parse_connect_opts: host and/or port not specified\n");
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qemu_opt_get_bool(opts, "ipv4", 0)) {
|
||||
ai.ai_family = PF_INET;
|
||||
}
|
||||
if (qemu_opt_get_bool(opts, "ipv6", 0)) {
|
||||
ai.ai_family = PF_INET6;
|
||||
}
|
||||
|
||||
/* lookup */
|
||||
rc = getaddrinfo(addr, port, &ai, &res);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "getaddrinfo(%s,%s): %s\n", addr, port,
|
||||
gai_strerror(rc));
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
return NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a socket and connect it to an address.
|
||||
*
|
||||
* @opts: QEMU options, recognized parameters strings "host" and "port",
|
||||
* bools "ipv4" and "ipv6".
|
||||
* @errp: set on error
|
||||
* @callback: callback function for non-blocking connect
|
||||
* @opaque: opaque for callback function
|
||||
*
|
||||
* Returns: -1 on error, file descriptor on success.
|
||||
*
|
||||
* If @callback is non-null, the connect is non-blocking. If this
|
||||
* function succeeds, callback will be called when the connection
|
||||
* completes, with the file descriptor on success, or -1 on error.
|
||||
*/
|
||||
int inet_connect_opts(QemuOpts *opts, Error **errp,
|
||||
NonBlockingConnectHandler *callback, void *opaque)
|
||||
{
|
||||
struct addrinfo *res, *e;
|
||||
int sock = -1;
|
||||
bool in_progress;
|
||||
ConnectState *connect_state = NULL;
|
||||
|
||||
res = inet_parse_connect_opts(opts, errp);
|
||||
if (!res) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qemu_opt_get_bool(opts, "ipv4", 0))
|
||||
ai.ai_family = PF_INET;
|
||||
if (qemu_opt_get_bool(opts, "ipv6", 0))
|
||||
ai.ai_family = PF_INET6;
|
||||
|
||||
/* lookup */
|
||||
if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
|
||||
fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
|
||||
gai_strerror(rc));
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
return -1;
|
||||
if (callback != NULL) {
|
||||
connect_state = g_malloc0(sizeof(*connect_state));
|
||||
connect_state->addr_list = res;
|
||||
connect_state->callback = callback;
|
||||
connect_state->opaque = opaque;
|
||||
}
|
||||
|
||||
for (e = res; e != NULL; e = e->ai_next) {
|
||||
if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
|
||||
uaddr,INET6_ADDRSTRLEN,uport,32,
|
||||
NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
|
||||
fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
|
||||
continue;
|
||||
if (connect_state != NULL) {
|
||||
connect_state->current_addr = e;
|
||||
}
|
||||
sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
|
||||
if (sock < 0) {
|
||||
fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
|
||||
inet_strfamily(e->ai_family), strerror(errno));
|
||||
continue;
|
||||
}
|
||||
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
|
||||
if (!block) {
|
||||
socket_set_nonblock(sock);
|
||||
}
|
||||
/* connect to peer */
|
||||
do {
|
||||
rc = 0;
|
||||
if (connect(sock, e->ai_addr, e->ai_addrlen) < 0) {
|
||||
rc = -socket_error();
|
||||
sock = inet_connect_addr(e, &in_progress, connect_state);
|
||||
if (in_progress) {
|
||||
return sock;
|
||||
} else if (sock >= 0) {
|
||||
/* non blocking socket immediate success, call callback */
|
||||
if (callback != NULL) {
|
||||
callback(sock, opaque);
|
||||
}
|
||||
} while (rc == -EINTR);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!block && (rc == -EINPROGRESS || rc == -EWOULDBLOCK
|
||||
|| rc == -WSAEALREADY)) {
|
||||
#else
|
||||
if (!block && (rc == -EINPROGRESS)) {
|
||||
#endif
|
||||
if (in_progress) {
|
||||
*in_progress = true;
|
||||
}
|
||||
} else if (rc < 0) {
|
||||
if (NULL == e->ai_next)
|
||||
fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
|
||||
inet_strfamily(e->ai_family),
|
||||
e->ai_canonname, uaddr, uport, strerror(errno));
|
||||
closesocket(sock);
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
return sock;
|
||||
}
|
||||
error_set(errp, QERR_SOCKET_CONNECT_FAILED);
|
||||
if (sock < 0) {
|
||||
error_set(errp, QERR_SOCKET_CONNECT_FAILED);
|
||||
}
|
||||
g_free(connect_state);
|
||||
freeaddrinfo(res);
|
||||
return -1;
|
||||
return sock;
|
||||
}
|
||||
|
||||
int inet_dgram_opts(QemuOpts *opts)
|
||||
@@ -353,7 +457,7 @@ int inet_dgram_opts(QemuOpts *opts)
|
||||
if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) {
|
||||
fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
|
||||
gai_strerror(rc));
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* create socket */
|
||||
@@ -493,17 +597,54 @@ int inet_listen(const char *str, char *ostr, int olen,
|
||||
return sock;
|
||||
}
|
||||
|
||||
int inet_connect(const char *str, bool block, bool *in_progress, Error **errp)
|
||||
/**
|
||||
* Create a blocking socket and connect it to an address.
|
||||
*
|
||||
* @str: address string
|
||||
* @errp: set in case of an error
|
||||
*
|
||||
* Returns -1 in case of error, file descriptor on success
|
||||
**/
|
||||
int inet_connect(const char *str, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
int sock = -1;
|
||||
|
||||
opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
|
||||
if (inet_parse(opts, str) == 0) {
|
||||
if (block) {
|
||||
qemu_opt_set(opts, "block", "on");
|
||||
}
|
||||
sock = inet_connect_opts(opts, in_progress, errp);
|
||||
sock = inet_connect_opts(opts, errp, NULL, NULL);
|
||||
} else {
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return sock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a non-blocking socket and connect it to an address.
|
||||
* Calls the callback function with fd in case of success or -1 in case of
|
||||
* error.
|
||||
*
|
||||
* @str: address string
|
||||
* @callback: callback function that is called when connect completes,
|
||||
* cannot be NULL.
|
||||
* @opaque: opaque for callback function
|
||||
* @errp: set in case of an error
|
||||
*
|
||||
* Returns: -1 on immediate error, file descriptor on success.
|
||||
**/
|
||||
int inet_nonblocking_connect(const char *str,
|
||||
NonBlockingConnectHandler *callback,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
int sock = -1;
|
||||
|
||||
g_assert(callback != NULL);
|
||||
|
||||
opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
|
||||
if (inet_parse(opts, str) == 0) {
|
||||
sock = inet_connect_opts(opts, errp, callback, opaque);
|
||||
} else {
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
}
|
||||
|
||||
+5
-3
@@ -218,7 +218,7 @@ static inline int64_t cpu_get_real_ticks(void)
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
|
||||
#elif defined(__sparc__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks (void)
|
||||
{
|
||||
@@ -227,6 +227,8 @@ static inline int64_t cpu_get_real_ticks (void)
|
||||
asm volatile("rd %%tick,%0" : "=r"(rval));
|
||||
return rval;
|
||||
#else
|
||||
/* We need an %o or %g register for this. For recent enough gcc
|
||||
there is an "h" constraint for that. Don't bother with that. */
|
||||
union {
|
||||
uint64_t i64;
|
||||
struct {
|
||||
@@ -234,8 +236,8 @@ static inline int64_t cpu_get_real_ticks (void)
|
||||
uint32_t low;
|
||||
} i32;
|
||||
} rval;
|
||||
asm volatile("rd %%tick,%1; srlx %1,32,%0"
|
||||
: "=r"(rval.i32.high), "=r"(rval.i32.low));
|
||||
asm volatile("rd %%tick,%%g1; srlx %%g1,32,%0; mov %%g1,%1"
|
||||
: "=r"(rval.i32.high), "=r"(rval.i32.low) : : "g1");
|
||||
return rval.i64;
|
||||
#endif
|
||||
}
|
||||
|
||||
+12
-3
@@ -38,12 +38,21 @@ void socket_set_block(int fd);
|
||||
void socket_set_nonblock(int fd);
|
||||
int send_all(int fd, const void *buf, int len1);
|
||||
|
||||
/* New, ipv6-ready socket helper functions, see qemu-sockets.c */
|
||||
/* callback function for nonblocking connect
|
||||
* valid fd on success, negative error code on failure
|
||||
*/
|
||||
typedef void NonBlockingConnectHandler(int fd, void *opaque);
|
||||
|
||||
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp);
|
||||
int inet_listen(const char *str, char *ostr, int olen,
|
||||
int socktype, int port_offset, Error **errp);
|
||||
int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp);
|
||||
int inet_connect(const char *str, bool block, bool *in_progress, Error **errp);
|
||||
int inet_connect_opts(QemuOpts *opts, Error **errp,
|
||||
NonBlockingConnectHandler *callback, void *opaque);
|
||||
int inet_connect(const char *str, Error **errp);
|
||||
int inet_nonblocking_connect(const char *str,
|
||||
NonBlockingConnectHandler *callback,
|
||||
void *opaque, Error **errp);
|
||||
|
||||
int inet_dgram_opts(QemuOpts *opts);
|
||||
const char *inet_strfamily(int family);
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ typedef struct QObject {
|
||||
|
||||
/* High-level interface for qobject_decref() */
|
||||
#define QDECREF(obj) \
|
||||
qobject_decref(QOBJECT(obj))
|
||||
qobject_decref(obj ? QOBJECT(obj) : NULL)
|
||||
|
||||
/* Initialize an object to default values */
|
||||
#define QOBJECT_INIT(obj, qtype_type) \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user