First commit
This commit is contained in:
commit
81f55e53d4
16 changed files with 3338 additions and 0 deletions
44
.gitignore
vendored
Normal file
44
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.fls
|
||||
|
||||
# Let git use modules
|
||||
externals/dynarmic/
|
||||
build/
|
||||
uni_libs/
|
||||
|
||||
# My test files
|
||||
*.bin
|
||||
samples/
|
||||
src/libfiles/
|
||||
src/test/*
|
||||
21
.vscode/c_cpp_properties.json
vendored
Normal file
21
.vscode/c_cpp_properties.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${default}"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE"
|
||||
],
|
||||
"windowsSdkVersion": "10.0.22621.0",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"configurationProvider": "ms-vscode.cmake-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
111
.vscode/settings.json
vendored
Normal file
111
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"*.ejs": "html",
|
||||
"*.c": "c",
|
||||
"*.s": "ca65",
|
||||
"*.h": "c",
|
||||
"memory": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"exception": "cpp",
|
||||
"filesystem": "cpp",
|
||||
"format": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"fstream": "cpp",
|
||||
"functional": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"ios": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"iterator": "cpp",
|
||||
"limits": "cpp",
|
||||
"list": "cpp",
|
||||
"locale": "cpp",
|
||||
"map": "cpp",
|
||||
"new": "cpp",
|
||||
"optional": "cpp",
|
||||
"ostream": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"set": "cpp",
|
||||
"span": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"string": "cpp",
|
||||
"system_error": "cpp",
|
||||
"thread": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"utility": "cpp",
|
||||
"variant": "cpp",
|
||||
"vector": "cpp",
|
||||
"xfacet": "cpp",
|
||||
"xhash": "cpp",
|
||||
"xiosbase": "cpp",
|
||||
"xlocale": "cpp",
|
||||
"xlocbuf": "cpp",
|
||||
"xlocinfo": "cpp",
|
||||
"xlocmes": "cpp",
|
||||
"xlocmon": "cpp",
|
||||
"xlocnum": "cpp",
|
||||
"xloctime": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xstring": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xtree": "cpp",
|
||||
"xutility": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"numbers": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"complex": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"deque": "cpp",
|
||||
"future": "cpp",
|
||||
"mutex": "cpp",
|
||||
"strstream": "cpp",
|
||||
"typeindex": "cpp",
|
||||
"*.ipp": "cpp",
|
||||
"any": "cpp",
|
||||
"cfenv": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"expected": "cpp",
|
||||
"numeric": "cpp",
|
||||
"queue": "cpp",
|
||||
"ranges": "cpp",
|
||||
"regex": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"source_location": "cpp",
|
||||
"stack": "cpp",
|
||||
"stdfloat": "cpp"
|
||||
},
|
||||
"C_Cpp.default.compilerPath": "d:\\Daffin\\vs_com_2022\\VC\\Tools\\MSVC\\14.42.34433\\bin\\Hostx64\\x64\\cl.exe",
|
||||
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
||||
"dotnet.defaultSolution": "disable"
|
||||
}
|
||||
62
CMakeLists.txt
Normal file
62
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
cmake_minimum_required(VERSION 3.10.0)
|
||||
project(qmgdec VERSION 0.1.0 LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if(POLICY CMP0167)
|
||||
cmake_policy(SET CMP0167 OLD)
|
||||
endif()
|
||||
|
||||
# 01 - Boost first
|
||||
set(BOOST_INCLUDEDIR "${PROJECT_SOURCE_DIR}/externals/dynarmic/externals/ext-boost")
|
||||
find_package(Boost 1.57 REQUIRED)
|
||||
|
||||
# 02 - Dynarmic
|
||||
set(DYNARMIC_TESTS OFF CACHE BOOL "")
|
||||
set(DYNARMIC_FRONTENDS "A32;A64" CACHE STRING "")
|
||||
set(DYNARMIC_USE_PRECOMPILED_HEADERS ON CACHE BOOL "")
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/externals/dynarmic")
|
||||
|
||||
# 03 - UTF-8 msvc
|
||||
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
|
||||
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
||||
|
||||
# 04 - My code
|
||||
add_subdirectory(src)
|
||||
|
||||
#add_library(dynarmic STATIC IMPORTED)
|
||||
|
||||
# set_target_properties(dynarmic PROPERTIES
|
||||
# IMPORTED_LOCATION "deps/dynarmic/"
|
||||
# IMPORTED_IMPLIB "${DEPENDENCIES_DIR}/allegro/lib/allegro.lib"
|
||||
# INTERFACE_INCLUDE_DIRECTORIES "${DEPENDENCIES_DIR}/allegro/include"
|
||||
# )
|
||||
|
||||
# # include_directories("${PROJECT_SOURCE_DIR}/deps/dynarmic/include")
|
||||
|
||||
# # target_link_libraries(dynarmic INTERFACE dynarmic::dynarmic)
|
||||
# # # The dynarmic package's cmake files are helpfully completely silent
|
||||
# # # so we have to inform the user of its status ourselves
|
||||
# # if(TARGET dynarmic::dynarmic)
|
||||
# # message(STATUS "dynarmic: found him!")
|
||||
# # include_directories("${PROJECT_SOURCE_DIR}/deps/dynarmic/include")
|
||||
# # endif()
|
||||
|
||||
#include_directories("${PROJECT_SOURCE_DIR}/ld/ext-boost")
|
||||
|
||||
#add_executable(qmgdec qmgtest.cpp)
|
||||
#target_link_libraries(qmgdec PUBLIC dynarmic::dynarmic)
|
||||
|
||||
#add_executable(ifgdec ifgtest.cpp)
|
||||
#target_link_libraries(ifgdec PUBLIC dynarmic::dynarmic)
|
||||
|
||||
# target_sources(sources
|
||||
# PUBLIC
|
||||
# FILE_SET CXX_MODULES
|
||||
# FILES
|
||||
# main.ixx
|
||||
# PRIVATE
|
||||
# main.cpp
|
||||
# )
|
||||
|
||||
# target_compile_features(sources PUBLIC cxx_std_20)
|
||||
1146
bindings/python/dynemu.py
Normal file
1146
bindings/python/dynemu.py
Normal file
File diff suppressed because it is too large
Load diff
28
bindings/python/src/bindings.h
Normal file
28
bindings/python/src/bindings.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef void Emulator;
|
||||
|
||||
Emulator *dynemu_open();
|
||||
void dynemu_delete(Emulator *e);
|
||||
void dynemu_mmap(Emulator *e, u32 vaddr, u32 size);
|
||||
size_t dynemu_upload_file(Emulator *e, const char *filename, int64_t dest, u32 size);
|
||||
u8 dynemu_upload_fls_memory(Emulator *e, const u8 *fls);
|
||||
void dynemu_upload_memstub(Emulator *e, u32 dest, u32 mem_start, u32 mem_size, u8 is_big);
|
||||
void dynemu_upload_memstub_nooffset(Emulator *e, u32 mem_start, u32 mem_size, u8 is_big);
|
||||
u8 dynemu_read_u8(Emulator *e, u32 vaddr);
|
||||
u16 dynemu_read_u16(Emulator *e, u32 vaddr, u8 is_big);
|
||||
u32 dynemu_read_u32(Emulator *e, u32 vaddr, u8 is_big);
|
||||
u64 dynemu_read_u64(Emulator *e, u32 vaddr, u8 is_big);
|
||||
void dynemu_write_u8(Emulator *e, u32 vaddr, u8 value);
|
||||
void dynemu_write_u16(Emulator *e, u32 vaddr, u16 value, u8 is_big);
|
||||
void dynemu_write_u32(Emulator *e, u32 vaddr, u32 value, u8 is_big);
|
||||
void dynemu_write_u64(Emulator *e, u32 vaddr, u64 value, u8 is_big);
|
||||
void dynemu_read_bytes(Emulator *e, u32 vaddr, u8 *output, u32 size);
|
||||
void dynemu_write_bytes(Emulator *e, u32 vaddr, const u8 *input, u32 size);
|
||||
u32 dynemu_execute(Emulator *e, u32 pc, u8 is_big);
|
||||
u32 dynemu_read_reg(Emulator *e, u8 reg);
|
||||
void dynemu_write_reg(Emulator *e, u8 reg, u32 value);
|
||||
69
bindings/python/src/bindings.py
Normal file
69
bindings/python/src/bindings.py
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
from ctypes import *
|
||||
|
||||
class Dynemu():
|
||||
def __init__(self):
|
||||
self._dynemu = dynemu_open()
|
||||
|
||||
def __del__(self):
|
||||
dynemu_delete(self._dynemu)
|
||||
|
||||
def memory_map(self, vaddr: int, size: int):
|
||||
dynemu_mmap(self._dynemu, vaddr, size)
|
||||
|
||||
def upload_file(self, filename: str, dest: int, size: int):
|
||||
return dynemu_upload_file(self._dynemu, filename, dest, size)
|
||||
|
||||
def upload_fls_memory(self, data: bytes|bytearray):
|
||||
temp = (c_ubyte * len(data)).from_buffer(bytearray(data))
|
||||
return dynemu_upload_fls_memory(self._dynemu, temp)
|
||||
|
||||
def upload_memstub(self, dest: int=-1, mem_start: int=0xa0000000, mem_size: int=0x2000000, is_big: bool=False):
|
||||
if dest == -1:
|
||||
dynemu_upload_memstub_nooffset(self._dynemu, mem_start, mem_size, is_big)
|
||||
|
||||
else:
|
||||
dynemu_upload_memstub(self._dynemu, dest, mem_start, mem_size, is_big)
|
||||
|
||||
def read_u8(self, vaddr: int):
|
||||
return dynemu_read_u8(self._dynemu, vaddr)
|
||||
|
||||
def read_u16(self, vaddr: int, is_big: bool=False):
|
||||
return dynemu_read_u16(self._dynemu, vaddr, is_big)
|
||||
|
||||
def read_u32(self, vaddr: int, is_big: bool=False):
|
||||
return dynemu_read_u32(self._dynemu, vaddr, is_big)
|
||||
|
||||
def read_u64(self, vaddr: int, is_big: bool=False):
|
||||
return dynemu_read_u64(self._dynemu, vaddr, is_big)
|
||||
|
||||
def write_u8(self, vaddr: int, value: int):
|
||||
return dynemu_write_u8(self._dynemu, vaddr, value)
|
||||
|
||||
def write_u16(self, vaddr: int, value: int, is_big: bool=False):
|
||||
return dynemu_write_u16(self._dynemu, vaddr, value, is_big)
|
||||
|
||||
def write_u32(self, vaddr: int, value: int, is_big: bool=False):
|
||||
return dynemu_write_u32(self._dynemu, vaddr, value, is_big)
|
||||
|
||||
def write_u64(self, vaddr: int, value: int, is_big: bool=False):
|
||||
return dynemu_write_u64(self._dynemu, vaddr, value, is_big)
|
||||
|
||||
def read_bytes(self, vaddr: int, size: int):
|
||||
temp = (c_ubyte * size)()
|
||||
dynemu_read_bytes(self._dynemu, vaddr, temp, size)
|
||||
return bytes(temp)
|
||||
|
||||
def write_bytes(self, vaddr: int, data: bytes|bytearray):
|
||||
temp = (c_ubyte * len(data)).from_buffer(bytearray(data))
|
||||
dynemu_write_bytes(self._dynemu, vaddr, temp, len(data))
|
||||
|
||||
def execute(self, pc: int, is_big: bool=False):
|
||||
return dynemu_execute(self._dynemu, pc, is_big)
|
||||
|
||||
def get_reg(self, reg: int):
|
||||
return dynemu_read_reg(self._dynemu, reg)
|
||||
|
||||
def set_reg(self, reg: int, value: int):
|
||||
dynemu_write_reg(self._dynemu, reg, value)
|
||||
|
||||
|
||||
2
bindings/python/src/make.bat
Normal file
2
bindings/python/src/make.bat
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
@echo off
|
||||
ctypesgen.exe -ldynemu_shared bindings.h -o ..\dynemu.py --insert-file=bindings.py
|
||||
6
src/CMakeLists.txt
Normal file
6
src/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
include_directories(.)
|
||||
set_property(DIRECTORY APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
|
||||
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(lib)
|
||||
15
src/lib/CMakeLists.txt
Normal file
15
src/lib/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
add_library(dynemu OBJECT libdynemu.cpp)
|
||||
add_dependencies(dynemu dynarmic mcl)
|
||||
target_link_libraries(dynemu PUBLIC dynarmic mcl)
|
||||
|
||||
set_property(TARGET dynemu PROPERTY POSITION_INDEPENDENT_CODE 1)
|
||||
|
||||
# shared and static libraries built from the same object files
|
||||
add_library(dynemu_shared SHARED $<TARGET_OBJECTS:dynemu>)
|
||||
add_library(dynemu_static STATIC $<TARGET_OBJECTS:dynemu>)
|
||||
|
||||
add_dependencies(dynemu_shared dynarmic mcl)
|
||||
target_link_libraries(dynemu_shared PUBLIC dynarmic mcl)
|
||||
|
||||
add_dependencies(dynemu_static dynarmic mcl)
|
||||
target_link_libraries(dynemu_static PUBLIC dynarmic mcl)
|
||||
109
src/lib/libdynemu.cpp
Normal file
109
src/lib/libdynemu.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#include "shared/sys_emulator.hpp"
|
||||
#include "libdynemu.hpp"
|
||||
|
||||
extern "C" {
|
||||
Emulator *dynemu_open() {
|
||||
auto temp = new Emulator();
|
||||
return temp;
|
||||
}
|
||||
|
||||
void dynemu_delete(Emulator *e) {
|
||||
delete e;
|
||||
}
|
||||
|
||||
void dynemu_mmap(Emulator *e, u32 vaddr, u32 size) {
|
||||
return e->env.CreateMemoryMap(vaddr, size);
|
||||
}
|
||||
|
||||
size_t dynemu_upload_file(Emulator *e, const char *filename, std::int64_t dest, u32 size) {
|
||||
return e->env.UploadToMemory(filename, dest, size);
|
||||
}
|
||||
|
||||
bool dynemu_upload_fls_memory(Emulator *e, const u8 *fls) {
|
||||
return e->env.UploadFLSFromBytes(fls);
|
||||
}
|
||||
|
||||
void dynemu_upload_memstub(Emulator *e, u32 dest, u32 mem_start, u32 mem_size, bool is_big) {
|
||||
return e->env.UploadOSStub(dest, mem_start, mem_size, is_big);
|
||||
}
|
||||
|
||||
void dynemu_upload_memstub_nooffset(Emulator *e, u32 mem_start, u32 mem_size, bool is_big) {
|
||||
return e->env.UploadOSStub(mem_start, mem_size, is_big);
|
||||
}
|
||||
|
||||
u8 dynemu_read_u8(Emulator *e, u32 vaddr) {
|
||||
return e->env.MemoryRead8(vaddr);
|
||||
}
|
||||
|
||||
u16 dynemu_read_u16(Emulator *e, u32 vaddr, bool is_big) {
|
||||
if (is_big) {
|
||||
return e->env.MemoryRead16_Big(vaddr);
|
||||
} else {
|
||||
return e->env.MemoryRead16(vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
u32 dynemu_read_u32(Emulator *e, u32 vaddr, bool is_big) {
|
||||
if (is_big) {
|
||||
return e->env.MemoryRead32_Big(vaddr);
|
||||
} else {
|
||||
return e->env.MemoryRead32(vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
u64 dynemu_read_u64(Emulator *e, u32 vaddr, bool is_big) {
|
||||
if (is_big) {
|
||||
return e->env.MemoryRead64_Big(vaddr);
|
||||
} else {
|
||||
return e->env.MemoryRead64(vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
void dynemu_write_u8(Emulator *e, u32 vaddr, u8 value) {
|
||||
e->env.MemoryWrite8(vaddr, value);
|
||||
}
|
||||
|
||||
void dynemu_write_u16(Emulator *e, u32 vaddr, u16 value, bool is_big) {
|
||||
if (is_big) {
|
||||
e->env.MemoryWrite16_Big(vaddr, value);
|
||||
} else {
|
||||
e->env.MemoryWrite16(vaddr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void dynemu_write_u32(Emulator *e, u32 vaddr, u32 value, bool is_big) {
|
||||
if (is_big) {
|
||||
e->env.MemoryWrite32_Big(vaddr, value);
|
||||
} else {
|
||||
e->env.MemoryWrite32(vaddr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void dynemu_write_u64(Emulator *e, u32 vaddr, u64 value, bool is_big) {
|
||||
if (is_big) {
|
||||
e->env.MemoryWrite64_Big(vaddr, value);
|
||||
} else {
|
||||
e->env.MemoryWrite64(vaddr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void dynemu_read_bytes(Emulator *e, u32 vaddr, u8 *output, u32 size) {
|
||||
e->env.MemoryReadBytes(vaddr, output, size);
|
||||
}
|
||||
|
||||
void dynemu_write_bytes(Emulator *e, u32 vaddr, const u8 *input, u32 size) {
|
||||
e->env.MemoryWriteBytes(vaddr, input, size);
|
||||
}
|
||||
|
||||
u32 dynemu_execute(Emulator *e, u32 pc, bool is_big) {
|
||||
return e->env.Execute(pc, is_big);
|
||||
}
|
||||
|
||||
u32 dynemu_read_reg(Emulator *e, u8 reg) {
|
||||
return e->env.cpu->Regs()[reg];
|
||||
}
|
||||
|
||||
void dynemu_write_reg(Emulator *e, u8 reg, u32 value) {
|
||||
e->env.cpu->Regs()[reg] = value;
|
||||
}
|
||||
}
|
||||
40
src/lib/libdynemu.hpp
Normal file
40
src/lib/libdynemu.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#include <cstdint>
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Microsoft
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#define IMPORT __declspec(dllimport)
|
||||
#elif defined(__GNUC__)
|
||||
// GCC
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
#define IMPORT
|
||||
#else
|
||||
// do nothing and hope for the best?
|
||||
#define EXPORT
|
||||
#define IMPORT
|
||||
#pragma warning Unknown dynamic link import/export semantics.
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
EXPORT Emulator *dynemu_open();
|
||||
EXPORT void dynemu_delete(Emulator *e);
|
||||
EXPORT void dynemu_mmap(Emulator *e, u32 vaddr, u32 size);
|
||||
EXPORT size_t dynemu_upload_file(Emulator *e, const char *filename, int64_t dest, u32 size);
|
||||
EXPORT bool dynemu_upload_fls_memory(Emulator *e, const u8 *fls);
|
||||
EXPORT void dynemu_upload_memstub(Emulator *e, u32 dest, u32 mem_start, u32 mem_size, bool is_big);
|
||||
EXPORT void dynemu_upload_memstub_nooffset(Emulator *e, u32 mem_start, u32 mem_size, bool is_big);
|
||||
EXPORT u8 dynemu_read_u8(Emulator *e, u32 vaddr);
|
||||
EXPORT u16 dynemu_read_u16(Emulator *e, u32 vaddr, bool is_big);
|
||||
EXPORT u32 dynemu_read_u32(Emulator *e, u32 vaddr, bool is_big);
|
||||
EXPORT u64 dynemu_read_u64(Emulator *e, u32 vaddr, bool is_big);
|
||||
EXPORT void dynemu_write_u8(Emulator *e, u32 vaddr, u8 value);
|
||||
EXPORT void dynemu_write_u16(Emulator *e, u32 vaddr, u16 value, bool is_big);
|
||||
EXPORT void dynemu_write_u32(Emulator *e, u32 vaddr, u32 value, bool is_big);
|
||||
EXPORT void dynemu_write_u64(Emulator *e, u32 vaddr, u64 value, bool is_big);
|
||||
EXPORT void dynemu_read_bytes(Emulator *e, u32 vaddr, u8 *output, u32 size);
|
||||
EXPORT void dynemu_write_bytes(Emulator *e, u32 vaddr, const u8 *input, u32 size);
|
||||
EXPORT u32 dynemu_execute(Emulator *e, u32 pc, bool is_big);
|
||||
EXPORT u32 dynemu_read_reg(Emulator *e, u8 reg);
|
||||
EXPORT void dynemu_write_reg(Emulator *e, u8 reg, u32 value);
|
||||
}
|
||||
1015
src/shared/os_wrapper.hpp
Normal file
1015
src/shared/os_wrapper.hpp
Normal file
File diff suppressed because it is too large
Load diff
511
src/shared/sys_emulator.hpp
Normal file
511
src/shared/sys_emulator.hpp
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
/* (c) 2025 Wrapper Inc. - The New Emulation Library */
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <format>
|
||||
|
||||
#include "os_wrapper.hpp"
|
||||
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
#include "dynarmic/interface/exclusive_monitor.h"
|
||||
|
||||
#include "mcl/assert.hpp"
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u64 = std::uint64_t;
|
||||
|
||||
#define DEBUG 0
|
||||
#define BLOCK_ALLIGN 0x10000
|
||||
|
||||
class MemMap final {
|
||||
public:
|
||||
u64 start;
|
||||
u64 size;
|
||||
std::unique_ptr<u8[]> data;
|
||||
};
|
||||
|
||||
struct FlashPartition {
|
||||
u32 start_vaddr;
|
||||
u32 size;
|
||||
std::unique_ptr<u8[]> data;
|
||||
};
|
||||
|
||||
struct FlashLoader {
|
||||
u16 magic;
|
||||
u32 count;
|
||||
std::unique_ptr<FlashPartition[]> data;
|
||||
};
|
||||
|
||||
class MyEmulator final : public Dynarmic::A32::UserCallbacks {
|
||||
private:
|
||||
u8 find_memory_map_id(u32 vaddr) {
|
||||
for (int i = 0; i < mem_map.size(); i++) {
|
||||
if (vaddr >= mem_map[i].start && vaddr < (mem_map[i].start + mem_map[i].size)) return i;
|
||||
}
|
||||
std::cerr << std::format("Memory map {:#08x} OOB, Emulation cannot continue", vaddr) << std::endl;
|
||||
throw std::out_of_range("Data abort");
|
||||
}
|
||||
|
||||
bool is_mmap_exists(u32 vaddr) {
|
||||
for (int i = 0; i < mem_map.size(); i++) {
|
||||
if (vaddr >= mem_map[i].start && vaddr < (mem_map[i].start + mem_map[i].size)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
bool CheckExecOverridePC(const std::array<u32, N> &list, u32 pc) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (pc == list[i]) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
std::array<MemMap, 64> mem_map{};
|
||||
u32 map_index = 0;
|
||||
u32 os_offset = 0xa8000000;
|
||||
Dynarmic::A32::Jit *cpu;
|
||||
|
||||
/*
|
||||
void CreateMemoryMap(u32 vaddr, u32 size)
|
||||
This function creates a memory map for this specific vaddr (virtual address) with specific size
|
||||
*/
|
||||
void CreateMemoryMap(u32 vaddr, u32 size) {
|
||||
if (!is_mmap_exists(vaddr)) mem_map[map_index++] = {vaddr, size, std::make_unique<u8[]>(size)};
|
||||
}
|
||||
|
||||
/*
|
||||
void RoutineReplaceWithBXLR(const std::array<u32, N> &list, bool is_thumb, bool is_big)
|
||||
This function replaces each instruction on the list with "bx lr" instruction
|
||||
Currently, this has no use outside for hooking functions
|
||||
*/
|
||||
template <std::size_t N>
|
||||
void RoutineReplaceWithBXLR(const std::array<u32, N> &list, bool is_thumb, bool is_big) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (is_thumb) {
|
||||
MemoryWrite16(list[i], is_big ? 0x7047 : 0x4770);
|
||||
} else {
|
||||
MemoryWrite32(list[i], is_big ? 0x1eff2fe1 : 0xe12fff1e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
size_t UploadToMemory(std::string filename, std::int64_t dest, u32 size)
|
||||
This function uploads a file into memory, automatically creating a memory map if not exists.
|
||||
Setting dest to -1 will use a multi-map parser
|
||||
Returns:
|
||||
0: NOK
|
||||
1 or FileSize: OK
|
||||
*/
|
||||
size_t UploadToMemory(std::string filename, std::int64_t dest, u32 size) {
|
||||
std::ifstream file(filename, std::ios::binary);
|
||||
u8 buf[2048];
|
||||
u32 offset = 0;
|
||||
int to_read = 0;
|
||||
|
||||
if (!file.is_open()) {
|
||||
std::cerr << std::format("Unable to open {}: {}", filename, std::strerror(errno)) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dest != -1) {
|
||||
file.seekg(0, file.end);
|
||||
size_t fileSize = file.tellg();
|
||||
file.seekg(0, file.beg);
|
||||
|
||||
if (size < fileSize && !is_mmap_exists((u32)dest)) {
|
||||
std::cerr << "Code file too large to fit into memory" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
CreateMemoryMap((u32)dest, size);
|
||||
|
||||
while ((size_t)file.tellg() < fileSize) {
|
||||
to_read = (int)((fileSize - file.tellg()) >= 2048 ? 2048 : (fileSize - file.tellg()));
|
||||
file.read((char *)buf, to_read);
|
||||
MemoryWriteBytes((u32)dest + offset, buf, to_read);
|
||||
offset += to_read;
|
||||
}
|
||||
|
||||
return fileSize;
|
||||
} else {
|
||||
FlashLoader fl{};
|
||||
file.read((char *)&fl.magic, sizeof(fl.magic));
|
||||
file.read((char *)&fl.count, sizeof(fl.count));
|
||||
|
||||
if (fl.magic != 0x4c46) {
|
||||
std::cerr << "Invalid FL magic check" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fl.data = std::make_unique<FlashPartition[]>(fl.count);
|
||||
|
||||
for (u32 i = 0; i < fl.count; i++) {
|
||||
file.read((char *)&fl.data.get()[i].start_vaddr, sizeof(fl.data.get()[i].start_vaddr));
|
||||
file.read((char *)&fl.data.get()[i].size, sizeof(fl.data.get()[i].size));
|
||||
fl.data.get()[i].data = std::make_unique<u8[]>(fl.data.get()[i].size);
|
||||
file.read((char *)fl.data.get()[i].data.get(), fl.data.get()[i].size);
|
||||
|
||||
CreateMemoryMap(fl.data.get()[i].start_vaddr, fl.data.get()[i].size + ((fl.data.get()[i].size % BLOCK_ALLIGN) ? (BLOCK_ALLIGN - (fl.data.get()[i].size % BLOCK_ALLIGN)) : 0));
|
||||
MemoryWriteBytes(fl.data.get()[i].start_vaddr, fl.data.get()[i].data.get(), fl.data.get()[i].size);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool UploadFLSFromBytes(const u8 *fls)
|
||||
This function uploads a multi-part code file from memory.
|
||||
Returns:
|
||||
0: NOK
|
||||
1: OK
|
||||
*/
|
||||
bool UploadFLSFromBytes(const u8 *fls) {
|
||||
FlashLoader fl{};
|
||||
|
||||
memcpy(&fl.magic, fls, sizeof(fl.magic));
|
||||
memcpy(&fl.count, fls + sizeof(fl.magic), sizeof(fl.count));
|
||||
|
||||
if (fl.magic != 0x4c46) {
|
||||
std::cerr << "Invalid FL magic check" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
fl.data = std::make_unique<FlashPartition[]>(fl.count);
|
||||
|
||||
auto offset = sizeof(fl.magic) + sizeof(fl.count);
|
||||
|
||||
for (u32 i = 0; i < fl.count; i++) {
|
||||
memcpy(&fl.data.get()[i].start_vaddr, fls + offset, sizeof(fl.data.get()[i].start_vaddr));
|
||||
memcpy(&fl.data.get()[i].size, fls + offset + sizeof(fl.data.get()[i].start_vaddr), sizeof(fl.data.get()[i].size));
|
||||
fl.data.get()[i].data = std::make_unique<u8[]>(fl.data.get()[i].size);
|
||||
memcpy((char *)fl.data.get()[i].data.get(), fls + offset + sizeof(fl.data.get()[i].start_vaddr) + sizeof(fl.data.get()[i].size), fl.data.get()[i].size);
|
||||
|
||||
offset += sizeof(fl.data.get()[i].start_vaddr) + sizeof(fl.data.get()[i].size) + fl.data.get()[i].size;
|
||||
|
||||
CreateMemoryMap(fl.data.get()[i].start_vaddr, fl.data.get()[i].size + ((fl.data.get()[i].size % BLOCK_ALLIGN) ? (BLOCK_ALLIGN - (fl.data.get()[i].size % BLOCK_ALLIGN)) : 0));
|
||||
MemoryWriteBytes(fl.data.get()[i].start_vaddr, fl.data.get()[i].data.get(), fl.data.get()[i].size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
bool UploadFLSFromBytes(const std::array<u8, N> &fls)
|
||||
This function uploads a multi-part code file from memory.
|
||||
Returns:
|
||||
0: NOK
|
||||
1: OK
|
||||
*/
|
||||
template <std::size_t N>
|
||||
bool UploadFLSFromBytes(const std::array<u8, N> &fls) {
|
||||
return UploadFLSFromBytes(fls.data());
|
||||
}
|
||||
|
||||
/*
|
||||
void UploadOSStub(u32 dest, u32 mem_start, u32 mem_size, bool is_big)
|
||||
This function uploads a stub libc to a specific dest virtual address, along with setting up the regions assosiated with the dynamic memory functions.
|
||||
Endianness were determined by is_big parameter.
|
||||
*/
|
||||
void UploadOSStub(u32 dest, u32 mem_start, u32 mem_size, bool is_big) {
|
||||
if (is_big) {
|
||||
MemoryWriteBytes(dest, OS_LoopLoader_BE.data(), (u32)OS_LoopLoader_BE.size());
|
||||
MemoryWrite32_Big(dest + MEM_INIT_REG_OFFSET, mem_start);
|
||||
MemoryWrite32_Big(dest + MEM_INIT_REG_SIZE, mem_size);
|
||||
} else {
|
||||
MemoryWriteBytes(dest, OS_LoopLoader.data(), (u32)OS_LoopLoader.size());
|
||||
MemoryWrite32(dest + MEM_INIT_REG_OFFSET, mem_start);
|
||||
MemoryWrite32(dest + MEM_INIT_REG_SIZE, mem_size);
|
||||
}
|
||||
os_offset = dest;
|
||||
}
|
||||
|
||||
/*
|
||||
void UploadOSStub(u32 mem_start, u32 mem_size, bool is_big)
|
||||
This function uploads a stub libc to the configured os_offset parameter virtual address, along with setting up the regions assosiated with the dynamic memory functions.
|
||||
Endianness were determined by is_big parameter.
|
||||
*/
|
||||
void UploadOSStub(u32 mem_start, u32 mem_size, bool is_big) {
|
||||
UploadOSStub(os_offset, mem_start, mem_size, is_big);
|
||||
}
|
||||
|
||||
/*
|
||||
bool PreCodeReadHook(bool is_thumb, u32 pc, Dynarmic::A32::IREmitter& ir)
|
||||
Custom function used for end of code detection.
|
||||
*/
|
||||
bool PreCodeReadHook(bool is_thumb, u32 pc, Dynarmic::A32::IREmitter& ir) override {
|
||||
#if DEBUG
|
||||
std::cout << std::format("executing at {:#08x}", pc) << std::endl;
|
||||
std::cout << std::format("REG P0 {:#08x}", cpu->Regs()[0]) << std::endl;
|
||||
std::cout << std::format("REG P1 {:#08x}", cpu->Regs()[1]) << std::endl;
|
||||
std::cout << std::format("REG P2 {:#08x}", cpu->Regs()[2]) << std::endl;
|
||||
std::cout << std::format("REG P12 {:#08x}", cpu->Regs()[12]) << std::endl;
|
||||
std::cout << std::format("REG P15 {:#08x}", cpu->Regs()[15]) << std::endl;
|
||||
#endif
|
||||
|
||||
if (pc == (os_offset + ROUTE_EXIT)) cpu->HaltExecution();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
u8 MemoryRead8(u32 vaddr)
|
||||
Reads an 8-bit value from vaddr
|
||||
Returns: byte[vaddr]
|
||||
*/
|
||||
u8 MemoryRead8(u32 vaddr) override {
|
||||
#if DEBUG
|
||||
if (cpu->IsExecuting()) printf("Reading at 0x%08x\n", vaddr);
|
||||
#endif
|
||||
try {
|
||||
u8 mem_now = find_memory_map_id(vaddr);
|
||||
return mem_map[mem_now].data.get()[vaddr - mem_map[mem_now].start];
|
||||
} catch (std::out_of_range) {
|
||||
cpu->HaltExecution(Dynarmic::HaltReason::MemoryAbort);
|
||||
return 0xff; // Undefined behavior can occur
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryReadBytes(u32 vaddr, u8 *output, u32 size)
|
||||
Copy data from memory map to a single u8 pointer.
|
||||
*/
|
||||
void MemoryReadBytes(u32 vaddr, u8 *output, u32 size) {
|
||||
u8 mem_now = find_memory_map_id(vaddr);
|
||||
ASSERT(((vaddr - mem_map[mem_now].start) + size) <= mem_map[mem_now].size);
|
||||
memcpy(output, mem_map[mem_now].data.get() + (vaddr - mem_map[mem_now].start), size);
|
||||
}
|
||||
|
||||
/*
|
||||
u16 MemoryRead16(u32 vaddr)
|
||||
Reads a 16-bit value from vaddr
|
||||
Returns: short[vaddr]
|
||||
*/
|
||||
u16 MemoryRead16(u32 vaddr) override {
|
||||
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||
}
|
||||
|
||||
/*
|
||||
u32 MemoryRead32(u32 vaddr)
|
||||
Reads a 32-bit value from vaddr
|
||||
Returns: word[vaddr]
|
||||
*/
|
||||
u32 MemoryRead32(u32 vaddr) override {
|
||||
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||
}
|
||||
|
||||
/*
|
||||
u64 MemoryRead64(u32 vaddr)
|
||||
Reads a 64-bit value from vaddr
|
||||
Returns: dword[vaddr]
|
||||
*/
|
||||
u64 MemoryRead64(u32 vaddr) override {
|
||||
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||
}
|
||||
|
||||
/*
|
||||
u16 MemoryRead16_Big(u32 vaddr)
|
||||
Reads a 16-bit value from vaddr
|
||||
Returns: short[vaddr]
|
||||
*/
|
||||
u16 MemoryRead16_Big(u32 vaddr) {
|
||||
return u16(MemoryRead8(vaddr + 1)) | u16(MemoryRead8(vaddr)) << 8;
|
||||
}
|
||||
|
||||
/*
|
||||
u32 MemoryRead32_Big(u32 vaddr)
|
||||
Reads a 32-bit value from vaddr
|
||||
Returns: word[vaddr]
|
||||
*/
|
||||
u32 MemoryRead32_Big(u32 vaddr) {
|
||||
return u32(MemoryRead16_Big(vaddr + 2)) | u32(MemoryRead16_Big(vaddr)) << 16;
|
||||
}
|
||||
|
||||
/*
|
||||
u64 MemoryRead64_Big(u32 vaddr)
|
||||
Reads a 64-bit value from vaddr
|
||||
Returns: dword[vaddr]
|
||||
*/
|
||||
u64 MemoryRead64_Big(u32 vaddr) {
|
||||
return u64(MemoryRead32_Big(vaddr + 4)) | u64(MemoryRead32_Big(vaddr)) << 32;
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryWrite8(u32 vaddr, u8 value)
|
||||
Writes an 8-bit value to vaddr
|
||||
*/
|
||||
void MemoryWrite8(u32 vaddr, u8 value) override {
|
||||
#if DEBUG
|
||||
if (cpu->IsExecuting()) printf("Writing at 0x%08x 0x%02x\n", vaddr, value);
|
||||
#endif
|
||||
try {
|
||||
u8 mem_now = find_memory_map_id(vaddr);
|
||||
mem_map[mem_now].data.get()[vaddr - mem_map[mem_now].start] = value;
|
||||
} catch (std::out_of_range) {
|
||||
cpu->HaltExecution(Dynarmic::HaltReason::MemoryAbort);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryWriteBytes(u32 vaddr, const u8 *input, u32 size)
|
||||
Copy data from a single u8 pointer into memory map.
|
||||
*/
|
||||
void MemoryWriteBytes(u32 vaddr, const u8 *input, u32 size) {
|
||||
u8 mem_now = find_memory_map_id(vaddr);
|
||||
ASSERT(((vaddr - mem_map[mem_now].start) + size) <= mem_map[mem_now].size);
|
||||
memcpy(mem_map[mem_now].data.get() + (vaddr - mem_map[mem_now].start), input, size);
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryWriteBytes(u32 vaddr, const std::array<u8, N> &data)
|
||||
Copy data from a single u8 pointer into memory map.
|
||||
*/
|
||||
template <std::size_t N>
|
||||
void MemoryWriteBytes(u32 vaddr, const std::array<u8, N> &data) {
|
||||
MemoryWriteBytes(vaddr, data.data(), N);
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryWrite16(u32 vaddr, u16 value)
|
||||
Writes an 16-bit value to vaddr
|
||||
*/
|
||||
void MemoryWrite16(u32 vaddr, u16 value) override {
|
||||
MemoryWrite8(vaddr, u8(value));
|
||||
MemoryWrite8(vaddr + 1, u8(value >> 8));
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryWrite32(u32 vaddr, u32 value)
|
||||
Writes an 32-bit value to vaddr
|
||||
*/
|
||||
void MemoryWrite32(u32 vaddr, u32 value) override {
|
||||
MemoryWrite16(vaddr, u16(value));
|
||||
MemoryWrite16(vaddr + 2, u16(value >> 16));
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryWrite64(u32 vaddr, u64 value)
|
||||
Writes an 64-bit value to vaddr
|
||||
*/
|
||||
void MemoryWrite64(u32 vaddr, u64 value) override {
|
||||
MemoryWrite32(vaddr, u32(value));
|
||||
MemoryWrite32(vaddr + 4, u32(value >> 32));
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryWrite16_Big(u32 vaddr, u16 value)
|
||||
Writes an 16-bit value to vaddr
|
||||
*/
|
||||
void MemoryWrite16_Big(u32 vaddr, u16 value) {
|
||||
MemoryWrite8(vaddr + 1, u8(value));
|
||||
MemoryWrite8(vaddr, u8(value >> 8));
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryWrite32_Big(u32 vaddr, u32 value)
|
||||
Writes an 32-bit value to vaddr
|
||||
*/
|
||||
void MemoryWrite32_Big(u32 vaddr, u32 value) {
|
||||
MemoryWrite16_Big(vaddr + 2, u16(value));
|
||||
MemoryWrite16_Big(vaddr, u16(value >> 16));
|
||||
}
|
||||
|
||||
/*
|
||||
void MemoryWrite64_Big(u32 vaddr, u64 value)
|
||||
Writes an 64-bit value to vaddr
|
||||
*/
|
||||
void MemoryWrite64_Big(u32 vaddr, u64 value) {
|
||||
MemoryWrite32_Big(vaddr + 4, u32(value));
|
||||
MemoryWrite32_Big(vaddr, u32(value >> 32));
|
||||
}
|
||||
|
||||
/*
|
||||
void InterpreterFallback(u32 pc, size_t num_instructions)
|
||||
*/
|
||||
void InterpreterFallback(u32 pc, size_t num_instructions) override {
|
||||
// This is never called in practice.
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
/*
|
||||
void CallSVC(u32 swi)
|
||||
*/
|
||||
void CallSVC(u32 swi) override {
|
||||
// Do something.
|
||||
}
|
||||
|
||||
/*
|
||||
u32 Execute(u32 pc, bool is_big)
|
||||
Executes from specific PC
|
||||
Returns: R0 register
|
||||
*/
|
||||
u32 Execute(u32 pc, bool is_big) {
|
||||
cpu->Regs()[14] = os_offset + ROUTE_EXIT;
|
||||
cpu->Regs()[15] = pc & ~1;
|
||||
cpu->SetCpsr(((pc & 1) ? 0x30 : 0x1d0) | (is_big ? 0x200 : 0x0));
|
||||
|
||||
Dynarmic::HaltReason returnCode = cpu->Run();
|
||||
cpu->ClearCache();
|
||||
|
||||
return cpu->Regs()[0];
|
||||
}
|
||||
|
||||
/*
|
||||
u32 Execute(u32 pc)
|
||||
Executes from specific PC
|
||||
Returns: R0 register
|
||||
*/
|
||||
u32 Execute(u32 pc) {
|
||||
return Execute(pc, false);
|
||||
}
|
||||
|
||||
/*
|
||||
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception)
|
||||
*/
|
||||
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
|
||||
std::cerr << std::format("decoder: exception at {:#08x}: ", pc);
|
||||
std::cerr << std::format("{}", (int)exception) << std::endl;
|
||||
std::terminate();
|
||||
// Do something.
|
||||
}
|
||||
|
||||
/*
|
||||
void AddTicks(u64 ticks)
|
||||
*/
|
||||
void AddTicks(u64 ticks) override {}
|
||||
|
||||
/*
|
||||
GetTicksRemaining()
|
||||
*/
|
||||
u64 GetTicksRemaining() override {return 8000;}
|
||||
};
|
||||
|
||||
class Emulator {
|
||||
private:
|
||||
std::unique_ptr<Dynarmic::A32::Jit> cpu;
|
||||
std::unique_ptr<Dynarmic::ExclusiveMonitor> mon;
|
||||
|
||||
public:
|
||||
MyEmulator env;
|
||||
|
||||
Emulator() {
|
||||
Dynarmic::A32::UserConfig user_config;
|
||||
|
||||
user_config.callbacks = &env;
|
||||
user_config.enable_cycle_counting = false;
|
||||
user_config.arch_version = Dynarmic::A32::ArchVersion::v7;
|
||||
|
||||
mon = std::make_unique<Dynarmic::ExclusiveMonitor>(1);
|
||||
user_config.global_monitor = mon.get();
|
||||
|
||||
cpu = std::make_unique<Dynarmic::A32::Jit>(user_config);
|
||||
env.cpu = cpu.get();
|
||||
};
|
||||
};
|
||||
18
utils/fls2bin.py
Normal file
18
utils/fls2bin.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from construct import *
|
||||
import sys
|
||||
import os
|
||||
|
||||
FlashLoader = Struct(
|
||||
"magic" / Const(b"FL"),
|
||||
"count" / Int32ul,
|
||||
"regions" / Array(this.count, Struct(
|
||||
"start" / Int32ul,
|
||||
"size" / Int32ul,
|
||||
"data" / Bytes(this.size)
|
||||
))
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
fls = FlashLoader.parse_file(sys.argv[1])
|
||||
for reg in fls.regions:
|
||||
open(os.path.splitext(sys.argv[1])[0] + f"_0x{reg.start:08x}.bin", "wb").write(reg.data)
|
||||
141
utils/packer_template.py
Normal file
141
utils/packer_template.py
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
import struct
|
||||
from keystone import *
|
||||
|
||||
# ("file_name", 0xOFFSET)
|
||||
files = [
|
||||
|
||||
]
|
||||
|
||||
asm = Ks(KS_ARCH_ARM, KS_MODE_ARM)
|
||||
asm_t = Ks(KS_ARCH_ARM, KS_MODE_THUMB)
|
||||
|
||||
asm_be = Ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_BIG_ENDIAN)
|
||||
asm_be_t = Ks(KS_ARCH_ARM, KS_MODE_THUMB + KS_MODE_BIG_ENDIAN)
|
||||
|
||||
# Override addresses
|
||||
MEMCPY_ADDRESS = []
|
||||
MALLOC_ADDRESS = []
|
||||
FREE_ADDRESS = []
|
||||
MEMSET_ADDRESS = []
|
||||
CALLOC_ADDRESS = []
|
||||
REALLOC_ADDRESS = []
|
||||
MEMMOVE_ADDRESS = []
|
||||
|
||||
MEMCPY_ADDRESS_T = []
|
||||
MALLOC_ADDRESS_T = []
|
||||
FREE_ADDRESS_T = []
|
||||
MEMSET_ADDRESS_T = []
|
||||
CALLOC_ADDRESS_T = []
|
||||
REALLOC_ADDRESS_T = []
|
||||
MEMMOVE_ADDRESS_T = []
|
||||
|
||||
ROUTE_INIT_REGION = 0x0
|
||||
ROUTE_MALLOC = 0x4
|
||||
ROUTE_MEMCPY = 0x8
|
||||
ROUTE_FREE = 0xc
|
||||
ROUTE_MEMSET = 0x10
|
||||
ROUTE_CALLOC = 0x14
|
||||
ROUTE_REALLOC = 0x18
|
||||
ROUTE_MEMMOVE = 0x1c
|
||||
ROUTE_EXIT = 0x20
|
||||
|
||||
ROUTE_MALLOC_T = 0x24
|
||||
ROUTE_MEMCPY_T = 0x2c
|
||||
ROUTE_FREE_T = 0x34
|
||||
ROUTE_MEMSET_T = 0x3c
|
||||
ROUTE_CALLOC_T = 0x44
|
||||
ROUTE_REALLOC_T = 0x4c
|
||||
ROUTE_MEMMOVE_T = 0x54
|
||||
ROUTE_EXIT_T = 0x5c
|
||||
|
||||
ROUTE_MEM_BASE = 0x0
|
||||
|
||||
if __name__ == "__main__":
|
||||
f = open("(OUTPUT_FILE).fls", "wb")
|
||||
|
||||
# 01 - Files
|
||||
f.write(b"FL")
|
||||
f.write(struct.pack("<L", 0))
|
||||
for fl in files:
|
||||
flashName, offset = fl
|
||||
flash = open(flashName, "rb").read()
|
||||
f.write(struct.pack("<LL", offset, len(flash))+flash)
|
||||
|
||||
tCount = len(files)
|
||||
|
||||
# 02 - Patching (ARM)
|
||||
for a in MALLOC_ADDRESS:
|
||||
b, c = asm.asm(f"b 0x{ROUTE_MEM_BASE + ROUTE_MALLOC:02x}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in MEMCPY_ADDRESS:
|
||||
b, c = asm.asm(f"b 0x{ROUTE_MEM_BASE + ROUTE_MEMCPY:02x}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in FREE_ADDRESS:
|
||||
b, c = asm.asm(f"b 0x{ROUTE_MEM_BASE + ROUTE_FREE:02x}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in MEMSET_ADDRESS:
|
||||
b, c = asm.asm(f"b 0x{ROUTE_MEM_BASE + ROUTE_MEMSET:02x}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in CALLOC_ADDRESS:
|
||||
b, c = asm.asm(f"b 0x{ROUTE_MEM_BASE + ROUTE_CALLOC:02x}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in REALLOC_ADDRESS:
|
||||
b, c = asm.asm(f"b 0x{ROUTE_MEM_BASE + ROUTE_REALLOC:02x}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in MEMMOVE_ADDRESS:
|
||||
b, c = asm.asm(f"b 0x{ROUTE_MEM_BASE + ROUTE_MEMMOVE:02x}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
# 03 - Patching thumb
|
||||
for a in MALLOC_ADDRESS_T:
|
||||
b, c = asm_t.asm("push {r4-r7, lr}; " + f"blx 0x{ROUTE_MEM_BASE + ROUTE_MALLOC:02x}; " + "pop {r4-r7, pc}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in MEMCPY_ADDRESS_T:
|
||||
b, c = asm_t.asm("push {r4-r7, lr}; " + f"blx 0x{ROUTE_MEM_BASE + ROUTE_MEMCPY:02x}; " + "pop {r4-r7, pc}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in FREE_ADDRESS_T:
|
||||
b, c = asm_t.asm("push {r4-r7, lr}; " + f"blx 0x{ROUTE_MEM_BASE + ROUTE_FREE:02x}; " + "pop {r4-r7, pc}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in MEMSET_ADDRESS_T:
|
||||
b, c = asm_t.asm("push {r4-r7, lr}; " + f"blx 0x{ROUTE_MEM_BASE + ROUTE_MEMSET:02x}; " + "pop {r4-r7, pc}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in CALLOC_ADDRESS_T:
|
||||
b, c = asm_t.asm("push {r4-r7, lr}; " + f"blx 0x{ROUTE_MEM_BASE + ROUTE_CALLOC:02x}; " + "pop {r4-r7, pc}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in REALLOC_ADDRESS_T:
|
||||
b, c = asm_t.asm("push {r4-r7, lr}; " + f"blx 0x{ROUTE_MEM_BASE + ROUTE_REALLOC:02x}; " + "pop {r4-r7, pc}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
for a in MEMMOVE_ADDRESS_T:
|
||||
b, c = asm_t.asm("push {r4-r7, lr}; " + f"blx 0x{ROUTE_MEM_BASE + ROUTE_MEMMOVE:02x}; " + "pop {r4-r7, pc}", a, True)
|
||||
f.write(struct.pack("<LL", a, len(b)) + b)
|
||||
tCount += 1
|
||||
|
||||
f.seek(2)
|
||||
f.write(struct.pack("<L", tCount))
|
||||
f.close()
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue