blob: a483f8e59702185794903929404ce6ecccd7d285 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Implementation of verified-boot flags for Chromium OS
*
* Copyright 2018 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#define LOG_CATEGORY UCLASS_CROS_VBOOT_FLAG
#include <common.h>
#include <dm.h>
#include <init.h>
#include <log.h>
#include <cros/vboot_flag.h>
#include <dm/device-internal.h>
/* Names for all the flag we know about */
static const char *const flag_name[] = {
[VBOOT_FLAG_WRITE_PROTECT] = "write-protect",
[VBOOT_FLAG_DEVELOPER] = "developer",
[VBOOT_FLAG_LID_OPEN] = "lid-open",
[VBOOT_FLAG_POWER_BUTTON] = "power-button",
[VBOOT_FLAG_EC_IN_RW] = "ec-in-rw",
[VBOOT_FLAG_OPROM_LOADED] = "oprom-loaded",
[VBOOT_FLAG_RECOVERY] = "recovery",
[VBOOT_FLAG_WIPEOUT] = "wipeout",
};
const char *vboot_flag_name(enum vboot_flag_t flag)
{
return flag_name[flag];
}
int vboot_flag_read(struct udevice *dev)
{
struct vboot_flag_ops *ops = vboot_flag_get_ops(dev);
if (!ops->read)
return -ENOSYS;
return ops->read(dev);
}
int vboot_flag_read_walk_prev(enum vboot_flag_t flag, int *prevp,
struct udevice **devp)
{
struct vboot_flag_state *priv;
struct udevice *dev;
struct uclass *uc;
int ret;
if (devp)
*devp = NULL;
if (prevp)
*prevp = -1;
ret = uclass_get(UCLASS_CROS_VBOOT_FLAG, &uc);
if (ret)
return log_msg_ret("uc", ret);
priv = uclass_get_priv(uc);
uclass_foreach_dev(dev, uc) {
struct vboot_flag_uc_priv *uc_priv;
ret = device_probe(dev);
if (ret) {
log_warning("Device '%s' failed to probe (err=%d)\n",
dev->name, ret);
continue;
}
uc_priv = dev_get_uclass_priv(dev);
if (uc_priv->flag != flag)
continue;
/* Skip this flag if it is only for the primary bootloader */
if (!ll_boot_init() && uc_priv->primary_only)
continue;
ret = vboot_flag_read(dev);
if (ret == -ENOENT) {
continue;
} else if (ret < 0) {
log_warning("%s: Failed to read\n", dev->name);
break;
}
if (prevp)
*prevp = priv->value[flag];
if (devp)
*devp = dev;
priv->value[flag] = ret;
return ret;
}
/* No devices provided the flag */
return -ENOENT;
}
int vboot_flag_read_walk(enum vboot_flag_t flag)
{
return vboot_flag_read_walk_prev(flag, NULL, NULL);
}
enum vboot_flag_t vboot_flag_find(const char *name)
{
int i;
for (i = 0; i < VBOOT_FLAG_COUNT; i++) {
if (!strcmp(name, flag_name[i]))
break;
}
if (i == VBOOT_FLAG_COUNT) {
log_warning("Unrecognised flag name '%s'\n", name);
return -EINVAL;
}
return (enum vboot_flag_t)i;
}
static int vboot_flag_pre_probe(struct udevice *dev)
{
struct vboot_flag_uc_priv *uc_priv = dev_get_uclass_priv(dev);
const char *name;
int ret;
name = dev_read_string(dev, "google,name");
if (!name)
name = dev->name;
ret = vboot_flag_find(name);
if (ret < 0)
return ret;
uc_priv->flag = ret;
uc_priv->primary_only = dev_read_bool(dev, "primary-only");
return 0;
}
static int vboot_flag_init(struct uclass *uc)
{
struct vboot_flag_state *uc_priv = uclass_get_priv(uc);
int i;
for (i = 0; i < VBOOT_FLAG_COUNT; i++)
uc_priv->value[i] = -1;
return 0;
}
UCLASS_DRIVER(vboot_flag) = {
.id = UCLASS_CROS_VBOOT_FLAG,
.name = "vboot_flag",
.init = vboot_flag_init,
.pre_probe = vboot_flag_pre_probe,
.priv_auto = sizeof(struct vboot_flag_state),
.per_device_auto = sizeof(struct vboot_flag_uc_priv),
};