Skip to content

Commit

Permalink
Allow SP to set active slot
Browse files Browse the repository at this point in the history
It's useful for the SP to be able to change the active slot.
Pull this through. The final finish step no longer implicitly
swaps the bank.
  • Loading branch information
labbott committed Jun 6, 2024
1 parent 0aa6370 commit 2f3f789
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 12 deletions.
35 changes: 34 additions & 1 deletion drv/stm32h7-update-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
#![no_std]

use drv_caboose::CabooseError;
use userlib::sys_send;
use hubpack::SerializedSize;
use serde::{Deserialize, Serialize};
use userlib::{sys_send, FromPrimitive};

pub use stage0_handoff::ImageVersion;

Expand All @@ -26,4 +28,35 @@ pub const BLOCK_SIZE_BYTES: usize = FLASH_WORD_BYTES * FLASH_WORDS_PER_BLOCK;

pub const BLOCK_SIZE_WORDS: usize = BLOCK_SIZE_BYTES / 4;

#[derive(
Clone,
Copy,
Eq,
PartialEq,
FromPrimitive,
Serialize,
Deserialize,
SerializedSize,
)]
pub enum SlotId {
Active = 0,
Inactive = 1,
}

impl TryFrom<u16> for SlotId {
type Error = ();
fn try_from(i: u16) -> Result<Self, Self::Error> {
Self::from_u16(i).ok_or(())
}
}

impl From<SlotId> for u16 {
fn from(id: SlotId) -> u16 {
match id {
SlotId::Active => 0,
SlotId::Inactive => 1,
}
}
}

include!(concat!(env!("OUT_DIR"), "/client_stub.rs"));
45 changes: 42 additions & 3 deletions drv/stm32h7-update-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
use core::convert::Infallible;
use drv_caboose::{CabooseError, CabooseReader};
use drv_stm32h7_update_api::{
ImageVersion, BLOCK_SIZE_BYTES, FLASH_WORDS_PER_BLOCK, FLASH_WORD_BYTES,
ImageVersion, SlotId, BLOCK_SIZE_BYTES, FLASH_WORDS_PER_BLOCK,
FLASH_WORD_BYTES,
};
use drv_update_api::UpdateError;
use idol_runtime::{
Expand Down Expand Up @@ -67,12 +68,14 @@ ringbuf!(Trace, 64, Trace::None);
struct ServerImpl<'a> {
flash: &'a device::flash::RegisterBlock,
state: UpdateState,
pending: SlotId,
}

