blob: 899b6e28ba4e5d3240e8cf07f28ee33fa7d66868 [file] [log] [blame]
Ameya Thakurc14fff02016-02-24 11:25:43 -08001/*
2 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
Ameya Thakur2f9e1a02016-06-22 18:25:38 -070029#include <map>
30#include <list>
31#include <string>
32#include <vector>
33#ifdef __cplusplus
34extern "C" {
35#endif
Ameya Thakurc14fff02016-02-24 11:25:43 -080036#include <errno.h>
37#define LOG_TAG "bootcontrolhal"
38#include <cutils/log.h>
39#include <hardware/boot_control.h>
40#include <stdio.h>
41#include <string.h>
42#include <unistd.h>
43#include <dirent.h>
44#include <sys/types.h>
45#include <sys/stat.h>
46#include <fcntl.h>
47#include <limits.h>
Ameya Thakur369d6832016-05-02 16:21:13 -070048#include <cutils/properties.h>
Ameya Thakurc14fff02016-02-24 11:25:43 -080049#include "gpt-utils.h"
50
51#define BOOTDEV_DIR "/dev/block/bootdevice/by-name"
52#define BOOT_IMG_PTN_NAME "boot"
53#define LUN_NAME_END_LOC 14
Ameya Thakur369d6832016-05-02 16:21:13 -070054#define BOOT_SLOT_PROP "ro.boot.slot_suffix"
Ameya Thakurc14fff02016-02-24 11:25:43 -080055
Ameya Thakur2f9e1a02016-06-22 18:25:38 -070056#define SLOT_ACTIVE 1
57#define SLOT_INACTIVE 2
58#define UPDATE_SLOT(pentry, guid, slot_state) ({ \
59 memcpy(pentry, guid, TYPE_GUID_SIZE); \
60 if (slot_state == SLOT_ACTIVE)\
61 *(pentry + AB_FLAG_OFFSET) = AB_SLOT_ACTIVE_VAL; \
62 else if (slot_state == SLOT_INACTIVE) \
63 *(pentry + AB_FLAG_OFFSET) = (*(pentry + AB_FLAG_OFFSET)& \
64 ~AB_PARTITION_ATTR_SLOT_ACTIVE); \
65 })
66
67using namespace std;
Ameya Thakurc14fff02016-02-24 11:25:43 -080068const char *slot_suffix_arr[] = {
69 AB_SLOT_A_SUFFIX,
70 AB_SLOT_B_SUFFIX,
71 NULL};
72
73enum part_attr_type {
74 ATTR_SLOT_ACTIVE = 0,
75 ATTR_BOOT_SUCCESSFUL,
76 ATTR_UNBOOTABLE,
77};
78
79void boot_control_init(struct boot_control_module *module)
80{
81 if (!module) {
82 ALOGE("Invalid argument passed to %s", __func__);
83 return;
84 }
85 return;
86}
87
88//Get the value of one of the attribute fields for a partition.
89static int get_partition_attribute(char *partname,
90 enum part_attr_type part_attr)
91{
92 struct gpt_disk *disk = NULL;
93 uint8_t *pentry = NULL;
94 int retval = -1;
95 uint8_t *attr = NULL;
96 if (!partname)
97 goto error;
98 disk = gpt_disk_alloc();
99 if (!disk) {
100 ALOGE("%s: Failed to alloc disk struct", __func__);
101 goto error;
102 }
103 if (gpt_disk_get_disk_info(partname, disk)) {
104 ALOGE("%s: Failed to get disk info", __func__);
105 goto error;
106 }
107 pentry = gpt_disk_get_pentry(disk, partname, PRIMARY_GPT);
108 if (!pentry) {
109 ALOGE("%s: pentry does not exist in disk struct",
110 __func__);
111 goto error;
112 }
113 attr = pentry + AB_FLAG_OFFSET;
114 if (part_attr == ATTR_SLOT_ACTIVE)
115 retval = !!(*attr & AB_PARTITION_ATTR_SLOT_ACTIVE);
116 else if (part_attr == ATTR_BOOT_SUCCESSFUL)
117 retval = !!(*attr & AB_PARTITION_ATTR_BOOT_SUCCESSFUL);
118 else if (part_attr == ATTR_UNBOOTABLE)
119 retval = !!(*attr & AB_PARTITION_ATTR_UNBOOTABLE);
120 else
121 retval = -1;
122 gpt_disk_free(disk);
123 return retval;
124error:
125 if (disk)
126 gpt_disk_free(disk);
127 return retval;
128}
129
130//Set a particular attribute for all the partitions in a
131//slot
132static int update_slot_attribute(const char *slot,
133 enum part_attr_type ab_attr)
134{
135 unsigned int i = 0;
136 char buf[PATH_MAX];
137 struct stat st;
138 struct gpt_disk *disk = NULL;
139 uint8_t *pentry = NULL;
140 uint8_t *pentry_bak = NULL;
141 int rc = -1;
142 uint8_t *attr = NULL;
143 uint8_t *attr_bak = NULL;
144 char partName[MAX_GPT_NAME_SIZE + 1] = {0};
145 const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
146 int slot_name_valid = 0;
147 if (!slot) {
148 ALOGE("%s: Invalid argument", __func__);
149 goto error;
150 }
151 for (i = 0; slot_suffix_arr[i] != NULL; i++)
152 {
153 if (!strncmp(slot, slot_suffix_arr[i],
154 strlen(slot_suffix_arr[i])))
155 slot_name_valid = 1;
156 }
157 if (!slot_name_valid) {
158 ALOGE("%s: Invalid slot name", __func__);
159 goto error;
160 }
161 for (i=0; i < ARRAY_SIZE(ptn_list); i++) {
162 memset(buf, '\0', sizeof(buf));
163 //Check if A/B versions of this ptn exist
164 snprintf(buf, sizeof(buf) - 1,
165 "%s/%s%s",
166 BOOT_DEV_DIR,
167 ptn_list[i],
168 AB_SLOT_A_SUFFIX
169 );
170 if (stat(buf, &st)) {
171 //partition does not have _a version
172 continue;
173 }
174 memset(buf, '\0', sizeof(buf));
175 snprintf(buf, sizeof(buf) - 1,
176 "%s/%s%s",
177 BOOT_DEV_DIR,
178 ptn_list[i],
179 AB_SLOT_B_SUFFIX
180 );
181 if (stat(buf, &st)) {
182 //partition does not have _a version
183 continue;
184 }
185 memset(partName, '\0', sizeof(partName));
186 snprintf(partName,
187 sizeof(partName) - 1,
188 "%s%s",
189 ptn_list[i],
190 slot);
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700191 disk = gpt_disk_alloc();
Ameya Thakurc14fff02016-02-24 11:25:43 -0800192 if (!disk) {
193 ALOGE("%s: Failed to alloc disk struct",
194 __func__);
195 goto error;
196 }
197 rc = gpt_disk_get_disk_info(partName, disk);
198 if (rc != 0) {
199 ALOGE("%s: Failed to get disk info for %s",
200 __func__,
201 partName);
202 goto error;
203 }
204 pentry = gpt_disk_get_pentry(disk, partName, PRIMARY_GPT);
205 pentry_bak = gpt_disk_get_pentry(disk, partName, SECONDARY_GPT);
206 if (!pentry || !pentry_bak) {
207 ALOGE("%s: Failed to get pentry/pentry_bak for %s",
208 __func__,
209 partName);
210 goto error;
211 }
212 attr = pentry + AB_FLAG_OFFSET;
213 attr_bak = pentry_bak + AB_FLAG_OFFSET;
214 if (ab_attr == ATTR_BOOT_SUCCESSFUL) {
215 *attr = (*attr) | AB_PARTITION_ATTR_BOOT_SUCCESSFUL;
216 *attr_bak = (*attr_bak) |
217 AB_PARTITION_ATTR_BOOT_SUCCESSFUL;
218 } else if (ab_attr == ATTR_UNBOOTABLE) {
219 *attr = (*attr) | AB_PARTITION_ATTR_UNBOOTABLE;
220 *attr_bak = (*attr_bak) | AB_PARTITION_ATTR_UNBOOTABLE;
221 } else if (ab_attr == ATTR_SLOT_ACTIVE) {
222 *attr = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE;
223 *attr_bak = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE;
224 } else {
225 ALOGE("%s: Unrecognized attr", __func__);
226 goto error;
227 }
228 if (gpt_disk_update_crc(disk)) {
229 ALOGE("%s: Failed to update crc for %s",
230 __func__,
231 partName);
232 goto error;
233 }
234 if (gpt_disk_commit(disk)) {
235 ALOGE("%s: Failed to write back entry for %s",
236 __func__,
237 partName);
238 goto error;
239 }
240 gpt_disk_free(disk);
241 disk = NULL;
242 }
243 return 0;
244error:
245 if (disk)
246 gpt_disk_free(disk);
247 return -1;
248}
249
250unsigned get_number_slots(struct boot_control_module *module)
251{
252 struct dirent *de = NULL;
253 DIR *dir_bootdev = NULL;
254 unsigned slot_count = 0;
255 if (!module) {
256 ALOGE("%s: Invalid argument", __func__);
257 goto error;
258 }
259 dir_bootdev = opendir(BOOTDEV_DIR);
260 if (!dir_bootdev) {
261 ALOGE("%s: Failed to open bootdev dir (%s)",
262 __func__,
263 strerror(errno));
264 goto error;
265 }
266 while ((de = readdir(dir_bootdev))) {
267 if (de->d_name[0] == '.')
268 continue;
269 if (!strncmp(de->d_name, BOOT_IMG_PTN_NAME,
270 strlen(BOOT_IMG_PTN_NAME)))
271 slot_count++;
272 }
273 closedir(dir_bootdev);
274 return slot_count;
275error:
276 if (dir_bootdev)
277 closedir(dir_bootdev);
278 return 0;
279}
280
281unsigned get_current_slot(struct boot_control_module *module)
282{
283 uint32_t num_slots = 0;
Ameya Thakur369d6832016-05-02 16:21:13 -0700284 char bootSlotProp[PROPERTY_VALUE_MAX] = {'\0'};
Ameya Thakurc14fff02016-02-24 11:25:43 -0800285 unsigned i = 0;
286 if (!module) {
287 ALOGE("%s: Invalid argument", __func__);
288 goto error;
289 }
290 num_slots = get_number_slots(module);
291 if (num_slots <= 1) {
292 //Slot 0 is the only slot around.
293 return 0;
294 }
Ameya Thakur369d6832016-05-02 16:21:13 -0700295 property_get(BOOT_SLOT_PROP, bootSlotProp, "N/A");
296 if (!strncmp(bootSlotProp, "N/A", strlen("N/A"))) {
297 ALOGE("%s: Unable to read boot slot property",
298 __func__);
299 goto error;
300 }
Ameya Thakurc14fff02016-02-24 11:25:43 -0800301 //Iterate through a list of partitons named as boot+suffix
302 //and see which one is currently active.
303 for (i = 0; slot_suffix_arr[i] != NULL ; i++) {
Ameya Thakur369d6832016-05-02 16:21:13 -0700304 if (!strncmp(bootSlotProp,
305 slot_suffix_arr[i],
306 strlen(slot_suffix_arr[i])))
307 return i;
Ameya Thakurc14fff02016-02-24 11:25:43 -0800308 }
309error:
310 //The HAL spec requires that we return a number between
311 //0 to num_slots - 1. Since something went wrong here we
312 //are just going to return the default slot.
313 return 0;
314}
315
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700316static int boot_control_check_slot_sanity(struct boot_control_module *module,
317 unsigned slot)
Ameya Thakurcc1b52c2016-05-03 17:57:23 -0700318{
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700319 if (!module)
320 return -1;
321 uint32_t num_slots = get_number_slots(module);
322 if ((num_slots < 1) || (slot > num_slots - 1)) {
323 ALOGE("Invalid slot number");
324 return -1;
Ameya Thakurcc1b52c2016-05-03 17:57:23 -0700325 }
Ameya Thakurcc1b52c2016-05-03 17:57:23 -0700326 return 0;
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700327
Ameya Thakurcc1b52c2016-05-03 17:57:23 -0700328}
329
Ameya Thakurc14fff02016-02-24 11:25:43 -0800330int mark_boot_successful(struct boot_control_module *module)
331{
332 unsigned cur_slot = 0;
333 if (!module) {
334 ALOGE("%s: Invalid argument", __func__);
335 goto error;
336 }
337 cur_slot = get_current_slot(module);
338 if (update_slot_attribute(slot_suffix_arr[cur_slot],
339 ATTR_BOOT_SUCCESSFUL)) {
340 goto error;
341 }
342 return 0;
343error:
344 ALOGE("%s: Failed to mark boot successful", __func__);
345 return -1;
346}
347
348const char *get_suffix(struct boot_control_module *module, unsigned slot)
349{
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700350 if (boot_control_check_slot_sanity(module, slot) != 0)
Ameya Thakurc14fff02016-02-24 11:25:43 -0800351 return NULL;
352 else
353 return slot_suffix_arr[slot];
354}
355
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700356
357//Return a gpt disk structure representing the disk that holds
358//partition.
359static struct gpt_disk* boot_ctl_get_disk_info(char *partition)
Ameya Thakurc14fff02016-02-24 11:25:43 -0800360{
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700361 struct gpt_disk *disk = NULL;
362 if (!partition)
363 return NULL;
364 disk = gpt_disk_alloc();
365 if (!disk) {
366 ALOGE("%s: Failed to alloc disk",
367 __func__);
368 goto error;
369 }
370 if (gpt_disk_get_disk_info(partition, disk)) {
371 ALOGE("failed to get disk info for %s",
372 partition);
373 goto error;
374 }
375 return disk;
376error:
377 if (disk)
378 gpt_disk_free(disk);
379 return NULL;
380}
381
382//The argument here is a vector of partition names(including the slot suffix)
383//that lie on a single disk
384static int boot_ctl_set_active_slot_for_partitions(vector<string> part_list,
385 unsigned slot)
386{
387 char buf[PATH_MAX] = {0};
388 struct gpt_disk *disk = NULL;
Ameya Thakurc14fff02016-02-24 11:25:43 -0800389 char slotA[MAX_GPT_NAME_SIZE + 1] = {0};
390 char slotB[MAX_GPT_NAME_SIZE + 1] = {0};
391 char active_guid[TYPE_GUID_SIZE + 1] = {0};
392 char inactive_guid[TYPE_GUID_SIZE + 1] = {0};
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700393 //Pointer to the partition entry of current 'A' partition
Ameya Thakurc14fff02016-02-24 11:25:43 -0800394 uint8_t *pentryA = NULL;
395 uint8_t *pentryA_bak = NULL;
396 //Pointer to partition entry of current 'B' partition
397 uint8_t *pentryB = NULL;
398 uint8_t *pentryB_bak = NULL;
Ameya Thakurc14fff02016-02-24 11:25:43 -0800399 struct stat st;
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700400 vector<string>::iterator partition_iterator;
Ameya Thakurc14fff02016-02-24 11:25:43 -0800401
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700402 for (partition_iterator = part_list.begin();
403 partition_iterator != part_list.end();
404 partition_iterator++) {
405 //Chop off the slot suffix from the partition name to
406 //make the string easier to work with.
407 string prefix = *partition_iterator;
408 if (prefix.size() < (strlen(AB_SLOT_A_SUFFIX) + 1)) {
409 ALOGE("Invalid partition name: %s", prefix.c_str());
410 goto error;
411 }
412 prefix.resize(prefix.size() - strlen(AB_SLOT_A_SUFFIX));
Ameya Thakurc14fff02016-02-24 11:25:43 -0800413 //Check if A/B versions of this ptn exist
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700414 snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
415 prefix.c_str(),
Ameya Thakurc14fff02016-02-24 11:25:43 -0800416 AB_SLOT_A_SUFFIX);
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700417 if (stat(buf, &st))
418 continue;
419 memset(buf, '\0', sizeof(buf));
420 snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
421 prefix.c_str(),
Ameya Thakurc14fff02016-02-24 11:25:43 -0800422 AB_SLOT_B_SUFFIX);
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700423 if (stat(buf, &st))
424 continue;
425 memset(slotA, 0, sizeof(slotA));
426 memset(slotB, 0, sizeof(slotA));
427 snprintf(slotA, sizeof(slotA) - 1, "%s%s", prefix.c_str(),
428 AB_SLOT_A_SUFFIX);
429 snprintf(slotB, sizeof(slotB) - 1,"%s%s", prefix.c_str(),
430 AB_SLOT_B_SUFFIX);
431 //Get the disk containing the partitions that were passed in.
432 //All partitions passed in must lie on the same disk.
433 if (!disk) {
434 disk = boot_ctl_get_disk_info(slotA);
435 if (!disk)
436 goto error;
437 }
438 //Get partition entry for slot A & B from the primary
439 //and backup tables.
Ameya Thakurc14fff02016-02-24 11:25:43 -0800440 pentryA = gpt_disk_get_pentry(disk, slotA, PRIMARY_GPT);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800441 pentryA_bak = gpt_disk_get_pentry(disk, slotA, SECONDARY_GPT);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800442 pentryB = gpt_disk_get_pentry(disk, slotB, PRIMARY_GPT);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800443 pentryB_bak = gpt_disk_get_pentry(disk, slotB, SECONDARY_GPT);
444 if ( !pentryA || !pentryA_bak || !pentryB || !pentryB_bak) {
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700445 //None of these should be NULL since we have already
446 //checked for A & B versions earlier.
Ameya Thakurc14fff02016-02-24 11:25:43 -0800447 ALOGE("Slot pentries for %s not found.",
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700448 prefix.c_str());
Ameya Thakurc14fff02016-02-24 11:25:43 -0800449 goto error;
450 }
451 memset(active_guid, '\0', sizeof(active_guid));
452 memset(inactive_guid, '\0', sizeof(inactive_guid));
453 if (get_partition_attribute(slotA, ATTR_SLOT_ACTIVE) == 1) {
454 //A is the current active slot
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700455 memcpy((void*)active_guid, (const void*)pentryA,
Ameya Thakurc14fff02016-02-24 11:25:43 -0800456 TYPE_GUID_SIZE);
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700457 memcpy((void*)inactive_guid,(const void*)pentryB,
Ameya Thakurc14fff02016-02-24 11:25:43 -0800458 TYPE_GUID_SIZE);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800459 } else if (get_partition_attribute(slotB,
460 ATTR_SLOT_ACTIVE) == 1) {
461 //B is the current active slot
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700462 memcpy((void*)active_guid, (const void*)pentryB,
Ameya Thakurc14fff02016-02-24 11:25:43 -0800463 TYPE_GUID_SIZE);
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700464 memcpy((void*)inactive_guid, (const void*)pentryA,
Ameya Thakurc14fff02016-02-24 11:25:43 -0800465 TYPE_GUID_SIZE);
466 } else {
Ameya Thakur31d13212017-05-11 13:29:37 -0700467 ALOGE("Both A & B for %s are inactive..Aborting",
468 prefix.c_str());
Ameya Thakurc14fff02016-02-24 11:25:43 -0800469 goto error;
470 }
471 if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
472 strlen(AB_SLOT_A_SUFFIX))){
473 //Mark A as active in primary table
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700474 UPDATE_SLOT(pentryA, active_guid, SLOT_ACTIVE);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800475 //Mark A as active in backup table
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700476 UPDATE_SLOT(pentryA_bak, active_guid, SLOT_ACTIVE);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800477 //Mark B as inactive in primary table
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700478 UPDATE_SLOT(pentryB, inactive_guid, SLOT_INACTIVE);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800479 //Mark B as inactive in backup table
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700480 UPDATE_SLOT(pentryB_bak, inactive_guid, SLOT_INACTIVE);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800481 } else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
482 strlen(AB_SLOT_B_SUFFIX))){
483 //Mark B as active in primary table
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700484 UPDATE_SLOT(pentryB, active_guid, SLOT_ACTIVE);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800485 //Mark B as active in backup table
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700486 UPDATE_SLOT(pentryB_bak, active_guid, SLOT_ACTIVE);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800487 //Mark A as inavtive in primary table
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700488 UPDATE_SLOT(pentryA, inactive_guid, SLOT_INACTIVE);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800489 //Mark A as inactive in backup table
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700490 UPDATE_SLOT(pentryA_bak, inactive_guid, SLOT_INACTIVE);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800491 } else {
492 //Something has gone terribly terribly wrong
493 ALOGE("%s: Unknown slot suffix!", __func__);
494 goto error;
495 }
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700496 if (disk) {
497 if (gpt_disk_update_crc(disk) != 0) {
498 ALOGE("%s: Failed to update gpt_disk crc",
499 __func__);
500 goto error;
501 }
Ameya Thakurc14fff02016-02-24 11:25:43 -0800502 }
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700503 }
504 //write updated content to disk
505 if (disk) {
506 if (gpt_disk_commit(disk)) {
507 ALOGE("Failed to commit disk entry");
Ameya Thakurc14fff02016-02-24 11:25:43 -0800508 goto error;
509 }
510 gpt_disk_free(disk);
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700511 }
512 return 0;
513
514error:
515 if (disk)
516 gpt_disk_free(disk);
517 return -1;
518}
519
520int set_active_boot_slot(struct boot_control_module *module, unsigned slot)
521{
522 map<string, vector<string>> ptn_map;
523 vector<string> ptn_vec;
524 const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
525 uint32_t i;
526 int rc = -1;
527 int is_ufs = gpt_utils_is_ufs_device();
528 map<string, vector<string>>::iterator map_iter;
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700529
530 if (boot_control_check_slot_sanity(module, slot)) {
531 ALOGE("%s: Bad arguments", __func__);
532 goto error;
533 }
534 //The partition list just contains prefixes(without the _a/_b) of the
535 //partitions that support A/B. In order to get the layout we need the
536 //actual names. To do this we append the slot suffix to every member
537 //in the list.
538 for (i = 0; i < ARRAY_SIZE(ptn_list); i++) {
Ameya Thakur31d13212017-05-11 13:29:37 -0700539 //XBL & XBL_CFG are handled differrently for ufs devices so
540 //ignore them
541 if (is_ufs && (!strncmp(ptn_list[i],
542 PTN_XBL,
543 strlen(PTN_XBL))
544 || !strncmp(ptn_list[i],
545 PTN_XBL_CFG,
546 strlen(PTN_XBL_CFG))))
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700547 continue;
548 //The partition list will be the list of _a partitions
549 string cur_ptn = ptn_list[i];
550 cur_ptn.append(AB_SLOT_A_SUFFIX);
551 ptn_vec.push_back(cur_ptn);
552
553 }
554 //The partition map gives us info in the following format:
555 // [path_to_block_device_1]--><partitions on device 1>
556 // [path_to_block_device_2]--><partitions on device 2>
557 // ...
558 // ...
559 // eg:
560 // [/dev/block/sdb]---><system, boot, rpm, tz,....>
561 if (gpt_utils_get_partition_map(ptn_vec, ptn_map)) {
562 ALOGE("%s: Failed to get partition map",
563 __func__);
564 goto error;
565 }
566 for (map_iter = ptn_map.begin(); map_iter != ptn_map.end(); map_iter++){
567 if (map_iter->second.size() < 1)
568 continue;
Ameya Thakur31d13212017-05-11 13:29:37 -0700569 if (boot_ctl_set_active_slot_for_partitions(map_iter->second,
570 slot)) {
571 ALOGE("%s: Failed to set active slot", __func__);
572 goto error;
573 }
Ameya Thakurc14fff02016-02-24 11:25:43 -0800574 }
575 if (is_ufs) {
576 if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
577 strlen(AB_SLOT_A_SUFFIX))){
578 //Set xbl_a as the boot lun
579 rc = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
580 } else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
581 strlen(AB_SLOT_B_SUFFIX))){
582 //Set xbl_b as the boot lun
583 rc = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
584 } else {
585 //Something has gone terribly terribly wrong
586 ALOGE("%s: Unknown slot suffix!", __func__);
587 goto error;
588 }
589 if (rc) {
590 ALOGE("%s: Failed to switch xbl boot partition",
591 __func__);
592 goto error;
593 }
594 }
595 return 0;
596error:
Ameya Thakurc14fff02016-02-24 11:25:43 -0800597 return -1;
598}
599
600int set_slot_as_unbootable(struct boot_control_module *module, unsigned slot)
601{
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700602 if (boot_control_check_slot_sanity(module, slot) != 0) {
603 ALOGE("%s: Argument check failed", __func__);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800604 goto error;
605 }
606 if (update_slot_attribute(slot_suffix_arr[slot],
607 ATTR_UNBOOTABLE)) {
608 goto error;
609 }
610 return 0;
611error:
612 ALOGE("%s: Failed to mark slot unbootable", __func__);
613 return -1;
614}
615
616int is_slot_bootable(struct boot_control_module *module, unsigned slot)
617{
Ameya Thakurc14fff02016-02-24 11:25:43 -0800618 int attr = 0;
619 char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700620
621 if (boot_control_check_slot_sanity(module, slot) != 0) {
622 ALOGE("%s: Argument check failed", __func__);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800623 goto error;
624 }
625 snprintf(bootPartition,
626 sizeof(bootPartition) - 1, "boot%s",
627 slot_suffix_arr[slot]);
628 attr = get_partition_attribute(bootPartition, ATTR_UNBOOTABLE);
629 if (attr >= 0)
630 return !attr;
631error:
632 return -1;
633}
634
635int is_slot_marked_successful(struct boot_control_module *module, unsigned slot)
636{
Ameya Thakurc14fff02016-02-24 11:25:43 -0800637 int attr = 0;
638 char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700639
640 if (boot_control_check_slot_sanity(module, slot) != 0) {
641 ALOGE("%s: Argument check failed", __func__);
Ameya Thakurc14fff02016-02-24 11:25:43 -0800642 goto error;
643 }
644 snprintf(bootPartition,
645 sizeof(bootPartition) - 1,
646 "boot%s", slot_suffix_arr[slot]);
647 attr = get_partition_attribute(bootPartition, ATTR_BOOT_SUCCESSFUL);
648 if (attr >= 0)
649 return attr;
650error:
651 return -1;
652}
653
654static hw_module_methods_t boot_control_module_methods = {
655 .open = NULL,
656};
657
658boot_control_module_t HAL_MODULE_INFO_SYM = {
659 .common = {
660 .tag = HARDWARE_MODULE_TAG,
661 .module_api_version = 1,
662 .hal_api_version = 0,
663 .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
664 .name = "Boot control HAL",
665 .author = "Code Aurora Forum",
666 .methods = &boot_control_module_methods,
667 },
668 .init = boot_control_init,
669 .getNumberSlots = get_number_slots,
670 .getCurrentSlot = get_current_slot,
671 .markBootSuccessful = mark_boot_successful,
672 .setActiveBootSlot = set_active_boot_slot,
673 .setSlotAsUnbootable = set_slot_as_unbootable,
674 .isSlotBootable = is_slot_bootable,
675 .getSuffix = get_suffix,
676 .isSlotMarkedSuccessful = is_slot_marked_successful,
677};
Ameya Thakur2f9e1a02016-06-22 18:25:38 -0700678#ifdef __cplusplus
679}
680#endif