diff --git a/backends-cryptodev-builtin-Fix-local_error-leaks.patch b/backends-cryptodev-builtin-Fix-local_error-leaks.patch new file mode 100644 index 0000000000000000000000000000000000000000..c2ecf63d461a7e0591bd6f30a8eec5da5f9d12e3 --- /dev/null +++ b/backends-cryptodev-builtin-Fix-local_error-leaks.patch @@ -0,0 +1,63 @@ +From 2781f5673cc43d13b73e66fb266e7ea0b945429d Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 20:55:38 +0800 +Subject: [PATCH] backends/cryptodev-builtin: Fix local_error leaks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 06479dbf3d7d245572c4b3016e5a1d923ff04d66 + +backends/cryptodev-builtin: Fix local_error leaks +It seems that this error does not need to be propagated to the upper, +directly output the error to avoid the leaks + +Closes: https://gitlab.com/qemu-project/qemu/-/issues/2283 +Fixes: 2fda101 ("virtio-crypto: Support asynchronous mode") +Signed-off-by: Li Zhijian +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: zhenwei pi +Reviewed-by: Michael Tokarev +Signed-off-by: Michael Tokarev +Signed-off-by: Gao Jiazhen +--- + backends/cryptodev-builtin.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c +index 39d0455280..0822f198d9 100644 +--- a/backends/cryptodev-builtin.c ++++ b/backends/cryptodev-builtin.c +@@ -23,6 +23,7 @@ + + #include "qemu/osdep.h" + #include "sysemu/cryptodev.h" ++#include "qemu/error-report.h" + #include "qapi/error.h" + #include "standard-headers/linux/virtio_crypto.h" + #include "crypto/cipher.h" +@@ -396,8 +397,8 @@ static int cryptodev_builtin_create_session( + case VIRTIO_CRYPTO_HASH_CREATE_SESSION: + case VIRTIO_CRYPTO_MAC_CREATE_SESSION: + default: +- error_setg(&local_error, "Unsupported opcode :%" PRIu32 "", +- sess_info->op_code); ++ error_report("Unsupported opcode :%" PRIu32 "", ++ sess_info->op_code); + return -VIRTIO_CRYPTO_NOTSUPP; + } + +@@ -552,8 +553,8 @@ static int cryptodev_builtin_operation( + + if (op_info->session_id >= MAX_NUM_SESSIONS || + builtin->sessions[op_info->session_id] == NULL) { +- error_setg(&local_error, "Cannot find a valid session id: %" PRIu64 "", +- op_info->session_id); ++ error_report("Cannot find a valid session id: %" PRIu64 "", ++ op_info->session_id); + return -VIRTIO_CRYPTO_INVSESS; + } + +-- +2.41.0.windows.1 + diff --git a/char-stdio-Restore-blocking-mode-of-stdout-on-exit.patch b/char-stdio-Restore-blocking-mode-of-stdout-on-exit.patch new file mode 100644 index 0000000000000000000000000000000000000000..1e5664ca182074dfda72806a439bca8eb95c89ab --- /dev/null +++ b/char-stdio-Restore-blocking-mode-of-stdout-on-exit.patch @@ -0,0 +1,54 @@ +From 5661b12a28b650226cca100aeddd92d5cc788153 Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 20:41:18 +0800 +Subject: [PATCH] char-stdio: Restore blocking mode of stdout on exit + +cherry picked from commit a0124e333e2176640f233e5ea57a2f413985d9b5 + +qemu_chr_open_fd() sets stdout into non-blocking mode. Restore the old +fd flags on exit to avoid breaking unsuspecting applications that run on +the same terminal after qemu and don't expect to get EAGAIN. + +While at at, also ensure term_exit is called once (at the moment it's +called both from char_stdio_finalize() and as the atexit() hook. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2423 +Signed-off-by: Maxim Mikityanskiy +Link: https://lore.kernel.org/r/20240703190812.3459514-1-m +Signed-off-by: Gao Jiazhen +--- + chardev/char-stdio.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/chardev/char-stdio.c b/chardev/char-stdio.c +index 3c648678ab..b960ddd4e4 100644 +--- a/chardev/char-stdio.c ++++ b/chardev/char-stdio.c +@@ -41,6 +41,7 @@ + /* init terminal so that we can grab keys */ + static struct termios oldtty; + static int old_fd0_flags; ++static int old_fd1_flags; + static bool stdio_in_use; + static bool stdio_allow_signal; + static bool stdio_echo_state; +@@ -50,6 +51,8 @@ static void term_exit(void) + if (stdio_in_use) { + tcsetattr(0, TCSANOW, &oldtty); + fcntl(0, F_SETFL, old_fd0_flags); ++ fcntl(1, F_SETFL, old_fd1_flags); ++ stdio_in_use = false; + } + } + +@@ -102,6 +105,7 @@ static void qemu_chr_open_stdio(Chardev *chr, + + stdio_in_use = true; + old_fd0_flags = fcntl(0, F_GETFL); ++ old_fd1_flags = fcntl(1, F_GETFL); + tcgetattr(0, &oldtty); + if (!g_unix_set_fd_nonblocking(0, true, NULL)) { + error_setg_errno(errp, errno, "Failed to set FD nonblocking"); +-- +2.41.0.windows.1 + diff --git a/confidential-guest-support-introduce-ConfidentialGue.patch b/confidential-guest-support-introduce-ConfidentialGue.patch new file mode 100644 index 0000000000000000000000000000000000000000..95c1cc06e7d0c88affa517983d678e3b10119e04 --- /dev/null +++ b/confidential-guest-support-introduce-ConfidentialGue.patch @@ -0,0 +1,67 @@ +From da96618de3227b87ddd78388b80278bde230ce79 Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Tue, 27 Jul 2021 11:41:37 +0000 +Subject: [PATCH] confidential guest support: introduce + ConfidentialGuestMemoryEncryptionOps for encrypted VMs + +cherry-picked from https://github.com/AMDESE/qemu/commit/74fce7be9bd. + +When memory encryption is enabled in VM, the guest RAM will be encrypted +with the guest-specific key, to protect the confidentiality of data while +in transit we need to platform specific hooks to save or migrate the +guest RAM. + +Introduce the new ConfidentialGuestMemoryEncryptionOps in this patch +which will be later used by the encrypted guest for migration. + +Signed-off-by: Brijesh Singh +Co-developed-by: Ashish Kalra +Signed-off-by: Ashish Kalra +Signed-off-by: hanliyang +--- + include/exec/confidential-guest-support.h | 27 +++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h +index ba2dd4b5df..343f686fc2 100644 +--- a/include/exec/confidential-guest-support.h ++++ b/include/exec/confidential-guest-support.h +@@ -53,8 +53,35 @@ struct ConfidentialGuestSupport { + bool ready; + }; + ++/** ++ * The functions registers with ConfidentialGuestMemoryEncryptionOps will be ++ * used during the encrypted guest migration. ++ */ ++struct ConfidentialGuestMemoryEncryptionOps { ++ /* Initialize the platform specific state before starting the migration */ ++ int (*save_setup)(const char *pdh, const char *plat_cert, ++ const char *amd_cert); ++ ++ /* Write the encrypted page and metadata associated with it */ ++ int (*save_outgoing_page)(QEMUFile *f, uint8_t *ptr, uint32_t size, ++ uint64_t *bytes_sent); ++ ++ /* Load the incoming encrypted page into guest memory */ ++ int (*load_incoming_page)(QEMUFile *f, uint8_t *ptr); ++ ++ /* Check if gfn is in shared/unencrypted region */ ++ bool (*is_gfn_in_unshared_region)(unsigned long gfn); ++ ++ /* Write the shared regions list */ ++ int (*save_outgoing_shared_regions_list)(QEMUFile *f); ++ ++ /* Load the shared regions list */ ++ int (*load_incoming_shared_regions_list)(QEMUFile *f); ++}; ++ + typedef struct ConfidentialGuestSupportClass { + ObjectClass parent; ++ struct ConfidentialGuestMemoryEncryptionOps *memory_encryption_ops; + } ConfidentialGuestSupportClass; + + #endif /* !CONFIG_USER_ONLY */ +-- +2.41.0.windows.1 + diff --git a/crypto-Introduce-SM3-hash-hmac-pbkdf-algorithm.patch b/crypto-Introduce-SM3-hash-hmac-pbkdf-algorithm.patch new file mode 100644 index 0000000000000000000000000000000000000000..5a599c9fe61190c3b5dab9be3d3e4ee9e082c985 --- /dev/null +++ b/crypto-Introduce-SM3-hash-hmac-pbkdf-algorithm.patch @@ -0,0 +1,403 @@ +From 7b7742e137fbf9283cbbfb823fcf2ebe14df3154 Mon Sep 17 00:00:00 2001 +From: gaochuanji +Date: Mon, 19 Aug 2024 10:52:49 +0800 +Subject: [PATCH] crypto: Introduce SM3 hash hmac pbkdf algorithm + +Introduce the SM3 cryptographic hash algorithm (GB/T 32905-2016). + +SM3 (GB/T 32905-2016) is a cryptographic standard issued by the +Organization of State Commercial Cryptography Administration (OSCCA) +as an authorized cryptographic algorithm for use within China. + +Detect the SM3 cryptographic hash algorithm and enable the feature silently +if it is available. + +Signed-off-by: cheliequan +--- + crypto/hash-gcrypt.c | 3 +++ + crypto/hash-nettle.c | 14 ++++++++++++ + crypto/hash.c | 3 +++ + crypto/hmac-gcrypt.c | 3 +++ + crypto/hmac-nettle.c | 11 ++++++++++ + crypto/pbkdf-gcrypt.c | 6 ++++++ + crypto/pbkdf-nettle.c | 13 ++++++++++++ + meson.build | 39 ++++++++++++++++++++++++++++++++++ + qapi/crypto.json | 4 +++- + tests/unit/test-crypto-hash.c | 16 ++++++++++++++ + tests/unit/test-crypto-hmac.c | 8 +++++++ + tests/unit/test-crypto-pbkdf.c | 16 ++++++++++++++ + 12 files changed, 135 insertions(+), 1 deletion(-) + +diff --git a/crypto/hash-gcrypt.c b/crypto/hash-gcrypt.c +index 829e48258d..d3bdfe5633 100644 +--- a/crypto/hash-gcrypt.c ++++ b/crypto/hash-gcrypt.c +@@ -33,6 +33,9 @@ static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160, ++#ifdef CONFIG_CRYPTO_SM3 ++ [QCRYPTO_HASH_ALG_SM3] = GCRY_MD_SM3, ++#endif + }; + + gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg) +diff --git a/crypto/hash-nettle.c b/crypto/hash-nettle.c +index 1ca1a41062..0c2f8ce86c 100644 +--- a/crypto/hash-nettle.c ++++ b/crypto/hash-nettle.c +@@ -25,6 +25,9 @@ + #include + #include + #include ++#ifdef CONFIG_CRYPTO_SM3 ++#include ++#endif + + typedef void (*qcrypto_nettle_init)(void *ctx); + typedef void (*qcrypto_nettle_write)(void *ctx, +@@ -42,6 +45,9 @@ union qcrypto_hash_ctx { + struct sha384_ctx sha384; + struct sha512_ctx sha512; + struct ripemd160_ctx ripemd160; ++#ifdef CONFIG_CRYPTO_SM3 ++ struct sm3_ctx sm3; ++#endif + }; + + struct qcrypto_hash_alg { +@@ -92,6 +98,14 @@ struct qcrypto_hash_alg { + .result = (qcrypto_nettle_result)ripemd160_digest, + .len = RIPEMD160_DIGEST_SIZE, + }, ++#ifdef CONFIG_CRYPTO_SM3 ++ [QCRYPTO_HASH_ALG_SM3] = { ++ .init = (qcrypto_nettle_init)sm3_init, ++ .write = (qcrypto_nettle_write)sm3_update, ++ .result = (qcrypto_nettle_result)sm3_digest, ++ .len = SM3_DIGEST_SIZE, ++ }, ++#endif + }; + + gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg) +diff --git a/crypto/hash.c b/crypto/hash.c +index b0f8228bdc..8f1502ce68 100644 +--- a/crypto/hash.c ++++ b/crypto/hash.c +@@ -30,6 +30,9 @@ static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_SHA384] = 48, + [QCRYPTO_HASH_ALG_SHA512] = 64, + [QCRYPTO_HASH_ALG_RIPEMD160] = 20, ++#ifdef CONFIG_CRYPTO_SM3 ++ [QCRYPTO_HASH_ALG_SM3] = 32, ++#endif + }; + + size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg) +diff --git a/crypto/hmac-gcrypt.c b/crypto/hmac-gcrypt.c +index 0c6f979711..888afb86ed 100644 +--- a/crypto/hmac-gcrypt.c ++++ b/crypto/hmac-gcrypt.c +@@ -26,6 +26,9 @@ static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_SHA384] = GCRY_MAC_HMAC_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GCRY_MAC_HMAC_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MAC_HMAC_RMD160, ++#ifdef CONFIG_CRYPTO_SM3 ++ [QCRYPTO_HASH_ALG_SM3] = GCRY_MAC_HMAC_SM3, ++#endif + }; + + typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt; +diff --git a/crypto/hmac-nettle.c b/crypto/hmac-nettle.c +index 1ad6c4f253..e51e3319ab 100644 +--- a/crypto/hmac-nettle.c ++++ b/crypto/hmac-nettle.c +@@ -38,6 +38,9 @@ struct QCryptoHmacNettle { + struct hmac_sha256_ctx sha256_ctx; /* equals hmac_sha224_ctx */ + struct hmac_sha512_ctx sha512_ctx; /* equals hmac_sha384_ctx */ + struct hmac_ripemd160_ctx ripemd160_ctx; ++#ifdef CONFIG_CRYPTO_SM3 ++ struct hmac_sm3_ctx ctx; ++#endif + } u; + }; + +@@ -89,6 +92,14 @@ struct qcrypto_nettle_hmac_alg { + .digest = (qcrypto_nettle_hmac_digest)hmac_ripemd160_digest, + .len = RIPEMD160_DIGEST_SIZE, + }, ++#ifdef CONFIG_CRYPTO_SM3 ++ [QCRYPTO_HASH_ALG_SM3] = { ++ .setkey = (qcrypto_nettle_hmac_setkey)hmac_sm3_set_key, ++ .update = (qcrypto_nettle_hmac_update)hmac_sm3_update, ++ .digest = (qcrypto_nettle_hmac_digest)hmac_sm3_digest, ++ .len = SM3_DIGEST_SIZE, ++ }, ++#endif + }; + + bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +diff --git a/crypto/pbkdf-gcrypt.c b/crypto/pbkdf-gcrypt.c +index a8d8e64f4d..09b38d0d6e 100644 +--- a/crypto/pbkdf-gcrypt.c ++++ b/crypto/pbkdf-gcrypt.c +@@ -33,6 +33,9 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) + case QCRYPTO_HASH_ALG_SHA384: + case QCRYPTO_HASH_ALG_SHA512: + case QCRYPTO_HASH_ALG_RIPEMD160: ++#ifdef CONFIG_CRYPTO_SM3 ++ case QCRYPTO_HASH_ALG_SM3: ++#endif + return true; + default: + return false; +@@ -54,6 +57,9 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, + [QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160, ++#ifdef CONFIG_CRYPTO_SM3 ++ [QCRYPTO_HASH_ALG_SM3] = GCRY_MD_SM3, ++#endif + }; + int ret; + +diff --git a/crypto/pbkdf-nettle.c b/crypto/pbkdf-nettle.c +index d6293c25a1..5fea570bd3 100644 +--- a/crypto/pbkdf-nettle.c ++++ b/crypto/pbkdf-nettle.c +@@ -34,6 +34,9 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) + case QCRYPTO_HASH_ALG_SHA384: + case QCRYPTO_HASH_ALG_SHA512: + case QCRYPTO_HASH_ALG_RIPEMD160: ++#ifdef CONFIG_CRYPTO_SM3 ++ case QCRYPTO_HASH_ALG_SM3: ++#endif + return true; + default: + return false; +@@ -55,6 +58,9 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, + struct hmac_sha384_ctx sha384; + struct hmac_sha512_ctx sha512; + struct hmac_ripemd160_ctx ripemd160; ++#ifdef CONFIG_CRYPTO_SM3 ++ struct hmac_sm3_ctx sm3; ++#endif + } ctx; + + if (iterations > UINT_MAX) { +@@ -106,6 +112,13 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, + PBKDF2(&ctx.ripemd160, hmac_ripemd160_update, hmac_ripemd160_digest, + RIPEMD160_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; ++#ifdef CONFIG_CRYPTO_SM3 ++ case QCRYPTO_HASH_ALG_SM3: ++ hmac_sm3_set_key(&ctx.sm3, nkey, key); ++ PBKDF2(&ctx.sm3, hmac_sm3_update, hmac_sm3_digest, ++ SM3_DIGEST_SIZE, iterations, nsalt, salt, nout, out); ++ break; ++#endif + + default: + error_setg_errno(errp, ENOSYS, +diff --git a/meson.build b/meson.build +index 089f45d386..4024f9a4bb 100644 +--- a/meson.build ++++ b/meson.build +@@ -1486,6 +1486,7 @@ gcrypt = not_found + nettle = not_found + hogweed = not_found + crypto_sm4 = not_found ++crypto_sm3 = not_found + xts = 'none' + + if get_option('nettle').enabled() and get_option('gcrypt').enabled() +@@ -1522,6 +1523,17 @@ if not gnutls_crypto.found() + }''', dependencies: gcrypt) + crypto_sm4 = not_found + endif ++ crypto_sm3 = gcrypt ++ # SM3 ALG is available in libgcrypt >= 1.8 ++ if gcrypt.found() and not cc.links(''' ++ #include ++ int main(void) { ++ gcry_md_hd_t handler; ++ gcry_md_open(&handler, GCRY_MD_SM3, 0); ++ return 0; ++ }''', dependencies: gcrypt) ++ crypto_sm3 = not_found ++ endif + endif + if (not get_option('nettle').auto() or have_system) and not gcrypt.found() + nettle = dependency('nettle', version: '>=3.4', +@@ -1542,6 +1554,31 @@ if not gnutls_crypto.found() + }''', dependencies: nettle) + crypto_sm4 = not_found + endif ++ crypto_sm3 = nettle ++ # SM3 ALG is available in nettle >= 3.4 ++ if nettle.found() and not cc.links(''' ++ #include ++ #include ++ int main(void) { ++ struct sm3_ctx ctx; ++ struct hmac_sm3_ctx hmac_ctx; ++ unsigned char data[64] = {0}; ++ unsigned char output[32]; ++ ++ // SM3 hash function test ++ sm3_init(&ctx); ++ sm3_update(&ctx, 64, data); ++ sm3_digest(&ctx, 32, data); ++ ++ // HMAC-SM3 test ++ hmac_sm3_set_key(&hmac_ctx, 32, data); ++ hmac_sm3_update(&hmac_ctx, 64, data); ++ hmac_sm3_digest(&hmac_ctx, 32, output); ++ ++ return 0; ++ }''', dependencies: nettle) ++ crypto_sm3 = not_found ++ endif + endif + endif + +@@ -2229,6 +2266,7 @@ config_host_data.set('CONFIG_TASN1', tasn1.found()) + config_host_data.set('CONFIG_GCRYPT', gcrypt.found()) + config_host_data.set('CONFIG_NETTLE', nettle.found()) + config_host_data.set('CONFIG_CRYPTO_SM4', crypto_sm4.found()) ++config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found()) + config_host_data.set('CONFIG_HOGWEED', hogweed.found()) + config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') + config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim) +@@ -4306,6 +4344,7 @@ if nettle.found() + summary_info += {' XTS': xts != 'private'} + endif + summary_info += {'SM4 ALG support': crypto_sm4} ++summary_info += {'SM3 ALG support': crypto_sm3} + summary_info += {'AF_ALG support': have_afalg} + summary_info += {'rng-none': get_option('rng_none')} + summary_info += {'Linux keyring': have_keyring} +diff --git a/qapi/crypto.json b/qapi/crypto.json +index 2f2aeff5fd..af38f0a4bd 100644 +--- a/qapi/crypto.json ++++ b/qapi/crypto.json +@@ -58,11 +58,13 @@ + # + # @ripemd160: RIPEMD-160. (since 2.7) + # ++# @sm3: SM3. (since 8.2.0) ++# + # Since: 2.6 + ## + { 'enum': 'QCryptoHashAlgorithm', + 'prefix': 'QCRYPTO_HASH_ALG', +- 'data': ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160']} ++ 'data': ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160', 'sm3']} + + ## + # @QCryptoCipherAlgorithm: +diff --git a/tests/unit/test-crypto-hash.c b/tests/unit/test-crypto-hash.c +index 1f4abb822b..61908e1769 100644 +--- a/tests/unit/test-crypto-hash.c ++++ b/tests/unit/test-crypto-hash.c +@@ -42,6 +42,9 @@ + "63b54e4cb2d2032b393994aa263c0dbb" \ + "e00a9f2fe9ef6037352232a1eec55ee7" + #define OUTPUT_RIPEMD160 "f3d658fad3fdfb2b52c9369cf0d441249ddfa8a0" ++#ifdef CONFIG_CRYPTO_SM3 ++#define OUTPUT_SM3 "d4a97db105b477b84c4f20ec9c31a6c814e2705a0b83a5a89748d75f0ef456a1" ++#endif + + #define OUTPUT_MD5_B64 "Yo0gY3FWMDWrjvYvSSveyQ==" + #define OUTPUT_SHA1_B64 "sudPJnWKOkIeUJzuBFJEt4dTzAI=" +@@ -54,6 +57,10 @@ + "7sVe5w==" + #define OUTPUT_RIPEMD160_B64 "89ZY+tP9+ytSyTac8NRBJJ3fqKA=" + ++#ifdef CONFIG_CRYPTO_SM3 ++#define OUTPUT_SM3_B64 "1Kl9sQW0d7hMTyDsnDGmyBTicFoLg6Wol0jXXw70VqE=" ++#endif ++ + static const char *expected_outputs[] = { + [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5, + [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1, +@@ -62,6 +69,9 @@ static const char *expected_outputs[] = { + [QCRYPTO_HASH_ALG_SHA384] = OUTPUT_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = OUTPUT_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = OUTPUT_RIPEMD160, ++#ifdef CONFIG_CRYPTO_SM3 ++ [QCRYPTO_HASH_ALG_SM3] = OUTPUT_SM3, ++#endif + }; + static const char *expected_outputs_b64[] = { + [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5_B64, +@@ -71,6 +81,9 @@ static const char *expected_outputs_b64[] = { + [QCRYPTO_HASH_ALG_SHA384] = OUTPUT_SHA384_B64, + [QCRYPTO_HASH_ALG_SHA512] = OUTPUT_SHA512_B64, + [QCRYPTO_HASH_ALG_RIPEMD160] = OUTPUT_RIPEMD160_B64, ++#ifdef CONFIG_CRYPTO_SM3 ++ [QCRYPTO_HASH_ALG_SM3] = OUTPUT_SM3_B64, ++#endif + }; + static const int expected_lens[] = { + [QCRYPTO_HASH_ALG_MD5] = 16, +@@ -80,6 +93,9 @@ static const int expected_lens[] = { + [QCRYPTO_HASH_ALG_SHA384] = 48, + [QCRYPTO_HASH_ALG_SHA512] = 64, + [QCRYPTO_HASH_ALG_RIPEMD160] = 20, ++#ifdef CONFIG_CRYPTO_SM3 ++ [QCRYPTO_HASH_ALG_SM3] = 32, ++#endif + }; + + static const char hex[] = "0123456789abcdef"; +diff --git a/tests/unit/test-crypto-hmac.c b/tests/unit/test-crypto-hmac.c +index 23eb724d94..b1d04e9fcc 100644 +--- a/tests/unit/test-crypto-hmac.c ++++ b/tests/unit/test-crypto-hmac.c +@@ -76,6 +76,14 @@ static QCryptoHmacTestData test_data[] = { + "94964ed4c1155b62b668c241d67279e5" + "8a711676", + }, ++#ifdef CONFIG_CRYPTO_SM3 ++ { ++ .alg = QCRYPTO_HASH_ALG_SM3, ++ .hex_digest = ++ "760e3799332bc913819b930085360ddb" ++ "c05529261313d5b15b75bab4fd7ae91e", ++ }, ++#endif + }; + + static const char hex[] = "0123456789abcdef"; +diff --git a/tests/unit/test-crypto-pbkdf.c b/tests/unit/test-crypto-pbkdf.c +index 43c417f6b4..3d76593c86 100644 +--- a/tests/unit/test-crypto-pbkdf.c ++++ b/tests/unit/test-crypto-pbkdf.c +@@ -326,6 +326,22 @@ static QCryptoPbkdfTestData test_data[] = { + "\xce\xbf\x91\x14\x8b\x5c\x48\x41", + .nout = 32 + }, ++#ifdef CONFIG_CRYPTO_SM3 ++ { ++ .path = "/crypto/pbkdf/nonrfc/sm3/iter2", ++ .hash = QCRYPTO_HASH_ALG_SM3, ++ .iterations = 2, ++ .key = "password", ++ .nkey = 8, ++ .salt = "ATHENA.MIT.EDUraeburn", ++ .nsalt = 21, ++ .out = "\x48\x71\x1b\x58\xa3\xcb\xce\x06" ++ "\xba\xad\x77\xa8\xb5\xb9\xd8\x07" ++ "\x6a\xe2\xb3\x5b\x95\xce\xc8\xce" ++ "\xe7\xb1\xcb\xee\x61\xdf\x04\xea", ++ .nout = 32 ++ }, ++#endif + #if 0 + { + .path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200", +-- +2.41.0.windows.1 + diff --git a/crypto-tlscredspsk-Free-username-on-finalize.patch b/crypto-tlscredspsk-Free-username-on-finalize.patch new file mode 100644 index 0000000000000000000000000000000000000000..3da983d169ab4db8117d6adff5235518644482c4 --- /dev/null +++ b/crypto-tlscredspsk-Free-username-on-finalize.patch @@ -0,0 +1,78 @@ +From ec07000764f578bb7cd21fe73c8e649a183d7674 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 26 Aug 2024 10:56:57 +0800 +Subject: [PATCH] crypto/tlscredspsk: Free username on finalize +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 87e012f29f2e47dcd8c385ff8bb8188f9e06d4ea + +When the creds->username property is set we allocate memory +for it in qcrypto_tls_creds_psk_prop_set_username(), but +we never free this when the QCryptoTLSCredsPSK is destroyed. +Free the memory in finalize. + +This fixes a LeakSanitizer complaint in migration-test: + +$ (cd build/asan; ASAN_OPTIONS="fast_unwind_on_malloc=0" QTEST_QEMU_BINARY=./qemu-system-x86_64 ./tests/qtest/migration-test --tap -k -p /x86_64/migration/precopy/unix/tls/psk) + +================================================================= +==3867512==ERROR: LeakSanitizer: detected memory leaks + +Direct leak of 5 byte(s) in 1 object(s) allocated from: + #0 0x5624e5c99dee in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/qemu-system-x86_64+0x218edee) (BuildId: a9e623fa1009a9435c0142c037cd7b8c1ad04ce3) + #1 0x7fb199ae9738 in g_malloc debian/build/deb/../../../glib/gmem.c:128:13 + #2 0x7fb199afe583 in g_strdup debian/build/deb/../../../glib/gstrfuncs.c:361:17 + #3 0x5624e82ea919 in qcrypto_tls_creds_psk_prop_set_username /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../crypto/tlscredspsk.c:255:23 + #4 0x5624e812c6b5 in property_set_str /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../qom/object.c:2277:5 + #5 0x5624e8125ce5 in object_property_set /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../qom/object.c:1463:5 + #6 0x5624e8136e7c in object_set_properties_from_qdict /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../qom/object_interfaces.c:55:14 + #7 0x5624e81372d2 in user_creatable_add_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../qom/object_interfaces.c:112:5 + #8 0x5624e8137964 in user_creatable_add_qapi /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../qom/object_interfaces.c:157:11 + #9 0x5624e891ba3c in qmp_object_add /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../qom/qom-qmp-cmds.c:227:5 + #10 0x5624e8af9118 in qmp_marshal_object_add /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/qapi/qapi-commands-qom.c:337:5 + #11 0x5624e8bd1d49 in do_qmp_dispatch_bh /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../qapi/qmp-dispatch.c:128:5 + #12 0x5624e8cb2531 in aio_bh_call /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../util/async.c:171:5 + #13 0x5624e8cb340c in aio_bh_poll /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../util/async.c:218:13 + #14 0x5624e8c0be98 in aio_dispatch /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../util/aio-posix.c:423:5 + #15 0x5624e8cba3ce in aio_ctx_dispatch /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../util/async.c:360:5 + #16 0x7fb199ae0d3a in g_main_dispatch debian/build/deb/../../../glib/gmain.c:3419:28 + #17 0x7fb199ae0d3a in g_main_context_dispatch debian/build/deb/../../../glib/gmain.c:4137:7 + #18 0x5624e8cbe1d9 in glib_pollfds_poll /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../util/main-loop.c:287:9 + #19 0x5624e8cbcb13 in os_host_main_loop_wait /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../util/main-loop.c:310:5 + #20 0x5624e8cbc6dc in main_loop_wait /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../util/main-loop.c:589:11 + #21 0x5624e6f3f917 in qemu_main_loop /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../system/runstate.c:801:9 + #22 0x5624e893379c in qemu_default_main /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../system/main.c:37:14 + #23 0x5624e89337e7 in main /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/../../system/main.c:48:12 + #24 0x7fb197972d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 + #25 0x7fb197972e3f in __libc_start_main csu/../csu/libc-start.c:392:3 + #26 0x5624e5c16fa4 in _start (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/asan/qemu-system-x86_64+0x210bfa4) (BuildId: a9e623fa1009a9435c0142c037cd7b8c1ad04ce3) + +SUMMARY: AddressSanitizer: 5 byte(s) leaked in 1 allocation(s). + +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Maydell +Reviewed-by: Daniel P. Berrangé +Message-ID: <20240819145021.38524-1-peter.maydell@linaro.org> +Signed-off-by: Philippe Mathieu-Daudé +Signed-off-by: qihao_yewu +--- + crypto/tlscredspsk.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c +index 546cad1c5a..0d6b71a37c 100644 +--- a/crypto/tlscredspsk.c ++++ b/crypto/tlscredspsk.c +@@ -243,6 +243,7 @@ qcrypto_tls_creds_psk_finalize(Object *obj) + QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj); + + qcrypto_tls_creds_psk_unload(creds); ++ g_free(creds->username); + } + + static void +-- +2.41.0.windows.1 + diff --git a/cvm-Implement-command-blacklist-for-cvm-security-enh.patch b/cvm-Implement-command-blacklist-for-cvm-security-enh.patch new file mode 100644 index 0000000000000000000000000000000000000000..69b45e6ea3fa1aa1ff1895b2cde70cb855e84ca7 --- /dev/null +++ b/cvm-Implement-command-blacklist-for-cvm-security-enh.patch @@ -0,0 +1,118 @@ +From 384b3f41fd69ed6f5bf376ff1aac1a12deeea0fb Mon Sep 17 00:00:00 2001 +From: liupingwei +Date: Fri, 16 Aug 2024 18:06:10 +0800 +Subject: [PATCH] cvm : Implement command blacklist for cvm security + enhancement + +Added a new feature to intercept and block specific virsh commands(virsh +save,virsh restore,virsh dump,virsh suspend,virsh resume)that can impact +the security of cvm. + +Signed-off-by: liupingwei +--- + dump/dump.c | 7 +++++++ + migration/migration-hmp-cmds.c | 6 ++++++ + migration/savevm.c | 6 ++++++ + monitor/qmp-cmds.c | 6 ++++++ + 4 files changed, 25 insertions(+) + +diff --git a/dump/dump.c b/dump/dump.c +index 4819050764..787059ac2c 100644 +--- a/dump/dump.c ++++ b/dump/dump.c +@@ -20,6 +20,7 @@ + #include "sysemu/dump.h" + #include "sysemu/runstate.h" + #include "sysemu/cpus.h" ++#include "sysemu/kvm.h" + #include "qapi/error.h" + #include "qapi/qapi-commands-dump.h" + #include "qapi/qapi-events-dump.h" +@@ -2065,6 +2066,12 @@ void qmp_dump_guest_memory(bool paging, const char *protocol, + Error **errp) + { + ERRP_GUARD(); ++ ++ if (virtcca_cvm_enabled()) { ++ error_setg(errp, "The dump-guest-memory command is temporarily unsupported in cvm."); ++ return; ++ } ++ + const char *p; + int fd; + DumpState *s; +diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c +index 1fa6a5f478..386ba7fc98 100644 +--- a/migration/migration-hmp-cmds.c ++++ b/migration/migration-hmp-cmds.c +@@ -30,6 +30,7 @@ + #include "sysemu/runstate.h" + #include "ui/qemu-spice.h" + #include "sysemu/sysemu.h" ++#include "sysemu/kvm.h" + #include "options.h" + #include "migration.h" + +@@ -406,6 +407,11 @@ void hmp_loadvm(Monitor *mon, const QDict *qdict) + const char *name = qdict_get_str(qdict, "name"); + Error *err = NULL; + ++ if (virtcca_cvm_enabled()) { ++ error_setg(&err, "The loadvm command is temporarily unsupported in cvm."); ++ return; ++ } ++ + vm_stop(RUN_STATE_RESTORE_VM); + + if (load_snapshot(name, NULL, false, NULL, &err) && saved_vm_running) { +diff --git a/migration/savevm.c b/migration/savevm.c +index 477a19719f..cc65da605e 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -61,6 +61,7 @@ + #include "sysemu/replay.h" + #include "sysemu/runstate.h" + #include "sysemu/sysemu.h" ++#include "sysemu/kvm.h" + #include "sysemu/xen.h" + #include "migration/colo.h" + #include "qemu/bitmap.h" +@@ -3044,6 +3045,11 @@ int qemu_loadvm_approve_switchover(void) + bool save_snapshot(const char *name, bool overwrite, const char *vmstate, + bool has_devices, strList *devices, Error **errp) + { ++ if (virtcca_cvm_enabled()) { ++ error_setg(errp, "The savevm command is temporarily unsupported in cvm."); ++ return false; ++ } ++ + BlockDriverState *bs; + QEMUSnapshotInfo sn1, *sn = &sn1; + int ret = -1, ret2; +diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c +index e78462b857..c0b66f11bf 100644 +--- a/monitor/qmp-cmds.c ++++ b/monitor/qmp-cmds.c +@@ -23,6 +23,7 @@ + #include "sysemu/runstate.h" + #include "sysemu/runstate-action.h" + #include "sysemu/block-backend.h" ++#include "sysemu/kvm.h" + #include "qapi/error.h" + #include "qapi/qapi-init-commands.h" + #include "qapi/qapi-commands-control.h" +@@ -50,6 +51,11 @@ void qmp_quit(Error **errp) + + void qmp_stop(Error **errp) + { ++ if (virtcca_cvm_enabled()) { ++ error_setg(errp, "The stop command is temporarily unsupported in cvm."); ++ return; ++ } ++ + /* if there is a dump in background, we should wait until the dump + * finished */ + if (qemu_system_dump_in_progress()) { +-- +2.41.0.windows.1 + diff --git a/doc-update-AMD-SEV-to-include-Live-migration-flow.patch b/doc-update-AMD-SEV-to-include-Live-migration-flow.patch new file mode 100644 index 0000000000000000000000000000000000000000..122a797b677f056c8ce1d7f1aefd0eb1d672d306 --- /dev/null +++ b/doc-update-AMD-SEV-to-include-Live-migration-flow.patch @@ -0,0 +1,69 @@ +From 2da2e7ebea456360cc41881ff2e4a81a03b6d10c Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Thu, 7 May 2020 22:26:17 +0000 +Subject: [PATCH] doc: update AMD SEV to include Live migration flow + +cherry-picked from https://github.com/AMDESE/qemu/commit/0e2b3d80e3. + +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Brijesh Singh +Signed-off-by: Ashish Kalra +Signed-off-by: hanliyang +--- + docs/system/i386/amd-memory-encryption.rst | 40 +++++++++++++++++++++- + 1 file changed, 39 insertions(+), 1 deletion(-) + +diff --git a/docs/system/i386/amd-memory-encryption.rst b/docs/system/i386/amd-memory-encryption.rst +index e9bc142bc1..b7e3f46ff6 100644 +--- a/docs/system/i386/amd-memory-encryption.rst ++++ b/docs/system/i386/amd-memory-encryption.rst +@@ -177,7 +177,45 @@ TODO + Live Migration + --------------- + +-TODO ++AMD SEV encrypts the memory of VMs and because a different key is used ++in each VM, the hypervisor will be unable to simply copy the ++ciphertext from one VM to another to migrate the VM. Instead the AMD SEV Key ++Management API provides sets of function which the hypervisor can use ++to package a guest page for migration, while maintaining the confidentiality ++provided by AMD SEV. ++ ++SEV guest VMs have the concept of private and shared memory. The private ++memory is encrypted with the guest-specific key, while shared memory may ++be encrypted with the hypervisor key. The migration APIs provided by the ++SEV API spec should be used for migrating the private pages. The ++KVM_GET_PAGE_ENC_BITMAP ioctl can be used to get the guest page encryption ++bitmap. The bitmap can be used to check if the given guest page is ++private or shared. ++ ++Before initiating the migration, we need to know the targets machine's public ++Diffie-Hellman key (PDH) and certificate chain. It can be retrieved ++with the 'query-sev-capabilities' QMP command or using the sev-tool. The ++migrate-set-parameter can be used to pass the target machine's PDH and ++certificate chain. ++ ++During the migration flow, the SEND_START is called on the source hypervisor ++to create an outgoing encryption context. The SEV guest policy dictates whether ++the certificate passed through the migrate-sev-set-info command will be ++validated. SEND_UPDATE_DATA is called to encrypt the guest private pages. ++After migration is completed, SEND_FINISH is called to destroy the encryption ++context and make the VM non-runnable to protect it against cloning. ++ ++On the target machine, RECEIVE_START is called first to create an ++incoming encryption context. The RECEIVE_UPDATE_DATA is called to copy ++the received encrypted page into guest memory. After migration has ++completed, RECEIVE_FINISH is called to make the VM runnable. ++ ++For more information about the migration see SEV API Appendix A ++Usage flow (Live migration section). ++ ++NOTE: ++To protect against the memory clone SEV APIs are designed to make the VM ++unrunnable in case of the migration failure. + + References + ---------- +-- +2.41.0.windows.1 + diff --git a/hw-core-ptimer-fix-timer-zero-period-condition-for-f.patch b/hw-core-ptimer-fix-timer-zero-period-condition-for-f.patch new file mode 100644 index 0000000000000000000000000000000000000000..20d112f0d532747ade8bd7db01cbfd377a7724b3 --- /dev/null +++ b/hw-core-ptimer-fix-timer-zero-period-condition-for-f.patch @@ -0,0 +1,101 @@ +From fcd3ff011e62739b824c2e465e01b98c47e364f5 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Fri, 16 Aug 2024 17:01:07 +0800 +Subject: [PATCH] hw/core/ptimer: fix timer zero period condition for freq > + 1GHz + +cheery-pick from 446e5e8b4515e9a7be69ef6a29852975289bb6f0 + +The real period is zero when both period and period_frac are zero. +Check the method ptimer_set_freq, if freq is larger than 1000 MHz, +the period is zero, but the period_frac is not, in this case, the +ptimer will work but the current code incorrectly recognizes that +the ptimer is disabled. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2306 +Signed-off-by: JianZhou Yue +Message-id: 3DA024AEA8B57545AF1B3CAA37077D0FB75E82C8@SHASXM03.verisilicon.com +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: qihao_yewu +--- + hw/core/ptimer.c | 4 ++-- + tests/unit/ptimer-test.c | 33 +++++++++++++++++++++++++++++++++ + 2 files changed, 35 insertions(+), 2 deletions(-) + +diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c +index e03165febf..7177ecfab0 100644 +--- a/hw/core/ptimer.c ++++ b/hw/core/ptimer.c +@@ -83,7 +83,7 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust) + delta = s->delta = s->limit; + } + +- if (s->period == 0) { ++ if (s->period == 0 && s->period_frac == 0) { + if (!qtest_enabled()) { + fprintf(stderr, "Timer with period zero, disabling\n"); + } +@@ -309,7 +309,7 @@ void ptimer_run(ptimer_state *s, int oneshot) + + assert(s->in_transaction); + +- if (was_disabled && s->period == 0) { ++ if (was_disabled && s->period == 0 && s->period_frac == 0) { + if (!qtest_enabled()) { + fprintf(stderr, "Timer with period zero, disabling\n"); + } +diff --git a/tests/unit/ptimer-test.c b/tests/unit/ptimer-test.c +index 04b5f4e3d0..08240594bb 100644 +--- a/tests/unit/ptimer-test.c ++++ b/tests/unit/ptimer-test.c +@@ -763,6 +763,33 @@ static void check_oneshot_with_load_0(gconstpointer arg) + ptimer_free(ptimer); + } + ++static void check_freq_more_than_1000M(gconstpointer arg) ++{ ++ const uint8_t *policy = arg; ++ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy); ++ bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN); ++ ++ triggered = false; ++ ++ ptimer_transaction_begin(ptimer); ++ ptimer_set_freq(ptimer, 2000000000); ++ ptimer_set_limit(ptimer, 8, 1); ++ ptimer_run(ptimer, 1); ++ ptimer_transaction_commit(ptimer); ++ ++ qemu_clock_step(3); ++ ++ g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 3 : 2); ++ g_assert_false(triggered); ++ ++ qemu_clock_step(1); ++ ++ g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); ++ g_assert_true(triggered); ++ ++ ptimer_free(ptimer); ++} ++ + static void add_ptimer_tests(uint8_t policy) + { + char policy_name[256] = ""; +@@ -857,6 +884,12 @@ static void add_ptimer_tests(uint8_t policy) + policy_name), + g_memdup2(&policy, 1), check_oneshot_with_load_0, g_free); + g_free(tmp); ++ ++ g_test_add_data_func_full( ++ tmp = g_strdup_printf("/ptimer/freq_more_than_1000M policy=%s", ++ policy_name), ++ g_memdup2(&policy, 1), check_freq_more_than_1000M, g_free); ++ g_free(tmp); + } + + static void add_all_ptimer_policies_comb_tests(void) +-- +2.41.0.windows.1 + diff --git a/hw-display-vhost-user-gpu.c-fix-vhost_user_gpu_chr_r.patch b/hw-display-vhost-user-gpu.c-fix-vhost_user_gpu_chr_r.patch new file mode 100644 index 0000000000000000000000000000000000000000..6b4ac413455e11b93cc72ce1275c1a45f8097352 --- /dev/null +++ b/hw-display-vhost-user-gpu.c-fix-vhost_user_gpu_chr_r.patch @@ -0,0 +1,39 @@ +From f2efa9729b4cb4ec98f93c1eafe38459fd82e7ae Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 26 Aug 2024 09:34:05 +0800 +Subject: [PATCH] hw/display/vhost-user-gpu.c: fix vhost_user_gpu_chr_read() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from d6192f3f7593536a4285e8ab6c6cf3f34973ce62 + +fix vhost_user_gpu_chr_read() where `size` was incorrectly passed to `msg->flags`. + +Fixes: 267f664658 ("hw/display: add vhost-user-vga & gpu-pci") +Signed-off-by: Haoran Zhang +Reviewed-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Michael Tokarev +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + hw/display/vhost-user-gpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 709c8a02a1..373f04a7b4 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -385,7 +385,7 @@ vhost_user_gpu_chr_read(void *opaque) + } + + msg->request = request; +- msg->flags = size; ++ msg->flags = flags; + msg->size = size; + + if (request == VHOST_USER_GPU_CURSOR_UPDATE || +-- +2.41.0.windows.1 + diff --git a/hw-loongarch-Fix-fdt-memory-node-wrong-reg.patch b/hw-loongarch-Fix-fdt-memory-node-wrong-reg.patch new file mode 100644 index 0000000000000000000000000000000000000000..3bae4ee1ab9a3ffb6234988b4567f152bfa1f90c --- /dev/null +++ b/hw-loongarch-Fix-fdt-memory-node-wrong-reg.patch @@ -0,0 +1,44 @@ +From 073620787702404e2d71486c30967455c3c7904c Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 10:57:38 +0800 +Subject: [PATCH] hw/loongarch: Fix fdt memory node wrong 'reg' + +cherry picked from commitd b11f9814526b833b3a052be2559457b1affad7f5 + +The right fdt memory node like [1], not [2] + + [1] + memory@0 { + device_type = "memory"; + reg = <0x00 0x00 0x00 0x10000000>; + }; + [2] + memory@0 { + device_type = "memory"; + reg = <0x02 0x00 0x02 0x10000000>; + }; + +Reviewed-by: Bibo Mao +Signed-off-by: Song Gao +Message-Id: <20240426091551.2397867-10-gaosong@loongson.cn> +Signed-off-by: Gao Jiazhen +--- + hw/loongarch/virt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index 01e59f3a95..fc7b70ed4e 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -360,7 +360,7 @@ static void fdt_add_memory_node(MachineState *ms, + char *nodename = g_strdup_printf("/memory@%" PRIx64, base); + + qemu_fdt_add_subnode(ms->fdt, nodename); +- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 2, base, 2, size); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, 0, size); + qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory"); + + if (ms->numa_state && ms->numa_state->num_nodes) { +-- +2.41.0.windows.1 + diff --git a/hw-loongarch-virt-Fix-FDT-memory-node-address-width.patch b/hw-loongarch-virt-Fix-FDT-memory-node-address-width.patch new file mode 100644 index 0000000000000000000000000000000000000000..f7d5ce8faddfbae68329b3c217a9ece3589b133e --- /dev/null +++ b/hw-loongarch-virt-Fix-FDT-memory-node-address-width.patch @@ -0,0 +1,36 @@ +From b9e94d97025251cfd13b3ad859b97002504285ce Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Fri, 13 Sep 2024 18:57:20 +0800 +Subject: [PATCH] hw/loongarch/virt: Fix FDT memory node address width + +cherry picked from commitd 6204af704a071ea68d3af55c0502b112a7af9546 + +Higher bits for memory nodes were omitted at qemu_fdt_setprop_cells. + +Cc: mailto:qemu-stable@nongnu.org +Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com +Reviewed-by: Song Gao gaosong@loongson.cn +Message-Id: 20240520-loongarch-fdt-memnode-v1-1-5ea9be93911e@flygoat.com +Signed-off-by: Song Gao gaosong@loongson.cn +Signed-off-by: Gao Jiazhen gaojiazhen_yewu@cmss.chinamobile.com +--- + hw/loongarch/virt.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c +index fc7b70ed4e..5d4fcb7a55 100644 +--- a/hw/loongarch/virt.c ++++ b/hw/loongarch/virt.c +@@ -360,7 +360,8 @@ static void fdt_add_memory_node(MachineState *ms, + char *nodename = g_strdup_printf("/memory@%" PRIx64, base); + + qemu_fdt_add_subnode(ms->fdt, nodename); +- qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, 0, size); ++ qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", base >> 32, base, ++ size >> 32, size); + qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory"); + + if (ms->numa_state && ms->numa_state->num_nodes) { +-- +2.41.0.windows.1 + diff --git a/hw-misc-bcm2835_property-Fix-handling-of-FRAMEBUFFER.patch b/hw-misc-bcm2835_property-Fix-handling-of-FRAMEBUFFER.patch new file mode 100644 index 0000000000000000000000000000000000000000..941afc2872dc36978e264c1b129f9c219fc76878 --- /dev/null +++ b/hw-misc-bcm2835_property-Fix-handling-of-FRAMEBUFFER.patch @@ -0,0 +1,92 @@ +From 93959a5378f57190fb79dd1ccdefb8d8cd095b58 Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 10:29:32 +0800 +Subject: [PATCH] hw/misc/bcm2835_property: Fix handling of + FRAMEBUFFER_SET_PALETTE +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 0892fffc2abaadfb5d8b79bb0250ae1794862560 + +The documentation of the "Set palette" mailbox property at +https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface#set-palette +says it has the form: + + Length: 24..1032 + Value: + u32: offset: first palette index to set (0-255) + u32: length: number of palette entries to set (1-256) + u32...: RGBA palette values (offset to offset+length-1) + +We get this wrong in a couple of ways: + * we aren't checking the offset and length are in range, so the guest + can make us spin for a long time by providing a large length + * the bounds check on our loop is wrong: we should iterate through + 'length' palette entries, not 'length - offset' entries + +Fix the loop to implement the bounds checks and get the loop +condition right. In the process, make the variables local to +this switch case, rather than function-global, so it's clearer +what type they are when reading the code. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Maydell +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20240723131029.1159908-2-peter.maydell@linaro.org +Signed-off-by: Gao Jiazhen +--- + hw/misc/bcm2835_property.c | 27 ++++++++++++++++----------- + 1 file changed, 16 insertions(+), 11 deletions(-) + +diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c +index ff55a4e2cd..12a1bc558a 100644 +--- a/hw/misc/bcm2835_property.c ++++ b/hw/misc/bcm2835_property.c +@@ -28,8 +28,6 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) + uint32_t tot_len; + size_t resplen; + uint32_t tmp; +- int n; +- uint32_t offset, length, color; + + /* + * Copy the current state of the framebuffer config; we will update +@@ -264,18 +262,25 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) + resplen = 16; + break; + case RPI_FWREQ_FRAMEBUFFER_SET_PALETTE: +- offset = ldl_le_phys(&s->dma_as, value + 12); +- length = ldl_le_phys(&s->dma_as, value + 16); +- n = 0; +- while (n < length - offset) { +- color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2)); +- stl_le_phys(&s->dma_as, +- s->fbdev->vcram_base + ((offset + n) << 2), color); +- n++; ++ { ++ uint32_t offset = ldl_le_phys(&s->dma_as, value + 12); ++ uint32_t length = ldl_le_phys(&s->dma_as, value + 16); ++ int resp; ++ ++ if (offset > 255 || length < 1 || length > 256) { ++ resp = 1; /* invalid request */ ++ } else { ++ for (uint32_t e = 0; e < length; e++) { ++ uint32_t color = ldl_le_phys(&s->dma_as, value + 20 + (e << 2)); ++ stl_le_phys(&s->dma_as, ++ s->fbdev->vcram_base + ((offset + e) << 2), color); ++ } ++ resp = 0; + } +- stl_le_phys(&s->dma_as, value + 12, 0); ++ stl_le_phys(&s->dma_as, value + 12, resp); + resplen = 4; + break; ++ } + case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS: + stl_le_phys(&s->dma_as, value + 12, 1); + resplen = 4; +-- +2.41.0.windows.1 + diff --git a/hw-misc-support-vpsp.patch b/hw-misc-support-vpsp.patch new file mode 100644 index 0000000000000000000000000000000000000000..21984f5d2523c2d013f78c5ab0bf9cb21f754241 --- /dev/null +++ b/hw-misc-support-vpsp.patch @@ -0,0 +1,190 @@ +From f74cee44cd57da213a790f7711a68da0f4de061a Mon Sep 17 00:00:00 2001 +From: xiongmengbiao +Date: Thu, 30 Nov 2023 13:47:21 +0800 +Subject: [PATCH] hw/misc: support vpsp + +simulate a psp misc device for support tkm's key isolation + +Signed-off-by: xiongmengbiao +--- + hw/misc/Kconfig | 4 ++ + hw/misc/meson.build | 1 + + hw/misc/psp.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 146 insertions(+) + create mode 100644 hw/misc/psp.c + +diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig +index cc8a8c1418..2ea5c68eb5 100644 +--- a/hw/misc/Kconfig ++++ b/hw/misc/Kconfig +@@ -200,4 +200,8 @@ config IOSB + config XLNX_VERSAL_TRNG + bool + ++config PSP_DEV ++ bool ++ default y ++ + source macio/Kconfig +diff --git a/hw/misc/meson.build b/hw/misc/meson.build +index 36c20d5637..28cba0ac28 100644 +--- a/hw/misc/meson.build ++++ b/hw/misc/meson.build +@@ -9,6 +9,7 @@ system_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) + system_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c')) + system_ss.add(when: 'CONFIG_LED', if_true: files('led.c')) + system_ss.add(when: 'CONFIG_PVPANIC_COMMON', if_true: files('pvpanic.c')) ++system_ss.add(when: 'CONFIG_PSP_DEV', if_true: files('psp.c')) + + # ARM devices + system_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c')) +diff --git a/hw/misc/psp.c b/hw/misc/psp.c +new file mode 100644 +index 0000000000..6ff2ceec10 +--- /dev/null ++++ b/hw/misc/psp.c +@@ -0,0 +1,141 @@ ++/* ++ * hygon psp device emulation ++ * ++ * Copyright 2024 HYGON Corp. ++ * ++ * 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 "qemu/compiler.h" ++#include "qemu/error-report.h" ++#include "qapi/error.h" ++#include "migration/vmstate.h" ++#include "hw/qdev-properties.h" ++#include "sysemu/runstate.h" ++#include ++ ++#define TYPE_PSP_DEV "psp" ++OBJECT_DECLARE_SIMPLE_TYPE(PSPDevState, PSP_DEV) ++ ++struct PSPDevState { ++ /* Private */ ++ DeviceState pdev; ++ ++ /* Public */ ++ Notifier shutdown_notifier; ++ int dev_fd; ++ bool enabled; ++ ++ /** ++ * vid is used to identify a virtual machine in qemu. ++ * When a virtual machine accesses a tkm key, ++ * the TKM module uses different key spaces based on different vids. ++ */ ++ uint32_t vid; ++}; ++ ++#define PSP_DEV_PATH "/dev/hygon_psp_config" ++#define HYGON_PSP_IOC_TYPE 'H' ++#define PSP_IOC_MUTEX_ENABLE _IOWR(HYGON_PSP_IOC_TYPE, 1, NULL) ++#define PSP_IOC_MUTEX_DISABLE _IOWR(HYGON_PSP_IOC_TYPE, 2, NULL) ++#define PSP_IOC_VPSP_OPT _IOWR(HYGON_PSP_IOC_TYPE, 3, NULL) ++ ++enum VPSP_DEV_CTRL_OPCODE { ++ VPSP_OP_VID_ADD, ++ VPSP_OP_VID_DEL, ++}; ++ ++struct psp_dev_ctrl { ++ unsigned char op; ++ union { ++ unsigned int vid; ++ unsigned char reserved[128]; ++ } data; ++}; ++ ++static void psp_dev_destroy(PSPDevState *state) ++{ ++ struct psp_dev_ctrl ctrl = { 0 }; ++ if (state && state->dev_fd) { ++ if (state->enabled) { ++ ctrl.op = VPSP_OP_VID_DEL; ++ if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { ++ error_report("VPSP_OP_VID_DEL: %d", -errno); ++ } else { ++ state->enabled = false; ++ } ++ } ++ qemu_close(state->dev_fd); ++ state->dev_fd = 0; ++ } ++} ++ ++/** ++ * Guest OS performs shut down operations through 'shutdown' and 'powerdown' event. ++ * The 'powerdown' event will also trigger 'shutdown' in the end, ++ * so only attention to the 'shutdown' event. ++ * ++ * When Guest OS trigger 'reboot' or 'reset' event, to do nothing. ++*/ ++static void psp_dev_shutdown_notify(Notifier *notifier, void *data) ++{ ++ PSPDevState *state = container_of(notifier, PSPDevState, shutdown_notifier); ++ psp_dev_destroy(state); ++} ++ ++static void psp_dev_realize(DeviceState *dev, Error **errp) ++{ ++ struct psp_dev_ctrl ctrl = { 0 }; ++ PSPDevState *state = PSP_DEV(dev); ++ ++ state->dev_fd = qemu_open_old(PSP_DEV_PATH, O_RDWR); ++ if (state->dev_fd < 0) { ++ error_setg(errp, "fail to open %s, errno %d.", PSP_DEV_PATH, errno); ++ goto end; ++ } ++ ++ ctrl.op = VPSP_OP_VID_ADD; ++ ctrl.data.vid = state->vid; ++ if (ioctl(state->dev_fd, PSP_IOC_VPSP_OPT, &ctrl) < 0) { ++ error_setg(errp, "psp_dev_realize VPSP_OP_VID_ADD vid %d, return %d", ctrl.data.vid, -errno); ++ goto end; ++ } ++ ++ state->enabled = true; ++ state->shutdown_notifier.notify = psp_dev_shutdown_notify; ++ qemu_register_shutdown_notifier(&state->shutdown_notifier); ++end: ++ return; ++} ++ ++static struct Property psp_dev_properties[] = { ++ DEFINE_PROP_UINT32("vid", PSPDevState, vid, 0), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void psp_dev_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ ++ dc->desc = "PSP Device"; ++ dc->realize = psp_dev_realize; ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); ++ device_class_set_props(dc, psp_dev_properties); ++} ++ ++static const TypeInfo psp_dev_info = { ++ .name = TYPE_PSP_DEV, ++ .parent = TYPE_DEVICE, ++ .instance_size = sizeof(PSPDevState), ++ .class_init = psp_dev_class_init, ++}; ++ ++static void psp_dev_register_types(void) ++{ ++ type_register_static(&psp_dev_info); ++} ++ ++type_init(psp_dev_register_types) +-- +2.41.0.windows.1 + diff --git a/hw-nvme-fix-leak-of-uninitialized-memory-in-io_mgmt_.patch b/hw-nvme-fix-leak-of-uninitialized-memory-in-io_mgmt_.patch new file mode 100644 index 0000000000000000000000000000000000000000..762e2ff430331e411e310647e90e74536498de11 --- /dev/null +++ b/hw-nvme-fix-leak-of-uninitialized-memory-in-io_mgmt_.patch @@ -0,0 +1,35 @@ +From 80f4d02d7afa212fba4420a3af04f3a670b9a5d4 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 26 Aug 2024 10:40:40 +0800 +Subject: [PATCH] hw/nvme: fix leak of uninitialized memory in io_mgmt_recv + +cheery-pick from 6a22121c4f25b181e99479f65958ecde65da1c92 + +Yutaro Shimizu from the Cyber Defense Institute discovered a bug in the +NVMe emulation that leaks contents of an uninitialized heap buffer if +subsystem and FDP emulation are enabled. + +Cc: qemu-stable@nongnu.org +Reported-by: Yutaro Shimizu +Signed-off-by: Klaus Jensen +Signed-off-by: qihao_yewu +--- + hw/nvme/ctrl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index aecf7c37bb..104aebc5ea 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -4302,7 +4302,7 @@ static uint16_t nvme_io_mgmt_recv_ruhs(NvmeCtrl *n, NvmeRequest *req, + + nruhsd = ns->fdp.nphs * endgrp->fdp.nrg; + trans_len = sizeof(NvmeRuhStatus) + nruhsd * sizeof(NvmeRuhStatusDescr); +- buf = g_malloc(trans_len); ++ buf = g_malloc0(trans_len); + + trans_len = MIN(trans_len, len); + +-- +2.41.0.windows.1 + diff --git a/kvm-Add-support-for-CSV2-reboot.patch b/kvm-Add-support-for-CSV2-reboot.patch new file mode 100644 index 0000000000000000000000000000000000000000..10b0a12555d475565df8e3ed7fafb350a0ef6589 --- /dev/null +++ b/kvm-Add-support-for-CSV2-reboot.patch @@ -0,0 +1,171 @@ +From 09934a231a513289caaae68e68912b735cb44b75 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Thu, 15 Apr 2021 08:32:24 -0400 +Subject: [PATCH] kvm: Add support for CSV2 reboot + +Linux will set vcpu.arch.guest_state_protected to true after execute +LAUNCH_UPDATE_VMSA successfully, and then KVM will prevent any changes +to VMCB State Save Area. + +In order to support CSV2 guest reboot, calls cpus_control_pre_system_reset() +to set vcpu.arch.guest_state_protected to false, and calls +cpus_control_post_system_reset() to restore VMSA of guest's vcpu with +data generated by LAUNCH_UPDATE_VMSA. + +In addition, for memory encrypted guest, additional works may be +required during system reset, such as flushing the cache. The function +cpus_control_post_system_reset() hints linux to flush caches of guest +memory. + +Signed-off-by: hanliyang +--- + accel/kvm/kvm-accel-ops.c | 3 +++ + accel/kvm/kvm-all.c | 10 ++++++++++ + accel/kvm/kvm-cpus.h | 3 +++ + include/sysemu/accel-ops.h | 3 +++ + include/sysemu/cpus.h | 2 ++ + linux-headers/linux/kvm.h | 4 ++++ + system/cpus.c | 14 ++++++++++++++ + system/runstate.c | 5 +++++ + 8 files changed, 44 insertions(+) + +diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c +index 6195150a0b..54f19028b8 100644 +--- a/accel/kvm/kvm-accel-ops.c ++++ b/accel/kvm/kvm-accel-ops.c +@@ -112,6 +112,9 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, void *data) + ops->remove_breakpoint = kvm_remove_breakpoint; + ops->remove_all_breakpoints = kvm_remove_all_breakpoints; + #endif ++ ++ ops->control_pre_system_reset = kvm_cpus_control_pre_system_reset; ++ ops->control_post_system_reset = kvm_cpus_control_post_system_reset; + } + + static const TypeInfo kvm_accel_ops_type = { +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index dc3605e648..8077630825 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -2810,6 +2810,16 @@ void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu) + run_on_cpu(cpu, do_kvm_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL); + } + ++void kvm_cpus_control_pre_system_reset(void) ++{ ++ kvm_vm_ioctl(kvm_state, KVM_CONTROL_VCPU_PRE_SYSTEM_RESET, NULL); ++} ++ ++void kvm_cpus_control_post_system_reset(void) ++{ ++ kvm_vm_ioctl(kvm_state, KVM_CONTROL_VCPU_POST_SYSTEM_RESET, NULL); ++} ++ + #ifdef KVM_HAVE_MCE_INJECTION + static __thread void *pending_sigbus_addr; + static __thread int pending_sigbus_code; +diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h +index ca40add32c..27b9d0d9db 100644 +--- a/accel/kvm/kvm-cpus.h ++++ b/accel/kvm/kvm-cpus.h +@@ -23,4 +23,7 @@ int kvm_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len); + int kvm_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len); + void kvm_remove_all_breakpoints(CPUState *cpu); + ++void kvm_cpus_control_pre_system_reset(void); ++void kvm_cpus_control_post_system_reset(void); ++ + #endif /* KVM_CPUS_H */ +diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h +index ef91fc28bb..7a32e7f820 100644 +--- a/include/sysemu/accel-ops.h ++++ b/include/sysemu/accel-ops.h +@@ -53,6 +53,9 @@ struct AccelOpsClass { + int (*insert_breakpoint)(CPUState *cpu, int type, vaddr addr, vaddr len); + int (*remove_breakpoint)(CPUState *cpu, int type, vaddr addr, vaddr len); + void (*remove_all_breakpoints)(CPUState *cpu); ++ ++ void (*control_pre_system_reset)(void); ++ void (*control_post_system_reset)(void); + }; + + #endif /* ACCEL_OPS_H */ +diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h +index b4a566cfe7..f24d27daf5 100644 +--- a/include/sysemu/cpus.h ++++ b/include/sysemu/cpus.h +@@ -44,6 +44,8 @@ extern int icount_align_option; + void qemu_cpu_kick_self(void); + + bool cpus_are_resettable(void); ++void cpus_control_pre_system_reset(void); ++void cpus_control_post_system_reset(void); + + void cpu_synchronize_all_states(void); + void cpu_synchronize_all_post_reset(void); +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index e796105b76..eb30402c2d 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1626,6 +1626,10 @@ struct kvm_master_dev_info + #define KVM_GET_DEVICE_ATTR _IOW(KVMIO, 0xe2, struct kvm_device_attr) + #define KVM_HAS_DEVICE_ATTR _IOW(KVMIO, 0xe3, struct kvm_device_attr) + ++/* ioctls for control vcpu setup during system reset */ ++#define KVM_CONTROL_VCPU_PRE_SYSTEM_RESET _IO(KVMIO, 0xe8) ++#define KVM_CONTROL_VCPU_POST_SYSTEM_RESET _IO(KVMIO, 0xe9) ++ + /* + * ioctls for vcpu fds + */ +diff --git a/system/cpus.c b/system/cpus.c +index f2289e9545..d9de09b9e8 100644 +--- a/system/cpus.c ++++ b/system/cpus.c +@@ -193,6 +193,20 @@ void cpu_synchronize_pre_loadvm(CPUState *cpu) + } + } + ++void cpus_control_pre_system_reset(void) ++{ ++ if (cpus_accel->control_pre_system_reset) { ++ cpus_accel->control_pre_system_reset(); ++ } ++} ++ ++void cpus_control_post_system_reset(void) ++{ ++ if (cpus_accel->control_post_system_reset) { ++ cpus_accel->control_post_system_reset(); ++ } ++} ++ + bool cpus_are_resettable(void) + { + if (cpus_accel->cpus_are_resettable) { +diff --git a/system/runstate.c b/system/runstate.c +index 538c645326..7e41626bb1 100644 +--- a/system/runstate.c ++++ b/system/runstate.c +@@ -487,6 +487,8 @@ void qemu_system_reset(ShutdownCause reason) + + mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; + ++ cpus_control_pre_system_reset(); ++ + cpu_synchronize_all_states(); + + if (mc && mc->reset) { +@@ -503,6 +505,9 @@ void qemu_system_reset(ShutdownCause reason) + qapi_event_send_reset(shutdown_caused_by_guest(reason), reason); + } + cpu_synchronize_all_post_reset(); ++ ++ cpus_control_post_system_reset(); ++ + monitor_qapi_event_discard_io_error(); + } + +-- +2.41.0.windows.1 + diff --git a/kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch b/kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch new file mode 100644 index 0000000000000000000000000000000000000000..e3b9f45950cee097849d1122d1c536d37cd072a8 --- /dev/null +++ b/kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch @@ -0,0 +1,315 @@ +From 02e6bfc88ce5e944ce36b8ccb7d2af103a969980 Mon Sep 17 00:00:00 2001 +From: Ashish Kalra +Date: Tue, 27 Jul 2021 15:05:49 +0000 +Subject: [PATCH] kvm: Add support for SEV shared regions list and + KVM_EXIT_HYPERCALL. + +cherry-picked from https://github.com/AMDESE/qemu/commit/fcbbd9b19ac. + +KVM_HC_MAP_GPA_RANGE hypercall is used by the SEV guest to notify a +change in the page encryption status to the hypervisor. The hypercall +should be invoked only when the encryption attribute is changed from +encrypted -> decrypted and vice versa. By default all guest pages are +considered encrypted. + +The hypercall exits to userspace with KVM_EXIT_HYPERCALL exit code, +currently this is used only by SEV guests for guest page encryptiion +status tracking. Add support to handle this exit and invoke SEV +shared regions list handlers. + +Add support for SEV guest shared regions and implementation of the +SEV shared regions list. + +Signed-off-by: Ashish Kalra +[ Fix conflicts. ] +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 3 ++ + target/i386/kvm/kvm.c | 48 +++++++++++++++++ + target/i386/kvm/sev-stub.c | 11 ++++ + target/i386/sev.c | 106 +++++++++++++++++++++++++++++++++++++ + target/i386/sev.h | 3 ++ + 5 files changed, 171 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 8d12435e41..9489a20835 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -348,6 +348,7 @@ struct kvm_run { + } iocsr_io; + /* KVM_EXIT_HYPERCALL */ + struct { ++#define KVM_HC_MAP_GPA_RANGE 12 + __u64 nr; + __u64 args[6]; + __u64 ret; +@@ -1204,6 +1205,8 @@ struct kvm_ppc_resize_hpt { + + #define KVM_CAP_ARM_VIRT_MSI_BYPASS 799 + ++#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) ++ + #ifdef KVM_CAP_IRQ_ROUTING + + struct kvm_irq_routing_irqchip { +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index a0bc9ea7b1..82f6d3b048 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -148,6 +148,7 @@ static int has_xcrs; + static int has_sregs2; + static int has_exception_payload; + static int has_triple_fault_event; ++static int has_map_gpa_range; + + static bool has_msr_mcg_ext_ctl; + +@@ -2191,6 +2192,17 @@ int kvm_arch_init_vcpu(CPUState *cs) + c->eax = MAX(c->eax, KVM_CPUID_SIGNATURE | 0x10); + } + ++ if (sev_enabled()) { ++ c = cpuid_find_entry(&cpuid_data.cpuid, ++ KVM_CPUID_FEATURES | kvm_base, 0); ++ if (c) { ++ c->eax |= (1 << KVM_FEATURE_MIGRATION_CONTROL); ++ if (has_map_gpa_range) { ++ c->eax |= (1 << KVM_FEATURE_HC_MAP_GPA_RANGE); ++ } ++ } ++ } ++ + cpuid_data.cpuid.nent = cpuid_i; + + cpuid_data.cpuid.padding = 0; +@@ -2584,6 +2596,17 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + #endif + } + ++ has_map_gpa_range = kvm_check_extension(s, KVM_CAP_EXIT_HYPERCALL); ++ if (has_map_gpa_range) { ++ ret = kvm_vm_enable_cap(s, KVM_CAP_EXIT_HYPERCALL, 0, ++ KVM_EXIT_HYPERCALL_VALID_MASK); ++ if (ret < 0) { ++ error_report("kvm: Failed to enable MAP_GPA_RANGE cap: %s", ++ strerror(-ret)); ++ return ret; ++ } ++ } ++ + ret = kvm_get_supported_msrs(s); + if (ret < 0) { + return ret; +@@ -4936,6 +4959,28 @@ static int kvm_handle_tpr_access(X86CPU *cpu) + return 1; + } + ++static int kvm_handle_exit_hypercall(X86CPU *cpu, struct kvm_run *run) ++{ ++ /* ++ * Currently this exit is only used by SEV guests for ++ * guest page encryption status tracking. ++ */ ++ if (run->hypercall.nr == KVM_HC_MAP_GPA_RANGE) { ++ unsigned long enc = run->hypercall.args[2]; ++ unsigned long gpa = run->hypercall.args[0]; ++ unsigned long npages = run->hypercall.args[1]; ++ unsigned long gfn_start = gpa >> TARGET_PAGE_BITS; ++ unsigned long gfn_end = gfn_start + npages; ++ ++ if (enc) { ++ sev_remove_shared_regions_list(gfn_start, gfn_end); ++ } else { ++ sev_add_shared_regions_list(gfn_start, gfn_end); ++ } ++ } ++ return 0; ++} ++ + int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) + { + static const uint8_t int3 = 0xcc; +@@ -5359,6 +5404,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + ret = kvm_xen_handle_exit(cpu, &run->xen); + break; + #endif ++ case KVM_EXIT_HYPERCALL: ++ ret = kvm_handle_exit_hypercall(cpu, run); ++ break; + default: + fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); + ret = -1; +diff --git a/target/i386/kvm/sev-stub.c b/target/i386/kvm/sev-stub.c +index 1be5341e8a..1282d242a7 100644 +--- a/target/i386/kvm/sev-stub.c ++++ b/target/i386/kvm/sev-stub.c +@@ -19,3 +19,14 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + /* If we get here, cgs must be some non-SEV thing */ + return 0; + } ++ ++int sev_remove_shared_regions_list(unsigned long gfn_start, ++ unsigned long gfn_end) ++{ ++ return 0; ++} ++ ++int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end) ++{ ++ return 0; ++} +diff --git a/target/i386/sev.c b/target/i386/sev.c +index de1a4b271e..8525a7351f 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -44,6 +44,11 @@ + #define TYPE_SEV_GUEST "sev-guest" + OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST) + ++struct shared_region { ++ unsigned long gfn_start, gfn_end; ++ QTAILQ_ENTRY(shared_region) list; ++}; ++ + + /** + * SevGuestState: +@@ -87,6 +92,8 @@ struct SevGuestState { + uint32_t reset_cs; + uint32_t reset_ip; + bool reset_data_valid; ++ ++ QTAILQ_HEAD(, shared_region) shared_regions_list; + }; + + #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ +@@ -1136,6 +1143,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + migration_add_notifier(&sev_migration_state, sev_migration_state_notifier); + + cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; ++ QTAILQ_INIT(&sev->shared_regions_list); + + cgs->ready = true; + +@@ -1671,6 +1679,104 @@ int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) + return sev_receive_update_data(f, ptr); + } + ++int sev_remove_shared_regions_list(unsigned long start, unsigned long end) ++{ ++ SevGuestState *s = sev_guest; ++ struct shared_region *pos; ++ ++ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { ++ unsigned long l, r; ++ unsigned long curr_gfn_end = pos->gfn_end; ++ ++ /* ++ * Find if any intersection exists ? ++ * left bound for intersecting segment ++ */ ++ l = MAX(start, pos->gfn_start); ++ /* right bound for intersecting segment */ ++ r = MIN(end, pos->gfn_end); ++ if (l <= r) { ++ if (pos->gfn_start == l && pos->gfn_end == r) { ++ QTAILQ_REMOVE(&s->shared_regions_list, pos, list); ++ } else if (l == pos->gfn_start) { ++ pos->gfn_start = r; ++ } else if (r == pos->gfn_end) { ++ pos->gfn_end = l; ++ } else { ++ /* Do a de-merge -- split linked list nodes */ ++ struct shared_region *shrd_region; ++ ++ pos->gfn_end = l; ++ shrd_region = g_malloc0(sizeof(*shrd_region)); ++ if (!shrd_region) { ++ return 0; ++ } ++ shrd_region->gfn_start = r; ++ shrd_region->gfn_end = curr_gfn_end; ++ QTAILQ_INSERT_AFTER(&s->shared_regions_list, pos, ++ shrd_region, list); ++ } ++ } ++ if (end <= curr_gfn_end) { ++ break; ++ } ++ } ++ return 0; ++} ++ ++int sev_add_shared_regions_list(unsigned long start, unsigned long end) ++{ ++ struct shared_region *shrd_region; ++ struct shared_region *pos; ++ SevGuestState *s = sev_guest; ++ ++ if (QTAILQ_EMPTY(&s->shared_regions_list)) { ++ shrd_region = g_malloc0(sizeof(*shrd_region)); ++ if (!shrd_region) { ++ return -1; ++ } ++ shrd_region->gfn_start = start; ++ shrd_region->gfn_end = end; ++ QTAILQ_INSERT_TAIL(&s->shared_regions_list, shrd_region, list); ++ return 0; ++ } ++ ++ /* ++ * shared regions list is a sorted list in ascending order ++ * of guest PA's and also merges consecutive range of guest PA's ++ */ ++ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { ++ /* handle duplicate overlapping regions */ ++ if (start >= pos->gfn_start && end <= pos->gfn_end) { ++ return 0; ++ } ++ if (pos->gfn_end < start) { ++ continue; ++ } ++ /* merge consecutive guest PA(s) -- forward merge */ ++ if (pos->gfn_start <= start && pos->gfn_end >= start) { ++ pos->gfn_end = end; ++ return 0; ++ } ++ break; ++ } ++ /* ++ * Add a new node ++ */ ++ shrd_region = g_malloc0(sizeof(*shrd_region)); ++ if (!shrd_region) { ++ return -1; ++ } ++ shrd_region->gfn_start = start; ++ shrd_region->gfn_end = end; ++ if (pos) { ++ QTAILQ_INSERT_BEFORE(pos, shrd_region, list); ++ } else { ++ QTAILQ_INSERT_TAIL(&s->shared_regions_list, shrd_region, list); ++ } ++ return 1; ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +diff --git a/target/i386/sev.h b/target/i386/sev.h +index d94da2956b..acf69d4e6f 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -61,6 +61,9 @@ int sev_inject_launch_secret(const char *hdr, const char *secret, + + int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size); + void sev_es_set_reset_vector(CPUState *cpu); ++int sev_remove_shared_regions_list(unsigned long gfn_start, ++ unsigned long gfn_end); ++int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); + + int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); + +-- +2.41.0.windows.1 + diff --git a/kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch b/kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch new file mode 100644 index 0000000000000000000000000000000000000000..f611f4a9445befdd24290b37cebf856531db88cc --- /dev/null +++ b/kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch @@ -0,0 +1,123 @@ +From 7aced2a5fff91e0fcff97bb5eafddafece0cb983 Mon Sep 17 00:00:00 2001 +From: Ashish Kalra +Date: Tue, 27 Jul 2021 17:59:33 +0000 +Subject: [PATCH] kvm: Add support for userspace MSR filtering and handling of + MSR_KVM_MIGRATION_CONTROL. + +cherry-picked from https://github.com/AMDESE/qemu/commit/67935c3fd5f. + +Add support for userspace MSR filtering using KVM_X86_SET_MSR_FILTER +ioctl and handling of MSRs in userspace. Currently this is only used +for SEV guests which use MSR_KVM_MIGRATION_CONTROL to indicate if the +guest is enabled and ready for migration. + +KVM arch code calls into SEV guest specific code to delete the +SEV migrate blocker which has been setup at SEV_LAUNCH_FINISH. + +Signed-off-by: Ashish Kalra +[ Fix conflicts. ] +Signed-off-by: hanliyang +--- + target/i386/kvm/kvm.c | 35 +++++++++++++++++++++++++++++++++++ + target/i386/kvm/sev-stub.c | 4 ++++ + target/i386/sev.c | 6 ++++++ + target/i386/sev.h | 1 + + 4 files changed, 46 insertions(+) + +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 82f6d3b048..a5a755db01 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -2488,6 +2488,32 @@ static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, uint32_t msr, + return true; + } + ++/* ++ * Currently this exit is only used by SEV guests for ++ * MSR_KVM_MIGRATION_CONTROL to indicate if the guest ++ * is ready for migration. ++ */ ++static uint64_t msr_kvm_migration_control; ++ ++static bool kvm_rdmsr_kvm_migration_control(X86CPU *cpu, uint32_t msr, ++ uint64_t *val) ++{ ++ *val = msr_kvm_migration_control; ++ ++ return true; ++} ++ ++static bool kvm_wrmsr_kvm_migration_control(X86CPU *cpu, uint32_t msr, ++ uint64_t val) ++{ ++ msr_kvm_migration_control = val; ++ ++ if (val == KVM_MIGRATION_READY) ++ sev_del_migrate_blocker(); ++ ++ return true; ++} ++ + static Notifier smram_machine_done; + static KVMMemoryListener smram_listener; + static AddressSpace smram_address_space; +@@ -2735,6 +2761,15 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + strerror(-ret)); + exit(1); + } ++ ++ r = kvm_filter_msr(s, MSR_KVM_MIGRATION_CONTROL, ++ kvm_rdmsr_kvm_migration_control, ++ kvm_wrmsr_kvm_migration_control); ++ if (!r) { ++ error_report("Could not install MSR_KVM_MIGRATION_CONTROL handler: %s", ++ strerror(-ret)); ++ exit(1); ++ } + } + + return 0; +diff --git a/target/i386/kvm/sev-stub.c b/target/i386/kvm/sev-stub.c +index 1282d242a7..99899688e4 100644 +--- a/target/i386/kvm/sev-stub.c ++++ b/target/i386/kvm/sev-stub.c +@@ -30,3 +30,7 @@ int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end) + { + return 0; + } ++ ++void sev_del_migrate_blocker(void) ++{ ++} +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 47f41aefe7..98b0d3937a 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -925,6 +925,12 @@ sev_launch_finish(SevGuestState *sev) + migrate_add_blocker(&sev_mig_blocker, &error_fatal); + } + ++void ++sev_del_migrate_blocker(void) ++{ ++ migrate_del_blocker(&sev_mig_blocker); ++} ++ + static int + sev_receive_finish(SevGuestState *s) + { +diff --git a/target/i386/sev.h b/target/i386/sev.h +index b9c2afb799..84e3bdf2df 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -70,6 +70,7 @@ int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); + int sev_save_outgoing_shared_regions_list(QEMUFile *f, uint64_t *bytes_sent); + int sev_load_incoming_shared_regions_list(QEMUFile *f); + bool sev_is_gfn_in_unshared_region(unsigned long gfn); ++void sev_del_migrate_blocker(void); + + int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); + +-- +2.41.0.windows.1 + diff --git a/load_elf-fix-iterator-s-type-for-elf-file-processing.patch b/load_elf-fix-iterator-s-type-for-elf-file-processing.patch new file mode 100644 index 0000000000000000000000000000000000000000..a78b0f1756e1de911b32e35beda4fb450ece46e2 --- /dev/null +++ b/load_elf-fix-iterator-s-type-for-elf-file-processing.patch @@ -0,0 +1,43 @@ +From 2651409cf43002dc497483ae3ae227d4c602ca45 Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 17:02:38 +0800 +Subject: [PATCH] load_elf: fix iterator's type for elf file processing + +cherry picked from commit 410c2a4d75f52f6a2fe978eda5a9b6f854afe5ea + +j is used while loading an ELF file to byteswap segments' +data. If data is larger than 2GB an overflow may happen. +So j should be elf_word. + +This commit fixes a minor bug: it's unlikely anybody is trying to +load ELF files with 2GB+ segments for wrong-endianness targets, +but if they did, it wouldn't work correctly. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Cc: qemu-stable@nongnu.org +Fixes: 7ef295e ("loader: Add data swap option to load-elf") +Signed-off-by: Anastasia Belova +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: Gao Jiazhen +--- + include/hw/elf_ops.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h +index 0a5c258fe6..9c35d1b9da 100644 +--- a/include/hw/elf_ops.h ++++ b/include/hw/elf_ops.h +@@ -500,7 +500,7 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd, + } + + if (data_swab) { +- int j; ++ elf_word j; + for (j = 0; j < file_size; j += (1 << data_swab)) { + uint8_t *dp = data + j; + switch (data_swab) { +-- +2.41.0.windows.1 + diff --git a/migration-add-support-to-migrate-shared-regions-list.patch b/migration-add-support-to-migrate-shared-regions-list.patch new file mode 100644 index 0000000000000000000000000000000000000000..f17b7c560fc7512d9ddf15d8d26d1e60d3d9f27e --- /dev/null +++ b/migration-add-support-to-migrate-shared-regions-list.patch @@ -0,0 +1,120 @@ +From 0f85e3a486c2d0130cb3be322900aa839d77d4bd Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Tue, 27 Jul 2021 16:31:36 +0000 +Subject: [PATCH] migration: add support to migrate shared regions list + +cherry-picked from https://github.com/AMDESE/qemu/commit/9236f522e48b6. + +When memory encryption is enabled, the hypervisor maintains a shared +regions list which is referred by hypervisor during migration to check +if page is private or shared. This list is built during the VM bootup and +must be migrated to the target host so that hypervisor on target host can +use it for future migration. + +Signed-off-by: Brijesh Singh +Co-developed-by: Ashish Kalra +Signed-off-by: Ashish Kalra +[ Fix conflicts. ] +Signed-off-by: hanliyang +--- + include/exec/confidential-guest-support.h | 2 +- + target/i386/sev.c | 45 +++++++++++++++++++++++ + target/i386/sev.h | 2 + + 3 files changed, 48 insertions(+), 1 deletion(-) + +diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h +index 343f686fc2..dd4887f65f 100644 +--- a/include/exec/confidential-guest-support.h ++++ b/include/exec/confidential-guest-support.h +@@ -73,7 +73,7 @@ struct ConfidentialGuestMemoryEncryptionOps { + bool (*is_gfn_in_unshared_region)(unsigned long gfn); + + /* Write the shared regions list */ +- int (*save_outgoing_shared_regions_list)(QEMUFile *f); ++ int (*save_outgoing_shared_regions_list)(QEMUFile *f, uint64_t *bytes_sent); + + /* Load the shared regions list */ + int (*load_incoming_shared_regions_list)(QEMUFile *f); +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 8525a7351f..92aedf0503 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -176,10 +176,15 @@ static const char *const sev_fw_errlist[] = { + + #define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */ + ++#define SHARED_REGION_LIST_CONT 0x1 ++#define SHARED_REGION_LIST_END 0x2 ++ + static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .save_setup = sev_save_setup, + .save_outgoing_page = sev_save_outgoing_page, + .load_incoming_page = sev_load_incoming_page, ++ .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, ++ .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, + }; + + static int +@@ -1777,6 +1782,46 @@ int sev_add_shared_regions_list(unsigned long start, unsigned long end) + return 1; + } + ++int sev_save_outgoing_shared_regions_list(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ SevGuestState *s = sev_guest; ++ struct shared_region *pos; ++ ++ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { ++ qemu_put_be32(f, SHARED_REGION_LIST_CONT); ++ qemu_put_be32(f, pos->gfn_start); ++ qemu_put_be32(f, pos->gfn_end); ++ *bytes_sent += 12; ++ } ++ ++ qemu_put_be32(f, SHARED_REGION_LIST_END); ++ *bytes_sent += 4; ++ return 0; ++} ++ ++int sev_load_incoming_shared_regions_list(QEMUFile *f) ++{ ++ SevGuestState *s = sev_guest; ++ struct shared_region *shrd_region; ++ int status; ++ ++ status = qemu_get_be32(f); ++ while (status == SHARED_REGION_LIST_CONT) { ++ ++ shrd_region = g_malloc0(sizeof(*shrd_region)); ++ if (!shrd_region) { ++ return 0; ++ } ++ shrd_region->gfn_start = qemu_get_be32(f); ++ shrd_region->gfn_end = qemu_get_be32(f); ++ ++ QTAILQ_INSERT_TAIL(&s->shared_regions_list, shrd_region, list); ++ ++ status = qemu_get_be32(f); ++ } ++ return 0; ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +diff --git a/target/i386/sev.h b/target/i386/sev.h +index acf69d4e6f..5b4231c859 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -64,6 +64,8 @@ void sev_es_set_reset_vector(CPUState *cpu); + int sev_remove_shared_regions_list(unsigned long gfn_start, + unsigned long gfn_end); + int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); ++int sev_save_outgoing_shared_regions_list(QEMUFile *f, uint64_t *bytes_sent); ++int sev_load_incoming_shared_regions_list(QEMUFile *f); + + int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); + +-- +2.41.0.windows.1 + diff --git a/migration-colo-Fix-bdrv_graph_rdlock_main_loop-Asser.patch b/migration-colo-Fix-bdrv_graph_rdlock_main_loop-Asser.patch new file mode 100644 index 0000000000000000000000000000000000000000..ae3db8e3cdb7d2db24981590092504f1bfc1a89c --- /dev/null +++ b/migration-colo-Fix-bdrv_graph_rdlock_main_loop-Asser.patch @@ -0,0 +1,87 @@ +From 015fc431353ae348e7e9cef2036b674a4e33eb1c Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 15:04:16 +0800 +Subject: [PATCH] =?UTF-8?q?migration/colo:=20Fix=20bdrv=5Fgraph=5Frdlock?= + =?UTF-8?q?=5Fmain=5Floop:=20Assertion=20`!qemu=5Fin=5F=E2=80=A6?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 2cc637f1ea08d2a1b19fc5b1a30bc609f948de93 + +…coroutine()' failed. + +bdrv_activate_all() should not be called from the coroutine context, move +it to the QEMU thread colo_process_incoming_thread() with the bql_lock +protected. + +The backtrace is as follows: + #4 0x0000561af7948362 in bdrv_graph_rdlock_main_loop () at ../block/graph-lock.c:260 + #5 0x0000561af7907a68 in graph_lockable_auto_lock_mainloop (x=0x7fd29810be7b) at /patch/to/qemu/include/block/graph-lock.h:259 + #6 0x0000561af79167d1 in bdrv_activate_all (errp=0x7fd29810bed0) at ../block.c:6906 + #7 0x0000561af762b4af in colo_incoming_co () at ../migration/colo.c:935 + #8 0x0000561af7607e57 in process_incoming_migration_co (opaque=0x0) at ../migration/migration.c:793 + #9 0x0000561af7adbeeb in coroutine_trampoline (i0=-106876144, i1=22042) at ../util/coroutine-ucontext.c:175 + #10 0x00007fd2a5cf21c0 in () at /lib64/libc.so.6 + +Cc: qemu-stable@nongnu.org +Cc: Fabiano Rosas +Closes: https://gitlab.com/qemu-project/qemu/-/issues/2277 +Fixes: 2b3912f ("block: Mark bdrv_first_blk() and bdrv_is_root_node() GRAPH_RDLOCK") +Signed-off-by: Li Zhijian +Reviewed-by: Zhang Chen +Tested-by: Zhang Chen +Reviewed-by: Fabiano Rosas +Link: https://lore.kernel.org/r/20240417025634.1014582-1-lizhijian@fujitsu.com +Signed-off-by: Peter Xu +Signed-off-by: Gao Jiazhen +--- + migration/colo.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/migration/colo.c b/migration/colo.c +index 4447e34914..8f301b7e57 100644 +--- a/migration/colo.c ++++ b/migration/colo.c +@@ -830,6 +830,16 @@ static void *colo_process_incoming_thread(void *opaque) + return NULL; + } + ++ /* Make sure all file formats throw away their mutable metadata */ ++ qemu_mutex_lock_iothread(); ++ bdrv_activate_all(&local_err); ++ if (local_err) { ++ qemu_mutex_unlock_iothread(); ++ error_report_err(local_err); ++ return NULL; ++ } ++ qemu_mutex_unlock_iothread(); ++ + failover_init_state(); + + mis->to_src_file = qemu_file_get_return_path(mis->from_src_file); +@@ -917,7 +927,6 @@ out: + int coroutine_fn colo_incoming_co(void) + { + MigrationIncomingState *mis = migration_incoming_get_current(); +- Error *local_err = NULL; + QemuThread th; + + assert(qemu_mutex_iothread_locked()); +@@ -926,13 +935,6 @@ int coroutine_fn colo_incoming_co(void) + return 0; + } + +- /* Make sure all file formats throw away their mutable metadata */ +- bdrv_activate_all(&local_err); +- if (local_err) { +- error_report_err(local_err); +- return -EINVAL; +- } +- + qemu_thread_create(&th, "COLO incoming", colo_process_incoming_thread, + mis, QEMU_THREAD_JOINABLE); + +-- +2.41.0.windows.1 + diff --git a/migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch b/migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch new file mode 100644 index 0000000000000000000000000000000000000000..c915c3e3a0b946c92f5ed88bb42d2d7686c06982 --- /dev/null +++ b/migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch @@ -0,0 +1,37 @@ +From eac3cab8dcd005b33365b5196801268d696a11bc Mon Sep 17 00:00:00 2001 +From: fangbaoshun +Date: Mon, 2 Aug 2021 14:49:45 +0800 +Subject: [PATCH] migration/ram: Accelerate the loading of CSV guest's + encrypted pages + +When memory encryption is enabled, the guest memory will be encrypted with +the guest specific key. The patch introduces an accelerate solution which +queued the pages into list and load them togather by COMMAND_BATCH. + +Signed-off-by: hanliyang +--- + migration/ram.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 7747f5af3a..790c0413c1 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1297,6 +1297,14 @@ static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) + return ops->load_incoming_page(f, ptr); + } else if (flag == RAM_SAVE_SHARED_REGIONS_LIST) { + return ops->load_incoming_shared_regions_list(f); ++ } else if (flag == RAM_SAVE_ENCRYPTED_PAGE_BATCH) { ++ return ops->queue_incoming_page(f, ptr); ++ } else if (flag == RAM_SAVE_ENCRYPTED_PAGE_BATCH_END) { ++ if (ops->queue_incoming_page(f, ptr)) { ++ error_report("Failed to queue incoming data"); ++ return -EINVAL; ++ } ++ return ops->load_queued_incoming_pages(f); + } else { + error_report("unknown encrypted flag %x", flag); + return 1; +-- +2.41.0.windows.1 + diff --git a/migration-ram-Accelerate-the-transmission-of-CSV-gue.patch b/migration-ram-Accelerate-the-transmission-of-CSV-gue.patch new file mode 100644 index 0000000000000000000000000000000000000000..75773d3edd19dc1da9f3a54601a04a89ce6054ae --- /dev/null +++ b/migration-ram-Accelerate-the-transmission-of-CSV-gue.patch @@ -0,0 +1,208 @@ +From e2b3943bf75d34f5e913e05fbdf8116179812866 Mon Sep 17 00:00:00 2001 +From: fangbaoshun +Date: Mon, 2 Aug 2021 14:35:51 +0800 +Subject: [PATCH] migration/ram: Accelerate the transmission of CSV guest's + encrypted pages + +When memory encryption is enabled, the guest memory will be encrypted with +the guest specific key. The patch introduces an accelerate solution which +queued the pages into list and send them togather by COMMAND_BATCH. + +Signed-off-by: hanliyang +--- + configs/devices/i386-softmmu/default.mak | 1 + + hw/i386/Kconfig | 5 + + migration/ram.c | 119 +++++++++++++++++++++++ + target/i386/csv.h | 2 + + 4 files changed, 127 insertions(+) + +diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak +index db83ffcab9..e948e54e4e 100644 +--- a/configs/devices/i386-softmmu/default.mak ++++ b/configs/devices/i386-softmmu/default.mak +@@ -24,6 +24,7 @@ + #CONFIG_VTD=n + #CONFIG_SGX=n + #CONFIG_CSV=n ++#CONFIG_HYGON_CSV_MIG_ACCEL=n + + # Boards: + # +diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig +index 08f3ae43f8..682e324f1c 100644 +--- a/hw/i386/Kconfig ++++ b/hw/i386/Kconfig +@@ -12,8 +12,13 @@ config SGX + + config CSV + bool ++ select HYGON_CSV_MIG_ACCEL + depends on SEV + ++config HYGON_CSV_MIG_ACCEL ++ bool ++ depends on CSV ++ + config PC + bool + imply APPLESMC +diff --git a/migration/ram.c b/migration/ram.c +index 1abe8476f7..7747f5af3a 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -67,6 +67,7 @@ + + /* Defines RAM_SAVE_ENCRYPTED_PAGE and RAM_SAVE_SHARED_REGION_LIST */ + #include "target/i386/sev.h" ++#include "target/i386/csv.h" + #include "sysemu/kvm.h" + + #include "hw/boards.h" /* for machine_dump_guest_core() */ +@@ -2336,6 +2337,112 @@ out: + return ret; + } + ++#ifdef CONFIG_HYGON_CSV_MIG_ACCEL ++/** ++ * ram_save_encrypted_pages_in_batch: send the given encrypted pages to ++ * the stream. ++ * ++ * Sending pages of 4K size in batch. The saving stops at the end of ++ * the block. ++ * ++ * The caller must be with ram_state.bitmap_mutex held to call this ++ * function. ++ * ++ * Returns the number of pages written or negative on error ++ * ++ * @rs: current RAM state ++ * @pss: data about the page we want to send ++ */ ++static int ++ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss) ++{ ++ bool page_dirty; ++ int ret; ++ int tmppages, pages = 0; ++ uint8_t *p; ++ uint32_t host_len = 0; ++ uint64_t bytes_xmit = 0; ++ ram_addr_t offset, start_offset = 0; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *)object_get_class(OBJECT(ms->cgs)); ++ struct ConfidentialGuestMemoryEncryptionOps *ops = ++ cgs_class->memory_encryption_ops; ++ ++ do { ++ page_dirty = migration_bitmap_clear_dirty(rs, pss->block, pss->page); ++ ++ /* Check the pages is dirty and if it is send it */ ++ if (page_dirty) { ++ /* Process the unencrypted page */ ++ if (!encrypted_test_list(rs, pss->block, pss->page)) { ++ tmppages = migration_ops->ram_save_target_page(rs, pss); ++ } else { ++ /* Caculate the offset and host virtual address of the page */ ++ offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS; ++ p = pss->block->host + offset; ++ ++ /* Record the offset and host virtual address of the first ++ * page in this loop which will be used below. ++ */ ++ if (host_len == 0) { ++ start_offset = offset | RAM_SAVE_FLAG_ENCRYPTED_DATA; ++ } else { ++ offset |= (RAM_SAVE_FLAG_ENCRYPTED_DATA | RAM_SAVE_FLAG_CONTINUE); ++ } ++ ++ /* Queue the outgoing page if the page is not zero page. ++ * If the queued pages are up to the outgoing page window size, ++ * process them below. ++ */ ++ if (ops->queue_outgoing_page(p, TARGET_PAGE_SIZE, offset)) ++ return -1; ++ ++ tmppages = 1; ++ host_len += TARGET_PAGE_SIZE; ++ ++ stat64_add(&mig_stats.normal_pages, 1); ++ } ++ } else { ++ tmppages = 0; ++ } ++ ++ if (tmppages >= 0) { ++ pages += tmppages; ++ } else { ++ return tmppages; ++ } ++ ++ pss_find_next_dirty(pss); ++ } while (offset_in_ramblock(pss->block, ++ ((ram_addr_t)pss->page) << TARGET_PAGE_BITS) && ++ host_len < CSV_OUTGOING_PAGE_WINDOW_SIZE); ++ ++ /* Check if there are any queued pages */ ++ if (host_len != 0) { ++ ram_transferred_add(save_page_header(pss, pss->pss_channel, ++ pss->block, start_offset)); ++ /* if only one page queued, flag is BATCH_END, else flag is BATCH */ ++ if (host_len > TARGET_PAGE_SIZE) ++ qemu_put_be32(pss->pss_channel, RAM_SAVE_ENCRYPTED_PAGE_BATCH); ++ else ++ qemu_put_be32(pss->pss_channel, RAM_SAVE_ENCRYPTED_PAGE_BATCH_END); ++ ram_transferred_add(4); ++ /* Process the queued pages in batch */ ++ ret = ops->save_queued_outgoing_pages(pss->pss_channel, &bytes_xmit); ++ if (ret) { ++ return -1; ++ } ++ ram_transferred_add(bytes_xmit); ++ } ++ ++ /* The offset we leave with is the last one we looked at */ ++ pss->page--; ++ ++ return pages; ++} ++#endif ++ + /** + * ram_save_host_page: save a whole host page + * +@@ -2371,6 +2478,18 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) + return 0; + } + ++#ifdef CONFIG_HYGON_CSV_MIG_ACCEL ++ /* ++ * If command_batch function is enabled and memory encryption is enabled ++ * then use command batch APIs to accelerate the sending process ++ * to write the outgoing buffer to the wire. The encryption APIs ++ * will re-encrypt the data with transport key so that data is prototect ++ * on the wire. ++ */ ++ if (memcrypt_enabled() && is_hygon_cpu() && !migration_in_postcopy()) ++ return ram_save_encrypted_pages_in_batch(rs, pss); ++#endif ++ + /* Update host page boundary information */ + pss_host_page_prepare(pss); + +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 977f08b982..74a54f9b9c 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -44,6 +44,8 @@ static bool __attribute__((unused)) is_hygon_cpu(void) + + #endif + ++#define CSV_OUTGOING_PAGE_WINDOW_SIZE (4094 * TARGET_PAGE_SIZE) ++ + typedef struct CsvBatchCmdList CsvBatchCmdList; + typedef void (*CsvDestroyCmdNodeFn) (void *data); + +-- +2.41.0.windows.1 + diff --git a/migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch b/migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch new file mode 100644 index 0000000000000000000000000000000000000000..811959046f00fd84e2eb1882341b5ecdb94ea290 --- /dev/null +++ b/migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch @@ -0,0 +1,57 @@ +From ec2518709b8d461c3a165c1722ccd2e585cec161 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Sun, 16 Jan 2022 20:05:02 -0500 +Subject: [PATCH] migration/ram: Fix calculation of gfn correpond to a page in + ramblock + +A RAMBlock contains a host memory region which may consist of many +discontiguous MemoryRegion in AddressSpace of a Guest, so we cannot +get gpa by MemoryRegion.addr. Since KVM memslot records the relationship +between gpa and hva, so we can pass the hva of page in RAMBlock to +kvm_phisical_memory_addr_from_host() to get the expected gpa. + +Signed-off-by: hanliyang +--- + migration/ram.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 66a36736ad..1abe8476f7 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -67,6 +67,7 @@ + + /* Defines RAM_SAVE_ENCRYPTED_PAGE and RAM_SAVE_SHARED_REGION_LIST */ + #include "target/i386/sev.h" ++#include "sysemu/kvm.h" + + #include "hw/boards.h" /* for machine_dump_guest_core() */ + +@@ -2145,6 +2146,8 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, + struct ConfidentialGuestMemoryEncryptionOps *ops = + cgs_class->memory_encryption_ops; + unsigned long gfn; ++ hwaddr paddr = 0; ++ int ret; + + /* ROM devices contains the unencrypted data */ + if (memory_region_is_rom(block->mr)) { +@@ -2167,7 +2170,14 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, + * Translate page in ram_addr_t address space to GPA address + * space using memory region. + */ +- gfn = page + (block->mr->addr >> TARGET_PAGE_BITS); ++ if (kvm_enabled()) { ++ ret = kvm_physical_memory_addr_from_host(kvm_state, ++ block->host + (page << TARGET_PAGE_BITS), &paddr); ++ if (ret == 0) { ++ return false; ++ } ++ } ++ gfn = paddr >> TARGET_PAGE_BITS; + + return ops->is_gfn_in_unshared_region(gfn); + } +-- +2.41.0.windows.1 + diff --git a/migration-ram-Force-encrypted-status-for-VGA-vram.patch b/migration-ram-Force-encrypted-status-for-VGA-vram.patch new file mode 100644 index 0000000000000000000000000000000000000000..e33e8dfb7aa7e274818c378150f1bed1b0fc4a95 --- /dev/null +++ b/migration-ram-Force-encrypted-status-for-VGA-vram.patch @@ -0,0 +1,32 @@ +From e6a20047ca9f61d7fc544e4f0b9b26aa268ccda7 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Tue, 8 Dec 2020 22:57:46 -0500 +Subject: [PATCH] migration/ram: Force encrypted status for VGA vram + +The VGA vram memory region act as frame buffer of VM. This memory +is decrypted in the QEMU process. For CSV VM live migration, we +should avoid memory encryption status check on VGA vram. + +Signed-off-by: hanliyang +--- + migration/ram.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 9ecd8580c5..66a36736ad 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -2159,6 +2159,10 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, + return false; + } + ++ if (!strcmp(memory_region_name(block->mr), "vga.vram")) { ++ return false; ++ } ++ + /* + * Translate page in ram_addr_t address space to GPA address + * space using memory region. +-- +2.41.0.windows.1 + diff --git a/migration-ram-Force-encrypted-status-for-flash0-flas.patch b/migration-ram-Force-encrypted-status-for-flash0-flas.patch new file mode 100644 index 0000000000000000000000000000000000000000..d8bd6dff718f2bf3214009d34151b5f57d88c487 --- /dev/null +++ b/migration-ram-Force-encrypted-status-for-flash0-flas.patch @@ -0,0 +1,44 @@ +From cbbac2aa57d5609c254f99bf247d16e4b9fd7de3 Mon Sep 17 00:00:00 2001 +From: Ashish Kalra +Date: Tue, 27 Jul 2021 18:05:25 +0000 +Subject: [PATCH] migration/ram: Force encrypted status for flash0 & flash1 + devices. + +cherry-picked from https://github.com/AMDESE/qemu/commit/803d6a4c8d. + +Currently OVMF clears the C-bit and marks NonExistent memory space +as decrypted in the page encryption bitmap. By marking the +NonExistent memory space as decrypted it gurantees any future MMIO adds +will work correctly, but this marks flash0 device space as decrypted. +At reset the SEV core will be in forced encrypted state, so this +decrypted marking of flash0 device space will cause VCPU reset to fail +as flash0 device pages will be migrated incorrectly. + +Signed-off-by: Ashish Kalra +Signed-off-by: hanliyang +--- + migration/ram.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index beac7ea2c0..9ecd8580c5 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -2151,6 +2151,14 @@ static bool encrypted_test_list(RAMState *rs, RAMBlock *block, + return false; + } + ++ if (!strcmp(memory_region_name(block->mr), "system.flash0")) { ++ return true; ++ } ++ ++ if (!strcmp(memory_region_name(block->mr), "system.flash1")) { ++ return false; ++ } ++ + /* + * Translate page in ram_addr_t address space to GPA address + * space using memory region. +-- +2.41.0.windows.1 + diff --git a/migration-ram-add-support-to-send-encrypted-pages.patch b/migration-ram-add-support-to-send-encrypted-pages.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef5fa89f3b86e41bb77c1de9794cac42acd965b9 --- /dev/null +++ b/migration-ram-add-support-to-send-encrypted-pages.patch @@ -0,0 +1,343 @@ +From af3077a2f19f0604c4e7f8b94eb0338b7f1f85d6 Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Tue, 27 Jul 2021 16:53:19 +0000 +Subject: [PATCH] migration/ram: add support to send encrypted pages + +cherry-picked from https://github.com/AMDESE/qemu/commit/2d6bda0d4cf. + +When memory encryption is enabled, the guest memory will be encrypted with +the guest specific key. The patch introduces RAM_SAVE_FLAG_ENCRYPTED_PAGE +flag to distinguish the encrypted data from plaintext. Encrypted pages +may need special handling. The sev_save_outgoing_page() is used +by the sender to write the encrypted pages onto the socket, similarly the +sev_load_incoming_page() is used by the target to read the +encrypted pages from the socket and load into the guest memory. + +Signed-off-by: Brijesh Singh +Co-developed-by: Ashish Kalra +Signed-off-by: Ashish Kalra +[ Fix conflicts. ] +Signed-off-by: hanliyang +--- + migration/migration.h | 2 + + migration/ram.c | 174 +++++++++++++++++++++++++++++++++++++++++- + target/i386/sev.c | 14 ++++ + target/i386/sev.h | 4 + + 4 files changed, 192 insertions(+), 2 deletions(-) + +diff --git a/migration/migration.h b/migration/migration.h +index 2f26c9509b..eeddb7c0bd 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -553,4 +553,6 @@ int migration_stop_vm(RunState state); + + void migrate_fd_cancel(MigrationState *s); + ++bool memcrypt_enabled(void); ++ + #endif +diff --git a/migration/ram.c b/migration/ram.c +index f9b2b9b985..beac7ea2c0 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -63,6 +63,10 @@ + #include "options.h" + #include "sysemu/dirtylimit.h" + #include "sysemu/kvm.h" ++#include "exec/confidential-guest-support.h" ++ ++/* Defines RAM_SAVE_ENCRYPTED_PAGE and RAM_SAVE_SHARED_REGION_LIST */ ++#include "target/i386/sev.h" + + #include "hw/boards.h" /* for machine_dump_guest_core() */ + +@@ -92,7 +96,16 @@ + /* 0x80 is reserved in rdma.h for RAM_SAVE_FLAG_HOOK */ + #define RAM_SAVE_FLAG_COMPRESS_PAGE 0x100 + #define RAM_SAVE_FLAG_MULTIFD_FLUSH 0x200 +-/* We can't use any flag that is bigger than 0x200 */ ++#define RAM_SAVE_FLAG_ENCRYPTED_DATA 0x400 ++ ++bool memcrypt_enabled(void) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ if(ms->cgs) ++ return ms->cgs->ready; ++ else ++ return false; ++} + + XBZRLECacheStats xbzrle_counters; + +@@ -1206,6 +1219,88 @@ static int save_normal_page(PageSearchStatus *pss, RAMBlock *block, + return 1; + } + ++/** ++ * ram_save_encrypted_page - send the given encrypted page to the stream ++ */ ++static int ram_save_encrypted_page(RAMState *rs, PageSearchStatus *pss) ++{ ++ QEMUFile *file = pss->pss_channel; ++ int ret; ++ uint8_t *p; ++ RAMBlock *block = pss->block; ++ ram_addr_t offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS; ++ uint64_t bytes_xmit = 0; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); ++ struct ConfidentialGuestMemoryEncryptionOps *ops = ++ cgs_class->memory_encryption_ops; ++ ++ p = block->host + offset; ++ trace_ram_save_page(block->idstr, (uint64_t)offset, p); ++ ++ ram_transferred_add(save_page_header(pss, file, block, ++ offset | RAM_SAVE_FLAG_ENCRYPTED_DATA)); ++ qemu_put_be32(file, RAM_SAVE_ENCRYPTED_PAGE); ++ ret = ops->save_outgoing_page(file, p, TARGET_PAGE_SIZE, &bytes_xmit); ++ if (ret) { ++ return -1; ++ } ++ ram_transferred_add(4 + bytes_xmit); ++ stat64_add(&mig_stats.normal_pages, 1); ++ ++ return 1; ++} ++ ++/** ++ * ram_save_shared_region_list: send the shared region list ++ */ ++static int ram_save_shared_region_list(RAMState *rs, QEMUFile *f) ++{ ++ int ret; ++ uint64_t bytes_xmit = 0; ++ PageSearchStatus *pss = &rs->pss[RAM_CHANNEL_PRECOPY]; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); ++ struct ConfidentialGuestMemoryEncryptionOps *ops = ++ cgs_class->memory_encryption_ops; ++ ++ ram_transferred_add(save_page_header(pss, f, ++ pss->last_sent_block, ++ RAM_SAVE_FLAG_ENCRYPTED_DATA)); ++ qemu_put_be32(f, RAM_SAVE_SHARED_REGIONS_LIST); ++ ret = ops->save_outgoing_shared_regions_list(f, &bytes_xmit); ++ if (ret < 0) { ++ return ret; ++ } ++ ram_transferred_add(4 + bytes_xmit); ++ ++ return 0; ++} ++ ++static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); ++ struct ConfidentialGuestMemoryEncryptionOps *ops = ++ cgs_class->memory_encryption_ops; ++ ++ int flag; ++ ++ flag = qemu_get_be32(f); ++ ++ if (flag == RAM_SAVE_ENCRYPTED_PAGE) { ++ return ops->load_incoming_page(f, ptr); ++ } else if (flag == RAM_SAVE_SHARED_REGIONS_LIST) { ++ return ops->load_incoming_shared_regions_list(f); ++ } else { ++ error_report("unknown encrypted flag %x", flag); ++ return 1; ++ } ++} ++ + /** + * ram_save_page: send the given page to the stream + * +@@ -2036,6 +2131,35 @@ static bool save_compress_page(RAMState *rs, PageSearchStatus *pss, + compress_send_queued_data); + } + ++/** ++ * encrypted_test_list: check if the page is encrypted ++ * ++ * Returns a bool indicating whether the page is encrypted. ++ */ ++static bool encrypted_test_list(RAMState *rs, RAMBlock *block, ++ unsigned long page) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); ++ struct ConfidentialGuestMemoryEncryptionOps *ops = ++ cgs_class->memory_encryption_ops; ++ unsigned long gfn; ++ ++ /* ROM devices contains the unencrypted data */ ++ if (memory_region_is_rom(block->mr)) { ++ return false; ++ } ++ ++ /* ++ * Translate page in ram_addr_t address space to GPA address ++ * space using memory region. ++ */ ++ gfn = page + (block->mr->addr >> TARGET_PAGE_BITS); ++ ++ return ops->is_gfn_in_unshared_region(gfn); ++} ++ + /** + * ram_save_target_page_legacy: save one target page + * +@@ -2054,6 +2178,17 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) + return res; + } + ++ /* ++ * If memory encryption is enabled then use memory encryption APIs ++ * to write the outgoing buffer to the wire. The encryption APIs ++ * will take care of accessing the guest memory and re-encrypt it ++ * for the transport purposes. ++ */ ++ if (memcrypt_enabled() && ++ encrypted_test_list(rs, pss->block, pss->page)) { ++ return ram_save_encrypted_page(rs, pss); ++ } ++ + if (save_compress_page(rs, pss, offset)) { + return 1; + } +@@ -2919,6 +3054,18 @@ void qemu_guest_free_page_hint(void *addr, size_t len) + } + } + ++static int ram_encrypted_save_setup(void) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); ++ struct ConfidentialGuestMemoryEncryptionOps *ops = ++ cgs_class->memory_encryption_ops; ++ MigrationParameters *p = &migrate_get_current()->parameters; ++ ++ return ops->save_setup(p->sev_pdh, p->sev_plat_cert, p->sev_amd_cert); ++} ++ + /* + * Each of ram_save_setup, ram_save_iterate and ram_save_complete has + * long-running RCU critical section. When rcu-reclaims in the code +@@ -2954,6 +3101,13 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + (*rsp)->pss[RAM_CHANNEL_PRECOPY].pss_channel = f; + + WITH_RCU_READ_LOCK_GUARD() { ++ ++ if (memcrypt_enabled()) { ++ if (ram_encrypted_save_setup()) { ++ return -1; ++ } ++ } ++ + qemu_put_be64(f, ram_bytes_total_with_ignored() + | RAM_SAVE_FLAG_MEM_SIZE); + +@@ -3183,6 +3337,15 @@ static int ram_save_complete(QEMUFile *f, void *opaque) + qemu_file_set_error(f, ret); + return ret; + } ++ ++ /* send the shared regions list */ ++ if (memcrypt_enabled()) { ++ ret = ram_save_shared_region_list(rs, f); ++ if (ret < 0) { ++ qemu_file_set_error(f, ret); ++ return ret; ++ } ++ } + } + + ret = multifd_send_sync_main(rs->pss[RAM_CHANNEL_PRECOPY].pss_channel); +@@ -3920,7 +4083,8 @@ static int ram_load_precopy(QEMUFile *f) + } + + if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE | +- RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE)) { ++ RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE | ++ RAM_SAVE_FLAG_ENCRYPTED_DATA)) { + RAMBlock *block = ram_block_from_stream(mis, f, flags, + RAM_CHANNEL_PRECOPY); + +@@ -4013,6 +4177,12 @@ static int ram_load_precopy(QEMUFile *f) + qemu_file_set_error(f, ret); + } + break; ++ case RAM_SAVE_FLAG_ENCRYPTED_DATA: ++ if (load_encrypted_data(f, host)) { ++ error_report("Failed to load encrypted data"); ++ ret = -EINVAL; ++ } ++ break; + default: + error_report("Unknown combination of migration flags: 0x%x", flags); + ret = -EINVAL; +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 92aedf0503..47f41aefe7 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -183,6 +183,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .save_setup = sev_save_setup, + .save_outgoing_page = sev_save_outgoing_page, + .load_incoming_page = sev_load_incoming_page, ++ .is_gfn_in_unshared_region = sev_is_gfn_in_unshared_region, + .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, + .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, + }; +@@ -1822,6 +1823,19 @@ int sev_load_incoming_shared_regions_list(QEMUFile *f) + return 0; + } + ++bool sev_is_gfn_in_unshared_region(unsigned long gfn) ++{ ++ SevGuestState *s = sev_guest; ++ struct shared_region *pos; ++ ++ QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { ++ if (gfn >= pos->gfn_start && gfn < pos->gfn_end) { ++ return false; ++ } ++ } ++ return true; ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +diff --git a/target/i386/sev.h b/target/i386/sev.h +index 5b4231c859..b9c2afb799 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -38,6 +38,9 @@ typedef struct SevKernelLoaderContext { + size_t cmdline_size; + } SevKernelLoaderContext; + ++#define RAM_SAVE_ENCRYPTED_PAGE 0x1 ++#define RAM_SAVE_SHARED_REGIONS_LIST 0x2 ++ + #ifdef CONFIG_SEV + bool sev_enabled(void); + bool sev_es_enabled(void); +@@ -66,6 +69,7 @@ int sev_remove_shared_regions_list(unsigned long gfn_start, + int sev_add_shared_regions_list(unsigned long gfn_start, unsigned long gfn_end); + int sev_save_outgoing_shared_regions_list(QEMUFile *f, uint64_t *bytes_sent); + int sev_load_incoming_shared_regions_list(QEMUFile *f); ++bool sev_is_gfn_in_unshared_region(unsigned long gfn); + + int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); + +-- +2.41.0.windows.1 + diff --git a/migration.json-add-AMD-SEV-specific-migration-parame.patch b/migration.json-add-AMD-SEV-specific-migration-parame.patch new file mode 100644 index 0000000000000000000000000000000000000000..bc1d6655b6f51fbe1853ce835e4fa4bddccfb83b --- /dev/null +++ b/migration.json-add-AMD-SEV-specific-migration-parame.patch @@ -0,0 +1,265 @@ +From 5ff59a5649385672da42097b24a2428bc2348d9b Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Tue, 27 Jul 2021 11:27:00 +0000 +Subject: [PATCH] migration.json: add AMD SEV specific migration parameters + +cherry-picked from https://github.com/AMDESE/qemu/commit/d6a23bde6b6e. + +AMD SEV migration flow requires that target machine's public Diffie-Hellman +key (PDH) and certificate chain must be passed before initiating the guest +migration. User can use QMP 'migrate-set-parameters' to pass the certificate +chain. The certificate chain will be used while creating the outgoing +encryption context. + +Signed-off-by: Brijesh Singh +Signed-off-by: Ashish Kalra +[ Fix conflicts and qapi errors. ] +Signed-off-by: hanliyang +--- + migration/migration-hmp-cmds.c | 28 ++++++++++++++++ + migration/options.c | 60 ++++++++++++++++++++++++++++++++++ + qapi/migration.json | 41 +++++++++++++++++++++-- + 3 files changed, 126 insertions(+), 3 deletions(-) + +diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c +index 1fa6a5f478..7ce0446d46 100644 +--- a/migration/migration-hmp-cmds.c ++++ b/migration/migration-hmp-cmds.c +@@ -395,6 +395,19 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) + monitor_printf(mon, "%s: %s\n", + MigrationParameter_str(MIGRATION_PARAMETER_MODE), + qapi_enum_lookup(&MigMode_lookup, params->mode)); ++ ++ assert(params->sev_pdh); ++ monitor_printf(mon, "%s: %s\n", ++ MigrationParameter_str(MIGRATION_PARAMETER_SEV_PDH), ++ params->sev_pdh); ++ assert(params->sev_plat_cert); ++ monitor_printf(mon, "%s: %s\n", ++ MigrationParameter_str(MIGRATION_PARAMETER_SEV_PLAT_CERT), ++ params->sev_plat_cert); ++ assert(params->sev_amd_cert); ++ monitor_printf(mon, "%s: %s\n", ++ MigrationParameter_str(MIGRATION_PARAMETER_SEV_AMD_CERT), ++ params->sev_amd_cert); + } + + qapi_free_MigrationParameters(params); +@@ -691,6 +704,21 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) + p->has_mode = true; + visit_type_MigMode(v, param, &p->mode, &err); + break; ++ case MIGRATION_PARAMETER_SEV_PDH: ++ p->sev_pdh = g_new0(StrOrNull, 1); ++ p->sev_pdh->type = QTYPE_QSTRING; ++ visit_type_str(v, param, &p->sev_pdh->u.s, &err); ++ break; ++ case MIGRATION_PARAMETER_SEV_PLAT_CERT: ++ p->sev_plat_cert = g_new0(StrOrNull, 1); ++ p->sev_plat_cert->type = QTYPE_QSTRING; ++ visit_type_str(v, param, &p->sev_plat_cert->u.s, &err); ++ break; ++ case MIGRATION_PARAMETER_SEV_AMD_CERT: ++ p->sev_amd_cert = g_new0(StrOrNull, 1); ++ p->sev_amd_cert->type = QTYPE_QSTRING; ++ visit_type_str(v, param, &p->sev_amd_cert->u.s, &err); ++ break; + default: + assert(0); + } +diff --git a/migration/options.c b/migration/options.c +index 9b68962a65..71e71ea801 100644 +--- a/migration/options.c ++++ b/migration/options.c +@@ -183,6 +183,9 @@ Property migration_properties[] = { + DEFINE_PROP_MIG_MODE("mode", MigrationState, + parameters.mode, + MIG_MODE_NORMAL), ++ DEFINE_PROP_STRING("sev-pdh", MigrationState, parameters.sev_pdh), ++ DEFINE_PROP_STRING("sev-plat-cert", MigrationState, parameters.sev_plat_cert), ++ DEFINE_PROP_STRING("sev-amd-cert", MigrationState, parameters.sev_amd_cert), + + /* Migration capabilities */ + DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE), +@@ -1012,6 +1015,9 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) + params->announce_rounds = s->parameters.announce_rounds; + params->has_announce_step = true; + params->announce_step = s->parameters.announce_step; ++ params->sev_pdh = g_strdup(s->parameters.sev_pdh); ++ params->sev_plat_cert = g_strdup(s->parameters.sev_plat_cert); ++ params->sev_amd_cert = g_strdup(s->parameters.sev_amd_cert); + + if (s->parameters.has_block_bitmap_mapping) { + params->has_block_bitmap_mapping = true; +@@ -1063,6 +1069,10 @@ void migrate_params_init(MigrationParameters *params) + params->has_x_vcpu_dirty_limit_period = true; + params->has_vcpu_dirty_limit = true; + params->has_mode = true; ++ ++ params->sev_pdh = g_strdup(""); ++ params->sev_plat_cert = g_strdup(""); ++ params->sev_amd_cert = g_strdup(""); + } + + static bool compress_level_check(MigrationParameters *params, Error **errp) +@@ -1392,6 +1402,19 @@ static void migrate_params_test_apply(MigrateSetParameters *params, + if (params->has_mode) { + dest->mode = params->mode; + } ++ ++ if (params->sev_pdh) { ++ assert(params->sev_pdh->type == QTYPE_QSTRING); ++ dest->sev_pdh = params->sev_pdh->u.s; ++ } ++ if (params->sev_plat_cert) { ++ assert(params->sev_plat_cert->type == QTYPE_QSTRING); ++ dest->sev_plat_cert = params->sev_plat_cert->u.s; ++ } ++ if (params->sev_amd_cert) { ++ assert(params->sev_amd_cert->type == QTYPE_QSTRING); ++ dest->sev_amd_cert = params->sev_amd_cert->u.s; ++ } + } + + static void migrate_params_apply(MigrateSetParameters *params, Error **errp) +@@ -1540,6 +1563,22 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) + if (params->has_mode) { + s->parameters.mode = params->mode; + } ++ ++ if (params->sev_pdh) { ++ g_free(s->parameters.sev_pdh); ++ assert(params->sev_pdh->type == QTYPE_QSTRING); ++ s->parameters.sev_pdh = g_strdup(params->sev_pdh->u.s); ++ } ++ if (params->sev_plat_cert) { ++ g_free(s->parameters.sev_plat_cert); ++ assert(params->sev_plat_cert->type == QTYPE_QSTRING); ++ s->parameters.sev_plat_cert = g_strdup(params->sev_plat_cert->u.s); ++ } ++ if (params->sev_amd_cert) { ++ g_free(s->parameters.sev_amd_cert); ++ assert(params->sev_amd_cert->type == QTYPE_QSTRING); ++ s->parameters.sev_amd_cert = g_strdup(params->sev_amd_cert->u.s); ++ } + } + + void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) +@@ -1565,6 +1604,27 @@ void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) + params->tls_authz->type = QTYPE_QSTRING; + params->tls_authz->u.s = strdup(""); + } ++ /* TODO Rewrite "" to null instead */ ++ if (params->sev_pdh ++ && params->sev_pdh->type == QTYPE_QNULL) { ++ qobject_unref(params->sev_pdh->u.n); ++ params->sev_pdh->type = QTYPE_QSTRING; ++ params->sev_pdh->u.s = strdup(""); ++ } ++ /* TODO Rewrite "" to null instead */ ++ if (params->sev_plat_cert ++ && params->sev_plat_cert->type == QTYPE_QNULL) { ++ qobject_unref(params->sev_plat_cert->u.n); ++ params->sev_plat_cert->type = QTYPE_QSTRING; ++ params->sev_plat_cert->u.s = strdup(""); ++ } ++ /* TODO Rewrite "" to null instead */ ++ if (params->sev_amd_cert ++ && params->sev_amd_cert->type == QTYPE_QNULL) { ++ qobject_unref(params->sev_amd_cert->u.n); ++ params->sev_amd_cert->type = QTYPE_QSTRING; ++ params->sev_amd_cert->u.s = strdup(""); ++ } + + migrate_params_test_apply(params, &tmp); + +diff --git a/qapi/migration.json b/qapi/migration.json +index 5d0855a1d8..038e99cba3 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -891,6 +891,15 @@ + # @mode: Migration mode. See description in @MigMode. Default is 'normal'. + # (Since 8.2) + # ++# @sev-pdh: The target host platform diffie-hellman key encoded in base64 ++# (Since 4.2) ++# ++# @sev-plat-cert: The target host platform certificate chain encoded in base64 ++# (Since 4.2) ++# ++# @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in ++# base64 (Since 4.2) ++# + # Features: + # + # @deprecated: Member @block-incremental is deprecated. Use +@@ -925,7 +934,8 @@ + 'block-bitmap-mapping', + { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] }, + 'vcpu-dirty-limit', +- 'mode'] } ++ 'mode', ++ 'sev-pdh', 'sev-plat-cert', 'sev-amd-cert'] } + + ## + # @MigrateSetParameters: +@@ -1083,6 +1093,15 @@ + # @mode: Migration mode. See description in @MigMode. Default is 'normal'. + # (Since 8.2) + # ++# @sev-pdh: The target host platform diffie-hellman key encoded in base64 ++# (Since 4.2) ++# ++# @sev-plat-cert: The target host platform certificate chain encoded in base64 ++# (Since 4.2) ++# ++# @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in ++# base64 (Since 4.2) ++# + # Features: + # + # @deprecated: Member @block-incremental is deprecated. Use +@@ -1139,7 +1158,11 @@ + '*x-vcpu-dirty-limit-period': { 'type': 'uint64', + 'features': [ 'unstable' ] }, + '*vcpu-dirty-limit': 'uint64', +- '*mode': 'MigMode'} } ++ '*mode': 'MigMode', ++ '*sev-pdh': 'StrOrNull', ++ '*sev-plat-cert': 'StrOrNull', ++ '*sev-amd-cert' : 'StrOrNull' } } ++ + + ## + # @migrate-set-parameters: +@@ -1317,6 +1340,15 @@ + # @mode: Migration mode. See description in @MigMode. Default is 'normal'. + # (Since 8.2) + # ++# @sev-pdh: The target host platform diffie-hellman key encoded in base64 ++# (Since 4.2) ++# ++# @sev-plat-cert: The target host platform certificate chain encoded in base64 ++# (Since 4.2) ++# ++# @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in ++# base64 (Since 4.2) ++# + # Features: + # + # @deprecated: Member @block-incremental is deprecated. Use +@@ -1369,7 +1401,10 @@ + '*x-vcpu-dirty-limit-period': { 'type': 'uint64', + 'features': [ 'unstable' ] }, + '*vcpu-dirty-limit': 'uint64', +- '*mode': 'MigMode'} } ++ '*mode': 'MigMode', ++ '*sev-pdh': 'str', ++ '*sev-plat-cert': 'str', ++ '*sev-amd-cert' : 'str'} } + + ## + # @query-migrate-parameters: +-- +2.41.0.windows.1 + diff --git a/nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch b/nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..dfabaed546cff944085d68df3bbe8348a42f9acf --- /dev/null +++ b/nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch @@ -0,0 +1,90 @@ +From 5da793de60f37cf0daaffee3fe8300a1a20bf36b Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Thu, 22 Aug 2024 09:35:29 -0500 +Subject: [PATCH] nbd/server: CVE-2024-7409: Avoid use-after-free when closing + server + +Commit 3e7ef738 plugged the use-after-free of the global nbd_server +object, but overlooked a use-after-free of nbd_server->listener. +Although this race is harder to hit, notice that our shutdown path +first drops the reference count of nbd_server->listener, then triggers +actions that can result in a pending client reaching the +nbd_blockdev_client_closed() callback, which in turn calls +qio_net_listener_set_client_func on a potentially stale object. + +If we know we don't want any more clients to connect, and have already +told the listener socket to shut down, then we should not be trying to +update the listener socket's associated function. + +Reproducer: + +> #!/usr/bin/python3 +> +> import os +> from threading import Thread +> +> def start_stop(): +> while 1: +> os.system('virsh qemu-monitor-command VM \'{"execute": "nbd-server-start", ++"arguments":{"addr":{"type":"unix","data":{"path":"/tmp/nbd-sock"}}}}\'') +> os.system('virsh qemu-monitor-command VM \'{"execute": "nbd-server-stop"}\'') +> +> def nbd_list(): +> while 1: +> os.system('/path/to/build/qemu-nbd -L -k /tmp/nbd-sock') +> +> def test(): +> sst = Thread(target=start_stop) +> sst.start() +> nlt = Thread(target=nbd_list) +> nlt.start() +> +> sst.join() +> nlt.join() +> +> test() + +Fixes: CVE-2024-7409 +Fixes: 3e7ef738c8 ("nbd/server: CVE-2024-7409: Close stray clients at server-stop") +CC: qemu-stable@nongnu.org +Reported-by: Andrey Drobyshev +Signed-off-by: Eric Blake +Message-ID: <20240822143617.800419-2-eblake@redhat.com> +Reviewed-by: Stefan Hajnoczi +--- + blockdev-nbd.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index f73409ae49..b36f41b7c5 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -92,10 +92,13 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, + + static void nbd_update_server_watch(NBDServerData *s) + { +- if (!s->max_connections || s->connections < s->max_connections) { +- qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, NULL); +- } else { +- qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); ++ if (s->listener) { ++ if (!s->max_connections || s->connections < s->max_connections) { ++ qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, ++ NULL); ++ } else { ++ qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); ++ } + } + } + +@@ -113,6 +116,7 @@ static void nbd_server_free(NBDServerData *server) + */ + qio_net_listener_disconnect(server->listener); + object_unref(OBJECT(server->listener)); ++ server->listener = NULL; + QLIST_FOREACH_SAFE(conn, &server->conns, next, tmp) { + qio_channel_shutdown(QIO_CHANNEL(conn->cioc), QIO_CHANNEL_SHUTDOWN_BOTH, + NULL); +-- +2.41.0.windows.1 + diff --git a/qemu.spec b/qemu.spec index 9c93ce5041ccd760b4f1aa9b7750efccf5f60f8d..f36ea50e1a7683d78ebb38cf46ee2b0e31c7ce5d 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 17 +Release: 18 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -302,6 +302,60 @@ Patch0285: target-i386-add-support-for-LAM-in-CPUID-enumeration.patch Patch0286: target-i386-add-control-bits-support-for-LAM.patch Patch0287: cvm-bug-fix-for-incorrect-device-name-check-for-vhos.patch Patch0288: cvm-bug-fix-for-undefined-reference-to-virtcca_cvm_a.patch +Patch0289: hw-misc-support-vpsp.patch +Patch0290: hw-core-ptimer-fix-timer-zero-period-condition-for-f.patch +Patch0291: vvfat-Fix-bug-in-writing-to-middle-of-file.patch +Patch0292: virtio-net-Use-virtual-time-for-RSC-timers.patch +Patch0293: crypto-Introduce-SM3-hash-hmac-pbkdf-algorithm.patch +Patch0294: cvm-Implement-command-blacklist-for-cvm-security-enh.patch +Patch0295: hw-display-vhost-user-gpu.c-fix-vhost_user_gpu_chr_r.patch +Patch0296: hw-nvme-fix-leak-of-uninitialized-memory-in-io_mgmt_.patch +Patch0297: crypto-tlscredspsk-Free-username-on-finalize.patch +Patch0298: doc-update-AMD-SEV-to-include-Live-migration-flow.patch +Patch0299: migration.json-add-AMD-SEV-specific-migration-parame.patch +Patch0300: confidential-guest-support-introduce-ConfidentialGue.patch +Patch0301: target-i386-sev-provide-callback-to-setup-outgoing-c.patch +Patch0302: target-i386-sev-do-not-create-launch-context-for-an-.patch +Patch0303: target-i386-sev-add-support-to-encrypt-the-outgoing-.patch +Patch0304: target-i386-sev-add-support-to-load-incoming-encrypt.patch +Patch0305: kvm-Add-support-for-SEV-shared-regions-list-and-KVM_.patch +Patch0306: migration-add-support-to-migrate-shared-regions-list.patch +Patch0307: migration-ram-add-support-to-send-encrypted-pages.patch +Patch0308: migration-ram-Force-encrypted-status-for-flash0-flas.patch +Patch0309: kvm-Add-support-for-userspace-MSR-filtering-and-hand.patch +Patch0310: target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch +Patch0311: migration-ram-Force-encrypted-status-for-VGA-vram.patch +Patch0312: target-i386-sev-Clear-shared_regions_list-when-reboo.patch +Patch0313: migration-ram-Fix-calculation-of-gfn-correpond-to-a-.patch +Patch0314: target-i386-Introduce-header-file-csv.h.patch +Patch0315: target-i386-csv-Read-cert-chain-from-file-when-prepa.patch +Patch0316: target-i386-csv-add-support-to-queue-the-outgoing-pa.patch +Patch0317: target-i386-csv-add-support-to-encrypt-the-outgoing-.patch +Patch0318: target-i386-csv-add-support-to-queue-the-incoming-pa.patch +Patch0319: target-i386-csv-add-support-to-load-incoming-encrypt.patch +Patch0320: migration-ram-Accelerate-the-transmission-of-CSV-gue.patch +Patch0321: migration-ram-Accelerate-the-loading-of-CSV-guest-s-.patch +Patch0322: target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch +Patch0323: target-i386-get-set-migrate-GHCB-state.patch +Patch0324: target-i386-kvm-Fix-the-resettable-info-when-emulate.patch +Patch0325: kvm-Add-support-for-CSV2-reboot.patch +Patch0326: update-docs-tools-virtfs-proxy-helper.rst.patch +Patch0327: update-io-trace-events.patch +Patch0328: nbd-server-CVE-2024-7409-Avoid-use-after-free-when-c.patch +Patch0329: virtio-net-Ensure-queue-index-fits-with-RSS-CVE-2024.patch +Patch0330: target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch +Patch0331: hw-misc-bcm2835_property-Fix-handling-of-FRAMEBUFFER.patch +Patch0332: target-arm-Disable-SVE-extensions-when-SVE-is-disabl.patch +Patch0333: virtio-pci-fix-use-of-a-released-vector.patch +Patch0334: target-loongarch-fix-a-wrong-print-in-cpu-dump.patch +Patch0335: backends-cryptodev-builtin-Fix-local_error-leaks.patch +Patch0336: char-stdio-Restore-blocking-mode-of-stdout-on-exit.patch +Patch0337: target-i386-no-single-step-exception-after-MOV-or-PO.patch +Patch0338: migration-colo-Fix-bdrv_graph_rdlock_main_loop-Asser.patch +Patch0339: load_elf-fix-iterator-s-type-for-elf-file-processing.patch +Patch0340: hw-loongarch-Fix-fdt-memory-node-wrong-reg.patch +Patch0341: hw-loongarch-virt-Fix-FDT-memory-node-address-width.patch + BuildRequires: flex BuildRequires: gcc @@ -899,6 +953,61 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Wed Sep 18 2024 Jiabo Feng - 11:8.2.0-18 +- hw/loongarch/virt: Fix FDT memory node address width +- hw/loongarch: Fix fdt memory node wrong 'reg' +- load_elf: fix iterator's type for elf file processing +- migration/colo: Fix bdrv_graph_rdlock_main_loop: Assertion `!qemu_in_… +- target/i386: no single-step exception after MOV or POP SS +- char-stdio: Restore blocking mode of stdout on exit +- backends/cryptodev-builtin: Fix local_error leaks +- target/loongarch: fix a wrong print in cpu dump +- virtio-pci: fix use of a released vector +- target/arm: Disable SVE extensions when SVE is disabled +- hw/misc/bcm2835_property: Fix handling of FRAMEBUFFER_SET_PALETTE +- target/i386: Introduce SapphireRapids-v3 to add missing features +- virtio-net: Ensure queue index fits with RSS (CVE-2024-6505) +- nbd/server: CVE-2024-7409: Avoid use-after-free when closing server +- update io/trace-events. Parameters should remain consistent. +- update docs/tools/virtfs-proxy-helper.rst. This place is spelled wrong. +- kvm: Add support for CSV2 reboot +- target/i386/kvm: Fix the resettable info when emulate Hygon CSV2 guest +- target/i386: get/set/migrate GHCB state +- target/i386: csv: Add support for migrate VMSA for CSV2 guest +- migration/ram: Accelerate the loading of CSV guest's encrypted pages +- migration/ram: Accelerate the transmission of CSV guest's encrypted pages +- target/i386: csv: add support to load incoming encrypted pages queued in the CMD list +- target/i386: csv: add support to queue the incoming page into a list +- target/i386: csv: add support to encrypt the outgoing pages in the list queued before. +- target/i386: csv: add support to queue the outgoing page into a list +- target/i386: csv: Read cert chain from file when prepared for CSV live migration +- target/i386: Introduce header file csv.h +- migration/ram: Fix calculation of gfn correpond to a page in ramblock +- target/i386: sev: Clear shared_regions_list when reboot CSV Guest +- migration/ram: Force encrypted status for VGA vram +- target/i386: sev: Return 0 if sev_send_get_packet_len() fails +- kvm: Add support for userspace MSR filtering and handling of MSR_KVM_MIGRATION_CONTROL. +- migration/ram: Force encrypted status for flash0 & flash1 devices. +- migration/ram: add support to send encrypted pages +- migration: add support to migrate shared regions list +- kvm: Add support for SEV shared regions list and KVM_EXIT_HYPERCALL. +- target/i386: sev: add support to load incoming encrypted page +- target/i386: sev: add support to encrypt the outgoing page +- target/i386: sev: do not create launch context for an incoming guest +- target/i386: sev: provide callback to setup outgoing context +- confidential guest support: introduce ConfidentialGuestMemoryEncryptionOps for encrypted VMs +- migration.json: add AMD SEV specific migration parameters +- doc: update AMD SEV to include Live migration flow +- crypto/tlscredspsk: Free username on finalize +- hw/nvme: fix leak of uninitialized memory in io_mgmt_recv +- hw/display/vhost-user-gpu.c: fix vhost_user_gpu_chr_read() +- cvm : Implement command blacklist for cvm security enhancement +- crypto: Introduce SM3 hash hmac pbkdf algorithm +- virtio-net: Use virtual time for RSC timers +- vvfat: Fix bug in writing to middle of file +- hw/core/ptimer: fix timer zero period condition for freq > 1GHz +- hw/misc: support vpsp + * Thu Sep 5 2024 Jiabo Feng - 11:8.2.0-17 - cvm : bug fix for undefined reference to 'virtcca_cvm_allowed' while compiling - cvm : bug-fix for incorrect device name check for vhost-user-fs diff --git a/target-arm-Disable-SVE-extensions-when-SVE-is-disabl.patch b/target-arm-Disable-SVE-extensions-when-SVE-is-disabl.patch new file mode 100644 index 0000000000000000000000000000000000000000..6fd4fec39b8db4d9359a0986a7dba8ee7d8848c9 --- /dev/null +++ b/target-arm-Disable-SVE-extensions-when-SVE-is-disabl.patch @@ -0,0 +1,39 @@ +From a113ddc33b432c8b4d21160dccb54ba19580ab01 Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 11:22:56 +0800 +Subject: [PATCH] target/arm: Disable SVE extensions when SVE is disabled + +cherry picked from commit daf9748ac002ec35258e5986b6257961fd04b565 + +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2304 +Reported-by: Marcin Juszkiewicz +Signed-off-by: Richard Henderson +Signed-off-by: Marcin Juszkiewicz +Message-id: 20240526204551.553282-1-richard.henderson@linaro.org +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: Gao Jiazhen +--- + target/arm/cpu64.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 5d28838175..6eca55ac29 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -110,6 +110,11 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) + */ + if (!cpu_isar_feature(aa64_sve, cpu)) { + /* SVE is disabled and so are all vector lengths. Good. */ ++ /* ++ * SVE is disabled and so are all vector lengths. Good. ++ * Disable all SVE extensions as well. ++ */ ++ cpu->isar.id_aa64zfr0 = 0; + return; + } + +-- +2.41.0.windows.1 + diff --git a/target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch b/target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch new file mode 100644 index 0000000000000000000000000000000000000000..420fcf1c81b895c9e228cf5af7530afd6fc6bb10 --- /dev/null +++ b/target-i386-Introduce-SapphireRapids-v3-to-add-missi.patch @@ -0,0 +1,48 @@ +From 3323c09d283e02c10bbf6e8dfc43ea9f41e746db Mon Sep 17 00:00:00 2001 +From: Lei Wang +Date: Wed, 24 Apr 2024 03:29:12 -0400 +Subject: [PATCH] target/i386: Introduce SapphireRapids-v3 to add missing + features + +commit b10b2481738304db13d28252e86c10555121a5b3 upstream. + +Add the missing features(ss, tsc-adjust, cldemote, movdiri, movdir64b) in +the SapphireRapids-v3 CPU model. + +Intel-SIG: commit b10b24817383 target/i386: Introduce SapphireRapids-v3 to add missing features. +8.2-SPR new model support + +Signed-off-by: Lei Wang +Message-ID: <20240424072912.43188-1-lei4.wang@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 19ebd49e8c..ca7e5337b0 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4020,6 +4020,17 @@ static const X86CPUDefinition builtin_x86_defs[] = { + { /* end of list */ } + } + }, ++ { ++ .version = 3, ++ .props = (PropValue[]) { ++ { "ss", "on" }, ++ { "tsc-adjust", "on" }, ++ { "cldemote", "on" }, ++ { "movdiri", "on" }, ++ { "movdir64b", "on" }, ++ { /* end of list */ } ++ } ++ }, + { /* end of list */ } + } + }, +-- +2.41.0.windows.1 + diff --git a/target-i386-Introduce-header-file-csv.h.patch b/target-i386-Introduce-header-file-csv.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..a31acbf71439bbdf43b08d3562fdfcffa789cdb8 --- /dev/null +++ b/target-i386-Introduce-header-file-csv.h.patch @@ -0,0 +1,107 @@ +From 2bdf07593dbec66205f2f20fa5430595678ded89 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Thu, 14 Mar 2024 19:21:11 +0800 +Subject: [PATCH] target/i386: Introduce header file csv.h + +This header file is used to provide common helper functions +and data structures for Hygon CSV. + +Signed-off-by: hanliyang +--- + configs/devices/i386-softmmu/default.mak | 1 + + hw/i386/Kconfig | 5 +++ + target/i386/csv.h | 47 ++++++++++++++++++++++++ + 3 files changed, 53 insertions(+) + create mode 100644 target/i386/csv.h + +diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak +index 598c6646df..db83ffcab9 100644 +--- a/configs/devices/i386-softmmu/default.mak ++++ b/configs/devices/i386-softmmu/default.mak +@@ -23,6 +23,7 @@ + #CONFIG_TPM_TIS_ISA=n + #CONFIG_VTD=n + #CONFIG_SGX=n ++#CONFIG_CSV=n + + # Boards: + # +diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig +index 55850791df..08f3ae43f8 100644 +--- a/hw/i386/Kconfig ++++ b/hw/i386/Kconfig +@@ -10,6 +10,10 @@ config SGX + bool + depends on KVM + ++config CSV ++ bool ++ depends on SEV ++ + config PC + bool + imply APPLESMC +@@ -26,6 +30,7 @@ config PC + imply QXL + imply SEV + imply SGX ++ imply CSV + imply TEST_DEVICES + imply TPM_CRB + imply TPM_TIS_ISA +diff --git a/target/i386/csv.h b/target/i386/csv.h +new file mode 100644 +index 0000000000..f935babe97 +--- /dev/null ++++ b/target/i386/csv.h +@@ -0,0 +1,47 @@ ++/* ++ * QEMU CSV support ++ * ++ * Copyright: Hygon Info Technologies Ltd. 2022 ++ * ++ * Author: ++ * Jiang Xin ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#ifndef I386_CSV_H ++#define I386_CSV_H ++ ++#ifdef CONFIG_CSV ++ ++#include "cpu.h" ++ ++#define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ ++#define CPUID_VENDOR_HYGON_ECX 0x656e6975 /* "uine" */ ++#define CPUID_VENDOR_HYGON_EDX 0x6e65476e /* "nGen" */ ++ ++static bool __attribute__((unused)) is_hygon_cpu(void) ++{ ++ uint32_t ebx = 0; ++ uint32_t ecx = 0; ++ uint32_t edx = 0; ++ ++ host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); ++ ++ if (ebx == CPUID_VENDOR_HYGON_EBX && ++ ecx == CPUID_VENDOR_HYGON_ECX && ++ edx == CPUID_VENDOR_HYGON_EDX) ++ return true; ++ else ++ return false; ++} ++ ++#else ++ ++#define is_hygon_cpu() (false) ++ ++#endif ++ ++#endif +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch b/target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch new file mode 100644 index 0000000000000000000000000000000000000000..483e7848a4b7e3825ef8855e318762dc1fe16be3 --- /dev/null +++ b/target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch @@ -0,0 +1,433 @@ +From 940858a3ab39575a0c1d91d4aa5bb65607259a8f Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Tue, 7 Jun 2022 15:19:32 +0800 +Subject: [PATCH] target/i386: csv: Add support for migrate VMSA for CSV2 guest + +CSV2 can protect guest's cpu state through memory encryption. Each +vcpu has its corresponding memory, which is also called VMSA, and +is encrypted by guest's specific encrytion key. + +When CSV2 guest exit to host, the vcpu's state will be encrypted +and saved to VMSA, and the VMSA will be decrypted and loaded to cpu +when the guest's vcpu running at next time. + +If user wants to migrate one CSV2 guest to target machine, the VMSA +of the vcpus also should be migrated to target. CSV firmware provides +SEND_UPDATE_VMSA/RECEIVE_UPDATE_VMSA API through which VMSA can be +converted into secure data and transmitted to the remote end (for +example, network transmission). + +The migration of cpu state is identified by CPUState.cpu_index which +may not equals to vcpu id from KVM's perspective. + +When migrate the VMSA, the source QEMU will invoke SEND_UPDATE_VMSA to +generate data correspond to VMSA, after target QEMU received the data, +it will calc target vcpu id in the KVM by CPUState.cpu_index, and then +invoke RECEIVE_UPDATE_VMSA to restore VMSA correspond to vcpu. + +Signed-off-by: hanliyang +--- + include/exec/confidential-guest-support.h | 6 + + linux-headers/linux/kvm.h | 16 ++ + migration/ram.c | 42 +++++ + target/i386/csv.h | 2 + + target/i386/sev.c | 201 ++++++++++++++++++++++ + target/i386/sev.h | 1 + + target/i386/trace-events | 2 + + 7 files changed, 270 insertions(+) + +diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h +index cb14b815cb..2cba27642f 100644 +--- a/include/exec/confidential-guest-support.h ++++ b/include/exec/confidential-guest-support.h +@@ -90,6 +90,12 @@ struct ConfidentialGuestMemoryEncryptionOps { + + /* Load the incoming encrypted pages queued in list into guest memory */ + int (*load_queued_incoming_pages)(QEMUFile *f); ++ ++ /* Write the encrypted cpu state */ ++ int (*save_outgoing_cpu_state)(QEMUFile *f, uint64_t *bytes_sent); ++ ++ /* Load the encrypted cpu state */ ++ int (*load_incoming_cpu_state)(QEMUFile *f); + }; + + typedef struct ConfidentialGuestSupportClass { +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index fcd09126a1..e9cd0ebaf1 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2052,6 +2052,14 @@ struct kvm_sev_send_update_data { + __u32 trans_len; + }; + ++struct kvm_sev_send_update_vmsa { ++ __u32 vcpu_id; ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ + struct kvm_sev_receive_start { + __u32 handle; + __u32 policy; +@@ -2070,6 +2078,14 @@ struct kvm_sev_receive_update_data { + __u32 trans_len; + }; + ++struct kvm_sev_receive_update_vmsa { ++ __u32 vcpu_id; ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ + struct kvm_csv_batch_list_node { + __u64 cmd_data_addr; + __u64 addr; +diff --git a/migration/ram.c b/migration/ram.c +index 790c0413c1..1377b9eb37 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1281,6 +1281,33 @@ static int ram_save_shared_region_list(RAMState *rs, QEMUFile *f) + return 0; + } + ++/** ++ * ram_save_encrypted_cpu_state: send the encrypted cpu state ++ */ ++static int ram_save_encrypted_cpu_state(RAMState *rs, QEMUFile *f) ++{ ++ int ret; ++ uint64_t bytes_xmit = 0; ++ PageSearchStatus *pss = &rs->pss[RAM_CHANNEL_PRECOPY]; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); ++ struct ConfidentialGuestMemoryEncryptionOps *ops = ++ cgs_class->memory_encryption_ops; ++ ++ ram_transferred_add(save_page_header(pss, f, ++ pss->last_sent_block, ++ RAM_SAVE_FLAG_ENCRYPTED_DATA)); ++ qemu_put_be32(f, RAM_SAVE_ENCRYPTED_CPU_STATE); ++ ret = ops->save_outgoing_cpu_state(f, &bytes_xmit); ++ if (ret < 0) { ++ return ret; ++ } ++ ram_transferred_add(4 + bytes_xmit); ++ ++ return 0; ++} ++ + static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) + { + MachineState *ms = MACHINE(qdev_get_machine()); +@@ -1305,6 +1332,8 @@ static int load_encrypted_data(QEMUFile *f, uint8_t *ptr) + return -EINVAL; + } + return ops->load_queued_incoming_pages(f); ++ } else if (flag == RAM_SAVE_ENCRYPTED_CPU_STATE) { ++ return ops->load_incoming_cpu_state(f); + } else { + error_report("unknown encrypted flag %x", flag); + return 1; +@@ -3494,6 +3523,19 @@ static int ram_save_complete(QEMUFile *f, void *opaque) + qemu_file_set_error(f, ret); + return ret; + } ++ ++ /* ++ * send the encrypted cpu state, for example, CSV2 guest's ++ * vmsa for each vcpu. ++ */ ++ if (is_hygon_cpu()) { ++ ret = ram_save_encrypted_cpu_state(rs, f); ++ if (ret < 0) { ++ error_report("Failed to save encrypted cpu state"); ++ qemu_file_set_error(f, ret); ++ return ret; ++ } ++ } + } + } + +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 74a54f9b9c..47741a0a4f 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -59,5 +59,7 @@ int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); + int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); + int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr); + int csv_load_queued_incoming_pages(QEMUFile *f); ++int csv_save_outgoing_cpu_state(QEMUFile *f, uint64_t *bytes_sent); ++int csv_load_incoming_cpu_state(QEMUFile *f); + + #endif +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 2dee46d852..6ba71c91d7 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -90,6 +90,10 @@ struct SevGuestState { + gchar *send_packet_hdr; + size_t send_packet_hdr_len; + ++ /* needed by live migration of HYGON CSV2 guest */ ++ gchar *send_vmsa_packet_hdr; ++ size_t send_vmsa_packet_hdr_len; ++ + uint32_t reset_cs; + uint32_t reset_ip; + bool reset_data_valid; +@@ -183,6 +187,9 @@ static const char *const sev_fw_errlist[] = { + #define SHARED_REGION_LIST_CONT 0x1 + #define SHARED_REGION_LIST_END 0x2 + ++#define ENCRYPTED_CPU_STATE_CONT 0x1 ++#define ENCRYPTED_CPU_STATE_END 0x2 ++ + static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .save_setup = sev_save_setup, + .save_outgoing_page = sev_save_outgoing_page, +@@ -194,6 +201,8 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, + .queue_incoming_page = csv_queue_incoming_page, + .load_queued_incoming_pages = csv_load_queued_incoming_pages, ++ .save_outgoing_cpu_state = csv_save_outgoing_cpu_state, ++ .load_incoming_cpu_state = csv_load_incoming_cpu_state, + }; + + static int +@@ -1047,6 +1056,9 @@ sev_send_finish(void) + } + + g_free(sev_guest->send_packet_hdr); ++ if (sev_es_enabled() && is_hygon_cpu()) { ++ g_free(sev_guest->send_vmsa_packet_hdr); ++ } + sev_set_guest_state(sev_guest, SEV_STATE_RUNNING); + } + +@@ -2238,6 +2250,195 @@ int csv_load_queued_incoming_pages(QEMUFile *f) + return csv_receive_update_data_batch(s); + } + ++static int ++sev_send_vmsa_get_packet_len(int *fw_err) ++{ ++ int ret; ++ struct kvm_sev_send_update_vmsa update = { 0, }; ++ ++ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_UPDATE_VMSA, ++ &update, fw_err); ++ if (*fw_err != SEV_RET_INVALID_LEN) { ++ ret = 0; ++ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", ++ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); ++ goto err; ++ } ++ ++ ret = update.hdr_len; ++ ++err: ++ return ret; ++} ++ ++static int ++sev_send_update_vmsa(SevGuestState *s, QEMUFile *f, uint32_t cpu_id, ++ uint32_t cpu_index, uint32_t size, uint64_t *bytes_sent) ++{ ++ int ret, fw_error; ++ guchar *trans = NULL; ++ struct kvm_sev_send_update_vmsa update = {}; ++ ++ /* ++ * If this is first call then query the packet header bytes and allocate ++ * the packet buffer. ++ */ ++ if (!s->send_vmsa_packet_hdr) { ++ s->send_vmsa_packet_hdr_len = sev_send_vmsa_get_packet_len(&fw_error); ++ if (s->send_vmsa_packet_hdr_len < 1) { ++ error_report("%s: SEND_UPDATE_VMSA fw_error=%d '%s'", ++ __func__, fw_error, fw_error_to_str(fw_error)); ++ return 1; ++ } ++ ++ s->send_vmsa_packet_hdr = g_new(gchar, s->send_vmsa_packet_hdr_len); ++ } ++ ++ /* allocate transport buffer */ ++ trans = g_new(guchar, size); ++ ++ update.vcpu_id = cpu_id; ++ update.hdr_uaddr = (uintptr_t)s->send_vmsa_packet_hdr; ++ update.hdr_len = s->send_vmsa_packet_hdr_len; ++ update.trans_uaddr = (uintptr_t)trans; ++ update.trans_len = size; ++ ++ trace_kvm_sev_send_update_vmsa(cpu_id, cpu_index, trans, size); ++ ++ ret = sev_ioctl(s->sev_fd, KVM_SEV_SEND_UPDATE_VMSA, &update, &fw_error); ++ if (ret) { ++ error_report("%s: SEND_UPDATE_VMSA ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++ /* ++ * Migration of vCPU's VMState according to the instance_id ++ * (i.e. CPUState.cpu_index) ++ */ ++ qemu_put_be32(f, sizeof(uint32_t)); ++ qemu_put_buffer(f, (uint8_t *)&cpu_index, sizeof(uint32_t)); ++ *bytes_sent += 4 + sizeof(uint32_t); ++ ++ qemu_put_be32(f, update.hdr_len); ++ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); ++ *bytes_sent += 4 + update.hdr_len; ++ ++ qemu_put_be32(f, update.trans_len); ++ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ *bytes_sent += 4 + update.trans_len; ++ ++err: ++ g_free(trans); ++ return ret; ++} ++ ++int csv_save_outgoing_cpu_state(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ SevGuestState *s = sev_guest; ++ CPUState *cpu; ++ int ret = 0; ++ ++ /* Only support migrate VMSAs for HYGON CSV2 guest */ ++ if (!sev_es_enabled() || !is_hygon_cpu()) { ++ return 0; ++ } ++ ++ CPU_FOREACH(cpu) { ++ qemu_put_be32(f, ENCRYPTED_CPU_STATE_CONT); ++ *bytes_sent += 4; ++ ret = sev_send_update_vmsa(s, f, kvm_arch_vcpu_id(cpu), ++ cpu->cpu_index, TARGET_PAGE_SIZE, bytes_sent); ++ if (ret) { ++ goto err; ++ } ++ } ++ ++ qemu_put_be32(f, ENCRYPTED_CPU_STATE_END); ++ *bytes_sent += 4; ++ ++err: ++ return ret; ++} ++ ++static int sev_receive_update_vmsa(QEMUFile *f) ++{ ++ int ret = 1, fw_error = 0; ++ CPUState *cpu; ++ uint32_t cpu_index, cpu_id = 0; ++ gchar *hdr = NULL, *trans = NULL; ++ struct kvm_sev_receive_update_vmsa update = {}; ++ ++ /* get cpu index buffer */ ++ assert(qemu_get_be32(f) == sizeof(uint32_t)); ++ qemu_get_buffer(f, (uint8_t *)&cpu_index, sizeof(uint32_t)); ++ ++ CPU_FOREACH(cpu) { ++ if (cpu->cpu_index == cpu_index) { ++ cpu_id = kvm_arch_vcpu_id(cpu); ++ break; ++ } ++ } ++ update.vcpu_id = cpu_id; ++ ++ /* get packet header */ ++ update.hdr_len = qemu_get_be32(f); ++ if (!check_blob_length(update.hdr_len)) { ++ return 1; ++ } ++ ++ hdr = g_new(gchar, update.hdr_len); ++ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); ++ update.hdr_uaddr = (uintptr_t)hdr; ++ ++ /* get transport buffer */ ++ update.trans_len = qemu_get_be32(f); ++ if (!check_blob_length(update.trans_len)) { ++ goto err; ++ } ++ ++ trans = g_new(gchar, update.trans_len); ++ update.trans_uaddr = (uintptr_t)trans; ++ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ ++ trace_kvm_sev_receive_update_vmsa(cpu_id, cpu_index, ++ trans, update.trans_len, hdr, update.hdr_len); ++ ++ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_RECEIVE_UPDATE_VMSA, ++ &update, &fw_error); ++ if (ret) { ++ error_report("Error RECEIVE_UPDATE_VMSA ret=%d fw_error=%d '%s'", ++ ret, fw_error, fw_error_to_str(fw_error)); ++ } ++ ++err: ++ g_free(trans); ++ g_free(hdr); ++ return ret; ++} ++ ++int csv_load_incoming_cpu_state(QEMUFile *f) ++{ ++ int status, ret = 0; ++ ++ /* Only support migrate VMSAs for HYGON CSV2 guest */ ++ if (!sev_es_enabled() || !is_hygon_cpu()) { ++ return 0; ++ } ++ ++ status = qemu_get_be32(f); ++ while (status == ENCRYPTED_CPU_STATE_CONT) { ++ ret = sev_receive_update_vmsa(f); ++ if (ret) { ++ break; ++ } ++ ++ status = qemu_get_be32(f); ++ } ++ ++ return ret; ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +diff --git a/target/i386/sev.h b/target/i386/sev.h +index f7886116e7..209c92fd6f 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -43,6 +43,7 @@ typedef struct SevKernelLoaderContext { + + #define RAM_SAVE_ENCRYPTED_PAGE_BATCH 0x4 + #define RAM_SAVE_ENCRYPTED_PAGE_BATCH_END 0x5 ++#define RAM_SAVE_ENCRYPTED_CPU_STATE 0x6 + + #ifdef CONFIG_SEV + bool sev_enabled(void); +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 475de65ad4..87b765c73c 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -17,3 +17,5 @@ kvm_sev_send_finish(void) "" + kvm_sev_receive_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p" + kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_len) "guest %p trans %p len %d hdr %p hdr_len %d" + kvm_sev_receive_finish(void) "" ++kvm_sev_send_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *dst, int len) "cpu_id %d cpu_index %d trans %p len %d" ++kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int len, void *hdr, int hdr_len) "cpu_id %d cpu_index %d trans %p len %d hdr %p hdr_len %d" +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-Read-cert-chain-from-file-when-prepa.patch b/target-i386-csv-Read-cert-chain-from-file-when-prepa.patch new file mode 100644 index 0000000000000000000000000000000000000000..e9440f46f8d6936157c839bdee0c27095ab3e0d4 --- /dev/null +++ b/target-i386-csv-Read-cert-chain-from-file-when-prepa.patch @@ -0,0 +1,140 @@ +From d23c6a2bcc836587620bd35726ca4d5f71c0a844 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Mon, 13 Nov 2023 21:55:33 +0000 +Subject: [PATCH] target/i386: csv: Read cert chain from file when prepared for + CSV live migration + +The cert chain is too long when encoded with base64, use the filename +of cert chain instead of the encoded string when prepared for CSV live +migration. + +[ Fix conflicts. ] +Signed-off-by: hanliyang +--- + qapi/migration.json | 24 +++++++++++++++--------- + target/i386/sev.c | 30 ++++++++++++++++++++++++++---- + 2 files changed, 41 insertions(+), 13 deletions(-) + +diff --git a/qapi/migration.json b/qapi/migration.json +index 038e99cba3..3aed216c3b 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -891,14 +891,16 @@ + # @mode: Migration mode. See description in @MigMode. Default is 'normal'. + # (Since 8.2) + # +-# @sev-pdh: The target host platform diffie-hellman key encoded in base64 ++# @sev-pdh: The target host platform diffie-hellman key encoded in base64, or ++# pdh filename for hygon + # (Since 4.2) + # +-# @sev-plat-cert: The target host platform certificate chain encoded in base64 ++# @sev-plat-cert: The target host platform certificate chain encoded in base64, ++# or plat cert filename for hygon + # (Since 4.2) + # + # @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in +-# base64 (Since 4.2) ++# base64, or vendor cert filename for hygon (Since 4.2) + # + # Features: + # +@@ -1093,14 +1095,16 @@ + # @mode: Migration mode. See description in @MigMode. Default is 'normal'. + # (Since 8.2) + # +-# @sev-pdh: The target host platform diffie-hellman key encoded in base64 ++# @sev-pdh: The target host platform diffie-hellman key encoded in base64, or ++# pdh filename for hygon + # (Since 4.2) + # +-# @sev-plat-cert: The target host platform certificate chain encoded in base64 ++# @sev-plat-cert: The target host platform certificate chain encoded in base64, ++# or plat cert filename for hygon + # (Since 4.2) + # + # @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in +-# base64 (Since 4.2) ++# base64, or vendor cert filename for hygon (Since 4.2) + # + # Features: + # +@@ -1340,14 +1344,16 @@ + # @mode: Migration mode. See description in @MigMode. Default is 'normal'. + # (Since 8.2) + # +-# @sev-pdh: The target host platform diffie-hellman key encoded in base64 ++# @sev-pdh: The target host platform diffie-hellman key encoded in base64, or ++# pdh filename for hygon + # (Since 4.2) + # +-# @sev-plat-cert: The target host platform certificate chain encoded in base64 ++# @sev-plat-cert: The target host platform certificate chain encoded in base64, ++# or plat cert filename for hygon + # (Since 4.2) + # + # @sev-amd-cert: AMD certificate chain which include ASK and OCA encoded in +-# base64 (Since 4.2) ++# base64, or vendor cert filename for hygon (Since 4.2) + # + # Features: + # +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 0b0f589aee..331dfa4516 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -27,6 +27,7 @@ + #include "crypto/hash.h" + #include "sysemu/kvm.h" + #include "sev.h" ++#include "csv.h" + #include "sysemu/sysemu.h" + #include "sysemu/runstate.h" + #include "trace.h" +@@ -979,18 +980,39 @@ int sev_save_setup(const char *pdh, const char *plat_cert, + { + SevGuestState *s = sev_guest; + +- s->remote_pdh = g_base64_decode(pdh, &s->remote_pdh_len); ++ if (is_hygon_cpu()) { ++ if (sev_read_file_base64(pdh, &s->remote_pdh, ++ &s->remote_pdh_len) < 0) { ++ goto error; ++ } ++ } else { ++ s->remote_pdh = g_base64_decode(pdh, &s->remote_pdh_len); ++ } + if (!check_blob_length(s->remote_pdh_len)) { + goto error; + } + +- s->remote_plat_cert = g_base64_decode(plat_cert, +- &s->remote_plat_cert_len); ++ if (is_hygon_cpu()) { ++ if (sev_read_file_base64(plat_cert, &s->remote_plat_cert, ++ &s->remote_plat_cert_len) < 0) { ++ goto error; ++ } ++ } else { ++ s->remote_plat_cert = g_base64_decode(plat_cert, ++ &s->remote_plat_cert_len); ++ } + if (!check_blob_length(s->remote_plat_cert_len)) { + goto error; + } + +- s->amd_cert = g_base64_decode(amd_cert, &s->amd_cert_len); ++ if (is_hygon_cpu()) { ++ if (sev_read_file_base64(amd_cert, &s->amd_cert, ++ &s->amd_cert_len) < 0) { ++ goto error; ++ } ++ } else { ++ s->amd_cert = g_base64_decode(amd_cert, &s->amd_cert_len); ++ } + if (!check_blob_length(s->amd_cert_len)) { + goto error; + } +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-add-support-to-encrypt-the-outgoing-.patch b/target-i386-csv-add-support-to-encrypt-the-outgoing-.patch new file mode 100644 index 0000000000000000000000000000000000000000..6b5023f8af6f8a20ce22a3d1ff9344771e632308 --- /dev/null +++ b/target-i386-csv-add-support-to-encrypt-the-outgoing-.patch @@ -0,0 +1,207 @@ +From b2091d245563f4bd2974c8d8e6ef186de614f8e2 Mon Sep 17 00:00:00 2001 +From: fangbaoshun +Date: Mon, 2 Aug 2021 11:41:58 +0800 +Subject: [PATCH] target/i386: csv: add support to encrypt the outgoing pages + in the list queued before. + +The csv_save_queued_outgoing_pages() provide the implementation to encrypt +the guest private pages during transmission. The routines uses SEND_START +command to create the outgoing encryption context on the first call then +uses COMMAND_BATCH command to send the SEND_UPDATE_DATA commands queued +in the list to encrypt the data before writing it to the socket. While +encrypting the data SEND_UPDATE_DATA produces some metadata (e.g MAC, IV). +The metadata is also sent to the target machine. After migration is completed, +we issue the SEND_FINISH command to transition the SEV guest state from sending +to unrunnable state. + +Signed-off-by: hanliyang +--- + include/exec/confidential-guest-support.h | 4 ++ + linux-headers/linux/kvm.h | 8 +++ + target/i386/csv.h | 1 + + target/i386/sev.c | 88 +++++++++++++++++++++++ + target/i386/sev.h | 3 + + 5 files changed, 104 insertions(+) + +diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h +index 8949568acc..c84f8c1efc 100644 +--- a/include/exec/confidential-guest-support.h ++++ b/include/exec/confidential-guest-support.h +@@ -80,6 +80,10 @@ struct ConfidentialGuestMemoryEncryptionOps { + + /* Queue the encrypted page and metadata associated with it into a list */ + int (*queue_outgoing_page)(uint8_t *ptr, uint32_t size, uint64_t addr); ++ ++ /* Write the list queued with encrypted pages and metadata associated ++ * with them */ ++ int (*save_queued_outgoing_pages)(QEMUFile *f, uint64_t *bytes_sent); + }; + + typedef struct ConfidentialGuestSupportClass { +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index ca78fdc8b6..fcd09126a1 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1971,6 +1971,9 @@ enum sev_cmd_id { + /* Guest Migration Extension */ + KVM_SEV_SEND_CANCEL, + ++ /* Hygon CSV batch command */ ++ KVM_CSV_COMMAND_BATCH = 0x18, ++ + KVM_SEV_NR_MAX, + }; + +@@ -2073,6 +2076,11 @@ struct kvm_csv_batch_list_node { + __u64 next_cmd_addr; + }; + ++struct kvm_csv_command_batch { ++ __u32 command_id; ++ __u64 csv_batch_list_uaddr; ++}; ++ + #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) + #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) + #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 4c1ef20029..2a3a3119d9 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -54,5 +54,6 @@ struct CsvBatchCmdList { + }; + + int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); ++int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); + + #endif +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 7dd35d64ee..1e2bbafe36 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -191,6 +191,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, + .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, + .queue_outgoing_page = csv_queue_outgoing_page, ++ .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, + }; + + static int +@@ -2012,6 +2013,69 @@ err: + return ret; + } + ++static int ++csv_command_batch(uint32_t cmd_id, uint64_t head_uaddr, int *fw_err) ++{ ++ int ret; ++ struct kvm_csv_command_batch command_batch = { }; ++ ++ command_batch.command_id = cmd_id; ++ command_batch.csv_batch_list_uaddr = head_uaddr; ++ ++ ret = sev_ioctl(sev_guest->sev_fd, KVM_CSV_COMMAND_BATCH, ++ &command_batch, fw_err); ++ if (ret) { ++ error_report("%s: COMMAND_BATCH ret=%d fw_err=%d '%s'", ++ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); ++ } ++ ++ return ret; ++} ++ ++static int ++csv_send_update_data_batch(SevGuestState *s, QEMUFile *f, uint64_t *bytes_sent) ++{ ++ int ret, fw_error = 0; ++ struct kvm_sev_send_update_data *update; ++ struct kvm_csv_batch_list_node *node; ++ ++ ret = csv_command_batch(KVM_SEV_SEND_UPDATE_DATA, ++ (uint64_t)s->csv_batch_cmd_list->head, &fw_error); ++ if (ret) { ++ error_report("%s: csv_command_batch ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++ for (node = s->csv_batch_cmd_list->head; ++ node != NULL; ++ node = (struct kvm_csv_batch_list_node *)node->next_cmd_addr) { ++ if (node != s->csv_batch_cmd_list->head) { ++ /* head's page header is saved before send_update_data */ ++ qemu_put_be64(f, node->addr); ++ *bytes_sent += 8; ++ if (node->next_cmd_addr != 0) ++ qemu_put_be32(f, RAM_SAVE_ENCRYPTED_PAGE_BATCH); ++ else ++ qemu_put_be32(f, RAM_SAVE_ENCRYPTED_PAGE_BATCH_END); ++ *bytes_sent += 4; ++ } ++ update = (struct kvm_sev_send_update_data *)node->cmd_data_addr; ++ qemu_put_be32(f, update->hdr_len); ++ qemu_put_buffer(f, (uint8_t *)update->hdr_uaddr, update->hdr_len); ++ *bytes_sent += (4 + update->hdr_len); ++ ++ qemu_put_be32(f, update->trans_len); ++ qemu_put_buffer(f, (uint8_t *)update->trans_uaddr, update->trans_len); ++ *bytes_sent += (4 + update->trans_len); ++ } ++ ++err: ++ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); ++ s->csv_batch_cmd_list = NULL; ++ return ret; ++} ++ + int + csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) + { +@@ -2026,6 +2090,30 @@ csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) + return csv_send_queue_data(s, ptr, sz, addr); + } + ++int ++csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ SevGuestState *s = sev_guest; ++ ++ /* Only support for HYGON CSV */ ++ if (!is_hygon_cpu()) { ++ error_report("Only support transfer queued pages for HYGON CSV"); ++ return -EINVAL; ++ } ++ ++ /* ++ * If this is a first buffer then create outgoing encryption context ++ * and write our PDH, policy and session data. ++ */ ++ if (!sev_check_state(s, SEV_STATE_SEND_UPDATE) && ++ sev_send_start(s, f, bytes_sent)) { ++ error_report("Failed to create outgoing context"); ++ return 1; ++ } ++ ++ return csv_send_update_data_batch(s, f, bytes_sent); ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +diff --git a/target/i386/sev.h b/target/i386/sev.h +index 84e3bdf2df..f7886116e7 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -41,6 +41,9 @@ typedef struct SevKernelLoaderContext { + #define RAM_SAVE_ENCRYPTED_PAGE 0x1 + #define RAM_SAVE_SHARED_REGIONS_LIST 0x2 + ++#define RAM_SAVE_ENCRYPTED_PAGE_BATCH 0x4 ++#define RAM_SAVE_ENCRYPTED_PAGE_BATCH_END 0x5 ++ + #ifdef CONFIG_SEV + bool sev_enabled(void); + bool sev_es_enabled(void); +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-add-support-to-load-incoming-encrypt.patch b/target-i386-csv-add-support-to-load-incoming-encrypt.patch new file mode 100644 index 0000000000000000000000000000000000000000..7af0a4e0d9c94d19a44234d6f31724c8f19ee6a7 --- /dev/null +++ b/target-i386-csv-add-support-to-load-incoming-encrypt.patch @@ -0,0 +1,107 @@ +From cb5c1c9c70110639eda0ff50c8dfcf24b0be561d Mon Sep 17 00:00:00 2001 +From: fangbaoshun +Date: Mon, 2 Aug 2021 14:11:43 +0800 +Subject: [PATCH] target/i386: csv: add support to load incoming encrypted + pages queued in the CMD list + +The csv_load_queued_incoming_pages() provide the implementation to read the +incoming guest private pages from the socket queued in the CMD list and load +them into the guest memory. The routines uses the RECEIVE_START command to +create the incoming encryption context on the first call then uses the +COMMAND_BATCH carried with RECEIEVE_UPDATE_DATA commands to load the encrypted +pages into the guest memory. After migration is completed, we issue the +RECEIVE_FINISH command to transition the SEV guest to the runnable state +so that it can be executed. + +Signed-off-by: hanliyang +--- + include/exec/confidential-guest-support.h | 3 +++ + target/i386/csv.h | 1 + + target/i386/sev.c | 32 +++++++++++++++++++++++ + 3 files changed, 36 insertions(+) + +diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h +index 101cc5220a..cb14b815cb 100644 +--- a/include/exec/confidential-guest-support.h ++++ b/include/exec/confidential-guest-support.h +@@ -87,6 +87,9 @@ struct ConfidentialGuestMemoryEncryptionOps { + + /* Queue the incoming encrypted page into a list */ + int (*queue_incoming_page)(QEMUFile *f, uint8_t *ptr); ++ ++ /* Load the incoming encrypted pages queued in list into guest memory */ ++ int (*load_queued_incoming_pages)(QEMUFile *f); + }; + + typedef struct ConfidentialGuestSupportClass { +diff --git a/target/i386/csv.h b/target/i386/csv.h +index d1bcc8bc16..977f08b982 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -56,5 +56,6 @@ struct CsvBatchCmdList { + int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); + int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); + int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr); ++int csv_load_queued_incoming_pages(QEMUFile *f); + + #endif +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 606aaad328..2dee46d852 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -193,6 +193,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .queue_outgoing_page = csv_queue_outgoing_page, + .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, + .queue_incoming_page = csv_queue_incoming_page, ++ .load_queued_incoming_pages = csv_load_queued_incoming_pages, + }; + + static int +@@ -2146,6 +2147,24 @@ err: + return ret; + } + ++static int ++csv_receive_update_data_batch(SevGuestState *s) ++{ ++ int ret; ++ int fw_error; ++ ++ ret = csv_command_batch(KVM_SEV_RECEIVE_UPDATE_DATA, ++ (uint64_t)s->csv_batch_cmd_list->head, &fw_error); ++ if (ret) { ++ error_report("%s: csv_command_batch ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ } ++ ++ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); ++ s->csv_batch_cmd_list = NULL; ++ return ret; ++} ++ + int + csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) + { +@@ -2206,6 +2225,19 @@ csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) + return csv_send_update_data_batch(s, f, bytes_sent); + } + ++int csv_load_queued_incoming_pages(QEMUFile *f) ++{ ++ SevGuestState *s = sev_guest; ++ ++ /* Only support for HYGON CSV */ ++ if (!is_hygon_cpu()) { ++ error_report("Only support load queued pages for HYGON CSV"); ++ return -EINVAL; ++ } ++ ++ return csv_receive_update_data_batch(s); ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-add-support-to-queue-the-incoming-pa.patch b/target-i386-csv-add-support-to-queue-the-incoming-pa.patch new file mode 100644 index 0000000000000000000000000000000000000000..8382ae20bbdd0fbfead55de07f1f21a67660f952 --- /dev/null +++ b/target-i386-csv-add-support-to-queue-the-incoming-pa.patch @@ -0,0 +1,170 @@ +From 8125145bcd3b8348e69686e26f482cf16b16ec98 Mon Sep 17 00:00:00 2001 +From: fangbaoshun +Date: Mon, 2 Aug 2021 13:49:48 +0800 +Subject: [PATCH] target/i386: csv: add support to queue the incoming page into + a list + +The csv_queue_incoming_page() provide the implementation to queue the +guest private pages during transmission. The routines queues the incoming +socket which contains the guest private pages into a list then uses the +COMMAND_BATCH command to load the encrypted pages into the guest memory. + +Signed-off-by: hanliyang +--- + include/exec/confidential-guest-support.h | 3 + + target/i386/csv.h | 1 + + target/i386/sev.c | 92 +++++++++++++++++++++++ + 3 files changed, 96 insertions(+) + +diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h +index c84f8c1efc..101cc5220a 100644 +--- a/include/exec/confidential-guest-support.h ++++ b/include/exec/confidential-guest-support.h +@@ -84,6 +84,9 @@ struct ConfidentialGuestMemoryEncryptionOps { + /* Write the list queued with encrypted pages and metadata associated + * with them */ + int (*save_queued_outgoing_pages)(QEMUFile *f, uint64_t *bytes_sent); ++ ++ /* Queue the incoming encrypted page into a list */ ++ int (*queue_incoming_page)(QEMUFile *f, uint8_t *ptr); + }; + + typedef struct ConfidentialGuestSupportClass { +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 2a3a3119d9..d1bcc8bc16 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -55,5 +55,6 @@ struct CsvBatchCmdList { + + int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); + int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); ++int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr); + + #endif +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 1e2bbafe36..606aaad328 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -192,6 +192,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, + .queue_outgoing_page = csv_queue_outgoing_page, + .save_queued_outgoing_pages = csv_save_queued_outgoing_pages, ++ .queue_incoming_page = csv_queue_incoming_page, + }; + + static int +@@ -1941,6 +1942,15 @@ static void send_update_data_free(void *data) + g_free(update); + } + ++static void receive_update_data_free(void *data) ++{ ++ struct kvm_sev_receive_update_data *update = ++ (struct kvm_sev_receive_update_data *)data; ++ g_free((guchar *)update->hdr_uaddr); ++ g_free((guchar *)update->trans_uaddr); ++ g_free(update); ++} ++ + static int + csv_send_queue_data(SevGuestState *s, uint8_t *ptr, + uint32_t size, uint64_t addr) +@@ -2013,6 +2023,66 @@ err: + return ret; + } + ++static int ++csv_receive_queue_data(SevGuestState *s, QEMUFile *f, uint8_t *ptr) ++{ ++ int ret = 0; ++ gchar *hdr = NULL, *trans = NULL; ++ struct kvm_sev_receive_update_data *update; ++ struct kvm_csv_batch_list_node *new_node = NULL; ++ ++ update = g_new0(struct kvm_sev_receive_update_data, 1); ++ /* get packet header */ ++ update->hdr_len = qemu_get_be32(f); ++ hdr = g_new(gchar, update->hdr_len); ++ qemu_get_buffer(f, (uint8_t *)hdr, update->hdr_len); ++ update->hdr_uaddr = (unsigned long)hdr; ++ ++ /* get transport buffer */ ++ update->trans_len = qemu_get_be32(f); ++ trans = g_new(gchar, update->trans_len); ++ update->trans_uaddr = (unsigned long)trans; ++ qemu_get_buffer(f, (uint8_t *)update->trans_uaddr, update->trans_len); ++ ++ /* set guest address,guest len is page_size */ ++ update->guest_uaddr = (uint64_t)ptr; ++ update->guest_len = TARGET_PAGE_SIZE; ++ ++ new_node = csv_batch_cmd_list_node_create((uint64_t)update, 0); ++ if (!new_node) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ if (s->csv_batch_cmd_list == NULL) { ++ s->csv_batch_cmd_list = csv_batch_cmd_list_create(new_node, ++ receive_update_data_free); ++ if (s->csv_batch_cmd_list == NULL) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } else { ++ /* Add new_node's command address to the last_node */ ++ csv_batch_cmd_list_add_after(s->csv_batch_cmd_list, new_node); ++ } ++ ++ trace_kvm_sev_receive_update_data(trans, (void *)ptr, update->guest_len, ++ (void *)hdr, update->hdr_len); ++ ++ return ret; ++ ++err: ++ g_free(trans); ++ g_free(update); ++ g_free(hdr); ++ g_free(new_node); ++ if (s->csv_batch_cmd_list) { ++ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); ++ s->csv_batch_cmd_list = NULL; ++ } ++ return ret; ++} ++ + static int + csv_command_batch(uint32_t cmd_id, uint64_t head_uaddr, int *fw_err) + { +@@ -2090,6 +2160,28 @@ csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) + return csv_send_queue_data(s, ptr, sz, addr); + } + ++int csv_queue_incoming_page(QEMUFile *f, uint8_t *ptr) ++{ ++ SevGuestState *s = sev_guest; ++ ++ /* Only support for HYGON CSV */ ++ if (!is_hygon_cpu()) { ++ error_report("Only support enqueue received pages for HYGON CSV"); ++ return -EINVAL; ++ } ++ ++ /* ++ * If this is first buffer and SEV is not in recieiving state then ++ * use RECEIVE_START command to create a encryption context. ++ */ ++ if (!sev_check_state(s, SEV_STATE_RECEIVE_UPDATE) && ++ sev_receive_start(s, f)) { ++ return 1; ++ } ++ ++ return csv_receive_queue_data(s, f, ptr); ++} ++ + int + csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) + { +-- +2.41.0.windows.1 + diff --git a/target-i386-csv-add-support-to-queue-the-outgoing-pa.patch b/target-i386-csv-add-support-to-queue-the-outgoing-pa.patch new file mode 100644 index 0000000000000000000000000000000000000000..0a6da4fc9825080d5f694002f9d20d371f566202 --- /dev/null +++ b/target-i386-csv-add-support-to-queue-the-outgoing-pa.patch @@ -0,0 +1,259 @@ +From e6d587b63c3950f5d5af9002a8ae14e0904d62c3 Mon Sep 17 00:00:00 2001 +From: fangbaoshun +Date: Mon, 2 Aug 2021 11:00:07 +0800 +Subject: [PATCH] target/i386: csv: add support to queue the outgoing page into + a list + +The csv_queue_outgoing_page() provide the implementation to queue the +guest private pages during transmission. The routines queues the outgoing +pages into a listi, and then issues the KVM_CSV_COMMAND_BATCH command to +encrypt the pages togather before writing them to the socket. + +Signed-off-by: hanliyang +--- + include/exec/confidential-guest-support.h | 3 + + linux-headers/linux/kvm.h | 6 + + target/i386/csv.h | 11 ++ + target/i386/sev.c | 161 ++++++++++++++++++++++ + 4 files changed, 181 insertions(+) + +diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h +index dd4887f65f..8949568acc 100644 +--- a/include/exec/confidential-guest-support.h ++++ b/include/exec/confidential-guest-support.h +@@ -77,6 +77,9 @@ struct ConfidentialGuestMemoryEncryptionOps { + + /* Load the shared regions list */ + int (*load_incoming_shared_regions_list)(QEMUFile *f); ++ ++ /* Queue the encrypted page and metadata associated with it into a list */ ++ int (*queue_outgoing_page)(uint8_t *ptr, uint32_t size, uint64_t addr); + }; + + typedef struct ConfidentialGuestSupportClass { +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 9489a20835..ca78fdc8b6 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2067,6 +2067,12 @@ struct kvm_sev_receive_update_data { + __u32 trans_len; + }; + ++struct kvm_csv_batch_list_node { ++ __u64 cmd_data_addr; ++ __u64 addr; ++ __u64 next_cmd_addr; ++}; ++ + #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) + #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) + #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2) +diff --git a/target/i386/csv.h b/target/i386/csv.h +index f935babe97..4c1ef20029 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -44,4 +44,15 @@ static bool __attribute__((unused)) is_hygon_cpu(void) + + #endif + ++typedef struct CsvBatchCmdList CsvBatchCmdList; ++typedef void (*CsvDestroyCmdNodeFn) (void *data); ++ ++struct CsvBatchCmdList { ++ struct kvm_csv_batch_list_node *head; ++ struct kvm_csv_batch_list_node *tail; ++ CsvDestroyCmdNodeFn destroy_fn; ++}; ++ ++int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); ++ + #endif +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 331dfa4516..7dd35d64ee 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -95,6 +95,9 @@ struct SevGuestState { + bool reset_data_valid; + + QTAILQ_HEAD(, shared_region) shared_regions_list; ++ ++ /* link list used for HYGON CSV */ ++ CsvBatchCmdList *csv_batch_cmd_list; + }; + + #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ +@@ -187,6 +190,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .is_gfn_in_unshared_region = sev_is_gfn_in_unshared_region, + .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, + .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, ++ .queue_outgoing_page = csv_queue_outgoing_page, + }; + + static int +@@ -1865,6 +1869,163 @@ bool sev_is_gfn_in_unshared_region(unsigned long gfn) + return true; + } + ++static CsvBatchCmdList * ++csv_batch_cmd_list_create(struct kvm_csv_batch_list_node *head, ++ CsvDestroyCmdNodeFn func) ++{ ++ CsvBatchCmdList *csv_batch_cmd_list = ++ g_malloc0(sizeof(*csv_batch_cmd_list)); ++ ++ if (!csv_batch_cmd_list) { ++ return NULL; ++ } ++ ++ csv_batch_cmd_list->head = head; ++ csv_batch_cmd_list->tail = head; ++ csv_batch_cmd_list->destroy_fn = func; ++ ++ return csv_batch_cmd_list; ++} ++ ++static int ++csv_batch_cmd_list_add_after(CsvBatchCmdList *list, ++ struct kvm_csv_batch_list_node *new_node) ++{ ++ list->tail->next_cmd_addr = (__u64)new_node; ++ list->tail = new_node; ++ ++ return 0; ++} ++ ++static struct kvm_csv_batch_list_node * ++csv_batch_cmd_list_node_create(uint64_t cmd_data_addr, uint64_t addr) ++{ ++ struct kvm_csv_batch_list_node *new_node = ++ g_malloc0(sizeof(struct kvm_csv_batch_list_node)); ++ ++ if (!new_node) { ++ return NULL; ++ } ++ ++ new_node->cmd_data_addr = cmd_data_addr; ++ new_node->addr = addr; ++ new_node->next_cmd_addr = 0; ++ ++ return new_node; ++} ++ ++static int csv_batch_cmd_list_destroy(CsvBatchCmdList *list) ++{ ++ struct kvm_csv_batch_list_node *node = list->head; ++ ++ while (node != NULL) { ++ if (list->destroy_fn != NULL) ++ list->destroy_fn((void *)node->cmd_data_addr); ++ ++ list->head = (struct kvm_csv_batch_list_node *)node->next_cmd_addr; ++ g_free(node); ++ node = list->head; ++ } ++ ++ g_free(list); ++ return 0; ++} ++ ++static void send_update_data_free(void *data) ++{ ++ struct kvm_sev_send_update_data *update = ++ (struct kvm_sev_send_update_data *)data; ++ g_free((guchar *)update->hdr_uaddr); ++ g_free((guchar *)update->trans_uaddr); ++ g_free(update); ++} ++ ++static int ++csv_send_queue_data(SevGuestState *s, uint8_t *ptr, ++ uint32_t size, uint64_t addr) ++{ ++ int ret = 0; ++ int fw_error; ++ guchar *trans; ++ guchar *packet_hdr; ++ struct kvm_sev_send_update_data *update; ++ struct kvm_csv_batch_list_node *new_node = NULL; ++ ++ /* If this is first call then query the packet header bytes and allocate ++ * the packet buffer. ++ */ ++ if (s->send_packet_hdr_len < 1) { ++ s->send_packet_hdr_len = sev_send_get_packet_len(&fw_error); ++ if (s->send_packet_hdr_len < 1) { ++ error_report("%s: SEND_UPDATE fw_error=%d '%s'", ++ __func__, fw_error, fw_error_to_str(fw_error)); ++ return 1; ++ } ++ } ++ ++ packet_hdr = g_new(guchar, s->send_packet_hdr_len); ++ memset(packet_hdr, 0, s->send_packet_hdr_len); ++ ++ update = g_new0(struct kvm_sev_send_update_data, 1); ++ ++ /* allocate transport buffer */ ++ trans = g_new(guchar, size); ++ ++ update->hdr_uaddr = (unsigned long)packet_hdr; ++ update->hdr_len = s->send_packet_hdr_len; ++ update->guest_uaddr = (unsigned long)ptr; ++ update->guest_len = size; ++ update->trans_uaddr = (unsigned long)trans; ++ update->trans_len = size; ++ ++ new_node = csv_batch_cmd_list_node_create((uint64_t)update, addr); ++ if (!new_node) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ if (s->csv_batch_cmd_list == NULL) { ++ s->csv_batch_cmd_list = csv_batch_cmd_list_create(new_node, ++ send_update_data_free); ++ if (s->csv_batch_cmd_list == NULL) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } else { ++ /* Add new_node's command address to the last_node */ ++ csv_batch_cmd_list_add_after(s->csv_batch_cmd_list, new_node); ++ } ++ ++ trace_kvm_sev_send_update_data(ptr, trans, size); ++ ++ return ret; ++ ++err: ++ g_free(trans); ++ g_free(update); ++ g_free(packet_hdr); ++ g_free(new_node); ++ if (s->csv_batch_cmd_list) { ++ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list); ++ s->csv_batch_cmd_list = NULL; ++ } ++ return ret; ++} ++ ++int ++csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) ++{ ++ SevGuestState *s = sev_guest; ++ ++ /* Only support for HYGON CSV */ ++ if (!is_hygon_cpu()) { ++ error_report("Only support enqueue pages for HYGON CSV"); ++ return -EINVAL; ++ } ++ ++ return csv_send_queue_data(s, ptr, sz, addr); ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +-- +2.41.0.windows.1 + diff --git a/target-i386-get-set-migrate-GHCB-state.patch b/target-i386-get-set-migrate-GHCB-state.patch new file mode 100644 index 0000000000000000000000000000000000000000..4e09ad530f33c90e9f447a4a9c5e659f41aeb26e --- /dev/null +++ b/target-i386-get-set-migrate-GHCB-state.patch @@ -0,0 +1,190 @@ +From 6a8b58a3ce6dc162cae4b74ca8f39392672e6cba Mon Sep 17 00:00:00 2001 +From: panpingsheng +Date: Sat, 12 Jun 2021 15:15:29 +0800 +Subject: [PATCH] target/i386: get/set/migrate GHCB state + +GHCB state is necessary to CSV2 guest when migrating to target. + +Add GHCB related definition, it also adds corresponding part +to kvm_get/put, and vmstate. + +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 2 ++ + target/i386/cpu.h | 5 +++++ + target/i386/kvm/kvm.c | 11 +++++++++++ + target/i386/kvm/sev-stub.c | 2 ++ + target/i386/machine.c | 24 ++++++++++++++++++++++++ + target/i386/sev.c | 10 ++++++++++ + target/i386/sev.h | 2 ++ + 7 files changed, 56 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index e9cd0ebaf1..e796105b76 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1203,6 +1203,8 @@ struct kvm_ppc_resize_hpt { + + #define KVM_CAP_ARM_TMM 300 + ++#define KVM_CAP_SEV_ES_GHCB 500 ++ + #define KVM_CAP_ARM_VIRT_MSI_BYPASS 799 + + #define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 6993552cd9..a9a646bba2 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -520,6 +520,8 @@ typedef enum X86Seg { + + #define MSR_VM_HSAVE_PA 0xc0010117 + ++#define MSR_AMD64_SEV_ES_GHCB 0xc0010130 ++ + #define MSR_IA32_XFD 0x000001c4 + #define MSR_IA32_XFD_ERR 0x000001c5 + +@@ -1885,6 +1887,9 @@ typedef struct CPUArchState { + + /* Number of dies within this CPU package. */ + unsigned nr_dies; ++ ++ /* GHCB guest physical address info */ ++ uint64_t ghcb_gpa; + } CPUX86State; + + struct kvm_msrs; +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 5730d0e0c0..9e65242739 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -3625,6 +3625,10 @@ static int kvm_put_msrs(X86CPU *cpu, int level) + } + } + ++ if (sev_kvm_has_msr_ghcb) { ++ kvm_msr_entry_add(cpu, MSR_AMD64_SEV_ES_GHCB, env->ghcb_gpa); ++ } ++ + return kvm_buf_set_msrs(cpu); + } + +@@ -3999,6 +4003,10 @@ static int kvm_get_msrs(X86CPU *cpu) + } + } + ++ if (sev_kvm_has_msr_ghcb) { ++ kvm_msr_entry_add(cpu, MSR_AMD64_SEV_ES_GHCB, 0); ++ } ++ + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf); + if (ret < 0) { + return ret; +@@ -4319,6 +4327,9 @@ static int kvm_get_msrs(X86CPU *cpu) + case MSR_ARCH_LBR_INFO_0 ... MSR_ARCH_LBR_INFO_0 + 31: + env->lbr_records[index - MSR_ARCH_LBR_INFO_0].info = msrs[i].data; + break; ++ case MSR_AMD64_SEV_ES_GHCB: ++ env->ghcb_gpa = msrs[i].data; ++ break; + } + } + +diff --git a/target/i386/kvm/sev-stub.c b/target/i386/kvm/sev-stub.c +index 99899688e4..a0aac1117f 100644 +--- a/target/i386/kvm/sev-stub.c ++++ b/target/i386/kvm/sev-stub.c +@@ -14,6 +14,8 @@ + #include "qemu/osdep.h" + #include "sev.h" + ++bool sev_kvm_has_msr_ghcb; ++ + int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + { + /* If we get here, cgs must be some non-SEV thing */ +diff --git a/target/i386/machine.c b/target/i386/machine.c +index a1041ef828..9a1cb8f3b8 100644 +--- a/target/i386/machine.c ++++ b/target/i386/machine.c +@@ -1605,6 +1605,27 @@ static const VMStateDescription vmstate_triple_fault = { + } + }; + ++#if defined(CONFIG_KVM) && defined(TARGET_X86_64) ++static bool msr_ghcb_gpa_needed(void *opaque) ++{ ++ X86CPU *cpu = opaque; ++ CPUX86State *env = &cpu->env; ++ ++ return env->ghcb_gpa != 0; ++} ++ ++static const VMStateDescription vmstate_msr_ghcb_gpa = { ++ .name = "cpu/svm_msr_ghcb_gpa", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .needed = msr_ghcb_gpa_needed, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT64(env.ghcb_gpa, X86CPU), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++#endif ++ + const VMStateDescription vmstate_x86_cpu = { + .name = "cpu", + .version_id = 12, +@@ -1751,6 +1772,9 @@ const VMStateDescription vmstate_x86_cpu = { + #endif + &vmstate_arch_lbr, + &vmstate_triple_fault, ++#if defined(CONFIG_KVM) && defined(TARGET_X86_64) ++ &vmstate_msr_ghcb_gpa, ++#endif + NULL + } + }; +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 6ba71c91d7..7744378112 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -152,6 +152,8 @@ QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0); + static SevGuestState *sev_guest; + static Error *sev_mig_blocker; + ++bool sev_kvm_has_msr_ghcb; ++ + static const char *const sev_fw_errlist[] = { + [SEV_RET_SUCCESS] = "", + [SEV_RET_INVALID_PLATFORM_STATE] = "Platform state is invalid", +@@ -1198,6 +1200,14 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; + QTAILQ_INIT(&sev->shared_regions_list); + ++ /* Determine whether support MSR_AMD64_SEV_ES_GHCB */ ++ if (sev_es_enabled()) { ++ sev_kvm_has_msr_ghcb = ++ kvm_vm_check_extension(kvm_state, KVM_CAP_SEV_ES_GHCB); ++ } else { ++ sev_kvm_has_msr_ghcb = false; ++ } ++ + cgs->ready = true; + + return 0; +diff --git a/target/i386/sev.h b/target/i386/sev.h +index 209c92fd6f..0bfe3879ef 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -78,4 +78,6 @@ void sev_del_migrate_blocker(void); + + int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); + ++extern bool sev_kvm_has_msr_ghcb; ++ + #endif +-- +2.41.0.windows.1 + diff --git a/target-i386-kvm-Fix-the-resettable-info-when-emulate.patch b/target-i386-kvm-Fix-the-resettable-info-when-emulate.patch new file mode 100644 index 0000000000000000000000000000000000000000..171bde129a285f1627ce50f4158834460199bb6d --- /dev/null +++ b/target-i386-kvm-Fix-the-resettable-info-when-emulate.patch @@ -0,0 +1,179 @@ +From 366c11c56875ae053043c48c8b93349c6e3125cc Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Sun, 19 Jun 2022 16:49:45 +0800 +Subject: [PATCH] target/i386/kvm: Fix the resettable info when emulate Hygon + CSV2 guest + +SEV-ES guest will be terminated by QEMU when receive reboot request. +In order to support reboot for CSV2 guest, report resettable in +kvm_arch_cpu_check_are_resettable(). But the CSV2 guest is still not +resettable if it was migrated to target machine. + +Signed-off-by: hanliyang +--- + target/i386/csv-sysemu-stub.c | 16 ++++++++++++++++ + target/i386/csv.c | 20 ++++++++++++++++++++ + target/i386/csv.h | 2 ++ + target/i386/kvm/csv-stub.c | 17 +++++++++++++++++ + target/i386/kvm/kvm.c | 4 ++++ + target/i386/kvm/meson.build | 1 + + target/i386/meson.build | 1 + + target/i386/sev.c | 9 +++++++++ + 8 files changed, 70 insertions(+) + create mode 100644 target/i386/csv-sysemu-stub.c + create mode 100644 target/i386/csv.c + create mode 100644 target/i386/kvm/csv-stub.c + +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +new file mode 100644 +index 0000000000..5874e4cc1d +--- /dev/null ++++ b/target/i386/csv-sysemu-stub.c +@@ -0,0 +1,16 @@ ++/* ++ * QEMU CSV system stub ++ * ++ * Copyright: Hygon Info Technologies Ltd. 2022 ++ * ++ * Author: ++ * Jiang Xin ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "sev.h" ++#include "csv.h" +diff --git a/target/i386/csv.c b/target/i386/csv.c +new file mode 100644 +index 0000000000..88fb05ac37 +--- /dev/null ++++ b/target/i386/csv.c +@@ -0,0 +1,20 @@ ++/* ++ * QEMU CSV support ++ * ++ * Copyright: Hygon Info Technologies Ltd. 2022 ++ * ++ * Author: ++ * Jiang Xin ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++ ++#include "cpu.h" ++#include "sev.h" ++#include "csv.h" ++ ++bool csv_kvm_cpu_reset_inhibit; +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 47741a0a4f..ac4bb5bee1 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -46,6 +46,8 @@ static bool __attribute__((unused)) is_hygon_cpu(void) + + #define CSV_OUTGOING_PAGE_WINDOW_SIZE (4094 * TARGET_PAGE_SIZE) + ++extern bool csv_kvm_cpu_reset_inhibit; ++ + typedef struct CsvBatchCmdList CsvBatchCmdList; + typedef void (*CsvDestroyCmdNodeFn) (void *data); + +diff --git a/target/i386/kvm/csv-stub.c b/target/i386/kvm/csv-stub.c +new file mode 100644 +index 0000000000..4d1376f268 +--- /dev/null ++++ b/target/i386/kvm/csv-stub.c +@@ -0,0 +1,17 @@ ++/* ++ * QEMU CSV stub ++ * ++ * Copyright Hygon Info Technologies Ltd. 2024 ++ * ++ * Authors: ++ * Han Liyang ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "csv.h" ++ ++bool csv_kvm_cpu_reset_inhibit; +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 9e65242739..2866a6d0ec 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -32,6 +32,7 @@ + #include "sysemu/runstate.h" + #include "kvm_i386.h" + #include "sev.h" ++#include "csv.h" + #include "xen-emu.h" + #include "hyperv.h" + #include "hyperv-proto.h" +@@ -5710,6 +5711,9 @@ bool kvm_has_waitpkg(void) + + bool kvm_arch_cpu_check_are_resettable(void) + { ++ if (is_hygon_cpu()) ++ return !csv_kvm_cpu_reset_inhibit; ++ + return !sev_es_enabled(); + } + +diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build +index 84d9143e60..3c3f8cf93c 100644 +--- a/target/i386/kvm/meson.build ++++ b/target/i386/kvm/meson.build +@@ -8,6 +8,7 @@ i386_kvm_ss.add(files( + i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen-emu.c')) + + i386_kvm_ss.add(when: 'CONFIG_SEV', if_false: files('sev-stub.c')) ++i386_kvm_ss.add(when: 'CONFIG_CSV', if_false: files('csv-stub.c')) + + i386_system_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c')) + +diff --git a/target/i386/meson.build b/target/i386/meson.build +index 7c74bfa859..594a0a6abf 100644 +--- a/target/i386/meson.build ++++ b/target/i386/meson.build +@@ -21,6 +21,7 @@ i386_system_ss.add(files( + 'cpu-sysemu.c', + )) + i386_system_ss.add(when: 'CONFIG_SEV', if_true: files('sev.c'), if_false: files('sev-sysemu-stub.c')) ++i386_system_ss.add(when: 'CONFIG_CSV', if_true: files('csv.c'), if_false: files('csv-sysemu-stub.c')) + + i386_user_ss = ss.source_set() + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 7744378112..2c6aecd1a3 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1190,6 +1190,15 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + error_setg(errp, "%s: failed to create encryption context", __func__); + goto err; + } ++ } else { ++ /* ++ * The CSV2 guest is not resettable after migrated to target machine, ++ * set csv_kvm_cpu_reset_inhibit to true to indicate the CSV2 guest is ++ * not resettable. ++ */ ++ if (is_hygon_cpu() && sev_es_enabled()) { ++ csv_kvm_cpu_reset_inhibit = true; ++ } + } + + ram_block_notifier_add(&sev_ram_notifier); +-- +2.41.0.windows.1 + diff --git a/target-i386-no-single-step-exception-after-MOV-or-PO.patch b/target-i386-no-single-step-exception-after-MOV-or-PO.patch new file mode 100644 index 0000000000000000000000000000000000000000..994472363319107b7c033b993655b8ac706ab263 --- /dev/null +++ b/target-i386-no-single-step-exception-after-MOV-or-PO.patch @@ -0,0 +1,34 @@ +From 004e0a984118380ff89ceaabb6ace1ebbfb1eb6d Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 11:08:13 +0800 +Subject: [PATCH] target/i386: no single-step exception after MOV or POP SS + +cherry picked from commitd f0f0136abba688a6516647a79cc91e03fad6d5d7 + +Intel SDM 18.3.1.4 "If an occurrence of the MOV or POP instruction +loads the SS register executes with EFLAGS.TF = 1, no single-step debug +exception occurs following the MOV or POP instruction." + +Cc: qemu-stable@nongnu.org +Signed-off-by: Paolo Bonzini +Signed-off-by: Gao Jiazhen +--- + target/i386/tcg/translate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c +index 037bc47e7c..dc672d7995 100644 +--- a/target/i386/tcg/translate.c ++++ b/target/i386/tcg/translate.c +@@ -2790,7 +2790,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, bool jr) + if (recheck_tf) { + gen_helper_rechecking_single_step(tcg_env); + tcg_gen_exit_tb(NULL, 0); +- } else if (s->flags & HF_TF_MASK) { ++ } else if ((s->flags & HF_TF_MASK) && !inhibit) { + gen_helper_single_step(tcg_env); + } else if (jr) { + tcg_gen_lookup_and_goto_ptr(); +-- +2.41.0.windows.1 + diff --git a/target-i386-sev-Clear-shared_regions_list-when-reboo.patch b/target-i386-sev-Clear-shared_regions_list-when-reboo.patch new file mode 100644 index 0000000000000000000000000000000000000000..aef897233ccbf5299e75269299369f7682ae3d4d --- /dev/null +++ b/target-i386-sev-Clear-shared_regions_list-when-reboo.patch @@ -0,0 +1,57 @@ +From e98147762cb47645c590ee000dbc12c654a6cc2d Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Sun, 16 Jan 2022 19:57:58 -0500 +Subject: [PATCH] target/i386: sev: Clear shared_regions_list when reboot CSV + Guest + +Also fix memory leak in sev_remove_shared_regions_list(). + +Signed-off-by: hanliyang +--- + target/i386/kvm/kvm.c | 5 +++++ + target/i386/sev.c | 5 +++-- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index a5a755db01..5730d0e0c0 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -2270,6 +2270,11 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) + env->mp_state = KVM_MP_STATE_RUNNABLE; + } + ++ if (cpu_is_bsp(cpu) && ++ sev_enabled() && has_map_gpa_range) { ++ sev_remove_shared_regions_list(0, -1); ++ } ++ + /* enabled by default */ + env->poll_control_msr = 1; + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 6ccb22c00a..0b0f589aee 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1694,9 +1694,9 @@ int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) + int sev_remove_shared_regions_list(unsigned long start, unsigned long end) + { + SevGuestState *s = sev_guest; +- struct shared_region *pos; ++ struct shared_region *pos, *next_pos; + +- QTAILQ_FOREACH(pos, &s->shared_regions_list, list) { ++ QTAILQ_FOREACH_SAFE(pos, &s->shared_regions_list, list, next_pos) { + unsigned long l, r; + unsigned long curr_gfn_end = pos->gfn_end; + +@@ -1710,6 +1710,7 @@ int sev_remove_shared_regions_list(unsigned long start, unsigned long end) + if (l <= r) { + if (pos->gfn_start == l && pos->gfn_end == r) { + QTAILQ_REMOVE(&s->shared_regions_list, pos, list); ++ g_free(pos); + } else if (l == pos->gfn_start) { + pos->gfn_start = r; + } else if (r == pos->gfn_end) { +-- +2.41.0.windows.1 + diff --git a/target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch b/target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad0f2796dfe73b930a4890facb59d7d0738f76fd --- /dev/null +++ b/target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch @@ -0,0 +1,59 @@ +From ccca5618025567c4168630459b90bf11bf96cca4 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Wed, 31 Jan 2024 07:26:57 +0800 +Subject: [PATCH] target/i386: sev: Return 0 if sev_send_get_packet_len() fails + +The send_packet_hdr_len of struct SEVState is of type size_t +which is an unsigned class type. If the send_packet_hdr_len +is assigned as -1, then it will be a huge number and the QEMU +process will crash when allocating packet buffer with the +huge size. + +For example, the following code could cause crash described +above. + + ``` + static int + sev_send_update_data(SEVState *s, QEMUFile *f, uint8_t *ptr, uint32_t size, + uint64_t *bytes_sent) + { + + ...... + + if (!s->send_packet_hdr) { + s->send_packet_hdr_len = sev_send_get_packet_len(&fw_error); + if (s->send_packet_hdr_len < 1) { + error_report("%s: SEND_UPDATE fw_error=%d '%s'", + __func__, fw_error, fw_error_to_str(fw_error)); + return 1; + } + + s->send_packet_hdr = g_new(gchar, s->send_packet_hdr_len); + } + + ...... + + } + ``` + +Signed-off-by: hanliyang +--- + target/i386/sev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 98b0d3937a..6ccb22c00a 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1492,7 +1492,7 @@ sev_send_get_packet_len(int *fw_err) + ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_UPDATE_DATA, + &update, fw_err); + if (*fw_err != SEV_RET_INVALID_LEN) { +- ret = -1; ++ ret = 0; + error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", + __func__, ret, *fw_err, fw_error_to_str(*fw_err)); + goto err; +-- +2.41.0.windows.1 + diff --git a/target-i386-sev-add-support-to-encrypt-the-outgoing-.patch b/target-i386-sev-add-support-to-encrypt-the-outgoing-.patch new file mode 100644 index 0000000000000000000000000000000000000000..44d5dcfb42fce2386fdbc4c7bacf8f1dd8814b8c --- /dev/null +++ b/target-i386-sev-add-support-to-encrypt-the-outgoing-.patch @@ -0,0 +1,319 @@ +From 0a7dde8450d9b6a6d0c75cef11e4bbff65e95edc Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Tue, 27 Jul 2021 12:55:25 +0000 +Subject: [PATCH] target/i386: sev: add support to encrypt the outgoing page + +cherry-picked from https://github.com/AMDESE/qemu/commit/5187c6f86bd. + +The sev_save_outgoing_page() provide the implementation to encrypt the +guest private pages during the transit. The routines uses the SEND_START +command to create the outgoing encryption context on the first call then +uses the SEND_UPDATE_DATA command to encrypt the data before writing it +to the socket. While encrypting the data SEND_UPDATE_DATA produces some +metadata (e.g MAC, IV). The metadata is also sent to the target machine. +After migration is completed, we issue the SEND_FINISH command to transition +the SEV guest state from sending to unrunnable state. + +Signed-off-by: Brijesh Singh +Co-developed-by: Ashish Kalra +Signed-off-by: Ashish Kalra +[ Fix conflict. ] +Signed-off-by: hanliyang +--- + target/i386/sev.c | 219 +++++++++++++++++++++++++++++++++++++++ + target/i386/sev.h | 2 + + target/i386/trace-events | 3 + + 3 files changed, 224 insertions(+) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 65984f013a..e1fa0ec5e5 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -31,6 +31,8 @@ + #include "sysemu/runstate.h" + #include "trace.h" + #include "migration/blocker.h" ++#include "migration/qemu-file.h" ++#include "migration/misc.h" + #include "qom/object.h" + #include "monitor/monitor.h" + #include "monitor/hmp-target.h" +@@ -79,6 +81,8 @@ struct SevGuestState { + size_t remote_plat_cert_len; + guchar *amd_cert; + size_t amd_cert_len; ++ gchar *send_packet_hdr; ++ size_t send_packet_hdr_len; + + uint32_t reset_cs; + uint32_t reset_ip; +@@ -167,6 +171,7 @@ static const char *const sev_fw_errlist[] = { + + static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .save_setup = sev_save_setup, ++ .save_outgoing_page = sev_save_outgoing_page, + }; + + static int +@@ -960,6 +965,38 @@ error: + return 1; + } + ++static void ++sev_send_finish(void) ++{ ++ int ret, error; ++ ++ trace_kvm_sev_send_finish(); ++ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_FINISH, 0, &error); ++ if (ret) { ++ error_report("%s: SEND_FINISH ret=%d fw_error=%d '%s'", ++ __func__, ret, error, fw_error_to_str(error)); ++ } ++ ++ g_free(sev_guest->send_packet_hdr); ++ sev_set_guest_state(sev_guest, SEV_STATE_RUNNING); ++} ++ ++static void ++sev_migration_state_notifier(Notifier *notifier, void *data) ++{ ++ MigrationState *s = data; ++ ++ if (migration_has_finished(s) || ++ migration_in_postcopy_after_devices(s) || ++ migration_has_failed(s)) { ++ if (sev_check_state(sev_guest, SEV_STATE_SEND_UPDATE)) { ++ sev_send_finish(); ++ } ++ } ++} ++ ++static Notifier sev_migration_state; ++ + int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + { + SevGuestState *sev +@@ -1075,6 +1112,7 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + ram_block_notifier_add(&sev_ram_notifier); + qemu_add_machine_init_done_notifier(&sev_machine_done_notify); + qemu_add_vm_change_state_handler(sev_vm_state_change, sev); ++ migration_add_notifier(&sev_migration_state, sev_migration_state_notifier); + + cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; + +@@ -1317,6 +1355,187 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size) + return 0; + } + ++static int ++sev_get_send_session_length(void) ++{ ++ int ret, fw_err = 0; ++ struct kvm_sev_send_start start = {}; ++ ++ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_START, &start, &fw_err); ++ if (fw_err != SEV_RET_INVALID_LEN) { ++ ret = -1; ++ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_err, fw_error_to_str(fw_err)); ++ goto err; ++ } ++ ++ ret = start.session_len; ++err: ++ return ret; ++} ++ ++static int ++sev_send_start(SevGuestState *s, QEMUFile *f, uint64_t *bytes_sent) ++{ ++ gsize pdh_len = 0, plat_cert_len; ++ int session_len, ret, fw_error; ++ struct kvm_sev_send_start start = { }; ++ guchar *pdh = NULL, *plat_cert = NULL, *session = NULL; ++ Error *local_err = NULL; ++ ++ if (!s->remote_pdh || !s->remote_plat_cert || !s->amd_cert_len) { ++ error_report("%s: missing remote PDH or PLAT_CERT", __func__); ++ return 1; ++ } ++ ++ start.pdh_cert_uaddr = (uintptr_t) s->remote_pdh; ++ start.pdh_cert_len = s->remote_pdh_len; ++ ++ start.plat_certs_uaddr = (uintptr_t)s->remote_plat_cert; ++ start.plat_certs_len = s->remote_plat_cert_len; ++ ++ start.amd_certs_uaddr = (uintptr_t)s->amd_cert; ++ start.amd_certs_len = s->amd_cert_len; ++ ++ /* get the session length */ ++ session_len = sev_get_send_session_length(); ++ if (session_len < 0) { ++ ret = 1; ++ goto err; ++ } ++ ++ session = g_new0(guchar, session_len); ++ start.session_uaddr = (unsigned long)session; ++ start.session_len = session_len; ++ ++ /* Get our PDH certificate */ ++ ret = sev_get_pdh_info(s->sev_fd, &pdh, &pdh_len, ++ &plat_cert, &plat_cert_len, &local_err); ++ if (ret) { ++ error_report("Failed to get our PDH cert"); ++ goto err; ++ } ++ ++ trace_kvm_sev_send_start(start.pdh_cert_uaddr, start.pdh_cert_len, ++ start.plat_certs_uaddr, start.plat_certs_len, ++ start.amd_certs_uaddr, start.amd_certs_len); ++ ++ ret = sev_ioctl(s->sev_fd, KVM_SEV_SEND_START, &start, &fw_error); ++ if (ret < 0) { ++ error_report("%s: SEND_START ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++ qemu_put_be32(f, start.policy); ++ qemu_put_be32(f, pdh_len); ++ qemu_put_buffer(f, (uint8_t *)pdh, pdh_len); ++ qemu_put_be32(f, start.session_len); ++ qemu_put_buffer(f, (uint8_t *)start.session_uaddr, start.session_len); ++ *bytes_sent = 12 + pdh_len + start.session_len; ++ ++ sev_set_guest_state(s, SEV_STATE_SEND_UPDATE); ++ ++err: ++ g_free(pdh); ++ g_free(plat_cert); ++ return ret; ++} ++ ++static int ++sev_send_get_packet_len(int *fw_err) ++{ ++ int ret; ++ struct kvm_sev_send_update_data update = { 0, }; ++ ++ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_UPDATE_DATA, ++ &update, fw_err); ++ if (*fw_err != SEV_RET_INVALID_LEN) { ++ ret = -1; ++ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", ++ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); ++ goto err; ++ } ++ ++ ret = update.hdr_len; ++ ++err: ++ return ret; ++} ++ ++static int ++sev_send_update_data(SevGuestState *s, QEMUFile *f, uint8_t *ptr, uint32_t size, ++ uint64_t *bytes_sent) ++{ ++ int ret, fw_error; ++ guchar *trans; ++ struct kvm_sev_send_update_data update = { }; ++ ++ /* ++ * If this is first call then query the packet header bytes and allocate ++ * the packet buffer. ++ */ ++ if (!s->send_packet_hdr) { ++ s->send_packet_hdr_len = sev_send_get_packet_len(&fw_error); ++ if (s->send_packet_hdr_len < 1) { ++ error_report("%s: SEND_UPDATE fw_error=%d '%s'", ++ __func__, fw_error, fw_error_to_str(fw_error)); ++ return 1; ++ } ++ ++ s->send_packet_hdr = g_new(gchar, s->send_packet_hdr_len); ++ } ++ ++ /* allocate transport buffer */ ++ trans = g_new(guchar, size); ++ ++ update.hdr_uaddr = (uintptr_t)s->send_packet_hdr; ++ update.hdr_len = s->send_packet_hdr_len; ++ update.guest_uaddr = (uintptr_t)ptr; ++ update.guest_len = size; ++ update.trans_uaddr = (uintptr_t)trans; ++ update.trans_len = size; ++ ++ trace_kvm_sev_send_update_data(ptr, trans, size); ++ ++ ret = sev_ioctl(s->sev_fd, KVM_SEV_SEND_UPDATE_DATA, &update, &fw_error); ++ if (ret) { ++ error_report("%s: SEND_UPDATE_DATA ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++ qemu_put_be32(f, update.hdr_len); ++ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len); ++ *bytes_sent = 4 + update.hdr_len; ++ ++ qemu_put_be32(f, update.trans_len); ++ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ *bytes_sent += (4 + update.trans_len); ++ ++err: ++ g_free(trans); ++ return ret; ++} ++ ++int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, ++ uint32_t sz, uint64_t *bytes_sent) ++{ ++ SevGuestState *s = sev_guest; ++ ++ /* ++ * If this is a first buffer then create outgoing encryption context ++ * and write our PDH, policy and session data. ++ */ ++ if (!sev_check_state(s, SEV_STATE_SEND_UPDATE) && ++ sev_send_start(s, f, bytes_sent)) { ++ error_report("Failed to create outgoing context"); ++ return 1; ++ } ++ ++ return sev_send_update_data(s, f, ptr, sz, bytes_sent); ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +diff --git a/target/i386/sev.h b/target/i386/sev.h +index e96de021f5..463e94bb81 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -53,6 +53,8 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp); + int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp); + int sev_save_setup(const char *pdh, const char *plat_cert, + const char *amd_cert); ++int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, ++ uint32_t size, uint64_t *bytes_sent); + int sev_inject_launch_secret(const char *hdr, const char *secret, + uint64_t gpa, Error **errp); + +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 2cd8726eeb..e8d4aec125 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -11,3 +11,6 @@ kvm_sev_launch_measurement(const char *value) "data %s" + kvm_sev_launch_finish(void) "" + kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d" + kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s" ++kvm_sev_send_start(uint64_t pdh, int l1, uint64_t plat, int l2, uint64_t amd, int l3) "pdh 0x%" PRIx64 " len %d plat 0x%" PRIx64 " len %d amd 0x%" PRIx64 " len %d" ++kvm_sev_send_update_data(void *src, void *dst, int len) "guest %p trans %p len %d" ++kvm_sev_send_finish(void) "" +-- +2.41.0.windows.1 + diff --git a/target-i386-sev-add-support-to-load-incoming-encrypt.patch b/target-i386-sev-add-support-to-load-incoming-encrypt.patch new file mode 100644 index 0000000000000000000000000000000000000000..4407508001055b7469e45e32c7a1f8139016562d --- /dev/null +++ b/target-i386-sev-add-support-to-load-incoming-encrypt.patch @@ -0,0 +1,221 @@ +From 778457c2f0f91b6a52e5db02dd3dc1f35ae64526 Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Tue, 27 Jul 2021 13:00:50 +0000 +Subject: [PATCH] target/i386: sev: add support to load incoming encrypted page + +cherry-picked from https://github.com/AMDESE/qemu/commit/e86e5dccb045. + +The sev_load_incoming_page() provide the implementation to read the +incoming guest private pages from the socket and load it into the guest +memory. The routines uses the RECEIVE_START command to create the +incoming encryption context on the first call then uses the +RECEIEVE_UPDATE_DATA command to load the encrypted pages into the guest +memory. After migration is completed, we issue the RECEIVE_FINISH command +to transition the SEV guest to the runnable state so that it can be +executed. + +Signed-off-by: Brijesh Singh +Co-developed-by: Ashish Kalra +Signed-off-by: Ashish Kalra +[ Fix conflicts. ] +Signed-off-by: hanliyang +--- + target/i386/sev.c | 137 ++++++++++++++++++++++++++++++++++++++- + target/i386/sev.h | 1 + + target/i386/trace-events | 3 + + 3 files changed, 140 insertions(+), 1 deletion(-) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index e1fa0ec5e5..de1a4b271e 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -172,6 +172,7 @@ static const char *const sev_fw_errlist[] = { + static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + .save_setup = sev_save_setup, + .save_outgoing_page = sev_save_outgoing_page, ++ .load_incoming_page = sev_load_incoming_page, + }; + + static int +@@ -911,13 +912,33 @@ sev_launch_finish(SevGuestState *sev) + migrate_add_blocker(&sev_mig_blocker, &error_fatal); + } + ++static int ++sev_receive_finish(SevGuestState *s) ++{ ++ int error, ret = 1; ++ ++ trace_kvm_sev_receive_finish(); ++ ret = sev_ioctl(s->sev_fd, KVM_SEV_RECEIVE_FINISH, 0, &error); ++ if (ret) { ++ error_report("%s: RECEIVE_FINISH ret=%d fw_error=%d '%s'", ++ __func__, ret, error, fw_error_to_str(error)); ++ goto err; ++ } ++ ++ sev_set_guest_state(s, SEV_STATE_RUNNING); ++err: ++ return ret; ++} ++ + static void + sev_vm_state_change(void *opaque, bool running, RunState state) + { + SevGuestState *sev = opaque; + + if (running) { +- if (!sev_check_state(sev, SEV_STATE_RUNNING)) { ++ if (sev_check_state(sev, SEV_STATE_RECEIVE_UPDATE)) { ++ sev_receive_finish(sev); ++ } else if (!sev_check_state(sev, SEV_STATE_RUNNING)) { + sev_launch_finish(sev); + } + } +@@ -1536,6 +1557,120 @@ int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, + return sev_send_update_data(s, f, ptr, sz, bytes_sent); + } + ++static int ++sev_receive_start(SevGuestState *sev, QEMUFile *f) ++{ ++ int ret = 1; ++ int fw_error; ++ struct kvm_sev_receive_start start = { }; ++ gchar *session = NULL, *pdh_cert = NULL; ++ ++ /* get SEV guest handle */ ++ start.handle = object_property_get_int(OBJECT(sev), "handle", ++ &error_abort); ++ ++ /* get the source policy */ ++ start.policy = qemu_get_be32(f); ++ ++ /* get source PDH key */ ++ start.pdh_len = qemu_get_be32(f); ++ if (!check_blob_length(start.pdh_len)) { ++ return 1; ++ } ++ ++ pdh_cert = g_new(gchar, start.pdh_len); ++ qemu_get_buffer(f, (uint8_t *)pdh_cert, start.pdh_len); ++ start.pdh_uaddr = (uintptr_t)pdh_cert; ++ ++ /* get source session data */ ++ start.session_len = qemu_get_be32(f); ++ if (!check_blob_length(start.session_len)) { ++ return 1; ++ } ++ session = g_new(gchar, start.session_len); ++ qemu_get_buffer(f, (uint8_t *)session, start.session_len); ++ start.session_uaddr = (uintptr_t)session; ++ ++ trace_kvm_sev_receive_start(start.policy, session, pdh_cert); ++ ++ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_RECEIVE_START, ++ &start, &fw_error); ++ if (ret < 0) { ++ error_report("Error RECEIVE_START ret=%d fw_error=%d '%s'", ++ ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++ object_property_set_int(OBJECT(sev), "handle", start.handle, &error_abort); ++ sev_set_guest_state(sev, SEV_STATE_RECEIVE_UPDATE); ++err: ++ g_free(session); ++ g_free(pdh_cert); ++ ++ return ret; ++} ++ ++static int sev_receive_update_data(QEMUFile *f, uint8_t *ptr) ++{ ++ int ret = 1, fw_error = 0; ++ gchar *hdr = NULL, *trans = NULL; ++ struct kvm_sev_receive_update_data update = {}; ++ ++ /* get packet header */ ++ update.hdr_len = qemu_get_be32(f); ++ if (!check_blob_length(update.hdr_len)) { ++ return 1; ++ } ++ ++ hdr = g_new(gchar, update.hdr_len); ++ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); ++ update.hdr_uaddr = (uintptr_t)hdr; ++ ++ /* get transport buffer */ ++ update.trans_len = qemu_get_be32(f); ++ if (!check_blob_length(update.trans_len)) { ++ goto err; ++ } ++ ++ trans = g_new(gchar, update.trans_len); ++ update.trans_uaddr = (uintptr_t)trans; ++ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ ++ update.guest_uaddr = (uintptr_t) ptr; ++ update.guest_len = update.trans_len; ++ ++ trace_kvm_sev_receive_update_data(trans, ptr, update.guest_len, ++ hdr, update.hdr_len); ++ ++ ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_RECEIVE_UPDATE_DATA, ++ &update, &fw_error); ++ if (ret) { ++ error_report("Error RECEIVE_UPDATE_DATA ret=%d fw_error=%d '%s'", ++ ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++err: ++ g_free(trans); ++ g_free(hdr); ++ return ret; ++} ++ ++int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr) ++{ ++ SevGuestState *s = sev_guest; ++ ++ /* ++ * If this is first buffer and SEV is not in recieiving state then ++ * use RECEIVE_START command to create a encryption context. ++ */ ++ if (!sev_check_state(s, SEV_STATE_RECEIVE_UPDATE) && ++ sev_receive_start(s, f)) { ++ return 1; ++ } ++ ++ return sev_receive_update_data(f, ptr); ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +diff --git a/target/i386/sev.h b/target/i386/sev.h +index 463e94bb81..d94da2956b 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -55,6 +55,7 @@ int sev_save_setup(const char *pdh, const char *plat_cert, + const char *amd_cert); + int sev_save_outgoing_page(QEMUFile *f, uint8_t *ptr, + uint32_t size, uint64_t *bytes_sent); ++int sev_load_incoming_page(QEMUFile *f, uint8_t *ptr); + int sev_inject_launch_secret(const char *hdr, const char *secret, + uint64_t gpa, Error **errp); + +diff --git a/target/i386/trace-events b/target/i386/trace-events +index e8d4aec125..475de65ad4 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -14,3 +14,6 @@ kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data + kvm_sev_send_start(uint64_t pdh, int l1, uint64_t plat, int l2, uint64_t amd, int l3) "pdh 0x%" PRIx64 " len %d plat 0x%" PRIx64 " len %d amd 0x%" PRIx64 " len %d" + kvm_sev_send_update_data(void *src, void *dst, int len) "guest %p trans %p len %d" + kvm_sev_send_finish(void) "" ++kvm_sev_receive_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p" ++kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_len) "guest %p trans %p len %d hdr %p hdr_len %d" ++kvm_sev_receive_finish(void) "" +-- +2.41.0.windows.1 + diff --git a/target-i386-sev-do-not-create-launch-context-for-an-.patch b/target-i386-sev-do-not-create-launch-context-for-an-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e52e4634abeced5b869b4a27b53416d5cb1f296 --- /dev/null +++ b/target-i386-sev-do-not-create-launch-context-for-an-.patch @@ -0,0 +1,49 @@ +From c8a6d5f18c45079575b707db8f017cce22acc970 Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Tue, 27 Jul 2021 12:16:09 +0000 +Subject: [PATCH] target/i386: sev: do not create launch context for an + incoming guest + +cherry-picked from https://github.com/AMDESE/qemu/commit/b85694233495. + +The LAUNCH_START is used for creating an encryption context to encrypt +newly created guest, for an incoming guest the RECEIVE_START should be +used. + +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Brijesh Singh +Signed-off-by: Ashish Kalra +[ Fix conflict. ] +Signed-off-by: hanliyang +--- + target/i386/sev.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 10233511cf..65984f013a 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1060,10 +1060,16 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + goto err; + } + +- ret = sev_launch_start(sev); +- if (ret) { +- error_setg(errp, "%s: failed to create encryption context", __func__); +- goto err; ++ /* ++ * The LAUNCH context is used for new guest, if its an incoming guest ++ * then RECEIVE context will be created after the connection is established. ++ */ ++ if (!runstate_check(RUN_STATE_INMIGRATE)) { ++ ret = sev_launch_start(sev); ++ if (ret) { ++ error_setg(errp, "%s: failed to create encryption context", __func__); ++ goto err; ++ } + } + + ram_block_notifier_add(&sev_ram_notifier); +-- +2.41.0.windows.1 + diff --git a/target-i386-sev-provide-callback-to-setup-outgoing-c.patch b/target-i386-sev-provide-callback-to-setup-outgoing-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..76cf1bd7a10a973a7aba7250011c92964c2bc230 --- /dev/null +++ b/target-i386-sev-provide-callback-to-setup-outgoing-c.patch @@ -0,0 +1,135 @@ +From f6753191237118294d04193908db503bb87619f7 Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Tue, 27 Jul 2021 12:10:23 +0000 +Subject: [PATCH] target/i386: sev: provide callback to setup outgoing context + +cherry-picked from https://github.com/AMDESE/qemu/commit/7521883afc0. + +The user provides the target machine's Platform Diffie-Hellman key (PDH) +and certificate chain before starting the SEV guest migration. Cache the +certificate chain as we need them while creating the outgoing context. + +Signed-off-by: Brijesh Singh +Co-developed-by: Ashish Kalra +Signed-off-by: Ashish Kalra +[ Fix conflict. ] +Signed-off-by: hanliyang +--- + target/i386/sev.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ + target/i386/sev.h | 2 ++ + 2 files changed, 61 insertions(+) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 1a9d1db7a8..10233511cf 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -73,6 +73,12 @@ struct SevGuestState { + int sev_fd; + SevState state; + gchar *measurement; ++ guchar *remote_pdh; ++ size_t remote_pdh_len; ++ guchar *remote_plat_cert; ++ size_t remote_plat_cert_len; ++ guchar *amd_cert; ++ size_t amd_cert_len; + + uint32_t reset_cs; + uint32_t reset_ip; +@@ -157,6 +163,12 @@ static const char *const sev_fw_errlist[] = { + + #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist) + ++#define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */ ++ ++static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { ++ .save_setup = sev_save_setup, ++}; ++ + static int + sev_ioctl(int fd, int cmd, void *data, int *error) + { +@@ -906,6 +918,48 @@ sev_vm_state_change(void *opaque, bool running, RunState state) + } + } + ++static inline bool check_blob_length(size_t value) ++{ ++ if (value > SEV_FW_BLOB_MAX_SIZE) { ++ error_report("invalid length max=%d got=%ld", ++ SEV_FW_BLOB_MAX_SIZE, value); ++ return false; ++ } ++ ++ return true; ++} ++ ++int sev_save_setup(const char *pdh, const char *plat_cert, ++ const char *amd_cert) ++{ ++ SevGuestState *s = sev_guest; ++ ++ s->remote_pdh = g_base64_decode(pdh, &s->remote_pdh_len); ++ if (!check_blob_length(s->remote_pdh_len)) { ++ goto error; ++ } ++ ++ s->remote_plat_cert = g_base64_decode(plat_cert, ++ &s->remote_plat_cert_len); ++ if (!check_blob_length(s->remote_plat_cert_len)) { ++ goto error; ++ } ++ ++ s->amd_cert = g_base64_decode(amd_cert, &s->amd_cert_len); ++ if (!check_blob_length(s->amd_cert_len)) { ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ g_free(s->remote_pdh); ++ g_free(s->remote_plat_cert); ++ g_free(s->amd_cert); ++ ++ return 1; ++} ++ + int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + { + SevGuestState *sev +@@ -920,6 +974,9 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + return 0; + } + ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(cgs)); ++ + ret = ram_block_discard_disable(true); + if (ret) { + error_report("%s: cannot disable RAM discard", __func__); +@@ -1013,6 +1070,8 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + qemu_add_machine_init_done_notifier(&sev_machine_done_notify); + qemu_add_vm_change_state_handler(sev_vm_state_change, sev); + ++ cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; ++ + cgs->ready = true; + + return 0; +diff --git a/target/i386/sev.h b/target/i386/sev.h +index e7499c95b1..e96de021f5 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -51,6 +51,8 @@ uint32_t sev_get_reduced_phys_bits(void); + bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp); + + int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp); ++int sev_save_setup(const char *pdh, const char *plat_cert, ++ const char *amd_cert); + int sev_inject_launch_secret(const char *hdr, const char *secret, + uint64_t gpa, Error **errp); + +-- +2.41.0.windows.1 + diff --git a/target-loongarch-fix-a-wrong-print-in-cpu-dump.patch b/target-loongarch-fix-a-wrong-print-in-cpu-dump.patch new file mode 100644 index 0000000000000000000000000000000000000000..4a5f57893512db2bba01e86bc9d608831619f14b --- /dev/null +++ b/target-loongarch-fix-a-wrong-print-in-cpu-dump.patch @@ -0,0 +1,39 @@ +From 4f76ccdc5bdad57b9c70da7a4fc00502cc335060 Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 11:27:12 +0800 +Subject: [PATCH] target/loongarch: fix a wrong print in cpu dump + +cherry picked from commit 78f932ea1f7b3b9b0ac628dc2a91281318fe51fa + +description: + loongarch_cpu_dump_state() want to dump all loongarch cpu +state registers, but there is a tiny typographical error when +printing "PRCFG2". + +Cc: qemu-stable@nongnu.org +Signed-off-by: lanyanzhi +Reviewed-by: Richard Henderson +Reviewed-by: Song Gao +Message-Id: <20240604073831.666690-1-lanyanzhi22b@ict.ac.cn> +Signed-off-by: Song Gao +Signed-off-by: Gao Jiazhen +--- + target/loongarch/cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c +index 8e7c8332da..f7b5dae7ed 100644 +--- a/target/loongarch/cpu.c ++++ b/target/loongarch/cpu.c +@@ -802,7 +802,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) + qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY); + qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 "," + " PRCFG3=%016" PRIx64 "\n", +- env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); ++ env->CSR_PRCFG1, env->CSR_PRCFG2, env->CSR_PRCFG3); + qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY); + qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV); + qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA); +-- +2.41.0.windows.1 + diff --git a/update-docs-tools-virtfs-proxy-helper.rst.patch b/update-docs-tools-virtfs-proxy-helper.rst.patch new file mode 100644 index 0000000000000000000000000000000000000000..aadfac66231a0d99f3acc042e0da54fceb5e4596 --- /dev/null +++ b/update-docs-tools-virtfs-proxy-helper.rst.patch @@ -0,0 +1,27 @@ +From c31f85b015326ad6619c707ada5cea2713970741 Mon Sep 17 00:00:00 2001 +From: lixiang_yewu +Date: Mon, 2 Sep 2024 07:35:57 +0000 +Subject: [PATCH] update docs/tools/virtfs-proxy-helper.rst. This place is + spelled wrong. + +Signed-off-by: lixiang_yewu +--- + docs/tools/virtfs-proxy-helper.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/tools/virtfs-proxy-helper.rst b/docs/tools/virtfs-proxy-helper.rst +index bd310ebb07..175b480926 100644 +--- a/docs/tools/virtfs-proxy-helper.rst ++++ b/docs/tools/virtfs-proxy-helper.rst +@@ -55,7 +55,7 @@ The following options are supported: + .. option:: -f, --fd SOCKET_ID + + Use given file descriptor as socket descriptor for communicating with +- qemu proxy fs drier. Usually a helper like libvirt will create ++ qemu proxy fs driver. Usually a helper like libvirt will create + socketpair and pass one of the fds as parameter to this option. + + .. option:: -s, --socket SOCKET_FILE +-- +2.41.0.windows.1 + diff --git a/update-io-trace-events.patch b/update-io-trace-events.patch new file mode 100644 index 0000000000000000000000000000000000000000..b9b66a88d77c66dc5c34b8cb79115b39dd7603b8 --- /dev/null +++ b/update-io-trace-events.patch @@ -0,0 +1,26 @@ +From c6b96a0e10db061c9ab790b443f0bfd8220d7d3c Mon Sep 17 00:00:00 2001 +From: lixiang_yewu +Date: Mon, 2 Sep 2024 07:39:00 +0000 +Subject: [PATCH] update io/trace-events. Parameters should remain consistent. + +Signed-off-by: lixiang_yewu +--- + io/trace-events | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/io/trace-events b/io/trace-events +index 3cc5cf1efd..79e1a19af7 100644 +--- a/io/trace-events ++++ b/io/trace-events +@@ -38,7 +38,7 @@ qio_channel_file_new_path(void *ioc, const char *path, int flags, int mode, int + + # channel-tls.c + qio_channel_tls_new_client(void *ioc, void *master, void *creds, const char *hostname) "TLS new client ioc=%p master=%p creds=%p hostname=%s" +-qio_channel_tls_new_server(void *ioc, void *master, void *creds, const char *aclname) "TLS new client ioc=%p master=%p creds=%p acltname=%s" ++qio_channel_tls_new_server(void *ioc, void *master, void *creds, const char *aclname) "TLS new client ioc=%p master=%p creds=%p aclname=%s" + qio_channel_tls_handshake_start(void *ioc) "TLS handshake start ioc=%p" + qio_channel_tls_handshake_pending(void *ioc, int status) "TLS handshake pending ioc=%p status=%d" + qio_channel_tls_handshake_fail(void *ioc) "TLS handshake fail ioc=%p" +-- +2.41.0.windows.1 + diff --git a/virtio-net-Ensure-queue-index-fits-with-RSS-CVE-2024.patch b/virtio-net-Ensure-queue-index-fits-with-RSS-CVE-2024.patch new file mode 100644 index 0000000000000000000000000000000000000000..abaa891643d2609030f45a184026532deba373c4 --- /dev/null +++ b/virtio-net-Ensure-queue-index-fits-with-RSS-CVE-2024.patch @@ -0,0 +1,36 @@ +From a8bc17bf7f94f684ba518c56e56b41974c50305e Mon Sep 17 00:00:00 2001 +From: Akihiko Odaki +Date: Mon, 1 Jul 2024 20:58:04 +0900 +Subject: [PATCH] virtio-net: Ensure queue index fits with RSS (CVE-2024-6505) + +Ensure the queue index points to a valid queue when software RSS +enabled. The new calculation matches with the behavior of Linux's TAP +device with the RSS eBPF program. + +Fixes: 4474e37a5b3a ("virtio-net: implement RX RSS processing") +Reported-by: Zhibin Hu +Cc: qemu-stable@nongnu.org +Signed-off-by: Akihiko Odaki +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +--- + hw/net/virtio-net.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 91c1504544..432c433540 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1931,7 +1931,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) { + int index = virtio_net_process_rss(nc, buf, size); + if (index >= 0) { +- NetClientState *nc2 = qemu_get_subqueue(n->nic, index); ++ NetClientState *nc2 = ++ qemu_get_subqueue(n->nic, index % n->curr_queue_pairs); + return virtio_net_receive_rcu(nc2, buf, size, true); + } + } +-- +2.41.0.windows.1 + diff --git a/virtio-net-Use-virtual-time-for-RSC-timers.patch b/virtio-net-Use-virtual-time-for-RSC-timers.patch new file mode 100644 index 0000000000000000000000000000000000000000..abb744c48df1c84241d674738fdea8f9ba6895cc --- /dev/null +++ b/virtio-net-Use-virtual-time-for-RSC-timers.patch @@ -0,0 +1,58 @@ +From 8f6c35e3acb54208564fcb773cf79809d7412cf5 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 20 Aug 2024 09:48:42 +0800 +Subject: [PATCH] virtio-net: Use virtual time for RSC timers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 44bc14fa1e78f01bfddcb265fc41c29204ebbfd8 + +Receive coalescing is visible to the target machine, so its timers +should use virtual time like other timers in virtio-net, to be +compatible with record-replay. + +Signed-off-by: Nicholas Piggin +Message-Id: <20240813050638.446172-10-npiggin@gmail.com> +Acked-by: Michael S. Tsirkin +Signed-off-by: Alex Bennée +Message-Id: <20240813202329.1237572-18-alex.bennee@linaro.org> +Signed-off-by: qihao_yewu +--- + hw/net/virtio-net.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index c0a54f2d61..91c1504544 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -2141,7 +2141,7 @@ static void virtio_net_rsc_purge(void *opq) + chain->stat.timer++; + if (!QTAILQ_EMPTY(&chain->buffers)) { + timer_mod(chain->drain_timer, +- qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); ++ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + chain->n->rsc_timeout); + } + } + +@@ -2377,7 +2377,7 @@ static size_t virtio_net_rsc_do_coalesce(VirtioNetRscChain *chain, + chain->stat.empty_cache++; + virtio_net_rsc_cache_buf(chain, nc, buf, size); + timer_mod(chain->drain_timer, +- qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); ++ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + chain->n->rsc_timeout); + return size; + } + +@@ -2615,7 +2615,7 @@ static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n, + chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD; + chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + } +- chain->drain_timer = timer_new_ns(QEMU_CLOCK_HOST, ++ chain->drain_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + virtio_net_rsc_purge, chain); + memset(&chain->stat, 0, sizeof(chain->stat)); + +-- +2.41.0.windows.1 + diff --git a/virtio-pci-fix-use-of-a-released-vector.patch b/virtio-pci-fix-use-of-a-released-vector.patch new file mode 100644 index 0000000000000000000000000000000000000000..00af28832a00fa29f1d3e14ac7a4a5d0af7ba1b1 --- /dev/null +++ b/virtio-pci-fix-use-of-a-released-vector.patch @@ -0,0 +1,156 @@ +From 11e71bc99d8811644ddf1a854e556170bb8f5db3 Mon Sep 17 00:00:00 2001 +From: Gao Jiazhen +Date: Thu, 12 Sep 2024 16:01:04 +0800 +Subject: [PATCH] virtio-pci: fix use of a released vector +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry picked from commit 2ce6cff94df2650c460f809e5ad263f1d22507c0 + +During the booting process of the non-standard image, the behavior of the +called function in qemu is as follows: + +1. vhost_net_stop() was triggered by guest image. This will call the function +virtio_pci_set_guest_notifiers() with assgin= false, +virtio_pci_set_guest_notifiers() will release the irqfd for vector 0 + +2. virtio_reset() was triggered, this will set configure vector to VIRTIO_NO_VECTOR + +3.vhost_net_start() was called (at this time, the configure vector is +still VIRTIO_NO_VECTOR) and then call virtio_pci_set_guest_notifiers() with +assgin=true, so the irqfd for vector 0 is still not "init" during this process + +4. The system continues to boot and sets the vector back to 0. After that +msix_fire_vector_notifier() was triggered to unmask the vector 0 and meet the crash + +To fix the issue, we need to support changing the vector after VIRTIO_CONFIG_S_DRIVER_OK is set. + +(gdb) bt +0 __pthread_kill_implementation (threadid=, signo=signo@entry=6, no_tid=no_tid@entry=0) + at pthread_kill.c:44 +1 0x00007fc87148ec53 in __pthread_kill_internal (signo=6, threadid=) at pthread_kill.c:78 +2 0x00007fc87143e956 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26 +3 0x00007fc8714287f4 in __GI_abort () at abort.c:79 +4 0x00007fc87142871b in __assert_fail_base + (fmt=0x7fc8715bbde0 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x5606413efd53 "ret == 0", file=0x5606413ef87d "../accel/kvm/kvm-all.c", line=1837, function=) at assert.c:92 +5 0x00007fc871437536 in __GI___assert_fail + (assertion=0x5606413efd53 "ret == 0", file=0x5606413ef87d "../accel/kvm/kvm-all.c", line=1837, function=0x5606413f06f0 <__PRETTY_FUNCTION__.19> "kvm_irqchip_commit_routes") at assert.c:101 +6 0x0000560640f884b5 in kvm_irqchip_commit_routes (s=0x560642cae1f0) at ../accel/kvm/kvm-all.c:1837 +7 0x0000560640c98f8e in virtio_pci_one_vector_unmask + (proxy=0x560643c65f00, queue_no=4294967295, vector=0, msg=..., n=0x560643c6e4c8) + at ../hw/virtio/virtio-pci.c:1005 +8 0x0000560640c99201 in virtio_pci_vector_unmask (dev=0x560643c65f00, vector=0, msg=...) + at ../hw/virtio/virtio-pci.c:1070 +9 0x0000560640bc402e in msix_fire_vector_notifier (dev=0x560643c65f00, vector=0, is_masked=false) + at ../hw/pci/msix.c:120 +10 0x0000560640bc40f1 in msix_handle_mask_update (dev=0x560643c65f00, vector=0, was_masked=true) + at ../hw/pci/msix.c:140 +11 0x0000560640bc4503 in msix_table_mmio_write (opaque=0x560643c65f00, addr=12, val=0, size=4) + at ../hw/pci/msix.c:231 +12 0x0000560640f26d83 in memory_region_write_accessor + (mr=0x560643c66540, addr=12, value=0x7fc86b7bc628, size=4, shift=0, mask=4294967295, attrs=...) + at ../system/memory.c:497 +13 0x0000560640f270a6 in access_with_adjusted_size + + (addr=12, value=0x7fc86b7bc628, size=4, access_size_min=1, access_size_max=4, access_fn=0x560640f26c8d , mr=0x560643c66540, attrs=...) at ../system/memory.c:573 +14 0x0000560640f2a2b5 in memory_region_dispatch_write (mr=0x560643c66540, addr=12, data=0, op=MO_32, attrs=...) + at ../system/memory.c:1521 +15 0x0000560640f37bac in flatview_write_continue + (fv=0x7fc65805e0b0, addr=4273803276, attrs=..., ptr=0x7fc871e9c028, len=4, addr1=12, l=4, mr=0x560643c66540) + at ../system/physmem.c:2714 +16 0x0000560640f37d0f in flatview_write + (fv=0x7fc65805e0b0, addr=4273803276, attrs=..., buf=0x7fc871e9c028, len=4) at ../system/physmem.c:2756 +17 0x0000560640f380bf in address_space_write + (as=0x560642161ae0 , addr=4273803276, attrs=..., buf=0x7fc871e9c028, len=4) + at ../system/physmem.c:2863 +18 0x0000560640f3812c in address_space_rw + (as=0x560642161ae0 , addr=4273803276, attrs=..., buf=0x7fc871e9c028, len=4, is_write=true) at ../system/physmem.c:2873 +--Type for more, q to quit, c to continue without paging-- +19 0x0000560640f8aa55 in kvm_cpu_exec (cpu=0x560642f205e0) at ../accel/kvm/kvm-all.c:2915 +20 0x0000560640f8d731 in kvm_vcpu_thread_fn (arg=0x560642f205e0) at ../accel/kvm/kvm-accel-ops.c:51 +21 0x00005606411949f4 in qemu_thread_start (args=0x560642f292b0) at ../util/qemu-thread-posix.c:541 +22 0x00007fc87148cdcd in start_thread (arg=) at pthread_create.c:442 +23 0x00007fc871512630 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81 +(gdb) + +MST: coding style and typo fixups + +Fixes: f9a09ca ("vhost: add support for configure interrupt") +Cc: qemu-stable@nongnu.org +Signed-off-by: Cindy Lu +Message-ID: <2321ade5f601367efe7380c04e3f61379c59b48f.1713173550.git.mst@redhat.com> +Cc: Lei Yang +Cc: Jason Wang +Signed-off-by: Michael S. Tsirkin +Tested-by: Cindy Lu +Signed-off-by: Gao Jiazhen +--- + hw/virtio/virtio-pci.c | 37 +++++++++++++++++++++++++++++++++++-- + 1 file changed, 35 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index f8adb0520a..3ad7487411 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -1456,6 +1456,38 @@ static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, + return offset; + } + ++static void virtio_pci_set_vector(VirtIODevice *vdev, ++ VirtIOPCIProxy *proxy, ++ int queue_no, uint16_t old_vector, ++ uint16_t new_vector) ++{ ++ bool kvm_irqfd = (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) && ++ msix_enabled(&proxy->pci_dev) && kvm_msi_via_irqfd_enabled(); ++ ++ if (new_vector == old_vector) { ++ return; ++ } ++ ++ /* ++ * If the device uses irqfd and the vector changes after DRIVER_OK is ++ * set, we need to release the old vector and set up the new one. ++ * Otherwise just need to set the new vector on the device. ++ */ ++ if (kvm_irqfd && old_vector != VIRTIO_NO_VECTOR) { ++ kvm_virtio_pci_vector_release_one(proxy, queue_no); ++ } ++ /* Set the new vector on the device. */ ++ if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { ++ vdev->config_vector = new_vector; ++ } else { ++ virtio_queue_set_vector(vdev, queue_no, new_vector); ++ } ++ /* If the new vector changed need to set it up. */ ++ if (kvm_irqfd && new_vector != VIRTIO_NO_VECTOR) { ++ kvm_virtio_pci_vector_use_one(proxy, queue_no); ++ } ++} ++ + int virtio_pci_add_shm_cap(VirtIOPCIProxy *proxy, + uint8_t bar, uint64_t offset, uint64_t length, + uint8_t id) +@@ -1602,7 +1634,8 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, + } else { + val = VIRTIO_NO_VECTOR; + } +- vdev->config_vector = val; ++ virtio_pci_set_vector(vdev, proxy, VIRTIO_CONFIG_IRQ_IDX, ++ vdev->config_vector, val); + break; + case VIRTIO_PCI_COMMON_STATUS: + if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) { +@@ -1642,7 +1675,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, + } else { + val = VIRTIO_NO_VECTOR; + } +- virtio_queue_set_vector(vdev, vdev->queue_sel, val); ++ virtio_pci_set_vector(vdev, proxy, vdev->queue_sel, vector, val); + break; + case VIRTIO_PCI_COMMON_Q_ENABLE: + if (val == 1) { +-- +2.41.0.windows.1 + diff --git a/vvfat-Fix-bug-in-writing-to-middle-of-file.patch b/vvfat-Fix-bug-in-writing-to-middle-of-file.patch new file mode 100644 index 0000000000000000000000000000000000000000..c37caba7b2d8ed735339a4e893d4440886bb2865 --- /dev/null +++ b/vvfat-Fix-bug-in-writing-to-middle-of-file.patch @@ -0,0 +1,41 @@ +From db722158867b3b7541ed788b0a0f42a29a839ee4 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Fri, 16 Aug 2024 17:51:45 +0800 +Subject: [PATCH] vvfat: Fix bug in writing to middle of file + +cheery-pick from b881cf00c99e03bc8a3648581f97736ff275b18b + +Before this commit, the behavior when calling `commit_one_file` for +example with `offset=0x2000` (second cluster), what will happen is that +we won't fetch the next cluster from the fat, and instead use the first +cluster for the read operation. + +This is due to off-by-one error here, where `i=0x2000 !< offset=0x2000`, +thus not fetching the next cluster. + +Signed-off-by: Amjad Alsharafi +Reviewed-by: Kevin Wolf +Tested-by: Kevin Wolf +Message-ID: +Signed-off-by: Kevin Wolf +Signed-off-by: qihao_yewu +--- + block/vvfat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/vvfat.c b/block/vvfat.c +index 9d050ba3ae..9010f3f33f 100644 +--- a/block/vvfat.c ++++ b/block/vvfat.c +@@ -2525,7 +2525,7 @@ commit_one_file(BDRVVVFATState* s, int dir_index, uint32_t offset) + return -1; + } + +- for (i = s->cluster_size; i < offset; i += s->cluster_size) ++ for (i = 0; i < offset; i += s->cluster_size) + c = modified_fat_get(s, c); + + fd = qemu_open_old(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666); +-- +2.41.0.windows.1 +