add virtuall tlb
this virtuall tlb allows to use mmu indipendent of the architectur
This commit is contained in:
parent
759d694e24
commit
e25419bb2d
@ -446,6 +446,8 @@ set(UNICORN_ARCH_COMMON
|
||||
qemu/accel/tcg/tcg-runtime-gvec.c
|
||||
qemu/accel/tcg/translate-all.c
|
||||
qemu/accel/tcg/translator.c
|
||||
|
||||
qemu/softmmu/unicorn_vtlb.c
|
||||
)
|
||||
|
||||
if(UNICORN_HAS_X86)
|
||||
|
@ -146,6 +146,8 @@ 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;
|
||||
|
||||
typedef uc_err (*uc_set_tlb_t)(struct uc_struct *uc, int mode);
|
||||
|
||||
struct hook {
|
||||
int type; // UC_HOOK_*
|
||||
int insn; // instruction for HOOK_INSN
|
||||
@ -202,6 +204,7 @@ typedef enum uc_hook_idx {
|
||||
UC_HOOK_INSN_INVALID_IDX,
|
||||
UC_HOOK_EDGE_GENERATED_IDX,
|
||||
UC_HOOK_TCG_OPCODE_IDX,
|
||||
UC_HOOK_TLB_FILL_IDX,
|
||||
|
||||
UC_HOOK_MAX,
|
||||
} uc_hook_idx;
|
||||
@ -337,6 +340,8 @@ struct uc_struct {
|
||||
GHashTable *flat_views;
|
||||
bool memory_region_update_pending;
|
||||
|
||||
uc_set_tlb_t set_tlb;
|
||||
|
||||
// linked lists containing hooks per type
|
||||
struct list hook[UC_HOOK_MAX];
|
||||
struct list hooks_to_del;
|
||||
|
@ -244,6 +244,22 @@ typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size,
|
||||
typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size,
|
||||
uint32_t value, void *user_data);
|
||||
|
||||
typedef struct uc_tlb_entry uc_tlb_entry;
|
||||
typedef enum uc_mem_type uc_mem_type;
|
||||
|
||||
/*
|
||||
Callback function for tlb lookups
|
||||
|
||||
@vaddr: virtuall address for lookup
|
||||
@rw: the access mode
|
||||
@result: result entry, contains physical address (paddr) and permitted access type (perms) for the entry
|
||||
|
||||
@return: return true if the entry was found. If a callback is present but
|
||||
no one returns true a pagefault is generated.
|
||||
*/
|
||||
typedef bool (*uc_cb_tlbevent_t)(uc_engine *uc, uint64_t vaddr, uc_mem_type type,
|
||||
uc_tlb_entry *result, void *user_data);
|
||||
|
||||
// Represent a TranslationBlock.
|
||||
typedef struct uc_tb {
|
||||
uint64_t pc;
|
||||
@ -295,7 +311,7 @@ typedef void (*uc_cb_mmio_write_t)(uc_engine *uc, uint64_t offset,
|
||||
void *user_data);
|
||||
|
||||
// All type of memory accesses for UC_HOOK_MEM_*
|
||||
typedef enum uc_mem_type {
|
||||
enum uc_mem_type {
|
||||
UC_MEM_READ = 16, // Memory is read from
|
||||
UC_MEM_WRITE, // Memory is written to
|
||||
UC_MEM_FETCH, // Memory is fetched
|
||||
@ -306,7 +322,7 @@ typedef enum uc_mem_type {
|
||||
UC_MEM_READ_PROT, // Read from read protected, but mapped, memory
|
||||
UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory
|
||||
UC_MEM_READ_AFTER, // Memory is read from (successful access)
|
||||
} uc_mem_type;
|
||||
};
|
||||
|
||||
// These are all op codes we support to hook for UC_HOOK_TCG_OP_CODE.
|
||||
// Be cautious since it may bring much more overhead than UC_HOOK_CODE without
|
||||
@ -369,6 +385,10 @@ typedef enum uc_hook_type {
|
||||
// Hook on specific tcg op code. The usage of this hook is similar to
|
||||
// UC_HOOK_INSN.
|
||||
UC_HOOK_TCG_OPCODE = 1 << 16,
|
||||
// Hook on tlb fill requests.
|
||||
// Register tlb fill request hook on the virtuall addresses.
|
||||
// The callback will be triggert if the tlb cache don't contain an address.
|
||||
UC_HOOK_TLB_FILL = 1 << 17,
|
||||
} uc_hook_type;
|
||||
|
||||
// Hook type for all events of unmapped memory access
|
||||
@ -490,6 +510,16 @@ typedef enum uc_query_type {
|
||||
#define UC_CTL_WRITE(type, nr) UC_CTL(type, nr, UC_CTL_IO_WRITE)
|
||||
#define UC_CTL_READ_WRITE(type, nr) UC_CTL(type, nr, UC_CTL_IO_READ_WRITE)
|
||||
|
||||
// unicorn tlb type selection
|
||||
typedef enum uc_tlb_type {
|
||||
// The tlb implementation of the CPU, best to use for full system emulation.
|
||||
UC_TLB_CPU = 0,
|
||||
// The default unicorn virtuall TLB implementation.
|
||||
// This tlb defaults to virtuall address == physical address
|
||||
// Also a hook is availible to override the tlb entries (see uc_cb_tlbevent_t).
|
||||
UC_TLB_VIRTUAL
|
||||
} uc_tlb_type;
|
||||
|
||||
// All type of controls for uc_ctl API.
|
||||
// The controls are organized in a tree level.
|
||||
// If a control don't have `Set` or `Get` for @args, it means it's r/o or w/o.
|
||||
@ -536,7 +566,11 @@ typedef enum uc_control_type {
|
||||
UC_CTL_TB_REMOVE_CACHE,
|
||||
// Invalidate all translation blocks.
|
||||
// No arguments.
|
||||
UC_CTL_TB_FLUSH
|
||||
UC_CTL_TB_FLUSH,
|
||||
// Change the tlb implementation
|
||||
// see uc_tlb_type for current implemented types
|
||||
// Write: @args = (int)
|
||||
UC_CTL_TLB_TYPE
|
||||
|
||||
} uc_control_type;
|
||||
|
||||
@ -612,6 +646,7 @@ See sample_ctl.c for a detailed example.
|
||||
#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))
|
||||
#define uc_ctl_tlb_mode(uc, mode) uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TLB_TYPE, 1), (mode))
|
||||
// Opaque storage for CPU context, used with uc_context_*()
|
||||
struct uc_context;
|
||||
typedef struct uc_context uc_context;
|
||||
@ -898,6 +933,11 @@ typedef enum uc_prot {
|
||||
UC_PROT_ALL = 7,
|
||||
} uc_prot;
|
||||
|
||||
struct uc_tlb_entry {
|
||||
uint64_t paddr;
|
||||
uc_prot perms;
|
||||
};
|
||||
|
||||
/*
|
||||
Map memory in for emulation.
|
||||
This API adds a memory region that can be used by emulation.
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _aarch64
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_aarch64
|
||||
#define uc_add_inline_hook uc_add_inline_hook_aarch64
|
||||
#define uc_del_inline_hook uc_del_inline_hook_aarch64
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_aarch64
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _arm
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_arm
|
||||
#define uc_add_inline_hook uc_add_inline_hook_arm
|
||||
#define uc_del_inline_hook uc_del_inline_hook_arm
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_arm
|
||||
|
@ -117,6 +117,9 @@ typedef struct CPUClass {
|
||||
bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
bool (*tlb_fill_cpu)(CPUState *cpu, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
|
||||
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
|
||||
MemTxAttrs *attrs);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define QEMU_CPUS_H
|
||||
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/core/cpu.h"
|
||||
|
||||
/* cpus.c */
|
||||
bool qemu_in_vcpu_thread(void);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _m68k
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_m68k
|
||||
#define uc_add_inline_hook uc_add_inline_hook_m68k
|
||||
#define uc_del_inline_hook uc_del_inline_hook_m68k
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_m68k
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _mips
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_mips
|
||||
#define uc_add_inline_hook uc_add_inline_hook_mips
|
||||
#define uc_del_inline_hook uc_del_inline_hook_mips
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _mips64
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_mips64
|
||||
#define uc_add_inline_hook uc_add_inline_hook_mips64
|
||||
#define uc_del_inline_hook uc_del_inline_hook_mips64
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips64
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _mips64el
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_mips64el
|
||||
#define uc_add_inline_hook uc_add_inline_hook_mips64el
|
||||
#define uc_del_inline_hook uc_del_inline_hook_mips64el
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips64el
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _mipsel
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_mipsel
|
||||
#define uc_add_inline_hook uc_add_inline_hook_mipsel
|
||||
#define uc_del_inline_hook uc_del_inline_hook_mipsel
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_mipsel
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _ppc
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_ppc
|
||||
#define uc_add_inline_hook uc_add_inline_hook_ppc
|
||||
#define uc_del_inline_hook uc_del_inline_hook_ppc
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_ppc
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _ppc64
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_ppc64
|
||||
#define uc_add_inline_hook uc_add_inline_hook_ppc64
|
||||
#define uc_del_inline_hook uc_del_inline_hook_ppc64
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_ppc64
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _riscv32
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_riscv32
|
||||
#define uc_add_inline_hook uc_add_inline_hook_riscv32
|
||||
#define uc_del_inline_hook uc_del_inline_hook_riscv32
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_riscv32
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _riscv64
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_riscv64
|
||||
#define uc_add_inline_hook uc_add_inline_hook_riscv64
|
||||
#define uc_del_inline_hook uc_del_inline_hook_riscv64
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_riscv64
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _s390x
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_s390x
|
||||
#define uc_add_inline_hook uc_add_inline_hook_s390x
|
||||
#define uc_del_inline_hook uc_del_inline_hook_s390x
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_s390x
|
||||
|
106
qemu/softmmu/unicorn_vtlb.c
Normal file
106
qemu/softmmu/unicorn_vtlb.c
Normal file
@ -0,0 +1,106 @@
|
||||
#include <stdint.h>
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "uc_priv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static void raise_mmu_exception(CPUState *cs, target_ulong address,
|
||||
int rw, uintptr_t retaddr)
|
||||
{
|
||||
cs->uc->invalid_error = UC_ERR_EXCEPTION;
|
||||
cs->uc->invalid_addr = address;
|
||||
cpu_exit(cs->uc->cpu);
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
static uc_mem_type rw_to_mem_type(int rw)
|
||||
{
|
||||
switch (rw) {
|
||||
case MMU_DATA_LOAD:
|
||||
return UC_MEM_READ;
|
||||
case MMU_DATA_STORE:
|
||||
return UC_MEM_WRITE;
|
||||
case MMU_INST_FETCH:
|
||||
return UC_MEM_FETCH;
|
||||
default:
|
||||
return UC_MEM_READ;
|
||||
}
|
||||
}
|
||||
|
||||
static int perms_to_prot(int perms)
|
||||
{
|
||||
int ret = 0;
|
||||
if (perms & UC_PROT_READ) {
|
||||
ret |= PAGE_READ;
|
||||
}
|
||||
if (perms & UC_PROT_WRITE) {
|
||||
ret |= PAGE_WRITE;
|
||||
}
|
||||
if (perms & UC_PROT_EXEC) {
|
||||
ret |= PAGE_EXEC;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool unicorn_fill_tlb(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType rw, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
bool handled = false;
|
||||
bool ret = false;
|
||||
struct uc_struct *uc = cs->uc;
|
||||
uc_tlb_entry e;
|
||||
struct hook *hook;
|
||||
HOOK_FOREACH_VAR_DECLARE;
|
||||
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_TLB_FILL) {
|
||||
if (hook->to_delete) {
|
||||
continue;
|
||||
}
|
||||
if (!HOOK_BOUND_CHECK(hook, address)) {
|
||||
continue;
|
||||
}
|
||||
handled = true;
|
||||
if ((ret = ((uc_cb_tlbevent_t)hook->callback)(uc, address & TARGET_PAGE_MASK, rw_to_mem_type(rw), &e, hook->user_data))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled && !ret) {
|
||||
goto tlb_miss;
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
e.paddr = address & TARGET_PAGE_MASK;
|
||||
e.perms = UC_PROT_READ|UC_PROT_WRITE|UC_PROT_EXEC;
|
||||
}
|
||||
|
||||
switch (rw) {
|
||||
case MMU_DATA_LOAD:
|
||||
ret = e.perms & UC_PROT_READ;
|
||||
break;
|
||||
case MMU_DATA_STORE:
|
||||
ret = e.perms & UC_PROT_WRITE;
|
||||
break;
|
||||
case MMU_INST_FETCH:
|
||||
ret = e.perms & UC_PROT_EXEC;
|
||||
break;
|
||||
default:
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
tlb_set_page(cs, address & TARGET_PAGE_MASK, e.paddr & TARGET_PAGE_MASK, perms_to_prot(e.perms), mmu_idx, TARGET_PAGE_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
tlb_miss:
|
||||
if (probe) {
|
||||
return false;
|
||||
}
|
||||
raise_mmu_exception(cs, address, rw, retaddr);
|
||||
return false;
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _sparc
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_sparc
|
||||
#define uc_add_inline_hook uc_add_inline_hook_sparc
|
||||
#define uc_del_inline_hook uc_del_inline_hook_sparc
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_sparc
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _sparc64
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_sparc64
|
||||
#define uc_add_inline_hook uc_add_inline_hook_sparc64
|
||||
#define uc_del_inline_hook uc_del_inline_hook_sparc64
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_sparc64
|
||||
|
@ -2081,6 +2081,7 @@ void arm_cpu_class_init(struct uc_struct *uc, CPUClass *oc)
|
||||
cc->asidx_from_attrs = arm_asidx_from_attrs;
|
||||
cc->tcg_initialize = arm_translate_init;
|
||||
cc->tlb_fill = arm_cpu_tlb_fill;
|
||||
cc->tlb_fill_cpu = arm_cpu_tlb_fill;
|
||||
cc->debug_excp_handler = arm_debug_excp_handler;
|
||||
cc->do_unaligned_access = arm_cpu_do_unaligned_access;
|
||||
}
|
||||
|
@ -5067,6 +5067,7 @@ static void x86_cpu_common_class_init(struct uc_struct *uc, CPUClass *oc, void *
|
||||
cc->cpu_exec_exit = x86_cpu_exec_exit;
|
||||
cc->tcg_initialize = tcg_x86_init;
|
||||
cc->tlb_fill = x86_cpu_tlb_fill;
|
||||
cc->tlb_fill_cpu = x86_cpu_tlb_fill;
|
||||
}
|
||||
|
||||
X86CPU *cpu_x86_init(struct uc_struct *uc)
|
||||
|
@ -232,6 +232,7 @@ static void m68k_cpu_class_init(CPUClass *c)
|
||||
cc->cpu_exec_interrupt = m68k_cpu_exec_interrupt;
|
||||
cc->set_pc = m68k_cpu_set_pc;
|
||||
cc->tlb_fill = m68k_cpu_tlb_fill;
|
||||
cc->tlb_fill_cpu = m68k_cpu_tlb_fill;
|
||||
cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
|
||||
cc->tcg_initialize = m68k_tcg_init;
|
||||
}
|
||||
|
@ -148,6 +148,7 @@ static void mips_cpu_class_init(CPUClass *c)
|
||||
cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
|
||||
cc->tcg_initialize = mips_tcg_init;
|
||||
cc->tlb_fill = mips_cpu_tlb_fill;
|
||||
cc->tlb_fill_cpu = mips_cpu_tlb_fill;
|
||||
}
|
||||
|
||||
MIPSCPU *cpu_mips_init(struct uc_struct *uc)
|
||||
|
@ -10254,6 +10254,7 @@ static void ppc_cpu_class_init(struct uc_struct *uc, CPUClass *oc)
|
||||
cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
|
||||
cc->tcg_initialize = ppc_translate_init;
|
||||
cc->tlb_fill = ppc_cpu_tlb_fill;
|
||||
cc->tlb_fill_cpu = ppc_cpu_tlb_fill;
|
||||
cc->cpu_exec_enter = ppc_cpu_exec_enter;
|
||||
cc->cpu_exec_exit = ppc_cpu_exec_exit;
|
||||
}
|
||||
|
@ -308,6 +308,7 @@ static void riscv_cpu_class_init(struct uc_struct *uc, CPUClass *c, void *data)
|
||||
cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
|
||||
cc->tcg_initialize = riscv_translate_init;
|
||||
cc->tlb_fill = riscv_cpu_tlb_fill;
|
||||
cc->tlb_fill_cpu = riscv_cpu_tlb_fill;
|
||||
}
|
||||
|
||||
typedef struct CPUModelInfo {
|
||||
|
@ -234,6 +234,7 @@ static void s390_cpu_class_init(struct uc_struct *uc, CPUClass *oc)
|
||||
cc->do_unaligned_access = s390x_cpu_do_unaligned_access;
|
||||
cc->tcg_initialize = s390x_translate_init;
|
||||
cc->tlb_fill = s390_cpu_tlb_fill;
|
||||
cc->tlb_fill_cpu = s390_cpu_tlb_fill;
|
||||
|
||||
// s390_cpu_model_class_register_props(oc);
|
||||
}
|
||||
|
@ -505,6 +505,7 @@ static void sparc_cpu_class_init(struct uc_struct *uc, CPUClass *oc)
|
||||
cc->set_pc = sparc_cpu_set_pc;
|
||||
cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
|
||||
cc->tlb_fill = sparc_cpu_tlb_fill;
|
||||
cc->tlb_fill_cpu = sparc_cpu_tlb_fill;
|
||||
cc->do_unaligned_access = sparc_cpu_do_unaligned_access;
|
||||
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
|
||||
cc->tcg_initialize = sparc_tcg_init;
|
||||
|
@ -138,6 +138,7 @@ static void tricore_cpu_class_init(CPUClass *c)
|
||||
cc->get_phys_page_debug = tricore_cpu_get_phys_page_debug;
|
||||
|
||||
cc->tlb_fill = tricore_cpu_tlb_fill;
|
||||
cc->tlb_fill_cpu = tricore_cpu_tlb_fill;
|
||||
cc->tcg_initialize = tricore_tcg_init;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _tricore
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_tricore
|
||||
#define uc_add_inline_hook uc_add_inline_hook_tricore
|
||||
#define uc_del_inline_hook uc_del_inline_hook_tricore
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_tricore
|
||||
|
@ -11,6 +11,9 @@
|
||||
|
||||
void vm_start(struct uc_struct*);
|
||||
void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size);
|
||||
bool unicorn_fill_tlb(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType rw, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
// return true on success, false on failure
|
||||
static inline bool cpu_physical_mem_read(AddressSpace *as, hwaddr addr,
|
||||
@ -91,6 +94,19 @@ static inline void target_page_init(struct uc_struct* uc)
|
||||
uc->target_page_align = TARGET_PAGE_SIZE - 1;
|
||||
}
|
||||
|
||||
static uc_err uc_set_tlb(struct uc_struct *uc, int mode) {
|
||||
switch (mode) {
|
||||
case UC_TLB_VIRTUAL:
|
||||
uc->cpu->cc->tlb_fill = unicorn_fill_tlb;
|
||||
return UC_ERR_OK;
|
||||
case UC_TLB_CPU:
|
||||
uc->cpu->cc->tlb_fill = uc->cpu->cc->tlb_fill_cpu;
|
||||
return UC_ERR_OK;
|
||||
default:
|
||||
return UC_ERR_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
void softfloat_init(void);
|
||||
static inline void uc_common_init(struct uc_struct* uc)
|
||||
{
|
||||
@ -107,6 +123,7 @@ static inline void uc_common_init(struct uc_struct* uc)
|
||||
uc->softfloat_initialize = softfloat_init;
|
||||
uc->tcg_flush_tlb = tcg_flush_softmmu_tlb;
|
||||
uc->memory_map_io = memory_map_io;
|
||||
uc->set_tlb = uc_set_tlb;
|
||||
|
||||
if (!uc->release)
|
||||
uc->release = release_common;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _x86_64
|
||||
#endif
|
||||
#define unicorn_fill_tlb unicorn_fill_tlb_x86_64
|
||||
#define uc_add_inline_hook uc_add_inline_hook_x86_64
|
||||
#define uc_del_inline_hook uc_del_inline_hook_x86_64
|
||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_x86_64
|
||||
|
@ -1,6 +1,25 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* mov rax, 57
|
||||
* syscall
|
||||
* test rax, rax
|
||||
* jz child
|
||||
* xor rax, rax
|
||||
* mov rax, 60
|
||||
* mov [0x4000], rax
|
||||
* syscall
|
||||
*
|
||||
* child:
|
||||
* xor rcx, rcx
|
||||
* mov rcx, 42
|
||||
* mov [0x4000], rcx
|
||||
* mov rax, 60
|
||||
* syscall
|
||||
*/
|
||||
char code[] = "\xB8\x39\x00\x00\x00\x0F\x05\x48\x85\xC0\x74\x0F\xB8\x3C\x00\x00\x00\x48\x89\x04\x25\x00\x40\x00\x00\x0F\x05\xB9\x2A\x00\x00\x00\x48\x89\x0C\x25\x00\x40\x00\x00\xB8\x3C\x00\x00\x00\x0F\x05";
|
||||
|
||||
static void mmu_write_callback(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data)
|
||||
{
|
||||
printf("write at 0x%lx: 0x%lx\n", address, value);
|
||||
@ -83,7 +102,7 @@ static void x86_mmu_pt_set(uc_engine *uc, uint64_t vaddr, uint64_t paddr, uint64
|
||||
uc_mem_write(uc, tlb_base + 0x3000 + pto, &pte, sizeof(pte));
|
||||
}
|
||||
|
||||
static void x86_mmu_callback(uc_engine *uc, void *userdata)
|
||||
static void x86_mmu_syscall_callback(uc_engine *uc, void *userdata)
|
||||
{
|
||||
uc_err err;
|
||||
bool *parrent_done = userdata;
|
||||
@ -99,6 +118,7 @@ static void x86_mmu_callback(uc_engine *uc, void *userdata)
|
||||
break;
|
||||
case 60:
|
||||
/* exit */
|
||||
*parrent_done = true;
|
||||
uc_emu_stop(uc);
|
||||
return;
|
||||
default:
|
||||
@ -107,7 +127,6 @@ static void x86_mmu_callback(uc_engine *uc, void *userdata)
|
||||
}
|
||||
|
||||
if (!(*parrent_done)) {
|
||||
*parrent_done = true;
|
||||
rax = 27;
|
||||
err = uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
||||
if (err) {
|
||||
@ -118,7 +137,7 @@ static void x86_mmu_callback(uc_engine *uc, void *userdata)
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
void cpu_tlb(void)
|
||||
{
|
||||
uint64_t tlb_base = 0x3000;
|
||||
uint64_t rax, rip;
|
||||
@ -129,24 +148,6 @@ int main(void)
|
||||
uc_err err;
|
||||
uc_hook h1, h2;
|
||||
|
||||
/*
|
||||
* mov rax, 57
|
||||
* syscall
|
||||
* test rax, rax
|
||||
* jz child
|
||||
* xor rax, rax
|
||||
* mov rax, 60
|
||||
* mov [0x4000], rax
|
||||
* syscall
|
||||
*
|
||||
* child:
|
||||
* xor rcx, rcx
|
||||
* mov rcx, 42
|
||||
* mov [0x4000], rcx
|
||||
* mov rax, 60
|
||||
* syscall
|
||||
*/
|
||||
char code[] = "\xB8\x39\x00\x00\x00\x0F\x05\x48\x85\xC0\x74\x0F\xB8\x3C\x00\x00\x00\x48\x89\x04\x25\x00\x40\x00\x00\x0F\x05\xB9\x2A\x00\x00\x00\x48\x89\x0C\x25\x00\x40\x00\x00\xB8\x3C\x00\x00\x00\x0F\x05";
|
||||
printf("Emulate x86 amd64 code with mmu enabled and switch mappings\n");
|
||||
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
|
||||
@ -154,13 +155,14 @@ int main(void)
|
||||
printf("Failed on uc_open() with error returned: %u\n", err);
|
||||
exit(1);
|
||||
}
|
||||
uc_ctl_tlb_mode(uc, UC_TLB_CPU);
|
||||
err = uc_context_alloc(uc, &context);
|
||||
if (err) {
|
||||
printf("Failed on uc_context_alloc() with error returned: %u\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
err = uc_hook_add(uc, &h1, UC_HOOK_INSN, &x86_mmu_callback, &parrent_done, 1, 0, UC_X86_INS_SYSCALL);
|
||||
err = uc_hook_add(uc, &h1, UC_HOOK_INSN, &x86_mmu_syscall_callback, &parrent_done, 1, 0, UC_X86_INS_SYSCALL);
|
||||
if (err) {
|
||||
printf("Failed on uc_hook_add() with error returned: %u\n", err);
|
||||
exit(1);
|
||||
@ -272,4 +274,157 @@ int main(void)
|
||||
}
|
||||
printf("parrent result == %lu\n", parrent);
|
||||
printf("child result == %lu\n", child);
|
||||
uc_close(uc);
|
||||
}
|
||||
|
||||
static bool virtual_tlb_callback(uc_engine *uc, uint64_t addr, uc_mem_type type, uc_tlb_entry *result, void *user_data)
|
||||
{
|
||||
bool *parrent_done = user_data;
|
||||
printf("tlb lookup for address: 0x%lX\n", addr);
|
||||
switch (addr & ~(0xfff)) {
|
||||
case 0x2000:
|
||||
result->paddr = 0x0;
|
||||
result->perms = UC_PROT_EXEC;
|
||||
return true;
|
||||
case 0x4000:
|
||||
if (*parrent_done) {
|
||||
result->paddr = 0x2000;
|
||||
} else {
|
||||
result->paddr = 0x1000;
|
||||
}
|
||||
result->perms = UC_PROT_READ | UC_PROT_WRITE;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void virtual_tlb(void)
|
||||
{
|
||||
uint64_t rax, rip;
|
||||
bool parrent_done = false;
|
||||
uint64_t parrent, child;
|
||||
uc_context *context;
|
||||
uc_engine *uc;
|
||||
uc_err err;
|
||||
uc_hook h1, h2, h3;
|
||||
|
||||
printf("Emulate x86 amd64 code with virtual mmu\n");
|
||||
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u\n", err);
|
||||
exit(1);
|
||||
}
|
||||
uc_ctl_tlb_mode(uc, UC_TLB_VIRTUAL);
|
||||
err = uc_context_alloc(uc, &context);
|
||||
if (err) {
|
||||
printf("Failed on uc_context_alloc() with error returned: %u\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
err = uc_hook_add(uc, &h1, UC_HOOK_INSN, &x86_mmu_syscall_callback, &parrent_done, 1, 0, UC_X86_INS_SYSCALL);
|
||||
if (err) {
|
||||
printf("Failed on uc_hook_add() with error returned: %u\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Memory hooks are called after the mmu translation, so hook the physicall addresses
|
||||
err = uc_hook_add(uc, &h2, UC_HOOK_MEM_WRITE, &mmu_write_callback, NULL, 0x1000, 0x3000);
|
||||
if (err) {
|
||||
printf("Faled on uc_hook_add() with error returned: %u\n", err);
|
||||
}
|
||||
|
||||
printf("map code\n");
|
||||
err = uc_mem_map(uc, 0x0, 0x1000, UC_PROT_ALL); //Code
|
||||
if (err) {
|
||||
printf("Failed on uc_mem_map() with error return: %u\n", err);
|
||||
exit(1);
|
||||
}
|
||||
err = uc_mem_write(uc, 0x0, code, sizeof(code) - 1);
|
||||
if (err) {
|
||||
printf("Failed on uc_mem_wirte() with error return: %u\n", err);
|
||||
exit(1);
|
||||
}
|
||||
printf("map parrent memory\n");
|
||||
err = uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL); //Parrent
|
||||
if (err) {
|
||||
printf("Failed on uc_mem_map() with error return: %u\n", err);
|
||||
exit(1);
|
||||
}
|
||||
printf("map child memory\n");
|
||||
err = uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL); //Child
|
||||
if (err) {
|
||||
printf("failed to map child memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
err = uc_hook_add(uc, &h3, UC_HOOK_TLB_FILL, virtual_tlb_callback, &parrent_done, 1, 0);
|
||||
|
||||
printf("run the parrent\n");
|
||||
err = uc_emu_start(uc, 0x2000, 0x0, 0, 0);
|
||||
if (err) {
|
||||
printf("failed to run parrent\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("save the context for the child\n");
|
||||
err = uc_context_save(uc, context);
|
||||
printf("finish the parrent\n");
|
||||
err = uc_reg_read(uc, UC_X86_REG_RIP, &rip);
|
||||
if (err) {
|
||||
printf("failed to read rip\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
err = uc_emu_start(uc, rip, 0x0, 0, 0);
|
||||
if (err) {
|
||||
printf("failed to flush tlb\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("restore the context for the child\n");
|
||||
err = uc_context_restore(uc, context);
|
||||
if (err) {
|
||||
printf("failed to restore context\n");
|
||||
exit(1);
|
||||
}
|
||||
rax = 0;
|
||||
parrent_done = true;
|
||||
err = uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
||||
if (err) {
|
||||
printf("failed to write rax\n");
|
||||
exit(1);
|
||||
}
|
||||
err = uc_ctl_flush_tlb(uc);
|
||||
if (err) {
|
||||
printf("failed to flush tlb\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
err = uc_emu_start(uc, rip, 0x0, 0, 0);
|
||||
if (err) {
|
||||
printf("failed to run child\n");
|
||||
exit(1);
|
||||
}
|
||||
err = uc_mem_read(uc, 0x1000, &parrent, sizeof(parrent));
|
||||
if (err) {
|
||||
printf("failed to read from parrent memory\n");
|
||||
exit(1);
|
||||
}
|
||||
err = uc_mem_read(uc, 0x2000, &child, sizeof(child));
|
||||
if (err) {
|
||||
printf("failed to read from child memory\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("parrent result == %lu\n", parrent);
|
||||
printf("child result == %lu\n", child);
|
||||
uc_close(uc);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
cpu_tlb();
|
||||
virtual_tlb();
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ CMD_PATH=$(realpath $0)
|
||||
SOURCE_DIR=$(dirname ${CMD_PATH})
|
||||
|
||||
COMMON_SYMBOLS="
|
||||
unicorn_fill_tlb \
|
||||
uc_add_inline_hook \
|
||||
uc_del_inline_hook \
|
||||
tb_invalidate_phys_range \
|
||||
|
@ -1384,6 +1384,36 @@ static void test_x86_mmu(void)
|
||||
TEST_CHECK(child == 42);
|
||||
}
|
||||
|
||||
static bool test_x86_vtlb_callback(uc_engine *uc, uint64_t addr, uc_mem_type type, uc_tlb_entry *result, void *user_data)
|
||||
{
|
||||
result->paddr = addr;
|
||||
result->perms = UC_PROT_ALL;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_x86_vtlb(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_hook hook;
|
||||
char code[] = "\xeb\x02\x90\x90\x90\x90\x90\x90"; // jmp 4; nop; nop; nop;
|
||||
// nop; nop; nop
|
||||
uint64_t r_eip = 0;
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||
|
||||
OK(uc_ctl_tlb_mode(uc, UC_TLB_VIRTUAL));
|
||||
OK(uc_hook_add(uc, &hook, UC_HOOK_TLB_FILL, test_x86_vtlb_callback, NULL, 1, 0));
|
||||
|
||||
OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0));
|
||||
|
||||
OK(uc_reg_read(uc, UC_X86_REG_EIP, &r_eip));
|
||||
|
||||
TEST_CHECK(r_eip == code_start + 4);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
|
||||
TEST_LIST = {
|
||||
{"test_x86_in", test_x86_in},
|
||||
{"test_x86_out", test_x86_out},
|
||||
@ -1428,4 +1458,5 @@ TEST_LIST = {
|
||||
{"test_x86_lazy_mapping", test_x86_lazy_mapping},
|
||||
{"test_x86_16_incorrect_ip", test_x86_16_incorrect_ip},
|
||||
{"test_x86_mmu", test_x86_mmu},
|
||||
{"test_x86_vtlb", test_x86_vtlb},
|
||||
{NULL, NULL}};
|
||||
|
23
uc.c
23
uc.c
@ -2377,6 +2377,19 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
|
||||
}
|
||||
break;
|
||||
|
||||
case UC_CTL_TLB_TYPE: {
|
||||
|
||||
UC_INIT(uc);
|
||||
|
||||
if (rw == UC_CTL_IO_WRITE) {
|
||||
int mode = va_arg(args, int);
|
||||
err = uc->set_tlb(uc, mode);
|
||||
} else {
|
||||
err = UC_ERR_ARG;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
err = UC_ERR_ARG;
|
||||
break;
|
||||
@ -2387,6 +2400,16 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
|
||||
return err;
|
||||
}
|
||||
|
||||
gint cmp_vaddr(gconstpointer a, gconstpointer b, gpointer user_data)
|
||||
{
|
||||
uint64_t va = (uint64_t)a;
|
||||
uint64_t vb = (uint64_t)b;
|
||||
if (va == vb) {
|
||||
return 0;
|
||||
}
|
||||
return va < vb ? -1 : 1;
|
||||
}
|
||||
|
||||
#ifdef UNICORN_TRACER
|
||||
uc_tracer *get_tracer()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user