aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.include2
-rw-r--r--tests/qemu-iotests/071.out8
-rw-r--r--tests/tcg/xtensa/Makefile2
-rw-r--r--tests/test-aio.c4
-rw-r--r--tests/test-crypto-cipher.c119
-rw-r--r--tests/test-crypto-hmac.c266
-rw-r--r--tests/virtio-9p-test.c478
7 files changed, 821 insertions, 58 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 6554ef877b..f776404d86 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -91,6 +91,7 @@ gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c
check-unit-y += tests/test-write-threshold$(EXESUF)
gcov-files-test-write-threshold-y = block/write-threshold.c
check-unit-y += tests/test-crypto-hash$(EXESUF)
+check-unit-y += tests/test-crypto-hmac$(EXESUF)
check-unit-y += tests/test-crypto-cipher$(EXESUF)
check-unit-y += tests/test-crypto-secret$(EXESUF)
check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF)
@@ -571,6 +572,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y)
tests/test-mul64$(EXESUF): tests/test-mul64.o $(test-util-obj-y)
tests/test-bitops$(EXESUF): tests/test-bitops.o $(test-util-obj-y)
tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o $(test-crypto-obj-y)
+tests/test-crypto-hmac$(EXESUF): tests/test-crypto-hmac.o $(test-crypto-obj-y)
tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o $(test-crypto-obj-y)
tests/test-crypto-secret$(EXESUF): tests/test-crypto-secret.o $(test-crypto-obj-y)
tests/test-crypto-xts$(EXESUF): tests/test-crypto-xts.o $(test-crypto-obj-y)
diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out
index 8ff423f56b..dd879f1212 100644
--- a/tests/qemu-iotests/071.out
+++ b/tests/qemu-iotests/071.out
@@ -12,7 +12,7 @@ read 512/512 bytes at offset 229376
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0
+blkverify: read offset=0 bytes=512 contents mismatch at offset 0
=== Testing blkverify through file blockref ===
@@ -26,7 +26,7 @@ read 512/512 bytes at offset 229376
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0
+blkverify: read offset=0 bytes=512 contents mismatch at offset 0
=== Testing blkdebug through filename ===
@@ -56,7 +56,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0
+blkverify: read offset=0 bytes=512 contents mismatch at offset 0
=== Testing blkverify on existing raw block device ===
@@ -66,7 +66,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0
+blkverify: read offset=0 bytes=512 contents mismatch at offset 0
=== Testing blkdebug's set-state through QMP ===
diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile
index 522a63e36b..7f9f2d96c3 100644
--- a/tests/tcg/xtensa/Makefile
+++ b/tests/tcg/xtensa/Makefile
@@ -19,7 +19,7 @@ AS = $(CROSS)gcc -x assembler-with-cpp
LD = $(CROSS)ld
XTENSA_SRC_PATH = $(SRC_PATH)/tests/tcg/xtensa
-INCLUDE_DIRS = $(XTENSA_SRC_PATH) $(SRC_PATH)/target-xtensa/core-$(CORE)
+INCLUDE_DIRS = $(XTENSA_SRC_PATH) $(SRC_PATH)/target/xtensa/core-$(CORE)
XTENSA_INC = $(addprefix -I,$(INCLUDE_DIRS))
LDFLAGS = -Tlinker.ld
diff --git a/tests/test-aio.c b/tests/test-aio.c
index 5be99f8287..2754f154ce 100644
--- a/tests/test-aio.c
+++ b/tests/test-aio.c
@@ -128,7 +128,7 @@ static void *test_acquire_thread(void *opaque)
static void set_event_notifier(AioContext *ctx, EventNotifier *notifier,
EventNotifierHandler *handler)
{
- aio_set_event_notifier(ctx, notifier, false, handler);
+ aio_set_event_notifier(ctx, notifier, false, handler, NULL);
}
static void dummy_notifier_read(EventNotifier *n)
@@ -388,7 +388,7 @@ static void test_aio_external_client(void)
for (i = 1; i < 3; i++) {
EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true };
event_notifier_init(&data.e, false);
- aio_set_event_notifier(ctx, &data.e, true, event_ready_cb);
+ aio_set_event_notifier(ctx, &data.e, true, event_ready_cb, NULL);
event_notifier_set(&data.e);
for (j = 0; j < i; j++) {
aio_disable_external(ctx);
diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c
index 5d9e535e2e..07fa2fa616 100644
--- a/tests/test-crypto-cipher.c
+++ b/tests/test-crypto-cipher.c
@@ -165,6 +165,125 @@ static QCryptoCipherTestData test_data[] = {
"ffd29f1bb5596ad94ea2d8e6196b7f09"
"30d8ed0bf2773af36dd82a6280c20926",
},
+#if defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT)
+ {
+ /* Borrowed from linux-kernel crypto/testmgr.h */
+ .path = "/crypto/cipher/3des-cbc",
+ .alg = QCRYPTO_CIPHER_ALG_3DES,
+ .mode = QCRYPTO_CIPHER_MODE_CBC,
+ .key =
+ "e9c0ff2e760b6424444d995a12d640c0"
+ "eac284e81495dbe8",
+ .iv =
+ "7d3388930f93b242",
+ .plaintext =
+ "6f54206f614d796e5320636565727374"
+ "54206f6f4d206e612079655372637465"
+ "20736f54206f614d796e532063656572"
+ "737454206f6f4d206e61207965537263"
+ "746520736f54206f614d796e53206365"
+ "6572737454206f6f4d206e6120796553"
+ "7263746520736f54206f614d796e5320"
+ "63656572737454206f6f4d206e610a79",
+ .ciphertext =
+ "0e2db6973c5633f4671721c76e8ad549"
+ "74b34905c51cd0ed12565c5396b6007d"
+ "9048fcf58d2939cc8ad5351836234ed7"
+ "76d1da0c9467bb048bf2036ca8cfb6ea"
+ "226447aa8f7513bf9fc2c3f0c956c57a"
+ "71632e897b1e12cae25fafd8a4f8c97a"
+ "d6f92131624445a6d6bc5ad32d5443cc"
+ "9ddea570e942458a6bfab19113b0d919",
+ },
+ {
+ /* Borrowed from linux-kernel crypto/testmgr.h */
+ .path = "/crypto/cipher/3des-ecb",
+ .alg = QCRYPTO_CIPHER_ALG_3DES,
+ .mode = QCRYPTO_CIPHER_MODE_ECB,
+ .key =
+ "0123456789abcdef5555555555555555"
+ "fedcba9876543210",
+ .plaintext =
+ "736f6d6564617461",
+ .ciphertext =
+ "18d748e563620572",
+ },
+ {
+ /* Borrowed from linux-kernel crypto/testmgr.h */
+ .path = "/crypto/cipher/3des-ctr",
+ .alg = QCRYPTO_CIPHER_ALG_3DES,
+ .mode = QCRYPTO_CIPHER_MODE_CTR,
+ .key =
+ "9cd6f39cb95a67005a67002dceeb2dce"
+ "ebb45172b451721f",
+ .iv =
+ "ffffffffffffffff",
+ .plaintext =
+ "05ec77fb42d559208b128669f05bcf56"
+ "39ad349f66ea7dc448d3ba0db118e34a"
+ "fe41285c278e11856cf75ec2553ca00b"
+ "9265e970db4fd6b900b41fe649fd442f"
+ "533a8d149863ca5dc1a833a70e9178ec"
+ "77de42d5bc078b12e54cf05b22563980"
+ "6b9f66c950c4af36ba0d947fe34add41"
+ "28b31a8e11f843f75e21553c876e9265"
+ "cc57dba235b900eb72e649d0442fb619"
+ "8d14ff46ca5d24a8339a6d9178c377de"
+ "a108bc07ee71e54cd75b22b51c806bf2"
+ "45c9503baf369960947fc64adda40fb3"
+ "1aed74f8432a5e218813876ef158cc57"
+ "3ea2359c67eb72c549d0bb02b619e04b"
+ "ff46295d248f169a6df45fc3aa3da108"
+ "937aee71d84cd7be01b51ce74ef2452c"
+ "503b82159960cb52c6a930a40f9679ed"
+ "74df432abd048813fa4df15823573e81"
+ "689c67ce51c5ac37bb02957ce04bd246"
+ "29b01b8f16f940f45f26aa3d846f937a"
+ "cd54d8a30abe01e873e74ed1452cb71e"
+ "8215fc47cb5225a9309b629679c074df"
+ "a609bd04ef76fa4dd458238a1d8168f3"
+ "5ace5138ac379e61957cc74bd2a50cb0"
+ "1be275f9402b5f268910846ff659cd54"
+ "3fa30a9d64e873da4ed1b803b71ee148"
+ "fc472e52258c179b62f55cc0ab32a609"
+ "907bef76d94dd4bf068a1de44ff35a2d"
+ "5138836a9e61c853c7ae31a50c977ee2"
+ "75dc402bb2058910fb42f65920543f86"
+ "699d64cf56daad34b803ea7de148d347",
+ .ciphertext =
+ "07c20820721f49ef19cd6f3253052215"
+ "a2852bdb85d2d8b9dd0d1b45cb6911d4"
+ "eabeb2455d0caebea0c127ac659f537e"
+ "afc21bb5b86d360c25c0f86d0b2901da"
+ "1378dc89121243faf612ef8d87627883"
+ "e2be41204c6d351bd10c30cfe2de2b03"
+ "bf4573d4e55995d1b39b276297bdde7f"
+ "a4d23980aa5023f074883da86a18793b"
+ "c4966c8d2240926ed6ad2a1fde63c0e7"
+ "07f72df7b5f3f0cc017c2a9bc210caaa"
+ "fd2b3fc5f3f6fc9b45db53e45bf3c97b"
+ "8e52ffc802b8ac9da10039da3d2d0e01"
+ "097d8d5ebe53b9b08ee7e2966ab278ea"
+ "de238ba5fa5ce3dabf8e316a55d16ab2"
+ "b5466fa5f0eeba1f9f98b0664fd03fa9"
+ "df5f58c4f4ff755c403a097e6e1c97d4"
+ "cce7e771cf0b150871fa0797cde6ca1d"
+ "14280ccf99137af1ebfafa9207de1da1"
+ "d33669fe514d9f2e83374f1f4830ed04"
+ "4da4ef3aca76f41c418f6337782f86a6"
+ "ef417ed2af88ab675271c38ef8269372"
+ "aad60ee70b46b13ab408a9a8a0cf200c"
+ "52bc8b0556b2bc319b74b92929969a50"
+ "dc45dc1aeb0c64d4d3057e5955c3f490"
+ "c2abf89b8adacea1c3f4ad77dd44c8ac"
+ "a3f1c9d2195cb0caa234c1f76cfdac65"
+ "32dc48c4f2006b77f17d76acc031632a"
+ "a53a62c891b10365cb43d106dfc367bc"
+ "dce0cd35ce4965a0527ba70d07a91bb0"
+ "407772c2ea0e3a7846b991b6e73d5142"
+ "fd51b0c62c6313785ceefccfc4700034",
+ },
+#endif
{
/* RFC 2144, Appendix B.1 */
.path = "/crypto/cipher/cast5-128",
diff --git a/tests/test-crypto-hmac.c b/tests/test-crypto-hmac.c
new file mode 100644
index 0000000000..ee55382a3c
--- /dev/null
+++ b/tests/test-crypto-hmac.c
@@ -0,0 +1,266 @@
+/*
+ * QEMU Crypto hmac algorithms tests
+ *
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ * Longpeng(Mike) <longpeng2@huawei.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/init.h"
+#include "crypto/hmac.h"
+
+#define INPUT_TEXT1 "ABCDEFGHIJKLMNOPQRSTUVWXY"
+#define INPUT_TEXT2 "Zabcdefghijklmnopqrstuvwx"
+#define INPUT_TEXT3 "yz0123456789"
+#define INPUT_TEXT INPUT_TEXT1 \
+ INPUT_TEXT2 \
+ INPUT_TEXT3
+
+#define KEY "monkey monkey monkey monkey"
+
+typedef struct QCryptoHmacTestData QCryptoHmacTestData;
+struct QCryptoHmacTestData {
+ QCryptoHashAlgorithm alg;
+ const char *hex_digest;
+};
+
+static QCryptoHmacTestData test_data[] = {
+ {
+ .alg = QCRYPTO_HASH_ALG_MD5,
+ .hex_digest =
+ "ede9cb83679ba82d88fbeae865b3f8fc",
+ },
+ {
+ .alg = QCRYPTO_HASH_ALG_SHA1,
+ .hex_digest =
+ "c7b5a631e3aac975c4ededfcd346e469"
+ "dbc5f2d1",
+ },
+ {
+ .alg = QCRYPTO_HASH_ALG_SHA224,
+ .hex_digest =
+ "5f768179dbb29ca722875d0f461a2e2f"
+ "597d0210340a84df1a8e9c63",
+ },
+ {
+ .alg = QCRYPTO_HASH_ALG_SHA256,
+ .hex_digest =
+ "3798f363c57afa6edaffe39016ca7bad"
+ "efd1e670afb0e3987194307dec3197db",
+ },
+ {
+ .alg = QCRYPTO_HASH_ALG_SHA384,
+ .hex_digest =
+ "d218680a6032d33dccd9882d6a6a7164"
+ "64f26623be257a9b2919b185294f4a49"
+ "9e54b190bfd6bc5cedd2cd05c7e65e82",
+ },
+ {
+ .alg = QCRYPTO_HASH_ALG_SHA512,
+ .hex_digest =
+ "835a4f5b3750b4c1fccfa88da2f746a4"
+ "900160c9f18964309bb736c13b59491b"
+ "8e32d37b724cc5aebb0f554c6338a3b5"
+ "94c4ba26862b2dadb59b7ede1d08d53e",
+ },
+ {
+ .alg = QCRYPTO_HASH_ALG_RIPEMD160,
+ .hex_digest =
+ "94964ed4c1155b62b668c241d67279e5"
+ "8a711676",
+ },
+};
+
+static const char hex[] = "0123456789abcdef";
+
+static void test_hmac_alloc(void)
+{
+ size_t i;
+
+ for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
+ QCryptoHmacTestData *data = &test_data[i];
+ QCryptoHmac *hmac = NULL;
+ uint8_t *result = NULL;
+ size_t resultlen = 0;
+ Error *err = NULL;
+ const char *exp_output = NULL;
+ int ret;
+ size_t j;
+
+ if (!qcrypto_hmac_supports(data->alg)) {
+ return;
+ }
+
+ exp_output = data->hex_digest;
+
+ hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
+ strlen(KEY), &err);
+ g_assert(err == NULL);
+ g_assert(hmac != NULL);
+
+ ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT,
+ strlen(INPUT_TEXT), &result,
+ &resultlen, &err);
+ g_assert(err == NULL);
+ g_assert(ret == 0);
+
+ for (j = 0; j < resultlen; j++) {
+ g_assert(exp_output[j * 2] == hex[(result[j] >> 4) & 0xf]);
+ g_assert(exp_output[j * 2 + 1] == hex[result[j] & 0xf]);
+ }
+
+ qcrypto_hmac_free(hmac);
+
+ g_free(result);
+ }
+}
+
+static void test_hmac_prealloc(void)
+{
+ size_t i;
+
+ for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
+ QCryptoHmacTestData *data = &test_data[i];
+ QCryptoHmac *hmac = NULL;
+ uint8_t *result = NULL;
+ size_t resultlen = 0;
+ Error *err = NULL;
+ const char *exp_output = NULL;
+ int ret;
+ size_t j;
+
+ if (!qcrypto_hmac_supports(data->alg)) {
+ return;
+ }
+
+ exp_output = data->hex_digest;
+
+ resultlen = strlen(exp_output) / 2;
+ result = g_new0(uint8_t, resultlen);
+
+ hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
+ strlen(KEY), &err);
+ g_assert(err == NULL);
+ g_assert(hmac != NULL);
+
+ ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT,
+ strlen(INPUT_TEXT), &result,
+ &resultlen, &err);
+ g_assert(err == NULL);
+ g_assert(ret == 0);
+
+ exp_output = data->hex_digest;
+ for (j = 0; j < resultlen; j++) {
+ g_assert(exp_output[j * 2] == hex[(result[j] >> 4) & 0xf]);
+ g_assert(exp_output[j * 2 + 1] == hex[result[j] & 0xf]);
+ }
+
+ qcrypto_hmac_free(hmac);
+
+ g_free(result);
+ }
+}
+
+static void test_hmac_iov(void)
+{
+ size_t i;
+
+ for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
+ QCryptoHmacTestData *data = &test_data[i];
+ QCryptoHmac *hmac = NULL;
+ uint8_t *result = NULL;
+ size_t resultlen = 0;
+ Error *err = NULL;
+ const char *exp_output = NULL;
+ int ret;
+ size_t j;
+ struct iovec iov[3] = {
+ { .iov_base = (char *)INPUT_TEXT1, .iov_len = strlen(INPUT_TEXT1) },
+ { .iov_base = (char *)INPUT_TEXT2, .iov_len = strlen(INPUT_TEXT2) },
+ { .iov_base = (char *)INPUT_TEXT3, .iov_len = strlen(INPUT_TEXT3) },
+ };
+
+ if (!qcrypto_hmac_supports(data->alg)) {
+ return;
+ }
+
+ exp_output = data->hex_digest;
+
+ hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
+ strlen(KEY), &err);
+ g_assert(err == NULL);
+ g_assert(hmac != NULL);
+
+ ret = qcrypto_hmac_bytesv(hmac, iov, 3, &result,
+ &resultlen, &err);
+ g_assert(err == NULL);
+ g_assert(ret == 0);
+
+ for (j = 0; j < resultlen; j++) {
+ g_assert(exp_output[j * 2] == hex[(result[j] >> 4) & 0xf]);
+ g_assert(exp_output[j * 2 + 1] == hex[result[j] & 0xf]);
+ }
+
+ qcrypto_hmac_free(hmac);
+
+ g_free(result);
+ }
+}
+
+static void test_hmac_digest(void)
+{
+ size_t i;
+
+ for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
+ QCryptoHmacTestData *data = &test_data[i];
+ QCryptoHmac *hmac = NULL;
+ uint8_t *result = NULL;
+ Error *err = NULL;
+ const char *exp_output = NULL;
+ int ret;
+
+ if (!qcrypto_hmac_supports(data->alg)) {
+ return;
+ }
+
+ exp_output = data->hex_digest;
+
+ hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
+ strlen(KEY), &err);
+ g_assert(err == NULL);
+ g_assert(hmac != NULL);
+
+ ret = qcrypto_hmac_digest(hmac, (const char *)INPUT_TEXT,
+ strlen(INPUT_TEXT), (char **)&result,
+ &err);
+ g_assert(err == NULL);
+ g_assert(ret == 0);
+
+ g_assert_cmpstr((const char *)result, ==, exp_output);
+
+ qcrypto_hmac_free(hmac);
+
+ g_free(result);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_assert(qcrypto_init(NULL) == 0);
+
+ g_test_add_func("/crypto/hmac/iov", test_hmac_iov);
+ g_test_add_func("/crypto/hmac/alloc", test_hmac_alloc);
+ g_test_add_func("/crypto/hmac/prealloc", test_hmac_prealloc);
+ g_test_add_func("/crypto/hmac/digest", test_hmac_digest);
+
+ return g_test_run();
+}
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
index 9c4f6cb406..060407b20e 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -16,61 +16,53 @@
#include "libqos/virtio-pci.h"
#include "standard-headers/linux/virtio_ids.h"
#include "standard-headers/linux/virtio_pci.h"
+#include "hw/9pfs/9p.h"
static const char mount_tag[] = "qtest";
-static char *test_share;
+typedef struct {
+ QVirtioDevice *dev;
+ QOSState *qs;
+ QVirtQueue *vq;
+ char *test_share;
+ uint16_t p9_req_tag;
+} QVirtIO9P;
-static QOSState *qvirtio_9p_start(void)
+static QVirtIO9P *qvirtio_9p_start(const char *driver)
{
const char *arch = qtest_get_arch();
const char *cmd = "-fsdev local,id=fsdev0,security_model=none,path=%s "
- "-device virtio-9p-pci,fsdev=fsdev0,mount_tag=%s";
+ "-device %s,fsdev=fsdev0,mount_tag=%s";
+ QVirtIO9P *v9p = g_new0(QVirtIO9P, 1);
- test_share = g_strdup("/tmp/qtest.XXXXXX");
- g_assert_nonnull(mkdtemp(test_share));
+ v9p->test_share = g_strdup("/tmp/qtest.XXXXXX");
+ g_assert_nonnull(mkdtemp(v9p->test_share));
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- return qtest_pc_boot(cmd, test_share, mount_tag);
- }
- if (strcmp(arch, "ppc64") == 0) {
- return qtest_spapr_boot(cmd, test_share, mount_tag);
+ v9p->qs = qtest_pc_boot(cmd, v9p->test_share, driver, mount_tag);
+ } else if (strcmp(arch, "ppc64") == 0) {
+ v9p->qs = qtest_spapr_boot(cmd, v9p->test_share, driver, mount_tag);
+ } else {
+ g_printerr("virtio-9p tests are only available on x86 or ppc64\n");
+ exit(EXIT_FAILURE);
}
- g_printerr("virtio-9p tests are only available on x86 or ppc64\n");
- exit(EXIT_FAILURE);
-}
-
-static void qvirtio_9p_stop(QOSState *qs)
-{
- qtest_shutdown(qs);
- rmdir(test_share);
- g_free(test_share);
+ return v9p;
}
-static void pci_nop(void)
+static void qvirtio_9p_stop(QVirtIO9P *v9p)
{
- QOSState *qs;
-
- qs = qvirtio_9p_start();
- qvirtio_9p_stop(qs);
+ qtest_shutdown(v9p->qs);
+ rmdir(v9p->test_share);
+ g_free(v9p->test_share);
+ g_free(v9p);
}
-typedef struct {
- QVirtioDevice *dev;
- QOSState *qs;
- QVirtQueue *vq;
-} QVirtIO9P;
-
-static QVirtIO9P *qvirtio_9p_pci_init(QOSState *qs)
+static QVirtIO9P *qvirtio_9p_pci_start(void)
{
- QVirtIO9P *v9p;
- QVirtioPCIDevice *dev;
-
- v9p = g_new0(QVirtIO9P, 1);
-
- v9p->qs = qs;
- dev = qvirtio_pci_device_find(v9p->qs->pcibus, VIRTIO_ID_9P);
+ QVirtIO9P *v9p = qvirtio_9p_start("virtio-9p-pci");
+ QVirtioPCIDevice *dev = qvirtio_pci_device_find(v9p->qs->pcibus,
+ VIRTIO_ID_9P);
g_assert_nonnull(dev);
g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_9P);
v9p->dev = (QVirtioDevice *) dev;
@@ -84,26 +76,20 @@ static QVirtIO9P *qvirtio_9p_pci_init(QOSState *qs)
return v9p;
}
-static void qvirtio_9p_pci_free(QVirtIO9P *v9p)
+static void qvirtio_9p_pci_stop(QVirtIO9P *v9p)
{
qvirtqueue_cleanup(v9p->dev->bus, v9p->vq, v9p->qs->alloc);
qvirtio_pci_device_disable(container_of(v9p->dev, QVirtioPCIDevice, vdev));
g_free(v9p->dev);
- g_free(v9p);
+ qvirtio_9p_stop(v9p);
}
-static void pci_basic_config(void)
+static void pci_config(QVirtIO9P *v9p)
{
- QVirtIO9P *v9p;
- size_t tag_len;
+ size_t tag_len = qvirtio_config_readw(v9p->dev, 0);
char *tag;
int i;
- QOSState *qs;
- qs = qvirtio_9p_start();
- v9p = qvirtio_9p_pci_init(qs);
-
- tag_len = qvirtio_config_readw(v9p->dev, 0);
g_assert_cmpint(tag_len, ==, strlen(mount_tag));
tag = g_malloc(tag_len);
@@ -112,16 +98,406 @@ static void pci_basic_config(void)
}
g_assert_cmpmem(tag, tag_len, mount_tag, tag_len);
g_free(tag);
+}
+
+#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */
+
+typedef struct {
+ QVirtIO9P *v9p;
+ uint16_t tag;
+ uint64_t t_msg;
+ uint32_t t_size;
+ uint64_t r_msg;
+ /* No r_size, it is hardcoded to P9_MAX_SIZE */
+ size_t t_off;
+ size_t r_off;
+} P9Req;
+
+static void v9fs_memwrite(P9Req *req, const void *addr, size_t len)
+{
+ memwrite(req->t_msg + req->t_off, addr, len);
+ req->t_off += len;
+}
+
+static void v9fs_memskip(P9Req *req, size_t len)
+{
+ req->r_off += len;
+}
+
+static void v9fs_memrewind(P9Req *req, size_t len)
+{
+ req->r_off -= len;
+}
+
+static void v9fs_memread(P9Req *req, void *addr, size_t len)
+{
+ memread(req->r_msg + req->r_off, addr, len);
+ req->r_off += len;
+}
+
+static void v9fs_uint16_write(P9Req *req, uint16_t val)
+{
+ uint16_t le_val = cpu_to_le16(val);
+
+ v9fs_memwrite(req, &le_val, 2);
+}
+
+static void v9fs_uint16_read(P9Req *req, uint16_t *val)
+{
+ v9fs_memread(req, val, 2);
+ le16_to_cpus(val);
+}
+
+static void v9fs_uint32_write(P9Req *req, uint32_t val)
+{
+ uint32_t le_val = cpu_to_le32(val);
+
+ v9fs_memwrite(req, &le_val, 4);
+}
+
+static void v9fs_uint32_read(P9Req *req, uint32_t *val)
+{
+ v9fs_memread(req, val, 4);
+ le32_to_cpus(val);
+}
+
+/* len[2] string[len] */
+static uint16_t v9fs_string_size(const char *string)
+{
+ size_t len = strlen(string);
+
+ g_assert_cmpint(len, <=, UINT16_MAX);
+
+ return 2 + len;
+}
+
+static void v9fs_string_write(P9Req *req, const char *string)
+{
+ int len = strlen(string);
+
+ g_assert_cmpint(len, <=, UINT16_MAX);
+
+ v9fs_uint16_write(req, (uint16_t) len);
+ v9fs_memwrite(req, string, len);
+}
+
+static void v9fs_string_read(P9Req *req, uint16_t *len, char **string)
+{
+ uint16_t local_len;
+
+ v9fs_uint16_read(req, &local_len);
+ if (len) {
+ *len = local_len;
+ }
+ if (string) {
+ *string = g_malloc(local_len);
+ v9fs_memread(req, *string, local_len);
+ } else {
+ v9fs_memskip(req, local_len);
+ }
+}
+
+ typedef struct {
+ uint32_t size;
+ uint8_t id;
+ uint16_t tag;
+} QEMU_PACKED P9Hdr;
+
+static P9Req *v9fs_req_init(QVirtIO9P *v9p, uint32_t size, uint8_t id,
+ uint16_t tag)
+{
+ P9Req *req = g_new0(P9Req, 1);
+ uint32_t t_size = 7 + size; /* 9P header has well-known size of 7 bytes */
+ P9Hdr hdr = {
+ .size = cpu_to_le32(t_size),
+ .id = id,
+ .tag = cpu_to_le16(tag)
+ };
+
+ g_assert_cmpint(t_size, <=, P9_MAX_SIZE);
- qvirtio_9p_pci_free(v9p);
- qvirtio_9p_stop(qs);
+ req->v9p = v9p;
+ req->t_size = t_size;
+ req->t_msg = guest_alloc(v9p->qs->alloc, req->t_size);
+ v9fs_memwrite(req, &hdr, 7);
+ req->tag = tag;
+ return req;
+}
+
+static void v9fs_req_send(P9Req *req)
+{
+ QVirtIO9P *v9p = req->v9p;
+ uint32_t free_head;
+
+ req->r_msg = guest_alloc(v9p->qs->alloc, P9_MAX_SIZE);
+ free_head = qvirtqueue_add(v9p->vq, req->t_msg, req->t_size, false, true);
+ qvirtqueue_add(v9p->vq, req->r_msg, P9_MAX_SIZE, true, false);
+ qvirtqueue_kick(v9p->dev, v9p->vq, free_head);
+ req->t_off = 0;
+}
+
+static void v9fs_req_recv(P9Req *req, uint8_t id)
+{
+ QVirtIO9P *v9p = req->v9p;
+ P9Hdr hdr;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ qvirtio_wait_queue_isr(v9p->dev, v9p->vq, 1000 * 1000);
+
+ v9fs_memread(req, &hdr, 7);
+ le32_to_cpus(&hdr.size);
+ le16_to_cpus(&hdr.tag);
+ if (hdr.size >= 7) {
+ break;
+ }
+ v9fs_memrewind(req, 7);
+ }
+
+ g_assert_cmpint(hdr.size, >=, 7);
+ g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE);
+ g_assert_cmpint(hdr.tag, ==, req->tag);
+
+ if (hdr.id != id && hdr.id == P9_RLERROR) {
+ uint32_t err;
+ v9fs_uint32_read(req, &err);
+ g_printerr("Received Rlerror (%d) instead of Response %d\n", err, id);
+ g_assert_not_reached();
+ }
+ g_assert_cmpint(hdr.id, ==, id);
+}
+
+static void v9fs_req_free(P9Req *req)
+{
+ QVirtIO9P *v9p = req->v9p;
+
+ guest_free(v9p->qs->alloc, req->t_msg);
+ guest_free(v9p->qs->alloc, req->r_msg);
+ g_free(req);
+}
+
+/* size[4] Rlerror tag[2] ecode[4] */
+static void v9fs_rlerror(P9Req *req, uint32_t *err)
+{
+ v9fs_req_recv(req, P9_RLERROR);
+ v9fs_uint32_read(req, err);
+ v9fs_req_free(req);
+}
+
+/* size[4] Tversion tag[2] msize[4] version[s] */
+static P9Req *v9fs_tversion(QVirtIO9P *v9p, uint32_t msize, const char *version)
+{
+ P9Req *req = v9fs_req_init(v9p, 4 + v9fs_string_size(version), P9_TVERSION,
+ P9_NOTAG);
+
+ v9fs_uint32_write(req, msize);
+ v9fs_string_write(req, version);
+ v9fs_req_send(req);
+ return req;
+}
+
+/* size[4] Rversion tag[2] msize[4] version[s] */
+static void v9fs_rversion(P9Req *req, uint16_t *len, char **version)
+{
+ uint32_t msize;
+
+ v9fs_req_recv(req, P9_RVERSION);
+ v9fs_uint32_read(req, &msize);
+
+ g_assert_cmpint(msize, ==, P9_MAX_SIZE);
+
+ if (len || version) {
+ v9fs_string_read(req, len, version);
+ }
+
+ v9fs_req_free(req);
+}
+
+/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */
+static P9Req *v9fs_tattach(QVirtIO9P *v9p, uint32_t fid, uint32_t n_uname)
+{
+ const char *uname = ""; /* ignored by QEMU */
+ const char *aname = ""; /* ignored by QEMU */
+ P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH,
+ ++(v9p->p9_req_tag));
+
+ v9fs_uint32_write(req, fid);
+ v9fs_uint32_write(req, P9_NOFID);
+ v9fs_string_write(req, uname);
+ v9fs_string_write(req, aname);
+ v9fs_uint32_write(req, n_uname);
+ v9fs_req_send(req);
+ return req;
+}
+
+typedef char v9fs_qid[13];
+
+/* size[4] Rattach tag[2] qid[13] */
+static void v9fs_rattach(P9Req *req, v9fs_qid *qid)
+{
+ v9fs_req_recv(req, P9_RATTACH);
+ if (qid) {
+ v9fs_memread(req, qid, 13);
+ }
+ v9fs_req_free(req);
+}
+
+/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
+static P9Req *v9fs_twalk(QVirtIO9P *v9p, uint32_t fid, uint32_t newfid,
+ uint16_t nwname, char *const wnames[])
+{
+ P9Req *req;
+ int i;
+ uint32_t size = 4 + 4 + 2;
+
+ for (i = 0; i < nwname; i++) {
+ size += v9fs_string_size(wnames[i]);
+ }
+ req = v9fs_req_init(v9p, size, P9_TWALK, ++(v9p->p9_req_tag));
+ v9fs_uint32_write(req, fid);
+ v9fs_uint32_write(req, newfid);
+ v9fs_uint16_write(req, nwname);
+ for (i = 0; i < nwname; i++) {
+ v9fs_string_write(req, wnames[i]);
+ }
+ v9fs_req_send(req);
+ return req;
+}
+
+/* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */
+static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid)
+{
+ uint16_t local_nwqid;
+
+ v9fs_req_recv(req, P9_RWALK);
+ v9fs_uint16_read(req, &local_nwqid);
+ if (nwqid) {
+ *nwqid = local_nwqid;
+ }
+ if (wqid) {
+ *wqid = g_malloc(local_nwqid * 13);
+ v9fs_memread(req, *wqid, local_nwqid * 13);
+ }
+ v9fs_req_free(req);
+}
+
+static void fs_version(QVirtIO9P *v9p)
+{
+ const char *version = "9P2000.L";
+ uint16_t server_len;
+ char *server_version;
+ P9Req *req;
+
+ req = v9fs_tversion(v9p, P9_MAX_SIZE, version);
+ v9fs_rversion(req, &server_len, &server_version);
+
+ g_assert_cmpmem(server_version, server_len, version, strlen(version));
+
+ g_free(server_version);
+}
+
+static void fs_attach(QVirtIO9P *v9p)
+{
+ P9Req *req;
+
+ fs_version(v9p);
+ req = v9fs_tattach(v9p, 0, getuid());
+ v9fs_rattach(req, NULL);
+}
+
+static void fs_walk(QVirtIO9P *v9p)
+{
+ char *wnames[P9_MAXWELEM], *paths[P9_MAXWELEM];
+ char *last_path = v9p->test_share;
+ uint16_t nwqid;
+ v9fs_qid *wqid;
+ int i;
+ P9Req *req;
+
+ for (i = 0; i < P9_MAXWELEM; i++) {
+ wnames[i] = g_strdup_printf("%s%d", __func__, i);
+ last_path = paths[i] = g_strdup_printf("%s/%s", last_path, wnames[i]);
+ g_assert(!mkdir(paths[i], 0700));
+ }
+
+ fs_attach(v9p);
+ req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames);
+ v9fs_rwalk(req, &nwqid, &wqid);
+
+ g_assert_cmpint(nwqid, ==, P9_MAXWELEM);
+
+ for (i = 0; i < P9_MAXWELEM; i++) {
+ rmdir(paths[P9_MAXWELEM - i - 1]);
+ g_free(paths[P9_MAXWELEM - i - 1]);
+ g_free(wnames[i]);
+ }
+
+ g_free(wqid);
+}
+
+static void fs_walk_no_slash(QVirtIO9P *v9p)
+{
+ char *const wnames[] = { g_strdup(" /") };
+ P9Req *req;
+ uint32_t err;
+
+ fs_attach(v9p);
+ req = v9fs_twalk(v9p, 0, 1, 1, wnames);
+ v9fs_rlerror(req, &err);
+
+ g_assert_cmpint(err, ==, ENOENT);
+
+ g_free(wnames[0]);
+}
+
+static void fs_walk_dotdot(QVirtIO9P *v9p)
+{
+ char *const wnames[] = { g_strdup("..") };
+ v9fs_qid root_qid, *wqid;
+ P9Req *req;
+
+ fs_version(v9p);
+ req = v9fs_tattach(v9p, 0, getuid());
+ v9fs_rattach(req, &root_qid);
+
+ req = v9fs_twalk(v9p, 0, 1, 1, wnames);
+ v9fs_rwalk(req, NULL, &wqid); /* We now we'll get one qid */
+
+ g_assert_cmpmem(&root_qid, 13, wqid[0], 13);
+
+ g_free(wqid);
+ g_free(wnames[0]);
+}
+
+typedef void (*v9fs_test_fn)(QVirtIO9P *v9p);
+
+static void v9fs_run_pci_test(gconstpointer data)
+{
+ v9fs_test_fn fn = data;
+ QVirtIO9P *v9p = qvirtio_9p_pci_start();
+
+ if (fn) {
+ fn(v9p);
+ }
+ qvirtio_9p_pci_stop(v9p);
+}
+
+static void v9fs_qtest_pci_add(const char *path, v9fs_test_fn fn)
+{
+ qtest_add_data_func(path, fn, v9fs_run_pci_test);
}
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);
+ v9fs_qtest_pci_add("/virtio/9p/pci/nop", NULL);
+ v9fs_qtest_pci_add("/virtio/9p/pci/config", pci_config);
+ v9fs_qtest_pci_add("/virtio/9p/pci/fs/version/basic", fs_version);
+ v9fs_qtest_pci_add("/virtio/9p/pci/fs/attach/basic", fs_attach);
+ v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/basic", fs_walk);
+ v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/no_slash", fs_walk_no_slash);
+ v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/dotdot_from_root",
+ fs_walk_dotdot);
return g_test_run();
}