1 /*
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 <errno.h>
26 #include <string.h>
27
28 #include <cutils/properties.h>
29 #include <hardware/boot_control.h>
30 #include <hardware/hardware.h>
31
32 #include <libavb_ab/libavb_ab.h>
33 #include <libavb_user/libavb_user.h>
34
35 static AvbOps* ops = NULL;
36
module_init(boot_control_module_t * module)37 static void module_init(boot_control_module_t* module) {
38 if (ops != NULL) {
39 return;
40 }
41
42 ops = avb_ops_user_new();
43 if (ops == NULL) {
44 avb_error("Unable to allocate AvbOps instance.\n");
45 }
46 }
47
module_getNumberSlots(boot_control_module_t * module)48 static unsigned int module_getNumberSlots(boot_control_module_t* module) {
49 return 2;
50 }
51
module_getCurrentSlot(boot_control_module_t * module)52 static unsigned int module_getCurrentSlot(boot_control_module_t* module) {
53 char propbuf[PROPERTY_VALUE_MAX];
54
55 property_get("ro.boot.slot_suffix", propbuf, "");
56 if (strcmp(propbuf, "_a") == 0) {
57 return 0;
58 } else if (strcmp(propbuf, "_b") == 0) {
59 return 1;
60 } else {
61 avb_error("Unexpected slot suffix '", propbuf, "'.\n");
62 return 0;
63 }
64 return 0;
65 }
66
module_markBootSuccessful(boot_control_module_t * module)67 static int module_markBootSuccessful(boot_control_module_t* module) {
68 if (avb_ab_mark_slot_successful(ops->ab_ops, module_getCurrentSlot(module)) ==
69 AVB_IO_RESULT_OK) {
70 return 0;
71 } else {
72 return -EIO;
73 }
74 }
75
module_setActiveBootSlot(boot_control_module_t * module,unsigned int slot)76 static int module_setActiveBootSlot(boot_control_module_t* module,
77 unsigned int slot) {
78 if (slot >= module_getNumberSlots(module)) {
79 return -EINVAL;
80 } else if (avb_ab_mark_slot_active(ops->ab_ops, slot) == AVB_IO_RESULT_OK) {
81 return 0;
82 } else {
83 return -EIO;
84 }
85 }
86
module_setSlotAsUnbootable(struct boot_control_module * module,unsigned int slot)87 static int module_setSlotAsUnbootable(struct boot_control_module* module,
88 unsigned int slot) {
89 if (slot >= module_getNumberSlots(module)) {
90 return -EINVAL;
91 } else if (avb_ab_mark_slot_unbootable(ops->ab_ops, slot) ==
92 AVB_IO_RESULT_OK) {
93 return 0;
94 } else {
95 return -EIO;
96 }
97 }
98
module_isSlotBootable(struct boot_control_module * module,unsigned int slot)99 static int module_isSlotBootable(struct boot_control_module* module,
100 unsigned int slot) {
101 AvbABData ab_data;
102 bool is_bootable;
103
104 avb_assert(slot < 2);
105
106 if (slot >= module_getNumberSlots(module)) {
107 return -EINVAL;
108 } else if (avb_ab_data_read(ops->ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
109 return -EIO;
110 }
111
112 is_bootable = (ab_data.slots[slot].priority > 0) &&
113 (ab_data.slots[slot].successful_boot ||
114 (ab_data.slots[slot].tries_remaining > 0));
115
116 return is_bootable ? 1 : 0;
117 }
118
module_isSlotMarkedSuccessful(struct boot_control_module * module,unsigned int slot)119 static int module_isSlotMarkedSuccessful(struct boot_control_module* module,
120 unsigned int slot) {
121 AvbABData ab_data;
122 bool is_marked_successful;
123
124 avb_assert(slot < 2);
125
126 if (slot >= module_getNumberSlots(module)) {
127 return -EINVAL;
128 } else if (avb_ab_data_read(ops->ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
129 return -EIO;
130 }
131
132 is_marked_successful = ab_data.slots[slot].successful_boot;
133
134 return is_marked_successful ? 1 : 0;
135 }
136
module_getSuffix(boot_control_module_t * module,unsigned int slot)137 static const char* module_getSuffix(boot_control_module_t* module,
138 unsigned int slot) {
139 static const char* suffix[2] = {"_a", "_b"};
140 if (slot >= 2) {
141 return NULL;
142 }
143 return suffix[slot];
144 }
145
146 static struct hw_module_methods_t module_methods = {
147 .open = NULL,
148 };
149
150 boot_control_module_t HAL_MODULE_INFO_SYM = {
151 .common =
152 {
153 .tag = HARDWARE_MODULE_TAG,
154 .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
155 .hal_api_version = HARDWARE_HAL_API_VERSION,
156 .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
157 .name = "AVB implementation of boot_control HAL",
158 .author = "The Android Open Source Project",
159 .methods = &module_methods,
160 },
161 .init = module_init,
162 .getNumberSlots = module_getNumberSlots,
163 .getCurrentSlot = module_getCurrentSlot,
164 .markBootSuccessful = module_markBootSuccessful,
165 .setActiveBootSlot = module_setActiveBootSlot,
166 .setSlotAsUnbootable = module_setSlotAsUnbootable,
167 .isSlotBootable = module_isSlotBootable,
168 .getSuffix = module_getSuffix,
169 .isSlotMarkedSuccessful = module_isSlotMarkedSuccessful,
170 };
171