vmm/cpu_config/
templates.rs

1// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4#[cfg(target_arch = "x86_64")]
5mod common_types {
6    pub use crate::cpu_config::x86_64::custom_cpu_template::CustomCpuTemplate;
7    pub use crate::cpu_config::x86_64::static_cpu_templates::StaticCpuTemplate;
8    pub use crate::cpu_config::x86_64::{
9        CpuConfiguration, CpuConfigurationError as GuestConfigError, test_utils,
10    };
11}
12
13#[cfg(target_arch = "aarch64")]
14mod common_types {
15    pub use crate::cpu_config::aarch64::custom_cpu_template::CustomCpuTemplate;
16    pub use crate::cpu_config::aarch64::static_cpu_templates::StaticCpuTemplate;
17    pub use crate::cpu_config::aarch64::{
18        CpuConfiguration, CpuConfigurationError as GuestConfigError, test_utils,
19    };
20}
21
22use std::borrow::Cow;
23use std::fmt::Debug;
24
25pub use common_types::*;
26use serde::de::Error as SerdeError;
27use serde::{Deserialize, Deserializer, Serialize, Serializer};
28
29/// Error for GetCpuTemplate trait.
30#[derive(Debug, thiserror::Error, displaydoc::Display, PartialEq, Eq)]
31pub enum GetCpuTemplateError {
32    #[cfg(target_arch = "x86_64")]
33    /// Failed to get CPU vendor information: {0}
34    GetCpuVendor(crate::cpu_config::x86_64::cpuid::common::GetCpuidError),
35    /// CPU vendor mismatched between actual CPU and CPU template.
36    CpuVendorMismatched,
37    /// Invalid static CPU template: {0}
38    InvalidStaticCpuTemplate(StaticCpuTemplate),
39    /// The current CPU model is not permitted to apply the CPU template.
40    InvalidCpuModel,
41}
42
43/// Trait to unwrap the inner [`CustomCpuTemplate`] from [`Option<CpuTemplateType>`].
44///
45/// This trait is needed because static CPU template and custom CPU template have different nested
46/// structures: `CpuTemplateType::Static(StaticCpuTemplate::StaticTemplateType(CustomCpuTemplate))`
47/// vs `CpuTemplateType::Custom(CustomCpuTemplate)`. As static CPU templates return owned
48/// `CustomCpuTemplate`s, `Cow` is used here to avoid unnecessary clone of `CustomCpuTemplate` for
49/// custom CPU templates and handle static CPU template and custom CPU template in a same manner.
50pub trait GetCpuTemplate {
51    /// Get CPU template
52    fn get_cpu_template(&self) -> Result<Cow<'_, CustomCpuTemplate>, GetCpuTemplateError>;
53}
54
55/// Enum that represents types of cpu templates available.
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub enum CpuTemplateType {
58    /// Custom cpu template
59    Custom(CustomCpuTemplate),
60    /// Static cpu template
61    Static(StaticCpuTemplate),
62}
63
64// This conversion is only used for snapshot, but the static CPU template
65// information has not been saved into snapshot since v1.1.
66impl From<&Option<CpuTemplateType>> for StaticCpuTemplate {
67    fn from(value: &Option<CpuTemplateType>) -> Self {
68        match value {
69            Some(CpuTemplateType::Static(template)) => *template,
70            Some(CpuTemplateType::Custom(_)) | None => StaticCpuTemplate::None,
71        }
72    }
73}
74
75// This conversion is used when converting `&VmConfig` to `MachineConfig` to
76// respond `GET /machine-config` and `GET /vm`.
77impl From<&CpuTemplateType> for StaticCpuTemplate {
78    fn from(value: &CpuTemplateType) -> Self {
79        match value {
80            CpuTemplateType::Static(template) => *template,
81            CpuTemplateType::Custom(_) => StaticCpuTemplate::None,
82        }
83    }
84}
85
86impl TryFrom<&[u8]> for CustomCpuTemplate {
87    type Error = serde_json::Error;
88
89    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
90        let template: CustomCpuTemplate = serde_json::from_slice(value)?;
91        template.validate()?;
92        Ok(template)
93    }
94}
95
96impl TryFrom<&str> for CustomCpuTemplate {
97    type Error = serde_json::Error;
98
99    fn try_from(value: &str) -> Result<Self, Self::Error> {
100        CustomCpuTemplate::try_from(value.as_bytes())
101    }
102}
103
104/// Struct to represent user defined kvm capability.
105/// Users can add or remove kvm capabilities to be checked
106/// by FC in addition to those FC checks by default.
107#[derive(Debug, Clone, Eq, PartialEq)]
108pub enum KvmCapability {
109    /// Add capability to the check list.
110    Add(u32),
111    /// Remove capability from the check list.
112    Remove(u32),
113}
114
115impl Serialize for KvmCapability {
116    /// Serialize KvmCapability into a string.
117    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
118    where
119        S: Serializer,
120    {
121        let s = match self {
122            KvmCapability::Add(cap) => format!("{cap}"),
123            KvmCapability::Remove(cap) => format!("!{cap}"),
124        };
125        serializer.serialize_str(&s)
126    }
127}
128
129impl<'de> Deserialize<'de> for KvmCapability {
130    /// Deserialize string into a KvmCapability.
131    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
132    where
133        D: Deserializer<'de>,
134    {
135        let original_str = <String as Deserialize>::deserialize(deserializer)?;
136
137        let parse_err = |e| {
138            D::Error::custom(format!(
139                "Failed to parse string [{}] as a kvm capability - can not convert to numeric: {}",
140                original_str, e
141            ))
142        };
143
144        match original_str.strip_prefix('!') {
145            Some(s) => {
146                let v = s.parse::<u32>().map_err(parse_err)?;
147                Ok(Self::Remove(v))
148            }
149            None => {
150                let v = original_str.parse::<u32>().map_err(parse_err)?;
151                Ok(Self::Add(v))
152            }
153        }
154    }
155}
156
157/// Bit-mapped value to adjust targeted bits of a register.
158#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
159pub struct RegisterValueFilter<V>
160where
161    V: Numeric,
162{
163    /// Filter to be used when writing the value bits.
164    pub filter: V,
165    /// Value to be applied.
166    pub value: V,
167}
168
169impl<V> RegisterValueFilter<V>
170where
171    V: Numeric + Debug,
172{
173    /// Applies filter to the value
174    #[inline]
175    pub fn apply(&self, value: V) -> V {
176        (value & !self.filter) | self.value
177    }
178}
179
180impl<V> Serialize for RegisterValueFilter<V>
181where
182    V: Numeric + Debug,
183{
184    /// Serialize combination of value and filter into a single tri state string
185    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
186    where
187        S: Serializer,
188    {
189        let mut bitmap_str = Vec::with_capacity(V::BITS as usize + 2);
190        bitmap_str.push(b'0');
191        bitmap_str.push(b'b');
192
193        for i in (0..V::BITS).rev() {
194            match self.filter.bit(i) {
195                true => {
196                    let val = self.value.bit(i);
197                    bitmap_str.push(b'0' + u8::from(val));
198                }
199                false => bitmap_str.push(b'x'),
200            }
201        }
202
203        // # Safety:
204        // We know that bitmap_str contains only ASCII characters
205        let s = unsafe { std::str::from_utf8_unchecked(&bitmap_str) };
206
207        serializer.serialize_str(s)
208    }
209}
210
211impl<'de, V> Deserialize<'de> for RegisterValueFilter<V>
212where
213    V: Numeric + Debug,
214{
215    /// Deserialize a composite bitmap string into a value pair
216    /// input string: "010x"
217    /// result: {
218    ///     filter: 1110
219    ///     value: 0100
220    /// }
221    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
222    where
223        D: Deserializer<'de>,
224    {
225        let original_str = <String as Deserialize>::deserialize(deserializer)?;
226
227        let stripped_str = original_str.strip_prefix("0b").unwrap_or(&original_str);
228
229        let (mut filter, mut value) = (V::zero(), V::zero());
230        let mut i = 0;
231        for s in stripped_str.as_bytes().iter().rev() {
232            if V::BITS == i {
233                return Err(D::Error::custom(format!(
234                    "Failed to parse string [{}] as a bitmap - string is too long",
235                    original_str
236                )));
237            }
238
239            match s {
240                b'_' => continue,
241                b'x' => {}
242                b'0' => {
243                    filter |= V::one() << i;
244                }
245                b'1' => {
246                    filter |= V::one() << i;
247                    value |= V::one() << i;
248                }
249                c => {
250                    return Err(D::Error::custom(format!(
251                        "Failed to parse string [{}] as a bitmap - unknown character: {}",
252                        original_str, c
253                    )));
254                }
255            }
256            i += 1;
257        }
258        Ok(RegisterValueFilter { filter, value })
259    }
260}
261
262/// Trait for numeric types
263pub trait Numeric:
264    Sized
265    + Copy
266    + PartialEq<Self>
267    + std::fmt::Binary
268    + std::ops::Not<Output = Self>
269    + std::ops::BitAnd<Output = Self>
270    + std::ops::BitOr<Output = Self>
271    + std::ops::BitOrAssign<Self>
272    + std::ops::BitXor<Output = Self>
273    + std::ops::Shl<u32, Output = Self>
274    + std::ops::AddAssign<Self>
275{
276    /// Number of bits for type
277    const BITS: u32;
278    /// Value of bit at pos
279    fn bit(&self, pos: u32) -> bool;
280    /// Returns 0 of the type
281    fn zero() -> Self;
282    /// Returns 1 of the type
283    fn one() -> Self;
284}
285
286macro_rules! impl_numeric {
287    ($type:tt) => {
288        impl Numeric for $type {
289            const BITS: u32 = $type::BITS;
290            fn bit(&self, pos: u32) -> bool {
291                (self & (Self::one() << pos)) != 0
292            }
293            fn zero() -> Self {
294                0
295            }
296            fn one() -> Self {
297                1
298            }
299        }
300    };
301}
302
303impl_numeric!(u8);
304impl_numeric!(u16);
305impl_numeric!(u32);
306impl_numeric!(u64);
307impl_numeric!(u128);
308
309#[cfg(test)]
310mod tests {
311    use super::*;
312
313    #[test]
314    fn test_kvm_capability_serde() {
315        let kvm_cap = KvmCapability::Add(69);
316
317        let expected_str = "\"69\"";
318        let serialized = serde_json::to_string(&kvm_cap).unwrap();
319        assert_eq!(&serialized, expected_str);
320
321        let kvm_cap = KvmCapability::Remove(69);
322
323        let expected_str = "\"!69\"";
324        let serialized = serde_json::to_string(&kvm_cap).unwrap();
325        assert_eq!(&serialized, expected_str);
326
327        let serialized = "\"69\"";
328        let deserialized: KvmCapability = serde_json::from_str(serialized).unwrap();
329        assert_eq!(deserialized, KvmCapability::Add(69));
330
331        let serialized = "\"!69\"";
332        let deserialized: KvmCapability = serde_json::from_str(serialized).unwrap();
333        assert_eq!(deserialized, KvmCapability::Remove(69));
334    }
335
336    #[test]
337    fn test_register_value_filter_serde() {
338        let rvf = RegisterValueFilter::<u8> {
339            value: 0b01010101,
340            filter: 0b11110000,
341        };
342
343        let expected_str = "\"0b0101xxxx\"";
344        let serialized = serde_json::to_string(&rvf).unwrap();
345        assert_eq!(&serialized, expected_str);
346
347        let expected_rvf = RegisterValueFilter::<u8> {
348            value: 0b01010000,
349            filter: 0b11110000,
350        };
351        let deserialized: RegisterValueFilter<u8> = serde_json::from_str(&serialized).unwrap();
352        assert_eq!(deserialized, expected_rvf);
353
354        let serialized = "\"0b0_101_xx_xx\"";
355        let deserialized: RegisterValueFilter<u8> = serde_json::from_str(serialized).unwrap();
356        assert_eq!(deserialized, expected_rvf);
357
358        let serialized = "\"0b0_xϽ1_xx_xx\"";
359        let deserialized: Result<RegisterValueFilter<u8>, _> = serde_json::from_str(serialized);
360        deserialized.unwrap_err();
361
362        let serialized = "\"0b0000_0000_0\"";
363        let deserialized: Result<RegisterValueFilter<u8>, _> = serde_json::from_str(serialized);
364        deserialized.unwrap_err();
365    }
366}