devices: avoid unnecessary allocations in TPM code

Use the data buffer in the TPM device directly.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu 2023-01-25 21:38:13 +00:00 committed by Rob Bradford
parent e41b7d90d5
commit cffde0ff65
2 changed files with 22 additions and 41 deletions

View File

@ -471,22 +471,14 @@ impl BusDevice for Tpm {
{ {
self.regs[CRB_CTRL_START as usize] |= CRB_START_INVOKE; self.regs[CRB_CTRL_START as usize] |= CRB_START_INVOKE;
let cmd = BackendCmd { let mut cmd = BackendCmd {
locality: locality as u8, locality: locality as u8,
input: self.data_buff[0..self.data_buff_len].to_vec(), buffer: &mut self.data_buff,
input_len: cmp::min(self.data_buff_len, TPM_CRB_BUFFER_MAX), input_len: cmp::min(self.data_buff_len, TPM_CRB_BUFFER_MAX),
output: self.data_buff.to_vec(),
output_len: TPM_CRB_BUFFER_MAX,
selftest_done: false, selftest_done: false,
}; };
let mut cmd = cmd.clone(); let _ = self.emulator.deliver_request(&mut cmd);
if let Ok(output) = self.emulator.deliver_request(&mut cmd) {
// TODO: drop the copy here
self.data_buff.fill(0);
self.data_buff.clone_from_slice(output.as_slice());
}
self.request_completed(TPM_SUCCESS as isize); self.request_completed(TPM_SUCCESS as isize);
} }

View File

@ -30,8 +30,8 @@ const PTM_CAP_SET_BUFFERSIZE: u64 = 1 << 13;
///Check if the input command is selftest ///Check if the input command is selftest
/// ///
pub fn is_selftest(input: Vec<u8>, in_len: usize) -> bool { pub fn is_selftest(input: &[u8]) -> bool {
if in_len >= TPM_REQ_HDR_SIZE { if input.len() >= TPM_REQ_HDR_SIZE {
let ordinal: &[u8; 4] = input[6..6 + 4] let ordinal: &[u8; 4] = input[6..6 + 4]
.try_into() .try_into()
.expect("slice with incorrect length"); .expect("slice with incorrect length");
@ -61,13 +61,12 @@ pub enum Error {
type Result<T> = anyhow::Result<T, Error>; type Result<T> = anyhow::Result<T, Error>;
#[derive(Clone)] pub struct BackendCmd<'a> {
pub struct BackendCmd {
pub locality: u8, pub locality: u8,
pub input: Vec<u8>, // This buffer is used for both input and output.
// When used for input, the length of the data is input_len.
pub buffer: &'a mut [u8],
pub input_len: usize, pub input_len: usize,
pub output: Vec<u8>,
pub output_len: usize,
pub selftest_done: bool, pub selftest_done: bool,
} }
@ -285,23 +284,23 @@ impl Emulator {
} }
/// Function to write to data socket and read the response from it /// Function to write to data socket and read the response from it
fn unix_tx_bufs(&mut self, cmd: &mut BackendCmd) -> Result<()> { pub fn deliver_request(&mut self, cmd: &mut BackendCmd) -> Result<()> {
let isselftest: bool; let isselftest: bool;
// SAFETY: type "sockaddr_storage" is valid with an all-zero byte-pattern value // SAFETY: type "sockaddr_storage" is valid with an all-zero byte-pattern value
let mut addr: sockaddr_storage = unsafe { mem::zeroed() }; let mut addr: sockaddr_storage = unsafe { mem::zeroed() };
let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
cmd.selftest_done = false; cmd.selftest_done = false;
isselftest = is_selftest(cmd.input.to_vec(), cmd.input_len); isselftest = is_selftest(&cmd.buffer[0..cmd.input_len]);
debug!( debug!(
"Send cmd: {:02X?} of len {:?} on data_ioc ", "Send cmd: {:02X?} of len {:?} on data_ioc ",
cmd.input, cmd.input_len cmd.buffer, cmd.input_len
); );
let data_vecs = [libc::iovec { let data_vecs = [libc::iovec {
iov_base: cmd.input.as_mut_ptr() as *mut libc::c_void, iov_base: cmd.buffer.as_ptr() as *mut libc::c_void,
iov_len: cmd.input.len(), iov_len: cmd.input_len,
}; 1]; }; 1];
// SAFETY: all zero values from the unsafe method are updated before usage // SAFETY: all zero values from the unsafe method are updated before usage
@ -324,13 +323,13 @@ impl Emulator {
} }
} }
cmd.output.fill(0); let output_len;
// SAFETY: FFI calls and return value from unsafe method is checked // SAFETY: FFI calls and return value from unsafe method is checked
unsafe { unsafe {
let ret = libc::recvfrom( let ret = libc::recvfrom(
self.data_fd, self.data_fd,
cmd.output.as_ptr() as *mut c_void, cmd.buffer.as_mut_ptr() as *mut c_void,
cmd.output.len(), cmd.buffer.len(),
0, 0,
&mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr, &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr,
&mut len as *mut socklen_t, &mut len as *mut socklen_t,
@ -341,38 +340,28 @@ impl Emulator {
std::io::Error::last_os_error() std::io::Error::last_os_error()
))); )));
} }
cmd.output_len = ret as usize; output_len = ret as usize;
} }
debug!( debug!(
"response = {:02X?} len = {:?} selftest = {:?}", "response = {:02X?} len = {:?} selftest = {:?}",
cmd.output, cmd.output_len, isselftest cmd.buffer, output_len, isselftest
); );
if isselftest { if isselftest {
if cmd.output_len < 10 { if output_len < 10 {
return Err(Error::SelfTest(anyhow!( return Err(Error::SelfTest(anyhow!(
"Self test response should have 10 bytes. Only {:?} returned", "Self test response should have 10 bytes. Only {:?} returned",
cmd.output_len output_len
))); )));
} }
let mut errcode: [u8; 4] = [0; 4]; let mut errcode: [u8; 4] = [0; 4];
errcode.copy_from_slice(&cmd.output[6..6 + 4]); errcode.copy_from_slice(&cmd.buffer[6..6 + 4]);
cmd.selftest_done = u32::from_ne_bytes(errcode).to_be() == 0; cmd.selftest_done = u32::from_ne_bytes(errcode).to_be() == 0;
} }
Ok(()) Ok(())
} }
pub fn deliver_request(&mut self, cmd: &mut BackendCmd) -> Result<Vec<u8>> {
self.unix_tx_bufs(cmd)?;
let output = cmd.output.clone();
cmd.output.fill(0);
cmd.output.clone_from(&output);
Ok(output)
}
pub fn cancel_cmd(&mut self) -> Result<()> { pub fn cancel_cmd(&mut self) -> Result<()> {
let mut res: PtmResult = 0; let mut res: PtmResult = 0;