import Unicorn2

This commit is contained in:
Nguyen Anh Quynh
2021-10-03 22:14:44 +08:00
parent 772558119a
commit aaaea14214
837 changed files with 368717 additions and 200912 deletions

204
qemu/softmmu/cpus.c Normal file
View File

@@ -0,0 +1,204 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "sysemu/tcg.h"
#include "sysemu/cpus.h"
#include "qemu/bitmap.h"
#include "tcg/tcg.h"
#include "exec/tb-hash.h"
#include "uc_priv.h"
int64_t cpu_icount_to_ns(int64_t icount)
{
// return icount << atomic_read(&timers_state.icount_time_shift);
// from configure_icount(QemuOpts *opts, Error **errp)
/* 125MIPS seems a reasonable initial guess at the guest speed.
It will be corrected fairly quickly anyway. */
// timers_state.icount_time_shift = 3;
return icount << 3;
}
bool cpu_is_stopped(CPUState *cpu)
{
return cpu->stopped;
}
/* return the time elapsed in VM between vm_start and vm_stop. Unless
* icount is active, cpu_get_ticks() uses units of the host CPU cycle
* counter.
*/
int64_t cpu_get_ticks(void)
{
return cpu_get_host_ticks();
}
/* Return the monotonic time elapsed in VM, i.e.,
* the time between vm_start and vm_stop
*/
int64_t cpu_get_clock(void)
{
return get_clock();
}
static bool cpu_can_run(CPUState *cpu)
{
if (cpu->stop) {
return false;
}
if (cpu_is_stopped(cpu)) {
return false;
}
return true;
}
static void cpu_handle_guest_debug(CPUState *cpu)
{
cpu->stopped = true;
}
static int tcg_cpu_exec(struct uc_struct *uc)
{
int r;
bool finish = false;
while (!uc->exit_request) {
CPUState *cpu = uc->cpu;
//qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
// (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
if (cpu_can_run(cpu)) {
uc->quit_request = false;
r = cpu_exec(uc, cpu);
// quit current TB but continue emulating?
if (uc->quit_request) {
// reset stop_request
uc->stop_request = false;
} else if (uc->stop_request) {
//printf(">>> got STOP request!!!\n");
finish = true;
break;
}
// save invalid memory access error & quit
if (uc->invalid_error) {
// printf(">>> invalid memory accessed, STOP = %u!!!\n", env->invalid_error);
finish = true;
break;
}
// printf(">>> stop with r = %x, HLT=%x\n", r, EXCP_HLT);
if (r == EXCP_DEBUG) {
cpu_handle_guest_debug(cpu);
break;
}
if (r == EXCP_HLT) {
//printf(">>> got HLT!!!\n");
finish = true;
break;
}
} else if (cpu->stop || cpu->stopped) {
// printf(">>> got stopped!!!\n");
break;
}
}
uc->exit_request = 0;
return finish;
}
void cpu_resume(CPUState *cpu)
{
cpu->stop = false;
cpu->stopped = false;
}
static void qemu_tcg_init_vcpu(CPUState *cpu)
{
/*
* Initialize TCG regions--once. Now is a good time, because:
* (1) TCG's init context, prologue and target globals have been set up.
* (2) qemu_tcg_mttcg_enabled() works now (TCG init code runs before the
* -accel flag is processed, so the check doesn't work then).
*/
tcg_region_init(cpu->uc->tcg_ctx);
cpu->created = true;
}
void qemu_init_vcpu(CPUState *cpu)
{
cpu->nr_cores = 1;
cpu->nr_threads = 1;
cpu->stopped = true;
qemu_tcg_init_vcpu(cpu);
return;
}
void cpu_stop_current(struct uc_struct *uc)
{
if (uc->cpu) {
uc->cpu->stop = false;
uc->cpu->stopped = true;
cpu_exit(uc->cpu);
}
}
void resume_all_vcpus(struct uc_struct* uc)
{
CPUState *cpu = uc->cpu;
cpu->halted = 0;
cpu->exit_request = 0;
cpu->exception_index = -1;
cpu_resume(cpu);
/* static void qemu_tcg_cpu_loop(struct uc_struct *uc) */
cpu->created = true;
while (true) {
if (tcg_cpu_exec(uc)) {
break;
}
}
// clear the cache of the addr_end address, since the generated code
// at that address is to exit emulation, but not for the instruction there.
// if we dont do this, next time we cannot emulate at that address
TranslationBlock *tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(uc, uc->addr_end)];
if (tb) {
qht_remove(&uc->tcg_ctx->tb_ctx.htable, tb, tb->hash);
tb_flush_jmp_cache(cpu, uc->addr_end);
}
cpu->created = false;
}
void vm_start(struct uc_struct* uc)
{
resume_all_vcpus(uc);
}

174
qemu/softmmu/ioport.c Normal file
View File

