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