VirtualBox

source: vbox/trunk/src/recompiler_new/exec-all.h@ 13337

Last change on this file since 13337 was 13337, checked in by vboxsync, 16 years ago

more recompiler work

  • Property svn:eol-style set to native
File size: 14.8 KB
Line 
1/*
2 * internal execution defines for qemu
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
23 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
24 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
25 * a choice of LGPL license versions is made available with the language indicating
26 * that LGPLv2 or any later version may be used, or where a choice of which version
27 * of the LGPL is applied is otherwise unspecified.
28 */
29
30/* allow to see translation results - the slowdown should be negligible, so we leave it */
31#ifndef VBOX
32#define DEBUG_DISAS
33#endif
34
35#ifdef VBOX
36# include <VBox/tm.h>
37# include <VBox/pgm.h> /* PGM_DYNAMIC_RAM_ALLOC */
38# ifndef LOG_GROUP
39# define LOG_GROUP LOG_GROUP_REM
40# endif
41# include <VBox/log.h>
42# include "REMInternal.h"
43# include <VBox/vm.h>
44#endif /* VBOX */
45
46/* is_jmp field values */
47#define DISAS_NEXT 0 /* next instruction can be analyzed */
48#define DISAS_JUMP 1 /* only pc was modified dynamically */
49#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
50#define DISAS_TB_JUMP 3 /* only pc was modified statically */
51
52typedef struct TranslationBlock TranslationBlock;
53
54/* XXX: make safe guess about sizes */
55#define MAX_OP_PER_INSTR 64
56/* A Call op needs up to 6 + 2N parameters (N = number of arguments). */
57#define MAX_OPC_PARAM 10
58#define OPC_BUF_SIZE 512
59#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
60
61/* Maximum size a TCG op can expand to. This is complicated because a
62 single op may require several host instructions and regirster reloads.
63 For now take a wild guess at 128 bytes, which should allow at least
64 a couple of fixup instructions per argument. */
65#define TCG_MAX_OP_SIZE 128
66
67#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM)
68
69extern target_ulong gen_opc_pc[OPC_BUF_SIZE];
70extern target_ulong gen_opc_npc[OPC_BUF_SIZE];
71extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
72extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
73extern uint16_t gen_opc_icount[OPC_BUF_SIZE];
74extern target_ulong gen_opc_jump_pc[2];
75extern uint32_t gen_opc_hflags[OPC_BUF_SIZE];
76
77typedef void (GenOpFunc)(void);
78typedef void (GenOpFunc1)(long);
79typedef void (GenOpFunc2)(long, long);
80typedef void (GenOpFunc3)(long, long, long);
81
82#include "qemu-log.h"
83
84void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
85void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
86void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
87 unsigned long searched_pc, int pc_pos, void *puc);
88
89unsigned long code_gen_max_block_size(void);
90void cpu_gen_init(void);
91int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
92 int *gen_code_size_ptr);
93int cpu_restore_state(struct TranslationBlock *tb,
94 CPUState *env, unsigned long searched_pc,
95 void *puc);
96int cpu_restore_state_copy(struct TranslationBlock *tb,
97 CPUState *env, unsigned long searched_pc,
98 void *puc);
99void cpu_resume_from_signal(CPUState *env1, void *puc);
100void cpu_io_recompile(CPUState *env, void *retaddr);
101TranslationBlock *tb_gen_code(CPUState *env,
102 target_ulong pc, target_ulong cs_base, int flags,
103 int cflags);
104void cpu_exec_init(CPUState *env);
105int page_unprotect(target_ulong address, unsigned long pc, void *puc);
106void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
107 int is_cpu_write_access);
108void tb_invalidate_page_range(target_ulong start, target_ulong end);
109void tlb_flush_page(CPUState *env, target_ulong addr);
110void tlb_flush(CPUState *env, int flush_global);
111int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
112 target_phys_addr_t paddr, int prot,
113 int mmu_idx, int is_softmmu);
114static inline int tlb_set_page(CPUState *env1, target_ulong vaddr,
115 target_phys_addr_t paddr, int prot,
116 int mmu_idx, int is_softmmu)
117{
118 if (prot & PAGE_READ)
119 prot |= PAGE_EXEC;
120 return tlb_set_page_exec(env1, vaddr, paddr, prot, mmu_idx, is_softmmu);
121}
122
123#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
124
125#define CODE_GEN_PHYS_HASH_BITS 15
126#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS)
127
128#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024)
129
130/* estimated block size for TB allocation */
131/* XXX: use a per code average code fragment size and modulate it
132 according to the host CPU */
133#if defined(CONFIG_SOFTMMU)
134#define CODE_GEN_AVG_BLOCK_SIZE 128
135#else
136#define CODE_GEN_AVG_BLOCK_SIZE 64
137#endif
138
139#if defined(__powerpc__) || defined(__x86_64__) || defined(__arm__)
140#define USE_DIRECT_JUMP
141#endif
142#if defined(__i386__) && !defined(_WIN32)
143#define USE_DIRECT_JUMP
144#endif
145
146#ifdef VBOX /* bird: not safe in next step because of threading & cpu_interrupt. */
147#undef USE_DIRECT_JUMP
148#endif /* VBOX */
149
150struct TranslationBlock {
151 target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
152 target_ulong cs_base; /* CS base for this block */
153 uint64_t flags; /* flags defining in which context the code was generated */
154 uint16_t size; /* size of target code for this block (1 <=
155 size <= TARGET_PAGE_SIZE) */
156 uint16_t cflags; /* compile flags */
157#define CF_COUNT_MASK 0x7fff
158#define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */
159
160#ifdef VBOX
161#define CF_RAW_MODE 0x0010 /* block was generated in raw mode */
162#endif
163
164 uint8_t *tc_ptr; /* pointer to the translated code */
165 /* next matching tb for physical address. */
166 struct TranslationBlock *phys_hash_next;
167 /* first and second physical page containing code. The lower bit
168 of the pointer tells the index in page_next[] */
169 struct TranslationBlock *page_next[2];
170 target_ulong page_addr[2];
171
172 /* the following data are used to directly call another TB from
173 the code of this one. */
174 uint16_t tb_next_offset[2]; /* offset of original jump target */
175#ifdef USE_DIRECT_JUMP
176 uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
177#else
178# if defined(VBOX) && defined(RT_OS_DARWIN) && defined(RT_ARCH_AMD64)
179# error "First 4GB aren't reachable. jmp dword [tb_next] wont work."
180# endif
181 unsigned long tb_next[2]; /* address of jump generated code */
182#endif
183 /* list of TBs jumping to this one. This is a circular list using
184 the two least significant bits of the pointers to tell what is
185 the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
186 jmp_first */
187 struct TranslationBlock *jmp_next[2];
188 struct TranslationBlock *jmp_first;
189 uint32_t icount;
190};
191
192static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
193{
194 target_ulong tmp;
195 tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
196 return (tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK;
197}
198
199static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
200{
201 target_ulong tmp;
202 tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
203 return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) |
204 (tmp & TB_JMP_ADDR_MASK));
205}
206
207static inline unsigned int tb_phys_hash_func(unsigned long pc)
208{
209 return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
210}
211
212TranslationBlock *tb_alloc(target_ulong pc);
213void tb_free(TranslationBlock *tb);
214void tb_flush(CPUState *env);
215void tb_link_phys(TranslationBlock *tb,
216 target_ulong phys_pc, target_ulong phys_page2);
217void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr);
218
219extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
220
221extern uint8_t *code_gen_ptr;
222extern int code_gen_max_blocks;
223
224#if defined(USE_DIRECT_JUMP)
225
226#if defined(__powerpc__)
227static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
228{
229 uint32_t val, *ptr;
230
231 /* patch the branch destination */
232 ptr = (uint32_t *)jmp_addr;
233 val = *ptr;
234 val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
235 *ptr = val;
236 /* flush icache */
237 asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
238 asm volatile ("sync" : : : "memory");
239 asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
240 asm volatile ("sync" : : : "memory");
241 asm volatile ("isync" : : : "memory");
242}
243#elif defined(__i386__)
244static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
245{
246 /* patch the branch destination */
247 *(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
248 /* no need to flush icache explicitely */
249}
250#endif
251
252static inline void tb_set_jmp_target(TranslationBlock *tb,
253 int n, unsigned long addr)
254{
255 unsigned long offset;
256
257 offset = tb->tb_jmp_offset[n];
258 tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
259 offset = tb->tb_jmp_offset[n + 2];
260 if (offset != 0xffff)
261 tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
262}
263
264#else
265
266/* set the jump target */
267static inline void tb_set_jmp_target(TranslationBlock *tb,
268 int n, unsigned long addr)
269{
270 tb->tb_next[n] = addr;
271}
272
273#endif
274
275static inline void tb_add_jump(TranslationBlock *tb, int n,
276 TranslationBlock *tb_next)
277{
278 /* NOTE: this test is only needed for thread safety */
279 if (!tb->jmp_next[n]) {
280 /* patch the native jump address */
281 tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
282
283 /* add in TB jmp circular list */
284 tb->jmp_next[n] = tb_next->jmp_first;
285 tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
286 }
287}
288
289TranslationBlock *tb_find_pc(unsigned long pc_ptr);
290
291#ifndef offsetof
292#define offsetof(type, field) ((size_t) &((type *)0)->field)
293#endif
294
295#if defined(_WIN32)
296#define ASM_DATA_SECTION ".section \".data\"\n"
297#define ASM_PREVIOUS_SECTION ".section .text\n"
298#elif defined(__APPLE__)
299#define ASM_DATA_SECTION ".data\n"
300#define ASM_PREVIOUS_SECTION ".text\n"
301#else
302#define ASM_DATA_SECTION ".section \".data\"\n"
303#define ASM_PREVIOUS_SECTION ".previous\n"
304#endif
305
306#define ASM_OP_LABEL_NAME(n, opname) \
307 ASM_NAME(__op_label) #n "." ASM_NAME(opname)
308
309extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
310extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
311extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
312
313#include "qemu-lock.h"
314
315extern spinlock_t tb_lock;
316
317extern int tb_invalidated_flag;
318
319#if !defined(CONFIG_USER_ONLY)
320
321void tlb_fill(target_ulong addr, int is_write, int is_user,
322 void *retaddr);
323
324#include "softmmu_defs.h"
325
326#define ACCESS_TYPE (NB_MMU_MODES + 1)
327#define MEMSUFFIX _code
328#define env cpu_single_env
329
330#define DATA_SIZE 1
331#include "softmmu_header.h"
332
333#define DATA_SIZE 2
334#include "softmmu_header.h"
335
336#define DATA_SIZE 4
337#include "softmmu_header.h"
338
339#define DATA_SIZE 8
340#include "softmmu_header.h"
341
342#undef ACCESS_TYPE
343#undef MEMSUFFIX
344#undef env
345
346#endif
347
348#if defined(CONFIG_USER_ONLY)
349static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
350{
351 return addr;
352}
353#else
354# ifdef VBOX
355target_ulong remR3PhysGetPhysicalAddressCode(CPUState *env, target_ulong addr, CPUTLBEntry *pTLBEntry);
356# if !defined(REM_PHYS_ADDR_IN_TLB)
357target_ulong remR3HCVirt2GCPhys(void *env, void *addr);
358# endif
359# endif
360/* NOTE: this function can trigger an exception */
361/* NOTE2: the returned address is not exactly the physical address: it
362 is the offset relative to phys_ram_base */
363static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
364{
365 int is_user, index, pd;
366
367 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
368#if defined(TARGET_I386)
369 is_user = ((env->hflags & HF_CPL_MASK) == 3);
370#elif defined (TARGET_PPC)
371 is_user = msr_pr;
372#elif defined (TARGET_MIPS)
373 is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
374#elif defined (TARGET_SPARC)
375 is_user = (env->psrs == 0);
376#elif defined (TARGET_ARM)
377 is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR);
378#elif defined (TARGET_SH4)
379 is_user = ((env->sr & SR_MD) == 0);
380#else
381#error unimplemented CPU
382#endif
383 if (__builtin_expect(env->tlb_table[is_user][index].addr_code !=
384 (addr & TARGET_PAGE_MASK), 0)) {
385 ldub_code(addr);
386 }
387 pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
388 if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
389# ifdef VBOX
390 /* deal with non-MMIO access handlers. */
391 return remR3PhysGetPhysicalAddressCode(env, addr, &env->tlb_table[is_user][index]);
392# else
393 cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr);
394# endif
395 }
396# if defined(VBOX) && defined(REM_PHYS_ADDR_IN_TLB)
397 return addr + env->tlb_table[is_user][index].addend;
398# elif defined(VBOX)
399 return remR3HCVirt2GCPhys(env, (void *)(addr + env->tlb_table[is_user][index].addend));
400# else
401 return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base;
402# endif
403}
404
405
406/* Deterministic execution requires that IO only be performed on the last
407 instruction of a TB so that interrupts take effect immediately. */
408static inline int can_do_io(CPUState *env)
409{
410 if (!use_icount)
411 return 1;
412
413 /* If not executing code then assume we are ok. */
414 if (!env->current_tb)
415 return 1;
416
417 return env->can_do_io != 0;
418}
419#endif
420
421
422#ifdef USE_KQEMU
423#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
424
425int kqemu_init(CPUState *env);
426int kqemu_cpu_exec(CPUState *env);
427void kqemu_flush_page(CPUState *env, target_ulong addr);
428void kqemu_flush(CPUState *env, int global);
429void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr);
430void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr);
431void kqemu_cpu_interrupt(CPUState *env);
432void kqemu_record_dump(void);
433
434static inline int kqemu_is_ok(CPUState *env)
435{
436 return(env->kqemu_enabled &&
437 (env->cr[0] & CR0_PE_MASK) &&
438 !(env->hflags & HF_INHIBIT_IRQ_MASK) &&
439 (env->eflags & IF_MASK) &&
440 !(env->eflags & VM_MASK) &&
441 (env->kqemu_enabled == 2 ||
442 ((env->hflags & HF_CPL_MASK) == 3 &&
443 (env->eflags & IOPL_MASK) != IOPL_MASK)));
444}
445
446#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette