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