Merge branch 'dev'

This commit is contained in:
Nguyen Anh Quynh 2022-07-07 23:49:09 +08:00
commit 6c1cbef6ac
85 changed files with 19582 additions and 402 deletions

View File

@ -71,6 +71,18 @@ jobs:
uses: microsoft/setup-msbuild@v1.0.3
with:
vs-version: '16.5'
- name: '🛠️ Win MSVC 32 dev cmd setup'
if: contains(matrix.config.name, 'win32')
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x86
- name: '🛠️ Win MSVC 64 dev cmd setup'
if: contains(matrix.config.name, 'win_amd64')
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: '🛠️ Win build dependencies'
if: contains(matrix.config.name, 'win')

View File

@ -31,7 +31,8 @@ jobs:
arch: x64,
python-arch: x64,
python-ver: '3.8',
name: 'windows-x64 MINGW64',
name: 'windows-x64 MINGW64 shared',
shared: 'yes',
mingw: MINGW64,
mingw-arch: x86_64,
artifact: 'windows_mingw64.7z',
@ -44,7 +45,36 @@ jobs:
arch: x64,
python-arch: x64,
python-ver: '3.8',
name: 'windows-x64 MINGW32',
name: 'windows-x64 MINGW64 static',
shared: 'no',
mingw: MINGW64,
mingw-arch: x86_64,
artifact: 'windows_mingw64.7z',
build_type: 'Debug',
archiver: '7z a',
generators: 'Ninja'
}
- {
os: windows-2019,
arch: x64,
python-arch: x64,
python-ver: '3.8',
name: 'windows-x64 MINGW32 shared',
shared: "yes",
mingw: MINGW32,
mingw-arch: i686,
artifact: 'windows_mingw32.7z',
build_type: 'Debug',
archiver: '7z a',
generators: 'Ninja'
}
- {
os: windows-2019,
arch: x64,
python-arch: x64,
python-ver: '3.8',
name: 'windows-x64 MINGW32 static',
shared: "no",
mingw: MINGW32,
mingw-arch: i686,
artifact: 'windows_mingw32.7z',
@ -124,6 +154,12 @@ jobs:
- name: '🛠️ Win MSVC 64 setup'
if: contains(matrix.config.name, 'MSVC 64')
uses: microsoft/setup-msbuild@v1
- name: '🛠️ Win MSVC 64 dev cmd setup'
if: contains(matrix.config.name, 'MSVC 64')
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: '🚧 Win MSVC 64 build'
if: contains(matrix.config.name, 'MSVC 64')
@ -138,7 +174,8 @@ jobs:
-B . \
-DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \
-G "${{ matrix.config.generators }}" \
-DCMAKE_INSTALL_PREFIX:PATH=instdir
-DCMAKE_INSTALL_PREFIX:PATH=instdir \
-DBUILD_SHARED_LIBS=${{ matrix.config.shared }}
cmake --build . --config ${{ matrix.config.build_type }}
cmake --install . --strip --config ${{ matrix.config.build_type }}
ctest -VV -C ${{ matrix.config.build_type }}
@ -164,7 +201,8 @@ jobs:
-A "win32" \
-DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \
-G "${{ matrix.config.generators }}" \
-DCMAKE_INSTALL_PREFIX:PATH=instdir
-DCMAKE_INSTALL_PREFIX:PATH=instdir \
-DBUILD_SHARED_LIBS=${{ matrix.config.shared }}
cmake --build . --config ${{ matrix.config.build_type }}
cmake --install . --strip --config ${{ matrix.config.build_type }}
ctest -VV -C ${{ matrix.config.build_type }}
@ -191,7 +229,8 @@ jobs:
-B . \
-DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \
-G "${{ matrix.config.generators }}" \
-DCMAKE_INSTALL_PREFIX:PATH=instdir
-DCMAKE_INSTALL_PREFIX:PATH=instdir \
-DBUILD_SHARED_LIBS=${{ matrix.config.shared }}
cmake --build . --config ${{ matrix.config.build_type }}
cmake --install . --strip
ctest -VV -C ${{ matrix.config.build_type }}
@ -277,7 +316,7 @@ jobs:
-DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \
-G "${{ matrix.config.generators }}" \
-DCMAKE_INSTALL_PREFIX:PATH=instdir \
-DBUILD_SHARED_LIB= ${{ matrix.config.shared }}
-DBUILD_SHARED_LIBS=${{ matrix.config.shared }}
cmake --build . --config ${{ matrix.config.build_type }}
cmake --install . --strip
ctest -VV -C ${{ matrix.config.build_type }}

3
.gitignore vendored
View File

@ -10,6 +10,7 @@
*.dll
*.class
*.jar
*.gem
*~
qemu/*-softmmu/
@ -52,7 +53,7 @@ bindings/python/unicorn.egg-info/
bindings/python/unicorn/lib/
bindings/python/unicorn/include/
bindings/python/MANIFEST
target/
/target/
Cargo.lock
config.log

View File

@ -40,11 +40,16 @@ set(UNICORN_VERSION_PATCH 0)
include(bundle_static.cmake)
# Even though we generate shared lib and static archive at the same time, we still support
# using unicorn as a subdirectory so we have to respect BUILD_SHARED_LIBS.
#
# Also we would like users to link a native cmake target, instead of a custom target for better
# compatability.
option(BUILD_SHARED_LIBS "Build shared instead of static library" ${PROJECT_IS_TOP_LEVEL})
option(UNICORN_FUZZ "Enable fuzzing" OFF)
option(UNICORN_BUILD_TESTS "Build unicorn tests" ${PROJECT_IS_TOP_LEVEL})
option(UNICORN_INSTALL "Enable unicorn installation" ${PROJECT_IS_TOP_LEVEL})
set(UNICORN_ARCH "x86;arm;aarch64;riscv;mips;sparc;m68k;ppc;s390x" CACHE STRING "Enabled unicorn architectures")
set(UNICORN_ARCH "x86;arm;aarch64;riscv;mips;sparc;m68k;ppc;s390x;tricore" CACHE STRING "Enabled unicorn architectures")
option(UNICORN_TRACER "Trace unicorn execution" OFF)
foreach(ARCH_LOOP ${UNICORN_ARCH})
@ -119,7 +124,7 @@ else()
string(FIND "${UC_COMPILER_VERSION}" "i686" UC_RET)
if(${UC_RET} GREATER_EQUAL "0")
set(UNICORN_TARGET_ARCH "i386")
set(UNICORN_CFLAGS -m32)
set(UNICORN_CFLAGS -m32 -static-libgcc) # Workaround for github action bugs
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32")
else()
@ -209,6 +214,11 @@ else()
set(UNICORN_TARGET_ARCH "s390")
break()
endif()
string(FIND ${UC_COMPILER_MACRO} "__tricore__" UC_RET)
if (${UC_RET} GREATER_EQUAL "0")
set(UNICORN_TARGET_ARCH "tricore")
break()
endif()
message(FATAL_ERROR "Unknown host compiler: ${CMAKE_C_COMPILER}.")
endwhile(TRUE)
endif()
@ -241,6 +251,9 @@ else()
if (UNICORN_HAS_S390X)
set (EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_S390X ")
endif()
if (UNICORN_HAS_TRICORE)
set (EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_TRICORE ")
endif()
set(EXTRA_CFLAGS "${EXTRA_CFLAGS}-fPIC")
if(ANDROID_ABI)
@ -282,6 +295,9 @@ else()
if(UNICORN_HAS_S390X)
set(TARGET_LIST "${TARGET_LIST}s390x-softmmu, ")
endif()
if (UNICORN_HAS_TRICORE)
set (TARGET_LIST "${TARGET_LIST}tricore-softmmu, ")
endif()
set(TARGET_LIST "${TARGET_LIST} ")
# GEN config-host.mak & target directories
@ -373,6 +389,12 @@ else()
OUTPUT_FILE ${CMAKE_BINARY_DIR}/s390x-softmmu/config-target.h
)
endif()
if (UNICORN_HAS_TRICORE)
execute_process(COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/qemu/scripts/create_config
INPUT_FILE ${CMAKE_BINARY_DIR}/tricore-softmmu/config-target.mak
OUTPUT_FILE ${CMAKE_BINARY_DIR}/tricore-softmmu/config-target.h
)
endif()
add_compile_options(
${UNICORN_CFLAGS}
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/tcg/${UNICORN_TARGET_ARCH}
@ -1034,6 +1056,36 @@ endif()
endif()
if (UNICORN_HAS_TRICORE)
add_library(tricore-softmmu STATIC
${UNICORN_ARCH_COMMON}
qemu/target/tricore/cpu.c
qemu/target/tricore/fpu_helper.c
qemu/target/tricore/helper.c
qemu/target/tricore/op_helper.c
qemu/target/tricore/translate.c
qemu/target/tricore/unicorn.c
)
if(MSVC)
target_compile_options(tricore-softmmu PRIVATE
-DNEED_CPU_H
/FItricore.h
/I${CMAKE_CURRENT_SOURCE_DIR}/msvc/tricore-softmmu
/I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/tricore
)
else()
target_compile_options(tricore-softmmu PRIVATE
-DNEED_CPU_H
-include tricore.h
-I${CMAKE_BINARY_DIR}/tricore-softmmu
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/tricore
)
endif()
endif()
set(UNICORN_SRCS
uc.c
@ -1093,6 +1145,7 @@ if(MSVC)
enable_language(ASM_MASM)
endif()
set(UNICORN_COMMON_SRCS ${UNICORN_COMMON_SRCS} qemu/util/setjmp-wrapper-win32.asm)
set_property(SOURCE qemu/util/setjmp-wrapper-win32.asm PROPERTY LANGUAGE ASM_MASM)
endif()
else()
set(UNICORN_COMMON_SRCS
@ -1110,14 +1163,12 @@ if(NOT MSVC AND NOT ANDROID_ABI)
target_link_libraries(unicorn-common PRIVATE pthread)
endif()
add_library(unicorn ${UNICORN_SRCS})
# For static archive
if (BUILD_SHARED_LIBS)
set(UNICORN_LIB_NAME "unicorn")
else()
set(UNICORN_LIB_NAME "unicorn-static") # This static lib is useless and it's just an intermediate target
add_library(unicorn_static STATIC ${UNICORN_SRCS})
endif()
add_library(${UNICORN_LIB_NAME} ${UNICORN_SRCS})
if(BUILD_SHARED_LIBS)
if(ANDROID_ABI)
file(APPEND ${CMAKE_BINARY_DIR}/adb.sh "adb push ./libunicorn.so /data/local/tmp/build/\n")
@ -1194,6 +1245,13 @@ if (UNICORN_HAS_S390X)
target_link_libraries(s390x-softmmu PRIVATE unicorn-common)
set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_s390x)
endif()
if (UNICORN_HAS_TRICORE)
set(UNICORN_COMPILE_OPTIONS ${UNICORN_COMPILE_OPTIONS} -DUNICORN_HAS_TRICORE)
set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} tricore-softmmu)
set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_tricore)
target_link_libraries(tricore-softmmu unicorn-common)
set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_tricore)
endif()
# Extra tests
set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_mem)
@ -1209,10 +1267,17 @@ target_compile_options(unicorn-common PRIVATE
${UNICORN_COMPILE_OPTIONS}
)
target_compile_options(${UNICORN_LIB_NAME} PRIVATE
target_compile_options(unicorn PRIVATE
${UNICORN_COMPILE_OPTIONS}
)
# For static archive
if (BUILD_SHARED_LIBS)
target_compile_options(unicorn_static PRIVATE
${UNICORN_COMPILE_OPTIONS}
)
endif()
if(MINGW)
set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} pthread)
endif()
@ -1223,29 +1288,46 @@ endif()
if(MSVC)
if(BUILD_SHARED_LIBS)
target_compile_options(${UNICORN_LIB_NAME} PRIVATE
target_compile_options(unicorn PRIVATE
-DUNICORN_SHARED
)
# For static archive
target_link_libraries(unicorn_static PRIVATE
${UNICORN_LINK_LIBRARIES}
)
endif()
target_link_libraries(${UNICORN_LIB_NAME} PRIVATE
target_link_libraries(unicorn PRIVATE
${UNICORN_LINK_LIBRARIES}
)
set_target_properties(${UNICORN_LIB_NAME} PROPERTIES
set_target_properties(unicorn PROPERTIES
VERSION "${UNICORN_VERSION_MAJOR}.${UNICORN_VERSION_MINOR}"
)
else()
target_link_libraries(${UNICORN_LIB_NAME} PRIVATE
target_link_libraries(unicorn PRIVATE
${UNICORN_LINK_LIBRARIES}
m
)
target_link_libraries(${UNICORN_LIB_NAME} PUBLIC
target_link_libraries(unicorn PUBLIC
m
)
set_target_properties(${UNICORN_LIB_NAME} PROPERTIES
# For static archive
if (BUILD_SHARED_LIBS)
target_link_libraries(unicorn_static PUBLIC
m
)
target_link_libraries(unicorn_static PRIVATE
${UNICORN_LINK_LIBRARIES}
m
)
endif()
set_target_properties(unicorn PROPERTIES
VERSION ${UNICORN_VERSION_MAJOR}
SOVERSION ${UNICORN_VERSION_MAJOR}
)
@ -1266,12 +1348,28 @@ else()
)
endif()
target_include_directories(${UNICORN_LIB_NAME} PUBLIC
target_include_directories(unicorn PUBLIC
include
)
if (NOT BUILD_SHARED_LIBS)
bundle_static_library(${UNICORN_LIB_NAME} unicorn) # Bundle our real unicorn static lib
# For static archive
if (BUILD_SHARED_LIBS)
target_include_directories(unicorn_static PUBLIC
include
)
endif()
# Black magic for generating static archives...
if (BUILD_SHARED_LIBS)
if (MSVC)
# Avoid the import lib built by MVSC clash with our archive.
set_target_properties(unicorn PROPERTIES ARCHIVE_OUTPUT_NAME "unicorn-import")
endif()
bundle_static_library(unicorn_static unicorn_archive unicorn)
else()
# Rename the "static" lib to avoid filename clash.
set_target_properties(unicorn PROPERTIES OUTPUT_NAME "unicorn-static")
bundle_static_library(unicorn unicorn_archive unicorn)
endif()
if(UNICORN_FUZZ)
@ -1327,9 +1425,8 @@ if(UNICORN_INSTALL AND NOT MSVC)
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
else()
install(FILES $<TARGET_FILE:unicorn> DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
install(FILES $<TARGET_FILE:unicorn_archive> DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES ${UNICORN_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/unicorn)
file(WRITE ${CMAKE_BINARY_DIR}/unicorn.pc "Name: unicorn\n\
Description: Unicorn emulator engine\n\

View File

@ -1,6 +1,6 @@
[package]
name = "unicorn-engine"
version = "2.0.0-rc7"
version = "2.0.0"
authors = ["Ziqiao Kong", "Lukas Seidel"]
documentation = "https://github.com/unicorn-engine/unicorn/wiki"
edition = "2021"
@ -34,11 +34,10 @@ bitflags = "1.3"
libc = "0.2"
[build-dependencies]
cc = { optional = true, version = "1.0" }
cmake = { optional = true, version = "0.1" }
pkg-config = { optional = true, version = "0.3" }
cc = { version = "1.0" }
cmake = { version = "0.1" }
pkg-config = { version = "0.3" }
[features]
default = ["build_unicorn_cmake"]
build_unicorn_cmake = ["cc", "cmake"]
use_system_unicorn = ["pkg-config"]
default = []
dynamic_linkage = []

View File

@ -1,5 +1,36 @@
This file details the changelog of Unicorn Engine.
-------------------------------
[Version 2.0.0]: July 7th, 2022
Features:
- TriCore Support (#1568)
Fixes/Improvements:
- Build both shared library and static archive as unicorn1 does.
- Misc bindings improvements. #1569 #1600 #1609 #1613 #1616
- Make sure setjmp-setjmp-wrapper-win32 participates in the build. #1604
- Improve Rust bindings build logic.
- Fix wrong python binding for UC_CTL_TB_REMOVE_CACHE
- Flush translation blocks when the count hook is removed.
- Fix unicorn crash when nested `uc_emu_start` deletes a hook
- Fix CPU not fully resumed when writing PC.
- Don't quit TB if `uc_mem_protect` doesn't change the protection of current TB memory.
- Add type annotations for python bindings.
- Add CPUID hook for python bindings. #1618
- Don't repeat memory hooks if there is already an unhandled error. #1618
- Support reads and writes over all Arm SIMD registers #1621
- Fix wrong registers range in python bindings.
- Fix uc_mem_protect on mmio regions
- Fix a UAF caused by hook cache.
- Fix the value collision between UC_MODE_ARMBE8 and UC_MODE_ARM926
Thanks:
@AfoHT @mrexodia @bet4it @lowlyw @ekilmer @ondryaso @QDucasse @PalumboN @uberwoozle
----------------------------------
[Version 2.0.0 rc7]: April 17, 2022

View File

@ -6,7 +6,7 @@ import sys, re, os
INCL_DIR = os.path.join('..', 'include', 'unicorn')
include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h', 'ppc.h', 'riscv.h', 's390x.h', 'unicorn.h' ]
include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h', 'ppc.h', 'riscv.h', 's390x.h', 'tricore.h', 'unicorn.h' ]
template = {
'python': {
@ -24,6 +24,7 @@ template = {
'ppc.h': 'ppc',
'riscv.h': 'riscv',
's390x.h' : 's390x',
'tricore.h' : 'tricore',
'unicorn.h': 'unicorn',
'comment_open': '#',
'comment_close': '',
@ -43,6 +44,7 @@ template = {
'ppc.h': 'ppc',
'riscv.h': 'riscv',
's390x.h' : 's390x',
'tricore.h' : 'tricore',
'unicorn.h': 'unicorn',
'comment_open': '#',
'comment_close': '',
@ -62,6 +64,7 @@ template = {
'ppc.h': 'ppc',
'riscv.h': 'riscv',
's390x.h' : 's390x',
'tricore.h' : 'tricore',
'unicorn.h': 'unicorn',
'comment_open': '//',
'comment_close': '',
@ -81,6 +84,7 @@ template = {
'ppc.h': 'Ppc',
'riscv.h': 'Riscv',
's390x.h' : 'S390x',
'tricore.h' : 'TriCore',
'unicorn.h': 'Unicorn',
'comment_open': '//',
'comment_close': '',
@ -100,6 +104,7 @@ template = {
'ppc.h': 'Ppc',
'riscv.h': 'Riscv',
's390x.h' : 'S390x',
'tricore.h' : 'TriCore',
'unicorn.h': 'Common',
'comment_open': ' //',
'comment_close': '',
@ -119,6 +124,7 @@ template = {
'ppc.h': 'Ppc',
'riscv.h': 'Riscv',
's390x.h' : 'S390x',
'tricore.h' : 'TriCore',
'unicorn.h': 'Unicorn',
'comment_open': '//',
'comment_close': '',

View File

@ -11,13 +11,13 @@ module Common =
let UC_API_MINOR = 0
let UC_API_PATCH = 0
let UC_API_EXTRA = 7
let UC_API_EXTRA = 255
let UC_VERSION_MAJOR = 2
let UC_VERSION_MINOR = 0
let UC_VERSION_PATCH = 0
let UC_VERSION_EXTRA = 7
let UC_VERSION_EXTRA = 255
let UC_SECOND_SCALE = 1000000
let UC_MILISECOND_SCALE = 1000
let UC_ARCH_ARM = 1
@ -29,7 +29,8 @@ module Common =
let UC_ARCH_M68K = 7
let UC_ARCH_RISCV = 8
let UC_ARCH_S390X = 9
let UC_ARCH_MAX = 10
let UC_ARCH_TRICORE = 10
let UC_ARCH_MAX = 11
let UC_MODE_LITTLE_ENDIAN = 0
let UC_MODE_BIG_ENDIAN = 1073741824
@ -38,7 +39,7 @@ module Common =
let UC_MODE_THUMB = 16
let UC_MODE_MCLASS = 32
let UC_MODE_V8 = 64
let UC_MODE_ARMBE8 = 128
let UC_MODE_ARMBE8 = 1024
let UC_MODE_ARM926 = 128
let UC_MODE_ARM946 = 256
let UC_MODE_ARM1176 = 512
@ -139,6 +140,7 @@ module Common =
let UC_CTL_CPU_MODEL = 7
let UC_CTL_TB_REQUEST_CACHE = 8
let UC_CTL_TB_REMOVE_CACHE = 9
let UC_CTL_TB_FLUSH = 10
let UC_PROT_NONE = 0
let UC_PROT_READ = 1

View File

@ -0,0 +1,132 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
open System
[<AutoOpen>]
module TriCore =
// TRICORE CPU
let UC_CPU_TRICORE_TC1796 = 0
let UC_CPU_TRICORE_TC1797 = 1
let UC_CPU_TRICORE_TC27X = 2
let UC_CPU_TRICORE_ENDING = 3
// TRICORE registers
let UC_TRICORE_REG_INVALID = 0
let UC_TRICORE_REG_A0 = 1
let UC_TRICORE_REG_A1 = 2
let UC_TRICORE_REG_A2 = 3
let UC_TRICORE_REG_A3 = 4
let UC_TRICORE_REG_A4 = 5
let UC_TRICORE_REG_A5 = 6
let UC_TRICORE_REG_A6 = 7
let UC_TRICORE_REG_A7 = 8
let UC_TRICORE_REG_A8 = 9
let UC_TRICORE_REG_A9 = 10
let UC_TRICORE_REG_A10 = 11
let UC_TRICORE_REG_A11 = 12
let UC_TRICORE_REG_A12 = 13
let UC_TRICORE_REG_A13 = 14
let UC_TRICORE_REG_A14 = 15
let UC_TRICORE_REG_A15 = 16
let UC_TRICORE_REG_D0 = 17
let UC_TRICORE_REG_D1 = 18
let UC_TRICORE_REG_D2 = 19
let UC_TRICORE_REG_D3 = 20
let UC_TRICORE_REG_D4 = 21
let UC_TRICORE_REG_D5 = 22
let UC_TRICORE_REG_D6 = 23
let UC_TRICORE_REG_D7 = 24
let UC_TRICORE_REG_D8 = 25
let UC_TRICORE_REG_D9 = 26
let UC_TRICORE_REG_D10 = 27
let UC_TRICORE_REG_D11 = 28
let UC_TRICORE_REG_D12 = 29
let UC_TRICORE_REG_D13 = 30
let UC_TRICORE_REG_D14 = 31
let UC_TRICORE_REG_D15 = 32
let UC_TRICORE_REG_PCXI = 33
let UC_TRICORE_REG_PSW = 34
let UC_TRICORE_REG_PSW_USB_C = 35
let UC_TRICORE_REG_PSW_USB_V = 36
let UC_TRICORE_REG_PSW_USB_SV = 37
let UC_TRICORE_REG_PSW_USB_AV = 38
let UC_TRICORE_REG_PSW_USB_SAV = 39
let UC_TRICORE_REG_PC = 40
let UC_TRICORE_REG_SYSCON = 41
let UC_TRICORE_REG_CPU_ID = 42
let UC_TRICORE_REG_BIV = 43
let UC_TRICORE_REG_BTV = 44
let UC_TRICORE_REG_ISP = 45
let UC_TRICORE_REG_ICR = 46
let UC_TRICORE_REG_FCX = 47
let UC_TRICORE_REG_LCX = 48
let UC_TRICORE_REG_COMPAT = 49
let UC_TRICORE_REG_DPR0_U = 50
let UC_TRICORE_REG_DPR1_U = 51
let UC_TRICORE_REG_DPR2_U = 52
let UC_TRICORE_REG_DPR3_U = 53
let UC_TRICORE_REG_DPR0_L = 54
let UC_TRICORE_REG_DPR1_L = 55
let UC_TRICORE_REG_DPR2_L = 56
let UC_TRICORE_REG_DPR3_L = 57
let UC_TRICORE_REG_CPR0_U = 58
let UC_TRICORE_REG_CPR1_U = 59
let UC_TRICORE_REG_CPR2_U = 60
let UC_TRICORE_REG_CPR3_U = 61
let UC_TRICORE_REG_CPR0_L = 62
let UC_TRICORE_REG_CPR1_L = 63
let UC_TRICORE_REG_CPR2_L = 64
let UC_TRICORE_REG_CPR3_L = 65
let UC_TRICORE_REG_DPM0 = 66
let UC_TRICORE_REG_DPM1 = 67
let UC_TRICORE_REG_DPM2 = 68
let UC_TRICORE_REG_DPM3 = 69
let UC_TRICORE_REG_CPM0 = 70
let UC_TRICORE_REG_CPM1 = 71
let UC_TRICORE_REG_CPM2 = 72
let UC_TRICORE_REG_CPM3 = 73
let UC_TRICORE_REG_MMU_CON = 74
let UC_TRICORE_REG_MMU_ASI = 75
let UC_TRICORE_REG_MMU_TVA = 76
let UC_TRICORE_REG_MMU_TPA = 77
let UC_TRICORE_REG_MMU_TPX = 78
let UC_TRICORE_REG_MMU_TFA = 79
let UC_TRICORE_REG_BMACON = 80
let UC_TRICORE_REG_SMACON = 81
let UC_TRICORE_REG_DIEAR = 82
let UC_TRICORE_REG_DIETR = 83
let UC_TRICORE_REG_CCDIER = 84
let UC_TRICORE_REG_MIECON = 85
let UC_TRICORE_REG_PIEAR = 86
let UC_TRICORE_REG_PIETR = 87
let UC_TRICORE_REG_CCPIER = 88
let UC_TRICORE_REG_DBGSR = 89
let UC_TRICORE_REG_EXEVT = 90
let UC_TRICORE_REG_CREVT = 91
let UC_TRICORE_REG_SWEVT = 92
let UC_TRICORE_REG_TR0EVT = 93
let UC_TRICORE_REG_TR1EVT = 94
let UC_TRICORE_REG_DMS = 95
let UC_TRICORE_REG_DCX = 96
let UC_TRICORE_REG_DBGTCR = 97
let UC_TRICORE_REG_CCTRL = 98
let UC_TRICORE_REG_CCNT = 99
let UC_TRICORE_REG_ICNT = 100
let UC_TRICORE_REG_M1CNT = 101
let UC_TRICORE_REG_M2CNT = 102
let UC_TRICORE_REG_M3CNT = 103
let UC_TRICORE_REG_ENDING = 104
let UC_TRICORE_REG_GA0 = 1
let UC_TRICORE_REG_GA1 = 2
let UC_TRICORE_REG_GA8 = 9
let UC_TRICORE_REG_GA9 = 10
let UC_TRICORE_REG_SP = 11
let UC_TRICORE_REG_LR = 12
let UC_TRICORE_REG_IA = 16
let UC_TRICORE_REG_ID = 32

View File

@ -0,0 +1,127 @@
package unicorn
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [tricore_const.go]
const (
// TRICORE CPU
CPU_TRICORE_TC1796 = 0
CPU_TRICORE_TC1797 = 1
CPU_TRICORE_TC27X = 2
CPU_TRICORE_ENDING = 3
// TRICORE registers
TRICORE_REG_INVALID = 0
TRICORE_REG_A0 = 1
TRICORE_REG_A1 = 2
TRICORE_REG_A2 = 3
TRICORE_REG_A3 = 4
TRICORE_REG_A4 = 5
TRICORE_REG_A5 = 6
TRICORE_REG_A6 = 7
TRICORE_REG_A7 = 8
TRICORE_REG_A8 = 9
TRICORE_REG_A9 = 10
TRICORE_REG_A10 = 11
TRICORE_REG_A11 = 12
TRICORE_REG_A12 = 13
TRICORE_REG_A13 = 14
TRICORE_REG_A14 = 15
TRICORE_REG_A15 = 16
TRICORE_REG_D0 = 17
TRICORE_REG_D1 = 18
TRICORE_REG_D2 = 19
TRICORE_REG_D3 = 20
TRICORE_REG_D4 = 21
TRICORE_REG_D5 = 22
TRICORE_REG_D6 = 23
TRICORE_REG_D7 = 24
TRICORE_REG_D8 = 25
TRICORE_REG_D9 = 26
TRICORE_REG_D10 = 27
TRICORE_REG_D11 = 28
TRICORE_REG_D12 = 29
TRICORE_REG_D13 = 30
TRICORE_REG_D14 = 31
TRICORE_REG_D15 = 32
TRICORE_REG_PCXI = 33
TRICORE_REG_PSW = 34
TRICORE_REG_PSW_USB_C = 35
TRICORE_REG_PSW_USB_V = 36
TRICORE_REG_PSW_USB_SV = 37
TRICORE_REG_PSW_USB_AV = 38
TRICORE_REG_PSW_USB_SAV = 39
TRICORE_REG_PC = 40
TRICORE_REG_SYSCON = 41
TRICORE_REG_CPU_ID = 42
TRICORE_REG_BIV = 43
TRICORE_REG_BTV = 44
TRICORE_REG_ISP = 45
TRICORE_REG_ICR = 46
TRICORE_REG_FCX = 47
TRICORE_REG_LCX = 48
TRICORE_REG_COMPAT = 49
TRICORE_REG_DPR0_U = 50
TRICORE_REG_DPR1_U = 51
TRICORE_REG_DPR2_U = 52
TRICORE_REG_DPR3_U = 53
TRICORE_REG_DPR0_L = 54
TRICORE_REG_DPR1_L = 55
TRICORE_REG_DPR2_L = 56
TRICORE_REG_DPR3_L = 57
TRICORE_REG_CPR0_U = 58
TRICORE_REG_CPR1_U = 59
TRICORE_REG_CPR2_U = 60
TRICORE_REG_CPR3_U = 61
TRICORE_REG_CPR0_L = 62
TRICORE_REG_CPR1_L = 63
TRICORE_REG_CPR2_L = 64
TRICORE_REG_CPR3_L = 65
TRICORE_REG_DPM0 = 66
TRICORE_REG_DPM1 = 67
TRICORE_REG_DPM2 = 68
TRICORE_REG_DPM3 = 69
TRICORE_REG_CPM0 = 70
TRICORE_REG_CPM1 = 71
TRICORE_REG_CPM2 = 72
TRICORE_REG_CPM3 = 73
TRICORE_REG_MMU_CON = 74
TRICORE_REG_MMU_ASI = 75
TRICORE_REG_MMU_TVA = 76
TRICORE_REG_MMU_TPA = 77
TRICORE_REG_MMU_TPX = 78
TRICORE_REG_MMU_TFA = 79
TRICORE_REG_BMACON = 80
TRICORE_REG_SMACON = 81
TRICORE_REG_DIEAR = 82
TRICORE_REG_DIETR = 83
TRICORE_REG_CCDIER = 84
TRICORE_REG_MIECON = 85
TRICORE_REG_PIEAR = 86
TRICORE_REG_PIETR = 87
TRICORE_REG_CCPIER = 88
TRICORE_REG_DBGSR = 89
TRICORE_REG_EXEVT = 90
TRICORE_REG_CREVT = 91
TRICORE_REG_SWEVT = 92
TRICORE_REG_TR0EVT = 93
TRICORE_REG_TR1EVT = 94
TRICORE_REG_DMS = 95
TRICORE_REG_DCX = 96
TRICORE_REG_DBGTCR = 97
TRICORE_REG_CCTRL = 98
TRICORE_REG_CCNT = 99
TRICORE_REG_ICNT = 100
TRICORE_REG_M1CNT = 101
TRICORE_REG_M2CNT = 102
TRICORE_REG_M3CNT = 103
TRICORE_REG_ENDING = 104
TRICORE_REG_GA0 = 1
TRICORE_REG_GA1 = 2
TRICORE_REG_GA8 = 9
TRICORE_REG_GA9 = 10
TRICORE_REG_SP = 11
TRICORE_REG_LR = 12
TRICORE_REG_IA = 16
TRICORE_REG_ID = 32
)

View File

@ -6,13 +6,13 @@ const (
API_MINOR = 0
API_PATCH = 0
API_EXTRA = 7
API_EXTRA = 255
VERSION_MAJOR = 2
VERSION_MINOR = 0
VERSION_PATCH = 0
VERSION_EXTRA = 7
VERSION_EXTRA = 255
SECOND_SCALE = 1000000
MILISECOND_SCALE = 1000
ARCH_ARM = 1
@ -24,7 +24,8 @@ const (
ARCH_M68K = 7
ARCH_RISCV = 8
ARCH_S390X = 9
ARCH_MAX = 10
ARCH_TRICORE = 10
ARCH_MAX = 11
MODE_LITTLE_ENDIAN = 0
MODE_BIG_ENDIAN = 1073741824
@ -33,7 +34,7 @@ const (
MODE_THUMB = 16
MODE_MCLASS = 32
MODE_V8 = 64
MODE_ARMBE8 = 128
MODE_ARMBE8 = 1024
MODE_ARM926 = 128
MODE_ARM946 = 256
MODE_ARM1176 = 512
@ -134,6 +135,7 @@ const (
CTL_CPU_MODEL = 7
CTL_TB_REQUEST_CACHE = 8
CTL_TB_REMOVE_CACHE = 9
CTL_TB_FLUSH = 10
PROT_NONE = 0
PROT_READ = 1

View File

@ -0,0 +1,130 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
package unicorn;
public interface TriCoreConst {
// TRICORE CPU
public static final int UC_CPU_TRICORE_TC1796 = 0;
public static final int UC_CPU_TRICORE_TC1797 = 1;
public static final int UC_CPU_TRICORE_TC27X = 2;
public static final int UC_CPU_TRICORE_ENDING = 3;
// TRICORE registers
public static final int UC_TRICORE_REG_INVALID = 0;
public static final int UC_TRICORE_REG_A0 = 1;
public static final int UC_TRICORE_REG_A1 = 2;
public static final int UC_TRICORE_REG_A2 = 3;
public static final int UC_TRICORE_REG_A3 = 4;
public static final int UC_TRICORE_REG_A4 = 5;
public static final int UC_TRICORE_REG_A5 = 6;
public static final int UC_TRICORE_REG_A6 = 7;
public static final int UC_TRICORE_REG_A7 = 8;
public static final int UC_TRICORE_REG_A8 = 9;
public static final int UC_TRICORE_REG_A9 = 10;
public static final int UC_TRICORE_REG_A10 = 11;
public static final int UC_TRICORE_REG_A11 = 12;
public static final int UC_TRICORE_REG_A12 = 13;
public static final int UC_TRICORE_REG_A13 = 14;
public static final int UC_TRICORE_REG_A14 = 15;
public static final int UC_TRICORE_REG_A15 = 16;
public static final int UC_TRICORE_REG_D0 = 17;
public static final int UC_TRICORE_REG_D1 = 18;
public static final int UC_TRICORE_REG_D2 = 19;
public static final int UC_TRICORE_REG_D3 = 20;
public static final int UC_TRICORE_REG_D4 = 21;
public static final int UC_TRICORE_REG_D5 = 22;
public static final int UC_TRICORE_REG_D6 = 23;
public static final int UC_TRICORE_REG_D7 = 24;
public static final int UC_TRICORE_REG_D8 = 25;
public static final int UC_TRICORE_REG_D9 = 26;
public static final int UC_TRICORE_REG_D10 = 27;
public static final int UC_TRICORE_REG_D11 = 28;
public static final int UC_TRICORE_REG_D12 = 29;
public static final int UC_TRICORE_REG_D13 = 30;
public static final int UC_TRICORE_REG_D14 = 31;
public static final int UC_TRICORE_REG_D15 = 32;
public static final int UC_TRICORE_REG_PCXI = 33;
public static final int UC_TRICORE_REG_PSW = 34;
public static final int UC_TRICORE_REG_PSW_USB_C = 35;
public static final int UC_TRICORE_REG_PSW_USB_V = 36;
public static final int UC_TRICORE_REG_PSW_USB_SV = 37;
public static final int UC_TRICORE_REG_PSW_USB_AV = 38;
public static final int UC_TRICORE_REG_PSW_USB_SAV = 39;
public static final int UC_TRICORE_REG_PC = 40;
public static final int UC_TRICORE_REG_SYSCON = 41;
public static final int UC_TRICORE_REG_CPU_ID = 42;
public static final int UC_TRICORE_REG_BIV = 43;
public static final int UC_TRICORE_REG_BTV = 44;
public static final int UC_TRICORE_REG_ISP = 45;
public static final int UC_TRICORE_REG_ICR = 46;
public static final int UC_TRICORE_REG_FCX = 47;
public static final int UC_TRICORE_REG_LCX = 48;
public static final int UC_TRICORE_REG_COMPAT = 49;
public static final int UC_TRICORE_REG_DPR0_U = 50;
public static final int UC_TRICORE_REG_DPR1_U = 51;
public static final int UC_TRICORE_REG_DPR2_U = 52;
public static final int UC_TRICORE_REG_DPR3_U = 53;
public static final int UC_TRICORE_REG_DPR0_L = 54;
public static final int UC_TRICORE_REG_DPR1_L = 55;
public static final int UC_TRICORE_REG_DPR2_L = 56;
public static final int UC_TRICORE_REG_DPR3_L = 57;
public static final int UC_TRICORE_REG_CPR0_U = 58;
public static final int UC_TRICORE_REG_CPR1_U = 59;
public static final int UC_TRICORE_REG_CPR2_U = 60;
public static final int UC_TRICORE_REG_CPR3_U = 61;
public static final int UC_TRICORE_REG_CPR0_L = 62;
public static final int UC_TRICORE_REG_CPR1_L = 63;
public static final int UC_TRICORE_REG_CPR2_L = 64;
public static final int UC_TRICORE_REG_CPR3_L = 65;
public static final int UC_TRICORE_REG_DPM0 = 66;
public static final int UC_TRICORE_REG_DPM1 = 67;
public static final int UC_TRICORE_REG_DPM2 = 68;
public static final int UC_TRICORE_REG_DPM3 = 69;
public static final int UC_TRICORE_REG_CPM0 = 70;
public static final int UC_TRICORE_REG_CPM1 = 71;
public static final int UC_TRICORE_REG_CPM2 = 72;
public static final int UC_TRICORE_REG_CPM3 = 73;
public static final int UC_TRICORE_REG_MMU_CON = 74;
public static final int UC_TRICORE_REG_MMU_ASI = 75;
public static final int UC_TRICORE_REG_MMU_TVA = 76;
public static final int UC_TRICORE_REG_MMU_TPA = 77;
public static final int UC_TRICORE_REG_MMU_TPX = 78;
public static final int UC_TRICORE_REG_MMU_TFA = 79;
public static final int UC_TRICORE_REG_BMACON = 80;
public static final int UC_TRICORE_REG_SMACON = 81;
public static final int UC_TRICORE_REG_DIEAR = 82;
public static final int UC_TRICORE_REG_DIETR = 83;
public static final int UC_TRICORE_REG_CCDIER = 84;
public static final int UC_TRICORE_REG_MIECON = 85;
public static final int UC_TRICORE_REG_PIEAR = 86;
public static final int UC_TRICORE_REG_PIETR = 87;
public static final int UC_TRICORE_REG_CCPIER = 88;
public static final int UC_TRICORE_REG_DBGSR = 89;
public static final int UC_TRICORE_REG_EXEVT = 90;
public static final int UC_TRICORE_REG_CREVT = 91;
public static final int UC_TRICORE_REG_SWEVT = 92;
public static final int UC_TRICORE_REG_TR0EVT = 93;
public static final int UC_TRICORE_REG_TR1EVT = 94;
public static final int UC_TRICORE_REG_DMS = 95;
public static final int UC_TRICORE_REG_DCX = 96;
public static final int UC_TRICORE_REG_DBGTCR = 97;
public static final int UC_TRICORE_REG_CCTRL = 98;
public static final int UC_TRICORE_REG_CCNT = 99;
public static final int UC_TRICORE_REG_ICNT = 100;
public static final int UC_TRICORE_REG_M1CNT = 101;
public static final int UC_TRICORE_REG_M2CNT = 102;
public static final int UC_TRICORE_REG_M3CNT = 103;
public static final int UC_TRICORE_REG_ENDING = 104;
public static final int UC_TRICORE_REG_GA0 = 1;
public static final int UC_TRICORE_REG_GA1 = 2;
public static final int UC_TRICORE_REG_GA8 = 9;
public static final int UC_TRICORE_REG_GA9 = 10;
public static final int UC_TRICORE_REG_SP = 11;
public static final int UC_TRICORE_REG_LR = 12;
public static final int UC_TRICORE_REG_IA = 16;
public static final int UC_TRICORE_REG_ID = 32;
}

View File

@ -821,5 +821,11 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
*/
public native void context_restore(long context);
/**
* Set the emulated cpu model.
*
* @param cpu_model CPU model type (see UC_CPU_*).
*/
public native void ctl_set_cpu_model(int cpu_model);
}

