brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · f3bc0d4 Raw
512 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Turris Mox rWTM firmware driver4 *5 * Copyright (C) 2019, 2024 Marek Behún <kabel@kernel.org>6 */7 8#include <crypto/sha2.h>9#include <linux/align.h>10#include <linux/armada-37xx-rwtm-mailbox.h>11#include <linux/completion.h>12#include <linux/container_of.h>13#include <linux/debugfs.h>14#include <linux/device.h>15#include <linux/dma-mapping.h>16#include <linux/err.h>17#include <linux/fs.h>18#include <linux/hw_random.h>19#include <linux/if_ether.h>20#include <linux/kobject.h>21#include <linux/mailbox_client.h>22#include <linux/minmax.h>23#include <linux/module.h>24#include <linux/mutex.h>25#include <linux/platform_device.h>26#include <linux/sizes.h>27#include <linux/sysfs.h>28#include <linux/types.h>29 30#define DRIVER_NAME		"turris-mox-rwtm"31 32#define RWTM_DMA_BUFFER_SIZE	SZ_4K33 34/*35 * The macros and constants below come from Turris Mox's rWTM firmware code.36 * This firmware is open source and it's sources can be found at37 * https://gitlab.labs.nic.cz/turris/mox-boot-builder/tree/master/wtmi.38 */39 40#define MOX_ECC_NUMBER_WORDS	1741#define MOX_ECC_NUMBER_LEN	(MOX_ECC_NUMBER_WORDS * sizeof(u32))42 43#define MOX_ECC_SIGNATURE_WORDS	(2 * MOX_ECC_NUMBER_WORDS)44 45#define MBOX_STS_SUCCESS	(0 << 30)46#define MBOX_STS_FAIL		(1 << 30)47#define MBOX_STS_BADCMD		(2 << 30)48#define MBOX_STS_ERROR(s)	((s) & (3 << 30))49#define MBOX_STS_VALUE(s)	(((s) >> 10) & 0xfffff)50#define MBOX_STS_CMD(s)		((s) & 0x3ff)51 52enum mbox_cmd {53	MBOX_CMD_GET_RANDOM	= 1,54	MBOX_CMD_BOARD_INFO	= 2,55	MBOX_CMD_ECDSA_PUB_KEY	= 3,56	MBOX_CMD_HASH		= 4,57	MBOX_CMD_SIGN		= 5,58	MBOX_CMD_VERIFY		= 6,59 60	MBOX_CMD_OTP_READ	= 7,61	MBOX_CMD_OTP_WRITE	= 8,62};63 64struct mox_rwtm {65	struct mbox_client mbox_client;66	struct mbox_chan *mbox;67	struct hwrng hwrng;68 69	struct armada_37xx_rwtm_rx_msg reply;70 71	void *buf;72	dma_addr_t buf_phys;73 74	struct mutex busy;75	struct completion cmd_done;76 77	/* board information */78	bool has_board_info;79	u64 serial_number;80	int board_version, ram_size;81	u8 mac_address1[ETH_ALEN], mac_address2[ETH_ALEN];82 83	/* public key burned in eFuse */84	bool has_pubkey;85	u8 pubkey[135];86 87#ifdef CONFIG_DEBUG_FS88	/*89	 * Signature process. This is currently done via debugfs, because it90	 * does not conform to the sysfs standard "one file per attribute".91	 * It should be rewritten via crypto API once akcipher API is available92	 * from userspace.93	 */94	u32 last_sig[MOX_ECC_SIGNATURE_WORDS];95	bool last_sig_done;96#endif97};98 99static inline struct device *rwtm_dev(struct mox_rwtm *rwtm)100{101	return rwtm->mbox_client.dev;102}103 104#define MOX_ATTR_RO(name, format, cat)				\105static ssize_t							\106name##_show(struct device *dev, struct device_attribute *a,	\107	    char *buf)						\108{								\109	struct mox_rwtm *rwtm = dev_get_drvdata(dev);		\110	if (!rwtm->has_##cat)					\111		return -ENODATA;				\112	return sysfs_emit(buf, format, rwtm->name);		\113}								\114static DEVICE_ATTR_RO(name)115 116MOX_ATTR_RO(serial_number, "%016llX\n", board_info);117MOX_ATTR_RO(board_version, "%i\n", board_info);118MOX_ATTR_RO(ram_size, "%i\n", board_info);119MOX_ATTR_RO(mac_address1, "%pM\n", board_info);120MOX_ATTR_RO(mac_address2, "%pM\n", board_info);121MOX_ATTR_RO(pubkey, "%s\n", pubkey);122 123static struct attribute *turris_mox_rwtm_attrs[] = {124	&dev_attr_serial_number.attr,125	&dev_attr_board_version.attr,126	&dev_attr_ram_size.attr,127	&dev_attr_mac_address1.attr,128	&dev_attr_mac_address2.attr,129	&dev_attr_pubkey.attr,130	NULL131};132ATTRIBUTE_GROUPS(turris_mox_rwtm);133 134static int mox_get_status(enum mbox_cmd cmd, u32 retval)135{136	if (MBOX_STS_CMD(retval) != cmd)137		return -EIO;138	else if (MBOX_STS_ERROR(retval) == MBOX_STS_FAIL)139		return -(int)MBOX_STS_VALUE(retval);140	else if (MBOX_STS_ERROR(retval) == MBOX_STS_BADCMD)141		return -EOPNOTSUPP;142	else if (MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS)143		return -EIO;144	else145		return MBOX_STS_VALUE(retval);146}147 148static void mox_rwtm_rx_callback(struct mbox_client *cl, void *data)149{150	struct mox_rwtm *rwtm = dev_get_drvdata(cl->dev);151	struct armada_37xx_rwtm_rx_msg *msg = data;152 153	if (completion_done(&rwtm->cmd_done))154		return;155 156	rwtm->reply = *msg;157	complete(&rwtm->cmd_done);158}159 160static int mox_rwtm_exec(struct mox_rwtm *rwtm, enum mbox_cmd cmd,161			 struct armada_37xx_rwtm_tx_msg *msg,162			 bool interruptible)163{164	struct armada_37xx_rwtm_tx_msg _msg = {};165	int ret;166 167	if (!msg)168		msg = &_msg;169 170	msg->command = cmd;171 172	ret = mbox_send_message(rwtm->mbox, msg);173	if (ret < 0)174		return ret;175 176	if (interruptible) {177		ret = wait_for_completion_interruptible(&rwtm->cmd_done);178		if (ret < 0)179			return ret;180	} else {181		if (!wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2))182			return -ETIMEDOUT;183	}184 185	return mox_get_status(cmd, rwtm->reply.retval);186}187 188static void reply_to_mac_addr(u8 *mac, u32 t1, u32 t2)189{190	mac[0] = t1 >> 8;191	mac[1] = t1;192	mac[2] = t2 >> 24;193	mac[3] = t2 >> 16;194	mac[4] = t2 >> 8;195	mac[5] = t2;196}197 198static int mox_get_board_info(struct mox_rwtm *rwtm)199{200	struct device *dev = rwtm_dev(rwtm);201	struct armada_37xx_rwtm_rx_msg *reply = &rwtm->reply;202	int ret;203 204	ret = mox_rwtm_exec(rwtm, MBOX_CMD_BOARD_INFO, NULL, false);205	if (ret == -ENODATA) {206		dev_warn(dev,207			 "Board does not have manufacturing information burned!\n");208	} else if (ret == -EOPNOTSUPP) {209		dev_notice(dev,210			   "Firmware does not support the BOARD_INFO command\n");211	} else if (ret < 0) {212		return ret;213	} else {214		rwtm->serial_number = reply->status[1];215		rwtm->serial_number <<= 32;216		rwtm->serial_number |= reply->status[0];217		rwtm->board_version = reply->status[2];218		rwtm->ram_size = reply->status[3];219		reply_to_mac_addr(rwtm->mac_address1, reply->status[4],220				  reply->status[5]);221		reply_to_mac_addr(rwtm->mac_address2, reply->status[6],222				  reply->status[7]);223		rwtm->has_board_info = true;224 225		pr_info("Turris Mox serial number %016llX\n",226			rwtm->serial_number);227		pr_info("           board version %i\n", rwtm->board_version);228		pr_info("           burned RAM size %i MiB\n", rwtm->ram_size);229	}230 231	ret = mox_rwtm_exec(rwtm, MBOX_CMD_ECDSA_PUB_KEY, NULL, false);232	if (ret == -ENODATA) {233		dev_warn(dev, "Board has no public key burned!\n");234	} else if (ret == -EOPNOTSUPP) {235		dev_notice(dev,236			   "Firmware does not support the ECDSA_PUB_KEY command\n");237	} else if (ret < 0) {238		return ret;239	} else {240		u32 *s = reply->status;241 242		rwtm->has_pubkey = true;243		sprintf(rwtm->pubkey,244			"%06x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",245			ret, s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],246			s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]);247	}248 249	return 0;250}251 252static int check_get_random_support(struct mox_rwtm *rwtm)253{254	struct armada_37xx_rwtm_tx_msg msg = {255		.args = { 1, rwtm->buf_phys, 4 },256	};257 258	return mox_rwtm_exec(rwtm, MBOX_CMD_GET_RANDOM, &msg, false);259}260 261static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)262{263	struct mox_rwtm *rwtm = container_of(rng, struct mox_rwtm, hwrng);264	struct armada_37xx_rwtm_tx_msg msg = {265		.args = { 1, rwtm->buf_phys, ALIGN(max, 4) },266	};267	int ret;268 269	max = min(max, RWTM_DMA_BUFFER_SIZE);270 271	if (!wait) {272		if (!mutex_trylock(&rwtm->busy))273			return -EBUSY;274	} else {275		mutex_lock(&rwtm->busy);276	}277 278	ret = mox_rwtm_exec(rwtm, MBOX_CMD_GET_RANDOM, &msg, true);279	if (ret < 0)280		goto unlock_mutex;281 282	memcpy(data, rwtm->buf, max);283	ret = max;284 285unlock_mutex:286	mutex_unlock(&rwtm->busy);287	return ret;288}289 290#ifdef CONFIG_DEBUG_FS291static int rwtm_debug_open(struct inode *inode, struct file *file)292{293	file->private_data = inode->i_private;294 295	return nonseekable_open(inode, file);296}297 298static ssize_t do_sign_read(struct file *file, char __user *buf, size_t len,299			    loff_t *ppos)300{301	struct mox_rwtm *rwtm = file->private_data;302	ssize_t ret;303 304	/* only allow one read, of whole signature, from position 0 */305	if (*ppos != 0)306		return 0;307 308	if (len < sizeof(rwtm->last_sig))309		return -EINVAL;310 311	if (!rwtm->last_sig_done)312		return -ENODATA;313 314	ret = simple_read_from_buffer(buf, len, ppos, rwtm->last_sig,315				      sizeof(rwtm->last_sig));316	rwtm->last_sig_done = false;317 318	return ret;319}320 321static ssize_t do_sign_write(struct file *file, const char __user *buf,322			     size_t len, loff_t *ppos)323{324	struct mox_rwtm *rwtm = file->private_data;325	struct armada_37xx_rwtm_tx_msg msg;326	loff_t dummy = 0;327	ssize_t ret;328 329	if (len != SHA512_DIGEST_SIZE)330		return -EINVAL;331 332	/* if last result is not zero user has not read that information yet */333	if (rwtm->last_sig_done)334		return -EBUSY;335 336	if (!mutex_trylock(&rwtm->busy))337		return -EBUSY;338 339	/*340	 * Here we have to send:341	 *   1. Address of the input to sign.342	 *      The input is an array of 17 32-bit words, the first (most343	 *      significat) is 0, the rest 16 words are copied from the SHA-512344	 *      hash given by the user and converted from BE to LE.345	 *   2. Address of the buffer where ECDSA signature value R shall be346	 *      stored by the rWTM firmware.347	 *   3. Address of the buffer where ECDSA signature value S shall be348	 *      stored by the rWTM firmware.349	 */350	memset(rwtm->buf, 0, sizeof(u32));351	ret = simple_write_to_buffer(rwtm->buf + sizeof(u32),352				     SHA512_DIGEST_SIZE, &dummy, buf, len);353	if (ret < 0)354		goto unlock_mutex;355	be32_to_cpu_array(rwtm->buf, rwtm->buf, MOX_ECC_NUMBER_WORDS);356 357	msg.args[0] = 1;358	msg.args[1] = rwtm->buf_phys;359	msg.args[2] = rwtm->buf_phys + MOX_ECC_NUMBER_LEN;360	msg.args[3] = rwtm->buf_phys + 2 * MOX_ECC_NUMBER_LEN;361 362	ret = mox_rwtm_exec(rwtm, MBOX_CMD_SIGN, &msg, true);363	if (ret < 0)364		goto unlock_mutex;365 366	/*367	 * Here we read the R and S values of the ECDSA signature368	 * computed by the rWTM firmware and convert their words from369	 * LE to BE.370	 */371	memcpy(rwtm->last_sig, rwtm->buf + MOX_ECC_NUMBER_LEN,372	       sizeof(rwtm->last_sig));373	cpu_to_be32_array(rwtm->last_sig, rwtm->last_sig,374			  MOX_ECC_SIGNATURE_WORDS);375	rwtm->last_sig_done = true;376 377	mutex_unlock(&rwtm->busy);378	return len;379unlock_mutex:380	mutex_unlock(&rwtm->busy);381	return ret;382}383 384static const struct file_operations do_sign_fops = {385	.owner	= THIS_MODULE,386	.open	= rwtm_debug_open,387	.read	= do_sign_read,388	.write	= do_sign_write,389};390 391static void rwtm_debugfs_release(void *root)392{393	debugfs_remove_recursive(root);394}395 396static void rwtm_register_debugfs(struct mox_rwtm *rwtm)397{398	struct dentry *root;399 400	root = debugfs_create_dir("turris-mox-rwtm", NULL);401 402	debugfs_create_file_unsafe("do_sign", 0600, root, rwtm, &do_sign_fops);403 404	devm_add_action_or_reset(rwtm_dev(rwtm), rwtm_debugfs_release, root);405}406#else407static inline void rwtm_register_debugfs(struct mox_rwtm *rwtm)408{409}410#endif411 412static void rwtm_devm_mbox_release(void *mbox)413{414	mbox_free_channel(mbox);415}416 417static void rwtm_firmware_symlink_drop(void *parent)418{419	sysfs_remove_link(parent, DRIVER_NAME);420}421 422static int turris_mox_rwtm_probe(struct platform_device *pdev)423{424	struct mox_rwtm *rwtm;425	struct device *dev = &pdev->dev;426	int ret;427 428	rwtm = devm_kzalloc(dev, sizeof(*rwtm), GFP_KERNEL);429	if (!rwtm)430		return -ENOMEM;431 432	rwtm->buf = dmam_alloc_coherent(dev, RWTM_DMA_BUFFER_SIZE,433					&rwtm->buf_phys, GFP_KERNEL);434	if (!rwtm->buf)435		return -ENOMEM;436 437	platform_set_drvdata(pdev, rwtm);438 439	ret = devm_mutex_init(dev, &rwtm->busy);440	if (ret)441		return ret;442 443	init_completion(&rwtm->cmd_done);444 445	rwtm->mbox_client.dev = dev;446	rwtm->mbox_client.rx_callback = mox_rwtm_rx_callback;447 448	rwtm->mbox = mbox_request_channel(&rwtm->mbox_client, 0);449	if (IS_ERR(rwtm->mbox))450		return dev_err_probe(dev, PTR_ERR(rwtm->mbox),451				     "Cannot request mailbox channel!\n");452 453	ret = devm_add_action_or_reset(dev, rwtm_devm_mbox_release, rwtm->mbox);454	if (ret)455		return ret;456 457	ret = mox_get_board_info(rwtm);458	if (ret < 0)459		dev_warn(dev, "Cannot read board information: %i\n", ret);460 461	ret = check_get_random_support(rwtm);462	if (ret < 0) {463		dev_notice(dev,464			   "Firmware does not support the GET_RANDOM command\n");465		return ret;466	}467 468	rwtm->hwrng.name = DRIVER_NAME "_hwrng";469	rwtm->hwrng.read = mox_hwrng_read;470 471	ret = devm_hwrng_register(dev, &rwtm->hwrng);472	if (ret)473		return dev_err_probe(dev, ret, "Cannot register HWRNG!\n");474 475	rwtm_register_debugfs(rwtm);476 477	dev_info(dev, "HWRNG successfully registered\n");478 479	/*480	 * For sysfs ABI compatibility, create symlink481	 * /sys/firmware/turris-mox-rwtm to this device's sysfs directory.482	 */483	ret = sysfs_create_link(firmware_kobj, &dev->kobj, DRIVER_NAME);484	if (!ret)485		devm_add_action_or_reset(dev, rwtm_firmware_symlink_drop,486					 firmware_kobj);487 488	return 0;489}490 491static const struct of_device_id turris_mox_rwtm_match[] = {492	{ .compatible = "cznic,turris-mox-rwtm", },493	{ .compatible = "marvell,armada-3700-rwtm-firmware", },494	{ },495};496 497MODULE_DEVICE_TABLE(of, turris_mox_rwtm_match);498 499static struct platform_driver turris_mox_rwtm_driver = {500	.probe	= turris_mox_rwtm_probe,501	.driver	= {502		.name		= DRIVER_NAME,503		.of_match_table	= turris_mox_rwtm_match,504		.dev_groups	= turris_mox_rwtm_groups,505	},506};507module_platform_driver(turris_mox_rwtm_driver);508 509MODULE_LICENSE("GPL v2");510MODULE_DESCRIPTION("Turris Mox rWTM firmware driver");511MODULE_AUTHOR("Marek Behun <kabel@kernel.org>");512