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

Adds `crt1.o` for the UEFI platform in the LLVM C library. This makes
things start to become useful.
This commit is contained in:
Tristan Ross
2025-05-09 09:02:33 -07:00
committed by GitHub
parent 0077d4ca78
commit 865fb9c1a5
14 changed files with 298 additions and 24 deletions

View File

@@ -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

34
libc/config/uefi/app.h Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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: []

View File

@@ -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

View File

@@ -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

View File

@@ -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
)

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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));
}
}

View File

@@ -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()

View File

@@ -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));
}
}

View File

@@ -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
)

View File

@@ -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; }