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 + +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::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 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(&e)); + app.system_table->ConOut->OutputString( + app.system_table->ConOut, reinterpret_cast(&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(&e)); + app.system_table->StdErr->OutputString( + app.system_table->StdErr, reinterpret_cast(&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 $ + DESTINATION ${LIBC_INSTALL_LIBRARY_DIR} + RENAME $ + 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; }