Compare commits
335 Commits
pull-input
...
pull-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
562f93754b | ||
|
|
e2f6bac301 | ||
| 2a19b229f6 | |||
|
|
2d5ee9e7a7 | ||
|
|
3749c11a72 | ||
|
|
be0df8cd1e | ||
|
|
3046bb5deb | ||
|
|
d461a44ca4 | ||
|
|
672558d2ea | ||
|
|
7692401a08 | ||
|
|
76e2aef392 | ||
|
|
e46e1a74ef | ||
|
|
711dc6f36b | ||
|
|
908680c644 | ||
|
|
f01a361bfc | ||
|
|
26e7e982b2 | ||
|
|
47ada0ad34 | ||
|
|
fe87c2b36a | ||
|
|
6a973e6b65 | ||
|
|
6b9c26fb5e | ||
|
|
d4f4f0d5d9 | ||
|
|
4dc89b7820 | ||
|
|
f5dec79ee8 | ||
|
|
560d027b54 | ||
|
|
9f5f380b54 | ||
|
|
48212d87d6 | ||
|
|
72e72e1a71 | ||
|
|
4ba4bc5e9b | ||
|
|
172c4356f3 | ||
|
|
796a060bc0 | ||
|
|
48ac0a4df8 | ||
|
|
17d9716d7b | ||
|
|
299bf09737 | ||
|
|
4c0cbd6fec | ||
|
|
661725da09 | ||
|
|
2af9170c8c | ||
|
|
0c7322cfd3 | ||
|
|
f3947986d9 | ||
|
|
e34d8f297d | ||
|
|
99a3c89d5d | ||
|
|
5a8ac6d9d7 | ||
|
|
3dbf00e058 | ||
|
|
80a1e13091 | ||
|
|
9a7dedbc43 | ||
|
|
33a604075c | ||
|
|
b4b059f628 | ||
|
|
df58179267 | ||
|
|
30349fd038 | ||
|
|
8b9d74e0ee | ||
|
|
0030ff4047 | ||
|
|
a16951375f | ||
|
|
f3a1b5068c | ||
|
|
4421c6a38a | ||
|
|
06c4670ff6 | ||
|
|
2a6391232f | ||
|
|
8aedc369c6 | ||
|
|
6e3c0c6edb | ||
|
|
6169b60285 | ||
|
|
16c1321bd7 | ||
|
|
a9dc4cf94c | ||
|
|
4f4f6976d8 | ||
|
|
032624868d | ||
|
|
6b625fde5e | ||
|
|
51d373cf5f | ||
|
|
efc6674be8 | ||
|
|
484406200e | ||
|
|
fb200d5f00 | ||
|
|
37b9de463b | ||
|
|
2de295c544 | ||
|
|
691b9572e3 | ||
|
|
4df81c6ed1 | ||
|
|
4a2b24edb7 | ||
|
|
2991b89047 | ||
|
|
ea3e984740 | ||
|
|
4bad9e392e | ||
|
|
3d57f7893c | ||
|
|
f7ec7f7b26 | ||
|
|
bbd77c180d | ||
|
|
6dd0f8342d | ||
|
|
b7bca73334 | ||
|
|
5a790cc4b9 | ||
|
|
291135b5da | ||
|
|
7c39163e38 | ||
|
|
199fc85acd | ||
|
|
5a2db89615 | ||
|
|
a8f13961fd | ||
|
|
d09a6fde15 | ||
|
|
acf7b7fdf3 | ||
|
|
c8e84287da | ||
|
|
702c8c8be2 | ||
|
|
9ab9993f71 | ||
|
|
d09952ee8c | ||
|
|
c8232b39bb | ||
|
|
62a3864eb0 | ||
|
|
2828a30723 | ||
|
|
800567a613 | ||
|
|
f6fa64f6d2 | ||
|
|
8e9b0d24fb | ||
|
|
488981a4af | ||
|
|
ed754746fe | ||
|
|
62893b67cd | ||
|
|
ca38a4cc9e | ||
|
|
c4fc82bf1a | ||
|
|
1e40356ce5 | ||
|
|
ada434cd0b | ||
|
|
c36f24a204 | ||
|
|
b2101eae63 | ||
|
|
412a82457e | ||
|
|
f56fc2d319 | ||
|
|
220a884642 | ||
|
|
b86f46132c | ||
|
|
7444ca4ee2 | ||
|
|
5add35bec1 | ||
|
|
45dcdb9da6 | ||
|
|
c54e1eb492 | ||
|
|
a3ef3b2272 | ||
|
|
50cbebb9a3 | ||
|
|
d2b3f390d4 | ||
|
|
ef0a03f230 | ||
|
|
00d2f3707a | ||
| d6c5528b0c | |||
| 601e5a0618 | |||
|
|
f300414cfe | ||
|
|
e82855d9aa | ||
|
|
73a652a1b0 | ||
|
|
59dc0a1e9b | ||
|
|
7ce0f7dc87 | ||
|
|
1a632032d1 | ||
|
|
30c6672aa4 | ||
|
|
9861b71fd6 | ||
|
|
cd3b29b745 | ||
|
|
92f2b4e71e | ||
|
|
c9c19b4932 | ||
|
|
b5edcddda3 | ||
|
|
6319b1dad0 | ||
|
|
aef87d1b87 | ||
|
|
7cb180079e | ||
|
|
e275934d2d | ||
|
|
0f888bfadd | ||
|
|
e634b89c6e | ||
|
|
16b0ea1d85 | ||
|
|
1d2d974244 | ||
|
|
a45863bda9 | ||
|
|
19fb2c36e2 | ||
|
|
bab99ea098 | ||
|
|
0da6f3fef9 | ||
|
|
8487d12318 | ||
|
|
db4ef288f4 | ||
|
|
9e734e3dee | ||
|
|
708414f03c | ||
|
|
5709af3b95 | ||
|
|
4d9ab7d4ed | ||
|
|
9b7d9284c3 | ||
|
|
4a7c347415 | ||
|
|
72187935b4 | ||
|
|
183930c0d7 | ||
|
|
1b71890729 | ||
|
|
fb16499418 | ||
|
|
28e0204254 | ||
|
|
780184aae6 | ||
|
|
f303f117fe | ||
|
|
2d103aae87 | ||
|
|
5c464f66f5 | ||
|
|
7d6b1daedd | ||
|
|
f2562fbb7a | ||
|
|
06ef227e51 | ||
|
|
28b8e4d0bf | ||
|
|
aeb72188e0 | ||
|
|
970311646a | ||
|
|
25d9747b64 | ||
|
|
53ec73e264 | ||
|
|
c2e0dbbfd7 | ||
|
|
dd63169766 | ||
|
|
2ff64038a5 | ||
|
|
59f39a4741 | ||
|
|
7cf1fe6d68 | ||
|
|
b05dc72342 | ||
|
|
598cd2bda0 | ||
|
|
f2bb932491 | ||
|
|
7844337d1e | ||
|
|
656a233440 | ||
|
|
a5c17b5f68 | ||
|
|
61964c23e5 | ||
|
|
df8961522a | ||
|
|
13d16814d2 | ||
|
|
df4b102452 | ||
|
|
ca3fc39ea9 | ||
|
|
5e0f1940ca | ||
|
|
ff14e817f6 | ||
|
|
ef4b722d19 | ||
|
|
afcddefdbe | ||
|
|
e4d633207c | ||
|
|
760ff4bebc | ||
|
|
03fcab3861 | ||
|
|
632e3a5cd8 | ||
|
|
b12f777798 | ||
|
|
4fb5364b90 | ||
|
|
24ec68ef84 | ||
|
|
1aca9a5f7d | ||
|
|
728470bea1 | ||
|
|
849729bb79 | ||
|
|
d0d2555852 | ||
|
|
96497af0af | ||
|
|
f211fcd75f | ||
|
|
d1a88c96b7 | ||
|
|
66851f640b | ||
|
|
b83b5f2ef9 | ||
|
|
5df6a1855b | ||
|
|
ec50dd4634 | ||
|
|
920557971b | ||
|
|
71ba2f0af3 | ||
|
|
9fd72468df | ||
|
|
6f2945cde6 | ||
|
|
ddbb0d0966 | ||
|
|
7a63f3cdc4 | ||
|
|
1bd84ee717 | ||
|
|
501eea4f41 | ||
|
|
b3409a3100 | ||
|
|
e18882952e | ||
|
|
6b3f7f639e | ||
|
|
1452673888 | ||
|
|
f329c74c1e | ||
|
|
be1e50a27d | ||
|
|
f6e3035f75 | ||
|
|
4330296996 | ||
|
|
f8d8a94400 | ||
|
|
fb5f816499 | ||
|
|
879904e863 | ||
|
|
715ca691da | ||
|
|
6a1a9cfa1c | ||
|
|
197e35249a | ||
|
|
1c9b71a731 | ||
|
|
f7ceed190d | ||
|
|
4e51361d79 | ||
|
|
7d489dcdf5 | ||
|
|
355023f201 | ||
|
|
fba72476c6 | ||
|
|
61e66c6237 | ||
|
|
6410848bec | ||
|
|
8db4936bb6 | ||
|
|
38bfe69180 | ||
|
|
7bbda04c8d | ||
|
|
8571ed35cf | ||
|
|
714f78c587 | ||
|
|
d6ff5cbc12 | ||
|
|
fc12d72e10 | ||
|
|
afd6895b45 | ||
|
|
25b8b39b6d | ||
|
|
7edd8e4660 | ||
|
|
b242e0e0e2 | ||
|
|
fba0a593b2 | ||
|
|
3fa18bc9a5 | ||
|
|
1479073b7e | ||
|
|
ddd44279fd | ||
|
|
261ccf426a | ||
|
|
257621a956 | ||
|
|
8a52340cba | ||
|
|
12dc273e98 | ||
|
|
c87e5a61c2 | ||
|
|
049e24a191 | ||
|
|
a7ffaf5c96 | ||
|
|
2a6332d968 | ||
|
|
f50a1640fb | ||
|
|
63a9294ddc | ||
|
|
7c649ac5b6 | ||
|
|
8146d7dc27 | ||
|
|
dd6282217d | ||
|
|
684d50132f | ||
|
|
ee364416c1 | ||
|
|
c82bd3c893 | ||
|
|
7f6cf5ee12 | ||
|
|
e08a98357b | ||
|
|
9364384de0 | ||
|
|
7c03a69107 | ||
|
|
54f3223730 | ||
|
|
631ddc22cb | ||
|
|
922f893e57 | ||
|
|
4614619ee4 | ||
|
|
a718978ed5 | ||
|
|
07a1ee7958 | ||
|
|
26ad004585 | ||
|
|
e38cc93aca | ||
|
|
a8973ff50a | ||
|
|
359790c254 | ||
|
|
4de484698b | ||
|
|
cb45304108 | ||
|
|
40d29928ca | ||
|
|
34475239b8 | ||
|
|
0437d32ae2 | ||
|
|
5d5f89212f | ||
|
|
d56f4d6965 | ||
|
|
3bcbe4aa80 | ||
|
|
a55c8231d0 | ||
|
|
b6fe41fa6d | ||
|
|
7763ed1506 | ||
|
|
d31a3ebc28 | ||
|
|
95ea663693 | ||
|
|
0d3e9d1f59 | ||
|
|
e9ebb2f767 | ||
|
|
e75e2a14d5 | ||
|
|
abafabd8c9 | ||
|
|
fa9ea81d15 | ||
|
|
8e23184b6b | ||
|
|
43bbb49ef7 | ||
|
|
a7d69ff10b | ||
|
|
35360642d0 | ||
|
|
5317b0f6d4 | ||
|
|
c4d3c0a269 | ||
|
|
55b1b753df | ||
|
|
6efd2c2a12 | ||
|
|
213941d73b | ||
|
|
0db87e0d17 | ||
|
|
c42767f2bb | ||
|
|
de7ea885c5 | ||
|
|
7070e085d4 | ||
|
|
80b7d2efb6 | ||
|
|
4b8523ee89 | ||
|
|
4840f10eff | ||
|
|
125b380666 | ||
|
|
196ea13104 | ||
|
|
afbe70535f | ||
|
|
2e7f7a3c86 | ||
|
|
bdf026317d | ||
|
|
62ac4a52e2 | ||
|
|
6e7cd94462 | ||
|
|
bdc7fe3638 | ||
|
|
ec7353a146 | ||
|
|
fa8b0ca5d1 | ||
|
|
41da4bd642 | ||
|
|
e1b89321ba | ||
|
|
9e0dc48c9f | ||
|
|
6e0b07306d | ||
|
|
94beb661bd | ||
|
|
27e7755bea | ||
|
|
34664507c7 |
@@ -1052,6 +1052,13 @@ S: Supported
|
|||||||
F: qemu-seccomp.c
|
F: qemu-seccomp.c
|
||||||
F: include/sysemu/seccomp.h
|
F: include/sysemu/seccomp.h
|
||||||
|
|
||||||
|
Cryptography
|
||||||
|
M: Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
S: Maintained
|
||||||
|
F: crypto/
|
||||||
|
F: include/crypto/
|
||||||
|
F: tests/test-crypto-*
|
||||||
|
|
||||||
Usermode Emulation
|
Usermode Emulation
|
||||||
------------------
|
------------------
|
||||||
Overall
|
Overall
|
||||||
@@ -1162,7 +1169,7 @@ S: Supported
|
|||||||
F: block/vmdk.c
|
F: block/vmdk.c
|
||||||
|
|
||||||
RBD
|
RBD
|
||||||
M: Josh Durgin <josh.durgin@inktank.com>
|
M: Josh Durgin <jdurgin@redhat.com>
|
||||||
M: Jeff Cody <jcody@redhat.com>
|
M: Jeff Cody <jcody@redhat.com>
|
||||||
L: qemu-block@nongnu.org
|
L: qemu-block@nongnu.org
|
||||||
S: Supported
|
S: Supported
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# Common libraries for tools and emulators
|
# Common libraries for tools and emulators
|
||||||
stub-obj-y = stubs/
|
stub-obj-y = stubs/
|
||||||
util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o
|
util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o
|
||||||
|
util-obj-y += crypto/
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||||
|
|||||||
@@ -853,6 +853,7 @@ static void *oss_audio_init (void)
|
|||||||
|
|
||||||
if (access(conf->devpath_in, R_OK | W_OK) < 0 ||
|
if (access(conf->devpath_in, R_OK | W_OK) < 0 ||
|
||||||
access(conf->devpath_out, R_OK | W_OK) < 0) {
|
access(conf->devpath_out, R_OK | W_OK) < 0) {
|
||||||
|
g_free(conf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return conf;
|
return conf;
|
||||||
|
|||||||
172
block.c
172
block.c
@@ -1102,12 +1102,46 @@ static int bdrv_fill_options(QDict **options, const char **pfilename,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||||
|
BlockDriverState *child_bs,
|
||||||
|
const BdrvChildRole *child_role)
|
||||||
|
{
|
||||||
|
BdrvChild *child = g_new(BdrvChild, 1);
|
||||||
|
*child = (BdrvChild) {
|
||||||
|
.bs = child_bs,
|
||||||
|
.role = child_role,
|
||||||
|
};
|
||||||
|
|
||||||
|
QLIST_INSERT_HEAD(&parent_bs->children, child, next);
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bdrv_detach_child(BdrvChild *child)
|
||||||
|
{
|
||||||
|
QLIST_REMOVE(child, next);
|
||||||
|
g_free(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
|
||||||
|
{
|
||||||
|
BlockDriverState *child_bs = child->bs;
|
||||||
|
|
||||||
|
if (child->bs->inherits_from == parent) {
|
||||||
|
child->bs->inherits_from = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_detach_child(child);
|
||||||
|
bdrv_unref(child_bs);
|
||||||
|
}
|
||||||
|
|
||||||
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (bs->backing_hd) {
|
if (bs->backing_hd) {
|
||||||
assert(bs->backing_blocker);
|
assert(bs->backing_blocker);
|
||||||
bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker);
|
bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker);
|
||||||
|
bdrv_detach_child(bs->backing_child);
|
||||||
} else if (backing_hd) {
|
} else if (backing_hd) {
|
||||||
error_setg(&bs->backing_blocker,
|
error_setg(&bs->backing_blocker,
|
||||||
"node is used as backing hd of '%s'",
|
"node is used as backing hd of '%s'",
|
||||||
@@ -1118,8 +1152,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
|||||||
if (!backing_hd) {
|
if (!backing_hd) {
|
||||||
error_free(bs->backing_blocker);
|
error_free(bs->backing_blocker);
|
||||||
bs->backing_blocker = NULL;
|
bs->backing_blocker = NULL;
|
||||||
|
bs->backing_child = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
bs->backing_child = bdrv_attach_child(bs, backing_hd, &child_backing);
|
||||||
bs->open_flags &= ~BDRV_O_NO_BACKING;
|
bs->open_flags &= ~BDRV_O_NO_BACKING;
|
||||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
|
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
|
||||||
pstrcpy(bs->backing_format, sizeof(bs->backing_format),
|
pstrcpy(bs->backing_format, sizeof(bs->backing_format),
|
||||||
@@ -1202,6 +1238,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
|||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
goto free_exit;
|
goto free_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_set_backing_hd(bs, backing_hd);
|
bdrv_set_backing_hd(bs, backing_hd);
|
||||||
|
|
||||||
free_exit:
|
free_exit:
|
||||||
@@ -1214,7 +1251,7 @@ free_exit:
|
|||||||
* device's options.
|
* device's options.
|
||||||
*
|
*
|
||||||
* If allow_none is true, no image will be opened if filename is false and no
|
* If allow_none is true, no image will be opened if filename is false and no
|
||||||
* BlockdevRef is given. *pbs will remain unchanged and 0 will be returned.
|
* BlockdevRef is given. NULL will be returned, but errp remains unset.
|
||||||
*
|
*
|
||||||
* bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
|
* bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
|
||||||
* That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
|
* That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
|
||||||
@@ -1222,6 +1259,56 @@ free_exit:
|
|||||||
* BlockdevRef.
|
* BlockdevRef.
|
||||||
*
|
*
|
||||||
* The BlockdevRef will be removed from the options QDict.
|
* The BlockdevRef will be removed from the options QDict.
|
||||||
|
*/
|
||||||
|
BdrvChild *bdrv_open_child(const char *filename,
|
||||||
|
QDict *options, const char *bdref_key,
|
||||||
|
BlockDriverState* parent,
|
||||||
|
const BdrvChildRole *child_role,
|
||||||
|
bool allow_none, Error **errp)
|
||||||
|
{
|
||||||
|
BdrvChild *c = NULL;
|
||||||
|
BlockDriverState *bs;
|
||||||
|
QDict *image_options;
|
||||||
|
int ret;
|
||||||
|
char *bdref_key_dot;
|
||||||
|
const char *reference;
|
||||||
|
|
||||||
|
assert(child_role != NULL);
|
||||||
|
|
||||||
|
bdref_key_dot = g_strdup_printf("%s.", bdref_key);
|
||||||
|
qdict_extract_subqdict(options, &image_options, bdref_key_dot);
|
||||||
|
g_free(bdref_key_dot);
|
||||||
|
|
||||||
|
reference = qdict_get_try_str(options, bdref_key);
|
||||||
|
if (!filename && !reference && !qdict_size(image_options)) {
|
||||||
|
if (!allow_none) {
|
||||||
|
error_setg(errp, "A block device must be specified for \"%s\"",
|
||||||
|
bdref_key);
|
||||||
|
}
|
||||||
|
QDECREF(image_options);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs = NULL;
|
||||||
|
ret = bdrv_open_inherit(&bs, filename, reference, image_options, 0,
|
||||||
|
parent, child_role, NULL, errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = bdrv_attach_child(parent, bs, child_role);
|
||||||
|
|
||||||
|
done:
|
||||||
|
qdict_del(options, bdref_key);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a version of bdrv_open_child() that returns 0/-EINVAL instead of
|
||||||
|
* a BdrvChild object.
|
||||||
|
*
|
||||||
|
* If allow_none is true, no image will be opened if filename is false and no
|
||||||
|
* BlockdevRef is given. *pbs will remain unchanged and 0 will be returned.
|
||||||
*
|
*
|
||||||
* To conform with the behavior of bdrv_open(), *pbs has to be NULL.
|
* To conform with the behavior of bdrv_open(), *pbs has to be NULL.
|
||||||
*/
|
*/
|
||||||
@@ -1230,37 +1317,24 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
|
|||||||
BlockDriverState* parent, const BdrvChildRole *child_role,
|
BlockDriverState* parent, const BdrvChildRole *child_role,
|
||||||
bool allow_none, Error **errp)
|
bool allow_none, Error **errp)
|
||||||
{
|
{
|
||||||
QDict *image_options;
|
Error *local_err = NULL;
|
||||||
int ret;
|
BdrvChild *c;
|
||||||
char *bdref_key_dot;
|
|
||||||
const char *reference;
|
|
||||||
|
|
||||||
assert(pbs);
|
assert(pbs);
|
||||||
assert(*pbs == NULL);
|
assert(*pbs == NULL);
|
||||||
|
|
||||||
bdref_key_dot = g_strdup_printf("%s.", bdref_key);
|
c = bdrv_open_child(filename, options, bdref_key, parent, child_role,
|
||||||
qdict_extract_subqdict(options, &image_options, bdref_key_dot);
|
allow_none, &local_err);
|
||||||
g_free(bdref_key_dot);
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
reference = qdict_get_try_str(options, bdref_key);
|
return -EINVAL;
|
||||||
if (!filename && !reference && !qdict_size(image_options)) {
|
|
||||||
if (allow_none) {
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
error_setg(errp, "A block device must be specified for \"%s\"",
|
|
||||||
bdref_key);
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
QDECREF(image_options);
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_open_inherit(pbs, filename, reference, image_options, 0,
|
if (c != NULL) {
|
||||||
parent, child_role, NULL, errp);
|
*pbs = c->bs;
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
return 0;
|
||||||
qdict_del(options, bdref_key);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
||||||
@@ -1271,7 +1345,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
|||||||
QemuOpts *opts = NULL;
|
QemuOpts *opts = NULL;
|
||||||
QDict *snapshot_options;
|
QDict *snapshot_options;
|
||||||
BlockDriverState *bs_snapshot;
|
BlockDriverState *bs_snapshot;
|
||||||
Error *local_err;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* if snapshot, we create a temporary backing file and open it
|
/* if snapshot, we create a temporary backing file and open it
|
||||||
@@ -1328,19 +1402,6 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_attach_child(BlockDriverState *parent_bs,
|
|
||||||
BlockDriverState *child_bs,
|
|
||||||
const BdrvChildRole *child_role)
|
|
||||||
{
|
|
||||||
BdrvChild *child = g_new(BdrvChild, 1);
|
|
||||||
*child = (BdrvChild) {
|
|
||||||
.bs = child_bs,
|
|
||||||
.role = child_role,
|
|
||||||
};
|
|
||||||
|
|
||||||
QLIST_INSERT_HEAD(&parent_bs->children, child, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opens a disk image (raw, qcow2, vmdk, ...)
|
* Opens a disk image (raw, qcow2, vmdk, ...)
|
||||||
*
|
*
|
||||||
@@ -1393,9 +1454,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
bdrv_ref(bs);
|
bdrv_ref(bs);
|
||||||
if (child_role) {
|
|
||||||
bdrv_attach_child(parent, bs, child_role);
|
|
||||||
}
|
|
||||||
*pbs = bs;
|
*pbs = bs;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1540,10 +1598,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
|
|||||||
goto close_and_fail;
|
goto close_and_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child_role) {
|
|
||||||
bdrv_attach_child(parent, bs, child_role);
|
|
||||||
}
|
|
||||||
|
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
*pbs = bs;
|
*pbs = bs;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1841,28 +1895,31 @@ void bdrv_close(BlockDriverState *bs)
|
|||||||
if (bs->job) {
|
if (bs->job) {
|
||||||
block_job_cancel_sync(bs->job);
|
block_job_cancel_sync(bs->job);
|
||||||
}
|
}
|
||||||
bdrv_drain_all(); /* complete I/O */
|
bdrv_drain(bs); /* complete I/O */
|
||||||
bdrv_flush(bs);
|
bdrv_flush(bs);
|
||||||
bdrv_drain_all(); /* in case flush left pending I/O */
|
bdrv_drain(bs); /* in case flush left pending I/O */
|
||||||
notifier_list_notify(&bs->close_notifiers, bs);
|
notifier_list_notify(&bs->close_notifiers, bs);
|
||||||
|
|
||||||
if (bs->drv) {
|
if (bs->drv) {
|
||||||
BdrvChild *child, *next;
|
BdrvChild *child, *next;
|
||||||
|
|
||||||
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
|
bs->drv->bdrv_close(bs);
|
||||||
if (child->bs->inherits_from == bs) {
|
|
||||||
child->bs->inherits_from = NULL;
|
|
||||||
}
|
|
||||||
QLIST_REMOVE(child, next);
|
|
||||||
g_free(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bs->backing_hd) {
|
if (bs->backing_hd) {
|
||||||
BlockDriverState *backing_hd = bs->backing_hd;
|
BlockDriverState *backing_hd = bs->backing_hd;
|
||||||
bdrv_set_backing_hd(bs, NULL);
|
bdrv_set_backing_hd(bs, NULL);
|
||||||
bdrv_unref(backing_hd);
|
bdrv_unref(backing_hd);
|
||||||
}
|
}
|
||||||
bs->drv->bdrv_close(bs);
|
|
||||||
|
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
|
||||||
|
/* TODO Remove bdrv_unref() from drivers' close function and use
|
||||||
|
* bdrv_unref_child() here */
|
||||||
|
if (child->bs->inherits_from == bs) {
|
||||||
|
child->bs->inherits_from = NULL;
|
||||||
|
}
|
||||||
|
bdrv_detach_child(child);
|
||||||
|
}
|
||||||
|
|
||||||
g_free(bs->opaque);
|
g_free(bs->opaque);
|
||||||
bs->opaque = NULL;
|
bs->opaque = NULL;
|
||||||
bs->drv = NULL;
|
bs->drv = NULL;
|
||||||
@@ -2116,7 +2173,6 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
|
|||||||
/* The contents of 'tmp' will become bs_top, as we are
|
/* The contents of 'tmp' will become bs_top, as we are
|
||||||
* swapping bs_new and bs_top contents. */
|
* swapping bs_new and bs_top contents. */
|
||||||
bdrv_set_backing_hd(bs_top, bs_new);
|
bdrv_set_backing_hd(bs_top, bs_new);
|
||||||
bdrv_attach_child(bs_top, bs_new, &child_backing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_delete(BlockDriverState *bs)
|
static void bdrv_delete(BlockDriverState *bs)
|
||||||
@@ -3906,7 +3962,7 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
|
|||||||
|
|
||||||
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
|
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
|
||||||
{
|
{
|
||||||
bdrv_drain_all(); /* ensure there are no in-flight requests */
|
bdrv_drain(bs); /* ensure there are no in-flight requests */
|
||||||
|
|
||||||
bdrv_detach_aio_context(bs);
|
bdrv_detach_aio_context(bs);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-c
|
|||||||
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||||
block-obj-y += qed-check.o
|
block-obj-y += qed-check.o
|
||||||
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
|
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
|
||||||
block-obj-$(CONFIG_QUORUM) += quorum.o
|
block-obj-y += quorum.o
|
||||||
block-obj-y += parallels.o blkdebug.o blkverify.o
|
block-obj-y += parallels.o blkdebug.o blkverify.o
|
||||||
block-obj-y += block-backend.o snapshot.o qapi.o
|
block-obj-y += block-backend.o snapshot.o qapi.o
|
||||||
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ static void coroutine_fn backup_run(void *opaque)
|
|||||||
|
|
||||||
if (job->sync_bitmap) {
|
if (job->sync_bitmap) {
|
||||||
BdrvDirtyBitmap *bm;
|
BdrvDirtyBitmap *bm;
|
||||||
if (ret < 0) {
|
if (ret < 0 || block_job_is_cancelled(&job->common)) {
|
||||||
/* Merge the successor back into the parent, delete nothing. */
|
/* Merge the successor back into the parent, delete nothing. */
|
||||||
bm = bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL);
|
bm = bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL);
|
||||||
assert(bm);
|
assert(bm);
|
||||||
|
|||||||
15
block/curl.c
15
block/curl.c
@@ -22,6 +22,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "qapi/qmp/qbool.h"
|
#include "qapi/qmp/qbool.h"
|
||||||
#include "qapi/qmp/qstring.h"
|
#include "qapi/qmp/qstring.h"
|
||||||
@@ -298,6 +299,18 @@ static void curl_multi_check_completion(BDRVCURLState *s)
|
|||||||
/* ACBs for successful messages get completed in curl_read_cb */
|
/* ACBs for successful messages get completed in curl_read_cb */
|
||||||
if (msg->data.result != CURLE_OK) {
|
if (msg->data.result != CURLE_OK) {
|
||||||
int i;
|
int i;
|
||||||
|
static int errcount = 100;
|
||||||
|
|
||||||
|
/* Don't lose the original error message from curl, since
|
||||||
|
* it contains extra data.
|
||||||
|
*/
|
||||||
|
if (errcount > 0) {
|
||||||
|
error_report("curl: %s", state->errmsg);
|
||||||
|
if (--errcount == 0) {
|
||||||
|
error_report("curl: further errors suppressed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < CURL_NUM_ACB; i++) {
|
for (i = 0; i < CURL_NUM_ACB; i++) {
|
||||||
CURLAIOCB *acb = state->acb[i];
|
CURLAIOCB *acb = state->acb[i];
|
||||||
|
|
||||||
@@ -305,7 +318,7 @@ static void curl_multi_check_completion(BDRVCURLState *s)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
acb->common.cb(acb->common.opaque, -EIO);
|
acb->common.cb(acb->common.opaque, -EPROTO);
|
||||||
qemu_aio_unref(acb);
|
qemu_aio_unref(acb);
|
||||||
state->acb[i] = NULL;
|
state->acb[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
20
block/io.c
20
block/io.c
@@ -236,12 +236,12 @@ static bool bdrv_requests_pending(BlockDriverState *bs)
|
|||||||
/*
|
/*
|
||||||
* Wait for pending requests to complete on a single BlockDriverState subtree
|
* Wait for pending requests to complete on a single BlockDriverState subtree
|
||||||
*
|
*
|
||||||
* See the warning in bdrv_drain_all(). This function can only be called if
|
|
||||||
* you are sure nothing can generate I/O because you have op blockers
|
|
||||||
* installed.
|
|
||||||
*
|
|
||||||
* Note that unlike bdrv_drain_all(), the caller must hold the BlockDriverState
|
* Note that unlike bdrv_drain_all(), the caller must hold the BlockDriverState
|
||||||
* AioContext.
|
* AioContext.
|
||||||
|
*
|
||||||
|
* Only this BlockDriverState's AioContext is run, so in-flight requests must
|
||||||
|
* not depend on events in other AioContexts. In that case, use
|
||||||
|
* bdrv_drain_all() instead.
|
||||||
*/
|
*/
|
||||||
void bdrv_drain(BlockDriverState *bs)
|
void bdrv_drain(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
@@ -260,12 +260,6 @@ void bdrv_drain(BlockDriverState *bs)
|
|||||||
*
|
*
|
||||||
* This function does not flush data to disk, use bdrv_flush_all() for that
|
* This function does not flush data to disk, use bdrv_flush_all() for that
|
||||||
* after calling this function.
|
* after calling this function.
|
||||||
*
|
|
||||||
* Note that completion of an asynchronous I/O operation can trigger any
|
|
||||||
* number of other I/O operations on other devices---for example a coroutine
|
|
||||||
* can be arbitrarily complex and a constant flow of I/O can come until the
|
|
||||||
* coroutine is complete. Because of this, it is not possible to have a
|
|
||||||
* function to drain a single device's I/O queue.
|
|
||||||
*/
|
*/
|
||||||
void bdrv_drain_all(void)
|
void bdrv_drain_all(void)
|
||||||
{
|
{
|
||||||
@@ -288,6 +282,12 @@ void bdrv_drain_all(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note that completion of an asynchronous I/O operation can trigger any
|
||||||
|
* number of other I/O operations on other devices---for example a
|
||||||
|
* coroutine can submit an I/O request to another device in response to
|
||||||
|
* request completion. Therefore we must keep looping until there was no
|
||||||
|
* more activity rather than simply draining each device independently.
|
||||||
|
*/
|
||||||
while (busy) {
|
while (busy) {
|
||||||
busy = false;
|
busy = false;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#define SLICE_TIME 100000000ULL /* ns */
|
#define SLICE_TIME 100000000ULL /* ns */
|
||||||
#define MAX_IN_FLIGHT 16
|
#define MAX_IN_FLIGHT 16
|
||||||
|
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
|
||||||
|
|
||||||
/* The mirroring buffer is a list of granularity-sized chunks.
|
/* The mirroring buffer is a list of granularity-sized chunks.
|
||||||
* Free chunks are organized in a list.
|
* Free chunks are organized in a list.
|
||||||
@@ -444,11 +445,23 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
|
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
|
||||||
mirror_free_init(s);
|
mirror_free_init(s);
|
||||||
|
|
||||||
|
last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||||
if (!s->is_none_mode) {
|
if (!s->is_none_mode) {
|
||||||
/* First part, loop on the sectors and initialize the dirty bitmap. */
|
/* First part, loop on the sectors and initialize the dirty bitmap. */
|
||||||
BlockDriverState *base = s->base;
|
BlockDriverState *base = s->base;
|
||||||
for (sector_num = 0; sector_num < end; ) {
|
for (sector_num = 0; sector_num < end; ) {
|
||||||
int64_t next = (sector_num | (sectors_per_chunk - 1)) + 1;
|
int64_t next = (sector_num | (sectors_per_chunk - 1)) + 1;
|
||||||
|
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||||
|
|
||||||
|
if (now - last_pause_ns > SLICE_TIME) {
|
||||||
|
last_pause_ns = now;
|
||||||
|
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block_job_is_cancelled(&s->common)) {
|
||||||
|
goto immediate_exit;
|
||||||
|
}
|
||||||
|
|
||||||
ret = bdrv_is_allocated_above(bs, base,
|
ret = bdrv_is_allocated_above(bs, base,
|
||||||
sector_num, next - sector_num, &n);
|
sector_num, next - sector_num, &n);
|
||||||
|
|
||||||
@@ -467,7 +480,6 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
|
bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
|
||||||
last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint64_t delay_ns = 0;
|
uint64_t delay_ns = 0;
|
||||||
int64_t cnt;
|
int64_t cnt;
|
||||||
@@ -690,6 +702,14 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buf_size < 0) {
|
||||||
|
error_setg(errp, "Invalid parameter 'buf-size'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf_size == 0) {
|
||||||
|
buf_size = DEFAULT_MIRROR_BUF_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
s = block_job_create(driver, bs, speed, cb, opaque, errp);
|
s = block_job_create(driver, bs, speed, cb, opaque, errp);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
@@ -703,11 +723,13 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
|||||||
s->is_none_mode = is_none_mode;
|
s->is_none_mode = is_none_mode;
|
||||||
s->base = base;
|
s->base = base;
|
||||||
s->granularity = granularity;
|
s->granularity = granularity;
|
||||||
s->buf_size = MAX(buf_size, granularity);
|
s->buf_size = ROUND_UP(buf_size, granularity);
|
||||||
s->unmap = unmap;
|
s->unmap = unmap;
|
||||||
|
|
||||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
|
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
|
||||||
if (!s->dirty_bitmap) {
|
if (!s->dirty_bitmap) {
|
||||||
|
g_free(s->replaces);
|
||||||
|
block_job_release(bs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bdrv_set_enable_write_cache(s->target, true);
|
bdrv_set_enable_write_cache(s->target, true);
|
||||||
|
|||||||
102
block/qcow.c
102
block/qcow.c
@@ -26,7 +26,7 @@
|
|||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "qemu/aes.h"
|
#include "crypto/cipher.h"
|
||||||
#include "migration/migration.h"
|
#include "migration/migration.h"
|
||||||
|
|
||||||
/**************************************************************/
|
/**************************************************************/
|
||||||
@@ -72,10 +72,8 @@ typedef struct BDRVQcowState {
|
|||||||
uint8_t *cluster_cache;
|
uint8_t *cluster_cache;
|
||||||
uint8_t *cluster_data;
|
uint8_t *cluster_data;
|
||||||
uint64_t cluster_cache_offset;
|
uint64_t cluster_cache_offset;
|
||||||
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
|
QCryptoCipher *cipher; /* NULL if no key yet */
|
||||||
uint32_t crypt_method_header;
|
uint32_t crypt_method_header;
|
||||||
AES_KEY aes_encrypt_key;
|
|
||||||
AES_KEY aes_decrypt_key;
|
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
Error *migration_blocker;
|
Error *migration_blocker;
|
||||||
} BDRVQcowState;
|
} BDRVQcowState;
|
||||||
@@ -154,6 +152,11 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128)) {
|
||||||
|
error_setg(errp, "AES cipher not available");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->crypt_method_header = header.crypt_method;
|
s->crypt_method_header = header.crypt_method;
|
||||||
if (s->crypt_method_header) {
|
if (s->crypt_method_header) {
|
||||||
bs->encrypted = 1;
|
bs->encrypted = 1;
|
||||||
@@ -260,6 +263,7 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
|
|||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint8_t keybuf[16];
|
uint8_t keybuf[16];
|
||||||
int len, i;
|
int len, i;
|
||||||
|
Error *err;
|
||||||
|
|
||||||
memset(keybuf, 0, 16);
|
memset(keybuf, 0, 16);
|
||||||
len = strlen(key);
|
len = strlen(key);
|
||||||
@@ -271,38 +275,67 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
|
|||||||
keybuf[i] = key[i];
|
keybuf[i] = key[i];
|
||||||
}
|
}
|
||||||
assert(bs->encrypted);
|
assert(bs->encrypted);
|
||||||
s->crypt_method = s->crypt_method_header;
|
|
||||||
|
|
||||||
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
|
qcrypto_cipher_free(s->cipher);
|
||||||
return -1;
|
s->cipher = qcrypto_cipher_new(
|
||||||
if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
|
QCRYPTO_CIPHER_ALG_AES_128,
|
||||||
|
QCRYPTO_CIPHER_MODE_CBC,
|
||||||
|
keybuf, G_N_ELEMENTS(keybuf),
|
||||||
|
&err);
|
||||||
|
|
||||||
|
if (!s->cipher) {
|
||||||
|
/* XXX would be nice if errors in this method could
|
||||||
|
* be properly propagate to the caller. Would need
|
||||||
|
* the bdrv_set_key() API signature to be fixed. */
|
||||||
|
error_free(err);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The crypt function is compatible with the linux cryptoloop
|
/* The crypt function is compatible with the linux cryptoloop
|
||||||
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
|
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
|
||||||
supported */
|
supported */
|
||||||
static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
||||||
uint8_t *out_buf, const uint8_t *in_buf,
|
uint8_t *out_buf, const uint8_t *in_buf,
|
||||||
int nb_sectors, int enc,
|
int nb_sectors, bool enc, Error **errp)
|
||||||
const AES_KEY *key)
|
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
uint64_t ll[2];
|
uint64_t ll[2];
|
||||||
uint8_t b[16];
|
uint8_t b[16];
|
||||||
} ivec;
|
} ivec;
|
||||||
int i;
|
int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
for(i = 0; i < nb_sectors; i++) {
|
for(i = 0; i < nb_sectors; i++) {
|
||||||
ivec.ll[0] = cpu_to_le64(sector_num);
|
ivec.ll[0] = cpu_to_le64(sector_num);
|
||||||
ivec.ll[1] = 0;
|
ivec.ll[1] = 0;
|
||||||
AES_cbc_encrypt(in_buf, out_buf, 512, key,
|
if (qcrypto_cipher_setiv(s->cipher,
|
||||||
ivec.b, enc);
|
ivec.b, G_N_ELEMENTS(ivec.b),
|
||||||
|
errp) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (enc) {
|
||||||
|
ret = qcrypto_cipher_encrypt(s->cipher,
|
||||||
|
in_buf,
|
||||||
|
out_buf,
|
||||||
|
512,
|
||||||
|
errp);
|
||||||
|
} else {
|
||||||
|
ret = qcrypto_cipher_decrypt(s->cipher,
|
||||||
|
in_buf,
|
||||||
|
out_buf,
|
||||||
|
512,
|
||||||
|
errp);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
sector_num++;
|
sector_num++;
|
||||||
in_buf += 512;
|
in_buf += 512;
|
||||||
out_buf += 512;
|
out_buf += 512;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 'allocate' is:
|
/* 'allocate' is:
|
||||||
@@ -416,15 +449,20 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
if (bs->encrypted &&
|
if (bs->encrypted &&
|
||||||
(n_end - n_start) < s->cluster_sectors) {
|
(n_end - n_start) < s->cluster_sectors) {
|
||||||
uint64_t start_sect;
|
uint64_t start_sect;
|
||||||
assert(s->crypt_method);
|
assert(s->cipher);
|
||||||
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
|
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
|
||||||
memset(s->cluster_data + 512, 0x00, 512);
|
memset(s->cluster_data + 512, 0x00, 512);
|
||||||
for(i = 0; i < s->cluster_sectors; i++) {
|
for(i = 0; i < s->cluster_sectors; i++) {
|
||||||
if (i < n_start || i >= n_end) {
|
if (i < n_start || i >= n_end) {
|
||||||
encrypt_sectors(s, start_sect + i,
|
Error *err = NULL;
|
||||||
s->cluster_data,
|
if (encrypt_sectors(s, start_sect + i,
|
||||||
s->cluster_data + 512, 1, 1,
|
s->cluster_data,
|
||||||
&s->aes_encrypt_key);
|
s->cluster_data + 512, 1,
|
||||||
|
true, &err) < 0) {
|
||||||
|
error_free(err);
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (bdrv_pwrite(bs->file, cluster_offset + i * 512,
|
if (bdrv_pwrite(bs->file, cluster_offset + i * 512,
|
||||||
s->cluster_data, 512) != 512)
|
s->cluster_data, 512) != 512)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -464,7 +502,7 @@ static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
|
|||||||
if (!cluster_offset) {
|
if (!cluster_offset) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypt_method) {
|
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->cipher) {
|
||||||
return BDRV_BLOCK_DATA;
|
return BDRV_BLOCK_DATA;
|
||||||
}
|
}
|
||||||
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
|
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
|
||||||
@@ -531,6 +569,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
QEMUIOVector hd_qiov;
|
QEMUIOVector hd_qiov;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
void *orig_buf;
|
void *orig_buf;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
if (qiov->niov > 1) {
|
if (qiov->niov > 1) {
|
||||||
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
|
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
|
||||||
@@ -594,10 +633,11 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
assert(s->crypt_method);
|
assert(s->cipher);
|
||||||
encrypt_sectors(s, sector_num, buf, buf,
|
if (encrypt_sectors(s, sector_num, buf, buf,
|
||||||
n, 0,
|
n, false, &err) < 0) {
|
||||||
&s->aes_decrypt_key);
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -618,6 +658,7 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
error_free(err);
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -666,12 +707,17 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
assert(s->crypt_method);
|
Error *err = NULL;
|
||||||
|
assert(s->cipher);
|
||||||
if (!cluster_data) {
|
if (!cluster_data) {
|
||||||
cluster_data = g_malloc0(s->cluster_size);
|
cluster_data = g_malloc0(s->cluster_size);
|
||||||
}
|
}
|
||||||
encrypt_sectors(s, sector_num, cluster_data, buf,
|
if (encrypt_sectors(s, sector_num, cluster_data, buf,
|
||||||
n, 1, &s->aes_encrypt_key);
|
n, true, &err) < 0) {
|
||||||
|
error_free(err);
|
||||||
|
ret = -EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
src_buf = cluster_data;
|
src_buf = cluster_data;
|
||||||
} else {
|
} else {
|
||||||
src_buf = buf;
|
src_buf = buf;
|
||||||
@@ -708,6 +754,8 @@ static void qcow_close(BlockDriverState *bs)
|
|||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
|
||||||
|
qcrypto_cipher_free(s->cipher);
|
||||||
|
s->cipher = NULL;
|
||||||
g_free(s->l1_table);
|
g_free(s->l1_table);
|
||||||
qemu_vfree(s->l2_cache);
|
qemu_vfree(s->l2_cache);
|
||||||
g_free(s->cluster_cache);
|
g_free(s->cluster_cache);
|
||||||
|
|||||||
@@ -281,9 +281,6 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
|
|||||||
i = min_lru_index;
|
i = min_lru_index;
|
||||||
trace_qcow2_cache_get_replace_entry(qemu_coroutine_self(),
|
trace_qcow2_cache_get_replace_entry(qemu_coroutine_self(),
|
||||||
c == s->l2_table_cache, i);
|
c == s->l2_table_cache, i);
|
||||||
if (i < 0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = qcow2_cache_entry_flush(bs, c, i);
|
ret = qcow2_cache_entry_flush(bs, c, i);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|||||||
@@ -339,26 +339,47 @@ static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_tab
|
|||||||
/* The crypt function is compatible with the linux cryptoloop
|
/* The crypt function is compatible with the linux cryptoloop
|
||||||
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
|
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
|
||||||
supported */
|
supported */
|
||||||
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
int qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
||||||
uint8_t *out_buf, const uint8_t *in_buf,
|
uint8_t *out_buf, const uint8_t *in_buf,
|
||||||
int nb_sectors, int enc,
|
int nb_sectors, bool enc,
|
||||||
const AES_KEY *key)
|
Error **errp)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
uint64_t ll[2];
|
uint64_t ll[2];
|
||||||
uint8_t b[16];
|
uint8_t b[16];
|
||||||
} ivec;
|
} ivec;
|
||||||
int i;
|
int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
for(i = 0; i < nb_sectors; i++) {
|
for(i = 0; i < nb_sectors; i++) {
|
||||||
ivec.ll[0] = cpu_to_le64(sector_num);
|
ivec.ll[0] = cpu_to_le64(sector_num);
|
||||||
ivec.ll[1] = 0;
|
ivec.ll[1] = 0;
|
||||||
AES_cbc_encrypt(in_buf, out_buf, 512, key,
|
if (qcrypto_cipher_setiv(s->cipher,
|
||||||
ivec.b, enc);
|
ivec.b, G_N_ELEMENTS(ivec.b),
|
||||||
|
errp) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (enc) {
|
||||||
|
ret = qcrypto_cipher_encrypt(s->cipher,
|
||||||
|
in_buf,
|
||||||
|
out_buf,
|
||||||
|
512,
|
||||||
|
errp);
|
||||||
|
} else {
|
||||||
|
ret = qcrypto_cipher_decrypt(s->cipher,
|
||||||
|
in_buf,
|
||||||
|
out_buf,
|
||||||
|
512,
|
||||||
|
errp);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
sector_num++;
|
sector_num++;
|
||||||
in_buf += 512;
|
in_buf += 512;
|
||||||
out_buf += 512;
|
out_buf += 512;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
||||||
@@ -401,10 +422,15 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
assert(s->crypt_method);
|
Error *err = NULL;
|
||||||
qcow2_encrypt_sectors(s, start_sect + n_start,
|
assert(s->cipher);
|
||||||
iov.iov_base, iov.iov_base, n, 1,
|
if (qcow2_encrypt_sectors(s, start_sect + n_start,
|
||||||
&s->aes_encrypt_key);
|
iov.iov_base, iov.iov_base, n,
|
||||||
|
true, &err) < 0) {
|
||||||
|
ret = -EIO;
|
||||||
|
error_free(err);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_pre_write_overlap_check(bs, 0,
|
ret = qcow2_pre_write_overlap_check(bs, 0,
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include "qemu/aes.h"
|
|
||||||
#include "block/qcow2.h"
|
#include "block/qcow2.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
@@ -699,6 +698,11 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128)) {
|
||||||
|
error_setg(errp, "AES cipher not available");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->crypt_method_header = header.crypt_method;
|
s->crypt_method_header = header.crypt_method;
|
||||||
if (s->crypt_method_header) {
|
if (s->crypt_method_header) {
|
||||||
bs->encrypted = 1;
|
bs->encrypted = 1;
|
||||||
@@ -1032,6 +1036,7 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
|
|||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint8_t keybuf[16];
|
uint8_t keybuf[16];
|
||||||
int len, i;
|
int len, i;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
memset(keybuf, 0, 16);
|
memset(keybuf, 0, 16);
|
||||||
len = strlen(key);
|
len = strlen(key);
|
||||||
@@ -1043,30 +1048,21 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
|
|||||||
keybuf[i] = key[i];
|
keybuf[i] = key[i];
|
||||||
}
|
}
|
||||||
assert(bs->encrypted);
|
assert(bs->encrypted);
|
||||||
s->crypt_method = s->crypt_method_header;
|
|
||||||
|
|
||||||
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
|
qcrypto_cipher_free(s->cipher);
|
||||||
|
s->cipher = qcrypto_cipher_new(
|
||||||
|
QCRYPTO_CIPHER_ALG_AES_128,
|
||||||
|
QCRYPTO_CIPHER_MODE_CBC,
|
||||||
|
keybuf, G_N_ELEMENTS(keybuf),
|
||||||
|
&err);
|
||||||
|
|
||||||
|
if (!s->cipher) {
|
||||||
|
/* XXX would be nice if errors in this method could
|
||||||
|
* be properly propagate to the caller. Would need
|
||||||
|
* the bdrv_set_key() API signature to be fixed. */
|
||||||
|
error_free(err);
|
||||||
return -1;
|
return -1;
|
||||||
if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
|
|
||||||
return -1;
|
|
||||||
#if 0
|
|
||||||
/* test */
|
|
||||||
{
|
|
||||||
uint8_t in[16];
|
|
||||||
uint8_t out[16];
|
|
||||||
uint8_t tmp[16];
|
|
||||||
for(i=0;i<16;i++)
|
|
||||||
in[i] = i;
|
|
||||||
AES_encrypt(in, tmp, &s->aes_encrypt_key);
|
|
||||||
AES_decrypt(tmp, out, &s->aes_decrypt_key);
|
|
||||||
for(i = 0; i < 16; i++)
|
|
||||||
printf(" %02x", tmp[i]);
|
|
||||||
printf("\n");
|
|
||||||
for(i = 0; i < 16; i++)
|
|
||||||
printf(" %02x", out[i]);
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1109,7 +1105,7 @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED &&
|
if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED &&
|
||||||
!s->crypt_method) {
|
!s->cipher) {
|
||||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||||
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
|
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
|
||||||
status |= BDRV_BLOCK_OFFSET_VALID | cluster_offset;
|
status |= BDRV_BLOCK_OFFSET_VALID | cluster_offset;
|
||||||
@@ -1159,7 +1155,7 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
|
|
||||||
/* prepare next request */
|
/* prepare next request */
|
||||||
cur_nr_sectors = remaining_sectors;
|
cur_nr_sectors = remaining_sectors;
|
||||||
if (s->crypt_method) {
|
if (s->cipher) {
|
||||||
cur_nr_sectors = MIN(cur_nr_sectors,
|
cur_nr_sectors = MIN(cur_nr_sectors,
|
||||||
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors);
|
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors);
|
||||||
}
|
}
|
||||||
@@ -1231,7 +1227,7 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
assert(s->crypt_method);
|
assert(s->cipher);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For encrypted images, read everything into a temporary
|
* For encrypted images, read everything into a temporary
|
||||||
@@ -1264,9 +1260,15 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
assert(s->crypt_method);
|
assert(s->cipher);
|
||||||
qcow2_encrypt_sectors(s, sector_num, cluster_data,
|
Error *err = NULL;
|
||||||
cluster_data, cur_nr_sectors, 0, &s->aes_decrypt_key);
|
if (qcow2_encrypt_sectors(s, sector_num, cluster_data,
|
||||||
|
cluster_data, cur_nr_sectors, false,
|
||||||
|
&err) < 0) {
|
||||||
|
error_free(err);
|
||||||
|
ret = -EIO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
qemu_iovec_from_buf(qiov, bytes_done,
|
qemu_iovec_from_buf(qiov, bytes_done,
|
||||||
cluster_data, 512 * cur_nr_sectors);
|
cluster_data, 512 * cur_nr_sectors);
|
||||||
}
|
}
|
||||||
@@ -1344,7 +1346,8 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
|||||||
cur_nr_sectors * 512);
|
cur_nr_sectors * 512);
|
||||||
|
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
assert(s->crypt_method);
|
Error *err = NULL;
|
||||||
|
assert(s->cipher);
|
||||||
if (!cluster_data) {
|
if (!cluster_data) {
|
||||||
cluster_data = qemu_try_blockalign(bs->file,
|
cluster_data = qemu_try_blockalign(bs->file,
|
||||||
QCOW_MAX_CRYPT_CLUSTERS
|
QCOW_MAX_CRYPT_CLUSTERS
|
||||||
@@ -1359,8 +1362,13 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
|||||||
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
|
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
|
||||||
qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size);
|
qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size);
|
||||||
|
|
||||||
qcow2_encrypt_sectors(s, sector_num, cluster_data,
|
if (qcow2_encrypt_sectors(s, sector_num, cluster_data,
|
||||||
cluster_data, cur_nr_sectors, 1, &s->aes_encrypt_key);
|
cluster_data, cur_nr_sectors,
|
||||||
|
true, &err) < 0) {
|
||||||
|
error_free(err);
|
||||||
|
ret = -EIO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_iovec_reset(&hd_qiov);
|
qemu_iovec_reset(&hd_qiov);
|
||||||
qemu_iovec_add(&hd_qiov, cluster_data,
|
qemu_iovec_add(&hd_qiov, cluster_data,
|
||||||
@@ -1466,6 +1474,9 @@ static void qcow2_close(BlockDriverState *bs)
|
|||||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||||
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
||||||
|
|
||||||
|
qcrypto_cipher_free(s->cipher);
|
||||||
|
s->cipher = NULL;
|
||||||
|
|
||||||
g_free(s->unknown_header_fields);
|
g_free(s->unknown_header_fields);
|
||||||
cleanup_unknown_header_ext(bs);
|
cleanup_unknown_header_ext(bs);
|
||||||
|
|
||||||
@@ -1482,9 +1493,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
|
|||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int flags = s->flags;
|
int flags = s->flags;
|
||||||
AES_KEY aes_encrypt_key;
|
QCryptoCipher *cipher = NULL;
|
||||||
AES_KEY aes_decrypt_key;
|
|
||||||
uint32_t crypt_method = 0;
|
|
||||||
QDict *options;
|
QDict *options;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1494,12 +1503,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
|
|||||||
* that means we don't have to worry about reopening them here.
|
* that means we don't have to worry about reopening them here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (bs->encrypted) {
|
cipher = s->cipher;
|
||||||
assert(s->crypt_method);
|
s->cipher = NULL;
|
||||||
crypt_method = s->crypt_method;
|
|
||||||
memcpy(&aes_encrypt_key, &s->aes_encrypt_key, sizeof(aes_encrypt_key));
|
|
||||||
memcpy(&aes_decrypt_key, &s->aes_decrypt_key, sizeof(aes_decrypt_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
qcow2_close(bs);
|
qcow2_close(bs);
|
||||||
|
|
||||||
@@ -1524,11 +1529,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->encrypted) {
|
s->cipher = cipher;
|
||||||
s->crypt_method = crypt_method;
|
|
||||||
memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key));
|
|
||||||
memcpy(&s->aes_decrypt_key, &aes_decrypt_key, sizeof(aes_decrypt_key));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t header_ext_add(char *buf, uint32_t magic, const void *s,
|
static size_t header_ext_add(char *buf, uint32_t magic, const void *s,
|
||||||
@@ -2729,8 +2730,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
|
|||||||
backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
|
backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
|
||||||
} else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT)) {
|
} else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT)) {
|
||||||
encrypt = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT,
|
encrypt = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT,
|
||||||
s->crypt_method);
|
!!s->cipher);
|
||||||
if (encrypt != !!s->crypt_method) {
|
|
||||||
|
if (encrypt != !!s->cipher) {
|
||||||
fprintf(stderr, "Changing the encryption flag is not "
|
fprintf(stderr, "Changing the encryption flag is not "
|
||||||
"supported.\n");
|
"supported.\n");
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
#ifndef BLOCK_QCOW2_H
|
#ifndef BLOCK_QCOW2_H
|
||||||
#define BLOCK_QCOW2_H
|
#define BLOCK_QCOW2_H
|
||||||
|
|
||||||
#include "qemu/aes.h"
|
#include "crypto/cipher.h"
|
||||||
#include "block/coroutine.h"
|
#include "block/coroutine.h"
|
||||||
|
|
||||||
//#define DEBUG_ALLOC
|
//#define DEBUG_ALLOC
|
||||||
@@ -253,10 +253,8 @@ typedef struct BDRVQcowState {
|
|||||||
|
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
|
|
||||||
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
|
QCryptoCipher *cipher; /* current cipher, NULL if no key yet */
|
||||||
uint32_t crypt_method_header;
|
uint32_t crypt_method_header;
|
||||||
AES_KEY aes_encrypt_key;
|
|
||||||
AES_KEY aes_decrypt_key;
|
|
||||||
uint64_t snapshots_offset;
|
uint64_t snapshots_offset;
|
||||||
int snapshots_size;
|
int snapshots_size;
|
||||||
unsigned int nb_snapshots;
|
unsigned int nb_snapshots;
|
||||||
@@ -536,10 +534,9 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
|
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
|
||||||
void qcow2_l2_cache_reset(BlockDriverState *bs);
|
void qcow2_l2_cache_reset(BlockDriverState *bs);
|
||||||
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
|
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
|
||||||
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
int qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
||||||
uint8_t *out_buf, const uint8_t *in_buf,
|
uint8_t *out_buf, const uint8_t *in_buf,
|
||||||
int nb_sectors, int enc,
|
int nb_sectors, bool enc, Error **errp);
|
||||||
const AES_KEY *key);
|
|
||||||
|
|
||||||
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int *num, uint64_t *cluster_offset);
|
int *num, uint64_t *cluster_offset);
|
||||||
|
|||||||
@@ -13,8 +13,6 @@
|
|||||||
* See the COPYING file in the top-level directory.
|
* See the COPYING file in the top-level directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gnutls/gnutls.h>
|
|
||||||
#include <gnutls/crypto.h>
|
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "qapi/qmp/qbool.h"
|
#include "qapi/qmp/qbool.h"
|
||||||
#include "qapi/qmp/qdict.h"
|
#include "qapi/qmp/qdict.h"
|
||||||
@@ -24,6 +22,7 @@
|
|||||||
#include "qapi/qmp/qlist.h"
|
#include "qapi/qmp/qlist.h"
|
||||||
#include "qapi/qmp/qstring.h"
|
#include "qapi/qmp/qstring.h"
|
||||||
#include "qapi-event.h"
|
#include "qapi-event.h"
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
|
||||||
#define HASH_LENGTH 32
|
#define HASH_LENGTH 32
|
||||||
|
|
||||||
@@ -34,7 +33,7 @@
|
|||||||
|
|
||||||
/* This union holds a vote hash value */
|
/* This union holds a vote hash value */
|
||||||
typedef union QuorumVoteValue {
|
typedef union QuorumVoteValue {
|
||||||
char h[HASH_LENGTH]; /* SHA-256 hash */
|
uint8_t h[HASH_LENGTH]; /* SHA-256 hash */
|
||||||
int64_t l; /* simpler 64 bits hash */
|
int64_t l; /* simpler 64 bits hash */
|
||||||
} QuorumVoteValue;
|
} QuorumVoteValue;
|
||||||
|
|
||||||
@@ -428,25 +427,21 @@ static void quorum_free_vote_list(QuorumVotes *votes)
|
|||||||
|
|
||||||
static int quorum_compute_hash(QuorumAIOCB *acb, int i, QuorumVoteValue *hash)
|
static int quorum_compute_hash(QuorumAIOCB *acb, int i, QuorumVoteValue *hash)
|
||||||
{
|
{
|
||||||
int j, ret;
|
|
||||||
gnutls_hash_hd_t dig;
|
|
||||||
QEMUIOVector *qiov = &acb->qcrs[i].qiov;
|
QEMUIOVector *qiov = &acb->qcrs[i].qiov;
|
||||||
|
size_t len = sizeof(hash->h);
|
||||||
|
uint8_t *data = hash->h;
|
||||||
|
|
||||||
ret = gnutls_hash_init(&dig, GNUTLS_DIG_SHA256);
|
/* XXX - would be nice if we could pass in the Error **
|
||||||
|
* and propagate that back, but this quorum code is
|
||||||
if (ret < 0) {
|
* restricted to just errno values currently */
|
||||||
return ret;
|
if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256,
|
||||||
|
qiov->iov, qiov->niov,
|
||||||
|
&data, &len,
|
||||||
|
NULL) < 0) {
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < qiov->niov; j++) {
|
return 0;
|
||||||
ret = gnutls_hash(dig, qiov->iov[j].iov_base, qiov->iov[j].iov_len);
|
|
||||||
if (ret < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gnutls_hash_deinit(dig, (void *) hash);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QuorumVoteVersion *quorum_get_vote_winner(QuorumVotes *votes)
|
static QuorumVoteVersion *quorum_get_vote_winner(QuorumVotes *votes)
|
||||||
@@ -870,6 +865,12 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
int i;
|
int i;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA256)) {
|
||||||
|
error_setg(errp,
|
||||||
|
"SHA256 hash support is required for quorum device");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
qdict_flatten(options);
|
qdict_flatten(options);
|
||||||
|
|
||||||
/* count how many different children are present */
|
/* count how many different children are present */
|
||||||
|
|||||||
@@ -2430,7 +2430,8 @@ static int floppy_probe_device(const char *filename)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (strstart(filename, "/dev/fd", NULL) &&
|
if (strstart(filename, "/dev/fd", NULL) &&
|
||||||
!strstart(filename, "/dev/fdset/", NULL)) {
|
!strstart(filename, "/dev/fdset/", NULL) &&
|
||||||
|
!strstart(filename, "/dev/fd/", NULL)) {
|
||||||
prio = 50;
|
prio = 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
64
block/rbd.c
64
block/rbd.c
@@ -74,25 +74,18 @@ typedef struct RBDAIOCB {
|
|||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
char *bounce;
|
char *bounce;
|
||||||
RBDAIOCmd cmd;
|
RBDAIOCmd cmd;
|
||||||
int64_t sector_num;
|
|
||||||
int error;
|
int error;
|
||||||
struct BDRVRBDState *s;
|
struct BDRVRBDState *s;
|
||||||
int status;
|
|
||||||
} RBDAIOCB;
|
} RBDAIOCB;
|
||||||
|
|
||||||
typedef struct RADOSCB {
|
typedef struct RADOSCB {
|
||||||
int rcbid;
|
|
||||||
RBDAIOCB *acb;
|
RBDAIOCB *acb;
|
||||||
struct BDRVRBDState *s;
|
struct BDRVRBDState *s;
|
||||||
int done;
|
|
||||||
int64_t size;
|
int64_t size;
|
||||||
char *buf;
|
char *buf;
|
||||||
int64_t ret;
|
int64_t ret;
|
||||||
} RADOSCB;
|
} RADOSCB;
|
||||||
|
|
||||||
#define RBD_FD_READ 0
|
|
||||||
#define RBD_FD_WRITE 1
|
|
||||||
|
|
||||||
typedef struct BDRVRBDState {
|
typedef struct BDRVRBDState {
|
||||||
rados_t cluster;
|
rados_t cluster;
|
||||||
rados_ioctx_t io_ctx;
|
rados_ioctx_t io_ctx;
|
||||||
@@ -235,7 +228,9 @@ static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
static int qemu_rbd_set_conf(rados_t cluster, const char *conf,
|
||||||
|
bool only_read_conf_file,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
char *p, *buf;
|
char *p, *buf;
|
||||||
char name[RBD_MAX_CONF_NAME_SIZE];
|
char name[RBD_MAX_CONF_NAME_SIZE];
|
||||||
@@ -267,14 +262,18 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
|
|||||||
qemu_rbd_unescape(value);
|
qemu_rbd_unescape(value);
|
||||||
|
|
||||||
if (strcmp(name, "conf") == 0) {
|
if (strcmp(name, "conf") == 0) {
|
||||||
ret = rados_conf_read_file(cluster, value);
|
/* read the conf file alone, so it doesn't override more
|
||||||
if (ret < 0) {
|
specific settings for a particular device */
|
||||||
error_setg(errp, "error reading conf file %s", value);
|
if (only_read_conf_file) {
|
||||||
break;
|
ret = rados_conf_read_file(cluster, value);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "error reading conf file %s", value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (strcmp(name, "id") == 0) {
|
} else if (strcmp(name, "id") == 0) {
|
||||||
/* ignore, this is parsed by qemu_rbd_parse_clientname() */
|
/* ignore, this is parsed by qemu_rbd_parse_clientname() */
|
||||||
} else {
|
} else if (!only_read_conf_file) {
|
||||||
ret = rados_conf_set(cluster, name, value);
|
ret = rados_conf_set(cluster, name, value);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "invalid conf option %s", name);
|
error_setg(errp, "invalid conf option %s", name);
|
||||||
@@ -337,10 +336,15 @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
if (strstr(conf, "conf=") == NULL) {
|
if (strstr(conf, "conf=") == NULL) {
|
||||||
/* try default location, but ignore failure */
|
/* try default location, but ignore failure */
|
||||||
rados_conf_read_file(cluster, NULL);
|
rados_conf_read_file(cluster, NULL);
|
||||||
|
} else if (conf[0] != '\0' &&
|
||||||
|
qemu_rbd_set_conf(cluster, conf, true, &local_err) < 0) {
|
||||||
|
rados_shutdown(cluster);
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf[0] != '\0' &&
|
if (conf[0] != '\0' &&
|
||||||
qemu_rbd_set_conf(cluster, conf, &local_err) < 0) {
|
qemu_rbd_set_conf(cluster, conf, false, &local_err) < 0) {
|
||||||
rados_shutdown(cluster);
|
rados_shutdown(cluster);
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
@@ -405,7 +409,6 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
|
|||||||
}
|
}
|
||||||
qemu_vfree(acb->bounce);
|
qemu_vfree(acb->bounce);
|
||||||
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
|
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
|
||||||
acb->status = 0;
|
|
||||||
|
|
||||||
qemu_aio_unref(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
}
|
||||||
@@ -468,6 +471,23 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->snap = g_strdup(snap_buf);
|
s->snap = g_strdup(snap_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strstr(conf, "conf=") == NULL) {
|
||||||
|
/* try default location, but ignore failure */
|
||||||
|
rados_conf_read_file(s->cluster, NULL);
|
||||||
|
} else if (conf[0] != '\0') {
|
||||||
|
r = qemu_rbd_set_conf(s->cluster, conf, true, errp);
|
||||||
|
if (r < 0) {
|
||||||
|
goto failed_shutdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf[0] != '\0') {
|
||||||
|
r = qemu_rbd_set_conf(s->cluster, conf, false, errp);
|
||||||
|
if (r < 0) {
|
||||||
|
goto failed_shutdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fallback to more conservative semantics if setting cache
|
* Fallback to more conservative semantics if setting cache
|
||||||
* options fails. Ignore errors from setting rbd_cache because the
|
* options fails. Ignore errors from setting rbd_cache because the
|
||||||
@@ -481,18 +501,6 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
rados_conf_set(s->cluster, "rbd_cache", "true");
|
rados_conf_set(s->cluster, "rbd_cache", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strstr(conf, "conf=") == NULL) {
|
|
||||||
/* try default location, but ignore failure */
|
|
||||||
rados_conf_read_file(s->cluster, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conf[0] != '\0') {
|
|
||||||
r = qemu_rbd_set_conf(s->cluster, conf, errp);
|
|
||||||
if (r < 0) {
|
|
||||||
goto failed_shutdown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r = rados_connect(s->cluster);
|
r = rados_connect(s->cluster);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
error_setg(errp, "error connecting");
|
error_setg(errp, "error connecting");
|
||||||
@@ -621,7 +629,6 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
|
|||||||
acb->error = 0;
|
acb->error = 0;
|
||||||
acb->s = s;
|
acb->s = s;
|
||||||
acb->bh = NULL;
|
acb->bh = NULL;
|
||||||
acb->status = -EINPROGRESS;
|
|
||||||
|
|
||||||
if (cmd == RBD_AIO_WRITE) {
|
if (cmd == RBD_AIO_WRITE) {
|
||||||
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
|
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
|
||||||
@@ -633,7 +640,6 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
|
|||||||
size = nb_sectors * BDRV_SECTOR_SIZE;
|
size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
rcb = g_new(RADOSCB, 1);
|
rcb = g_new(RADOSCB, 1);
|
||||||
rcb->done = 0;
|
|
||||||
rcb->acb = acb;
|
rcb->acb = acb;
|
||||||
rcb->buf = buf;
|
rcb->buf = buf;
|
||||||
rcb->s = acb->s;
|
rcb->s = acb->s;
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* drain all pending i/o before deleting snapshot */
|
/* drain all pending i/o before deleting snapshot */
|
||||||
bdrv_drain_all();
|
bdrv_drain(bs);
|
||||||
|
|
||||||
if (drv->bdrv_snapshot_delete) {
|
if (drv->bdrv_snapshot_delete) {
|
||||||
return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
|
return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
|
||||||
|
|||||||
@@ -2380,9 +2380,6 @@ void qmp_block_commit(const char *device,
|
|||||||
aio_context = bdrv_get_aio_context(bs);
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
aio_context_acquire(aio_context);
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
/* drain all i/o before commits */
|
|
||||||
bdrv_drain_all();
|
|
||||||
|
|
||||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, errp)) {
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, errp)) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -2642,8 +2639,6 @@ out:
|
|||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
|
|
||||||
|
|
||||||
void qmp_drive_mirror(const char *device, const char *target,
|
void qmp_drive_mirror(const char *device, const char *target,
|
||||||
bool has_format, const char *format,
|
bool has_format, const char *format,
|
||||||
bool has_node_name, const char *node_name,
|
bool has_node_name, const char *node_name,
|
||||||
@@ -2685,7 +2680,7 @@ void qmp_drive_mirror(const char *device, const char *target,
|
|||||||
granularity = 0;
|
granularity = 0;
|
||||||
}
|
}
|
||||||
if (!has_buf_size) {
|
if (!has_buf_size) {
|
||||||
buf_size = DEFAULT_MIRROR_BUF_SIZE;
|
buf_size = 0;
|
||||||
}
|
}
|
||||||
if (!has_unmap) {
|
if (!has_unmap) {
|
||||||
unmap = true;
|
unmap = true;
|
||||||
|
|||||||
20
blockjob.c
20
blockjob.c
@@ -66,10 +66,7 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
|||||||
|
|
||||||
block_job_set_speed(job, speed, &local_err);
|
block_job_set_speed(job, speed, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
bs->job = NULL;
|
block_job_release(bs);
|
||||||
bdrv_op_unblock_all(bs, job->blocker);
|
|
||||||
error_free(job->blocker);
|
|
||||||
g_free(job);
|
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -77,16 +74,23 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
|||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void block_job_release(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BlockJob *job = bs->job;
|
||||||
|
|
||||||
|
bs->job = NULL;
|
||||||
|
bdrv_op_unblock_all(bs, job->blocker);
|
||||||
|
error_free(job->blocker);
|
||||||
|
g_free(job);
|
||||||
|
}
|
||||||
|
|
||||||
void block_job_completed(BlockJob *job, int ret)
|
void block_job_completed(BlockJob *job, int ret)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = job->bs;
|
BlockDriverState *bs = job->bs;
|
||||||
|
|
||||||
assert(bs->job == job);
|
assert(bs->job == job);
|
||||||
job->cb(job->opaque, ret);
|
job->cb(job->opaque, ret);
|
||||||
bs->job = NULL;
|
block_job_release(bs);
|
||||||
bdrv_op_unblock_all(bs, job->blocker);
|
|
||||||
error_free(job->blocker);
|
|
||||||
g_free(job);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ void fork_start(void)
|
|||||||
void fork_end(int child)
|
void fork_end(int child)
|
||||||
{
|
{
|
||||||
if (child) {
|
if (child) {
|
||||||
gdbserver_fork((CPUArchState *)thread_cpu->env_ptr);
|
gdbserver_fork(thread_cpu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +166,8 @@ static void set_idt(int n, unsigned int dpl)
|
|||||||
|
|
||||||
void cpu_loop(CPUX86State *env)
|
void cpu_loop(CPUX86State *env)
|
||||||
{
|
{
|
||||||
|
X86CPU *cpu = x86_env_get_cpu(env);
|
||||||
|
CPUState *cs = CPU(cpu);
|
||||||
int trapnr;
|
int trapnr;
|
||||||
abi_ulong pc;
|
abi_ulong pc;
|
||||||
//target_siginfo_t info;
|
//target_siginfo_t info;
|
||||||
@@ -512,7 +514,7 @@ void cpu_loop(CPUSPARCState *env)
|
|||||||
//target_siginfo_t info;
|
//target_siginfo_t info;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
trapnr = cpu_sparc_exec (env);
|
trapnr = cpu_sparc_exec(cs);
|
||||||
|
|
||||||
switch (trapnr) {
|
switch (trapnr) {
|
||||||
#ifndef TARGET_SPARC64
|
#ifndef TARGET_SPARC64
|
||||||
|
|||||||
187
configure
vendored
187
configure
vendored
@@ -246,7 +246,6 @@ vnc_tls=""
|
|||||||
vnc_sasl=""
|
vnc_sasl=""
|
||||||
vnc_jpeg=""
|
vnc_jpeg=""
|
||||||
vnc_png=""
|
vnc_png=""
|
||||||
vnc_ws=""
|
|
||||||
xen=""
|
xen=""
|
||||||
xen_ctrl_version=""
|
xen_ctrl_version=""
|
||||||
xen_pci_passthrough=""
|
xen_pci_passthrough=""
|
||||||
@@ -315,6 +314,7 @@ snappy=""
|
|||||||
bzip2=""
|
bzip2=""
|
||||||
guest_agent=""
|
guest_agent=""
|
||||||
guest_agent_with_vss="no"
|
guest_agent_with_vss="no"
|
||||||
|
guest_agent_ntddscsi="no"
|
||||||
guest_agent_msi=""
|
guest_agent_msi=""
|
||||||
vss_win32_sdk=""
|
vss_win32_sdk=""
|
||||||
win_sdk="no"
|
win_sdk="no"
|
||||||
@@ -330,11 +330,12 @@ glusterfs_zerofill="no"
|
|||||||
archipelago="no"
|
archipelago="no"
|
||||||
gtk=""
|
gtk=""
|
||||||
gtkabi=""
|
gtkabi=""
|
||||||
|
gnutls=""
|
||||||
|
gnutls_hash=""
|
||||||
vte=""
|
vte=""
|
||||||
tpm="yes"
|
tpm="yes"
|
||||||
libssh2=""
|
libssh2=""
|
||||||
vhdx=""
|
vhdx=""
|
||||||
quorum=""
|
|
||||||
numa=""
|
numa=""
|
||||||
tcmalloc="no"
|
tcmalloc="no"
|
||||||
|
|
||||||
@@ -732,7 +733,7 @@ if test "$mingw32" = "yes" ; then
|
|||||||
sysconfdir="\${prefix}"
|
sysconfdir="\${prefix}"
|
||||||
local_statedir=
|
local_statedir=
|
||||||
confsuffix=""
|
confsuffix=""
|
||||||
libs_qga="-lws2_32 -lwinmm -lpowrprof $libs_qga"
|
libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi $libs_qga"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
werror=""
|
werror=""
|
||||||
@@ -895,10 +896,6 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-vnc-png) vnc_png="yes"
|
--enable-vnc-png) vnc_png="yes"
|
||||||
;;
|
;;
|
||||||
--disable-vnc-ws) vnc_ws="no"
|
|
||||||
;;
|
|
||||||
--enable-vnc-ws) vnc_ws="yes"
|
|
||||||
;;
|
|
||||||
--disable-slirp) slirp="no"
|
--disable-slirp) slirp="no"
|
||||||
;;
|
;;
|
||||||
--disable-uuid) uuid="no"
|
--disable-uuid) uuid="no"
|
||||||
@@ -1118,6 +1115,10 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-gtk) gtk="yes"
|
--enable-gtk) gtk="yes"
|
||||||
;;
|
;;
|
||||||
|
--disable-gnutls) gnutls="no"
|
||||||
|
;;
|
||||||
|
--enable-gnutls) gnutls="yes"
|
||||||
|
;;
|
||||||
--enable-rdma) rdma="yes"
|
--enable-rdma) rdma="yes"
|
||||||
;;
|
;;
|
||||||
--disable-rdma) rdma="no"
|
--disable-rdma) rdma="no"
|
||||||
@@ -1140,10 +1141,6 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--disable-vhdx) vhdx="no"
|
--disable-vhdx) vhdx="no"
|
||||||
;;
|
;;
|
||||||
--disable-quorum) quorum="no"
|
|
||||||
;;
|
|
||||||
--enable-quorum) quorum="yes"
|
|
||||||
;;
|
|
||||||
--disable-numa) numa="no"
|
--disable-numa) numa="no"
|
||||||
;;
|
;;
|
||||||
--enable-numa) numa="yes"
|
--enable-numa) numa="yes"
|
||||||
@@ -1328,6 +1325,7 @@ disabled with --disable-FEATURE, default is enabled if available:
|
|||||||
debug-info debugging information
|
debug-info debugging information
|
||||||
sparse sparse checker
|
sparse sparse checker
|
||||||
|
|
||||||
|
gnutls GNUTLS cryptography support
|
||||||
sdl SDL UI
|
sdl SDL UI
|
||||||
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
||||||
gtk gtk UI
|
gtk gtk UI
|
||||||
@@ -1375,7 +1373,6 @@ disabled with --disable-FEATURE, default is enabled if available:
|
|||||||
tpm TPM support
|
tpm TPM support
|
||||||
libssh2 ssh block device support
|
libssh2 ssh block device support
|
||||||
vhdx support for the Microsoft VHDX image format
|
vhdx support for the Microsoft VHDX image format
|
||||||
quorum quorum block filter support
|
|
||||||
numa libnuma support
|
numa libnuma support
|
||||||
tcmalloc tcmalloc support
|
tcmalloc tcmalloc support
|
||||||
|
|
||||||
@@ -2115,6 +2112,86 @@ if test "$gtk" != "no"; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# GNUTLS probe
|
||||||
|
|
||||||
|
gnutls_gcrypt=no
|
||||||
|
gnutls_nettle=no
|
||||||
|
if test "$gnutls" != "no"; then
|
||||||
|
if $pkg_config --exists "gnutls"; then
|
||||||
|
gnutls_cflags=`$pkg_config --cflags gnutls`
|
||||||
|
gnutls_libs=`$pkg_config --libs gnutls`
|
||||||
|
libs_softmmu="$gnutls_libs $libs_softmmu"
|
||||||
|
libs_tools="$gnutls_libs $libs_tools"
|
||||||
|
QEMU_CFLAGS="$QEMU_CFLAGS $gnutls_cflags"
|
||||||
|
gnutls="yes"
|
||||||
|
|
||||||
|
# gnutls_hash_init requires >= 2.9.10
|
||||||
|
if $pkg_config --exists "gnutls >= 2.9.10"; then
|
||||||
|
gnutls_hash="yes"
|
||||||
|
else
|
||||||
|
gnutls_hash="no"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $pkg_config --exists 'gnutls >= 3.0'; then
|
||||||
|
gnutls_gcrypt=no
|
||||||
|
gnutls_nettle=yes
|
||||||
|
elif $pkg_config --exists 'gnutls >= 2.12'; then
|
||||||
|
case `$pkg_config --libs --static gnutls` in
|
||||||
|
*gcrypt*)
|
||||||
|
gnutls_gcrypt=yes
|
||||||
|
gnutls_nettle=no
|
||||||
|
;;
|
||||||
|
*nettle*)
|
||||||
|
gnutls_gcrypt=no
|
||||||
|
gnutls_nettle=yes
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
gnutls_gcrypt=yes
|
||||||
|
gnutls_nettle=no
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
gnutls_gcrypt=yes
|
||||||
|
gnutls_nettle=no
|
||||||
|
fi
|
||||||
|
elif test "$gnutls" = "yes"; then
|
||||||
|
feature_not_found "gnutls" "Install gnutls devel"
|
||||||
|
else
|
||||||
|
gnutls="no"
|
||||||
|
gnutls_hash="no"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
gnutls_hash="no"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$gnutls_gcrypt" != "no"; then
|
||||||
|
if has "libgcrypt-config"; then
|
||||||
|
gcrypt_cflags=`libgcrypt-config --cflags`
|
||||||
|
gcrypt_libs=`libgcrypt-config --libs`
|
||||||
|
libs_softmmu="$gcrypt_libs $libs_softmmu"
|
||||||
|
libs_tools="$gcrypt_libs $libs_tools"
|
||||||
|
QEMU_CFLAGS="$QEMU_CFLAGS $gcrypt_cflags"
|
||||||
|
else
|
||||||
|
feature_not_found "gcrypt" "Install gcrypt devel"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if test "$gnutls_nettle" != "no"; then
|
||||||
|
if $pkg_config --exists "nettle"; then
|
||||||
|
nettle_cflags=`$pkg_config --cflags nettle`
|
||||||
|
nettle_libs=`$pkg_config --libs nettle`
|
||||||
|
libs_softmmu="$nettle_libs $libs_softmmu"
|
||||||
|
libs_tools="$nettle_libs $libs_tools"
|
||||||
|
QEMU_CFLAGS="$QEMU_CFLAGS $nettle_cflags"
|
||||||
|
else
|
||||||
|
feature_not_found "nettle" "Install nettle devel"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# VTE probe
|
# VTE probe
|
||||||
|
|
||||||
@@ -2262,7 +2339,7 @@ fi
|
|||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# VNC TLS/WS detection
|
# VNC TLS/WS detection
|
||||||
if test "$vnc" = "yes" -a \( "$vnc_tls" != "no" -o "$vnc_ws" != "no" \) ; then
|
if test "$vnc" = "yes" -a "$vnc_tls" != "no" ; then
|
||||||
cat > $TMPC <<EOF
|
cat > $TMPC <<EOF
|
||||||
#include <gnutls/gnutls.h>
|
#include <gnutls/gnutls.h>
|
||||||
int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; }
|
int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; }
|
||||||
@@ -2273,50 +2350,16 @@ EOF
|
|||||||
if test "$vnc_tls" != "no" ; then
|
if test "$vnc_tls" != "no" ; then
|
||||||
vnc_tls=yes
|
vnc_tls=yes
|
||||||
fi
|
fi
|
||||||
if test "$vnc_ws" != "no" ; then
|
|
||||||
vnc_ws=yes
|
|
||||||
fi
|
|
||||||
libs_softmmu="$vnc_tls_libs $libs_softmmu"
|
libs_softmmu="$vnc_tls_libs $libs_softmmu"
|
||||||
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_tls_cflags"
|
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_tls_cflags"
|
||||||
else
|
else
|
||||||
if test "$vnc_tls" = "yes" ; then
|
if test "$vnc_tls" = "yes" ; then
|
||||||
feature_not_found "vnc-tls" "Install gnutls devel"
|
feature_not_found "vnc-tls" "Install gnutls devel"
|
||||||
fi
|
fi
|
||||||
if test "$vnc_ws" = "yes" ; then
|
|
||||||
feature_not_found "vnc-ws" "Install gnutls devel"
|
|
||||||
fi
|
|
||||||
vnc_tls=no
|
vnc_tls=no
|
||||||
vnc_ws=no
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
##########################################
|
|
||||||
# Quorum probe (check for gnutls)
|
|
||||||
if test "$quorum" != "no" ; then
|
|
||||||
cat > $TMPC <<EOF
|
|
||||||
#include <gnutls/gnutls.h>
|
|
||||||
#include <gnutls/crypto.h>
|
|
||||||
int main(void) {char data[4096], digest[32];
|
|
||||||
gnutls_hash_fast(GNUTLS_DIG_SHA256, data, 4096, digest);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
quorum_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null`
|
|
||||||
quorum_tls_libs=`$pkg_config --libs gnutls 2> /dev/null`
|
|
||||||
if compile_prog "$quorum_tls_cflags" "$quorum_tls_libs" ; then
|
|
||||||
qcow_tls=yes
|
|
||||||
libs_softmmu="$quorum_tls_libs $libs_softmmu"
|
|
||||||
libs_tools="$quorum_tls_libs $libs_softmmu"
|
|
||||||
QEMU_CFLAGS="$QEMU_CFLAGS $quorum_tls_cflags"
|
|
||||||
quorum="yes"
|
|
||||||
else
|
|
||||||
if test "$quorum" = "yes"; then
|
|
||||||
feature_not_found "gnutls" "gnutls > 2.10.0 required to compile Quorum"
|
|
||||||
fi
|
|
||||||
quorum="no"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# VNC SASL detection
|
# VNC SASL detection
|
||||||
if test "$vnc" = "yes" -a "$vnc_sasl" != "no" ; then
|
if test "$vnc" = "yes" -a "$vnc_sasl" != "no" ; then
|
||||||
@@ -3819,6 +3862,26 @@ if test "$mingw32" = "yes" -a "$guest_agent" != "no" -a "$guest_agent_with_vss"
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# check if mingw environment provides a recent ntddscsi.h
|
||||||
|
if test "$mingw32" = "yes" -a "$guest_agent" != "no"; then
|
||||||
|
cat > $TMPC << EOF
|
||||||
|
#include <windows.h>
|
||||||
|
#include <ntddscsi.h>
|
||||||
|
int main(void) {
|
||||||
|
#if !defined(IOCTL_SCSI_GET_ADDRESS)
|
||||||
|
#error Missing required ioctl definitions
|
||||||
|
#endif
|
||||||
|
SCSI_ADDRESS addr = { .Lun = 0, .TargetId = 0, .PathId = 0 };
|
||||||
|
return addr.Lun;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
if compile_prog "" "" ; then
|
||||||
|
guest_agent_ntddscsi=yes
|
||||||
|
libs_qga="-lsetupapi $libs_qga"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# Guest agent Window MSI package
|
# Guest agent Window MSI package
|
||||||
|
|
||||||
@@ -4424,6 +4487,10 @@ fi
|
|||||||
echo "pixman $pixman"
|
echo "pixman $pixman"
|
||||||
echo "SDL support $sdl"
|
echo "SDL support $sdl"
|
||||||
echo "GTK support $gtk"
|
echo "GTK support $gtk"
|
||||||
|
echo "GNUTLS support $gnutls"
|
||||||
|
echo "GNUTLS hash $gnutls_hash"
|
||||||
|
echo "GNUTLS gcrypt $gnutls_gcrypt"
|
||||||
|
echo "GNUTLS nettle $gnutls_nettle"
|
||||||
echo "VTE support $vte"
|
echo "VTE support $vte"
|
||||||
echo "curses support $curses"
|
echo "curses support $curses"
|
||||||
echo "curl support $curl"
|
echo "curl support $curl"
|
||||||
@@ -4438,7 +4505,6 @@ if test "$vnc" = "yes" ; then
|
|||||||
echo "VNC SASL support $vnc_sasl"
|
echo "VNC SASL support $vnc_sasl"
|
||||||
echo "VNC JPEG support $vnc_jpeg"
|
echo "VNC JPEG support $vnc_jpeg"
|
||||||
echo "VNC PNG support $vnc_png"
|
echo "VNC PNG support $vnc_png"
|
||||||
echo "VNC WS support $vnc_ws"
|
|
||||||
fi
|
fi
|
||||||
if test -n "$sparc_cpu"; then
|
if test -n "$sparc_cpu"; then
|
||||||
echo "Target Sparc Arch $sparc_cpu"
|
echo "Target Sparc Arch $sparc_cpu"
|
||||||
@@ -4489,6 +4555,7 @@ echo "libiscsi support $libiscsi"
|
|||||||
echo "libnfs support $libnfs"
|
echo "libnfs support $libnfs"
|
||||||
echo "build guest agent $guest_agent"
|
echo "build guest agent $guest_agent"
|
||||||
echo "QGA VSS support $guest_agent_with_vss"
|
echo "QGA VSS support $guest_agent_with_vss"
|
||||||
|
echo "QGA w32 disk info $guest_agent_ntddscsi"
|
||||||
echo "seccomp support $seccomp"
|
echo "seccomp support $seccomp"
|
||||||
echo "coroutine backend $coroutine"
|
echo "coroutine backend $coroutine"
|
||||||
echo "coroutine pool $coroutine_pool"
|
echo "coroutine pool $coroutine_pool"
|
||||||
@@ -4501,7 +4568,6 @@ echo "libssh2 support $libssh2"
|
|||||||
echo "TPM passthrough $tpm_passthrough"
|
echo "TPM passthrough $tpm_passthrough"
|
||||||
echo "QOM debugging $qom_cast_debug"
|
echo "QOM debugging $qom_cast_debug"
|
||||||
echo "vhdx $vhdx"
|
echo "vhdx $vhdx"
|
||||||
echo "Quorum $quorum"
|
|
||||||
echo "lzo support $lzo"
|
echo "lzo support $lzo"
|
||||||
echo "snappy support $snappy"
|
echo "snappy support $snappy"
|
||||||
echo "bzip2 support $bzip2"
|
echo "bzip2 support $bzip2"
|
||||||
@@ -4566,6 +4632,9 @@ if test "$mingw32" = "yes" ; then
|
|||||||
echo "CONFIG_QGA_VSS=y" >> $config_host_mak
|
echo "CONFIG_QGA_VSS=y" >> $config_host_mak
|
||||||
echo "WIN_SDK=\"$win_sdk\"" >> $config_host_mak
|
echo "WIN_SDK=\"$win_sdk\"" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
if test "$guest_agent_ntddscsi" = "yes" ; then
|
||||||
|
echo "CONFIG_QGA_NTDDDISK=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
if test "$guest_agent_msi" != "no"; then
|
if test "$guest_agent_msi" != "no"; then
|
||||||
echo "QEMU_GA_MSI_ENABLED=yes" >> $config_host_mak
|
echo "QEMU_GA_MSI_ENABLED=yes" >> $config_host_mak
|
||||||
echo "QEMU_GA_MSI_MINGW_DLL_PATH=${QEMU_GA_MSI_MINGW_DLL_PATH}" >> $config_host_mak
|
echo "QEMU_GA_MSI_MINGW_DLL_PATH=${QEMU_GA_MSI_MINGW_DLL_PATH}" >> $config_host_mak
|
||||||
@@ -4651,10 +4720,6 @@ fi
|
|||||||
if test "$vnc_png" = "yes" ; then
|
if test "$vnc_png" = "yes" ; then
|
||||||
echo "CONFIG_VNC_PNG=y" >> $config_host_mak
|
echo "CONFIG_VNC_PNG=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
if test "$vnc_ws" = "yes" ; then
|
|
||||||
echo "CONFIG_VNC_WS=y" >> $config_host_mak
|
|
||||||
echo "VNC_WS_CFLAGS=$vnc_ws_cflags" >> $config_host_mak
|
|
||||||
fi
|
|
||||||
if test "$fnmatch" = "yes" ; then
|
if test "$fnmatch" = "yes" ; then
|
||||||
echo "CONFIG_FNMATCH=y" >> $config_host_mak
|
echo "CONFIG_FNMATCH=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
@@ -4782,6 +4847,18 @@ if test "$gtk" = "yes" ; then
|
|||||||
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
|
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
|
||||||
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
if test "$gnutls" = "yes" ; then
|
||||||
|
echo "CONFIG_GNUTLS=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$gnutls_hash" = "yes" ; then
|
||||||
|
echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$gnutls_gcrypt" = "yes" ; then
|
||||||
|
echo "CONFIG_GNUTLS_GCRYPT=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$gnutls_nettle" = "yes" ; then
|
||||||
|
echo "CONFIG_GNUTLS_NETTLE=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
if test "$vte" = "yes" ; then
|
if test "$vte" = "yes" ; then
|
||||||
echo "CONFIG_VTE=y" >> $config_host_mak
|
echo "CONFIG_VTE=y" >> $config_host_mak
|
||||||
echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
|
echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
|
||||||
@@ -4971,10 +5048,6 @@ if test "$libssh2" = "yes" ; then
|
|||||||
echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
|
echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$quorum" = "yes" ; then
|
|
||||||
echo "CONFIG_QUORUM=y" >> $config_host_mak
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$vhdx" = "yes" ; then
|
if test "$vhdx" = "yes" ; then
|
||||||
echo "CONFIG_VHDX=y" >> $config_host_mak
|
echo "CONFIG_VHDX=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|||||||
29
cpu-exec.c
29
cpu-exec.c
@@ -27,6 +27,7 @@
|
|||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "exec/memory-internal.h"
|
#include "exec/memory-internal.h"
|
||||||
#include "qemu/rcu.h"
|
#include "qemu/rcu.h"
|
||||||
|
#include "exec/tb-hash.h"
|
||||||
|
|
||||||
/* -icount align implementation. */
|
/* -icount align implementation. */
|
||||||
|
|
||||||
@@ -226,10 +227,9 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
|
|||||||
|
|
||||||
/* Execute the code without caching the generated code. An interpreter
|
/* Execute the code without caching the generated code. An interpreter
|
||||||
could be used if available. */
|
could be used if available. */
|
||||||
static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
|
static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
|
||||||
TranslationBlock *orig_tb)
|
TranslationBlock *orig_tb)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
target_ulong pc = orig_tb->pc;
|
target_ulong pc = orig_tb->pc;
|
||||||
target_ulong cs_base = orig_tb->cs_base;
|
target_ulong cs_base = orig_tb->cs_base;
|
||||||
@@ -253,12 +253,12 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
|
|||||||
tb_free(tb);
|
tb_free(tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TranslationBlock *tb_find_slow(CPUArchState *env,
|
static TranslationBlock *tb_find_slow(CPUState *cpu,
|
||||||
target_ulong pc,
|
target_ulong pc,
|
||||||
target_ulong cs_base,
|
target_ulong cs_base,
|
||||||
uint64_t flags)
|
uint64_t flags)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||||
TranslationBlock *tb, **ptb1;
|
TranslationBlock *tb, **ptb1;
|
||||||
unsigned int h;
|
unsigned int h;
|
||||||
tb_page_addr_t phys_pc, phys_page1;
|
tb_page_addr_t phys_pc, phys_page1;
|
||||||
@@ -310,9 +310,9 @@ static TranslationBlock *tb_find_slow(CPUArchState *env,
|
|||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline TranslationBlock *tb_find_fast(CPUArchState *env)
|
static inline TranslationBlock *tb_find_fast(CPUState *cpu)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
target_ulong cs_base, pc;
|
target_ulong cs_base, pc;
|
||||||
int flags;
|
int flags;
|
||||||
@@ -324,14 +324,13 @@ static inline TranslationBlock *tb_find_fast(CPUArchState *env)
|
|||||||
tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
|
tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
|
||||||
if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
|
if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
|
||||||
tb->flags != flags)) {
|
tb->flags != flags)) {
|
||||||
tb = tb_find_slow(env, pc, cs_base, flags);
|
tb = tb_find_slow(cpu, pc, cs_base, flags);
|
||||||
}
|
}
|
||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_handle_debug_exception(CPUArchState *env)
|
static void cpu_handle_debug_exception(CPUState *cpu)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
CPUWatchpoint *wp;
|
CPUWatchpoint *wp;
|
||||||
|
|
||||||
@@ -348,12 +347,12 @@ static void cpu_handle_debug_exception(CPUArchState *env)
|
|||||||
|
|
||||||
volatile sig_atomic_t exit_request;
|
volatile sig_atomic_t exit_request;
|
||||||
|
|
||||||
int cpu_exec(CPUArchState *env)
|
int cpu_exec(CPUState *cpu)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||||
|
CPUArchState *env = &x86_cpu->env;
|
||||||
#endif
|
#endif
|
||||||
int ret, interrupt_request;
|
int ret, interrupt_request;
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
@@ -406,7 +405,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
/* exit request from the cpu execution loop */
|
/* exit request from the cpu execution loop */
|
||||||
ret = cpu->exception_index;
|
ret = cpu->exception_index;
|
||||||
if (ret == EXCP_DEBUG) {
|
if (ret == EXCP_DEBUG) {
|
||||||
cpu_handle_debug_exception(env);
|
cpu_handle_debug_exception(cpu);
|
||||||
}
|
}
|
||||||
cpu->exception_index = -1;
|
cpu->exception_index = -1;
|
||||||
break;
|
break;
|
||||||
@@ -482,7 +481,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
}
|
}
|
||||||
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
|
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
|
||||||
have_tb_lock = true;
|
have_tb_lock = true;
|
||||||
tb = tb_find_fast(env);
|
tb = tb_find_fast(cpu);
|
||||||
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
||||||
doing it in tb_find_slow */
|
doing it in tb_find_slow */
|
||||||
if (tcg_ctx.tb_ctx.tb_invalidated_flag) {
|
if (tcg_ctx.tb_ctx.tb_invalidated_flag) {
|
||||||
@@ -542,7 +541,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
if (insns_left > 0) {
|
if (insns_left > 0) {
|
||||||
/* Execute remaining instructions. */
|
/* Execute remaining instructions. */
|
||||||
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||||
cpu_exec_nocache(env, insns_left, tb);
|
cpu_exec_nocache(cpu, insns_left, tb);
|
||||||
align_clocks(&sc, cpu);
|
align_clocks(&sc, cpu);
|
||||||
}
|
}
|
||||||
cpu->exception_index = EXCP_INTERRUPT;
|
cpu->exception_index = EXCP_INTERRUPT;
|
||||||
@@ -566,11 +565,11 @@ int cpu_exec(CPUArchState *env)
|
|||||||
/* Reload env after longjmp - the compiler may have smashed all
|
/* Reload env after longjmp - the compiler may have smashed all
|
||||||
* local variables as longjmp is marked 'noreturn'. */
|
* local variables as longjmp is marked 'noreturn'. */
|
||||||
cpu = current_cpu;
|
cpu = current_cpu;
|
||||||
env = cpu->env_ptr;
|
|
||||||
cc = CPU_GET_CLASS(cpu);
|
cc = CPU_GET_CLASS(cpu);
|
||||||
cpu->can_do_io = 1;
|
cpu->can_do_io = 1;
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
x86_cpu = X86_CPU(cpu);
|
x86_cpu = X86_CPU(cpu);
|
||||||
|
env = &x86_cpu->env;
|
||||||
#endif
|
#endif
|
||||||
if (have_tb_lock) {
|
if (have_tb_lock) {
|
||||||
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
||||||
|
|||||||
27
cpus.c
27
cpus.c
@@ -954,7 +954,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
|
|||||||
CPUState *cpu = arg;
|
CPUState *cpu = arg;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
qemu_mutex_lock(&qemu_global_mutex);
|
qemu_mutex_lock_iothread();
|
||||||
qemu_thread_get_self(cpu->thread);
|
qemu_thread_get_self(cpu->thread);
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
cpu->can_do_io = 1;
|
cpu->can_do_io = 1;
|
||||||
@@ -1034,10 +1034,10 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
|||||||
{
|
{
|
||||||
CPUState *cpu = arg;
|
CPUState *cpu = arg;
|
||||||
|
|
||||||
|
qemu_mutex_lock_iothread();
|
||||||
qemu_tcg_init_cpu_signals();
|
qemu_tcg_init_cpu_signals();
|
||||||
qemu_thread_get_self(cpu->thread);
|
qemu_thread_get_self(cpu->thread);
|
||||||
|
|
||||||
qemu_mutex_lock(&qemu_global_mutex);
|
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
cpu->created = true;
|
cpu->created = true;
|
||||||
@@ -1146,10 +1146,21 @@ bool qemu_in_vcpu_thread(void)
|
|||||||
return current_cpu && qemu_cpu_is_self(current_cpu);
|
return current_cpu && qemu_cpu_is_self(current_cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __thread bool iothread_locked = false;
|
||||||
|
|
||||||
|
bool qemu_mutex_iothread_locked(void)
|
||||||
|
{
|
||||||
|
return iothread_locked;
|
||||||
|
}
|
||||||
|
|
||||||
void qemu_mutex_lock_iothread(void)
|
void qemu_mutex_lock_iothread(void)
|
||||||
{
|
{
|
||||||
atomic_inc(&iothread_requesting_mutex);
|
atomic_inc(&iothread_requesting_mutex);
|
||||||
if (!tcg_enabled() || !first_cpu || !first_cpu->thread) {
|
/* In the simple case there is no need to bump the VCPU thread out of
|
||||||
|
* TCG code execution.
|
||||||
|
*/
|
||||||
|
if (!tcg_enabled() || qemu_in_vcpu_thread() ||
|
||||||
|
!first_cpu || !first_cpu->thread) {
|
||||||
qemu_mutex_lock(&qemu_global_mutex);
|
qemu_mutex_lock(&qemu_global_mutex);
|
||||||
atomic_dec(&iothread_requesting_mutex);
|
atomic_dec(&iothread_requesting_mutex);
|
||||||
} else {
|
} else {
|
||||||
@@ -1160,10 +1171,12 @@ void qemu_mutex_lock_iothread(void)
|
|||||||
atomic_dec(&iothread_requesting_mutex);
|
atomic_dec(&iothread_requesting_mutex);
|
||||||
qemu_cond_broadcast(&qemu_io_proceeded_cond);
|
qemu_cond_broadcast(&qemu_io_proceeded_cond);
|
||||||
}
|
}
|
||||||
|
iothread_locked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_mutex_unlock_iothread(void)
|
void qemu_mutex_unlock_iothread(void)
|
||||||
{
|
{
|
||||||
|
iothread_locked = false;
|
||||||
qemu_mutex_unlock(&qemu_global_mutex);
|
qemu_mutex_unlock(&qemu_global_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1344,9 +1357,8 @@ int vm_stop_force_state(RunState state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcg_cpu_exec(CPUArchState *env)
|
static int tcg_cpu_exec(CPUState *cpu)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
|
||||||
int ret;
|
int ret;
|
||||||
#ifdef CONFIG_PROFILER
|
#ifdef CONFIG_PROFILER
|
||||||
int64_t ti;
|
int64_t ti;
|
||||||
@@ -1381,7 +1393,7 @@ static int tcg_cpu_exec(CPUArchState *env)
|
|||||||
cpu->icount_decr.u16.low = decr;
|
cpu->icount_decr.u16.low = decr;
|
||||||
cpu->icount_extra = count;
|
cpu->icount_extra = count;
|
||||||
}
|
}
|
||||||
ret = cpu_exec(env);
|
ret = cpu_exec(cpu);
|
||||||
#ifdef CONFIG_PROFILER
|
#ifdef CONFIG_PROFILER
|
||||||
tcg_time += profile_getclock() - ti;
|
tcg_time += profile_getclock() - ti;
|
||||||
#endif
|
#endif
|
||||||
@@ -1408,13 +1420,12 @@ static void tcg_exec_all(void)
|
|||||||
}
|
}
|
||||||
for (; next_cpu != NULL && !exit_request; next_cpu = CPU_NEXT(next_cpu)) {
|
for (; next_cpu != NULL && !exit_request; next_cpu = CPU_NEXT(next_cpu)) {
|
||||||
CPUState *cpu = next_cpu;
|
CPUState *cpu = next_cpu;
|
||||||
CPUArchState *env = cpu->env_ptr;
|
|
||||||
|
|
||||||
qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
|
qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
|
||||||
(cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
|
(cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
|
||||||
|
|
||||||
if (cpu_can_run(cpu)) {
|
if (cpu_can_run(cpu)) {
|
||||||
r = tcg_cpu_exec(env);
|
r = tcg_cpu_exec(cpu);
|
||||||
if (r == EXCP_DEBUG) {
|
if (r == EXCP_DEBUG) {
|
||||||
cpu_handle_guest_debug(cpu);
|
cpu_handle_guest_debug(cpu);
|
||||||
break;
|
break;
|
||||||
|
|||||||
5
crypto/Makefile.objs
Normal file
5
crypto/Makefile.objs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
util-obj-y += init.o
|
||||||
|
util-obj-y += hash.o
|
||||||
|
util-obj-y += aes.o
|
||||||
|
util-obj-y += desrfb.o
|
||||||
|
util-obj-y += cipher.o
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qemu/aes.h"
|
#include "crypto/aes.h"
|
||||||
|
|
||||||
typedef uint32_t u32;
|
typedef uint32_t u32;
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
400
crypto/cipher-builtin.c
Normal file
400
crypto/cipher-builtin.c
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Crypto cipher built-in algorithms
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "crypto/aes.h"
|
||||||
|
#include "crypto/desrfb.h"
|
||||||
|
|
||||||
|
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
|
||||||
|
struct QCryptoCipherBuiltinAES {
|
||||||
|
AES_KEY encrypt_key;
|
||||||
|
AES_KEY decrypt_key;
|
||||||
|
uint8_t *iv;
|
||||||
|
size_t niv;
|
||||||
|
};
|
||||||
|
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
|
||||||
|
struct QCryptoCipherBuiltinDESRFB {
|
||||||
|
uint8_t *key;
|
||||||
|
size_t nkey;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct QCryptoCipherBuiltin QCryptoCipherBuiltin;
|
||||||
|
struct QCryptoCipherBuiltin {
|
||||||
|
union {
|
||||||
|
QCryptoCipherBuiltinAES aes;
|
||||||
|
QCryptoCipherBuiltinDESRFB desrfb;
|
||||||
|
} state;
|
||||||
|
void (*free)(QCryptoCipher *cipher);
|
||||||
|
int (*setiv)(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *iv, size_t niv,
|
||||||
|
Error **errp);
|
||||||
|
int (*encrypt)(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp);
|
||||||
|
int (*decrypt)(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
|
||||||
|
g_free(ctxt->state.aes.iv);
|
||||||
|
g_free(ctxt);
|
||||||
|
cipher->opaque = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
|
||||||
|
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
||||||
|
const uint8_t *inptr = in;
|
||||||
|
uint8_t *outptr = out;
|
||||||
|
while (len) {
|
||||||
|
if (len > AES_BLOCK_SIZE) {
|
||||||
|
AES_encrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
|
||||||
|
inptr += AES_BLOCK_SIZE;
|
||||||
|
outptr += AES_BLOCK_SIZE;
|
||||||
|
len -= AES_BLOCK_SIZE;
|
||||||
|
} else {
|
||||||
|
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||||
|
memcpy(tmp1, inptr, len);
|
||||||
|
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||||
|
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||||
|
AES_encrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
|
||||||
|
memcpy(outptr, tmp2, len);
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AES_cbc_encrypt(in, out, len,
|
||||||
|
&ctxt->state.aes.encrypt_key,
|
||||||
|
ctxt->state.aes.iv, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
|
||||||
|
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
||||||
|
const uint8_t *inptr = in;
|
||||||
|
uint8_t *outptr = out;
|
||||||
|
while (len) {
|
||||||
|
if (len > AES_BLOCK_SIZE) {
|
||||||
|
AES_decrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
|
||||||
|
inptr += AES_BLOCK_SIZE;
|
||||||
|
outptr += AES_BLOCK_SIZE;
|
||||||
|
len -= AES_BLOCK_SIZE;
|
||||||
|
} else {
|
||||||
|
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||||
|
memcpy(tmp1, inptr, len);
|
||||||
|
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||||
|
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||||
|
AES_decrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
|
||||||
|
memcpy(outptr, tmp2, len);
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AES_cbc_encrypt(in, out, len,
|
||||||
|
&ctxt->state.aes.encrypt_key,
|
||||||
|
ctxt->state.aes.iv, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_cipher_setiv_aes(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
if (niv != 16) {
|
||||||
|
error_setg(errp, "IV must be 16 bytes not %zu", niv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(ctxt->state.aes.iv);
|
||||||
|
ctxt->state.aes.iv = g_new0(uint8_t, niv);
|
||||||
|
memcpy(ctxt->state.aes.iv, iv, niv);
|
||||||
|
ctxt->state.aes.niv = niv;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt;
|
||||||
|
|
||||||
|
if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
|
||||||
|
cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
|
||||||
|
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt = g_new0(QCryptoCipherBuiltin, 1);
|
||||||
|
|
||||||
|
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.encrypt_key) != 0) {
|
||||||
|
error_setg(errp, "Failed to set encryption key");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.decrypt_key) != 0) {
|
||||||
|
error_setg(errp, "Failed to set decryption key");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt->free = qcrypto_cipher_free_aes;
|
||||||
|
ctxt->setiv = qcrypto_cipher_setiv_aes;
|
||||||
|
ctxt->encrypt = qcrypto_cipher_encrypt_aes;
|
||||||
|
ctxt->decrypt = qcrypto_cipher_decrypt_aes;
|
||||||
|
|
||||||
|
cipher->opaque = ctxt;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_free(ctxt);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qcrypto_cipher_free_des_rfb(QCryptoCipher *cipher)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
|
||||||
|
g_free(ctxt->state.desrfb.key);
|
||||||
|
g_free(ctxt);
|
||||||
|
cipher->opaque = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (len % 8) {
|
||||||
|
error_setg(errp, "Buffer size must be multiple of 8 not %zu",
|
||||||
|
len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
deskey(ctxt->state.desrfb.key, EN0);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += 8) {
|
||||||
|
des((void *)in + i, out + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (len % 8) {
|
||||||
|
error_setg(errp, "Buffer size must be multiple of 8 not %zu",
|
||||||
|
len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
deskey(ctxt->state.desrfb.key, DE1);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += 8) {
|
||||||
|
des((void *)in + i, out + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int qcrypto_cipher_setiv_des_rfb(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
error_setg(errp, "Setting IV is not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int qcrypto_cipher_init_des_rfb(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt;
|
||||||
|
|
||||||
|
if (cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
|
||||||
|
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt = g_new0(QCryptoCipherBuiltin, 1);
|
||||||
|
|
||||||
|
ctxt->state.desrfb.key = g_new0(uint8_t, nkey);
|
||||||
|
memcpy(ctxt->state.desrfb.key, key, nkey);
|
||||||
|
ctxt->state.desrfb.nkey = nkey;
|
||||||
|
|
||||||
|
ctxt->free = qcrypto_cipher_free_des_rfb;
|
||||||
|
ctxt->setiv = qcrypto_cipher_setiv_des_rfb;
|
||||||
|
ctxt->encrypt = qcrypto_cipher_encrypt_des_rfb;
|
||||||
|
ctxt->decrypt = qcrypto_cipher_decrypt_des_rfb;
|
||||||
|
|
||||||
|
cipher->opaque = ctxt;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||||
|
{
|
||||||
|
switch (alg) {
|
||||||
|
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
|
QCryptoCipherMode mode,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipher *cipher;
|
||||||
|
|
||||||
|
cipher = g_new0(QCryptoCipher, 1);
|
||||||
|
cipher->alg = alg;
|
||||||
|
cipher->mode = mode;
|
||||||
|
|
||||||
|
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cipher->alg) {
|
||||||
|
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||||
|
if (qcrypto_cipher_init_des_rfb(cipher, key, nkey, errp) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||||
|
if (qcrypto_cipher_init_aes(cipher, key, nkey, errp) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_setg(errp,
|
||||||
|
"Unsupported cipher algorithm %d", cipher->alg);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_free(cipher);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt;
|
||||||
|
|
||||||
|
if (!cipher) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt = cipher->opaque;
|
||||||
|
ctxt->free(cipher);
|
||||||
|
g_free(cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
|
||||||
|
return ctxt->encrypt(cipher, in, out, len, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
|
||||||
|
return ctxt->decrypt(cipher, in, out, len, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_cipher_setiv(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
|
||||||
|
return ctxt->setiv(cipher, iv, niv, errp);
|
||||||
|
}
|
||||||
195
crypto/cipher-gcrypt.c
Normal file
195
crypto/cipher-gcrypt.c
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Crypto cipher libgcrypt algorithms
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gcrypt.h>
|
||||||
|
|
||||||
|
|
||||||
|
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||||
|
{
|
||||||
|
switch (alg) {
|
||||||
|
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
|
QCryptoCipherMode mode,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipher *cipher;
|
||||||
|
gcry_cipher_hd_t handle;
|
||||||
|
gcry_error_t err;
|
||||||
|
int gcryalg, gcrymode;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
|
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||||||
|
break;
|
||||||
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
|
gcrymode = GCRY_CIPHER_MODE_CBC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_setg(errp, "Unsupported cipher mode %d", mode);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (alg) {
|
||||||
|
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||||
|
gcryalg = GCRY_CIPHER_DES;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||||
|
gcryalg = GCRY_CIPHER_AES128;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
|
gcryalg = GCRY_CIPHER_AES192;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||||
|
gcryalg = GCRY_CIPHER_AES256;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher = g_new0(QCryptoCipher, 1);
|
||||||
|
cipher->alg = alg;
|
||||||
|
cipher->mode = mode;
|
||||||
|
|
||||||
|
err = gcry_cipher_open(&handle, gcryalg, gcrymode, 0);
|
||||||
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot initialize cipher: %s",
|
||||||
|
gcry_strerror(err));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||||
|
/* We're using standard DES cipher from gcrypt, so we need
|
||||||
|
* to munge the key so that the results are the same as the
|
||||||
|
* bizarre RFB variant of DES :-)
|
||||||
|
*/
|
||||||
|
uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
|
||||||
|
err = gcry_cipher_setkey(handle, rfbkey, nkey);
|
||||||
|
g_free(rfbkey);
|
||||||
|
} else {
|
||||||
|
err = gcry_cipher_setkey(handle, key, nkey);
|
||||||
|
}
|
||||||
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot set key: %s",
|
||||||
|
gcry_strerror(err));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher->opaque = handle;
|
||||||
|
return cipher;
|
||||||
|
|
||||||
|
error:
|
||||||
|
gcry_cipher_close(handle);
|
||||||
|
g_free(cipher);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||||
|
{
|
||||||
|
gcry_cipher_hd_t handle;
|
||||||
|
if (!cipher) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handle = cipher->opaque;
|
||||||
|
gcry_cipher_close(handle);
|
||||||
|
g_free(cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
gcry_cipher_hd_t handle = cipher->opaque;
|
||||||
|
gcry_error_t err;
|
||||||
|
|
||||||
|
err = gcry_cipher_encrypt(handle,
|
||||||
|
out, len,
|
||||||
|
in, len);
|
||||||
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot encrypt data: %s",
|
||||||
|
gcry_strerror(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
gcry_cipher_hd_t handle = cipher->opaque;
|
||||||
|
gcry_error_t err;
|
||||||
|
|
||||||
|
err = gcry_cipher_decrypt(handle,
|
||||||
|
out, len,
|
||||||
|
in, len);
|
||||||
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot decrypt data: %s",
|
||||||
|
gcry_strerror(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_cipher_setiv(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
gcry_cipher_hd_t handle = cipher->opaque;
|
||||||
|
gcry_error_t err;
|
||||||
|
|
||||||
|
gcry_cipher_reset(handle);
|
||||||
|
err = gcry_cipher_setiv(handle, iv, niv);
|
||||||
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot set IV: %s",
|
||||||
|
gcry_strerror(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
206
crypto/cipher-nettle.c
Normal file
206
crypto/cipher-nettle.c
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Crypto cipher nettle algorithms
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nettle/nettle-types.h>
|
||||||
|
#include <nettle/aes.h>
|
||||||
|
#include <nettle/des.h>
|
||||||
|
#include <nettle/cbc.h>
|
||||||
|
|
||||||
|
typedef struct QCryptoCipherNettle QCryptoCipherNettle;
|
||||||
|
struct QCryptoCipherNettle {
|
||||||
|
void *ctx_encrypt;
|
||||||
|
void *ctx_decrypt;
|
||||||
|
nettle_crypt_func *alg_encrypt;
|
||||||
|
nettle_crypt_func *alg_decrypt;
|
||||||
|
uint8_t *iv;
|
||||||
|
size_t niv;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||||
|
{
|
||||||
|
switch (alg) {
|
||||||
|
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
|
QCryptoCipherMode mode,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipher *cipher;
|
||||||
|
QCryptoCipherNettle *ctx;
|
||||||
|
uint8_t *rfbkey;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_setg(errp, "Unsupported cipher mode %d", mode);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher = g_new0(QCryptoCipher, 1);
|
||||||
|
cipher->alg = alg;
|
||||||
|
cipher->mode = mode;
|
||||||
|
|
||||||
|
ctx = g_new0(QCryptoCipherNettle, 1);
|
||||||
|
|
||||||
|
switch (alg) {
|
||||||
|
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||||
|
ctx->ctx_encrypt = g_new0(struct des_ctx, 1);
|
||||||
|
ctx->ctx_decrypt = NULL; /* 1 ctx can do both */
|
||||||
|
rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
|
||||||
|
des_set_key(ctx->ctx_encrypt, rfbkey);
|
||||||
|
g_free(rfbkey);
|
||||||
|
|
||||||
|
ctx->alg_encrypt = (nettle_crypt_func *)des_encrypt;
|
||||||
|
ctx->alg_decrypt = (nettle_crypt_func *)des_decrypt;
|
||||||
|
|
||||||
|
ctx->niv = DES_BLOCK_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
|
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||||
|
ctx->ctx_encrypt = g_new0(struct aes_ctx, 1);
|
||||||
|
ctx->ctx_decrypt = g_new0(struct aes_ctx, 1);
|
||||||
|
|
||||||
|
aes_set_encrypt_key(ctx->ctx_encrypt, nkey, key);
|
||||||
|
aes_set_decrypt_key(ctx->ctx_decrypt, nkey, key);
|
||||||
|
|
||||||
|
ctx->alg_encrypt = (nettle_crypt_func *)aes_encrypt;
|
||||||
|
ctx->alg_decrypt = (nettle_crypt_func *)aes_decrypt;
|
||||||
|
|
||||||
|
ctx->niv = AES_BLOCK_SIZE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->iv = g_new0(uint8_t, ctx->niv);
|
||||||
|
cipher->opaque = ctx;
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_free(cipher);
|
||||||
|
g_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||||
|
{
|
||||||
|
QCryptoCipherNettle *ctx;
|
||||||
|
|
||||||
|
if (!cipher) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = cipher->opaque;
|
||||||
|
g_free(ctx->iv);
|
||||||
|
g_free(ctx->ctx_encrypt);
|
||||||
|
g_free(ctx->ctx_decrypt);
|
||||||
|
g_free(ctx);
|
||||||
|
g_free(cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherNettle *ctx = cipher->opaque;
|
||||||
|
|
||||||
|
switch (cipher->mode) {
|
||||||
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
|
ctx->alg_encrypt(ctx->ctx_encrypt, len, out, in);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
|
cbc_encrypt(ctx->ctx_encrypt, ctx->alg_encrypt,
|
||||||
|
ctx->niv, ctx->iv,
|
||||||
|
len, out, in);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||||
|
cipher->alg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||||
|
const void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherNettle *ctx = cipher->opaque;
|
||||||
|
|
||||||
|
switch (cipher->mode) {
|
||||||
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
|
ctx->alg_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
||||||
|
len, out, in);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
|
cbc_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
||||||
|
ctx->alg_decrypt, ctx->niv, ctx->iv,
|
||||||
|
len, out, in);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||||
|
cipher->alg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_cipher_setiv(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherNettle *ctx = cipher->opaque;
|
||||||
|
if (niv != ctx->niv) {
|
||||||
|
error_setg(errp, "Expected IV size %zu not %zu",
|
||||||
|
ctx->niv, niv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(ctx->iv, iv, niv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
74
crypto/cipher.c
Normal file
74
crypto/cipher.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Crypto cipher algorithms
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "crypto/cipher.h"
|
||||||
|
|
||||||
|
|
||||||
|
static size_t alg_key_len[QCRYPTO_CIPHER_ALG_LAST] = {
|
||||||
|
[QCRYPTO_CIPHER_ALG_AES_128] = 16,
|
||||||
|
[QCRYPTO_CIPHER_ALG_AES_192] = 24,
|
||||||
|
[QCRYPTO_CIPHER_ALG_AES_256] = 32,
|
||||||
|
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
||||||
|
size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
if ((unsigned)alg >= QCRYPTO_CIPHER_ALG_LAST) {
|
||||||
|
error_setg(errp, "Cipher algorithm %d out of range",
|
||||||
|
alg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alg_key_len[alg] != nkey) {
|
||||||
|
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||||
|
alg_key_len[alg], nkey);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_GNUTLS_GCRYPT) || defined(CONFIG_GNUTLS_NETTLE)
|
||||||
|
static uint8_t *
|
||||||
|
qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
|
||||||
|
size_t nkey)
|
||||||
|
{
|
||||||
|
uint8_t *ret = g_new0(uint8_t, nkey);
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < nkey; i++) {
|
||||||
|
uint8_t r = key[i];
|
||||||
|
r = (r & 0xf0) >> 4 | (r & 0x0f) << 4;
|
||||||
|
r = (r & 0xcc) >> 2 | (r & 0x33) << 2;
|
||||||
|
r = (r & 0xaa) >> 1 | (r & 0x55) << 1;
|
||||||
|
ret[i] = r;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_GNUTLS_GCRYPT || CONFIG_GNUTLS_NETTLE */
|
||||||
|
|
||||||
|
#ifdef CONFIG_GNUTLS_GCRYPT
|
||||||
|
#include "crypto/cipher-gcrypt.c"
|
||||||
|
#elif defined CONFIG_GNUTLS_NETTLE
|
||||||
|
#include "crypto/cipher-nettle.c"
|
||||||
|
#else
|
||||||
|
#include "crypto/cipher-builtin.c"
|
||||||
|
#endif
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
|
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "d3des.h"
|
#include "crypto/desrfb.h"
|
||||||
|
|
||||||
static void scrunch(unsigned char *, unsigned long *);
|
static void scrunch(unsigned char *, unsigned long *);
|
||||||
static void unscrun(unsigned long *, unsigned char *);
|
static void unscrun(unsigned long *, unsigned char *);
|
||||||
200
crypto/hash.c
Normal file
200
crypto/hash.c
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Crypto hash algorithms
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_GNUTLS_HASH
|
||||||
|
#include <gnutls/gnutls.h>
|
||||||
|
#include <gnutls/crypto.h>
|
||||||
|
|
||||||
|
static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG_LAST] = {
|
||||||
|
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
|
||||||
|
};
|
||||||
|
|
||||||
|
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
|
||||||
|
{
|
||||||
|
if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *resultlen,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
gnutls_hash_hd_t dig;
|
||||||
|
|
||||||
|
if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map)) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Unknown hash algorithm %d",
|
||||||
|
alg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gnutls_hash_init(&dig, qcrypto_hash_alg_map[alg]);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Unable to initialize hash algorithm: %s",
|
||||||
|
gnutls_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < niov; i++) {
|
||||||
|
ret = gnutls_hash(dig, iov[i].iov_base, iov[i].iov_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Unable process hash data: %s",
|
||||||
|
gnutls_strerror(ret));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]);
|
||||||
|
if (ret <= 0) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Unable to get hash length: %s",
|
||||||
|
gnutls_strerror(ret));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (*resultlen == 0) {
|
||||||
|
*resultlen = ret;
|
||||||
|
*result = g_new0(uint8_t, *resultlen);
|
||||||
|
} else if (*resultlen != ret) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Result buffer size %zu is smaller than hash %d",
|
||||||
|
*resultlen, ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnutls_hash_deinit(dig, *result);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
gnutls_hash_deinit(dig, NULL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* ! CONFIG_GNUTLS_HASH */
|
||||||
|
|
||||||
|
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
|
||||||
|
const struct iovec *iov G_GNUC_UNUSED,
|
||||||
|
size_t niov G_GNUC_UNUSED,
|
||||||
|
uint8_t **result G_GNUC_UNUSED,
|
||||||
|
size_t *resultlen G_GNUC_UNUSED,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
error_setg(errp,
|
||||||
|
"Hash algorithm %d not supported without GNUTLS",
|
||||||
|
alg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ! CONFIG_GNUTLS_HASH */
|
||||||
|
|
||||||
|
int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
|
||||||
|
const char *buf,
|
||||||
|
size_t len,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *resultlen,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
struct iovec iov = { .iov_base = (char *)buf,
|
||||||
|
.iov_len = len };
|
||||||
|
return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char hex[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
int qcrypto_hash_digestv(QCryptoHashAlgorithm alg,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
char **digest,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
uint8_t *result = NULL;
|
||||||
|
size_t resultlen = 0;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*digest = g_new0(char, (resultlen * 2) + 1);
|
||||||
|
for (i = 0 ; i < resultlen ; i++) {
|
||||||
|
(*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf];
|
||||||
|
(*digest)[(i * 2) + 1] = hex[result[i] & 0xf];
|
||||||
|
}
|
||||||
|
(*digest)[resultlen * 2] = '\0';
|
||||||
|
g_free(result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_digest(QCryptoHashAlgorithm alg,
|
||||||
|
const char *buf,
|
||||||
|
size_t len,
|
||||||
|
char **digest,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
|
||||||
|
|
||||||
|
return qcrypto_hash_digestv(alg, &iov, 1, digest, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_base64v(QCryptoHashAlgorithm alg,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
char **base64,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
uint8_t *result = NULL;
|
||||||
|
size_t resultlen = 0;
|
||||||
|
|
||||||
|
if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*base64 = g_base64_encode(result, resultlen);
|
||||||
|
g_free(result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_base64(QCryptoHashAlgorithm alg,
|
||||||
|
const char *buf,
|
||||||
|
size_t len,
|
||||||
|
char **base64,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
|
||||||
|
|
||||||
|
return qcrypto_hash_base64v(alg, &iov, 1, base64, errp);
|
||||||
|
}
|
||||||
150
crypto/init.c
Normal file
150
crypto/init.c
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Crypto initialization
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "crypto/init.h"
|
||||||
|
#include "qemu/thread.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_GNUTLS
|
||||||
|
#include <gnutls/gnutls.h>
|
||||||
|
#include <gnutls/crypto.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_GNUTLS_GCRYPT
|
||||||
|
#include <gcrypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* #define DEBUG_GNUTLS */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If GNUTLS is built against GCrypt then
|
||||||
|
*
|
||||||
|
* - When GNUTLS >= 2.12, we must not initialize gcrypt threading
|
||||||
|
* because GNUTLS will do that itself
|
||||||
|
* - When GNUTLS < 2.12 we must always initialize gcrypt threading
|
||||||
|
*
|
||||||
|
* But....
|
||||||
|
*
|
||||||
|
* When gcrypt >= 1.6.0 we must not initialize gcrypt threading
|
||||||
|
* because gcrypt will do that itself.
|
||||||
|
*
|
||||||
|
* So we need to init gcrypt threading if
|
||||||
|
*
|
||||||
|
* - gcrypt < 1.6.0
|
||||||
|
* AND
|
||||||
|
* - gnutls < 2.12
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (defined(CONFIG_GNUTLS_GCRYPT) && \
|
||||||
|
(!defined(GNUTLS_VERSION_NUMBER) || \
|
||||||
|
(GNUTLS_VERSION_NUMBER < 0x020c00)) && \
|
||||||
|
(!defined(GCRYPT_VERSION_NUMBER) || \
|
||||||
|
(GCRYPT_VERSION_NUMBER < 0x010600)))
|
||||||
|
#define QCRYPTO_INIT_GCRYPT_THREADS
|
||||||
|
#else
|
||||||
|
#undef QCRYPTO_INIT_GCRYPT_THREADS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_GNUTLS
|
||||||
|
static void qcrypto_gnutls_log(int level, const char *str)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%d: %s", level, str);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QCRYPTO_INIT_GCRYPT_THREADS
|
||||||
|
static int qcrypto_gcrypt_mutex_init(void **priv)
|
||||||
|
{ \
|
||||||
|
QemuMutex *lock = NULL;
|
||||||
|
lock = g_new0(QemuMutex, 1);
|
||||||
|
qemu_mutex_init(lock);
|
||||||
|
*priv = lock;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_mutex_destroy(void **priv)
|
||||||
|
{
|
||||||
|
QemuMutex *lock = *priv;
|
||||||
|
qemu_mutex_destroy(lock);
|
||||||
|
g_free(lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_mutex_lock(void **priv)
|
||||||
|
{
|
||||||
|
QemuMutex *lock = *priv;
|
||||||
|
qemu_mutex_lock(lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_mutex_unlock(void **priv)
|
||||||
|
{
|
||||||
|
QemuMutex *lock = *priv;
|
||||||
|
qemu_mutex_unlock(lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct gcry_thread_cbs qcrypto_gcrypt_thread_impl = {
|
||||||
|
(GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)),
|
||||||
|
NULL,
|
||||||
|
qcrypto_gcrypt_mutex_init,
|
||||||
|
qcrypto_gcrypt_mutex_destroy,
|
||||||
|
qcrypto_gcrypt_mutex_lock,
|
||||||
|
qcrypto_gcrypt_mutex_unlock,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||||
|
};
|
||||||
|
#endif /* QCRYPTO_INIT_GCRYPT */
|
||||||
|
|
||||||
|
int qcrypto_init(Error **errp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = gnutls_global_init();
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Unable to initialize GNUTLS library: %s",
|
||||||
|
gnutls_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_GNUTLS
|
||||||
|
gnutls_global_set_log_level(10);
|
||||||
|
gnutls_global_set_log_function(qcrypto_gnutls_log);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_GNUTLS_GCRYPT
|
||||||
|
if (!gcry_check_version(GCRYPT_VERSION)) {
|
||||||
|
error_setg(errp, "Unable to initialize gcrypt");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifdef QCRYPTO_INIT_GCRYPT_THREADS
|
||||||
|
gcry_control(GCRYCTL_SET_THREAD_CBS, &qcrypto_gcrypt_thread_impl);
|
||||||
|
#endif /* QCRYPTO_INIT_GCRYPT_THREADS */
|
||||||
|
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* ! CONFIG_GNUTLS */
|
||||||
|
|
||||||
|
int qcrypto_init(Error **errp G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ! CONFIG_GNUTLS */
|
||||||
@@ -16,6 +16,7 @@ CONFIG_PCKBD=y
|
|||||||
CONFIG_FDC=y
|
CONFIG_FDC=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
CONFIG_ACPI_X86=y
|
CONFIG_ACPI_X86=y
|
||||||
|
CONFIG_ACPI_X86_ICH=y
|
||||||
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
||||||
CONFIG_ACPI_CPU_HOTPLUG=y
|
CONFIG_ACPI_CPU_HOTPLUG=y
|
||||||
CONFIG_APM=y
|
CONFIG_APM=y
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ CONFIG_PCKBD=y
|
|||||||
CONFIG_FDC=y
|
CONFIG_FDC=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
CONFIG_ACPI_X86=y
|
CONFIG_ACPI_X86=y
|
||||||
|
CONFIG_ACPI_X86_ICH=y
|
||||||
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
||||||
CONFIG_ACPI_CPU_HOTPLUG=y
|
CONFIG_ACPI_CPU_HOTPLUG=y
|
||||||
CONFIG_APM=y
|
CONFIG_APM=y
|
||||||
|
|||||||
119
disas.c
119
disas.c
@@ -1,5 +1,6 @@
|
|||||||
/* General "disassemble this chunk" code. Used for debugging. */
|
/* General "disassemble this chunk" code. Used for debugging. */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
#include "disas/bfd.h"
|
#include "disas/bfd.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -150,14 +151,6 @@ bfd_vma bfd_getb16 (const bfd_byte *addr)
|
|||||||
return (bfd_vma) v;
|
return (bfd_vma) v;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_ARM
|
|
||||||
static int
|
|
||||||
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
|
|
||||||
{
|
|
||||||
return print_insn_arm(pc | 1, info);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
|
static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
|
||||||
const char *prefix)
|
const char *prefix)
|
||||||
{
|
{
|
||||||
@@ -190,7 +183,6 @@ static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
|
|||||||
/* Disassemble this for me please... (debugging). 'flags' has the following
|
/* Disassemble this for me please... (debugging). 'flags' has the following
|
||||||
values:
|
values:
|
||||||
i386 - 1 means 16 bit code, 2 means 64 bit code
|
i386 - 1 means 16 bit code, 2 means 64 bit code
|
||||||
arm - bit 0 = thumb, bit 1 = reverse endian, bit 2 = A64
|
|
||||||
ppc - bits 0:15 specify (optionally) the machine instruction set;
|
ppc - bits 0:15 specify (optionally) the machine instruction set;
|
||||||
bit 16 indicates little endian.
|
bit 16 indicates little endian.
|
||||||
other targets - unused
|
other targets - unused
|
||||||
@@ -198,10 +190,10 @@ static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
|
|||||||
void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
||||||
target_ulong size, int flags)
|
target_ulong size, int flags)
|
||||||
{
|
{
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
target_ulong pc;
|
target_ulong pc;
|
||||||
int count;
|
int count;
|
||||||
CPUDebug s;
|
CPUDebug s;
|
||||||
int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
|
|
||||||
|
|
||||||
INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
|
INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
|
||||||
|
|
||||||
@@ -216,6 +208,11 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
|||||||
#else
|
#else
|
||||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (cc->disas_set_info) {
|
||||||
|
cc->disas_set_info(cpu, &s.info);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
if (flags == 2) {
|
if (flags == 2) {
|
||||||
s.info.mach = bfd_mach_x86_64;
|
s.info.mach = bfd_mach_x86_64;
|
||||||
@@ -224,30 +221,9 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
|||||||
} else {
|
} else {
|
||||||
s.info.mach = bfd_mach_i386_i386;
|
s.info.mach = bfd_mach_i386_i386;
|
||||||
}
|
}
|
||||||
print_insn = print_insn_i386;
|
s.info.print_insn = print_insn_i386;
|
||||||
#elif defined(TARGET_ARM)
|
|
||||||
if (flags & 4) {
|
|
||||||
/* We might not be compiled with the A64 disassembler
|
|
||||||
* because it needs a C++ compiler; in that case we will
|
|
||||||
* fall through to the default print_insn_od case.
|
|
||||||
*/
|
|
||||||
#if defined(CONFIG_ARM_A64_DIS)
|
|
||||||
print_insn = print_insn_arm_a64;
|
|
||||||
#endif
|
|
||||||
} else if (flags & 1) {
|
|
||||||
print_insn = print_insn_thumb1;
|
|
||||||
} else {
|
|
||||||
print_insn = print_insn_arm;
|
|
||||||
}
|
|
||||||
if (flags & 2) {
|
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
|
||||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
|
||||||
#else
|
|
||||||
s.info.endian = BFD_ENDIAN_BIG;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
print_insn = print_insn_sparc;
|
s.info.print_insn = print_insn_sparc;
|
||||||
#ifdef TARGET_SPARC64
|
#ifdef TARGET_SPARC64
|
||||||
s.info.mach = bfd_mach_sparc_v9b;
|
s.info.mach = bfd_mach_sparc_v9b;
|
||||||
#endif
|
#endif
|
||||||
@@ -266,49 +242,38 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
s.info.disassembler_options = (char *)"any";
|
s.info.disassembler_options = (char *)"any";
|
||||||
print_insn = print_insn_ppc;
|
s.info.print_insn = print_insn_ppc;
|
||||||
#elif defined(TARGET_M68K)
|
#elif defined(TARGET_M68K)
|
||||||
print_insn = print_insn_m68k;
|
s.info.print_insn = print_insn_m68k;
|
||||||
#elif defined(TARGET_MIPS)
|
#elif defined(TARGET_MIPS)
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
print_insn = print_insn_big_mips;
|
s.info.print_insn = print_insn_big_mips;
|
||||||
#else
|
#else
|
||||||
print_insn = print_insn_little_mips;
|
s.info.print_insn = print_insn_little_mips;
|
||||||
#endif
|
#endif
|
||||||
#elif defined(TARGET_SH4)
|
#elif defined(TARGET_SH4)
|
||||||
s.info.mach = bfd_mach_sh4;
|
s.info.mach = bfd_mach_sh4;
|
||||||
print_insn = print_insn_sh;
|
s.info.print_insn = print_insn_sh;
|
||||||
#elif defined(TARGET_ALPHA)
|
#elif defined(TARGET_ALPHA)
|
||||||
s.info.mach = bfd_mach_alpha_ev6;
|
s.info.mach = bfd_mach_alpha_ev6;
|
||||||
print_insn = print_insn_alpha;
|
s.info.print_insn = print_insn_alpha;
|
||||||
#elif defined(TARGET_CRIS)
|
|
||||||
if (flags != 32) {
|
|
||||||
s.info.mach = bfd_mach_cris_v0_v10;
|
|
||||||
print_insn = print_insn_crisv10;
|
|
||||||
} else {
|
|
||||||
s.info.mach = bfd_mach_cris_v32;
|
|
||||||
print_insn = print_insn_crisv32;
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_S390X)
|
#elif defined(TARGET_S390X)
|
||||||
s.info.mach = bfd_mach_s390_64;
|
s.info.mach = bfd_mach_s390_64;
|
||||||
print_insn = print_insn_s390;
|
s.info.print_insn = print_insn_s390;
|
||||||
#elif defined(TARGET_MICROBLAZE)
|
|
||||||
s.info.mach = bfd_arch_microblaze;
|
|
||||||
print_insn = print_insn_microblaze;
|
|
||||||
#elif defined(TARGET_MOXIE)
|
#elif defined(TARGET_MOXIE)
|
||||||
s.info.mach = bfd_arch_moxie;
|
s.info.mach = bfd_arch_moxie;
|
||||||
print_insn = print_insn_moxie;
|
s.info.print_insn = print_insn_moxie;
|
||||||
#elif defined(TARGET_LM32)
|
#elif defined(TARGET_LM32)
|
||||||
s.info.mach = bfd_mach_lm32;
|
s.info.mach = bfd_mach_lm32;
|
||||||
print_insn = print_insn_lm32;
|
s.info.print_insn = print_insn_lm32;
|
||||||
#endif
|
#endif
|
||||||
if (print_insn == NULL) {
|
if (s.info.print_insn == NULL) {
|
||||||
print_insn = print_insn_od_target;
|
s.info.print_insn = print_insn_od_target;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pc = code; size > 0; pc += count, size -= count) {
|
for (pc = code; size > 0; pc += count, size -= count) {
|
||||||
fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
|
fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
|
||||||
count = print_insn(pc, &s.info);
|
count = s.info.print_insn(pc, &s.info);
|
||||||
#if 0
|
#if 0
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -450,9 +415,9 @@ monitor_fprintf(FILE *stream, const char *fmt, ...)
|
|||||||
void monitor_disas(Monitor *mon, CPUState *cpu,
|
void monitor_disas(Monitor *mon, CPUState *cpu,
|
||||||
target_ulong pc, int nb_insn, int is_physical, int flags)
|
target_ulong pc, int nb_insn, int is_physical, int flags)
|
||||||
{
|
{
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
int count, i;
|
int count, i;
|
||||||
CPUDebug s;
|
CPUDebug s;
|
||||||
int (*print_insn)(bfd_vma pc, disassemble_info *info);
|
|
||||||
|
|
||||||
INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
|
INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
|
||||||
|
|
||||||
@@ -468,6 +433,11 @@ void monitor_disas(Monitor *mon, CPUState *cpu,
|
|||||||
#else
|
#else
|
||||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (cc->disas_set_info) {
|
||||||
|
cc->disas_set_info(cpu, &s.info);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
if (flags == 2) {
|
if (flags == 2) {
|
||||||
s.info.mach = bfd_mach_x86_64;
|
s.info.mach = bfd_mach_x86_64;
|
||||||
@@ -476,13 +446,11 @@ void monitor_disas(Monitor *mon, CPUState *cpu,
|
|||||||
} else {
|
} else {
|
||||||
s.info.mach = bfd_mach_i386_i386;
|
s.info.mach = bfd_mach_i386_i386;
|
||||||
}
|
}
|
||||||
print_insn = print_insn_i386;
|
s.info.print_insn = print_insn_i386;
|
||||||
#elif defined(TARGET_ARM)
|
|
||||||
print_insn = print_insn_arm;
|
|
||||||
#elif defined(TARGET_ALPHA)
|
#elif defined(TARGET_ALPHA)
|
||||||
print_insn = print_insn_alpha;
|
s.info.print_insn = print_insn_alpha;
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
print_insn = print_insn_sparc;
|
s.info.print_insn = print_insn_sparc;
|
||||||
#ifdef TARGET_SPARC64
|
#ifdef TARGET_SPARC64
|
||||||
s.info.mach = bfd_mach_sparc_v9b;
|
s.info.mach = bfd_mach_sparc_v9b;
|
||||||
#endif
|
#endif
|
||||||
@@ -500,36 +468,37 @@ void monitor_disas(Monitor *mon, CPUState *cpu,
|
|||||||
if ((flags >> 16) & 1) {
|
if ((flags >> 16) & 1) {
|
||||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||||
}
|
}
|
||||||
print_insn = print_insn_ppc;
|
s.info.print_insn = print_insn_ppc;
|
||||||
#elif defined(TARGET_M68K)
|
#elif defined(TARGET_M68K)
|
||||||
print_insn = print_insn_m68k;
|
s.info.print_insn = print_insn_m68k;
|
||||||
#elif defined(TARGET_MIPS)
|
#elif defined(TARGET_MIPS)
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
print_insn = print_insn_big_mips;
|
s.info.print_insn = print_insn_big_mips;
|
||||||
#else
|
#else
|
||||||
print_insn = print_insn_little_mips;
|
s.info.print_insn = print_insn_little_mips;
|
||||||
#endif
|
#endif
|
||||||
#elif defined(TARGET_SH4)
|
#elif defined(TARGET_SH4)
|
||||||
s.info.mach = bfd_mach_sh4;
|
s.info.mach = bfd_mach_sh4;
|
||||||
print_insn = print_insn_sh;
|
s.info.print_insn = print_insn_sh;
|
||||||
#elif defined(TARGET_S390X)
|
#elif defined(TARGET_S390X)
|
||||||
s.info.mach = bfd_mach_s390_64;
|
s.info.mach = bfd_mach_s390_64;
|
||||||
print_insn = print_insn_s390;
|
s.info.print_insn = print_insn_s390;
|
||||||
#elif defined(TARGET_MOXIE)
|
#elif defined(TARGET_MOXIE)
|
||||||
s.info.mach = bfd_arch_moxie;
|
s.info.mach = bfd_arch_moxie;
|
||||||
print_insn = print_insn_moxie;
|
s.info.print_insn = print_insn_moxie;
|
||||||
#elif defined(TARGET_LM32)
|
#elif defined(TARGET_LM32)
|
||||||
s.info.mach = bfd_mach_lm32;
|
s.info.mach = bfd_mach_lm32;
|
||||||
print_insn = print_insn_lm32;
|
s.info.print_insn = print_insn_lm32;
|
||||||
#else
|
|
||||||
monitor_printf(mon, "0x" TARGET_FMT_lx
|
|
||||||
": Asm output not supported on this arch\n", pc);
|
|
||||||
return;
|
|
||||||
#endif
|
#endif
|
||||||
|
if (!s.info.print_insn) {
|
||||||
|
monitor_printf(mon, "0x" TARGET_FMT_lx
|
||||||
|
": Asm output not supported on this arch\n", pc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for(i = 0; i < nb_insn; i++) {
|
for(i = 0; i < nb_insn; i++) {
|
||||||
monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
|
monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
|
||||||
count = print_insn(pc, &s.info);
|
count = s.info.print_insn(pc, &s.info);
|
||||||
monitor_printf(mon, "\n");
|
monitor_printf(mon, "\n");
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -35,16 +35,25 @@ static Disassembler *vixl_disasm = NULL;
|
|||||||
*/
|
*/
|
||||||
class QEMUDisassembler : public Disassembler {
|
class QEMUDisassembler : public Disassembler {
|
||||||
public:
|
public:
|
||||||
explicit QEMUDisassembler(FILE *stream) : stream_(stream) { }
|
QEMUDisassembler() : printf_(NULL), stream_(NULL) { }
|
||||||
~QEMUDisassembler() { }
|
~QEMUDisassembler() { }
|
||||||
|
|
||||||
|
void SetStream(FILE *stream) {
|
||||||
|
stream_ = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPrintf(int (*printf_fn)(FILE *, const char *, ...)) {
|
||||||
|
printf_ = printf_fn;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void ProcessOutput(const Instruction *instr) {
|
virtual void ProcessOutput(const Instruction *instr) {
|
||||||
fprintf(stream_, "%08" PRIx32 " %s",
|
printf_(stream_, "%08" PRIx32 " %s",
|
||||||
instr->InstructionBits(), GetOutput());
|
instr->InstructionBits(), GetOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int (*printf_)(FILE *, const char *, ...);
|
||||||
FILE *stream_;
|
FILE *stream_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,9 +62,9 @@ static int vixl_is_initialized(void)
|
|||||||
return vixl_decoder != NULL;
|
return vixl_decoder != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vixl_init(FILE *f) {
|
static void vixl_init() {
|
||||||
vixl_decoder = new Decoder();
|
vixl_decoder = new Decoder();
|
||||||
vixl_disasm = new QEMUDisassembler(f);
|
vixl_disasm = new QEMUDisassembler();
|
||||||
vixl_decoder->AppendVisitor(vixl_disasm);
|
vixl_decoder->AppendVisitor(vixl_disasm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,9 +87,12 @@ int print_insn_arm_a64(uint64_t addr, disassemble_info *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!vixl_is_initialized()) {
|
if (!vixl_is_initialized()) {
|
||||||
vixl_init(info->stream);
|
vixl_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
((QEMUDisassembler *)vixl_disasm)->SetPrintf(info->fprintf_func);
|
||||||
|
((QEMUDisassembler *)vixl_disasm)->SetStream(info->stream);
|
||||||
|
|
||||||
instrval = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24;
|
instrval = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24;
|
||||||
instr = reinterpret_cast<const Instruction *>(&instrval);
|
instr = reinterpret_cast<const Instruction *>(&instrval);
|
||||||
vixl_disasm->MapCodeAddress(addr, instr);
|
vixl_disasm->MapCodeAddress(addr, instr);
|
||||||
|
|||||||
@@ -2575,9 +2575,9 @@ print_insn_cris_generic (bfd_vma memaddr,
|
|||||||
If we can't get any data, or we do not get enough data, we print
|
If we can't get any data, or we do not get enough data, we print
|
||||||
the error message. */
|
the error message. */
|
||||||
|
|
||||||
nbytes = info->buffer_length;
|
nbytes = info->buffer_length ? info->buffer_length
|
||||||
if (nbytes > MAX_BYTES_PER_CRIS_INSN)
|
: MAX_BYTES_PER_CRIS_INSN;
|
||||||
nbytes = MAX_BYTES_PER_CRIS_INSN;
|
nbytes = MIN(nbytes, MAX_BYTES_PER_CRIS_INSN);
|
||||||
status = (*info->read_memory_func) (memaddr, buffer, nbytes, info);
|
status = (*info->read_memory_func) (memaddr, buffer, nbytes, info);
|
||||||
|
|
||||||
/* If we did not get all we asked for, then clear the rest.
|
/* If we did not get all we asked for, then clear the rest.
|
||||||
|
|||||||
12
disas/mips.c
12
disas/mips.c
@@ -1296,12 +1296,12 @@ const struct mips_opcode mips_builtin_opcodes[] =
|
|||||||
{"dmod", "d,s,t", 0x000000de, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
{"dmod", "d,s,t", 0x000000de, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||||
{"ddivu", "d,s,t", 0x0000009f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
{"ddivu", "d,s,t", 0x0000009f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||||
{"dmodu", "d,s,t", 0x000000df, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
{"dmodu", "d,s,t", 0x000000df, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||||
{"ll", "t,o(b)", 0x7c000036, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6},
|
{"ll", "t,+o(b)", 0x7c000036, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6},
|
||||||
{"sc", "t,o(b)", 0x7c000026, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6},
|
{"sc", "t,+o(b)", 0x7c000026, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6},
|
||||||
{"lld", "t,o(b)", 0x7c000037, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6},
|
{"lld", "t,+o(b)", 0x7c000037, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6},
|
||||||
{"scd", "t,o(b)", 0x7c000027, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6},
|
{"scd", "t,+o(b)", 0x7c000027, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6},
|
||||||
{"pref", "h,o(b)", 0x7c000035, 0xfc00007f, RD_b, 0, I32R6},
|
{"pref", "h,+o(b)", 0x7c000035, 0xfc00007f, RD_b, 0, I32R6},
|
||||||
{"cache", "k,o(b)", 0x7c000025, 0xfc00007f, RD_b, 0, I32R6},
|
{"cache", "k,+o(b)", 0x7c000025, 0xfc00007f, RD_b, 0, I32R6},
|
||||||
{"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
{"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||||
{"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
{"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||||
{"maddf.s", "D,S,T", 0x46000018, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
{"maddf.s", "D,S,T", 0x46000018, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "qemu-common.h"
|
||||||
#include "disas/bfd.h"
|
#include "disas/bfd.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
|
|
||||||
|
|||||||
@@ -473,6 +473,20 @@ Example:
|
|||||||
{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
|
{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
|
||||||
"event": "SPICE_MIGRATE_COMPLETED" }
|
"event": "SPICE_MIGRATE_COMPLETED" }
|
||||||
|
|
||||||
|
MIGRATION
|
||||||
|
---------
|
||||||
|
|
||||||
|
Emitted when a migration event happens
|
||||||
|
|
||||||
|
Data: None.
|
||||||
|
|
||||||
|
- "status": migration status
|
||||||
|
See MigrationStatus in ~/qapi-schema.json for possible values
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{"timestamp": {"seconds": 1432121972, "microseconds": 744001},
|
||||||
|
"event": "MIGRATION", "data": {"status": "completed"}}
|
||||||
|
|
||||||
STOP
|
STOP
|
||||||
----
|
----
|
||||||
|
|||||||
@@ -284,4 +284,22 @@ struct rtas_event_log_v6_hp {
|
|||||||
} drc;
|
} drc;
|
||||||
} QEMU_PACKED;
|
} QEMU_PACKED;
|
||||||
|
|
||||||
|
== ibm,lrdr-capacity ==
|
||||||
|
|
||||||
|
ibm,lrdr-capacity is a property in the /rtas device tree node that identifies
|
||||||
|
the dynamic reconfiguration capabilities of the guest. It consists of a triple
|
||||||
|
consisting of <phys>, <size> and <maxcpus>.
|
||||||
|
|
||||||
|
<phys>, encoded in BE format represents the maximum address in bytes and
|
||||||
|
hence the maximum memory that can be allocated to the guest.
|
||||||
|
|
||||||
|
<size>, encoded in BE format represents the size increments in which
|
||||||
|
memory can be hot-plugged to the guest.
|
||||||
|
|
||||||
|
<maxcpus>, a BE-encoded integer, represents the maximum number of
|
||||||
|
processors that the guest can have.
|
||||||
|
|
||||||
|
pseries guests use this property to note the maximum allowed CPUs for the
|
||||||
|
guest.
|
||||||
|
|
||||||
[1] http://thread.gmane.org/gmane.linux.ports.ppc.embedded/75350/focus=106867
|
[1] http://thread.gmane.org/gmane.linux.ports.ppc.embedded/75350/focus=106867
|
||||||
|
|||||||
@@ -637,6 +637,7 @@ The TLVs for Rx descriptor buffer are:
|
|||||||
(1 << 5): TCP packet
|
(1 << 5): TCP packet
|
||||||
(1 << 6): UDP packet
|
(1 << 6): UDP packet
|
||||||
(1 << 7): TCP/UDP csum good
|
(1 << 7): TCP/UDP csum good
|
||||||
|
(1 << 8): Offload forward
|
||||||
RX_CSUM 2 IP calculated checksum:
|
RX_CSUM 2 IP calculated checksum:
|
||||||
IPv4: IP payload csum
|
IPv4: IP payload csum
|
||||||
IPv6: header and payload csum
|
IPv6: header and payload csum
|
||||||
@@ -645,6 +646,9 @@ The TLVs for Rx descriptor buffer are:
|
|||||||
RX_FRAG_MAX_LEN 2 Packet maximum fragment length
|
RX_FRAG_MAX_LEN 2 Packet maximum fragment length
|
||||||
RX_FRAG_LEN 2 Actual packet fragment length after receive
|
RX_FRAG_LEN 2 Actual packet fragment length after receive
|
||||||
|
|
||||||
|
Offload forward RX_FLAG indicates the device has already forwarded the packet
|
||||||
|
so the host CPU should not also forward the packet.
|
||||||
|
|
||||||
Possible status return codes in descriptor on completion are:
|
Possible status return codes in descriptor on completion are:
|
||||||
|
|
||||||
DESC_COMP_ERR reason
|
DESC_COMP_ERR reason
|
||||||
|
|||||||
166
exec.c
166
exec.c
@@ -48,6 +48,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "exec/cpu-all.h"
|
#include "exec/cpu-all.h"
|
||||||
#include "qemu/rcu_queue.h"
|
#include "qemu/rcu_queue.h"
|
||||||
|
#include "qemu/main-loop.h"
|
||||||
#include "exec/cputlb.h"
|
#include "exec/cputlb.h"
|
||||||
#include "translate-all.h"
|
#include "translate-all.h"
|
||||||
|
|
||||||
@@ -352,6 +353,18 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
|
|||||||
*xlat = addr + section->offset_within_region;
|
*xlat = addr + section->offset_within_region;
|
||||||
|
|
||||||
mr = section->mr;
|
mr = section->mr;
|
||||||
|
|
||||||
|
/* MMIO registers can be expected to perform full-width accesses based only
|
||||||
|
* on their address, without considering adjacent registers that could
|
||||||
|
* decode to completely different MemoryRegions. When such registers
|
||||||
|
* exist (e.g. I/O ports 0xcf8 and 0xcf9 on most PC chipsets), MMIO
|
||||||
|
* regions overlap wildly. For this reason we cannot clamp the accesses
|
||||||
|
* here.
|
||||||
|
*
|
||||||
|
* If the length is small (as is the case for address_space_ldl/stl),
|
||||||
|
* everything works fine. If the incoming length is large, however,
|
||||||
|
* the caller really has to do the clamping through memory_access_size.
|
||||||
|
*/
|
||||||
if (memory_region_is_ram(mr)) {
|
if (memory_region_is_ram(mr)) {
|
||||||
diff = int128_sub(section->size, int128_make64(addr));
|
diff = int128_sub(section->size, int128_make64(addr));
|
||||||
*plen = int128_get64(int128_min(diff, int128_make64(*plen)));
|
*plen = int128_get64(int128_min(diff, int128_make64(*plen)));
|
||||||
@@ -513,29 +526,74 @@ void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void cpu_exec_init(CPUArchState *env)
|
#ifndef CONFIG_USER_ONLY
|
||||||
{
|
static DECLARE_BITMAP(cpu_index_map, MAX_CPUMASK_BITS);
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
static int cpu_get_free_index(Error **errp)
|
||||||
CPUState *some_cpu;
|
{
|
||||||
int cpu_index;
|
int cpu = find_first_zero_bit(cpu_index_map, MAX_CPUMASK_BITS);
|
||||||
|
|
||||||
|
if (cpu >= MAX_CPUMASK_BITS) {
|
||||||
|
error_setg(errp, "Trying to use more CPUs than max of %d",
|
||||||
|
MAX_CPUMASK_BITS);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_set(cpu_index_map, cpu, 1);
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_exec_exit(CPUState *cpu)
|
||||||
|
{
|
||||||
|
if (cpu->cpu_index == -1) {
|
||||||
|
/* cpu_index was never allocated by this @cpu or was already freed. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_clear(cpu_index_map, cpu->cpu_index, 1);
|
||||||
|
cpu->cpu_index = -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int cpu_get_free_index(Error **errp)
|
||||||
|
{
|
||||||
|
CPUState *some_cpu;
|
||||||
|
int cpu_index = 0;
|
||||||
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
|
||||||
cpu_list_lock();
|
|
||||||
#endif
|
|
||||||
cpu_index = 0;
|
|
||||||
CPU_FOREACH(some_cpu) {
|
CPU_FOREACH(some_cpu) {
|
||||||
cpu_index++;
|
cpu_index++;
|
||||||
}
|
}
|
||||||
cpu->cpu_index = cpu_index;
|
return cpu_index;
|
||||||
cpu->numa_node = 0;
|
}
|
||||||
QTAILQ_INIT(&cpu->breakpoints);
|
|
||||||
QTAILQ_INIT(&cpu->watchpoints);
|
void cpu_exec_exit(CPUState *cpu)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void cpu_exec_init(CPUState *cpu, Error **errp)
|
||||||
|
{
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
int cpu_index;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cpu->as = &address_space_memory;
|
cpu->as = &address_space_memory;
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
cpu_reload_memory_map(cpu);
|
cpu_reload_memory_map(cpu);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
cpu_list_lock();
|
||||||
|
#endif
|
||||||
|
cpu_index = cpu->cpu_index = cpu_get_free_index(&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
cpu_list_unlock();
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
QTAILQ_INSERT_TAIL(&cpus, cpu, node);
|
QTAILQ_INSERT_TAIL(&cpus, cpu, node);
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
cpu_list_unlock();
|
cpu_list_unlock();
|
||||||
@@ -545,7 +603,7 @@ void cpu_exec_init(CPUArchState *env)
|
|||||||
}
|
}
|
||||||
#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
|
#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
|
||||||
register_savevm(NULL, "cpu", cpu_index, CPU_SAVE_VERSION,
|
register_savevm(NULL, "cpu", cpu_index, CPU_SAVE_VERSION,
|
||||||
cpu_save, cpu_load, env);
|
cpu_save, cpu_load, cpu->env_ptr);
|
||||||
assert(cc->vmsd == NULL);
|
assert(cc->vmsd == NULL);
|
||||||
assert(qdev_get_vmsd(DEVICE(cpu)) == NULL);
|
assert(qdev_get_vmsd(DEVICE(cpu)) == NULL);
|
||||||
#endif
|
#endif
|
||||||
@@ -757,8 +815,7 @@ void cpu_single_step(CPUState *cpu, int enabled)
|
|||||||
} else {
|
} else {
|
||||||
/* must flush all the translated code to avoid inconsistencies */
|
/* must flush all the translated code to avoid inconsistencies */
|
||||||
/* XXX: only flush what is necessary */
|
/* XXX: only flush what is necessary */
|
||||||
CPUArchState *env = cpu->env_ptr;
|
tb_flush(cpu);
|
||||||
tb_flush(env);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1401,6 +1458,11 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_ram_size = MAX(old_ram_size,
|
||||||
|
(new_block->offset + new_block->max_length) >> TARGET_PAGE_BITS);
|
||||||
|
if (new_ram_size > old_ram_size) {
|
||||||
|
migration_bitmap_extend(old_ram_size, new_ram_size);
|
||||||
|
}
|
||||||
/* Keep the list sorted from biggest to smallest block. Unlike QTAILQ,
|
/* Keep the list sorted from biggest to smallest block. Unlike QTAILQ,
|
||||||
* QLIST (which has an RCU-friendly variant) does not have insertion at
|
* QLIST (which has an RCU-friendly variant) does not have insertion at
|
||||||
* tail, so save the last element in last_block.
|
* tail, so save the last element in last_block.
|
||||||
@@ -2316,6 +2378,29 @@ static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool prepare_mmio_access(MemoryRegion *mr)
|
||||||
|
{
|
||||||
|
bool unlocked = !qemu_mutex_iothread_locked();
|
||||||
|
bool release_lock = false;
|
||||||
|
|
||||||
|
if (unlocked && mr->global_locking) {
|
||||||
|
qemu_mutex_lock_iothread();
|
||||||
|
unlocked = false;
|
||||||
|
release_lock = true;
|
||||||
|
}
|
||||||
|
if (mr->flush_coalesced_mmio) {
|
||||||
|
if (unlocked) {
|
||||||
|
qemu_mutex_lock_iothread();
|
||||||
|
}
|
||||||
|
qemu_flush_coalesced_mmio_buffer();
|
||||||
|
if (unlocked) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return release_lock;
|
||||||
|
}
|
||||||
|
|
||||||
MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||||
uint8_t *buf, int len, bool is_write)
|
uint8_t *buf, int len, bool is_write)
|
||||||
{
|
{
|
||||||
@@ -2325,6 +2410,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
|||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
MemTxResult result = MEMTX_OK;
|
MemTxResult result = MEMTX_OK;
|
||||||
|
bool release_lock = false;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
@@ -2333,6 +2419,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
|||||||
|
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
if (!memory_access_is_direct(mr, is_write)) {
|
if (!memory_access_is_direct(mr, is_write)) {
|
||||||
|
release_lock |= prepare_mmio_access(mr);
|
||||||
l = memory_access_size(mr, l, addr1);
|
l = memory_access_size(mr, l, addr1);
|
||||||
/* XXX: could force current_cpu to NULL to avoid
|
/* XXX: could force current_cpu to NULL to avoid
|
||||||
potential bugs */
|
potential bugs */
|
||||||
@@ -2374,6 +2461,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
|||||||
} else {
|
} else {
|
||||||
if (!memory_access_is_direct(mr, is_write)) {
|
if (!memory_access_is_direct(mr, is_write)) {
|
||||||
/* I/O case */
|
/* I/O case */
|
||||||
|
release_lock |= prepare_mmio_access(mr);
|
||||||
l = memory_access_size(mr, l, addr1);
|
l = memory_access_size(mr, l, addr1);
|
||||||
switch (l) {
|
switch (l) {
|
||||||
case 8:
|
case 8:
|
||||||
@@ -2409,6 +2497,12 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
|||||||
memcpy(buf, ptr, l);
|
memcpy(buf, ptr, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (release_lock) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
release_lock = false;
|
||||||
|
}
|
||||||
|
|
||||||
len -= l;
|
len -= l;
|
||||||
buf += l;
|
buf += l;
|
||||||
addr += l;
|
addr += l;
|
||||||
@@ -2458,7 +2552,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
|
|||||||
|
|
||||||
if (!(memory_region_is_ram(mr) ||
|
if (!(memory_region_is_ram(mr) ||
|
||||||
memory_region_is_romd(mr))) {
|
memory_region_is_romd(mr))) {
|
||||||
/* do nothing */
|
l = memory_access_size(mr, l, addr1);
|
||||||
} else {
|
} else {
|
||||||
addr1 += memory_region_get_ram_addr(mr);
|
addr1 += memory_region_get_ram_addr(mr);
|
||||||
/* ROM/RAM case */
|
/* ROM/RAM case */
|
||||||
@@ -2735,10 +2829,13 @@ static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
|
|||||||
hwaddr l = 4;
|
hwaddr l = 4;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
bool release_lock = false;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||||
if (l < 4 || !memory_access_is_direct(mr, false)) {
|
if (l < 4 || !memory_access_is_direct(mr, false)) {
|
||||||
|
release_lock |= prepare_mmio_access(mr);
|
||||||
|
|
||||||
/* I/O case */
|
/* I/O case */
|
||||||
r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs);
|
r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs);
|
||||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
@@ -2771,6 +2868,9 @@ static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
if (release_lock) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -2823,11 +2923,14 @@ static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
|
|||||||
hwaddr l = 8;
|
hwaddr l = 8;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
bool release_lock = false;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
false);
|
false);
|
||||||
if (l < 8 || !memory_access_is_direct(mr, false)) {
|
if (l < 8 || !memory_access_is_direct(mr, false)) {
|
||||||
|
release_lock |= prepare_mmio_access(mr);
|
||||||
|
|
||||||
/* I/O case */
|
/* I/O case */
|
||||||
r = memory_region_dispatch_read(mr, addr1, &val, 8, attrs);
|
r = memory_region_dispatch_read(mr, addr1, &val, 8, attrs);
|
||||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
@@ -2860,6 +2963,9 @@ static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
if (release_lock) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -2932,11 +3038,14 @@ static inline uint32_t address_space_lduw_internal(AddressSpace *as,
|
|||||||
hwaddr l = 2;
|
hwaddr l = 2;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
bool release_lock = false;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
false);
|
false);
|
||||||
if (l < 2 || !memory_access_is_direct(mr, false)) {
|
if (l < 2 || !memory_access_is_direct(mr, false)) {
|
||||||
|
release_lock |= prepare_mmio_access(mr);
|
||||||
|
|
||||||
/* I/O case */
|
/* I/O case */
|
||||||
r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs);
|
r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs);
|
||||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
@@ -2969,6 +3078,9 @@ static inline uint32_t address_space_lduw_internal(AddressSpace *as,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
if (release_lock) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -3021,11 +3133,14 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
|
|||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
uint8_t dirty_log_mask;
|
uint8_t dirty_log_mask;
|
||||||
|
bool release_lock = false;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
true);
|
true);
|
||||||
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
||||||
|
release_lock |= prepare_mmio_access(mr);
|
||||||
|
|
||||||
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
|
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
|
||||||
} else {
|
} else {
|
||||||
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
|
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
|
||||||
@@ -3040,6 +3155,9 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
if (release_lock) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3060,11 +3178,14 @@ static inline void address_space_stl_internal(AddressSpace *as,
|
|||||||
hwaddr l = 4;
|
hwaddr l = 4;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
bool release_lock = false;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
true);
|
true);
|
||||||
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
||||||
|
release_lock |= prepare_mmio_access(mr);
|
||||||
|
|
||||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||||
val = bswap32(val);
|
val = bswap32(val);
|
||||||
@@ -3096,6 +3217,9 @@ static inline void address_space_stl_internal(AddressSpace *as,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
if (release_lock) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3165,10 +3289,13 @@ static inline void address_space_stw_internal(AddressSpace *as,
|
|||||||
hwaddr l = 2;
|
hwaddr l = 2;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
bool release_lock = false;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l, true);
|
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||||
if (l < 2 || !memory_access_is_direct(mr, true)) {
|
if (l < 2 || !memory_access_is_direct(mr, true)) {
|
||||||
|
release_lock |= prepare_mmio_access(mr);
|
||||||
|
|
||||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||||
val = bswap16(val);
|
val = bswap16(val);
|
||||||
@@ -3200,6 +3327,9 @@ static inline void address_space_stw_internal(AddressSpace *as,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
if (release_lock) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
gdbstub.c
14
gdbstub.c
@@ -754,12 +754,9 @@ static void gdb_breakpoint_remove_all(void)
|
|||||||
static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
|
static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
|
||||||
{
|
{
|
||||||
CPUState *cpu = s->c_cpu;
|
CPUState *cpu = s->c_cpu;
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
|
||||||
|
|
||||||
cpu_synchronize_state(cpu);
|
cpu_synchronize_state(cpu);
|
||||||
if (cc->set_pc) {
|
cpu_set_pc(cpu, pc);
|
||||||
cc->set_pc(cpu, pc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static CPUState *find_cpu(uint32_t thread_id)
|
static CPUState *find_cpu(uint32_t thread_id)
|
||||||
@@ -1226,7 +1223,6 @@ void gdb_set_stop_cpu(CPUState *cpu)
|
|||||||
static void gdb_vm_state_change(void *opaque, int running, RunState state)
|
static void gdb_vm_state_change(void *opaque, int running, RunState state)
|
||||||
{
|
{
|
||||||
GDBState *s = gdbserver_state;
|
GDBState *s = gdbserver_state;
|
||||||
CPUArchState *env = s->c_cpu->env_ptr;
|
|
||||||
CPUState *cpu = s->c_cpu;
|
CPUState *cpu = s->c_cpu;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
const char *type;
|
const char *type;
|
||||||
@@ -1261,7 +1257,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
|
|||||||
cpu->watchpoint_hit = NULL;
|
cpu->watchpoint_hit = NULL;
|
||||||
goto send_packet;
|
goto send_packet;
|
||||||
}
|
}
|
||||||
tb_flush(env);
|
tb_flush(cpu);
|
||||||
ret = GDB_SIGNAL_TRAP;
|
ret = GDB_SIGNAL_TRAP;
|
||||||
break;
|
break;
|
||||||
case RUN_STATE_PAUSED:
|
case RUN_STATE_PAUSED:
|
||||||
@@ -1490,7 +1486,6 @@ gdb_queuesig (void)
|
|||||||
int
|
int
|
||||||
gdb_handlesig(CPUState *cpu, int sig)
|
gdb_handlesig(CPUState *cpu, int sig)
|
||||||
{
|
{
|
||||||
CPUArchState *env = cpu->env_ptr;
|
|
||||||
GDBState *s;
|
GDBState *s;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int n;
|
int n;
|
||||||
@@ -1502,7 +1497,7 @@ gdb_handlesig(CPUState *cpu, int sig)
|
|||||||
|
|
||||||
/* disable single step if it was enabled */
|
/* disable single step if it was enabled */
|
||||||
cpu_single_step(cpu, 0);
|
cpu_single_step(cpu, 0);
|
||||||
tb_flush(env);
|
tb_flush(cpu);
|
||||||
|
|
||||||
if (sig != 0) {
|
if (sig != 0) {
|
||||||
snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb(sig));
|
snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb(sig));
|
||||||
@@ -1631,9 +1626,8 @@ int gdbserver_start(int port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Disable gdb stub for child processes. */
|
/* Disable gdb stub for child processes. */
|
||||||
void gdbserver_fork(CPUArchState *env)
|
void gdbserver_fork(CPUState *cpu)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
|
||||||
GDBState *s = gdbserver_state;
|
GDBState *s = gdbserver_state;
|
||||||
|
|
||||||
if (gdbserver_fd < 0 || s->fd < 0) {
|
if (gdbserver_fd < 0 || s->fd < 0) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o ich9.o pcihp.o
|
common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o
|
||||||
|
common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o
|
||||||
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
|
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
|
||||||
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
|
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
|
||||||
common-obj-$(CONFIG_ACPI) += acpi_interface.o
|
common-obj-$(CONFIG_ACPI) += acpi_interface.o
|
||||||
|
|||||||
@@ -528,6 +528,7 @@ void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
|
|||||||
ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar);
|
ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar);
|
||||||
memory_region_init_io(&ar->tmr.io, memory_region_owner(parent),
|
memory_region_init_io(&ar->tmr.io, memory_region_owner(parent),
|
||||||
&acpi_pm_tmr_ops, ar, "acpi-tmr", 4);
|
&acpi_pm_tmr_ops, ar, "acpi-tmr", 4);
|
||||||
|
memory_region_clear_global_locking(&ar->tmr.io);
|
||||||
memory_region_add_subregion(parent, 8, &ar->tmr.io);
|
memory_region_add_subregion(parent, 8, &ar->tmr.io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "hw/acpi/acpi.h"
|
#include "hw/acpi/acpi.h"
|
||||||
|
#include "hw/acpi/tco.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
|
|
||||||
@@ -92,8 +93,16 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
unsigned width)
|
unsigned width)
|
||||||
{
|
{
|
||||||
ICH9LPCPMRegs *pm = opaque;
|
ICH9LPCPMRegs *pm = opaque;
|
||||||
|
TCOIORegs *tr = &pm->tco_regs;
|
||||||
|
uint64_t tco_en;
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case 0:
|
case 0:
|
||||||
|
tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN;
|
||||||
|
/* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */
|
||||||
|
if (tr->tco.cnt1 & TCO_LOCK) {
|
||||||
|
val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en;
|
||||||
|
}
|
||||||
pm->smi_en &= ~pm->smi_en_wmask;
|
pm->smi_en &= ~pm->smi_en_wmask;
|
||||||
pm->smi_en |= (val & pm->smi_en_wmask);
|
pm->smi_en |= (val & pm->smi_en_wmask);
|
||||||
break;
|
break;
|
||||||
@@ -159,6 +168,25 @@ static const VMStateDescription vmstate_memhp_state = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool vmstate_test_use_tco(void *opaque)
|
||||||
|
{
|
||||||
|
ICH9LPCPMRegs *s = opaque;
|
||||||
|
return s->enable_tco;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_tco_io_state = {
|
||||||
|
.name = "ich9_pm/tco",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.needed = vmstate_test_use_tco,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
|
||||||
|
TCOIORegs),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_ich9_pm = {
|
const VMStateDescription vmstate_ich9_pm = {
|
||||||
.name = "ich9_pm",
|
.name = "ich9_pm",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
@@ -179,6 +207,10 @@ const VMStateDescription vmstate_ich9_pm = {
|
|||||||
.subsections = (const VMStateDescription*[]) {
|
.subsections = (const VMStateDescription*[]) {
|
||||||
&vmstate_memhp_state,
|
&vmstate_memhp_state,
|
||||||
NULL
|
NULL
|
||||||
|
},
|
||||||
|
.subsections = (const VMStateDescription*[]) {
|
||||||
|
&vmstate_tco_io_state,
|
||||||
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -192,7 +224,7 @@ static void pm_reset(void *opaque)
|
|||||||
acpi_pm_tmr_reset(&pm->acpi_regs);
|
acpi_pm_tmr_reset(&pm->acpi_regs);
|
||||||
acpi_gpe_reset(&pm->acpi_regs);
|
acpi_gpe_reset(&pm->acpi_regs);
|
||||||
|
|
||||||
if (kvm_enabled()) {
|
if (!pm->smm_enabled) {
|
||||||
/* Mark SMM as already inited to prevent SMM from running. KVM does not
|
/* Mark SMM as already inited to prevent SMM from running. KVM does not
|
||||||
* support SMM mode. */
|
* support SMM mode. */
|
||||||
pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
|
pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
|
||||||
@@ -210,6 +242,7 @@ static void pm_powerdown_req(Notifier *n, void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
||||||
|
bool smm_enabled, bool enable_tco,
|
||||||
qemu_irq sci_irq)
|
qemu_irq sci_irq)
|
||||||
{
|
{
|
||||||
memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
|
memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
|
||||||
@@ -231,6 +264,13 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
|||||||
"acpi-smi", 8);
|
"acpi-smi", 8);
|
||||||
memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
|
memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
|
||||||
|
|
||||||
|
pm->smm_enabled = smm_enabled;
|
||||||
|
|
||||||
|
pm->enable_tco = enable_tco;
|
||||||
|
if (pm->enable_tco) {
|
||||||
|
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
|
||||||
|
}
|
||||||
|
|
||||||
pm->irq = sci_irq;
|
pm->irq = sci_irq;
|
||||||
qemu_register_reset(pm_reset, pm);
|
qemu_register_reset(pm_reset, pm);
|
||||||
pm->powerdown_notifier.notify = pm_powerdown_req;
|
pm->powerdown_notifier.notify = pm_powerdown_req;
|
||||||
@@ -351,6 +391,18 @@ out:
|
|||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ich9_pm_get_enable_tco(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
||||||
|
return s->pm.enable_tco;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp)
|
||||||
|
{
|
||||||
|
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
||||||
|
s->pm.enable_tco = value;
|
||||||
|
}
|
||||||
|
|
||||||
void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
|
void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
|
||||||
{
|
{
|
||||||
static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
|
static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
|
||||||
@@ -382,6 +434,10 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
|
|||||||
ich9_pm_get_s4_val,
|
ich9_pm_get_s4_val,
|
||||||
ich9_pm_set_s4_val,
|
ich9_pm_set_s4_val,
|
||||||
NULL, pm, NULL);
|
NULL, pm, NULL);
|
||||||
|
object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED,
|
||||||
|
ich9_pm_get_enable_tco,
|
||||||
|
ich9_pm_set_enable_tco,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp)
|
void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ typedef struct PIIX4PMState {
|
|||||||
|
|
||||||
qemu_irq irq;
|
qemu_irq irq;
|
||||||
qemu_irq smi_irq;
|
qemu_irq smi_irq;
|
||||||
int kvm_enabled;
|
int smm_enabled;
|
||||||
Notifier machine_ready;
|
Notifier machine_ready;
|
||||||
Notifier powerdown_notifier;
|
Notifier powerdown_notifier;
|
||||||
|
|
||||||
@@ -112,6 +112,9 @@ static void apm_ctrl_changed(uint32_t val, void *arg)
|
|||||||
|
|
||||||
/* ACPI specs 3.0, 4.7.2.5 */
|
/* ACPI specs 3.0, 4.7.2.5 */
|
||||||
acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE);
|
acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE);
|
||||||
|
if (val == ACPI_ENABLE || val == ACPI_DISABLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (d->config[0x5b] & (1 << 1)) {
|
if (d->config[0x5b] & (1 << 1)) {
|
||||||
if (s->smi_irq) {
|
if (s->smi_irq) {
|
||||||
@@ -319,7 +322,7 @@ static void piix4_reset(void *opaque)
|
|||||||
pci_conf[0x40] = 0x01; /* PM io base read only bit */
|
pci_conf[0x40] = 0x01; /* PM io base read only bit */
|
||||||
pci_conf[0x80] = 0;
|
pci_conf[0x80] = 0;
|
||||||
|
|
||||||
if (s->kvm_enabled) {
|
if (!s->smm_enabled) {
|
||||||
/* Mark SMM as already inited (until KVM supports SMM). */
|
/* Mark SMM as already inited (until KVM supports SMM). */
|
||||||
pci_conf[0x5B] = 0x02;
|
pci_conf[0x5B] = 0x02;
|
||||||
}
|
}
|
||||||
@@ -450,7 +453,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
|
|||||||
/* APM */
|
/* APM */
|
||||||
apm_init(dev, &s->apm, apm_ctrl_changed, s);
|
apm_init(dev, &s->apm, apm_ctrl_changed, s);
|
||||||
|
|
||||||
if (s->kvm_enabled) {
|
if (!s->smm_enabled) {
|
||||||
/* Mark SMM as already inited to prevent SMM from running. KVM does not
|
/* Mark SMM as already inited to prevent SMM from running. KVM does not
|
||||||
* support SMM mode. */
|
* support SMM mode. */
|
||||||
pci_conf[0x5B] = 0x02;
|
pci_conf[0x5B] = 0x02;
|
||||||
@@ -501,7 +504,7 @@ Object *piix4_pm_find(void)
|
|||||||
|
|
||||||
I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
||||||
qemu_irq sci_irq, qemu_irq smi_irq,
|
qemu_irq sci_irq, qemu_irq smi_irq,
|
||||||
int kvm_enabled, DeviceState **piix4_pm)
|
int smm_enabled, DeviceState **piix4_pm)
|
||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
PIIX4PMState *s;
|
PIIX4PMState *s;
|
||||||
@@ -515,7 +518,7 @@ I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
|||||||
s = PIIX4_PM(dev);
|
s = PIIX4_PM(dev);
|
||||||
s->irq = sci_irq;
|
s->irq = sci_irq;
|
||||||
s->smi_irq = smi_irq;
|
s->smi_irq = smi_irq;
|
||||||
s->kvm_enabled = kvm_enabled;
|
s->smm_enabled = smm_enabled;
|
||||||
if (xen_enabled()) {
|
if (xen_enabled()) {
|
||||||
s->use_acpi_pci_hotplug = false;
|
s->use_acpi_pci_hotplug = false;
|
||||||
}
|
}
|
||||||
|
|||||||
264
hw/acpi/tco.c
Normal file
264
hw/acpi/tco.c
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* QEMU ICH9 TCO emulation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Paulo Alcantara <pcacjr@zytor.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "sysemu/watchdog.h"
|
||||||
|
#include "hw/i386/ich9.h"
|
||||||
|
|
||||||
|
#include "hw/acpi/tco.h"
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define TCO_DEBUG(fmt, ...) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, "%s "fmt, __func__, ## __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define TCO_DEBUG(fmt, ...) do { } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TCO_RLD_DEFAULT = 0x0000,
|
||||||
|
TCO_DAT_IN_DEFAULT = 0x00,
|
||||||
|
TCO_DAT_OUT_DEFAULT = 0x00,
|
||||||
|
TCO1_STS_DEFAULT = 0x0000,
|
||||||
|
TCO2_STS_DEFAULT = 0x0000,
|
||||||
|
TCO1_CNT_DEFAULT = 0x0000,
|
||||||
|
TCO2_CNT_DEFAULT = 0x0008,
|
||||||
|
TCO_MESSAGE1_DEFAULT = 0x00,
|
||||||
|
TCO_MESSAGE2_DEFAULT = 0x00,
|
||||||
|
TCO_WDCNT_DEFAULT = 0x00,
|
||||||
|
TCO_TMR_DEFAULT = 0x0004,
|
||||||
|
SW_IRQ_GEN_DEFAULT = 0x03,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void tco_timer_reload(TCOIORegs *tr)
|
||||||
|
{
|
||||||
|
tr->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||||
|
((int64_t)(tr->tco.tmr & TCO_TMR_MASK) * TCO_TICK_NSEC);
|
||||||
|
timer_mod(tr->tco_timer, tr->expire_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void tco_timer_stop(TCOIORegs *tr)
|
||||||
|
{
|
||||||
|
tr->expire_time = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tco_timer_expired(void *opaque)
|
||||||
|
{
|
||||||
|
TCOIORegs *tr = opaque;
|
||||||
|
ICH9LPCPMRegs *pm = container_of(tr, ICH9LPCPMRegs, tco_regs);
|
||||||
|
ICH9LPCState *lpc = container_of(pm, ICH9LPCState, pm);
|
||||||
|
uint32_t gcs = pci_get_long(lpc->chip_config + ICH9_CC_GCS);
|
||||||
|
|
||||||
|
tr->tco.rld = 0;
|
||||||
|
tr->tco.sts1 |= TCO_TIMEOUT;
|
||||||
|
if (++tr->timeouts_no == 2) {
|
||||||
|
tr->tco.sts2 |= TCO_SECOND_TO_STS;
|
||||||
|
tr->tco.sts2 |= TCO_BOOT_STS;
|
||||||
|
tr->timeouts_no = 0;
|
||||||
|
|
||||||
|
if (!lpc->pin_strap.spkr_hi && !(gcs & ICH9_CC_GCS_NO_REBOOT)) {
|
||||||
|
watchdog_perform_action();
|
||||||
|
tco_timer_stop(tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN) {
|
||||||
|
ich9_generate_smi();
|
||||||
|
} else {
|
||||||
|
ich9_generate_nmi();
|
||||||
|
}
|
||||||
|
tr->tco.rld = tr->tco.tmr;
|
||||||
|
tco_timer_reload(tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: values of 0 or 1 will be ignored by ICH */
|
||||||
|
static inline int can_start_tco_timer(TCOIORegs *tr)
|
||||||
|
{
|
||||||
|
return !(tr->tco.cnt1 & TCO_TMR_HLT) && tr->tco.tmr > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t tco_ioport_readw(TCOIORegs *tr, uint32_t addr)
|
||||||
|
{
|
||||||
|
uint16_t rld;
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case TCO_RLD:
|
||||||
|
if (tr->expire_time != -1) {
|
||||||
|
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
|
int64_t elapsed = (tr->expire_time - now) / TCO_TICK_NSEC;
|
||||||
|
rld = (uint16_t)elapsed | (tr->tco.rld & ~TCO_RLD_MASK);
|
||||||
|
} else {
|
||||||
|
rld = tr->tco.rld;
|
||||||
|
}
|
||||||
|
return rld;
|
||||||
|
case TCO_DAT_IN:
|
||||||
|
return tr->tco.din;
|
||||||
|
case TCO_DAT_OUT:
|
||||||
|
return tr->tco.dout;
|
||||||
|
case TCO1_STS:
|
||||||
|
return tr->tco.sts1;
|
||||||
|
case TCO2_STS:
|
||||||
|
return tr->tco.sts2;
|
||||||
|
case TCO1_CNT:
|
||||||
|
return tr->tco.cnt1;
|
||||||
|
case TCO2_CNT:
|
||||||
|
return tr->tco.cnt2;
|
||||||
|
case TCO_MESSAGE1:
|
||||||
|
return tr->tco.msg1;
|
||||||
|
case TCO_MESSAGE2:
|
||||||
|
return tr->tco.msg2;
|
||||||
|
case TCO_WDCNT:
|
||||||
|
return tr->tco.wdcnt;
|
||||||
|
case TCO_TMR:
|
||||||
|
return tr->tco.tmr;
|
||||||
|
case SW_IRQ_GEN:
|
||||||
|
return tr->sw_irq_gen;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tco_ioport_writew(TCOIORegs *tr, uint32_t addr, uint32_t val)
|
||||||
|
{
|
||||||
|
switch (addr) {
|
||||||
|
case TCO_RLD:
|
||||||
|
tr->timeouts_no = 0;
|
||||||
|
if (can_start_tco_timer(tr)) {
|
||||||
|
tr->tco.rld = tr->tco.tmr;
|
||||||
|
tco_timer_reload(tr);
|
||||||
|
} else {
|
||||||
|
tr->tco.rld = val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TCO_DAT_IN:
|
||||||
|
tr->tco.din = val;
|
||||||
|
tr->tco.sts1 |= SW_TCO_SMI;
|
||||||
|
ich9_generate_smi();
|
||||||
|
break;
|
||||||
|
case TCO_DAT_OUT:
|
||||||
|
tr->tco.dout = val;
|
||||||
|
tr->tco.sts1 |= TCO_INT_STS;
|
||||||
|
/* TODO: cause an interrupt, as selected by the TCO_INT_SEL bits */
|
||||||
|
break;
|
||||||
|
case TCO1_STS:
|
||||||
|
tr->tco.sts1 = val & TCO1_STS_MASK;
|
||||||
|
break;
|
||||||
|
case TCO2_STS:
|
||||||
|
tr->tco.sts2 = val & TCO2_STS_MASK;
|
||||||
|
break;
|
||||||
|
case TCO1_CNT:
|
||||||
|
val &= TCO1_CNT_MASK;
|
||||||
|
/*
|
||||||
|
* once TCO_LOCK bit is set, it can not be cleared by software. a reset
|
||||||
|
* is required to change this bit from 1 to 0 -- it defaults to 0.
|
||||||
|
*/
|
||||||
|
tr->tco.cnt1 = val | (tr->tco.cnt1 & TCO_LOCK);
|
||||||
|
if (can_start_tco_timer(tr)) {
|
||||||
|
tr->tco.rld = tr->tco.tmr;
|
||||||
|
tco_timer_reload(tr);
|
||||||
|
} else {
|
||||||
|
tco_timer_stop(tr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TCO2_CNT:
|
||||||
|
tr->tco.cnt2 = val;
|
||||||
|
break;
|
||||||
|
case TCO_MESSAGE1:
|
||||||
|
tr->tco.msg1 = val;
|
||||||
|
break;
|
||||||
|
case TCO_MESSAGE2:
|
||||||
|
tr->tco.msg2 = val;
|
||||||
|
break;
|
||||||
|
case TCO_WDCNT:
|
||||||
|
tr->tco.wdcnt = val;
|
||||||
|
break;
|
||||||
|
case TCO_TMR:
|
||||||
|
tr->tco.tmr = val;
|
||||||
|
break;
|
||||||
|
case SW_IRQ_GEN:
|
||||||
|
tr->sw_irq_gen = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t tco_io_readw(void *opaque, hwaddr addr, unsigned width)
|
||||||
|
{
|
||||||
|
TCOIORegs *tr = opaque;
|
||||||
|
return tco_ioport_readw(tr, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tco_io_writew(void *opaque, hwaddr addr, uint64_t val,
|
||||||
|
unsigned width)
|
||||||
|
{
|
||||||
|
TCOIORegs *tr = opaque;
|
||||||
|
tco_ioport_writew(tr, addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps tco_io_ops = {
|
||||||
|
.read = tco_io_readw,
|
||||||
|
.write = tco_io_writew,
|
||||||
|
.valid.min_access_size = 1,
|
||||||
|
.valid.max_access_size = 4,
|
||||||
|
.impl.min_access_size = 1,
|
||||||
|
.impl.max_access_size = 2,
|
||||||
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
void acpi_pm_tco_init(TCOIORegs *tr, MemoryRegion *parent)
|
||||||
|
{
|
||||||
|
*tr = (TCOIORegs) {
|
||||||
|
.tco = {
|
||||||
|
.rld = TCO_RLD_DEFAULT,
|
||||||
|
.din = TCO_DAT_IN_DEFAULT,
|
||||||
|
.dout = TCO_DAT_OUT_DEFAULT,
|
||||||
|
.sts1 = TCO1_STS_DEFAULT,
|
||||||
|
.sts2 = TCO2_STS_DEFAULT,
|
||||||
|
.cnt1 = TCO1_CNT_DEFAULT,
|
||||||
|
.cnt2 = TCO2_CNT_DEFAULT,
|
||||||
|
.msg1 = TCO_MESSAGE1_DEFAULT,
|
||||||
|
.msg2 = TCO_MESSAGE2_DEFAULT,
|
||||||
|
.wdcnt = TCO_WDCNT_DEFAULT,
|
||||||
|
.tmr = TCO_TMR_DEFAULT,
|
||||||
|
},
|
||||||
|
.sw_irq_gen = SW_IRQ_GEN_DEFAULT,
|
||||||
|
.tco_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tco_timer_expired, tr),
|
||||||
|
.expire_time = -1,
|
||||||
|
.timeouts_no = 0,
|
||||||
|
};
|
||||||
|
memory_region_init_io(&tr->io, memory_region_owner(parent),
|
||||||
|
&tco_io_ops, tr, "sm-tco", ICH9_PMIO_TCO_LEN);
|
||||||
|
memory_region_add_subregion(parent, ICH9_PMIO_TCO_RLD, &tr->io);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_tco_io_sts = {
|
||||||
|
.name = "tco io device status",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT16(tco.rld, TCOIORegs),
|
||||||
|
VMSTATE_UINT8(tco.din, TCOIORegs),
|
||||||
|
VMSTATE_UINT8(tco.dout, TCOIORegs),
|
||||||
|
VMSTATE_UINT16(tco.sts1, TCOIORegs),
|
||||||
|
VMSTATE_UINT16(tco.sts2, TCOIORegs),
|
||||||
|
VMSTATE_UINT16(tco.cnt1, TCOIORegs),
|
||||||
|
VMSTATE_UINT16(tco.cnt2, TCOIORegs),
|
||||||
|
VMSTATE_UINT8(tco.msg1, TCOIORegs),
|
||||||
|
VMSTATE_UINT8(tco.msg2, TCOIORegs),
|
||||||
|
VMSTATE_UINT8(tco.wdcnt, TCOIORegs),
|
||||||
|
VMSTATE_UINT16(tco.tmr, TCOIORegs),
|
||||||
|
VMSTATE_UINT8(sw_irq_gen, TCOIORegs),
|
||||||
|
VMSTATE_TIMER_PTR(tco_timer, TCOIORegs),
|
||||||
|
VMSTATE_INT64(expire_time, TCOIORegs),
|
||||||
|
VMSTATE_UINT8(timeouts_no, TCOIORegs),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -168,11 +168,11 @@ static void default_write_secondary(ARMCPU *cpu,
|
|||||||
static void default_reset_secondary(ARMCPU *cpu,
|
static void default_reset_secondary(ARMCPU *cpu,
|
||||||
const struct arm_boot_info *info)
|
const struct arm_boot_info *info)
|
||||||
{
|
{
|
||||||
CPUARMState *env = &cpu->env;
|
CPUState *cs = CPU(cpu);
|
||||||
|
|
||||||
address_space_stl_notdirty(&address_space_memory, info->smp_bootreg_addr,
|
address_space_stl_notdirty(&address_space_memory, info->smp_bootreg_addr,
|
||||||
0, MEMTXATTRS_UNSPECIFIED, NULL);
|
0, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
env->regs[15] = info->smp_loader_start;
|
cpu_set_pc(cs, info->smp_loader_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool have_dtb(const struct arm_boot_info *info)
|
static inline bool have_dtb(const struct arm_boot_info *info)
|
||||||
@@ -445,19 +445,21 @@ fail:
|
|||||||
static void do_cpu_reset(void *opaque)
|
static void do_cpu_reset(void *opaque)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = opaque;
|
ARMCPU *cpu = opaque;
|
||||||
|
CPUState *cs = CPU(cpu);
|
||||||
CPUARMState *env = &cpu->env;
|
CPUARMState *env = &cpu->env;
|
||||||
const struct arm_boot_info *info = env->boot_info;
|
const struct arm_boot_info *info = env->boot_info;
|
||||||
|
|
||||||
cpu_reset(CPU(cpu));
|
cpu_reset(cs);
|
||||||
if (info) {
|
if (info) {
|
||||||
if (!info->is_linux) {
|
if (!info->is_linux) {
|
||||||
/* Jump to the entry point. */
|
/* Jump to the entry point. */
|
||||||
if (env->aarch64) {
|
uint64_t entry = info->entry;
|
||||||
env->pc = info->entry;
|
|
||||||
} else {
|
if (!env->aarch64) {
|
||||||
env->regs[15] = info->entry & 0xfffffffe;
|
|
||||||
env->thumb = info->entry & 1;
|
env->thumb = info->entry & 1;
|
||||||
|
entry &= 0xfffffffe;
|
||||||
}
|
}
|
||||||
|
cpu_set_pc(cs, entry);
|
||||||
} else {
|
} else {
|
||||||
/* If we are booting Linux then we need to check whether we are
|
/* If we are booting Linux then we need to check whether we are
|
||||||
* booting into secure or non-secure state and adjust the state
|
* booting into secure or non-secure state and adjust the state
|
||||||
@@ -487,12 +489,8 @@ static void do_cpu_reset(void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CPU(cpu) == first_cpu) {
|
if (cs == first_cpu) {
|
||||||
if (env->aarch64) {
|
cpu_set_pc(cs, info->loader_start);
|
||||||
env->pc = info->loader_start;
|
|
||||||
} else {
|
|
||||||
env->regs[15] = info->loader_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!have_dtb(info)) {
|
if (!have_dtb(info)) {
|
||||||
if (old_param) {
|
if (old_param) {
|
||||||
@@ -737,12 +735,28 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
|
|||||||
* we point to the kernel args.
|
* we point to the kernel args.
|
||||||
*/
|
*/
|
||||||
if (have_dtb(info)) {
|
if (have_dtb(info)) {
|
||||||
/* Place the DTB after the initrd in memory. Note that some
|
hwaddr align;
|
||||||
* kernels will trash anything in the 4K page the initrd
|
hwaddr dtb_start;
|
||||||
* ends in, so make sure the DTB isn't caught up in that.
|
|
||||||
*/
|
if (elf_machine == EM_AARCH64) {
|
||||||
hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size,
|
/*
|
||||||
4096);
|
* Some AArch64 kernels on early bootup map the fdt region as
|
||||||
|
*
|
||||||
|
* [ ALIGN_DOWN(fdt, 2MB) ... ALIGN_DOWN(fdt, 2MB) + 2MB ]
|
||||||
|
*
|
||||||
|
* Let's play safe and prealign it to 2MB to give us some space.
|
||||||
|
*/
|
||||||
|
align = 2 * 1024 * 1024;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Some 32bit kernels will trash anything in the 4K page the
|
||||||
|
* initrd ends in, so make sure the DTB isn't caught up in that.
|
||||||
|
*/
|
||||||
|
align = 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Place the DTB after the initrd in memory with alignment. */
|
||||||
|
dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, align);
|
||||||
if (load_dtb(dtb_start, info, 0) < 0) {
|
if (load_dtb(dtb_start, info, 0) < 0) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,11 +207,23 @@ static void nvme_rw_cb(void *opaque, int ret)
|
|||||||
} else {
|
} else {
|
||||||
req->status = NVME_INTERNAL_DEV_ERROR;
|
req->status = NVME_INTERNAL_DEV_ERROR;
|
||||||
}
|
}
|
||||||
|
if (req->has_sg) {
|
||||||
qemu_sglist_destroy(&req->qsg);
|
qemu_sglist_destroy(&req->qsg);
|
||||||
|
}
|
||||||
nvme_enqueue_req_completion(cq, req);
|
nvme_enqueue_req_completion(cq, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint16_t nvme_flush(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
||||||
|
NvmeRequest *req)
|
||||||
|
{
|
||||||
|
req->has_sg = false;
|
||||||
|
block_acct_start(blk_get_stats(n->conf.blk), &req->acct, 0,
|
||||||
|
BLOCK_ACCT_FLUSH);
|
||||||
|
req->aiocb = blk_aio_flush(n->conf.blk, nvme_rw_cb, req);
|
||||||
|
|
||||||
|
return NVME_NO_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
||||||
NvmeRequest *req)
|
NvmeRequest *req)
|
||||||
{
|
{
|
||||||
@@ -235,6 +247,7 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
|||||||
}
|
}
|
||||||
assert((nlb << data_shift) == req->qsg.size);
|
assert((nlb << data_shift) == req->qsg.size);
|
||||||
|
|
||||||
|
req->has_sg = true;
|
||||||
dma_acct_start(n->conf.blk, &req->acct, &req->qsg,
|
dma_acct_start(n->conf.blk, &req->acct, &req->qsg,
|
||||||
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
|
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
|
||||||
req->aiocb = is_write ?
|
req->aiocb = is_write ?
|
||||||
@@ -256,7 +269,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
|||||||
ns = &n->namespaces[nsid - 1];
|
ns = &n->namespaces[nsid - 1];
|
||||||
switch (cmd->opcode) {
|
switch (cmd->opcode) {
|
||||||
case NVME_CMD_FLUSH:
|
case NVME_CMD_FLUSH:
|
||||||
return NVME_SUCCESS;
|
return nvme_flush(n, ns, cmd, req);
|
||||||
case NVME_CMD_WRITE:
|
case NVME_CMD_WRITE:
|
||||||
case NVME_CMD_READ:
|
case NVME_CMD_READ:
|
||||||
return nvme_rw(n, ns, cmd, req);
|
return nvme_rw(n, ns, cmd, req);
|
||||||
@@ -474,26 +487,32 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
|
|||||||
static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
||||||
{
|
{
|
||||||
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
|
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
|
||||||
|
uint32_t result;
|
||||||
|
|
||||||
switch (dw10) {
|
switch (dw10) {
|
||||||
case NVME_NUMBER_OF_QUEUES:
|
|
||||||
req->cqe.result =
|
|
||||||
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
|
||||||
break;
|
|
||||||
case NVME_VOLATILE_WRITE_CACHE:
|
case NVME_VOLATILE_WRITE_CACHE:
|
||||||
req->cqe.result = cpu_to_le32(1);
|
result = blk_enable_write_cache(n->conf.blk);
|
||||||
|
break;
|
||||||
|
case NVME_NUMBER_OF_QUEUES:
|
||||||
|
result = cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
return NVME_INVALID_FIELD | NVME_DNR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req->cqe.result = result;
|
||||||
return NVME_SUCCESS;
|
return NVME_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
||||||
{
|
{
|
||||||
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
|
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
|
||||||
|
uint32_t dw11 = le32_to_cpu(cmd->cdw11);
|
||||||
|
|
||||||
switch (dw10) {
|
switch (dw10) {
|
||||||
|
case NVME_VOLATILE_WRITE_CACHE:
|
||||||
|
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
|
||||||
|
break;
|
||||||
case NVME_NUMBER_OF_QUEUES:
|
case NVME_NUMBER_OF_QUEUES:
|
||||||
req->cqe.result =
|
req->cqe.result =
|
||||||
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||||
@@ -818,6 +837,9 @@ static int nvme_init(PCIDevice *pci_dev)
|
|||||||
id->psd[0].mp = cpu_to_le16(0x9c4);
|
id->psd[0].mp = cpu_to_le16(0x9c4);
|
||||||
id->psd[0].enlat = cpu_to_le32(0x10);
|
id->psd[0].enlat = cpu_to_le32(0x10);
|
||||||
id->psd[0].exlat = cpu_to_le32(0x4);
|
id->psd[0].exlat = cpu_to_le32(0x4);
|
||||||
|
if (blk_enable_write_cache(n->conf.blk)) {
|
||||||
|
id->vwc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
n->bar.cap = 0;
|
n->bar.cap = 0;
|
||||||
NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
|
NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
|
||||||
|
|||||||
@@ -638,6 +638,7 @@ typedef struct NvmeRequest {
|
|||||||
struct NvmeSQueue *sq;
|
struct NvmeSQueue *sq;
|
||||||
BlockAIOCB *aiocb;
|
BlockAIOCB *aiocb;
|
||||||
uint16_t status;
|
uint16_t status;
|
||||||
|
bool has_sg;
|
||||||
NvmeCqe cqe;
|
NvmeCqe cqe;
|
||||||
BlockAcctCookie acct;
|
BlockAcctCookie acct;
|
||||||
QEMUSGList qsg;
|
QEMUSGList qsg;
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Forward declaration */
|
/* Forward declaration */
|
||||||
static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
target_ulong reg = args[0];
|
target_ulong reg = args[0];
|
||||||
@@ -101,7 +101,7 @@ static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
target_ulong reg = args[0];
|
target_ulong reg = args[0];
|
||||||
@@ -193,7 +193,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
|
|||||||
DeviceState *iter = kid->child;
|
DeviceState *iter = kid->child;
|
||||||
|
|
||||||
/* Only look at VTY devices */
|
/* Only look at VTY devices */
|
||||||
if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
|
if (!object_dynamic_cast(OBJECT(iter), TYPE_VIO_SPAPR_VTY_DEVICE)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
|
|||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
VIOsPAPRDevice *vty_lookup(sPAPRMachineState *spapr, target_ulong reg)
|
||||||
{
|
{
|
||||||
VIOsPAPRDevice *sdev;
|
VIOsPAPRDevice *sdev;
|
||||||
|
|
||||||
@@ -228,6 +228,10 @@ VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
|||||||
return spapr_vty_get_default(spapr->vio_bus);
|
return spapr_vty_get_default(spapr->vio_bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!object_dynamic_cast(OBJECT(sdev), TYPE_VIO_SPAPR_VTY_DEVICE)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return sdev;
|
return sdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -933,7 +933,7 @@ static void rom_reset(void *unused)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int rom_load_all(void)
|
int rom_check_and_register_reset(void)
|
||||||
{
|
{
|
||||||
hwaddr addr = 0;
|
hwaddr addr = 0;
|
||||||
MemoryRegionSection section;
|
MemoryRegionSection section;
|
||||||
@@ -957,12 +957,8 @@ int rom_load_all(void)
|
|||||||
memory_region_unref(section.mr);
|
memory_region_unref(section.mr);
|
||||||
}
|
}
|
||||||
qemu_register_reset(rom_reset, NULL);
|
qemu_register_reset(rom_reset, NULL);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rom_load_done(void)
|
|
||||||
{
|
|
||||||
roms_loaded = 1;
|
roms_loaded = 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rom_set_fw(FWCfgState *f)
|
void rom_set_fw(FWCfgState *f)
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ PropertyInfo qdev_prop_bit = {
|
|||||||
|
|
||||||
static uint64_t qdev_get_prop_mask64(Property *prop)
|
static uint64_t qdev_get_prop_mask64(Property *prop)
|
||||||
{
|
{
|
||||||
assert(prop->info == &qdev_prop_bit);
|
assert(prop->info == &qdev_prop_bit64);
|
||||||
return 0x1ull << prop->bitnr;
|
return 0x1ull << prop->bitnr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,13 @@ qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n)
|
|||||||
|
|
||||||
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
|
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
|
||||||
{
|
{
|
||||||
|
SysBusDeviceClass *sbd = SYS_BUS_DEVICE_GET_CLASS(dev);
|
||||||
|
|
||||||
qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);
|
qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);
|
||||||
|
|
||||||
|
if (sbd->connect_irq_notifier) {
|
||||||
|
sbd->connect_irq_notifier(dev, irq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check whether an MMIO region exists */
|
/* Check whether an MMIO region exists */
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include "hw/virtio/virtio-gpu.h"
|
#include "hw/virtio/virtio-gpu.h"
|
||||||
|
|
||||||
static Property virtio_gpu_pci_properties[] = {
|
static Property virtio_gpu_pci_properties[] = {
|
||||||
DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOGPUPCI, vdev.conf),
|
|
||||||
DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
|
DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
@@ -25,13 +24,21 @@ static Property virtio_gpu_pci_properties[] = {
|
|||||||
static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||||
{
|
{
|
||||||
VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev);
|
VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev);
|
||||||
|
VirtIOGPU *g = &vgpu->vdev;
|
||||||
DeviceState *vdev = DEVICE(&vgpu->vdev);
|
DeviceState *vdev = DEVICE(&vgpu->vdev);
|
||||||
|
int i;
|
||||||
|
|
||||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||||
/* force virtio-1.0 */
|
/* force virtio-1.0 */
|
||||||
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
|
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
|
||||||
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
|
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
|
||||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||||
|
|
||||||
|
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||||
|
object_property_set_link(OBJECT(g->scanout[i].con),
|
||||||
|
OBJECT(vpci_dev),
|
||||||
|
"device", errp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
|
static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
|
||||||
@@ -49,8 +56,9 @@ static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
|
|||||||
static void virtio_gpu_initfn(Object *obj)
|
static void virtio_gpu_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
VirtIOGPUPCI *dev = VIRTIO_GPU_PCI(obj);
|
VirtIOGPUPCI *dev = VIRTIO_GPU_PCI(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU);
|
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||||
|
TYPE_VIRTIO_GPU);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo virtio_gpu_pci_info = {
|
static const TypeInfo virtio_gpu_pci_info = {
|
||||||
|
|||||||
@@ -871,7 +871,7 @@ static void virtio_gpu_reset(VirtIODevice *vdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Property virtio_gpu_properties[] = {
|
static Property virtio_gpu_properties[] = {
|
||||||
DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOGPU, conf),
|
DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
|||||||
VirtIOGPU *g = &vvga->vdev;
|
VirtIOGPU *g = &vvga->vdev;
|
||||||
VGACommonState *vga = &vvga->vga;
|
VGACommonState *vga = &vvga->vga;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* init vga compat bits */
|
/* init vga compat bits */
|
||||||
vga->vram_size_mb = 8;
|
vga->vram_size_mb = 8;
|
||||||
@@ -120,6 +121,12 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
|||||||
|
|
||||||
vga->con = g->scanout[0].con;
|
vga->con = g->scanout[0].con;
|
||||||
graphic_console_set_hwops(vga->con, &virtio_vga_ops, vvga);
|
graphic_console_set_hwops(vga->con, &virtio_vga_ops, vvga);
|
||||||
|
|
||||||
|
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||||
|
object_property_set_link(OBJECT(g->scanout[i].con),
|
||||||
|
OBJECT(vpci_dev),
|
||||||
|
"device", errp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_vga_reset(DeviceState *dev)
|
static void virtio_vga_reset(DeviceState *dev)
|
||||||
@@ -131,7 +138,6 @@ static void virtio_vga_reset(DeviceState *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Property virtio_vga_properties[] = {
|
static Property virtio_vga_properties[] = {
|
||||||
DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOVGA, vdev.conf),
|
|
||||||
DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
|
DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
@@ -155,8 +161,9 @@ static void virtio_vga_class_init(ObjectClass *klass, void *data)
|
|||||||
static void virtio_vga_inst_initfn(Object *obj)
|
static void virtio_vga_inst_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
VirtIOVGA *dev = VIRTIO_VGA(obj);
|
VirtIOVGA *dev = VIRTIO_VGA(obj);
|
||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU);
|
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||||
|
TYPE_VIRTIO_GPU);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeInfo virtio_vga_info = {
|
static TypeInfo virtio_vga_info = {
|
||||||
|
|||||||
@@ -1509,7 +1509,7 @@ build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
|
|||||||
*/
|
*/
|
||||||
if (hotplugabble_address_space_size) {
|
if (hotplugabble_address_space_size) {
|
||||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||||
acpi_build_srat_memory(numamem, pcms->hotplug_memory_base,
|
acpi_build_srat_memory(numamem, pcms->hotplug_memory.base,
|
||||||
hotplugabble_address_space_size, 0,
|
hotplugabble_address_space_size, 0,
|
||||||
MEM_AFFINITY_HOTPLUGGABLE |
|
MEM_AFFINITY_HOTPLUGGABLE |
|
||||||
MEM_AFFINITY_ENABLED);
|
MEM_AFFINITY_ENABLED);
|
||||||
|
|||||||
264
hw/i386/pc.c
264
hw/i386/pc.c
@@ -64,7 +64,6 @@
|
|||||||
#include "hw/pci/pci_host.h"
|
#include "hw/pci/pci_host.h"
|
||||||
#include "acpi-build.h"
|
#include "acpi-build.h"
|
||||||
#include "hw/mem/pc-dimm.h"
|
#include "hw/mem/pc-dimm.h"
|
||||||
#include "trace.h"
|
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
#include "qapi-visit.h"
|
#include "qapi-visit.h"
|
||||||
|
|
||||||
@@ -294,11 +293,82 @@ static void pc_boot_set(void *opaque, const char *boot_device, Error **errp)
|
|||||||
set_boot_dev(opaque, boot_device, errp);
|
set_boot_dev(opaque, boot_device, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pc_cmos_init_floppy(ISADevice *rtc_state, ISADevice *floppy)
|
||||||
|
{
|
||||||
|
int val, nb, i;
|
||||||
|
FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
|
||||||
|
|
||||||
|
/* floppy type */
|
||||||
|
if (floppy) {
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
fd_type[i] = isa_fdc_get_drive_type(floppy, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
|
||||||
|
cmos_get_fd_drive_type(fd_type[1]);
|
||||||
|
rtc_set_memory(rtc_state, 0x10, val);
|
||||||
|
|
||||||
|
val = rtc_get_memory(rtc_state, REG_EQUIPMENT_BYTE);
|
||||||
|
nb = 0;
|
||||||
|
if (fd_type[0] < FDRIVE_DRV_NONE) {
|
||||||
|
nb++;
|
||||||
|
}
|
||||||
|
if (fd_type[1] < FDRIVE_DRV_NONE) {
|
||||||
|
nb++;
|
||||||
|
}
|
||||||
|
switch (nb) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
val |= 0x01; /* 1 drive, ready for boot */
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
val |= 0x41; /* 2 drives, ready for boot */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rtc_set_memory(rtc_state, REG_EQUIPMENT_BYTE, val);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct pc_cmos_init_late_arg {
|
typedef struct pc_cmos_init_late_arg {
|
||||||
ISADevice *rtc_state;
|
ISADevice *rtc_state;
|
||||||
BusState *idebus[2];
|
BusState *idebus[2];
|
||||||
} pc_cmos_init_late_arg;
|
} pc_cmos_init_late_arg;
|
||||||
|
|
||||||
|
typedef struct check_fdc_state {
|
||||||
|
ISADevice *floppy;
|
||||||
|
bool multiple;
|
||||||
|
} CheckFdcState;
|
||||||
|
|
||||||
|
static int check_fdc(Object *obj, void *opaque)
|
||||||
|
{
|
||||||
|
CheckFdcState *state = opaque;
|
||||||
|
Object *fdc;
|
||||||
|
uint32_t iobase;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
fdc = object_dynamic_cast(obj, TYPE_ISA_FDC);
|
||||||
|
if (!fdc) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iobase = object_property_get_int(obj, "iobase", &local_err);
|
||||||
|
if (local_err || iobase != 0x3f0) {
|
||||||
|
error_free(local_err);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->floppy) {
|
||||||
|
state->multiple = true;
|
||||||
|
} else {
|
||||||
|
state->floppy = ISA_DEVICE(obj);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * const fdc_container_path[] = {
|
||||||
|
"/unattached", "/peripheral", "/peripheral-anon"
|
||||||
|
};
|
||||||
|
|
||||||
static void pc_cmos_init_late(void *opaque)
|
static void pc_cmos_init_late(void *opaque)
|
||||||
{
|
{
|
||||||
pc_cmos_init_late_arg *arg = opaque;
|
pc_cmos_init_late_arg *arg = opaque;
|
||||||
@@ -307,6 +377,8 @@ static void pc_cmos_init_late(void *opaque)
|
|||||||
int8_t heads, sectors;
|
int8_t heads, sectors;
|
||||||
int val;
|
int val;
|
||||||
int i, trans;
|
int i, trans;
|
||||||
|
Object *container;
|
||||||
|
CheckFdcState state = { 0 };
|
||||||
|
|
||||||
val = 0;
|
val = 0;
|
||||||
if (ide_get_geometry(arg->idebus[0], 0,
|
if (ide_get_geometry(arg->idebus[0], 0,
|
||||||
@@ -336,16 +408,32 @@ static void pc_cmos_init_late(void *opaque)
|
|||||||
}
|
}
|
||||||
rtc_set_memory(s, 0x39, val);
|
rtc_set_memory(s, 0x39, val);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Locate the FDC at IO address 0x3f0, and configure the CMOS registers
|
||||||
|
* accordingly.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ARRAY_SIZE(fdc_container_path); i++) {
|
||||||
|
container = container_get(qdev_get_machine(), fdc_container_path[i]);
|
||||||
|
object_child_foreach(container, check_fdc, &state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.multiple) {
|
||||||
|
error_report("warning: multiple floppy disk controllers with "
|
||||||
|
"iobase=0x3f0 have been found;\n"
|
||||||
|
"the one being picked for CMOS setup might not reflect "
|
||||||
|
"your intent");
|
||||||
|
}
|
||||||
|
pc_cmos_init_floppy(s, state.floppy);
|
||||||
|
|
||||||
qemu_unregister_reset(pc_cmos_init_late, opaque);
|
qemu_unregister_reset(pc_cmos_init_late, opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||||
const char *boot_device, MachineState *machine,
|
const char *boot_device, MachineState *machine,
|
||||||
ISADevice *floppy, BusState *idebus0, BusState *idebus1,
|
BusState *idebus0, BusState *idebus1,
|
||||||
ISADevice *s)
|
ISADevice *s)
|
||||||
{
|
{
|
||||||
int val, nb, i;
|
int val;
|
||||||
FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
|
|
||||||
static pc_cmos_init_late_arg arg;
|
static pc_cmos_init_late_arg arg;
|
||||||
PCMachineState *pc_machine = PC_MACHINE(machine);
|
PCMachineState *pc_machine = PC_MACHINE(machine);
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
@@ -402,39 +490,12 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* floppy type */
|
|
||||||
if (floppy) {
|
|
||||||
for (i = 0; i < 2; i++) {
|
|
||||||
fd_type[i] = isa_fdc_get_drive_type(floppy, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
|
|
||||||
cmos_get_fd_drive_type(fd_type[1]);
|
|
||||||
rtc_set_memory(s, 0x10, val);
|
|
||||||
|
|
||||||
val = 0;
|
val = 0;
|
||||||
nb = 0;
|
|
||||||
if (fd_type[0] < FDRIVE_DRV_NONE) {
|
|
||||||
nb++;
|
|
||||||
}
|
|
||||||
if (fd_type[1] < FDRIVE_DRV_NONE) {
|
|
||||||
nb++;
|
|
||||||
}
|
|
||||||
switch (nb) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
val |= 0x01; /* 1 drive, ready for boot */
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
val |= 0x41; /* 2 drives, ready for boot */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
val |= 0x02; /* FPU is there */
|
val |= 0x02; /* FPU is there */
|
||||||
val |= 0x04; /* PS/2 mouse installed */
|
val |= 0x04; /* PS/2 mouse installed */
|
||||||
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
|
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
|
||||||
|
|
||||||
/* hard drives */
|
/* hard drives and FDC */
|
||||||
arg.rtc_state = s;
|
arg.rtc_state = s;
|
||||||
arg.idebus[0] = idebus0;
|
arg.idebus[0] = idebus0;
|
||||||
arg.idebus[1] = idebus1;
|
arg.idebus[1] = idebus1;
|
||||||
@@ -1297,7 +1358,7 @@ FWCfgState *pc_memory_init(MachineState *machine,
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pcms->hotplug_memory_base =
|
pcms->hotplug_memory.base =
|
||||||
ROUND_UP(0x100000000ULL + above_4g_mem_size, 1ULL << 30);
|
ROUND_UP(0x100000000ULL + above_4g_mem_size, 1ULL << 30);
|
||||||
|
|
||||||
if (pcms->enforce_aligned_dimm) {
|
if (pcms->enforce_aligned_dimm) {
|
||||||
@@ -1305,17 +1366,17 @@ FWCfgState *pc_memory_init(MachineState *machine,
|
|||||||
hotplug_mem_size += (1ULL << 30) * machine->ram_slots;
|
hotplug_mem_size += (1ULL << 30) * machine->ram_slots;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pcms->hotplug_memory_base + hotplug_mem_size) <
|
if ((pcms->hotplug_memory.base + hotplug_mem_size) <
|
||||||
hotplug_mem_size) {
|
hotplug_mem_size) {
|
||||||
error_report("unsupported amount of maximum memory: " RAM_ADDR_FMT,
|
error_report("unsupported amount of maximum memory: " RAM_ADDR_FMT,
|
||||||
machine->maxram_size);
|
machine->maxram_size);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_init(&pcms->hotplug_memory, OBJECT(pcms),
|
memory_region_init(&pcms->hotplug_memory.mr, OBJECT(pcms),
|
||||||
"hotplug-memory", hotplug_mem_size);
|
"hotplug-memory", hotplug_mem_size);
|
||||||
memory_region_add_subregion(system_memory, pcms->hotplug_memory_base,
|
memory_region_add_subregion(system_memory, pcms->hotplug_memory.base,
|
||||||
&pcms->hotplug_memory);
|
&pcms->hotplug_memory.mr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize PC system firmware */
|
/* Initialize PC system firmware */
|
||||||
@@ -1333,9 +1394,9 @@ FWCfgState *pc_memory_init(MachineState *machine,
|
|||||||
fw_cfg = bochs_bios_init();
|
fw_cfg = bochs_bios_init();
|
||||||
rom_set_fw(fw_cfg);
|
rom_set_fw(fw_cfg);
|
||||||
|
|
||||||
if (guest_info->has_reserved_memory && pcms->hotplug_memory_base) {
|
if (guest_info->has_reserved_memory && pcms->hotplug_memory.base) {
|
||||||
uint64_t *val = g_malloc(sizeof(*val));
|
uint64_t *val = g_malloc(sizeof(*val));
|
||||||
*val = cpu_to_le64(ROUND_UP(pcms->hotplug_memory_base, 0x1ULL << 30));
|
*val = cpu_to_le64(ROUND_UP(pcms->hotplug_memory.base, 0x1ULL << 30));
|
||||||
fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
|
fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1402,7 +1463,6 @@ static const MemoryRegionOps ioportF0_io_ops = {
|
|||||||
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||||
ISADevice **rtc_state,
|
ISADevice **rtc_state,
|
||||||
bool create_fdctrl,
|
bool create_fdctrl,
|
||||||
ISADevice **floppy,
|
|
||||||
bool no_vmport,
|
bool no_vmport,
|
||||||
uint32 hpet_irqs)
|
uint32 hpet_irqs)
|
||||||
{
|
{
|
||||||
@@ -1498,7 +1558,9 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
|||||||
fd[i] = drive_get(IF_FLOPPY, 0, i);
|
fd[i] = drive_get(IF_FLOPPY, 0, i);
|
||||||
create_fdctrl |= !!fd[i];
|
create_fdctrl |= !!fd[i];
|
||||||
}
|
}
|
||||||
*floppy = create_fdctrl ? fdctrl_init_isa(isa_bus, fd) : NULL;
|
if (create_fdctrl) {
|
||||||
|
fdctrl_init_isa(isa_bus, fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
|
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
|
||||||
@@ -1554,88 +1616,31 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
|
|||||||
static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
||||||
DeviceState *dev, Error **errp)
|
DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
int slot;
|
|
||||||
HotplugHandlerClass *hhc;
|
HotplugHandlerClass *hhc;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||||
MachineState *machine = MACHINE(hotplug_dev);
|
|
||||||
PCDIMMDevice *dimm = PC_DIMM(dev);
|
PCDIMMDevice *dimm = PC_DIMM(dev);
|
||||||
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
|
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
|
||||||
MemoryRegion *mr = ddc->get_memory_region(dimm);
|
MemoryRegion *mr = ddc->get_memory_region(dimm);
|
||||||
uint64_t existing_dimms_capacity = 0;
|
|
||||||
uint64_t align = TARGET_PAGE_SIZE;
|
uint64_t align = TARGET_PAGE_SIZE;
|
||||||
uint64_t addr;
|
|
||||||
|
|
||||||
addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memory_region_get_alignment(mr) && pcms->enforce_aligned_dimm) {
|
if (memory_region_get_alignment(mr) && pcms->enforce_aligned_dimm) {
|
||||||
align = memory_region_get_alignment(mr);
|
align = memory_region_get_alignment(mr);
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = pc_dimm_get_free_addr(pcms->hotplug_memory_base,
|
|
||||||
memory_region_size(&pcms->hotplug_memory),
|
|
||||||
!addr ? NULL : &addr, align,
|
|
||||||
memory_region_size(mr), &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
existing_dimms_capacity = pc_existing_dimms_capacity(&local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existing_dimms_capacity + memory_region_size(mr) >
|
|
||||||
machine->maxram_size - machine->ram_size) {
|
|
||||||
error_setg(&local_err, "not enough space, currently 0x%" PRIx64
|
|
||||||
" in use of total hot pluggable 0x" RAM_ADDR_FMT,
|
|
||||||
existing_dimms_capacity,
|
|
||||||
machine->maxram_size - machine->ram_size);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
object_property_set_int(OBJECT(dev), addr, PC_DIMM_ADDR_PROP, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
trace_mhp_pc_dimm_assigned_address(addr);
|
|
||||||
|
|
||||||
slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
slot = pc_dimm_get_free_slot(slot == PC_DIMM_UNASSIGNED_SLOT ? NULL : &slot,
|
|
||||||
machine->ram_slots, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
object_property_set_int(OBJECT(dev), slot, PC_DIMM_SLOT_PROP, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
trace_mhp_pc_dimm_assigned_slot(slot);
|
|
||||||
|
|
||||||
if (!pcms->acpi_dev) {
|
if (!pcms->acpi_dev) {
|
||||||
error_setg(&local_err,
|
error_setg(&local_err,
|
||||||
"memory hotplug is not enabled: missing acpi device");
|
"memory hotplug is not enabled: missing acpi device");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kvm_enabled() && !kvm_has_free_slot(machine)) {
|
pc_dimm_memory_plug(dev, &pcms->hotplug_memory, mr, align, &local_err);
|
||||||
error_setg(&local_err, "hypervisor has no free memory slots left");
|
if (local_err) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_add_subregion(&pcms->hotplug_memory,
|
|
||||||
addr - pcms->hotplug_memory_base, mr);
|
|
||||||
vmstate_register_ram(mr, dev);
|
|
||||||
|
|
||||||
hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
|
hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
|
||||||
hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &error_abort);
|
||||||
out:
|
out:
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
@@ -1677,9 +1682,7 @@ static void pc_dimm_unplug(HotplugHandler *hotplug_dev,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_del_subregion(&pcms->hotplug_memory, mr);
|
pc_dimm_memory_unplug(dev, &pcms->hotplug_memory, mr);
|
||||||
vmstate_unregister_ram(mr, dev);
|
|
||||||
|
|
||||||
object_unparent(OBJECT(dev));
|
object_unparent(OBJECT(dev));
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -1766,7 +1769,7 @@ pc_machine_get_hotplug_memory_region_size(Object *obj, Visitor *v, void *opaque,
|
|||||||
const char *name, Error **errp)
|
const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
PCMachineState *pcms = PC_MACHINE(obj);
|
PCMachineState *pcms = PC_MACHINE(obj);
|
||||||
int64_t value = memory_region_size(&pcms->hotplug_memory);
|
int64_t value = memory_region_size(&pcms->hotplug_memory.mr);
|
||||||
|
|
||||||
visit_type_int(v, &value, name, errp);
|
visit_type_int(v, &value, name, errp);
|
||||||
}
|
}
|
||||||
@@ -1828,6 +1831,48 @@ static void pc_machine_set_vmport(Object *obj, Visitor *v, void *opaque,
|
|||||||
visit_type_OnOffAuto(v, &pcms->vmport, name, errp);
|
visit_type_OnOffAuto(v, &pcms->vmport, name, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pc_machine_is_smm_enabled(PCMachineState *pcms)
|
||||||
|
{
|
||||||
|
bool smm_available = false;
|
||||||
|
|
||||||
|
if (pcms->smm == ON_OFF_AUTO_OFF) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcg_enabled() || qtest_enabled()) {
|
||||||
|
smm_available = true;
|
||||||
|
} else if (kvm_enabled()) {
|
||||||
|
smm_available = kvm_has_smm();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smm_available) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcms->smm == ON_OFF_AUTO_ON) {
|
||||||
|
error_report("System Management Mode not supported by this hypervisor.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pc_machine_get_smm(Object *obj, Visitor *v, void *opaque,
|
||||||
|
const char *name, Error **errp)
|
||||||
|
{
|
||||||
|
PCMachineState *pcms = PC_MACHINE(obj);
|
||||||
|
OnOffAuto smm = pcms->smm;
|
||||||
|
|
||||||
|
visit_type_OnOffAuto(v, &smm, name, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pc_machine_set_smm(Object *obj, Visitor *v, void *opaque,
|
||||||
|
const char *name, Error **errp)
|
||||||
|
{
|
||||||
|
PCMachineState *pcms = PC_MACHINE(obj);
|
||||||
|
|
||||||
|
visit_type_OnOffAuto(v, &pcms->smm, name, errp);
|
||||||
|
}
|
||||||
|
|
||||||
static bool pc_machine_get_aligned_dimm(Object *obj, Error **errp)
|
static bool pc_machine_get_aligned_dimm(Object *obj, Error **errp)
|
||||||
{
|
{
|
||||||
PCMachineState *pcms = PC_MACHINE(obj);
|
PCMachineState *pcms = PC_MACHINE(obj);
|
||||||
@@ -1852,6 +1897,15 @@ static void pc_machine_initfn(Object *obj)
|
|||||||
"Maximum ram below the 4G boundary (32bit boundary)",
|
"Maximum ram below the 4G boundary (32bit boundary)",
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
pcms->smm = ON_OFF_AUTO_AUTO;
|
||||||
|
object_property_add(obj, PC_MACHINE_SMM, "OnOffAuto",
|
||||||
|
pc_machine_get_smm,
|
||||||
|
pc_machine_set_smm,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
object_property_set_description(obj, PC_MACHINE_SMM,
|
||||||
|
"Enable SMM (pc & q35)",
|
||||||
|
NULL);
|
||||||
|
|
||||||
pcms->vmport = ON_OFF_AUTO_AUTO;
|
pcms->vmport = ON_OFF_AUTO_AUTO;
|
||||||
object_property_add(obj, PC_MACHINE_VMPORT, "OnOffAuto",
|
object_property_add(obj, PC_MACHINE_VMPORT, "OnOffAuto",
|
||||||
pc_machine_get_vmport,
|
pc_machine_get_vmport,
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ static void pc_init1(MachineState *machine)
|
|||||||
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
||||||
BusState *idebus[MAX_IDE_BUS];
|
BusState *idebus[MAX_IDE_BUS];
|
||||||
ISADevice *rtc_state;
|
ISADevice *rtc_state;
|
||||||
ISADevice *floppy;
|
|
||||||
MemoryRegion *ram_memory;
|
MemoryRegion *ram_memory;
|
||||||
MemoryRegion *pci_memory;
|
MemoryRegion *pci_memory;
|
||||||
MemoryRegion *rom_memory;
|
MemoryRegion *rom_memory;
|
||||||
@@ -241,7 +240,7 @@ static void pc_init1(MachineState *machine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* init basic PC hardware */
|
/* init basic PC hardware */
|
||||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, true, &floppy,
|
pc_basic_device_init(isa_bus, gsi, &rtc_state, true,
|
||||||
(pc_machine->vmport != ON_OFF_AUTO_ON), 0x4);
|
(pc_machine->vmport != ON_OFF_AUTO_ON), 0x4);
|
||||||
|
|
||||||
pc_nic_init(isa_bus, pci_bus);
|
pc_nic_init(isa_bus, pci_bus);
|
||||||
@@ -273,7 +272,7 @@ static void pc_init1(MachineState *machine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
|
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
|
||||||
machine, floppy, idebus[0], idebus[1], rtc_state);
|
machine, idebus[0], idebus[1], rtc_state);
|
||||||
|
|
||||||
if (pci_enabled && usb_enabled()) {
|
if (pci_enabled && usb_enabled()) {
|
||||||
pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
|
pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
|
||||||
@@ -287,7 +286,8 @@ static void pc_init1(MachineState *machine)
|
|||||||
/* TODO: Populate SPD eeprom data. */
|
/* TODO: Populate SPD eeprom data. */
|
||||||
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
|
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
|
||||||
gsi[9], smi_irq,
|
gsi[9], smi_irq,
|
||||||
kvm_enabled(), &piix4_pm);
|
pc_machine_is_smm_enabled(pc_machine),
|
||||||
|
&piix4_pm);
|
||||||
smbus_eeprom_init(smbus, 8, NULL, 0);
|
smbus_eeprom_init(smbus, 8, NULL, 0);
|
||||||
|
|
||||||
object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
|
object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
|
||||||
@@ -306,7 +306,13 @@ static void pc_init1(MachineState *machine)
|
|||||||
|
|
||||||
static void pc_compat_2_3(MachineState *machine)
|
static void pc_compat_2_3(MachineState *machine)
|
||||||
{
|
{
|
||||||
|
PCMachineState *pcms = PC_MACHINE(machine);
|
||||||
savevm_skip_section_footers();
|
savevm_skip_section_footers();
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
pcms->smm = ON_OFF_AUTO_OFF;
|
||||||
|
}
|
||||||
|
global_state_set_optional();
|
||||||
|
savevm_skip_configuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_compat_2_2(MachineState *machine)
|
static void pc_compat_2_2(MachineState *machine)
|
||||||
@@ -486,7 +492,7 @@ DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
|
|||||||
|
|
||||||
static void pc_i440fx_2_3_machine_options(MachineClass *m)
|
static void pc_i440fx_2_3_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
pc_i440fx_machine_options(m);
|
pc_i440fx_2_4_machine_options(m);
|
||||||
m->alias = NULL;
|
m->alias = NULL;
|
||||||
m->is_default = 0;
|
m->is_default = 0;
|
||||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
PCIDevice *lpc;
|
PCIDevice *lpc;
|
||||||
BusState *idebus[MAX_SATA_PORTS];
|
BusState *idebus[MAX_SATA_PORTS];
|
||||||
ISADevice *rtc_state;
|
ISADevice *rtc_state;
|
||||||
ISADevice *floppy;
|
|
||||||
MemoryRegion *pci_memory;
|
MemoryRegion *pci_memory;
|
||||||
MemoryRegion *rom_memory;
|
MemoryRegion *rom_memory;
|
||||||
MemoryRegion *ram_memory;
|
MemoryRegion *ram_memory;
|
||||||
@@ -249,11 +248,11 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* init basic PC hardware */
|
/* init basic PC hardware */
|
||||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, !mc->no_floppy, &floppy,
|
pc_basic_device_init(isa_bus, gsi, &rtc_state, !mc->no_floppy,
|
||||||
(pc_machine->vmport != ON_OFF_AUTO_ON), 0xff0104);
|
(pc_machine->vmport != ON_OFF_AUTO_ON), 0xff0104);
|
||||||
|
|
||||||
/* connect pm stuff to lpc */
|
/* connect pm stuff to lpc */
|
||||||
ich9_lpc_pm_init(lpc);
|
ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pc_machine), !mc->no_tco);
|
||||||
|
|
||||||
/* ahci and SATA device, for q35 1 ahci controller is built-in */
|
/* ahci and SATA device, for q35 1 ahci controller is built-in */
|
||||||
ahci = pci_create_simple_multifunction(host_bus,
|
ahci = pci_create_simple_multifunction(host_bus,
|
||||||
@@ -278,7 +277,7 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
8, NULL, 0);
|
8, NULL, 0);
|
||||||
|
|
||||||
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
|
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
|
||||||
machine, floppy, idebus[0], idebus[1], rtc_state);
|
machine, idebus[0], idebus[1], rtc_state);
|
||||||
|
|
||||||
/* the rest devices to which pci devfn is automatically assigned */
|
/* the rest devices to which pci devfn is automatically assigned */
|
||||||
pc_vga_init(isa_bus, host_bus);
|
pc_vga_init(isa_bus, host_bus);
|
||||||
@@ -290,7 +289,13 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
|
|
||||||
static void pc_compat_2_3(MachineState *machine)
|
static void pc_compat_2_3(MachineState *machine)
|
||||||
{
|
{
|
||||||
|
PCMachineState *pcms = PC_MACHINE(machine);
|
||||||
savevm_skip_section_footers();
|
savevm_skip_section_footers();
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
pcms->smm = ON_OFF_AUTO_OFF;
|
||||||
|
}
|
||||||
|
global_state_set_optional();
|
||||||
|
savevm_skip_configuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_compat_2_2(MachineState *machine)
|
static void pc_compat_2_2(MachineState *machine)
|
||||||
@@ -393,6 +398,7 @@ static void pc_q35_2_4_machine_options(MachineClass *m)
|
|||||||
m->default_machine_opts = "firmware=bios-256k.bin";
|
m->default_machine_opts = "firmware=bios-256k.bin";
|
||||||
m->default_display = "std";
|
m->default_display = "std";
|
||||||
m->no_floppy = 1;
|
m->no_floppy = 1;
|
||||||
|
m->no_tco = 0;
|
||||||
m->alias = "q35";
|
m->alias = "q35";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,6 +410,7 @@ static void pc_q35_2_3_machine_options(MachineClass *m)
|
|||||||
{
|
{
|
||||||
pc_q35_2_4_machine_options(m);
|
pc_q35_2_4_machine_options(m);
|
||||||
m->no_floppy = 0;
|
m->no_floppy = 0;
|
||||||
|
m->no_tco = 1;
|
||||||
m->alias = NULL;
|
m->alias = NULL;
|
||||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
|
||||||
}
|
}
|
||||||
|
|||||||
439
hw/ide/ahci.c
439
hw/ide/ahci.c
@@ -45,11 +45,11 @@ do { \
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static void check_cmd(AHCIState *s, int port);
|
static void check_cmd(AHCIState *s, int port);
|
||||||
static int handle_cmd(AHCIState *s,int port,int slot);
|
static int handle_cmd(AHCIState *s, int port, uint8_t slot);
|
||||||
static void ahci_reset_port(AHCIState *s, int port);
|
static void ahci_reset_port(AHCIState *s, int port);
|
||||||
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
|
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
|
||||||
static void ahci_init_d2h(AHCIDevice *ad);
|
static void ahci_init_d2h(AHCIDevice *ad);
|
||||||
static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write);
|
static int ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit);
|
||||||
static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes);
|
static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes);
|
||||||
static bool ahci_map_clb_address(AHCIDevice *ad);
|
static bool ahci_map_clb_address(AHCIDevice *ad);
|
||||||
static bool ahci_map_fis_address(AHCIDevice *ad);
|
static bool ahci_map_fis_address(AHCIDevice *ad);
|
||||||
@@ -106,8 +106,6 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
|
|||||||
val = pr->scr_err;
|
val = pr->scr_err;
|
||||||
break;
|
break;
|
||||||
case PORT_SCR_ACT:
|
case PORT_SCR_ACT:
|
||||||
pr->scr_act &= ~s->dev[port].finished;
|
|
||||||
s->dev[port].finished = 0;
|
|
||||||
val = pr->scr_act;
|
val = pr->scr_act;
|
||||||
break;
|
break;
|
||||||
case PORT_CMD_ISSUE:
|
case PORT_CMD_ISSUE:
|
||||||
@@ -331,8 +329,7 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t ahci_mem_read(void *opaque, hwaddr addr,
|
static uint64_t ahci_mem_read_32(void *opaque, hwaddr addr)
|
||||||
unsigned size)
|
|
||||||
{
|
{
|
||||||
AHCIState *s = opaque;
|
AHCIState *s = opaque;
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
@@ -368,6 +365,30 @@ static uint64_t ahci_mem_read(void *opaque, hwaddr addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AHCI 1.3 section 3 ("HBA Memory Registers")
|
||||||
|
* Support unaligned 8/16/32 bit reads, and 64 bit aligned reads.
|
||||||
|
* Caller is responsible for masking unwanted higher order bytes.
|
||||||
|
*/
|
||||||
|
static uint64_t ahci_mem_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
|
{
|
||||||
|
hwaddr aligned = addr & ~0x3;
|
||||||
|
int ofst = addr - aligned;
|
||||||
|
uint64_t lo = ahci_mem_read_32(opaque, aligned);
|
||||||
|
uint64_t hi;
|
||||||
|
|
||||||
|
/* if < 8 byte read does not cross 4 byte boundary */
|
||||||
|
if (ofst + size <= 4) {
|
||||||
|
return lo >> (ofst * 8);
|
||||||
|
}
|
||||||
|
g_assert_cmpint(size, >, 1);
|
||||||
|
|
||||||
|
/* If the 64bit read is unaligned, we will produce undefined
|
||||||
|
* results. AHCI does not support unaligned 64bit reads. */
|
||||||
|
hi = ahci_mem_read_32(opaque, aligned + 4);
|
||||||
|
return (hi << 32 | lo) >> (ofst * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void ahci_mem_write(void *opaque, hwaddr addr,
|
static void ahci_mem_write(void *opaque, hwaddr addr,
|
||||||
uint64_t val, unsigned size)
|
uint64_t val, unsigned size)
|
||||||
@@ -483,7 +504,7 @@ static void ahci_reg_init(AHCIState *s)
|
|||||||
static void check_cmd(AHCIState *s, int port)
|
static void check_cmd(AHCIState *s, int port)
|
||||||
{
|
{
|
||||||
AHCIPortRegs *pr = &s->dev[port].port_regs;
|
AHCIPortRegs *pr = &s->dev[port].port_regs;
|
||||||
int slot;
|
uint8_t slot;
|
||||||
|
|
||||||
if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
|
if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
|
||||||
for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
|
for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
|
||||||
@@ -558,6 +579,7 @@ static void ahci_reset_port(AHCIState *s, int port)
|
|||||||
/* reset ncq queue */
|
/* reset ncq queue */
|
||||||
for (i = 0; i < AHCI_MAX_CMDS; i++) {
|
for (i = 0; i < AHCI_MAX_CMDS; i++) {
|
||||||
NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i];
|
NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i];
|
||||||
|
ncq_tfs->halt = false;
|
||||||
if (!ncq_tfs->used) {
|
if (!ncq_tfs->used) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -642,14 +664,14 @@ static void ahci_unmap_clb_address(AHCIDevice *ad)
|
|||||||
ad->lst = NULL;
|
ad->lst = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
|
static void ahci_write_fis_sdb(AHCIState *s, NCQTransferState *ncq_tfs)
|
||||||
{
|
{
|
||||||
AHCIDevice *ad = &s->dev[port];
|
AHCIDevice *ad = ncq_tfs->drive;
|
||||||
AHCIPortRegs *pr = &ad->port_regs;
|
AHCIPortRegs *pr = &ad->port_regs;
|
||||||
IDEState *ide_state;
|
IDEState *ide_state;
|
||||||
SDBFIS *sdb_fis;
|
SDBFIS *sdb_fis;
|
||||||
|
|
||||||
if (!s->dev[port].res_fis ||
|
if (!ad->res_fis ||
|
||||||
!(pr->cmd & PORT_CMD_FIS_RX)) {
|
!(pr->cmd & PORT_CMD_FIS_RX)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -659,53 +681,35 @@ static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
|
|||||||
|
|
||||||
sdb_fis->type = SATA_FIS_TYPE_SDB;
|
sdb_fis->type = SATA_FIS_TYPE_SDB;
|
||||||
/* Interrupt pending & Notification bit */
|
/* Interrupt pending & Notification bit */
|
||||||
sdb_fis->flags = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
|
sdb_fis->flags = 0x40; /* Interrupt bit, always 1 for NCQ */
|
||||||
sdb_fis->status = ide_state->status & 0x77;
|
sdb_fis->status = ide_state->status & 0x77;
|
||||||
sdb_fis->error = ide_state->error;
|
sdb_fis->error = ide_state->error;
|
||||||
/* update SAct field in SDB_FIS */
|
/* update SAct field in SDB_FIS */
|
||||||
s->dev[port].finished |= finished;
|
|
||||||
sdb_fis->payload = cpu_to_le32(ad->finished);
|
sdb_fis->payload = cpu_to_le32(ad->finished);
|
||||||
|
|
||||||
/* Update shadow registers (except BSY 0x80 and DRQ 0x08) */
|
/* Update shadow registers (except BSY 0x80 and DRQ 0x08) */
|
||||||
pr->tfdata = (ad->port.ifs[0].error << 8) |
|
pr->tfdata = (ad->port.ifs[0].error << 8) |
|
||||||
(ad->port.ifs[0].status & 0x77) |
|
(ad->port.ifs[0].status & 0x77) |
|
||||||
(pr->tfdata & 0x88);
|
(pr->tfdata & 0x88);
|
||||||
|
pr->scr_act &= ~ad->finished;
|
||||||
|
ad->finished = 0;
|
||||||
|
|
||||||
ahci_trigger_irq(s, ad, PORT_IRQ_SDB_FIS);
|
/* Trigger IRQ if interrupt bit is set (which currently, it always is) */
|
||||||
|
if (sdb_fis->flags & 0x40) {
|
||||||
|
ahci_trigger_irq(s, ad, PORT_IRQ_SDB_FIS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
|
static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
|
||||||
{
|
{
|
||||||
AHCIPortRegs *pr = &ad->port_regs;
|
AHCIPortRegs *pr = &ad->port_regs;
|
||||||
uint8_t *pio_fis, *cmd_fis;
|
uint8_t *pio_fis;
|
||||||
uint64_t tbl_addr;
|
|
||||||
dma_addr_t cmd_len = 0x80;
|
|
||||||
IDEState *s = &ad->port.ifs[0];
|
IDEState *s = &ad->port.ifs[0];
|
||||||
|
|
||||||
if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
|
if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* map cmd_fis */
|
|
||||||
tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr);
|
|
||||||
cmd_fis = dma_memory_map(ad->hba->as, tbl_addr, &cmd_len,
|
|
||||||
DMA_DIRECTION_TO_DEVICE);
|
|
||||||
|
|
||||||
if (cmd_fis == NULL) {
|
|
||||||
DPRINTF(ad->port_no, "dma_memory_map failed in ahci_write_fis_pio");
|
|
||||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_HBUS_ERR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd_len != 0x80) {
|
|
||||||
DPRINTF(ad->port_no,
|
|
||||||
"dma_memory_map mapped too few bytes in ahci_write_fis_pio");
|
|
||||||
dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len,
|
|
||||||
DMA_DIRECTION_TO_DEVICE, cmd_len);
|
|
||||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_HBUS_ERR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pio_fis = &ad->res_fis[RES_FIS_PSFIS];
|
pio_fis = &ad->res_fis[RES_FIS_PSFIS];
|
||||||
|
|
||||||
pio_fis[0] = SATA_FIS_TYPE_PIO_SETUP;
|
pio_fis[0] = SATA_FIS_TYPE_PIO_SETUP;
|
||||||
@@ -721,8 +725,8 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
|
|||||||
pio_fis[9] = s->hob_lcyl;
|
pio_fis[9] = s->hob_lcyl;
|
||||||
pio_fis[10] = s->hob_hcyl;
|
pio_fis[10] = s->hob_hcyl;
|
||||||
pio_fis[11] = 0;
|
pio_fis[11] = 0;
|
||||||
pio_fis[12] = cmd_fis[12];
|
pio_fis[12] = s->nsector & 0xFF;
|
||||||
pio_fis[13] = cmd_fis[13];
|
pio_fis[13] = (s->nsector >> 8) & 0xFF;
|
||||||
pio_fis[14] = 0;
|
pio_fis[14] = 0;
|
||||||
pio_fis[15] = s->status;
|
pio_fis[15] = s->status;
|
||||||
pio_fis[16] = len & 255;
|
pio_fis[16] = len & 255;
|
||||||
@@ -739,9 +743,6 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS);
|
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS);
|
||||||
|
|
||||||
dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len,
|
|
||||||
DMA_DIRECTION_TO_DEVICE, cmd_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
||||||
@@ -749,22 +750,12 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
|||||||
AHCIPortRegs *pr = &ad->port_regs;
|
AHCIPortRegs *pr = &ad->port_regs;
|
||||||
uint8_t *d2h_fis;
|
uint8_t *d2h_fis;
|
||||||
int i;
|
int i;
|
||||||
dma_addr_t cmd_len = 0x80;
|
|
||||||
int cmd_mapped = 0;
|
|
||||||
IDEState *s = &ad->port.ifs[0];
|
IDEState *s = &ad->port.ifs[0];
|
||||||
|
|
||||||
if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
|
if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cmd_fis) {
|
|
||||||
/* map cmd_fis */
|
|
||||||
uint64_t tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr);
|
|
||||||
cmd_fis = dma_memory_map(ad->hba->as, tbl_addr, &cmd_len,
|
|
||||||
DMA_DIRECTION_TO_DEVICE);
|
|
||||||
cmd_mapped = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
d2h_fis = &ad->res_fis[RES_FIS_RFIS];
|
d2h_fis = &ad->res_fis[RES_FIS_RFIS];
|
||||||
|
|
||||||
d2h_fis[0] = SATA_FIS_TYPE_REGISTER_D2H;
|
d2h_fis[0] = SATA_FIS_TYPE_REGISTER_D2H;
|
||||||
@@ -780,8 +771,8 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
|||||||
d2h_fis[9] = s->hob_lcyl;
|
d2h_fis[9] = s->hob_lcyl;
|
||||||
d2h_fis[10] = s->hob_hcyl;
|
d2h_fis[10] = s->hob_hcyl;
|
||||||
d2h_fis[11] = 0;
|
d2h_fis[11] = 0;
|
||||||
d2h_fis[12] = cmd_fis[12];
|
d2h_fis[12] = s->nsector & 0xFF;
|
||||||
d2h_fis[13] = cmd_fis[13];
|
d2h_fis[13] = (s->nsector >> 8) & 0xFF;
|
||||||
for (i = 14; i < 20; i++) {
|
for (i = 14; i < 20; i++) {
|
||||||
d2h_fis[i] = 0;
|
d2h_fis[i] = 0;
|
||||||
}
|
}
|
||||||
@@ -795,26 +786,22 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
|
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
|
||||||
|
|
||||||
if (cmd_mapped) {
|
|
||||||
dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len,
|
|
||||||
DMA_DIRECTION_TO_DEVICE, cmd_len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prdt_tbl_entry_size(const AHCI_SG *tbl)
|
static int prdt_tbl_entry_size(const AHCI_SG *tbl)
|
||||||
{
|
{
|
||||||
|
/* flags_size is zero-based */
|
||||||
return (le32_to_cpu(tbl->flags_size) & AHCI_PRDT_SIZE_MASK) + 1;
|
return (le32_to_cpu(tbl->flags_size) & AHCI_PRDT_SIZE_MASK) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
|
static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
|
||||||
int32_t offset)
|
AHCICmdHdr *cmd, int64_t limit, int32_t offset)
|
||||||
{
|
{
|
||||||
AHCICmdHdr *cmd = ad->cur_cmd;
|
uint16_t opts = le16_to_cpu(cmd->opts);
|
||||||
uint32_t opts = le32_to_cpu(cmd->opts);
|
uint16_t prdtl = le16_to_cpu(cmd->prdtl);
|
||||||
uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;
|
uint64_t cfis_addr = le64_to_cpu(cmd->tbl_addr);
|
||||||
int sglist_alloc_hint = opts >> AHCI_CMD_HDR_PRDT_LEN;
|
uint64_t prdt_addr = cfis_addr + 0x80;
|
||||||
dma_addr_t prdt_len = (sglist_alloc_hint * sizeof(AHCI_SG));
|
dma_addr_t prdt_len = (prdtl * sizeof(AHCI_SG));
|
||||||
dma_addr_t real_prdt_len = prdt_len;
|
dma_addr_t real_prdt_len = prdt_len;
|
||||||
uint8_t *prdt;
|
uint8_t *prdt;
|
||||||
int i;
|
int i;
|
||||||
@@ -834,7 +821,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
|
|||||||
* request for sector sizes up to 32K.
|
* request for sector sizes up to 32K.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!sglist_alloc_hint) {
|
if (!prdtl) {
|
||||||
DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
|
DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -853,13 +840,12 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get entries in the PRDT, init a qemu sglist accordingly */
|
/* Get entries in the PRDT, init a qemu sglist accordingly */
|
||||||
if (sglist_alloc_hint > 0) {
|
if (prdtl > 0) {
|
||||||
AHCI_SG *tbl = (AHCI_SG *)prdt;
|
AHCI_SG *tbl = (AHCI_SG *)prdt;
|
||||||
sum = 0;
|
sum = 0;
|
||||||
for (i = 0; i < sglist_alloc_hint; i++) {
|
for (i = 0; i < prdtl; i++) {
|
||||||
/* flags_size is zero-based */
|
|
||||||
tbl_entry_size = prdt_tbl_entry_size(&tbl[i]);
|
tbl_entry_size = prdt_tbl_entry_size(&tbl[i]);
|
||||||
if (offset <= (sum + tbl_entry_size)) {
|
if (offset < (sum + tbl_entry_size)) {
|
||||||
off_idx = i;
|
off_idx = i;
|
||||||
off_pos = offset - sum;
|
off_pos = offset - sum;
|
||||||
break;
|
break;
|
||||||
@@ -874,15 +860,16 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_sglist_init(sglist, qbus->parent, (sglist_alloc_hint - off_idx),
|
qemu_sglist_init(sglist, qbus->parent, (prdtl - off_idx),
|
||||||
ad->hba->as);
|
ad->hba->as);
|
||||||
qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr) + off_pos,
|
qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr) + off_pos,
|
||||||
prdt_tbl_entry_size(&tbl[off_idx]) - off_pos);
|
MIN(prdt_tbl_entry_size(&tbl[off_idx]) - off_pos,
|
||||||
|
limit));
|
||||||
|
|
||||||
for (i = off_idx + 1; i < sglist_alloc_hint; i++) {
|
for (i = off_idx + 1; i < prdtl && sglist->size < limit; i++) {
|
||||||
/* flags_size is zero-based */
|
|
||||||
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
|
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
|
||||||
prdt_tbl_entry_size(&tbl[i]));
|
MIN(prdt_tbl_entry_size(&tbl[i]),
|
||||||
|
limit - sglist->size));
|
||||||
if (sglist->size > INT32_MAX) {
|
if (sglist->size > INT32_MAX) {
|
||||||
error_report("AHCI Physical Region Descriptor Table describes "
|
error_report("AHCI Physical Region Descriptor Table describes "
|
||||||
"more than 2 GiB.\n");
|
"more than 2 GiB.\n");
|
||||||
@@ -899,28 +886,25 @@ out:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ncq_cb(void *opaque, int ret)
|
static void ncq_err(NCQTransferState *ncq_tfs)
|
||||||
{
|
{
|
||||||
NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
|
|
||||||
IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
|
IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
|
||||||
|
|
||||||
if (ret == -ECANCELED) {
|
ide_state->error = ABRT_ERR;
|
||||||
return;
|
ide_state->status = READY_STAT | ERR_STAT;
|
||||||
}
|
ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
|
||||||
/* Clear bit for this tag in SActive */
|
}
|
||||||
ncq_tfs->drive->port_regs.scr_act &= ~(1 << ncq_tfs->tag);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
static void ncq_finish(NCQTransferState *ncq_tfs)
|
||||||
/* error */
|
{
|
||||||
ide_state->error = ABRT_ERR;
|
/* If we didn't error out, set our finished bit. Errored commands
|
||||||
ide_state->status = READY_STAT | ERR_STAT;
|
* do not get a bit set for the SDB FIS ACT register, nor do they
|
||||||
ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
|
* clear the outstanding bit in scr_act (PxSACT). */
|
||||||
} else {
|
if (!(ncq_tfs->drive->port_regs.scr_err & (1 << ncq_tfs->tag))) {
|
||||||
ide_state->status = READY_STAT | SEEK_STAT;
|
ncq_tfs->drive->finished |= (1 << ncq_tfs->tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs->drive->port_no,
|
ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs);
|
||||||
(1 << ncq_tfs->tag));
|
|
||||||
|
|
||||||
DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
|
DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
|
||||||
ncq_tfs->tag);
|
ncq_tfs->tag);
|
||||||
@@ -931,6 +915,35 @@ static void ncq_cb(void *opaque, int ret)
|
|||||||
ncq_tfs->used = 0;
|
ncq_tfs->used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ncq_cb(void *opaque, int ret)
|
||||||
|
{
|
||||||
|
NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
|
||||||
|
IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
|
||||||
|
|
||||||
|
if (ret == -ECANCELED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
bool is_read = ncq_tfs->cmd == READ_FPDMA_QUEUED;
|
||||||
|
BlockErrorAction action = blk_get_error_action(ide_state->blk,
|
||||||
|
is_read, -ret);
|
||||||
|
if (action == BLOCK_ERROR_ACTION_STOP) {
|
||||||
|
ncq_tfs->halt = true;
|
||||||
|
ide_state->bus->error_status = IDE_RETRY_HBA;
|
||||||
|
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
|
||||||
|
ncq_err(ncq_tfs);
|
||||||
|
}
|
||||||
|
blk_error_action(ide_state->blk, action, is_read, -ret);
|
||||||
|
} else {
|
||||||
|
ide_state->status = READY_STAT | SEEK_STAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ncq_tfs->halt) {
|
||||||
|
ncq_finish(ncq_tfs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int is_ncq(uint8_t ata_cmd)
|
static int is_ncq(uint8_t ata_cmd)
|
||||||
{
|
{
|
||||||
/* Based on SATA 3.2 section 13.6.3.2 */
|
/* Based on SATA 3.2 section 13.6.3.2 */
|
||||||
@@ -946,13 +959,60 @@ static int is_ncq(uint8_t ata_cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
|
static void execute_ncq_command(NCQTransferState *ncq_tfs)
|
||||||
int slot)
|
|
||||||
{
|
{
|
||||||
|
AHCIDevice *ad = ncq_tfs->drive;
|
||||||
|
IDEState *ide_state = &ad->port.ifs[0];
|
||||||
|
int port = ad->port_no;
|
||||||
|
|
||||||
|
g_assert(is_ncq(ncq_tfs->cmd));
|
||||||
|
ncq_tfs->halt = false;
|
||||||
|
|
||||||
|
switch (ncq_tfs->cmd) {
|
||||||
|
case READ_FPDMA_QUEUED:
|
||||||
|
DPRINTF(port, "NCQ reading %d sectors from LBA %"PRId64", tag %d\n",
|
||||||
|
ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag);
|
||||||
|
|
||||||
|
DPRINTF(port, "tag %d aio read %"PRId64"\n",
|
||||||
|
ncq_tfs->tag, ncq_tfs->lba);
|
||||||
|
|
||||||
|
dma_acct_start(ide_state->blk, &ncq_tfs->acct,
|
||||||
|
&ncq_tfs->sglist, BLOCK_ACCT_READ);
|
||||||
|
ncq_tfs->aiocb = dma_blk_read(ide_state->blk, &ncq_tfs->sglist,
|
||||||
|
ncq_tfs->lba, ncq_cb, ncq_tfs);
|
||||||
|
break;
|
||||||
|
case WRITE_FPDMA_QUEUED:
|
||||||
|
DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n",
|
||||||
|
ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag);
|
||||||
|
|
||||||
|
DPRINTF(port, "tag %d aio write %"PRId64"\n",
|
||||||
|
ncq_tfs->tag, ncq_tfs->lba);
|
||||||
|
|
||||||
|
dma_acct_start(ide_state->blk, &ncq_tfs->acct,
|
||||||
|
&ncq_tfs->sglist, BLOCK_ACCT_WRITE);
|
||||||
|
ncq_tfs->aiocb = dma_blk_write(ide_state->blk, &ncq_tfs->sglist,
|
||||||
|
ncq_tfs->lba, ncq_cb, ncq_tfs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DPRINTF(port, "error: unsupported NCQ command (0x%02x) received\n",
|
||||||
|
ncq_tfs->cmd);
|
||||||
|
qemu_sglist_destroy(&ncq_tfs->sglist);
|
||||||
|
ncq_err(ncq_tfs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
|
||||||
|
uint8_t slot)
|
||||||
|
{
|
||||||
|
AHCIDevice *ad = &s->dev[port];
|
||||||
|
IDEState *ide_state = &ad->port.ifs[0];
|
||||||
NCQFrame *ncq_fis = (NCQFrame*)cmd_fis;
|
NCQFrame *ncq_fis = (NCQFrame*)cmd_fis;
|
||||||
uint8_t tag = ncq_fis->tag >> 3;
|
uint8_t tag = ncq_fis->tag >> 3;
|
||||||
NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[tag];
|
NCQTransferState *ncq_tfs = &ad->ncq_tfs[tag];
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
g_assert(is_ncq(ncq_fis->command));
|
||||||
if (ncq_tfs->used) {
|
if (ncq_tfs->used) {
|
||||||
/* error - already in use */
|
/* error - already in use */
|
||||||
fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
|
fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
|
||||||
@@ -960,75 +1020,82 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ncq_tfs->used = 1;
|
ncq_tfs->used = 1;
|
||||||
ncq_tfs->drive = &s->dev[port];
|
ncq_tfs->drive = ad;
|
||||||
ncq_tfs->slot = slot;
|
ncq_tfs->slot = slot;
|
||||||
|
ncq_tfs->cmdh = &((AHCICmdHdr *)ad->lst)[slot];
|
||||||
|
ncq_tfs->cmd = ncq_fis->command;
|
||||||
ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
|
ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
|
||||||
((uint64_t)ncq_fis->lba4 << 32) |
|
((uint64_t)ncq_fis->lba4 << 32) |
|
||||||
((uint64_t)ncq_fis->lba3 << 24) |
|
((uint64_t)ncq_fis->lba3 << 24) |
|
||||||
((uint64_t)ncq_fis->lba2 << 16) |
|
((uint64_t)ncq_fis->lba2 << 16) |
|
||||||
((uint64_t)ncq_fis->lba1 << 8) |
|
((uint64_t)ncq_fis->lba1 << 8) |
|
||||||
(uint64_t)ncq_fis->lba0;
|
(uint64_t)ncq_fis->lba0;
|
||||||
|
ncq_tfs->tag = tag;
|
||||||
|
|
||||||
/* Note: We calculate the sector count, but don't currently rely on it.
|
/* Sanity-check the NCQ packet */
|
||||||
* The total size of the DMA buffer tells us the transfer size instead. */
|
if (tag != slot) {
|
||||||
ncq_tfs->sector_count = ((uint16_t)ncq_fis->sector_count_high << 8) |
|
DPRINTF(port, "Warn: NCQ slot (%d) did not match the given tag (%d)\n",
|
||||||
ncq_fis->sector_count_low;
|
slot, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ncq_fis->aux0 || ncq_fis->aux1 || ncq_fis->aux2 || ncq_fis->aux3) {
|
||||||
|
DPRINTF(port, "Warn: Attempt to use NCQ auxiliary fields.\n");
|
||||||
|
}
|
||||||
|
if (ncq_fis->prio || ncq_fis->icc) {
|
||||||
|
DPRINTF(port, "Warn: Unsupported attempt to use PRIO/ICC fields\n");
|
||||||
|
}
|
||||||
|
if (ncq_fis->fua & NCQ_FIS_FUA_MASK) {
|
||||||
|
DPRINTF(port, "Warn: Unsupported attempt to use Force Unit Access\n");
|
||||||
|
}
|
||||||
|
if (ncq_fis->tag & NCQ_FIS_RARC_MASK) {
|
||||||
|
DPRINTF(port, "Warn: Unsupported attempt to use Rebuild Assist\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
ncq_tfs->sector_count = ((ncq_fis->sector_count_high << 8) |
|
||||||
|
ncq_fis->sector_count_low);
|
||||||
|
if (!ncq_tfs->sector_count) {
|
||||||
|
ncq_tfs->sector_count = 0x10000;
|
||||||
|
}
|
||||||
|
size = ncq_tfs->sector_count * 512;
|
||||||
|
ahci_populate_sglist(ad, &ncq_tfs->sglist, ncq_tfs->cmdh, size, 0);
|
||||||
|
|
||||||
|
if (ncq_tfs->sglist.size < size) {
|
||||||
|
error_report("ahci: PRDT length for NCQ command (0x%zx) "
|
||||||
|
"is smaller than the requested size (0x%zx)",
|
||||||
|
ncq_tfs->sglist.size, size);
|
||||||
|
qemu_sglist_destroy(&ncq_tfs->sglist);
|
||||||
|
ncq_err(ncq_tfs);
|
||||||
|
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_OVERFLOW);
|
||||||
|
return;
|
||||||
|
} else if (ncq_tfs->sglist.size != size) {
|
||||||
|
DPRINTF(port, "Warn: PRDTL (0x%zx)"
|
||||||
|
" does not match requested size (0x%zx)",
|
||||||
|
ncq_tfs->sglist.size, size);
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTF(port, "NCQ transfer LBA from %"PRId64" to %"PRId64", "
|
DPRINTF(port, "NCQ transfer LBA from %"PRId64" to %"PRId64", "
|
||||||
"drive max %"PRId64"\n",
|
"drive max %"PRId64"\n",
|
||||||
ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
|
ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 1,
|
||||||
s->dev[port].port.ifs[0].nb_sectors - 1);
|
ide_state->nb_sectors - 1);
|
||||||
|
|
||||||
ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist, 0);
|
execute_ncq_command(ncq_tfs);
|
||||||
ncq_tfs->tag = tag;
|
}
|
||||||
|
|
||||||
switch(ncq_fis->command) {
|
static AHCICmdHdr *get_cmd_header(AHCIState *s, uint8_t port, uint8_t slot)
|
||||||
case READ_FPDMA_QUEUED:
|
{
|
||||||
DPRINTF(port, "NCQ reading %d sectors from LBA %"PRId64", "
|
if (port >= s->ports || slot >= AHCI_MAX_CMDS) {
|
||||||
"tag %d\n",
|
return NULL;
|
||||||
ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
|
|
||||||
|
|
||||||
DPRINTF(port, "tag %d aio read %"PRId64"\n",
|
|
||||||
ncq_tfs->tag, ncq_tfs->lba);
|
|
||||||
|
|
||||||
dma_acct_start(ncq_tfs->drive->port.ifs[0].blk, &ncq_tfs->acct,
|
|
||||||
&ncq_tfs->sglist, BLOCK_ACCT_READ);
|
|
||||||
ncq_tfs->aiocb = dma_blk_read(ncq_tfs->drive->port.ifs[0].blk,
|
|
||||||
&ncq_tfs->sglist, ncq_tfs->lba,
|
|
||||||
ncq_cb, ncq_tfs);
|
|
||||||
break;
|
|
||||||
case WRITE_FPDMA_QUEUED:
|
|
||||||
DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n",
|
|
||||||
ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
|
|
||||||
|
|
||||||
DPRINTF(port, "tag %d aio write %"PRId64"\n",
|
|
||||||
ncq_tfs->tag, ncq_tfs->lba);
|
|
||||||
|
|
||||||
dma_acct_start(ncq_tfs->drive->port.ifs[0].blk, &ncq_tfs->acct,
|
|
||||||
&ncq_tfs->sglist, BLOCK_ACCT_WRITE);
|
|
||||||
ncq_tfs->aiocb = dma_blk_write(ncq_tfs->drive->port.ifs[0].blk,
|
|
||||||
&ncq_tfs->sglist, ncq_tfs->lba,
|
|
||||||
ncq_cb, ncq_tfs);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (is_ncq(cmd_fis[2])) {
|
|
||||||
DPRINTF(port,
|
|
||||||
"error: unsupported NCQ command (0x%02x) received\n",
|
|
||||||
cmd_fis[2]);
|
|
||||||
} else {
|
|
||||||
DPRINTF(port,
|
|
||||||
"error: tried to process non-NCQ command as NCQ\n");
|
|
||||||
}
|
|
||||||
qemu_sglist_destroy(&ncq_tfs->sglist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return s->dev[port].lst ? &((AHCICmdHdr *)s->dev[port].lst)[slot] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_reg_h2d_fis(AHCIState *s, int port,
|
static void handle_reg_h2d_fis(AHCIState *s, int port,
|
||||||
int slot, uint8_t *cmd_fis)
|
uint8_t slot, uint8_t *cmd_fis)
|
||||||
{
|
{
|
||||||
IDEState *ide_state = &s->dev[port].port.ifs[0];
|
IDEState *ide_state = &s->dev[port].port.ifs[0];
|
||||||
AHCICmdHdr *cmd = s->dev[port].cur_cmd;
|
AHCICmdHdr *cmd = get_cmd_header(s, port, slot);
|
||||||
uint32_t opts = le32_to_cpu(cmd->opts);
|
uint16_t opts = le16_to_cpu(cmd->opts);
|
||||||
|
|
||||||
if (cmd_fis[1] & 0x0F) {
|
if (cmd_fis[1] & 0x0F) {
|
||||||
DPRINTF(port, "Port Multiplier not supported."
|
DPRINTF(port, "Port Multiplier not supported."
|
||||||
@@ -1108,7 +1175,7 @@ static void handle_reg_h2d_fis(AHCIState *s, int port,
|
|||||||
ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
|
ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_cmd(AHCIState *s, int port, int slot)
|
static int handle_cmd(AHCIState *s, int port, uint8_t slot)
|
||||||
{
|
{
|
||||||
IDEState *ide_state;
|
IDEState *ide_state;
|
||||||
uint64_t tbl_addr;
|
uint64_t tbl_addr;
|
||||||
@@ -1126,7 +1193,7 @@ static int handle_cmd(AHCIState *s, int port, int slot)
|
|||||||
DPRINTF(port, "error: lst not given but cmd handled");
|
DPRINTF(port, "error: lst not given but cmd handled");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cmd = &((AHCICmdHdr *)s->dev[port].lst)[slot];
|
cmd = get_cmd_header(s, port, slot);
|
||||||
/* remember current slot handle for later */
|
/* remember current slot handle for later */
|
||||||
s->dev[port].cur_cmd = cmd;
|
s->dev[port].cur_cmd = cmd;
|
||||||
|
|
||||||
@@ -1185,7 +1252,7 @@ static void ahci_start_transfer(IDEDMA *dma)
|
|||||||
IDEState *s = &ad->port.ifs[0];
|
IDEState *s = &ad->port.ifs[0];
|
||||||
uint32_t size = (uint32_t)(s->data_end - s->data_ptr);
|
uint32_t size = (uint32_t)(s->data_end - s->data_ptr);
|
||||||
/* write == ram -> device */
|
/* write == ram -> device */
|
||||||
uint32_t opts = le32_to_cpu(ad->cur_cmd->opts);
|
uint16_t opts = le16_to_cpu(ad->cur_cmd->opts);
|
||||||
int is_write = opts & AHCI_CMD_WRITE;
|
int is_write = opts & AHCI_CMD_WRITE;
|
||||||
int is_atapi = opts & AHCI_CMD_ATAPI;
|
int is_atapi = opts & AHCI_CMD_ATAPI;
|
||||||
int has_sglist = 0;
|
int has_sglist = 0;
|
||||||
@@ -1197,7 +1264,7 @@ static void ahci_start_transfer(IDEDMA *dma)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ahci_dma_prepare_buf(dma, is_write)) {
|
if (ahci_dma_prepare_buf(dma, size)) {
|
||||||
has_sglist = 1;
|
has_sglist = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1242,17 +1309,35 @@ static void ahci_restart_dma(IDEDMA *dma)
|
|||||||
/* Nothing to do, ahci_start_dma already resets s->io_buffer_offset. */
|
/* Nothing to do, ahci_start_dma already resets s->io_buffer_offset. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IDE/PIO restarts are handled by the core layer, but NCQ commands
|
||||||
|
* need an extra kick from the AHCI HBA.
|
||||||
|
*/
|
||||||
|
static void ahci_restart(IDEDMA *dma)
|
||||||
|
{
|
||||||
|
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < AHCI_MAX_CMDS; i++) {
|
||||||
|
NCQTransferState *ncq_tfs = &ad->ncq_tfs[i];
|
||||||
|
if (ncq_tfs->halt) {
|
||||||
|
execute_ncq_command(ncq_tfs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called in DMA R/W chains to read the PRDT, utilizing ahci_populate_sglist.
|
* Called in DMA R/W chains to read the PRDT, utilizing ahci_populate_sglist.
|
||||||
* Not currently invoked by PIO R/W chains,
|
* Not currently invoked by PIO R/W chains,
|
||||||
* which invoke ahci_populate_sglist via ahci_start_transfer.
|
* which invoke ahci_populate_sglist via ahci_start_transfer.
|
||||||
*/
|
*/
|
||||||
static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
|
static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit)
|
||||||
{
|
{
|
||||||
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
||||||
IDEState *s = &ad->port.ifs[0];
|
IDEState *s = &ad->port.ifs[0];
|
||||||
|
|
||||||
if (ahci_populate_sglist(ad, &s->sg, s->io_buffer_offset) == -1) {
|
if (ahci_populate_sglist(ad, &s->sg, ad->cur_cmd,
|
||||||
|
limit, s->io_buffer_offset) == -1) {
|
||||||
DPRINTF(ad->port_no, "ahci_dma_prepare_buf failed.\n");
|
DPRINTF(ad->port_no, "ahci_dma_prepare_buf failed.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1287,7 +1372,7 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
|
|||||||
uint8_t *p = s->io_buffer + s->io_buffer_index;
|
uint8_t *p = s->io_buffer + s->io_buffer_index;
|
||||||
int l = s->io_buffer_size - s->io_buffer_index;
|
int l = s->io_buffer_size - s->io_buffer_index;
|
||||||
|
|
||||||
if (ahci_populate_sglist(ad, &s->sg, s->io_buffer_offset)) {
|
if (ahci_populate_sglist(ad, &s->sg, ad->cur_cmd, l, s->io_buffer_offset)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1330,6 +1415,7 @@ static void ahci_irq_set(void *opaque, int n, int level)
|
|||||||
|
|
||||||
static const IDEDMAOps ahci_dma_ops = {
|
static const IDEDMAOps ahci_dma_ops = {
|
||||||
.start_dma = ahci_start_dma,
|
.start_dma = ahci_start_dma,
|
||||||
|
.restart = ahci_restart,
|
||||||
.restart_dma = ahci_restart_dma,
|
.restart_dma = ahci_restart_dma,
|
||||||
.start_transfer = ahci_start_transfer,
|
.start_transfer = ahci_start_transfer,
|
||||||
.prepare_buf = ahci_dma_prepare_buf,
|
.prepare_buf = ahci_dma_prepare_buf,
|
||||||
@@ -1400,6 +1486,21 @@ void ahci_reset(AHCIState *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_ncq_tfs = {
|
||||||
|
.name = "ncq state",
|
||||||
|
.version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(sector_count, NCQTransferState),
|
||||||
|
VMSTATE_UINT64(lba, NCQTransferState),
|
||||||
|
VMSTATE_UINT8(tag, NCQTransferState),
|
||||||
|
VMSTATE_UINT8(cmd, NCQTransferState),
|
||||||
|
VMSTATE_UINT8(slot, NCQTransferState),
|
||||||
|
VMSTATE_BOOL(used, NCQTransferState),
|
||||||
|
VMSTATE_BOOL(halt, NCQTransferState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const VMStateDescription vmstate_ahci_device = {
|
static const VMStateDescription vmstate_ahci_device = {
|
||||||
.name = "ahci port",
|
.name = "ahci port",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
@@ -1425,14 +1526,17 @@ static const VMStateDescription vmstate_ahci_device = {
|
|||||||
VMSTATE_BOOL(done_atapi_packet, AHCIDevice),
|
VMSTATE_BOOL(done_atapi_packet, AHCIDevice),
|
||||||
VMSTATE_INT32(busy_slot, AHCIDevice),
|
VMSTATE_INT32(busy_slot, AHCIDevice),
|
||||||
VMSTATE_BOOL(init_d2h_sent, AHCIDevice),
|
VMSTATE_BOOL(init_d2h_sent, AHCIDevice),
|
||||||
|
VMSTATE_STRUCT_ARRAY(ncq_tfs, AHCIDevice, AHCI_MAX_CMDS,
|
||||||
|
1, vmstate_ncq_tfs, NCQTransferState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ahci_state_post_load(void *opaque, int version_id)
|
static int ahci_state_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
int i;
|
int i, j;
|
||||||
struct AHCIDevice *ad;
|
struct AHCIDevice *ad;
|
||||||
|
NCQTransferState *ncq_tfs;
|
||||||
AHCIState *s = opaque;
|
AHCIState *s = opaque;
|
||||||
|
|
||||||
for (i = 0; i < s->ports; i++) {
|
for (i = 0; i < s->ports; i++) {
|
||||||
@@ -1444,6 +1548,37 @@ static int ahci_state_post_load(void *opaque, int version_id)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < AHCI_MAX_CMDS; j++) {
|
||||||
|
ncq_tfs = &ad->ncq_tfs[j];
|
||||||
|
ncq_tfs->drive = ad;
|
||||||
|
|
||||||
|
if (ncq_tfs->used != ncq_tfs->halt) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!ncq_tfs->halt) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!is_ncq(ncq_tfs->cmd)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ncq_tfs->slot != ncq_tfs->tag) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* If ncq_tfs->halt is justly set, the engine should be engaged,
|
||||||
|
* and the command list buffer should be mapped. */
|
||||||
|
ncq_tfs->cmdh = get_cmd_header(s, i, ncq_tfs->slot);
|
||||||
|
if (!ncq_tfs->cmdh) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ahci_populate_sglist(ncq_tfs->drive, &ncq_tfs->sglist,
|
||||||
|
ncq_tfs->cmdh, ncq_tfs->sector_count * 512,
|
||||||
|
0);
|
||||||
|
if (ncq_tfs->sector_count != ncq_tfs->sglist.size >> 9) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If an error is present, ad->busy_slot will be valid and not -1.
|
* If an error is present, ad->busy_slot will be valid and not -1.
|
||||||
* In this case, an operation is waiting to resume and will re-check
|
* In this case, an operation is waiting to resume and will re-check
|
||||||
@@ -1460,7 +1595,7 @@ static int ahci_state_post_load(void *opaque, int version_id)
|
|||||||
if (ad->busy_slot < 0 || ad->busy_slot >= AHCI_MAX_CMDS) {
|
if (ad->busy_slot < 0 || ad->busy_slot >= AHCI_MAX_CMDS) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ad->cur_cmd = &((AHCICmdHdr *)ad->lst)[ad->busy_slot];
|
ad->cur_cmd = get_cmd_header(s, i, ad->busy_slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,7 @@
|
|||||||
#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f
|
#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f
|
||||||
#define AHCI_CMD_HDR_PRDT_LEN 16
|
#define AHCI_CMD_HDR_PRDT_LEN 16
|
||||||
|
|
||||||
#define SATA_SIGNATURE_CDROM 0xeb140000
|
#define SATA_SIGNATURE_CDROM 0xeb140101
|
||||||
#define SATA_SIGNATURE_DISK 0x00000101
|
#define SATA_SIGNATURE_DISK 0x00000101
|
||||||
|
|
||||||
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
|
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
|
||||||
@@ -195,6 +195,9 @@
|
|||||||
#define RECEIVE_FPDMA_QUEUED 0x65
|
#define RECEIVE_FPDMA_QUEUED 0x65
|
||||||
#define SEND_FPDMA_QUEUED 0x64
|
#define SEND_FPDMA_QUEUED 0x64
|
||||||
|
|
||||||
|
#define NCQ_FIS_FUA_MASK 0x80
|
||||||
|
#define NCQ_FIS_RARC_MASK 0x01
|
||||||
|
|
||||||
#define RES_FIS_DSFIS 0x00
|
#define RES_FIS_DSFIS 0x00
|
||||||
#define RES_FIS_PSFIS 0x20
|
#define RES_FIS_PSFIS 0x20
|
||||||
#define RES_FIS_RFIS 0x40
|
#define RES_FIS_RFIS 0x40
|
||||||
@@ -233,7 +236,8 @@ typedef struct AHCIPortRegs {
|
|||||||
} AHCIPortRegs;
|
} AHCIPortRegs;
|
||||||
|
|
||||||
typedef struct AHCICmdHdr {
|
typedef struct AHCICmdHdr {
|
||||||
uint32_t opts;
|
uint16_t opts;
|
||||||
|
uint16_t prdtl;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
uint64_t tbl_addr;
|
uint64_t tbl_addr;
|
||||||
uint32_t reserved[4];
|
uint32_t reserved[4];
|
||||||
@@ -250,13 +254,16 @@ typedef struct AHCIDevice AHCIDevice;
|
|||||||
typedef struct NCQTransferState {
|
typedef struct NCQTransferState {
|
||||||
AHCIDevice *drive;
|
AHCIDevice *drive;
|
||||||
BlockAIOCB *aiocb;
|
BlockAIOCB *aiocb;
|
||||||
|
AHCICmdHdr *cmdh;
|
||||||
QEMUSGList sglist;
|
QEMUSGList sglist;
|
||||||
BlockAcctCookie acct;
|
BlockAcctCookie acct;
|
||||||
uint16_t sector_count;
|
uint32_t sector_count;
|
||||||
uint64_t lba;
|
uint64_t lba;
|
||||||
uint8_t tag;
|
uint8_t tag;
|
||||||
int slot;
|
uint8_t cmd;
|
||||||
int used;
|
uint8_t slot;
|
||||||
|
bool used;
|
||||||
|
bool halt;
|
||||||
} NCQTransferState;
|
} NCQTransferState;
|
||||||
|
|
||||||
struct AHCIDevice {
|
struct AHCIDevice {
|
||||||
@@ -312,27 +319,39 @@ extern const VMStateDescription vmstate_ahci;
|
|||||||
.offset = vmstate_offset_value(_state, _field, AHCIState), \
|
.offset = vmstate_offset_value(_state, _field, AHCIState), \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NCQFrame is the same as a Register H2D FIS (described in SATA 3.2),
|
||||||
|
* but some fields have been re-mapped and re-purposed, as seen in
|
||||||
|
* SATA 3.2 section 13.6.4.1 ("READ FPDMA QUEUED")
|
||||||
|
*
|
||||||
|
* cmd_fis[3], feature 7:0, becomes sector count 7:0.
|
||||||
|
* cmd_fis[7], device 7:0, uses bit 7 as the Force Unit Access bit.
|
||||||
|
* cmd_fis[11], feature 15:8, becomes sector count 15:8.
|
||||||
|
* cmd_fis[12], count 7:0, becomes the NCQ TAG (7:3) and RARC bit (0)
|
||||||
|
* cmd_fis[13], count 15:8, becomes the priority value (7:6)
|
||||||
|
* bytes 16-19 become an le32 "auxiliary" field.
|
||||||
|
*/
|
||||||
typedef struct NCQFrame {
|
typedef struct NCQFrame {
|
||||||
uint8_t fis_type;
|
uint8_t fis_type;
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
uint8_t command;
|
uint8_t command;
|
||||||
uint8_t sector_count_low;
|
uint8_t sector_count_low; /* (feature 7:0) */
|
||||||
uint8_t lba0;
|
uint8_t lba0;
|
||||||
uint8_t lba1;
|
uint8_t lba1;
|
||||||
uint8_t lba2;
|
uint8_t lba2;
|
||||||
uint8_t fua;
|
uint8_t fua; /* (device 7:0) */
|
||||||
uint8_t lba3;
|
uint8_t lba3;
|
||||||
uint8_t lba4;
|
uint8_t lba4;
|
||||||
uint8_t lba5;
|
uint8_t lba5;
|
||||||
uint8_t sector_count_high;
|
uint8_t sector_count_high; /* (feature 15:8) */
|
||||||
uint8_t tag;
|
uint8_t tag; /* (count 0:7) */
|
||||||
uint8_t reserved5;
|
uint8_t prio; /* (count 15:8) */
|
||||||
uint8_t reserved6;
|
uint8_t icc;
|
||||||
uint8_t control;
|
uint8_t control;
|
||||||
uint8_t reserved7;
|
uint8_t aux0;
|
||||||
uint8_t reserved8;
|
uint8_t aux1;
|
||||||
uint8_t reserved9;
|
uint8_t aux2;
|
||||||
uint8_t reserved10;
|
uint8_t aux3;
|
||||||
} QEMU_PACKED NCQFrame;
|
} QEMU_PACKED NCQFrame;
|
||||||
|
|
||||||
typedef struct SDBFIS {
|
typedef struct SDBFIS {
|
||||||
|
|||||||
@@ -716,8 +716,8 @@ static void ide_dma_cb(void *opaque, int ret)
|
|||||||
|
|
||||||
sector_num = ide_get_sector(s);
|
sector_num = ide_get_sector(s);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
assert(s->io_buffer_size == s->sg.size);
|
assert(n * 512 == s->sg.size);
|
||||||
dma_buf_commit(s, s->io_buffer_size);
|
dma_buf_commit(s, s->sg.size);
|
||||||
sector_num += n;
|
sector_num += n;
|
||||||
ide_set_sector(s, sector_num);
|
ide_set_sector(s, sector_num);
|
||||||
s->nsector -= n;
|
s->nsector -= n;
|
||||||
@@ -734,7 +734,7 @@ static void ide_dma_cb(void *opaque, int ret)
|
|||||||
n = s->nsector;
|
n = s->nsector;
|
||||||
s->io_buffer_index = 0;
|
s->io_buffer_index = 0;
|
||||||
s->io_buffer_size = n * 512;
|
s->io_buffer_size = n * 512;
|
||||||
if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) < 512) {
|
if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->io_buffer_size) < 512) {
|
||||||
/* The PRDs were too short. Reset the Active bit, but don't raise an
|
/* The PRDs were too short. Reset the Active bit, but don't raise an
|
||||||
* interrupt. */
|
* interrupt. */
|
||||||
s->status = READY_STAT | SEEK_STAT;
|
s->status = READY_STAT | SEEK_STAT;
|
||||||
@@ -2326,7 +2326,7 @@ static void ide_nop(IDEDMA *dma)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t ide_nop_int32(IDEDMA *dma, int x)
|
static int32_t ide_nop_int32(IDEDMA *dma, int32_t l)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2371,6 +2371,13 @@ static void ide_restart_bh(void *opaque)
|
|||||||
* called function can set a new error status. */
|
* called function can set a new error status. */
|
||||||
bus->error_status = 0;
|
bus->error_status = 0;
|
||||||
|
|
||||||
|
/* The HBA has generically asked to be kicked on retry */
|
||||||
|
if (error_status & IDE_RETRY_HBA) {
|
||||||
|
if (s->bus->dma->ops->restart) {
|
||||||
|
s->bus->dma->ops->restart(s->bus->dma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (error_status & IDE_RETRY_DMA) {
|
if (error_status & IDE_RETRY_DMA) {
|
||||||
if (error_status & IDE_RETRY_TRIM) {
|
if (error_status & IDE_RETRY_TRIM) {
|
||||||
ide_restart_dma(s, IDE_DMA_TRIM);
|
ide_restart_dma(s, IDE_DMA_TRIM);
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ typedef void EndTransferFunc(IDEState *);
|
|||||||
typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockCompletionFunc *);
|
typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockCompletionFunc *);
|
||||||
typedef void DMAVoidFunc(IDEDMA *);
|
typedef void DMAVoidFunc(IDEDMA *);
|
||||||
typedef int DMAIntFunc(IDEDMA *, int);
|
typedef int DMAIntFunc(IDEDMA *, int);
|
||||||
typedef int32_t DMAInt32Func(IDEDMA *, int);
|
typedef int32_t DMAInt32Func(IDEDMA *, int32_t len);
|
||||||
typedef void DMAu32Func(IDEDMA *, uint32_t);
|
typedef void DMAu32Func(IDEDMA *, uint32_t);
|
||||||
typedef void DMAStopFunc(IDEDMA *, bool);
|
typedef void DMAStopFunc(IDEDMA *, bool);
|
||||||
typedef void DMARestartFunc(void *, int, RunState);
|
typedef void DMARestartFunc(void *, int, RunState);
|
||||||
@@ -436,6 +436,7 @@ struct IDEDMAOps {
|
|||||||
DMAInt32Func *prepare_buf;
|
DMAInt32Func *prepare_buf;
|
||||||
DMAu32Func *commit_buf;
|
DMAu32Func *commit_buf;
|
||||||
DMAIntFunc *rw_buf;
|
DMAIntFunc *rw_buf;
|
||||||
|
DMAVoidFunc *restart;
|
||||||
DMAVoidFunc *restart_dma;
|
DMAVoidFunc *restart_dma;
|
||||||
DMAStopFunc *set_inactive;
|
DMAStopFunc *set_inactive;
|
||||||
DMAVoidFunc *cmd_done;
|
DMAVoidFunc *cmd_done;
|
||||||
@@ -499,6 +500,7 @@ struct IDEDevice {
|
|||||||
#define IDE_RETRY_READ 0x20
|
#define IDE_RETRY_READ 0x20
|
||||||
#define IDE_RETRY_FLUSH 0x40
|
#define IDE_RETRY_FLUSH 0x40
|
||||||
#define IDE_RETRY_TRIM 0x80
|
#define IDE_RETRY_TRIM 0x80
|
||||||
|
#define IDE_RETRY_HBA 0x100
|
||||||
|
|
||||||
static inline IDEState *idebus_active_if(IDEBus *bus)
|
static inline IDEState *idebus_active_if(IDEBus *bus)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -499,7 +499,7 @@ static int ide_nop_int(IDEDMA *dma, int x)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t ide_nop_int32(IDEDMA *dma, int x)
|
static int32_t ide_nop_int32(IDEDMA *dma, int32_t l)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
21
hw/ide/pci.c
21
hw/ide/pci.c
@@ -53,10 +53,14 @@ static void bmdma_start_dma(IDEDMA *dma, IDEState *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the number of bytes successfully prepared.
|
* Prepare an sglist based on available PRDs.
|
||||||
* -1 on error.
|
* @limit: How many bytes to prepare total.
|
||||||
|
*
|
||||||
|
* Returns the number of bytes prepared, -1 on error.
|
||||||
|
* IDEState.io_buffer_size will contain the number of bytes described
|
||||||
|
* by the PRDs, whether or not we added them to the sglist.
|
||||||
*/
|
*/
|
||||||
static int32_t bmdma_prepare_buf(IDEDMA *dma, int is_write)
|
static int32_t bmdma_prepare_buf(IDEDMA *dma, int32_t limit)
|
||||||
{
|
{
|
||||||
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
|
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
|
||||||
IDEState *s = bmdma_active_if(bm);
|
IDEState *s = bmdma_active_if(bm);
|
||||||
@@ -75,7 +79,7 @@ static int32_t bmdma_prepare_buf(IDEDMA *dma, int is_write)
|
|||||||
/* end of table (with a fail safe of one page) */
|
/* end of table (with a fail safe of one page) */
|
||||||
if (bm->cur_prd_last ||
|
if (bm->cur_prd_last ||
|
||||||
(bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) {
|
(bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) {
|
||||||
return s->io_buffer_size;
|
return s->sg.size;
|
||||||
}
|
}
|
||||||
pci_dma_read(pci_dev, bm->cur_addr, &prd, 8);
|
pci_dma_read(pci_dev, bm->cur_addr, &prd, 8);
|
||||||
bm->cur_addr += 8;
|
bm->cur_addr += 8;
|
||||||
@@ -90,7 +94,14 @@ static int32_t bmdma_prepare_buf(IDEDMA *dma, int is_write)
|
|||||||
}
|
}
|
||||||
l = bm->cur_prd_len;
|
l = bm->cur_prd_len;
|
||||||
if (l > 0) {
|
if (l > 0) {
|
||||||
qemu_sglist_add(&s->sg, bm->cur_prd_addr, l);
|
uint64_t sg_len;
|
||||||
|
|
||||||
|
/* Don't add extra bytes to the SGList; consume any remaining
|
||||||
|
* PRDs from the guest, but ignore them. */
|
||||||
|
sg_len = MIN(limit - s->sg.size, bm->cur_prd_len);
|
||||||
|
if (sg_len) {
|
||||||
|
qemu_sglist_add(&s->sg, bm->cur_prd_addr, sg_len);
|
||||||
|
}
|
||||||
|
|
||||||
/* Note: We limit the max transfer to be 2GiB.
|
/* Note: We limit the max transfer to be 2GiB.
|
||||||
* This should accommodate the largest ATA transaction
|
* This should accommodate the largest ATA transaction
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
|
|||||||
|
|
||||||
static void hid_keyboard_process_keycode(HIDState *hs)
|
static void hid_keyboard_process_keycode(HIDState *hs)
|
||||||
{
|
{
|
||||||
uint8_t hid_code, key;
|
uint8_t hid_code, index, key;
|
||||||
int i, keycode, slot;
|
int i, keycode, slot;
|
||||||
|
|
||||||
if (hs->n == 0) {
|
if (hs->n == 0) {
|
||||||
@@ -249,7 +249,8 @@ static void hid_keyboard_process_keycode(HIDState *hs)
|
|||||||
keycode = hs->kbd.keycodes[slot];
|
keycode = hs->kbd.keycodes[slot];
|
||||||
|
|
||||||
key = keycode & 0x7f;
|
key = keycode & 0x7f;
|
||||||
hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
|
index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
|
||||||
|
hid_code = hid_usage_keys[index];
|
||||||
hs->kbd.modifiers &= ~(1 << 8);
|
hs->kbd.modifiers &= ~(1 << 8);
|
||||||
|
|
||||||
switch (hid_code) {
|
switch (hid_code) {
|
||||||
@@ -257,18 +258,41 @@ static void hid_keyboard_process_keycode(HIDState *hs)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case 0xe0:
|
case 0xe0:
|
||||||
|
assert(key == 0x1d);
|
||||||
if (hs->kbd.modifiers & (1 << 9)) {
|
if (hs->kbd.modifiers & (1 << 9)) {
|
||||||
hs->kbd.modifiers ^= 3 << 8;
|
/* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0.
|
||||||
|
* Here we're processing the second hid_code. By dropping bit 9
|
||||||
|
* and setting bit 8, the scancode after 0x1d will access the
|
||||||
|
* second half of the table.
|
||||||
|
*/
|
||||||
|
hs->kbd.modifiers ^= (1 << 8) | (1 << 9);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* fall through to process Ctrl_L */
|
||||||
case 0xe1 ... 0xe7:
|
case 0xe1 ... 0xe7:
|
||||||
|
/* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R.
|
||||||
|
* Handle releases here, or fall through to process presses.
|
||||||
|
*/
|
||||||
if (keycode & (1 << 7)) {
|
if (keycode & (1 << 7)) {
|
||||||
hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
|
hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 0xe8 ... 0xef:
|
/* fall through */
|
||||||
|
case 0xe8 ... 0xe9:
|
||||||
|
/* USB modifiers are just 1 byte long. Bits 8 and 9 of
|
||||||
|
* hs->kbd.modifiers implement a state machine that detects the
|
||||||
|
* 0xe0 and 0xe1/0x1d sequences. These bits do not follow the
|
||||||
|
* usual rules where bit 7 marks released keys; they are cleared
|
||||||
|
* elsewhere in the function as the state machine dictates.
|
||||||
|
*/
|
||||||
hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
|
hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 0xea ... 0xef:
|
||||||
|
abort();
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keycode & (1 << 7)) {
|
if (keycode & (1 << 7)) {
|
||||||
|
|||||||
@@ -308,6 +308,7 @@ static void virtio_input_hid_handle_status(VirtIOInput *vinput,
|
|||||||
static Property virtio_input_hid_properties[] = {
|
static Property virtio_input_hid_properties[] = {
|
||||||
DEFINE_PROP_STRING("display", VirtIOInputHID, display),
|
DEFINE_PROP_STRING("display", VirtIOInputHID, display),
|
||||||
DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0),
|
DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
|
static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "hw/virtio/virtio.h"
|
#include "hw/virtio/virtio.h"
|
||||||
#include "hw/virtio/virtio-input.h"
|
#include "hw/virtio/virtio-input.h"
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include "standard-headers/linux/input.h"
|
#include "standard-headers/linux/input.h"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------- */
|
/* ----------------------------------------------------------------- */
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ static void arm_gic_common_realize(DeviceState *dev, Error **errp)
|
|||||||
static void arm_gic_common_reset(DeviceState *dev)
|
static void arm_gic_common_reset(DeviceState *dev)
|
||||||
{
|
{
|
||||||
GICState *s = ARM_GIC_COMMON(dev);
|
GICState *s = ARM_GIC_COMMON(dev);
|
||||||
int i;
|
int i, j;
|
||||||
memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
|
memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
|
||||||
for (i = 0 ; i < s->num_cpu; i++) {
|
for (i = 0 ; i < s->num_cpu; i++) {
|
||||||
if (s->revision == REV_11MPCORE) {
|
if (s->revision == REV_11MPCORE) {
|
||||||
@@ -135,15 +135,30 @@ static void arm_gic_common_reset(DeviceState *dev)
|
|||||||
s->running_irq[i] = 1023;
|
s->running_irq[i] = 1023;
|
||||||
s->running_priority[i] = 0x100;
|
s->running_priority[i] = 0x100;
|
||||||
s->cpu_ctlr[i] = 0;
|
s->cpu_ctlr[i] = 0;
|
||||||
|
s->bpr[i] = GIC_MIN_BPR;
|
||||||
|
s->abpr[i] = GIC_MIN_ABPR;
|
||||||
|
for (j = 0; j < GIC_INTERNAL; j++) {
|
||||||
|
s->priority1[j][i] = 0;
|
||||||
|
}
|
||||||
|
for (j = 0; j < GIC_NR_SGIS; j++) {
|
||||||
|
s->sgi_pending[j][i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < GIC_NR_SGIS; i++) {
|
for (i = 0; i < GIC_NR_SGIS; i++) {
|
||||||
GIC_SET_ENABLED(i, ALL_CPU_MASK);
|
GIC_SET_ENABLED(i, ALL_CPU_MASK);
|
||||||
GIC_SET_EDGE_TRIGGER(i);
|
GIC_SET_EDGE_TRIGGER(i);
|
||||||
}
|
}
|
||||||
if (s->num_cpu == 1) {
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(s->priority2); i++) {
|
||||||
|
s->priority2[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < GIC_MAXIRQ; i++) {
|
||||||
/* For uniprocessor GICs all interrupts always target the sole CPU */
|
/* For uniprocessor GICs all interrupts always target the sole CPU */
|
||||||
for (i = 0; i < GIC_MAXIRQ; i++) {
|
if (s->num_cpu == 1) {
|
||||||
s->irq_target[i] = 1;
|
s->irq_target[i] = 1;
|
||||||
|
} else {
|
||||||
|
s->irq_target[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s->ctlr = 0;
|
s->ctlr = 0;
|
||||||
|
|||||||
@@ -570,6 +570,12 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
|||||||
*/
|
*/
|
||||||
i += (GIC_INTERNAL * s->num_cpu);
|
i += (GIC_INTERNAL * s->num_cpu);
|
||||||
qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
|
qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
|
||||||
|
|
||||||
|
for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
|
||||||
|
qemu_irq irq = qdev_get_gpio_in(dev, i);
|
||||||
|
kvm_irqchip_set_qemuirq_gsi(kvm_state, irq, i);
|
||||||
|
}
|
||||||
|
|
||||||
/* We never use our outbound IRQ/FIQ lines but provide them so that
|
/* We never use our outbound IRQ/FIQ lines but provide them so that
|
||||||
* we maintain the same interface as the non-KVM GIC.
|
* we maintain the same interface as the non-KVM GIC.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -806,7 +806,7 @@ void xics_free(XICSState *icp, int irq, int num)
|
|||||||
* Guest interfaces
|
* Guest interfaces
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
@@ -816,7 +816,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
target_ulong server = get_cpu_index_by_dt_id(args[0]);
|
target_ulong server = get_cpu_index_by_dt_id(args[0]);
|
||||||
@@ -830,7 +830,7 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
@@ -840,7 +840,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
@@ -852,7 +852,7 @@ static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
@@ -862,7 +862,7 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
@@ -874,7 +874,7 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t token,
|
uint32_t token,
|
||||||
uint32_t nargs, target_ulong args,
|
uint32_t nargs, target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
@@ -902,7 +902,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t token,
|
uint32_t token,
|
||||||
uint32_t nargs, target_ulong args,
|
uint32_t nargs, target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
@@ -927,7 +927,7 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
|
rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t token,
|
uint32_t token,
|
||||||
uint32_t nargs, target_ulong args,
|
uint32_t nargs, target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
@@ -953,7 +953,7 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t token,
|
uint32_t token,
|
||||||
uint32_t nargs, target_ulong args,
|
uint32_t nargs, target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
|
|||||||
@@ -331,6 +331,15 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are reusing a parked vCPU fd corresponding to the CPU
|
||||||
|
* which was hot-removed earlier we don't have to renable
|
||||||
|
* KVM_CAP_IRQ_XICS capability again.
|
||||||
|
*/
|
||||||
|
if (ss->cap_irq_xics_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (icpkvm->kernel_xics_fd != -1) {
|
if (icpkvm->kernel_xics_fd != -1) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -343,6 +352,7 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
|||||||
kvm_arch_vcpu_id(cs), strerror(errno));
|
kvm_arch_vcpu_id(cs), strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
ss->cap_irq_xics_enabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +378,7 @@ static void xics_kvm_set_nr_servers(XICSState *icp, uint32_t nr_servers,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_dummy(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t token,
|
uint32_t token,
|
||||||
uint32_t nargs, target_ulong args,
|
uint32_t nargs, target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ static void ich9_cc_reset(ICH9LPCState *lpc)
|
|||||||
pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT);
|
pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT);
|
||||||
pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT);
|
pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT);
|
||||||
pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT);
|
pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT);
|
||||||
|
pci_set_long(c + ICH9_CC_GCS, ICH9_CC_GCS_DEFAULT);
|
||||||
|
|
||||||
ich9_cc_update(lpc);
|
ich9_cc_update(lpc);
|
||||||
}
|
}
|
||||||
@@ -313,6 +314,16 @@ PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
|
|||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ich9_generate_smi(void)
|
||||||
|
{
|
||||||
|
cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ich9_generate_nmi(void)
|
||||||
|
{
|
||||||
|
cpu_interrupt(first_cpu, CPU_INTERRUPT_NMI);
|
||||||
|
}
|
||||||
|
|
||||||
static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
|
static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
|
||||||
{
|
{
|
||||||
switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
|
switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
|
||||||
@@ -357,11 +368,13 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ich9_lpc_pm_init(PCIDevice *lpc_pci)
|
void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled, bool enable_tco)
|
||||||
{
|
{
|
||||||
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
|
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
|
||||||
|
qemu_irq sci_irq;
|
||||||
|
|
||||||
ich9_pm_init(lpc_pci, &lpc->pm, qemu_allocate_irq(ich9_set_sci, lpc, 0));
|
sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0);
|
||||||
|
ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, enable_tco, sci_irq);
|
||||||
ich9_lpc_reset(&lpc->d.qdev);
|
ich9_lpc_reset(&lpc->d.qdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,6 +388,9 @@ static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
|
|||||||
acpi_pm1_cnt_update(&lpc->pm.acpi_regs,
|
acpi_pm1_cnt_update(&lpc->pm.acpi_regs,
|
||||||
val == ICH9_APM_ACPI_ENABLE,
|
val == ICH9_APM_ACPI_ENABLE,
|
||||||
val == ICH9_APM_ACPI_DISABLE);
|
val == ICH9_APM_ACPI_DISABLE);
|
||||||
|
if (val == ICH9_APM_ACPI_ENABLE || val == ICH9_APM_ACPI_DISABLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* SMI_EN = PMBASE + 30. SMI control and enable register */
|
/* SMI_EN = PMBASE + 30. SMI control and enable register */
|
||||||
if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
|
if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
|
||||||
@@ -676,6 +692,11 @@ static const VMStateDescription vmstate_ich9_lpc = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Property ich9_lpc_properties[] = {
|
||||||
|
DEFINE_PROP_BOOL("noreboot", ICH9LPCState, pin_strap.spkr_hi, true),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
static void ich9_lpc_class_init(ObjectClass *klass, void *data)
|
static void ich9_lpc_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
@@ -687,6 +708,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data)
|
|||||||
dc->reset = ich9_lpc_reset;
|
dc->reset = ich9_lpc_reset;
|
||||||
k->init = ich9_lpc_init;
|
k->init = ich9_lpc_init;
|
||||||
dc->vmsd = &vmstate_ich9_lpc;
|
dc->vmsd = &vmstate_ich9_lpc;
|
||||||
|
dc->props = ich9_lpc_properties;
|
||||||
k->config_write = ich9_lpc_config_write;
|
k->config_write = ich9_lpc_config_write;
|
||||||
dc->desc = "ICH9 LPC bridge";
|
dc->desc = "ICH9 LPC bridge";
|
||||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||||
|
|||||||
@@ -23,12 +23,96 @@
|
|||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
#include "qemu/range.h"
|
#include "qemu/range.h"
|
||||||
#include "sysemu/numa.h"
|
#include "sysemu/numa.h"
|
||||||
|
#include "sysemu/kvm.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
typedef struct pc_dimms_capacity {
|
typedef struct pc_dimms_capacity {
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
Error **errp;
|
Error **errp;
|
||||||
} pc_dimms_capacity;
|
} pc_dimms_capacity;
|
||||||
|
|
||||||
|
void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
|
||||||
|
MemoryRegion *mr, uint64_t align, Error **errp)
|
||||||
|
{
|
||||||
|
int slot;
|
||||||
|
MachineState *machine = MACHINE(qdev_get_machine());
|
||||||
|
PCDIMMDevice *dimm = PC_DIMM(dev);
|
||||||
|
Error *local_err = NULL;
|
||||||
|
uint64_t existing_dimms_capacity = 0;
|
||||||
|
uint64_t addr;
|
||||||
|
|
||||||
|
addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = pc_dimm_get_free_addr(hpms->base,
|
||||||
|
memory_region_size(&hpms->mr),
|
||||||
|
!addr ? NULL : &addr, align,
|
||||||
|
memory_region_size(mr), &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
existing_dimms_capacity = pc_existing_dimms_capacity(&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing_dimms_capacity + memory_region_size(mr) >
|
||||||
|
machine->maxram_size - machine->ram_size) {
|
||||||
|
error_setg(&local_err, "not enough space, currently 0x%" PRIx64
|
||||||
|
" in use of total hot pluggable 0x" RAM_ADDR_FMT,
|
||||||
|
existing_dimms_capacity,
|
||||||
|
machine->maxram_size - machine->ram_size);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_property_set_int(OBJECT(dev), addr, PC_DIMM_ADDR_PROP, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
trace_mhp_pc_dimm_assigned_address(addr);
|
||||||
|
|
||||||
|
slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot = pc_dimm_get_free_slot(slot == PC_DIMM_UNASSIGNED_SLOT ? NULL : &slot,
|
||||||
|
machine->ram_slots, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
object_property_set_int(OBJECT(dev), slot, PC_DIMM_SLOT_PROP, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
trace_mhp_pc_dimm_assigned_slot(slot);
|
||||||
|
|
||||||
|
if (kvm_enabled() && !kvm_has_free_slot(machine)) {
|
||||||
|
error_setg(&local_err, "hypervisor has no free memory slots left");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_add_subregion(&hpms->mr, addr - hpms->base, mr);
|
||||||
|
vmstate_register_ram(mr, dev);
|
||||||
|
numa_set_mem_node_id(addr, memory_region_size(mr), dimm->node);
|
||||||
|
|
||||||
|
out:
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pc_dimm_memory_unplug(DeviceState *dev, MemoryHotplugState *hpms,
|
||||||
|
MemoryRegion *mr)
|
||||||
|
{
|
||||||
|
PCDIMMDevice *dimm = PC_DIMM(dev);
|
||||||
|
|
||||||
|
numa_unset_mem_node_id(dimm->addr, memory_region_size(mr), dimm->node);
|
||||||
|
memory_region_del_subregion(&hpms->mr, mr);
|
||||||
|
vmstate_unregister_ram(mr, dev);
|
||||||
|
}
|
||||||
|
|
||||||
static int pc_existing_dimms_capacity_internal(Object *obj, void *opaque)
|
static int pc_existing_dimms_capacity_internal(Object *obj, void *opaque)
|
||||||
{
|
{
|
||||||
pc_dimms_capacity *cap = opaque;
|
pc_dimms_capacity *cap = opaque;
|
||||||
|
|||||||
@@ -48,13 +48,14 @@ static struct
|
|||||||
static void main_cpu_reset(void *opaque)
|
static void main_cpu_reset(void *opaque)
|
||||||
{
|
{
|
||||||
MicroBlazeCPU *cpu = opaque;
|
MicroBlazeCPU *cpu = opaque;
|
||||||
|
CPUState *cs = CPU(cpu);
|
||||||
CPUMBState *env = &cpu->env;
|
CPUMBState *env = &cpu->env;
|
||||||
|
|
||||||
cpu_reset(CPU(cpu));
|
cpu_reset(cs);
|
||||||
env->regs[5] = boot_info.cmdline;
|
env->regs[5] = boot_info.cmdline;
|
||||||
env->regs[6] = boot_info.initrd_start;
|
env->regs[6] = boot_info.initrd_start;
|
||||||
env->regs[7] = boot_info.fdt;
|
env->regs[7] = boot_info.fdt;
|
||||||
env->sregs[SR_PC] = boot_info.bootstrap_pc;
|
cpu_set_pc(cs, boot_info.bootstrap_pc);
|
||||||
if (boot_info.machine_cpu_reset) {
|
if (boot_info.machine_cpu_reset) {
|
||||||
boot_info.machine_cpu_reset(cpu);
|
boot_info.machine_cpu_reset(cpu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,8 +132,6 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
|
|||||||
SysBusDevice *sysbus_dev;
|
SysBusDevice *sysbus_dev;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
d->config[0x3d] = 0x01; // interrupt on pin 1
|
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
|
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
|
|||||||
@@ -185,6 +185,9 @@ e1000_link_up(E1000State *s)
|
|||||||
{
|
{
|
||||||
s->mac_reg[STATUS] |= E1000_STATUS_LU;
|
s->mac_reg[STATUS] |= E1000_STATUS_LU;
|
||||||
s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
|
s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
|
||||||
|
|
||||||
|
/* E1000_STATUS_LU is tested by e1000_can_receive() */
|
||||||
|
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ World *rocker_get_world(Rocker *r, enum rocker_world_type type)
|
|||||||
|
|
||||||
RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
|
RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
RockerSwitch *rocker = g_malloc0(sizeof(*rocker));
|
RockerSwitch *rocker;
|
||||||
Rocker *r;
|
Rocker *r;
|
||||||
|
|
||||||
r = rocker_find(name);
|
r = rocker_find(name);
|
||||||
@@ -106,6 +106,7 @@ RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rocker = g_new0(RockerSwitch, 1);
|
||||||
rocker->name = g_strdup(r->name);
|
rocker->name = g_strdup(r->name);
|
||||||
rocker->id = r->switch_id;
|
rocker->id = r->switch_id;
|
||||||
rocker->ports = r->fp_ports;
|
rocker->ports = r->fp_ports;
|
||||||
@@ -192,11 +193,13 @@ static int tx_consume(Rocker *r, DescInfo *info)
|
|||||||
if (!tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
|
if (!tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
|
||||||
return -ROCKER_EINVAL;
|
return -ROCKER_EINVAL;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case ROCKER_TX_OFFLOAD_TSO:
|
case ROCKER_TX_OFFLOAD_TSO:
|
||||||
if (!tlvs[ROCKER_TLV_TX_TSO_MSS] ||
|
if (!tlvs[ROCKER_TLV_TX_TSO_MSS] ||
|
||||||
!tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
|
!tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
|
||||||
return -ROCKER_EINVAL;
|
return -ROCKER_EINVAL;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
|
if (tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
|
||||||
@@ -600,7 +603,7 @@ static DescRing *rocker_get_rx_ring_by_pport(Rocker *r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int rx_produce(World *world, uint32_t pport,
|
int rx_produce(World *world, uint32_t pport,
|
||||||
const struct iovec *iov, int iovcnt)
|
const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu)
|
||||||
{
|
{
|
||||||
Rocker *r = world_rocker(world);
|
Rocker *r = world_rocker(world);
|
||||||
PCIDevice *dev = (PCIDevice *)r;
|
PCIDevice *dev = (PCIDevice *)r;
|
||||||
@@ -643,6 +646,10 @@ int rx_produce(World *world, uint32_t pport,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (copy_to_cpu) {
|
||||||
|
rx_flags |= ROCKER_RX_FLAGS_FWD_OFFLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX calc rx flags/csum */
|
/* XXX calc rx flags/csum */
|
||||||
|
|
||||||
tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* flags */
|
tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* flags */
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up);
|
|||||||
int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
|
int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
|
||||||
uint16_t vlan_id);
|
uint16_t vlan_id);
|
||||||
int rx_produce(World *world, uint32_t pport,
|
int rx_produce(World *world, uint32_t pport,
|
||||||
const struct iovec *iov, int iovcnt);
|
const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu);
|
||||||
int rocker_port_eg(Rocker *r, uint32_t pport,
|
int rocker_port_eg(Rocker *r, uint32_t pport,
|
||||||
const struct iovec *iov, int iovcnt);
|
const struct iovec *iov, int iovcnt);
|
||||||
|
|
||||||
|
|||||||
@@ -125,18 +125,21 @@ int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt)
|
|||||||
return ROCKER_OK;
|
return ROCKER_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fp_port_can_receive(NetClientState *nc)
|
|
||||||
{
|
|
||||||
FpPort *port = qemu_get_nic_opaque(nc);
|
|
||||||
|
|
||||||
return port->enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t fp_port_receive_iov(NetClientState *nc, const struct iovec *iov,
|
static ssize_t fp_port_receive_iov(NetClientState *nc, const struct iovec *iov,
|
||||||
int iovcnt)
|
int iovcnt)
|
||||||
{
|
{
|
||||||
FpPort *port = qemu_get_nic_opaque(nc);
|
FpPort *port = qemu_get_nic_opaque(nc);
|
||||||
|
|
||||||
|
/* If the port is disabled, we want to drop this pkt
|
||||||
|
* now rather than queing it for later. We don't want
|
||||||
|
* any stale pkts getting into the device when the port
|
||||||
|
* transitions to enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!port->enabled) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return world_ingress(port->world, port->pport, iov, iovcnt);
|
return world_ingress(port->world, port->pport, iov, iovcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +168,6 @@ static void fp_port_set_link_status(NetClientState *nc)
|
|||||||
static NetClientInfo fp_port_info = {
|
static NetClientInfo fp_port_info = {
|
||||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||||
.size = sizeof(NICState),
|
.size = sizeof(NICState),
|
||||||
.can_receive = fp_port_can_receive,
|
|
||||||
.receive = fp_port_receive,
|
.receive = fp_port_receive,
|
||||||
.receive_iov = fp_port_receive_iov,
|
.receive_iov = fp_port_receive_iov,
|
||||||
.cleanup = fp_port_cleanup,
|
.cleanup = fp_port_cleanup,
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ enum {
|
|||||||
#define ROCKER_RX_FLAGS_TCP (1 << 5)
|
#define ROCKER_RX_FLAGS_TCP (1 << 5)
|
||||||
#define ROCKER_RX_FLAGS_UDP (1 << 6)
|
#define ROCKER_RX_FLAGS_UDP (1 << 6)
|
||||||
#define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD (1 << 7)
|
#define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD (1 << 7)
|
||||||
|
#define ROCKER_RX_FLAGS_FWD_OFFLOAD (1 << 8)
|
||||||
|
|
||||||
/* Tx msg */
|
/* Tx msg */
|
||||||
enum {
|
enum {
|
||||||
|
|||||||
@@ -825,6 +825,8 @@ static OfDpaGroup *of_dpa_group_alloc(uint32_t id)
|
|||||||
static void of_dpa_output_l2_interface(OfDpaFlowContext *fc,
|
static void of_dpa_output_l2_interface(OfDpaFlowContext *fc,
|
||||||
OfDpaGroup *group)
|
OfDpaGroup *group)
|
||||||
{
|
{
|
||||||
|
uint8_t copy_to_cpu = fc->action_set.apply.copy_to_cpu;
|
||||||
|
|
||||||
if (group->l2_interface.pop_vlan) {
|
if (group->l2_interface.pop_vlan) {
|
||||||
of_dpa_flow_pkt_strip_vlan(fc);
|
of_dpa_flow_pkt_strip_vlan(fc);
|
||||||
}
|
}
|
||||||
@@ -837,7 +839,8 @@ static void of_dpa_output_l2_interface(OfDpaFlowContext *fc,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (group->l2_interface.out_pport == 0) {
|
if (group->l2_interface.out_pport == 0) {
|
||||||
rx_produce(fc->of_dpa->world, fc->in_pport, fc->iov, fc->iovcnt);
|
rx_produce(fc->of_dpa->world, fc->in_pport, fc->iov, fc->iovcnt,
|
||||||
|
copy_to_cpu);
|
||||||
} else if (group->l2_interface.out_pport != fc->in_pport) {
|
} else if (group->l2_interface.out_pport != fc->in_pport) {
|
||||||
rocker_port_eg(world_rocker(fc->of_dpa->world),
|
rocker_port_eg(world_rocker(fc->of_dpa->world),
|
||||||
group->l2_interface.out_pport,
|
group->l2_interface.out_pport,
|
||||||
@@ -2525,7 +2528,6 @@ static void of_dpa_group_fill(void *key, void *value, void *user_data)
|
|||||||
ngroup->has_set_vlan_id = true;
|
ngroup->has_set_vlan_id = true;
|
||||||
ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id);
|
ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) {
|
if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) {
|
||||||
ngroup->has_set_eth_src = true;
|
ngroup->has_set_eth_src = true;
|
||||||
ngroup->set_eth_src =
|
ngroup->set_eth_src =
|
||||||
@@ -2536,6 +2538,7 @@ static void of_dpa_group_fill(void *key, void *value, void *user_data)
|
|||||||
ngroup->set_eth_dst =
|
ngroup->set_eth_dst =
|
||||||
qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a);
|
qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
|
case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
|
||||||
case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
|
case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
|
||||||
ngroup->has_vlan_id = true;
|
ngroup->has_vlan_id = true;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ ssize_t world_ingress(World *world, uint32_t pport,
|
|||||||
return world->ops->ig(world, pport, iov, iovcnt);
|
return world->ops->ig(world, pport, iov, iovcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return iov_size(iov, iovcnt);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int world_do_cmd(World *world, DescInfo *info,
|
int world_do_cmd(World *world, DescInfo *info,
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
|
static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
|
||||||
sPAPREnvironment *spapr,
|
sPAPRMachineState *spapr,
|
||||||
target_ulong opcode,
|
target_ulong opcode,
|
||||||
target_ulong *args)
|
target_ulong *args)
|
||||||
{
|
{
|
||||||
@@ -349,7 +349,8 @@ static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_free_logical_lan(PowerPCCPU *cpu,
|
||||||
|
sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
target_ulong reg = args[0];
|
target_ulong reg = args[0];
|
||||||
@@ -371,7 +372,7 @@ static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
|
static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
|
||||||
sPAPREnvironment *spapr,
|
sPAPRMachineState *spapr,
|
||||||
target_ulong opcode,
|
target_ulong opcode,
|
||||||
target_ulong *args)
|
target_ulong *args)
|
||||||
{
|
{
|
||||||
@@ -421,7 +422,8 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
|
|||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_send_logical_lan(PowerPCCPU *cpu,
|
||||||
|
sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
target_ulong reg = args[0];
|
target_ulong reg = args[0];
|
||||||
@@ -490,7 +492,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
target_ulong reg = args[0];
|
target_ulong reg = args[0];
|
||||||
|
|||||||
@@ -466,7 +466,6 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!get_vhost_net(nc->peer)) {
|
if (!get_vhost_net(nc->peer)) {
|
||||||
virtio_add_feature(&features, VIRTIO_F_VERSION_1);
|
|
||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
return vhost_net_get_features(get_vhost_net(nc->peer), features);
|
return vhost_net_get_features(get_vhost_net(nc->peer), features);
|
||||||
|
|||||||
@@ -1879,6 +1879,12 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s->peer_has_vhdr) {
|
||||||
|
vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf);
|
||||||
|
buf += sizeof(struct virtio_net_hdr);
|
||||||
|
size -= sizeof(struct virtio_net_hdr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Pad to minimum Ethernet frame length */
|
/* Pad to minimum Ethernet frame length */
|
||||||
if (size < sizeof(min_buf)) {
|
if (size < sizeof(min_buf)) {
|
||||||
memcpy(min_buf, buf, size);
|
memcpy(min_buf, buf, size);
|
||||||
@@ -1887,12 +1893,6 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||||||
size = sizeof(min_buf);
|
size = sizeof(min_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->peer_has_vhdr) {
|
|
||||||
vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf);
|
|
||||||
buf += sizeof(struct virtio_net_hdr);
|
|
||||||
size -= sizeof(struct virtio_net_hdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
vmxnet_rx_pkt_set_packet_type(s->rx_pkt,
|
vmxnet_rx_pkt_set_packet_type(s->rx_pkt,
|
||||||
get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
|
get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ typedef struct sPAPRNVRAM {
|
|||||||
#define DEFAULT_NVRAM_SIZE 65536
|
#define DEFAULT_NVRAM_SIZE 65536
|
||||||
#define MAX_NVRAM_SIZE 1048576
|
#define MAX_NVRAM_SIZE 1048576
|
||||||
|
|
||||||
static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t token, uint32_t nargs,
|
uint32_t token, uint32_t nargs,
|
||||||
target_ulong args,
|
target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
@@ -86,7 +86,7 @@ static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
rtas_st(rets, 1, len);
|
rtas_st(rets, 1, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t token, uint32_t nargs,
|
uint32_t token, uint32_t nargs,
|
||||||
target_ulong args,
|
target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
|
|||||||
PCI_EXP_LNK_LS_25);
|
PCI_EXP_LNK_LS_25);
|
||||||
|
|
||||||
pci_set_word(exp_cap + PCI_EXP_LNKSTA,
|
pci_set_word(exp_cap + PCI_EXP_LNKSTA,
|
||||||
PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
|
PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25 |PCI_EXP_LNKSTA_DLLLA);
|
||||||
|
|
||||||
pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
|
pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
|
||||||
PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
|
PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ static void ppc_core99_reset(void *opaque)
|
|||||||
static void ppc_core99_init(MachineState *machine)
|
static void ppc_core99_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = machine->ram_size;
|
ram_addr_t ram_size = machine->ram_size;
|
||||||
const char *cpu_model = machine->cpu_model;
|
|
||||||
const char *kernel_filename = machine->kernel_filename;
|
const char *kernel_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||||
const char *initrd_filename = machine->initrd_filename;
|
const char *initrd_filename = machine->initrd_filename;
|
||||||
@@ -182,14 +181,15 @@ static void ppc_core99_init(MachineState *machine)
|
|||||||
linux_boot = (kernel_filename != NULL);
|
linux_boot = (kernel_filename != NULL);
|
||||||
|
|
||||||
/* init CPUs */
|
/* init CPUs */
|
||||||
if (cpu_model == NULL)
|
if (machine->cpu_model == NULL) {
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
cpu_model = "970fx";
|
machine->cpu_model = "970fx";
|
||||||
#else
|
#else
|
||||||
cpu_model = "G4";
|
machine->cpu_model = "G4";
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
for (i = 0; i < smp_cpus; i++) {
|
for (i = 0; i < smp_cpus; i++) {
|
||||||
cpu = cpu_ppc_init(cpu_model);
|
cpu = cpu_ppc_init(machine->cpu_model);
|
||||||
if (cpu == NULL) {
|
if (cpu == NULL) {
|
||||||
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
|
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ static void ppc_heathrow_reset(void *opaque)
|
|||||||
static void ppc_heathrow_init(MachineState *machine)
|
static void ppc_heathrow_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = machine->ram_size;
|
ram_addr_t ram_size = machine->ram_size;
|
||||||
const char *cpu_model = machine->cpu_model;
|
|
||||||
const char *kernel_filename = machine->kernel_filename;
|
const char *kernel_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||||
const char *initrd_filename = machine->initrd_filename;
|
const char *initrd_filename = machine->initrd_filename;
|
||||||
@@ -107,10 +106,10 @@ static void ppc_heathrow_init(MachineState *machine)
|
|||||||
linux_boot = (kernel_filename != NULL);
|
linux_boot = (kernel_filename != NULL);
|
||||||
|
|
||||||
/* init CPUs */
|
/* init CPUs */
|
||||||
if (cpu_model == NULL)
|
if (machine->cpu_model == NULL)
|
||||||
cpu_model = "G3";
|
machine->cpu_model = "G3";
|
||||||
for (i = 0; i < smp_cpus; i++) {
|
for (i = 0; i < smp_cpus; i++) {
|
||||||
cpu = cpu_ppc_init(cpu_model);
|
cpu = cpu_ppc_init(machine->cpu_model);
|
||||||
if (cpu == NULL) {
|
if (cpu == NULL) {
|
||||||
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
|
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
@@ -159,7 +159,6 @@ static void main_cpu_reset(void *opaque)
|
|||||||
static void bamboo_init(MachineState *machine)
|
static void bamboo_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = machine->ram_size;
|
ram_addr_t ram_size = machine->ram_size;
|
||||||
const char *cpu_model = machine->cpu_model;
|
|
||||||
const char *kernel_filename = machine->kernel_filename;
|
const char *kernel_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||||
const char *initrd_filename = machine->initrd_filename;
|
const char *initrd_filename = machine->initrd_filename;
|
||||||
@@ -184,10 +183,10 @@ static void bamboo_init(MachineState *machine)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Setup CPU. */
|
/* Setup CPU. */
|
||||||
if (cpu_model == NULL) {
|
if (machine->cpu_model == NULL) {
|
||||||
cpu_model = "440EP";
|
machine->cpu_model = "440EP";
|
||||||
}
|
}
|
||||||
cpu = cpu_ppc_init(cpu_model);
|
cpu = cpu_ppc_init(machine->cpu_model);
|
||||||
if (cpu == NULL) {
|
if (cpu == NULL) {
|
||||||
fprintf(stderr, "Unable to initialize CPU!\n");
|
fprintf(stderr, "Unable to initialize CPU!\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
@@ -506,7 +506,6 @@ static int PPC_NVRAM_set_params (Nvram *nvram, uint16_t NVRAM_size,
|
|||||||
static void ppc_prep_init(MachineState *machine)
|
static void ppc_prep_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = machine->ram_size;
|
ram_addr_t ram_size = machine->ram_size;
|
||||||
const char *cpu_model = machine->cpu_model;
|
|
||||||
const char *kernel_filename = machine->kernel_filename;
|
const char *kernel_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||||
const char *initrd_filename = machine->initrd_filename;
|
const char *initrd_filename = machine->initrd_filename;
|
||||||
@@ -536,10 +535,10 @@ static void ppc_prep_init(MachineState *machine)
|
|||||||
linux_boot = (kernel_filename != NULL);
|
linux_boot = (kernel_filename != NULL);
|
||||||
|
|
||||||
/* init CPUs */
|
/* init CPUs */
|
||||||
if (cpu_model == NULL)
|
if (machine->cpu_model == NULL)
|
||||||
cpu_model = "602";
|
machine->cpu_model = "602";
|
||||||
for (i = 0; i < smp_cpus; i++) {
|
for (i = 0; i < smp_cpus; i++) {
|
||||||
cpu = cpu_ppc_init(cpu_model);
|
cpu = cpu_ppc_init(machine->cpu_model);
|
||||||
if (cpu == NULL) {
|
if (cpu == NULL) {
|
||||||
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
|
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
453
hw/ppc/spapr.c
453
hw/ppc/spapr.c
@@ -34,6 +34,7 @@
|
|||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "kvm_ppc.h"
|
#include "kvm_ppc.h"
|
||||||
|
#include "migration/migration.h"
|
||||||
#include "mmu-hash64.h"
|
#include "mmu-hash64.h"
|
||||||
#include "qom/cpu.h"
|
#include "qom/cpu.h"
|
||||||
|
|
||||||
@@ -90,25 +91,6 @@
|
|||||||
|
|
||||||
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
||||||
|
|
||||||
typedef struct sPAPRMachineState sPAPRMachineState;
|
|
||||||
|
|
||||||
#define TYPE_SPAPR_MACHINE "spapr-machine"
|
|
||||||
#define SPAPR_MACHINE(obj) \
|
|
||||||
OBJECT_CHECK(sPAPRMachineState, (obj), TYPE_SPAPR_MACHINE)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sPAPRMachineState:
|
|
||||||
*/
|
|
||||||
struct sPAPRMachineState {
|
|
||||||
/*< private >*/
|
|
||||||
MachineState parent_obj;
|
|
||||||
|
|
||||||
/*< public >*/
|
|
||||||
char *kvm_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
sPAPREnvironment *spapr;
|
|
||||||
|
|
||||||
static XICSState *try_create_xics(const char *type, int nr_servers,
|
static XICSState *try_create_xics(const char *type, int nr_servers,
|
||||||
int nr_irqs, Error **errp)
|
int nr_irqs, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -184,7 +166,28 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, CPUState *cs)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
|
int index = ppc_get_vcpu_dt_id(cpu);
|
||||||
|
uint32_t associativity[] = {cpu_to_be32(0x5),
|
||||||
|
cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(0x0),
|
||||||
|
cpu_to_be32(cs->numa_node),
|
||||||
|
cpu_to_be32(index)};
|
||||||
|
|
||||||
|
/* Advertise NUMA via ibm,associativity */
|
||||||
|
if (nb_numa_nodes > 1) {
|
||||||
|
ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
|
||||||
|
sizeof(associativity));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
|
||||||
{
|
{
|
||||||
int ret = 0, offset, cpus_offset;
|
int ret = 0, offset, cpus_offset;
|
||||||
CPUState *cs;
|
CPUState *cs;
|
||||||
@@ -196,12 +199,6 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
|||||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||||
int index = ppc_get_vcpu_dt_id(cpu);
|
int index = ppc_get_vcpu_dt_id(cpu);
|
||||||
uint32_t associativity[] = {cpu_to_be32(0x5),
|
|
||||||
cpu_to_be32(0x0),
|
|
||||||
cpu_to_be32(0x0),
|
|
||||||
cpu_to_be32(0x0),
|
|
||||||
cpu_to_be32(cs->numa_node),
|
|
||||||
cpu_to_be32(index)};
|
|
||||||
|
|
||||||
if ((index % smt) != 0) {
|
if ((index % smt) != 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -225,20 +222,17 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nb_numa_nodes > 1) {
|
|
||||||
ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
|
|
||||||
sizeof(associativity));
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = fdt_setprop(fdt, offset, "ibm,pft-size",
|
ret = fdt_setprop(fdt, offset, "ibm,pft-size",
|
||||||
pft_size_prop, sizeof(pft_size_prop));
|
pft_size_prop, sizeof(pft_size_prop));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = spapr_fixup_cpu_numa_dt(fdt, offset, cs);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
|
ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
|
||||||
ppc_get_compat_smt_threads(cpu));
|
ppc_get_compat_smt_threads(cpu));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -284,15 +278,18 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
|
|||||||
|
|
||||||
static hwaddr spapr_node0_size(void)
|
static hwaddr spapr_node0_size(void)
|
||||||
{
|
{
|
||||||
|
MachineState *machine = MACHINE(qdev_get_machine());
|
||||||
|
|
||||||
if (nb_numa_nodes) {
|
if (nb_numa_nodes) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < nb_numa_nodes; ++i) {
|
for (i = 0; i < nb_numa_nodes; ++i) {
|
||||||
if (numa_info[i].node_mem) {
|
if (numa_info[i].node_mem) {
|
||||||
return MIN(pow2floor(numa_info[i].node_mem), ram_size);
|
return MIN(pow2floor(numa_info[i].node_mem),
|
||||||
|
machine->ram_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ram_size;
|
return machine->ram_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _FDT(exp) \
|
#define _FDT(exp) \
|
||||||
@@ -318,18 +315,13 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
|||||||
uint32_t epow_irq)
|
uint32_t epow_irq)
|
||||||
{
|
{
|
||||||
void *fdt;
|
void *fdt;
|
||||||
CPUState *cs;
|
|
||||||
uint32_t start_prop = cpu_to_be32(initrd_base);
|
uint32_t start_prop = cpu_to_be32(initrd_base);
|
||||||
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
|
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
|
||||||
GString *hypertas = g_string_sized_new(256);
|
GString *hypertas = g_string_sized_new(256);
|
||||||
GString *qemu_hypertas = g_string_sized_new(256);
|
GString *qemu_hypertas = g_string_sized_new(256);
|
||||||
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
|
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
|
||||||
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
|
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(max_cpus)};
|
||||||
int smt = kvmppc_smt_threads();
|
|
||||||
unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
|
unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
|
||||||
QemuOpts *opts = qemu_opts_find(qemu_find_opts("smp-opts"), NULL);
|
|
||||||
unsigned sockets = opts ? qemu_opt_get_number(opts, "sockets", 0) : 0;
|
|
||||||
uint32_t cpus_per_socket = sockets ? (smp_cpus / sockets) : 1;
|
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
add_str(hypertas, "hcall-pft");
|
add_str(hypertas, "hcall-pft");
|
||||||
@@ -415,107 +407,6 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
|||||||
|
|
||||||
_FDT((fdt_end_node(fdt)));
|
_FDT((fdt_end_node(fdt)));
|
||||||
|
|
||||||
/* cpus */
|
|
||||||
_FDT((fdt_begin_node(fdt, "cpus")));
|
|
||||||
|
|
||||||
_FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
|
|
||||||
_FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
|
|
||||||
|
|
||||||
CPU_FOREACH(cs) {
|
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
|
||||||
CPUPPCState *env = &cpu->env;
|
|
||||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
|
||||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
|
||||||
int index = ppc_get_vcpu_dt_id(cpu);
|
|
||||||
char *nodename;
|
|
||||||
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
|
|
||||||
0xffffffff, 0xffffffff};
|
|
||||||
uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
|
|
||||||
uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
|
|
||||||
uint32_t page_sizes_prop[64];
|
|
||||||
size_t page_sizes_prop_size;
|
|
||||||
|
|
||||||
if ((index % smt) != 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
|
|
||||||
|
|
||||||
_FDT((fdt_begin_node(fdt, nodename)));
|
|
||||||
|
|
||||||
g_free(nodename);
|
|
||||||
|
|
||||||
_FDT((fdt_property_cell(fdt, "reg", index)));
|
|
||||||
_FDT((fdt_property_string(fdt, "device_type", "cpu")));
|
|
||||||
|
|
||||||
_FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
|
|
||||||
_FDT((fdt_property_cell(fdt, "d-cache-block-size",
|
|
||||||
env->dcache_line_size)));
|
|
||||||
_FDT((fdt_property_cell(fdt, "d-cache-line-size",
|
|
||||||
env->dcache_line_size)));
|
|
||||||
_FDT((fdt_property_cell(fdt, "i-cache-block-size",
|
|
||||||
env->icache_line_size)));
|
|
||||||
_FDT((fdt_property_cell(fdt, "i-cache-line-size",
|
|
||||||
env->icache_line_size)));
|
|
||||||
|
|
||||||
if (pcc->l1_dcache_size) {
|
|
||||||
_FDT((fdt_property_cell(fdt, "d-cache-size", pcc->l1_dcache_size)));
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n");
|
|
||||||
}
|
|
||||||
if (pcc->l1_icache_size) {
|
|
||||||
_FDT((fdt_property_cell(fdt, "i-cache-size", pcc->l1_icache_size)));
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
_FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq)));
|
|
||||||
_FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq)));
|
|
||||||
_FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
|
|
||||||
_FDT((fdt_property_string(fdt, "status", "okay")));
|
|
||||||
_FDT((fdt_property(fdt, "64-bit", NULL, 0)));
|
|
||||||
|
|
||||||
if (env->spr_cb[SPR_PURR].oea_read) {
|
|
||||||
_FDT((fdt_property(fdt, "ibm,purr", NULL, 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env->mmu_model & POWERPC_MMU_1TSEG) {
|
|
||||||
_FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
|
|
||||||
segs, sizeof(segs))));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Advertise VMX/VSX (vector extensions) if available
|
|
||||||
* 0 / no property == no vector extensions
|
|
||||||
* 1 == VMX / Altivec available
|
|
||||||
* 2 == VSX available */
|
|
||||||
if (env->insns_flags & PPC_ALTIVEC) {
|
|
||||||
uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
|
|
||||||
|
|
||||||
_FDT((fdt_property_cell(fdt, "ibm,vmx", vmx)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Advertise DFP (Decimal Floating Point) if available
|
|
||||||
* 0 / no property == no DFP
|
|
||||||
* 1 == DFP available */
|
|
||||||
if (env->insns_flags2 & PPC2_DFP) {
|
|
||||||
_FDT((fdt_property_cell(fdt, "ibm,dfp", 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop,
|
|
||||||
sizeof(page_sizes_prop));
|
|
||||||
if (page_sizes_prop_size) {
|
|
||||||
_FDT((fdt_property(fdt, "ibm,segment-page-sizes",
|
|
||||||
page_sizes_prop, page_sizes_prop_size)));
|
|
||||||
}
|
|
||||||
|
|
||||||
_FDT((fdt_property_cell(fdt, "ibm,chip-id",
|
|
||||||
cs->cpu_index / cpus_per_socket)));
|
|
||||||
|
|
||||||
_FDT((fdt_end_node(fdt)));
|
|
||||||
}
|
|
||||||
|
|
||||||
_FDT((fdt_end_node(fdt)));
|
|
||||||
|
|
||||||
/* RTAS */
|
/* RTAS */
|
||||||
_FDT((fdt_begin_node(fdt, "rtas")));
|
_FDT((fdt_begin_node(fdt, "rtas")));
|
||||||
|
|
||||||
@@ -604,7 +495,8 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
|||||||
return fdt;
|
return fdt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spapr_h_cas_compose_response(target_ulong addr, target_ulong size)
|
int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
|
||||||
|
target_ulong addr, target_ulong size)
|
||||||
{
|
{
|
||||||
void *fdt, *fdt_skel;
|
void *fdt, *fdt_skel;
|
||||||
sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
|
sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
|
||||||
@@ -665,8 +557,9 @@ static void spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
|
|||||||
sizeof(associativity))));
|
sizeof(associativity))));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
|
static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
|
||||||
{
|
{
|
||||||
|
MachineState *machine = MACHINE(spapr);
|
||||||
hwaddr mem_start, node_size;
|
hwaddr mem_start, node_size;
|
||||||
int i, nb_nodes = nb_numa_nodes;
|
int i, nb_nodes = nb_numa_nodes;
|
||||||
NodeInfo *nodes = numa_info;
|
NodeInfo *nodes = numa_info;
|
||||||
@@ -675,7 +568,7 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
|
|||||||
/* No NUMA nodes, assume there is just one node with whole RAM */
|
/* No NUMA nodes, assume there is just one node with whole RAM */
|
||||||
if (!nb_numa_nodes) {
|
if (!nb_numa_nodes) {
|
||||||
nb_nodes = 1;
|
nb_nodes = 1;
|
||||||
ramnode.node_mem = ram_size;
|
ramnode.node_mem = machine->ram_size;
|
||||||
nodes = &ramnode;
|
nodes = &ramnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,12 +576,12 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
|
|||||||
if (!nodes[i].node_mem) {
|
if (!nodes[i].node_mem) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (mem_start >= ram_size) {
|
if (mem_start >= machine->ram_size) {
|
||||||
node_size = 0;
|
node_size = 0;
|
||||||
} else {
|
} else {
|
||||||
node_size = nodes[i].node_mem;
|
node_size = nodes[i].node_mem;
|
||||||
if (node_size > ram_size - mem_start) {
|
if (node_size > machine->ram_size - mem_start) {
|
||||||
node_size = ram_size - mem_start;
|
node_size = machine->ram_size - mem_start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mem_start) {
|
if (!mem_start) {
|
||||||
@@ -714,7 +607,138 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
|
||||||
|
sPAPRMachineState *spapr)
|
||||||
|
{
|
||||||
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
|
CPUPPCState *env = &cpu->env;
|
||||||
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||||
|
int index = ppc_get_vcpu_dt_id(cpu);
|
||||||
|
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
|
||||||
|
0xffffffff, 0xffffffff};
|
||||||
|
uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
|
||||||
|
uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
|
||||||
|
uint32_t page_sizes_prop[64];
|
||||||
|
size_t page_sizes_prop_size;
|
||||||
|
QemuOpts *opts = qemu_opts_find(qemu_find_opts("smp-opts"), NULL);
|
||||||
|
unsigned sockets = opts ? qemu_opt_get_number(opts, "sockets", 0) : 0;
|
||||||
|
uint32_t cpus_per_socket = sockets ? (smp_cpus / sockets) : 1;
|
||||||
|
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
|
||||||
|
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
|
||||||
|
_FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
|
||||||
|
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
|
||||||
|
env->dcache_line_size)));
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
|
||||||
|
env->dcache_line_size)));
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
|
||||||
|
env->icache_line_size)));
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
|
||||||
|
env->icache_line_size)));
|
||||||
|
|
||||||
|
if (pcc->l1_dcache_size) {
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
|
||||||
|
pcc->l1_dcache_size)));
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n");
|
||||||
|
}
|
||||||
|
if (pcc->l1_icache_size) {
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
|
||||||
|
pcc->l1_icache_size)));
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
|
||||||
|
_FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
|
||||||
|
_FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
|
||||||
|
|
||||||
|
if (env->spr_cb[SPR_PURR].oea_read) {
|
||||||
|
_FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env->mmu_model & POWERPC_MMU_1TSEG) {
|
||||||
|
_FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
|
||||||
|
segs, sizeof(segs))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advertise VMX/VSX (vector extensions) if available
|
||||||
|
* 0 / no property == no vector extensions
|
||||||
|
* 1 == VMX / Altivec available
|
||||||
|
* 2 == VSX available */
|
||||||
|
if (env->insns_flags & PPC_ALTIVEC) {
|
||||||
|
uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
|
||||||
|
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advertise DFP (Decimal Floating Point) if available
|
||||||
|
* 0 / no property == no DFP
|
||||||
|
* 1 == DFP available */
|
||||||
|
if (env->insns_flags2 & PPC2_DFP) {
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop,
|
||||||
|
sizeof(page_sizes_prop));
|
||||||
|
if (page_sizes_prop_size) {
|
||||||
|
_FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
|
||||||
|
page_sizes_prop, page_sizes_prop_size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
|
||||||
|
cs->cpu_index / cpus_per_socket)));
|
||||||
|
|
||||||
|
_FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
|
||||||
|
pft_size_prop, sizeof(pft_size_prop))));
|
||||||
|
|
||||||
|
_FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs));
|
||||||
|
|
||||||
|
_FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
|
||||||
|
ppc_get_compat_smt_threads(cpu)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
|
||||||
|
{
|
||||||
|
CPUState *cs;
|
||||||
|
int cpus_offset;
|
||||||
|
char *nodename;
|
||||||
|
int smt = kvmppc_smt_threads();
|
||||||
|
|
||||||
|
cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
|
||||||
|
_FDT(cpus_offset);
|
||||||
|
_FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
|
||||||
|
_FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We walk the CPUs in reverse order to ensure that CPU DT nodes
|
||||||
|
* created by fdt_add_subnode() end up in the right order in FDT
|
||||||
|
* for the guest kernel the enumerate the CPUs correctly.
|
||||||
|
*/
|
||||||
|
CPU_FOREACH_REVERSE(cs) {
|
||||||
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
|
int index = ppc_get_vcpu_dt_id(cpu);
|
||||||
|
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
if ((index % smt) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
|
||||||
|
offset = fdt_add_subnode(fdt, cpus_offset, nodename);
|
||||||
|
g_free(nodename);
|
||||||
|
_FDT(offset);
|
||||||
|
spapr_populate_cpu_dt(cs, fdt, offset, spapr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spapr_finalize_fdt(sPAPRMachineState *spapr,
|
||||||
hwaddr fdt_addr,
|
hwaddr fdt_addr,
|
||||||
hwaddr rtas_addr,
|
hwaddr rtas_addr,
|
||||||
hwaddr rtas_size)
|
hwaddr rtas_size)
|
||||||
@@ -759,11 +783,8 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
|||||||
fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
|
fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advertise NUMA via ibm,associativity */
|
/* cpus */
|
||||||
ret = spapr_fixup_cpu_dt(fdt, spapr);
|
spapr_populate_cpus_dt_node(fdt, spapr);
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "Couldn't finalize CPU device tree properties\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
bootlist = get_boot_devices_list(&cb, true);
|
bootlist = get_boot_devices_list(&cb, true);
|
||||||
if (cb && bootlist) {
|
if (cb && bootlist) {
|
||||||
@@ -830,7 +851,7 @@ static void emulate_spapr_hypercall(PowerPCCPU *cpu)
|
|||||||
#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
|
#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
|
||||||
#define DIRTY_HPTE(_hpte) ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
|
#define DIRTY_HPTE(_hpte) ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
|
||||||
|
|
||||||
static void spapr_reset_htab(sPAPREnvironment *spapr)
|
static void spapr_reset_htab(sPAPRMachineState *spapr)
|
||||||
{
|
{
|
||||||
long shift;
|
long shift;
|
||||||
int index;
|
int index;
|
||||||
@@ -892,7 +913,7 @@ static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
|||||||
* A guest reset will cause spapr->htab_fd to become stale if being used.
|
* A guest reset will cause spapr->htab_fd to become stale if being used.
|
||||||
* Reopen the file descriptor to make sure the whole HTAB is properly read.
|
* Reopen the file descriptor to make sure the whole HTAB is properly read.
|
||||||
*/
|
*/
|
||||||
static int spapr_check_htab_fd(sPAPREnvironment *spapr)
|
static int spapr_check_htab_fd(sPAPRMachineState *spapr)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
@@ -912,6 +933,7 @@ static int spapr_check_htab_fd(sPAPREnvironment *spapr)
|
|||||||
|
|
||||||
static void ppc_spapr_reset(void)
|
static void ppc_spapr_reset(void)
|
||||||
{
|
{
|
||||||
|
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||||
PowerPCCPU *first_ppc_cpu;
|
PowerPCCPU *first_ppc_cpu;
|
||||||
uint32_t rtas_limit;
|
uint32_t rtas_limit;
|
||||||
|
|
||||||
@@ -945,12 +967,13 @@ static void ppc_spapr_reset(void)
|
|||||||
first_ppc_cpu->env.gpr[3] = spapr->fdt_addr;
|
first_ppc_cpu->env.gpr[3] = spapr->fdt_addr;
|
||||||
first_ppc_cpu->env.gpr[5] = 0;
|
first_ppc_cpu->env.gpr[5] = 0;
|
||||||
first_cpu->halted = 0;
|
first_cpu->halted = 0;
|
||||||
first_ppc_cpu->env.nip = spapr->entry_point;
|
first_ppc_cpu->env.nip = SPAPR_ENTRY_POINT;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_cpu_reset(void *opaque)
|
static void spapr_cpu_reset(void *opaque)
|
||||||
{
|
{
|
||||||
|
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||||
PowerPCCPU *cpu = opaque;
|
PowerPCCPU *cpu = opaque;
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
@@ -979,12 +1002,12 @@ static void spapr_cpu_reset(void *opaque)
|
|||||||
* We have 8 hpte per group, and each hpte is 16 bytes.
|
* We have 8 hpte per group, and each hpte is 16 bytes.
|
||||||
* ie have 128 bytes per hpte entry.
|
* ie have 128 bytes per hpte entry.
|
||||||
*/
|
*/
|
||||||
env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1;
|
env->htab_mask = (1ULL << (spapr->htab_shift - 7)) - 1;
|
||||||
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
|
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
|
||||||
(spapr->htab_shift - 18);
|
(spapr->htab_shift - 18);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_create_nvram(sPAPREnvironment *spapr)
|
static void spapr_create_nvram(sPAPRMachineState *spapr)
|
||||||
{
|
{
|
||||||
DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
|
DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
|
||||||
DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
|
DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||||
@@ -998,7 +1021,7 @@ static void spapr_create_nvram(sPAPREnvironment *spapr)
|
|||||||
spapr->nvram = (struct sPAPRNVRAM *)dev;
|
spapr->nvram = (struct sPAPRNVRAM *)dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_rtc_create(sPAPREnvironment *spapr)
|
static void spapr_rtc_create(sPAPRMachineState *spapr)
|
||||||
{
|
{
|
||||||
DeviceState *dev = qdev_create(NULL, TYPE_SPAPR_RTC);
|
DeviceState *dev = qdev_create(NULL, TYPE_SPAPR_RTC);
|
||||||
|
|
||||||
@@ -1028,7 +1051,7 @@ static int spapr_vga_init(PCIBus *pci_bus)
|
|||||||
|
|
||||||
static int spapr_post_load(void *opaque, int version_id)
|
static int spapr_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
|
sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/* In earlier versions, there was no separate qdev for the PAPR
|
/* In earlier versions, there was no separate qdev for the PAPR
|
||||||
@@ -1057,16 +1080,16 @@ static const VMStateDescription vmstate_spapr = {
|
|||||||
VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
|
VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
|
||||||
|
|
||||||
/* RTC offset */
|
/* RTC offset */
|
||||||
VMSTATE_UINT64_TEST(rtc_offset, sPAPREnvironment, version_before_3),
|
VMSTATE_UINT64_TEST(rtc_offset, sPAPRMachineState, version_before_3),
|
||||||
|
|
||||||
VMSTATE_PPC_TIMEBASE_V(tb, sPAPREnvironment, 2),
|
VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int htab_save_setup(QEMUFile *f, void *opaque)
|
static int htab_save_setup(QEMUFile *f, void *opaque)
|
||||||
{
|
{
|
||||||
sPAPREnvironment *spapr = opaque;
|
sPAPRMachineState *spapr = opaque;
|
||||||
|
|
||||||
/* "Iteration" header */
|
/* "Iteration" header */
|
||||||
qemu_put_be32(f, spapr->htab_shift);
|
qemu_put_be32(f, spapr->htab_shift);
|
||||||
@@ -1090,7 +1113,7 @@ static int htab_save_setup(QEMUFile *f, void *opaque)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
|
||||||
int64_t max_ns)
|
int64_t max_ns)
|
||||||
{
|
{
|
||||||
int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
|
int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
|
||||||
@@ -1140,7 +1163,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
|||||||
spapr->htab_save_index = index;
|
spapr->htab_save_index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
|
||||||
int64_t max_ns)
|
int64_t max_ns)
|
||||||
{
|
{
|
||||||
bool final = max_ns < 0;
|
bool final = max_ns < 0;
|
||||||
@@ -1222,7 +1245,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
|
|||||||
|
|
||||||
static int htab_save_iterate(QEMUFile *f, void *opaque)
|
static int htab_save_iterate(QEMUFile *f, void *opaque)
|
||||||
{
|
{
|
||||||
sPAPREnvironment *spapr = opaque;
|
sPAPRMachineState *spapr = opaque;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/* Iteration header */
|
/* Iteration header */
|
||||||
@@ -1257,7 +1280,7 @@ static int htab_save_iterate(QEMUFile *f, void *opaque)
|
|||||||
|
|
||||||
static int htab_save_complete(QEMUFile *f, void *opaque)
|
static int htab_save_complete(QEMUFile *f, void *opaque)
|
||||||
{
|
{
|
||||||
sPAPREnvironment *spapr = opaque;
|
sPAPRMachineState *spapr = opaque;
|
||||||
|
|
||||||
/* Iteration header */
|
/* Iteration header */
|
||||||
qemu_put_be32(f, 0);
|
qemu_put_be32(f, 0);
|
||||||
@@ -1292,7 +1315,7 @@ static int htab_save_complete(QEMUFile *f, void *opaque)
|
|||||||
|
|
||||||
static int htab_load(QEMUFile *f, void *opaque, int version_id)
|
static int htab_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
sPAPREnvironment *spapr = opaque;
|
sPAPRMachineState *spapr = opaque;
|
||||||
uint32_t section_hdr;
|
uint32_t section_hdr;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
|
||||||
@@ -1386,16 +1409,42 @@ static void spapr_boot_set(void *opaque, const char *boot_device,
|
|||||||
machine->boot_order = g_strdup(boot_device);
|
machine->boot_order = g_strdup(boot_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu)
|
||||||
|
{
|
||||||
|
CPUPPCState *env = &cpu->env;
|
||||||
|
|
||||||
|
/* Set time-base frequency to 512 MHz */
|
||||||
|
cpu_ppc_tb_init(env, TIMEBASE_FREQ);
|
||||||
|
|
||||||
|
/* PAPR always has exception vectors in RAM not ROM. To ensure this,
|
||||||
|
* MSR[IP] should never be set.
|
||||||
|
*/
|
||||||
|
env->msr_mask &= ~(1 << 6);
|
||||||
|
|
||||||
|
/* Tell KVM that we're in PAPR mode */
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
kvmppc_set_papr(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu->max_compat) {
|
||||||
|
if (ppc_set_compat(cpu, cpu->max_compat) < 0) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xics_cpu_setup(spapr->icp, cpu);
|
||||||
|
|
||||||
|
qemu_register_reset(spapr_cpu_reset, cpu);
|
||||||
|
}
|
||||||
|
|
||||||
/* pSeries LPAR / sPAPR hardware init */
|
/* pSeries LPAR / sPAPR hardware init */
|
||||||
static void ppc_spapr_init(MachineState *machine)
|
static void ppc_spapr_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = machine->ram_size;
|
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
|
||||||
const char *cpu_model = machine->cpu_model;
|
|
||||||
const char *kernel_filename = machine->kernel_filename;
|
const char *kernel_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||||
const char *initrd_filename = machine->initrd_filename;
|
const char *initrd_filename = machine->initrd_filename;
|
||||||
PowerPCCPU *cpu;
|
PowerPCCPU *cpu;
|
||||||
CPUPPCState *env;
|
|
||||||
PCIHostState *phb;
|
PCIHostState *phb;
|
||||||
int i;
|
int i;
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
@@ -1412,7 +1461,6 @@ static void ppc_spapr_init(MachineState *machine)
|
|||||||
|
|
||||||
msi_supported = true;
|
msi_supported = true;
|
||||||
|
|
||||||
spapr = g_malloc0(sizeof(*spapr));
|
|
||||||
QLIST_INIT(&spapr->phbs);
|
QLIST_INIT(&spapr->phbs);
|
||||||
|
|
||||||
cpu_ppc_hypercall = emulate_spapr_hypercall;
|
cpu_ppc_hypercall = emulate_spapr_hypercall;
|
||||||
@@ -1459,7 +1507,7 @@ static void ppc_spapr_init(MachineState *machine)
|
|||||||
* more than needed for the Linux guests we support. */
|
* more than needed for the Linux guests we support. */
|
||||||
spapr->htab_shift = 18; /* Minimum architected size */
|
spapr->htab_shift = 18; /* Minimum architected size */
|
||||||
while (spapr->htab_shift <= 46) {
|
while (spapr->htab_shift <= 46) {
|
||||||
if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) {
|
if ((1ULL << (spapr->htab_shift + 7)) >= machine->ram_size) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
spapr->htab_shift++;
|
spapr->htab_shift++;
|
||||||
@@ -1467,43 +1515,21 @@ static void ppc_spapr_init(MachineState *machine)
|
|||||||
|
|
||||||
/* Set up Interrupt Controller before we create the VCPUs */
|
/* Set up Interrupt Controller before we create the VCPUs */
|
||||||
spapr->icp = xics_system_init(machine,
|
spapr->icp = xics_system_init(machine,
|
||||||
smp_cpus * kvmppc_smt_threads() / smp_threads,
|
DIV_ROUND_UP(max_cpus * kvmppc_smt_threads(),
|
||||||
|
smp_threads),
|
||||||
XICS_IRQS);
|
XICS_IRQS);
|
||||||
|
|
||||||
/* init CPUs */
|
/* init CPUs */
|
||||||
if (cpu_model == NULL) {
|
if (machine->cpu_model == NULL) {
|
||||||
cpu_model = kvm_enabled() ? "host" : "POWER7";
|
machine->cpu_model = kvm_enabled() ? "host" : "POWER7";
|
||||||
}
|
}
|
||||||
for (i = 0; i < smp_cpus; i++) {
|
for (i = 0; i < smp_cpus; i++) {
|
||||||
cpu = cpu_ppc_init(cpu_model);
|
cpu = cpu_ppc_init(machine->cpu_model);
|
||||||
if (cpu == NULL) {
|
if (cpu == NULL) {
|
||||||
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
|
fprintf(stderr, "Unable to find PowerPC CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
env = &cpu->env;
|
spapr_cpu_init(spapr, cpu);
|
||||||
|
|
||||||
/* Set time-base frequency to 512 MHz */
|
|
||||||
cpu_ppc_tb_init(env, TIMEBASE_FREQ);
|
|
||||||
|
|
||||||
/* PAPR always has exception vectors in RAM not ROM. To ensure this,
|
|
||||||
* MSR[IP] should never be set.
|
|
||||||
*/
|
|
||||||
env->msr_mask &= ~(1 << 6);
|
|
||||||
|
|
||||||
/* Tell KVM that we're in PAPR mode */
|
|
||||||
if (kvm_enabled()) {
|
|
||||||
kvmppc_set_papr(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cpu->max_compat) {
|
|
||||||
if (ppc_set_compat(cpu, cpu->max_compat) < 0) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xics_cpu_setup(spapr->icp, cpu);
|
|
||||||
|
|
||||||
qemu_register_reset(spapr_cpu_reset, cpu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
@@ -1512,9 +1538,8 @@ static void ppc_spapr_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* allocate RAM */
|
/* allocate RAM */
|
||||||
spapr->ram_limit = ram_size;
|
|
||||||
memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
|
memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
|
||||||
spapr->ram_limit);
|
machine->ram_size);
|
||||||
memory_region_add_subregion(sysmem, 0, ram);
|
memory_region_add_subregion(sysmem, 0, ram);
|
||||||
|
|
||||||
if (rma_alloc_size && rma) {
|
if (rma_alloc_size && rma) {
|
||||||
@@ -1658,8 +1683,9 @@ static void ppc_spapr_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
g_free(filename);
|
g_free(filename);
|
||||||
|
|
||||||
spapr->entry_point = 0x100;
|
/* FIXME: Should register things through the MachineState's qdev
|
||||||
|
* interface, this is a legacy from the sPAPREnvironment structure
|
||||||
|
* which predated MachineState but had a similar function */
|
||||||
vmstate_register(NULL, 0, &vmstate_spapr, spapr);
|
vmstate_register(NULL, 0, &vmstate_spapr, spapr);
|
||||||
register_savevm_live(NULL, "spapr/htab", -1, 1,
|
register_savevm_live(NULL, "spapr/htab", -1, 1,
|
||||||
&savevm_htab_handlers, spapr);
|
&savevm_htab_handlers, spapr);
|
||||||
@@ -1755,17 +1781,17 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
|||||||
|
|
||||||
static char *spapr_get_kvm_type(Object *obj, Error **errp)
|
static char *spapr_get_kvm_type(Object *obj, Error **errp)
|
||||||
{
|
{
|
||||||
sPAPRMachineState *sm = SPAPR_MACHINE(obj);
|
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||||
|
|
||||||
return g_strdup(sm->kvm_type);
|
return g_strdup(spapr->kvm_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
|
static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
|
||||||
{
|
{
|
||||||
sPAPRMachineState *sm = SPAPR_MACHINE(obj);
|
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||||
|
|
||||||
g_free(sm->kvm_type);
|
g_free(spapr->kvm_type);
|
||||||
sm->kvm_type = g_strdup(value);
|
spapr->kvm_type = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_machine_initfn(Object *obj)
|
static void spapr_machine_initfn(Object *obj)
|
||||||
@@ -1820,6 +1846,7 @@ static const TypeInfo spapr_machine_info = {
|
|||||||
.abstract = true,
|
.abstract = true,
|
||||||
.instance_size = sizeof(sPAPRMachineState),
|
.instance_size = sizeof(sPAPRMachineState),
|
||||||
.instance_init = spapr_machine_initfn,
|
.instance_init = spapr_machine_initfn,
|
||||||
|
.class_size = sizeof(sPAPRMachineClass),
|
||||||
.class_init = spapr_machine_class_init,
|
.class_init = spapr_machine_class_init,
|
||||||
.interfaces = (InterfaceInfo[]) {
|
.interfaces = (InterfaceInfo[]) {
|
||||||
{ TYPE_FW_PATH_PROVIDER },
|
{ TYPE_FW_PATH_PROVIDER },
|
||||||
@@ -1851,6 +1878,8 @@ static const TypeInfo spapr_machine_info = {
|
|||||||
|
|
||||||
static void spapr_compat_2_3(Object *obj)
|
static void spapr_compat_2_3(Object *obj)
|
||||||
{
|
{
|
||||||
|
savevm_skip_section_footers();
|
||||||
|
global_state_set_optional();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_compat_2_2(Object *obj)
|
static void spapr_compat_2_2(Object *obj)
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ void spapr_events_fdt_skel(void *fdt, uint32_t check_exception_irq)
|
|||||||
|
|
||||||
static void rtas_event_log_queue(int log_type, void *data, bool exception)
|
static void rtas_event_log_queue(int log_type, void *data, bool exception)
|
||||||
{
|
{
|
||||||
|
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||||
sPAPREventLogEntry *entry = g_new(sPAPREventLogEntry, 1);
|
sPAPREventLogEntry *entry = g_new(sPAPREventLogEntry, 1);
|
||||||
|
|
||||||
g_assert(data);
|
g_assert(data);
|
||||||
@@ -250,6 +251,7 @@ static void rtas_event_log_queue(int log_type, void *data, bool exception)
|
|||||||
static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask,
|
static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask,
|
||||||
bool exception)
|
bool exception)
|
||||||
{
|
{
|
||||||
|
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||||
sPAPREventLogEntry *entry = NULL;
|
sPAPREventLogEntry *entry = NULL;
|
||||||
|
|
||||||
/* we only queue EPOW events atm. */
|
/* we only queue EPOW events atm. */
|
||||||
@@ -278,6 +280,7 @@ static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask,
|
|||||||
|
|
||||||
static bool rtas_event_log_contains(uint32_t event_mask, bool exception)
|
static bool rtas_event_log_contains(uint32_t event_mask, bool exception)
|
||||||
{
|
{
|
||||||
|
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||||
sPAPREventLogEntry *entry = NULL;
|
sPAPREventLogEntry *entry = NULL;
|
||||||
|
|
||||||
/* we only queue EPOW events atm. */
|
/* we only queue EPOW events atm. */
|
||||||
@@ -314,6 +317,7 @@ static void spapr_init_v6hdr(struct rtas_event_log_v6 *v6hdr)
|
|||||||
static void spapr_init_maina(struct rtas_event_log_v6_maina *maina,
|
static void spapr_init_maina(struct rtas_event_log_v6_maina *maina,
|
||||||
int section_count)
|
int section_count)
|
||||||
{
|
{
|
||||||
|
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
int year;
|
int year;
|
||||||
|
|
||||||
@@ -336,7 +340,7 @@ static void spapr_init_maina(struct rtas_event_log_v6_maina *maina,
|
|||||||
|
|
||||||
static void spapr_powerdown_req(Notifier *n, void *opaque)
|
static void spapr_powerdown_req(Notifier *n, void *opaque)
|
||||||
{
|
{
|
||||||
sPAPREnvironment *spapr = container_of(n, sPAPREnvironment, epow_notifier);
|
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||||
struct rtas_error_log *hdr;
|
struct rtas_error_log *hdr;
|
||||||
struct rtas_event_log_v6 *v6hdr;
|
struct rtas_event_log_v6 *v6hdr;
|
||||||
struct rtas_event_log_v6_maina *maina;
|
struct rtas_event_log_v6_maina *maina;
|
||||||
@@ -384,6 +388,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)
|
|||||||
|
|
||||||
static void spapr_hotplug_req_event(sPAPRDRConnector *drc, uint8_t hp_action)
|
static void spapr_hotplug_req_event(sPAPRDRConnector *drc, uint8_t hp_action)
|
||||||
{
|
{
|
||||||
|
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||||
struct hp_log_full *new_hp;
|
struct hp_log_full *new_hp;
|
||||||
struct rtas_error_log *hdr;
|
struct rtas_error_log *hdr;
|
||||||
struct rtas_event_log_v6 *v6hdr;
|
struct rtas_event_log_v6 *v6hdr;
|
||||||
@@ -453,7 +458,7 @@ void spapr_hotplug_req_remove_event(sPAPRDRConnector *drc)
|
|||||||
spapr_hotplug_req_event(drc, RTAS_LOG_V6_HP_ACTION_REMOVE);
|
spapr_hotplug_req_event(drc, RTAS_LOG_V6_HP_ACTION_REMOVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t token, uint32_t nargs,
|
uint32_t token, uint32_t nargs,
|
||||||
target_ulong args,
|
target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
@@ -508,7 +513,7 @@ out_no_events:
|
|||||||
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
|
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void event_scan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||||
uint32_t token, uint32_t nargs,
|
uint32_t token, uint32_t nargs,
|
||||||
target_ulong args,
|
target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
@@ -548,7 +553,7 @@ out_no_events:
|
|||||||
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
|
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spapr_events_init(sPAPREnvironment *spapr)
|
void spapr_events_init(sPAPRMachineState *spapr)
|
||||||
{
|
{
|
||||||
QTAILQ_INIT(&spapr->pending_events);
|
QTAILQ_INIT(&spapr->pending_events);
|
||||||
spapr->check_exception_irq = xics_alloc(spapr->icp, 0, 0, false);
|
spapr->check_exception_irq = xics_alloc(spapr->icp, 0, 0, false);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user