QEMU update to version 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

Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
This commit is contained in:
Jiabo Feng 2024-09-18 15:20:53 +08:00
parent b36d41c519
commit 4f059b938c
54 changed files with 6570 additions and 1 deletions

View File

@ -0,0 +1,63 @@
From 2781f5673cc43d13b73e66fb266e7ea0b945429d Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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 <lizhijian@fujitsu.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: zhenwei pi <pizhenwei@bytedance.com>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,54 @@
From 5661b12a28b650226cca100aeddd92d5cc788153 Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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 <maxtram95@gmail.com>
Link: https://lore.kernel.org/r/20240703190812.3459514-1-m
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,67 @@
From da96618de3227b87ddd78388b80278bde230ce79 Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
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 <brijesh.singh@amd.com>
Co-developed-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,403 @@
From 7b7742e137fbf9283cbbfb823fcf2ebe14df3154 Mon Sep 17 00:00:00 2001
From: gaochuanji <gaochuanji@inspur.com>
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 <cheliequan@inspur.com>
---
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 <nettle/md5.h>
#include <nettle/sha.h>
#include <nettle/ripemd160.h>
+#ifdef CONFIG_CRYPTO_SM3
+#include <nettle/sm3.h>
+#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 <gcrypt.h>
+ 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 <nettle/sm3.h>
+ #include <nettle/hmac.h>
+ 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

View File

@ -0,0 +1,78 @@
From ec07000764f578bb7cd21fe73c8e649a183d7674 Mon Sep 17 00:00:00 2001
From: qihao <qihao_yewu@cmss.chinamobile.com>
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 <peter.maydell@linaro.org>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20240819145021.38524-1-peter.maydell@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: qihao_yewu <qihao_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,118 @@
From 384b3f41fd69ed6f5bf376ff1aac1a12deeea0fb Mon Sep 17 00:00:00 2001
From: liupingwei <liupingwei0317@outlook.com>
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 <liupingwei0317@outlook.com>
---
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

View File

@ -0,0 +1,69 @@
From 2da2e7ebea456360cc41881ff2e4a81a03b6d10c Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
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 <dgilbert@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,101 @@
From fcd3ff011e62739b824c2e465e01b98c47e364f5 Mon Sep 17 00:00:00 2001
From: qihao <qihao_yewu@cmss.chinamobile.com>
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 <JianZhou.Yue@verisilicon.com>
Message-id: 3DA024AEA8B57545AF1B3CAA37077D0FB75E82C8@SHASXM03.verisilicon.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: qihao_yewu <qihao_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,39 @@
From f2efa9729b4cb4ec98f93c1eafe38459fd82e7ae Mon Sep 17 00:00:00 2001
From: qihao <qihao_yewu@cmss.chinamobile.com>
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 <wh1sper@zju.edu.cn>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: qihao_yewu <qihao_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,44 @@
From 073620787702404e2d71486c30967455c3c7904c Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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 <maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240426091551.2397867-10-gaosong@loongson.cn>
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,36 @@
From b9e94d97025251cfd13b3ad859b97002504285ce Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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

View File

@ -0,0 +1,92 @@
From 93959a5378f57190fb79dd1ccdefb8d8cd095b58 Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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 <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20240723131029.1159908-2-peter.maydell@linaro.org
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

190
hw-misc-support-vpsp.patch Normal file
View File

@ -0,0 +1,190 @@
From f74cee44cd57da213a790f7711a68da0f4de061a Mon Sep 17 00:00:00 2001
From: xiongmengbiao <xiongmengbiao@hygon.cn>
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 <xiongmengbiao@hygon.cn>
---
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 <sys/ioctl.h>
+
+#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

View File

