Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8b2f64e23 | ||
|
|
88f72048d2 | ||
|
|
faaaf017d5 | ||
|
|
5836af0783 | ||
|
|
de784dc0a0 | ||
|
|
607132e6b6 | ||
|
|
0c0729b46a | ||
|
|
b2a9482207 | ||
|
|
30f830fa88 | ||
|
|
6ad034e712 | ||
|
|
7db162fa01 | ||
|
|
e262646e12 | ||
|
|
c0df98ab1f | ||
|
|
4af976ef39 | ||
|
|
65677b7aad | ||
|
|
040237436f | ||
|
|
fc8ee8fe58 | ||
|
|
88e5a28d5a | ||
|
|
f757d9d90d | ||
|
|
624d746304 | ||
|
|
2190173141 | ||
|
|
621dbaee01 | ||
|
|
53493c1f83 | ||
|
|
bc0c24fdb1 | ||
|
|
31b737b19d | ||
|
|
4f50fa9391 | ||
|
|
79f57adce6 | ||
|
|
60e847dcf0 | ||
|
|
13b4d19ced | ||
|
|
d9f4b45713 | ||
|
|
322ee16824 | ||
|
|
76cfb87f5f | ||
|
|
a74434580e | ||
|
|
6b30d735cf | ||
|
|
e66644c48e | ||
|
|
8c9aae4364 | ||
|
|
5a5d18c756 | ||
|
|
cd21ee5b27 | ||
|
|
c7ac771ee7 | ||
|
|
0fa821f1e9 | ||
|
|
a04ba043a3 | ||
|
|
e0006a8661 | ||
|
|
d2d08975fc | ||
|
|
afeb002e0a | ||
|
|
b217d987a3 | ||
|
|
eb013cd6a1 | ||
|
|
4e5d58969e | ||
|
|
8ee899e9b1 | ||
|
|
90fd159131 | ||
|
|
40b242884e | ||
|
|
823d9b0045 | ||
|
|
7574baef43 | ||
|
|
3c7bde41a3 | ||
|
|
3241a61a13 | ||
|
|
0f2ff99479 | ||
|
|
1585ab9f1b | ||
|
|
b82e7a2a1d | ||
|
|
3025ea65bd | ||
|
|
0a9a27305d | ||
|
|
61432e805e | ||
|
|
a41280fd5b | ||
|
|
a666a84b32 | ||
|
|
0311a6edb9 | ||
|
|
41ae2640c4 | ||
|
|
13ed972b4c | ||
|
|
d63961f957 | ||
|
|
5ff7ad61c0 | ||
|
|
7bf9ae8cc2 | ||
|
|
676ab6a211 | ||
|
|
97b3d732af | ||
|
|
35cca0f95f | ||
|
|
4f2b82f604 | ||
|
|
e7b77e681f | ||
|
|
b10bd4bd17 | ||
|
|
a0555e36fc | ||
|
|
e5859141b9 | ||
|
|
2b290d67f0 | ||
|
|
4caf74916d | ||
|
|
4164adc476 | ||
|
|
e8145dcd31 | ||
|
|
cd16f08ad4 | ||
|
|
5088651138 | ||
|
|
8d5613d2ee | ||
|
|
c0ef803a87 | ||
|
|
10690920b0 | ||
|
|
47d3b32d6f | ||
|
|
a7842d9406 | ||
|
|
47d50cc421 | ||
|
|
96c75abc87 | ||
|
|
cad9aa6fbd | ||
|
|
6071d13c6a | ||
|
|
d63c388dad | ||
|
|
c1997099dc | ||
|
|
6fcf5ebafa | ||
|
|
cd9f752fee | ||
|
|
31995cc408 | ||
|
|
caab7ac835 | ||
|
|
4e06566dbd | ||
|
|
86bc3a0abf | ||
|
|
e443ba0336 | ||
|
|
30ef718423 | ||
|
|
09ac27a9b5 | ||
|
|
16aa7771af | ||
|
|
e111ffe48b | ||
|
|
b6f1244678 | ||
|
|
f3c8b7767f | ||
|
|
a3b95362ce | ||
|
|
35d129399d | ||
|
|
77707bfdf8 | ||
|
|
9b80226ece | ||
|
|
7a3abf7243 | ||
|
|
e52966be20 | ||
|
|
0ae375ab08 | ||
|
|
a95b3c0ad8 | ||
|
|
a14f6d3288 | ||
|
|
1047cc2816 | ||
|
|
a3004697f7 | ||
|
|
d4d91ed42e | ||
|
|
67e4808403 | ||
|
|
653a75a9d7 | ||
|
|
2865bf1c57 | ||
|
|
014bb30d21 | ||
|
|
2bfcd27e00 | ||
|
|
b496a392fe | ||
|
|
962316a6a3 | ||
|
|
8e8cb3b572 | ||
|
|
e895095c78 | ||
|
|
0db7e4cb62 | ||
|
|
e0b33efe2a | ||
|
|
9751377c3a | ||
|
|
1dc1220fbd | ||
|
|
1ebdd2d926 | ||
|
|
92c05be4df | ||
|
|
20b28f58b4 | ||
|
|
bf7da34454 | ||
|
|
061758d7b8 | ||
|
|
26453a7f35 | ||
|
|
62e1fa22f5 | ||
|
|
ef7e21964d | ||
|
|
d27340ff8a | ||
|
|
bb743978f0 | ||
|
|
cac08383f0 | ||
|
|
6da616bb17 | ||
|
|
408c862910 | ||
|
|
25aaf0cb7f | ||
|
|
d0aa5df775 | ||
|
|
ab8bf8f6e4 | ||
|
|
a80e2c26f1 | ||
|
|
78029e9283 | ||
|
|
ebbc04adbb | ||
|
|
f1f25eed03 | ||
|
|
bd0eb9b0cd | ||
|
|
1ab41da6bb | ||
|
|
9b6656668f | ||
|
|
8d6c7de1cc | ||
|
|
e35215db40 | ||
|
|
99870aff90 | ||
|
|
3cdd990aa9 | ||
|
|
feea87cd6b | ||
|
|
fbc8fb36e3 | ||
|
|
c017386f28 | ||
|
|
d3c9de45b2 | ||
|
|
92ac518223 | ||
|
|
919c486c40 | ||
|
|
a7aa2af13e | ||
|
|
bd52d8bc9e | ||
|
|
7428c46c06 | ||
|
|
4726be1c69 | ||
|
|
1c6aae5efb | ||
|
|
b79f944e09 | ||
|
|
aba39946ba | ||
|
|
0e171b427b | ||
|
|
b8882becd5 | ||
|
|
012842c075 | ||
|
|
0fb961e392 | ||
|
|
cf8f0f006d | ||
|
|
076b4306f9 | ||
|
|
01286ee41e | ||
|
|
884216cf41 | ||
|
|
1da3e7f863 | ||
|
|
c4103b2797 | ||
|
|
0db6f79802 | ||
|
|
eb3618e9e2 | ||
|
|
edea818371 | ||
|
|
24ad5e1995 | ||
|
|
eaec556bc8 | ||
|
|
fd1514cbd9 | ||
|
|
2251f9ac92 | ||
|
|
9e601684dc | ||
|
|
f1d630011e | ||
|
|
f63000d943 | ||
|
|
0d70c5aa1b | ||
|
|
4bc8fb0135 | ||
|
|
df3614b798 | ||
|
|
3a50f36469 | ||
|
|
714bae7351 | ||
|
|
f030f35109 | ||
|
|
6ef7784360 | ||
|
|
6936d2f561 | ||
|
|
ba127a1e48 | ||
|
|
ca0081ef7e | ||
|
|
565e6d4d21 | ||
|
|
7a40b50757 | ||
|
|
365e322cfb | ||
|
|
203181cebd | ||
|
|
370ea4a4b6 | ||
|
|
04627e2206 | ||
|
|
384f0365ab | ||
|
|
64a18e0c37 | ||
|
|
cf454eaa96 | ||
|
|
581bec5a04 | ||
|
|
3516b9b673 | ||
|
|
46f5ee8885 | ||
|
|
d16214ed2c | ||
|
|
cc15d50b6e | ||
|
|
1319cb8997 | ||
|
|
64c772ca16 | ||
|
|
9ad30401ce | ||
|
|
97cd373e6c | ||
|
|
1a0cd94252 | ||
|
|
701ab1857a | ||
|
|
555e446019 | ||
|
|
b22ffb4299 | ||
|
|
9898cc8030 | ||
|
|
d273abbfba | ||
|
|
14cbb7bf12 | ||
|
|
c2cee7477f | ||
|
|
279031bc03 | ||
|
|
261626dce1 | ||
|
|
9d466ab9b6 | ||
|
|
14bcc5239f | ||
|
|
ad9175f8a2 | ||
|
|
3abbec04e6 | ||
|
|
d4720a7faf | ||
|
|
8d37317618 | ||
|
|
a1577527e2 | ||
|
|
576830428e | ||
|
|
bde8c148bb | ||
|
|
d1023a296c | ||
|
|
e8cf73b849 | ||
|
|
f16697292a | ||
|
|
f0aab77941 | ||
|
|
301fbbaf03 |
@@ -21,5 +21,3 @@ python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
|
||||
# We want all the document formats
|
||||
formats: all
|
||||
|
||||
+9
-5
@@ -295,7 +295,7 @@ F: tests/tcg/openrisc/
|
||||
|
||||
PowerPC TCG CPUs
|
||||
M: Nicholas Piggin <npiggin@gmail.com>
|
||||
M: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: Chinmay Rath <rathc@linux.ibm.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: target/ppc/
|
||||
@@ -452,7 +452,7 @@ F: target/mips/system/
|
||||
|
||||
PPC KVM CPUs
|
||||
M: Nicholas Piggin <npiggin@gmail.com>
|
||||
R: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
R: Harsh Prateek Bora <harshpb@linux.ibm.com>
|
||||
S: Odd Fixes
|
||||
F: target/ppc/kvm.c
|
||||
|
||||
@@ -1550,7 +1550,7 @@ F: tests/functional/test_ppc_40p.py
|
||||
|
||||
sPAPR (pseries)
|
||||
M: Nicholas Piggin <npiggin@gmail.com>
|
||||
R: Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
M: Harsh Prateek Bora <harshpb@linux.ibm.com>
|
||||
R: Harsh Prateek Bora <harshpb@linux.ibm.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
@@ -1575,7 +1575,7 @@ F: tests/functional/test_ppc64_tuxrun.py
|
||||
|
||||
PowerNV (Non-Virtualized)
|
||||
M: Nicholas Piggin <npiggin@gmail.com>
|
||||
R: Frédéric Barrat <fbarrat@linux.ibm.com>
|
||||
R: Aditya Gupta <adityag@linux.ibm.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: docs/system/ppc/powernv.rst
|
||||
@@ -1695,6 +1695,7 @@ S: Supported
|
||||
F: docs/system/riscv/sifive_u.rst
|
||||
F: hw/*/*sifive*.c
|
||||
F: include/hw/*/*sifive*.h
|
||||
F: tests/functional/test_riscv64_sifive_u.py
|
||||
|
||||
AMD Microblaze-V Generic Board
|
||||
M: Sai Pavan Boddu <sai.pavan.boddu@amd.com>
|
||||
@@ -2322,6 +2323,7 @@ F: include/*/vhost*
|
||||
F: subprojects/libvhost-user/
|
||||
F: block/export/vhost-user*
|
||||
F: util/vhost-user-server.c
|
||||
F: net/vhost*
|
||||
|
||||
vhost-shadow-virtqueue
|
||||
R: Eugenio Pérez <eperezma@redhat.com>
|
||||
@@ -2776,7 +2778,7 @@ F: tests/qtest/fw_cfg-test.c
|
||||
T: git https://github.com/philmd/qemu.git fw_cfg-next
|
||||
|
||||
XIVE
|
||||
R: Frédéric Barrat <fbarrat@linux.ibm.com>
|
||||
R: Gautam Menghani <gautam@linux.ibm.com>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: hw/*/*xive*
|
||||
@@ -3511,6 +3513,7 @@ S: Maintained
|
||||
F: rust/qemu-api
|
||||
F: rust/qemu-api-macros
|
||||
F: rust/rustfmt.toml
|
||||
F: scripts/get-wraps-from-cargo-registry.py
|
||||
|
||||
Rust-related patches CC here
|
||||
L: qemu-rust@nongnu.org
|
||||
@@ -4432,6 +4435,7 @@ F: docs/requirements.txt
|
||||
F: docs/sphinx/
|
||||
F: docs/_templates/
|
||||
F: docs/devel/docs.rst
|
||||
F: docs/devel/qapi-domain.rst
|
||||
|
||||
Rust build system integration
|
||||
M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
|
||||
+68
-36
@@ -99,6 +99,14 @@ typedef struct BDRVRBDState {
|
||||
char *namespace;
|
||||
uint64_t image_size;
|
||||
uint64_t object_size;
|
||||
|
||||
/*
|
||||
* If @bs->encrypted is true, this is the encryption format actually loaded
|
||||
* at the librbd level. If it is false, it is the result of probing.
|
||||
* RBD_IMAGE_ENCRYPTION_FORMAT__MAX means that encryption is not enabled and
|
||||
* probing didn't find any known encryption header either.
|
||||
*/
|
||||
RbdImageEncryptionFormat encryption_format;
|
||||
} BDRVRBDState;
|
||||
|
||||
typedef struct RBDTask {
|
||||
@@ -470,10 +478,12 @@ static int qemu_rbd_encryption_format(rbd_image_t image,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qemu_rbd_encryption_load(rbd_image_t image,
|
||||
static int qemu_rbd_encryption_load(BlockDriverState *bs,
|
||||
rbd_image_t image,
|
||||
RbdEncryptionOptions *encrypt,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
int r = 0;
|
||||
g_autofree char *passphrase = NULL;
|
||||
rbd_encryption_luks1_format_options_t luks_opts;
|
||||
@@ -544,15 +554,19 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
|
||||
error_setg_errno(errp, -r, "encryption load fail");
|
||||
return r;
|
||||
}
|
||||
bs->encrypted = true;
|
||||
s->encryption_format = encrypt->format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
|
||||
static int qemu_rbd_encryption_load2(rbd_image_t image,
|
||||
static int qemu_rbd_encryption_load2(BlockDriverState *bs,
|
||||
rbd_image_t image,
|
||||
RbdEncryptionOptions *encrypt,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
int r = 0;
|
||||
int encrypt_count = 1;
|
||||
int i;
|
||||
@@ -638,6 +652,8 @@ static int qemu_rbd_encryption_load2(rbd_image_t image,
|
||||
error_setg_errno(errp, -r, "layered encryption load fail");
|
||||
goto exit;
|
||||
}
|
||||
bs->encrypted = true;
|
||||
s->encryption_format = encrypt->format;
|
||||
|
||||
exit:
|
||||
for (i = 0; i < encrypt_count; ++i) {
|
||||
@@ -671,6 +687,45 @@ exit:
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For an image without encryption enabled on the rbd layer, probe the start of
|
||||
* the image if it could be opened as an encrypted image so that we can display
|
||||
* it when the user queries the node (most importantly in qemu-img).
|
||||
*
|
||||
* If the guest writes an encryption header to its disk after this probing, this
|
||||
* won't be reflected when queried, but that's okay. There is no reason why the
|
||||
* user should want to apply encryption at the rbd level while the image is
|
||||
* still in use. This is just guest data.
|
||||
*/
|
||||
static void qemu_rbd_encryption_probe(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
char buf[RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {0};
|
||||
int r;
|
||||
|
||||
assert(s->encryption_format == RBD_IMAGE_ENCRYPTION_FORMAT__MAX);
|
||||
|
||||
r = rbd_read(s->image, 0,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN, buf);
|
||||
if (r < RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(buf, rbd_luks_header_verification,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||
s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
|
||||
} else if (memcmp(buf, rbd_luks2_header_verification,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||
s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
|
||||
} else if (memcmp(buf, rbd_layered_luks_header_verification,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||
s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
|
||||
} else if (memcmp(buf, rbd_layered_luks2_header_verification,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||
s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME Deprecate and remove keypairs or make it available in QMP. */
|
||||
static int qemu_rbd_do_create(BlockdevCreateOptions *options,
|
||||
const char *keypairs, const char *password_secret,
|
||||
@@ -1133,17 +1188,18 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto failed_open;
|
||||
}
|
||||
|
||||
s->encryption_format = RBD_IMAGE_ENCRYPTION_FORMAT__MAX;
|
||||
if (opts->encrypt) {
|
||||
#ifdef LIBRBD_SUPPORTS_ENCRYPTION
|
||||
if (opts->encrypt->parent) {
|
||||
#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
|
||||
r = qemu_rbd_encryption_load2(s->image, opts->encrypt, errp);
|
||||
r = qemu_rbd_encryption_load2(bs, s->image, opts->encrypt, errp);
|
||||
#else
|
||||
r = -ENOTSUP;
|
||||
error_setg(errp, "RBD library does not support layered encryption");
|
||||
#endif
|
||||
} else {
|
||||
r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp);
|
||||
r = qemu_rbd_encryption_load(bs, s->image, opts->encrypt, errp);
|
||||
}
|
||||
if (r < 0) {
|
||||
goto failed_post_open;
|
||||
@@ -1153,6 +1209,8 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
error_setg(errp, "RBD library does not support image encryption");
|
||||
goto failed_post_open;
|
||||
#endif
|
||||
} else {
|
||||
qemu_rbd_encryption_probe(bs);
|
||||
}
|
||||
|
||||
r = rbd_stat(s->image, &info, sizeof(info));
|
||||
@@ -1412,17 +1470,6 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
ImageInfoSpecific *spec_info;
|
||||
char buf[RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {0};
|
||||
int r;
|
||||
|
||||
if (s->image_size >= RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) {
|
||||
r = rbd_read(s->image, 0,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN, buf);
|
||||
if (r < 0) {
|
||||
error_setg_errno(errp, -r, "cannot read image start for probe");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
spec_info = g_new(ImageInfoSpecific, 1);
|
||||
*spec_info = (ImageInfoSpecific){
|
||||
@@ -1430,28 +1477,13 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
|
||||
.u.rbd.data = g_new0(ImageInfoSpecificRbd, 1),
|
||||
};
|
||||
|
||||
if (memcmp(buf, rbd_luks_header_verification,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||
spec_info->u.rbd.data->encryption_format =
|
||||
RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
|
||||
spec_info->u.rbd.data->has_encryption_format = true;
|
||||
} else if (memcmp(buf, rbd_luks2_header_verification,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||
spec_info->u.rbd.data->encryption_format =
|
||||
RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
|
||||
spec_info->u.rbd.data->has_encryption_format = true;
|
||||
} else if (memcmp(buf, rbd_layered_luks_header_verification,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||
spec_info->u.rbd.data->encryption_format =
|
||||
RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
|
||||
spec_info->u.rbd.data->has_encryption_format = true;
|
||||
} else if (memcmp(buf, rbd_layered_luks2_header_verification,
|
||||
RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
|
||||
spec_info->u.rbd.data->encryption_format =
|
||||
RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
|
||||
spec_info->u.rbd.data->has_encryption_format = true;
|
||||
if (s->encryption_format == RBD_IMAGE_ENCRYPTION_FORMAT__MAX) {
|
||||
assert(!bs->encrypted);
|
||||
} else {
|
||||
spec_info->u.rbd.data->has_encryption_format = false;
|
||||
ImageInfoSpecificRbd *rbd_info = spec_info->u.rbd.data;
|
||||
|
||||
rbd_info->has_encryption_format = true;
|
||||
rbd_info->encryption_format = s->encryption_format;
|
||||
}
|
||||
|
||||
return spec_info;
|
||||
|
||||
@@ -1186,10 +1186,12 @@ fi
|
||||
meson_version=$($meson --version)
|
||||
if test "$rust" != disabled && ! version_ge "$meson_version" 1.8.1; then
|
||||
if test "$rust" = enabled; then
|
||||
error_exit "Rust support needs Meson 1.8.1 or newer"
|
||||
$mkvenv ensuregroup --dir "${source_path}/python/wheels" \
|
||||
${source_path}/pythondeps.toml meson-rust || exit 1
|
||||
else
|
||||
echo "Rust needs Meson 1.8.1, disabling" 2>&1
|
||||
rust=disabled
|
||||
fi
|
||||
echo "Rust needs Meson 1.8.1, disabling" 2>&1
|
||||
rust=disabled
|
||||
fi
|
||||
if test "$rust" != disabled && has "$rustc" && $rustc -vV > "${TMPDIR1}/${TMPB}.out"; then
|
||||
rust_host_triple=$(sed -n 's/^host: //p' "${TMPDIR1}/${TMPB}.out")
|
||||
@@ -1800,6 +1802,7 @@ echo "SRC_PATH=$source_path" >> tests/tcg/$config_host_mak
|
||||
if test "$plugins" = "yes" ; then
|
||||
echo "CONFIG_PLUGIN=y" >> tests/tcg/$config_host_mak
|
||||
fi
|
||||
echo "PYTHON=$python" >> tests/tcg/$config_host_mak
|
||||
|
||||
tcg_tests_targets=
|
||||
for target in $target_list; do
|
||||
|
||||
+100
-3
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "crypto/tlssession.h"
|
||||
#include "crypto/tlscredsanon.h"
|
||||
#include "crypto/tlscredspsk.h"
|
||||
@@ -51,6 +53,14 @@ struct QCryptoTLSSession {
|
||||
*/
|
||||
Error *rerr;
|
||||
Error *werr;
|
||||
|
||||
/*
|
||||
* Used to protect against broken GNUTLS thread safety
|
||||
* https://gitlab.com/gnutls/gnutls/-/issues/1717
|
||||
*/
|
||||
bool requireThreadSafety;
|
||||
bool lockEnabled;
|
||||
QemuMutex lock;
|
||||
};
|
||||
|
||||
|
||||
@@ -69,6 +79,7 @@ qcrypto_tls_session_free(QCryptoTLSSession *session)
|
||||
g_free(session->peername);
|
||||
g_free(session->authzid);
|
||||
object_unref(OBJECT(session->creds));
|
||||
qemu_mutex_destroy(&session->lock);
|
||||
g_free(session);
|
||||
}
|
||||
|
||||
@@ -84,10 +95,19 @@ qcrypto_tls_session_push(void *opaque, const void *buf, size_t len)
|
||||
return -1;
|
||||
};
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_unlock(&session->lock);
|
||||
}
|
||||
|
||||
error_free(session->werr);
|
||||
session->werr = NULL;
|
||||
|
||||
ret = session->writeFunc(buf, len, session->opaque, &session->werr);
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_lock(&session->lock);
|
||||
}
|
||||
|
||||
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
@@ -114,7 +134,16 @@ qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
|
||||
error_free(session->rerr);
|
||||
session->rerr = NULL;
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_unlock(&session->lock);
|
||||
}
|
||||
|
||||
ret = session->readFunc(buf, len, session->opaque, &session->rerr);
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_lock(&session->lock);
|
||||
}
|
||||
|
||||
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
@@ -153,6 +182,8 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
|
||||
session->creds = creds;
|
||||
object_ref(OBJECT(creds));
|
||||
|
||||
qemu_mutex_init(&session->lock);
|
||||
|
||||
if (creds->endpoint != endpoint) {
|
||||
error_setg(errp, "Credentials endpoint doesn't match session");
|
||||
goto error;
|
||||
@@ -289,6 +320,11 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess)
|
||||
{
|
||||
sess->requireThreadSafety = true;
|
||||
}
|
||||
|
||||
static int
|
||||
qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
|
||||
Error **errp)
|
||||
@@ -480,7 +516,17 @@ qcrypto_tls_session_write(QCryptoTLSSession *session,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
ssize_t ret = gnutls_record_send(session->handle, buf, len);
|
||||
ssize_t ret;
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_lock(&session->lock);
|
||||
}
|
||||
|
||||
ret = gnutls_record_send(session->handle, buf, len);
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_unlock(&session->lock);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret == GNUTLS_E_AGAIN) {
|
||||
@@ -509,7 +555,17 @@ qcrypto_tls_session_read(QCryptoTLSSession *session,
|
||||
bool gracefulTermination,
|
||||
Error **errp)
|
||||
{
|
||||
ssize_t ret = gnutls_record_recv(session->handle, buf, len);
|
||||
ssize_t ret;
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_lock(&session->lock);
|
||||
}
|
||||
|
||||
ret = gnutls_record_recv(session->handle, buf, len);
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_unlock(&session->lock);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret == GNUTLS_E_AGAIN) {
|
||||
@@ -545,8 +601,39 @@ int
|
||||
qcrypto_tls_session_handshake(QCryptoTLSSession *session,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = gnutls_handshake(session->handle);
|
||||
int ret;
|
||||
ret = gnutls_handshake(session->handle);
|
||||
|
||||
if (!ret) {
|
||||
#ifdef CONFIG_GNUTLS_BUG1717_WORKAROUND
|
||||
gnutls_cipher_algorithm_t cipher =
|
||||
gnutls_cipher_get(session->handle);
|
||||
|
||||
/*
|
||||
* Any use of rekeying in TLS 1.3 is unsafe for
|
||||
* a gnutls with bug 1717, however, we know that
|
||||
* QEMU won't initiate manual rekeying. Thus we
|
||||
* only have to protect against automatic rekeying
|
||||
* which doesn't trigger with CHACHA20
|
||||
*/
|
||||
trace_qcrypto_tls_session_parameters(
|
||||
session,
|
||||
session->requireThreadSafety,
|
||||
gnutls_protocol_get_version(session->handle),
|
||||
cipher);
|
||||
|
||||
if (session->requireThreadSafety &&
|
||||
gnutls_protocol_get_version(session->handle) ==
|
||||
GNUTLS_TLS1_3 &&
|
||||
cipher != GNUTLS_CIPHER_CHACHA20_POLY1305) {
|
||||
warn_report("WARNING: activating thread safety countermeasures "
|
||||
"for potentially broken GNUTLS with TLS1.3 cipher=%d",
|
||||
cipher);
|
||||
trace_qcrypto_tls_session_bug1717_workaround(session);
|
||||
session->lockEnabled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
session->handshakeComplete = true;
|
||||
return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
|
||||
}
|
||||
@@ -584,8 +671,15 @@ qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_lock(&session->lock);
|
||||
}
|
||||
ret = gnutls_bye(session->handle, GNUTLS_SHUT_WR);
|
||||
|
||||
if (session->lockEnabled) {
|
||||
qemu_mutex_unlock(&session->lock);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
return QCRYPTO_TLS_BYE_COMPLETE;
|
||||
}
|
||||
@@ -651,6 +745,9 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds G_GNUC_UNUSED,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
qcrypto_tls_session_free(QCryptoTLSSession *sess G_GNUC_UNUSED)
|
||||
|
||||
@@ -21,6 +21,8 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds
|
||||
# tlssession.c
|
||||
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *authzid, int endpoint) "TLS session new session=%p creds=%p hostname=%s authzid=%s endpoint=%d"
|
||||
qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"
|
||||
qcrypto_tls_session_parameters(void *session, int threadSafety, int protocol, int cipher) "TLS session parameters session=%p threadSafety=%d protocol=%d cipher=%d"
|
||||
qcrypto_tls_session_bug1717_workaround(void *session) "TLS session bug1717 workaround session=%p"
|
||||
|
||||
# tls-cipher-suites.c
|
||||
qcrypto_tls_cipher_suite_priority(const char *name) "priority: %s"
|
||||
|
||||
@@ -127,6 +127,14 @@ Rust build dependencies
|
||||
(or newer) package. The path to ``rustc`` and ``rustdoc`` must be
|
||||
provided manually to the configure script.
|
||||
|
||||
Some distros prefer to avoid vendored crate sources, and instead use
|
||||
local sources from e.g. ``/usr/share/cargo/registry``. QEMU includes a
|
||||
script, ``scripts/get-wraps-from-cargo-registry.py``, that automatically
|
||||
performs this task. The script is meant to be invoked after unpacking
|
||||
the QEMU tarball. QEMU also includes ``rust/Cargo.toml`` and
|
||||
``rust/Cargo.lock`` files that can be used to compute QEMU's build
|
||||
dependencies, e.g. using ``cargo2rpm -p rust/Cargo.toml buildrequires``.
|
||||
|
||||
Optional build dependencies
|
||||
Build components whose absence does not affect the ability to build QEMU
|
||||
may not be available in distros, or may be too old for our requirements.
|
||||
|
||||
@@ -646,9 +646,9 @@ Member 'event' names the event. This is the event name used in the
|
||||
Client JSON Protocol.
|
||||
|
||||
Member 'data' defines the event-specific data. It defaults to an
|
||||
empty MEMBERS object.
|
||||
empty MEMBERS_ object.
|
||||
|
||||
If 'data' is a MEMBERS object, then MEMBERS defines event-specific
|
||||
If 'data' is a MEMBERS_ object, then MEMBERS defines event-specific
|
||||
data just like a struct type's 'data' defines struct type members.
|
||||
|
||||
If 'data' is a STRING, then STRING names a complex type whose members
|
||||
@@ -786,8 +786,8 @@ Configuring the schema
|
||||
Syntax::
|
||||
|
||||
COND = STRING
|
||||
| { 'all: [ COND, ... ] }
|
||||
| { 'any: [ COND, ... ] }
|
||||
| { 'all': [ COND, ... ] }
|
||||
| { 'any': [ COND, ... ] }
|
||||
| { 'not': COND }
|
||||
|
||||
All definitions take an optional 'if' member. Its value must be a
|
||||
@@ -943,9 +943,14 @@ The usual ****strong****, *\*emphasized\** and ````literal```` markup
|
||||
should be used. If you need a single literal ``*``, you will need to
|
||||
backslash-escape it.
|
||||
|
||||
Use ``@foo`` to reference a name in the schema. This is an rST
|
||||
extension. It is rendered the same way as ````foo````, but carries
|
||||
additional meaning.
|
||||
Use ```foo``` to reference a definition in the schema. This generates
|
||||
a link to the definition. In the event that such a cross-reference is
|
||||
ambiguous, you can use `QAPI cross-reference roles
|
||||
<QAPI-domain-cross-references>` to disambiguate.
|
||||
|
||||
Use @foo to reference a member description within the current
|
||||
definition. This is an rST extension. It is currently rendered the
|
||||
same way as ````foo````, but carries additional meaning.
|
||||
|
||||
Example::
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ in Sphinx is provided by the QAPI Domain, located in
|
||||
`Python Domain
|
||||
<https://www.sphinx-doc.org/en/master/usage/domains/python.html>`_
|
||||
included with Sphinx, but provides special directives and roles
|
||||
speciically for annotating and documenting QAPI definitions
|
||||
for annotating and documenting QAPI definitions
|
||||
specifically.
|
||||
|
||||
A `Domain
|
||||
@@ -101,7 +101,7 @@ without types. The QAPI domain uses this class for features, returns,
|
||||
and enum values.
|
||||
|
||||
TypedField:
|
||||
* Creates a grouped, typed field. Multiple adjacent entres will be
|
||||
* Creates a grouped, typed field. Multiple adjacent entries will be
|
||||
merged into one section, and the content will form a bulleted list.
|
||||
* *Must* take at least one argument, but supports up to two -
|
||||
nominally, a name and a type.
|
||||
@@ -375,6 +375,7 @@ Will allow you to add arbitrary field lists in QAPI directives::
|
||||
|
||||
:see also: Lorem ipsum, dolor sit amet ...
|
||||
|
||||
.. _QAPI-domain-cross-references:
|
||||
|
||||
Cross-references
|
||||
================
|
||||
|
||||
@@ -235,6 +235,38 @@ to another list.) ``git send-email`` (`step-by-step setup guide
|
||||
works best for delivering the patch without mangling it, but
|
||||
attachments can be used as a last resort on a first-time submission.
|
||||
|
||||
.. _use_b4:
|
||||
|
||||
Use B4
|
||||
~~~~~~
|
||||
|
||||
The `b4`_ tool, used for Linux kernel development, can also be used for QEMU
|
||||
development. It is packaged in most distros and PyPi. The QEMU source tree
|
||||
includes a ``b4`` project configuration file at the root: ``.b4-config``.
|
||||
|
||||
Example workflow to prepare a patch series:
|
||||
|
||||
1. Start with a clean checkout of the ``master`` branch.
|
||||
2. Create a new series with a topical branch name using ``b4 prep -n descriptive-name``.
|
||||
``b4`` will create a ``b4/descriptive-name`` branch and switch to it.
|
||||
3. Commit your changes, following this page's guidelines about proper commit messages etc.
|
||||
4. Write a descriptive cover letter with ``b4 prep --edit-cover``.
|
||||
5. Add maintainer and reviewer CCs with ``b4 prep --auto-to-cc``. You can make
|
||||
changes to Cc: and To: recipients by editing the cover letter.
|
||||
6. Run patch checks with ``b4 prep --check``.
|
||||
7. Optionally review the patches with ``b4 send --dry-run`` which will print the
|
||||
raw patches in standard output.
|
||||
|
||||
To send the patches, you can:
|
||||
|
||||
- Setup ``git-send-email`` and use ``b4 send``, or
|
||||
- Export the patches to files using ``b4 send -o OUTPUT_DIR`` and send them manually.
|
||||
|
||||
For more details, consult the `b4 documentation`_.
|
||||
|
||||
.. _b4 documentation: https://b4.docs.kernel.org/
|
||||
.. _b4: https://github.com/mricon/b4/
|
||||
|
||||
.. _use_git_publish:
|
||||
|
||||
Use git-publish
|
||||
@@ -418,7 +450,7 @@ Retrieve an existing series
|
||||
---------------------------
|
||||
|
||||
If you want to apply an existing series on top of your tree, you can simply use
|
||||
`b4 <https://github.com/mricon/b4>`__.
|
||||
`b4`_.
|
||||
|
||||
::
|
||||
|
||||
@@ -533,7 +565,11 @@ summary belongs. The `git-publish
|
||||
<https://github.com/stefanha/git-publish>`__ script can help with
|
||||
tracking a good summary across versions. Also, the `git-backport-diff
|
||||
<https://github.com/codyprime/git-scripts>`__ script can help focus
|
||||
reviewers on what changed between revisions.
|
||||
reviewers on what changed between revisions. The ``b4`` tool automatically
|
||||
generates a version history section in the cover letter, including links to the
|
||||
previous versions on `Lore`_.
|
||||
|
||||
.. _Lore: https://lore.kernel.org/
|
||||
|
||||
.. _tips_and_tricks:
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ Intel document [1] shows how to dump VBIOS to file. For UEFI Option ROM, see
|
||||
QEMU also provides a "Legacy" mode that implicitly enables full functionality
|
||||
on IGD, it is automatically enabled when
|
||||
* IGD generation is 6 to 9 (Sandy Bridge to Comet Lake)
|
||||
* IGD claims VGA cycles on host (IGD is VGA controller on host)
|
||||
* Machine type is i440fx
|
||||
* IGD is assigned to guest BDF 00:02.0
|
||||
* ROM BAR or romfile is present
|
||||
|
||||
@@ -21,11 +21,17 @@ configure it as if it was a real ethernet card.
|
||||
Linux host
|
||||
^^^^^^^^^^
|
||||
|
||||
As an example, you can download the ``linux-test-xxx.tar.gz`` archive
|
||||
and copy the script ``qemu-ifup`` in ``/etc`` and configure properly
|
||||
``sudo`` so that the command ``ifconfig`` contained in ``qemu-ifup`` can
|
||||
be executed as root. You must verify that your host kernel supports the
|
||||
TAP network interfaces: the device ``/dev/net/tun`` must be present.
|
||||
A distribution will generally provide specific helper scripts when it
|
||||
packages QEMU. By default these are found at ``/etc/qemu-ifup`` and
|
||||
``/etc/qemu-ifdown`` and are called appropriately when QEMU wants to
|
||||
change the network state.
|
||||
|
||||
If QEMU is being run as a non-privileged user you may need properly
|
||||
configure ``sudo`` so that network commands in the scripts can be
|
||||
executed as root.
|
||||
|
||||
You must verify that your host kernel supports the TAP network
|
||||
interfaces: the device ``/dev/net/tun`` must be present.
|
||||
|
||||
See :ref:`sec_005finvocation` to have examples of command
|
||||
lines using the TAP network interfaces.
|
||||
|
||||
+3
-2
@@ -5,8 +5,9 @@ User Mode Emulation
|
||||
-------------------
|
||||
|
||||
This section of the manual is the overall guide for users using QEMU
|
||||
for user-mode emulation. In this mode, QEMU can launch
|
||||
processes compiled for one CPU on another CPU.
|
||||
for user-mode emulation. In this mode, QEMU can launch programs
|
||||
compiled for one CPU architecture on the same Operating System (OS)
|
||||
but running on a different CPU architecture.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
+35
-19
@@ -17,28 +17,44 @@ Features
|
||||
|
||||
QEMU user space emulation has the following notable features:
|
||||
|
||||
**System call translation:**
|
||||
QEMU includes a generic system call translator. This means that the
|
||||
parameters of the system calls can be converted to fix endianness and
|
||||
32/64-bit mismatches between hosts and targets. IOCTLs can be
|
||||
converted too.
|
||||
System call translation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**POSIX signal handling:**
|
||||
QEMU can redirect to the running program all signals coming from the
|
||||
host (such as ``SIGALRM``), as well as synthesize signals from
|
||||
virtual CPU exceptions (for example ``SIGFPE`` when the program
|
||||
executes a division by zero).
|
||||
System calls are the principle interface between user-space and the
|
||||
kernel. Generally the same system calls exist on all versions of the
|
||||
kernel so QEMU includes a generic system call translator. The
|
||||
translator takes care of adjusting endianess, 32/64 bit parameter size
|
||||
and then calling the equivalent host system call.
|
||||
|
||||
QEMU relies on the host kernel to emulate most signal system calls,
|
||||
for example to emulate the signal mask. On Linux, QEMU supports both
|
||||
normal and real-time signals.
|
||||
QEMU can also adjust device specific ``ioctl()`` calls in a similar
|
||||
fashion.
|
||||
|
||||
**Threading:**
|
||||
On Linux, QEMU can emulate the ``clone`` syscall and create a real
|
||||
host thread (with a separate virtual CPU) for each emulated thread.
|
||||
Note that not all targets currently emulate atomic operations
|
||||
correctly. x86 and Arm use a global lock in order to preserve their
|
||||
semantics.
|
||||
POSIX signal handling
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
QEMU can redirect to the running program all signals coming from the
|
||||
host (such as ``SIGALRM``), as well as synthesize signals from
|
||||
virtual CPU exceptions (for example ``SIGFPE`` when the program
|
||||
executes a division by zero).
|
||||
|
||||
QEMU relies on the host kernel to emulate most signal system calls,
|
||||
for example to emulate the signal mask. On Linux, QEMU supports both
|
||||
normal and real-time signals.
|
||||
|
||||
Threading
|
||||
~~~~~~~~~
|
||||
|
||||
On Linux, QEMU can emulate the ``clone`` syscall and create a real
|
||||
host thread (with a separate virtual CPU) for each emulated thread.
|
||||
However as QEMU relies on the system libc to call ``clone`` on its
|
||||
behalf we limit the flags accepted to those it uses. Specifically this
|
||||
means flags affecting namespaces (e.g. container runtimes) are not
|
||||
supported. QEMU user-mode processes can still be run inside containers
|
||||
though.
|
||||
|
||||
While QEMU does its best to emulate atomic operations properly
|
||||
differences between the host and guest memory models can cause issues
|
||||
for software that makes assumptions about the memory model.
|
||||
|
||||
QEMU was conceived so that ultimately it can emulate itself. Although it
|
||||
is not very useful, it is an important test to show the power of the
|
||||
|
||||
@@ -319,7 +319,7 @@ void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
|
||||
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
|
||||
}
|
||||
|
||||
inline void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
|
||||
void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
|
||||
{
|
||||
trace_smmu_iotlb_inv_vmid_s1(vmid);
|
||||
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &vmid);
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ GlobalProperty hw_compat_10_0[] = {
|
||||
{ "scsi-hd", "dpofua", "off" },
|
||||
{ "vfio-pci", "x-migration-load-config-after-iter", "off" },
|
||||
{ "ramfb", "use-legacy-x86-rom", "true"},
|
||||
{ "vfio-pci", "use-legacy-x86-rom", "true" },
|
||||
{ "vfio-pci-nohotplug", "use-legacy-x86-rom", "true" },
|
||||
};
|
||||
const size_t hw_compat_10_0_len = G_N_ELEMENTS(hw_compat_10_0);
|
||||
|
||||
|
||||
@@ -95,9 +95,9 @@ void framebuffer_update_display(
|
||||
}
|
||||
first = -1;
|
||||
|
||||
addr += i * src_width;
|
||||
src += i * src_width;
|
||||
dest += i * dest_row_pitch;
|
||||
addr += (uint64_t)i * src_width;
|
||||
src += (uint64_t)i * src_width;
|
||||
dest += (uint64_t)i * dest_row_pitch;
|
||||
|
||||
snap = memory_region_snapshot_and_clear_dirty(mem, addr, src_width * rows,
|
||||
DIRTY_MEMORY_VGA);
|
||||
|
||||
+10
-1
@@ -222,6 +222,7 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl,
|
||||
uint32_t max_chunks = 32;
|
||||
size_t offset = 0;
|
||||
size_t bytes;
|
||||
QXLPHYSICAL next_chunk_phys = 0;
|
||||
|
||||
for (;;) {
|
||||
bytes = MIN(size - offset, chunk->data_size);
|
||||
@@ -230,7 +231,15 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl,
|
||||
if (offset == size) {
|
||||
return;
|
||||
}
|
||||
chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id,
|
||||
next_chunk_phys = chunk->next_chunk;
|
||||
/* fist time, only get the next chunk's data size */
|
||||
chunk = qxl_phys2virt(qxl, next_chunk_phys, group_id,
|
||||
sizeof(QXLDataChunk));
|
||||
if (!chunk) {
|
||||
return;
|
||||
}
|
||||
/* second time, check data size and get data */
|
||||
chunk = qxl_phys2virt(qxl, next_chunk_phys, group_id,
|
||||
sizeof(QXLDataChunk) + chunk->data_size);
|
||||
if (!chunk) {
|
||||
return;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/usb/hcd-ohci.h"
|
||||
|
||||
+2
-1
@@ -4,7 +4,7 @@ config X86_FW_OVMF
|
||||
config SEV
|
||||
bool
|
||||
select X86_FW_OVMF
|
||||
depends on KVM
|
||||
depends on KVM && X86_64
|
||||
|
||||
config SGX
|
||||
bool
|
||||
@@ -131,6 +131,7 @@ config MICROVM
|
||||
select I8259
|
||||
select MC146818RTC
|
||||
select VIRTIO_MMIO
|
||||
select ACPI_PCI
|
||||
select ACPI_HW_REDUCED
|
||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||
select USB_XHCI_SYSBUS
|
||||
|
||||
+79
-23
@@ -123,8 +123,13 @@ static void amdvi_writew(AMDVIState *s, hwaddr addr, uint16_t val)
|
||||
uint16_t romask = lduw_le_p(&s->romask[addr]);
|
||||
uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]);
|
||||
uint16_t oldval = lduw_le_p(&s->mmior[addr]);
|
||||
|
||||
uint16_t oldval_preserved = oldval & (romask | w1cmask);
|
||||
uint16_t newval_write = val & ~romask;
|
||||
uint16_t newval_w1c_set = val & w1cmask;
|
||||
|
||||
stw_le_p(&s->mmior[addr],
|
||||
((oldval & romask) | (val & ~romask)) & ~(val & w1cmask));
|
||||
(oldval_preserved | newval_write) & ~newval_w1c_set);
|
||||
}
|
||||
|
||||
static void amdvi_writel(AMDVIState *s, hwaddr addr, uint32_t val)
|
||||
@@ -132,8 +137,13 @@ static void amdvi_writel(AMDVIState *s, hwaddr addr, uint32_t val)
|
||||
uint32_t romask = ldl_le_p(&s->romask[addr]);
|
||||
uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]);
|
||||
uint32_t oldval = ldl_le_p(&s->mmior[addr]);
|
||||
|
||||
uint32_t oldval_preserved = oldval & (romask | w1cmask);
|
||||
uint32_t newval_write = val & ~romask;
|
||||
uint32_t newval_w1c_set = val & w1cmask;
|
||||
|
||||
stl_le_p(&s->mmior[addr],
|
||||
((oldval & romask) | (val & ~romask)) & ~(val & w1cmask));
|
||||
(oldval_preserved | newval_write) & ~newval_w1c_set);
|
||||
}
|
||||
|
||||
static void amdvi_writeq(AMDVIState *s, hwaddr addr, uint64_t val)
|
||||
@@ -141,14 +151,19 @@ static void amdvi_writeq(AMDVIState *s, hwaddr addr, uint64_t val)
|
||||
uint64_t romask = ldq_le_p(&s->romask[addr]);
|
||||
uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]);
|
||||
uint64_t oldval = ldq_le_p(&s->mmior[addr]);
|
||||
|
||||
uint64_t oldval_preserved = oldval & (romask | w1cmask);
|
||||
uint64_t newval_write = val & ~romask;
|
||||
uint64_t newval_w1c_set = val & w1cmask;
|
||||
|
||||
stq_le_p(&s->mmior[addr],
|
||||
((oldval & romask) | (val & ~romask)) & ~(val & w1cmask));
|
||||
(oldval_preserved | newval_write) & ~newval_w1c_set);
|
||||
}
|
||||
|
||||
/* OR a 64-bit register with a 64-bit value */
|
||||
/* AND a 64-bit register with a 64-bit value */
|
||||
static bool amdvi_test_mask(AMDVIState *s, hwaddr addr, uint64_t val)
|
||||
{
|
||||
return amdvi_readq(s, addr) | val;
|
||||
return amdvi_readq(s, addr) & val;
|
||||
}
|
||||
|
||||
/* OR a 64-bit register with a 64-bit value storing result in the register */
|
||||
@@ -177,19 +192,31 @@ static void amdvi_generate_msi_interrupt(AMDVIState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t get_next_eventlog_entry(AMDVIState *s)
|
||||
{
|
||||
uint32_t evtlog_size = s->evtlog_len * AMDVI_EVENT_LEN;
|
||||
return (s->evtlog_tail + AMDVI_EVENT_LEN) % evtlog_size;
|
||||
}
|
||||
|
||||
static void amdvi_log_event(AMDVIState *s, uint64_t *evt)
|
||||
{
|
||||
uint32_t evtlog_tail_next;
|
||||
|
||||
/* event logging not enabled */
|
||||
if (!s->evtlog_enabled || amdvi_test_mask(s, AMDVI_MMIO_STATUS,
|
||||
AMDVI_MMIO_STATUS_EVT_OVF)) {
|
||||
return;
|
||||
}
|
||||
|
||||
evtlog_tail_next = get_next_eventlog_entry(s);
|
||||
|
||||
/* event log buffer full */
|
||||
if (s->evtlog_tail >= s->evtlog_len) {
|
||||
amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_EVT_OVF);
|
||||
/* generate interrupt */
|
||||
amdvi_generate_msi_interrupt(s);
|
||||
if (evtlog_tail_next == s->evtlog_head) {
|
||||
/* generate overflow interrupt */
|
||||
if (s->evtlog_intr) {
|
||||
amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_EVT_OVF);
|
||||
amdvi_generate_msi_interrupt(s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -198,9 +225,13 @@ static void amdvi_log_event(AMDVIState *s, uint64_t *evt)
|
||||
trace_amdvi_evntlog_fail(s->evtlog, s->evtlog_tail);
|
||||
}
|
||||
|
||||
s->evtlog_tail += AMDVI_EVENT_LEN;
|
||||
amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_COMP_INT);
|
||||
amdvi_generate_msi_interrupt(s);
|
||||
s->evtlog_tail = evtlog_tail_next;
|
||||
amdvi_writeq_raw(s, AMDVI_MMIO_EVENT_TAIL, s->evtlog_tail);
|
||||
|
||||
if (s->evtlog_intr) {
|
||||
amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_EVENT_INT);
|
||||
amdvi_generate_msi_interrupt(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void amdvi_setevent_bits(uint64_t *buffer, uint64_t value, int start,
|
||||
@@ -592,18 +623,31 @@ static void amdvi_cmdbuf_run(AMDVIState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void amdvi_mmio_trace(hwaddr addr, unsigned size)
|
||||
static inline uint8_t amdvi_mmio_get_index(hwaddr addr)
|
||||
{
|
||||
uint8_t index = (addr & ~0x2000) / 8;
|
||||
|
||||
if ((addr & 0x2000)) {
|
||||
/* high table */
|
||||
index = index >= AMDVI_MMIO_REGS_HIGH ? AMDVI_MMIO_REGS_HIGH : index;
|
||||
trace_amdvi_mmio_read(amdvi_mmio_high[index], addr, size, addr & ~0x07);
|
||||
} else {
|
||||
index = index >= AMDVI_MMIO_REGS_LOW ? AMDVI_MMIO_REGS_LOW : index;
|
||||
trace_amdvi_mmio_read(amdvi_mmio_low[index], addr, size, addr & ~0x07);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static void amdvi_mmio_trace_read(hwaddr addr, unsigned size)
|
||||
{
|
||||
uint8_t index = amdvi_mmio_get_index(addr);
|
||||
trace_amdvi_mmio_read(amdvi_mmio_low[index], addr, size, addr & ~0x07);
|
||||
}
|
||||
|
||||
static void amdvi_mmio_trace_write(hwaddr addr, unsigned size, uint64_t val)
|
||||
{
|
||||
uint8_t index = amdvi_mmio_get_index(addr);
|
||||
trace_amdvi_mmio_write(amdvi_mmio_low[index], addr, size, val,
|
||||
addr & ~0x07);
|
||||
}
|
||||
|
||||
static uint64_t amdvi_mmio_read(void *opaque, hwaddr addr, unsigned size)
|
||||
@@ -623,7 +667,7 @@ static uint64_t amdvi_mmio_read(void *opaque, hwaddr addr, unsigned size)
|
||||
} else if (size == 8) {
|
||||
val = amdvi_readq(s, addr);
|
||||
}
|
||||
amdvi_mmio_trace(addr, size);
|
||||
amdvi_mmio_trace_read(addr, size);
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -633,7 +677,6 @@ static void amdvi_handle_control_write(AMDVIState *s)
|
||||
unsigned long control = amdvi_readq(s, AMDVI_MMIO_CONTROL);
|
||||
s->enabled = !!(control & AMDVI_MMIO_CONTROL_AMDVIEN);
|
||||
|
||||
s->ats_enabled = !!(control & AMDVI_MMIO_CONTROL_HTTUNEN);
|
||||
s->evtlog_enabled = s->enabled && !!(control &
|
||||
AMDVI_MMIO_CONTROL_EVENTLOGEN);
|
||||
|
||||
@@ -704,9 +747,19 @@ static inline void amdvi_handle_excllim_write(AMDVIState *s)
|
||||
static inline void amdvi_handle_evtbase_write(AMDVIState *s)
|
||||
{
|
||||
uint64_t val = amdvi_readq(s, AMDVI_MMIO_EVENT_BASE);
|
||||
|
||||
if (amdvi_readq(s, AMDVI_MMIO_STATUS) & AMDVI_MMIO_STATUS_EVENT_INT)
|
||||
/* Do not reset if eventlog interrupt bit is set*/
|
||||
return;
|
||||
|
||||
s->evtlog = val & AMDVI_MMIO_EVTLOG_BASE_MASK;
|
||||
s->evtlog_len = 1UL << (amdvi_readq(s, AMDVI_MMIO_EVTLOG_SIZE_BYTE)
|
||||
& AMDVI_MMIO_EVTLOG_SIZE_MASK);
|
||||
|
||||
/* clear tail and head pointer to 0 when event base is updated */
|
||||
s->evtlog_tail = s->evtlog_head = 0;
|
||||
amdvi_writeq_raw(s, AMDVI_MMIO_EVENT_HEAD, s->evtlog_head);
|
||||
amdvi_writeq_raw(s, AMDVI_MMIO_EVENT_TAIL, s->evtlog_tail);
|
||||
}
|
||||
|
||||
static inline void amdvi_handle_evttail_write(AMDVIState *s)
|
||||
@@ -770,7 +823,7 @@ static void amdvi_mmio_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
return;
|
||||
}
|
||||
|
||||
amdvi_mmio_trace(addr, size);
|
||||
amdvi_mmio_trace_write(addr, size, val);
|
||||
switch (addr & ~0x07) {
|
||||
case AMDVI_MMIO_CONTROL:
|
||||
amdvi_mmio_reg_write(s, size, val, addr);
|
||||
@@ -835,6 +888,9 @@ static void amdvi_mmio_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
amdvi_mmio_reg_write(s, size, val, addr);
|
||||
amdvi_handle_pprtail_write(s);
|
||||
break;
|
||||
case AMDVI_MMIO_STATUS:
|
||||
amdvi_mmio_reg_write(s, size, val, addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1542,7 +1598,6 @@ static void amdvi_init(AMDVIState *s)
|
||||
s->excl_allow = false;
|
||||
s->mmio_enabled = false;
|
||||
s->enabled = false;
|
||||
s->ats_enabled = false;
|
||||
s->cmdbuf_enabled = false;
|
||||
|
||||
/* reset MMIO */
|
||||
@@ -1613,7 +1668,8 @@ static const VMStateDescription vmstate_amdvi_sysbus_migratable = {
|
||||
/* Updated in amdvi_handle_control_write() */
|
||||
VMSTATE_BOOL(enabled, AMDVIState),
|
||||
VMSTATE_BOOL(ga_enabled, AMDVIState),
|
||||
VMSTATE_BOOL(ats_enabled, AMDVIState),
|
||||
/* bool ats_enabled is obsolete */
|
||||
VMSTATE_UNUSED(1), /* was ats_enabled */
|
||||
VMSTATE_BOOL(cmdbuf_enabled, AMDVIState),
|
||||
VMSTATE_BOOL(completion_wait_intr, AMDVIState),
|
||||
VMSTATE_BOOL(evtlog_enabled, AMDVIState),
|
||||
@@ -1686,9 +1742,6 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
|
||||
s->iotlb = g_hash_table_new_full(amdvi_uint64_hash,
|
||||
amdvi_uint64_equal, g_free, g_free);
|
||||
|
||||
/* Pseudo address space under root PCI bus. */
|
||||
x86ms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID);
|
||||
|
||||
/* set up MMIO */
|
||||
memory_region_init_io(&s->mr_mmio, OBJECT(s), &mmio_mem_ops, s,
|
||||
"amdvi-mmio", AMDVI_MMIO_SIZE);
|
||||
@@ -1711,6 +1764,9 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_add_subregion_overlap(&s->mr_sys, AMDVI_INT_ADDR_FIRST,
|
||||
&s->mr_ir, 1);
|
||||
|
||||
/* Pseudo address space under root PCI bus. */
|
||||
x86ms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID);
|
||||
|
||||
if (kvm_enabled() && x86ms->apic_id_limit > 255 && !s->xtsup) {
|
||||
error_report("AMD IOMMU with x2APIC configuration requires xtsup=on");
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
+1
-1
@@ -111,6 +111,7 @@
|
||||
#define AMDVI_MMIO_STATUS_CMDBUF_RUN (1 << 4)
|
||||
#define AMDVI_MMIO_STATUS_EVT_RUN (1 << 3)
|
||||
#define AMDVI_MMIO_STATUS_COMP_INT (1 << 2)
|
||||
#define AMDVI_MMIO_STATUS_EVENT_INT (1 << 1)
|
||||
#define AMDVI_MMIO_STATUS_EVT_OVF (1 << 0)
|
||||
|
||||
#define AMDVI_CMDBUF_ID_BYTE 0x07
|
||||
@@ -322,7 +323,6 @@ struct AMDVIState {
|
||||
uint64_t mmio_addr;
|
||||
|
||||
bool enabled; /* IOMMU enabled */
|
||||
bool ats_enabled; /* address translation enabled */
|
||||
bool cmdbuf_enabled; /* command buffer enabled */
|
||||
bool evtlog_enabled; /* event log enabled */
|
||||
bool excl_enabled;
|
||||
|
||||
@@ -2828,6 +2828,7 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
|
||||
{
|
||||
uint64_t mask[4] = {VTD_INV_DESC_WAIT_RSVD_LO, VTD_INV_DESC_WAIT_RSVD_HI,
|
||||
VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
|
||||
bool ret = true;
|
||||
|
||||
if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
|
||||
__func__, "wait")) {
|
||||
@@ -2839,8 +2840,6 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
|
||||
uint32_t status_data = (uint32_t)(inv_desc->lo >>
|
||||
VTD_INV_DESC_WAIT_DATA_SHIFT);
|
||||
|
||||
assert(!(inv_desc->lo & VTD_INV_DESC_WAIT_IF));
|
||||
|
||||
/* FIXME: need to be masked with HAW? */
|
||||
dma_addr_t status_addr = inv_desc->hi;
|
||||
trace_vtd_inv_desc_wait_sw(status_addr, status_data);
|
||||
@@ -2849,18 +2848,22 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
|
||||
&status_data, sizeof(status_data),
|
||||
MEMTXATTRS_UNSPECIFIED)) {
|
||||
trace_vtd_inv_desc_wait_write_fail(inv_desc->hi, inv_desc->lo);
|
||||
return false;
|
||||
ret = false;
|
||||
}
|
||||
} else if (inv_desc->lo & VTD_INV_DESC_WAIT_IF) {
|
||||
}
|
||||
|
||||
if (inv_desc->lo & VTD_INV_DESC_WAIT_IF) {
|
||||
/* Interrupt flag */
|
||||
vtd_generate_completion_event(s);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (!(inv_desc->lo & (VTD_INV_DESC_WAIT_IF | VTD_INV_DESC_WAIT_SW))) {
|
||||
error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64
|
||||
" (unknown type)", __func__, inv_desc->hi,
|
||||
inv_desc->lo);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
|
||||
|
||||
+1
-1
@@ -635,7 +635,7 @@ GlobalProperty microvm_properties[] = {
|
||||
*/
|
||||
{ "pcie-root-port", "io-reserve", "0" },
|
||||
{ TYPE_RAMFB_DEVICE, "use-legacy-x86-rom", "true" },
|
||||
{ TYPE_VFIO_PCI, "use-legacy-x86-rom", "true" },
|
||||
{ TYPE_VFIO_PCI_NOHOTPLUG, "use-legacy-x86-rom", "true" },
|
||||
};
|
||||
|
||||
static void microvm_class_init(ObjectClass *oc, const void *data)
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
|
||||
|
||||
static GlobalProperty pc_piix_compat_defaults[] = {
|
||||
{ TYPE_RAMFB_DEVICE, "use-legacy-x86-rom", "true" },
|
||||
{ TYPE_VFIO_PCI, "use-legacy-x86-rom", "true" },
|
||||
{ TYPE_VFIO_PCI_NOHOTPLUG, "use-legacy-x86-rom", "true" },
|
||||
};
|
||||
static const size_t pc_piix_compat_defaults_len =
|
||||
G_N_ELEMENTS(pc_piix_compat_defaults);
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@
|
||||
static GlobalProperty pc_q35_compat_defaults[] = {
|
||||
{ TYPE_VIRTIO_IOMMU_PCI, "aw-bits", "39" },
|
||||
{ TYPE_RAMFB_DEVICE, "use-legacy-x86-rom", "true" },
|
||||
{ TYPE_VFIO_PCI, "use-legacy-x86-rom", "true" },
|
||||
{ TYPE_VFIO_PCI_NOHOTPLUG, "use-legacy-x86-rom", "true" },
|
||||
};
|
||||
static const size_t pc_q35_compat_defaults_len =
|
||||
G_N_ELEMENTS(pc_q35_compat_defaults);
|
||||
|
||||
@@ -295,7 +295,7 @@ static void kvm_dist_putbmp(GICv3State *s, uint32_t offset,
|
||||
* the 1 bits.
|
||||
*/
|
||||
if (clroffset != 0) {
|
||||
reg = 0;
|
||||
reg = ~0;
|
||||
kvm_gicd_access(s, clroffset, ®, true);
|
||||
clroffset += 4;
|
||||
}
|
||||
@@ -387,8 +387,6 @@ static void kvm_arm_gicv3_put(GICv3State *s)
|
||||
reg = c->level;
|
||||
kvm_gic_line_level_access(s, 0, ncpu, ®, true);
|
||||
|
||||
reg = ~0;
|
||||
kvm_gicr_access(s, GICR_ICPENDR0, ncpu, ®, true);
|
||||
reg = c->gicr_ipendr0;
|
||||
kvm_gicr_access(s, GICR_ISPENDR0, ncpu, ®, true);
|
||||
|
||||
@@ -445,7 +443,7 @@ static void kvm_arm_gicv3_put(GICv3State *s)
|
||||
kvm_gic_put_line_level_bmp(s, s->level);
|
||||
|
||||
/* s->pending bitmap -> GICD_ISPENDRn */
|
||||
kvm_dist_putbmp(s, GICD_ISPENDR, GICD_ICPENDR, s->pending);
|
||||
kvm_dist_putbmp(s, GICD_ISPENDR, 0, s->pending);
|
||||
|
||||
/* s->active bitmap -> GICD_ISACTIVERn */
|
||||
kvm_dist_putbmp(s, GICD_ISACTIVER, GICD_ICACTIVER, s->active);
|
||||
|
||||
+16
-11
@@ -23,36 +23,41 @@ static void kvm_ipi_access_regs(void *opaque, bool write)
|
||||
LoongarchIPIState *lis = LOONGARCH_IPI(opaque);
|
||||
IPICore *core;
|
||||
uint64_t attr;
|
||||
int cpu, fd = lis->dev_fd;
|
||||
int i, cpu_index, fd = lis->dev_fd;
|
||||
|
||||
if (fd == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (cpu = 0; cpu < ipi->num_cpu; cpu++) {
|
||||
core = &ipi->cpu[cpu];
|
||||
attr = (cpu << 16) | CORE_STATUS_OFF;
|
||||
for (i = 0; i < ipi->num_cpu; i++) {
|
||||
core = &ipi->cpu[i];
|
||||
if (core->cpu == NULL) {
|
||||
continue;
|
||||
}
|
||||
cpu_index = i;
|
||||
|
||||
attr = (cpu_index << 16) | CORE_STATUS_OFF;
|
||||
kvm_ipi_access_reg(fd, attr, &core->status, write);
|
||||
|
||||
attr = (cpu << 16) | CORE_EN_OFF;
|
||||
attr = (cpu_index << 16) | CORE_EN_OFF;
|
||||
kvm_ipi_access_reg(fd, attr, &core->en, write);
|
||||
|
||||
attr = (cpu << 16) | CORE_SET_OFF;
|
||||
attr = (cpu_index << 16) | CORE_SET_OFF;
|
||||
kvm_ipi_access_reg(fd, attr, &core->set, write);
|
||||
|
||||
attr = (cpu << 16) | CORE_CLEAR_OFF;
|
||||
attr = (cpu_index << 16) | CORE_CLEAR_OFF;
|
||||
kvm_ipi_access_reg(fd, attr, &core->clear, write);
|
||||
|
||||
attr = (cpu << 16) | CORE_BUF_20;
|
||||
attr = (cpu_index << 16) | CORE_BUF_20;
|
||||
kvm_ipi_access_reg(fd, attr, &core->buf[0], write);
|
||||
|
||||
attr = (cpu << 16) | CORE_BUF_28;
|
||||
attr = (cpu_index << 16) | CORE_BUF_28;
|
||||
kvm_ipi_access_reg(fd, attr, &core->buf[2], write);
|
||||
|
||||
attr = (cpu << 16) | CORE_BUF_30;
|
||||
attr = (cpu_index << 16) | CORE_BUF_30;
|
||||
kvm_ipi_access_reg(fd, attr, &core->buf[4], write);
|
||||
|
||||
attr = (cpu << 16) | CORE_BUF_38;
|
||||
attr = (cpu_index << 16) | CORE_BUF_38;
|
||||
kvm_ipi_access_reg(fd, attr, &core->buf[6], write);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -470,14 +470,13 @@ static bool pnv_xive_is_cpu_enabled(PnvXive *xive, PowerPCCPU *cpu)
|
||||
return xive->regs[reg >> 3] & PPC_BIT(bit);
|
||||
}
|
||||
|
||||
static int pnv_xive_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
static bool pnv_xive_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
{
|
||||
PnvXive *xive = PNV_XIVE(xptr);
|
||||
PnvChip *chip = xive->chip;
|
||||
int count = 0;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < chip->nr_cores; i++) {
|
||||
@@ -510,17 +509,18 @@ static int pnv_xive_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: already found a "
|
||||
"thread context NVT %x/%x\n",
|
||||
nvt_blk, nvt_idx);
|
||||
return -1;
|
||||
match->count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
match->ring = ring;
|
||||
match->tctx = tctx;
|
||||
count++;
|
||||
match->count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return !!match->count;
|
||||
}
|
||||
|
||||
static uint32_t pnv_xive_presenter_get_config(XivePresenter *xptr)
|
||||
|
||||
+104
-36
@@ -101,12 +101,10 @@ static uint32_t pnv_xive2_block_id(PnvXive2 *xive)
|
||||
}
|
||||
|
||||
/*
|
||||
* Remote access to controllers. HW uses MMIOs. For now, a simple scan
|
||||
* of the chips is good enough.
|
||||
*
|
||||
* TODO: Block scope support
|
||||
* Remote access to INT controllers. HW uses MMIOs(?). For now, a simple
|
||||
* scan of all the chips INT controller is good enough.
|
||||
*/
|
||||
static PnvXive2 *pnv_xive2_get_remote(uint8_t blk)
|
||||
static PnvXive2 *pnv_xive2_get_remote(uint32_t vsd_type, hwaddr fwd_addr)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
|
||||
int i;
|
||||
@@ -115,10 +113,23 @@ static PnvXive2 *pnv_xive2_get_remote(uint8_t blk)
|
||||
Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]);
|
||||
PnvXive2 *xive = &chip10->xive;
|
||||
|
||||
if (pnv_xive2_block_id(xive) == blk) {
|
||||
/*
|
||||
* Is this the XIVE matching the forwarded VSD address is for this
|
||||
* VSD type
|
||||
*/
|
||||
if ((vsd_type == VST_ESB && fwd_addr == xive->esb_base) ||
|
||||
(vsd_type == VST_END && fwd_addr == xive->end_base) ||
|
||||
((vsd_type == VST_NVP ||
|
||||
vsd_type == VST_NVG) && fwd_addr == xive->nvpg_base) ||
|
||||
(vsd_type == VST_NVC && fwd_addr == xive->nvc_base)) {
|
||||
return xive;
|
||||
}
|
||||
}
|
||||
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"XIVE: >>>>> %s vsd_type %u fwd_addr 0x%"HWADDR_PRIx
|
||||
" NOT FOUND\n",
|
||||
__func__, vsd_type, fwd_addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -251,8 +262,7 @@ static uint64_t pnv_xive2_vst_addr(PnvXive2 *xive, uint32_t type, uint8_t blk,
|
||||
|
||||
/* Remote VST access */
|
||||
if (GETFIELD(VSD_MODE, vsd) == VSD_MODE_FORWARD) {
|
||||
xive = pnv_xive2_get_remote(blk);
|
||||
|
||||
xive = pnv_xive2_get_remote(type, (vsd & VSD_ADDRESS_MASK));
|
||||
return xive ? pnv_xive2_vst_addr(xive, type, blk, idx) : 0;
|
||||
}
|
||||
|
||||
@@ -595,20 +605,28 @@ static uint32_t pnv_xive2_get_config(Xive2Router *xrtr)
|
||||
{
|
||||
PnvXive2 *xive = PNV_XIVE2(xrtr);
|
||||
uint32_t cfg = 0;
|
||||
uint64_t reg = xive->cq_regs[CQ_XIVE_CFG >> 3];
|
||||
|
||||
if (xive->cq_regs[CQ_XIVE_CFG >> 3] & CQ_XIVE_CFG_GEN1_TIMA_OS) {
|
||||
if (reg & CQ_XIVE_CFG_GEN1_TIMA_OS) {
|
||||
cfg |= XIVE2_GEN1_TIMA_OS;
|
||||
}
|
||||
|
||||
if (xive->cq_regs[CQ_XIVE_CFG >> 3] & CQ_XIVE_CFG_EN_VP_SAVE_RESTORE) {
|
||||
if (reg & CQ_XIVE_CFG_EN_VP_SAVE_RESTORE) {
|
||||
cfg |= XIVE2_VP_SAVE_RESTORE;
|
||||
}
|
||||
|
||||
if (GETFIELD(CQ_XIVE_CFG_HYP_HARD_RANGE,
|
||||
xive->cq_regs[CQ_XIVE_CFG >> 3]) == CQ_XIVE_CFG_THREADID_8BITS) {
|
||||
if (GETFIELD(CQ_XIVE_CFG_HYP_HARD_RANGE, reg) ==
|
||||
CQ_XIVE_CFG_THREADID_8BITS) {
|
||||
cfg |= XIVE2_THREADID_8BITS;
|
||||
}
|
||||
|
||||
if (reg & CQ_XIVE_CFG_EN_VP_GRP_PRIORITY) {
|
||||
cfg |= XIVE2_EN_VP_GRP_PRIORITY;
|
||||
}
|
||||
|
||||
cfg = SETFIELD(XIVE2_VP_INT_PRIO, cfg,
|
||||
GETFIELD(CQ_XIVE_CFG_VP_INT_PRIO, reg));
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@@ -622,24 +640,28 @@ static bool pnv_xive2_is_cpu_enabled(PnvXive2 *xive, PowerPCCPU *cpu)
|
||||
return xive->tctxt_regs[reg >> 3] & PPC_BIT(bit);
|
||||
}
|
||||
|
||||
static int pnv_xive2_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
static bool pnv_xive2_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
{
|
||||
PnvXive2 *xive = PNV_XIVE2(xptr);
|
||||
PnvChip *chip = xive->chip;
|
||||
int count = 0;
|
||||
int i, j;
|
||||
bool gen1_tima_os =
|
||||
xive->cq_regs[CQ_XIVE_CFG >> 3] & CQ_XIVE_CFG_GEN1_TIMA_OS;
|
||||
static int next_start_core;
|
||||
static int next_start_thread;
|
||||
int start_core = next_start_core;
|
||||
int start_thread = next_start_thread;
|
||||
|
||||
for (i = 0; i < chip->nr_cores; i++) {
|
||||
PnvCore *pc = chip->cores[i];
|
||||
PnvCore *pc = chip->cores[(i + start_core) % chip->nr_cores];
|
||||
CPUCore *cc = CPU_CORE(pc);
|
||||
|
||||
for (j = 0; j < cc->nr_threads; j++) {
|
||||
PowerPCCPU *cpu = pc->threads[j];
|
||||
/* Start search for match with different thread each call */
|
||||
PowerPCCPU *cpu = pc->threads[(j + start_thread) % cc->nr_threads];
|
||||
XiveTCTX *tctx;
|
||||
int ring;
|
||||
|
||||
@@ -669,7 +691,8 @@ static int pnv_xive2_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
"thread context NVT %x/%x\n",
|
||||
nvt_blk, nvt_idx);
|
||||
/* Should set a FIR if we ever model it */
|
||||
return -1;
|
||||
match->count++;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* For a group notification, we need to know if the
|
||||
@@ -684,14 +707,23 @@ static int pnv_xive2_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
if (!match->tctx) {
|
||||
match->ring = ring;
|
||||
match->tctx = tctx;
|
||||
|
||||
next_start_thread = j + start_thread + 1;
|
||||
if (next_start_thread >= cc->nr_threads) {
|
||||
next_start_thread = 0;
|
||||
next_start_core = i + start_core + 1;
|
||||
if (next_start_core >= chip->nr_cores) {
|
||||
next_start_core = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
count++;
|
||||
match->count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return !!match->count;
|
||||
}
|
||||
|
||||
static uint32_t pnv_xive2_presenter_get_config(XivePresenter *xptr)
|
||||
@@ -1173,7 +1205,8 @@ static void pnv_xive2_ic_cq_write(void *opaque, hwaddr offset,
|
||||
case CQ_FIRMASK_OR: /* FIR error reporting */
|
||||
break;
|
||||
default:
|
||||
xive2_error(xive, "CQ: invalid write 0x%"HWADDR_PRIx, offset);
|
||||
xive2_error(xive, "CQ: invalid write 0x%"HWADDR_PRIx" value 0x%"PRIx64,
|
||||
offset, val);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1304,7 +1337,6 @@ static uint64_t pnv_xive2_ic_vc_read(void *opaque, hwaddr offset,
|
||||
case VC_ENDC_WATCH2_SPEC:
|
||||
case VC_ENDC_WATCH3_SPEC:
|
||||
watch_engine = (offset - VC_ENDC_WATCH0_SPEC) >> 6;
|
||||
xive->vc_regs[reg] &= ~(VC_ENDC_WATCH_FULL | VC_ENDC_WATCH_CONFLICT);
|
||||
pnv_xive2_endc_cache_watch_release(xive, watch_engine);
|
||||
val = xive->vc_regs[reg];
|
||||
break;
|
||||
@@ -1315,10 +1347,11 @@ static uint64_t pnv_xive2_ic_vc_read(void *opaque, hwaddr offset,
|
||||
case VC_ENDC_WATCH3_DATA0:
|
||||
/*
|
||||
* Load DATA registers from cache with data requested by the
|
||||
* SPEC register
|
||||
* SPEC register. Clear gen_flipped bit in word 1.
|
||||
*/
|
||||
watch_engine = (offset - VC_ENDC_WATCH0_DATA0) >> 6;
|
||||
pnv_xive2_end_cache_load(xive, watch_engine);
|
||||
xive->vc_regs[reg] &= ~(uint64_t)END2_W1_GEN_FLIPPED;
|
||||
val = xive->vc_regs[reg];
|
||||
break;
|
||||
|
||||
@@ -1386,7 +1419,14 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset,
|
||||
/*
|
||||
* ESB cache updates (not modeled)
|
||||
*/
|
||||
/* case VC_ESBC_FLUSH_CTRL: */
|
||||
case VC_ESBC_FLUSH_CTRL:
|
||||
if (val & VC_ESBC_FLUSH_CTRL_WANT_CACHE_DISABLE) {
|
||||
xive2_error(xive, "VC: unsupported write @0x%"HWADDR_PRIx
|
||||
" value 0x%"PRIx64" bit[2] poll_want_cache_disable",
|
||||
offset, val);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case VC_ESBC_FLUSH_POLL:
|
||||
xive->vc_regs[VC_ESBC_FLUSH_CTRL >> 3] |= VC_ESBC_FLUSH_CTRL_POLL_VALID;
|
||||
/* ESB update */
|
||||
@@ -1402,7 +1442,14 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset,
|
||||
/*
|
||||
* EAS cache updates (not modeled)
|
||||
*/
|
||||
/* case VC_EASC_FLUSH_CTRL: */
|
||||
case VC_EASC_FLUSH_CTRL:
|
||||
if (val & VC_EASC_FLUSH_CTRL_WANT_CACHE_DISABLE) {
|
||||
xive2_error(xive, "VC: unsupported write @0x%"HWADDR_PRIx
|
||||
" value 0x%"PRIx64" bit[2] poll_want_cache_disable",
|
||||
offset, val);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case VC_EASC_FLUSH_POLL:
|
||||
xive->vc_regs[VC_EASC_FLUSH_CTRL >> 3] |= VC_EASC_FLUSH_CTRL_POLL_VALID;
|
||||
/* EAS update */
|
||||
@@ -1441,7 +1488,14 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
|
||||
/* case VC_ENDC_FLUSH_CTRL: */
|
||||
case VC_ENDC_FLUSH_CTRL:
|
||||
if (val & VC_ENDC_FLUSH_CTRL_WANT_CACHE_DISABLE) {
|
||||
xive2_error(xive, "VC: unsupported write @0x%"HWADDR_PRIx
|
||||
" value 0x%"PRIx64" bit[2] poll_want_cache_disable",
|
||||
offset, val);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case VC_ENDC_FLUSH_POLL:
|
||||
xive->vc_regs[VC_ENDC_FLUSH_CTRL >> 3] |= VC_ENDC_FLUSH_CTRL_POLL_VALID;
|
||||
break;
|
||||
@@ -1470,7 +1524,8 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
default:
|
||||
xive2_error(xive, "VC: invalid write @%"HWADDR_PRIx, offset);
|
||||
xive2_error(xive, "VC: invalid write @0x%"HWADDR_PRIx" value 0x%"PRIx64,
|
||||
offset, val);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1661,7 +1716,14 @@ static void pnv_xive2_ic_pc_write(void *opaque, hwaddr offset,
|
||||
pnv_xive2_nxc_update(xive, watch_engine);
|
||||
break;
|
||||
|
||||
/* case PC_NXC_FLUSH_CTRL: */
|
||||
case PC_NXC_FLUSH_CTRL:
|
||||
if (val & PC_NXC_FLUSH_CTRL_WANT_CACHE_DISABLE) {
|
||||
xive2_error(xive, "VC: unsupported write @0x%"HWADDR_PRIx
|
||||
" value 0x%"PRIx64" bit[2] poll_want_cache_disable",
|
||||
offset, val);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case PC_NXC_FLUSH_POLL:
|
||||
xive->pc_regs[PC_NXC_FLUSH_CTRL >> 3] |= PC_NXC_FLUSH_CTRL_POLL_VALID;
|
||||
break;
|
||||
@@ -1678,7 +1740,8 @@ static void pnv_xive2_ic_pc_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
default:
|
||||
xive2_error(xive, "PC: invalid write @%"HWADDR_PRIx, offset);
|
||||
xive2_error(xive, "PC: invalid write @0x%"HWADDR_PRIx" value 0x%"PRIx64,
|
||||
offset, val);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1765,7 +1828,8 @@ static void pnv_xive2_ic_tctxt_write(void *opaque, hwaddr offset,
|
||||
xive->tctxt_regs[reg] = val;
|
||||
break;
|
||||
default:
|
||||
xive2_error(xive, "TCTXT: invalid write @%"HWADDR_PRIx, offset);
|
||||
xive2_error(xive, "TCTXT: invalid write @0x%"HWADDR_PRIx
|
||||
" data 0x%"PRIx64, offset, val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1836,7 +1900,8 @@ static void pnv_xive2_xscom_write(void *opaque, hwaddr offset,
|
||||
pnv_xive2_ic_tctxt_write(opaque, mmio_offset, val, size);
|
||||
break;
|
||||
default:
|
||||
xive2_error(xive, "XSCOM: invalid write @%"HWADDR_PRIx, offset);
|
||||
xive2_error(xive, "XSCOM: invalid write @%"HWADDR_PRIx
|
||||
" value 0x%"PRIx64, offset, val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1904,7 +1969,8 @@ static void pnv_xive2_ic_notify_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
default:
|
||||
xive2_error(xive, "NOTIFY: invalid write @%"HWADDR_PRIx, offset);
|
||||
xive2_error(xive, "NOTIFY: invalid write @%"HWADDR_PRIx
|
||||
" value 0x%"PRIx64, offset, val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1946,7 +2012,8 @@ static void pnv_xive2_ic_lsi_write(void *opaque, hwaddr offset,
|
||||
{
|
||||
PnvXive2 *xive = PNV_XIVE2(opaque);
|
||||
|
||||
xive2_error(xive, "LSI: invalid write @%"HWADDR_PRIx, offset);
|
||||
xive2_error(xive, "LSI: invalid write @%"HWADDR_PRIx" value 0x%"PRIx64,
|
||||
offset, val);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pnv_xive2_ic_lsi_ops = {
|
||||
@@ -2049,7 +2116,8 @@ static void pnv_xive2_ic_sync_write(void *opaque, hwaddr offset,
|
||||
inject_type = PNV_XIVE2_QUEUE_NXC_ST_RMT_CI;
|
||||
break;
|
||||
default:
|
||||
xive2_error(xive, "SYNC: invalid write @%"HWADDR_PRIx, offset);
|
||||
xive2_error(xive, "SYNC: invalid write @%"HWADDR_PRIx" value 0x%"PRIx64,
|
||||
offset, val);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
#define CQ_XIVE_CFG_GEN1_TIMA_HYP_BLK0 PPC_BIT(26) /* 0 if bit[25]=0 */
|
||||
#define CQ_XIVE_CFG_GEN1_TIMA_CROWD_DIS PPC_BIT(27) /* 0 if bit[25]=0 */
|
||||
#define CQ_XIVE_CFG_GEN1_END_ESX PPC_BIT(28)
|
||||
#define CQ_XIVE_CFG_EN_VP_GRP_PRIORITY PPC_BIT(32) /* 0 if bit[25]=1 */
|
||||
#define CQ_XIVE_CFG_EN_VP_SAVE_RESTORE PPC_BIT(38) /* 0 if bit[25]=1 */
|
||||
#define CQ_XIVE_CFG_EN_VP_SAVE_REST_STRICT PPC_BIT(39) /* 0 if bit[25]=1 */
|
||||
|
||||
|
||||
@@ -628,7 +628,7 @@ static void riscv_aplic_request(void *opaque, int irq, int level)
|
||||
|
||||
static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
uint32_t irq, word, idc;
|
||||
uint32_t irq, word, idc, sm;
|
||||
RISCVAPLICState *aplic = opaque;
|
||||
|
||||
/* Reads must be 4 byte words */
|
||||
@@ -696,6 +696,10 @@ static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size)
|
||||
} else if ((APLIC_TARGET_BASE <= addr) &&
|
||||
(addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) {
|
||||
irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1;
|
||||
sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK;
|
||||
if (sm == APLIC_SOURCECFG_SM_INACTIVE) {
|
||||
return 0;
|
||||
}
|
||||
return aplic->target[irq];
|
||||
} else if (!aplic->msimode && (APLIC_IDC_BASE <= addr) &&
|
||||
(addr < (APLIC_IDC_BASE + aplic->num_harts * APLIC_IDC_SIZE))) {
|
||||
|
||||
@@ -428,14 +428,13 @@ static int spapr_xive_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static int spapr_xive_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore,
|
||||
uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
static bool spapr_xive_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore,
|
||||
uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
{
|
||||
CPUState *cs;
|
||||
int count = 0;
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
@@ -463,16 +462,17 @@ static int spapr_xive_match_nvt(XivePresenter *xptr, uint8_t format,
|
||||
if (match->tctx) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: already found a thread "
|
||||
"context NVT %x/%x\n", nvt_blk, nvt_idx);
|
||||
return -1;
|
||||
match->count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
match->ring = ring;
|
||||
match->tctx = tctx;
|
||||
count++;
|
||||
match->count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return !!match->count;
|
||||
}
|
||||
|
||||
static uint32_t spapr_xive_presenter_get_config(XivePresenter *xptr)
|
||||
|
||||
@@ -274,11 +274,13 @@ kvm_xive_cpu_connect(uint32_t id) "connect CPU%d to KVM device"
|
||||
kvm_xive_source_reset(uint32_t srcno) "IRQ 0x%x"
|
||||
|
||||
# xive.c
|
||||
xive_tctx_accept(uint32_t index, uint8_t ring, uint8_t ipb, uint8_t pipr, uint8_t cppr, uint8_t nsr) "target=%d ring=0x%x IBP=0x%02x PIPR=0x%02x CPPR=0x%02x NSR=0x%02x ACK"
|
||||
xive_tctx_notify(uint32_t index, uint8_t ring, uint8_t ipb, uint8_t pipr, uint8_t cppr, uint8_t nsr) "target=%d ring=0x%x IBP=0x%02x PIPR=0x%02x CPPR=0x%02x NSR=0x%02x raise !"
|
||||
xive_tctx_set_cppr(uint32_t index, uint8_t ring, uint8_t ipb, uint8_t pipr, uint8_t cppr, uint8_t nsr) "target=%d ring=0x%x IBP=0x%02x PIPR=0x%02x new CPPR=0x%02x NSR=0x%02x"
|
||||
xive_tctx_accept(uint32_t index, uint8_t ring, uint8_t ipb, uint8_t pipr, uint8_t cppr, uint8_t nsr) "target=%d ring=0x%x IPB=0x%02x PIPR=0x%02x CPPR=0x%02x NSR=0x%02x ACK"
|
||||
xive_tctx_notify(uint32_t index, uint8_t ring, uint8_t ipb, uint8_t pipr, uint8_t cppr, uint8_t nsr) "target=%d ring=0x%x IPB=0x%02x PIPR=0x%02x CPPR=0x%02x NSR=0x%02x raise !"
|
||||
xive_tctx_set_cppr(uint32_t index, uint8_t ring, uint8_t ipb, uint8_t pipr, uint8_t cppr, uint8_t nsr) "target=%d ring=0x%x IPB=0x%02x PIPR=0x%02x new CPPR=0x%02x NSR=0x%02x"
|
||||
xive_source_esb_read(uint64_t addr, uint32_t srcno, uint64_t value) "@0x%"PRIx64" IRQ 0x%x val=0x%"PRIx64
|
||||
xive_source_esb_write(uint64_t addr, uint32_t srcno, uint64_t value) "@0x%"PRIx64" IRQ 0x%x val=0x%"PRIx64
|
||||
xive_source_notify(uint32_t srcno) "Processing notification for queued IRQ 0x%x"
|
||||
xive_source_blocked(uint32_t srcno) "No action needed for IRQ 0x%x currently"
|
||||
xive_router_end_notify(uint8_t end_blk, uint32_t end_idx, uint32_t end_data) "END 0x%02x/0x%04x -> enqueue 0x%08x"
|
||||
xive_router_end_escalate(uint8_t end_blk, uint32_t end_idx, uint8_t esc_blk, uint32_t esc_idx, uint32_t end_data) "END 0x%02x/0x%04x -> escalate END 0x%02x/0x%04x data 0x%08x"
|
||||
xive_tctx_tm_write(uint32_t index, uint64_t offset, unsigned int size, uint64_t value) "target=%d @0x%"PRIx64" sz=%d val=0x%" PRIx64
|
||||
@@ -289,6 +291,10 @@ xive_end_source_read(uint8_t end_blk, uint32_t end_idx, uint64_t addr) "END 0x%x
|
||||
# xive2.c
|
||||
xive_nvp_backlog_op(uint8_t blk, uint32_t idx, uint8_t op, uint8_t priority, uint8_t rc) "NVP 0x%x/0x%x operation=%d priority=%d rc=%d"
|
||||
xive_nvgc_backlog_op(bool c, uint8_t blk, uint32_t idx, uint8_t op, uint8_t priority, uint32_t rc) "NVGC crowd=%d 0x%x/0x%x operation=%d priority=%d rc=%d"
|
||||
xive_redistribute(uint32_t index, uint8_t ring, uint8_t end_blk, uint32_t end_idx) "Redistribute from target=%d ring=0x%x NVP 0x%x/0x%x"
|
||||
xive_end_enqueue(uint8_t end_blk, uint32_t end_idx, uint32_t end_data) "Queue event for END 0x%x/0x%x data=0x%x"
|
||||
xive_escalate_end(uint8_t end_blk, uint32_t end_idx, uint8_t esc_blk, uint32_t esc_idx, uint32_t esc_data) "Escalate from END 0x%x/0x%x to END 0x%x/0x%x data=0x%x"
|
||||
xive_escalate_esb(uint8_t end_blk, uint32_t end_idx, uint32_t lisn) "Escalate from END 0x%x/0x%x to LISN=0x%x"
|
||||
|
||||
# pnv_xive.c
|
||||
pnv_xive_ic_hw_trigger(uint64_t addr, uint64_t val) "@0x%"PRIx64" val=0x%"PRIx64
|
||||
|
||||
+359
-198
@@ -25,6 +25,58 @@
|
||||
/*
|
||||
* XIVE Thread Interrupt Management context
|
||||
*/
|
||||
bool xive_ring_valid(XiveTCTX *tctx, uint8_t ring)
|
||||
{
|
||||
uint8_t cur_ring;
|
||||
|
||||
for (cur_ring = ring; cur_ring <= TM_QW3_HV_PHYS;
|
||||
cur_ring += XIVE_TM_RING_SIZE) {
|
||||
if (!(tctx->regs[cur_ring + TM_WORD2] & 0x80)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xive_nsr_indicates_exception(uint8_t ring, uint8_t nsr)
|
||||
{
|
||||
switch (ring) {
|
||||
case TM_QW1_OS:
|
||||
return !!(nsr & TM_QW1_NSR_EO);
|
||||
case TM_QW2_HV_POOL:
|
||||
case TM_QW3_HV_PHYS:
|
||||
return !!(nsr & TM_QW3_NSR_HE);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
bool xive_nsr_indicates_group_exception(uint8_t ring, uint8_t nsr)
|
||||
{
|
||||
if ((nsr & TM_NSR_GRP_LVL) > 0) {
|
||||
g_assert(xive_nsr_indicates_exception(ring, nsr));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t xive_nsr_exception_ring(uint8_t ring, uint8_t nsr)
|
||||
{
|
||||
/* NSR determines if pool/phys ring is for phys or pool interrupt */
|
||||
if ((ring == TM_QW3_HV_PHYS) || (ring == TM_QW2_HV_POOL)) {
|
||||
uint8_t he = (nsr & TM_QW3_NSR_HE) >> 6;
|
||||
|
||||
if (he == TM_QW3_NSR_HE_PHYS) {
|
||||
return TM_QW3_HV_PHYS;
|
||||
} else if (he == TM_QW3_NSR_HE_POOL) {
|
||||
return TM_QW2_HV_POOL;
|
||||
} else {
|
||||
/* Don't support LSI mode */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
return ring;
|
||||
}
|
||||
|
||||
static qemu_irq xive_tctx_output(XiveTCTX *tctx, uint8_t ring)
|
||||
{
|
||||
@@ -41,74 +93,83 @@ static qemu_irq xive_tctx_output(XiveTCTX *tctx, uint8_t ring)
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring)
|
||||
/*
|
||||
* interrupt is accepted on the presentation ring, for PHYS ring the NSR
|
||||
* directs it to the PHYS or POOL rings.
|
||||
*/
|
||||
uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t sig_ring)
|
||||
{
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
uint8_t nsr = regs[TM_NSR];
|
||||
uint8_t *sig_regs = &tctx->regs[sig_ring];
|
||||
uint8_t nsr = sig_regs[TM_NSR];
|
||||
|
||||
qemu_irq_lower(xive_tctx_output(tctx, ring));
|
||||
g_assert(sig_ring == TM_QW1_OS || sig_ring == TM_QW3_HV_PHYS);
|
||||
|
||||
if (regs[TM_NSR] != 0) {
|
||||
uint8_t cppr = regs[TM_PIPR];
|
||||
uint8_t alt_ring;
|
||||
uint8_t *alt_regs;
|
||||
g_assert(tctx->regs[TM_QW2_HV_POOL + TM_NSR] == 0);
|
||||
g_assert(tctx->regs[TM_QW2_HV_POOL + TM_PIPR] == 0);
|
||||
g_assert(tctx->regs[TM_QW2_HV_POOL + TM_CPPR] == 0);
|
||||
|
||||
/* POOL interrupt uses IPB in QW2, POOL ring */
|
||||
if ((ring == TM_QW3_HV_PHYS) && (nsr & (TM_QW3_NSR_HE_POOL << 6))) {
|
||||
alt_ring = TM_QW2_HV_POOL;
|
||||
} else {
|
||||
alt_ring = ring;
|
||||
}
|
||||
alt_regs = &tctx->regs[alt_ring];
|
||||
if (xive_nsr_indicates_exception(sig_ring, nsr)) {
|
||||
uint8_t cppr = sig_regs[TM_PIPR];
|
||||
uint8_t ring;
|
||||
uint8_t *regs;
|
||||
|
||||
regs[TM_CPPR] = cppr;
|
||||
ring = xive_nsr_exception_ring(sig_ring, nsr);
|
||||
regs = &tctx->regs[ring];
|
||||
|
||||
sig_regs[TM_CPPR] = cppr;
|
||||
|
||||
/*
|
||||
* If the interrupt was for a specific VP, reset the pending
|
||||
* buffer bit, otherwise clear the logical server indicator
|
||||
*/
|
||||
if (regs[TM_NSR] & TM_NSR_GRP_LVL) {
|
||||
regs[TM_NSR] &= ~TM_NSR_GRP_LVL;
|
||||
} else {
|
||||
alt_regs[TM_IPB] &= ~xive_priority_to_ipb(cppr);
|
||||
if (!xive_nsr_indicates_group_exception(sig_ring, nsr)) {
|
||||
regs[TM_IPB] &= ~xive_priority_to_ipb(cppr);
|
||||
}
|
||||
|
||||
/* Drop the exception bit and any group/crowd */
|
||||
regs[TM_NSR] = 0;
|
||||
/* Clear the exception from NSR */
|
||||
sig_regs[TM_NSR] = 0;
|
||||
qemu_irq_lower(xive_tctx_output(tctx, sig_ring));
|
||||
|
||||
trace_xive_tctx_accept(tctx->cs->cpu_index, alt_ring,
|
||||
alt_regs[TM_IPB], regs[TM_PIPR],
|
||||
regs[TM_CPPR], regs[TM_NSR]);
|
||||
trace_xive_tctx_accept(tctx->cs->cpu_index, ring,
|
||||
regs[TM_IPB], sig_regs[TM_PIPR],
|
||||
sig_regs[TM_CPPR], sig_regs[TM_NSR]);
|
||||
}
|
||||
|
||||
return ((uint64_t)nsr << 8) | regs[TM_CPPR];
|
||||
return ((uint64_t)nsr << 8) | sig_regs[TM_CPPR];
|
||||
}
|
||||
|
||||
void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring, uint8_t group_level)
|
||||
/* Change PIPR and calculate NSR and irq based on PIPR, CPPR, group */
|
||||
void xive_tctx_pipr_set(XiveTCTX *tctx, uint8_t ring, uint8_t pipr,
|
||||
uint8_t group_level)
|
||||
{
|
||||
/* HV_POOL ring uses HV_PHYS NSR, CPPR and PIPR registers */
|
||||
uint8_t alt_ring = (ring == TM_QW2_HV_POOL) ? TM_QW3_HV_PHYS : ring;
|
||||
uint8_t *alt_regs = &tctx->regs[alt_ring];
|
||||
uint8_t *sig_regs = xive_tctx_signal_regs(tctx, ring);
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
|
||||
if (alt_regs[TM_PIPR] < alt_regs[TM_CPPR]) {
|
||||
g_assert(!xive_nsr_indicates_group_exception(ring, sig_regs[TM_NSR]));
|
||||
|
||||
sig_regs[TM_PIPR] = pipr;
|
||||
|
||||
if (pipr < sig_regs[TM_CPPR]) {
|
||||
switch (ring) {
|
||||
case TM_QW1_OS:
|
||||
regs[TM_NSR] = TM_QW1_NSR_EO | (group_level & 0x3F);
|
||||
sig_regs[TM_NSR] = TM_QW1_NSR_EO | (group_level & 0x3F);
|
||||
break;
|
||||
case TM_QW2_HV_POOL:
|
||||
alt_regs[TM_NSR] = (TM_QW3_NSR_HE_POOL << 6) | (group_level & 0x3F);
|
||||
sig_regs[TM_NSR] = (TM_QW3_NSR_HE_POOL << 6) | (group_level & 0x3F);
|
||||
break;
|
||||
case TM_QW3_HV_PHYS:
|
||||
regs[TM_NSR] = (TM_QW3_NSR_HE_PHYS << 6) | (group_level & 0x3F);
|
||||
sig_regs[TM_NSR] = (TM_QW3_NSR_HE_PHYS << 6) | (group_level & 0x3F);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
trace_xive_tctx_notify(tctx->cs->cpu_index, ring,
|
||||
regs[TM_IPB], alt_regs[TM_PIPR],
|
||||
alt_regs[TM_CPPR], alt_regs[TM_NSR]);
|
||||
regs[TM_IPB], pipr,
|
||||
sig_regs[TM_CPPR], sig_regs[TM_NSR]);
|
||||
qemu_irq_raise(xive_tctx_output(tctx, ring));
|
||||
} else {
|
||||
sig_regs[TM_NSR] = 0;
|
||||
qemu_irq_lower(xive_tctx_output(tctx, ring));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,25 +185,32 @@ void xive_tctx_reset_signal(XiveTCTX *tctx, uint8_t ring)
|
||||
|
||||
static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
|
||||
{
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
uint8_t *sig_regs = &tctx->regs[ring];
|
||||
uint8_t pipr_min;
|
||||
uint8_t ring_min;
|
||||
|
||||
g_assert(ring == TM_QW1_OS || ring == TM_QW3_HV_PHYS);
|
||||
|
||||
g_assert(tctx->regs[TM_QW2_HV_POOL + TM_NSR] == 0);
|
||||
g_assert(tctx->regs[TM_QW2_HV_POOL + TM_PIPR] == 0);
|
||||
g_assert(tctx->regs[TM_QW2_HV_POOL + TM_CPPR] == 0);
|
||||
|
||||
/* XXX: should show pool IPB for PHYS ring */
|
||||
trace_xive_tctx_set_cppr(tctx->cs->cpu_index, ring,
|
||||
regs[TM_IPB], regs[TM_PIPR],
|
||||
cppr, regs[TM_NSR]);
|
||||
sig_regs[TM_IPB], sig_regs[TM_PIPR],
|
||||
cppr, sig_regs[TM_NSR]);
|
||||
|
||||
if (cppr > XIVE_PRIORITY_MAX) {
|
||||
cppr = 0xff;
|
||||
}
|
||||
|
||||
tctx->regs[ring + TM_CPPR] = cppr;
|
||||
sig_regs[TM_CPPR] = cppr;
|
||||
|
||||
/*
|
||||
* Recompute the PIPR based on local pending interrupts. The PHYS
|
||||
* ring must take the minimum of both the PHYS and POOL PIPR values.
|
||||
*/
|
||||
pipr_min = xive_ipb_to_pipr(regs[TM_IPB]);
|
||||
pipr_min = xive_ipb_to_pipr(sig_regs[TM_IPB]);
|
||||
ring_min = ring;
|
||||
|
||||
/* PHYS updates also depend on POOL values */
|
||||
@@ -151,7 +219,6 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
|
||||
|
||||
/* POOL values only matter if POOL ctx is valid */
|
||||
if (pool_regs[TM_WORD2] & 0x80) {
|
||||
|
||||
uint8_t pool_pipr = xive_ipb_to_pipr(pool_regs[TM_IPB]);
|
||||
|
||||
/*
|
||||
@@ -165,30 +232,39 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
|
||||
}
|
||||
}
|
||||
|
||||
regs[TM_PIPR] = pipr_min;
|
||||
|
||||
/* CPPR has changed, check if we need to raise a pending exception */
|
||||
xive_tctx_notify(tctx, ring_min, 0);
|
||||
/* CPPR has changed, this may present or preclude a pending exception */
|
||||
xive_tctx_pipr_set(tctx, ring_min, pipr_min, 0);
|
||||
}
|
||||
|
||||
void xive_tctx_pipr_update(XiveTCTX *tctx, uint8_t ring, uint8_t priority,
|
||||
uint8_t group_level)
|
||||
{
|
||||
/* HV_POOL ring uses HV_PHYS NSR, CPPR and PIPR registers */
|
||||
uint8_t alt_ring = (ring == TM_QW2_HV_POOL) ? TM_QW3_HV_PHYS : ring;
|
||||
uint8_t *alt_regs = &tctx->regs[alt_ring];
|
||||
static void xive_tctx_pipr_recompute_from_ipb(XiveTCTX *tctx, uint8_t ring)
|
||||
{
|
||||
uint8_t *sig_regs = xive_tctx_signal_regs(tctx, ring);
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
|
||||
/* Does not support a presented group interrupt */
|
||||
g_assert(!xive_nsr_indicates_group_exception(ring, sig_regs[TM_NSR]));
|
||||
|
||||
xive_tctx_pipr_set(tctx, ring, xive_ipb_to_pipr(regs[TM_IPB]), 0);
|
||||
}
|
||||
|
||||
void xive_tctx_pipr_present(XiveTCTX *tctx, uint8_t ring, uint8_t priority,
|
||||
uint8_t group_level)
|
||||
{
|
||||
uint8_t *sig_regs = xive_tctx_signal_regs(tctx, ring);
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
uint8_t pipr = xive_priority_to_pipr(priority);
|
||||
|
||||
if (group_level == 0) {
|
||||
/* VP-specific */
|
||||
regs[TM_IPB] |= xive_priority_to_ipb(priority);
|
||||
alt_regs[TM_PIPR] = xive_ipb_to_pipr(regs[TM_IPB]);
|
||||
} else {
|
||||
/* VP-group */
|
||||
alt_regs[TM_PIPR] = xive_priority_to_pipr(priority);
|
||||
if (pipr >= sig_regs[TM_PIPR]) {
|
||||
/* VP interrupts can come here with lower priority than PIPR */
|
||||
return;
|
||||
}
|
||||
}
|
||||
xive_tctx_notify(tctx, ring, group_level);
|
||||
}
|
||||
g_assert(pipr <= xive_ipb_to_pipr(regs[TM_IPB]));
|
||||
g_assert(pipr < sig_regs[TM_PIPR]);
|
||||
xive_tctx_pipr_set(tctx, ring, pipr, group_level);
|
||||
}
|
||||
|
||||
/*
|
||||
* XIVE Thread Interrupt Management Area (TIMA)
|
||||
@@ -206,25 +282,78 @@ static uint64_t xive_tm_ack_hv_reg(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
return xive_tctx_accept(tctx, TM_QW3_HV_PHYS);
|
||||
}
|
||||
|
||||
static void xive_pool_cam_decode(uint32_t cam, uint8_t *nvt_blk,
|
||||
uint32_t *nvt_idx, bool *vp)
|
||||
{
|
||||
if (nvt_blk) {
|
||||
*nvt_blk = xive_nvt_blk(cam);
|
||||
}
|
||||
if (nvt_idx) {
|
||||
*nvt_idx = xive_nvt_idx(cam);
|
||||
}
|
||||
if (vp) {
|
||||
*vp = !!(cam & TM_QW2W2_VP);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t xive_tctx_get_pool_cam(XiveTCTX *tctx, uint8_t *nvt_blk,
|
||||
uint32_t *nvt_idx, bool *vp)
|
||||
{
|
||||
uint32_t qw2w2 = xive_tctx_word2(&tctx->regs[TM_QW2_HV_POOL]);
|
||||
uint32_t cam = be32_to_cpu(qw2w2);
|
||||
|
||||
xive_pool_cam_decode(cam, nvt_blk, nvt_idx, vp);
|
||||
return qw2w2;
|
||||
}
|
||||
|
||||
static void xive_tctx_set_pool_cam(XiveTCTX *tctx, uint32_t qw2w2)
|
||||
{
|
||||
memcpy(&tctx->regs[TM_QW2_HV_POOL + TM_WORD2], &qw2w2, 4);
|
||||
}
|
||||
|
||||
static uint64_t xive_tm_pull_pool_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, unsigned size)
|
||||
{
|
||||
uint32_t qw2w2_prev = xive_tctx_word2(&tctx->regs[TM_QW2_HV_POOL]);
|
||||
uint32_t qw2w2;
|
||||
uint32_t qw2w2_new;
|
||||
uint8_t nvt_blk;
|
||||
uint32_t nvt_idx;
|
||||
bool vp;
|
||||
|
||||
qw2w2 = xive_tctx_get_pool_cam(tctx, &nvt_blk, &nvt_idx, &vp);
|
||||
|
||||
if (!vp) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: pull invalid POOL NVT %x/%x !?\n",
|
||||
nvt_blk, nvt_idx);
|
||||
}
|
||||
|
||||
/* Invalidate CAM line */
|
||||
qw2w2_new = xive_set_field32(TM_QW2W2_VP, qw2w2, 0);
|
||||
xive_tctx_set_pool_cam(tctx, qw2w2_new);
|
||||
|
||||
xive_tctx_reset_signal(tctx, TM_QW1_OS);
|
||||
xive_tctx_reset_signal(tctx, TM_QW2_HV_POOL);
|
||||
/* Re-check phys for interrupts if pool was disabled */
|
||||
xive_tctx_pipr_recompute_from_ipb(tctx, TM_QW3_HV_PHYS);
|
||||
|
||||
qw2w2 = xive_set_field32(TM_QW2W2_VP, qw2w2_prev, 0);
|
||||
memcpy(&tctx->regs[TM_QW2_HV_POOL + TM_WORD2], &qw2w2, 4);
|
||||
return qw2w2;
|
||||
}
|
||||
|
||||
static uint64_t xive_tm_pull_phys_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, unsigned size)
|
||||
{
|
||||
uint8_t qw3b8_prev = tctx->regs[TM_QW3_HV_PHYS + TM_WORD2];
|
||||
uint8_t qw3b8;
|
||||
uint8_t qw3b8 = tctx->regs[TM_QW3_HV_PHYS + TM_WORD2];
|
||||
uint8_t qw3b8_new;
|
||||
|
||||
qw3b8 = qw3b8_prev & ~TM_QW3B8_VT;
|
||||
tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] = qw3b8;
|
||||
qw3b8 = tctx->regs[TM_QW3_HV_PHYS + TM_WORD2];
|
||||
if (!(qw3b8 & TM_QW3B8_VT)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: pulling invalid PHYS thread!?\n");
|
||||
}
|
||||
qw3b8_new = qw3b8 & ~TM_QW3B8_VT;
|
||||
tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] = qw3b8_new;
|
||||
|
||||
xive_tctx_reset_signal(tctx, TM_QW1_OS);
|
||||
xive_tctx_reset_signal(tctx, TM_QW3_HV_PHYS);
|
||||
return qw3b8;
|
||||
}
|
||||
|
||||
@@ -255,14 +384,14 @@ static uint64_t xive_tm_vt_poll(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
|
||||
static const uint8_t xive_tm_hw_view[] = {
|
||||
3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-0 User */
|
||||
3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-1 OS */
|
||||
3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 3, /* QW-1 OS */
|
||||
0, 0, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
|
||||
3, 3, 3, 3, 0, 3, 0, 2, 3, 0, 0, 3, 3, 3, 3, 0, /* QW-3 PHYS */
|
||||
};
|
||||
|
||||
static const uint8_t xive_tm_hv_view[] = {
|
||||
3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-0 User */
|
||||
3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-1 OS */
|
||||
3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 3, /* QW-1 OS */
|
||||
0, 0, 3, 3, 0, 3, 3, 0, 0, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
|
||||
3, 3, 3, 3, 0, 3, 0, 2, 3, 0, 0, 3, 0, 0, 0, 0, /* QW-3 PHYS */
|
||||
};
|
||||
@@ -326,7 +455,7 @@ static void xive_tm_raw_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
|
||||
*/
|
||||
if (size < 4 || !mask || ring_offset == TM_QW0_USER) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA @%"
|
||||
HWADDR_PRIx"\n", offset);
|
||||
HWADDR_PRIx" size %d\n", offset, size);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -357,7 +486,7 @@ static uint64_t xive_tm_raw_read(XiveTCTX *tctx, hwaddr offset, unsigned size)
|
||||
*/
|
||||
if (size < 4 || !mask || ring_offset == TM_QW0_USER) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid read access at TIMA @%"
|
||||
HWADDR_PRIx"\n", offset);
|
||||
HWADDR_PRIx" size %d\n", offset, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -403,6 +532,12 @@ static void xive_tm_set_os_lgs(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
xive_tctx_set_lgs(tctx, TM_QW1_OS, value & 0xff);
|
||||
}
|
||||
|
||||
static void xive_tm_set_pool_lgs(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size)
|
||||
{
|
||||
xive_tctx_set_lgs(tctx, TM_QW2_HV_POOL, value & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the PIPR to allow a CPU to process event queues of other
|
||||
* priorities during one physical interrupt cycle.
|
||||
@@ -410,7 +545,12 @@ static void xive_tm_set_os_lgs(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
static void xive_tm_set_os_pending(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size)
|
||||
{
|
||||
xive_tctx_pipr_update(tctx, TM_QW1_OS, value & 0xff, 0);
|
||||
uint8_t ring = TM_QW1_OS;
|
||||
uint8_t *regs = &tctx->regs[ring];
|
||||
|
||||
/* XXX: how should this work exactly? */
|
||||
regs[TM_IPB] |= xive_priority_to_ipb(value & 0xff);
|
||||
xive_tctx_pipr_recompute_from_ipb(tctx, ring);
|
||||
}
|
||||
|
||||
static void xive_os_cam_decode(uint32_t cam, uint8_t *nvt_blk,
|
||||
@@ -454,7 +594,7 @@ static uint64_t xive_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
qw1w2 = xive_tctx_get_os_cam(tctx, &nvt_blk, &nvt_idx, &vo);
|
||||
|
||||
if (!vo) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: pulling invalid NVT %x/%x !?\n",
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: pull invalid OS NVT %x/%x !?\n",
|
||||
nvt_blk, nvt_idx);
|
||||
}
|
||||
|
||||
@@ -466,7 +606,7 @@ static uint64_t xive_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
return qw1w2;
|
||||
}
|
||||
|
||||
static void xive_tctx_need_resend(XiveRouter *xrtr, XiveTCTX *tctx,
|
||||
static void xive_tctx_restore_nvp(XiveRouter *xrtr, XiveTCTX *tctx,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx)
|
||||
{
|
||||
XiveNVT nvt;
|
||||
@@ -492,16 +632,6 @@ static void xive_tctx_need_resend(XiveRouter *xrtr, XiveTCTX *tctx,
|
||||
uint8_t *regs = &tctx->regs[TM_QW1_OS];
|
||||
regs[TM_IPB] |= ipb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Always call xive_tctx_pipr_update(). Even if there were no
|
||||
* escalation triggered, there could be a pending interrupt which
|
||||
* was saved when the context was pulled and that we need to take
|
||||
* into account by recalculating the PIPR (which is not
|
||||
* saved/restored).
|
||||
* It will also raise the External interrupt signal if needed.
|
||||
*/
|
||||
xive_tctx_pipr_update(tctx, TM_QW1_OS, 0xFF, 0); /* fxb */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -523,7 +653,17 @@ static void xive_tm_push_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
|
||||
/* Check the interrupt pending bits */
|
||||
if (vo) {
|
||||
xive_tctx_need_resend(XIVE_ROUTER(xptr), tctx, nvt_blk, nvt_idx);
|
||||
xive_tctx_restore_nvp(XIVE_ROUTER(xptr), tctx, nvt_blk, nvt_idx);
|
||||
|
||||
/*
|
||||
* Always call xive_tctx_recompute_from_ipb(). Even if there were no
|
||||
* escalation triggered, there could be a pending interrupt which
|
||||
* was saved when the context was pulled and that we need to take
|
||||
* into account by recalculating the PIPR (which is not
|
||||
* saved/restored).
|
||||
* It will also raise the External interrupt signal if needed.
|
||||
*/
|
||||
xive_tctx_pipr_recompute_from_ipb(tctx, TM_QW1_OS); /* fxb */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,6 +682,8 @@ typedef struct XiveTmOp {
|
||||
uint8_t page_offset;
|
||||
uint32_t op_offset;
|
||||
unsigned size;
|
||||
bool hw_ok;
|
||||
bool sw_ok;
|
||||
void (*write_handler)(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset,
|
||||
uint64_t value, unsigned size);
|
||||
@@ -554,34 +696,34 @@ static const XiveTmOp xive_tm_operations[] = {
|
||||
* MMIOs below 2K : raw values and special operations without side
|
||||
* effects
|
||||
*/
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive_tm_push_os_ctx,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL,
|
||||
xive_tm_vt_poll },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, true, true,
|
||||
xive_tm_set_os_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, true, true,
|
||||
xive_tm_push_os_ctx, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, true, true,
|
||||
xive_tm_set_hv_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, false, true,
|
||||
xive_tm_vt_push, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, true, true,
|
||||
NULL, xive_tm_vt_poll },
|
||||
|
||||
/* MMIOs above 2K : special operations with side effects */
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL,
|
||||
xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL,
|
||||
xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL,
|
||||
xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL,
|
||||
xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, NULL,
|
||||
xive_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, true, false,
|
||||
NULL, xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, true, false,
|
||||
xive_tm_set_os_pending, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, true, false,
|
||||
NULL, xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, true, false,
|
||||
NULL, xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, true, false,
|
||||
NULL, xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, true, false,
|
||||
NULL, xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, true, false,
|
||||
NULL, xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, true, false,
|
||||
NULL, xive_tm_pull_phys_ctx },
|
||||
};
|
||||
|
||||
static const XiveTmOp xive2_tm_operations[] = {
|
||||
@@ -589,50 +731,58 @@ static const XiveTmOp xive2_tm_operations[] = {
|
||||
* MMIOs below 2K : raw values and special operations without side
|
||||
* effects
|
||||
*/
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive2_tm_set_os_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive2_tm_push_os_ctx,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 8, xive2_tm_push_os_ctx,
|
||||
NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_LGS, 1, xive_tm_set_os_lgs,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive2_tm_set_hv_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL,
|
||||
xive_tm_vt_poll },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_T, 1, xive2_tm_set_hv_target,
|
||||
NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, true, true,
|
||||
xive2_tm_set_os_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, true, true,
|
||||
xive2_tm_push_os_ctx, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 8, true, true,
|
||||
xive2_tm_push_os_ctx, NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_LGS, 1, true, true,
|
||||
xive_tm_set_os_lgs, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW2_HV_POOL + TM_WORD2, 4, true, true,
|
||||
xive2_tm_push_pool_ctx, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW2_HV_POOL + TM_WORD2, 8, true, true,
|
||||
xive2_tm_push_pool_ctx, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW2_HV_POOL + TM_LGS, 1, true, true,
|
||||
xive_tm_set_pool_lgs, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, true, true,
|
||||
xive2_tm_set_hv_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, false, true,
|
||||
xive2_tm_push_phys_ctx, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, true, true,
|
||||
NULL, xive_tm_vt_poll },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_T, 1, true, true,
|
||||
xive2_tm_set_hv_target, NULL },
|
||||
|
||||
/* MMIOs above 2K : special operations with side effects */
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL,
|
||||
xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_G2, 4, NULL,
|
||||
xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL,
|
||||
xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL,
|
||||
xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL,
|
||||
xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX_G2, 4, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_OL, 1, xive2_tm_pull_os_ctx_ol,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_G2, 4, NULL,
|
||||
xive_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, NULL,
|
||||
xive_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_OL, 1, xive2_tm_pull_phys_ctx_ol,
|
||||
NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, true, false,
|
||||
NULL, xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, true, false,
|
||||
xive2_tm_set_os_pending, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_G2, 4, true, false,
|
||||
NULL, xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, true, false,
|
||||
NULL, xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, true, false,
|
||||
NULL, xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, true, false,
|
||||
NULL, xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX_G2, 4, true, false,
|
||||
NULL, xive2_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, true, false,
|
||||
NULL, xive2_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, true, false,
|
||||
NULL, xive2_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_OL, 1, true, false,
|
||||
xive2_tm_pull_os_ctx_ol, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_G2, 4, true, false,
|
||||
NULL, xive2_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, true, false,
|
||||
NULL, xive2_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_OL, 1, true, false,
|
||||
xive2_tm_pull_phys_ctx_ol, NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_EL, 1, true, false,
|
||||
xive2_tm_ack_os_el, NULL },
|
||||
};
|
||||
|
||||
static const XiveTmOp *xive_tm_find_op(XivePresenter *xptr, hwaddr offset,
|
||||
@@ -674,21 +824,31 @@ void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
const XiveTmOp *xto;
|
||||
uint8_t ring = offset & TM_RING_OFFSET;
|
||||
bool is_valid = xive_ring_valid(tctx, ring);
|
||||
bool hw_owned = is_valid;
|
||||
|
||||
trace_xive_tctx_tm_write(tctx->cs->cpu_index, offset, size, value);
|
||||
|
||||
/*
|
||||
* TODO: check V bit in Q[0-3]W2
|
||||
*/
|
||||
|
||||
/*
|
||||
* First, check for special operations in the 2K region
|
||||
*/
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, true);
|
||||
if (xto) {
|
||||
if (hw_owned && !xto->hw_ok) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined write to HW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
if (!hw_owned && !xto->sw_ok) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined write to SW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (offset & TM_SPECIAL_OP) {
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, true);
|
||||
if (!xto) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA "
|
||||
"@%"HWADDR_PRIx"\n", offset);
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
} else {
|
||||
xto->write_handler(xptr, tctx, offset, value, size);
|
||||
}
|
||||
@@ -698,7 +858,6 @@ void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
/*
|
||||
* Then, for special operations in the region below 2K.
|
||||
*/
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, true);
|
||||
if (xto) {
|
||||
xto->write_handler(xptr, tctx, offset, value, size);
|
||||
return;
|
||||
@@ -707,6 +866,11 @@ void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
/*
|
||||
* Finish with raw access to the register values
|
||||
*/
|
||||
if (hw_owned) {
|
||||
/* Store context operations are dangerous when context is valid */
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined write to HW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
xive_tm_raw_write(tctx, offset, value, size);
|
||||
}
|
||||
|
||||
@@ -714,20 +878,30 @@ uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
const XiveTmOp *xto;
|
||||
uint8_t ring = offset & TM_RING_OFFSET;
|
||||
bool is_valid = xive_ring_valid(tctx, ring);
|
||||
bool hw_owned = is_valid;
|
||||
uint64_t ret;
|
||||
|
||||
/*
|
||||
* TODO: check V bit in Q[0-3]W2
|
||||
*/
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, false);
|
||||
if (xto) {
|
||||
if (hw_owned && !xto->hw_ok) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined read to HW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
if (!hw_owned && !xto->sw_ok) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined read to SW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* First, check for special operations in the 2K region
|
||||
*/
|
||||
if (offset & TM_SPECIAL_OP) {
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, false);
|
||||
if (!xto) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid read access to TIMA"
|
||||
"@%"HWADDR_PRIx"\n", offset);
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
return -1;
|
||||
}
|
||||
ret = xto->read_handler(xptr, tctx, offset, size);
|
||||
@@ -737,7 +911,6 @@ uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
/*
|
||||
* Then, for special operations in the region below 2K.
|
||||
*/
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, false);
|
||||
if (xto) {
|
||||
ret = xto->read_handler(xptr, tctx, offset, size);
|
||||
goto out;
|
||||
@@ -1191,6 +1364,7 @@ static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)
|
||||
|
||||
/* Forward the source event notification for routing */
|
||||
if (ret) {
|
||||
trace_xive_source_notify(srcno);
|
||||
xive_source_notify(xsrc, srcno);
|
||||
}
|
||||
break;
|
||||
@@ -1286,6 +1460,8 @@ out:
|
||||
/* Forward the source event notification for routing */
|
||||
if (notify) {
|
||||
xive_source_notify(xsrc, srcno);
|
||||
} else {
|
||||
trace_xive_source_blocked(srcno);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1672,8 +1848,8 @@ uint32_t xive_get_vpgroup_size(uint32_t nvp_index)
|
||||
return 1U << (first_zero + 1);
|
||||
}
|
||||
|
||||
static uint8_t xive_get_group_level(bool crowd, bool ignore,
|
||||
uint32_t nvp_blk, uint32_t nvp_index)
|
||||
uint8_t xive_get_group_level(bool crowd, bool ignore,
|
||||
uint32_t nvp_blk, uint32_t nvp_index)
|
||||
{
|
||||
int first_zero;
|
||||
uint8_t level;
|
||||
@@ -1791,15 +1967,14 @@ int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
* This is our simple Xive Presenter Engine model. It is merged in the
|
||||
* Router as it does not require an extra object.
|
||||
*/
|
||||
bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
|
||||
bool xive_presenter_match(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, bool *precluded)
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
{
|
||||
XiveFabricClass *xfc = XIVE_FABRIC_GET_CLASS(xfb);
|
||||
XiveTCTXMatch match = { .tctx = NULL, .ring = 0, .precluded = false };
|
||||
uint8_t group_level;
|
||||
int count;
|
||||
|
||||
memset(match, 0, sizeof(*match));
|
||||
|
||||
/*
|
||||
* Ask the machine to scan the interrupt controllers for a match.
|
||||
@@ -1824,22 +1999,8 @@ bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
|
||||
* a new command to the presenters (the equivalent of the "assign"
|
||||
* power bus command in the documented full notify sequence.
|
||||
*/
|
||||
count = xfc->match_nvt(xfb, format, nvt_blk, nvt_idx, crowd, cam_ignore,
|
||||
priority, logic_serv, &match);
|
||||
if (count < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* handle CPU exception delivery */
|
||||
if (count) {
|
||||
group_level = xive_get_group_level(crowd, cam_ignore, nvt_blk, nvt_idx);
|
||||
trace_xive_presenter_notify(nvt_blk, nvt_idx, match.ring, group_level);
|
||||
xive_tctx_pipr_update(match.tctx, match.ring, priority, group_level);
|
||||
} else {
|
||||
*precluded = match.precluded;
|
||||
}
|
||||
|
||||
return !!count;
|
||||
return xfc->match_nvt(xfb, format, nvt_blk, nvt_idx, crowd, cam_ignore,
|
||||
priority, logic_serv, match);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1876,7 +2037,7 @@ void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas)
|
||||
uint8_t nvt_blk;
|
||||
uint32_t nvt_idx;
|
||||
XiveNVT nvt;
|
||||
bool found, precluded;
|
||||
XiveTCTXMatch match;
|
||||
|
||||
uint8_t end_blk = xive_get_field64(EAS_END_BLOCK, eas->w);
|
||||
uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w);
|
||||
@@ -1956,16 +2117,16 @@ void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas)
|
||||
return;
|
||||
}
|
||||
|
||||
found = xive_presenter_notify(xrtr->xfb, format, nvt_blk, nvt_idx,
|
||||
false /* crowd */,
|
||||
xive_get_field32(END_W7_F0_IGNORE, end.w7),
|
||||
priority,
|
||||
xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7),
|
||||
&precluded);
|
||||
/* we don't support VP-group notification on P9, so precluded is not used */
|
||||
/* TODO: Auto EOI. */
|
||||
|
||||
if (found) {
|
||||
/* we don't support VP-group notification on P9, so precluded is not used */
|
||||
if (xive_presenter_match(xrtr->xfb, format, nvt_blk, nvt_idx,
|
||||
false /* crowd */,
|
||||
xive_get_field32(END_W7_F0_IGNORE, end.w7),
|
||||
priority,
|
||||
xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7),
|
||||
&match)) {
|
||||
trace_xive_presenter_notify(nvt_blk, nvt_idx, match.ring, 0);
|
||||
xive_tctx_pipr_present(match.tctx, match.ring, priority, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+551
-168
File diff suppressed because it is too large
Load Diff
@@ -1756,6 +1756,7 @@ static void gem_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
|
||||
}
|
||||
|
||||
gem_init_register_masks(s);
|
||||
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||
|
||||
s->nic = qemu_new_nic(&net_gem_info, &s->conf,
|
||||
@@ -1776,7 +1777,6 @@ static void gem_init(Object *obj)
|
||||
|
||||
DB_PRINT("\n");
|
||||
|
||||
gem_init_register_masks(s);
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &gem_ops, s,
|
||||
"enet", sizeof(s->regs));
|
||||
|
||||
|
||||
+4
-3
@@ -929,8 +929,9 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
|
||||
vhost_net_save_acked_features(nc->peer);
|
||||
}
|
||||
|
||||
if (!virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) {
|
||||
memset(n->vlans, 0xff, MAX_VLAN >> 3);
|
||||
if (virtio_has_feature(vdev->guest_features ^ features, VIRTIO_NET_F_CTRL_VLAN)) {
|
||||
bool vlan = virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN);
|
||||
memset(n->vlans, vlan ? 0 : 0xff, MAX_VLAN >> 3);
|
||||
}
|
||||
|
||||
if (virtio_has_feature(features, VIRTIO_NET_F_STANDBY)) {
|
||||
@@ -3942,6 +3943,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
|
||||
n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
|
||||
|
||||
n->vlans = g_malloc0(MAX_VLAN >> 3);
|
||||
memset(n->vlans, 0xff, MAX_VLAN >> 3);
|
||||
|
||||
nc = qemu_get_queue(n->nic);
|
||||
nc->rxfilter_notify_enabled = 1;
|
||||
@@ -4041,7 +4043,6 @@ static void virtio_net_reset(VirtIODevice *vdev)
|
||||
memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
|
||||
memcpy(&n->mac[0], &n->nic->conf->macaddr, sizeof(n->mac));
|
||||
qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
|
||||
memset(n->vlans, 0, MAX_VLAN >> 3);
|
||||
|
||||
/* Flush any async TX */
|
||||
for (i = 0; i < n->max_queue_pairs; i++) {
|
||||
|
||||
+28
-15
@@ -6816,7 +6816,7 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
|
||||
|
||||
switch (sel) {
|
||||
case NVME_NS_ATTACHMENT_ATTACH:
|
||||
if (nvme_ns(n, nsid)) {
|
||||
if (nvme_ns(ctrl, nsid)) {
|
||||
return NVME_NS_ALREADY_ATTACHED | NVME_DNR;
|
||||
}
|
||||
|
||||
@@ -6824,7 +6824,7 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
|
||||
return NVME_NS_PRIVATE | NVME_DNR;
|
||||
}
|
||||
|
||||
if (!nvme_csi_supported(n, ns->csi)) {
|
||||
if (!nvme_csi_supported(ctrl, ns->csi)) {
|
||||
return NVME_IOCS_NOT_SUPPORTED | NVME_DNR;
|
||||
}
|
||||
|
||||
@@ -6834,6 +6834,10 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
|
||||
break;
|
||||
|
||||
case NVME_NS_ATTACHMENT_DETACH:
|
||||
if (!nvme_ns(ctrl, nsid)) {
|
||||
return NVME_NS_NOT_ATTACHED | NVME_DNR;
|
||||
}
|
||||
|
||||
nvme_detach_ns(ctrl, ns);
|
||||
nvme_update_dsm_limits(ctrl, NULL);
|
||||
|
||||
@@ -8335,6 +8339,11 @@ static bool nvme_check_params(NvmeCtrl *n, Error **errp)
|
||||
host_memory_backend_set_mapped(n->pmr.dev, true);
|
||||
}
|
||||
|
||||
if (!n->params.mdts || ((1 << n->params.mdts) + 1) > IOV_MAX) {
|
||||
error_setg(errp, "mdts exceeds IOV_MAX");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n->params.zasl > n->params.mdts) {
|
||||
error_setg(errp, "zoned.zasl (Zone Append Size Limit) must be less "
|
||||
"than or equal to mdts (Maximum Data Transfer Size)");
|
||||
@@ -8776,7 +8785,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
|
||||
uint8_t *pci_conf = pci_dev->config;
|
||||
uint64_t cap = ldq_le_p(&n->bar.cap);
|
||||
NvmeSecCtrlEntry *sctrl = nvme_sctrl(n);
|
||||
uint32_t ctratt;
|
||||
uint32_t ctratt = le32_to_cpu(id->ctratt);
|
||||
uint16_t oacs;
|
||||
|
||||
memcpy(n->cse.acs, nvme_cse_acs_default, sizeof(n->cse.acs));
|
||||
@@ -8794,10 +8803,11 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
|
||||
|
||||
id->oaes = cpu_to_le32(NVME_OAES_NS_ATTR);
|
||||
|
||||
ctratt = NVME_CTRATT_ELBAS;
|
||||
ctratt |= NVME_CTRATT_ELBAS;
|
||||
if (n->params.ctratt.mem) {
|
||||
ctratt |= NVME_CTRATT_MEM;
|
||||
}
|
||||
id->ctratt = cpu_to_le32(ctratt);
|
||||
|
||||
id->rab = 6;
|
||||
|
||||
@@ -8880,17 +8890,6 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
|
||||
id->psd[0].enlat = cpu_to_le32(0x10);
|
||||
id->psd[0].exlat = cpu_to_le32(0x4);
|
||||
|
||||
id->cmic |= NVME_CMIC_MULTI_CTRL;
|
||||
ctratt |= NVME_CTRATT_ENDGRPS;
|
||||
|
||||
id->endgidmax = cpu_to_le16(0x1);
|
||||
|
||||
if (n->subsys->endgrp.fdp.enabled) {
|
||||
ctratt |= NVME_CTRATT_FDPS;
|
||||
}
|
||||
|
||||
id->ctratt = cpu_to_le32(ctratt);
|
||||
|
||||
NVME_CAP_SET_MQES(cap, n->params.mqes);
|
||||
NVME_CAP_SET_CQR(cap, 1);
|
||||
NVME_CAP_SET_TO(cap, 0xf);
|
||||
@@ -8923,6 +8922,20 @@ static int nvme_init_subsys(NvmeCtrl *n, Error **errp)
|
||||
}
|
||||
|
||||
n->subsys = NVME_SUBSYS(dev);
|
||||
} else {
|
||||
NvmeIdCtrl *id = &n->id_ctrl;
|
||||
uint32_t ctratt = le32_to_cpu(id->ctratt);
|
||||
|
||||
id->cmic |= NVME_CMIC_MULTI_CTRL;
|
||||
ctratt |= NVME_CTRATT_ENDGRPS;
|
||||
|
||||
id->endgidmax = cpu_to_le16(0x1);
|
||||
|
||||
if (n->subsys->endgrp.fdp.enabled) {
|
||||
ctratt |= NVME_CTRATT_FDPS;
|
||||
}
|
||||
|
||||
id->ctratt = cpu_to_le32(ctratt);
|
||||
}
|
||||
|
||||
cntlid = nvme_subsys_register_ctrl(n, errp);
|
||||
|
||||
+23
-19
@@ -64,6 +64,27 @@ static void unregister_vfs(PCIDevice *dev)
|
||||
pci_set_word(dev->wmask + dev->exp.sriov_cap + PCI_SRIOV_NUM_VF, 0xffff);
|
||||
}
|
||||
|
||||
static void consume_config(PCIDevice *dev)
|
||||
{
|
||||
uint8_t *cfg = dev->config + dev->exp.sriov_cap;
|
||||
|
||||
if (pci_get_word(cfg + PCI_SRIOV_CTRL) & PCI_SRIOV_CTRL_VFE) {
|
||||
register_vfs(dev);
|
||||
} else {
|
||||
uint8_t *wmask = dev->wmask + dev->exp.sriov_cap;
|
||||
uint16_t num_vfs = pci_get_word(cfg + PCI_SRIOV_NUM_VF);
|
||||
uint16_t wmask_val = PCI_SRIOV_CTRL_MSE | PCI_SRIOV_CTRL_ARI;
|
||||
|
||||
unregister_vfs(dev);
|
||||
|
||||
if (num_vfs <= pci_get_word(cfg + PCI_SRIOV_TOTAL_VF)) {
|
||||
wmask_val |= PCI_SRIOV_CTRL_VFE;
|
||||
}
|
||||
|
||||
pci_set_word(wmask + PCI_SRIOV_CTRL, wmask_val);
|
||||
}
|
||||
}
|
||||
|
||||
static bool pcie_sriov_pf_init_common(PCIDevice *dev, uint16_t offset,
|
||||
uint16_t vf_dev_id, uint16_t init_vfs,
|
||||
uint16_t total_vfs, uint16_t vf_offset,
|
||||
@@ -416,30 +437,13 @@ void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
|
||||
trace_sriov_config_write(dev->name, PCI_SLOT(dev->devfn),
|
||||
PCI_FUNC(dev->devfn), off, val, len);
|
||||
|
||||
if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) {
|
||||
if (val & PCI_SRIOV_CTRL_VFE) {
|
||||
register_vfs(dev);
|
||||
} else {
|
||||
unregister_vfs(dev);
|
||||
}
|
||||
} else if (range_covers_byte(off, len, PCI_SRIOV_NUM_VF)) {
|
||||
uint8_t *cfg = dev->config + sriov_cap;
|
||||
uint8_t *wmask = dev->wmask + sriov_cap;
|
||||
uint16_t num_vfs = pci_get_word(cfg + PCI_SRIOV_NUM_VF);
|
||||
uint16_t wmask_val = PCI_SRIOV_CTRL_MSE | PCI_SRIOV_CTRL_ARI;
|
||||
|
||||
if (num_vfs <= pci_get_word(cfg + PCI_SRIOV_TOTAL_VF)) {
|
||||
wmask_val |= PCI_SRIOV_CTRL_VFE;
|
||||
}
|
||||
|
||||
pci_set_word(wmask + PCI_SRIOV_CTRL, wmask_val);
|
||||
}
|
||||
consume_config(dev);
|
||||
}
|
||||
|
||||
void pcie_sriov_pf_post_load(PCIDevice *dev)
|
||||
{
|
||||
if (dev->exp.sriov_cap) {
|
||||
register_vfs(dev);
|
||||
consume_config(dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-32
@@ -2608,62 +2608,46 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj, GString *buf)
|
||||
}
|
||||
}
|
||||
|
||||
static int pnv_match_nvt(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv,
|
||||
XiveTCTXMatch *match)
|
||||
static bool pnv_match_nvt(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv,
|
||||
XiveTCTXMatch *match)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(xfb);
|
||||
int total_count = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pnv->num_chips; i++) {
|
||||
Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]);
|
||||
XivePresenter *xptr = XIVE_PRESENTER(&chip9->xive);
|
||||
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
|
||||
int count;
|
||||
|
||||
count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
|
||||
cam_ignore, priority, logic_serv, match);
|
||||
|
||||
if (count < 0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
total_count += count;
|
||||
xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
|
||||
cam_ignore, priority, logic_serv, match);
|
||||
}
|
||||
|
||||
return total_count;
|
||||
return !!match->count;
|
||||
}
|
||||
|
||||
static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv,
|
||||
XiveTCTXMatch *match)
|
||||
static bool pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv,
|
||||
XiveTCTXMatch *match)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(xfb);
|
||||
int total_count = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pnv->num_chips; i++) {
|
||||
Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]);
|
||||
XivePresenter *xptr = XIVE_PRESENTER(&chip10->xive);
|
||||
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
|
||||
int count;
|
||||
|
||||
count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
|
||||
cam_ignore, priority, logic_serv, match);
|
||||
|
||||
if (count < 0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
total_count += count;
|
||||
xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd,
|
||||
cam_ignore, priority, logic_serv, match);
|
||||
}
|
||||
|
||||
return total_count;
|
||||
return !!match->count;
|
||||
}
|
||||
|
||||
static int pnv10_xive_broadcast(XiveFabric *xfb,
|
||||
|
||||
+8
-13
@@ -4468,21 +4468,14 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj, GString *buf)
|
||||
/*
|
||||
* This is a XIVE only operation
|
||||
*/
|
||||
static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
static bool spapr_match_nvt(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match)
|
||||
{
|
||||
SpaprMachineState *spapr = SPAPR_MACHINE(xfb);
|
||||
XivePresenter *xptr = XIVE_PRESENTER(spapr->active_intc);
|
||||
XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr);
|
||||
int count;
|
||||
|
||||
count = xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd, cam_ignore,
|
||||
priority, logic_serv, match);
|
||||
if (count < 0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we implement the save and restore of the thread interrupt
|
||||
@@ -4493,12 +4486,14 @@ static int spapr_match_nvt(XiveFabric *xfb, uint8_t format,
|
||||
* Until this is done, the sPAPR machine should find at least one
|
||||
* matching context always.
|
||||
*/
|
||||
if (count == 0) {
|
||||
if (!xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd, cam_ignore,
|
||||
priority, logic_serv, match)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is not dispatched\n",
|
||||
nvt_blk, nvt_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return count;
|
||||
return true;
|
||||
}
|
||||
|
||||
int spapr_get_vcpu_id(PowerPCCPU *cpu)
|
||||
|
||||
+10
-15
@@ -270,11 +270,8 @@ spcr_setup(GArray *table_data, BIOSLinker *linker, RISCVVirtState *s)
|
||||
#define RHCT_NODE_ARRAY_OFFSET 56
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 6.5+
|
||||
* 5.2.36 RISC-V Hart Capabilities Table (RHCT)
|
||||
* REF: https://github.com/riscv-non-isa/riscv-acpi/issues/16
|
||||
* https://drive.google.com/file/d/1nP3nFiH4jkPMp6COOxP6123DCZKR-tia/view
|
||||
* https://drive.google.com/file/d/1sKbOa8m1UZw1JkquZYe3F1zQBN1xXsaf/view
|
||||
* ACPI spec, Revision 6.6
|
||||
* 5.2.37 RISC-V Hart Capabilities Table (RHCT)
|
||||
*/
|
||||
static void build_rhct(GArray *table_data,
|
||||
BIOSLinker *linker,
|
||||
@@ -421,7 +418,10 @@ static void build_rhct(GArray *table_data,
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
/* FADT */
|
||||
/*
|
||||
* ACPI spec, Revision 6.6
|
||||
* 5.2.9 Fixed ACPI Description Table (MADT)
|
||||
*/
|
||||
static void build_fadt_rev6(GArray *table_data,
|
||||
BIOSLinker *linker,
|
||||
RISCVVirtState *s,
|
||||
@@ -429,7 +429,7 @@ static void build_fadt_rev6(GArray *table_data,
|
||||
{
|
||||
AcpiFadtData fadt = {
|
||||
.rev = 6,
|
||||
.minor_ver = 5,
|
||||
.minor_ver = 6,
|
||||
.flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI,
|
||||
.xdsdt_tbl_offset = &dsdt_tbl_offset,
|
||||
};
|
||||
@@ -508,11 +508,8 @@ static void build_dsdt(GArray *table_data,
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 6.5+
|
||||
* ACPI spec, Revision 6.6
|
||||
* 5.2.12 Multiple APIC Description Table (MADT)
|
||||
* REF: https://github.com/riscv-non-isa/riscv-acpi/issues/15
|
||||
* https://drive.google.com/file/d/1R6k4MshhN3WTT-hwqAquu5nX6xSEqK2l/view
|
||||
* https://drive.google.com/file/d/1oMGPyOD58JaPgMl1pKasT-VKsIKia7zR/view
|
||||
*/
|
||||
static void build_madt(GArray *table_data,
|
||||
BIOSLinker *linker,
|
||||
@@ -537,7 +534,7 @@ static void build_madt(GArray *table_data,
|
||||
|
||||
hart_index_bits = imsic_num_bits(imsic_max_hart_per_socket);
|
||||
|
||||
AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = s->oem_id,
|
||||
AcpiTable table = { .sig = "APIC", .rev = 7, .oem_id = s->oem_id,
|
||||
.oem_table_id = s->oem_table_id };
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
@@ -812,10 +809,8 @@ static void build_rimt(GArray *table_data, BIOSLinker *linker,
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 6.5+
|
||||
* ACPI spec, Revision 6.6
|
||||
* 5.2.16 System Resource Affinity Table (SRAT)
|
||||
* REF: https://github.com/riscv-non-isa/riscv-acpi/issues/25
|
||||
* https://drive.google.com/file/d/1YTdDx2IPm5IeZjAW932EYU-tUtgS08tX/view
|
||||
*/
|
||||
static void
|
||||
build_srat(GArray *table_data, BIOSLinker *linker, RISCVVirtState *vms)
|
||||
|
||||
@@ -233,7 +233,7 @@ static void allwinner_sdhost_send_command(AwSdHostState *s)
|
||||
{
|
||||
SDRequest request;
|
||||
uint8_t resp[16];
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
|
||||
/* Auto clear load flag */
|
||||
s->command &= ~SD_CMDR_LOAD;
|
||||
@@ -246,10 +246,7 @@ static void allwinner_sdhost_send_command(AwSdHostState *s)
|
||||
request.arg = s->command_arg;
|
||||
|
||||
/* Send request to SD bus */
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, resp);
|
||||
if (rlen < 0) {
|
||||
goto error;
|
||||
}
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, resp, sizeof(resp));
|
||||
|
||||
/* If the command has a response, store it in the response registers */
|
||||
if ((s->command & SD_CMDR_RESPONSE)) {
|
||||
|
||||
@@ -113,15 +113,12 @@ static void bcm2835_sdhost_send_command(BCM2835SDHostState *s)
|
||||
{
|
||||
SDRequest request;
|
||||
uint8_t rsp[16];
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
|
||||
request.cmd = s->cmd & SDCMD_CMD_MASK;
|
||||
request.arg = s->cmdarg;
|
||||
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, rsp);
|
||||
if (rlen < 0) {
|
||||
goto error;
|
||||
}
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, rsp, sizeof(rsp));
|
||||
if (!(s->cmd & SDCMD_NO_RESPONSE)) {
|
||||
if (rlen == 0 || (rlen == 4 && (s->cmd & SDCMD_LONG_RESPONSE))) {
|
||||
goto error;
|
||||
|
||||
+3
-2
@@ -90,7 +90,8 @@ void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
|
||||
}
|
||||
}
|
||||
|
||||
int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
|
||||
size_t sdbus_do_command(SDBus *sdbus, SDRequest *req,
|
||||
uint8_t *resp, size_t respsz)
|
||||
{
|
||||
SDState *card = get_card(sdbus);
|
||||
|
||||
@@ -98,7 +99,7 @@ int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
|
||||
if (card) {
|
||||
SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
|
||||
|
||||
return sc->do_command(card, req, response);
|
||||
return sc->do_command(card, req, resp, respsz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+3
-2
@@ -130,7 +130,8 @@ static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir,
|
||||
sd_rsp_type_t resptype, int init)
|
||||
{
|
||||
uint32_t rspstatus, mask;
|
||||
int rsplen, timeout;
|
||||
size_t rsplen;
|
||||
int timeout;
|
||||
SDRequest request;
|
||||
uint8_t response[16];
|
||||
|
||||
@@ -157,7 +158,7 @@ static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir,
|
||||
request.arg = host->arg;
|
||||
request.crc = 0; /* FIXME */
|
||||
|
||||
rsplen = sdbus_do_command(&host->sdbus, &request, response);
|
||||
rsplen = sdbus_do_command(&host->sdbus, &request, response, sizeof(response));
|
||||
|
||||
/* TODO: validate CRCs */
|
||||
switch (resptype) {
|
||||
|
||||
+2
-4
@@ -173,14 +173,12 @@ static void pl181_do_command(PL181State *s)
|
||||
{
|
||||
SDRequest request;
|
||||
uint8_t response[16];
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
|
||||
request.cmd = s->cmd & PL181_CMD_INDEX;
|
||||
request.arg = s->cmdarg;
|
||||
trace_pl181_command_send(request.cmd, request.arg);
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, response);
|
||||
if (rlen < 0)
|
||||
goto error;
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
|
||||
if (s->cmd & PL181_CMD_RESPONSE) {
|
||||
if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
|
||||
goto error;
|
||||
|
||||
+145
-53
@@ -61,6 +61,7 @@
|
||||
typedef enum {
|
||||
sd_r0 = 0, /* no response */
|
||||
sd_r1, /* normal response command */
|
||||
spi_r2, /* STATUS */
|
||||
sd_r2_i, /* CID register */
|
||||
sd_r2_s, /* CSD register */
|
||||
sd_r3, /* OCR register */
|
||||
@@ -146,7 +147,6 @@ struct SDState {
|
||||
|
||||
/* Runtime changeables */
|
||||
|
||||
uint32_t mode; /* current card mode, one of SDCardModes */
|
||||
int32_t state; /* current card state, one of SDCardStates */
|
||||
uint32_t vhs;
|
||||
bool wp_switch;
|
||||
@@ -247,6 +247,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
|
||||
static const char *response_name[] = {
|
||||
[sd_r0] = "RESP#0 (no response)",
|
||||
[sd_r1] = "RESP#1 (normal cmd)",
|
||||
[spi_r2] = "RESP#2 (STATUS reg)",
|
||||
[sd_r2_i] = "RESP#2 (CID reg)",
|
||||
[sd_r2_s] = "RESP#2 (CSD reg)",
|
||||
[sd_r3] = "RESP#3 (OCR reg)",
|
||||
@@ -313,27 +314,24 @@ static void sd_set_voltage(SDState *sd, uint16_t millivolts)
|
||||
}
|
||||
}
|
||||
|
||||
static void sd_set_mode(SDState *sd)
|
||||
static enum SDCardModes sd_mode(SDState *sd)
|
||||
{
|
||||
switch (sd->state) {
|
||||
case sd_inactive_state:
|
||||
sd->mode = sd_inactive;
|
||||
break;
|
||||
|
||||
return sd_inactive;
|
||||
case sd_idle_state:
|
||||
case sd_ready_state:
|
||||
case sd_identification_state:
|
||||
sd->mode = sd_card_identification_mode;
|
||||
break;
|
||||
|
||||
return sd_card_identification_mode;
|
||||
case sd_standby_state:
|
||||
case sd_transfer_state:
|
||||
case sd_sendingdata_state:
|
||||
case sd_receivingdata_state:
|
||||
case sd_programming_state:
|
||||
case sd_disconnect_state:
|
||||
sd->mode = sd_data_transfer_mode;
|
||||
break;
|
||||
return sd_data_transfer_mode;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,16 +727,82 @@ static int sd_req_crc_validate(SDRequest *req)
|
||||
return sd_crc7(buffer, 5) != req->crc; /* TODO */
|
||||
}
|
||||
|
||||
static size_t sd_response_size(SDState *sd, sd_rsp_type_t rtype)
|
||||
{
|
||||
switch (rtype) {
|
||||
case sd_r1:
|
||||
case sd_r1b:
|
||||
return sd_is_spi(sd) ? 1 : 4;
|
||||
|
||||
case spi_r2:
|
||||
assert(sd_is_spi(sd));
|
||||
return 2;
|
||||
|
||||
case sd_r2_i:
|
||||
case sd_r2_s:
|
||||
assert(!sd_is_spi(sd));
|
||||
return 16;
|
||||
|
||||
case sd_r3:
|
||||
case sd_r7:
|
||||
return sd_is_spi(sd) ? 5 : 4;
|
||||
|
||||
case sd_r6:
|
||||
assert(!sd_is_spi(sd));
|
||||
return 4;
|
||||
|
||||
case sd_r0:
|
||||
case sd_illegal:
|
||||
return sd_is_spi(sd) ? 1 : 0;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void sd_response_r1_make(SDState *sd, uint8_t *response)
|
||||
{
|
||||
stl_be_p(response, sd->card_status);
|
||||
if (sd_is_spi(sd)) {
|
||||
response[0] = sd->state == sd_idle_state
|
||||
&& !FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP);
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_RESET) << 1;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, ILLEGAL_COMMAND) << 2;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, COM_CRC_ERROR) << 3;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_SEQ_ERROR) << 4;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, ADDRESS_ERROR) << 5;
|
||||
response[0] |= FIELD_EX32(sd->card_status, CSR, BLOCK_LEN_ERROR) << 6;
|
||||
response[0] |= 0 << 7;
|
||||
} else {
|
||||
stl_be_p(response, sd->card_status);
|
||||
}
|
||||
|
||||
/* Clear the "clear on read" status bits */
|
||||
sd->card_status &= ~CARD_STATUS_C;
|
||||
}
|
||||
|
||||
static void spi_response_r2_make(SDState *sd, uint8_t *resp)
|
||||
{
|
||||
/* Prepend R1 */
|
||||
sd_response_r1_make(sd, resp);
|
||||
|
||||
resp[1] = FIELD_EX32(sd->card_status, CSR, CARD_IS_LOCKED) << 0;
|
||||
resp[1] |= (FIELD_EX32(sd->card_status, CSR, LOCK_UNLOCK_FAILED)
|
||||
|| FIELD_EX32(sd->card_status, CSR, WP_ERASE_SKIP)) << 1;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, ERROR) << 2;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, CC_ERROR) << 3;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, CARD_ECC_FAILED) << 4;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, WP_VIOLATION) << 5;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, ERASE_PARAM) << 6;
|
||||
resp[1] |= FIELD_EX32(sd->card_status, CSR, OUT_OF_RANGE) << 7;
|
||||
}
|
||||
|
||||
static void sd_response_r3_make(SDState *sd, uint8_t *response)
|
||||
{
|
||||
if (sd_is_spi(sd)) {
|
||||
/* Prepend R1 */
|
||||
sd_response_r1_make(sd, response);
|
||||
response++;
|
||||
}
|
||||
stl_be_p(response, sd->ocr & ACMD41_R3_MASK);
|
||||
}
|
||||
|
||||
@@ -756,6 +820,11 @@ static void sd_response_r6_make(SDState *sd, uint8_t *response)
|
||||
|
||||
static void sd_response_r7_make(SDState *sd, uint8_t *response)
|
||||
{
|
||||
if (sd_is_spi(sd)) {
|
||||
/* Prepend R1 */
|
||||
sd_response_r1_make(sd, response);
|
||||
response++;
|
||||
}
|
||||
stl_be_p(response, sd->vhs);
|
||||
}
|
||||
|
||||
@@ -952,7 +1021,7 @@ static const VMStateDescription sd_vmstate = {
|
||||
.minimum_version_id = 2,
|
||||
.pre_load = sd_vmstate_pre_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(mode, SDState),
|
||||
VMSTATE_UNUSED(4),
|
||||
VMSTATE_INT32(state, SDState),
|
||||
VMSTATE_UINT8_ARRAY(cid, SDState, 16),
|
||||
VMSTATE_UINT8_ARRAY(csd, SDState, 16),
|
||||
@@ -1252,7 +1321,7 @@ static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req)
|
||||
static sd_rsp_type_t sd_invalid_mode_for_cmd(SDState *sd, SDRequest req)
|
||||
{
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: CMD%i in a wrong mode: %s (spec %s)\n",
|
||||
sd->proto->name, req.cmd, sd_mode_name(sd->mode),
|
||||
sd->proto->name, req.cmd, sd_mode_name(sd_mode(sd)),
|
||||
sd_version_str(sd->spec_version));
|
||||
|
||||
return sd_illegal;
|
||||
@@ -1305,7 +1374,7 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
if (sd->state != sd_transfer_state) {
|
||||
sd_invalid_state_for_cmd(sd, req);
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
|
||||
sd->state = sd_sendingdata_state;
|
||||
@@ -1341,14 +1410,6 @@ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req)
|
||||
return sd_is_spi(sd) ? sd_r1 : sd_r0;
|
||||
}
|
||||
|
||||
/* CMD1 */
|
||||
static sd_rsp_type_t spi_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
|
||||
{
|
||||
sd->state = sd_transfer_state;
|
||||
|
||||
return sd_r1;
|
||||
}
|
||||
|
||||
/* CMD2 */
|
||||
static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req)
|
||||
{
|
||||
@@ -1420,11 +1481,17 @@ static sd_rsp_type_t emmc_cmd_sleep_awake(SDState *sd, SDRequest req)
|
||||
/* CMD6 */
|
||||
static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req)
|
||||
{
|
||||
if (sd->mode != sd_data_transfer_mode) {
|
||||
if (sd_mode(sd) != sd_data_transfer_mode) {
|
||||
return sd_invalid_mode_for_cmd(sd, req);
|
||||
}
|
||||
if (sd->state != sd_transfer_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
if (sd_is_spi(sd)) {
|
||||
if (sd->state == sd_idle_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
} else {
|
||||
if (sd->state != sd_transfer_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
}
|
||||
|
||||
sd_function_switch(sd, req.arg);
|
||||
@@ -1517,14 +1584,30 @@ static sd_rsp_type_t emmc_cmd_SEND_EXT_CSD(SDState *sd, SDRequest req)
|
||||
sd->ext_csd, sizeof(sd->ext_csd));
|
||||
}
|
||||
|
||||
/* CMD9 */
|
||||
static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
|
||||
static sd_rsp_type_t spi_cmd_SEND_CxD(SDState *sd, SDRequest req,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
/*
|
||||
* XXX as of v10.1.0-rc1 command is reached in sd_idle_state,
|
||||
* so disable this check.
|
||||
if (sd->state != sd_standby_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
|
||||
sd->csd, 16);
|
||||
*/
|
||||
|
||||
/*
|
||||
* Since SPI returns CSD and CID on the DAT lines,
|
||||
* switch to sd_transfer_state.
|
||||
*/
|
||||
sd->state = sd_transfer_state;
|
||||
|
||||
return sd_cmd_to_sendingdata(sd, req, 0, data, size);
|
||||
}
|
||||
|
||||
/* CMD9 */
|
||||
static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
|
||||
{
|
||||
return spi_cmd_SEND_CxD(sd, req, sd->csd, sizeof(sd->csd));
|
||||
}
|
||||
|
||||
static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
|
||||
@@ -1539,11 +1622,7 @@ static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
|
||||
/* CMD10 */
|
||||
static sd_rsp_type_t spi_cmd_SEND_CID(SDState *sd, SDRequest req)
|
||||
{
|
||||
if (sd->state != sd_standby_state) {
|
||||
return sd_invalid_state_for_cmd(sd, req);
|
||||
}
|
||||
return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
|
||||
sd->cid, 16);
|
||||
return spi_cmd_SEND_CxD(sd, req, sd->cid, sizeof(sd->cid));
|
||||
}
|
||||
|
||||
static sd_rsp_type_t sd_cmd_SEND_CID(SDState *sd, SDRequest req)
|
||||
@@ -1575,7 +1654,7 @@ static sd_rsp_type_t sd_cmd_STOP_TRANSMISSION(SDState *sd, SDRequest req)
|
||||
/* CMD13 */
|
||||
static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
|
||||
{
|
||||
if (sd->mode != sd_data_transfer_mode) {
|
||||
if (sd_mode(sd) != sd_data_transfer_mode) {
|
||||
return sd_invalid_mode_for_cmd(sd, req);
|
||||
}
|
||||
|
||||
@@ -1592,7 +1671,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
|
||||
}
|
||||
|
||||
if (sd_is_spi(sd)) {
|
||||
return sd_r2_s;
|
||||
return spi_r2;
|
||||
}
|
||||
|
||||
return sd_req_rca_same(sd, req) ? sd_r1 : sd_r0;
|
||||
@@ -1601,7 +1680,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
|
||||
/* CMD15 */
|
||||
static sd_rsp_type_t sd_cmd_GO_INACTIVE_STATE(SDState *sd, SDRequest req)
|
||||
{
|
||||
if (sd->mode != sd_data_transfer_mode) {
|
||||
if (sd_mode(sd) != sd_data_transfer_mode) {
|
||||
return sd_invalid_mode_for_cmd(sd, req);
|
||||
}
|
||||
switch (sd->state) {
|
||||
@@ -1906,8 +1985,14 @@ static sd_rsp_type_t sd_acmd_SET_BUS_WIDTH(SDState *sd, SDRequest req)
|
||||
/* ACMD13 */
|
||||
static sd_rsp_type_t sd_acmd_SD_STATUS(SDState *sd, SDRequest req)
|
||||
{
|
||||
return sd_cmd_to_sendingdata(sd, req, 0,
|
||||
sd->sd_status, sizeof(sd->sd_status));
|
||||
sd_rsp_type_t rsp;
|
||||
|
||||
rsp = sd_cmd_to_sendingdata(sd, req, 0,
|
||||
sd->sd_status, sizeof(sd->sd_status));
|
||||
if (sd_is_spi(sd) && rsp != sd_illegal) {
|
||||
return spi_r2;
|
||||
}
|
||||
return rsp;
|
||||
}
|
||||
|
||||
/* ACMD22 */
|
||||
@@ -1967,6 +2052,9 @@ static sd_rsp_type_t sd_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
|
||||
sd->state = sd_ready_state;
|
||||
}
|
||||
|
||||
if (sd_is_spi(sd)) {
|
||||
return sd_r1;
|
||||
}
|
||||
return sd_r3;
|
||||
}
|
||||
|
||||
@@ -1998,7 +2086,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
|
||||
if (req.cmd != 55 || sd->expecting_acmd) {
|
||||
trace_sdcard_normal_command(sd->proto->name,
|
||||
sd->last_cmd_name, req.cmd,
|
||||
req.arg, sd_state_name(sd->state));
|
||||
req.arg,
|
||||
sd_mode_name(sd_mode(sd)),
|
||||
sd_state_name(sd->state));
|
||||
}
|
||||
|
||||
/* Not interpreting this as an app command */
|
||||
@@ -2084,7 +2174,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
|
||||
{
|
||||
sd->last_cmd_name = sd_acmd_name(sd, req.cmd);
|
||||
trace_sdcard_app_command(sd->proto->name, sd->last_cmd_name,
|
||||
req.cmd, req.arg, sd_state_name(sd->state));
|
||||
req.cmd, req.arg,
|
||||
sd_mode_name(sd_mode(sd)),
|
||||
sd_state_name(sd->state));
|
||||
sd->card_status |= APP_CMD;
|
||||
|
||||
if (sd->proto->acmd[req.cmd].handler) {
|
||||
@@ -2139,8 +2231,9 @@ static bool cmd_valid_while_locked(SDState *sd, unsigned cmd)
|
||||
return cmd_class == 0 || cmd_class == 7;
|
||||
}
|
||||
|
||||
static int sd_do_command(SDState *sd, SDRequest *req,
|
||||
uint8_t *response) {
|
||||
static size_t sd_do_command(SDState *sd, SDRequest *req,
|
||||
uint8_t *response, size_t respsz)
|
||||
{
|
||||
int last_state;
|
||||
sd_rsp_type_t rtype;
|
||||
int rsplen;
|
||||
@@ -2183,7 +2276,6 @@ static int sd_do_command(SDState *sd, SDRequest *req,
|
||||
}
|
||||
|
||||
last_state = sd->state;
|
||||
sd_set_mode(sd);
|
||||
|
||||
if (sd->expecting_acmd) {
|
||||
sd->expecting_acmd = false;
|
||||
@@ -2203,36 +2295,37 @@ static int sd_do_command(SDState *sd, SDRequest *req,
|
||||
}
|
||||
|
||||
send_response:
|
||||
rsplen = sd_response_size(sd, rtype);
|
||||
assert(rsplen <= respsz);
|
||||
|
||||
switch (rtype) {
|
||||
case sd_r1:
|
||||
case sd_r1b:
|
||||
sd_response_r1_make(sd, response);
|
||||
rsplen = 4;
|
||||
break;
|
||||
|
||||
case spi_r2:
|
||||
spi_response_r2_make(sd, response);
|
||||
break;
|
||||
|
||||
case sd_r2_i:
|
||||
memcpy(response, sd->cid, sizeof(sd->cid));
|
||||
rsplen = 16;
|
||||
break;
|
||||
|
||||
case sd_r2_s:
|
||||
memcpy(response, sd->csd, sizeof(sd->csd));
|
||||
rsplen = 16;
|
||||
break;
|
||||
|
||||
case sd_r3:
|
||||
sd_response_r3_make(sd, response);
|
||||
rsplen = 4;
|
||||
break;
|
||||
|
||||
case sd_r6:
|
||||
sd_response_r6_make(sd, response);
|
||||
rsplen = 4;
|
||||
break;
|
||||
|
||||
case sd_r7:
|
||||
sd_response_r7_make(sd, response);
|
||||
rsplen = 4;
|
||||
break;
|
||||
|
||||
case sd_r0:
|
||||
@@ -2244,7 +2337,6 @@ send_response:
|
||||
sd->data_offset = 0;
|
||||
/* fall-through */
|
||||
case sd_illegal:
|
||||
rsplen = 0;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
@@ -2510,7 +2602,7 @@ static const SDProto sd_proto_spi = {
|
||||
.name = "SPI",
|
||||
.cmd = {
|
||||
[0] = {0, sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE},
|
||||
[1] = {0, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
|
||||
[1] = {0, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
|
||||
[5] = {9, sd_spi, "IO_SEND_OP_COND", sd_cmd_optional},
|
||||
[6] = {10, sd_spi, "SWITCH_FUNCTION", sd_cmd_SWITCH_FUNCTION},
|
||||
[8] = {0, sd_spi, "SEND_IF_COND", sd_cmd_SEND_IF_COND},
|
||||
@@ -2546,7 +2638,7 @@ static const SDProto sd_proto_spi = {
|
||||
[13] = {8, sd_spi, "SD_STATUS", sd_acmd_SD_STATUS},
|
||||
[22] = {8, sd_spi, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS},
|
||||
[23] = {8, sd_spi, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT},
|
||||
[41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
|
||||
[41] = {8, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
|
||||
[42] = {8, sd_spi, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT},
|
||||
[51] = {8, sd_spi, "SEND_SCR", sd_acmd_SEND_SCR},
|
||||
},
|
||||
|
||||
+3
-3
@@ -337,7 +337,7 @@ static void sdhci_send_command(SDHCIState *s)
|
||||
{
|
||||
SDRequest request;
|
||||
uint8_t response[16];
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
bool timeout = false;
|
||||
|
||||
s->errintsts = 0;
|
||||
@@ -346,7 +346,7 @@ static void sdhci_send_command(SDHCIState *s)
|
||||
request.arg = s->argument;
|
||||
|
||||
trace_sdhci_send_command(request.cmd, request.arg);
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, response);
|
||||
rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
|
||||
|
||||
if (s->cmdreg & SDHC_CMD_RESPONSE) {
|
||||
if (rlen == 4) {
|
||||
@@ -400,7 +400,7 @@ static void sdhci_end_transfer(SDHCIState *s)
|
||||
request.cmd = 0x0C;
|
||||
request.arg = 0;
|
||||
trace_sdhci_end_transfer(request.cmd, request.arg);
|
||||
sdbus_do_command(&s->sdbus, &request, response);
|
||||
sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
|
||||
/* Auto CMD12 response goes to the upper Response register */
|
||||
s->rspreg[3] = ldl_be_p(response);
|
||||
}
|
||||
|
||||
+17
-87
@@ -70,23 +70,6 @@ struct ssi_sd_state {
|
||||
#define TYPE_SSI_SD "ssi-sd"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
|
||||
|
||||
/* State word bits. */
|
||||
#define SSI_SDR_LOCKED 0x0001
|
||||
#define SSI_SDR_WP_ERASE 0x0002
|
||||
#define SSI_SDR_ERROR 0x0004
|
||||
#define SSI_SDR_CC_ERROR 0x0008
|
||||
#define SSI_SDR_ECC_FAILED 0x0010
|
||||
#define SSI_SDR_WP_VIOLATION 0x0020
|
||||
#define SSI_SDR_ERASE_PARAM 0x0040
|
||||
#define SSI_SDR_OUT_OF_RANGE 0x0080
|
||||
#define SSI_SDR_IDLE 0x0100
|
||||
#define SSI_SDR_ERASE_RESET 0x0200
|
||||
#define SSI_SDR_ILLEGAL_COMMAND 0x0400
|
||||
#define SSI_SDR_COM_CRC_ERROR 0x0800
|
||||
#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
|
||||
#define SSI_SDR_ADDRESS_ERROR 0x2000
|
||||
#define SSI_SDR_PARAMETER_ERROR 0x4000
|
||||
|
||||
/* multiple block write */
|
||||
#define SSI_TOKEN_MULTI_WRITE 0xfc
|
||||
/* terminate multiple block write */
|
||||
@@ -104,7 +87,11 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
||||
{
|
||||
ssi_sd_state *s = SSI_SD(dev);
|
||||
SDRequest request;
|
||||
uint8_t longresp[16];
|
||||
uint8_t longresp[5];
|
||||
|
||||
if (!sdbus_get_inserted(&s->sdbus)) {
|
||||
return SSI_DUMMY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.
|
||||
@@ -146,8 +133,9 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
||||
/* manually issue cmd12 to stop the transfer */
|
||||
request.cmd = 12;
|
||||
request.arg = 0;
|
||||
s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
|
||||
if (s->arglen <= 0) {
|
||||
s->arglen = sdbus_do_command(&s->sdbus, &request,
|
||||
longresp, sizeof(longresp));
|
||||
if (s->arglen == 0) {
|
||||
s->arglen = 1;
|
||||
/* a zero value indicates the card is busy */
|
||||
s->response[0] = 0;
|
||||
@@ -170,73 +158,15 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
|
||||
/* FIXME: Check CRC. */
|
||||
request.cmd = s->cmd;
|
||||
request.arg = ldl_be_p(s->cmdarg);
|
||||
DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
|
||||
s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
|
||||
if (s->arglen <= 0) {
|
||||
s->arglen = 1;
|
||||
s->response[0] = 4;
|
||||
DPRINTF("SD command failed\n");
|
||||
} else if (s->cmd == 8 || s->cmd == 58) {
|
||||
/* CMD8/CMD58 returns R3/R7 response */
|
||||
DPRINTF("Returned R3/R7\n");
|
||||
s->arglen = 5;
|
||||
s->response[0] = 1;
|
||||
memcpy(&s->response[1], longresp, 4);
|
||||
} else if (s->arglen != 4) {
|
||||
BADF("Unexpected response to cmd %d\n", s->cmd);
|
||||
/* Illegal command is about as near as we can get. */
|
||||
s->arglen = 1;
|
||||
s->response[0] = 4;
|
||||
} else {
|
||||
/* All other commands return status. */
|
||||
uint32_t cardstatus;
|
||||
uint16_t status;
|
||||
/* CMD13 returns a 2-byte statuse work. Other commands
|
||||
only return the first byte. */
|
||||
s->arglen = (s->cmd == 13) ? 2 : 1;
|
||||
s->arglen = sdbus_do_command(&s->sdbus, &request,
|
||||
longresp, sizeof(longresp));
|
||||
DPRINTF("CMD%d arg 0x%08x = %d\n", s->cmd, request.arg, s->arglen);
|
||||
assert(s->arglen > 0);
|
||||
memcpy(s->response, longresp, s->arglen);
|
||||
|
||||
/* handle R1b */
|
||||
if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
|
||||
s->stopping = 1;
|
||||
}
|
||||
|
||||
cardstatus = ldl_be_p(longresp);
|
||||
status = 0;
|
||||
if (((cardstatus >> 9) & 0xf) < 4)
|
||||
status |= SSI_SDR_IDLE;
|
||||
if (cardstatus & ERASE_RESET)
|
||||
status |= SSI_SDR_ERASE_RESET;
|
||||
if (cardstatus & ILLEGAL_COMMAND)
|
||||
status |= SSI_SDR_ILLEGAL_COMMAND;
|
||||
if (cardstatus & COM_CRC_ERROR)
|
||||
status |= SSI_SDR_COM_CRC_ERROR;
|
||||
if (cardstatus & ERASE_SEQ_ERROR)
|
||||
status |= SSI_SDR_ERASE_SEQ_ERROR;
|
||||
if (cardstatus & ADDRESS_ERROR)
|
||||
status |= SSI_SDR_ADDRESS_ERROR;
|
||||
if (cardstatus & CARD_IS_LOCKED)
|
||||
status |= SSI_SDR_LOCKED;
|
||||
if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
|
||||
status |= SSI_SDR_WP_ERASE;
|
||||
if (cardstatus & SD_ERROR)
|
||||
status |= SSI_SDR_ERROR;
|
||||
if (cardstatus & CC_ERROR)
|
||||
status |= SSI_SDR_CC_ERROR;
|
||||
if (cardstatus & CARD_ECC_FAILED)
|
||||
status |= SSI_SDR_ECC_FAILED;
|
||||
if (cardstatus & WP_VIOLATION)
|
||||
status |= SSI_SDR_WP_VIOLATION;
|
||||
if (cardstatus & ERASE_PARAM)
|
||||
status |= SSI_SDR_ERASE_PARAM;
|
||||
if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
|
||||
status |= SSI_SDR_OUT_OF_RANGE;
|
||||
/* ??? Don't know what Parameter Error really means, so
|
||||
assume it's set if the second byte is nonzero. */
|
||||
if (status & 0xff)
|
||||
status |= SSI_SDR_PARAMETER_ERROR;
|
||||
s->response[0] = status >> 8;
|
||||
s->response[1] = status;
|
||||
DPRINTF("Card status 0x%02x\n", status);
|
||||
/* handle R1b (busy signal) */
|
||||
if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
|
||||
s->stopping = 1;
|
||||
}
|
||||
s->mode = SSI_SD_PREP_RESP;
|
||||
s->response_pos = 0;
|
||||
@@ -333,7 +263,7 @@ static int ssi_sd_post_load(void *opaque, int version_id)
|
||||
return -EINVAL;
|
||||
}
|
||||
if (s->mode == SSI_SD_CMDARG &&
|
||||
(s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) {
|
||||
(s->arglen >= ARRAY_SIZE(s->cmdarg))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (s->mode == SSI_SD_RESPONSE &&
|
||||
|
||||
+2
-2
@@ -37,8 +37,8 @@ sdhci_write_dataport(uint16_t data_count) "write buffer filled with %u bytes of
|
||||
sdhci_capareg(const char *desc, uint16_t val) "%s: %u"
|
||||
|
||||
# sd.c
|
||||
sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *state) "%s %20s/ CMD%02d arg 0x%08x (state %s)"
|
||||
sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *state) "%s %23s/ACMD%02d arg 0x%08x (state %s)"
|
||||
sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *mode, const char *state) "%s %20s/ CMD%02d arg 0x%08x (mode %s, state %s)"
|
||||
sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *mode, const char *state) "%s %23s/ACMD%02d arg 0x%08x (mode %s, state %s)"
|
||||
sdcard_response(const char *rspdesc, int rsplen) "%s (sz:%d)"
|
||||
sdcard_powerup(void) ""
|
||||
sdcard_inquiry_cmd41(void) ""
|
||||
|
||||
+2
-1
@@ -1857,7 +1857,8 @@ static void aspeed_1030_fmc_class_init(ObjectClass *klass, const void *data)
|
||||
asc->resets = aspeed_1030_fmc_resets;
|
||||
asc->flash_window_base = 0x80000000;
|
||||
asc->flash_window_size = 0x10000000;
|
||||
asc->features = ASPEED_SMC_FEATURE_DMA;
|
||||
asc->features = ASPEED_SMC_FEATURE_DMA |
|
||||
ASPEED_SMC_FEATURE_WDT_CONTROL;
|
||||
asc->dma_flash_mask = 0x0FFFFFFC;
|
||||
asc->dma_dram_mask = 0x000BFFFC;
|
||||
asc->dma_start_length = 1;
|
||||
|
||||
@@ -259,8 +259,8 @@ static void uefi_vars_write(void *opaque, hwaddr addr, uint64_t val, unsigned si
|
||||
uv->buf_size = val;
|
||||
g_free(uv->buffer);
|
||||
g_free(uv->pio_xfer_buffer);
|
||||
uv->buffer = g_malloc(uv->buf_size);
|
||||
uv->pio_xfer_buffer = g_malloc(uv->buf_size);
|
||||
uv->buffer = g_malloc0(uv->buf_size);
|
||||
uv->pio_xfer_buffer = g_malloc0(uv->buf_size);
|
||||
break;
|
||||
case UEFI_VARS_REG_DMA_BUFFER_ADDR_LO:
|
||||
uv->buf_addr_lo = val;
|
||||
|
||||
@@ -172,7 +172,7 @@ static GString *uefi_vars_to_json(uefi_vars_state *uv)
|
||||
void uefi_vars_json_init(uefi_vars_state *uv, Error **errp)
|
||||
{
|
||||
if (uv->jsonfile) {
|
||||
uv->jsonfd = qemu_create(uv->jsonfile, O_RDWR, 0666, errp);
|
||||
uv->jsonfd = qemu_create(uv->jsonfile, O_RDWR | O_BINARY, 0666, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -357,6 +357,9 @@ uefi_vars_mm_get_next_variable(uefi_vars_state *uv, mm_header *mhdr,
|
||||
if (uefi_strlen(name, nv->name_size) == 0) {
|
||||
/* empty string -> first */
|
||||
var = QTAILQ_FIRST(&uv->variables);
|
||||
while (var && !check_access(uv, var)) {
|
||||
var = QTAILQ_NEXT(var, next);
|
||||
}
|
||||
if (!var) {
|
||||
return uefi_vars_mm_error(mhdr, mvar, EFI_NOT_FOUND);
|
||||
}
|
||||
@@ -702,12 +705,14 @@ uint32_t uefi_vars_mm_vars_proto(uefi_vars_state *uv)
|
||||
case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
|
||||
trace_uefi_event("ready-to-boot");
|
||||
uv->ready_to_boot = true;
|
||||
mvar->status = EFI_SUCCESS;
|
||||
length = 0;
|
||||
break;
|
||||
|
||||
case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:
|
||||
trace_uefi_event("exit-boot-service");
|
||||
uv->exit_boot_service = true;
|
||||
mvar->status = EFI_SUCCESS;
|
||||
length = 0;
|
||||
break;
|
||||
|
||||
|
||||
+94
-1
@@ -70,7 +70,7 @@ static void vfio_cpr_claim_vectors(VFIOPCIDevice *vdev, int nr_vectors,
|
||||
fd = vfio_cpr_load_vector_fd(vdev, "interrupt", i);
|
||||
if (fd >= 0) {
|
||||
vfio_pci_vector_init(vdev, i);
|
||||
vfio_pci_msi_set_handler(vdev, i);
|
||||
vfio_pci_msi_set_handler(vdev, i, true);
|
||||
}
|
||||
|
||||
if (vfio_cpr_load_vector_fd(vdev, "kvm_interrupt", i) >= 0) {
|
||||
@@ -116,6 +116,8 @@ static int vfio_cpr_pci_post_load(void *opaque, int version_id)
|
||||
PCIDevice *pdev = &vdev->pdev;
|
||||
int nr_vectors;
|
||||
|
||||
vfio_sub_page_bar_update_mappings(vdev);
|
||||
|
||||
if (msix_enabled(pdev)) {
|
||||
vfio_pci_msix_set_notifiers(vdev);
|
||||
nr_vectors = vdev->msix->entries;
|
||||
@@ -198,3 +200,94 @@ void vfio_cpr_add_kvm_notifier(void)
|
||||
MIG_MODE_CPR_TRANSFER);
|
||||
}
|
||||
}
|
||||
|
||||
static int set_irqfd_notifier_gsi(KVMState *s, EventNotifier *n,
|
||||
EventNotifier *rn, int virq, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
return kvm_irqchip_add_irqfd_notifier_gsi(s, n, rn, virq);
|
||||
} else {
|
||||
return kvm_irqchip_remove_irqfd_notifier_gsi(s, n, virq);
|
||||
}
|
||||
}
|
||||
|
||||
static int vfio_cpr_set_msi_virq(VFIOPCIDevice *vdev, Error **errp, bool enable)
|
||||
{
|
||||
const char *op = (enable ? "enable" : "disable");
|
||||
PCIDevice *pdev = &vdev->pdev;
|
||||
int i, nr_vectors, ret = 0;
|
||||
|
||||
if (msix_enabled(pdev)) {
|
||||
nr_vectors = vdev->msix->entries;
|
||||
|
||||
} else if (msi_enabled(pdev)) {
|
||||
nr_vectors = msi_nr_vectors_allocated(pdev);
|
||||
|
||||
} else if (vfio_pci_read_config(pdev, PCI_INTERRUPT_PIN, 1)) {
|
||||
ret = set_irqfd_notifier_gsi(kvm_state, &vdev->intx.interrupt,
|
||||
&vdev->intx.unmask, vdev->intx.route.irq,
|
||||
enable);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret, "failed to %s INTx irq %d",
|
||||
op, vdev->intx.route.irq);
|
||||
return ret;
|
||||
}
|
||||
vfio_pci_intx_set_handler(vdev, enable);
|
||||
return ret;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_vectors; i++) {
|
||||
VFIOMSIVector *vector = &vdev->msi_vectors[i];
|
||||
if (vector->use) {
|
||||
ret = set_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt,
|
||||
NULL, vector->virq, enable);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"failed to %s msi vector %d virq %d",
|
||||
op, i, vector->virq);
|
||||
return ret;
|
||||
}
|
||||
vfio_pci_msi_set_handler(vdev, i, enable);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* When CPR starts, detach IRQs from the VFIO device so future interrupts
|
||||
* are posted to kvm_interrupt, which is preserved in new QEMU. Interrupts
|
||||
* that were already posted to the old KVM instance, but not delivered to the
|
||||
* VCPU, are recovered via KVM_GET_LAPIC and pushed to the new KVM instance
|
||||
* in new QEMU.
|
||||
*
|
||||
* If CPR fails, reattach the IRQs.
|
||||
*/
|
||||
static int vfio_cpr_pci_notifier(NotifierWithReturn *notifier,
|
||||
MigrationEvent *e, Error **errp)
|
||||
{
|
||||
VFIOPCIDevice *vdev =
|
||||
container_of(notifier, VFIOPCIDevice, cpr.transfer_notifier);
|
||||
|
||||
if (e->type == MIG_EVENT_PRECOPY_SETUP) {
|
||||
return vfio_cpr_set_msi_virq(vdev, errp, false);
|
||||
} else if (e->type == MIG_EVENT_PRECOPY_FAILED) {
|
||||
return vfio_cpr_set_msi_virq(vdev, errp, true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vfio_cpr_pci_register_device(VFIOPCIDevice *vdev)
|
||||
{
|
||||
migration_add_notifier_mode(&vdev->cpr.transfer_notifier,
|
||||
vfio_cpr_pci_notifier,
|
||||
MIG_MODE_CPR_TRANSFER);
|
||||
}
|
||||
|
||||
void vfio_cpr_pci_unregister_device(VFIOPCIDevice *vdev)
|
||||
{
|
||||
migration_remove_notifier(&vdev->cpr.transfer_notifier);
|
||||
}
|
||||
|
||||
+12
-7
@@ -113,6 +113,7 @@ static int igd_gen(VFIOPCIDevice *vdev)
|
||||
#define IGD_BDSM 0x5c /* Base Data of Stolen Memory */
|
||||
#define IGD_BDSM_GEN11 0xc0 /* Base Data of Stolen Memory of gen 11 and later */
|
||||
|
||||
#define IGD_GMCH_VGA_DISABLE BIT(1)
|
||||
#define IGD_GMCH_GEN6_GMS_SHIFT 3 /* SNB_GMCH in i915 */
|
||||
#define IGD_GMCH_GEN6_GMS_MASK 0x1f
|
||||
#define IGD_GMCH_GEN8_GMS_SHIFT 8 /* BDW_GMCH in i915 */
|
||||
@@ -533,12 +534,14 @@ static bool vfio_pci_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp)
|
||||
/*
|
||||
* For backward compatibility, enable legacy mode when
|
||||
* - Device geneation is 6 to 9 (including both)
|
||||
* - IGD claims VGA cycles on host
|
||||
* - Machine type is i440fx (pc_piix)
|
||||
* - IGD device is at guest BDF 00:02.0
|
||||
* - Not manually disabled by x-igd-legacy-mode=off
|
||||
*/
|
||||
if ((vdev->igd_legacy_mode != ON_OFF_AUTO_OFF) &&
|
||||
(gen >= 6 && gen <= 9) &&
|
||||
!(gmch & IGD_GMCH_VGA_DISABLE) &&
|
||||
!strcmp(MACHINE_GET_CLASS(qdev_get_machine())->family, "pc_piix") &&
|
||||
(&vdev->pdev == pci_find_device(pci_device_root_bus(&vdev->pdev),
|
||||
0, PCI_DEVFN(0x2, 0)))) {
|
||||
@@ -568,14 +571,16 @@ static bool vfio_pci_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp)
|
||||
}
|
||||
|
||||
/*
|
||||
* If IGD VGA Disable is clear (expected) and VGA is not already
|
||||
* enabled, try to enable it. Probably shouldn't be using legacy mode
|
||||
* without VGA, but also no point in us enabling VGA if disabled in
|
||||
* hardware.
|
||||
* If VGA is not already enabled, try to enable it. We shouldn't be
|
||||
* using legacy mode without VGA.
|
||||
*/
|
||||
if (!(gmch & 0x2) && !vdev->vga && !vfio_populate_vga(vdev, &err)) {
|
||||
error_setg(&err, "Unable to enable VGA access");
|
||||
goto error;
|
||||
if (!vdev->vga) {
|
||||
if (vfio_populate_vga(vdev, &err)) {
|
||||
vfio_pci_config_register_vga(vdev);
|
||||
} else {
|
||||
error_setg(&err, "Unable to enable VGA access");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable OpRegion and LPC bridge quirk */
|
||||
|
||||
+40
-7
@@ -49,8 +49,6 @@
|
||||
#include "vfio-migration-internal.h"
|
||||
#include "vfio-helpers.h"
|
||||
|
||||
#define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug"
|
||||
|
||||
/* Protected by BQL */
|
||||
static KVMRouteChange vfio_route_change;
|
||||
|
||||
@@ -415,6 +413,14 @@ bool vfio_pci_intx_enable(VFIOPCIDevice *vdev, Error **errp)
|
||||
return vfio_intx_enable(vdev, errp);
|
||||
}
|
||||
|
||||
void vfio_pci_intx_set_handler(VFIOPCIDevice *vdev, bool enable)
|
||||
{
|
||||
int fd = event_notifier_get_fd(&vdev->intx.interrupt);
|
||||
IOHandler *handler = (enable ? vfio_intx_interrupt : NULL);
|
||||
|
||||
qemu_set_fd_handler(fd, handler, NULL, vdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* MSI/X
|
||||
*/
|
||||
@@ -453,12 +459,13 @@ static void vfio_msi_interrupt(void *opaque)
|
||||
notify(&vdev->pdev, nr);
|
||||
}
|
||||
|
||||
void vfio_pci_msi_set_handler(VFIOPCIDevice *vdev, int nr)
|
||||
void vfio_pci_msi_set_handler(VFIOPCIDevice *vdev, int nr, bool enable)
|
||||
{
|
||||
VFIOMSIVector *vector = &vdev->msi_vectors[nr];
|
||||
int fd = event_notifier_get_fd(&vector->interrupt);
|
||||
IOHandler *handler = (enable ? vfio_msi_interrupt : NULL);
|
||||
|
||||
qemu_set_fd_handler(fd, vfio_msi_interrupt, NULL, vector);
|
||||
qemu_set_fd_handler(fd, handler, NULL, vector);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2826,6 +2833,20 @@ static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void vfio_sub_page_bar_update_mappings(VFIOPCIDevice *vdev)
|
||||
{
|
||||
PCIDevice *pdev = &vdev->pdev;
|
||||
int page_size = qemu_real_host_page_size();
|
||||
int bar;
|
||||
|
||||
for (bar = 0; bar < PCI_ROM_SLOT; bar++) {
|
||||
PCIIORegion *r = &pdev->io_regions[bar];
|
||||
if (r->addr != PCI_BAR_UNMAPPED && r->size > 0 && r->size < page_size) {
|
||||
vfio_sub_page_bar_update_mapping(pdev, bar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VFIODeviceOps vfio_pci_ops = {
|
||||
.vfio_compute_needs_reset = vfio_pci_compute_needs_reset,
|
||||
.vfio_hot_reset_multi = vfio_pci_hot_reset_multi,
|
||||
@@ -2980,6 +3001,7 @@ void vfio_pci_put_device(VFIOPCIDevice *vdev)
|
||||
{
|
||||
vfio_display_finalize(vdev);
|
||||
vfio_bars_finalize(vdev);
|
||||
vfio_cpr_pci_unregister_device(vdev);
|
||||
g_free(vdev->emulated_config_bits);
|
||||
g_free(vdev->rom);
|
||||
/*
|
||||
@@ -3150,6 +3172,15 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev)
|
||||
vdev->req_enabled = false;
|
||||
}
|
||||
|
||||
void vfio_pci_config_register_vga(VFIOPCIDevice *vdev)
|
||||
{
|
||||
assert(vdev->vga != NULL);
|
||||
|
||||
pci_register_vga(&vdev->pdev, &vdev->vga->region[QEMU_PCI_VGA_MEM].mem,
|
||||
&vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem,
|
||||
&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem);
|
||||
}
|
||||
|
||||
bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp)
|
||||
{
|
||||
PCIDevice *pdev = &vdev->pdev;
|
||||
@@ -3271,9 +3302,7 @@ bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp)
|
||||
vfio_bars_register(vdev);
|
||||
|
||||
if (vdev->vga && vfio_is_vga(vdev)) {
|
||||
pci_register_vga(&vdev->pdev, &vdev->vga->region[QEMU_PCI_VGA_MEM].mem,
|
||||
&vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem,
|
||||
&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem);
|
||||
vfio_pci_config_register_vga(vdev);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -3452,6 +3481,7 @@ static void vfio_pci_realize(PCIDevice *pdev, Error **errp)
|
||||
vfio_pci_register_err_notifier(vdev);
|
||||
vfio_pci_register_req_notifier(vdev);
|
||||
vfio_setup_resetfn_quirk(vdev);
|
||||
vfio_cpr_pci_register_device(vdev);
|
||||
|
||||
return;
|
||||
|
||||
@@ -3871,6 +3901,9 @@ static void vfio_pci_nohotplug_dev_class_init(ObjectClass *klass,
|
||||
"x-ramfb-migrate",
|
||||
"Override default migration support for ramfb support "
|
||||
"(DEBUG)");
|
||||
object_class_property_set_description(klass, /* 10.1 */
|
||||
"use-legacy-x86-rom",
|
||||
"Controls loading of a legacy VGA BIOS ROM");
|
||||
}
|
||||
|
||||
static const TypeInfo vfio_pci_nohotplug_dev_info = {
|
||||
|
||||
+5
-1
@@ -188,6 +188,7 @@ struct VFIOPCIDevice {
|
||||
bool skip_vsc_check;
|
||||
VFIODisplay *dpy;
|
||||
Notifier irqchip_change_notifier;
|
||||
VFIOPCICPR cpr;
|
||||
};
|
||||
|
||||
/* Use uin32_t for vendor & device so PCI_ANY_ID expands and cannot match hw */
|
||||
@@ -209,8 +210,9 @@ void vfio_pci_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector,
|
||||
void vfio_pci_prepare_kvm_msi_virq_batch(VFIOPCIDevice *vdev);
|
||||
void vfio_pci_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev);
|
||||
bool vfio_pci_intx_enable(VFIOPCIDevice *vdev, Error **errp);
|
||||
void vfio_pci_intx_set_handler(VFIOPCIDevice *vdev, bool enable);
|
||||
void vfio_pci_msix_set_notifiers(VFIOPCIDevice *vdev);
|
||||
void vfio_pci_msi_set_handler(VFIOPCIDevice *vdev, int nr);
|
||||
void vfio_pci_msi_set_handler(VFIOPCIDevice *vdev, int nr, bool enable);
|
||||
|
||||
uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
|
||||
void vfio_pci_write_config(PCIDevice *pdev,
|
||||
@@ -219,6 +221,7 @@ void vfio_pci_write_config(PCIDevice *pdev,
|
||||
uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size);
|
||||
void vfio_vga_write(void *opaque, hwaddr addr, uint64_t data, unsigned size);
|
||||
|
||||
void vfio_sub_page_bar_update_mappings(VFIOPCIDevice *vdev);
|
||||
bool vfio_opt_rom_in_denylist(VFIOPCIDevice *vdev);
|
||||
bool vfio_config_quirk_setup(VFIOPCIDevice *vdev, Error **errp);
|
||||
void vfio_vga_quirk_setup(VFIOPCIDevice *vdev);
|
||||
@@ -252,6 +255,7 @@ extern const VMStateDescription vfio_display_vmstate;
|
||||
|
||||
void vfio_pci_bars_exit(VFIOPCIDevice *vdev);
|
||||
bool vfio_pci_add_capabilities(VFIOPCIDevice *vdev, Error **errp);
|
||||
void vfio_pci_config_register_vga(VFIOPCIDevice *vdev);
|
||||
bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp);
|
||||
bool vfio_pci_interrupt_setup(VFIOPCIDevice *vdev, Error **errp);
|
||||
void vfio_pci_intx_eoi(VFIODevice *vbasedev);
|
||||
|
||||
@@ -18,4 +18,6 @@
|
||||
#define TYPE_VFIO_PCI "vfio-pci"
|
||||
/* TYPE_VFIO_PCI shares struct VFIOPCIDevice. */
|
||||
|
||||
#define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug"
|
||||
|
||||
#endif /* HW_VFIO_VFIO_TYPES_H */
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <linux/vfio.h>
|
||||
#endif
|
||||
|
||||
#include "qemu/typedefs.h"
|
||||
#include "qemu/notify.h"
|
||||
|
||||
/*
|
||||
|
||||
+4
-2
@@ -1110,7 +1110,8 @@ static bool vhost_log_global_start(MemoryListener *listener, Error **errp)
|
||||
|
||||
r = vhost_migration_log(listener, true);
|
||||
if (r < 0) {
|
||||
abort();
|
||||
error_setg_errno(errp, -r, "vhost: Failed to start logging");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1121,7 +1122,8 @@ static void vhost_log_global_stop(MemoryListener *listener)
|
||||
|
||||
r = vhost_migration_log(listener, false);
|
||||
if (r < 0) {
|
||||
abort();
|
||||
/* Not fatal, so report it, but take no further action */
|
||||
warn_report("vhost: Failed to stop logging");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-6
@@ -938,18 +938,18 @@ static void virtqueue_packed_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
static void virtqueue_ordered_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int i, steps, max_steps;
|
||||
unsigned int i, steps, max_steps, ndescs;
|
||||
|
||||
i = vq->used_idx % vq->vring.num;
|
||||
steps = 0;
|
||||
/*
|
||||
* We shouldn't need to increase 'i' by more than the distance
|
||||
* between used_idx and last_avail_idx.
|
||||
* We shouldn't need to increase 'i' by more than or equal to
|
||||
* the distance between used_idx and last_avail_idx (max_steps).
|
||||
*/
|
||||
max_steps = (vq->last_avail_idx - vq->used_idx) % vq->vring.num;
|
||||
|
||||
/* Search for element in vq->used_elems */
|
||||
while (steps <= max_steps) {
|
||||
while (steps < max_steps) {
|
||||
/* Found element, set length and mark as filled */
|
||||
if (vq->used_elems[i].index == elem->index) {
|
||||
vq->used_elems[i].len = len;
|
||||
@@ -957,8 +957,18 @@ static void virtqueue_ordered_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
break;
|
||||
}
|
||||
|
||||
i += vq->used_elems[i].ndescs;
|
||||
steps += vq->used_elems[i].ndescs;
|
||||
ndescs = vq->used_elems[i].ndescs;
|
||||
|
||||
/* Defensive sanity check */
|
||||
if (unlikely(ndescs == 0 || ndescs > vq->vring.num)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: %s invalid ndescs %u at position %u\n",
|
||||
__func__, vq->vdev->name, ndescs, i);
|
||||
return;
|
||||
}
|
||||
|
||||
i += ndescs;
|
||||
steps += ndescs;
|
||||
|
||||
if (i >= vq->vring.num) {
|
||||
i -= vq->vring.num;
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "hw/pci/pci.h"
|
||||
|
||||
@@ -165,6 +165,20 @@ void qcrypto_tls_session_free(QCryptoTLSSession *sess);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free)
|
||||
|
||||
/**
|
||||
* qcrypto_tls_session_require_thread_safety:
|
||||
* @sess: the TLS session object
|
||||
*
|
||||
* Mark that this TLS session will require thread safety
|
||||
* for concurrent I/O in both directions. This must be
|
||||
* called before the handshake is performed.
|
||||
*
|
||||
* This will activate a workaround for GNUTLS thread
|
||||
* safety issues, where appropriate for the negotiated
|
||||
* TLS session parameters.
|
||||
*/
|
||||
void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess);
|
||||
|
||||
/**
|
||||
* qcrypto_tls_session_check_credentials:
|
||||
* @sess: the TLS session object
|
||||
|
||||
+50
-16
@@ -365,6 +365,11 @@ static inline uint32_t xive_tctx_word2(uint8_t *ring)
|
||||
return *((uint32_t *) &ring[TM_WORD2]);
|
||||
}
|
||||
|
||||
bool xive_ring_valid(XiveTCTX *tctx, uint8_t ring);
|
||||
bool xive_nsr_indicates_exception(uint8_t ring, uint8_t nsr);
|
||||
bool xive_nsr_indicates_group_exception(uint8_t ring, uint8_t nsr);
|
||||
uint8_t xive_nsr_exception_ring(uint8_t ring, uint8_t nsr);
|
||||
|
||||
/*
|
||||
* XIVE Router
|
||||
*/
|
||||
@@ -421,6 +426,7 @@ void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas);
|
||||
|
||||
typedef struct XiveTCTXMatch {
|
||||
XiveTCTX *tctx;
|
||||
int count;
|
||||
uint8_t ring;
|
||||
bool precluded;
|
||||
} XiveTCTXMatch;
|
||||
@@ -436,10 +442,10 @@ DECLARE_CLASS_CHECKERS(XivePresenterClass, XIVE_PRESENTER,
|
||||
|
||||
struct XivePresenterClass {
|
||||
InterfaceClass parent;
|
||||
int (*match_nvt)(XivePresenter *xptr, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match);
|
||||
bool (*match_nvt)(XivePresenter *xptr, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match);
|
||||
bool (*in_kernel)(const XivePresenter *xptr);
|
||||
uint32_t (*get_config)(XivePresenter *xptr);
|
||||
int (*broadcast)(XivePresenter *xptr,
|
||||
@@ -451,12 +457,14 @@ int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool cam_ignore, uint32_t logic_serv);
|
||||
bool xive_presenter_notify(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, bool *precluded);
|
||||
bool xive_presenter_match(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match);
|
||||
|
||||
uint32_t xive_get_vpgroup_size(uint32_t nvp_index);
|
||||
uint8_t xive_get_group_level(bool crowd, bool ignore,
|
||||
uint32_t nvp_blk, uint32_t nvp_index);
|
||||
|
||||
/*
|
||||
* XIVE Fabric (Interface between Interrupt Controller and Machine)
|
||||
@@ -471,10 +479,10 @@ DECLARE_CLASS_CHECKERS(XiveFabricClass, XIVE_FABRIC,
|
||||
|
||||
struct XiveFabricClass {
|
||||
InterfaceClass parent;
|
||||
int (*match_nvt)(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match);
|
||||
bool (*match_nvt)(XiveFabric *xfb, uint8_t format,
|
||||
uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority,
|
||||
uint32_t logic_serv, XiveTCTXMatch *match);
|
||||
int (*broadcast)(XiveFabric *xfb, uint8_t nvt_blk, uint32_t nvt_idx,
|
||||
bool crowd, bool cam_ignore, uint8_t priority);
|
||||
};
|
||||
@@ -532,7 +540,7 @@ static inline uint8_t xive_ipb_to_pipr(uint8_t ibp)
|
||||
}
|
||||
|
||||
/*
|
||||
* XIVE Thread Interrupt Management Aera (TIMA)
|
||||
* XIVE Thread Interrupt Management Area (TIMA)
|
||||
*
|
||||
* This region gives access to the registers of the thread interrupt
|
||||
* management context. It is four page wide, each page providing a
|
||||
@@ -544,6 +552,30 @@ static inline uint8_t xive_ipb_to_pipr(uint8_t ibp)
|
||||
#define XIVE_TM_OS_PAGE 0x2
|
||||
#define XIVE_TM_USER_PAGE 0x3
|
||||
|
||||
/*
|
||||
* The TCTX (TIMA) has 4 rings (phys, pool, os, user), but only signals
|
||||
* (raises an interrupt on) the CPU from 3 of them. Phys and pool both
|
||||
* cause a hypervisor privileged interrupt so interrupts presented on
|
||||
* those rings signal using the phys ring. This helper returns the signal
|
||||
* regs from the given ring.
|
||||
*/
|
||||
static inline uint8_t *xive_tctx_signal_regs(XiveTCTX *tctx, uint8_t ring)
|
||||
{
|
||||
/*
|
||||
* This is a good point to add invariants to ensure nothing has tried to
|
||||
* signal using the POOL ring.
|
||||
*/
|
||||
g_assert(tctx->regs[TM_QW2_HV_POOL + TM_NSR] == 0);
|
||||
g_assert(tctx->regs[TM_QW2_HV_POOL + TM_PIPR] == 0);
|
||||
g_assert(tctx->regs[TM_QW2_HV_POOL + TM_CPPR] == 0);
|
||||
|
||||
if (ring == TM_QW2_HV_POOL) {
|
||||
/* POOL and PHYS rings share the signal regs (PIPR, NSR, CPPR) */
|
||||
ring = TM_QW3_HV_PHYS;
|
||||
}
|
||||
return &tctx->regs[ring];
|
||||
}
|
||||
|
||||
void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
uint64_t value, unsigned size);
|
||||
uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
@@ -553,10 +585,12 @@ void xive_tctx_pic_print_info(XiveTCTX *tctx, GString *buf);
|
||||
Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp);
|
||||
void xive_tctx_reset(XiveTCTX *tctx);
|
||||
void xive_tctx_destroy(XiveTCTX *tctx);
|
||||
void xive_tctx_pipr_update(XiveTCTX *tctx, uint8_t ring, uint8_t priority,
|
||||
uint8_t group_level);
|
||||
void xive_tctx_pipr_set(XiveTCTX *tctx, uint8_t ring, uint8_t priority,
|
||||
uint8_t group_level);
|
||||
void xive_tctx_pipr_present(XiveTCTX *tctx, uint8_t ring, uint8_t priority,
|
||||
uint8_t group_level);
|
||||
void xive_tctx_reset_signal(XiveTCTX *tctx, uint8_t ring);
|
||||
void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring, uint8_t group_level);
|
||||
uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring);
|
||||
|
||||
/*
|
||||
* KVM XIVE device helpers
|
||||
|
||||
+18
-4
@@ -29,9 +29,11 @@ OBJECT_DECLARE_TYPE(Xive2Router, Xive2RouterClass, XIVE2_ROUTER);
|
||||
* Configuration flags
|
||||
*/
|
||||
|
||||
#define XIVE2_GEN1_TIMA_OS 0x00000001
|
||||
#define XIVE2_VP_SAVE_RESTORE 0x00000002
|
||||
#define XIVE2_THREADID_8BITS 0x00000004
|
||||
#define XIVE2_GEN1_TIMA_OS 0x00000001
|
||||
#define XIVE2_VP_SAVE_RESTORE 0x00000002
|
||||
#define XIVE2_THREADID_8BITS 0x00000004
|
||||
#define XIVE2_EN_VP_GRP_PRIORITY 0x00000008
|
||||
#define XIVE2_VP_INT_PRIO 0x00000030
|
||||
|
||||
typedef struct Xive2RouterClass {
|
||||
SysBusDeviceClass parent;
|
||||
@@ -80,6 +82,7 @@ int xive2_router_write_nvgc(Xive2Router *xrtr, bool crowd,
|
||||
uint32_t xive2_router_get_config(Xive2Router *xrtr);
|
||||
|
||||
void xive2_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked);
|
||||
void xive2_notify(Xive2Router *xrtr, uint32_t lisn, bool pq_checked);
|
||||
|
||||
/*
|
||||
* XIVE2 Presenter (POWER10)
|
||||
@@ -127,6 +130,8 @@ void xive2_tm_set_hv_cppr(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size);
|
||||
void xive2_tm_set_os_cppr(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size);
|
||||
void xive2_tm_set_os_pending(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size);
|
||||
void xive2_tm_push_os_ctx(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
uint64_t value, unsigned size);
|
||||
uint64_t xive2_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
@@ -137,7 +142,16 @@ bool xive2_tm_irq_precluded(XiveTCTX *tctx, int ring, uint8_t priority);
|
||||
void xive2_tm_set_lsmfb(XiveTCTX *tctx, int ring, uint8_t priority);
|
||||
void xive2_tm_set_hv_target(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size);
|
||||
void xive2_tm_push_pool_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size);
|
||||
uint64_t xive2_tm_pull_pool_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, unsigned size);
|
||||
void xive2_tm_push_phys_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size);
|
||||
uint64_t xive2_tm_pull_phys_ctx(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, unsigned size);
|
||||
void xive2_tm_pull_phys_ctx_ol(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size);
|
||||
|
||||
void xive2_tm_ack_os_el(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset, uint64_t value, unsigned size);
|
||||
#endif /* PPC_XIVE2_H */
|
||||
|
||||
@@ -39,15 +39,18 @@
|
||||
|
||||
typedef struct Xive2Eas {
|
||||
uint64_t w;
|
||||
#define EAS2_VALID PPC_BIT(0)
|
||||
#define EAS2_END_BLOCK PPC_BITMASK(4, 7) /* Destination EQ block# */
|
||||
#define EAS2_END_INDEX PPC_BITMASK(8, 31) /* Destination EQ index */
|
||||
#define EAS2_MASKED PPC_BIT(32) /* Masked */
|
||||
#define EAS2_END_DATA PPC_BITMASK(33, 63) /* written to the EQ */
|
||||
#define EAS2_VALID PPC_BIT(0)
|
||||
#define EAS2_QOS PPC_BIT(1, 2) /* Quality of Service(unimp) */
|
||||
#define EAS2_RESUME PPC_BIT(3) /* END Resume(unimp) */
|
||||
#define EAS2_END_BLOCK PPC_BITMASK(4, 7) /* Destination EQ block# */
|
||||
#define EAS2_END_INDEX PPC_BITMASK(8, 31) /* Destination EQ index */
|
||||
#define EAS2_MASKED PPC_BIT(32) /* Masked */
|
||||
#define EAS2_END_DATA PPC_BITMASK(33, 63) /* written to the EQ */
|
||||
} Xive2Eas;
|
||||
|
||||
#define xive2_eas_is_valid(eas) (be64_to_cpu((eas)->w) & EAS2_VALID)
|
||||
#define xive2_eas_is_masked(eas) (be64_to_cpu((eas)->w) & EAS2_MASKED)
|
||||
#define xive2_eas_is_resume(eas) (be64_to_cpu((eas)->w) & EAS2_RESUME)
|
||||
|
||||
void xive2_eas_pic_print_info(Xive2Eas *eas, uint32_t lisn, GString *buf);
|
||||
|
||||
@@ -87,6 +90,7 @@ typedef struct Xive2End {
|
||||
#define END2_W2_EQ_ADDR_HI PPC_BITMASK32(8, 31)
|
||||
uint32_t w3;
|
||||
#define END2_W3_EQ_ADDR_LO PPC_BITMASK32(0, 24)
|
||||
#define END2_W3_CL PPC_BIT32(27)
|
||||
#define END2_W3_QSIZE PPC_BITMASK32(28, 31)
|
||||
uint32_t w4;
|
||||
#define END2_W4_END_BLOCK PPC_BITMASK32(4, 7)
|
||||
@@ -154,6 +158,7 @@ typedef struct Xive2Nvp {
|
||||
#define NVP2_W0_L PPC_BIT32(8)
|
||||
#define NVP2_W0_G PPC_BIT32(9)
|
||||
#define NVP2_W0_T PPC_BIT32(10)
|
||||
#define NVP2_W0_P PPC_BIT32(11)
|
||||
#define NVP2_W0_ESC_END PPC_BIT32(25) /* 'N' bit 0:ESB 1:END */
|
||||
#define NVP2_W0_PGOFIRST PPC_BITMASK32(26, 31)
|
||||
uint32_t w1;
|
||||
@@ -205,9 +210,9 @@ static inline uint32_t xive2_nvp_idx(uint32_t cam_line)
|
||||
return cam_line & ((1 << XIVE2_NVP_SHIFT) - 1);
|
||||
}
|
||||
|
||||
static inline uint32_t xive2_nvp_blk(uint32_t cam_line)
|
||||
static inline uint8_t xive2_nvp_blk(uint32_t cam_line)
|
||||
{
|
||||
return (cam_line >> XIVE2_NVP_SHIFT) & 0xf;
|
||||
return (uint8_t)((cam_line >> XIVE2_NVP_SHIFT) & 0xf);
|
||||
}
|
||||
|
||||
void xive2_nvp_pic_print_info(Xive2Nvp *nvp, uint32_t nvp_idx, GString *buf);
|
||||
@@ -220,6 +225,9 @@ typedef struct Xive2Nvgc {
|
||||
#define NVGC2_W0_VALID PPC_BIT32(0)
|
||||
#define NVGC2_W0_PGONEXT PPC_BITMASK32(26, 31)
|
||||
uint32_t w1;
|
||||
#define NVGC2_W1_PSIZE PPC_BITMASK32(0, 1)
|
||||
#define NVGC2_W1_END_BLK PPC_BITMASK32(4, 7)
|
||||
#define NVGC2_W1_END_IDX PPC_BITMASK32(8, 31)
|
||||
uint32_t w2;
|
||||
uint32_t w3;
|
||||
uint32_t w4;
|
||||
|
||||
+21
-2
@@ -96,7 +96,17 @@ struct SDCardClass {
|
||||
DeviceClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
int (*do_command)(SDState *sd, SDRequest *req, uint8_t *response);
|
||||
/**
|
||||
* Process a SD command request.
|
||||
* @sd: card
|
||||
* @req: command request
|
||||
* @resp: buffer to receive the command response
|
||||
* @respsz: size of @resp buffer
|
||||
*
|
||||
* Return: size of the response
|
||||
*/
|
||||
size_t (*do_command)(SDState *sd, SDRequest *req,
|
||||
uint8_t *resp, size_t respsz);
|
||||
/**
|
||||
* Write a byte to a SD card.
|
||||
* @sd: card
|
||||
@@ -153,7 +163,16 @@ struct SDBusClass {
|
||||
void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts);
|
||||
uint8_t sdbus_get_dat_lines(SDBus *sdbus);
|
||||
bool sdbus_get_cmd_line(SDBus *sdbus);
|
||||
int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response);
|
||||
/**
|
||||
* sdbus_do_command: Process a SD command request
|
||||
* @sd: card
|
||||
* @req: command request
|
||||
* @resp: buffer to receive the command response
|
||||
* @respsz: size of @resp buffer
|
||||
*
|
||||
* Return: size of the response
|
||||
*/
|
||||
size_t sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *resp, size_t respsz);
|
||||
/**
|
||||
* Write a byte to a SD bus.
|
||||
* @sd: bus
|
||||
|
||||
@@ -38,6 +38,10 @@ typedef struct VFIODeviceCPR {
|
||||
uint32_t ioas_id;
|
||||
} VFIODeviceCPR;
|
||||
|
||||
typedef struct VFIOPCICPR {
|
||||
NotifierWithReturn transfer_notifier;
|
||||
} VFIOPCICPR;
|
||||
|
||||
bool vfio_legacy_cpr_register_container(struct VFIOContainer *container,
|
||||
Error **errp);
|
||||
void vfio_legacy_cpr_unregister_container(struct VFIOContainer *container);
|
||||
@@ -77,5 +81,7 @@ extern const VMStateDescription vfio_cpr_pci_vmstate;
|
||||
extern const VMStateDescription vmstate_cpr_vfio_devices;
|
||||
|
||||
void vfio_cpr_add_kvm_notifier(void);
|
||||
void vfio_cpr_pci_register_device(struct VFIOPCIDevice *vdev);
|
||||
void vfio_cpr_pci_unregister_device(struct VFIOPCIDevice *vdev);
|
||||
|
||||
#endif /* HW_VFIO_VFIO_CPR_H */
|
||||
|
||||
@@ -46,6 +46,7 @@ enum QIOChannelFeature {
|
||||
QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY,
|
||||
QIO_CHANNEL_FEATURE_READ_MSG_PEEK,
|
||||
QIO_CHANNEL_FEATURE_SEEKABLE,
|
||||
QIO_CHANNEL_FEATURE_CONCURRENT_IO,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -241,6 +241,11 @@ void qio_channel_tls_handshake(QIOChannelTLS *ioc,
|
||||
{
|
||||
QIOTask *task;
|
||||
|
||||
if (qio_channel_has_feature(QIO_CHANNEL(ioc),
|
||||
QIO_CHANNEL_FEATURE_CONCURRENT_IO)) {
|
||||
qcrypto_tls_session_require_thread_safety(ioc->session);
|
||||
}
|
||||
|
||||
task = qio_task_new(OBJECT(ioc),
|
||||
func, opaque, destroy);
|
||||
|
||||
|
||||
+136
-3
@@ -121,6 +121,30 @@ struct target_za_context {
|
||||
#define TARGET_ZA_SIG_CONTEXT_SIZE(VQ) \
|
||||
TARGET_ZA_SIG_ZAV_OFFSET(VQ, VQ * TARGET_SVE_VQ_BYTES)
|
||||
|
||||
#define TARGET_TPIDR2_MAGIC 0x54504902
|
||||
|
||||
struct target_tpidr2_context {
|
||||
struct target_aarch64_ctx head;
|
||||
uint64_t tpidr2;
|
||||
};
|
||||
|
||||
#define TARGET_ZT_MAGIC 0x5a544e01
|
||||
|
||||
struct target_zt_context {
|
||||
struct target_aarch64_ctx head;
|
||||
uint16_t nregs;
|
||||
uint16_t reserved[3];
|
||||
/* ZTn register data immediately follows */
|
||||
};
|
||||
|
||||
#define TARGET_ZT_SIG_REG_BYTES (512 / 8)
|
||||
#define TARGET_ZT_SIG_REGS_SIZE(n) (TARGET_ZT_SIG_REG_BYTES * (n))
|
||||
#define TARGET_ZT_SIG_CONTEXT_SIZE(n) (sizeof(struct target_zt_context) + \
|
||||
TARGET_ZT_SIG_REGS_SIZE(n))
|
||||
#define TARGET_ZT_SIG_REGS_OFFSET sizeof(struct target_zt_context)
|
||||
QEMU_BUILD_BUG_ON(TARGET_ZT_SIG_REG_BYTES != \
|
||||
sizeof_field(CPUARMState, za_state.zt0));
|
||||
|
||||
struct target_rt_sigframe {
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext uc;
|
||||
@@ -253,6 +277,36 @@ static void target_setup_za_record(struct target_za_context *za,
|
||||
}
|
||||
}
|
||||
|
||||
static void target_setup_tpidr2_record(struct target_tpidr2_context *tpidr2,
|
||||
CPUARMState *env)
|
||||
{
|
||||
__put_user(TARGET_TPIDR2_MAGIC, &tpidr2->head.magic);
|
||||
__put_user(sizeof(struct target_tpidr2_context), &tpidr2->head.size);
|
||||
__put_user(env->cp15.tpidr2_el0, &tpidr2->tpidr2);
|
||||
}
|
||||
|
||||
static void target_setup_zt_record(struct target_zt_context *zt,
|
||||
CPUARMState *env, int size)
|
||||
{
|
||||
uint64_t *z;
|
||||
|
||||
memset(zt, 0, sizeof(*zt));
|
||||
__put_user(TARGET_ZT_MAGIC, &zt->head.magic);
|
||||
__put_user(size, &zt->head.size);
|
||||
/*
|
||||
* The record format allows for multiple ZT regs, but
|
||||
* currently there is only one, ZT0.
|
||||
*/
|
||||
__put_user(1, &zt->nregs);
|
||||
assert(size == TARGET_ZT_SIG_CONTEXT_SIZE(1));
|
||||
|
||||
/* ZT0 is the same byte-stream format as SVE regs and ZA */
|
||||
z = (void *)zt + TARGET_ZT_SIG_REGS_OFFSET;
|
||||
for (int i = 0; i < ARRAY_SIZE(env->za_state.zt0); i++) {
|
||||
__put_user_e(env->za_state.zt0[i], z + i, le);
|
||||
}
|
||||
}
|
||||
|
||||
static void target_restore_general_frame(CPUARMState *env,
|
||||
struct target_rt_sigframe *sf)
|
||||
{
|
||||
@@ -403,6 +457,36 @@ static bool target_restore_za_record(CPUARMState *env,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void target_restore_tpidr2_record(CPUARMState *env,
|
||||
struct target_tpidr2_context *tpidr2)
|
||||
{
|
||||
__get_user(env->cp15.tpidr2_el0, &tpidr2->tpidr2);
|
||||
}
|
||||
|
||||
static bool target_restore_zt_record(CPUARMState *env,
|
||||
struct target_zt_context *zt, int size,
|
||||
int svcr)
|
||||
{
|
||||
uint16_t nregs;
|
||||
uint64_t *z;
|
||||
|
||||
if (!(FIELD_EX64(svcr, SVCR, ZA))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
__get_user(nregs, &zt->nregs);
|
||||
|
||||
if (nregs != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
z = (void *)zt + TARGET_ZT_SIG_REGS_OFFSET;
|
||||
for (int i = 0; i < ARRAY_SIZE(env->za_state.zt0); i++) {
|
||||
__get_user_e(env->za_state.zt0[i], z + i, le);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int target_restore_sigframe(CPUARMState *env,
|
||||
struct target_rt_sigframe *sf)
|
||||
{
|
||||
@@ -410,10 +494,13 @@ static int target_restore_sigframe(CPUARMState *env,
|
||||
struct target_fpsimd_context *fpsimd = NULL;
|
||||
struct target_sve_context *sve = NULL;
|
||||
struct target_za_context *za = NULL;
|
||||
struct target_tpidr2_context *tpidr2 = NULL;
|
||||
struct target_zt_context *zt = NULL;
|
||||
uint64_t extra_datap = 0;
|
||||
bool used_extra = false;
|
||||
int sve_size = 0;
|
||||
int za_size = 0;
|
||||
int zt_size = 0;
|
||||
int svcr = 0;
|
||||
|
||||
target_restore_general_frame(env, sf);
|
||||
@@ -460,6 +547,23 @@ static int target_restore_sigframe(CPUARMState *env,
|
||||
za_size = size;
|
||||
break;
|
||||
|
||||
case TARGET_TPIDR2_MAGIC:
|
||||
if (tpidr2 || size != sizeof(struct target_tpidr2_context) ||
|
||||
!cpu_isar_feature(aa64_sme, env_archcpu(env))) {
|
||||
goto err;
|
||||
}
|
||||
tpidr2 = (struct target_tpidr2_context *)ctx;
|
||||
break;
|
||||
|
||||
case TARGET_ZT_MAGIC:
|
||||
if (zt || size != TARGET_ZT_SIG_CONTEXT_SIZE(1) ||
|
||||
!cpu_isar_feature(aa64_sme2, env_archcpu(env))) {
|
||||
goto err;
|
||||
}
|
||||
zt = (struct target_zt_context *)ctx;
|
||||
zt_size = size;
|
||||
break;
|
||||
|
||||
case TARGET_EXTRA_MAGIC:
|
||||
if (extra || size != sizeof(struct target_extra_context)) {
|
||||
goto err;
|
||||
@@ -497,6 +601,16 @@ static int target_restore_sigframe(CPUARMState *env,
|
||||
if (za && !target_restore_za_record(env, za, za_size, &svcr)) {
|
||||
goto err;
|
||||
}
|
||||
if (tpidr2) {
|
||||
target_restore_tpidr2_record(env, tpidr2);
|
||||
}
|
||||
/*
|
||||
* NB that we must restore ZT after ZA so the check that there's
|
||||
* no ZT record if SVCR.ZA is 0 gets the right value of SVCR.
|
||||
*/
|
||||
if (zt && !target_restore_zt_record(env, zt, zt_size, svcr)) {
|
||||
goto err;
|
||||
}
|
||||
if (env->svcr != svcr) {
|
||||
env->svcr = svcr;
|
||||
arm_rebuild_hflags(env);
|
||||
@@ -568,8 +682,9 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
||||
.total_size = offsetof(struct target_rt_sigframe,
|
||||
uc.tuc_mcontext.__reserved),
|
||||
};
|
||||
int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0;
|
||||
int sve_size = 0, za_size = 0;
|
||||
int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0, tpidr2_ofs = 0;
|
||||
int zt_ofs = 0;
|
||||
int sve_size = 0, za_size = 0, tpidr2_size = 0, zt_size = 0;
|
||||
struct target_rt_sigframe *frame;
|
||||
struct target_rt_frame_record *fr;
|
||||
abi_ulong frame_addr, return_addr;
|
||||
@@ -585,6 +700,8 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
||||
sve_ofs = alloc_sigframe_space(sve_size, &layout);
|
||||
}
|
||||
if (cpu_isar_feature(aa64_sme, env_archcpu(env))) {
|
||||
tpidr2_size = sizeof(struct target_tpidr2_context);
|
||||
tpidr2_ofs = alloc_sigframe_space(tpidr2_size, &layout);
|
||||
/* ZA state needs saving only if it is enabled. */
|
||||
if (FIELD_EX64(env->svcr, SVCR, ZA)) {
|
||||
za_size = TARGET_ZA_SIG_CONTEXT_SIZE(sme_vq(env));
|
||||
@@ -593,6 +710,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
||||
}
|
||||
za_ofs = alloc_sigframe_space(za_size, &layout);
|
||||
}
|
||||
if (cpu_isar_feature(aa64_sme2, env_archcpu(env)) &&
|
||||
FIELD_EX64(env->svcr, SVCR, ZA)) {
|
||||
/* If SME ZA storage is enabled, we must also save SME2 ZT0 */
|
||||
zt_size = TARGET_ZT_SIG_CONTEXT_SIZE(1);
|
||||
zt_ofs = alloc_sigframe_space(zt_size, &layout);
|
||||
}
|
||||
|
||||
if (layout.extra_ofs) {
|
||||
/* Reserve space for the extra end marker. The standard end marker
|
||||
@@ -644,6 +767,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
||||
if (za_ofs) {
|
||||
target_setup_za_record((void *)frame + za_ofs, env, za_size);
|
||||
}
|
||||
if (tpidr2_ofs) {
|
||||
target_setup_tpidr2_record((void *)frame + tpidr2_ofs, env);
|
||||
}
|
||||
if (zt_ofs) {
|
||||
target_setup_zt_record((void *)frame + zt_ofs, env, zt_size);
|
||||
}
|
||||
|
||||
/* Set up the stack frame for unwinding. */
|
||||
fr = (void *)frame + fr_ofs;
|
||||
@@ -666,8 +795,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
||||
env->btype = 2;
|
||||
}
|
||||
|
||||
/* Invoke the signal handler with both SM and ZA disabled. */
|
||||
/*
|
||||
* Invoke the signal handler with a clean SME state: both SM and ZA
|
||||
* disabled and TPIDR2_EL0 cleared.
|
||||
*/
|
||||
aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK);
|
||||
env->cp15.tpidr2_el0 = 0;
|
||||
|
||||
if (info) {
|
||||
frame->info = *info;
|
||||
|
||||
@@ -1716,3 +1716,6 @@
|
||||
{ TARGET_NR_clock_gettime64, "clock_gettime64" , NULL, print_clock_gettime64,
|
||||
print_syscall_ret_clock_gettime64 },
|
||||
#endif
|
||||
#ifdef TARGET_NR_riscv_hwprobe
|
||||
{ TARGET_NR_riscv_hwprobe, "riscv_hwprobe" , "%s(%p,%d,%d,%d,%d,%d)", NULL, NULL },
|
||||
#endif
|
||||
|
||||
+14
-3
@@ -1586,9 +1586,11 @@ if not get_option('brlapi').auto() or have_system
|
||||
brlapi = cc.find_library('brlapi', has_headers: ['brlapi.h'],
|
||||
required: get_option('brlapi'))
|
||||
if brlapi.found() and not cc.links('''
|
||||
#include <brlapi.h>
|
||||
#include <stddef.h>
|
||||
int main(void) { return brlapi__openConnection (NULL, NULL, NULL); }''', dependencies: brlapi)
|
||||
#include <brlapi.h>
|
||||
#include <stddef.h>
|
||||
int main(void) {
|
||||
return brlapi__openConnection(NULL, NULL, NULL) == BRLAPI_INVALID_FILE_DESCRIPTOR;
|
||||
}''', dependencies: brlapi)
|
||||
brlapi = not_found
|
||||
if get_option('brlapi').enabled()
|
||||
error('could not link brlapi')
|
||||
@@ -1809,6 +1811,7 @@ endif
|
||||
|
||||
gnutls = not_found
|
||||
gnutls_crypto = not_found
|
||||
gnutls_bug1717_workaround = false
|
||||
if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_system)
|
||||
# For general TLS support our min gnutls matches
|
||||
# that implied by our platform support matrix
|
||||
@@ -1834,6 +1837,12 @@ if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_syste
|
||||
method: 'pkg-config',
|
||||
required: get_option('gnutls'))
|
||||
endif
|
||||
|
||||
#if gnutls.found() and not get_option('gnutls-bug1717-workaround').disabled()
|
||||
# XXX: when bug 1717 is resolved, add logic to probe for
|
||||
# the GNUTLS fixed version number to handle the 'auto' case
|
||||
# gnutls_bug1717_workaround = true
|
||||
#endif
|
||||
endif
|
||||
|
||||
# We prefer use of gnutls for crypto, unless the options
|
||||
@@ -2585,6 +2594,7 @@ config_host_data.set('CONFIG_KEYUTILS', keyutils.found())
|
||||
config_host_data.set('CONFIG_GETTID', has_gettid)
|
||||
config_host_data.set('CONFIG_GNUTLS', gnutls.found())
|
||||
config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
|
||||
config_host_data.set('CONFIG_GNUTLS_BUG1717_WORKAROUND', gnutls_bug1717_workaround)
|
||||
config_host_data.set('CONFIG_TASN1', tasn1.found())
|
||||
config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
|
||||
config_host_data.set('CONFIG_NETTLE', nettle.found())
|
||||
@@ -4869,6 +4879,7 @@ summary_info += {'TLS priority': get_option('tls_priority')}
|
||||
summary_info += {'GNUTLS support': gnutls}
|
||||
if gnutls.found()
|
||||
summary_info += {' GNUTLS crypto': gnutls_crypto.found()}
|
||||
summary_info += {' GNUTLS bug 1717 workaround': gnutls_bug1717_workaround }
|
||||
endif
|
||||
summary_info += {'libgcrypt': gcrypt}
|
||||
summary_info += {'nettle': nettle}
|
||||
|
||||
@@ -51,4 +51,4 @@ system_ss.add(when: qatzip, if_true: files('multifd-qatzip.c'))
|
||||
|
||||
specific_ss.add(when: 'CONFIG_SYSTEM_ONLY',
|
||||
if_true: files('ram.c',
|
||||
'target.c'))
|
||||
'vfio.c'))
|
||||
|
||||
@@ -57,11 +57,9 @@ static const gchar *format_time_str(uint64_t us)
|
||||
const char *units[] = {"us", "ms", "sec"};
|
||||
int index = 0;
|
||||
|
||||
while (us > 1000) {
|
||||
while (us >= 1000 && index + 1 < ARRAY_SIZE(units)) {
|
||||
us /= 1000;
|
||||
if (++index >= (sizeof(units) - 1)) {
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return g_strdup_printf("%"PRIu64" %s", us, units[index]);
|
||||
@@ -153,7 +151,9 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
||||
if (info->has_status) {
|
||||
monitor_printf(mon, "Status: \t\t%s",
|
||||
MigrationStatus_str(info->status));
|
||||
if (info->status == MIGRATION_STATUS_FAILED && info->error_desc) {
|
||||
if ((info->status == MIGRATION_STATUS_FAILED ||
|
||||
info->status == MIGRATION_STATUS_POSTCOPY_PAUSED) &&
|
||||
info->error_desc) {
|
||||
monitor_printf(mon, " (%s)\n", info->error_desc);
|
||||
} else {
|
||||
monitor_printf(mon, "\n");
|
||||
|
||||
@@ -90,6 +90,10 @@ void migration_tls_channel_process_incoming(MigrationState *s,
|
||||
|
||||
trace_migration_tls_incoming_handshake_start();
|
||||
qio_channel_set_name(QIO_CHANNEL(tioc), "migration-tls-incoming");
|
||||
if (migrate_postcopy_ram() || migrate_return_path()) {
|
||||
qio_channel_set_feature(QIO_CHANNEL(tioc),
|
||||
QIO_CHANNEL_FEATURE_CONCURRENT_IO);
|
||||
}
|
||||
qio_channel_tls_handshake(tioc,
|
||||
migration_tls_incoming_handshake,
|
||||
NULL,
|
||||
@@ -149,6 +153,11 @@ void migration_tls_channel_connect(MigrationState *s,
|
||||
s->hostname = g_strdup(hostname);
|
||||
trace_migration_tls_outgoing_handshake_start(hostname);
|
||||
qio_channel_set_name(QIO_CHANNEL(tioc), "migration-tls-outgoing");
|
||||
|
||||
if (migrate_postcopy_ram() || migrate_return_path()) {
|
||||
qio_channel_set_feature(QIO_CHANNEL(tioc),
|
||||
QIO_CHANNEL_FEATURE_CONCURRENT_IO);
|
||||
}
|
||||
qio_channel_tls_handshake(tioc,
|
||||
migration_tls_outgoing_handshake,
|
||||
s,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* QEMU live migration - functions that need to be compiled target-specific
|
||||
* QEMU live migration - VFIO
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2
|
||||
* or (at your option) any later version.
|
||||
+2
-3
@@ -1840,9 +1840,8 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
|
||||
|
||||
queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, features,
|
||||
&has_cvq, errp);
|
||||
if (queue_pairs < 0) {
|
||||
qemu_close(vdpa_device_fd);
|
||||
return queue_pairs;
|
||||
if (queue_pairs <= 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range);
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -84,6 +84,7 @@ from typing import (
|
||||
Sequence,
|
||||
Tuple,
|
||||
Union,
|
||||
cast,
|
||||
)
|
||||
import venv
|
||||
|
||||
@@ -94,17 +95,39 @@ import venv
|
||||
HAVE_DISTLIB = True
|
||||
try:
|
||||
import distlib.scripts
|
||||
import distlib.version
|
||||
except ImportError:
|
||||
try:
|
||||
# Reach into pip's cookie jar. pylint and flake8 don't understand
|
||||
# that these imports will be used via distlib.xxx.
|
||||
from pip._vendor import distlib
|
||||
import pip._vendor.distlib.scripts # noqa, pylint: disable=unused-import
|
||||
import pip._vendor.distlib.version # noqa, pylint: disable=unused-import
|
||||
except ImportError:
|
||||
HAVE_DISTLIB = False
|
||||
|
||||
# pip 25.2 does not vendor distlib.version, but it uses vendored
|
||||
# packaging.version
|
||||
HAVE_DISTLIB_VERSION = True
|
||||
try:
|
||||
import distlib.version # pylint: disable=ungrouped-imports
|
||||
except ImportError:
|
||||
try:
|
||||
# pylint: disable=unused-import,ungrouped-imports
|
||||
import pip._vendor.distlib.version # noqa
|
||||
except ImportError:
|
||||
HAVE_DISTLIB_VERSION = False
|
||||
|
||||
HAVE_PACKAGING_VERSION = True
|
||||
try:
|
||||
# Do not bother importing non-vendored packaging, because it is not
|
||||
# in stdlib.
|
||||
from pip._vendor import packaging
|
||||
# pylint: disable=unused-import
|
||||
import pip._vendor.packaging.requirements # noqa
|
||||
import pip._vendor.packaging.version # noqa
|
||||
except ImportError:
|
||||
HAVE_PACKAGING_VERSION = False
|
||||
|
||||
|
||||
# Try to load tomllib, with a fallback to tomli.
|
||||
# HAVE_TOMLLIB is checked below, just-in-time, so that mkvenv does not fail
|
||||
# outside the venv or before a potential call to ensurepip in checkpip().
|
||||
@@ -133,6 +156,39 @@ class Ouch(RuntimeError):
|
||||
"""An Exception class we can't confuse with a builtin."""
|
||||
|
||||
|
||||
class Matcher:
|
||||
"""Compatibility appliance for version/requirement string parsing."""
|
||||
def __init__(self, name_and_constraint: str):
|
||||
"""Create a matcher from a requirement-like string."""
|
||||
if HAVE_DISTLIB_VERSION:
|
||||
self._m = distlib.version.LegacyMatcher(name_and_constraint)
|
||||
elif HAVE_PACKAGING_VERSION:
|
||||
self._m = packaging.requirements.Requirement(name_and_constraint)
|
||||
else:
|
||||
raise Ouch("found neither distlib.version nor packaging.version")
|
||||
self.name = self._m.name
|
||||
|
||||
def match(self, version_str: str) -> bool:
|
||||
"""Return True if `version` satisfies the stored constraint."""
|
||||
if HAVE_DISTLIB_VERSION:
|
||||
return cast(
|
||||
bool,
|
||||
self._m.match(distlib.version.LegacyVersion(version_str))
|
||||
)
|
||||
|
||||
assert HAVE_PACKAGING_VERSION
|
||||
return cast(
|
||||
bool,
|
||||
self._m.specifier.contains(
|
||||
packaging.version.Version(version_str), prereleases=True
|
||||
)
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Stable debug representation delegated to the backend."""
|
||||
return repr(self._m)
|
||||
|
||||
|
||||
class QemuEnvBuilder(venv.EnvBuilder):
|
||||
"""
|
||||
An extension of venv.EnvBuilder for building QEMU's configure-time venv.
|
||||
@@ -669,7 +725,7 @@ def _do_ensure(
|
||||
canary = None
|
||||
for name, info in group.items():
|
||||
constraint = _make_version_constraint(info, False)
|
||||
matcher = distlib.version.LegacyMatcher(name + constraint)
|
||||
matcher = Matcher(name + constraint)
|
||||
print(f"mkvenv: checking for {matcher}", file=sys.stderr)
|
||||
|
||||
dist: Optional[Distribution] = None
|
||||
@@ -683,7 +739,7 @@ def _do_ensure(
|
||||
# Always pass installed package to pip, so that they can be
|
||||
# updated if the requested version changes
|
||||
or not _is_system_package(dist)
|
||||
or not matcher.match(distlib.version.LegacyVersion(dist.version))
|
||||
or not matcher.match(dist.version)
|
||||
):
|
||||
absent.append(name + _make_version_constraint(info, True))
|
||||
if len(absent) == 1:
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
meson = { accepted = ">=1.5.0", installed = "1.8.1", canary = "meson" }
|
||||
pycotap = { accepted = ">=1.1.0", installed = "1.3.1" }
|
||||
|
||||
[meson-rust]
|
||||
# The install key should match the version in python/wheels/
|
||||
meson = { accepted = ">=1.8.1", installed = "1.8.1", canary = "meson" }
|
||||
|
||||
[docs]
|
||||
# Please keep the installed versions in sync with docs/requirements.txt
|
||||
sphinx = { accepted = ">=3.4.3", installed = "6.2.1", canary = "sphinx-build" }
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
##
|
||||
# = Accelerators
|
||||
# ************
|
||||
# Accelerators
|
||||
# ************
|
||||
##
|
||||
|
||||
{ 'include': 'common.json' }
|
||||
|
||||
@@ -159,7 +159,14 @@
|
||||
##
|
||||
# @ImageInfoSpecificRbd:
|
||||
#
|
||||
# @encryption-format: Image encryption format
|
||||
# @encryption-format: Image encryption format. If encryption is enabled for the
|
||||
# image (see encrypted in BlockNodeInfo), this is the actual format in which the
|
||||
# image is accessed. If encryption is not enabled, this is the result of
|
||||
# probing when the image was opened, to give a suggestion which encryption
|
||||
# format could be enabled. Note that probing results can be changed by the
|
||||
# guest by writing a (possibly partial) encryption format header to the
|
||||
# image, so don't treat this information as trusted if the guest is not
|
||||
# trusted.
|
||||
#
|
||||
# Since: 6.1
|
||||
##
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@
|
||||
#
|
||||
# @detach: if true, QMP will return immediately rather than waiting
|
||||
# for the dump to finish. The user can track progress using
|
||||
# "query-dump". (since 2.6).
|
||||
# `query-dump`. (since 2.6).
|
||||
#
|
||||
# @begin: if specified, the starting physical address.
|
||||
#
|
||||
|
||||
+1
-1
@@ -2087,7 +2087,7 @@
|
||||
#
|
||||
# @deprecated-props: an optional list of properties that are flagged as
|
||||
# deprecated by the CPU vendor. The list depends on the
|
||||
# CpuModelExpansionType: "static" properties are a subset of the
|
||||
# `CpuModelExpansionType`: "static" properties are a subset of the
|
||||
# enabled-properties for the expanded model; "full" properties are
|
||||
# a set of properties that are deprecated across all models for
|
||||
# the architecture. (since: 10.1 -- since 9.1 on s390x --).
|
||||
|
||||
+2
-2
@@ -641,7 +641,7 @@
|
||||
#
|
||||
# This mode supports VFIO devices provided the user first puts the
|
||||
# guest in the suspended runstate, such as by issuing
|
||||
# guest-suspend-ram to the QEMU guest agent.
|
||||
# `guest-suspend-ram` to the QEMU guest agent.
|
||||
#
|
||||
# Best performance is achieved when the memory backend is shared
|
||||
# and the @x-ignore-shared migration capability is set, but this
|
||||
@@ -1704,7 +1704,7 @@
|
||||
#
|
||||
# .. admonition:: Notes
|
||||
#
|
||||
# 1. The 'query-migrate' command should be used to check
|
||||
# 1. The `query-migrate` command should be used to check
|
||||
# migration's progress and final result (this information is
|
||||
# provided by the 'status' member).
|
||||
#
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
#
|
||||
# Reset the RTC interrupt reinjection backlog. Can be used if another
|
||||
# mechanism to synchronize guest time is in effect, for example QEMU
|
||||
# guest agent's guest-set-time command.
|
||||
# guest agent's `guest-set-time` command.
|
||||
#
|
||||
# Use of this command is only applicable for x86 machines with an RTC,
|
||||
# and on other machines will silently return without performing any
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
# @inmigrate: guest is paused waiting for an incoming migration. Note
|
||||
# that this state does not tell whether the machine will start at
|
||||
# the end of the migration. This depends on the command-line -S
|
||||
# option and any invocation of 'stop' or 'cont' that has happened
|
||||
# option and any invocation of `stop` or `cont` that has happened
|
||||
# since QEMU was started.
|
||||
#
|
||||
# @internal-error: An internal error that prevents further guest
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@
|
||||
#
|
||||
# @str: decimal is for file descriptor number, otherwise it's a file
|
||||
# descriptor name. Named file descriptors are permitted in
|
||||
# monitor commands, in combination with the 'getfd' command.
|
||||
# monitor commands, in combination with the `getfd` command.
|
||||
# Decimal file descriptors are permitted at startup or other
|
||||
# contexts where no monitor context is active.
|
||||
#
|
||||
|
||||
@@ -1400,20 +1400,22 @@ static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp)
|
||||
|
||||
static void linux_sys_state_suspend(SuspendMode mode, Error **errp)
|
||||
{
|
||||
g_autoptr(GError) local_gerr = NULL;
|
||||
const char *sysfile_strs[3] = {"disk", "mem", NULL};
|
||||
const char *sysfile_str = sysfile_strs[mode];
|
||||
int fd;
|
||||
|
||||
if (!sysfile_str) {
|
||||
error_setg(errp, "unknown guest suspend mode");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str,
|
||||
-1, &local_gerr)) {
|
||||
error_setg(errp, "suspend: cannot write to '%s': %s",
|
||||
LINUX_SYS_STATE_FILE, local_gerr->message);
|
||||
return;
|
||||
fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
|
||||
if (fd < 0 || write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
|
||||
error_setg(errp, "suspend: cannot write to '%s': %m",
|
||||
LINUX_SYS_STATE_FILE);
|
||||
}
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+42
-67
@@ -96,11 +96,11 @@
|
||||
# In cases where a partial stale response was previously received by
|
||||
# the client, this cannot always be done reliably. One particular
|
||||
# scenario being if qemu-ga responses are fed character-by-character
|
||||
# into a JSON parser. In these situations, using guest-sync-delimited
|
||||
# into a JSON parser. In these situations, using `guest-sync-delimited`
|
||||
# may be optimal.
|
||||
#
|
||||
# For clients that fetch responses line by line and convert them to
|
||||
# JSON objects, guest-sync should be sufficient, but note that in
|
||||
# JSON objects, `guest-sync` should be sufficient, but note that in
|
||||
# cases where the channel is dirty some attempts at parsing the
|
||||
# response may result in a parser error.
|
||||
#
|
||||
@@ -202,8 +202,6 @@
|
||||
#
|
||||
# Get some information about the guest agent.
|
||||
#
|
||||
# Returns: @GuestAgentInfo
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
{ 'command': 'guest-info',
|
||||
@@ -219,7 +217,7 @@
|
||||
#
|
||||
# This command does NOT return a response on success. Success
|
||||
# condition is indicated by the VM exiting with a zero exit status or,
|
||||
# when running with --no-shutdown, by issuing the query-status QMP
|
||||
# when running with --no-shutdown, by issuing the `query-status` QMP
|
||||
# command to confirm the VM status is "shutdown".
|
||||
#
|
||||
# Since: 0.15.0
|
||||
@@ -249,7 +247,7 @@
|
||||
#
|
||||
# Close an open file in the guest
|
||||
#
|
||||
# @handle: filehandle returned by guest-file-open
|
||||
# @handle: filehandle returned by `guest-file-open`
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
@@ -280,13 +278,11 @@
|
||||
# As this command is just for limited, ad-hoc debugging, such as log
|
||||
# file access, the number of bytes to read is limited to 48 MB.
|
||||
#
|
||||
# @handle: filehandle returned by guest-file-open
|
||||
# @handle: filehandle returned by `guest-file-open`
|
||||
#
|
||||
# @count: maximum number of bytes to read (default is 4KB, maximum is
|
||||
# 48MB)
|
||||
#
|
||||
# Returns: @GuestFileRead
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
{ 'command': 'guest-file-read',
|
||||
@@ -313,15 +309,13 @@
|
||||
#
|
||||
# Write to an open file in the guest.
|
||||
#
|
||||
# @handle: filehandle returned by guest-file-open
|
||||
# @handle: filehandle returned by `guest-file-open`
|
||||
#
|
||||
# @buf-b64: base64-encoded string representing data to be written
|
||||
#
|
||||
# @count: bytes to write (actual bytes, after base64-decode), default
|
||||
# is all content in buf-b64 buffer after base64 decoding
|
||||
#
|
||||
# Returns: @GuestFileWrite
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
{ 'command': 'guest-file-write',
|
||||
@@ -346,7 +340,7 @@
|
||||
##
|
||||
# @QGASeek:
|
||||
#
|
||||
# Symbolic names for use in @guest-file-seek
|
||||
# Symbolic names for use in `guest-file-seek`
|
||||
#
|
||||
# @set: Set to the specified offset (same effect as 'whence':0)
|
||||
#
|
||||
@@ -361,7 +355,7 @@
|
||||
##
|
||||
# @GuestFileWhence:
|
||||
#
|
||||
# Controls the meaning of offset to @guest-file-seek.
|
||||
# Controls the meaning of offset to `guest-file-seek`.
|
||||
#
|
||||
# @value: Integral value (0 for set, 1 for cur, 2 for end), available
|
||||
# for historical reasons, and might differ from the host's or
|
||||
@@ -381,14 +375,12 @@
|
||||
# current file position afterward. Also encapsulates ftell()'s
|
||||
# functionality, with offset=0 and whence=1.
|
||||
#
|
||||
# @handle: filehandle returned by guest-file-open
|
||||
# @handle: filehandle returned by `guest-file-open`
|
||||
#
|
||||
# @offset: bytes to skip over in the file stream
|
||||
#
|
||||
# @whence: Symbolic or numeric code for interpreting offset
|
||||
#
|
||||
# Returns: @GuestFileSeek
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
{ 'command': 'guest-file-seek',
|
||||
@@ -401,7 +393,7 @@
|
||||
#
|
||||
# Write file changes buffered in userspace to disk/kernel buffers
|
||||
#
|
||||
# @handle: filehandle returned by guest-file-open
|
||||
# @handle: filehandle returned by `guest-file-open`
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
@@ -428,9 +420,6 @@
|
||||
#
|
||||
# Get guest fsfreeze state.
|
||||
#
|
||||
# Returns: GuestFsfreezeStatus ("thawed", "frozen", etc., as defined
|
||||
# below)
|
||||
#
|
||||
# .. note:: This may fail to properly report the current state as a
|
||||
# result of some other guest processes having issued an fs
|
||||
# freeze/thaw.
|
||||
@@ -445,12 +434,12 @@
|
||||
# @guest-fsfreeze-freeze:
|
||||
#
|
||||
# Sync and freeze all freezable, local guest filesystems. If this
|
||||
# command succeeded, you may call @guest-fsfreeze-thaw later to
|
||||
# command succeeded, you may call `guest-fsfreeze-thaw` later to
|
||||
# unfreeze.
|
||||
#
|
||||
# On error, all filesystems will be thawed. If no filesystems are
|
||||
# frozen as a result of this call, then @guest-fsfreeze-status will
|
||||
# remain "thawed" and calling @guest-fsfreeze-thaw is not necessary.
|
||||
# frozen as a result of this call, then `guest-fsfreeze-status` will
|
||||
# remain "thawed" and calling `guest-fsfreeze-thaw` is not necessary.
|
||||
#
|
||||
# Returns: Number of file systems currently frozen.
|
||||
#
|
||||
@@ -468,7 +457,7 @@
|
||||
# @guest-fsfreeze-freeze-list:
|
||||
#
|
||||
# Sync and freeze specified guest filesystems. See also
|
||||
# @guest-fsfreeze-freeze.
|
||||
# `guest-fsfreeze-freeze`.
|
||||
#
|
||||
# On error, all filesystems will be thawed.
|
||||
#
|
||||
@@ -493,7 +482,7 @@
|
||||
# Returns: Number of file systems thawed by this call
|
||||
#
|
||||
# .. note:: If the return value does not match the previous call to
|
||||
# guest-fsfreeze-freeze, this likely means some freezable filesystems
|
||||
# `guest-fsfreeze-freeze`, this likely means some freezable filesystems
|
||||
# were unfrozen before this call, and that the filesystem state may
|
||||
# have changed before issuing this command.
|
||||
#
|
||||
@@ -524,7 +513,7 @@
|
||||
##
|
||||
# @GuestFilesystemTrimResponse:
|
||||
#
|
||||
# @paths: list of @GuestFilesystemTrimResult per path that was trimmed
|
||||
# @paths: list of `GuestFilesystemTrimResult` per path that was trimmed
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
@@ -545,8 +534,7 @@
|
||||
# discarded. The default value is zero, meaning "discard every
|
||||
# free block".
|
||||
#
|
||||
# Returns: A @GuestFilesystemTrimResponse which contains the status of
|
||||
# all trimmed paths. (since 2.4)
|
||||
# Returns: status of all trimmed paths. (since 2.4)
|
||||
#
|
||||
# Since: 1.2
|
||||
##
|
||||
@@ -569,7 +557,7 @@
|
||||
#
|
||||
# This command does NOT return a response on success. There is a high
|
||||
# chance the command succeeded if the VM exits with a zero exit status
|
||||
# or, when running with --no-shutdown, by issuing the query-status QMP
|
||||
# or, when running with --no-shutdown, by issuing the `query-status` QMP
|
||||
# command to to confirm the VM status is "shutdown". However, the VM
|
||||
# could also exit (or set its status to "shutdown") due to other
|
||||
# reasons.
|
||||
@@ -577,7 +565,7 @@
|
||||
# Errors:
|
||||
# - If suspend to disk is not supported, Unsupported
|
||||
#
|
||||
# .. note:: It's strongly recommended to issue the guest-sync command
|
||||
# .. note:: It's strongly recommended to issue the `guest-sync` command
|
||||
# before sending commands when the guest resumes.
|
||||
#
|
||||
# Since: 1.1
|
||||
@@ -597,8 +585,8 @@
|
||||
# - pm-utils (via pm-hibernate)
|
||||
# - manual write into sysfs
|
||||
#
|
||||
# IMPORTANT: guest-suspend-ram requires working wakeup support in
|
||||
# QEMU. You should check QMP command query-current-machine returns
|
||||
# IMPORTANT: `guest-suspend-ram` requires working wakeup support in
|
||||
# QEMU. You should check QMP command `query-current-machine` returns
|
||||
# wakeup-suspend-support: true before issuing this command. Failure
|
||||
# in doing so can result in a suspended guest that QEMU will not be
|
||||
# able to awaken, forcing the user to power cycle the guest to bring
|
||||
@@ -607,14 +595,14 @@
|
||||
# This command does NOT return a response on success. There are two
|
||||
# options to check for success:
|
||||
#
|
||||
# 1. Wait for the SUSPEND QMP event from QEMU
|
||||
# 2. Issue the query-status QMP command to confirm the VM status is
|
||||
# 1. Wait for the `SUSPEND` QMP event from QEMU
|
||||
# 2. Issue the `query-status` QMP command to confirm the VM status is
|
||||
# "suspended"
|
||||
#
|
||||
# Errors:
|
||||
# - If suspend to ram is not supported, Unsupported
|
||||
#
|
||||
# .. note:: It's strongly recommended to issue the guest-sync command
|
||||
# .. note:: It's strongly recommended to issue the `guest-sync` command
|
||||
# before sending commands when the guest resumes.
|
||||
#
|
||||
# Since: 1.1
|
||||
@@ -633,8 +621,8 @@
|
||||
# - systemd hybrid-sleep
|
||||
# - pm-utils (via pm-suspend-hybrid)
|
||||
#
|
||||
# IMPORTANT: guest-suspend-hybrid requires working wakeup support in
|
||||
# QEMU. You should check QMP command query-current-machine returns
|
||||
# IMPORTANT: `guest-suspend-hybrid` requires working wakeup support in
|
||||
# QEMU. You should check QMP command `query-current-machine` returns
|
||||
# wakeup-suspend-support: true before issuing this command. Failure
|
||||
# in doing so can result in a suspended guest that QEMU will not be
|
||||
# able to awaken, forcing the user to power cycle the guest to bring
|
||||
@@ -643,14 +631,14 @@
|
||||
# This command does NOT return a response on success. There are two
|
||||
# options to check for success:
|
||||
#
|
||||
# 1. Wait for the SUSPEND QMP event from QEMU
|
||||
# 2. Issue the query-status QMP command to confirm the VM status is
|
||||
# 1. Wait for the `SUSPEND` QMP event from QEMU
|
||||
# 2. Issue the `query-status` QMP command to confirm the VM status is
|
||||
# "suspended"
|
||||
#
|
||||
# Errors:
|
||||
# - If hybrid suspend is not supported, Unsupported
|
||||
#
|
||||
# .. note:: It's strongly recommended to issue the guest-sync command
|
||||
# .. note:: It's strongly recommended to issue the `guest-sync` command
|
||||
# before sending commands when the guest resumes.
|
||||
#
|
||||
# Since: 1.1
|
||||
@@ -749,8 +737,6 @@
|
||||
#
|
||||
# Get list of guest IP addresses, MAC addresses and netmasks.
|
||||
#
|
||||
# Returns: List of GuestNetworkInterface
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'guest-network-get-interfaces',
|
||||
@@ -807,7 +793,7 @@
|
||||
# There's no restriction on list length or on repeating the same
|
||||
# @logical-id (with possibly different @online field). Preferably
|
||||
# the input list should describe a modified subset of
|
||||
# @guest-get-vcpus' return value.
|
||||
# `guest-get-vcpus`' return value.
|
||||
#
|
||||
# Returns: The length of the initial sublist that has been
|
||||
# successfully processed. The guest agent maximizes this value.
|
||||
@@ -1083,7 +1069,7 @@
|
||||
#
|
||||
# Returns: The list of filesystems information mounted in the guest.
|
||||
# The returned mountpoints may be specified to
|
||||
# @guest-fsfreeze-freeze-list. Network filesystems (such as CIFS
|
||||
# `guest-fsfreeze-freeze-list`. Network filesystems (such as CIFS
|
||||
# and NFS) are not listed.
|
||||
#
|
||||
# Since: 2.2
|
||||
@@ -1185,7 +1171,7 @@
|
||||
##
|
||||
# @GuestMemoryBlockResponse:
|
||||
#
|
||||
# @phys-index: same with the 'phys-index' member of @GuestMemoryBlock.
|
||||
# @phys-index: same with the 'phys-index' member of `GuestMemoryBlock`.
|
||||
#
|
||||
# @response: the result of memory block operation.
|
||||
#
|
||||
@@ -1215,11 +1201,11 @@
|
||||
# guest-supported identifiers. There's no restriction on list
|
||||
# length or on repeating the same @phys-index (with possibly
|
||||
# different @online field). Preferably the input list should
|
||||
# describe a modified subset of @guest-get-memory-blocks' return
|
||||
# describe a modified subset of `guest-get-memory-blocks`' return
|
||||
# value.
|
||||
#
|
||||
# Returns: The operation results, it is a list of
|
||||
# @GuestMemoryBlockResponse, which is corresponding to the input
|
||||
# `GuestMemoryBlockResponse`, which is corresponding to the input
|
||||
# list.
|
||||
#
|
||||
# Note: it will return an empty list if the @mem-blks list was
|
||||
@@ -1251,8 +1237,6 @@
|
||||
#
|
||||
# Get information relating to guest memory blocks.
|
||||
#
|
||||
# Returns: @GuestMemoryBlockInfo
|
||||
#
|
||||
# Since: 2.3
|
||||
##
|
||||
{ 'command': 'guest-get-memory-block-info',
|
||||
@@ -1274,7 +1258,7 @@
|
||||
#
|
||||
# @err-data: base64-encoded stderr of the process. Note: @out-data
|
||||
# and @err-data are present only if 'capture-output' was specified
|
||||
# for 'guest-exec'. This field will only be populated after the
|
||||
# for `guest-exec`. This field will only be populated after the
|
||||
# process exits.
|
||||
#
|
||||
# @out-truncated: true if stdout was not fully captured due to size
|
||||
@@ -1293,12 +1277,10 @@
|
||||
# @guest-exec-status:
|
||||
#
|
||||
# Check status of process associated with PID retrieved via
|
||||
# guest-exec. Reap the process and associated metadata if it has
|
||||
# `guest-exec`. Reap the process and associated metadata if it has
|
||||
# exited.
|
||||
#
|
||||
# @pid: pid returned from guest-exec
|
||||
#
|
||||
# Returns: GuestExecStatus
|
||||
# @pid: pid returned from `guest-exec`
|
||||
#
|
||||
# Since: 2.5
|
||||
##
|
||||
@@ -1319,7 +1301,7 @@
|
||||
##
|
||||
# @GuestExecCaptureOutputMode:
|
||||
#
|
||||
# An enumeration of guest-exec capture modes.
|
||||
# An enumeration of `guest-exec` capture modes.
|
||||
#
|
||||
# @none: do not capture any output
|
||||
#
|
||||
@@ -1328,7 +1310,7 @@
|
||||
# @stderr: only capture stderr
|
||||
#
|
||||
# @separated: capture both stdout and stderr, but separated into
|
||||
# GuestExecStatus out-data and err-data, respectively
|
||||
# `GuestExecStatus` out-data and err-data, respectively
|
||||
#
|
||||
# @merged: capture both stdout and stderr, but merge together into
|
||||
# out-data. Not effective on windows guests.
|
||||
@@ -1342,10 +1324,10 @@
|
||||
##
|
||||
# @GuestExecCaptureOutput:
|
||||
#
|
||||
# Controls what guest-exec output gets captures.
|
||||
# Controls what `guest-exec` output gets captures.
|
||||
#
|
||||
# @flag: captures both stdout and stderr if true. Equivalent to
|
||||
# GuestExecCaptureOutputMode::all. (since 2.5)
|
||||
# `GuestExecCaptureOutputMode`::all. (since 2.5)
|
||||
#
|
||||
# @mode: capture mode; preferred interface
|
||||
#
|
||||
@@ -1458,8 +1440,6 @@
|
||||
#
|
||||
# Retrieves the timezone information from the guest.
|
||||
#
|
||||
# Returns: A GuestTimezone dictionary.
|
||||
#
|
||||
# Since: 2.10
|
||||
##
|
||||
{ 'command': 'guest-get-timezone',
|
||||
@@ -1533,8 +1513,6 @@
|
||||
#
|
||||
# Retrieve guest operating system information
|
||||
#
|
||||
# Returns: @GuestOSInfo
|
||||
#
|
||||
# Since: 2.10
|
||||
##
|
||||
{ 'command': 'guest-get-osinfo',
|
||||
@@ -1604,8 +1582,6 @@
|
||||
#
|
||||
# Retrieve information about device drivers in Windows guest
|
||||
#
|
||||
# Returns: @GuestDeviceInfo
|
||||
#
|
||||
# Since: 5.2
|
||||
##
|
||||
{ 'command': 'guest-get-devices',
|
||||
@@ -1633,8 +1609,6 @@
|
||||
#
|
||||
# @username: the user account to add the authorized keys
|
||||
#
|
||||
# Returns: @GuestAuthorizedKeys
|
||||
#
|
||||
# Since: 5.2
|
||||
##
|
||||
{ 'command': 'guest-ssh-get-authorized-keys',
|
||||
@@ -1966,6 +1940,7 @@
|
||||
# @guest-network-get-route:
|
||||
#
|
||||
# Retrieve information about route of network.
|
||||
#
|
||||
# Returns: List of route info of guest.
|
||||
#
|
||||
# Since: 9.1
|
||||
|
||||
+9
-4
@@ -68,6 +68,7 @@ default help:
|
||||
@echo " u-boot.sam460 -- update u-boot.sam460"
|
||||
@echo " npcm7xx_bootrom -- update vbootrom for npcm7xx"
|
||||
@echo " npcm8xx_bootrom -- update vbootrom for npcm8xx"
|
||||
@echo " ast27x0_bootrom -- update vbootrom for ast27x0"
|
||||
@echo " efi -- update UEFI (edk2) platform firmware"
|
||||
@echo " opensbi32-generic -- update OpenSBI for 32-bit generic machine"
|
||||
@echo " opensbi64-generic -- update OpenSBI for 64-bit generic machine"
|
||||
@@ -193,12 +194,16 @@ qboot:
|
||||
cp qboot/build/bios.bin ../pc-bios/qboot.rom
|
||||
|
||||
npcm7xx_bootrom:
|
||||
$(MAKE) -C vbootrom CROSS_COMPILE=$(arm_cross_prefix)
|
||||
cp vbootrom/npcm7xx_bootrom.bin ../pc-bios/npcm7xx_bootrom.bin
|
||||
$(MAKE) -C vbootrom/npcm7xx CROSS_COMPILE=$(arm_cross_prefix)
|
||||
cp vbootrom/npcm7xx/npcm7xx_bootrom.bin ../pc-bios/npcm7xx_bootrom.bin
|
||||
|
||||
npcm8xx_bootrom:
|
||||
$(MAKE) -C vbootrom CROSS_COMPILE=$(aarch64_cross_prefix)
|
||||
cp vbootrom/npcm8xx_bootrom.bin ../pc-bios/npcm8xx_bootrom.bin
|
||||
$(MAKE) -C vbootrom/npcm8xx CROSS_COMPILE=$(aarch64_cross_prefix)
|
||||
cp vbootrom/npcm8xx/npcm8xx_bootrom.bin ../pc-bios/npcm8xx_bootrom.bin
|
||||
|
||||
ast27x0_bootrom:
|
||||
$(MAKE) -C vbootrom/ast27x0 CROSS_COMPILE=$(aarch64_cross_prefix)
|
||||
cp vbootrom/ast27x0/ast27x0_bootrom.bin ../pc-bios/ast27x0_bootrom.bin
|
||||
|
||||
hppa-firmware:
|
||||
$(MAKE) -C seabios-hppa parisc
|
||||
|
||||
+1
-1
Submodule roms/vbootrom updated: 1287b6e42e...183c9ff805
@@ -12,9 +12,6 @@ license.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
bilge = { version = "0.2.0" }
|
||||
bilge-impl = { version = "0.2.0" }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user