Compare commits
3 Commits
84e37b572b
...
891a5551a2
Author | SHA1 | Date | |
---|---|---|---|
891a5551a2 | |||
f5a2b25e85 | |||
e11c3d5a03 |
33
.gitea/workflows/build.yml
Normal file
33
.gitea/workflows/build.yml
Normal file
@ -0,0 +1,33 @@
|
||||
name: 'CI'
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
# Jobs
|
||||
jobs:
|
||||
# Test Project
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch:
|
||||
- AMD64
|
||||
- ARM64
|
||||
name: Test
|
||||
runs-on: ${{ startsWith(matrix.arch, 'ARM') && 'raspberry-pi' || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
# Dependencies
|
||||
- name: Install Dependencies
|
||||
run: ./scripts/install-dependencies.sh
|
||||
# Build
|
||||
- name: Build
|
||||
run: ./example/build.sh
|
||||
# Test
|
||||
- name: Test (Pipe-Based)
|
||||
run: MCPI_USE_PIPE_TRAMPOLINE=1 ./example/run.sh
|
||||
- name: Test (Syscall-Based)
|
||||
run: ./example/run.sh
|
||||
if: ${{ ! startsWith(matrix.arch, 'ARM') }}
|
@ -19,8 +19,9 @@ add_executable(runtime
|
||||
)
|
||||
|
||||
# QEMU
|
||||
check_symbol_exists("__x86_64__" "" USE_QEMU)
|
||||
if(USE_QEMU)
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists("__ARM_ARCH" "" DONT_USE_QEMU)
|
||||
if(NOT DONT_USE_QEMU)
|
||||
add_subdirectory(qemu)
|
||||
target_sources(runtime PRIVATE
|
||||
src/syscall/main.cpp
|
||||
@ -39,9 +40,13 @@ target_link_libraries(runtime
|
||||
trampoline-headers
|
||||
)
|
||||
|
||||
# External Library
|
||||
set(TRAMPOLINE_LIBRARY_NAME "trampoline" CACHE STRING "Trampoline Library That The Runtime Uses")
|
||||
target_compile_definitions(runtime PRIVATE "TRAMPOLINE_LIBRARY=\"lib${TRAMPOLINE_LIBRARY_NAME}.so\"")
|
||||
|
||||
# Install
|
||||
if(DEFINED MCPI_BIN_DIR)
|
||||
install(TARGETS runtime DESTINATION "${MCPI_BIN_DIR}")
|
||||
if(DEFINED MCPI_LIB_DIR)
|
||||
install(TARGETS runtime DESTINATION "${MCPI_LIB_DIR}")
|
||||
# License
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" DESTINATION "${MCPI_LEGAL_DIR}/${PROJECT_NAME}")
|
||||
endif()
|
16
README.md
16
README.md
@ -1,28 +1,24 @@
|
||||
# Reborn Runtime
|
||||
This is a simple program allowing ARM32 code to easily call "native" code.
|
||||
|
||||
By running an ARM32 program inside this runtime, it gains the ability to call `raw_trampoline`. This function copies its arguments and passes them to the `trampoline` function inside `libmedia-layer-trampoline.so`.
|
||||
By running an ARM32 program inside this runtime, it gains the ability to call `raw_trampoline()`. This function copies its arguments and passes them to the "host" code.
|
||||
|
||||
The runtime also automatically uses QEMU on x86_64 systems.
|
||||
The runtime also automatically uses QEMU on non-ARM systems.
|
||||
|
||||
## Terminology
|
||||
- "Guest" code is the main ARM32 program.
|
||||
- "Host" code is the native code located in `libmedia-layer-trampoline.so`.
|
||||
- "Guest" code is the main ARM32 program. It is running inside the runtime.
|
||||
- "Host" code is the native code located in `libtrampoline.so`. It is running "alongside" the runtime.
|
||||
|
||||
## Example
|
||||
There is a simple C example [here](./example). It sends a given string to the host, which returns the string's length multiplied by two.
|
||||
There is a simple C example [here](./example).
|
||||
|
||||
## Early Returning
|
||||
`raw_trampoline` supports returning before the host code has finished executing. This can be enabled by passing `true` to `allow_early_return`. However, this is only supported in certain circumstances, can cause race-conditions, and prevents the guest code from receiving the host's return value.
|
||||
|
||||
## Syscall Versus Pipe Trampolines
|
||||
## Syscall Vs. Pipe Trampolines
|
||||
The runtime supports two methods of passing data between the guest and host.
|
||||
- System Call
|
||||
- Data is passed through a custom system-call added to QEMU.
|
||||
- Only supported on x86_64.
|
||||
- Pipes
|
||||
- Data is passed through standard UNIX pipes.
|
||||
- Supports early-returning.
|
||||
- Can be forced using an environmental variable.
|
||||
|
||||
## Licensing
|
||||
|
@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Run Script
|
||||
RUN="$(pwd)/run.sh"
|
||||
@ -10,33 +11,25 @@ out() {
|
||||
}
|
||||
out '#!/bin/sh'
|
||||
out 'set -e'
|
||||
out 'cd "$(dirname "$0")"'
|
||||
chmod +x "${RUN}"
|
||||
|
||||
# Create Build Directory
|
||||
rm -rf build
|
||||
dir() {
|
||||
mkdir "$1"
|
||||
mkdir -p "$1"
|
||||
cd "$1"
|
||||
}
|
||||
dir build
|
||||
|
||||
# Build Runtime
|
||||
dir runtime
|
||||
build() {
|
||||
cmake -GNinja "../../$1"
|
||||
cmake --build .
|
||||
}
|
||||
build ../
|
||||
out "export PATH=\"$(pwd):\${PATH}\""
|
||||
cd ../
|
||||
|
||||
# Build Host Component
|
||||
build_example_part() {
|
||||
dir "$1"
|
||||
build "$1"
|
||||
cmake -GNinja "../../$1"
|
||||
cmake --build .
|
||||
}
|
||||
build_example_part host
|
||||
out "export LD_LIBRARY_PATH=\"$(pwd):\${LD_LIBRARY_PATH}\""
|
||||
out "export PATH=\"$(pwd)/runtime:\${PATH}\""
|
||||
cd ../
|
||||
|
||||
# Build Guest Component
|
||||
|
@ -10,7 +10,7 @@ set(CMAKE_SYSTEM_PROCESSOR "arm")
|
||||
project(guest)
|
||||
|
||||
# Build Library
|
||||
add_subdirectory(../../lib lib)
|
||||
add_subdirectory(../../ runtime)
|
||||
|
||||
# Build
|
||||
add_executable(example src/example.c)
|
||||
|
@ -1,19 +1,30 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <trampoline/types.h>
|
||||
|
||||
// Call Trampoline With String
|
||||
void run(uint32_t cmd, const char *str) {
|
||||
// Arguments Must Be Modifiable
|
||||
unsigned char *args = (unsigned char *) strdup(str);
|
||||
// Sned Command
|
||||
unsigned char *args = (unsigned char *) str;
|
||||
// Send Command
|
||||
fprintf(stderr, "Guest Is Sending: %u: %s\n", cmd, str);
|
||||
uint32_t ret = raw_trampoline(cmd, 0, strlen(str) + 1, args);
|
||||
uint32_t ret;
|
||||
raw_trampoline(cmd, &ret, strlen(str) + 1, args);
|
||||
fprintf(stderr, "Guest Has Received: %u\n", ret);
|
||||
free(args);
|
||||
}
|
||||
|
||||
// Main
|
||||
#define INFO(str) fprintf(stderr, "==== %s ====\n", str)
|
||||
int main() {
|
||||
// Check Trampoline Type
|
||||
fprintf(stderr, "Using Pipe-Based Trampoline: %i\n", is_trampoline_pipe_based());
|
||||
// Normal Calls
|
||||
INFO("Testing Normal Trampoline Calls");
|
||||
run(0, "Hello World!");
|
||||
run(1, "Bye World!");
|
||||
// Calls without a return value *may* return control
|
||||
// to guest code before the call has finished.
|
||||
INFO("Testing Trampoline Call That May Return Early");
|
||||
raw_trampoline(100, NULL, 0, NULL);
|
||||
fprintf(stderr, "Control Returned To Guest\n");
|
||||
}
|
@ -4,8 +4,8 @@ cmake_minimum_required(VERSION 3.17.0)
|
||||
project(host)
|
||||
|
||||
# Build Library
|
||||
add_subdirectory(../../lib lib)
|
||||
add_subdirectory(../../ runtime)
|
||||
|
||||
# Build
|
||||
add_library(media-layer-trampoline SHARED src/trampoline.c)
|
||||
target_link_libraries(media-layer-trampoline trampoline-headers)
|
||||
add_library("${TRAMPOLINE_LIBRARY_NAME}" SHARED src/trampoline.c)
|
||||
target_link_libraries("${TRAMPOLINE_LIBRARY_NAME}" trampoline-headers)
|
@ -1,5 +1,6 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <trampoline/types.h>
|
||||
|
||||
@ -8,7 +9,16 @@
|
||||
// args: Pointer To Command Arguments
|
||||
// Return Value: Returned To The Guest (Unless Early Return Is Enabled)
|
||||
uint32_t trampoline(trampoline_writer_t writer, uint32_t id, const unsigned char *args) {
|
||||
const char *str = (const char *) args;
|
||||
fprintf(stderr, "Host Has Recieved: %u: %s\n", id, str);
|
||||
return strlen(str) * 2;
|
||||
if (id == 100 /* Defined In ../../guest/src/example.c */) {
|
||||
// Early Return Allowed
|
||||
fprintf(stderr, "Early Return Call Started\n");
|
||||
sleep(1);
|
||||
fprintf(stderr, "Early Return Call Done\n");
|
||||
return 0;
|
||||
} else {
|
||||
// Normal Call
|
||||
const char *str = (const char *) args;
|
||||
fprintf(stderr, "Host Has Received: %u: %s\n", id, str);
|
||||
return strlen(str) * 2;
|
||||
}
|
||||
}
|
@ -1,6 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.17.0)
|
||||
|
||||
# Start Project
|
||||
project(trampoline)
|
||||
|
||||
# Headers
|
||||
@ -16,5 +13,9 @@ if(NOT TRAMPOLINE_IS_GUEST)
|
||||
endif()
|
||||
|
||||
# Library To Call Trampoline
|
||||
add_library(trampoline OBJECT src/guest.cpp)
|
||||
add_library(trampoline OBJECT
|
||||
src/lib.cpp
|
||||
src/syscall.cpp
|
||||
src/pipe.cpp
|
||||
)
|
||||
target_link_libraries(trampoline trampoline-headers)
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// C++ Support
|
||||
#ifdef __cplusplus
|
||||
@ -30,15 +31,17 @@ typedef trampoline_raw_t *trampoline_t;
|
||||
#endif
|
||||
|
||||
// Environmental Variables
|
||||
#ifdef __cplusplus
|
||||
#define ENV(name, ...) constexpr const char *name##_ENV = #name;
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#define ENV(name, ...) static const char *name##_ENV = #name;
|
||||
#include "env-list.h"
|
||||
#undef ENV
|
||||
#endif
|
||||
#pragma GCC diagnostic pop
|
||||
#define is_trampoline_pipe_based() (getenv(MCPI_USE_PIPE_TRAMPOLINE_ENV) != NULL)
|
||||
|
||||
// Call Trampoline From Guest Code
|
||||
#ifndef MCPI_BUILD_RUNTIME
|
||||
uint32_t raw_trampoline(uint32_t id, int allow_early_return, uint32_t length, unsigned char *args);
|
||||
uint32_t raw_trampoline(uint32_t id, uint32_t *ret /* Can Be Null */, uint32_t length, const unsigned char *args);
|
||||
#endif
|
||||
|
||||
// C++
|
||||
|
@ -1,86 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#include <trampoline/types.h>
|
||||
|
||||
// Logging
|
||||
#define ERR(format, ...) \
|
||||
({ \
|
||||
fprintf(stderr, "TRAMPOLINE ERROR: " format "\n", ##__VA_ARGS__); \
|
||||
exit(EXIT_FAILURE); \
|
||||
})
|
||||
|
||||
// Syscall Method
|
||||
static uint32_t trampoline_syscall(const uint32_t id, unsigned char *args) {
|
||||
// Make Syscall
|
||||
const long ret = syscall(TRAMPOLINE_SYSCALL, id, args); // This Modifies Arguments
|
||||
if (ret == -1) {
|
||||
// Error
|
||||
ERR("System Call Error: %s", strerror(errno));
|
||||
}
|
||||
// Return
|
||||
return *(uint32_t *) args;
|
||||
}
|
||||
|
||||
// Pipe Method
|
||||
static int get_pipe(const char *env) {
|
||||
const char *value = getenv(env);
|
||||
if (value == nullptr) {
|
||||
ERR("Missing Variable: %s", env);
|
||||
}
|
||||
const std::string str = value;
|
||||
return std::stoi(str);
|
||||
}
|
||||
static uint32_t trampoline_pipe(const uint32_t id, const bool allow_early_return, const uint32_t length, const unsigned char *args) {
|
||||
// Get Pipes
|
||||
static int arguments_pipe = -1;
|
||||
static int return_value_pipe = -1;
|
||||
if (arguments_pipe == -1) {
|
||||
arguments_pipe = get_pipe(_MCPI_TRAMPOLINE_ARGUMENTS_ENV);
|
||||
return_value_pipe = get_pipe(_MCPI_TRAMPOLINE_RETURN_VALUE_ENV);
|
||||
}
|
||||
// Write Command
|
||||
const trampoline_pipe_arguments cmd = {
|
||||
.id = id,
|
||||
.allow_early_return = allow_early_return,
|
||||
.length = length
|
||||
};
|
||||
if (write(arguments_pipe, &cmd, sizeof(trampoline_pipe_arguments)) != sizeof(trampoline_pipe_arguments)) {
|
||||
ERR("Unable To Write Command");
|
||||
}
|
||||
// Write Arguments
|
||||
size_t position = 0;
|
||||
while (position < length) {
|
||||
const ssize_t ret = write(arguments_pipe, args + position, length - position);
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Write Arguments");
|
||||
} else {
|
||||
position += ret;
|
||||
}
|
||||
}
|
||||
if (allow_early_return) {
|
||||
return 0;
|
||||
}
|
||||
// Return
|
||||
uint32_t ret;
|
||||
if (read(return_value_pipe, &ret, sizeof(uint32_t)) != sizeof(uint32_t)) {
|
||||
ERR("Unable To Read Return Value");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Main Function
|
||||
uint32_t raw_trampoline(const uint32_t id, const int allow_early_return, const uint32_t length, unsigned char *args) {
|
||||
if (length > MAX_TRAMPOLINE_ARGS_SIZE) {
|
||||
ERR("Command Too Big");
|
||||
}
|
||||
// Configure Method
|
||||
static bool use_syscall = getenv(MCPI_USE_PIPE_TRAMPOLINE_ENV) == nullptr;
|
||||
// Use Correct Method
|
||||
if (use_syscall) {
|
||||
return trampoline_syscall(id, args);
|
||||
} else {
|
||||
return trampoline_pipe(id, allow_early_return, length, args);
|
||||
}
|
||||
}
|
22
lib/src/lib.cpp
Normal file
22
lib/src/lib.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "lib.h"
|
||||
|
||||
// Call
|
||||
static Trampoline::Error trampoline(const uint32_t id, uint32_t *ret, const uint32_t length, const unsigned char *args) {
|
||||
// Check Arguments Length
|
||||
if (length > MAX_TRAMPOLINE_ARGS_SIZE) {
|
||||
return Trampoline::Error::COMMAND_TOO_BIG;
|
||||
}
|
||||
// Configure Method
|
||||
static bool use_syscall = SyscallTrampoline::should_use();
|
||||
// Use Correct Method
|
||||
if (use_syscall) {
|
||||
static SyscallTrampoline syscall;
|
||||
return syscall.call(id, ret, length, args);
|
||||
} else {
|
||||
static PipeTrampoline pipe;
|
||||
return pipe.call(id, ret, length, args);
|
||||
}
|
||||
}
|
||||
uint32_t raw_trampoline(const uint32_t id, uint32_t *ret, const uint32_t length, const unsigned char *args) {
|
||||
return uint32_t(trampoline(id, ret, length, args));
|
||||
}
|
41
lib/src/lib.h
Normal file
41
lib/src/lib.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <trampoline/types.h>
|
||||
|
||||
// Common
|
||||
struct Trampoline {
|
||||
virtual ~Trampoline() = default;
|
||||
// Error Codes
|
||||
enum class Error : uint32_t {
|
||||
NONE = 0,
|
||||
// Generic
|
||||
COMMAND_TOO_BIG,
|
||||
// System Call
|
||||
SYSCALL,
|
||||
// Pipe
|
||||
MISSING_PIPE,
|
||||
INVALID_PIPE,
|
||||
PIPE_WRITE,
|
||||
PIPE_READ
|
||||
};
|
||||
// Call
|
||||
virtual Error call(uint32_t id, uint32_t *ret_ptr, uint32_t length, const unsigned char *args) = 0;
|
||||
};
|
||||
|
||||
// Syscall Method
|
||||
struct SyscallTrampoline final : Trampoline {
|
||||
static bool should_use();
|
||||
Error call(uint32_t id, uint32_t *ret_ptr, uint32_t length, const unsigned char *args) override;
|
||||
};
|
||||
|
||||
// Pipe Method
|
||||
struct PipeTrampoline final : Trampoline {
|
||||
PipeTrampoline();
|
||||
Error call(uint32_t id, uint32_t *ret_ptr, uint32_t length, const unsigned char *args) override;
|
||||
private:
|
||||
Error status;
|
||||
int arguments_pipe;
|
||||
int return_value_pipe;
|
||||
};
|
71
lib/src/pipe.cpp
Normal file
71
lib/src/pipe.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
// Load Pipes
|
||||
static std::variant<int, Trampoline::Error> get_pipe(const char *env) {
|
||||
const char *value = getenv(env);
|
||||
if (value == nullptr) {
|
||||
return Trampoline::Error::MISSING_PIPE;
|
||||
}
|
||||
try {
|
||||
const int val = std::stoi(value);
|
||||
if (val >= 0) {
|
||||
return val;
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
return Trampoline::Error::INVALID_PIPE;
|
||||
}
|
||||
#define set(var, env) \
|
||||
val = get_pipe(env); \
|
||||
if (std::holds_alternative<Error>(val)) { \
|
||||
status = std::get<Error>(val); \
|
||||
return; \
|
||||
} \
|
||||
var = std::get<int>(val)
|
||||
PipeTrampoline::PipeTrampoline() {
|
||||
std::variant<int, Error> val;
|
||||
set(arguments_pipe, _MCPI_TRAMPOLINE_ARGUMENTS_ENV);
|
||||
set(return_value_pipe, _MCPI_TRAMPOLINE_RETURN_VALUE_ENV);
|
||||
// Success
|
||||
status = Error::NONE;
|
||||
}
|
||||
#undef set
|
||||
|
||||
// Call
|
||||
Trampoline::Error PipeTrampoline::call(const uint32_t id, uint32_t *ret_ptr, const uint32_t length, const unsigned char *args) {
|
||||
// Check
|
||||
if (status != Error::NONE) {
|
||||
return status;
|
||||
}
|
||||
// Write Command
|
||||
const trampoline_pipe_arguments cmd = {
|
||||
.id = id,
|
||||
.allow_early_return = ret_ptr == nullptr,
|
||||
.length = length
|
||||
};
|
||||
if (write(arguments_pipe, &cmd, sizeof(trampoline_pipe_arguments)) != sizeof(trampoline_pipe_arguments)) {
|
||||
return Error::PIPE_WRITE;
|
||||
}
|
||||
// Write Arguments
|
||||
size_t position = 0;
|
||||
while (position < length) {
|
||||
const ssize_t ret = write(arguments_pipe, args + position, length - position);
|
||||
if (ret == -1) {
|
||||
return Error::PIPE_WRITE;
|
||||
} else {
|
||||
position += ret;
|
||||
}
|
||||
}
|
||||
// Return Value
|
||||
if (ret_ptr != nullptr && read(return_value_pipe, ret_ptr, sizeof(uint32_t)) != sizeof(uint32_t)) {
|
||||
return Error::PIPE_READ;
|
||||
}
|
||||
// Success
|
||||
return Error::NONE;
|
||||
}
|
14
lib/src/syscall.cpp
Normal file
14
lib/src/syscall.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include <unistd.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
// Check
|
||||
bool SyscallTrampoline::should_use() {
|
||||
return !is_trampoline_pipe_based();
|
||||
}
|
||||
|
||||
// Call
|
||||
Trampoline::Error SyscallTrampoline::call(const uint32_t id, uint32_t *ret_ptr, uint32_t length, const unsigned char *args) {
|
||||
return syscall(TRAMPOLINE_SYSCALL, id, ret_ptr, args) != 0 ? Error::SYSCALL : Error::NONE;
|
||||
}
|
@ -6,8 +6,8 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24.0)
|
||||
endif()
|
||||
|
||||
# Archive
|
||||
set(QEMU_ARCHIVE "qemu-9.2.0.tar.xz")
|
||||
set(QEMU_HASH "f859f0bc65e1f533d040bbe8c92bcfecee5af2c921a6687c652fb44d089bd894")
|
||||
set(QEMU_ARCHIVE "qemu-9.2.1.tar.xz")
|
||||
set(QEMU_HASH "b7b0782ead63a5373fdfe08e084d3949a9395ec196180286b841f78a464d169c")
|
||||
|
||||
# Library
|
||||
set(QEMU_LIBRARY "/lib/libqemu-arm.so")
|
||||
|
@ -13,7 +13,7 @@
|
||||
int, __to_dfd, const char *, __to_pathname, unsigned int, flag)
|
||||
#endif
|
||||
|
||||
+extern int trampoline_handle_syscall(int32_t num, uint32_t arg1, uint32_t arg2);
|
||||
+extern int trampoline_handle_syscall(int32_t num, uint32_t arg1, uint32_t arg2, uint32_t arg3);
|
||||
+
|
||||
/* 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
|
||||
@ -22,7 +22,7 @@
|
||||
#endif
|
||||
void *p;
|
||||
|
||||
+ if (trampoline_handle_syscall(num, arg1, arg2)) {
|
||||
+ if (trampoline_handle_syscall(num, arg1, arg2, arg3)) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
|
Binary file not shown.
13
scripts/install-dependencies.sh
Executable file
13
scripts/install-dependencies.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
cmake \
|
||||
ninja-build \
|
||||
gcc g++ \
|
||||
python3 \
|
||||
python3-venv \
|
||||
python3-tomli \
|
||||
libglib2.0-dev
|
@ -16,7 +16,7 @@ int main(int argc, char *argv[]) {
|
||||
// Create Implementation
|
||||
Implementation *impl = new PipeImplementation;
|
||||
#ifdef MCPI_HAS_QEMU
|
||||
if (getenv(MCPI_USE_PIPE_TRAMPOLINE_ENV) == nullptr) {
|
||||
if (!is_trampoline_pipe_based()) {
|
||||
delete impl;
|
||||
impl = new SyscallImplementation;
|
||||
}
|
||||
|
@ -7,6 +7,9 @@
|
||||
|
||||
// Access QEMU's Memory
|
||||
void *QEMU::guest_to_host(const uint32_t guest_addr) {
|
||||
if (guest_addr == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return (void *) (uintptr_t) (guest_addr + QEMU_GUEST_BASE);;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
// QEMU API
|
||||
extern "C" {
|
||||
// Called By Patched QEMU
|
||||
int trampoline_handle_syscall(int32_t num, uint32_t arg1, uint32_t arg2);
|
||||
int trampoline_handle_syscall(int32_t num, uint32_t arg1, uint32_t arg2, uint32_t arg3);
|
||||
// Main
|
||||
int qemu_main(int argc, char **argv, char **envp);
|
||||
}
|
||||
|
@ -4,18 +4,23 @@
|
||||
#include "main.h"
|
||||
|
||||
// Handle Syscall
|
||||
int trampoline_handle_syscall(const int32_t num, const uint32_t arg1, uint32_t arg2) {
|
||||
int trampoline_handle_syscall(const int32_t num, const uint32_t arg1, const uint32_t arg2, const uint32_t arg3) {
|
||||
// Check Syscall
|
||||
if (num != TRAMPOLINE_SYSCALL) {
|
||||
return 0;
|
||||
}
|
||||
// Run
|
||||
SyscallImplementation::instance->handle_syscall(arg1, arg2);
|
||||
SyscallImplementation::instance->handle_syscall(arg1, arg2, arg3);
|
||||
return 1;
|
||||
}
|
||||
void SyscallImplementation::handle_syscall(const uint32_t arg1, const uint32_t arg2) const {
|
||||
void SyscallImplementation::handle_syscall(const uint32_t arg1, const uint32_t arg2, const uint32_t arg3) const {
|
||||
// Get Arguments
|
||||
const uint32_t id = arg1;
|
||||
const unsigned char *args = (const unsigned char *) QEMU::guest_to_host(arg2);
|
||||
uint32_t *ret_ptr = (uint32_t *) QEMU::guest_to_host(arg2);
|
||||
const unsigned char *args = (const unsigned char *) QEMU::guest_to_host(arg3);
|
||||
// Call
|
||||
const uint32_t ret = trampoline(id, args);
|
||||
*(uint32_t *) args = ret;
|
||||
if (ret_ptr != nullptr) {
|
||||
*ret_ptr = ret;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,6 @@
|
||||
struct SyscallImplementation final : Implementation {
|
||||
int main(int argc, char *argv[]) override;
|
||||
void memory_writer(uint32_t guest_addr, const void *data, uint32_t size) const override;
|
||||
void handle_syscall(uint32_t arg1, uint32_t arg2) const;
|
||||
void handle_syscall(uint32_t arg1, uint32_t arg2, uint32_t arg3) const;
|
||||
static SyscallImplementation *instance;
|
||||
};
|
@ -20,11 +20,11 @@ uint32_t Trampoline::operator()(const uint32_t id, const unsigned char *args) co
|
||||
void Trampoline::init(const Implementation *impl) {
|
||||
stored_impl = impl;
|
||||
// Open Library
|
||||
void *handle = dlopen("libmedia-layer-trampoline.so", RTLD_NOW);
|
||||
void *handle = dlopen(TRAMPOLINE_LIBRARY, RTLD_NOW);
|
||||
if (handle != nullptr) {
|
||||
func = (trampoline_t) dlsym(handle, "trampoline");
|
||||
}
|
||||
if (func == nullptr) {
|
||||
ERR("Unable To Load Media Layer Trampoline: %s", dlerror());
|
||||
ERR("Unable To Trampoline: %s", dlerror());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user