@ -0,0 +1,35 @@
From 80f4d02d7afa212fba4420a3af04f3a670b9a5d4 Mon Sep 17 00:00:00 2001
From: qihao <qihao_yewu@cmss.chinamobile.com>
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 <shimizu@cyberdefense.jp>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Signed-off-by: qihao_yewu <qihao_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,171 @@
From 09934a231a513289caaae68e68912b735cb44b75 Mon Sep 17 00:00:00 2001
From: hanliyang <hanliyang@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,315 @@
From 02e6bfc88ce5e944ce36b8ccb7d2af103a969980 Mon Sep 17 00:00:00 2001
From: Ashish Kalra <ashish.kalra@amd.com>
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 <ashish.kalra@amd.com>
[ Fix conflicts. ]
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,123 @@
From 7aced2a5fff91e0fcff97bb5eafddafece0cb983 Mon Sep 17 00:00:00 2001
From: Ashish Kalra <ashish.kalra@amd.com>
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 <ashish.kalra@amd.com>
[ Fix conflicts. ]
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,43 @@
From 2651409cf43002dc497483ae3ae227d4c602ca45 Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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 <abelova@astralinux.ru>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,120 @@
From 0f85e3a486c2d0130cb3be322900aa839d77d4bd Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
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 <brijesh.singh@amd.com>
Co-developed-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
[ Fix conflicts. ]
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,87 @@
From 015fc431353ae348e7e9cef2036b674a4e33eb1c Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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 <farosas@suse.de>
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 <lizhijian@fujitsu.com>
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
Tested-by: Zhang Chen <chen.zhang@intel.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Link: https://lore.kernel.org/r/20240417025634.1014582-1-lizhijian@fujitsu.com
Signed-off-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,37 @@
From eac3cab8dcd005b33365b5196801268d696a11bc Mon Sep 17 00:00:00 2001
From: fangbaoshun <fangbaoshun@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,208 @@
From e2b3943bf75d34f5e913e05fbdf8116179812866 Mon Sep 17 00:00:00 2001
From: fangbaoshun <fangbaoshun@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,57 @@
From ec2518709b8d461c3a165c1722ccd2e585cec161 Mon Sep 17 00:00:00 2001
From: hanliyang <hanliyang@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,32 @@
From e6a20047ca9f61d7fc544e4f0b9b26aa268ccda7 Mon Sep 17 00:00:00 2001
From: hanliyang <hanliyang@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,44 @@
From cbbac2aa57d5609c254f99bf247d16e4b9fd7de3 Mon Sep 17 00:00:00 2001
From: Ashish Kalra <ashish.kalra@amd.com>
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 <ashish.kalra@amd.com>
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,343 @@
From af3077a2f19f0604c4e7f8b94eb0338b7f1f85d6 Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
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 <brijesh.singh@amd.com>
Co-developed-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
[ Fix conflicts. ]
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,265 @@
From 5ff59a5649385672da42097b24a2428bc2348d9b Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
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 <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
[ Fix conflicts and qapi errors. ]
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,90 @@
From 5da793de60f37cf0daaffee3fe8300a1a20bf36b Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
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 <andrey.drobyshev@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-ID: <20240822143617.800419-2-eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
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

111
qemu.spec
View File

@ -3,7 +3,7 @@
Name: qemu Name: qemu
Version: 8.2.0 Version: 8.2.0
Release: 17 Release: 18
Epoch: 11 Epoch: 11
Summary: QEMU is a generic and open source machine emulator and virtualizer Summary: QEMU is a generic and open source machine emulator and virtualizer
License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 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 Patch0286: target-i386-add-control-bits-support-for-LAM.patch
Patch0287: cvm-bug-fix-for-incorrect-device-name-check-for-vhos.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 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: flex
BuildRequires: gcc BuildRequires: gcc
@ -899,6 +953,61 @@ getent passwd qemu >/dev/null || \
%endif %endif
%changelog %changelog
* Wed Sep 18 2024 Jiabo Feng <fengjiabo1@huawei.com> - 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 <fengjiabo1@huawei.com> - 11:8.2.0-17 * Thu Sep 5 2024 Jiabo Feng <fengjiabo1@huawei.com> - 11:8.2.0-17
- cvm : bug fix for undefined reference to 'virtcca_cvm_allowed' while compiling - cvm : bug fix for undefined reference to 'virtcca_cvm_allowed' while compiling
- cvm : bug-fix for incorrect device name check for vhost-user-fs - cvm : bug-fix for incorrect device name check for vhost-user-fs

