@@ -498,48 +498,53 @@ impl idl::InOrderUpdateImpl for ServerImpl<'_> {
498498 UpdateState :: Finished | UpdateState :: NoUpdate => ( ) ,
499499 }
500500
501- let image = match ( component, slot) {
501+ self . image = match ( component, slot) {
502502 ( RotComponent :: Hubris , SlotId :: A )
503503 | ( RotComponent :: Hubris , SlotId :: B ) => {
504- let active = match bootstate ( )
505- . map_err ( |_| UpdateError :: MissingHandoffData ) ?
506- . active
507- {
508- stage0_handoff:: RotSlot :: A => SlotId :: A ,
509- stage0_handoff:: RotSlot :: B => SlotId :: B ,
510- } ;
511- if active == slot {
504+ // Fail early on attempt to update the running image.
505+ if same_image ( component, slot) {
512506 return Err ( UpdateError :: InvalidSlotIdForOperation . into ( ) ) ;
513507 }
508+
514509 // Rollback protection will be implemented by refusing to set
515- // boot preference to an image that has a lower EPOC vale in the
516- // caboose.
517- //
510+ // boot preference to an image that has a lower EPOC value in
511+ // its caboose.
518512 // Setting the boot preference before updating would sidestep that
519513 // protection. So, we will fail the prepare step if any
520514 // preference settings are selecting the update target image.
515+ //
516+ // After the update, the boot image selection will be based on:
517+ // - there being only one properly signed image, or
518+ // - transient boot selection (highest priority), or
519+ // - pending persistent selection (altering the persistent
520+ // selection)
521+ // - persistent preference if neither of the above was used.
522+
521523 let ( persistent, pending_persistent, transient) =
522524 self . boot_preferences ( ) ?;
525+
526+ // The transient preference must not select the update target.
523527 if let Some ( pref) = transient {
524- if active ! = pref {
528+ if slot = = pref {
525529 return Err ( UpdateError :: InvalidPreferredSlotId . into ( ) ) ;
526530 }
527531 }
532+ // If there is a pending persistent preference, it must
533+ // not select the update target.
528534 if let Some ( pref) = pending_persistent {
529- if active ! = pref {
535+ if slot = = pref {
530536 return Err ( UpdateError :: InvalidPreferredSlotId . into ( ) ) ;
531537 }
532- }
533- if active != persistent {
538+ } else if slot == persistent {
539+ // If there is no pending persistent preference, then the
540+ // persistent preference must select the currently active image.
534541 return Err ( UpdateError :: InvalidPreferredSlotId . into ( ) ) ;
535542 }
536543 Some ( ( component, slot) )
537544 }
538545 ( RotComponent :: Stage0 , SlotId :: B ) => Some ( ( component, slot) ) ,
539546 _ => return Err ( UpdateError :: InvalidSlotIdForOperation . into ( ) ) ,
540547 } ;
541-
542- self . image = image;
543548 self . state = UpdateState :: InProgress ;
544549 ringbuf_entry ! ( Trace :: State ( self . state) ) ;
545550 self . next_block = None ;
@@ -1430,16 +1435,15 @@ fn get_transient_override() -> [u8; 32] {
14301435}
14311436
14321437// Preference constants are taken from bootleby:src/lib.rs
1438+ // Note that Bootleby uses this same array to communicate the boot decision log to Hubris.
14331439const PREFER_SLOT_A : [ u8 ; 32 ] =
14341440 hex ! ( "edb23f2e9b399c3d57695262f29615910ed10c8d9b261bfc2076b8c16c84f66d" ) ;
14351441const PREFER_SLOT_B : [ u8 ; 32 ] =
14361442 hex ! ( "70ed2914e6fdeeebbb02763b96da9faa0160b7fc887425f4d45547071d0ce4ba" ) ;
1437- // Bootleby writes all zeros after reading. We write all ones to reset.
14381443const PREFER_NOTHING : [ u8 ; 32 ] = [ 0xffu8 ; 32 ] ;
14391444
14401445pub fn set_hubris_transient_override ( bank : Option < SlotId > ) {
14411446 match bank {
1442- // Do we need a value that says we were here and cleared?
14431447 None => set_transient_override ( PREFER_NOTHING ) ,
14441448 Some ( SlotId :: A ) => set_transient_override ( PREFER_SLOT_A ) ,
14451449 Some ( SlotId :: B ) => set_transient_override ( PREFER_SLOT_B ) ,
0 commit comments