[libc-commits] [libc] [libc][uefi] Encode the error bit in EFI_STATUS error codes (PR #235071)
Prabhu Rajasekaran via libc-commits
libc-commits at lists.llvm.org
Sat Oct 24 15:24:52 PDT 2026
https://github.com/Prabhuk updated https://github.com/llvm/llvm-project/pull/235071
>From 35ad8fe1471ccb3fadca2639ab0c451cc81f317e Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Sat, 17 Oct 2026 00:55:43 -0700
Subject: [PATCH 1/2] [libc][uefi] Encode the error bit in EFI_STATUS error
codes
Set the high bit on the EFI_STATUS error macros and use them directly in
the errno translation table, so that error codes match the values
returned by UEFI firmware while warnings remain plain values. Map
unrecognized error statuses to EIO and unrecognized warnings to success.
Include the standard boolean header in the UEFI type definitions that
use bool, so that C translation units prior to C23 can include them.
---
.../llvm-libc-types/EFI_BOOT_SERVICES.h | 1 +
.../llvm-libc-types/EFI_RUNTIME_SERVICES.h | 1 +
.../EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h | 1 +
.../EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h | 1 +
libc/include/llvm-libc-types/EFI_STATUS.h | 72 ++++++------
libc/include/llvm-libc-types/EFI_TIME.h | 1 +
libc/src/__support/OSUtil/uefi/error.h | 110 ++++++++----------
7 files changed, 93 insertions(+), 94 deletions(-)
diff --git a/libc/include/llvm-libc-types/EFI_BOOT_SERVICES.h b/libc/include/llvm-libc-types/EFI_BOOT_SERVICES.h
index 8b7a6aadd7a24b..bd8afbb30db61d 100644
--- a/libc/include/llvm-libc-types/EFI_BOOT_SERVICES.h
+++ b/libc/include/llvm-libc-types/EFI_BOOT_SERVICES.h
@@ -26,6 +26,7 @@
#include "EFI_TPL.h"
#include "char16_t.h"
#include "size_t.h"
+#include <stdbool.h>
#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42
#define EFI_BOOT_SERVICES_REVISION EFI_SPECIFICATION_VERSION
diff --git a/libc/include/llvm-libc-types/EFI_RUNTIME_SERVICES.h b/libc/include/llvm-libc-types/EFI_RUNTIME_SERVICES.h
index 8913118b0844cf..8bf93aa73d16fd 100644
--- a/libc/include/llvm-libc-types/EFI_RUNTIME_SERVICES.h
+++ b/libc/include/llvm-libc-types/EFI_RUNTIME_SERVICES.h
@@ -19,6 +19,7 @@
#include "EFI_TIME.h"
#include "char16_t.h"
#include "size_t.h"
+#include <stdbool.h>
#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552
#define EFI_RUNTIME_SERVICES_REVISION EFI_SPECIFICATION_VERSION
diff --git a/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h b/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h
index a6dc0952b63101..dcbd9ef9482374 100644
--- a/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h
+++ b/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h
@@ -14,6 +14,7 @@
#include "EFI_EVENT.h"
#include "EFI_STATUS.h"
#include "char16_t.h"
+#include <stdbool.h>
#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \
{0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
diff --git a/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h b/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h
index 91d169f018dbc9..1c59d0af7de9da 100644
--- a/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h
+++ b/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h
@@ -13,6 +13,7 @@
#include "../llvm-libc-macros/stdint-macros.h"
#include "EFI_STATUS.h"
#include "size_t.h"
+#include <stdbool.h>
#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \
{0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
diff --git a/libc/include/llvm-libc-types/EFI_STATUS.h b/libc/include/llvm-libc-types/EFI_STATUS.h
index bb9542bed8efc7..e6906262fa3868 100644
--- a/libc/include/llvm-libc-types/EFI_STATUS.h
+++ b/libc/include/llvm-libc-types/EFI_STATUS.h
@@ -13,41 +13,47 @@
typedef uintptr_t EFI_STATUS;
+// Error codes have the highest bit of EFI_STATUS set, warning codes do not
+// (UEFI Specification, Appendix D "Status Codes").
+#define EFI_ERROR_BIT ((EFI_STATUS)1 << (8 * sizeof(EFI_STATUS) - 1))
+#define EFIERR(a) (EFI_ERROR_BIT | (EFI_STATUS)(a))
+#define EFI_ERROR(a) (((EFI_STATUS)(a) & EFI_ERROR_BIT) != 0)
+
#define EFI_SUCCESS 0
-#define EFI_LOAD_ERROR 1
-#define EFI_INVALID_PARAMETER 2
-#define EFI_UNSUPPORTED 3
-#define EFI_BAD_BUFFER_SIZE 4
-#define EFI_BUFFER_TOO_SMALL 5
-#define EFI_NOT_READY 6
-#define EFI_DEVICE_ERROR 7
-#define EFI_WRITE_PROTECTED 8
-#define EFI_OUT_OF_RESOURCES 9
-#define EFI_VOLUME_CORRUPTED 10
-#define EFI_VOLUME_FULL 11
-#define EFI_NO_MEDIA 12
-#define EFI_MEDIA_CHANGED 13
-#define EFI_NOT_FOUND 14
-#define EFI_ACCESS_DENIED 15
-#define EFI_NO_RESPONSE 16
-#define EFI_NO_MAPPING 17
-#define EFI_TIMEOUT 18
-#define EFI_NOT_STARTED 19
-#define EFI_ALREADY_STARTED 20
-#define EFI_ABORTED 21
-#define EFI_ICMP_ERROR 22
-#define EFI_TFTP_ERROR 23
-#define EFI_PROTOCOL_ERROR 24
-#define EFI_INCOMPATIBLE_VERSION 25
-#define EFI_SECURITY_VIOLATION 26
-#define EFI_CRC_ERROR 27
-#define EFI_END_OF_MEDIA 28
-#define EFI_END_OF_FILE 31
-#define EFI_INVALID_LANGUAGE 32
-#define EFI_COMPROMISED_DATA 33
-#define EFI_IP_ADDRESS_CONFLICT 34
-#define EFI_HTTP_ERROR 35
+#define EFI_LOAD_ERROR EFIERR(1)
+#define EFI_INVALID_PARAMETER EFIERR(2)
+#define EFI_UNSUPPORTED EFIERR(3)
+#define EFI_BAD_BUFFER_SIZE EFIERR(4)
+#define EFI_BUFFER_TOO_SMALL EFIERR(5)
+#define EFI_NOT_READY EFIERR(6)
+#define EFI_DEVICE_ERROR EFIERR(7)
+#define EFI_WRITE_PROTECTED EFIERR(8)
+#define EFI_OUT_OF_RESOURCES EFIERR(9)
+#define EFI_VOLUME_CORRUPTED EFIERR(10)
+#define EFI_VOLUME_FULL EFIERR(11)
+#define EFI_NO_MEDIA EFIERR(12)
+#define EFI_MEDIA_CHANGED EFIERR(13)
+#define EFI_NOT_FOUND EFIERR(14)
+#define EFI_ACCESS_DENIED EFIERR(15)
+#define EFI_NO_RESPONSE EFIERR(16)
+#define EFI_NO_MAPPING EFIERR(17)
+#define EFI_TIMEOUT EFIERR(18)
+#define EFI_NOT_STARTED EFIERR(19)
+#define EFI_ALREADY_STARTED EFIERR(20)
+#define EFI_ABORTED EFIERR(21)
+#define EFI_ICMP_ERROR EFIERR(22)
+#define EFI_TFTP_ERROR EFIERR(23)
+#define EFI_PROTOCOL_ERROR EFIERR(24)
+#define EFI_INCOMPATIBLE_VERSION EFIERR(25)
+#define EFI_SECURITY_VIOLATION EFIERR(26)
+#define EFI_CRC_ERROR EFIERR(27)
+#define EFI_END_OF_MEDIA EFIERR(28)
+#define EFI_END_OF_FILE EFIERR(31)
+#define EFI_INVALID_LANGUAGE EFIERR(32)
+#define EFI_COMPROMISED_DATA EFIERR(33)
+#define EFI_IP_ADDRESS_CONFLICT EFIERR(34)
+#define EFI_HTTP_ERROR EFIERR(35)
#define EFI_WARN_UNKNOWN_GLYPH 1
#define EFI_WARN_DELETE_FAILURE 2
diff --git a/libc/include/llvm-libc-types/EFI_TIME.h b/libc/include/llvm-libc-types/EFI_TIME.h
index b0e38b987d44ec..e5a428d5be18b4 100644
--- a/libc/include/llvm-libc-types/EFI_TIME.h
+++ b/libc/include/llvm-libc-types/EFI_TIME.h
@@ -10,6 +10,7 @@
#define LLVM_LIBC_TYPES_EFI_TIME_H
#include "../llvm-libc-macros/stdint-macros.h"
+#include <stdbool.h>
typedef struct {
uint16_t Year; // 1900 - 9999
diff --git a/libc/src/__support/OSUtil/uefi/error.h b/libc/src/__support/OSUtil/uefi/error.h
index 9fdc569bab5742..b22a3ce82f3c8a 100644
--- a/libc/src/__support/OSUtil/uefi/error.h
+++ b/libc/src/__support/OSUtil/uefi/error.h
@@ -1,4 +1,4 @@
-//===----------- UEFI implementation of error utils --------------*- C++-*-===//
+//===-- Definition of UEFI error utilities --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -12,88 +12,76 @@
#include "hdr/errno_macros.h"
#include "include/llvm-libc-types/EFI_STATUS.h"
#include "src/__support/CPP/array.h"
-#include "src/__support/CPP/limits.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
-static constexpr int EFI_ERROR_MAX_BIT = cpp::numeric_limits<EFI_STATUS>::max();
-
-static constexpr int EFI_ENCODE_ERROR(int value) {
- return EFI_ERROR_MAX_BIT | (EFI_ERROR_MAX_BIT >> 2) | (value);
-}
-
-static constexpr int EFI_ENCODE_WARNING(int value) {
- return (EFI_ERROR_MAX_BIT >> 2) | (value);
-}
-
struct UefiStatusErrnoEntry {
EFI_STATUS status;
int errno_value;
};
-static constexpr cpp::array<UefiStatusErrnoEntry, 43> UEFI_STATUS_ERRNO_MAP = {{
+// The EFI_* macros already carry the error bit as defined by the UEFI
+// specification; warnings are plain values.
+static constexpr cpp::array<UefiStatusErrnoEntry, 42> UEFI_STATUS_ERRNO_MAP = {{
{EFI_SUCCESS, 0},
- {EFI_ENCODE_ERROR(EFI_LOAD_ERROR), EINVAL},
- {EFI_ENCODE_ERROR(EFI_INVALID_PARAMETER), EINVAL},
- {EFI_ENCODE_ERROR(EFI_BAD_BUFFER_SIZE), EINVAL},
- {EFI_ENCODE_ERROR(EFI_NOT_READY), EBUSY},
- {EFI_ENCODE_ERROR(EFI_DEVICE_ERROR), EIO},
- {EFI_ENCODE_ERROR(EFI_WRITE_PROTECTED), EPERM},
- {EFI_ENCODE_ERROR(EFI_OUT_OF_RESOURCES), ENOMEM},
- {EFI_ENCODE_ERROR(EFI_VOLUME_CORRUPTED), EROFS},
- {EFI_ENCODE_ERROR(EFI_VOLUME_FULL), ENOSPC},
- {EFI_ENCODE_ERROR(EFI_NO_MEDIA), ENODEV},
- {EFI_ENCODE_ERROR(EFI_MEDIA_CHANGED), ENXIO},
- {EFI_ENCODE_ERROR(EFI_NOT_FOUND), ENOENT},
- {EFI_ENCODE_ERROR(EFI_ACCESS_DENIED), EACCES},
- {EFI_ENCODE_ERROR(EFI_NO_RESPONSE), EBUSY},
- {EFI_ENCODE_ERROR(EFI_NO_MAPPING), ENODEV},
- {EFI_ENCODE_ERROR(EFI_TIMEOUT), EBUSY},
- {EFI_ENCODE_ERROR(EFI_NOT_STARTED), EAGAIN},
- {EFI_ENCODE_ERROR(EFI_ALREADY_STARTED), EINVAL},
- {EFI_ENCODE_ERROR(EFI_ABORTED), EFAULT},
- {EFI_ENCODE_ERROR(EFI_ICMP_ERROR), EIO},
- {EFI_ENCODE_ERROR(EFI_TFTP_ERROR), EIO},
- {EFI_ENCODE_ERROR(EFI_PROTOCOL_ERROR), EINVAL},
- {EFI_ENCODE_ERROR(EFI_INCOMPATIBLE_VERSION), EINVAL},
- {EFI_ENCODE_ERROR(EFI_SECURITY_VIOLATION), EPERM},
- {EFI_ENCODE_ERROR(EFI_CRC_ERROR), EINVAL},
- {EFI_ENCODE_ERROR(EFI_END_OF_MEDIA), EPIPE},
- {EFI_ENCODE_ERROR(EFI_END_OF_FILE), EPIPE},
- {EFI_ENCODE_ERROR(EFI_INVALID_LANGUAGE), EINVAL},
- {EFI_ENCODE_ERROR(EFI_COMPROMISED_DATA), EINVAL},
- {EFI_ENCODE_ERROR(EFI_IP_ADDRESS_CONFLICT), EINVAL},
- {EFI_ENCODE_ERROR(EFI_HTTP_ERROR), EIO},
- {EFI_ENCODE_WARNING(EFI_WARN_UNKNOWN_GLYPH), EINVAL},
- {EFI_ENCODE_WARNING(EFI_WARN_DELETE_FAILURE), EROFS},
- {EFI_ENCODE_WARNING(EFI_WARN_WRITE_FAILURE), EROFS},
- {EFI_ENCODE_WARNING(EFI_WARN_BUFFER_TOO_SMALL), E2BIG},
- {EFI_ENCODE_WARNING(EFI_WARN_STALE_DATA), EINVAL},
- {EFI_ENCODE_WARNING(EFI_WARN_FILE_SYSTEM), EROFS},
- {EFI_ENCODE_WARNING(EFI_WARN_RESET_REQUIRED), EINTR},
+ {EFI_LOAD_ERROR, EINVAL},
+ {EFI_INVALID_PARAMETER, EINVAL},
+ {EFI_UNSUPPORTED, EINVAL},
+ {EFI_BAD_BUFFER_SIZE, EINVAL},
+ {EFI_BUFFER_TOO_SMALL, ERANGE},
+ {EFI_NOT_READY, EBUSY},
+ {EFI_DEVICE_ERROR, EIO},
+ {EFI_WRITE_PROTECTED, EPERM},
+ {EFI_OUT_OF_RESOURCES, ENOMEM},
+ {EFI_VOLUME_CORRUPTED, EROFS},
+ {EFI_VOLUME_FULL, ENOSPC},
+ {EFI_NO_MEDIA, ENODEV},
+ {EFI_MEDIA_CHANGED, ENXIO},
+ {EFI_NOT_FOUND, ENOENT},
+ {EFI_ACCESS_DENIED, EACCES},
+ {EFI_NO_RESPONSE, EBUSY},
+ {EFI_NO_MAPPING, ENODEV},
+ {EFI_TIMEOUT, EBUSY},
+ {EFI_NOT_STARTED, EAGAIN},
+ {EFI_ALREADY_STARTED, EINVAL},
+ {EFI_ABORTED, EFAULT},
+ {EFI_ICMP_ERROR, EIO},
+ {EFI_TFTP_ERROR, EIO},
+ {EFI_PROTOCOL_ERROR, EINVAL},
+ {EFI_INCOMPATIBLE_VERSION, EINVAL},
+ {EFI_SECURITY_VIOLATION, EPERM},
+ {EFI_CRC_ERROR, EINVAL},
+ {EFI_END_OF_MEDIA, EPIPE},
+ {EFI_END_OF_FILE, EPIPE},
+ {EFI_INVALID_LANGUAGE, EINVAL},
+ {EFI_COMPROMISED_DATA, EINVAL},
+ {EFI_IP_ADDRESS_CONFLICT, EINVAL},
+ {EFI_HTTP_ERROR, EIO},
+ {EFI_WARN_UNKNOWN_GLYPH, EINVAL},
+ {EFI_WARN_DELETE_FAILURE, EROFS},
+ {EFI_WARN_WRITE_FAILURE, EROFS},
+ {EFI_WARN_BUFFER_TOO_SMALL, E2BIG},
+ {EFI_WARN_STALE_DATA, EINVAL},
+ {EFI_WARN_FILE_SYSTEM, EROFS},
+ {EFI_WARN_RESET_REQUIRED, EINTR},
}};
LIBC_INLINE int uefi_status_to_errno(EFI_STATUS status) {
- for (auto it = UEFI_STATUS_ERRNO_MAP.begin();
- it != UEFI_STATUS_ERRNO_MAP.end(); it++) {
- const struct UefiStatusErrnoEntry entry = *it;
+ for (const UefiStatusErrnoEntry &entry : UEFI_STATUS_ERRNO_MAP)
if (entry.status == status)
return entry.errno_value;
- }
- // Unknown type
- return EINVAL;
+ // Unknown status; report it as an I/O error if it is an error code and as
+ // success otherwise, since warnings do not fail the operation.
+ return EFI_ERROR(status) ? EIO : 0;
}
LIBC_INLINE EFI_STATUS errno_to_uefi_status(int errno_value) {
- for (auto it = UEFI_STATUS_ERRNO_MAP.begin();
- it != UEFI_STATUS_ERRNO_MAP.end(); it++) {
- const struct UefiStatusErrnoEntry entry = *it;
+ for (const UefiStatusErrnoEntry &entry : UEFI_STATUS_ERRNO_MAP)
if (entry.errno_value == errno_value)
return entry.status;
- }
// Unknown type
return EFI_INVALID_PARAMETER;
>From 0f2842e7b4e109e358ea56510aff3e80d3c5dec0 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Sat, 24 Oct 2026 22:22:38 +0000
Subject: [PATCH 2/2] [libc][uefi] Test the UEFI status and errno conversions
Add a unit test for the EFI_STATUS error bit and both conversion
directions, and give the error utilities their own header target that the
test and the startup code depend on. Make the status map an inline
variable and the conversions constexpr, convert EINVAL back to
EFI_INVALID_PARAMETER, and declare the char16_t dependency of the text
output protocol.
---
libc/include/llvm-libc-types/CMakeLists.txt | 1 +
.../EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h | 1 +
libc/src/__support/OSUtil/uefi/CMakeLists.txt | 12 ++
libc/src/__support/OSUtil/uefi/error.h | 104 ++++++++++--------
libc/startup/uefi/CMakeLists.txt | 1 +
.../src/__support/OSUtil/uefi/CMakeLists.txt | 10 ++
.../src/__support/OSUtil/uefi/error_test.cpp | 76 +++++++++++++
7 files changed, 157 insertions(+), 48 deletions(-)
create mode 100644 libc/test/src/__support/OSUtil/uefi/CMakeLists.txt
create mode 100644 libc/test/src/__support/OSUtil/uefi/error_test.cpp
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 46a1a5bcfe6ee9..c6bf43b2210e7f 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -707,6 +707,7 @@ add_header(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
libc.include.llvm-libc-macros.EFIAPI_macros
libc.include.llvm-libc-macros.stdint_macros
.EFI_STATUS
+ .char16_t
.size_t
)
diff --git a/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h b/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h
index 1c59d0af7de9da..9b0fbebc75b2be 100644
--- a/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h
+++ b/libc/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h
@@ -12,6 +12,7 @@
#include "../llvm-libc-macros/EFIAPI-macros.h"
#include "../llvm-libc-macros/stdint-macros.h"
#include "EFI_STATUS.h"
+#include "char16_t.h"
#include "size_t.h"
#include <stdbool.h>
diff --git a/libc/src/__support/OSUtil/uefi/CMakeLists.txt b/libc/src/__support/OSUtil/uefi/CMakeLists.txt
index b8b785a6a0c283..d558ec93b28795 100644
--- a/libc/src/__support/OSUtil/uefi/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/uefi/CMakeLists.txt
@@ -1,3 +1,15 @@
+add_header_library(
+ uefi_error
+ HDRS
+ error.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.include.llvm-libc-types.EFI_STATUS
+ libc.src.__support.CPP.array
+ libc.src.__support.macros.attributes
+ libc.src.__support.macros.config
+)
+
add_object_library(
uefi_util
SRCS
diff --git a/libc/src/__support/OSUtil/uefi/error.h b/libc/src/__support/OSUtil/uefi/error.h
index b22a3ce82f3c8a..5ca5b6ab5b3907 100644
--- a/libc/src/__support/OSUtil/uefi/error.h
+++ b/libc/src/__support/OSUtil/uefi/error.h
@@ -1,10 +1,15 @@
-//===-- Definition of UEFI error utilities --------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// UEFI implementation of error utils.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_UEFI_ERROR_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_UEFI_ERROR_H
@@ -23,52 +28,55 @@ struct UefiStatusErrnoEntry {
};
// The EFI_* macros already carry the error bit as defined by the UEFI
-// specification; warnings are plain values.
-static constexpr cpp::array<UefiStatusErrnoEntry, 42> UEFI_STATUS_ERRNO_MAP = {{
- {EFI_SUCCESS, 0},
- {EFI_LOAD_ERROR, EINVAL},
- {EFI_INVALID_PARAMETER, EINVAL},
- {EFI_UNSUPPORTED, EINVAL},
- {EFI_BAD_BUFFER_SIZE, EINVAL},
- {EFI_BUFFER_TOO_SMALL, ERANGE},
- {EFI_NOT_READY, EBUSY},
- {EFI_DEVICE_ERROR, EIO},
- {EFI_WRITE_PROTECTED, EPERM},
- {EFI_OUT_OF_RESOURCES, ENOMEM},
- {EFI_VOLUME_CORRUPTED, EROFS},
- {EFI_VOLUME_FULL, ENOSPC},
- {EFI_NO_MEDIA, ENODEV},
- {EFI_MEDIA_CHANGED, ENXIO},
- {EFI_NOT_FOUND, ENOENT},
- {EFI_ACCESS_DENIED, EACCES},
- {EFI_NO_RESPONSE, EBUSY},
- {EFI_NO_MAPPING, ENODEV},
- {EFI_TIMEOUT, EBUSY},
- {EFI_NOT_STARTED, EAGAIN},
- {EFI_ALREADY_STARTED, EINVAL},
- {EFI_ABORTED, EFAULT},
- {EFI_ICMP_ERROR, EIO},
- {EFI_TFTP_ERROR, EIO},
- {EFI_PROTOCOL_ERROR, EINVAL},
- {EFI_INCOMPATIBLE_VERSION, EINVAL},
- {EFI_SECURITY_VIOLATION, EPERM},
- {EFI_CRC_ERROR, EINVAL},
- {EFI_END_OF_MEDIA, EPIPE},
- {EFI_END_OF_FILE, EPIPE},
- {EFI_INVALID_LANGUAGE, EINVAL},
- {EFI_COMPROMISED_DATA, EINVAL},
- {EFI_IP_ADDRESS_CONFLICT, EINVAL},
- {EFI_HTTP_ERROR, EIO},
- {EFI_WARN_UNKNOWN_GLYPH, EINVAL},
- {EFI_WARN_DELETE_FAILURE, EROFS},
- {EFI_WARN_WRITE_FAILURE, EROFS},
- {EFI_WARN_BUFFER_TOO_SMALL, E2BIG},
- {EFI_WARN_STALE_DATA, EINVAL},
- {EFI_WARN_FILE_SYSTEM, EROFS},
- {EFI_WARN_RESET_REQUIRED, EINTR},
-}};
+// specification; warnings are plain values. Several statuses share an errno
+// value, and errno_to_uefi_status returns the first entry that matches, so
+// the preferred status for each errno value must come first.
+LIBC_INLINE_VAR constexpr cpp::array<UefiStatusErrnoEntry, 41>
+ UEFI_STATUS_ERRNO_MAP = {{
+ {EFI_SUCCESS, 0},
+ {EFI_INVALID_PARAMETER, EINVAL},
+ {EFI_LOAD_ERROR, EINVAL},
+ {EFI_UNSUPPORTED, EINVAL},
+ {EFI_BAD_BUFFER_SIZE, EINVAL},
+ {EFI_BUFFER_TOO_SMALL, ERANGE},
+ {EFI_NOT_READY, EBUSY},
+ {EFI_DEVICE_ERROR, EIO},
+ {EFI_WRITE_PROTECTED, EPERM},
+ {EFI_OUT_OF_RESOURCES, ENOMEM},
+ {EFI_VOLUME_CORRUPTED, EROFS},
+ {EFI_VOLUME_FULL, ENOSPC},
+ {EFI_NO_MEDIA, ENODEV},
+ {EFI_MEDIA_CHANGED, ENXIO},
+ {EFI_NOT_FOUND, ENOENT},
+ {EFI_ACCESS_DENIED, EACCES},
+ {EFI_NO_RESPONSE, EBUSY},
+ {EFI_NO_MAPPING, ENODEV},
+ {EFI_TIMEOUT, EBUSY},
+ {EFI_NOT_STARTED, EAGAIN},
+ {EFI_ALREADY_STARTED, EINVAL},
+ {EFI_ABORTED, EFAULT},
+ {EFI_ICMP_ERROR, EIO},
+ {EFI_TFTP_ERROR, EIO},
+ {EFI_PROTOCOL_ERROR, EINVAL},
+ {EFI_INCOMPATIBLE_VERSION, EINVAL},
+ {EFI_SECURITY_VIOLATION, EPERM},
+ {EFI_CRC_ERROR, EINVAL},
+ {EFI_END_OF_MEDIA, EPIPE},
+ {EFI_END_OF_FILE, EPIPE},
+ {EFI_INVALID_LANGUAGE, EINVAL},
+ {EFI_COMPROMISED_DATA, EINVAL},
+ {EFI_IP_ADDRESS_CONFLICT, EINVAL},
+ {EFI_HTTP_ERROR, EIO},
+ {EFI_WARN_UNKNOWN_GLYPH, EINVAL},
+ {EFI_WARN_DELETE_FAILURE, EROFS},
+ {EFI_WARN_WRITE_FAILURE, EROFS},
+ {EFI_WARN_BUFFER_TOO_SMALL, E2BIG},
+ {EFI_WARN_STALE_DATA, EINVAL},
+ {EFI_WARN_FILE_SYSTEM, EROFS},
+ {EFI_WARN_RESET_REQUIRED, EINTR},
+ }};
-LIBC_INLINE int uefi_status_to_errno(EFI_STATUS status) {
+LIBC_INLINE constexpr int uefi_status_to_errno(EFI_STATUS status) {
for (const UefiStatusErrnoEntry &entry : UEFI_STATUS_ERRNO_MAP)
if (entry.status == status)
return entry.errno_value;
@@ -78,12 +86,12 @@ LIBC_INLINE int uefi_status_to_errno(EFI_STATUS status) {
return EFI_ERROR(status) ? EIO : 0;
}
-LIBC_INLINE EFI_STATUS errno_to_uefi_status(int errno_value) {
+LIBC_INLINE constexpr EFI_STATUS errno_to_uefi_status(int errno_value) {
for (const UefiStatusErrnoEntry &entry : UEFI_STATUS_ERRNO_MAP)
if (entry.errno_value == errno_value)
return entry.status;
- // Unknown type
+ // Unknown errno
return EFI_INVALID_PARAMETER;
}
diff --git a/libc/startup/uefi/CMakeLists.txt b/libc/startup/uefi/CMakeLists.txt
index 645d35a44029ff..c924e1c45a8fe7 100644
--- a/libc/startup/uefi/CMakeLists.txt
+++ b/libc/startup/uefi/CMakeLists.txt
@@ -35,6 +35,7 @@ add_startup_object(
crt1.cpp
DEPENDS
libc.config.app_h
+ libc.src.__support.OSUtil.uefi.uefi_error
libc.src.__support.OSUtil.uefi.uefi_util
)
diff --git a/libc/test/src/__support/OSUtil/uefi/CMakeLists.txt b/libc/test/src/__support/OSUtil/uefi/CMakeLists.txt
new file mode 100644
index 00000000000000..bb5d87caa7053d
--- /dev/null
+++ b/libc/test/src/__support/OSUtil/uefi/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_libc_test(
+ error_test
+ SUITE libc-osutil-tests
+ SRCS error_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.include.llvm-libc-types.EFI_STATUS
+ libc.src.__support.CPP.span
+ libc.src.__support.OSUtil.uefi.uefi_error
+)
diff --git a/libc/test/src/__support/OSUtil/uefi/error_test.cpp b/libc/test/src/__support/OSUtil/uefi/error_test.cpp
new file mode 100644
index 00000000000000..a8853ef82021d1
--- /dev/null
+++ b/libc/test/src/__support/OSUtil/uefi/error_test.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for UEFI status macros and errno conversion utilities.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "include/llvm-libc-types/EFI_STATUS.h"
+#include "src/__support/CPP/span.h"
+#include "src/__support/OSUtil/uefi/error.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcUefiErrorTest, StatusBitMacros) {
+ // Every entry after the leading EFI_SUCCESS one maps a failure.
+ const LIBC_NAMESPACE::cpp::span<const LIBC_NAMESPACE::UefiStatusErrnoEntry>
+ failures(LIBC_NAMESPACE::UEFI_STATUS_ERRNO_MAP.data() + 1,
+ LIBC_NAMESPACE::UEFI_STATUS_ERRNO_MAP.size() - 1);
+
+ EXPECT_FALSE(EFI_ERROR(EFI_SUCCESS));
+
+ for (const LIBC_NAMESPACE::UefiStatusErrnoEntry &entry : failures) {
+ EXPECT_NE(entry.status, static_cast<EFI_STATUS>(EFI_SUCCESS));
+ EXPECT_NE(entry.errno_value, 0);
+ }
+
+ EXPECT_TRUE(EFI_ERROR(EFI_LOAD_ERROR));
+ EXPECT_TRUE(EFI_ERROR(EFI_INVALID_PARAMETER));
+ EXPECT_TRUE(EFI_ERROR(EFI_UNSUPPORTED));
+ EXPECT_TRUE(EFI_ERROR(EFI_BUFFER_TOO_SMALL));
+ EXPECT_TRUE(EFI_ERROR(EFI_OUT_OF_RESOURCES));
+ EXPECT_TRUE(EFI_ERROR(EFI_NOT_FOUND));
+ EXPECT_TRUE(EFI_ERROR(EFI_ABORTED));
+ EXPECT_TRUE(EFI_ERROR(EFI_HTTP_ERROR));
+
+ EXPECT_FALSE(EFI_ERROR(EFI_WARN_UNKNOWN_GLYPH));
+ EXPECT_FALSE(EFI_ERROR(EFI_WARN_DELETE_FAILURE));
+ EXPECT_FALSE(EFI_ERROR(EFI_WARN_WRITE_FAILURE));
+ EXPECT_FALSE(EFI_ERROR(EFI_WARN_BUFFER_TOO_SMALL));
+ EXPECT_FALSE(EFI_ERROR(EFI_WARN_STALE_DATA));
+ EXPECT_FALSE(EFI_ERROR(EFI_WARN_FILE_SYSTEM));
+ EXPECT_FALSE(EFI_ERROR(EFI_WARN_RESET_REQUIRED));
+}
+
+TEST(LlvmLibcUefiErrorTest, StatusToErrno) {
+ using LIBC_NAMESPACE::uefi_status_to_errno;
+
+ EXPECT_EQ(uefi_status_to_errno(EFI_SUCCESS), 0);
+ EXPECT_EQ(uefi_status_to_errno(EFI_INVALID_PARAMETER), EINVAL);
+ EXPECT_EQ(uefi_status_to_errno(EFI_UNSUPPORTED), EINVAL);
+ EXPECT_EQ(uefi_status_to_errno(EFI_BUFFER_TOO_SMALL), ERANGE);
+ EXPECT_EQ(uefi_status_to_errno(EFI_OUT_OF_RESOURCES), ENOMEM);
+ EXPECT_EQ(uefi_status_to_errno(EFI_NOT_FOUND), ENOENT);
+ EXPECT_EQ(uefi_status_to_errno(EFI_WARN_BUFFER_TOO_SMALL), E2BIG);
+
+ // Unknown error status maps to EIO; unknown warning status maps to 0.
+ EXPECT_EQ(uefi_status_to_errno(EFIERR(999)), EIO);
+ EXPECT_EQ(uefi_status_to_errno(static_cast<EFI_STATUS>(999)), 0);
+}
+
+TEST(LlvmLibcUefiErrorTest, ErrnoToStatus) {
+ using LIBC_NAMESPACE::errno_to_uefi_status;
+
+ EXPECT_EQ(errno_to_uefi_status(0), static_cast<EFI_STATUS>(EFI_SUCCESS));
+ EXPECT_EQ(errno_to_uefi_status(EINVAL), EFI_INVALID_PARAMETER);
+ EXPECT_EQ(errno_to_uefi_status(ERANGE), EFI_BUFFER_TOO_SMALL);
+ EXPECT_EQ(errno_to_uefi_status(ENOMEM), EFI_OUT_OF_RESOURCES);
+ EXPECT_EQ(errno_to_uefi_status(ENOENT), EFI_NOT_FOUND);
+ EXPECT_EQ(errno_to_uefi_status(-1), EFI_INVALID_PARAMETER);
+}
More information about the libc-commits
mailing list