Merge pull request #4888 from lioncash/unicorn-remove

core: Remove usage of unicorn
This commit is contained in:
bunnei 2020-11-06 22:39:05 -08:00 committed by GitHub
commit af477fb8c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 18 additions and 520 deletions

3
.gitmodules vendored
View file

@ -7,9 +7,6 @@
[submodule "dynarmic"] [submodule "dynarmic"]
path = externals/dynarmic path = externals/dynarmic
url = https://github.com/MerryMage/dynarmic.git url = https://github.com/MerryMage/dynarmic.git
[submodule "unicorn"]
path = externals/unicorn
url = https://github.com/yuzu-emu/unicorn
[submodule "soundtouch"] [submodule "soundtouch"]
path = externals/soundtouch path = externals/soundtouch
url = https://github.com/citra-emu/ext-soundtouch.git url = https://github.com/citra-emu/ext-soundtouch.git

View file

@ -4,16 +4,8 @@ cd /yuzu
# override Travis CI unreasonable ccache size # override Travis CI unreasonable ccache size
echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf" echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf"
# Dirty hack to trick unicorn makefile into believing we are in a MINGW system
mv /bin/uname /bin/uname1 && echo -e '#!/bin/sh\necho MINGW64' >> /bin/uname
chmod +x /bin/uname
# Dirty hack to trick unicorn makefile into believing we have cmd
echo '' >> /bin/cmd
chmod +x /bin/cmd
mkdir build && cd build mkdir build && cd build
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release
ninja ninja
# Clean up the dirty hacks # Clean up the dirty hacks

View file

@ -3,7 +3,7 @@
cd /yuzu cd /yuzu
mkdir build && cd build mkdir build && cd build
cmake .. -G Ninja -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON cmake .. -G Ninja -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
ninja ninja
ccache -s ccache -s

View file

@ -4,13 +4,12 @@ set -o pipefail
export MACOSX_DEPLOYMENT_TARGET=10.14 export MACOSX_DEPLOYMENT_TARGET=10.14
export Qt5_DIR=$(brew --prefix)/opt/qt5 export Qt5_DIR=$(brew --prefix)/opt/qt5
export UNICORNDIR=$(pwd)/externals/unicorn
export PATH="/usr/local/opt/ccache/libexec:$PATH" export PATH="/usr/local/opt/ccache/libexec:$PATH"
# TODO: Build using ninja instead of make # TODO: Build using ninja instead of make
mkdir build && cd build mkdir build && cd build
cmake --version cmake --version
cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON cmake .. -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
make -j4 make -j4
ccache -s ccache -s

View file

@ -18,8 +18,6 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "EN
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON)
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON) option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON)
@ -372,81 +370,6 @@ endif()
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
# If unicorn isn't found, msvc -> download bundled unicorn; everyone else -> build external
if (YUZU_USE_BUNDLED_UNICORN)
if (MSVC)
message(STATUS "unicorn not found, falling back to bundled")
# Detect toolchain and platform
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
set(UNICORN_VER "unicorn-yuzu")
else()
message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
endif()
if (DEFINED UNICORN_VER)
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
endif()
if (DEFINED UNICORN_VER)
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
endif()
set(UNICORN_FOUND YES)
set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/lib/x64/unicorn_dynload.lib" CACHE PATH "Path to Unicorn library" FORCE)
set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/lib/x64/" CACHE PATH "Path to unicorn.dll" FORCE)
else()
message(STATUS "unicorn not found, falling back to externals")
if (MINGW)
set(UNICORN_LIB_NAME "unicorn.a")
else()
set(UNICORN_LIB_NAME "libunicorn.a")
endif()
set(UNICORN_FOUND YES)
set(UNICORN_PREFIX ${PROJECT_SOURCE_DIR}/externals/unicorn)
set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/${UNICORN_LIB_NAME}" CACHE PATH "Path to Unicorn library" FORCE)
set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/" CACHE PATH "Path to unicorn dynamic library" FORCE)
find_package(PythonInterp 2.7 REQUIRED)
if (MINGW)
# Intentionally call the unicorn makefile directly instead of using make.sh so that we can override the
# UNAME_S makefile variable to MINGW. This way we don't have to hack at the uname binary to build
# Additionally, overriding DO_WINDOWS_EXPORT prevents unicorn from patching the static unicorn.a by using msvc and cmd,
# which are both things we don't have in a mingw cross compiling environment.
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-gcc-ar RANLIB=x86_64-w64-mingw32-gcc-ranlib make UNAME_S=MINGW DO_WINDOWS_EXPORT=0
WORKING_DIRECTORY ${UNICORN_PREFIX}
)
else()
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no
WORKING_DIRECTORY ${UNICORN_PREFIX}
)
endif()
# ALL makes this custom target build every time
# but it won't actually build if LIBUNICORN_LIBRARY is up to date
add_custom_target(unicorn-build ALL
DEPENDS ${LIBUNICORN_LIBRARY}
)
unset(UNICORN_LIB_NAME)
endif()
else()
find_package(Unicorn REQUIRED)
endif()
if (UNICORN_FOUND)
add_library(unicorn INTERFACE)
add_dependencies(unicorn unicorn-build)
target_link_libraries(unicorn INTERFACE "${LIBUNICORN_LIBRARY}")
target_include_directories(unicorn INTERFACE "${LIBUNICORN_INCLUDE_DIR}")
else()
message(FATAL_ERROR "Could not find or build unicorn which is required.")
endif()
# Platform-specific library requirements # Platform-specific library requirements
# ====================================== # ======================================

