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