Add a simple rust global allocator to each component.

- add a linked_list_allocator::LockedHeap instance to each component that
  might want to allocate memory and init the allocator with a fixed-size
  memory block in the component post_init hook
- add an alloc_test shell command that exercises the allocator

This does not dynamically add memory or support sharing memory between
components; this is an intermediate step to simplify bringing in crates
that want to allocate memory (e.g. hashbrown)..

Change-Id: Idaf11fb5d4999218c75bf932133df24de35e3053
GitOrigin-RevId: 7c9b14bf9463239ce030c374b58a140f0835759e
This commit is contained in:
Sam Leffler 2021-07-14 12:16:29 -07:00
parent e4973577ec
commit 8d7e4bf44a
6 changed files with 88 additions and 76 deletions

View File

@ -1,49 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "cty"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
[[package]]
name = "kata-debug-console"
version = "0.1.0"
dependencies = [
"kata-shell",
"kata-uart-client",
"panic-halt",
]
[[package]]
name = "kata-io"
version = "0.1.0"
[[package]]
name = "kata-line-reader"
version = "0.1.0"
dependencies = [
"kata-io",
]
[[package]]
name = "kata-shell"
version = "0.1.0"
dependencies = [
"kata-io",
"kata-line-reader",
]
[[package]]
name = "kata-uart-client"
version = "0.1.0"
dependencies = [
"cty",
"kata-io",
]
[[package]]
name = "panic-halt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"

View File

@ -9,6 +9,7 @@ description = "Kata OS DebugConsole"
panic-halt = "0.2.0"
kata-shell = { path = "../kata-shell" }
kata-uart-client = { path = "../kata-uart-client" }
linked_list_allocator = "0.9"
[lib]
name = "kata_debug_console"

View File

@ -12,11 +12,29 @@
// std:: requires at least an allocator, which Kata does not have yet. For now
// the CLI will be implemented with only core::.
#![no_std]
// NB: not really what we want but resolves undefineds for now
#![feature(default_alloc_error_handler)]
extern crate panic_halt;
use kata_shell;
use kata_uart_client;
use linked_list_allocator::LockedHeap;
#[global_allocator]
static KATA_ALLOCATOR: LockedHeap = LockedHeap::empty();
#[no_mangle]
// NB: use post_init insted of pre_init so syslog interface is setup
pub extern "C" fn post_init() {
// TODO(sleffler): temp until we integrate with seL4
static mut HEAP_MEMORY: [u8; 16 * 1024] = [0; 16 * 1024];
unsafe {
KATA_ALLOCATOR
.lock()
.init(HEAP_MEMORY.as_mut_ptr() as usize, HEAP_MEMORY.len());
}
}
/// Entry point for DebugConsole. Runs the shell with UART IO.
#[no_mangle]

View File