View file

@ -1,9 +0,0 @@
function(copy_yuzu_unicorn_deps target_dir)
include(WindowsCopyFiles)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
windows_copy_files(${target_dir} ${UNICORN_DLL_DIR} ${DLL_DEST}
libgcc_s_seh-1.dll
libwinpthread-1.dll
unicorn.dll
)
endfunction(copy_yuzu_unicorn_deps)

1
externals/unicorn vendored

@ -1 +0,0 @@
Subproject commit 73f45735354396766a4bfb26d0b96b06e5cf31b2

View file

@ -13,8 +13,6 @@ add_library(core STATIC
arm/dynarmic/arm_exclusive_monitor.h arm/dynarmic/arm_exclusive_monitor.h
arm/exclusive_monitor.cpp arm/exclusive_monitor.cpp
arm/exclusive_monitor.h arm/exclusive_monitor.h
arm/unicorn/arm_unicorn.cpp
arm/unicorn/arm_unicorn.h
constants.cpp constants.cpp
constants.h constants.h
core.cpp core.cpp
@ -646,7 +644,7 @@ endif()
create_target_directory_groups(core) create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus unicorn zip) target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip)
if (YUZU_ENABLE_BOXCAT) if (YUZU_ENABLE_BOXCAT)
target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT) target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)

View file

@ -7,6 +7,7 @@
#include <dynarmic/A32/a32.h> #include <dynarmic/A32/a32.h>
#include <dynarmic/A32/config.h> #include <dynarmic/A32/config.h>
#include <dynarmic/A32/context.h> #include <dynarmic/A32/context.h>
#include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/page_table.h" #include "common/page_table.h"
#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/cpu_interrupt_handler.h"

View file

