Can you not just mask of the error bit, and index into the table
(after a bounds check) as opposed to doing this looping search?

Also I think an strerror type interface would be nicer to callers
(maybe in addition) as opposed to this perror stuff, that
way they can do their own grub_error, or other thing as they wish.

On Thu, Jun 26, 2025 at 10:25 AM Khalid Ali <khaliidca...@gmail.com> wrote:
>
> This RFC patch introduces a UEFI error message printer that translates
> UEFI status codes from hexadecimal values into human-readable strings.
>
> The problem this rfc solves is, undescriptive error messages in Grub (on 
> failure what
> get printed). Specifically the documented firmware spec which UEFI. In UEFI 
> specific code
> i noticed error messages like "unknown error", "cannot load image" and so on. 
> Unfortunately
> changing error message one by one is expensive and bad idea, all privious 
> attempt resulted
> alot of code duplication. So this idea of centralized error handling for UEFI 
> specific was the
> easiest and cleanest way the problem could be solved.
>
> The idea is inspired by the GNU C Library's "perror()" function, which 
> translates
> "errno" values into descriptive error messages. Similarly, this 
> implementation eliminates
> the need for conditional statements when printing UEFI error messages. In 
> short, it's a "perror"-like
> mechanism tailored for UEFI status codes in GRUB.
>
> The function takes three parameter:
>   - "grub_err_t err": if the caller desires to set errno. Caller can safely
>     return errno if it wants to return status code.
>   - "const char *s": a null-terminated string that further
>     describes the error context, like the reason of failure.
>   - "EFI_STATUS status": the UEFI status code returned by a call to UEFI
>     service, to translate to string.
>
> Additionally, if this patch is accepted, it maybe better if we propogate
> this function throughout UEFI subsystem. That would mean replacing some
> grub_error() calls to this function as it is the one who is calling it
> internally, putting on UEFI service calls in case of failure to check and 
> print
> status codes. Then the caller can safely return "grub_errno" if there
> were a failure. The benefit would be clearer, and more descriptive error 
> messages,
> instead of raw hex codes and reduction of the amount of code needed for
> printing error messages like conditional statements. This will improve user 
> experience,
> debugging clarity and code readability.
>
> Looking forward for your feedback and what community think of this idea
> and the code. Additionally i left something i felt worth dicussing with
> the commuinty, which is if translation is ideal on this context.
>
> Best regard
> khaalid
>
> Signed-off-by: Khalid Ali <khaliidca...@gmail.com>
> ---
>  grub-core/kern/efi/err.c | 81 ++++++++++++++++++++++++++++++++++++++++
>  include/grub/efi/api.h   |  6 +++
>  include/grub/efi/efi.h   |  3 ++
>  3 files changed, 90 insertions(+)
>  create mode 100644 grub-core/kern/efi/err.c
>
> diff --git a/grub-core/kern/efi/err.c b/grub-core/kern/efi/err.c
> new file mode 100644
> index 000000000..b870b26ba
> --- /dev/null
> +++ b/grub-core/kern/efi/err.c
> @@ -0,0 +1,81 @@
> +/* err.c - uefi specific error handling routine */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2025 Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/err.h>
> +#include <grub/misc.h>
> +#include <grub/efi/api.h>
> +#include <grub/efi/efi.h>
> +
> +struct grub_efi_err
> +{
> +    grub_efi_status_t status;
> +    const char *error_msg;
> +};
> +
> +/* EFI error table: keep entries sorted alphabetically. */
> +static const struct grub_efi_err grub_efi_err_table[] =
> +{
> +    {GRUB_EFI_ABORTED, "aborted"},
> +    {GRUB_EFI_ACCESS_DENIED, "access denied"},
> +    {GRUB_EFI_ALREADY_STARTED, "already started"},
> +    {GRUB_EFI_BAD_BUFFER_SIZE, "bad buffer size"},
> +    {GRUB_EFI_BUFFER_TOO_SMALL, "buffer too small"},
> +    {GRUB_EFI_CRC_ERROR, "crc error"},
> +    {GRUB_EFI_DEVICE_ERROR, "device error"},
> +    {GRUB_EFI_END_OF_FILE, "end of file"},
> +    {GRUB_EFI_END_OF_MEDIA, "end of media"},
> +    {GRUB_EFI_HTTP_ERROR, "http error"},
> +    {GRUB_EFI_ICMP_ERROR, "icmp error"},
> +    {GRUB_EFI_INCOMPATIBLE_VERSION, "incompatible version"},
> +    {GRUB_EFI_INVALID_PARAMETER, "invalid parameter"},
> +    {GRUB_EFI_IP_ADDRESS_CONFLICT, "ip address conflict"},
> +    {GRUB_EFI_LOAD_ERROR, "load error"},
> +    {GRUB_EFI_MEDIA_CHANGED, "media changed"},
> +    {GRUB_EFI_NO_MAPPING, "no mapping"},
> +    {GRUB_EFI_NO_MEDIA, "no media"},
> +    {GRUB_EFI_NO_RESPONSE, "no response"},
> +    {GRUB_EFI_NOT_FOUND, "not found"},
> +    {GRUB_EFI_NOT_READY, "not ready"},
> +    {GRUB_EFI_NOT_STARTED, "not started"},
> +    {GRUB_EFI_OUT_OF_RESOURCES, "out of resources"},
> +    {GRUB_EFI_PROTOCOL_ERROR, "protocol error"},
> +    {GRUB_EFI_SECURITY_VIOLATION, "security violation"},
> +    {GRUB_EFI_SUCCESS, "success"},
> +    {GRUB_EFI_TFTP_ERROR, "tftp error"},
> +    {GRUB_EFI_TIMEOUT, "timed out"},
> +    {GRUB_EFI_UNSPECIFIED_TIMEZONE, "unspecified timezone"},
> +    {GRUB_EFI_UNSUPPORTED, "unsupported"},
> +    {GRUB_EFI_VOLUME_CORRUPTED, "volume corrupted"},
> +    {GRUB_EFI_VOLUME_FULL, "volume full"},
> +    {GRUB_EFI_WRITE_PROTECTED, "write protected"}
> +};
> +
> +void
> +grub_efi_perror(grub_err_t err, const char *s, grub_efi_status_t status)
> +{
> +    for (grub_size_t i = 0; i < ARRAY_SIZE(grub_efi_err_table); i++)
> +    {
> +        if (grub_efi_err_table[i].status == status)
> +        {
> +            grub_error (err, "%s : %s", s, grub_efi_err_table[i].error_msg);
> +            return; /* we got what we needed, that is enough*/
> +        }
> +    }
> +    grub_error (err, "%s : unknown error", s);
> +}
> \ No newline at end of file
> diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
> index b686e8afe..f74bc0287 100644
> --- a/include/grub/efi/api.h
> +++ b/include/grub/efi/api.h
> @@ -632,6 +632,12 @@ typedef grub_efi_uintn_t grub_efi_status_t;
>  #define GRUB_EFI_INCOMPATIBLE_VERSION  GRUB_EFI_ERROR_CODE (25)
>  #define GRUB_EFI_SECURITY_VIOLATION    GRUB_EFI_ERROR_CODE (26)
>  #define GRUB_EFI_CRC_ERROR             GRUB_EFI_ERROR_CODE (27)
> +#define GRUB_EFI_END_OF_MEDIA GRUB_EFI_ERROR_CODE (28)
> +#define GRUB_EFI_END_OF_FILE GRUB_EFI_ERROR_CODE (31)
> +#define GRUB_EFI_INVALID_LANGUAGE GRUB_EFI_ERROR_CODE (32)
> +#define GRUB_EFI_COMPROMISED_DATA GRUB_EFI_ERROR_CODE (33)
> +#define GRUB_EFI_IP_ADDRESS_CONFLICT GRUB_EFI_ERROR_CODE (34)
> +#define GRUB_EFI_HTTP_ERROR GRUB_EFI_ERROR_CODE (35)
>
>  #define GRUB_EFI_WARN_UNKNOWN_GLYPH    GRUB_EFI_WARNING_CODE (1)
>  #define GRUB_EFI_WARN_DELETE_FAILURE   GRUB_EFI_WARNING_CODE (2)
> diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
> index a5cd99e5a..8e91eaad4 100644
> --- a/include/grub/efi/efi.h
> +++ b/include/grub/efi/efi.h
> @@ -122,6 +122,9 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) 
> (grub_efi_handle_t hnd,
>  void *
>  EXPORT_FUNC (grub_efi_find_configuration_table) (const grub_guid_t 
> *target_guid);
>
> +void
> +EXPORT_FUNC (grub_efi_perror) (grub_err_t err, const char *s, 
> grub_efi_status_t status);
> +
>  #if defined(__arm__) || defined(__aarch64__) || defined(__riscv) || 
> defined(__loongarch__)
>  void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
>  grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
> --
> 2.49.0
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to