View File

@ -8,13 +8,13 @@ public interface UnicornConst {
public static final int UC_API_MINOR = 0;
public static final int UC_API_PATCH = 0;
public static final int UC_API_EXTRA = 7;
public static final int UC_API_EXTRA = 255;
public static final int UC_VERSION_MAJOR = 2;
public static final int UC_VERSION_MINOR = 0;
public static final int UC_VERSION_PATCH = 0;
public static final int UC_VERSION_EXTRA = 7;
public static final int UC_VERSION_EXTRA = 255;
public static final int UC_SECOND_SCALE = 1000000;
public static final int UC_MILISECOND_SCALE = 1000;
public static final int UC_ARCH_ARM = 1;
@ -26,7 +26,8 @@ public interface UnicornConst {
public static final int UC_ARCH_M68K = 7;
public static final int UC_ARCH_RISCV = 8;
public static final int UC_ARCH_S390X = 9;
public static final int UC_ARCH_MAX = 10;
public static final int UC_ARCH_TRICORE = 10;
public static final int UC_ARCH_MAX = 11;
public static final int UC_MODE_LITTLE_ENDIAN = 0;
public static final int UC_MODE_BIG_ENDIAN = 1073741824;
@ -35,7 +36,7 @@ public interface UnicornConst {
public static final int UC_MODE_THUMB = 16;
public static final int UC_MODE_MCLASS = 32;
public static final int UC_MODE_V8 = 64;
public static final int UC_MODE_ARMBE8 = 128;
public static final int UC_MODE_ARMBE8 = 1024;
public static final int UC_MODE_ARM926 = 128;
public static final int UC_MODE_ARM946 = 256;
public static final int UC_MODE_ARM1176 = 512;
@ -136,6 +137,7 @@ public interface UnicornConst {
public static final int UC_CTL_CPU_MODEL = 7;
public static final int UC_CTL_TB_REQUEST_CACHE = 8;
public static final int UC_CTL_TB_REMOVE_CACHE = 9;
public static final int UC_CTL_TB_FLUSH = 10;
public static final int UC_PROT_NONE = 0;
public static final int UC_PROT_READ = 1;

View File

@ -779,3 +779,17 @@ JNIEXPORT void JNICALL Java_unicorn_Unicorn_context_1restore
throwException(env, err);
}
}
/*
* Class: unicorn_Unicorn
* Method: ctl_set_cpu_model
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_unicorn_Unicorn_ctl_1set_1cpu_1model
(JNIEnv *env, jobject self, jint cpu_model) {
uc_engine *eng = getEngine(env, self);
uc_err err = uc_ctl_set_cpu_model(eng, cpu_model);
if (err != UC_ERR_OK) {
throwException(env, err);
}
}

View File

@ -0,0 +1,132 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
unit TriCoreConst;
interface
const
// TRICORE CPU
UC_CPU_TRICORE_TC1796 = 0;
UC_CPU_TRICORE_TC1797 = 1;
UC_CPU_TRICORE_TC27X = 2;
UC_CPU_TRICORE_ENDING = 3;
// TRICORE registers
UC_TRICORE_REG_INVALID = 0;
UC_TRICORE_REG_A0 = 1;
UC_TRICORE_REG_A1 = 2;
UC_TRICORE_REG_A2 = 3;
UC_TRICORE_REG_A3 = 4;
UC_TRICORE_REG_A4 = 5;
UC_TRICORE_REG_A5 = 6;
UC_TRICORE_REG_A6 = 7;
UC_TRICORE_REG_A7 = 8;
UC_TRICORE_REG_A8 = 9;
UC_TRICORE_REG_A9 = 10;
UC_TRICORE_REG_A10 = 11;
UC_TRICORE_REG_A11 = 12;
UC_TRICORE_REG_A12 = 13;
UC_TRICORE_REG_A13 = 14;
UC_TRICORE_REG_A14 = 15;
UC_TRICORE_REG_A15 = 16;
UC_TRICORE_REG_D0 = 17;
UC_TRICORE_REG_D1 = 18;
UC_TRICORE_REG_D2 = 19;
UC_TRICORE_REG_D3 = 20;
UC_TRICORE_REG_D4 = 21;
UC_TRICORE_REG_D5 = 22;
UC_TRICORE_REG_D6 = 23;
UC_TRICORE_REG_D7 = 24;
UC_TRICORE_REG_D8 = 25;
UC_TRICORE_REG_D9 = 26;
UC_TRICORE_REG_D10 = 27;
UC_TRICORE_REG_D11 = 28;
UC_TRICORE_REG_D12 = 29;
UC_TRICORE_REG_D13 = 30;
UC_TRICORE_REG_D14 = 31;
UC_TRICORE_REG_D15 = 32;
UC_TRICORE_REG_PCXI = 33;
UC_TRICORE_REG_PSW = 34;
UC_TRICORE_REG_PSW_USB_C = 35;
UC_TRICORE_REG_PSW_USB_V = 36;
UC_TRICORE_REG_PSW_USB_SV = 37;
UC_TRICORE_REG_PSW_USB_AV = 38;
UC_TRICORE_REG_PSW_USB_SAV = 39;
UC_TRICORE_REG_PC = 40;
UC_TRICORE_REG_SYSCON = 41;
UC_TRICORE_REG_CPU_ID = 42;
UC_TRICORE_REG_BIV = 43;
UC_TRICORE_REG_BTV = 44;
UC_TRICORE_REG_ISP = 45;
UC_TRICORE_REG_ICR = 46;
UC_TRICORE_REG_FCX = 47;
UC_TRICORE_REG_LCX = 48;
UC_TRICORE_REG_COMPAT = 49;
UC_TRICORE_REG_DPR0_U = 50;
UC_TRICORE_REG_DPR1_U = 51;
UC_TRICORE_REG_DPR2_U = 52;
UC_TRICORE_REG_DPR3_U = 53;
UC_TRICORE_REG_DPR0_L = 54;
UC_TRICORE_REG_DPR1_L = 55;
UC_TRICORE_REG_DPR2_L = 56;
UC_TRICORE_REG_DPR3_L = 57;
UC_TRICORE_REG_CPR0_U = 58;
UC_TRICORE_REG_CPR1_U = 59;
UC_TRICORE_REG_CPR2_U = 60;
UC_TRICORE_REG_CPR3_U = 61;
UC_TRICORE_REG_CPR0_L = 62;
UC_TRICORE_REG_CPR1_L = 63;
UC_TRICORE_REG_CPR2_L = 64;
UC_TRICORE_REG_CPR3_L = 65;
UC_TRICORE_REG_DPM0 = 66;
UC_TRICORE_REG_DPM1 = 67;
UC_TRICORE_REG_DPM2 = 68;
UC_TRICORE_REG_DPM3 = 69;
UC_TRICORE_REG_CPM0 = 70;
UC_TRICORE_REG_CPM1 = 71;
UC_TRICORE_REG_CPM2 = 72;
UC_TRICORE_REG_CPM3 = 73;
UC_TRICORE_REG_MMU_CON = 74;
UC_TRICORE_REG_MMU_ASI = 75;
UC_TRICORE_REG_MMU_TVA = 76;
UC_TRICORE_REG_MMU_TPA = 77;
UC_TRICORE_REG_MMU_TPX = 78;
UC_TRICORE_REG_MMU_TFA = 79;
UC_TRICORE_REG_BMACON = 80;
UC_TRICORE_REG_SMACON = 81;
UC_TRICORE_REG_DIEAR = 82;
UC_TRICORE_REG_DIETR = 83;
UC_TRICORE_REG_CCDIER = 84;
UC_TRICORE_REG_MIECON = 85;
UC_TRICORE_REG_PIEAR = 86;
UC_TRICORE_REG_PIETR = 87;
UC_TRICORE_REG_CCPIER = 88;
UC_TRICORE_REG_DBGSR = 89;
UC_TRICORE_REG_EXEVT = 90;
UC_TRICORE_REG_CREVT = 91;
UC_TRICORE_REG_SWEVT = 92;
UC_TRICORE_REG_TR0EVT = 93;
UC_TRICORE_REG_TR1EVT = 94;
UC_TRICORE_REG_DMS = 95;
UC_TRICORE_REG_DCX = 96;
UC_TRICORE_REG_DBGTCR = 97;
UC_TRICORE_REG_CCTRL = 98;
UC_TRICORE_REG_CCNT = 99;
UC_TRICORE_REG_ICNT = 100;
UC_TRICORE_REG_M1CNT = 101;
UC_TRICORE_REG_M2CNT = 102;
UC_TRICORE_REG_M3CNT = 103;
UC_TRICORE_REG_ENDING = 104;
UC_TRICORE_REG_GA0 = 1;
UC_TRICORE_REG_GA1 = 2;
UC_TRICORE_REG_GA8 = 9;
UC_TRICORE_REG_GA9 = 10;
UC_TRICORE_REG_SP = 11;
UC_TRICORE_REG_LR = 12;
UC_TRICORE_REG_IA = 16;
UC_TRICORE_REG_ID = 32;
implementation
end.

View File

@ -9,13 +9,13 @@ const UC_API_MAJOR = 2;
UC_API_MINOR = 0;
UC_API_PATCH = 0;
UC_API_EXTRA = 7;
UC_API_EXTRA = 255;
UC_VERSION_MAJOR = 2;
UC_VERSION_MINOR = 0;
UC_VERSION_PATCH = 0;
UC_VERSION_EXTRA = 7;
UC_VERSION_EXTRA = 255;
UC_SECOND_SCALE = 1000000;
UC_MILISECOND_SCALE = 1000;
UC_ARCH_ARM = 1;
@ -27,7 +27,8 @@ const UC_API_MAJOR = 2;
UC_ARCH_M68K = 7;
UC_ARCH_RISCV = 8;
UC_ARCH_S390X = 9;
UC_ARCH_MAX = 10;
UC_ARCH_TRICORE = 10;
UC_ARCH_MAX = 11;
UC_MODE_LITTLE_ENDIAN = 0;
UC_MODE_BIG_ENDIAN = 1073741824;
@ -36,7 +37,7 @@ const UC_API_MAJOR = 2;
UC_MODE_THUMB = 16;
UC_MODE_MCLASS = 32;
UC_MODE_V8 = 64;
UC_MODE_ARMBE8 = 128;
UC_MODE_ARMBE8 = 1024;
UC_MODE_ARM926 = 128;
UC_MODE_ARM946 = 256;
UC_MODE_ARM1176 = 512;
@ -137,6 +138,7 @@ const UC_API_MAJOR = 2;
UC_CTL_CPU_MODEL = 7;
UC_CTL_TB_REQUEST_CACHE = 8;
UC_CTL_TB_REMOVE_CACHE = 9;
UC_CTL_TB_FLUSH = 10;
UC_PROT_NONE = 0;
UC_PROT_READ = 1;

View File

@ -0,0 +1,57 @@
#!/usr/bin/env python
'''
Created for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
'''
from __future__ import print_function
from unicorn import *
from unicorn.tricore_const import *
# code to be emulated
TRICORE_CODE = b"\x82\x11\xbb\x00\x00\x08" # mov d0, #0x1; mov.u d0, #0x8000
# memory address where emulation starts
ADDRESS = 0x10000
# callback for tracing basic blocks
def hook_block(uc, address, size, user_data):
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
# Test TriCore
def test_tricore():
print("Emulate TriCore code")
try:
# Initialize emulator in TriCore mode
mu = Uc(UC_ARCH_TRICORE, UC_MODE_LITTLE_ENDIAN)
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, TRICORE_CODE)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block)
# tracing one instruction at ADDRESS with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(TRICORE_CODE))
# now print out some registers
print(">>> Emulation done. Below is the CPU context")
r0 = mu.reg_read(UC_TRICORE_REG_D0)
print(">>> D0 = 0x%x" %r0)
except UcError as e:
print("ERROR: %s" % e)
if __name__ == '__main__':
test_tricore()

View File

@ -29,17 +29,17 @@ SRC_DIR = os.path.join(ROOT_DIR, 'src')
UC_DIR = os.path.join(ROOT_DIR, '../..')
BUILD_DIR = os.path.join(UC_DIR, 'build_python')
VERSION = "2.0.0rc7"
VERSION = "2.0.0"
if SYSTEM == 'darwin':
LIBRARY_FILE = "libunicorn.dylib"
STATIC_LIBRARY_FILE = None
LIBRARY_FILE = "libunicorn.2.dylib"
STATIC_LIBRARY_FILE = "libunicorn.a"
elif SYSTEM in ('win32', 'cygwin'):
LIBRARY_FILE = "unicorn.dll"
STATIC_LIBRARY_FILE = "unicorn.lib"
else:
LIBRARY_FILE = "libunicorn.so"
STATIC_LIBRARY_FILE = None
LIBRARY_FILE = "libunicorn.so.2"
STATIC_LIBRARY_FILE = "libunicorn.a"
def clean_bins():
shutil.rmtree(LIBS_DIR, ignore_errors=True)
@ -124,7 +124,7 @@ def build_libraries():
obj_dir = os.path.join(BUILD_DIR, conf)
shutil.copy(os.path.join(obj_dir, LIBRARY_FILE), LIBS_DIR)
shutil.copy(os.path.join(obj_dir, STATIC_LIBRARY_FILE), LIBS_DIR)
shutil.copy(os.path.join(BUILD_DIR, STATIC_LIBRARY_FILE), LIBS_DIR)
else:
# platform description refs at https://docs.python.org/2/library/sys.html#sys.platform
if not os.path.exists(BUILD_DIR):
@ -140,15 +140,8 @@ def build_libraries():
subprocess.check_call(["cmake", "--build", ".", "-j" + threads])
shutil.copy(LIBRARY_FILE, LIBS_DIR)
try:
# static library may fail to build on windows if user doesn't have visual studio installed. this is fine.
if STATIC_LIBRARY_FILE is not None:
shutil.copy(STATIC_LIBRARY_FILE, LIBS_DIR)
except FileNotFoundError:
print('Warning: Could not build static library file! This build is not appropriate for a binary distribution')
# enforce this
if 'upload' in sys.argv:
sys.exit(1)
shutil.copy(STATIC_LIBRARY_FILE, LIBS_DIR)
os.chdir(cwd)

View File

@ -0,0 +1,124 @@
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [tricore_const.py]
# TRICORE CPU
UC_CPU_TRICORE_TC1796 = 0
UC_CPU_TRICORE_TC1797 = 1
UC_CPU_TRICORE_TC27X = 2
UC_CPU_TRICORE_ENDING = 3
# TRICORE registers
UC_TRICORE_REG_INVALID = 0
UC_TRICORE_REG_A0 = 1
UC_TRICORE_REG_A1 = 2
UC_TRICORE_REG_A2 = 3
UC_TRICORE_REG_A3 = 4
UC_TRICORE_REG_A4 = 5
UC_TRICORE_REG_A5 = 6
UC_TRICORE_REG_A6 = 7
UC_TRICORE_REG_A7 = 8
UC_TRICORE_REG_A8 = 9
UC_TRICORE_REG_A9 = 10
UC_TRICORE_REG_A10 = 11
UC_TRICORE_REG_A11 = 12
UC_TRICORE_REG_A12 = 13
UC_TRICORE_REG_A13 = 14
UC_TRICORE_REG_A14 = 15
UC_TRICORE_REG_A15 = 16
UC_TRICORE_REG_D0 = 17
UC_TRICORE_REG_D1 = 18
UC_TRICORE_REG_D2 = 19
UC_TRICORE_REG_D3 = 20
UC_TRICORE_REG_D4 = 21
UC_TRICORE_REG_D5 = 22
UC_TRICORE_REG_D6 = 23
UC_TRICORE_REG_D7 = 24
UC_TRICORE_REG_D8 = 25
UC_TRICORE_REG_D9 = 26
UC_TRICORE_REG_D10 = 27
UC_TRICORE_REG_D11 = 28
UC_TRICORE_REG_D12 = 29
UC_TRICORE_REG_D13 = 30
UC_TRICORE_REG_D14 = 31
UC_TRICORE_REG_D15 = 32
UC_TRICORE_REG_PCXI = 33
UC_TRICORE_REG_PSW = 34
UC_TRICORE_REG_PSW_USB_C = 35
UC_TRICORE_REG_PSW_USB_V = 36
UC_TRICORE_REG_PSW_USB_SV = 37
UC_TRICORE_REG_PSW_USB_AV = 38
UC_TRICORE_REG_PSW_USB_SAV = 39
UC_TRICORE_REG_PC = 40
UC_TRICORE_REG_SYSCON = 41
UC_TRICORE_REG_CPU_ID = 42
UC_TRICORE_REG_BIV = 43
UC_TRICORE_REG_BTV = 44
UC_TRICORE_REG_ISP = 45
UC_TRICORE_REG_ICR = 46
UC_TRICORE_REG_FCX = 47
UC_TRICORE_REG_LCX = 48
UC_TRICORE_REG_COMPAT = 49
UC_TRICORE_REG_DPR0_U = 50
UC_TRICORE_REG_DPR1_U = 51
UC_TRICORE_REG_DPR2_U = 52
UC_TRICORE_REG_DPR3_U = 53
UC_TRICORE_REG_DPR0_L = 54
UC_TRICORE_REG_DPR1_L = 55
UC_TRICORE_REG_DPR2_L = 56
UC_TRICORE_REG_DPR3_L = 57
UC_TRICORE_REG_CPR0_U = 58
UC_TRICORE_REG_CPR1_U = 59
UC_TRICORE_REG_CPR2_U = 60
UC_TRICORE_REG_CPR3_U = 61
UC_TRICORE_REG_CPR0_L = 62
UC_TRICORE_REG_CPR1_L = 63
UC_TRICORE_REG_CPR2_L = 64
UC_TRICORE_REG_CPR3_L = 65
UC_TRICORE_REG_DPM0 = 66
UC_TRICORE_REG_DPM1 = 67
UC_TRICORE_REG_DPM2 = 68
UC_TRICORE_REG_DPM3 = 69
UC_TRICORE_REG_CPM0 = 70
UC_TRICORE_REG_CPM1 = 71
UC_TRICORE_REG_CPM2 = 72
UC_TRICORE_REG_CPM3 = 73
UC_TRICORE_REG_MMU_CON = 74
UC_TRICORE_REG_MMU_ASI = 75
UC_TRICORE_REG_MMU_TVA = 76
UC_TRICORE_REG_MMU_TPA = 77
UC_TRICORE_REG_MMU_TPX = 78
UC_TRICORE_REG_MMU_TFA = 79
UC_TRICORE_REG_BMACON = 80
UC_TRICORE_REG_SMACON = 81
UC_TRICORE_REG_DIEAR = 82
UC_TRICORE_REG_DIETR = 83
UC_TRICORE_REG_CCDIER = 84
UC_TRICORE_REG_MIECON = 85
UC_TRICORE_REG_PIEAR = 86
UC_TRICORE_REG_PIETR = 87
UC_TRICORE_REG_CCPIER = 88
UC_TRICORE_REG_DBGSR = 89
UC_TRICORE_REG_EXEVT = 90
UC_TRICORE_REG_CREVT = 91
UC_TRICORE_REG_SWEVT = 92
UC_TRICORE_REG_TR0EVT = 93
UC_TRICORE_REG_TR1EVT = 94
UC_TRICORE_REG_DMS = 95
UC_TRICORE_REG_DCX = 96
UC_TRICORE_REG_DBGTCR = 97
UC_TRICORE_REG_CCTRL = 98
UC_TRICORE_REG_CCNT = 99
UC_TRICORE_REG_ICNT = 100
UC_TRICORE_REG_M1CNT = 101
UC_TRICORE_REG_M2CNT = 102
UC_TRICORE_REG_M3CNT = 103
UC_TRICORE_REG_ENDING = 104
UC_TRICORE_REG_GA0 = 1
UC_TRICORE_REG_GA1 = 2
UC_TRICORE_REG_GA8 = 9
UC_TRICORE_REG_GA9 = 10
UC_TRICORE_REG_SP = 11
UC_TRICORE_REG_LR = 12
UC_TRICORE_REG_IA = 16
UC_TRICORE_REG_ID = 32

View File

@ -1,9 +1,10 @@
# Unicorn Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com>
from __future__ import annotations
import ctypes
import ctypes.util
import distutils.sysconfig
from functools import wraps
from typing import Any, Callable, List, Tuple, Union
import pkg_resources
import inspect
import os.path
@ -21,11 +22,11 @@ _python2 = sys.version_info[0] < 3
if _python2:
range = xrange
_lib = { 'darwin': 'libunicorn.dylib',
_lib = { 'darwin': 'libunicorn.2.dylib',
'win32': 'unicorn.dll',
'cygwin': 'cygunicorn.dll',
'linux': 'libunicorn.so',
'linux2': 'libunicorn.so' }
'linux': 'libunicorn.so.2',
'linux2': 'libunicorn.so.2' }
# Windows DLL in dependency order
@ -57,12 +58,12 @@ def _load_win_support(path):
if sys.platform in ('win32', 'cygwin'):
_load_win_support('')
def _load_lib(path):
def _load_lib(path, lib_name):
try:
if sys.platform in ('win32', 'cygwin'):
_load_win_support(path)
lib_file = os.path.join(path, _lib.get(sys.platform, 'libunicorn.so'))
lib_file = os.path.join(path, lib_name)
dll = ctypes.cdll.LoadLibrary(lib_file)
#print('SUCCESS')
return dll
@ -93,12 +94,26 @@ _path_list = [os.getenv('LIBUNICORN_PATH', None),
for _path in _path_list:
if _path is None: continue
_uc = _load_lib(_path)
if _uc is not None: break
else:
_uc = _load_lib(_path, _lib.get(sys.platform, "libunicorn.so"))
if _uc is not None:
break
# Try to search old unicorn1 library without SONAME
if _uc is None:
for _path in _path_list:
if _path is None:
continue
_uc = _load_lib(_path, "libunicorn.so")
if _uc is not None:
# In this case, show a warning for users
print("Found an old style dynamic library libunicorn.so, consider checking your installation", file=sys.stderr)
break
if _uc is None:
raise ImportError("ERROR: fail to load the dynamic library.")
__version__ = "%u.%u.%u" % (uc.UC_VERSION_MAJOR, uc.UC_VERSION_MINOR, uc.UC_VERSION_EXTRA)
__version__ = "%u.%u.%u" % (uc.UC_VERSION_MAJOR, uc.UC_VERSION_MINOR, uc.UC_VERSION_PATCH)
# setup all the function prototype
def _setup_prototype(lib, fname, restype, *argtypes):
@ -184,6 +199,7 @@ UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(
)
UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_void_p)
UC_HOOK_INSN_SYS_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p)
UC_HOOK_INSN_CPUID_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_void_p)
UC_MMIO_READ_CB = ctypes.CFUNCTYPE(
ctypes.c_uint64, uc_engine, ctypes.c_uint64, ctypes.c_int, ctypes.c_void_p
)
@ -226,6 +242,13 @@ def version_bind():
def uc_arch_supported(query):
return _uc.uc_arch_supported(query)
ARMCPReg = Tuple[int, int, int, int, int, int, int]
ARM64CPReg = Tuple[int, int, int, int, int]
ARMCPRegValue = Tuple[int, int, int, int, int, int, int, int]
ARM64CPRegValue = Tuple[int, int, int, int, int, int]
X86MMRReg = Tuple[int, int, int, int]
X86FPReg = Tuple[int, int]
# uc_reg_read/write and uc_context_reg_read/write.
def reg_read(reg_read_func, arch, reg_id, opt=None):
if arch == uc.UC_ARCH_X86:
@ -285,7 +308,7 @@ def reg_read(reg_read_func, arch, reg_id, opt=None):
raise UcError(status)
return reg.val
elif reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1):
elif reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or reg_id in range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1):
reg = uc_arm64_neon128()
status = reg_read_func(reg_id, ctypes.byref(reg))
if status != uc.UC_ERR_OK:
@ -330,7 +353,7 @@ def reg_write(reg_write_func, arch, reg_id, value):
reg.value = value[1]
if arch == uc.UC_ARCH_ARM64:
if reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1):
if reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or reg_id in range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1):
reg = uc_arm64_neon128()
reg.low_qword = value & 0xffffffffffffffff
reg.high_qword = value >> 64
@ -484,7 +507,7 @@ class UcCleanupManager(object):
class Uc(object):
_cleanup = UcCleanupManager()
def __init__(self, arch, mode):
def __init__(self, arch: int, mode: int):
# verify version compatibility with the core before doing anything
(major, minor, _combined) = uc_version()
# print("core version =", uc_version())
@ -508,7 +531,7 @@ class Uc(object):
self._hook_exception = None # The exception raised in a hook
@staticmethod
def release_handle(uch):
def release_handle(uch: ctypes.CDLL):
if uch:
try:
status = _uc.uc_close(uch)
@ -518,7 +541,7 @@ class Uc(object):
pass
# emulate from @begin, and stop when reaching address @until
def emu_start(self, begin, until, timeout=0, count=0):
def emu_start(self, begin: int, until: int, timeout: int=0, count: int=0) -> None:
self._hook_exception = None
status = _uc.uc_emu_start(self._uch, begin, until, timeout, count)
if status != uc.UC_ERR_OK:
@ -528,29 +551,29 @@ class Uc(object):
raise self._hook_exception
# stop emulation
def emu_stop(self):
def emu_stop(self) -> None:
status = _uc.uc_emu_stop(self._uch)
if status != uc.UC_ERR_OK:
raise UcError(status)
# return the value of a register
def reg_read(self, reg_id, opt=None):
# return the value of a register, for @opt parameter, specify int for x86 msr, tuple for arm cp/neon regs.
def reg_read(self, reg_id: int, opt: Union[None, int, ARMCPReg, ARM64CPReg]=None) -> Union[int, X86MMRReg, X86FPReg]:
return reg_read(functools.partial(_uc.uc_reg_read, self._uch), self._arch, reg_id, opt)
# write to a register
def reg_write(self, reg_id, value):
# write to a register, tuple for arm cp regs.
def reg_write(self, reg_id: Union[int, ARMCPRegValue, ARM64CPRegValue, X86MMRReg, X86FPReg], value: int):
return reg_write(functools.partial(_uc.uc_reg_write, self._uch), self._arch, reg_id, value)
# read from MSR - X86 only
def msr_read(self, msr_id):
def msr_read(self, msr_id: int):
return self.reg_read(x86_const.UC_X86_REG_MSR, msr_id)
# write to MSR - X86 only
def msr_write(self, msr_id, value):
def msr_write(self, msr_id, value: int):
return self.reg_write(x86_const.UC_X86_REG_MSR, (msr_id, value))
# read data from memory
def mem_read(self, address, size):
def mem_read(self, address: int, size: int):
data = ctypes.create_string_buffer(size)
status = _uc.uc_mem_read(self._uch, address, data, size)
if status != uc.UC_ERR_OK:
@ -558,7 +581,7 @@ class Uc(object):
return bytearray(data)
# write to memory
def mem_write(self, address, data):
def mem_write(self, address: int, data: bytes):
status = _uc.uc_mem_write(self._uch, address, data, len(data))
if status != uc.UC_ERR_OK:
raise UcError(status)
@ -571,7 +594,9 @@ class Uc(object):
(cb, data) = self._callbacks[user_data]
cb(self, offset, size, value, data)
def mmio_map(self, address, size, read_cb, user_data_read, write_cb, user_data_write):
def mmio_map(self, address: int, size: int,
read_cb: UC_MMIO_READ_TYPE, user_data_read: Any,
write_cb: UC_MMIO_WRITE_TYPE, user_data_write: Any):
internal_read_cb = ctypes.cast(UC_MMIO_READ_CB(self._mmio_map_read_cb), UC_MMIO_READ_CB)
internal_write_cb = ctypes.cast(UC_MMIO_WRITE_CB(self._mmio_map_write_cb), UC_MMIO_WRITE_CB)
@ -591,31 +616,31 @@ class Uc(object):
self._ctype_cbs.append(internal_write_cb)
# map a range of memory
def mem_map(self, address, size, perms=uc.UC_PROT_ALL):
def mem_map(self, address: int, size: int, perms: int=uc.UC_PROT_ALL):
status = _uc.uc_mem_map(self._uch, address, size, perms)
if status != uc.UC_ERR_OK:
raise UcError(status)
# map a range of memory from a raw host memory address
def mem_map_ptr(self, address, size, perms, ptr):
def mem_map_ptr(self, address: int, size: int, perms: int, ptr: int):
status = _uc.uc_mem_map_ptr(self._uch, address, size, perms, ptr)
if status != uc.UC_ERR_OK:
raise UcError(status)
# unmap a range of memory
def mem_unmap(self, address, size):
def mem_unmap(self, address: int, size: int):
status = _uc.uc_mem_unmap(self._uch, address, size)
if status != uc.UC_ERR_OK:
raise UcError(status)
# protect a range of memory
def mem_protect(self, address, size, perms=uc.UC_PROT_ALL):
def mem_protect(self, address: int, size: int, perms: int=uc.UC_PROT_ALL):
status = _uc.uc_mem_protect(self._uch, address, size, perms)
if status != uc.UC_ERR_OK:
raise UcError(status)
# return CPU mode at runtime
def query(self, query_mode):
def query(self, query_mode: int):
result = ctypes.c_size_t(0)
status = _uc.uc_query(self._uch, query_mode, ctypes.byref(result))
if status != uc.UC_ERR_OK:
@ -690,7 +715,13 @@ class Uc(object):
(cb, data) = self._callbacks[user_data]
cb(self, data)
def ctl(self, control, *args):
@_catch_hook_exception
def _hook_insn_cpuid_cb(self, handle: int, user_data: int) -> int:
# call user's callback with self object
(cb, data) = self._callbacks[user_data]
return cb(self, data)
def ctl(self, control: int, *args):
status = _uc.uc_ctl(self._uch, control, *args)
if status != uc.UC_ERR_OK:
raise UcError(status)
@ -717,6 +748,11 @@ class Uc(object):
arg = ctp(val)
self.ctl(self.__ctl_w(ctl, 1), arg)
def __ctl_w_2_arg(self, ctl, val1, val2, ctp1, ctp2):
arg1 = ctp1(val1)
arg2 = ctp2(val2)
self.ctl(self.__ctl_w(ctl, 2), arg1, arg2)
def __ctl_rw_1_1_arg(self, ctl, val, ctp1, ctp2):
arg1 = ctp1(val)
arg2 = ctp2()
@ -729,7 +765,7 @@ class Uc(object):
def ctl_get_page_size(self):
return self.__ctl_r_1_arg(uc.UC_CTL_UC_PAGE_SIZE, ctypes.c_uint32)
def ctl_set_page_size(self, val):
def ctl_set_page_size(self, val: int):
self.__ctl_w_1_arg(uc.UC_CTL_UC_PAGE_SIZE, val, ctypes.c_uint32)
def ctl_get_arch(self):
@ -738,7 +774,7 @@ class Uc(object):
def ctl_get_timeout(self):
return self.__ctl_r_1_arg(uc.UC_CTL_UC_TIMEOUT, ctypes.c_uint64)
def ctl_exits_enabled(self, val):
def ctl_exits_enabled(self, val: bool):
self.__ctl_w_1_arg(uc.UC_CTL_UC_USE_EXITS, val, ctypes.c_int)
def ctl_get_exits_cnt(self):
@ -750,7 +786,7 @@ class Uc(object):
self.ctl(self.__ctl_r(uc.UC_CTL_UC_EXITS, 2), ctypes.cast(arr, ctypes.c_void_p), ctypes.c_size_t(l))
return [i for i in arr]
def ctl_set_exits(self, exits):
def ctl_set_exits(self, exits: List[int]):
arr = (ctypes.c_uint64 * len(exits))()
for idx, exit in enumerate(exits):
arr[idx] = exit
@ -759,17 +795,20 @@ class Uc(object):
def ctl_get_cpu_model(self):
return self.__ctl_r_1_arg(uc.UC_CTL_CPU_MODEL, ctypes.c_int)
def ctl_set_cpu_model(self, val):
def ctl_set_cpu_model(self, val: int):
self.__ctl_w_1_arg(uc.UC_CTL_CPU_MODEL, val, ctypes.c_int)
def ctl_remove_cache(self, addr):
self.__ctl_w_1_arg(uc.UC_CTL_TB_REMOVE_CACHE, addr, ctypes.c_uint64)
def ctl_remove_cache(self, addr: int, end: int):
self.__ctl_w_2_arg(uc.UC_CTL_TB_REMOVE_CACHE, addr, end, ctypes.c_uint64, ctypes.c_uint64)
def ctl_request_cache(self, addr):
def ctl_request_cache(self, addr: int):
return self.__ctl_rw_1_1_arg(uc.UC_CTL_TB_REQUEST_CACHE, addr, ctypes.c_uint64, uc_tb)
def ctl_flush_tb(self):
self.ctl(self.__ctl_w(uc.UC_CTL_TB_FLUSH, 0))
# add a hook
def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0, arg2=0):
def hook_add(self, htype: int, callback: UC_HOOK_CALLBACK_TYPE , user_data: Any=None, begin: int=1, end: int=0, arg1: int=0, arg2: int=0):
_h2 = uc_hook_h()
# save callback & user_data
@ -785,6 +824,8 @@ class Uc(object):
cb = ctypes.cast(UC_HOOK_INSN_OUT_CB(self._hook_insn_out_cb), UC_HOOK_INSN_OUT_CB)
if arg1 in (x86_const.UC_X86_INS_SYSCALL, x86_const.UC_X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction
cb = ctypes.cast(UC_HOOK_INSN_SYSCALL_CB(self._hook_insn_syscall_cb), UC_HOOK_INSN_SYSCALL_CB)
if arg1 == x86_const.UC_X86_INS_CPUID: # CPUID instruction
cb = ctypes.cast(UC_HOOK_INSN_CPUID_CB(self._hook_insn_cpuid_cb), UC_HOOK_INSN_CPUID_CB)
if arg1 in (arm64_const.UC_ARM64_INS_MRS, arm64_const.UC_ARM64_INS_MSR, arm64_const.UC_ARM64_INS_SYS, arm64_const.UC_ARM64_INS_SYSL):
cb = ctypes.cast(UC_HOOK_INSN_SYS_CB(self._hook_insn_sys_cb), UC_HOOK_INSN_SYS_CB)
status = _uc.uc_hook_add(
@ -861,7 +902,7 @@ class Uc(object):
return _h2.value
# delete a hook
def hook_del(self, h):
def hook_del(self, h: int):
_h = uc_hook_h(h)
status = _uc.uc_hook_del(self._uch, _h)
if status != uc.UC_ERR_OK:
@ -876,12 +917,12 @@ class Uc(object):
return context
def context_update(self, context):
def context_update(self, context: UcContext):
status = _uc.uc_context_save(self._uch, context.context)
if status != uc.UC_ERR_OK:
raise UcError(status)
def context_restore(self, context):
def context_restore(self, context: UcContext):
status = _uc.uc_context_restore(self._uch, context.context)
if status != uc.UC_ERR_OK:
raise UcError(status)
@ -956,6 +997,34 @@ class UcContext:
if self._to_free:
_uc.uc_context_free(self._context)
UC_HOOK_CODE_TYPE = Callable[[Uc, int, int, Any], None]
UC_HOOK_INSN_INVALID_TYPE = Callable[[Uc, Any], bool]
UC_HOOK_MEM_INVALID_TYPE = Callable[[Uc, int, int, int, int, Any], bool]
UC_HOOK_MEM_ACCESS_TYPE = Callable[[Uc, int, int, int, int, Any], None]
UC_HOOK_INTR_TYPE = Callable[[Uc, int, Any], None]
UC_HOOK_INSN_IN_TYPE = Callable[[Uc, int, int, Any], int]
UC_HOOK_INSN_OUT_TYPE = Callable[[Uc, int, int, int, Any], None]
UC_HOOK_INSN_SYSCALL_TYPE = Callable[[Uc, Any], None]
UC_HOOK_INSN_SYS_TYPE = Callable[[Uc, int, Tuple[int, int, int, int, int, int], Any], int]
UC_HOOK_INSN_CPUID_TYPE = Callable[[Uc, Any], int]
UC_MMIO_READ_TYPE = Callable[[Uc, int, int, Any], int]
UC_MMIO_WRITE_TYPE = Callable[[Uc, int, int, int, Any], None]
UC_HOOK_EDGE_GEN_TYPE = Callable[[Uc, uc_tb, uc_tb, Any], None]
UC_HOOK_TCG_OPCODE_TYPE = Callable[[Uc, int, int, int, Any], None]
UC_HOOK_CALLBACK_TYPE = Union[
UC_HOOK_CODE_TYPE,
UC_HOOK_INSN_INVALID_TYPE,
UC_HOOK_MEM_INVALID_TYPE,
UC_HOOK_MEM_ACCESS_TYPE,
UC_HOOK_INSN_IN_TYPE,
UC_HOOK_INSN_OUT_TYPE,
UC_HOOK_INSN_SYSCALL_TYPE,
UC_HOOK_INSN_SYS_TYPE,
UC_HOOK_INSN_CPUID_TYPE,
UC_HOOK_EDGE_GEN_TYPE,
UC_HOOK_TCG_OPCODE_TYPE
]
# print out debugging info
def debug():

View File

@ -4,13 +4,13 @@ UC_API_MAJOR = 2
UC_API_MINOR = 0
UC_API_PATCH = 0
UC_API_EXTRA = 7
UC_API_EXTRA = 255
UC_VERSION_MAJOR = 2
UC_VERSION_MINOR = 0
UC_VERSION_PATCH = 0
UC_VERSION_EXTRA = 7
UC_VERSION_EXTRA = 255
UC_SECOND_SCALE = 1000000
UC_MILISECOND_SCALE = 1000
UC_ARCH_ARM = 1
@ -22,7 +22,8 @@ UC_ARCH_SPARC = 6
UC_ARCH_M68K = 7
UC_ARCH_RISCV = 8
UC_ARCH_S390X = 9
UC_ARCH_MAX = 10
UC_ARCH_TRICORE = 10
UC_ARCH_MAX = 11
UC_MODE_LITTLE_ENDIAN = 0
UC_MODE_BIG_ENDIAN = 1073741824
@ -31,7 +32,7 @@ UC_MODE_ARM = 0
UC_MODE_THUMB = 16
UC_MODE_MCLASS = 32
UC_MODE_V8 = 64
UC_MODE_ARMBE8 = 128
UC_MODE_ARMBE8 = 1024
UC_MODE_ARM926 = 128
UC_MODE_ARM946 = 256
UC_MODE_ARM1176 = 512
@ -132,6 +133,7 @@ UC_CTL_UC_EXITS = 6
UC_CTL_CPU_MODEL = 7
UC_CTL_TB_REQUEST_CACHE = 8
UC_CTL_TB_REMOVE_CACHE = 9
UC_CTL_TB_FLUSH = 10
UC_PROT_NONE = 0
UC_PROT_READ = 1

View File

@ -5,7 +5,7 @@
# Use bundle install && rake to install gem and test
install: gen_const
cd unicorn_gem && rake build
cd unicorn_gem && gem install --local pkg/unicorn-engine-1.0.1.gem
cd unicorn_gem && gem install --local pkg/unicorn-engine-2.0.0.gem
gen_const:
cd .. && python3 const_generator.py ruby

View File

@ -3,6 +3,7 @@ require 'mkmf'
extension_name = 'unicorn_engine'
dir_config(extension_name)
pkg_config('unicorn')
have_library('unicorn')
create_makefile(extension_name)

View File

@ -0,0 +1,127 @@
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [tricore_const.rb]
module UnicornEngine
# TRICORE CPU
UC_CPU_TRICORE_TC1796 = 0
UC_CPU_TRICORE_TC1797 = 1
UC_CPU_TRICORE_TC27X = 2
UC_CPU_TRICORE_ENDING = 3
# TRICORE registers
UC_TRICORE_REG_INVALID = 0
UC_TRICORE_REG_A0 = 1
UC_TRICORE_REG_A1 = 2
UC_TRICORE_REG_A2 = 3
UC_TRICORE_REG_A3 = 4
UC_TRICORE_REG_A4 = 5
UC_TRICORE_REG_A5 = 6
UC_TRICORE_REG_A6 = 7
UC_TRICORE_REG_A7 = 8
UC_TRICORE_REG_A8 = 9
UC_TRICORE_REG_A9 = 10
UC_TRICORE_REG_A10 = 11
UC_TRICORE_REG_A11 = 12
UC_TRICORE_REG_A12 = 13
UC_TRICORE_REG_A13 = 14
UC_TRICORE_REG_A14 = 15
UC_TRICORE_REG_A15 = 16
UC_TRICORE_REG_D0 = 17
UC_TRICORE_REG_D1 = 18
UC_TRICORE_REG_D2 = 19
UC_TRICORE_REG_D3 = 20
UC_TRICORE_REG_D4 = 21
UC_TRICORE_REG_D5 = 22
UC_TRICORE_REG_D6 = 23
UC_TRICORE_REG_D7 = 24
UC_TRICORE_REG_D8 = 25
UC_TRICORE_REG_D9 = 26
UC_TRICORE_REG_D10 = 27
UC_TRICORE_REG_D11 = 28
UC_TRICORE_REG_D12 = 29
UC_TRICORE_REG_D13 = 30
UC_TRICORE_REG_D14 = 31
UC_TRICORE_REG_D15 = 32
UC_TRICORE_REG_PCXI = 33
UC_TRICORE_REG_PSW = 34
UC_TRICORE_REG_PSW_USB_C = 35
UC_TRICORE_REG_PSW_USB_V = 36
UC_TRICORE_REG_PSW_USB_SV = 37
UC_TRICORE_REG_PSW_USB_AV = 38
UC_TRICORE_REG_PSW_USB_SAV = 39
UC_TRICORE_REG_PC = 40
UC_TRICORE_REG_SYSCON = 41
UC_TRICORE_REG_CPU_ID = 42
UC_TRICORE_REG_BIV = 43
UC_TRICORE_REG_BTV = 44
UC_TRICORE_REG_ISP = 45
UC_TRICORE_REG_ICR = 46
UC_TRICORE_REG_FCX = 47
UC_TRICORE_REG_LCX = 48
UC_TRICORE_REG_COMPAT = 49
UC_TRICORE_REG_DPR0_U = 50
UC_TRICORE_REG_DPR1_U = 51
UC_TRICORE_REG_DPR2_U = 52
UC_TRICORE_REG_DPR3_U = 53
UC_TRICORE_REG_DPR0_L = 54
UC_TRICORE_REG_DPR1_L = 55
UC_TRICORE_REG_DPR2_L = 56
UC_TRICORE_REG_DPR3_L = 57
UC_TRICORE_REG_CPR0_U = 58
UC_TRICORE_REG_CPR1_U = 59
UC_TRICORE_REG_CPR2_U = 60
UC_TRICORE_REG_CPR3_U = 61
UC_TRICORE_REG_CPR0_L = 62
UC_TRICORE_REG_CPR1_L = 63
UC_TRICORE_REG_CPR2_L = 64
UC_TRICORE_REG_CPR3_L = 65
UC_TRICORE_REG_DPM0 = 66
UC_TRICORE_REG_DPM1 = 67
UC_TRICORE_REG_DPM2 = 68
UC_TRICORE_REG_DPM3 = 69
UC_TRICORE_REG_CPM0 = 70
UC_TRICORE_REG_CPM1 = 71
UC_TRICORE_REG_CPM2 = 72
UC_TRICORE_REG_CPM3 = 73
UC_TRICORE_REG_MMU_CON = 74
UC_TRICORE_REG_MMU_ASI = 75
UC_TRICORE_REG_MMU_TVA = 76
UC_TRICORE_REG_MMU_TPA = 77
UC_TRICORE_REG_MMU_TPX = 78
UC_TRICORE_REG_MMU_TFA = 79
UC_TRICORE_REG_BMACON = 80
UC_TRICORE_REG_SMACON = 81
UC_TRICORE_REG_DIEAR = 82
UC_TRICORE_REG_DIETR = 83
UC_TRICORE_REG_CCDIER = 84
UC_TRICORE_REG_MIECON = 85
UC_TRICORE_REG_PIEAR = 86
UC_TRICORE_REG_PIETR = 87
UC_TRICORE_REG_CCPIER = 88
UC_TRICORE_REG_DBGSR = 89
UC_TRICORE_REG_EXEVT = 90
UC_TRICORE_REG_CREVT = 91
UC_TRICORE_REG_SWEVT = 92
UC_TRICORE_REG_TR0EVT = 93
UC_TRICORE_REG_TR1EVT = 94
UC_TRICORE_REG_DMS = 95
UC_TRICORE_REG_DCX = 96
UC_TRICORE_REG_DBGTCR = 97
UC_TRICORE_REG_CCTRL = 98
UC_TRICORE_REG_CCNT = 99
UC_TRICORE_REG_ICNT = 100
UC_TRICORE_REG_M1CNT = 101
UC_TRICORE_REG_M2CNT = 102
UC_TRICORE_REG_M3CNT = 103
UC_TRICORE_REG_ENDING = 104
UC_TRICORE_REG_GA0 = 1
UC_TRICORE_REG_GA1 = 2
UC_TRICORE_REG_GA8 = 9
UC_TRICORE_REG_GA9 = 10
UC_TRICORE_REG_SP = 11
UC_TRICORE_REG_LR = 12
UC_TRICORE_REG_IA = 16
UC_TRICORE_REG_ID = 32
end

View File

@ -6,13 +6,13 @@ module UnicornEngine
UC_API_MINOR = 0
UC_API_PATCH = 0
UC_API_EXTRA = 7
UC_API_EXTRA = 255
UC_VERSION_MAJOR = 2
UC_VERSION_MINOR = 0
UC_VERSION_PATCH = 0
UC_VERSION_EXTRA = 7
UC_VERSION_EXTRA = 255
UC_SECOND_SCALE = 1000000
UC_MILISECOND_SCALE = 1000
UC_ARCH_ARM = 1
@ -24,7 +24,8 @@ module UnicornEngine
UC_ARCH_M68K = 7
UC_ARCH_RISCV = 8
UC_ARCH_S390X = 9
UC_ARCH_MAX = 10
UC_ARCH_TRICORE = 10
UC_ARCH_MAX = 11
UC_MODE_LITTLE_ENDIAN = 0
UC_MODE_BIG_ENDIAN = 1073741824
@ -33,7 +34,7 @@ module UnicornEngine
UC_MODE_THUMB = 16
UC_MODE_MCLASS = 32
UC_MODE_V8 = 64
UC_MODE_ARMBE8 = 128
UC_MODE_ARMBE8 = 1024
UC_MODE_ARM926 = 128
UC_MODE_ARM946 = 256
UC_MODE_ARM1176 = 512
@ -134,6 +135,7 @@ module UnicornEngine
UC_CTL_CPU_MODEL = 7
UC_CTL_TB_REQUEST_CACHE = 8
UC_CTL_TB_REMOVE_CACHE = 9
UC_CTL_TB_FLUSH = 10
UC_PROT_NONE = 0
UC_PROT_READ = 1

View File

@ -1,3 +1,3 @@
module Unicorn
VERSION = "1.0.1"
VERSION = "2.0.0"
end

View File

@ -12,7 +12,7 @@ fn main() {
let arm_code32: Vec<u8> = vec![0x17, 0x00, 0x40, 0xe2]; // sub r0, #23
let mut unicorn = Unicorn::new(Arch::ARM, Mode::LITTLE_ENDIAN).expect("failed to initialize Unicorn instance");
let mut emu = unicorn.borrow();
let emu = &mut unicorn;
emu.mem_map(0x1000, 0x4000, Permission::ALL).expect("failed to map code page");
emu.mem_write(0x1000, &arm_code32).expect("failed to write instructions");
@ -20,11 +20,11 @@ fn main() {
emu.reg_write(RegisterARM::R5, 1337).expect("failed write R5");
let _ = emu.emu_start(0x1000, (0x1000 + arm_code32.len()) as u64, 10 * SECOND_SCALE, 1000);
assert_eq!(emu.reg_read(RegisterARM::R0, Ok(100));
assert_eq!(emu.reg_read(RegisterARM::R5, Ok(1337));
assert_eq!(emu.reg_read(RegisterARM::R0), Ok(100));
assert_eq!(emu.reg_read(RegisterARM::R5), Ok(1337));
}
```
Further sample code can be found in ```tests/unicorn.rs```.
Further sample code can be found in [tests](../../tests/rust-tests/main.rs).
## Usage
@ -32,7 +32,7 @@ Add this to your `Cargo.toml`:
```
[dependencies]
unicorn-engine = "2.0.0-rc3"
unicorn-engine = "2.0.0"
```
## Acknowledgements

View File

@ -1,23 +1,16 @@
#[cfg(feature = "use_system_unicorn")]
use pkg_config;
#[cfg(feature = "build_unicorn_cmake")]
use std::env;
#[cfg(feature = "build_unicorn_cmake")]
use std::path::PathBuf;
#[cfg(feature = "build_unicorn_cmake")]
use std::process::Command;
#[cfg(all(feature = "build_unicorn_cmake"))]
fn ninja_available() -> bool {
Command::new("ninja").arg("--version").spawn().is_ok()
}
#[cfg(all(feature = "build_unicorn_cmake"))]
fn msvc_cmake_tools_available() -> bool {
Command::new("cmake").arg("--version").spawn().is_ok() && ninja_available()
}
#[cfg(all(feature = "build_unicorn_cmake"))]
fn setup_env_msvc(compiler: &cc::Tool) {
// If PATH already contains what we need, skip this
if msvc_cmake_tools_available() {
@ -27,20 +20,24 @@ fn setup_env_msvc(compiler: &cc::Tool) {
let target = env::var("TARGET").unwrap();
let devenv = cc::windows_registry::find_tool(target.as_str(), "devenv");
let tool_root: PathBuf = match devenv {
Some(devenv_tool) => {
devenv_tool.path().parent().unwrap().to_path_buf()
},
Some(devenv_tool) => devenv_tool.path().parent().unwrap().to_path_buf(),
None => {
// if devenv (i.e. Visual Studio) was not found, assume compiler is
// from standalone Build Tools and look there instead.
// this should be done properly in cc crate, but for now it's not.
let tools_name = std::ffi::OsStr::new("BuildTools");
let compiler_path = compiler.path().to_path_buf();
compiler_path.iter().find(|x| *x == tools_name)
compiler_path
.iter()
.find(|x| *x == tools_name)
.expect("Failed to find devenv or Build Tools");
compiler_path.iter().take_while(|x| *x != tools_name)
.collect::<PathBuf>().join(tools_name).join(r"Common7\IDE")
},
compiler_path
.iter()
.take_while(|x| *x != tools_name)
.collect::<PathBuf>()
.join(tools_name)
.join(r"Common7\IDE")
}
};
let cmake_pkg_dir = tool_root.join(r"CommonExtensions\Microsoft\CMake");
let cmake_path = cmake_pkg_dir.join(r"CMake\bin\cmake.exe");
@ -63,7 +60,6 @@ fn setup_env_msvc(compiler: &cc::Tool) {
}
}
#[cfg(feature = "build_unicorn_cmake")]
fn build_with_cmake() {
let uc_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let compiler = cc::Build::new().get_compiler();
@ -92,14 +88,22 @@ fn build_with_cmake() {
// unicorn's CMakeLists.txt doesn't properly support 'install', so we use
// the build artifacts from the build directory, which cmake crate sets
// to "<out_dir>/build/"
let dst = config.define("BUILD_SHARED_LIBS", "OFF")
let dst = config
.define("UNICORN_BUILD_TESTS", "OFF")
.define("UNICORN_INSTALL", "OFF")
.no_build_target(true).build();
println!("cargo:rustc-link-search=native={}", dst.join("build").display());
.no_build_target(true)
.build();
println!(
"cargo:rustc-link-search=native={}",
dst.join("build").display()
);
// Lazymio(@wtdcode): Why do I stick to static link? See: https://github.com/rust-lang/cargo/issues/5077
println!("cargo:rustc-link-lib=static=unicorn");
// Lazymio(@wtdcode): Dynamic link may break. See: https://github.com/rust-lang/cargo/issues/5077
if cfg!(feature = "dynamic_linkage") {
println!("cargo:rustc-link-lib=dylib=unicorn");
} else {
println!("cargo:rustc-link-lib=static=unicorn");
}
if !compiler.is_like_msvc() {
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=m");
@ -107,14 +111,26 @@ fn build_with_cmake() {
}
fn main() {
if cfg!(feature = "use_system_unicorn") {
#[cfg(feature = "use_system_unicorn")]
pkg_config::Config::new()
.atleast_version("2")
.probe("unicorn")
.expect("Could not find system unicorn2");
} else {
#[cfg(feature = "build_unicorn_cmake")]
build_with_cmake();
}
match pkg_config::Config::new()
.atleast_version("2")
.cargo_metadata(false)
.probe("unicorn")
{
Ok(lib) => {
for dir in lib.link_paths {
println!("cargo:rustc-link-search=native={}", dir.to_str().unwrap());
}
if cfg!(feature = "dynamic_linkage") {
println!("cargo:rustc-link-lib=dylib=unicorn");
} else {
println!("cargo:rustc-link-arg=-Wl,-allow-multiple-definition");
println!("cargo:rustc-link-lib=static=unicorn");
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=m");
}
}
Err(_) => {
build_with_cmake();
}
};
}

View File

@ -305,14 +305,14 @@ pub enum RegisterARM64 {
VBAR_EL3 = 289,
CP_REG = 290,
ENDING = 291,
}
impl RegisterARM64 {
// alias registers
// (assoc) IP0 = 215,
// (assoc) IP1 = 216,
// (assoc) FP = 1,
// (assoc) LR = 2,
}
impl RegisterARM64 {
pub const IP0: RegisterARM64 = RegisterARM64::X16;
pub const IP1: RegisterARM64 = RegisterARM64::X17;
pub const FP: RegisterARM64 = RegisterARM64::X29;

View File

@ -188,10 +188,7 @@ pub extern "C" fn insn_in_hook_proxy<D, F>(
(user_data.callback)(&mut user_data.uc, port, size);
}
pub extern "C" fn insn_invalid_hook_proxy<D, F>(
uc: uc_handle,
user_data: *mut UcHook<D, F>,
) -> bool
pub extern "C" fn insn_invalid_hook_proxy<D, F>(uc: uc_handle, user_data: *mut UcHook<D, F>) -> bool
where
F: FnMut(&mut crate::Unicorn<D>) -> bool,
{

View File

@ -42,11 +42,12 @@ mod ppc;
mod riscv;
mod s390x;
mod sparc;
mod tricore;
mod x86;
pub use crate::{
arm::*, arm64::*, m68k::*, mips::*, ppc::*, riscv::*, s390x::*, sparc::*, unicorn_const::*,
x86::*,
arm::*, arm64::*, m68k::*, mips::*, ppc::*, riscv::*, s390x::*, sparc::*, tricore::*,
unicorn_const::*, x86::*,
};
use alloc::{boxed::Box, rc::Rc, vec::Vec};
@ -544,7 +545,6 @@ impl<'a, D> Unicorn<'a, D> {
///
/// This adds safe support for registers >64 bit (GDTR/IDTR, XMM, YMM, ZMM, ST (x86); Q, V (arm64)).
pub fn reg_read_long<T: Into<i32>>(&self, regid: T) -> Result<Box<[u8]>, uc_error> {
let err: uc_error;
let boxed: Box<[u8]>;
let mut value: Vec<u8>;
let curr_reg_id = regid.into();
@ -586,7 +586,7 @@ impl<'a, D> Unicorn<'a, D> {
return Err(uc_error::ARCH);
}
err = unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) };
let err: uc_error = unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) };
if err == uc_error::OK {
boxed = value.into_boxed_slice();
@ -900,15 +900,13 @@ impl<'a, D> Unicorn<'a, D> {
///
/// `hook` is the value returned by `add_*_hook` functions.
pub fn remove_hook(&mut self, hook: ffi::uc_hook) -> Result<(), uc_error> {
let err: uc_error;
// drop the hook
let inner = self.inner_mut();
inner
.hooks
.retain(|(hook_ptr, _hook_impl)| hook_ptr != &hook);
err = unsafe { ffi::uc_hook_del(inner.handle, hook) };
let err: uc_error = unsafe { ffi::uc_hook_del(inner.handle, hook) };
if err == uc_error::OK {
Ok(())
@ -1041,6 +1039,7 @@ impl<'a, D> Unicorn<'a, D> {
Arch::PPC => RegisterPPC::PC as i32,
Arch::RISCV => RegisterRISCV::PC as i32,
Arch::S390X => RegisterS390X::PC as i32,
Arch::TRICORE => RegisterTRICORE::PC as i32,
Arch::MAX => panic!("Illegal Arch specified"),
};
self.reg_read(reg)
@ -1060,6 +1059,7 @@ impl<'a, D> Unicorn<'a, D> {
Arch::PPC => RegisterPPC::PC as i32,
Arch::RISCV => RegisterRISCV::PC as i32,
Arch::S390X => RegisterS390X::PC as i32,
Arch::TRICORE => RegisterTRICORE::PC as i32,
Arch::MAX => panic!("Illegal Arch specified"),
};
self.reg_write(reg, value)

View File

@ -0,0 +1,137 @@
// TRICORE registers
#[repr(C)]
#[derive(PartialEq, Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum RegisterTRICORE {
INVALID = 0,
A0 = 1,
A1 = 2,
A2 = 3,
A3 = 4,
A4 = 5,
A5 = 6,
A6 = 7,
A7 = 8,
A8 = 9,
A9 = 10,
A10 = 11,
A11 = 12,
A12 = 13,
A13 = 14,
A14 = 15,
A15 = 16,
D0 = 17,
D1 = 18,
D2 = 19,
D3 = 20,
D4 = 21,
D5 = 22,
D6 = 23,
D7 = 24,
D8 = 25,
D9 = 26,
D10 = 27,
D11 = 28,
D12 = 29,
D13 = 30,
D14 = 31,
D15 = 32,
PCXI = 33,
PSW = 34,
PSW_USB_C = 35,
PSW_USB_V = 36,
PSW_USB_SV = 37,
PSW_USB_AV = 38,
PSW_USB_SAV = 39,
PC = 40,
SYSCON = 41,
CPU_ID = 42,
BIV = 43,
BTV = 44,
ISP = 45,
ICR = 46,
FCX = 47,
LCX = 48,
COMPAT = 49,
DPR0_U = 50,
DPR1_U = 51,
DPR2_U = 52,
DPR3_U = 53,
DPR0_L = 54,
DPR1_L = 55,
DPR2_L = 56,
DPR3_L = 57,
CPR0_U = 58,
CPR1_U = 59,
CPR2_U = 60,
CPR3_U = 61,
CPR0_L = 62,
CPR1_L = 63,
CPR2_L = 64,
CPR3_L = 65,
DPM0 = 66,
DPM1 = 67,
DPM2 = 68,
DPM3 = 69,
CPM0 = 70,
CPM1 = 71,
CPM2 = 72,
CPM3 = 73,
MMU_CON = 74,
MMU_ASI = 75,
MMU_TVA = 76,
MMU_TPA = 77,
MMU_TPX = 78,
MMU_TFA = 79,
BMACON = 80,
SMACON = 81,
DIEAR = 82,
DIETR = 83,
CCDIER = 84,
MIECON = 85,
PIEAR = 86,
PIETR = 87,
CCPIER = 88,
DBGSR = 89,
EXEVT = 90,
CREVT = 91,
SWEVT = 92,
TR0EVT = 93,
TR1EVT = 94,
DMS = 95,
DCX = 96,
DBGTCR = 97,
CCTRL = 98,
CCNT = 99,
ICNT = 100,
M1CNT = 101,
M2CNT = 102,
M3CNT = 103,
ENDING = 104,
}
impl RegisterTRICORE {
// alias registers
// (assoc) GA0 = 1,
// (assoc) GA1 = 2,
// (assoc) GA8 = 9,
// (assoc) GA9 = 10,
// (assoc) SP = 11,
// (assoc) LR = 12,
// (assoc) IA = 16,
// (assoc) ID = 32,
pub const GA0: RegisterTRICORE = RegisterTRICORE::A0;
pub const GA1: RegisterTRICORE = RegisterTRICORE::A1;
pub const GA8: RegisterTRICORE = RegisterTRICORE::A8;
pub const GA9: RegisterTRICORE = RegisterTRICORE::A9;
pub const SP: RegisterTRICORE = RegisterTRICORE::A10;
pub const LR: RegisterTRICORE = RegisterTRICORE::A11;
pub const IA: RegisterTRICORE = RegisterTRICORE::A15;
pub const ID: RegisterTRICORE = RegisterTRICORE::D15;
}
impl From<RegisterTRICORE> for i32 {
fn from(r: RegisterTRICORE) -> Self {
r as i32
}
}

View File

@ -5,7 +5,8 @@ pub const API_MAJOR: u64 = 2;
pub const API_MINOR: u64 = 0;
pub const VERSION_MAJOR: u64 = 2;
pub const VERSION_MINOR: u64 = 0;
pub const VERSION_EXTRA: u64 = 6;
pub const VERSION_PATCH: u64 = 0;
pub const VERSION_EXTRA: u64 = 7;
pub const SECOND_SCALE: u64 = 1_000_000;
pub const MILISECOND_SCALE: u64 = 1_000;
@ -129,7 +130,8 @@ pub enum Arch {
M68K = 7,
RISCV = 8,
S390X = 9,
MAX = 10,
TRICORE = 10,
MAX = 11,
}
impl TryFrom<usize> for Arch {
@ -146,6 +148,7 @@ impl TryFrom<usize> for Arch {
x if x == Self::M68K as usize => Ok(Self::M68K),
x if x == Self::RISCV as usize => Ok(Self::RISCV),
x if x == Self::S390X as usize => Ok(Self::S390X),
x if x == Self::TRICORE as usize => Ok(Self::TRICORE),
x if x == Self::MAX as usize => Ok(Self::MAX),
_ => Err(uc_error::ARCH),
}
@ -162,8 +165,8 @@ bitflags! {
const THUMB = 0x10;
const MCLASS = 0x20;
const V8 = 0x40;
const ARMBE8 = 0x80;
const ARM926 = Self::ARMBE8.bits;
const ARMBE8 = 0x400;
const ARM926 = 0x80;
const ARM946 = 0x100;
const ARM1176 = 0x200;
const MICRO = Self::THUMB.bits;

View File

@ -1,5 +1,5 @@
# https://cristianadam.eu/20190501/bundling-together-static-libraries-with-cmake/
function(bundle_static_library tgt_name bundled_tgt_name)
function(bundle_static_library tgt_name bundled_tgt_name library_name)
list(APPEND static_libs ${tgt_name})
set(dep_libs "")
@ -41,10 +41,10 @@ function(bundle_static_library tgt_name bundled_tgt_name)
list(REMOVE_DUPLICATES dep_libs)
set(bundled_tgt_full_name
${CMAKE_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${bundled_tgt_name}${CMAKE_STATIC_LIBRARY_SUFFIX})
${CMAKE_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${library_name}${CMAKE_STATIC_LIBRARY_SUFFIX})
if (APPLE)
find_program(lib_tool libtool)
find_program(lib_tool libtool REQUIRED)
foreach(tgt IN LISTS static_libs)
list(APPEND static_libs_full_names $<TARGET_FILE:${tgt}>)
@ -55,7 +55,7 @@ function(bundle_static_library tgt_name bundled_tgt_name)
OUTPUT ${bundled_tgt_full_name}
COMMENT "Bundling ${bundled_tgt_name}"
VERBATIM)
elseif(UNIX)
elseif(UNIX OR MINGW)
file(WRITE ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in
"CREATE ${bundled_tgt_full_name}\n" )
@ -82,7 +82,10 @@ function(bundle_static_library tgt_name bundled_tgt_name)
COMMENT "Bundling ${bundled_tgt_name}"
VERBATIM)
elseif(WIN32)
find_program(lib_tool lib)
# https://stackoverflow.com/a/38096930/1806760
get_filename_component(vs_bin_path "${CMAKE_LINKER}" DIRECTORY)
find_program(lib_tool lib HINTS "${vs_bin_path}" REQUIRED)
foreach(tgt IN LISTS static_libs)
list(APPEND static_libs_full_names $<TARGET_FILE:${tgt}>)

View File

@ -1,6 +1,6 @@
This HOWTO introduces how to build Unicorn2 natively on Linux/Mac/Windows or cross-build to Windows from Linux host.
Note: Please run `make clean` before you switch to `dev` branch.
Note: By default, CMake will build both the shared and static libraries while only static libraries are built if unicorn is used as a Cmake subdirectory. In most cases, you don't need to care about which kind of library to build. ONLY use `BUILD_SHARED_LIBS=no`if you know what you are doing.
## Native build on Linux/macOS

View File

@ -5,7 +5,7 @@ Typically, its due to
- Instrumenting every instruction executed.
- Instrumenting every memory access.
Optimize your program with less instrumentation.
Optimize your program with less instrumentation, e.g. by using `UC_HOOK_BLOCK` instead of `UC_HOOK_CODE`
## Why do I get a wrong PC after emulation stops?
@ -26,6 +26,7 @@ On x86, all available instructions are: `in` `out` `syscall` `sysenter` `cpuid`.
1. Some instructions are not enabled by default on some architectures. For example, you have to setup CSR on RISC-V or VFP on ARM before emulating floating-point instructions. Refer to the corresponding manual to check if you leave out possible switches in special registers.
2. If you are on ARM, please check whether you are emulating a THUMB instruction. If so, please use `UC_MODE_THUMB` and make sure the starting address is odd.
3. If either is not the case, it might be some newer instruction sets that qemu5 doesnt support.
4. Note some instruction sets are not implemented by QEMU.
If you are still using Unicorn1, please upgrade to Unicorn2 for better support.
@ -37,6 +38,29 @@ It is due to the fact that, if users return `true` without memory mapping set up
See the [sample](https://github.com/unicorn-engine/unicorn/blob/c05fbb7e63aed0b60fc2888e08beceb17bce8ac4/samples/sample_x86.c#L1379-L1393) for details.
## My MIPS emulation gets weird read/write error and CPU exceptions.
Note you might have an address that falls in MIPS `kseg` segments. In that case, MMU is bypassed and you have to make sure the corresponding physical memory is mapped. See [#217](https://github.com/unicorn-engine/unicorn/issues/217), [#1371](https://github.com/unicorn-engine/unicorn/issues/1371), [#1550](https://github.com/unicorn-engine/unicorn/issues/1371).
## KeyboardInterrupt is not raised during `uc.emu_start`
This is intended as python [signal module](https://docs.python.org/3.10/library/signal.html) states:
> A long-running calculation implemented purely in C (such as regular expression matching on a large body of text) may run uninterrupted for an arbitrary amount of time, regardless of any signals received. The Python signal handlers will be called when the calculation finishes.
A workaround is to start emulation in another thread.
## Editing an instruction doesn't take effect/Hooks added during emulation are not called.
Unicorn is a fork of QEMU and inherits most QEMU internal mechanisms, one of which is called TB chaining. In short, every block (in most cases, a `basic block`) is translated, executed and __cached__. Therefore, any operation on cached addresses won't immediately take effect without a call to `uc_ctl_remove_cache`. Check a more detailed discussion here: [#1561](https://github.com/unicorn-engine/unicorn/issues/1561)
Note, this doesn't mean you have to care about Self Modifying Code because the read/write happens within emulation (TB execution) and QEMU would handle such special cases. For technical details, refer to the [QEMU paper](https://www.usenix.org/legacy/event/usenix05/tech/freenix/full_papers/bellard/bellard.pdf).
TLDR: To ensure any modification to an address will take effect:
1. Call `uc_ctl_remove_cache` on the target address.
2. Call `uc_reg_write` to write current PC to the PC register, if the modification happens during emulation. It restarts emulation (but doesn't quit `uc_emu_start`) on current address to re-translate the block.
## How to emulate interrupts (or ticks) with Unicorn?
As stated, Unicorn is a pure CPU emulator. For such emulation, you have two choices:

View File

@ -9,6 +9,7 @@
#include <stdio.h>
#include "qemu.h"
#include "qemu/xxhash.h"
#include "unicorn/unicorn.h"
#include "list.h"
@ -33,6 +34,7 @@
#define UC_MODE_RISCV_MASK \
(UC_MODE_RISCV32 | UC_MODE_RISCV64 | UC_MODE_LITTLE_ENDIAN)
#define UC_MODE_S390X_MASK (UC_MODE_BIG_ENDIAN)
#define UC_MODE_TRICORE_MASK (UC_MODE_LITTLE_ENDIAN)
#define ARR_SIZE(a) (sizeof(a) / sizeof(a[0]))
@ -92,6 +94,8 @@ typedef void (*uc_args_uc_long_t)(struct uc_struct *, unsigned long);
typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr);
typedef uint64_t (*uc_get_pc_t)(struct uc_struct *);
typedef MemoryRegion *(*uc_args_uc_ram_size_t)(struct uc_struct *, hwaddr begin,
size_t size, uint32_t perms);
@ -139,6 +143,9 @@ typedef void (*uc_invalidate_tb_t)(struct uc_struct *uc, uint64_t start,
// Request generating TB at given address
typedef uc_err (*uc_gen_tb_t)(struct uc_struct *uc, uint64_t pc, uc_tb *out_tb);
// tb flush
typedef uc_tcg_flush_tlb uc_tb_flush_t;
struct hook {
int type; // UC_HOOK_*
int insn; // instruction for HOOK_INSN
@ -151,6 +158,7 @@ struct hook {
// address (depends on hook type)
void *callback; // a uc_cb_* type
void *user_data;
GHashTable *hooked_regions; // The regions this hook instrumented on
};
// Add an inline hook to helper_table
@ -254,6 +262,7 @@ struct uc_struct {
uc_read_mem_t read_mem;
uc_args_void_t release; // release resource when uc_close()
uc_args_uc_u64_t set_pc; // set PC for tracecode
uc_get_pc_t get_pc;
uc_args_int_t
stop_interrupt; // check if the interrupt should stop emulation
uc_memory_map_io_t memory_map_io;
@ -272,6 +281,7 @@ struct uc_struct {
uc_tcg_flush_tlb tcg_flush_tlb;
uc_invalidate_tb_t uc_invalidate_tb;
uc_gen_tb_t uc_gen_tb;
uc_tb_flush_t tb_flush;
uc_add_inline_hook_t add_inline_hook;
uc_del_inline_hook_t del_inline_hook;
@ -406,6 +416,62 @@ static inline int uc_addr_is_exit(uc_engine *uc, uint64_t addr)
}
}
typedef struct HookedRegion {
uint64_t start;
uint64_t length;
} HookedRegion;
// hooked_regions related functions
static inline guint hooked_regions_hash(const void *p)
{
HookedRegion *region = (HookedRegion *)p;
return qemu_xxhash4(region->start, region->length);
}
static inline gboolean hooked_regions_equal(const void *lhs, const void *rhs)
{
HookedRegion *l = (HookedRegion *)lhs;
HookedRegion *r = (HookedRegion *)rhs;
return l->start == r->start && l->length == r->length;
}
static inline void hooked_regions_add(struct hook *h, uint64_t start,
uint64_t length)
{
HookedRegion tmp;
tmp.start = start;
tmp.length = length;
if (!g_hash_table_lookup(h->hooked_regions, (void *)&tmp)) {
HookedRegion *r = malloc(sizeof(HookedRegion));
r->start = start;
r->length = length;
g_hash_table_insert(h->hooked_regions, (void *)r, (void *)1);
}
}
static inline void hooked_regions_check_single(struct list_item *cur,
uint64_t start, uint64_t length)
{
while (cur != NULL) {
if (HOOK_BOUND_CHECK((struct hook *)cur->data, start)) {
hooked_regions_add((struct hook *)cur->data, start, length);
}
cur = cur->next;
}
}
static inline void hooked_regions_check(uc_engine *uc, uint64_t start,
uint64_t length)
{
// Only UC_HOOK_BLOCK and UC_HOOK_CODE might be wrongle cached!
hooked_regions_check_single(uc->hook[UC_HOOK_CODE_IDX].head, start, length);
hooked_regions_check_single(uc->hook[UC_HOOK_BLOCK_IDX].head, start,
length);
}
#ifdef UNICORN_TRACER
#define UC_TRACE_START(loc) trace_start(get_tracer(), loc)
#define UC_TRACE_END(loc, fmt, ...) \

174
include/unicorn/tricore.h Normal file
View File

@ -0,0 +1,174 @@
/* This file is released under LGPL2.
See COPYING.LGPL2 in root directory for more details
*/
/*
Created for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#ifndef UNICORN_TRICORE_H
#define UNICORN_TRICORE_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
#pragma warning(disable : 4201)
#endif
//> TRICORE CPU
typedef enum uc_cpu_tricore {
UC_CPU_TRICORE_TC1796,
UC_CPU_TRICORE_TC1797,
UC_CPU_TRICORE_TC27X,
UC_CPU_TRICORE_ENDING
} uc_cpu_tricore;
//> TRICORE registers
typedef enum uc_tricore_reg {
UC_TRICORE_REG_INVALID = 0,
// General purpose registers (GPR)
// Address GPR
UC_TRICORE_REG_A0,
UC_TRICORE_REG_A1,
UC_TRICORE_REG_A2,
UC_TRICORE_REG_A3,
UC_TRICORE_REG_A4,
UC_TRICORE_REG_A5,
UC_TRICORE_REG_A6,
UC_TRICORE_REG_A7,
UC_TRICORE_REG_A8,
UC_TRICORE_REG_A9,
UC_TRICORE_REG_A10,
UC_TRICORE_REG_A11,
UC_TRICORE_REG_A12,
UC_TRICORE_REG_A13,
UC_TRICORE_REG_A14,
UC_TRICORE_REG_A15,
// Data GPR
UC_TRICORE_REG_D0,
UC_TRICORE_REG_D1,
UC_TRICORE_REG_D2,
UC_TRICORE_REG_D3,
UC_TRICORE_REG_D4,
UC_TRICORE_REG_D5,
UC_TRICORE_REG_D6,
UC_TRICORE_REG_D7,
UC_TRICORE_REG_D8,
UC_TRICORE_REG_D9,
UC_TRICORE_REG_D10,
UC_TRICORE_REG_D11,
UC_TRICORE_REG_D12,
UC_TRICORE_REG_D13,
UC_TRICORE_REG_D14,
UC_TRICORE_REG_D15,
/* CSFR Register */
UC_TRICORE_REG_PCXI,
UC_TRICORE_REG_PSW,
/* PSW flag cache for faster execution */
UC_TRICORE_REG_PSW_USB_C,
UC_TRICORE_REG_PSW_USB_V,
UC_TRICORE_REG_PSW_USB_SV,
UC_TRICORE_REG_PSW_USB_AV,
UC_TRICORE_REG_PSW_USB_SAV,
UC_TRICORE_REG_PC,
UC_TRICORE_REG_SYSCON,
UC_TRICORE_REG_CPU_ID,
UC_TRICORE_REG_BIV,
UC_TRICORE_REG_BTV,
UC_TRICORE_REG_ISP,
UC_TRICORE_REG_ICR,
UC_TRICORE_REG_FCX,
UC_TRICORE_REG_LCX,
UC_TRICORE_REG_COMPAT,
UC_TRICORE_REG_DPR0_U,
UC_TRICORE_REG_DPR1_U,
UC_TRICORE_REG_DPR2_U,
UC_TRICORE_REG_DPR3_U,
UC_TRICORE_REG_DPR0_L,
UC_TRICORE_REG_DPR1_L,
UC_TRICORE_REG_DPR2_L,
UC_TRICORE_REG_DPR3_L,
UC_TRICORE_REG_CPR0_U,
UC_TRICORE_REG_CPR1_U,
UC_TRICORE_REG_CPR2_U,
UC_TRICORE_REG_CPR3_U,
UC_TRICORE_REG_CPR0_L,
UC_TRICORE_REG_CPR1_L,
UC_TRICORE_REG_CPR2_L,
UC_TRICORE_REG_CPR3_L,
UC_TRICORE_REG_DPM0,
UC_TRICORE_REG_DPM1,
UC_TRICORE_REG_DPM2,
UC_TRICORE_REG_DPM3,
UC_TRICORE_REG_CPM0,
UC_TRICORE_REG_CPM1,
UC_TRICORE_REG_CPM2,
UC_TRICORE_REG_CPM3,
/* Memory Management Registers */
UC_TRICORE_REG_MMU_CON,
UC_TRICORE_REG_MMU_ASI,
UC_TRICORE_REG_MMU_TVA,
UC_TRICORE_REG_MMU_TPA,
UC_TRICORE_REG_MMU_TPX,
UC_TRICORE_REG_MMU_TFA,
// 1.3.1 Only
UC_TRICORE_REG_BMACON,
UC_TRICORE_REG_SMACON,
UC_TRICORE_REG_DIEAR,
UC_TRICORE_REG_DIETR,
UC_TRICORE_REG_CCDIER,
UC_TRICORE_REG_MIECON,
UC_TRICORE_REG_PIEAR,
UC_TRICORE_REG_PIETR,
UC_TRICORE_REG_CCPIER,
/* Debug Registers */
UC_TRICORE_REG_DBGSR,
UC_TRICORE_REG_EXEVT,
UC_TRICORE_REG_CREVT,
UC_TRICORE_REG_SWEVT,
UC_TRICORE_REG_TR0EVT,
UC_TRICORE_REG_TR1EVT,
UC_TRICORE_REG_DMS,
UC_TRICORE_REG_DCX,
UC_TRICORE_REG_DBGTCR,
UC_TRICORE_REG_CCTRL,
UC_TRICORE_REG_CCNT,
UC_TRICORE_REG_ICNT,
UC_TRICORE_REG_M1CNT,
UC_TRICORE_REG_M2CNT,
UC_TRICORE_REG_M3CNT,
UC_TRICORE_REG_ENDING, // <-- mark the end of the list of registers
// alias registers
UC_TRICORE_REG_GA0 = UC_TRICORE_REG_A0,
UC_TRICORE_REG_GA1 = UC_TRICORE_REG_A1,
UC_TRICORE_REG_GA8 = UC_TRICORE_REG_A8,
UC_TRICORE_REG_GA9 = UC_TRICORE_REG_A9,
UC_TRICORE_REG_SP = UC_TRICORE_REG_A10,
UC_TRICORE_REG_LR = UC_TRICORE_REG_A11,
UC_TRICORE_REG_IA = UC_TRICORE_REG_A15,
UC_TRICORE_REG_ID = UC_TRICORE_REG_D15,
} uc_tricore_reg;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -35,6 +35,7 @@ typedef size_t uc_hook;
#include "ppc.h"
#include "riscv.h"
#include "s390x.h"
#include "tricore.h"
#ifdef __GNUC__
#define DEFAULT_VISIBILITY __attribute__((visibility("default")))
@ -72,7 +73,8 @@ typedef size_t uc_hook;
#define UC_API_MAJOR 2
#define UC_API_MINOR 0
#define UC_API_PATCH 0
#define UC_API_EXTRA 7
// Release candidate version, 255 means the official release.
#define UC_API_EXTRA 255
// Unicorn package version
#define UC_VERSION_MAJOR UC_API_MAJOR
@ -103,6 +105,7 @@ typedef enum uc_arch {
UC_ARCH_M68K, // M68K architecture
UC_ARCH_RISCV, // RISCV architecture
UC_ARCH_S390X, // S390X architecture
UC_ARCH_TRICORE, // TriCore architecture
UC_ARCH_MAX,
} uc_arch;
@ -117,8 +120,8 @@ typedef enum uc_mode {
// Depreciated, use UC_ARM_CPU_* with uc_ctl instead.
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series.
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM
UC_MODE_ARMBE8 = 1 << 7, // Big-endian data and Little-endian code.
// Legacy support for UC1 only.
UC_MODE_ARMBE8 = 1 << 10, // Big-endian data and Little-endian code.
// Legacy support for UC1 only.
// arm (32bit) cpu types
// Depreciated, use UC_ARM_CPU_* with uc_ctl instead.
@ -530,7 +533,10 @@ typedef enum uc_control_type {
UC_CTL_TB_REQUEST_CACHE,
// Invalidate a tb cache at a specific address
// Write: @args = (uint64_t, uint64_t)
UC_CTL_TB_REMOVE_CACHE
UC_CTL_TB_REMOVE_CACHE,
// Invalidate all translation blocks.
// No arguments.
UC_CTL_TB_FLUSH
} uc_control_type;
@ -605,7 +611,7 @@ See sample_ctl.c for a detailed example.
uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TB_REMOVE_CACHE, 2), (address), (end))
#define uc_ctl_request_cache(uc, address, tb) \
uc_ctl(uc, UC_CTL_READ_WRITE(UC_CTL_TB_REQUEST_CACHE, 2), (address), (tb))
#define uc_ctl_flush_tlb(uc) uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TB_FLUSH, 0))
// Opaque storage for CPU context, used with uc_context_*()
struct uc_context;
typedef struct uc_context uc_context;

