exec-all.h 15.0 KB
Newer Older
B
bellard 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * internal execution defines for qemu
 * 
 *  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
 */

B
bellard 已提交
21 22 23
/* allow to see translation results - the slowdown should be negligible, so we leave it */
#define DEBUG_DISAS

24 25 26 27 28 29 30 31 32 33 34
#ifndef glue
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s)	tostring(s)
#define tostring(s)	#s
#endif

#if GCC_MAJOR < 3
#define __builtin_expect(x, n) (x)
#endif

B
bellard 已提交
35 36 37 38 39 40
#ifdef __i386__
#define REGPARM(n) __attribute((regparm(n)))
#else
#define REGPARM(n)
#endif

B
bellard 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
/* is_jmp field values */
#define DISAS_NEXT    0 /* next instruction can be analyzed */
#define DISAS_JUMP    1 /* only pc was modified dynamically */
#define DISAS_UPDATE  2 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP 3 /* only pc was modified statically */

struct TranslationBlock;

/* XXX: make safe guess about sizes */
#define MAX_OP_PER_INSTR 32
#define OPC_BUF_SIZE 512
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)

#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)

extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
B
bellard 已提交
59
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
B
bellard 已提交
60 61
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];

B
bellard 已提交
62 63 64 65 66
typedef void (GenOpFunc)(void);
typedef void (GenOpFunc1)(long);
typedef void (GenOpFunc2)(long, long);
typedef void (GenOpFunc3)(long, long, long);
                    
B
bellard 已提交
67 68
#if defined(TARGET_I386)

69
void optimize_flags_init(void);
B
bellard 已提交
70

B
bellard 已提交
71 72 73 74 75
#endif

extern FILE *logfile;
extern int loglevel;

B
bellard 已提交
76 77
int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
B
bellard 已提交
78
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
B
bellard 已提交
79
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
B
bellard 已提交
80
                 int max_code_size, int *gen_code_size_ptr);
B
bellard 已提交
81 82
int cpu_restore_state(struct TranslationBlock *tb, 
                      CPUState *env, unsigned long searched_pc);
B
bellard 已提交
83
void cpu_exec_init(void);
B
bellard 已提交
84
int page_unprotect(unsigned long address);
85
void tb_invalidate_page_range(target_ulong start, target_ulong end);
86
void tlb_flush_page(CPUState *env, uint32_t addr);
B
bellard 已提交
87
void tlb_flush_page_write(CPUState *env, uint32_t addr);
88
void tlb_flush(CPUState *env, int flush_global);
89 90
int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, 
                 int is_user, int is_softmmu);
B
bellard 已提交
91 92 93 94 95 96 97

#define CODE_GEN_MAX_SIZE        65536
#define CODE_GEN_ALIGN           16 /* must be >= of the size of a icache line */

#define CODE_GEN_HASH_BITS     15
#define CODE_GEN_HASH_SIZE     (1 << CODE_GEN_HASH_BITS)

98 99 100
#define CODE_GEN_PHYS_HASH_BITS     15
#define CODE_GEN_PHYS_HASH_SIZE     (1 << CODE_GEN_PHYS_HASH_BITS)

B
bellard 已提交
101
/* maximum total translate dcode allocated */
102 103

/* NOTE: the translated code area cannot be too big because on some
B
bellard 已提交
104
   archs the range of "fast" function calls is limited. Here is a
105 106 107 108 109 110 111 112 113 114 115 116
   summary of the ranges:

   i386  : signed 32 bits
   arm   : signed 26 bits
   ppc   : signed 24 bits
   sparc : signed 32 bits
   alpha : signed 23 bits
*/

#if defined(__alpha__)
#define CODE_GEN_BUFFER_SIZE     (2 * 1024 * 1024)
#elif defined(__powerpc__)
B
bellard 已提交
117
#define CODE_GEN_BUFFER_SIZE     (6 * 1024 * 1024)
118 119 120 121
#else
#define CODE_GEN_BUFFER_SIZE     (8 * 1024 * 1024)
#endif

B
bellard 已提交
122 123
//#define CODE_GEN_BUFFER_SIZE     (128 * 1024)

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
/* estimated block size for TB allocation */
/* XXX: use a per code average code fragment size and modulate it
   according to the host CPU */
#if defined(CONFIG_SOFTMMU)
#define CODE_GEN_AVG_BLOCK_SIZE 128
#else
#define CODE_GEN_AVG_BLOCK_SIZE 64
#endif