@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include <dynarmic/A64/a64.h> #include <dynarmic/A64/a64.h>
#include <dynarmic/A64/config.h> #include <dynarmic/A64/config.h>
#include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/page_table.h" #include "common/page_table.h"
#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/cpu_interrupt_handler.h"
@ -13,7 +14,6 @@
#include "core/arm/dynarmic/arm_exclusive_monitor.h" #include "core/arm/dynarmic/arm_exclusive_monitor.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/gdbstub/gdbstub.h" #include "core/gdbstub/gdbstub.h"
#include "core/hardware_properties.h" #include "core/hardware_properties.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
@ -82,16 +82,9 @@ public:
} }
void InterpreterFallback(u64 pc, std::size_t num_instructions) override { void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, LOG_ERROR(Core_ARM,
num_instructions, MemoryReadCode(pc)); "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, MemoryReadCode(pc));
ARM_Interface::ThreadContext64 ctx;
parent.SaveContext(ctx);
parent.inner_unicorn.LoadContext(ctx);
parent.inner_unicorn.ExecuteInstructions(num_instructions);
parent.inner_unicorn.SaveContext(ctx);
parent.LoadContext(ctx);
num_interpreted_instructions += num_instructions;
} }
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
@ -127,18 +120,17 @@ public:
if (parent.uses_wall_clock) { if (parent.uses_wall_clock) {
return; return;
} }
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
// rough approximation of the amount of executed ticks in the system, it may be thrown off // rough approximation of the amount of executed ticks in the system, it may be thrown off
// if not all cores are doing a similar amount of work. Instead of doing this, we should // if not all cores are doing a similar amount of work. Instead of doing this, we should
// device a way so that timing is consistent across all cores without increasing the ticks 4 // device a way so that timing is consistent across all cores without increasing the ticks 4
// times. // times.
u64 amortized_ticks = u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
(ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
// Always execute at least one tick. // Always execute at least one tick.
amortized_ticks = std::max<u64>(amortized_ticks, 1); amortized_ticks = std::max<u64>(amortized_ticks, 1);
parent.system.CoreTiming().AddTicks(amortized_ticks); parent.system.CoreTiming().AddTicks(amortized_ticks);
num_interpreted_instructions = 0;
} }
u64 GetTicksRemaining() override { u64 GetTicksRemaining() override {
@ -156,7 +148,6 @@ public:
} }
ARM_Dynarmic_64& parent; ARM_Dynarmic_64& parent;
std::size_t num_interpreted_instructions = 0;
u64 tpidrro_el0 = 0; u64 tpidrro_el0 = 0;
u64 tpidr_el0 = 0; u64 tpidr_el0 = 0;
static constexpr u64 minimum_run_cycles = 1000U; static constexpr u64 minimum_run_cycles = 1000U;
@ -248,12 +239,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index) std::size_t core_index)
: ARM_Interface{system, interrupt_handlers, uses_wall_clock}, : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handlers, cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
uses_wall_clock, exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
ARM_Unicorn::Arch::AArch64,
core_index},
core_index{core_index}, exclusive_monitor{
dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;

View file

@ -12,7 +12,6 @@
#include "common/hash.h" #include "common/hash.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/arm/exclusive_monitor.h" #include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
namespace Core::Memory { namespace Core::Memory {
class Memory; class Memory;
@ -71,7 +70,6 @@ private:
std::unique_ptr<DynarmicCallbacks64> cb; std::unique_ptr<DynarmicCallbacks64> cb;
JitCacheType jit_cache; JitCacheType jit_cache;
std::shared_ptr<Dynarmic::A64::Jit> jit; std::shared_ptr<Dynarmic::A64::Jit> jit;
ARM_Unicorn inner_unicorn;
std::size_t core_index; std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor; DynarmicExclusiveMonitor& exclusive_monitor;

View file

@ -1,295 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <unicorn/arm64.h>
#include "common/assert.h"
#include "common/microprofile.h"
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
namespace Core {
// Load Unicorn DLL once on Windows using RAII
#ifdef _MSC_VER
#include <unicorn_dynload.h>
struct LoadDll {
private:
LoadDll() {
ASSERT(uc_dyn_load(NULL, 0));
}
~LoadDll() {
ASSERT(uc_dyn_free());
}
static LoadDll g_load_dll;
};
LoadDll LoadDll::g_load_dll;
#endif
#define CHECKED(expr) \
do { \
if (auto _cerr = (expr)) { \
ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", _cerr, \
uc_strerror(_cerr)); \
} \
} while (0)
static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
GDBStub::BreakpointAddress bkpt =
GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute);
if (GDBStub::IsMemoryBreak() ||
(bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) {
auto core = static_cast<ARM_Unicorn*>(user_data);
core->RecordBreak(bkpt);
uc_emu_stop(uc);
}
}
static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
void* user_data) {
auto* const system = static_cast<System*>(user_data);
ARM_Interface::ThreadContext64 ctx{};
system->CurrentArmInterface().SaveContext(ctx);
ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr,
ctx.pc, ctx.cpu_registers[30]);
return false;
}
ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
Arch architecture, std::size_t core_index)
: ARM_Interface{system, interrupt_handlers, uses_wall_clock}, core_index{core_index} {
const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64;
CHECKED(uc_open(arch, UC_MODE_ARM, &uc));
auto fpv = 3 << 20;
CHECKED(uc_reg_write(uc, UC_ARM64_REG_CPACR_EL1, &fpv));
uc_hook hook{};
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, UINT64_MAX));
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0,
UINT64_MAX));
if (GDBStub::IsServerEnabled()) {
CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, UINT64_MAX));
last_bkpt_hit = false;
}
}
ARM_Unicorn::~ARM_Unicorn() {
CHECKED(uc_close(uc));
}
void ARM_Unicorn::SetPC(u64 pc) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
}
u64 ARM_Unicorn::GetPC() const {
u64 val{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &val));
return val;
}
u64 ARM_Unicorn::GetReg(int regn) const {
u64 val{};
auto treg = UC_ARM64_REG_SP;
if (regn <= 28) {
treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
} else if (regn < 31) {
treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
}
CHECKED(uc_reg_read(uc, treg, &val));
return val;
}
void ARM_Unicorn::SetReg(int regn, u64 val) {
auto treg = UC_ARM64_REG_SP;
if (regn <= 28) {
treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
} else if (regn < 31) {
treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
}
CHECKED(uc_reg_write(uc, treg, &val));
}
u128 ARM_Unicorn::GetVectorReg(int /*index*/) const {
UNIMPLEMENTED();
static constexpr u128 res{};
return res;
}
void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) {
UNIMPLEMENTED();
}
u32 ARM_Unicorn::GetPSTATE() const {
u64 nzcv{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv));
return static_cast<u32>(nzcv);
}
void ARM_Unicorn::SetPSTATE(u32 pstate) {
u64 nzcv = pstate;
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv));
}
VAddr ARM_Unicorn::GetTlsAddress() const {
u64 base{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
return base;
}
void ARM_Unicorn::SetTlsAddress(VAddr base) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
}
u64 ARM_Unicorn::GetTPIDR_EL0() const {
u64 value{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value));
return value;
}
void ARM_Unicorn::SetTPIDR_EL0(u64 value) {
CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value));
}
void ARM_Unicorn::ChangeProcessorID(std::size_t new_core_id) {
core_index = new_core_id;
}
void ARM_Unicorn::Run() {
if (GDBStub::IsServerEnabled()) {
ExecuteInstructions(std::max(4000000U, 0U));
} else {
while (true) {
if (interrupt_handlers[core_index].IsInterrupted()) {
return;
}
ExecuteInstructions(10);
}
}
}
void ARM_Unicorn::Step() {
ExecuteInstructions(1);
}
MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) {
MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
// Temporarily map the code page for Unicorn
u64 map_addr{GetPC() & ~Memory::PAGE_MASK};
std::vector<u8> page_buffer(Memory::PAGE_SIZE);
system.Memory().ReadBlock(map_addr, page_buffer.data(), page_buffer.size());
CHECKED(uc_mem_map_ptr(uc, map_addr, page_buffer.size(),
UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, page_buffer.data()));
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
CHECKED(uc_mem_unmap(uc, map_addr, page_buffer.size()));
if (GDBStub::IsServerEnabled()) {
if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
}
Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread();
SaveContext(thread->GetContext64());
if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
last_bkpt_hit = false;
GDBStub::Break();
GDBStub::SendTrap(thread, 5);
}
}
}
void ARM_Unicorn::SaveContext(ThreadContext64& ctx) {
int uregs[32];
void* tregs[32];
CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp));
CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc));
CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
for (auto i = 0; i < 29; ++i) {
uregs[i] = UC_ARM64_REG_X0 + i;
tregs[i] = &ctx.cpu_registers[i];
}
uregs[29] = UC_ARM64_REG_X29;
tregs[29] = (void*)&ctx.cpu_registers[29];
uregs[30] = UC_ARM64_REG_X30;
tregs[30] = (void*)&ctx.cpu_registers[30];
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 31));
for (int i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
tregs[i] = &ctx.vector_registers[i];
}
CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
}
void ARM_Unicorn::LoadContext(const ThreadContext64& ctx) {
int uregs[32];
void* tregs[32];
CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp));
CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc));
CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
for (int i = 0; i < 29; ++i) {
uregs[i] = UC_ARM64_REG_X0 + i;
tregs[i] = (void*)&ctx.cpu_registers[i];
}
uregs[29] = UC_ARM64_REG_X29;
tregs[29] = (void*)&ctx.cpu_registers[29];
uregs[30] = UC_ARM64_REG_X30;
tregs[30] = (void*)&ctx.cpu_registers[30];
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 31));
for (auto i = 0; i < 32; ++i) {
uregs[i] = UC_ARM64_REG_Q0 + i;
tregs[i] = (void*)&ctx.vector_registers[i];
}
CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32));
}
void ARM_Unicorn::PrepareReschedule() {
CHECKED(uc_emu_stop(uc));
}
void ARM_Unicorn::ClearExclusiveState() {}
void ARM_Unicorn::ClearInstructionCache() {}
void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
last_bkpt = bkpt;
last_bkpt_hit = true;
}
void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
u32 esr{};
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
const auto ec = esr >> 26;
const auto iss = esr & 0xFFFFFF;
auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
switch (ec) {
case 0x15: // SVC
Kernel::Svc::Call(arm_instance->system, iss);
break;
}
}
} // namespace Core

