📄 exec-dm.c
字号:
/* * virtual page mapping and translated block handling * * Copyright (c) 2003 Fabrice Bellard * * 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 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "config.h"#ifdef _WIN32#include <windows.h>#else#include <sys/types.h>#include <sys/mman.h>#endif#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <inttypes.h>#include "cpu.h"#include "exec-all.h"#include "vl.h"//#define DEBUG_TB_INVALIDATE//#define DEBUG_FLUSH//#define DEBUG_TLB/* make various TB consistency checks *///#define DEBUG_TB_CHECK //#define DEBUG_TLB_CHECK #ifndef CONFIG_DM/* threshold to flush the translated code buffer */#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)#define SMC_BITMAP_USE_THRESHOLD 10#define MMAP_AREA_START 0x00000000#define MMAP_AREA_END 0xa8000000TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];int nb_tbs;/* any access to the tbs or the page table must use this lock */spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];uint8_t *code_gen_ptr;#endif /* !CONFIG_DM */uint64_t phys_ram_size;extern uint64_t ram_size;int phys_ram_fd;uint8_t *phys_ram_base;uint8_t *phys_ram_dirty;CPUState *first_cpu;/* current CPU in the current thread. It is only valid inside cpu_exec() */CPUState *cpu_single_env; typedef struct PageDesc { /* list of TBs intersecting this ram page */ TranslationBlock *first_tb; /* in order to optimize self modifying code, we count the number of lookups we do to a given page to use a bitmap */ unsigned int code_write_count; uint8_t *code_bitmap;#if defined(CONFIG_USER_ONLY) unsigned long flags;#endif} PageDesc;typedef struct PhysPageDesc { /* offset in host memory of the page + io_index in the low 12 bits */ unsigned long phys_offset;} PhysPageDesc;typedef struct VirtPageDesc { /* physical address of code page. It is valid only if 'valid_tag' matches 'virt_valid_tag' */ target_ulong phys_addr; unsigned int valid_tag;#if !defined(CONFIG_SOFTMMU) /* original page access rights. It is valid only if 'valid_tag' matches 'virt_valid_tag' */ unsigned int prot;#endif} VirtPageDesc;#define L2_BITS 10#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)#define L1_SIZE (1 << L1_BITS)#define L2_SIZE (1 << L2_BITS)unsigned long qemu_real_host_page_size;unsigned long qemu_host_page_bits;unsigned long qemu_host_page_size;unsigned long qemu_host_page_mask;/* io memory support */CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];void *io_mem_opaque[IO_MEM_NB_ENTRIES];static int io_mem_nb = 1;/* log support */FILE *logfile;int loglevel;void cpu_exec_init(CPUState *env){ CPUState **penv; int cpu_index; env->next_cpu = NULL; penv = &first_cpu; cpu_index = 0; while (*penv != NULL) { penv = (CPUState **)&(*penv)->next_cpu; cpu_index++; } env->cpu_index = cpu_index; *penv = env; /* alloc dirty bits array */ phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);}/* enable or disable low levels log */void cpu_set_log(int log_flags){ loglevel = log_flags; if (!logfile) logfile = stderr;}void cpu_set_log_filename(const char *filename){ logfile = fopen(filename, "w"); if (!logfile) { perror(filename); _exit(1); }#if !defined(CONFIG_SOFTMMU) /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ { static uint8_t logfile_buf[4096]; setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); }#else setvbuf(logfile, NULL, _IOLBF, 0);#endif dup2(fileno(logfile), 1); dup2(fileno(logfile), 2);}/* mask must never be zero, except for A20 change call */void cpu_interrupt(CPUState *env, int mask){ env->interrupt_request |= mask;}void cpu_reset_interrupt(CPUState *env, int mask){ env->interrupt_request &= ~mask;}CPULogItem cpu_log_items[] = { { CPU_LOG_TB_OUT_ASM, "out_asm", "show generated host assembly code for each compiled TB" }, { CPU_LOG_TB_IN_ASM, "in_asm", "show target assembly code for each compiled TB" }, { CPU_LOG_TB_OP, "op", "show micro ops for each compiled TB (only usable if 'in_asm' used)" },#ifdef TARGET_I386 { CPU_LOG_TB_OP_OPT, "op_opt", "show micro ops after optimization for each compiled TB" },#endif { CPU_LOG_INT, "int", "show interrupts/exceptions in short format" }, { CPU_LOG_EXEC, "exec", "show trace before each executed TB (lots of logs)" }, { CPU_LOG_TB_CPU, "cpu", "show CPU state before bloc translation" },#ifdef TARGET_I386 { CPU_LOG_PCALL, "pcall", "show protected mode far calls/returns/exceptions" },#endif#ifdef DEBUG_IOPORT { CPU_LOG_IOPORT, "ioport", "show all i/o ports accesses" },#endif { 0, NULL, NULL },};static int cmp1(const char *s1, int n, const char *s2){ if (strlen(s2) != n) return 0; return memcmp(s1, s2, n) == 0;} /* takes a comma separated list of log masks. Return 0 if error. */int cpu_str_to_log_mask(const char *str){ CPULogItem *item; int mask; const char *p, *p1; p = str; mask = 0; for(;;) { p1 = strchr(p, ','); if (!p1) p1 = p + strlen(p); if(cmp1(p,p1-p,"all")) { for(item = cpu_log_items; item->mask != 0; item++) { mask |= item->mask; } } else { for(item = cpu_log_items; item->mask != 0; item++) { if (cmp1(p, p1 - p, item->name)) goto found; } return 0; } found: mask |= item->mask; if (*p1 != ',') break; p = p1 + 1; } return mask;}void cpu_abort(CPUState *env, const char *fmt, ...){ va_list ap; va_start(ap, fmt); fprintf(stderr, "qemu: fatal: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); abort();}/* XXX: Simple implementation. Fix later */#define MAX_MMIO 32struct mmio_space { target_phys_addr_t start; unsigned long size; unsigned long io_index;} mmio[MAX_MMIO];unsigned long mmio_cnt;/* register physical memory. 'size' must be a multiple of the target page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an io memory page */void cpu_register_physical_memory(target_phys_addr_t start_addr, unsigned long size, unsigned long phys_offset){ int i; for (i = 0; i < mmio_cnt; i++) { if(mmio[i].start == start_addr) { mmio[i].io_index = phys_offset; mmio[i].size = size; return; } } if (mmio_cnt == MAX_MMIO) { fprintf(logfile, "too many mmio regions\n"); exit(-1); } mmio[mmio_cnt].io_index = phys_offset; mmio[mmio_cnt].start = start_addr; mmio[mmio_cnt++].size = size;}/* mem_read and mem_write are arrays of functions containing the function to access byte (index 0), word (index 1) and dword (index 2). All functions must be supplied. If io_index is non zero, the corresponding io zone is modified. If it is zero, a new io zone is allocated. The return value can be used with cpu_register_physical_memory(). (-1) is returned if error. */int cpu_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, void *opaque){ int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -