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