property.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  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. #include <linux/err.h>
  10. #include <linux/slab.h>
  11. #include <linux/string.h>
  12. #include <linux/uuid.h>
  13. #include <linux/thunderbolt.h>
  14. struct tb_property_entry {
  15. u32 key_hi;
  16. u32 key_lo;
  17. u16 length;
  18. u8 reserved;
  19. u8 type;
  20. u32 value;
  21. };
  22. struct tb_property_rootdir_entry {
  23. u32 magic;
  24. u32 length;
  25. struct tb_property_entry entries[];
  26. };
  27. struct tb_property_dir_entry {
  28. u32 uuid[4];
  29. struct tb_property_entry entries[];
  30. };
  31. #define TB_PROPERTY_ROOTDIR_MAGIC 0x55584401
  32. static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
  33. size_t block_len, unsigned int dir_offset, size_t dir_len,
  34. bool is_root);
  35. static inline void parse_dwdata(void *dst, const void *src, size_t dwords)
  36. {
  37. be32_to_cpu_array(dst, src, dwords);
  38. }
  39. static inline void format_dwdata(void *dst, const void *src, size_t dwords)
  40. {
  41. cpu_to_be32_array(dst, src, dwords);
  42. }
  43. static bool tb_property_entry_valid(const struct tb_property_entry *entry,
  44. size_t block_len)
  45. {
  46. switch (entry->type) {
  47. case TB_PROPERTY_TYPE_DIRECTORY:
  48. case TB_PROPERTY_TYPE_DATA:
  49. case TB_PROPERTY_TYPE_TEXT:
  50. if (entry->length > block_len)
  51. return false;
  52. if (entry->value + entry->length > block_len)
  53. return false;
  54. break;
  55. case TB_PROPERTY_TYPE_VALUE:
  56. if (entry->length != 1)
  57. return false;
  58. break;
  59. }
  60. return true;
  61. }
  62. static bool tb_property_key_valid(const char *key)
  63. {
  64. return key && strlen(key) <= TB_PROPERTY_KEY_SIZE;
  65. }
  66. static struct tb_property *
  67. tb_property_alloc(const char *key, enum tb_property_type type)
  68. {
  69. struct tb_property *property;
  70. property = kzalloc(sizeof(*property), GFP_KERNEL);
  71. if (!property)
  72. return NULL;
  73. strcpy(property->key, key);
  74. property->type = type;
  75. INIT_LIST_HEAD(&property->list);
  76. return property;
  77. }
  78. static struct tb_property *tb_property_parse(const u32 *block, size_t block_len,
  79. const struct tb_property_entry *entry)
  80. {
  81. char key[TB_PROPERTY_KEY_SIZE + 1];
  82. struct tb_property *property;
  83. struct tb_property_dir *dir;
  84. if (!tb_property_entry_valid(entry, block_len))
  85. return NULL;
  86. parse_dwdata(key, entry, 2);
  87. key[TB_PROPERTY_KEY_SIZE] = '\0';
  88. property = tb_property_alloc(key, entry->type);
  89. if (!property)
  90. return NULL;
  91. property->length = entry->length;
  92. switch (property->type) {
  93. case TB_PROPERTY_TYPE_DIRECTORY:
  94. dir = __tb_property_parse_dir(block, block_len, entry->value,
  95. entry->length, false);
  96. if (!dir) {
  97. kfree(property);
  98. return NULL;
  99. }
  100. property->value.dir = dir;
  101. break;
  102. case TB_PROPERTY_TYPE_DATA:
  103. property->value.data = kcalloc(property->length, sizeof(u32),
  104. GFP_KERNEL);
  105. if (!property->value.data) {
  106. kfree(property);
  107. return NULL;
  108. }
  109. parse_dwdata(property->value.data, block + entry->value,
  110. entry->length);
  111. break;
  112. case TB_PROPERTY_TYPE_TEXT:
  113. property->value.text = kcalloc(property->length, sizeof(u32),
  114. GFP_KERNEL);
  115. if (!property->value.text) {
  116. kfree(property);
  117. return NULL;
  118. }
  119. parse_dwdata(property->value.text, block + entry->value,
  120. entry->length);
  121. /* Force null termination */
  122. property->value.text[property->length * 4 - 1] = '\0';
  123. break;
  124. case TB_PROPERTY_TYPE_VALUE:
  125. property->value.immediate = entry->value;
  126. break;
  127. default:
  128. property->type = TB_PROPERTY_TYPE_UNKNOWN;
  129. break;
  130. }
  131. return property;
  132. }
  133. static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
  134. size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root)
  135. {
  136. const struct tb_property_entry *entries;
  137. size_t i, content_len, nentries;
  138. unsigned int content_offset;
  139. struct tb_property_dir *dir;
  140. dir = kzalloc(sizeof(*dir), GFP_KERNEL);
  141. if (!dir)
  142. return NULL;
  143. if (is_root) {
  144. content_offset = dir_offset + 2;
  145. content_len = dir_len;
  146. } else {
  147. dir->uuid = kmemdup(&block[dir_offset], sizeof(*dir->uuid),
  148. GFP_KERNEL);
  149. if (!dir->uuid) {
  150. tb_property_free_dir(dir);
  151. return NULL;
  152. }
  153. content_offset = dir_offset + 4;
  154. content_len = dir_len - 4; /* Length includes UUID */
  155. }
  156. entries = (const struct tb_property_entry *)&block[content_offset];
  157. nentries = content_len / (sizeof(*entries) / 4);
  158. INIT_LIST_HEAD(&dir->properties);
  159. for (i = 0; i < nentries; i++) {
  160. struct tb_property *property;
  161. property = tb_property_parse(block, block_len, &entries[i]);
  162. if (!property) {
  163. tb_property_free_dir(dir);
  164. return NULL;
  165. }
  166. list_add_tail(&property->list, &dir->properties);
  167. }
  168. return dir;
  169. }
  170. /**
  171. * tb_property_parse_dir() - Parses properties from given property block
  172. * @block: Property block to parse
  173. * @block_len: Number of dword elements in the property block
  174. *
  175. * This function parses the XDomain properties data block into format that
  176. * can be traversed using the helper functions provided by this module.
  177. * Upon success returns the parsed directory. In case of error returns
  178. * %NULL. The resulting &struct tb_property_dir needs to be released by
  179. * calling tb_property_free_dir() when not needed anymore.
  180. *
  181. * The @block is expected to be root directory.
  182. */
  183. struct tb_property_dir *tb_property_parse_dir(const u32 *block,
  184. size_t block_len)
  185. {
  186. const struct tb_property_rootdir_entry *rootdir =
  187. (const struct tb_property_rootdir_entry *)block;
  188. if (rootdir->magic != TB_PROPERTY_ROOTDIR_MAGIC)
  189. return NULL;
  190. if (rootdir->length > block_len)
  191. return NULL;
  192. return __tb_property_parse_dir(block, block_len, 0, rootdir->length,
  193. true);
  194. }
  195. /**
  196. * tb_property_create_dir() - Creates new property directory
  197. * @uuid: UUID used to identify the particular directory
  198. *
  199. * Creates new, empty property directory. If @uuid is %NULL then the
  200. * directory is assumed to be root directory.
  201. */
  202. struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid)
  203. {
  204. struct tb_property_dir *dir;
  205. dir = kzalloc(sizeof(*dir), GFP_KERNEL);
  206. if (!dir)
  207. return NULL;
  208. INIT_LIST_HEAD(&dir->properties);
  209. if (uuid) {
  210. dir->uuid = kmemdup(uuid, sizeof(*dir->uuid), GFP_KERNEL);
  211. if (!dir->uuid) {
  212. kfree(dir);
  213. return NULL;
  214. }
  215. }
  216. return dir;
  217. }
  218. EXPORT_SYMBOL_GPL(tb_property_create_dir);
  219. static void tb_property_free(struct tb_property *property)
  220. {
  221. switch (property->type) {
  222. case TB_PROPERTY_TYPE_DIRECTORY:
  223. tb_property_free_dir(property->value.dir);
  224. break;
  225. case TB_PROPERTY_TYPE_DATA:
  226. kfree(property->value.data);
  227. break;
  228. case TB_PROPERTY_TYPE_TEXT:
  229. kfree(property->value.text);
  230. break;
  231. default:
  232. break;
  233. }
  234. kfree(property);
  235. }
  236. /**
  237. * tb_property_free_dir() - Release memory allocated for property directory
  238. * @dir: Directory to release
  239. *
  240. * This will release all the memory the directory occupies including all
  241. * descendants. It is OK to pass %NULL @dir, then the function does
  242. * nothing.
  243. */
  244. void tb_property_free_dir(struct tb_property_dir *dir)
  245. {
  246. struct tb_property *property, *tmp;
  247. if (!dir)
  248. return;
  249. list_for_each_entry_safe(property, tmp, &dir->properties, list) {
  250. list_del(&property->list);
  251. tb_property_free(property);
  252. }
  253. kfree(dir->uuid);
  254. kfree(dir);
  255. }
  256. EXPORT_SYMBOL_GPL(tb_property_free_dir);
  257. static size_t tb_property_dir_length(const struct tb_property_dir *dir,
  258. bool recurse, size_t *data_len)
  259. {
  260. const struct tb_property *property;
  261. size_t len = 0;
  262. if (dir->uuid)
  263. len += sizeof(*dir->uuid) / 4;
  264. else
  265. len += sizeof(struct tb_property_rootdir_entry) / 4;
  266. list_for_each_entry(property, &dir->properties, list) {
  267. len += sizeof(struct tb_property_entry) / 4;
  268. switch (property->type) {
  269. case TB_PROPERTY_TYPE_DIRECTORY:
  270. if (recurse) {
  271. len += tb_property_dir_length(
  272. property->value.dir, recurse, data_len);
  273. }
  274. /* Reserve dword padding after each directory */
  275. if (data_len)
  276. *data_len += 1;
  277. break;
  278. case TB_PROPERTY_TYPE_DATA:
  279. case TB_PROPERTY_TYPE_TEXT:
  280. if (data_len)
  281. *data_len += property->length;
  282. break;
  283. default:
  284. break;
  285. }
  286. }
  287. return len;
  288. }
  289. static ssize_t __tb_property_format_dir(const struct tb_property_dir *dir,
  290. u32 *block, unsigned int start_offset, size_t block_len)
  291. {
  292. unsigned int data_offset, dir_end;
  293. const struct tb_property *property;
  294. struct tb_property_entry *entry;
  295. size_t dir_len, data_len = 0;
  296. int ret;
  297. /*
  298. * The structure of property block looks like following. Leaf
  299. * data/text is included right after the directory and each
  300. * directory follows each other (even nested ones).
  301. *
  302. * +----------+ <-- start_offset
  303. * | header | <-- root directory header
  304. * +----------+ ---
  305. * | entry 0 | -^--------------------.
  306. * +----------+ | |
  307. * | entry 1 | -|--------------------|--.
  308. * +----------+ | | |
  309. * | entry 2 | -|-----------------. | |
  310. * +----------+ | | | |
  311. * : : | dir_len | | |
  312. * . . | | | |
  313. * : : | | | |
  314. * +----------+ | | | |
  315. * | entry n | v | | |
  316. * +----------+ <-- data_offset | | |
  317. * | data 0 | <------------------|--' |
  318. * +----------+ | |
  319. * | data 1 | <------------------|-----'
  320. * +----------+ |
  321. * | 00000000 | padding |
  322. * +----------+ <-- dir_end <------'
  323. * | UUID | <-- directory UUID (child directory)
  324. * +----------+
  325. * | entry 0 |
  326. * +----------+
  327. * | entry 1 |
  328. * +----------+
  329. * : :
  330. * . .
  331. * : :
  332. * +----------+
  333. * | entry n |
  334. * +----------+
  335. * | data 0 |
  336. * +----------+
  337. *
  338. * We use dir_end to hold pointer to the end of the directory. It
  339. * will increase as we add directories and each directory should be
  340. * added starting from previous dir_end.
  341. */
  342. dir_len = tb_property_dir_length(dir, false, &data_len);
  343. data_offset = start_offset + dir_len;
  344. dir_end = start_offset + data_len + dir_len;
  345. if (data_offset > dir_end)
  346. return -EINVAL;
  347. if (dir_end > block_len)
  348. return -EINVAL;
  349. /* Write headers first */
  350. if (dir->uuid) {
  351. struct tb_property_dir_entry *pe;
  352. pe = (struct tb_property_dir_entry *)&block[start_offset];
  353. memcpy(pe->uuid, dir->uuid, sizeof(pe->uuid));
  354. entry = pe->entries;
  355. } else {
  356. struct tb_property_rootdir_entry *re;
  357. re = (struct tb_property_rootdir_entry *)&block[start_offset];
  358. re->magic = TB_PROPERTY_ROOTDIR_MAGIC;
  359. re->length = dir_len - sizeof(*re) / 4;
  360. entry = re->entries;
  361. }
  362. list_for_each_entry(property, &dir->properties, list) {
  363. const struct tb_property_dir *child;
  364. format_dwdata(entry, property->key, 2);
  365. entry->type = property->type;
  366. switch (property->type) {
  367. case TB_PROPERTY_TYPE_DIRECTORY:
  368. child = property->value.dir;
  369. ret = __tb_property_format_dir(child, block, dir_end,
  370. block_len);
  371. if (ret < 0)
  372. return ret;
  373. entry->length = tb_property_dir_length(child, false,
  374. NULL);
  375. entry->value = dir_end;
  376. dir_end = ret;
  377. break;
  378. case TB_PROPERTY_TYPE_DATA:
  379. format_dwdata(&block[data_offset], property->value.data,
  380. property->length);
  381. entry->length = property->length;
  382. entry->value = data_offset;
  383. data_offset += entry->length;
  384. break;
  385. case TB_PROPERTY_TYPE_TEXT:
  386. format_dwdata(&block[data_offset], property->value.text,
  387. property->length);
  388. entry->length = property->length;
  389. entry->value = data_offset;
  390. data_offset += entry->length;
  391. break;
  392. case TB_PROPERTY_TYPE_VALUE:
  393. entry->length = property->length;
  394. entry->value = property->value.immediate;
  395. break;
  396. default:
  397. break;
  398. }
  399. entry++;
  400. }
  401. return dir_end;
  402. }
  403. /**
  404. * tb_property_format_dir() - Formats directory to the packed XDomain format
  405. * @dir: Directory to format
  406. * @block: Property block where the packed data is placed
  407. * @block_len: Length of the property block
  408. *
  409. * This function formats the directory to the packed format that can be
  410. * then send over the thunderbolt fabric to receiving host. Returns %0 in
  411. * case of success and negative errno on faulure. Passing %NULL in @block
  412. * returns number of entries the block takes.
  413. */
  414. ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block,
  415. size_t block_len)
  416. {
  417. ssize_t ret;
  418. if (!block) {
  419. size_t dir_len, data_len = 0;
  420. dir_len = tb_property_dir_length(dir, true, &data_len);
  421. return dir_len + data_len;
  422. }
  423. ret = __tb_property_format_dir(dir, block, 0, block_len);
  424. return ret < 0 ? ret : 0;
  425. }
  426. /**
  427. * tb_property_add_immediate() - Add immediate property to directory
  428. * @parent: Directory to add the property
  429. * @key: Key for the property
  430. * @value: Immediate value to store with the property
  431. */
  432. int tb_property_add_immediate(struct tb_property_dir *parent, const char *key,
  433. u32 value)
  434. {
  435. struct tb_property *property;
  436. if (!tb_property_key_valid(key))
  437. return -EINVAL;
  438. property = tb_property_alloc(key, TB_PROPERTY_TYPE_VALUE);
  439. if (!property)
  440. return -ENOMEM;
  441. property->length = 1;
  442. property->value.immediate = value;
  443. list_add_tail(&property->list, &parent->properties);
  444. return 0;
  445. }
  446. EXPORT_SYMBOL_GPL(tb_property_add_immediate);
  447. /**
  448. * tb_property_add_data() - Adds arbitrary data property to directory
  449. * @parent: Directory to add the property
  450. * @key: Key for the property
  451. * @buf: Data buffer to add
  452. * @buflen: Number of bytes in the data buffer
  453. *
  454. * Function takes a copy of @buf and adds it to the directory.
  455. */
  456. int tb_property_add_data(struct tb_property_dir *parent, const char *key,
  457. const void *buf, size_t buflen)
  458. {
  459. /* Need to pad to dword boundary */
  460. size_t size = round_up(buflen, 4);
  461. struct tb_property *property;
  462. if (!tb_property_key_valid(key))
  463. return -EINVAL;
  464. property = tb_property_alloc(key, TB_PROPERTY_TYPE_DATA);
  465. if (!property)
  466. return -ENOMEM;
  467. property->length = size / 4;
  468. property->value.data = kzalloc(size, GFP_KERNEL);
  469. if (!property->value.data) {
  470. kfree(property);
  471. return -ENOMEM;
  472. }
  473. memcpy(property->value.data, buf, buflen);
  474. list_add_tail(&property->list, &parent->properties);
  475. return 0;
  476. }
  477. EXPORT_SYMBOL_GPL(tb_property_add_data);
  478. /**
  479. * tb_property_add_text() - Adds string property to directory
  480. * @parent: Directory to add the property
  481. * @key: Key for the property
  482. * @text: String to add
  483. *
  484. * Function takes a copy of @text and adds it to the directory.
  485. */
  486. int tb_property_add_text(struct tb_property_dir *parent, const char *key,
  487. const char *text)
  488. {
  489. /* Need to pad to dword boundary */
  490. size_t size = round_up(strlen(text) + 1, 4);
  491. struct tb_property *property;
  492. if (!tb_property_key_valid(key))
  493. return -EINVAL;
  494. property = tb_property_alloc(key, TB_PROPERTY_TYPE_TEXT);
  495. if (!property)
  496. return -ENOMEM;
  497. property->length = size / 4;
  498. property->value.text = kzalloc(size, GFP_KERNEL);
  499. if (!property->value.text) {
  500. kfree(property);
  501. return -ENOMEM;
  502. }
  503. strcpy(property->value.text, text);
  504. list_add_tail(&property->list, &parent->properties);
  505. return 0;
  506. }
  507. EXPORT_SYMBOL_GPL(tb_property_add_text);
  508. /**
  509. * tb_property_add_dir() - Adds a directory to the parent directory
  510. * @parent: Directory to add the property
  511. * @key: Key for the property
  512. * @dir: Directory to add
  513. */
  514. int tb_property_add_dir(struct tb_property_dir *parent, const char *key,
  515. struct tb_property_dir *dir)
  516. {
  517. struct tb_property *property;
  518. if (!tb_property_key_valid(key))
  519. return -EINVAL;
  520. property = tb_property_alloc(key, TB_PROPERTY_TYPE_DIRECTORY);
  521. if (!property)
  522. return -ENOMEM;
  523. property->value.dir = dir;
  524. list_add_tail(&property->list, &parent->properties);
  525. return 0;
  526. }
  527. EXPORT_SYMBOL_GPL(tb_property_add_dir);
  528. /**
  529. * tb_property_remove() - Removes property from a parent directory
  530. * @property: Property to remove
  531. *
  532. * Note memory for @property is released as well so it is not allowed to
  533. * touch the object after call to this function.
  534. */
  535. void tb_property_remove(struct tb_property *property)
  536. {
  537. list_del(&property->list);
  538. kfree(property);
  539. }
  540. EXPORT_SYMBOL_GPL(tb_property_remove);
  541. /**
  542. * tb_property_find() - Find a property from a directory
  543. * @dir: Directory where the property is searched
  544. * @key: Key to look for
  545. * @type: Type of the property
  546. *
  547. * Finds and returns property from the given directory. Does not recurse
  548. * into sub-directories. Returns %NULL if the property was not found.
  549. */
  550. struct tb_property *tb_property_find(struct tb_property_dir *dir,
  551. const char *key, enum tb_property_type type)
  552. {
  553. struct tb_property *property;
  554. list_for_each_entry(property, &dir->properties, list) {
  555. if (property->type == type && !strcmp(property->key, key))
  556. return property;
  557. }
  558. return NULL;
  559. }
  560. EXPORT_SYMBOL_GPL(tb_property_find);
  561. /**
  562. * tb_property_get_next() - Get next property from directory
  563. * @dir: Directory holding properties
  564. * @prev: Previous property in the directory (%NULL returns the first)
  565. */
  566. struct tb_property *tb_property_get_next(struct tb_property_dir *dir,
  567. struct tb_property *prev)
  568. {
  569. if (prev) {
  570. if (list_is_last(&prev->list, &dir->properties))
  571. return NULL;
  572. return list_next_entry(prev, list);
  573. }
  574. return list_first_entry_or_null(&dir->properties, struct tb_property,
  575. list);
  576. }
  577. EXPORT_SYMBOL_GPL(tb_property_get_next);