diff options
author | android-build-team Robot | 2019-01-12 22:09:12 -0600 |
---|---|---|
committer | android-build-team Robot | 2019-01-12 22:09:12 -0600 |
commit | 1f95a049c93e6a9ceb0f88d852bca75d161257e6 (patch) | |
tree | 0b8683ab5a13b8e34d8206fa3afc8b48287acbea | |
parent | 12e4569d313e47412ffd4c6a8bc30c471f7b27ee (diff) | |
parent | 5136ea99414cc735933e4d92d6a44ff6b005b181 (diff) | |
download | hardware-ti-am57x-1f95a049c93e6a9ceb0f88d852bca75d161257e6.tar.gz hardware-ti-am57x-1f95a049c93e6a9ceb0f88d852bca75d161257e6.tar.xz hardware-ti-am57x-1f95a049c93e6a9ceb0f88d852bca75d161257e6.zip |
Snap for 5228332 from 5136ea99414cc735933e4d92d6a44ff6b005b181 to qt-release
Change-Id: I8abb0b4abd5c8b414081df7e628442b0c0faba98
-rw-r--r-- | bootctrl/Android.bp | 40 | ||||
-rw-r--r-- | bootctrl/boot_control.cc | 351 | ||||
-rw-r--r-- | bootctrl/bootloader_message.cpp | 249 | ||||
-rw-r--r-- | bootctrl/bootloader_message.h | 249 |
4 files changed, 889 insertions, 0 deletions
diff --git a/bootctrl/Android.bp b/bootctrl/Android.bp new file mode 100644 index 0000000..ce5041f --- /dev/null +++ b/bootctrl/Android.bp | |||
@@ -0,0 +1,40 @@ | |||
1 | // Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | // See the License for the specific language governing permissions and | ||
13 | // limitations under the License. | ||
14 | |||
15 | cc_library_shared { | ||
16 | name: "bootctrl.am57x", | ||
17 | |||
18 | vendor: true, | ||
19 | relative_install_path: "hw", | ||
20 | |||
21 | srcs: [ | ||
22 | "boot_control.cc", | ||
23 | "bootloader_message.cpp" | ||
24 | ], | ||
25 | |||
26 | cflags: [ | ||
27 | "-DLOG_TAG=\"ti_bootcontrol\"", | ||
28 | ], | ||
29 | |||
30 | header_libs: ["libhardware_headers"], | ||
31 | |||
32 | static_libs: ["libfstab",], | ||
33 | |||
34 | shared_libs: [ | ||
35 | "liblog", | ||
36 | "libcutils", | ||
37 | "libbase", | ||
38 | "libz" | ||
39 | ], | ||
40 | } | ||
diff --git a/bootctrl/boot_control.cc b/bootctrl/boot_control.cc new file mode 100644 index 0000000..28c30d4 --- /dev/null +++ b/bootctrl/boot_control.cc | |||
@@ -0,0 +1,351 @@ | |||
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. | ||
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 | |||
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 | |||
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. | ||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | }; | ||
diff --git a/bootctrl/bootloader_message.cpp b/bootctrl/bootloader_message.cpp new file mode 100644 index 0000000..a4634ed --- /dev/null +++ b/bootctrl/bootloader_message.cpp | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 The Android Open Source Project | ||
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 "bootloader_message.h" | ||
18 | |||
19 | #include <errno.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <string.h> | ||
22 | |||
23 | #include <string> | ||
24 | #include <vector> | ||
25 | |||
26 | #include <android-base/file.h> | ||
27 | #include <android-base/properties.h> | ||
28 | #include <android-base/stringprintf.h> | ||
29 | #include <android-base/unique_fd.h> | ||
30 | #include <fstab/fstab.h> | ||
31 | |||
32 | constexpr off_t kBootloaderControlOffset = offsetof(bootloader_message_ab, slot_suffix); | ||
33 | |||
34 | static std::string get_misc_blk_device(std::string* err) { | ||
35 | std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(), | ||
36 | fs_mgr_free_fstab); | ||
37 | if (!fstab) { | ||
38 | *err = "failed to read default fstab"; | ||
39 | return ""; | ||
40 | } | ||
41 | fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab.get(), "/misc"); | ||
42 | if (record == nullptr) { | ||
43 | *err = "failed to find /misc partition"; | ||
44 | return ""; | ||
45 | } | ||
46 | return record->blk_device; | ||
47 | } | ||
48 | |||
49 | // In recovery mode, recovery can get started and try to access the misc | ||
50 | // device before the kernel has actually created it. | ||
51 | static bool wait_for_device(const std::string& blk_device, std::string* err) { | ||
52 | int tries = 0; | ||
53 | int ret; | ||
54 | err->clear(); | ||
55 | do { | ||
56 | ++tries; | ||
57 | struct stat buf; | ||
58 | ret = stat(blk_device.c_str(), &buf); | ||
59 | if (ret == -1) { | ||
60 | *err += android::base::StringPrintf("failed to stat %s try %d: %s\n", | ||
61 | blk_device.c_str(), tries, strerror(errno)); | ||
62 | sleep(1); | ||
63 | } | ||
64 | } while (ret && tries < 10); | ||
65 | |||
66 | if (ret) { | ||
67 | *err += android::base::StringPrintf("failed to stat %s\n", blk_device.c_str()); | ||
68 | } | ||
69 | return ret == 0; | ||
70 | } | ||
71 | |||
72 | static bool read_misc_partition(void* p, size_t size, const std::string& misc_blk_device, | ||
73 | size_t offset, std::string* err) { | ||
74 | if (!wait_for_device(misc_blk_device, err)) { | ||
75 | return false; | ||
76 | } | ||
77 | android::base::unique_fd fd(open(misc_blk_device.c_str(), O_RDONLY)); | ||
78 | if (fd == -1) { | ||
79 | *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(), | ||
80 | strerror(errno)); | ||
81 | return false; | ||
82 | } | ||
83 | if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) { | ||
84 | *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(), | ||
85 | strerror(errno)); | ||
86 | return false; | ||
87 | } | ||
88 | if (!android::base::ReadFully(fd, p, size)) { | ||
89 | *err = android::base::StringPrintf("failed to read %s: %s", misc_blk_device.c_str(), | ||
90 | strerror(errno)); | ||
91 | return false; | ||
92 | } | ||
93 | return true; | ||
94 | } | ||
95 | |||
96 | static bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device, | ||
97 | size_t offset, std::string* err) { | ||
98 | android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY)); | ||
99 | if (fd == -1) { | ||
100 | *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(), | ||
101 | strerror(errno)); | ||
102 | return false; | ||
103 | } | ||
104 | if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) { | ||
105 | *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(), | ||
106 | strerror(errno)); | ||
107 | return false; | ||
108 | } | ||
109 | if (!android::base::WriteFully(fd, p, size)) { | ||
110 | *err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(), | ||
111 | strerror(errno)); | ||
112 | return false; | ||
113 | } | ||
114 | if (fsync(fd) == -1) { | ||
115 | *err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(), | ||
116 | strerror(errno)); | ||
117 | return false; | ||
118 | } | ||
119 | return true; | ||
120 | } | ||
121 | |||
122 | std::string get_bootloader_message_blk_device(std::string* err) { | ||
123 | std::string misc_blk_device = get_misc_blk_device(err); | ||
124 | if (misc_blk_device.empty()) return ""; | ||
125 | if (!wait_for_device(misc_blk_device, err)) return ""; | ||
126 | return misc_blk_device; | ||
127 | } | ||
128 | |||
129 | bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device, | ||
130 | std::string* err) { | ||
131 | return read_misc_partition(boot, sizeof(*boot), misc_blk_device, | ||
132 | BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err); | ||
133 | } | ||
134 | |||
135 | bool read_bootloader_message(bootloader_message* boot, std::string* err) { | ||
136 | std::string misc_blk_device = get_misc_blk_device(err); | ||
137 | if (misc_blk_device.empty()) { | ||
138 | return false; | ||
139 | } | ||
140 | return read_bootloader_message_from(boot, misc_blk_device, err); | ||
141 | } | ||
142 | |||
143 | bool read_bootloader_control_from(bootloader_control* boot_ctrl, const std::string& misc_blk_device, | ||
144 | std::string* err) { | ||
145 | return read_misc_partition(boot_ctrl, sizeof(bootloader_control), misc_blk_device, | ||
146 | kBootloaderControlOffset, err); | ||
147 | } | ||
148 | |||
149 | bool write_bootloader_message_to(const bootloader_message& boot, const std::string& misc_blk_device, | ||
150 | std::string* err) { | ||
151 | return write_misc_partition(&boot, sizeof(boot), misc_blk_device, | ||
152 | BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err); | ||
153 | } | ||
154 | |||
155 | bool write_bootloader_message(const bootloader_message& boot, std::string* err) { | ||
156 | std::string misc_blk_device = get_misc_blk_device(err); | ||
157 | if (misc_blk_device.empty()) { | ||
158 | return false; | ||
159 | } | ||
160 | return write_bootloader_message_to(boot, misc_blk_device, err); | ||
161 | } | ||
162 | |||
163 | bool write_bootloader_control_to(const bootloader_control* boot_ctrl, const std::string& misc_blk_device, | ||
164 | std::string* err) { | ||
165 | return write_misc_partition(boot_ctrl, sizeof(bootloader_control), misc_blk_device, | ||
166 | kBootloaderControlOffset, err); | ||
167 | } | ||
168 | |||
169 | bool clear_bootloader_message(std::string* err) { | ||
170 | bootloader_message boot = {}; | ||
171 | return write_bootloader_message(boot, err); | ||
172 | } | ||
173 | |||
174 | bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) { | ||
175 | bootloader_message boot = {}; | ||
176 | update_bootloader_message_in_struct(&boot, options); | ||
177 | |||
178 | return write_bootloader_message(boot, err); | ||
179 | } | ||
180 | |||
181 | bool update_bootloader_message(const std::vector<std::string>& options, std::string* err) { | ||
182 | bootloader_message boot; | ||
183 | if (!read_bootloader_message(&boot, err)) { | ||
184 | return false; | ||
185 | } | ||
186 | update_bootloader_message_in_struct(&boot, options); | ||
187 | |||
188 | return write_bootloader_message(boot, err); | ||
189 | } | ||
190 | |||
191 | bool update_bootloader_message_in_struct(bootloader_message* boot, | ||
192 | const std::vector<std::string>& options) { | ||
193 | if (!boot) return false; | ||
194 | // Replace the command & recovery fields. | ||
195 | memset(boot->command, 0, sizeof(boot->command)); | ||
196 | memset(boot->recovery, 0, sizeof(boot->recovery)); | ||
197 | |||
198 | strlcpy(boot->command, "boot-recovery", sizeof(boot->command)); | ||
199 | strlcpy(boot->recovery, "recovery\n", sizeof(boot->recovery)); | ||
200 | for (const auto& s : options) { | ||
201 | strlcat(boot->recovery, s.c_str(), sizeof(boot->recovery)); | ||
202 | if (s.back() != '\n') { | ||
203 | strlcat(boot->recovery, "\n", sizeof(boot->recovery)); | ||
204 | } | ||
205 | } | ||
206 | return true; | ||
207 | } | ||
208 | |||
209 | bool write_reboot_bootloader(std::string* err) { | ||
210 | bootloader_message boot; | ||
211 | if (!read_bootloader_message(&boot, err)) { | ||
212 | return false; | ||
213 | } | ||
214 | if (boot.command[0] != '\0') { | ||
215 | *err = "Bootloader command pending."; | ||
216 | return false; | ||
217 | } | ||
218 | strlcpy(boot.command, "bootonce-bootloader", sizeof(boot.command)); | ||
219 | return write_bootloader_message(boot, err); | ||
220 | } | ||
221 | |||
222 | bool read_wipe_package(std::string* package_data, size_t size, std::string* err) { | ||
223 | std::string misc_blk_device = get_misc_blk_device(err); | ||
224 | if (misc_blk_device.empty()) { | ||
225 | return false; | ||
226 | } | ||
227 | package_data->resize(size); | ||
228 | return read_misc_partition(&(*package_data)[0], size, misc_blk_device, | ||
229 | WIPE_PACKAGE_OFFSET_IN_MISC, err); | ||
230 | } | ||
231 | |||
232 | bool write_wipe_package(const std::string& package_data, std::string* err) { | ||
233 | std::string misc_blk_device = get_misc_blk_device(err); | ||
234 | if (misc_blk_device.empty()) { | ||
235 | return false; | ||
236 | } | ||
237 | return write_misc_partition(package_data.data(), package_data.size(), misc_blk_device, | ||
238 | WIPE_PACKAGE_OFFSET_IN_MISC, err); | ||
239 | } | ||
240 | |||
241 | extern "C" bool write_reboot_bootloader(void) { | ||
242 | std::string err; | ||
243 | return write_reboot_bootloader(&err); | ||
244 | } | ||
245 | |||
246 | extern "C" bool write_bootloader_message(const char* options) { | ||
247 | std::string err; | ||
248 | return write_bootloader_message({options}, &err); | ||
249 | } | ||
diff --git a/bootctrl/bootloader_message.h b/bootctrl/bootloader_message.h new file mode 100644 index 0000000..e5b9489 --- /dev/null +++ b/bootctrl/bootloader_message.h | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 The Android Open Source Project | ||
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 | #ifndef _BOOTLOADER_MESSAGE_H | ||
18 | #define _BOOTLOADER_MESSAGE_H | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <stddef.h> | ||
22 | #include <stdint.h> | ||
23 | |||
24 | // Spaces used by misc partition are as below: | ||
25 | // 0 - 2K For bootloader_message | ||
26 | // 2K - 16K Used by Vendor's bootloader (the 2K - 4K range may be optionally used | ||
27 | // as bootloader_message_ab struct) | ||
28 | // 16K - 64K Used by uncrypt and recovery to store wipe_package for A/B devices | ||
29 | // Note that these offsets are admitted by bootloader,recovery and uncrypt, so they | ||
30 | // are not configurable without changing all of them. | ||
31 | static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0; | ||
32 | static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024; | ||
33 | |||
34 | /* Bootloader Message (2-KiB) | ||
35 | * | ||
36 | * This structure describes the content of a block in flash | ||
37 | * that is used for recovery and the bootloader to talk to | ||
38 | * each other. | ||
39 | * | ||
40 | * The command field is updated by linux when it wants to | ||
41 | * reboot into recovery or to update radio or bootloader firmware. | ||
42 | * It is also updated by the bootloader when firmware update | ||
43 | * is complete (to boot into recovery for any final cleanup) | ||
44 | * | ||
45 | * The status field was used by the bootloader after the completion | ||
46 | * of an "update-radio" or "update-hboot" command, which has been | ||
47 | * deprecated since Froyo. | ||
48 | * | ||
49 | * The recovery field is only written by linux and used | ||
50 | * for the system to send a message to recovery or the | ||
51 | * other way around. | ||
52 | * | ||
53 | * The stage field is written by packages which restart themselves | ||
54 | * multiple times, so that the UI can reflect which invocation of the | ||
55 | * package it is. If the value is of the format "#/#" (eg, "1/3"), | ||
56 | * the UI will add a simple indicator of that status. | ||
57 | * | ||
58 | * We used to have slot_suffix field for A/B boot control metadata in | ||
59 | * this struct, which gets unintentionally cleared by recovery or | ||
60 | * uncrypt. Move it into struct bootloader_message_ab to avoid the | ||
61 | * issue. | ||
62 | */ | ||
63 | struct bootloader_message { | ||
64 | char command[32]; | ||
65 | char status[32]; | ||
66 | char recovery[768]; | ||
67 | |||
68 | // The 'recovery' field used to be 1024 bytes. It has only ever | ||
69 | // been used to store the recovery command line, so 768 bytes | ||
70 | // should be plenty. We carve off the last 256 bytes to store the | ||
71 | // stage string (for multistage packages) and possible future | ||
72 | // expansion. | ||
73 | char stage[32]; | ||
74 | |||
75 | // The 'reserved' field used to be 224 bytes when it was initially | ||
76 | // carved off from the 1024-byte recovery field. Bump it up to | ||
77 | // 1184-byte so that the entire bootloader_message struct rounds up | ||
78 | // to 2048-byte. | ||
79 | char reserved[1184]; | ||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * We must be cautious when changing the bootloader_message struct size, | ||
84 | * because A/B-specific fields may end up with different offsets. | ||
85 | */ | ||
86 | #if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus) | ||
87 | static_assert(sizeof(struct bootloader_message) == 2048, | ||
88 | "struct bootloader_message size changes, which may break A/B devices"); | ||
89 | #endif | ||
90 | |||
91 | /** | ||
92 | * The A/B-specific bootloader message structure (4-KiB). | ||
93 | * | ||
94 | * We separate A/B boot control metadata from the regular bootloader | ||
95 | * message struct and keep it here. Everything that's A/B-specific | ||
96 | * stays after struct bootloader_message, which should be managed by | ||
97 | * the A/B-bootloader or boot control HAL. | ||
98 | * | ||
99 | * The slot_suffix field is used for A/B implementations where the | ||
100 | * bootloader does not set the androidboot.ro.boot.slot_suffix kernel | ||
101 | * commandline parameter. This is used by fs_mgr to mount /system and | ||
102 | * other partitions with the slotselect flag set in fstab. A/B | ||
103 | * implementations are free to use all 32 bytes and may store private | ||
104 | * data past the first NUL-byte in this field. It is encouraged, but | ||
105 | * not mandatory, to use 'struct bootloader_control' described below. | ||
106 | * | ||
107 | * The update_channel field is used to store the Omaha update channel | ||
108 | * if update_engine is compiled with Omaha support. | ||
109 | */ | ||
110 | struct bootloader_message_ab { | ||
111 | struct bootloader_message message; | ||
112 | char slot_suffix[32]; | ||
113 | char update_channel[128]; | ||
114 | |||
115 | // Round up the entire struct to 4096-byte. | ||
116 | char reserved[1888]; | ||
117 | }; | ||
118 | |||
119 | /** | ||
120 | * Be cautious about the struct size change, in case we put anything post | ||
121 | * bootloader_message_ab struct (b/29159185). | ||
122 | */ | ||
123 | #if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus) | ||
124 | static_assert(sizeof(struct bootloader_message_ab) == 4096, | ||
125 | "struct bootloader_message_ab size changes"); | ||
126 | #endif | ||
127 | |||
128 | #define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */ | ||
129 | #define BOOT_CTRL_VERSION 1 | ||
130 | |||
131 | struct slot_metadata { | ||
132 | // Slot priority with 15 meaning highest priority, 1 lowest | ||
133 | // priority and 0 the slot is unbootable. | ||
134 | uint8_t priority : 4; | ||
135 | // Number of times left attempting to boot this slot. | ||
136 | uint8_t tries_remaining : 3; | ||
137 | // 1 if this slot has booted successfully, 0 otherwise. | ||
138 | uint8_t successful_boot : 1; | ||
139 | // 1 if this slot is corrupted from a dm-verity corruption, 0 | ||
140 | // otherwise. | ||
141 | uint8_t verity_corrupted : 1; | ||
142 | // Reserved for further use. | ||
143 | uint8_t reserved : 7; | ||
144 | } __attribute__((packed)); | ||
145 | |||
146 | /* Bootloader Control AB | ||
147 | * | ||
148 | * This struct can be used to manage A/B metadata. It is designed to | ||
149 | * be put in the 'slot_suffix' field of the 'bootloader_message' | ||
150 | * structure described above. It is encouraged to use the | ||
151 | * 'bootloader_control' structure to store the A/B metadata, but not | ||
152 | * mandatory. | ||
153 | */ | ||
154 | struct bootloader_control { | ||
155 | // NUL terminated active slot suffix. | ||
156 | char slot_suffix[4]; | ||
157 | // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC). | ||
158 | uint32_t magic; | ||
159 | // Version of struct being used (see BOOT_CTRL_VERSION). | ||
160 | uint8_t version; | ||
161 | // Number of slots being managed. | ||
162 | uint8_t nb_slot : 3; | ||
163 | // Number of times left attempting to boot recovery. | ||
164 | uint8_t recovery_tries_remaining : 3; | ||
165 | // Ensure 4-bytes alignment for slot_info field. | ||
166 | uint8_t reserved0[2]; | ||
167 | // Per-slot information. Up to 4 slots. | ||
168 | struct slot_metadata slot_info[4]; | ||
169 | // Reserved for further use. | ||
170 | uint8_t reserved1[8]; | ||
171 | // CRC32 of all 28 bytes preceding this field (little endian | ||
172 | // format). | ||
173 | uint32_t crc32_le; | ||
174 | } __attribute__((packed)); | ||
175 | |||
176 | #if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus) | ||
177 | static_assert(sizeof(struct bootloader_control) == | ||
178 | sizeof(((struct bootloader_message_ab *)0)->slot_suffix), | ||
179 | "struct bootloader_control has wrong size"); | ||
180 | #endif | ||
181 | |||
182 | #ifdef __cplusplus | ||
183 | |||
184 | #include <string> | ||
185 | #include <vector> | ||
186 | |||
187 | // Return the block device name for the bootloader message partition and waits | ||
188 | // for the device for up to 10 seconds. In case of error returns the empty | ||
189 | // string. | ||
190 | std::string get_bootloader_message_blk_device(std::string* err); | ||
191 | |||
192 | // Read bootloader message into boot. Error message will be set in err. | ||
193 | bool read_bootloader_message(bootloader_message* boot, std::string* err); | ||
194 | |||
195 | // Read bootloader message from the specified misc device into boot. | ||
196 | bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device, | ||
197 | std::string* err); | ||
198 | |||
199 | // Read bootloader control block from the specified misc device into boot_ctrl. | ||
200 | bool read_bootloader_control_from(bootloader_control* boot_ctrl, const std::string& misc_blk_device, | ||
201 | std::string* err); | ||
202 | |||
203 | // Write bootloader message to BCB. | ||
204 | bool write_bootloader_message(const bootloader_message& boot, std::string* err); | ||
205 | |||
206 | // Write bootloader message to the specified BCB device. | ||
207 | bool write_bootloader_message_to(const bootloader_message& boot, | ||
208 | const std::string& misc_blk_device, std::string* err); | ||
209 | |||
210 | // Write bootloader message (boots into recovery with the options) to BCB. Will | ||
211 | // set the command and recovery fields, and reset the rest. | ||
212 | bool write_bootloader_message(const std::vector<std::string>& options, std::string* err); | ||
213 | |||
214 | // Write bootloader control block to the specified BCB device. | ||
215 | bool write_bootloader_control_to(const bootloader_control* boot_ctrl, const std::string& misc_blk_device, | ||
216 | std::string* err); | ||
217 | |||
218 | // Update bootloader message (boots into recovery with the options) to BCB. Will | ||
219 | // only update the command and recovery fields. | ||
220 | bool update_bootloader_message(const std::vector<std::string>& options, std::string* err); | ||
221 | |||
222 | // Update bootloader message (boots into recovery with the |options|) in |boot|. Will only update | ||
223 | // the command and recovery fields. | ||
224 | bool update_bootloader_message_in_struct(bootloader_message* boot, | ||
225 | const std::vector<std::string>& options); | ||
226 | |||
227 | // Clear BCB. | ||
228 | bool clear_bootloader_message(std::string* err); | ||
229 | |||
230 | // Writes the reboot-bootloader reboot reason to the bootloader_message. | ||
231 | bool write_reboot_bootloader(std::string* err); | ||
232 | |||
233 | // Read the wipe package from BCB (from offset WIPE_PACKAGE_OFFSET_IN_MISC). | ||
234 | bool read_wipe_package(std::string* package_data, size_t size, std::string* err); | ||
235 | |||
236 | // Write the wipe package into BCB (to offset WIPE_PACKAGE_OFFSET_IN_MISC). | ||
237 | bool write_wipe_package(const std::string& package_data, std::string* err); | ||
238 | |||
239 | #else | ||
240 | |||
241 | #include <stdbool.h> | ||
242 | |||
243 | // C Interface. | ||
244 | bool write_bootloader_message(const char* options); | ||
245 | bool write_reboot_bootloader(void); | ||
246 | |||
247 | #endif // ifdef __cplusplus | ||
248 | |||
249 | #endif // _BOOTLOADER_MESSAGE_H | ||