1#[cfg(target_os = "linux")]
8use crate::{
9 error::FirmwareError,
10 firmware::guest::GuestPolicy,
11 launch::linux::{ioctl::*, shared::*, snp::*},
12};
13
14use std::{marker::PhantomData, os::unix::io::AsRawFd, result::Result};
15
16use bitflags::bitflags;
17
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize};
20
21pub struct New;
23
24pub struct Started;
26
27pub struct Launcher<T, U: AsRawFd, V: AsRawFd> {
29 vm_fd: U,
30 sev: V,
31 state: PhantomData<T>,
32}
33
34impl<T, U: AsRawFd, V: AsRawFd> AsRef<U> for Launcher<T, U, V> {
35 fn as_ref(&self) -> &U {
37 &self.vm_fd
38 }
39}
40
41impl<T, U: AsRawFd, V: AsRawFd> AsMut<U> for Launcher<T, U, V> {
42 fn as_mut(&mut self) -> &mut U {
44 &mut self.vm_fd
45 }
46}
47
48impl<U: AsRawFd, V: AsRawFd> Launcher<New, U, V> {
49 pub fn new(vm_fd: U, sev: V) -> Result<Self, FirmwareError> {
52 let mut launcher = Launcher {
53 vm_fd,
54 sev,
55 state: PhantomData,
56 };
57
58 let init = Init2::init_default_snp();
59
60 let mut cmd = Command::from(&launcher.sev, &init);
61
62 INIT2
63 .ioctl(&mut launcher.vm_fd, &mut cmd)
64 .map_err(|_| cmd.encapsulate())?;
65
66 Ok(launcher)
67 }
68
69 pub fn start(mut self, start: Start) -> Result<Launcher<Started, U, V>, FirmwareError> {
71 let launch_start = LaunchStart::from(start);
72 let mut cmd = Command::from(&self.sev, &launch_start);
73
74 SNP_LAUNCH_START
75 .ioctl(&mut self.vm_fd, &mut cmd)
76 .map_err(|_| cmd.encapsulate())?;
77
78 let launcher = Launcher {
79 vm_fd: self.vm_fd,
80 sev: self.sev,
81 state: PhantomData,
82 };
83
84 Ok(launcher)
85 }
86}
87
88impl<U: AsRawFd, V: AsRawFd> Launcher<Started, U, V> {
89 pub fn update_data(
91 &mut self,
92 mut update: Update,
93 gpa: u64,
94 gpa_len: u64,
95 ) -> Result<(), FirmwareError> {
96 loop {
97 let launch_update_data = LaunchUpdate::from(update);
98 let mut cmd = Command::from(&self.sev, &launch_update_data);
99
100 KvmEncRegion::new(update.uaddr).register(&mut self.vm_fd)?;
102
103 KvmSetMemoryAttributes::new(gpa, gpa_len, KVM_MEMORY_ATTRIBUTE_PRIVATE)
105 .set_attributes(&mut self.vm_fd)?;
106
107 match SNP_LAUNCH_UPDATE.ioctl(&mut self.vm_fd, &mut cmd) {
109 Ok(_) => {
110 if launch_update_data.len == 0 {
112 break;
113 }
114
115 update.start_gfn = launch_update_data.start_gfn;
117 update.uaddr = unsafe {
118 std::slice::from_raw_parts(
119 launch_update_data.uaddr as *const u8,
120 launch_update_data.len as usize,
121 )
122 };
123 }
124 Err(e) if e.raw_os_error() == Some(libc::EAGAIN) => {
125 continue;
127 }
128 Err(_) => {
129 return Err(cmd.encapsulate());
131 }
132 }
133 }
134
135 Ok(())
136 }
137
138 pub fn finish(mut self, finish: Finish) -> Result<(U, V), FirmwareError> {
140 let launch_finish = LaunchFinish::from(finish);
141 let mut cmd = Command::from(&self.sev, &launch_finish);
142
143 SNP_LAUNCH_FINISH
144 .ioctl(&mut self.vm_fd, &mut cmd)
145 .map_err(|_| cmd.encapsulate())?;
146
147 Ok((self.vm_fd, self.sev))
148 }
149}
150
151#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
153#[derive(Default, Clone, Debug, PartialEq, Eq)]
154pub struct Start {
155 pub(crate) policy: GuestPolicy,
157
158 pub(crate) gosvw: [u8; 16],
160
161 pub(crate) flags: u16,
163}
164
165impl Start {
166 pub fn new(policy: GuestPolicy, gosvw: [u8; 16]) -> Self {
168 Self {
169 policy,
170 gosvw,
171 flags: 0,
172 }
173 }
174}
175
176#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
179#[derive(Copy, Clone, Debug, PartialEq, Eq)]
180#[repr(C)]
181#[non_exhaustive]
182pub enum PageType {
183 Normal = 0x1,
185
186 Vmsa = 0x2,
188
189 Zero = 0x3,
191
192 Unmeasured = 0x4,
194
195 Secrets = 0x5,
197
198 Cpuid = 0x6,
200}
201
202#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
204#[derive(Copy, Clone, Debug, PartialEq, Eq)]
205pub struct Update<'a> {
206 pub(crate) start_gfn: u64,
208
209 pub(crate) uaddr: &'a [u8],
211
212 pub(crate) page_type: PageType,
214}
215
216impl<'a> Update<'a> {
217 pub fn new(start_gfn: u64, uaddr: &'a [u8], page_type: PageType) -> Self {
219 Self {
220 start_gfn,
221 uaddr,
222 page_type,
223 }
224 }
225}
226
227bitflags! {
228 #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
229 pub struct VmplPerms: u8 {
231 const READ = 1;
233
234 const WRITE = 1 << 1;
236
237 const EXECUTE_USER = 1 << 2;
239
240 const EXECUTE_SUPERVISOR = 1 << 3;
242 }
243}
244
245#[cfg(feature = "serde")]
246impl Serialize for VmplPerms {
247 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
248 where
249 S: serde::Serializer,
250 {
251 serializer.serialize_u8(self.bits())
252 }
253}
254
255#[cfg(feature = "serde")]
256impl<'de> Deserialize<'de> for VmplPerms {
257 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
258 where
259 D: serde::Deserializer<'de>,
260 {
261 let bits = u8::deserialize(deserializer)?;
262 Ok(VmplPerms::from_bits_truncate(bits))
263 }
264}
265
266#[derive(Copy, Clone, Debug, PartialEq, Eq)]
268pub struct Finish<'a, 'b> {
269 pub(crate) id_block: Option<&'a [u8]>,
271
272 pub(crate) id_auth: Option<&'b [u8]>,
274
275 pub(crate) host_data: [u8; KVM_SEV_SNP_FINISH_DATA_SIZE],
278}
279
280impl<'a, 'b> Finish<'a, 'b> {
281 pub fn new(
283 id_block: Option<&'a [u8]>,
284 id_auth: Option<&'b [u8]>,
285 host_data: [u8; KVM_SEV_SNP_FINISH_DATA_SIZE],
286 ) -> Self {
287 Self {
288 id_block,
289 id_auth,
290 host_data,
291 }
292 }
293}