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 while (idx > 0) 231 free(stbl->strings[--idx].string); 232 free(stbl->strings); 233 } 234 free(stbl); 235 236 return ret; 237 } 238 239 static void remove_guid_package(struct efi_hii_packagelist *hii) 240 { 241 struct efi_guid_data *data; 242 243 while (!list_empty(&hii->guid_list)) { 244 data = list_first_entry(&hii->guid_list, 245 struct efi_guid_data, link); 246 list_del(&data->link); 247 free(data); 248 } 249 } 250 251 static efi_status_t 252 add_guid_package(struct efi_hii_packagelist *hii, 253 struct efi_hii_guid_package *package) 254 { 255 struct efi_guid_data *data; 256 257 data = calloc(sizeof(*data), 1); 258 if (!data) 259 return EFI_OUT_OF_RESOURCES; 260 261 /* TODO: we don't know any about data field */ 262 memcpy(&data->package, package, sizeof(*package)); 263 list_add_tail(&data->link, &hii->guid_list); 264 265 return EFI_SUCCESS; 266 } 267 268 static void free_keyboard_layouts(struct efi_keyboard_package_data *package) 269 { 270 struct efi_keyboard_layout_data *layout_data; 271 272 while (!list_empty(&package->keyboard_layout_list)) { 273 layout_data = list_first_entry(&package->keyboard_layout_list, 274 struct efi_keyboard_layout_data, 275 link); 276 list_del(&layout_data->link); 277 list_del(&layout_data->link_sys); 278 free(layout_data); 279 } 280 } 281 282 static void remove_keyboard_package(struct efi_hii_packagelist *hii) 283 { 284 struct efi_keyboard_package_data *package; 285 286 while (!list_empty(&hii->keyboard_packages)) { 287 package = list_first_entry(&hii->keyboard_packages, 288 struct efi_keyboard_package_data, 289 link); 290 free_keyboard_layouts(package); 291 list_del(&package->link); 292 free(package); 293 } 294 } 295 296 static efi_status_t 297 add_keyboard_package(struct efi_hii_packagelist *hii, 298 struct efi_hii_keyboard_package *keyboard_package) 299 { 300 struct efi_keyboard_package_data *package_data; 301 struct efi_hii_keyboard_layout *layout; 302 struct efi_keyboard_layout_data *layout_data; 303 u16 layout_count, layout_length; 304 int i; 305 306 package_data = malloc(sizeof(*package_data)); 307 if (!package_data) 308 return EFI_OUT_OF_RESOURCES; 309 INIT_LIST_HEAD(&package_data->link); 310 INIT_LIST_HEAD(&package_data->keyboard_layout_list); 311 312 layout = &keyboard_package->layout[0]; 313 layout_count = get_unaligned_le16(&keyboard_package->layout_count); 314 for (i = 0; i < layout_count; i++) { 315 layout_length = get_unaligned_le16(&layout->layout_length); 316 layout_data = malloc(sizeof(*layout_data) + layout_length); 317 if (!layout_data) 318 goto out; 319 320 memcpy(&layout_data->keyboard_layout, layout, layout_length); 321 list_add_tail(&layout_data->link, 322 &package_data->keyboard_layout_list); 323 list_add_tail(&layout_data->link_sys, 324 &efi_keyboard_layout_list); 325 326 layout += layout_length; 327 } 328 329 list_add_tail(&package_data->link, &hii->keyboard_packages); 330 331 return EFI_SUCCESS; 332 333 out: 334 free_keyboard_layouts(package_data); 335 free(package_data); 336 337 return EFI_OUT_OF_RESOURCES; 338 } 339 340 static struct efi_hii_packagelist *new_packagelist(void) 341 { 342 struct efi_hii_packagelist *hii; 343 344 hii = malloc(sizeof(*hii)); 345 list_add_tail(&hii->link, &efi_package_lists); 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 EFI_PRINT("Form 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 EFI_PRINT("Font package not supported\n"); 399 ret = EFI_INVALID_PARAMETER; 400 break; 401 case EFI_HII_PACKAGE_IMAGES: 402 EFI_PRINT("Image package not supported\n"); 403 ret = EFI_INVALID_PARAMETER; 404 break; 405 case EFI_HII_PACKAGE_SIMPLE_FONTS: 406 EFI_PRINT("Simple font package not supported\n"); 407 ret = EFI_INVALID_PARAMETER; 408 break; 409 case EFI_HII_PACKAGE_DEVICE_PATH: 410 EFI_PRINT("Device 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 EFI_PRINT("Animation 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 *handle = hii; 469 470 return EFI_EXIT(EFI_SUCCESS); 471 } 472 473 static efi_status_t EFIAPI 474 remove_package_list(const struct efi_hii_database_protocol *this, 475 efi_hii_handle_t handle) 476 { 477 struct efi_hii_packagelist *hii = handle; 478 479 EFI_ENTRY("%p, %p", this, handle); 480 481 if (!handle || !efi_hii_packagelist_exists(handle)) 482 return EFI_EXIT(EFI_NOT_FOUND); 483 484 free_packagelist(hii); 485 486 return EFI_EXIT(EFI_SUCCESS); 487 } 488 489 static efi_status_t EFIAPI 490 update_package_list(const struct efi_hii_database_protocol *this, 491 efi_hii_handle_t handle, 492 const struct efi_hii_package_list_header *package_list) 493 { 494 struct efi_hii_packagelist *hii = handle; 495 struct efi_hii_package_header *package; 496 void *end; 497 efi_status_t ret = EFI_SUCCESS; 498 499 EFI_ENTRY("%p, %p, %p", this, handle, package_list); 500 501 if (!handle || !efi_hii_packagelist_exists(handle)) 502 return EFI_EXIT(EFI_NOT_FOUND); 503 504 if (!package_list) 505 return EFI_EXIT(EFI_INVALID_PARAMETER); 506 507 EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid, 508 get_unaligned_le32(&package_list->package_length)); 509 510 package = ((void *)package_list) + sizeof(*package_list); 511 end = ((void *)package_list) 512 + get_unaligned_le32(&package_list->package_length); 513 514 while ((void *)package < end) { 515 EFI_PRINT("package=%p, package type=%x, length=%u\n", package, 516 efi_hii_package_type(package), 517 efi_hii_package_len(package)); 518 519 switch (efi_hii_package_type(package)) { 520 case EFI_HII_PACKAGE_TYPE_GUID: 521 remove_guid_package(hii); 522 break; 523 case EFI_HII_PACKAGE_FORMS: 524 EFI_PRINT("Form package not supported\n"); 525 ret = EFI_INVALID_PARAMETER; 526 break; 527 case EFI_HII_PACKAGE_STRINGS: 528 remove_strings_package(hii); 529 break; 530 case EFI_HII_PACKAGE_FONTS: 531 EFI_PRINT("Font package not supported\n"); 532 ret = EFI_INVALID_PARAMETER; 533 break; 534 case EFI_HII_PACKAGE_IMAGES: 535 EFI_PRINT("Image package not supported\n"); 536 ret = EFI_INVALID_PARAMETER; 537 break; 538 case EFI_HII_PACKAGE_SIMPLE_FONTS: 539 EFI_PRINT("Simple font package not supported\n"); 540 ret = EFI_INVALID_PARAMETER; 541 break; 542 case EFI_HII_PACKAGE_DEVICE_PATH: 543 EFI_PRINT("Device path package not supported\n"); 544 ret = EFI_INVALID_PARAMETER; 545 break; 546 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: 547 remove_keyboard_package(hii); 548 break; 549 case EFI_HII_PACKAGE_ANIMATIONS: 550 EFI_PRINT("Animation package not supported\n"); 551 ret = EFI_INVALID_PARAMETER; 552 break; 553 case EFI_HII_PACKAGE_END: 554 goto out; 555 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN: 556 case EFI_HII_PACKAGE_TYPE_SYSTEM_END: 557 default: 558 break; 559 } 560 561 /* TODO: already removed some packages */ 562 if (ret != EFI_SUCCESS) 563 return EFI_EXIT(ret); 564 565 package = ((void *)package) 566 + efi_hii_package_len(package); 567 } 568 out: 569 ret = add_packages(hii, package_list); 570 571 return EFI_EXIT(ret); 572 } 573 574 static efi_status_t EFIAPI 575 list_package_lists(const struct efi_hii_database_protocol *this, 576 u8 package_type, 577 const efi_guid_t *package_guid, 578 efi_uintn_t *handle_buffer_length, 579 efi_hii_handle_t *handle) 580 { 581 struct efi_hii_packagelist *hii = 582 (struct efi_hii_packagelist *)handle; 583 int package_cnt, package_max; 584 efi_status_t ret = EFI_SUCCESS; 585 586 EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid, 587 handle_buffer_length, handle); 588 589 if (!handle_buffer_length || 590 (*handle_buffer_length && !handle)) 591 return EFI_EXIT(EFI_INVALID_PARAMETER); 592 593 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) || 594 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) 595 return EFI_EXIT(EFI_INVALID_PARAMETER); 596 597 EFI_PRINT("package type=%x, guid=%pUl, length=%zu\n", (int)package_type, 598 package_guid, *handle_buffer_length); 599 600 package_cnt = 0; 601 package_max = *handle_buffer_length / sizeof(*handle); 602 list_for_each_entry(hii, &efi_package_lists, link) { 603 switch (package_type) { 604 case EFI_HII_PACKAGE_TYPE_ALL: 605 break; 606 case EFI_HII_PACKAGE_TYPE_GUID: 607 if (!list_empty(&hii->guid_list)) 608 break; 609 continue; 610 case EFI_HII_PACKAGE_FORMS: 611 EFI_PRINT("Form package not supported\n"); 612 ret = EFI_INVALID_PARAMETER; 613 continue; 614 case EFI_HII_PACKAGE_STRINGS: 615 if (!list_empty(&hii->string_tables)) 616 break; 617 continue; 618 case EFI_HII_PACKAGE_FONTS: 619 EFI_PRINT("Font package not supported\n"); 620 ret = EFI_INVALID_PARAMETER; 621 continue; 622 case EFI_HII_PACKAGE_IMAGES: 623 EFI_PRINT("Image package not supported\n"); 624 ret = EFI_INVALID_PARAMETER; 625 continue; 626 case EFI_HII_PACKAGE_SIMPLE_FONTS: 627 EFI_PRINT("Simple font package not supported\n"); 628 ret = EFI_INVALID_PARAMETER; 629 continue; 630 case EFI_HII_PACKAGE_DEVICE_PATH: 631 EFI_PRINT("Device path package not supported\n"); 632 ret = EFI_INVALID_PARAMETER; 633 continue; 634 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: 635 if (!list_empty(&hii->keyboard_packages)) 636 break; 637 continue; 638 case EFI_HII_PACKAGE_ANIMATIONS: 639 EFI_PRINT("Animation package not supported\n"); 640 ret = EFI_INVALID_PARAMETER; 641 continue; 642 case EFI_HII_PACKAGE_END: 643 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN: 644 case EFI_HII_PACKAGE_TYPE_SYSTEM_END: 645 default: 646 continue; 647 } 648 649 package_cnt++; 650 if (package_cnt <= package_max) 651 *handle++ = hii; 652 else 653 ret = EFI_BUFFER_TOO_SMALL; 654 } 655 *handle_buffer_length = package_cnt * sizeof(*handle); 656 657 return EFI_EXIT(ret); 658 } 659 660 static efi_status_t EFIAPI 661 export_package_lists(const struct efi_hii_database_protocol *this, 662 efi_hii_handle_t handle, 663 efi_uintn_t *buffer_size, 664 struct efi_hii_package_list_header *buffer) 665 { 666 EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer); 667 668 if (!buffer_size || !buffer) 669 return EFI_EXIT(EFI_INVALID_PARAMETER); 670 671 return EFI_EXIT(EFI_NOT_FOUND); 672 } 673 674 static efi_status_t EFIAPI 675 register_package_notify(const struct efi_hii_database_protocol *this, 676 u8 package_type, 677 const efi_guid_t *package_guid, 678 const void *package_notify_fn, 679 efi_uintn_t notify_type, 680 efi_handle_t *notify_handle) 681 { 682 EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type, 683 package_guid, package_notify_fn, notify_type, 684 notify_handle); 685 686 if (!notify_handle) 687 return EFI_EXIT(EFI_INVALID_PARAMETER); 688 689 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) || 690 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) 691 return EFI_EXIT(EFI_INVALID_PARAMETER); 692 693 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 694 } 695 696 static efi_status_t EFIAPI 697 unregister_package_notify(const struct efi_hii_database_protocol *this, 698 efi_handle_t notification_handle) 699 { 700 EFI_ENTRY("%p, %p", this, notification_handle); 701 702 return EFI_EXIT(EFI_NOT_FOUND); 703 } 704 705 static efi_status_t EFIAPI 706 find_keyboard_layouts(const struct efi_hii_database_protocol *this, 707 u16 *key_guid_buffer_length, 708 efi_guid_t *key_guid_buffer) 709 { 710 struct efi_keyboard_layout_data *layout_data; 711 int package_cnt, package_max; 712 efi_status_t ret = EFI_SUCCESS; 713 714 EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer); 715 716 if (!key_guid_buffer_length || 717 (*key_guid_buffer_length && !key_guid_buffer)) 718 return EFI_EXIT(EFI_INVALID_PARAMETER); 719 720 package_cnt = 0; 721 package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer); 722 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) { 723 package_cnt++; 724 if (package_cnt <= package_max) 725 memcpy(key_guid_buffer++, 726 &layout_data->keyboard_layout.guid, 727 sizeof(*key_guid_buffer)); 728 else 729 ret = EFI_BUFFER_TOO_SMALL; 730 } 731 *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer); 732 733 return EFI_EXIT(ret); 734 } 735 736 static efi_status_t EFIAPI 737 get_keyboard_layout(const struct efi_hii_database_protocol *this, 738 efi_guid_t *key_guid, 739 u16 *keyboard_layout_length, 740 struct efi_hii_keyboard_layout *keyboard_layout) 741 { 742 struct efi_keyboard_layout_data *layout_data; 743 u16 layout_length; 744 745 EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length, 746 keyboard_layout); 747 748 if (!keyboard_layout_length || 749 (*keyboard_layout_length && !keyboard_layout)) 750 return EFI_EXIT(EFI_INVALID_PARAMETER); 751 752 /* TODO: no notion of current keyboard layout */ 753 if (!key_guid) 754 return EFI_EXIT(EFI_INVALID_PARAMETER); 755 756 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) { 757 if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid)) 758 goto found; 759 } 760 761 return EFI_EXIT(EFI_NOT_FOUND); 762 763 found: 764 layout_length = 765 get_unaligned_le16(&layout_data->keyboard_layout.layout_length); 766 if (*keyboard_layout_length < layout_length) { 767 *keyboard_layout_length = layout_length; 768 return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 769 } 770 771 memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length); 772 773 return EFI_EXIT(EFI_SUCCESS); 774 } 775 776 static efi_status_t EFIAPI 777 set_keyboard_layout(const struct efi_hii_database_protocol *this, 778 efi_guid_t *key_guid) 779 { 780 EFI_ENTRY("%p, %pUl", this, key_guid); 781 782 return EFI_EXIT(EFI_NOT_FOUND); 783 } 784 785 static efi_status_t EFIAPI 786 get_package_list_handle(const struct efi_hii_database_protocol *this, 787 efi_hii_handle_t package_list_handle, 788 efi_handle_t *driver_handle) 789 { 790 struct efi_hii_packagelist *hii; 791 792 EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle); 793 794 if (!driver_handle) 795 return EFI_EXIT(EFI_INVALID_PARAMETER); 796 797 list_for_each_entry(hii, &efi_package_lists, link) { 798 if (hii == package_list_handle) { 799 *driver_handle = hii->driver_handle; 800 return EFI_EXIT(EFI_SUCCESS); 801 } 802 } 803 804 return EFI_EXIT(EFI_NOT_FOUND); 805 } 806 807 const struct efi_hii_database_protocol efi_hii_database = { 808 .new_package_list = new_package_list, 809 .remove_package_list = remove_package_list, 810 .update_package_list = update_package_list, 811 .list_package_lists = list_package_lists, 812 .export_package_lists = export_package_lists, 813 .register_package_notify = register_package_notify, 814 .unregister_package_notify = unregister_package_notify, 815 .find_keyboard_layouts = find_keyboard_layouts, 816 .get_keyboard_layout = get_keyboard_layout, 817 .set_keyboard_layout = set_keyboard_layout, 818 .get_package_list_handle = get_package_list_handle 819 }; 820 821 /* 822 * EFI_HII_STRING_PROTOCOL 823 */ 824 825 static bool language_match(char *language, char *languages) 826 { 827 size_t n; 828 829 n = strlen(language); 830 /* match primary language? */ 831 if (!strncasecmp(language, languages, n) && 832 (languages[n] == ';' || languages[n] == '\0')) 833 return true; 834 835 return false; 836 } 837 838 static efi_status_t EFIAPI 839 new_string(const struct efi_hii_string_protocol *this, 840 efi_hii_handle_t package_list, 841 efi_string_id_t *string_id, 842 const u8 *language, 843 const u16 *language_name, 844 const efi_string_t string, 845 const struct efi_font_info *string_font_info) 846 { 847 struct efi_hii_packagelist *hii = package_list; 848 struct efi_string_table *stbl; 849 850 EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list, 851 string_id, language, language_name, string, 852 string_font_info); 853 854 if (!package_list || !efi_hii_packagelist_exists(package_list)) 855 return EFI_EXIT(EFI_NOT_FOUND); 856 857 if (!string_id || !language || !string) 858 return EFI_EXIT(EFI_INVALID_PARAMETER); 859 860 list_for_each_entry(stbl, &hii->string_tables, link) { 861 if (language_match((char *)language, stbl->language)) { 862 efi_string_id_t new_id; 863 void *buf; 864 efi_string_t str; 865 866 new_id = ++hii->max_string_id; 867 if (stbl->nstrings < new_id) { 868 buf = realloc(stbl->strings, 869 sizeof(stbl->strings[0]) 870 * new_id); 871 if (!buf) 872 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 873 874 memset(&stbl->strings[stbl->nstrings], 0, 875 (new_id - stbl->nstrings) 876 * sizeof(stbl->strings[0])); 877 stbl->strings = buf; 878 stbl->nstrings = new_id; 879 } 880 881 str = u16_strdup(string); 882 if (!str) 883 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 884 885 stbl->strings[new_id - 1].string = str; 886 *string_id = new_id; 887 888 return EFI_EXIT(EFI_SUCCESS); 889 } 890 } 891 892 return EFI_EXIT(EFI_NOT_FOUND); 893 } 894 895 static efi_status_t EFIAPI 896 get_string(const struct efi_hii_string_protocol *this, 897 const u8 *language, 898 efi_hii_handle_t package_list, 899 efi_string_id_t string_id, 900 efi_string_t string, 901 efi_uintn_t *string_size, 902 struct efi_font_info **string_font_info) 903 { 904 struct efi_hii_packagelist *hii = package_list; 905 struct efi_string_table *stbl; 906 907 EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language, 908 package_list, string_id, string, string_size, 909 string_font_info); 910 911 if (!package_list || !efi_hii_packagelist_exists(package_list)) 912 return EFI_EXIT(EFI_NOT_FOUND); 913 914 list_for_each_entry(stbl, &hii->string_tables, link) { 915 if (language_match((char *)language, stbl->language)) { 916 efi_string_t str; 917 size_t len; 918 919 if (stbl->nstrings < string_id) 920 return EFI_EXIT(EFI_NOT_FOUND); 921 922 str = stbl->strings[string_id - 1].string; 923 if (str) { 924 len = (u16_strlen(str) + 1) * sizeof(u16); 925 if (*string_size < len) { 926 *string_size = len; 927 928 return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 929 } 930 memcpy(string, str, len); 931 *string_size = len; 932 } else { 933 return EFI_EXIT(EFI_NOT_FOUND); 934 } 935 936 return EFI_EXIT(EFI_SUCCESS); 937 } 938 } 939 940 return EFI_EXIT(EFI_NOT_FOUND); 941 } 942 943 static efi_status_t EFIAPI 944 set_string(const struct efi_hii_string_protocol *this, 945 efi_hii_handle_t package_list, 946 efi_string_id_t string_id, 947 const u8 *language, 948 const efi_string_t string, 949 const struct efi_font_info *string_font_info) 950 { 951 struct efi_hii_packagelist *hii = package_list; 952 struct efi_string_table *stbl; 953 954 EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list, 955 string_id, language, string, string_font_info); 956 957 if (!package_list || !efi_hii_packagelist_exists(package_list)) 958 return EFI_EXIT(EFI_NOT_FOUND); 959 960 if (string_id > hii->max_string_id) 961 return EFI_EXIT(EFI_NOT_FOUND); 962 963 if (!string || !language) 964 return EFI_EXIT(EFI_INVALID_PARAMETER); 965 966 list_for_each_entry(stbl, &hii->string_tables, link) { 967 if (language_match((char *)language, stbl->language)) { 968 efi_string_t str; 969 970 if (hii->max_string_id < string_id) 971 return EFI_EXIT(EFI_NOT_FOUND); 972 973 if (stbl->nstrings < string_id) { 974 void *buf; 975 976 buf = realloc(stbl->strings, 977 string_id 978 * sizeof(stbl->strings[0])); 979 if (!buf) 980 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 981 982 memset(&stbl->strings[string_id - 1], 0, 983 (string_id - stbl->nstrings) 984 * sizeof(stbl->strings[0])); 985 stbl->strings = buf; 986 } 987 988 str = u16_strdup(string); 989 if (!str) 990 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 991 992 free(stbl->strings[string_id - 1].string); 993 stbl->strings[string_id - 1].string = str; 994 995 return EFI_EXIT(EFI_SUCCESS); 996 } 997 } 998 999 return EFI_EXIT(EFI_NOT_FOUND); 1000 } 1001 1002 static efi_status_t EFIAPI 1003 get_languages(const struct efi_hii_string_protocol *this, 1004 efi_hii_handle_t package_list, 1005 u8 *languages, 1006 efi_uintn_t *languages_size) 1007 { 1008 struct efi_hii_packagelist *hii = package_list; 1009 struct efi_string_table *stbl; 1010 size_t len = 0; 1011 char *p; 1012 1013 EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages, 1014 languages_size); 1015 1016 if (!package_list || !efi_hii_packagelist_exists(package_list)) 1017 return EFI_EXIT(EFI_NOT_FOUND); 1018 1019 if (!languages_size || 1020 (*languages_size && !languages)) 1021 return EFI_EXIT(EFI_INVALID_PARAMETER); 1022 1023 /* figure out required size: */ 1024 list_for_each_entry(stbl, &hii->string_tables, link) { 1025 len += strlen((char *)stbl->language) + 1; 1026 } 1027 1028 if (*languages_size < len) { 1029 *languages_size = len; 1030 1031 return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 1032 } 1033 1034 p = (char *)languages; 1035 list_for_each_entry(stbl, &hii->string_tables, link) { 1036 if (p != (char *)languages) 1037 *p++ = ';'; 1038 strcpy(p, stbl->language); 1039 p += strlen((char *)stbl->language); 1040 } 1041 *p = '\0'; 1042 1043 EFI_PRINT("languages: %s\n", languages); 1044 1045 return EFI_EXIT(EFI_SUCCESS); 1046 } 1047 1048 static efi_status_t EFIAPI 1049 get_secondary_languages(const struct efi_hii_string_protocol *this, 1050 efi_hii_handle_t package_list, 1051 const u8 *primary_language, 1052 u8 *secondary_languages, 1053 efi_uintn_t *secondary_languages_size) 1054 { 1055 struct efi_hii_packagelist *hii = package_list; 1056 struct efi_string_table *stbl; 1057 bool found = false; 1058 1059 EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list, 1060 primary_language, secondary_languages, 1061 secondary_languages_size); 1062 1063 if (!package_list || !efi_hii_packagelist_exists(package_list)) 1064 return EFI_EXIT(EFI_NOT_FOUND); 1065 1066 if (!secondary_languages_size || 1067 (*secondary_languages_size && !secondary_languages)) 1068 return EFI_EXIT(EFI_INVALID_PARAMETER); 1069 1070 list_for_each_entry(stbl, &hii->string_tables, link) { 1071 if (language_match((char *)primary_language, stbl->language)) { 1072 found = true; 1073 break; 1074 } 1075 } 1076 if (!found) 1077 return EFI_EXIT(EFI_INVALID_LANGUAGE); 1078 1079 /* 1080 * TODO: What is secondary language? 1081 * *secondary_languages = '\0'; 1082 * *secondary_languages_size = 0; 1083 */ 1084 1085 return EFI_EXIT(EFI_NOT_FOUND); 1086 } 1087 1088 const struct efi_hii_string_protocol efi_hii_string = { 1089 .new_string = new_string, 1090 .get_string = get_string, 1091 .set_string = set_string, 1092 .get_languages = get_languages, 1093 .get_secondary_languages = get_secondary_languages 1094 }; 1095