#define CODE_GEN_MAX_BLOCKS    (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE)

#if defined(__powerpc__) 
#define USE_DIRECT_JUMP
#endif
#if defined(__i386__) 
B
bellard 已提交
139 140 141 142 143 144 145 146 147 148
#define USE_DIRECT_JUMP
#endif

typedef struct TranslationBlock {
    unsigned long pc;   /* simulated PC corresponding to this block (EIP + CS base) */
    unsigned long cs_base; /* CS base for this block */
    unsigned int flags; /* flags defining in which context the code was generated */
    uint16_t size;      /* size of target code for this block (1 <=
                           size <= TARGET_PAGE_SIZE) */
    uint8_t *tc_ptr;    /* pointer to the translated code */
149 150 151 152 153 154 155 156
    struct TranslationBlock *hash_next; /* next matching tb for virtual address */
    /* next matching tb for physical address. */
    struct TranslationBlock *phys_hash_next; 
    /* first and second physical page containing code. The lower bit
       of the pointer tells the index in page_next[] */
    struct TranslationBlock *page_next[2]; 
    target_ulong page_addr[2]; 

B
bellard 已提交
157 158 159 160
    /* the following data are used to directly call another TB from
       the code of this one. */
    uint16_t tb_next_offset[2]; /* offset of original jump target */
#ifdef USE_DIRECT_JUMP
161
    uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
B
bellard 已提交
162
#else
163
    uint32_t tb_next[2]; /* address of jump generated code */
B
bellard 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177
#endif
    /* list of TBs jumping to this one. This is a circular list using
       the two least significant bits of the pointers to tell what is
       the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
       jmp_first */
    struct TranslationBlock *jmp_next[2]; 
    struct TranslationBlock *jmp_first;
} TranslationBlock;

static inline unsigned int tb_hash_func(unsigned long pc)
{
    return pc & (CODE_GEN_HASH_SIZE - 1);
}

178 179 180 181 182
static inline unsigned int tb_phys_hash_func(unsigned long pc)
{
    return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
}

B
bellard 已提交
183
TranslationBlock *tb_alloc(unsigned long pc);
184
void tb_flush(CPUState *env);
B
bellard 已提交
185
void tb_link(TranslationBlock *tb);
186 187
void tb_link_phys(TranslationBlock *tb, 
                  target_ulong phys_pc, target_ulong phys_page2);
B
bellard 已提交
188 189

extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
190
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
B
bellard 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
extern uint8_t *code_gen_ptr;

/* find a translation block in the translation cache. If not found,
   return NULL and the pointer to the last element of the list in pptb */
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
                                        unsigned long pc, 
                                        unsigned long cs_base,
                                        unsigned int flags)
{
    TranslationBlock **ptb, *tb;
    unsigned int h;
 
    h = tb_hash_func(pc);
    ptb = &tb_hash[h];
    for(;;) {
        tb = *ptb;
        if (!tb)
            break;
        if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
            return tb;
        ptb = &tb->hash_next;
    }
    *pptb = ptb;
    return NULL;
}


220 221 222
#if defined(USE_DIRECT_JUMP)

