aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS10
-rw-r--r--block/crypto.c6
-rw-r--r--crypto/block-luks.c78
-rw-r--r--crypto/pbkdf-gcrypt.c21
-rw-r--r--crypto/pbkdf-nettle.c71
-rw-r--r--crypto/pbkdf-stub.c2
-rw-r--r--crypto/pbkdf.c35
-rw-r--r--crypto/tlssession.c10
-rw-r--r--crypto/trace-events1
-rw-r--r--fsdev/9p-marshal.c5
-rw-r--r--fsdev/9p-marshal.h1
-rw-r--r--hw/9pfs/9p-local.c7
-rw-r--r--hw/9pfs/9p-proxy.c75
-rw-r--r--hw/9pfs/9p.c32
-rw-r--r--hw/9pfs/9p.h1
-rw-r--r--hw/s390x/s390-virtio-ccw.c17
-rw-r--r--hw/s390x/virtio-ccw.c50
-rw-r--r--hw/s390x/virtio-ccw.h3
-rw-r--r--hw/virtio/virtio-bus.c9
-rw-r--r--hw/virtio/virtio-pci.c36
-rw-r--r--hw/virtio/virtio-pci.h5
-rw-r--r--include/crypto/pbkdf.h16
-rw-r--r--include/hw/s390x/s390-virtio-ccw.h3
-rw-r--r--include/hw/virtio/virtio-bus.h10
-rw-r--r--qapi-schema.json8
-rw-r--r--qapi/crypto.json6
-rw-r--r--target-s390x/kvm.c2
-rw-r--r--tests/Makefile.include2
-rw-r--r--tests/test-crypto-pbkdf.c54
-rw-r--r--tests/virtio-9p-test.c119
30 files changed, 518 insertions, 177 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index d4ee9495b0..09d13bf1c0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -669,6 +669,9 @@ F: hw/s390x/
F: include/hw/s390x/
F: pc-bios/s390-ccw/
F: hw/watchdog/wdt_diag288.c
+F: include/hw/watchdog/wdt_diag288.h
+F: pc-bios/s390-ccw.img
+F: default-configs/s390x-softmmu.mak
T: git git://github.com/cohuck/qemu.git s390-next
T: git git://github.com/borntraeger/qemu.git s390-next
@@ -831,6 +834,7 @@ Network devices
M: Jason Wang <jasowang@redhat.com>
S: Odd Fixes
F: hw/net/
+F: tests/virtio-net-test.c
T: git git://github.com/jasowang/qemu.git net
SCSI
@@ -838,6 +842,7 @@ M: Paolo Bonzini <pbonzini@redhat.com>
S: Supported
F: include/hw/scsi/*
F: hw/scsi/*
+F: tests/virtio-scsi-test.c
T: git git://github.com/bonzini/qemu.git scsi-next
LSI53C895A
@@ -890,6 +895,7 @@ S: Supported
F: hw/*/virtio*
F: net/vhost-user.c
F: include/hw/virtio/
+F: tests/virtio-balloon-test.c
virtio-9p
M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
@@ -907,6 +913,7 @@ L: qemu-block@nongnu.org
S: Supported
F: hw/block/virtio-blk.c
F: hw/block/dataplane/*
+F: tests/virtio-blk-test.c
T: git git://github.com/stefanha/qemu.git block
virtio-ccw
@@ -929,6 +936,8 @@ S: Supported
F: hw/char/virtio-serial-bus.c
F: hw/char/virtio-console.c
F: include/hw/virtio/virtio-serial.h
+F: tests/virtio-console-test.c
+F: tests/virtio-serial-test.c
virtio-rng
M: Amit Shah <amit.shah@redhat.com>
@@ -937,6 +946,7 @@ F: hw/virtio/virtio-rng.c
F: include/hw/virtio/virtio-rng.h
F: include/sysemu/rng*.h
F: backends/rng*.c
+F: tests/virtio-rng-test.c
nvme
M: Keith Busch <keith.busch@intel.com>
diff --git a/block/crypto.c b/block/crypto.c
index 7f61e12686..7aa7eb553e 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -33,6 +33,7 @@
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg"
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
+#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
typedef struct BlockCrypto BlockCrypto;
@@ -183,6 +184,11 @@ static QemuOptsList block_crypto_create_opts_luks = {
.type = QEMU_OPT_STRING,
.help = "Name of encryption hash algorithm",
},
+ {
+ .name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME,
+ .type = QEMU_OPT_NUMBER,
+ .help = "Time to spend in PBKDF in milliseconds",
+ },
{ /* end of list */ }
},
};
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index aba4455646..a848232034 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -917,8 +917,12 @@ qcrypto_block_luks_create(QCryptoBlock *block,
const char *hash_alg;
char *cipher_mode_spec = NULL;
QCryptoCipherAlgorithm ivcipheralg = 0;
+ uint64_t iters;
memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts));
+ if (!luks_opts.has_iter_time) {
+ luks_opts.iter_time = 2000;
+ }
if (!luks_opts.has_cipher_alg) {
luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256;
}
@@ -1064,26 +1068,40 @@ qcrypto_block_luks_create(QCryptoBlock *block,
/* Determine how many iterations we need to hash the master
* key, in order to have 1 second of compute time used
*/
- luks->header.master_key_iterations =
- qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
- masterkey, luks->header.key_bytes,
- luks->header.master_key_salt,
- QCRYPTO_BLOCK_LUKS_SALT_LEN,
- &local_err);
+ iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
+ masterkey, luks->header.key_bytes,
+ luks->header.master_key_salt,
+ QCRYPTO_BLOCK_LUKS_SALT_LEN,
+ QCRYPTO_BLOCK_LUKS_DIGEST_LEN,
+ &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto error;
}
+ if (iters > (ULLONG_MAX / luks_opts.iter_time)) {
+ error_setg_errno(errp, ERANGE,
+ "PBKDF iterations %llu too large to scale",
+ (unsigned long long)iters);
+ goto error;
+ }
+
+ /* iter_time was in millis, but count_iters reported for secs */
+ iters = iters * luks_opts.iter_time / 1000;
+
/* Why /= 8 ? That matches cryptsetup, but there's no
* explanation why they chose /= 8... Probably so that
* if all 8 keyslots are active we only spend 1 second
* in total time to check all keys */
- luks->header.master_key_iterations /= 8;
- luks->header.master_key_iterations = MAX(
- luks->header.master_key_iterations,
- QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);
-
+ iters /= 8;
+ if (iters > UINT32_MAX) {
+ error_setg_errno(errp, ERANGE,
+ "PBKDF iterations %llu larger than %u",
+ (unsigned long long)iters, UINT32_MAX);
+ goto error;
+ }
+ iters = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);
+ luks->header.master_key_iterations = iters;
/* Hash the master key, saving the result in the LUKS
* header. This hash is used when opening the encrypted
@@ -1131,22 +1149,36 @@ qcrypto_block_luks_create(QCryptoBlock *block,
/* Again we determine how many iterations are required to
* hash the user password while consuming 1 second of compute
* time */
- luks->header.key_slots[0].iterations =
- qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
- (uint8_t *)password, strlen(password),
- luks->header.key_slots[0].salt,
- QCRYPTO_BLOCK_LUKS_SALT_LEN,
- &local_err);
+ iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
+ (uint8_t *)password, strlen(password),
+ luks->header.key_slots[0].salt,
+ QCRYPTO_BLOCK_LUKS_SALT_LEN,
+ luks->header.key_bytes,
+ &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto error;
}
- /* Why /= 2 ? That matches cryptsetup, but there's no
- * explanation why they chose /= 2... */
- luks->header.key_slots[0].iterations /= 2;
- luks->header.key_slots[0].iterations = MAX(
- luks->header.key_slots[0].iterations,
- QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
+
+ if (iters > (ULLONG_MAX / luks_opts.iter_time)) {
+ error_setg_errno(errp, ERANGE,
+ "PBKDF iterations %llu too large to scale",
+ (unsigned long long)iters);
+ goto error;
+ }
+
+ /* iter_time was in millis, but count_iters reported for secs */
+ iters = iters * luks_opts.iter_time / 1000;
+
+ if (iters > UINT32_MAX) {
+ error_setg_errno(errp, ERANGE,
+ "PBKDF iterations %llu larger than %u",
+ (unsigned long long)iters, UINT32_MAX);
+ goto error;
+ }
+
+ luks->header.key_slots[0].iterations =
+ MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
/* Generate a key that we'll use to encrypt the master
diff --git a/crypto/pbkdf-gcrypt.c b/crypto/pbkdf-gcrypt.c
index 34af3a97e9..40289858bf 100644
--- a/crypto/pbkdf-gcrypt.c
+++ b/crypto/pbkdf-gcrypt.c
@@ -28,7 +28,11 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
switch (hash) {
case QCRYPTO_HASH_ALG_MD5:
case QCRYPTO_HASH_ALG_SHA1:
+ case QCRYPTO_HASH_ALG_SHA224:
case QCRYPTO_HASH_ALG_SHA256:
+ case QCRYPTO_HASH_ALG_SHA384:
+ case QCRYPTO_HASH_ALG_SHA512:
+ case QCRYPTO_HASH_ALG_RIPEMD160:
return true;
default:
return false;
@@ -38,20 +42,33 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
- unsigned int iterations,
+ uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp)
{
static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
[QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5,
[QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1,
+ [QCRYPTO_HASH_ALG_SHA224] = GCRY_MD_SHA224,
[QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256,
+ [QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384,
+ [QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512,
+ [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160,
};
int ret;
+ if (iterations > ULONG_MAX) {
+ error_setg_errno(errp, ERANGE,
+ "PBKDF iterations %llu must be less than %lu",
+ (long long unsigned)iterations, ULONG_MAX);
+ return -1;
+ }
+
if (hash >= G_N_ELEMENTS(hash_map) ||
hash_map[hash] == GCRY_MD_NONE) {
- error_setg(errp, "Unexpected hash algorithm %d", hash);
+ error_setg_errno(errp, ENOSYS,
+ "PBKDF does not support hash algorithm %s",
+ QCryptoHashAlgorithm_lookup[hash]);
return -1;
}
diff --git a/crypto/pbkdf-nettle.c b/crypto/pbkdf-nettle.c
index d681a606f9..6fb2671656 100644
--- a/crypto/pbkdf-nettle.c
+++ b/crypto/pbkdf-nettle.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include <nettle/pbkdf2.h>
+#include <nettle/hmac.h>
#include "qapi/error.h"
#include "crypto/pbkdf.h"
@@ -28,7 +29,11 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
{
switch (hash) {
case QCRYPTO_HASH_ALG_SHA1:
+ case QCRYPTO_HASH_ALG_SHA224:
case QCRYPTO_HASH_ALG_SHA256:
+ case QCRYPTO_HASH_ALG_SHA384:
+ case QCRYPTO_HASH_ALG_SHA512:
+ case QCRYPTO_HASH_ALG_RIPEMD160:
return true;
default:
return false;
@@ -38,28 +43,74 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
- unsigned int iterations,
+ uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp)
{
+ union {
+ struct hmac_md5_ctx md5;
+ struct hmac_sha1_ctx sha1;
+ struct hmac_sha224_ctx sha224;
+ struct hmac_sha256_ctx sha256;
+ struct hmac_sha384_ctx sha384;
+ struct hmac_sha512_ctx sha512;
+ struct hmac_ripemd160_ctx ripemd160;
+ } ctx;
+
+ if (iterations > UINT_MAX) {
+ error_setg_errno(errp, ERANGE,
+ "PBKDF iterations %llu must be less than %u",
+ (long long unsigned)iterations, UINT_MAX);
+ return -1;
+ }
+
switch (hash) {
+ case QCRYPTO_HASH_ALG_MD5:
+ hmac_md5_set_key(&ctx.md5, nkey, key);
+ PBKDF2(&ctx.md5, hmac_md5_update, hmac_md5_digest,
+ MD5_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
+ break;
+
case QCRYPTO_HASH_ALG_SHA1:
- pbkdf2_hmac_sha1(nkey, key,
- iterations,
- nsalt, salt,
- nout, out);
+ hmac_sha1_set_key(&ctx.sha1, nkey, key);
+ PBKDF2(&ctx.sha1, hmac_sha1_update, hmac_sha1_digest,
+ SHA1_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
+ break;
+
+ case QCRYPTO_HASH_ALG_SHA224:
+ hmac_sha224_set_key(&ctx.sha224, nkey, key);
+ PBKDF2(&ctx.sha224, hmac_sha224_update, hmac_sha224_digest,
+ SHA224_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
case QCRYPTO_HASH_ALG_SHA256:
- pbkdf2_hmac_sha256(nkey, key,
- iterations,
- nsalt, salt,
- nout, out);
+ hmac_sha256_set_key(&ctx.sha256, nkey, key);
+ PBKDF2(&ctx.sha256, hmac_sha256_update, hmac_sha256_digest,
+ SHA256_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
+ break;
+
+ case QCRYPTO_HASH_ALG_SHA384:
+ hmac_sha384_set_key(&ctx.sha384, nkey, key);
+ PBKDF2(&ctx.sha384, hmac_sha384_update, hmac_sha384_digest,
+ SHA384_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
+ break;
+
+ case QCRYPTO_HASH_ALG_SHA512:
+ hmac_sha512_set_key(&ctx.sha512, nkey, key);
+ PBKDF2(&ctx.sha512, hmac_sha512_update, hmac_sha512_digest,
+ SHA512_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
+ break;
+
+ case QCRYPTO_HASH_ALG_RIPEMD160:
+ hmac_ripemd160_set_key(&ctx.ripemd160, nkey, key);
+ PBKDF2(&ctx.ripemd160, hmac_ripemd160_update, hmac_ripemd160_digest,
+ RIPEMD160_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
default:
error_setg_errno(errp, ENOSYS,
- "PBKDF does not support hash algorithm %d", hash);
+ "PBKDF does not support hash algorithm %s",
+ QCryptoHashAlgorithm_lookup[hash]);
return -1;
}
return 0;
diff --git a/crypto/pbkdf-stub.c b/crypto/pbkdf-stub.c
index 266a5051b7..a15044da42 100644
--- a/crypto/pbkdf-stub.c
+++ b/crypto/pbkdf-stub.c
@@ -32,7 +32,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash G_GNUC_UNUSED,
size_t nkey G_GNUC_UNUSED,
const uint8_t *salt G_GNUC_UNUSED,
size_t nsalt G_GNUC_UNUSED,
- unsigned int iterations G_GNUC_UNUSED,
+ uint64_t iterations G_GNUC_UNUSED,
uint8_t *out G_GNUC_UNUSED,
size_t nout G_GNUC_UNUSED,
Error **errp)
diff --git a/crypto/pbkdf.c b/crypto/pbkdf.c
index 695cc35df1..f22e71d183 100644
--- a/crypto/pbkdf.c
+++ b/crypto/pbkdf.c
@@ -62,29 +62,33 @@ static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
#endif
}
-int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
- const uint8_t *key, size_t nkey,
- const uint8_t *salt, size_t nsalt,
- Error **errp)
+uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
+ const uint8_t *key, size_t nkey,
+ const uint8_t *salt, size_t nsalt,
+ size_t nout,
+ Error **errp)
{
- uint8_t out[32];
- long long int iterations = (1 << 15);
+ uint64_t ret = -1;
+ uint8_t *out;
+ uint64_t iterations = (1 << 15);
unsigned long long delta_ms, start_ms, end_ms;
+ out = g_new(uint8_t, nout);
+
while (1) {
if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) {
- return -1;
+ goto cleanup;
}
if (qcrypto_pbkdf2(hash,
key, nkey,
salt, nsalt,
iterations,
- out, sizeof(out),
+ out, nout,
errp) < 0) {
- return -1;
+ goto cleanup;
}
if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) {
- return -1;
+ goto cleanup;
}
delta_ms = end_ms - start_ms;
@@ -100,11 +104,10 @@ int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
iterations = iterations * 1000 / delta_ms;
- if (iterations > INT32_MAX) {
- error_setg(errp, "Iterations %lld too large for a 32-bit int",
- iterations);
- return -1;
- }
+ ret = iterations;
- return iterations;
+ cleanup:
+ memset(out, 0, nout);
+ g_free(out);
+ return ret;
}
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
index 2de42c61cb..96a02deb69 100644
--- a/crypto/tlssession.c
+++ b/crypto/tlssession.c
@@ -351,16 +351,22 @@ qcrypto_tls_session_check_credentials(QCryptoTLSSession *session,
{
if (object_dynamic_cast(OBJECT(session->creds),
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
+ trace_qcrypto_tls_session_check_creds(session, "nop");
return 0;
} else if (object_dynamic_cast(OBJECT(session->creds),
TYPE_QCRYPTO_TLS_CREDS_X509)) {
if (session->creds->verifyPeer) {
- return qcrypto_tls_session_check_certificate(session,
- errp);
+ int ret = qcrypto_tls_session_check_certificate(session,
+ errp);
+ trace_qcrypto_tls_session_check_creds(session,
+ ret == 0 ? "pass" : "fail");
+ return ret;
} else {
+ trace_qcrypto_tls_session_check_creds(session, "skip");
return 0;
}
} else {
+ trace_qcrypto_tls_session_check_creds(session, "error");
error_setg(errp, "Unexpected credential type %s",
object_get_typename(OBJECT(session->creds)));
return -1;
diff --git a/crypto/trace-events b/crypto/trace-events
index 8181843723..dc6ddd30d6 100644
--- a/crypto/trace-events
+++ b/crypto/trace-events
@@ -17,3 +17,4 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds
# crypto/tlssession.c
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *aclname, int endpoint) "TLS session new session=%p creds=%p hostname=%s aclname=%s endpoint=%d"
+qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"
diff --git a/fsdev/9p-marshal.c b/fsdev/9p-marshal.c
index 238dbf21b1..a01bba6908 100644
--- a/fsdev/9p-marshal.c
+++ b/fsdev/9p-marshal.c
@@ -25,11 +25,6 @@ void v9fs_string_free(V9fsString *str)
str->size = 0;
}
-void v9fs_string_null(V9fsString *str)
-{
- v9fs_string_free(str);
-}
-
void GCC_FMT_ATTR(2, 3)
v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
{
diff --git a/fsdev/9p-marshal.h b/fsdev/9p-marshal.h
index 140db6d99f..77f7fef326 100644
--- a/fsdev/9p-marshal.h
+++ b/fsdev/9p-marshal.h
@@ -77,7 +77,6 @@ static inline void v9fs_string_init(V9fsString *str)
str->size = 0;
}
extern void v9fs_string_free(V9fsString *str);
-extern void v9fs_string_null(V9fsString *str);
extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 3f271fcbd2..845675e7a1 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -1060,13 +1060,10 @@ static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
const char *name, V9fsPath *target)
{
if (dir_path) {
- v9fs_string_sprintf((V9fsString *)target, "%s/%s",
- dir_path->data, name);
+ v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
} else {
- v9fs_string_sprintf((V9fsString *)target, "%s", name);
+ v9fs_path_sprintf(target, "%s", name);
}
- /* Bump the size for including terminating NULL */
- target->size++;
return 0;
}
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
index f265501eac..f2417b7fd7 100644
--- a/hw/9pfs/9p-proxy.c
+++ b/hw/9pfs/9p-proxy.c
@@ -294,8 +294,7 @@ static int v9fs_receive_status(V9fsProxy *proxy,
* This request read by proxy helper process
* returns 0 on success and -errno on error
*/
-static int v9fs_request(V9fsProxy *proxy, int type,
- void *response, const char *fmt, ...)
+static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...)
{
dev_t rdev;
va_list ap;
@@ -317,7 +316,7 @@ static int v9fs_request(V9fsProxy *proxy, int type,
}
iovec = &proxy->out_iovec;
reply = &proxy->in_iovec;
- va_start(ap, fmt);
+ va_start(ap, response);
switch (type) {
case T_OPEN:
path = va_arg(ap, V9fsString *);
@@ -605,7 +604,7 @@ close_error:
static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
{
int retval;
- retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path);
+ retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path);
if (retval < 0) {
errno = -retval;
return -1;
@@ -617,8 +616,7 @@ static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
char *buf, size_t bufsz)
{
int retval;
- retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd",
- fs_path, bufsz);
+ retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz);
if (retval < 0) {
errno = -retval;
return -1;
@@ -639,7 +637,7 @@ static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
int flags, V9fsFidOpenState *fs)
{
- fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, flags);
+ fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags);
if (fs->fd < 0) {
errno = -fs->fd;
fs->fd = -1;
@@ -653,7 +651,7 @@ static int proxy_opendir(FsContext *ctx,
int serrno, fd;
fs->dir.stream = NULL;
- fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY);
+ fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY);
if (fd < 0) {
errno = -fd;
return -1;
@@ -735,8 +733,8 @@ static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
int retval;
- retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, "sd",
- fs_path, credp->fc_mode);
+ retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path,
+ credp->fc_mode);
if (retval < 0) {
errno = -retval;
}
@@ -752,8 +750,8 @@ static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd",
- &fullname, credp->fc_mode, credp->fc_rdev,
+ retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname,
+ credp->fc_mode, credp->fc_rdev,
credp->fc_uid, credp->fc_gid);
v9fs_string_free(&fullname);
if (retval < 0) {
@@ -772,14 +770,13 @@ static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname,
+ retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname,
credp->fc_mode, credp->fc_uid, credp->fc_gid);
v9fs_string_free(&fullname);
if (retval < 0) {
errno = -retval;
retval = -1;
}
- v9fs_string_free(&fullname);
return retval;
}
@@ -804,9 +801,8 @@ static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd",
- &fullname, flags, credp->fc_mode,
- credp->fc_uid, credp->fc_gid);
+ fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags,
+ credp->fc_mode, credp->fc_uid, credp->fc_gid);
v9fs_string_free(&fullname);
if (fs->fd < 0) {
errno = -fs->fd;
@@ -827,8 +823,8 @@ static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
v9fs_string_sprintf(&target, "%s", oldpath);
- retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd",
- &target, &fullname, credp->fc_uid, credp->fc_gid);
+ retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname,
+ credp->fc_uid, credp->fc_gid);
v9fs_string_free(&fullname);
v9fs_string_free(&target);
if (retval < 0) {
@@ -847,7 +843,7 @@ static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
v9fs_string_init(&newpath);
v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
- retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath);
+ retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath);
v9fs_string_free(&newpath);
if (retval < 0) {
errno = -retval;
@@ -860,7 +856,7 @@ static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
{
int retval;
- retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, "sq", fs_path, size);
+ retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size);
if (retval < 0) {
errno = -retval;
return -1;
@@ -879,8 +875,7 @@ static int proxy_rename(FsContext *ctx, const char *oldpath,
v9fs_string_sprintf(&oldname, "%s", oldpath);
v9fs_string_sprintf(&newname, "%s", newpath);
- retval = v9fs_request(ctx->private, T_RENAME, NULL, "ss",
- &oldname, &newname);
+ retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname);
v9fs_string_free(&oldname);
v9fs_string_free(&newname);
if (retval < 0) {
@@ -892,8 +887,8 @@ static int proxy_rename(FsContext *ctx, const char *oldpath,
static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
int retval;
- retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, "sdd",
- fs_path, credp->fc_uid, credp->fc_gid);
+ retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path,
+ credp->fc_uid, credp->fc_gid);
if (retval < 0) {
errno = -retval;
}
@@ -904,8 +899,7 @@ static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
const struct timespec *buf)
{
int retval;
- retval = v9fs_request(s->private, T_UTIME, NULL, "sqqqq",
- fs_path,
+ retval = v9fs_request(s->private, T_UTIME, NULL, fs_path,
buf[0].tv_sec, buf[0].tv_nsec,
buf[1].tv_sec, buf[1].tv_nsec);
if (retval < 0) {
@@ -920,7 +914,7 @@ static int proxy_remove(FsContext *ctx, const char *path)
V9fsString name;
v9fs_string_init(&name);
v9fs_string_sprintf(&name, "%s", path);
- retval = v9fs_request(ctx->private, T_REMOVE, NULL, "s", &name);
+ retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name);
v9fs_string_free(&name);
if (retval < 0) {
errno = -retval;
@@ -949,7 +943,7 @@ static int proxy_fsync(FsContext *ctx, int fid_type,
static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
{
int retval;
- retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path);
+ retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path);
if (retval < 0) {
errno = -retval;
return -1;
@@ -965,8 +959,8 @@ static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
v9fs_string_init(&xname);
v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size,
- fs_path, &xname);
+ retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path,
+ &xname);
v9fs_string_free(&xname);
if (retval < 0) {
errno = -retval;
@@ -978,8 +972,7 @@ static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
void *value, size_t size)
{
int retval;
- retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size,
- fs_path);
+ retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path);
if (retval < 0) {
errno = -retval;
}
@@ -1000,8 +993,8 @@ static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
xvalue.data = g_malloc(size);
memcpy(xvalue.data, value, size);
- retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd",
- fs_path, &xname, &xvalue, size, flags);
+ retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname,
+ &xvalue, size, flags);
v9fs_string_free(&xname);
v9fs_string_free(&xvalue);
if (retval < 0) {
@@ -1018,8 +1011,7 @@ static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
v9fs_string_init(&xname);
v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss",
- fs_path, &xname);
+ retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname);
v9fs_string_free(&xname);
if (retval < 0) {
errno = -retval;
@@ -1031,13 +1023,10 @@ static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
const char *name, V9fsPath *target)
{
if (dir_path) {
- v9fs_string_sprintf((V9fsString *)target, "%s/%s",
- dir_path->data, name);
+ v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
} else {
- v9fs_string_sprintf((V9fsString *)target, "%s", name);
+ v9fs_path_sprintf(target, "%s", name);
}
- /* Bump the size for including terminating NULL */
- target->size++;
return 0;
}
@@ -1086,7 +1075,7 @@ static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
errno = ENOTTY;
return -1;
}
- err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path);
+ err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path);
if (err < 0) {
errno = -err;
err = -1;
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index dfe293d11d..119ee58496 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -12,6 +12,7 @@
*/
#include "qemu/osdep.h"
+#include <glib/gprintf.h>
#include "hw/virtio/virtio.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -179,6 +180,20 @@ void v9fs_path_free(V9fsPath *path)
path->size = 0;
}
+
+void GCC_FMT_ATTR(2, 3)
+v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...)
+{
+ va_list ap;
+
+ v9fs_path_free(path);
+
+ va_start(ap, fmt);
+ /* Bump the size for including terminating NULL */
+ path->size = g_vasprintf(&path->data, fmt, ap) + 1;
+ va_end(ap);
+}
+
void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
{
v9fs_path_free(lhs);
@@ -810,15 +825,15 @@ static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
v9stat->mtime = stbuf->st_mtime;
v9stat->length = stbuf->st_size;
- v9fs_string_null(&v9stat->uid);
- v9fs_string_null(&v9stat->gid);
- v9fs_string_null(&v9stat->muid);
+ v9fs_string_free(&v9stat->uid);
+ v9fs_string_free(&v9stat->gid);
+ v9fs_string_free(&v9stat->muid);
v9stat->n_uid = stbuf->st_uid;
v9stat->n_gid = stbuf->st_gid;
v9stat->n_muid = 0;
- v9fs_string_null(&v9stat->extension);
+ v9fs_string_free(&v9stat->extension);
if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
err = v9fs_co_readlink(pdu, name, &v9stat->extension);
@@ -917,10 +932,8 @@ static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
V9fsPath str;
v9fs_path_init(&str);
v9fs_path_copy(&str, dst);
- v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
+ v9fs_path_sprintf(dst, "%s%s", src->data, str.data + len);
v9fs_path_free(&str);
- /* +1 to include terminating NULL */
- dst->size++;
}
static inline bool is_ro_export(FsContext *ctx)
@@ -1320,13 +1333,14 @@ static void v9fs_walk(void *opaque)
goto out_nofid;
}
+ v9fs_path_init(&dpath);
+ v9fs_path_init(&path);
+
err = fid_to_qid(pdu, fidp, &qid);
if (err < 0) {
goto out;
}
- v9fs_path_init(&dpath);
- v9fs_path_init(&path);
/*
* Both dpath and path initially poin to fidp.
* Needed to handle request with nwnames == 0
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
index a38603398e..d539d2ebe9 100644
--- a/hw/9pfs/9p.h
+++ b/hw/9pfs/9p.h
@@ -327,6 +327,7 @@ static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu)
extern void v9fs_reclaim_fd(V9fsPDU *pdu);
extern void v9fs_path_init(V9fsPath *path);
extern void v9fs_path_free(V9fsPath *path);
+extern void v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...);
extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
const char *name, V9fsPath *path);
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index a63b4e8c61..e340eab36b 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -193,6 +193,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
s390mc->ri_allowed = true;
+ s390mc->cpu_model_allowed = true;
mc->init = ccw_init;
mc->reset = s390_machine_reset;
mc->hot_add_cpu = s390_hot_add_cpu;
@@ -258,6 +259,19 @@ bool ri_allowed(void)
return 0;
}
+bool cpu_model_allowed(void)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+ if (object_class_dynamic_cast(OBJECT_CLASS(mc),
+ TYPE_S390_CCW_MACHINE)) {
+ S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+
+ return s390mc->cpu_model_allowed;
+ }
+ /* allow CPU model qmp queries with the "none" machine */
+ return true;
+}
+
static inline void s390_machine_initfn(Object *obj)
{
object_property_add_bool(obj, "aes-key-wrap",
@@ -397,6 +411,9 @@ static void ccw_machine_2_7_instance_options(MachineState *machine)
static void ccw_machine_2_7_class_options(MachineClass *mc)
{
+ S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+
+ s390mc->cpu_model_allowed = false;
ccw_machine_2_8_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_7);
}
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 96789569a7..ee136ab940 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -455,6 +455,26 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
}
}
break;
+ case CCW_CMD_READ_STATUS:
+ if (check_len) {
+ if (ccw.count != sizeof(status)) {
+ ret = -EINVAL;
+ break;
+ }
+ } else if (ccw.count < sizeof(status)) {
+ /* Can't execute command. */
+ ret = -EINVAL;
+ break;
+ }
+ if (!ccw.cda) {
+ ret = -EFAULT;
+ } else {
+ address_space_stb(&address_space_memory, ccw.cda, vdev->status,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+ sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status);;
+ ret = 0;
+ }
+ break;
case CCW_CMD_WRITE_STATUS:
if (check_len) {
if (ccw.count != sizeof(status)) {
@@ -1261,6 +1281,16 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
return 0;
}
+static void virtio_ccw_pre_plugged(DeviceState *d, Error **errp)
+{
+ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+ VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
+
+ if (dev->max_rev >= 1) {
+ virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
+ }
+}
+
/* This is called by virtio-bus just after the device is plugged. */
static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
{
@@ -1270,6 +1300,10 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
SubchDev *sch = ccw_dev->sch;
int n = virtio_get_num_queues(vdev);
+ if (!virtio_has_feature(vdev->host_features, VIRTIO_F_VERSION_1)) {
+ dev->max_rev = 0;
+ }
+
if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) {
error_setg(errp, "The number of virtqueues %d "
"exceeds ccw limit %d", n,
@@ -1283,25 +1317,11 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus);
- if (dev->max_rev >= 1) {
- virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
- }
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
d->hotplugged, 1);
}
-static void virtio_ccw_post_plugged(DeviceState *d, Error **errp)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
-
- if (!virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1)) {
- /* A backend didn't support modern virtio. */
- dev->max_rev = 0;
- }
-}
-
static void virtio_ccw_device_unplugged(DeviceState *d)
{
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
@@ -1593,8 +1613,8 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
k->load_queue = virtio_ccw_load_queue;
k->save_config = virtio_ccw_save_config;
k->load_config = virtio_ccw_load_config;
+ k->pre_plugged = virtio_ccw_pre_plugged;
k->device_plugged = virtio_ccw_device_plugged;
- k->post_plugged = virtio_ccw_post_plugged;
k->device_unplugged = virtio_ccw_device_unplugged;
k->ioeventfd_started = virtio_ccw_ioeventfd_started;
k->ioeventfd_set_started = virtio_ccw_ioeventfd_set_started;
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index b58ab21d4c..565094e4fb 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -45,6 +45,7 @@
#define CCW_CMD_SET_IND 0x43
#define CCW_CMD_SET_CONF_IND 0x53
#define CCW_CMD_READ_VQ_CONF 0x32
+#define CCW_CMD_READ_STATUS 0x72
#define CCW_CMD_SET_IND_ADAPTER 0x73
#define CCW_CMD_SET_VIRTIO_REV 0x83
@@ -98,7 +99,7 @@ struct VirtioCcwDevice {
};
/* The maximum virtio revision we support. */
-#define VIRTIO_CCW_MAX_REV 1
+#define VIRTIO_CCW_MAX_REV 2
static inline int virtio_ccw_rev_max(VirtioCcwDevice *dev)
{
return dev->max_rev;
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index 14927935ae..11f65bd225 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -49,16 +49,17 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
DPRINTF("%s: plug device.\n", qbus->name);
- if (klass->device_plugged != NULL) {
- klass->device_plugged(qbus->parent, errp);
+ if (klass->pre_plugged != NULL) {
+ klass->pre_plugged(qbus->parent, errp);
}
/* Get the features of the plugged device. */
assert(vdc->get_features != NULL);
vdev->host_features = vdc->get_features(vdev, vdev->host_features,
errp);
- if (klass->post_plugged != NULL) {
- klass->post_plugged(qbus->parent, errp);
+
+ if (klass->device_plugged != NULL) {
+ klass->device_plugged(qbus->parent, errp);
}
}
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index dde71a5965..2d60a005b6 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1576,18 +1576,48 @@ static void virtio_pci_modern_io_region_unmap(VirtIOPCIProxy *proxy,
&region->mr);
}
+static void virtio_pci_pre_plugged(DeviceState *d, Error **errp)
+{
+ VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+
+ if (virtio_pci_modern(proxy)) {
+ virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
+ }
+
+ virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE);
+}
+
/* This is called by virtio-bus just after the device is plugged. */
static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
VirtioBusState *bus = &proxy->bus;
bool legacy = virtio_pci_legacy(proxy);
- bool modern = virtio_pci_modern(proxy);
+ bool modern;
bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
uint8_t *config;
uint32_t size;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+ /*
+ * Virtio capabilities present without
+ * VIRTIO_F_VERSION_1 confuses guests
+ */
+ if (!virtio_has_feature(vdev->host_features, VIRTIO_F_VERSION_1)) {
+ virtio_pci_disable_modern(proxy);
+
+ if (!legacy) {
+ error_setg(errp, "Device doesn't support modern mode, and legacy"
+ " mode is disabled");
+ error_append_hint(errp, "Set disable-legacy to off\n");
+
+ return;
+ }
+ }
+
+ modern = virtio_pci_modern(proxy);
+
config = proxy->pci_dev.config;
if (proxy->class_code) {
pci_config_set_class(config, proxy->class_code);
@@ -1629,7 +1659,6 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
struct virtio_pci_cfg_cap *cfg_mask;
- virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
virtio_pci_modern_regions_init(proxy);
virtio_pci_modern_mem_region_map(proxy, &proxy->common, &cap);
@@ -1694,8 +1723,6 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
if (!kvm_has_many_ioeventfds()) {
proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
}
-
- virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE);
}
static void virtio_pci_device_unplugged(DeviceState *d)
@@ -2508,6 +2535,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
k->vmstate_change = virtio_pci_vmstate_change;
+ k->pre_plugged = virtio_pci_pre_plugged;
k->device_plugged = virtio_pci_device_plugged;
k->device_unplugged = virtio_pci_device_unplugged;
k->query_nvectors = virtio_pci_query_nvectors;
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index 0698157b32..541cbdbc2b 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -181,6 +181,11 @@ static inline void virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy)
proxy->disable_legacy = ON_OFF_AUTO_ON;
}
+static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
+{
+ proxy->disable_modern = true;
+}
+
/*
* virtio-scsi-pci: This extends VirtioPCIProxy.
*/
diff --git a/include/crypto/pbkdf.h b/include/crypto/pbkdf.h
index e9e4ceca83..ef209b3e03 100644
--- a/include/crypto/pbkdf.h
+++ b/include/crypto/pbkdf.h
@@ -122,7 +122,7 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash);
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
- unsigned int iterations,
+ uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp);
@@ -133,6 +133,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
* @nkey: the length of @key in bytes
* @salt: a random salt
* @nsalt: length of @salt in bytes
+ * @nout: size of desired derived key
* @errp: pointer to a NULL-initialized error object
*
* Time the PBKDF2 algorithm to determine how many
@@ -140,13 +141,16 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
* key from a user password provided in @key in 1
* second of compute time. The result of this can
* be used as a the @iterations parameter of a later
- * call to qcrypto_pbkdf2().
+ * call to qcrypto_pbkdf2(). The value of @nout should
+ * match that value that will later be provided with
+ * a call to qcrypto_pbkdf2().
*
* Returns: number of iterations in 1 second, -1 on error
*/
-int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
- const uint8_t *key, size_t nkey,
- const uint8_t *salt, size_t nsalt,
- Error **errp);
+uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
+ const uint8_t *key, size_t nkey,
+ const uint8_t *salt, size_t nsalt,
+ size_t nout,
+ Error **errp);
#endif /* QCRYPTO_PBKDF_H */
diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
index a0c1fc8083..6ecae00386 100644
--- a/include/hw/s390x/s390-virtio-ccw.h
+++ b/include/hw/s390x/s390-virtio-ccw.h
@@ -36,9 +36,12 @@ typedef struct S390CcwMachineClass {
/*< public >*/
bool ri_allowed;
+ bool cpu_model_allowed;
} S390CcwMachineClass;
/* runtime-instrumentation allowed by the machine */
bool ri_allowed(void);
+/* cpu model allowed by the machine */
+bool cpu_model_allowed(void);
#endif
diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h
index c98aa526d1..2e4b67ea50 100644
--- a/include/hw/virtio/virtio-bus.h
+++ b/include/hw/virtio/virtio-bus.h
@@ -54,16 +54,16 @@ typedef struct VirtioBusClass {
int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign);
void (*vmstate_change)(DeviceState *d, bool running);
/*
+ * Expose the features the transport layer supports before
+ * the negotiation takes place.
+ */
+ void (*pre_plugged)(DeviceState *d, Error **errp);
+ /*
* transport independent init function.
* This is called by virtio-bus just after the device is plugged.
*/
void (*device_plugged)(DeviceState *d, Error **errp);
/*
- * Re-evaluate setup after feature bits have been validated
- * by the device backend.
- */
- void (*post_plugged)(DeviceState *d, Error **errp);
- /*
* transport independent exit function.
* This is called by virtio-bus just before the device is unplugged.
*/
diff --git a/qapi-schema.json b/qapi-schema.json
index 55f825dd06..e50706111c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3224,7 +3224,7 @@
# @CpuModelCompareResult:
#
# An enumeration of CPU model comparation results. The result is usually
-# calcualted using e.g. CPU features or CPU generations.
+# calculated using e.g. CPU features or CPU generations.
#
# @incompatible: If model A is incompatible to model B, model A is not
# guaranteed to run where model B runs and the other way around.
@@ -3277,14 +3277,14 @@
# CPU model has to be created by baselining.
#
# Usually, a CPU model is compared against the maximum possible CPU model
-# of a ceratin configuration (e.g. the "host" model for KVM). If that CPU
+# of a certain configuration (e.g. the "host" model for KVM). If that CPU
# model is identical or a subset, it will run in that configuration.
#
# The result returned by this command may be affected by:
#
# * QEMU version: CPU models may look different depending on the QEMU version.
# (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine-type: CPU model may look different depending on the machine-type.
+# * machine-type: CPU model may look different depending on the machine-type.
# (Except for CPU models reported as "static" in query-cpu-definitions.)
# * machine options (including accelerator): in some architectures, CPU models
# may look different depending on machine and accelerator options. (Except for
@@ -3335,7 +3335,7 @@
#
# * QEMU version: CPU models may look different depending on the QEMU version.
# (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine-type: CPU model may look different depending on the machine-type.
+# * machine-type: CPU model may look different depending on the machine-type.
# (Except for CPU models reported as "static" in query-cpu-definitions.)
# * machine options (including accelerator): in some architectures, CPU models
# may look different depending on machine and accelerator options. (Except for
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 34d2583154..6933b13bd0 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -185,6 +185,9 @@
# Currently defaults to 'sha256'
# @hash-alg: #optional the master key hash algorithm
# Currently defaults to 'sha256'
+# @iter-time: #optional number of milliseconds to spend in
+# PBKDF passphrase processing. Currently defaults
+# to 2000. (since 2.8)
# Since: 2.6
##
{ 'struct': 'QCryptoBlockCreateOptionsLUKS',
@@ -193,7 +196,8 @@
'*cipher-mode': 'QCryptoCipherMode',
'*ivgen-alg': 'QCryptoIVGenAlgorithm',
'*ivgen-hash-alg': 'QCryptoHashAlgorithm',
- '*hash-alg': 'QCryptoHashAlgorithm'}}
+ '*hash-alg': 'QCryptoHashAlgorithm',
+ '*iter-time': 'int'}}
##
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index dfaf1ca8d1..4b847a3be4 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -2490,7 +2490,7 @@ static int configure_cpu_feat(const S390FeatBitmap features)
bool kvm_s390_cpu_models_supported(void)
{
- if (!ri_allowed()) {
+ if (!cpu_model_allowed()) {
/* compatibility machines interfere with the cpu model */
return false;
}
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 2f11064699..6052a3828f 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -627,7 +627,7 @@ tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y)
tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y)
tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o $(libqos-pc-obj-y)
tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
-tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o
+tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o $(libqos-virtio-obj-y)
tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o
tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o
tests/tpci200-test$(EXESUF): tests/tpci200-test.o
diff --git a/tests/test-crypto-pbkdf.c b/tests/test-crypto-pbkdf.c
index 8ceceb1827..d937aff6b2 100644
--- a/tests/test-crypto-pbkdf.c
+++ b/tests/test-crypto-pbkdf.c
@@ -261,7 +261,6 @@ static QCryptoPbkdfTestData test_data[] = {
"\xcc\x4a\x5e\x6d\xca\x04\xec\x58",
.nout = 32
},
-#if 0
{
.path = "/crypto/pbkdf/nonrfc/sha512/iter1200",
.hash = QCRYPTO_HASH_ALG_SHA512,
@@ -280,6 +279,58 @@ static QCryptoPbkdfTestData test_data[] = {
.nout = 32
},
{
+ .path = "/crypto/pbkdf/nonrfc/sha224/iter1200",
+ .hash = QCRYPTO_HASH_ALG_SHA224,
+ .iterations = 1200,
+ .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ .nkey = 129,
+ .salt = "pass phrase exceeds block size",
+ .nsalt = 30,
+ .out = "\x13\x3b\x88\x0c\x0e\x52\xa2\x41"
+ "\x49\x33\x35\xa6\xc3\x83\xae\x23"
+ "\xf6\x77\x43\x9e\x5b\x30\x92\x3e"
+ "\x4a\x3a\xaa\x24\x69\x3c\xed\x20",
+ .nout = 32
+ },
+ {
+ .path = "/crypto/pbkdf/nonrfc/sha384/iter1200",
+ .hash = QCRYPTO_HASH_ALG_SHA384,
+ .iterations = 1200,
+ .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ .nkey = 129,
+ .salt = "pass phrase exceeds block size",
+ .nsalt = 30,
+ .out = "\xfe\xe3\xe1\x84\xc9\x25\x3e\x10"
+ "\x47\xc8\x7d\x53\xc6\xa5\xe3\x77"
+ "\x29\x41\x76\xbd\x4b\xe3\x9b\xac"
+ "\x05\x6c\x11\xdd\x17\xc5\x93\x80",
+ .nout = 32
+ },
+ {
+ .path = "/crypto/pbkdf/nonrfc/ripemd160/iter1200",
+ .hash = QCRYPTO_HASH_ALG_RIPEMD160,
+ .iterations = 1200,
+ .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ .nkey = 129,
+ .salt = "pass phrase exceeds block size",
+ .nsalt = 30,
+ .out = "\xd6\xcb\xd8\xa7\xdb\x0c\xa2\x2a"
+ "\x23\x5e\x47\xaf\xdb\xda\xa8\xef"
+ "\xe4\x01\x0d\x6f\xb5\x33\xc8\xbd"
+ "\xce\xbf\x91\x14\x8b\x5c\x48\x41",
+ .nout = 32
+ },
+#if 0
+ {
.path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200",
.hash = QCRYPTO_HASH_ALG_WHIRLPOOL,
.iterations = 1200,
@@ -358,6 +409,7 @@ static void test_pbkdf_timing(void)
iters = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256,
key, sizeof(key),
salt, sizeof(salt),
+ 32,
&error_abort);
g_assert(iters >= (1 << 15));
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
index 1e39335a79..b8fb6cd869 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -10,34 +10,119 @@
#include "qemu/osdep.h"
#include "libqtest.h"
#include "qemu-common.h"
+#include "libqos/pci-pc.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+#include "libqos/malloc.h"
+#include "libqos/malloc-pc.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_pci.h"
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void pci_nop(void)
-{
-}
+static const char mount_tag[] = "qtest";
+static char *test_share;
-static char test_share[] = "/tmp/qtest.XXXXXX";
-
-int main(int argc, char **argv)
+static void qvirtio_9p_start(void)
{
char *args;
- int ret;
- g_test_init(&argc, &argv, NULL);
- qtest_add_func("/virtio/9p/pci/nop", pci_nop);
-
- g_assert(mkdtemp(test_share));
+ test_share = g_strdup("/tmp/qtest.XXXXXX");
+ g_assert_nonnull(mkdtemp(test_share));
args = g_strdup_printf("-fsdev local,id=fsdev0,security_model=none,path=%s "
- "-device virtio-9p-pci,fsdev=fsdev0,mount_tag=qtest",
- test_share);
+ "-device virtio-9p-pci,fsdev=fsdev0,mount_tag=%s",
+ test_share, mount_tag);
+
qtest_start(args);
g_free(args);
+}
- ret = g_test_run();
-
+static void qvirtio_9p_stop(void)
+{
qtest_end();
rmdir(test_share);
+ g_free(test_share);
+}
+
+static void pci_nop(void)
+{
+ qvirtio_9p_start();
+ qvirtio_9p_stop();
+}
+
+typedef struct {
+ QVirtioDevice *dev;
+ QGuestAllocator *alloc;
+ QPCIBus *bus;
+ QVirtQueue *vq;
+} QVirtIO9P;
+
+static QVirtIO9P *qvirtio_9p_pci_init(void)
+{
+ QVirtIO9P *v9p;
+ QVirtioPCIDevice *dev;
+
+ v9p = g_new0(QVirtIO9P, 1);
+ v9p->alloc = pc_alloc_init();
+ v9p->bus = qpci_init_pc();
+
+ dev = qvirtio_pci_device_find(v9p->bus, VIRTIO_ID_9P);
+ g_assert_nonnull(dev);
+ g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_9P);
+ v9p->dev = (QVirtioDevice *) dev;
+
+ qvirtio_pci_device_enable(dev);
+ qvirtio_reset(&qvirtio_pci, v9p->dev);
+ qvirtio_set_acknowledge(&qvirtio_pci, v9p->dev);
+ qvirtio_set_driver(&qvirtio_pci, v9p->dev);
+
+ v9p->vq = qvirtqueue_setup(&qvirtio_pci, v9p->dev, v9p->alloc, 0);
+ return v9p;
+}
+
+static void qvirtio_9p_pci_free(QVirtIO9P *v9p)
+{
+ qvirtqueue_cleanup(&qvirtio_pci, v9p->vq, v9p->alloc);
+ pc_alloc_uninit(v9p->alloc);
+ qvirtio_pci_device_disable(container_of(v9p->dev, QVirtioPCIDevice, vdev));
+ g_free(v9p->dev);
+ qpci_free_pc(v9p->bus);
+ g_free(v9p);
+}
+
+static void pci_basic_config(void)
+{
+ QVirtIO9P *v9p;
+ void *addr;
+ size_t tag_len;
+ char *tag;
+ int i;
+
+ qvirtio_9p_start();
+ v9p = qvirtio_9p_pci_init();
+
+ addr = ((QVirtioPCIDevice *) v9p->dev)->addr + VIRTIO_PCI_CONFIG_OFF(false);
+ tag_len = qvirtio_config_readw(&qvirtio_pci, v9p->dev,
+ (uint64_t)(uintptr_t)addr);
+ g_assert_cmpint(tag_len, ==, strlen(mount_tag));
+ addr += sizeof(uint16_t);
+
+ tag = g_malloc(tag_len);
+ for (i = 0; i < tag_len; i++) {
+ tag[i] = qvirtio_config_readb(&qvirtio_pci, v9p->dev,
+ (uint64_t)(uintptr_t)addr + i);
+ }
+ g_assert_cmpmem(tag, tag_len, mount_tag, tag_len);
+ g_free(tag);
+
+ qvirtio_9p_pci_free(v9p);
+ qvirtio_9p_stop();
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/virtio/9p/pci/nop", pci_nop);
+ qtest_add_func("/virtio/9p/pci/basic/configuration", pci_basic_config);
- return ret;
+ return g_test_run();
}