1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * EFI Human Interface Infrastructure ... database and packages 4 * 5 * Copyright (c) 2017 Leif Lindholm 6 * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited 7 */ 8 9 #include <common.h> 10 #include <efi_loader.h> 11 #include <malloc.h> 12 #include <asm/unaligned.h> 13 14 const efi_guid_t efi_guid_hii_database_protocol 15 = EFI_HII_DATABASE_PROTOCOL_GUID; 16 const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID; 17 18 static LIST_HEAD(efi_package_lists); 19 static LIST_HEAD(efi_keyboard_layout_list); 20 21 struct efi_hii_packagelist { 22 struct list_head link; 23 // TODO should there be an associated efi_object? 24 efi_handle_t driver_handle; 25 u32 max_string_id; 26 struct list_head string_tables; /* list of efi_string_table */ 27 struct list_head guid_list; 28 struct list_head keyboard_packages; 29 30 /* we could also track fonts, images, etc */ 31 }; 32 33 static int efi_hii_packagelist_exists(efi_hii_handle_t package_list) 34 { 35 struct efi_hii_packagelist *hii; 36 int found = 0; 37 38 list_for_each_entry(hii, &efi_package_lists, link) { 39 if (hii == package_list) { 40 found = 1; 41 break; 42 } 43 } 44 45 return found; 46 } 47 48 static u32 efi_hii_package_type(struct efi_hii_package_header *header) 49 { 50 u32 fields; 51 52 fields = get_unaligned_le32(&header->fields); 53 54 return (fields >> __EFI_HII_PACKAGE_TYPE_SHIFT) 55 & __EFI_HII_PACKAGE_TYPE_MASK; 56 } 57 58 static u32 efi_hii_package_len(struct efi_hii_package_header *header) 59 { 60 u32 fields; 61 62 fields = get_unaligned_le32(&header->fields); 63 64 return (fields >> __EFI_HII_PACKAGE_LEN_SHIFT) 65 & __EFI_HII_PACKAGE_LEN_MASK; 66 } 67 68 struct efi_string_info { 69 efi_string_t string; 70 /* we could also track font info, etc */ 71 }; 72 73 struct efi_string_table { 74 struct list_head link; 75 efi_string_id_t language_name; 76 char *language; 77 u32 nstrings; 78 /* 79 * NOTE: 80 * string id starts at 1 so value is stbl->strings[id-1], 81 * and strings[] is a array of stbl->nstrings elements 82 */ 83 struct efi_string_info *strings; 84 }; 85 86 struct efi_guid_data { 87 struct list_head link; 88 struct efi_hii_guid_package package; 89 }; 90 91 struct efi_keyboard_layout_data { 92 struct list_head link; /* in package */ 93 struct list_head link_sys; /* in global list */ 94 struct efi_hii_keyboard_layout keyboard_layout; 95 }; 96 97 struct efi_keyboard_package_data { 98 struct list_head link; /* in package_list */ 99 struct list_head keyboard_layout_list; 100 }; 101 102 static void free_strings_table(struct efi_string_table *stbl) 103 { 104 int i; 105 106 for (i = 0; i < stbl->nstrings; i++) 107 free(stbl->strings[i].string); 108 free(stbl->strings); 109 free(stbl->language); 110 free(stbl); 111 } 112 113 static void remove_strings_package(struct efi_hii_packagelist *hii) 114 { 115 while (!list_empty(&hii->string_tables)) { 116 struct efi_string_table *stbl; 117 118 stbl = list_first_entry(&hii->string_tables, 119 struct efi_string_table, link); 120 list_del(&stbl->link); 121 free_strings_table(stbl); 122 } 123 } 124 125 static efi_status_t 126 add_strings_package(struct efi_hii_packagelist *hii, 127 struct efi_hii_strings_package *strings_package) 128 { 129 struct efi_hii_string_block *block; 130 void *end; 131 u32 nstrings = 0, idx = 0; 132 struct efi_string_table *stbl = NULL; 133 efi_status_t ret; 134 135 EFI_PRINT("header_size: %08x\n", 136 get_unaligned_le32(&strings_package->header_size)); 137 EFI_PRINT("string_info_offset: %08x\n", 138 get_unaligned_le32(&strings_package->string_info_offset)); 139 EFI_PRINT("language_name: %u\n", 140 get_unaligned_le16(&strings_package->language_name)); 141 EFI_PRINT("language: %s\n", strings_package->language); 142 143 /* count # of string entries: */ 144 end = ((void *)strings_package) 145 + efi_hii_package_len(&strings_package->header); 146 block = ((void *)strings_package) 147 + get_unaligned_le32(&strings_package->string_info_offset); 148 149 while ((void *)block < end) { 150 switch (block->block_type) { 151 case EFI_HII_SIBT_STRING_UCS2: { 152 struct efi_hii_sibt_string_ucs2_block *ucs2; 153 154 ucs2 = (void *)block; 155 nstrings++; 156 block = efi_hii_sibt_string_ucs2_block_next(ucs2); 157 break; 158 } 159 case EFI_HII_SIBT_END: 160 block = end; 161 break; 162 default: 163 EFI_PRINT("unknown HII string block type: %02x\n", 164 block->block_type); 165 return EFI_INVALID_PARAMETER; 166 } 167 } 168 169 stbl = calloc(sizeof(*stbl), 1); 170 if (!stbl) { 171 ret = EFI_OUT_OF_RESOURCES; 172 goto error; 173 } 174 stbl->strings = calloc(sizeof(stbl->strings[0]), nstrings); 175 if (!stbl->strings) { 176 ret = EFI_OUT_OF_RESOURCES; 177 goto error; 178 } 179 stbl->language_name = 180 get_unaligned_le16(&strings_package->language_name); 181 stbl->language = strdup((char *)strings_package->language); 182 if (!stbl->language) { 183 ret = EFI_OUT_OF_RESOURCES; 184 goto error; 185 } 186 stbl->nstrings = nstrings; 187 188 /* and now parse string entries and populate efi_string_table */ 189 block = ((void *)strings_package) 190 + get_unaligned_le32(&strings_package->string_info_offset); 191 192 while ((void *)block < end) { 193 switch (block->block_type) { 194 case EFI_HII_SIBT_STRING_UCS2: { 195 struct efi_hii_sibt_string_ucs2_block *ucs2; 196 197 ucs2 = (void *)block; 198 EFI_PRINT("%4u: \"%ls\"\n", idx + 1, ucs2->string_text); 199 stbl->strings[idx].string = 200 u16_strdup(ucs2->string_text); 201 if (!stbl->strings[idx].string) { 202 ret = EFI_OUT_OF_RESOURCES; 203 goto error; 204 } 205 idx++; 206 /* FIXME: accessing u16 * here */ 207 block = efi_hii_sibt_string_ucs2_block_next(ucs2); 208 break; 209 } 210 case EFI_HII_SIBT_END: 211 goto out; 212 default: 213 EFI_PRINT("unknown HII string block type: %02x\n", 214 block->block_type); 215 ret = EFI_INVALID_PARAMETER; 216 goto error; 217 } 218 } 219 220 out: 221 list_add(&stbl->link, &hii->string_tables); 222 if (hii->max_string_id < nstrings) 223 hii->max_string_id = nstrings; 224 225 return EFI_SUCCESS; 226 227 error: 228 if (stbl) { 229 free(stbl->language); 230 if (idx > 0) 231 while (--idx >= 0) 232 free(stbl->strings[idx].string); 233 free(stbl->strings); 234 } 235 free(stbl); 236 237 return ret; 238 } 239 240 static void remove_guid_package(struct efi_hii_packagelist *hii) 241 { 242 struct efi_guid_data *data; 243 244 while (!list_empty(&hii->guid_list)) { 245 data = list_first_entry(&hii->guid_list, 246 struct efi_guid_data, link); 247 list_del(&data->link); 248 free(data); 249 } 250 } 251 252 static efi_status_t 253 add_guid_package(struct efi_hii_packagelist *hii, 254 struct efi_hii_guid_package *package) 255 { 256 struct efi_guid_data *data; 257 258 data = calloc(sizeof(*data), 1); 259 if (!data) 260 return EFI_OUT_OF_RESOURCES; 261 262 /* TODO: we don't know any about data field */ 263 memcpy(&data->package, package, sizeof(*package)); 264 list_add_tail(&data->link, &hii->guid_list); 265 266 return EFI_SUCCESS; 267 } 268 269 static void free_keyboard_layouts(struct efi_keyboard_package_data *package) 270 { 271 struct efi_keyboard_layout_data *layout_data; 272 273 while (!list_empty(&package->keyboard_layout_list)) { 274 layout_data = list_first_entry(&package->keyboard_layout_list, 275 struct efi_keyboard_layout_data, 276 link); 277 list_del(&layout_data->link); 278 list_del(&layout_data->link_sys); 279 free(layout_data); 280 } 281 } 282 283 static void remove_keyboard_package(struct efi_hii_packagelist *hii) 284 { 285 struct efi_keyboard_package_data *package; 286 287 while (!list_empty(&hii->keyboard_packages)) { 288 package = list_first_entry(&hii->keyboard_packages, 289 struct efi_keyboard_package_data, 290 link); 291 free_keyboard_layouts(package); 292 list_del(&package->link); 293 free(package); 294 } 295 } 296 297 static efi_status_t 298 add_keyboard_package(struct efi_hii_packagelist *hii, 299 struct efi_hii_keyboard_package *keyboard_package) 300 { 301 struct efi_keyboard_package_data *package_data; 302 struct efi_hii_keyboard_layout *layout; 303 struct efi_keyboard_layout_data *layout_data; 304 u16 layout_count, layout_length; 305 int i; 306 307 package_data = malloc(sizeof(*package_data)); 308 if (!package_data) 309 return EFI_OUT_OF_RESOURCES; 310 INIT_LIST_HEAD(&package_data->link); 311 INIT_LIST_HEAD(&package_data->keyboard_layout_list); 312 313 layout = &keyboard_package->layout[0]; 314 layout_count = get_unaligned_le16(&keyboard_package->layout_count); 315 for (i = 0; i < layout_count; i++) { 316 layout_length = get_unaligned_le16(&layout->layout_length); 317 layout_data = malloc(sizeof(*layout_data) + layout_length); 318 if (!layout_data) 319 goto out; 320 321 memcpy(&layout_data->keyboard_layout, layout, layout_length); 322 list_add_tail(&layout_data->link, 323 &package_data->keyboard_layout_list); 324 list_add_tail(&layout_data->link_sys, 325 &efi_keyboard_layout_list); 326 327 layout += layout_length; 328 } 329 330 list_add_tail(&package_data->link, &hii->keyboard_packages); 331 332 return EFI_SUCCESS; 333 334 out: 335 free_keyboard_layouts(package_data); 336 free(package_data); 337 338 return EFI_OUT_OF_RESOURCES; 339 } 340 341 static struct efi_hii_packagelist *new_packagelist(void) 342 { 343 struct efi_hii_packagelist *hii; 344 345 hii = malloc(sizeof(*hii)); 346 hii->max_string_id = 0; 347 INIT_LIST_HEAD(&hii->string_tables); 348 INIT_LIST_HEAD(&hii->guid_list); 349 INIT_LIST_HEAD(&hii->keyboard_packages); 350 351 return hii; 352 } 353 354 static void free_packagelist(struct efi_hii_packagelist *hii) 355 { 356 remove_strings_package(hii); 357 remove_guid_package(hii); 358 remove_keyboard_package(hii); 359 360 list_del(&hii->link); 361 free(hii); 362 } 363 364 static efi_status_t 365 add_packages(struct efi_hii_packagelist *hii, 366 const struct efi_hii_package_list_header *package_list) 367 { 368 struct efi_hii_package_header *package; 369 void *end; 370 efi_status_t ret = EFI_SUCCESS; 371 372 end = ((void *)package_list) 373 + get_unaligned_le32(&package_list->package_length); 374 375 EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid, 376 get_unaligned_le32(&package_list->package_length)); 377 378 package = ((void *)package_list) + sizeof(*package_list); 379 while ((void *)package < end) { 380 EFI_PRINT("package=%p, package type=%x, length=%u\n", package, 381 efi_hii_package_type(package), 382 efi_hii_package_len(package)); 383 384 switch (efi_hii_package_type(package)) { 385 case EFI_HII_PACKAGE_TYPE_GUID: 386 ret = add_guid_package(hii, 387 (struct efi_hii_guid_package *)package); 388 break; 389 case EFI_HII_PACKAGE_FORMS: 390 printf("\tForm package not supported\n"); 391 ret = EFI_INVALID_PARAMETER; 392 break; 393 case EFI_HII_PACKAGE_STRINGS: 394 ret = add_strings_package(hii, 395 (struct efi_hii_strings_package *)package); 396 break; 397 case EFI_HII_PACKAGE_FONTS: 398 printf("\tFont package not supported\n"); 399 ret = EFI_INVALID_PARAMETER; 400 break; 401 case EFI_HII_PACKAGE_IMAGES: 402 printf("\tImage package not supported\n"); 403 ret = EFI_INVALID_PARAMETER; 404 break; 405 case EFI_HII_PACKAGE_SIMPLE_FONTS: 406 printf("\tSimple font package not supported\n"); 407 ret = EFI_INVALID_PARAMETER; 408 break; 409 case EFI_HII_PACKAGE_DEVICE_PATH: 410 printf("\tDevice path package not supported\n"); 411 ret = EFI_INVALID_PARAMETER; 412 break; 413 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: 414 ret = add_keyboard_package(hii, 415 (struct efi_hii_keyboard_package *)package); 416 break; 417 case EFI_HII_PACKAGE_ANIMATIONS: 418 printf("\tAnimation package not supported\n"); 419 ret = EFI_INVALID_PARAMETER; 420 break; 421 case EFI_HII_PACKAGE_END: 422 goto out; 423 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN: 424 case EFI_HII_PACKAGE_TYPE_SYSTEM_END: 425 default: 426 break; 427 } 428 429 if (ret != EFI_SUCCESS) 430 return ret; 431 432 package = (void *)package + efi_hii_package_len(package); 433 } 434 out: 435 // TODO in theory there is some notifications that should be sent.. 436 return EFI_SUCCESS; 437 } 438 439 /* 440 * EFI_HII_DATABASE_PROTOCOL 441 */ 442 443 static efi_status_t EFIAPI 444 new_package_list(const struct efi_hii_database_protocol *this, 445 const struct efi_hii_package_list_header *package_list, 446 const efi_handle_t driver_handle, 447 efi_hii_handle_t *handle) 448 { 449 struct efi_hii_packagelist *hii; 450 efi_status_t ret; 451 452 EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle); 453 454 if (!package_list || !handle) 455 return EFI_EXIT(EFI_INVALID_PARAMETER); 456 457 hii = new_packagelist(); 458 if (!hii) 459 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 460 461 ret = add_packages(hii, package_list); 462 if (ret != EFI_SUCCESS) { 463 free_packagelist(hii); 464 return EFI_EXIT(ret); 465 } 466 467 hii->driver_handle = driver_handle; 468 list_add_tail(&hii->link, &efi_package_lists); 469 *handle = hii; 470 471 return EFI_EXIT(EFI_SUCCESS); 472 } 473 474 static efi_status_t EFIAPI 475 remove_package_list(const struct efi_hii_database_protocol *this, 476 efi_hii_handle_t handle) 477 { 478 struct efi_hii_packagelist *hii = handle; 479 480 EFI_ENTRY("%p, %p", this, handle); 481 482 if (!handle || !efi_hii_packagelist_exists(handle)) 483 return EFI_EXIT(EFI_NOT_FOUND); 484 485 free_packagelist(hii); 486 487 return EFI_EXIT(EFI_SUCCESS); 488 } 489 490 static efi_status_t EFIAPI 491 update_package_list(const struct efi_hii_database_protocol *this, 492 efi_hii_handle_t handle, 493 const struct efi_hii_package_list_header *package_list) 494 { 495 struct efi_hii_packagelist *hii = handle; 496 struct efi_hii_package_header *package; 497 void *end; 498 efi_status_t ret = EFI_SUCCESS; 499 500 EFI_ENTRY("%p, %p, %p", this, handle, package_list); 501 502 if (!handle || !efi_hii_packagelist_exists(handle)) 503 return EFI_EXIT(EFI_NOT_FOUND); 504 505 if (!package_list) 506 return EFI_EXIT(EFI_INVALID_PARAMETER); 507 508 EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid, 509 get_unaligned_le32(&package_list->package_length)); 510 511 package = ((void *)package_list) + sizeof(*package_list); 512 end = ((void *)package_list) 513 + get_unaligned_le32(&package_list->package_length); 514 515 while ((void *)package < end) { 516 EFI_PRINT("package=%p, package type=%x, length=%u\n", package, 517 efi_hii_package_type(package), 518 efi_hii_package_len(package)); 519 520 switch (efi_hii_package_type(package)) { 521 case EFI_HII_PACKAGE_TYPE_GUID: 522 remove_guid_package(hii); 523 break; 524 case EFI_HII_PACKAGE_FORMS: 525 printf("\tForm package not supported\n"); 526 ret = EFI_INVALID_PARAMETER; 527 break; 528 case EFI_HII_PACKAGE_STRINGS: 529 remove_strings_package(hii); 530 break; 531 case EFI_HII_PACKAGE_FONTS: 532 printf("\tFont package not supported\n"); 533 ret = EFI_INVALID_PARAMETER; 534 break; 535 case EFI_HII_PACKAGE_IMAGES: 536 printf("\tImage package not supported\n"); 537 ret = EFI_INVALID_PARAMETER; 538 break; 539 case EFI_HII_PACKAGE_SIMPLE_FONTS: 540 printf("\tSimple font package not supported\n"); 541 ret = EFI_INVALID_PARAMETER; 542 break; 543 case EFI_HII_PACKAGE_DEVICE_PATH: 544 printf("\tDevice path package not supported\n"); 545 ret = EFI_INVALID_PARAMETER; 546 break; 547 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: 548 remove_keyboard_package(hii); 549 break; 550 case EFI_HII_PACKAGE_ANIMATIONS: 551 printf("\tAnimation package not supported\n"); 552 ret = EFI_INVALID_PARAMETER; 553 break; 554 case EFI_HII_PACKAGE_END: 555 goto out; 556 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN: 557 case EFI_HII_PACKAGE_TYPE_SYSTEM_END: 558 default: 559 break; 560 } 561 562 /* TODO: already removed some packages */ 563 if (ret != EFI_SUCCESS) 564 return EFI_EXIT(ret); 565 566 package = ((void *)package) 567 + efi_hii_package_len(package); 568 } 569 out: 570 ret = add_packages(hii, package_list); 571 572 return EFI_EXIT(ret); 573 } 574 575 static efi_status_t EFIAPI 576 list_package_lists(const struct efi_hii_database_protocol *this, 577 u8 package_type, 578 const efi_guid_t *package_guid, 579 efi_uintn_t *handle_buffer_length, 580 efi_hii_handle_t *handle) 581 { 582 struct efi_hii_packagelist *hii = 583 (struct efi_hii_packagelist *)handle; 584 int package_cnt, package_max; 585 efi_status_t ret = EFI_SUCCESS; 586 587 EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid, 588 handle_buffer_length, handle); 589 590 if (!handle_buffer_length || 591 (*handle_buffer_length && !handle)) 592 return EFI_EXIT(EFI_INVALID_PARAMETER); 593 594 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) || 595 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) 596 return EFI_EXIT(EFI_INVALID_PARAMETER); 597 598 EFI_PRINT("package type=%x, guid=%pUl, length=%zu\n", (int)package_type, 599 package_guid, *handle_buffer_length); 600 601 package_cnt = 0; 602 package_max = *handle_buffer_length / sizeof(*handle); 603 list_for_each_entry(hii, &efi_package_lists, link) { 604 switch (package_type) { 605 case EFI_HII_PACKAGE_TYPE_ALL: 606 break; 607 case EFI_HII_PACKAGE_TYPE_GUID: 608 if (!list_empty(&hii->guid_list)) 609 break; 610 continue; 611 case EFI_HII_PACKAGE_FORMS: 612 printf("\tForm package not supported\n"); 613 ret = EFI_INVALID_PARAMETER; 614 continue; 615 case EFI_HII_PACKAGE_STRINGS: 616 if (!list_empty(&hii->string_tables)) 617 break; 618 continue; 619 case EFI_HII_PACKAGE_FONTS: 620 printf("\tFont package not supported\n"); 621 ret = EFI_INVALID_PARAMETER; 622 continue; 623 case EFI_HII_PACKAGE_IMAGES: 624 printf("\tImage package not supported\n"); 625 ret = EFI_INVALID_PARAMETER; 626 continue; 627 case EFI_HII_PACKAGE_SIMPLE_FONTS: 628 printf("\tSimple font package not supported\n"); 629 ret = EFI_INVALID_PARAMETER; 630 continue; 631 case EFI_HII_PACKAGE_DEVICE_PATH: 632 printf("\tDevice path package not supported\n"); 633 ret = EFI_INVALID_PARAMETER; 634 continue; 635 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: 636 if (!list_empty(&hii->keyboard_packages)) 637 break; 638 continue; 639 case EFI_HII_PACKAGE_ANIMATIONS: 640 printf("\tAnimation package not supported\n"); 641 ret = EFI_INVALID_PARAMETER; 642 continue; 643 case EFI_HII_PACKAGE_END: 644 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN: 645 case EFI_HII_PACKAGE_TYPE_SYSTEM_END: 646 default: 647 continue; 648 } 649 650 package_cnt++; 651 if (package_cnt <= package_max) 652 *handle++ = hii; 653 else 654 ret = EFI_BUFFER_TOO_SMALL; 655 } 656 *handle_buffer_length = package_cnt * sizeof(*handle); 657 658 return EFI_EXIT(ret); 659 } 660 661 static efi_status_t EFIAPI 662 export_package_lists(const struct efi_hii_database_protocol *this, 663 efi_hii_handle_t handle, 664 efi_uintn_t *buffer_size, 665 struct efi_hii_package_list_header *buffer) 666 { 667 EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer); 668 669 if (!buffer_size || !buffer) 670 return EFI_EXIT(EFI_INVALID_PARAMETER); 671 672 return EFI_EXIT(EFI_NOT_FOUND); 673 } 674 675 static efi_status_t EFIAPI 676 register_package_notify(const struct efi_hii_database_protocol *this, 677 u8 package_type, 678 const efi_guid_t *package_guid, 679 const void *package_notify_fn, 680 efi_uintn_t notify_type, 681 efi_handle_t *notify_handle) 682 { 683 EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type, 684 package_guid, package_notify_fn, notify_type, 685 notify_handle); 686 687 if (!notify_handle) 688 return EFI_EXIT(EFI_INVALID_PARAMETER); 689 690 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) || 691 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) 692 return EFI_EXIT(EFI_INVALID_PARAMETER); 693 694 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 695 } 696 697 static efi_status_t EFIAPI 698 unregister_package_notify(const struct efi_hii_database_protocol *this, 699 efi_handle_t notification_handle) 700 { 701 EFI_ENTRY("%p, %p", this, notification_handle); 702 703 return EFI_EXIT(EFI_NOT_FOUND); 704 } 705 706 static efi_status_t EFIAPI 707 find_keyboard_layouts(const struct efi_hii_database_protocol *this, 708 u16 *key_guid_buffer_length, 709 efi_guid_t *key_guid_buffer) 710 { 711 struct efi_keyboard_layout_data *layout_data; 712 int package_cnt, package_max; 713 efi_status_t ret = EFI_SUCCESS; 714 715 EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer); 716 717 if (!key_guid_buffer_length || 718 (*key_guid_buffer_length && !key_guid_buffer)) 719 return EFI_EXIT(EFI_INVALID_PARAMETER); 720 721 package_cnt = 0; 722 package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer); 723 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) { 724 package_cnt++; 725 if (package_cnt <= package_max) 726 memcpy(key_guid_buffer++, 727 &layout_data->keyboard_layout.guid, 728 sizeof(*key_guid_buffer)); 729 else 730 ret = EFI_BUFFER_TOO_SMALL; 731 } 732 *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer); 733 734 return EFI_EXIT(ret); 735 } 736 737 static efi_status_t EFIAPI 738 get_keyboard_layout(const struct efi_hii_database_protocol *this, 739 efi_guid_t *key_guid, 740 u16 *keyboard_layout_length, 741 struct efi_hii_keyboard_layout *keyboard_layout) 742 { 743 struct efi_keyboard_layout_data *layout_data; 744 u16 layout_length; 745 746 EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length, 747 keyboard_layout); 748 749 if (!keyboard_layout_length || 750 (*keyboard_layout_length && !keyboard_layout)) 751 return EFI_EXIT(EFI_INVALID_PARAMETER); 752 753 /* TODO: no notion of current keyboard layout */ 754 if (!key_guid) 755 return EFI_EXIT(EFI_INVALID_PARAMETER); 756 757 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) { 758 if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid)) 759 goto found; 760 } 761 762 return EFI_EXIT(EFI_NOT_FOUND); 763 764 found: 765 layout_length = 766 get_unaligned_le16(&layout_data->keyboard_layout.layout_length); 767 if (*keyboard_layout_length < layout_length) { 768 *keyboard_layout_length = layout_length; 769 return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 770 } 771 772 memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length); 773 774 return EFI_EXIT(EFI_SUCCESS); 775 } 776 777 static efi_status_t EFIAPI 778 set_keyboard_layout(const struct efi_hii_database_protocol *this, 779 efi_guid_t *key_guid) 780 { 781 EFI_ENTRY("%p, %pUl", this, key_guid); 782 783 return EFI_EXIT(EFI_NOT_FOUND); 784 } 785 786 static efi_status_t EFIAPI 787 get_package_list_handle(const struct efi_hii_database_protocol *this, 788 efi_hii_handle_t package_list_handle, 789 efi_handle_t *driver_handle) 790 { 791 struct efi_hii_packagelist *hii; 792 793 EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle); 794 795 if (!driver_handle) 796 return EFI_EXIT(EFI_INVALID_PARAMETER); 797 798 list_for_each_entry(hii, &efi_package_lists, link) { 799 if (hii == package_list_handle) { 800 *driver_handle = hii->driver_handle; 801 return EFI_EXIT(EFI_SUCCESS); 802 } 803 } 804 805 return EFI_EXIT(EFI_NOT_FOUND); 806 } 807 808 const struct efi_hii_database_protocol efi_hii_database = { 809 .new_package_list = new_package_list, 810 .remove_package_list = remove_package_list, 811 .update_package_list = update_package_list, 812 .list_package_lists = list_package_lists, 813 .export_package_lists = export_package_lists, 814 .register_package_notify = register_package_notify, 815 .unregister_package_notify = unregister_package_notify, 816 .find_keyboard_layouts = find_keyboard_layouts, 817 .get_keyboard_layout = get_keyboard_layout, 818 .set_keyboard_layout = set_keyboard_layout, 819 .get_package_list_handle = get_package_list_handle 820 }; 821 822 /* 823 * EFI_HII_STRING_PROTOCOL 824 */ 825 826 static bool language_match(char *language, char *languages) 827 { 828 size_t n; 829 830 n = strlen(language); 831 /* match primary language? */ 832 if (!strncasecmp(language, languages, n) && 833 (languages[n] == ';' || languages[n] == '\0')) 834 return true; 835 836 return false; 837 } 838 839 static efi_status_t EFIAPI 840 new_string(const struct efi_hii_string_protocol *this, 841 efi_hii_handle_t package_list, 842 efi_string_id_t *string_id, 843 const u8 *language, 844 const u16 *language_name, 845 const efi_string_t string, 846 const struct efi_font_info *string_font_info) 847 { 848 struct efi_hii_packagelist *hii = package_list; 849 struct efi_string_table *stbl; 850 851 EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list, 852 string_id, language, language_name, string, 853 string_font_info); 854 855 if (!package_list || !efi_hii_packagelist_exists(package_list)) 856 return EFI_EXIT(EFI_NOT_FOUND); 857 858 if (!string_id || !language || !string) 859 return EFI_EXIT(EFI_INVALID_PARAMETER); 860 861 list_for_each_entry(stbl, &hii->string_tables, link) { 862 if (language_match((char *)language, stbl->language)) { 863 efi_string_id_t new_id; 864 void *buf; 865 efi_string_t str; 866 867 new_id = ++hii->max_string_id; 868 if (stbl->nstrings < new_id) { 869 buf = realloc(stbl->strings, 870 sizeof(stbl->strings[0]) 871 * new_id); 872 if (!buf) 873 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 874 875 memset(&stbl->strings[stbl->nstrings], 0, 876 (new_id - stbl->nstrings) 877 * sizeof(stbl->strings[0])); 878 stbl->strings = buf; 879 stbl->nstrings = new_id; 880 } 881 882 str = u16_strdup(string); 883 if (!str) 884 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 885 886 stbl->strings[new_id - 1].string = str; 887 *string_id = new_id; 888 889 return EFI_EXIT(EFI_SUCCESS); 890 } 891 } 892 893 return EFI_EXIT(EFI_NOT_FOUND); 894 } 895 896 static efi_status_t EFIAPI 897 get_string(const struct efi_hii_string_protocol *this, 898 const u8 *language, 899 efi_hii_handle_t package_list, 900 efi_string_id_t string_id, 901 efi_string_t string, 902 efi_uintn_t *string_size, 903 struct efi_font_info **string_font_info) 904 { 905 struct efi_hii_packagelist *hii = package_list; 906 struct efi_string_table *stbl; 907 908 EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language, 909 package_list, string_id, string, string_size, 910 string_font_info); 911 912 if (!package_list || !efi_hii_packagelist_exists(package_list)) 913 return EFI_EXIT(EFI_NOT_FOUND); 914 915 list_for_each_entry(stbl, &hii->string_tables, link) { 916 if (language_match((char *)language, stbl->language)) { 917 efi_string_t str; 918 size_t len; 919 920 if (stbl->nstrings < string_id) 921 return EFI_EXIT(EFI_NOT_FOUND); 922 923 str = stbl->strings[string_id - 1].string; 924 if (str) { 925 len = (u16_strlen(str) + 1) * sizeof(u16); 926 if (*string_size < len) { 927 *string_size = len; 928 929 return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 930 } 931 memcpy(string, str, len); 932 *string_size = len; 933 } else { 934 return EFI_EXIT(EFI_NOT_FOUND); 935 } 936 937 return EFI_EXIT(EFI_SUCCESS); 938 } 939 } 940 941 return EFI_EXIT(EFI_NOT_FOUND); 942 } 943 944 static efi_status_t EFIAPI 945 set_string(const struct efi_hii_string_protocol *this, 946 efi_hii_handle_t package_list, 947 efi_string_id_t string_id, 948 const u8 *language, 949 const efi_string_t string, 950 const struct efi_font_info *string_font_info) 951 { 952 struct efi_hii_packagelist *hii = package_list; 953 struct efi_string_table *stbl; 954 955 EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list, 956 string_id, language, string, string_font_info); 957 958 if (!package_list || !efi_hii_packagelist_exists(package_list)) 959 return EFI_EXIT(EFI_NOT_FOUND); 960 961 if (string_id > hii->max_string_id) 962 return EFI_EXIT(EFI_NOT_FOUND); 963 964 if (!string || !language) 965 return EFI_EXIT(EFI_INVALID_PARAMETER); 966 967 list_for_each_entry(stbl, &hii->string_tables, link) { 968 if (language_match((char *)language, stbl->language)) { 969 efi_string_t str; 970 971 if (hii->max_string_id < string_id) 972 return EFI_EXIT(EFI_NOT_FOUND); 973 974 if (stbl->nstrings < string_id) { 975 void *buf; 976 977 buf = realloc(stbl->strings, 978 string_id 979 * sizeof(stbl->strings[0])); 980 if (!buf) 981 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 982 983 memset(&stbl->strings[string_id - 1], 0, 984 (string_id - stbl->nstrings) 985 * sizeof(stbl->strings[0])); 986 stbl->strings = buf; 987 } 988 989 str = u16_strdup(string); 990 if (!str) 991 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 992 993 free(stbl->strings[string_id - 1].string); 994 stbl->strings[string_id - 1].string = str; 995 996 return EFI_EXIT(EFI_SUCCESS); 997 } 998 } 999 1000 return EFI_EXIT(EFI_NOT_FOUND); 1001 } 1002 1003 static efi_status_t EFIAPI 1004 get_languages(const struct efi_hii_string_protocol *this, 1005 efi_hii_handle_t package_list, 1006 u8 *languages, 1007 efi_uintn_t *languages_size) 1008 { 1009 struct efi_hii_packagelist *hii = package_list; 1010 struct efi_string_table *stbl; 1011 size_t len = 0; 1012 char *p; 1013 1014 EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages, 1015 languages_size); 1016 1017 if (!package_list || !efi_hii_packagelist_exists(package_list)) 1018 return EFI_EXIT(EFI_NOT_FOUND); 1019 1020 if (!languages_size || 1021 (*languages_size && !languages)) 1022 return EFI_EXIT(EFI_INVALID_PARAMETER); 1023 1024 /* figure out required size: */ 1025 list_for_each_entry(stbl, &hii->string_tables, link) { 1026 len += strlen((char *)stbl->language) + 1; 1027 } 1028 1029 if (*languages_size < len) { 1030 *languages_size = len; 1031 1032 return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 1033 } 1034 1035 p = (char *)languages; 1036 list_for_each_entry(stbl, &hii->string_tables, link) { 1037 if (p != (char *)languages) 1038 *p++ = ';'; 1039 strcpy(p, stbl->language); 1040 p += strlen((char *)stbl->language); 1041 } 1042 *p = '\0'; 1043 1044 EFI_PRINT("languages: %s\n", languages); 1045 1046 return EFI_EXIT(EFI_SUCCESS); 1047 } 1048 1049 static efi_status_t EFIAPI 1050 get_secondary_languages(const struct efi_hii_string_protocol *this, 1051 efi_hii_handle_t package_list, 1052 const u8 *primary_language, 1053 u8 *secondary_languages, 1054 efi_uintn_t *secondary_languages_size) 1055 { 1056 struct efi_hii_packagelist *hii = package_list; 1057 struct efi_string_table *stbl; 1058 bool found = false; 1059 1060 EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list, 1061 primary_language, secondary_languages, 1062 secondary_languages_size); 1063 1064 if (!package_list || !efi_hii_packagelist_exists(package_list)) 1065 return EFI_EXIT(EFI_NOT_FOUND); 1066 1067 if (!secondary_languages_size || 1068 (*secondary_languages_size && !secondary_languages)) 1069 return EFI_EXIT(EFI_INVALID_PARAMETER); 1070 1071 list_for_each_entry(stbl, &hii->string_tables, link) { 1072 if (language_match((char *)primary_language, stbl->language)) { 1073 found = true; 1074 break; 1075 } 1076 } 1077 if (!found) 1078 return EFI_EXIT(EFI_INVALID_LANGUAGE); 1079 1080 /* 1081 * TODO: What is secondary language? 1082 * *secondary_languages = '\0'; 1083 * *secondary_languages_size = 0; 1084 */ 1085 1086 return EFI_EXIT(EFI_NOT_FOUND); 1087 } 1088 1089 const struct efi_hii_string_protocol efi_hii_string = { 1090 .new_string = new_string, 1091 .get_string = get_string, 1092 .set_string = set_string, 1093 .get_languages = get_languages, 1094 .get_secondary_languages = get_secondary_languages 1095 }; 1096