sev_guest_device/
ioctl.rs
1#![expect(unsafe_code)]
8
9use crate::protocol;
10use std::fs::File;
11use std::os::fd::AsRawFd;
12use thiserror::Error;
13use zerocopy::FromZeros;
14use zerocopy::IntoBytes;
15
16#[expect(missing_docs)] #[derive(Debug, Error)]
18pub enum Error {
19 #[error("failed to open /dev/sev-guest")]
20 OpenDevSevGuest(#[source] std::io::Error),
21 #[error("SNP_GET_REPORT ioctl failed")]
22 SnpGetReportIoctl(#[source] nix::Error),
23 #[error("SNP_GET_DERIVED_KEY ioctl failed")]
24 SnpGetDerivedKeyIoctl(#[source] nix::Error),
25}
26
27nix::ioctl_readwrite!(
28 snp_get_report,
30 protocol::SNP_GUEST_REQ_IOC_TYPE,
31 0x0,
32 protocol::SnpGuestRequestIoctl
33);
34
35nix::ioctl_readwrite!(
36 snp_get_derived_key,
38 protocol::SNP_GUEST_REQ_IOC_TYPE,
39 0x1,
40 protocol::SnpGuestRequestIoctl
41);
42
43pub struct SevGuestDevice {
45 file: File,
46}
47
48impl SevGuestDevice {
49 pub fn open() -> Result<Self, Error> {
51 let sev_guest = std::fs::OpenOptions::new()
52 .read(true)
53 .write(true)
54 .open("/dev/sev-guest")
55 .map_err(Error::OpenDevSevGuest)?;
56
57 Ok(Self { file: sev_guest })
58 }
59
60 pub fn get_report(&self, user_data: [u8; 64], vmpl: u32) -> Result<protocol::SnpReport, Error> {
62 let req = protocol::SnpReportReq {
63 user_data,
64 vmpl,
65 rsvd: [0u8; 28],
66 };
67
68 let resp = protocol::SnpReportResp::new_zeroed();
69
70 let mut snp_guest_request = protocol::SnpGuestRequestIoctl {
71 msg_version: protocol::SNP_GUEST_REQ_MSG_VERSION,
72 req_data: req.as_bytes().as_ptr() as u64,
73 resp_data: resp.as_bytes().as_ptr() as u64,
74 exitinfo: protocol::VmmErrorCode::new_zeroed(),
75 };
76
77 unsafe {
79 snp_get_report(self.file.as_raw_fd(), &mut snp_guest_request)
80 .map_err(Error::SnpGetReportIoctl)?;
81 }
82
83 Ok(resp.report)
84 }
85
86 pub fn get_derived_key(
88 &self,
89 root_key_select: u32,
90 guest_field_select: u64,
91 vmpl: u32,
92 guest_svn: u32,
93 tcb_version: u64,
94 ) -> Result<[u8; protocol::SNP_DERIVED_KEY_SIZE], Error> {
95 let req = protocol::SnpDerivedKeyReq {
96 root_key_select,
97 rsvd: 0u32,
98 guest_field_select,
99 vmpl,
100 guest_svn,
101 tcb_version,
102 };
103
104 let resp = protocol::SnpDerivedKeyResp::new_zeroed();
105
106 let mut snp_guest_request = protocol::SnpGuestRequestIoctl {
107 msg_version: protocol::SNP_GUEST_REQ_MSG_VERSION,
108 req_data: req.as_bytes().as_ptr() as u64,
109 resp_data: resp.as_bytes().as_ptr() as u64,
110 exitinfo: protocol::VmmErrorCode::new_zeroed(),
111 };
112
113 unsafe {
115 snp_get_derived_key(self.file.as_raw_fd(), &mut snp_guest_request)
116 .map_err(Error::SnpGetReportIoctl)?;
117 }
118
119 Ok(resp.derived_key)
120 }
121}