Compare commits
286
Commits
v1.3.1
...
stable-1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff0245dea2 | ||
|
|
e1a0ffb957 | ||
|
|
178ef3a43a | ||
|
|
cd00334f1a | ||
|
|
8c9283c82a | ||
|
|
bf47da47db | ||
|
|
ea08f3a4e2 | ||
|
|
cef2566953 | ||
|
|
707f2b69ff | ||
|
|
972a2bf072 | ||
|
|
ffffff0146 | ||
|
|
54c6c5a35d | ||
|
|
f05a3da4e0 | ||
|
|
0aad8f1a49 | ||
|
|
a99cb0d20a | ||
|
|
5e19e498b4 | ||
|
|
4fb9656b9d | ||
|
|
38c6d17e75 | ||
|
|
600a9efdb1 | ||
|
|
ea79e157c6 | ||
|
|
4a8e490cbc | ||
|
|
ede76edace | ||
|
|
ac914c1fc2 | ||
|
|
357414daa4 | ||
|
|
f6b803df74 | ||
|
|
879c264803 | ||
|
|
382a582c1f | ||
|
|
5c0d5aebd5 | ||
|
|
3dd59b4dc7 | ||
|
|
03e044136a | ||
|
|
db6e5ab78e | ||
|
|
7817b8d858 | ||
|
|
0dfd8215c2 | ||
|
|
e16d81df85 | ||
|
|
3dfbc51e78 | ||
|
|
eb63b0c2da | ||
|
|
4843c928f9 | ||
|
|
a106eaa3a6 | ||
|
|
472da83043 | ||
|
|
85c91ea7e2 | ||
|
|
5af7caaadd | ||
|
|
0ae18b369c | ||
|
|
5a99c8ca01 | ||
|
|
029eae1a75 | ||
|
|
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 |
No files matched your search
+12
@@ -398,6 +398,12 @@ M: Blue Swirl <blauwirbel@gmail.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/sun4u.c
|
F: hw/sun4u.c
|
||||||
|
|
||||||
|
Leon3
|
||||||
|
M: Fabien Chouteau <chouteau@adacore.com>
|
||||||
|
S: Maintained
|
||||||
|
F: hw/leon3.c
|
||||||
|
F: hw/grlib*
|
||||||
|
|
||||||
S390 Machines
|
S390 Machines
|
||||||
-------------
|
-------------
|
||||||
S390 Virtio
|
S390 Virtio
|
||||||
@@ -525,6 +531,12 @@ M: Anthony Liguori <aliguori@us.ibm.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: qemu-char.c
|
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
|
Device Tree
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||||
M: Alexander Graf <agraf@suse.de>
|
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=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
|
||||||
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(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)
|
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
|
||||||
$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@")
|
$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@")
|
||||||
|
endif
|
||||||
|
|
||||||
-include $(SUBDIR_DEVICES_MAK_DEP)
|
-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
|
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
|
# Linux user emulator target
|
||||||
|
|
||||||
|
|||||||
+9
-4
@@ -562,7 +562,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
|||||||
if ((i & 63) == 0) {
|
if ((i & 63) == 0) {
|
||||||
uint64_t t1 = (qemu_get_clock_ns(rt_clock) - bwidth) / 1000000;
|
uint64_t t1 = (qemu_get_clock_ns(rt_clock) - bwidth) / 1000000;
|
||||||
if (t1 > MAX_WAIT) {
|
if (t1 > MAX_WAIT) {
|
||||||
DPRINTF("big wait: " PRIu64 " milliseconds, %d iterations\n",
|
DPRINTF("big wait: %" PRIu64 " milliseconds, %d iterations\n",
|
||||||
t1, i);
|
t1, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -587,7 +587,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
|||||||
|
|
||||||
expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
|
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());
|
expected_time, migrate_max_downtime());
|
||||||
|
|
||||||
if (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));
|
} while (!(flags & RAM_SAVE_FLAG_EOS));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
DPRINTF("Completed load of VM with exit code %d seq iteration " PRIu64 "\n",
|
DPRINTF("Completed load of VM with exit code %d seq iteration "
|
||||||
ret, seq_iter);
|
"%" PRIu64 "\n", ret, seq_iter);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,11 +922,16 @@ void select_soundhw(const char *optarg)
|
|||||||
if (is_help_option(optarg)) {
|
if (is_help_option(optarg)) {
|
||||||
show_valid_cards:
|
show_valid_cards:
|
||||||
|
|
||||||
|
#ifdef HAS_AUDIO_CHOICE
|
||||||
printf("Valid sound card names (comma separated):\n");
|
printf("Valid sound card names (comma separated):\n");
|
||||||
for (c = soundhw; c->name; ++c) {
|
for (c = soundhw; c->name; ++c) {
|
||||||
printf ("%-11s %s\n", c->name, c->descr);
|
printf ("%-11s %s\n", c->name, c->descr);
|
||||||
}
|
}
|
||||||
printf("\n-soundhw all will enable all of the above\n");
|
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));
|
exit(!is_help_option(optarg));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -410,15 +410,15 @@ SW *glue (AUD_open_, TYPE) (
|
|||||||
SW *old_sw = NULL;
|
SW *old_sw = NULL;
|
||||||
#endif
|
#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)) {
|
if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
|
||||||
dolog ("card=%p name=%p callback_fn=%p as=%p\n",
|
dolog ("card=%p name=%p callback_fn=%p as=%p\n",
|
||||||
card, name, callback_fn, as);
|
card, name, callback_fn, as);
|
||||||
goto fail;
|
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))) {
|
if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
|
||||||
audio_print_settings (as);
|
audio_print_settings (as);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|||||||
@@ -433,7 +433,11 @@ int get_tmp_filename(char *filename, int size)
|
|||||||
return -EOVERFLOW;
|
return -EOVERFLOW;
|
||||||
}
|
}
|
||||||
fd = mkstemp(filename);
|
fd = mkstemp(filename);
|
||||||
if (fd < 0 || close(fd)) {
|
if (fd < 0) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
if (close(fd) != 0) {
|
||||||
|
unlink(filename);
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -664,7 +668,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
|
|||||||
open_flags |= BDRV_O_RDWR;
|
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 */
|
/* Open the image, either directly or using a protocol */
|
||||||
if (drv->bdrv_file_open) {
|
if (drv->bdrv_file_open) {
|
||||||
@@ -735,7 +739,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
|||||||
BlockDriver *drv)
|
BlockDriver *drv)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char tmp_filename[PATH_MAX];
|
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||||
|
char tmp_filename[PATH_MAX + 1];
|
||||||
|
|
||||||
if (flags & BDRV_O_SNAPSHOT) {
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
BlockDriverState *bs1;
|
BlockDriverState *bs1;
|
||||||
@@ -804,6 +809,12 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
|||||||
goto unlink_and_fail;
|
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 */
|
/* Open the image */
|
||||||
ret = bdrv_open_common(bs, filename, flags, drv);
|
ret = bdrv_open_common(bs, filename, flags, drv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -833,12 +844,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
|||||||
bdrv_close(bs);
|
bdrv_close(bs);
|
||||||
return ret;
|
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)) {
|
if (!bdrv_key_required(bs)) {
|
||||||
@@ -897,10 +902,10 @@ void bdrv_close(BlockDriverState *bs)
|
|||||||
bdrv_delete(bs->file);
|
bdrv_delete(bs->file);
|
||||||
bs->file = NULL;
|
bs->file = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_dev_change_media_cb(bs, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bdrv_dev_change_media_cb(bs, false);
|
||||||
|
|
||||||
/*throttling disk I/O limits*/
|
/*throttling disk I/O limits*/
|
||||||
if (bs->io_limits_enabled) {
|
if (bs->io_limits_enabled) {
|
||||||
bdrv_io_limits_disable(bs);
|
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_COPY_ON_READ 0x0400 /* copy read backing sectors into image */
|
||||||
#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */
|
#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */
|
||||||
#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */
|
#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)
|
#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)
|
if (s->multi)
|
||||||
curl_multi_cleanup(s->multi);
|
curl_multi_cleanup(s->multi);
|
||||||
if (s->url)
|
g_free(s->url);
|
||||||
free(s->url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t curl_getlength(BlockDriverState *bs)
|
static int64_t curl_getlength(BlockDriverState *bs)
|
||||||
|
|||||||
+94
-189
@@ -65,13 +65,6 @@ typedef struct IscsiAIOCB {
|
|||||||
#endif
|
#endif
|
||||||
} IscsiAIOCB;
|
} IscsiAIOCB;
|
||||||
|
|
||||||
struct IscsiTask {
|
|
||||||
IscsiLun *iscsilun;
|
|
||||||
BlockDriverState *bs;
|
|
||||||
int status;
|
|
||||||
int complete;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
iscsi_bh_cb(void *p)
|
iscsi_bh_cb(void *p)
|
||||||
{
|
{
|
||||||
@@ -167,12 +160,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;
|
iscsilun->events = ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,7 +377,7 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
*(uint16_t *)&acb->task->cdb[7] = htons(num_sectors);
|
*(uint16_t *)&acb->task->cdb[7] = htons(num_sectors);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||||
iscsi_aio_read16_cb,
|
iscsi_aio_read16_cb,
|
||||||
NULL,
|
NULL,
|
||||||
@@ -628,9 +615,17 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
|||||||
return &acb->common;
|
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)
|
static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||||
{
|
{
|
||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
|
int status;
|
||||||
|
|
||||||
switch (req) {
|
switch (req) {
|
||||||
case SG_GET_VERSION_NUM:
|
case SG_GET_VERSION_NUM:
|
||||||
@@ -639,6 +634,15 @@ static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
|||||||
case SG_GET_SCSI_ID:
|
case SG_GET_SCSI_ID:
|
||||||
((struct sg_scsi_id *)buf)->scsi_type = iscsilun->type;
|
((struct sg_scsi_id *)buf)->scsi_type = iscsilun->type;
|
||||||
break;
|
break;
|
||||||
|
case SG_IO:
|
||||||
|
status = -EINPROGRESS;
|
||||||
|
iscsi_aio_ioctl(bs, req, buf, ioctl_cb, &status);
|
||||||
|
|
||||||
|
while (status == -EINPROGRESS) {
|
||||||
|
qemu_aio_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -658,163 +662,6 @@ iscsi_getlength(BlockDriverState *bs)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
|
|
||||||
void *command_data, void *opaque)
|
|
||||||
{
|
|
||||||
struct IscsiTask *itask = opaque;
|
|
||||||
struct scsi_readcapacity16 *rc16;
|
|
||||||
struct scsi_task *task = command_data;
|
|
||||||
|
|
||||||
if (status != 0) {
|
|
||||||
error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
|
|
||||||
iscsi_get_error(iscsi));
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc16 = scsi_datain_unmarshall(task);
|
|
||||||
if (rc16 == NULL) {
|
|
||||||
error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
itask->iscsilun->block_size = rc16->block_length;
|
|
||||||
itask->iscsilun->num_blocks = rc16->returned_lba + 1;
|
|
||||||
itask->bs->total_sectors = itask->iscsilun->num_blocks *
|
|
||||||
itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
|
||||||
|
|
||||||
itask->status = 0;
|
|
||||||
itask->complete = 1;
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
|
|
||||||
void *command_data, void *opaque)
|
|
||||||
{
|
|
||||||
struct IscsiTask *itask = opaque;
|
|
||||||
struct scsi_readcapacity10 *rc10;
|
|
||||||
struct scsi_task *task = command_data;
|
|
||||||
|
|
||||||
if (status != 0) {
|
|
||||||
error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
|
|
||||||
iscsi_get_error(iscsi));
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc10 = scsi_datain_unmarshall(task);
|
|
||||||
if (rc10 == NULL) {
|
|
||||||
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
itask->iscsilun->block_size = rc10->block_size;
|
|
||||||
if (rc10->lba == 0) {
|
|
||||||
/* blank disk loaded */
|
|
||||||
itask->iscsilun->num_blocks = 0;
|
|
||||||
} else {
|
|
||||||
itask->iscsilun->num_blocks = rc10->lba + 1;
|
|
||||||
}
|
|
||||||
itask->bs->total_sectors = itask->iscsilun->num_blocks *
|
|
||||||
itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
|
||||||
|
|
||||||
itask->status = 0;
|
|
||||||
itask->complete = 1;
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
|
||||||
void *opaque)
|
|
||||||
{
|
|
||||||
struct IscsiTask *itask = opaque;
|
|
||||||
struct scsi_task *task = command_data;
|
|
||||||
struct scsi_inquiry_standard *inq;
|
|
||||||
|
|
||||||
if (status != 0) {
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inq = scsi_datain_unmarshall(task);
|
|
||||||
if (inq == NULL) {
|
|
||||||
error_report("iSCSI: Failed to unmarshall inquiry data.");
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
itask->iscsilun->type = inq->periperal_device_type;
|
|
||||||
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
|
|
||||||
switch (itask->iscsilun->type) {
|
|
||||||
case TYPE_DISK:
|
|
||||||
task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
|
|
||||||
iscsi_readcapacity16_cb, opaque);
|
|
||||||
if (task == NULL) {
|
|
||||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TYPE_ROM:
|
|
||||||
task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun,
|
|
||||||
0, 0,
|
|
||||||
iscsi_readcapacity10_cb, opaque);
|
|
||||||
if (task == NULL) {
|
|
||||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
itask->status = 0;
|
|
||||||
itask->complete = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
|
||||||
void *opaque)
|
|
||||||
{
|
|
||||||
struct IscsiTask *itask = opaque;
|
|
||||||
struct scsi_task *task;
|
|
||||||
|
|
||||||
if (status != 0) {
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
task = iscsi_inquiry_task(iscsi, itask->iscsilun->lun,
|
|
||||||
0, 0, 36,
|
|
||||||
iscsi_inquiry_cb, opaque);
|
|
||||||
if (task == NULL) {
|
|
||||||
error_report("iSCSI: failed to send inquiry command.");
|
|
||||||
itask->status = 1;
|
|
||||||
itask->complete = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_chap(struct iscsi_context *iscsi, const char *target)
|
static int parse_chap(struct iscsi_context *iscsi, const char *target)
|
||||||
{
|
{
|
||||||
QemuOptsList *list;
|
QemuOptsList *list;
|
||||||
@@ -927,7 +774,10 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
struct iscsi_context *iscsi = NULL;
|
struct iscsi_context *iscsi = NULL;
|
||||||
struct iscsi_url *iscsi_url = NULL;
|
struct iscsi_url *iscsi_url = NULL;
|
||||||
struct IscsiTask task;
|
struct scsi_task *task = NULL;
|
||||||
|
struct scsi_inquiry_standard *inq = NULL;
|
||||||
|
struct scsi_readcapacity10 *rc10 = NULL;
|
||||||
|
struct scsi_readcapacity16 *rc16 = NULL;
|
||||||
char *initiator_name = NULL;
|
char *initiator_name = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -940,8 +790,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
|
|
||||||
iscsi_url = iscsi_parse_full_url(iscsi, filename);
|
iscsi_url = iscsi_parse_full_url(iscsi, filename);
|
||||||
if (iscsi_url == NULL) {
|
if (iscsi_url == NULL) {
|
||||||
error_report("Failed to parse URL : %s %s", filename,
|
error_report("Failed to parse URL : %s", filename);
|
||||||
iscsi_get_error(iscsi));
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -991,33 +840,80 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
/* check if we got HEADER_DIGEST via the options */
|
/* check if we got HEADER_DIGEST via the options */
|
||||||
parse_header_digest(iscsi, iscsi_url->target);
|
parse_header_digest(iscsi, iscsi_url->target);
|
||||||
|
|
||||||
task.iscsilun = iscsilun;
|
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
|
||||||
task.status = 0;
|
error_report("iSCSI: Failed to connect to LUN : %s",
|
||||||
task.complete = 0;
|
iscsi_get_error(iscsi));
|
||||||
task.bs = bs;
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
iscsilun->iscsi = iscsi;
|
iscsilun->iscsi = iscsi;
|
||||||
iscsilun->lun = iscsi_url->lun;
|
iscsilun->lun = iscsi_url->lun;
|
||||||
|
|
||||||
if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
|
task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);
|
||||||
iscsi_connect_cb, &task)
|
|
||||||
!= 0) {
|
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||||
error_report("iSCSI: Failed to start async connect.");
|
error_report("iSCSI: failed to send inquiry command.");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!task.complete) {
|
inq = scsi_datain_unmarshall(task);
|
||||||
iscsi_set_events(iscsilun);
|
if (inq == NULL) {
|
||||||
qemu_aio_wait();
|
error_report("iSCSI: Failed to unmarshall inquiry data.");
|
||||||
}
|
|
||||||
if (task.status != 0) {
|
|
||||||
error_report("iSCSI: Failed to connect to LUN : %s",
|
|
||||||
iscsi_get_error(iscsi));
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iscsilun->type = inq->periperal_device_type;
|
||||||
|
|
||||||
|
scsi_free_scsi_task(task);
|
||||||
|
|
||||||
|
switch (iscsilun->type) {
|
||||||
|
case TYPE_DISK:
|
||||||
|
task = iscsi_readcapacity16_sync(iscsi, iscsilun->lun);
|
||||||
|
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||||
|
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc16 = scsi_datain_unmarshall(task);
|
||||||
|
if (rc16 == NULL) {
|
||||||
|
error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
iscsilun->block_size = rc16->block_length;
|
||||||
|
iscsilun->num_blocks = rc16->returned_lba + 1;
|
||||||
|
break;
|
||||||
|
case TYPE_ROM:
|
||||||
|
task = iscsi_readcapacity10_sync(iscsi, iscsilun->lun, 0, 0);
|
||||||
|
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||||
|
error_report("iSCSI: failed to send readcapacity10 command.");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc10 = scsi_datain_unmarshall(task);
|
||||||
|
if (rc10 == NULL) {
|
||||||
|
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
iscsilun->block_size = rc10->block_size;
|
||||||
|
if (rc10->lba == 0) {
|
||||||
|
/* blank disk loaded */
|
||||||
|
iscsilun->num_blocks = 0;
|
||||||
|
} else {
|
||||||
|
iscsilun->num_blocks = rc10->lba + 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs->total_sectors = iscsilun->num_blocks *
|
||||||
|
iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
||||||
|
|
||||||
/* Medium changer or tape. We dont have any emulation for this so this must
|
/* Medium changer or tape. We dont have any emulation for this so this must
|
||||||
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
|
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
|
||||||
* to read from the device to guess the image format.
|
* to read from the device to guess the image format.
|
||||||
@@ -1036,6 +932,9 @@ out:
|
|||||||
if (iscsi_url != NULL) {
|
if (iscsi_url != NULL) {
|
||||||
iscsi_destroy_url(iscsi_url);
|
iscsi_destroy_url(iscsi_url);
|
||||||
}
|
}
|
||||||
|
if (task != NULL) {
|
||||||
|
scsi_free_scsi_task(task);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (iscsi != NULL) {
|
if (iscsi != NULL) {
|
||||||
@@ -1056,6 +955,11 @@ static void iscsi_close(BlockDriverState *bs)
|
|||||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int iscsi_has_zero_init(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static BlockDriver bdrv_iscsi = {
|
static BlockDriver bdrv_iscsi = {
|
||||||
.format_name = "iscsi",
|
.format_name = "iscsi",
|
||||||
.protocol_name = "iscsi",
|
.protocol_name = "iscsi",
|
||||||
@@ -1071,6 +975,7 @@ static BlockDriver bdrv_iscsi = {
|
|||||||
.bdrv_aio_flush = iscsi_aio_flush,
|
.bdrv_aio_flush = iscsi_aio_flush,
|
||||||
|
|
||||||
.bdrv_aio_discard = iscsi_aio_discard,
|
.bdrv_aio_discard = iscsi_aio_discard,
|
||||||
|
.bdrv_has_zero_init = iscsi_has_zero_init,
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
.bdrv_ioctl = iscsi_ioctl,
|
.bdrv_ioctl = iscsi_ioctl,
|
||||||
|
|||||||
@@ -301,7 +301,8 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
uint64_t last_table_size;
|
uint64_t last_table_size;
|
||||||
uint64_t blocks_clusters;
|
uint64_t blocks_clusters;
|
||||||
do {
|
do {
|
||||||
uint64_t table_clusters = size_to_clusters(s, table_size);
|
uint64_t table_clusters =
|
||||||
|
size_to_clusters(s, table_size * sizeof(uint64_t));
|
||||||
blocks_clusters = 1 +
|
blocks_clusters = 1 +
|
||||||
((table_clusters + refcount_block_clusters - 1)
|
((table_clusters + refcount_block_clusters - 1)
|
||||||
/ refcount_block_clusters);
|
/ refcount_block_clusters);
|
||||||
|
|||||||
+2
-1
@@ -1986,7 +1986,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
|||||||
vdi_index = pos / SD_DATA_OBJ_SIZE;
|
vdi_index = pos / SD_DATA_OBJ_SIZE;
|
||||||
offset = 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);
|
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;
|
pos += data_len;
|
||||||
|
data += data_len;
|
||||||
remaining -= data_len;
|
remaining -= data_len;
|
||||||
}
|
}
|
||||||
ret = size;
|
ret = size;
|
||||||
|
|||||||
+12
-13
@@ -628,7 +628,6 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
|||||||
VdiHeader header;
|
VdiHeader header;
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t bmap_size;
|
size_t bmap_size;
|
||||||
uint32_t *bmap;
|
|
||||||
|
|
||||||
logout("\n");
|
logout("\n");
|
||||||
|
|
||||||
@@ -693,21 +692,21 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
|||||||
result = -errno;
|
result = -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
bmap = NULL;
|
|
||||||
if (bmap_size > 0) {
|
if (bmap_size > 0) {
|
||||||
bmap = (uint32_t *)g_malloc0(bmap_size);
|
uint32_t *bmap = g_malloc0(bmap_size);
|
||||||
}
|
for (i = 0; i < blocks; i++) {
|
||||||
for (i = 0; i < blocks; i++) {
|
if (image_type == VDI_TYPE_STATIC) {
|
||||||
if (image_type == VDI_TYPE_STATIC) {
|
bmap[i] = i;
|
||||||
bmap[i] = i;
|
} else {
|
||||||
} else {
|
bmap[i] = VDI_UNALLOCATED;
|
||||||
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 (image_type == VDI_TYPE_STATIC) {
|
||||||
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
|||||||
@@ -527,6 +527,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
|||||||
if_name[type], mediastr, unit_id);
|
if_name[type], mediastr, unit_id);
|
||||||
}
|
}
|
||||||
dinfo->bdrv = bdrv_new(dinfo->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->devaddr = devaddr;
|
||||||
dinfo->type = type;
|
dinfo->type = type;
|
||||||
dinfo->bus = bus_id;
|
dinfo->bus = bus_id;
|
||||||
|
|||||||
@@ -44,6 +44,11 @@
|
|||||||
/* Use gnu_printf when supported (qemu uses standard format strings). */
|
/* Use gnu_printf when supported (qemu uses standard format strings). */
|
||||||
# define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
|
# define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
|
||||||
# define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m)))
|
# 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
|
# endif
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define GCC_WEAK __attribute__((weak))
|
#define GCC_WEAK __attribute__((weak))
|
||||||
|
|||||||
@@ -111,14 +111,12 @@ source_path=`dirname "$0"`
|
|||||||
cpu=""
|
cpu=""
|
||||||
interp_prefix="/usr/gnemul/qemu-%M"
|
interp_prefix="/usr/gnemul/qemu-%M"
|
||||||
static="no"
|
static="no"
|
||||||
sparc_cpu=""
|
|
||||||
cross_prefix=""
|
cross_prefix=""
|
||||||
audio_drv_list=""
|
audio_drv_list=""
|
||||||
audio_card_list="ac97 es1370 sb16 hda"
|
audio_card_list="ac97 es1370 sb16 hda"
|
||||||
audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus hda"
|
audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus hda"
|
||||||
block_drv_whitelist=""
|
block_drv_whitelist=""
|
||||||
host_cc="gcc"
|
host_cc="gcc"
|
||||||
helper_cflags=""
|
|
||||||
libs_softmmu=""
|
libs_softmmu=""
|
||||||
libs_tools=""
|
libs_tools=""
|
||||||
audio_pt_int=""
|
audio_pt_int=""
|
||||||
@@ -183,6 +181,7 @@ datadir="\${prefix}/share"
|
|||||||
qemu_docdir="\${prefix}/share/doc/qemu"
|
qemu_docdir="\${prefix}/share/doc/qemu"
|
||||||
bindir="\${prefix}/bin"
|
bindir="\${prefix}/bin"
|
||||||
libdir="\${prefix}/lib"
|
libdir="\${prefix}/lib"
|
||||||
|
libexecdir="\${prefix}/libexec"
|
||||||
includedir="\${prefix}/include"
|
includedir="\${prefix}/include"
|
||||||
sysconfdir="\${prefix}/etc"
|
sysconfdir="\${prefix}/etc"
|
||||||
confsuffix="/qemu"
|
confsuffix="/qemu"
|
||||||
@@ -216,6 +215,7 @@ usb_redir=""
|
|||||||
opengl=""
|
opengl=""
|
||||||
zlib="yes"
|
zlib="yes"
|
||||||
guest_agent="yes"
|
guest_agent="yes"
|
||||||
|
want_tools="yes"
|
||||||
libiscsi=""
|
libiscsi=""
|
||||||
coroutine=""
|
coroutine=""
|
||||||
seccomp=""
|
seccomp=""
|
||||||
@@ -240,21 +240,6 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--disable-debug-info) debug_info="no"
|
--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
|
esac
|
||||||
done
|
done
|
||||||
# OS specific
|
# OS specific
|
||||||
@@ -342,8 +327,6 @@ elif check_define __i386__ ; then
|
|||||||
elif check_define __x86_64__ ; then
|
elif check_define __x86_64__ ; then
|
||||||
cpu="x86_64"
|
cpu="x86_64"
|
||||||
elif check_define __sparc__ ; then
|
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
|
if check_define __arch64__ ; then
|
||||||
cpu="sparc64"
|
cpu="sparc64"
|
||||||
else
|
else
|
||||||
@@ -633,6 +616,8 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--libdir=*) libdir="$optarg"
|
--libdir=*) libdir="$optarg"
|
||||||
;;
|
;;
|
||||||
|
--libexecdir=*) libexecdir="$optarg"
|
||||||
|
;;
|
||||||
--includedir=*) includedir="$optarg"
|
--includedir=*) includedir="$optarg"
|
||||||
;;
|
;;
|
||||||
--datadir=*) datadir="$optarg"
|
--datadir=*) datadir="$optarg"
|
||||||
@@ -643,7 +628,7 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--sysconfdir=*) sysconfdir="$optarg"
|
--sysconfdir=*) sysconfdir="$optarg"
|
||||||
;;
|
;;
|
||||||
--sbindir=*|--libexecdir=*|--sharedstatedir=*|--localstatedir=*|\
|
--sbindir=*|--sharedstatedir=*|--localstatedir=*|\
|
||||||
--oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\
|
--oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\
|
||||||
--htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*)
|
--htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*)
|
||||||
# These switches are silently ignored, for compatibility with
|
# These switches are silently ignored, for compatibility with
|
||||||
@@ -789,8 +774,6 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-uname-release=*) uname_release="$optarg"
|
--enable-uname-release=*) uname_release="$optarg"
|
||||||
;;
|
;;
|
||||||
--sparc_cpu=*)
|
|
||||||
;;
|
|
||||||
--enable-werror) werror="yes"
|
--enable-werror) werror="yes"
|
||||||
;;
|
;;
|
||||||
--disable-werror) werror="no"
|
--disable-werror) werror="no"
|
||||||
@@ -865,6 +848,10 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--disable-guest-agent) guest_agent="no"
|
--disable-guest-agent) guest_agent="no"
|
||||||
;;
|
;;
|
||||||
|
--enable-tools) want_tools="yes"
|
||||||
|
;;
|
||||||
|
--disable-tools) want_tools="no"
|
||||||
|
;;
|
||||||
--enable-seccomp) seccomp="yes"
|
--enable-seccomp) seccomp="yes"
|
||||||
;;
|
;;
|
||||||
--disable-seccomp) seccomp="no"
|
--disable-seccomp) seccomp="no"
|
||||||
@@ -874,36 +861,17 @@ for opt do
|
|||||||
esac
|
esac
|
||||||
done
|
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"
|
host_guest_base="no"
|
||||||
case "$cpu" in
|
case "$cpu" in
|
||||||
sparc) case $sparc_cpu in
|
sparc)
|
||||||
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
|
|
||||||
LDFLAGS="-m32 $LDFLAGS"
|
LDFLAGS="-m32 $LDFLAGS"
|
||||||
QEMU_CFLAGS="-m32 -ffixed-g2 -ffixed-g3 $QEMU_CFLAGS"
|
QEMU_CFLAGS="-m32 -mcpu=ultrasparc $QEMU_CFLAGS"
|
||||||
if test "$solaris" = "no" ; then
|
host_guest_base="yes"
|
||||||
QEMU_CFLAGS="-ffixed-g1 -ffixed-g6 $QEMU_CFLAGS"
|
|
||||||
helper_cflags="-ffixed-i0"
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
sparc64)
|
sparc64)
|
||||||
QEMU_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__ $QEMU_CFLAGS"
|
|
||||||
LDFLAGS="-m64 $LDFLAGS"
|
LDFLAGS="-m64 $LDFLAGS"
|
||||||
QEMU_CFLAGS="-ffixed-g5 -ffixed-g6 -ffixed-g7 $QEMU_CFLAGS"
|
QEMU_CFLAGS="-m64 -mcpu=ultrasparc $QEMU_CFLAGS"
|
||||||
if test "$solaris" != "no" ; then
|
host_guest_base="yes"
|
||||||
QEMU_CFLAGS="-ffixed-g1 $QEMU_CFLAGS"
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
s390)
|
s390)
|
||||||
QEMU_CFLAGS="-m31 -march=z990 $QEMU_CFLAGS"
|
QEMU_CFLAGS="-m31 -march=z990 $QEMU_CFLAGS"
|
||||||
@@ -919,7 +887,6 @@ case "$cpu" in
|
|||||||
QEMU_CFLAGS="-m32 $QEMU_CFLAGS"
|
QEMU_CFLAGS="-m32 $QEMU_CFLAGS"
|
||||||
LDFLAGS="-m32 $LDFLAGS"
|
LDFLAGS="-m32 $LDFLAGS"
|
||||||
cc_i386='$(CC) -m32'
|
cc_i386='$(CC) -m32'
|
||||||
helper_cflags="-fomit-frame-pointer"
|
|
||||||
host_guest_base="yes"
|
host_guest_base="yes"
|
||||||
;;
|
;;
|
||||||
x86_64)
|
x86_64)
|
||||||
@@ -1319,10 +1286,6 @@ if test -z "$target_list" ; then
|
|||||||
else
|
else
|
||||||
target_list=`echo "$target_list" | sed -e 's/,/ /g'`
|
target_list=`echo "$target_list" | sed -e 's/,/ /g'`
|
||||||
fi
|
fi
|
||||||
if test -z "$target_list" ; then
|
|
||||||
echo "No targets enabled"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# see if system emulation was really requested
|
# see if system emulation was really requested
|
||||||
case " $target_list " in
|
case " $target_list " in
|
||||||
*"-softmmu "*) softmmu=yes
|
*"-softmmu "*) softmmu=yes
|
||||||
@@ -1428,10 +1391,10 @@ if test "$seccomp" != "no" ; then
|
|||||||
LIBS=`$pkg_config --libs libseccomp`
|
LIBS=`$pkg_config --libs libseccomp`
|
||||||
seccomp="yes"
|
seccomp="yes"
|
||||||
else
|
else
|
||||||
seccomp="no"
|
|
||||||
if test "$seccomp" = "yes"; then
|
if test "$seccomp" = "yes"; then
|
||||||
feature_not_found "libseccomp"
|
feature_not_found "libseccomp"
|
||||||
fi
|
fi
|
||||||
|
seccomp="no"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
##########################################
|
##########################################
|
||||||
@@ -2426,8 +2389,7 @@ cat > $TMPC << EOF
|
|||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
pipe2(pipefd, O_CLOEXEC);
|
return pipe2(pipefd, O_CLOEXEC);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
if compile_prog "" "" ; then
|
if compile_prog "" "" ; then
|
||||||
@@ -2667,18 +2629,45 @@ EOF
|
|||||||
fi
|
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
|
# 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
|
cat > $TMPC <<EOF
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <time.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
|
EOF
|
||||||
|
|
||||||
if compile_prog "" "" ; then
|
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="-lrt $LIBS"
|
||||||
|
libs_qga="-lrt $libs_qga"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \
|
if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \
|
||||||
@@ -2701,6 +2690,11 @@ EOF
|
|||||||
spice="yes"
|
spice="yes"
|
||||||
libs_softmmu="$libs_softmmu $spice_libs"
|
libs_softmmu="$libs_softmmu $spice_libs"
|
||||||
QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags"
|
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
|
else
|
||||||
if test "$spice" = "yes" ; then
|
if test "$spice" = "yes" ; then
|
||||||
feature_not_found "spice"
|
feature_not_found "spice"
|
||||||
@@ -2755,7 +2749,7 @@ if test "$usb_redir" != "no" ; then
|
|||||||
usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
|
usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
|
||||||
usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
|
usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
|
||||||
QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
|
QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
|
||||||
LIBS="$LIBS $usb_redir_libs"
|
libs_softmmu="$libs_softmmu $usb_redir_libs"
|
||||||
else
|
else
|
||||||
if test "$usb_redir" = "yes"; then
|
if test "$usb_redir" = "yes"; then
|
||||||
feature_not_found "usb-redir"
|
feature_not_found "usb-redir"
|
||||||
@@ -2963,11 +2957,12 @@ if compile_prog "-Werror" "" ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# check if we have valgrind/valgrind.h
|
# check if we have valgrind/valgrind.h and valgrind/memcheck.h
|
||||||
|
|
||||||
valgrind_h=no
|
valgrind_h=no
|
||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
#include <valgrind/valgrind.h>
|
#include <valgrind/valgrind.h>
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
int main(void) {
|
int main(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3039,9 +3034,14 @@ fi
|
|||||||
qemu_confdir=$sysconfdir$confsuffix
|
qemu_confdir=$sysconfdir$confsuffix
|
||||||
qemu_datadir=$datadir$confsuffix
|
qemu_datadir=$datadir$confsuffix
|
||||||
|
|
||||||
tools=
|
tools=""
|
||||||
if test "$softmmu" = yes ; then
|
if test "$want_tools" = "yes" ; then
|
||||||
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
|
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 "$virtfs" != no ; then
|
||||||
if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
|
if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
|
||||||
virtfs=yes
|
virtfs=yes
|
||||||
@@ -3055,14 +3055,13 @@ if test "$softmmu" = yes ; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
|
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
|
||||||
tools="qemu-nbd\$(EXESUF) $tools"
|
|
||||||
if [ "$guest_agent" = "yes" ]; then
|
if [ "$guest_agent" = "yes" ]; then
|
||||||
tools="qemu-ga\$(EXESUF) $tools"
|
tools="qemu-ga\$(EXESUF) $tools"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
if test "$smartcard_nss" = "yes" ; then
|
||||||
if test "$smartcard_nss" = "yes" ; then
|
tools="vscclient\$(EXESUF) $tools"
|
||||||
tools="vscclient\$(EXESUF) $tools"
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Mac OS X ships with a broken assembler
|
# Mac OS X ships with a broken assembler
|
||||||
@@ -3080,6 +3079,7 @@ echo "Install prefix $prefix"
|
|||||||
echo "BIOS directory `eval echo $qemu_datadir`"
|
echo "BIOS directory `eval echo $qemu_datadir`"
|
||||||
echo "binary directory `eval echo $bindir`"
|
echo "binary directory `eval echo $bindir`"
|
||||||
echo "library directory `eval echo $libdir`"
|
echo "library directory `eval echo $libdir`"
|
||||||
|
echo "libexec directory `eval echo $libexecdir`"
|
||||||
echo "include directory `eval echo $includedir`"
|
echo "include directory `eval echo $includedir`"
|
||||||
echo "config directory `eval echo $sysconfdir`"
|
echo "config directory `eval echo $sysconfdir`"
|
||||||
if test "$mingw32" = "no" ; then
|
if test "$mingw32" = "no" ; then
|
||||||
@@ -3156,7 +3156,7 @@ echo "libcap-ng support $cap_ng"
|
|||||||
echo "vhost-net support $vhost_net"
|
echo "vhost-net support $vhost_net"
|
||||||
echo "Trace backend $trace_backend"
|
echo "Trace backend $trace_backend"
|
||||||
echo "Trace output file $trace_file-<pid>"
|
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 "rbd support $rbd"
|
||||||
echo "xfsctl support $xfs"
|
echo "xfsctl support $xfs"
|
||||||
echo "nss used $smartcard_nss"
|
echo "nss used $smartcard_nss"
|
||||||
@@ -3183,14 +3183,14 @@ echo all: >> $config_host_mak
|
|||||||
echo "prefix=$prefix" >> $config_host_mak
|
echo "prefix=$prefix" >> $config_host_mak
|
||||||
echo "bindir=$bindir" >> $config_host_mak
|
echo "bindir=$bindir" >> $config_host_mak
|
||||||
echo "libdir=$libdir" >> $config_host_mak
|
echo "libdir=$libdir" >> $config_host_mak
|
||||||
|
echo "libexecdir=$libexecdir" >> $config_host_mak
|
||||||
echo "includedir=$includedir" >> $config_host_mak
|
echo "includedir=$includedir" >> $config_host_mak
|
||||||
echo "mandir=$mandir" >> $config_host_mak
|
echo "mandir=$mandir" >> $config_host_mak
|
||||||
echo "sysconfdir=$sysconfdir" >> $config_host_mak
|
echo "sysconfdir=$sysconfdir" >> $config_host_mak
|
||||||
echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
|
echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
|
||||||
echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
|
echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
|
||||||
echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
|
echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
|
||||||
echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
|
echo "qemu_helperdir=$libexecdir" >> $config_host_mak
|
||||||
echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
|
|
||||||
|
|
||||||
echo "ARCH=$ARCH" >> $config_host_mak
|
echo "ARCH=$ARCH" >> $config_host_mak
|
||||||
if test "$debug_tcg" = "yes" ; then
|
if test "$debug_tcg" = "yes" ; then
|
||||||
@@ -3438,6 +3438,10 @@ if test "$spice" = "yes" ; then
|
|||||||
echo "CONFIG_SPICE=y" >> $config_host_mak
|
echo "CONFIG_SPICE=y" >> $config_host_mak
|
||||||
fi
|
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
|
if test "$smartcard" = "yes" ; then
|
||||||
echo "CONFIG_SMARTCARD=y" >> $config_host_mak
|
echo "CONFIG_SMARTCARD=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
@@ -3572,7 +3576,6 @@ if test "$sparse" = "yes" ; then
|
|||||||
echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak
|
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
|
echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
echo "HELPER_CFLAGS=$helper_cflags" >> $config_host_mak
|
|
||||||
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
|
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
|
||||||
echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak
|
echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak
|
||||||
echo "ARLIBS_END=$arlibs_end" >> $config_host_mak
|
echo "ARLIBS_END=$arlibs_end" >> $config_host_mak
|
||||||
@@ -3827,13 +3830,6 @@ fi
|
|||||||
|
|
||||||
symlink "$source_path/Makefile.target" "$target_dir/Makefile"
|
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() {
|
upper() {
|
||||||
echo "$@"| LC_ALL=C tr '[a-z]' '[A-Z]'
|
echo "$@"| LC_ALL=C tr '[a-z]' '[A-Z]'
|
||||||
}
|
}
|
||||||
@@ -4085,10 +4081,6 @@ fi
|
|||||||
|
|
||||||
if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then
|
if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then
|
||||||
case "$ARCH" in
|
case "$ARCH" in
|
||||||
sparc)
|
|
||||||
# -static is used to avoid g1/g3 usage by the dynamic linker
|
|
||||||
ldflags="$linker_script -static $ldflags"
|
|
||||||
;;
|
|
||||||
alpha | s390x)
|
alpha | s390x)
|
||||||
# The default placement of the application is fine.
|
# 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 */
|
case TTY_STATE_CSI: /* handle escape sequence parameters */
|
||||||
if (ch >= '0' && ch <= '9') {
|
if (ch >= '0' && ch <= '9') {
|
||||||
if (s->nb_esc_params < MAX_ESC_PARAMS) {
|
if (s->nb_esc_params < MAX_ESC_PARAMS) {
|
||||||
s->esc_params[s->nb_esc_params] =
|
int *param = &s->esc_params[s->nb_esc_params];
|
||||||
s->esc_params[s->nb_esc_params] * 10 + ch - '0';
|
int digit = (ch - '0');
|
||||||
|
|
||||||
|
*param = (*param <= (INT_MAX - digit) / 10) ?
|
||||||
|
*param * 10 + digit : INT_MAX;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (s->nb_esc_params < MAX_ESC_PARAMS)
|
if (s->nb_esc_params < MAX_ESC_PARAMS)
|
||||||
@@ -1611,7 +1614,7 @@ PixelFormat qemu_different_endianness_pixelformat(int bpp)
|
|||||||
memset(&pf, 0x00, sizeof(PixelFormat));
|
memset(&pf, 0x00, sizeof(PixelFormat));
|
||||||
|
|
||||||
pf.bits_per_pixel = bpp;
|
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;
|
pf.depth = bpp == 32 ? 24 : bpp;
|
||||||
|
|
||||||
switch (bpp) {
|
switch (bpp) {
|
||||||
@@ -1660,13 +1663,12 @@ PixelFormat qemu_default_pixelformat(int bpp)
|
|||||||
memset(&pf, 0x00, sizeof(PixelFormat));
|
memset(&pf, 0x00, sizeof(PixelFormat));
|
||||||
|
|
||||||
pf.bits_per_pixel = bpp;
|
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;
|
pf.depth = bpp == 32 ? 24 : bpp;
|
||||||
|
|
||||||
switch (bpp) {
|
switch (bpp) {
|
||||||
case 15:
|
case 15:
|
||||||
pf.bits_per_pixel = 16;
|
pf.bits_per_pixel = 16;
|
||||||
pf.bytes_per_pixel = 2;
|
|
||||||
pf.rmask = 0x00007c00;
|
pf.rmask = 0x00007c00;
|
||||||
pf.gmask = 0x000003E0;
|
pf.gmask = 0x000003E0;
|
||||||
pf.bmask = 0x0000001F;
|
pf.bmask = 0x0000001F;
|
||||||
|
|||||||
@@ -260,14 +260,6 @@ extern unsigned long reserved_va;
|
|||||||
#define stfl(p, v) stfl_raw(p, v)
|
#define stfl(p, v) stfl_raw(p, v)
|
||||||
#define stfq(p, v) stfq_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_ldub_code(env1, p) ldub_raw(p)
|
||||||
#define cpu_ldsb_code(env1, p) ldsb_raw(p)
|
#define cpu_ldsb_code(env1, p) ldsb_raw(p)
|
||||||
#define cpu_lduw_code(env1, p) lduw_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_stw_kernel(env, addr, data) stw_raw(addr, data)
|
||||||
#define cpu_stl_kernel(env, addr, data) stl_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)
|
#define cpu_stq_kernel(env, addr, data) stq_raw(addr, data)
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ldub_kernel(p) ldub_raw(p)
|
#define ldub_kernel(p) ldub_raw(p)
|
||||||
#define ldsb_kernel(p) ldsb_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 stfl_kernel(p, v) stfl_raw(p, v)
|
||||||
#define stfq_kernel(p, vt) stfq_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_ldub_data(env, addr) ldub_raw(addr)
|
||||||
#define cpu_lduw_data(env, addr) lduw_raw(addr)
|
#define cpu_lduw_data(env, addr) lduw_raw(addr)
|
||||||
#define cpu_ldl_data(env, addr) ldl_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_stb_data(env, addr, data) stb_raw(addr, data)
|
||||||
#define cpu_stw_data(env, addr, data) stw_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)
|
#define cpu_stl_data(env, addr, data) stl_raw(addr, data)
|
||||||
#endif
|
|
||||||
#endif /* defined(CONFIG_USER_ONLY) */
|
#endif /* defined(CONFIG_USER_ONLY) */
|
||||||
|
|
||||||
/* page related stuff */
|
/* 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);
|
mmu_idx = cpu_mmu_index(env1);
|
||||||
if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
|
if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
|
||||||
(addr & TARGET_PAGE_MASK))) {
|
(addr & TARGET_PAGE_MASK))) {
|
||||||
#ifdef CONFIG_TCG_PASS_AREG0
|
|
||||||
cpu_ldub_code(env1, addr);
|
cpu_ldub_code(env1, addr);
|
||||||
#else
|
|
||||||
ldub_code(addr);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
|
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
|
||||||
mr = iotlb_to_region(pd);
|
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
|
#define MMUSUFFIX _cmmu
|
||||||
#undef GETPC
|
#undef GETPC
|
||||||
#define GETPC() ((uintptr_t)0)
|
#define GETPC() ((uintptr_t)0)
|
||||||
#define env cpu_single_env
|
|
||||||
#define SOFTMMU_CODE_ACCESS
|
#define SOFTMMU_CODE_ACCESS
|
||||||
|
|
||||||
#define SHIFT 0
|
#define SHIFT 0
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ time_t mktimegm(struct tm *tm)
|
|||||||
m += 12;
|
m += 12;
|
||||||
y--;
|
y--;
|
||||||
}
|
}
|
||||||
t = 86400 * (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 +
|
t = 86400ULL * (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 +
|
||||||
y / 400 - 719469);
|
y / 400 - 719469);
|
||||||
t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
|
t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
|
||||||
return t;
|
return t;
|
||||||
|
|||||||
@@ -128,6 +128,8 @@
|
|||||||
#define DEF_HELPER_5(name, ret, t1, t2, t3, t4, t5) \
|
#define DEF_HELPER_5(name, ret, t1, t2, t3, t4, t5) \
|
||||||
DEF_HELPER_FLAGS_5(name, 0, 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 */
|
#endif /* DEF_HELPER_H */
|
||||||
|
|
||||||
#ifndef GEN_HELPER
|
#ifndef GEN_HELPER
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ CONFIG_M48T59=y
|
|||||||
CONFIG_PTIMER=y
|
CONFIG_PTIMER=y
|
||||||
CONFIG_VGA=y
|
CONFIG_VGA=y
|
||||||
CONFIG_VGA_PCI=y
|
CONFIG_VGA_PCI=y
|
||||||
CONFIG_VGA_CIRRUS=y
|
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
CONFIG_PARALLEL=y
|
CONFIG_PARALLEL=y
|
||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
|
|||||||
@@ -316,9 +316,7 @@ void disas(FILE *out, void *code, unsigned long size)
|
|||||||
print_insn = print_insn_alpha;
|
print_insn = print_insn_alpha;
|
||||||
#elif defined(__sparc__)
|
#elif defined(__sparc__)
|
||||||
print_insn = print_insn_sparc;
|
print_insn = print_insn_sparc;
|
||||||
#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
|
|
||||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||||
#endif
|
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
print_insn = print_insn_arm;
|
print_insn = print_insn_arm;
|
||||||
#elif defined(__MIPSEB__)
|
#elif defined(__MIPSEB__)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ Arguments:
|
|||||||
|
|
||||||
Returns:
|
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)
|
will have been stored in the parameter block)
|
||||||
H_PARAMETER : Unknown token
|
H_PARAMETER : Unknown token
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -58,11 +58,11 @@ try ...
|
|||||||
xhci controller support
|
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
|
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
|
ehci may work better for you. On the other hand the xhci hardware
|
||||||
design is much more virtualization-friendly, thus xhci emulation uses
|
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 ...
|
use this to add the host controller ...
|
||||||
|
|
||||||
qemu -device nec-usb-xhci,id=xhci
|
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
|
#else
|
||||||
#define MAX_OPC_PARAM_PER_ARG 1
|
#define MAX_OPC_PARAM_PER_ARG 1
|
||||||
#endif
|
#endif
|
||||||
#define MAX_OPC_PARAM_IARGS 4
|
#define MAX_OPC_PARAM_IARGS 5
|
||||||
#define MAX_OPC_PARAM_OARGS 1
|
#define MAX_OPC_PARAM_OARGS 1
|
||||||
#define MAX_OPC_PARAM_ARGS (MAX_OPC_PARAM_IARGS + MAX_OPC_PARAM_OARGS)
|
#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
|
#define CODE_GEN_AVG_BLOCK_SIZE 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__)
|
#if defined(__arm__) || defined(_ARCH_PPC) \
|
||||||
#define USE_DIRECT_JUMP
|
|| defined(__x86_64__) || defined(__i386__) \
|
||||||
#elif defined(CONFIG_TCG_INTERPRETER)
|
|| defined(__sparc__) \
|
||||||
|
|| defined(CONFIG_TCG_INTERPRETER)
|
||||||
#define USE_DIRECT_JUMP
|
#define USE_DIRECT_JUMP
|
||||||
#endif
|
#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));
|
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#elif defined(__sparc__)
|
||||||
|
void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr);
|
||||||
#else
|
#else
|
||||||
#error tb_set_jmp_target1 is missing
|
#error tb_set_jmp_target1 is missing
|
||||||
#endif
|
#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 ACCESS_TYPE (NB_MMU_MODES + 1)
|
||||||
#define MEMSUFFIX _code
|
#define MEMSUFFIX _code
|
||||||
#ifndef CONFIG_TCG_PASS_AREG0
|
|
||||||
#define env cpu_single_env
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DATA_SIZE 1
|
#define DATA_SIZE 1
|
||||||
#include "softmmu_header.h"
|
#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 ACCESS_TYPE
|
||||||
#undef MEMSUFFIX
|
#undef MEMSUFFIX
|
||||||
#undef env
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ static int nb_tbs;
|
|||||||
/* any access to the tbs or the page table must use this lock */
|
/* any access to the tbs or the page table must use this lock */
|
||||||
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
|
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
|
/* The prologue must be reachable with a direct jump. ARM and Sparc64
|
||||||
have limited branch ranges (possibly also PPC) so place it in a
|
have limited branch ranges (possibly also PPC) so place it in a
|
||||||
section close to code segment. */
|
section close to code segment. */
|
||||||
@@ -541,10 +541,9 @@ static void code_gen_alloc(unsigned long tb_size)
|
|||||||
/* Cannot map more than that */
|
/* Cannot map more than that */
|
||||||
if (code_gen_buffer_size > (800 * 1024 * 1024))
|
if (code_gen_buffer_size > (800 * 1024 * 1024))
|
||||||
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
|
// Map the buffer below 2G, so we can use direct calls and branches
|
||||||
flags |= MAP_FIXED;
|
start = (void *) 0x40000000UL;
|
||||||
start = (void *) 0x60000000UL;
|
|
||||||
if (code_gen_buffer_size > (512 * 1024 * 1024))
|
if (code_gen_buffer_size > (512 * 1024 * 1024))
|
||||||
code_gen_buffer_size = (512 * 1024 * 1024);
|
code_gen_buffer_size = (512 * 1024 * 1024);
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
@@ -582,10 +581,9 @@ static void code_gen_alloc(unsigned long tb_size)
|
|||||||
/* Cannot map more than that */
|
/* Cannot map more than that */
|
||||||
if (code_gen_buffer_size > (800 * 1024 * 1024))
|
if (code_gen_buffer_size > (800 * 1024 * 1024))
|
||||||
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
|
// Map the buffer below 2G, so we can use direct calls and branches
|
||||||
flags |= MAP_FIXED;
|
addr = (void *) 0x40000000UL;
|
||||||
addr = (void *) 0x60000000UL;
|
|
||||||
if (code_gen_buffer_size > (512 * 1024 * 1024)) {
|
if (code_gen_buffer_size > (512 * 1024 * 1024)) {
|
||||||
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 */
|
/* ROM/RAM case */
|
||||||
ptr = qemu_get_ram_ptr(addr1);
|
ptr = qemu_get_ram_ptr(addr1);
|
||||||
memcpy(ptr, buf, l);
|
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);
|
qemu_put_ram_ptr(ptr);
|
||||||
}
|
}
|
||||||
len -= l;
|
len -= l;
|
||||||
|
|||||||
+2
-2
@@ -1238,7 +1238,7 @@ float32 uint64_to_float32( uint64 a STATUS_PARAM )
|
|||||||
if ( a == 0 ) return float32_zero;
|
if ( a == 0 ) return float32_zero;
|
||||||
shiftCount = countLeadingZeros64( a ) - 40;
|
shiftCount = countLeadingZeros64( a ) - 40;
|
||||||
if ( 0 <= shiftCount ) {
|
if ( 0 <= shiftCount ) {
|
||||||
return packFloat32( 1 > 0, 0x95 - shiftCount, a<<shiftCount );
|
return packFloat32(0, 0x95 - shiftCount, a<<shiftCount);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
shiftCount += 7;
|
shiftCount += 7;
|
||||||
@@ -1248,7 +1248,7 @@ float32 uint64_to_float32( uint64 a STATUS_PARAM )
|
|||||||
else {
|
else {
|
||||||
a <<= shiftCount;
|
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)
|
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)) {
|
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
|
||||||
GET_REGL(env->gregs[n + 16]);
|
GET_REGL(env->gregs[n + 16]);
|
||||||
} else {
|
} else {
|
||||||
GET_REGL(env->gregs[n]);
|
GET_REGL(env->gregs[n]);
|
||||||
}
|
}
|
||||||
} else if (n < 16) {
|
case 8 ... 15:
|
||||||
GET_REGL(env->gregs[n]);
|
GET_REGL(env->gregs[n]);
|
||||||
} else if (n >= 25 && n < 41) {
|
case 16:
|
||||||
GET_REGL(env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)]);
|
GET_REGL(env->pc);
|
||||||
} else if (n >= 43 && n < 51) {
|
case 17:
|
||||||
GET_REGL(env->gregs[n - 43]);
|
GET_REGL(env->pr);
|
||||||
} else if (n >= 51 && n < 59) {
|
case 18:
|
||||||
GET_REGL(env->gregs[n - (51 - 16)]);
|
GET_REGL(env->gbr);
|
||||||
}
|
case 19:
|
||||||
switch (n) {
|
GET_REGL(env->vbr);
|
||||||
case 16: GET_REGL(env->pc);
|
case 20:
|
||||||
case 17: GET_REGL(env->pr);
|
GET_REGL(env->mach);
|
||||||
case 18: GET_REGL(env->gbr);
|
case 21:
|
||||||
case 19: GET_REGL(env->vbr);
|
GET_REGL(env->macl);
|
||||||
case 20: GET_REGL(env->mach);
|
case 22:
|
||||||
case 21: GET_REGL(env->macl);
|
GET_REGL(env->sr);
|
||||||
case 22: GET_REGL(env->sr);
|
case 23:
|
||||||
case 23: GET_REGL(env->fpul);
|
GET_REGL(env->fpul);
|
||||||
case 24: GET_REGL(env->fpscr);
|
case 24:
|
||||||
case 41: GET_REGL(env->ssr);
|
GET_REGL(env->fpscr);
|
||||||
case 42: GET_REGL(env->spc);
|
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;
|
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)
|
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) {
|
switch (n) {
|
||||||
case 16: env->pc = tmp; break;
|
case 0 ... 7:
|
||||||
case 17: env->pr = tmp; break;
|
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
|
||||||
case 18: env->gbr = tmp; break;
|
env->gregs[n + 16] = ldl_p(mem_buf);
|
||||||
case 19: env->vbr = tmp; break;
|
} else {
|
||||||
case 20: env->mach = tmp; break;
|
env->gregs[n] = ldl_p(mem_buf);
|
||||||
case 21: env->macl = tmp; break;
|
}
|
||||||
case 22: env->sr = tmp; break;
|
break;
|
||||||
case 23: env->fpul = tmp; break;
|
case 8 ... 15:
|
||||||
case 24: env->fpscr = tmp; break;
|
env->gregs[n] = ldl_p(mem_buf);
|
||||||
case 41: env->ssr = tmp; break;
|
break;
|
||||||
case 42: env->spc = tmp; 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;
|
default: return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -512,9 +512,9 @@ STEXI
|
|||||||
@item sendkey @var{keys}
|
@item sendkey @var{keys}
|
||||||
@findex sendkey
|
@findex sendkey
|
||||||
|
|
||||||
Send @var{keys} to the emulator. @var{keys} could be the name of the
|
Send @var{keys} to the guest. @var{keys} could be the name of the
|
||||||
key or @code{#} followed by the raw value in either decimal or hexadecimal
|
key or the raw value in hexadecimal format. Use @code{-} to press
|
||||||
format. Use @code{-} to press several keys simultaneously. Example:
|
several keys simultaneously. Example:
|
||||||
@example
|
@example
|
||||||
sendkey ctrl-alt-f1
|
sendkey ctrl-alt-f1
|
||||||
@end example
|
@end example
|
||||||
|
|||||||
@@ -413,6 +413,8 @@ void hmp_info_spice(Monitor *mon)
|
|||||||
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
|
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
|
||||||
info->host, info->tls_port);
|
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, " auth: %s\n", info->auth);
|
||||||
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
||||||
monitor_printf(mon, " mouse-mode: %s\n",
|
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,
|
memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem,
|
||||||
0x100, 0xc00);
|
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
|
/* Map the whole thing into system memory at the location required
|
||||||
* by the v7M architecture.
|
* 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;
|
uint32_t c = 0;
|
||||||
|
|
||||||
offset >>= 2;
|
offset >>= 2;
|
||||||
if (offset > R_MAX) {
|
if (offset >= R_MAX) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (offset == R_TX_RX) {
|
} else if (offset == R_TX_RX) {
|
||||||
uart_read_rx_fifo(s, &c);
|
uart_read_rx_fifo(s, &c);
|
||||||
|
|||||||
+16
-5
@@ -59,6 +59,9 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
|
|||||||
#define PNPMMIO_SIZE 0x20000
|
#define PNPMMIO_SIZE 0x20000
|
||||||
#define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */
|
#define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */
|
||||||
|
|
||||||
|
/* this is the size past which hardware will drop packets when setting LPE=0 */
|
||||||
|
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HW models:
|
* HW models:
|
||||||
* E1000_DEV_ID_82540EM works with Windows and Linux
|
* E1000_DEV_ID_82540EM works with Windows and Linux
|
||||||
@@ -92,7 +95,6 @@ typedef struct E1000State_st {
|
|||||||
|
|
||||||
uint32_t rxbuf_size;
|
uint32_t rxbuf_size;
|
||||||
uint32_t rxbuf_min_shift;
|
uint32_t rxbuf_min_shift;
|
||||||
int check_rxov;
|
|
||||||
struct e1000_tx {
|
struct e1000_tx {
|
||||||
unsigned char header[256];
|
unsigned char header[256];
|
||||||
unsigned char vlan_header[4];
|
unsigned char vlan_header[4];
|
||||||
@@ -295,6 +297,7 @@ set_rx_control(E1000State *s, int index, uint32_t val)
|
|||||||
s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
|
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],
|
DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
|
||||||
s->mac_reg[RCTL]);
|
s->mac_reg[RCTL]);
|
||||||
|
qemu_flush_queued_packets(&s->nic->nc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -740,11 +743,11 @@ static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
|
|||||||
int bufs;
|
int bufs;
|
||||||
/* Fast-path short packets */
|
/* Fast-path short packets */
|
||||||
if (total_size <= s->rxbuf_size) {
|
if (total_size <= s->rxbuf_size) {
|
||||||
return s->mac_reg[RDH] != s->mac_reg[RDT] || !s->check_rxov;
|
return s->mac_reg[RDH] != s->mac_reg[RDT];
|
||||||
}
|
}
|
||||||
if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
|
if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
|
||||||
bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
|
bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
|
||||||
} else if (s->mac_reg[RDH] > s->mac_reg[RDT] || !s->check_rxov) {
|
} else if (s->mac_reg[RDH] > s->mac_reg[RDT]) {
|
||||||
bufs = s->mac_reg[RDLEN] / sizeof(struct e1000_rx_desc) +
|
bufs = s->mac_reg[RDLEN] / sizeof(struct e1000_rx_desc) +
|
||||||
s->mac_reg[RDT] - s->mac_reg[RDH];
|
s->mac_reg[RDT] - s->mac_reg[RDH];
|
||||||
} else {
|
} else {
|
||||||
@@ -795,6 +798,13 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||||||
size = sizeof(min_buf);
|
size = sizeof(min_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Discard oversized packets if !LPE and !SBP. */
|
||||||
|
if (size > MAXIMUM_ETHERNET_VLAN_SIZE
|
||||||
|
&& !(s->mac_reg[RCTL] & E1000_RCTL_LPE)
|
||||||
|
&& !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
if (!receive_filter(s, buf, size))
|
if (!receive_filter(s, buf, size))
|
||||||
return size;
|
return size;
|
||||||
|
|
||||||
@@ -847,7 +857,6 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||||||
|
|
||||||
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
|
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
|
||||||
s->mac_reg[RDH] = 0;
|
s->mac_reg[RDH] = 0;
|
||||||
s->check_rxov = 1;
|
|
||||||
/* see comment in start_xmit; same here */
|
/* see comment in start_xmit; same here */
|
||||||
if (s->mac_reg[RDH] == rdh_start) {
|
if (s->mac_reg[RDH] == rdh_start) {
|
||||||
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
|
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
|
||||||
@@ -924,8 +933,10 @@ mac_writereg(E1000State *s, int index, uint32_t val)
|
|||||||
static void
|
static void
|
||||||
set_rdt(E1000State *s, int index, uint32_t val)
|
set_rdt(E1000State *s, int index, uint32_t val)
|
||||||
{
|
{
|
||||||
s->check_rxov = 0;
|
|
||||||
s->mac_reg[index] = val & 0xffff;
|
s->mac_reg[index] = val & 0xffff;
|
||||||
|
if (e1000_has_rxbufs(s, 1)) {
|
||||||
|
qemu_flush_queued_packets(&s->nic->nc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
+3
-1
@@ -1036,6 +1036,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
|
|||||||
}
|
}
|
||||||
set_ru_state(s, ru_ready);
|
set_ru_state(s, ru_ready);
|
||||||
s->ru_offset = e100_read_reg4(s, SCBPointer);
|
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));
|
TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
|
||||||
break;
|
break;
|
||||||
case RX_RESUME:
|
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) {
|
if (rfd_command & COMMAND_EL) {
|
||||||
/* EL bit is set, so this was the last frame. */
|
/* EL bit is set, so this was the last frame. */
|
||||||
logout("receive: Running out of frames\n");
|
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) {
|
if (rfd_command & COMMAND_S) {
|
||||||
/* S bit is set. */
|
/* S bit is set. */
|
||||||
|
|||||||
@@ -269,6 +269,17 @@ static int glue(load_elf, SZ)(const char *name, int fd,
|
|||||||
addr = ph->p_paddr;
|
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);
|
snprintf(label, sizeof(label), "phdr #%d: %s", i, name);
|
||||||
rom_add_blob_fixed(label, data, mem_size, addr);
|
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_no = i;
|
||||||
ad->port.dma = &ad->dma;
|
ad->port.dma = &ad->dma;
|
||||||
ad->port.dma->ops = &ahci_dma_ops;
|
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_stat = 0;
|
||||||
pr->irq_mask = 0;
|
pr->irq_mask = 0;
|
||||||
pr->scr_ctl = 0;
|
pr->scr_ctl = 0;
|
||||||
|
pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
|
||||||
ahci_reset_port(s, i);
|
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},
|
{ 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||||
/* airflow-temperature-celsius */
|
/* airflow-temperature-celsius */
|
||||||
{ 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
|
{ 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);
|
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:
|
case SMART_READ_THRESH:
|
||||||
memset(s->io_buffer, 0, 0x200);
|
memset(s->io_buffer, 0, 0x200);
|
||||||
s->io_buffer[0] = 0x01; /* smart struct version */
|
s->io_buffer[0] = 0x01; /* smart struct version */
|
||||||
for (n=0; n<30; n++) {
|
for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
|
||||||
if (smart_attributes[n][0] == 0)
|
|
||||||
break;
|
|
||||||
s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
|
s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
|
||||||
s->io_buffer[2+1+(n*12)] = smart_attributes[n][11];
|
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:
|
case SMART_READ_DATA:
|
||||||
memset(s->io_buffer, 0, 0x200);
|
memset(s->io_buffer, 0, 0x200);
|
||||||
s->io_buffer[0] = 0x01; /* smart struct version */
|
s->io_buffer[0] = 0x01; /* smart struct version */
|
||||||
for (n=0; n<30; n++) {
|
for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
|
||||||
if (smart_attributes[n][0] == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 11; i++) {
|
for(i = 0; i < 11; i++) {
|
||||||
s->io_buffer[2+i+(n*12)] = smart_attributes[n][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);
|
rc = pcie_chassis_add_slot(s);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
goto err_pcie_cap;
|
goto err_pcie_cap;
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
pcie_cap_root_init(d);
|
pcie_cap_root_init(d);
|
||||||
rc = pcie_aer_init(d, IOH_EP_AER_OFFSET);
|
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 {
|
} else {
|
||||||
/* Hash matching */
|
/* Hash matching */
|
||||||
hash = (crc32(~0, addr, 6) >> 26);
|
hash = compute_mcast_idx(addr);
|
||||||
if (hash & 0x20) {
|
if (hash & 0x20) {
|
||||||
return (s->mac_hashh >> (hash & 0x1f)) & 1;
|
return (s->mac_hashh >> (hash & 0x1f)) & 1;
|
||||||
} else {
|
} 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.
|
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");
|
DPRINTF("write_sample Buffer full\n");
|
||||||
return 0;
|
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;
|
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||||
offset &= 0x3ff;
|
offset &= 0x3ff;
|
||||||
if (offset > 0x200) {
|
if (offset >= 0x200) {
|
||||||
hw_error("Bad MBAR read offset 0x%x", (int)offset);
|
hw_error("Bad MBAR read offset 0x%x", (int)offset);
|
||||||
}
|
}
|
||||||
if (m5206_mbar_width[offset >> 2] > 1) {
|
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;
|
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||||
int width;
|
int width;
|
||||||
offset &= 0x3ff;
|
offset &= 0x3ff;
|
||||||
if (offset > 0x200) {
|
if (offset >= 0x200) {
|
||||||
hw_error("Bad MBAR read offset 0x%x", (int)offset);
|
hw_error("Bad MBAR read offset 0x%x", (int)offset);
|
||||||
}
|
}
|
||||||
width = m5206_mbar_width[offset >> 2];
|
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;
|
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||||
int width;
|
int width;
|
||||||
offset &= 0x3ff;
|
offset &= 0x3ff;
|
||||||
if (offset > 0x200) {
|
if (offset >= 0x200) {
|
||||||
hw_error("Bad MBAR read offset 0x%x", (int)offset);
|
hw_error("Bad MBAR read offset 0x%x", (int)offset);
|
||||||
}
|
}
|
||||||
width = m5206_mbar_width[offset >> 2];
|
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;
|
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||||
int width;
|
int width;
|
||||||
offset &= 0x3ff;
|
offset &= 0x3ff;
|
||||||
if (offset > 0x200) {
|
if (offset >= 0x200) {
|
||||||
hw_error("Bad MBAR write offset 0x%x", (int)offset);
|
hw_error("Bad MBAR write offset 0x%x", (int)offset);
|
||||||
}
|
}
|
||||||
width = m5206_mbar_width[offset >> 2];
|
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;
|
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||||
int width;
|
int width;
|
||||||
offset &= 0x3ff;
|
offset &= 0x3ff;
|
||||||
if (offset > 0x200) {
|
if (offset >= 0x200) {
|
||||||
hw_error("Bad MBAR write offset 0x%x", (int)offset);
|
hw_error("Bad MBAR write offset 0x%x", (int)offset);
|
||||||
}
|
}
|
||||||
width = m5206_mbar_width[offset >> 2];
|
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;
|
m5206_mbar_state *s = (m5206_mbar_state *)opaque;
|
||||||
int width;
|
int width;
|
||||||
offset &= 0x3ff;
|
offset &= 0x3ff;
|
||||||
if (offset > 0x200) {
|
if (offset >= 0x200) {
|
||||||
hw_error("Bad MBAR write offset 0x%x", (int)offset);
|
hw_error("Bad MBAR write offset 0x%x", (int)offset);
|
||||||
}
|
}
|
||||||
width = m5206_mbar_width[offset >> 2];
|
width = m5206_mbar_width[offset >> 2];
|
||||||
|
|||||||
+2
-1
@@ -860,7 +860,8 @@ void mips_malta_init (ram_addr_t ram_size,
|
|||||||
be = 0;
|
be = 0;
|
||||||
#endif
|
#endif
|
||||||
/* FPGA */
|
/* FPGA */
|
||||||
malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[2], serial_hds[2]);
|
/* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
|
||||||
|
malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]);
|
||||||
|
|
||||||
/* Load firmware in flash / BIOS. */
|
/* Load firmware in flash / BIOS. */
|
||||||
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
|
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
|
||||||
|
|||||||
+2
-2
@@ -1583,7 +1583,7 @@ static void musicpal_init(ram_addr_t ram_size,
|
|||||||
* image is smaller than 32 MB.
|
* image is smaller than 32 MB.
|
||||||
*/
|
*/
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#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,
|
"musicpal.flash", flash_size,
|
||||||
dinfo->bdrv, 0x10000,
|
dinfo->bdrv, 0x10000,
|
||||||
(flash_size + 0xffff) >> 16,
|
(flash_size + 0xffff) >> 16,
|
||||||
@@ -1591,7 +1591,7 @@ static void musicpal_init(ram_addr_t ram_size,
|
|||||||
2, 0x00BF, 0x236D, 0x0000, 0x0000,
|
2, 0x00BF, 0x236D, 0x0000, 0x0000,
|
||||||
0x5555, 0x2AAA, 1);
|
0x5555, 0x2AAA, 1);
|
||||||
#else
|
#else
|
||||||
pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL,
|
pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
|
||||||
"musicpal.flash", flash_size,
|
"musicpal.flash", flash_size,
|
||||||
dinfo->bdrv, 0x10000,
|
dinfo->bdrv, 0x10000,
|
||||||
(flash_size + 0xffff) >> 16,
|
(flash_size + 0xffff) >> 16,
|
||||||
|
|||||||
@@ -654,7 +654,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
|
|||||||
sector = SECTOR(s->addr);
|
sector = SECTOR(s->addr);
|
||||||
off = (s->addr & PAGE_MASK) + s->offset;
|
off = (s->addr & PAGE_MASK) + s->offset;
|
||||||
soff = SECTOR_OFFSET(s->addr);
|
soff = SECTOR_OFFSET(s->addr);
|
||||||
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
|
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
|
||||||
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
|
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -666,21 +666,23 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
|
|||||||
MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
|
MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
|
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
|
||||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
|
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
|
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
|
||||||
sector = off >> 9;
|
sector = off >> 9;
|
||||||
soff = off & 0x1ff;
|
soff = off & 0x1ff;
|
||||||
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
|
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
|
||||||
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
|
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mem_and(iobuf + soff, s->io, s->iolen);
|
mem_and(iobuf + soff, s->io, s->iolen);
|
||||||
|
|
||||||
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
|
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
|
||||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
|
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s->offset = 0;
|
s->offset = 0;
|
||||||
}
|
}
|
||||||
@@ -704,31 +706,37 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
|
|||||||
i = SECTOR(addr);
|
i = SECTOR(addr);
|
||||||
page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
|
page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
|
||||||
for (; i < page; i ++)
|
for (; i < page; i ++)
|
||||||
if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
|
if (bdrv_write(s->bdrv, i, iobuf, 1) < 0) {
|
||||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
|
printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
addr = PAGE_START(addr);
|
addr = PAGE_START(addr);
|
||||||
page = addr >> 9;
|
page = addr >> 9;
|
||||||
if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
|
if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
|
||||||
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
|
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
|
||||||
|
}
|
||||||
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
|
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
|
||||||
if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
|
if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
|
||||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
|
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
|
||||||
|
}
|
||||||
|
|
||||||
memset(iobuf, 0xff, 0x200);
|
memset(iobuf, 0xff, 0x200);
|
||||||
i = (addr & ~0x1ff) + 0x200;
|
i = (addr & ~0x1ff) + 0x200;
|
||||||
for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
|
for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
|
||||||
i < addr; i += 0x200)
|
i < addr; i += 0x200)
|
||||||
if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
|
if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) < 0) {
|
||||||
printf("%s: write error in sector %" PRIu64 "\n",
|
printf("%s: write error in sector %" PRIu64 "\n",
|
||||||
__func__, i >> 9);
|
__func__, i >> 9);
|
||||||
|
}
|
||||||
|
|
||||||
page = i >> 9;
|
page = i >> 9;
|
||||||
if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
|
if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
|
||||||
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
|
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
|
||||||
|
}
|
||||||
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
|
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
|
||||||
if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
|
if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
|
||||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
|
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -740,18 +748,20 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
|
|||||||
|
|
||||||
if (s->bdrv) {
|
if (s->bdrv) {
|
||||||
if (s->mem_oob) {
|
if (s->mem_oob) {
|
||||||
if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
|
if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) < 0) {
|
||||||
printf("%s: read error in sector %" PRIu64 "\n",
|
printf("%s: read error in sector %" PRIu64 "\n",
|
||||||
__func__, SECTOR(addr));
|
__func__, SECTOR(addr));
|
||||||
|
}
|
||||||
memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
|
memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
|
||||||
s->storage + (PAGE(s->addr) << OOB_SHIFT),
|
s->storage + (PAGE(s->addr) << OOB_SHIFT),
|
||||||
OOB_SIZE);
|
OOB_SIZE);
|
||||||
s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
|
s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
|
||||||
} else {
|
} else {
|
||||||
if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
|
if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
|
||||||
s->io, (PAGE_SECTORS + 2)) == -1)
|
s->io, (PAGE_SECTORS + 2)) < 0) {
|
||||||
printf("%s: read error in sector %" PRIu64 "\n",
|
printf("%s: read error in sector %" PRIu64 "\n",
|
||||||
__func__, PAGE_START(addr) >> 9);
|
__func__, PAGE_START(addr) >> 9);
|
||||||
|
}
|
||||||
s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
|
s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-1
@@ -351,7 +351,7 @@ static inline int onenand_erase(OneNANDState *s, int sec, int num)
|
|||||||
for (; num > 0; num--, sec++) {
|
for (; num > 0; num--, sec++) {
|
||||||
if (s->bdrv_cur) {
|
if (s->bdrv_cur) {
|
||||||
int erasesec = s->secs_cur + (sec >> 5);
|
int erasesec = s->secs_cur + (sec >> 5);
|
||||||
if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1)) {
|
if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1) < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
|
if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
|
||||||
|
|||||||
+7
-1
@@ -80,7 +80,13 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
|
|||||||
SCSIBus *scsibus;
|
SCSIBus *scsibus;
|
||||||
SCSIDevice *scsidev;
|
SCSIDevice *scsidev;
|
||||||
|
|
||||||
scsibus = SCSI_BUS(QLIST_FIRST(&adapter->child_bus));
|
scsibus = (SCSIBus *)
|
||||||
|
object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)),
|
||||||
|
TYPE_SCSI_BUS);
|
||||||
|
if (!scsibus) {
|
||||||
|
error_report("Device is not a SCSI adapter");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* drive_init() tries to find a default for dinfo->unit. Doesn't
|
* drive_init() tries to find a default for dinfo->unit. Doesn't
|
||||||
|
|||||||
@@ -439,7 +439,7 @@ const VMStateDescription vmstate_pci_device = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_pcie_device = {
|
const VMStateDescription vmstate_pcie_device = {
|
||||||
.name = "PCIDevice",
|
.name = "PCIEDevice",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.minimum_version_id_old = 1,
|
||||||
|
|||||||
@@ -133,7 +133,6 @@ extern const VMStateDescription vmstate_pcie_device;
|
|||||||
|
|
||||||
#define VMSTATE_PCIE_DEVICE(_field, _state) { \
|
#define VMSTATE_PCIE_DEVICE(_field, _state) { \
|
||||||
.name = (stringify(_field)), \
|
.name = (stringify(_field)), \
|
||||||
.version_id = 2, \
|
|
||||||
.size = sizeof(PCIDevice), \
|
.size = sizeof(PCIDevice), \
|
||||||
.vmsd = &vmstate_pcie_device, \
|
.vmsd = &vmstate_pcie_device, \
|
||||||
.flags = VMS_STRUCT, \
|
.flags = VMS_STRUCT, \
|
||||||
|
|||||||
@@ -738,6 +738,11 @@ void pcie_aer_root_init(PCIDevice *dev)
|
|||||||
PCI_ERR_ROOT_CMD_EN_MASK);
|
PCI_ERR_ROOT_CMD_EN_MASK);
|
||||||
pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS,
|
pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS,
|
||||||
PCI_ERR_ROOT_STATUS_REPORT_MASK);
|
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)
|
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->wcycle++;
|
||||||
pfl->cmd = cmd;
|
pfl->cmd = cmd;
|
||||||
return;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
switch (pfl->cmd) {
|
switch (pfl->cmd) {
|
||||||
case 0x10: /* Single Byte Program */
|
case 0x10: /* Single Byte Program */
|
||||||
@@ -375,7 +375,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
|
|||||||
default:
|
default:
|
||||||
goto error_flash;
|
goto error_flash;
|
||||||
}
|
}
|
||||||
return;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
switch (pfl->cmd) {
|
switch (pfl->cmd) {
|
||||||
case 0xe8: /* Block write */
|
case 0xe8: /* Block write */
|
||||||
@@ -406,7 +406,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
|
|||||||
default:
|
default:
|
||||||
goto error_flash;
|
goto error_flash;
|
||||||
}
|
}
|
||||||
return;
|
break;
|
||||||
case 3: /* Confirm mode */
|
case 3: /* Confirm mode */
|
||||||
switch (pfl->cmd) {
|
switch (pfl->cmd) {
|
||||||
case 0xe8: /* Block write */
|
case 0xe8: /* Block write */
|
||||||
@@ -422,7 +422,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
|
|||||||
default:
|
default:
|
||||||
goto error_flash;
|
goto error_flash;
|
||||||
}
|
}
|
||||||
return;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Should never happen */
|
/* Should never happen */
|
||||||
DPRINTF("%s: invalid write state\n", __func__);
|
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[0x33] = 'I';
|
||||||
|
|
||||||
pfl->cfi_table[0x34] = '1';
|
pfl->cfi_table[0x34] = '1';
|
||||||
pfl->cfi_table[0x35] = '1';
|
pfl->cfi_table[0x35] = '0';
|
||||||
|
|
||||||
pfl->cfi_table[0x36] = 0x00;
|
pfl->cfi_table[0x36] = 0x00;
|
||||||
pfl->cfi_table[0x37] = 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[0x3b] = 0x00;
|
||||||
pfl->cfi_table[0x3c] = 0x00;
|
pfl->cfi_table[0x3c] = 0x00;
|
||||||
|
|
||||||
|
pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
|
||||||
|
|
||||||
return pfl;
|
return pfl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-6
@@ -117,12 +117,18 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t offset,
|
|||||||
return s->protected;
|
return s->protected;
|
||||||
case 12: /* VECTADDR */
|
case 12: /* VECTADDR */
|
||||||
/* Read vector address at the start of an ISR. Increases the
|
/* Read vector address at the start of an ISR. Increases the
|
||||||
current priority level to that of the current interrupt. */
|
* current priority level to that of the current interrupt.
|
||||||
for (i = 0; i < s->priority; i++)
|
*
|
||||||
{
|
* Since an enabled interrupt X at priority P causes prio_mask[Y]
|
||||||
if ((s->level | s->soft_level) & s->prio_mask[i])
|
* to have bit X set for all Y > P, this loop will stop with
|
||||||
break;
|
* 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.
|
/* Reading this value with no pending interrupts is undefined.
|
||||||
We return the default address. */
|
We return the default address. */
|
||||||
if (i == PL190_NUM_PRIO)
|
if (i == PL190_NUM_PRIO)
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ static int bamboo_load_device_tree(target_phys_addr_t addr,
|
|||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
#ifdef CONFIG_FDT
|
#ifdef CONFIG_FDT
|
||||||
uint32_t mem_reg_property[] = { 0, 0, ramsize };
|
uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
|
||||||
char *filename;
|
char *filename;
|
||||||
int fdt_size;
|
int fdt_size;
|
||||||
void *fdt;
|
void *fdt;
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
|||||||
{
|
{
|
||||||
VGACommonState *vga = &qxl->vga;
|
VGACommonState *vga = &qxl->vga;
|
||||||
int i;
|
int i;
|
||||||
DisplaySurface *surface = vga->ds->surface;
|
|
||||||
|
|
||||||
if (qxl->guest_primary.resized) {
|
if (qxl->guest_primary.resized) {
|
||||||
qxl->guest_primary.resized = 0;
|
qxl->guest_primary.resized = 0;
|
||||||
@@ -112,9 +111,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
|||||||
qxl->guest_primary.qxl_stride,
|
qxl->guest_primary.qxl_stride,
|
||||||
qxl->guest_primary.bytes_pp,
|
qxl->guest_primary.bytes_pp,
|
||||||
qxl->guest_primary.bits_pp);
|
qxl->guest_primary.bits_pp);
|
||||||
}
|
|
||||||
if (surface->width != qxl->guest_primary.surface.width ||
|
|
||||||
surface->height != qxl->guest_primary.surface.height) {
|
|
||||||
if (qxl->guest_primary.qxl_stride > 0) {
|
if (qxl->guest_primary.qxl_stride > 0) {
|
||||||
qemu_free_displaysurface(vga->ds);
|
qemu_free_displaysurface(vga->ds);
|
||||||
qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
|
qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
|
||||||
|
|||||||
@@ -27,6 +27,11 @@
|
|||||||
|
|
||||||
#include "qxl.h"
|
#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
|
* 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
|
* 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, ...)
|
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_send_events(qxl, QXL_INTERRUPT_ERROR);
|
||||||
qxl->guest_bug = 1;
|
qxl->guest_bug = 1;
|
||||||
if (qxl->guestdebug) {
|
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);
|
spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie);
|
||||||
} else {
|
} else {
|
||||||
qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
|
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)
|
void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
|
||||||
{
|
{
|
||||||
trace_qxl_spice_reset_image_cache(qxl->id);
|
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_DESTROY_ALL_SURFACES_ASYNC",
|
||||||
[QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC",
|
[QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC",
|
||||||
[QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE",
|
[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];
|
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_DESTROY_PRIMARY_ASYNC:
|
||||||
case QXL_IO_UPDATE_AREA_ASYNC:
|
case QXL_IO_UPDATE_AREA_ASYNC:
|
||||||
case QXL_IO_FLUSH_SURFACES_ASYNC:
|
case QXL_IO_FLUSH_SURFACES_ASYNC:
|
||||||
|
case QXL_IO_MONITORS_CONFIG_ASYNC:
|
||||||
break;
|
break;
|
||||||
case QXL_IO_CREATE_PRIMARY_ASYNC:
|
case QXL_IO_CREATE_PRIMARY_ASYNC:
|
||||||
qxl_create_guest_primary_complete(qxl);
|
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:
|
case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA:
|
||||||
qxl_render_update_area_done(qxl, cookie);
|
qxl_render_update_area_done(qxl, cookie);
|
||||||
break;
|
break;
|
||||||
|
case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
|
fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
|
||||||
__func__, cookie->type);
|
__func__, cookie->type);
|
||||||
@@ -958,9 +1002,10 @@ static void qxl_update_irq(PCIQXLDevice *d)
|
|||||||
static void qxl_check_state(PCIQXLDevice *d)
|
static void qxl_check_state(PCIQXLDevice *d)
|
||||||
{
|
{
|
||||||
QXLRam *ram = d->ram;
|
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(!spice_display_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->cursor_ring));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qxl_reset_state(PCIQXLDevice *d)
|
static void qxl_reset_state(PCIQXLDevice *d)
|
||||||
@@ -1314,6 +1359,13 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
|
|||||||
return;
|
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) {
|
switch (io_port) {
|
||||||
case QXL_IO_RESET:
|
case QXL_IO_RESET:
|
||||||
case QXL_IO_SET_MODE:
|
case QXL_IO_SET_MODE:
|
||||||
@@ -1330,10 +1382,10 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
trace_qxl_io_unexpected_vga_mode(d->id,
|
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 */
|
/* be nice to buggy guest drivers */
|
||||||
if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
|
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);
|
qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1361,6 +1413,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
|
|||||||
io_port = QXL_IO_DESTROY_ALL_SURFACES;
|
io_port = QXL_IO_DESTROY_ALL_SURFACES;
|
||||||
goto async_common;
|
goto async_common;
|
||||||
case QXL_IO_FLUSH_SURFACES_ASYNC:
|
case QXL_IO_FLUSH_SURFACES_ASYNC:
|
||||||
|
case QXL_IO_MONITORS_CONFIG_ASYNC:
|
||||||
async_common:
|
async_common:
|
||||||
async = QXL_ASYNC;
|
async = QXL_ASYNC;
|
||||||
qemu_mutex_lock(&d->async_lock);
|
qemu_mutex_lock(&d->async_lock);
|
||||||
@@ -1385,6 +1438,25 @@ async_common:
|
|||||||
QXLCookie *cookie = NULL;
|
QXLCookie *cookie = NULL;
|
||||||
QXLRect update = d->ram->update_area;
|
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) {
|
if (async == QXL_ASYNC) {
|
||||||
cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
|
cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
|
||||||
QXL_IO_UPDATE_AREA_ASYNC);
|
QXL_IO_UPDATE_AREA_ASYNC);
|
||||||
@@ -1490,6 +1562,9 @@ async_common:
|
|||||||
d->mode = QXL_MODE_UNDEFINED;
|
d->mode = QXL_MODE_UNDEFINED;
|
||||||
qxl_spice_destroy_surfaces(d, async);
|
qxl_spice_destroy_surfaces(d, async);
|
||||||
break;
|
break;
|
||||||
|
case QXL_IO_MONITORS_CONFIG_ASYNC:
|
||||||
|
qxl_spice_monitors_config_async(d, 0);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
|
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,
|
static uint64_t ioport_read(void *opaque, target_phys_addr_t addr,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
PCIQXLDevice *d = opaque;
|
PCIQXLDevice *qxl = opaque;
|
||||||
|
|
||||||
trace_qxl_io_read_unexpected(d->id);
|
trace_qxl_io_read_unexpected(qxl->id);
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1538,7 +1613,8 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
|
|||||||
uint32_t old_pending;
|
uint32_t old_pending;
|
||||||
uint32_t le_events = cpu_to_le32(events);
|
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);
|
old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
|
||||||
if ((old_pending & le_events) == le_events) {
|
if ((old_pending & le_events) == le_events) {
|
||||||
return;
|
return;
|
||||||
@@ -1627,7 +1703,7 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
|
|||||||
|
|
||||||
static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
|
static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
|
||||||
{
|
{
|
||||||
intptr_t vram_start;
|
uintptr_t vram_start;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) {
|
if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) {
|
||||||
@@ -1638,7 +1714,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
|
|||||||
qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
|
qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
|
||||||
qxl->shadow_rom.surface0_area_size);
|
qxl->shadow_rom.surface0_area_size);
|
||||||
|
|
||||||
vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
|
vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
|
||||||
|
|
||||||
/* dirty the off-screen surfaces */
|
/* dirty the off-screen surfaces */
|
||||||
for (i = 0; i < NUM_SURFACES; i++) {
|
for (i = 0; i < NUM_SURFACES; i++) {
|
||||||
@@ -1785,6 +1861,17 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
|||||||
io_size = 16;
|
io_size = 16;
|
||||||
break;
|
break;
|
||||||
case 3: /* qxl-3 */
|
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:
|
default:
|
||||||
pci_device_rev = QXL_DEFAULT_REVISION;
|
pci_device_rev = QXL_DEFAULT_REVISION;
|
||||||
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
|
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
|
||||||
@@ -1955,6 +2042,7 @@ static int qxl_post_load(void *opaque, int version)
|
|||||||
|
|
||||||
switch (newmode) {
|
switch (newmode) {
|
||||||
case QXL_MODE_UNDEFINED:
|
case QXL_MODE_UNDEFINED:
|
||||||
|
qxl_create_memslots(d);
|
||||||
break;
|
break;
|
||||||
case QXL_MODE_VGA:
|
case QXL_MODE_VGA:
|
||||||
qxl_create_memslots(d);
|
qxl_create_memslots(d);
|
||||||
@@ -1983,7 +2071,9 @@ static int qxl_post_load(void *opaque, int version)
|
|||||||
}
|
}
|
||||||
qxl_spice_loadvm_commands(d, cmds, out);
|
qxl_spice_loadvm_commands(d, cmds, out);
|
||||||
g_free(cmds);
|
g_free(cmds);
|
||||||
|
if (d->guest_monitors_config) {
|
||||||
|
qxl_spice_monitors_config_async(d, 1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case QXL_MODE_COMPAT:
|
case QXL_MODE_COMPAT:
|
||||||
/* note: no need to call qxl_create_memslots, qxl_set_mode
|
/* note: no need to call qxl_create_memslots, qxl_set_mode
|
||||||
@@ -1996,6 +2086,14 @@ static int qxl_post_load(void *opaque, int version)
|
|||||||
|
|
||||||
#define QXL_SAVE_VERSION 21
|
#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 = {
|
static VMStateDescription qxl_memslot = {
|
||||||
.name = "qxl-memslot",
|
.name = "qxl-memslot",
|
||||||
.version_id = QXL_SAVE_VERSION,
|
.version_id = QXL_SAVE_VERSION,
|
||||||
@@ -2026,6 +2124,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 = {
|
static VMStateDescription qxl_vmstate = {
|
||||||
.name = "qxl",
|
.name = "qxl",
|
||||||
.version_id = QXL_SAVE_VERSION,
|
.version_id = QXL_SAVE_VERSION,
|
||||||
@@ -2033,7 +2141,7 @@ static VMStateDescription qxl_vmstate = {
|
|||||||
.pre_save = qxl_pre_save,
|
.pre_save = qxl_pre_save,
|
||||||
.pre_load = qxl_pre_load,
|
.pre_load = qxl_pre_load,
|
||||||
.post_load = qxl_post_load,
|
.post_load = qxl_post_load,
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
|
VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
|
||||||
VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
|
VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
|
||||||
VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
|
VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
|
||||||
@@ -2052,6 +2160,14 @@ static VMStateDescription qxl_vmstate = {
|
|||||||
VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
|
VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
|
.subsections = (VMStateSubsection[]) {
|
||||||
|
{
|
||||||
|
.vmsd = &qxl_vmstate_monitors_config,
|
||||||
|
.needed = qxl_monitors_config_needed,
|
||||||
|
}, {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static Property qxl_properties[] = {
|
static Property qxl_properties[] = {
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ typedef struct PCIQXLDevice {
|
|||||||
} guest_surfaces;
|
} guest_surfaces;
|
||||||
QXLPHYSICAL guest_cursor;
|
QXLPHYSICAL guest_cursor;
|
||||||
|
|
||||||
|
QXLPHYSICAL guest_monitors_config;
|
||||||
|
|
||||||
QemuMutex track_lock;
|
QemuMutex track_lock;
|
||||||
|
|
||||||
/* thread signaling */
|
/* thread signaling */
|
||||||
@@ -128,7 +130,12 @@ typedef struct PCIQXLDevice {
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} 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
|
#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
|
||||||
|
#endif
|
||||||
|
|
||||||
/* qxl.c */
|
/* qxl.c */
|
||||||
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
|
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
|
||||||
|
|||||||
+2
-2
@@ -284,8 +284,8 @@ static void s390_init(ram_addr_t my_ram_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* we have to overwrite values in the kernel image, which are "rom" */
|
/* we have to overwrite values in the kernel image, which are "rom" */
|
||||||
memcpy(rom_ptr(INITRD_PARM_START), &initrd_offset, 8);
|
stq_p(rom_ptr(INITRD_PARM_START), initrd_offset);
|
||||||
memcpy(rom_ptr(INITRD_PARM_SIZE), &initrd_size, 8);
|
stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rom_ptr(KERN_PARM_AREA)) {
|
if (rom_ptr(KERN_PARM_AREA)) {
|
||||||
|
|||||||
+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.
|
* is actually implemented, but we're good enough.
|
||||||
*/
|
*/
|
||||||
outbuf[2] = 5;
|
outbuf[2] = 5;
|
||||||
outbuf[3] = 2; /* Format 2 */
|
outbuf[3] = 2 | 0x10; /* Format 2, HiSup */
|
||||||
|
|
||||||
if (buflen > 36) {
|
if (buflen > 36) {
|
||||||
outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
|
outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
|
||||||
@@ -1449,6 +1449,22 @@ invalid_field:
|
|||||||
return;
|
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 {
|
typedef struct UnmapCBData {
|
||||||
SCSIDiskReq *r;
|
SCSIDiskReq *r;
|
||||||
uint8_t *inbuf;
|
uint8_t *inbuf;
|
||||||
@@ -1473,8 +1489,7 @@ static void scsi_unmap_complete(void *opaque, int ret)
|
|||||||
if (data->count > 0 && !r->req.io_canceled) {
|
if (data->count > 0 && !r->req.io_canceled) {
|
||||||
sector_num = ldq_be_p(&data->inbuf[0]);
|
sector_num = ldq_be_p(&data->inbuf[0]);
|
||||||
nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
|
nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
|
||||||
if (sector_num > sector_num + nb_sectors ||
|
if (!check_lba_range(s, sector_num, nb_sectors)) {
|
||||||
sector_num + nb_sectors - 1 > s->qdev.max_lba) {
|
|
||||||
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
||||||
goto done;
|
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));
|
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors ||
|
if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
|
||||||
r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) {
|
|
||||||
goto illegal_lba;
|
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) {
|
if (r->req.cmd.buf[1] & 0xe0) {
|
||||||
goto illegal_request;
|
goto illegal_request;
|
||||||
}
|
}
|
||||||
if (r->req.cmd.lba > r->req.cmd.lba + len ||
|
if (!check_lba_range(s, r->req.cmd.lba, len)) {
|
||||||
r->req.cmd.lba + len - 1 > s->qdev.max_lba) {
|
|
||||||
goto illegal_lba;
|
goto illegal_lba;
|
||||||
}
|
}
|
||||||
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
|
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) {
|
if (r->req.cmd.buf[1] & 0xe0) {
|
||||||
goto illegal_request;
|
goto illegal_request;
|
||||||
}
|
}
|
||||||
if (r->req.cmd.lba > r->req.cmd.lba + len ||
|
if (!check_lba_range(s, r->req.cmd.lba, len)) {
|
||||||
r->req.cmd.lba + len - 1 > s->qdev.max_lba) {
|
|
||||||
goto illegal_lba;
|
goto illegal_lba;
|
||||||
}
|
}
|
||||||
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
|
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
|
||||||
|
|||||||
@@ -1407,7 +1407,7 @@ static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
|
|||||||
|
|
||||||
DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n",
|
DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n",
|
||||||
(unsigned long long) addr, len);
|
(unsigned long long) addr, len);
|
||||||
if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) {
|
if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
|
||||||
fprintf(stderr, "sd_blk_read: read error on host side\n");
|
fprintf(stderr, "sd_blk_read: read error on host side\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1415,7 +1415,7 @@ static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
|
|||||||
if (end > (addr & ~511) + 512) {
|
if (end > (addr & ~511) + 512) {
|
||||||
memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511));
|
memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511));
|
||||||
|
|
||||||
if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) {
|
if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) < 0) {
|
||||||
fprintf(stderr, "sd_blk_read: read error on host side\n");
|
fprintf(stderr, "sd_blk_read: read error on host side\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1429,29 +1429,31 @@ static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
|
|||||||
uint64_t end = addr + len;
|
uint64_t end = addr + len;
|
||||||
|
|
||||||
if ((addr & 511) || len < 512)
|
if ((addr & 511) || len < 512)
|
||||||
if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) {
|
if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
|
||||||
fprintf(stderr, "sd_blk_write: read error on host side\n");
|
fprintf(stderr, "sd_blk_write: read error on host side\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end > (addr & ~511) + 512) {
|
if (end > (addr & ~511) + 512) {
|
||||||
memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511));
|
memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511));
|
||||||
if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1) {
|
if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
|
||||||
fprintf(stderr, "sd_blk_write: write error on host side\n");
|
fprintf(stderr, "sd_blk_write: write error on host side\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) {
|
if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) < 0) {
|
||||||
fprintf(stderr, "sd_blk_write: read error on host side\n");
|
fprintf(stderr, "sd_blk_write: read error on host side\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511);
|
memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511);
|
||||||
if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) == -1)
|
if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) < 0) {
|
||||||
fprintf(stderr, "sd_blk_write: write error on host side\n");
|
fprintf(stderr, "sd_blk_write: write error on host side\n");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(sd->buf + (addr & 511), sd->data, len);
|
memcpy(sd->buf + (addr & 511), sd->data, len);
|
||||||
if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1)
|
if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
|
||||||
fprintf(stderr, "sd_blk_write: write error on host side\n");
|
fprintf(stderr, "sd_blk_write: write error on host side\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -556,7 +556,12 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
|
|||||||
|
|
||||||
static void emulate_spapr_hypercall(CPUPPCState *env)
|
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)
|
static void spapr_reset(void *opaque)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "dyngen-exec.h"
|
|
||||||
#include "qemu-char.h"
|
#include "qemu-char.h"
|
||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
#include "qemu-char.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 spapr_hypercall(CPUPPCState *env, target_ulong opcode,
|
||||||
target_ulong *args)
|
target_ulong *args)
|
||||||
{
|
{
|
||||||
if (msr_pr) {
|
|
||||||
hcall_dprintf("Hypercall made with MSR[PR]=1\n");
|
|
||||||
return H_PRIVILEGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((opcode <= MAX_HCALL_OPCODE)
|
if ((opcode <= MAX_HCALL_OPCODE)
|
||||||
&& ((opcode & 0x3) == 0)) {
|
&& ((opcode & 0x3) == 0)) {
|
||||||
spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
|
spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
|
||||||
|
|||||||
@@ -177,13 +177,13 @@ struct srp_tsk_mgmt {
|
|||||||
uint8_t reserved1[6];
|
uint8_t reserved1[6];
|
||||||
uint64_t tag;
|
uint64_t tag;
|
||||||
uint8_t reserved2[4];
|
uint8_t reserved2[4];
|
||||||
uint64_t lun QEMU_PACKED;
|
uint64_t lun;
|
||||||
uint8_t reserved3[2];
|
uint8_t reserved3[2];
|
||||||
uint8_t tsk_mgmt_func;
|
uint8_t tsk_mgmt_func;
|
||||||
uint8_t reserved4;
|
uint8_t reserved4;
|
||||||
uint64_t task_tag;
|
uint64_t task_tag;
|
||||||
uint8_t reserved5[8];
|
uint8_t reserved5[8];
|
||||||
};
|
} QEMU_PACKED;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need the packed attribute because the SRP spec only aligns the
|
* 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;
|
uint8_t data_in_desc_cnt;
|
||||||
uint64_t tag;
|
uint64_t tag;
|
||||||
uint8_t reserved2[4];
|
uint8_t reserved2[4];
|
||||||
uint64_t lun QEMU_PACKED;
|
uint64_t lun;
|
||||||
uint8_t reserved3;
|
uint8_t reserved3;
|
||||||
uint8_t task_attr;
|
uint8_t task_attr;
|
||||||
uint8_t reserved4;
|
uint8_t reserved4;
|
||||||
uint8_t add_cdb_len;
|
uint8_t add_cdb_len;
|
||||||
uint8_t cdb[16];
|
uint8_t cdb[16];
|
||||||
uint8_t add_data[0];
|
uint8_t add_data[0];
|
||||||
};
|
} QEMU_PACKED;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SRP_RSP_FLAG_RSPVALID = 1 << 0,
|
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);
|
uint16_t raw);
|
||||||
int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
|
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);
|
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_attach(USBPort *port);
|
||||||
void usb_detach(USBPort *port);
|
void usb_detach(USBPort *port);
|
||||||
|
|||||||
@@ -585,6 +585,13 @@ USBDevice *usbdevice_create(const char *cmdline)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!bus) {
|
||||||
|
error_report("Error: no usb bus to attach usbdevice %s, "
|
||||||
|
"please try -machine usb=on and check that "
|
||||||
|
"the machine model supports USB", driver);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!f->usbdevice_init) {
|
if (!f->usbdevice_init) {
|
||||||
if (*params) {
|
if (*params) {
|
||||||
error_report("usbdevice %s accepts no params", driver);
|
error_report("usbdevice %s accepts no params", driver);
|
||||||
|
|||||||
+20
-3
@@ -398,9 +398,11 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
|
|||||||
* When pipelining is enabled usb-devices must always return async,
|
* When pipelining is enabled usb-devices must always return async,
|
||||||
* otherwise packets can complete out of order!
|
* otherwise packets can complete out of order!
|
||||||
*/
|
*/
|
||||||
assert(!p->ep->pipeline);
|
assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue));
|
||||||
p->result = ret;
|
if (ret != USB_RET_NAK) {
|
||||||
usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
p->result = ret;
|
||||||
|
usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = USB_RET_ASYNC;
|
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);
|
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
|
||||||
uep->pipeline = enabled;
|
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 = {
|
static const USBDescDevice desc_device = {
|
||||||
.bcdUSB = 0x0200,
|
.bcdUSB = 0x0100,
|
||||||
.bMaxPacketSize0 = 64,
|
.bMaxPacketSize0 = 64,
|
||||||
.bNumConfigurations = 1,
|
.bNumConfigurations = 1,
|
||||||
.confs = (USBDescConfig[]) {
|
.confs = (USBDescConfig[]) {
|
||||||
|
|||||||
+33
-16
@@ -1001,6 +1001,13 @@ static int rndis_keepalive_response(USBNetState *s,
|
|||||||
return 0;
|
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)
|
static int rndis_parse(USBNetState *s, uint8_t *data, int length)
|
||||||
{
|
{
|
||||||
uint32_t msg_type;
|
uint32_t msg_type;
|
||||||
@@ -1025,7 +1032,8 @@ static int rndis_parse(USBNetState *s, uint8_t *data, int length)
|
|||||||
|
|
||||||
case RNDIS_RESET_MSG:
|
case RNDIS_RESET_MSG:
|
||||||
rndis_clear_responsequeue(s);
|
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);
|
return rndis_reset_response(s, (rndis_reset_msg_type *) data);
|
||||||
|
|
||||||
case RNDIS_KEEPALIVE_MSG:
|
case RNDIS_KEEPALIVE_MSG:
|
||||||
@@ -1135,7 +1143,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
|
|||||||
int ret = USB_RET_NAK;
|
int ret = USB_RET_NAK;
|
||||||
|
|
||||||
if (s->in_ptr > s->in_len) {
|
if (s->in_ptr > s->in_len) {
|
||||||
s->in_ptr = s->in_len = 0;
|
usb_net_reset_in_buf(s);
|
||||||
ret = USB_RET_NAK;
|
ret = USB_RET_NAK;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1152,7 +1160,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
|
|||||||
if (s->in_ptr >= s->in_len &&
|
if (s->in_ptr >= s->in_len &&
|
||||||
(is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
|
(is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
|
||||||
/* no short packet necessary */
|
/* no short packet necessary */
|
||||||
s->in_ptr = s->in_len = 0;
|
usb_net_reset_in_buf(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TRAFFIC_DEBUG
|
#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)
|
static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||||
{
|
{
|
||||||
USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
|
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)) {
|
if (is_rndis(s)) {
|
||||||
msg = (struct rndis_packet_msg_type *) s->in_buf;
|
|
||||||
if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
|
if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf))
|
total_size += sizeof(struct rndis_packet_msg_type);
|
||||||
return -1;
|
}
|
||||||
|
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));
|
memset(msg, 0, sizeof(struct rndis_packet_msg_type));
|
||||||
msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
|
msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
|
||||||
msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type));
|
msg->MessageLength = cpu_to_le32(size + sizeof(*msg));
|
||||||
msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8);
|
msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8);
|
||||||
msg->DataLength = cpu_to_le32(size);
|
msg->DataLength = cpu_to_le32(size);
|
||||||
/* msg->OOBDataOffset;
|
/* msg->OOBDataOffset;
|
||||||
* msg->OOBDataLength;
|
* msg->OOBDataLength;
|
||||||
@@ -1273,14 +1293,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz
|
|||||||
* msg->VcHandle;
|
* msg->VcHandle;
|
||||||
* msg->Reserved;
|
* msg->Reserved;
|
||||||
*/
|
*/
|
||||||
memcpy(msg + 1, buf, size);
|
in_buf += sizeof(*msg);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(in_buf, buf, size);
|
||||||
|
s->in_len = total_size;
|
||||||
s->in_ptr = 0;
|
s->in_ptr = 0;
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -113,7 +113,7 @@ enum {
|
|||||||
static const USBDescStrings desc_strings = {
|
static const USBDescStrings desc_strings = {
|
||||||
[STR_MANUFACTURER] = "QEMU",
|
[STR_MANUFACTURER] = "QEMU",
|
||||||
[STR_PRODUCT_SERIAL] = "QEMU USB SERIAL",
|
[STR_PRODUCT_SERIAL] = "QEMU USB SERIAL",
|
||||||
[STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE",
|
[STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE",
|
||||||
[STR_SERIALNUMBER] = "1",
|
[STR_SERIALNUMBER] = "1",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+256
-153
@@ -2,6 +2,11 @@
|
|||||||
* QEMU USB EHCI Emulation
|
* QEMU USB EHCI Emulation
|
||||||
*
|
*
|
||||||
* Copyright(c) 2008 Emutex Ltd. (address@hidden)
|
* 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
|
* EHCI project was started by Mark Burkley, with contributions by
|
||||||
* Niels de Vos. David S. Ahern continued working on it. Kevin Wolf,
|
* Niels de Vos. David S. Ahern continued working on it. Kevin Wolf,
|
||||||
@@ -29,6 +34,7 @@
|
|||||||
#include "monitor.h"
|
#include "monitor.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
|
#include "sysemu.h"
|
||||||
|
|
||||||
#define EHCI_DEBUG 0
|
#define EHCI_DEBUG 0
|
||||||
|
|
||||||
@@ -134,6 +140,7 @@
|
|||||||
#define NB_PORTS 6 // Number of downstream ports
|
#define NB_PORTS 6 // Number of downstream ports
|
||||||
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
|
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
|
||||||
#define MAX_QH 100 // Max allowable queue heads in a chain
|
#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
|
/* Internal periodic / asynchronous schedule state machine states
|
||||||
*/
|
*/
|
||||||
@@ -340,6 +347,7 @@ typedef struct EHCIState EHCIState;
|
|||||||
|
|
||||||
enum async_state {
|
enum async_state {
|
||||||
EHCI_ASYNC_NONE = 0,
|
EHCI_ASYNC_NONE = 0,
|
||||||
|
EHCI_ASYNC_INITIALIZED,
|
||||||
EHCI_ASYNC_INFLIGHT,
|
EHCI_ASYNC_INFLIGHT,
|
||||||
EHCI_ASYNC_FINISHED,
|
EHCI_ASYNC_FINISHED,
|
||||||
};
|
};
|
||||||
@@ -365,7 +373,6 @@ struct EHCIQueue {
|
|||||||
uint32_t seen;
|
uint32_t seen;
|
||||||
uint64_t ts;
|
uint64_t ts;
|
||||||
int async;
|
int async;
|
||||||
int revalidate;
|
|
||||||
|
|
||||||
/* cached data from guest - needs to be flushed
|
/* cached data from guest - needs to be flushed
|
||||||
* when guest removes an entry (doorbell, handshake sequence)
|
* when guest removes an entry (doorbell, handshake sequence)
|
||||||
@@ -384,6 +391,9 @@ struct EHCIState {
|
|||||||
USBBus bus;
|
USBBus bus;
|
||||||
qemu_irq irq;
|
qemu_irq irq;
|
||||||
MemoryRegion mem;
|
MemoryRegion mem;
|
||||||
|
MemoryRegion mem_caps;
|
||||||
|
MemoryRegion mem_opreg;
|
||||||
|
MemoryRegion mem_ports;
|
||||||
int companion_count;
|
int companion_count;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
@@ -393,10 +403,10 @@ struct EHCIState {
|
|||||||
* EHCI spec version 1.0 Section 2.3
|
* EHCI spec version 1.0 Section 2.3
|
||||||
* Host Controller Operational Registers
|
* Host Controller Operational Registers
|
||||||
*/
|
*/
|
||||||
|
uint8_t caps[OPREGBASE];
|
||||||
union {
|
union {
|
||||||
uint8_t mmio[MMIO_SIZE];
|
uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)];
|
||||||
struct {
|
struct {
|
||||||
uint8_t cap[OPREGBASE];
|
|
||||||
uint32_t usbcmd;
|
uint32_t usbcmd;
|
||||||
uint32_t usbsts;
|
uint32_t usbsts;
|
||||||
uint32_t usbintr;
|
uint32_t usbintr;
|
||||||
@@ -406,9 +416,9 @@ struct EHCIState {
|
|||||||
uint32_t asynclistaddr;
|
uint32_t asynclistaddr;
|
||||||
uint32_t notused[9];
|
uint32_t notused[9];
|
||||||
uint32_t configflag;
|
uint32_t configflag;
|
||||||
uint32_t portsc[NB_PORTS];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
uint32_t portsc[NB_PORTS];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal states, shadow registers, etc
|
* Internal states, shadow registers, etc
|
||||||
@@ -466,25 +476,18 @@ static const char *ehci_state_names[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const char *ehci_mmio_names[] = {
|
static const char *ehci_mmio_names[] = {
|
||||||
[CAPLENGTH] = "CAPLENGTH",
|
|
||||||
[HCIVERSION] = "HCIVERSION",
|
|
||||||
[HCSPARAMS] = "HCSPARAMS",
|
|
||||||
[HCCPARAMS] = "HCCPARAMS",
|
|
||||||
[USBCMD] = "USBCMD",
|
[USBCMD] = "USBCMD",
|
||||||
[USBSTS] = "USBSTS",
|
[USBSTS] = "USBSTS",
|
||||||
[USBINTR] = "USBINTR",
|
[USBINTR] = "USBINTR",
|
||||||
[FRINDEX] = "FRINDEX",
|
[FRINDEX] = "FRINDEX",
|
||||||
[PERIODICLISTBASE] = "P-LIST BASE",
|
[PERIODICLISTBASE] = "P-LIST BASE",
|
||||||
[ASYNCLISTADDR] = "A-LIST ADDR",
|
[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",
|
[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)
|
static const char *nr2str(const char **n, size_t len, uint32_t nr)
|
||||||
{
|
{
|
||||||
if (nr < len && n[nr] != NULL) {
|
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)
|
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)
|
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));
|
(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)
|
static inline bool ehci_enabled(EHCIState *s)
|
||||||
{
|
{
|
||||||
return s->usbcmd & USBCMD_RUNSTOP;
|
return s->usbcmd & USBCMD_RUNSTOP;
|
||||||
@@ -740,9 +750,25 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
|
|||||||
|
|
||||||
static void ehci_free_packet(EHCIPacket *p)
|
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");
|
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) {
|
if (p->async == EHCI_ASYNC_INFLIGHT) {
|
||||||
usb_cancel_packet(&p->packet);
|
usb_cancel_packet(&p->packet);
|
||||||
|
usb_packet_unmap(&p->packet, &p->sgl);
|
||||||
|
qemu_sglist_destroy(&p->sgl);
|
||||||
}
|
}
|
||||||
QTAILQ_REMOVE(&p->queue->packets, p, next);
|
QTAILQ_REMOVE(&p->queue->packets, p, next);
|
||||||
usb_packet_cleanup(&p->packet);
|
usb_packet_cleanup(&p->packet);
|
||||||
@@ -766,27 +792,45 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
|
|||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ehci_cancel_queue(EHCIQueue *q)
|
static int ehci_cancel_queue(EHCIQueue *q)
|
||||||
{
|
{
|
||||||
EHCIPacket *p;
|
EHCIPacket *p;
|
||||||
|
int packets = 0;
|
||||||
|
|
||||||
p = QTAILQ_FIRST(&q->packets);
|
p = QTAILQ_FIRST(&q->packets);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_usb_ehci_queue_action(q, "cancel");
|
trace_usb_ehci_queue_action(q, "cancel");
|
||||||
do {
|
do {
|
||||||
ehci_free_packet(p);
|
ehci_free_packet(p);
|
||||||
|
packets++;
|
||||||
} while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
|
} 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;
|
EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
|
||||||
|
int cancelled;
|
||||||
|
|
||||||
trace_usb_ehci_queue_action(q, "free");
|
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);
|
QTAILQ_REMOVE(head, q, next);
|
||||||
g_free(q);
|
g_free(q);
|
||||||
}
|
}
|
||||||
@@ -805,20 +849,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
|
|||||||
return NULL;
|
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)
|
static void ehci_queues_rip_unused(EHCIState *ehci, int async)
|
||||||
{
|
{
|
||||||
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
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;
|
uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
|
||||||
EHCIQueue *q, *tmp;
|
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) {
|
if (ehci->last_run_ns < q->ts + maxage) {
|
||||||
continue;
|
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) {
|
if (q->dev != dev) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ehci_free_queue(q);
|
ehci_free_queue(q, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ehci_queues_rip_all(EHCIState *ehci, int async)
|
static void ehci_queues_rip_all(EHCIState *ehci, int async)
|
||||||
{
|
{
|
||||||
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
||||||
|
const char *warn = async ? "guest stopped busy async schedule" : NULL;
|
||||||
EHCIQueue *q, *tmp;
|
EHCIQueue *q, *tmp;
|
||||||
|
|
||||||
QTAILQ_FOREACH_SAFE(q, head, next, 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->companion_count++;
|
||||||
s->mmio[0x05] = (s->companion_count << 4) | portcount;
|
s->caps[0x05] = (s->companion_count << 4) | portcount;
|
||||||
|
|
||||||
return 0;
|
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->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
|
||||||
s->usbsts = USBSTS_HALT;
|
s->usbsts = USBSTS_HALT;
|
||||||
@@ -1051,50 +1099,35 @@ static void ehci_reset(void *opaque)
|
|||||||
qemu_bh_cancel(s->async_bh);
|
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;
|
EHCIState *s = ptr;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
|
||||||
val = s->mmio[addr];
|
val = s->opreg[addr >> 2];
|
||||||
|
trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val);
|
||||||
return 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;
|
EHCIState *s = ptr;
|
||||||
uint32_t val;
|
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;
|
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)
|
static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
|
||||||
{
|
{
|
||||||
USBDevice *dev = s->ports[port].dev;
|
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 *portsc = &s->portsc[port];
|
||||||
|
uint32_t old = *portsc;
|
||||||
USBDevice *dev = s->ports[port].dev;
|
USBDevice *dev = s->ports[port].dev;
|
||||||
|
|
||||||
|
trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val);
|
||||||
|
|
||||||
/* Clear rwc bits */
|
/* Clear rwc bits */
|
||||||
*portsc &= ~(val & PORTSC_RWC_MASK);
|
*portsc &= ~(val & PORTSC_RWC_MASK);
|
||||||
/* The guest may clear, but not set the PED bit */
|
/* 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 &= ~PORTSC_RO_MASK;
|
||||||
*portsc |= val;
|
*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;
|
EHCIState *s = ptr;
|
||||||
uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);
|
uint32_t *mmio = s->opreg + (addr >> 2);
|
||||||
uint32_t old = *mmio;
|
uint32_t old = *mmio;
|
||||||
int i;
|
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 */
|
switch (addr + OPREGBASE) {
|
||||||
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) {
|
|
||||||
case USBCMD:
|
case USBCMD:
|
||||||
if (val & USBCMD_HCRESET) {
|
if (val & USBCMD_HCRESET) {
|
||||||
ehci_reset(s);
|
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 */
|
/* not supporting dynamic frame list size at the moment */
|
||||||
if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
|
if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
|
||||||
fprintf(stderr, "attempt to set frame list size -- value %d\n",
|
fprintf(stderr, "attempt to set frame list size -- value %d\n",
|
||||||
val & USBCMD_FLS);
|
(int)val & USBCMD_FLS);
|
||||||
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;
|
s->async_stepdown = 0;
|
||||||
qemu_bh_schedule(s->async_bh);
|
qemu_bh_schedule(s->async_bh);
|
||||||
|
trace_usb_ehci_doorbell_ring();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) !=
|
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;
|
*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 != NULL);
|
||||||
assert(p->qtdaddr == q->qtdaddr);
|
assert(p->qtdaddr == q->qtdaddr);
|
||||||
assert(p->async != EHCI_ASYNC_INFLIGHT);
|
assert(p->async == EHCI_ASYNC_INITIALIZED ||
|
||||||
p->async = EHCI_ASYNC_NONE;
|
p->async == EHCI_ASYNC_FINISHED);
|
||||||
|
|
||||||
DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
|
DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
|
||||||
q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
|
q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
|
||||||
@@ -1481,10 +1502,6 @@ static void ehci_execute_complete(EHCIQueue *q)
|
|||||||
assert(0);
|
assert(0);
|
||||||
break;
|
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 {
|
} else {
|
||||||
// TODO check 4.12 for splits
|
// TODO check 4.12 for splits
|
||||||
|
|
||||||
@@ -1500,6 +1517,7 @@ static void ehci_execute_complete(EHCIQueue *q)
|
|||||||
ehci_finish_transfer(q, p->usb_status);
|
ehci_finish_transfer(q, p->usb_status);
|
||||||
usb_packet_unmap(&p->packet, &p->sgl);
|
usb_packet_unmap(&p->packet, &p->sgl);
|
||||||
qemu_sglist_destroy(&p->sgl);
|
qemu_sglist_destroy(&p->sgl);
|
||||||
|
p->async = EHCI_ASYNC_NONE;
|
||||||
|
|
||||||
q->qh.token ^= QTD_TOKEN_DTOGGLE;
|
q->qh.token ^= QTD_TOKEN_DTOGGLE;
|
||||||
q->qh.token &= ~QTD_TOKEN_ACTIVE;
|
q->qh.token &= ~QTD_TOKEN_ACTIVE;
|
||||||
@@ -1517,6 +1535,9 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
|||||||
int ret;
|
int ret;
|
||||||
int endp;
|
int endp;
|
||||||
|
|
||||||
|
assert(p->async == EHCI_ASYNC_NONE ||
|
||||||
|
p->async == EHCI_ASYNC_INITIALIZED);
|
||||||
|
|
||||||
if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
|
if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
|
||||||
fprintf(stderr, "Attempting to execute inactive qtd\n");
|
fprintf(stderr, "Attempting to execute inactive qtd\n");
|
||||||
return USB_RET_PROCERR;
|
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;
|
p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
|
||||||
if (p->tbytes > BUFF_SIZE) {
|
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;
|
return USB_RET_PROCERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1544,15 +1566,18 @@ static int ehci_execute(EHCIPacket *p, const char *action)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ehci_init_transfer(p) != 0) {
|
|
||||||
return USB_RET_PROCERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
|
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
|
||||||
ep = usb_ep_get(p->queue->dev, p->pid, endp);
|
ep = usb_ep_get(p->queue->dev, p->pid, endp);
|
||||||
|
|
||||||
usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
|
if (p->async == EHCI_ASYNC_NONE) {
|
||||||
usb_packet_map(&p->packet, &p->sgl);
|
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);
|
trace_usb_ehci_packet_action(p->queue, p, action);
|
||||||
ret = usb_handle_packet(p->queue->dev, &p->packet);
|
ret = usb_handle_packet(p->queue->dev, &p->packet);
|
||||||
@@ -1771,7 +1796,7 @@ out:
|
|||||||
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||||
{
|
{
|
||||||
EHCIPacket *p;
|
EHCIPacket *p;
|
||||||
uint32_t entry, devaddr;
|
uint32_t entry, devaddr, endp;
|
||||||
EHCIQueue *q;
|
EHCIQueue *q;
|
||||||
EHCIqh qh;
|
EHCIqh qh;
|
||||||
|
|
||||||
@@ -1792,26 +1817,26 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
|||||||
|
|
||||||
get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
||||||
(uint32_t *) &qh, sizeof(EHCIqh) >> 2);
|
(uint32_t *) &qh, sizeof(EHCIqh) >> 2);
|
||||||
if (q->revalidate && (q->qh.epchar != qh.epchar ||
|
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh);
|
||||||
q->qh.epcap != qh.epcap ||
|
|
||||||
q->qh.current_qtd != qh.current_qtd)) {
|
/*
|
||||||
ehci_free_queue(q);
|
* The overlay area of the qh should never be changed by the guest,
|
||||||
q = ehci_alloc_queue(ehci, entry, async);
|
* except when idle, in which case the reset is a nop.
|
||||||
q->seen++;
|
*/
|
||||||
|
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;
|
p = NULL;
|
||||||
}
|
}
|
||||||
q->qh = qh;
|
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) {
|
if (q->dev == NULL) {
|
||||||
q->dev = ehci_find_device(q->ehci, devaddr);
|
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.next) && (p->qtd.next != qtd.next)) ||
|
||||||
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
|
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
|
||||||
p->qtd.bufptr[0] != qtd.bufptr[0]) {
|
p->qtd.bufptr[0] != qtd.bufptr[0]) {
|
||||||
/* guest bug: guest updated active QH or qTD underneath us */
|
|
||||||
ehci_cancel_queue(q);
|
ehci_cancel_queue(q);
|
||||||
|
ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD");
|
||||||
p = NULL;
|
p = NULL;
|
||||||
} else {
|
} else {
|
||||||
p->qtd = qtd;
|
p->qtd = qtd;
|
||||||
@@ -1989,15 +2014,22 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
|
|||||||
} else if (p != NULL) {
|
} else if (p != NULL) {
|
||||||
switch (p->async) {
|
switch (p->async) {
|
||||||
case EHCI_ASYNC_NONE:
|
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) */
|
/* Previously nacked packet (likely interrupt ep) */
|
||||||
ehci_set_state(q->ehci, q->async, EST_EXECUTE);
|
ehci_set_state(q->ehci, q->async, EST_EXECUTE);
|
||||||
break;
|
break;
|
||||||
case EHCI_ASYNC_INFLIGHT:
|
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);
|
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
||||||
break;
|
break;
|
||||||
case EHCI_ASYNC_FINISHED:
|
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);
|
ehci_set_state(q->ehci, q->async, EST_EXECUTING);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2028,7 +2060,7 @@ static int ehci_state_horizqh(EHCIQueue *q)
|
|||||||
return again;
|
return again;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ehci_fill_queue(EHCIPacket *p)
|
static int ehci_fill_queue(EHCIPacket *p)
|
||||||
{
|
{
|
||||||
EHCIQueue *q = p->queue;
|
EHCIQueue *q = p->queue;
|
||||||
EHCIqtd qtd = p->qtd;
|
EHCIqtd qtd = p->qtd;
|
||||||
@@ -2052,9 +2084,13 @@ static void ehci_fill_queue(EHCIPacket *p)
|
|||||||
p->qtdaddr = qtdaddr;
|
p->qtdaddr = qtdaddr;
|
||||||
p->qtd = qtd;
|
p->qtd = qtd;
|
||||||
p->usb_status = ehci_execute(p, "queue");
|
p->usb_status = ehci_execute(p, "queue");
|
||||||
|
if (p->usb_status == USB_RET_PROCERR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
assert(p->usb_status == USB_RET_ASYNC);
|
assert(p->usb_status == USB_RET_ASYNC);
|
||||||
p->async = EHCI_ASYNC_INFLIGHT;
|
p->async = EHCI_ASYNC_INFLIGHT;
|
||||||
}
|
}
|
||||||
|
return p->usb_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ehci_state_execute(EHCIQueue *q)
|
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");
|
trace_usb_ehci_packet_action(p->queue, p, "async");
|
||||||
p->async = EHCI_ASYNC_INFLIGHT;
|
p->async = EHCI_ASYNC_INFLIGHT;
|
||||||
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
|
||||||
again = 1;
|
again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
|
||||||
ehci_fill_queue(p);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2310,8 +2345,8 @@ static void ehci_advance_async_state(EHCIState *ehci)
|
|||||||
*/
|
*/
|
||||||
if (ehci->usbcmd & USBCMD_IAAD) {
|
if (ehci->usbcmd & USBCMD_IAAD) {
|
||||||
/* Remove all unseen qhs from the async qhs queue */
|
/* Remove all unseen qhs from the async qhs queue */
|
||||||
ehci_queues_tag_unused_async(ehci);
|
ehci_queues_rip_unseen(ehci, async);
|
||||||
DPRINTF("ASYNC: doorbell request acknowledged\n");
|
trace_usb_ehci_doorbell_ack();
|
||||||
ehci->usbcmd &= ~USBCMD_IAAD;
|
ehci->usbcmd &= ~USBCMD_IAAD;
|
||||||
ehci_raise_irq(ehci, USBSTS_IAA);
|
ehci_raise_irq(ehci, USBSTS_IAA);
|
||||||
}
|
}
|
||||||
@@ -2392,7 +2427,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames)
|
|||||||
if (ehci->frindex == 0x00004000) {
|
if (ehci->frindex == 0x00004000) {
|
||||||
ehci_raise_irq(ehci, USBSTS_FLR);
|
ehci_raise_irq(ehci, USBSTS_FLR);
|
||||||
ehci->frindex = 0;
|
ehci->frindex = 0;
|
||||||
if (ehci->usbsts_frindex > 0x00004000) {
|
if (ehci->usbsts_frindex >= 0x00004000) {
|
||||||
ehci->usbsts_frindex -= 0x00004000;
|
ehci->usbsts_frindex -= 0x00004000;
|
||||||
} else {
|
} else {
|
||||||
ehci->usbsts_frindex = 0;
|
ehci->usbsts_frindex = 0;
|
||||||
@@ -2427,6 +2462,19 @@ static void ehci_frame_timer(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < frames; i++) {
|
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_update_frindex(ehci, 1);
|
||||||
ehci_advance_periodic_state(ehci);
|
ehci_advance_periodic_state(ehci);
|
||||||
ehci->last_run_ns += FRAME_TIMER_NS;
|
ehci->last_run_ns += FRAME_TIMER_NS;
|
||||||
@@ -2466,11 +2514,28 @@ static void ehci_async_bh(void *opaque)
|
|||||||
ehci_advance_async_state(ehci);
|
ehci_advance_async_state(ehci);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps ehci_mem_ops = {
|
static const MemoryRegionOps ehci_mmio_caps_ops = {
|
||||||
.old_mmio = {
|
.read = ehci_caps_read,
|
||||||
.read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl },
|
.valid.min_access_size = 1,
|
||||||
.write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel },
|
.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,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2508,6 +2573,32 @@ static int usb_ehci_post_load(void *opaque, int version_id)
|
|||||||
return 0;
|
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 = {
|
static const VMStateDescription vmstate_ehci = {
|
||||||
.name = "ehci",
|
.name = "ehci",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
@@ -2627,19 +2718,19 @@ static int usb_ehci_initfn(PCIDevice *dev)
|
|||||||
pci_conf[0x6e] = 0x00;
|
pci_conf[0x6e] = 0x00;
|
||||||
pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS
|
pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS
|
||||||
|
|
||||||
// 2.2 host controller interface version
|
/* 2.2 host controller interface version */
|
||||||
s->mmio[0x00] = (uint8_t) OPREGBASE;
|
s->caps[0x00] = (uint8_t) OPREGBASE;
|
||||||
s->mmio[0x01] = 0x00;
|
s->caps[0x01] = 0x00;
|
||||||
s->mmio[0x02] = 0x00;
|
s->caps[0x02] = 0x00;
|
||||||
s->mmio[0x03] = 0x01; // HC version
|
s->caps[0x03] = 0x01; /* HC version */
|
||||||
s->mmio[0x04] = NB_PORTS; // Number of downstream ports
|
s->caps[0x04] = NB_PORTS; /* Number of downstream ports */
|
||||||
s->mmio[0x05] = 0x00; // No companion ports at present
|
s->caps[0x05] = 0x00; /* No companion ports at present */
|
||||||
s->mmio[0x06] = 0x00;
|
s->caps[0x06] = 0x00;
|
||||||
s->mmio[0x07] = 0x00;
|
s->caps[0x07] = 0x00;
|
||||||
s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable
|
s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */
|
||||||
s->mmio[0x09] = 0x68; // EECP
|
s->caps[0x09] = 0x68; /* EECP */
|
||||||
s->mmio[0x0a] = 0x00;
|
s->caps[0x0a] = 0x00;
|
||||||
s->mmio[0x0b] = 0x00;
|
s->caps[0x0b] = 0x00;
|
||||||
|
|
||||||
s->irq = s->dev.irq[3];
|
s->irq = s->dev.irq[3];
|
||||||
|
|
||||||
@@ -2657,8 +2748,20 @@ static int usb_ehci_initfn(PCIDevice *dev)
|
|||||||
usb_packet_init(&s->ipacket);
|
usb_packet_init(&s->ipacket);
|
||||||
|
|
||||||
qemu_register_reset(ehci_reset, s);
|
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);
|
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+13
-7
@@ -729,11 +729,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
|
|||||||
*int_mask |= 0x01;
|
*int_mask |= 0x01;
|
||||||
|
|
||||||
if (pid == USB_TOKEN_IN) {
|
if (pid == USB_TOKEN_IN) {
|
||||||
if (len > max_len) {
|
|
||||||
ret = USB_RET_BABBLE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
|
if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
|
||||||
*int_mask |= 0x02;
|
*int_mask |= 0x02;
|
||||||
/* short packet: do not update QH */
|
/* short packet: do not update QH */
|
||||||
@@ -831,8 +826,16 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
|
|||||||
USBEndpoint *ep;
|
USBEndpoint *ep;
|
||||||
|
|
||||||
/* Is active ? */
|
/* Is active ? */
|
||||||
if (!(td->ctrl & TD_CTRL_ACTIVE))
|
if (!(td->ctrl & TD_CTRL_ACTIVE)) {
|
||||||
|
/*
|
||||||
|
* ehci11d spec page 22: "Even if the Active bit in the TD is already
|
||||||
|
* cleared when the TD is fetched ... an IOC interrupt is generated"
|
||||||
|
*/
|
||||||
|
if (td->ctrl & TD_CTRL_IOC) {
|
||||||
|
*int_mask |= 0x01;
|
||||||
|
}
|
||||||
return TD_RESULT_NEXT_QH;
|
return TD_RESULT_NEXT_QH;
|
||||||
|
}
|
||||||
|
|
||||||
async = uhci_async_find_td(s, addr, td);
|
async = uhci_async_find_td(s, addr, td);
|
||||||
if (async) {
|
if (async) {
|
||||||
@@ -1005,6 +1008,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
|
|||||||
}
|
}
|
||||||
assert(ret == TD_RESULT_ASYNC_START);
|
assert(ret == TD_RESULT_ASYNC_START);
|
||||||
assert(int_mask == 0);
|
assert(int_mask == 0);
|
||||||
|
if (ptd.ctrl & TD_CTRL_SPD) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
plink = ptd.link;
|
plink = ptd.link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1102,7 +1108,7 @@ static void uhci_process_frame(UHCIState *s)
|
|||||||
|
|
||||||
case TD_RESULT_ASYNC_START:
|
case TD_RESULT_ASYNC_START:
|
||||||
trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
|
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);
|
uhci_fill_queue(s, &td);
|
||||||
}
|
}
|
||||||
link = curr_qh ? qh.link : td.link;
|
link = curr_qh ? qh.link : td.link;
|
||||||
|
|||||||
+80
-336
@@ -45,8 +45,6 @@
|
|||||||
#define MAXPORTS (USB2_PORTS+USB3_PORTS)
|
#define MAXPORTS (USB2_PORTS+USB3_PORTS)
|
||||||
|
|
||||||
#define TD_QUEUE 24
|
#define TD_QUEUE 24
|
||||||
#define BG_XFERS 8
|
|
||||||
#define BG_PKTS 8
|
|
||||||
|
|
||||||
/* Very pessimistic, let's hope it's enough for all cases */
|
/* Very pessimistic, let's hope it's enough for all cases */
|
||||||
#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS)
|
#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS)
|
||||||
@@ -307,26 +305,21 @@ typedef struct XHCIState XHCIState;
|
|||||||
typedef struct XHCITransfer {
|
typedef struct XHCITransfer {
|
||||||
XHCIState *xhci;
|
XHCIState *xhci;
|
||||||
USBPacket packet;
|
USBPacket packet;
|
||||||
|
QEMUSGList sgl;
|
||||||
bool running_async;
|
bool running_async;
|
||||||
bool running_retry;
|
bool running_retry;
|
||||||
bool cancelled;
|
bool cancelled;
|
||||||
bool complete;
|
bool complete;
|
||||||
bool backgrounded;
|
|
||||||
unsigned int iso_pkts;
|
unsigned int iso_pkts;
|
||||||
unsigned int slotid;
|
unsigned int slotid;
|
||||||
unsigned int epid;
|
unsigned int epid;
|
||||||
bool in_xfer;
|
bool in_xfer;
|
||||||
bool iso_xfer;
|
bool iso_xfer;
|
||||||
bool bg_xfer;
|
|
||||||
|
|
||||||
unsigned int trb_count;
|
unsigned int trb_count;
|
||||||
unsigned int trb_alloced;
|
unsigned int trb_alloced;
|
||||||
XHCITRB *trbs;
|
XHCITRB *trbs;
|
||||||
|
|
||||||
unsigned int data_length;
|
|
||||||
unsigned int data_alloced;
|
|
||||||
uint8_t *data;
|
|
||||||
|
|
||||||
TRBCCode status;
|
TRBCCode status;
|
||||||
|
|
||||||
unsigned int pkts;
|
unsigned int pkts;
|
||||||
@@ -340,14 +333,9 @@ typedef struct XHCIEPContext {
|
|||||||
unsigned int comp_xfer;
|
unsigned int comp_xfer;
|
||||||
XHCITransfer transfers[TD_QUEUE];
|
XHCITransfer transfers[TD_QUEUE];
|
||||||
XHCITransfer *retry;
|
XHCITransfer *retry;
|
||||||
bool bg_running;
|
|
||||||
bool bg_updating;
|
|
||||||
unsigned int next_bg;
|
|
||||||
XHCITransfer bg_transfers[BG_XFERS];
|
|
||||||
EPType type;
|
EPType type;
|
||||||
dma_addr_t pctx;
|
dma_addr_t pctx;
|
||||||
unsigned int max_psize;
|
unsigned int max_psize;
|
||||||
bool has_bg;
|
|
||||||
uint32_t state;
|
uint32_t state;
|
||||||
} XHCIEPContext;
|
} XHCIEPContext;
|
||||||
|
|
||||||
@@ -866,10 +854,6 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
|
|||||||
epctx->pctx = pctx;
|
epctx->pctx = pctx;
|
||||||
epctx->max_psize = ctx[1]>>16;
|
epctx->max_psize = ctx[1]>>16;
|
||||||
epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
|
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",
|
DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
|
||||||
epid/2, epid%2, epctx->max_psize);
|
epid/2, epid%2, epctx->max_psize);
|
||||||
for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
|
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;
|
t->running_retry = 0;
|
||||||
epctx->retry = NULL;
|
epctx->retry = NULL;
|
||||||
}
|
}
|
||||||
if (t->backgrounded) {
|
|
||||||
t->backgrounded = 0;
|
|
||||||
}
|
|
||||||
if (t->trbs) {
|
if (t->trbs) {
|
||||||
g_free(t->trbs);
|
g_free(t->trbs);
|
||||||
}
|
}
|
||||||
if (t->data) {
|
|
||||||
g_free(t->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
t->trbs = NULL;
|
t->trbs = NULL;
|
||||||
t->data = NULL;
|
|
||||||
t->trb_count = t->trb_alloced = 0;
|
t->trb_count = t->trb_alloced = 0;
|
||||||
t->data_length = t->data_alloced = 0;
|
|
||||||
xferi = (xferi + 1) % TD_QUEUE;
|
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;
|
return killed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1107,24 +1064,13 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
|
|||||||
return CC_SUCCESS;
|
return CC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
static int xhci_xfer_map(XHCITransfer *xfer)
|
||||||
unsigned int length, bool in_xfer, bool out_xfer,
|
|
||||||
bool report)
|
|
||||||
{
|
{
|
||||||
int i;
|
int in_xfer = (xfer->packet.pid == USB_TOKEN_IN);
|
||||||
uint32_t edtla = 0;
|
|
||||||
unsigned int transferred = 0;
|
|
||||||
unsigned int left = length;
|
|
||||||
bool reported = 0;
|
|
||||||
bool shortpkt = 0;
|
|
||||||
XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
|
|
||||||
XHCIState *xhci = xfer->xhci;
|
XHCIState *xhci = xfer->xhci;
|
||||||
|
int i;
|
||||||
|
|
||||||
DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n",
|
pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count);
|
||||||
length, in_xfer, out_xfer, report);
|
|
||||||
|
|
||||||
assert(!(in_xfer && out_xfer));
|
|
||||||
|
|
||||||
for (i = 0; i < xfer->trb_count; i++) {
|
for (i = 0; i < xfer->trb_count; i++) {
|
||||||
XHCITRB *trb = &xfer->trbs[i];
|
XHCITRB *trb = &xfer->trbs[i];
|
||||||
dma_addr_t addr;
|
dma_addr_t addr;
|
||||||
@@ -1134,54 +1080,70 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
|||||||
case TR_DATA:
|
case TR_DATA:
|
||||||
if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
|
if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
|
||||||
fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n");
|
fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n");
|
||||||
xhci_die(xhci);
|
goto err;
|
||||||
return transferred;
|
|
||||||
}
|
}
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case TR_NORMAL:
|
case TR_NORMAL:
|
||||||
case TR_ISOCH:
|
case TR_ISOCH:
|
||||||
addr = xhci_mask64(trb->parameter);
|
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;
|
chunk = trb->status & 0x1ffff;
|
||||||
if (chunk > left) {
|
if (chunk > left) {
|
||||||
chunk = left;
|
chunk = left;
|
||||||
shortpkt = 1;
|
if (xfer->status == CC_SUCCESS) {
|
||||||
}
|
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
left -= chunk;
|
left -= chunk;
|
||||||
data += chunk;
|
|
||||||
edtla += chunk;
|
edtla += chunk;
|
||||||
transferred += chunk;
|
|
||||||
break;
|
break;
|
||||||
case TR_STATUS:
|
case TR_STATUS:
|
||||||
reported = 0;
|
reported = 0;
|
||||||
@@ -1189,8 +1151,9 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (report && !reported && (trb->control & TRB_TR_IOC ||
|
if (!reported && ((trb->control & TRB_TR_IOC) ||
|
||||||
(shortpkt && (trb->control & TRB_TR_ISP)))) {
|
(shortpkt && (trb->control & TRB_TR_ISP)) ||
|
||||||
|
(xfer->status != CC_SUCCESS))) {
|
||||||
event.slotid = xfer->slotid;
|
event.slotid = xfer->slotid;
|
||||||
event.epid = xfer->epid;
|
event.epid = xfer->epid;
|
||||||
event.length = (trb->status & 0x1ffff) - chunk;
|
event.length = (trb->status & 0x1ffff) - chunk;
|
||||||
@@ -1210,9 +1173,11 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
|
|||||||
}
|
}
|
||||||
xhci_event(xhci, &event);
|
xhci_event(xhci, &event);
|
||||||
reported = 1;
|
reported = 1;
|
||||||
|
if (xfer->status != CC_SUCCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return transferred;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xhci_stall_ep(XHCITransfer *xfer)
|
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,
|
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
|
||||||
XHCIEPContext *epctx);
|
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)
|
static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
|
||||||
{
|
{
|
||||||
USBEndpoint *ep;
|
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;
|
dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
|
||||||
ep = usb_ep_get(dev, dir, xfer->epid >> 1);
|
ep = usb_ep_get(dev, dir, xfer->epid >> 1);
|
||||||
usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr);
|
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",
|
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
|
||||||
xfer->packet.pid, dev->addr, ep->nr);
|
xfer->packet.pid, dev->addr, ep->nr);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1419,12 +1230,13 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
|
|||||||
xfer->running_async = 0;
|
xfer->running_async = 0;
|
||||||
xfer->running_retry = 0;
|
xfer->running_retry = 0;
|
||||||
xfer->complete = 1;
|
xfer->complete = 1;
|
||||||
|
xhci_xfer_unmap(xfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret >= 0) {
|
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);
|
trace_usb_xhci_xfer_success(xfer, ret);
|
||||||
|
xfer->status = CC_SUCCESS;
|
||||||
|
xhci_xfer_report(xfer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1433,12 +1245,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
|
|||||||
switch (ret) {
|
switch (ret) {
|
||||||
case USB_RET_NODEV:
|
case USB_RET_NODEV:
|
||||||
xfer->status = CC_USB_TRANSACTION_ERROR;
|
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);
|
xhci_stall_ep(xfer);
|
||||||
break;
|
break;
|
||||||
case USB_RET_STALL:
|
case USB_RET_STALL:
|
||||||
xfer->status = CC_STALL_ERROR;
|
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);
|
xhci_stall_ep(xfer);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1460,7 +1272,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
|
|||||||
{
|
{
|
||||||
XHCITRB *trb_setup, *trb_status;
|
XHCITRB *trb_setup, *trb_status;
|
||||||
uint8_t bmRequestType;
|
uint8_t bmRequestType;
|
||||||
uint16_t wLength;
|
|
||||||
XHCIPort *port;
|
XHCIPort *port;
|
||||||
USBDevice *dev;
|
USBDevice *dev;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1468,8 +1279,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
|
|||||||
trb_setup = &xfer->trbs[0];
|
trb_setup = &xfer->trbs[0];
|
||||||
trb_status = &xfer->trbs[xfer->trb_count-1];
|
trb_status = &xfer->trbs[xfer->trb_count-1];
|
||||||
|
|
||||||
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid,
|
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
|
||||||
trb_setup->parameter >> 48);
|
|
||||||
|
|
||||||
/* at most one Event Data TRB allowed after STATUS */
|
/* at most one Event Data TRB allowed after STATUS */
|
||||||
if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
|
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;
|
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];
|
port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
|
||||||
dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
|
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);
|
xhci_setup_packet(xfer, dev);
|
||||||
xfer->packet.parameter = trb_setup->parameter;
|
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);
|
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;
|
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 (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
|
||||||
if (!xfer->bg_xfer) {
|
xfer->pkts = 1;
|
||||||
xfer->pkts = 1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
xfer->pkts = 0;
|
xfer->pkts = 0;
|
||||||
}
|
}
|
||||||
@@ -1593,9 +1375,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
|
|||||||
return -1;
|
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);
|
ret = usb_handle_packet(dev, &xfer->packet);
|
||||||
|
|
||||||
xhci_complete_packet(xfer, ret);
|
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)
|
static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
|
||||||
{
|
{
|
||||||
int i;
|
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
|
||||||
unsigned int length = 0;
|
return xhci_submit(xhci, xfer, epctx);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
|
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) {
|
while (1) {
|
||||||
XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
|
XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
|
||||||
if (xfer->running_async || xfer->running_retry || xfer->backgrounded) {
|
if (xfer->running_async || xfer->running_retry) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
length = xhci_ring_chain_length(xhci, &epctx->ring);
|
length = xhci_ring_chain_length(xhci, &epctx->ring);
|
||||||
@@ -2356,7 +2098,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
|
|||||||
ret = 0x02000402; /* USB 2.0 */
|
ret = 0x02000402; /* USB 2.0 */
|
||||||
break;
|
break;
|
||||||
case 0x24: /* Supported Protocol:04 */
|
case 0x24: /* Supported Protocol:04 */
|
||||||
ret = 0x20425455; /* "USB " */
|
ret = 0x20425355; /* "USB " */
|
||||||
break;
|
break;
|
||||||
case 0x28: /* Supported Protocol:08 */
|
case 0x28: /* Supported Protocol:08 */
|
||||||
ret = 0x00000001 | (USB2_PORTS<<8);
|
ret = 0x00000001 | (USB2_PORTS<<8);
|
||||||
@@ -2368,7 +2110,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
|
|||||||
ret = 0x03000002; /* USB 3.0 */
|
ret = 0x03000002; /* USB 3.0 */
|
||||||
break;
|
break;
|
||||||
case 0x34: /* Supported Protocol:04 */
|
case 0x34: /* Supported Protocol:04 */
|
||||||
ret = 0x20425455; /* "USB " */
|
ret = 0x20425355; /* "USB " */
|
||||||
break;
|
break;
|
||||||
case 0x38: /* Supported Protocol:08 */
|
case 0x38: /* Supported Protocol:08 */
|
||||||
ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8);
|
ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8);
|
||||||
@@ -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)
|
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) {
|
switch (reg) {
|
||||||
case 0x20: /* IMAN */
|
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 = {
|
static const MemoryRegionOps xhci_mem_ops = {
|
||||||
.read = xhci_mem_read,
|
.read = xhci_mem_read,
|
||||||
.write = xhci_mem_write,
|
.write = xhci_mem_write,
|
||||||
.valid.min_access_size = 4,
|
.valid.min_access_size = 1,
|
||||||
.valid.max_access_size = 4,
|
.valid.max_access_size = 4,
|
||||||
|
.impl.min_access_size = 4,
|
||||||
|
.impl.max_access_size = 4,
|
||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
.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 */
|
/* Note request is (bRequestType << 8) | bRequest */
|
||||||
trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
|
trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
|
||||||
assert(p->result == 0);
|
|
||||||
|
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
||||||
@@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* The rest are asynchronous */
|
/* The rest are asynchronous */
|
||||||
|
assert(p && p->result == 0);
|
||||||
|
|
||||||
if (length > sizeof(dev->data_buf)) {
|
if (length > sizeof(dev->data_buf)) {
|
||||||
fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
|
fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
|
||||||
|
|||||||
+163
-229
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* USB redirector usb-guest
|
* USB redirector usb-guest
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011 Red Hat, Inc.
|
* Copyright (c) 2011-2012 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* Red Hat Authors:
|
* Red Hat Authors:
|
||||||
* Hans de Goede <hdegoede@redhat.com>
|
* Hans de Goede <hdegoede@redhat.com>
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
|
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
|
||||||
#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
|
#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
|
||||||
|
|
||||||
typedef struct AsyncURB AsyncURB;
|
typedef struct Cancelled Cancelled;
|
||||||
typedef struct USBRedirDevice USBRedirDevice;
|
typedef struct USBRedirDevice USBRedirDevice;
|
||||||
|
|
||||||
/* Struct to hold buffered packets (iso or int input packets) */
|
/* 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 */
|
/* Data passed from chardev the fd_read cb to the usbredirparser read cb */
|
||||||
const uint8_t *read_buf;
|
const uint8_t *read_buf;
|
||||||
int read_buf_size;
|
int read_buf_size;
|
||||||
/* For async handling of open/close */
|
/* For async handling of close */
|
||||||
QEMUBH *open_close_bh;
|
QEMUBH *chardev_close_bh;
|
||||||
/* To delay the usb attach in case of quick chardev close + open */
|
/* To delay the usb attach in case of quick chardev close + open */
|
||||||
QEMUTimer *attach_timer;
|
QEMUTimer *attach_timer;
|
||||||
int64_t next_attach_time;
|
int64_t next_attach_time;
|
||||||
struct usbredirparser *parser;
|
struct usbredirparser *parser;
|
||||||
struct endp_data endpoint[MAX_ENDPOINTS];
|
struct endp_data endpoint[MAX_ENDPOINTS];
|
||||||
uint32_t packet_id;
|
QTAILQ_HEAD(, Cancelled) cancelled;
|
||||||
QTAILQ_HEAD(, AsyncURB) asyncq;
|
|
||||||
/* Data for device filtering */
|
/* Data for device filtering */
|
||||||
struct usb_redir_device_connect_header device_info;
|
struct usb_redir_device_connect_header device_info;
|
||||||
struct usb_redir_interface_info_header interface_info;
|
struct usb_redir_interface_info_header interface_info;
|
||||||
@@ -95,17 +94,9 @@ struct USBRedirDevice {
|
|||||||
int filter_rules_count;
|
int filter_rules_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AsyncURB {
|
struct Cancelled {
|
||||||
USBRedirDevice *dev;
|
uint64_t id;
|
||||||
USBPacket *packet;
|
QTAILQ_ENTRY(Cancelled)next;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usbredir_hello(void *priv, struct usb_redir_hello_header *h);
|
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,
|
static int usbredir_handle_status(USBRedirDevice *dev,
|
||||||
int status, int actual_len);
|
int status, int actual_len);
|
||||||
|
|
||||||
|
#define VERSION "qemu usb-redir guest " QEMU_VERSION
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Logging stuff
|
* 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)
|
static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
|
||||||
{
|
{
|
||||||
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
||||||
AsyncURB *aurb;
|
Cancelled *c;
|
||||||
|
|
||||||
QTAILQ_FOREACH(aurb, &dev->asyncq, next) {
|
DPRINTF("cancel packet id %"PRIu64"\n", p->id);
|
||||||
if (p != aurb->packet) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINTF("async cancel id %u\n", aurb->packet_id);
|
c = g_malloc0(sizeof(Cancelled));
|
||||||
usbredirparser_send_cancel_data_packet(dev->parser, aurb->packet_id);
|
c->id = p->id;
|
||||||
usbredirparser_do_write(dev->parser);
|
QTAILQ_INSERT_TAIL(&dev->cancelled, c, next);
|
||||||
|
|
||||||
/* Mark it as dead */
|
usbredirparser_send_cancel_data_packet(dev->parser, p->id);
|
||||||
aurb->packet = NULL;
|
usbredirparser_do_write(dev->parser);
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
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,
|
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,
|
static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
|
||||||
uint8_t ep)
|
uint8_t ep)
|
||||||
{
|
{
|
||||||
AsyncURB *aurb = async_alloc(dev, p);
|
|
||||||
struct usb_redir_bulk_packet_header bulk_packet;
|
struct usb_redir_bulk_packet_header bulk_packet;
|
||||||
|
|
||||||
DPRINTF("bulk-out ep %02X len %zd id %u\n", ep,
|
DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id);
|
||||||
p->iov.size, aurb->packet_id);
|
|
||||||
|
|
||||||
bulk_packet.endpoint = ep;
|
bulk_packet.endpoint = ep;
|
||||||
bulk_packet.length = p->iov.size;
|
bulk_packet.length = p->iov.size;
|
||||||
bulk_packet.stream_id = 0;
|
bulk_packet.stream_id = 0;
|
||||||
aurb->bulk_packet = bulk_packet;
|
|
||||||
|
|
||||||
if (ep & USB_DIR_IN) {
|
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);
|
&bulk_packet, NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
uint8_t buf[p->iov.size];
|
uint8_t buf[p->iov.size];
|
||||||
usb_packet_copy(p, buf, p->iov.size);
|
usb_packet_copy(p, buf, p->iov.size);
|
||||||
usbredir_log_data(dev, "bulk data out:", 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);
|
&bulk_packet, buf, p->iov.size);
|
||||||
}
|
}
|
||||||
usbredirparser_do_write(dev->parser);
|
usbredirparser_do_write(dev->parser);
|
||||||
@@ -573,20 +563,18 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
|
|||||||
return len;
|
return len;
|
||||||
} else {
|
} else {
|
||||||
/* Output interrupt endpoint, normal async operation */
|
/* Output interrupt endpoint, normal async operation */
|
||||||
AsyncURB *aurb = async_alloc(dev, p);
|
|
||||||
struct usb_redir_interrupt_packet_header interrupt_packet;
|
struct usb_redir_interrupt_packet_header interrupt_packet;
|
||||||
uint8_t buf[p->iov.size];
|
uint8_t buf[p->iov.size];
|
||||||
|
|
||||||
DPRINTF("interrupt-out ep %02X len %zd id %u\n", ep, p->iov.size,
|
DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
|
||||||
aurb->packet_id);
|
p->iov.size, p->id);
|
||||||
|
|
||||||
interrupt_packet.endpoint = ep;
|
interrupt_packet.endpoint = ep;
|
||||||
interrupt_packet.length = p->iov.size;
|
interrupt_packet.length = p->iov.size;
|
||||||
aurb->interrupt_packet = interrupt_packet;
|
|
||||||
|
|
||||||
usb_packet_copy(p, buf, p->iov.size);
|
usb_packet_copy(p, buf, p->iov.size);
|
||||||
usbredir_log_data(dev, "interrupt data out:", 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);
|
&interrupt_packet, buf, p->iov.size);
|
||||||
usbredirparser_do_write(dev->parser);
|
usbredirparser_do_write(dev->parser);
|
||||||
return USB_RET_ASYNC;
|
return USB_RET_ASYNC;
|
||||||
@@ -640,10 +628,9 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
|
|||||||
int config)
|
int config)
|
||||||
{
|
{
|
||||||
struct usb_redir_set_configuration_header set_config;
|
struct usb_redir_set_configuration_header set_config;
|
||||||
AsyncURB *aurb = async_alloc(dev, p);
|
|
||||||
int i;
|
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++) {
|
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||||
switch (dev->endpoint[i].type) {
|
switch (dev->endpoint[i].type) {
|
||||||
@@ -660,20 +647,16 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_config.configuration = config;
|
set_config.configuration = config;
|
||||||
usbredirparser_send_set_configuration(dev->parser, aurb->packet_id,
|
usbredirparser_send_set_configuration(dev->parser, p->id, &set_config);
|
||||||
&set_config);
|
|
||||||
usbredirparser_do_write(dev->parser);
|
usbredirparser_do_write(dev->parser);
|
||||||
return USB_RET_ASYNC;
|
return USB_RET_ASYNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
|
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);
|
usbredirparser_send_get_configuration(dev->parser, p->id);
|
||||||
|
|
||||||
aurb->get = 1;
|
|
||||||
usbredirparser_send_get_configuration(dev->parser, aurb->packet_id);
|
|
||||||
usbredirparser_do_write(dev->parser);
|
usbredirparser_do_write(dev->parser);
|
||||||
return USB_RET_ASYNC;
|
return USB_RET_ASYNC;
|
||||||
}
|
}
|
||||||
@@ -682,11 +665,9 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
|
|||||||
int interface, int alt)
|
int interface, int alt)
|
||||||
{
|
{
|
||||||
struct usb_redir_set_alt_setting_header set_alt;
|
struct usb_redir_set_alt_setting_header set_alt;
|
||||||
AsyncURB *aurb = async_alloc(dev, p);
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
DPRINTF("set interface %d alt %d id %u\n", interface, alt,
|
DPRINTF("set interface %d alt %d id %"PRIu64"\n", interface, alt, p->id);
|
||||||
aurb->packet_id);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||||
if (dev->endpoint[i].interface == interface) {
|
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.interface = interface;
|
||||||
set_alt.alt = alt;
|
set_alt.alt = alt;
|
||||||
usbredirparser_send_set_alt_setting(dev->parser, aurb->packet_id,
|
usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt);
|
||||||
&set_alt);
|
|
||||||
usbredirparser_do_write(dev->parser);
|
usbredirparser_do_write(dev->parser);
|
||||||
return USB_RET_ASYNC;
|
return USB_RET_ASYNC;
|
||||||
}
|
}
|
||||||
@@ -716,14 +696,11 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
|
|||||||
int interface)
|
int interface)
|
||||||
{
|
{
|
||||||
struct usb_redir_get_alt_setting_header get_alt;
|
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;
|
get_alt.interface = interface;
|
||||||
aurb->get = 1;
|
usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt);
|
||||||
usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id,
|
|
||||||
&get_alt);
|
|
||||||
usbredirparser_do_write(dev->parser);
|
usbredirparser_do_write(dev->parser);
|
||||||
return USB_RET_ASYNC;
|
return USB_RET_ASYNC;
|
||||||
}
|
}
|
||||||
@@ -733,7 +710,6 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
|||||||
{
|
{
|
||||||
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
|
||||||
struct usb_redir_control_packet_header control_packet;
|
struct usb_redir_control_packet_header control_packet;
|
||||||
AsyncURB *aurb;
|
|
||||||
|
|
||||||
/* Special cases for certain standard device requests */
|
/* Special cases for certain standard device requests */
|
||||||
switch (request) {
|
switch (request) {
|
||||||
@@ -751,13 +727,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
|||||||
return usbredir_get_interface(dev, p, index);
|
return usbredir_get_interface(dev, p, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* "Normal" ctrl requests */
|
/* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */
|
||||||
aurb = async_alloc(dev, p);
|
DPRINTF(
|
||||||
|
"ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %"PRIu64"\n",
|
||||||
/* Note request is (bRequestType << 8) | bRequest */
|
request >> 8, request & 0xff, value, index, length, p->id);
|
||||||
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);
|
|
||||||
|
|
||||||
control_packet.request = request & 0xFF;
|
control_packet.request = request & 0xFF;
|
||||||
control_packet.requesttype = request >> 8;
|
control_packet.requesttype = request >> 8;
|
||||||
@@ -765,14 +738,13 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
|
|||||||
control_packet.value = value;
|
control_packet.value = value;
|
||||||
control_packet.index = index;
|
control_packet.index = index;
|
||||||
control_packet.length = length;
|
control_packet.length = length;
|
||||||
aurb->control_packet = control_packet;
|
|
||||||
|
|
||||||
if (control_packet.requesttype & USB_DIR_IN) {
|
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);
|
&control_packet, NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
usbredir_log_data(dev, "ctrl data out:", data, length);
|
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);
|
&control_packet, data, length);
|
||||||
}
|
}
|
||||||
usbredirparser_do_write(dev->parser);
|
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
|
* from within the USBDevice data / control packet callbacks and doing a
|
||||||
* usb_detach from within these callbacks is not a good idea.
|
* 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
|
* So we use a bh handler to take care of close events.
|
||||||
* open events from this callback to make sure that a close directly followed
|
|
||||||
* by an open gets handled in the right order.
|
|
||||||
*/
|
*/
|
||||||
static void usbredir_open_close_bh(void *opaque)
|
static void usbredir_chardev_close_bh(void *opaque)
|
||||||
{
|
{
|
||||||
USBRedirDevice *dev = 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);
|
usbredir_device_disconnect(dev);
|
||||||
|
|
||||||
@@ -803,36 +768,44 @@ static void usbredir_open_close_bh(void *opaque)
|
|||||||
usbredirparser_destroy(dev->parser);
|
usbredirparser_destroy(dev->parser);
|
||||||
dev->parser = NULL;
|
dev->parser = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dev->cs->opened) {
|
static void usbredir_chardev_open(USBRedirDevice *dev)
|
||||||
dev->parser = qemu_oom_check(usbredirparser_create());
|
{
|
||||||
dev->parser->priv = dev;
|
uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
|
||||||
dev->parser->log_func = usbredir_log;
|
char version[32];
|
||||||
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);
|
/* Make sure any pending closes are handled (no-op if none pending) */
|
||||||
usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
|
usbredir_chardev_close_bh(dev);
|
||||||
usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0);
|
qemu_bh_cancel(dev->chardev_close_bh);
|
||||||
usbredirparser_do_write(dev->parser);
|
|
||||||
}
|
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)
|
static void usbredir_do_attach(void *opaque)
|
||||||
@@ -856,13 +829,13 @@ static int usbredir_chardev_can_read(void *opaque)
|
|||||||
{
|
{
|
||||||
USBRedirDevice *dev = opaque;
|
USBRedirDevice *dev = opaque;
|
||||||
|
|
||||||
if (dev->parser) {
|
if (!dev->parser) {
|
||||||
/* usbredir_parser_do_read will consume *all* data we give it */
|
WARNING("chardev_can_read called on non open chardev!\n");
|
||||||
return 1024 * 1024;
|
|
||||||
} else {
|
|
||||||
/* usbredir_open_close_bh hasn't handled the open event yet */
|
|
||||||
return 0;
|
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)
|
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) {
|
switch (event) {
|
||||||
case CHR_EVENT_OPENED:
|
case CHR_EVENT_OPENED:
|
||||||
|
usbredir_chardev_open(dev);
|
||||||
|
break;
|
||||||
case CHR_EVENT_CLOSED:
|
case CHR_EVENT_CLOSED:
|
||||||
qemu_bh_schedule(dev->open_close_bh);
|
qemu_bh_schedule(dev->chardev_close_bh);
|
||||||
break;
|
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);
|
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++) {
|
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||||
QTAILQ_INIT(&dev->endpoint[i].bufpq);
|
QTAILQ_INIT(&dev->endpoint[i].bufpq);
|
||||||
}
|
}
|
||||||
@@ -939,11 +914,12 @@ static int usbredir_initfn(USBDevice *udev)
|
|||||||
|
|
||||||
static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
|
static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
|
||||||
{
|
{
|
||||||
AsyncURB *aurb, *next_aurb;
|
Cancelled *c, *next_c;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
QTAILQ_FOREACH_SAFE(aurb, &dev->asyncq, next, next_aurb) {
|
QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) {
|
||||||
async_free(dev, aurb);
|
QTAILQ_REMOVE(&dev->cancelled, c, next);
|
||||||
|
g_free(c);
|
||||||
}
|
}
|
||||||
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
for (i = 0; i < MAX_ENDPOINTS; i++) {
|
||||||
usbredir_free_bufpq(dev, I2EP(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_fe_close(dev->cs);
|
||||||
qemu_chr_delete(dev->cs);
|
qemu_chr_delete(dev->cs);
|
||||||
/* Note must be done after qemu_chr_close, as that causes a close event */
|
/* 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_del_timer(dev->attach_timer);
|
||||||
qemu_free_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:
|
case usb_redir_stall:
|
||||||
return USB_RET_STALL;
|
return USB_RET_STALL;
|
||||||
case usb_redir_cancelled:
|
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:
|
case usb_redir_inval:
|
||||||
WARNING("got invalid param error from usb-host?\n");
|
WARNING("got invalid param error from usb-host?\n");
|
||||||
return USB_RET_NAK;
|
return USB_RET_IOERROR;
|
||||||
case usb_redir_babble:
|
case usb_redir_babble:
|
||||||
return USB_RET_BABBLE;
|
return USB_RET_BABBLE;
|
||||||
case usb_redir_ioerror:
|
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)
|
struct usb_redir_configuration_status_header *config_status)
|
||||||
{
|
{
|
||||||
USBRedirDevice *dev = priv;
|
USBRedirDevice *dev = priv;
|
||||||
AsyncURB *aurb;
|
USBPacket *p;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
DPRINTF("set config status %d config %d id %u\n", config_status->status,
|
DPRINTF("set config status %d config %d id %u\n", config_status->status,
|
||||||
config_status->configuration, id);
|
config_status->configuration, id);
|
||||||
|
|
||||||
aurb = async_find(dev, id);
|
p = usbredir_find_packet_by_id(dev, 0, id);
|
||||||
if (!aurb) {
|
if (p) {
|
||||||
return;
|
if (dev->dev.setup_buf[0] & USB_DIR_IN) {
|
||||||
}
|
|
||||||
if (aurb->packet) {
|
|
||||||
if (aurb->get) {
|
|
||||||
dev->dev.data_buf[0] = config_status->configuration;
|
dev->dev.data_buf[0] = config_status->configuration;
|
||||||
len = 1;
|
len = 1;
|
||||||
}
|
}
|
||||||
aurb->packet->result =
|
p->result = usbredir_handle_status(dev, config_status->status, len);
|
||||||
usbredir_handle_status(dev, config_status->status, len);
|
usb_generic_async_ctrl_complete(&dev->dev, p);
|
||||||
usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
|
|
||||||
}
|
}
|
||||||
async_free(dev, aurb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
static void usbredir_alt_setting_status(void *priv, uint32_t id,
|
||||||
struct usb_redir_alt_setting_status_header *alt_setting_status)
|
struct usb_redir_alt_setting_status_header *alt_setting_status)
|
||||||
{
|
{
|
||||||
USBRedirDevice *dev = priv;
|
USBRedirDevice *dev = priv;
|
||||||
AsyncURB *aurb;
|
USBPacket *p;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
DPRINTF("alt status %d intf %d alt %d id: %u\n",
|
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->interface,
|
||||||
alt_setting_status->alt, id);
|
alt_setting_status->alt, id);
|
||||||
|
|
||||||
aurb = async_find(dev, id);
|
p = usbredir_find_packet_by_id(dev, 0, id);
|
||||||
if (!aurb) {
|
if (p) {
|
||||||
return;
|
if (dev->dev.setup_buf[0] & USB_DIR_IN) {
|
||||||
}
|
|
||||||
if (aurb->packet) {
|
|
||||||
if (aurb->get) {
|
|
||||||
dev->dev.data_buf[0] = alt_setting_status->alt;
|
dev->dev.data_buf[0] = alt_setting_status->alt;
|
||||||
len = 1;
|
len = 1;
|
||||||
}
|
}
|
||||||
aurb->packet->result =
|
p->result =
|
||||||
usbredir_handle_status(dev, alt_setting_status->status, len);
|
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,
|
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)
|
uint8_t *data, int data_len)
|
||||||
{
|
{
|
||||||
USBRedirDevice *dev = priv;
|
USBRedirDevice *dev = priv;
|
||||||
|
USBPacket *p;
|
||||||
int len = control_packet->length;
|
int len = control_packet->length;
|
||||||
AsyncURB *aurb;
|
|
||||||
|
|
||||||
DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status,
|
DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status,
|
||||||
len, id);
|
len, id);
|
||||||
|
|
||||||
aurb = async_find(dev, id);
|
p = usbredir_find_packet_by_id(dev, 0, id);
|
||||||
if (!aurb) {
|
if (p) {
|
||||||
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) {
|
|
||||||
len = usbredir_handle_status(dev, control_packet->status, len);
|
len = usbredir_handle_status(dev, control_packet->status, len);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
usbredir_log_data(dev, "ctrl data in:", data, data_len);
|
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;
|
len = USB_RET_STALL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aurb->packet->result = len;
|
p->result = len;
|
||||||
usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
|
usb_generic_async_ctrl_complete(&dev->dev, p);
|
||||||
}
|
}
|
||||||
async_free(dev, aurb);
|
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1354,39 +1310,27 @@ static void usbredir_bulk_packet(void *priv, uint32_t id,
|
|||||||
USBRedirDevice *dev = priv;
|
USBRedirDevice *dev = priv;
|
||||||
uint8_t ep = bulk_packet->endpoint;
|
uint8_t ep = bulk_packet->endpoint;
|
||||||
int len = bulk_packet->length;
|
int len = bulk_packet->length;
|
||||||
AsyncURB *aurb;
|
USBPacket *p;
|
||||||
|
|
||||||
DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status,
|
DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status,
|
||||||
ep, len, id);
|
ep, len, id);
|
||||||
|
|
||||||
aurb = async_find(dev, id);
|
p = usbredir_find_packet_by_id(dev, ep, id);
|
||||||
if (!aurb) {
|
if (p) {
|
||||||
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) {
|
|
||||||
len = usbredir_handle_status(dev, bulk_packet->status, len);
|
len = usbredir_handle_status(dev, bulk_packet->status, len);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
usbredir_log_data(dev, "bulk data in:", data, data_len);
|
usbredir_log_data(dev, "bulk data in:", data, data_len);
|
||||||
if (data_len <= aurb->packet->iov.size) {
|
if (data_len <= p->iov.size) {
|
||||||
usb_packet_copy(aurb->packet, data, data_len);
|
usb_packet_copy(p, data, data_len);
|
||||||
} else {
|
} else {
|
||||||
ERROR("bulk buffer too small (%d > %zd)\n", data_len,
|
ERROR("bulk got more data then requested (%d > %zd)\n",
|
||||||
aurb->packet->iov.size);
|
data_len, p->iov.size);
|
||||||
len = USB_RET_STALL;
|
len = USB_RET_BABBLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aurb->packet->result = len;
|
p->result = len;
|
||||||
usb_packet_complete(&dev->dev, aurb->packet);
|
usb_packet_complete(&dev->dev, p);
|
||||||
}
|
}
|
||||||
async_free(dev, aurb);
|
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1444,22 +1388,12 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
|
|||||||
} else {
|
} else {
|
||||||
int len = interrupt_packet->length;
|
int len = interrupt_packet->length;
|
||||||
|
|
||||||
AsyncURB *aurb = async_find(dev, id);
|
USBPacket *p = usbredir_find_packet_by_id(dev, ep, id);
|
||||||
if (!aurb) {
|
if (p) {
|
||||||
return;
|
p->result = usbredir_handle_status(dev,
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
interrupt_packet->status, len);
|
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_COMPACTFLASH,
|
||||||
VE_CLCD,
|
VE_CLCD,
|
||||||
VE_NORFLASH0,
|
VE_NORFLASH0,
|
||||||
VE_NORFLASH0ALIAS,
|
|
||||||
VE_NORFLASH1,
|
VE_NORFLASH1,
|
||||||
VE_SRAM,
|
VE_SRAM,
|
||||||
VE_VIDEORAM,
|
VE_VIDEORAM,
|
||||||
@@ -104,9 +103,8 @@ static target_phys_addr_t motherboard_legacy_map[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static target_phys_addr_t motherboard_aseries_map[] = {
|
static target_phys_addr_t motherboard_aseries_map[] = {
|
||||||
/* CS0: 0x00000000 .. 0x0c000000 */
|
/* CS0: 0x08000000 .. 0x0c000000 */
|
||||||
[VE_NORFLASH0] = 0x00000000,
|
[VE_NORFLASH0] = 0x08000000,
|
||||||
[VE_NORFLASH0ALIAS] = 0x08000000,
|
|
||||||
/* CS4: 0x0c000000 .. 0x10000000 */
|
/* CS4: 0x0c000000 .. 0x10000000 */
|
||||||
[VE_NORFLASH1] = 0x0c000000,
|
[VE_NORFLASH1] = 0x0c000000,
|
||||||
/* CS5: 0x10000000 .. 0x14000000 */
|
/* CS5: 0x10000000 .. 0x14000000 */
|
||||||
@@ -413,7 +411,6 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
|
|||||||
sysbus_create_simple("pl111", map[VE_CLCD], pic[14]);
|
sysbus_create_simple("pl111", map[VE_CLCD], pic[14]);
|
||||||
|
|
||||||
/* VE_NORFLASH0: not modelled */
|
/* VE_NORFLASH0: not modelled */
|
||||||
/* VE_NORFLASH0ALIAS: not modelled */
|
|
||||||
/* VE_NORFLASH1: not modelled */
|
/* VE_NORFLASH1: not modelled */
|
||||||
|
|
||||||
sram_size = 0x2000000;
|
sram_size = 0x2000000;
|
||||||
|
|||||||
@@ -447,10 +447,6 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
VirtIONet *n = to_virtio_net(vdev);
|
VirtIONet *n = to_virtio_net(vdev);
|
||||||
|
|
||||||
qemu_flush_queued_packets(&n->nic->nc);
|
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)
|
static int virtio_net_can_receive(NetClientState *nc)
|
||||||
|
|||||||
+7
-5
@@ -424,15 +424,17 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
|||||||
size_t resid)
|
size_t resid)
|
||||||
{
|
{
|
||||||
VirtIOSCSIReq *req = r->hba_private;
|
VirtIOSCSIReq *req = r->hba_private;
|
||||||
|
uint32_t sense_len;
|
||||||
|
|
||||||
req->resp.cmd->response = VIRTIO_SCSI_S_OK;
|
req->resp.cmd->response = VIRTIO_SCSI_S_OK;
|
||||||
req->resp.cmd->status = status;
|
req->resp.cmd->status = status;
|
||||||
if (req->resp.cmd->status == GOOD) {
|
if (req->resp.cmd->status == GOOD) {
|
||||||
req->resp.cmd->resid = resid;
|
req->resp.cmd->resid = tswap32(resid);
|
||||||
} else {
|
} else {
|
||||||
req->resp.cmd->resid = 0;
|
req->resp.cmd->resid = 0;
|
||||||
req->resp.cmd->sense_len =
|
sense_len = scsi_req_get_sense(r, req->resp.cmd->sense,
|
||||||
scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE);
|
VIRTIO_SCSI_SENSE_SIZE);
|
||||||
|
req->resp.cmd->sense_len = tswap32(sense_len);
|
||||||
}
|
}
|
||||||
virtio_scsi_complete_req(req);
|
virtio_scsi_complete_req(req);
|
||||||
}
|
}
|
||||||
@@ -532,8 +534,8 @@ static void virtio_scsi_get_config(VirtIODevice *vdev,
|
|||||||
stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
|
stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
|
||||||
stl_raw(&scsiconf->sense_size, s->sense_size);
|
stl_raw(&scsiconf->sense_size, s->sense_size);
|
||||||
stl_raw(&scsiconf->cdb_size, s->cdb_size);
|
stl_raw(&scsiconf->cdb_size, s->cdb_size);
|
||||||
stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
|
stw_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
|
||||||
stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
|
stw_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
|
||||||
stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
|
stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -361,10 +361,10 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data)
|
|||||||
uint16_t value;
|
uint16_t value;
|
||||||
|
|
||||||
if (s->i2c_len >= 2) {
|
if (s->i2c_len >= 2) {
|
||||||
printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
|
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
return 1;
|
printf("%s: long message (%i bytes)\n", __func__, s->i2c_len);
|
||||||
#endif
|
#endif
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
s->i2c_data[s->i2c_len ++] = data;
|
s->i2c_data[s->i2c_len ++] = data;
|
||||||
if (s->i2c_len != 2)
|
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);
|
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
|
||||||
net_tx_packets(netdev);
|
net_tx_packets(netdev);
|
||||||
|
qemu_flush_queued_packets(&netdev->nic->nc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int net_free(struct XenDevice *xendev)
|
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.
|
* - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* emulated register infomation */
|
/* emulated register information */
|
||||||
struct XenPTRegInfo {
|
struct XenPTRegInfo {
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
@@ -140,7 +140,7 @@ typedef int (*xen_pt_reg_size_init_fn)
|
|||||||
(XenPCIPassthroughState *, const XenPTRegGroupInfo *,
|
(XenPCIPassthroughState *, const XenPTRegGroupInfo *,
|
||||||
uint32_t base_offset, uint8_t *size);
|
uint32_t base_offset, uint8_t *size);
|
||||||
|
|
||||||
/* emulated register group infomation */
|
/* emulated register group information */
|
||||||
struct XenPTRegGroupInfo {
|
struct XenPTRegGroupInfo {
|
||||||
uint8_t grp_id;
|
uint8_t grp_id;
|
||||||
XenPTRegisterGroupType grp_type;
|
XenPTRegisterGroupType grp_type;
|
||||||
|
|||||||
@@ -562,7 +562,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Header Type0 reg static infomation table */
|
/* Header Type0 reg static information table */
|
||||||
static XenPTRegInfo xen_pt_emu_reg_header0[] = {
|
static XenPTRegInfo xen_pt_emu_reg_header0[] = {
|
||||||
/* Vendor ID reg */
|
/* Vendor ID reg */
|
||||||
{
|
{
|
||||||
@@ -753,7 +753,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = {
|
|||||||
* Vital Product Data Capability
|
* 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[] = {
|
static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
|
||||||
{
|
{
|
||||||
.offset = PCI_CAP_LIST_NEXT,
|
.offset = PCI_CAP_LIST_NEXT,
|
||||||
@@ -775,7 +775,7 @@ static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
|
|||||||
* Vendor Specific Capability
|
* 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[] = {
|
static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
|
||||||
{
|
{
|
||||||
.offset = PCI_CAP_LIST_NEXT,
|
.offset = PCI_CAP_LIST_NEXT,
|
||||||
@@ -866,7 +866,7 @@ static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
|
|||||||
return 0;
|
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[] = {
|
static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
|
||||||
/* Next Pointer reg */
|
/* Next Pointer reg */
|
||||||
{
|
{
|
||||||
@@ -981,7 +981,7 @@ static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Power Management Capability reg static infomation table */
|
/* Power Management Capability reg static information table */
|
||||||
static XenPTRegInfo xen_pt_emu_reg_pm[] = {
|
static XenPTRegInfo xen_pt_emu_reg_pm[] = {
|
||||||
/* Next Pointer reg */
|
/* Next Pointer reg */
|
||||||
{
|
{
|
||||||
@@ -1259,7 +1259,7 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MSI Capability Structure reg static infomation table */
|
/* MSI Capability Structure reg static information table */
|
||||||
static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||||
/* Next Pointer reg */
|
/* Next Pointer reg */
|
||||||
{
|
{
|
||||||
@@ -1396,7 +1396,7 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
|
|||||||
return 0;
|
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[] = {
|
static XenPTRegInfo xen_pt_emu_reg_msix[] = {
|
||||||
/* Next Pointer reg */
|
/* 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;
|
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, "one-timer-only", oto);
|
||||||
qdev_prop_set_uint32(dev, "frequency", freq);
|
qdev_prop_set_uint32(dev, "frequency", freq);
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
@@ -55,13 +55,16 @@ xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer,
|
|||||||
int txmem, int rxmem)
|
int txmem, int rxmem)
|
||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
|
Error *errp = NULL;
|
||||||
|
|
||||||
qemu_check_nic_model(nd, "xlnx.axi-ethernet");
|
qemu_check_nic_model(nd, "xlnx.axi-ethernet");
|
||||||
|
|
||||||
dev = qdev_create(NULL, "xlnx.axi-ethernet");
|
dev = qdev_create(NULL, "xlnx.axi-ethernet");
|
||||||
qdev_set_nic_properties(dev, nd);
|
qdev_set_nic_properties(dev, nd);
|
||||||
qdev_prop_set_uint32(dev, "rxmem", rxmem);
|
qdev_prop_set_uint32(dev, "rxmem", rxmem);
|
||||||
qdev_prop_set_uint32(dev, "txmem", txmem);
|
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);
|
qdev_init_nofail(dev);
|
||||||
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
|
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
|
||||||
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
|
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,
|
target_phys_addr_t base, qemu_irq irq,
|
||||||
qemu_irq irq2, int freqhz)
|
qemu_irq irq2, int freqhz)
|
||||||
{
|
{
|
||||||
|
Error *errp = NULL;
|
||||||
|
|
||||||
qdev_prop_set_uint32(dev, "freqhz", freqhz);
|
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);
|
qdev_init_nofail(dev);
|
||||||
|
|
||||||
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
|
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
|
||||||
|
|||||||
+7
-6
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "sysbus.h"
|
#include "sysbus.h"
|
||||||
#include "ptimer.h"
|
#include "ptimer.h"
|
||||||
|
#include "qemu-log.h"
|
||||||
|
|
||||||
#define D(x)
|
#define D(x)
|
||||||
|
|
||||||
@@ -119,7 +120,7 @@ timer_read(void *opaque, target_phys_addr_t addr, unsigned int size)
|
|||||||
break;
|
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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +128,7 @@ static void timer_enable(struct xlx_timer *xt)
|
|||||||
{
|
{
|
||||||
uint64_t count;
|
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));
|
xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
|
||||||
|
|
||||||
ptimer_stop(xt->ptimer);
|
ptimer_stop(xt->ptimer);
|
||||||
@@ -152,7 +153,7 @@ timer_write(void *opaque, target_phys_addr_t addr,
|
|||||||
addr >>= 2;
|
addr >>= 2;
|
||||||
timer = timer_from_addr(addr);
|
timer = timer_from_addr(addr);
|
||||||
xt = &t->timers[timer];
|
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));
|
__func__, addr * 4, value, timer, addr & 3));
|
||||||
/* Further decoding to address a specific timers reg. */
|
/* Further decoding to address a specific timers reg. */
|
||||||
addr &= 3;
|
addr &= 3;
|
||||||
@@ -189,7 +190,7 @@ static void timer_hit(void *opaque)
|
|||||||
{
|
{
|
||||||
struct xlx_timer *xt = opaque;
|
struct xlx_timer *xt = opaque;
|
||||||
struct timerblock *t = xt->parent;
|
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;
|
xt->regs[R_TCSR] |= TCSR_TINT;
|
||||||
|
|
||||||
if (xt->regs[R_TCSR] & TCSR_ARHT)
|
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);
|
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));
|
R_MAX * 4 * num_timers(t));
|
||||||
sysbus_init_mmio(dev, &t->mmio);
|
sysbus_init_mmio(dev, &t->mmio);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -239,7 +240,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static TypeInfo xilinx_timer_info = {
|
static TypeInfo xilinx_timer_info = {
|
||||||
.name = "xlnx,xps-timer",
|
.name = "xlnx.xps-timer",
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
.instance_size = sizeof(struct timerblock),
|
.instance_size = sizeof(struct timerblock),
|
||||||
.class_init = xilinx_timer_class_init,
|
.class_init = xilinx_timer_class_init,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ static inline void ratelimit_set_speed(RateLimit *limit, uint64_t speed,
|
|||||||
uint64_t slice_ns)
|
uint64_t slice_ns)
|
||||||
{
|
{
|
||||||
limit->slice_ns = slice_ns;
|
limit->slice_ns = slice_ns;
|
||||||
limit->slice_quota = ((double)speed * 1000000000ULL) / slice_ns;
|
limit->slice_quota = ((double)speed * slice_ns)/1000000000ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -56,6 +56,8 @@ int qemu_set_fd_handler2(int fd,
|
|||||||
{
|
{
|
||||||
IOHandlerRecord *ioh;
|
IOHandlerRecord *ioh;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
if (!fd_read && !fd_write) {
|
if (!fd_read && !fd_write) {
|
||||||
QLIST_FOREACH(ioh, &io_handlers, next) {
|
QLIST_FOREACH(ioh, &io_handlers, next) {
|
||||||
if (ioh->fd == fd) {
|
if (ioh->fd == fd) {
|
||||||
|
|||||||
@@ -39,6 +39,10 @@
|
|||||||
#include <sys/eventfd.h>
|
#include <sys/eventfd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_VALGRIND_H
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* KVM uses PAGE_SIZE in its definition of COALESCED_MMIO_MAX */
|
/* KVM uses PAGE_SIZE in its definition of COALESCED_MMIO_MAX */
|
||||||
#define PAGE_SIZE TARGET_PAGE_SIZE
|
#define PAGE_SIZE TARGET_PAGE_SIZE
|
||||||
|
|
||||||
@@ -1370,13 +1374,11 @@ int kvm_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (s) {
|
if (s->vmfd >= 0) {
|
||||||
if (s->vmfd >= 0) {
|
close(s->vmfd);
|
||||||
close(s->vmfd);
|
}
|
||||||
}
|
if (s->fd != -1) {
|
||||||
if (s->fd != -1) {
|
close(s->fd);
|
||||||
close(s->fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g_free(s);
|
g_free(s);
|
||||||
|
|
||||||
@@ -1719,6 +1721,9 @@ void *kvm_vmalloc(ram_addr_t size)
|
|||||||
|
|
||||||
void kvm_setup_guest_memory(void *start, size_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()) {
|
if (!kvm_has_sync_mmu()) {
|
||||||
int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK);
|
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);
|
unlock_user(argptr, arg, target_size);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
if (big_buf) {
|
g_free(big_buf);
|
||||||
free(big_buf);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -538,12 +538,12 @@ static void render_memory_region(FlatView *view,
|
|||||||
offset_in_region += int128_get64(now);
|
offset_in_region += int128_get64(now);
|
||||||
int128_subfrom(&remain, now);
|
int128_subfrom(&remain, now);
|
||||||
}
|
}
|
||||||
if (int128_eq(base, view->ranges[i].addr.start)) {
|
now = int128_sub(int128_min(int128_add(base, remain),
|
||||||
now = int128_min(remain, view->ranges[i].addr.size);
|
addrrange_end(view->ranges[i].addr)),
|
||||||
int128_addto(&base, now);
|
base);
|
||||||
offset_in_region += int128_get64(now);
|
int128_addto(&base, now);
|
||||||
int128_subfrom(&remain, now);
|
offset_in_region += int128_get64(now);
|
||||||
}
|
int128_subfrom(&remain, now);
|
||||||
}
|
}
|
||||||
if (int128_nz(remain)) {
|
if (int128_nz(remain)) {
|
||||||
fr.mr = mr;
|
fr.mr = mr;
|
||||||
|
|||||||
+9
-28
@@ -53,54 +53,35 @@ static int tcp_close(MigrationState *s)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcp_wait_for_connect(void *opaque)
|
static void tcp_wait_for_connect(int fd, void *opaque)
|
||||||
{
|
{
|
||||||
MigrationState *s = opaque;
|
MigrationState *s = opaque;
|
||||||
int val, ret;
|
|
||||||
socklen_t valsize = sizeof(val);
|
|
||||||
|
|
||||||
DPRINTF("connect completed\n");
|
if (fd < 0) {
|
||||||
do {
|
DPRINTF("migrate connect error\n");
|
||||||
ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
|
s->fd = -1;
|
||||||
} while (ret == -1 && (socket_error()) == EINTR);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
migrate_fd_error(s);
|
migrate_fd_error(s);
|
||||||
return;
|
} else {
|
||||||
}
|
DPRINTF("migrate connect success\n");
|
||||||
|
s->fd = fd;
|
||||||
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (val == 0)
|
|
||||||
migrate_fd_connect(s);
|
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,
|
int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
bool in_progress;
|
|
||||||
|
|
||||||
s->get_error = socket_errno;
|
s->get_error = socket_errno;
|
||||||
s->write = socket_write;
|
s->write = socket_write;
|
||||||
s->close = tcp_close;
|
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)) {
|
if (error_is_set(errp)) {
|
||||||
migrate_fd_error(s);
|
migrate_fd_error(s);
|
||||||
return -1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -240,7 +240,9 @@ static int migrate_fd_cleanup(MigrationState *s)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
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) {
|
if (s->file) {
|
||||||
DPRINTF("closing file\n");
|
DPRINTF("closing file\n");
|
||||||
|
|||||||
@@ -455,6 +455,7 @@ static const char *monitor_event_names[] = {
|
|||||||
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
|
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
|
||||||
[QEVENT_WAKEUP] = "WAKEUP",
|
[QEVENT_WAKEUP] = "WAKEUP",
|
||||||
[QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
|
[QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
|
||||||
|
[QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED",
|
||||||
};
|
};
|
||||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
|
QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ typedef enum MonitorEvent {
|
|||||||
QEVENT_SUSPEND_DISK,
|
QEVENT_SUSPEND_DISK,
|
||||||
QEVENT_WAKEUP,
|
QEVENT_WAKEUP,
|
||||||
QEVENT_BALLOON_CHANGE,
|
QEVENT_BALLOON_CHANGE,
|
||||||
|
QEVENT_SPICE_MIGRATE_COMPLETED,
|
||||||
|
|
||||||
/* Add to 'monitor_event_names' array in monitor.c when
|
/* Add to 'monitor_event_names' array in monitor.c when
|
||||||
* defining new events here */
|
* 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)
|
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)
|
int tcp_socket_incoming(const char *address, uint16_t port)
|
||||||
@@ -399,24 +399,23 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
|
|||||||
return -serrno;
|
return -serrno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & NBD_FLAG_READ_ONLY) {
|
if (ioctl(fd, NBD_SET_FLAGS, flags) < 0) {
|
||||||
int read_only = 1;
|
if (errno == ENOTTY) {
|
||||||
TRACE("Setting readonly attribute");
|
int read_only = (flags & NBD_FLAG_READ_ONLY) != 0;
|
||||||
|
TRACE("Setting readonly attribute");
|
||||||
|
|
||||||
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
|
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
|
||||||
|
int serrno = errno;
|
||||||
|
LOG("Failed setting read-only attribute");
|
||||||
|
return -serrno;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
int serrno = errno;
|
int serrno = errno;
|
||||||
LOG("Failed setting read-only attribute");
|
LOG("Failed setting flags");
|
||||||
return -serrno;
|
return -serrno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, NBD_SET_FLAGS, flags) < 0
|
|
||||||
&& errno != ENOTTY) {
|
|
||||||
int serrno = errno;
|
|
||||||
LOG("Failed setting flags");
|
|
||||||
return -serrno;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("Negotiation ended");
|
TRACE("Negotiation ended");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -357,7 +357,12 @@ void qemu_flush_queued_packets(NetClientState *nc)
|
|||||||
{
|
{
|
||||||
nc->receive_disabled = 0;
|
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,
|
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)
|
void *opaque)
|
||||||
{
|
{
|
||||||
NetClientState *nc = opaque;
|
NetClientState *nc = opaque;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (nc->link_down) {
|
if (nc->link_down) {
|
||||||
return iov_size(iov, iovcnt);
|
return iov_size(iov, iovcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nc->info->receive_iov) {
|
if (nc->receive_disabled) {
|
||||||
return nc->info->receive_iov(nc, iov, iovcnt);
|
return 0;
|
||||||
} else {
|
|
||||||
return nc_sendv_compat(nc, iov, iovcnt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
ssize_t qemu_sendv_packet_async(NetClientState *sender,
|
||||||
|
|||||||
@@ -97,12 +97,12 @@ static int net_hub_port_can_receive(NetClientState *nc)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!qemu_can_send_packet(&port->nc)) {
|
if (qemu_can_send_packet(&port->nc)) {
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t net_hub_port_receive(NetClientState *nc,
|
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);
|
g_free(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t qemu_net_queue_append(NetQueue *queue,
|
static void qemu_net_queue_append(NetQueue *queue,
|
||||||
NetClientState *sender,
|
NetClientState *sender,
|
||||||
unsigned flags,
|
unsigned flags,
|
||||||
const uint8_t *buf,
|
const uint8_t *buf,
|
||||||
size_t size,
|
size_t size,
|
||||||
NetPacketSent *sent_cb)
|
NetPacketSent *sent_cb)
|
||||||
{
|
{
|
||||||
NetPacket *packet;
|
NetPacket *packet;
|
||||||
|
|
||||||
@@ -100,16 +100,14 @@ static ssize_t qemu_net_queue_append(NetQueue *queue,
|
|||||||
memcpy(packet->data, buf, size);
|
memcpy(packet->data, buf, size);
|
||||||
|
|
||||||
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
|
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
|
static void qemu_net_queue_append_iov(NetQueue *queue,
|
||||||
NetClientState *sender,
|
NetClientState *sender,
|
||||||
unsigned flags,
|
unsigned flags,
|
||||||
const struct iovec *iov,
|
const struct iovec *iov,
|
||||||
int iovcnt,
|
int iovcnt,
|
||||||
NetPacketSent *sent_cb)
|
NetPacketSent *sent_cb)
|
||||||
{
|
{
|
||||||
NetPacket *packet;
|
NetPacket *packet;
|
||||||
size_t max_len = 0;
|
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);
|
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
|
||||||
|
|
||||||
return packet->size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t qemu_net_queue_deliver(NetQueue *queue,
|
static ssize_t qemu_net_queue_deliver(NetQueue *queue,
|
||||||
@@ -177,7 +173,8 @@ ssize_t qemu_net_queue_send(NetQueue *queue,
|
|||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
if (queue->delivering || !qemu_can_send_packet(sender)) {
|
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);
|
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;
|
ssize_t ret;
|
||||||
|
|
||||||
if (queue->delivering || !qemu_can_send_packet(sender)) {
|
if (queue->delivering || !qemu_can_send_packet(sender)) {
|
||||||
return qemu_net_queue_append_iov(queue, sender, flags,
|
qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
|
||||||
iov, iovcnt, sent_cb);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt);
|
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)) {
|
while (!QTAILQ_EMPTY(&queue->packets)) {
|
||||||
NetPacket *packet;
|
NetPacket *packet;
|
||||||
@@ -244,7 +241,7 @@ void qemu_net_queue_flush(NetQueue *queue)
|
|||||||
packet->size);
|
packet->size);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
|
QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet->sent_cb) {
|
if (packet->sent_cb) {
|
||||||
@@ -253,4 +250,5 @@ void qemu_net_queue_flush(NetQueue *queue)
|
|||||||
|
|
||||||
g_free(packet);
|
g_free(packet);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
+1
-1
@@ -53,6 +53,6 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue,
|
|||||||
NetPacketSent *sent_cb);
|
NetPacketSent *sent_cb);
|
||||||
|
|
||||||
void qemu_net_queue_purge(NetQueue *queue, NetClientState *from);
|
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 */
|
#endif /* QEMU_NET_QUEUE_H */
|
||||||
+95
-13
@@ -32,6 +32,7 @@
|
|||||||
#include "qemu-error.h"
|
#include "qemu-error.h"
|
||||||
#include "qemu-option.h"
|
#include "qemu-option.h"
|
||||||
#include "qemu_socket.h"
|
#include "qemu_socket.h"
|
||||||
|
#include "iov.h"
|
||||||
|
|
||||||
typedef struct NetSocketState {
|
typedef struct NetSocketState {
|
||||||
NetClientState nc;
|
NetClientState nc;
|
||||||
@@ -40,29 +41,106 @@ typedef struct NetSocketState {
|
|||||||
int state; /* 0 = getting length, 1 = getting data */
|
int state; /* 0 = getting length, 1 = getting data */
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
unsigned int packet_len;
|
unsigned int packet_len;
|
||||||
|
unsigned int send_index; /* number of bytes sent (only SOCK_STREAM) */
|
||||||
uint8_t buf[4096];
|
uint8_t buf[4096];
|
||||||
struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
|
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;
|
} NetSocketState;
|
||||||
|
|
||||||
static void net_socket_accept(void *opaque);
|
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)
|
static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||||
{
|
{
|
||||||
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
||||||
uint32_t len;
|
uint32_t len = htonl(size);
|
||||||
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));
|
remaining = iov_size(iov, 2) - s->send_index;
|
||||||
return send_all(s->fd, buf, size);
|
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)
|
static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||||
{
|
{
|
||||||
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
return sendto(s->fd, (const void *)buf, size, 0,
|
do {
|
||||||
(struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
|
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)
|
static void net_socket_send(void *opaque)
|
||||||
@@ -81,7 +159,8 @@ static void net_socket_send(void *opaque)
|
|||||||
} else if (size == 0) {
|
} else if (size == 0) {
|
||||||
/* end of connection */
|
/* end of connection */
|
||||||
eoc:
|
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) {
|
if (s->listen_fd != -1) {
|
||||||
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
|
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;
|
return;
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
/* end of connection */
|
/* 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;
|
return;
|
||||||
}
|
}
|
||||||
qemu_send_packet(&s->nc, s->buf, size);
|
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);
|
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
||||||
if (s->fd != -1) {
|
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);
|
close(s->fd);
|
||||||
s->fd = -1;
|
s->fd = -1;
|
||||||
}
|
}
|
||||||
@@ -314,8 +395,8 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
|
|||||||
|
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
s->listen_fd = -1;
|
s->listen_fd = -1;
|
||||||
|
s->send_fn = net_socket_send_dgram;
|
||||||
qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
|
net_socket_read_poll(s, true);
|
||||||
|
|
||||||
/* mcast: save bound address as dst */
|
/* mcast: save bound address as dst */
|
||||||
if (is_connected) {
|
if (is_connected) {
|
||||||
@@ -332,7 +413,8 @@ err:
|
|||||||
static void net_socket_connect(void *opaque)
|
static void net_socket_connect(void *opaque)
|
||||||
{
|
{
|
||||||
NetSocketState *s = 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 = {
|
static NetClientInfo net_socket_info = {
|
||||||
|
|||||||
@@ -360,3 +360,8 @@ int qemu_create_pidfile(const char *filename)
|
|||||||
/* keep pidfile open & locked forever */
|
/* keep pidfile open & locked forever */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_daemonized(void)
|
||||||
|
{
|
||||||
|
return daemonize;
|
||||||
|
}
|
||||||
@@ -74,6 +74,30 @@ void qemu_vfree(void *ptr)
|
|||||||
VirtualFree(ptr, 0, MEM_RELEASE);
|
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)
|
void socket_set_block(int fd)
|
||||||
{
|
{
|
||||||
unsigned long opt = 0;
|
unsigned long opt = 0;
|
||||||
|
|||||||
Loaded 100 of 218 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user