blob: 8f0e94822ff18cad960d5e70304fa831b201c071 [file] [log] [blame]
/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein is
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
* the prior written permission of MediaTek inc. and/or its licensors, any
* reproduction, modification, use or disclosure of MediaTek Software, and
* information contained herein, in whole or in part, shall be strictly
* prohibited.
*
* SPDX-License-Identifier: MediaTekProprietary
* MediaTek Inc. (C) 2016. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek
* Software") have been modified by MediaTek Inc. All revisions are subject to
* any receiver's applicable license agreements with MediaTek Inc.
*/
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hardware/hardware.h>
#include <hardware/boot_control.h>
//#include <android-base/logging.h>
//#include <cutils/properties.h>
#define LOG_TAG "bootctrlHAL"
//#include <log/log.h>
//#include <utils/Log.h>
#include "bootctrl.h"
#if !defined(ARCH_X86)
#include "sd_misc.h"
#endif
//#include <fstab/fstab.h>
#include "avb/libavb/avb_util.h"
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
extern "C"{
#include "mtk_device_wrap.h"
}
#endif
#define FSTAB_SUPPORT 0
// Debug for update_engine_sideload
#define ALOGE printf
#define ALOGI printf
static struct fstab* fstab = NULL;
static char *blk_dev_path = "/dev/disk/by-partlabel/misc";
#if FSTAB_SUPPORT
static void free_fstab(void)
{
fs_mgr_free_fstab(fstab);
}
static char *get_device_path(const char *mount_point)
{
struct fstab_rec *rec = NULL;
char *source = NULL;
rec = fs_mgr_get_entry_for_mount_point(fstab, mount_point);
if (!rec) {
ALOGE("%s failed to get entry for %s \n", __func__ , mount_point);
return NULL;
}
source = strdup(rec->blk_device);
return source;
}
#endif
static int bootctrl_read_metadata(AvbABData *bctrl)
{
int fd, err;
ssize_t sz, size;
char *buf = (char *)bctrl;
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
fd = mtk_device_wrap_open(blk_dev_path, O_RDONLY);
#else
fd = open(blk_dev_path, O_RDONLY);
#endif
if (fd < 0) {
err = errno;
ALOGE("%s Error opening metadata file: %s\n", __func__ ,strerror(errno));
return -err;
}
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
if (mtk_device_wrap_seek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0)
#else
if (lseek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0)
#endif
{
err = errno;
ALOGE("%s Error seeking to metadata offset: %s\n", __func__ ,strerror(errno));
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
mtk_device_wrap_close(fd);
#else
close(fd);
#endif
return -err;
}
size = sizeof(AvbABData);
do {
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
sz = mtk_device_wrap_read(fd, buf, size);
#else
sz = read(fd, buf, size);
#endif
if (sz == 0) {
break;
} else if (sz < 0) {
if (errno == EINTR) {
continue;
}
err = -errno;
ALOGE("%s Error reading metadata file\n", __func__);
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
mtk_device_wrap_close(fd);
#else
close(fd);
#endif
return err;
}
size -= sz;
buf += sz;
} while(size > 0);
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
mtk_device_wrap_close(fd);
#else
close(fd);
#endif
/* Check bootctrl magic number */
if (memcmp(bctrl->magic , AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
ALOGE("metadata is not initialised or corrupted %s.\n", bctrl->magic);
return -EIO;
}
return 0;
}
static int bootctrl_write_metadata(AvbABData *bctrl)
{
int fd, err;
ssize_t sz, size;
char *buf = (char *)bctrl;
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
char *tmpbuf = NULL;
#endif
ALOGI("Enter in bootctrl: bootctrl_write_metadata \n");
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
fd = mtk_device_wrap_open(blk_dev_path, O_RDWR);
#else
fd = open(blk_dev_path, O_RDWR);
#endif
if (fd < 0) {
err = errno;
ALOGE("%s Error opening metadata file: %s\n", __func__,strerror(errno));
return -err;
}
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
if (mtk_device_wrap_seek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0)
#else
if (lseek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0)
#endif
{
err = errno;
ALOGE("%s Error seeking to metadata offset: %s\n", __func__ ,strerror(errno));
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
mtk_device_wrap_close(fd);
#else
close(fd);
#endif
return -err;
}
bctrl->crc32 = avb_htobe32(
avb_crc32((const uint8_t*)bctrl, sizeof(AvbABData) - sizeof(uint32_t)));
size = sizeof(AvbABData);
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
tmpbuf = (char *)malloc(sizeof(char)* OFFSETOF_SLOT_SUFFIX);
if (tmpbuf == NULL){
ALOGE("Error Writing metadata: malloc tmpbuf failed\n");
mtk_device_wrap_close(fd);
err = -errno;
return err;
}
#endif
do {
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
memset(tmpbuf, 0xFF, OFFSETOF_SLOT_SUFFIX);
if (mtk_device_wrap_seek(fd, 0, SEEK_SET) < 0){
err = errno;
ALOGE("%s Error seeking to metadata offset: %s\n", __func__ ,strerror(errno));
mtk_device_wrap_close(fd);
free(tmpbuf);
return -err;
}
if (mtk_device_wrap_write_force(fd, tmpbuf, OFFSETOF_SLOT_SUFFIX) < 0){
err = -errno;
ALOGE("%s Error Writing metadata file\n",__func__);
mtk_device_wrap_close(fd);
free(tmpbuf);
return err;
}
memcpy(tmpbuf, bctrl, size);
sz = mtk_device_wrap_write_force(fd, tmpbuf, sizeof(char)* OFFSETOF_SLOT_SUFFIX);
#else
sz = write(fd, buf, size);
#endif
if (sz == 0) {
break;
} else if (sz < 0) {
if (errno == EINTR) {
continue;
}
err = -errno;
ALOGE("%s Error Writing metadata file\n",__func__);
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
mtk_device_wrap_close(fd);
free(tmpbuf);
#else
close(fd);
#endif
return err;
}
size -= sz;
buf += sz;
} while(size > 0);
#if MTK_BOOTDEV_TYPE == BOOTDEV_TYPE_NAND
free(tmpbuf);
mtk_device_wrap_close(fd);
#else
close(fd);
#endif
return 0;
}
void bootctrl_init(boot_control_module_t *module )
{
ALOGI("boot control HAL init");
if(blk_dev_path == NULL) {
#if FSTAB_SUPPORT
/* Initial read fstab */
fstab = fs_mgr_read_fstab_default();
if (!fstab) {
ALOGE("failed to read default fstab");
}
blk_dev_path = get_device_path("/misc");
/* Free fstab */
free_fstab();
#endif
}
ALOGI("%s misc blk device path = %s\n", __func__ ,blk_dev_path);
}
unsigned bootctrl_get_number_slots(boot_control_module_t *module )
{
return 2;
}
int bootctrl_get_active_slot()
{
int fd, err, slot;
ssize_t size = COMMAND_LINE_SIZE, sz;
char *buf, *ptr;
char *str;
fd = open(COMMAND_LINE_PATH, O_RDONLY);
if (fd < 0) {
err = -errno;
ALOGE("%s error reading commandline\n", __func__);
return err;
}
ptr = buf = (char *)malloc(size);
if (!buf) {
err = -errno;
ALOGE("%s Error allocating memory\n", __func__);
close(fd);
return err;
}
do {
sz = read(fd, buf, size);
if (sz == 0) {
break;
} else if (sz < 0) {
if (errno == EINTR) {
continue;
}
err = -errno;
ALOGE("%s Error reading file\n",__func__);
free(ptr);
close(fd);
return err;
}
size -= sz;
buf += sz;
} while(size > 0);
str = strstr((char *)ptr, SLOT_SUFFIX_STR);
if (!str) {
err = -EIO;
ALOGE("%s cannot find %s in kernel commandline.\n", __func__ , SLOT_SUFFIX_STR);
free(ptr);
close(fd);
return err;
}
str += strlen(SLOT_SUFFIX_STR) + 1;
//str += strlen(SLOT_SUFFIX_STR);
slot = (*str == 'a') ? 0 : 1;
free(ptr);
close(fd);
return slot;
}
uint32_t bootctrl_get_current_slot(boot_control_module_t *module )
{
ALOGI("boot control bootctrl_get_current_slot\n");
uint32_t slot = 0;
slot = bootctrl_get_active_slot();
ALOGI("bootctrl_get_current_slot %d\n", slot);
return slot;
}
int bootctrl_mark_boot_successful(boot_control_module_t *module )
{
ALOGI("boot control bootctrl_mark_boot_successful\n");
int ret;
int slot = 0;
AvbABData metadata;
AvbABSlotData *slotp;
ret = bootctrl_read_metadata(&metadata);
if (ret < 0) {
return ret;
}
slot = bootctrl_get_active_slot();
if (slot < 0) {
ALOGE("bootctrl_mark_boot_successful fail , slot = \n");
return slot;
}
slotp = &metadata.slots[slot];
slotp->successful_boot = 1;
slotp->tries_remaining = 0;
return bootctrl_write_metadata(&metadata);
}
int bootctrl_set_active_boot_slot(boot_control_module_t *module ,
unsigned slot)
{
ALOGI("boot control bootctrl_set_active_boot_slot , slot is %d\n", slot);
int ret, slot2;
AvbABData metadata;
AvbABSlotData *slotp;
if (slot >= 2) {
ALOGE("%s Wrong Slot value %u\n", __func__ , slot);
return -EINVAL;
}
ret = bootctrl_read_metadata(&metadata);
if (ret < 0) {
return ret;
}
/* Set highest priority and reset retry count */
slotp = &metadata.slots[slot];
slotp->successful_boot = 0;
slotp->priority = AVB_AB_MAX_PRIORITY;
slotp->tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
/* Ensure other slot doesn't have as high a priority. */
slot2 = (slot == 0) ? 1 : 0;
slotp = &metadata.slots[slot2];
if(slotp->priority == AVB_AB_MAX_PRIORITY)
slotp->priority = AVB_AB_MAX_PRIORITY - 1;
ret = bootctrl_write_metadata(&metadata);
if (ret < 0) {
return ret;
}
return 0;
}
int bootctrl_set_slot_as_unbootable(boot_control_module_t *module ,
unsigned slot)
{
ALOGI("boot control bootctrl_set_slot_as_unbootable\n");
int ret;
AvbABData metadata;
AvbABSlotData *slotp;
if (slot >= 2) {
ALOGE("%s Wrong Slot value %u\n", __func__ , slot);
return -EINVAL;
}
ret = bootctrl_read_metadata(&metadata);
if (ret < 0) {
return ret;
}
/* Set zero to priority ,successful_boot and tries_remaining */
slotp = &metadata.slots[slot];
slotp->successful_boot = 0;
slotp->priority = 0;
slotp->tries_remaining = 0;
ret = bootctrl_write_metadata(&metadata);
if (ret < 0) {
return ret;
}
return 0;
}
int bootctrl_is_slot_bootable(boot_control_module_t *module ,
unsigned slot)
{
ALOGI("boot control bootctrl_is_slot_bootable\n");
int ret;
AvbABData metadata;
/* slot 0 is A , slot 1 is B */
if (slot >= 2) {
ALOGE("%s Wrong slot value %u\n", __func__,slot);
return -EINVAL;
}
ret = bootctrl_read_metadata(&metadata);
if (ret < 0) {
return ret;
}
return (metadata.slots[slot].priority != 0);
}
int bootctrl_get_bootup_status(boot_control_module_t *module ,
unsigned slot)
{
ALOGI("bootctrl bootctrl_get_bootup_status\n");
int ret = -1;
AvbABSlotData *slotp;
AvbABData metadata;
if(slot >= 2) {
ALOGE("%s Wrong slot value %u\n", __func__,slot);
return -1;
}
ret = bootctrl_read_metadata(&metadata);
if (ret < 0) {
return ret;
}
slotp = &metadata.slots[slot];
ALOGI("bootctrl bootctrl_get_bootup_status = %d\n", slotp->successful_boot);
return slotp->successful_boot;
}
const char *bootctrl_get_suffix(boot_control_module_t *module ,
unsigned slot)
{
ALOGI("boot control bootctrl_get_suffix %d\n",slot);
static const char* suffix[2] = {BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B};
if (slot >= 2)
return NULL;
return suffix[slot];
}
static struct hw_module_methods_t bootctrl_methods = {
.open = NULL,
};
/* Boot Control Module implementation */
boot_control_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = BOOT_CONTROL_HARDWARE_MODULE_ID,
.name = "boot_control HAL",
.author = "Mediatek Corporation",
.methods = &bootctrl_methods,
},
.init = bootctrl_init,
.getNumberSlots = bootctrl_get_number_slots,
.getCurrentSlot = bootctrl_get_current_slot,
.markBootSuccessful = bootctrl_mark_boot_successful,
.setActiveBootSlot = bootctrl_set_active_boot_slot,
.setSlotAsUnbootable = bootctrl_set_slot_as_unbootable,
.isSlotBootable = bootctrl_is_slot_bootable,
.getSuffix = bootctrl_get_suffix,
.isSlotMarkedSuccessful = bootctrl_get_bootup_status,
};