Browse Source
Merge pull request #4888 from lioncash/unicorn-remove
Merge pull request #4888 from lioncash/unicorn-remove
core: Remove usage of unicornnce_cpp
committed by
GitHub
18 changed files with 18 additions and 520 deletions
-
3.gitmodules
-
10.travis/linux-mingw/docker.sh
-
2.travis/linux/docker.sh
-
3.travis/macos/build.sh
-
77CMakeLists.txt
-
9CMakeModules/CopyYuzuUnicornDeps.cmake
-
1externals/unicorn
-
4src/core/CMakeLists.txt
-
1src/core/arm/dynarmic/arm_dynarmic_32.cpp
-
29src/core/arm/dynarmic/arm_dynarmic_64.cpp
-
2src/core/arm/dynarmic/arm_dynarmic_64.h
-
295src/core/arm/unicorn/arm_unicorn.cpp
-
63src/core/arm/unicorn/arm_unicorn.h
-
16src/core/hle/kernel/physical_core.cpp
-
17src/core/hle/kernel/thread.cpp
-
2src/yuzu/CMakeLists.txt
-
2src/yuzu_cmd/CMakeLists.txt
-
2src/yuzu_tester/CMakeLists.txt
@ -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,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
|
|||
@ -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 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue