• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_NOT_FOUND;
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 		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=%pUl, 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, %pUl, %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, %pUl, %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, %pUl", this, key_guid);
760 
761 	return EFI_EXIT(EFI_NOT_FOUND);
762 }
763 
764 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)765 get_package_list_handle(const struct efi_hii_database_protocol *this,
766 			efi_hii_handle_t package_list_handle,
767 			efi_handle_t *driver_handle)
768 {
769 	struct efi_hii_packagelist *hii;
770 
771 	EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
772 
773 	if (!driver_handle)
774 		return EFI_EXIT(EFI_INVALID_PARAMETER);
775 
776 	list_for_each_entry(hii, &efi_package_lists, link) {
777 		if (hii == package_list_handle) {
778 			*driver_handle = hii->driver_handle;
779 			return EFI_EXIT(EFI_SUCCESS);
780 		}
781 	}
782 
783 	return EFI_EXIT(EFI_NOT_FOUND);
784 }
785 
786 const struct efi_hii_database_protocol efi_hii_database = {
787 	.new_package_list = new_package_list,
788 	.remove_package_list = remove_package_list,
789 	.update_package_list = update_package_list,
790 	.list_package_lists = list_package_lists,
791 	.export_package_lists = export_package_lists,
792 	.register_package_notify = register_package_notify,
793 	.unregister_package_notify = unregister_package_notify,
794 	.find_keyboard_layouts = find_keyboard_layouts,
795 	.get_keyboard_layout = get_keyboard_layout,
796 	.set_keyboard_layout = set_keyboard_layout,
797 	.get_package_list_handle = get_package_list_handle
798 };
799 
800 /*
801  * EFI_HII_STRING_PROTOCOL
802  */
803 
language_match(char * language,char * languages)804 static bool language_match(char *language, char *languages)
805 {
806 	size_t n;
807 
808 	n = strlen(language);
809 	/* match primary language? */
810 	if (!strncasecmp(language, languages, n) &&
811 	    (languages[n] == ';' || languages[n] == '\0'))
812 		return true;
813 
814 	return false;
815 }
816 
817 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)818 new_string(const struct efi_hii_string_protocol *this,
819 	   efi_hii_handle_t package_list,
820 	   efi_string_id_t *string_id,
821 	   const u8 *language,
822 	   const u16 *language_name,
823 	   const efi_string_t string,
824 	   const struct efi_font_info *string_font_info)
825 {
826 	struct efi_hii_packagelist *hii = package_list;
827 	struct efi_string_table *stbl;
828 
829 	EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
830 		  string_id, language, language_name, string,
831 		  string_font_info);
832 
833 	if (!package_list || !efi_hii_packagelist_exists(package_list))
834 		return EFI_EXIT(EFI_NOT_FOUND);
835 
836 	if (!string_id || !language || !string)
837 		return EFI_EXIT(EFI_INVALID_PARAMETER);
838 
839 	list_for_each_entry(stbl, &hii->string_tables, link) {
840 		if (language_match((char *)language, stbl->language)) {
841 			efi_string_id_t new_id;
842 			void *buf;
843 			efi_string_t str;
844 
845 			new_id = ++hii->max_string_id;
846 			if (stbl->nstrings < new_id) {
847 				buf = realloc(stbl->strings,
848 					      sizeof(stbl->strings[0])
849 						* new_id);
850 				if (!buf)
851 					return EFI_EXIT(EFI_OUT_OF_RESOURCES);
852 
853 				memset(&stbl->strings[stbl->nstrings], 0,
854 				       (new_id - stbl->nstrings)
855 					 * sizeof(stbl->strings[0]));
856 				stbl->strings = buf;
857 				stbl->nstrings = new_id;
858 			}
859 
860 			str = u16_strdup(string);
861 			if (!str)
862 				return EFI_EXIT(EFI_OUT_OF_RESOURCES);
863 
864 			stbl->strings[new_id - 1].string = str;
865 			*string_id = new_id;
866 
867 			return EFI_EXIT(EFI_SUCCESS);
868 		}
869 	}
870 
871 	return EFI_EXIT(EFI_NOT_FOUND);
872 }
873 
874 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)875 get_string(const struct efi_hii_string_protocol *this,
876 	   const u8 *language,
877 	   efi_hii_handle_t package_list,
878 	   efi_string_id_t string_id,
879 	   efi_string_t string,
880 	   efi_uintn_t *string_size,
881 	   struct efi_font_info **string_font_info)
882 {
883 	struct efi_hii_packagelist *hii = package_list;
884 	struct efi_string_table *stbl;
885 
886 	EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
887 		  package_list, string_id, string, string_size,
888 		  string_font_info);
889 
890 	if (!package_list || !efi_hii_packagelist_exists(package_list))
891 		return EFI_EXIT(EFI_NOT_FOUND);
892 
893 	list_for_each_entry(stbl, &hii->string_tables, link) {
894 		if (language_match((char *)language, stbl->language)) {
895 			efi_string_t str;
896 			size_t len;
897 
898 			if (stbl->nstrings < string_id)
899 				return EFI_EXIT(EFI_NOT_FOUND);
900 
901 			str = stbl->strings[string_id - 1].string;
902 			if (str) {
903 				len = (u16_strlen(str) + 1) * sizeof(u16);
904 				if (*string_size < len) {
905 					*string_size = len;
906 
907 					return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
908 				}
909 				memcpy(string, str, len);
910 				*string_size = len;
911 			} else {
912 				return EFI_EXIT(EFI_NOT_FOUND);
913 			}
914 
915 			return EFI_EXIT(EFI_SUCCESS);
916 		}
917 	}
918 
919 	return EFI_EXIT(EFI_NOT_FOUND);
920 }
921 
922 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)923 set_string(const struct efi_hii_string_protocol *this,
924 	   efi_hii_handle_t package_list,
925 	   efi_string_id_t string_id,
926 	   const u8 *language,
927 	   const efi_string_t string,
928 	   const struct efi_font_info *string_font_info)
929 {
930 	struct efi_hii_packagelist *hii = package_list;
931 	struct efi_string_table *stbl;
932 
933 	EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
934 		  string_id, language, string, string_font_info);
935 
936 	if (!package_list || !efi_hii_packagelist_exists(package_list))
937 		return EFI_EXIT(EFI_NOT_FOUND);
938 
939 	if (string_id > hii->max_string_id)
940 		return EFI_EXIT(EFI_NOT_FOUND);
941 
942 	if (!string || !language)
943 		return EFI_EXIT(EFI_INVALID_PARAMETER);
944 
945 	list_for_each_entry(stbl, &hii->string_tables, link) {
946 		if (language_match((char *)language, stbl->language)) {
947 			efi_string_t str;
948 
949 			if (hii->max_string_id < string_id)
950 				return EFI_EXIT(EFI_NOT_FOUND);
951 
952 			if (stbl->nstrings < string_id) {
953 				void *buf;
954 
955 				buf = realloc(stbl->strings,
956 					      string_id
957 						* sizeof(stbl->strings[0]));
958 				if (!buf)
959 					return EFI_EXIT(EFI_OUT_OF_RESOURCES);
960 
961 				memset(&stbl->strings[string_id - 1], 0,
962 				       (string_id - stbl->nstrings)
963 					 * sizeof(stbl->strings[0]));
964 				stbl->strings = buf;
965 			}
966 
967 			str = u16_strdup(string);
968 			if (!str)
969 				return EFI_EXIT(EFI_OUT_OF_RESOURCES);
970 
971 			free(stbl->strings[string_id - 1].string);
972 			stbl->strings[string_id - 1].string = str;
973 
974 			return EFI_EXIT(EFI_SUCCESS);
975 		}
976 	}
977 
978 	return EFI_EXIT(EFI_NOT_FOUND);
979 }
980 
981 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)982 get_languages(const struct efi_hii_string_protocol *this,
983 	      efi_hii_handle_t package_list,
984 	      u8 *languages,
985 	      efi_uintn_t *languages_size)
986 {
987 	struct efi_hii_packagelist *hii = package_list;
988 	struct efi_string_table *stbl;
989 	size_t len = 0;
990 	char *p;
991 
992 	EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
993 		  languages_size);
994 
995 	if (!package_list || !efi_hii_packagelist_exists(package_list))
996 		return EFI_EXIT(EFI_NOT_FOUND);
997 
998 	if (!languages_size ||
999 	    (*languages_size && !languages))
1000 		return EFI_EXIT(EFI_INVALID_PARAMETER);
1001 
1002 	/* figure out required size: */
1003 	list_for_each_entry(stbl, &hii->string_tables, link) {
1004 		len += strlen((char *)stbl->language) + 1;
1005 	}
1006 
1007 	if (*languages_size < len) {
1008 		*languages_size = len;
1009 
1010 		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
1011 	}
1012 
1013 	p = (char *)languages;
1014 	list_for_each_entry(stbl, &hii->string_tables, link) {
1015 		if (p != (char *)languages)
1016 			*p++ = ';';
1017 		strcpy(p, stbl->language);
1018 		p += strlen((char *)stbl->language);
1019 	}
1020 	*p = '\0';
1021 
1022 	EFI_PRINT("languages: %s\n", languages);
1023 
1024 	return EFI_EXIT(EFI_SUCCESS);
1025 }
1026 
1027 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)1028 get_secondary_languages(const struct efi_hii_string_protocol *this,
1029 			efi_hii_handle_t package_list,
1030 			const u8 *primary_language,
1031 			u8 *secondary_languages,
1032 			efi_uintn_t *secondary_languages_size)
1033 {
1034 	struct efi_hii_packagelist *hii = package_list;
1035 	struct efi_string_table *stbl;
1036 	bool found = false;
1037 
1038 	EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
1039 		  primary_language, secondary_languages,
1040 		  secondary_languages_size);
1041 
1042 	if (!package_list || !efi_hii_packagelist_exists(package_list))
1043 		return EFI_EXIT(EFI_NOT_FOUND);
1044 
1045 	if (!secondary_languages_size ||
1046 	    (*secondary_languages_size && !secondary_languages))
1047 		return EFI_EXIT(EFI_INVALID_PARAMETER);
1048 
1049 	list_for_each_entry(stbl, &hii->string_tables, link) {
1050 		if (language_match((char *)primary_language, stbl->language)) {
1051 			found = true;
1052 			break;
1053 		}
1054 	}
1055 	if (!found)
1056 		return EFI_EXIT(EFI_INVALID_LANGUAGE);
1057 
1058 	/*
1059 	 * TODO: What is secondary language?
1060 	 * *secondary_languages = '\0';
1061 	 * *secondary_languages_size = 0;
1062 	 */
1063 
1064 	return EFI_EXIT(EFI_NOT_FOUND);
1065 }
1066 
1067 const struct efi_hii_string_protocol efi_hii_string = {
1068 	.new_string = new_string,
1069 	.get_string = get_string,
1070 	.set_string = set_string,
1071 	.get_languages = get_languages,
1072 	.get_secondary_languages = get_secondary_languages
1073 };
1074