@@ -0,0 +1,174 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* splitted out ioport related stuffs from vl.c.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/memory.h"
#include "uc_priv.h"
static uint64_t unassigned_io_read(struct uc_struct *uc, void* opaque, hwaddr addr, unsigned size)
{
#ifdef _MSC_VER
return (uint64_t)0xffffffffffffffffULL;
#else
return (uint64_t)-1ULL;
#endif
}
static void unassigned_io_write(struct uc_struct *uc, void* opaque, hwaddr addr, uint64_t data, unsigned size)
{
}
const MemoryRegionOps unassigned_io_ops = {
.read = unassigned_io_read,
.write = unassigned_io_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
void cpu_outb(struct uc_struct *uc, uint32_t addr, uint8_t val)
{
// address_space_write(&uc->address_space_io, addr, MEMTXATTRS_UNSPECIFIED,
// &val, 1);
//LOG_IOPORT("outb: %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
// Unicorn: call registered OUT callbacks
struct hook *hook;
HOOK_FOREACH_VAR_DECLARE;
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
if (hook->to_delete)
continue;
if (hook->insn == UC_X86_INS_OUT)
((uc_cb_insn_out_t)hook->callback)(uc, addr, 1, val, hook->user_data);
}
}
void cpu_outw(struct uc_struct *uc, uint32_t addr, uint16_t val)
{
// uint8_t buf[2];
// stw_p(buf, val);
// address_space_write(&uc->address_space_io, addr, MEMTXATTRS_UNSPECIFIED,
// buf, 2);
//LOG_IOPORT("outw: %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
// Unicorn: call registered OUT callbacks
struct hook *hook;
HOOK_FOREACH_VAR_DECLARE;
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
if (hook->to_delete)
continue;
if (hook->insn == UC_X86_INS_OUT)
((uc_cb_insn_out_t)hook->callback)(uc, addr, 2, val, hook->user_data);
}
}
void cpu_outl(struct uc_struct *uc, uint32_t addr, uint32_t val)
{
// uint8_t buf[4];
// stl_p(buf, val);
// address_space_write(&uc->address_space_io, addr, MEMTXATTRS_UNSPECIFIED,
// buf, 4);
//LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
// Unicorn: call registered OUT callbacks
struct hook *hook;
HOOK_FOREACH_VAR_DECLARE;
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
if (hook->to_delete)
continue;
if (hook->insn == UC_X86_INS_OUT)
((uc_cb_insn_out_t)hook->callback)(uc, addr, 4, val, hook->user_data);
}
}
uint8_t cpu_inb(struct uc_struct *uc, uint32_t addr)
{
// uint8_t val;
// address_space_read(&uc->address_space_io, addr, MEMTXATTRS_UNSPECIFIED,
// &val, 1);
//LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
// Unicorn: call registered IN callbacks
struct hook *hook;
HOOK_FOREACH_VAR_DECLARE;
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
if (hook->to_delete)
continue;
if (hook->insn == UC_X86_INS_IN)
return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 1, hook->user_data);
}
return 0;
}
uint16_t cpu_inw(struct uc_struct *uc, uint32_t addr)
{
// uint8_t buf[2];
// uint16_t val;
// address_space_read(&uc->address_space_io, addr, MEMTXATTRS_UNSPECIFIED, buf, 2);
// val = lduw_p(buf);
//LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
// Unicorn: call registered IN callbacks
struct hook *hook;
HOOK_FOREACH_VAR_DECLARE;
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
if (hook->to_delete)
continue;
if (hook->insn == UC_X86_INS_IN)
return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 2, hook->user_data);
}
return 0;
}
uint32_t cpu_inl(struct uc_struct *uc, uint32_t addr)
{
// uint8_t buf[4];
// uint32_t val;
// printf("inl_addr=%x\n", addr);
// address_space_read(&uc->address_space_io, addr, MEMTXATTRS_UNSPECIFIED, buf, 4);
// val = ldl_p(buf);
//LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
// Unicorn: call registered IN callbacks
struct hook *hook;
HOOK_FOREACH_VAR_DECLARE;
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
if (hook->to_delete)
continue;
if (hook->insn == UC_X86_INS_IN)
return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 4, hook->user_data);
}
return 0;
}

