From a1139d052c7d7e72530b700d68f804da0fecf616 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Wed, 11 Oct 2023 09:36:03 +0000 Subject: [PATCH 01/12] crates/sel4-shared-ring-buffer: Improve robustness in the face of malicious peers - Rework ring buffer API to only expose good peer behavior - Add sel4-shared-ring-buffer-bookkeeping crate And rename from crates/sel4-async/request-statuses Signed-off-by: Nick Spinale --- Cargo.lock | 17 +- Cargo.toml | 2 +- .../microkit/http-server/http-server.system | 2 - .../http-server/pds/server/Cargo.toml | 4 +- .../http-server/pds/server/src/handler.rs | 7 +- .../http-server/pds/server/src/main.rs | 72 ++-- .../pds/virtio-blk-driver/src/main.rs | 45 +-- .../pds/virtio-net-driver/src/main.rs | 67 ++-- crates/private/meta/Cargo.toml | 2 +- crates/private/meta/src/lib.rs | 2 +- crates/sel4-async/block-io/src/lib.rs | 5 + crates/sel4-async/request-statuses/Cargo.toml | 6 - crates/sel4-async/request-statuses/src/lib.rs | 108 ----- .../block-io/Cargo.toml | 2 +- .../block-io/src/errors.rs | 115 ++++++ .../block-io/src/lib.rs | 249 ++++++------ .../block-io/src/owned.rs | 378 ++++++++++++++++++ .../block-io/types/src/lib.rs | 12 + .../bookkeeping/Cargo.toml | 9 + .../bookkeeping/src/lib.rs | 11 + .../bookkeeping/src/slot_count_tracker.rs | 37 ++ .../bookkeeping/src/slot_set_semaphore.rs | 293 ++++++++++++++ .../bookkeeping/src/slot_tracker.rs | 237 +++++++++++ .../smoltcp/src/inner.rs | 69 ++-- .../smoltcp/src/lib.rs | 6 +- .../sel4-shared-ring-buffer/src/descriptor.rs | 60 +++ crates/sel4-shared-ring-buffer/src/lib.rs | 322 ++++++++++----- crates/sel4-shared-ring-buffer/src/roles.rs | 98 +++++ .../microkit/http-server/pds/server/crate.nix | 4 +- .../crates/private/meta/crate.nix | 2 +- .../sel4-async/request-statuses/crate.nix | 5 - .../crates/sel4-async/unsync/crate.nix | 2 +- .../block-io/crate.nix | 6 +- .../bookkeeping/crate.nix | 8 + .../generated-cargo-manifests/default.nix | 1 + 35 files changed, 1750 insertions(+), 515 deletions(-) delete mode 100644 crates/sel4-async/request-statuses/Cargo.toml delete mode 100644 crates/sel4-async/request-statuses/src/lib.rs create mode 100644 crates/sel4-shared-ring-buffer/block-io/src/errors.rs create mode 100644 crates/sel4-shared-ring-buffer/block-io/src/owned.rs create mode 100644 crates/sel4-shared-ring-buffer/bookkeeping/Cargo.toml create mode 100644 crates/sel4-shared-ring-buffer/bookkeeping/src/lib.rs create mode 100644 crates/sel4-shared-ring-buffer/bookkeeping/src/slot_count_tracker.rs create mode 100644 crates/sel4-shared-ring-buffer/bookkeeping/src/slot_set_semaphore.rs create mode 100644 crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs create mode 100644 crates/sel4-shared-ring-buffer/src/descriptor.rs create mode 100644 crates/sel4-shared-ring-buffer/src/roles.rs delete mode 100644 hacking/cargo-manifest-sources/crates/sel4-async/request-statuses/crate.nix create mode 100644 hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/bookkeeping/crate.nix diff --git a/Cargo.lock b/Cargo.lock index 2c4312960..348d6eb37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2444,7 +2444,6 @@ dependencies = [ "sel4-async-block-io-cpiofs", "sel4-async-block-io-fat", "sel4-async-network", - "sel4-async-request-statuses", "sel4-async-single-threaded-executor", "sel4-async-time", "sel4-async-unsync", @@ -2463,6 +2462,7 @@ dependencies = [ "sel4-shared-ring-buffer", "sel4-shared-ring-buffer-block-io", "sel4-shared-ring-buffer-block-io-types", + "sel4-shared-ring-buffer-bookkeeping", "sel4-shared-ring-buffer-smoltcp", "sel4-sync", "sel4-sys", @@ -2491,7 +2491,6 @@ dependencies = [ "sel4-async-block-io", "sel4-async-block-io-fat", "sel4-async-network", - "sel4-async-request-statuses", "sel4-async-single-threaded-executor", "sel4-async-time", "sel4-bounce-buffer-allocator", @@ -2504,6 +2503,7 @@ dependencies = [ "sel4-shared-ring-buffer", "sel4-shared-ring-buffer-block-io", "sel4-shared-ring-buffer-block-io-types", + "sel4-shared-ring-buffer-bookkeeping", "sel4-shared-ring-buffer-smoltcp", "sel4-sync", "smoltcp", @@ -3536,10 +3536,6 @@ dependencies = [ name = "sel4-async-network-mbedtls-mozilla-ca-list" version = "0.1.0" -[[package]] -name = "sel4-async-request-statuses" -version = "0.1.0" - [[package]] name = "sel4-async-single-threaded-executor" version = "0.1.0" @@ -4103,11 +4099,11 @@ dependencies = [ "futures", "log", "sel4-async-block-io", - "sel4-async-request-statuses", "sel4-bounce-buffer-allocator", "sel4-externally-shared", "sel4-shared-ring-buffer", "sel4-shared-ring-buffer-block-io-types", + "sel4-shared-ring-buffer-bookkeeping", ] [[package]] @@ -4119,6 +4115,13 @@ dependencies = [ "zerocopy 0.7.6", ] +[[package]] +name = "sel4-shared-ring-buffer-bookkeeping" +version = "0.1.0" +dependencies = [ + "async-unsync", +] + [[package]] name = "sel4-shared-ring-buffer-smoltcp" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index c78750ca0..f80176e24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,6 @@ members = [ "crates/sel4-async/network", "crates/sel4-async/network/mbedtls", "crates/sel4-async/network/mbedtls/mozilla-ca-list", - "crates/sel4-async/request-statuses", "crates/sel4-async/single-threaded-executor", "crates/sel4-async/time", "crates/sel4-async/unsync", @@ -108,6 +107,7 @@ members = [ "crates/sel4-shared-ring-buffer", "crates/sel4-shared-ring-buffer/block-io", "crates/sel4-shared-ring-buffer/block-io/types", + "crates/sel4-shared-ring-buffer/bookkeeping", "crates/sel4-shared-ring-buffer/smoltcp", "crates/sel4-sync", "crates/sel4/bitfield-ops", diff --git a/crates/examples/microkit/http-server/http-server.system b/crates/examples/microkit/http-server/http-server.system index 7f2970947..b41fb009e 100644 --- a/crates/examples/microkit/http-server/http-server.system +++ b/crates/examples/microkit/http-server/http-server.system @@ -57,7 +57,6 @@ - @@ -79,7 +78,6 @@ - diff --git a/crates/examples/microkit/http-server/pds/server/Cargo.toml b/crates/examples/microkit/http-server/pds/server/Cargo.toml index 30af0d520..c622bb692 100644 --- a/crates/examples/microkit/http-server/pds/server/Cargo.toml +++ b/crates/examples/microkit/http-server/pds/server/Cargo.toml @@ -14,7 +14,6 @@ sel4 = { path = "../../../../../sel4" } sel4-async-block-io = { path = "../../../../../sel4-async/block-io" } sel4-async-block-io-fat = { path = "../../../../../sel4-async/block-io/fat" } sel4-async-network = { path = "../../../../../sel4-async/network" } -sel4-async-request-statuses = { path = "../../../../../sel4-async/request-statuses" } sel4-async-time = { path = "../../../../../sel4-async/time" } sel4-bounce-buffer-allocator = { path = "../../../../../sel4-bounce-buffer-allocator" } sel4-immediate-sync-once-cell = { path = "../../../../../sel4-immediate-sync-once-cell" } @@ -53,6 +52,9 @@ features = ["nosys", "all-symbols", "sel4-panicking-env"] [dependencies.sel4-shared-ring-buffer-block-io-types] path = "../../../../../sel4-shared-ring-buffer/block-io/types" +[dependencies.sel4-shared-ring-buffer-bookkeeping] +path = "../../../../../sel4-shared-ring-buffer/bookkeeping" + [dependencies.smoltcp] version = "0.10.0" default-features = false diff --git a/crates/examples/microkit/http-server/pds/server/src/handler.rs b/crates/examples/microkit/http-server/pds/server/src/handler.rs index 79adf3ab5..ef6650717 100644 --- a/crates/examples/microkit/http-server/pds/server/src/handler.rs +++ b/crates/examples/microkit/http-server/pds/server/src/handler.rs @@ -12,6 +12,7 @@ use sel4_async_block_io::constant_block_sizes::BlockSize512; use sel4_async_network::{DhcpOverrides, ManagedInterface}; use sel4_async_single_threaded_executor::{LocalPool, LocalSpawner}; use sel4_async_time::{Instant, TimerManager}; +use sel4_bounce_buffer_allocator::Basic; use sel4_shared_ring_buffer_block_io::SharedRingBufferBlockIO; use crate::{DeviceImpl, TimerClient}; @@ -22,7 +23,7 @@ pub(crate) struct HandlerImpl { block_driver_channel: sel4_microkit::Channel, timer: TimerClient, net_device: DeviceImpl, - shared_block_io: SharedRingBufferBlockIO, + shared_block_io: SharedRingBufferBlockIO, shared_timers: TimerManager, shared_network: ManagedInterface, local_pool: LocalPool, @@ -38,7 +39,7 @@ impl HandlerImpl { timer: TimerClient, mut net_device: DeviceImpl, net_config: Config, - shared_block_io: SharedRingBufferBlockIO, + shared_block_io: SharedRingBufferBlockIO, f: impl FnOnce(TimerManager, ManagedInterface, LocalSpawner) -> T, ) -> Self { let now = Self::now_with_timer_client(&timer); @@ -103,7 +104,7 @@ impl HandlerImpl { activity |= self.shared_timers.poll(now); activity |= self.net_device.poll(); activity |= self.shared_network.poll(now_smoltcp, &mut self.net_device); - activity |= self.shared_block_io.poll(); + activity |= self.shared_block_io.poll().unwrap(); if !activity { let delays = &[ self.shared_timers.poll_at().map(|absolute| absolute - now), diff --git a/crates/examples/microkit/http-server/pds/server/src/main.rs b/crates/examples/microkit/http-server/pds/server/src/main.rs index aa09e98b7..258381edf 100644 --- a/crates/examples/microkit/http-server/pds/server/src/main.rs +++ b/crates/examples/microkit/http-server/pds/server/src/main.rs @@ -20,10 +20,11 @@ use smoltcp::wire::{EthernetAddress, HardwareAddress}; use sel4_async_block_io::{ constant_block_sizes::BlockSize512, disk::Disk, CachedBlockIO, ConstantBlockSize, }; +use sel4_bounce_buffer_allocator::{Basic, BounceBufferAllocator}; use sel4_externally_shared::ExternallySharedRef; use sel4_logging::{LevelFilter, Logger, LoggerBuilder}; use sel4_microkit::{memory_region_symbol, protection_domain, var, Channel, Handler}; -use sel4_shared_ring_buffer::{RingBuffer, RingBuffers}; +use sel4_shared_ring_buffer::RingBuffers; use sel4_shared_ring_buffer_block_io::SharedRingBufferBlockIO; use sel4_shared_ring_buffer_smoltcp::DeviceImpl; @@ -75,15 +76,8 @@ fn init() -> impl Handler { let net_client = NetClient::new(NET_DRIVER); let block_client = BlockClient::new(BLOCK_DRIVER); - let notify_net = || { - NET_DRIVER.notify(); - Ok::<_, !>(()) - }; - - let notify_block = || { - BLOCK_DRIVER.notify(); - Ok::<_, !>(()) - }; + let notify_net: fn() = || NET_DRIVER.notify(); + let notify_block: fn() = || BLOCK_DRIVER.notify(); let net_device = DeviceImpl::new( unsafe { @@ -92,22 +86,16 @@ fn init() -> impl Handler { ) }, *var!(virtio_net_client_dma_paddr: usize = 0), - unsafe { - RingBuffers::new( - RingBuffer::from_ptr(memory_region_symbol!(virtio_net_rx_free: *mut _)), - RingBuffer::from_ptr(memory_region_symbol!(virtio_net_rx_used: *mut _)), - notify_net, - true, - ) - }, - unsafe { - RingBuffers::new( - RingBuffer::from_ptr(memory_region_symbol!(virtio_net_tx_free: *mut _)), - RingBuffer::from_ptr(memory_region_symbol!(virtio_net_tx_used: *mut _)), - notify_net, - true, - ) - }, + RingBuffers::from_ptrs_using_default_initialization_strategy_for_role( + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_rx_free: *mut _)) }, + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_rx_used: *mut _)) }, + notify_net, + ), + RingBuffers::from_ptrs_using_default_initialization_strategy_for_role( + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_tx_free: *mut _)) }, + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_tx_used: *mut _)) }, + notify_net, + ), 16, 2048, 1500, @@ -124,24 +112,28 @@ fn init() -> impl Handler { let num_blocks = block_client.get_num_blocks(); - let shared_block_io = SharedRingBufferBlockIO::new( - BlockSize512::SINGLETON, - num_blocks, - unsafe { + let shared_block_io = { + let dma_region = unsafe { ExternallySharedRef::<'static, _>::new( memory_region_symbol!(virtio_blk_client_dma_vaddr: *mut [u8], n = *var!(virtio_blk_client_dma_size: usize = 0)), ) - }, - *var!(virtio_blk_client_dma_paddr: usize = 0), - unsafe { - RingBuffers::new( - RingBuffer::from_ptr(memory_region_symbol!(virtio_blk_free: *mut _)), - RingBuffer::from_ptr(memory_region_symbol!(virtio_blk_used: *mut _)), + }; + + let bounce_buffer_allocator = + BounceBufferAllocator::new(Basic::new(dma_region.as_ptr().len()), 1); + + SharedRingBufferBlockIO::new( + BlockSize512::SINGLETON, + num_blocks, + dma_region, + bounce_buffer_allocator, + RingBuffers::from_ptrs_using_default_initialization_strategy_for_role( + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_blk_free: *mut _)) }, + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_blk_used: *mut _)) }, notify_block, - true, - ) - }, - ); + ), + ) + }; HandlerImpl::new( TIMER_DRIVER, diff --git a/crates/examples/microkit/http-server/pds/virtio-blk-driver/src/main.rs b/crates/examples/microkit/http-server/pds/virtio-blk-driver/src/main.rs index 2113b481d..143a87aa9 100644 --- a/crates/examples/microkit/http-server/pds/virtio-blk-driver/src/main.rs +++ b/crates/examples/microkit/http-server/pds/virtio-blk-driver/src/main.rs @@ -20,7 +20,7 @@ use virtio_drivers::{ use sel4_externally_shared::ExternallySharedRef; use sel4_microkit::{memory_region_symbol, protection_domain, var, Channel, Handler, MessageInfo}; use sel4_microkit_message::MessageInfoExt as _; -use sel4_shared_ring_buffer::{RingBuffer, RingBuffers}; +use sel4_shared_ring_buffer::{roles::Use, RingBuffers}; use sel4_shared_ring_buffer_block_io_types::{ BlockIORequest, BlockIORequestStatus, BlockIORequestType, }; @@ -61,16 +61,14 @@ fn init() -> HandlerImpl { ) }; - let client_client_dma_region_paddr = *var!(virtio_blk_client_dma_paddr: usize = 0); + let notify_client: fn() = || CLIENT.notify(); - let ring_buffers = unsafe { - RingBuffers::<'_, fn() -> Result<(), !>, BlockIORequest>::new( - RingBuffer::from_ptr(memory_region_symbol!(virtio_blk_free: *mut _)), - RingBuffer::from_ptr(memory_region_symbol!(virtio_blk_used: *mut _)), + let ring_buffers = + RingBuffers::<'_, Use, fn(), BlockIORequest>::from_ptrs_using_default_initialization_strategy_for_role( + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_blk_free: *mut _)) }, + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_blk_used: *mut _)) }, notify_client, - true, - ) - }; + ); dev.ack_interrupt(); DEVICE.irq_ack().unwrap(); @@ -78,22 +76,15 @@ fn init() -> HandlerImpl { HandlerImpl { dev, client_region, - client_client_dma_region_paddr, ring_buffers, pending: BTreeMap::new(), } } -fn notify_client() -> Result<(), !> { - CLIENT.notify(); - Ok::<_, !>(()) -} - struct HandlerImpl { dev: VirtIOBlk, client_region: ExternallySharedRef<'static, [u8]>, - client_client_dma_region_paddr: usize, - ring_buffers: RingBuffers<'static, fn() -> Result<(), !>, BlockIORequest>, + ring_buffers: RingBuffers<'static, Use, fn(), BlockIORequest>, pending: BTreeMap>>, } @@ -115,8 +106,7 @@ impl Handler for HandlerImpl { let token = self.dev.peek_used().unwrap(); let mut pending_entry = self.pending.remove(&token).unwrap(); let buf_range = { - let start = pending_entry.client_req.buf().encoded_addr() - - self.client_client_dma_region_paddr; + let start = pending_entry.client_req.buf().encoded_addr(); let len = usize::try_from(pending_entry.client_req.buf().len()).unwrap(); start..start + len }; @@ -142,12 +132,18 @@ impl Handler for HandlerImpl { }; let mut completed_req = pending_entry.client_req; completed_req.set_status(status); - self.ring_buffers.used_mut().enqueue(completed_req).unwrap(); + self.ring_buffers + .used_mut() + .enqueue_and_commit(completed_req) + .unwrap() + .unwrap(); notify = true; } - while self.pending.len() < QUEUE_SIZE && !self.ring_buffers.free().is_empty() { - let client_req = self.ring_buffers.free_mut().dequeue().unwrap(); + while self.pending.len() < QUEUE_SIZE + && !self.ring_buffers.free_mut().is_empty().unwrap() + { + let client_req = self.ring_buffers.free_mut().dequeue().unwrap().unwrap(); assert_eq!(client_req.ty().unwrap(), BlockIORequestType::Read); let mut pending_entry = Box::pin(PendingEntry { client_req, @@ -155,8 +151,7 @@ impl Handler for HandlerImpl { virtio_resp: BlkResp::default(), }); let buf_range = { - let start = - client_req.buf().encoded_addr() - self.client_client_dma_region_paddr; + let start = client_req.buf().encoded_addr(); let len = usize::try_from(client_req.buf().len()).unwrap(); start..start + len }; @@ -186,7 +181,7 @@ impl Handler for HandlerImpl { } if notify { - self.ring_buffers.notify().unwrap(); + self.ring_buffers.notify(); } self.dev.ack_interrupt(); diff --git a/crates/examples/microkit/http-server/pds/virtio-net-driver/src/main.rs b/crates/examples/microkit/http-server/pds/virtio-net-driver/src/main.rs index 6a0be2bc2..5c752b8fb 100644 --- a/crates/examples/microkit/http-server/pds/virtio-net-driver/src/main.rs +++ b/crates/examples/microkit/http-server/pds/virtio-net-driver/src/main.rs @@ -15,7 +15,7 @@ use virtio_drivers::{ use sel4_externally_shared::ExternallySharedRef; use sel4_microkit::{memory_region_symbol, protection_domain, var, Channel, Handler, MessageInfo}; use sel4_microkit_message::MessageInfoExt as _; -use sel4_shared_ring_buffer::{RingBuffer, RingBuffers}; +use sel4_shared_ring_buffer::{roles::Use, RingBuffers}; use microkit_http_server_example_virtio_hal_impl::HalImpl; use microkit_http_server_example_virtio_net_driver_interface_types::*; @@ -53,25 +53,21 @@ fn init() -> HandlerImpl { ) }; - let client_client_dma_region_paddr = *var!(virtio_net_client_dma_paddr: usize = 0); + let notify_client: fn() = || CLIENT.notify(); - let rx_ring_buffers = unsafe { - RingBuffers::<'_, fn() -> Result<(), !>>::new( - RingBuffer::from_ptr(memory_region_symbol!(virtio_net_rx_free: *mut _)), - RingBuffer::from_ptr(memory_region_symbol!(virtio_net_rx_used: *mut _)), + let rx_ring_buffers = + RingBuffers::<'_, Use, fn()>::from_ptrs_using_default_initialization_strategy_for_role( + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_rx_free: *mut _)) }, + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_rx_used: *mut _)) }, notify_client, - true, - ) - }; + ); - let tx_ring_buffers = unsafe { - RingBuffers::<'_, fn() -> Result<(), !>>::new( - RingBuffer::from_ptr(memory_region_symbol!(virtio_net_tx_free: *mut _)), - RingBuffer::from_ptr(memory_region_symbol!(virtio_net_tx_used: *mut _)), + let tx_ring_buffers = + RingBuffers::<'_, Use, fn()>::from_ptrs_using_default_initialization_strategy_for_role( + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_tx_free: *mut _)) }, + unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_tx_used: *mut _)) }, notify_client, - true, - ) - }; + ); dev.ack_interrupt(); DEVICE.irq_ack().unwrap(); @@ -79,23 +75,16 @@ fn init() -> HandlerImpl { HandlerImpl { dev, client_region, - client_client_dma_region_paddr, rx_ring_buffers, tx_ring_buffers, } } -fn notify_client() -> Result<(), !> { - CLIENT.notify(); - Ok::<_, !>(()) -} - struct HandlerImpl { dev: VirtIONet, client_region: ExternallySharedRef<'static, [u8]>, - client_client_dma_region_paddr: usize, - rx_ring_buffers: RingBuffers<'static, fn() -> Result<(), !>>, - tx_ring_buffers: RingBuffers<'static, fn() -> Result<(), !>>, + rx_ring_buffers: RingBuffers<'static, Use, fn()>, + tx_ring_buffers: RingBuffers<'static, Use, fn()>, } impl Handler for HandlerImpl { @@ -106,13 +95,13 @@ impl Handler for HandlerImpl { DEVICE | CLIENT => { let mut notify_rx = false; - while self.dev.can_recv() && !self.rx_ring_buffers.free().is_empty() { + while self.dev.can_recv() && !self.rx_ring_buffers.free_mut().is_empty().unwrap() { let rx_buf = self.dev.receive().unwrap(); - let desc = self.rx_ring_buffers.free_mut().dequeue().unwrap(); + let desc = self.rx_ring_buffers.free_mut().dequeue().unwrap().unwrap(); let desc_len = usize::try_from(desc.len()).unwrap(); assert!(desc_len >= rx_buf.packet_len()); let buf_range = { - let start = desc.encoded_addr() - self.client_client_dma_region_paddr; + let start = desc.encoded_addr(); start..start + rx_buf.packet_len() }; self.client_region @@ -120,20 +109,24 @@ impl Handler for HandlerImpl { .index(buf_range) .copy_from_slice(rx_buf.packet()); self.dev.recycle_rx_buffer(rx_buf).unwrap(); - self.rx_ring_buffers.used_mut().enqueue(desc).unwrap(); + self.rx_ring_buffers + .used_mut() + .enqueue_and_commit(desc) + .unwrap() + .unwrap(); notify_rx = true; } if notify_rx { - self.rx_ring_buffers.notify().unwrap(); + self.rx_ring_buffers.notify(); } let mut notify_tx = false; - while !self.tx_ring_buffers.free().is_empty() && self.dev.can_send() { - let desc = self.tx_ring_buffers.free_mut().dequeue().unwrap(); + while !self.tx_ring_buffers.free_mut().is_empty().unwrap() && self.dev.can_send() { + let desc = self.tx_ring_buffers.free_mut().dequeue().unwrap().unwrap(); let buf_range = { - let start = desc.encoded_addr() - self.client_client_dma_region_paddr; + let start = desc.encoded_addr(); start..start + usize::try_from(desc.len()).unwrap() }; let mut tx_buf = self.dev.new_tx_buffer(buf_range.len()); @@ -142,12 +135,16 @@ impl Handler for HandlerImpl { .index(buf_range) .copy_into_slice(tx_buf.packet_mut()); self.dev.send(tx_buf).unwrap(); - self.tx_ring_buffers.used_mut().enqueue(desc).unwrap(); + self.tx_ring_buffers + .used_mut() + .enqueue_and_commit(desc) + .unwrap() + .unwrap(); notify_tx = true; } if notify_tx { - self.tx_ring_buffers.notify().unwrap(); + self.tx_ring_buffers.notify(); } self.dev.ack_interrupt(); diff --git a/crates/private/meta/Cargo.toml b/crates/private/meta/Cargo.toml index 10b8cf81a..edccbb015 100644 --- a/crates/private/meta/Cargo.toml +++ b/crates/private/meta/Cargo.toml @@ -17,7 +17,6 @@ sel4-async-block-io = { path = "../../sel4-async/block-io" } sel4-async-block-io-cpiofs = { path = "../../sel4-async/block-io/cpiofs" } sel4-async-block-io-fat = { path = "../../sel4-async/block-io/fat" } sel4-async-network = { path = "../../sel4-async/network" } -sel4-async-request-statuses = { path = "../../sel4-async/request-statuses" } sel4-async-single-threaded-executor = { path = "../../sel4-async/single-threaded-executor" } sel4-async-time = { path = "../../sel4-async/time" } sel4-async-unsync = { path = "../../sel4-async/unsync" } @@ -34,6 +33,7 @@ sel4-root-task = { path = "../../sel4-root-task", features = ["full"], optional sel4-shared-ring-buffer = { path = "../../sel4-shared-ring-buffer" } sel4-shared-ring-buffer-block-io = { path = "../../sel4-shared-ring-buffer/block-io" } sel4-shared-ring-buffer-block-io-types = { path = "../../sel4-shared-ring-buffer/block-io/types" } +sel4-shared-ring-buffer-bookkeeping = { path = "../../sel4-shared-ring-buffer/bookkeeping" } sel4-shared-ring-buffer-smoltcp = { path = "../../sel4-shared-ring-buffer/smoltcp" } sel4-sync = { path = "../../sel4-sync" } sel4-sys = { path = "../../sel4/sys" } diff --git a/crates/private/meta/src/lib.rs b/crates/private/meta/src/lib.rs index 9244850b0..338a4960d 100644 --- a/crates/private/meta/src/lib.rs +++ b/crates/private/meta/src/lib.rs @@ -78,7 +78,6 @@ definitely! { sel4_async_block_io_cpiofs sel4_async_block_io_fat sel4_async_network - sel4_async_request_statuses sel4_async_single_threaded_executor sel4_async_time sel4_async_unsync @@ -92,6 +91,7 @@ definitely! { sel4_shared_ring_buffer sel4_shared_ring_buffer_block_io sel4_shared_ring_buffer_block_io_types + sel4_shared_ring_buffer_bookkeeping sel4_shared_ring_buffer_smoltcp sel4_sync sel4_sys diff --git a/crates/sel4-async/block-io/src/lib.rs b/crates/sel4-async/block-io/src/lib.rs index 720965c7a..34d0c0df2 100644 --- a/crates/sel4-async/block-io/src/lib.rs +++ b/crates/sel4-async/block-io/src/lib.rs @@ -32,6 +32,11 @@ pub trait BlockIO { fn num_blocks(&self) -> u64; async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error>; + + // TODO + async fn write_blocks(&self, _start_block_idx: u64, _buf: &[u8]) -> Result<(), Self::Error> { + unimplemented!() + } } pub trait BlockSize { diff --git a/crates/sel4-async/request-statuses/Cargo.toml b/crates/sel4-async/request-statuses/Cargo.toml deleted file mode 100644 index 834f760dc..000000000 --- a/crates/sel4-async/request-statuses/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "sel4-async-request-statuses" -version = "0.1.0" -authors = ["Nick Spinale "] -edition = "2021" -license = "BSD-2-Clause" diff --git a/crates/sel4-async/request-statuses/src/lib.rs b/crates/sel4-async/request-statuses/src/lib.rs deleted file mode 100644 index 69ea498ff..000000000 --- a/crates/sel4-async/request-statuses/src/lib.rs +++ /dev/null @@ -1,108 +0,0 @@ -#![no_std] -#![feature(map_try_insert)] - -extern crate alloc; - -use alloc::collections::BTreeMap; -use core::mem; -use core::task::{Poll, Waker}; - -pub struct RequestStatuses(BTreeMap>); - -struct RequestEntry { - value: V, - status: RequestStatus, -} - -enum RequestStatus { - Complete(T), - Incomplete(Option), -} - -pub struct Completion { - pub key: K, - pub value: V, - pub complete: T, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum Error { - NotPresent, - AlreadyPresent, - AlreadyComplete, -} - -impl RequestStatuses { - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self(BTreeMap::new()) - } - - pub fn add(&mut self, key: K, value: V) -> Result<(), Error> { - self.0 - .try_insert( - key, - RequestEntry { - value, - status: RequestStatus::Incomplete(None), - }, - ) - .map(|_| ()) - .map_err(|_| Error::AlreadyPresent) - } - - pub fn get(&mut self, key: &K) -> Option<&V> { - self.0.get(key).map(|entry| &entry.value) - } - - pub fn mark_complete(&mut self, key: &K, complete: T) -> Result<(), Error> { - self.0 - .get_mut(key) - .ok_or(Error::NotPresent)? - .status - .mark_complete(complete) - } - - pub fn poll(&mut self, key: &K, waker: &Waker) -> Result>, Error> { - let (key, entry) = self.0.remove_entry(key).ok_or(Error::NotPresent)?; - let value = entry.value; - Ok(match entry.status { - RequestStatus::Complete(complete) => Poll::Ready(Completion { - key, - value, - complete, - }), - RequestStatus::Incomplete(_) => { - self.0.insert( - key, - RequestEntry { - value, - status: RequestStatus::Incomplete(Some(waker.clone())), - }, - ); - Poll::Pending - } - }) - } -} - -impl RequestStatus { - fn mark_complete(&mut self, complete: T) -> Result<(), Error> { - match mem::replace(self, Self::Complete(complete)) { - Self::Complete(_) => Err(Error::AlreadyComplete), - Self::Incomplete(maybe_waker) => { - if let Some(waker) = maybe_waker { - waker.wake(); - } - Ok(()) - } - } - } - - // fn set_waker(&mut self, waker: &Waker) -> Result<(), Error> { - // match mem::replace(self, Self::Incomplete(Some(waker.clone()))) { - // Self::Complete(_) => Err(Error::AlreadyComplete), - // _ => Ok(()), - // } - // } -} diff --git a/crates/sel4-shared-ring-buffer/block-io/Cargo.toml b/crates/sel4-shared-ring-buffer/block-io/Cargo.toml index 83923fcaa..b43a9692c 100644 --- a/crates/sel4-shared-ring-buffer/block-io/Cargo.toml +++ b/crates/sel4-shared-ring-buffer/block-io/Cargo.toml @@ -10,8 +10,8 @@ async-unsync = { version = "0.2.2", default-features = false } futures = { version = "0.3.28", default-features = false, features = ["async-await", "alloc"] } log = "0.4.17" sel4-async-block-io = { path = "../../sel4-async/block-io" } -sel4-async-request-statuses = { path = "../../sel4-async/request-statuses" } sel4-bounce-buffer-allocator = { path = "../../sel4-bounce-buffer-allocator" } sel4-externally-shared = { path = "../../sel4-externally-shared", features = ["unstable"] } sel4-shared-ring-buffer = { path = ".." } sel4-shared-ring-buffer-block-io-types = { path = "./types" } +sel4-shared-ring-buffer-bookkeeping = { path = "../bookkeeping", features = ["async-unsync"] } diff --git a/crates/sel4-shared-ring-buffer/block-io/src/errors.rs b/crates/sel4-shared-ring-buffer/block-io/src/errors.rs new file mode 100644 index 000000000..dc0bf3820 --- /dev/null +++ b/crates/sel4-shared-ring-buffer/block-io/src/errors.rs @@ -0,0 +1,115 @@ +use sel4_shared_ring_buffer::PeerMisbehaviorError as SharedRingBuffersPeerMisbehaviorError; +use sel4_shared_ring_buffer_bookkeeping::slot_tracker::SlotTrackerError; + +#[derive(Debug, Clone)] +pub enum ErrorOrUserError { + Error(Error), + UserError(UserError), +} + +#[derive(Debug, Clone)] +pub enum UserError { + InvalidRequestIndex, + RequestStateMismatch, + TooManyOutstandingRequests, +} + +#[derive(Debug, Clone)] +pub enum Error { + IOError(IOError), + BounceBufferAllocationError, + PeerMisbehaviorError(PeerMisbehaviorError), +} + +#[derive(Debug, Clone)] +pub struct IOError; + +#[derive(Debug, Clone)] +pub enum PeerMisbehaviorError { + InvalidDescriptor, + DescriptorMismatch, + OutOfBoundsCookie, + StateMismatch, + SharedRingBuffersPeerMisbehaviorError(SharedRingBuffersPeerMisbehaviorError), +} + +impl ErrorOrUserError { + pub fn unwrap_error(self) -> Error { + match self { + Self::Error(err) => err, + Self::UserError(err) => panic!( + "called `ErrorOrUserError::unwrap_error()` on an `UserError` value: {:?}", + err + ), + } + } +} + +impl From for ErrorOrUserError { + fn from(err: Error) -> Self { + Self::Error(err) + } +} + +impl From for ErrorOrUserError { + fn from(err: UserError) -> Self { + Self::UserError(err) + } +} + +impl From for Error { + fn from(err: IOError) -> Self { + Self::IOError(err) + } +} + +impl From for ErrorOrUserError { + fn from(err: IOError) -> Self { + Error::from(err).into() + } +} + +impl From for Error { + fn from(err: PeerMisbehaviorError) -> Self { + Self::PeerMisbehaviorError(err) + } +} + +impl From for ErrorOrUserError { + fn from(err: PeerMisbehaviorError) -> Self { + Error::from(err).into() + } +} + +impl From for PeerMisbehaviorError { + fn from(err: SharedRingBuffersPeerMisbehaviorError) -> Self { + Self::SharedRingBuffersPeerMisbehaviorError(err) + } +} + +impl From for Error { + fn from(err: SharedRingBuffersPeerMisbehaviorError) -> Self { + PeerMisbehaviorError::from(err).into() + } +} + +impl From for ErrorOrUserError { + fn from(err: SharedRingBuffersPeerMisbehaviorError) -> Self { + Error::from(err).into() + } +} + +impl From for UserError { + fn from(err: SlotTrackerError) -> Self { + match err { + SlotTrackerError::OutOfBounds => UserError::InvalidRequestIndex, + SlotTrackerError::StateMismatch => UserError::RequestStateMismatch, + } + } +} + +impl From for ErrorOrUserError { + fn from(err: SlotTrackerError) -> Self { + UserError::from(err).into() + } +} diff --git a/crates/sel4-shared-ring-buffer/block-io/src/lib.rs b/crates/sel4-shared-ring-buffer/block-io/src/lib.rs index a4e65e825..ee77040fa 100644 --- a/crates/sel4-shared-ring-buffer/block-io/src/lib.rs +++ b/crates/sel4-shared-ring-buffer/block-io/src/lib.rs @@ -1,176 +1,183 @@ #![no_std] #![feature(async_fn_in_trait)] -#![feature(never_type)] -#![feature(strict_provenance)] +#![feature(return_position_impl_trait_in_trait)] #![allow(clippy::useless_conversion)] extern crate alloc; use alloc::rc::Rc; -use core::alloc::Layout; use core::cell::RefCell; -use core::task::{ready, Poll}; +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; use async_unsync::semaphore::Semaphore; -use futures::prelude::*; use sel4_async_block_io::{BlockIO, BlockSize}; -use sel4_async_request_statuses::RequestStatuses; -use sel4_bounce_buffer_allocator::{Basic, BounceBufferAllocator}; +use sel4_bounce_buffer_allocator::{AbstractBounceBufferAllocator, BounceBufferAllocator}; use sel4_externally_shared::ExternallySharedRef; -use sel4_shared_ring_buffer::{ - Descriptor, Error as SharedRingBuffersError, RingBuffers, RING_BUFFER_SIZE, -}; -use sel4_shared_ring_buffer_block_io_types::{ - BlockIORequest, BlockIORequestStatus, BlockIORequestType, -}; +use sel4_shared_ring_buffer::{roles::Provide, RingBuffers}; +use sel4_shared_ring_buffer_block_io_types::BlockIORequest; -// TODO clean up dropped requests +mod errors; +mod owned; -pub const BLOCK_SIZE: usize = 512; +pub use errors::{Error, ErrorOrUserError, IOError, PeerMisbehaviorError, UserError}; +pub use owned::{IssueRequestBuf, OwnedSharedRingBufferBlockIO, PollRequestBuf, RequestBuf}; -#[derive(Clone)] -pub struct SharedRingBufferBlockIO { - shared_inner: Rc>>, +pub struct SharedRingBufferBlockIO { + shared: Rc>>, } -type EncodedAddr = usize; - -struct Inner { +struct Inner { + owned: OwnedSharedRingBufferBlockIO, A, F>, block_size: N, num_blocks: u64, - dma_region: ExternallySharedRef<'static, [u8]>, - dma_region_paddr: usize, - bounce_buffer_allocator: BounceBufferAllocator, - ring_buffers: RingBuffers<'static, fn() -> Result<(), !>, BlockIORequest>, - request_statuses: RequestStatuses, - queue_guard: Rc, } -impl SharedRingBufferBlockIO { +impl SharedRingBufferBlockIO { pub fn new( block_size: N, num_blocks: u64, dma_region: ExternallySharedRef<'static, [u8]>, - dma_region_paddr: usize, - ring_buffers: RingBuffers<'static, fn() -> Result<(), !>, BlockIORequest>, + bounce_buffer_allocator: BounceBufferAllocator, + ring_buffers: RingBuffers<'static, Provide, F, BlockIORequest>, ) -> Self { - let max_alignment = 1 - << dma_region - .as_ptr() - .as_raw_ptr() - .addr() - .trailing_zeros() - .min(dma_region_paddr.trailing_zeros()); - - let bounce_buffer_allocator = - BounceBufferAllocator::new(Basic::new(dma_region.as_ptr().len()), max_alignment); - Self { - shared_inner: Rc::new(RefCell::new(Inner { + shared: Rc::new(RefCell::new(Inner { + owned: OwnedSharedRingBufferBlockIO::new( + dma_region, + bounce_buffer_allocator, + ring_buffers, + ), block_size, num_blocks, - dma_region, - dma_region_paddr, - bounce_buffer_allocator, - ring_buffers, - request_statuses: RequestStatuses::new(), - queue_guard: Rc::new(Semaphore::new(RING_BUFFER_SIZE)), })), } } -} - -impl SharedRingBufferBlockIO { - pub fn poll(&self) -> bool { - let mut inner = self.shared_inner.borrow_mut(); - let mut notify = false; + pub fn poll(&self) -> Result { + self.shared + .borrow_mut() + .owned + .poll() + .map_err(ErrorOrUserError::unwrap_error) + } - while let Ok(mut completed_req) = inner - .ring_buffers - .used_mut() - .dequeue() - .map_err(|err| assert_eq!(err, SharedRingBuffersError::RingIsEmpty)) - { - let status = completed_req.status().unwrap(); - let key = completed_req.buf().encoded_addr() - inner.dma_region_paddr; - completed_req.set_status(BlockIORequestStatus::Pending); - let expected_req = completed_req; - let actual_req = inner.request_statuses.get(&key).unwrap(); - assert_eq!(&expected_req, actual_req); - inner.request_statuses.mark_complete(&key, status).unwrap(); - notify = true; + async fn request<'a>( + &'a self, + start_block_idx: u64, + mut request_buf: RequestBuf<'a>, + ) -> Result<(), Error> { + let request_index = { + let sem = self.shared.borrow().owned.slot_set_semaphore().clone(); + let mut reservation = sem.reserve(1).await.unwrap(); + self.shared + .borrow_mut() + .owned + .issue_request( + &mut reservation, + start_block_idx, + &mut request_buf.issue_request_buf(), + ) + .map_err(ErrorOrUserError::unwrap_error)? + }; + RequestFuture { + io: self, + request_buf, + request_index, + poll_returned_ready: false, } + .await + } +} - if notify { - inner.ring_buffers.notify().unwrap(); +impl Clone for SharedRingBufferBlockIO { + fn clone(&self) -> Self { + Self { + shared: self.shared.clone(), } - - notify } } -impl BlockIO for SharedRingBufferBlockIO { - type Error = !; +impl BlockIO + for SharedRingBufferBlockIO +{ + type Error = Error; type BlockSize = N; fn block_size(&self) -> Self::BlockSize { - self.shared_inner.borrow().block_size + self.shared.borrow().block_size } fn num_blocks(&self) -> u64 { - self.shared_inner.borrow().num_blocks + self.shared.borrow().num_blocks } async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error> { - let sem = self.shared_inner.borrow().queue_guard.clone(); - let permit = sem.acquire().await; - - let key = { - let mut inner = self.shared_inner.borrow_mut(); - let range = inner - .bounce_buffer_allocator - .allocate(Layout::from_size_align(buf.len(), 1).unwrap()) - .unwrap(); - let key = range.start; - let req = BlockIORequest::new( - BlockIORequestStatus::Pending, - BlockIORequestType::Read, - start_block_idx.try_into().unwrap(), - Descriptor::new( - inner.dma_region_paddr + range.start, - range.len().try_into().unwrap(), - 0, - ), - ); - inner.request_statuses.add(key, req).unwrap(); - inner.ring_buffers.free_mut().enqueue(req).unwrap(); - inner.ring_buffers.notify().unwrap(); - key + self.request(start_block_idx, RequestBuf::Read { buf }) + .await + } + + async fn write_blocks(&self, start_block_idx: u64, buf: &[u8]) -> Result<(), Self::Error> { + self.request(start_block_idx, RequestBuf::Write { buf }) + .await + } +} + +pub struct RequestFuture<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> { + io: &'a SharedRingBufferBlockIO, + request_buf: RequestBuf<'a>, + request_index: usize, + poll_returned_ready: bool, +} + +impl<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> RequestFuture<'a, N, A, F> { + fn poll_inner<'b>(&'b mut self, cx: &mut Context<'_>) -> Poll> + where + 'a: 'b, + { + assert!(!self.poll_returned_ready); + let ret = match self + .io + .shared + .borrow_mut() + .owned + .poll_request( + self.request_index, + &mut self.request_buf.poll_request_buf(), + Some(cx.waker().clone()), + ) + .map_err(ErrorOrUserError::unwrap_error) + { + Ok(val) => val.map_err(Error::from), + Err(err) => Poll::Ready(Err(err)), }; + if ret.is_ready() { + self.poll_returned_ready = true; + } + ret + } +} + +impl<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> Future for RequestFuture<'a, N, A, F> { + type Output = Result<(), Error>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.poll_inner(cx) + } +} - future::poll_fn(|cx| { - let mut inner = self.shared_inner.borrow_mut(); - let completion = ready!(inner.request_statuses.poll(&key, cx.waker()).unwrap()); - assert_eq!(completion.complete, BlockIORequestStatus::Ok); - let req = completion.value; - let range_start = req.buf().encoded_addr() - inner.dma_region_paddr; - let range_end = range_start + usize::try_from(req.buf().len()).unwrap(); - let range = range_start..range_end; - inner - .dma_region - .as_mut_ptr() - .index(range.clone()) - .copy_into_slice(buf); - inner.bounce_buffer_allocator.deallocate(range); - Poll::Ready(()) - }) - .await; - - drop(permit); // explicit extent of scope - - Ok(()) +impl<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> Drop for RequestFuture<'a, N, A, F> { + fn drop(&mut self) { + if !self.poll_returned_ready { + self.io + .shared + .borrow_mut() + .owned + .cancel_request(self.request_index) + .unwrap(); + } } } diff --git a/crates/sel4-shared-ring-buffer/block-io/src/owned.rs b/crates/sel4-shared-ring-buffer/block-io/src/owned.rs new file mode 100644 index 000000000..159241ce6 --- /dev/null +++ b/crates/sel4-shared-ring-buffer/block-io/src/owned.rs @@ -0,0 +1,378 @@ +use core::alloc::Layout; +use core::task::{Poll, Waker}; + +use sel4_bounce_buffer_allocator::{AbstractBounceBufferAllocator, BounceBufferAllocator}; +use sel4_externally_shared::ExternallySharedRef; +use sel4_shared_ring_buffer::{ + roles::Provide, Descriptor, PeerMisbehaviorError as SharedRingBuffersPeerMisbehaviorError, + RingBuffers, +}; +use sel4_shared_ring_buffer_block_io_types::{ + BlockIORequest, BlockIORequestStatus, BlockIORequestType, +}; +use sel4_shared_ring_buffer_bookkeeping::{slot_set_semaphore::*, slot_tracker::*}; + +pub use crate::errors::{Error, ErrorOrUserError, IOError, PeerMisbehaviorError, UserError}; + +pub struct OwnedSharedRingBufferBlockIO { + dma_region: ExternallySharedRef<'static, [u8]>, + bounce_buffer_allocator: BounceBufferAllocator, + ring_buffers: RingBuffers<'static, Provide, F, BlockIORequest>, + requests: SlotTracker, + slot_set_semaphore: SlotSetSemaphore, +} + +const RING_BUFFERS_SLOT_POOL_INDEX: usize = 0; +const REQUESTS_SLOT_POOL_INDEX: usize = 1; +const NUM_SLOT_POOLS: usize = 2; + +enum StateTypesImpl {} + +impl SlotStateTypes for StateTypesImpl { + type Occupied = Occupied; +} + +struct Occupied { + req: BlockIORequest, + state: OccupiedState, +} + +enum OccupiedState { + Pending { waker: Option }, + Canceled, + Complete { error: Option }, +} + +pub enum RequestBuf<'a> { + Read { buf: &'a mut [u8] }, + Write { buf: &'a [u8] }, +} + +impl<'a> RequestBuf<'a> { + pub fn issue_request_buf<'b>(&'b mut self) -> IssueRequestBuf<'a> { + match self { + Self::Read { buf } => IssueRequestBuf::Read { len: buf.len() }, + Self::Write { buf } => IssueRequestBuf::Write { buf }, + } + } + + pub fn poll_request_buf<'b>(&'b mut self) -> PollRequestBuf<'b> + where + 'a: 'b, + { + match self { + Self::Read { buf } => PollRequestBuf::Read { buf }, + Self::Write { .. } => PollRequestBuf::Write, + } + } +} + +pub enum IssueRequestBuf<'a> { + Read { len: usize }, + Write { buf: &'a [u8] }, +} + +impl<'a> IssueRequestBuf<'a> { + fn len(&self) -> usize { + match self { + Self::Read { len } => *len, + Self::Write { buf } => buf.len(), + } + } + + fn ty(&self) -> BlockIORequestType { + match self { + Self::Read { .. } => BlockIORequestType::Read, + Self::Write { .. } => BlockIORequestType::Write, + } + } +} + +pub enum PollRequestBuf<'a> { + Read { buf: &'a mut [u8] }, + Write, +} + +impl + OwnedSharedRingBufferBlockIO +{ + pub fn new( + dma_region: ExternallySharedRef<'static, [u8]>, + bounce_buffer_allocator: BounceBufferAllocator, + mut ring_buffers: RingBuffers<'static, Provide, F, BlockIORequest>, + ) -> Self { + assert!(ring_buffers.free_mut().is_empty().unwrap()); + assert!(ring_buffers.used_mut().is_empty().unwrap()); + let n = ring_buffers.free().capacity(); + Self { + dma_region, + bounce_buffer_allocator, + ring_buffers, + requests: SlotTracker::new_with_capacity((), (), n), + slot_set_semaphore: SlotSetSemaphore::new([n, n]), + } + } + + pub fn slot_set_semaphore(&self) -> &SlotSetSemaphoreHandle { + self.slot_set_semaphore.handle() + } + + fn report_current_num_free_current_num_free_ring_buffers_slots( + &mut self, + ) -> Result<(), ErrorOrUserError> { + let current_num_free = self.requests.num_free(); + self.slot_set_semaphore + .report_current_num_free_slots(RING_BUFFERS_SLOT_POOL_INDEX, current_num_free) + .unwrap(); + Ok(()) + } + + fn report_current_num_free_current_num_free_requests_slots( + &mut self, + ) -> Result<(), ErrorOrUserError> { + let current_num_free = self.ring_buffers.free_mut().num_empty_slots()?; + self.slot_set_semaphore + .report_current_num_free_slots(REQUESTS_SLOT_POOL_INDEX, current_num_free) + .unwrap(); + Ok(()) + } + + fn can_issue_requests( + &mut self, + n: usize, + ) -> Result { + let can = + self.ring_buffers.free_mut().num_empty_slots()? >= n && self.requests.num_free() >= n; + Ok(can) + } + + pub fn issue_read_request( + &mut self, + reservation: &mut SlotSetReservation<'_, S, NUM_SLOT_POOLS>, + start_block_idx: u64, + num_bytes: usize, + ) -> Result { + self.issue_request( + reservation, + start_block_idx, + &mut IssueRequestBuf::Read { len: num_bytes }, + ) + } + + pub fn issue_write_request( + &mut self, + reservation: &mut SlotSetReservation<'_, S, NUM_SLOT_POOLS>, + start_block_idx: u64, + buf: &[u8], + ) -> Result { + self.issue_request( + reservation, + start_block_idx, + &mut IssueRequestBuf::Write { buf }, + ) + } + + pub fn issue_request<'a>( + &mut self, + reservation: &mut SlotSetReservation<'_, S, NUM_SLOT_POOLS>, + start_block_idx: u64, + buf: &mut IssueRequestBuf, + ) -> Result { + if reservation.count() < 1 { + return Err(UserError::TooManyOutstandingRequests.into()); + } + + assert!(self.can_issue_requests(1)?); + + let request_index = self.requests.peek_next_free_index().unwrap(); + + let range = self + .bounce_buffer_allocator + .allocate(Layout::from_size_align(buf.len(), 1).unwrap()) + .map_err(|_| Error::BounceBufferAllocationError)?; + + if let IssueRequestBuf::Write { buf } = buf { + self.dma_region + .as_mut_ptr() + .index(range.clone()) + .copy_from_slice(buf); + } + + let req = BlockIORequest::new( + BlockIORequestStatus::Pending, + buf.ty(), + start_block_idx.try_into().unwrap(), + Descriptor::from_encoded_addr_range(range, request_index), + ); + + self.requests + .occupy(Occupied { + req: req.clone(), + state: OccupiedState::Pending { waker: None }, + }) + .unwrap(); + + self.ring_buffers + .free_mut() + .enqueue_and_commit(req)? + .unwrap(); + + self.ring_buffers.notify_mut(); + + self.slot_set_semaphore.consume(reservation, 1).unwrap(); + + Ok(request_index) + } + + pub fn cancel_request(&mut self, request_index: usize) -> Result<(), ErrorOrUserError> { + let mut state_value = self.requests.get_state_value_mut(request_index)?; + let occupied = state_value.as_occupied()?; + match &occupied.state { + OccupiedState::Pending { .. } => { + occupied.state = OccupiedState::Canceled; + } + OccupiedState::Complete { .. } => { + let range = occupied.req.buf().encoded_addr_range(); + self.bounce_buffer_allocator.deallocate(range); + self.requests.free(request_index, ()).unwrap(); + self.report_current_num_free_current_num_free_requests_slots()?; + } + _ => { + return Err(UserError::RequestStateMismatch.into()); + } + } + Ok(()) + } + + pub fn poll_read_request( + &mut self, + request_index: usize, + buf: &mut [u8], + waker: Option, + ) -> Result>, ErrorOrUserError> { + self.poll_request(request_index, &mut PollRequestBuf::Read { buf }, waker) + } + + pub fn poll_write_request( + &mut self, + request_index: usize, + waker: Option, + ) -> Result>, ErrorOrUserError> { + self.poll_request(request_index, &mut PollRequestBuf::Write, waker) + } + + pub fn poll_request( + &mut self, + request_index: usize, + buf: &mut PollRequestBuf, + waker: Option, + ) -> Result>, ErrorOrUserError> { + let mut state_value = self.requests.get_state_value_mut(request_index)?; + let occupied = state_value.as_occupied()?; + + Ok(match &mut occupied.state { + OccupiedState::Pending { + waker: ref mut waker_slot, + } => { + if let Some(waker) = waker { + waker_slot.replace(waker); + } + Poll::Pending + } + OccupiedState::Complete { error } => { + let val = match error { + None => Ok(()), + Some(err) => Err(err.clone()), + }; + + let range = occupied.req.buf().encoded_addr_range(); + + match buf { + PollRequestBuf::Read { buf } => { + self.dma_region + .as_mut_ptr() + .index(range.clone()) + .copy_into_slice(buf); + } + PollRequestBuf::Write => {} + } + + self.bounce_buffer_allocator.deallocate(range); + + self.requests.free(request_index, ()).unwrap(); + self.report_current_num_free_current_num_free_requests_slots()?; + + Poll::Ready(val) + } + _ => { + return Err(UserError::RequestStateMismatch.into()); + } + }) + } + + pub fn poll(&mut self) -> Result { + self.report_current_num_free_current_num_free_ring_buffers_slots()?; + + let mut notify = false; + + while let Some(completed_req) = self.ring_buffers.used_mut().dequeue()? { + let request_index = completed_req.buf().cookie(); + + let mut state_value = self + .requests + .get_state_value_mut(request_index) + .map_err(|_| PeerMisbehaviorError::OutOfBoundsCookie)?; + + let occupied = state_value + .as_occupied() + .map_err(|_| PeerMisbehaviorError::StateMismatch)?; + + { + let mut observed_request = completed_req; + observed_request.set_status(BlockIORequestStatus::Pending); + if observed_request != occupied.req { + return Err(PeerMisbehaviorError::DescriptorMismatch.into()); + } + } + + match &mut occupied.state { + OccupiedState::Pending { waker } => { + let waker = waker.take(); + + let status = completed_req + .status() + .map_err(|_| PeerMisbehaviorError::InvalidDescriptor)?; + + occupied.state = OccupiedState::Complete { + error: match status { + BlockIORequestStatus::Pending => { + return Err(PeerMisbehaviorError::InvalidDescriptor.into()); + } + BlockIORequestStatus::Ok => None, + BlockIORequestStatus::IOError => Some(IOError), + }, + }; + + waker.map(Waker::wake); + } + OccupiedState::Canceled => { + let range = occupied.req.buf().encoded_addr_range(); + self.bounce_buffer_allocator.deallocate(range); + self.requests.free(request_index, ()).unwrap(); + self.report_current_num_free_current_num_free_requests_slots()?; + } + _ => { + return Err(UserError::RequestStateMismatch.into()); + } + } + + notify = true; + } + + if notify { + self.ring_buffers.notify_mut(); + } + + Ok(notify) + } +} diff --git a/crates/sel4-shared-ring-buffer/block-io/types/src/lib.rs b/crates/sel4-shared-ring-buffer/block-io/types/src/lib.rs index 1dc388732..20c74c198 100644 --- a/crates/sel4-shared-ring-buffer/block-io/types/src/lib.rs +++ b/crates/sel4-shared-ring-buffer/block-io/types/src/lib.rs @@ -58,11 +58,23 @@ impl BlockIORequest { self.ty.try_into() } + pub fn set_ty(&mut self, ty: BlockIORequestType) { + self.ty = ty.into(); + } + pub fn start_block_idx(&self) -> u64 { self.start_block_idx } + pub fn set_start_block_idx(&mut self, start_block_idx: u64) { + self.start_block_idx = start_block_idx; + } + pub fn buf(&self) -> &Descriptor { &self.buf } + + pub fn buf_mut(&mut self) -> &mut Descriptor { + &mut self.buf + } } diff --git a/crates/sel4-shared-ring-buffer/bookkeeping/Cargo.toml b/crates/sel4-shared-ring-buffer/bookkeeping/Cargo.toml new file mode 100644 index 000000000..8b190c5cf --- /dev/null +++ b/crates/sel4-shared-ring-buffer/bookkeeping/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "sel4-shared-ring-buffer-bookkeeping" +version = "0.1.0" +authors = ["Nick Spinale "] +edition = "2021" +license = "BSD-2-Clause" + +[dependencies] +async-unsync = { version = "0.2.2", default-features = false, optional = true } diff --git a/crates/sel4-shared-ring-buffer/bookkeeping/src/lib.rs b/crates/sel4-shared-ring-buffer/bookkeeping/src/lib.rs new file mode 100644 index 000000000..92ad980e4 --- /dev/null +++ b/crates/sel4-shared-ring-buffer/bookkeeping/src/lib.rs @@ -0,0 +1,11 @@ +#![no_std] +#![feature(associated_type_bounds)] +#![feature(associated_type_defaults)] +#![feature(async_fn_in_trait)] +#![feature(return_position_impl_trait_in_trait)] + +extern crate alloc; + +pub mod slot_count_tracker; +pub mod slot_set_semaphore; +pub mod slot_tracker; diff --git a/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_count_tracker.rs b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_count_tracker.rs new file mode 100644 index 000000000..6f8ee5876 --- /dev/null +++ b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_count_tracker.rs @@ -0,0 +1,37 @@ +pub struct SlotCountTracker { + stored_num_free: usize, +} + +impl SlotCountTracker { + pub fn new(initial_num_free: usize) -> Self { + Self { + stored_num_free: initial_num_free, + } + } + + pub fn report_occupied(&mut self, count: usize) -> Result<(), SlotCountTrackerError> { + if count > self.stored_num_free { + return Err(SlotCountTrackerError::ReportOccupiedCountGreaterThanStoredNumFree); + } + self.stored_num_free -= count; + Ok(()) + } + + pub fn redeem_newly_free( + &mut self, + current_num_free: usize, + ) -> Result { + if current_num_free < self.stored_num_free { + return Err(SlotCountTrackerError::CurrentNumFreeLessThanStoredNumFree); + } + let newly_free = current_num_free - self.stored_num_free; + self.stored_num_free = current_num_free; + Ok(newly_free) + } +} + +#[derive(Debug)] +pub enum SlotCountTrackerError { + CurrentNumFreeLessThanStoredNumFree, + ReportOccupiedCountGreaterThanStoredNumFree, +} diff --git a/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_set_semaphore.rs b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_set_semaphore.rs new file mode 100644 index 000000000..a7be8587b --- /dev/null +++ b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_set_semaphore.rs @@ -0,0 +1,293 @@ +use alloc::rc::Rc; +use core::array; +use core::cell::Cell; +use core::future::Future; +use core::mem; + +use crate::slot_count_tracker::{SlotCountTracker, SlotCountTrackerError}; + +pub trait SlotSemaphore { + fn new(count: usize) -> Self; + + fn try_take(&self, n: usize) -> Result; + + fn give(&self, n: usize); + + fn close(&self); +} + +pub trait AsyncSlotSemaphore: SlotSemaphore { + fn take<'a>( + &'a self, + n: usize, + ) -> impl Future> + 'a; +} + +pub struct SlotSetSemaphore { + per_pool_slot_count_trackers: [SlotCountTracker; N], + handle: SlotSetSemaphoreHandle, +} + +#[derive(Clone)] +pub struct SlotSetSemaphoreHandle { + per_pool_semaphores: [T; N], +} + +pub struct SlotSetReservation<'a, T: SlotSemaphore, const N: usize> { + handle: &'a SlotSetSemaphoreHandle, + n: usize, +} + +impl SlotSetSemaphore { + pub fn new(slot_pool_capacities: [usize; N]) -> Self { + Self { + per_pool_slot_count_trackers: array::from_fn(|i| { + SlotCountTracker::new(slot_pool_capacities[i]) + }), + handle: SlotSetSemaphoreHandle { + per_pool_semaphores: array::from_fn(|i| T::new(slot_pool_capacities[i])), + }, + } + } + + pub fn close(&self) { + for sem in &self.handle.per_pool_semaphores { + sem.close(); + } + } + + pub fn handle(&self) -> &SlotSetSemaphoreHandle { + &self.handle + } + + pub fn consume( + &mut self, + reservation: &mut SlotSetReservation<'_, T, N>, + n: usize, + ) -> Result<(), Error> { + reservation.reduce_count(n)?; + for tracker in &mut self.per_pool_slot_count_trackers { + tracker.report_occupied(n)?; + } + Ok(()) + } + + pub fn report_current_num_free_slots( + &mut self, + slot_pool_index: usize, + current_num_free_slots: usize, + ) -> Result<(), SlotCountTrackerError> { + self.handle.per_pool_semaphores[slot_pool_index].give( + self.per_pool_slot_count_trackers[slot_pool_index] + .redeem_newly_free(current_num_free_slots)?, + ); + Ok(()) + } +} + +impl SlotSetSemaphoreHandle { + pub fn try_reserve( + &self, + n: usize, + ) -> Result>, SlotSemaphoreClosedError> { + let mut tmp_permits: [Option>; N] = array::from_fn(|_| None); + for (i, sem) in self.per_pool_semaphores.iter().enumerate() { + if sem.try_take(n)? { + tmp_permits[i] = Some(TemporaryPermit::new(sem, n)); + } else { + return Ok(None); + } + } + + mem::forget(tmp_permits); + + Ok(Some(self.reservation(n))) + } + + fn reservation(&self, n: usize) -> SlotSetReservation<'_, T, N> { + SlotSetReservation { handle: self, n } + } +} + +impl SlotSetSemaphoreHandle { + pub async fn reserve( + &self, + n: usize, + ) -> Result, SlotSemaphoreClosedError> { + let mut tmp_permits: [Option>; N] = array::from_fn(|_| None); + for (i, sem) in self.per_pool_semaphores.iter().enumerate() { + sem.take(n).await?; + tmp_permits[i] = Some(TemporaryPermit::new(sem, n)); + } + + mem::forget(tmp_permits); + + Ok(self.reservation(n)) + } +} + +struct TemporaryPermit<'a, T: SlotSemaphore> { + sem: &'a T, + n: usize, +} + +impl<'a, T: SlotSemaphore> TemporaryPermit<'a, T> { + fn new(sem: &'a T, n: usize) -> Self { + Self { sem, n } + } +} + +impl<'a, T: SlotSemaphore> Drop for TemporaryPermit<'a, T> { + fn drop(&mut self) { + self.sem.give(self.n); + } +} + +impl<'a, T: SlotSemaphore, const N: usize> SlotSetReservation<'a, T, N> { + pub fn count(&self) -> usize { + self.n + } + + fn reduce_count(&mut self, n: usize) -> Result<(), SlotReservationExhaustedError> { + if n > self.n { + return Err(SlotReservationExhaustedError::new()); + } + self.n -= n; + Ok(()) + } + + pub fn split(&mut self, split_off: usize) -> Result { + self.reduce_count(split_off)?; + Ok(Self { + handle: self.handle, + n: split_off, + }) + } + + pub fn merge(&mut self, other: Self) { + self.n = self.n.checked_add(other.n).unwrap(); + } +} + +impl<'a, T: SlotSemaphore, const N: usize> Drop for SlotSetReservation<'a, T, N> { + fn drop(&mut self) { + for sem in &self.handle.per_pool_semaphores { + sem.give(self.n); + } + } +} + +#[derive(Debug)] +pub enum Error { + SlotReservationExhausted, + SlotCountTrackingError, +} + +impl From for Error { + fn from(_err: SlotReservationExhaustedError) -> Self { + Self::SlotReservationExhausted + } +} + +impl From for Error { + fn from(_err: SlotCountTrackerError) -> Self { + Self::SlotCountTrackingError + } +} + +#[derive(Debug)] +pub struct SlotSemaphoreClosedError(()); + +impl SlotSemaphoreClosedError { + pub fn new() -> Self { + Self(()) + } +} + +#[derive(Debug)] +pub struct SlotReservationExhaustedError(()); + +impl SlotReservationExhaustedError { + pub fn new() -> Self { + Self(()) + } +} + +pub struct DummySlotSemaphore { + permits: Cell>, +} + +impl SlotSemaphore for Rc { + fn new(count: usize) -> Self { + Rc::new(DummySlotSemaphore { + permits: Cell::new(Some(count)), + }) + } + + fn try_take(&self, n: usize) -> Result { + match self.permits.get() { + Some(permits) => Ok(match n.checked_sub(permits) { + Some(new_permits) => { + self.permits.set(Some(new_permits)); + true + } + None => false, + }), + None => Err(SlotSemaphoreClosedError::new()), + } + } + + fn give(&self, n: usize) { + if let Some(permits) = self.permits.get() { + self.permits.set(Some(permits.checked_add(n).unwrap())); + } + } + + fn close(&self) { + self.permits.set(None); + } +} + +#[cfg(feature = "async-unsync")] +mod async_unsync_impl { + use alloc::rc::Rc; + + use async_unsync::semaphore::{Semaphore, TryAcquireError}; + + use super::*; + + impl SlotSemaphore for Rc { + fn new(count: usize) -> Self { + Rc::new(Semaphore::new(count)) + } + + fn try_take(&self, n: usize) -> Result { + match self.try_acquire_many(n) { + Ok(permit) => { + permit.forget(); + Ok(true) + } + Err(TryAcquireError::NoPermits) => Ok(false), + Err(TryAcquireError::Closed) => Err(SlotSemaphoreClosedError::new()), + } + } + + fn give(&self, n: usize) { + self.add_permits(n) + } + + fn close(&self) { + Semaphore::close(self); + } + } + + impl AsyncSlotSemaphore for Rc { + async fn take(&self, n: usize) -> Result<(), SlotSemaphoreClosedError> { + self.acquire_many(n) + .await + .map_err(|_| SlotSemaphoreClosedError::new())? + .forget(); + Ok(()) + } + } +} diff --git a/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs new file mode 100644 index 000000000..102be73a3 --- /dev/null +++ b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs @@ -0,0 +1,237 @@ +extern crate alloc; + +use alloc::vec::Vec; +use core::iter; +use core::mem; + +type Result = core::result::Result; + +pub trait SlotStateTypes { + type Common = (); + type Free = (); + type Occupied = (); +} + +pub struct SlotTracker { + entries: Vec>, + free_list_head_index: Option, + num_free: usize, +} + +struct Entry { + common: T::Common, + state: StateInternal, +} + +enum StateInternal { + Free { + free_list_next_index: Option, + value: T::Free, + }, + Occupied { + value: T::Occupied, + }, +} + +impl StateInternal { + fn project(&self) -> SlotState { + match self { + Self::Free { .. } => SlotState::Free, + Self::Occupied { .. } => SlotState::Occupied, + } + } +} + +impl SlotTracker { + pub fn new(iter: impl Iterator) -> Self { + let mut entries = Vec::new(); + let mut free_list_head_index = None; + entries.extend(iter.enumerate().map(|(i, (v_common, v_free))| Entry { + common: v_common, + state: StateInternal::Free { + free_list_next_index: free_list_head_index.replace(i), + value: v_free, + }, + })); + let num_free = entries.len(); + Self { + entries, + free_list_head_index, + num_free, + } + } + + pub fn new_with_capacity(common: T::Common, free: T::Free, capacity: usize) -> Self + where + T: SlotStateTypes, + { + Self::new(iter::repeat((common, free)).take(capacity)) + } + + pub fn capacity(&self) -> usize { + self.entries.capacity() + } + + pub fn num_free(&self) -> usize { + self.num_free + } + + pub fn num_occupied(&self) -> usize { + self.capacity() - self.num_free() + } + + pub fn peek_next_free_index(&self) -> Option { + self.free_list_head_index + } + + fn get_entry(&self, index: usize) -> Result<&Entry> { + self.entries.get(index).ok_or(SlotTrackerError::OutOfBounds) + } + + fn get_entry_mut(&mut self, index: usize) -> Result<&mut Entry> { + self.entries + .get_mut(index) + .ok_or(SlotTrackerError::OutOfBounds) + } + + pub fn get_common_value(&self, index: usize) -> Result<&T::Common> { + Ok(&self.get_entry(index)?.common) + } + + pub fn get_common_value_mut(&mut self, index: usize) -> Result<&mut T::Common> { + Ok(&mut self.get_entry_mut(index)?.common) + } + + pub fn get_state(&self, index: usize) -> Result { + Ok(self.get_entry(index)?.state.project()) + } + + pub fn get_state_value(&self, index: usize) -> Result> { + Ok(match self.get_entry(index)?.state { + StateInternal::Free { ref value, .. } => SlotStateValueRef::Free(value), + StateInternal::Occupied { ref value, .. } => SlotStateValueRef::Occupied(value), + }) + } + + pub fn get_state_value_mut(&mut self, index: usize) -> Result> { + Ok(match self.get_entry_mut(index)?.state { + StateInternal::Free { ref mut value, .. } => SlotStateValueRefMut::Free(value), + StateInternal::Occupied { ref mut value, .. } => SlotStateValueRefMut::Occupied(value), + }) + } + + pub fn occupy(&mut self, value: T::Occupied) -> Option<(usize, T::Free)> { + let index = self.free_list_head_index?; + let new_state = StateInternal::Occupied { value }; + let old_state = self.replace_state(index, new_state); + let value = match old_state { + StateInternal::Free { + free_list_next_index, + value, + } => { + self.free_list_head_index = free_list_next_index; + value + } + _ => { + unreachable!() + } + }; + Some((index, value)) + } + + pub fn free(&mut self, index: usize, value: T::Free) -> Result { + self.ensure_state(index, SlotState::Occupied)?; + let old_state = self.replace_state_with_free(index, value); + let value = match old_state { + StateInternal::Occupied { value } => value, + _ => unreachable!(), + }; + Ok(value) + } + + fn ensure_state(&self, index: usize, state: SlotState) -> Result<()> { + if self.get_state(index)? == state { + Ok(()) + } else { + Err(SlotTrackerError::StateMismatch) + } + } + + fn replace_state(&mut self, index: usize, new_state: StateInternal) -> StateInternal { + mem::replace(&mut self.get_entry_mut(index).unwrap().state, new_state) + } + + fn replace_state_with_free(&mut self, index: usize, value: T::Free) -> StateInternal { + let new_state = StateInternal::Free { + free_list_next_index: self.free_list_head_index.replace(index), + value, + }; + self.replace_state(index, new_state) + } +} + +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub enum SlotState { + Free, + Occupied, +} + +impl SlotState { + pub fn is_free(&self) -> bool { + *self == Self::Free + } + + pub fn is_occupied(&self) -> bool { + *self == Self::Occupied + } +} + +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub enum SlotStateValueRef<'a, T: SlotStateTypes> { + Free(&'a T::Free), + Occupied(&'a T::Occupied), +} + +impl<'a, T: SlotStateTypes> SlotStateValueRef<'a, T> { + pub fn as_free(&self) -> Result<&T::Free> { + match self { + Self::Free(r) => Ok(r), + _ => Err(SlotTrackerError::StateMismatch), + } + } + + pub fn as_occupied(&self) -> Result<&T::Occupied> { + match self { + Self::Occupied(r) => Ok(r), + _ => Err(SlotTrackerError::StateMismatch), + } + } +} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub enum SlotStateValueRefMut<'a, T: SlotStateTypes> { + Free(&'a mut T::Free), + Occupied(&'a mut T::Occupied), +} + +impl<'a, T: SlotStateTypes> SlotStateValueRefMut<'a, T> { + pub fn as_free(&mut self) -> Result<&mut T::Free> { + match self { + Self::Free(r) => Ok(r), + _ => Err(SlotTrackerError::StateMismatch), + } + } + + pub fn as_occupied(&mut self) -> Result<&mut T::Occupied> { + match self { + Self::Occupied(r) => Ok(r), + _ => Err(SlotTrackerError::StateMismatch), + } + } +} + +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub enum SlotTrackerError { + OutOfBounds, + StateMismatch, +} diff --git a/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs b/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs index e20255a4c..d0770619b 100644 --- a/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs +++ b/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs @@ -5,16 +5,13 @@ use core::ops::Range; use sel4_bounce_buffer_allocator::{Basic, BounceBufferAllocator}; use sel4_externally_shared::ExternallySharedRef; -use sel4_shared_ring_buffer::{ - Descriptor, Error as SharedRingBuffersError, RingBuffers, RING_BUFFER_SIZE, -}; +use sel4_shared_ring_buffer::{roles::Provide, Descriptor, RingBuffers, RING_BUFFER_SIZE}; pub(crate) struct Inner { dma_region: ExternallySharedRef<'static, [u8]>, - dma_region_paddr: usize, bounce_buffer_allocator: BounceBufferAllocator, - rx_ring_buffers: RingBuffers<'static, fn() -> Result<(), !>>, - tx_ring_buffers: RingBuffers<'static, fn() -> Result<(), !>>, + rx_ring_buffers: RingBuffers<'static, Provide, fn()>, + tx_ring_buffers: RingBuffers<'static, Provide, fn()>, rx_buffers: Vec, tx_buffers: Vec, mtu: usize, @@ -53,8 +50,8 @@ impl Inner { pub(crate) fn new( dma_region: ExternallySharedRef<'static, [u8]>, dma_region_paddr: usize, - mut rx_ring_buffers: RingBuffers<'static, fn() -> Result<(), !>>, - tx_ring_buffers: RingBuffers<'static, fn() -> Result<(), !>>, + mut rx_ring_buffers: RingBuffers<'static, Provide, fn()>, + tx_ring_buffers: RingBuffers<'static, Provide, fn()>, num_rx_buffers: usize, rx_buffer_size: usize, mtu: usize, @@ -82,7 +79,8 @@ impl Inner { for entry in rx_buffers.iter() { rx_ring_buffers .free_mut() - .enqueue(descriptor_of(dma_region_paddr, entry.range.clone())) + .enqueue_and_commit(descriptor_of(entry.range.clone())) + .unwrap() .unwrap(); } let tx_buffers = iter::repeat_with(|| TxBufferEntry { @@ -93,7 +91,6 @@ impl Inner { Self { dma_region, - dma_region_paddr, bounce_buffer_allocator, rx_ring_buffers, tx_ring_buffers, @@ -110,12 +107,7 @@ impl Inner { pub(crate) fn poll(&mut self) -> bool { let mut notify_rx = false; - while let Ok(desc) = self - .rx_ring_buffers - .used_mut() - .dequeue() - .map_err(|err| assert_eq!(err, SharedRingBuffersError::RingIsEmpty)) - { + while let Some(desc) = self.rx_ring_buffers.used_mut().dequeue().unwrap() { let ix = self .lookup_rx_buffer_by_encoded_addr(desc.encoded_addr()) .unwrap(); @@ -128,17 +120,12 @@ impl Inner { } if notify_rx { - self.rx_ring_buffers.notify().unwrap(); + self.rx_ring_buffers.notify(); } let mut notify_tx = false; - while let Ok(desc) = self - .tx_ring_buffers - .used_mut() - .dequeue() - .map_err(|err| assert_eq!(err, SharedRingBuffersError::RingIsEmpty)) - { + while let Some(desc) = self.tx_ring_buffers.used_mut().dequeue().unwrap() { let ix = self.lookup_tx_buffer_by_descriptor(&desc).unwrap(); let entry = self.tx_buffer_entry_mut(ix); let range = match &entry.state { @@ -153,7 +140,7 @@ impl Inner { } if notify_tx { - self.tx_ring_buffers.notify().unwrap(); + self.tx_ring_buffers.notify(); } notify_rx || notify_tx @@ -163,7 +150,7 @@ impl Inner { self.rx_buffers .iter() .enumerate() - .find(|(_i, entry)| self.dma_region_paddr + entry.range.start == encoded_addr) + .find(|(_i, entry)| entry.range.start == encoded_addr) .map(|(i, _entry)| i) } @@ -172,9 +159,7 @@ impl Inner { .iter() .enumerate() .find(|(_i, entry)| match &entry.state { - TxBufferState::Sent { range } => { - &descriptor_of(self.dma_region_paddr, range.clone()) == desc - } + TxBufferState::Sent { range } => &descriptor_of(range.clone()) == desc, _ => false, }) .map(|(i, _entry)| i) @@ -262,9 +247,13 @@ impl Inner { RxBufferState::Claimed { .. } => { entry.state = RxBufferState::Free; let range = entry.range.clone(); - let desc = descriptor_of(self.dma_region_paddr, range); - self.rx_ring_buffers.free_mut().enqueue(desc).unwrap(); - self.rx_ring_buffers.notify().unwrap(); + let desc = descriptor_of(range); + self.rx_ring_buffers + .free_mut() + .enqueue_and_commit(desc) + .unwrap() + .unwrap(); + self.rx_ring_buffers.notify(); } _ => { panic!() @@ -292,9 +281,13 @@ impl Inner { .as_raw_ptr() .as_mut() }); - let desc = descriptor_of(self.dma_region_paddr, range); - self.tx_ring_buffers.free_mut().enqueue(desc).unwrap(); - self.tx_ring_buffers.notify().unwrap(); + let desc = descriptor_of(range); + self.tx_ring_buffers + .free_mut() + .enqueue_and_commit(desc) + .unwrap() + .unwrap(); + self.tx_ring_buffers.notify(); r } @@ -313,10 +306,6 @@ impl Inner { } } -fn descriptor_of(dma_region_paddr: usize, range: Range) -> Descriptor { - Descriptor::new( - dma_region_paddr + range.start, - range.len().try_into().unwrap(), - 0, - ) +fn descriptor_of(range: Range) -> Descriptor { + Descriptor::from_encoded_addr_range(range, 0) } diff --git a/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs b/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs index 893b88fc9..39e2696d3 100644 --- a/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs +++ b/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs @@ -11,7 +11,7 @@ use smoltcp::phy::{self, Device, DeviceCapabilities}; use smoltcp::time::Instant; use sel4_externally_shared::ExternallySharedRef; -use sel4_shared_ring_buffer::RingBuffers; +use sel4_shared_ring_buffer::{roles::Provide, RingBuffers}; mod inner; @@ -27,8 +27,8 @@ impl DeviceImpl { pub fn new( dma_region: ExternallySharedRef<'static, [u8]>, dma_region_paddr: usize, - rx_ring_buffers: RingBuffers<'static, fn() -> Result<(), !>>, - tx_ring_buffers: RingBuffers<'static, fn() -> Result<(), !>>, + rx_ring_buffers: RingBuffers<'static, Provide, fn()>, + tx_ring_buffers: RingBuffers<'static, Provide, fn()>, num_rx_buffers: usize, rx_buffer_size: usize, mtu: usize, diff --git a/crates/sel4-shared-ring-buffer/src/descriptor.rs b/crates/sel4-shared-ring-buffer/src/descriptor.rs new file mode 100644 index 000000000..33d8a104d --- /dev/null +++ b/crates/sel4-shared-ring-buffer/src/descriptor.rs @@ -0,0 +1,60 @@ +use core::ops::Range; + +use zerocopy::{AsBytes, FromBytes, FromZeroes}; + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, AsBytes, FromBytes, FromZeroes)] +pub struct Descriptor { + encoded_addr: usize, + len: u32, + _padding: [u8; 4], + cookie: usize, +} + +impl Descriptor { + pub fn new(encoded_addr: usize, len: u32, cookie: usize) -> Self { + Self { + encoded_addr, + len, + _padding: [0; 4], + cookie, + } + } + + pub fn from_encoded_addr_range(encoded_addr_range: Range, cookie: usize) -> Self { + let encoded_addr = encoded_addr_range.start; + let len = encoded_addr_range.len().try_into().unwrap(); + Self::new(encoded_addr, len, cookie) + } + + pub fn encoded_addr(&self) -> usize { + self.encoded_addr + } + + pub fn set_encoded_addr(&mut self, encoded_addr: usize) { + self.encoded_addr = encoded_addr; + } + + #[allow(clippy::len_without_is_empty)] + pub fn len(&self) -> u32 { + self.len + } + + pub fn set_len(&mut self, len: u32) { + self.len = len; + } + + pub fn cookie(&self) -> usize { + self.cookie + } + + pub fn set_cookie(&mut self, cookie: usize) { + self.cookie = cookie; + } + + pub fn encoded_addr_range(&self) -> Range { + let start = self.encoded_addr(); + let len = self.len().try_into().unwrap(); + start..start.checked_add(len).unwrap() + } +} diff --git a/crates/sel4-shared-ring-buffer/src/lib.rs b/crates/sel4-shared-ring-buffer/src/lib.rs index efb88f58c..6a13e2f87 100644 --- a/crates/sel4-shared-ring-buffer/src/lib.rs +++ b/crates/sel4-shared-ring-buffer/src/lib.rs @@ -1,199 +1,303 @@ #![no_std] +use core::marker::PhantomData; use core::num::Wrapping; -use core::ptr::NonNull; use core::sync::atomic::Ordering; -use zerocopy::{AsBytes, FromBytes, FromZeroes}; - use sel4_externally_shared::{map_field, ExternallySharedPtr, ExternallySharedRef}; +pub mod roles; + +use roles::{Read, RingBufferRole, RingBufferRoleValue, RingBuffersRole, Write}; + +mod descriptor; + +pub use descriptor::Descriptor; + +// TODO +// - zerocopy for RawRingBuffer +// - require zerocopy for T in enqueue and dequeue? +// - variable length descriptor array? + pub const RING_BUFFER_SIZE: usize = 512; -pub struct RingBuffers<'a, F, T = Descriptor> { - free: RingBuffer<'a, T>, - used: RingBuffer<'a, T>, +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct PeerMisbehaviorError(()); + +impl PeerMisbehaviorError { + fn new() -> Self { + Self(()) + } +} + +pub struct RingBuffers<'a, R: RingBuffersRole, F, T = Descriptor> { + free: RingBuffer<'a, R::FreeRole, T>, + used: RingBuffer<'a, R::UsedRole, T>, notify: F, } -impl<'a, F, T: Copy> RingBuffers<'a, F, T> { +impl<'a, R: RingBuffersRole, F, T: Copy> RingBuffers<'a, R, F, T> { pub fn new( - free: RingBuffer<'a, T>, - used: RingBuffer<'a, T>, + free: RingBuffer<'a, R::FreeRole, T>, + used: RingBuffer<'a, R::UsedRole, T>, notify: F, - initialize: bool, ) -> Self { - let mut this = Self { free, used, notify }; - if initialize { - this.free_mut().initialize(); - this.used_mut().initialize(); - } - this + Self { free, used, notify } + } + + pub fn from_ptrs_using_default_initialization_strategy_for_role( + free: ExternallySharedRef<'a, RawRingBuffer>, + used: ExternallySharedRef<'a, RawRingBuffer>, + notify: F, + ) -> Self { + let initialization_strategy = R::default_initialization_strategy(); + Self::new( + RingBuffer::new(free, initialization_strategy), + RingBuffer::new(used, initialization_strategy), + notify, + ) } - pub fn free(&self) -> &RingBuffer<'a, T> { + pub fn free(&self) -> &RingBuffer<'a, R::FreeRole, T> { &self.free } - pub fn used(&self) -> &RingBuffer<'a, T> { + pub fn used(&self) -> &RingBuffer<'a, R::UsedRole, T> { &self.used } - pub fn free_mut(&mut self) -> &mut RingBuffer<'a, T> { + pub fn free_mut(&mut self) -> &mut RingBuffer<'a, R::FreeRole, T> { &mut self.free } - pub fn used_mut(&mut self) -> &mut RingBuffer<'a, T> { + pub fn used_mut(&mut self) -> &mut RingBuffer<'a, R::UsedRole, T> { &mut self.used } } -impl<'a, T, F: Fn() -> R, R> RingBuffers<'a, F, T> { - pub fn notify(&self) -> R { +impl<'a, U, R: RingBuffersRole, F: Fn() -> U, T> RingBuffers<'a, R, F, T> { + pub fn notify(&self) -> U { (self.notify)() } } -impl<'a, T, F: FnMut() -> R, R> RingBuffers<'a, F, T> { - pub fn notify_mut(&mut self) -> R { +impl<'a, U, R: RingBuffersRole, F: FnMut() -> U, T> RingBuffers<'a, R, F, T> { + pub fn notify_mut(&mut self) -> U { (self.notify)() } } -// TODO: zerocopy AsBytes and FromBytes #[repr(C)] #[derive(Copy, Clone, Debug)] pub struct RawRingBuffer { - write_index: u32, - read_index: u32, - descriptors: [T; RING_BUFFER_SIZE], + pub write_index: u32, + pub read_index: u32, + pub descriptors: [T; RING_BUFFER_SIZE], } -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, AsBytes, FromBytes, FromZeroes)] -pub struct Descriptor { - encoded_addr: usize, - len: u32, - _padding: [u8; 4], - cookie: usize, +pub struct RingBuffer<'a, R: RingBufferRole, T = Descriptor> { + inner: ExternallySharedRef<'a, RawRingBuffer>, + stored_write_index: Wrapping, + stored_read_index: Wrapping, + _phantom: PhantomData, } -impl Descriptor { - pub fn new(encoded_addr: usize, len: u32, cookie: usize) -> Self { +impl<'a, R: RingBufferRole, T: Copy> RingBuffer<'a, R, T> { + const SIZE: usize = RING_BUFFER_SIZE; + + pub fn new( + ptr: ExternallySharedRef<'a, RawRingBuffer>, + initialization_strategy: InitializationStrategy, + ) -> Self { + let mut inner = ptr; + let initial_state = match initialization_strategy { + InitializationStrategy::ReadState => { + let ptr = inner.as_ptr(); + InitialState { + write_index: map_field!(ptr.write_index).read(), + read_index: map_field!(ptr.read_index).read(), + } + } + InitializationStrategy::UseState(initial_state) => initial_state, + InitializationStrategy::UseAndWriteState(initial_state) => { + let ptr = inner.as_mut_ptr(); + map_field!(ptr.write_index).write(initial_state.write_index); + map_field!(ptr.read_index).write(initial_state.read_index); + initial_state + } + }; Self { - encoded_addr, - len, - _padding: [0; 4], - cookie, + inner, + stored_write_index: Wrapping(initial_state.write_index), + stored_read_index: Wrapping(initial_state.read_index), + _phantom: PhantomData, } } - pub fn encoded_addr(&self) -> usize { - self.encoded_addr + const fn role(&self) -> RingBufferRoleValue { + R::ROLE } - #[allow(clippy::len_without_is_empty)] - pub fn len(&self) -> u32 { - self.len + pub const fn capacity(&self) -> usize { + Self::SIZE - 1 } - pub fn cookie(&self) -> usize { - self.cookie + fn write_index(&mut self) -> ExternallySharedPtr<'_, u32> { + let ptr = self.inner.as_mut_ptr(); + map_field!(ptr.write_index) } -} -pub struct RingBuffer<'a, T = Descriptor> { - inner: ExternallySharedRef<'a, RawRingBuffer>, -} + fn read_index(&mut self) -> ExternallySharedPtr<'_, u32> { + let ptr = self.inner.as_mut_ptr(); + map_field!(ptr.read_index) + } -impl<'a, T: Copy> RingBuffer<'a, T> { - // TODO parameterizing RingBuffer to use this const is not very ergonomic - // pub const SIZE: usize = RING_BUFFER_SIZE; + fn descriptor(&mut self, index: Wrapping) -> ExternallySharedPtr<'_, T> { + let residue = self.residue(index); + let ptr = self.inner.as_mut_ptr(); + map_field!(ptr.descriptors).as_slice().index(residue) + } - pub fn new(inner: ExternallySharedRef<'a, RawRingBuffer>) -> Self { - Self { inner } + fn update_stored_write_index(&mut self) -> Result<(), PeerMisbehaviorError> { + debug_assert!(self.role().is_read()); + let observed_write_index = Wrapping(self.write_index().read()); + let observed_num_filled_slots = self.residue(observed_write_index - self.stored_read_index); + if observed_num_filled_slots < self.stored_num_filled_slots() { + return Err(PeerMisbehaviorError::new()); + } + self.stored_write_index = observed_write_index; + Ok(()) } - #[allow(clippy::missing_safety_doc)] - pub unsafe fn from_ptr(ptr: NonNull>) -> Self { - Self::new(ExternallySharedRef::new(ptr)) + fn update_stored_read_index(&mut self) -> Result<(), PeerMisbehaviorError> { + debug_assert!(self.role().is_write()); + let observed_read_index = Wrapping(self.read_index().read()); + let observed_num_filled_slots = self.residue(self.stored_write_index - observed_read_index); + if observed_num_filled_slots > self.stored_num_filled_slots() { + return Err(PeerMisbehaviorError::new()); + } + self.stored_read_index = observed_read_index; + Ok(()) } - fn write_index(&self) -> Wrapping { - let ptr = self.inner.as_ptr(); - Wrapping(map_field!(ptr.write_index).read()) + fn stored_num_filled_slots(&mut self) -> usize { + self.residue(self.stored_write_index - self.stored_read_index) } - fn read_index(&self) -> Wrapping { - let ptr = self.inner.as_ptr(); - Wrapping(map_field!(ptr.read_index).read()) + pub fn num_filled_slots(&mut self) -> Result { + match self.role() { + RingBufferRoleValue::Read => self.update_stored_write_index(), + RingBufferRoleValue::Write => self.update_stored_read_index(), + }?; + Ok(self.stored_num_filled_slots()) } - fn set_write_index(&mut self, index: Wrapping) { - let ptr = self.inner.as_mut_ptr(); - map_field!(ptr.write_index).write(index.0) + pub fn num_empty_slots(&mut self) -> Result { + Ok(self.capacity() - self.num_filled_slots()?) } - fn set_read_index(&mut self, index: Wrapping) { - let ptr = self.inner.as_mut_ptr(); - map_field!(ptr.read_index).write(index.0) + pub fn is_empty(&mut self) -> Result { + Ok(self.num_filled_slots()? == 0) } - fn initialize(&mut self) { - self.set_write_index(Wrapping(0)); - self.set_read_index(Wrapping(0)); + pub fn is_full(&mut self) -> Result { + Ok(self.num_empty_slots()? == 0) } - fn descriptor(&mut self, index: Wrapping) -> ExternallySharedPtr<'_, T> { - let linear_index = usize::try_from(residue(index).0).unwrap(); - let ptr = self.inner.as_mut_ptr(); - map_field!(ptr.descriptors).as_slice().index(linear_index) + fn residue(&self, index: Wrapping) -> usize { + usize::try_from(index.0).unwrap() % Self::SIZE } +} - pub fn is_empty(&self) -> bool { - !has_nonzero_residue(self.write_index() - self.read_index()) +impl<'a, T: Copy> RingBuffer<'a, Write, T> { + pub fn enqueue_and_commit(&mut self, desc: T) -> Result, PeerMisbehaviorError> { + self.enqueue(desc, true) } - pub fn is_full(&self) -> bool { - !has_nonzero_residue(self.write_index() - self.read_index() + Wrapping(1)) + pub fn enqueue_without_committing( + &mut self, + desc: T, + ) -> Result, PeerMisbehaviorError> { + self.enqueue(desc, false) } - pub fn enqueue(&mut self, desc: T) -> Result<(), Error> { - if self.is_full() { - return Err(Error::RingIsFull); - } - self.descriptor(self.write_index()).write(desc); - { - let ptr = self.inner.as_mut_ptr(); - map_field!(ptr.write_index).with_atomic(|x| x.fetch_add(1, Ordering::Release)); + pub fn enqueue( + &mut self, + desc: T, + commit: bool, + ) -> Result, PeerMisbehaviorError> { + if self.is_full()? { + return Ok(Err(desc)); } - Ok(()) + self.force_enqueue(desc, commit); + Ok(Ok(())) } - pub fn dequeue(&mut self) -> Result { - if self.is_empty() { - return Err(Error::RingIsEmpty); + pub fn force_enqueue(&mut self, desc: T, commit: bool) { + self.descriptor(self.stored_write_index).write(desc); + self.stored_write_index += 1; + if commit { + self.commit(); } - let desc = self.descriptor(self.read_index()).read(); - { - let ptr = self.inner.as_mut_ptr(); - map_field!(ptr.read_index).with_atomic(|x| x.fetch_add(1, Ordering::Release)); + } + + pub fn commit(&mut self) { + self.expose_write_index(); + } + + fn expose_write_index(&mut self) { + let write_index = self.stored_write_index.0; + self.write_index() + .with_atomic(|x| x.store(write_index, Ordering::Release)); + } +} + +impl<'a, T: Copy> RingBuffer<'a, Read, T> { + pub fn dequeue(&mut self) -> Result, PeerMisbehaviorError> { + if self.is_empty()? { + return Ok(None); } - Ok(desc) + Ok(Some(self.force_dequeue())) + } + + pub fn force_dequeue(&mut self) -> T { + let desc = self.descriptor(self.stored_read_index).read(); + self.stored_read_index += 1; + self.expose_read_index(); + desc + } + + fn expose_read_index(&mut self) { + let read_index = self.stored_read_index.0; + self.read_index() + .with_atomic(|x| x.store(read_index, Ordering::Release)); } } -#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] -pub enum Error { - RingIsFull, - RingIsEmpty, +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub enum InitializationStrategy { + ReadState, + UseState(InitialState), + UseAndWriteState(InitialState), } -fn residue(n: Wrapping) -> Wrapping { - let size = Wrapping(u32::try_from(RING_BUFFER_SIZE).unwrap()); - n % size +impl Default for InitializationStrategy { + fn default() -> Self { + Self::ReadState + } } -fn has_nonzero_residue(n: Wrapping) -> bool { - residue(n) != Wrapping(0) +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)] +pub struct InitialState { + write_index: u32, + read_index: u32, +} + +impl InitialState { + pub fn new(write_index: u32, read_index: u32) -> Self { + Self { + write_index, + read_index, + } + } } diff --git a/crates/sel4-shared-ring-buffer/src/roles.rs b/crates/sel4-shared-ring-buffer/src/roles.rs new file mode 100644 index 000000000..283c68cdb --- /dev/null +++ b/crates/sel4-shared-ring-buffer/src/roles.rs @@ -0,0 +1,98 @@ +use crate::InitializationStrategy; + +pub enum Provide {} +pub enum Use {} + +pub trait RingBuffersRole: RingBuffersRoleSealed { + type FreeRole: RingBufferRole; + type UsedRole: RingBufferRole; + + const ROLE: RingBuffersRoleValue; + + fn default_initialization_strategy() -> InitializationStrategy; +} + +impl RingBuffersRole for Provide { + type FreeRole = Write; + type UsedRole = Read; + + const ROLE: RingBuffersRoleValue = RingBuffersRoleValue::Provide; + + fn default_initialization_strategy() -> InitializationStrategy { + InitializationStrategy::UseAndWriteState(Default::default()) + } +} + +impl RingBuffersRole for Use { + type FreeRole = Read; + type UsedRole = Write; + + const ROLE: RingBuffersRoleValue = RingBuffersRoleValue::Use; + + fn default_initialization_strategy() -> InitializationStrategy { + InitializationStrategy::ReadState + } +} + +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub enum RingBuffersRoleValue { + Provide, + Use, +} + +impl RingBuffersRoleValue { + pub fn is_provide(self) -> bool { + self == Self::Provide + } + + pub fn is_use(self) -> bool { + self == Self::Use + } +} + +pub enum Write {} +pub enum Read {} + +pub trait RingBufferRole: RingBufferRoleSealed { + const ROLE: RingBufferRoleValue; +} + +impl RingBufferRole for Write { + const ROLE: RingBufferRoleValue = RingBufferRoleValue::Write; +} + +impl RingBufferRole for Read { + const ROLE: RingBufferRoleValue = RingBufferRoleValue::Read; +} + +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub enum RingBufferRoleValue { + Write, + Read, +} + +impl RingBufferRoleValue { + pub fn is_write(self) -> bool { + self == Self::Write + } + + pub fn is_read(self) -> bool { + self == Self::Read + } +} + +use sealing::{RingBufferRoleSealed, RingBuffersRoleSealed}; + +mod sealing { + use super::*; + + pub trait RingBuffersRoleSealed {} + + impl RingBuffersRoleSealed for Provide {} + impl RingBuffersRoleSealed for Use {} + + pub trait RingBufferRoleSealed {} + + impl RingBufferRoleSealed for Write {} + impl RingBufferRoleSealed for Read {} +} diff --git a/hacking/cargo-manifest-sources/crates/examples/microkit/http-server/pds/server/crate.nix b/hacking/cargo-manifest-sources/crates/examples/microkit/http-server/pds/server/crate.nix index a01fb148e..b13516509 100644 --- a/hacking/cargo-manifest-sources/crates/examples/microkit/http-server/pds/server/crate.nix +++ b/hacking/cargo-manifest-sources/crates/examples/microkit/http-server/pds/server/crate.nix @@ -16,7 +16,7 @@ mk { smoltcp = smoltcpWith []; - async-unsync = { version = "0.2.2"; default-features = false; }; + async-unsync = { version = versions.async-unsync; default-features = false; }; sel4-newlib = { features = [ @@ -47,7 +47,7 @@ mk { sel4-async-single-threaded-executor sel4-async-network sel4-async-time - sel4-async-request-statuses + sel4-shared-ring-buffer-bookkeeping sel4-async-block-io-fat sel4-newlib sel4-bounce-buffer-allocator diff --git a/hacking/cargo-manifest-sources/crates/private/meta/crate.nix b/hacking/cargo-manifest-sources/crates/private/meta/crate.nix index ac26536cd..b4ea3311f 100644 --- a/hacking/cargo-manifest-sources/crates/private/meta/crate.nix +++ b/hacking/cargo-manifest-sources/crates/private/meta/crate.nix @@ -17,7 +17,6 @@ mk { sel4-async-block-io-cpiofs sel4-async-block-io-fat sel4-async-network - sel4-async-request-statuses sel4-async-single-threaded-executor sel4-async-time sel4-async-unsync @@ -30,6 +29,7 @@ mk { sel4-shared-ring-buffer sel4-shared-ring-buffer-block-io sel4-shared-ring-buffer-block-io-types + sel4-shared-ring-buffer-bookkeeping sel4-shared-ring-buffer-smoltcp sel4-sync ]; diff --git a/hacking/cargo-manifest-sources/crates/sel4-async/request-statuses/crate.nix b/hacking/cargo-manifest-sources/crates/sel4-async/request-statuses/crate.nix deleted file mode 100644 index d19ec35b0..000000000 --- a/hacking/cargo-manifest-sources/crates/sel4-async/request-statuses/crate.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ mk }: - -mk { - package.name = "sel4-async-request-statuses"; -} diff --git a/hacking/cargo-manifest-sources/crates/sel4-async/unsync/crate.nix b/hacking/cargo-manifest-sources/crates/sel4-async/unsync/crate.nix index 6c065b105..009a94aec 100644 --- a/hacking/cargo-manifest-sources/crates/sel4-async/unsync/crate.nix +++ b/hacking/cargo-manifest-sources/crates/sel4-async/unsync/crate.nix @@ -3,6 +3,6 @@ mk { package.name = "sel4-async-unsync"; dependencies = { - async-unsync = { version = "0.2.2"; default-features = false; }; + async-unsync = { version = versions.async-unsync; default-features = false; }; }; } diff --git a/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/block-io/crate.nix b/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/block-io/crate.nix index 905450b25..cf5664817 100644 --- a/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/block-io/crate.nix +++ b/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/block-io/crate.nix @@ -14,16 +14,18 @@ mk { ]; }; - async-unsync = { version = "0.2.2"; default-features = false; }; + async-unsync = { version = versions.async-unsync; default-features = false; }; sel4-externally-shared.features = [ "unstable" ]; + + sel4-shared-ring-buffer-bookkeeping = { features = [ "async-unsync" ]; }; }; nix.local.dependencies = with localCrates; [ sel4-externally-shared sel4-shared-ring-buffer sel4-shared-ring-buffer-block-io-types sel4-bounce-buffer-allocator - sel4-async-request-statuses + sel4-shared-ring-buffer-bookkeeping sel4-async-block-io ]; } diff --git a/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/bookkeeping/crate.nix b/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/bookkeeping/crate.nix new file mode 100644 index 000000000..e615ce6d4 --- /dev/null +++ b/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/bookkeeping/crate.nix @@ -0,0 +1,8 @@ +{ mk, versions }: + +mk { + package.name = "sel4-shared-ring-buffer-bookkeeping"; + dependencies = { + async-unsync = { version = versions.async-unsync; default-features = false; optional = true; }; + }; +} diff --git a/hacking/nix/scope/generated-cargo-manifests/default.nix b/hacking/nix/scope/generated-cargo-manifests/default.nix index c7e1943d4..422806b8d 100644 --- a/hacking/nix/scope/generated-cargo-manifests/default.nix +++ b/hacking/nix/scope/generated-cargo-manifests/default.nix @@ -82,6 +82,7 @@ let versions = { addr2line = "0.21.0"; anyhow = "1.0.66"; + async-unsync = "0.2.2"; cfg-if = "1.0.0"; clap = "4.4.6"; fallible-iterator = "0.2.0"; From eaf244ce41a79ca797cbc9ab15f3c13f6586bf7a Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Tue, 17 Oct 2023 11:31:43 +0000 Subject: [PATCH 02/12] crates/sel4-shared-ring-buffer/smoltcp: Improve modularity of API Signed-off-by: Nick Spinale --- .../http-server/pds/server/src/handler.rs | 4 +- .../http-server/pds/server/src/main.rs | 51 +++++++----- .../sel4-bounce-buffer-allocator/src/lib.rs | 3 +- .../smoltcp/src/inner.rs | 21 ++--- .../smoltcp/src/lib.rs | 78 +++++++++++-------- 5 files changed, 87 insertions(+), 70 deletions(-) diff --git a/crates/examples/microkit/http-server/pds/server/src/handler.rs b/crates/examples/microkit/http-server/pds/server/src/handler.rs index ef6650717..75c2a65b0 100644 --- a/crates/examples/microkit/http-server/pds/server/src/handler.rs +++ b/crates/examples/microkit/http-server/pds/server/src/handler.rs @@ -22,7 +22,7 @@ pub(crate) struct HandlerImpl { net_driver_channel: sel4_microkit::Channel, block_driver_channel: sel4_microkit::Channel, timer: TimerClient, - net_device: DeviceImpl, + net_device: DeviceImpl, shared_block_io: SharedRingBufferBlockIO, shared_timers: TimerManager, shared_network: ManagedInterface, @@ -37,7 +37,7 @@ impl HandlerImpl { net_driver_channel: sel4_microkit::Channel, block_driver_channel: sel4_microkit::Channel, timer: TimerClient, - mut net_device: DeviceImpl, + mut net_device: DeviceImpl, net_config: Config, shared_block_io: SharedRingBufferBlockIO, f: impl FnOnce(TimerManager, ManagedInterface, LocalSpawner) -> T, diff --git a/crates/examples/microkit/http-server/pds/server/src/main.rs b/crates/examples/microkit/http-server/pds/server/src/main.rs index 258381edf..403aaf764 100644 --- a/crates/examples/microkit/http-server/pds/server/src/main.rs +++ b/crates/examples/microkit/http-server/pds/server/src/main.rs @@ -79,27 +79,42 @@ fn init() -> impl Handler { let notify_net: fn() = || NET_DRIVER.notify(); let notify_block: fn() = || BLOCK_DRIVER.notify(); - let net_device = DeviceImpl::new( - unsafe { + let net_device = { + let dma_region = unsafe { ExternallySharedRef::<'static, _>::new( memory_region_symbol!(virtio_net_client_dma_vaddr: *mut [u8], n = *var!(virtio_net_client_dma_size: usize = 0)), ) - }, - *var!(virtio_net_client_dma_paddr: usize = 0), - RingBuffers::from_ptrs_using_default_initialization_strategy_for_role( - unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_rx_free: *mut _)) }, - unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_rx_used: *mut _)) }, - notify_net, - ), - RingBuffers::from_ptrs_using_default_initialization_strategy_for_role( - unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_tx_free: *mut _)) }, - unsafe { ExternallySharedRef::new(memory_region_symbol!(virtio_net_tx_used: *mut _)) }, - notify_net, - ), - 16, - 2048, - 1500, - ); + }; + + let bounce_buffer_allocator = + BounceBufferAllocator::new(Basic::new(dma_region.as_ptr().len()), 1); + + DeviceImpl::new( + dma_region, + bounce_buffer_allocator, + RingBuffers::from_ptrs_using_default_initialization_strategy_for_role( + unsafe { + ExternallySharedRef::new(memory_region_symbol!(virtio_net_rx_free: *mut _)) + }, + unsafe { + ExternallySharedRef::new(memory_region_symbol!(virtio_net_rx_used: *mut _)) + }, + notify_net, + ), + RingBuffers::from_ptrs_using_default_initialization_strategy_for_role( + unsafe { + ExternallySharedRef::new(memory_region_symbol!(virtio_net_tx_free: *mut _)) + }, + unsafe { + ExternallySharedRef::new(memory_region_symbol!(virtio_net_tx_used: *mut _)) + }, + notify_net, + ), + 16, + 2048, + 1500, + ) + }; let net_config = { assert_eq!(net_device.capabilities().medium, Medium::Ethernet); diff --git a/crates/sel4-bounce-buffer-allocator/src/lib.rs b/crates/sel4-bounce-buffer-allocator/src/lib.rs index 1dd155618..68d46a141 100644 --- a/crates/sel4-bounce-buffer-allocator/src/lib.rs +++ b/crates/sel4-bounce-buffer-allocator/src/lib.rs @@ -8,6 +8,7 @@ extern crate alloc; use core::alloc::Layout; +use core::fmt; use core::ops::Range; type Offset = usize; @@ -23,7 +24,7 @@ pub use bump::Bump; const MIN_ALLOCATION_SIZE: Size = 1; pub trait AbstractBounceBufferAllocator { - type Error; + type Error: fmt::Debug; fn allocate(&mut self, layout: Layout) -> Result; diff --git a/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs b/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs index d0770619b..f8a9dd23e 100644 --- a/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs +++ b/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs @@ -3,13 +3,13 @@ use core::alloc::Layout; use core::iter; use core::ops::Range; -use sel4_bounce_buffer_allocator::{Basic, BounceBufferAllocator}; +use sel4_bounce_buffer_allocator::{AbstractBounceBufferAllocator, BounceBufferAllocator}; use sel4_externally_shared::ExternallySharedRef; use sel4_shared_ring_buffer::{roles::Provide, Descriptor, RingBuffers, RING_BUFFER_SIZE}; -pub(crate) struct Inner { +pub(crate) struct Inner { dma_region: ExternallySharedRef<'static, [u8]>, - bounce_buffer_allocator: BounceBufferAllocator, + bounce_buffer_allocator: BounceBufferAllocator, rx_ring_buffers: RingBuffers<'static, Provide, fn()>, tx_ring_buffers: RingBuffers<'static, Provide, fn()>, rx_buffers: Vec, @@ -46,27 +46,16 @@ enum TxBufferState { Sent { range: Range }, } -impl Inner { +impl Inner { pub(crate) fn new( dma_region: ExternallySharedRef<'static, [u8]>, - dma_region_paddr: usize, + mut bounce_buffer_allocator: BounceBufferAllocator, mut rx_ring_buffers: RingBuffers<'static, Provide, fn()>, tx_ring_buffers: RingBuffers<'static, Provide, fn()>, num_rx_buffers: usize, rx_buffer_size: usize, mtu: usize, ) -> Self { - let max_alignment = 1 - << dma_region - .as_ptr() - .as_raw_ptr() - .addr() - .trailing_zeros() - .min(dma_region_paddr.trailing_zeros()); - - let mut bounce_buffer_allocator = - BounceBufferAllocator::new(Basic::new(dma_region.as_ptr().len()), max_alignment); - let rx_buffers = iter::repeat_with(|| RxBufferEntry { state: RxBufferState::Free, range: bounce_buffer_allocator diff --git a/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs b/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs index 39e2696d3..1327b7b27 100644 --- a/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs +++ b/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs @@ -10,6 +10,7 @@ use core::cell::RefCell; use smoltcp::phy::{self, Device, DeviceCapabilities}; use smoltcp::time::Instant; +use sel4_bounce_buffer_allocator::{AbstractBounceBufferAllocator, BounceBufferAllocator}; use sel4_externally_shared::ExternallySharedRef; use sel4_shared_ring_buffer::{roles::Provide, RingBuffers}; @@ -17,16 +18,22 @@ mod inner; use inner::{Inner, RxBufferIndex, TxBufferIndex}; -pub struct DeviceImpl { - shared_inner: SharedInner, +pub struct DeviceImpl { + inner: Rc>>, } -type SharedInner = Rc>; +impl Clone for DeviceImpl { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} -impl DeviceImpl { +impl DeviceImpl { pub fn new( dma_region: ExternallySharedRef<'static, [u8]>, - dma_region_paddr: usize, + bounce_buffer_allocator: BounceBufferAllocator, rx_ring_buffers: RingBuffers<'static, Provide, fn()>, tx_ring_buffers: RingBuffers<'static, Provide, fn()>, num_rx_buffers: usize, @@ -34,9 +41,9 @@ impl DeviceImpl { mtu: usize, ) -> Self { Self { - shared_inner: Rc::new(RefCell::new(Inner::new( + inner: Rc::new(RefCell::new(Inner::new( dma_region, - dma_region_paddr, + bounce_buffer_allocator, rx_ring_buffers, tx_ring_buffers, num_rx_buffers, @@ -46,47 +53,47 @@ impl DeviceImpl { } } - fn shared_inner(&self) -> &SharedInner { - &self.shared_inner + fn inner(&self) -> &Rc>> { + &self.inner } pub fn poll(&self) -> bool { - self.shared_inner().borrow_mut().poll() + self.inner().borrow_mut().poll() } - fn new_rx_token(&self, rx_buffer: RxBufferIndex) -> RxToken { + fn new_rx_token(&self, rx_buffer: RxBufferIndex) -> RxToken { RxToken { buffer: rx_buffer, - shared_inner: self.shared_inner().clone(), + shared: self.clone(), } } - fn new_tx_token(&self, tx_buffer: TxBufferIndex) -> TxToken { + fn new_tx_token(&self, tx_buffer: TxBufferIndex) -> TxToken { TxToken { buffer: tx_buffer, - shared_inner: self.shared_inner().clone(), + shared: self.clone(), } } } -impl Device for DeviceImpl { - type RxToken<'a> = RxToken; - type TxToken<'a> = TxToken; +impl Device for DeviceImpl { + type RxToken<'a> = RxToken where A: 'a; + type TxToken<'a> = TxToken where A: 'a; fn capabilities(&self) -> DeviceCapabilities { let mut cap = DeviceCapabilities::default(); - cap.max_transmission_unit = self.shared_inner().borrow().mtu(); + cap.max_transmission_unit = self.inner().borrow().mtu(); cap } fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { - let r = self.shared_inner().borrow_mut().receive(); + let r = self.inner().borrow_mut().receive(); r.ok() .map(|(rx_ix, tx_ix)| (self.new_rx_token(rx_ix), self.new_tx_token(tx_ix))) } fn transmit(&mut self, _timestamp: Instant) -> Option> { - self.shared_inner() + self.inner() .borrow_mut() .transmit() .ok() @@ -94,42 +101,47 @@ impl Device for DeviceImpl { } } -pub struct RxToken { +pub struct RxToken { buffer: RxBufferIndex, - shared_inner: SharedInner, + shared: DeviceImpl, } -impl phy::RxToken for RxToken { +impl phy::RxToken for RxToken { fn consume(self, f: F) -> R where F: FnOnce(&mut [u8]) -> R, { - // let r = self.shared_inner.borrow_mut().consume_rx(self.buffer, f); - let ptr = self.shared_inner.borrow_mut().consume_rx_start(self.buffer); + // let r = self.handle.inner().borrow_mut().consume_rx(self.buffer, f); + let ptr = self + .shared + .inner() + .borrow_mut() + .consume_rx_start(self.buffer); let r = f(unsafe { ptr.as_mut().unwrap() }); drop(self); r } } -impl Drop for RxToken { +impl Drop for RxToken { fn drop(&mut self) { - self.shared_inner.borrow_mut().drop_rx(self.buffer) + self.shared.inner().borrow_mut().drop_rx(self.buffer) } } -pub struct TxToken { +pub struct TxToken { buffer: TxBufferIndex, - shared_inner: SharedInner, + shared: DeviceImpl, } -impl phy::TxToken for TxToken { +impl phy::TxToken for TxToken { fn consume(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R, { let r = self - .shared_inner + .shared + .inner() .borrow_mut() .consume_tx(self.buffer, len, f); drop(self); @@ -137,8 +149,8 @@ impl phy::TxToken for TxToken { } } -impl Drop for TxToken { +impl Drop for TxToken { fn drop(&mut self) { - self.shared_inner.borrow_mut().drop_tx(self.buffer) + self.shared.inner().borrow_mut().drop_tx(self.buffer) } } From 70cd126aec1368dbe7c828a8beb45753439268b6 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Tue, 17 Oct 2023 11:36:56 +0000 Subject: [PATCH 03/12] crates/sel4-shared-ring-buffer/smoltcp: Clean up and reduce use of unsafe Signed-off-by: Nick Spinale --- .../smoltcp/src/inner.rs | 27 +++++++++---------- .../smoltcp/src/lib.rs | 14 +++------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs b/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs index f8a9dd23e..14e463fcc 100644 --- a/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs +++ b/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs @@ -2,6 +2,7 @@ use alloc::vec::Vec; use core::alloc::Layout; use core::iter; use core::ops::Range; +use core::ptr::NonNull; use sel4_bounce_buffer_allocator::{AbstractBounceBufferAllocator, BounceBufferAllocator}; use sel4_externally_shared::ExternallySharedRef; @@ -212,20 +213,17 @@ impl Inner { entry.state = TxBufferState::SlotClaimed; } - pub(crate) fn consume_rx_start(&mut self, index: RxBufferIndex) -> *mut [u8] { + pub(crate) fn consume_rx_start(&mut self, index: RxBufferIndex) -> NonNull<[u8]> { let entry = self.rx_buffer_entry_mut(index); let range = entry.range.clone(); let len = match entry.state { RxBufferState::Claimed { len } => len, _ => panic!(), }; - unsafe { - self.dma_region - .as_mut_ptr() - .index(range.start..range.start + len) - .as_raw_ptr() - .as_mut() - } + self.dma_region + .as_mut_ptr() + .index(range.start..range.start + len) + .as_raw_ptr() } pub(crate) fn drop_rx(&mut self, index: RxBufferIndex) { @@ -263,13 +261,12 @@ impl Inner { entry.state = TxBufferState::Sent { range: range.clone(), }; - let r = f(unsafe { - self.dma_region - .as_mut_ptr() - .index(range.clone()) - .as_raw_ptr() - .as_mut() - }); + let mut ptr = self + .dma_region + .as_mut_ptr() + .index(range.clone()) + .as_raw_ptr(); + let r = f(unsafe { ptr.as_mut() }); let desc = descriptor_of(range); self.tx_ring_buffers .free_mut() diff --git a/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs b/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs index 1327b7b27..5edf7960a 100644 --- a/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs +++ b/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs @@ -111,15 +111,12 @@ impl phy::RxToken for RxToken { where F: FnOnce(&mut [u8]) -> R, { - // let r = self.handle.inner().borrow_mut().consume_rx(self.buffer, f); - let ptr = self + let mut ptr = self .shared .inner() .borrow_mut() .consume_rx_start(self.buffer); - let r = f(unsafe { ptr.as_mut().unwrap() }); - drop(self); - r + f(unsafe { ptr.as_mut() }) } } @@ -139,13 +136,10 @@ impl phy::TxToken for TxToken { where F: FnOnce(&mut [u8]) -> R, { - let r = self - .shared + self.shared .inner() .borrow_mut() - .consume_tx(self.buffer, len, f); - drop(self); - r + .consume_tx(self.buffer, len, f) } } From 4af4237624d610f698083e136c7f422371e647c3 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Tue, 17 Oct 2023 11:45:46 +0000 Subject: [PATCH 04/12] crates/sel4-shared-ring-buffer/smoltcp: Add dependency On sel4-shared-ring-buffer-bookkeeping Signed-off-by: Nick Spinale --- Cargo.lock | 1 + crates/sel4-shared-ring-buffer/smoltcp/Cargo.toml | 1 + .../crates/sel4-shared-ring-buffer/smoltcp/crate.nix | 1 + 3 files changed, 3 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 348d6eb37..e09078ed5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4130,6 +4130,7 @@ dependencies = [ "sel4-bounce-buffer-allocator", "sel4-externally-shared", "sel4-shared-ring-buffer", + "sel4-shared-ring-buffer-bookkeeping", "smoltcp", ] diff --git a/crates/sel4-shared-ring-buffer/smoltcp/Cargo.toml b/crates/sel4-shared-ring-buffer/smoltcp/Cargo.toml index 6ccfe05f0..635024e9d 100644 --- a/crates/sel4-shared-ring-buffer/smoltcp/Cargo.toml +++ b/crates/sel4-shared-ring-buffer/smoltcp/Cargo.toml @@ -10,6 +10,7 @@ log = "0.4.17" sel4-bounce-buffer-allocator = { path = "../../sel4-bounce-buffer-allocator" } sel4-externally-shared = { path = "../../sel4-externally-shared", features = ["unstable"] } sel4-shared-ring-buffer = { path = ".." } +sel4-shared-ring-buffer-bookkeeping = { path = "../bookkeeping" } [dependencies.smoltcp] version = "0.10.0" diff --git a/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/smoltcp/crate.nix b/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/smoltcp/crate.nix index 7ac6d2b8e..a46857085 100644 --- a/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/smoltcp/crate.nix +++ b/hacking/cargo-manifest-sources/crates/sel4-shared-ring-buffer/smoltcp/crate.nix @@ -10,6 +10,7 @@ mk { nix.local.dependencies = with localCrates; [ sel4-externally-shared sel4-shared-ring-buffer + sel4-shared-ring-buffer-bookkeeping sel4-bounce-buffer-allocator ]; } From 8c0a26ab5554684a7fd2fdd7bd236b29a349b052 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Tue, 17 Oct 2023 11:47:57 +0000 Subject: [PATCH 05/12] Remove unecessary setvars in HTTP server system description Signed-off-by: Nick Spinale --- crates/examples/microkit/http-server/http-server.system | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/examples/microkit/http-server/http-server.system b/crates/examples/microkit/http-server/http-server.system index b41fb009e..854c32b8f 100644 --- a/crates/examples/microkit/http-server/http-server.system +++ b/crates/examples/microkit/http-server/http-server.system @@ -23,7 +23,6 @@ - @@ -32,7 +31,6 @@ - From 8668ce32bd6dff163493194af7b1f3f09d158190 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Tue, 17 Oct 2023 23:43:01 +0000 Subject: [PATCH 06/12] crates/sel4-shared-ring-buffer/bookkeeping: Improve API Signed-off-by: Nick Spinale --- crates/sel4-shared-ring-buffer/block-io/src/owned.rs | 6 +++--- .../bookkeeping/src/slot_tracker.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/sel4-shared-ring-buffer/block-io/src/owned.rs b/crates/sel4-shared-ring-buffer/block-io/src/owned.rs index 159241ce6..0a9b64dc2 100644 --- a/crates/sel4-shared-ring-buffer/block-io/src/owned.rs +++ b/crates/sel4-shared-ring-buffer/block-io/src/owned.rs @@ -225,7 +225,7 @@ impl } pub fn cancel_request(&mut self, request_index: usize) -> Result<(), ErrorOrUserError> { - let mut state_value = self.requests.get_state_value_mut(request_index)?; + let state_value = self.requests.get_state_value_mut(request_index)?; let occupied = state_value.as_occupied()?; match &occupied.state { OccupiedState::Pending { .. } => { @@ -267,7 +267,7 @@ impl buf: &mut PollRequestBuf, waker: Option, ) -> Result>, ErrorOrUserError> { - let mut state_value = self.requests.get_state_value_mut(request_index)?; + let state_value = self.requests.get_state_value_mut(request_index)?; let occupied = state_value.as_occupied()?; Ok(match &mut occupied.state { @@ -318,7 +318,7 @@ impl while let Some(completed_req) = self.ring_buffers.used_mut().dequeue()? { let request_index = completed_req.buf().cookie(); - let mut state_value = self + let state_value = self .requests .get_state_value_mut(request_index) .map_err(|_| PeerMisbehaviorError::OutOfBoundsCookie)?; diff --git a/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs index 102be73a3..332ce835b 100644 --- a/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs +++ b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs @@ -193,14 +193,14 @@ pub enum SlotStateValueRef<'a, T: SlotStateTypes> { } impl<'a, T: SlotStateTypes> SlotStateValueRef<'a, T> { - pub fn as_free(&self) -> Result<&T::Free> { + pub fn as_free(self) -> Result<&'a T::Free> { match self { Self::Free(r) => Ok(r), _ => Err(SlotTrackerError::StateMismatch), } } - pub fn as_occupied(&self) -> Result<&T::Occupied> { + pub fn as_occupied(self) -> Result<&'a T::Occupied> { match self { Self::Occupied(r) => Ok(r), _ => Err(SlotTrackerError::StateMismatch), @@ -215,14 +215,14 @@ pub enum SlotStateValueRefMut<'a, T: SlotStateTypes> { } impl<'a, T: SlotStateTypes> SlotStateValueRefMut<'a, T> { - pub fn as_free(&mut self) -> Result<&mut T::Free> { + pub fn as_free(self) -> Result<&'a mut T::Free> { match self { Self::Free(r) => Ok(r), _ => Err(SlotTrackerError::StateMismatch), } } - pub fn as_occupied(&mut self) -> Result<&mut T::Occupied> { + pub fn as_occupied(self) -> Result<&'a mut T::Occupied> { match self { Self::Occupied(r) => Ok(r), _ => Err(SlotTrackerError::StateMismatch), From 552cdc843fa758aa3c52335ca84923050fbbe6ae Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Tue, 17 Oct 2023 23:44:13 +0000 Subject: [PATCH 07/12] crates/sel4-shared-ring-buffer/bookkeeping: Expand API Signed-off-by: Nick Spinale --- .../bookkeeping/src/slot_tracker.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs index 332ce835b..8fb271fa8 100644 --- a/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs +++ b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs @@ -68,6 +68,31 @@ impl SlotTracker { Self::new(iter::repeat((common, free)).take(capacity)) } + pub fn new_occupied(iter: impl Iterator) -> Self { + let entries = iter + .map(|(v_common, v_occupied)| Entry { + common: v_common, + state: StateInternal::Occupied { value: v_occupied }, + }) + .collect(); + Self { + entries, + free_list_head_index: None, + num_free: 0, + } + } + + pub fn new_occupied_with_capacity( + common: T::Common, + occupied: T::Occupied, + capacity: usize, + ) -> Self + where + T: SlotStateTypes, + { + Self::new_occupied(iter::repeat((common, occupied)).take(capacity)) + } + pub fn capacity(&self) -> usize { self.entries.capacity() } @@ -84,6 +109,11 @@ impl SlotTracker { self.free_list_head_index } + pub fn peek_next_free_value(&self) -> Option<&T::Free> { + let index = self.peek_next_free_index()?; + Some(self.get_state_value(index).unwrap().as_free().unwrap()) + } + fn get_entry(&self, index: usize) -> Result<&Entry> { self.entries.get(index).ok_or(SlotTrackerError::OutOfBounds) } From 613c4ecf025fd6cf9809373be03f2e1ea8d83173 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Wed, 18 Oct 2023 00:07:02 +0000 Subject: [PATCH 08/12] crates/sel4-shared-ring-buffer/bookkeeping: Fix num_free() Signed-off-by: Nick Spinale --- .../bookkeeping/src/slot_tracker.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs index 8fb271fa8..fcd0851b1 100644 --- a/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs +++ b/crates/sel4-shared-ring-buffer/bookkeeping/src/slot_tracker.rs @@ -166,16 +166,22 @@ impl SlotTracker { unreachable!() } }; + self.num_free -= 1; Some((index, value)) } pub fn free(&mut self, index: usize, value: T::Free) -> Result { self.ensure_state(index, SlotState::Occupied)?; - let old_state = self.replace_state_with_free(index, value); + let new_state = StateInternal::Free { + free_list_next_index: self.free_list_head_index.replace(index), + value, + }; + let old_state = self.replace_state(index, new_state); let value = match old_state { StateInternal::Occupied { value } => value, _ => unreachable!(), }; + self.num_free += 1; Ok(value) } @@ -190,14 +196,6 @@ impl SlotTracker { fn replace_state(&mut self, index: usize, new_state: StateInternal) -> StateInternal { mem::replace(&mut self.get_entry_mut(index).unwrap().state, new_state) } - - fn replace_state_with_free(&mut self, index: usize, value: T::Free) -> StateInternal { - let new_state = StateInternal::Free { - free_list_next_index: self.free_list_head_index.replace(index), - value, - }; - self.replace_state(index, new_state) - } } #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] From 4266a8ae3b4861becac41b16998cda7ccc556694 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Tue, 17 Oct 2023 22:01:51 +0000 Subject: [PATCH 09/12] crates/sel4-shared-ring-buffer/smoltcp: Use sel4-sharedd-ring-buffer-bookkeeping Signed-off-by: Nick Spinale --- .../http-server/pds/server/src/main.rs | 1 + .../smoltcp/src/inner.rs | 363 ++++++++++-------- .../smoltcp/src/lib.rs | 29 +- 3 files changed, 218 insertions(+), 175 deletions(-) diff --git a/crates/examples/microkit/http-server/pds/server/src/main.rs b/crates/examples/microkit/http-server/pds/server/src/main.rs index 403aaf764..9e6b2c656 100644 --- a/crates/examples/microkit/http-server/pds/server/src/main.rs +++ b/crates/examples/microkit/http-server/pds/server/src/main.rs @@ -114,6 +114,7 @@ fn init() -> impl Handler { 2048, 1500, ) + .unwrap() }; let net_config = { diff --git a/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs b/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs index 14e463fcc..099b0dfdd 100644 --- a/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs +++ b/crates/sel4-shared-ring-buffer/smoltcp/src/inner.rs @@ -1,49 +1,54 @@ -use alloc::vec::Vec; use core::alloc::Layout; -use core::iter; use core::ops::Range; use core::ptr::NonNull; use sel4_bounce_buffer_allocator::{AbstractBounceBufferAllocator, BounceBufferAllocator}; use sel4_externally_shared::ExternallySharedRef; -use sel4_shared_ring_buffer::{roles::Provide, Descriptor, RingBuffers, RING_BUFFER_SIZE}; +use sel4_shared_ring_buffer::{ + roles::Provide, Descriptor, PeerMisbehaviorError as SharedRingBuffersPeerMisbehaviorError, + RingBuffers, +}; +use sel4_shared_ring_buffer_bookkeeping::slot_tracker::*; pub(crate) struct Inner { dma_region: ExternallySharedRef<'static, [u8]>, bounce_buffer_allocator: BounceBufferAllocator, rx_ring_buffers: RingBuffers<'static, Provide, fn()>, tx_ring_buffers: RingBuffers<'static, Provide, fn()>, - rx_buffers: Vec, - tx_buffers: Vec, + rx_buffers: SlotTracker, + tx_buffers: SlotTracker, mtu: usize, } pub(crate) type RxBufferIndex = usize; -#[derive(Clone, Debug, Eq, PartialEq)] -struct RxBufferEntry { - state: RxBufferState, - range: Range, +enum RxStateTypesImpl {} + +impl SlotStateTypes for RxStateTypesImpl { + type Common = Descriptor; + type Free = RxFree; + type Occupied = RxOccupied; +} + +struct RxFree { + len: usize, } -#[derive(Clone, Debug, Eq, PartialEq)] -enum RxBufferState { - Free, - Used { len: usize }, +enum RxOccupied { + Waiting, Claimed { len: usize }, } pub(crate) type TxBufferIndex = usize; -#[derive(Clone, Debug, Eq, PartialEq)] -struct TxBufferEntry { - state: TxBufferState, +enum TxStateTypesImpl {} + +impl SlotStateTypes for TxStateTypesImpl { + type Occupied = TxOccupied; } -#[derive(Clone, Debug, Eq, PartialEq)] -enum TxBufferState { - Unclaimed, - SlotClaimed, +enum TxOccupied { + Claimed, Sent { range: Range }, } @@ -56,30 +61,24 @@ impl Inner { num_rx_buffers: usize, rx_buffer_size: usize, mtu: usize, - ) -> Self { - let rx_buffers = iter::repeat_with(|| RxBufferEntry { - state: RxBufferState::Free, - range: bounce_buffer_allocator + ) -> Result { + let rx_buffers = SlotTracker::new_occupied((0..num_rx_buffers).map(|i| { + let range = bounce_buffer_allocator .allocate(Layout::from_size_align(rx_buffer_size, 1).unwrap()) - .unwrap(), - }) - .take(num_rx_buffers) - .collect::>(); - - for entry in rx_buffers.iter() { + .map_err(|_| Error::BounceBufferAllocationError) + .unwrap(); + let desc = Descriptor::from_encoded_addr_range(range, i); rx_ring_buffers .free_mut() - .enqueue_and_commit(descriptor_of(entry.range.clone())) + .enqueue_and_commit(desc) .unwrap() .unwrap(); - } - let tx_buffers = iter::repeat_with(|| TxBufferEntry { - state: TxBufferState::Unclaimed, - }) - .take(RING_BUFFER_SIZE) - .collect::>(); + (desc, RxOccupied::Waiting) + })); - Self { + let tx_buffers = SlotTracker::new_with_capacity((), (), tx_ring_buffers.free().capacity()); + + Ok(Self { dma_region, bounce_buffer_allocator, rx_ring_buffers, @@ -87,25 +86,45 @@ impl Inner { rx_buffers, tx_buffers, mtu, - } + }) } pub(crate) fn mtu(&self) -> usize { self.mtu } - pub(crate) fn poll(&mut self) -> bool { + pub(crate) fn poll(&mut self) -> Result { let mut notify_rx = false; - while let Some(desc) = self.rx_ring_buffers.used_mut().dequeue().unwrap() { - let ix = self - .lookup_rx_buffer_by_encoded_addr(desc.encoded_addr()) + while let Some(desc) = self.rx_ring_buffers.used_mut().dequeue()? { + let ix = desc.cookie(); + if !(ix < self.rx_buffers.capacity()) { + return Err(PeerMisbehaviorError::OutOfBoundsCookie); + } + + let provided_desc = self.rx_buffers.get_common_value(ix).unwrap(); + if desc.encoded_addr() != provided_desc.encoded_addr() + || desc.len() > provided_desc.len() + { + return Err(PeerMisbehaviorError::DescriptorMismatch); + } + + if !matches!( + self.rx_buffers.get_state_value(ix).unwrap(), + SlotStateValueRef::Occupied(RxOccupied::Waiting) + ) { + return Err(PeerMisbehaviorError::StateMismatch); + } + + self.rx_buffers + .free( + ix, + RxFree { + len: desc.encoded_addr_range().len(), + }, + ) .unwrap(); - let entry = self.rx_buffer_entry_mut(ix); - assert_eq!(entry.state, RxBufferState::Free); - entry.state = RxBufferState::Used { - len: desc.len().try_into().unwrap(), - }; + notify_rx = true; } @@ -115,17 +134,25 @@ impl Inner { let mut notify_tx = false; - while let Some(desc) = self.tx_ring_buffers.used_mut().dequeue().unwrap() { - let ix = self.lookup_tx_buffer_by_descriptor(&desc).unwrap(); - let entry = self.tx_buffer_entry_mut(ix); - let range = match &entry.state { - TxBufferState::Sent { range } => range.clone(), + while let Some(desc) = self.tx_ring_buffers.used_mut().dequeue()? { + let ix = desc.cookie(); + + let state_value = self + .tx_buffers + .get_state_value(ix) + .map_err(|_| PeerMisbehaviorError::OutOfBoundsCookie)?; + + match state_value { + SlotStateValueRef::Occupied(TxOccupied::Sent { range }) => { + self.bounce_buffer_allocator.deallocate(range.clone()); + } _ => { - panic!() + return Err(PeerMisbehaviorError::StateMismatch); } - }; - entry.state = TxBufferState::Unclaimed; - self.bounce_buffer_allocator.deallocate(range); + } + + self.tx_buffers.free(ix, ()).unwrap(); + notify_tx = true; } @@ -133,165 +160,171 @@ impl Inner { self.tx_ring_buffers.notify(); } - notify_rx || notify_tx + Ok(notify_rx || notify_tx) } - fn lookup_rx_buffer_by_encoded_addr(&self, encoded_addr: usize) -> Option { - self.rx_buffers - .iter() - .enumerate() - .find(|(_i, entry)| entry.range.start == encoded_addr) - .map(|(i, _entry)| i) - } - - fn lookup_tx_buffer_by_descriptor(&self, desc: &Descriptor) -> Option { - self.tx_buffers - .iter() - .enumerate() - .find(|(_i, entry)| match &entry.state { - TxBufferState::Sent { range } => &descriptor_of(range.clone()) == desc, - _ => false, - }) - .map(|(i, _entry)| i) - } - - fn rx_buffer_entry_mut(&mut self, index: RxBufferIndex) -> &mut RxBufferEntry { - &mut self.rx_buffers[index] - } - - fn tx_buffer_entry_mut(&mut self, index: TxBufferIndex) -> &mut TxBufferEntry { - &mut self.tx_buffers[index] - } - - pub(crate) fn receive(&mut self) -> Result<(RxBufferIndex, TxBufferIndex), ()> { - if let (Some(rx), Some(tx)) = (self.can_claim_rx_buffer(), self.can_claim_tx_buffer()) { - self.claim_rx_buffer(rx); - self.claim_tx_buffer(tx); - Ok((rx, tx)) + pub(crate) fn receive(&mut self) -> Option<(RxBufferIndex, TxBufferIndex)> { + if self.can_claim_rx_buffer() && self.can_claim_tx_buffer() { + let rx = self.claim_rx_buffer().unwrap(); + let tx = self.claim_tx_buffer().unwrap(); + Some((rx, tx)) } else { - Err(()) + None } } - pub(crate) fn transmit(&mut self) -> Result { - self.can_claim_tx_buffer() - .map(|index| { - self.claim_tx_buffer(index); - index - }) - .ok_or(()) + pub(crate) fn transmit(&mut self) -> Option { + self.claim_tx_buffer() } - fn can_claim_rx_buffer(&self) -> Option { - self.rx_buffers - .iter() - .enumerate() - .find(|(_i, entry)| matches!(entry.state, RxBufferState::Used { .. })) - .map(|(i, _entry)| i) + fn can_claim_rx_buffer(&self) -> bool { + self.rx_buffers.num_free() > 0 } - fn claim_rx_buffer(&mut self, index: RxBufferIndex) { - let entry = self.rx_buffer_entry_mut(index); - let len = match entry.state { - RxBufferState::Used { len } => len, - _ => panic!(), - }; - entry.state = RxBufferState::Claimed { len }; + fn claim_rx_buffer(&mut self) -> Option { + let len = self.rx_buffers.peek_next_free_value()?.len; + let (ix, _) = self.rx_buffers.occupy(RxOccupied::Claimed { len }).unwrap(); + Some(ix) } - fn can_claim_tx_buffer(&self) -> Option { - self.tx_buffers - .iter() - .enumerate() - .find(|(_i, entry)| entry.state == TxBufferState::Unclaimed) - .map(|(i, _entry)| i) + fn can_claim_tx_buffer(&self) -> bool { + self.tx_buffers.num_free() > 0 } - fn claim_tx_buffer(&mut self, index: TxBufferIndex) { - let entry = self.tx_buffer_entry_mut(index); - assert_eq!(entry.state, TxBufferState::Unclaimed); - entry.state = TxBufferState::SlotClaimed; + fn claim_tx_buffer(&mut self) -> Option { + let (ix, _) = self.tx_buffers.occupy(TxOccupied::Claimed)?; + Some(ix) } pub(crate) fn consume_rx_start(&mut self, index: RxBufferIndex) -> NonNull<[u8]> { - let entry = self.rx_buffer_entry_mut(index); - let range = entry.range.clone(); - let len = match entry.state { - RxBufferState::Claimed { len } => len, + let desc = self.rx_buffers.get_common_value(index).unwrap(); + let start = desc.encoded_addr_range().start; + let len = match self + .rx_buffers + .get_state_value(index) + .unwrap() + .as_occupied() + .unwrap() + { + RxOccupied::Claimed { len } => len, _ => panic!(), }; self.dma_region .as_mut_ptr() - .index(range.start..range.start + len) + .index(start..(start + len)) .as_raw_ptr() } - pub(crate) fn drop_rx(&mut self, index: RxBufferIndex) { - let entry = self.rx_buffer_entry_mut(index); - let state = entry.state.clone(); - match state { - RxBufferState::Used { .. } => {} - RxBufferState::Claimed { .. } => { - entry.state = RxBufferState::Free; - let range = entry.range.clone(); - let desc = descriptor_of(range); - self.rx_ring_buffers - .free_mut() - .enqueue_and_commit(desc) - .unwrap() - .unwrap(); - self.rx_ring_buffers.notify(); - } - _ => { - panic!() - } - } + pub(crate) fn consume_rx_finish(&mut self, _index: RxBufferIndex) { + // nothing to do, for now } - pub(crate) fn consume_tx(&mut self, index: TxBufferIndex, len: usize, f: F) -> R + pub(crate) fn drop_rx(&mut self, index: RxBufferIndex) -> Result<(), PeerMisbehaviorError> { + let occupied = self + .rx_buffers + .get_state_value_mut(index) + .unwrap() + .as_occupied() + .unwrap(); + assert!(matches!(occupied, RxOccupied::Claimed { .. })); + *occupied = RxOccupied::Waiting; + let desc = self.rx_buffers.get_common_value(index).unwrap(); + self.rx_ring_buffers + .free_mut() + .enqueue_and_commit(*desc)? + .unwrap(); + self.rx_ring_buffers.notify(); + Ok(()) + } + + pub(crate) fn consume_tx( + &mut self, + index: TxBufferIndex, + len: usize, + f: F, + ) -> Result where F: FnOnce(&mut [u8]) -> R, { let range = self .bounce_buffer_allocator .allocate(Layout::from_size_align(len, 1).unwrap()) + .map_err(|_| Error::BounceBufferAllocationError)?; + + let occupied = self + .tx_buffers + .get_state_value_mut(index) + .unwrap() + .as_occupied() .unwrap(); - let entry = self.tx_buffer_entry_mut(index); - assert_eq!(entry.state, TxBufferState::SlotClaimed); - entry.state = TxBufferState::Sent { + assert!(matches!(occupied, TxOccupied::Claimed { .. })); + *occupied = TxOccupied::Sent { range: range.clone(), }; + let mut ptr = self .dma_region .as_mut_ptr() .index(range.clone()) .as_raw_ptr(); let r = f(unsafe { ptr.as_mut() }); - let desc = descriptor_of(range); + + let desc = Descriptor::from_encoded_addr_range(range, index); self.tx_ring_buffers .free_mut() - .enqueue_and_commit(desc) - .unwrap() + .enqueue_and_commit(desc)? .unwrap(); self.tx_ring_buffers.notify(); - r + + Ok(r) } pub(crate) fn drop_tx(&mut self, index: TxBufferIndex) { - let entry = self.tx_buffer_entry_mut(index); - let state = entry.state.clone(); - match state { - TxBufferState::SlotClaimed => { - entry.state = TxBufferState::Unclaimed; - } - TxBufferState::Sent { .. } => {} - _ => { - panic!() + let occupied = self + .tx_buffers + .get_state_value(index) + .unwrap() + .as_occupied() + .unwrap(); + match occupied { + TxOccupied::Claimed => { + self.tx_buffers.free(index, ()).unwrap(); } + TxOccupied::Sent { .. } => {} } } } -fn descriptor_of(range: Range) -> Descriptor { - Descriptor::from_encoded_addr_range(range, 0) +// // // + +#[derive(Debug, Clone)] +pub enum Error { + BounceBufferAllocationError, + PeerMisbehaviorError(PeerMisbehaviorError), +} + +#[derive(Debug, Clone)] +pub enum PeerMisbehaviorError { + DescriptorMismatch, + OutOfBoundsCookie, + StateMismatch, + SharedRingBuffersPeerMisbehaviorError(SharedRingBuffersPeerMisbehaviorError), +} + +impl From for Error { + fn from(err: PeerMisbehaviorError) -> Self { + Self::PeerMisbehaviorError(err) + } +} + +impl From for PeerMisbehaviorError { + fn from(err: SharedRingBuffersPeerMisbehaviorError) -> Self { + Self::SharedRingBuffersPeerMisbehaviorError(err) + } +} + +impl From for Error { + fn from(err: SharedRingBuffersPeerMisbehaviorError) -> Self { + PeerMisbehaviorError::from(err).into() + } } diff --git a/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs b/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs index 5edf7960a..65e2c1487 100644 --- a/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs +++ b/crates/sel4-shared-ring-buffer/smoltcp/src/lib.rs @@ -16,6 +16,7 @@ use sel4_shared_ring_buffer::{roles::Provide, RingBuffers}; mod inner; +pub use inner::{Error, PeerMisbehaviorError}; use inner::{Inner, RxBufferIndex, TxBufferIndex}; pub struct DeviceImpl { @@ -39,8 +40,8 @@ impl DeviceImpl { num_rx_buffers: usize, rx_buffer_size: usize, mtu: usize, - ) -> Self { - Self { + ) -> Result { + Ok(Self { inner: Rc::new(RefCell::new(Inner::new( dma_region, bounce_buffer_allocator, @@ -49,8 +50,8 @@ impl DeviceImpl { num_rx_buffers, rx_buffer_size, mtu, - ))), - } + )?)), + }) } fn inner(&self) -> &Rc>> { @@ -58,7 +59,7 @@ impl DeviceImpl { } pub fn poll(&self) -> bool { - self.inner().borrow_mut().poll() + self.inner().borrow_mut().poll().unwrap() } fn new_rx_token(&self, rx_buffer: RxBufferIndex) -> RxToken { @@ -88,15 +89,13 @@ impl Device for DeviceImpl { fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { let r = self.inner().borrow_mut().receive(); - r.ok() - .map(|(rx_ix, tx_ix)| (self.new_rx_token(rx_ix), self.new_tx_token(tx_ix))) + r.map(|(rx_ix, tx_ix)| (self.new_rx_token(rx_ix), self.new_tx_token(tx_ix))) } fn transmit(&mut self, _timestamp: Instant) -> Option> { self.inner() .borrow_mut() .transmit() - .ok() .map(|ix| self.new_tx_token(ix)) } } @@ -116,13 +115,22 @@ impl phy::RxToken for RxToken { .inner() .borrow_mut() .consume_rx_start(self.buffer); - f(unsafe { ptr.as_mut() }) + let r = f(unsafe { ptr.as_mut() }); + self.shared + .inner() + .borrow_mut() + .consume_rx_finish(self.buffer); + r } } impl Drop for RxToken { fn drop(&mut self) { - self.shared.inner().borrow_mut().drop_rx(self.buffer) + self.shared + .inner() + .borrow_mut() + .drop_rx(self.buffer) + .unwrap() } } @@ -140,6 +148,7 @@ impl phy::TxToken for TxToken { .inner() .borrow_mut() .consume_tx(self.buffer, len, f) + .unwrap() } } From a2a878c8bf88b648c1e7d89755c85acc562e298f Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Wed, 18 Oct 2023 04:37:49 +0000 Subject: [PATCH 10/12] crates/sel4-async/block-io: Support writes Signed-off-by: Nick Spinale --- .../http-server/pds/server/core/src/lib.rs | 8 +- .../http-server/pds/server/src/handler.rs | 6 +- .../http-server/pds/server/src/main.rs | 2 +- .../block-io/fat/src/block_io_wrapper.rs | 53 ++- crates/sel4-async/block-io/src/access.rs | 73 +++++ crates/sel4-async/block-io/src/disk.rs | 6 +- crates/sel4-async/block-io/src/lib.rs | 305 +++++++++++++++--- crates/sel4-async/block-io/src/operation.rs | 200 ++++++++++++ crates/sel4-async/block-io/src/when_alloc.rs | 86 +++-- .../block-io/src/lib.rs | 65 ++-- .../block-io/src/owned.rs | 44 ++- 11 files changed, 708 insertions(+), 140 deletions(-) create mode 100644 crates/sel4-async/block-io/src/access.rs create mode 100644 crates/sel4-async/block-io/src/operation.rs diff --git a/crates/examples/microkit/http-server/pds/server/core/src/lib.rs b/crates/examples/microkit/http-server/pds/server/core/src/lib.rs index 927a1d4fc..a51db03d9 100644 --- a/crates/examples/microkit/http-server/pds/server/core/src/lib.rs +++ b/crates/examples/microkit/http-server/pds/server/core/src/lib.rs @@ -12,7 +12,7 @@ use futures::task::LocalSpawnExt; use mbedtls::ssl::async_io::ClosedError; -use sel4_async_block_io::{constant_block_sizes, BlockIO}; +use sel4_async_block_io::{access::ReadOnly, constant_block_sizes, BlockIO}; use sel4_async_block_io_fat as fat; use sel4_async_network::{ManagedInterface, TcpSocketError}; use sel4_async_network_mbedtls::{ @@ -29,7 +29,9 @@ use server::Server; const HTTP_PORT: u16 = 80; const HTTPS_PORT: u16 = 443; -pub async fn run_server + Clone>( +pub async fn run_server< + T: BlockIO + Clone, +>( _timers_ctx: TimerManager, network_ctx: ManagedInterface, fs_block_io: T, @@ -101,7 +103,7 @@ pub async fn run_server = Box< dyn Fn( - Server, fat::DummyTimeSource>, + Server, fat::DummyTimeSource>, TcpSocketWrapper, ) -> LocalBoxFuture<'static, ()>, >; diff --git a/crates/examples/microkit/http-server/pds/server/src/handler.rs b/crates/examples/microkit/http-server/pds/server/src/handler.rs index 75c2a65b0..e19ec5838 100644 --- a/crates/examples/microkit/http-server/pds/server/src/handler.rs +++ b/crates/examples/microkit/http-server/pds/server/src/handler.rs @@ -8,7 +8,7 @@ use futures::future::LocalBoxFuture; use smoltcp::iface::Config; use smoltcp::time::Instant as SmoltcpInstant; -use sel4_async_block_io::constant_block_sizes::BlockSize512; +use sel4_async_block_io::{access::ReadOnly, constant_block_sizes::BlockSize512}; use sel4_async_network::{DhcpOverrides, ManagedInterface}; use sel4_async_single_threaded_executor::{LocalPool, LocalSpawner}; use sel4_async_time::{Instant, TimerManager}; @@ -23,7 +23,7 @@ pub(crate) struct HandlerImpl { block_driver_channel: sel4_microkit::Channel, timer: TimerClient, net_device: DeviceImpl, - shared_block_io: SharedRingBufferBlockIO, + shared_block_io: SharedRingBufferBlockIO, shared_timers: TimerManager, shared_network: ManagedInterface, local_pool: LocalPool, @@ -39,7 +39,7 @@ impl HandlerImpl { timer: TimerClient, mut net_device: DeviceImpl, net_config: Config, - shared_block_io: SharedRingBufferBlockIO, + shared_block_io: SharedRingBufferBlockIO, f: impl FnOnce(TimerManager, ManagedInterface, LocalSpawner) -> T, ) -> Self { let now = Self::now_with_timer_client(&timer); diff --git a/crates/examples/microkit/http-server/pds/server/src/main.rs b/crates/examples/microkit/http-server/pds/server/src/main.rs index 9e6b2c656..fc8e8569b 100644 --- a/crates/examples/microkit/http-server/pds/server/src/main.rs +++ b/crates/examples/microkit/http-server/pds/server/src/main.rs @@ -139,7 +139,7 @@ fn init() -> impl Handler { BounceBufferAllocator::new(Basic::new(dma_region.as_ptr().len()), 1); SharedRingBufferBlockIO::new( - BlockSize512::SINGLETON, + BlockSize512::BLOCK_SIZE, num_blocks, dma_region, bounce_buffer_allocator, diff --git a/crates/sel4-async/block-io/fat/src/block_io_wrapper.rs b/crates/sel4-async/block-io/fat/src/block_io_wrapper.rs index 975d63b6a..8db7db0c3 100644 --- a/crates/sel4-async/block-io/fat/src/block_io_wrapper.rs +++ b/crates/sel4-async/block-io/fat/src/block_io_wrapper.rs @@ -1,21 +1,30 @@ +use core::marker::PhantomData; + use futures::future; -use sel4_async_block_io::{constant_block_sizes, BlockIO}; +use sel4_async_block_io::{ + access::{Access, Witness}, + constant_block_sizes, BlockIO, Operation, +}; pub use embedded_fat as fat; -pub struct BlockIOWrapper { +pub struct BlockIOWrapper { inner: T, + _phantom: PhantomData, } -impl BlockIOWrapper { +impl BlockIOWrapper { pub fn new(inner: T) -> Self { - Self { inner } + Self { + inner, + _phantom: PhantomData, + } } } -impl> fat::BlockDevice - for BlockIOWrapper +impl, A: Access> fat::BlockDevice + for BlockIOWrapper { type Error = !; @@ -30,7 +39,15 @@ impl> fat::BlockDevic .unwrap() .checked_add(i.try_into().unwrap()) .unwrap(); - self.inner.read_blocks(block_idx, &mut block.contents).await + self.inner + .read_or_write_blocks( + block_idx, + Operation::Read { + buf: &mut block.contents, + witness: A::ReadWitness::TRY_WITNESS.unwrap(), + }, + ) + .await })) .await; Ok(()) @@ -38,10 +55,26 @@ impl> fat::BlockDevic async fn write( &self, - _blocks: &[fat::Block], - _start_block_idx: fat::BlockIdx, + blocks: &[fat::Block], + start_block_idx: fat::BlockIdx, ) -> Result<(), Self::Error> { - panic!() + future::join_all(blocks.iter().enumerate().map(|(i, block)| async move { + let block_idx = u64::try_from(start_block_idx.0) + .unwrap() + .checked_add(i.try_into().unwrap()) + .unwrap(); + self.inner + .read_or_write_blocks( + block_idx, + Operation::Write { + buf: &block.contents, + witness: A::WriteWitness::TRY_WITNESS.unwrap(), + }, + ) + .await + })) + .await; + Ok(()) } async fn num_blocks(&self) -> Result { diff --git a/crates/sel4-async/block-io/src/access.rs b/crates/sel4-async/block-io/src/access.rs new file mode 100644 index 000000000..9a2a7ac7c --- /dev/null +++ b/crates/sel4-async/block-io/src/access.rs @@ -0,0 +1,73 @@ +pub trait Access: AccessSealed { + type ReadWitness: Witness; + type WriteWitness: Witness; +} + +pub trait Witness: Sized + Copy + Unpin { + const TRY_WITNESS: Option; +} + +impl Witness for () { + const TRY_WITNESS: Option = Some(()); +} + +impl Witness for ! { + const TRY_WITNESS: Option = None; +} + +pub trait ReadAccess: Access { + const READ_WITNESS: Self::ReadWitness; +} + +pub trait WriteAccess: Access { + const WRITE_WITNESS: Self::WriteWitness; +} + +use sealing::AccessSealed; + +mod sealing { + use super::{ReadOnly, ReadWrite, WriteOnly}; + + pub trait AccessSealed {} + + impl AccessSealed for ReadOnly {} + impl AccessSealed for WriteOnly {} + impl AccessSealed for ReadWrite {} +} + +pub enum ReadOnly {} + +impl Access for ReadOnly { + type ReadWitness = (); + type WriteWitness = !; +} + +impl ReadAccess for ReadOnly { + const READ_WITNESS: Self::ReadWitness = (); +} + +pub enum WriteOnly {} + +impl Access for WriteOnly { + type ReadWitness = !; + type WriteWitness = (); +} + +impl WriteAccess for WriteOnly { + const WRITE_WITNESS: Self::WriteWitness = (); +} + +pub enum ReadWrite {} + +impl Access for ReadWrite { + type ReadWitness = (); + type WriteWitness = (); +} + +impl ReadAccess for ReadWrite { + const READ_WITNESS: Self::ReadWitness = (); +} + +impl WriteAccess for ReadWrite { + const WRITE_WITNESS: Self::WriteWitness = (); +} diff --git a/crates/sel4-async/block-io/src/disk.rs b/crates/sel4-async/block-io/src/disk.rs index 664c7e453..d10ce1ce4 100644 --- a/crates/sel4-async/block-io/src/disk.rs +++ b/crates/sel4-async/block-io/src/disk.rs @@ -4,7 +4,7 @@ use core::ops::Range; use gpt_disk_types::{GptHeader, MasterBootRecord, MbrPartitionRecord}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -use crate::{read_bytes, BlockIO, Partition}; +use crate::{access::ReadOnly, read_bytes, BlockIO, Partition}; pub struct Disk { io: T, @@ -88,7 +88,7 @@ impl From for PartitionId { } } -impl Disk { +impl> Disk { pub fn new(io: T) -> Self { Self { io } } @@ -110,7 +110,7 @@ impl Disk { } } -impl Disk { +impl> Disk { pub fn partition_using_mbr(self, entry: &MbrPartitionEntry) -> Partition { Partition::new(self.io, entry.lba_range()) } diff --git a/crates/sel4-async/block-io/src/lib.rs b/crates/sel4-async/block-io/src/lib.rs index 34d0c0df2..540a277ff 100644 --- a/crates/sel4-async/block-io/src/lib.rs +++ b/crates/sel4-async/block-io/src/lib.rs @@ -9,20 +9,28 @@ #[cfg(feature = "alloc")] extern crate alloc; +use core::cell::RefCell; use core::fmt; use core::ops::Range; use futures::future; +pub mod access; pub mod disk; +mod operation; + +pub use operation::{Operation, OperationType}; + +use access::{Access, ReadAccess, ReadOnly, ReadWrite, WriteAccess}; + #[cfg(feature = "alloc")] mod when_alloc; #[cfg(feature = "alloc")] pub use when_alloc::{CachedBlockIO, DynamicBlockSize}; -pub trait BlockIO { +pub trait BlockIOLayout { type Error: fmt::Debug; type BlockSize: BlockSize; @@ -30,12 +38,41 @@ pub trait BlockIO { fn block_size(&self) -> Self::BlockSize; fn num_blocks(&self) -> u64; +} - async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error>; +pub trait BlockIO: BlockIOLayout { + async fn read_or_write_blocks( + &self, + start_block_idx: u64, + operation: Operation<'_, A>, + ) -> Result<(), Self::Error>; + + async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error> + where + A: ReadAccess, + { + self.read_or_write_blocks( + start_block_idx, + Operation::Read { + buf, + witness: A::READ_WITNESS, + }, + ) + .await + } - // TODO - async fn write_blocks(&self, _start_block_idx: u64, _buf: &[u8]) -> Result<(), Self::Error> { - unimplemented!() + async fn write_blocks(&self, start_block_idx: u64, buf: &[u8]) -> Result<(), Self::Error> + where + A: WriteAccess, + { + self.read_or_write_blocks( + start_block_idx, + Operation::Write { + buf, + witness: A::WRITE_WITNESS, + }, + ) + .await } } @@ -52,7 +89,7 @@ pub trait BlockSize { } pub trait ConstantBlockSize: BlockSize { - const SINGLETON: Self; + const BLOCK_SIZE: Self; const BYTES: usize; } @@ -86,7 +123,7 @@ pub mod constant_block_sizes { } impl ConstantBlockSize for $ident { - const SINGLETON: Self = $ident; + const BLOCK_SIZE: Self = $ident; const BYTES: usize = $n; } @@ -117,6 +154,30 @@ pub mod constant_block_sizes { declare_next_block_size!(BlockSize4096, BlockSize8192); } +impl BlockIOLayout for &T { + type Error = T::Error; + + type BlockSize = T::BlockSize; + + fn block_size(&self) -> Self::BlockSize { + T::block_size(self) + } + + fn num_blocks(&self) -> u64 { + T::num_blocks(self) + } +} + +impl, A: Access> BlockIO for &T { + async fn read_or_write_blocks( + &self, + start_block_idx: u64, + operation: Operation<'_, A>, + ) -> Result<(), <&T as BlockIOLayout>::Error> { + T::read_or_write_blocks(self, start_block_idx, operation).await + } +} + macro_rules! wrapper_methods { ($inner:path) => { pub fn into_inner(self) -> $inner { @@ -148,13 +209,13 @@ impl NextBlockSizeAdapter { wrapper_methods!(T); } -impl> BlockIO for NextBlockSizeAdapter { +impl> BlockIOLayout for NextBlockSizeAdapter { type Error = T::Error; type BlockSize = ::NextBlockSize; fn block_size(&self) -> Self::BlockSize { - Self::BlockSize::SINGLETON + Self::BlockSize::BLOCK_SIZE } fn num_blocks(&self) -> u64 { @@ -162,10 +223,18 @@ impl> BlockIO for NextBlockSizeAdapter Result<(), Self::Error> { +impl, A: Access> BlockIO for NextBlockSizeAdapter { + async fn read_or_write_blocks( + &self, + start_block_idx: u64, + operation: Operation<'_, A>, + ) -> Result<(), Self::Error> { let inner_start_block_idx = start_block_idx.checked_mul(2).unwrap(); - self.inner().read_blocks(inner_start_block_idx, buf).await + self.inner() + .read_or_write_blocks(inner_start_block_idx, operation) + .await } } @@ -182,23 +251,31 @@ impl PrevBlockSizeAdapter { wrapper_methods!(T); } -impl> BlockIO for PrevBlockSizeAdapter { +impl> BlockIOLayout for PrevBlockSizeAdapter { type Error = T::Error; type BlockSize = ::PrevBlockSize; fn block_size(&self) -> Self::BlockSize { - Self::BlockSize::SINGLETON + Self::BlockSize::BLOCK_SIZE } fn num_blocks(&self) -> u64 { self.inner().num_blocks().checked_mul(2).unwrap() } +} - async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error> { +impl, A: ReadAccess> BlockIO + for PrevBlockSizeAdapter +{ + async fn read_or_write_blocks( + &self, + start_block_idx: u64, + operation: Operation<'_, A>, + ) -> Result<(), Self::Error> { let block_size = Self::BlockSize::BYTES.try_into().unwrap(); let start_byte_idx = start_block_idx.checked_mul(block_size).unwrap(); - read_bytes(self.inner(), start_byte_idx, buf).await + read_or_write_bytes(self.inner(), start_byte_idx, operation).await } } @@ -208,17 +285,19 @@ pub struct Partition { range: Range, } -impl Partition { +impl> Partition { pub fn new(inner: T, range: Range) -> Self { assert!(range.start <= range.end); assert!(range.end <= inner.num_blocks()); Self { inner, range } } +} +impl Partition { wrapper_methods!(T); } -impl BlockIO for Partition { +impl BlockIOLayout for Partition { type Error = T::Error; type BlockSize = T::BlockSize; @@ -230,23 +309,52 @@ impl BlockIO for Partition { fn num_blocks(&self) -> u64 { self.range.end - self.range.start } +} - async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error> { +impl, A: Access> BlockIO for Partition { + async fn read_or_write_blocks( + &self, + start_block_idx: u64, + operation: Operation<'_, A>, + ) -> Result<(), Self::Error> { assert!( - start_block_idx + u64::try_from(buf.len()).unwrap() / self.block_size().bytes_u64() + start_block_idx + + u64::try_from(operation.len()).unwrap() / self.block_size().bytes_u64() <= self.num_blocks() ); let inner_block_idx = self.range.start + start_block_idx; - self.inner().read_blocks(inner_block_idx, buf).await + self.inner() + .read_or_write_blocks(inner_block_idx, operation) + .await } } -pub trait ByteIO { +pub trait ByteIOLayout { type Error: fmt::Debug; fn size(&self) -> u64; +} + +pub trait ByteIO: ByteIOLayout { + async fn read_or_write( + &self, + offset: u64, + operation: Operation<'_, A>, + ) -> Result<(), Self::Error>; + + async fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), Self::Error> + where + A: ReadAccess, + { + self.read_or_write(offset, Operation::read(buf)).await + } - async fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), Self::Error>; + async fn write(&self, offset: u64, buf: &[u8]) -> Result<(), Self::Error> + where + A: WriteAccess, + { + self.read_or_write(offset, Operation::write(buf)).await + } } #[derive(Clone, Debug)] @@ -262,15 +370,21 @@ impl ByteIOAdapter { wrapper_methods!(T); } -impl ByteIO for ByteIOAdapter { +impl ByteIOLayout for ByteIOAdapter { type Error = T::Error; fn size(&self) -> u64 { self.inner().num_blocks() * self.inner().block_size().bytes_u64() } +} - async fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), Self::Error> { - read_bytes(self.inner(), offset, buf).await +impl, A: ReadAccess> ByteIO for ByteIOAdapter { + async fn read_or_write( + &self, + offset: u64, + operation: Operation<'_, A>, + ) -> Result<(), Self::Error> { + read_or_write_bytes(self.inner(), offset, operation).await } } @@ -288,7 +402,7 @@ impl BlockIOAdapter { wrapper_methods!(T); } -impl BlockIO for BlockIOAdapter { +impl BlockIOLayout for BlockIOAdapter { type Error = T::Error; type BlockSize = N; @@ -300,12 +414,18 @@ impl BlockIO for BlockIOAdapter { fn num_blocks(&self) -> u64 { self.inner().size() / self.block_size().bytes_u64() } +} - async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error> { +impl, A: Access, N: BlockSize + Copy> BlockIO for BlockIOAdapter { + async fn read_or_write_blocks( + &self, + start_block_idx: u64, + operation: Operation<'_, A>, + ) -> Result<(), Self::Error> { let start_byte_idx = start_block_idx .checked_mul(self.block_size().bytes_u64()) .unwrap(); - self.inner().read(start_byte_idx, buf).await + self.inner().read_or_write(start_byte_idx, operation).await } } @@ -321,56 +441,128 @@ impl SliceByteIO { wrapper_methods!(T); } -impl> ByteIO for SliceByteIO { +impl> ByteIOLayout for SliceByteIO { type Error = !; fn size(&self) -> u64 { self.inner().as_ref().len().try_into().unwrap() } +} + +impl> ByteIO for SliceByteIO { + async fn read_or_write( + &self, + offset: u64, + operation: Operation<'_, ReadOnly>, + ) -> Result<(), Self::Error> { + let offset = offset.try_into().unwrap(); + match operation { + Operation::Read { buf, .. } => { + buf.copy_from_slice(&self.inner().as_ref()[offset..][..buf.len()]); + } + Operation::Write { witness, .. } => witness, + } + Ok(()) + } +} + +impl + AsMut<[u8]>> ByteIOLayout for RefCell> { + type Error = !; + + fn size(&self) -> u64 { + self.borrow().size() + } +} - async fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), Self::Error> { +impl + AsMut<[u8]>> ByteIO for RefCell> { + async fn read_or_write( + &self, + offset: u64, + operation: Operation<'_, ReadWrite>, + ) -> Result<(), Self::Error> { let offset = offset.try_into().unwrap(); - buf.copy_from_slice(&self.inner().as_ref()[offset..][..buf.len()]); + match operation { + Operation::Read { buf, .. } => { + buf.copy_from_slice(&self.borrow().inner().as_ref()[offset..][..buf.len()]); + } + Operation::Write { buf, .. } => { + self.borrow_mut().inner_mut().as_mut()[offset..][..buf.len()].copy_from_slice(buf); + } + } Ok(()) } } -async fn read_partial_block( +async fn read_or_write_partial_block, A: ReadAccess>( io: &T, block_idx: u64, offset_into_block: usize, - buf: &mut [u8], + operation: Operation<'_, A>, ) -> Result<(), T::Error> { - assert!(offset_into_block + buf.len() <= io.block_size().bytes()); + assert!(offset_into_block + operation.len() <= io.block_size().bytes()); let mut block_buf = io.block_size().zeroed_block(); io.read_blocks(block_idx, block_buf.as_mut()).await?; - buf.copy_from_slice(&block_buf.as_ref()[offset_into_block..][..buf.len()]); + match operation { + Operation::Read { buf, .. } => { + buf.copy_from_slice(&block_buf.as_ref()[offset_into_block..][..buf.len()]); + } + Operation::Write { buf, witness } => { + block_buf.as_mut()[offset_into_block..][..buf.len()].copy_from_slice(buf); + io.read_or_write_blocks( + block_idx, + Operation::Write { + buf: block_buf.as_ref(), + witness, + }, + ) + .await?; + } + } Ok(()) } -async fn read_bytes(io: &T, offset: u64, buf: &mut [u8]) -> Result<(), T::Error> { +async fn read_or_write_bytes, A: ReadAccess>( + io: &T, + offset: u64, + mut operation: Operation<'_, A>, +) -> Result<(), T::Error> { let block_size = io.block_size().bytes(); let block_size_u64 = io.block_size().bytes_u64(); let byte_offset_of_first_full_block = offset.next_multiple_of(block_size_u64); let byte_offset_of_first_full_block_in_buf = usize::try_from(byte_offset_of_first_full_block - offset).unwrap(); let first_full_block_idx = byte_offset_of_first_full_block / block_size_u64; - let num_full_blocks = (buf.len() - byte_offset_of_first_full_block_in_buf) / block_size; - if byte_offset_of_first_full_block > offset + u64::try_from(buf.len()).unwrap() { + let num_full_blocks = (operation.len() - byte_offset_of_first_full_block_in_buf) / block_size; + if byte_offset_of_first_full_block > offset + u64::try_from(operation.len()).unwrap() { let block_idx = first_full_block_idx - 1; let offset_into_block = offset - block_idx * block_size_u64; - read_partial_block(io, block_idx, offset_into_block.try_into().unwrap(), buf).await?; + read_or_write_partial_block( + io, + block_idx, + offset_into_block.try_into().unwrap(), + operation, + ) + .await?; } else { - let (left_partial_block, rest) = buf.split_at_mut(byte_offset_of_first_full_block_in_buf); - let (full_blocks, right_partial_block) = rest.split_at_mut(num_full_blocks * block_size); + let (left_partial_block, mut rest) = + operation.split_at(byte_offset_of_first_full_block_in_buf); + let (full_blocks, right_partial_block) = rest.split_at(num_full_blocks * block_size); future::try_join3( - async { io.read_blocks(first_full_block_idx, full_blocks).await }, + async { + io.read_or_write_blocks(first_full_block_idx, full_blocks) + .await + }, async { if !left_partial_block.is_empty() { let block_idx = first_full_block_idx - 1; let offset_into_block = block_size - left_partial_block.len(); - read_partial_block(io, block_idx, offset_into_block, left_partial_block) - .await?; + read_or_write_partial_block( + io, + block_idx, + offset_into_block, + left_partial_block, + ) + .await?; } Ok(()) }, @@ -378,8 +570,13 @@ async fn read_bytes(io: &T, offset: u64, buf: &mut [u8]) -> Result<( if !right_partial_block.is_empty() { let block_idx = first_full_block_idx + u64::try_from(num_full_blocks).unwrap(); let offset_into_block = 0; - read_partial_block(io, block_idx, offset_into_block, right_partial_block) - .await?; + read_or_write_partial_block( + io, + block_idx, + offset_into_block, + right_partial_block, + ) + .await?; } Ok(()) }, @@ -388,3 +585,19 @@ async fn read_bytes(io: &T, offset: u64, buf: &mut [u8]) -> Result<( } Ok(()) } + +pub async fn read_bytes, A: ReadAccess>( + io: &T, + offset: u64, + buf: &mut [u8], +) -> Result<(), T::Error> { + read_or_write_bytes(io, offset, Operation::read(buf)).await +} + +pub async fn write_bytes, A: ReadAccess + WriteAccess>( + io: &T, + offset: u64, + buf: &mut [u8], +) -> Result<(), T::Error> { + read_or_write_bytes(io, offset, Operation::write(buf)).await +} diff --git a/crates/sel4-async/block-io/src/operation.rs b/crates/sel4-async/block-io/src/operation.rs new file mode 100644 index 000000000..0d7fdb67b --- /dev/null +++ b/crates/sel4-async/block-io/src/operation.rs @@ -0,0 +1,200 @@ +use core::ops::Range; +use core::slice::{Chunks, ChunksMut}; + +use crate::access::{Access, ReadAccess, ReadOnly, WriteAccess, WriteOnly}; + +pub enum Operation<'a, A: Access> { + Read { + buf: &'a mut [u8], + witness: A::ReadWitness, + }, + Write { + buf: &'a [u8], + witness: A::WriteWitness, + }, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum OperationType { + Read, + Write, +} + +impl OperationType { + pub fn is_read(self) -> bool { + self == Self::Read + } + + pub fn is_write(self) -> bool { + self == Self::Write + } +} + +impl<'a, A: Access> Operation<'a, A> { + pub fn with_read_access>( + &'a mut self, + ) -> Operation<'a, A1> { + match self { + Self::Read { buf, .. } => Operation::Read { + buf, + witness: A1::READ_WITNESS, + }, + Self::Write { buf, witness } => Operation::Write { + buf, + witness: *witness, + }, + } + } + + pub fn with_write_access>( + &'a mut self, + ) -> Operation<'a, A1> { + match self { + Self::Read { buf, witness } => Operation::Read { + buf, + witness: *witness, + }, + Self::Write { buf, .. } => Operation::Write { + buf, + witness: A1::WRITE_WITNESS, + }, + } + } + + pub fn len(&self) -> usize { + match self { + Self::Read { buf, .. } => buf.len(), + Self::Write { buf, .. } => buf.len(), + } + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn ty(&self) -> OperationType { + match self { + Self::Read { .. } => OperationType::Read, + Self::Write { .. } => OperationType::Write, + } + } + + pub fn index(&'a mut self, index: Range) -> Self { + match self { + Self::Read { buf, witness } => Self::Read { + buf: &mut buf[index], + witness: *witness, + }, + Self::Write { buf, witness } => Self::Write { + buf: &buf[index], + witness: *witness, + }, + } + } + + pub fn split_at(&'a mut self, mid: usize) -> (Self, Self) { + match self { + Self::Read { buf, witness } => { + let (left, right) = buf.split_at_mut(mid); + let left = Self::Read { + buf: left, + witness: *witness, + }; + let right = Self::Read { + buf: right, + witness: *witness, + }; + (left, right) + } + Self::Write { buf, witness } => { + let (left, right) = buf.split_at(mid); + let left = Self::Write { + buf: left, + witness: *witness, + }; + let right = Self::Write { + buf: right, + witness: *witness, + }; + (left, right) + } + } + } + + pub fn chunks(&'a mut self, chunk_size: usize) -> impl Iterator> { + match self { + Self::Read { buf, witness } => OperationChunks::Read { + it: buf.chunks_mut(chunk_size), + witness: *witness, + }, + Self::Write { buf, witness } => OperationChunks::Write { + it: buf.chunks(chunk_size), + witness: *witness, + }, + } + } +} + +enum OperationChunks<'a, A: Access> { + Read { + it: ChunksMut<'a, u8>, + witness: A::ReadWitness, + }, + Write { + it: Chunks<'a, u8>, + witness: A::WriteWitness, + }, +} + +impl<'a, A: Access> Iterator for OperationChunks<'a, A> { + type Item = Operation<'a, A>; + + fn next(&mut self) -> Option> { + match self { + Self::Read { it, witness } => it.next().map(|buf| Operation::Read { + buf, + witness: *witness, + }), + Self::Write { it, witness } => it.next().map(|buf| Operation::Write { + buf, + witness: *witness, + }), + } + } +} + +impl<'a> Operation<'a, ReadOnly> { + pub fn as_read(&'a mut self) -> &'a mut [u8] { + match self { + Self::Read { buf, .. } => buf, + Self::Write { witness, .. } => *witness, + } + } +} + +impl<'a> Operation<'a, WriteOnly> { + pub fn as_write(&'a self) -> &'a [u8] { + match self { + Self::Read { witness, .. } => *witness, + Self::Write { buf, .. } => buf, + } + } +} + +impl<'a, A: ReadAccess> Operation<'a, A> { + pub fn read(buf: &'a mut [u8]) -> Self { + Self::Read { + buf, + witness: A::READ_WITNESS, + } + } +} + +impl<'a, A: WriteAccess> Operation<'a, A> { + pub fn write(buf: &'a [u8]) -> Self { + Self::Write { + buf, + witness: A::WRITE_WITNESS, + } + } +} diff --git a/crates/sel4-async/block-io/src/when_alloc.rs b/crates/sel4-async/block-io/src/when_alloc.rs index 3c0f046e4..191365ed2 100644 --- a/crates/sel4-async/block-io/src/when_alloc.rs +++ b/crates/sel4-async/block-io/src/when_alloc.rs @@ -11,7 +11,7 @@ use core::ops::Deref; use futures::future; use lru::LruCache; -use crate::{wrapper_methods, BlockIO, BlockSize}; +use crate::{wrapper_methods, Access, BlockIO, BlockIOLayout, BlockSize, Operation}; pub struct DynamicBlockSize { bits: usize, @@ -35,7 +35,7 @@ impl BlockSize for DynamicBlockSize { } } -impl BlockIO for Rc { +impl BlockIOLayout for Rc { type Error = T::Error; type BlockSize = T::BlockSize; @@ -47,19 +47,27 @@ impl BlockIO for Rc { fn num_blocks(&self) -> u64 { self.deref().num_blocks() } +} - async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error> { - self.deref().read_blocks(start_block_idx, buf).await +impl, A: Access> BlockIO for Rc { + async fn read_or_write_blocks( + &self, + start_block_idx: u64, + operation: Operation<'_, A>, + ) -> Result<(), Self::Error> { + self.deref() + .read_or_write_blocks(start_block_idx, operation) + .await } } #[derive(Debug)] -pub struct CachedBlockIO { +pub struct CachedBlockIO { inner: T, lru: RefCell::Block>>, } -impl CachedBlockIO { +impl CachedBlockIO { pub fn new(inner: T, cache_size_in_blocks: usize) -> Self { Self { inner, @@ -72,33 +80,65 @@ impl CachedBlockIO { wrapper_methods!(T); } -impl BlockIO for CachedBlockIO { - type Error = T::Error; +impl BlockIOLayout for CachedBlockIO { + type Error = ::Error; - type BlockSize = T::BlockSize; + type BlockSize = ::BlockSize; fn block_size(&self) -> Self::BlockSize { - self.inner().block_size() + ::block_size(self.inner()) } fn num_blocks(&self) -> u64 { - self.inner().num_blocks() + ::num_blocks(self.inner()) } +} - async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error> { - assert_eq!(buf.len() % self.block_size().bytes(), 0); - future::try_join_all(buf.chunks_mut(self.block_size().bytes()).enumerate().map( - |(i, block_buf)| async move { +impl, A: Access> BlockIO for CachedBlockIO { + async fn read_or_write_blocks( + &self, + start_block_idx: u64, + mut operation: Operation<'_, A>, + ) -> Result<(), Self::Error> { + assert_eq!(operation.len() % self.block_size().bytes(), 0); + future::try_join_all(operation.chunks(self.block_size().bytes()).enumerate().map( + |(i, block_operation)| async move { let block_idx = start_block_idx.checked_add(i.try_into().unwrap()).unwrap(); - // NOTE: odd control flow to avoid holding core::cell::RefMut across await - if let Some(block) = self.lru.borrow_mut().get(&block_idx) { - block_buf.copy_from_slice(block.as_ref()); - return Ok(()); + match block_operation { + Operation::Read { buf, witness } => { + // NOTE: odd control flow to avoid holding core::cell::RefMut across await + let cached = self + .lru + .borrow_mut() + .get(&block_idx) + .map(|block| { + buf.copy_from_slice(block.as_ref()); + }) + .is_some(); + if !cached { + let mut block = self.block_size().zeroed_block(); + self.inner + .read_or_write_blocks( + block_idx, + Operation::Read { + buf: block.as_mut(), + witness, + }, + ) + .await?; + buf.copy_from_slice(block.as_ref()); + let _ = self.lru.borrow_mut().put(block_idx, block); + } + } + Operation::Write { buf, witness } => { + self.inner + .read_or_write_blocks(block_idx, Operation::Write { buf, witness }) + .await?; + let mut block = self.block_size().zeroed_block(); + block.as_mut().copy_from_slice(buf); + let _ = self.lru.borrow_mut().put(block_idx, block); + } } - let mut block = self.block_size().zeroed_block(); - self.inner.read_blocks(block_idx, block.as_mut()).await?; - block_buf.copy_from_slice(block.as_ref()); - let _ = self.lru.borrow_mut().put(block_idx, block); Ok(()) }, )) diff --git a/crates/sel4-shared-ring-buffer/block-io/src/lib.rs b/crates/sel4-shared-ring-buffer/block-io/src/lib.rs index ee77040fa..219cac7a6 100644 --- a/crates/sel4-shared-ring-buffer/block-io/src/lib.rs +++ b/crates/sel4-shared-ring-buffer/block-io/src/lib.rs @@ -8,12 +8,13 @@ extern crate alloc; use alloc::rc::Rc; use core::cell::RefCell; use core::future::Future; +use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; use async_unsync::semaphore::Semaphore; -use sel4_async_block_io::{BlockIO, BlockSize}; +use sel4_async_block_io::{access::Access, BlockIO, BlockIOLayout, BlockSize, Operation}; use sel4_bounce_buffer_allocator::{AbstractBounceBufferAllocator, BounceBufferAllocator}; use sel4_externally_shared::ExternallySharedRef; use sel4_shared_ring_buffer::{roles::Provide, RingBuffers}; @@ -23,19 +24,22 @@ mod errors; mod owned; pub use errors::{Error, ErrorOrUserError, IOError, PeerMisbehaviorError, UserError}; -pub use owned::{IssueRequestBuf, OwnedSharedRingBufferBlockIO, PollRequestBuf, RequestBuf}; +pub use owned::{IssueRequestBuf, OwnedSharedRingBufferBlockIO, PollRequestBuf}; -pub struct SharedRingBufferBlockIO { - shared: Rc>>, +pub struct SharedRingBufferBlockIO { + shared: Rc>>, } -struct Inner { +struct Inner { owned: OwnedSharedRingBufferBlockIO, A, F>, block_size: N, num_blocks: u64, + _phantom: PhantomData

, } -impl SharedRingBufferBlockIO { +impl + SharedRingBufferBlockIO +{ pub fn new( block_size: N, num_blocks: u64, @@ -52,6 +56,7 @@ impl SharedRingBufferBlockIO SharedRingBufferBlockIO( &'a self, start_block_idx: u64, - mut request_buf: RequestBuf<'a>, + mut operation: Operation<'a, P>, ) -> Result<(), Error> { let request_index = { let sem = self.shared.borrow().owned.slot_set_semaphore().clone(); @@ -78,13 +83,13 @@ impl SharedRingBufferBlockIO SharedRingBufferBlockIO Clone for SharedRingBufferBlockIO { +impl Clone for SharedRingBufferBlockIO { fn clone(&self) -> Self { Self { shared: self.shared.clone(), @@ -100,8 +105,8 @@ impl Clone for SharedRingBufferBlockIO { } } -impl BlockIO - for SharedRingBufferBlockIO +impl BlockIOLayout + for SharedRingBufferBlockIO { type Error = Error; @@ -114,26 +119,28 @@ impl BlockIO fn num_blocks(&self) -> u64 { self.shared.borrow().num_blocks } +} - async fn read_blocks(&self, start_block_idx: u64, buf: &mut [u8]) -> Result<(), Self::Error> { - self.request(start_block_idx, RequestBuf::Read { buf }) - .await - } - - async fn write_blocks(&self, start_block_idx: u64, buf: &[u8]) -> Result<(), Self::Error> { - self.request(start_block_idx, RequestBuf::Write { buf }) - .await +impl BlockIO

+ for SharedRingBufferBlockIO +{ + async fn read_or_write_blocks( + &self, + start_block_idx: u64, + operation: Operation<'_, P>, + ) -> Result<(), Self::Error> { + self.request(start_block_idx, operation).await } } -pub struct RequestFuture<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> { - io: &'a SharedRingBufferBlockIO, - request_buf: RequestBuf<'a>, +pub struct RequestFuture<'a, N, P: Access, A: AbstractBounceBufferAllocator, F: FnMut()> { + io: &'a SharedRingBufferBlockIO, + operation: Operation<'a, P>, request_index: usize, poll_returned_ready: bool, } -impl<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> RequestFuture<'a, N, A, F> { +impl<'a, N, P: Access, A: AbstractBounceBufferAllocator, F: FnMut()> RequestFuture<'a, N, P, A, F> { fn poll_inner<'b>(&'b mut self, cx: &mut Context<'_>) -> Poll> where 'a: 'b, @@ -146,7 +153,7 @@ impl<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> RequestFuture<'a, N, A .owned .poll_request( self.request_index, - &mut self.request_buf.poll_request_buf(), + &mut PollRequestBuf::new(&mut self.operation), Some(cx.waker().clone()), ) .map_err(ErrorOrUserError::unwrap_error) @@ -161,7 +168,9 @@ impl<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> RequestFuture<'a, N, A } } -impl<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> Future for RequestFuture<'a, N, A, F> { +impl<'a, N, P: Access, A: AbstractBounceBufferAllocator, F: FnMut()> Future + for RequestFuture<'a, N, P, A, F> +{ type Output = Result<(), Error>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -169,7 +178,9 @@ impl<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> Future for RequestFutu } } -impl<'a, N, A: AbstractBounceBufferAllocator, F: FnMut()> Drop for RequestFuture<'a, N, A, F> { +impl<'a, N, P: Access, A: AbstractBounceBufferAllocator, F: FnMut()> Drop + for RequestFuture<'a, N, P, A, F> +{ fn drop(&mut self) { if !self.poll_returned_ready { self.io diff --git a/crates/sel4-shared-ring-buffer/block-io/src/owned.rs b/crates/sel4-shared-ring-buffer/block-io/src/owned.rs index 0a9b64dc2..6c63af832 100644 --- a/crates/sel4-shared-ring-buffer/block-io/src/owned.rs +++ b/crates/sel4-shared-ring-buffer/block-io/src/owned.rs @@ -1,6 +1,7 @@ use core::alloc::Layout; use core::task::{Poll, Waker}; +use sel4_async_block_io::{access::Access, Operation}; use sel4_bounce_buffer_allocator::{AbstractBounceBufferAllocator, BounceBufferAllocator}; use sel4_externally_shared::ExternallySharedRef; use sel4_shared_ring_buffer::{ @@ -43,36 +44,19 @@ enum OccupiedState { Complete { error: Option }, } -pub enum RequestBuf<'a> { - Read { buf: &'a mut [u8] }, - Write { buf: &'a [u8] }, -} - -impl<'a> RequestBuf<'a> { - pub fn issue_request_buf<'b>(&'b mut self) -> IssueRequestBuf<'a> { - match self { - Self::Read { buf } => IssueRequestBuf::Read { len: buf.len() }, - Self::Write { buf } => IssueRequestBuf::Write { buf }, - } - } - - pub fn poll_request_buf<'b>(&'b mut self) -> PollRequestBuf<'b> - where - 'a: 'b, - { - match self { - Self::Read { buf } => PollRequestBuf::Read { buf }, - Self::Write { .. } => PollRequestBuf::Write, - } - } -} - pub enum IssueRequestBuf<'a> { Read { len: usize }, Write { buf: &'a [u8] }, } impl<'a> IssueRequestBuf<'a> { + pub fn new(operation: &'a Operation<'a, A>) -> Self { + match operation { + Operation::Read { buf, .. } => Self::Read { len: buf.len() }, + Operation::Write { buf, .. } => Self::Write { buf }, + } + } + fn len(&self) -> usize { match self { Self::Read { len } => *len, @@ -93,6 +77,18 @@ pub enum PollRequestBuf<'a> { Write, } +impl<'a> PollRequestBuf<'a> { + pub fn new<'b, A: Access>(operation: &'a mut Operation<'b, A>) -> Self + where + 'b: 'a, + { + match operation { + Operation::Read { buf, .. } => Self::Read { buf }, + Operation::Write { .. } => Self::Write, + } + } +} + impl OwnedSharedRingBufferBlockIO { From caca69e60ee37099375a7d999390266b90f1fa31 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Wed, 18 Oct 2023 10:35:06 +0000 Subject: [PATCH 11/12] Remove unecessary #[allow] attributes Signed-off-by: Nick Spinale --- crates/sel4-async/block-io/src/when_alloc.rs | 3 --- crates/sel4-bounce-buffer-allocator/src/basic.rs | 7 +------ 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/sel4-async/block-io/src/when_alloc.rs b/crates/sel4-async/block-io/src/when_alloc.rs index 191365ed2..5385f9972 100644 --- a/crates/sel4-async/block-io/src/when_alloc.rs +++ b/crates/sel4-async/block-io/src/when_alloc.rs @@ -1,6 +1,3 @@ -#![allow(dead_code)] -#![allow(unused_variables)] - use alloc::rc::Rc; use alloc::vec; use alloc::vec::Vec; diff --git a/crates/sel4-bounce-buffer-allocator/src/basic.rs b/crates/sel4-bounce-buffer-allocator/src/basic.rs index a87e8c632..8ed552452 100644 --- a/crates/sel4-bounce-buffer-allocator/src/basic.rs +++ b/crates/sel4-bounce-buffer-allocator/src/basic.rs @@ -1,14 +1,9 @@ -#![allow(dead_code)] -#![allow(unused_imports)] -#![allow(unused_variables)] - use alloc::alloc::Global; use alloc::collections::BTreeMap; -use alloc::vec::Vec; use core::alloc::{Allocator, Layout}; use core::ops::Bound; -use crate::{AbstractBounceBufferAllocator, Align, Offset, Size}; +use crate::{AbstractBounceBufferAllocator, Offset, Size}; const GRANULE_SIZE: usize = 2048; From fd2f3dd2621c1ff419c1632fe03f0db14583a288 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Wed, 18 Oct 2023 10:50:49 +0000 Subject: [PATCH 12/12] crates/sel4-async/block-io/cpiofs: Update for improvements in dependencies Signed-off-by: Nick Spinale --- crates/sel4-async/block-io/cpiofs/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/sel4-async/block-io/cpiofs/src/lib.rs b/crates/sel4-async/block-io/cpiofs/src/lib.rs index 07fda16af..d37e1711c 100644 --- a/crates/sel4-async/block-io/cpiofs/src/lib.rs +++ b/crates/sel4-async/block-io/cpiofs/src/lib.rs @@ -13,7 +13,7 @@ use core::mem; use hex::FromHex; use zerocopy::{AsBytes, FromBytes, FromZeroes}; -use sel4_async_block_io::ByteIO; +use sel4_async_block_io::{access::ReadOnly, ByteIO}; const CPIO_ALIGN: usize = 4; @@ -79,7 +79,7 @@ impl EntryLocation { self.offset } - async fn read_entry(&self, io: &T) -> Result { + async fn read_entry>(&self, io: &T) -> Result { let mut header = Header::new_zeroed(); io.read(self.offset().try_into().unwrap(), header.as_bytes_mut()) .await?; @@ -133,7 +133,7 @@ impl Entry { } } - async fn read_name(&self, io: &T) -> Result { + async fn read_name>(&self, io: &T) -> Result { let mut buf = vec![0; self.header().name_size()]; io.read(self.name_offset().try_into().unwrap(), &mut buf) .await?; @@ -154,7 +154,7 @@ pub struct Index { io: T, } -impl Index { +impl> Index { pub async fn create(io: T) -> Result { let mut entries = BTreeMap::new(); let mut location = EntryLocation::first();