xref: /openbmc/qemu/target/i386/sev.c (revision b8eada54b2ad8a7d98d93d5ab4d3e888c5880097)
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