1a9b4942fSBrijesh Singh /*
2a9b4942fSBrijesh Singh * QEMU SEV support
3a9b4942fSBrijesh Singh *
4a9b4942fSBrijesh Singh * Copyright Advanced Micro Devices 2016-2018
5a9b4942fSBrijesh Singh *
6a9b4942fSBrijesh Singh * Author:
7a9b4942fSBrijesh Singh * Brijesh Singh <brijesh.singh@amd.com>
8a9b4942fSBrijesh Singh *
9a9b4942fSBrijesh Singh * This work is licensed under the terms of the GNU GPL, version 2 or later.
10a9b4942fSBrijesh Singh * See the COPYING file in the top-level directory.
11a9b4942fSBrijesh Singh *
12a9b4942fSBrijesh Singh */
13a9b4942fSBrijesh Singh
14b7d89466SMarkus Armbruster #include "qemu/osdep.h"
15b7d89466SMarkus Armbruster
16d8575c6cSBrijesh Singh #include <linux/kvm.h>
17e3cddff9SMichael Roth #include <linux/kvm_para.h>
18d8575c6cSBrijesh Singh #include <linux/psp-sev.h>
19d8575c6cSBrijesh Singh
20d8575c6cSBrijesh Singh #include <sys/ioctl.h>
21d8575c6cSBrijesh Singh
22a9b4942fSBrijesh Singh #include "qapi/error.h"
23a9b4942fSBrijesh Singh #include "qom/object_interfaces.h"
24a9b4942fSBrijesh Singh #include "qemu/base64.h"
250b8fa32fSMarkus Armbruster #include "qemu/module.h"
26b2f73a07SPaolo Bonzini #include "qemu/uuid.h"
27cc37d98bSRichard Henderson #include "qemu/error-report.h"
28cff03145SDov Murik #include "crypto/hash.h"
29a9b4942fSBrijesh Singh #include "sysemu/kvm.h"
30663e2f44SPaolo Bonzini #include "kvm/kvm_i386.h"
3193777de3SPhilippe Mathieu-Daudé #include "sev.h"
32a9b4942fSBrijesh Singh #include "sysemu/sysemu.h"
3354d31236SMarkus Armbruster #include "sysemu/runstate.h"
34d8575c6cSBrijesh Singh #include "trace.h"
358fa4466dSBrijesh Singh #include "migration/blocker.h"
36db1015e9SEduardo Habkost #include "qom/object.h"
37c7f7e697STobin Feldman-Fitzthum #include "monitor/monitor.h"
38cd35beb4SPhilippe Mathieu-Daudé #include "monitor/hmp-target.h"
393208de1cSPhilippe Mathieu-Daudé #include "qapi/qapi-commands-misc-target.h"
40d82e9c84SPaolo Bonzini #include "confidential-guest.h"
41b2f73a07SPaolo Bonzini #include "hw/i386/pc.h"
4258603ba2SDov Murik #include "exec/address-spaces.h"
43d3107f88SBrijesh Singh #include "qemu/queue.h"
44a9b4942fSBrijesh Singh
4516dcf200SMichael Roth OBJECT_DECLARE_TYPE(SevCommonState, SevCommonStateClass, SEV_COMMON)
4616dcf200SMichael Roth OBJECT_DECLARE_TYPE(SevGuestState, SevCommonStateClass, SEV_GUEST)
477b34df44SBrijesh Singh OBJECT_DECLARE_TYPE(SevSnpGuestState, SevCommonStateClass, SEV_SNP_GUEST)
48a86ab19dSDavid Gibson
49cc483bf9SDov Murik /* hard code sha256 digest size */
50cc483bf9SDov Murik #define HASH_SIZE 32
51cc483bf9SDov Murik
52cc483bf9SDov Murik typedef struct QEMU_PACKED SevHashTableEntry {
53cc483bf9SDov Murik QemuUUID guid;
54cc483bf9SDov Murik uint16_t len;
55cc483bf9SDov Murik uint8_t hash[HASH_SIZE];
56cc483bf9SDov Murik } SevHashTableEntry;
57cc483bf9SDov Murik
58cc483bf9SDov Murik typedef struct QEMU_PACKED SevHashTable {
59cc483bf9SDov Murik QemuUUID guid;
60cc483bf9SDov Murik uint16_t len;
61cc483bf9SDov Murik SevHashTableEntry cmdline;
62cc483bf9SDov Murik SevHashTableEntry initrd;
63cc483bf9SDov Murik SevHashTableEntry kernel;
64cc483bf9SDov Murik } SevHashTable;
65cc483bf9SDov Murik
66cc483bf9SDov Murik /*
67cc483bf9SDov Murik * Data encrypted by sev_encrypt_flash() must be padded to a multiple of
68cc483bf9SDov Murik * 16 bytes.
69cc483bf9SDov Murik */
70cc483bf9SDov Murik typedef struct QEMU_PACKED PaddedSevHashTable {
71cc483bf9SDov Murik SevHashTable ht;
72cc483bf9SDov Murik uint8_t padding[ROUND_UP(sizeof(SevHashTable), 16) - sizeof(SevHashTable)];
73cc483bf9SDov Murik } PaddedSevHashTable;
74cc483bf9SDov Murik
75cc483bf9SDov Murik QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
76cc483bf9SDov Murik
77cc483bf9SDov Murik #define SEV_INFO_BLOCK_GUID "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
78cc483bf9SDov Murik typedef struct __attribute__((__packed__)) SevInfoBlock {
79cc483bf9SDov Murik /* SEV-ES Reset Vector Address */
80cc483bf9SDov Murik uint32_t reset_addr;
81cc483bf9SDov Murik } SevInfoBlock;
82cc483bf9SDov Murik
83cc483bf9SDov Murik #define SEV_HASH_TABLE_RV_GUID "7255371f-3a3b-4b04-927b-1da6efa8d454"
84cc483bf9SDov Murik typedef struct QEMU_PACKED SevHashTableDescriptor {
85cc483bf9SDov Murik /* SEV hash table area guest address */
86cc483bf9SDov Murik uint32_t base;
87cc483bf9SDov Murik /* SEV hash table area size (in bytes) */
88cc483bf9SDov Murik uint32_t size;
89cc483bf9SDov Murik } SevHashTableDescriptor;
90cc483bf9SDov Murik
9116dcf200SMichael Roth struct SevCommonState {
9216dcf200SMichael Roth X86ConfidentialGuest parent_obj;
9316dcf200SMichael Roth
9416dcf200SMichael Roth int kvm_type;
9516dcf200SMichael Roth
9616dcf200SMichael Roth /* configuration parameters */
9716dcf200SMichael Roth char *sev_device;
9816dcf200SMichael Roth uint32_t cbitpos;
9916dcf200SMichael Roth uint32_t reduced_phys_bits;
10016dcf200SMichael Roth bool kernel_hashes;
10116dcf200SMichael Roth
10216dcf200SMichael Roth /* runtime state */
10316dcf200SMichael Roth uint8_t api_major;
10416dcf200SMichael Roth uint8_t api_minor;
10516dcf200SMichael Roth uint8_t build_id;
10616dcf200SMichael Roth int sev_fd;
10716dcf200SMichael Roth SevState state;
10816dcf200SMichael Roth
10916dcf200SMichael Roth uint32_t reset_cs;
11016dcf200SMichael Roth uint32_t reset_ip;
11116dcf200SMichael Roth bool reset_data_valid;
11216dcf200SMichael Roth };
11316dcf200SMichael Roth
11416dcf200SMichael Roth struct SevCommonStateClass {
11516dcf200SMichael Roth X86ConfidentialGuestClass parent_class;
11616dcf200SMichael Roth
1176600f1acSPankaj Gupta /* public */
118c1996992SDov Murik bool (*build_kernel_loader_hashes)(SevCommonState *sev_common,
119c1996992SDov Murik SevHashTableDescriptor *area,
120c1996992SDov Murik SevKernelLoaderContext *ctx,
121c1996992SDov Murik Error **errp);
1226600f1acSPankaj Gupta int (*launch_start)(SevCommonState *sev_common);
123bce615a1SPankaj Gupta void (*launch_finish)(SevCommonState *sev_common);
124cb61b174SRichard Henderson int (*launch_update_data)(SevCommonState *sev_common, hwaddr gpa, uint8_t *ptr, size_t len);
125990da8d2SPankaj Gupta int (*kvm_init)(ConfidentialGuestSupport *cgs, Error **errp);
12616dcf200SMichael Roth };
127a86ab19dSDavid Gibson
12875a877e3SDavid Gibson /**
12975a877e3SDavid Gibson * SevGuestState:
13075a877e3SDavid Gibson *
13175a877e3SDavid Gibson * The SevGuestState object is used for creating and managing a SEV
13275a877e3SDavid Gibson * guest.
13375a877e3SDavid Gibson *
13475a877e3SDavid Gibson * # $QEMU \
13575a877e3SDavid Gibson * -object sev-guest,id=sev0 \
13675a877e3SDavid Gibson * -machine ...,memory-encryption=sev0
13775a877e3SDavid Gibson */
13875a877e3SDavid Gibson struct SevGuestState {
13916dcf200SMichael Roth SevCommonState parent_obj;
14016dcf200SMichael Roth gchar *measurement;
141663e2f44SPaolo Bonzini
14275a877e3SDavid Gibson /* configuration parameters */
14316dcf200SMichael Roth uint32_t handle;
14475a877e3SDavid Gibson uint32_t policy;
14575a877e3SDavid Gibson char *dh_cert_file;
14675a877e3SDavid Gibson char *session_file;
1479d38d9dcSMichael Roth OnOffAuto legacy_vm_type;
14875a877e3SDavid Gibson };
14975a877e3SDavid Gibson
1507b34df44SBrijesh Singh struct SevSnpGuestState {
1517b34df44SBrijesh Singh SevCommonState parent_obj;
1527b34df44SBrijesh Singh
1537b34df44SBrijesh Singh /* configuration parameters */
1547b34df44SBrijesh Singh char *guest_visible_workarounds;
15568c3aa3eSPaolo Bonzini char *id_block_base64;
156dd1b2fb5SPaolo Bonzini uint8_t *id_block;
157803b7718SPaolo Bonzini char *id_auth_base64;
1581ab620bfSPaolo Bonzini uint8_t *id_auth;
1597b34df44SBrijesh Singh char *host_data;
1607b34df44SBrijesh Singh
1617b34df44SBrijesh Singh struct kvm_sev_snp_launch_start kvm_start_conf;
1627b34df44SBrijesh Singh struct kvm_sev_snp_launch_finish kvm_finish_conf;
163c1996992SDov Murik
164c1996992SDov Murik uint32_t kernel_hashes_offset;
165c1996992SDov Murik PaddedSevHashTable *kernel_hashes_data;
1667b34df44SBrijesh Singh };
1677b34df44SBrijesh Singh
168a9b4942fSBrijesh Singh #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
169a9b4942fSBrijesh Singh #define DEFAULT_SEV_DEVICE "/dev/sev"
1707b34df44SBrijesh Singh #define DEFAULT_SEV_SNP_POLICY 0x30000
171a9b4942fSBrijesh Singh
172d3107f88SBrijesh Singh typedef struct SevLaunchUpdateData {
173d3107f88SBrijesh Singh QTAILQ_ENTRY(SevLaunchUpdateData) next;
174d3107f88SBrijesh Singh hwaddr gpa;
175d3107f88SBrijesh Singh void *hva;
176cb61b174SRichard Henderson size_t len;
177d3107f88SBrijesh Singh int type;
178d3107f88SBrijesh Singh } SevLaunchUpdateData;
179d3107f88SBrijesh Singh
180d3107f88SBrijesh Singh static QTAILQ_HEAD(, SevLaunchUpdateData) launch_update;
181d3107f88SBrijesh Singh
1828fa4466dSBrijesh Singh static Error *sev_mig_blocker;
183d8575c6cSBrijesh Singh
184d8575c6cSBrijesh Singh static const char *const sev_fw_errlist[] = {
1855811b936SConnor Kuehl [SEV_RET_SUCCESS] = "",
1865811b936SConnor Kuehl [SEV_RET_INVALID_PLATFORM_STATE] = "Platform state is invalid",
1875811b936SConnor Kuehl [SEV_RET_INVALID_GUEST_STATE] = "Guest state is invalid",
1885811b936SConnor Kuehl [SEV_RET_INAVLID_CONFIG] = "Platform configuration is invalid",
1895811b936SConnor Kuehl [SEV_RET_INVALID_LEN] = "Buffer too small",
1905811b936SConnor Kuehl [SEV_RET_ALREADY_OWNED] = "Platform is already owned",
1915811b936SConnor Kuehl [SEV_RET_INVALID_CERTIFICATE] = "Certificate is invalid",
1925811b936SConnor Kuehl [SEV_RET_POLICY_FAILURE] = "Policy is not allowed",
1935811b936SConnor Kuehl [SEV_RET_INACTIVE] = "Guest is not active",
1945811b936SConnor Kuehl [SEV_RET_INVALID_ADDRESS] = "Invalid address",
1955811b936SConnor Kuehl [SEV_RET_BAD_SIGNATURE] = "Bad signature",
1965811b936SConnor Kuehl [SEV_RET_BAD_MEASUREMENT] = "Bad measurement",
1975811b936SConnor Kuehl [SEV_RET_ASID_OWNED] = "ASID is already owned",
1985811b936SConnor Kuehl [SEV_RET_INVALID_ASID] = "Invalid ASID",
1995811b936SConnor Kuehl [SEV_RET_WBINVD_REQUIRED] = "WBINVD is required",
2005811b936SConnor Kuehl [SEV_RET_DFFLUSH_REQUIRED] = "DF_FLUSH is required",
2015811b936SConnor Kuehl [SEV_RET_INVALID_GUEST] = "Guest handle is invalid",
2025811b936SConnor Kuehl [SEV_RET_INVALID_COMMAND] = "Invalid command",
2035811b936SConnor Kuehl [SEV_RET_ACTIVE] = "Guest is active",
2045811b936SConnor Kuehl [SEV_RET_HWSEV_RET_PLATFORM] = "Hardware error",
2055811b936SConnor Kuehl [SEV_RET_HWSEV_RET_UNSAFE] = "Hardware unsafe",
2065811b936SConnor Kuehl [SEV_RET_UNSUPPORTED] = "Feature not supported",
2075811b936SConnor Kuehl [SEV_RET_INVALID_PARAM] = "Invalid parameter",
208d47b8550SConnor Kuehl [SEV_RET_RESOURCE_LIMIT] = "Required firmware resource depleted",
209d47b8550SConnor Kuehl [SEV_RET_SECURE_DATA_INVALID] = "Part-specific integrity check failure",
210d8575c6cSBrijesh Singh };
211d8575c6cSBrijesh Singh
212d8575c6cSBrijesh Singh #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
213d8575c6cSBrijesh Singh
21470943ad8SMichael Roth /* <linux/kvm.h> doesn't expose this, so re-use the max from kvm.c */
21570943ad8SMichael Roth #define KVM_MAX_CPUID_ENTRIES 100
21670943ad8SMichael Roth
21770943ad8SMichael Roth typedef struct KvmCpuidInfo {
21870943ad8SMichael Roth struct kvm_cpuid2 cpuid;
21970943ad8SMichael Roth struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES];
22070943ad8SMichael Roth } KvmCpuidInfo;
22170943ad8SMichael Roth
22270943ad8SMichael Roth #define SNP_CPUID_FUNCTION_MAXCOUNT 64
22370943ad8SMichael Roth #define SNP_CPUID_FUNCTION_UNKNOWN 0xFFFFFFFF
22470943ad8SMichael Roth
22570943ad8SMichael Roth typedef struct {
22670943ad8SMichael Roth uint32_t eax_in;
22770943ad8SMichael Roth uint32_t ecx_in;
22870943ad8SMichael Roth uint64_t xcr0_in;
22970943ad8SMichael Roth uint64_t xss_in;
23070943ad8SMichael Roth uint32_t eax;
23170943ad8SMichael Roth uint32_t ebx;
23270943ad8SMichael Roth uint32_t ecx;
23370943ad8SMichael Roth uint32_t edx;
23470943ad8SMichael Roth uint64_t reserved;
23570943ad8SMichael Roth } __attribute__((packed)) SnpCpuidFunc;
23670943ad8SMichael Roth
23770943ad8SMichael Roth typedef struct {
23870943ad8SMichael Roth uint32_t count;
23970943ad8SMichael Roth uint32_t reserved1;
24070943ad8SMichael Roth uint64_t reserved2;
24170943ad8SMichael Roth SnpCpuidFunc entries[SNP_CPUID_FUNCTION_MAXCOUNT];
24270943ad8SMichael Roth } __attribute__((packed)) SnpCpuidInfo;
24370943ad8SMichael Roth
244d8575c6cSBrijesh Singh static int
sev_ioctl(int fd,int cmd,void * data,int * error)245d8575c6cSBrijesh Singh sev_ioctl(int fd, int cmd, void *data, int *error)
246d8575c6cSBrijesh Singh {
247d8575c6cSBrijesh Singh int r;
248d8575c6cSBrijesh Singh struct kvm_sev_cmd input;
249d8575c6cSBrijesh Singh
250d8575c6cSBrijesh Singh memset(&input, 0x0, sizeof(input));
251d8575c6cSBrijesh Singh
252d8575c6cSBrijesh Singh input.id = cmd;
253d8575c6cSBrijesh Singh input.sev_fd = fd;
254592d0bc0SPaolo Bonzini input.data = (uintptr_t)data;
255d8575c6cSBrijesh Singh
256d8575c6cSBrijesh Singh r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
257d8575c6cSBrijesh Singh
258d8575c6cSBrijesh Singh if (error) {
259d8575c6cSBrijesh Singh *error = input.error;
260d8575c6cSBrijesh Singh }
261d8575c6cSBrijesh Singh
262d8575c6cSBrijesh Singh return r;
263d8575c6cSBrijesh Singh }
264d8575c6cSBrijesh Singh
265d8575c6cSBrijesh Singh static int
sev_platform_ioctl(int fd,int cmd,void * data,int * error)266d8575c6cSBrijesh Singh sev_platform_ioctl(int fd, int cmd, void *data, int *error)
267d8575c6cSBrijesh Singh {
268d8575c6cSBrijesh Singh int r;
269d8575c6cSBrijesh Singh struct sev_issue_cmd arg;
270d8575c6cSBrijesh Singh
271d8575c6cSBrijesh Singh arg.cmd = cmd;
272d8575c6cSBrijesh Singh arg.data = (unsigned long)data;
273d8575c6cSBrijesh Singh r = ioctl(fd, SEV_ISSUE_CMD, &arg);
274d8575c6cSBrijesh Singh if (error) {
275d8575c6cSBrijesh Singh *error = arg.error;
276d8575c6cSBrijesh Singh }
277d8575c6cSBrijesh Singh
278d8575c6cSBrijesh Singh return r;
279d8575c6cSBrijesh Singh }
280d8575c6cSBrijesh Singh
281d8575c6cSBrijesh Singh static const char *
fw_error_to_str(int code)282d8575c6cSBrijesh Singh fw_error_to_str(int code)
283d8575c6cSBrijesh Singh {
284d8575c6cSBrijesh Singh if (code < 0 || code >= SEV_FW_MAX_ERROR) {
285d8575c6cSBrijesh Singh return "unknown error";
286d8575c6cSBrijesh Singh }
287d8575c6cSBrijesh Singh
288d8575c6cSBrijesh Singh return sev_fw_errlist[code];
289d8575c6cSBrijesh Singh }
290d8575c6cSBrijesh Singh
291b738d630SBrijesh Singh static bool
sev_check_state(const SevCommonState * sev_common,SevState state)29216dcf200SMichael Roth sev_check_state(const SevCommonState *sev_common, SevState state)
293b738d630SBrijesh Singh {
29416dcf200SMichael Roth assert(sev_common);
29516dcf200SMichael Roth return sev_common->state == state ? true : false;
296b738d630SBrijesh Singh }
297b738d630SBrijesh Singh
298a9b4942fSBrijesh Singh static void
sev_set_guest_state(SevCommonState * sev_common,SevState new_state)29916dcf200SMichael Roth sev_set_guest_state(SevCommonState *sev_common, SevState new_state)
300620fd55cSBrijesh Singh {
301620fd55cSBrijesh Singh assert(new_state < SEV_STATE__MAX);
30216dcf200SMichael Roth assert(sev_common);
303620fd55cSBrijesh Singh
30416dcf200SMichael Roth trace_kvm_sev_change_state(SevState_str(sev_common->state),
305620fd55cSBrijesh Singh SevState_str(new_state));
30616dcf200SMichael Roth sev_common->state = new_state;
307620fd55cSBrijesh Singh }
308620fd55cSBrijesh Singh
309620fd55cSBrijesh Singh static void
sev_ram_block_added(RAMBlockNotifier * n,void * host,size_t size,size_t max_size)3108f44304cSDavid Hildenbrand sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size,
3118f44304cSDavid Hildenbrand size_t max_size)
3122b308e44SBrijesh Singh {
3132b308e44SBrijesh Singh int r;
3142b308e44SBrijesh Singh struct kvm_enc_region range;
315cedc0ad5SSingh, Brijesh ram_addr_t offset;
316cedc0ad5SSingh, Brijesh MemoryRegion *mr;
317cedc0ad5SSingh, Brijesh
318cedc0ad5SSingh, Brijesh /*
319cedc0ad5SSingh, Brijesh * The RAM device presents a memory region that should be treated
320cedc0ad5SSingh, Brijesh * as IO region and should not be pinned.
321cedc0ad5SSingh, Brijesh */
322cedc0ad5SSingh, Brijesh mr = memory_region_from_host(host, &offset);
323cedc0ad5SSingh, Brijesh if (mr && memory_region_is_ram_device(mr)) {
324cedc0ad5SSingh, Brijesh return;
325cedc0ad5SSingh, Brijesh }
3262b308e44SBrijesh Singh
327592d0bc0SPaolo Bonzini range.addr = (uintptr_t)host;
3288f44304cSDavid Hildenbrand range.size = max_size;
3292b308e44SBrijesh Singh
3308f44304cSDavid Hildenbrand trace_kvm_memcrypt_register_region(host, max_size);
3312b308e44SBrijesh Singh r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
3322b308e44SBrijesh Singh if (r) {
3332b308e44SBrijesh Singh error_report("%s: failed to register region (%p+%#zx) error '%s'",
3348f44304cSDavid Hildenbrand __func__, host, max_size, strerror(errno));
3352b308e44SBrijesh Singh exit(1);
3362b308e44SBrijesh Singh }
3372b308e44SBrijesh Singh }
3382b308e44SBrijesh Singh
3392b308e44SBrijesh Singh static void
sev_ram_block_removed(RAMBlockNotifier * n,void * host,size_t size,size_t max_size)3408f44304cSDavid Hildenbrand sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size,
3418f44304cSDavid Hildenbrand size_t max_size)
3422b308e44SBrijesh Singh {
3432b308e44SBrijesh Singh int r;
3442b308e44SBrijesh Singh struct kvm_enc_region range;
34556e2ec94SAlex Williamson ram_addr_t offset;
34656e2ec94SAlex Williamson MemoryRegion *mr;
34756e2ec94SAlex Williamson
34856e2ec94SAlex Williamson /*
34956e2ec94SAlex Williamson * The RAM device presents a memory region that should be treated
35056e2ec94SAlex Williamson * as IO region and should not have been pinned.
35156e2ec94SAlex Williamson */
35256e2ec94SAlex Williamson mr = memory_region_from_host(host, &offset);
35356e2ec94SAlex Williamson if (mr && memory_region_is_ram_device(mr)) {
35456e2ec94SAlex Williamson return;
35556e2ec94SAlex Williamson }
3562b308e44SBrijesh Singh
357592d0bc0SPaolo Bonzini range.addr = (uintptr_t)host;
3588f44304cSDavid Hildenbrand range.size = max_size;
3592b308e44SBrijesh Singh
3608f44304cSDavid Hildenbrand trace_kvm_memcrypt_unregister_region(host, max_size);
3612b308e44SBrijesh Singh r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
3622b308e44SBrijesh Singh if (r) {
3632b308e44SBrijesh Singh error_report("%s: failed to unregister region (%p+%#zx)",
3648f44304cSDavid Hildenbrand __func__, host, max_size);
3652b308e44SBrijesh Singh }
3662b308e44SBrijesh Singh }
3672b308e44SBrijesh Singh
3682b308e44SBrijesh Singh static struct RAMBlockNotifier sev_ram_notifier = {
3692b308e44SBrijesh Singh .ram_block_added = sev_ram_block_added,
3702b308e44SBrijesh Singh .ram_block_removed = sev_ram_block_removed,
3712b308e44SBrijesh Singh };
3722b308e44SBrijesh Singh
373d8575c6cSBrijesh Singh bool
sev_enabled(void)374d8575c6cSBrijesh Singh sev_enabled(void)
375d8575c6cSBrijesh Singh {
37616dcf200SMichael Roth ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
37716dcf200SMichael Roth
37816dcf200SMichael Roth return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_COMMON);
379d8575c6cSBrijesh Singh }
380d8575c6cSBrijesh Singh
3816b98e96fSTom Lendacky bool
sev_snp_enabled(void)38299190f80SMichael Roth sev_snp_enabled(void)
38399190f80SMichael Roth {
38499190f80SMichael Roth ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
38599190f80SMichael Roth
38699190f80SMichael Roth return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_SNP_GUEST);
38799190f80SMichael Roth }
38899190f80SMichael Roth
38999190f80SMichael Roth bool
sev_es_enabled(void)3906b98e96fSTom Lendacky sev_es_enabled(void)
3916b98e96fSTom Lendacky {
39216dcf200SMichael Roth ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
39316dcf200SMichael Roth
39499190f80SMichael Roth return sev_snp_enabled() ||
39599190f80SMichael Roth (sev_enabled() && SEV_GUEST(cgs)->policy & SEV_POLICY_ES);
3966b98e96fSTom Lendacky }
3976b98e96fSTom Lendacky
398d8575c6cSBrijesh Singh uint32_t
sev_get_cbit_position(void)399d8575c6cSBrijesh Singh sev_get_cbit_position(void)
400d8575c6cSBrijesh Singh {
40116dcf200SMichael Roth SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
40216dcf200SMichael Roth
40316dcf200SMichael Roth return sev_common ? sev_common->cbitpos : 0;
404d8575c6cSBrijesh Singh }
405d8575c6cSBrijesh Singh
406d8575c6cSBrijesh Singh uint32_t
sev_get_reduced_phys_bits(void)407d8575c6cSBrijesh Singh sev_get_reduced_phys_bits(void)
408d8575c6cSBrijesh Singh {
40916dcf200SMichael Roth SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
41016dcf200SMichael Roth
41116dcf200SMichael Roth return sev_common ? sev_common->reduced_phys_bits : 0;
412d8575c6cSBrijesh Singh }
413d8575c6cSBrijesh Singh
sev_get_info(void)414aa395018SPhilippe Mathieu-Daudé static SevInfo *sev_get_info(void)
415d8575c6cSBrijesh Singh {
416d8575c6cSBrijesh Singh SevInfo *info;
41716dcf200SMichael Roth SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
418d8575c6cSBrijesh Singh
419d8575c6cSBrijesh Singh info = g_new0(SevInfo, 1);
4208673dee3SDavid Gibson info->enabled = sev_enabled();
421d8575c6cSBrijesh Singh
422d8575c6cSBrijesh Singh if (info->enabled) {
42316dcf200SMichael Roth info->api_major = sev_common->api_major;
42416dcf200SMichael Roth info->api_minor = sev_common->api_minor;
42516dcf200SMichael Roth info->build_id = sev_common->build_id;
42616dcf200SMichael Roth info->state = sev_common->state;
42759d3740cSMichael Roth
42859d3740cSMichael Roth if (sev_snp_enabled()) {
42959d3740cSMichael Roth info->sev_type = SEV_GUEST_TYPE_SEV_SNP;
43059d3740cSMichael Roth info->u.sev_snp.snp_policy =
43159d3740cSMichael Roth object_property_get_uint(OBJECT(sev_common), "policy", NULL);
43259d3740cSMichael Roth } else {
43359d3740cSMichael Roth info->sev_type = SEV_GUEST_TYPE_SEV;
43459d3740cSMichael Roth info->u.sev.handle = SEV_GUEST(sev_common)->handle;
43559d3740cSMichael Roth info->u.sev.policy =
43616dcf200SMichael Roth (uint32_t)object_property_get_uint(OBJECT(sev_common),
43716dcf200SMichael Roth "policy", NULL);
43816dcf200SMichael Roth }
43959d3740cSMichael Roth }
440d8575c6cSBrijesh Singh
441d8575c6cSBrijesh Singh return info;
442d8575c6cSBrijesh Singh }
443d8575c6cSBrijesh Singh
qmp_query_sev(Error ** errp)444aa395018SPhilippe Mathieu-Daudé SevInfo *qmp_query_sev(Error **errp)
445aa395018SPhilippe Mathieu-Daudé {
446aa395018SPhilippe Mathieu-Daudé SevInfo *info;
447aa395018SPhilippe Mathieu-Daudé
448aa395018SPhilippe Mathieu-Daudé info = sev_get_info();
449aa395018SPhilippe Mathieu-Daudé if (!info) {
450aa395018SPhilippe Mathieu-Daudé error_setg(errp, "SEV feature is not available");
451aa395018SPhilippe Mathieu-Daudé return NULL;
452aa395018SPhilippe Mathieu-Daudé }
453aa395018SPhilippe Mathieu-Daudé
454aa395018SPhilippe Mathieu-Daudé return info;
455aa395018SPhilippe Mathieu-Daudé }
456aa395018SPhilippe Mathieu-Daudé
hmp_info_sev(Monitor * mon,const QDict * qdict)457aa395018SPhilippe Mathieu-Daudé void hmp_info_sev(Monitor *mon, const QDict *qdict)
458aa395018SPhilippe Mathieu-Daudé {
459aa395018SPhilippe Mathieu-Daudé SevInfo *info = sev_get_info();
460aa395018SPhilippe Mathieu-Daudé
46159d3740cSMichael Roth if (!info || !info->enabled) {
462aa395018SPhilippe Mathieu-Daudé monitor_printf(mon, "SEV is not enabled\n");
46359d3740cSMichael Roth goto out;
464aa395018SPhilippe Mathieu-Daudé }
465aa395018SPhilippe Mathieu-Daudé
46659d3740cSMichael Roth monitor_printf(mon, "SEV type: %s\n", SevGuestType_str(info->sev_type));
46759d3740cSMichael Roth monitor_printf(mon, "state: %s\n", SevState_str(info->state));
46859d3740cSMichael Roth monitor_printf(mon, "build: %d\n", info->build_id);
46959d3740cSMichael Roth monitor_printf(mon, "api version: %d.%d\n", info->api_major,
47059d3740cSMichael Roth info->api_minor);
47159d3740cSMichael Roth
47259d3740cSMichael Roth if (sev_snp_enabled()) {
47359d3740cSMichael Roth monitor_printf(mon, "debug: %s\n",
47459d3740cSMichael Roth info->u.sev_snp.snp_policy & SEV_SNP_POLICY_DBG ? "on"
47559d3740cSMichael Roth : "off");
47659d3740cSMichael Roth monitor_printf(mon, "SMT allowed: %s\n",
47759d3740cSMichael Roth info->u.sev_snp.snp_policy & SEV_SNP_POLICY_SMT ? "on"
47859d3740cSMichael Roth : "off");
47959d3740cSMichael Roth } else {
48059d3740cSMichael Roth monitor_printf(mon, "handle: %d\n", info->u.sev.handle);
48159d3740cSMichael Roth monitor_printf(mon, "debug: %s\n",
48259d3740cSMichael Roth info->u.sev.policy & SEV_POLICY_NODBG ? "off" : "on");
48359d3740cSMichael Roth monitor_printf(mon, "key-sharing: %s\n",
48459d3740cSMichael Roth info->u.sev.policy & SEV_POLICY_NOKS ? "off" : "on");
48559d3740cSMichael Roth }
48659d3740cSMichael Roth
48759d3740cSMichael Roth out:
488aa395018SPhilippe Mathieu-Daudé qapi_free_SevInfo(info);
489aa395018SPhilippe Mathieu-Daudé }
490aa395018SPhilippe Mathieu-Daudé
491620fd55cSBrijesh Singh static int
sev_get_pdh_info(int fd,guchar ** pdh,size_t * pdh_len,guchar ** cert_chain,size_t * cert_chain_len,Error ** errp)4929f750794SBrijesh Singh sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
493e4f62785SPaolo Bonzini size_t *cert_chain_len, Error **errp)
4949f750794SBrijesh Singh {
495bf3175b4SPaolo Bonzini guchar *pdh_data = NULL;
496bf3175b4SPaolo Bonzini guchar *cert_chain_data = NULL;
4979f750794SBrijesh Singh struct sev_user_data_pdh_cert_export export = {};
4989f750794SBrijesh Singh int err, r;
4999f750794SBrijesh Singh
5009f750794SBrijesh Singh /* query the certificate length */
5019f750794SBrijesh Singh r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
5029f750794SBrijesh Singh if (r < 0) {
5039f750794SBrijesh Singh if (err != SEV_RET_INVALID_LEN) {
5042c7233ebSPhilippe Mathieu-Daudé error_setg(errp, "SEV: Failed to export PDH cert"
5052c7233ebSPhilippe Mathieu-Daudé " ret=%d fw_err=%d (%s)",
5069f750794SBrijesh Singh r, err, fw_error_to_str(err));
5079f750794SBrijesh Singh return 1;
5089f750794SBrijesh Singh }
5099f750794SBrijesh Singh }
5109f750794SBrijesh Singh
5119f750794SBrijesh Singh pdh_data = g_new(guchar, export.pdh_cert_len);
5129f750794SBrijesh Singh cert_chain_data = g_new(guchar, export.cert_chain_len);
5139f750794SBrijesh Singh export.pdh_cert_address = (unsigned long)pdh_data;
5149f750794SBrijesh Singh export.cert_chain_address = (unsigned long)cert_chain_data;
5159f750794SBrijesh Singh
5169f750794SBrijesh Singh r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
5179f750794SBrijesh Singh if (r < 0) {
5182c7233ebSPhilippe Mathieu-Daudé error_setg(errp, "SEV: Failed to export PDH cert ret=%d fw_err=%d (%s)",
5199f750794SBrijesh Singh r, err, fw_error_to_str(err));
5209f750794SBrijesh Singh goto e_free;
5219f750794SBrijesh Singh }
5229f750794SBrijesh Singh
5239f750794SBrijesh Singh *pdh = pdh_data;
5249f750794SBrijesh Singh *pdh_len = export.pdh_cert_len;
5259f750794SBrijesh Singh *cert_chain = cert_chain_data;
5269f750794SBrijesh Singh *cert_chain_len = export.cert_chain_len;
5279f750794SBrijesh Singh return 0;
5289f750794SBrijesh Singh
5299f750794SBrijesh Singh e_free:
5309f750794SBrijesh Singh g_free(pdh_data);
5319f750794SBrijesh Singh g_free(cert_chain_data);
5329f750794SBrijesh Singh return 1;
5339f750794SBrijesh Singh }
5349f750794SBrijesh Singh
sev_get_cpu0_id(int fd,guchar ** id,size_t * id_len,Error ** errp)535811b4ec7SDov Murik static int sev_get_cpu0_id(int fd, guchar **id, size_t *id_len, Error **errp)
536811b4ec7SDov Murik {
537811b4ec7SDov Murik guchar *id_data;
538811b4ec7SDov Murik struct sev_user_data_get_id2 get_id2 = {};
539811b4ec7SDov Murik int err, r;
540811b4ec7SDov Murik
541811b4ec7SDov Murik /* query the ID length */
542811b4ec7SDov Murik r = sev_platform_ioctl(fd, SEV_GET_ID2, &get_id2, &err);
543811b4ec7SDov Murik if (r < 0 && err != SEV_RET_INVALID_LEN) {
544811b4ec7SDov Murik error_setg(errp, "SEV: Failed to get ID ret=%d fw_err=%d (%s)",
545811b4ec7SDov Murik r, err, fw_error_to_str(err));
546811b4ec7SDov Murik return 1;
547811b4ec7SDov Murik }
548811b4ec7SDov Murik
549811b4ec7SDov Murik id_data = g_new(guchar, get_id2.length);
550811b4ec7SDov Murik get_id2.address = (unsigned long)id_data;
551811b4ec7SDov Murik
552811b4ec7SDov Murik r = sev_platform_ioctl(fd, SEV_GET_ID2, &get_id2, &err);
553811b4ec7SDov Murik if (r < 0) {
554811b4ec7SDov Murik error_setg(errp, "SEV: Failed to get ID ret=%d fw_err=%d (%s)",
555811b4ec7SDov Murik r, err, fw_error_to_str(err));
556811b4ec7SDov Murik goto err;
557811b4ec7SDov Murik }
558811b4ec7SDov Murik
559811b4ec7SDov Murik *id = id_data;
560811b4ec7SDov Murik *id_len = get_id2.length;
561811b4ec7SDov Murik return 0;
562811b4ec7SDov Murik
563811b4ec7SDov Murik err:
564811b4ec7SDov Murik g_free(id_data);
565811b4ec7SDov Murik return 1;
566811b4ec7SDov Murik }
567811b4ec7SDov Murik
sev_get_capabilities(Error ** errp)5688371df29SPhilippe Mathieu-Daudé static SevCapability *sev_get_capabilities(Error **errp)
5699f750794SBrijesh Singh {
570bf3175b4SPaolo Bonzini SevCapability *cap = NULL;
571bf3175b4SPaolo Bonzini guchar *pdh_data = NULL;
572bf3175b4SPaolo Bonzini guchar *cert_chain_data = NULL;
573811b4ec7SDov Murik guchar *cpu0_id_data = NULL;
574811b4ec7SDov Murik size_t pdh_len = 0, cert_chain_len = 0, cpu0_id_len = 0;
5759f750794SBrijesh Singh uint32_t ebx;
5769f750794SBrijesh Singh int fd;
57716dcf200SMichael Roth SevCommonState *sev_common;
57816dcf200SMichael Roth char *sev_device;
5799f750794SBrijesh Singh
5801b38750cSPaolo Bonzini if (!kvm_enabled()) {
5811b38750cSPaolo Bonzini error_setg(errp, "KVM not enabled");
5821b38750cSPaolo Bonzini return NULL;
5831b38750cSPaolo Bonzini }
5841b38750cSPaolo Bonzini if (kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, NULL) < 0) {
5851b38750cSPaolo Bonzini error_setg(errp, "SEV is not enabled in KVM");
5861b38750cSPaolo Bonzini return NULL;
5871b38750cSPaolo Bonzini }
5881b38750cSPaolo Bonzini
58916dcf200SMichael Roth sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
590f4e5f302SMichal Privoznik if (sev_common) {
59116dcf200SMichael Roth sev_device = object_property_get_str(OBJECT(sev_common), "sev-device",
59216dcf200SMichael Roth &error_abort);
593f4e5f302SMichal Privoznik } else {
594f4e5f302SMichal Privoznik sev_device = g_strdup(DEFAULT_SEV_DEVICE);
595f4e5f302SMichal Privoznik }
596f4e5f302SMichal Privoznik
59716dcf200SMichael Roth fd = open(sev_device, O_RDWR);
5989f750794SBrijesh Singh if (fd < 0) {
5992c7233ebSPhilippe Mathieu-Daudé error_setg_errno(errp, errno, "SEV: Failed to open %s",
600ab5f4edfSMichal Privoznik sev_device);
60116dcf200SMichael Roth g_free(sev_device);
6029f750794SBrijesh Singh return NULL;
6039f750794SBrijesh Singh }
60416dcf200SMichael Roth g_free(sev_device);
6059f750794SBrijesh Singh
6069f750794SBrijesh Singh if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
607e4f62785SPaolo Bonzini &cert_chain_data, &cert_chain_len, errp)) {
608bf3175b4SPaolo Bonzini goto out;
6099f750794SBrijesh Singh }
6109f750794SBrijesh Singh
611811b4ec7SDov Murik if (sev_get_cpu0_id(fd, &cpu0_id_data, &cpu0_id_len, errp)) {
612811b4ec7SDov Murik goto out;
613811b4ec7SDov Murik }
614811b4ec7SDov Murik
6159f750794SBrijesh Singh cap = g_new0(SevCapability, 1);
6169f750794SBrijesh Singh cap->pdh = g_base64_encode(pdh_data, pdh_len);
6179f750794SBrijesh Singh cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
618811b4ec7SDov Murik cap->cpu0_id = g_base64_encode(cpu0_id_data, cpu0_id_len);
6199f750794SBrijesh Singh
6209f750794SBrijesh Singh host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
6219f750794SBrijesh Singh cap->cbitpos = ebx & 0x3f;
6229f750794SBrijesh Singh
6239f750794SBrijesh Singh /*
6249f750794SBrijesh Singh * When SEV feature is enabled, we loose one bit in guest physical
6259f750794SBrijesh Singh * addressing.
6269f750794SBrijesh Singh */
6279f750794SBrijesh Singh cap->reduced_phys_bits = 1;
6289f750794SBrijesh Singh
629bf3175b4SPaolo Bonzini out:
630811b4ec7SDov Murik g_free(cpu0_id_data);
6319f750794SBrijesh Singh g_free(pdh_data);
6329f750794SBrijesh Singh g_free(cert_chain_data);
6339f750794SBrijesh Singh close(fd);
6349f750794SBrijesh Singh return cap;
6359f750794SBrijesh Singh }
6369f750794SBrijesh Singh
qmp_query_sev_capabilities(Error ** errp)6378371df29SPhilippe Mathieu-Daudé SevCapability *qmp_query_sev_capabilities(Error **errp)
6388371df29SPhilippe Mathieu-Daudé {
6398371df29SPhilippe Mathieu-Daudé return sev_get_capabilities(errp);
6408371df29SPhilippe Mathieu-Daudé }
6418371df29SPhilippe Mathieu-Daudé
642f3c30c57SBrijesh Singh static OvmfSevMetadata *ovmf_sev_metadata_table;
643f3c30c57SBrijesh Singh
644f3c30c57SBrijesh Singh #define OVMF_SEV_META_DATA_GUID "dc886566-984a-4798-A75e-5585a7bf67cc"
645f3c30c57SBrijesh Singh typedef struct __attribute__((__packed__)) OvmfSevMetadataOffset {
646f3c30c57SBrijesh Singh uint32_t offset;
647f3c30c57SBrijesh Singh } OvmfSevMetadataOffset;
648f3c30c57SBrijesh Singh
pc_system_get_ovmf_sev_metadata_ptr(void)649f3c30c57SBrijesh Singh OvmfSevMetadata *pc_system_get_ovmf_sev_metadata_ptr(void)
650f3c30c57SBrijesh Singh {
651f3c30c57SBrijesh Singh return ovmf_sev_metadata_table;
652f3c30c57SBrijesh Singh }
653f3c30c57SBrijesh Singh
pc_system_parse_sev_metadata(uint8_t * flash_ptr,size_t flash_size)654f3c30c57SBrijesh Singh void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size)
655f3c30c57SBrijesh Singh {
656f3c30c57SBrijesh Singh OvmfSevMetadata *metadata;
657f3c30c57SBrijesh Singh OvmfSevMetadataOffset *data;
658f3c30c57SBrijesh Singh
659f3c30c57SBrijesh Singh if (!pc_system_ovmf_table_find(OVMF_SEV_META_DATA_GUID, (uint8_t **)&data,
660f3c30c57SBrijesh Singh NULL)) {
661f3c30c57SBrijesh Singh return;
662f3c30c57SBrijesh Singh }
663f3c30c57SBrijesh Singh
664f3c30c57SBrijesh Singh metadata = (OvmfSevMetadata *)(flash_ptr + flash_size - data->offset);
665f3c30c57SBrijesh Singh if (memcmp(metadata->signature, "ASEV", 4) != 0 ||
666f3c30c57SBrijesh Singh metadata->len < sizeof(OvmfSevMetadata) ||
667f3c30c57SBrijesh Singh metadata->len > flash_size - data->offset) {
668f3c30c57SBrijesh Singh return;
669f3c30c57SBrijesh Singh }
670f3c30c57SBrijesh Singh
671f3c30c57SBrijesh Singh ovmf_sev_metadata_table = g_memdup2(metadata, metadata->len);
672f3c30c57SBrijesh Singh }
673f3c30c57SBrijesh Singh
sev_get_attestation_report(const char * mnonce,Error ** errp)6743208de1cSPhilippe Mathieu-Daudé static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
6753208de1cSPhilippe Mathieu-Daudé Error **errp)
6763ea1a802SBrijesh Singh {
6773ea1a802SBrijesh Singh struct kvm_sev_attestation_report input = {};
6783ea1a802SBrijesh Singh SevAttestationReport *report = NULL;
67916dcf200SMichael Roth SevCommonState *sev_common;
680ed84ae72SDr. David Alan Gilbert g_autofree guchar *data = NULL;
681ed84ae72SDr. David Alan Gilbert g_autofree guchar *buf = NULL;
6823ea1a802SBrijesh Singh gsize len;
6833ea1a802SBrijesh Singh int err = 0, ret;
6843ea1a802SBrijesh Singh
6853ea1a802SBrijesh Singh if (!sev_enabled()) {
6863ea1a802SBrijesh Singh error_setg(errp, "SEV is not enabled");
6873ea1a802SBrijesh Singh return NULL;
6883ea1a802SBrijesh Singh }
6893ea1a802SBrijesh Singh
6903ea1a802SBrijesh Singh /* lets decode the mnonce string */
6913ea1a802SBrijesh Singh buf = g_base64_decode(mnonce, &len);
6923ea1a802SBrijesh Singh if (!buf) {
6933ea1a802SBrijesh Singh error_setg(errp, "SEV: failed to decode mnonce input");
6943ea1a802SBrijesh Singh return NULL;
6953ea1a802SBrijesh Singh }
6963ea1a802SBrijesh Singh
6973ea1a802SBrijesh Singh /* verify the input mnonce length */
6983ea1a802SBrijesh Singh if (len != sizeof(input.mnonce)) {
6993ea1a802SBrijesh Singh error_setg(errp, "SEV: mnonce must be %zu bytes (got %" G_GSIZE_FORMAT ")",
7003ea1a802SBrijesh Singh sizeof(input.mnonce), len);
7013ea1a802SBrijesh Singh return NULL;
7023ea1a802SBrijesh Singh }
7033ea1a802SBrijesh Singh
70416dcf200SMichael Roth sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
70516dcf200SMichael Roth
7063ea1a802SBrijesh Singh /* Query the report length */
70716dcf200SMichael Roth ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
7083ea1a802SBrijesh Singh &input, &err);
7093ea1a802SBrijesh Singh if (ret < 0) {
7103ea1a802SBrijesh Singh if (err != SEV_RET_INVALID_LEN) {
7112c7233ebSPhilippe Mathieu-Daudé error_setg(errp, "SEV: Failed to query the attestation report"
7122c7233ebSPhilippe Mathieu-Daudé " length ret=%d fw_err=%d (%s)",
7132c7233ebSPhilippe Mathieu-Daudé ret, err, fw_error_to_str(err));
7143ea1a802SBrijesh Singh return NULL;
7153ea1a802SBrijesh Singh }
7163ea1a802SBrijesh Singh }
7173ea1a802SBrijesh Singh
7183ea1a802SBrijesh Singh data = g_malloc(input.len);
7193ea1a802SBrijesh Singh input.uaddr = (unsigned long)data;
7203ea1a802SBrijesh Singh memcpy(input.mnonce, buf, sizeof(input.mnonce));
7213ea1a802SBrijesh Singh
7223ea1a802SBrijesh Singh /* Query the report */
72316dcf200SMichael Roth ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
7243ea1a802SBrijesh Singh &input, &err);
7253ea1a802SBrijesh Singh if (ret) {
7262c7233ebSPhilippe Mathieu-Daudé error_setg_errno(errp, errno, "SEV: Failed to get attestation report"
7273ea1a802SBrijesh Singh " ret=%d fw_err=%d (%s)", ret, err, fw_error_to_str(err));
728ed84ae72SDr. David Alan Gilbert return NULL;
7293ea1a802SBrijesh Singh }
7303ea1a802SBrijesh Singh
7313ea1a802SBrijesh Singh report = g_new0(SevAttestationReport, 1);
7323ea1a802SBrijesh Singh report->data = g_base64_encode(data, input.len);
7333ea1a802SBrijesh Singh
7343ea1a802SBrijesh Singh trace_kvm_sev_attestation_report(mnonce, report->data);
7353ea1a802SBrijesh Singh
7363ea1a802SBrijesh Singh return report;
7373ea1a802SBrijesh Singh }
7383ea1a802SBrijesh Singh
qmp_query_sev_attestation_report(const char * mnonce,Error ** errp)7393208de1cSPhilippe Mathieu-Daudé SevAttestationReport *qmp_query_sev_attestation_report(const char *mnonce,
7403208de1cSPhilippe Mathieu-Daudé Error **errp)
7413208de1cSPhilippe Mathieu-Daudé {
7423208de1cSPhilippe Mathieu-Daudé return sev_get_attestation_report(mnonce, errp);
7433208de1cSPhilippe Mathieu-Daudé }
7443208de1cSPhilippe Mathieu-Daudé
7459f750794SBrijesh Singh static int
sev_read_file_base64(const char * filename,guchar ** data,gsize * len)746620fd55cSBrijesh Singh sev_read_file_base64(const char *filename, guchar **data, gsize *len)
747620fd55cSBrijesh Singh {
748620fd55cSBrijesh Singh gsize sz;
749523a3d95SPeter Maydell g_autofree gchar *base64 = NULL;
750620fd55cSBrijesh Singh GError *error = NULL;
751620fd55cSBrijesh Singh
752620fd55cSBrijesh Singh if (!g_file_get_contents(filename, &base64, &sz, &error)) {
7532c7233ebSPhilippe Mathieu-Daudé error_report("SEV: Failed to read '%s' (%s)", filename, error->message);
754efacd5b8SPan Nengyuan g_error_free(error);
755620fd55cSBrijesh Singh return -1;
756620fd55cSBrijesh Singh }
757620fd55cSBrijesh Singh
758620fd55cSBrijesh Singh *data = g_base64_decode(base64, len);
759620fd55cSBrijesh Singh return 0;
760620fd55cSBrijesh Singh }
761620fd55cSBrijesh Singh
762620fd55cSBrijesh Singh static int
sev_snp_launch_start(SevCommonState * sev_common)763d3107f88SBrijesh Singh sev_snp_launch_start(SevCommonState *sev_common)
764d3107f88SBrijesh Singh {
765d3107f88SBrijesh Singh int fw_error, rc;
766d3107f88SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(sev_common);
767d3107f88SBrijesh Singh struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
768d3107f88SBrijesh Singh
769d3107f88SBrijesh Singh trace_kvm_sev_snp_launch_start(start->policy,
770d3107f88SBrijesh Singh sev_snp_guest->guest_visible_workarounds);
771d3107f88SBrijesh Singh
772e3cddff9SMichael Roth if (!kvm_enable_hypercall(BIT_ULL(KVM_HC_MAP_GPA_RANGE))) {
773e3cddff9SMichael Roth return 1;
774e3cddff9SMichael Roth }
775e3cddff9SMichael Roth
776d3107f88SBrijesh Singh rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_START,
777d3107f88SBrijesh Singh start, &fw_error);
778d3107f88SBrijesh Singh if (rc < 0) {
779d3107f88SBrijesh Singh error_report("%s: SNP_LAUNCH_START ret=%d fw_error=%d '%s'",
780d3107f88SBrijesh Singh __func__, rc, fw_error, fw_error_to_str(fw_error));
781d3107f88SBrijesh Singh return 1;
782d3107f88SBrijesh Singh }
783d3107f88SBrijesh Singh
784d3107f88SBrijesh Singh QTAILQ_INIT(&launch_update);
785d3107f88SBrijesh Singh
786d3107f88SBrijesh Singh sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE);
787d3107f88SBrijesh Singh
788d3107f88SBrijesh Singh return 0;
789d3107f88SBrijesh Singh }
790d3107f88SBrijesh Singh
791d3107f88SBrijesh Singh static int
sev_launch_start(SevCommonState * sev_common)7926600f1acSPankaj Gupta sev_launch_start(SevCommonState *sev_common)
793620fd55cSBrijesh Singh {
794620fd55cSBrijesh Singh gsize sz;
795620fd55cSBrijesh Singh int ret = 1;
796bf3175b4SPaolo Bonzini int fw_error, rc;
7976600f1acSPankaj Gupta SevGuestState *sev_guest = SEV_GUEST(sev_common);
798eb8257a2SDov Murik struct kvm_sev_launch_start start = {
79916dcf200SMichael Roth .handle = sev_guest->handle, .policy = sev_guest->policy
800eb8257a2SDov Murik };
801620fd55cSBrijesh Singh guchar *session = NULL, *dh_cert = NULL;
802620fd55cSBrijesh Singh
80316dcf200SMichael Roth if (sev_guest->session_file) {
80416dcf200SMichael Roth if (sev_read_file_base64(sev_guest->session_file, &session, &sz) < 0) {
805bf3175b4SPaolo Bonzini goto out;
806620fd55cSBrijesh Singh }
807eb8257a2SDov Murik start.session_uaddr = (unsigned long)session;
808eb8257a2SDov Murik start.session_len = sz;
809620fd55cSBrijesh Singh }
810620fd55cSBrijesh Singh
81116dcf200SMichael Roth if (sev_guest->dh_cert_file) {
81216dcf200SMichael Roth if (sev_read_file_base64(sev_guest->dh_cert_file, &dh_cert, &sz) < 0) {
813bf3175b4SPaolo Bonzini goto out;
814620fd55cSBrijesh Singh }
815eb8257a2SDov Murik start.dh_uaddr = (unsigned long)dh_cert;
816eb8257a2SDov Murik start.dh_len = sz;
817620fd55cSBrijesh Singh }
818620fd55cSBrijesh Singh
819eb8257a2SDov Murik trace_kvm_sev_launch_start(start.policy, session, dh_cert);
82016dcf200SMichael Roth rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_START, &start, &fw_error);
821bf3175b4SPaolo Bonzini if (rc < 0) {
822620fd55cSBrijesh Singh error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
823620fd55cSBrijesh Singh __func__, ret, fw_error, fw_error_to_str(fw_error));
824bf3175b4SPaolo Bonzini goto out;
825620fd55cSBrijesh Singh }
826620fd55cSBrijesh Singh
82716dcf200SMichael Roth sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE);
82816dcf200SMichael Roth sev_guest->handle = start.handle;
829bf3175b4SPaolo Bonzini ret = 0;
830620fd55cSBrijesh Singh
831bf3175b4SPaolo Bonzini out:
832620fd55cSBrijesh Singh g_free(session);
833620fd55cSBrijesh Singh g_free(dh_cert);
834bf3175b4SPaolo Bonzini return ret;
835620fd55cSBrijesh Singh }
836620fd55cSBrijesh Singh
83770943ad8SMichael Roth static void
sev_snp_cpuid_report_mismatches(SnpCpuidInfo * old,SnpCpuidInfo * new)83870943ad8SMichael Roth sev_snp_cpuid_report_mismatches(SnpCpuidInfo *old,
83970943ad8SMichael Roth SnpCpuidInfo *new)
84070943ad8SMichael Roth {
84170943ad8SMichael Roth size_t i;
84270943ad8SMichael Roth
84370943ad8SMichael Roth if (old->count != new->count) {
84470943ad8SMichael Roth error_report("SEV-SNP: CPUID validation failed due to count mismatch, "
84570943ad8SMichael Roth "provided: %d, expected: %d", old->count, new->count);
84670943ad8SMichael Roth return;
84770943ad8SMichael Roth }
84870943ad8SMichael Roth
84970943ad8SMichael Roth for (i = 0; i < old->count; i++) {
85070943ad8SMichael Roth SnpCpuidFunc *old_func, *new_func;
85170943ad8SMichael Roth
85270943ad8SMichael Roth old_func = &old->entries[i];
85370943ad8SMichael Roth new_func = &new->entries[i];
85470943ad8SMichael Roth
85570943ad8SMichael Roth if (memcmp(old_func, new_func, sizeof(SnpCpuidFunc))) {
8569b40d376SPaolo Bonzini error_report("SEV-SNP: CPUID validation failed for function 0x%x, index: 0x%x, "
8579b40d376SPaolo Bonzini "provided: eax:0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x, "
85870943ad8SMichael Roth "expected: eax:0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x",
85970943ad8SMichael Roth old_func->eax_in, old_func->ecx_in,
86070943ad8SMichael Roth old_func->eax, old_func->ebx, old_func->ecx, old_func->edx,
86170943ad8SMichael Roth new_func->eax, new_func->ebx, new_func->ecx, new_func->edx);
86270943ad8SMichael Roth }
86370943ad8SMichael Roth }
86470943ad8SMichael Roth }
86570943ad8SMichael Roth
8669f3a6999SBrijesh Singh static const char *
snp_page_type_to_str(int type)8679f3a6999SBrijesh Singh snp_page_type_to_str(int type)
8689f3a6999SBrijesh Singh {
8699f3a6999SBrijesh Singh switch (type) {
8709f3a6999SBrijesh Singh case KVM_SEV_SNP_PAGE_TYPE_NORMAL: return "Normal";
8719f3a6999SBrijesh Singh case KVM_SEV_SNP_PAGE_TYPE_ZERO: return "Zero";
8729f3a6999SBrijesh Singh case KVM_SEV_SNP_PAGE_TYPE_UNMEASURED: return "Unmeasured";
8739f3a6999SBrijesh Singh case KVM_SEV_SNP_PAGE_TYPE_SECRETS: return "Secrets";
8749f3a6999SBrijesh Singh case KVM_SEV_SNP_PAGE_TYPE_CPUID: return "Cpuid";
8759f3a6999SBrijesh Singh default: return "unknown";
8769f3a6999SBrijesh Singh }
8779f3a6999SBrijesh Singh }
8789f3a6999SBrijesh Singh
8799f3a6999SBrijesh Singh static int
sev_snp_launch_update(SevSnpGuestState * sev_snp_guest,SevLaunchUpdateData * data)8809f3a6999SBrijesh Singh sev_snp_launch_update(SevSnpGuestState *sev_snp_guest,
8819f3a6999SBrijesh Singh SevLaunchUpdateData *data)
8829f3a6999SBrijesh Singh {
8839f3a6999SBrijesh Singh int ret, fw_error;
88470943ad8SMichael Roth SnpCpuidInfo snp_cpuid_info;
8859f3a6999SBrijesh Singh struct kvm_sev_snp_launch_update update = {0};
8869f3a6999SBrijesh Singh
8879f3a6999SBrijesh Singh if (!data->hva || !data->len) {
8889f3a6999SBrijesh Singh error_report("SNP_LAUNCH_UPDATE called with invalid address"
889cb61b174SRichard Henderson "/ length: %p / %zx",
8909f3a6999SBrijesh Singh data->hva, data->len);
8919f3a6999SBrijesh Singh return 1;
8929f3a6999SBrijesh Singh }
8939f3a6999SBrijesh Singh
89470943ad8SMichael Roth if (data->type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
89570943ad8SMichael Roth /* Save a copy for comparison in case the LAUNCH_UPDATE fails */
89670943ad8SMichael Roth memcpy(&snp_cpuid_info, data->hva, sizeof(snp_cpuid_info));
89770943ad8SMichael Roth }
89870943ad8SMichael Roth
8999f3a6999SBrijesh Singh update.uaddr = (__u64)(unsigned long)data->hva;
9009f3a6999SBrijesh Singh update.gfn_start = data->gpa >> TARGET_PAGE_BITS;
9019f3a6999SBrijesh Singh update.len = data->len;
9029f3a6999SBrijesh Singh update.type = data->type;
9039f3a6999SBrijesh Singh
9049f3a6999SBrijesh Singh /*
9059f3a6999SBrijesh Singh * KVM_SEV_SNP_LAUNCH_UPDATE requires that GPA ranges have the private
9069f3a6999SBrijesh Singh * memory attribute set in advance.
9079f3a6999SBrijesh Singh */
9089f3a6999SBrijesh Singh ret = kvm_set_memory_attributes_private(data->gpa, data->len);
9099f3a6999SBrijesh Singh if (ret) {
9109f3a6999SBrijesh Singh error_report("SEV-SNP: failed to configure initial"
9119f3a6999SBrijesh Singh "private guest memory");
9129f3a6999SBrijesh Singh goto out;
9139f3a6999SBrijesh Singh }
9149f3a6999SBrijesh Singh
9159f3a6999SBrijesh Singh while (update.len || ret == -EAGAIN) {
9169f3a6999SBrijesh Singh trace_kvm_sev_snp_launch_update(update.uaddr, update.gfn_start <<
9179f3a6999SBrijesh Singh TARGET_PAGE_BITS, update.len,
9189f3a6999SBrijesh Singh snp_page_type_to_str(update.type));
9199f3a6999SBrijesh Singh
9209f3a6999SBrijesh Singh ret = sev_ioctl(SEV_COMMON(sev_snp_guest)->sev_fd,
9219f3a6999SBrijesh Singh KVM_SEV_SNP_LAUNCH_UPDATE,
9229f3a6999SBrijesh Singh &update, &fw_error);
9239f3a6999SBrijesh Singh if (ret && ret != -EAGAIN) {
9249f3a6999SBrijesh Singh error_report("SNP_LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
9259f3a6999SBrijesh Singh ret, fw_error, fw_error_to_str(fw_error));
92670943ad8SMichael Roth
92770943ad8SMichael Roth if (data->type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
92870943ad8SMichael Roth sev_snp_cpuid_report_mismatches(&snp_cpuid_info, data->hva);
92970943ad8SMichael Roth error_report("SEV-SNP: failed update CPUID page");
93070943ad8SMichael Roth }
9319f3a6999SBrijesh Singh break;
9329f3a6999SBrijesh Singh }
9339f3a6999SBrijesh Singh }
9349f3a6999SBrijesh Singh
9359f3a6999SBrijesh Singh out:
9369f3a6999SBrijesh Singh if (!ret && update.gfn_start << TARGET_PAGE_BITS != data->gpa + data->len) {
937b31d3867SRichard Henderson error_report("SEV-SNP: expected update of GPA range %"
938b31d3867SRichard Henderson HWADDR_PRIx "-%" HWADDR_PRIx ","
939b31d3867SRichard Henderson "got GPA range %" HWADDR_PRIx "-%llx",
9409f3a6999SBrijesh Singh data->gpa, data->gpa + data->len, data->gpa,
9419f3a6999SBrijesh Singh update.gfn_start << TARGET_PAGE_BITS);
9429f3a6999SBrijesh Singh ret = -EIO;
9439f3a6999SBrijesh Singh }
9449f3a6999SBrijesh Singh
9459f3a6999SBrijesh Singh return ret;
9469f3a6999SBrijesh Singh }
9479f3a6999SBrijesh Singh
948188569c1SPaolo Bonzini static uint32_t
sev_snp_mask_cpuid_features(X86ConfidentialGuest * cg,uint32_t feature,uint32_t index,int reg,uint32_t value)949188569c1SPaolo Bonzini sev_snp_mask_cpuid_features(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index,
950188569c1SPaolo Bonzini int reg, uint32_t value)
951188569c1SPaolo Bonzini {
952188569c1SPaolo Bonzini switch (feature) {
953188569c1SPaolo Bonzini case 1:
954188569c1SPaolo Bonzini if (reg == R_ECX) {
955188569c1SPaolo Bonzini return value & ~CPUID_EXT_TSC_DEADLINE_TIMER;
956188569c1SPaolo Bonzini }
957188569c1SPaolo Bonzini break;
958188569c1SPaolo Bonzini case 7:
959188569c1SPaolo Bonzini if (index == 0 && reg == R_EBX) {
960188569c1SPaolo Bonzini return value & ~CPUID_7_0_EBX_TSC_ADJUST;
961188569c1SPaolo Bonzini }
962188569c1SPaolo Bonzini if (index == 0 && reg == R_EDX) {
963188569c1SPaolo Bonzini return value & ~(CPUID_7_0_EDX_SPEC_CTRL |
964188569c1SPaolo Bonzini CPUID_7_0_EDX_STIBP |
965188569c1SPaolo Bonzini CPUID_7_0_EDX_FLUSH_L1D |
966188569c1SPaolo Bonzini CPUID_7_0_EDX_ARCH_CAPABILITIES |
967188569c1SPaolo Bonzini CPUID_7_0_EDX_CORE_CAPABILITY |
968188569c1SPaolo Bonzini CPUID_7_0_EDX_SPEC_CTRL_SSBD);
969188569c1SPaolo Bonzini }
970188569c1SPaolo Bonzini break;
971188569c1SPaolo Bonzini case 0x80000008:
972188569c1SPaolo Bonzini if (reg == R_EBX) {
973188569c1SPaolo Bonzini return value & ~CPUID_8000_0008_EBX_VIRT_SSBD;
974188569c1SPaolo Bonzini }
975188569c1SPaolo Bonzini break;
976188569c1SPaolo Bonzini }
977188569c1SPaolo Bonzini return value;
978188569c1SPaolo Bonzini }
979188569c1SPaolo Bonzini
980b738d630SBrijesh Singh static int
sev_launch_update_data(SevCommonState * sev_common,hwaddr gpa,uint8_t * addr,size_t len)981cb61b174SRichard Henderson sev_launch_update_data(SevCommonState *sev_common, hwaddr gpa,
982cb61b174SRichard Henderson uint8_t *addr, size_t len)
983b738d630SBrijesh Singh {
984b738d630SBrijesh Singh int ret, fw_error;
985b738d630SBrijesh Singh struct kvm_sev_launch_update_data update;
986b738d630SBrijesh Singh
987b738d630SBrijesh Singh if (!addr || !len) {
988b738d630SBrijesh Singh return 1;
989b738d630SBrijesh Singh }
990b738d630SBrijesh Singh
991592d0bc0SPaolo Bonzini update.uaddr = (uintptr_t)addr;
992b738d630SBrijesh Singh update.len = len;
993b738d630SBrijesh Singh trace_kvm_sev_launch_update_data(addr, len);
9949861405aSPaolo Bonzini ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
995b738d630SBrijesh Singh &update, &fw_error);
996b738d630SBrijesh Singh if (ret) {
997b738d630SBrijesh Singh error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
998b738d630SBrijesh Singh __func__, ret, fw_error, fw_error_to_str(fw_error));
999b738d630SBrijesh Singh }
1000b738d630SBrijesh Singh
1001b738d630SBrijesh Singh return ret;
1002b738d630SBrijesh Singh }
1003b738d630SBrijesh Singh
10046b98e96fSTom Lendacky static int
sev_launch_update_vmsa(SevGuestState * sev_guest)100516dcf200SMichael Roth sev_launch_update_vmsa(SevGuestState *sev_guest)
10066b98e96fSTom Lendacky {
10076b98e96fSTom Lendacky int ret, fw_error;
10086b98e96fSTom Lendacky
100916dcf200SMichael Roth ret = sev_ioctl(SEV_COMMON(sev_guest)->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA,
101016dcf200SMichael Roth NULL, &fw_error);
10116b98e96fSTom Lendacky if (ret) {
10126b98e96fSTom Lendacky error_report("%s: LAUNCH_UPDATE_VMSA ret=%d fw_error=%d '%s'",
10136b98e96fSTom Lendacky __func__, ret, fw_error, fw_error_to_str(fw_error));
10146b98e96fSTom Lendacky }
10156b98e96fSTom Lendacky
10166b98e96fSTom Lendacky return ret;
10176b98e96fSTom Lendacky }
10186b98e96fSTom Lendacky
1019c6c89c97SBrijesh Singh static void
sev_launch_get_measure(Notifier * notifier,void * unused)1020c6c89c97SBrijesh Singh sev_launch_get_measure(Notifier *notifier, void *unused)
1021c6c89c97SBrijesh Singh {
102216dcf200SMichael Roth SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
102316dcf200SMichael Roth SevGuestState *sev_guest = SEV_GUEST(sev_common);
1024c6c89c97SBrijesh Singh int ret, error;
10252f573c41SPhilippe Mathieu-Daudé g_autofree guchar *data = NULL;
102659e42d88SDov Murik struct kvm_sev_launch_measure measurement = {};
1027c6c89c97SBrijesh Singh
102816dcf200SMichael Roth if (!sev_check_state(sev_common, SEV_STATE_LAUNCH_UPDATE)) {
1029c6c89c97SBrijesh Singh return;
1030c6c89c97SBrijesh Singh }
1031c6c89c97SBrijesh Singh
10326b98e96fSTom Lendacky if (sev_es_enabled()) {
10336b98e96fSTom Lendacky /* measure all the VM save areas before getting launch_measure */
103416dcf200SMichael Roth ret = sev_launch_update_vmsa(sev_guest);
10356b98e96fSTom Lendacky if (ret) {
10366b98e96fSTom Lendacky exit(1);
10376b98e96fSTom Lendacky }
10385c3131c3SPaolo Bonzini kvm_mark_guest_state_protected();
10396b98e96fSTom Lendacky }
10406b98e96fSTom Lendacky
1041c6c89c97SBrijesh Singh /* query the measurement blob length */
104216dcf200SMichael Roth ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_MEASURE,
104359e42d88SDov Murik &measurement, &error);
104459e42d88SDov Murik if (!measurement.len) {
1045c6c89c97SBrijesh Singh error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
1046c6c89c97SBrijesh Singh __func__, ret, error, fw_error_to_str(errno));
10472f573c41SPhilippe Mathieu-Daudé return;
1048c6c89c97SBrijesh Singh }
1049c6c89c97SBrijesh Singh
105059e42d88SDov Murik data = g_new0(guchar, measurement.len);
105159e42d88SDov Murik measurement.uaddr = (unsigned long)data;
1052c6c89c97SBrijesh Singh
1053c6c89c97SBrijesh Singh /* get the measurement blob */
105416dcf200SMichael Roth ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_MEASURE,
105559e42d88SDov Murik &measurement, &error);
1056c6c89c97SBrijesh Singh if (ret) {
1057c6c89c97SBrijesh Singh error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
1058c6c89c97SBrijesh Singh __func__, ret, error, fw_error_to_str(errno));
10592f573c41SPhilippe Mathieu-Daudé return;
1060c6c89c97SBrijesh Singh }
1061c6c89c97SBrijesh Singh
106216dcf200SMichael Roth sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_SECRET);
1063c6c89c97SBrijesh Singh
1064c6c89c97SBrijesh Singh /* encode the measurement value and emit the event */
106516dcf200SMichael Roth sev_guest->measurement = g_base64_encode(data, measurement.len);
106616dcf200SMichael Roth trace_kvm_sev_launch_measurement(sev_guest->measurement);
1067c6c89c97SBrijesh Singh }
1068c6c89c97SBrijesh Singh
sev_get_launch_measurement(void)10690875a703SPhilippe Mathieu-Daudé static char *sev_get_launch_measurement(void)
1070c6c89c97SBrijesh Singh {
107173ae63b1SMichael Roth ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
107273ae63b1SMichael Roth SevGuestState *sev_guest =
107373ae63b1SMichael Roth (SevGuestState *)object_dynamic_cast(OBJECT(cgs), TYPE_SEV_GUEST);
107416dcf200SMichael Roth
10758673dee3SDavid Gibson if (sev_guest &&
107616dcf200SMichael Roth SEV_COMMON(sev_guest)->state >= SEV_STATE_LAUNCH_SECRET) {
1077421522ebSDavid Gibson return g_strdup(sev_guest->measurement);
1078c6c89c97SBrijesh Singh }
1079c6c89c97SBrijesh Singh
1080c6c89c97SBrijesh Singh return NULL;
1081c6c89c97SBrijesh Singh }
1082c6c89c97SBrijesh Singh
qmp_query_sev_launch_measure(Error ** errp)10830875a703SPhilippe Mathieu-Daudé SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error **errp)
10840875a703SPhilippe Mathieu-Daudé {
10850875a703SPhilippe Mathieu-Daudé char *data;
10860875a703SPhilippe Mathieu-Daudé SevLaunchMeasureInfo *info;
10870875a703SPhilippe Mathieu-Daudé
10880875a703SPhilippe Mathieu-Daudé data = sev_get_launch_measurement();
10890875a703SPhilippe Mathieu-Daudé if (!data) {
10900875a703SPhilippe Mathieu-Daudé error_setg(errp, "SEV launch measurement is not available");
10910875a703SPhilippe Mathieu-Daudé return NULL;
10920875a703SPhilippe Mathieu-Daudé }
10930875a703SPhilippe Mathieu-Daudé
10940875a703SPhilippe Mathieu-Daudé info = g_malloc0(sizeof(*info));
10950875a703SPhilippe Mathieu-Daudé info->data = data;
10960875a703SPhilippe Mathieu-Daudé
10970875a703SPhilippe Mathieu-Daudé return info;
10980875a703SPhilippe Mathieu-Daudé }
10990875a703SPhilippe Mathieu-Daudé
1100c6c89c97SBrijesh Singh static Notifier sev_machine_done_notify = {
1101c6c89c97SBrijesh Singh .notify = sev_launch_get_measure,
1102c6c89c97SBrijesh Singh };
1103c6c89c97SBrijesh Singh
11045dd0df7eSBrijesh Singh static void
sev_launch_finish(SevCommonState * sev_common)1105bce615a1SPankaj Gupta sev_launch_finish(SevCommonState *sev_common)
11065dd0df7eSBrijesh Singh {
11075dd0df7eSBrijesh Singh int ret, error;
11085dd0df7eSBrijesh Singh
11095dd0df7eSBrijesh Singh trace_kvm_sev_launch_finish();
1110bce615a1SPankaj Gupta ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_FINISH, 0,
111116dcf200SMichael Roth &error);
11125dd0df7eSBrijesh Singh if (ret) {
11135dd0df7eSBrijesh Singh error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
11145dd0df7eSBrijesh Singh __func__, ret, error, fw_error_to_str(error));
11155dd0df7eSBrijesh Singh exit(1);
11165dd0df7eSBrijesh Singh }
11175dd0df7eSBrijesh Singh
1118bce615a1SPankaj Gupta sev_set_guest_state(sev_common, SEV_STATE_RUNNING);
11198fa4466dSBrijesh Singh
11208fa4466dSBrijesh Singh /* add migration blocker */
11218fa4466dSBrijesh Singh error_setg(&sev_mig_blocker,
11228fa4466dSBrijesh Singh "SEV: Migration is not implemented");
1123c8a7fc51SSteve Sistare migrate_add_blocker(&sev_mig_blocker, &error_fatal);
11245dd0df7eSBrijesh Singh }
11255dd0df7eSBrijesh Singh
11263d8c2a7fSBrijesh Singh static int
snp_launch_update_data(uint64_t gpa,void * hva,size_t len,int type)1127cb61b174SRichard Henderson snp_launch_update_data(uint64_t gpa, void *hva, size_t len, int type)
11283d8c2a7fSBrijesh Singh {
11293d8c2a7fSBrijesh Singh SevLaunchUpdateData *data;
11303d8c2a7fSBrijesh Singh
11313d8c2a7fSBrijesh Singh data = g_new0(SevLaunchUpdateData, 1);
11323d8c2a7fSBrijesh Singh data->gpa = gpa;
11333d8c2a7fSBrijesh Singh data->hva = hva;
11343d8c2a7fSBrijesh Singh data->len = len;
11353d8c2a7fSBrijesh Singh data->type = type;
11363d8c2a7fSBrijesh Singh
11373d8c2a7fSBrijesh Singh QTAILQ_INSERT_TAIL(&launch_update, data, next);
11383d8c2a7fSBrijesh Singh
11393d8c2a7fSBrijesh Singh return 0;
11403d8c2a7fSBrijesh Singh }
11413d8c2a7fSBrijesh Singh
11423d8c2a7fSBrijesh Singh static int
sev_snp_launch_update_data(SevCommonState * sev_common,hwaddr gpa,uint8_t * ptr,size_t len)11430765d136SPankaj Gupta sev_snp_launch_update_data(SevCommonState *sev_common, hwaddr gpa,
1144cb61b174SRichard Henderson uint8_t *ptr, size_t len)
11450765d136SPankaj Gupta {
11460765d136SPankaj Gupta int ret = snp_launch_update_data(gpa, ptr, len,
11470765d136SPankaj Gupta KVM_SEV_SNP_PAGE_TYPE_NORMAL);
11480765d136SPankaj Gupta return ret;
11490765d136SPankaj Gupta }
11500765d136SPankaj Gupta
11510765d136SPankaj Gupta static int
sev_snp_cpuid_info_fill(SnpCpuidInfo * snp_cpuid_info,const KvmCpuidInfo * kvm_cpuid_info)115270943ad8SMichael Roth sev_snp_cpuid_info_fill(SnpCpuidInfo *snp_cpuid_info,
115370943ad8SMichael Roth const KvmCpuidInfo *kvm_cpuid_info)
115470943ad8SMichael Roth {
115570943ad8SMichael Roth size_t i;
115670943ad8SMichael Roth
115770943ad8SMichael Roth if (kvm_cpuid_info->cpuid.nent > SNP_CPUID_FUNCTION_MAXCOUNT) {
115870943ad8SMichael Roth error_report("SEV-SNP: CPUID entry count (%d) exceeds max (%d)",
115970943ad8SMichael Roth kvm_cpuid_info->cpuid.nent, SNP_CPUID_FUNCTION_MAXCOUNT);
116070943ad8SMichael Roth return -1;
116170943ad8SMichael Roth }
116270943ad8SMichael Roth
116370943ad8SMichael Roth memset(snp_cpuid_info, 0, sizeof(*snp_cpuid_info));
116470943ad8SMichael Roth
116570943ad8SMichael Roth for (i = 0; i < kvm_cpuid_info->cpuid.nent; i++) {
116670943ad8SMichael Roth const struct kvm_cpuid_entry2 *kvm_cpuid_entry;
116770943ad8SMichael Roth SnpCpuidFunc *snp_cpuid_entry;
116870943ad8SMichael Roth
116970943ad8SMichael Roth kvm_cpuid_entry = &kvm_cpuid_info->entries[i];
117070943ad8SMichael Roth snp_cpuid_entry = &snp_cpuid_info->entries[i];
117170943ad8SMichael Roth
117270943ad8SMichael Roth snp_cpuid_entry->eax_in = kvm_cpuid_entry->function;
117370943ad8SMichael Roth if (kvm_cpuid_entry->flags == KVM_CPUID_FLAG_SIGNIFCANT_INDEX) {
117470943ad8SMichael Roth snp_cpuid_entry->ecx_in = kvm_cpuid_entry->index;
117570943ad8SMichael Roth }
117670943ad8SMichael Roth snp_cpuid_entry->eax = kvm_cpuid_entry->eax;
117770943ad8SMichael Roth snp_cpuid_entry->ebx = kvm_cpuid_entry->ebx;
117870943ad8SMichael Roth snp_cpuid_entry->ecx = kvm_cpuid_entry->ecx;
117970943ad8SMichael Roth snp_cpuid_entry->edx = kvm_cpuid_entry->edx;
118070943ad8SMichael Roth
118170943ad8SMichael Roth /*
118270943ad8SMichael Roth * Guest kernels will calculate EBX themselves using the 0xD
118370943ad8SMichael Roth * subfunctions corresponding to the individual XSAVE areas, so only
118470943ad8SMichael Roth * encode the base XSAVE size in the initial leaves, corresponding
118570943ad8SMichael Roth * to the initial XCR0=1 state.
118670943ad8SMichael Roth */
118770943ad8SMichael Roth if (snp_cpuid_entry->eax_in == 0xD &&
118870943ad8SMichael Roth (snp_cpuid_entry->ecx_in == 0x0 || snp_cpuid_entry->ecx_in == 0x1)) {
118970943ad8SMichael Roth snp_cpuid_entry->ebx = 0x240;
119070943ad8SMichael Roth snp_cpuid_entry->xcr0_in = 1;
119170943ad8SMichael Roth snp_cpuid_entry->xss_in = 0;
119270943ad8SMichael Roth }
119370943ad8SMichael Roth }
119470943ad8SMichael Roth
119570943ad8SMichael Roth snp_cpuid_info->count = i;
119670943ad8SMichael Roth
119770943ad8SMichael Roth return 0;
119870943ad8SMichael Roth }
119970943ad8SMichael Roth
120070943ad8SMichael Roth static int
snp_launch_update_cpuid(uint32_t cpuid_addr,void * hva,size_t cpuid_len)1201cb61b174SRichard Henderson snp_launch_update_cpuid(uint32_t cpuid_addr, void *hva, size_t cpuid_len)
120270943ad8SMichael Roth {
120370943ad8SMichael Roth KvmCpuidInfo kvm_cpuid_info = {0};
120470943ad8SMichael Roth SnpCpuidInfo snp_cpuid_info;
120570943ad8SMichael Roth CPUState *cs = first_cpu;
120670943ad8SMichael Roth int ret;
120770943ad8SMichael Roth uint32_t i = 0;
120870943ad8SMichael Roth
120970943ad8SMichael Roth assert(sizeof(snp_cpuid_info) <= cpuid_len);
121070943ad8SMichael Roth
121170943ad8SMichael Roth /* get the cpuid list from KVM */
121270943ad8SMichael Roth do {
121370943ad8SMichael Roth kvm_cpuid_info.cpuid.nent = ++i;
121470943ad8SMichael Roth ret = kvm_vcpu_ioctl(cs, KVM_GET_CPUID2, &kvm_cpuid_info);
121570943ad8SMichael Roth } while (ret == -E2BIG);
121670943ad8SMichael Roth
121770943ad8SMichael Roth if (ret) {
121870943ad8SMichael Roth error_report("SEV-SNP: unable to query CPUID values for CPU: '%s'",
121970943ad8SMichael Roth strerror(-ret));
122070943ad8SMichael Roth return 1;
122170943ad8SMichael Roth }
122270943ad8SMichael Roth
122370943ad8SMichael Roth ret = sev_snp_cpuid_info_fill(&snp_cpuid_info, &kvm_cpuid_info);
122470943ad8SMichael Roth if (ret) {
122570943ad8SMichael Roth error_report("SEV-SNP: failed to generate CPUID table information");
122670943ad8SMichael Roth return 1;
122770943ad8SMichael Roth }
122870943ad8SMichael Roth
122970943ad8SMichael Roth memcpy(hva, &snp_cpuid_info, sizeof(snp_cpuid_info));
123070943ad8SMichael Roth
123170943ad8SMichael Roth return snp_launch_update_data(cpuid_addr, hva, cpuid_len,
123270943ad8SMichael Roth KVM_SEV_SNP_PAGE_TYPE_CPUID);
123370943ad8SMichael Roth }
123470943ad8SMichael Roth
123570943ad8SMichael Roth static int
snp_launch_update_kernel_hashes(SevSnpGuestState * sev_snp,uint32_t addr,void * hva,uint32_t len)1236c1996992SDov Murik snp_launch_update_kernel_hashes(SevSnpGuestState *sev_snp, uint32_t addr,
1237c1996992SDov Murik void *hva, uint32_t len)
1238c1996992SDov Murik {
1239c1996992SDov Murik int type = KVM_SEV_SNP_PAGE_TYPE_ZERO;
1240c1996992SDov Murik if (sev_snp->parent_obj.kernel_hashes) {
1241c1996992SDov Murik assert(sev_snp->kernel_hashes_data);
1242c1996992SDov Murik assert((sev_snp->kernel_hashes_offset +
1243c1996992SDov Murik sizeof(*sev_snp->kernel_hashes_data)) <= len);
1244c1996992SDov Murik memset(hva, 0, len);
1245c1996992SDov Murik memcpy(hva + sev_snp->kernel_hashes_offset, sev_snp->kernel_hashes_data,
1246c1996992SDov Murik sizeof(*sev_snp->kernel_hashes_data));
1247c1996992SDov Murik type = KVM_SEV_SNP_PAGE_TYPE_NORMAL;
1248c1996992SDov Murik }
1249c1996992SDov Murik return snp_launch_update_data(addr, hva, len, type);
1250c1996992SDov Murik }
1251c1996992SDov Murik
1252c1996992SDov Murik static int
snp_metadata_desc_to_page_type(int desc_type)12533d8c2a7fSBrijesh Singh snp_metadata_desc_to_page_type(int desc_type)
12543d8c2a7fSBrijesh Singh {
12553d8c2a7fSBrijesh Singh switch (desc_type) {
12563d8c2a7fSBrijesh Singh /* Add the umeasured prevalidated pages as a zero page */
12573d8c2a7fSBrijesh Singh case SEV_DESC_TYPE_SNP_SEC_MEM: return KVM_SEV_SNP_PAGE_TYPE_ZERO;
12583d8c2a7fSBrijesh Singh case SEV_DESC_TYPE_SNP_SECRETS: return KVM_SEV_SNP_PAGE_TYPE_SECRETS;
12593d8c2a7fSBrijesh Singh case SEV_DESC_TYPE_CPUID: return KVM_SEV_SNP_PAGE_TYPE_CPUID;
12603d8c2a7fSBrijesh Singh default:
12613d8c2a7fSBrijesh Singh return KVM_SEV_SNP_PAGE_TYPE_ZERO;
12623d8c2a7fSBrijesh Singh }
12633d8c2a7fSBrijesh Singh }
12643d8c2a7fSBrijesh Singh
12653d8c2a7fSBrijesh Singh static void
snp_populate_metadata_pages(SevSnpGuestState * sev_snp,OvmfSevMetadata * metadata)12663d8c2a7fSBrijesh Singh snp_populate_metadata_pages(SevSnpGuestState *sev_snp,
12673d8c2a7fSBrijesh Singh OvmfSevMetadata *metadata)
12683d8c2a7fSBrijesh Singh {
12693d8c2a7fSBrijesh Singh OvmfSevMetadataDesc *desc;
12703d8c2a7fSBrijesh Singh int type, ret, i;
12713d8c2a7fSBrijesh Singh void *hva;
12723d8c2a7fSBrijesh Singh MemoryRegion *mr = NULL;
12733d8c2a7fSBrijesh Singh
12743d8c2a7fSBrijesh Singh for (i = 0; i < metadata->num_desc; i++) {
12753d8c2a7fSBrijesh Singh desc = &metadata->descs[i];
12763d8c2a7fSBrijesh Singh
12773d8c2a7fSBrijesh Singh type = snp_metadata_desc_to_page_type(desc->type);
12783d8c2a7fSBrijesh Singh
12793d8c2a7fSBrijesh Singh hva = gpa2hva(&mr, desc->base, desc->len, NULL);
12803d8c2a7fSBrijesh Singh if (!hva) {
12813d8c2a7fSBrijesh Singh error_report("%s: Failed to get HVA for GPA 0x%x sz 0x%x",
12823d8c2a7fSBrijesh Singh __func__, desc->base, desc->len);
12833d8c2a7fSBrijesh Singh exit(1);
12843d8c2a7fSBrijesh Singh }
12853d8c2a7fSBrijesh Singh
128670943ad8SMichael Roth if (type == KVM_SEV_SNP_PAGE_TYPE_CPUID) {
128770943ad8SMichael Roth ret = snp_launch_update_cpuid(desc->base, hva, desc->len);
1288c1996992SDov Murik } else if (desc->type == SEV_DESC_TYPE_SNP_KERNEL_HASHES) {
1289c1996992SDov Murik ret = snp_launch_update_kernel_hashes(sev_snp, desc->base, hva,
1290c1996992SDov Murik desc->len);
129170943ad8SMichael Roth } else {
12923d8c2a7fSBrijesh Singh ret = snp_launch_update_data(desc->base, hva, desc->len, type);
129370943ad8SMichael Roth }
129470943ad8SMichael Roth
12953d8c2a7fSBrijesh Singh if (ret) {
12963d8c2a7fSBrijesh Singh error_report("%s: Failed to add metadata page gpa 0x%x+%x type %d",
12973d8c2a7fSBrijesh Singh __func__, desc->base, desc->len, desc->type);
12983d8c2a7fSBrijesh Singh exit(1);
12993d8c2a7fSBrijesh Singh }
13003d8c2a7fSBrijesh Singh }
13013d8c2a7fSBrijesh Singh }
13023d8c2a7fSBrijesh Singh
13035dd0df7eSBrijesh Singh static void
sev_snp_launch_finish(SevCommonState * sev_common)13049f3a6999SBrijesh Singh sev_snp_launch_finish(SevCommonState *sev_common)
13059f3a6999SBrijesh Singh {
13069f3a6999SBrijesh Singh int ret, error;
13079f3a6999SBrijesh Singh Error *local_err = NULL;
13083d8c2a7fSBrijesh Singh OvmfSevMetadata *metadata;
13099f3a6999SBrijesh Singh SevLaunchUpdateData *data;
13109f3a6999SBrijesh Singh SevSnpGuestState *sev_snp = SEV_SNP_GUEST(sev_common);
13119f3a6999SBrijesh Singh struct kvm_sev_snp_launch_finish *finish = &sev_snp->kvm_finish_conf;
13129f3a6999SBrijesh Singh
13133d8c2a7fSBrijesh Singh /*
13143d8c2a7fSBrijesh Singh * To boot the SNP guest, the hypervisor is required to populate the CPUID
13153d8c2a7fSBrijesh Singh * and Secrets page before finalizing the launch flow. The location of
13163d8c2a7fSBrijesh Singh * the secrets and CPUID page is available through the OVMF metadata GUID.
13173d8c2a7fSBrijesh Singh */
13183d8c2a7fSBrijesh Singh metadata = pc_system_get_ovmf_sev_metadata_ptr();
13193d8c2a7fSBrijesh Singh if (metadata == NULL) {
13203d8c2a7fSBrijesh Singh error_report("%s: Failed to locate SEV metadata header", __func__);
13213d8c2a7fSBrijesh Singh exit(1);
13223d8c2a7fSBrijesh Singh }
13233d8c2a7fSBrijesh Singh
13243d8c2a7fSBrijesh Singh /* Populate all the metadata pages */
13253d8c2a7fSBrijesh Singh snp_populate_metadata_pages(sev_snp, metadata);
13263d8c2a7fSBrijesh Singh
13279f3a6999SBrijesh Singh QTAILQ_FOREACH(data, &launch_update, next) {
13289f3a6999SBrijesh Singh ret = sev_snp_launch_update(sev_snp, data);
13299f3a6999SBrijesh Singh if (ret) {
13309f3a6999SBrijesh Singh exit(1);
13319f3a6999SBrijesh Singh }
13329f3a6999SBrijesh Singh }
13339f3a6999SBrijesh Singh
1334803b7718SPaolo Bonzini trace_kvm_sev_snp_launch_finish(sev_snp->id_block_base64, sev_snp->id_auth_base64,
13359f3a6999SBrijesh Singh sev_snp->host_data);
13369f3a6999SBrijesh Singh ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_FINISH,
13379f3a6999SBrijesh Singh finish, &error);
13389f3a6999SBrijesh Singh if (ret) {
13399f3a6999SBrijesh Singh error_report("SNP_LAUNCH_FINISH ret=%d fw_error=%d '%s'",
13409f3a6999SBrijesh Singh ret, error, fw_error_to_str(error));
13419f3a6999SBrijesh Singh exit(1);
13429f3a6999SBrijesh Singh }
13439f3a6999SBrijesh Singh
13443d44fdffSMichael Roth kvm_mark_guest_state_protected();
13459f3a6999SBrijesh Singh sev_set_guest_state(sev_common, SEV_STATE_RUNNING);
13469f3a6999SBrijesh Singh
13479f3a6999SBrijesh Singh /* add migration blocker */
13489f3a6999SBrijesh Singh error_setg(&sev_mig_blocker,
13499f3a6999SBrijesh Singh "SEV-SNP: Migration is not implemented");
13509f3a6999SBrijesh Singh ret = migrate_add_blocker(&sev_mig_blocker, &local_err);
13519f3a6999SBrijesh Singh if (local_err) {
13529f3a6999SBrijesh Singh error_report_err(local_err);
13539f3a6999SBrijesh Singh error_free(sev_mig_blocker);
13549f3a6999SBrijesh Singh exit(1);
13559f3a6999SBrijesh Singh }
13569f3a6999SBrijesh Singh }
13579f3a6999SBrijesh Singh
13589f3a6999SBrijesh Singh
13599f3a6999SBrijesh Singh static void
sev_vm_state_change(void * opaque,bool running,RunState state)1360538f0497SPhilippe Mathieu-Daudé sev_vm_state_change(void *opaque, bool running, RunState state)
13615dd0df7eSBrijesh Singh {
136216dcf200SMichael Roth SevCommonState *sev_common = opaque;
1363bce615a1SPankaj Gupta SevCommonStateClass *klass = SEV_COMMON_GET_CLASS(opaque);
13645dd0df7eSBrijesh Singh
13655dd0df7eSBrijesh Singh if (running) {
136616dcf200SMichael Roth if (!sev_check_state(sev_common, SEV_STATE_RUNNING)) {
1367bce615a1SPankaj Gupta klass->launch_finish(sev_common);
13685dd0df7eSBrijesh Singh }
13695dd0df7eSBrijesh Singh }
13705dd0df7eSBrijesh Singh }
13715dd0df7eSBrijesh Singh
13729d38d9dcSMichael Roth /*
13739d38d9dcSMichael Roth * This helper is to examine sev-guest properties and determine if any options
13749d38d9dcSMichael Roth * have been set which rely on the newer KVM_SEV_INIT2 interface and associated
13759d38d9dcSMichael Roth * KVM VM types.
13769d38d9dcSMichael Roth */
sev_init2_required(SevGuestState * sev_guest)13779d38d9dcSMichael Roth static bool sev_init2_required(SevGuestState *sev_guest)
13789d38d9dcSMichael Roth {
13799d38d9dcSMichael Roth /* Currently no KVM_SEV_INIT2-specific options are exposed via QEMU */
13809d38d9dcSMichael Roth return false;
13819d38d9dcSMichael Roth }
13829d38d9dcSMichael Roth
sev_kvm_type(X86ConfidentialGuest * cg)1383663e2f44SPaolo Bonzini static int sev_kvm_type(X86ConfidentialGuest *cg)
1384663e2f44SPaolo Bonzini {
138516dcf200SMichael Roth SevCommonState *sev_common = SEV_COMMON(cg);
138616dcf200SMichael Roth SevGuestState *sev_guest = SEV_GUEST(sev_common);
1387663e2f44SPaolo Bonzini int kvm_type;
1388663e2f44SPaolo Bonzini
138916dcf200SMichael Roth if (sev_common->kvm_type != -1) {
1390663e2f44SPaolo Bonzini goto out;
1391663e2f44SPaolo Bonzini }
1392663e2f44SPaolo Bonzini
13939d38d9dcSMichael Roth /* These are the only cases where legacy VM types can be used. */
13949d38d9dcSMichael Roth if (sev_guest->legacy_vm_type == ON_OFF_AUTO_ON ||
13959d38d9dcSMichael Roth (sev_guest->legacy_vm_type == ON_OFF_AUTO_AUTO &&
13969d38d9dcSMichael Roth !sev_init2_required(sev_guest))) {
139716dcf200SMichael Roth sev_common->kvm_type = KVM_X86_DEFAULT_VM;
13989d38d9dcSMichael Roth goto out;
1399663e2f44SPaolo Bonzini }
1400663e2f44SPaolo Bonzini
14019d38d9dcSMichael Roth /*
14029d38d9dcSMichael Roth * Newer VM types are required, either explicitly via legacy-vm-type=on, or
14039d38d9dcSMichael Roth * implicitly via legacy-vm-type=auto along with additional sev-guest
14049d38d9dcSMichael Roth * properties that require the newer VM types.
14059d38d9dcSMichael Roth */
14069d38d9dcSMichael Roth kvm_type = (sev_guest->policy & SEV_POLICY_ES) ?
14079d38d9dcSMichael Roth KVM_X86_SEV_ES_VM : KVM_X86_SEV_VM;
14089d38d9dcSMichael Roth if (!kvm_is_vm_type_supported(kvm_type)) {
14099d38d9dcSMichael Roth if (sev_guest->legacy_vm_type == ON_OFF_AUTO_AUTO) {
14109d38d9dcSMichael Roth error_report("SEV: host kernel does not support requested %s VM type, which is required "
14119d38d9dcSMichael Roth "for the set of options specified. To allow use of the legacy "
14129d38d9dcSMichael Roth "KVM_X86_DEFAULT_VM VM type, please disable any options that are not "
14139d38d9dcSMichael Roth "compatible with the legacy VM type, or upgrade your kernel.",
14149d38d9dcSMichael Roth kvm_type == KVM_X86_SEV_VM ? "KVM_X86_SEV_VM" : "KVM_X86_SEV_ES_VM");
14159d38d9dcSMichael Roth } else {
14169d38d9dcSMichael Roth error_report("SEV: host kernel does not support requested %s VM type. To allow use of "
14179d38d9dcSMichael Roth "the legacy KVM_X86_DEFAULT_VM VM type, the 'legacy-vm-type' argument "
14189d38d9dcSMichael Roth "must be set to 'on' or 'auto' for the sev-guest object.",
14199d38d9dcSMichael Roth kvm_type == KVM_X86_SEV_VM ? "KVM_X86_SEV_VM" : "KVM_X86_SEV_ES_VM");
14209d38d9dcSMichael Roth }
14219d38d9dcSMichael Roth
14229d38d9dcSMichael Roth return -1;
14239d38d9dcSMichael Roth }
14249d38d9dcSMichael Roth
14259d38d9dcSMichael Roth sev_common->kvm_type = kvm_type;
1426663e2f44SPaolo Bonzini out:
142716dcf200SMichael Roth return sev_common->kvm_type;
1428663e2f44SPaolo Bonzini }
1429663e2f44SPaolo Bonzini
sev_snp_kvm_type(X86ConfidentialGuest * cg)1430a808132fSPaolo Bonzini static int sev_snp_kvm_type(X86ConfidentialGuest *cg)
1431a808132fSPaolo Bonzini {
1432a808132fSPaolo Bonzini return KVM_X86_SNP_VM;
1433a808132fSPaolo Bonzini }
1434a808132fSPaolo Bonzini
sev_common_kvm_init(ConfidentialGuestSupport * cgs,Error ** errp)1435990da8d2SPankaj Gupta static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
1436d8575c6cSBrijesh Singh {
1437d8575c6cSBrijesh Singh char *devname;
14386b98e96fSTom Lendacky int ret, fw_error, cmd;
1439d8575c6cSBrijesh Singh uint32_t ebx;
1440d8575c6cSBrijesh Singh uint32_t host_cbitpos;
1441d8575c6cSBrijesh Singh struct sev_user_data_status status = {};
1442125b95a6SPankaj Gupta SevCommonState *sev_common = SEV_COMMON(cgs);
14436600f1acSPankaj Gupta SevCommonStateClass *klass = SEV_COMMON_GET_CLASS(cgs);
1444a808132fSPaolo Bonzini X86ConfidentialGuestClass *x86_klass =
1445a808132fSPaolo Bonzini X86_CONFIDENTIAL_GUEST_GET_CLASS(cgs);
1446d8575c6cSBrijesh Singh
144716dcf200SMichael Roth sev_common->state = SEV_STATE_UNINIT;
1448d8575c6cSBrijesh Singh
1449d8575c6cSBrijesh Singh host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
1450d8575c6cSBrijesh Singh host_cbitpos = ebx & 0x3f;
1451d8575c6cSBrijesh Singh
14528168fed9STom Lendacky /*
14538168fed9STom Lendacky * The cbitpos value will be placed in bit positions 5:0 of the EBX
14548168fed9STom Lendacky * register of CPUID 0x8000001F. No need to verify the range as the
14558168fed9STom Lendacky * comparison against the host value accomplishes that.
14568168fed9STom Lendacky */
145716dcf200SMichael Roth if (host_cbitpos != sev_common->cbitpos) {
1458c9f5aaa6SDavid Gibson error_setg(errp, "%s: cbitpos check failed, host '%d' requested '%d'",
145916dcf200SMichael Roth __func__, host_cbitpos, sev_common->cbitpos);
1460990da8d2SPankaj Gupta return -1;
1461d8575c6cSBrijesh Singh }
1462d8575c6cSBrijesh Singh
14638168fed9STom Lendacky /*
14648168fed9STom Lendacky * The reduced-phys-bits value will be placed in bit positions 11:6 of
14658168fed9STom Lendacky * the EBX register of CPUID 0x8000001F, so verify the supplied value
14668168fed9STom Lendacky * is in the range of 1 to 63.
14678168fed9STom Lendacky */
146816dcf200SMichael Roth if (sev_common->reduced_phys_bits < 1 ||
146916dcf200SMichael Roth sev_common->reduced_phys_bits > 63) {
14708168fed9STom Lendacky error_setg(errp, "%s: reduced_phys_bits check failed,"
14718168fed9STom Lendacky " it should be in the range of 1 to 63, requested '%d'",
147216dcf200SMichael Roth __func__, sev_common->reduced_phys_bits);
1473990da8d2SPankaj Gupta return -1;
1474d8575c6cSBrijesh Singh }
1475d8575c6cSBrijesh Singh
147616dcf200SMichael Roth devname = object_property_get_str(OBJECT(sev_common), "sev-device", NULL);
147716dcf200SMichael Roth sev_common->sev_fd = open(devname, O_RDWR);
147816dcf200SMichael Roth if (sev_common->sev_fd < 0) {
1479c9f5aaa6SDavid Gibson error_setg(errp, "%s: Failed to open %s '%s'", __func__,
1480d8575c6cSBrijesh Singh devname, strerror(errno));
1481d8575c6cSBrijesh Singh g_free(devname);
1482990da8d2SPankaj Gupta return -1;
14835d7bc72aSGreg Kurz }
1484c9f5aaa6SDavid Gibson g_free(devname);
1485d8575c6cSBrijesh Singh
148616dcf200SMichael Roth ret = sev_platform_ioctl(sev_common->sev_fd, SEV_PLATFORM_STATUS, &status,
1487d8575c6cSBrijesh Singh &fw_error);
1488d8575c6cSBrijesh Singh if (ret) {
1489c9f5aaa6SDavid Gibson error_setg(errp, "%s: failed to get platform status ret=%d "
1490d8575c6cSBrijesh Singh "fw_error='%d: %s'", __func__, ret, fw_error,
1491d8575c6cSBrijesh Singh fw_error_to_str(fw_error));
1492990da8d2SPankaj Gupta return -1;
1493d8575c6cSBrijesh Singh }
149416dcf200SMichael Roth sev_common->build_id = status.build;
149516dcf200SMichael Roth sev_common->api_major = status.api_major;
149616dcf200SMichael Roth sev_common->api_minor = status.api_minor;
1497d8575c6cSBrijesh Singh
14986b98e96fSTom Lendacky if (sev_es_enabled()) {
14999681f867STom Lendacky if (!kvm_kernel_irqchip_allowed()) {
150018c45340SPankaj Gupta error_setg(errp, "%s: SEV-ES guests require in-kernel irqchip"
150118c45340SPankaj Gupta "support", __func__);
1502990da8d2SPankaj Gupta return -1;
15039681f867STom Lendacky }
150499190f80SMichael Roth }
15059681f867STom Lendacky
150699190f80SMichael Roth if (sev_es_enabled() && !sev_snp_enabled()) {
15076b98e96fSTom Lendacky if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) {
150818c45340SPankaj Gupta error_setg(errp, "%s: guest policy requires SEV-ES, but "
15096b98e96fSTom Lendacky "host SEV-ES support unavailable",
15106b98e96fSTom Lendacky __func__);
1511990da8d2SPankaj Gupta return -1;
15126b98e96fSTom Lendacky }
15136b98e96fSTom Lendacky }
15146b98e96fSTom Lendacky
1515d8575c6cSBrijesh Singh trace_kvm_sev_init();
15169d38d9dcSMichael Roth switch (x86_klass->kvm_type(X86_CONFIDENTIAL_GUEST(sev_common))) {
15179d38d9dcSMichael Roth case KVM_X86_DEFAULT_VM:
1518663e2f44SPaolo Bonzini cmd = sev_es_enabled() ? KVM_SEV_ES_INIT : KVM_SEV_INIT;
1519663e2f44SPaolo Bonzini
152016dcf200SMichael Roth ret = sev_ioctl(sev_common->sev_fd, cmd, NULL, &fw_error);
15219d38d9dcSMichael Roth break;
15229d38d9dcSMichael Roth case KVM_X86_SEV_VM:
15239d38d9dcSMichael Roth case KVM_X86_SEV_ES_VM:
15249d38d9dcSMichael Roth case KVM_X86_SNP_VM: {
1525663e2f44SPaolo Bonzini struct kvm_sev_init args = { 0 };
1526663e2f44SPaolo Bonzini
152716dcf200SMichael Roth ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_INIT2, &args, &fw_error);
15289d38d9dcSMichael Roth break;
15299d38d9dcSMichael Roth }
15309d38d9dcSMichael Roth default:
15319d38d9dcSMichael Roth error_setg(errp, "%s: host kernel does not support the requested SEV configuration.",
15329d38d9dcSMichael Roth __func__);
15339d38d9dcSMichael Roth return -1;
1534663e2f44SPaolo Bonzini }
1535663e2f44SPaolo Bonzini
1536d8575c6cSBrijesh Singh if (ret) {
1537c9f5aaa6SDavid Gibson error_setg(errp, "%s: failed to initialize ret=%d fw_error=%d '%s'",
1538d8575c6cSBrijesh Singh __func__, ret, fw_error, fw_error_to_str(fw_error));
1539990da8d2SPankaj Gupta return -1;
1540d8575c6cSBrijesh Singh }
1541d8575c6cSBrijesh Singh
15426600f1acSPankaj Gupta ret = klass->launch_start(sev_common);
1543d3107f88SBrijesh Singh
1544620fd55cSBrijesh Singh if (ret) {
1545c9f5aaa6SDavid Gibson error_setg(errp, "%s: failed to create encryption context", __func__);
1546990da8d2SPankaj Gupta return -1;
1547620fd55cSBrijesh Singh }
1548620fd55cSBrijesh Singh
1549990da8d2SPankaj Gupta if (klass->kvm_init && klass->kvm_init(cgs, errp)) {
1550990da8d2SPankaj Gupta return -1;
1551990da8d2SPankaj Gupta }
1552990da8d2SPankaj Gupta
155316dcf200SMichael Roth qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
15542b308e44SBrijesh Singh
1555abc27d42SDavid Gibson cgs->ready = true;
1556abc27d42SDavid Gibson
1557aacdb844SDavid Gibson return 0;
1558990da8d2SPankaj Gupta }
1559990da8d2SPankaj Gupta
sev_kvm_init(ConfidentialGuestSupport * cgs,Error ** errp)1560990da8d2SPankaj Gupta static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
1561990da8d2SPankaj Gupta {
1562990da8d2SPankaj Gupta int ret;
1563990da8d2SPankaj Gupta
1564990da8d2SPankaj Gupta /*
1565990da8d2SPankaj Gupta * SEV/SEV-ES rely on pinned memory to back guest RAM so discarding
1566990da8d2SPankaj Gupta * isn't actually possible. With SNP, only guest_memfd pages are used
1567990da8d2SPankaj Gupta * for private guest memory, so discarding of shared memory is still
1568990da8d2SPankaj Gupta * possible..
1569990da8d2SPankaj Gupta */
1570990da8d2SPankaj Gupta ret = ram_block_discard_disable(true);
1571990da8d2SPankaj Gupta if (ret) {
1572990da8d2SPankaj Gupta error_setg(errp, "%s: cannot disable RAM discard", __func__);
1573aacdb844SDavid Gibson return -1;
1574d8575c6cSBrijesh Singh }
1575d8575c6cSBrijesh Singh
1576990da8d2SPankaj Gupta /*
1577990da8d2SPankaj Gupta * SEV uses these notifiers to register/pin pages prior to guest use,
1578990da8d2SPankaj Gupta * but SNP relies on guest_memfd for private pages, which has its
1579990da8d2SPankaj Gupta * own internal mechanisms for registering/pinning private memory.
1580990da8d2SPankaj Gupta */
1581990da8d2SPankaj Gupta ram_block_notifier_add(&sev_ram_notifier);
1582990da8d2SPankaj Gupta
1583990da8d2SPankaj Gupta /*
1584990da8d2SPankaj Gupta * The machine done notify event is used for SEV guests to get the
1585990da8d2SPankaj Gupta * measurement of the encrypted images. When SEV-SNP is enabled, the
1586990da8d2SPankaj Gupta * measurement is part of the guest attestation process where it can
1587990da8d2SPankaj Gupta * be collected without any reliance on the VMM. So skip registering
1588990da8d2SPankaj Gupta * the notifier for SNP in favor of using guest attestation instead.
1589990da8d2SPankaj Gupta */
1590990da8d2SPankaj Gupta qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
1591990da8d2SPankaj Gupta
1592990da8d2SPankaj Gupta return 0;
1593990da8d2SPankaj Gupta }
1594990da8d2SPankaj Gupta
sev_snp_kvm_init(ConfidentialGuestSupport * cgs,Error ** errp)1595125b95a6SPankaj Gupta static int sev_snp_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
1596125b95a6SPankaj Gupta {
1597125b95a6SPankaj Gupta MachineState *ms = MACHINE(qdev_get_machine());
1598125b95a6SPankaj Gupta X86MachineState *x86ms = X86_MACHINE(ms);
1599125b95a6SPankaj Gupta
1600125b95a6SPankaj Gupta if (x86ms->smm == ON_OFF_AUTO_AUTO) {
1601125b95a6SPankaj Gupta x86ms->smm = ON_OFF_AUTO_OFF;
1602125b95a6SPankaj Gupta } else if (x86ms->smm == ON_OFF_AUTO_ON) {
1603125b95a6SPankaj Gupta error_setg(errp, "SEV-SNP does not support SMM.");
1604125b95a6SPankaj Gupta return -1;
1605125b95a6SPankaj Gupta }
1606125b95a6SPankaj Gupta
1607125b95a6SPankaj Gupta return 0;
1608125b95a6SPankaj Gupta }
1609125b95a6SPankaj Gupta
1610b738d630SBrijesh Singh int
sev_encrypt_flash(hwaddr gpa,uint8_t * ptr,uint64_t len,Error ** errp)161177d1abd9SBrijesh Singh sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t len, Error **errp)
1612b738d630SBrijesh Singh {
161316dcf200SMichael Roth SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
161448779faeSPankaj Gupta SevCommonStateClass *klass;
161516dcf200SMichael Roth
161616dcf200SMichael Roth if (!sev_common) {
1617aacdb844SDavid Gibson return 0;
1618aacdb844SDavid Gibson }
161948779faeSPankaj Gupta klass = SEV_COMMON_GET_CLASS(sev_common);
1620b738d630SBrijesh Singh
1621b738d630SBrijesh Singh /* if SEV is in update state then encrypt the data else do nothing */
162216dcf200SMichael Roth if (sev_check_state(sev_common, SEV_STATE_LAUNCH_UPDATE)) {
16239861405aSPaolo Bonzini int ret;
16249861405aSPaolo Bonzini
16259861405aSPaolo Bonzini ret = klass->launch_update_data(sev_common, gpa, ptr, len);
1626aacdb844SDavid Gibson if (ret < 0) {
16272c7233ebSPhilippe Mathieu-Daudé error_setg(errp, "SEV: Failed to encrypt pflash rom");
1628aacdb844SDavid Gibson return ret;
1629aacdb844SDavid Gibson }
1630b738d630SBrijesh Singh }
1631b738d630SBrijesh Singh
1632b738d630SBrijesh Singh return 0;
1633b738d630SBrijesh Singh }
1634b738d630SBrijesh Singh
sev_inject_launch_secret(const char * packet_hdr,const char * secret,uint64_t gpa,Error ** errp)1635c7f7e697STobin Feldman-Fitzthum int sev_inject_launch_secret(const char *packet_hdr, const char *secret,
1636c7f7e697STobin Feldman-Fitzthum uint64_t gpa, Error **errp)
1637c7f7e697STobin Feldman-Fitzthum {
1638f55cceacSZhao Liu ERRP_GUARD();
1639c7f7e697STobin Feldman-Fitzthum struct kvm_sev_launch_secret input;
1640c7f7e697STobin Feldman-Fitzthum g_autofree guchar *data = NULL, *hdr = NULL;
1641c7f7e697STobin Feldman-Fitzthum int error, ret = 1;
1642c7f7e697STobin Feldman-Fitzthum void *hva;
1643c7f7e697STobin Feldman-Fitzthum gsize hdr_sz = 0, data_sz = 0;
1644c7f7e697STobin Feldman-Fitzthum MemoryRegion *mr = NULL;
164516dcf200SMichael Roth SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
1646c7f7e697STobin Feldman-Fitzthum
164716dcf200SMichael Roth if (!sev_common) {
16482c7233ebSPhilippe Mathieu-Daudé error_setg(errp, "SEV not enabled for guest");
1649c7f7e697STobin Feldman-Fitzthum return 1;
1650c7f7e697STobin Feldman-Fitzthum }
1651c7f7e697STobin Feldman-Fitzthum
1652c7f7e697STobin Feldman-Fitzthum /* secret can be injected only in this state */
165316dcf200SMichael Roth if (!sev_check_state(sev_common, SEV_STATE_LAUNCH_SECRET)) {
1654c7f7e697STobin Feldman-Fitzthum error_setg(errp, "SEV: Not in correct state. (LSECRET) %x",
165516dcf200SMichael Roth sev_common->state);
1656c7f7e697STobin Feldman-Fitzthum return 1;
1657c7f7e697STobin Feldman-Fitzthum }
1658c7f7e697STobin Feldman-Fitzthum
1659c7f7e697STobin Feldman-Fitzthum hdr = g_base64_decode(packet_hdr, &hdr_sz);
1660c7f7e697STobin Feldman-Fitzthum if (!hdr || !hdr_sz) {
1661c7f7e697STobin Feldman-Fitzthum error_setg(errp, "SEV: Failed to decode sequence header");
1662c7f7e697STobin Feldman-Fitzthum return 1;
1663c7f7e697STobin Feldman-Fitzthum }
1664c7f7e697STobin Feldman-Fitzthum
1665c7f7e697STobin Feldman-Fitzthum data = g_base64_decode(secret, &data_sz);
1666c7f7e697STobin Feldman-Fitzthum if (!data || !data_sz) {
1667c7f7e697STobin Feldman-Fitzthum error_setg(errp, "SEV: Failed to decode data");
1668c7f7e697STobin Feldman-Fitzthum return 1;
1669c7f7e697STobin Feldman-Fitzthum }
1670c7f7e697STobin Feldman-Fitzthum
1671c7f7e697STobin Feldman-Fitzthum hva = gpa2hva(&mr, gpa, data_sz, errp);
1672c7f7e697STobin Feldman-Fitzthum if (!hva) {
1673c7f7e697STobin Feldman-Fitzthum error_prepend(errp, "SEV: Failed to calculate guest address: ");
1674c7f7e697STobin Feldman-Fitzthum return 1;
1675c7f7e697STobin Feldman-Fitzthum }
1676c7f7e697STobin Feldman-Fitzthum
1677c7f7e697STobin Feldman-Fitzthum input.hdr_uaddr = (uint64_t)(unsigned long)hdr;
1678c7f7e697STobin Feldman-Fitzthum input.hdr_len = hdr_sz;
1679c7f7e697STobin Feldman-Fitzthum
1680c7f7e697STobin Feldman-Fitzthum input.trans_uaddr = (uint64_t)(unsigned long)data;
1681c7f7e697STobin Feldman-Fitzthum input.trans_len = data_sz;
1682c7f7e697STobin Feldman-Fitzthum
1683c7f7e697STobin Feldman-Fitzthum input.guest_uaddr = (uint64_t)(unsigned long)hva;
1684c7f7e697STobin Feldman-Fitzthum input.guest_len = data_sz;
1685c7f7e697STobin Feldman-Fitzthum
1686c7f7e697STobin Feldman-Fitzthum trace_kvm_sev_launch_secret(gpa, input.guest_uaddr,
1687c7f7e697STobin Feldman-Fitzthum input.trans_uaddr, input.trans_len);
1688c7f7e697STobin Feldman-Fitzthum
168916dcf200SMichael Roth ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_SECRET,
1690c7f7e697STobin Feldman-Fitzthum &input, &error);
1691c7f7e697STobin Feldman-Fitzthum if (ret) {
1692c7f7e697STobin Feldman-Fitzthum error_setg(errp, "SEV: failed to inject secret ret=%d fw_error=%d '%s'",
1693c7f7e697STobin Feldman-Fitzthum ret, error, fw_error_to_str(error));
1694c7f7e697STobin Feldman-Fitzthum return ret;
1695c7f7e697STobin Feldman-Fitzthum }
1696c7f7e697STobin Feldman-Fitzthum
1697c7f7e697STobin Feldman-Fitzthum return 0;
1698c7f7e697STobin Feldman-Fitzthum }
1699c7f7e697STobin Feldman-Fitzthum
170011a6ed0eSPhilippe Mathieu-Daudé #define SEV_SECRET_GUID "4c2eb361-7d9b-4cc3-8081-127c90d3d294"
170111a6ed0eSPhilippe Mathieu-Daudé struct sev_secret_area {
170211a6ed0eSPhilippe Mathieu-Daudé uint32_t base;
170311a6ed0eSPhilippe Mathieu-Daudé uint32_t size;
170411a6ed0eSPhilippe Mathieu-Daudé };
170511a6ed0eSPhilippe Mathieu-Daudé
qmp_sev_inject_launch_secret(const char * packet_hdr,const char * secret,bool has_gpa,uint64_t gpa,Error ** errp)170611a6ed0eSPhilippe Mathieu-Daudé void qmp_sev_inject_launch_secret(const char *packet_hdr,
170711a6ed0eSPhilippe Mathieu-Daudé const char *secret,
170811a6ed0eSPhilippe Mathieu-Daudé bool has_gpa, uint64_t gpa,
170911a6ed0eSPhilippe Mathieu-Daudé Error **errp)
171011a6ed0eSPhilippe Mathieu-Daudé {
171111a6ed0eSPhilippe Mathieu-Daudé if (!sev_enabled()) {
171211a6ed0eSPhilippe Mathieu-Daudé error_setg(errp, "SEV not enabled for guest");
171311a6ed0eSPhilippe Mathieu-Daudé return;
171411a6ed0eSPhilippe Mathieu-Daudé }
171511a6ed0eSPhilippe Mathieu-Daudé if (!has_gpa) {
171611a6ed0eSPhilippe Mathieu-Daudé uint8_t *data;
171711a6ed0eSPhilippe Mathieu-Daudé struct sev_secret_area *area;
171811a6ed0eSPhilippe Mathieu-Daudé
171911a6ed0eSPhilippe Mathieu-Daudé if (!pc_system_ovmf_table_find(SEV_SECRET_GUID, &data, NULL)) {
172011a6ed0eSPhilippe Mathieu-Daudé error_setg(errp, "SEV: no secret area found in OVMF,"
172111a6ed0eSPhilippe Mathieu-Daudé " gpa must be specified.");
172211a6ed0eSPhilippe Mathieu-Daudé return;
172311a6ed0eSPhilippe Mathieu-Daudé }
172411a6ed0eSPhilippe Mathieu-Daudé area = (struct sev_secret_area *)data;
172511a6ed0eSPhilippe Mathieu-Daudé gpa = area->base;
172611a6ed0eSPhilippe Mathieu-Daudé }
172711a6ed0eSPhilippe Mathieu-Daudé
172811a6ed0eSPhilippe Mathieu-Daudé sev_inject_launch_secret(packet_hdr, secret, gpa, errp);
172911a6ed0eSPhilippe Mathieu-Daudé }
173011a6ed0eSPhilippe Mathieu-Daudé
1731b2f73a07SPaolo Bonzini static int
sev_es_parse_reset_block(SevInfoBlock * info,uint32_t * addr)1732b2f73a07SPaolo Bonzini sev_es_parse_reset_block(SevInfoBlock *info, uint32_t *addr)
1733b2f73a07SPaolo Bonzini {
1734b2f73a07SPaolo Bonzini if (!info->reset_addr) {
1735b2f73a07SPaolo Bonzini error_report("SEV-ES reset address is zero");
1736b2f73a07SPaolo Bonzini return 1;
1737b2f73a07SPaolo Bonzini }
1738b2f73a07SPaolo Bonzini
1739b2f73a07SPaolo Bonzini *addr = info->reset_addr;
1740b2f73a07SPaolo Bonzini
1741b2f73a07SPaolo Bonzini return 0;
1742b2f73a07SPaolo Bonzini }
1743b2f73a07SPaolo Bonzini
1744b2f73a07SPaolo Bonzini static int
sev_es_find_reset_vector(void * flash_ptr,uint64_t flash_size,uint32_t * addr)1745b2f73a07SPaolo Bonzini sev_es_find_reset_vector(void *flash_ptr, uint64_t flash_size,
1746b2f73a07SPaolo Bonzini uint32_t *addr)
1747b2f73a07SPaolo Bonzini {
1748b2f73a07SPaolo Bonzini QemuUUID info_guid, *guid;
1749b2f73a07SPaolo Bonzini SevInfoBlock *info;
1750b2f73a07SPaolo Bonzini uint8_t *data;
1751b2f73a07SPaolo Bonzini uint16_t *len;
1752b2f73a07SPaolo Bonzini
1753b2f73a07SPaolo Bonzini /*
1754b2f73a07SPaolo Bonzini * Initialize the address to zero. An address of zero with a successful
1755b2f73a07SPaolo Bonzini * return code indicates that SEV-ES is not active.
1756b2f73a07SPaolo Bonzini */
1757b2f73a07SPaolo Bonzini *addr = 0;
1758b2f73a07SPaolo Bonzini
1759b2f73a07SPaolo Bonzini /*
1760b2f73a07SPaolo Bonzini * Extract the AP reset vector for SEV-ES guests by locating the SEV GUID.
1761b2f73a07SPaolo Bonzini * The SEV GUID is located on its own (original implementation) or within
1762b2f73a07SPaolo Bonzini * the Firmware GUID Table (new implementation), either of which are
1763b2f73a07SPaolo Bonzini * located 32 bytes from the end of the flash.
1764b2f73a07SPaolo Bonzini *
1765b2f73a07SPaolo Bonzini * Check the Firmware GUID Table first.
1766b2f73a07SPaolo Bonzini */
1767b2f73a07SPaolo Bonzini if (pc_system_ovmf_table_find(SEV_INFO_BLOCK_GUID, &data, NULL)) {
1768b2f73a07SPaolo Bonzini return sev_es_parse_reset_block((SevInfoBlock *)data, addr);
1769b2f73a07SPaolo Bonzini }
1770b2f73a07SPaolo Bonzini
1771b2f73a07SPaolo Bonzini /*
1772b2f73a07SPaolo Bonzini * SEV info block not found in the Firmware GUID Table (or there isn't
1773b2f73a07SPaolo Bonzini * a Firmware GUID Table), fall back to the original implementation.
1774b2f73a07SPaolo Bonzini */
1775b2f73a07SPaolo Bonzini data = flash_ptr + flash_size - 0x20;
1776b2f73a07SPaolo Bonzini
1777b2f73a07SPaolo Bonzini qemu_uuid_parse(SEV_INFO_BLOCK_GUID, &info_guid);
1778b2f73a07SPaolo Bonzini info_guid = qemu_uuid_bswap(info_guid); /* GUIDs are LE */
1779b2f73a07SPaolo Bonzini
1780b2f73a07SPaolo Bonzini guid = (QemuUUID *)(data - sizeof(info_guid));
1781b2f73a07SPaolo Bonzini if (!qemu_uuid_is_equal(guid, &info_guid)) {
1782b2f73a07SPaolo Bonzini error_report("SEV information block/Firmware GUID Table block not found in pflash rom");
1783b2f73a07SPaolo Bonzini return 1;
1784b2f73a07SPaolo Bonzini }
1785b2f73a07SPaolo Bonzini
1786b2f73a07SPaolo Bonzini len = (uint16_t *)((uint8_t *)guid - sizeof(*len));
1787b2f73a07SPaolo Bonzini info = (SevInfoBlock *)(data - le16_to_cpu(*len));
1788b2f73a07SPaolo Bonzini
1789b2f73a07SPaolo Bonzini return sev_es_parse_reset_block(info, addr);
1790b2f73a07SPaolo Bonzini }
1791b2f73a07SPaolo Bonzini
sev_es_set_reset_vector(CPUState * cpu)1792b2f73a07SPaolo Bonzini void sev_es_set_reset_vector(CPUState *cpu)
1793b2f73a07SPaolo Bonzini {
1794b2f73a07SPaolo Bonzini X86CPU *x86;
1795b2f73a07SPaolo Bonzini CPUX86State *env;
1796109238a8SPaolo Bonzini ConfidentialGuestSupport *cgs = MACHINE(qdev_get_machine())->cgs;
1797109238a8SPaolo Bonzini SevCommonState *sev_common = SEV_COMMON(
1798109238a8SPaolo Bonzini object_dynamic_cast(OBJECT(cgs), TYPE_SEV_COMMON));
1799b2f73a07SPaolo Bonzini
1800b2f73a07SPaolo Bonzini /* Only update if we have valid reset information */
180116dcf200SMichael Roth if (!sev_common || !sev_common->reset_data_valid) {
1802b2f73a07SPaolo Bonzini return;
1803b2f73a07SPaolo Bonzini }
1804b2f73a07SPaolo Bonzini
1805b2f73a07SPaolo Bonzini /* Do not update the BSP reset state */
1806b2f73a07SPaolo Bonzini if (cpu->cpu_index == 0) {
1807b2f73a07SPaolo Bonzini return;
1808b2f73a07SPaolo Bonzini }
1809b2f73a07SPaolo Bonzini
1810b2f73a07SPaolo Bonzini x86 = X86_CPU(cpu);
1811b2f73a07SPaolo Bonzini env = &x86->env;
1812b2f73a07SPaolo Bonzini
181316dcf200SMichael Roth cpu_x86_load_seg_cache(env, R_CS, 0xf000, sev_common->reset_cs, 0xffff,
1814b2f73a07SPaolo Bonzini DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
1815b2f73a07SPaolo Bonzini DESC_R_MASK | DESC_A_MASK);
1816b2f73a07SPaolo Bonzini
181716dcf200SMichael Roth env->eip = sev_common->reset_ip;
1818b2f73a07SPaolo Bonzini }
1819b2f73a07SPaolo Bonzini
sev_es_save_reset_vector(void * flash_ptr,uint64_t flash_size)1820b2f73a07SPaolo Bonzini int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size)
1821b2f73a07SPaolo Bonzini {
1822b2f73a07SPaolo Bonzini CPUState *cpu;
1823b2f73a07SPaolo Bonzini uint32_t addr;
1824b2f73a07SPaolo Bonzini int ret;
182516dcf200SMichael Roth SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
1826b2f73a07SPaolo Bonzini
1827b2f73a07SPaolo Bonzini if (!sev_es_enabled()) {
1828b2f73a07SPaolo Bonzini return 0;
1829b2f73a07SPaolo Bonzini }
1830b2f73a07SPaolo Bonzini
1831b2f73a07SPaolo Bonzini addr = 0;
1832b2f73a07SPaolo Bonzini ret = sev_es_find_reset_vector(flash_ptr, flash_size,
1833b2f73a07SPaolo Bonzini &addr);
1834b2f73a07SPaolo Bonzini if (ret) {
1835b2f73a07SPaolo Bonzini return ret;
1836b2f73a07SPaolo Bonzini }
1837b2f73a07SPaolo Bonzini
1838b2f73a07SPaolo Bonzini if (addr) {
183916dcf200SMichael Roth sev_common->reset_cs = addr & 0xffff0000;
184016dcf200SMichael Roth sev_common->reset_ip = addr & 0x0000ffff;
184116dcf200SMichael Roth sev_common->reset_data_valid = true;
1842b2f73a07SPaolo Bonzini
1843b2f73a07SPaolo Bonzini CPU_FOREACH(cpu) {
1844b2f73a07SPaolo Bonzini sev_es_set_reset_vector(cpu);
1845b2f73a07SPaolo Bonzini }
1846b2f73a07SPaolo Bonzini }
1847b2f73a07SPaolo Bonzini
1848b2f73a07SPaolo Bonzini return 0;
1849b2f73a07SPaolo Bonzini }
1850b2f73a07SPaolo Bonzini
1851cff03145SDov Murik static const QemuUUID sev_hash_table_header_guid = {
1852cff03145SDov Murik .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93,
1853cff03145SDov Murik 0xd4, 0x11, 0xfd, 0x21)
1854cff03145SDov Murik };
1855cff03145SDov Murik
1856cff03145SDov Murik static const QemuUUID sev_kernel_entry_guid = {
1857cff03145SDov Murik .data = UUID_LE(0x4de79437, 0xabd2, 0x427f, 0xb8, 0x35, 0xd5, 0xb1,
1858cff03145SDov Murik 0x72, 0xd2, 0x04, 0x5b)
1859cff03145SDov Murik };
1860cff03145SDov Murik static const QemuUUID sev_initrd_entry_guid = {
1861cff03145SDov Murik .data = UUID_LE(0x44baf731, 0x3a2f, 0x4bd7, 0x9a, 0xf1, 0x41, 0xe2,
1862cff03145SDov Murik 0x91, 0x69, 0x78, 0x1d)
1863cff03145SDov Murik };
1864cff03145SDov Murik static const QemuUUID sev_cmdline_entry_guid = {
1865cff03145SDov Murik .data = UUID_LE(0x97d02dd8, 0xbd20, 0x4c94, 0xaa, 0x78, 0xe7, 0x71,
1866cff03145SDov Murik 0x4d, 0x36, 0xab, 0x2a)
1867cff03145SDov Murik };
1868cff03145SDov Murik
build_kernel_loader_hashes(PaddedSevHashTable * padded_ht,SevKernelLoaderContext * ctx,Error ** errp)186906cbd66cSDov Murik static bool build_kernel_loader_hashes(PaddedSevHashTable *padded_ht,
187006cbd66cSDov Murik SevKernelLoaderContext *ctx,
187106cbd66cSDov Murik Error **errp)
1872cff03145SDov Murik {
1873cff03145SDov Murik SevHashTable *ht;
1874cff03145SDov Murik uint8_t cmdline_hash[HASH_SIZE];
1875cff03145SDov Murik uint8_t initrd_hash[HASH_SIZE];
1876cff03145SDov Murik uint8_t kernel_hash[HASH_SIZE];
1877cff03145SDov Murik uint8_t *hashp;
1878cff03145SDov Murik size_t hash_len = HASH_SIZE;
1879cff03145SDov Murik
1880cff03145SDov Murik /*
1881cff03145SDov Murik * Calculate hash of kernel command-line with the terminating null byte. If
1882cff03145SDov Murik * the user doesn't supply a command-line via -append, the 1-byte "\0" will
1883cff03145SDov Murik * be used.
1884cff03145SDov Murik */
1885cff03145SDov Murik hashp = cmdline_hash;
1886*ef834aa2SMarkus Armbruster if (qcrypto_hash_bytes(QCRYPTO_HASH_ALGO_SHA256, ctx->cmdline_data,
1887cff03145SDov Murik ctx->cmdline_size, &hashp, &hash_len, errp) < 0) {
1888cff03145SDov Murik return false;
1889cff03145SDov Murik }
1890cff03145SDov Murik assert(hash_len == HASH_SIZE);
1891cff03145SDov Murik
1892cff03145SDov Murik /*
1893cff03145SDov Murik * Calculate hash of initrd. If the user doesn't supply an initrd via
1894cff03145SDov Murik * -initrd, an empty buffer will be used (ctx->initrd_size == 0).
1895cff03145SDov Murik */
1896cff03145SDov Murik hashp = initrd_hash;
1897*ef834aa2SMarkus Armbruster if (qcrypto_hash_bytes(QCRYPTO_HASH_ALGO_SHA256, ctx->initrd_data,
1898cff03145SDov Murik ctx->initrd_size, &hashp, &hash_len, errp) < 0) {
1899cff03145SDov Murik return false;
1900cff03145SDov Murik }
1901cff03145SDov Murik assert(hash_len == HASH_SIZE);
1902cff03145SDov Murik
1903cff03145SDov Murik /* Calculate hash of the kernel */
1904cff03145SDov Murik hashp = kernel_hash;
1905cff03145SDov Murik struct iovec iov[2] = {
1906cff03145SDov Murik { .iov_base = ctx->setup_data, .iov_len = ctx->setup_size },
1907cff03145SDov Murik { .iov_base = ctx->kernel_data, .iov_len = ctx->kernel_size }
1908cff03145SDov Murik };
1909*ef834aa2SMarkus Armbruster if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALGO_SHA256, iov, ARRAY_SIZE(iov),
1910cff03145SDov Murik &hashp, &hash_len, errp) < 0) {
1911cff03145SDov Murik return false;
1912cff03145SDov Murik }
1913cff03145SDov Murik assert(hash_len == HASH_SIZE);
1914cff03145SDov Murik
1915ddcc0d89SDov Murik ht = &padded_ht->ht;
1916cff03145SDov Murik
1917cff03145SDov Murik ht->guid = sev_hash_table_header_guid;
1918cff03145SDov Murik ht->len = sizeof(*ht);
1919cff03145SDov Murik
1920cff03145SDov Murik ht->cmdline.guid = sev_cmdline_entry_guid;
1921cff03145SDov Murik ht->cmdline.len = sizeof(ht->cmdline);
1922cff03145SDov Murik memcpy(ht->cmdline.hash, cmdline_hash, sizeof(ht->cmdline.hash));
1923cff03145SDov Murik
1924cff03145SDov Murik ht->initrd.guid = sev_initrd_entry_guid;
1925cff03145SDov Murik ht->initrd.len = sizeof(ht->initrd);
1926cff03145SDov Murik memcpy(ht->initrd.hash, initrd_hash, sizeof(ht->initrd.hash));
1927cff03145SDov Murik
1928cff03145SDov Murik ht->kernel.guid = sev_kernel_entry_guid;
1929cff03145SDov Murik ht->kernel.len = sizeof(ht->kernel);
1930cff03145SDov Murik memcpy(ht->kernel.hash, kernel_hash, sizeof(ht->kernel.hash));
1931cff03145SDov Murik
1932cff03145SDov Murik /* zero the excess data so the measurement can be reliably calculated */
1933ddcc0d89SDov Murik memset(padded_ht->padding, 0, sizeof(padded_ht->padding));
1934cff03145SDov Murik
193506cbd66cSDov Murik return true;
193606cbd66cSDov Murik }
193706cbd66cSDov Murik
sev_snp_build_kernel_loader_hashes(SevCommonState * sev_common,SevHashTableDescriptor * area,SevKernelLoaderContext * ctx,Error ** errp)1938c1996992SDov Murik static bool sev_snp_build_kernel_loader_hashes(SevCommonState *sev_common,
1939c1996992SDov Murik SevHashTableDescriptor *area,
1940c1996992SDov Murik SevKernelLoaderContext *ctx,
1941c1996992SDov Murik Error **errp)
194206cbd66cSDov Murik {
1943c1996992SDov Murik /*
1944c1996992SDov Murik * SNP: Populate the hashes table in an area that later in
1945c1996992SDov Murik * snp_launch_update_kernel_hashes() will be copied to the guest memory
1946c1996992SDov Murik * and encrypted.
1947c1996992SDov Murik */
1948c1996992SDov Murik SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(sev_common);
1949c1996992SDov Murik sev_snp_guest->kernel_hashes_offset = area->base & ~TARGET_PAGE_MASK;
1950c1996992SDov Murik sev_snp_guest->kernel_hashes_data = g_new0(PaddedSevHashTable, 1);
1951c1996992SDov Murik return build_kernel_loader_hashes(sev_snp_guest->kernel_hashes_data, ctx, errp);
1952c1996992SDov Murik }
1953c1996992SDov Murik
sev_build_kernel_loader_hashes(SevCommonState * sev_common,SevHashTableDescriptor * area,SevKernelLoaderContext * ctx,Error ** errp)1954c1996992SDov Murik static bool sev_build_kernel_loader_hashes(SevCommonState *sev_common,
1955c1996992SDov Murik SevHashTableDescriptor *area,
1956c1996992SDov Murik SevKernelLoaderContext *ctx,
1957c1996992SDov Murik Error **errp)
1958c1996992SDov Murik {
195906cbd66cSDov Murik PaddedSevHashTable *padded_ht;
196006cbd66cSDov Murik hwaddr mapped_len = sizeof(*padded_ht);
196106cbd66cSDov Murik MemTxAttrs attrs = { 0 };
196206cbd66cSDov Murik bool ret = true;
196306cbd66cSDov Murik
196406cbd66cSDov Murik /*
196506cbd66cSDov Murik * Populate the hashes table in the guest's memory at the OVMF-designated
196606cbd66cSDov Murik * area for the SEV hashes table
196706cbd66cSDov Murik */
196806cbd66cSDov Murik padded_ht = address_space_map(&address_space_memory, area->base,
196906cbd66cSDov Murik &mapped_len, true, attrs);
197006cbd66cSDov Murik if (!padded_ht || mapped_len != sizeof(*padded_ht)) {
197106cbd66cSDov Murik error_setg(errp, "SEV: cannot map hashes table guest memory area");
197206cbd66cSDov Murik return false;
197306cbd66cSDov Murik }
197406cbd66cSDov Murik
197506cbd66cSDov Murik if (build_kernel_loader_hashes(padded_ht, ctx, errp)) {
197677d1abd9SBrijesh Singh if (sev_encrypt_flash(area->base, (uint8_t *)padded_ht,
197777d1abd9SBrijesh Singh sizeof(*padded_ht), errp) < 0) {
197858603ba2SDov Murik ret = false;
1979cff03145SDov Murik }
198006cbd66cSDov Murik } else {
198106cbd66cSDov Murik ret = false;
198206cbd66cSDov Murik }
1983cff03145SDov Murik
198458603ba2SDov Murik address_space_unmap(&address_space_memory, padded_ht,
198558603ba2SDov Murik mapped_len, true, mapped_len);
198658603ba2SDov Murik
198758603ba2SDov Murik return ret;
1988cff03145SDov Murik }
1989cff03145SDov Murik
1990c1996992SDov Murik /*
1991c1996992SDov Murik * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page
1992c1996992SDov Murik * which is included in SEV's initial memory measurement.
1993c1996992SDov Murik */
sev_add_kernel_loader_hashes(SevKernelLoaderContext * ctx,Error ** errp)1994c1996992SDov Murik bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
1995c1996992SDov Murik {
1996c1996992SDov Murik uint8_t *data;
1997c1996992SDov Murik SevHashTableDescriptor *area;
1998c1996992SDov Murik SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
1999c1996992SDov Murik SevCommonStateClass *klass = SEV_COMMON_GET_CLASS(sev_common);
2000c1996992SDov Murik
2001c1996992SDov Murik /*
2002c1996992SDov Murik * Only add the kernel hashes if the sev-guest configuration explicitly
2003c1996992SDov Murik * stated kernel-hashes=on.
2004c1996992SDov Murik */
2005c1996992SDov Murik if (!sev_common->kernel_hashes) {
2006c1996992SDov Murik return false;
2007c1996992SDov Murik }
2008c1996992SDov Murik
2009c1996992SDov Murik if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) {
2010c1996992SDov Murik error_setg(errp, "SEV: kernel specified but guest firmware "
2011c1996992SDov Murik "has no hashes table GUID");
2012c1996992SDov Murik return false;
2013c1996992SDov Murik }
2014c1996992SDov Murik
2015c1996992SDov Murik area = (SevHashTableDescriptor *)data;
2016c1996992SDov Murik if (!area->base || area->size < sizeof(PaddedSevHashTable)) {
2017c1996992SDov Murik error_setg(errp, "SEV: guest firmware hashes table area is invalid "
2018c1996992SDov Murik "(base=0x%x size=0x%x)", area->base, area->size);
2019c1996992SDov Murik return false;
2020c1996992SDov Murik }
2021c1996992SDov Murik
2022c1996992SDov Murik return klass->build_kernel_loader_hashes(sev_common, area, ctx, errp);
2023c1996992SDov Murik }
2024c1996992SDov Murik
202516dcf200SMichael Roth static char *
sev_common_get_sev_device(Object * obj,Error ** errp)202616dcf200SMichael Roth sev_common_get_sev_device(Object *obj, Error **errp)
202716dcf200SMichael Roth {
202816dcf200SMichael Roth return g_strdup(SEV_COMMON(obj)->sev_device);
202916dcf200SMichael Roth }
203016dcf200SMichael Roth
2031a9b4942fSBrijesh Singh static void
sev_common_set_sev_device(Object * obj,const char * value,Error ** errp)203216dcf200SMichael Roth sev_common_set_sev_device(Object *obj, const char *value, Error **errp)
203316dcf200SMichael Roth {
203416dcf200SMichael Roth SEV_COMMON(obj)->sev_device = g_strdup(value);
203516dcf200SMichael Roth }
203616dcf200SMichael Roth
sev_common_get_kernel_hashes(Object * obj,Error ** errp)203716dcf200SMichael Roth static bool sev_common_get_kernel_hashes(Object *obj, Error **errp)
203816dcf200SMichael Roth {
203916dcf200SMichael Roth return SEV_COMMON(obj)->kernel_hashes;
204016dcf200SMichael Roth }
204116dcf200SMichael Roth
sev_common_set_kernel_hashes(Object * obj,bool value,Error ** errp)204216dcf200SMichael Roth static void sev_common_set_kernel_hashes(Object *obj, bool value, Error **errp)
204316dcf200SMichael Roth {
204416dcf200SMichael Roth SEV_COMMON(obj)->kernel_hashes = value;
204516dcf200SMichael Roth }
204616dcf200SMichael Roth
204716dcf200SMichael Roth static void
sev_common_class_init(ObjectClass * oc,void * data)204816dcf200SMichael Roth sev_common_class_init(ObjectClass *oc, void *data)
2049637c95b3SXiaoyao Li {
2050637c95b3SXiaoyao Li ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
2051637c95b3SXiaoyao Li
2052990da8d2SPankaj Gupta klass->kvm_init = sev_common_kvm_init;
2053637c95b3SXiaoyao Li
2054637c95b3SXiaoyao Li object_class_property_add_str(oc, "sev-device",
205516dcf200SMichael Roth sev_common_get_sev_device,
205616dcf200SMichael Roth sev_common_set_sev_device);
2057637c95b3SXiaoyao Li object_class_property_set_description(oc, "sev-device",
2058637c95b3SXiaoyao Li "SEV device to use");
205916dcf200SMichael Roth object_class_property_add_bool(oc, "kernel-hashes",
206016dcf200SMichael Roth sev_common_get_kernel_hashes,
206116dcf200SMichael Roth sev_common_set_kernel_hashes);
206216dcf200SMichael Roth object_class_property_set_description(oc, "kernel-hashes",
206316dcf200SMichael Roth "add kernel hashes to guest firmware for measured Linux boot");
206416dcf200SMichael Roth }
206516dcf200SMichael Roth
206616dcf200SMichael Roth static void
sev_common_instance_init(Object * obj)206716dcf200SMichael Roth sev_common_instance_init(Object *obj)
206816dcf200SMichael Roth {
206916dcf200SMichael Roth SevCommonState *sev_common = SEV_COMMON(obj);
207016dcf200SMichael Roth
207116dcf200SMichael Roth sev_common->kvm_type = -1;
207216dcf200SMichael Roth
207316dcf200SMichael Roth sev_common->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
207416dcf200SMichael Roth
207516dcf200SMichael Roth object_property_add_uint32_ptr(obj, "cbitpos", &sev_common->cbitpos,
207616dcf200SMichael Roth OBJ_PROP_FLAG_READWRITE);
207716dcf200SMichael Roth object_property_add_uint32_ptr(obj, "reduced-phys-bits",
207816dcf200SMichael Roth &sev_common->reduced_phys_bits,
207916dcf200SMichael Roth OBJ_PROP_FLAG_READWRITE);
208016dcf200SMichael Roth }
208116dcf200SMichael Roth
208216dcf200SMichael Roth /* sev guest info common to sev/sev-es/sev-snp */
208316dcf200SMichael Roth static const TypeInfo sev_common_info = {
208416dcf200SMichael Roth .parent = TYPE_X86_CONFIDENTIAL_GUEST,
208516dcf200SMichael Roth .name = TYPE_SEV_COMMON,
208616dcf200SMichael Roth .instance_size = sizeof(SevCommonState),
208716dcf200SMichael Roth .instance_init = sev_common_instance_init,
208816dcf200SMichael Roth .class_size = sizeof(SevCommonStateClass),
208916dcf200SMichael Roth .class_init = sev_common_class_init,
209016dcf200SMichael Roth .abstract = true,
209116dcf200SMichael Roth .interfaces = (InterfaceInfo[]) {
209216dcf200SMichael Roth { TYPE_USER_CREATABLE },
209316dcf200SMichael Roth { }
209416dcf200SMichael Roth }
209516dcf200SMichael Roth };
209616dcf200SMichael Roth
209716dcf200SMichael Roth static char *
sev_guest_get_dh_cert_file(Object * obj,Error ** errp)209816dcf200SMichael Roth sev_guest_get_dh_cert_file(Object *obj, Error **errp)
209916dcf200SMichael Roth {
210016dcf200SMichael Roth return g_strdup(SEV_GUEST(obj)->dh_cert_file);
210116dcf200SMichael Roth }
210216dcf200SMichael Roth
210316dcf200SMichael Roth static void
sev_guest_set_dh_cert_file(Object * obj,const char * value,Error ** errp)210416dcf200SMichael Roth sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
210516dcf200SMichael Roth {
210616dcf200SMichael Roth SEV_GUEST(obj)->dh_cert_file = g_strdup(value);
210716dcf200SMichael Roth }
210816dcf200SMichael Roth
210916dcf200SMichael Roth static char *
sev_guest_get_session_file(Object * obj,Error ** errp)211016dcf200SMichael Roth sev_guest_get_session_file(Object *obj, Error **errp)
211116dcf200SMichael Roth {
211216dcf200SMichael Roth SevGuestState *sev_guest = SEV_GUEST(obj);
211316dcf200SMichael Roth
211416dcf200SMichael Roth return sev_guest->session_file ? g_strdup(sev_guest->session_file) : NULL;
211516dcf200SMichael Roth }
211616dcf200SMichael Roth
211716dcf200SMichael Roth static void
sev_guest_set_session_file(Object * obj,const char * value,Error ** errp)211816dcf200SMichael Roth sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
211916dcf200SMichael Roth {
212016dcf200SMichael Roth SEV_GUEST(obj)->session_file = g_strdup(value);
212116dcf200SMichael Roth }
212216dcf200SMichael Roth
sev_guest_get_legacy_vm_type(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)21239d38d9dcSMichael Roth static void sev_guest_get_legacy_vm_type(Object *obj, Visitor *v,
21249d38d9dcSMichael Roth const char *name, void *opaque,
21259d38d9dcSMichael Roth Error **errp)
212616dcf200SMichael Roth {
21279d38d9dcSMichael Roth SevGuestState *sev_guest = SEV_GUEST(obj);
21289d38d9dcSMichael Roth OnOffAuto legacy_vm_type = sev_guest->legacy_vm_type;
21299d38d9dcSMichael Roth
21309d38d9dcSMichael Roth visit_type_OnOffAuto(v, name, &legacy_vm_type, errp);
213116dcf200SMichael Roth }
213216dcf200SMichael Roth
sev_guest_set_legacy_vm_type(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)21339d38d9dcSMichael Roth static void sev_guest_set_legacy_vm_type(Object *obj, Visitor *v,
21349d38d9dcSMichael Roth const char *name, void *opaque,
21359d38d9dcSMichael Roth Error **errp)
213616dcf200SMichael Roth {
21379d38d9dcSMichael Roth SevGuestState *sev_guest = SEV_GUEST(obj);
21389d38d9dcSMichael Roth
21399d38d9dcSMichael Roth visit_type_OnOffAuto(v, name, &sev_guest->legacy_vm_type, errp);
214016dcf200SMichael Roth }
214116dcf200SMichael Roth
214216dcf200SMichael Roth static void
sev_guest_class_init(ObjectClass * oc,void * data)214316dcf200SMichael Roth sev_guest_class_init(ObjectClass *oc, void *data)
214416dcf200SMichael Roth {
21456600f1acSPankaj Gupta SevCommonStateClass *klass = SEV_COMMON_CLASS(oc);
2146a808132fSPaolo Bonzini X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
21476600f1acSPankaj Gupta
2148c1996992SDov Murik klass->build_kernel_loader_hashes = sev_build_kernel_loader_hashes;
21496600f1acSPankaj Gupta klass->launch_start = sev_launch_start;
2150bce615a1SPankaj Gupta klass->launch_finish = sev_launch_finish;
21519861405aSPaolo Bonzini klass->launch_update_data = sev_launch_update_data;
2152990da8d2SPankaj Gupta klass->kvm_init = sev_kvm_init;
2153a808132fSPaolo Bonzini x86_klass->kvm_type = sev_kvm_type;
21546600f1acSPankaj Gupta
2155637c95b3SXiaoyao Li object_class_property_add_str(oc, "dh-cert-file",
2156637c95b3SXiaoyao Li sev_guest_get_dh_cert_file,
2157637c95b3SXiaoyao Li sev_guest_set_dh_cert_file);
2158637c95b3SXiaoyao Li object_class_property_set_description(oc, "dh-cert-file",
2159637c95b3SXiaoyao Li "guest owners DH certificate (encoded with base64)");
2160637c95b3SXiaoyao Li object_class_property_add_str(oc, "session-file",
2161637c95b3SXiaoyao Li sev_guest_get_session_file,
2162637c95b3SXiaoyao Li sev_guest_set_session_file);
2163637c95b3SXiaoyao Li object_class_property_set_description(oc, "session-file",
2164637c95b3SXiaoyao Li "guest owners session parameters (encoded with base64)");
21659d38d9dcSMichael Roth object_class_property_add(oc, "legacy-vm-type", "OnOffAuto",
216602326733SMichael Roth sev_guest_get_legacy_vm_type,
21679d38d9dcSMichael Roth sev_guest_set_legacy_vm_type, NULL, NULL);
216802326733SMichael Roth object_class_property_set_description(oc, "legacy-vm-type",
216902326733SMichael Roth "use legacy VM type to maintain measurement compatibility with older QEMU or kernel versions.");
2170637c95b3SXiaoyao Li }
2171637c95b3SXiaoyao Li
2172637c95b3SXiaoyao Li static void
sev_guest_instance_init(Object * obj)2173637c95b3SXiaoyao Li sev_guest_instance_init(Object *obj)
2174637c95b3SXiaoyao Li {
217516dcf200SMichael Roth SevGuestState *sev_guest = SEV_GUEST(obj);
2176637c95b3SXiaoyao Li
217716dcf200SMichael Roth sev_guest->policy = DEFAULT_GUEST_POLICY;
217816dcf200SMichael Roth object_property_add_uint32_ptr(obj, "handle", &sev_guest->handle,
2179637c95b3SXiaoyao Li OBJ_PROP_FLAG_READWRITE);
218016dcf200SMichael Roth object_property_add_uint32_ptr(obj, "policy", &sev_guest->policy,
2181637c95b3SXiaoyao Li OBJ_PROP_FLAG_READWRITE);
2182ea7fbd37SMichael Roth object_apply_compat_props(obj);
21839d38d9dcSMichael Roth
21849d38d9dcSMichael Roth sev_guest->legacy_vm_type = ON_OFF_AUTO_AUTO;
2185637c95b3SXiaoyao Li }
2186637c95b3SXiaoyao Li
218716dcf200SMichael Roth /* guest info specific sev/sev-es */
2188637c95b3SXiaoyao Li static const TypeInfo sev_guest_info = {
218916dcf200SMichael Roth .parent = TYPE_SEV_COMMON,
2190637c95b3SXiaoyao Li .name = TYPE_SEV_GUEST,
2191637c95b3SXiaoyao Li .instance_size = sizeof(SevGuestState),
2192637c95b3SXiaoyao Li .instance_init = sev_guest_instance_init,
219316dcf200SMichael Roth .class_init = sev_guest_class_init,
2194637c95b3SXiaoyao Li };
2195637c95b3SXiaoyao Li
2196637c95b3SXiaoyao Li static void
sev_snp_guest_get_policy(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)21977b34df44SBrijesh Singh sev_snp_guest_get_policy(Object *obj, Visitor *v, const char *name,
21987b34df44SBrijesh Singh void *opaque, Error **errp)
21997b34df44SBrijesh Singh {
22007b34df44SBrijesh Singh visit_type_uint64(v, name,
22017b34df44SBrijesh Singh (uint64_t *)&SEV_SNP_GUEST(obj)->kvm_start_conf.policy,
22027b34df44SBrijesh Singh errp);
22037b34df44SBrijesh Singh }
22047b34df44SBrijesh Singh
22057b34df44SBrijesh Singh static void
sev_snp_guest_set_policy(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)22067b34df44SBrijesh Singh sev_snp_guest_set_policy(Object *obj, Visitor *v, const char *name,
22077b34df44SBrijesh Singh void *opaque, Error **errp)
22087b34df44SBrijesh Singh {
22097b34df44SBrijesh Singh visit_type_uint64(v, name,
22107b34df44SBrijesh Singh (uint64_t *)&SEV_SNP_GUEST(obj)->kvm_start_conf.policy,
22117b34df44SBrijesh Singh errp);
22127b34df44SBrijesh Singh }
22137b34df44SBrijesh Singh
22147b34df44SBrijesh Singh static char *
sev_snp_guest_get_guest_visible_workarounds(Object * obj,Error ** errp)22157b34df44SBrijesh Singh sev_snp_guest_get_guest_visible_workarounds(Object *obj, Error **errp)
22167b34df44SBrijesh Singh {
22177b34df44SBrijesh Singh return g_strdup(SEV_SNP_GUEST(obj)->guest_visible_workarounds);
22187b34df44SBrijesh Singh }
22197b34df44SBrijesh Singh
22207b34df44SBrijesh Singh static void
sev_snp_guest_set_guest_visible_workarounds(Object * obj,const char * value,Error ** errp)22217b34df44SBrijesh Singh sev_snp_guest_set_guest_visible_workarounds(Object *obj, const char *value,
22227b34df44SBrijesh Singh Error **errp)
22237b34df44SBrijesh Singh {
22247b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
22257b34df44SBrijesh Singh struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
22267b34df44SBrijesh Singh g_autofree guchar *blob;
22277b34df44SBrijesh Singh gsize len;
22287b34df44SBrijesh Singh
22297b34df44SBrijesh Singh g_free(sev_snp_guest->guest_visible_workarounds);
22307b34df44SBrijesh Singh
22317b34df44SBrijesh Singh /* store the base64 str so we don't need to re-encode in getter */
22327b34df44SBrijesh Singh sev_snp_guest->guest_visible_workarounds = g_strdup(value);
22337b34df44SBrijesh Singh
22347b34df44SBrijesh Singh blob = qbase64_decode(sev_snp_guest->guest_visible_workarounds,
22357b34df44SBrijesh Singh -1, &len, errp);
22367b34df44SBrijesh Singh if (!blob) {
22377b34df44SBrijesh Singh return;
22387b34df44SBrijesh Singh }
22397b34df44SBrijesh Singh
22407b34df44SBrijesh Singh if (len != sizeof(start->gosvw)) {
2241b31d3867SRichard Henderson error_setg(errp, "parameter length of %" G_GSIZE_FORMAT
2242b31d3867SRichard Henderson " exceeds max of %zu",
22437b34df44SBrijesh Singh len, sizeof(start->gosvw));
22447b34df44SBrijesh Singh return;
22457b34df44SBrijesh Singh }
22467b34df44SBrijesh Singh
22477b34df44SBrijesh Singh memcpy(start->gosvw, blob, len);
22487b34df44SBrijesh Singh }
22497b34df44SBrijesh Singh
22507b34df44SBrijesh Singh static char *
sev_snp_guest_get_id_block(Object * obj,Error ** errp)22517b34df44SBrijesh Singh sev_snp_guest_get_id_block(Object *obj, Error **errp)
22527b34df44SBrijesh Singh {
22537b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
22547b34df44SBrijesh Singh
225568c3aa3eSPaolo Bonzini return g_strdup(sev_snp_guest->id_block_base64);
22567b34df44SBrijesh Singh }
22577b34df44SBrijesh Singh
22587b34df44SBrijesh Singh static void
sev_snp_guest_set_id_block(Object * obj,const char * value,Error ** errp)22597b34df44SBrijesh Singh sev_snp_guest_set_id_block(Object *obj, const char *value, Error **errp)
22607b34df44SBrijesh Singh {
22617b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
22627b34df44SBrijesh Singh struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
22637b34df44SBrijesh Singh gsize len;
22647b34df44SBrijesh Singh
2265c94eb5dbSPankaj Gupta finish->id_block_en = 0;
2266dd1b2fb5SPaolo Bonzini g_free(sev_snp_guest->id_block);
226768c3aa3eSPaolo Bonzini g_free(sev_snp_guest->id_block_base64);
22687b34df44SBrijesh Singh
22697b34df44SBrijesh Singh /* store the base64 str so we don't need to re-encode in getter */
227068c3aa3eSPaolo Bonzini sev_snp_guest->id_block_base64 = g_strdup(value);
2271dd1b2fb5SPaolo Bonzini sev_snp_guest->id_block =
2272dd1b2fb5SPaolo Bonzini qbase64_decode(sev_snp_guest->id_block_base64, -1, &len, errp);
22737b34df44SBrijesh Singh
2274dd1b2fb5SPaolo Bonzini if (!sev_snp_guest->id_block) {
22757b34df44SBrijesh Singh return;
22767b34df44SBrijesh Singh }
22777b34df44SBrijesh Singh
22787b34df44SBrijesh Singh if (len != KVM_SEV_SNP_ID_BLOCK_SIZE) {
2279b31d3867SRichard Henderson error_setg(errp, "parameter length of %" G_GSIZE_FORMAT
2280b31d3867SRichard Henderson " not equal to %u",
22817b34df44SBrijesh Singh len, KVM_SEV_SNP_ID_BLOCK_SIZE);
22827b34df44SBrijesh Singh return;
22837b34df44SBrijesh Singh }
22847b34df44SBrijesh Singh
2285c94eb5dbSPankaj Gupta finish->id_block_en = 1;
2286dd1b2fb5SPaolo Bonzini finish->id_block_uaddr = (uintptr_t)sev_snp_guest->id_block;
22877b34df44SBrijesh Singh }
22887b34df44SBrijesh Singh
22897b34df44SBrijesh Singh static char *
sev_snp_guest_get_id_auth(Object * obj,Error ** errp)22907b34df44SBrijesh Singh sev_snp_guest_get_id_auth(Object *obj, Error **errp)
22917b34df44SBrijesh Singh {
22927b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
22937b34df44SBrijesh Singh
2294803b7718SPaolo Bonzini return g_strdup(sev_snp_guest->id_auth_base64);
22957b34df44SBrijesh Singh }
22967b34df44SBrijesh Singh
22977b34df44SBrijesh Singh static void
sev_snp_guest_set_id_auth(Object * obj,const char * value,Error ** errp)22987b34df44SBrijesh Singh sev_snp_guest_set_id_auth(Object *obj, const char *value, Error **errp)
22997b34df44SBrijesh Singh {
23007b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
23017b34df44SBrijesh Singh struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
23027b34df44SBrijesh Singh gsize len;
23037b34df44SBrijesh Singh
23041ab620bfSPaolo Bonzini finish->id_auth_uaddr = 0;
23051ab620bfSPaolo Bonzini g_free(sev_snp_guest->id_auth);
2306803b7718SPaolo Bonzini g_free(sev_snp_guest->id_auth_base64);
23077b34df44SBrijesh Singh
23087b34df44SBrijesh Singh /* store the base64 str so we don't need to re-encode in getter */
2309803b7718SPaolo Bonzini sev_snp_guest->id_auth_base64 = g_strdup(value);
23101ab620bfSPaolo Bonzini sev_snp_guest->id_auth =
23111ab620bfSPaolo Bonzini qbase64_decode(sev_snp_guest->id_auth_base64, -1, &len, errp);
23127b34df44SBrijesh Singh
23131ab620bfSPaolo Bonzini if (!sev_snp_guest->id_auth) {
23147b34df44SBrijesh Singh return;
23157b34df44SBrijesh Singh }
23167b34df44SBrijesh Singh
23177b34df44SBrijesh Singh if (len > KVM_SEV_SNP_ID_AUTH_SIZE) {
2318b31d3867SRichard Henderson error_setg(errp, "parameter length:ID_AUTH %" G_GSIZE_FORMAT
2319b31d3867SRichard Henderson " exceeds max of %u",
23207b34df44SBrijesh Singh len, KVM_SEV_SNP_ID_AUTH_SIZE);
23217b34df44SBrijesh Singh return;
23227b34df44SBrijesh Singh }
23231ab620bfSPaolo Bonzini
23241ab620bfSPaolo Bonzini finish->id_auth_uaddr = (uintptr_t)sev_snp_guest->id_auth;
23257b34df44SBrijesh Singh }
23267b34df44SBrijesh Singh
23277b34df44SBrijesh Singh static bool
sev_snp_guest_get_author_key_enabled(Object * obj,Error ** errp)23287b34df44SBrijesh Singh sev_snp_guest_get_author_key_enabled(Object *obj, Error **errp)
23297b34df44SBrijesh Singh {
23307b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
23317b34df44SBrijesh Singh
23327b34df44SBrijesh Singh return !!sev_snp_guest->kvm_finish_conf.auth_key_en;
23337b34df44SBrijesh Singh }
23347b34df44SBrijesh Singh
23357b34df44SBrijesh Singh static void
sev_snp_guest_set_author_key_enabled(Object * obj,bool value,Error ** errp)23367b34df44SBrijesh Singh sev_snp_guest_set_author_key_enabled(Object *obj, bool value, Error **errp)
23377b34df44SBrijesh Singh {
23387b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
23397b34df44SBrijesh Singh
23407b34df44SBrijesh Singh sev_snp_guest->kvm_finish_conf.auth_key_en = value;
23417b34df44SBrijesh Singh }
23427b34df44SBrijesh Singh
23437b34df44SBrijesh Singh static bool
sev_snp_guest_get_vcek_disabled(Object * obj,Error ** errp)23447b34df44SBrijesh Singh sev_snp_guest_get_vcek_disabled(Object *obj, Error **errp)
23457b34df44SBrijesh Singh {
23467b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
23477b34df44SBrijesh Singh
23487b34df44SBrijesh Singh return !!sev_snp_guest->kvm_finish_conf.vcek_disabled;
23497b34df44SBrijesh Singh }
23507b34df44SBrijesh Singh
23517b34df44SBrijesh Singh static void
sev_snp_guest_set_vcek_disabled(Object * obj,bool value,Error ** errp)23527b34df44SBrijesh Singh sev_snp_guest_set_vcek_disabled(Object *obj, bool value, Error **errp)
23537b34df44SBrijesh Singh {
23547b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
23557b34df44SBrijesh Singh
23567b34df44SBrijesh Singh sev_snp_guest->kvm_finish_conf.vcek_disabled = value;
23577b34df44SBrijesh Singh }
23587b34df44SBrijesh Singh
23597b34df44SBrijesh Singh static char *
sev_snp_guest_get_host_data(Object * obj,Error ** errp)23607b34df44SBrijesh Singh sev_snp_guest_get_host_data(Object *obj, Error **errp)
23617b34df44SBrijesh Singh {
23627b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
23637b34df44SBrijesh Singh
23647b34df44SBrijesh Singh return g_strdup(sev_snp_guest->host_data);
23657b34df44SBrijesh Singh }
23667b34df44SBrijesh Singh
23677b34df44SBrijesh Singh static void
sev_snp_guest_set_host_data(Object * obj,const char * value,Error ** errp)23687b34df44SBrijesh Singh sev_snp_guest_set_host_data(Object *obj, const char *value, Error **errp)
23697b34df44SBrijesh Singh {
23707b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
23717b34df44SBrijesh Singh struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
23727b34df44SBrijesh Singh g_autofree guchar *blob;
23737b34df44SBrijesh Singh gsize len;
23747b34df44SBrijesh Singh
23757b34df44SBrijesh Singh g_free(sev_snp_guest->host_data);
23767b34df44SBrijesh Singh
23777b34df44SBrijesh Singh /* store the base64 str so we don't need to re-encode in getter */
23787b34df44SBrijesh Singh sev_snp_guest->host_data = g_strdup(value);
23797b34df44SBrijesh Singh
23807b34df44SBrijesh Singh blob = qbase64_decode(sev_snp_guest->host_data, -1, &len, errp);
23817b34df44SBrijesh Singh
23827b34df44SBrijesh Singh if (!blob) {
23837b34df44SBrijesh Singh return;
23847b34df44SBrijesh Singh }
23857b34df44SBrijesh Singh
23867b34df44SBrijesh Singh if (len != sizeof(finish->host_data)) {
2387b31d3867SRichard Henderson error_setg(errp, "parameter length of %" G_GSIZE_FORMAT
2388b31d3867SRichard Henderson " not equal to %zu",
23897b34df44SBrijesh Singh len, sizeof(finish->host_data));
23907b34df44SBrijesh Singh return;
23917b34df44SBrijesh Singh }
23927b34df44SBrijesh Singh
23937b34df44SBrijesh Singh memcpy(finish->host_data, blob, len);
23947b34df44SBrijesh Singh }
23957b34df44SBrijesh Singh
23967b34df44SBrijesh Singh static void
sev_snp_guest_class_init(ObjectClass * oc,void * data)23977b34df44SBrijesh Singh sev_snp_guest_class_init(ObjectClass *oc, void *data)
23987b34df44SBrijesh Singh {
2399125b95a6SPankaj Gupta SevCommonStateClass *klass = SEV_COMMON_CLASS(oc);
2400a808132fSPaolo Bonzini X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
2401125b95a6SPankaj Gupta
2402c1996992SDov Murik klass->build_kernel_loader_hashes = sev_snp_build_kernel_loader_hashes;
2403d3107f88SBrijesh Singh klass->launch_start = sev_snp_launch_start;
24049f3a6999SBrijesh Singh klass->launch_finish = sev_snp_launch_finish;
24050765d136SPankaj Gupta klass->launch_update_data = sev_snp_launch_update_data;
2406125b95a6SPankaj Gupta klass->kvm_init = sev_snp_kvm_init;
2407188569c1SPaolo Bonzini x86_klass->mask_cpuid_features = sev_snp_mask_cpuid_features;
2408a808132fSPaolo Bonzini x86_klass->kvm_type = sev_snp_kvm_type;
2409125b95a6SPankaj Gupta
24107b34df44SBrijesh Singh object_class_property_add(oc, "policy", "uint64",
24117b34df44SBrijesh Singh sev_snp_guest_get_policy,
24127b34df44SBrijesh Singh sev_snp_guest_set_policy, NULL, NULL);
24137b34df44SBrijesh Singh object_class_property_add_str(oc, "guest-visible-workarounds",
24147b34df44SBrijesh Singh sev_snp_guest_get_guest_visible_workarounds,
24157b34df44SBrijesh Singh sev_snp_guest_set_guest_visible_workarounds);
24167b34df44SBrijesh Singh object_class_property_add_str(oc, "id-block",
24177b34df44SBrijesh Singh sev_snp_guest_get_id_block,
24187b34df44SBrijesh Singh sev_snp_guest_set_id_block);
24197b34df44SBrijesh Singh object_class_property_add_str(oc, "id-auth",
24207b34df44SBrijesh Singh sev_snp_guest_get_id_auth,
24217b34df44SBrijesh Singh sev_snp_guest_set_id_auth);
24227b34df44SBrijesh Singh object_class_property_add_bool(oc, "author-key-enabled",
24237b34df44SBrijesh Singh sev_snp_guest_get_author_key_enabled,
24247b34df44SBrijesh Singh sev_snp_guest_set_author_key_enabled);
2425d4392415SPaolo Bonzini object_class_property_add_bool(oc, "vcek-disabled",
24267b34df44SBrijesh Singh sev_snp_guest_get_vcek_disabled,
24277b34df44SBrijesh Singh sev_snp_guest_set_vcek_disabled);
24287b34df44SBrijesh Singh object_class_property_add_str(oc, "host-data",
24297b34df44SBrijesh Singh sev_snp_guest_get_host_data,
24307b34df44SBrijesh Singh sev_snp_guest_set_host_data);
24317b34df44SBrijesh Singh }
24327b34df44SBrijesh Singh
24337b34df44SBrijesh Singh static void
sev_snp_guest_instance_init(Object * obj)24347b34df44SBrijesh Singh sev_snp_guest_instance_init(Object *obj)
24357b34df44SBrijesh Singh {
2436125b95a6SPankaj Gupta ConfidentialGuestSupport *cgs = CONFIDENTIAL_GUEST_SUPPORT(obj);
24377b34df44SBrijesh Singh SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
24387b34df44SBrijesh Singh
2439125b95a6SPankaj Gupta cgs->require_guest_memfd = true;
2440125b95a6SPankaj Gupta
24417b34df44SBrijesh Singh /* default init/start/finish params for kvm */
24427b34df44SBrijesh Singh sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY;
24437b34df44SBrijesh Singh }
24447b34df44SBrijesh Singh
24457b34df44SBrijesh Singh /* guest info specific to sev-snp */
24467b34df44SBrijesh Singh static const TypeInfo sev_snp_guest_info = {
24477b34df44SBrijesh Singh .parent = TYPE_SEV_COMMON,
24487b34df44SBrijesh Singh .name = TYPE_SEV_SNP_GUEST,
24497b34df44SBrijesh Singh .instance_size = sizeof(SevSnpGuestState),
24507b34df44SBrijesh Singh .class_init = sev_snp_guest_class_init,
24517b34df44SBrijesh Singh .instance_init = sev_snp_guest_instance_init,
24527b34df44SBrijesh Singh };
24537b34df44SBrijesh Singh
24547b34df44SBrijesh Singh static void
sev_register_types(void)2455a9b4942fSBrijesh Singh sev_register_types(void)
2456a9b4942fSBrijesh Singh {
245716dcf200SMichael Roth type_register_static(&sev_common_info);
2458d2d8a198SDavid Gibson type_register_static(&sev_guest_info);
24597b34df44SBrijesh Singh type_register_static(&sev_snp_guest_info);
2460a9b4942fSBrijesh Singh }
2461a9b4942fSBrijesh Singh
2462a9b4942fSBrijesh Singh type_init(sev_register_types);
2463