#if defined(__powerpc__)
223
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
B
bellard 已提交
224 225 226 227
{
    uint32_t val, *ptr;

    /* patch the branch destination */
228
    ptr = (uint32_t *)jmp_addr;
B
bellard 已提交
229
    val = *ptr;
230
    val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
B
bellard 已提交
231 232 233 234 235 236 237 238
    *ptr = val;
    /* flush icache */
    asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
    asm volatile ("sync" : : : "memory");
    asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
    asm volatile ("sync" : : : "memory");
    asm volatile ("isync" : : : "memory");
}
239 240 241 242 243 244 245 246
#elif defined(__i386__)
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
{
    /* patch the branch destination */
    *(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
    /* no need to flush icache explicitely */
}
#endif
B
bellard 已提交
247

248 249 250 251 252 253 254 255 256 257 258 259
static inline void tb_set_jmp_target(TranslationBlock *tb, 
                                     int n, unsigned long addr)
{
    unsigned long offset;

    offset = tb->tb_jmp_offset[n];
    tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
    offset = tb->tb_jmp_offset[n + 2];
    if (offset != 0xffff)
        tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
}

B
bellard 已提交
260 261 262 263 264 265
#else

/* set the jump target */
static inline void tb_set_jmp_target(TranslationBlock *tb, 
                                     int n, unsigned long addr)
{
266
    tb->tb_next[n] = addr;
B
bellard 已提交
267 268 269 270 271 272 273
}

#endif

static inline void tb_add_jump(TranslationBlock *tb, int n, 
                               TranslationBlock *tb_next)
{
B
bellard 已提交
274 275 276 277 278 279 280 281 282
    /* NOTE: this test is only needed for thread safety */
    if (!tb->jmp_next[n]) {
        /* patch the native jump address */
        tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
        
        /* add in TB jmp circular list */
        tb->jmp_next[n] = tb_next->jmp_first;
        tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
    }
B
bellard 已提交
283 284
}

B
bellard 已提交
285 286
TranslationBlock *tb_find_pc(unsigned long pc_ptr);

B
bellard 已提交
287 288 289 290
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif

B
bellard 已提交
291 292
#if defined(__powerpc__)

293
/* we patch the jump instruction directly */
294
#define JUMP_TB(opname, tbparam, n, eip)\
B
bellard 已提交
295
do {\
296 297 298 299 300 301
    asm volatile (".section \".data\"\n"\
		  "__op_label" #n "." stringify(opname) ":\n"\
		  ".long 1f\n"\
		  ".previous\n"\
                  "b __op_jmp" #n "\n"\
		  "1:\n");\
B
bellard 已提交
302 303
    T0 = (long)(tbparam) + (n);\
    EIP = eip;\
B
bellard 已提交
304
    EXIT_TB();\
B
bellard 已提交
305 306
} while (0)

307 308
#define JUMP_TB2(opname, tbparam, n)\
do {\
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
    asm volatile ("b __op_jmp" #n "\n");\
} while (0)

#elif defined(__i386__) && defined(USE_DIRECT_JUMP)

/* we patch the jump instruction directly */
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
    asm volatile (".section \".data\"\n"\
		  "__op_label" #n "." stringify(opname) ":\n"\
		  ".long 1f\n"\
		  ".previous\n"\
                  "jmp __op_jmp" #n "\n"\
		  "1:\n");\
    T0 = (long)(tbparam) + (n);\
    EIP = eip;\
    EXIT_TB();\
} while (0)

#define JUMP_TB2(opname, tbparam, n)\
do {\
    asm volatile ("jmp __op_jmp" #n "\n");\
331 332
} while (0)

B
bellard 已提交
333 334 335 336
#else

/* jump to next block operations (more portable code, does not need
   cache flushing, but slower because of indirect jump) */
337
#define JUMP_TB(opname, tbparam, n, eip)\
B
bellard 已提交
338 339
do {\
    static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
B
bellard 已提交
340
    static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
B
bellard 已提交
341 342 343 344
    goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
label ## n:\
    T0 = (long)(tbparam) + (n);\
    EIP = eip;\
B
bellard 已提交
345
dummy_label ## n:\
B
bellard 已提交
346
    EXIT_TB();\
B
bellard 已提交
347 348
} while (0)

349 350 351
/* second jump to same destination 'n' */
#define JUMP_TB2(opname, tbparam, n)\
do {\
352
    goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\
353 354
} while (0)

B
bellard 已提交
355 356
#endif

357 358 359
extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];

B
bellard 已提交
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
#ifdef __powerpc__
static inline int testandset (int *p)
{
    int ret;
    __asm__ __volatile__ (
                          "0:    lwarx %0,0,%1 ;"
                          "      xor. %0,%3,%0;"
                          "      bne 1f;"
                          "      stwcx. %2,0,%1;"
                          "      bne- 0b;"
                          "1:    "
                          : "=&r" (ret)
                          : "r" (p), "r" (1), "r" (0)
                          : "cr0", "memory");
    return ret;
}
#endif

#ifdef __i386__
static inline int testandset (int *p)
{
    char ret;
    long int readval;
    
    __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
                          : "=q" (ret), "=m" (*p), "=a" (readval)
                          : "r" (1), "m" (*p), "a" (0)
                          : "memory");
    return ret;
}
#endif

#ifdef __s390__
static inline int testandset (int *p)
{
    int ret;

    __asm__ __volatile__ ("0: cs    %0,%1,0(%2)\n"
			  "   jl    0b"
			  : "=&d" (ret)
			  : "r" (1), "a" (p), "0" (*p) 
			  : "cc", "memory" );
    return ret;
}
#endif

