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