xref: /aosp_15_r20/external/avb/boot_control/boot_control_avb.c (revision d289c2ba6de359471b23d594623b906876bc48a0)
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