Skip to content

Commit 17cd61d

Browse files
committed
std: sys: io: io_slice: Add UEFI types
UEFI networking APIs do support vectored read/write. While the types for UDP4, UDP6, TCP4 and TCP6 are defined separately, they are essentially the same C struct. So we can map IoSlice and IoSliceMut to have the same binary representation. Since all UEFI networking types for read/write are DSTs, `IoSlice` and `IoSliceMut` will need to be copied to the end of the transmit/receive structures. So having the same binary representation just allows us to do a single memcpy instead of having to loop and set the DST. Signed-off-by: Ayush Singh <[email protected]>
1 parent ca9eecd commit 17cd61d

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//! A buffer type used with `Write::write_vectored` for UEFI Networking APIs. Vectored writing to
2+
//! File is not supported as of UEFI Spec 2.11.
3+
4+
use crate::marker::PhantomData;
5+
use crate::slice;
6+
7+
#[derive(Copy, Clone)]
8+
#[repr(C)]
9+
pub struct IoSlice<'a> {
10+
len: u32,
11+
data: *const u8,
12+
_p: PhantomData<&'a [u8]>,
13+
}
14+
15+
impl<'a> IoSlice<'a> {
16+
#[inline]
17+
pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
18+
let len = buf.len().try_into().unwrap();
19+
Self { len, data: buf.as_ptr(), _p: PhantomData }
20+
}
21+
22+
#[inline]
23+
pub fn advance(&mut self, n: usize) {
24+
let count: u32 = n.try_into().unwrap();
25+
self.len += count;
26+
unsafe { self.data = self.data.add(n) };
27+
}
28+
29+
#[inline]
30+
pub const fn as_slice(&self) -> &'a [u8] {
31+
unsafe { slice::from_raw_parts(self.data, self.len as usize) }
32+
}
33+
}
34+
35+
#[repr(C)]
36+
pub struct IoSliceMut<'a> {
37+
len: u32,
38+
data: *mut u8,
39+
_p: PhantomData<&'a mut [u8]>,
40+
}
41+
42+
impl<'a> IoSliceMut<'a> {
43+
#[inline]
44+
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
45+
let len = buf.len().try_into().unwrap();
46+
Self { len, data: buf.as_mut_ptr(), _p: PhantomData }
47+
}
48+
49+
#[inline]
50+
pub fn advance(&mut self, n: usize) {
51+
let count: u32 = n.try_into().unwrap();
52+
self.len += count;
53+
unsafe { self.data = self.data.add(n) };
54+
}
55+
56+
#[inline]
57+
pub fn as_slice(&self) -> &[u8] {
58+
unsafe { slice::from_raw_parts(self.data, self.len as usize) }
59+
}
60+
61+
#[inline]
62+
pub const fn into_slice(self) -> &'a mut [u8] {
63+
unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) }
64+
}
65+
66+
#[inline]
67+
pub fn as_mut_slice(&mut self) -> &mut [u8] {
68+
unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) }
69+
}
70+
}

