blob: fd851d3d5a4db27e8678c929aeaa9130580e2451 [file] [log] [blame]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! IO support for reading input from an ObjDescBundle of page frames
//! contained in a top-level CNode.
#![no_std]
extern crate alloc;
use alloc::boxed::Box;
use cantrip_memory_interface::ObjDescBundle;
use cantrip_os_common::camkes::Camkes;
use cantrip_os_common::copyregion::CopyRegion;
use cantrip_os_common::cspace_slot::CSpaceSlot;
use cantrip_os_common::sel4_sys;
use core2::io::{Cursor, Read};
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_Result;
use cantrip_io as io;
extern "Rust" {
fn get_upload_mut() -> &'static mut [u8];
}
/// Rx io trait that returns data from an ObjDescBundle of page frames.
pub struct Rx<'a> {
src: &'a ObjDescBundle,
cptr_iter: Box<dyn Iterator<Item = seL4_CPtr> + 'a>,
cur_frame: Option<seL4_CPtr>,
copyregion: CopyRegion<'a>,
cursor: Cursor<&'a [u8]>,
top_slot: CSpaceSlot,
}
impl<'a> Rx<'a> {
pub fn new(src: &'a ObjDescBundle) -> Self {
Camkes::debug_assert_slot_cnode("objdesc-client::new", &Camkes::top_level_path(src.cnode));
Self {
src,
cptr_iter: Box::new(src.cptr_iter()),
cur_frame: None,
copyregion: unsafe { CopyRegion::new(get_upload_mut()) },
cursor: Cursor::new(&[]),
top_slot: CSpaceSlot::new(),
}
}
fn is_empty(&self) -> bool {
// XXX can't enable Cursor::is_empty for some reason
self.cursor.position() >= self.cursor.get_ref().len() as u64
}
// Unmaps any page from |copyregion| & moves the cap back to |src|.
fn unmap_current(&mut self) -> seL4_Result {
if let Some(cptr) = self.cur_frame {
self.copyregion.unmap()?;
self.top_slot
.move_from(self.src.cnode, cptr, self.src.depth as _)?;
self.cur_frame = None;
}
Ok(())
}
// Moves |cptr| to the top-level & maps it into |copyregion|.
fn map_current(&mut self, cptr: seL4_CPtr) -> seL4_Result {
self.top_slot
.move_to(self.src.cnode, cptr, self.src.depth as _)?;
Camkes::debug_assert_slot_frame(
"objdesc-client::read",
&Camkes::top_level_path(self.top_slot.slot),
);
// NB: drop recovers move if map fails
self.copyregion.map(self.top_slot.slot)?;
self.cur_frame = Some(cptr);
// XXX need slice len to end of data? (cheat for now and let LineReader discard zero's)
self.cursor = Cursor::new(self.copyregion.as_ref());
Ok(())
}
}
impl<'a> Drop for Rx<'a> {
fn drop(&mut self) { let _ = self.unmap_current(); }
}
impl<'a> io::Read for Rx<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.is_empty() {
// Unmap any current page, advance to the next
// ObjDesc, and setup the cursor.
self.unmap_current().or(Err(io::Error))?;
if let Some(cptr) = self.cptr_iter.next() {
self.map_current(cptr).or(Err(io::Error))?;
} else {
return Ok(0); // EOF
}
}
self.cursor.read(buf).or(Err(io::Error))
}
}