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(®s, 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