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