View File

@ -0,0 +1,5 @@
/* Automatically generated by create_config - do not modify */
#define TARGET_TRICORE 1
#define TARGET_NAME "tricore"
#define TARGET_TRICORE 1
#define CONFIG_SOFTMMU 1

View File

@ -1441,36 +1441,41 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
// memory might be still unmapped while reading or fetching
if (mr == NULL) {
handled = false;
if (code_read) {
// code fetching
error_code = UC_ERR_FETCH_UNMAPPED;
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) {
if (hook->to_delete)
continue;
if (!HOOK_BOUND_CHECK(hook, addr))
continue;
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, size - uc->size_recur_mem, 0, hook->user_data)))
break;
// if there is already an unhandled eror, skip callbacks.
if (uc->invalid_error == UC_ERR_OK) {
if (code_read) {
// code fetching
error_code = UC_ERR_FETCH_UNMAPPED;
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) {
if (hook->to_delete)
continue;
if (!HOOK_BOUND_CHECK(hook, addr))
continue;
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, size - uc->size_recur_mem, 0, hook->user_data)))
break;
// the last callback may already asked to stop emulation
if (uc->stop_request)
break;
// the last callback may already asked to stop emulation
if (uc->stop_request)
break;
}
} else {
// data reading
error_code = UC_ERR_READ_UNMAPPED;
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) {
if (hook->to_delete)
continue;
if (!HOOK_BOUND_CHECK(hook, addr))
continue;
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, size - uc->size_recur_mem, 0, hook->user_data)))
break;
// the last callback may already asked to stop emulation
if (uc->stop_request)
break;
}
}
} else {
// data reading
error_code = UC_ERR_READ_UNMAPPED;
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) {
if (hook->to_delete)
continue;
if (!HOOK_BOUND_CHECK(hook, addr))
continue;
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, size - uc->size_recur_mem, 0, hook->user_data)))
break;
// the last callback may already asked to stop emulation
if (uc->stop_request)
break;
}
error_code = uc->invalid_error;
}
if (handled) {

View File

@ -985,6 +985,10 @@ static void tb_htable_init(struct uc_struct *uc)
}
static void uc_tb_flush(struct uc_struct *uc) {
tb_flush(uc->cpu);
}
static void uc_invalidate_tb(struct uc_struct *uc, uint64_t start_addr, size_t len)
{
tb_page_addr_t start, end;
@ -1095,6 +1099,7 @@ void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size)
/* Invalidate / Cache TBs */
uc->uc_invalidate_tb = uc_invalidate_tb;
uc->uc_gen_tb = uc_gen_tb;
uc->tb_flush = uc_tb_flush;
/* Inline hooks optimization */
uc->add_inline_hook = uc_add_inline_hook;