#ifdef __alpha__
B
bellard 已提交
407
static inline int testandset (int *p)
B
bellard 已提交
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
{
    int ret;
    unsigned long one;

    __asm__ __volatile__ ("0:	mov 1,%2\n"
			  "	ldl_l %0,%1\n"
			  "	stl_c %2,%1\n"
			  "	beq %2,1f\n"
			  ".subsection 2\n"
			  "1:	br 0b\n"
			  ".previous"
			  : "=r" (ret), "=m" (*p), "=r" (one)
			  : "m" (*p));
    return ret;
}
#endif

#ifdef __sparc__
static inline int testandset (int *p)
{
	int ret;

	__asm__ __volatile__("ldstub	[%1], %0"
			     : "=r" (ret)
			     : "r" (p)
			     : "memory");

	return (ret ? 1 : 0);
}
#endif

B
bellard 已提交
439 440 441 442 443 444 445 446 447 448 449 450
#ifdef __arm__
static inline int testandset (int *spinlock)
{
    register unsigned int ret;
    __asm__ __volatile__("swp %0, %1, [%2]"
                         : "=r"(ret)
                         : "0"(1), "r"(spinlock));
    
    return ret;
}
#endif

B
bellard 已提交
451 452 453 454 455 456 457 458 459 460 461 462
#ifdef __mc68000
static inline int testandset (int *p)
{
    char ret;
    __asm__ __volatile__("tas %1; sne %0"
                         : "=r" (ret)
                         : "m" (p)
                         : "cc","memory");
    return ret == 0;
}
#endif

B
bellard 已提交
463 464 465 466
typedef int spinlock_t;

#define SPIN_LOCK_UNLOCKED 0

B
bellard 已提交
467
#if defined(CONFIG_USER_ONLY)
B
bellard 已提交
468 469 470 471 472 473 474 475 476 477 478 479 480 481
static inline void spin_lock(spinlock_t *lock)
{
    while (testandset(lock));
}

static inline void spin_unlock(spinlock_t *lock)
{
    *lock = 0;
}

static inline int spin_trylock(spinlock_t *lock)
{
    return !testandset(lock);
}
482 483 484 485 486 487 488 489 490 491 492 493 494 495
#else
static inline void spin_lock(spinlock_t *lock)
{
}

static inline void spin_unlock(spinlock_t *lock)
{
}

static inline int spin_trylock(spinlock_t *lock)
{
    return 1;
}
#endif
B
bellard 已提交
496 497 498

extern spinlock_t tb_lock;

499
extern int tb_invalidated_flag;
B
bellard 已提交
500

B
bellard 已提交
501 502
#if (defined(TARGET_I386) || defined(TARGET_PPC)) && \
    !defined(CONFIG_USER_ONLY)
B
bellard 已提交
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524

void tlb_fill(unsigned long addr, int is_write, int is_user, 
              void *retaddr);

#define ACCESS_TYPE 3
#define MEMSUFFIX _code
#define env cpu_single_env

#define DATA_SIZE 1
#include "softmmu_header.h"

#define DATA_SIZE 2
#include "softmmu_header.h"

#define DATA_SIZE 4
#include "softmmu_header.h"

#undef ACCESS_TYPE
#undef MEMSUFFIX
#undef env

#endif
525 526 527 528 529 530 531 532

#if defined(CONFIG_USER_ONLY)
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
{
    return addr;
}
#else
/* NOTE: this function can trigger an exception */
533 534
/* NOTE2: the returned address is not exactly the physical address: it
   is the offset relative to phys_ram_base */
535 536 537 538 539 540
/* XXX: i386 target specific */
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
{
    int is_user, index;

    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
B
bellard 已提交
541
#if defined(TARGET_I386)
542
    is_user = ((env->hflags & HF_CPL_MASK) == 3);
B
bellard 已提交
543 544 545 546 547
#elif defined (TARGET_PPC)
    is_user = msr_pr;
#else
#error "Unimplemented !"
#endif
548 549 550 551 552 553 554 555
    if (__builtin_expect(env->tlb_read[is_user][index].address != 
                         (addr & TARGET_PAGE_MASK), 0)) {
        ldub_code((void *)addr);
    }
    return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base;
}
#endif