• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <log/log.h>
18 #include <cutils/properties.h>
19 #include <zlib.h>
20 #include <hardware/boot_control.h>
21 #include <bootloader_message.h>
22 
23 #include <string>
24 
25 #define BOOT_SLOT_PROP "ro.boot.slot_suffix"
26 
27 struct BootControlPrivate {
28   // The base struct needs to be first in the list.
29   boot_control_module_t base;
30 
31   // Whether this struct was initialized with data from the bootloader message
32   // that doesn't change until next reboot.
33   bool initialized;
34 
35   // The path to the misc_device as reported in the fstab.
36   const char* misc_device;
37 
38   // The number of slots present on the device.
39   unsigned int num_slots;
40 
41   // The slot where we are running from.
42   unsigned int current_slot;
43 };
44 
45 constexpr unsigned int kMaxNumSlots =
46   sizeof(bootloader_control::slot_info) /
47   sizeof(bootloader_control::slot_info[0]);
48 
49 constexpr const char* kSlotSuffixes[kMaxNumSlots] = { "_a", "_b", "_c", "_d" };
50 
51 // Return the little-endian representation of the CRC-32 of the first fields
52 // in |boot_ctrl| up to the crc32_le field.
GetBootloaderControlCRC(const bootloader_control * boot_ctrl)53 static uint32_t GetBootloaderControlCRC(const bootloader_control* boot_ctrl) {
54   return crc32(0, (const uint8_t*)boot_ctrl,
55                offsetof(bootloader_control, crc32_le));
56 }
57 
LoadBootloaderControl(const char * misc_device,bootloader_control * boot_ctrl)58 static bool LoadBootloaderControl(const char* misc_device,
59                                   bootloader_control* boot_ctrl) {
60   std::string str_err;
61   if (read_bootloader_control_from(boot_ctrl, misc_device, &str_err))
62     return true;
63 
64   ALOGE("%s", str_err.c_str());
65 
66   return false;
67 }
68 
SaveBootloaderControl(const char * misc_device,bootloader_control * boot_ctrl)69 static bool SaveBootloaderControl(const char* misc_device,
70                                   bootloader_control* boot_ctrl) {
71   boot_ctrl->crc32_le = GetBootloaderControlCRC(boot_ctrl);
72 
73   std::string str_err;
74   if (write_bootloader_control_to(boot_ctrl, misc_device, &str_err))
75     return true;
76 
77   ALOGE("%s", str_err.c_str());
78 
79   return false;
80 }
81 
82 // Return the index of the slot suffix passed or -1 if not a valid slot suffix.
SlotSuffixToIndex(const char * suffix)83 static int SlotSuffixToIndex(const char* suffix) {
84   for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) {
85     if (!strcmp(kSlotSuffixes[slot], suffix)) return slot;
86   }
87 
88   return -1;
89 }
90 
IsInitialized(const BootControlPrivate * module)91 static bool IsInitialized(const BootControlPrivate* module) {
92   if (!module->initialized) {
93     ALOGW("Module not initialized");
94     return false;
95   }
96 
97   return true;
98 }
99 
BootControlInit(boot_control_module_t * module)100 void BootControlInit(boot_control_module_t* module) {
101   struct BootControlPrivate* bootctrl_module =
102     reinterpret_cast<BootControlPrivate*>(module);
103 
104   if (bootctrl_module->initialized) return;
105 
106   if (!module) {
107     ALOGE("Invalid argument passed to %s", __func__);
108     return;
109   }
110 
111   ALOGI("Init %s", module->common.name);
112 
113   // Initialize the current_slot from the read-only property. If the property
114   // was not set (from either the command line or the device tree), we can later
115   // initialize it from the bootloader_control struct.
116   char suffix_prop[PROPERTY_VALUE_MAX] = {0};
117   property_get(BOOT_SLOT_PROP, suffix_prop, "");
118   bootctrl_module->current_slot = SlotSuffixToIndex(suffix_prop);
119 
120   std::string err;
121   std::string device = get_bootloader_message_blk_device(&err);
122 
123   bootloader_control boot_ctrl;
124   if (!LoadBootloaderControl(device.c_str(), &boot_ctrl))
125     ALOGE("Error loading metadata");
126 
127   // Note that since there isn't a module unload function this memory is leaked.
128   bootctrl_module->misc_device = strdup(device.c_str());
129   uint32_t computed_crc32 = GetBootloaderControlCRC(&boot_ctrl);
130   if (boot_ctrl.crc32_le != computed_crc32) {
131     ALOGE("Invalid boot control found, expected CRC-32 0x%04X, "
132           "but found 0x%04X. Should re-initializing A/B metadata.",
133           computed_crc32, boot_ctrl.crc32_le);
134     return;
135   }
136 
137   std::string metadata_suffix = "_" + std::string(boot_ctrl.slot_suffix);
138   if (SlotSuffixToIndex(metadata_suffix.c_str()) !=
139       bootctrl_module->current_slot) {
140     ALOGE("Kernel slot argument and A/B metadata do not match, "
141           "%s=%s, slot metadata=%s", BOOT_SLOT_PROP, suffix_prop,
142           boot_ctrl.slot_suffix);
143     return;
144   }
145 
146   bootctrl_module->initialized = true;
147   bootctrl_module->num_slots = boot_ctrl.nb_slot;
148 
149   ALOGI("Current slot: %s(%d), number of slots: %d", boot_ctrl.slot_suffix,
150         bootctrl_module->current_slot, bootctrl_module->num_slots);
151 
152   return;
153 }
154 
GetNumberSlots(boot_control_module_t * module)155 unsigned int GetNumberSlots(boot_control_module_t* module) {
156   BootControlPrivate* const bootctrl_module =
157     reinterpret_cast<BootControlPrivate*>(module);
158 
159   if (!IsInitialized(bootctrl_module)) return -1;
160 
161   return bootctrl_module->num_slots;
162 }
163 
GetCurrentSlot(boot_control_module_t * module)164 unsigned int GetCurrentSlot(boot_control_module_t* module) {
165   BootControlPrivate* const bootctrl_module =
166     reinterpret_cast<BootControlPrivate*>(module);
167 
168   if (!IsInitialized(bootctrl_module)) return -1;
169 
170   return bootctrl_module->current_slot;
171 }
172 
IsSlotMarkedSuccessful(boot_control_module_t * module,unsigned int slot)173 int IsSlotMarkedSuccessful(boot_control_module_t* module, unsigned int slot) {
174   BootControlPrivate* const bootctrl_module =
175     reinterpret_cast<BootControlPrivate*>(module);
176 
177   if (!IsInitialized(bootctrl_module)) return -1;
178 
179   if (slot >= kMaxNumSlots || slot >= bootctrl_module->num_slots) {
180     // Invalid slot number.
181     return -1;
182   }
183 
184   bootloader_control bootctrl;
185   if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl))
186     return -1;
187 
188   return (bootctrl.slot_info[slot].successful_boot &&
189           bootctrl.slot_info[slot].tries_remaining);
190 }
191 
MarkBootSuccessful(boot_control_module_t * module)192 int MarkBootSuccessful(boot_control_module_t* module) {
193   BootControlPrivate* const bootctrl_module =
194     reinterpret_cast<BootControlPrivate*>(module);
195 
196   if (!IsInitialized(bootctrl_module)) return -1;
197 
198   bootloader_control bootctrl;
199   if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl))
200     return -1;
201 
202   bootctrl.slot_info[bootctrl_module->current_slot].successful_boot = 1;
203   // tries_remaining == 0 means that the slot is not bootable anymore, make
204   // sure we mark the current slot as bootable if it succeeds in the last
205   // attempt.
206   bootctrl.slot_info[bootctrl_module->current_slot].tries_remaining = 1;
207   if (!SaveBootloaderControl(bootctrl_module->misc_device, &bootctrl))
208     return -1;
209 
210   ALOGI("Slot %d is marked as successfully booted",
211         bootctrl_module->current_slot);
212 
213   return 0;
214 }
215 
SetActiveBootSlot(boot_control_module_t * module,unsigned int slot)216 int SetActiveBootSlot(boot_control_module_t* module, unsigned int slot) {
217   BootControlPrivate* const bootctrl_module =
218     reinterpret_cast<BootControlPrivate*>(module);
219 
220   if (!IsInitialized(bootctrl_module))
221     return -1;
222 
223   if (slot >= kMaxNumSlots || slot >= bootctrl_module->num_slots) {
224     // Invalid slot number.
225     return -1;
226   }
227 
228   bootloader_control bootctrl;
229   if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl))
230     return -1;
231 
232   // Set every other slot with a lower priority than the new "active" slot.
233   const unsigned int kActivePriority = 15;
234   const unsigned int kActiveTries = 6;
235   for (unsigned int i = 0; i < bootctrl_module->num_slots; ++i) {
236     if (i != slot) {
237       if (bootctrl.slot_info[i].priority >= kActivePriority)
238         bootctrl.slot_info[i].priority = kActivePriority - 1;
239     }
240   }
241 
242   // Note that setting a slot as active doesn't change the successful bit.
243   // The successful bit will only be changed by setSlotAsUnbootable().
244   bootctrl.slot_info[slot].priority = kActivePriority;
245   bootctrl.slot_info[slot].tries_remaining = kActiveTries;
246 
247   // Setting the current slot as active is a way to revert the operation that
248   // set *another* slot as active at the end of an updater. This is commonly
249   // used to cancel the pending update. We should only reset the verity_corrpted
250   // bit when attempting a new slot, otherwise the verity bit on the current
251   // slot would be flip.
252   if (slot != bootctrl_module->current_slot)
253     bootctrl.slot_info[slot].verity_corrupted = 0;
254 
255   if (!SaveBootloaderControl(bootctrl_module->misc_device, &bootctrl))
256     return -1;
257 
258   ALOGI("Slot %d is set as active", slot);
259 
260   return 0;
261 }
262 
SetSlotAsUnbootable(boot_control_module_t * module,unsigned int slot)263 int SetSlotAsUnbootable(boot_control_module_t* module, unsigned int slot) {
264   BootControlPrivate* const bootctrl_module =
265     reinterpret_cast<BootControlPrivate*>(module);
266 
267   if (!IsInitialized(bootctrl_module))
268     return -1;
269 
270   if (slot >= kMaxNumSlots || slot >= bootctrl_module->num_slots) {
271     // Invalid slot number.
272     return -1;
273   }
274 
275   bootloader_control bootctrl;
276   if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl))
277     return -1;
278 
279   // The only way to mark a slot as unbootable, regardless of the priority is to
280   // set the tries_remaining to 0.
281   bootctrl.slot_info[slot].successful_boot = 0;
282   bootctrl.slot_info[slot].tries_remaining = 0;
283   if (!SaveBootloaderControl(bootctrl_module->misc_device, &bootctrl))
284     return -1;
285 
286   ALOGI("Slot %d is marked as unbootable", slot);
287 
288   return 0;
289 }
290 
IsSlotBootable(struct boot_control_module * module,unsigned int slot)291 int IsSlotBootable(struct boot_control_module* module, unsigned int slot) {
292   BootControlPrivate* const bootctrl_module =
293     reinterpret_cast<BootControlPrivate*>(module);
294 
295   if (!IsInitialized(bootctrl_module)) return -1;
296 
297   if (slot >= kMaxNumSlots || slot >= bootctrl_module->num_slots) {
298     // Invalid slot number.
299     return -1;
300   }
301 
302   bootloader_control bootctrl;
303   if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl))
304     return -1;
305 
306   return bootctrl.slot_info[slot].tries_remaining;
307 }
308 
GetSuffix(boot_control_module_t * module,unsigned int slot)309 const char* GetSuffix(boot_control_module_t* module, unsigned int slot) {
310   BootControlPrivate* const bootctrl_module =
311     reinterpret_cast<BootControlPrivate*>(module);
312 
313   if (!IsInitialized(bootctrl_module)) return NULL;
314 
315   if (slot >= kMaxNumSlots || slot >= bootctrl_module->num_slots) return NULL;
316 
317   return kSlotSuffixes[slot];
318 }
319 
320 static hw_module_methods_t boot_control_module_methods = {
321   .open = NULL,
322 };
323 
324 BootControlPrivate HAL_MODULE_INFO_SYM = {
325   .base = {
326     .common ={
327       .tag = HARDWARE_MODULE_TAG,
328       .module_api_version = 1,
329       .hal_api_version = 0,
330       .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
331       .name = "AM57xx Boot control HAL",
332       .author = "Texas Instruments",
333       .methods = &boot_control_module_methods
334     },
335 
336     .init = BootControlInit,
337     .getNumberSlots = GetNumberSlots,
338     .getCurrentSlot = GetCurrentSlot,
339     .markBootSuccessful = MarkBootSuccessful,
340     .setActiveBootSlot = SetActiveBootSlot,
341     .setSlotAsUnbootable = SetSlotAsUnbootable,
342     .isSlotBootable = IsSlotBootable,
343     .getSuffix = GetSuffix,
344     .isSlotMarkedSuccessful = IsSlotMarkedSuccessful
345   },
346 
347   .initialized = false,
348   .misc_device = nullptr,
349   .num_slots = 0,
350   .current_slot = 0
351 };
352