View File

@ -147,6 +147,8 @@ _end_loop:
db->tb->size = db->pc_next - db->pc_first;
db->tb->icount = db->num_insns;
hooked_regions_check(uc, db->tb->pc, db->tb->size);
if (block_hook) {
TCGOp *tcg_op;

11
qemu/configure vendored
View File

@ -489,6 +489,8 @@ elif check_define __arm__ ; then
cpu="arm"
elif check_define __aarch64__ ; then
cpu="aarch64"
elif check_define __tricore__ ; then
cpu="tricore"
else
cpu=$(uname -m)
fi
@ -528,6 +530,10 @@ case "$cpu" in
cpu="sparc"
supported_cpu="yes"
;;
tricore)
cpu="tricore"
supported_cpu="yes"
;;
*)
# This will result in either an error or falling back to TCI later
ARCH=unknown
@ -852,7 +858,8 @@ QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS"
default_target_list="aarch64-softmmu \
arm-softmmu m68k-softmmu mips64el-softmmu mips64-softmmu mipsel-softmmu \
mips-softmmu ppc64-softmmu ppc-softmmu sparc64-softmmu sparc-softmmu \
x86_64-softmmu riscv32-softmmu riscv64-softmmu s390x-softmmu"
x86_64-softmmu riscv32-softmmu riscv64-softmmu s390x-softmmu \
tricore-softmmu"
if test x"$show_help" = x"yes" ; then
cat << EOF
@ -2747,6 +2754,8 @@ case "$target_name" in
tilegx)
;;
tricore)
TARGET_ARCH=tricore
TARGET_BASE_ARCH=tricore
;;
unicore32)
;;