impl<'a> ServerImpl<'a> {
// See RM0433 Rev 7 section 4.3.13
fn swap_banks(&mut self) -> Result<(), RequestError<UpdateError>> {
ringbuf_entry!(Trace::FinishStart);
self.unlock();
if self.flash.optsr_cur().read().swap_bank_opt().bit() {
self.flash
.optsr_prg()
Expand All @@ -91,6 +94,10 @@ impl<'a> ServerImpl<'a> {
}
}

self.pending = match self.pending {
SlotId::Active => SlotId::Inactive,
SlotId::Inactive => SlotId::Active,
};
ringbuf_entry!(Trace::FinishEnd);
Ok(())
}
Expand Down Expand Up @@ -279,6 +286,24 @@ impl<'a> ServerImpl<'a> {
}

impl idl::InOrderUpdateImpl for ServerImpl<'_> {
fn set_pending_boot_slot(
&mut self,
_: &RecvMessage,
slot: SlotId,
) -> Result<(), RequestError<UpdateError>> {
if slot != self.pending {
self.swap_banks()?;
}
Ok(())
}

fn get_pending_boot_slot(
&mut self,
_: &RecvMessage,
) -> Result<SlotId, RequestError<Infallible>> {
Ok(self.pending)
}

fn prep_image_update(
&mut self,
_: &RecvMessage,
Expand Down Expand Up @@ -380,7 +405,6 @@ impl idl::InOrderUpdateImpl for ServerImpl<'_> {
UpdateState::InProgress => (),
}

self.swap_banks()?;
self.state = UpdateState::Finished;
Ok(())
}
Expand Down Expand Up @@ -519,9 +543,24 @@ impl NotificationHandler for ServerImpl<'_> {
fn main() -> ! {
let flash = unsafe { &*device::FLASH::ptr() };

// If the server restarts we need to fix our pending state
// `FLASH_OPTCR` always has our current bank swap bit while
// `FLASH_OPTSR_CUR` has the result after we have programmed.
// If they are the same this means we will be booking into the
// active slot. If they differ, we will be booting into the
// alternate slot.
let pending = if flash.optsr_cur().read().swap_bank_opt().bit()
== flash.optcr().read().swap_bank().bit()
{
SlotId::Active
} else {
SlotId::Inactive
};

let mut server = ServerImpl {
flash,
state: UpdateState::NoUpdate,
pending,
};
let mut incoming = [0u8; idl::INCOMING_SIZE];

Expand All @@ -532,7 +571,7 @@ fn main() -> ! {

include!(concat!(env!("OUT_DIR"), "/consts.rs"));
mod idl {
use super::{CabooseError, ImageVersion};
use super::{CabooseError, ImageVersion, SlotId};

include!(concat!(env!("OUT_DIR"), "/server_stub.rs"));
}
Expand Down
19 changes: 19 additions & 0 deletions idl/stm32h7-update.idol
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,24 @@ Interface(
),
idempotent: true,
),
"get_pending_boot_slot": (
doc: "Get the boot setting that will be applied on the next reboot",
args: {},
reply: Simple("SlotId"),
idempotent: true,
encoding: Hubpack
),
"set_pending_boot_slot": (
doc: "Set the boot setting that will be applied on the next reboot",
args: {
"slot": "SlotId",
},
reply: Result (
ok: "()",
err: CLike("drv_update_api::UpdateError"),
),
encoding: Hubpack
),

},
)
24 changes: 18 additions & 6 deletions task/control-plane-agent/src/mgs_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ impl MgsCommon {
match component {
SpComponent::SP_ITSELF => match slot {
0 => {
// Active running slot
let reader = drv_caboose_pos::CABOOSE_POS
.as_slice()
.map(CabooseReader::new)
Expand All @@ -193,6 +194,7 @@ impl MgsCommon {
}
}
1 => {
// Inactive slot
let len = self
.update_sp
.read_caboose_value(key, buf)
Expand Down Expand Up @@ -336,6 +338,9 @@ impl MgsCommon {
component: SpComponent,
) -> Result<u16, GwSpError> {
match component {
SpComponent::SP_ITSELF => {
Ok(self.update_sp.get_pending_boot_slot().into())
}
SpComponent::ROT => {
let slot = match self.sprot.rot_boot_info()?.active {
SpSlotId::A => 0,
Expand Down Expand Up @@ -386,12 +391,19 @@ impl MgsCommon {
Ok(())
}

// SpComponent::SP_ITSELF:
// update_server for SP needs to decouple finish_update()
// from swap_banks() for SwitchDuration::Forever to make sense.
// There isn't currently a mechanism implemented for SP that
// enables SwitchDuration::Once.
//
SpComponent::SP_ITSELF => {
let slot = slot
.try_into()
.map_err(|()| GwSpError::RequestUnsupportedForComponent)?;
if !persist {
// We have no mechanism to temporarily swap the banks on the SP
return Err(GwSpError::RequestUnsupportedForComponent);
};
self.update_sp
.set_pending_boot_slot(slot)
.map_err(|err| GwSpError::UpdateFailed(err as u32))?;
Ok(())
}
// Other components might also be served someday.
_ => Err(GwSpError::RequestUnsupportedForComponent),
}
Expand Down
14 changes: 12 additions & 2 deletions task/control-plane-agent/src/update/sp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ use crate::update::ComponentUpdater;
use cfg_if::cfg_if;
use core::ops::{Deref, DerefMut};
use drv_caboose::CabooseReader;
use drv_stm32h7_update_api::{Update, BLOCK_SIZE_BYTES};
use drv_stm32h7_update_api::{SlotId, Update, BLOCK_SIZE_BYTES};
use drv_update_api::UpdateError;
use gateway_messages::{
ImageVersion, SpComponent, SpError, SpUpdatePrepare, UpdateId,
Expand Down Expand Up @@ -536,7 +536,17 @@ impl AcceptingData {
if let Ok(n) = sp_task.read_caboose_value(BOARD_KEY, &mut other) {
if ours.map(|b| b == &other[..n as usize]).unwrap_or(true) {
match sp_task.finish_image_update() {
Ok(()) => (State::Complete, Ok(())),
Ok(()) => {
match sp_task
.set_pending_boot_slot(SlotId::Inactive)
{
Ok(()) => (State::Complete, Ok(())),
Err(err) => (
State::Failed(err),
Err(SpError::UpdateFailed(err as u32)),
),
}
}
Err(err) => (
State::Failed(err),
Err(SpError::UpdateFailed(err as u32)),
Expand Down

0 comments on commit 2f3f789

Please sign in to comment.