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);
19 static LIST_HEAD(efi_keyboard_layout_list);
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;
26 struct list_head string_tables; /* list of efi_string_table */
27 struct list_head guid_list;
28 struct list_head keyboard_packages;
30 /* we could also track fonts, images, etc */
33 static int efi_hii_packagelist_exists(efi_hii_handle_t package_list)
35 struct efi_hii_packagelist *hii;
38 list_for_each_entry(hii, &efi_package_lists, link) {
39 if (hii == package_list) {
48 static u32 efi_hii_package_type(struct efi_hii_package_header *header)
52 fields = get_unaligned_le32(&header->fields);
54 return (fields >> __EFI_HII_PACKAGE_TYPE_SHIFT)
55 & __EFI_HII_PACKAGE_TYPE_MASK;
58 static u32 efi_hii_package_len(struct efi_hii_package_header *header)
62 fields = get_unaligned_le32(&header->fields);
64 return (fields >> __EFI_HII_PACKAGE_LEN_SHIFT)
65 & __EFI_HII_PACKAGE_LEN_MASK;
68 struct efi_string_info {
70 /* we could also track font info, etc */
73 struct efi_string_table {
74 struct list_head link;
75 efi_string_id_t language_name;
80 * string id starts at 1 so value is stbl->strings[id-1],
81 * and strings[] is a array of stbl->nstrings elements
83 struct efi_string_info *strings;
86 struct efi_guid_data {
87 struct list_head link;
88 struct efi_hii_guid_package package;
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;
97 struct efi_keyboard_package_data {
98 struct list_head link; /* in package_list */
99 struct list_head keyboard_layout_list;
102 static void free_strings_table(struct efi_string_table *stbl)
106 for (i = 0; i < stbl->nstrings; i++)
107 free(stbl->strings[i].string);
109 free(stbl->language);
113 static void remove_strings_package(struct efi_hii_packagelist *hii)
115 while (!list_empty(&hii->string_tables)) {
116 struct efi_string_table *stbl;
118 stbl = list_first_entry(&hii->string_tables,
119 struct efi_string_table, link);
120 list_del(&stbl->link);
121 free_strings_table(stbl);
126 add_strings_package(struct efi_hii_packagelist *hii,
127 struct efi_hii_strings_package *strings_package)
129 struct efi_hii_string_block *block;
131 u32 nstrings = 0, idx = 0;
132 struct efi_string_table *stbl = NULL;
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);
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);
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;
154 ucs2 = (void *)block;
156 block = efi_hii_sibt_string_ucs2_block_next(ucs2);
159 case EFI_HII_SIBT_END:
163 EFI_PRINT("unknown HII string block type: %02x\n",
165 return EFI_INVALID_PARAMETER;
169 stbl = calloc(sizeof(*stbl), 1);
171 ret = EFI_OUT_OF_RESOURCES;
174 stbl->strings = calloc(sizeof(stbl->strings[0]), nstrings);
175 if (!stbl->strings) {
176 ret = EFI_OUT_OF_RESOURCES;
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;
186 stbl->nstrings = nstrings;
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);
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;
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;
206 /* FIXME: accessing u16 * here */
207 block = efi_hii_sibt_string_ucs2_block_next(ucs2);
210 case EFI_HII_SIBT_END:
213 EFI_PRINT("unknown HII string block type: %02x\n",
215 ret = EFI_INVALID_PARAMETER;
221 list_add(&stbl->link, &hii->string_tables);
222 if (hii->max_string_id < nstrings)
223 hii->max_string_id = nstrings;
229 free(stbl->language);
231 free(stbl->strings[--idx].string);
239 static void remove_guid_package(struct efi_hii_packagelist *hii)
241 struct efi_guid_data *data;
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);
252 add_guid_package(struct efi_hii_packagelist *hii,
253 struct efi_hii_guid_package *package)
255 struct efi_guid_data *data;
257 data = calloc(sizeof(*data), 1);
259 return EFI_OUT_OF_RESOURCES;
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);
268 static void free_keyboard_layouts(struct efi_keyboard_package_data *package)
270 struct efi_keyboard_layout_data *layout_data;
272 while (!list_empty(&package->keyboard_layout_list)) {
273 layout_data = list_first_entry(&package->keyboard_layout_list,
274 struct efi_keyboard_layout_data,
276 list_del(&layout_data->link);
277 list_del(&layout_data->link_sys);
282 static void remove_keyboard_package(struct efi_hii_packagelist *hii)
284 struct efi_keyboard_package_data *package;
286 while (!list_empty(&hii->keyboard_packages)) {
287 package = list_first_entry(&hii->keyboard_packages,
288 struct efi_keyboard_package_data,
290 free_keyboard_layouts(package);
291 list_del(&package->link);
297 add_keyboard_package(struct efi_hii_packagelist *hii,
298 struct efi_hii_keyboard_package *keyboard_package)
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;
306 package_data = malloc(sizeof(*package_data));
308 return EFI_OUT_OF_RESOURCES;
309 INIT_LIST_HEAD(&package_data->link);
310 INIT_LIST_HEAD(&package_data->keyboard_layout_list);
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);
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);
326 layout += layout_length;
329 list_add_tail(&package_data->link, &hii->keyboard_packages);
334 free_keyboard_layouts(package_data);
337 return EFI_OUT_OF_RESOURCES;
340 static struct efi_hii_packagelist *new_packagelist(void)
342 struct efi_hii_packagelist *hii;
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);
354 static void free_packagelist(struct efi_hii_packagelist *hii)
356 remove_strings_package(hii);
357 remove_guid_package(hii);
358 remove_keyboard_package(hii);
360 list_del(&hii->link);
365 add_packages(struct efi_hii_packagelist *hii,
366 const struct efi_hii_package_list_header *package_list)
368 struct efi_hii_package_header *package;
370 efi_status_t ret = EFI_SUCCESS;
372 end = ((void *)package_list)
373 + get_unaligned_le32(&package_list->package_length);
375 EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid,
376 get_unaligned_le32(&package_list->package_length));
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));
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);
389 case EFI_HII_PACKAGE_FORMS:
390 EFI_PRINT("Form package not supported\n");
391 ret = EFI_INVALID_PARAMETER;
393 case EFI_HII_PACKAGE_STRINGS:
394 ret = add_strings_package(hii,
395 (struct efi_hii_strings_package *)package);
397 case EFI_HII_PACKAGE_FONTS:
398 EFI_PRINT("Font package not supported\n");
399 ret = EFI_INVALID_PARAMETER;
401 case EFI_HII_PACKAGE_IMAGES:
402 EFI_PRINT("Image package not supported\n");
403 ret = EFI_INVALID_PARAMETER;
405 case EFI_HII_PACKAGE_SIMPLE_FONTS:
406 EFI_PRINT("Simple font package not supported\n");
407 ret = EFI_INVALID_PARAMETER;
409 case EFI_HII_PACKAGE_DEVICE_PATH:
410 EFI_PRINT("Device path package not supported\n");
411 ret = EFI_INVALID_PARAMETER;
413 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
414 ret = add_keyboard_package(hii,
415 (struct efi_hii_keyboard_package *)package);
417 case EFI_HII_PACKAGE_ANIMATIONS:
418 EFI_PRINT("Animation package not supported\n");
419 ret = EFI_INVALID_PARAMETER;
421 case EFI_HII_PACKAGE_END:
423 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
424 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
429 if (ret != EFI_SUCCESS)
432 package = (void *)package + efi_hii_package_len(package);
435 // TODO in theory there is some notifications that should be sent..
440 * EFI_HII_DATABASE_PROTOCOL
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)
449 struct efi_hii_packagelist *hii;
452 EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
454 if (!package_list || !handle)
455 return EFI_EXIT(EFI_INVALID_PARAMETER);
457 hii = new_packagelist();
459 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
461 ret = add_packages(hii, package_list);
462 if (ret != EFI_SUCCESS) {
463 free_packagelist(hii);
464 return EFI_EXIT(ret);
467 hii->driver_handle = driver_handle;
470 return EFI_EXIT(EFI_SUCCESS);
473 static efi_status_t EFIAPI
474 remove_package_list(const struct efi_hii_database_protocol *this,
475 efi_hii_handle_t handle)
477 struct efi_hii_packagelist *hii = handle;
479 EFI_ENTRY("%p, %p", this, handle);
481 if (!handle || !efi_hii_packagelist_exists(handle))
482 return EFI_EXIT(EFI_NOT_FOUND);
484 free_packagelist(hii);
486 return EFI_EXIT(EFI_SUCCESS);
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)
494 struct efi_hii_packagelist *hii = handle;
495 struct efi_hii_package_header *package;
497 efi_status_t ret = EFI_SUCCESS;
499 EFI_ENTRY("%p, %p, %p", this, handle, package_list);
501 if (!handle || !efi_hii_packagelist_exists(handle))
502 return EFI_EXIT(EFI_NOT_FOUND);
505 return EFI_EXIT(EFI_INVALID_PARAMETER);
507 EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid,
508 get_unaligned_le32(&package_list->package_length));
510 package = ((void *)package_list) + sizeof(*package_list);
511 end = ((void *)package_list)
512 + get_unaligned_le32(&package_list->package_length);
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));
519 switch (efi_hii_package_type(package)) {
520 case EFI_HII_PACKAGE_TYPE_GUID:
521 remove_guid_package(hii);
523 case EFI_HII_PACKAGE_FORMS:
524 EFI_PRINT("Form package not supported\n");
525 ret = EFI_INVALID_PARAMETER;
527 case EFI_HII_PACKAGE_STRINGS:
528 remove_strings_package(hii);
530 case EFI_HII_PACKAGE_FONTS:
531 EFI_PRINT("Font package not supported\n");
532 ret = EFI_INVALID_PARAMETER;
534 case EFI_HII_PACKAGE_IMAGES:
535 EFI_PRINT("Image package not supported\n");
536 ret = EFI_INVALID_PARAMETER;
538 case EFI_HII_PACKAGE_SIMPLE_FONTS:
539 EFI_PRINT("Simple font package not supported\n");
540 ret = EFI_INVALID_PARAMETER;
542 case EFI_HII_PACKAGE_DEVICE_PATH:
543 EFI_PRINT("Device path package not supported\n");
544 ret = EFI_INVALID_PARAMETER;
546 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
547 remove_keyboard_package(hii);
549 case EFI_HII_PACKAGE_ANIMATIONS:
550 EFI_PRINT("Animation package not supported\n");
551 ret = EFI_INVALID_PARAMETER;
553 case EFI_HII_PACKAGE_END:
555 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
556 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
561 /* TODO: already removed some packages */
562 if (ret != EFI_SUCCESS)
563 return EFI_EXIT(ret);
565 package = ((void *)package)
566 + efi_hii_package_len(package);
569 ret = add_packages(hii, package_list);
571 return EFI_EXIT(ret);
574 static efi_status_t EFIAPI
575 list_package_lists(const struct efi_hii_database_protocol *this,
577 const efi_guid_t *package_guid,
578 efi_uintn_t *handle_buffer_length,
579 efi_hii_handle_t *handle)
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;
586 EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
587 handle_buffer_length, handle);
589 if (!handle_buffer_length ||
590 (*handle_buffer_length && !handle)) {
591 ret = EFI_INVALID_PARAMETER;
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;
601 EFI_PRINT("package type=%x, guid=%pUl, length=%zu\n", (int)package_type,
602 package_guid, *handle_buffer_length);
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:
610 case EFI_HII_PACKAGE_TYPE_GUID:
611 if (!list_empty(&hii->guid_list))
614 case EFI_HII_PACKAGE_STRINGS:
615 if (!list_empty(&hii->string_tables))
618 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
619 if (!list_empty(&hii->keyboard_packages))
627 if (package_cnt <= package_max) {
631 ret = EFI_BUFFER_TOO_SMALL;
634 *handle_buffer_length = package_cnt * sizeof(*handle);
636 return EFI_EXIT(ret);
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)
645 EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
647 if (!buffer_size || !buffer)
648 return EFI_EXIT(EFI_INVALID_PARAMETER);
650 return EFI_EXIT(EFI_NOT_FOUND);
653 static efi_status_t EFIAPI
654 register_package_notify(const struct efi_hii_database_protocol *this,
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)
661 EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
662 package_guid, package_notify_fn, notify_type,
666 return EFI_EXIT(EFI_INVALID_PARAMETER);
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);
672 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
675 static efi_status_t EFIAPI
676 unregister_package_notify(const struct efi_hii_database_protocol *this,
677 efi_handle_t notification_handle)
679 EFI_ENTRY("%p, %p", this, notification_handle);
681 return EFI_EXIT(EFI_NOT_FOUND);
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)
689 struct efi_keyboard_layout_data *layout_data;
690 int package_cnt, package_max;
691 efi_status_t ret = EFI_SUCCESS;
693 EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
695 if (!key_guid_buffer_length ||
696 (*key_guid_buffer_length && !key_guid_buffer))
697 return EFI_EXIT(EFI_INVALID_PARAMETER);
700 package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer);
701 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
703 if (package_cnt <= package_max)
704 memcpy(key_guid_buffer++,
705 &layout_data->keyboard_layout.guid,
706 sizeof(*key_guid_buffer));
708 ret = EFI_BUFFER_TOO_SMALL;
710 *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer);
712 return EFI_EXIT(ret);
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)
721 struct efi_keyboard_layout_data *layout_data;
724 EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
727 if (!keyboard_layout_length ||
728 (*keyboard_layout_length && !keyboard_layout))
729 return EFI_EXIT(EFI_INVALID_PARAMETER);
731 /* TODO: no notion of current keyboard layout */
733 return EFI_EXIT(EFI_INVALID_PARAMETER);
735 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
736 if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid))
740 return EFI_EXIT(EFI_NOT_FOUND);
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);
750 memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length);
752 return EFI_EXIT(EFI_SUCCESS);
755 static efi_status_t EFIAPI
756 set_keyboard_layout(const struct efi_hii_database_protocol *this,
757 efi_guid_t *key_guid)
759 EFI_ENTRY("%p, %pUl", this, key_guid);
761 return EFI_EXIT(EFI_NOT_FOUND);
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)
769 struct efi_hii_packagelist *hii;
771 EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
774 return EFI_EXIT(EFI_INVALID_PARAMETER);
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);
783 return EFI_EXIT(EFI_NOT_FOUND);
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
801 * EFI_HII_STRING_PROTOCOL
804 static bool language_match(char *language, char *languages)
808 n = strlen(language);
809 /* match primary language? */
810 if (!strncasecmp(language, languages, n) &&
811 (languages[n] == ';' || languages[n] == '\0'))
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,
822 const u16 *language_name,
823 const efi_string_t string,
824 const struct efi_font_info *string_font_info)
826 struct efi_hii_packagelist *hii = package_list;
827 struct efi_string_table *stbl;
829 EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
830 string_id, language, language_name, string,
833 if (!package_list || !efi_hii_packagelist_exists(package_list))
834 return EFI_EXIT(EFI_NOT_FOUND);
836 if (!string_id || !language || !string)
837 return EFI_EXIT(EFI_INVALID_PARAMETER);
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;
845 new_id = ++hii->max_string_id;
846 if (stbl->nstrings < new_id) {
847 buf = realloc(stbl->strings,
848 sizeof(stbl->strings[0])
851 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
853 memset(&stbl->strings[stbl->nstrings], 0,
854 (new_id - stbl->nstrings)
855 * sizeof(stbl->strings[0]));
857 stbl->nstrings = new_id;
860 str = u16_strdup(string);
862 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
864 stbl->strings[new_id - 1].string = str;
867 return EFI_EXIT(EFI_SUCCESS);
871 return EFI_EXIT(EFI_NOT_FOUND);
874 static efi_status_t EFIAPI
875 get_string(const struct efi_hii_string_protocol *this,
877 efi_hii_handle_t package_list,
878 efi_string_id_t string_id,
880 efi_uintn_t *string_size,
881 struct efi_font_info **string_font_info)
883 struct efi_hii_packagelist *hii = package_list;
884 struct efi_string_table *stbl;
886 EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
887 package_list, string_id, string, string_size,
890 if (!package_list || !efi_hii_packagelist_exists(package_list))
891 return EFI_EXIT(EFI_NOT_FOUND);
893 list_for_each_entry(stbl, &hii->string_tables, link) {
894 if (language_match((char *)language, stbl->language)) {
898 if (stbl->nstrings < string_id)
899 return EFI_EXIT(EFI_NOT_FOUND);
901 str = stbl->strings[string_id - 1].string;
903 len = (u16_strlen(str) + 1) * sizeof(u16);
904 if (*string_size < len) {
907 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
909 memcpy(string, str, len);
912 return EFI_EXIT(EFI_NOT_FOUND);
915 return EFI_EXIT(EFI_SUCCESS);
919 return EFI_EXIT(EFI_NOT_FOUND);
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,
927 const efi_string_t string,
928 const struct efi_font_info *string_font_info)
930 struct efi_hii_packagelist *hii = package_list;
931 struct efi_string_table *stbl;
933 EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
934 string_id, language, string, string_font_info);
936 if (!package_list || !efi_hii_packagelist_exists(package_list))
937 return EFI_EXIT(EFI_NOT_FOUND);
939 if (string_id > hii->max_string_id)
940 return EFI_EXIT(EFI_NOT_FOUND);
942 if (!string || !language)
943 return EFI_EXIT(EFI_INVALID_PARAMETER);
945 list_for_each_entry(stbl, &hii->string_tables, link) {
946 if (language_match((char *)language, stbl->language)) {
949 if (hii->max_string_id < string_id)
950 return EFI_EXIT(EFI_NOT_FOUND);
952 if (stbl->nstrings < string_id) {
955 buf = realloc(stbl->strings,
957 * sizeof(stbl->strings[0]));
959 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
961 memset(&stbl->strings[string_id - 1], 0,
962 (string_id - stbl->nstrings)
963 * sizeof(stbl->strings[0]));
967 str = u16_strdup(string);
969 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
971 free(stbl->strings[string_id - 1].string);
972 stbl->strings[string_id - 1].string = str;
974 return EFI_EXIT(EFI_SUCCESS);
978 return EFI_EXIT(EFI_NOT_FOUND);
981 static efi_status_t EFIAPI
982 get_languages(const struct efi_hii_string_protocol *this,
983 efi_hii_handle_t package_list,
985 efi_uintn_t *languages_size)
987 struct efi_hii_packagelist *hii = package_list;
988 struct efi_string_table *stbl;
992 EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
995 if (!package_list || !efi_hii_packagelist_exists(package_list))
996 return EFI_EXIT(EFI_NOT_FOUND);
998 if (!languages_size ||
999 (*languages_size && !languages))
1000 return EFI_EXIT(EFI_INVALID_PARAMETER);
1002 /* figure out required size: */
1003 list_for_each_entry(stbl, &hii->string_tables, link) {
1004 len += strlen((char *)stbl->language) + 1;
1007 if (*languages_size < len) {
1008 *languages_size = len;
1010 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
1013 p = (char *)languages;
1014 list_for_each_entry(stbl, &hii->string_tables, link) {
1015 if (p != (char *)languages)
1017 strcpy(p, stbl->language);
1018 p += strlen((char *)stbl->language);
1022 EFI_PRINT("languages: %s\n", languages);
1024 return EFI_EXIT(EFI_SUCCESS);
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)
1034 struct efi_hii_packagelist *hii = package_list;
1035 struct efi_string_table *stbl;
1038 EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
1039 primary_language, secondary_languages,
1040 secondary_languages_size);
1042 if (!package_list || !efi_hii_packagelist_exists(package_list))
1043 return EFI_EXIT(EFI_NOT_FOUND);
1045 if (!secondary_languages_size ||
1046 (*secondary_languages_size && !secondary_languages))
1047 return EFI_EXIT(EFI_INVALID_PARAMETER);
1049 list_for_each_entry(stbl, &hii->string_tables, link) {
1050 if (language_match((char *)primary_language, stbl->language)) {
1056 return EFI_EXIT(EFI_INVALID_LANGUAGE);
1059 * TODO: What is secondary language?
1060 * *secondary_languages = '\0';
1061 * *secondary_languages_size = 0;
1064 return EFI_EXIT(EFI_NOT_FOUND);
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