mirror of
https://github.com/AmbiML/sparrow-kata-full.git
synced 2025-09-26 15:25:17 +00:00
DebugConsole: hookup zmodem to MemoryManager
- change zmodem uploads to get memory from the MemoryManager - add a "-z" option to the "install" command to start a zmodem upload to generate the package contents to send to ProcessManager - increase CNode headroom for loading package contents Change-Id: I5f329cdd044368e5568ad891245d67a4a13f8468 GitOrigin-RevId: 2853cde48cb8232f3ba75fe7e8efdbd3032bcb66
This commit is contained in:
@@ -31,9 +31,14 @@ component DebugConsole {
|
||||
// Enable KataOS CAmkES support.
|
||||
attribute int kataos = true;
|
||||
|
||||
// Add a bunch of free slots for test code to use.
|
||||
attribute int cnode_headroom = 64;
|
||||
// Install requires enough slots to hold dynamically allocated
|
||||
// memory for package contents. Size this to handle up to 4MB
|
||||
// (at 4KB / page) though that exceeds our target memory config.
|
||||
attribute int cnode_headroom = 1024;
|
||||
|
||||
// Copyregions for loading bundle images.
|
||||
// Copyregions for zmodem upload and for loading bundle images.
|
||||
// Could do this with one region since upload never happens
|
||||
// concurrently with bundle image loading.
|
||||
has copyregion BUNDLE_IMAGE;
|
||||
has copyregion UPLOAD;
|
||||
}
|
||||
|
@@ -14,10 +14,21 @@
|
||||
use kata_io;
|
||||
use kata_os_common::allocator;
|
||||
use kata_os_common::logger::KataLogger;
|
||||
use kata_os_common::sel4_sys;
|
||||
use kata_os_common::slot_allocator;
|
||||
use kata_shell;
|
||||
use kata_uart_client;
|
||||
use log::trace;
|
||||
|
||||
use sel4_sys::seL4_CPtr;
|
||||
|
||||
use slot_allocator::KATA_CSPACE_SLOTS;
|
||||
|
||||
extern "C" {
|
||||
static SELF_CNODE_FIRST_SLOT: seL4_CPtr;
|
||||
static SELF_CNODE_LAST_SLOT: seL4_CPtr;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pre_init() {
|
||||
static KATA_LOGGER: KataLogger = KataLogger;
|
||||
@@ -36,6 +47,16 @@ pub extern "C" fn pre_init() {
|
||||
HEAP_MEMORY.len()
|
||||
);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
KATA_CSPACE_SLOTS.init(
|
||||
/*first_slot=*/ SELF_CNODE_FIRST_SLOT,
|
||||
/*size=*/ SELF_CNODE_LAST_SLOT - SELF_CNODE_FIRST_SLOT
|
||||
);
|
||||
trace!("setup cspace slots: first slot {} free {}",
|
||||
KATA_CSPACE_SLOTS.base_slot(),
|
||||
KATA_CSPACE_SLOTS.free_slots());
|
||||
}
|
||||
}
|
||||
|
||||
/// Entry point for DebugConsole. Runs the shell with UART IO.
|
||||
|
@@ -13,6 +13,7 @@ use kata_io as io;
|
||||
use kata_line_reader::LineReader;
|
||||
use kata_memory_interface::*;
|
||||
use kata_os_common::sel4_sys;
|
||||
use kata_os_common::slot_allocator;
|
||||
use kata_proc_interface::kata_pkg_mgmt_install;
|
||||
use kata_proc_interface::kata_pkg_mgmt_uninstall;
|
||||
use kata_proc_interface::kata_proc_ctrl_get_running_bundles;
|
||||
@@ -26,18 +27,26 @@ use kata_timer_interface::timer_service_completed_timers;
|
||||
use kata_timer_interface::timer_service_oneshot;
|
||||
use kata_timer_interface::timer_service_wait;
|
||||
|
||||
use sel4_sys::seL4_CNode_Delete;
|
||||
use sel4_sys::seL4_CPtr;
|
||||
use sel4_sys::seL4_MinSchedContextBits;
|
||||
use sel4_sys::seL4_ObjectType::*;
|
||||
use sel4_sys::seL4_WordBits;
|
||||
|
||||
use slot_allocator::KATA_CSPACE_SLOTS;
|
||||
|
||||
mod rz;
|
||||
|
||||
extern "C" {
|
||||
static SELF_CNODE: seL4_CPtr;
|
||||
}
|
||||
|
||||
/// Error type indicating why a command line is not runnable.
|
||||
enum CommandError {
|
||||
UnknownCommand,
|
||||
BadArgs,
|
||||
IO,
|
||||
Memory,
|
||||
Formatter(fmt::Error),
|
||||
}
|
||||
|
||||
@@ -47,6 +56,7 @@ impl fmt::Display for CommandError {
|
||||
CommandError::UnknownCommand => write!(f, "unknown command"),
|
||||
CommandError::BadArgs => write!(f, "invalid arguments"),
|
||||
CommandError::IO => write!(f, "input / output error"),
|
||||
CommandError::Memory => write!(f, "memory allocation error"),
|
||||
CommandError::Formatter(e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
@@ -118,7 +128,7 @@ fn dispatch_command(cmdline: &str, input: &mut dyn io::BufRead, output: &mut dyn
|
||||
"kvdelete" => kvdelete_command(&mut args, output),
|
||||
"kvread" => kvread_command(&mut args, output),
|
||||
"kvwrite" => kvwrite_command(&mut args, output),
|
||||
"install" => install_command(&mut args, output),
|
||||
"install" => install_command(&mut args, input, output),
|
||||
"loglevel" => loglevel_command(&mut args, output),
|
||||
"malloc" => malloc_command(&mut args, output),
|
||||
"mfree" => mfree_command(&mut args, output),
|
||||
@@ -226,7 +236,7 @@ fn rz_command(
|
||||
writeln!(
|
||||
output,
|
||||
"size: {}, crc32: {}",
|
||||
upload.contents().len(),
|
||||
upload.len(),
|
||||
hex::encode(upload.crc32().to_be_bytes())
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -281,13 +291,53 @@ fn bundles_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn collect_from_zmodem(
|
||||
input: &mut dyn io::BufRead,
|
||||
mut output: &mut dyn io::Write,
|
||||
) -> Option<ObjDescBundle> {
|
||||
writeln!(output, "Starting zmodem upload...").ok()?;
|
||||
let mut upload = rz::rz(input, &mut output).ok()?;
|
||||
upload.finish();
|
||||
writeln!(output, "Received {} bytes of data, crc32 {}",
|
||||
upload.len(),
|
||||
hex::encode(upload.crc32().to_be_bytes())).ok()?;
|
||||
Some(upload.frames().clone())
|
||||
}
|
||||
|
||||
fn install_command(
|
||||
_args: &mut dyn Iterator<Item = &str>,
|
||||
output: &mut dyn io::Write,
|
||||
args: &mut dyn Iterator<Item = &str>,
|
||||
input: &mut dyn io::BufRead,
|
||||
mut output: &mut dyn io::Write,
|
||||
) -> Result<(), CommandError> {
|
||||
// TODO(sleffler): supply a real bundle (e.g. from serial)
|
||||
let pkg_buffer = &[0u8; 64];
|
||||
match kata_pkg_mgmt_install(pkg_buffer) {
|
||||
fn clear_slot(slot: seL4_CPtr) {
|
||||
unsafe {
|
||||
KATA_CSPACE_SLOTS.free(slot, 1);
|
||||
seL4_CNode_Delete(SELF_CNODE, slot, seL4_WordBits as u8)
|
||||
.expect("install");
|
||||
}
|
||||
}
|
||||
|
||||
// Collect/setup the package frames. If a -z arg is present a zmodem
|
||||
// upload is used; otherwise we use some raw pages (for testing).
|
||||
let mut pkg_contents = match args.next() {
|
||||
Some("-z") => {
|
||||
collect_from_zmodem(input, &mut output).ok_or(CommandError::IO)?
|
||||
}
|
||||
_ => {
|
||||
// TODO: pattern-fill pages
|
||||
kata_frame_alloc(8192).map_err(|_| CommandError::IO)?
|
||||
}
|
||||
};
|
||||
|
||||
// The frames are in SELF_CNODE; wrap them in a dynamically allocated
|
||||
// CNode (as expected by kata_pgk_mgmt_install).
|
||||
// TODO(sleffler): useful idiom, add to MemoryManager
|
||||
let cnode_depth = pkg_contents.count_log2();
|
||||
let cnode = kata_cnode_alloc(cnode_depth)
|
||||
.map_err(|_| CommandError::Memory)?; // XXX leaks pkg_contents
|
||||
pkg_contents.move_objects_from_toplevel(cnode.objs[0].cptr, cnode_depth as u8)
|
||||
.map_err(|_| CommandError::Memory)?; // XXX leaks pkg_contents + cnode
|
||||
match kata_pkg_mgmt_install(&pkg_contents) {
|
||||
Ok(bundle_id) => {
|
||||
writeln!(output, "Bundle \"{}\" installed", bundle_id)?;
|
||||
}
|
||||
@@ -295,6 +345,13 @@ fn install_command(
|
||||
writeln!(output, "install failed: {:?}", status)?;
|
||||
}
|
||||
}
|
||||
|
||||
// SecurityCoordinator owns the cnode & frames contained within but we
|
||||
// still have a cap for the cnode in our top-level CNode; clean it up.
|
||||
debug_assert!(cnode.cnode == unsafe { SELF_CNODE });
|
||||
sel4_sys::debug_assert_slot_cnode!(cnode.objs[0].cptr);
|
||||
clear_slot(cnode.objs[0].cptr);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@@ -1,40 +1,167 @@
|
||||
/// Wrapper types for fully-buffered ZMODEM receives.
|
||||
use alloc::vec::Vec;
|
||||
|
||||
// TODO(sleffler): maybe extract the page-at-a-time support to it's own crate
|
||||
|
||||
use alloc::vec;
|
||||
use crc::crc32;
|
||||
use crc::Hasher32;
|
||||
use core::cmp;
|
||||
use core::ptr;
|
||||
use kata_memory_interface::kata_frame_alloc;
|
||||
use kata_memory_interface::ObjDescBundle;
|
||||
use kata_os_common::sel4_sys;
|
||||
use log;
|
||||
|
||||
use sel4_sys::seL4_CapRights;
|
||||
use sel4_sys::seL4_CPtr;
|
||||
use sel4_sys::seL4_PageBits;
|
||||
use sel4_sys::seL4_WordBits;
|
||||
|
||||
use sel4_sys::seL4_RISCV_Page_Map as seL4_Page_Map;
|
||||
use sel4_sys::seL4_RISCV_Page_Unmap as seL4_Page_Unmap;
|
||||
use sel4_sys::seL4_RISCV_VMAttributes::Default_VMAttributes as seL4_Default_VMAttributes;
|
||||
|
||||
use zmodem;
|
||||
|
||||
use kata_io as io;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum UploadError {
|
||||
PageMapFailed,
|
||||
PageUnmapFailed,
|
||||
MallocFailed,
|
||||
}
|
||||
impl From<UploadError> for io::Error {
|
||||
fn from(_err: UploadError) -> io::Error {
|
||||
io::Error
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(sleffler): use ObjDesc::size_bytes
|
||||
const PAGE_SIZE: usize = 1 << seL4_PageBits;
|
||||
|
||||
extern "C" {
|
||||
static SELF_CNODE: seL4_CPtr;
|
||||
static SELF_VSPACE_ROOT: seL4_CPtr;
|
||||
static mut UPLOAD: [u8; PAGE_SIZE];
|
||||
}
|
||||
|
||||
pub struct Upload {
|
||||
digest: crc32::Digest,
|
||||
contents: Vec<u8>,
|
||||
frames: ObjDescBundle, // Page frames
|
||||
mapped_page: *mut u8, // Currently mapped page frame
|
||||
mapped_bytes: usize, // Bytes in mapped_frame, 0 =>'s no frame mapped
|
||||
next_free: usize, // Next available byte in mapped frame
|
||||
}
|
||||
|
||||
impl Upload {
|
||||
pub fn new() -> Upload {
|
||||
pub fn new() -> Self {
|
||||
Upload {
|
||||
digest: crc32::Digest::new(crc32::IEEE),
|
||||
contents: Vec::new(),
|
||||
frames: ObjDescBundle::new(
|
||||
// Collect frames in the top-level CNode for now
|
||||
unsafe { SELF_CNODE }, seL4_WordBits as u8,
|
||||
vec![],
|
||||
),
|
||||
mapped_page: unsafe { ptr::addr_of_mut!(UPLOAD[0]) },
|
||||
mapped_bytes: 0, // NB: nothing mapped
|
||||
next_free: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn crc32(&self) -> u32 {
|
||||
self.digest.sum32()
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
(self.frames.count() * PAGE_SIZE) - (self.mapped_bytes - self.next_free)
|
||||
}
|
||||
pub fn finish(&mut self) {
|
||||
self.unmap_current_frame().expect("finish");
|
||||
}
|
||||
pub fn frames(&self) -> &ObjDescBundle {
|
||||
&self.frames
|
||||
}
|
||||
|
||||
pub fn contents(&self) -> &[u8] {
|
||||
self.contents.as_slice()
|
||||
// Unmap the current page and reset state.
|
||||
fn unmap_current_frame(&mut self) -> Result<(), UploadError> {
|
||||
if let Some(frame) = &self.frames.objs.last() {
|
||||
unsafe { seL4_Page_Unmap(frame.cptr) }
|
||||
.map_err(|_| UploadError::PageUnmapFailed)?;
|
||||
}
|
||||
// Try to combine this frame w/ the previous so large input
|
||||
// data streams don't generate many singleton ObjDesc's.
|
||||
self.frames.maybe_combine_last();
|
||||
|
||||
self.mapped_bytes = 0;
|
||||
self.next_free = 0;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Expand storage and map the new frame into our VSpace.
|
||||
fn expand_and_map(&mut self) -> Result<(), UploadError> {
|
||||
let new_page = kata_frame_alloc(PAGE_SIZE)
|
||||
.map_err(|_| UploadError::MallocFailed)?;
|
||||
// Verify the new frame is in the same CNode as previous.
|
||||
assert_eq!(new_page.cnode, self.frames.cnode);
|
||||
assert_eq!(new_page.depth, self.frames.depth);
|
||||
self.frames.objs.push(new_page.objs[0]);
|
||||
|
||||
let frame = &self.frames.objs.last().unwrap();
|
||||
unsafe {
|
||||
seL4_Page_Map(
|
||||
/*sel4_page=*/ frame.cptr,
|
||||
/*seL4_pd=*/ SELF_VSPACE_ROOT,
|
||||
/*vaddr=*/ self.mapped_page as usize,
|
||||
seL4_CapRights::new(
|
||||
// NB: RW 'cuz W-only silently gets upgraded by kernel
|
||||
/*grant_reply=*/0, /*grant=*/0, /*read=1*/1, /*write=*/1,
|
||||
),
|
||||
seL4_Default_VMAttributes,
|
||||
)
|
||||
}.map_err(|_| UploadError::PageMapFailed)?;
|
||||
self.mapped_bytes = PAGE_SIZE;
|
||||
self.next_free = 0;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Drop for Upload {
|
||||
fn drop(&mut self) {
|
||||
self.finish();
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for Upload {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.digest.write(buf);
|
||||
self.contents.extend_from_slice(buf);
|
||||
let mut cursor = buf;
|
||||
while cursor.len() > 0 {
|
||||
let available_bytes = self.mapped_bytes - self.next_free;
|
||||
if available_bytes > 0 {
|
||||
// Fill the current frame (as space permits).
|
||||
let region = unsafe {
|
||||
core::slice::from_raw_parts_mut(self.mapped_page, self.mapped_bytes)
|
||||
};
|
||||
let bytes_to_write = cmp::min(available_bytes, cursor.len());
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
cursor.as_ptr(),
|
||||
region[self.next_free..].as_mut_ptr(),
|
||||
bytes_to_write
|
||||
)
|
||||
};
|
||||
self.next_free += bytes_to_write;
|
||||
cursor = &cursor[bytes_to_write..];
|
||||
|
||||
assert!(self.next_free <= self.mapped_bytes);
|
||||
if self.next_free == self.mapped_bytes {
|
||||
// Current frame is full; unmap and prepare for next.
|
||||
self.unmap_current_frame()?;
|
||||
}
|
||||
}
|
||||
if cursor.len() == 0 { break }
|
||||
|
||||
// Allocate another frame and map it for write.
|
||||
self.expand_and_map()?;
|
||||
}
|
||||
self.digest.write(buf); // Update crc32 calculation
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
|
@@ -97,9 +97,6 @@ assembly {
|
||||
connection seL4HardwareMMIO vc_dtcm(from ml_coordinator.dtcm,
|
||||
to vctop.dtcm);
|
||||
|
||||
connection seL4HardwareMMIO vc_elf(from ml_coordinator.elf_file,
|
||||
to vc_payload.elf_file);
|
||||
|
||||
// TimerService
|
||||
connection seL4HardwareMMIO timer_csr(from timer_service.csr,
|
||||
to timer.csr);
|
||||
@@ -123,7 +120,8 @@ assembly {
|
||||
// component and copies data between components.
|
||||
connection seL4RPCOverMultiSharedData multi_memory(
|
||||
from debug_console.memory,
|
||||
// TODO(sleffler): from process_manager.memory,
|
||||
from process_manager.memory,
|
||||
from security_coordinator.memory,
|
||||
// TOOD(sleffler): from ml_coordinator.memory,
|
||||
to memory_manager.memory);
|
||||
|
||||
|
Reference in New Issue
Block a user