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/tcg-runtime-gvec.c
|
||||||
qemu/accel/tcg/translate-all.c
|
qemu/accel/tcg/translate-all.c
|
||||||
qemu/accel/tcg/translator.c
|
qemu/accel/tcg/translator.c
|
||||||
|
|
||||||
|
qemu/softmmu/unicorn_vtlb.c
|
||||||
)
|
)
|
||||||
|
|
||||||
if(UNICORN_HAS_X86)
|
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
|
// tb flush
|
||||||
typedef uc_tcg_flush_tlb uc_tb_flush_t;
|
typedef uc_tcg_flush_tlb uc_tb_flush_t;
|
||||||
|
|
||||||
|
typedef uc_err (*uc_set_tlb_t)(struct uc_struct *uc, int mode);
|
||||||
|
|
||||||
struct hook {
|
struct hook {
|
||||||
int type; // UC_HOOK_*
|
int type; // UC_HOOK_*
|
||||||
int insn; // instruction for HOOK_INSN
|
int insn; // instruction for HOOK_INSN
|
||||||
@ -202,6 +204,7 @@ typedef enum uc_hook_idx {
|
|||||||
UC_HOOK_INSN_INVALID_IDX,
|
UC_HOOK_INSN_INVALID_IDX,
|
||||||
UC_HOOK_EDGE_GENERATED_IDX,
|
UC_HOOK_EDGE_GENERATED_IDX,
|
||||||
UC_HOOK_TCG_OPCODE_IDX,
|
UC_HOOK_TCG_OPCODE_IDX,
|
||||||
|
UC_HOOK_TLB_FILL_IDX,
|
||||||
|
|
||||||
UC_HOOK_MAX,
|
UC_HOOK_MAX,
|
||||||
} uc_hook_idx;
|
} uc_hook_idx;
|
||||||
@ -337,6 +340,8 @@ struct uc_struct {
|
|||||||
GHashTable *flat_views;
|
GHashTable *flat_views;
|
||||||
bool memory_region_update_pending;
|
bool memory_region_update_pending;
|
||||||
|
|
||||||
|
uc_set_tlb_t set_tlb;
|
||||||
|
|
||||||
// linked lists containing hooks per type
|
// linked lists containing hooks per type
|
||||||
struct list hook[UC_HOOK_MAX];
|
struct list hook[UC_HOOK_MAX];
|
||||||
struct list hooks_to_del;
|
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,
|
typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size,
|
||||||
uint32_t value, void *user_data);
|
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.
|
// Represent a TranslationBlock.
|
||||||
typedef struct uc_tb {
|
typedef struct uc_tb {
|
||||||
uint64_t pc;
|
uint64_t pc;
|
||||||
@ -295,7 +311,7 @@ typedef void (*uc_cb_mmio_write_t)(uc_engine *uc, uint64_t offset,
|
|||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
// All type of memory accesses for UC_HOOK_MEM_*
|
// 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_READ = 16, // Memory is read from
|
||||||
UC_MEM_WRITE, // Memory is written to
|
UC_MEM_WRITE, // Memory is written to
|
||||||
UC_MEM_FETCH, // Memory is fetched
|
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_READ_PROT, // Read from read protected, but mapped, memory
|
||||||
UC_MEM_FETCH_PROT, // Fetch from non-executable, 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_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.
|
// 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
|
// 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
|
// Hook on specific tcg op code. The usage of this hook is similar to
|
||||||
// UC_HOOK_INSN.
|
// UC_HOOK_INSN.
|
||||||
UC_HOOK_TCG_OPCODE = 1 << 16,
|
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;
|
} uc_hook_type;
|
||||||
|
|
||||||
// Hook type for all events of unmapped memory access
|
// 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_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)
|
#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.
|
// All type of controls for uc_ctl API.
|
||||||
// The controls are organized in a tree level.
|
// 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.
|
// 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,
|
UC_CTL_TB_REMOVE_CACHE,
|
||||||
// Invalidate all translation blocks.
|
// Invalidate all translation blocks.
|
||||||
// No arguments.
|
// 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;
|
} uc_control_type;
|
||||||
|
|
||||||
@ -612,6 +646,7 @@ See sample_ctl.c for a detailed example.
|
|||||||
#define uc_ctl_request_cache(uc, address, tb) \
|
#define uc_ctl_request_cache(uc, address, tb) \
|
||||||
uc_ctl(uc, UC_CTL_READ_WRITE(UC_CTL_TB_REQUEST_CACHE, 2), (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_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_*()
|
// Opaque storage for CPU context, used with uc_context_*()
|
||||||
struct uc_context;
|
struct uc_context;
|
||||||
typedef struct uc_context uc_context;
|
typedef struct uc_context uc_context;
|
||||||
@ -898,6 +933,11 @@ typedef enum uc_prot {
|
|||||||
UC_PROT_ALL = 7,
|
UC_PROT_ALL = 7,
|
||||||
} uc_prot;
|
} uc_prot;
|
||||||
|
|
||||||
|
struct uc_tlb_entry {
|
||||||
|
uint64_t paddr;
|
||||||
|
uc_prot perms;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Map memory in for emulation.
|
Map memory in for emulation.
|
||||||
This API adds a memory region that can be used by emulation.
|
This API adds a memory region that can be used by emulation.
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _aarch64
|
#define UNICORN_ARCH_POSTFIX _aarch64
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_aarch64
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_aarch64
|
#define uc_add_inline_hook uc_add_inline_hook_aarch64
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_aarch64
|
#define uc_del_inline_hook uc_del_inline_hook_aarch64
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_aarch64
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_aarch64
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _arm
|
#define UNICORN_ARCH_POSTFIX _arm
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_arm
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_arm
|
#define uc_add_inline_hook uc_add_inline_hook_arm
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_arm
|
#define uc_del_inline_hook uc_del_inline_hook_arm
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_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,
|
bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
|
||||||
MMUAccessType access_type, int mmu_idx,
|
MMUAccessType access_type, int mmu_idx,
|
||||||
bool probe, uintptr_t retaddr);
|
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_debug)(CPUState *cpu, vaddr addr);
|
||||||
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
|
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
|
||||||
MemTxAttrs *attrs);
|
MemTxAttrs *attrs);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define QEMU_CPUS_H
|
#define QEMU_CPUS_H
|
||||||
|
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
|
#include "hw/core/cpu.h"
|
||||||
|
|
||||||
/* cpus.c */
|
/* cpus.c */
|
||||||
bool qemu_in_vcpu_thread(void);
|
bool qemu_in_vcpu_thread(void);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _m68k
|
#define UNICORN_ARCH_POSTFIX _m68k
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_m68k
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_m68k
|
#define uc_add_inline_hook uc_add_inline_hook_m68k
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_m68k
|
#define uc_del_inline_hook uc_del_inline_hook_m68k
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_m68k
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_m68k
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _mips
|
#define UNICORN_ARCH_POSTFIX _mips
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_mips
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_mips
|
#define uc_add_inline_hook uc_add_inline_hook_mips
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_mips
|
#define uc_del_inline_hook uc_del_inline_hook_mips
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _mips64
|
#define UNICORN_ARCH_POSTFIX _mips64
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_mips64
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_mips64
|
#define uc_add_inline_hook uc_add_inline_hook_mips64
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_mips64
|
#define uc_del_inline_hook uc_del_inline_hook_mips64
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips64
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips64
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _mips64el
|
#define UNICORN_ARCH_POSTFIX _mips64el
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_mips64el
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_mips64el
|
#define uc_add_inline_hook uc_add_inline_hook_mips64el
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_mips64el
|
#define uc_del_inline_hook uc_del_inline_hook_mips64el
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips64el
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips64el
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _mipsel
|
#define UNICORN_ARCH_POSTFIX _mipsel
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_mipsel
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_mipsel
|
#define uc_add_inline_hook uc_add_inline_hook_mipsel
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_mipsel
|
#define uc_del_inline_hook uc_del_inline_hook_mipsel
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_mipsel
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_mipsel
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _ppc
|
#define UNICORN_ARCH_POSTFIX _ppc
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_ppc
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_ppc
|
#define uc_add_inline_hook uc_add_inline_hook_ppc
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_ppc
|
#define uc_del_inline_hook uc_del_inline_hook_ppc
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_ppc
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_ppc
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _ppc64
|
#define UNICORN_ARCH_POSTFIX _ppc64
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_ppc64
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_ppc64
|
#define uc_add_inline_hook uc_add_inline_hook_ppc64
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_ppc64
|
#define uc_del_inline_hook uc_del_inline_hook_ppc64
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_ppc64
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_ppc64
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _riscv32
|
#define UNICORN_ARCH_POSTFIX _riscv32
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_riscv32
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_riscv32
|
#define uc_add_inline_hook uc_add_inline_hook_riscv32
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_riscv32
|
#define uc_del_inline_hook uc_del_inline_hook_riscv32
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_riscv32
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_riscv32
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _riscv64
|
#define UNICORN_ARCH_POSTFIX _riscv64
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_riscv64
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_riscv64
|
#define uc_add_inline_hook uc_add_inline_hook_riscv64
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_riscv64
|
#define uc_del_inline_hook uc_del_inline_hook_riscv64
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_riscv64
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_riscv64
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _s390x
|
#define UNICORN_ARCH_POSTFIX _s390x
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_s390x
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_s390x
|
#define uc_add_inline_hook uc_add_inline_hook_s390x
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_s390x
|
#define uc_del_inline_hook uc_del_inline_hook_s390x
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_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
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _sparc
|
#define UNICORN_ARCH_POSTFIX _sparc
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_sparc
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_sparc
|
#define uc_add_inline_hook uc_add_inline_hook_sparc
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_sparc
|
#define uc_del_inline_hook uc_del_inline_hook_sparc
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_sparc
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_sparc
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _sparc64
|
#define UNICORN_ARCH_POSTFIX _sparc64
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_sparc64
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_sparc64
|
#define uc_add_inline_hook uc_add_inline_hook_sparc64
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_sparc64
|
#define uc_del_inline_hook uc_del_inline_hook_sparc64
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_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->asidx_from_attrs = arm_asidx_from_attrs;
|
||||||
cc->tcg_initialize = arm_translate_init;
|
cc->tcg_initialize = arm_translate_init;
|
||||||
cc->tlb_fill = arm_cpu_tlb_fill;
|
cc->tlb_fill = arm_cpu_tlb_fill;
|
||||||
|
cc->tlb_fill_cpu = arm_cpu_tlb_fill;
|
||||||
cc->debug_excp_handler = arm_debug_excp_handler;
|
cc->debug_excp_handler = arm_debug_excp_handler;
|
||||||
cc->do_unaligned_access = arm_cpu_do_unaligned_access;
|
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->cpu_exec_exit = x86_cpu_exec_exit;
|
||||||
cc->tcg_initialize = tcg_x86_init;
|
cc->tcg_initialize = tcg_x86_init;
|
||||||
cc->tlb_fill = x86_cpu_tlb_fill;
|
cc->tlb_fill = x86_cpu_tlb_fill;
|
||||||
|
cc->tlb_fill_cpu = x86_cpu_tlb_fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
X86CPU *cpu_x86_init(struct uc_struct *uc)
|
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->cpu_exec_interrupt = m68k_cpu_exec_interrupt;
|
||||||
cc->set_pc = m68k_cpu_set_pc;
|
cc->set_pc = m68k_cpu_set_pc;
|
||||||
cc->tlb_fill = m68k_cpu_tlb_fill;
|
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->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
|
||||||
cc->tcg_initialize = m68k_tcg_init;
|
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->get_phys_page_debug = mips_cpu_get_phys_page_debug;
|
||||||
cc->tcg_initialize = mips_tcg_init;
|
cc->tcg_initialize = mips_tcg_init;
|
||||||
cc->tlb_fill = mips_cpu_tlb_fill;
|
cc->tlb_fill = mips_cpu_tlb_fill;
|
||||||
|
cc->tlb_fill_cpu = mips_cpu_tlb_fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
MIPSCPU *cpu_mips_init(struct uc_struct *uc)
|
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->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
|
||||||
cc->tcg_initialize = ppc_translate_init;
|
cc->tcg_initialize = ppc_translate_init;
|
||||||
cc->tlb_fill = ppc_cpu_tlb_fill;
|
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_enter = ppc_cpu_exec_enter;
|
||||||
cc->cpu_exec_exit = ppc_cpu_exec_exit;
|
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->do_unaligned_access = riscv_cpu_do_unaligned_access;
|
||||||
cc->tcg_initialize = riscv_translate_init;
|
cc->tcg_initialize = riscv_translate_init;
|
||||||
cc->tlb_fill = riscv_cpu_tlb_fill;
|
cc->tlb_fill = riscv_cpu_tlb_fill;
|
||||||
|
cc->tlb_fill_cpu = riscv_cpu_tlb_fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct CPUModelInfo {
|
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->do_unaligned_access = s390x_cpu_do_unaligned_access;
|
||||||
cc->tcg_initialize = s390x_translate_init;
|
cc->tcg_initialize = s390x_translate_init;
|
||||||
cc->tlb_fill = s390_cpu_tlb_fill;
|
cc->tlb_fill = s390_cpu_tlb_fill;
|
||||||
|
cc->tlb_fill_cpu = s390_cpu_tlb_fill;
|
||||||
|
|
||||||
// s390_cpu_model_class_register_props(oc);
|
// 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->set_pc = sparc_cpu_set_pc;
|
||||||
cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
|
cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
|
||||||
cc->tlb_fill = sparc_cpu_tlb_fill;
|
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->do_unaligned_access = sparc_cpu_do_unaligned_access;
|
||||||
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
|
||||||
cc->tcg_initialize = sparc_tcg_init;
|
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->get_phys_page_debug = tricore_cpu_get_phys_page_debug;
|
||||||
|
|
||||||
cc->tlb_fill = tricore_cpu_tlb_fill;
|
cc->tlb_fill = tricore_cpu_tlb_fill;
|
||||||
|
cc->tlb_fill_cpu = tricore_cpu_tlb_fill;
|
||||||
cc->tcg_initialize = tricore_tcg_init;
|
cc->tcg_initialize = tricore_tcg_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _tricore
|
#define UNICORN_ARCH_POSTFIX _tricore
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_tricore
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_tricore
|
#define uc_add_inline_hook uc_add_inline_hook_tricore
|
||||||
#define uc_del_inline_hook uc_del_inline_hook_tricore
|
#define uc_del_inline_hook uc_del_inline_hook_tricore
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_tricore
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_tricore
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
void vm_start(struct uc_struct*);
|
void vm_start(struct uc_struct*);
|
||||||
void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size);
|
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
|
// return true on success, false on failure
|
||||||
static inline bool cpu_physical_mem_read(AddressSpace *as, hwaddr addr,
|
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;
|
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);
|
void softfloat_init(void);
|
||||||
static inline void uc_common_init(struct uc_struct* uc)
|
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->softfloat_initialize = softfloat_init;
|
||||||
uc->tcg_flush_tlb = tcg_flush_softmmu_tlb;
|
uc->tcg_flush_tlb = tcg_flush_softmmu_tlb;
|
||||||
uc->memory_map_io = memory_map_io;
|
uc->memory_map_io = memory_map_io;
|
||||||
|
uc->set_tlb = uc_set_tlb;
|
||||||
|
|
||||||
if (!uc->release)
|
if (!uc->release)
|
||||||
uc->release = release_common;
|
uc->release = release_common;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef UNICORN_ARCH_POSTFIX
|
#ifndef UNICORN_ARCH_POSTFIX
|
||||||
#define UNICORN_ARCH_POSTFIX _x86_64
|
#define UNICORN_ARCH_POSTFIX _x86_64
|
||||||
#endif
|
#endif
|
||||||
|
#define unicorn_fill_tlb unicorn_fill_tlb_x86_64
|
||||||
#define uc_add_inline_hook uc_add_inline_hook_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 uc_del_inline_hook uc_del_inline_hook_x86_64
|
||||||
#define tb_invalidate_phys_range tb_invalidate_phys_range_x86_64
|
#define tb_invalidate_phys_range tb_invalidate_phys_range_x86_64
|
||||||
|
@ -1,6 +1,25 @@
|
|||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <stdio.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)
|
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);
|
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));
|
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;
|
uc_err err;
|
||||||
bool *parrent_done = userdata;
|
bool *parrent_done = userdata;
|
||||||
@ -99,6 +118,7 @@ static void x86_mmu_callback(uc_engine *uc, void *userdata)
|
|||||||
break;
|
break;
|
||||||
case 60:
|
case 60:
|
||||||
/* exit */
|
/* exit */
|
||||||
|
*parrent_done = true;
|
||||||
uc_emu_stop(uc);
|
uc_emu_stop(uc);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
@ -107,7 +127,6 @@ static void x86_mmu_callback(uc_engine *uc, void *userdata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(*parrent_done)) {
|
if (!(*parrent_done)) {
|
||||||
*parrent_done = true;
|
|
||||||
rax = 27;
|
rax = 27;
|
||||||
err = uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
err = uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
||||||
if (err) {
|
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 tlb_base = 0x3000;
|
||||||
uint64_t rax, rip;
|
uint64_t rax, rip;
|
||||||
@ -129,24 +148,6 @@ int main(void)
|
|||||||
uc_err err;
|
uc_err err;
|
||||||
uc_hook h1, h2;
|
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");
|
printf("Emulate x86 amd64 code with mmu enabled and switch mappings\n");
|
||||||
|
|
||||||
err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
|
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);
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
uc_ctl_tlb_mode(uc, UC_TLB_CPU);
|
||||||
err = uc_context_alloc(uc, &context);
|
err = uc_context_alloc(uc, &context);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_context_alloc() with error returned: %u\n", err);
|
printf("Failed on uc_context_alloc() with error returned: %u\n", err);
|
||||||
exit(1);
|
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) {
|
if (err) {
|
||||||
printf("Failed on uc_hook_add() with error returned: %u\n", err);
|
printf("Failed on uc_hook_add() with error returned: %u\n", err);
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -272,4 +274,157 @@ int main(void)
|
|||||||
}
|
}
|
||||||
printf("parrent result == %lu\n", parrent);
|
printf("parrent result == %lu\n", parrent);
|
||||||
printf("child result == %lu\n", child);
|
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})
|
SOURCE_DIR=$(dirname ${CMD_PATH})
|
||||||
|
|
||||||
COMMON_SYMBOLS="
|
COMMON_SYMBOLS="
|
||||||
|
unicorn_fill_tlb \
|
||||||
uc_add_inline_hook \
|
uc_add_inline_hook \
|
||||||
uc_del_inline_hook \
|
uc_del_inline_hook \
|
||||||
tb_invalidate_phys_range \
|
tb_invalidate_phys_range \
|
||||||
|
@ -1384,6 +1384,36 @@ static void test_x86_mmu(void)
|
|||||||
TEST_CHECK(child == 42);
|
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_LIST = {
|
||||||
{"test_x86_in", test_x86_in},
|
{"test_x86_in", test_x86_in},
|
||||||
{"test_x86_out", test_x86_out},
|
{"test_x86_out", test_x86_out},
|
||||||
@ -1428,4 +1458,5 @@ TEST_LIST = {
|
|||||||
{"test_x86_lazy_mapping", test_x86_lazy_mapping},
|
{"test_x86_lazy_mapping", test_x86_lazy_mapping},
|
||||||
{"test_x86_16_incorrect_ip", test_x86_16_incorrect_ip},
|
{"test_x86_16_incorrect_ip", test_x86_16_incorrect_ip},
|
||||||
{"test_x86_mmu", test_x86_mmu},
|
{"test_x86_mmu", test_x86_mmu},
|
||||||
|
{"test_x86_vtlb", test_x86_vtlb},
|
||||||
{NULL, NULL}};
|
{NULL, NULL}};
|
||||||
|
23
uc.c
23
uc.c
@ -2377,6 +2377,19 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
err = UC_ERR_ARG;
|
err = UC_ERR_ARG;
|
||||||
break;
|
break;
|
||||||
@ -2387,6 +2400,16 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
|
|||||||
return err;
|
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
|
#ifdef UNICORN_TRACER
|
||||||
uc_tracer *get_tracer()
|
uc_tracer *get_tracer()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user