View File

@ -0,0 +1,39 @@
From a113ddc33b432c8b4d21160dccb54ba19580ab01 Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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 <marcin.juszkiewicz@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
Message-id: 20240526204551.553282-1-richard.henderson@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,48 @@
From 3323c09d283e02c10bbf6e8dfc43ea9f41e746db Mon Sep 17 00:00:00 2001
From: Lei Wang <lei4.wang@intel.com>
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 <lei4.wang@intel.com>
Message-ID: <20240424072912.43188-1-lei4.wang@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
[ Quanxian Wang: amend commit log ]
Signed-off-by: Quanxian Wang <quanxian.wang@intel.com>
---
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

View File

@ -0,0 +1,107 @@
From 2bdf07593dbec66205f2f20fa5430595678ded89 Mon Sep 17 00:00:00 2001
From: hanliyang <hanliyang@hygon.cn>
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 <hanliyang@hygon.cn>
---
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 <jiangxin@hygon.cn>
+ *
+ * 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

View File

@ -0,0 +1,433 @@
From 940858a3ab39575a0c1d91d4aa5bb65607259a8f Mon Sep 17 00:00:00 2001
From: hanliyang <hanliyang@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,140 @@
From d23c6a2bcc836587620bd35726ca4d5f71c0a844 Mon Sep 17 00:00:00 2001
From: hanliyang <hanliyang@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,207 @@
From b2091d245563f4bd2974c8d8e6ef186de614f8e2 Mon Sep 17 00:00:00 2001
From: fangbaoshun <fangbaoshun@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,107 @@
From cb5c1c9c70110639eda0ff50c8dfcf24b0be561d Mon Sep 17 00:00:00 2001
From: fangbaoshun <fangbaoshun@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,170 @@
From 8125145bcd3b8348e69686e26f482cf16b16ec98 Mon Sep 17 00:00:00 2001
From: fangbaoshun <fangbaoshun@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,259 @@
From e6d587b63c3950f5d5af9002a8ae14e0904d62c3 Mon Sep 17 00:00:00 2001
From: fangbaoshun <fangbaoshun@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,190 @@
From 6a8b58a3ce6dc162cae4b74ca8f39392672e6cba Mon Sep 17 00:00:00 2001
From: panpingsheng <panpingsheng@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,179 @@
From 366c11c56875ae053043c48c8b93349c6e3125cc Mon Sep 17 00:00:00 2001
From: hanliyang <hanliyang@hygon.cn>
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 <hanliyang@hygon.cn>
---
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 <jiangxin@hygon.cn>
+ *
+ * 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 <jiangxin@hygon.cn>
+ *
+ * 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 <hanliyang@hygon.cn>
+ *
+ * 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

View File

@ -0,0 +1,34 @@
From 004e0a984118380ff89ceaabb6ace1ebbfb1eb6d Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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 <pbonzini@redhat.com>
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,57 @@
From e98147762cb47645c590ee000dbc12c654a6cc2d Mon Sep 17 00:00:00 2001
From: hanliyang <hanliyang@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,59 @@
From ccca5618025567c4168630459b90bf11bf96cca4 Mon Sep 17 00:00:00 2001
From: hanliyang <hanliyang@hygon.cn>
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 <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,319 @@
From 0a7dde8450d9b6a6d0c75cef11e4bbff65e95edc Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
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 <brijesh.singh@amd.com>
Co-developed-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
[ Fix conflict. ]
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,221 @@
From 778457c2f0f91b6a52e5db02dd3dc1f35ae64526 Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
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 <brijesh.singh@amd.com>
Co-developed-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
[ Fix conflicts. ]
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,49 @@
From c8a6d5f18c45079575b707db8f017cce22acc970 Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
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 <dgilbert@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
[ Fix conflict. ]
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,135 @@
From f6753191237118294d04193908db503bb87619f7 Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
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 <brijesh.singh@amd.com>
Co-developed-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
[ Fix conflict. ]
Signed-off-by: hanliyang <hanliyang@hygon.cn>
---
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

