[libc-commits] [libc] 865fb9c - [libc][uefi] add crt1 (#132150)

via libc-commits libc-commits at lists.llvm.org
Fri May 9 09:02:36 PDT 2025


Author: Tristan Ross
Date: 2025-05-09T09:02:33-07:00
New Revision: 865fb9c1a50f8b836a8c9ee6f4d1cbe7cce59fc3

URL: https://github.com/llvm/llvm-project/commit/865fb9c1a50f8b836a8c9ee6f4d1cbe7cce59fc3
DIFF: https://github.com/llvm/llvm-project/commit/865fb9c1a50f8b836a8c9ee6f4d1cbe7cce59fc3.diff

LOG: [libc][uefi] add crt1 (#132150)

Adds `crt1.o` for the UEFI platform in the LLVM C library. This makes
things start to become useful.

Added: 
    libc/config/uefi/app.h
    libc/src/__support/OSUtil/uefi/error.h
    libc/startup/uefi/CMakeLists.txt
    libc/startup/uefi/crt1.cpp
    libc/test/integration/startup/uefi/CMakeLists.txt
    libc/test/integration/startup/uefi/main_without_args.cpp

Modified: 
    libc/config/app.h
    libc/include/CMakeLists.txt
    libc/include/Uefi.yaml
    libc/include/llvm-libc-types/CMakeLists.txt
    libc/include/llvm-libc-types/EFI_STATUS.h
    libc/src/__support/OSUtil/uefi/CMakeLists.txt
    libc/src/__support/OSUtil/uefi/exit.cpp
    libc/src/__support/OSUtil/uefi/io.cpp

Removed: 
    libc/include/Uefi.h.def


################################################################################
diff  --git a/libc/config/app.h b/libc/config/app.h
index 27f4141d80c4b..e9206c7242250 100644
--- a/libc/config/app.h
+++ b/libc/config/app.h
@@ -15,6 +15,8 @@
 #include "gpu/app.h"
 #elif defined(__linux__)
 #include "linux/app.h"
+#elif defined(__UEFI__)
+#include "uefi/app.h"
 #endif
 
 #endif // LLVM_LIBC_CONFIG_APP_H

diff  --git a/libc/config/uefi/app.h b/libc/config/uefi/app.h
new file mode 100644
index 0000000000000..0374a47ba3402
--- /dev/null
+++ b/libc/config/uefi/app.h
@@ -0,0 +1,34 @@
+//===-- Classes to capture properites of UEFI applications ------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_CONFIG_UEFI_APP_H
+#define LLVM_LIBC_CONFIG_UEFI_APP_H
+
+#include "include/llvm-libc-types/EFI_HANDLE.h"
+#include "include/llvm-libc-types/EFI_SYSTEM_TABLE.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
+
+#include <stdint.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Data structure which captures properties of a UEFI application.
+struct AppProperties {
+  // UEFI system table
+  EFI_SYSTEM_TABLE *system_table;
+
+  // UEFI image handle
+  EFI_HANDLE image_handle;
+};
+
+[[gnu::weak]] extern AppProperties app;
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_CONFIG_UEFI_APP_H

diff  --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index e407de2f16959..7209e10c68b8f 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -741,7 +741,6 @@ add_header_macro(
 add_header_macro(
   uefi
   ../libc/include/Uefi.yaml
-  Uefi.h.def
   Uefi.h
   DEPENDS
     .llvm_libc_common_h

diff  --git a/libc/include/Uefi.yaml b/libc/include/Uefi.yaml
index 9f38ff3f4a497..72b50ed724660 100644
--- a/libc/include/Uefi.yaml
+++ b/libc/include/Uefi.yaml
@@ -9,8 +9,4 @@ types:
   - type_name: EFI_SYSTEM_TABLE
 enums: []
 functions: []
-objects:
-  - object_name: efi_system_table
-    object_type: EFI_SYSTEM_TABLE *
-  - object_name: efi_image_handle
-    object_type: EFI_HANDLE
+objects: []

diff  --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 26a3ed06b6f05..b24c97301668a 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -186,7 +186,7 @@ add_header(EFI_HANDLE HDR EFI_HANDLE.h)
 add_header(EFI_TIME HDR EFI_TIME.h DEPENDS libc.include.llvm-libc-macros.stdint_macros)
 add_header(EFI_TIMER_DELAY HDR EFI_TIMER_DELAY.h)
 add_header(EFI_TPL HDR EFI_TPL.h DEPENDS .size_t)
-add_header(EFI_STATUS HDR EFI_STATUS.h DEPENDS .size_t)
+add_header(EFI_STATUS HDR EFI_STATUS.h DEPENDS libc.include.llvm-libc-macros.stdint_macros)
 
 add_header(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
   HDR

diff  --git a/libc/include/llvm-libc-types/EFI_STATUS.h b/libc/include/llvm-libc-types/EFI_STATUS.h
index f7fa6e52381e1..bb9542bed8efc 100644
--- a/libc/include/llvm-libc-types/EFI_STATUS.h
+++ b/libc/include/llvm-libc-types/EFI_STATUS.h
@@ -9,8 +9,52 @@
 #ifndef LLVM_LIBC_TYPES_EFI_STATUS_H
 #define LLVM_LIBC_TYPES_EFI_STATUS_H
 
-#include "size_t.h"
+#include "../llvm-libc-macros/stdint-macros.h"
 
-typedef size_t EFI_STATUS;
+typedef uintptr_t EFI_STATUS;
+
+#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_WARN_UNKNOWN_GLYPH 1
+#define EFI_WARN_DELETE_FAILURE 2
+#define EFI_WARN_WRITE_FAILURE 3
+#define EFI_WARN_BUFFER_TOO_SMALL 4
+#define EFI_WARN_STALE_DATA 5
+#define EFI_WARN_FILE_SYSTEM 6
+#define EFI_WARN_RESET_REQUIRED 7
 
 #endif // LLVM_LIBC_TYPES_EFI_STATUS_H

diff  --git a/libc/src/__support/OSUtil/uefi/CMakeLists.txt b/libc/src/__support/OSUtil/uefi/CMakeLists.txt
index 79ec8ab602456..b8b785a6a0c28 100644
--- a/libc/src/__support/OSUtil/uefi/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/uefi/CMakeLists.txt
@@ -6,6 +6,8 @@ add_object_library(
   HDRS
     io.h
   DEPENDS
+    libc.config.app_h
+    libc.include.llvm-libc-types.EFI_SYSTEM_TABLE
     libc.src.__support.common
     libc.src.__support.CPP.string_view
 )

diff  --git a/libc/src/__support/OSUtil/uefi/error.h b/libc/src/__support/OSUtil/uefi/error.h
new file mode 100644
index 0000000000000..9fdc569bab574
--- /dev/null
+++ b/libc/src/__support/OSUtil/uefi/error.h
@@ -0,0 +1,104 @@
+//===----------- UEFI implementation of error utils --------------*- C++-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_UEFI_ERROR_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_UEFI_ERROR_H
+
+#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 = {{
+    {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},
+}};
+
+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;
+    if (entry.status == status)
+      return entry.errno_value;
+  }
+
+  // Unknown type
+  return EINVAL;
+}
+
+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;
+    if (entry.errno_value == errno_value)
+      return entry.status;
+  }
+
+  // Unknown type
+  return EFI_INVALID_PARAMETER;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_UEFI_ERROR_H

diff  --git a/libc/src/__support/OSUtil/uefi/exit.cpp b/libc/src/__support/OSUtil/uefi/exit.cpp
index 432f69a306b79..e734983cd125b 100644
--- a/libc/src/__support/OSUtil/uefi/exit.cpp
+++ b/libc/src/__support/OSUtil/uefi/exit.cpp
@@ -7,14 +7,16 @@
 //===-----------------------------------------------------------------===//
 
 #include "src/__support/OSUtil/exit.h"
-#include "include/Uefi.h"
+#include "config/uefi.h"
+#include "include/llvm-libc-types/EFI_SYSTEM_TABLE.h"
 #include "src/__support/macros/config.h"
 
 namespace LIBC_NAMESPACE_DECL {
 namespace internal {
 
 [[noreturn]] void exit(int status) {
-  efi_system_table->BootServices->Exit(efi_image_handle, status, 0, nullptr);
+  app.system_table->BootServices->Exit(__llvm_libc_efi_image_handle, status, 0,
+                                       nullptr);
   __builtin_unreachable();
 }
 

diff  --git a/libc/src/__support/OSUtil/uefi/io.cpp b/libc/src/__support/OSUtil/uefi/io.cpp
index 756c5aaf8f452..e1e50fbad3931 100644
--- a/libc/src/__support/OSUtil/uefi/io.cpp
+++ b/libc/src/__support/OSUtil/uefi/io.cpp
@@ -8,19 +8,24 @@
 
 #include "io.h"
 
+#include "Uefi.h"
+#include "config/app.h"
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/macros/config.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-ssize_t read_from_stdin(char *buf, size_t size) { return 0; }
+ssize_t read_from_stdin([[gnu::unused]] char *buf,
+                        [[gnu::unused]] size_t size) {
+  return 0;
+}
 
 void write_to_stdout(cpp::string_view msg) {
   // TODO: use mbstowcs once implemented
   for (size_t i = 0; i < msg.size(); i++) {
     char16_t e[2] = {msg[i], 0};
-    efi_system_table->ConOut->OutputString(
-        efi_system_table->ConOut, reinterpret_cast<const char16_t *>(&e));
+    app.system_table->ConOut->OutputString(
+        app.system_table->ConOut, reinterpret_cast<const char16_t *>(&e));
   }
 }
 
@@ -28,8 +33,8 @@ void write_to_stderr(cpp::string_view msg) {
   // TODO: use mbstowcs once implemented
   for (size_t i = 0; i < msg.size(); i++) {
     char16_t e[2] = {msg[i], 0};
-    efi_system_table->StdErr->OutputString(
-        efi_system_table->StdErr, reinterpret_cast<const char16_t *>(&e));
+    app.system_table->StdErr->OutputString(
+        app.system_table->StdErr, reinterpret_cast<const char16_t *>(&e));
   }
 }
 

diff  --git a/libc/startup/uefi/CMakeLists.txt b/libc/startup/uefi/CMakeLists.txt
new file mode 100644
index 0000000000000..2e6a993e77e30
--- /dev/null
+++ b/libc/startup/uefi/CMakeLists.txt
@@ -0,0 +1,50 @@
+# TODO: Use generic "add_startup_object" https://github.com/llvm/llvm-project/issues/133156
+function(add_startup_object name)
+  cmake_parse_arguments(
+    "ADD_STARTUP_OBJECT"
+    "ALIAS" # Option argument
+    "SRC"   # Single value arguments
+    "DEPENDS;COMPILE_OPTIONS" # Multi value arguments
+    ${ARGN}
+  )
+
+  get_fq_target_name(${name} fq_target_name)
+  if(ADD_STARTUP_OBJECT_ALIAS)
+    get_fq_deps_list(fq_dep_list ${ADD_STARTUP_OBJECT_DEPENDS})
+    add_library(${fq_target_name} ALIAS ${fq_dep_list})
+    return()
+  endif()
+
+  add_object_library(
+    ${name}
+    SRCS ${ADD_STARTUP_OBJECT_SRC}
+    COMPILE_OPTIONS ${ADD_STARTUP_OBJECT_COMPILE_OPTIONS}
+    ${ADD_STARTUP_OBJECT_UNPARSED_ARGUMENTS}
+    DEPENDS ${ADD_STARTUP_OBJECT_DEPENDS}
+  )
+  set_target_properties(
+    ${fq_target_name}
+    PROPERTIES
+      OUTPUT_NAME ${name}.o
+  )
+endfunction()
+
+add_startup_object(
+  crt1
+  SRCS
+    crt1.cpp
+  DEPENDS
+    libc.config.app_h
+    libc.src.__support.OSUtil.uefi.uefi_util
+)
+
+add_custom_target(libc-startup)
+set(startup_components crt1)
+foreach(target IN LISTS startup_components)
+  set(fq_target_name libc.startup.uefi.${target})
+  add_dependencies(libc-startup ${fq_target_name})
+  install(FILES $<TARGET_OBJECTS:${fq_target_name}>
+          DESTINATION ${LIBC_INSTALL_LIBRARY_DIR}
+          RENAME $<TARGET_PROPERTY:${fq_target_name},OUTPUT_NAME>
+          COMPONENT libc)
+endforeach()

diff  --git a/libc/startup/uefi/crt1.cpp b/libc/startup/uefi/crt1.cpp
new file mode 100644
index 0000000000000..6883a88ff1c30
--- /dev/null
+++ b/libc/startup/uefi/crt1.cpp
@@ -0,0 +1,32 @@
+//===-- Implementation of crt for UEFI ------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "config/app.h"
+#include "include/llvm-libc-types/EFI_STATUS.h"
+#include "src/__support/OSUtil/uefi/error.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+AppProperties app;
+}
+
+extern "C" {
+EFI_HANDLE __llvm_libc_efi_image_handle;
+EFI_SYSTEM_TABLE *__llvm_libc_efi_system_table;
+
+int main(int argc, char **argv, char **envp);
+
+EFI_STATUS EfiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
+  LIBC_NAMESPACE::app.image_handle = ImageHandle;
+  LIBC_NAMESPACE::app.system_table = SystemTable;
+
+  // TODO: we need the EFI_SHELL_PROTOCOL, malloc, free, and UTF16 -> UTF8
+  // conversion.
+  return LIBC_NAMESPACE::errno_to_uefi_status(main(0, nullptr, nullptr));
+}
+}