View File

@ -794,6 +794,12 @@ struct TCGContext {
TCGv NULL_QREG;
/* Used to distinguish stores from bad addressing modes. */
TCGv store_dummy;
// target/tricore/translate.c
TCGv_i32 cpu_gpr_a[16];
TCGv_i32 cpu_gpr_d[16];
TCGv_i32 cpu_PSW_C, cpu_PSW_V, cpu_PSW_SV, cpu_PSW_AV, cpu_PSW_SAV;
TCGv_i32 cpu_PC, cpu_PCXI, cpu_PSW, cpu_ICR;
// Used to store the start of current instrution.
uint64_t pc_start;

View File

@ -99,6 +99,12 @@ static int tcg_cpu_exec(struct uc_struct *uc)
if (uc->quit_request) {
// reset stop_request
uc->stop_request = false;
// resume cpu
cpu->halted = 0;
cpu->exit_request = 0;
cpu->exception_index = -1;
cpu_resume(cpu);
} else if (uc->stop_request) {
//printf(">>> got STOP request!!!\n");
finish = true;

View File

@ -82,7 +82,7 @@ MemoryRegion *memory_map_ptr(struct uc_struct *uc, hwaddr begin, size_t size, ui
static uint64_t mmio_read_wrapper(struct uc_struct *uc, void *opaque, hwaddr addr, unsigned size)
{
mmio_cbs* cbs = (mmio_cbs*)opaque;
// We have to care about 32bit target.
addr = addr & ( (target_ulong)(-1) );
if (cbs->read) {
@ -123,7 +123,9 @@ MemoryRegion *memory_map_io(struct uc_struct *uc, ram_addr_t begin, size_t size,
memset(ops, 0, sizeof(*ops));
ops->read = mmio_read_wrapper;
ops->read_with_attrs = NULL;
ops->write = mmio_write_wrapper;
ops->write_with_attrs = NULL;
ops->endianness = DEVICE_NATIVE_ENDIAN;
memory_region_init_io(uc, mmio, ops, opaques, size);

View File

@ -18,6 +18,11 @@ static void arm64_set_pc(struct uc_struct *uc, uint64_t address)
((CPUARMState *)uc->cpu->env_ptr)->pc = address;
}
static uint64_t arm64_get_pc(struct uc_struct *uc)
{
return ((CPUARMState *)uc->cpu->env_ptr)->pc;
}
static void arm64_release(void *ctx)
{
int i;
@ -431,6 +436,7 @@ void arm64_uc_init(struct uc_struct *uc)
uc->reg_write = arm64_reg_write;
uc->reg_reset = arm64_reg_reset;
uc->set_pc = arm64_set_pc;
uc->get_pc = arm64_get_pc;
uc->release = arm64_release;
uc->cpus_init = arm64_cpus_init;
uc->cpu_context_size = offsetof(CPUARMState, cpu_watchpoint);

View File

@ -16,7 +16,14 @@ ARMCPU *cpu_arm_init(struct uc_struct *uc);
static void arm_set_pc(struct uc_struct *uc, uint64_t address)
{
((CPUARMState *)uc->cpu->env_ptr)->pc = address;
((CPUARMState *)uc->cpu->env_ptr)->regs[15] = address;
((CPUARMState *)uc->cpu->env_ptr)->regs[15] = address & ~1;
((CPUARMState *)uc->cpu->env_ptr)->thumb = address & 1;
}
static uint64_t arm_get_pc(struct uc_struct *uc)
{
return ((CPUARMState *)uc->cpu->env_ptr)->regs[15] |
((CPUARMState *)uc->cpu->env_ptr)->thumb;
}
static void arm_release(void *ctx)
@ -204,10 +211,23 @@ static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value)
uc_err ret = UC_ERR_OK;
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) {
*(int32_t *)value = env->regs[regid - UC_ARM_REG_R0];
*(uint32_t *)value = env->regs[regid - UC_ARM_REG_R0];
} else if (regid >= UC_ARM_REG_Q0 && regid <= UC_ARM_REG_Q15) {
uint32_t reg_index = regid - UC_ARM_REG_Q0;
*(uint64_t *)value = env->vfp.zregs[reg_index].d[0];
*(((uint64_t *)value) + 1) = env->vfp.zregs[reg_index].d[1];
} else if (regid >= UC_ARM_REG_D0 && regid <= UC_ARM_REG_D31) {
uint32_t reg_index = regid - UC_ARM_REG_D0;
*(float64 *)value = env->vfp.zregs[reg_index / 2].d[reg_index & 1];
*(uint64_t *)value = env->vfp.zregs[reg_index / 2].d[reg_index & 1];
} else if (regid >= UC_ARM_REG_S0 && regid <= UC_ARM_REG_S31) {
uint32_t reg_index = regid - UC_ARM_REG_S0;
uint64_t reg_value = env->vfp.zregs[reg_index / 4].d[reg_index % 4 / 2];
if (reg_index % 2 == 0) {
*(uint32_t *)value = (uint32_t)(reg_value & 0xffffffff);
} else {
*(uint32_t *)value = (uint32_t)(reg_value >> 32);
}
} else {
switch (regid) {
case UC_ARM_REG_APSR:
@ -308,9 +328,25 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value)
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) {
env->regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value;
} else if (regid >= UC_ARM_REG_Q0 && regid <= UC_ARM_REG_Q15) {
uint32_t reg_index = regid - UC_ARM_REG_Q0;
env->vfp.zregs[reg_index].d[0] = *(uint64_t *)value;
env->vfp.zregs[reg_index].d[1] = *(((uint64_t *)value) + 1);
} else if (regid >= UC_ARM_REG_D0 && regid <= UC_ARM_REG_D31) {
uint32_t reg_index = regid - UC_ARM_REG_D0;
env->vfp.zregs[reg_index / 2].d[reg_index & 1] = *(float64 *)value;
env->vfp.zregs[reg_index / 2].d[reg_index & 1] = *(uint64_t *)value;
} else if (regid >= UC_ARM_REG_S0 && regid <= UC_ARM_REG_S31) {
uint32_t reg_index = regid - UC_ARM_REG_S0;
uint64_t *p_reg_value =
&env->vfp.zregs[reg_index / 4].d[reg_index % 4 / 2];
uint64_t in_value = *((uint32_t *)value);
if (reg_index % 2 == 0) {
in_value |= *p_reg_value & 0xffffffff00000000ul;
} else {
in_value = (in_value << 32) | (*p_reg_value & 0xfffffffful);
}
*p_reg_value = in_value;
} else {
switch (regid) {
case UC_ARM_REG_APSR:
@ -591,6 +627,7 @@ void arm_uc_init(struct uc_struct *uc)
uc->reg_write = arm_reg_write;
uc->reg_reset = arm_reg_reset;
uc->set_pc = arm_set_pc;
uc->get_pc = arm_get_pc;
uc->stop_interrupt = arm_stop_interrupt;
uc->release = arm_release;
uc->query = arm_query;

View File

@ -33,6 +33,16 @@ static void x86_set_pc(struct uc_struct *uc, uint64_t address)
((CPUX86State *)uc->cpu->env_ptr)->eip = address;
}
static uint64_t x86_get_pc(struct uc_struct *uc)
{
if (uc->mode == UC_MODE_16) {
return X86_CPU(uc->cpu)->env.segs[R_CS].selector * 16 +
((CPUX86State *)uc->cpu->env_ptr)->eip;
} else {
return ((CPUX86State *)uc->cpu->env_ptr)->eip;
}
}
static void x86_release(void *ctx)
{
int i;
@ -1644,6 +1654,7 @@ void x86_uc_init(struct uc_struct *uc)
uc->reg_reset = x86_reg_reset;
uc->release = x86_release;
uc->set_pc = x86_set_pc;
uc->get_pc = x86_get_pc;
uc->stop_interrupt = x86_stop_interrupt;
uc->insn_hook_validate = x86_insn_hook_validate;
uc->opcode_hook_invalidate = x86_opcode_hook_invalidate;

View File

@ -15,6 +15,11 @@ static void m68k_set_pc(struct uc_struct *uc, uint64_t address)
((CPUM68KState *)uc->cpu->env_ptr)->pc = address;
}
static uint64_t m68k_get_pc(struct uc_struct *uc)
{
return ((CPUM68KState *)uc->cpu->env_ptr)->pc;
}
static void m68k_release(void *ctx)
{
int i;
@ -170,6 +175,7 @@ void m68k_uc_init(struct uc_struct *uc)
uc->reg_write = m68k_reg_write;
uc->reg_reset = m68k_reg_reset;
uc->set_pc = m68k_set_pc;
uc->get_pc = m68k_get_pc;
uc->cpus_init = m68k_cpus_init;
uc->cpu_context_size = offsetof(CPUM68KState, end_reset_fields);
uc_common_init(uc);

View File

@ -37,6 +37,11 @@ static void mips_set_pc(struct uc_struct *uc, uint64_t address)
((CPUMIPSState *)uc->cpu->env_ptr)->active_tc.PC = address;
}
static uint64_t mips_get_pc(struct uc_struct *uc)
{
return ((CPUMIPSState *)uc->cpu->env_ptr)->active_tc.PC;
}
static void mips_release(void *ctx)
{
int i;
@ -266,6 +271,7 @@ void mipsel_uc_init(struct uc_struct *uc)
uc->reg_reset = mips_reg_reset;
uc->release = mips_release;
uc->set_pc = mips_set_pc;
uc->get_pc = mips_get_pc;
uc->mem_redirect = mips_mem_redirect;
uc->cpus_init = mips_cpus_init;
uc->cpu_context_size = offsetof(CPUMIPSState, end_reset_fields);

View File

@ -97,6 +97,11 @@ static void ppc_set_pc(struct uc_struct *uc, uint64_t address)
((CPUPPCState *)uc->cpu->env_ptr)->nip = address;
}
static uint64_t ppc_get_pc(struct uc_struct *uc)
{
return ((CPUPPCState *)uc->cpu->env_ptr)->nip;
}
void ppc_cpu_instance_finalize(CPUState *obj);
void ppc_cpu_unrealize(CPUState *dev);
static void ppc_release(void *ctx)
@ -414,6 +419,7 @@ void ppc_uc_init(struct uc_struct *uc)
uc->reg_reset = ppc_reg_reset;
uc->release = ppc_release;
uc->set_pc = ppc_set_pc;
uc->get_pc = ppc_get_pc;
uc->mem_redirect = ppc_mem_redirect;
uc->cpus_init = ppc_cpus_init;
uc->cpu_context_size = offsetof(CPUPPCState, uc);

View File

@ -52,6 +52,11 @@ static void riscv_set_pc(struct uc_struct *uc, uint64_t address)
RISCV_CPU(uc->cpu)->env.pc = address;
}
static uint64_t riscv_get_pc(struct uc_struct *uc)
{
return RISCV_CPU(uc->cpu)->env.pc;
}
static void riscv_release(void *ctx)
{
int i;
@ -651,6 +656,7 @@ void riscv64_uc_init(struct uc_struct *uc)
uc->reg_reset = riscv_reg_reset;
uc->release = riscv_release;
uc->set_pc = riscv_set_pc;
uc->get_pc = riscv_get_pc;
uc->stop_interrupt = riscv_stop_interrupt;
uc->insn_hook_validate = riscv_insn_hook_validate;
uc->cpus_init = riscv_cpus_init;

View File

@ -21,50 +21,50 @@ typedef struct SigpInfo {
uint64_t *status_reg;
} SigpInfo;
static void set_sigp_status(SigpInfo *si, uint64_t status)
{
*si->status_reg &= 0xffffffff00000000ULL;
*si->status_reg |= status;
si->cc = SIGP_CC_STATUS_STORED;
}
// static void set_sigp_status(SigpInfo *si, uint64_t status)
// {
// *si->status_reg &= 0xffffffff00000000ULL;
// *si->status_reg |= status;
// si->cc = SIGP_CC_STATUS_STORED;
// }
static void sigp_sense(S390CPU *dst_cpu, SigpInfo *si)
{
uint8_t state = s390_cpu_get_state(dst_cpu);
bool ext_call = dst_cpu->env.pending_int & INTERRUPT_EXTERNAL_CALL;
uint64_t status = 0;
// static void sigp_sense(S390CPU *dst_cpu, SigpInfo *si)
// {
// uint8_t state = s390_cpu_get_state(dst_cpu);
// bool ext_call = dst_cpu->env.pending_int & INTERRUPT_EXTERNAL_CALL;
// uint64_t status = 0;
/* sensing without locks is racy, but it's the same for real hw */
if (state != S390_CPU_STATE_STOPPED && !ext_call) {
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
} else {
if (ext_call) {
status |= SIGP_STAT_EXT_CALL_PENDING;
}
if (state == S390_CPU_STATE_STOPPED) {
status |= SIGP_STAT_STOPPED;
}
set_sigp_status(si, status);
}
}
// /* sensing without locks is racy, but it's the same for real hw */
// if (state != S390_CPU_STATE_STOPPED && !ext_call) {
// si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
// } else {
// if (ext_call) {
// status |= SIGP_STAT_EXT_CALL_PENDING;
// }
// if (state == S390_CPU_STATE_STOPPED) {
// status |= SIGP_STAT_STOPPED;
// }
// set_sigp_status(si, status);
// }
// }
static void sigp_external_call(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
{
int ret;
// static void sigp_external_call(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
// {
// int ret;
ret = cpu_inject_external_call(dst_cpu, src_cpu->env.core_id);
if (!ret) {
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
} else {
set_sigp_status(si, SIGP_STAT_EXT_CALL_PENDING);
}
}
// ret = cpu_inject_external_call(dst_cpu, src_cpu->env.core_id);
// if (!ret) {
// si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
// } else {
// set_sigp_status(si, SIGP_STAT_EXT_CALL_PENDING);
// }
// }
static void sigp_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
{
cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
// static void sigp_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
// {
// cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
// si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
// }
#if 0
static void sigp_start(CPUState *cs, run_on_cpu_data arg)
@ -277,146 +277,146 @@ static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
}
#endif
static void sigp_cond_emergency(S390CPU *src_cpu, S390CPU *dst_cpu,
SigpInfo *si)
{
const uint64_t psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
uint16_t p_asn, s_asn, asn;
uint64_t psw_addr, psw_mask;
bool idle;
// static void sigp_cond_emergency(S390CPU *src_cpu, S390CPU *dst_cpu,
// SigpInfo *si)
// {
// const uint64_t psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
// uint16_t p_asn, s_asn, asn;
// uint64_t psw_addr, psw_mask;
// bool idle;
/* this looks racy, but these values are only used when STOPPED */
idle = CPU(dst_cpu)->halted;
psw_addr = dst_cpu->env.psw.addr;
psw_mask = dst_cpu->env.psw.mask;
asn = si->param;
p_asn = dst_cpu->env.cregs[4] & 0xffff; /* Primary ASN */
s_asn = dst_cpu->env.cregs[3] & 0xffff; /* Secondary ASN */
// /* this looks racy, but these values are only used when STOPPED */
// idle = CPU(dst_cpu)->halted;
// psw_addr = dst_cpu->env.psw.addr;
// psw_mask = dst_cpu->env.psw.mask;
// asn = si->param;
// p_asn = dst_cpu->env.cregs[4] & 0xffff; /* Primary ASN */
// s_asn = dst_cpu->env.cregs[3] & 0xffff; /* Secondary ASN */
if (s390_cpu_get_state(dst_cpu) != S390_CPU_STATE_STOPPED ||
(psw_mask & psw_int_mask) != psw_int_mask ||
(idle && psw_addr != 0) ||
(!idle && (asn == p_asn || asn == s_asn))) {
cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
} else {
set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
}
// if (s390_cpu_get_state(dst_cpu) != S390_CPU_STATE_STOPPED ||
// (psw_mask & psw_int_mask) != psw_int_mask ||
// (idle && psw_addr != 0) ||
// (!idle && (asn == p_asn || asn == s_asn))) {
// cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
// } else {
// set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
// }
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
// si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
// }
static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si)
{
/* sensing without locks is racy, but it's the same for real hw */
//if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) {
// set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
// return;
//}
// static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si)
// {
// /* sensing without locks is racy, but it's the same for real hw */
// //if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) {
// // set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
// // return;
// //}
/* If halted (which includes also STOPPED), it is not running */
if (CPU(dst_cpu)->halted) {
set_sigp_status(si, SIGP_STAT_NOT_RUNNING);
} else {
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
}
// /* If halted (which includes also STOPPED), it is not running */
// if (CPU(dst_cpu)->halted) {
// set_sigp_status(si, SIGP_STAT_NOT_RUNNING);
// } else {
// si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
// }
// }
static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order,
uint64_t param, uint64_t *status_reg)
{
SigpInfo si = {
.param = param,
.status_reg = status_reg,
};
// static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order,
// uint64_t param, uint64_t *status_reg)
// {
// SigpInfo si = {
// .param = param,
// .status_reg = status_reg,
// };
/* cpu available? */
if (dst_cpu == NULL) {
return SIGP_CC_NOT_OPERATIONAL;
}
// /* cpu available? */
// if (dst_cpu == NULL) {
// return SIGP_CC_NOT_OPERATIONAL;
// }
/* only resets can break pending orders */
if (dst_cpu->env.sigp_order != 0 &&
order != SIGP_CPU_RESET &&
order != SIGP_INITIAL_CPU_RESET) {
return SIGP_CC_BUSY;
}
// /* only resets can break pending orders */
// if (dst_cpu->env.sigp_order != 0 &&
// order != SIGP_CPU_RESET &&
// order != SIGP_INITIAL_CPU_RESET) {
// return SIGP_CC_BUSY;
// }
switch (order) {
case SIGP_SENSE:
sigp_sense(dst_cpu, &si);
break;
case SIGP_EXTERNAL_CALL:
sigp_external_call(cpu, dst_cpu, &si);
break;
case SIGP_EMERGENCY:
sigp_emergency(cpu, dst_cpu, &si);
break;
case SIGP_START:
//run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_STOP:
//run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_RESTART:
//run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_STOP_STORE_STATUS:
//run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_STORE_STATUS_ADDR:
//run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_STORE_ADTL_STATUS:
//run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_SET_PREFIX:
//run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_INITIAL_CPU_RESET:
//run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_CPU_RESET:
//run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_COND_EMERGENCY:
sigp_cond_emergency(cpu, dst_cpu, &si);
break;
case SIGP_SENSE_RUNNING:
sigp_sense_running(dst_cpu, &si);
break;
default:
set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
}
// switch (order) {
// case SIGP_SENSE:
// sigp_sense(dst_cpu, &si);
// break;
// case SIGP_EXTERNAL_CALL:
// sigp_external_call(cpu, dst_cpu, &si);
// break;
// case SIGP_EMERGENCY:
// sigp_emergency(cpu, dst_cpu, &si);
// break;
// case SIGP_START:
// //run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si));
// break;
// case SIGP_STOP:
// //run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si));
// break;
// case SIGP_RESTART:
// //run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
// break;
// case SIGP_STOP_STORE_STATUS:
// //run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si));
// break;
// case SIGP_STORE_STATUS_ADDR:
// //run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si));
// break;
// case SIGP_STORE_ADTL_STATUS:
// //run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si));
// break;
// case SIGP_SET_PREFIX:
// //run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si));
// break;
// case SIGP_INITIAL_CPU_RESET:
// //run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
// break;
// case SIGP_CPU_RESET:
// //run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
// break;
// case SIGP_COND_EMERGENCY:
// sigp_cond_emergency(cpu, dst_cpu, &si);
// break;
// case SIGP_SENSE_RUNNING:
// sigp_sense_running(dst_cpu, &si);
// break;
// default:
// set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
// }
return si.cc;
}
// return si.cc;
// }
static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
uint64_t *status_reg)
{
bool all_stopped = true;
// static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
// uint64_t *status_reg)
// {
// bool all_stopped = true;
#if 0
CPU_FOREACH(cur_cs) {
cur_cpu = S390_CPU(cur_cs);
// #if 0
// CPU_FOREACH(cur_cs) {
// cur_cpu = S390_CPU(cur_cs);
if (cur_cpu == cpu) {
continue;
}
if (s390_cpu_get_state(cur_cpu) != S390_CPU_STATE_STOPPED) {
all_stopped = false;
}
}
#endif
// if (cur_cpu == cpu) {
// continue;
// }
// if (s390_cpu_get_state(cur_cpu) != S390_CPU_STATE_STOPPED) {
// all_stopped = false;
// }
// }
// #endif
all_stopped = false;
*status_reg &= 0xffffffff00000000ULL;
// all_stopped = false;
// *status_reg &= 0xffffffff00000000ULL;
/* Reject set arch order, with czam we're always in z/Arch mode. */
*status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
SIGP_STAT_INCORRECT_STATE);
return SIGP_CC_STATUS_STORED;
}
// /* Reject set arch order, with czam we're always in z/Arch mode. */
// *status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
// SIGP_STAT_INCORRECT_STATE);
// return SIGP_CC_STATUS_STORED;
// }
#if 0
int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3)

View File

@ -12,7 +12,12 @@ S390CPU *cpu_s390_init(struct uc_struct *uc, const char *cpu_model);
static void s390_set_pc(struct uc_struct *uc, uint64_t address)
{
// ((CPUS390XState *)uc->cpu->env_ptr)->pc = address;
((CPUS390XState *)uc->cpu->env_ptr)->psw.addr = address;
}
static uint64_t s390_get_pc(struct uc_struct *uc)
{
return ((CPUS390XState *)uc->cpu->env_ptr)->psw.addr;
}
static void s390_release(void *ctx)
@ -183,6 +188,7 @@ void s390_uc_init(struct uc_struct *uc)
uc->reg_write = s390_reg_write;
uc->reg_reset = s390_reg_reset;
uc->set_pc = s390_set_pc;
uc->get_pc = s390_get_pc;
uc->cpus_init = s390_cpus_init;
uc->cpu_context_size = offsetof(CPUS390XState, end_reset_fields);
uc_common_init(uc);

View File

@ -24,6 +24,11 @@ static void sparc_set_pc(struct uc_struct *uc, uint64_t address)
((CPUSPARCState *)uc->cpu->env_ptr)->npc = address + 4;
}
static uint64_t sparc_get_pc(struct uc_struct *uc)
{
return ((CPUSPARCState *)uc->cpu->env_ptr)->pc;
}
static void sparc_release(void *ctx)
{
int i;
@ -190,6 +195,7 @@ void sparc_uc_init(struct uc_struct *uc)
uc->reg_write = sparc_reg_write;
uc->reg_reset = sparc_reg_reset;
uc->set_pc = sparc_set_pc;
uc->get_pc = sparc_get_pc;
uc->stop_interrupt = sparc_stop_interrupt;
uc->cpus_init = sparc_cpus_init;
uc->cpu_context_size = offsetof(CPUSPARCState, irq_manager);

View File

@ -26,6 +26,11 @@ static void sparc_set_pc(struct uc_struct *uc, uint64_t address)
((CPUSPARCState *)uc->cpu->env_ptr)->npc = address + 4;
}
static uint64_t sparc_get_pc(struct uc_struct *uc)
{
return ((CPUSPARCState *)uc->cpu->env_ptr)->pc;
}
static void sparc_release(void *ctx)
{
release_common(ctx);
@ -196,6 +201,7 @@ void sparc64_uc_init(struct uc_struct* uc)
uc->reg_write = sparc_reg_write;
uc->reg_reset = sparc_reg_reset;
uc->set_pc = sparc_set_pc;
uc->get_pc = sparc_get_pc;
uc->stop_interrupt = sparc_stop_interrupt;
uc->cpus_init = sparc_cpus_init;
uc_common_init(uc);

View File

@ -0,0 +1,17 @@
/*
* TriCore cpu parameters for qemu.
*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef TRICORE_CPU_PARAM_H
#define TRICORE_CPU_PARAM_H 1
#define TARGET_LONG_BITS 32
#define TARGET_PAGE_BITS 14
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#define TARGET_VIRT_ADDR_SPACE_BITS 32
#define NB_MMU_MODES 3
#endif

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#ifndef QEMU_TRICORE_CPU_QOM_H
#define QEMU_TRICORE_CPU_QOM_H
#include "hw/core/cpu.h"
#define TYPE_TRICORE_CPU "tricore-cpu"
#define TRICORE_CPU(obj) ((TriCoreCPU *)obj)
#define TRICORE_CPU_CLASS(klass) ((TriCoreCPUClass *)klass)
#define TRICORE_CPU_GET_CLASS(obj) (&((TriCoreCPU *)obj)->cc)
typedef struct TriCoreCPUClass {
/*< private >*/
CPUClass parent_class;
/*< public >*/
void (*parent_reset)(CPUState *cpu);
} TriCoreCPUClass;
#endif /* QEMU_TRICORE_CPU_QOM_H */

205
qemu/target/tricore/cpu.c Normal file
View File

@ -0,0 +1,205 @@
/*
* TriCore emulation for qemu: main translation routines.
*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "cpu-qom.h"
#include "exec/exec-all.h"
#include <uc_priv.h>
static inline void set_feature(CPUTriCoreState *env, int feature)
{
env->features |= 1ULL << feature;
}
static void tricore_cpu_set_pc(CPUState *cs, vaddr value)
{
TriCoreCPU *cpu = TRICORE_CPU(cs);
CPUTriCoreState *env = &cpu->env;
env->PC = value & ~(target_ulong)1;
}
static void tricore_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
{
TriCoreCPU *cpu = TRICORE_CPU(cs);
CPUTriCoreState *env = &cpu->env;
env->PC = tb->pc;
}
static void tricore_cpu_reset(CPUState *dev)
{
CPUState *s = CPU(dev);
TriCoreCPU *cpu = TRICORE_CPU(s);
TriCoreCPUClass *tcc = TRICORE_CPU_GET_CLASS(cpu);
CPUTriCoreState *env = &cpu->env;
tcc->parent_reset(dev);
memset(env, 0, offsetof(CPUTriCoreState, end_reset_fields));
cpu_state_reset(env);
}
static bool tricore_cpu_has_work(CPUState *cs)
{
return true;
}
static void tricore_cpu_realizefn(CPUState *dev)
{
CPUState *cs = CPU(dev);
TriCoreCPU *cpu = TRICORE_CPU(dev);
CPUTriCoreState *env = &cpu->env;
cpu_exec_realizefn(cs);
/* Some features automatically imply others */
if (tricore_feature(env, TRICORE_FEATURE_161)) {
set_feature(env, TRICORE_FEATURE_16);
}
if (tricore_feature(env, TRICORE_FEATURE_16)) {
set_feature(env, TRICORE_FEATURE_131);
}
if (tricore_feature(env, TRICORE_FEATURE_131)) {
set_feature(env, TRICORE_FEATURE_13);
}
cpu_reset(cs);
}
static void tricore_cpu_initfn(struct uc_struct *uc, CPUState *obj)
{
TriCoreCPU *cpu = TRICORE_CPU(obj);
CPUTriCoreState *env = &cpu->env;
env->uc = uc;
cpu_set_cpustate_pointers(cpu);
}
static void tc1796_initfn(CPUState *obj)
{
TriCoreCPU *cpu = TRICORE_CPU(obj);
set_feature(&cpu->env, TRICORE_FEATURE_13);
}
static void tc1797_initfn(CPUState *obj)
{
TriCoreCPU *cpu = TRICORE_CPU(obj);
set_feature(&cpu->env, TRICORE_FEATURE_131);
}
static void tc27x_initfn(CPUState *obj)
{
TriCoreCPU *cpu = TRICORE_CPU(obj);
set_feature(&cpu->env, TRICORE_FEATURE_161);
}
static void tricore_cpu_class_init(CPUClass *c)
{
TriCoreCPUClass *mcc = TRICORE_CPU_CLASS(c);
CPUClass *cc = CPU_CLASS(c);
/* parent class is CPUClass, parent_reset() is cpu_common_reset(). */
mcc->parent_reset = cc->reset;
cc->reset = tricore_cpu_reset;
cc->has_work = tricore_cpu_has_work;
cc->set_pc = tricore_cpu_set_pc;
cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb;
cc->get_phys_page_debug = tricore_cpu_get_phys_page_debug;
cc->tlb_fill = tricore_cpu_tlb_fill;
cc->tcg_initialize = tricore_tcg_init;
}
#define DEFINE_TRICORE_CPU_TYPE(cpu_model, initfn) \
{ \
.parent = TYPE_TRICORE_CPU, \
.initfn = initfn, \
.name = TRICORE_CPU_TYPE_NAME(cpu_model), \
}
struct TriCoreCPUInfo {
const char *name;
void (*initfn)(CPUState *obj);
};
static struct TriCoreCPUInfo tricore_cpus_type_infos[] = {
{ "tc1796", tc1796_initfn },
{ "tc1797", tc1797_initfn },
{ "tc27x", tc27x_initfn },
};
TriCoreCPU *cpu_tricore_init(struct uc_struct *uc)
{
TriCoreCPU *cpu;
CPUState *cs;
CPUClass *cc;
cpu = calloc(1, sizeof(*cpu));
if (cpu == NULL) {
return NULL;
}
if (uc->cpu_model == INT_MAX) {
uc->cpu_model = 2; // tc27x
} else if (uc->cpu_model >= ARRAY_SIZE(tricore_cpus_type_infos)) {
free(cpu);
return NULL;
}
cs = (CPUState *)cpu;
cc = (CPUClass *)&cpu->cc;
cs->cc = cc;
cs->uc = uc;
uc->cpu = cs;
cpu_class_init(uc, cc);
tricore_cpu_class_init(cc);
cpu_common_initfn(uc, cs);
tricore_cpu_initfn(uc, cs);
tricore_cpus_type_infos[uc->cpu_model].initfn(cs);
tricore_cpu_realizefn(cs);
// init address space
cpu_address_space_init(cs, 0, cs->memory);
qemu_init_vcpu(cs);
return cpu;
}

410
qemu/target/tricore/cpu.h Normal file
View File

@ -0,0 +1,410 @@
/*
* TriCore emulation for qemu: main CPU struct.
*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#ifndef TRICORE_CPU_H
#define TRICORE_CPU_H
#include "cpu-qom.h"
#include "exec/cpu-defs.h"
#include "tricore-defs.h"
struct tricore_boot_info;
typedef struct tricore_def_t tricore_def_t;
// struct CPUTriCoreState {
typedef struct CPUTriCoreState {
/* GPR Register */
uint32_t gpr_a[16];
uint32_t gpr_d[16];
/* CSFR Register */
uint32_t PCXI;
/* Frequently accessed PSW_USB bits are stored separately for efficiency.
This contains all the other bits. Use psw_{read,write} to access
the whole PSW. */
uint32_t PSW;
/* PSW flag cache for faster execution
*/
uint32_t PSW_USB_C;
uint32_t PSW_USB_V; /* Only if bit 31 set, then flag is set */
uint32_t PSW_USB_SV; /* Only if bit 31 set, then flag is set */
uint32_t PSW_USB_AV; /* Only if bit 31 set, then flag is set. */
uint32_t PSW_USB_SAV; /* Only if bit 31 set, then flag is set. */
uint32_t PC;
uint32_t SYSCON;
uint32_t CPU_ID;
uint32_t CORE_ID;
uint32_t BIV;
uint32_t BTV;
uint32_t ISP;
uint32_t ICR;
uint32_t FCX;
uint32_t LCX;
uint32_t COMPAT;
/* Mem Protection Register */
uint32_t DPR0_0L;
uint32_t DPR0_0U;
uint32_t DPR0_1L;
uint32_t DPR0_1U;
uint32_t DPR0_2L;
uint32_t DPR0_2U;
uint32_t DPR0_3L;
uint32_t DPR0_3U;
uint32_t DPR1_0L;
uint32_t DPR1_0U;
uint32_t DPR1_1L;
uint32_t DPR1_1U;
uint32_t DPR1_2L;
uint32_t DPR1_2U;
uint32_t DPR1_3L;
uint32_t DPR1_3U;
uint32_t DPR2_0L;
uint32_t DPR2_0U;
uint32_t DPR2_1L;
uint32_t DPR2_1U;
uint32_t DPR2_2L;
uint32_t DPR2_2U;
uint32_t DPR2_3L;
uint32_t DPR2_3U;
uint32_t DPR3_0L;
uint32_t DPR3_0U;
uint32_t DPR3_1L;
uint32_t DPR3_1U;
uint32_t DPR3_2L;
uint32_t DPR3_2U;
uint32_t DPR3_3L;
uint32_t DPR3_3U;
uint32_t CPR0_0L;
uint32_t CPR0_0U;
uint32_t CPR0_1L;
uint32_t CPR0_1U;
uint32_t CPR0_2L;
uint32_t CPR0_2U;
uint32_t CPR0_3L;
uint32_t CPR0_3U;
uint32_t CPR1_0L;
uint32_t CPR1_0U;
uint32_t CPR1_1L;
uint32_t CPR1_1U;
uint32_t CPR1_2L;
uint32_t CPR1_2U;
uint32_t CPR1_3L;
uint32_t CPR1_3U;
uint32_t CPR2_0L;
uint32_t CPR2_0U;
uint32_t CPR2_1L;
uint32_t CPR2_1U;
uint32_t CPR2_2L;
uint32_t CPR2_2U;
uint32_t CPR2_3L;
uint32_t CPR2_3U;
uint32_t CPR3_0L;
uint32_t CPR3_0U;
uint32_t CPR3_1L;
uint32_t CPR3_1U;
uint32_t CPR3_2L;
uint32_t CPR3_2U;
uint32_t CPR3_3L;
uint32_t CPR3_3U;
uint32_t DPM0;
uint32_t DPM1;
uint32_t DPM2;
uint32_t DPM3;
uint32_t CPM0;
uint32_t CPM1;
uint32_t CPM2;
uint32_t CPM3;
/* Memory Management Registers */
uint32_t MMU_CON;
uint32_t MMU_ASI;
uint32_t MMU_TVA;
uint32_t MMU_TPA;
uint32_t MMU_TPX;
uint32_t MMU_TFA;
/* {1.3.1 only */
uint32_t BMACON;
uint32_t SMACON;
uint32_t DIEAR;
uint32_t DIETR;
uint32_t CCDIER;
uint32_t MIECON;
uint32_t PIEAR;
uint32_t PIETR;
uint32_t CCPIER;
/*} */
/* Debug Registers */
uint32_t DBGSR;
uint32_t EXEVT;
uint32_t CREVT;
uint32_t SWEVT;
uint32_t TR0EVT;
uint32_t TR1EVT;
uint32_t DMS;
uint32_t DCX;
uint32_t DBGTCR;
uint32_t CCTRL;
uint32_t CCNT;
uint32_t ICNT;
uint32_t M1CNT;
uint32_t M2CNT;
uint32_t M3CNT;
/* Floating Point Registers */
float_status fp_status;
/* QEMU */
int error_code;
uint32_t hflags; /* CPU State */
const tricore_def_t *cpu_model;
void *irq[8];
struct QEMUTimer *timer; /* Internal timer */
/* Fields up to this point are cleared by a CPU reset */
int end_reset_fields;
/* Fields from here on are preserved across CPU reset. */
uint32_t features;
// Unicorn engine
struct uc_struct *uc;
} CPUTriCoreState;
/**
* TriCoreCPU:
* @env: #CPUTriCoreState
*
* A TriCore CPU.
*/
// TODO: Why is the type def needed? Without it the later typedef fails to find this... ?
typedef struct TriCoreCPU {
/*< private >*/
CPUState parent_obj;
/*< public >*/
CPUNegativeOffsetState neg;
CPUTriCoreState env;
struct TriCoreCPUClass cc;
} TriCoreCPU;
hwaddr tricore_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
void tricore_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
#define MASK_PCXI_PCPN 0xff000000
#define MASK_PCXI_PIE_1_3 0x00800000
#define MASK_PCXI_PIE_1_6 0x00200000
#define MASK_PCXI_UL 0x00400000
#define MASK_PCXI_PCXS 0x000f0000
#define MASK_PCXI_PCXO 0x0000ffff
#define MASK_PSW_USB 0xff000000
#define MASK_USB_C 0x80000000
#define MASK_USB_V 0x40000000
#define MASK_USB_SV 0x20000000
#define MASK_USB_AV 0x10000000
#define MASK_USB_SAV 0x08000000
#define MASK_PSW_PRS 0x00003000
#define MASK_PSW_IO 0x00000c00
#define MASK_PSW_IS 0x00000200
#define MASK_PSW_GW 0x00000100
#define MASK_PSW_CDE 0x00000080
#define MASK_PSW_CDC 0x0000007f
#define MASK_PSW_FPU_RM 0x3000000
#define MASK_SYSCON_PRO_TEN 0x2
#define MASK_SYSCON_FCD_SF 0x1
#define MASK_CPUID_MOD 0xffff0000
#define MASK_CPUID_MOD_32B 0x0000ff00
#define MASK_CPUID_REV 0x000000ff
#define MASK_ICR_PIPN 0x00ff0000
#define MASK_ICR_IE_1_3 0x00000100
#define MASK_ICR_IE_1_6 0x00008000
#define MASK_ICR_CCPN 0x000000ff
#define MASK_FCX_FCXS 0x000f0000
#define MASK_FCX_FCXO 0x0000ffff
#define MASK_LCX_LCXS 0x000f0000
#define MASK_LCX_LCX0 0x0000ffff
#define MASK_DBGSR_DE 0x1
#define MASK_DBGSR_HALT 0x6
#define MASK_DBGSR_SUSP 0x10
#define MASK_DBGSR_PREVSUSP 0x20
#define MASK_DBGSR_PEVT 0x40
#define MASK_DBGSR_EVTSRC 0x1f00
#define TRICORE_HFLAG_KUU 0x3
#define TRICORE_HFLAG_UM0 0x00002 /* user mode-0 flag */
#define TRICORE_HFLAG_UM1 0x00001 /* user mode-1 flag */
#define TRICORE_HFLAG_SM 0x00000 /* kernel mode flag */
enum tricore_features {
TRICORE_FEATURE_13,
TRICORE_FEATURE_131,
TRICORE_FEATURE_16,
TRICORE_FEATURE_161,
};
static inline int tricore_feature(CPUTriCoreState *env, int feature)
{
return (env->features & (1ULL << feature)) != 0;
}
/* TriCore Traps Classes*/
enum {
TRAPC_NONE = -1,
TRAPC_MMU = 0,
TRAPC_PROT = 1,
TRAPC_INSN_ERR = 2,
TRAPC_CTX_MNG = 3,
TRAPC_SYSBUS = 4,
TRAPC_ASSERT = 5,
TRAPC_SYSCALL = 6,
TRAPC_NMI = 7,
TRAPC_IRQ = 8
};
/* Class 0 TIN */
enum {
TIN0_VAF = 0,
TIN0_VAP = 1,
};
/* Class 1 TIN */
enum {
TIN1_PRIV = 1,
TIN1_MPR = 2,
TIN1_MPW = 3,
TIN1_MPX = 4,
TIN1_MPP = 5,
TIN1_MPN = 6,
TIN1_GRWP = 7,
};
/* Class 2 TIN */
enum {
TIN2_IOPC = 1,
TIN2_UOPC = 2,
TIN2_OPD = 3,
TIN2_ALN = 4,
TIN2_MEM = 5,
};
/* Class 3 TIN */
enum {
TIN3_FCD = 1,
TIN3_CDO = 2,
TIN3_CDU = 3,
TIN3_FCU = 4,
TIN3_CSU = 5,
TIN3_CTYP = 6,
TIN3_NEST = 7,
};
/* Class 4 TIN */
enum {
TIN4_PSE = 1,
TIN4_DSE = 2,
TIN4_DAE = 3,
TIN4_CAE = 4,
TIN4_PIE = 5,
TIN4_DIE = 6,
};
/* Class 5 TIN */
enum {
TIN5_OVF = 1,
TIN5_SOVF = 1,
};
/* Class 6 TIN
*
* Is always TIN6_SYS
*/
/* Class 7 TIN */
enum {
TIN7_NMI = 0,
};
uint32_t psw_read(CPUTriCoreState *env);
void psw_write(CPUTriCoreState *env, uint32_t val);
int tricore_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
int tricore_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
void fpu_set_state(CPUTriCoreState *env);
#define MMU_USER_IDX 2
void tricore_cpu_list(void);
#define cpu_list tricore_cpu_list
static inline int cpu_mmu_index(CPUTriCoreState *env, bool ifetch)
{
return 0;
}
typedef CPUTriCoreState CPUArchState;
typedef TriCoreCPU ArchCPU;
#include "exec/cpu-all.h"
void cpu_state_reset(CPUTriCoreState *s);
void tricore_tcg_init(struct uc_struct *uc);
static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
*pc = env->PC;
*cs_base = 0;
*flags = 0;
}
#define TRICORE_CPU_TYPE_SUFFIX "-" TYPE_TRICORE_CPU
#define TRICORE_CPU_TYPE_NAME(model) model TRICORE_CPU_TYPE_SUFFIX
#define CPU_RESOLVING_TYPE TYPE_TRICORE_CPU
/* helpers.c */
bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr);
#endif /* TRICORE_CPU_H */