View file

@ -1,63 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <unicorn/unicorn.h>
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/gdbstub/gdbstub.h"
namespace Core {
class System;
class ARM_Unicorn final : public ARM_Interface {
public:
enum class Arch {
AArch32, // 32-bit ARM
AArch64, // 64-bit ARM
};
explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
Arch architecture, std::size_t core_index);
~ARM_Unicorn() override;
void SetPC(u64 pc) override;
u64 GetPC() const override;
u64 GetReg(int index) const override;
void SetReg(int index, u64 value) override;
u128 GetVectorReg(int index) const override;
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
void ChangeProcessorID(std::size_t new_core_id) override;
void PrepareReschedule() override;
void ClearExclusiveState() override;
void ExecuteInstructions(std::size_t num_instructions);
void Run() override;
void Step() override;
void ClearInstructionCache() override;
void PageTableChanged(Common::PageTable&, std::size_t) override {}
void RecordBreak(GDBStub::BreakpointAddress bkpt);
void SaveContext(ThreadContext32& ctx) override {}
void SaveContext(ThreadContext64& ctx) override;
void LoadContext(const ThreadContext32& ctx) override {}
void LoadContext(const ThreadContext64& ctx) override;
private:
static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
uc_engine* uc{};
GDBStub::BreakpointAddress last_bkpt{};
bool last_bkpt_hit = false;
std::size_t core_index;
};
} // namespace Core