library/std/src/sys/io/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ mod io_slice {
1111
} else if #[cfg(target_os = "wasi")] {
1212
mod wasi;
1313
pub use wasi::*;
14+
} else if #[cfg(target_os = "uefi")] {
15+
mod uefi;
16+
pub use uefi::*;
1417
} else {
1518
mod unsupported;
1619
pub use unsupported::*;

library/std/src/sys/pal/uefi/tests.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::alloc::*;
22
use super::time::*;
3+
use crate::io::{IoSlice, IoSliceMut};
34
use crate::time::Duration;
45

56
#[test]
@@ -39,3 +40,92 @@ fn epoch() {
3940
};
4041
assert_eq!(system_time_internal::uefi_time_to_duration(t), Duration::new(0, 0));
4142
}
43+
44+
// UEFI IoSlice and IoSliceMut Tests
45+
//
46+
// Strictly speaking, vectored read/write types for UDP4, UDP6, TCP4, TCP6 are defined
47+
// separately in the UEFI Spec. However, they have the same signature. These tests just ensure
48+
// that `IoSlice` and `IoSliceMut` are compatible with the vectored types for all the
49+
// networking protocols.
50+
51+
fn to_slice<T>(val: &T) -> &[u8] {
52+
let len = size_of_val(val);
53+
unsafe { crate::slice::from_raw_parts(crate::ptr::from_ref(val).cast(), len) }
54+
}
55+
56+
#[test]
57+
fn io_slice_single() {
58+
let mut data = [0, 1, 2, 3, 4];
59+
60+
let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
61+
fragment_length: data.len().try_into().unwrap(),
62+
fragment_buffer: data.as_mut_ptr().cast(),
63+
};
64+
let tcp6_frag = r_efi::protocols::tcp6::FragmentData {
65+
fragment_length: data.len().try_into().unwrap(),
66+
fragment_buffer: data.as_mut_ptr().cast(),
67+
};
68+
let udp4_frag = r_efi::protocols::udp4::FragmentData {
69+
fragment_length: data.len().try_into().unwrap(),
70+
fragment_buffer: data.as_mut_ptr().cast(),
71+
};
72+
let udp6_frag = r_efi::protocols::udp6::FragmentData {
73+
fragment_length: data.len().try_into().unwrap(),
74+
fragment_buffer: data.as_mut_ptr().cast(),
75+
};
76+
let io_slice = IoSlice::new(&data);
77+
78+
assert_eq!(to_slice(&io_slice), to_slice(&tcp4_frag));
79+
assert_eq!(to_slice(&io_slice), to_slice(&tcp6_frag));
80+
assert_eq!(to_slice(&io_slice), to_slice(&udp4_frag));
81+
assert_eq!(to_slice(&io_slice), to_slice(&udp6_frag));
82+
}
83+
84+
#[test]
85+
fn io_slice_mut_single() {
86+
let mut data = [0, 1, 2, 3, 4];
87+
88+
let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
89+
fragment_length: data.len().try_into().unwrap(),
90+
fragment_buffer: data.as_mut_ptr().cast(),
91+
};
92+
let tcp6_frag = r_efi::protocols::tcp6::FragmentData {
93+
fragment_length: data.len().try_into().unwrap(),
94+
fragment_buffer: data.as_mut_ptr().cast(),
95+
};
96+
let udp4_frag = r_efi::protocols::udp4::FragmentData {
97+
fragment_length: data.len().try_into().unwrap(),
98+
fragment_buffer: data.as_mut_ptr().cast(),
99+
};
100+
let udp6_frag = r_efi::protocols::udp6::FragmentData {
101+
fragment_length: data.len().try_into().unwrap(),
102+
fragment_buffer: data.as_mut_ptr().cast(),
103+
};
104+
let io_slice_mut = IoSliceMut::new(&mut data);
105+
106+
assert_eq!(to_slice(&io_slice_mut), to_slice(&tcp4_frag));
107+
assert_eq!(to_slice(&io_slice_mut), to_slice(&tcp6_frag));
108+
assert_eq!(to_slice(&io_slice_mut), to_slice(&udp4_frag));
109+
assert_eq!(to_slice(&io_slice_mut), to_slice(&udp6_frag));
110+
}
111+
112+
#[test]
113+
fn io_slice_multi() {
114+
let mut data = [0, 1, 2, 3, 4];
115+
116+
let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
117+
fragment_length: data.len().try_into().unwrap(),
118+
fragment_buffer: data.as_mut_ptr().cast(),
119+
};
120+
let rhs =
121+
[tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag];
122+
let lhs = [
123+
IoSlice::new(&data),
124+
IoSlice::new(&data),
125+
IoSlice::new(&data),
126+
IoSlice::new(&data),
127+
IoSlice::new(&data),
128+
];
129+
130+
assert_eq!(to_slice(&lhs), to_slice(&rhs));
131+
}

0 commit comments

Comments
 (0)