cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mlxbf-bootctl.c (8503B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Mellanox boot control driver
      4 *
      5 * This driver provides a sysfs interface for systems management
      6 * software to manage reset-time actions.
      7 *
      8 * Copyright (C) 2019 Mellanox Technologies
      9 */
     10
     11#include <linux/acpi.h>
     12#include <linux/arm-smccc.h>
     13#include <linux/module.h>
     14#include <linux/platform_device.h>
     15
     16#include "mlxbf-bootctl.h"
     17
     18#define MLXBF_BOOTCTL_SB_SECURE_MASK		0x03
     19#define MLXBF_BOOTCTL_SB_TEST_MASK		0x0c
     20
     21#define MLXBF_SB_KEY_NUM			4
     22
     23/* UUID used to probe ATF service. */
     24static const char *mlxbf_bootctl_svc_uuid_str =
     25	"89c036b4-e7d7-11e6-8797-001aca00bfc4";
     26
     27struct mlxbf_bootctl_name {
     28	u32 value;
     29	const char *name;
     30};
     31
     32static struct mlxbf_bootctl_name boot_names[] = {
     33	{ MLXBF_BOOTCTL_EXTERNAL, "external" },
     34	{ MLXBF_BOOTCTL_EMMC, "emmc" },
     35	{ MLNX_BOOTCTL_SWAP_EMMC, "swap_emmc" },
     36	{ MLXBF_BOOTCTL_EMMC_LEGACY, "emmc_legacy" },
     37	{ MLXBF_BOOTCTL_NONE, "none" },
     38};
     39
     40static const char * const mlxbf_bootctl_lifecycle_states[] = {
     41	[0] = "Production",
     42	[1] = "GA Secured",
     43	[2] = "GA Non-Secured",
     44	[3] = "RMA",
     45};
     46
     47/* ARM SMC call which is atomic and no need for lock. */
     48static int mlxbf_bootctl_smc(unsigned int smc_op, int smc_arg)
     49{
     50	struct arm_smccc_res res;
     51
     52	arm_smccc_smc(smc_op, smc_arg, 0, 0, 0, 0, 0, 0, &res);
     53
     54	return res.a0;
     55}
     56
     57/* Return the action in integer or an error code. */
     58static int mlxbf_bootctl_reset_action_to_val(const char *action)
     59{
     60	int i;
     61
     62	for (i = 0; i < ARRAY_SIZE(boot_names); i++)
     63		if (sysfs_streq(boot_names[i].name, action))
     64			return boot_names[i].value;
     65
     66	return -EINVAL;
     67}
     68
     69/* Return the action in string. */
     70static const char *mlxbf_bootctl_action_to_string(int action)
     71{
     72	int i;
     73
     74	for (i = 0; i < ARRAY_SIZE(boot_names); i++)
     75		if (boot_names[i].value == action)
     76			return boot_names[i].name;
     77
     78	return "invalid action";
     79}
     80
     81static ssize_t post_reset_wdog_show(struct device *dev,
     82				    struct device_attribute *attr, char *buf)
     83{
     84	int ret;
     85
     86	ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_POST_RESET_WDOG, 0);
     87	if (ret < 0)
     88		return ret;
     89
     90	return sprintf(buf, "%d\n", ret);
     91}
     92
     93static ssize_t post_reset_wdog_store(struct device *dev,
     94				     struct device_attribute *attr,
     95				     const char *buf, size_t count)
     96{
     97	unsigned long value;
     98	int ret;
     99
    100	ret = kstrtoul(buf, 10, &value);
    101	if (ret)
    102		return ret;
    103
    104	ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_POST_RESET_WDOG, value);
    105	if (ret < 0)
    106		return ret;
    107
    108	return count;
    109}
    110
    111static ssize_t mlxbf_bootctl_show(int smc_op, char *buf)
    112{
    113	int action;
    114
    115	action = mlxbf_bootctl_smc(smc_op, 0);
    116	if (action < 0)
    117		return action;
    118
    119	return sprintf(buf, "%s\n", mlxbf_bootctl_action_to_string(action));
    120}
    121
    122static int mlxbf_bootctl_store(int smc_op, const char *buf, size_t count)
    123{
    124	int ret, action;
    125
    126	action = mlxbf_bootctl_reset_action_to_val(buf);
    127	if (action < 0)
    128		return action;
    129
    130	ret = mlxbf_bootctl_smc(smc_op, action);
    131	if (ret < 0)
    132		return ret;
    133
    134	return count;
    135}
    136
    137static ssize_t reset_action_show(struct device *dev,
    138				 struct device_attribute *attr, char *buf)
    139{
    140	return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_RESET_ACTION, buf);
    141}
    142
    143static ssize_t reset_action_store(struct device *dev,
    144				  struct device_attribute *attr,
    145				  const char *buf, size_t count)
    146{
    147	return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_RESET_ACTION, buf, count);
    148}
    149
    150static ssize_t second_reset_action_show(struct device *dev,
    151					struct device_attribute *attr,
    152					char *buf)
    153{
    154	return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_SECOND_RESET_ACTION, buf);
    155}
    156
    157static ssize_t second_reset_action_store(struct device *dev,
    158					 struct device_attribute *attr,
    159					 const char *buf, size_t count)
    160{
    161	return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION, buf,
    162				   count);
    163}
    164
    165static ssize_t lifecycle_state_show(struct device *dev,
    166				    struct device_attribute *attr, char *buf)
    167{
    168	int lc_state;
    169
    170	lc_state = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS,
    171				     MLXBF_BOOTCTL_FUSE_STATUS_LIFECYCLE);
    172	if (lc_state < 0)
    173		return lc_state;
    174
    175	lc_state &=
    176		MLXBF_BOOTCTL_SB_TEST_MASK | MLXBF_BOOTCTL_SB_SECURE_MASK;
    177
    178	/*
    179	 * If the test bits are set, we specify that the current state may be
    180	 * due to using the test bits.
    181	 */
    182	if (lc_state & MLXBF_BOOTCTL_SB_TEST_MASK) {
    183		lc_state &= MLXBF_BOOTCTL_SB_SECURE_MASK;
    184
    185		return sprintf(buf, "%s(test)\n",
    186			       mlxbf_bootctl_lifecycle_states[lc_state]);
    187	}
    188
    189	return sprintf(buf, "%s\n", mlxbf_bootctl_lifecycle_states[lc_state]);
    190}
    191
    192static ssize_t secure_boot_fuse_state_show(struct device *dev,
    193					   struct device_attribute *attr,
    194					   char *buf)
    195{
    196	int burnt, valid, key, key_state, buf_len = 0, upper_key_used = 0;
    197	const char *status;
    198
    199	key_state = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS,
    200				      MLXBF_BOOTCTL_FUSE_STATUS_KEYS);
    201	if (key_state < 0)
    202		return key_state;
    203
    204	/*
    205	 * key_state contains the bits for 4 Key versions, loaded from eFuses
    206	 * after a hard reset. Lower 4 bits are a thermometer code indicating
    207	 * key programming has started for key n (0000 = none, 0001 = version 0,
    208	 * 0011 = version 1, 0111 = version 2, 1111 = version 3). Upper 4 bits
    209	 * are a thermometer code indicating key programming has completed for
    210	 * key n (same encodings as the start bits). This allows for detection
    211	 * of an interruption in the programming process which has left the key
    212	 * partially programmed (and thus invalid). The process is to burn the
    213	 * eFuse for the new key start bit, burn the key eFuses, then burn the
    214	 * eFuse for the new key complete bit.
    215	 *
    216	 * For example 0000_0000: no key valid, 0001_0001: key version 0 valid,
    217	 * 0011_0011: key 1 version valid, 0011_0111: key version 2 started
    218	 * programming but did not complete, etc. The most recent key for which
    219	 * both start and complete bit is set is loaded. On soft reset, this
    220	 * register is not modified.
    221	 */
    222	for (key = MLXBF_SB_KEY_NUM - 1; key >= 0; key--) {
    223		burnt = key_state & BIT(key);
    224		valid = key_state & BIT(key + MLXBF_SB_KEY_NUM);
    225
    226		if (burnt && valid)
    227			upper_key_used = 1;
    228
    229		if (upper_key_used) {
    230			if (burnt)
    231				status = valid ? "Used" : "Wasted";
    232			else
    233				status = valid ? "Invalid" : "Skipped";
    234		} else {
    235			if (burnt)
    236				status = valid ? "InUse" : "Incomplete";
    237			else
    238				status = valid ? "Invalid" : "Free";
    239		}
    240		buf_len += sprintf(buf + buf_len, "%d:%s ", key, status);
    241	}
    242	buf_len += sprintf(buf + buf_len, "\n");
    243
    244	return buf_len;
    245}
    246
    247static DEVICE_ATTR_RW(post_reset_wdog);
    248static DEVICE_ATTR_RW(reset_action);
    249static DEVICE_ATTR_RW(second_reset_action);
    250static DEVICE_ATTR_RO(lifecycle_state);
    251static DEVICE_ATTR_RO(secure_boot_fuse_state);
    252
    253static struct attribute *mlxbf_bootctl_attrs[] = {
    254	&dev_attr_post_reset_wdog.attr,
    255	&dev_attr_reset_action.attr,
    256	&dev_attr_second_reset_action.attr,
    257	&dev_attr_lifecycle_state.attr,
    258	&dev_attr_secure_boot_fuse_state.attr,
    259	NULL
    260};
    261
    262ATTRIBUTE_GROUPS(mlxbf_bootctl);
    263
    264static const struct acpi_device_id mlxbf_bootctl_acpi_ids[] = {
    265	{"MLNXBF04", 0},
    266	{}
    267};
    268
    269MODULE_DEVICE_TABLE(acpi, mlxbf_bootctl_acpi_ids);
    270
    271static bool mlxbf_bootctl_guid_match(const guid_t *guid,
    272				     const struct arm_smccc_res *res)
    273{
    274	guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16,
    275			      res->a2, res->a2 >> 8, res->a2 >> 16,
    276			      res->a2 >> 24, res->a3, res->a3 >> 8,
    277			      res->a3 >> 16, res->a3 >> 24);
    278
    279	return guid_equal(guid, &id);
    280}
    281
    282static int mlxbf_bootctl_probe(struct platform_device *pdev)
    283{
    284	struct arm_smccc_res res = { 0 };
    285	guid_t guid;
    286	int ret;
    287
    288	/* Ensure we have the UUID we expect for this service. */
    289	arm_smccc_smc(MLXBF_BOOTCTL_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res);
    290	guid_parse(mlxbf_bootctl_svc_uuid_str, &guid);
    291	if (!mlxbf_bootctl_guid_match(&guid, &res))
    292		return -ENODEV;
    293
    294	/*
    295	 * When watchdog is used, it sets boot mode to MLXBF_BOOTCTL_SWAP_EMMC
    296	 * in case of boot failures. However it doesn't clear the state if there
    297	 * is no failure. Restore the default boot mode here to avoid any
    298	 * unnecessary boot partition swapping.
    299	 */
    300	ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_RESET_ACTION,
    301				MLXBF_BOOTCTL_EMMC);
    302	if (ret < 0)
    303		dev_warn(&pdev->dev, "Unable to reset the EMMC boot mode\n");
    304
    305	return 0;
    306}
    307
    308static struct platform_driver mlxbf_bootctl_driver = {
    309	.probe = mlxbf_bootctl_probe,
    310	.driver = {
    311		.name = "mlxbf-bootctl",
    312		.dev_groups = mlxbf_bootctl_groups,
    313		.acpi_match_table = mlxbf_bootctl_acpi_ids,
    314	}
    315};
    316
    317module_platform_driver(mlxbf_bootctl_driver);
    318
    319MODULE_DESCRIPTION("Mellanox boot control driver");
    320MODULE_LICENSE("GPL v2");
    321MODULE_AUTHOR("Mellanox Technologies");