efi_loader: image_loader: support image authentication
[oweals/u-boot.git] / lib / efi_loader / efi_hii.c
index d6dba5719cdb8827822db90ae701bc46ac860445..77e330285a72f61592ba2f0bc09dce4d5e819096 100644 (file)
@@ -16,6 +16,7 @@ const efi_guid_t efi_guid_hii_database_protocol
 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;
@@ -23,6 +24,8 @@ struct efi_hii_packagelist {
        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 */
 };
@@ -80,6 +83,22 @@ struct efi_string_table {
        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;
@@ -113,13 +132,13 @@ add_strings_package(struct efi_hii_packagelist *hii,
        struct efi_string_table *stbl = NULL;
        efi_status_t ret;
 
-       debug("header_size: %08x\n",
-             get_unaligned_le32(&strings_package->header_size));
-       debug("string_info_offset: %08x\n",
-             get_unaligned_le32(&strings_package->string_info_offset));
-       debug("language_name: %u\n",
-             get_unaligned_le16(&strings_package->language_name));
-       debug("language: %s\n", strings_package->language);
+       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)
@@ -141,8 +160,8 @@ add_strings_package(struct efi_hii_packagelist *hii,
                        block = end;
                        break;
                default:
-                       debug("unknown HII string block type: %02x\n",
-                             block->block_type);
+                       EFI_PRINT("unknown HII string block type: %02x\n",
+                                 block->block_type);
                        return EFI_INVALID_PARAMETER;
                }
        }
@@ -176,7 +195,7 @@ add_strings_package(struct efi_hii_packagelist *hii,
                        struct efi_hii_sibt_string_ucs2_block *ucs2;
 
                        ucs2 = (void *)block;
-                       debug("%4u: \"%ls\"\n", idx + 1, ucs2->string_text);
+                       EFI_PRINT("%4u: \"%ls\"\n", idx + 1, ucs2->string_text);
                        stbl->strings[idx].string =
                                u16_strdup(ucs2->string_text);
                        if (!stbl->strings[idx].string) {
@@ -191,8 +210,8 @@ add_strings_package(struct efi_hii_packagelist *hii,
                case EFI_HII_SIBT_END:
                        goto out;
                default:
-                       debug("unknown HII string block type: %02x\n",
-                             block->block_type);
+                       EFI_PRINT("unknown HII string block type: %02x\n",
+                                 block->block_type);
                        ret = EFI_INVALID_PARAMETER;
                        goto error;
                }
@@ -208,9 +227,8 @@ out:
 error:
        if (stbl) {
                free(stbl->language);
-               if (idx > 0)
-                       while (--idx >= 0)
-                               free(stbl->strings[idx].string);
+               while (idx > 0)
+                       free(stbl->strings[--idx].string);
                free(stbl->strings);
        }
        free(stbl);
@@ -218,13 +236,117 @@ error:
        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;
 }
@@ -232,6 +354,8 @@ static struct efi_hii_packagelist *new_packagelist(void)
 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);
