VirtualBox

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

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

*: rebrand Sun (L)GPL disclaimers

  • Property svn:eol-style set to native
File size: 15.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/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 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);
114#ifndef VBOX
115static inline int tlb_set_page(CPUState *env1, target_ulong vaddr,
116 target_phys_addr_t paddr, int prot,
117 int mmu_idx, int is_softmmu)
118#else
119DECLINLINE(int) tlb_set_page(CPUState *env1, target_ulong vaddr,
120 target_phys_addr_t paddr, int prot,
121 int mmu_idx, int is_softmmu)
122#endif
123{
124 if (prot & PAGE_READ)
125 prot |= PAGE_EXEC;
126 return tlb_set_page_exec(env1, vaddr, paddr, prot, mmu_idx, is_softmmu);
127}
128
129#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
130
131#define CODE_GEN_PHYS_HASH_BITS 15
132#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS)
133
134#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024)
135
136/* estimated block size for TB allocation */
137/* XXX: use a per code average code fragment size and modulate it
138 according to the host CPU */
139#if defined(CONFIG_SOFTMMU)
140#define CODE_GEN_AVG_BLOCK_SIZE 128
141#else
142#define CODE_GEN_AVG_BLOCK_SIZE 64
143#endif
144
145#if defined(__powerpc__) || defined(__x86_64__) || defined(__arm__)
146#define USE_DIRECT_JUMP
147#endif
148#if defined(__i386__) && !defined(_WIN32)
149#define USE_DIRECT_JUMP
150#endif
151
152#ifdef VBOX /* bird: not safe in next step because of threading & cpu_interrupt. */
153#undef USE_DIRECT_JUMP
154#endif /* VBOX */
155
156struct TranslationBlock {
157 target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
158 target_ulong cs_base; /* CS base for this block */
159 uint64_t flags; /* flags defining in which context the code was generated */
160 uint16_t size; /* size of target code for this block (1 <=
161 size <= TARGET_PAGE_SIZE) */
162 uint16_t cflags; /* compile flags */
163#define CF_COUNT_MASK 0x7fff
164#define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */
165
166#ifdef VBOX
167#define CF_RAW_MODE 0x0010 /* block was generated in raw mode */
168#endif
169
170 uint8_t *tc_ptr; /* pointer to the translated code */
171 /* next matching tb for physical address. */
172 struct TranslationBlock *phys_hash_next;
173 /* first and second physical page containing code. The lower bit
174 of the pointer tells the index in page_next[] */
175 struct TranslationBlock *page_next[2];
176 target_ulong page_addr[2];
177
178 /* the following data are used to directly call another TB from
179 the code of this one. */
180 uint16_t tb_next_offset[2]; /* offset of original jump target */
181#ifdef USE_DIRECT_JUMP
182 uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
183#else
184 unsigned long tb_next[2]; /* address of jump generated code */
185#endif
186 /* list of TBs jumping to this one. This is a circular list using
187 the two least significant bits of the pointers to tell what is
188 the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
189 jmp_first */
190 struct TranslationBlock *jmp_next[2];
191 struct TranslationBlock *jmp_first;
192 uint32_t icount;
193};
194
195#ifndef VBOX
196static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
197#else
198DECLINLINE(unsigned int) tb_jmp_cache_hash_page(target_ulong pc)
199#endif
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}
205
206#ifndef VBOX
207static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
208#else
209DECLINLINE(unsigned int) tb_jmp_cache_hash_func(target_ulong pc)
210#endif
211
212{
213 target_ulong tmp;
214 tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
215 return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) |
216 (tmp & TB_JMP_ADDR_MASK));
217}
218
219#ifndef VBOX
220static inline unsigned int tb_phys_hash_func(unsigned long pc)
221#else
222DECLINLINE(unsigned int) tb_phys_hash_func(unsigned long pc)
223#endif
224{
225 return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
226}
227
228TranslationBlock *tb_alloc(target_ulong pc);
229void tb_free(TranslationBlock *tb);
230void tb_flush(CPUState *env);
231void tb_link_phys(TranslationBlock *tb,
232 target_ulong phys_pc, target_ulong phys_page2);
233void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr);
234
235extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
236
237extern uint8_t *code_gen_ptr;
238extern int code_gen_max_blocks;
239
240#if defined(USE_DIRECT_JUMP)
241
242#if defined(__powerpc__)
243static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
244{
245 uint32_t val, *ptr;
246
247 /* patch the branch destination */
248 ptr = (uint32_t *)jmp_addr;
249 val = *ptr;
250 val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
251 *ptr = val;
252 /* flush icache */
253 asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
254 asm volatile ("sync" : : : "memory");
255 asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
256 asm volatile ("sync" : : : "memory");
257 asm volatile ("isync" : : : "memory");
258}
259#elif defined(__i386__)
260static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
261{
262 /* patch the branch destination */
263 *(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
264 /* no need to flush icache explicitely */
265}
266#endif
267
268static inline void tb_set_jmp_target(TranslationBlock *tb,
269 int n, unsigned long addr)
270{
271 unsigned long offset;
272
273 offset = tb->tb_jmp_offset[n];
274 tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
275 offset = tb->tb_jmp_offset[n + 2];
276 if (offset != 0xffff)
277 tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
278}
279
280#else
281
282/* set the jump target */
283#ifndef VBOX
284static inline void tb_set_jmp_target(TranslationBlock *tb,
285 int n, unsigned long addr)
286#else
287DECLINLINE(void) tb_set_jmp_target(TranslationBlock *tb,
288 int n, unsigned long addr)
289#endif
290{
291 tb->tb_next[n] = addr;
292}
293
294#endif
295
296#ifndef VBOX
297static inline void tb_add_jump(TranslationBlock *tb, int n,
298 TranslationBlock *tb_next)
299#else
300DECLINLINE(void) tb_add_jump(TranslationBlock *tb, int n,
301 TranslationBlock *tb_next)
302#endif
303{
304 /* NOTE: this test is only needed for thread safety */
305 if (!tb->jmp_next[n]) {
306 /* patch the native jump address */
307 tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
308
309 /* add in TB jmp circular list */
310 tb->jmp_next[n] = tb_next->jmp_first;
311 tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
312 }
313}
314
315TranslationBlock *tb_find_pc(unsigned long pc_ptr);
316
317#ifndef offsetof
318#define offsetof(type, field) ((size_t) &((type *)0)->field)
319#endif
320
321#if defined(_WIN32)
322#define ASM_DATA_SECTION ".section \".data\"\n"
323#define ASM_PREVIOUS_SECTION ".section .text\n"
324#elif defined(__APPLE__)
325#define ASM_DATA_SECTION ".data\n"
326#define ASM_PREVIOUS_SECTION ".text\n"
327#else
328#define ASM_DATA_SECTION ".section \".data\"\n"
329#define ASM_PREVIOUS_SECTION ".previous\n"
330#endif
331
332#define ASM_OP_LABEL_NAME(n, opname) \
333 ASM_NAME(__op_label) #n "." ASM_NAME(opname)
334
335extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
336extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
337extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
338
339#include "qemu-lock.h"
340
341extern spinlock_t tb_lock;
342
343extern int tb_invalidated_flag;
344
345#if !defined(CONFIG_USER_ONLY)
346
347void tlb_fill(target_ulong addr, int is_write, int mmu_idx,
348 void *retaddr);
349
350#include "softmmu_defs.h"
351
352#define ACCESS_TYPE (NB_MMU_MODES + 1)
353#define MEMSUFFIX _code
354#define env cpu_single_env
355
356#define DATA_SIZE 1
357#include "softmmu_header.h"
358
359#define DATA_SIZE 2
360#include "softmmu_header.h"
361
362#define DATA_SIZE 4
363#include "softmmu_header.h"
364
365#define DATA_SIZE 8
366#include "softmmu_header.h"
367
368#undef ACCESS_TYPE
369#undef MEMSUFFIX
370#undef env
371
372#endif
373
374#if defined(CONFIG_USER_ONLY)
375static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
376{
377 return addr;
378}
379#else
380# ifdef VBOX
381target_ulong remR3PhysGetPhysicalAddressCode(CPUState *env, target_ulong addr, CPUTLBEntry *pTLBEntry, target_phys_addr_t ioTLBEntry);
382# endif
383/* NOTE: this function can trigger an exception */
384/* NOTE2: the returned address is not exactly the physical address: it
385 is the offset relative to phys_ram_base */
386#ifndef VBOX
387static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
388#else
389DECLINLINE(target_ulong) get_phys_addr_code(CPUState *env1, target_ulong addr)
390#endif
391{
392 int mmu_idx, page_index, pd;
393
394 page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
395 mmu_idx = cpu_mmu_index(env1);
396 if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
397 (addr & TARGET_PAGE_MASK))) {
398 ldub_code(addr);
399 }
400 pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
401 if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
402# ifdef VBOX
403 /* deal with non-MMIO access handlers. */
404 return remR3PhysGetPhysicalAddressCode(env1, addr,
405 &env1->tlb_table[mmu_idx][page_index],
406 env1->iotlb[mmu_idx][page_index]);
407# elif defined(TARGET_SPARC) || defined(TARGET_MIPS)
408 do_unassigned_access(addr, 0, 1, 0, 4);
409#else
410 cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
411#endif
412 }
413
414# if defined(VBOX) && defined(REM_PHYS_ADDR_IN_TLB)
415 return addr + env1->tlb_table[mmu_idx][page_index].addend;
416# elif defined(VBOX)
417 Assert(env1->phys_addends[mmu_idx][page_index] != -1);
418 return addr + env1->phys_addends[mmu_idx][page_index];
419# else
420 return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base;
421# endif
422}
423
424
425/* Deterministic execution requires that IO only be performed on the last
426 instruction of a TB so that interrupts take effect immediately. */
427#ifndef VBOX
428static inline int can_do_io(CPUState *env)
429#else
430DECLINLINE(int) can_do_io(CPUState *env)
431#endif
432{
433 if (!use_icount)
434 return 1;
435
436 /* If not executing code then assume we are ok. */
437 if (!env->current_tb)
438 return 1;
439
440 return env->can_do_io != 0;
441}
442#endif
443
444
445#ifdef USE_KQEMU
446#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
447
448int kqemu_init(CPUState *env);
449int kqemu_cpu_exec(CPUState *env);
450void kqemu_flush_page(CPUState *env, target_ulong addr);
451void kqemu_flush(CPUState *env, int global);
452void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr);
453void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr);
454void kqemu_cpu_interrupt(CPUState *env);
455void kqemu_record_dump(void);
456
457static inline int kqemu_is_ok(CPUState *env)
458{
459 return(env->kqemu_enabled &&
460 (env->cr[0] & CR0_PE_MASK) &&
461 !(env->hflags & HF_INHIBIT_IRQ_MASK) &&
462 (env->eflags & IF_MASK) &&
463 !(env->eflags & VM_MASK) &&
464 (env->kqemu_enabled == 2 ||
465 ((env->hflags & HF_CPL_MASK) == 3 &&
466 (env->eflags & IOPL_MASK) != IOPL_MASK)));
467}
468
469#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