kata-os-logger: support no logging interface connection out of a component

When a CAmkES component lacks an outbound connection to send log msgs
there will be no logger_log symbol. Use a weak ref here to handle that
without resorting to a feature or similar.

Mark logger connections as "maybe" so they are optional.

Change-Id: I6ecd939014d26a612d115741fd2ac673afa40857
GitOrigin-RevId: 0b1bf2611cbb628500cae37889c6547a996d50e9
This commit is contained in:
Sam Leffler 2022-08-25 15:36:09 -07:00
parent 326ec0d6c9
commit b099005951
10 changed files with 42 additions and 33 deletions

View File

@ -25,5 +25,5 @@ component MailboxDriver {
consumes Interrupt rtirq;
consumes Interrupt eirq;
uses LoggerInterface logger;
maybe uses LoggerInterface logger;
}

View File

@ -20,7 +20,7 @@ import <MemoryInterface.camkes>;
component MemoryManager {
provides MemoryInterface memory;
uses LoggerInterface logger;
maybe uses LoggerInterface logger;
// Enable KataOS CAmkES support.
attribute int kataos = true;

View File

@ -16,6 +16,7 @@ import <LoggerInterface.camkes>;
import <MemoryInterface.camkes>;
import <MlCoordinatorInterface.camkes>;
import <SecurityCoordinatorInterface.camkes>;
import <TimerServiceInterface.camkes>;
component MlCoordinator {
control;
@ -32,7 +33,7 @@ component MlCoordinator {
dataport Buf CSR;
dataport Buf(0x1000000) TCM;
uses LoggerInterface logger;
maybe uses LoggerInterface logger;
uses MemoryInterface memory;
uses SecurityCoordinatorInterface security;

View File

@ -24,7 +24,7 @@ component ProcessManager {
provides PackageManagementInterface pkg_mgmt;
provides ProcessControlInterface proc_ctrl;
uses LoggerInterface logger;
maybe uses LoggerInterface logger;
uses MemoryInterface memory;
uses SecurityCoordinatorInterface security;

View File

@ -20,7 +20,7 @@ import <SDKRuntimeInterface.camkes>;
component SDKRuntime {
provides SDKRuntimeInterface sdk_runtime;
uses LoggerInterface logger;
maybe uses LoggerInterface logger;
// Enable KataOS CAmkES support.
attribute int kataos = true;

View File

@ -22,7 +22,7 @@ import <MailboxInterface.camkes>;
component SecurityCoordinator {
provides SecurityCoordinatorInterface security;
uses LoggerInterface logger;
maybe uses LoggerInterface logger;
uses MemoryInterface memory;
uses MailboxAPI mailbox_api;

View File

@ -21,7 +21,7 @@ import <StorageInterface.camkes>;
component StorageManager {
provides StorageInterface storage;
uses LoggerInterface logger;
maybe uses LoggerInterface logger;
uses SecurityCoordinatorInterface security;
// Enable KataOS CAmkES support.

View File

@ -20,7 +20,7 @@ component TimerService {
dataport Buf csr;
consumes Interrupt timer_interrupt;
uses LoggerInterface logger;
maybe uses LoggerInterface logger;
// Enable KataOS CAmkES support.
attribute int kataos = true;

View File

@ -8,4 +8,4 @@ arrayvec = { version = "0.7", default-features = false }
core2 = { version = "0.3", default-features = false }
# Disable default so we don't pull in CString which requires an allocator
cstr_core = { version = "0.2.3", default-features = false }
log = "0.4"
log = { version = "0.4" }

View File

@ -13,6 +13,14 @@
// limitations under the License.
#![cfg_attr(not(test), no_std)]
#![feature(linkage)]
extern "C" {
// NB: components may not have a logging connection in which case
// logger_log will be undefined/null.
#[linkage = "extern_weak"]
static logger_log: *const ();
}
use core2::io::{Cursor, Write};
use cstr_core::CStr;
@ -28,10 +36,12 @@ impl log::Log for KataLogger {
fn enabled(&self, _metadata: &Metadata) -> bool { true }
fn log(&self, record: &Record) {
let typed_logger_log: Option<extern "C" fn(level: u8, msg: *const u8)> =
unsafe { core::mem::transmute(logger_log) };
if typed_logger_log.is_none() {
return;
}
if self.enabled(record.metadata()) {
extern "C" {
fn logger_log(level: u8, msg: *const cstr_core::c_char);
}
let mut buf = [0 as u8; MAX_MSG_LEN];
let mut cur = Cursor::new(&mut buf[..]);
// Log msgs are of the form: '<target>::<fmt'd-msg>
@ -41,29 +51,27 @@ impl log::Log for KataLogger {
cur.write(b"...\0").expect("write!");
()
});
unsafe {
// If an embedded nul is identified, replace the message; there
// are likely better solutions but this should not happen.
fn embedded_nul_cstr<'a>(
buf: &'a mut [u8; MAX_MSG_LEN],
record: &Record,
) -> &'a cstr_core::CStr {
let mut cur = Cursor::new(&mut buf[..]);
write!(&mut cur, "{}::<embedded nul>\0", record.target()).expect("nul!");
let pos = cur.position() as usize;
CStr::from_bytes_with_nul(&buf[..pos]).unwrap()
}
// NB: this releases the ref on buf held by the Cursor
// If an embedded nul is identified, replace the message; there
// are likely better solutions but this should not happen.
fn embedded_nul_cstr<'a>(
buf: &'a mut [u8; MAX_MSG_LEN],
record: &Record,
) -> &'a cstr_core::CStr {
let mut cur = Cursor::new(&mut buf[..]);
write!(&mut cur, "{}::<embedded nul>\0", record.target()).expect("nul!");
let pos = cur.position() as usize;
logger_log(
record.level() as u8,
match CStr::from_bytes_with_nul(&buf[..pos]) {
Ok(cstr) => cstr,
Err(_) => embedded_nul_cstr(&mut buf, record),
}
.as_ptr(),
);
CStr::from_bytes_with_nul(&buf[..pos]).unwrap()
}
// NB: this releases the ref on buf held by the Cursor
let pos = cur.position() as usize;
(typed_logger_log.unwrap())(
record.level() as u8,
match CStr::from_bytes_with_nul(&buf[..pos]) {
Ok(cstr) => cstr,
Err(_) => embedded_nul_cstr(&mut buf, record),
}
.as_ptr(),
);
}
}