View File

@ -0,0 +1,125 @@
/* A(ll) access permited
R(ead only) access
E(nd init protected) access
A|R|E(offset, register, feature introducing reg)
NOTE: PSW is handled as a special case in gen_mtcr/mfcr */
A(0xfe00, PCXI, TRICORE_FEATURE_13)
A(0xfe08, PC, TRICORE_FEATURE_13)
A(0xfe14, SYSCON, TRICORE_FEATURE_13)
R(0xfe18, CPU_ID, TRICORE_FEATURE_13)
R(0xfe1c, CORE_ID, TRICORE_FEATURE_161)
E(0xfe20, BIV, TRICORE_FEATURE_13)
E(0xfe24, BTV, TRICORE_FEATURE_13)
E(0xfe28, ISP, TRICORE_FEATURE_13)
A(0xfe2c, ICR, TRICORE_FEATURE_13)
A(0xfe38, FCX, TRICORE_FEATURE_13)
A(0xfe3c, LCX, TRICORE_FEATURE_13)
E(0x9400, COMPAT, TRICORE_FEATURE_131)
/* memory protection register */
A(0xC000, DPR0_0L, TRICORE_FEATURE_13)
A(0xC004, DPR0_0U, TRICORE_FEATURE_13)
A(0xC008, DPR0_1L, TRICORE_FEATURE_13)
A(0xC00C, DPR0_1U, TRICORE_FEATURE_13)
A(0xC010, DPR0_2L, TRICORE_FEATURE_13)
A(0xC014, DPR0_2U, TRICORE_FEATURE_13)
A(0xC018, DPR0_3L, TRICORE_FEATURE_13)
A(0xC01C, DPR0_3U, TRICORE_FEATURE_13)
A(0xC400, DPR1_0L, TRICORE_FEATURE_13)
A(0xC404, DPR1_0U, TRICORE_FEATURE_13)
A(0xC408, DPR1_1L, TRICORE_FEATURE_13)
A(0xC40C, DPR1_1U, TRICORE_FEATURE_13)
A(0xC410, DPR1_2L, TRICORE_FEATURE_13)
A(0xC414, DPR1_2U, TRICORE_FEATURE_13)
A(0xC418, DPR1_3L, TRICORE_FEATURE_13)
A(0xC41C, DPR1_3U, TRICORE_FEATURE_13)
A(0xC800, DPR2_0L, TRICORE_FEATURE_13)
A(0xC804, DPR2_0U, TRICORE_FEATURE_13)
A(0xC808, DPR2_1L, TRICORE_FEATURE_13)
A(0xC80C, DPR2_1U, TRICORE_FEATURE_13)
A(0xC810, DPR2_2L, TRICORE_FEATURE_13)
A(0xC814, DPR2_2U, TRICORE_FEATURE_13)
A(0xC818, DPR2_3L, TRICORE_FEATURE_13)
A(0xC81C, DPR2_3U, TRICORE_FEATURE_13)
A(0xCC00, DPR3_0L, TRICORE_FEATURE_13)
A(0xCC04, DPR3_0U, TRICORE_FEATURE_13)
A(0xCC08, DPR3_1L, TRICORE_FEATURE_13)
A(0xCC0C, DPR3_1U, TRICORE_FEATURE_13)
A(0xCC10, DPR3_2L, TRICORE_FEATURE_13)
A(0xCC14, DPR3_2U, TRICORE_FEATURE_13)
A(0xCC18, DPR3_3L, TRICORE_FEATURE_13)
A(0xCC1C, DPR3_3U, TRICORE_FEATURE_13)
A(0xD000, CPR0_0L, TRICORE_FEATURE_13)
A(0xD004, CPR0_0U, TRICORE_FEATURE_13)
A(0xD008, CPR0_1L, TRICORE_FEATURE_13)
A(0xD00C, CPR0_1U, TRICORE_FEATURE_13)
A(0xD010, CPR0_2L, TRICORE_FEATURE_13)
A(0xD014, CPR0_2U, TRICORE_FEATURE_13)
A(0xD018, CPR0_3L, TRICORE_FEATURE_13)
A(0xD01C, CPR0_3U, TRICORE_FEATURE_13)
A(0xD400, CPR1_0L, TRICORE_FEATURE_13)
A(0xD404, CPR1_0U, TRICORE_FEATURE_13)
A(0xD408, CPR1_1L, TRICORE_FEATURE_13)
A(0xD40C, CPR1_1U, TRICORE_FEATURE_13)
A(0xD410, CPR1_2L, TRICORE_FEATURE_13)
A(0xD414, CPR1_2U, TRICORE_FEATURE_13)
A(0xD418, CPR1_3L, TRICORE_FEATURE_13)
A(0xD41C, CPR1_3U, TRICORE_FEATURE_13)
A(0xD800, CPR2_0L, TRICORE_FEATURE_13)
A(0xD804, CPR2_0U, TRICORE_FEATURE_13)
A(0xD808, CPR2_1L, TRICORE_FEATURE_13)
A(0xD80C, CPR2_1U, TRICORE_FEATURE_13)
A(0xD810, CPR2_2L, TRICORE_FEATURE_13)
A(0xD814, CPR2_2U, TRICORE_FEATURE_13)
A(0xD818, CPR2_3L, TRICORE_FEATURE_13)
A(0xD81C, CPR2_3U, TRICORE_FEATURE_13)
A(0xDC00, CPR3_0L, TRICORE_FEATURE_13)
A(0xDC04, CPR3_0U, TRICORE_FEATURE_13)
A(0xDC08, CPR3_1L, TRICORE_FEATURE_13)
A(0xDC0C, CPR3_1U, TRICORE_FEATURE_13)
A(0xDC10, CPR3_2L, TRICORE_FEATURE_13)
A(0xDC14, CPR3_2U, TRICORE_FEATURE_13)
A(0xDC18, CPR3_3L, TRICORE_FEATURE_13)
A(0xDC1C, CPR3_3U, TRICORE_FEATURE_13)
A(0xE000, DPM0, TRICORE_FEATURE_13)
A(0xE080, DPM1, TRICORE_FEATURE_13)
A(0xE100, DPM2, TRICORE_FEATURE_13)
A(0xE180, DPM3, TRICORE_FEATURE_13)
A(0xE200, CPM0, TRICORE_FEATURE_13)
A(0xE280, CPM1, TRICORE_FEATURE_13)
A(0xE300, CPM2, TRICORE_FEATURE_13)
A(0xE380, CPM3, TRICORE_FEATURE_13)
/* memory management registers */
A(0x8000, MMU_CON, TRICORE_FEATURE_13)
A(0x8004, MMU_ASI, TRICORE_FEATURE_13)
A(0x800C, MMU_TVA, TRICORE_FEATURE_13)
A(0x8010, MMU_TPA, TRICORE_FEATURE_13)
A(0x8014, MMU_TPX, TRICORE_FEATURE_13)
A(0x8018, MMU_TFA, TRICORE_FEATURE_13)
E(0x9004, BMACON, TRICORE_FEATURE_131)
E(0x900C, SMACON, TRICORE_FEATURE_131)
A(0x9020, DIEAR, TRICORE_FEATURE_131)
A(0x9024, DIETR, TRICORE_FEATURE_131)
A(0x9028, CCDIER, TRICORE_FEATURE_131)
E(0x9044, MIECON, TRICORE_FEATURE_131)
A(0x9210, PIEAR, TRICORE_FEATURE_131)
A(0x9214, PIETR, TRICORE_FEATURE_131)
A(0x9218, CCPIER, TRICORE_FEATURE_131)
/* debug registers */
A(0xFD00, DBGSR, TRICORE_FEATURE_13)
A(0xFD08, EXEVT, TRICORE_FEATURE_13)
A(0xFD0C, CREVT, TRICORE_FEATURE_13)
A(0xFD10, SWEVT, TRICORE_FEATURE_13)
A(0xFD20, TR0EVT, TRICORE_FEATURE_13)
A(0xFD24, TR1EVT, TRICORE_FEATURE_13)
A(0xFD40, DMS, TRICORE_FEATURE_13)
A(0xFD44, DCX, TRICORE_FEATURE_13)
A(0xFD48, DBGTCR, TRICORE_FEATURE_131)
A(0xFC00, CCTRL, TRICORE_FEATURE_131)
A(0xFC04, CCNT, TRICORE_FEATURE_131)
A(0xFC08, ICNT, TRICORE_FEATURE_131)
A(0xFC0C, M1CNT, TRICORE_FEATURE_131)
A(0xFC10, M2CNT, TRICORE_FEATURE_131)
A(0xFC14, M3CNT, TRICORE_FEATURE_131)

View File

