blob: 89e1a6c2369c4cdf41e415944b8519c5c28bcede [file] [log] [blame]
Leif Lindholm5aab1b82019-01-21 12:12:57 +09001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * EFI Human Interface Infrastructure ... database and packages
4 *
5 * Copyright (c) 2017 Leif Lindholm
6 * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
7 */
8
9#include <common.h>
10#include <efi_loader.h>
11#include <malloc.h>
12#include <asm/unaligned.h>
13
14const efi_guid_t efi_guid_hii_database_protocol
15 = EFI_HII_DATABASE_PROTOCOL_GUID;
16const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID;
17
18static LIST_HEAD(efi_package_lists);
AKASHI Takahiro976e9312019-01-21 12:12:59 +090019static LIST_HEAD(efi_keyboard_layout_list);
Leif Lindholm5aab1b82019-01-21 12:12:57 +090020
21struct 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 */
AKASHI Takahiro0fa82b92019-01-21 12:12:58 +090027 struct list_head guid_list;
AKASHI Takahiro976e9312019-01-21 12:12:59 +090028 struct list_head keyboard_packages;
Leif Lindholm5aab1b82019-01-21 12:12:57 +090029
30 /* we could also track fonts, images, etc */
31};
32
33static 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
48static 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
58static 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
68struct efi_string_info {
69 efi_string_t string;
70 /* we could also track font info, etc */
71};
72
73struct 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
AKASHI Takahiro0fa82b92019-01-21 12:12:58 +090086struct efi_guid_data {
87 struct list_head link;
88 struct efi_hii_guid_package package;
89};
90
AKASHI Takahiro976e9312019-01-21 12:12:59 +090091struct 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
97struct efi_keyboard_package_data {
98 struct list_head link; /* in package_list */
99 struct list_head keyboard_layout_list;
100};
101
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900102static 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
113static 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
125static efi_status_t
126add_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 debug("header_size: %08x\n",
136 get_unaligned_le32(&strings_package->header_size));
137 debug("string_info_offset: %08x\n",
138 get_unaligned_le32(&strings_package->string_info_offset));
139 debug("language_name: %u\n",
140 get_unaligned_le16(&strings_package->language_name));
141 debug("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 debug("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 debug("%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 debug("unknown HII string block type: %02x\n",
214 block->block_type);
215 ret = EFI_INVALID_PARAMETER;
216 goto error;
217 }
218 }
219
220out:
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
227error:
228 if (stbl) {
229 free(stbl->language);
230 if (idx > 0)
231 while (--idx >= 0)
232 free(stbl->strings[idx].string);
233 free(stbl->strings);
234 }
235 free(stbl);
236
237 return ret;
238}
239
AKASHI Takahiro0fa82b92019-01-21 12:12:58 +0900240static void remove_guid_package(struct efi_hii_packagelist *hii)
241{
242 struct efi_guid_data *data;
243
244 while (!list_empty(&hii->guid_list)) {
245 data = list_first_entry(&hii->guid_list,
246 struct efi_guid_data, link);
247 list_del(&data->link);
248 free(data);
249 }
250}
251
252static efi_status_t
253add_guid_package(struct efi_hii_packagelist *hii,
254 struct efi_hii_guid_package *package)
255{
256 struct efi_guid_data *data;
257
258 data = calloc(sizeof(*data), 1);
259 if (!data)
260 return EFI_OUT_OF_RESOURCES;
261
262 /* TODO: we don't know any about data field */
263 memcpy(&data->package, package, sizeof(*package));
264 list_add_tail(&data->link, &hii->guid_list);
265
266 return EFI_SUCCESS;
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900267}
268
269static void free_keyboard_layouts(struct efi_keyboard_package_data *package)
270{
271 struct efi_keyboard_layout_data *layout_data;
272
273 while (!list_empty(&package->keyboard_layout_list)) {
274 layout_data = list_first_entry(&package->keyboard_layout_list,
275 struct efi_keyboard_layout_data,
276 link);
277 list_del(&layout_data->link);
278 list_del(&layout_data->link_sys);
279 free(layout_data);
280 }
281}
282
283static void remove_keyboard_package(struct efi_hii_packagelist *hii)
284{
285 struct efi_keyboard_package_data *package;
286
287 while (!list_empty(&hii->keyboard_packages)) {
288 package = list_first_entry(&hii->keyboard_packages,
289 struct efi_keyboard_package_data,
290 link);
291 free_keyboard_layouts(package);
292 list_del(&package->link);
293 free(package);
294 }
295}
296
297static efi_status_t
298add_keyboard_package(struct efi_hii_packagelist *hii,
299 struct efi_hii_keyboard_package *keyboard_package)
300{
301 struct efi_keyboard_package_data *package_data;
302 struct efi_hii_keyboard_layout *layout;
303 struct efi_keyboard_layout_data *layout_data;
304 u16 layout_count, layout_length;
305 int i;
306
307 package_data = malloc(sizeof(*package_data));
308 if (!package_data)
309 return EFI_OUT_OF_RESOURCES;
310 INIT_LIST_HEAD(&package_data->link);
311 INIT_LIST_HEAD(&package_data->keyboard_layout_list);
312
313 layout = &keyboard_package->layout[0];
314 layout_count = get_unaligned_le16(&keyboard_package->layout_count);
315 for (i = 0; i < layout_count; i++) {
316 layout_length = get_unaligned_le16(&layout->layout_length);
317 layout_data = malloc(sizeof(*layout_data) + layout_length);
318 if (!layout_data)
319 goto out;
320
321 memcpy(&layout_data->keyboard_layout, layout, layout_length);
322 list_add_tail(&layout_data->link,
323 &package_data->keyboard_layout_list);
324 list_add_tail(&layout_data->link_sys,
325 &efi_keyboard_layout_list);
326
327 layout += layout_length;
328 }
329
330 list_add_tail(&package_data->link, &hii->keyboard_packages);
331
332 return EFI_SUCCESS;
333
334out:
335 free_keyboard_layouts(package_data);
336 free(package_data);
337
338 return EFI_OUT_OF_RESOURCES;
AKASHI Takahiro0fa82b92019-01-21 12:12:58 +0900339}
340
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900341static struct efi_hii_packagelist *new_packagelist(void)
342{
343 struct efi_hii_packagelist *hii;
344
345 hii = malloc(sizeof(*hii));
346 hii->max_string_id = 0;
347 INIT_LIST_HEAD(&hii->string_tables);
AKASHI Takahiro0fa82b92019-01-21 12:12:58 +0900348 INIT_LIST_HEAD(&hii->guid_list);
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900349 INIT_LIST_HEAD(&hii->keyboard_packages);
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900350
351 return hii;
352}
353
354static void free_packagelist(struct efi_hii_packagelist *hii)
355{
356 remove_strings_package(hii);
AKASHI Takahiro0fa82b92019-01-21 12:12:58 +0900357 remove_guid_package(hii);
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900358 remove_keyboard_package(hii);
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900359
360 list_del(&hii->link);
361 free(hii);
362}
363
364static efi_status_t
365add_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 debug("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 debug("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:
AKASHI Takahiro0fa82b92019-01-21 12:12:58 +0900386 ret = add_guid_package(hii,
387 (struct efi_hii_guid_package *)package);
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900388 break;
389 case EFI_HII_PACKAGE_FORMS:
390 printf("\tForm package not supported\n");
391 ret = EFI_INVALID_PARAMETER;
392 break;
393 case EFI_HII_PACKAGE_STRINGS:
394 ret = add_strings_package(hii,
395 (struct efi_hii_strings_package *)package);
396 break;
397 case EFI_HII_PACKAGE_FONTS:
398 printf("\tFont package not supported\n");
399 ret = EFI_INVALID_PARAMETER;
400 break;
401 case EFI_HII_PACKAGE_IMAGES:
402 printf("\tImage package not supported\n");
403 ret = EFI_INVALID_PARAMETER;
404 break;
405 case EFI_HII_PACKAGE_SIMPLE_FONTS:
406 printf("\tSimple font package not supported\n");
407 ret = EFI_INVALID_PARAMETER;
408 break;
409 case EFI_HII_PACKAGE_DEVICE_PATH:
410 printf("\tDevice path package not supported\n");
411 ret = EFI_INVALID_PARAMETER;
412 break;
413 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900414 ret = add_keyboard_package(hii,
415 (struct efi_hii_keyboard_package *)package);
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900416 break;
417 case EFI_HII_PACKAGE_ANIMATIONS:
418 printf("\tAnimation package not supported\n");
419 ret = EFI_INVALID_PARAMETER;
420 break;
421 case EFI_HII_PACKAGE_END:
422 goto out;
423 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
424 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
425 default:
426 break;
427 }
428
429 if (ret != EFI_SUCCESS)
430 return ret;
431
432 package = (void *)package + efi_hii_package_len(package);
433 }
434out:
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
443static efi_status_t EFIAPI
444new_package_list(const struct efi_hii_database_protocol *this,
445 const struct efi_hii_package_list_header *package_list,
446 const efi_handle_t driver_handle,
447 efi_hii_handle_t *handle)
448{
449 struct efi_hii_packagelist *hii;
450 efi_status_t ret;
451
452 EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
453
454 if (!package_list || !handle)
455 return EFI_EXIT(EFI_INVALID_PARAMETER);
456
457 hii = new_packagelist();
458 if (!hii)
459 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
460
461 ret = add_packages(hii, package_list);
462 if (ret != EFI_SUCCESS) {
463 free_packagelist(hii);
464 return EFI_EXIT(ret);
465 }
466
467 hii->driver_handle = driver_handle;
468 list_add_tail(&hii->link, &efi_package_lists);
469 *handle = hii;
470
471 return EFI_EXIT(EFI_SUCCESS);
472}
473
474static efi_status_t EFIAPI
475remove_package_list(const struct efi_hii_database_protocol *this,
476 efi_hii_handle_t handle)
477{
478 struct efi_hii_packagelist *hii = handle;
479
480 EFI_ENTRY("%p, %p", this, handle);
481
482 if (!handle || !efi_hii_packagelist_exists(handle))
483 return EFI_EXIT(EFI_NOT_FOUND);
484
485 free_packagelist(hii);
486
487 return EFI_EXIT(EFI_SUCCESS);
488}
489
490static efi_status_t EFIAPI
491update_package_list(const struct efi_hii_database_protocol *this,
492 efi_hii_handle_t handle,
493 const struct efi_hii_package_list_header *package_list)
494{
495 struct efi_hii_packagelist *hii = handle;
496 struct efi_hii_package_header *package;
497 void *end;
498 efi_status_t ret = EFI_SUCCESS;
499
500 EFI_ENTRY("%p, %p, %p", this, handle, package_list);
501
502 if (!handle || !efi_hii_packagelist_exists(handle))
503 return EFI_EXIT(EFI_NOT_FOUND);
504
505 if (!package_list)
506 return EFI_EXIT(EFI_INVALID_PARAMETER);
507
508 debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
509 get_unaligned_le32(&package_list->package_length));
510
511 package = ((void *)package_list) + sizeof(*package_list);
512 end = ((void *)package_list)
513 + get_unaligned_le32(&package_list->package_length);
514
515 while ((void *)package < end) {
516 debug("package=%p, package type=%x, length=%u\n", package,
517 efi_hii_package_type(package),
518 efi_hii_package_len(package));
519
520 switch (efi_hii_package_type(package)) {
521 case EFI_HII_PACKAGE_TYPE_GUID:
AKASHI Takahiro0fa82b92019-01-21 12:12:58 +0900522 remove_guid_package(hii);
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900523 break;
524 case EFI_HII_PACKAGE_FORMS:
525 printf("\tForm package not supported\n");
526 ret = EFI_INVALID_PARAMETER;
527 break;
528 case EFI_HII_PACKAGE_STRINGS:
529 remove_strings_package(hii);
530 break;
531 case EFI_HII_PACKAGE_FONTS:
532 printf("\tFont package not supported\n");
533 ret = EFI_INVALID_PARAMETER;
534 break;
535 case EFI_HII_PACKAGE_IMAGES:
536 printf("\tImage package not supported\n");
537 ret = EFI_INVALID_PARAMETER;
538 break;
539 case EFI_HII_PACKAGE_SIMPLE_FONTS:
540 printf("\tSimple font package not supported\n");
541 ret = EFI_INVALID_PARAMETER;
542 break;
543 case EFI_HII_PACKAGE_DEVICE_PATH:
544 printf("\tDevice path package not supported\n");
545 ret = EFI_INVALID_PARAMETER;
546 break;
547 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900548 remove_keyboard_package(hii);
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900549 break;
550 case EFI_HII_PACKAGE_ANIMATIONS:
551 printf("\tAnimation package not supported\n");
552 ret = EFI_INVALID_PARAMETER;
553 break;
554 case EFI_HII_PACKAGE_END:
555 goto out;
556 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
557 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
558 default:
559 break;
560 }
561
562 /* TODO: already removed some packages */
563 if (ret != EFI_SUCCESS)
564 return EFI_EXIT(ret);
565
566 package = ((void *)package)
567 + efi_hii_package_len(package);
568 }
569out:
570 ret = add_packages(hii, package_list);
571
572 return EFI_EXIT(ret);
573}
574
575static efi_status_t EFIAPI
576list_package_lists(const struct efi_hii_database_protocol *this,
577 u8 package_type,
578 const efi_guid_t *package_guid,
579 efi_uintn_t *handle_buffer_length,
580 efi_hii_handle_t *handle)
581{
582 struct efi_hii_packagelist *hii =
583 (struct efi_hii_packagelist *)handle;
584 int package_cnt, package_max;
585 efi_status_t ret = EFI_SUCCESS;
586
587 EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
588 handle_buffer_length, handle);
589
590 if (!handle_buffer_length ||
591 (*handle_buffer_length && !handle))
592 return EFI_EXIT(EFI_INVALID_PARAMETER);
593
594 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
595 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
596 return EFI_EXIT(EFI_INVALID_PARAMETER);
597
598 debug("package type=%x, guid=%pUl, length=%lu\n", (int)package_type,
599 package_guid, *handle_buffer_length);
600
601 package_cnt = 0;
602 package_max = *handle_buffer_length / sizeof(*handle);
603 list_for_each_entry(hii, &efi_package_lists, link) {
604 switch (package_type) {
605 case EFI_HII_PACKAGE_TYPE_ALL:
606 break;
607 case EFI_HII_PACKAGE_TYPE_GUID:
AKASHI Takahiro0fa82b92019-01-21 12:12:58 +0900608 if (!list_empty(&hii->guid_list))
609 break;
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900610 continue;
611 case EFI_HII_PACKAGE_FORMS:
612 printf("\tForm package not supported\n");
613 ret = EFI_INVALID_PARAMETER;
614 continue;
615 case EFI_HII_PACKAGE_STRINGS:
616 if (!list_empty(&hii->string_tables))
617 break;
618 continue;
619 case EFI_HII_PACKAGE_FONTS:
620 printf("\tFont package not supported\n");
621 ret = EFI_INVALID_PARAMETER;
622 continue;
623 case EFI_HII_PACKAGE_IMAGES:
624 printf("\tImage package not supported\n");
625 ret = EFI_INVALID_PARAMETER;
626 continue;
627 case EFI_HII_PACKAGE_SIMPLE_FONTS:
628 printf("\tSimple font package not supported\n");
629 ret = EFI_INVALID_PARAMETER;
630 continue;
631 case EFI_HII_PACKAGE_DEVICE_PATH:
632 printf("\tDevice path package not supported\n");
633 ret = EFI_INVALID_PARAMETER;
634 continue;
635 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900636 if (!list_empty(&hii->keyboard_packages))
637 break;
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900638 continue;
639 case EFI_HII_PACKAGE_ANIMATIONS:
640 printf("\tAnimation package not supported\n");
641 ret = EFI_INVALID_PARAMETER;
642 continue;
643 case EFI_HII_PACKAGE_END:
644 case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
645 case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
646 default:
647 continue;
648 }
649
650 package_cnt++;
651 if (package_cnt <= package_max)
652 *handle++ = hii;
653 else
654 ret = EFI_BUFFER_TOO_SMALL;
655 }
656 *handle_buffer_length = package_cnt * sizeof(*handle);
657
658 return EFI_EXIT(ret);
659}
660
661static efi_status_t EFIAPI
662export_package_lists(const struct efi_hii_database_protocol *this,
663 efi_hii_handle_t handle,
664 efi_uintn_t *buffer_size,
665 struct efi_hii_package_list_header *buffer)
666{
667 EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
668
669 if (!buffer_size || !buffer)
670 return EFI_EXIT(EFI_INVALID_PARAMETER);
671
672 return EFI_EXIT(EFI_NOT_FOUND);
673}
674
675static efi_status_t EFIAPI
676register_package_notify(const struct efi_hii_database_protocol *this,
677 u8 package_type,
678 const efi_guid_t *package_guid,
679 const void *package_notify_fn,
680 efi_uintn_t notify_type,
681 efi_handle_t *notify_handle)
682{
683 EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
684 package_guid, package_notify_fn, notify_type,
685 notify_handle);
686
687 if (!notify_handle)
688 return EFI_EXIT(EFI_INVALID_PARAMETER);
689
690 if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
691 (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
692 return EFI_EXIT(EFI_INVALID_PARAMETER);
693
694 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
695}
696
697static efi_status_t EFIAPI
698unregister_package_notify(const struct efi_hii_database_protocol *this,
699 efi_handle_t notification_handle)
700{
701 EFI_ENTRY("%p, %p", this, notification_handle);
702
703 return EFI_EXIT(EFI_NOT_FOUND);
704}
705
706static efi_status_t EFIAPI
707find_keyboard_layouts(const struct efi_hii_database_protocol *this,
708 u16 *key_guid_buffer_length,
709 efi_guid_t *key_guid_buffer)
710{
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900711 struct efi_keyboard_layout_data *layout_data;
712 int package_cnt, package_max;
713 efi_status_t ret = EFI_SUCCESS;
714
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900715 EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
716
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900717 if (!key_guid_buffer_length ||
718 (*key_guid_buffer_length && !key_guid_buffer))
719 return EFI_EXIT(EFI_INVALID_PARAMETER);
720
721 package_cnt = 0;
722 package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer);
723 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
724 package_cnt++;
725 if (package_cnt <= package_max)
726 memcpy(key_guid_buffer++,
727 &layout_data->keyboard_layout.guid,
728 sizeof(*key_guid_buffer));
729 else
730 ret = EFI_BUFFER_TOO_SMALL;
731 }
732 *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer);
733
734 return EFI_EXIT(ret);
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900735}
736
737static efi_status_t EFIAPI
738get_keyboard_layout(const struct efi_hii_database_protocol *this,
739 efi_guid_t *key_guid,
740 u16 *keyboard_layout_length,
741 struct efi_hii_keyboard_layout *keyboard_layout)
742{
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900743 struct efi_keyboard_layout_data *layout_data;
744 u16 layout_length;
745
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900746 EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
747 keyboard_layout);
748
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900749 if (!keyboard_layout_length ||
750 (*keyboard_layout_length && !keyboard_layout))
751 return EFI_EXIT(EFI_INVALID_PARAMETER);
752
753 /* TODO: no notion of current keyboard layout */
754 if (!key_guid)
755 return EFI_EXIT(EFI_INVALID_PARAMETER);
756
757 list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
758 if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid))
759 goto found;
760 }
761
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900762 return EFI_EXIT(EFI_NOT_FOUND);
AKASHI Takahiro976e9312019-01-21 12:12:59 +0900763
764found:
765 layout_length =
766 get_unaligned_le16(&layout_data->keyboard_layout.layout_length);
767 if (*keyboard_layout_length < layout_length) {
768 *keyboard_layout_length = layout_length;
769 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
770 }
771
772 memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length);
773
774 return EFI_EXIT(EFI_SUCCESS);
Leif Lindholm5aab1b82019-01-21 12:12:57 +0900775}
776
777static efi_status_t EFIAPI
778set_keyboard_layout(const struct efi_hii_database_protocol *this,
779 efi_guid_t *key_guid)
780{
781 EFI_ENTRY("%p, %pUl", this, key_guid);
782
783 return EFI_EXIT(EFI_NOT_FOUND);
784}
785
786static efi_status_t EFIAPI
787get_package_list_handle(const struct efi_hii_database_protocol *this,
788 efi_hii_handle_t package_list_handle,
789 efi_handle_t *driver_handle)
790{
791 struct efi_hii_packagelist *hii;
792
793 EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
794
795 if (!driver_handle)
796 return EFI_EXIT(EFI_INVALID_PARAMETER);
797
798 list_for_each_entry(hii, &efi_package_lists, link) {
799 if (hii == package_list_handle) {
800 *driver_handle = hii->driver_handle;
801 return EFI_EXIT(EFI_SUCCESS);
802 }
803 }
804
805 return EFI_EXIT(EFI_NOT_FOUND);
806}
807
808const struct efi_hii_database_protocol efi_hii_database = {
809 .new_package_list = new_package_list,
810 .remove_package_list = remove_package_list,
811 .update_package_list = update_package_list,
812 .list_package_lists = list_package_lists,
813 .export_package_lists = export_package_lists,
814 .register_package_notify = register_package_notify,
815 .unregister_package_notify = unregister_package_notify,
816 .find_keyboard_layouts = find_keyboard_layouts,
817 .get_keyboard_layout = get_keyboard_layout,
818 .set_keyboard_layout = set_keyboard_layout,
819 .get_package_list_handle = get_package_list_handle
820};
821
822/*
823 * EFI_HII_STRING_PROTOCOL
824 */
825
826static bool language_match(char *language, char *languages)
827{
828 size_t n;
829
830 n = strlen(language);
831 /* match primary language? */
832 if (!strncasecmp(language, languages, n) &&
833 (languages[n] == ';' || languages[n] == '\0'))
834 return true;
835
836 return false;
837}
838
839static efi_status_t EFIAPI
840new_string(const struct efi_hii_string_protocol *this,
841 efi_hii_handle_t package_list,
842 efi_string_id_t *string_id,
843 const u8 *language,
844 const u16 *language_name,
845 const efi_string_t string,
846 const struct efi_font_info *string_font_info)
847{
848 struct efi_hii_packagelist *hii = package_list;
849 struct efi_string_table *stbl;
850
851 EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
852 string_id, language, language_name, string,
853 string_font_info);
854
855 if (!package_list || !efi_hii_packagelist_exists(package_list))
856 return EFI_EXIT(EFI_NOT_FOUND);
857
858 if (!string_id || !language || !string)
859 return EFI_EXIT(EFI_INVALID_PARAMETER);
860
861 list_for_each_entry(stbl, &hii->string_tables, link) {
862 if (language_match((char *)language, stbl->language)) {
863 efi_string_id_t new_id;
864 void *buf;
865 efi_string_t str;
866
867 new_id = ++hii->max_string_id;
868 if (stbl->nstrings < new_id) {
869 buf = realloc(stbl->strings,
870 sizeof(stbl->strings[0])
871 * new_id);
872 if (!buf)
873 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
874
875 memset(&stbl->strings[stbl->nstrings], 0,
876 (new_id - stbl->nstrings)
877 * sizeof(stbl->strings[0]));
878 stbl->strings = buf;
879 stbl->nstrings = new_id;
880 }
881
882 str = u16_strdup(string);
883 if (!str)
884 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
885
886 stbl->strings[new_id - 1].string = str;
887 *string_id = new_id;
888
889 return EFI_EXIT(EFI_SUCCESS);
890 }
891 }
892
893 return EFI_EXIT(EFI_NOT_FOUND);
894}
895
896static efi_status_t EFIAPI
897get_string(const struct efi_hii_string_protocol *this,
898 const u8 *language,
899 efi_hii_handle_t package_list,
900 efi_string_id_t string_id,
901 efi_string_t string,
902 efi_uintn_t *string_size,
903 struct efi_font_info **string_font_info)
904{
905 struct efi_hii_packagelist *hii = package_list;
906 struct efi_string_table *stbl;
907
908 EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
909 package_list, string_id, string, string_size,
910 string_font_info);
911
912 if (!package_list || !efi_hii_packagelist_exists(package_list))
913 return EFI_EXIT(EFI_NOT_FOUND);
914
915 list_for_each_entry(stbl, &hii->string_tables, link) {
916 if (language_match((char *)language, stbl->language)) {
917 efi_string_t str;
918 size_t len;
919
920 if (stbl->nstrings < string_id)
921 return EFI_EXIT(EFI_NOT_FOUND);
922
923 str = stbl->strings[string_id - 1].string;
924 if (str) {
925 len = (u16_strlen(str) + 1) * sizeof(u16);
926 if (*string_size < len) {
927 *string_size = len;
928
929 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
930 }
931 memcpy(string, str, len);
932 *string_size = len;
933 } else {
934 return EFI_EXIT(EFI_NOT_FOUND);
935 }
936
937 return EFI_EXIT(EFI_SUCCESS);
938 }
939 }
940
941 return EFI_EXIT(EFI_NOT_FOUND);
942}
943
944static efi_status_t EFIAPI
945set_string(const struct efi_hii_string_protocol *this,
946 efi_hii_handle_t package_list,
947 efi_string_id_t string_id,
948 const u8 *language,
949 const efi_string_t string,
950 const struct efi_font_info *string_font_info)
951{
952 struct efi_hii_packagelist *hii = package_list;
953 struct efi_string_table *stbl;
954
955 EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
956 string_id, language, string, string_font_info);
957
958 if (!package_list || !efi_hii_packagelist_exists(package_list))
959 return EFI_EXIT(EFI_NOT_FOUND);
960
961 if (string_id > hii->max_string_id)
962 return EFI_EXIT(EFI_NOT_FOUND);
963
964 if (!string || !language)
965 return EFI_EXIT(EFI_INVALID_PARAMETER);
966
967 list_for_each_entry(stbl, &hii->string_tables, link) {
968 if (language_match((char *)language, stbl->language)) {
969 efi_string_t str;
970
971 if (hii->max_string_id < string_id)
972 return EFI_EXIT(EFI_NOT_FOUND);
973
974 if (stbl->nstrings < string_id) {
975 void *buf;
976
977 buf = realloc(stbl->strings,
978 string_id
979 * sizeof(stbl->strings[0]));
980 if (!buf)
981 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
982
983 memset(&stbl->strings[string_id - 1], 0,
984 (string_id - stbl->nstrings)
985 * sizeof(stbl->strings[0]));
986 stbl->strings = buf;
987 }
988
989 str = u16_strdup(string);
990 if (!str)
991 return EFI_EXIT(EFI_OUT_OF_RESOURCES);
992
993 free(stbl->strings[string_id - 1].string);
994 stbl->strings[string_id - 1].string = str;
995
996 return EFI_EXIT(EFI_SUCCESS);
997 }
998 }
999
1000 return EFI_EXIT(EFI_NOT_FOUND);
1001}
1002
1003static efi_status_t EFIAPI
1004get_languages(const struct efi_hii_string_protocol *this,
1005 efi_hii_handle_t package_list,
1006 u8 *languages,
1007 efi_uintn_t *languages_size)
1008{
1009 struct efi_hii_packagelist *hii = package_list;
1010 struct efi_string_table *stbl;
1011 size_t len = 0;
1012 char *p;
1013
1014 EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
1015 languages_size);
1016
1017 if (!package_list || !efi_hii_packagelist_exists(package_list))
1018 return EFI_EXIT(EFI_NOT_FOUND);
1019
1020 if (!languages_size ||
1021 (*languages_size && !languages))
1022 return EFI_EXIT(EFI_INVALID_PARAMETER);
1023
1024 /* figure out required size: */
1025 list_for_each_entry(stbl, &hii->string_tables, link) {
1026 len += strlen((char *)stbl->language) + 1;
1027 }
1028
1029 if (*languages_size < len) {
1030 *languages_size = len;
1031
1032 return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
1033 }
1034
1035 p = (char *)languages;
1036 list_for_each_entry(stbl, &hii->string_tables, link) {
1037 if (p != (char *)languages)
1038 *p++ = ';';
1039 strcpy(p, stbl->language);
1040 p += strlen((char *)stbl->language);
1041 }
1042 *p = '\0';
1043
1044 debug("languages: %s\n", languages);
1045
1046 return EFI_EXIT(EFI_SUCCESS);
1047}
1048
1049static efi_status_t EFIAPI
1050get_secondary_languages(const struct efi_hii_string_protocol *this,
1051 efi_hii_handle_t package_list,
1052 const u8 *primary_language,
1053 u8 *secondary_languages,
1054 efi_uintn_t *secondary_languages_size)
1055{
1056 struct efi_hii_packagelist *hii = package_list;
1057 struct efi_string_table *stbl;
1058 bool found = false;
1059
1060 EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
1061 primary_language, secondary_languages,
1062 secondary_languages_size);
1063
1064 if (!package_list || !efi_hii_packagelist_exists(package_list))
1065 return EFI_EXIT(EFI_NOT_FOUND);
1066
1067 if (!secondary_languages_size ||
1068 (*secondary_languages_size && !secondary_languages))
1069 return EFI_EXIT(EFI_INVALID_PARAMETER);
1070
1071 list_for_each_entry(stbl, &hii->string_tables, link) {
1072 if (language_match((char *)primary_language, stbl->language)) {
1073 found = true;
1074 break;
1075 }
1076 }
1077 if (!found)
1078 return EFI_EXIT(EFI_INVALID_LANGUAGE);
1079
1080 /*
1081 * TODO: What is secondary language?
1082 * *secondary_languages = '\0';
1083 * *secondary_languages_size = 0;
1084 */
1085
1086 return EFI_EXIT(EFI_NOT_FOUND);
1087}
1088
1089const struct efi_hii_string_protocol efi_hii_string = {
1090 .new_string = new_string,
1091 .get_string = get_string,
1092 .set_string = set_string,
1093 .get_languages = get_languages,
1094 .get_secondary_languages = get_secondary_languages
1095};