diff --git a/CMakeLists.txt b/CMakeLists.txt index a41f182..6ad4b3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,23 @@ cmake_minimum_required(VERSION 3.17.0) # Start Project -project(native-trampoline) +project(trampoline) + +# Headers +add_library(trampoline-headers INTERFACE) +target_include_directories(trampoline-headers INTERFACE include) + +# Check Architecture +include(CheckSymbolExists) +check_symbol_exists("__aarch64__" "" USE_NATIVE_TRAMPOLINE) +check_symbol_exists("__x86_64__" "" USE_QEMU_TRAMPOLINE) # Build -add_executable(qemu-arm src/memory.cpp src/main.cpp src/trampoline.cpp src/ptrace.cpp) - -# Warnings -target_compile_options(qemu-arm PRIVATE -Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference) - -# Link -target_link_libraries(qemu-arm dl) \ No newline at end of file +if(USE_NATIVE_TRAMPOLINE) + add_subdirectory(native) +elseif(USE_QEMU_TRAMPOLINE) + add_subdirectory(qemu) + target_compile_definitions(trampoline-headers INTERFACE MCPI_USE_QEMU) +else() + message(FATAL_ERROR "Unsupported Architecture") +endif() \ No newline at end of file diff --git a/include/trampoline/types.h b/include/trampoline/types.h new file mode 100644 index 0000000..df4443c --- /dev/null +++ b/include/trampoline/types.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +// Constants +#define MAX_TRAMPOLINE_ARGS_SIZE 2097152 // 2 MiB +#define TRAMPOLINE_SYSCALL 0x1337 + +// Function Types +typedef void (*trampoline_writer_t)(uint32_t guest_addr, void *data, uint32_t size); +typedef uint32_t (*trampoline_t)(trampoline_writer_t writer, uint32_t id, const unsigned char *args); diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt new file mode 100644 index 0000000..0a36572 --- /dev/null +++ b/native/CMakeLists.txt @@ -0,0 +1,15 @@ +project(native-trampoline) + +# Build +add_executable(trampoline src/memory.cpp src/main.cpp src/trampoline.cpp src/ptrace.cpp) + +# Warnings +target_compile_options(trampoline PRIVATE -Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference) + +# Link +target_link_libraries(trampoline dl trampoline-headers) + +# Install +function(install_trampoline bin_dir) + install(TARGETS trampoline DESTINATION "${bin_dir}") +endfunction() diff --git a/src/log.h b/native/src/log.h similarity index 100% rename from src/log.h rename to native/src/log.h diff --git a/src/main.cpp b/native/src/main.cpp similarity index 100% rename from src/main.cpp rename to native/src/main.cpp diff --git a/src/memory.cpp b/native/src/memory.cpp similarity index 100% rename from src/memory.cpp rename to native/src/memory.cpp diff --git a/src/memory.h b/native/src/memory.h similarity index 100% rename from src/memory.h rename to native/src/memory.h diff --git a/src/ptrace.cpp b/native/src/ptrace.cpp similarity index 100% rename from src/ptrace.cpp rename to native/src/ptrace.cpp diff --git a/src/ptrace.h b/native/src/ptrace.h similarity index 100% rename from src/ptrace.h rename to native/src/ptrace.h diff --git a/src/trampoline.cpp b/native/src/trampoline.cpp similarity index 100% rename from src/trampoline.cpp rename to native/src/trampoline.cpp diff --git a/src/trampoline.h b/native/src/trampoline.h similarity index 70% rename from src/trampoline.h rename to native/src/trampoline.h index c8d66b3..44d2345 100644 --- a/src/trampoline.h +++ b/native/src/trampoline.h @@ -1,6 +1,6 @@ #pragma once -#include "../../minecraft-pi-reborn/media-layer/trampoline/src/common/types.h" +#include #define MAX_TRAMPOLINE_ARGS_SIZE 2097152 // See media-layer/trampoline/src/guest/guest.h uint32_t trampoline(uint32_t id, const unsigned char *args); diff --git a/qemu/CMakeLists.txt b/qemu/CMakeLists.txt new file mode 100644 index 0000000..94ad4b6 --- /dev/null +++ b/qemu/CMakeLists.txt @@ -0,0 +1,58 @@ +project(qemu) + +# Archive +if(NOT DEFINED TRAMPOLINE_QEMU_ARCHIVE) + message(FATAL_ERROR "Missing QEMU Archive") +endif() + +# Flatpak Support +set(QEMU_FLATPAK_PATCH "") +if(MCPI_IS_FLATPAK_BUILD) + set(QEMU_FLATPAK_PATCH "sed" "-i" "s/libdrm/libdrm-dis/g" "/meson.build") +endif() + +# Build +include(ExternalProject) +set(PKGCONFIG_ENV "") +if(DEFINED ENV{PKG_CONFIG_LIBDIR}) + set(PKGCONFIG_ENV "PKG_CONFIG_LIBDIR=$ENV{PKG_CONFIG_LIBDIR}") +endif() +set(EXTRA_C_FLAGS "-s -I${CMAKE_CURRENT_SOURCE_DIR}/../include") +ExternalProject_Add(qemu + URL "${TRAMPOLINE_QEMU_ARCHIVE}" + # Configure Build + CONFIGURE_COMMAND + "${CMAKE_COMMAND}" "-E" "env" + ${PKGCONFIG_ENV} + "CFLAGS=${EXTRA_C_FLAGS}" + "CXXFLAGS=${EXTRA_C_FLAGS}" + "/configure" + "--prefix=${CMAKE_INSTALL_PREFIX}" + "--cross-prefix=" + "--cc=${CMAKE_C_COMPILER}" + "--cxx=${CMAKE_CXX_COMPILER}" + "--extra-ldflags=-ldl -Wl,-rpath=$ORIGIN/../lib/native -Wl,--disable-new-dtags" + "--disable-debug-info" + "--target-list=arm-linux-user" + "--without-default-features" + USES_TERMINAL_CONFIGURE TRUE + # Build Command + BUILD_COMMAND "ninja" "qemu-arm" + BUILD_BYPRODUCTS "/qemu-arm" + USES_TERMINAL_BUILD TRUE + # Disable Install/Test Commands + INSTALL_COMMAND "" + TEST_COMMAND "" + # Patch Command + PATCH_COMMAND "patch" "-p1" "<" "${CMAKE_CURRENT_SOURCE_DIR}/src/trampoline.patch" + COMMAND ${QEMU_FLATPAK_PATCH} +) + +# Install +function(install_trampoline bin_dir legal_dir) + ExternalProject_Get_property(qemu BINARY_DIR) + install(PROGRAMS "${BINARY_DIR}/qemu-arm" DESTINATION "${bin_dir}/trampoline") + # License + ExternalProject_Get_property(qemu SOURCE_DIR) + install(FILES "${SOURCE_DIR}/COPYING" DESTINATION "${legal_dir}/qemu") +endfunction() \ No newline at end of file diff --git a/qemu/src/trampoline.patch b/qemu/src/trampoline.patch new file mode 100644 index 0000000..63b46e7 --- /dev/null +++ b/qemu/src/trampoline.patch @@ -0,0 +1,57 @@ +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -17,6 +17,8 @@ + * along with this program; if not, see . + */ + #define _ATFILE_SOURCE ++#include ++#include + #include "qemu/osdep.h" + #include "qemu/cutils.h" + #include "qemu/path.h" +@@ -9070,6 +9072,13 @@ _syscall5(int, sys_move_mount, int, __from_dfd, const char *, __from_pathname, + int, __to_dfd, const char *, __to_pathname, unsigned int, flag) + #endif + ++// g2h For Trampoline ++static CPUState *_trampoline_g2h_cpu = NULL; ++static void _trampoline_writer(uint32_t guest_addr, void *data, uint32_t size) { ++ void *out = g2h(_trampoline_g2h_cpu, guest_addr); ++ memcpy(out, data, size); ++} ++ + /* This is an internal helper for do_syscall so that it is easier + * to have a single return point, so that actions, such as logging + * of syscall results, can be performed. +@@ -9095,6 +9104,31 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, + void *p; + + switch(num) { ++ case TRAMPOLINE_SYSCALL: { ++ // Load Trampoline ++ static trampoline_t _trampoline = NULL; ++ if (_trampoline == NULL) { ++ // Open Library ++ void *_trampoline_handle = dlopen("libmedia-layer-trampoline.so", RTLD_NOW); ++ // Load Function ++ if (_trampoline_handle != NULL) { ++ _trampoline = dlsym(_trampoline_handle, "trampoline"); ++ } ++ } ++ if (_trampoline == NULL) { ++ // Failed To Load ++ qemu_log_mask(LOG_UNIMP, "Unable To Load Media Layer Trampoline: %s\n", dlerror()); ++ return -TARGET_ENOSYS; ++ } ++ // Call Trampoline ++ _trampoline_g2h_cpu = cpu; ++ uint32_t _trampoline_id = arg1; ++ __attribute__((unused)) uint32_t _trampoline_length = arg2; ++ const unsigned char *_trampoline_args = g2h(cpu, arg3); ++ uint32_t _trampoline_ret = _trampoline(_trampoline_writer, _trampoline_id, _trampoline_args); ++ *(uint32_t *) _trampoline_args = _trampoline_ret; ++ return 0; ++ } + case TARGET_NR_exit: + /* In old applications this may be used to implement _exit(2). + However in threaded applications it is used for thread termination,