Skip to main content

csv_rs/api/platform/
mod.rs

1// Copyright (C) Hygon Info Technologies Ltd.
2//
3// SPDX-License-Identifier: Apache-2.0
4
5//! Modules for interfacing with CSV Firmware
6//! Rust-fridenly API wrappers to communicate the the FFI functions.
7
8/// A handle to the CSV platform.
9mod ioctl;
10pub use ioctl::*;
11
12mod types;
13pub use types::*;
14
15use crate::{certs::csv::*, error::*, Build, Version};
16use std::{
17    fs::{File, OpenOptions},
18    mem::MaybeUninit,
19    os::unix::io::{AsRawFd, RawFd},
20};
21
22/// The CPU-unique identifier for the platform.
23#[derive(Clone, Debug, PartialEq, Eq)]
24pub struct Identifier(pub Vec<u8>);
25
26impl From<Identifier> for Vec<u8> {
27    fn from(id: Identifier) -> Vec<u8> {
28        id.0
29    }
30}
31
32impl std::fmt::Display for Identifier {
33    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
34        for b in self.0.iter() {
35            write!(f, "{b:02X}")?;
36        }
37
38        Ok(())
39    }
40}
41
42pub struct Firmware(File);
43
44impl Firmware {
45    /// Create a handle to the CSV platform.
46    pub fn open() -> std::io::Result<Firmware> {
47        Ok(Firmware(
48            OpenOptions::new().read(true).write(true).open("/dev/sev")?,
49        ))
50    }
51
52    /// Reset the platform persistent state.
53    pub fn platform_reset(&mut self) -> Result<(), Indeterminate<Error>> {
54        PLATFORM_RESET.ioctl(&mut self.0, &mut Command::from(&PlatformReset))?;
55        Ok(())
56    }
57
58    /// Query the platform status.
59    pub fn platform_status(&mut self) -> Result<Status, Indeterminate<Error>> {
60        let mut info: PlatformStatus = Default::default();
61        PLATFORM_STATUS.ioctl(&mut self.0, &mut Command::from_mut(&mut info))?;
62
63        Ok(Status {
64            build: Build {
65                version: Version {
66                    major: info.version.major,
67                    minor: info.version.minor,
68                },
69                build: info.build,
70            },
71            guests: info.guest_count,
72            flags: info.flags,
73            state: match info.state {
74                0 => State::Uninitialized,
75                1 => State::Initialized,
76                2 => State::Working,
77                _ => return Err(Indeterminate::Unknown),
78            },
79        })
80    }
81
82    /// Generate a new Platform Encryption Key (PEK).
83    pub fn pek_generate(&mut self) -> Result<(), Indeterminate<Error>> {
84        PEK_GEN.ioctl(&mut self.0, &mut Command::from(&PekGen))?;
85        Ok(())
86    }
87
88    /// Request a signature for the PEK.
89    pub fn pek_csr(&mut self) -> Result<Certificate, Indeterminate<Error>> {
90        let mut pek = MaybeUninit::uninit();
91        let mut csr = PekCsr::new(&mut pek);
92        PEK_CSR.ioctl(&mut self.0, &mut Command::from_mut(&mut csr))?;
93
94        Ok(unsafe { pek.assume_init() })
95    }
96
97    /// Generate a new Platform Diffie-Hellman (PDH) key pair.
98    pub fn pdh_generate(&mut self) -> Result<(), Indeterminate<Error>> {
99        PDH_GEN.ioctl(&mut self.0, &mut Command::from(&PdhGen))?;
100        Ok(())
101    }
102
103    /// Export the CSV certificate chain.
104    pub fn pdh_cert_export(&mut self) -> Result<Chain, Indeterminate<Error>> {
105        let mut chain: MaybeUninit<[Certificate; 3]> = MaybeUninit::uninit();
106        let mut pdh = MaybeUninit::uninit();
107
108        let mut pdh_cert_export = PdhCertExport::new(&mut pdh, &mut chain);
109        PDH_CERT_EXPORT.ioctl(&mut self.0, &mut Command::from_mut(&mut pdh_cert_export))?;
110
111        Ok(Chain {
112            pdh: unsafe { pdh.assume_init() },
113            pek: unsafe { chain.assume_init() }[0],
114            oca: unsafe { chain.assume_init() }[1],
115            cek: unsafe { chain.assume_init() }[2],
116        })
117    }
118
119    /// Take ownership of the CSV platform.
120    pub fn pek_cert_import(
121        &mut self,
122        pek: &Certificate,
123        oca: &Certificate,
124    ) -> Result<(), Indeterminate<Error>> {
125        let pek_cert_import = PekCertImport::new(pek, oca);
126        PEK_CERT_IMPORT.ioctl(&mut self.0, &mut Command::from(&pek_cert_import))?;
127        Ok(())
128    }
129
130    /// Get the unique CPU identifier.
131    ///
132    /// This is especially helpful for sending HYGON an HTTP request to fetch
133    /// the signed CEK certificate.
134    pub fn get_identifier(&mut self) -> Result<Identifier, Indeterminate<Error>> {
135        let mut bytes = [0u8; 64];
136        let mut id = GetId::new(&mut bytes);
137
138        GET_ID.ioctl(&mut self.0, &mut Command::from_mut(&mut id))?;
139
140        Ok(Identifier(id.as_slice().to_vec()))
141    }
142}
143
144impl AsRawFd for Firmware {
145    fn as_raw_fd(&self) -> RawFd {
146        self.0.as_raw_fd()
147    }
148}