Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add mctp userspace lib support #76

Merged
merged 5 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ members = [
"romtime",
"runtime",
"runtime/apps/example",
"runtime/apps/apis",
"runtime/apps/libtock/apis/interface/buttons",
"runtime/apps/libtock/apis/interface/buzzer",
"runtime/apps/libtock/apis/interface/console",
Expand Down Expand Up @@ -91,6 +92,7 @@ num-traits = "0.2"
portable-atomic = "1.7.0"
proc-macro2 = "1.0.66"
quote = "1.0"
rand = "0.8.5"
semver = "1.0.23"
serde = { version = "1.0.209", features = ["alloc", "derive", "serde_derive"] }
serde_json = { version = "1.0.127", features = ["alloc"] }
Expand Down Expand Up @@ -128,6 +130,7 @@ libtock_debug_panic = { path = "runtime/apps/libtock/panic_handlers/debug_panic"
libtock_platform = { path = "runtime/apps/libtock/platform" }
libtock_runtime = { path = "runtime/apps/libtock/runtime" }
libtock_unittest = { path = "runtime/apps/libtock/unittest" }
libtock_caliptra = { path = "runtime/apps/apis" }

# caliptra dependencies; keep git revs in sync
caliptra-api-types = { git = "https://github.com/chipsalliance/caliptra-sw.git", rev = "2f6de531e321b7bb24b17b1bd02b43d2854aef3a" }
Expand Down
96 changes: 52 additions & 44 deletions docs/src/mctp.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ sequenceDiagram

## Syscall Library in userspace
Userspace applications can use syscall library in to send and receive MCTP messages. The following APIs are provided by the MCTP syscall library.
Each user space application will instantiate the `AsyncMctp` module with appropriate driver number. The `AsyncMctp` module provides the following APIs to send and receive MCTP messages.
Each user space application will instantiate the `Mctp` module with appropriate driver number. The `Mctp` module provides the following APIs to send and receive MCTP messages.

```Rust
//! The MCTP library provides the interface to send and receive MCTP messages.
Expand All @@ -96,27 +96,27 @@ Each user space application will instantiate the `AsyncMctp` module with appropr
//! Usage
//! -----
//!```Rust
//! use mctp::AsyncMctp;
//! use mctp::Mctp;
//!
//! const SPDM_MESSAGE_TYPE: u8 = 0x5;
//! const SECURE_SPDM_MESSAGE_TYPE: u8 = 0x6;
//!
//! #[embassy_executor::task]
//! async fn async_main() {
//! /// Initialize the MCTP driver with the driver number
//! let mctp = AsyncMctp::<TockSyscalls>::new(MCTP_SPDM_DRIVER_NUM);
//! let mctp = Mctp::<TockSyscalls>::new(MCTP_SPDM_DRIVER_NUM);
//!
//! loop {
//! /// Receive the MCTP request
//! let mut rx_buf = [0; 1024];
//! let res = mctp.receive_request(0x0, SPDM_MESSAGE_TYPE, &mut rx_buf).await;
//! let res = mctp.receive_request(&mut rx_buf).await;
//! match res {
//! Ok(msg_info) => {
//! Ok((req_len, msg_info)) => {
//! /// Process the received message
//! /// ........
//! /// Send the response message
//! let mut tx_buf = [0; 1024];
//! let result = mctp.send_response(msg_info.eid, msg_info.msg_tag, &tx_buf).await;
//! let result = mctp.send_response(&tx_buf, msg_info).await;
//! match result {
//! Ok(_) => {
//! /// Handle the send response success
Expand All @@ -135,68 +135,75 @@ Each user space application will instantiate the `AsyncMctp` module with appropr
//!```

/// mctp/src/lib.rs
pub struct AsyncMctp<S:Syscalls, C:Config = DefaultConfig > {
syscall: PhantomData<S>,
config: PhantomData<C>,
driver_num: usize,
}
type EndpointId = u8;
type Tag = u8;

pub struct MessageInfo {
pub eid: u8,
pub msg_tag: u8,
pub msg_type: u8, /// Needed for SPDM to differentiate between SPDM(0x5) and secured SPDM(0x6) messages
pub payload_len: usize,
eid: EndpointId,
tag: Tag,
}

pub struct Mctp<S: Syscalls> {
syscall: PhantomData<S>,
driver_num: u32,
}

impl<S:Syscalls, C:Config> Mctp<S,C> {
impl<S: Syscalls> Mctp<S> {
/// Create a new instance of the MCTP driver
///
/// # Arguments
/// * `driver_num` - The driver number for the MCTP driver
///
/// # Returns
/// * `Mctp` - The MCTP driver instance
pub fn new(drv_num: u32) -> Self;
/// Check if the MCTP driver for a specific message type exists
///
/// # Returns
/// * `bool` - `true` if the driver exists, `false` otherwise
pub fn exists() -> Result<(), ErrorCode>;
/// Receive the MCTP request from the source EID
/// Receive the MCTP request.
/// Receives a message from any source EID. The user should use the returned MessageInfo to send a response.
///
/// # Arguments
/// * `source_eid` - The source EID from which the request is to be received.
/// * `message_types` - The message types to receive. This is needed for SPDM to receive both SPDM(0x5) and secured SPDM(0x6) messages
/// * `msg_payload` - The buffer to store the received message payload
/// * `req` - The buffer to store the received request payload
///
/// # Returns
/// * `MessageInfo` - The message information containing the EID, message tag, message type, and payload length on success
/// * `(u32, MessageInfo)` - On success, returns tuple containing length of the request received and the message information containing the source EID, message tag
/// * `ErrorCode` - The error code on failure
pub async fn receive_request(&self, source_eid: u8, message_types: [u8], msg_payload: &mut [u8]) -> Result<MessageInfo, ErrorCode>;
/// Send the MCTP response to the destination EID
pub async fn receive_request(&self, req: &mut [u8]) -> Result<(u32, MessageInfo), ErrorCode>;
/// Send the MCTP response to an endpoint
///
/// # Arguments
/// * `dest_eid` - The destination EID to which the response is to be sent
/// * `msg_tag` - The message tag assigned to the request
/// * `msg_payload` - The payload to be sent in the response
/// * `resp` - The buffer containing the response payload
/// * `info` - The message information containing the destination EID, message tag which was received in `receive_request` call
///
/// # Returns
/// * `()` - On success
/// * `ErrorCode` - The error code on failure
pub async fn send_response(&self, dest_eid: u8, msg_tag: u8, msg_payload: &[u8]) -> Result<(), ErrorCode>;
pub async fn send_response(&self, resp: &[u8], info: MessageInfo) -> Result<(), ErrorCode>;
/// Send the MCTP request to the destination EID

/// The function returns the message tag assigned to the request.
/// The function returns the message tag assigned to the request by the MCTP Capsule.
/// This tag will be used in the `receive_response` call to receive the corresponding response.
///
/// # Arguments
/// * `dest_eid` - The destination EID to which the request is to be sent
/// * `msg_payload` - The payload to be sent in the request
/// * `req` - The payload to be sent in the request
///
/// # Returns
/// * `u8` - The message tag assigned to the request
/// * `Tag` - The message tag assigned to the request
/// * `ErrorCode` - The error code on failure
pub async fn send_request(&self, dest_eid: u8, msg_payload: &[u8]) -> Result<u8, ErrorCode>;

/// Receive the MCTP response from the source EID
pub async fn send_request(&self, dest_eid: u8, req: &[u8]) -> Result<Tag, ErrorCode>;
/// Receive the MCTP response from an endpoint
///
/// # Arguments
/// * `source_eid` - The source EID from which the response is to be received
/// * `message_type` - The message type to receive. This is needed for SPDM to differentiate between SPDM(0x5) and secured SPDM(0x6) messages
/// * `msg_payload` - The buffer to store the received response payload
///
/// * `resp` - The buffer to store the received response payload from the endpoint
/// * `tag` - The message tag to match against the response message
///
/// # Returns
/// * `()` - On success
/// * `(u32, MessageInfo)` - On success, returns tuple containing length of the response received and the message information containing the source EID, message tag
/// * `ErrorCode` - The error code on failure
pub async fn receive_response(&self, source_eid: u8, message_type: u8, msg_payload: &mut [u8]) -> Result<(), ErrorCode>;
pub async fn receive_response(&self, resp: &mut [u8], tag: Tag) -> Result<(u32, MessageInfo), ErrorCode>;
}
```

Expand All @@ -209,8 +216,9 @@ pub enum NUM {
...
// Mctp
MctpSpdm = 0xA0000,
MctpPldm = 0xA0001,
MctpVenDef = 0xA0002,
MctpSecureSpdm = 0xA0001,
MctpPldm = 0xA0002,
MctpVenDef = 0xA0003,
...
}

Expand Down Expand Up @@ -287,7 +295,7 @@ pub struct App {
bound_msg_type : u8,
}

/// Implements userspace driver for a particular message_type.
/// Implements userspace driver for a particular msg_type.
pub struct VirtualMCTPDriver {
mctp_sender: &dyn MCTPSender,
apps : Grant<App, 2 /*upcalls*/, 1 /*allowro*/, 1/*allow_rw*/>,
Expand Down Expand Up @@ -333,7 +341,7 @@ pub struct MCTPTxState<M:MCTPTransportBinding> {

```Rust
/// This is the trait implemented by VirtualMCTPDriver instance to get notified of
/// the messages received on corresponding message_type.
/// the messages received on corresponding msg_type.
pub trait MCTPRxClient {
fn receive(&self, dst_eid: u8, msg_type: u8, msg_tag: u8, msg_payload: &[u8]);
}
Expand Down
6 changes: 4 additions & 2 deletions emulator/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ emulator-types.workspace = true
gdbstub_arch.workspace = true
gdbstub.workspace = true
hex.workspace = true
rand.workspace = true
strum_macros.workspace = true
strum.workspace = true
tock-registers.workspace = true
Expand All @@ -37,7 +38,8 @@ test-i3c-constant-writes = ["emulator-periph/test-i3c-constant-writes"]
test-flash-ctrl-init = []
test-flash-ctrl-read-write-page = []
test-flash-ctrl-erase-page = []
test-mctp-ctrl-cmds = ["emulator-periph/test-mctp-ctrl-cmds"]
test-mctp-send-loopback = ["emulator-periph/test-mctp-send-loopback"]
test-flash-storage-read-write = []
test-flash-storage-erase = []
test-mctp-ctrl-cmds = ["emulator-periph/test-mctp-ctrl-cmds"]
test-mctp-capsule-loopback = ["emulator-periph/test-mctp-capsule-loopback"]
test-mctp-user-loopback = ["emulator-periph/test-mctp-user-loopback"]
19 changes: 18 additions & 1 deletion emulator/app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ fn run(cli: Emulator, capture_uart_output: bool) -> io::Result<Vec<u8>> {
i3c.get_dynamic_address().unwrap(),
tests,
);
} else if cfg!(feature = "test-mctp-send-loopback") {
} else if cfg!(feature = "test-mctp-capsule-loopback") {
i3c_controller.start();
println!(
"Starting loopback test thread for testing target {:?}",
Expand All @@ -385,6 +385,23 @@ fn run(cli: Emulator, capture_uart_output: bool) -> io::Result<Vec<u8>> {
i3c.get_dynamic_address().unwrap(),
tests,
);
} else if cfg!(feature = "test-mctp-user-loopback") {
i3c_controller.start();
println!(
"Starting loopback test thread for testing target {:?}",
i3c.get_dynamic_address().unwrap()
);

let spdm_loopback_tests = tests::mctp_user_loopback::MctpUserAppTests::generate_tests(
tests::mctp_util::base_protocol::MctpMsgType::Spdm as u8,
);

i3c_socket::run_tests(
running.clone(),
cli.i3c_port.unwrap(),
i3c.get_dynamic_address().unwrap(),
spdm_loopback_tests,
);
}

let flash_ctrl_error_irq = pic.register_irq(CaliptraRootBus::FLASH_CTRL_ERROR_IRQ);
Expand Down
8 changes: 3 additions & 5 deletions emulator/app/src/tests/mctp_ctrl_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::i3c_socket::{
receive_ibi, receive_private_read, send_private_write, TestState, TestTrait,
};
use crate::tests::mctp_util::base_protocol::{
MCTPHdr, MCTPMsgHdr, MCTP_HDR_SIZE, MCTP_MSG_HDR_SIZE,
MCTPHdr, MCTPMsgHdr, LOCAL_TEST_ENDPOINT_EID, MCTP_HDR_SIZE, MCTP_MSG_HDR_SIZE,
};
use crate::tests::mctp_util::ctrl_protocol::*;
use std::net::TcpStream;
Expand All @@ -28,8 +28,6 @@ const MCTP_MSG_HDR_OFFSET: usize = MCTP_HDR_OFFSET + MCTP_HDR_SIZE;
const MCTP_CTRL_MSG_HDR_OFFSET: usize = MCTP_MSG_HDR_OFFSET + MCTP_MSG_HDR_SIZE;
const MCTP_CTRL_PAYLOAD_OFFSET: usize = MCTP_CTRL_MSG_HDR_OFFSET + MCTP_CTRL_MSG_HDR_SIZE;

const LOCAL_ENDPOINT_EID: u8 = 0x08;

#[derive(EnumIter, Debug)]
pub(crate) enum MCTPCtrlCmdTests {
SetEID,
Expand All @@ -54,7 +52,7 @@ impl MCTPCtrlCmdTests {

fn generate_request_packet(&self) -> Vec<u8> {
let mut mctp_hdr = MCTPHdr::new();
mctp_hdr.prepare_header(0, LOCAL_ENDPOINT_EID, 1, 1, 0, 1, self.msg_tag());
mctp_hdr.prepare_header(0, LOCAL_TEST_ENDPOINT_EID, 1, 1, 0, 1, self.msg_tag());

let mctp_common_msg_hdr = MCTPMsgHdr::new();

Expand Down Expand Up @@ -86,7 +84,7 @@ impl MCTPCtrlCmdTests {

fn generate_response_packet(&self) -> Vec<u8> {
let mut mctp_hdr = MCTPHdr::new();
mctp_hdr.prepare_header(LOCAL_ENDPOINT_EID, 0, 1, 1, 0, 0, self.msg_tag());
mctp_hdr.prepare_header(LOCAL_TEST_ENDPOINT_EID, 0, 1, 1, 0, 0, self.msg_tag());

let mctp_common_msg_hdr = MCTPMsgHdr::new();

Expand Down
Loading