1346
qemu/softmmu/memory.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,150 @@
/*
* QEMU memory mapping
*
* Copyright Fujitsu, Corp. 2011, 2012
*
* Authors:
* Wen Congyang <wency@cn.fujitsu.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "sysemu/memory_mapping.h"
#include "exec/memory.h"
//#define DEBUG_GUEST_PHYS_REGION_ADD
static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
MemoryMapping *mapping)
{
MemoryMapping *p;
QTAILQ_FOREACH(p, &list->head, next) {
if (p->phys_addr >= mapping->phys_addr) {
QTAILQ_INSERT_BEFORE(p, mapping, next);
return;
}
}
QTAILQ_INSERT_TAIL(&list->head, mapping, next);
}
static void create_new_memory_mapping(MemoryMappingList *list,
hwaddr phys_addr,
hwaddr virt_addr,
ram_addr_t length)
{
MemoryMapping *memory_mapping;
memory_mapping = g_malloc(sizeof(MemoryMapping));
memory_mapping->phys_addr = phys_addr;
memory_mapping->virt_addr = virt_addr;
memory_mapping->length = length;
list->last_mapping = memory_mapping;
list->num++;
memory_mapping_list_add_mapping_sorted(list, memory_mapping);
}
static inline bool mapping_contiguous(MemoryMapping *map,
hwaddr phys_addr,
hwaddr virt_addr)
{
return phys_addr == map->phys_addr + map->length &&
virt_addr == map->virt_addr + map->length;
}
/*
* [map->phys_addr, map->phys_addr + map->length) and
* [phys_addr, phys_addr + length) have intersection?
*/
static inline bool mapping_have_same_region(MemoryMapping *map,
hwaddr phys_addr,
ram_addr_t length)
{
return !(phys_addr + length < map->phys_addr ||
phys_addr >= map->phys_addr + map->length);
}
/*
* [map->phys_addr, map->phys_addr + map->length) and
* [phys_addr, phys_addr + length) have intersection. The virtual address in the
* intersection are the same?
*/
static inline bool mapping_conflict(MemoryMapping *map,
hwaddr phys_addr,
hwaddr virt_addr)
{
return virt_addr - map->virt_addr != phys_addr - map->phys_addr;
}
/*
* [map->virt_addr, map->virt_addr + map->length) and
* [virt_addr, virt_addr + length) have intersection. And the physical address
* in the intersection are the same.
*/
static inline void mapping_merge(MemoryMapping *map,
hwaddr virt_addr,
ram_addr_t length)
{
if (virt_addr < map->virt_addr) {
map->length += map->virt_addr - virt_addr;
map->virt_addr = virt_addr;
}
if ((virt_addr + length) >
(map->virt_addr + map->length)) {
map->length = virt_addr + length - map->virt_addr;
}
}
void memory_mapping_list_add_merge_sorted(MemoryMappingList *list,
hwaddr phys_addr,
hwaddr virt_addr,
ram_addr_t length)
{
MemoryMapping *memory_mapping, *last_mapping;
if (QTAILQ_EMPTY(&list->head)) {
create_new_memory_mapping(list, phys_addr, virt_addr, length);
return;
}
last_mapping = list->last_mapping;
if (last_mapping) {
if (mapping_contiguous(last_mapping, phys_addr, virt_addr)) {
last_mapping->length += length;
return;
}
}
QTAILQ_FOREACH(memory_mapping, &list->head, next) {
if (mapping_contiguous(memory_mapping, phys_addr, virt_addr)) {
memory_mapping->length += length;
list->last_mapping = memory_mapping;
return;
}
if (phys_addr + length < memory_mapping->phys_addr) {
/* create a new region before memory_mapping */
break;
}
if (mapping_have_same_region(memory_mapping, phys_addr, length)) {
if (mapping_conflict(memory_mapping, phys_addr, virt_addr)) {
continue;
}
/* merge this region into memory_mapping */
mapping_merge(memory_mapping, virt_addr, length);
list->last_mapping = memory_mapping;
return;
}
}
/* this region can not be merged into any existed memory mapping. */
create_new_memory_mapping(list, phys_addr, virt_addr, length);
}

68
qemu/softmmu/vl.c Normal file
View File

@@ -0,0 +1,68 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "sysemu/sysemu.h"
#include "sysemu/cpus.h"
#include "uc_priv.h"
void init_real_host_page_size(struct uc_struct *uc);
void init_cache_info(struct uc_struct *uc);
DEFAULT_VISIBILITY
int machine_initialize(struct uc_struct *uc)
{
init_get_clock();
/* Init uc->qemu_real_host_page_size. */
init_real_host_page_size(uc);
/* Init uc->qemu_icache_linesize. */
init_cache_info(uc);
// Initialize arch specific.
uc->init_arch(uc);
/* Init memory. */
uc->cpu_exec_init_all(uc);
uc->target_page(uc);
/* Init tcg. use DEFAULT_CODE_GEN_BUFFER_SIZE. */
uc->tcg_exec_init(uc, 0);
/* Init cpu. use default cpu_model. */
return uc->cpus_init(uc, NULL);
}
void qemu_system_reset_request(struct uc_struct* uc)
{
cpu_stop(uc);
}
void qemu_system_shutdown_request(struct uc_struct *uc)
{
/* TODO: shutdown(exit program) immediately? */
cpu_stop(uc);
}