xref: /cloud-hypervisor/devices/src/tpm.rs (revision 1b91aa8ef3ba490a12853d41783ed558cf7b7060)
1d0b253d1SPraveen K Paladugu // Copyright © 2022, Microsoft Corporation
2d0b253d1SPraveen K Paladugu //
3d0b253d1SPraveen K Paladugu // SPDX-License-Identifier: Apache-2.0
4d0b253d1SPraveen K Paladugu //
5d0b253d1SPraveen K Paladugu 
688a9f799SRob Bradford use std::cmp;
788a9f799SRob Bradford use std::sync::{Arc, Barrier};
888a9f799SRob Bradford 
9d0b253d1SPraveen K Paladugu use anyhow::anyhow;
10d0b253d1SPraveen K Paladugu #[cfg(target_arch = "aarch64")]
11d0b253d1SPraveen K Paladugu use arch::aarch64::layout::{TPM_SIZE, TPM_START};
12d0b253d1SPraveen K Paladugu #[cfg(target_arch = "x86_64")]
13d0b253d1SPraveen K Paladugu use arch::x86_64::layout::{TPM_SIZE, TPM_START};
14d0b253d1SPraveen K Paladugu use thiserror::Error;
15d0b253d1SPraveen K Paladugu use tpm::emulator::{BackendCmd, Emulator};
16d0b253d1SPraveen K Paladugu use tpm::TPM_CRB_BUFFER_MAX;
17d0b253d1SPraveen K Paladugu use vm_device::BusDevice;
18d0b253d1SPraveen K Paladugu 
19d0b253d1SPraveen K Paladugu #[derive(Error, Debug)]
20d0b253d1SPraveen K Paladugu pub enum Error {
21*1b91aa8eSPhilipp Schuster     #[error("Emulator doesn't implement min required capabilities")]
22d0b253d1SPraveen K Paladugu     CheckCaps(#[source] anyhow::Error),
23*1b91aa8eSPhilipp Schuster     #[error("Failed to initialize tpm")]
24d0b253d1SPraveen K Paladugu     Init(#[source] anyhow::Error),
25d0b253d1SPraveen K Paladugu }
26d0b253d1SPraveen K Paladugu type Result<T> = anyhow::Result<T, Error>;
27d0b253d1SPraveen K Paladugu 
28cd1470e2SWei Liu #[allow(dead_code)]
29cd1470e2SWei Liu enum LocStateFields {
30cd1470e2SWei Liu     TpmEstablished,
31cd1470e2SWei Liu     LocAssigned,
32cd1470e2SWei Liu     ActiveLocality,
33cd1470e2SWei Liu     Reserved,
34cd1470e2SWei Liu     TpmRegValidSts,
35cd1470e2SWei Liu }
36cd1470e2SWei Liu 
37cd1470e2SWei Liu enum LocStsFields {
38cd1470e2SWei Liu     Granted,
39cd1470e2SWei Liu     BeenSeized,
40cd1470e2SWei Liu }
41cd1470e2SWei Liu 
42cd1470e2SWei Liu #[allow(dead_code)]
43cd1470e2SWei Liu enum IntfIdFields {
44cd1470e2SWei Liu     InterfaceType,
45cd1470e2SWei Liu     InterfaceVersion,
46cd1470e2SWei Liu     CapLocality,
47cd1470e2SWei Liu     CapCRBIdleBypass,
48cd1470e2SWei Liu     Reserved1,
49cd1470e2SWei Liu     CapDataXferSizeSupport,
50cd1470e2SWei Liu     CapFIFO,
51cd1470e2SWei Liu     CapCRB,
52cd1470e2SWei Liu     CapIFRes,
53cd1470e2SWei Liu     InterfaceSelector,
54cd1470e2SWei Liu     IntfSelLock,
55cd1470e2SWei Liu     Reserved2,
56cd1470e2SWei Liu     Rid,
57cd1470e2SWei Liu }
58cd1470e2SWei Liu 
59cd1470e2SWei Liu #[allow(dead_code)]
60cd1470e2SWei Liu enum IntfId2Fields {
61cd1470e2SWei Liu     Vid,
62cd1470e2SWei Liu     Did,
63cd1470e2SWei Liu }
64cd1470e2SWei Liu 
65cd1470e2SWei Liu enum CtrlStsFields {
66cd1470e2SWei Liu     TpmSts,
67cd1470e2SWei Liu     TpmIdle,
68cd1470e2SWei Liu }
69cd1470e2SWei Liu 
70cd1470e2SWei Liu enum CrbRegister {
71cd1470e2SWei Liu     LocState(LocStateFields),
72cd1470e2SWei Liu     LocSts(LocStsFields),
73cd1470e2SWei Liu     IntfId(IntfIdFields),
74cd1470e2SWei Liu     IntfId2(IntfId2Fields),
75cd1470e2SWei Liu     CtrlSts(CtrlStsFields),
76cd1470e2SWei Liu }
77cd1470e2SWei Liu 
78d0b253d1SPraveen K Paladugu /* crb 32-bit registers */
79d0b253d1SPraveen K Paladugu const CRB_LOC_STATE: u32 = 0x0;
80d0b253d1SPraveen K Paladugu //Register Fields
81cd1470e2SWei Liu // Field => (base, offset, length)
82cd1470e2SWei Liu // base:   starting position of the register
83cd1470e2SWei Liu // offset: lowest bit in the bit field numbered from 0
84d0b253d1SPraveen K Paladugu // length: length of the bit field
get_crb_loc_state_field(f: LocStateFields) -> (u32, u32, u32)85cd1470e2SWei Liu const fn get_crb_loc_state_field(f: LocStateFields) -> (u32, u32, u32) {
86cd1470e2SWei Liu     let (offset, len) = match f {
87cd1470e2SWei Liu         LocStateFields::TpmEstablished => (0, 1),
88cd1470e2SWei Liu         LocStateFields::LocAssigned => (1, 1),
89cd1470e2SWei Liu         LocStateFields::ActiveLocality => (2, 3),
90cd1470e2SWei Liu         LocStateFields::Reserved => (5, 2),
91cd1470e2SWei Liu         LocStateFields::TpmRegValidSts => (7, 1),
92d0b253d1SPraveen K Paladugu     };
93cd1470e2SWei Liu 
94cd1470e2SWei Liu     (CRB_LOC_STATE, offset, len)
95cd1470e2SWei Liu }
96cd1470e2SWei Liu 
97d0b253d1SPraveen K Paladugu const CRB_LOC_CTRL: u32 = 0x08;
98d0b253d1SPraveen K Paladugu const CRB_LOC_CTRL_REQUEST_ACCESS: u32 = 1 << 0;
99d0b253d1SPraveen K Paladugu const CRB_LOC_CTRL_RELINQUISH: u32 = 1 << 1;
100d0b253d1SPraveen K Paladugu const CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT: u32 = 1 << 3;
101d0b253d1SPraveen K Paladugu const CRB_LOC_STS: u32 = 0x0C;
get_crb_loc_sts_field(f: LocStsFields) -> (u32, u32, u32)102cd1470e2SWei Liu const fn get_crb_loc_sts_field(f: LocStsFields) -> (u32, u32, u32) {
103cd1470e2SWei Liu     let (offset, len) = match f {
104cd1470e2SWei Liu         LocStsFields::Granted => (0, 1),
105cd1470e2SWei Liu         LocStsFields::BeenSeized => (1, 1),
106d0b253d1SPraveen K Paladugu     };
107cd1470e2SWei Liu 
108cd1470e2SWei Liu     (CRB_LOC_STS, offset, len)
109cd1470e2SWei Liu }
110cd1470e2SWei Liu 
111d0b253d1SPraveen K Paladugu const CRB_INTF_ID: u32 = 0x30;
get_crb_intf_id_field(f: IntfIdFields) -> (u32, u32, u32)112cd1470e2SWei Liu const fn get_crb_intf_id_field(f: IntfIdFields) -> (u32, u32, u32) {
113cd1470e2SWei Liu     let (offset, len) = match f {
114cd1470e2SWei Liu         IntfIdFields::InterfaceType => (0, 4),
115cd1470e2SWei Liu         IntfIdFields::InterfaceVersion => (4, 4),
116cd1470e2SWei Liu         IntfIdFields::CapLocality => (8, 1),
117cd1470e2SWei Liu         IntfIdFields::CapCRBIdleBypass => (9, 1),
118cd1470e2SWei Liu         IntfIdFields::Reserved1 => (10, 1),
119cd1470e2SWei Liu         IntfIdFields::CapDataXferSizeSupport => (11, 2),
120cd1470e2SWei Liu         IntfIdFields::CapFIFO => (13, 1),
121cd1470e2SWei Liu         IntfIdFields::CapCRB => (14, 1),
122cd1470e2SWei Liu         IntfIdFields::CapIFRes => (15, 2),
123cd1470e2SWei Liu         IntfIdFields::InterfaceSelector => (17, 2),
124cd1470e2SWei Liu         IntfIdFields::IntfSelLock => (19, 1),
125cd1470e2SWei Liu         IntfIdFields::Reserved2 => (20, 4),
126cd1470e2SWei Liu         IntfIdFields::Rid => (24, 8),
127d0b253d1SPraveen K Paladugu     };
128cd1470e2SWei Liu 
129cd1470e2SWei Liu     (CRB_INTF_ID, offset, len)
130cd1470e2SWei Liu }
131cd1470e2SWei Liu 
132d0b253d1SPraveen K Paladugu const CRB_INTF_ID2: u32 = 0x34;
get_crb_intf_id2_field(f: IntfId2Fields) -> (u32, u32, u32)133cd1470e2SWei Liu const fn get_crb_intf_id2_field(f: IntfId2Fields) -> (u32, u32, u32) {
134cd1470e2SWei Liu     let (offset, len) = match f {
135cd1470e2SWei Liu         IntfId2Fields::Vid => (0, 16),
136cd1470e2SWei Liu         IntfId2Fields::Did => (16, 16),
137d0b253d1SPraveen K Paladugu     };
138cd1470e2SWei Liu 
139cd1470e2SWei Liu     (CRB_INTF_ID2, offset, len)
140cd1470e2SWei Liu }
141cd1470e2SWei Liu 
142d0b253d1SPraveen K Paladugu const CRB_CTRL_REQ: u32 = 0x40;
143d0b253d1SPraveen K Paladugu const CRB_CTRL_REQ_CMD_READY: u32 = 1 << 0;
144d0b253d1SPraveen K Paladugu const CRB_CTRL_REQ_GO_IDLE: u32 = 1 << 1;
145d0b253d1SPraveen K Paladugu const CRB_CTRL_STS: u32 = 0x44;
get_crb_ctrl_sts_field(f: CtrlStsFields) -> (u32, u32, u32)146cd1470e2SWei Liu const fn get_crb_ctrl_sts_field(f: CtrlStsFields) -> (u32, u32, u32) {
147cd1470e2SWei Liu     let (offset, len) = match f {
148cd1470e2SWei Liu         CtrlStsFields::TpmSts => (0, 1),
149cd1470e2SWei Liu         CtrlStsFields::TpmIdle => (1, 1),
150d0b253d1SPraveen K Paladugu     };
151cd1470e2SWei Liu 
152cd1470e2SWei Liu     (CRB_CTRL_STS, offset, len)
153cd1470e2SWei Liu }
154d0b253d1SPraveen K Paladugu const CRB_CTRL_CANCEL: u32 = 0x48;
155d0b253d1SPraveen K Paladugu const CRB_CANCEL_INVOKE: u32 = 1 << 0;
156d0b253d1SPraveen K Paladugu const CRB_CTRL_START: u32 = 0x4C;
157d0b253d1SPraveen K Paladugu const CRB_START_INVOKE: u32 = 1 << 0;
158d0b253d1SPraveen K Paladugu const CRB_CTRL_CMD_LADDR: u32 = 0x5C;
159d0b253d1SPraveen K Paladugu const CRB_CTRL_CMD_HADDR: u32 = 0x60;
160d0b253d1SPraveen K Paladugu const CRB_CTRL_RSP_SIZE: u32 = 0x64;
161d0b253d1SPraveen K Paladugu const CRB_CTRL_RSP_ADDR: u32 = 0x68;
162d0b253d1SPraveen K Paladugu const CRB_DATA_BUFFER: u32 = 0x80;
163d0b253d1SPraveen K Paladugu 
164d0b253d1SPraveen K Paladugu const TPM_CRB_NO_LOCALITY: u32 = 0xff;
165d0b253d1SPraveen K Paladugu 
166d0b253d1SPraveen K Paladugu const TPM_CRB_ADDR_BASE: u32 = TPM_START.0 as u32;
167d0b253d1SPraveen K Paladugu const TPM_CRB_ADDR_SIZE: usize = TPM_SIZE as usize;
168d0b253d1SPraveen K Paladugu 
16999d8c348SWei Liu const TPM_CRB_R_MAX: usize = CRB_DATA_BUFFER as usize;
170d0b253d1SPraveen K Paladugu 
171d0b253d1SPraveen K Paladugu // CRB Protocol details
172d0b253d1SPraveen K Paladugu const CRB_INTF_TYPE_CRB_ACTIVE: u32 = 0b1;
173d0b253d1SPraveen K Paladugu const CRB_INTF_VERSION_CRB: u32 = 0b1;
174d0b253d1SPraveen K Paladugu const CRB_INTF_CAP_LOCALITY_0_ONLY: u32 = 0b0;
175d0b253d1SPraveen K Paladugu const CRB_INTF_CAP_IDLE_FAST: u32 = 0b0;
176d0b253d1SPraveen K Paladugu const CRB_INTF_CAP_XFER_SIZE_64: u32 = 0b11;
177d0b253d1SPraveen K Paladugu const CRB_INTF_CAP_FIFO_NOT_SUPPORTED: u32 = 0b0;
178d0b253d1SPraveen K Paladugu const CRB_INTF_CAP_CRB_SUPPORTED: u32 = 0b1;
179d0b253d1SPraveen K Paladugu const CRB_INTF_IF_SELECTOR_CRB: u32 = 0b1;
180d0b253d1SPraveen K Paladugu const PCI_VENDOR_ID_IBM: u32 = 0x1014;
181d0b253d1SPraveen K Paladugu const CRB_CTRL_CMD_SIZE_REG: u32 = 0x58;
182d0b253d1SPraveen K Paladugu const CRB_CTRL_CMD_SIZE: usize = TPM_CRB_ADDR_SIZE - CRB_DATA_BUFFER as usize;
183d0b253d1SPraveen K Paladugu 
184cd1470e2SWei Liu // Returns (register base, offset, len)
get_field(reg: CrbRegister) -> (u32, u32, u32)185cd1470e2SWei Liu const fn get_field(reg: CrbRegister) -> (u32, u32, u32) {
186d0b253d1SPraveen K Paladugu     match reg {
187cd1470e2SWei Liu         CrbRegister::LocState(f) => get_crb_loc_state_field(f),
188cd1470e2SWei Liu         CrbRegister::LocSts(f) => get_crb_loc_sts_field(f),
189cd1470e2SWei Liu         CrbRegister::IntfId(f) => get_crb_intf_id_field(f),
190cd1470e2SWei Liu         CrbRegister::IntfId2(f) => get_crb_intf_id2_field(f),
191cd1470e2SWei Liu         CrbRegister::CtrlSts(f) => get_crb_ctrl_sts_field(f),
192d0b253d1SPraveen K Paladugu     }
193d0b253d1SPraveen K Paladugu }
194d0b253d1SPraveen K Paladugu 
195cd1470e2SWei Liu // Set a particular field in a Register
set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX], reg: CrbRegister, value: u32)196cd1470e2SWei Liu fn set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX], reg: CrbRegister, value: u32) {
197cd1470e2SWei Liu     let (base, offset, len) = get_field(reg);
198cd1470e2SWei Liu     let mask = (!(0_u32) >> (32 - len)) << offset;
199cd1470e2SWei Liu     regs[base as usize] = (regs[base as usize] & !mask) | ((value << offset) & mask);
200d0b253d1SPraveen K Paladugu }
201cd1470e2SWei Liu 
202cd1470e2SWei Liu // Get the value of a particular field in a Register
get_reg_field(regs: &[u32; TPM_CRB_R_MAX], reg: CrbRegister) -> u32203cd1470e2SWei Liu const fn get_reg_field(regs: &[u32; TPM_CRB_R_MAX], reg: CrbRegister) -> u32 {
204cd1470e2SWei Liu     let (base, offset, len) = get_field(reg);
205cd1470e2SWei Liu     let mask = (!(0_u32) >> (32 - len)) << offset;
206cd1470e2SWei Liu     (regs[base as usize] & mask) >> offset
207d0b253d1SPraveen K Paladugu }
208d0b253d1SPraveen K Paladugu 
locality_from_addr(addr: u32) -> u8209d0b253d1SPraveen K Paladugu fn locality_from_addr(addr: u32) -> u8 {
210d0b253d1SPraveen K Paladugu     (addr >> 12) as u8
211d0b253d1SPraveen K Paladugu }
212d0b253d1SPraveen K Paladugu 
213d0b253d1SPraveen K Paladugu pub struct Tpm {
214d0b253d1SPraveen K Paladugu     emulator: Emulator,
21599d8c348SWei Liu     regs: [u32; TPM_CRB_R_MAX],
216d0b253d1SPraveen K Paladugu     backend_buff_size: usize,
217d0b253d1SPraveen K Paladugu     data_buff: [u8; TPM_CRB_BUFFER_MAX],
218d0b253d1SPraveen K Paladugu     data_buff_len: usize,
219d0b253d1SPraveen K Paladugu }
220d0b253d1SPraveen K Paladugu 
221d0b253d1SPraveen K Paladugu impl Tpm {
new(path: String) -> Result<Self>222d0b253d1SPraveen K Paladugu     pub fn new(path: String) -> Result<Self> {
223d0b253d1SPraveen K Paladugu         let emulator = Emulator::new(path)
224d0b253d1SPraveen K Paladugu             .map_err(|e| Error::Init(anyhow!("Failed while initializing tpm Emulator: {:?}", e)))?;
225d0b253d1SPraveen K Paladugu         let mut tpm = Tpm {
226d0b253d1SPraveen K Paladugu             emulator,
22799d8c348SWei Liu             regs: [0; TPM_CRB_R_MAX],
228d0b253d1SPraveen K Paladugu             backend_buff_size: TPM_CRB_BUFFER_MAX,
229d0b253d1SPraveen K Paladugu             data_buff: [0; TPM_CRB_BUFFER_MAX],
230d0b253d1SPraveen K Paladugu             data_buff_len: 0,
231d0b253d1SPraveen K Paladugu         };
232d0b253d1SPraveen K Paladugu         tpm.reset()?;
233d0b253d1SPraveen K Paladugu         Ok(tpm)
234d0b253d1SPraveen K Paladugu     }
235d0b253d1SPraveen K Paladugu 
get_active_locality(&mut self) -> u32236d0b253d1SPraveen K Paladugu     fn get_active_locality(&mut self) -> u32 {
237cd1470e2SWei Liu         if get_reg_field(
238cd1470e2SWei Liu             &self.regs,
239cd1470e2SWei Liu             CrbRegister::LocState(LocStateFields::LocAssigned),
240cd1470e2SWei Liu         ) == 0
241cd1470e2SWei Liu         {
242d0b253d1SPraveen K Paladugu             return TPM_CRB_NO_LOCALITY;
243d0b253d1SPraveen K Paladugu         }
244cd1470e2SWei Liu         get_reg_field(
245cd1470e2SWei Liu             &self.regs,
246cd1470e2SWei Liu             CrbRegister::LocState(LocStateFields::ActiveLocality),
247cd1470e2SWei Liu         )
248d0b253d1SPraveen K Paladugu     }
249d0b253d1SPraveen K Paladugu 
request_completed(&mut self, success: bool)2502d2f356dSWei Liu     fn request_completed(&mut self, success: bool) {
251d0b253d1SPraveen K Paladugu         self.regs[CRB_CTRL_START as usize] = !CRB_START_INVOKE;
2522d2f356dSWei Liu         if !success {
253cd1470e2SWei Liu             set_reg_field(
254cd1470e2SWei Liu                 &mut self.regs,
255cd1470e2SWei Liu                 CrbRegister::CtrlSts(CtrlStsFields::TpmSts),
256cd1470e2SWei Liu                 1,
257cd1470e2SWei Liu             );
258d0b253d1SPraveen K Paladugu         }
259d0b253d1SPraveen K Paladugu     }
260d0b253d1SPraveen K Paladugu 
reset(&mut self) -> Result<()>261d0b253d1SPraveen K Paladugu     fn reset(&mut self) -> Result<()> {
26260425471SWei Liu         let cur_buff_size = self.emulator.get_buffer_size();
26399d8c348SWei Liu         self.regs = [0; TPM_CRB_R_MAX];
264d0b253d1SPraveen K Paladugu         set_reg_field(
265d0b253d1SPraveen K Paladugu             &mut self.regs,
266cd1470e2SWei Liu             CrbRegister::LocState(LocStateFields::TpmRegValidSts),
267cd1470e2SWei Liu             1,
268cd1470e2SWei Liu         );
269cd1470e2SWei Liu         set_reg_field(
270cd1470e2SWei Liu             &mut self.regs,
271cd1470e2SWei Liu             CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
272cd1470e2SWei Liu             1,
273cd1470e2SWei Liu         );
274cd1470e2SWei Liu         set_reg_field(
275cd1470e2SWei Liu             &mut self.regs,
276cd1470e2SWei Liu             CrbRegister::IntfId(IntfIdFields::InterfaceType),
277d0b253d1SPraveen K Paladugu             CRB_INTF_TYPE_CRB_ACTIVE,
278d0b253d1SPraveen K Paladugu         );
279d0b253d1SPraveen K Paladugu         set_reg_field(
280d0b253d1SPraveen K Paladugu             &mut self.regs,
281cd1470e2SWei Liu             CrbRegister::IntfId(IntfIdFields::InterfaceVersion),
282d0b253d1SPraveen K Paladugu             CRB_INTF_VERSION_CRB,
283d0b253d1SPraveen K Paladugu         );
284d0b253d1SPraveen K Paladugu         set_reg_field(
285d0b253d1SPraveen K Paladugu             &mut self.regs,
286cd1470e2SWei Liu             CrbRegister::IntfId(IntfIdFields::CapLocality),
287d0b253d1SPraveen K Paladugu             CRB_INTF_CAP_LOCALITY_0_ONLY,
288d0b253d1SPraveen K Paladugu         );
289d0b253d1SPraveen K Paladugu         set_reg_field(
290d0b253d1SPraveen K Paladugu             &mut self.regs,
291cd1470e2SWei Liu             CrbRegister::IntfId(IntfIdFields::CapCRBIdleBypass),
292d0b253d1SPraveen K Paladugu             CRB_INTF_CAP_IDLE_FAST,
293d0b253d1SPraveen K Paladugu         );
294d0b253d1SPraveen K Paladugu         set_reg_field(
295d0b253d1SPraveen K Paladugu             &mut self.regs,
296cd1470e2SWei Liu             CrbRegister::IntfId(IntfIdFields::CapDataXferSizeSupport),
297d0b253d1SPraveen K Paladugu             CRB_INTF_CAP_XFER_SIZE_64,
298d0b253d1SPraveen K Paladugu         );
299d0b253d1SPraveen K Paladugu         set_reg_field(
300d0b253d1SPraveen K Paladugu             &mut self.regs,
301cd1470e2SWei Liu             CrbRegister::IntfId(IntfIdFields::CapFIFO),
302d0b253d1SPraveen K Paladugu             CRB_INTF_CAP_FIFO_NOT_SUPPORTED,
303d0b253d1SPraveen K Paladugu         );
304d0b253d1SPraveen K Paladugu         set_reg_field(
305d0b253d1SPraveen K Paladugu             &mut self.regs,
306cd1470e2SWei Liu             CrbRegister::IntfId(IntfIdFields::CapCRB),
307d0b253d1SPraveen K Paladugu             CRB_INTF_CAP_CRB_SUPPORTED,
308d0b253d1SPraveen K Paladugu         );
309d0b253d1SPraveen K Paladugu         set_reg_field(
310d0b253d1SPraveen K Paladugu             &mut self.regs,
311cd1470e2SWei Liu             CrbRegister::IntfId(IntfIdFields::InterfaceSelector),
312d0b253d1SPraveen K Paladugu             CRB_INTF_IF_SELECTOR_CRB,
313d0b253d1SPraveen K Paladugu         );
314cd1470e2SWei Liu         set_reg_field(
315cd1470e2SWei Liu             &mut self.regs,
316cd1470e2SWei Liu             CrbRegister::IntfId(IntfIdFields::Rid),
317cd1470e2SWei Liu             0b0000,
318cd1470e2SWei Liu         );
319cd1470e2SWei Liu         set_reg_field(
320cd1470e2SWei Liu             &mut self.regs,
321cd1470e2SWei Liu             CrbRegister::IntfId2(IntfId2Fields::Vid),
322cd1470e2SWei Liu             PCI_VENDOR_ID_IBM,
323cd1470e2SWei Liu         );
324d0b253d1SPraveen K Paladugu 
325d0b253d1SPraveen K Paladugu         self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = CRB_CTRL_CMD_SIZE as u32;
326d0b253d1SPraveen K Paladugu         self.regs[CRB_CTRL_CMD_LADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
327d0b253d1SPraveen K Paladugu         self.regs[CRB_CTRL_RSP_SIZE as usize] = CRB_CTRL_CMD_SIZE as u32;
328d0b253d1SPraveen K Paladugu         self.regs[CRB_CTRL_RSP_ADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
329d0b253d1SPraveen K Paladugu 
330d0b253d1SPraveen K Paladugu         self.backend_buff_size = cmp::min(cur_buff_size, TPM_CRB_BUFFER_MAX);
331d0b253d1SPraveen K Paladugu 
332d0b253d1SPraveen K Paladugu         if let Err(e) = self.emulator.startup_tpm(self.backend_buff_size) {
333d0b253d1SPraveen K Paladugu             return Err(Error::Init(anyhow!(
334d0b253d1SPraveen K Paladugu                 "Failed while running Startup TPM. Error: {:?}",
335d0b253d1SPraveen K Paladugu                 e
336d0b253d1SPraveen K Paladugu             )));
337d0b253d1SPraveen K Paladugu         }
338d0b253d1SPraveen K Paladugu         Ok(())
339d0b253d1SPraveen K Paladugu     }
340d0b253d1SPraveen K Paladugu }
341d0b253d1SPraveen K Paladugu 
342d0b253d1SPraveen K Paladugu impl BusDevice for Tpm {
read(&mut self, _base: u64, offset: u64, data: &mut [u8])343d0b253d1SPraveen K Paladugu     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
344d0b253d1SPraveen K Paladugu         let mut offset: u32 = offset as u32;
345d0b253d1SPraveen K Paladugu         let read_len: usize = data.len();
346d0b253d1SPraveen K Paladugu 
347d0b253d1SPraveen K Paladugu         if offset >= CRB_DATA_BUFFER
348d0b253d1SPraveen K Paladugu             && (offset + read_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32)
349d0b253d1SPraveen K Paladugu         {
350d0b253d1SPraveen K Paladugu             // Read from Data Buffer
351d0b253d1SPraveen K Paladugu             let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize);
352d0b253d1SPraveen K Paladugu             let end: usize = start + read_len;
353d0b253d1SPraveen K Paladugu             data[..].clone_from_slice(&self.data_buff[start..end]);
354d0b253d1SPraveen K Paladugu         } else {
355d0b253d1SPraveen K Paladugu             offset &= 0xff;
356d0b253d1SPraveen K Paladugu             let mut val = self.regs[offset as usize];
357d0b253d1SPraveen K Paladugu 
358d0b253d1SPraveen K Paladugu             if offset == CRB_LOC_STATE && !self.emulator.get_established_flag() {
359d0b253d1SPraveen K Paladugu                 val |= 0x1;
360d0b253d1SPraveen K Paladugu             }
361d0b253d1SPraveen K Paladugu 
362d0b253d1SPraveen K Paladugu             if data.len() <= 4 {
363d0b253d1SPraveen K Paladugu                 data.clone_from_slice(val.to_ne_bytes()[0..read_len].as_ref());
364d0b253d1SPraveen K Paladugu             } else {
365d0b253d1SPraveen K Paladugu                 error!(
366d0b253d1SPraveen K Paladugu                     "Invalid tpm read: offset {:#X}, data length {:?}",
367d0b253d1SPraveen K Paladugu                     offset,
368d0b253d1SPraveen K Paladugu                     data.len()
369d0b253d1SPraveen K Paladugu                 );
370d0b253d1SPraveen K Paladugu             }
371d0b253d1SPraveen K Paladugu         }
372d0b253d1SPraveen K Paladugu         debug!(
373d0b253d1SPraveen K Paladugu             "MMIO Read: offset {:#X} len {:?} val = {:02X?}  ",
374d0b253d1SPraveen K Paladugu             offset,
375d0b253d1SPraveen K Paladugu             data.len(),
376d0b253d1SPraveen K Paladugu             data
377d0b253d1SPraveen K Paladugu         );
378d0b253d1SPraveen K Paladugu     }
379d0b253d1SPraveen K Paladugu 
write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>380d0b253d1SPraveen K Paladugu     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
381d0b253d1SPraveen K Paladugu         debug!(
382d0b253d1SPraveen K Paladugu             "MMIO Write: offset {:#X} len {:?} input data {:02X?}",
383d0b253d1SPraveen K Paladugu             offset,
384d0b253d1SPraveen K Paladugu             data.len(),
385d0b253d1SPraveen K Paladugu             data
386d0b253d1SPraveen K Paladugu         );
387d0b253d1SPraveen K Paladugu         let mut offset: u32 = offset as u32;
388d0b253d1SPraveen K Paladugu         if offset < CRB_DATA_BUFFER {
389d0b253d1SPraveen K Paladugu             offset &= 0xff;
390d0b253d1SPraveen K Paladugu         }
391d0b253d1SPraveen K Paladugu         let locality = locality_from_addr(offset) as u32;
392d0b253d1SPraveen K Paladugu         let write_len = data.len();
393d0b253d1SPraveen K Paladugu 
394d0b253d1SPraveen K Paladugu         if offset >= CRB_DATA_BUFFER
395d0b253d1SPraveen K Paladugu             && (offset + write_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32)
396d0b253d1SPraveen K Paladugu         {
397d0b253d1SPraveen K Paladugu             let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize);
398d0b253d1SPraveen K Paladugu             if start == 0 {
399d0b253d1SPraveen K Paladugu                 // If filling data_buff at index 0, reset length to 0
400d0b253d1SPraveen K Paladugu                 self.data_buff_len = 0;
401d0b253d1SPraveen K Paladugu                 self.data_buff.fill(0);
402d0b253d1SPraveen K Paladugu             }
403d0b253d1SPraveen K Paladugu             let end: usize = start + data.len();
404d0b253d1SPraveen K Paladugu             self.data_buff[start..end].clone_from_slice(data);
405d0b253d1SPraveen K Paladugu             self.data_buff_len += data.len();
406d0b253d1SPraveen K Paladugu         } else {
407d0b253d1SPraveen K Paladugu             // Ctrl Commands that take more than 4 bytes as input are not yet supported
408d0b253d1SPraveen K Paladugu             // CTRL_RSP_ADDR usually gets 8 byte write request. Last 4 bytes are zeros.
409d0b253d1SPraveen K Paladugu             if write_len > 4 && offset != CRB_CTRL_RSP_ADDR {
410d0b253d1SPraveen K Paladugu                 error!(
411d0b253d1SPraveen K Paladugu                     "Invalid tpm write: offset {:#X}, data length {}",
412d0b253d1SPraveen K Paladugu                     offset,
413d0b253d1SPraveen K Paladugu                     data.len()
414d0b253d1SPraveen K Paladugu                 );
415d0b253d1SPraveen K Paladugu                 return None;
416d0b253d1SPraveen K Paladugu             }
417d0b253d1SPraveen K Paladugu 
418d0b253d1SPraveen K Paladugu             let mut input: [u8; 4] = [0; 4];
419d0b253d1SPraveen K Paladugu             input.copy_from_slice(&data[0..4]);
420d0b253d1SPraveen K Paladugu             let v = u32::from_le_bytes(input);
421d0b253d1SPraveen K Paladugu 
422d0b253d1SPraveen K Paladugu             match offset {
423d0b253d1SPraveen K Paladugu                 CRB_CTRL_CMD_SIZE_REG => {
424d0b253d1SPraveen K Paladugu                     self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = v;
425d0b253d1SPraveen K Paladugu                 }
426d0b253d1SPraveen K Paladugu                 CRB_CTRL_CMD_LADDR => {
427d0b253d1SPraveen K Paladugu                     self.regs[CRB_CTRL_CMD_LADDR as usize] = v;
428d0b253d1SPraveen K Paladugu                 }
429d0b253d1SPraveen K Paladugu                 CRB_CTRL_CMD_HADDR => {
430d0b253d1SPraveen K Paladugu                     self.regs[CRB_CTRL_CMD_HADDR as usize] = v;
431d0b253d1SPraveen K Paladugu                 }
432d0b253d1SPraveen K Paladugu                 CRB_CTRL_RSP_SIZE => {
433d0b253d1SPraveen K Paladugu                     self.regs[CRB_CTRL_RSP_SIZE as usize] = v;
434d0b253d1SPraveen K Paladugu                 }
435d0b253d1SPraveen K Paladugu                 CRB_CTRL_RSP_ADDR => {
436d0b253d1SPraveen K Paladugu                     self.regs[CRB_CTRL_RSP_ADDR as usize] = v;
437d0b253d1SPraveen K Paladugu                 }
438d0b253d1SPraveen K Paladugu                 CRB_CTRL_REQ => match v {
439d0b253d1SPraveen K Paladugu                     CRB_CTRL_REQ_CMD_READY => {
440cd1470e2SWei Liu                         set_reg_field(
441cd1470e2SWei Liu                             &mut self.regs,
442cd1470e2SWei Liu                             CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
443cd1470e2SWei Liu                             0,
444cd1470e2SWei Liu                         );
445d0b253d1SPraveen K Paladugu                     }
446d0b253d1SPraveen K Paladugu                     CRB_CTRL_REQ_GO_IDLE => {
447cd1470e2SWei Liu                         set_reg_field(
448cd1470e2SWei Liu                             &mut self.regs,
449cd1470e2SWei Liu                             CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
450cd1470e2SWei Liu                             1,
451cd1470e2SWei Liu                         );
452d0b253d1SPraveen K Paladugu                     }
453d0b253d1SPraveen K Paladugu                     _ => {
45442e9632cSJosh Soref                         error!("Invalid value passed to CTRL_REQ register");
455d0b253d1SPraveen K Paladugu                         return None;
456d0b253d1SPraveen K Paladugu                     }
457d0b253d1SPraveen K Paladugu                 },
458d0b253d1SPraveen K Paladugu                 CRB_CTRL_CANCEL => {
459d0b253d1SPraveen K Paladugu                     if v == CRB_CANCEL_INVOKE
460d0b253d1SPraveen K Paladugu                         && (self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE != 0)
461d0b253d1SPraveen K Paladugu                     {
462d0b253d1SPraveen K Paladugu                         if let Err(e) = self.emulator.cancel_cmd() {
463d0b253d1SPraveen K Paladugu                             error!("Failed to run cancel command. Error: {:?}", e);
464d0b253d1SPraveen K Paladugu                         }
465d0b253d1SPraveen K Paladugu                     }
466d0b253d1SPraveen K Paladugu                 }
467d0b253d1SPraveen K Paladugu                 CRB_CTRL_START => {
468d0b253d1SPraveen K Paladugu                     if v == CRB_START_INVOKE
469d0b253d1SPraveen K Paladugu                         && ((self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE) == 0)
470d0b253d1SPraveen K Paladugu                         && self.get_active_locality() == locality
471d0b253d1SPraveen K Paladugu                     {
472d0b253d1SPraveen K Paladugu                         self.regs[CRB_CTRL_START as usize] |= CRB_START_INVOKE;
473d0b253d1SPraveen K Paladugu 
474cffde0ffSWei Liu                         let mut cmd = BackendCmd {
475cffde0ffSWei Liu                             buffer: &mut self.data_buff,
476d0b253d1SPraveen K Paladugu                             input_len: cmp::min(self.data_buff_len, TPM_CRB_BUFFER_MAX),
47715ace525SWei Liu                         };
478d0b253d1SPraveen K Paladugu 
4792d2f356dSWei Liu                         let status = self.emulator.deliver_request(&mut cmd).is_ok();
480d0b253d1SPraveen K Paladugu 
4812d2f356dSWei Liu                         self.request_completed(status);
482d0b253d1SPraveen K Paladugu                     }
483d0b253d1SPraveen K Paladugu                 }
484d0b253d1SPraveen K Paladugu                 CRB_LOC_CTRL => {
485d0b253d1SPraveen K Paladugu                     warn!(
486d0b253d1SPraveen K Paladugu                         "CRB_LOC_CTRL locality to write = {:?} val = {:?}",
487d0b253d1SPraveen K Paladugu                         locality, v
488d0b253d1SPraveen K Paladugu                     );
489d0b253d1SPraveen K Paladugu                     match v {
490d0b253d1SPraveen K Paladugu                         CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT => {}
491d0b253d1SPraveen K Paladugu                         CRB_LOC_CTRL_RELINQUISH => {
492cd1470e2SWei Liu                             set_reg_field(
493cd1470e2SWei Liu                                 &mut self.regs,
494cd1470e2SWei Liu                                 CrbRegister::LocState(LocStateFields::LocAssigned),
495cd1470e2SWei Liu                                 0,
496cd1470e2SWei Liu                             );
497cd1470e2SWei Liu                             set_reg_field(
498cd1470e2SWei Liu                                 &mut self.regs,
499cd1470e2SWei Liu                                 CrbRegister::LocSts(LocStsFields::Granted),
500cd1470e2SWei Liu                                 0,
501cd1470e2SWei Liu                             );
502d0b253d1SPraveen K Paladugu                         }
503d0b253d1SPraveen K Paladugu                         CRB_LOC_CTRL_REQUEST_ACCESS => {
504cd1470e2SWei Liu                             set_reg_field(
505cd1470e2SWei Liu                                 &mut self.regs,
506cd1470e2SWei Liu                                 CrbRegister::LocSts(LocStsFields::Granted),
507cd1470e2SWei Liu                                 1,
508cd1470e2SWei Liu                             );
509cd1470e2SWei Liu                             set_reg_field(
510cd1470e2SWei Liu                                 &mut self.regs,
511cd1470e2SWei Liu                                 CrbRegister::LocSts(LocStsFields::BeenSeized),
512cd1470e2SWei Liu                                 0,
513cd1470e2SWei Liu                             );
514cd1470e2SWei Liu                             set_reg_field(
515cd1470e2SWei Liu                                 &mut self.regs,
516cd1470e2SWei Liu                                 CrbRegister::LocState(LocStateFields::LocAssigned),
517cd1470e2SWei Liu                                 1,
518cd1470e2SWei Liu                             );
519d0b253d1SPraveen K Paladugu                         }
520d0b253d1SPraveen K Paladugu                         _ => {
521d0b253d1SPraveen K Paladugu                             error!("Invalid value to write in CRB_LOC_CTRL {:#X} ", v);
522d0b253d1SPraveen K Paladugu                         }
523d0b253d1SPraveen K Paladugu                     }
524d0b253d1SPraveen K Paladugu                 }
525d0b253d1SPraveen K Paladugu                 _ => {
526d0b253d1SPraveen K Paladugu                     error!(
527d0b253d1SPraveen K Paladugu                         "Invalid tpm write: offset {:#X}, data length {:?}",
528d0b253d1SPraveen K Paladugu                         offset,
529d0b253d1SPraveen K Paladugu                         data.len()
530d0b253d1SPraveen K Paladugu                     );
531d0b253d1SPraveen K Paladugu                 }
532d0b253d1SPraveen K Paladugu             }
533d0b253d1SPraveen K Paladugu         }
534d0b253d1SPraveen K Paladugu         None
535d0b253d1SPraveen K Paladugu     }
536d0b253d1SPraveen K Paladugu }
537d0b253d1SPraveen K Paladugu 
538d0b253d1SPraveen K Paladugu #[cfg(test)]
539d0b253d1SPraveen K Paladugu mod tests {
540d0b253d1SPraveen K Paladugu     use super::*;
541d0b253d1SPraveen K Paladugu 
542d0b253d1SPraveen K Paladugu     #[test]
test_set_get_reg_field()543d0b253d1SPraveen K Paladugu     fn test_set_get_reg_field() {
54499d8c348SWei Liu         let mut regs: [u32; TPM_CRB_R_MAX] = [0; TPM_CRB_R_MAX];
545cd1470e2SWei Liu         set_reg_field(&mut regs, CrbRegister::IntfId(IntfIdFields::Rid), 0xAC);
546d0b253d1SPraveen K Paladugu         assert_eq!(
547cd1470e2SWei Liu             get_reg_field(&regs, CrbRegister::IntfId(IntfIdFields::Rid)),
548d0b253d1SPraveen K Paladugu             0xAC,
549d0b253d1SPraveen K Paladugu             concat!("Test: ", stringify!(set_get_reg_field))
550d0b253d1SPraveen K Paladugu         );
551d0b253d1SPraveen K Paladugu     }
552d0b253d1SPraveen K Paladugu }
553