u-boot-brain/lib/efi_loader/efi_hii.c
Heinrich Schuchardt 1a9fce5039 efi_loader: HII protocols: debug messages
When package types are not supported by our implementation of the HII
database protocol supported error messages are displayed.

Essentially the output is only needed for debugging. By using EFI_PRINT()
the messages are only written for in debug mode and with correct
indentation.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
2019-03-02 23:34:26 +01:00

1096 lines
28 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* EFI Human Interface Infrastructure ... database and packages
*
* Copyright (c) 2017 Leif Lindholm
* Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
*/
#include <common.h>
#include <efi_loader.h>
#include <malloc.h>
#include <asm/unaligned.h>
const efi_guid_t efi_guid_hii_database_protocol
= EFI_HII_DATABASE_PROTOCOL_GUID;
const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID;
static LIST_HEAD(efi_package_lists);
static LIST_HEAD(efi_keyboard_layout_list);
struct efi_hii_packagelist {
struct list_head link;
// TODO should there be an associated efi_object?
efi_handle_t driver_handle;
u32 max_string_id;
struct list_head string_tables; /* list of efi_string_table */
struct list_head guid_list;
struct list_head keyboard_packages;
/* we could also track fonts, images, etc */
};
static int efi_hii_packagelist_exists(efi_hii_handle_t package_list)
{
struct efi_hii_packagelist *hii;
int found = 0;
list_for_each_entry(hii, &efi_package_lists, link) {
if (hii == package_list) {
found = 1;
break;
}
}
return found;
}
static u32 efi_hii_package_type(struct efi_hii_package_header *header)
{
u32 fields;
fields = get_unaligned_le32(&header->fields);
return (fields >> __EFI_HII_PACKAGE_TYPE_SHIFT)
& __EFI_HII_PACKAGE_TYPE_MASK;
}
static u32 efi_hii_package_len(struct efi_hii_package_header *header)
{
u32 fields;
fields = get_unaligned_le32(&header->fields);
return (fields >> __EFI_HII_PACKAGE_LEN_SHIFT)
& __EFI_HII_PACKAGE_LEN_MASK;
}
struct efi_string_info {
efi_string_t string;
/* we could also track font info, etc */
};
struct efi_string_table {
struct list_head link;
efi_string_id_t language_name;
char *language;
u32 nstrings;
/*
* NOTE:
* string id starts at 1 so value is stbl->strings[id-1],
* and strings[] is a array of stbl->nstrings elements
*/
struct efi_string_info *strings;
};
struct efi_guid_data {
struct list_head link;
struct efi_hii_guid_package package;
};
struct efi_keyboard_layout_data {
struct list_head link; /* in package */
struct list_head link_sys; /* in global list */
struct efi_hii_keyboard_layout keyboard_layout;
};
struct efi_keyboard_package_data {
struct list_head link; /* in package_list */
struct list_head keyboard_layout_list;
};
static void free_strings_table(struct efi_string_table *stbl)
{
int i;
for (i = 0; i < stbl->nstrings; i++)
free(stbl->strings[i].string);
free(stbl->strings);
free(stbl->language);
free(stbl);
}
static void remove_strings_package(struct efi_hii_packagelist *hii)
{
while (!list_empty(&hii->string_tables)) {
struct efi_string_table *stbl;
stbl = list_first_entry(&hii->string_tables,
struct efi_string_table, link);
list_del(&stbl->link);
free_strings_table(stbl);
}
}
static efi_status_t
add_strings_package(struct efi_hii_packagelist *hii,
struct efi_hii_strings_package *strings_package)
{
struct efi_hii_string_block *block;
void *end;
u32 nstrings = 0, idx = 0;
struct efi_string_table *stbl = NULL;
efi_status_t ret;
EFI_PRINT("header_size: %08x\n",
get_unaligned_le32(&strings_package->header_size));
EFI_PRINT("string_info_offset: %08x\n",
get_unaligned_le32(&strings_package->string_info_offset));
EFI_PRINT("language_name: %u\n",
get_unaligned_le16(&strings_package->language_name));
EFI_PRINT("language: %s\n", strings_package->language);
/* count # of string entries: */
end = ((void *)strings_package)
+ efi_hii_package_len(&strings_package->header);
block = ((void *)strings_package)
+ get_unaligned_le32(&strings_package->string_info_offset);
while ((void *)block < end) {
switch (block->block_type) {
case EFI_HII_SIBT_STRING_UCS2: {
struct efi_hii_sibt_string_ucs2_block *ucs2;
ucs2 = (void *)block;
nstrings++;
block = efi_hii_sibt_string_ucs2_block_next(ucs2);
break;
}
case EFI_HII_SIBT_END:
block = end;
break;
default:
EFI_PRINT("unknown HII string block type: %02x\n",
block->block_type);
return EFI_INVALID_PARAMETER;
}
}
stbl = calloc(sizeof(*stbl), 1);
if (!stbl) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
}
stbl->strings = calloc(sizeof(stbl->strings[0]), nstrings);
if (!stbl->strings) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
}
stbl->language_name =
get_unaligned_le16(&strings_package->language_name);
stbl->language = strdup((char *)strings_package->language);
if (!stbl->language) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
}
stbl->nstrings = nstrings;
/* and now parse string entries and populate efi_string_table */
block = ((void *)strings_package)
+ get_unaligned_le32(&strings_package->string_info_offset);
while ((void *)block < end) {
switch (block->block_type) {
case EFI_HII_SIBT_STRING_UCS2: {
struct efi_hii_sibt_string_ucs2_block *ucs2;
ucs2 = (void *)block;
EFI_PRINT("%4u: \"%ls\"\n", idx + 1, ucs2->string_text);
stbl->strings[idx].string =
u16_strdup(ucs2->string_text);
if (!stbl->strings[idx].string) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
}
idx++;
/* FIXME: accessing u16 * here */
block = efi_hii_sibt_string_ucs2_block_next(ucs2);
break;
}
case EFI_HII_SIBT_END:
goto out;
default:
EFI_PRINT("unknown HII string block type: %02x\n",
block->block_type);
ret = EFI_INVALID_PARAMETER;
goto error;
}
}
out:
list_add(&stbl->link, &hii->string_tables);
if (hii->max_string_id < nstrings)
hii->max_string_id = nstrings;
return EFI_SUCCESS;
error:
if (stbl) {
free(stbl->language);
if (idx > 0)
while (--idx >= 0)
free(stbl->strings[idx].string);
free(stbl->strings);
}
free(stbl);
return ret;
}
static void remove_guid_package(struct efi_hii_packagelist *hii)
{
struct efi_guid_data *data;
while (!list_empty(&hii->guid_list)) {
data = list_first_entry(&hii->guid_list,
struct efi_guid_data, link);
list_del(&data->link);
free(data);
}
}
static efi_status_t
add_guid_package(struct efi_hii_packagelist *hii,
struct efi_hii_guid_package *package)
{
struct efi_guid_data *data;
data = calloc(sizeof(*data), 1);
if (!data)
return EFI_OUT_OF_RESOURCES;
/* TODO: we don't know any about data field */
memcpy(&data->package, package, sizeof(*package));
list_add_tail(&data->link, &hii->guid_list);
return EFI_SUCCESS;
}
static void free_keyboard_layouts(struct efi_keyboard_package_data *package)
{
struct efi_keyboard_layout_data *layout_data;
while (!list_empty(&package->keyboard_layout_list)) {
layout_data = list_first_entry(&package->keyboard_layout_list,
struct efi_keyboard_layout_data,
link);
list_del(&layout_data->link);
list_del(&layout_data->link_sys);
free(layout_data);
}
}
static void remove_keyboard_package(struct efi_hii_packagelist *hii)
{
struct efi_keyboard_package_data *package;
while (!list_empty(&hii->keyboard_packages)) {
package = list_first_entry(&hii->keyboard_packages,
struct efi_keyboard_package_data,
link);
free_keyboard_layouts(package);
list_del(&package->link);
free(package);
}
}
static efi_status_t
add_keyboard_package(struct efi_hii_packagelist *hii,
struct efi_hii_keyboard_package *keyboard_package)
{
struct efi_keyboard_package_data *package_data;
struct efi_hii_keyboard_layout *layout;
struct efi_keyboard_layout_data *layout_data;
u16 layout_count, layout_length;
int i;
package_data = malloc(sizeof(*package_data));
if (!package_data)
return EFI_OUT_OF_RESOURCES;
INIT_LIST_HEAD(&package_data->link);
INIT_LIST_HEAD(&package_data->keyboard_layout_list);
layout = &keyboard_package->layout[0];
layout_count = get_unaligned_le16(&keyboard_package->layout_count);
for (i = 0; i < layout_count; i++) {
layout_length = get_unaligned_le16(&layout->layout_length);
layout_data = malloc(sizeof(*layout_data) + layout_length);
if (!layout_data)
goto out;
memcpy(&layout_data->keyboard_layout, layout, layout_length);
list_add_tail(&layout_data->link,
&package_data->keyboard_layout_list);
list_add_tail(&layout_data->link_sys,
&efi_keyboard_layout_list);
layout += layout_length;
}
list_add_tail(&package_data->link, &hii->keyboard_packages);
return EFI_SUCCESS;
out:
free_keyboard_layouts(package_data);
free(package_data);
return EFI_OUT_OF_RESOURCES;
}
static struct efi_hii_packagelist *new_packagelist(void)
{
struct efi_hii_packagelist *hii;
hii = malloc(sizeof(*hii));
list_add_tail(&hii->link, &efi_package_lists);
hii->max_string_id = 0;
INIT_LIST_HEAD(&hii->string_tables);
INIT_LIST_HEAD(&hii->guid_list);
INIT_LIST_HEAD(&hii->keyboard_packages);
return hii;
}
static void free_packagelist(struct efi_hii_packagelist *hii)
{
remove_strings_package(hii);
remove_guid_package(hii);
remove_keyboard_package(hii);
list_del(&hii->link);
free(hii);
}
static efi_status_t
add_packages(struct efi_hii_packagelist *hii,
const struct efi_hii_package_list_header *package_list)
{
struct efi_hii_package_header *package;
void *end;
efi_status_t ret = EFI_SUCCESS;
end = ((void *)package_list)
+ get_unaligned_le32(&package_list->package_length);
EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid,
get_unaligned_le32(&package_list->package_length));
package = ((void *)package_list) + sizeof(*package_list);
while ((void *)package < end) {
EFI_PRINT("package=%p, package type=%x, length=%u\n", package,
efi_hii_package_type(package),
efi_hii_package_len(package));
switch (efi_hii_package_type(package)) {
case EFI_HII_PACKAGE_TYPE_GUID:
ret = add_guid_package(hii,
(struct efi_hii_guid_package *)package);
break;
case EFI_HII_PACKAGE_FORMS:
EFI_PRINT("Form package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_STRINGS:
ret = add_strings_package(hii,
(struct efi_hii_strings_package *)package);
break;
case EFI_HII_PACKAGE_FONTS:
EFI_PRINT("Font package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_IMAGES:
EFI_PRINT("Image package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
EFI_PRINT("Simple font package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_DEVICE_PATH:
EFI_PRINT("Device path package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
ret = add_keyboard_package(hii,
(struct efi_hii_keyboard_package *)package);
break;
case EFI_HII_PACKAGE_ANIMATIONS:
EFI_PRINT("Animation package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_END:
goto out;
case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
default:
break;
}
if (ret != EFI_SUCCESS)
return ret;
package = (void *)package + efi_hii_package_len(package);
}
out:
// TODO in theory there is some notifications that should be sent..
return EFI_SUCCESS;
}
/*
* EFI_HII_DATABASE_PROTOCOL
*/
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)
{
struct efi_hii_packagelist *hii;
efi_status_t ret;
EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
if (!package_list || !handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
hii = new_packagelist();
if (!hii)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
ret = add_packages(hii, package_list);
if (ret != EFI_SUCCESS) {
free_packagelist(hii);
return EFI_EXIT(ret);
}
hii->driver_handle = driver_handle;
*handle = hii;
return EFI_EXIT(EFI_SUCCESS);
}
static efi_status_t EFIAPI
remove_package_list(const struct efi_hii_database_protocol *this,
efi_hii_handle_t handle)
{
struct efi_hii_packagelist *hii = handle;
EFI_ENTRY("%p, %p", this, handle);
if (!handle || !efi_hii_packagelist_exists(handle))
return EFI_EXIT(EFI_NOT_FOUND);
free_packagelist(hii);
return EFI_EXIT(EFI_SUCCESS);
}
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)
{
struct efi_hii_packagelist *hii = handle;
struct efi_hii_package_header *package;
void *end;
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %p, %p", this, handle, package_list);
if (!handle || !efi_hii_packagelist_exists(handle))
return EFI_EXIT(EFI_NOT_FOUND);
if (!package_list)
return EFI_EXIT(EFI_INVALID_PARAMETER);
EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid,
get_unaligned_le32(&package_list->package_length));
package = ((void *)package_list) + sizeof(*package_list);
end = ((void *)package_list)
+ get_unaligned_le32(&package_list->package_length);
while ((void *)package < end) {
EFI_PRINT("package=%p, package type=%x, length=%u\n", package,
efi_hii_package_type(package),
efi_hii_package_len(package));
switch (efi_hii_package_type(package)) {
case EFI_HII_PACKAGE_TYPE_GUID:
remove_guid_package(hii);
break;
case EFI_HII_PACKAGE_FORMS:
EFI_PRINT("Form package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_STRINGS:
remove_strings_package(hii);
break;
case EFI_HII_PACKAGE_FONTS:
EFI_PRINT("Font package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_IMAGES:
EFI_PRINT("Image package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
EFI_PRINT("Simple font package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_DEVICE_PATH:
EFI_PRINT("Device path package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
remove_keyboard_package(hii);
break;
case EFI_HII_PACKAGE_ANIMATIONS:
EFI_PRINT("Animation package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_END:
goto out;
case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
default:
break;
}
/* TODO: already removed some packages */
if (ret != EFI_SUCCESS)
return EFI_EXIT(ret);
package = ((void *)package)
+ efi_hii_package_len(package);
}
out:
ret = add_packages(hii, package_list);
return EFI_EXIT(ret);
}
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)
{
struct efi_hii_packagelist *hii =
(struct efi_hii_packagelist *)handle;
int package_cnt, package_max;
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
handle_buffer_length, handle);
if (!handle_buffer_length ||
(*handle_buffer_length && !handle))
return EFI_EXIT(EFI_INVALID_PARAMETER);
if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
(package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
return EFI_EXIT(EFI_INVALID_PARAMETER);
EFI_PRINT("package type=%x, guid=%pUl, length=%zu\n", (int)package_type,
package_guid, *handle_buffer_length);
package_cnt = 0;
package_max = *handle_buffer_length / sizeof(*handle);
list_for_each_entry(hii, &efi_package_lists, link) {
switch (package_type) {
case EFI_HII_PACKAGE_TYPE_ALL:
break;
case EFI_HII_PACKAGE_TYPE_GUID:
if (!list_empty(&hii->guid_list))
break;
continue;
case EFI_HII_PACKAGE_FORMS:
EFI_PRINT("Form package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_STRINGS:
if (!list_empty(&hii->string_tables))
break;
continue;
case EFI_HII_PACKAGE_FONTS:
EFI_PRINT("Font package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_IMAGES:
EFI_PRINT("Image package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
EFI_PRINT("Simple font package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_DEVICE_PATH:
EFI_PRINT("Device path package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
if (!list_empty(&hii->keyboard_packages))
break;
continue;
case EFI_HII_PACKAGE_ANIMATIONS:
EFI_PRINT("Animation package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_END:
case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
default:
continue;
}
package_cnt++;
if (package_cnt <= package_max)
*handle++ = hii;
else
ret = EFI_BUFFER_TOO_SMALL;
}
*handle_buffer_length = package_cnt * sizeof(*handle);
return EFI_EXIT(ret);
}
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)
{
EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
if (!buffer_size || !buffer)
return EFI_EXIT(EFI_INVALID_PARAMETER);
return EFI_EXIT(EFI_NOT_FOUND);
}
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)
{
EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
package_guid, package_notify_fn, notify_type,
notify_handle);
if (!notify_handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
(package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
return EFI_EXIT(EFI_INVALID_PARAMETER);
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
}
static efi_status_t EFIAPI
unregister_package_notify(const struct efi_hii_database_protocol *this,
efi_handle_t notification_handle)
{
EFI_ENTRY("%p, %p", this, notification_handle);
return EFI_EXIT(EFI_NOT_FOUND);
}
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)
{
struct efi_keyboard_layout_data *layout_data;
int package_cnt, package_max;
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
if (!key_guid_buffer_length ||
(*key_guid_buffer_length && !key_guid_buffer))
return EFI_EXIT(EFI_INVALID_PARAMETER);
package_cnt = 0;
package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer);
list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
package_cnt++;
if (package_cnt <= package_max)
memcpy(key_guid_buffer++,
&layout_data->keyboard_layout.guid,
sizeof(*key_guid_buffer));
else
ret = EFI_BUFFER_TOO_SMALL;
}
*key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer);
return EFI_EXIT(ret);
}
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)
{
struct efi_keyboard_layout_data *layout_data;
u16 layout_length;
EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
keyboard_layout);
if (!keyboard_layout_length ||
(*keyboard_layout_length && !keyboard_layout))
return EFI_EXIT(EFI_INVALID_PARAMETER);
/* TODO: no notion of current keyboard layout */
if (!key_guid)
return EFI_EXIT(EFI_INVALID_PARAMETER);
list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid))
goto found;
}
return EFI_EXIT(EFI_NOT_FOUND);
found:
layout_length =
get_unaligned_le16(&layout_data->keyboard_layout.layout_length);
if (*keyboard_layout_length < layout_length) {
*keyboard_layout_length = layout_length;
return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
}
memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length);
return EFI_EXIT(EFI_SUCCESS);
}
static efi_status_t EFIAPI
set_keyboard_layout(const struct efi_hii_database_protocol *this,
efi_guid_t *key_guid)
{
EFI_ENTRY("%p, %pUl", this, key_guid);
return EFI_EXIT(EFI_NOT_FOUND);
}
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)
{
struct efi_hii_packagelist *hii;
EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
if (!driver_handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
list_for_each_entry(hii, &efi_package_lists, link) {
if (hii == package_list_handle) {
*driver_handle = hii->driver_handle;
return EFI_EXIT(EFI_SUCCESS);
}
}
return EFI_EXIT(EFI_NOT_FOUND);
}
const struct efi_hii_database_protocol efi_hii_database = {
.new_package_list = new_package_list,
.remove_package_list = remove_package_list,
.update_package_list = update_package_list,
.list_package_lists = list_package_lists,
.export_package_lists = export_package_lists,
.register_package_notify = register_package_notify,
.unregister_package_notify = unregister_package_notify,
.find_keyboard_layouts = find_keyboard_layouts,
.get_keyboard_layout = get_keyboard_layout,
.set_keyboard_layout = set_keyboard_layout,
.get_package_list_handle = get_package_list_handle
};
/*
* EFI_HII_STRING_PROTOCOL
*/
static bool language_match(char *language, char *languages)
{
size_t n;
n = strlen(language);
/* match primary language? */
if (!strncasecmp(language, languages, n) &&
(languages[n] == ';' || languages[n] == '\0'))
return true;
return false;
}
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)
{
struct efi_hii_packagelist *hii = package_list;
struct efi_string_table *stbl;
EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
string_id, language, language_name, string,
string_font_info);
if (!package_list || !efi_hii_packagelist_exists(package_list))
return EFI_EXIT(EFI_NOT_FOUND);
if (!string_id || !language || !string)
return EFI_EXIT(EFI_INVALID_PARAMETER);
list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)language, stbl->language)) {
efi_string_id_t new_id;
void *buf;
efi_string_t str;
new_id = ++hii->max_string_id;
if (stbl->nstrings < new_id) {
buf = realloc(stbl->strings,
sizeof(stbl->strings[0])
* new_id);
if (!buf)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
memset(&stbl->strings[stbl->nstrings], 0,
(new_id - stbl->nstrings)
* sizeof(stbl->strings[0]));
stbl->strings = buf;
stbl->nstrings = new_id;
}
str = u16_strdup(string);
if (!str)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
stbl->strings[new_id - 1].string = str;
*string_id = new_id;
return EFI_EXIT(EFI_SUCCESS);
}
}
return EFI_EXIT(EFI_NOT_FOUND);
}
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)
{
struct efi_hii_packagelist *hii = package_list;
struct efi_string_table *stbl;
EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
package_list, string_id, string, string_size,
string_font_info);
if (!package_list || !efi_hii_packagelist_exists(package_list))
return EFI_EXIT(EFI_NOT_FOUND);
list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)language, stbl->language)) {
efi_string_t str;
size_t len;
if (stbl->nstrings < string_id)
return EFI_EXIT(EFI_NOT_FOUND);
str = stbl->strings[string_id - 1].string;
if (str) {
len = (u16_strlen(str) + 1) * sizeof(u16);
if (*string_size < len) {
*string_size = len;
return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
}
memcpy(string, str, len);
*string_size = len;
} else {
return EFI_EXIT(EFI_NOT_FOUND);
}
return EFI_EXIT(EFI_SUCCESS);
}
}
return EFI_EXIT(EFI_NOT_FOUND);
}
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)
{
struct efi_hii_packagelist *hii = package_list;
struct efi_string_table *stbl;
EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
string_id, language, string, string_font_info);
if (!package_list || !efi_hii_packagelist_exists(package_list))
return EFI_EXIT(EFI_NOT_FOUND);
if (string_id > hii->max_string_id)
return EFI_EXIT(EFI_NOT_FOUND);
if (!string || !language)
return EFI_EXIT(EFI_INVALID_PARAMETER);
list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)language, stbl->language)) {
efi_string_t str;
if (hii->max_string_id < string_id)
return EFI_EXIT(EFI_NOT_FOUND);
if (stbl->nstrings < string_id) {
void *buf;
buf = realloc(stbl->strings,
string_id
* sizeof(stbl->strings[0]));
if (!buf)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
memset(&stbl->strings[string_id - 1], 0,
(string_id - stbl->nstrings)
* sizeof(stbl->strings[0]));
stbl->strings = buf;
}
str = u16_strdup(string);
if (!str)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
free(stbl->strings[string_id - 1].string);
stbl->strings[string_id - 1].string = str;
return EFI_EXIT(EFI_SUCCESS);
}
}
return EFI_EXIT(EFI_NOT_FOUND);
}
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)
{
struct efi_hii_packagelist *hii = package_list;
struct efi_string_table *stbl;
size_t len = 0;
char *p;
EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
languages_size);
if (!package_list || !efi_hii_packagelist_exists(package_list))
return EFI_EXIT(EFI_NOT_FOUND);
if (!languages_size ||
(*languages_size && !languages))
return EFI_EXIT(EFI_INVALID_PARAMETER);
/* figure out required size: */
list_for_each_entry(stbl, &hii->string_tables, link) {
len += strlen((char *)stbl->language) + 1;
}
if (*languages_size < len) {
*languages_size = len;
return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
}
p = (char *)languages;
list_for_each_entry(stbl, &hii->string_tables, link) {
if (p != (char *)languages)
*p++ = ';';
strcpy(p, stbl->language);
p += strlen((char *)stbl->language);
}
*p = '\0';
EFI_PRINT("languages: %s\n", languages);
return EFI_EXIT(EFI_SUCCESS);
}
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)
{
struct efi_hii_packagelist *hii = package_list;
struct efi_string_table *stbl;
bool found = false;
EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
primary_language, secondary_languages,
secondary_languages_size);
if (!package_list || !efi_hii_packagelist_exists(package_list))
return EFI_EXIT(EFI_NOT_FOUND);
if (!secondary_languages_size ||
(*secondary_languages_size && !secondary_languages))
return EFI_EXIT(EFI_INVALID_PARAMETER);
list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)primary_language, stbl->language)) {
found = true;
break;
}
}
if (!found)
return EFI_EXIT(EFI_INVALID_LANGUAGE);
/*
* TODO: What is secondary language?
* *secondary_languages = '\0';
* *secondary_languages_size = 0;
*/
return EFI_EXIT(EFI_NOT_FOUND);
}
const struct efi_hii_string_protocol efi_hii_string = {
.new_string = new_string,
.get_string = get_string,
.set_string = set_string,
.get_languages = get_languages,
.get_secondary_languages = get_secondary_languages
};