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 content_offset = dir_offset + 4; 180 content_len = dir_len - 4; /* Length includes UUID */ 181 } 182 183 entries = (const struct tb_property_entry *)&block[content_offset]; 184 nentries = content_len / (sizeof(*entries) / 4); 185 186 INIT_LIST_HEAD(&dir->properties); 187 188 for (i = 0; i < nentries; i++) { 189 struct tb_property *property; 190 191 property = tb_property_parse(block, block_len, &entries[i]); 192 if (!property) { 193 tb_property_free_dir(dir); 194 return NULL; 195 } 196 197 list_add_tail(&property->list, &dir->properties); 198 } 199 200 return dir; 201 } 202 203 /** 204 * tb_property_parse_dir() - Parses properties from given property block 205 * @block: Property block to parse 206 * @block_len: Number of dword elements in the property block 207 * 208 * This function parses the XDomain properties data block into format that 209 * can be traversed using the helper functions provided by this module. 210 * Upon success returns the parsed directory. In case of error returns 211 * %NULL. The resulting &struct tb_property_dir needs to be released by 212 * calling tb_property_free_dir() when not needed anymore. 213 * 214 * The @block is expected to be root directory. 215 */ 216 struct tb_property_dir *tb_property_parse_dir(const u32 *block, 217 size_t block_len) 218 { 219 const struct tb_property_rootdir_entry *rootdir = 220 (const struct tb_property_rootdir_entry *)block; 221 222 if (rootdir->magic != TB_PROPERTY_ROOTDIR_MAGIC) 223 return NULL; 224 if (rootdir->length > block_len) 225 return NULL; 226 227 return __tb_property_parse_dir(block, block_len, 0, rootdir->length, 228 true); 229 } 230 231 /** 232 * tb_property_create_dir() - Creates new property directory 233 * @uuid: UUID used to identify the particular directory 234 * 235 * Creates new, empty property directory. If @uuid is %NULL then the 236 * directory is assumed to be root directory. 237 */ 238 struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid) 239 { 240 struct tb_property_dir *dir; 241 242 dir = kzalloc(sizeof(*dir), GFP_KERNEL); 243 if (!dir) 244 return NULL; 245 246 INIT_LIST_HEAD(&dir->properties); 247 if (uuid) { 248 dir->uuid = kmemdup(uuid, sizeof(*dir->uuid), GFP_KERNEL); 249 if (!dir->uuid) { 250 kfree(dir); 251 return NULL; 252 } 253 } 254 255 return dir; 256 } 257 EXPORT_SYMBOL_GPL(tb_property_create_dir); 258 259 static void tb_property_free(struct tb_property *property) 260 { 261 switch (property->type) { 262 case TB_PROPERTY_TYPE_DIRECTORY: 263 tb_property_free_dir(property->value.dir); 264 break; 265 266 case TB_PROPERTY_TYPE_DATA: 267 kfree(property->value.data); 268 break; 269 270 case TB_PROPERTY_TYPE_TEXT: 271 kfree(property->value.text); 272 break; 273 274 default: 275 break; 276 } 277 278 kfree(property); 279 } 280 281 /** 282 * tb_property_free_dir() - Release memory allocated for property directory 283 * @dir: Directory to release 284 * 285 * This will release all the memory the directory occupies including all 286 * descendants. It is OK to pass %NULL @dir, then the function does 287 * nothing. 288 */ 289 void tb_property_free_dir(struct tb_property_dir *dir) 290 { 291 struct tb_property *property, *tmp; 292 293 if (!dir) 294 return; 295 296 list_for_each_entry_safe(property, tmp, &dir->properties, list) { 297 list_del(&property->list); 298 tb_property_free(property); 299 } 300 kfree(dir->uuid); 301 kfree(dir); 302 } 303 EXPORT_SYMBOL_GPL(tb_property_free_dir); 304 305 static size_t tb_property_dir_length(const struct tb_property_dir *dir, 306 bool recurse, size_t *data_len) 307 { 308 const struct tb_property *property; 309 size_t len = 0; 310 311 if (dir->uuid) 312 len += sizeof(*dir->uuid) / 4; 313 else 314 len += sizeof(struct tb_property_rootdir_entry) / 4; 315 316 list_for_each_entry(property, &dir->properties, list) { 317 len += sizeof(struct tb_property_entry) / 4; 318 319 switch (property->type) { 320 case TB_PROPERTY_TYPE_DIRECTORY: 321 if (recurse) { 322 len += tb_property_dir_length( 323 property->value.dir, recurse, data_len); 324 } 325 /* Reserve dword padding after each directory */ 326 if (data_len) 327 *data_len += 1; 328 break; 329 330 case TB_PROPERTY_TYPE_DATA: 331 case TB_PROPERTY_TYPE_TEXT: 332 if (data_len) 333 *data_len += property->length; 334 break; 335 336 default: 337 break; 338 } 339 } 340 341 return len; 342 } 343 344 static ssize_t __tb_property_format_dir(const struct tb_property_dir *dir, 345 u32 *block, unsigned int start_offset, size_t block_len) 346 { 347 unsigned int data_offset, dir_end; 348 const struct tb_property *property; 349 struct tb_property_entry *entry; 350 size_t dir_len, data_len = 0; 351 int ret; 352 353 /* 354 * The structure of property block looks like following. Leaf 355 * data/text is included right after the directory and each 356 * directory follows each other (even nested ones). 357 * 358 * +----------+ <-- start_offset 359 * | header | <-- root directory header 360 * +----------+ --- 361 * | entry 0 | -^--------------------. 362 * +----------+ | | 363 * | entry 1 | -|--------------------|--. 364 * +----------+ | | | 365 * | entry 2 | -|-----------------. | | 366 * +----------+ | | | | 367 * : : | dir_len | | | 368 * . . | | | | 369 * : : | | | | 370 * +----------+ | | | | 371 * | entry n | v | | | 372 * +----------+ <-- data_offset | | | 373 * | data 0 | <------------------|--' | 374 * +----------+ | | 375 * | data 1 | <------------------|-----' 376 * +----------+ | 377 * | 00000000 | padding | 378 * +----------+ <-- dir_end <------' 379 * | UUID | <-- directory UUID (child directory) 380 * +----------+ 381 * | entry 0 | 382 * +----------+ 383 * | entry 1 | 384 * +----------+ 385 * : : 386 * . . 387 * : : 388 * +----------+ 389 * | entry n | 390 * +----------+ 391 * | data 0 | 392 * +----------+ 393 * 394 * We use dir_end to hold pointer to the end of the directory. It 395 * will increase as we add directories and each directory should be 396 * added starting from previous dir_end. 397 */ 398 dir_len = tb_property_dir_length(dir, false, &data_len); 399 data_offset = start_offset + dir_len; 400 dir_end = start_offset + data_len + dir_len; 401 402 if (data_offset > dir_end) 403 return -EINVAL; 404 if (dir_end > block_len) 405 return -EINVAL; 406 407 /* Write headers first */ 408 if (dir->uuid) { 409 struct tb_property_dir_entry *pe; 410 411 pe = (struct tb_property_dir_entry *)&block[start_offset]; 412 memcpy(pe->uuid, dir->uuid, sizeof(pe->uuid)); 413 entry = pe->entries; 414 } else { 415 struct tb_property_rootdir_entry *re; 416 417 re = (struct tb_property_rootdir_entry *)&block[start_offset]; 418 re->magic = TB_PROPERTY_ROOTDIR_MAGIC; 419 re->length = dir_len - sizeof(*re) / 4; 420 entry = re->entries; 421 } 422 423 list_for_each_entry(property, &dir->properties, list) { 424 const struct tb_property_dir *child; 425 426 format_dwdata(entry, property->key, 2); 427 entry->type = property->type; 428 429 switch (property->type) { 430 case TB_PROPERTY_TYPE_DIRECTORY: 431 child = property->value.dir; 432 ret = __tb_property_format_dir(child, block, dir_end, 433 block_len); 434 if (ret < 0) 435 return ret; 436 entry->length = tb_property_dir_length(child, false, 437 NULL); 438 entry->value = dir_end; 439 dir_end = ret; 440 break; 441 442 case TB_PROPERTY_TYPE_DATA: 443 format_dwdata(&block[data_offset], property->value.data, 444 property->length); 445 entry->length = property->length; 446 entry->value = data_offset; 447 data_offset += entry->length; 448 break; 449 450 case TB_PROPERTY_TYPE_TEXT: 451 format_dwdata(&block[data_offset], property->value.text, 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_VALUE: 459 entry->length = property->length; 460 entry->value = property->value.immediate; 461 break; 462 463 default: 464 break; 465 } 466 467 entry++; 468 } 469 470 return dir_end; 471 } 472 473 /** 474 * tb_property_format_dir() - Formats directory to the packed XDomain format 475 * @dir: Directory to format 476 * @block: Property block where the packed data is placed 477 * @block_len: Length of the property block 478 * 479 * This function formats the directory to the packed format that can be 480 * then send over the thunderbolt fabric to receiving host. Returns %0 in 481 * case of success and negative errno on faulure. Passing %NULL in @block 482 * returns number of entries the block takes. 483 */ 484 ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block, 485 size_t block_len) 486 { 487 ssize_t ret; 488 489 if (!block) { 490 size_t dir_len, data_len = 0; 491 492 dir_len = tb_property_dir_length(dir, true, &data_len); 493 return dir_len + data_len; 494 } 495 496 ret = __tb_property_format_dir(dir, block, 0, block_len); 497 return ret < 0 ? ret : 0; 498 } 499 500 /** 501 * tb_property_add_immediate() - Add immediate property to directory 502 * @parent: Directory to add the property 503 * @key: Key for the property 504 * @value: Immediate value to store with the property 505 */ 506 int tb_property_add_immediate(struct tb_property_dir *parent, const char *key, 507 u32 value) 508 { 509 struct tb_property *property; 510 511 if (!tb_property_key_valid(key)) 512 return -EINVAL; 513 514 property = tb_property_alloc(key, TB_PROPERTY_TYPE_VALUE); 515 if (!property) 516 return -ENOMEM; 517 518 property->length = 1; 519 property->value.immediate = value; 520 521 list_add_tail(&property->list, &parent->properties); 522 return 0; 523 } 524 EXPORT_SYMBOL_GPL(tb_property_add_immediate); 525 526 /** 527 * tb_property_add_data() - Adds arbitrary data property to directory 528 * @parent: Directory to add the property 529 * @key: Key for the property 530 * @buf: Data buffer to add 531 * @buflen: Number of bytes in the data buffer 532 * 533 * Function takes a copy of @buf and adds it to the directory. 534 */ 535 int tb_property_add_data(struct tb_property_dir *parent, const char *key, 536 const void *buf, size_t buflen) 537 { 538 /* Need to pad to dword boundary */ 539 size_t size = round_up(buflen, 4); 540 struct tb_property *property; 541 542 if (!tb_property_key_valid(key)) 543 return -EINVAL; 544 545 property = tb_property_alloc(key, TB_PROPERTY_TYPE_DATA); 546 if (!property) 547 return -ENOMEM; 548 549 property->length = size / 4; 550 property->value.data = kzalloc(size, GFP_KERNEL); 551 memcpy(property->value.data, buf, buflen); 552 553 list_add_tail(&property->list, &parent->properties); 554 return 0; 555 } 556 EXPORT_SYMBOL_GPL(tb_property_add_data); 557 558 /** 559 * tb_property_add_text() - Adds string property to directory 560 * @parent: Directory to add the property 561 * @key: Key for the property 562 * @text: String to add 563 * 564 * Function takes a copy of @text and adds it to the directory. 565 */ 566 int tb_property_add_text(struct tb_property_dir *parent, const char *key, 567 const char *text) 568 { 569 /* Need to pad to dword boundary */ 570 size_t size = round_up(strlen(text) + 1, 4); 571 struct tb_property *property; 572 573 if (!tb_property_key_valid(key)) 574 return -EINVAL; 575 576 property = tb_property_alloc(key, TB_PROPERTY_TYPE_TEXT); 577 if (!property) 578 return -ENOMEM; 579 580 property->length = size / 4; 581 property->value.data = kzalloc(size, GFP_KERNEL); 582 strcpy(property->value.text, text); 583 584 list_add_tail(&property->list, &parent->properties); 585 return 0; 586 } 587 EXPORT_SYMBOL_GPL(tb_property_add_text); 588 589 /** 590 * tb_property_add_dir() - Adds a directory to the parent directory 591 * @parent: Directory to add the property 592 * @key: Key for the property 593 * @dir: Directory to add 594 */ 595 int tb_property_add_dir(struct tb_property_dir *parent, const char *key, 596 struct tb_property_dir *dir) 597 { 598 struct tb_property *property; 599 600 if (!tb_property_key_valid(key)) 601 return -EINVAL; 602 603 property = tb_property_alloc(key, TB_PROPERTY_TYPE_DIRECTORY); 604 if (!property) 605 return -ENOMEM; 606 607 property->value.dir = dir; 608 609 list_add_tail(&property->list, &parent->properties); 610 return 0; 611 } 612 EXPORT_SYMBOL_GPL(tb_property_add_dir); 613 614 /** 615 * tb_property_remove() - Removes property from a parent directory 616 * @property: Property to remove 617 * 618 * Note memory for @property is released as well so it is not allowed to 619 * touch the object after call to this function. 620 */ 621 void tb_property_remove(struct tb_property *property) 622 { 623 list_del(&property->list); 624 kfree(property); 625 } 626 EXPORT_SYMBOL_GPL(tb_property_remove); 627 628 /** 629 * tb_property_find() - Find a property from a directory 630 * @dir: Directory where the property is searched 631 * @key: Key to look for 632 * @type: Type of the property 633 * 634 * Finds and returns property from the given directory. Does not recurse 635 * into sub-directories. Returns %NULL if the property was not found. 636 */ 637 struct tb_property *tb_property_find(struct tb_property_dir *dir, 638 const char *key, enum tb_property_type type) 639 { 640 struct tb_property *property; 641 642 list_for_each_entry(property, &dir->properties, list) { 643 if (property->type == type && !strcmp(property->key, key)) 644 return property; 645 } 646 647 return NULL; 648 } 649 EXPORT_SYMBOL_GPL(tb_property_find); 650 651 /** 652 * tb_property_get_next() - Get next property from directory 653 * @dir: Directory holding properties 654 * @prev: Previous property in the directory (%NULL returns the first) 655 */ 656 struct tb_property *tb_property_get_next(struct tb_property_dir *dir, 657 struct tb_property *prev) 658 { 659 if (prev) { 660 if (list_is_last(&prev->list, &dir->properties)) 661 return NULL; 662 return list_next_entry(prev, list); 663 } 664 return list_first_entry_or_null(&dir->properties, struct tb_property, 665 list); 666 } 667 EXPORT_SYMBOL_GPL(tb_property_get_next); 668