xref: /linux/drivers/thunderbolt/property.c (revision e3966940559d52aa1800a008dcfeec218dd31f88)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Thunderbolt XDomain property support
4  *
5  * Copyright (C) 2017, Intel Corporation
6  * Authors: Michael Jamet <michael.jamet@intel.com>
7  *          Mika Westerberg <mika.westerberg@linux.intel.com>
8  */
9 
10 #include <linux/err.h>
11 #include <linux/slab.h>
12 #include <linux/string.h>
13 #include <linux/uuid.h>
14 #include <linux/thunderbolt.h>
15 
16 struct tb_property_entry {
17 	u32 key_hi;
18 	u32 key_lo;
19 	u16 length;
20 	u8 reserved;
21 	u8 type;
22 	u32 value;
23 };
24 
25 struct tb_property_rootdir_entry {
26 	u32 magic;
27 	u32 length;
28 	struct tb_property_entry entries[];
29 };
30 
31 struct tb_property_dir_entry {
32 	u32 uuid[4];
33 	struct tb_property_entry entries[];
34 };
35 
36 #define TB_PROPERTY_ROOTDIR_MAGIC	0x55584401
37 
38 static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
39 	size_t block_len, unsigned int dir_offset, size_t dir_len,
40 	bool is_root);
41 
42 static inline void parse_dwdata(void *dst, const void *src, size_t dwords)
43 {
44 	be32_to_cpu_array(dst, src, dwords);
45 }
46 
47 static inline void format_dwdata(void *dst, const void *src, size_t dwords)
48 {
49 	cpu_to_be32_array(dst, src, dwords);
50 }
51 
52 static bool tb_property_entry_valid(const struct tb_property_entry *entry,
53 				  size_t block_len)
54 {
55 	switch (entry->type) {
56 	case TB_PROPERTY_TYPE_DIRECTORY:
57 	case TB_PROPERTY_TYPE_DATA:
58 	case TB_PROPERTY_TYPE_TEXT:
59 		if (entry->length > block_len)
60 			return false;
61 		if (entry->value + entry->length > block_len)
62 			return false;
63 		break;
64 
65 	case TB_PROPERTY_TYPE_VALUE:
66 		if (entry->length != 1)
67 			return false;
68 		break;
69 	}
70 
71 	return true;
72 }
73 
74 static bool tb_property_key_valid(const char *key)
75 {
76 	return key && strlen(key) <= TB_PROPERTY_KEY_SIZE;
77 }
78 
79 static struct tb_property *
80 tb_property_alloc(const char *key, enum tb_property_type type)
81 {
82 	struct tb_property *property;
83 
84 	property = kzalloc(sizeof(*property), GFP_KERNEL);
85 	if (!property)
86 		return NULL;
87 
88 	strcpy(property->key, key);
89 	property->type = type;
90 	INIT_LIST_HEAD(&property->list);
91 
92 	return property;
93 }
94 
95 static struct tb_property *tb_property_parse(const u32 *block, size_t block_len,
96 					const struct tb_property_entry *entry)
97 {
98 	char key[TB_PROPERTY_KEY_SIZE + 1];
99 	struct tb_property *property;
100 	struct tb_property_dir *dir;
101 
102 	if (!tb_property_entry_valid(entry, block_len))
103 		return NULL;
104 
105 	parse_dwdata(key, entry, 2);
106 	key[TB_PROPERTY_KEY_SIZE] = '\0';
107 
108 	property = tb_property_alloc(key, entry->type);
109 	if (!property)
110 		return NULL;
111 
112 	property->length = entry->length;
113 
114 	switch (property->type) {
115 	case TB_PROPERTY_TYPE_DIRECTORY:
116 		dir = __tb_property_parse_dir(block, block_len, entry->value,
117 					      entry->length, false);
118 		if (!dir) {
119 			kfree(property);
120 			return NULL;
121 		}
122 		property->value.dir = dir;
123 		break;
124 
125 	case TB_PROPERTY_TYPE_DATA:
126 		property->value.data = kcalloc(property->length, sizeof(u32),
127 					       GFP_KERNEL);
128 		if (!property->value.data) {
129 			kfree(property);
130 			return NULL;
131 		}
132 		parse_dwdata(property->value.data, block + entry->value,
133 			     entry->length);
134 		break;
135 
136 	case TB_PROPERTY_TYPE_TEXT:
137 		property->value.text = kcalloc(property->length, sizeof(u32),
138 					       GFP_KERNEL);
139 		if (!property->value.text) {
140 			kfree(property);
141 			return NULL;
142 		}
143 		parse_dwdata(property->value.text, block + entry->value,
144 			     entry->length);
145 		/* Force null termination */
146 		property->value.text[property->length * 4 - 1] = '\0';
147 		break;
148 
149 	case TB_PROPERTY_TYPE_VALUE:
150 		property->value.immediate = entry->value;
151 		break;
152 
153 	default:
154 		property->type = TB_PROPERTY_TYPE_UNKNOWN;
155 		break;
156 	}
157 
158 	return property;
159 }
160 
161 static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
162 	size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root)
163 {
164 	const struct tb_property_entry *entries;
165 	size_t i, content_len, nentries;
166 	unsigned int content_offset;
167 	struct tb_property_dir *dir;
168 
169 	dir = kzalloc(sizeof(*dir), GFP_KERNEL);
170 	if (!dir)
171 		return NULL;
172 
173 	if (is_root) {
174 		content_offset = dir_offset + 2;
175 		content_len = dir_len;
176 	} else {
177 		dir->uuid = kmemdup(&block[dir_offset], sizeof(*dir->uuid),
178 				    GFP_KERNEL);
179 		if (!dir->uuid) {
180 			tb_property_free_dir(dir);
181 			return NULL;
182 		}
183 		content_offset = dir_offset + 4;
184 		content_len = dir_len - 4; /* Length includes UUID */
185 	}
186 
187 	entries = (const struct tb_property_entry *)&block[content_offset];
188 	nentries = content_len / (sizeof(*entries) / 4);
189 
190 	INIT_LIST_HEAD(&dir->properties);
191 
192 	for (i = 0; i < nentries; i++) {
193 		struct tb_property *property;
194 
195 		property = tb_property_parse(block, block_len, &entries[i]);
196 		if (!property) {
197 			tb_property_free_dir(dir);
198 			return NULL;
199 		}
200 
201 		list_add_tail(&property->list, &dir->properties);
202 	}
203 
204 	return dir;
205 }
206 
207 /**
208  * tb_property_parse_dir() - Parses properties from given property block
209  * @block: Property block to parse
210  * @block_len: Number of dword elements in the property block
211  *
212  * This function parses the XDomain properties data block into format that
213  * can be traversed using the helper functions provided by this module.
214  *
215  * The resulting &struct tb_property_dir needs to be released by
216  * calling tb_property_free_dir() when not needed anymore.
217  *
218  * The @block is expected to be root directory.
219  *
220  * Return: Pointer to &struct tb_property_dir, %NULL in case of failure.
221  */
222 struct tb_property_dir *tb_property_parse_dir(const u32 *block,
223 					      size_t block_len)
224 {
225 	const struct tb_property_rootdir_entry *rootdir =
226 		(const struct tb_property_rootdir_entry *)block;
227 
228 	if (rootdir->magic != TB_PROPERTY_ROOTDIR_MAGIC)
229 		return NULL;
230 	if (rootdir->length > block_len)
231 		return NULL;
232 
233 	return __tb_property_parse_dir(block, block_len, 0, rootdir->length,
234 				       true);
235 }
236 
237 /**
238  * tb_property_create_dir() - Creates new property directory
239  * @uuid: UUID used to identify the particular directory
240  *
241  * Creates new, empty property directory. If @uuid is %NULL then the
242  * directory is assumed to be root directory.
243  *
244  * Return: Pointer to &struct tb_property_dir, %NULL in case of failure.
245  */
246 struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid)
247 {
248 	struct tb_property_dir *dir;
249 
250 	dir = kzalloc(sizeof(*dir), GFP_KERNEL);
251 	if (!dir)
252 		return NULL;
253 
254 	INIT_LIST_HEAD(&dir->properties);
255 	if (uuid) {
256 		dir->uuid = kmemdup(uuid, sizeof(*dir->uuid), GFP_KERNEL);
257 		if (!dir->uuid) {
258 			kfree(dir);
259 			return NULL;
260 		}
261 	}
262 
263 	return dir;
264 }
265 EXPORT_SYMBOL_GPL(tb_property_create_dir);
266 
267 static void tb_property_free(struct tb_property *property)
268 {
269 	switch (property->type) {
270 	case TB_PROPERTY_TYPE_DIRECTORY:
271 		tb_property_free_dir(property->value.dir);
272 		break;
273 
274 	case TB_PROPERTY_TYPE_DATA:
275 		kfree(property->value.data);
276 		break;
277 
278 	case TB_PROPERTY_TYPE_TEXT:
279 		kfree(property->value.text);
280 		break;
281 
282 	default:
283 		break;
284 	}
285 
286 	kfree(property);
287 }
288 
289 /**
290  * tb_property_free_dir() - Release memory allocated for property directory
291  * @dir: Directory to release
292  *
293  * This will release all the memory the directory occupies including all
294  * descendants. It is OK to pass %NULL @dir, then the function does
295  * nothing.
296  */
297 void tb_property_free_dir(struct tb_property_dir *dir)
298 {
299 	struct tb_property *property, *tmp;
300 
301 	if (!dir)
302 		return;
303 
304 	list_for_each_entry_safe(property, tmp, &dir->properties, list) {
305 		list_del(&property->list);
306 		tb_property_free(property);
307 	}
308 	kfree(dir->uuid);
309 	kfree(dir);
310 }
311 EXPORT_SYMBOL_GPL(tb_property_free_dir);
312 
313 static size_t tb_property_dir_length(const struct tb_property_dir *dir,
314 				     bool recurse, size_t *data_len)
315 {
316 	const struct tb_property *property;
317 	size_t len = 0;
318 
319 	if (dir->uuid)
320 		len += sizeof(*dir->uuid) / 4;
321 	else
322 		len += sizeof(struct tb_property_rootdir_entry) / 4;
323 
324 	list_for_each_entry(property, &dir->properties, list) {
325 		len += sizeof(struct tb_property_entry) / 4;
326 
327 		switch (property->type) {
328 		case TB_PROPERTY_TYPE_DIRECTORY:
329 			if (recurse) {
330 				len += tb_property_dir_length(
331 					property->value.dir, recurse, data_len);
332 			}
333 			/* Reserve dword padding after each directory */
334 			if (data_len)
335 				*data_len += 1;
336 			break;
337 
338 		case TB_PROPERTY_TYPE_DATA:
339 		case TB_PROPERTY_TYPE_TEXT:
340 			if (data_len)
341 				*data_len += property->length;
342 			break;
343 
344 		default:
345 			break;
346 		}
347 	}
348 
349 	return len;
350 }
351 
352 static ssize_t __tb_property_format_dir(const struct tb_property_dir *dir,
353 	u32 *block, unsigned int start_offset, size_t block_len)
354 {
355 	unsigned int data_offset, dir_end;
356 	const struct tb_property *property;
357 	struct tb_property_entry *entry;
358 	size_t dir_len, data_len = 0;
359 	int ret;
360 
361 	/*
362 	 * The structure of property block looks like following. Leaf
363 	 * data/text is included right after the directory and each
364 	 * directory follows each other (even nested ones).
365 	 *
366 	 * +----------+ <-- start_offset
367 	 * |  header  | <-- root directory header
368 	 * +----------+ ---
369 	 * |  entry 0 | -^--------------------.
370 	 * +----------+  |                    |
371 	 * |  entry 1 | -|--------------------|--.
372 	 * +----------+  |                    |  |
373 	 * |  entry 2 | -|-----------------.  |  |
374 	 * +----------+  |                 |  |  |
375 	 * :          :  |  dir_len        |  |  |
376 	 * .          .  |                 |  |  |
377 	 * :          :  |                 |  |  |
378 	 * +----------+  |                 |  |  |
379 	 * |  entry n |  v                 |  |  |
380 	 * +----------+ <-- data_offset    |  |  |
381 	 * |  data 0  | <------------------|--'  |
382 	 * +----------+                    |     |
383 	 * |  data 1  | <------------------|-----'
384 	 * +----------+                    |
385 	 * | 00000000 | padding            |
386 	 * +----------+ <-- dir_end <------'
387 	 * |   UUID   | <-- directory UUID (child directory)
388 	 * +----------+
389 	 * |  entry 0 |
390 	 * +----------+
391 	 * |  entry 1 |
392 	 * +----------+
393 	 * :          :
394 	 * .          .
395 	 * :          :
396 	 * +----------+
397 	 * |  entry n |
398 	 * +----------+
399 	 * |  data 0  |
400 	 * +----------+
401 	 *
402 	 * We use dir_end to hold pointer to the end of the directory. It
403 	 * will increase as we add directories and each directory should be
404 	 * added starting from previous dir_end.
405 	 */
406 	dir_len = tb_property_dir_length(dir, false, &data_len);
407 	data_offset = start_offset + dir_len;
408 	dir_end = start_offset + data_len + dir_len;
409 
410 	if (data_offset > dir_end)
411 		return -EINVAL;
412 	if (dir_end > block_len)
413 		return -EINVAL;
414 
415 	/* Write headers first */
416 	if (dir->uuid) {
417 		struct tb_property_dir_entry *pe;
418 
419 		pe = (struct tb_property_dir_entry *)&block[start_offset];
420 		memcpy(pe->uuid, dir->uuid, sizeof(pe->uuid));
421 		entry = pe->entries;
422 	} else {
423 		struct tb_property_rootdir_entry *re;
424 
425 		re = (struct tb_property_rootdir_entry *)&block[start_offset];
426 		re->magic = TB_PROPERTY_ROOTDIR_MAGIC;
427 		re->length = dir_len - sizeof(*re) / 4;
428 		entry = re->entries;
429 	}
430 
431 	list_for_each_entry(property, &dir->properties, list) {
432 		const struct tb_property_dir *child;
433 
434 		format_dwdata(entry, property->key, 2);
435 		entry->type = property->type;
436 
437 		switch (property->type) {
438 		case TB_PROPERTY_TYPE_DIRECTORY:
439 			child = property->value.dir;
440 			ret = __tb_property_format_dir(child, block, dir_end,
441 						       block_len);
442 			if (ret < 0)
443 				return ret;
444 			entry->length = tb_property_dir_length(child, false,
445 							       NULL);
446 			entry->value = dir_end;
447 			dir_end = ret;
448 			break;
449 
450 		case TB_PROPERTY_TYPE_DATA:
451 			format_dwdata(&block[data_offset], property->value.data,
452 				      property->length);
453 			entry->length = property->length;
454 			entry->value = data_offset;
455 			data_offset += entry->length;
456 			break;
457 
458 		case TB_PROPERTY_TYPE_TEXT:
459 			format_dwdata(&block[data_offset], property->value.text,
460 				      property->length);
461 			entry->length = property->length;
462 			entry->value = data_offset;
463 			data_offset += entry->length;
464 			break;
465 
466 		case TB_PROPERTY_TYPE_VALUE:
467 			entry->length = property->length;
468 			entry->value = property->value.immediate;
469 			break;
470 
471 		default:
472 			break;
473 		}
474 
475 		entry++;
476 	}
477 
478 	return dir_end;
479 }
480 
481 /**
482  * tb_property_format_dir() - Formats directory to the packed XDomain format
483  * @dir: Directory to format
484  * @block: Property block where the packed data is placed
485  * @block_len: Length of the property block
486  *
487  * This function formats the directory to the packed format that can be
488  * then sent over the thunderbolt fabric to receiving host.
489  *
490  * Passing %NULL in @block returns number of entries the block takes.
491  *
492  * Return: %0 on success, negative errno otherwise.
493  */
494 ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block,
495 			       size_t block_len)
496 {
497 	ssize_t ret;
498 
499 	if (!block) {
500 		size_t dir_len, data_len = 0;
501 
502 		dir_len = tb_property_dir_length(dir, true, &data_len);
503 		return dir_len + data_len;
504 	}
505 
506 	ret = __tb_property_format_dir(dir, block, 0, block_len);
507 	return ret < 0 ? ret : 0;
508 }
509 
510 /**
511  * tb_property_copy_dir() - Take a deep copy of directory
512  * @dir: Directory to copy
513  *
514  * The resulting directory needs to be released by calling tb_property_free_dir().
515  *
516  * Return: Pointer to &struct tb_property_dir, %NULL in case of failure.
517  */
518 struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir)
519 {
520 	struct tb_property *property, *p = NULL;
521 	struct tb_property_dir *d;
522 
523 	if (!dir)
524 		return NULL;
525 
526 	d = tb_property_create_dir(dir->uuid);
527 	if (!d)
528 		return NULL;
529 
530 	list_for_each_entry(property, &dir->properties, list) {
531 		struct tb_property *p;
532 
533 		p = tb_property_alloc(property->key, property->type);
534 		if (!p)
535 			goto err_free;
536 
537 		p->length = property->length;
538 
539 		switch (property->type) {
540 		case TB_PROPERTY_TYPE_DIRECTORY:
541 			p->value.dir = tb_property_copy_dir(property->value.dir);
542 			if (!p->value.dir)
543 				goto err_free;
544 			break;
545 
546 		case TB_PROPERTY_TYPE_DATA:
547 			p->value.data = kmemdup(property->value.data,
548 						property->length * 4,
549 						GFP_KERNEL);
550 			if (!p->value.data)
551 				goto err_free;
552 			break;
553 
554 		case TB_PROPERTY_TYPE_TEXT:
555 			p->value.text = kzalloc(p->length * 4, GFP_KERNEL);
556 			if (!p->value.text)
557 				goto err_free;
558 			strcpy(p->value.text, property->value.text);
559 			break;
560 
561 		case TB_PROPERTY_TYPE_VALUE:
562 			p->value.immediate = property->value.immediate;
563 			break;
564 
565 		default:
566 			break;
567 		}
568 
569 		list_add_tail(&p->list, &d->properties);
570 	}
571 
572 	return d;
573 
574 err_free:
575 	kfree(p);
576 	tb_property_free_dir(d);
577 
578 	return NULL;
579 }
580 
581 /**
582  * tb_property_add_immediate() - Add immediate property to directory
583  * @parent: Directory to add the property
584  * @key: Key for the property
585  * @value: Immediate value to store with the property
586  *
587  * Return: %0 on success, negative errno otherwise.
588  */
589 int tb_property_add_immediate(struct tb_property_dir *parent, const char *key,
590 			      u32 value)
591 {
592 	struct tb_property *property;
593 
594 	if (!tb_property_key_valid(key))
595 		return -EINVAL;
596 
597 	property = tb_property_alloc(key, TB_PROPERTY_TYPE_VALUE);
598 	if (!property)
599 		return -ENOMEM;
600 
601 	property->length = 1;
602 	property->value.immediate = value;
603 
604 	list_add_tail(&property->list, &parent->properties);
605 	return 0;
606 }
607 EXPORT_SYMBOL_GPL(tb_property_add_immediate);
608 
609 /**
610  * tb_property_add_data() - Adds arbitrary data property to directory
611  * @parent: Directory to add the property
612  * @key: Key for the property
613  * @buf: Data buffer to add
614  * @buflen: Number of bytes in the data buffer
615  *
616  * Function takes a copy of @buf and adds it to the directory.
617  *
618  * Return: %0 on success, negative errno otherwise.
619  */
620 int tb_property_add_data(struct tb_property_dir *parent, const char *key,
621 			 const void *buf, size_t buflen)
622 {
623 	/* Need to pad to dword boundary */
624 	size_t size = round_up(buflen, 4);
625 	struct tb_property *property;
626 
627 	if (!tb_property_key_valid(key))
628 		return -EINVAL;
629 
630 	property = tb_property_alloc(key, TB_PROPERTY_TYPE_DATA);
631 	if (!property)
632 		return -ENOMEM;
633 
634 	property->length = size / 4;
635 	property->value.data = kzalloc(size, GFP_KERNEL);
636 	if (!property->value.data) {
637 		kfree(property);
638 		return -ENOMEM;
639 	}
640 
641 	memcpy(property->value.data, buf, buflen);
642 
643 	list_add_tail(&property->list, &parent->properties);
644 	return 0;
645 }
646 EXPORT_SYMBOL_GPL(tb_property_add_data);
647 
648 /**
649  * tb_property_add_text() - Adds string property to directory
650  * @parent: Directory to add the property
651  * @key: Key for the property
652  * @text: String to add
653  *
654  * Function takes a copy of @text and adds it to the directory.
655  *
656  * Return: %0 on success, negative errno otherwise.
657  */
658 int tb_property_add_text(struct tb_property_dir *parent, const char *key,
659 			 const char *text)
660 {
661 	/* Need to pad to dword boundary */
662 	size_t size = round_up(strlen(text) + 1, 4);
663 	struct tb_property *property;
664 
665 	if (!tb_property_key_valid(key))
666 		return -EINVAL;
667 
668 	property = tb_property_alloc(key, TB_PROPERTY_TYPE_TEXT);
669 	if (!property)
670 		return -ENOMEM;
671 
672 	property->length = size / 4;
673 	property->value.text = kzalloc(size, GFP_KERNEL);
674 	if (!property->value.text) {
675 		kfree(property);
676 		return -ENOMEM;
677 	}
678 
679 	strcpy(property->value.text, text);
680 
681 	list_add_tail(&property->list, &parent->properties);
682 	return 0;
683 }
684 EXPORT_SYMBOL_GPL(tb_property_add_text);
685 
686 /**
687  * tb_property_add_dir() - Adds a directory to the parent directory
688  * @parent: Directory to add the property
689  * @key: Key for the property
690  * @dir: Directory to add
691  *
692  * Return: %0 on success, negative errno otherwise.
693  */
694 int tb_property_add_dir(struct tb_property_dir *parent, const char *key,
695 			struct tb_property_dir *dir)
696 {
697 	struct tb_property *property;
698 
699 	if (!tb_property_key_valid(key))
700 		return -EINVAL;
701 
702 	property = tb_property_alloc(key, TB_PROPERTY_TYPE_DIRECTORY);
703 	if (!property)
704 		return -ENOMEM;
705 
706 	property->value.dir = dir;
707 
708 	list_add_tail(&property->list, &parent->properties);
709 	return 0;
710 }
711 EXPORT_SYMBOL_GPL(tb_property_add_dir);
712 
713 /**
714  * tb_property_remove() - Removes property from a parent directory
715  * @property: Property to remove
716  *
717  * Note memory for @property is released as well so it is not allowed to
718  * touch the object after call to this function.
719  */
720 void tb_property_remove(struct tb_property *property)
721 {
722 	list_del(&property->list);
723 	kfree(property);
724 }
725 EXPORT_SYMBOL_GPL(tb_property_remove);
726 
727 /**
728  * tb_property_find() - Find a property from a directory
729  * @dir: Directory where the property is searched
730  * @key: Key to look for
731  * @type: Type of the property
732  *
733  * Finds and returns property from the given directory. Does not
734  * recurse into sub-directories.
735  *
736  * Return: Pointer to &struct tb_property, %NULL if the property was not found.
737  */
738 struct tb_property *tb_property_find(struct tb_property_dir *dir,
739 	const char *key, enum tb_property_type type)
740 {
741 	struct tb_property *property;
742 
743 	list_for_each_entry(property, &dir->properties, list) {
744 		if (property->type == type && !strcmp(property->key, key))
745 			return property;
746 	}
747 
748 	return NULL;
749 }
750 EXPORT_SYMBOL_GPL(tb_property_find);
751 
752 /**
753  * tb_property_get_next() - Get next property from directory
754  * @dir: Directory holding properties
755  * @prev: Previous property in the directory (%NULL returns the first)
756  *
757  * Return: Pointer to &struct tb_property, %NULL if property was not found.
758  */
759 struct tb_property *tb_property_get_next(struct tb_property_dir *dir,
760 					 struct tb_property *prev)
761 {
762 	if (prev) {
763 		if (list_is_last(&prev->list, &dir->properties))
764 			return NULL;
765 		return list_next_entry(prev, list);
766 	}
767 	return list_first_entry_or_null(&dir->properties, struct tb_property,
768 					list);
769 }
770 EXPORT_SYMBOL_GPL(tb_property_get_next);
771