@ -0,0 +1,478 @@
/*
* TriCore emulation for qemu: fpu helper.
*
* Copyright (c) 2016 Bastian Koppelmann University of Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "qemu/host-utils.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "fpu/softfloat.h"
#define QUIET_NAN 0x7fc00000
#define ADD_NAN 0x7fc00001
#define SQRT_NAN 0x7fc00004
#define DIV_NAN 0x7fc00008
#define MUL_NAN 0x7fc00002
#define FPU_FS PSW_USB_C
#define FPU_FI PSW_USB_V
#define FPU_FV PSW_USB_SV
#define FPU_FZ PSW_USB_AV
#define FPU_FU PSW_USB_SAV
#define float32_sqrt_nan make_float32(SQRT_NAN)
#define float32_quiet_nan make_float32(QUIET_NAN)
/* we don't care about input_denormal */
static inline uint8_t f_get_excp_flags(CPUTriCoreState *env)
{
return get_float_exception_flags(&env->fp_status)
& (float_flag_invalid
| float_flag_overflow
| float_flag_underflow
| float_flag_output_denormal
| float_flag_divbyzero
| float_flag_inexact);
}
static inline float32 f_maddsub_nan_result(float32 arg1, float32 arg2,
float32 arg3, float32 result,
uint32_t muladd_negate_c)
{
uint32_t aSign, bSign, cSign;
uint32_t aExp, bExp, cExp;
if (float32_is_any_nan(arg1) || float32_is_any_nan(arg2) ||
float32_is_any_nan(arg3)) {
return QUIET_NAN;
} else if (float32_is_infinity(arg1) && float32_is_zero(arg2)) {
return MUL_NAN;
} else if (float32_is_zero(arg1) && float32_is_infinity(arg2)) {
return MUL_NAN;
} else {
aSign = arg1 >> 31;
bSign = arg2 >> 31;
cSign = arg3 >> 31;
aExp = (arg1 >> 23) & 0xff;
bExp = (arg2 >> 23) & 0xff;
cExp = (arg3 >> 23) & 0xff;
if (muladd_negate_c) {
cSign ^= 1;
}
if (((aExp == 0xff) || (bExp == 0xff)) && (cExp == 0xff)) {
if (aSign ^ bSign ^ cSign) {
return ADD_NAN;
}
}
}
return result;
}
static void f_update_psw_flags(CPUTriCoreState *env, uint8_t flags)
{
uint8_t some_excp = 0;
set_float_exception_flags(0, &env->fp_status);
if (flags & float_flag_invalid) {
env->FPU_FI = 1 << 31;
some_excp = 1;
}
if (flags & float_flag_overflow) {
env->FPU_FV = 1 << 31;
some_excp = 1;
}
if (flags & float_flag_underflow || flags & float_flag_output_denormal) {
env->FPU_FU = 1 << 31;
some_excp = 1;
}
if (flags & float_flag_divbyzero) {
env->FPU_FZ = 1 << 31;
some_excp = 1;
}
if (flags & float_flag_inexact || flags & float_flag_output_denormal) {
env->PSW |= 1 << 26;
some_excp = 1;
}
env->FPU_FS = some_excp;
}
#define FADD_SUB(op) \
uint32_t helper_f##op(CPUTriCoreState *env, uint32_t r1, uint32_t r2) \
{ \
float32 arg1 = make_float32(r1); \
float32 arg2 = make_float32(r2); \
uint32_t flags; \
float32 f_result; \
\
f_result = float32_##op(arg2, arg1, &env->fp_status); \
flags = f_get_excp_flags(env); \
if (flags) { \
/* If the output is a NaN, but the inputs aren't, \
we return a unique value. */ \
if ((flags & float_flag_invalid) \
&& !float32_is_any_nan(arg1) \
&& !float32_is_any_nan(arg2)) { \
f_result = ADD_NAN; \
} \
f_update_psw_flags(env, flags); \
} else { \
env->FPU_FS = 0; \
} \
return (uint32_t)f_result; \
}
FADD_SUB(add)
FADD_SUB(sub)
uint32_t helper_fmul(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
{
uint32_t flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
float32 f_result;
f_result = float32_mul(arg1, arg2, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
/* If the output is a NaN, but the inputs aren't,
we return a unique value. */
if ((flags & float_flag_invalid)
&& !float32_is_any_nan(arg1)
&& !float32_is_any_nan(arg2)) {
f_result = MUL_NAN;
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
/*
* Target TriCore QSEED.F significand Lookup Table
*
* The QSEED.F output significand depends on the least-significant
* exponent bit and the 6 most-significant significand bits.
*
* IEEE 754 float datatype
* partitioned into Sign (S), Exponent (E) and Significand (M):
*
* S E E E E E E E E M M M M M M ...
* | | |
* +------+------+-------+-------+
* | |
* for lookup table
* calculating index for
* output E output M
*
* This lookup table was extracted by analyzing QSEED output
* from the real hardware
*/
static const uint8_t target_qseed_significand_table[128] = {
253, 252, 245, 244, 239, 238, 231, 230, 225, 224, 217, 216,
211, 210, 205, 204, 201, 200, 195, 194, 189, 188, 185, 184,
179, 178, 175, 174, 169, 168, 165, 164, 161, 160, 157, 156,
153, 152, 149, 148, 145, 144, 141, 140, 137, 136, 133, 132,
131, 130, 127, 126, 123, 122, 121, 120, 117, 116, 115, 114,
111, 110, 109, 108, 103, 102, 99, 98, 93, 92, 89, 88, 83,
82, 79, 78, 75, 74, 71, 70, 67, 66, 63, 62, 59, 58, 55,
54, 53, 52, 49, 48, 45, 44, 43, 42, 39, 38, 37, 36, 33,
32, 31, 30, 27, 26, 25, 24, 23, 22, 19, 18, 17, 16, 15,
14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2
};
uint32_t helper_qseed(CPUTriCoreState *env, uint32_t r1)
{
uint32_t arg1, S, E, M, E_minus_one, m_idx;
uint32_t new_E, new_M, new_S, result;
arg1 = make_float32(r1);
/* fetch IEEE-754 fields S, E and the uppermost 6-bit of M */
S = extract32(arg1, 31, 1);
E = extract32(arg1, 23, 8);
M = extract32(arg1, 17, 6);
if (float32_is_any_nan(arg1)) {
result = float32_quiet_nan;
} else if (float32_is_zero_or_denormal(arg1)) {
if (float32_is_neg(arg1)) {
result = float32_infinity | (1 << 31);
} else {
result = float32_infinity;
}
} else if (float32_is_neg(arg1)) {
result = float32_sqrt_nan;
} else if (float32_is_infinity(arg1)) {
result = float32_zero;
} else {
E_minus_one = E - 1;
m_idx = ((E_minus_one & 1) << 6) | M;
new_S = S;
new_E = 0xBD - E_minus_one / 2;
new_M = target_qseed_significand_table[m_idx];
result = 0;
result = deposit32(result, 31, 1, new_S);
result = deposit32(result, 23, 8, new_E);
result = deposit32(result, 15, 8, new_M);
}
if (float32_is_signaling_nan(arg1, &env->fp_status)
|| result == float32_sqrt_nan) {
env->FPU_FI = 1 << 31;
env->FPU_FS = 1;
} else {
env->FPU_FS = 0;
}
return (uint32_t) result;
}
uint32_t helper_fdiv(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
{
uint32_t flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
float32 f_result;
f_result = float32_div(arg1, arg2 , &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
/* If the output is a NaN, but the inputs aren't,
we return a unique value. */
if ((flags & float_flag_invalid)
&& !float32_is_any_nan(arg1)
&& !float32_is_any_nan(arg2)) {
f_result = DIV_NAN;
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_fmadd(CPUTriCoreState *env, uint32_t r1,
uint32_t r2, uint32_t r3)
{
uint32_t flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
float32 arg3 = make_float32(r3);
float32 f_result;
f_result = float32_muladd(arg1, arg2, arg3, 0, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
if (flags & float_flag_invalid) {
arg1 = float32_squash_input_denormal(arg1, &env->fp_status);
arg2 = float32_squash_input_denormal(arg2, &env->fp_status);
arg3 = float32_squash_input_denormal(arg3, &env->fp_status);
f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, 0);
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_fmsub(CPUTriCoreState *env, uint32_t r1,
uint32_t r2, uint32_t r3)
{
uint32_t flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
float32 arg3 = make_float32(r3);
float32 f_result;
f_result = float32_muladd(arg1, arg2, arg3, float_muladd_negate_product,
&env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
if (flags & float_flag_invalid) {
arg1 = float32_squash_input_denormal(arg1, &env->fp_status);
arg2 = float32_squash_input_denormal(arg2, &env->fp_status);
arg3 = float32_squash_input_denormal(arg3, &env->fp_status);
f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, 1);
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_fcmp(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
{
uint32_t result, flags;
float32 arg1 = make_float32(r1);
float32 arg2 = make_float32(r2);
set_flush_inputs_to_zero(0, &env->fp_status);
result = 1 << (float32_compare_quiet(arg1, arg2, &env->fp_status) + 1);
result |= float32_is_denormal(arg1) << 4;
result |= float32_is_denormal(arg2) << 5;
flags = f_get_excp_flags(env);
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
set_flush_inputs_to_zero(1, &env->fp_status);
return result;
}
uint32_t helper_ftoi(CPUTriCoreState *env, uint32_t arg)
{
float32 f_arg = make_float32(arg);
int32_t result, flags;
result = float32_to_int32(f_arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
if (float32_is_any_nan(f_arg)) {
result = 0;
}
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)result;
}
uint32_t helper_itof(CPUTriCoreState *env, uint32_t arg)
{
float32 f_result;
uint32_t flags;
f_result = int32_to_float32(arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_utof(CPUTriCoreState *env, uint32_t arg)
{
float32 f_result;
uint32_t flags;
f_result = uint32_to_float32(arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return (uint32_t)f_result;
}
uint32_t helper_ftoiz(CPUTriCoreState *env, uint32_t arg)
{
float32 f_arg = make_float32(arg);
uint32_t result;
int32_t flags;
result = float32_to_int32_round_to_zero(f_arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags & float_flag_invalid) {
flags &= ~float_flag_inexact;
if (float32_is_any_nan(f_arg)) {
result = 0;
}
}
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return result;
}
uint32_t helper_ftouz(CPUTriCoreState *env, uint32_t arg)
{
float32 f_arg = make_float32(arg);
uint32_t result;
int32_t flags;
result = float32_to_uint32_round_to_zero(f_arg, &env->fp_status);
flags = f_get_excp_flags(env);
if (flags & float_flag_invalid) {
flags &= ~float_flag_inexact;
if (float32_is_any_nan(f_arg)) {
result = 0;
}
} else if (float32_lt_quiet(f_arg, 0, &env->fp_status)) {
flags = float_flag_invalid;
result = 0;
}
if (flags) {
f_update_psw_flags(env, flags);
} else {
env->FPU_FS = 0;
}
return result;
}
void helper_updfl(CPUTriCoreState *env, uint32_t arg)
{
env->FPU_FS = extract32(arg, 7, 1) & extract32(arg, 15, 1);
env->FPU_FI = (extract32(arg, 6, 1) & extract32(arg, 14, 1)) << 31;
env->FPU_FV = (extract32(arg, 5, 1) & extract32(arg, 13, 1)) << 31;
env->FPU_FZ = (extract32(arg, 4, 1) & extract32(arg, 12, 1)) << 31;
env->FPU_FU = (extract32(arg, 3, 1) & extract32(arg, 11, 1)) << 31;
/* clear FX and RM */
env->PSW &= ~(extract32(arg, 10, 1) << 26);
env->PSW |= (extract32(arg, 2, 1) & extract32(arg, 10, 1)) << 26;
fpu_set_state(env);
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "fpu/softfloat-helpers.h"
enum {
TLBRET_DIRTY = -4,
TLBRET_INVALID = -3,
TLBRET_NOMATCH = -2,
TLBRET_BADADDR = -1,
TLBRET_MATCH = 0
};
#if defined(CONFIG_SOFTMMU)
static int get_physical_address(CPUTriCoreState *env, hwaddr *physical,
int *prot, target_ulong address,
MMUAccessType access_type, int mmu_idx)
{
int ret = TLBRET_MATCH;
*physical = address & 0xFFFFFFFF;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
return ret;
}
hwaddr tricore_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
TriCoreCPU *cpu = TRICORE_CPU(cs);
hwaddr phys_addr;
int prot;
int mmu_idx = cpu_mmu_index(&cpu->env, false);
if (get_physical_address(&cpu->env, &phys_addr, &prot, addr,
MMU_DATA_LOAD, mmu_idx)) {
return -1;
}
return phys_addr;
}
#endif
/* TODO: Add exeption support*/
static void raise_mmu_exception(CPUTriCoreState *env, target_ulong address,
int rw, int tlb_error)
{
}
bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType rw, int mmu_idx,
bool probe, uintptr_t retaddr)
{
TriCoreCPU *cpu = TRICORE_CPU(cs);
CPUTriCoreState *env = &cpu->env;
hwaddr physical;
int prot;
int ret = 0;
rw &= 1;
ret = get_physical_address(env, &physical, &prot,
address, rw, mmu_idx);
// qemu_log_mask(CPU_LOG_MMU, "%s address=" TARGET_FMT_lx " ret %d physical "
// TARGET_FMT_plx " prot %d\n",
// __func__, (target_ulong)address, ret, physical, prot);
if (ret == TLBRET_MATCH) {
tlb_set_page(cs, address & TARGET_PAGE_MASK,
physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
mmu_idx, TARGET_PAGE_SIZE);
return true;
} else {
assert(ret < 0);
if (probe) {
return false;
}
raise_mmu_exception(env, address, rw, ret);
cpu_loop_exit_restore(cs, retaddr);
}
}
#if 0
static void tricore_cpu_list_entry(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
const char *typename;
char *name;
typename = object_class_get_name(oc);
name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_TRICORE_CPU));
qemu_printf(" %s\n", name);
g_free(name);
}
#endif
#if 0
void tricore_cpu_list(void)
{
GSList *list;
list = object_class_get_list_sorted(TYPE_TRICORE_CPU, false);
qemu_printf("Available CPUs:\n");
g_slist_foreach(list, tricore_cpu_list_entry, NULL);
g_slist_free(list);
}
#endif
void fpu_set_state(CPUTriCoreState *env)
{
set_float_rounding_mode(env->PSW & MASK_PSW_FPU_RM, &env->fp_status);
set_flush_inputs_to_zero(1, &env->fp_status);
set_flush_to_zero(1, &env->fp_status);
set_default_nan_mode(1, &env->fp_status);
}
uint32_t psw_read(CPUTriCoreState *env)
{
/* clear all USB bits */
env->PSW &= 0x6ffffff;
/* now set them from the cache */
env->PSW |= ((env->PSW_USB_C != 0) << 31);
env->PSW |= ((env->PSW_USB_V & (1 << 31)) >> 1);
env->PSW |= ((env->PSW_USB_SV & (1 << 31)) >> 2);
env->PSW |= ((env->PSW_USB_AV & (1 << 31)) >> 3);
env->PSW |= ((env->PSW_USB_SAV & (1 << 31)) >> 4);
return env->PSW;
}
void psw_write(CPUTriCoreState *env, uint32_t val)
{
env->PSW_USB_C = (val & MASK_USB_C);
env->PSW_USB_V = (val & MASK_USB_V) << 1;
env->PSW_USB_SV = (val & MASK_USB_SV) << 2;
env->PSW_USB_AV = (val & MASK_USB_AV) << 3;
env->PSW_USB_SAV = (val & MASK_USB_SAV) << 4;
env->PSW = val;
fpu_set_state(env);
}

View File

@ -0,0 +1,163 @@
/*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64)
/* Arithmetic */
DEF_HELPER_3(add_ssov, i32, env, i32, i32)
DEF_HELPER_3(add64_ssov, i64, env, i64, i64)
DEF_HELPER_3(add_suov, i32, env, i32, i32)
DEF_HELPER_3(add_h_ssov, i32, env, i32, i32)
DEF_HELPER_3(add_h_suov, i32, env, i32, i32)
DEF_HELPER_4(addr_h_ssov, i32, env, i64, i32, i32)
DEF_HELPER_4(addsur_h_ssov, i32, env, i64, i32, i32)
DEF_HELPER_3(sub_ssov, i32, env, i32, i32)
DEF_HELPER_3(sub64_ssov, i64, env, i64, i64)
DEF_HELPER_3(sub_suov, i32, env, i32, i32)
DEF_HELPER_3(sub_h_ssov, i32, env, i32, i32)
DEF_HELPER_3(sub_h_suov, i32, env, i32, i32)
DEF_HELPER_4(subr_h_ssov, i32, env, i64, i32, i32)
DEF_HELPER_4(subadr_h_ssov, i32, env, i64, i32, i32)
DEF_HELPER_3(mul_ssov, i32, env, i32, i32)
DEF_HELPER_3(mul_suov, i32, env, i32, i32)
DEF_HELPER_3(sha_ssov, i32, env, i32, i32)
DEF_HELPER_3(absdif_ssov, i32, env, i32, i32)
DEF_HELPER_4(madd32_ssov, i32, env, i32, i32, i32)
DEF_HELPER_4(madd32_suov, i32, env, i32, i32, i32)
DEF_HELPER_4(madd64_ssov, i64, env, i32, i64, i32)
DEF_HELPER_5(madd64_q_ssov, i64, env, i64, i32, i32, i32)
DEF_HELPER_3(madd32_q_add_ssov, i32, env, i64, i64)
DEF_HELPER_5(maddr_q_ssov, i32, env, i32, i32, i32, i32)
DEF_HELPER_4(madd64_suov, i64, env, i32, i64, i32)
DEF_HELPER_4(msub32_ssov, i32, env, i32, i32, i32)
DEF_HELPER_4(msub32_suov, i32, env, i32, i32, i32)
DEF_HELPER_4(msub64_ssov, i64, env, i32, i64, i32)
DEF_HELPER_5(msub64_q_ssov, i64, env, i64, i32, i32, i32)
DEF_HELPER_3(msub32_q_sub_ssov, i32, env, i64, i64)
DEF_HELPER_5(msubr_q_ssov, i32, env, i32, i32, i32, i32)
DEF_HELPER_4(msub64_suov, i64, env, i32, i64, i32)
DEF_HELPER_3(absdif_h_ssov, i32, env, i32, i32)
DEF_HELPER_2(abs_ssov, i32, env, i32)
DEF_HELPER_2(abs_h_ssov, i32, env, i32)
/* hword/byte arithmetic */
DEF_HELPER_2(abs_b, i32, env, i32)
DEF_HELPER_2(abs_h, i32, env, i32)
DEF_HELPER_3(absdif_b, i32, env, i32, i32)
DEF_HELPER_3(absdif_h, i32, env, i32, i32)
DEF_HELPER_4(addr_h, i32, env, i64, i32, i32)
DEF_HELPER_4(addsur_h, i32, env, i64, i32, i32)
DEF_HELPER_5(maddr_q, i32, env, i32, i32, i32, i32)
DEF_HELPER_3(add_b, i32, env, i32, i32)
DEF_HELPER_3(add_h, i32, env, i32, i32)
DEF_HELPER_3(sub_b, i32, env, i32, i32)
DEF_HELPER_3(sub_h, i32, env, i32, i32)
DEF_HELPER_4(subr_h, i32, env, i64, i32, i32)
DEF_HELPER_4(subadr_h, i32, env, i64, i32, i32)
DEF_HELPER_5(msubr_q, i32, env, i32, i32, i32, i32)
DEF_HELPER_FLAGS_2(eq_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(eq_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(eqany_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(eqany_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(lt_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(lt_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(lt_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(lt_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(max_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(ixmax, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(ixmax_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(min_b, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(min_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(min_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(min_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(ixmin, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(ixmin_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
/* count leading ... */
DEF_HELPER_FLAGS_1(clo_h, TCG_CALL_NO_RWG_SE, i32, i32)
DEF_HELPER_FLAGS_1(clz_h, TCG_CALL_NO_RWG_SE, i32, i32)
DEF_HELPER_FLAGS_1(cls_h, TCG_CALL_NO_RWG_SE, i32, i32)
/* sh */
DEF_HELPER_FLAGS_2(sh, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_2(sh_h, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_3(sha, i32, env, i32, i32)
DEF_HELPER_2(sha_h, i32, i32, i32)
/* merge/split/parity */
DEF_HELPER_FLAGS_2(bmerge, TCG_CALL_NO_RWG_SE, i32, i32, i32)
DEF_HELPER_FLAGS_1(bsplit, TCG_CALL_NO_RWG_SE, i64, i32)
DEF_HELPER_FLAGS_1(parity, TCG_CALL_NO_RWG_SE, i32, i32)
/* float */
DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32)
DEF_HELPER_1(unpack, i64, i32)
DEF_HELPER_3(fadd, i32, env, i32, i32)
DEF_HELPER_3(fsub, i32, env, i32, i32)
DEF_HELPER_3(fmul, i32, env, i32, i32)
DEF_HELPER_3(fdiv, i32, env, i32, i32)
DEF_HELPER_4(fmadd, i32, env, i32, i32, i32)
DEF_HELPER_4(fmsub, i32, env, i32, i32, i32)
DEF_HELPER_3(fcmp, i32, env, i32, i32)
DEF_HELPER_2(qseed, i32, env, i32)
DEF_HELPER_2(ftoi, i32, env, i32)
DEF_HELPER_2(itof, i32, env, i32)
DEF_HELPER_2(utof, i32, env, i32)
DEF_HELPER_2(ftoiz, i32, env, i32)
DEF_HELPER_2(ftouz, i32, env, i32)
DEF_HELPER_2(updfl, void, env, i32)
/* dvinit */
DEF_HELPER_3(dvinit_b_13, i64, env, i32, i32)
DEF_HELPER_3(dvinit_b_131, i64, env, i32, i32)
DEF_HELPER_3(dvinit_h_13, i64, env, i32, i32)
DEF_HELPER_3(dvinit_h_131, i64, env, i32, i32)
DEF_HELPER_FLAGS_2(dvadj, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(dvstep, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(dvstep_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_3(divide, i64, env, i32, i32)
DEF_HELPER_3(divide_u, i64, env, i32, i32)
/* mulh */
DEF_HELPER_FLAGS_5(mul_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)
DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)
DEF_HELPER_FLAGS_5(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32)
/* crc32 */
DEF_HELPER_FLAGS_2(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32)
/* CSA */
DEF_HELPER_2(call, void, env, i32)
DEF_HELPER_1(ret, void, env)
DEF_HELPER_2(bisr, void, env, i32)
DEF_HELPER_1(rfe, void, env)
DEF_HELPER_1(rfm, void, env)
DEF_HELPER_2(ldlcx, void, env, i32)
DEF_HELPER_2(lducx, void, env, i32)
DEF_HELPER_2(stlcx, void, env, i32)
DEF_HELPER_2(stucx, void, env, i32)
DEF_HELPER_1(svlcx, void, env)
DEF_HELPER_1(svucx, void, env)
DEF_HELPER_1(rslcx, void, env)
/* Address mode helper */
DEF_HELPER_1(br_update, i32, i32)
DEF_HELPER_2(circ_update, i32, i32, i32)
/* PSW cache helper */
DEF_HELPER_2(psw_write, void, env, i32)
DEF_HELPER_1(psw_read, i32, env)
/* Exceptions */
DEF_HELPER_3(raise_exception_sync, noreturn, env, i32, i32)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QEMU_TRICORE_DEFS_H
#define QEMU_TRICORE_DEFS_H
#define TRICORE_TLB_MAX 128
#endif /* QEMU_TRICORE_DEFS_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,276 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
/*
Created for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#include "qemu/typedefs.h"
#include "unicorn/unicorn.h"
#include "sysemu/cpus.h"
#include "sysemu/tcg.h"
#include "cpu.h"
#include "uc_priv.h"
#include "unicorn_common.h"
#include "unicorn.h"
TriCoreCPU *cpu_tricore_init(struct uc_struct *uc);
static void tricore_set_pc(struct uc_struct *uc, uint64_t address)
{
((CPUTriCoreState *)uc->cpu->env_ptr)->PC = address;
}
static uint64_t tricore_get_pc(struct uc_struct *uc)
{
return ((CPUTriCoreState *)uc->cpu->env_ptr)->PC;
}
void tricore_reg_reset(struct uc_struct *uc)
{
CPUTriCoreState *env;
(void)uc;
env = uc->cpu->env_ptr;
memset(env->gpr_a, 0, sizeof(env->gpr_a));
memset(env->gpr_d, 0, sizeof(env->gpr_d));
env->PC = 0;
}
static void reg_read(CPUTriCoreState *env, unsigned int regid, void *value)
{
if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9)
*(int32_t *)value = env->gpr_a[regid - UC_TRICORE_REG_A0];
if (regid >= UC_TRICORE_REG_A12 && regid <= UC_TRICORE_REG_A15)
*(int32_t *)value = env->gpr_a[regid - UC_TRICORE_REG_A0];
else if (regid >= UC_TRICORE_REG_D0 && regid <= UC_TRICORE_REG_D15)
*(int32_t *)value = env->gpr_d[regid - UC_TRICORE_REG_D0];
else {
switch (regid) {
// case UC_TRICORE_REG_SP:
case UC_TRICORE_REG_A10:
*(int32_t *)value = env->gpr_a[10];
break;
// case UC_TRICORE_REG_LR:
case UC_TRICORE_REG_A11:
*(int32_t *)value = env->gpr_a[11];
break;
case UC_TRICORE_REG_PC:
*(int32_t *)value = env->PC;
break;
case UC_TRICORE_REG_PCXI:
*(int32_t *)value = env->PCXI;
break;
case UC_TRICORE_REG_PSW:
*(int32_t *)value = env->PSW;
break;
case UC_TRICORE_REG_PSW_USB_C:
*(int32_t *)value = env->PSW_USB_C;
break;
case UC_TRICORE_REG_PSW_USB_V:
*(int32_t *)value = env->PSW_USB_V;
break;
case UC_TRICORE_REG_PSW_USB_SV:
*(int32_t *)value = env->PSW_USB_SV;
break;
case UC_TRICORE_REG_PSW_USB_AV:
*(int32_t *)value = env->PSW_USB_AV;
break;
case UC_TRICORE_REG_PSW_USB_SAV:
*(int32_t *)value = env->PSW_USB_SAV;
break;
case UC_TRICORE_REG_SYSCON:
*(int32_t *)value = env->SYSCON;
break;
case UC_TRICORE_REG_CPU_ID:
*(int32_t *)value = env->CPU_ID;
break;
case UC_TRICORE_REG_BIV:
*(int32_t *)value = env->BIV;
break;
case UC_TRICORE_REG_BTV:
*(int32_t *)value = env->BTV;
break;
case UC_TRICORE_REG_ISP:
*(int32_t *)value = env->ISP;
break;
case UC_TRICORE_REG_ICR:
*(int32_t *)value = env->ICR;
break;
case UC_TRICORE_REG_FCX:
*(int32_t *)value = env->FCX;
break;
case UC_TRICORE_REG_LCX:
*(int32_t *)value = env->LCX;
break;
case UC_TRICORE_REG_COMPAT:
*(int32_t *)value = env->COMPAT;
break;
}
}
}
int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
int count)
{
CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env);
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_read(env, regid, value);
}
return 0;
}
int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs,
void **vals, int count)
{
CPUTriCoreState *env = (CPUTriCoreState *)uc->data;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_read(env, regid, value);
}
return 0;
}
static void reg_write(CPUTriCoreState *env, unsigned int regid,
const void *value)
{
if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9)
env->gpr_a[regid - UC_TRICORE_REG_A0] = *(int32_t *)value;
if (regid >= UC_TRICORE_REG_A12 && regid <= UC_TRICORE_REG_A15)
env->gpr_a[regid - UC_TRICORE_REG_A0] = *(int32_t *)value;
else if (regid >= UC_TRICORE_REG_D0 && regid <= UC_TRICORE_REG_D15)
env->gpr_d[regid - UC_TRICORE_REG_D0] = *(int32_t *)value;
else {
switch (regid) {
// case UC_TRICORE_REG_SP:
case UC_TRICORE_REG_A10:
env->gpr_a[10] = *(int32_t *)value;
break;
// case UC_TRICORE_REG_LR:
case UC_TRICORE_REG_A11:
env->gpr_a[11] = *(int32_t *)value;
break;
case UC_TRICORE_REG_PC:
env->PC = *(int32_t *)value;
break;
case UC_TRICORE_REG_PCXI:
env->PCXI = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW:
env->PSW = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_C:
env->PSW_USB_C = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_V:
env->PSW_USB_V = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_SV:
env->PSW_USB_SV = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_AV:
env->PSW_USB_AV = *(int32_t *)value;
break;
case UC_TRICORE_REG_PSW_USB_SAV:
env->PSW_USB_SAV = *(int32_t *)value;
break;
case UC_TRICORE_REG_SYSCON:
env->SYSCON = *(int32_t *)value;
break;
case UC_TRICORE_REG_CPU_ID:
env->CPU_ID = *(int32_t *)value;
break;
case UC_TRICORE_REG_BIV:
env->BIV = *(int32_t *)value;
break;
case UC_TRICORE_REG_BTV:
env->BTV = *(int32_t *)value;
break;
case UC_TRICORE_REG_ISP:
env->ISP = *(int32_t *)value;
break;
case UC_TRICORE_REG_ICR:
env->ICR = *(int32_t *)value;
break;
case UC_TRICORE_REG_FCX:
env->FCX = *(int32_t *)value;
break;
case UC_TRICORE_REG_LCX:
env->LCX = *(int32_t *)value;
break;
case UC_TRICORE_REG_COMPAT:
env->COMPAT = *(int32_t *)value;
break;
}
}
}
int tricore_reg_write(struct uc_struct *uc, unsigned int *regs,
void *const *vals, int count)
{
CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env);
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_write(env, regid, value);
if (regid == UC_TRICORE_REG_PC) {
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
}
}
return 0;
}
int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs,
void *const *vals, int count)
{
CPUTriCoreState *env = (CPUTriCoreState *)uc->data;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
reg_write(env, regid, value);
}
return 0;
}
static int tricore_cpus_init(struct uc_struct *uc, const char *cpu_model)
{
TriCoreCPU *cpu;
cpu = cpu_tricore_init(uc);
if (cpu == NULL) {
return -1;
}
return 0;
}
void tricore_uc_init(struct uc_struct *uc)
{
uc->reg_read = tricore_reg_read;
uc->reg_write = tricore_reg_write;
uc->reg_reset = tricore_reg_reset;
uc->set_pc = tricore_set_pc;
uc->get_pc = tricore_get_pc;
uc->cpus_init = tricore_cpus_init;
uc->cpu_context_size = offsetof(CPUTriCoreState, end_reset_fields);
uc_common_init(uc);
}

View File

@ -0,0 +1,27 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
/*
Modified for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
#ifndef UC_QEMU_TARGET_TRICORE_H
#define UC_QEMU_TARGET_TRICORE_H
// functions to read & write registers
int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
int count);
int tricore_reg_write(struct uc_struct *uc, unsigned int *regs,
void *const *vals, int count);
int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs,
void **vals, int count);
int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs,
void *const *vals, int count);
void tricore_reg_reset(struct uc_struct *uc);
void tricore_uc_init(struct uc_struct *uc);
#endif

1289
qemu/tricore.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -89,6 +89,9 @@ endif
ifneq (,$(findstring m68k,$(UNICORN_ARCHS)))
SOURCES += sample_m68k.c
endif
ifneq (,$(findstring tricore,$(UNICORN_ARCHS)))
SOURCES += sample_tricore.c
endif
BINS = $(SOURCES:.c=$(BIN_EXT))
OBJS = $(SOURCES:.c=.o)

84
samples/sample_tricore.c Normal file
View File

@ -0,0 +1,84 @@
/*
Created for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
Copyright 2022 Aptiv
*/
/* Sample code to demonstrate how to emulate TriCore code */
#include <unicorn/unicorn.h>
#include <string.h>
// code to be emulated
#define CODE "\x82\x11\xbb\x00\x00\x08" // mov d0, #0x1; mov.u d0, #0x8000
// memory address where emulation starts
#define ADDRESS 0x10000
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size,
void *user_data)
{
printf(">>> Tracing basic block at 0x%" PRIx64 ", block size = 0x%x\n",
address, size);
}
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size,
void *user_data)
{
printf(">>> Tracing instruction at 0x%" PRIx64
", instruction size = 0x%x\n",
address, size);
}
static void test_tricore(void)
{
uc_engine *uc;
uc_err err;
uc_hook trace1, trace2;
uint32_t d0 = 0x0; // d0 register
printf("Emulate TriCore code\n");
// Initialize emulator in TriCore mode
err = uc_open(UC_ARCH_TRICORE, UC_MODE_LITTLE_ENDIAN, &uc);
if (err) {
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
uc_strerror(err));
return;
}
// map 2MB memory for this emulation
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
// write machine code to be emulated to memory
uc_mem_write(uc, ADDRESS, CODE, sizeof(CODE) - 1);
// tracing all basic blocks with customized callback
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
// tracing one instruction at ADDRESS with customized callback
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS,
ADDRESS + sizeof(CODE) - 1);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(CODE) - 1, 0, 0);
if (err) {
printf("Failed on uc_emu_start() with error returned: %u\n", err);
}
// now print out some registers
printf(">>> Emulation done. Below is the CPU context\n");
uc_reg_read(uc, UC_TRICORE_REG_D0, &d0);
printf(">>> d0 = 0x%x\n", d0);
uc_close(uc);
}
int main(int argc, char **argv, char **envp)
{
test_tricore();
return 0;
}

View File

@ -6274,7 +6274,19 @@ tcg_s390_program_interrupt \
tcg_s390_data_exception \
"
ARCHS="x86_64 arm aarch64 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x"
tricore_SYMBOLS="
helper_fadd \
helper_fsub \
helper_fmul \
helper_fdiv \
helper_fmadd \
helper_fmsub \
helper_pack \
gen_intermediate_code \
restore_state_to_opc \
"
ARCHS="x86_64 arm aarch64 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x tricore"
for arch in $ARCHS; do

View File

@ -195,10 +195,110 @@ static void test_arm64_mrs_hook(void)
OK(uc_close(uc));
}
static bool test_arm64_correct_address_in_small_jump_hook_callback(
uc_engine *uc, int type, uint64_t address, int size, int64_t value,
void *user_data)
{
// Check registers
uint64_t r_x0 = 0x0;
uint64_t r_pc = 0x0;
OK(uc_reg_read(uc, UC_ARM64_REG_X0, &r_x0));
OK(uc_reg_read(uc, UC_ARM64_REG_PC, &r_pc));
TEST_CHECK(r_x0 == 0x7F00);
TEST_CHECK(r_pc == 0x7F00);
// Check address
// printf("%lx\n", address);
TEST_CHECK(address == 0x7F00);
return false;
}
static void test_arm64_correct_address_in_small_jump_hook(void)
{
uc_engine *uc;
// mov x0, 0x7F00;
// br x0
char code[] = "\x00\xe0\x8f\xd2\x00\x00\x1f\xd6";
uint64_t r_x0 = 0x0;
uint64_t r_pc = 0x0;
uc_hook hook;
uc_common_setup(&uc, UC_ARCH_ARM64, UC_MODE_ARM, code, sizeof(code) - 1,
UC_CPU_ARM64_A72);
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_UNMAPPED,
test_arm64_correct_address_in_small_jump_hook_callback, NULL,
1, 0));
uc_assert_err(
UC_ERR_FETCH_UNMAPPED,
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_ARM64_REG_X0, &r_x0));
OK(uc_reg_read(uc, UC_ARM64_REG_PC, &r_pc));
TEST_CHECK(r_x0 == 0x7F00);
TEST_CHECK(r_pc == 0x7F00);
OK(uc_close(uc));
}
static bool test_arm64_correct_address_in_long_jump_hook_callback(
uc_engine *uc, int type, uint64_t address, int size, int64_t value,
void *user_data)
{
// Check registers
uint64_t r_x0 = 0x0;
uint64_t r_pc = 0x0;
OK(uc_reg_read(uc, UC_ARM64_REG_X0, &r_x0));
OK(uc_reg_read(uc, UC_ARM64_REG_PC, &r_pc));
TEST_CHECK(r_x0 == 0x7FFFFFFFFFFFFF00);
TEST_CHECK(r_pc == 0x7FFFFFFFFFFFFF00);
// Check address
// printf("%lx\n", address);
TEST_CHECK(address == 0x7FFFFFFFFFFFFF00);
return false;
}
static void test_arm64_correct_address_in_long_jump_hook(void)
{
uc_engine *uc;
// mov x0, 0x7FFFFFFFFFFFFF00;
// br x0
char code[] = "\xe0\xdb\x78\xb2\x00\x00\x1f\xd6";
uint64_t r_x0 = 0x0;
uint64_t r_pc = 0x0;
uc_hook hook;
uc_common_setup(&uc, UC_ARCH_ARM64, UC_MODE_ARM, code, sizeof(code) - 1,
UC_CPU_ARM64_A72);
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_UNMAPPED,
test_arm64_correct_address_in_long_jump_hook_callback, NULL,
1, 0));
uc_assert_err(
UC_ERR_FETCH_UNMAPPED,
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_ARM64_REG_X0, &r_x0));
OK(uc_reg_read(uc, UC_ARM64_REG_PC, &r_pc));
TEST_CHECK(r_x0 == 0x7FFFFFFFFFFFFF00);
TEST_CHECK(r_pc == 0x7FFFFFFFFFFFFF00);
OK(uc_close(uc));
}
TEST_LIST = {{"test_arm64_until", test_arm64_until},
{"test_arm64_code_patching", test_arm64_code_patching},
{"test_arm64_code_patching_count", test_arm64_code_patching_count},
{"test_arm64_v8_pac", test_arm64_v8_pac},
{"test_arm64_read_sctlr", test_arm64_read_sctlr},
{"test_arm64_mrs_hook", test_arm64_mrs_hook},
{"test_arm64_correct_address_in_small_jump_hook",
test_arm64_correct_address_in_small_jump_hook},
{"test_arm64_correct_address_in_long_jump_hook",
test_arm64_correct_address_in_long_jump_hook},
{NULL, NULL}};

View File

@ -49,6 +49,7 @@ static inline int64_t get_clock_realtime(void)
#else
#include <sys/time.h>
#include "sys/mman.h"
/* get host real time in nanosecond */
static inline int64_t get_clock_realtime(void)
@ -226,6 +227,62 @@ static void test_uc_ctl_arm_cpu(void)
OK(uc_close(uc));
}
static void test_uc_hook_cached_cb(uc_engine *uc, uint64_t addr, size_t size,
void *user_data)
{
// Don't add any TEST_CHECK here since we can't refer to the global variable
// here.
uint64_t *p = (uint64_t *)user_data;
(*p)++;
return;
}
static void test_uc_hook_cached_uaf(void)
{
uc_engine *uc;
// "INC ecx; DEC edx; jmp t; t: nop"
char code[] = "\x41\x4a\xeb\x00\x90";
uc_hook h;
uint64_t count = 0;
#ifndef _WIN32
void *callback = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#else
void *callback = VirtualAlloc(NULL, 4096, MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
#endif
memcpy(callback, (void *)test_uc_hook_cached_cb, 4096);
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
OK(uc_hook_add(uc, &h, UC_HOOK_CODE, (void *)callback, (void *)&count, 1,
0));
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
// Move the hook to the deleted hooks list.
OK(uc_hook_del(uc, h));
// This will clear deleted hooks and SHOULD clear cache.
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
memset(callback, 0, 4096);
// Now hooks are deleted and thus this will trigger a UAF
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
TEST_CHECK(count == 4);
OK(uc_close(uc));
#ifndef _WIN32
munmap(callback, 4096);
#else
VirtualFree(callback, 0, MEM_RELEASE);
#endif
}
TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode},
{"test_uc_ctl_page_size", test_uc_ctl_page_size},
{"test_uc_ctl_arch", test_uc_ctl_arch},
@ -234,4 +291,5 @@ TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode},
{"test_uc_ctl_tb_cache", test_uc_ctl_tb_cache},
{"test_uc_ctl_change_page_size", test_uc_ctl_change_page_size},
{"test_uc_ctl_arm_cpu", test_uc_ctl_arm_cpu},
{"test_uc_hook_cached_uaf", test_uc_hook_cached_uaf},
{NULL, NULL}};

View File

@ -187,6 +187,84 @@ static void test_map_big_memory(void)
OK(uc_close(uc));
}
static void test_mem_protect_remove_exec_callback(uc_engine *uc, uint64_t addr,
size_t size, void *data)
{
uint64_t *p = (uint64_t *)data;
(*p)++;
OK(uc_mem_protect(uc, 0x2000, 0x1000, UC_PROT_READ));
}
static void test_mem_protect_remove_exec(void)
{
uc_engine *uc;
char code[] = "\x90\xeb\x00\x90";
uc_hook hk;
uint64_t called_count = 0;
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL));
OK(uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL));
OK(uc_mem_write(uc, 0x1000, code, sizeof(code) - 1));
OK(uc_hook_add(uc, &hk, UC_HOOK_BLOCK,
test_mem_protect_remove_exec_callback, (void *)&called_count,
1, 0));
OK(uc_emu_start(uc, 0x1000, 0x1000 + sizeof(code) - 1, 0, 0));
TEST_CHECK(called_count == 2);
OK(uc_close(uc));
}
static uint64_t test_mem_protect_mmio_read_cb(struct uc_struct *uc,
uint64_t addr, unsigned size,
void *user_data)
{
TEST_CHECK(addr == 0x20); // note, it's not 0x1020
*(uint64_t *)user_data = *(uint64_t *)user_data + 1;
return 0x114514;
}
static void test_mem_protect_mmio_write_cb(struct uc_struct *uc, uint64_t addr,
unsigned size, uint64_t data,
void *user_data)
{
TEST_CHECK(false);
return;
}
static void test_mem_protect_mmio(void)
{
uc_engine *uc;
// mov eax, [0x2020]; mov [0x2020], eax
char code[] = "\xa1\x20\x20\x00\x00\x00\x00\x00\x00\xa3\x20\x20\x00\x00\x00"
"\x00\x00\x00";
uint64_t called = 0;
uint64_t r_eax;
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
OK(uc_mem_map(uc, 0x8000, 0x1000, UC_PROT_ALL));
OK(uc_mem_write(uc, 0x8000, code, sizeof(code) - 1));
OK(uc_mmio_map(uc, 0x1000, 0x3000, test_mem_protect_mmio_read_cb,
(void *)&called, test_mem_protect_mmio_write_cb,
(void *)&called));
OK(uc_mem_protect(uc, 0x2000, 0x1000, UC_PROT_READ));
uc_assert_err(UC_ERR_WRITE_PROT,
uc_emu_start(uc, 0x8000, 0x8000 + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_X86_REG_RAX, &r_eax));
TEST_CHECK(called == 1);
TEST_CHECK(r_eax == 0x114514);
OK(uc_close(uc));
}
TEST_LIST = {{"test_map_correct", test_map_correct},
{"test_map_wrapping", test_map_wrapping},
{"test_mem_protect", test_mem_protect},
@ -196,4 +274,6 @@ TEST_LIST = {{"test_map_correct", test_map_correct},
{"test_map_at_the_end", test_map_at_the_end},
{"test_map_wrap", test_map_wrap},
{"test_map_big_memory", test_map_big_memory},
{"test_mem_protect_remove_exec", test_mem_protect_remove_exec},
{"test_mem_protect_mmio", test_mem_protect_mmio},
{NULL, NULL}};

View File

@ -537,6 +537,103 @@ static void test_riscv64_mmio_map(void)
OK(uc_close(uc));
}
static bool test_riscv_correct_address_in_small_jump_hook_callback(
uc_engine *uc, int type, uint64_t address, int size, int64_t value,
void *user_data)
{
// Check registers
uint64_t r_x5 = 0x0;
uint64_t r_pc = 0x0;
OK(uc_reg_read(uc, UC_RISCV_REG_X5, &r_x5));
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
TEST_CHECK(r_x5 == 0x7F00);
TEST_CHECK(r_pc == 0x7F00);
// Check address
// printf("%lx\n", address);
TEST_CHECK(address == 0x7F00);
return false;
}
static void test_riscv_correct_address_in_small_jump_hook(void)
{
uc_engine *uc;
// li 0x7F00, x5 > lui t0, 8; addiw t0, t0, -256;
// jr x5
char code[] = "\xb7\x82\x00\x00\x9b\x82\x02\xf0\x67\x80\x02\x00";
uint64_t r_x5 = 0x0;
uint64_t r_pc = 0x0;
uc_hook hook;
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV64, code,
sizeof(code) - 1);
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_UNMAPPED,
test_riscv_correct_address_in_small_jump_hook_callback, NULL,
1, 0));
uc_assert_err(
UC_ERR_FETCH_UNMAPPED,
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_RISCV_REG_X5, &r_x5));
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
TEST_CHECK(r_x5 == 0x7F00);
TEST_CHECK(r_pc == 0x7F00);
OK(uc_close(uc));
}
static bool test_riscv_correct_address_in_long_jump_hook_callback(
uc_engine *uc, int type, uint64_t address, int size, int64_t value,
void *user_data)
{
// Check registers
uint64_t r_x5 = 0x0;
uint64_t r_pc = 0x0;
OK(uc_reg_read(uc, UC_RISCV_REG_X5, &r_x5));
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
TEST_CHECK(r_x5 == 0x7FFFFFFFFFFFFF00);
TEST_CHECK(r_pc == 0x7FFFFFFFFFFFFF00);
// Check address
// printf("%lx\n", address);
TEST_CHECK(address == 0x7FFFFFFFFFFFFF00);
return false;
}
static void test_riscv_correct_address_in_long_jump_hook(void)
{
uc_engine *uc;
// li 0x7FFFFFFFFFFFFF00, x5 > addi t0, zero, -1; slli t0, t0, 63; addi
// t0, t0, -256; jr x5
char code[] =
"\x93\x02\xf0\xff\x93\x92\xf2\x03\x93\x82\x02\xf0\x67\x80\x02\x00";
uint64_t r_x5 = 0x0;
uint64_t r_pc = 0x0;
uc_hook hook;
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV64, code,
sizeof(code) - 1);
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_UNMAPPED,
test_riscv_correct_address_in_long_jump_hook_callback, NULL,
1, 0));
uc_assert_err(
UC_ERR_FETCH_UNMAPPED,
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_RISCV_REG_X5, &r_x5));
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
TEST_CHECK(r_x5 == 0x7FFFFFFFFFFFFF00);
TEST_CHECK(r_pc == 0x7FFFFFFFFFFFFF00);
OK(uc_close(uc));
}
TEST_LIST = {
{"test_riscv32_nop", test_riscv32_nop},
{"test_riscv64_nop", test_riscv64_nop},
@ -556,4 +653,8 @@ TEST_LIST = {
{"test_riscv32_map", test_riscv32_map},
{"test_riscv64_code_patching", test_riscv64_code_patching},
{"test_riscv64_code_patching_count", test_riscv64_code_patching_count},
{"test_riscv_correct_address_in_small_jump_hook",
test_riscv_correct_address_in_small_jump_hook},
{"test_riscv_correct_address_in_long_jump_hook",
test_riscv_correct_address_in_long_jump_hook},
{NULL, NULL}};

View File

@ -0,0 +1,6 @@
#include "unicorn_test.h"
const uint64_t code_start = 0x1000;
const uint64_t code_len = 0x4000;
TEST_LIST = {{NULL, NULL}};

View File

@ -690,6 +690,35 @@ static void test_x86_clear_tb_cache(void)
OK(uc_close(uc));
}
static void test_x86_clear_count_cache(void)
{
uc_engine *uc;
// uc_emu_start will clear last TB when exiting so generating a tb at last
// by design
char code[] =
"\x83\xc1\x01\x4a\xeb\x00\x83\xc3\x01"; // ADD ecx, 1; DEC edx;
// jmp t;
// t:
// ADD ebx, 1
int r_ecx = 0x1234;
int r_edx = 0x7890;
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
OK(uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx));
OK(uc_reg_write(uc, UC_X86_REG_EDX, &r_edx));
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 2));
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx));
OK(uc_reg_read(uc, UC_X86_REG_EDX, &r_edx));
TEST_CHECK(r_ecx == 0x1236);
TEST_CHECK(r_edx == 0x788e);
OK(uc_close(uc));
}
// This is a regression bug.
static void test_x86_clear_empty_tb(void)
{
@ -797,7 +826,7 @@ static void test_x86_hook_tcg_op(void)
OK(uc_close(uc));
}
static void test_x86_cmpxchg_mem_hook(uc_engine *uc, uc_mem_type type,
static bool test_x86_cmpxchg_mem_hook(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t val,
void *data)
{
@ -806,6 +835,8 @@ static void test_x86_cmpxchg_mem_hook(uc_engine *uc, uc_mem_type type,
} else {
*((int *)data) |= 2;
}
return true;
}
static void test_x86_cmpxchg(void)
@ -981,6 +1012,100 @@ static void test_x86_nested_uc_emu_start_exits(void)
OK(uc_close(uc));
}
static bool test_x86_correct_address_in_small_jump_hook_callback(
uc_engine *uc, int type, uint64_t address, int size, int64_t value,
void *user_data)
{
// Check registers
uint64_t r_rax = 0x0;
uint64_t r_rip = 0x0;
OK(uc_reg_read(uc, UC_X86_REG_RAX, &r_rax));
OK(uc_reg_read(uc, UC_X86_REG_RIP, &r_rip));
TEST_CHECK(r_rax == 0x7F00);
TEST_CHECK(r_rip == 0x7F00);
// Check address
// printf("%lx\n", address);
TEST_CHECK(address == 0x7F00);
return false;
}
static void test_x86_correct_address_in_small_jump_hook(void)
{
uc_engine *uc;
// movabs $0x7F00, %rax
// jmp *%rax
char code[] = "\x48\xb8\x00\x7F\x00\x00\x00\x00\x00\x00\xff\xe0";
uint64_t r_rax = 0x0;
uint64_t r_rip = 0x0;
uc_hook hook;
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code) - 1);
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_UNMAPPED,
test_x86_correct_address_in_small_jump_hook_callback, NULL,
1, 0));
uc_assert_err(
UC_ERR_FETCH_UNMAPPED,
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_X86_REG_RAX, &r_rax));
OK(uc_reg_read(uc, UC_X86_REG_RIP, &r_rip));
TEST_CHECK(r_rax == 0x7F00);
TEST_CHECK(r_rip == 0x7F00);
OK(uc_close(uc));
}
static bool test_x86_correct_address_in_long_jump_hook_callback(
uc_engine *uc, int type, uint64_t address, int size, int64_t value,
void *user_data)
{
// Check registers
uint64_t r_rax = 0x0;
uint64_t r_rip = 0x0;
OK(uc_reg_read(uc, UC_X86_REG_RAX, &r_rax));
OK(uc_reg_read(uc, UC_X86_REG_RIP, &r_rip));
TEST_CHECK(r_rax == 0x7FFFFFFFFFFFFF00);
TEST_CHECK(r_rip == 0x7FFFFFFFFFFFFF00);
// Check address
// printf("%lx\n", address);
TEST_CHECK(address == 0x7FFFFFFFFFFFFF00);
return false;
}
static void test_x86_correct_address_in_long_jump_hook(void)
{
uc_engine *uc;
// movabs $0x7FFFFFFFFFFFFF00, %rax
// jmp *%rax
char code[] = "\x48\xb8\x00\xff\xff\xff\xff\xff\xff\x7f\xff\xe0";
uint64_t r_rax = 0x0;
uint64_t r_rip = 0x0;
uc_hook hook;
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code) - 1);
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_UNMAPPED,
test_x86_correct_address_in_long_jump_hook_callback, NULL, 1,
0));
uc_assert_err(
UC_ERR_FETCH_UNMAPPED,
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_X86_REG_RAX, &r_rax));
OK(uc_reg_read(uc, UC_X86_REG_RIP, &r_rip));
TEST_CHECK(r_rax == 0x7FFFFFFFFFFFFF00);
TEST_CHECK(r_rip == 0x7FFFFFFFFFFFFF00);
OK(uc_close(uc));
}
TEST_LIST = {
{"test_x86_in", test_x86_in},
{"test_x86_out", test_x86_out},
@ -1013,4 +1138,9 @@ TEST_LIST = {
{"test_x86_64_nested_emu_start_error", test_x86_64_nested_emu_start_error},
{"test_x86_eflags_reserved_bit", test_x86_eflags_reserved_bit},
{"test_x86_nested_uc_emu_start_exits", test_x86_nested_uc_emu_start_exits},
{"test_x86_clear_count_cache", test_x86_clear_count_cache},
{"test_x86_correct_address_in_small_jump_hook",
test_x86_correct_address_in_small_jump_hook},
{"test_x86_correct_address_in_long_jump_hook",
test_x86_correct_address_in_long_jump_hook},
{NULL, NULL}};

114
uc.c
View File

@ -24,6 +24,7 @@
#include "qemu/target/ppc/unicorn.h"
#include "qemu/target/riscv/unicorn.h"
#include "qemu/target/s390x/unicorn.h"
#include "qemu/target/tricore/unicorn.h"
#include "qemu/include/qemu/queue.h"
#include "qemu-common.h"
@ -48,6 +49,14 @@ static void *hook_append(struct list *l, struct hook *h)
return item;
}
static void hook_invalidate_region(void *key, void *data, void *opaq)
{
uc_engine *uc = (uc_engine *)opaq;
HookedRegion *region = (HookedRegion *)key;
uc->uc_invalidate_tb(uc, region->start, region->length);
}
static void hook_delete(void *data)
{
struct hook *h = (struct hook *)data;
@ -55,6 +64,7 @@ static void hook_delete(void *data)
h->refs--;
if (h->refs == 0) {
g_hash_table_destroy(h->hooked_regions);
free(h);
}
}
@ -167,6 +177,10 @@ bool uc_arch_supported(uc_arch arch)
#ifdef UNICORN_HAS_S390X
case UC_ARCH_S390X:
return true;
#endif
#ifdef UNICORN_HAS_TRICORE
case UC_ARCH_TRICORE:
return true;
#endif
/* Invalid or disabled arch */
default:
@ -384,6 +398,15 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
}
uc->init_arch = s390_uc_init;
break;
#endif
#ifdef UNICORN_HAS_TRICORE
case UC_ARCH_TRICORE:
if ((mode & ~UC_MODE_TRICORE_MASK)) {
free(uc);
return UC_ERR_MODE;
}
uc->init_arch = tricore_uc_init;
break;
#endif
}
@ -798,6 +821,11 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
case UC_ARCH_S390X:
uc_reg_write(uc, UC_S390X_REG_PC, &begin);
break;
#endif
#ifdef UNICORN_HAS_TRICORE
case UC_ARCH_TRICORE:
uc_reg_write(uc, UC_TRICORE_REG_PC, &begin);
break;
#endif
}
@ -808,6 +836,9 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
if (count <= 0 && uc->count_hook != 0) {
uc_hook_del(uc, uc->count_hook);
uc->count_hook = 0;
// In this case, we have to drop all translated blocks.
uc->tb_flush(uc);
}
// set up count hook to count instructions.
if (count > 0 && uc->count_hook == 0) {
@ -844,10 +875,11 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
// or we may lost uc_emu_stop
if (uc->nested_level == 0) {
uc->emulation_done = true;
}
// remove hooks to delete
clear_deleted_hooks(uc);
// remove hooks to delete
// make sure we delete all hooks at the first level.
clear_deleted_hooks(uc);
}
if (timeout) {
// wait for the timer to finish
@ -1091,15 +1123,13 @@ static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
/*
This function is similar to split_region, but for MMIO memory.
This function would delete the region unconditionally.
Note this function may be called recursively.
*/
static bool split_mmio_region(struct uc_struct *uc, MemoryRegion *mr,
uint64_t address, size_t size)
uint64_t address, size_t size, bool do_delete)
{
uint64_t begin, end, chunk_end;
size_t l_size, r_size;
size_t l_size, r_size, m_size;
mmio_cbs backup;
chunk_end = address + size;
@ -1142,6 +1172,7 @@ static bool split_mmio_region(struct uc_struct *uc, MemoryRegion *mr,
// compute sub region sizes
l_size = (size_t)(address - begin);
r_size = (size_t)(end - chunk_end);
m_size = (size_t)(chunk_end - address);
if (l_size > 0) {
if (uc_mmio_map(uc, begin, l_size, backup.read, backup.user_data_read,
@ -1150,6 +1181,13 @@ static bool split_mmio_region(struct uc_struct *uc, MemoryRegion *mr,
}
}
if (m_size > 0 && !do_delete) {
if (uc_mmio_map(uc, address, m_size, backup.read, backup.user_data_read,
backup.write, backup.user_data_write) != UC_ERR_OK) {
return false;
}
}
if (r_size > 0) {
if (uc_mmio_map(uc, chunk_end, r_size, backup.read,
backup.user_data_read, backup.write,
@ -1335,6 +1373,7 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
{
MemoryRegion *mr;
uint64_t addr = address;
uint64_t pc;
size_t count, len;
bool remove_exec = false;
@ -1376,18 +1415,28 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
while (count < size) {
mr = memory_mapping(uc, addr);
len = (size_t)MIN(size - count, mr->end - addr);
if (!split_region(uc, mr, addr, len, false)) {
return UC_ERR_NOMEM;
}
if (mr->ram) {
if (!split_region(uc, mr, addr, len, false)) {
return UC_ERR_NOMEM;
}
mr = memory_mapping(uc, addr);
// will this remove EXEC permission?
if (((mr->perms & UC_PROT_EXEC) != 0) &&
((perms & UC_PROT_EXEC) == 0)) {
remove_exec = true;
mr = memory_mapping(uc, addr);
// will this remove EXEC permission?
if (((mr->perms & UC_PROT_EXEC) != 0) &&
((perms & UC_PROT_EXEC) == 0)) {
remove_exec = true;
}
mr->perms = perms;
uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0);
} else {
if (!split_mmio_region(uc, mr, addr, len, false)) {
return UC_ERR_NOMEM;
}
mr = memory_mapping(uc, addr);
mr->perms = perms;
}
mr->perms = perms;
uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0);
count += len;
addr += len;
@ -1396,8 +1445,11 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
// if EXEC permission is removed, then quit TB and continue at the same
// place
if (remove_exec) {
uc->quit_request = true;
uc_emu_stop(uc);
pc = uc->get_pc(uc);
if (pc < address + size && pc >= address) {
uc->quit_request = true;
uc_emu_stop(uc);
}
}
return UC_ERR_OK;
@ -1444,7 +1496,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
mr = memory_mapping(uc, addr);
len = (size_t)MIN(size - count, mr->end - addr);
if (!mr->ram) {
if (!split_mmio_region(uc, mr, addr, len)) {
if (!split_mmio_region(uc, mr, addr, len, true)) {
return UC_ERR_NOMEM;
}
} else {
@ -1518,6 +1570,8 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
hook->user_data = user_data;
hook->refs = 0;
hook->to_delete = false;
hook->hooked_regions = g_hash_table_new_full(
hooked_regions_hash, hooked_regions_equal, g_free, NULL);
*hh = (uc_hook)hook;
// UC_HOOK_INSN has an extra argument for instruction ID
@ -1627,6 +1681,9 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
// and store the type mask in the hook pointer.
for (i = 0; i < UC_HOOK_MAX; i++) {
if (list_exists(&uc->hook[i], (void *)hook)) {
g_hash_table_foreach(hook->hooked_regions, hook_invalidate_region,
uc);
g_hash_table_remove_all(hook->hooked_regions);
hook->to_delete = true;
uc->hooks_count[i]--;
hook_append(&uc->hooks_to_del, hook);
@ -1956,6 +2013,12 @@ static void find_context_reg_rw_function(uc_arch arch, uc_mode mode,
rw->context_reg_read = s390_context_reg_read;
rw->context_reg_write = s390_context_reg_write;
break;
#endif
#ifdef UNICORN_HAS_TRICORE
case UC_ARCH_TRICORE:
rw->context_reg_read = tricore_context_reg_read;
rw->context_reg_write = tricore_context_reg_write;
break;
#endif
}
@ -2300,6 +2363,17 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
break;
}
case UC_CTL_TB_FLUSH:
UC_INIT(uc);
if (rw == UC_CTL_IO_WRITE) {
uc->tb_flush(uc);
} else {
err = UC_ERR_ARG;
}
break;
default:
err = UC_ERR_ARG;
break;