@ -43,8 +43,8 @@ impl From<fmt::Error> for CommandError {
/// Read-eval-print loop for the DebugConsole command line interface.
pub fn repl(output: &mut dyn io::Write, input: &mut dyn io::Read) -> ! {
let _ = write!(output, "DebugConsole::repl()\n");
let mut line_reader = LineReader::new();
let _ = write!(output, "DebugConsole::repl()\n");
let mut line_reader = LineReader::new();
loop {
const PROMPT: &str = "KATA_PROMPT> ";
let _ = output.write_str(PROMPT);
@ -75,6 +75,7 @@ fn dispatch_command(cmdline: &str, output: &mut dyn io::Write) {
"add" => add_command(&mut args, output),
"clear" => clear_command(output),
"ps" => ps_command(),
"alloc_test" => alloc_test_command(output),
_ => Err(CommandError::UnknownCommand),
};
if let Err(e) = result {
@ -103,8 +104,12 @@ fn echo_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), Command
/// Implements a "ps" command that dumps seL4 scheduler state to the console.
fn ps_command() -> Result<(), CommandError> {
extern "C" { fn sel4debug_dump_scheduler(); }
unsafe { sel4debug_dump_scheduler(); }
extern "C" {
fn sel4debug_dump_scheduler();
}
unsafe {
sel4debug_dump_scheduler();
}
Ok(())
}
@ -133,3 +138,40 @@ fn add_command(
fn clear_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
Ok(output.write_str("\x1b\x63")?)
}
/// Implements a command that tests facilities that use the global allocator.
/// Shamelessly cribbed from https://os.phil-opp.com/heap-allocation/
fn alloc_test_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
extern crate alloc;
use alloc::{boxed::Box, rc::Rc, vec, vec::Vec};
// allocate a number on the heap
let heap_value = Box::new(41);
writeln!(output, "heap_value at {:p}", heap_value).expect("Box failed");
// create a dynamically sized vector
let mut vec = Vec::new();
for i in 0..500 {
vec.push(i);
}
writeln!(output, "vec at {:p}", vec.as_slice()).expect("Vec failed");
// create a reference counted vector -> will be freed when count reaches 0
let reference_counted = Rc::new(vec![1, 2, 3]);
let cloned_reference = reference_counted.clone();
writeln!(
output,
"current reference count is {}",
Rc::strong_count(&cloned_reference)
)
.expect("Rc 1 failed");
core::mem::drop(reference_counted);
writeln!(
output,
"reference count is {} now",
Rc::strong_count(&cloned_reference)
)
.expect("Rc 2 failed");
Ok(writeln!(output, "All tests passed!")?)
}

View File

@ -6,8 +6,8 @@ edition = "2018"
[dependencies]
arrayvec = { version = "0.7", default-features = false }
cstr_core = { version = "0.2.3", default-features = false }
kata-proc-common = { path = "../kata-proc-common" }
linked_list_allocator = "0.9"
panic-halt = "0.2.0"
[lib]

View File

@ -4,30 +4,38 @@
#![cfg_attr(not(test), no_std)]
#![feature(const_fn_trait_bound)] // NB: for ProcessManager::empty using manager: None
#![feature(default_alloc_error_handler)]
#[cfg(not(test))]
extern crate panic_halt;
use arrayvec::ArrayVec;
use core::marker::Sync;
use cstr_core::CStr;
use linked_list_allocator::LockedHeap;
use kata_proc_common as proc;
use proc::*;
// Prints/logs a message to the console.
// Temporary workaround for LoggerInterface not working
fn syslog(_level: i32, msg: &str) {
// Print |str| on the consule using the SeL4 debug syscall.
// NB: for now the message must be explicitly \0-terminated.
fn sel4_putstr(msg: &str) {
extern "C" {
fn sel4debug_put_string(msg: *const cstr_core::c_char);
}
unsafe {
sel4debug_put_string(CStr::from_bytes_with_nul(msg.as_bytes()).unwrap().as_ptr());
}
#[global_allocator]
static KATA_ALLOCATOR: LockedHeap = LockedHeap::empty();
#[no_mangle]
// NB: use post_init insted of pre_init so logger is setup
pub extern "C" fn post_init() {
// TODO(sleffler): temp until we integrate with seL4
static mut HEAP_MEMORY: [u8; 16 * 1024] = [0; 16 * 1024];
unsafe {
KATA_ALLOCATOR
.lock()
.init(HEAP_MEMORY.as_mut_ptr() as usize, HEAP_MEMORY.len());
}
sel4_putstr(msg); // NB:assumes caller includes \0
}
// TODO(sleffler): move to init or similar if a thread isn't needed
#[no_mangle]
pub extern "C" fn run() {
// Setup the userland address spaces, lifecycles, and system introspection
// for third-party applications.
}
// Bundle state tracks start/stop operations.
@ -175,14 +183,6 @@ impl<'a> ProcessControlInterface for ProcessManager<'a> {
}
}
// TODO(sleffler): move to init or similar if a thread isn't needed
#[no_mangle]
pub extern "C" fn run() {
// Setup the userland address spaces, lifecycles, and system introspection
// for third-party applications.
syslog(0, "ProcessManager::run\n\0");
}
#[cfg(test)]
mod tests {
use super::*;