Skip to content

Commit

Permalink
gimlet-inspector: first draft.
Browse files Browse the repository at this point in the history
  • Loading branch information
cbiffle committed Jan 25, 2024
1 parent dc95c25 commit 148f998
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 17 deletions.
56 changes: 39 additions & 17 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ zip = { version = "0.6", default-features = false, features = ["bzip2"] }
attest-data = { git = "https://github.com/oxidecomputer/dice-util", default-features = false, version = "0.1.0" }
dice-mfg-msgs = { git = "https://github.com/oxidecomputer/dice-util", default-features = false, version = "0.2.1" }
gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", default-features = false, features = ["smoltcp"] }
gimlet-inspector-protocol = { git = "https://github.com/oxidecomputer/gimlet-inspector-protocol", version = "0.1.0", branch = "initial-protocol" }
hif = { git = "https://github.com/oxidecomputer/hif", default-features = false }
humpty = { git = "https://github.com/oxidecomputer/humpty", default-features = false, version = "0.1.3" }
hubtools = { git = "https://github.com/oxidecomputer/hubtools", default-features = false, version = "0.4.1" }
Expand Down
17 changes: 17 additions & 0 deletions app/gimlet/base.toml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,16 @@ copy-to-archive = ["register_defs"]
fpga_image = "fpga-b.bin"
register_defs = "gimlet-regs-b.json"

[tasks.gimlet_inspector]
name = "task-gimlet-inspector"
priority = 6
features = ["vlan"]
max-sizes = {flash = 65536, ram = 8192 }
stacksize = 1600
start = true
task-slots = ["net", {seq = "gimlet_seq"}]
notifications = ["socket"]

[tasks.hash_driver]
name = "drv-stm32h7-hash-server"
features = ["h753"]
Expand Down Expand Up @@ -1271,6 +1281,13 @@ port = 11113
tx = { packets = 3, bytes = 1024 }
rx = { packets = 3, bytes = 1024 }

[config.net.sockets.inspector]
kind = "udp"
owner = {name = "gimlet_inspector", notification = "socket"}
port = 23547
tx = { packets = 3, bytes = 1024 }
rx = { packets = 3, bytes = 512 }

[config.sprot]
# ROT_IRQ (af=0 for GPIO, af=15 when EXTI is implemneted)
rot_irq = { port = "E", pin = 3, af = 0}
28 changes: 28 additions & 0 deletions task/gimlet-inspector/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "task-gimlet-inspector"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { workspace = true }
hubpack = { workspace = true }
gimlet-inspector-protocol = { workspace = true }

task-net-api = { path = "../net-api" }
drv-gimlet-seq-api = { path = "../../drv/gimlet-seq-api" }
userlib = { path = "../../sys/userlib", features = ["panic-messages"] }


[build-dependencies]
build-util = { path = "../../build/util" }

[features]
vlan = ["task-net-api/vlan"]

# This section is here to discourage RLS/rust-analyzer from doing test builds,
# since test builds don't work for cross compilation.
[[bin]]
name = "task-gimlet-inspector"
test = false
doctest = false
bench = false
8 changes: 8 additions & 0 deletions task/gimlet-inspector/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
build_util::build_notifications()?;
Ok(())
}
134 changes: 134 additions & 0 deletions task/gimlet-inspector/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! The Gimlet Inspector provides a deliberately limited set of IPCs over the
//! network, for extracting diagnostic data from a live system. This is intended
//! to supplement the more general `dump_agent`.
#![no_std]
#![no_main]

use task_net_api::*;
use userlib::*;
use gimlet_inspector_protocol::{Request, Query, SequencerRegistersResponse};
use drv_gimlet_seq_api::{Sequencer, SeqError};
use hubpack::SerializedSize;

task_slot!(NET, net);
task_slot!(SEQ, seq);

// Increase this if a new message requires a larger trailer.
const MAX_REQ_TRAILER_SIZE: usize = 0;

#[export_name = "main"]
fn main() -> ! {
// Look up our peer task IDs and make clients.
let net = Net::from(NET.get_task_id());
let seq = Sequencer::from(SEQ.get_task_id());

const SOCKET: SocketName = SocketName::inspector;

loop {
// These buffers are currently kept kinda small because our protocol
// messages are small.
let mut rx_data_buf = [0u8; Request::MAX_SIZE + MAX_REQ_TRAILER_SIZE];
let mut tx_data_buf = [0u8; 128];

match net.recv_packet(
SOCKET,
LargePayloadBehavior::Discard,
&mut rx_data_buf,
) {
Ok(mut meta) => {
let Ok((request, _trailer)) = hubpack::deserialize::<Request>(&rx_data_buf) else {
// We ignore malformatted, truncated, etc. packets.
continue;
};

match request {
Request::V0(Query::SequencerRegisters) => {
let (resp, trailer) = match seq.read_fpga_regs() {
Ok(regs) => {
(SequencerRegistersResponse::Success, Some(regs))
}
Err(SeqError::ServerRestarted) => {
(SequencerRegistersResponse::SequencerTaskDead, None)
}
Err(_) => {
// The SeqError type represents a mashing
// together of all possible errors for all
// possible sequencer IPC operations. The only
// one we _expect_ here is ReadRegsFailed.
(SequencerRegistersResponse::SequencerReadRegsFailed, None)
}
};
let mut len = hubpack::serialize(&mut tx_data_buf, &resp)
.unwrap_lite();
if let Some(t) = trailer {
tx_data_buf[len..len + t.len()].copy_from_slice(&t);
len += t.len();
}
meta.size = len as u32;
}
}

// With the response packet prepared, we may need to attempt
// sending more than once.
loop {
match net.send_packet(
SOCKET,
meta,
&tx_data_buf[0..(meta.size as usize)],
) {
Ok(()) => break,
// If `net` just restarted, immediately retry our send.
Err(SendError::ServerRestarted) => continue,
// If our tx queue is full, wait for space. This is the
// same notification we get for incoming packets, so we
// might spuriously wake up due to an incoming packet
// (which we can't service anyway because we are still
// waiting to respond to a previous request); once we
// finally succeed in sending we'll peel any queued
// packets off our recv queue at the top of our main
// loop.
Err(SendError::QueueFull) => {
sys_recv_closed(
&mut [],
notifications::SOCKET_MASK,
TaskId::KERNEL,
)
.unwrap_lite();
}
// These errors should be impossible if we're configured
// correctly.
Err(SendError::NotYours | SendError::InvalidVLan) => {
unreachable!()
}
// Unclear under what conditions we could se `Other` -
// just panic for now? At the time of this writing
// `Other` should only come back if the destination
// address in `meta` is bogus or our socket is closed,
// neither of which should be possible here.
Err(SendError::Other) => panic!(),
}
}
}
Err(RecvError::QueueEmpty) => {
// Our incoming queue is empty. Wait for more packets.
sys_recv_closed(
&mut [],
notifications::SOCKET_MASK,
TaskId::KERNEL,
)
.unwrap_lite();
}
Err(RecvError::ServerRestarted) => {
// `net` restarted (probably due to the watchdog); just retry.
}
Err(RecvError::NotYours | RecvError::Other) => panic!(),
}
}
}

include!(concat!(env!("OUT_DIR"), "/notifications.rs"));

0 comments on commit 148f998

Please sign in to comment.