1 // SPDX-License-Identifier: GPL-2.0+
3 * EFI Human Interface Infrastructure ... database and packages
5 * Copyright (c) 2017 Leif Lindholm
6 * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
10 #include <efi_loader.h>
12 #include <asm/unaligned.h>
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;
18 static LIST_HEAD(efi_package_lists);
20 struct efi_hii_packagelist {
21 struct list_head link;
22 // TODO should there be an associated efi_object?
23 efi_handle_t driver_handle;
25 struct list_head string_tables; /* list of efi_string_table */
26 struct list_head guid_list;
28 /* we could also track fonts, images, etc */
31 static int efi_hii_packagelist_exists(efi_hii_handle_t package_list)
33 struct efi_hii_packagelist *hii;
36 list_for_each_entry(hii, &efi_package_lists, link) {
37 if (hii == package_list) {
46 static u32 efi_hii_package_type(struct efi_hii_package_header *header)
50 fields = get_unaligned_le32(&header->fields);
52 return (fields >> __EFI_HII_PACKAGE_TYPE_SHIFT)
53 & __EFI_HII_PACKAGE_TYPE_MASK;
56 static u32 efi_hii_package_len(struct efi_hii_package_header *header)
60 fields = get_unaligned_le32(&header->fields);
62 return (fields >> __EFI_HII_PACKAGE_LEN_SHIFT)
63 & __EFI_HII_PACKAGE_LEN_MASK;
66 struct efi_string_info {
68 /* we could also track font info, etc */
71 struct efi_string_table {
72 struct list_head link;
73 efi_string_id_t language_name;
78 * string id starts at 1 so value is stbl->strings[id-1],
79 * and strings[] is a array of stbl->nstrings elements
81 struct efi_string_info *strings;
84 struct efi_guid_data {
85 struct list_head link;
86 struct efi_hii_guid_package package;
89 static void free_strings_table(struct efi_string_table *stbl)
93 for (i = 0; i < stbl->nstrings; i++)
94 free(stbl->strings[i].string);
100 static void remove_strings_package(struct efi_hii_packagelist *hii)
102 while (!list_empty(&hii->string_tables)) {
103 struct efi_string_table *stbl;
105 stbl = list_first_entry(&hii->string_tables,
106 struct efi_string_table, link);
107 list_del(&stbl->link);
108 free_strings_table(stbl);
113 add_strings_package(struct efi_hii_packagelist *hii,
114 struct efi_hii_strings_package *strings_package)
116 struct efi_hii_string_block *block;
118 u32 nstrings = 0, idx = 0;
119 struct efi_string_table *stbl = NULL;
122 debug("header_size: %08x\n",
123 get_unaligned_le32(&strings_package->header_size));
124 debug("string_info_offset: %08x\n",
125 get_unaligned_le32(&strings_package->string_info_offset));
126 debug("language_name: %u\n",
127 get_unaligned_le16(&strings_package->language_name));
128 debug("language: %s\n", strings_package->language);
130 /* count # of string entries: */
131 end = ((void *)strings_package)
132 + efi_hii_package_len(&strings_package->header);
133 block = ((void *)strings_package)
134 + get_unaligned_le32(&strings_package->string_info_offset);
136 while ((void *)block < end) {
137 switch (block->block_type) {
138 case EFI_HII_SIBT_STRING_UCS2: {
139 struct efi_hii_sibt_string_ucs2_block *ucs2;
141 ucs2 = (void *)block;
143 block = efi_hii_sibt_string_ucs2_block_next(ucs2);
146 case EFI_HII_SIBT_END:
150 debug("unknown HII string block type: %02x\n",
152 return EFI_INVALID_PARAMETER;
156 stbl = calloc(sizeof(*stbl), 1);
158 ret = EFI_OUT_OF_RESOURCES;
161 stbl->strings = calloc(sizeof(stbl->strings[0]), nstrings);
162 if (!stbl->strings) {
163 ret = EFI_OUT_OF_RESOURCES;
166 stbl->language_name =
167 get_unaligned_le16(&strings_package->language_name);
168 stbl->language = strdup((char *)strings_package->language);
169 if (!stbl->language) {
170 ret = EFI_OUT_OF_RESOURCES;
173 stbl->nstrings = nstrings;
175 /* and now parse string entries and populate efi_string_table */
176 block = ((void *)strings_package)
177 + get_unaligned_le32(&strings_package->string_info_offset);
179 while ((void *)block < end) {
180 switch (block->block_type) {
181 case EFI_HII_SIBT_STRING_UCS2: {
182 struct efi_hii_sibt_string_ucs2_block *ucs2;
184 ucs2 = (void *)block;
185 debug("%4u: \"%ls\"\n", idx + 1, ucs2->string_text);
186 stbl->strings[idx].string =
187 u16_strdup(ucs2->string_text);
188 if (!stbl->strings[idx].string) {
189 ret = EFI_OUT_OF_RESOURCES;
193 /* FIXME: accessing u16 * here */
194 block = efi_hii_sibt_string_ucs2_block_next(ucs2);
197 case EFI_HII_SIBT_END:
200 debug("unknown HII string block type: %02x\n",
202 ret = EFI_INVALID_PARAMETER;
208 list_add(&stbl->link, &hii->string_tables);
209 if (hii->max_string_id < nstrings)
210 hii->max_string_id = nstrings;
216 free(stbl->language);
219 free(stbl->strings[idx].string);
227 static void remove_guid_package(struct efi_hii_packagelist *hii)
229 struct efi_guid_data *data;
231 while (!list_empty(&hii->guid_list)) {
232 data = list_first_entry(&hii->guid_list,
233 struct efi_guid_data, link);
234 list_del(&data->link);
240 add_guid_package(struct efi_hii_packagelist *hii,
241 struct efi_hii_guid_package *package)
243 struct efi_guid_data *data;
245 data = calloc(sizeof(*data), 1);
247 return EFI_OUT_OF_RESOURCES;
249 /* TODO: we don't know any about data field */
250 memcpy(&data->package, package, sizeof(*package));
251 list_add_tail(&data->link, &hii->guid_list);
256 static struct efi_hii_packagelist *new_packagelist(void)
258 struct efi_hii_packagelist *hii;
260 hii = malloc(sizeof(*hii));
261 hii->max_string_id = 0;
262 INIT_LIST_HEAD(&hii->string_tables);
263 INIT_LIST_HEAD(&hii->guid_list);
268 static void free_packagelist(struct efi_hii_packagelist *hii)
270 remove_strings_package(hii);
271 remove_guid_package(hii);
273 list_del(&hii->link);
278 add_packages(struct efi_hii_packagelist *hii,
279 const struct efi_hii_package_list_header *package_list)
281 struct efi_hii_package_header *package;
283 efi_status_t ret = EFI_SUCCESS;
285 end = ((void *)package_list)
286 + get_unaligned_le32(&package_list->package_length);
288 debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
289 get_unaligned_le32(&package_list->package_length));
291 package = ((void *)package_list) + sizeof(*package_list);
292 while ((void *)package < end) {
293 debug("package=%p, package type=%x, length=%u\n", package,
294 efi_hii_package_type(package),
295 efi_hii_package_len(package));
297 switch (efi_hii_package_type(package)) {
298 case EFI_HII_PACKAGE_TYPE_GUID:
299 ret = add_guid_package(hii,
300 (struct efi_hii_guid_package *)package);
302 case EFI_HII_PACKAGE_FORMS:
303 printf("\tForm package not supported\n");
304 ret = EFI_INVALID_PARAMETER;
306 case EFI_HII_PACKAGE_STRINGS:
307 ret = add_strings_package(hii,
308 (struct efi_hii_strings_package *)package);
310 case EFI_HII_PACKAGE_FONTS:
311 printf("\tFont package not supported\n");
312 ret = EFI_INVALID_PARAMETER;
314 case EFI_HII_PACKAGE_IMAGES:
315 printf("\tImage package not supported\n");
316 ret = EFI_INVALID_PARAMETER;
318 case EFI_HII_PACKAGE_SIMPLE_FONTS:
319 printf("\tSimple font package not supported\n");
320 ret = EFI_INVALID_PARAMETER;
322 case EFI_HII_PACKAGE_DEVICE_PATH:
323 printf("\tDevice path package not supported\n");
324 ret = EFI_INVALID_PARAMETER;
326 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
327 printf("\tKeyboard layout package not supported\n");
328 ret = EFI_INVALID_PARAMETER;
330 case EFI_HII_PACKAGE_ANIMATIONS:
331 printf("\tAnimation package not supported\n");
332 ret = EFI_INVALID_PARAMETER;
334 case EFI_HII_PACKAGE_END:
336 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
337 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
342 if (ret != EFI_SUCCESS)
345 package = (void *)package + efi_hii_package_len(package);
348 // TODO in theory there is some notifications that should be sent..
353 * EFI_HII_DATABASE_PROTOCOL
356 static efi_status_t EFIAPI
357 new_package_list(const struct efi_hii_database_protocol *this,
358 const struct efi_hii_package_list_header *package_list,
359 const efi_handle_t driver_handle,
360 efi_hii_handle_t *handle)
362 struct efi_hii_packagelist *hii;
365 EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
367 if (!package_list || !handle)
368 return EFI_EXIT(EFI_INVALID_PARAMETER);
370 hii = new_packagelist();
372 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
374 ret = add_packages(hii, package_list);
375 if (ret != EFI_SUCCESS) {
376 free_packagelist(hii);
377 return EFI_EXIT(ret);
380 hii->driver_handle = driver_handle;
381 list_add_tail(&hii->link, &efi_package_lists);
384 return EFI_EXIT(EFI_SUCCESS);
387 static efi_status_t EFIAPI
388 remove_package_list(const struct efi_hii_database_protocol *this,
389 efi_hii_handle_t handle)
391 struct efi_hii_packagelist *hii = handle;
393 EFI_ENTRY("%p, %p", this, handle);
395 if (!handle || !efi_hii_packagelist_exists(handle))
396 return EFI_EXIT(EFI_NOT_FOUND);
398 free_packagelist(hii);
400 return EFI_EXIT(EFI_SUCCESS);
403 static efi_status_t EFIAPI
404 update_package_list(const struct efi_hii_database_protocol *this,
405 efi_hii_handle_t handle,
406 const struct efi_hii_package_list_header *package_list)
408 struct efi_hii_packagelist *hii = handle;
409 struct efi_hii_package_header *package;
411 efi_status_t ret = EFI_SUCCESS;
413 EFI_ENTRY("%p, %p, %p", this, handle, package_list);
415 if (!handle || !efi_hii_packagelist_exists(handle))
416 return EFI_EXIT(EFI_NOT_FOUND);
419 return EFI_EXIT(EFI_INVALID_PARAMETER);
421 debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
422 get_unaligned_le32(&package_list->package_length));
424 package = ((void *)package_list) + sizeof(*package_list);
425 end = ((void *)package_list)
426 + get_unaligned_le32(&package_list->package_length);
428 while ((void *)package < end) {
429 debug("package=%p, package type=%x, length=%u\n", package,
430 efi_hii_package_type(package),
431 efi_hii_package_len(package));
433 switch (efi_hii_package_type(package)) {
434 case EFI_HII_PACKAGE_TYPE_GUID:
435 remove_guid_package(hii);
437 case EFI_HII_PACKAGE_FORMS:
438 printf("\tForm package not supported\n");
439 ret = EFI_INVALID_PARAMETER;
441 case EFI_HII_PACKAGE_STRINGS:
442 remove_strings_package(hii);
444 case EFI_HII_PACKAGE_FONTS:
445 printf("\tFont package not supported\n");
446 ret = EFI_INVALID_PARAMETER;
448 case EFI_HII_PACKAGE_IMAGES:
449 printf("\tImage package not supported\n");
450 ret = EFI_INVALID_PARAMETER;
452 case EFI_HII_PACKAGE_SIMPLE_FONTS:
453 printf("\tSimple font package not supported\n");
454 ret = EFI_INVALID_PARAMETER;
456 case EFI_HII_PACKAGE_DEVICE_PATH:
457 printf("\tDevice path package not supported\n");
458 ret = EFI_INVALID_PARAMETER;
460 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
461 printf("\tKeyboard layout package not supported\n");
463 case EFI_HII_PACKAGE_ANIMATIONS:
464 printf("\tAnimation package not supported\n");
465 ret = EFI_INVALID_PARAMETER;
467 case EFI_HII_PACKAGE_END:
469 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
470 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
475 /* TODO: already removed some packages */
476 if (ret != EFI_SUCCESS)
477 return EFI_EXIT(ret);
479 package = ((void *)package)
480 + efi_hii_package_len(package);
483 ret = add_packages(hii, package_list);
485 return EFI_EXIT(ret);
488 static efi_status_t EFIAPI
489 list_package_lists(const struct efi_hii_database_protocol *this,
491 const efi_guid_t *package_guid,
492 efi_uintn_t *handle_buffer_length,
493 efi_hii_handle_t *handle)
495 struct efi_hii_packagelist *hii =
496 (struct efi_hii_packagelist *)handle;
497 int package_cnt, package_max;
498 efi_status_t ret = EFI_SUCCESS;
500 EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
501 handle_buffer_length, handle);
503 if (!handle_buffer_length ||
504 (*handle_buffer_length && !handle))
505 return EFI_EXIT(EFI_INVALID_PARAMETER);
507 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
508 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
509 return EFI_EXIT(EFI_INVALID_PARAMETER);
511 debug("package type=%x, guid=%pUl, length=%lu\n", (int)package_type,
512 package_guid, *handle_buffer_length);
515 package_max = *handle_buffer_length / sizeof(*handle);
516 list_for_each_entry(hii, &efi_package_lists, link) {
517 switch (package_type) {
518 case EFI_HII_PACKAGE_TYPE_ALL:
520 case EFI_HII_PACKAGE_TYPE_GUID:
521 if (!list_empty(&hii->guid_list))
524 case EFI_HII_PACKAGE_FORMS:
525 printf("\tForm package not supported\n");
526 ret = EFI_INVALID_PARAMETER;
528 case EFI_HII_PACKAGE_STRINGS:
529 if (!list_empty(&hii->string_tables))
532 case EFI_HII_PACKAGE_FONTS:
533 printf("\tFont package not supported\n");
534 ret = EFI_INVALID_PARAMETER;
536 case EFI_HII_PACKAGE_IMAGES:
537 printf("\tImage package not supported\n");
538 ret = EFI_INVALID_PARAMETER;
540 case EFI_HII_PACKAGE_SIMPLE_FONTS:
541 printf("\tSimple font package not supported\n");
542 ret = EFI_INVALID_PARAMETER;
544 case EFI_HII_PACKAGE_DEVICE_PATH:
545 printf("\tDevice path package not supported\n");
546 ret = EFI_INVALID_PARAMETER;
548 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
549 printf("\tKeyboard layout package not supported\n");
551 case EFI_HII_PACKAGE_ANIMATIONS:
552 printf("\tAnimation package not supported\n");
553 ret = EFI_INVALID_PARAMETER;
555 case EFI_HII_PACKAGE_END:
556 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
557 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
563 if (package_cnt <= package_max)
566 ret = EFI_BUFFER_TOO_SMALL;
568 *handle_buffer_length = package_cnt * sizeof(*handle);
570 return EFI_EXIT(ret);
573 static efi_status_t EFIAPI
574 export_package_lists(const struct efi_hii_database_protocol *this,
575 efi_hii_handle_t handle,
576 efi_uintn_t *buffer_size,
577 struct efi_hii_package_list_header *buffer)
579 EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
581 if (!buffer_size || !buffer)
582 return EFI_EXIT(EFI_INVALID_PARAMETER);
584 return EFI_EXIT(EFI_NOT_FOUND);
587 static efi_status_t EFIAPI
588 register_package_notify(const struct efi_hii_database_protocol *this,
590 const efi_guid_t *package_guid,
591 const void *package_notify_fn,
592 efi_uintn_t notify_type,
593 efi_handle_t *notify_handle)
595 EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
596 package_guid, package_notify_fn, notify_type,
600 return EFI_EXIT(EFI_INVALID_PARAMETER);
602 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
603 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
604 return EFI_EXIT(EFI_INVALID_PARAMETER);
606 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
609 static efi_status_t EFIAPI
610 unregister_package_notify(const struct efi_hii_database_protocol *this,
611 efi_handle_t notification_handle)
613 EFI_ENTRY("%p, %p", this, notification_handle);
615 return EFI_EXIT(EFI_NOT_FOUND);
618 static efi_status_t EFIAPI
619 find_keyboard_layouts(const struct efi_hii_database_protocol *this,
620 u16 *key_guid_buffer_length,
621 efi_guid_t *key_guid_buffer)
623 EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
625 return EFI_EXIT(EFI_NOT_FOUND);
628 static efi_status_t EFIAPI
629 get_keyboard_layout(const struct efi_hii_database_protocol *this,
630 efi_guid_t *key_guid,
631 u16 *keyboard_layout_length,
632 struct efi_hii_keyboard_layout *keyboard_layout)
634 EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
637 return EFI_EXIT(EFI_NOT_FOUND);
640 static efi_status_t EFIAPI
641 set_keyboard_layout(const struct efi_hii_database_protocol *this,
642 efi_guid_t *key_guid)
644 EFI_ENTRY("%p, %pUl", this, key_guid);
646 return EFI_EXIT(EFI_NOT_FOUND);
649 static efi_status_t EFIAPI
650 get_package_list_handle(const struct efi_hii_database_protocol *this,
651 efi_hii_handle_t package_list_handle,
652 efi_handle_t *driver_handle)
654 struct efi_hii_packagelist *hii;
656 EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
659 return EFI_EXIT(EFI_INVALID_PARAMETER);
661 list_for_each_entry(hii, &efi_package_lists, link) {
662 if (hii == package_list_handle) {
663 *driver_handle = hii->driver_handle;
664 return EFI_EXIT(EFI_SUCCESS);
668 return EFI_EXIT(EFI_NOT_FOUND);
671 const struct efi_hii_database_protocol efi_hii_database = {
672 .new_package_list = new_package_list,
673 .remove_package_list = remove_package_list,
674 .update_package_list = update_package_list,
675 .list_package_lists = list_package_lists,
676 .export_package_lists = export_package_lists,
677 .register_package_notify = register_package_notify,
678 .unregister_package_notify = unregister_package_notify,
679 .find_keyboard_layouts = find_keyboard_layouts,
680 .get_keyboard_layout = get_keyboard_layout,
681 .set_keyboard_layout = set_keyboard_layout,
682 .get_package_list_handle = get_package_list_handle
686 * EFI_HII_STRING_PROTOCOL
689 static bool language_match(char *language, char *languages)
693 n = strlen(language);
694 /* match primary language? */
695 if (!strncasecmp(language, languages, n) &&
696 (languages[n] == ';' || languages[n] == '\0'))
702 static efi_status_t EFIAPI
703 new_string(const struct efi_hii_string_protocol *this,
704 efi_hii_handle_t package_list,
705 efi_string_id_t *string_id,
707 const u16 *language_name,
708 const efi_string_t string,
709 const struct efi_font_info *string_font_info)
711 struct efi_hii_packagelist *hii = package_list;
712 struct efi_string_table *stbl;
714 EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
715 string_id, language, language_name, string,
718 if (!package_list || !efi_hii_packagelist_exists(package_list))
719 return EFI_EXIT(EFI_NOT_FOUND);
721 if (!string_id || !language || !string)
722 return EFI_EXIT(EFI_INVALID_PARAMETER);
724 list_for_each_entry(stbl, &hii->string_tables, link) {
725 if (language_match((char *)language, stbl->language)) {
726 efi_string_id_t new_id;
730 new_id = ++hii->max_string_id;
731 if (stbl->nstrings < new_id) {
732 buf = realloc(stbl->strings,
733 sizeof(stbl->strings[0])
736 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
738 memset(&stbl->strings[stbl->nstrings], 0,
739 (new_id - stbl->nstrings)
740 * sizeof(stbl->strings[0]));
742 stbl->nstrings = new_id;
745 str = u16_strdup(string);
747 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
749 stbl->strings[new_id - 1].string = str;
752 return EFI_EXIT(EFI_SUCCESS);
756 return EFI_EXIT(EFI_NOT_FOUND);
759 static efi_status_t EFIAPI
760 get_string(const struct efi_hii_string_protocol *this,
762 efi_hii_handle_t package_list,
763 efi_string_id_t string_id,
765 efi_uintn_t *string_size,
766 struct efi_font_info **string_font_info)
768 struct efi_hii_packagelist *hii = package_list;
769 struct efi_string_table *stbl;
771 EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
772 package_list, string_id, string, string_size,
775 if (!package_list || !efi_hii_packagelist_exists(package_list))
776 return EFI_EXIT(EFI_NOT_FOUND);
778 list_for_each_entry(stbl, &hii->string_tables, link) {
779 if (language_match((char *)language, stbl->language)) {
783 if (stbl->nstrings < string_id)
784 return EFI_EXIT(EFI_NOT_FOUND);
786 str = stbl->strings[string_id - 1].string;
788 len = (u16_strlen(str) + 1) * sizeof(u16);
789 if (*string_size < len) {
792 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
794 memcpy(string, str, len);
797 return EFI_EXIT(EFI_NOT_FOUND);
800 return EFI_EXIT(EFI_SUCCESS);
804 return EFI_EXIT(EFI_NOT_FOUND);
807 static efi_status_t EFIAPI
808 set_string(const struct efi_hii_string_protocol *this,
809 efi_hii_handle_t package_list,
810 efi_string_id_t string_id,
812 const efi_string_t string,
813 const struct efi_font_info *string_font_info)
815 struct efi_hii_packagelist *hii = package_list;
816 struct efi_string_table *stbl;
818 EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
819 string_id, language, string, string_font_info);
821 if (!package_list || !efi_hii_packagelist_exists(package_list))
822 return EFI_EXIT(EFI_NOT_FOUND);
824 if (string_id > hii->max_string_id)
825 return EFI_EXIT(EFI_NOT_FOUND);
827 if (!string || !language)
828 return EFI_EXIT(EFI_INVALID_PARAMETER);
830 list_for_each_entry(stbl, &hii->string_tables, link) {
831 if (language_match((char *)language, stbl->language)) {
834 if (hii->max_string_id < string_id)
835 return EFI_EXIT(EFI_NOT_FOUND);
837 if (stbl->nstrings < string_id) {
840 buf = realloc(stbl->strings,
842 * sizeof(stbl->strings[0]));
844 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
846 memset(&stbl->strings[string_id - 1], 0,
847 (string_id - stbl->nstrings)
848 * sizeof(stbl->strings[0]));
852 str = u16_strdup(string);
854 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
856 free(stbl->strings[string_id - 1].string);
857 stbl->strings[string_id - 1].string = str;
859 return EFI_EXIT(EFI_SUCCESS);
863 return EFI_EXIT(EFI_NOT_FOUND);
866 static efi_status_t EFIAPI
867 get_languages(const struct efi_hii_string_protocol *this,
868 efi_hii_handle_t package_list,
870 efi_uintn_t *languages_size)
872 struct efi_hii_packagelist *hii = package_list;
873 struct efi_string_table *stbl;
877 EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
880 if (!package_list || !efi_hii_packagelist_exists(package_list))
881 return EFI_EXIT(EFI_NOT_FOUND);
883 if (!languages_size ||
884 (*languages_size && !languages))
885 return EFI_EXIT(EFI_INVALID_PARAMETER);
887 /* figure out required size: */
888 list_for_each_entry(stbl, &hii->string_tables, link) {
889 len += strlen((char *)stbl->language) + 1;
892 if (*languages_size < len) {
893 *languages_size = len;
895 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
898 p = (char *)languages;
899 list_for_each_entry(stbl, &hii->string_tables, link) {
900 if (p != (char *)languages)
902 strcpy(p, stbl->language);
903 p += strlen((char *)stbl->language);
907 debug("languages: %s\n", languages);
909 return EFI_EXIT(EFI_SUCCESS);
912 static efi_status_t EFIAPI
913 get_secondary_languages(const struct efi_hii_string_protocol *this,
914 efi_hii_handle_t package_list,
915 const u8 *primary_language,
916 u8 *secondary_languages,
917 efi_uintn_t *secondary_languages_size)
919 struct efi_hii_packagelist *hii = package_list;
920 struct efi_string_table *stbl;
923 EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
924 primary_language, secondary_languages,
925 secondary_languages_size);
927 if (!package_list || !efi_hii_packagelist_exists(package_list))
928 return EFI_EXIT(EFI_NOT_FOUND);
930 if (!secondary_languages_size ||
931 (*secondary_languages_size && !secondary_languages))
932 return EFI_EXIT(EFI_INVALID_PARAMETER);
934 list_for_each_entry(stbl, &hii->string_tables, link) {
935 if (language_match((char *)primary_language, stbl->language)) {
941 return EFI_EXIT(EFI_INVALID_LANGUAGE);
944 * TODO: What is secondary language?
945 * *secondary_languages = '\0';
946 * *secondary_languages_size = 0;
949 return EFI_EXIT(EFI_NOT_FOUND);
952 const struct efi_hii_string_protocol efi_hii_string = {
953 .new_string = new_string,
954 .get_string = get_string,
955 .set_string = set_string,
956 .get_languages = get_languages,
957 .get_secondary_languages = get_secondary_languages