From nobody Thu Apr 2 23:56:16 2026 Received: from mail.thorondor.fr (unknown [82.66.128.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B48693F075A; Mon, 2 Mar 2026 14:43:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.66.128.71 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772462612; cv=none; b=evwQ1tZ4x91Wzy+nKnO+YH0tbqZywhxiMI0Lc5JMG6GvwhtYKhIIlckqti9T2tplM1uuF3P5T7cmKzXcy3E5BtpUuhknah7/zI5gTvoe00iOPVF91VOLGar7DDAGu2lwETU3NfUoaRj3aniLuoPvVnAxIObPXmVziedZXzPu0N0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772462612; c=relaxed/simple; bh=nYjx79fZztIa5TJbbooYfCYuewiabVCPe8nl482GY+s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lx2dtdVRKEFLqBe34F1qnY07Q5p0qNAIbSireOU+i0F3MW8AU+kyoTZXBU/BlgUPJecyoTGUtuUBMFCkmFBmZqcOcFaWuG4lRZ9AzCtY5JjJWhM8A5OccG05IiLYy0uaqtTEsb0ooggSJiyg7GdHOPyGIdQGSS45t5L4/liEvd0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=thorondor.fr; spf=pass smtp.mailfrom=thorondor.fr; dkim=pass (2048-bit key) header.d=thorondor.fr header.i=@thorondor.fr header.b=HL2R3zNB; arc=none smtp.client-ip=82.66.128.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=thorondor.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=thorondor.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=thorondor.fr header.i=@thorondor.fr header.b="HL2R3zNB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=thorondor.fr; s=mail; t=1772462190; bh=nYjx79fZztIa5TJbbooYfCYuewiabVCPe8nl482GY+s=; h=From:To:Cc:Subject:In-Reply-To:References; b=HL2R3zNBQao2GwcS2gKd+P41E4gssOGAa96/SSqLQKT65K1/dzTBAqjftXQRsuBj9 UEnpnL4g9D0oYlDOJwvFQhaPvNOWQBqL2tH/Mm2BdN4AnEq5fgi2nW9fB5HanbGtCs 7YcFbHzy0crpoyIarFeHSsxBs9NsgnhwAo/H/ACefww5nnU28xXu4hRZsffkbXdpjR u+dVCleStlYA9rzXUw1Do9aY1ELLIGNt3weXxtBIbspIUtYMG72Iq6Kv7cy9VoL7aI TWmV+TDvWu/k9jMoLq43mKac+LVCYBBF0y3dqUkeeVrFZKPExi5TB/8O1mH8caSCYt 03pjl9khSpU7Q== From: Thomas Courrege To: ashish.kalra@amd.com, corbet@lwn.net, herbert@gondor.apana.org.au, john.allen@amd.com, nikunj@amd.com, pbonzini@redhat.com, seanjc@google.com, thomas.lendacky@amd.com Cc: kvm@vger.kernel.org, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org, Thomas Courrege Subject: [PATCH v7 1/1] KVM: SEV: Add KVM_SEV_SNP_HV_REPORT_REQ command Date: Mon, 2 Mar 2026 15:36:24 +0100 Message-ID: <20260302143626.289792-2-thomas.courrege@thorondor.fr> In-Reply-To: <20260302143626.289792-1-thomas.courrege@thorondor.fr> References: <20260302143626.289792-1-thomas.courrege@thorondor.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for retrieving the SEV-SNP attestation report via the SNP_HV_REPORT_REQ firmware command and expose it through a new KVM ioctl for SNP guests. Signed-off-by: Thomas Courrege --- .../virt/kvm/x86/amd-memory-encryption.rst | 27 ++++++++ arch/x86/include/uapi/asm/kvm.h | 9 +++ arch/x86/kvm/svm/sev.c | 63 +++++++++++++++++++ drivers/crypto/ccp/sev-dev.c | 1 + include/linux/psp-sev.h | 31 +++++++++ 5 files changed, 131 insertions(+) diff --git a/Documentation/virt/kvm/x86/amd-memory-encryption.rst b/Documen= tation/virt/kvm/x86/amd-memory-encryption.rst index b2395dd4769d..38522b174a7b 100644 --- a/Documentation/virt/kvm/x86/amd-memory-encryption.rst +++ b/Documentation/virt/kvm/x86/amd-memory-encryption.rst @@ -618,6 +618,33 @@ approach to synchronizing firmware/certificate updates= via file-locking, which should make it easier to maintain interoperability across tools/VMMs/vendors. =20 +22. KVM_SEV_SNP_HV_REPORT_REQ +----------------------------- + +The KVM_SEV_SNP_HV_REPORT_REQ command requests a hypervisor-generated +SNP guest attestation report. This report is produced by the SEV firmware +using the key selected by the caller. + +The ``key_sel`` field indicates which key the platform will use to sign the +report: + * ``0``: If VLEK is installed, sign with VLEK. Otherwise, sign with VCEK. + * ``1``: Sign with VCEK. + * ``2``: Sign with VLEK. + * Other values are reserved. + +Parameters (in): struct kvm_sev_snp_hv_report_req + +Returns: 0 on success, -negative on error + +:: + struct kvm_sev_snp_hv_report_req { + __u64 report_uaddr; + __u64 report_len; + __u8 key_sel; + __u8 pad0[7]; + __u64 pad1[4]; + }; + Device attribute API =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kv= m.h index 846a63215ce1..d86cb352ea89 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -745,6 +745,7 @@ enum sev_cmd_id { KVM_SEV_SNP_LAUNCH_UPDATE, KVM_SEV_SNP_LAUNCH_FINISH, KVM_SEV_SNP_ENABLE_REQ_CERTS, + KVM_SEV_SNP_HV_REPORT_REQ, =20 KVM_SEV_NR_MAX, }; @@ -873,6 +874,14 @@ struct kvm_sev_receive_update_data { __u32 pad2; }; =20 +struct kvm_sev_snp_hv_report_req { + __u64 report_uaddr; + __u64 report_len; + __u8 key_sel; + __u8 pad0[7]; + __u64 pad1[4]; +}; + struct kvm_sev_snp_launch_start { __u64 policy; __u8 gosvw[16]; diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 3f9c1aa39a0a..62daa23ccd1b 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2271,6 +2271,66 @@ static int snp_launch_start(struct kvm *kvm, struct = kvm_sev_cmd *argp) return rc; } =20 +static int sev_snp_hv_report_request(struct kvm *kvm, struct kvm_sev_cmd *= argp) +{ + struct kvm_sev_info *sev =3D to_kvm_sev_info(kvm); + struct sev_data_snp_msg_report_rsp *report_rsp; + struct kvm_sev_snp_hv_report_req params; + struct sev_data_snp_hv_report_req data; + size_t rsp_size =3D sizeof(*report_rsp); + void __user *u_report; + void __user *u_params; + int ret; + + if (!sev_snp_guest(kvm)) + return -ENOTTY; + + u_params =3D u64_to_user_ptr(argp->data); + if (copy_from_user(¶ms, u_params, sizeof(params))) + return -EFAULT; + + if (params.report_len < rsp_size) + return -ENOSPC; + + u_report =3D u64_to_user_ptr(params.report_uaddr); + if (!u_report) + return -EINVAL; + + report_rsp =3D snp_alloc_firmware_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!report_rsp) + return -ENOMEM; + + data.len =3D sizeof(data); + data.key_sel =3D params.key_sel; + data.gctx_addr =3D __psp_pa(sev->snp_context); + data.hv_report_paddr =3D __psp_pa(report_rsp); + data.rsvd =3D 0; + + ret =3D sev_issue_cmd(kvm, SEV_CMD_SNP_HV_REPORT_REQ, &data, + &argp->error); + if (ret) + goto e_free_rsp; + + if (!report_rsp->status) { + if (params.report_len < (rsp_size + report_rsp->report_size)) + ret =3D -ENOSPC; + else + rsp_size +=3D report_rsp->report_size; + + params.report_len =3D sizeof(*report_rsp) + report_rsp->report_size; + } + + if (copy_to_user(u_report, report_rsp, rsp_size)) + ret =3D -EFAULT; + + if (copy_to_user(u_params, ¶ms, sizeof(params))) + ret =3D -EFAULT; + +e_free_rsp: + snp_free_firmware_page(report_rsp); + return ret; +} + struct sev_gmem_populate_args { __u8 type; int sev_fd; @@ -2678,6 +2738,9 @@ int sev_mem_enc_ioctl(struct kvm *kvm, void __user *a= rgp) case KVM_SEV_SNP_LAUNCH_FINISH: r =3D snp_launch_finish(kvm, &sev_cmd); break; + case KVM_SEV_SNP_HV_REPORT_REQ: + r =3D sev_snp_hv_report_request(kvm, &sev_cmd); + break; case KVM_SEV_SNP_ENABLE_REQ_CERTS: r =3D snp_enable_certs(kvm); break; diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 096f993974d1..30d715f19a25 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -252,6 +252,7 @@ static int sev_cmd_buffer_len(int cmd) case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct sev_data_snp_feature= _info); case SEV_CMD_SNP_VLEK_LOAD: return sizeof(struct sev_user_data_snp_vlek_= load); + case SEV_CMD_SNP_HV_REPORT_REQ: return sizeof(struct sev_data_snp_hv_rep= ort_req); default: return sev_tio_cmd_buffer_len(cmd); } =20 diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index 69ffa4b4d1fa..c651a400d124 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -124,6 +124,7 @@ enum sev_cmd { SEV_CMD_SNP_GCTX_CREATE =3D 0x093, SEV_CMD_SNP_GUEST_REQUEST =3D 0x094, SEV_CMD_SNP_ACTIVATE_EX =3D 0x095, + SEV_CMD_SNP_HV_REPORT_REQ =3D 0x096, SEV_CMD_SNP_LAUNCH_START =3D 0x0A0, SEV_CMD_SNP_LAUNCH_UPDATE =3D 0x0A1, SEV_CMD_SNP_LAUNCH_FINISH =3D 0x0A2, @@ -594,6 +595,36 @@ struct sev_data_attestation_report { u32 len; /* In/Out */ } __packed; =20 +/** + * struct sev_data_snp_hv_report_req - SNP_HV_REPORT_REQ command params + * + * @len: length of the command buffer in bytes + * @key_sel: Selects which key to use for generating the signature. + * @gctx_addr: System physical address of guest context page + * @hv_report_paddr: System physical address where MSG_EXPORT_RSP will be = written + */ +struct sev_data_snp_hv_report_req { + u32 len; /* In */ + u32 key_sel :2, /* In */ + rsvd :30; + u64 gctx_addr; /* In */ + u64 hv_report_paddr; /* In */ +} __packed; + +/** + * struct sev_data_snp_msg_export_rsp + * + * @status: Status : 0h: Success. 16h: Invalid parameters. + * @report_size: Size in bytes of the attestation report + * @report: attestation report + */ +struct sev_data_snp_msg_report_rsp { + u32 status; /* Out */ + u32 report_size; /* Out */ + u8 rsvd[24]; + u8 report[]; +} __packed; + /** * struct sev_data_snp_download_firmware - SNP_DOWNLOAD_FIRMWARE command p= arams * --=20 2.53.0