1 // Copyright (c) 2019-2021 Linaro LTD 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 //! Support and tests related to the dependency management for multi-image 6 //! support. 7 8 use crate::image::ImageVersion; 9 10 pub trait Depender { 11 /// Generate a version for this particular image. The slot indicates 12 /// which slot this is being put in. my_version(&self, offset: usize, slot: usize) -> ImageVersion13 fn my_version(&self, offset: usize, slot: usize) -> ImageVersion; 14 15 /// Return dependencies for this image/slot combination. my_deps(&self, offset: usize, slot: usize) -> Vec<ImageVersion>16 fn my_deps(&self, offset: usize, slot: usize) -> Vec<ImageVersion>; 17 18 /// Return the image ID of the other version. other_id(&self) -> u819 fn other_id(&self) -> u8; 20 } 21 22 /// A boring image is used when we aren't testing dependencies. There will 23 /// be meaningful version numbers. The size field is the image number we 24 /// are. 25 pub struct BoringDep { 26 number: usize, 27 test: DepTest, 28 } 29 30 impl BoringDep { new(number: usize, test: &DepTest) -> BoringDep31 pub fn new(number: usize, test: &DepTest) -> BoringDep { 32 BoringDep { 33 number, 34 test: test.clone(), 35 } 36 } 37 } 38 39 impl Depender for BoringDep { my_version(&self, _offset: usize, slot: usize) -> ImageVersion40 fn my_version(&self, _offset: usize, slot: usize) -> ImageVersion { 41 let slot = if self.test.downgrade { 42 1 - slot 43 } else { 44 slot 45 }; 46 ImageVersion::new_synthetic(self.number as u8, slot as u8, 0) 47 } 48 my_deps(&self, _offset: usize, _slot: usize) -> Vec<ImageVersion>49 fn my_deps(&self, _offset: usize, _slot: usize) -> Vec<ImageVersion> { 50 vec![] 51 } 52 other_id(&self) -> u853 fn other_id(&self) -> u8 { 54 0 55 } 56 } 57 58 /// An individual test of the dependency mechanism describes one of the 59 /// possibilities for the dependency information for each image, and what 60 /// the expected outcome is. 61 #[derive(Clone, Debug)] 62 pub struct DepTest { 63 /// What kinds of dependency should be installed in the image. 64 pub depends: [DepType; 2], 65 66 /// What is the expected outcome of the upgrade. 67 pub upgrades: [UpgradeInfo; 2], 68 69 /// Should this be considered a downgrade (cause the version number to 70 /// decrease). 71 pub downgrade: bool, 72 } 73 74 /// Describes the various types of dependency information that can be 75 /// provided. 76 #[derive(Clone, Debug)] 77 pub enum DepType { 78 /// Do not include dependency information 79 Nothing, 80 /// Provide dependency information that matches the other image. 81 Correct, 82 /// Provide a dependency that matches the old version of the other 83 /// image. 84 OldCorrect, 85 /// Provide dependency information describing something newer than the 86 /// other image. 87 Newer, 88 /// Don't provide an upgrade image at all for this image 89 NoUpgrade, 90 } 91 92 /// Describes what our expectation is for an upgrade. 93 #[derive(Clone, Debug, PartialEq, Eq)] 94 pub enum UpgradeInfo { 95 /// The current version should be held. 96 Held, 97 /// The image should be upgraded 98 Upgraded, 99 } 100 101 /// A "test" that gives no dependency information. 102 pub static NO_DEPS: DepTest = DepTest { 103 depends: [DepType::Nothing, DepType::Nothing], 104 upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Upgraded], 105 downgrade: false, 106 }; 107 108 /// A "test" with no dependency information, and the images marked as a 109 /// downgrade. 110 pub static REV_DEPS: DepTest = DepTest { 111 depends: [DepType::Nothing, DepType::Nothing], 112 upgrades: [UpgradeInfo::Held, UpgradeInfo::Held], 113 downgrade: true, 114 }; 115 116 /// A PairDep describes the dependencies between two pairs. 117 pub struct PairDep { 118 /// The image number of this image. 119 number: usize, 120 121 test: DepTest, 122 } 123 124 impl PairDep { new(total_image: usize, my_image: usize, deps: &DepTest) -> PairDep125 pub fn new(total_image: usize, my_image: usize, deps: &DepTest) -> PairDep { 126 if total_image != 2 { 127 panic!("PairDep only works when there are two images"); 128 } 129 130 PairDep { 131 number: my_image, 132 test: deps.clone(), 133 } 134 } 135 } 136 137 impl Depender for PairDep { my_version(&self, _offset: usize, slot: usize) -> ImageVersion138 fn my_version(&self, _offset: usize, slot: usize) -> ImageVersion { 139 let slot = if self.test.downgrade { 140 1 - slot 141 } else { 142 slot 143 }; 144 ImageVersion::new_synthetic(self.number as u8, slot as u8, 0) 145 } 146 my_deps(&self, _offset: usize, slot: usize) -> Vec<ImageVersion>147 fn my_deps(&self, _offset: usize, slot: usize) -> Vec<ImageVersion> { 148 // For now, don't put any dependencies in slot zero. They could be 149 // added here if we someday implement checking these. 150 if slot == 0 { 151 vec![] 152 } else { 153 match self.test.depends[self.number] { 154 DepType::Nothing => vec![], 155 DepType::NoUpgrade => panic!("Shouldn't get to this point"), 156 DepType::Correct => vec![ 157 ImageVersion::new_synthetic(self.other_id(), slot as u8, 0) 158 ], 159 DepType::OldCorrect => vec![ 160 ImageVersion::new_synthetic(self.other_id(), 0, 0) 161 ], 162 DepType::Newer => vec![ 163 ImageVersion::new_synthetic(self.other_id(), slot as u8, 1) 164 ], 165 } 166 } 167 } 168 other_id(&self) -> u8169 fn other_id(&self) -> u8 { 170 (1 - self.number) as u8 171 } 172 } 173 174 impl ImageVersion { 175 /// Generate an image version based on some key information. The image 176 /// number influences the major version number (by an arbitrary factor), 177 /// and the slot affects the major number on the build_number. The minor 178 /// number can also be given to force numbers to be different. new_synthetic(image_id: u8, slot: u8, minor: u8) -> ImageVersion179 fn new_synthetic(image_id: u8, slot: u8, minor: u8) -> ImageVersion { 180 ImageVersion { 181 major: image_id * 20 + slot, 182 minor, 183 revision: 1, 184 build_num: slot as u32, 185 } 186 } 187 } 188