Skip to content

Commit 662935c

Browse files
authored
Merge pull request #185 from Freax13/enhancement/fast-cstring-read
optimize cstring reading
2 parents 491b3d4 + 931c238 commit 662935c

File tree

2 files changed

+46
-14
lines changed

2 files changed

+46
-14
lines changed

tee/kernel/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
step_trait,
2424
sync_unsafe_cell,
2525
try_trait_v2,
26-
vec_deque_pop_if
26+
vec_deque_pop_if,
27+
vec_split_at_spare
2728
)]
2829
#![forbid(unsafe_op_in_unsafe_fn)]
2930
#![allow(incomplete_features, internal_features)]

tee/kernel/src/user/process/memory.rs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::{
44
cell::SyncUnsafeCell,
55
cmp::{self, Ordering},
66
fmt::{self, Display, Write},
7-
iter::{Step, repeat_with},
7+
iter::repeat_with,
88
mem::{MaybeUninit, needs_drop},
99
num::{NonZeroU32, NonZeroUsize},
1010
ops::{Bound, Range, RangeBounds},
@@ -280,21 +280,52 @@ impl VirtualMemory {
280280
}
281281

282282
/// Read a string from userspace.
283-
pub fn read_cstring(&self, pointer: Pointer<CString>, max_length: usize) -> Result<CString> {
284-
let mut addr = pointer.get();
285-
let mut ret = Vec::new();
283+
pub fn read_cstring(&self, pointer: Pointer<CString>, max_len: usize) -> Result<CString> {
284+
let mut buf = Vec::new();
285+
286286
loop {
287-
let mut buf = 0;
288-
self.read_bytes(addr, core::array::from_mut(&mut buf))?;
289-
if buf == 0 {
290-
break;
287+
// Make sure that the string doesn't exceed the maximum length.
288+
ensure!(buf.len() < max_len, NameTooLong);
289+
290+
// Allocate some more memory.
291+
buf.reserve(1);
292+
let (init, uninit) = buf.split_at_spare_mut();
293+
294+
// Determine how many bytes to read. Reads are limited by the following:
295+
// - the remaining capacity
296+
// - the maximum (remaining) string length
297+
// - the end of the page
298+
let current_len = init.len();
299+
let addr = pointer.get() + u64::from_usize(current_len);
300+
let page_offset = u16::from(addr.page_offset());
301+
let remaining_len_in_page =
302+
usize::from((page_offset + 1).next_multiple_of(0x1000) - page_offset);
303+
let read_len = cmp::min(uninit.len(), max_len - current_len);
304+
let read_len = cmp::min(read_len, remaining_len_in_page);
305+
debug_assert_ne!(read_len, 0);
306+
307+
// Read more string bytes.
308+
let bytes = self.read_uninit_bytes(addr, &mut uninit[..read_len])?;
309+
310+
// Look for a null-byte in the newly read bytes.
311+
let idx = bytes.iter().position(|&b| b == 0);
312+
313+
// Update the buffer length.
314+
let new_len = current_len + read_len;
315+
unsafe {
316+
buf.set_len(new_len);
317+
}
318+
319+
// If there was a null-byte, then we're done.
320+
if let Some(idx) = idx {
321+
// Truncate the string just after the null-byte.
322+
let cstring_len = current_len + idx + 1;
323+
buf.truncate(cstring_len);
324+
325+
let cstr = unsafe { CString::from_vec_with_nul_unchecked(buf) };
326+
return Ok(cstr);
291327
}
292-
ensure!(ret.len() < max_length, NameTooLong);
293-
addr = Step::forward(addr, 1);
294-
ret.push(buf);
295328
}
296-
let ret = CString::new(ret).unwrap();
297-
Ok(ret)
298329
}
299330

300331
pub fn set_bytes(&self, addr: VirtAddr, count: usize, byte: u8) -> Result<()> {

0 commit comments

Comments
 (0)