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