mirror of
https://github.com/AmbiML/sparrow-kata-full.git
synced 2025-09-26 07:22:13 +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.
|
// Enable KataOS CAmkES support.
|
||||||
attribute int kataos = true;
|
attribute int kataos = true;
|
||||||
|
|
||||||
// Add a bunch of free slots for test code to use.
|
// Install requires enough slots to hold dynamically allocated
|
||||||
attribute int cnode_headroom = 64;
|
// 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 BUNDLE_IMAGE;
|
||||||
|
has copyregion UPLOAD;
|
||||||
}
|
}
|
||||||
|
@@ -14,10 +14,21 @@
|
|||||||
use kata_io;
|
use kata_io;
|
||||||
use kata_os_common::allocator;
|
use kata_os_common::allocator;
|
||||||
use kata_os_common::logger::KataLogger;
|
use kata_os_common::logger::KataLogger;
|
||||||
|
use kata_os_common::sel4_sys;
|
||||||
|
use kata_os_common::slot_allocator;
|
||||||
use kata_shell;
|
use kata_shell;
|
||||||
use kata_uart_client;
|
use kata_uart_client;
|
||||||
use log::trace;
|
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]
|
#[no_mangle]
|
||||||
pub extern "C" fn pre_init() {
|
pub extern "C" fn pre_init() {
|
||||||
static KATA_LOGGER: KataLogger = KataLogger;
|
static KATA_LOGGER: KataLogger = KataLogger;
|
||||||
@@ -36,6 +47,16 @@ pub extern "C" fn pre_init() {
|
|||||||
HEAP_MEMORY.len()
|
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.
|
/// 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_line_reader::LineReader;
|
||||||
use kata_memory_interface::*;
|
use kata_memory_interface::*;
|
||||||
use kata_os_common::sel4_sys;
|
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_install;
|
||||||
use kata_proc_interface::kata_pkg_mgmt_uninstall;
|
use kata_proc_interface::kata_pkg_mgmt_uninstall;
|
||||||
use kata_proc_interface::kata_proc_ctrl_get_running_bundles;
|
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_oneshot;
|
||||||
use kata_timer_interface::timer_service_wait;
|
use kata_timer_interface::timer_service_wait;
|
||||||
|
|
||||||
|
use sel4_sys::seL4_CNode_Delete;
|
||||||
use sel4_sys::seL4_CPtr;
|
use sel4_sys::seL4_CPtr;
|
||||||
use sel4_sys::seL4_MinSchedContextBits;
|
use sel4_sys::seL4_MinSchedContextBits;
|
||||||
use sel4_sys::seL4_ObjectType::*;
|
use sel4_sys::seL4_ObjectType::*;
|
||||||
use sel4_sys::seL4_WordBits;
|
use sel4_sys::seL4_WordBits;
|
||||||
|
|
||||||
|
use slot_allocator::KATA_CSPACE_SLOTS;
|
||||||
|
|
||||||
mod rz;
|
mod rz;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static SELF_CNODE: seL4_CPtr;
|
||||||
|
}
|
||||||
|
|
||||||
/// Error type indicating why a command line is not runnable.
|
/// Error type indicating why a command line is not runnable.
|
||||||
enum CommandError {
|
enum CommandError {
|
||||||
UnknownCommand,
|
UnknownCommand,
|
||||||
BadArgs,
|
BadArgs,
|
||||||
IO,
|
IO,
|
||||||
|
Memory,
|
||||||
Formatter(fmt::Error),
|
Formatter(fmt::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +56,7 @@ impl fmt::Display for CommandError {
|
|||||||
CommandError::UnknownCommand => write!(f, "unknown command"),
|
CommandError::UnknownCommand => write!(f, "unknown command"),
|
||||||
CommandError::BadArgs => write!(f, "invalid arguments"),
|
CommandError::BadArgs => write!(f, "invalid arguments"),
|
||||||
CommandError::IO => write!(f, "input / output error"),
|
CommandError::IO => write!(f, "input / output error"),
|
||||||
|
CommandError::Memory => write!(f, "memory allocation error"),
|
||||||
CommandError::Formatter(e) => write!(f, "{}", e),
|
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),
|
"kvdelete" => kvdelete_command(&mut args, output),
|
||||||
"kvread" => kvread_command(&mut args, output),
|
"kvread" => kvread_command(&mut args, output),
|
||||||
"kvwrite" => kvwrite_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),
|
"loglevel" => loglevel_command(&mut args, output),
|
||||||
"malloc" => malloc_command(&mut args, output),
|
"malloc" => malloc_command(&mut args, output),
|
||||||
"mfree" => mfree_command(&mut args, output),
|
"mfree" => mfree_command(&mut args, output),
|
||||||
@@ -226,7 +236,7 @@ fn rz_command(
|
|||||||
writeln!(
|
writeln!(
|
||||||
output,
|
output,
|
||||||
"size: {}, crc32: {}",
|
"size: {}, crc32: {}",
|
||||||
upload.contents().len(),
|
upload.len(),
|
||||||
hex::encode(upload.crc32().to_be_bytes())
|
hex::encode(upload.crc32().to_be_bytes())
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -281,13 +291,53 @@ fn bundles_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
|||||||
Ok(())
|
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(
|
fn install_command(
|
||||||
_args: &mut dyn Iterator<Item = &str>,
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
output: &mut dyn io::Write,
|
input: &mut dyn io::BufRead,
|
||||||
|
mut output: &mut dyn io::Write,
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
// TODO(sleffler): supply a real bundle (e.g. from serial)
|
fn clear_slot(slot: seL4_CPtr) {
|
||||||
let pkg_buffer = &[0u8; 64];
|
unsafe {
|
||||||
match kata_pkg_mgmt_install(pkg_buffer) {
|
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) => {
|
Ok(bundle_id) => {
|
||||||
writeln!(output, "Bundle \"{}\" installed", bundle_id)?;
|
writeln!(output, "Bundle \"{}\" installed", bundle_id)?;
|
||||||
}
|
}
|
||||||
@@ -295,6 +345,13 @@ fn install_command(
|
|||||||
writeln!(output, "install failed: {:?}", status)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,40 +1,167 @@
|
|||||||
/// Wrapper types for fully-buffered ZMODEM receives.
|
/// 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::crc32;
|
||||||
use crc::Hasher32;
|
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 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 zmodem;
|
||||||
|
|
||||||
use kata_io as io;
|
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 {
|
pub struct Upload {
|
||||||
digest: crc32::Digest,
|
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 {
|
impl Upload {
|
||||||
pub fn new() -> Upload {
|
pub fn new() -> Self {
|
||||||
Upload {
|
Upload {
|
||||||
digest: crc32::Digest::new(crc32::IEEE),
|
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 {
|
pub fn crc32(&self) -> u32 {
|
||||||
self.digest.sum32()
|
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] {
|
// Unmap the current page and reset state.
|
||||||
self.contents.as_slice()
|
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 {
|
impl io::Write for Upload {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
self.digest.write(buf);
|
let mut cursor = buf;
|
||||||
self.contents.extend_from_slice(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())
|
Ok(buf.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -97,9 +97,6 @@ assembly {
|
|||||||
connection seL4HardwareMMIO vc_dtcm(from ml_coordinator.dtcm,
|
connection seL4HardwareMMIO vc_dtcm(from ml_coordinator.dtcm,
|
||||||
to vctop.dtcm);
|
to vctop.dtcm);
|
||||||
|
|
||||||
connection seL4HardwareMMIO vc_elf(from ml_coordinator.elf_file,
|
|
||||||
to vc_payload.elf_file);
|
|
||||||
|
|
||||||
// TimerService
|
// TimerService
|
||||||
connection seL4HardwareMMIO timer_csr(from timer_service.csr,
|
connection seL4HardwareMMIO timer_csr(from timer_service.csr,
|
||||||
to timer.csr);
|
to timer.csr);
|
||||||
@@ -123,7 +120,8 @@ assembly {
|
|||||||
// component and copies data between components.
|
// component and copies data between components.
|
||||||
connection seL4RPCOverMultiSharedData multi_memory(
|
connection seL4RPCOverMultiSharedData multi_memory(
|
||||||
from debug_console.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,
|
// TOOD(sleffler): from ml_coordinator.memory,
|
||||||
to memory_manager.memory);
|
to memory_manager.memory);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user