View File

@ -0,0 +1,39 @@
From 4f76ccdc5bdad57b9c70da7a4fc00502cc335060 Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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 <lanyanzhi22b@ict.ac.cn>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240604073831.666690-1-lanyanzhi22b@ict.ac.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,27 @@
From c31f85b015326ad6619c707ada5cea2713970741 Mon Sep 17 00:00:00 2001
From: lixiang_yewu <lixiang_yewu@cmss.chinamobile.com>
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 <lixiang_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,26 @@
From c6b96a0e10db061c9ab790b443f0bfd8220d7d3c Mon Sep 17 00:00:00 2001
From: lixiang_yewu <lixiang_yewu@cmss.chinamobile.com>
Date: Mon, 2 Sep 2024 07:39:00 +0000
Subject: [PATCH] update io/trace-events. Parameters should remain consistent.
Signed-off-by: lixiang_yewu <lixiang_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,36 @@
From a8bc17bf7f94f684ba518c56e56b41974c50305e Mon Sep 17 00:00:00 2001
From: Akihiko Odaki <akihiko.odaki@daynix.com>
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 <huzhibin5@huawei.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
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

View File

@ -0,0 +1,58 @@
From 8f6c35e3acb54208564fcb773cf79809d7412cf5 Mon Sep 17 00:00:00 2001
From: qihao <qihao_yewu@cmss.chinamobile.com>
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 <npiggin@gmail.com>
Message-Id: <20240813050638.446172-10-npiggin@gmail.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20240813202329.1237572-18-alex.bennee@linaro.org>
Signed-off-by: qihao_yewu <qihao_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,156 @@
From 11e71bc99d8811644ddf1a854e556170bb8f5db3 Mon Sep 17 00:00:00 2001
From: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
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=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0)
at pthread_kill.c:44
1 0x00007fc87148ec53 in __pthread_kill_internal (signo=6, threadid=<optimized out>) 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=<optimized out>) 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 <memory_region_write_accessor>, 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 <address_space_memory>, addr=4273803276, attrs=..., buf=0x7fc871e9c028, len=4)
at ../system/physmem.c:2863
18 0x0000560640f3812c in address_space_rw
(as=0x560642161ae0 <address_space_memory>, addr=4273803276, attrs=..., buf=0x7fc871e9c028, len=4, is_write=true) at ../system/physmem.c:2873
--Type <RET> 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=<optimized out>) 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 <lulu@redhat.com>
Message-ID: <2321ade5f601367efe7380c04e3f61379c59b48f.1713173550.git.mst@redhat.com>
Cc: Lei Yang <leiyang@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Tested-by: Cindy Lu <lulu@redhat.com>
Signed-off-by: Gao Jiazhen <gaojiazhen_yewu@cmss.chinamobile.com>
---
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

View File

@ -0,0 +1,41 @@
From db722158867b3b7541ed788b0a0f42a29a839ee4 Mon Sep 17 00:00:00 2001
From: qihao <qihao_yewu@cmss.chinamobile.com>
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 <amjadsharafi10@gmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Tested-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <b97c1e1f1bc2f776061ae914f95d799d124fcd73.1721470238.git.amjadsharafi10@gmail.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: qihao_yewu <qihao_yewu@cmss.chinamobile.com>
---
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