@@ -248,22 +372,22 @@ add_packages(struct efi_hii_packagelist *hii,
        end = ((void *)package_list)
                + get_unaligned_le32(&package_list->package_length);
 
-       debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
-             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) {
-               debug("package=%p, package type=%x, length=%u\n", package,
-                     efi_hii_package_type(package),
-                     efi_hii_package_len(package));
+               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:
-                       printf("\tGuid package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
+                       ret = add_guid_package(hii,
+                               (struct efi_hii_guid_package *)package);
                        break;
                case EFI_HII_PACKAGE_FORMS:
-                       printf("\tForm package not supported\n");
+                       EFI_PRINT("Form package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_STRINGS:
@@ -271,27 +395,27 @@ add_packages(struct efi_hii_packagelist *hii,
                                (struct efi_hii_strings_package *)package);
                        break;
                case EFI_HII_PACKAGE_FONTS:
-                       printf("\tFont package not supported\n");
+                       EFI_PRINT("Font package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_IMAGES:
-                       printf("\tImage package not supported\n");
+                       EFI_PRINT("Image package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_SIMPLE_FONTS:
-                       printf("\tSimple font package not supported\n");
+                       EFI_PRINT("Simple font package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_DEVICE_PATH:
-                       printf("\tDevice path package not supported\n");
+                       EFI_PRINT("Device path package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
-                       printf("\tKeyboard layout package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
+                       ret = add_keyboard_package(hii,
+                               (struct efi_hii_keyboard_package *)package);
                        break;
                case EFI_HII_PACKAGE_ANIMATIONS:
-                       printf("\tAnimation package not supported\n");
+                       EFI_PRINT("Animation package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_END:
@@ -341,7 +465,6 @@ new_package_list(const struct efi_hii_database_protocol *this,
        }
 
        hii->driver_handle = driver_handle;
-       list_add_tail(&hii->link, &efi_package_lists);
        *handle = hii;
 
        return EFI_EXIT(EFI_SUCCESS);
@@ -381,51 +504,50 @@ update_package_list(const struct efi_hii_database_protocol *this,
        if (!package_list)
                return EFI_EXIT(EFI_INVALID_PARAMETER);
 
-       debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
-             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);
        end = ((void *)package_list)
                + get_unaligned_le32(&package_list->package_length);
 
        while ((void *)package < end) {
-               debug("package=%p, package type=%x, length=%u\n", package,
-                     efi_hii_package_type(package),
-                     efi_hii_package_len(package));
+               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:
-                       printf("\tGuid package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
+                       remove_guid_package(hii);
                        break;
                case EFI_HII_PACKAGE_FORMS:
-                       printf("\tForm package not supported\n");
+                       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:
-                       printf("\tFont package not supported\n");
+                       EFI_PRINT("Font package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_IMAGES:
-                       printf("\tImage package not supported\n");
+                       EFI_PRINT("Image package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_SIMPLE_FONTS:
-                       printf("\tSimple font package not supported\n");
+                       EFI_PRINT("Simple font package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_DEVICE_PATH:
-                       printf("\tDevice path package not supported\n");
+                       EFI_PRINT("Device path package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
-                       printf("\tKeyboard layout package not supported\n");
+                       remove_keyboard_package(hii);
                        break;
                case EFI_HII_PACKAGE_ANIMATIONS:
-                       printf("\tAnimation package not supported\n");
+                       EFI_PRINT("Animation package not supported\n");
                        ret = EFI_INVALID_PARAMETER;
                        break;
                case EFI_HII_PACKAGE_END:
@@ -459,21 +581,25 @@ list_package_lists(const struct efi_hii_database_protocol *this,
        struct efi_hii_packagelist *hii =
                                (struct efi_hii_packagelist *)handle;
        int package_cnt, package_max;
-       efi_status_t ret = EFI_SUCCESS;
+       efi_status_t ret = EFI_NOT_FOUND;
 
        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);
+           (*handle_buffer_length && !handle)) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
 
        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);
+           (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
 
-       debug("package type=%x, guid=%pUl, length=%lu\n", (int)package_type,
-             package_guid, *handle_buffer_length);
+       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);
@@ -482,55 +608,31 @@ list_package_lists(const struct efi_hii_database_protocol *this,
                case EFI_HII_PACKAGE_TYPE_ALL:
                        break;
                case EFI_HII_PACKAGE_TYPE_GUID:
-                       printf("\tGuid package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
-                       continue;
-               case EFI_HII_PACKAGE_FORMS:
-                       printf("\tForm package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
+                       if (!list_empty(&hii->guid_list))
+                               break;
                        continue;
                case EFI_HII_PACKAGE_STRINGS:
                        if (!list_empty(&hii->string_tables))
                                break;
                        continue;
-               case EFI_HII_PACKAGE_FONTS:
-                       printf("\tFont package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
-                       continue;
-               case EFI_HII_PACKAGE_IMAGES:
-                       printf("\tImage package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
-                       continue;
-               case EFI_HII_PACKAGE_SIMPLE_FONTS:
-                       printf("\tSimple font package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
-                       continue;
-               case EFI_HII_PACKAGE_DEVICE_PATH:
-                       printf("\tDevice path package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
-                       continue;
                case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
-                       printf("\tKeyboard layout package not supported\n");
-                       continue;
-               case EFI_HII_PACKAGE_ANIMATIONS:
-                       printf("\tAnimation package not supported\n");
-                       ret = EFI_INVALID_PARAMETER;
+                       if (!list_empty(&hii->keyboard_packages))
+                               break;
                        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)
+               if (package_cnt <= package_max) {
                        *handle++ = hii;
-               else
+                       ret = EFI_SUCCESS;
+               } else {
                        ret = EFI_BUFFER_TOO_SMALL;
+               }
        }
        *handle_buffer_length = package_cnt * sizeof(*handle);
-
+out:
        return EFI_EXIT(ret);
 }
 
@@ -584,9 +686,30 @@ 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);
 
-       return EFI_EXIT(EFI_NOT_FOUND);
+       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
@@ -595,10 +718,38 @@ get_keyboard_layout(const struct efi_hii_database_protocol *this,
                    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
@@ -868,7 +1019,7 @@ get_languages(const struct efi_hii_string_protocol *this,
        }
        *p = '\0';
 
-       debug("languages: %s\n", languages);
+       EFI_PRINT("languages: %s\n", languages);
 
        return EFI_EXIT(EFI_SUCCESS);
 }