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; efi_create_current_boot_var(u16 var_name[],size_t var_name_size)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 efi_get_dp_from_boot(const efi_guid_t guid)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_NOT_FOUND; 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 ret = EFI_INVALID_PARAMETER; 592 goto out; 593 } 594 595 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) || 596 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) { 597 ret = EFI_INVALID_PARAMETER; 598 goto out; 599 } 600 601 EFI_PRINT("package type=%x, guid=%pUl, length=%zu\n", (int)package_type, 602 package_guid, *handle_buffer_length); 603 604 package_cnt = 0; 605 package_max = *handle_buffer_length / sizeof(*handle); 606 list_for_each_entry(hii, &efi_package_lists, link) { 607 switch (package_type) { 608 case EFI_HII_PACKAGE_TYPE_ALL: 609 break; 610 case EFI_HII_PACKAGE_TYPE_GUID: 611 if (!list_empty(&hii->guid_list)) 612 break; 613 continue; 614 case EFI_HII_PACKAGE_STRINGS: 615 if (!list_empty(&hii->string_tables)) 616 break; 617 continue; 618 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: 619 if (!list_empty(&hii->keyboard_packages)) 620 break; 621 continue; 622 default: 623 continue; 624 } 625 626 package_cnt++; 627 if (package_cnt <= package_max) { 628 *handle++ = hii; 629 ret = EFI_SUCCESS; 630 } else { 631 ret = EFI_BUFFER_TOO_SMALL; 632 } 633 } 634 *handle_buffer_length = package_cnt * sizeof(*handle); 635 out: 636 return EFI_EXIT(ret); 637 } 638 639 static efi_status_t EFIAPI 640 export_package_lists(const struct efi_hii_database_protocol *this, 641 efi_hii_handle_t handle, 642 efi_uintn_t *buffer_size, 643 struct efi_hii_package_list_header *buffer) 644 { 645 EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer); 646 647 if (!buffer_size || !buffer) 648 return EFI_EXIT(EFI_INVALID_PARAMETER); 649 650 return EFI_EXIT(EFI_NOT_FOUND); 651 } 652 653 static efi_status_t EFIAPI 654 register_package_notify(const struct efi_hii_database_protocol *this, 655 u8 package_type, 656 const efi_guid_t *package_guid, 657 const void *package_notify_fn, 658 efi_uintn_t notify_type, 659 efi_handle_t *notify_handle) 660 { 661 EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type, 662 package_guid, package_notify_fn, notify_type, 663 notify_handle); 664 665 if (!notify_handle) 666 return EFI_EXIT(EFI_INVALID_PARAMETER); 667 668 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) || 669 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) 670 return EFI_EXIT(EFI_INVALID_PARAMETER); 671 672 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 673 } 674 675 static efi_status_t EFIAPI 676 unregister_package_notify(const struct efi_hii_database_protocol *this, 677 efi_handle_t notification_handle) 678 { 679 EFI_ENTRY("%p, %p", this, notification_handle); 680 681 return EFI_EXIT(EFI_NOT_FOUND); 682 } 683 684 static efi_status_t EFIAPI 685 find_keyboard_layouts(const struct efi_hii_database_protocol *this, 686 u16 *key_guid_buffer_length, 687 efi_guid_t *key_guid_buffer) 688 { 689 struct efi_keyboard_layout_data *layout_data; 690 int package_cnt, package_max; 691 efi_status_t ret = EFI_SUCCESS; 692 693 EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer); 694 695 if (!key_guid_buffer_length || 696 (*key_guid_buffer_length && !key_guid_buffer)) 697 return EFI_EXIT(EFI_INVALID_PARAMETER); 698 699 package_cnt = 0; 700 package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer); 701 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) { 702 package_cnt++; 703 if (package_cnt <= package_max) 704 memcpy(key_guid_buffer++, 705 &layout_data->keyboard_layout.guid, 706 sizeof(*key_guid_buffer)); 707 else 708 ret = EFI_BUFFER_TOO_SMALL; 709 } 710 *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer); 711 712 return EFI_EXIT(ret); 713 } 714 715 static efi_status_t EFIAPI 716 get_keyboard_layout(const struct efi_hii_database_protocol *this, 717 efi_guid_t *key_guid, 718 u16 *keyboard_layout_length, 719 struct efi_hii_keyboard_layout *keyboard_layout) 720 { 721 struct efi_keyboard_layout_data *layout_data; 722 u16 layout_length; 723 724 EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length, 725 keyboard_layout); 726 727 if (!keyboard_layout_length || 728 (*keyboard_layout_length && !keyboard_layout)) 729 return EFI_EXIT(EFI_INVALID_PARAMETER); 730 731 /* TODO: no notion of current keyboard layout */ 732 if (!key_guid) 733 return EFI_EXIT(EFI_INVALID_PARAMETER); 734 735 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) { 736 if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid)) 737 goto found; 738 } 739 740 return EFI_EXIT(EFI_NOT_FOUND); 741 742 found: 743 layout_length = 744 get_unaligned_le16(&layout_data->keyboard_layout.layout_length); 745 if (*keyboard_layout_length < layout_length) { 746 *keyboard_layout_length = layout_length; 747 return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 748 } 749 750 memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length); 751 752 return EFI_EXIT(EFI_SUCCESS); 753 } 754 755 static efi_status_t EFIAPI 756 set_keyboard_layout(const struct efi_hii_database_protocol *this, 757 efi_guid_t *key_guid) 758 { 759 EFI_ENTRY("%p, %pUl", this, key_guid); 760 761 return EFI_EXIT(EFI_NOT_FOUND); 762 } 763 764 static efi_status_t EFIAPI 765 get_package_list_handle(const struct efi_hii_database_protocol *this, 766 efi_hii_handle_t package_list_handle, 767 efi_handle_t *driver_handle) 768 { 769 struct efi_hii_packagelist *hii; 770 771 EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle); 772 773 if (!driver_handle) 774 return EFI_EXIT(EFI_INVALID_PARAMETER); 775 776 list_for_each_entry(hii, &efi_package_lists, link) { 777 if (hii == package_list_handle) { 778 *driver_handle = hii->driver_handle; 779 return EFI_EXIT(EFI_SUCCESS); 780 } 781 } 782 783 return EFI_EXIT(EFI_NOT_FOUND); 784 } 785 786 const struct efi_hii_database_protocol efi_hii_database = { 787 .new_package_list = new_package_list, 788 .remove_package_list = remove_package_list, 789 .update_package_list = update_package_list, 790 .list_package_lists = list_package_lists, 791 .export_package_lists = export_package_lists, 792 .register_package_notify = register_package_notify, 793 .unregister_package_notify = unregister_package_notify, 794 .find_keyboard_layouts = find_keyboard_layouts, 795 .get_keyboard_layout = get_keyboard_layout, 796 .set_keyboard_layout = set_keyboard_layout, 797 .get_package_list_handle = get_package_list_handle 798 }; 799 800 /* 801 * EFI_HII_STRING_PROTOCOL 802 */ 803 804 static bool language_match(char *language, char *languages) 805 { 806 size_t n; 807 808 n = strlen(language); 809 /* match primary language? */ 810 if (!strncasecmp(language, languages, n) && 811 (languages[n] == ';' || languages[n] == '\0')) 812 return true; 813 814 return false; 815 } 816 817 static efi_status_t EFIAPI 818 new_string(const struct efi_hii_string_protocol *this, 819 efi_hii_handle_t package_list, 820 efi_string_id_t *string_id, 821 const u8 *language, 822 const u16 *language_name, 823 const efi_string_t string, 824 const struct efi_font_info *string_font_info) 825 { 826 struct efi_hii_packagelist *hii = package_list; 827 struct efi_string_table *stbl; 828 829 EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list, 830 string_id, language, language_name, string, 831 string_font_info); 832 833 if (!package_list || !efi_hii_packagelist_exists(package_list)) 834 return EFI_EXIT(EFI_NOT_FOUND); 835 836 if (!string_id || !language || !string) 837 return EFI_EXIT(EFI_INVALID_PARAMETER); 838 839 list_for_each_entry(stbl, &hii->string_tables, link) { 840 if (language_match((char *)language, stbl->language)) { 841 efi_string_id_t new_id; 842 void *buf; 843 efi_string_t str; 844 845 new_id = ++hii->max_string_id; 846 if (stbl->nstrings < new_id) { 847 buf = realloc(stbl->strings, 848 sizeof(stbl->strings[0]) 849 * new_id); 850 if (!buf) 851 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 852 853 memset(&stbl->strings[stbl->nstrings], 0, 854 (new_id - stbl->nstrings) 855 * sizeof(stbl->strings[0])); 856 stbl->strings = buf; 857 stbl->nstrings = new_id; 858 } 859 860 str = u16_strdup(string); 861 if (!str) 862 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 863 864 stbl->strings[new_id - 1].string = str; 865 *string_id = new_id; 866 867 return EFI_EXIT(EFI_SUCCESS); 868 } 869 } 870 871 return EFI_EXIT(EFI_NOT_FOUND); 872 } 873 874 static efi_status_t EFIAPI 875 get_string(const struct efi_hii_string_protocol *this, 876 const u8 *language, 877 efi_hii_handle_t package_list, 878 efi_string_id_t string_id, 879 efi_string_t string, 880 efi_uintn_t *string_size, 881 struct efi_font_info **string_font_info) 882 { 883 struct efi_hii_packagelist *hii = package_list; 884 struct efi_string_table *stbl; 885 886 EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language, 887 package_list, string_id, string, string_size, 888 string_font_info); 889 890 if (!package_list || !efi_hii_packagelist_exists(package_list)) 891 return EFI_EXIT(EFI_NOT_FOUND); 892 893 list_for_each_entry(stbl, &hii->string_tables, link) { 894 if (language_match((char *)language, stbl->language)) { 895 efi_string_t str; 896 size_t len; 897 898 if (stbl->nstrings < string_id) 899 return EFI_EXIT(EFI_NOT_FOUND); 900 901 str = stbl->strings[string_id - 1].string; 902 if (str) { 903 len = (u16_strlen(str) + 1) * sizeof(u16); 904 if (*string_size < len) { 905 *string_size = len; 906 907 return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 908 } 909 memcpy(string, str, len); 910 *string_size = len; 911 } else { 912 return EFI_EXIT(EFI_NOT_FOUND); 913 } 914 915 return EFI_EXIT(EFI_SUCCESS); 916 } 917 } 918 919 return EFI_EXIT(EFI_NOT_FOUND); 920 } 921 922 static efi_status_t EFIAPI 923 set_string(const struct efi_hii_string_protocol *this, 924 efi_hii_handle_t package_list, 925 efi_string_id_t string_id, 926 const u8 *language, 927 const efi_string_t string, 928 const struct efi_font_info *string_font_info) 929 { 930 struct efi_hii_packagelist *hii = package_list; 931 struct efi_string_table *stbl; 932 933 EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list, 934 string_id, language, string, string_font_info); 935 936 if (!package_list || !efi_hii_packagelist_exists(package_list)) 937 return EFI_EXIT(EFI_NOT_FOUND); 938 939 if (string_id > hii->max_string_id) 940 return EFI_EXIT(EFI_NOT_FOUND); 941 942 if (!string || !language) 943 return EFI_EXIT(EFI_INVALID_PARAMETER); 944 945 list_for_each_entry(stbl, &hii->string_tables, link) { 946 if (language_match((char *)language, stbl->language)) { 947 efi_string_t str; 948 949 if (hii->max_string_id < string_id) 950 return EFI_EXIT(EFI_NOT_FOUND); 951 952 if (stbl->nstrings < string_id) { 953 void *buf; 954 955 buf = realloc(stbl->strings, 956 string_id 957 * sizeof(stbl->strings[0])); 958 if (!buf) 959 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 960 961 memset(&stbl->strings[string_id - 1], 0, 962 (string_id - stbl->nstrings) 963 * sizeof(stbl->strings[0])); 964 stbl->strings = buf; 965 } 966 967 str = u16_strdup(string); 968 if (!str) 969 return EFI_EXIT(EFI_OUT_OF_RESOURCES); 970 971 free(stbl->strings[string_id - 1].string); 972 stbl->strings[string_id - 1].string = str; 973 974 return EFI_EXIT(EFI_SUCCESS); 975 } 976 } 977 978 return EFI_EXIT(EFI_NOT_FOUND); 979 } 980 981 static efi_status_t EFIAPI 982 get_languages(const struct efi_hii_string_protocol *this, 983 efi_hii_handle_t package_list, 984 u8 *languages, 985 efi_uintn_t *languages_size) 986 { 987 struct efi_hii_packagelist *hii = package_list; 988 struct efi_string_table *stbl; 989 size_t len = 0; 990 char *p; 991 992 EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages, 993 languages_size); 994 995 if (!package_list || !efi_hii_packagelist_exists(package_list)) 996 return EFI_EXIT(EFI_NOT_FOUND); 997 998 if (!languages_size || 999 (*languages_size && !languages)) 1000 return EFI_EXIT(EFI_INVALID_PARAMETER); 1001 1002 /* figure out required size: */ 1003 list_for_each_entry(stbl, &hii->string_tables, link) { 1004 len += strlen((char *)stbl->language) + 1; 1005 } 1006 1007 if (*languages_size < len) { 1008 *languages_size = len; 1009 1010 return EFI_EXIT(EFI_BUFFER_TOO_SMALL); 1011 } 1012 1013 p = (char *)languages; 1014 list_for_each_entry(stbl, &hii->string_tables, link) { 1015 if (p != (char *)languages) 1016 *p++ = ';'; 1017 strcpy(p, stbl->language); 1018 p += strlen((char *)stbl->language); 1019 } 1020 *p = '\0'; 1021 1022 EFI_PRINT("languages: %s\n", languages); 1023 1024 return EFI_EXIT(EFI_SUCCESS); 1025 } 1026 1027 static efi_status_t EFIAPI 1028 get_secondary_languages(const struct efi_hii_string_protocol *this, 1029 efi_hii_handle_t package_list, 1030 const u8 *primary_language, 1031 u8 *secondary_languages, 1032 efi_uintn_t *secondary_languages_size) 1033 { 1034 struct efi_hii_packagelist *hii = package_list; 1035 struct efi_string_table *stbl; 1036 bool found = false; 1037 1038 EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list, 1039 primary_language, secondary_languages, 1040 secondary_languages_size); 1041 1042 if (!package_list || !efi_hii_packagelist_exists(package_list)) 1043 return EFI_EXIT(EFI_NOT_FOUND); 1044 1045 if (!secondary_languages_size || 1046 (*secondary_languages_size && !secondary_languages)) 1047 return EFI_EXIT(EFI_INVALID_PARAMETER); 1048 1049 list_for_each_entry(stbl, &hii->string_tables, link) { 1050 if (language_match((char *)primary_language, stbl->language)) { 1051 found = true; 1052 break; 1053 } 1054 } 1055 if (!found) 1056 return EFI_EXIT(EFI_INVALID_LANGUAGE); 1057 1058 /* 1059 * TODO: What is secondary language? 1060 * *secondary_languages = '\0'; 1061 * *secondary_languages_size = 0; 1062 */ 1063 1064 return EFI_EXIT(EFI_NOT_FOUND); 1065 } 1066 1067 const struct efi_hii_string_protocol efi_hii_string = { 1068 .new_string = new_string, 1069 .get_string = get_string, 1070 .set_string = set_string, 1071 .get_languages = get_languages, 1072 .get_secondary_languages = get_secondary_languages 1073 }; 1074