mx6sabreauto: convert to DM_VIDEO
[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_SUCCESS;
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                 return EFI_EXIT(EFI_INVALID_PARAMETER);
592
593         if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
594             (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
595                 return EFI_EXIT(EFI_INVALID_PARAMETER);
596
597         EFI_PRINT("package type=%x, guid=%pUl, length=%zu\n", (int)package_type,
598                   package_guid, *handle_buffer_length);
599
600         package_cnt = 0;
601         package_max = *handle_buffer_length / sizeof(*handle);
602         list_for_each_entry(hii, &efi_package_lists, link) {
603                 switch (package_type) {
604                 case EFI_HII_PACKAGE_TYPE_ALL:
605                         break;
606                 case EFI_HII_PACKAGE_TYPE_GUID:
607                         if (!list_empty(&hii->guid_list))
608                                 break;
609                         continue;
610                 case EFI_HII_PACKAGE_FORMS:
611                         EFI_PRINT("Form package not supported\n");
612                         ret = EFI_INVALID_PARAMETER;
613                         continue;
614                 case EFI_HII_PACKAGE_STRINGS:
615                         if (!list_empty(&hii->string_tables))
616                                 break;
617                         continue;
618                 case EFI_HII_PACKAGE_FONTS:
619                         EFI_PRINT("Font package not supported\n");
620                         ret = EFI_INVALID_PARAMETER;
621                         continue;
622                 case EFI_HII_PACKAGE_IMAGES:
623                         EFI_PRINT("Image package not supported\n");
624                         ret = EFI_INVALID_PARAMETER;
625                         continue;
626                 case EFI_HII_PACKAGE_SIMPLE_FONTS:
627                         EFI_PRINT("Simple font package not supported\n");
628                         ret = EFI_INVALID_PARAMETER;
629                         continue;
630                 case EFI_HII_PACKAGE_DEVICE_PATH:
631                         EFI_PRINT("Device path package not supported\n");
632                         ret = EFI_INVALID_PARAMETER;
633                         continue;
634                 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
635                         if (!list_empty(&hii->keyboard_packages))
636                                 break;
637                         continue;
638                 case EFI_HII_PACKAGE_ANIMATIONS:
639                         EFI_PRINT("Animation package not supported\n");
640                         ret = EFI_INVALID_PARAMETER;
641                         continue;
642                 case EFI_HII_PACKAGE_END:
643                 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
644                 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
645                 default:
646                         continue;
647                 }
648
649                 package_cnt++;
650                 if (package_cnt <= package_max)
651                         *handle++ = hii;
652                 else
653                         ret = EFI_BUFFER_TOO_SMALL;
654         }
655         *handle_buffer_length = package_cnt * sizeof(*handle);
656
657         return EFI_EXIT(ret);
658 }
659
660 static efi_status_t EFIAPI
661 export_package_lists(const struct efi_hii_database_protocol *this,
662                      efi_hii_handle_t handle,
663                      efi_uintn_t *buffer_size,
664                      struct efi_hii_package_list_header *buffer)
665 {
666         EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
667
668         if (!buffer_size || !buffer)
669                 return EFI_EXIT(EFI_INVALID_PARAMETER);
670
671         return EFI_EXIT(EFI_NOT_FOUND);
672 }
673
674 static efi_status_t EFIAPI
675 register_package_notify(const struct efi_hii_database_protocol *this,
676                         u8 package_type,
677                         const efi_guid_t *package_guid,
678                         const void *package_notify_fn,
679                         efi_uintn_t notify_type,
680                         efi_handle_t *notify_handle)
681 {
682         EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
683                   package_guid, package_notify_fn, notify_type,
684                   notify_handle);
685
686         if (!notify_handle)
687                 return EFI_EXIT(EFI_INVALID_PARAMETER);
688
689         if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
690             (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
691                 return EFI_EXIT(EFI_INVALID_PARAMETER);
692
693         return EFI_EXIT(EFI_OUT_OF_RESOURCES);
694 }
695
696 static efi_status_t EFIAPI
697 unregister_package_notify(const struct efi_hii_database_protocol *this,
698                           efi_handle_t notification_handle)
699 {
700         EFI_ENTRY("%p, %p", this, notification_handle);
701
702         return EFI_EXIT(EFI_NOT_FOUND);
703 }
704
705 static efi_status_t EFIAPI
706 find_keyboard_layouts(const struct efi_hii_database_protocol *this,
707                       u16 *key_guid_buffer_length,
708                       efi_guid_t *key_guid_buffer)
709 {
710         struct efi_keyboard_layout_data *layout_data;
711         int package_cnt, package_max;
712         efi_status_t ret = EFI_SUCCESS;
713
714         EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
715
716         if (!key_guid_buffer_length ||
717             (*key_guid_buffer_length && !key_guid_buffer))
718                 return EFI_EXIT(EFI_INVALID_PARAMETER);
719
720         package_cnt = 0;
721         package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer);
722         list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
723                 package_cnt++;
724                 if (package_cnt <= package_max)
725                         memcpy(key_guid_buffer++,
726                                &layout_data->keyboard_layout.guid,
727                                sizeof(*key_guid_buffer));
728                 else
729                         ret = EFI_BUFFER_TOO_SMALL;
730         }
731         *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer);
732
733         return EFI_EXIT(ret);
734 }
735
736 static efi_status_t EFIAPI
737 get_keyboard_layout(const struct efi_hii_database_protocol *this,
738                     efi_guid_t *key_guid,
739                     u16 *keyboard_layout_length,
740                     struct efi_hii_keyboard_layout *keyboard_layout)
741 {
742         struct efi_keyboard_layout_data *layout_data;
743         u16 layout_length;
744
745         EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
746                   keyboard_layout);
747
748         if (!keyboard_layout_length ||
749             (*keyboard_layout_length && !keyboard_layout))
750                 return EFI_EXIT(EFI_INVALID_PARAMETER);
751
752         /* TODO: no notion of current keyboard layout */
753         if (!key_guid)
754                 return EFI_EXIT(EFI_INVALID_PARAMETER);
755
756         list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
757                 if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid))
758                         goto found;
759         }
760
761         return EFI_EXIT(EFI_NOT_FOUND);
762
763 found:
764         layout_length =
765                 get_unaligned_le16(&layout_data->keyboard_layout.layout_length);
766         if (*keyboard_layout_length < layout_length) {
767                 *keyboard_layout_length = layout_length;
768                 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
769         }
770
771         memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length);
772
773         return EFI_EXIT(EFI_SUCCESS);
774 }
775
776 static efi_status_t EFIAPI
777 set_keyboard_layout(const struct efi_hii_database_protocol *this,
778                     efi_guid_t *key_guid)
779 {
780         EFI_ENTRY("%p, %pUl", this, key_guid);
781
782         return EFI_EXIT(EFI_NOT_FOUND);
783 }
784
785 static efi_status_t EFIAPI
786 get_package_list_handle(const struct efi_hii_database_protocol *this,
787                         efi_hii_handle_t package_list_handle,
788                         efi_handle_t *driver_handle)
789 {
790         struct efi_hii_packagelist *hii;
791
792         EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
793
794         if (!driver_handle)
795                 return EFI_EXIT(EFI_INVALID_PARAMETER);
796
797         list_for_each_entry(hii, &efi_package_lists, link) {
798                 if (hii == package_list_handle) {
799                         *driver_handle = hii->driver_handle;
800                         return EFI_EXIT(EFI_SUCCESS);
801                 }
802         }
803
804         return EFI_EXIT(EFI_NOT_FOUND);
805 }
806
807 const struct efi_hii_database_protocol efi_hii_database = {
808         .new_package_list = new_package_list,
809         .remove_package_list = remove_package_list,
810         .update_package_list = update_package_list,
811         .list_package_lists = list_package_lists,
812         .export_package_lists = export_package_lists,
813         .register_package_notify = register_package_notify,
814         .unregister_package_notify = unregister_package_notify,
815         .find_keyboard_layouts = find_keyboard_layouts,
816         .get_keyboard_layout = get_keyboard_layout,
817         .set_keyboard_layout = set_keyboard_layout,
818         .get_package_list_handle = get_package_list_handle
819 };
820
821 /*
822  * EFI_HII_STRING_PROTOCOL
823  */
824
825 static bool language_match(char *language, char *languages)
826 {
827         size_t n;
828
829         n = strlen(language);
830         /* match primary language? */
831         if (!strncasecmp(language, languages, n) &&
832             (languages[n] == ';' || languages[n] == '\0'))
833                 return true;
834
835         return false;
836 }
837
838 static efi_status_t EFIAPI
839 new_string(const struct efi_hii_string_protocol *this,
840            efi_hii_handle_t package_list,
841            efi_string_id_t *string_id,
842            const u8 *language,
843            const u16 *language_name,
844            const efi_string_t string,
845            const struct efi_font_info *string_font_info)
846 {
847         struct efi_hii_packagelist *hii = package_list;
848         struct efi_string_table *stbl;
849
850         EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
851                   string_id, language, language_name, string,
852                   string_font_info);
853
854         if (!package_list || !efi_hii_packagelist_exists(package_list))
855                 return EFI_EXIT(EFI_NOT_FOUND);
856
857         if (!string_id || !language || !string)
858                 return EFI_EXIT(EFI_INVALID_PARAMETER);
859
860         list_for_each_entry(stbl, &hii->string_tables, link) {
861                 if (language_match((char *)language, stbl->language)) {
862                         efi_string_id_t new_id;
863                         void *buf;
864                         efi_string_t str;
865
866                         new_id = ++hii->max_string_id;
867                         if (stbl->nstrings < new_id) {
868                                 buf = realloc(stbl->strings,
869                                               sizeof(stbl->strings[0])
870                                                 * new_id);
871                                 if (!buf)
872                                         return EFI_EXIT(EFI_OUT_OF_RESOURCES);
873
874                                 memset(&stbl->strings[stbl->nstrings], 0,
875                                        (new_id - stbl->nstrings)
876                                          * sizeof(stbl->strings[0]));
877                                 stbl->strings = buf;
878                                 stbl->nstrings = new_id;
879                         }
880
881                         str = u16_strdup(string);
882                         if (!str)
883                                 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
884
885                         stbl->strings[new_id - 1].string = str;
886                         *string_id = new_id;
887
888                         return EFI_EXIT(EFI_SUCCESS);
889                 }
890         }
891
892         return EFI_EXIT(EFI_NOT_FOUND);
893 }
894
895 static efi_status_t EFIAPI
896 get_string(const struct efi_hii_string_protocol *this,
897            const u8 *language,
898            efi_hii_handle_t package_list,
899            efi_string_id_t string_id,
900            efi_string_t string,
901            efi_uintn_t *string_size,
902            struct efi_font_info **string_font_info)
903 {
904         struct efi_hii_packagelist *hii = package_list;
905         struct efi_string_table *stbl;
906
907         EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
908                   package_list, string_id, string, string_size,
909                   string_font_info);
910
911         if (!package_list || !efi_hii_packagelist_exists(package_list))
912                 return EFI_EXIT(EFI_NOT_FOUND);
913
914         list_for_each_entry(stbl, &hii->string_tables, link) {
915                 if (language_match((char *)language, stbl->language)) {
916                         efi_string_t str;
917                         size_t len;
918
919                         if (stbl->nstrings < string_id)
920                                 return EFI_EXIT(EFI_NOT_FOUND);
921
922                         str = stbl->strings[string_id - 1].string;
923                         if (str) {
924                                 len = (u16_strlen(str) + 1) * sizeof(u16);
925                                 if (*string_size < len) {
926                                         *string_size = len;
927
928                                         return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
929                                 }
930                                 memcpy(string, str, len);
931                                 *string_size = len;
932                         } else {
933                                 return EFI_EXIT(EFI_NOT_FOUND);
934                         }
935
936                         return EFI_EXIT(EFI_SUCCESS);
937                 }
938         }
939
940         return EFI_EXIT(EFI_NOT_FOUND);
941 }
942
943 static efi_status_t EFIAPI
944 set_string(const struct efi_hii_string_protocol *this,
945            efi_hii_handle_t package_list,
946            efi_string_id_t string_id,
947            const u8 *language,
948            const efi_string_t string,
949            const struct efi_font_info *string_font_info)
950 {
951         struct efi_hii_packagelist *hii = package_list;
952         struct efi_string_table *stbl;
953
954         EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
955                   string_id, language, string, string_font_info);
956
957         if (!package_list || !efi_hii_packagelist_exists(package_list))
958                 return EFI_EXIT(EFI_NOT_FOUND);
959
960         if (string_id > hii->max_string_id)
961                 return EFI_EXIT(EFI_NOT_FOUND);
962
963         if (!string || !language)
964                 return EFI_EXIT(EFI_INVALID_PARAMETER);
965
966         list_for_each_entry(stbl, &hii->string_tables, link) {
967                 if (language_match((char *)language, stbl->language)) {
968                         efi_string_t str;
969
970                         if (hii->max_string_id < string_id)
971                                 return EFI_EXIT(EFI_NOT_FOUND);
972
973                         if (stbl->nstrings < string_id) {
974                                 void *buf;
975
976                                 buf = realloc(stbl->strings,
977                                               string_id
978                                                 * sizeof(stbl->strings[0]));
979                                 if (!buf)
980                                         return EFI_EXIT(EFI_OUT_OF_RESOURCES);
981
982                                 memset(&stbl->strings[string_id - 1], 0,
983                                        (string_id - stbl->nstrings)
984                                          * sizeof(stbl->strings[0]));
985                                 stbl->strings = buf;
986                         }
987
988                         str = u16_strdup(string);
989                         if (!str)
990                                 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
991
992                         free(stbl->strings[string_id - 1].string);
993                         stbl->strings[string_id - 1].string = str;
994
995                         return EFI_EXIT(EFI_SUCCESS);
996                 }
997         }
998
999         return EFI_EXIT(EFI_NOT_FOUND);
1000 }
1001
1002 static efi_status_t EFIAPI
1003 get_languages(const struct efi_hii_string_protocol *this,
1004               efi_hii_handle_t package_list,
1005               u8 *languages,
1006               efi_uintn_t *languages_size)
1007 {
1008         struct efi_hii_packagelist *hii = package_list;
1009         struct efi_string_table *stbl;
1010         size_t len = 0;
1011         char *p;
1012
1013         EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
1014                   languages_size);
1015
1016         if (!package_list || !efi_hii_packagelist_exists(package_list))
1017                 return EFI_EXIT(EFI_NOT_FOUND);
1018
1019         if (!languages_size ||
1020             (*languages_size && !languages))
1021                 return EFI_EXIT(EFI_INVALID_PARAMETER);
1022
1023         /* figure out required size: */
1024         list_for_each_entry(stbl, &hii->string_tables, link) {
1025                 len += strlen((char *)stbl->language) + 1;
1026         }
1027
1028         if (*languages_size < len) {
1029                 *languages_size = len;
1030
1031                 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
1032         }
1033
1034         p = (char *)languages;
1035         list_for_each_entry(stbl, &hii->string_tables, link) {
1036                 if (p != (char *)languages)
1037                         *p++ = ';';
1038                 strcpy(p, stbl->language);
1039                 p += strlen((char *)stbl->language);
1040         }
1041         *p = '\0';
1042
1043         EFI_PRINT("languages: %s\n", languages);
1044
1045         return EFI_EXIT(EFI_SUCCESS);
1046 }
1047
1048 static efi_status_t EFIAPI
1049 get_secondary_languages(const struct efi_hii_string_protocol *this,
1050                         efi_hii_handle_t package_list,
1051                         const u8 *primary_language,
1052                         u8 *secondary_languages,
1053                         efi_uintn_t *secondary_languages_size)
1054 {
1055         struct efi_hii_packagelist *hii = package_list;
1056         struct efi_string_table *stbl;
1057         bool found = false;
1058
1059         EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
1060                   primary_language, secondary_languages,
1061                   secondary_languages_size);
1062
1063         if (!package_list || !efi_hii_packagelist_exists(package_list))
1064                 return EFI_EXIT(EFI_NOT_FOUND);
1065
1066         if (!secondary_languages_size ||
1067             (*secondary_languages_size && !secondary_languages))
1068                 return EFI_EXIT(EFI_INVALID_PARAMETER);
1069
1070         list_for_each_entry(stbl, &hii->string_tables, link) {
1071                 if (language_match((char *)primary_language, stbl->language)) {
1072                         found = true;
1073                         break;
1074                 }
1075         }
1076         if (!found)
1077                 return EFI_EXIT(EFI_INVALID_LANGUAGE);
1078
1079         /*
1080          * TODO: What is secondary language?
1081          * *secondary_languages = '\0';
1082          * *secondary_languages_size = 0;
1083          */
1084
1085         return EFI_EXIT(EFI_NOT_FOUND);
1086 }
1087
1088 const struct efi_hii_string_protocol efi_hii_string = {
1089         .new_string = new_string,
1090         .get_string = get_string,
1091         .set_string = set_string,
1092         .get_languages = get_languages,
1093         .get_secondary_languages = get_secondary_languages
1094 };