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