blob: 006e61770c2fd63540bed68cbc7f9440666bfe30 [file] [log] [blame]
David Zeuthen8b6973b2016-09-20 12:39:49 -04001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include "avb_ab_flow.h"
David Zeuthen8b6973b2016-09-20 12:39:49 -040026
27bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) {
28 /* Ensure magic is correct. */
29 if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
30 avb_error("Magic is incorrect.\n");
31 return false;
32 }
33
34 avb_memcpy(dest, src, sizeof(AvbABData));
35 dest->crc32 = avb_be32toh(dest->crc32);
36
37 /* Ensure we don't attempt to access any fields if the major version
38 * is not supported.
39 */
40 if (dest->version_major > AVB_AB_MAJOR_VERSION) {
41 avb_error("No support for given major version.\n");
42 return false;
43 }
44
45 /* Bail if CRC32 doesn't match. */
46 if (dest->crc32 !=
47 avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) {
48 avb_error("CRC32 does not match.\n");
49 return false;
50 }
51
52 return true;
53}
54
55void avb_ab_data_update_crc_and_byteswap(const AvbABData* src,
56 AvbABData* dest) {
57 avb_memcpy(dest, src, sizeof(AvbABData));
58 dest->crc32 = avb_htobe32(
59 avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t)));
60}
61
62void avb_ab_data_init(AvbABData* data) {
63 avb_memset(data, '\0', sizeof(AvbABData));
64 avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
65 data->version_major = AVB_AB_MAJOR_VERSION;
66 data->version_minor = AVB_AB_MINOR_VERSION;
67 data->slots[0].priority = AVB_AB_MAX_PRIORITY;
68 data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
69 data->slots[0].successful_boot = 0;
70 data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
71 data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
72 data->slots[1].successful_boot = 0;
73}
74
75/* The AvbABData struct is stored 2048 bytes into the 'misc' partition
76 * following the 'struct bootloader_message' field. The struct is
77 * compatible with the guidelines in bootable/recovery/bootloader.h -
78 * e.g. it is stored in the |slot_suffix| field, starts with a
79 * NUL-byte, and is 32 bytes long.
80 */
81#define AB_METADATA_MISC_PARTITION_OFFSET 2048
82
David Zeuthenbaf59e22016-11-14 15:39:43 -050083AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data) {
David Zeuthen574ed992017-01-05 15:43:11 -050084 AvbOps* ops = ab_ops->ops;
David Zeuthen8b6973b2016-09-20 12:39:49 -040085 AvbABData serialized;
David Zeuthen507752b2016-09-29 16:31:18 -040086 AvbIOResult io_ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -040087 size_t num_bytes_read;
88
David Zeuthen4b6a6342017-01-03 15:19:56 -050089 io_ret = ops->read_from_partition(ops,
90 "misc",
91 AB_METADATA_MISC_PARTITION_OFFSET,
92 sizeof(AvbABData),
93 &serialized,
94 &num_bytes_read);
David Zeuthen507752b2016-09-29 16:31:18 -040095 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
96 return AVB_IO_RESULT_ERROR_OOM;
97 } else if (io_ret != AVB_IO_RESULT_OK ||
98 num_bytes_read != sizeof(AvbABData)) {
David Zeuthen8b6973b2016-09-20 12:39:49 -040099 avb_error("Error reading A/B metadata.\n");
David Zeuthen507752b2016-09-29 16:31:18 -0400100 return AVB_IO_RESULT_ERROR_IO;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400101 }
102
103 if (!avb_ab_data_verify_and_byteswap(&serialized, data)) {
104 avb_error(
105 "Error validating A/B metadata from disk. "
106 "Resetting and writing new A/B metadata to disk.\n");
107 avb_ab_data_init(data);
David Zeuthenbaf59e22016-11-14 15:39:43 -0500108 return avb_ab_data_write(ab_ops, data);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400109 }
110
David Zeuthen507752b2016-09-29 16:31:18 -0400111 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400112}
113
David Zeuthenbaf59e22016-11-14 15:39:43 -0500114AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data) {
David Zeuthen574ed992017-01-05 15:43:11 -0500115 AvbOps* ops = ab_ops->ops;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400116 AvbABData serialized;
David Zeuthen507752b2016-09-29 16:31:18 -0400117 AvbIOResult io_ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400118
119 avb_ab_data_update_crc_and_byteswap(data, &serialized);
David Zeuthen4b6a6342017-01-03 15:19:56 -0500120 io_ret = ops->write_to_partition(ops,
121 "misc",
122 AB_METADATA_MISC_PARTITION_OFFSET,
123 sizeof(AvbABData),
124 &serialized);
David Zeuthen507752b2016-09-29 16:31:18 -0400125 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
126 return AVB_IO_RESULT_ERROR_OOM;
127 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400128 avb_error("Error writing A/B metadata.\n");
David Zeuthen507752b2016-09-29 16:31:18 -0400129 return AVB_IO_RESULT_ERROR_IO;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400130 }
David Zeuthen507752b2016-09-29 16:31:18 -0400131 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400132}
133
134static bool slot_is_bootable(AvbABSlotData* slot) {
135 return slot->priority > 0 &&
136 (slot->successful_boot || (slot->tries_remaining > 0));
137}
138
139static void slot_set_unbootable(AvbABSlotData* slot) {
140 slot->priority = 0;
141 slot->tries_remaining = 0;
142 slot->successful_boot = 0;
143}
144
145/* Ensure all unbootable and/or illegal states are marked as the
146 * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
147 * and successful_boot=0.
148 */
149static void slot_normalize(AvbABSlotData* slot) {
150 if (slot->priority > 0) {
151 if (slot->tries_remaining == 0 && !slot->successful_boot) {
152 /* We've exhausted all tries -> unbootable. */
153 slot_set_unbootable(slot);
154 }
155 if (slot->tries_remaining > 0 && slot->successful_boot) {
156 /* Illegal state - avb_ab_mark_slot_successful() will clear
157 * tries_remaining when setting successful_boot.
158 */
159 slot_set_unbootable(slot);
160 }
161 } else {
162 slot_set_unbootable(slot);
163 }
164}
165
166static const char* slot_suffixes[2] = {"_a", "_b"};
167
David Zeuthen507752b2016-09-29 16:31:18 -0400168/* Helper function to load metadata - returns AVB_IO_RESULT_OK on
169 * success, error code otherwise.
170 */
David Zeuthen4b6a6342017-01-03 15:19:56 -0500171static AvbIOResult load_metadata(AvbABOps* ab_ops,
172 AvbABData* ab_data,
David Zeuthen507752b2016-09-29 16:31:18 -0400173 AvbABData* ab_data_orig) {
174 AvbIOResult io_ret;
175
David Zeuthenbaf59e22016-11-14 15:39:43 -0500176 io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data);
David Zeuthen507752b2016-09-29 16:31:18 -0400177 if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400178 avb_error("I/O error while loading A/B metadata.\n");
David Zeuthen507752b2016-09-29 16:31:18 -0400179 return io_ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400180 }
181 *ab_data_orig = *ab_data;
182
183 /* Ensure data is normalized, e.g. illegal states will be marked as
184 * unbootable and all unbootable states are represented with
185 * (priority=0, tries_remaining=0, successful_boot=0).
186 */
187 slot_normalize(&ab_data->slots[0]);
188 slot_normalize(&ab_data->slots[1]);
David Zeuthen507752b2016-09-29 16:31:18 -0400189 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400190}
191
David Zeuthen507752b2016-09-29 16:31:18 -0400192/* Writes A/B metadata to disk only if it has changed - returns
193 * AVB_IO_RESULT_OK on success, error code otherwise.
David Zeuthen8b6973b2016-09-20 12:39:49 -0400194 */
David Zeuthenbaf59e22016-11-14 15:39:43 -0500195static AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops,
196 AvbABData* ab_data,
David Zeuthen507752b2016-09-29 16:31:18 -0400197 AvbABData* ab_data_orig) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400198 if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) {
199 avb_debug("Writing A/B metadata to disk.\n");
David Zeuthenbaf59e22016-11-14 15:39:43 -0500200 return ab_ops->write_ab_metadata(ab_ops, ab_data);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400201 }
David Zeuthen507752b2016-09-29 16:31:18 -0400202 return AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400203}
204
David Zeuthenbaf59e22016-11-14 15:39:43 -0500205AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
David Zeuthena8bb9a02016-10-28 14:36:55 -0400206 const char* const* requested_partitions,
David Zeuthen0155e6b2016-11-16 17:58:13 -0500207 bool allow_verification_error,
David Zeuthena8bb9a02016-10-28 14:36:55 -0400208 AvbSlotVerifyData** out_data) {
David Zeuthen574ed992017-01-05 15:43:11 -0500209 AvbOps* ops = ab_ops->ops;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400210 AvbSlotVerifyData* slot_data[2] = {NULL, NULL};
211 AvbSlotVerifyData* data = NULL;
212 AvbABFlowResult ret;
213 AvbABData ab_data, ab_data_orig;
214 size_t slot_index_to_boot, n;
David Zeuthen507752b2016-09-29 16:31:18 -0400215 AvbIOResult io_ret;
David Zeuthen0155e6b2016-11-16 17:58:13 -0500216 bool saw_and_allowed_verification_error = false;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400217
David Zeuthenbaf59e22016-11-14 15:39:43 -0500218 io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
David Zeuthen507752b2016-09-29 16:31:18 -0400219 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
220 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
221 goto out;
222 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400223 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
224 goto out;
225 }
226
227 /* Validate all bootable slots. */
228 for (n = 0; n < 2; n++) {
229 if (slot_is_bootable(&ab_data.slots[n])) {
230 AvbSlotVerifyResult verify_result;
David Zeuthen0155e6b2016-11-16 17:58:13 -0500231 bool set_slot_unbootable = false;
232
David Zeuthen4b6a6342017-01-03 15:19:56 -0500233 verify_result = avb_slot_verify(ops,
234 requested_partitions,
235 slot_suffixes[n],
236 allow_verification_error,
237 &slot_data[n]);
David Zeuthen0155e6b2016-11-16 17:58:13 -0500238 switch (verify_result) {
239 case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
David Zeuthen8b6973b2016-09-20 12:39:49 -0400240 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
241 goto out;
David Zeuthen0155e6b2016-11-16 17:58:13 -0500242
243 case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
David Zeuthen8b6973b2016-09-20 12:39:49 -0400244 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
245 goto out;
David Zeuthen0155e6b2016-11-16 17:58:13 -0500246
247 case AVB_SLOT_VERIFY_RESULT_OK:
248 break;
249
250 case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
251 /* Even with |allow_verification_error| this is game over. */
252 set_slot_unbootable = true;
253 break;
254
255 /* explicit fallthrough. */
256 case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
257 case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
258 case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
259 if (allow_verification_error) {
260 /* Do nothing since we allow this. */
David Zeuthen4b6a6342017-01-03 15:19:56 -0500261 avb_debugv("Allowing slot ",
262 slot_suffixes[n],
David Zeuthen0155e6b2016-11-16 17:58:13 -0500263 " which verified "
264 "with result ",
265 avb_slot_verify_result_to_string(verify_result),
David Zeuthen4b6a6342017-01-03 15:19:56 -0500266 " because |allow_verification_error| is true.\n",
267 NULL);
David Zeuthen0155e6b2016-11-16 17:58:13 -0500268 saw_and_allowed_verification_error = true;
269 } else {
270 set_slot_unbootable = true;
271 }
272 break;
273 }
274
275 if (set_slot_unbootable) {
David Zeuthen4b6a6342017-01-03 15:19:56 -0500276 avb_errorv("Error verifying slot ",
277 slot_suffixes[n],
278 " with result ",
David Zeuthen8b6973b2016-09-20 12:39:49 -0400279 avb_slot_verify_result_to_string(verify_result),
David Zeuthen4b6a6342017-01-03 15:19:56 -0500280 " - setting unbootable.\n",
281 NULL);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400282 slot_set_unbootable(&ab_data.slots[n]);
283 }
284 }
285 }
286
287 if (slot_is_bootable(&ab_data.slots[0]) &&
288 slot_is_bootable(&ab_data.slots[1])) {
289 if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
290 slot_index_to_boot = 1;
291 } else {
292 slot_index_to_boot = 0;
293 }
294 } else if (slot_is_bootable(&ab_data.slots[0])) {
295 slot_index_to_boot = 0;
296 } else if (slot_is_bootable(&ab_data.slots[1])) {
297 slot_index_to_boot = 1;
298 } else {
299 /* No bootable slots! */
300 avb_error("No bootable slots found.\n");
301 ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
302 goto out;
303 }
304
305 /* Update stored rollback index such that the stored rollback index
306 * is the largest value supporting all currently bootable slots. Do
David Zeuthen40ee1da2016-11-23 15:14:49 -0500307 * this for every rollback index location.
David Zeuthen8b6973b2016-09-20 12:39:49 -0400308 */
David Zeuthen40ee1da2016-11-23 15:14:49 -0500309 for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400310 uint64_t rollback_index_value = 0;
311
312 if (slot_data[0] != NULL && slot_data[1] != NULL) {
313 uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n];
314 uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n];
315 rollback_index_value =
316 (a_rollback_index < b_rollback_index ? a_rollback_index
317 : b_rollback_index);
318 } else if (slot_data[0] != NULL) {
319 rollback_index_value = slot_data[0]->rollback_indexes[n];
320 } else if (slot_data[1] != NULL) {
321 rollback_index_value = slot_data[1]->rollback_indexes[n];
322 }
323
324 if (rollback_index_value != 0) {
325 uint64_t current_rollback_index_value;
David Zeuthen507752b2016-09-29 16:31:18 -0400326 io_ret = ops->read_rollback_index(ops, n, &current_rollback_index_value);
327 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
328 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
329 goto out;
330 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400331 avb_error("Error getting rollback index for slot.\n");
332 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
333 goto out;
334 }
335 if (current_rollback_index_value != rollback_index_value) {
David Zeuthen507752b2016-09-29 16:31:18 -0400336 io_ret = ops->write_rollback_index(ops, n, rollback_index_value);
337 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
338 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
339 goto out;
340 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400341 avb_error("Error setting stored rollback index.\n");
342 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
343 goto out;
344 }
345 }
346 }
347 }
348
349 /* Finally, select this slot. */
350 avb_assert(slot_data[slot_index_to_boot] != NULL);
351 data = slot_data[slot_index_to_boot];
352 slot_data[slot_index_to_boot] = NULL;
David Zeuthen0155e6b2016-11-16 17:58:13 -0500353 if (saw_and_allowed_verification_error) {
354 avb_assert(allow_verification_error);
355 ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR;
356 } else {
357 ret = AVB_AB_FLOW_RESULT_OK;
358 }
David Zeuthen8b6973b2016-09-20 12:39:49 -0400359
360 /* ... and decrement tries remaining, if applicable. */
361 if (!ab_data.slots[slot_index_to_boot].successful_boot &&
362 ab_data.slots[slot_index_to_boot].tries_remaining > 0) {
363 ab_data.slots[slot_index_to_boot].tries_remaining -= 1;
364 }
365
366out:
David Zeuthenbaf59e22016-11-14 15:39:43 -0500367 io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
David Zeuthen507752b2016-09-29 16:31:18 -0400368 if (io_ret != AVB_IO_RESULT_OK) {
369 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
370 ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
371 } else {
372 ret = AVB_AB_FLOW_RESULT_ERROR_IO;
373 }
David Zeuthen8b6973b2016-09-20 12:39:49 -0400374 if (data != NULL) {
375 avb_slot_verify_data_free(data);
376 data = NULL;
377 }
378 }
379
380 for (n = 0; n < 2; n++) {
381 if (slot_data[n] != NULL) {
382 avb_slot_verify_data_free(slot_data[n]);
383 }
384 }
385
386 if (out_data != NULL) {
387 *out_data = data;
388 } else {
389 if (data != NULL) {
390 avb_slot_verify_data_free(data);
391 }
392 }
393
394 return ret;
395}
396
David Zeuthenbaf59e22016-11-14 15:39:43 -0500397AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops,
398 unsigned int slot_number) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400399 AvbABData ab_data, ab_data_orig;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400400 unsigned int other_slot_number;
David Zeuthen507752b2016-09-29 16:31:18 -0400401 AvbIOResult ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400402
403 avb_assert(slot_number < 2);
404
David Zeuthenbaf59e22016-11-14 15:39:43 -0500405 ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
David Zeuthen507752b2016-09-29 16:31:18 -0400406 if (ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400407 goto out;
408 }
409
410 /* Make requested slot top priority, unsuccessful, and with max tries. */
411 ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY;
412 ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
413 ab_data.slots[slot_number].successful_boot = 0;
414
415 /* Ensure other slot doesn't have as high a priority. */
416 other_slot_number = 1 - slot_number;
417 if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) {
418 ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1;
419 }
420
David Zeuthen507752b2016-09-29 16:31:18 -0400421 ret = AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400422
423out:
David Zeuthen507752b2016-09-29 16:31:18 -0400424 if (ret == AVB_IO_RESULT_OK) {
David Zeuthenbaf59e22016-11-14 15:39:43 -0500425 ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400426 }
427 return ret;
428}
429
David Zeuthenbaf59e22016-11-14 15:39:43 -0500430AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
431 unsigned int slot_number) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400432 AvbABData ab_data, ab_data_orig;
David Zeuthen507752b2016-09-29 16:31:18 -0400433 AvbIOResult ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400434
435 avb_assert(slot_number < 2);
436
David Zeuthenbaf59e22016-11-14 15:39:43 -0500437 ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
David Zeuthen507752b2016-09-29 16:31:18 -0400438 if (ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400439 goto out;
440 }
441
442 slot_set_unbootable(&ab_data.slots[slot_number]);
David Zeuthen507752b2016-09-29 16:31:18 -0400443
444 ret = AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400445
446out:
David Zeuthen507752b2016-09-29 16:31:18 -0400447 if (ret == AVB_IO_RESULT_OK) {
David Zeuthenbaf59e22016-11-14 15:39:43 -0500448 ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400449 }
450 return ret;
451}
452
David Zeuthenbaf59e22016-11-14 15:39:43 -0500453AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
454 unsigned int slot_number) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400455 AvbABData ab_data, ab_data_orig;
David Zeuthen507752b2016-09-29 16:31:18 -0400456 AvbIOResult ret;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400457
458 avb_assert(slot_number < 2);
459
David Zeuthenbaf59e22016-11-14 15:39:43 -0500460 ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
David Zeuthen507752b2016-09-29 16:31:18 -0400461 if (ret != AVB_IO_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400462 goto out;
463 }
464
465 if (!slot_is_bootable(&ab_data.slots[slot_number])) {
466 avb_error("Cannot mark unbootable slot as successful.\n");
David Zeuthen507752b2016-09-29 16:31:18 -0400467 ret = AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400468 goto out;
469 }
470
471 ab_data.slots[slot_number].tries_remaining = 0;
472 ab_data.slots[slot_number].successful_boot = 1;
473
David Zeuthen507752b2016-09-29 16:31:18 -0400474 ret = AVB_IO_RESULT_OK;
David Zeuthen8b6973b2016-09-20 12:39:49 -0400475
476out:
David Zeuthen507752b2016-09-29 16:31:18 -0400477 if (ret == AVB_IO_RESULT_OK) {
David Zeuthenbaf59e22016-11-14 15:39:43 -0500478 ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
David Zeuthen8b6973b2016-09-20 12:39:49 -0400479 }
480 return ret;
481}
David Zeuthen0155e6b2016-11-16 17:58:13 -0500482
483const char* avb_ab_flow_result_to_string(AvbABFlowResult result) {
484 const char* ret = NULL;
485
486 switch (result) {
487 case AVB_AB_FLOW_RESULT_OK:
488 ret = "OK";
489 break;
490
491 case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR:
492 ret = "OK_WITH_VERIFICATION_ERROR";
493 break;
494
495 case AVB_AB_FLOW_RESULT_ERROR_OOM:
496 ret = "ERROR_OOM";
497 break;
498
499 case AVB_AB_FLOW_RESULT_ERROR_IO:
500 ret = "ERROR_IO";
501 break;
502
503 case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS:
504 ret = "ERROR_NO_BOOTABLE_SLOTS";
505 break;
506 /* Do not add a 'default:' case here because of -Wswitch. */
507 }
508
509 if (ret == NULL) {
510 avb_error("Unknown AvbABFlowResult value.\n");
511 ret = "(unknown)";
512 }
513
514 return ret;
515}