120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi/*
220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * Copyright (C) 2015 Intel Corporation
320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi *
420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * Licensed under the Apache License, Version 2.0 (the "License");
520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * you may not use this file except in compliance with the License.
620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * You may obtain a copy of the License at
720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi *
820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi *    http://www.apache.org/licenses/LICENSE-2.0
920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi *
1020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * Unless required by applicable law or agreed to in writing, software
1120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * distributed under the License is distributed on an "AS IS" BASIS,
1220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * See the License for the specific language governing permissions and
1420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * limitations under the License.
1520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi */
1620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
1720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi/*
1820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * Implementation of boot_control HAL as specified by google in
1920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * Brillo Development Platform Specification. Please refer to the
2020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi * said document for more details.
2120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi */
2220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
2320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
2420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#include <errno.h>
2520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#include <fcntl.h>
2620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#include <unistd.h>
2720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#include <stdio.h>
2820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#include <stdlib.h>
2920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#include <string.h>
3020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#include <hardware/hardware.h>
3120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#include <hardware/boot_control.h>
3220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
3320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#include "bootctrl.h"
3420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
3520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#define BOOTCTRL_METADATA_FILE  "/dev/block/by-name/misc"
3620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#define SLOT_SUFFIX_STR "androidboot.slot_suffix="
3720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
3820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi#define COMMAND_LINE_SIZE 2048
3920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
4020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmistatic int bootctrl_read_metadata(boot_ctrl_t *bctrl)
4120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
4220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    int fd, err;
4320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ssize_t sz, size;
4420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    char *buf = (char *)bctrl;
4520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
4620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    fd = open(BOOTCTRL_METADATA_FILE, O_RDONLY);
4720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (fd < 0) {
4820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        err = errno;
4920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "Error opening metadata file: %s\n", strerror(errno));
5020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return -err;
5120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
5220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (lseek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0) {
5320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        err = errno;
5420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "Error seeking to metadata offset: %s\n", strerror(errno));
5520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        close(fd);
5620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return -err;
5720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
5820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    size = sizeof(boot_ctrl_t);
5920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    do {
6020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        sz = read(fd, buf, size);
6120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        if (sz == 0) {
6220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            break;
6320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        } else if (sz < 0) {
6420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            if (errno == EINTR) {
6520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi                continue;
6620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            }
6720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            err = -errno;
6820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            fprintf(stderr, "Error reading metadata file\n");
6920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            close(fd);
7020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            return err;
7120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        }
7220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        size -= sz;
7320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        buf += sz;
7420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    } while(size > 0);
7520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
7620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    close(fd);
7720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
7820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    /* Check if the data is correct */
7920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (bctrl->magic != BOOTCTRL_MAGIC) {
8020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "metadata is not initialised or corrupted.\n");
8120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return -EIO;
8220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
8320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return 0;
8420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
8520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
8620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmistatic int bootctrl_write_metadata(boot_ctrl_t *bctrl)
8720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
8820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    int fd, err;
8920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ssize_t sz, size;
9020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    char *buf = (char *)bctrl;
9120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
9220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    fd = open(BOOTCTRL_METADATA_FILE, O_RDWR);
9320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (fd < 0) {
9420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        err = errno;
9520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "Error opening metadata file: %s\n", strerror(errno));
9620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return -err;
9720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
9820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
9920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (lseek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0) {
10020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        err = errno;
10120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "Error seeking to metadata offset: %s\n", strerror(errno));
10220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        close(fd);
10320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return -err;
10420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
10520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    size = sizeof(boot_ctrl_t);
10620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    do {
10720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        sz = write(fd, buf, size);
10820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        if (sz == 0) {
10920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            break;
11020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        } else if (sz < 0) {
11120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            if (errno == EINTR) {
11220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi                continue;
11320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            }
11420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            err = -errno;
11520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            fprintf(stderr, "Error Writing metadata file\n");
11620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            close(fd);
11720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            return err;
11820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        }
11920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        size -= sz;
12020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        buf += sz;
12120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    } while(size > 0);
12220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
12320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    close(fd);
12420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return 0;
12520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
12620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
12720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmivoid bootctrl_init(boot_control_module_t *module __unused)
12820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
12920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    /* Nothing to init */
13020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
13120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
13220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmiunsigned bootctrl_get_number_slots(boot_control_module_t *module __unused)
13320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
13420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    /* This is A/B system, so it will be always 2. */
13520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return 2;
13620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
13720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
13820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmiint bootctrl_get_active_slot()
13920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
14020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    int fd, err, slot;
14120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ssize_t size = COMMAND_LINE_SIZE, sz;
14220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    off_t off;
14320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    char *buf, *ptr;
14420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    char *str;
14520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
14620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    fd = open("/proc/cmdline", O_RDONLY);
14720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (fd < 0) {
14820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        err = -errno;
14920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "error reading commandline\n");
15020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return err;
15120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
15220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ptr = buf = malloc(size);
15320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (!buf) {
15420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        err = -errno;
15520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "Error allocating memory\n");
15620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        close(fd);
15720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return err;
15820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
15920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    do {
16020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        sz = read(fd, buf, size);
16120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        if (sz == 0) {
16220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            break;
16320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        } else if (sz < 0) {
16420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            if (errno == EINTR) {
16520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi                continue;
16620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            }
16720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            err = -errno;
16820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            fprintf(stderr, "Error reading file\n");
16920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            free(ptr);
17020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            close(fd);
17120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi            return err;
17220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        }
17320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        size -= sz;
17420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        buf += sz;
17520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    } while(size > 0);
17620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    str = strstr((char *)ptr, SLOT_SUFFIX_STR);
17720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (!str) {
17820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        err = -EIO;
17920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "cannot find %s in kernel commandline.\n", SLOT_SUFFIX_STR);
18020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        free(ptr);
18120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        close(fd);
18220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return err;
18320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
18420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    str += sizeof(SLOT_SUFFIX_STR);
18520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slot = (*str == 'a') ? 0 : 1;
18620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    free(ptr);
18720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    close(fd);
18820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
18920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return slot;
19020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
19120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
19220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmiunsigned bootctrl_get_current_slot(boot_control_module_t *module __unused)
19320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
19420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    int ret;
19520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    boot_ctrl_t metadata;
19620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
19720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ret = bootctrl_read_metadata(&metadata);
19820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (ret < 0) {
19920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi	/* anything larger than 2 will be considered as error. */
20020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return (unsigned)ret;
20120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
20220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
20320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return bootctrl_get_active_slot();
20420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
20520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
20620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmiint bootctrl_mark_boot_successful(boot_control_module_t *module __unused)
20720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
20820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    int ret, slot;
20920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    boot_ctrl_t metadata;
21020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slot_metadata_t *slotp;
21120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
21220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ret = bootctrl_read_metadata(&metadata);
21320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (ret < 0) {
21420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return ret;
21520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
21620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
21720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    /* In markBootSuccessful(), set Successful Boot to 1 and
21820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi     * Tries Remaining to 0.
21920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi     */
22020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slot = bootctrl_get_active_slot();
22120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (slot < 0) {
22220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return slot;
22320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
22420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp = &metadata.slot_info[slot];
22520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp->successful_boot = 1;
22620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp->tries_remaining = 0;
22720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
22820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return bootctrl_write_metadata(&metadata);
22920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
23020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
23120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmiint bootctrl_set_active_boot_slot(boot_control_module_t *module __unused,
23220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    unsigned slot)
23320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
23420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    int ret, slot2;
23520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    boot_ctrl_t metadata;
23620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slot_metadata_t *slotp;
23720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
23820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (slot >= 2) {
23920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "Wrong Slot value %u\n", slot);
24020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return -EINVAL;
24120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
24220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ret = bootctrl_read_metadata(&metadata);
24320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (ret < 0) {
24420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return ret;
24520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
24620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
24720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    /* In setActiveBootSlot(), set Priority to 15, Tries Remaining to 7 and
24820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi     * Successful Boot to 0. Before doing this, lower priorities of other slots
24920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi     * so they are all less than 15 in a way that preserves existing priority
25020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi     * ordering. Calling setActiveBootSlot() on a slot that already has
25120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi     * Successful Boot set to 1 MUST not fail.
25220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi     */
25320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp = &metadata.slot_info[slot];
25420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp->successful_boot = 0;
25520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp->priority = 15;
25620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp->tries_remaining = 7;
25720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
25820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slot2 = (slot == 0) ? 1 : 0;
25920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp = &metadata.slot_info[slot2];
26020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (slotp->priority >= 15) {
26120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        slotp->priority = 14;
26220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
26320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ret = bootctrl_write_metadata(&metadata);
26420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (ret < 0) {
26520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return ret;
26620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
26720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
26820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return 0;
26920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
27020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
27120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmiint bootctrl_set_slot_as_unbootable(boot_control_module_t *module __unused,
27220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    unsigned slot)
27320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
27420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    int ret;
27520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    boot_ctrl_t metadata;
27620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slot_metadata_t *slotp;
27720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
27820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (slot >= 2) {
27920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "Wrong Slot value %u\n", slot);
28020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return -EINVAL;
28120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
28220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ret = bootctrl_read_metadata(&metadata);
28320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (ret < 0) {
28420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return ret;
28520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
28620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
28720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    /* In setSlotAsUnbootable(), set Priority, Tries Remaining and
28820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi     * Successful Boot to 0.
28920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi     */
29020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp = &metadata.slot_info[slot];
29120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp->successful_boot = 0;
29220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp->priority = 0;
29320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    slotp->tries_remaining = 0;
29420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ret = bootctrl_write_metadata(&metadata);
29520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (ret < 0) {
29620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return ret;
29720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
29820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
29920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return 0;
30020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
30120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
30220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmiint bootctrl_is_slot_bootable(boot_control_module_t *module __unused,
30320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi	unsigned slot)
30420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
30520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    int ret;
30620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    boot_ctrl_t metadata;
30720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
30820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (slot >= 2) {
30920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        fprintf(stderr, "Wrong Slot value %u\n", slot);
31020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return -EINVAL;
31120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
31220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    ret = bootctrl_read_metadata(&metadata);
31320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (ret < 0) {
31420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return ret;
31520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    }
31620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
31720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return (metadata.slot_info[slot].priority != 0);
31820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
31920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
32020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmiconst char *bootctrl_get_suffix(boot_control_module_t *module __unused,
32120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    unsigned slot)
32220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
32320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    static const char* suffix[2] = {BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B};
32420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    if (slot >= 2)
32520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        return NULL;
32620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return suffix[slot];
32720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
32820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
32920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmistatic int bootctrl_open(const hw_module_t *module, const char *id __unused,
33020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    hw_device_t **device __unused)
33120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi{
33220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    /* Nothing to do currently */
33320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    return 0;
33420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi}
33520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
33620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmistatic struct hw_module_methods_t bootctrl_methods = {
33720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .open  = bootctrl_open,
33820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi};
33920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
34020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi/* Boot Control Module implementation */
34120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmiboot_control_module_t HAL_MODULE_INFO_SYM = {
34220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .common = {
34320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        .tag                 = HARDWARE_MODULE_TAG,
34420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        .module_api_version  = BOOT_CONTROL_MODULE_API_VERSION_0_1,
34520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        .hal_api_version     = HARDWARE_HAL_API_VERSION,
34620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        .id                  = BOOT_CONTROL_HARDWARE_MODULE_ID,
34720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        .name                = "boot_control HAL",
34820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        .author              = "Intel Corporation",
34920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi        .methods             = &bootctrl_methods,
35020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    },
35120b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .init                 = bootctrl_init,
35220b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .getNumberSlots       = bootctrl_get_number_slots,
35320b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .getCurrentSlot       = bootctrl_get_current_slot,
35420b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .markBootSuccessful   = bootctrl_mark_boot_successful,
35520b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .setActiveBootSlot    = bootctrl_set_active_boot_slot,
35620b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .setSlotAsUnbootable  = bootctrl_set_slot_as_unbootable,
35720b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .isSlotBootable       = bootctrl_is_slot_bootable,
35820b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi    .getSuffix            = bootctrl_get_suffix,
35920b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi};
36020b554f16dc6ee081d0952272d1f130e957d1600Manish Regmi
361