Merge branch 'master' of https://gitlab.denx.de/u-boot/custodians/u-boot-sunxi
[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                 while (idx > 0)
231                         free(stbl->strings[--idx].string);
232                 free(stbl->strings);
233         }
234         free(stbl);
235
236         return ret;
237 }
238
239 static void remove_guid_package(struct efi_hii_packagelist *hii)
240 {
241         struct efi_guid_data *data;
242
243         while (!list_empty(&hii->guid_list)) {
244                 data = list_first_entry(&hii->guid_list,
245                                         struct efi_guid_data, link);
246                 list_del(&data->link);
247                 free(data);
248         }
249 }
250
251 static efi_status_t
252 add_guid_package(struct efi_hii_packagelist *hii,
253                  struct efi_hii_guid_package *package)
254 {
255         struct efi_guid_data *data;
256
257         data = calloc(sizeof(*data), 1);
258         if (!data)
259                 return EFI_OUT_OF_RESOURCES;
260
261         /* TODO: we don't know any about data field */
262         memcpy(&data->package, package, sizeof(*package));
263         list_add_tail(&data->link, &hii->guid_list);
264
265         return EFI_SUCCESS;
266 }
267
268 static void free_keyboard_layouts(struct efi_keyboard_package_data *package)
269 {
270         struct efi_keyboard_layout_data *layout_data;
271
272         while (!list_empty(&package->keyboard_layout_list)) {
273                 layout_data = list_first_entry(&package->keyboard_layout_list,
274                                                struct efi_keyboard_layout_data,
275                                                link);
276                 list_del(&layout_data->link);
277                 list_del(&layout_data->link_sys);
278                 free(layout_data);
279         }
280 }
281
282 static void remove_keyboard_package(struct efi_hii_packagelist *hii)
283 {
284         struct efi_keyboard_package_data *package;
285
286         while (!list_empty(&hii->keyboard_packages)) {
287                 package = list_first_entry(&hii->keyboard_packages,
288                                            struct efi_keyboard_package_data,
289                                            link);
290                 free_keyboard_layouts(package);
291                 list_del(&package->link);
292                 free(package);
293         }
294 }
295
296 static efi_status_t
297 add_keyboard_package(struct efi_hii_packagelist *hii,
298                      struct efi_hii_keyboard_package *keyboard_package)
299 {
300         struct efi_keyboard_package_data *package_data;
301         struct efi_hii_keyboard_layout *layout;
302         struct efi_keyboard_layout_data *layout_data;
303         u16 layout_count, layout_length;
304         int i;
305
306         package_data = malloc(sizeof(*package_data));
307         if (!package_data)
308                 return EFI_OUT_OF_RESOURCES;
309         INIT_LIST_HEAD(&package_data->link);
310         INIT_LIST_HEAD(&package_data->keyboard_layout_list);
311
312         layout = &keyboard_package->layout[0];
313         layout_count = get_unaligned_le16(&keyboard_package->layout_count);
314         for (i = 0; i < layout_count; i++) {
315                 layout_length = get_unaligned_le16(&layout->layout_length);
316                 layout_data = malloc(sizeof(*layout_data) + layout_length);
317                 if (!layout_data)
318                         goto out;
319
320                 memcpy(&layout_data->keyboard_layout, layout, layout_length);
321                 list_add_tail(&layout_data->link,
322                               &package_data->keyboard_layout_list);
323                 list_add_tail(&layout_data->link_sys,
324                               &efi_keyboard_layout_list);
325
326                 layout += layout_length;
327         }
328
329         list_add_tail(&package_data->link, &hii->keyboard_packages);
330
331         return EFI_SUCCESS;
332
333 out:
334         free_keyboard_layouts(package_data);
335         free(package_data);
336
337         return EFI_OUT_OF_RESOURCES;
338 }
339
340 static struct efi_hii_packagelist *new_packagelist(void)
341 {
342         struct efi_hii_packagelist *hii;
343
344         hii = malloc(sizeof(*hii));
345         list_add_tail(&hii->link, &efi_package_lists);
346         hii->max_string_id = 0;
347         INIT_LIST_HEAD(&hii->string_tables);
348         INIT_LIST_HEAD(&hii->guid_list);
349         INIT_LIST_HEAD(&hii->keyboard_packages);
350
351         return hii;
352 }
353
354 static void free_packagelist(struct efi_hii_packagelist *hii)
355 {
356         remove_strings_package(hii);
357         remove_guid_package(hii);
358         remove_keyboard_package(hii);
359
360         list_del(&hii->link);
361         free(hii);
362 }
363
364 static efi_status_t
365 add_packages(struct efi_hii_packagelist *hii,
366              const struct efi_hii_package_list_header *package_list)
367 {
368         struct efi_hii_package_header *package;
369         void *end;
370         efi_status_t ret = EFI_SUCCESS;
371
372         end = ((void *)package_list)
373                 + get_unaligned_le32(&package_list->package_length);
374
375         EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid,
376                   get_unaligned_le32(&package_list->package_length));
377
378         package = ((void *)package_list) + sizeof(*package_list);
379         while ((void *)package < end) {
380                 EFI_PRINT("package=%p, package type=%x, length=%u\n", package,
381                           efi_hii_package_type(package),
382                           efi_hii_package_len(package));
383
384                 switch (efi_hii_package_type(package)) {
385                 case EFI_HII_PACKAGE_TYPE_GUID:
386                         ret = add_guid_package(hii,
387                                 (struct efi_hii_guid_package *)package);
388                         break;
389                 case EFI_HII_PACKAGE_FORMS:
390                         EFI_PRINT("Form package not supported\n");
391                         ret = EFI_INVALID_PARAMETER;
392                         break;
393                 case EFI_HII_PACKAGE_STRINGS:
394                         ret = add_strings_package(hii,
395                                 (struct efi_hii_strings_package *)package);
396                         break;
397                 case EFI_HII_PACKAGE_FONTS:
398                         EFI_PRINT("Font package not supported\n");
399                         ret = EFI_INVALID_PARAMETER;
400                         break;
401                 case EFI_HII_PACKAGE_IMAGES:
402                         EFI_PRINT("Image package not supported\n");
403                         ret = EFI_INVALID_PARAMETER;
404                         break;
405                 case EFI_HII_PACKAGE_SIMPLE_FONTS:
406                         EFI_PRINT("Simple font package not supported\n");
407                         ret = EFI_INVALID_PARAMETER;
408                         break;
409                 case EFI_HII_PACKAGE_DEVICE_PATH:
410                         EFI_PRINT("Device path package not supported\n");
411                         ret = EFI_INVALID_PARAMETER;
412                         break;
413                 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
414                         ret = add_keyboard_package(hii,
415                                 (struct efi_hii_keyboard_package *)package);
416                         break;
417                 case EFI_HII_PACKAGE_ANIMATIONS:
418                         EFI_PRINT("Animation package not supported\n");
419                         ret = EFI_INVALID_PARAMETER;
420                         break;
421                 case EFI_HII_PACKAGE_END:
422                         goto out;
423                 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
424                 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
425                 default:
426                         break;
427                 }
428
429                 if (ret != EFI_SUCCESS)
430                         return ret;
431
432                 package = (void *)package + efi_hii_package_len(package);
433         }
434 out:
435         // TODO in theory there is some notifications that should be sent..
436         return EFI_SUCCESS;
437 }
438
439 /*
440  * EFI_HII_DATABASE_PROTOCOL
441  */
442
443 static efi_status_t EFIAPI
444 new_package_list(const struct efi_hii_database_protocol *this,
445                  const struct efi_hii_package_list_header *package_list,
446                  const efi_handle_t driver_handle,
447                  efi_hii_handle_t *handle)
448 {
449         struct efi_hii_packagelist *hii;
450         efi_status_t ret;
451
452         EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
453
454         if (!package_list || !handle)
455                 return EFI_EXIT(EFI_INVALID_PARAMETER);
456
457         hii = new_packagelist();
458         if (!hii)
459                 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
460
461         ret = add_packages(hii, package_list);
462         if (ret != EFI_SUCCESS) {
463                 free_packagelist(hii);
464                 return EFI_EXIT(ret);
465         }
466
467         hii->driver_handle = driver_handle;
468         *handle = hii;
469
470         return EFI_EXIT(EFI_SUCCESS);
471 }
472
473 static efi_status_t EFIAPI
474 remove_package_list(const struct efi_hii_database_protocol *this,
475                     efi_hii_handle_t handle)
476 {
477         struct efi_hii_packagelist *hii = handle;
478
479         EFI_ENTRY("%p, %p", this, handle);
480
481         if (!handle || !efi_hii_packagelist_exists(handle))
482                 return EFI_EXIT(EFI_NOT_FOUND);
483
484         free_packagelist(hii);
485
486         return EFI_EXIT(EFI_SUCCESS);
487 }
488
489 static efi_status_t EFIAPI
490 update_package_list(const struct efi_hii_database_protocol *this,
491                     efi_hii_handle_t handle,
492                     const struct efi_hii_package_list_header *package_list)
493 {
494         struct efi_hii_packagelist *hii = handle;
495         struct efi_hii_package_header *package;
496         void *end;
497         efi_status_t ret = EFI_SUCCESS;
498
499         EFI_ENTRY("%p, %p, %p", this, handle, package_list);
500
501         if (!handle || !efi_hii_packagelist_exists(handle))
502                 return EFI_EXIT(EFI_NOT_FOUND);
503
504         if (!package_list)
505                 return EFI_EXIT(EFI_INVALID_PARAMETER);
506
507         EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid,
508                   get_unaligned_le32(&package_list->package_length));
509
510         package = ((void *)package_list) + sizeof(*package_list);
511         end = ((void *)package_list)
512                 + get_unaligned_le32(&package_list->package_length);
513
514         while ((void *)package < end) {
515                 EFI_PRINT("package=%p, package type=%x, length=%u\n", package,
516                           efi_hii_package_type(package),
517                           efi_hii_package_len(package));
518
519                 switch (efi_hii_package_type(package)) {
520                 case EFI_HII_PACKAGE_TYPE_GUID:
521                         remove_guid_package(hii);
522                         break;
523                 case EFI_HII_PACKAGE_FORMS:
524                         EFI_PRINT("Form package not supported\n");
525                         ret = EFI_INVALID_PARAMETER;
526                         break;
527                 case EFI_HII_PACKAGE_STRINGS:
528                         remove_strings_package(hii);
529                         break;
530                 case EFI_HII_PACKAGE_FONTS:
531                         EFI_PRINT("Font package not supported\n");
532                         ret = EFI_INVALID_PARAMETER;
533                         break;
534                 case EFI_HII_PACKAGE_IMAGES:
535                         EFI_PRINT("Image package not supported\n");
536                         ret = EFI_INVALID_PARAMETER;
537                         break;
538                 case EFI_HII_PACKAGE_SIMPLE_FONTS:
539                         EFI_PRINT("Simple font package not supported\n");
540                         ret = EFI_INVALID_PARAMETER;
541                         break;
542                 case EFI_HII_PACKAGE_DEVICE_PATH:
543                         EFI_PRINT("Device path package not supported\n");
544                         ret = EFI_INVALID_PARAMETER;
545                         break;
546                 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
547                         remove_keyboard_package(hii);
548                         break;
549                 case EFI_HII_PACKAGE_ANIMATIONS:
550                         EFI_PRINT("Animation package not supported\n");
551                         ret = EFI_INVALID_PARAMETER;
552                         break;
553                 case EFI_HII_PACKAGE_END:
554                         goto out;
555                 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
556                 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
557                 default:
558                         break;
559                 }
560
561                 /* TODO: already removed some packages */
562                 if (ret != EFI_SUCCESS)
563                         return EFI_EXIT(ret);
564
565                 package = ((void *)package)
566                           + efi_hii_package_len(package);
567         }
568 out:
569         ret = add_packages(hii, package_list);
570
571         return EFI_EXIT(ret);
572 }
573
574 static efi_status_t EFIAPI
575 list_package_lists(const struct efi_hii_database_protocol *this,
576                    u8 package_type,
577                    const efi_guid_t *package_guid,
578                    efi_uintn_t *handle_buffer_length,
579                    efi_hii_handle_t *handle)
580 {
581         struct efi_hii_packagelist *hii =
582                                 (struct efi_hii_packagelist *)handle;
583         int package_cnt, package_max;
584         efi_status_t ret = EFI_NOT_FOUND;
585
586         EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
587                   handle_buffer_length, handle);
588
589         if (!handle_buffer_length ||
590             (*handle_buffer_length && !handle)) {
591                 ret = EFI_INVALID_PARAMETER;
592                 goto out;
593         }
594
595         if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
596             (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) {
597                 ret = EFI_INVALID_PARAMETER;
598                 goto out;
599         }
600
601         EFI_PRINT("package type=%x, guid=%pUl, length=%zu\n", (int)package_type,
602                   package_guid, *handle_buffer_length);
603
604         package_cnt = 0;
605         package_max = *handle_buffer_length / sizeof(*handle);
606         list_for_each_entry(hii, &efi_package_lists, link) {
607                 switch (package_type) {
608                 case EFI_HII_PACKAGE_TYPE_ALL:
609                         break;
610                 case EFI_HII_PACKAGE_TYPE_GUID:
611                         if (!list_empty(&hii->guid_list))
612                                 break;
613                         continue;
614                 case EFI_HII_PACKAGE_STRINGS:
615                         if (!list_empty(&hii->string_tables))
616                                 break;
617                         continue;
618                 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
619                         if (!list_empty(&hii->keyboard_packages))
620                                 break;
621                         continue;
622                 default:
623                         continue;
624                 }
625
626                 package_cnt++;
627                 if (package_cnt <= package_max) {
628                         *handle++ = hii;
629                         ret = EFI_SUCCESS;
630                 } else {
631                         ret = EFI_BUFFER_TOO_SMALL;
632                 }
633         }
634         *handle_buffer_length = package_cnt * sizeof(*handle);
635 out:
636         return EFI_EXIT(ret);
637 }
638
639 static efi_status_t EFIAPI
640 export_package_lists(const struct efi_hii_database_protocol *this,
641                      efi_hii_handle_t handle,
642                      efi_uintn_t *buffer_size,
643                      struct efi_hii_package_list_header *buffer)
644 {
645         EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
646
647         if (!buffer_size || !buffer)
648                 return EFI_EXIT(EFI_INVALID_PARAMETER);
649
650         return EFI_EXIT(EFI_NOT_FOUND);
651 }
652
653 static efi_status_t EFIAPI
654 register_package_notify(const struct efi_hii_database_protocol *this,
655                         u8 package_type,
656                         const efi_guid_t *package_guid,
657                         const void *package_notify_fn,
658                         efi_uintn_t notify_type,
659                         efi_handle_t *notify_handle)
660 {
661         EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
662                   package_guid, package_notify_fn, notify_type,
663                   notify_handle);
664
665         if (!notify_handle)
666                 return EFI_EXIT(EFI_INVALID_PARAMETER);
667
668         if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
669             (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
670                 return EFI_EXIT(EFI_INVALID_PARAMETER);
671
672         return EFI_EXIT(EFI_OUT_OF_RESOURCES);
673 }
674
675 static efi_status_t EFIAPI
676 unregister_package_notify(const struct efi_hii_database_protocol *this,
677                           efi_handle_t notification_handle)
678 {
679         EFI_ENTRY("%p, %p", this, notification_handle);
680
681         return EFI_EXIT(EFI_NOT_FOUND);
682 }
683
684 static efi_status_t EFIAPI
685 find_keyboard_layouts(const struct efi_hii_database_protocol *this,
686                       u16 *key_guid_buffer_length,
687                       efi_guid_t *key_guid_buffer)
688 {
689         struct efi_keyboard_layout_data *layout_data;
690         int package_cnt, package_max;
691         efi_status_t ret = EFI_SUCCESS;
692
693         EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
694
695         if (!key_guid_buffer_length ||
696             (*key_guid_buffer_length && !key_guid_buffer))
697                 return EFI_EXIT(EFI_INVALID_PARAMETER);
698
699         package_cnt = 0;
700         package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer);
701         list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
702                 package_cnt++;
703                 if (package_cnt <= package_max)
704                         memcpy(key_guid_buffer++,
705                                &layout_data->keyboard_layout.guid,
706                                sizeof(*key_guid_buffer));
707                 else
708                         ret = EFI_BUFFER_TOO_SMALL;
709         }
710         *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer);
711
712         return EFI_EXIT(ret);
713 }
714
715 static efi_status_t EFIAPI
716 get_keyboard_layout(const struct efi_hii_database_protocol *this,
717                     efi_guid_t *key_guid,
718                     u16 *keyboard_layout_length,
719                     struct efi_hii_keyboard_layout *keyboard_layout)
720 {
721         struct efi_keyboard_layout_data *layout_data;
722         u16 layout_length;
723
724         EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
725                   keyboard_layout);
726
727         if (!keyboard_layout_length ||
728             (*keyboard_layout_length && !keyboard_layout))
729                 return EFI_EXIT(EFI_INVALID_PARAMETER);
730
731         /* TODO: no notion of current keyboard layout */
732         if (!key_guid)
733                 return EFI_EXIT(EFI_INVALID_PARAMETER);
734
735         list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
736                 if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid))
737                         goto found;
738         }
739
740         return EFI_EXIT(EFI_NOT_FOUND);
741
742 found:
743         layout_length =
744                 get_unaligned_le16(&layout_data->keyboard_layout.layout_length);
745         if (*keyboard_layout_length < layout_length) {
746                 *keyboard_layout_length = layout_length;
747                 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
748         }
749
750         memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length);
751
752         return EFI_EXIT(EFI_SUCCESS);
753 }
754
755 static efi_status_t EFIAPI
756 set_keyboard_layout(const struct efi_hii_database_protocol *this,
757                     efi_guid_t *key_guid)
758 {
759         EFI_ENTRY("%p, %pUl", this, key_guid);
760
761         return EFI_EXIT(EFI_NOT_FOUND);
762 }
763
764 static efi_status_t EFIAPI
765 get_package_list_handle(const struct efi_hii_database_protocol *this,
766                         efi_hii_handle_t package_list_handle,
767                         efi_handle_t *driver_handle)
768 {
769         struct efi_hii_packagelist *hii;
770
771         EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
772
773         if (!driver_handle)
774                 return EFI_EXIT(EFI_INVALID_PARAMETER);
775
776         list_for_each_entry(hii, &efi_package_lists, link) {
777                 if (hii == package_list_handle) {
778                         *driver_handle = hii->driver_handle;
779                         return EFI_EXIT(EFI_SUCCESS);
780                 }
781         }
782
783         return EFI_EXIT(EFI_NOT_FOUND);
784 }
785
786 const struct efi_hii_database_protocol efi_hii_database = {
787         .new_package_list = new_package_list,
788         .remove_package_list = remove_package_list,
789         .update_package_list = update_package_list,
790         .list_package_lists = list_package_lists,
791         .export_package_lists = export_package_lists,
792         .register_package_notify = register_package_notify,
793         .unregister_package_notify = unregister_package_notify,
794         .find_keyboard_layouts = find_keyboard_layouts,
795         .get_keyboard_layout = get_keyboard_layout,
796         .set_keyboard_layout = set_keyboard_layout,
797         .get_package_list_handle = get_package_list_handle
798 };
799
800 /*
801  * EFI_HII_STRING_PROTOCOL
802  */
803
804 static bool language_match(char *language, char *languages)
805 {
806         size_t n;
807
808         n = strlen(language);
809         /* match primary language? */
810         if (!strncasecmp(language, languages, n) &&
811             (languages[n] == ';' || languages[n] == '\0'))
812                 return true;
813
814         return false;
815 }
816
817 static efi_status_t EFIAPI
818 new_string(const struct efi_hii_string_protocol *this,
819            efi_hii_handle_t package_list,
820            efi_string_id_t *string_id,
821            const u8 *language,
822            const u16 *language_name,
823            const efi_string_t string,
824            const struct efi_font_info *string_font_info)
825 {
826         struct efi_hii_packagelist *hii = package_list;
827         struct efi_string_table *stbl;
828
829         EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
830                   string_id, language, language_name, string,
831                   string_font_info);
832
833         if (!package_list || !efi_hii_packagelist_exists(package_list))
834                 return EFI_EXIT(EFI_NOT_FOUND);
835
836         if (!string_id || !language || !string)
837                 return EFI_EXIT(EFI_INVALID_PARAMETER);
838
839         list_for_each_entry(stbl, &hii->string_tables, link) {
840                 if (language_match((char *)language, stbl->language)) {
841                         efi_string_id_t new_id;
842                         void *buf;
843                         efi_string_t str;
844
845                         new_id = ++hii->max_string_id;
846                         if (stbl->nstrings < new_id) {
847                                 buf = realloc(stbl->strings,
848                                               sizeof(stbl->strings[0])
849                                                 * new_id);
850                                 if (!buf)
851                                         return EFI_EXIT(EFI_OUT_OF_RESOURCES);
852
853                                 memset(&stbl->strings[stbl->nstrings], 0,
854                                        (new_id - stbl->nstrings)
855                                          * sizeof(stbl->strings[0]));
856                                 stbl->strings = buf;
857                                 stbl->nstrings = new_id;
858                         }
859
860                         str = u16_strdup(string);
861                         if (!str)
862                                 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
863
864                         stbl->strings[new_id - 1].string = str;
865                         *string_id = new_id;
866
867                         return EFI_EXIT(EFI_SUCCESS);
868                 }
869         }
870
871         return EFI_EXIT(EFI_NOT_FOUND);
872 }
873
874 static efi_status_t EFIAPI
875 get_string(const struct efi_hii_string_protocol *this,
876            const u8 *language,
877            efi_hii_handle_t package_list,
878            efi_string_id_t string_id,
879            efi_string_t string,
880            efi_uintn_t *string_size,
881            struct efi_font_info **string_font_info)
882 {
883         struct efi_hii_packagelist *hii = package_list;
884         struct efi_string_table *stbl;
885
886         EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
887                   package_list, string_id, string, string_size,
888                   string_font_info);
889
890         if (!package_list || !efi_hii_packagelist_exists(package_list))
891                 return EFI_EXIT(EFI_NOT_FOUND);
892
893         list_for_each_entry(stbl, &hii->string_tables, link) {
894                 if (language_match((char *)language, stbl->language)) {
895                         efi_string_t str;
896                         size_t len;
897
898                         if (stbl->nstrings < string_id)
899                                 return EFI_EXIT(EFI_NOT_FOUND);
900
901                         str = stbl->strings[string_id - 1].string;
902                         if (str) {
903                                 len = (u16_strlen(str) + 1) * sizeof(u16);
904                                 if (*string_size < len) {
905                                         *string_size = len;
906
907                                         return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
908                                 }
909                                 memcpy(string, str, len);
910                                 *string_size = len;
911                         } else {
912                                 return EFI_EXIT(EFI_NOT_FOUND);
913                         }
914
915                         return EFI_EXIT(EFI_SUCCESS);
916                 }
917         }
918
919         return EFI_EXIT(EFI_NOT_FOUND);
920 }
921
922 static efi_status_t EFIAPI
923 set_string(const struct efi_hii_string_protocol *this,
924            efi_hii_handle_t package_list,
925            efi_string_id_t string_id,
926            const u8 *language,
927            const efi_string_t string,
928            const struct efi_font_info *string_font_info)
929 {
930         struct efi_hii_packagelist *hii = package_list;
931         struct efi_string_table *stbl;
932
933         EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
934                   string_id, language, string, string_font_info);
935
936         if (!package_list || !efi_hii_packagelist_exists(package_list))
937                 return EFI_EXIT(EFI_NOT_FOUND);
938
939         if (string_id > hii->max_string_id)
940                 return EFI_EXIT(EFI_NOT_FOUND);
941
942         if (!string || !language)
943                 return EFI_EXIT(EFI_INVALID_PARAMETER);
944
945         list_for_each_entry(stbl, &hii->string_tables, link) {
946                 if (language_match((char *)language, stbl->language)) {
947                         efi_string_t str;
948
949                         if (hii->max_string_id < string_id)
950                                 return EFI_EXIT(EFI_NOT_FOUND);
951
952                         if (stbl->nstrings < string_id) {
953                                 void *buf;
954
955                                 buf = realloc(stbl->strings,
956                                               string_id
957                                                 * sizeof(stbl->strings[0]));
958                                 if (!buf)
959                                         return EFI_EXIT(EFI_OUT_OF_RESOURCES);
960
961                                 memset(&stbl->strings[string_id - 1], 0,
962                                        (string_id - stbl->nstrings)
963                                          * sizeof(stbl->strings[0]));
964                                 stbl->strings = buf;
965                         }
966
967                         str = u16_strdup(string);
968                         if (!str)
969                                 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
970
971                         free(stbl->strings[string_id - 1].string);
972                         stbl->strings[string_id - 1].string = str;
973
974                         return EFI_EXIT(EFI_SUCCESS);
975                 }
976         }
977
978         return EFI_EXIT(EFI_NOT_FOUND);
979 }
980
981 static efi_status_t EFIAPI
982 get_languages(const struct efi_hii_string_protocol *this,
983               efi_hii_handle_t package_list,
984               u8 *languages,
985               efi_uintn_t *languages_size)
986 {
987         struct efi_hii_packagelist *hii = package_list;
988         struct efi_string_table *stbl;
989         size_t len = 0;
990         char *p;
991
992         EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
993                   languages_size);
994
995         if (!package_list || !efi_hii_packagelist_exists(package_list))
996                 return EFI_EXIT(EFI_NOT_FOUND);
997
998         if (!languages_size ||
999             (*languages_size && !languages))
1000                 return EFI_EXIT(EFI_INVALID_PARAMETER);
1001
1002         /* figure out required size: */
1003         list_for_each_entry(stbl, &hii->string_tables, link) {
1004                 len += strlen((char *)stbl->language) + 1;
1005         }
1006
1007         if (*languages_size < len) {
1008                 *languages_size = len;
1009
1010                 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
1011         }
1012
1013         p = (char *)languages;
1014         list_for_each_entry(stbl, &hii->string_tables, link) {
1015                 if (p != (char *)languages)
1016                         *p++ = ';';
1017                 strcpy(p, stbl->language);
1018                 p += strlen((char *)stbl->language);
1019         }
1020         *p = '\0';
1021
1022         EFI_PRINT("languages: %s\n", languages);
1023
1024         return EFI_EXIT(EFI_SUCCESS);
1025 }
1026
1027 static efi_status_t EFIAPI
1028 get_secondary_languages(const struct efi_hii_string_protocol *this,
1029                         efi_hii_handle_t package_list,
1030                         const u8 *primary_language,
1031                         u8 *secondary_languages,
1032                         efi_uintn_t *secondary_languages_size)
1033 {
1034         struct efi_hii_packagelist *hii = package_list;
1035         struct efi_string_table *stbl;
1036         bool found = false;
1037
1038         EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
1039                   primary_language, secondary_languages,
1040                   secondary_languages_size);
1041
1042         if (!package_list || !efi_hii_packagelist_exists(package_list))
1043                 return EFI_EXIT(EFI_NOT_FOUND);
1044
1045         if (!secondary_languages_size ||
1046             (*secondary_languages_size && !secondary_languages))
1047                 return EFI_EXIT(EFI_INVALID_PARAMETER);
1048
1049         list_for_each_entry(stbl, &hii->string_tables, link) {
1050                 if (language_match((char *)primary_language, stbl->language)) {
1051                         found = true;
1052                         break;
1053                 }
1054         }
1055         if (!found)
1056                 return EFI_EXIT(EFI_INVALID_LANGUAGE);
1057
1058         /*
1059          * TODO: What is secondary language?
1060          * *secondary_languages = '\0';
1061          * *secondary_languages_size = 0;
1062          */
1063
1064         return EFI_EXIT(EFI_NOT_FOUND);
1065 }
1066
1067 const struct efi_hii_string_protocol efi_hii_string = {
1068         .new_string = new_string,
1069         .get_string = get_string,
1070         .set_string = set_string,
1071         .get_languages = get_languages,
1072         .get_secondary_languages = get_secondary_languages
1073 };