diff options
author | Emilio López <emilio.lopez@collabora.co.uk> | 2015-09-21 15:38:22 +0200 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2015-10-08 00:05:53 +0200 |
commit | 18800fc7a04e7df8a345e7ef4fc3064368276f83 (patch) | |
tree | e70b6cb9f8db8bc4e94e022d3273984219893151 /drivers/platform | |
parent | sysfs: Support is_visible() on binary attributes (diff) | |
download | linux-18800fc7a04e7df8a345e7ef4fc3064368276f83.tar.xz linux-18800fc7a04e7df8a345e7ef4fc3064368276f83.zip |
platform/chrome: Support reading/writing the vboot context
Some EC implementations include a small nvram space used to store
verified boot context data. This patch offers a way to expose this
data to userspace.
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Signed-off-by: Emilio López <emilio.lopez@collabora.co.uk>
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/chrome/Makefile | 3 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_ec_dev.c | 1 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_ec_vbc.c | 137 |
3 files changed, 140 insertions, 1 deletions
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 4a11b010f5d8..bc498bda8211 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -1,7 +1,8 @@ obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o -cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o cros_ec_lightbar.o +cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \ + cros_ec_lightbar.o cros_ec_vbc.o obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c index 2f4099820480..d45cd254ed1c 100644 --- a/drivers/platform/chrome/cros_ec_dev.c +++ b/drivers/platform/chrome/cros_ec_dev.c @@ -32,6 +32,7 @@ static int ec_major; static const struct attribute_group *cros_ec_groups[] = { &cros_ec_attr_group, &cros_ec_lightbar_attr_group, + &cros_ec_vbc_attr_group, NULL, }; diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c new file mode 100644 index 000000000000..564a0d08c8bf --- /dev/null +++ b/drivers/platform/chrome/cros_ec_vbc.c @@ -0,0 +1,137 @@ +/* + * cros_ec_vbc - Expose the vboot context nvram to userspace + * + * Copyright (C) 2015 Collabora Ltd. + * + * based on vendor driver, + * + * Copyright (C) 2012 The Chromium OS Authors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/mfd/cros_ec.h> +#include <linux/mfd/cros_ec_commands.h> +#include <linux/slab.h> + +static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *att, char *buf, + loff_t pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, + class_dev); + struct cros_ec_device *ecdev = ec->ec_dev; + struct ec_params_vbnvcontext *params; + struct cros_ec_command *msg; + int err; + const size_t para_sz = sizeof(params->op); + const size_t resp_sz = sizeof(struct ec_response_vbnvcontext); + const size_t payload = max(para_sz, resp_sz); + + msg = kmalloc(sizeof(*msg) + payload, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + /* NB: we only kmalloc()ated enough space for the op field */ + params = (struct ec_params_vbnvcontext *)msg->data; + params->op = EC_VBNV_CONTEXT_OP_READ; + + msg->version = EC_VER_VBNV_CONTEXT; + msg->command = EC_CMD_VBNV_CONTEXT; + msg->outsize = para_sz; + msg->insize = resp_sz; + + err = cros_ec_cmd_xfer(ecdev, msg); + if (err < 0) { + dev_err(dev, "Error sending read request: %d\n", err); + kfree(msg); + return err; + } + + memcpy(buf, msg->data, resp_sz); + + kfree(msg); + return resp_sz; +} + +static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, + class_dev); + struct cros_ec_device *ecdev = ec->ec_dev; + struct ec_params_vbnvcontext *params; + struct cros_ec_command *msg; + int err; + const size_t para_sz = sizeof(*params); + const size_t data_sz = sizeof(params->block); + + /* Only write full values */ + if (count != data_sz) + return -EINVAL; + + msg = kmalloc(sizeof(*msg) + para_sz, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + params = (struct ec_params_vbnvcontext *)msg->data; + params->op = EC_VBNV_CONTEXT_OP_WRITE; + memcpy(params->block, buf, data_sz); + + msg->version = EC_VER_VBNV_CONTEXT; + msg->command = EC_CMD_VBNV_CONTEXT; + msg->outsize = para_sz; + msg->insize = 0; + + err = cros_ec_cmd_xfer(ecdev, msg); + if (err < 0) { + dev_err(dev, "Error sending write request: %d\n", err); + kfree(msg); + return err; + } + + kfree(msg); + return data_sz; +} + +static umode_t cros_ec_vbc_is_visible(struct kobject *kobj, + struct bin_attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, + class_dev); + struct device_node *np = ec->ec_dev->dev->of_node; + + if (IS_ENABLED(CONFIG_OF) && np) { + if (of_property_read_bool(np, "google,has-vbc-nvram")) + return a->attr.mode; + } + + return 0; +} + +static BIN_ATTR_RW(vboot_context, 16); + +static struct bin_attribute *cros_ec_vbc_bin_attrs[] = { + &bin_attr_vboot_context, + NULL +}; + +struct attribute_group cros_ec_vbc_attr_group = { + .name = "vbc", + .bin_attrs = cros_ec_vbc_bin_attrs, + .is_bin_visible = cros_ec_vbc_is_visible, +}; |