Skip to content

Commit 6e75abd

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 e1b9081 commit 6e75abd

File tree

3 files changed

+196
-0
lines changed

3 files changed

+196
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
self.len = u32::try_from(n)
25+
.ok()
26+
.and_then(|n| self.len.checked_sub(n))
27+
.expect("advancing IoSlice beyond its length");
28+
unsafe { self.data = self.data.add(n) };
29+
}
30+
31+
#[inline]
32+
pub const fn as_slice(&self) -> &'a [u8] {
33+
unsafe { slice::from_raw_parts(self.data, self.len as usize) }
34+
}
35+
}
36+
37+
#[repr(C)]
38+
pub struct IoSliceMut<'a> {
39+
len: u32,
40+
data: *mut u8,
41+
_p: PhantomData<&'a mut [u8]>,
42+
}
43+
44+
impl<'a> IoSliceMut<'a> {
45+
#[inline]
46+
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
47+
let len = buf.len().try_into().unwrap();
48+
Self { len, data: buf.as_mut_ptr(), _p: PhantomData }
49+
}
50+
51+
#[inline]
52+
pub fn advance(&mut self, n: usize) {
53+
self.len = u32::try_from(n)
54+
.ok()
55+
.and_then(|n| self.len.checked_sub(n))
56+
.expect("advancing IoSlice beyond its length");
57+
unsafe { self.data = self.data.add(n) };
58+
}
59+
60+
#[inline]
61+
pub fn as_slice(&self) -> &[u8] {
62+
unsafe { slice::from_raw_parts(self.data, self.len as usize) }
63+
}
64+
65+
#[inline]
66+
pub const fn into_slice(self) -> &'a mut [u8] {
67+
unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) }
68+
}
69+
70+
#[inline]
71+
pub fn as_mut_slice(&mut self) -> &mut [u8] {
72+
unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) }
73+
}
74+
}

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: 119 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,121 @@ 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+
unsafe 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+
unsafe {
79+
assert_eq!(to_slice(&io_slice), to_slice(&tcp4_frag));
80+
assert_eq!(to_slice(&io_slice), to_slice(&tcp6_frag));
81+
assert_eq!(to_slice(&io_slice), to_slice(&udp4_frag));
82+
assert_eq!(to_slice(&io_slice), to_slice(&udp6_frag));
83+
}
84+
}
85+
86+
#[test]
87+
fn io_slice_mut_single() {
88+
let mut data = [0, 1, 2, 3, 4];
89+
90+
let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
91+
fragment_length: data.len().try_into().unwrap(),
92+
fragment_buffer: data.as_mut_ptr().cast(),
93+
};
94+
let tcp6_frag = r_efi::protocols::tcp6::FragmentData {
95+
fragment_length: data.len().try_into().unwrap(),
96+
fragment_buffer: data.as_mut_ptr().cast(),
97+
};
98+
let udp4_frag = r_efi::protocols::udp4::FragmentData {
99+
fragment_length: data.len().try_into().unwrap(),
100+
fragment_buffer: data.as_mut_ptr().cast(),
101+
};
102+
let udp6_frag = r_efi::protocols::udp6::FragmentData {
103+
fragment_length: data.len().try_into().unwrap(),
104+
fragment_buffer: data.as_mut_ptr().cast(),
105+
};
106+
let io_slice_mut = IoSliceMut::new(&mut data);
107+
108+
unsafe {
109+
assert_eq!(to_slice(&io_slice_mut), to_slice(&tcp4_frag));
110+
assert_eq!(to_slice(&io_slice_mut), to_slice(&tcp6_frag));
111+
assert_eq!(to_slice(&io_slice_mut), to_slice(&udp4_frag));
112+
assert_eq!(to_slice(&io_slice_mut), to_slice(&udp6_frag));
113+
}
114+
}
115+
116+
#[test]
117+
fn io_slice_multi() {
118+
let mut data = [0, 1, 2, 3, 4];
119+
120+
let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
121+
fragment_length: data.len().try_into().unwrap(),
122+
fragment_buffer: data.as_mut_ptr().cast(),
123+
};
124+
let rhs =
125+
[tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag];
126+
let lhs = [
127+
IoSlice::new(&data),
128+
IoSlice::new(&data),
129+
IoSlice::new(&data),
130+
IoSlice::new(&data),
131+
IoSlice::new(&data),
132+
];
133+
134+
unsafe {
135+
assert_eq!(to_slice(&lhs), to_slice(&rhs));
136+
}
137+
}
138+
139+
#[test]
140+
fn io_slice_basic() {
141+
let data = [0, 1, 2, 3, 4];
142+
let mut io_slice = IoSlice::new(&data);
143+
144+
assert_eq!(data, io_slice.as_slice());
145+
io_slice.advance(2);
146+
assert_eq!(&data[2..], io_slice.as_slice());
147+
}
148+
149+
#[test]
150+
fn io_slice_mut_basic() {
151+
let data = [0, 1, 2, 3, 4];
152+
let mut data_clone = [0, 1, 2, 3, 4];
153+
let mut io_slice_mut = IoSliceMut::new(&mut data_clone);
154+
155+
assert_eq!(data, io_slice_mut.as_slice());
156+
assert_eq!(data, io_slice_mut.as_mut_slice());
157+
158+
io_slice_mut.advance(2);
159+
assert_eq!(&data[2..], io_slice_mut.into_slice());
160+
}

0 commit comments

Comments
 (0)