@@ -13,7 +13,6 @@ use drv_sprot_api::{
1313 CabooseOrSprotError ,
1414 Fwid as SpFwid ,
1515 ImageError as SpImageError ,
16- ImageVersion as SpImageVersion ,
1716 RotBootInfo as SpRotBootInfo ,
1817 RotBootInfoV2 as SpRotBootInfoV2 ,
1918 RotComponent as SpRotComponent ,
@@ -612,6 +611,25 @@ impl MgsCommon {
612611 Ok ( ( ) )
613612 }
614613
614+ /// Returns the `GwRotBootInfo` version requested by MGS, or falls back to
615+ /// the highest supported version that does not exceed the request.
616+ ///
617+ /// This "best-effort" behavior simplifies the client's logic. Later
618+ /// response versions are improvements and the control plane benefits from
619+ /// the most complete information for update planning. We provide the best
620+ /// available data directly rather than forcing the client to handle errors
621+ /// and search for a supported version. Callers that require strict
622+ /// versioning can treat version mismatches as an error.
623+ ///
624+ /// The supported versions are constrained by this SP and the RoT firmware.
625+ /// Some version skew between the control plane (MGS), SP, and RoT is
626+ /// expected.
627+ /// Temporary version skew is **unavoidable** during normal system updates
628+ /// but can also result from update failures or they can occur during
629+ /// development.
630+ /// The fallback logic is designed to handle these mismatches gracefully.
631+ /// Introducing a new `GwRotBootInfo` variant requires care, as an
632+ /// unhandled mismatch can break the update process.
615633 pub ( crate ) fn versioned_rot_boot_info (
616634 & mut self ,
617635 version : u8 ,
@@ -620,17 +638,66 @@ impl MgsCommon {
620638 version
621639 } ) ) ;
622640
623- match self . sprot . versioned_rot_boot_info ( version) ? {
624- SpVersionedRotBootInfo :: V1 ( v1) => {
625- Ok ( GwRotBootInfo :: V1 ( MgsRotState :: from ( v1) . 0 ) )
641+ // For full context on the version mapping, see the RoT's
642+ // `versioned_rot_boot_info` function in `drv/lpc55-update-server`
643+ // and the corresponding MGS data structures.
644+
645+ // Ensure that the version mapping logic below is
646+ // intentionally reviewed whenever a new `GwRotBootInfo` version
647+ // or SpVersionedRotBootInfo variant is added.
648+ // If these assertions fail, both the `match version` mapping and the
649+ // `match self.sprot...` response construction must be updated.
650+
651+ // Force update of this code if new MGS variants are introduced
652+ const _HIGHEST_KNOWN_MGS_VERSION: u8 = 3 ;
653+ static_assertions:: const_assert_eq!(
654+ GwRotBootInfo :: HIGHEST_KNOWN_VERSION ,
655+ _HIGHEST_KNOWN_MGS_VERSION
656+ ) ;
657+
658+ // Force update of this code if new ROT variants are introduced
659+ const HIGHEST_KNOWN_ROT_VERSION : u8 = 2 ;
660+ static_assertions:: const_assert_eq!(
661+ SpVersionedRotBootInfo :: HIGHEST_KNOWN_VERSION ,
662+ HIGHEST_KNOWN_ROT_VERSION
663+ ) ;
664+
665+ // Map the MGS RotBootInfo 1-based versions to RoT 0-based versions.
666+ let rot_version = match version {
667+ // There is no version -1 in the RoT version number scheme.
668+ 0 => return Err ( GwSpError :: RequestUnsupportedForComponent ) ,
669+
670+ // See Issue #2193: To maintain compatibility with older systems,
671+ // we intentionally preserve a legacy bug where MGS V1 was passed
672+ // unaltered to the RoT instead of being mapped to RoT V0.
673+ // 1 => 0, // This is the correct mapping.
674+ 1 => 1 , // This is the bug-compatible mapping
675+
676+ // The remaining mappings are consistent with the design.
677+ 2 => 1 ,
678+ 3 => 2 ,
679+ // Clamp the version to the highest known by the SP.
680+ _ => HIGHEST_KNOWN_ROT_VERSION ,
681+ } ;
682+
683+ match self . sprot . versioned_rot_boot_info ( rot_version) ? {
684+ SpVersionedRotBootInfo :: V1 ( rot_v1) => {
685+ if version == 1 {
686+ // The MGS request is for a deprecated RoT response.
687+ // Maintain bug compatibility until issue #2193 is resolved.
688+ // Construct an MGS V1 from the more recent RoT V1 struct.
689+ Ok ( GwRotBootInfo :: V1 ( MgsRotState :: from ( rot_v1) . 0 ) )
690+ } else {
691+ // The RoT V1 response corresponds to the MGS V2 or is the
692+ // highest that the RoT could provide.
693+ Ok ( GwRotBootInfo :: V2 ( MgsRotStateV2 :: from ( rot_v1) . 0 ) )
694+ }
695+ }
696+ // The RoT V2 response corresponds to the MGS V3 or is the highest
697+ // version the RoT could provide.
698+ SpVersionedRotBootInfo :: V2 ( rot_v2) => {
699+ Ok ( GwRotBootInfo :: V3 ( MgsRotStateV3 :: from ( rot_v2) . 0 ) )
626700 }
627- SpVersionedRotBootInfo :: V2 ( v2) => match version {
628- 2 => Ok ( GwRotBootInfo :: V2 ( MgsRotStateV2 :: from ( v2) . 0 ) ) ,
629- // RoT's V2 is MGS V3 and the highest version that we can offer today.
630- _ => Ok ( GwRotBootInfo :: V3 ( MgsRotStateV3 :: from ( v2) . 0 ) ) ,
631- } ,
632- // New variants that this code doesn't know about yet will
633- // result in a deserialization error.
634701 }
635702 }
636703
@@ -693,6 +760,7 @@ impl From<SpSlotId> for MgsRotSlotId {
693760 }
694761}
695762
763+ // Note: this struct and impl go away when issue #2193 is resolved.
696764struct MgsRotState ( GwRotState ) ;
697765
698766impl From < SpRotBootInfo > for MgsRotState {
@@ -703,21 +771,19 @@ impl From<SpRotBootInfo> for MgsRotState {
703771 active : MgsRotSlotId :: from ( v1. active ) . 0 ,
704772 slot_a : v1. slot_a_sha3_256_digest . map ( |digest| {
705773 GwRotImageDetails {
706- version : MgsImageVersion :: from ( SpImageVersion {
774+ version : GwImageVersion {
707775 version : 0 ,
708776 epoch : 0 ,
709- } )
710- . 0 ,
777+ } ,
711778 digest,
712779 }
713780 } ) ,
714781 slot_b : v1. slot_b_sha3_256_digest . map ( |digest| {
715782 GwRotImageDetails {
716- version : MgsImageVersion :: from ( SpImageVersion {
783+ version : GwImageVersion {
717784 version : 0 ,
718785 epoch : 0 ,
719- } )
720- . 0 ,
786+ } ,
721787 digest,
722788 }
723789 } ) ,
@@ -781,17 +847,6 @@ impl From<SpRotBootInfoV2> for MgsRotStateV2 {
781847 }
782848}
783849
784- struct MgsImageVersion ( GwImageVersion ) ;
785-
786- impl From < SpImageVersion > for MgsImageVersion {
787- fn from ( iv : SpImageVersion ) -> Self {
788- MgsImageVersion ( GwImageVersion {
789- version : iv. version ,
790- epoch : iv. epoch ,
791- } )
792- }
793- }
794-
795850struct MgsRotStateV3 ( GwRotStateV3 ) ;
796851
797852impl From < SpRotBootInfoV2 > for MgsRotStateV3 {
0 commit comments