1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Turris Mox rWTM firmware driver
4  *
5  * Copyright (C) 2019 Marek Behun <marek.behun@nic.cz>
6  */
7 
8 #include <linux/armada-37xx-rwtm-mailbox.h>
9 #include <linux/completion.h>
10 #include <linux/dma-mapping.h>
11 #include <linux/hw_random.h>
12 #include <linux/mailbox_client.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 
19 #define DRIVER_NAME		"turris-mox-rwtm"
20 
21 /*
22  * The macros and constants below come from Turris Mox's rWTM firmware code.
23  * This firmware is open source and it's sources can be found at
24  * https://gitlab.labs.nic.cz/turris/mox-boot-builder/tree/master/wtmi.
25  */
26 
27 #define MBOX_STS_SUCCESS	(0 << 30)
28 #define MBOX_STS_FAIL		(1 << 30)
29 #define MBOX_STS_BADCMD		(2 << 30)
30 #define MBOX_STS_ERROR(s)	((s) & (3 << 30))
31 #define MBOX_STS_VALUE(s)	(((s) >> 10) & 0xfffff)
32 #define MBOX_STS_CMD(s)		((s) & 0x3ff)
33 
34 enum mbox_cmd {
35 	MBOX_CMD_GET_RANDOM	= 1,
36 	MBOX_CMD_BOARD_INFO	= 2,
37 	MBOX_CMD_ECDSA_PUB_KEY	= 3,
38 	MBOX_CMD_HASH		= 4,
39 	MBOX_CMD_SIGN		= 5,
40 	MBOX_CMD_VERIFY		= 6,
41 
42 	MBOX_CMD_OTP_READ	= 7,
43 	MBOX_CMD_OTP_WRITE	= 8,
44 };
45 
46 struct mox_kobject;
47 
48 struct mox_rwtm {
49 	struct device *dev;
50 	struct mbox_client mbox_client;
51 	struct mbox_chan *mbox;
52 	struct mox_kobject *kobj;
53 	struct hwrng hwrng;
54 
55 	struct armada_37xx_rwtm_rx_msg reply;
56 
57 	void *buf;
58 	dma_addr_t buf_phys;
59 
60 	struct mutex busy;
61 	struct completion cmd_done;
62 
63 	/* board information */
64 	int has_board_info;
65 	u64 serial_number;
66 	int board_version, ram_size;
67 	u8 mac_address1[6], mac_address2[6];
68 
69 	/* public key burned in eFuse */
70 	int has_pubkey;
71 	u8 pubkey[135];
72 };
73 
74 struct mox_kobject {
75 	struct kobject kobj;
76 	struct mox_rwtm *rwtm;
77 };
78 
79 static inline struct kobject *rwtm_to_kobj(struct mox_rwtm *rwtm)
80 {
81 	return &rwtm->kobj->kobj;
82 }
83 
84 static inline struct mox_rwtm *to_rwtm(struct kobject *kobj)
85 {
86 	return container_of(kobj, struct mox_kobject, kobj)->rwtm;
87 }
88 
89 static void mox_kobj_release(struct kobject *kobj)
90 {
91 	kfree(to_rwtm(kobj)->kobj);
92 }
93 
94 static struct kobj_type mox_kobj_ktype = {
95 	.release	= mox_kobj_release,
96 	.sysfs_ops	= &kobj_sysfs_ops,
97 };
98 
99 static int mox_kobj_create(struct mox_rwtm *rwtm)
100 {
101 	rwtm->kobj = kzalloc(sizeof(*rwtm->kobj), GFP_KERNEL);
102 	if (!rwtm->kobj)
103 		return -ENOMEM;
104 
105 	kobject_init(rwtm_to_kobj(rwtm), &mox_kobj_ktype);
106 	if (kobject_add(rwtm_to_kobj(rwtm), firmware_kobj, "turris-mox-rwtm")) {
107 		kobject_put(rwtm_to_kobj(rwtm));
108 		return -ENXIO;
109 	}
110 
111 	rwtm->kobj->rwtm = rwtm;
112 
113 	return 0;
114 }
115 
116 #define MOX_ATTR_RO(name, format, cat)				\
117 static ssize_t							\
118 name##_show(struct kobject *kobj, struct kobj_attribute *a,	\
119 	    char *buf)						\
120 {								\
121 	struct mox_rwtm *rwtm = to_rwtm(kobj);	\
122 	if (!rwtm->has_##cat)					\
123 		return -ENODATA;				\
124 	return sprintf(buf, format, rwtm->name);		\
125 }								\
126 static struct kobj_attribute mox_attr_##name = __ATTR_RO(name)
127 
128 MOX_ATTR_RO(serial_number, "%016llX\n", board_info);
129 MOX_ATTR_RO(board_version, "%i\n", board_info);
130 MOX_ATTR_RO(ram_size, "%i\n", board_info);
131 MOX_ATTR_RO(mac_address1, "%pM\n", board_info);
132 MOX_ATTR_RO(mac_address2, "%pM\n", board_info);
133 MOX_ATTR_RO(pubkey, "%s\n", pubkey);
134 
135 static int mox_get_status(enum mbox_cmd cmd, u32 retval)
136 {
137 	if (MBOX_STS_CMD(retval) != cmd ||
138 	    MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS)
139 		return -EIO;
140 	else if (MBOX_STS_ERROR(retval) == MBOX_STS_FAIL)
141 		return -(int)MBOX_STS_VALUE(retval);
142 	else
143 		return MBOX_STS_VALUE(retval);
144 }
145 
146 static const struct attribute *mox_rwtm_attrs[] = {
147 	&mox_attr_serial_number.attr,
148 	&mox_attr_board_version.attr,
149 	&mox_attr_ram_size.attr,
150 	&mox_attr_mac_address1.attr,
151 	&mox_attr_mac_address2.attr,
152 	&mox_attr_pubkey.attr,
153 	NULL
154 };
155 
156 static void mox_rwtm_rx_callback(struct mbox_client *cl, void *data)
157 {
158 	struct mox_rwtm *rwtm = dev_get_drvdata(cl->dev);
159 	struct armada_37xx_rwtm_rx_msg *msg = data;
160 
161 	rwtm->reply = *msg;
162 	complete(&rwtm->cmd_done);
163 }
164 
165 static void reply_to_mac_addr(u8 *mac, u32 t1, u32 t2)
166 {
167 	mac[0] = t1 >> 8;
168 	mac[1] = t1;
169 	mac[2] = t2 >> 24;
170 	mac[3] = t2 >> 16;
171 	mac[4] = t2 >> 8;
172 	mac[5] = t2;
173 }
174 
175 static int mox_get_board_info(struct mox_rwtm *rwtm)
176 {
177 	struct armada_37xx_rwtm_tx_msg msg;
178 	struct armada_37xx_rwtm_rx_msg *reply = &rwtm->reply;
179 	int ret;
180 
181 	msg.command = MBOX_CMD_BOARD_INFO;
182 	ret = mbox_send_message(rwtm->mbox, &msg);
183 	if (ret < 0)
184 		return ret;
185 
186 	ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2);
187 	if (ret < 0)
188 		return ret;
189 
190 	ret = mox_get_status(MBOX_CMD_BOARD_INFO, reply->retval);
191 	if (ret < 0 && ret != -ENODATA) {
192 		return ret;
193 	} else if (ret == -ENODATA) {
194 		dev_warn(rwtm->dev,
195 			 "Board does not have manufacturing information burned!\n");
196 	} else {
197 		rwtm->serial_number = reply->status[1];
198 		rwtm->serial_number <<= 32;
199 		rwtm->serial_number |= reply->status[0];
200 		rwtm->board_version = reply->status[2];
201 		rwtm->ram_size = reply->status[3];
202 		reply_to_mac_addr(rwtm->mac_address1, reply->status[4],
203 				  reply->status[5]);
204 		reply_to_mac_addr(rwtm->mac_address2, reply->status[6],
205 				  reply->status[7]);
206 		rwtm->has_board_info = 1;
207 
208 		pr_info("Turris Mox serial number %016llX\n",
209 			rwtm->serial_number);
210 		pr_info("           board version %i\n", rwtm->board_version);
211 		pr_info("           burned RAM size %i MiB\n", rwtm->ram_size);
212 	}
213 
214 	msg.command = MBOX_CMD_ECDSA_PUB_KEY;
215 	ret = mbox_send_message(rwtm->mbox, &msg);
216 	if (ret < 0)
217 		return ret;
218 
219 	ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2);
220 	if (ret < 0)
221 		return ret;
222 
223 	ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval);
224 	if (ret < 0 && ret != -ENODATA) {
225 		return ret;
226 	} else if (ret == -ENODATA) {
227 		dev_warn(rwtm->dev, "Board has no public key burned!\n");
228 	} else {
229 		u32 *s = reply->status;
230 
231 		rwtm->has_pubkey = 1;
232 		sprintf(rwtm->pubkey,
233 			"%06x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
234 			ret, s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],
235 			s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]);
236 	}
237 
238 	return 0;
239 }
240 
241 static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
242 {
243 	struct mox_rwtm *rwtm = (struct mox_rwtm *) rng->priv;
244 	struct armada_37xx_rwtm_tx_msg msg;
245 	int ret;
246 
247 	if (max > 4096)
248 		max = 4096;
249 
250 	msg.command = MBOX_CMD_GET_RANDOM;
251 	msg.args[0] = 1;
252 	msg.args[1] = rwtm->buf_phys;
253 	msg.args[2] = (max + 3) & ~3;
254 
255 	if (!wait) {
256 		if (!mutex_trylock(&rwtm->busy))
257 			return -EBUSY;
258 	} else {
259 		mutex_lock(&rwtm->busy);
260 	}
261 
262 	ret = mbox_send_message(rwtm->mbox, &msg);
263 	if (ret < 0)
264 		goto unlock_mutex;
265 
266 	ret = wait_for_completion_interruptible(&rwtm->cmd_done);
267 	if (ret < 0)
268 		goto unlock_mutex;
269 
270 	ret = mox_get_status(MBOX_CMD_GET_RANDOM, rwtm->reply.retval);
271 	if (ret < 0)
272 		goto unlock_mutex;
273 
274 	memcpy(data, rwtm->buf, max);
275 	ret = max;
276 
277 unlock_mutex:
278 	mutex_unlock(&rwtm->busy);
279 	return ret;
280 }
281 
282 static int turris_mox_rwtm_probe(struct platform_device *pdev)
283 {
284 	struct mox_rwtm *rwtm;
285 	struct device *dev = &pdev->dev;
286 	int ret;
287 
288 	rwtm = devm_kzalloc(dev, sizeof(*rwtm), GFP_KERNEL);
289 	if (!rwtm)
290 		return -ENOMEM;
291 
292 	rwtm->dev = dev;
293 	rwtm->buf = dmam_alloc_coherent(dev, PAGE_SIZE, &rwtm->buf_phys,
294 					GFP_KERNEL);
295 	if (!rwtm->buf)
296 		return -ENOMEM;
297 
298 	ret = mox_kobj_create(rwtm);
299 	if (ret < 0) {
300 		dev_err(dev, "Cannot create turris-mox-rwtm kobject!\n");
301 		return ret;
302 	}
303 
304 	ret = sysfs_create_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
305 	if (ret < 0) {
306 		dev_err(dev, "Cannot create sysfs files!\n");
307 		goto put_kobj;
308 	}
309 
310 	platform_set_drvdata(pdev, rwtm);
311 
312 	mutex_init(&rwtm->busy);
313 
314 	rwtm->mbox_client.dev = dev;
315 	rwtm->mbox_client.rx_callback = mox_rwtm_rx_callback;
316 
317 	rwtm->mbox = mbox_request_channel(&rwtm->mbox_client, 0);
318 	if (IS_ERR(rwtm->mbox)) {
319 		ret = PTR_ERR(rwtm->mbox);
320 		if (ret != -EPROBE_DEFER)
321 			dev_err(dev, "Cannot request mailbox channel: %i\n",
322 				ret);
323 		goto remove_files;
324 	}
325 
326 	init_completion(&rwtm->cmd_done);
327 
328 	ret = mox_get_board_info(rwtm);
329 	if (ret < 0)
330 		dev_warn(dev, "Cannot read board information: %i\n", ret);
331 
332 	rwtm->hwrng.name = DRIVER_NAME "_hwrng";
333 	rwtm->hwrng.read = mox_hwrng_read;
334 	rwtm->hwrng.priv = (unsigned long) rwtm;
335 	rwtm->hwrng.quality = 1024;
336 
337 	ret = devm_hwrng_register(dev, &rwtm->hwrng);
338 	if (ret < 0) {
339 		dev_err(dev, "Cannot register HWRNG: %i\n", ret);
340 		goto free_channel;
341 	}
342 
343 	return 0;
344 
345 free_channel:
346 	mbox_free_channel(rwtm->mbox);
347 remove_files:
348 	sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
349 put_kobj:
350 	kobject_put(rwtm_to_kobj(rwtm));
351 	return ret;
352 }
353 
354 static int turris_mox_rwtm_remove(struct platform_device *pdev)
355 {
356 	struct mox_rwtm *rwtm = platform_get_drvdata(pdev);
357 
358 	sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
359 	kobject_put(rwtm_to_kobj(rwtm));
360 	mbox_free_channel(rwtm->mbox);
361 
362 	return 0;
363 }
364 
365 static const struct of_device_id turris_mox_rwtm_match[] = {
366 	{ .compatible = "cznic,turris-mox-rwtm", },
367 	{ },
368 };
369 
370 MODULE_DEVICE_TABLE(of, turris_mox_rwtm_match);
371 
372 static struct platform_driver turris_mox_rwtm_driver = {
373 	.probe	= turris_mox_rwtm_probe,
374 	.remove	= turris_mox_rwtm_remove,
375 	.driver	= {
376 		.name		= DRIVER_NAME,
377 		.of_match_table	= turris_mox_rwtm_match,
378 	},
379 };
380 module_platform_driver(turris_mox_rwtm_driver);
381 
382 MODULE_LICENSE("GPL v2");
383 MODULE_DESCRIPTION("Turris Mox rWTM firmware driver");
384 MODULE_AUTHOR("Marek Behun <marek.behun@nic.cz>");
385