diff --git a/app/minibar/base.toml b/app/minibar/base.toml index b6f970f7c..576d4ed87 100644 --- a/app/minibar/base.toml +++ b/app/minibar/base.toml @@ -148,6 +148,17 @@ start = true task-slots = ["sys", "i2c_driver"] stacksize = 800 +[tasks.update_server] +name = "stm32h7-update-server" +priority = 2 +max-sizes = {flash = 16384, ram = 4096} +stacksize = 2048 +start = true +uses = ["flash_controller"] +extern-regions = ["bank2"] +interrupts = {"flash_controller.irq" = "flash-irq"} +notifications = ["flash-irq"] + [tasks.idle] name = "task-idle" priority = 8 diff --git a/app/minibar/rev-b.toml b/app/minibar/rev-b.toml index 4855cf29b..b6f0e2a9c 100644 --- a/app/minibar/rev-b.toml +++ b/app/minibar/rev-b.toml @@ -50,6 +50,29 @@ extern-regions = [ "sram1", "sram2", "sram3", "sram4" ] notifications = ["socket"] features = ["net", "vlan"] +# Rev A boards had a hardware bug that kept the minibar's SP from being +# reachable over the management network, therefore we only include +# control-plane-agent for rev B. +[tasks.control_plane_agent] +name = "task-control-plane-agent" +priority = 7 +stacksize = 8000 +start = true +task-slots = [ + "jefe", + "net", + "sys", + "packrat", + "sensor", + "sprot", + "ignition", + "validate", + "update_server", + "dump_agent", +] +features = ["minibar", "vlan"] +notifications = ["socket", "timer"] + # VLAN configuration [config.net.vlans.port1] @@ -76,3 +99,10 @@ port = 11113 tx = { packets = 3, bytes = 1024 } rx = { packets = 3, bytes = 1024 } +[config.net.sockets.control_plane_agent] +kind = "udp" +owner = {name = "control_plane_agent", notification = "socket"} +port = 11111 +tx = { packets = 3, bytes = 2048 } +rx = { packets = 3, bytes = 2048 } + diff --git a/task/control-plane-agent/Cargo.toml b/task/control-plane-agent/Cargo.toml index 519193cea..dfbc71f39 100644 --- a/task/control-plane-agent/Cargo.toml +++ b/task/control-plane-agent/Cargo.toml @@ -66,6 +66,7 @@ gimlet = ["compute-sled"] cosmo = ["compute-sled"] sidecar = ["drv-sidecar-seq-api", "drv-monorail-api", "drv-ignition-api", "drv-transceivers-api", "p256", "sha2", "drv-rng-api"] psc = ["drv-user-leds-api"] +minibar = ["drv-ignition-api"] vpd = ["task-vpd-api"] vlan = ["task-net-api/vlan"] diff --git a/task/control-plane-agent/src/mgs_sidecar/ignition.rs b/task/control-plane-agent/src/ignition_controller.rs similarity index 76% rename from task/control-plane-agent/src/mgs_sidecar/ignition.rs rename to task/control-plane-agent/src/ignition_controller.rs index 71d4894e9..dd78b9a83 100644 --- a/task/control-plane-agent/src/mgs_sidecar/ignition.rs +++ b/task/control-plane-agent/src/ignition_controller.rs @@ -10,13 +10,13 @@ use gateway_messages::ignition::{ IgnitionState, LinkEvents, ReceiverStatus, SystemFaults, SystemPowerState, SystemType, TargetState, TransceiverEvents, TransceiverSelect, }; -use gateway_messages::IgnitionCommand; +use gateway_messages::{IgnitionCommand, SpError}; use heapless::Vec; use userlib::UnwrapLite; userlib::task_slot!(IGNITION, ignition); -pub(super) struct IgnitionController { +pub(crate) struct IgnitionController { task: Ignition, // We cache the number of ignition ports the first time we successfully call // it since it never changes (it's the total number of ports, which is baked @@ -26,54 +26,70 @@ pub(super) struct IgnitionController { } impl IgnitionController { - pub(super) fn new() -> Self { + pub(crate) fn new() -> Self { Self { task: Ignition::new(IGNITION.get_task_id()), num_ports: Cell::new(None), } } - pub(super) fn num_ports(&self) -> Result { + pub(crate) fn num_ports(&self) -> Result { if let Some(n) = self.num_ports.get() { return Ok(n); } - let n = u32::from(self.task.port_count()?); + let n = u32::from( + self.task + .port_count() + .map_err(sp_error_from_ignition_error)?, + ); self.num_ports.set(Some(n)); Ok(n) } - pub(super) fn target_state( + pub(crate) fn target_state( &self, target: u8, - ) -> Result { - let port = self.task.port(target)?; + ) -> Result { + let port = self + .task + .port(target) + .map_err(sp_error_from_ignition_error)?; Ok(PortConvert(port).into()) } - pub(super) fn bulk_state( + pub(crate) fn bulk_state( &self, offset: u32, - ) -> Result { - let iter = self.task.all_ports()?; + ) -> Result { + let iter = self + .task + .all_ports() + .map_err(sp_error_from_ignition_error)?; Ok(BulkIgnitionStateIter { iter: iter.skip(offset as usize), }) } - pub(super) fn target_link_events( + pub(crate) fn target_link_events( &self, target: u8, - ) -> Result { - let events = self.task.link_events(target)?; + ) -> Result { + let events = self + .task + .link_events(target) + .map_err(sp_error_from_ignition_error)?; Ok(LinkEventsConvert(events).into()) } - pub(super) fn bulk_link_events( + pub(crate) fn bulk_link_events( &self, offset: u32, - ) -> Result { - let iter = self.task.all_link_events()?; + ) -> Result { + let iter = self + .task + .all_link_events() + .map_err(sp_error_from_ignition_error)?; Ok(BulkIgnitionLinkEventsIter { iter: iter.skip(offset as usize), }) @@ -83,7 +99,7 @@ impl IgnitionController { &self, target: Option, transceiver_select: Option, - ) -> Result<(), IgnitionError> { + ) -> Result<(), SpError> { use drv_ignition_api::TransceiverSelect as IgnitionTxrSelect; // Convert `target` to a range (either of length 1, if we got a target, @@ -121,7 +137,9 @@ impl IgnitionController { // each target/transceiver they care about? for target in targets { for &txr in &txrs { - self.task.clear_transceiver_events(target, txr)?; + self.task + .clear_transceiver_events(target, txr) + .map_err(sp_error_from_ignition_error)?; } } @@ -132,26 +150,31 @@ impl IgnitionController { &self, target: u8, command: IgnitionCommand, - ) -> Result<(), IgnitionError> { + ) -> Result<(), SpError> { use drv_ignition_api::Request; let cmd = match command { // We intercept the AlwaysTransmit command as it is not part of the // Ignition protocol (not something we send to a target), it is // a setting in the controller itself. IgnitionCommand::AlwaysTransmit { enabled } => { - return self.task.set_always_transmit(target, enabled); + return self + .task + .set_always_transmit(target, enabled) + .map_err(sp_error_from_ignition_error); } IgnitionCommand::PowerOn => Request::SystemPowerOn, IgnitionCommand::PowerOff => Request::SystemPowerOff, IgnitionCommand::PowerReset => Request::SystemPowerReset, }; - self.task.send_request(target, cmd)?; + self.task + .send_request(target, cmd) + .map_err(sp_error_from_ignition_error)?; Ok(()) } } -pub struct BulkIgnitionStateIter { +pub(crate) struct BulkIgnitionStateIter { iter: core::iter::Skip, } @@ -163,7 +186,7 @@ impl Iterator for BulkIgnitionStateIter { } } -pub struct BulkIgnitionLinkEventsIter { +pub(crate) struct BulkIgnitionLinkEventsIter { iter: core::iter::Skip, } @@ -280,3 +303,19 @@ impl From for TransceiverEvents { } } } + +// Helper function for `.map_err()`; we can't use `?` because we can't implement +// `From<_>` between these types due to orphan rules. +fn sp_error_from_ignition_error(err: IgnitionError) -> SpError { + use gateway_messages::ignition::IgnitionError as E; + let err = match err { + IgnitionError::FpgaError => E::FpgaError, + IgnitionError::InvalidPort => E::InvalidPort, + IgnitionError::InvalidValue => E::InvalidValue, + IgnitionError::NoTargetPresent => E::NoTargetPresent, + IgnitionError::RequestInProgress => E::RequestInProgress, + IgnitionError::RequestDiscarded => E::RequestDiscarded, + _ => E::Other(err as u32), + }; + SpError::Ignition(err) +} diff --git a/task/control-plane-agent/src/main.rs b/task/control-plane-agent/src/main.rs index 2d0ee1490..dc7cfbbf6 100644 --- a/task/control-plane-agent/src/main.rs +++ b/task/control-plane-agent/src/main.rs @@ -32,17 +32,21 @@ mod update; pub(crate) mod dump; -// If the build system enables multiple of the gimlet/sidecar/psc features, this +// If the build system enables multiple of the gimlet/sidecar/psc/minibar features, this // sequence of `cfg_attr`s will trigger an unused_attributes warning. We build // everything with -Dunused_attributes, which will catch any such build system // misconfiguration. #[cfg_attr(feature = "compute-sled", path = "mgs_compute_sled.rs")] #[cfg_attr(feature = "sidecar", path = "mgs_sidecar.rs")] #[cfg_attr(feature = "psc", path = "mgs_psc.rs")] +#[cfg_attr(feature = "minibar", path = "mgs_minibar.rs")] mod mgs_handler; use self::mgs_handler::MgsHandler; +#[cfg(any(feature = "sidecar", feature = "minibar"))] +mod ignition_controller; + task_slot!(JEFE, jefe); task_slot!(NET, net); task_slot!(SYS, sys); @@ -259,12 +263,21 @@ impl ServerImpl { impl NotificationHandler for ServerImpl { fn current_notification_mask(&self) -> u32 { - notifications::SOCKET_MASK + #[cfg(not(feature = "minibar"))] + let mask = notifications::SOCKET_MASK | notifications::USART_IRQ_MASK - | notifications::TIMER_MASK + | notifications::TIMER_MASK; + + // Minibar does not configure USART for serial console, so omit it + // from the mask. + #[cfg(feature = "minibar")] + let mask = notifications::SOCKET_MASK | notifications::TIMER_MASK; + + mask } fn handle_notification(&mut self, bits: userlib::NotificationBits) { + #[cfg(not(feature = "minibar"))] if bits.check_notification_mask(notifications::USART_IRQ_MASK) { self.mgs_handler.drive_usart(); } diff --git a/task/control-plane-agent/src/mgs_minibar.rs b/task/control-plane-agent/src/mgs_minibar.rs new file mode 100644 index 000000000..758180df5 --- /dev/null +++ b/task/control-plane-agent/src/mgs_minibar.rs @@ -0,0 +1,683 @@ +// 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/. + +use crate::{ + ignition_controller::{self, IgnitionController}, + mgs_common::MgsCommon, + update::rot::RotUpdate, + update::sp::SpUpdate, + update::ComponentUpdater, + usize_max, CriticalEvent, Log, MgsMessage, +}; +use gateway_messages::sp_impl::{ + BoundsChecked, DeviceDescription, Sender, SpHandler, +}; +use gateway_messages::{ + ignition, ComponentAction, ComponentActionResponse, ComponentDetails, + ComponentUpdatePrepare, DiscoverResponse, DumpSegment, DumpTask, + IgnitionCommand, IgnitionState, MgsError, MgsRequest, MgsResponse, + PowerState, PowerStateTransition, RotBootInfo, RotRequest, RotResponse, + SensorRequest, SensorResponse, SpComponent, SpError, SpStateV2, + SpUpdatePrepare, UpdateChunk, UpdateId, UpdateStatus, +}; +use host_sp_messages::HostStartupOptions; +use idol_runtime::{Leased, RequestError}; +use ringbuf::ringbuf_entry_root; +use task_control_plane_agent_api::{ControlPlaneAgentError, OxideIdentity}; +use task_net_api::{MacAddress, UdpMetadata, VLanId}; +use userlib::sys_get_timer; + +// How big does our shared update buffer need to be? Has to be able to handle SP +// update blocks for now, no other updateable components. +const UPDATE_BUFFER_SIZE: usize = + usize_max(SpUpdate::BLOCK_SIZE, RotUpdate::BLOCK_SIZE); + +// Create type aliases that include our `UpdateBuffer` size (i.e., the size of +// the largest update chunk of all the components we update). +pub(crate) type UpdateBuffer = + update_buffer::UpdateBuffer; +pub(crate) type BorrowedUpdateBuffer = update_buffer::BorrowedUpdateBuffer< + 'static, + SpComponent, + UPDATE_BUFFER_SIZE, +>; + +// Our single, shared update buffer. +static UPDATE_MEMORY: UpdateBuffer = UpdateBuffer::new(); + +pub(crate) struct MgsHandler { + common: MgsCommon, + ignition: IgnitionController, +} + +impl MgsHandler { + /// Instantiate an `MgsHandler` that claims static buffers and device + /// resources. Can only be called once; will panic if called multiple times! + pub(crate) fn claim_static_resources(base_mac_address: MacAddress) -> Self { + Self { + common: MgsCommon::claim_static_resources(base_mac_address), + ignition: IgnitionController::new(), + } + } + + pub(crate) fn identity(&self) -> OxideIdentity { + self.common.identity() + } + + /// If we want to be woken by the system timer, we return a deadline here. + /// `main()` is responsible for calling this method and actually setting the + /// timer. + pub(crate) fn timer_deadline(&self) -> Option { + if self.common.sp_update.is_preparing() { + Some(sys_get_timer().now + 1) + } else { + None + } + } + + pub(crate) fn handle_timer_fired(&mut self) { + // This is a no-op if we're not preparing for an SP update. + self.common.sp_update.step_preparation(); + } + + pub(crate) fn wants_to_send_packet_to_mgs(&mut self) -> bool { + false + } + + pub(crate) fn packet_to_mgs( + &mut self, + _tx_buf: &mut [u8; gateway_messages::MAX_SERIALIZED_SIZE], + ) -> Option { + None + } + + pub(crate) fn fetch_host_phase2_data( + &mut self, + _msg: &userlib::RecvMessage, + _image_hash: [u8; 32], + _offset: u64, + _notification_bit: u8, + ) -> Result<(), RequestError> { + Err(ControlPlaneAgentError::OperationUnsupported.into()) + } + + pub(crate) fn get_host_phase2_data( + &mut self, + _image_hash: [u8; 32], + _offset: u64, + _data: Leased, + ) -> Result> { + Err(ControlPlaneAgentError::OperationUnsupported.into()) + } + + pub(crate) fn startup_options_impl( + &self, + ) -> Result> { + // We don't have a host to give startup options; no one should be + // calling this method. + Err(ControlPlaneAgentError::OperationUnsupported.into()) + } + + pub(crate) fn set_startup_options_impl( + &mut self, + _startup_options: HostStartupOptions, + ) -> Result<(), RequestError> { + // We don't have a host to give startup options; no one should be + // calling this method. + Err(ControlPlaneAgentError::OperationUnsupported.into()) + } + + fn power_state_impl(&self) -> Result { + // Minibar has no configurable power states. + Ok(PowerState::A2) + } +} + +impl SpHandler for MgsHandler { + type BulkIgnitionStateIter = ignition_controller::BulkIgnitionStateIter; + type BulkIgnitionLinkEventsIter = + ignition_controller::BulkIgnitionLinkEventsIter; + type VLanId = VLanId; + + fn ensure_request_trusted( + &mut self, + kind: MgsRequest, + _sender: Sender, + ) -> Result { + // Minibar trusts all requests. + Ok(kind) + } + + fn ensure_response_trusted( + &mut self, + kind: MgsResponse, + _sender: Sender, + ) -> Option { + // Minibar trusts all responses. + Some(kind) + } + + fn discover( + &mut self, + sender: Sender, + ) -> Result { + self.common.discover(sender.vid) + } + + fn num_ignition_ports(&mut self) -> Result { + self.ignition.num_ports() + } + + fn ignition_state(&mut self, target: u8) -> Result { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::IgnitionState { + target + })); + self.ignition.target_state(target) + } + + fn bulk_ignition_state( + &mut self, + offset: u32, + ) -> Result { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::BulkIgnitionState { + offset + })); + self.ignition.bulk_state(offset) + } + + fn ignition_link_events( + &mut self, + target: u8, + ) -> Result { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::IgnitionLinkEvents { + target + })); + self.ignition.target_link_events(target) + } + + fn bulk_ignition_link_events( + &mut self, + offset: u32, + ) -> Result { + ringbuf_entry_root!(Log::MgsMessage( + MgsMessage::BulkIgnitionLinkEvents { offset } + )); + self.ignition.bulk_link_events(offset) + } + + fn clear_ignition_link_events( + &mut self, + target: Option, + transceiver_select: Option, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage( + MgsMessage::ClearIgnitionLinkEvents + )); + self.ignition.clear_link_events(target, transceiver_select) + } + + fn ignition_command( + &mut self, + target: u8, + command: IgnitionCommand, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::IgnitionCommand { + target, + command + })); + self.ignition.command(target, command) + } + + fn sp_state(&mut self) -> Result { + let power_state = self.power_state_impl()?; + self.common.sp_state(power_state) + } + + fn sp_update_prepare( + &mut self, + update: SpUpdatePrepare, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::UpdatePrepare { + length: update.aux_flash_size + update.sp_image_size, + component: SpComponent::SP_ITSELF, + id: update.id, + slot: 0, + })); + + self.common.sp_update.prepare(&UPDATE_MEMORY, update) + } + + fn component_update_prepare( + &mut self, + update: ComponentUpdatePrepare, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::UpdatePrepare { + length: update.total_size, + component: update.component, + id: update.id, + slot: update.slot, + })); + + match update.component { + SpComponent::ROT | SpComponent::STAGE0 => { + self.common.rot_update.prepare(&UPDATE_MEMORY, update) + } + _ => Err(SpError::RequestUnsupportedForComponent), + } + } + + fn component_action( + &mut self, + _sender: Sender, + _component: SpComponent, + _action: ComponentAction, + ) -> Result { + // Minibar doesn't support component actions yet. + Err(SpError::RequestUnsupportedForComponent) + } + + fn update_status( + &mut self, + component: SpComponent, + ) -> Result { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::UpdateStatus { + component + })); + + match component { + SpComponent::SP_ITSELF => Ok(self.common.sp_update.status()), + SpComponent::ROT | SpComponent::STAGE0 => { + Ok(self.common.rot_update.status()) + } + _ => Err(SpError::RequestUnsupportedForComponent), + } + } + + fn update_chunk( + &mut self, + chunk: UpdateChunk, + data: &[u8], + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::UpdateChunk { + component: chunk.component, + offset: chunk.offset, + })); + + match chunk.component { + SpComponent::SP_ITSELF | SpComponent::SP_AUX_FLASH => self + .common + .sp_update + .ingest_chunk(&chunk.component, &chunk.id, chunk.offset, data), + SpComponent::ROT | SpComponent::STAGE0 => self + .common + .rot_update + .ingest_chunk(&(), &chunk.id, chunk.offset, data), + _ => Err(SpError::RequestUnsupportedForComponent), + } + } + + fn update_abort( + &mut self, + component: SpComponent, + id: UpdateId, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::UpdateAbort { + component + })); + + match component { + SpComponent::SP_ITSELF => self.common.sp_update.abort(&id), + SpComponent::ROT | SpComponent::STAGE0 => { + self.common.rot_update.abort(&id) + } + _ => Err(SpError::RequestUnsupportedForComponent), + } + } + + fn power_state(&mut self) -> Result { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::GetPowerState)); + self.power_state_impl() + } + + fn set_power_state( + &mut self, + sender: Sender, + power_state: PowerState, + ) -> Result { + ringbuf_entry_root!( + CRITICAL, + CriticalEvent::SetPowerState { + sender, + power_state, + ticks_since_boot: sys_get_timer().now, + } + ); + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::SetPowerState( + power_state + ))); + + // Minibar has no configurable power states. + Err(SpError::RequestUnsupportedForSp) + } + + fn serial_console_attach( + &mut self, + _sender: Sender, + _component: SpComponent, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::SerialConsoleAttach)); + Err(SpError::RequestUnsupportedForSp) + } + + fn serial_console_write( + &mut self, + _sender: Sender, + offset: u64, + data: &[u8], + ) -> Result { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::SerialConsoleWrite { + offset, + length: data.len() as u16 + })); + Err(SpError::RequestUnsupportedForSp) + } + + fn serial_console_keepalive( + &mut self, + _sender: Sender, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage( + MgsMessage::SerialConsoleKeepAlive + )); + Err(SpError::RequestUnsupportedForSp) + } + + fn serial_console_detach( + &mut self, + _sender: Sender, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::SerialConsoleDetach)); + Err(SpError::RequestUnsupportedForSp) + } + + fn serial_console_break( + &mut self, + _sender: Sender, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::SerialConsoleBreak)); + Err(SpError::RequestUnsupportedForSp) + } + + fn num_devices(&mut self) -> u32 { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::Inventory)); + self.common.inventory().num_devices() as u32 + } + + fn device_description( + &mut self, + index: BoundsChecked, + ) -> DeviceDescription<'static> { + self.common.inventory().device_description(index) + } + + fn num_component_details( + &mut self, + component: SpComponent, + ) -> Result { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::ComponentDetails { + component + })); + + self.common.inventory().num_component_details(&component) + } + + fn component_details( + &mut self, + component: SpComponent, + index: BoundsChecked, + ) -> ComponentDetails { + self.common + .inventory() + .component_details(&component, index, |_, _| { + // This should never be called, because num_component_details + // never returns > 0 for devices in the OUR_DEVICES array + panic!("no custom devices") + }) + } + + fn component_get_active_slot( + &mut self, + component: SpComponent, + ) -> Result { + ringbuf_entry_root!(Log::MgsMessage( + MgsMessage::ComponentGetActiveSlot { component } + )); + + self.common.component_get_active_slot(component) + } + + fn component_set_active_slot( + &mut self, + component: SpComponent, + slot: u16, + persist: bool, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage( + MgsMessage::ComponentSetActiveSlot { + component, + slot, + persist, + } + )); + + self.common + .component_set_active_slot(component, slot, persist) + } + + fn component_get_persistent_slot( + &mut self, + component: SpComponent, + ) -> Result { + ringbuf_entry_root!(Log::MgsMessage( + MgsMessage::ComponentGetPersistentSlot { component } + )); + + self.common.component_get_persistent_slot(component) + } + + fn component_clear_status( + &mut self, + component: SpComponent, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage( + MgsMessage::ComponentClearStatus { component } + )); + Err(SpError::RequestUnsupportedForComponent) + } + + fn get_startup_options( + &mut self, + ) -> Result { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::GetStartupOptions)); + Err(SpError::RequestUnsupportedForSp) + } + + fn set_startup_options( + &mut self, + options: gateway_messages::StartupOptions, + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::SetStartupOptions( + options + ))); + Err(SpError::RequestUnsupportedForSp) + } + + fn mgs_response_error(&mut self, message_id: u32, err: MgsError) { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::MgsError { + message_id, + err + })); + } + + fn mgs_response_host_phase2_data( + &mut self, + _sender: Sender, + _message_id: u32, + hash: [u8; 32], + offset: u64, + data: &[u8], + ) { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::HostPhase2Data { + hash, + offset, + data_len: data.len(), + })); + } + + fn send_host_nmi(&mut self) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::SendHostNmi)); + Err(SpError::RequestUnsupportedForSp) + } + + fn set_ipcc_key_lookup_value( + &mut self, + key: u8, + value: &[u8], + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::SetIpccKeyValue { + key, + value_len: value.len(), + })); + Err(SpError::RequestUnsupportedForSp) + } + + fn get_component_caboose_value( + &mut self, + component: SpComponent, + slot: u16, + key: [u8; 4], + buf: &mut [u8], + ) -> Result { + self.common + .get_component_caboose_value(component, slot, key, buf) + } + + fn reset_component_prepare( + &mut self, + component: SpComponent, + ) -> Result<(), SpError> { + self.common.reset_component_prepare(component) + } + + fn reset_component_trigger( + &mut self, + component: SpComponent, + ) -> Result<(), SpError> { + self.common.reset_component_trigger(component) + } + + fn read_sensor( + &mut self, + req: SensorRequest, + ) -> Result { + self.common.read_sensor(req) + } + + fn current_time(&mut self) -> Result { + self.common.current_time() + } + + fn read_rot( + &mut self, + req: RotRequest, + buf: &mut [u8], + ) -> Result { + self.common.read_rot_page(req, buf) + } + + fn vpd_lock_status_all( + &mut self, + buf: &mut [u8], + ) -> Result { + self.common.vpd_lock_status_all(buf) + } + + fn reset_component_trigger_with_watchdog( + &mut self, + component: SpComponent, + time_ms: u32, + ) -> Result<(), SpError> { + self.common + .reset_component_trigger_with_watchdog(component, time_ms) + } + + fn disable_component_watchdog( + &mut self, + component: SpComponent, + ) -> Result<(), SpError> { + self.common.disable_component_watchdog(component) + } + + fn component_watchdog_supported( + &mut self, + component: SpComponent, + ) -> Result<(), SpError> { + self.common.component_watchdog_supported(component) + } + + fn versioned_rot_boot_info( + &mut self, + version: u8, + ) -> Result { + self.common.versioned_rot_boot_info(version) + } + + fn get_task_dump_count(&mut self) -> Result { + self.common.get_task_dump_count() + } + + fn task_dump_read_start( + &mut self, + index: u32, + key: [u8; 16], + ) -> Result { + self.common.task_dump_read_start(index, key) + } + + fn task_dump_read_continue( + &mut self, + key: [u8; 16], + seq: u32, + buf: &mut [u8], + ) -> Result, SpError> { + self.common.task_dump_read_continue(key, seq, buf) + } + + fn read_host_flash( + &mut self, + _slot: u16, + _addr: u32, + _buf: &mut [u8], + ) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::ReadHostFlash { + addr: 0 + })); + + Err(SpError::RequestUnsupportedForSp) + } + + fn start_host_flash_hash(&mut self, _slot: u16) -> Result<(), SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::StartHostFlashHash { + slot: 0 + })); + Err(SpError::RequestUnsupportedForSp) + } + + fn get_host_flash_hash(&mut self, _slot: u16) -> Result<[u8; 32], SpError> { + ringbuf_entry_root!(Log::MgsMessage(MgsMessage::GetHostFlashHash { + slot: 0 + })); + Err(SpError::RequestUnsupportedForSp) + } +} diff --git a/task/control-plane-agent/src/mgs_sidecar.rs b/task/control-plane-agent/src/mgs_sidecar.rs index 35cb8d82f..7e6660c12 100644 --- a/task/control-plane-agent/src/mgs_sidecar.rs +++ b/task/control-plane-agent/src/mgs_sidecar.rs @@ -3,10 +3,13 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use crate::{ - mgs_common::MgsCommon, update::rot::RotUpdate, update::sp::SpUpdate, - update::ComponentUpdater, usize_max, CriticalEvent, Log, MgsMessage, + ignition_controller::{self, IgnitionController}, + mgs_common::MgsCommon, + update::rot::RotUpdate, + update::sp::SpUpdate, + update::ComponentUpdater, + usize_max, CriticalEvent, Log, MgsMessage, }; -use drv_ignition_api::IgnitionError; use drv_monorail_api::{Monorail, MonorailError}; use drv_sidecar_seq_api::Sequencer; use drv_transceivers_api::Transceivers; @@ -35,13 +38,9 @@ use zerocopy::IntoBytes; // We're included under a special `path` cfg from main.rs, which confuses rustc // about where our submodules live. Pass explicit paths to correct it. -#[path = "mgs_sidecar/ignition.rs"] -mod ignition_handler; #[path = "mgs_sidecar/monorail_port_status.rs"] mod monorail_port_status; -use ignition_handler::IgnitionController; - userlib::task_slot!(SIDECAR_SEQ, sequencer); userlib::task_slot!(MONORAIL, monorail); userlib::task_slot!(TRANSCEIVERS, transceivers); @@ -466,9 +465,9 @@ fn verify_signature( } impl SpHandler for MgsHandler { - type BulkIgnitionStateIter = ignition_handler::BulkIgnitionStateIter; + type BulkIgnitionStateIter = ignition_controller::BulkIgnitionStateIter; type BulkIgnitionLinkEventsIter = - ignition_handler::BulkIgnitionLinkEventsIter; + ignition_controller::BulkIgnitionLinkEventsIter; type VLanId = VLanId; /// Checks whether we trust the given message @@ -528,18 +527,14 @@ impl SpHandler for MgsHandler { } fn num_ignition_ports(&mut self) -> Result { - self.ignition - .num_ports() - .map_err(sp_error_from_ignition_error) + self.ignition.num_ports() } fn ignition_state(&mut self, target: u8) -> Result { ringbuf_entry_root!(Log::MgsMessage(MgsMessage::IgnitionState { target })); - self.ignition - .target_state(target) - .map_err(sp_error_from_ignition_error) + self.ignition.target_state(target) } fn bulk_ignition_state( @@ -549,9 +544,7 @@ impl SpHandler for MgsHandler { ringbuf_entry_root!(Log::MgsMessage(MgsMessage::BulkIgnitionState { offset })); - self.ignition - .bulk_state(offset) - .map_err(sp_error_from_ignition_error) + self.ignition.bulk_state(offset) } fn ignition_link_events( @@ -561,9 +554,7 @@ impl SpHandler for MgsHandler { ringbuf_entry_root!(Log::MgsMessage(MgsMessage::IgnitionLinkEvents { target })); - self.ignition - .target_link_events(target) - .map_err(sp_error_from_ignition_error) + self.ignition.target_link_events(target) } fn bulk_ignition_link_events( @@ -573,9 +564,7 @@ impl SpHandler for MgsHandler { ringbuf_entry_root!(Log::MgsMessage( MgsMessage::BulkIgnitionLinkEvents { offset } )); - self.ignition - .bulk_link_events(offset) - .map_err(sp_error_from_ignition_error) + self.ignition.bulk_link_events(offset) } fn clear_ignition_link_events( @@ -586,9 +575,7 @@ impl SpHandler for MgsHandler { ringbuf_entry_root!(Log::MgsMessage( MgsMessage::ClearIgnitionLinkEvents )); - self.ignition - .clear_link_events(target, transceiver_select) - .map_err(sp_error_from_ignition_error) + self.ignition.clear_link_events(target, transceiver_select) } fn ignition_command( @@ -600,9 +587,7 @@ impl SpHandler for MgsHandler { target, command })); - self.ignition - .command(target, command) - .map_err(sp_error_from_ignition_error) + self.ignition.command(target, command) } fn sp_state(&mut self) -> Result { @@ -1242,22 +1227,6 @@ impl SpHandler for MgsHandler { } } -// Helper function for `.map_err()`; we can't use `?` because we can't implement -// `From<_>` between these types due to orphan rules. -fn sp_error_from_ignition_error(err: IgnitionError) -> SpError { - use gateway_messages::ignition::IgnitionError as E; - let err = match err { - IgnitionError::FpgaError => E::FpgaError, - IgnitionError::InvalidPort => E::InvalidPort, - IgnitionError::InvalidValue => E::InvalidValue, - IgnitionError::NoTargetPresent => E::NoTargetPresent, - IgnitionError::RequestInProgress => E::RequestInProgress, - IgnitionError::RequestDiscarded => E::RequestDiscarded, - _ => E::Other(err as u32), - }; - SpError::Ignition(err) -} - fn get_ecdsa_challenge() -> Result { // Get a nonce from our RNG driver let rng = drv_rng_api::Rng::from(RNG.get_task_id());