blob: 877a40b28419f2441f808e471532594747fe89ad [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <fs_mgr.h>
#include <hardware/hardware.h>
#include <hardware/boot_control.h>
#include <cutils/properties.h>
#include "bootinfo.h"
void boot_control_init(struct boot_control_module *module __unused)
{
return;
}
unsigned get_number_slots(struct boot_control_module *module __unused)
{
return MAX_SLOTS;
}
unsigned get_current_slot(struct boot_control_module *module __unused)
{
char propbuf[PROPERTY_VALUE_MAX];
const char* suffix[MAX_SLOTS] = {"_a", "_b"};
int i;
property_get("ro.boot.slot_suffix", propbuf, "");
if (propbuf[0] != '\0') {
for (i = 0; i < MAX_SLOTS; i++) {
if (strncmp(propbuf, suffix[i], 2) == 0)
return i;
}
if (i == MAX_SLOTS)
fprintf(stderr, "WARNING: androidboot.slot_suffix is invalid\n");
} else {
fprintf(stderr, "WARNING: androidboot.slot_suffix is NULL\n");
}
return 0;
}
int mark_boot_successful(struct boot_control_module *module __unused)
{
BrilloBootInfo info;
unsigned current_slot;
int i;
if (!boot_info_load(&info)) {
fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
boot_info_reset(&info);
} else {
if (!boot_info_validate(&info)) {
fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
boot_info_reset(&info);
}
}
current_slot = get_current_slot(module);
info.slot_info[current_slot].boot_successful = true;
info.slot_info[current_slot].tries_remaining = 0;
if (!boot_info_save(&info)) {
fprintf(stderr, "WARNING: Error saving boot-info.\n");
return -errno;
}
return 0;
}
int set_active_boot_slot(struct boot_control_module *module __unused,
unsigned slot)
{
BrilloBootInfo info;
unsigned other_slot;
int i;
if (slot >= MAX_SLOTS)
return -EINVAL;
if (!boot_info_load(&info)) {
fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
boot_info_reset(&info);
} else {
if (!boot_info_validate(&info)) {
fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
boot_info_reset(&info);
}
}
other_slot = 1 - slot;
if (info.slot_info[other_slot].priority == 15)
info.slot_info[other_slot].priority = 14;
info.slot_info[slot].bootable = true;
info.slot_info[slot].priority = 15;
info.slot_info[slot].tries_remaining = 7;
info.slot_info[slot].boot_successful = false;
if (!boot_info_save(&info)) {
fprintf(stderr, "WARNING: Error saving boot-info.\n");
return -errno;
}
return 0;
}
int set_slot_as_unbootable(struct boot_control_module *module __unused,
unsigned slot)
{
BrilloBootInfo info;
if (slot >= MAX_SLOTS)
return -EINVAL;
if (!boot_info_load(&info)) {
fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
boot_info_reset(&info);
} else {
if (!boot_info_validate(&info)) {
fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
boot_info_reset(&info);
}
}
info.slot_info[slot].bootable = false;
info.slot_info[slot].priority = 0;
info.slot_info[slot].tries_remaining = 0;
info.slot_info[slot].boot_successful = false;
if (!boot_info_save(&info)) {
fprintf(stderr, "WARNING: Error saving boot-info.\n");
return -errno;
}
return 0;
}
int is_slot_bootable(struct boot_control_module *module __unused,
unsigned slot)
{
BrilloBootInfo info;
if (slot >= MAX_SLOTS)
return -EINVAL;
if (!boot_info_load(&info)) {
fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
boot_info_reset(&info);
} else {
if (!boot_info_validate(&info)) {
fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
boot_info_reset(&info);
}
}
return info.slot_info[slot].bootable;
}
const char* get_suffix(struct boot_control_module *module __unused,
unsigned slot)
{
static const char* suffix[MAX_SLOTS] = {"_a", "_b"};
if (slot >= MAX_SLOTS)
return NULL;
return suffix[slot];
}
int is_slot_marked_successful(struct boot_control_module *module __unused,
unsigned slot)
{
BrilloBootInfo info;
if (slot >= MAX_SLOTS)
return -EINVAL;
if (!boot_info_load(&info)) {
fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
boot_info_reset(&info);
} else {
if (!boot_info_validate(&info)) {
fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
boot_info_reset(&info);
}
}
return info.slot_info[slot].boot_successful;
}
static struct hw_module_methods_t boot_control_module_methods = {
.open = NULL,
};
struct boot_control_module 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 = "Marvell Boot Control HAL",
.author = "Marvell SEEDS",
.methods = &boot_control_module_methods,
},
.init = boot_control_init,
.getNumberSlots = get_number_slots,
.getCurrentSlot = get_current_slot,
.markBootSuccessful = mark_boot_successful,
.setActiveBootSlot = set_active_boot_slot,
.setSlotAsUnbootable = set_slot_as_unbootable,
.isSlotBootable = is_slot_bootable,
.getSuffix = get_suffix,
.isSlotMarkedSuccessful = is_slot_marked_successful,
};