diff  --git a/libc/test/integration/startup/uefi/CMakeLists.txt b/libc/test/integration/startup/uefi/CMakeLists.txt
new file mode 100644
index 0000000000000..cb43dcb31ddf8
--- /dev/null
+++ b/libc/test/integration/startup/uefi/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_custom_target(libc-startup-tests)
+add_dependencies(libc-integration-tests libc-startup-tests)
+
+add_integration_test(
+  startup_no_args_test
+  SUITE libc-startup-tests
+  SRCS
+    main_without_args.cpp
+)

diff  --git a/libc/include/Uefi.h.def b/libc/test/integration/startup/uefi/main_without_args.cpp
similarity index 58%
rename from libc/include/Uefi.h.def
rename to libc/test/integration/startup/uefi/main_without_args.cpp
index 6655e13579cd8..9bc3546aeb123 100644
--- a/libc/include/Uefi.h.def
+++ b/libc/test/integration/startup/uefi/main_without_args.cpp
@@ -1,4 +1,4 @@
-//===-- UEFI header uefi.h --------------------------------------------------===//
+//===-- Loader test for main without args ---------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,11 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_LIBC_UEFI_H
-#define LLVM_LIBC_UEFI_H
+#include "test/IntegrationTest/test.h"
 
-#include "__llvm-libc-common.h"
-
-%%public_api()
-
-#endif // LLVM_LIBC_UEFI_H
+TEST_MAIN() { return 0; }


        


More information about the libc-commits mailing list