diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index d76e3e576f330..db2d18646d026 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -69,12 +69,11 @@ impl TcpStream { } pub fn read_vectored(&self, buf: &mut [IoSliceMut<'_>]) -> io::Result { - // FIXME: UEFI does support vectored read, so implement that. - crate::io::default_read_vectored(|b| self.read(b), buf) + self.inner.read_vectored(buf, self.read_timeout()?) } pub fn is_read_vectored(&self) -> bool { - false + true } pub fn write(&self, buf: &[u8]) -> io::Result { diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 16283e64fb35a..1e7e829c85f35 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -1,5 +1,5 @@ use super::tcp4; -use crate::io::{self, IoSlice}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::SocketAddr; use crate::ptr::NonNull; use crate::sys::{helpers, unsupported}; @@ -44,6 +44,16 @@ impl Tcp { } } + pub(crate) fn read_vectored( + &self, + buf: &mut [IoSliceMut<'_>], + timeout: Option, + ) -> io::Result { + match self { + Self::V4(client) => client.read_vectored(buf, timeout), + } + } + pub(crate) fn ttl(&self) -> io::Result { match self { Self::V4(client) => client.get_mode_data().map(|x| x.time_to_live.into()), diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs index ba0424454d738..0409997f02721 100644 --- a/library/std/src/sys/net/connection/uefi/tcp4.rs +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -1,7 +1,7 @@ use r_efi::efi::{self, Status}; use r_efi::protocols::tcp4; -use crate::io::{self, IoSlice}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::SocketAddrV4; use crate::ptr::NonNull; use crate::sync::atomic::{AtomicBool, Ordering}; @@ -193,30 +193,74 @@ impl Tcp4 { } pub(crate) fn read(&self, buf: &mut [u8], timeout: Option) -> io::Result { - let evt = unsafe { self.create_evt() }?; - let completion_token = - tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; let data_len = u32::try_from(buf.len()).unwrap_or(u32::MAX); let fragment = tcp4::FragmentData { fragment_length: data_len, fragment_buffer: buf.as_mut_ptr().cast::(), }; - let mut tx_data = tcp4::ReceiveData { + let mut rx_data = tcp4::ReceiveData { urgent_flag: r_efi::efi::Boolean::FALSE, data_length: data_len, fragment_count: 1, fragment_table: [fragment], }; - let protocol = self.protocol.as_ptr(); - let mut token = tcp4::IoToken { - completion_token, - packet: tcp4::IoTokenPacket { - rx_data: (&raw mut tx_data).cast::>(), - }, + self.read_inner((&raw mut rx_data).cast(), timeout).map(|_| data_len as usize) + } + + pub(crate) fn read_vectored( + &self, + buf: &[IoSliceMut<'_>], + timeout: Option, + ) -> io::Result { + let mut data_length = 0u32; + let mut fragment_count = 0u32; + + // Calculate how many IoSlice in buf can be transmitted. + for i in buf { + // IoSlice length is always <= u32::MAX in UEFI. + match data_length.checked_add(u32::try_from(i.len()).expect("value is stored as a u32")) + { + Some(x) => data_length = x, + None => break, + } + fragment_count += 1; + } + + let rx_data_size = size_of::>() + + size_of::() * (fragment_count as usize); + let mut rx_data = helpers::UefiBox::::new(rx_data_size)?; + rx_data.write(tcp4::ReceiveData { + urgent_flag: r_efi::efi::Boolean::FALSE, + data_length, + fragment_count, + fragment_table: [], + }); + unsafe { + // SAFETY: IoSlice and FragmentData are guaranteed to have same layout. + crate::ptr::copy_nonoverlapping( + buf.as_ptr().cast(), + (*rx_data.as_mut_ptr()).fragment_table.as_mut_ptr(), + fragment_count as usize, + ); }; + self.read_inner(rx_data.as_mut_ptr(), timeout).map(|_| data_length as usize) + } + + pub(crate) fn read_inner( + &self, + rx_data: *mut tcp4::ReceiveData, + timeout: Option, + ) -> io::Result<()> { + let evt = unsafe { self.create_evt() }?; + let completion_token = + tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; + + let protocol = self.protocol.as_ptr(); + let mut token = tcp4::IoToken { completion_token, packet: tcp4::IoTokenPacket { rx_data } }; + let r = unsafe { ((*protocol).receive)(protocol, &mut token) }; if r.is_error() { return Err(io::Error::from_raw_os_error(r.as_usize())); @@ -227,7 +271,7 @@ impl Tcp4 { if completion_token.status.is_error() { Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) } else { - Ok(data_len as usize) + Ok(()) } }