Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot
[oweals/u-boot.git] / lib / efi_loader / efi_hii.c
1 // SPDX-License-Identifier:     GPL-2.0+
2 /*
3  *  EFI Human Interface Infrastructure ... database and packages
4  *
5  *  Copyright (c) 2017 Leif Lindholm
6  *  Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
7  */
8
9 #include <common.h>
10 #include <efi_loader.h>
11 #include <malloc.h>
12 #include <asm/unaligned.h>
13
14 const efi_guid_t efi_guid_hii_database_protocol
15                 = EFI_HII_DATABASE_PROTOCOL_GUID;
16 const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID;
17
18 static LIST_HEAD(efi_package_lists);
19 static LIST_HEAD(efi_keyboard_layout_list);
20
21 struct efi_hii_packagelist {
22         struct list_head link;
23         // TODO should there be an associated efi_object?
24         efi_handle_t driver_handle;
25         u32 max_string_id;
26         struct list_head string_tables;     /* list of efi_string_table */
27         struct list_head guid_list;
28         struct list_head keyboard_packages;
29
30         /* we could also track fonts, images, etc */
31 };
32
33 static int efi_hii_packagelist_exists(efi_hii_handle_t package_list)
34 {
35         struct efi_hii_packagelist *hii;
36         int found = 0;
37
38         list_for_each_entry(hii, &efi_package_lists, link) {
39                 if (hii == package_list) {
40                         found = 1;
41                         break;
42                 }
43         }
44
45         return found;
46 }
47
48 static u32 efi_hii_package_type(struct efi_hii_package_header *header)
49 {
50         u32 fields;
51
52         fields = get_unaligned_le32(&header->fields);
53
54         return (fields >> __EFI_HII_PACKAGE_TYPE_SHIFT)
55                 & __EFI_HII_PACKAGE_TYPE_MASK;
56 }
57
58 static u32 efi_hii_package_len(struct efi_hii_package_header *header)
59 {
60         u32 fields;
61
62         fields = get_unaligned_le32(&header->fields);
63
64         return (fields >> __EFI_HII_PACKAGE_LEN_SHIFT)
65                 & __EFI_HII_PACKAGE_LEN_MASK;
66 }
67
68 struct efi_string_info {
69         efi_string_t string;
70         /* we could also track font info, etc */
71 };
72
73 struct efi_string_table {
74         struct list_head link;
75         efi_string_id_t language_name;
76         char *language;
77         u32 nstrings;
78         /*
79          * NOTE:
80          *  string id starts at 1 so value is stbl->strings[id-1],
81          *  and strings[] is a array of stbl->nstrings elements
82          */
83         struct efi_string_info *strings;
84 };
85
86 struct efi_guid_data {
87         struct list_head link;
88         struct efi_hii_guid_package package;
89 };
90
91 struct efi_keyboard_layout_data {
92         struct list_head link;          /* in package */
93         struct list_head link_sys;      /* in global list */
94         struct efi_hii_keyboard_layout keyboard_layout;
95 };
96
97 struct efi_keyboard_package_data {
98         struct list_head link;          /* in package_list */
99         struct list_head keyboard_layout_list;
100 };
101
102 static void free_strings_table(struct efi_string_table *stbl)
103 {
104         int i;
105
106         for (i = 0; i < stbl->nstrings; i++)
107                 free(stbl->strings[i].string);
108         free(stbl->strings);
109         free(stbl->language);
110         free(stbl);
111 }
112
113 static void remove_strings_package(struct efi_hii_packagelist *hii)
114 {
115         while (!list_empty(&hii->string_tables)) {
116                 struct efi_string_table *stbl;
117
118                 stbl = list_first_entry(&hii->string_tables,
119                                         struct efi_string_table, link);
120                 list_del(&stbl->link);
121                 free_strings_table(stbl);
122         }
123 }
124
125 static efi_status_t
126 add_strings_package(struct efi_hii_packagelist *hii,
127                     struct efi_hii_strings_package *strings_package)
128 {
129         struct efi_hii_string_block *block;
130         void *end;
131         u32 nstrings = 0, idx = 0;
132         struct efi_string_table *stbl = NULL;
133         efi_status_t ret;
134
135         EFI_PRINT("header_size: %08x\n",
136                   get_unaligned_le32(&strings_package->header_size));
137         EFI_PRINT("string_info_offset: %08x\n",
138                   get_unaligned_le32(&strings_package->string_info_offset));
139         EFI_PRINT("language_name: %u\n",
140                   get_unaligned_le16(&strings_package->language_name));
141         EFI_PRINT("language: %s\n", strings_package->language);
142
143         /* count # of string entries: */
144         end = ((void *)strings_package)
145                         + efi_hii_package_len(&strings_package->header);
146         block = ((void *)strings_package)
147                 + get_unaligned_le32(&strings_package->string_info_offset);
148
149         while ((void *)block < end) {
150                 switch (block->block_type) {
151                 case EFI_HII_SIBT_STRING_UCS2: {
152                         struct efi_hii_sibt_string_ucs2_block *ucs2;
153
154                         ucs2 = (void *)block;
155                         nstrings++;
156                         block = efi_hii_sibt_string_ucs2_block_next(ucs2);
157                         break;
158                 }
159                 case EFI_HII_SIBT_END:
160                         block = end;
161                         break;
162                 default:
163                         EFI_PRINT("unknown HII string block type: %02x\n",
164                                   block->block_type);
165                         return EFI_INVALID_PARAMETER;
166                 }
167         }
168
169         stbl = calloc(sizeof(*stbl), 1);
170         if (!stbl) {
171                 ret = EFI_OUT_OF_RESOURCES;
172                 goto error;
173         }
174         stbl->strings = calloc(sizeof(stbl->strings[0]), nstrings);
175         if (!stbl->strings) {
176                 ret = EFI_OUT_OF_RESOURCES;
177                 goto error;
178         }
179         stbl->language_name =
180                         get_unaligned_le16(&strings_package->language_name);
181         stbl->language = strdup((char *)strings_package->language);
182         if (!stbl->language) {
183                 ret = EFI_OUT_OF_RESOURCES;
184                 goto error;
185         }
186         stbl->nstrings = nstrings;
187
188         /* and now parse string entries and populate efi_string_table */
189         block = ((void *)strings_package)
190                 + get_unaligned_le32(&strings_package->string_info_offset);
191
192         while ((void *)block < end) {
193                 switch (block->block_type) {
194                 case EFI_HII_SIBT_STRING_UCS2: {
195                         struct efi_hii_sibt_string_ucs2_block *ucs2;
196
197                         ucs2 = (void *)block;
198                         EFI_PRINT("%4u: \"%ls\"\n", idx + 1, ucs2->string_text);
199                         stbl->strings[idx].string =
200                                 u16_strdup(ucs2->string_text);
201                         if (!stbl->strings[idx].string) {
202                                 ret = EFI_OUT_OF_RESOURCES;
203                                 goto error;
204                         }
205                         idx++;
206                         /* FIXME: accessing u16 * here */
207                         block = efi_hii_sibt_string_ucs2_block_next(ucs2);
208                         break;
209                 }
210                 case EFI_HII_SIBT_END:
211                         goto out;
212                 default:
213                         EFI_PRINT("unknown HII string block type: %02x\n",
214                                   block->block_type);
215                         ret = EFI_INVALID_PARAMETER;
216                         goto error;
217                 }
218         }
219
220 out:
221         list_add(&stbl->link, &hii->string_tables);
222         if (hii->max_string_id < nstrings)
223                 hii->max_string_id = nstrings;
224
225         return EFI_SUCCESS;
226
227 error:
228         if (stbl) {
229                 free(stbl->language);
230                 if (idx > 0)
231                         while (--idx >= 0)
232                                 free(stbl->strings[idx].string);
233                 free(stbl->strings);
234         }
235         free(stbl);
236
237         return ret;
238 }
239
240 static void remove_guid_package(struct efi_hii_packagelist *hii)
241 {
242         struct efi_guid_data *data;
243
244         while (!list_empty(&hii->guid_list)) {
245                 data = list_first_entry(&hii->guid_list,
246                                         struct efi_guid_data, link);
247                 list_del(&data->link);
248                 free(data);
249         }
250 }
251
252 static efi_status_t
253 add_guid_package(struct efi_hii_packagelist *hii,
254                  struct efi_hii_guid_package *package)
255 {
256         struct efi_guid_data *data;
257
258         data = calloc(sizeof(*data), 1);
259         if (!data)
260                 return EFI_OUT_OF_RESOURCES;
261
262         /* TODO: we don't know any about data field */
263         memcpy(&data->package, package, sizeof(*package));
264         list_add_tail(&data->link, &hii->guid_list);
265
266         return EFI_SUCCESS;
267 }
268
269 static void free_keyboard_layouts(struct efi_keyboard_package_data *package)
270 {
271         struct efi_keyboard_layout_data *layout_data;
272
273         while (!list_empty(&package->keyboard_layout_list)) {
274                 layout_data = list_first_entry(&package->keyboard_layout_list,
275                                                struct efi_keyboard_layout_data,
276                                                link);
277                 list_del(&layout_data->link);
278                 list_del(&layout_data->link_sys);
279                 free(layout_data);
280         }
281 }
282
283 static void remove_keyboard_package(struct efi_hii_packagelist *hii)
284 {
285         struct efi_keyboard_package_data *package;
286
287         while (!list_empty(&hii->keyboard_packages)) {
288                 package = list_first_entry(&hii->keyboard_packages,
289                                            struct efi_keyboard_package_data,
290                                            link);
291                 free_keyboard_layouts(package);
292                 list_del(&package->link);
293                 free(package);
294         }
295 }
296
297 static efi_status_t
298 add_keyboard_package(struct efi_hii_packagelist *hii,
299                      struct efi_hii_keyboard_package *keyboard_package)
300 {
301         struct efi_keyboard_package_data *package_data;
302         struct efi_hii_keyboard_layout *layout;
303         struct efi_keyboard_layout_data *layout_data;
304         u16 layout_count, layout_length;
305         int i;
306
307         package_data = malloc(sizeof(*package_data));
308         if (!package_data)
309                 return EFI_OUT_OF_RESOURCES;
310         INIT_LIST_HEAD(&package_data->link);
311         INIT_LIST_HEAD(&package_data->keyboard_layout_list);
312
313         layout = &keyboard_package->layout[0];
314         layout_count = get_unaligned_le16(&keyboard_package->layout_count);
315         for (i = 0; i < layout_count; i++) {
316                 layout_length = get_unaligned_le16(&layout->layout_length);
317                 layout_data = malloc(sizeof(*layout_data) + layout_length);
318                 if (!layout_data)
319                         goto out;
320
321                 memcpy(&layout_data->keyboard_layout, layout, layout_length);
322                 list_add_tail(&layout_data->link,
323                               &package_data->keyboard_layout_list);
324                 list_add_tail(&layout_data->link_sys,
325                               &efi_keyboard_layout_list);
326
327                 layout += layout_length;
328         }
329
330         list_add_tail(&package_data->link, &hii->keyboard_packages);
331
332         return EFI_SUCCESS;
333
334 out:
335         free_keyboard_layouts(package_data);
336         free(package_data);
337
338         return EFI_OUT_OF_RESOURCES;
339 }
340
341 static struct efi_hii_packagelist *new_packagelist(void)
342 {
343         struct efi_hii_packagelist *hii;
344
345         hii = malloc(sizeof(*hii));
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                         printf("\tForm 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                         printf("\tFont package not supported\n");
399                         ret = EFI_INVALID_PARAMETER;
400                         break;
401                 case EFI_HII_PACKAGE_IMAGES:
402                         printf("\tImage package not supported\n");
403                         ret = EFI_INVALID_PARAMETER;
404                         break;
405                 case EFI_HII_PACKAGE_SIMPLE_FONTS:
406                         printf("\tSimple font package not supported\n");
407                         ret = EFI_INVALID_PARAMETER;
408                         break;
409                 case EFI_HII_PACKAGE_DEVICE_PATH:
410                         printf("\tDevice 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                         printf("\tAnimation 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         list_add_tail(&hii->link, &efi_package_lists);
469         *handle = hii;
470
471         return EFI_EXIT(EFI_SUCCESS);
472 }
473
474 static efi_status_t EFIAPI
475 remove_package_list(const struct efi_hii_database_protocol *this,
476                     efi_hii_handle_t handle)
477 {
478         struct efi_hii_packagelist *hii = handle;
479
480         EFI_ENTRY("%p, %p", this, handle);
481
482         if (!handle || !efi_hii_packagelist_exists(handle))
483                 return EFI_EXIT(EFI_NOT_FOUND);
484
485         free_packagelist(hii);
486
487         return EFI_EXIT(EFI_SUCCESS);
488 }
489
490 static efi_status_t EFIAPI
491 update_package_list(const struct efi_hii_database_protocol *this,
492                     efi_hii_handle_t handle,
493                     const struct efi_hii_package_list_header *package_list)
494 {
495         struct efi_hii_packagelist *hii = handle;
496         struct efi_hii_package_header *package;
497         void *end;
498         efi_status_t ret = EFI_SUCCESS;
499
500         EFI_ENTRY("%p, %p, %p", this, handle, package_list);
501
502         if (!handle || !efi_hii_packagelist_exists(handle))
503                 return EFI_EXIT(EFI_NOT_FOUND);
504
505         if (!package_list)
506                 return EFI_EXIT(EFI_INVALID_PARAMETER);
507
508         EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid,
509                   get_unaligned_le32(&package_list->package_length));
510
511         package = ((void *)package_list) + sizeof(*package_list);
512         end = ((void *)package_list)
513                 + get_unaligned_le32(&package_list->package_length);
514
515         while ((void *)package < end) {
516                 EFI_PRINT("package=%p, package type=%x, length=%u\n", package,
517                           efi_hii_package_type(package),
518                           efi_hii_package_len(package));
519
520                 switch (efi_hii_package_type(package)) {
521                 case EFI_HII_PACKAGE_TYPE_GUID:
522                         remove_guid_package(hii);
523                         break;
524                 case EFI_HII_PACKAGE_FORMS:
525                         printf("\tForm package not supported\n");
526                         ret = EFI_INVALID_PARAMETER;
527                         break;
528                 case EFI_HII_PACKAGE_STRINGS:
529                         remove_strings_package(hii);
530                         break;
531                 case EFI_HII_PACKAGE_FONTS:
532                         printf("\tFont package not supported\n");
533                         ret = EFI_INVALID_PARAMETER;
534                         break;
535                 case EFI_HII_PACKAGE_IMAGES:
536                         printf("\tImage package not supported\n");
537                         ret = EFI_INVALID_PARAMETER;
538                         break;
539                 case EFI_HII_PACKAGE_SIMPLE_FONTS:
540                         printf("\tSimple font package not supported\n");
541                         ret = EFI_INVALID_PARAMETER;
542                         break;
543                 case EFI_HII_PACKAGE_DEVICE_PATH:
544                         printf("\tDevice path package not supported\n");
545                         ret = EFI_INVALID_PARAMETER;
546                         break;
547                 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
548                         remove_keyboard_package(hii);
549                         break;
550                 case EFI_HII_PACKAGE_ANIMATIONS:
551                         printf("\tAnimation package not supported\n");
552                         ret = EFI_INVALID_PARAMETER;
553                         break;
554                 case EFI_HII_PACKAGE_END:
555                         goto out;
556                 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
557                 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
558                 default:
559                         break;
560                 }
561
562                 /* TODO: already removed some packages */
563                 if (ret != EFI_SUCCESS)
564                         return EFI_EXIT(ret);
565
566                 package = ((void *)package)
567                           + efi_hii_package_len(package);
568         }
569 out:
570         ret = add_packages(hii, package_list);
571
572         return EFI_EXIT(ret);
573 }
574
575 static efi_status_t EFIAPI
576 list_package_lists(const struct efi_hii_database_protocol *this,
577                    u8 package_type,
578                    const efi_guid_t *package_guid,
579                    efi_uintn_t *handle_buffer_length,
580                    efi_hii_handle_t *handle)
581 {
582         struct efi_hii_packagelist *hii =
583                                 (struct efi_hii_packagelist *)handle;
584         int package_cnt, package_max;
585         efi_status_t ret = EFI_SUCCESS;
586
587         EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
588                   handle_buffer_length, handle);
589
590         if (!handle_buffer_length ||
591             (*handle_buffer_length && !handle))
592                 return EFI_EXIT(EFI_INVALID_PARAMETER);
593
594         if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
595             (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
596                 return EFI_EXIT(EFI_INVALID_PARAMETER);
597
598         EFI_PRINT("package type=%x, guid=%pUl, length=%zu\n", (int)package_type,
599                   package_guid, *handle_buffer_length);
600
601         package_cnt = 0;
602         package_max = *handle_buffer_length / sizeof(*handle);
603         list_for_each_entry(hii, &efi_package_lists, link) {
604                 switch (package_type) {
605                 case EFI_HII_PACKAGE_TYPE_ALL:
606                         break;
607                 case EFI_HII_PACKAGE_TYPE_GUID:
608                         if (!list_empty(&hii->guid_list))
609                                 break;
610                         continue;
611                 case EFI_HII_PACKAGE_FORMS:
612                         printf("\tForm package not supported\n");
613                         ret = EFI_INVALID_PARAMETER;
614                         continue;
615                 case EFI_HII_PACKAGE_STRINGS:
616                         if (!list_empty(&hii->string_tables))
617                                 break;
618                         continue;
619                 case EFI_HII_PACKAGE_FONTS:
620                         printf("\tFont package not supported\n");
621                         ret = EFI_INVALID_PARAMETER;
622                         continue;
623                 case EFI_HII_PACKAGE_IMAGES:
624                         printf("\tImage package not supported\n");
625                         ret = EFI_INVALID_PARAMETER;
626                         continue;
627                 case EFI_HII_PACKAGE_SIMPLE_FONTS:
628                         printf("\tSimple font package not supported\n");
629                         ret = EFI_INVALID_PARAMETER;
630                         continue;
631                 case EFI_HII_PACKAGE_DEVICE_PATH:
632                         printf("\tDevice path package not supported\n");
633                         ret = EFI_INVALID_PARAMETER;
634                         continue;
635                 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
636                         if (!list_empty(&hii->keyboard_packages))
637                                 break;
638                         continue;
639                 case EFI_HII_PACKAGE_ANIMATIONS:
640                         printf("\tAnimation package not supported\n");
641                         ret = EFI_INVALID_PARAMETER;
642                         continue;
643                 case EFI_HII_PACKAGE_END:
644                 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
645                 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
646                 default:
647                         continue;
648                 }
649
650                 package_cnt++;
651                 if (package_cnt <= package_max)
652                         *handle++ = hii;
653                 else
654                         ret = EFI_BUFFER_TOO_SMALL;
655         }
656         *handle_buffer_length = package_cnt * sizeof(*handle);
657
658         return EFI_EXIT(ret);
659 }
660
661 static efi_status_t EFIAPI
662 export_package_lists(const struct efi_hii_database_protocol *this,
663                      efi_hii_handle_t handle,
664                      efi_uintn_t *buffer_size,
665                      struct efi_hii_package_list_header *buffer)
666 {
667         EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
668
669         if (!buffer_size || !buffer)
670                 return EFI_EXIT(EFI_INVALID_PARAMETER);
671
672         return EFI_EXIT(EFI_NOT_FOUND);
673 }
674
675 static efi_status_t EFIAPI
676 register_package_notify(const struct efi_hii_database_protocol *this,
677                         u8 package_type,
678                         const efi_guid_t *package_guid,
679                         const void *package_notify_fn,
680                         efi_uintn_t notify_type,
681                         efi_handle_t *notify_handle)
682 {
683         EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
684                   package_guid, package_notify_fn, notify_type,
685                   notify_handle);
686
687         if (!notify_handle)
688                 return EFI_EXIT(EFI_INVALID_PARAMETER);
689
690         if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
691             (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
692                 return EFI_EXIT(EFI_INVALID_PARAMETER);
693
694         return EFI_EXIT(EFI_OUT_OF_RESOURCES);
695 }
696
697 static efi_status_t EFIAPI
698 unregister_package_notify(const struct efi_hii_database_protocol *this,
699                           efi_handle_t notification_handle)
700 {
701         EFI_ENTRY("%p, %p", this, notification_handle);
702
703         return EFI_EXIT(EFI_NOT_FOUND);
704 }
705
706 static efi_status_t EFIAPI
707 find_keyboard_layouts(const struct efi_hii_database_protocol *this,
708                       u16 *key_guid_buffer_length,
709                       efi_guid_t *key_guid_buffer)
710 {
711         struct efi_keyboard_layout_data *layout_data;
712         int package_cnt, package_max;
713         efi_status_t ret = EFI_SUCCESS;
714
715         EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
716
717         if (!key_guid_buffer_length ||
718             (*key_guid_buffer_length && !key_guid_buffer))
719                 return EFI_EXIT(EFI_INVALID_PARAMETER);
720
721         package_cnt = 0;
722         package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer);
723         list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
724                 package_cnt++;
725                 if (package_cnt <= package_max)
726                         memcpy(key_guid_buffer++,
727                                &layout_data->keyboard_layout.guid,
728                                sizeof(*key_guid_buffer));
729                 else
730                         ret = EFI_BUFFER_TOO_SMALL;
731         }
732         *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer);
733
734         return EFI_EXIT(ret);
735 }
736
737 static efi_status_t EFIAPI
738 get_keyboard_layout(const struct efi_hii_database_protocol *this,
739                     efi_guid_t *key_guid,
740                     u16 *keyboard_layout_length,
741                     struct efi_hii_keyboard_layout *keyboard_layout)
742 {
743         struct efi_keyboard_layout_data *layout_data;
744         u16 layout_length;
745
746         EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
747                   keyboard_layout);
748
749         if (!keyboard_layout_length ||
750             (*keyboard_layout_length && !keyboard_layout))
751                 return EFI_EXIT(EFI_INVALID_PARAMETER);
752
753         /* TODO: no notion of current keyboard layout */
754         if (!key_guid)
755                 return EFI_EXIT(EFI_INVALID_PARAMETER);
756
757         list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
758                 if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid))
759                         goto found;
760         }
761
762         return EFI_EXIT(EFI_NOT_FOUND);
763
764 found:
765         layout_length =
766                 get_unaligned_le16(&layout_data->keyboard_layout.layout_length);
767         if (*keyboard_layout_length < layout_length) {
768                 *keyboard_layout_length = layout_length;
769                 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
770         }
771
772         memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length);
773
774         return EFI_EXIT(EFI_SUCCESS);
775 }
776
777 static efi_status_t EFIAPI
778 set_keyboard_layout(const struct efi_hii_database_protocol *this,
779                     efi_guid_t *key_guid)
780 {
781         EFI_ENTRY("%p, %pUl", this, key_guid);
782
783         return EFI_EXIT(EFI_NOT_FOUND);
784 }
785
786 static efi_status_t EFIAPI
787 get_package_list_handle(const struct efi_hii_database_protocol *this,
788                         efi_hii_handle_t package_list_handle,
789                         efi_handle_t *driver_handle)
790 {
791         struct efi_hii_packagelist *hii;
792
793         EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
794
795         if (!driver_handle)
796                 return EFI_EXIT(EFI_INVALID_PARAMETER);
797
798         list_for_each_entry(hii, &efi_package_lists, link) {
799                 if (hii == package_list_handle) {
800                         *driver_handle = hii->driver_handle;
801                         return EFI_EXIT(EFI_SUCCESS);
802                 }
803         }
804
805         return EFI_EXIT(EFI_NOT_FOUND);
806 }
807
808 const struct efi_hii_database_protocol efi_hii_database = {
809         .new_package_list = new_package_list,
810         .remove_package_list = remove_package_list,
811         .update_package_list = update_package_list,
812         .list_package_lists = list_package_lists,
813         .export_package_lists = export_package_lists,
814         .register_package_notify = register_package_notify,
815         .unregister_package_notify = unregister_package_notify,
816         .find_keyboard_layouts = find_keyboard_layouts,
817         .get_keyboard_layout = get_keyboard_layout,
818         .set_keyboard_layout = set_keyboard_layout,
819         .get_package_list_handle = get_package_list_handle
820 };
821
822 /*
823  * EFI_HII_STRING_PROTOCOL
824  */
825
826 static bool language_match(char *language, char *languages)
827 {
828         size_t n;
829
830         n = strlen(language);
831         /* match primary language? */
832         if (!strncasecmp(language, languages, n) &&
833             (languages[n] == ';' || languages[n] == '\0'))
834                 return true;
835
836         return false;
837 }
838
839 static efi_status_t EFIAPI
840 new_string(const struct efi_hii_string_protocol *this,
841            efi_hii_handle_t package_list,
842            efi_string_id_t *string_id,
843            const u8 *language,
844            const u16 *language_name,
845            const efi_string_t string,
846            const struct efi_font_info *string_font_info)
847 {
848         struct efi_hii_packagelist *hii = package_list;
849         struct efi_string_table *stbl;
850
851         EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
852                   string_id, language, language_name, string,
853                   string_font_info);
854
855         if (!package_list || !efi_hii_packagelist_exists(package_list))
856                 return EFI_EXIT(EFI_NOT_FOUND);
857
858         if (!string_id || !language || !string)
859                 return EFI_EXIT(EFI_INVALID_PARAMETER);
860
861         list_for_each_entry(stbl, &hii->string_tables, link) {
862                 if (language_match((char *)language, stbl->language)) {
863                         efi_string_id_t new_id;
864                         void *buf;
865                         efi_string_t str;
866
867                         new_id = ++hii->max_string_id;
868                         if (stbl->nstrings < new_id) {
869                                 buf = realloc(stbl->strings,
870                                               sizeof(stbl->strings[0])
871                                                 * new_id);
872                                 if (!buf)
873                                         return EFI_EXIT(EFI_OUT_OF_RESOURCES);
874
875                                 memset(&stbl->strings[stbl->nstrings], 0,
876                                        (new_id - stbl->nstrings)
877                                          * sizeof(stbl->strings[0]));
878                                 stbl->strings = buf;
879                                 stbl->nstrings = new_id;
880                         }
881
882                         str = u16_strdup(string);
883                         if (!str)
884                                 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
885
886                         stbl->strings[new_id - 1].string = str;
887                         *string_id = new_id;
888
889                         return EFI_EXIT(EFI_SUCCESS);
890                 }
891         }
892
893         return EFI_EXIT(EFI_NOT_FOUND);
894 }
895
896 static efi_status_t EFIAPI
897 get_string(const struct efi_hii_string_protocol *this,
898            const u8 *language,
899            efi_hii_handle_t package_list,
900            efi_string_id_t string_id,
901            efi_string_t string,
902            efi_uintn_t *string_size,
903            struct efi_font_info **string_font_info)
904 {
905         struct efi_hii_packagelist *hii = package_list;
906         struct efi_string_table *stbl;
907
908         EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
909                   package_list, string_id, string, string_size,
910                   string_font_info);
911
912         if (!package_list || !efi_hii_packagelist_exists(package_list))
913                 return EFI_EXIT(EFI_NOT_FOUND);
914
915         list_for_each_entry(stbl, &hii->string_tables, link) {
916                 if (language_match((char *)language, stbl->language)) {
917                         efi_string_t str;
918                         size_t len;
919
920                         if (stbl->nstrings < string_id)
921                                 return EFI_EXIT(EFI_NOT_FOUND);
922
923                         str = stbl->strings[string_id - 1].string;
924                         if (str) {
925                                 len = (u16_strlen(str) + 1) * sizeof(u16);
926                                 if (*string_size < len) {
927                                         *string_size = len;
928
929                                         return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
930                                 }
931                                 memcpy(string, str, len);
932                                 *string_size = len;
933                         } else {
934                                 return EFI_EXIT(EFI_NOT_FOUND);
935                         }
936
937                         return EFI_EXIT(EFI_SUCCESS);
938                 }
939         }
940
941         return EFI_EXIT(EFI_NOT_FOUND);
942 }
943
944 static efi_status_t EFIAPI
945 set_string(const struct efi_hii_string_protocol *this,
946            efi_hii_handle_t package_list,
947            efi_string_id_t string_id,
948            const u8 *language,
949            const efi_string_t string,
950            const struct efi_font_info *string_font_info)
951 {
952         struct efi_hii_packagelist *hii = package_list;
953         struct efi_string_table *stbl;
954
955         EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
956                   string_id, language, string, string_font_info);
957
958         if (!package_list || !efi_hii_packagelist_exists(package_list))
959                 return EFI_EXIT(EFI_NOT_FOUND);
960
961         if (string_id > hii->max_string_id)
962                 return EFI_EXIT(EFI_NOT_FOUND);
963
964         if (!string || !language)
965                 return EFI_EXIT(EFI_INVALID_PARAMETER);
966
967         list_for_each_entry(stbl, &hii->string_tables, link) {
968                 if (language_match((char *)language, stbl->language)) {
969                         efi_string_t str;
970
971                         if (hii->max_string_id < string_id)
972                                 return EFI_EXIT(EFI_NOT_FOUND);
973
974                         if (stbl->nstrings < string_id) {
975                                 void *buf;
976
977                                 buf = realloc(stbl->strings,
978                                               string_id
979                                                 * sizeof(stbl->strings[0]));
980                                 if (!buf)
981                                         return EFI_EXIT(EFI_OUT_OF_RESOURCES);
982
983                                 memset(&stbl->strings[string_id - 1], 0,
984                                        (string_id - stbl->nstrings)
985                                          * sizeof(stbl->strings[0]));
986                                 stbl->strings = buf;
987                         }
988
989                         str = u16_strdup(string);
990                         if (!str)
991                                 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
992
993                         free(stbl->strings[string_id - 1].string);
994                         stbl->strings[string_id - 1].string = str;
995
996                         return EFI_EXIT(EFI_SUCCESS);
997                 }
998         }
999
1000         return EFI_EXIT(EFI_NOT_FOUND);
1001 }
1002
1003 static efi_status_t EFIAPI
1004 get_languages(const struct efi_hii_string_protocol *this,
1005               efi_hii_handle_t package_list,
1006               u8 *languages,
1007               efi_uintn_t *languages_size)
1008 {
1009         struct efi_hii_packagelist *hii = package_list;
1010         struct efi_string_table *stbl;
1011         size_t len = 0;
1012         char *p;
1013
1014         EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
1015                   languages_size);
1016
1017         if (!package_list || !efi_hii_packagelist_exists(package_list))
1018                 return EFI_EXIT(EFI_NOT_FOUND);
1019
1020         if (!languages_size ||
1021             (*languages_size && !languages))
1022                 return EFI_EXIT(EFI_INVALID_PARAMETER);
1023
1024         /* figure out required size: */
1025         list_for_each_entry(stbl, &hii->string_tables, link) {
1026                 len += strlen((char *)stbl->language) + 1;
1027         }
1028
1029         if (*languages_size < len) {
1030                 *languages_size = len;
1031
1032                 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
1033         }
1034
1035         p = (char *)languages;
1036         list_for_each_entry(stbl, &hii->string_tables, link) {
1037                 if (p != (char *)languages)
1038                         *p++ = ';';
1039                 strcpy(p, stbl->language);
1040                 p += strlen((char *)stbl->language);
1041         }
1042         *p = '\0';
1043
1044         EFI_PRINT("languages: %s\n", languages);
1045
1046         return EFI_EXIT(EFI_SUCCESS);
1047 }
1048
1049 static efi_status_t EFIAPI
1050 get_secondary_languages(const struct efi_hii_string_protocol *this,
1051                         efi_hii_handle_t package_list,
1052                         const u8 *primary_language,
1053                         u8 *secondary_languages,
1054                         efi_uintn_t *secondary_languages_size)
1055 {
1056         struct efi_hii_packagelist *hii = package_list;
1057         struct efi_string_table *stbl;
1058         bool found = false;
1059
1060         EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
1061                   primary_language, secondary_languages,
1062                   secondary_languages_size);
1063
1064         if (!package_list || !efi_hii_packagelist_exists(package_list))
1065                 return EFI_EXIT(EFI_NOT_FOUND);
1066
1067         if (!secondary_languages_size ||
1068             (*secondary_languages_size && !secondary_languages))
1069                 return EFI_EXIT(EFI_INVALID_PARAMETER);
1070
1071         list_for_each_entry(stbl, &hii->string_tables, link) {
1072                 if (language_match((char *)primary_language, stbl->language)) {
1073                         found = true;
1074                         break;
1075                 }
1076         }
1077         if (!found)
1078                 return EFI_EXIT(EFI_INVALID_LANGUAGE);
1079
1080         /*
1081          * TODO: What is secondary language?
1082          * *secondary_languages = '\0';
1083          * *secondary_languages_size = 0;
1084          */
1085
1086         return EFI_EXIT(EFI_NOT_FOUND);
1087 }
1088
1089 const struct efi_hii_string_protocol efi_hii_string = {
1090         .new_string = new_string,
1091         .get_string = get_string,
1092         .set_string = set_string,
1093         .get_languages = get_languages,
1094         .get_secondary_languages = get_secondary_languages
1095 };