VirtualBox

source: vbox/trunk/src/recompiler/exec-all.h@ 36125

Last change on this file since 36125 was 36125, checked in by vboxsync, 14 years ago

recompiler: Removing traces of attempts at making the recompiler compile with the microsoft compiler. (untested)

  • Property svn:eol-style set to native
File size: 14.4 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 * Oracle 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, Oracle 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/vmm/tm.h>
37# include <VBox/vmm/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/vmm/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 register 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 unsigned long tb_next[2]; /* address of jump generated code */
179#endif
180 /* list of TBs jumping to this one. This is a circular list using
181 the two least significant bits of the pointers to tell what is
182 the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
183 jmp_first */
184 struct TranslationBlock *jmp_next[2];
185 struct TranslationBlock *jmp_first;
186 uint32_t icount;
187};
188
189static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
190{
191 target_ulong tmp;
192 tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
193 return (tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK;
194}
195
196static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
197{
198 target_ulong tmp;
199 tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
200 return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) |
201 (tmp & TB_JMP_ADDR_MASK));
202}
203
204static inline unsigned int tb_phys_hash_func(unsigned long pc)
205{
206 return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
207}
208
209TranslationBlock *tb_alloc(target_ulong pc);
210void tb_free(TranslationBlock *tb);
211void tb_flush(CPUState *env);
212void tb_link_phys(TranslationBlock *tb,
213 target_ulong phys_pc, target_ulong phys_page2);
214void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr);
215
216extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
217
218extern uint8_t *code_gen_ptr;
219extern int code_gen_max_blocks;
220
221#if defined(USE_DIRECT_JUMP)
222
223#if defined(__powerpc__)
224static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
225{
226 uint32_t val, *ptr;
227
228 /* patch the branch destination */
229 ptr = (uint32_t *)jmp_addr;
230 val = *ptr;
231 val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
232 *ptr = val;
233 /* flush icache */
234 asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
235 asm volatile ("sync" : : : "memory");
236 asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
237 asm volatile ("sync" : : : "memory");
238 asm volatile ("isync" : : : "memory");
239}
240#elif defined(__i386__)
241static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
242{
243 /* patch the branch destination */
244 *(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
245 /* no need to flush icache explicitely */
246}
247#endif
248
249static inline void tb_set_jmp_target(TranslationBlock *tb,
250 int n, unsigned long addr)
251{
252 unsigned long offset;
253
254 offset = tb->tb_jmp_offset[n];
255 tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
256 offset = tb->tb_jmp_offset[n + 2];
257 if (offset != 0xffff)
258 tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
259}
260
261#else
262
263/* set the jump target */
264static inline void tb_set_jmp_target(TranslationBlock *tb,
265 int n, unsigned long addr)
266{
267 tb->tb_next[n] = addr;
268}
269
270#endif
271
272static inline void tb_add_jump(TranslationBlock *tb, int n,
273 TranslationBlock *tb_next)
274{
275 /* NOTE: this test is only needed for thread safety */
276 if (!tb->jmp_next[n]) {
277 /* patch the native jump address */
278 tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
279
280 /* add in TB jmp circular list */
281 tb->jmp_next[n] = tb_next->jmp_first;
282 tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
283 }
284}
285
286TranslationBlock *tb_find_pc(unsigned long pc_ptr);
287
288#ifndef offsetof
289#define offsetof(type, field) ((size_t) &((type *)0)->field)
290#endif
291
292#if defined(_WIN32)
293#define ASM_DATA_SECTION ".section \".data\"\n"
294#define ASM_PREVIOUS_SECTION ".section .text\n"
295#elif defined(__APPLE__)
296#define ASM_DATA_SECTION ".data\n"
297#define ASM_PREVIOUS_SECTION ".text\n"
298#else
299#define ASM_DATA_SECTION ".section \".data\"\n"
300#define ASM_PREVIOUS_SECTION ".previous\n"
301#endif
302
303#define ASM_OP_LABEL_NAME(n, opname) \
304 ASM_NAME(__op_label) #n "." ASM_NAME(opname)
305
306extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
307extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
308extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
309
310#include "qemu-lock.h"
311
312extern spinlock_t tb_lock;
313
314extern int tb_invalidated_flag;
315
316#if !defined(CONFIG_USER_ONLY)
317
318void tlb_fill(target_ulong addr, int is_write, int mmu_idx,
319 void *retaddr);
320
321#include "softmmu_defs.h"
322
323#define ACCESS_TYPE (NB_MMU_MODES + 1)
324#define MEMSUFFIX _code
325#define env cpu_single_env
326
327#define DATA_SIZE 1
328#include "softmmu_header.h"
329
330#define DATA_SIZE 2
331#include "softmmu_header.h"
332
333#define DATA_SIZE 4
334#include "softmmu_header.h"
335
336#define DATA_SIZE 8
337#include "softmmu_header.h"
338
339#undef ACCESS_TYPE
340#undef MEMSUFFIX
341#undef env
342
343#endif
344
345#if defined(CONFIG_USER_ONLY)
346static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
347{
348 return addr;
349}
350#else
351# ifdef VBOX
352target_ulong remR3PhysGetPhysicalAddressCode(CPUState *env, target_ulong addr, CPUTLBEntry *pTLBEntry, target_phys_addr_t ioTLBEntry);
353# endif
354/* NOTE: this function can trigger an exception */
355/* NOTE2: the returned address is not exactly the physical address: it
356 is the offset relative to phys_ram_base */
357static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
358{
359 int mmu_idx, page_index, pd;
360
361 page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
362 mmu_idx = cpu_mmu_index(env1);
363 if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
364 (addr & TARGET_PAGE_MASK))) {
365 ldub_code(addr);
366 }
367 pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
368 if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
369# ifdef VBOX
370 /* deal with non-MMIO access handlers. */
371 return remR3PhysGetPhysicalAddressCode(env1, addr,
372 &env1->tlb_table[mmu_idx][page_index],
373 env1->iotlb[mmu_idx][page_index]);
374# elif defined(TARGET_SPARC) || defined(TARGET_MIPS)
375 do_unassigned_access(addr, 0, 1, 0, 4);
376#else
377 cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
378#endif
379 }
380
381# if defined(VBOX) && defined(REM_PHYS_ADDR_IN_TLB)
382 return addr + env1->tlb_table[mmu_idx][page_index].addend;
383# elif defined(VBOX)
384 Assert(env1->phys_addends[mmu_idx][page_index] != -1);
385 return addr + env1->phys_addends[mmu_idx][page_index];
386# else
387 return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base;
388# endif
389}
390
391
392/* Deterministic execution requires that IO only be performed on the last
393 instruction of a TB so that interrupts take effect immediately. */
394static inline int can_do_io(CPUState *env)
395{
396 if (!use_icount)
397 return 1;
398
399 /* If not executing code then assume we are ok. */
400 if (!env->current_tb)
401 return 1;
402
403 return env->can_do_io != 0;
404}
405#endif
406
407
408#ifdef USE_KQEMU
409#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
410
411int kqemu_init(CPUState *env);
412int kqemu_cpu_exec(CPUState *env);
413void kqemu_flush_page(CPUState *env, target_ulong addr);
414void kqemu_flush(CPUState *env, int global);
415void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr);
416void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr);
417void kqemu_cpu_interrupt(CPUState *env);
418void kqemu_record_dump(void);
419
420static inline int kqemu_is_ok(CPUState *env)
421{
422 return(env->kqemu_enabled &&
423 (env->cr[0] & CR0_PE_MASK) &&
424 !(env->hflags & HF_INHIBIT_IRQ_MASK) &&
425 (env->eflags & IF_MASK) &&
426 !(env->eflags & VM_MASK) &&
427 (env->kqemu_enabled == 2 ||
428 ((env->hflags & HF_CPL_MASK) == 3 &&
429 (env->eflags & IOPL_MASK) != IOPL_MASK)));
430}
431
432#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