From patchwork Sun Sep 10 13:22:25 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rob Clark X-Patchwork-Id: 812141 X-Patchwork-Delegate: agraf@suse.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="uGgEkTCZ"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3xqsKD5jp4z9s7g for ; Sun, 10 Sep 2017 23:26:40 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 82567C21E54; Sun, 10 Sep 2017 13:24:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id ECAE2C21E9D; Sun, 10 Sep 2017 13:23:32 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id AEC1DC21F70; Sun, 10 Sep 2017 13:22:58 +0000 (UTC) Received: from mail-qt0-f193.google.com (mail-qt0-f193.google.com [209.85.216.193]) by lists.denx.de (Postfix) with ESMTPS id 3C9FDC21F21 for ; Sun, 10 Sep 2017 13:22:56 +0000 (UTC) Received: by mail-qt0-f193.google.com with SMTP id u48so1297306qtc.4 for ; Sun, 10 Sep 2017 06:22:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=5IFF6U5h3HI/ExkQAAxHlPYlx3w+z48LBx/kneAdp10=; b=uGgEkTCZixKi96CSFNy1kZt8h5+blbmkz5V2jSKgkwlJdrbVOnkDpGgGcGv1A7U1ml U732JkL7GqjCh+sdFC6+dYk5NCxIOODvE8fyCrXtZR+64bkPdeV4JdVLssGRi8PhFn0X 09SBU3aR/tPkoQkRA6tW2zf1LMz+lGiyoP4lzzVtIwg2iPl0MnW0EQSUuQfHdyh6F8Gn d39AdsvAxAwSTugWGhp2CcibVBEr0IvAJebW2MIRGoWIROyRUwcxBSW/v3HTeeMl4t/R KQ9EIjMK6pBYVy4QtNriHvsJTRwaC7c1KJJVV5qrHsyMjKZFbCY1Ax8eQX5THp3FACYf R27w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=5IFF6U5h3HI/ExkQAAxHlPYlx3w+z48LBx/kneAdp10=; b=QpLB13BZg1X343MXBAqH3o3dIQ26+bQYxp+QTtu3A7p0+THYG0LQQCrxLZOem0Ekqj 26mkic0o2lTToLmTUXoMP/rMplFyLH51rpjg+PM3eiZuARtyeTTiFxTAPJB1J/GFfqLY tfV+7CNSIvDR7RbYLsP29dMkIEiB/Gq+18Lat5Q/6uC8wDIKWI8pcgPo/n5DE32UXj83 /t+zpW+sgF3oGyTXcqW0zlkg5hcRAPWYHac7fv9jSCn0/OaCNesMPM+G50gBky0AnkXp UI2HYlyUsD0N3ngX6+TMn4D0rZhI1Lss2Nicvv1zVi57Kz7A7dZ5uFI9iNLHSeQh45gh wrfw== X-Gm-Message-State: AHPjjUiZ3plQeDWc2noLtg/FyS5IQ/XuUs9DYmxDuoOcL1X8QDhxU0XZ 188W9SAiYih6P2fp/70= X-Google-Smtp-Source: AOwi7QAfxCJENDMs9Pq6X8XOCFjZFTimn+vn+mg4N0GfWV0R1T4opOw/+1PMrXgzXt4XWut6nmvGjQ== X-Received: by 10.200.34.168 with SMTP id f37mr11797783qta.91.1505049774829; Sun, 10 Sep 2017 06:22:54 -0700 (PDT) Received: from localhost ([2601:184:4780:aac0:25f8:dd96:a084:785a]) by smtp.gmail.com with ESMTPSA id i39sm4644411qte.11.2017.09.10.06.22.53 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 10 Sep 2017 06:22:53 -0700 (PDT) From: Rob Clark To: U-Boot Mailing List Date: Sun, 10 Sep 2017 09:22:25 -0400 Message-Id: <20170910132236.14318-5-robdclark@gmail.com> X-Mailer: git-send-email 2.13.5 In-Reply-To: <20170910132236.14318-1-robdclark@gmail.com> References: <20170910132236.14318-1-robdclark@gmail.com> Cc: Heinrich Schuchardt , Peter Jones , Leif Lindholm Subject: [U-Boot] [PATCH v1 04/12] efi_loader: start fleshing out HII X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Not complete but enough for Shell.efi and SCT.efi. Signed-off-by: Rob Clark --- include/efi_api.h | 68 +++++++++++- lib/efi_loader/efi_hii.c | 274 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 304 insertions(+), 38 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index 25f774f253..4853b71497 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -16,6 +16,7 @@ #define _EFI_API_H #include +#include #ifdef CONFIG_EFI_LOADER #include @@ -540,6 +541,8 @@ struct efi_device_path_utilities_protocol EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \ 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f) +typedef uint16_t efi_string_id_t; + struct efi_hii_config_routing_protocol { efi_status_t(EFIAPI *extract_config)( @@ -630,7 +633,69 @@ struct efi_hii_package_list_header { efi_guid_t package_list_guid; uint32_t package_length; -}; +} __packed; + +struct efi_hii_package_header { + uint32_t length : 24; + uint32_t type : 8; +} __packed; + +#define EFI_HII_PACKAGE_TYPE_ALL 0x00 +#define EFI_HII_PACKAGE_TYPE_GUID 0x01 +#define EFI_HII_PACKAGE_FORMS 0x02 +#define EFI_HII_PACKAGE_STRINGS 0x04 +#define EFI_HII_PACKAGE_FONTS 0x05 +#define EFI_HII_PACKAGE_IMAGES 0x06 +#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 +#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09 +#define EFI_HII_PACKAGE_ANIMATIONS 0x0A +#define EFI_HII_PACKAGE_END 0xDF +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF + +struct efi_hii_strings_package { + struct efi_hii_package_header header; + uint32_t header_size; + uint32_t string_info_offset; + uint16_t language_window[16]; + efi_string_id_t language_name; + uint8_t language[]; +} __packed; + +struct efi_hii_string_block { + uint8_t block_type; + /*uint8_t block_body[];*/ +} __packed; + +#define EFI_HII_SIBT_END 0x00 // The end of the string information. +#define EFI_HII_SIBT_STRING_SCSU 0x10 // Single string using default font information. +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 // Single string with font information. +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 // Multiple strings using default font information. +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information. +#define EFI_HII_SIBT_STRING_UCS2 0x14 // Single UCS-2 string using default font information. +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 // Single UCS-2 string with font information +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 // Multiple UCS-2 strings using default font information. +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information. +#define EFI_HII_SIBT_DUPLICATE 0x20 // Create a duplicate of an existing string. +#define EFI_HII_SIBT_SKIP2 0x21 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_SKIP1 0x22 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_EXT1 0x30 // For future expansion (one byte length field) +#define EFI_HII_SIBT_EXT2 0x31 // For future expansion (two byte length field) +#define EFI_HII_SIBT_EXT4 0x32 // For future expansion (four byte length field) +#define EFI_HII_SIBT_FONT 0x40 // Font information. + +struct efi_hii_sibt_string_ucs2_block { + struct efi_hii_string_block header; + uint16_t string_text[]; +} __packed; + +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next( + struct efi_hii_sibt_string_ucs2_block *blk) +{ + return ((void *)blk) + sizeof(*blk) + + (utf16_strlen(blk->string_text) + 1) * 2; +} typedef void *efi_hii_handle_t; @@ -693,7 +758,6 @@ struct efi_hii_database_protocol 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a) typedef uint32_t efi_hii_font_style_t; -typedef uint16_t efi_string_id_t; struct efi_font_info { diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c index cc68a28d2b..d818f409dc 100644 --- a/lib/efi_loader/efi_hii.c +++ b/lib/efi_loader/efi_hii.c @@ -7,6 +7,7 @@ */ #include +#include #include const efi_guid_t efi_guid_hii_config_routing_protocol = @@ -14,12 +15,128 @@ const efi_guid_t efi_guid_hii_config_routing_protocol = 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; +struct hii_package { + // TODO should there be an associated efi_object? + struct list_head string_tables; /* list of string_table */ + /* we could also track fonts, images, etc */ +}; + +struct string_table { + struct list_head link; + efi_string_id_t language_name; + char *language; + uint32_t nstrings; + /* NOTE: string id starts at 1 so value is stbl->strings[id-1] */ + struct { + efi_string_t string; + /* we could also track font info, etc */ + } strings[]; +}; + +static void free_strings_table(struct string_table *stbl) +{ + for (int i = 0; i < stbl->nstrings; i++) + free(stbl->strings[i].string); + free(stbl->language); + free(stbl); +} + +static struct hii_package *new_package(void) +{ + struct hii_package *hii = malloc(sizeof(*hii)); + INIT_LIST_HEAD(&hii->string_tables); + return hii; +} + +static void free_package(struct hii_package *hii) +{ + + while (!list_empty(&hii->string_tables)) { + struct string_table *stbl; + + stbl = list_first_entry(&hii->string_tables, + struct string_table, link); + list_del(&stbl->link); + free_strings_table(stbl); + } + + free(hii); +} + +static efi_status_t add_strings_package(struct hii_package *hii, + struct efi_hii_strings_package *strings_package) +{ + struct efi_hii_string_block *block; + void *end = ((void *)strings_package) + strings_package->header.length; + uint32_t nstrings = 0; + unsigned id = 0; + + debug("header_size: %08x\n", strings_package->header_size); + debug("string_info_offset: %08x\n", strings_package->string_info_offset); + debug("language_name: %u\n", strings_package->language_name); + debug("language: %s\n", strings_package->language); + + /* count # of string entries: */ + block = ((void *)strings_package) + 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 = + (void *)block; + nstrings++; + block = efi_hii_sibt_string_ucs2_block_next(ucs2); + break; + } + case EFI_HII_SIBT_END: + block = end; + break; + default: + debug("unknown HII string block type: %02x\n", + block->block_type); + return EFI_INVALID_PARAMETER; + } + } + + struct string_table *stbl = malloc(sizeof(*stbl) + + (nstrings * sizeof(stbl->strings[0]))); + stbl->language_name = strings_package->language_name; + stbl->language = strdup((char *)strings_package->language); + stbl->nstrings = nstrings; + + list_add(&stbl->link, &hii->string_tables); + + /* and now parse string entries and populate string_table */ + block = ((void *)strings_package) + 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 = + (void *)block; + id++; + debug("%4u: \"%ls\"\n", id, ucs2->string_text); + stbl->strings[id-1].string = + utf16_strdup(ucs2->string_text); + block = efi_hii_sibt_string_ucs2_block_next(ucs2); + break; + } + case EFI_HII_SIBT_END: + return EFI_SUCCESS; + default: + debug("unknown HII string block type: %02x\n", + block->block_type); + return EFI_INVALID_PARAMETER; + } + } + + return EFI_SUCCESS; +} /* * EFI_HII_CONFIG_ROUTING_PROTOCOL */ -static efi_status_t extract_config( +static efi_status_t EFIAPI extract_config( const struct efi_hii_config_routing_protocol *this, const efi_string_t request, efi_string_t *progress, @@ -29,7 +146,7 @@ static efi_status_t extract_config( return EFI_EXIT(EFI_OUT_OF_RESOURCES); } -static efi_status_t export_config( +static efi_status_t EFIAPI export_config( const struct efi_hii_config_routing_protocol *this, efi_string_t *results) { @@ -37,7 +154,7 @@ static efi_status_t export_config( return EFI_EXIT(EFI_OUT_OF_RESOURCES); } -static efi_status_t route_config( +static efi_status_t EFIAPI route_config( const struct efi_hii_config_routing_protocol *this, const efi_string_t configuration, efi_string_t *progress) @@ -46,7 +163,7 @@ static efi_status_t route_config( return EFI_EXIT(EFI_OUT_OF_RESOURCES); } -static efi_status_t block_to_config( +static efi_status_t EFIAPI block_to_config( const struct efi_hii_config_routing_protocol *this, const efi_string_t config_request, const uint8_t *block, @@ -54,12 +171,12 @@ static efi_status_t block_to_config( efi_string_t *config, efi_string_t *progress) { - EFI_ENTRY("%p, \"%ls\", %p, %lu, %p, %p", this, config_request, block, + EFI_ENTRY("%p, \"%ls\", %p, %zu, %p, %p", this, config_request, block, block_size, config, progress); return EFI_EXIT(EFI_OUT_OF_RESOURCES); } -static efi_status_t config_to_block( +static efi_status_t EFIAPI config_to_block( const struct efi_hii_config_routing_protocol *this, const efi_string_t config_resp, const uint8_t *block, @@ -71,7 +188,7 @@ static efi_status_t config_to_block( return EFI_EXIT(EFI_OUT_OF_RESOURCES); } -static efi_status_t get_alt_config( +static efi_status_t EFIAPI get_alt_config( const struct efi_hii_config_routing_protocol *this, const efi_string_t config_resp, const efi_guid_t *guid, @@ -91,28 +208,67 @@ static efi_status_t get_alt_config( * EFI_HII_DATABASE_PROTOCOL */ -static efi_status_t new_package_list( +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) { - /* Current shell start failure. */ - /* Invoked from MdeModulePkg/Library/UefiHiiLib/HiiLib.c : HiiAddPackages */ - /* (Via autogenerated .c file.) */ + efi_status_t ret = EFI_SUCCESS; + EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle); - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + if (!package_list || !driver_handle) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + struct hii_package *hii = new_package(); + struct efi_hii_package_header *package; + void *end = ((void *)package_list) + package_list->package_length; + + debug("package_list: %pUl (%u)\n", &package_list->package_list_guid, + 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, + package->type, package->length); + switch (package->type) { + case EFI_HII_PACKAGE_STRINGS: + ret = add_strings_package(hii, + (struct efi_hii_strings_package *)package); + break; + default: + break; + } + + if (ret != EFI_SUCCESS) + goto error; + + package = ((void *)package) + package->length; + } + + // TODO in theory there is some notifications that should be sent.. + + *handle = hii; + + return EFI_EXIT(EFI_SUCCESS); + +error: + free_package(hii); + return EFI_EXIT(ret); } -static efi_status_t remove_package_list( +static efi_status_t EFIAPI remove_package_list( const struct efi_hii_database_protocol *this, efi_hii_handle_t handle) { + struct hii_package *hii = handle; EFI_ENTRY("%p, %p", this, handle); - return EFI_EXIT(EFI_NOT_FOUND); + free_package(hii); + return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t update_package_list( +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) @@ -121,7 +277,7 @@ static efi_status_t update_package_list( return EFI_EXIT(EFI_NOT_FOUND); } -static efi_status_t list_package_lists( +static efi_status_t EFIAPI list_package_lists( const struct efi_hii_database_protocol *this, uint8_t package_type, const efi_guid_t *package_guid, @@ -133,7 +289,7 @@ static efi_status_t list_package_lists( return EFI_EXIT(EFI_NOT_FOUND); } -static efi_status_t export_package_lists( +static efi_status_t EFIAPI export_package_lists( const struct efi_hii_database_protocol *this, efi_hii_handle_t handle, UINTN *buffer_size, @@ -143,7 +299,7 @@ static efi_status_t export_package_lists( return EFI_EXIT(EFI_NOT_FOUND); } -static efi_status_t register_package_notify( +static efi_status_t EFIAPI register_package_notify( const struct efi_hii_database_protocol *this, uint8_t package_type, const efi_guid_t *package_guid, @@ -151,13 +307,13 @@ static efi_status_t register_package_notify( UINTN notify_type, efi_handle_t *notify_handle) { - EFI_ENTRY("%p, %u, %pUl, %p, %lu, %p", this, package_type, + EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type, package_guid, package_notify_fn, notify_type, notify_handle); return EFI_EXIT(EFI_OUT_OF_RESOURCES); } -static efi_status_t unregister_package_notify( +static efi_status_t EFIAPI unregister_package_notify( const struct efi_hii_database_protocol *this, efi_handle_t notification_handle) { @@ -165,7 +321,7 @@ static efi_status_t unregister_package_notify( return EFI_EXIT(EFI_NOT_FOUND); } -static efi_status_t find_keyboard_layouts( +static efi_status_t EFIAPI find_keyboard_layouts( const struct efi_hii_database_protocol *this, uint16_t *key_guid_buffer_length, efi_guid_t *key_guid_buffer) @@ -174,7 +330,7 @@ static efi_status_t find_keyboard_layouts( return EFI_EXIT(EFI_NOT_FOUND); /* Invalid */ } -static efi_status_t get_keyboard_layout( +static efi_status_t EFIAPI get_keyboard_layout( const struct efi_hii_database_protocol *this, efi_guid_t *key_guid, uint16_t *keyboard_layout_length, @@ -185,7 +341,7 @@ static efi_status_t get_keyboard_layout( return EFI_EXIT(EFI_NOT_FOUND); } -static efi_status_t set_keyboard_layout( +static efi_status_t EFIAPI set_keyboard_layout( const struct efi_hii_database_protocol *this, efi_guid_t *key_guid) { @@ -193,7 +349,7 @@ static efi_status_t set_keyboard_layout( return EFI_EXIT(EFI_NOT_FOUND); } -static efi_status_t get_package_list_handle( +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) @@ -207,7 +363,7 @@ static efi_status_t get_package_list_handle( * EFI_HII_STRING_PROTOCOL */ -static efi_status_t new_string( +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, @@ -216,13 +372,13 @@ static efi_status_t new_string( const efi_string_t string, const struct efi_font_info *string_font_info) { - EFI_ENTRY("%p, %p, %p, %p, %p, \"%ls\", %p", this, package_list, + EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list, string_id, language, language_name, string, string_font_info); return EFI_EXIT(EFI_NOT_FOUND); } -static efi_status_t get_string( +static efi_status_t EFIAPI get_string( const struct efi_hii_string_protocol *this, const uint8_t *language, efi_hii_handle_t package_list, @@ -231,13 +387,34 @@ static efi_status_t get_string( UINTN *string_size, struct efi_font_info **string_font_info) { - EFI_ENTRY("%p, %p, %p, %u, \"%ls\", %p, %p", this, language, + struct hii_package *hii = package_list; + struct string_table *stbl; + + EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language, package_list, string_id, string, string_size, string_font_info); + + list_for_each_entry(stbl, &hii->string_tables, link) { + if (!strcmp((char *)language, (char *)stbl->language)) { + unsigned idx = string_id - 1; + if (idx > stbl->nstrings) + return EFI_EXIT(EFI_NOT_FOUND); + efi_string_t str = stbl->strings[idx].string; + size_t len = utf16_strlen(str) + 1; + if (*string_size < len * 2) { + *string_size = len * 2; + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + } + memcpy(string, str, len * 2); + *string_size = len * 2; + return EFI_EXIT(EFI_SUCCESS); + } + } + return EFI_EXIT(EFI_NOT_FOUND); } -static efi_status_t set_string( +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, @@ -245,31 +422,56 @@ static efi_status_t set_string( const efi_string_t string, const struct efi_font_info *string_font_info) { - EFI_ENTRY("%p, %p, %u, %p, \"%ls\", %p", this, package_list, string_id, - language, string, string_font_info); + EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list, + string_id, language, string, string_font_info); return EFI_EXIT(EFI_NOT_FOUND); } -static efi_status_t get_languages( +static efi_status_t EFIAPI get_languages( const struct efi_hii_string_protocol *this, efi_hii_handle_t package_list, uint8_t *languages, UINTN *languages_size) { + struct hii_package *hii = package_list; + struct string_table *stbl; + size_t len = 0; + EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages, languages_size); - return EFI_EXIT(EFI_NOT_FOUND); + + /* 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); + } + + char *p = (char *)languages; + list_for_each_entry(stbl, &hii->string_tables, link) { + if (p != (char *)languages) + p += sprintf(p, ";"); + p += sprintf(p, "%s", stbl->language); + } + + debug("languages: %s\n", languages); + + return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t get_secondary_languages( +static efi_status_t EFIAPI get_secondary_languages( const struct efi_hii_string_protocol *this, efi_hii_handle_t package_list, const uint8_t *primary_language, uint8_t *secondary_languages, UINTN *secondary_languages_size) { - EFI_ENTRY("%p, %p, %p, %p, %p", this, package_list, primary_language, - secondary_languages, secondary_languages_size); + EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list, + primary_language, secondary_languages, + secondary_languages_size); return EFI_EXIT(EFI_NOT_FOUND); }