View file

@ -2,30 +2,18 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/spin_lock.h" #include "common/spin_lock.h"
#include "core/arm/arm_interface.h"
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic_32.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
#endif
#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
namespace Kernel { namespace Kernel {
PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler,
Core::CPUInterruptHandler& interrupt_handler) Core::CPUInterruptHandler& interrupt_handler)
: interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} { : interrupt_handler{interrupt_handler},
core_index{id}, scheduler{scheduler}, guard{std::make_unique<Common::SpinLock>()} {}
guard = std::make_unique<Common::SpinLock>();
}
PhysicalCore::~PhysicalCore() = default; PhysicalCore::~PhysicalCore() = default;

View file

@ -13,7 +13,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/thread_queue_list.h" #include "common/thread_queue_list.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h" #include "core/core.h"
#include "core/cpu_manager.h" #include "core/cpu_manager.h"
#include "core/hardware_properties.h" #include "core/hardware_properties.h"
@ -217,8 +216,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
} else { } else {
thread->tls_address = 0; thread->tls_address = 0;
} }
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
thread->arm_interface.reset(); thread->arm_interface.reset();
if ((type_flags & THREADTYPE_HLE) == 0) { if ((type_flags & THREADTYPE_HLE) == 0) {
#ifdef ARCHITECTURE_x86_64 #ifdef ARCHITECTURE_x86_64
@ -231,19 +229,10 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(),
processor_id); processor_id);
} }
#else #else
if (owner_process && !owner_process->Is64BitProcess()) { #error Platform not supported yet.
thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32,
processor_id);
} else {
thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64,
processor_id);
}
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif #endif
ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top), ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
static_cast<u32>(entry_point), static_cast<u32>(arg)); static_cast<u32>(entry_point), static_cast<u32>(arg));
ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);

View file

@ -264,11 +264,9 @@ endif()
if (MSVC) if (MSVC)
include(CopyYuzuQt5Deps) include(CopyYuzuQt5Deps)
include(CopyYuzuSDLDeps) include(CopyYuzuSDLDeps)
include(CopyYuzuUnicornDeps)
include(CopyYuzuFFmpegDeps) include(CopyYuzuFFmpegDeps)
copy_yuzu_Qt5_deps(yuzu) copy_yuzu_Qt5_deps(yuzu)
copy_yuzu_SDL_deps(yuzu) copy_yuzu_SDL_deps(yuzu)
copy_yuzu_unicorn_deps(yuzu)
copy_yuzu_FFmpeg_deps(yuzu) copy_yuzu_FFmpeg_deps(yuzu)
endif() endif()

View file

@ -39,7 +39,5 @@ endif()
if (MSVC) if (MSVC)
include(CopyYuzuSDLDeps) include(CopyYuzuSDLDeps)
include(CopyYuzuUnicornDeps)
copy_yuzu_SDL_deps(yuzu-cmd) copy_yuzu_SDL_deps(yuzu-cmd)
copy_yuzu_unicorn_deps(yuzu-cmd)
endif() endif()

View file

@ -28,7 +28,5 @@ endif()
if (MSVC) if (MSVC)
include(CopyYuzuSDLDeps) include(CopyYuzuSDLDeps)
include(CopyYuzuUnicornDeps)
copy_yuzu_SDL_deps(yuzu-tester) copy_yuzu_SDL_deps(yuzu-tester)
copy_yuzu_unicorn_deps(yuzu-tester)
endif() endif()