tests/Makefile\
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
tests/test-i386-muldiv.h\
-tests/test2.c tests/hello.c tests/sha1.c
+tests/test2.c tests/hello.c tests/hello tests/sha1.c
FILE=gemu-$(VERSION)
TMPDIR1="/tmp"
fi
-TMPC="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.c"
-TMPO="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.o"
-TMPE="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}"
-TMPS="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.S"
-TMPH="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.h"
+TMPC="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.c"
+TMPO="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.o"
+TMPE="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}"
+TMPS="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.S"
+TMPH="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.h"
# default parameters
prefix="/usr/local"
fi
# check gcc version
+cat > $TMPC <<EOF
+int main(void) {
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+return 0;
+#else
+#error gcc < 3.2
+#endif
+}
+EOF
+
gcc_major="2"
-gcc_version="$($cc -v 2>&1 | grep version | cut -d ' ' -f3-)"
-case "$gcc_version" in
-3.*) gcc_major="3";
-;;
-esac
+if $cc -o $TMPO $TMPC 2> /dev/null ; then
+ gcc_major="3"
+fi
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
cat << EOF
elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> config.mak
elif test "$cpu" = "powerpc" ; then
- echo "ARCH=ppc" > config.mak
+ echo "ARCH=ppc" >> config.mak
elif test "$cpu" = "mips" ; then
- echo "ARCH=mips" > config.mak
+ echo "ARCH=mips" >> config.mak
else
echo "Unsupported CPU"
exit 1
#ifndef CPU_I386_H
#define CPU_I386_H
+#include "config.h"
#include <setjmp.h>
#define R_EAX 0
int exception_index;
} CPUX86State;
+/* all CPU memory access use these macros */
static inline int ldub(void *ptr)
{
return *(uint8_t *)ptr;
return *(int8_t *)ptr;
}
+static inline void stb(void *ptr, int v)
+{
+ *(uint8_t *)ptr = v;
+}
+
+#ifdef WORDS_BIGENDIAN
+
+/* conservative code for little endian unaligned accesses */
+static inline int lduw(void *ptr)
+{
+#ifdef __powerpc__
+ int val;
+ __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
+ return val;
+#else
+ uint8_t *p = ptr;
+ return p[0] | (p[1] << 8);
+#endif
+}
+
+static inline int ldsw(void *ptr)
+{
+#ifdef __powerpc__
+ int val;
+ __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
+ return (int16_t)val;
+#else
+ uint8_t *p = ptr;
+ return (int16_t)(p[0] | (p[1] << 8));
+#endif
+}
+
+static inline int ldl(void *ptr)
+{
+#ifdef __powerpc__
+ int val;
+ __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
+ return val;
+#else
+ uint8_t *p = ptr;
+ return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+#endif
+}
+
+static inline uint64_t ldq(void *ptr)
+{
+ uint8_t *p = ptr;
+ uint32_t v1, v2;
+ v1 = ldl(p);
+ v2 = ldl(p + 4);
+ return v1 | ((uint64_t)v2 << 32);
+}
+
+static inline void stw(void *ptr, int v)
+{
+#ifdef __powerpc__
+ __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
+#else
+ uint8_t *p = ptr;
+ p[0] = v;
+ p[1] = v >> 8;
+#endif
+}
+
+static inline void stl(void *ptr, int v)
+{
+#ifdef __powerpc__
+ __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
+#else
+ uint8_t *p = ptr;
+ p[0] = v;
+ p[1] = v >> 8;
+ p[2] = v >> 16;
+ p[3] = v >> 24;
+#endif
+}
+
+static inline void stq(void *ptr, uint64_t v)
+{
+ uint8_t *p = ptr;
+ stl(p, (uint32_t)v);
+ stl(p + 4, v >> 32);
+}
+
+/* float access */
+
+static inline float ldfl(void *ptr)
+{
+ union {
+ float f;
+ uint32_t i;
+ } u;
+ u.i = ldl(ptr);
+ return u.f;
+}
+
+static inline double ldfq(void *ptr)
+{
+ union {
+ double d;
+ uint64_t i;
+ } u;
+ u.i = ldq(ptr);
+ return u.d;
+}
+
+static inline void stfl(void *ptr, float v)
+{
+ union {
+ float f;
+ uint32_t i;
+ } u;
+ u.f = v;
+ stl(ptr, u.i);
+}
+
+static inline void stfq(void *ptr, double v)
+{
+ union {
+ double d;
+ uint64_t i;
+ } u;
+ u.d = v;
+ stq(ptr, u.i);
+}
+
+#else
+
static inline int lduw(void *ptr)
{
return *(uint16_t *)ptr;
return *(uint64_t *)ptr;
}
-static inline void stb(void *ptr, int v)
-{
- *(uint8_t *)ptr = v;
-}
-
static inline void stw(void *ptr, int v)
{
*(uint16_t *)ptr = v;
{
*(double *)ptr = v;
}
+#endif
#ifndef IN_OP_I386
void cpu_x86_outb(int addr, int val);
#define DIS_ASM_H
#include <stdio.h>
+#include <string.h>
#include "bfd.h"
typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
*/
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <stdarg.h>
#include <inttypes.h>
#include <elf.h>
{
uint8_t *p;
p = (void *)(p_end - 4);
- /* find ret */
- while (p > p_start && get32((uint32_t *)p) != 0x4e800020)
- p -= 4;
- /* skip double ret */
- if (p > p_start && get32((uint32_t *)(p - 4)) == 0x4e800020)
- p -= 4;
if (p == p_start)
error("empty code for %s", name);
+ if (get32((uint32_t *)p) != 0x4e800020)
+ error("blr expected at the end of %s", name);
copy_size = p - p_start;
}
break;
}
}
break;
+ case EM_PPC:
+ {
+ Elf32_Rela *rel;
+ char name[256];
+ int type;
+ long addend;
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
+ sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
+ if (strstart(sym_name, "__op_param", &p)) {
+ snprintf(name, sizeof(name), "param%s", p);
+ } else {
+ snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
+ }
+ type = ELF32_R_TYPE(rel->r_info);
+ addend = rel->r_addend;
+ switch(type) {
+ case R_PPC_ADDR32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n",
+ rel->r_offset - offset, name, addend);
+ break;
+ case R_PPC_ADDR16_LO:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld);\n",
+ rel->r_offset - offset, name, addend);
+ break;
+ case R_PPC_ADDR16_HI:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld) >> 16;\n",
+ rel->r_offset - offset, name, addend);
+ break;
+ case R_PPC_ADDR16_HA:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld + 0x8000) >> 16;\n",
+ rel->r_offset - offset, name, addend);
+ break;
+ case R_PPC_REL24:
+ /* warning: must be at 32 MB distancy */
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = (*(uint32_t *)(gen_code_ptr + %ld) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %ld) + %ld) & 0x03fffffc);\n",
+ rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend);
+ break;
+ default:
+ error("unsupported powerpc relocation (%d)", type);
+ }
+ }
+ }
+ }
+ break;
default:
error("unsupported CPU for relocations (%d)", e_machine);
}
case EM_386:
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
break;
+ case EM_PPC:
+ fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n");
+ break;
default:
error("no return generation for cpu '%s'", cpu_name);
}
{
int saved_T0, saved_T1, saved_A0;
CPUX86State *saved_env;
+#ifdef reg_EAX
+ int saved_EAX;
+#endif
+#ifdef reg_ECX
+ int saved_ECX;
+#endif
+#ifdef reg_EDX
+ int saved_EDX;
+#endif
+#ifdef reg_EBX
+ int saved_EBX;
+#endif
+#ifdef reg_ESP
+ int saved_ESP;
+#endif
+#ifdef reg_EBP
+ int saved_EBP;
+#endif
+#ifdef reg_ESI
+ int saved_ESI;
+#endif
+#ifdef reg_EDI
+ int saved_EDI;
+#endif
int code_gen_size, ret;
void (*gen_func)(void);
TranslationBlock *tb;
saved_A0 = A0;
saved_env = env;
env = env1;
+#ifdef reg_EAX
+ saved_EAX = EAX;
+ EAX = env->regs[R_EAX];
+#endif
+#ifdef reg_ECX
+ saved_ECX = ECX;
+ ECX = env->regs[R_ECX];
+#endif
+#ifdef reg_EDX
+ saved_EDX = EDX;
+ EDX = env->regs[R_EDX];
+#endif
+#ifdef reg_EBX
+ saved_EBX = EBX;
+ EBX = env->regs[R_EBX];
+#endif
+#ifdef reg_ESP
+ saved_ESP = ESP;
+ ESP = env->regs[R_ESP];
+#endif
+#ifdef reg_EBP
+ saved_EBP = EBP;
+ EBP = env->regs[R_EBP];
+#endif
+#ifdef reg_ESI
+ saved_ESI = ESI;
+ ESI = env->regs[R_ESI];
+#endif
+#ifdef reg_EDI
+ saved_EDI = EDI;
+ EDI = env->regs[R_EDI];
+#endif
/* prepare setjmp context for exception handling */
if (setjmp(env->jmp_env) == 0) {
ret = env->exception_index;
/* restore global registers */
+#ifdef reg_EAX
+ EAX = saved_EAX;
+#endif
+#ifdef reg_ECX
+ ECX = saved_ECX;
+#endif
+#ifdef reg_EDX
+ EDX = saved_EDX;
+#endif
+#ifdef reg_EBX
+ EBX = saved_EBX;
+#endif
+#ifdef reg_ESP
+ ESP = saved_ESP;
+#endif
+#ifdef reg_EBP
+ EBP = saved_EBP;
+#endif
+#ifdef reg_ESI
+ ESI = saved_ESI;
+#endif
+#ifdef reg_EDI
+ EDI = saved_EDI;
+#endif
T0 = saved_T0;
T1 = saved_T1;
A0 = saved_A0;
register struct CPUX86State *env asm("ebp");
#endif
#ifdef __powerpc__
+register unsigned int EAX asm("r16");
+register unsigned int ECX asm("r17");
+register unsigned int EDX asm("r18");
+register unsigned int EBX asm("r19");
+register unsigned int ESP asm("r20");
+register unsigned int EBP asm("r21");
+register unsigned int ESI asm("r22");
+register unsigned int EDI asm("r23");
register unsigned int T0 asm("r24");
register unsigned int T1 asm("r25");
register unsigned int A0 asm("r26");
register struct CPUX86State *env asm("r27");
+#define USE_INT_TO_FLOAT_HELPERS
+#define reg_EAX
+#define reg_ECX
+#define reg_EDX
+#define reg_EBX
+#define reg_ESP
+#define reg_EBP
+#define reg_ESI
+#define reg_EDI
#endif
#ifdef __arm__
register unsigned int T0 asm("r4");
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
+#ifndef reg_EAX
#define EAX (env->regs[R_EAX])
+#endif
+#ifndef reg_ECX
#define ECX (env->regs[R_ECX])
+#endif
+#ifndef reg_EDX
#define EDX (env->regs[R_EDX])
+#endif
+#ifndef reg_EBX
#define EBX (env->regs[R_EBX])
+#endif
+#ifndef reg_ESP
#define ESP (env->regs[R_ESP])
+#endif
+#ifndef reg_EBP
#define EBP (env->regs[R_EBP])
+#endif
+#ifndef reg_ESI
#define ESI (env->regs[R_ESI])
+#endif
+#ifndef reg_EDI
#define EDI (env->regs[R_EDI])
+#endif
#define PC (env->pc)
#define DF (env->df)
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
+#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
+#include <string.h>
#include <elf.h>
#include <endian.h>
#include <errno.h>
#define termios host_termios
#define winsize host_winsize
#define termio host_termio
+#define sgttyb host_sgttyb /* same as target */
+#define tchars host_tchars /* same as target */
+#define ltchars host_ltchars /* same as target */
#include <linux/termios.h>
#include <linux/unistd.h>
case TARGET_NR_ftime:
goto unimplemented;
case TARGET_NR_sync:
- ret = get_errno(sync());
+ sync();
+ ret = 0;
break;
case TARGET_NR_kill:
ret = get_errno(kill(arg1, arg2));
/* NOTE: not static to force relocation generation by GCC */
void raise_exception(int exception_index)
{
+ /* NOTE: the register at this point must be saved by hand because
+ longjmp restore them */
+#ifdef reg_EAX
+ env->regs[R_EAX] = EAX;
+#endif
+#ifdef reg_ECX
+ env->regs[R_ECX] = ECX;
+#endif
+#ifdef reg_EDX
+ env->regs[R_EDX] = EDX;
+#endif
+#ifdef reg_EBX
+ env->regs[R_EBX] = EBX;
+#endif
+#ifdef reg_ESP
+ env->regs[R_ESP] = ESP;
+#endif
+#ifdef reg_EBP
+ env->regs[R_EBP] = EBP;
+#endif
+#ifdef reg_ESI
+ env->regs[R_ESI] = ESI;
+#endif
+#ifdef reg_EDI
+ env->regs[R_EDI] = EDI;
+#endif
env->exception_index = exception_index;
longjmp(env->jmp_env, 1);
}
FT0 = ldfq((void *)A0);
}
+/* helpers are needed to avoid static constant reference. XXX: find a better way */
+#ifdef USE_INT_TO_FLOAT_HELPERS
+
+void helper_fild_FT0_A0(void)
+{
+ FT0 = (CPU86_LDouble)ldsw((void *)A0);
+}
+
+void helper_fildl_FT0_A0(void)
+{
+ FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
+}
+
+void helper_fildll_FT0_A0(void)
+{
+ FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
+}
+
+void OPPROTO op_fild_FT0_A0(void)
+{
+ helper_fild_FT0_A0();
+}
+
+void OPPROTO op_fildl_FT0_A0(void)
+{
+ helper_fildl_FT0_A0();
+}
+
+void OPPROTO op_fildll_FT0_A0(void)
+{
+ helper_fildll_FT0_A0();
+}
+
+#else
+
void OPPROTO op_fild_FT0_A0(void)
{
FT0 = (CPU86_LDouble)ldsw((void *)A0);
{
FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
}
+#endif
/* fp load ST0 */
}
#endif
+/* helpers are needed to avoid static constant reference. XXX: find a better way */
+#ifdef USE_INT_TO_FLOAT_HELPERS
+
+void helper_fild_ST0_A0(void)
+{
+ ST0 = (CPU86_LDouble)ldsw((void *)A0);
+}
+
+void helper_fildl_ST0_A0(void)
+{
+ ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
+}
+
+void helper_fildll_ST0_A0(void)
+{
+ ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
+}
+
+void OPPROTO op_fild_ST0_A0(void)
+{
+ helper_fild_ST0_A0();
+}
+
+void OPPROTO op_fildl_ST0_A0(void)
+{
+ helper_fildl_ST0_A0();
+}
+
+void OPPROTO op_fildll_ST0_A0(void)
+{
+ helper_fildll_ST0_A0();
+}
+
+#else
+
void OPPROTO op_fild_ST0_A0(void)
{
ST0 = (CPU86_LDouble)ldsw((void *)A0);
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
}
+#endif
+
/* fp store */
void OPPROTO op_fsts_ST0_A0(void)
EDI += inc;
ECX--;
}
+ FORCE_RET();
}
void OPPROTO glue(op_stos, SUFFIX)(void)
EDI += inc;
ECX--;
}
+ FORCE_RET();
}
void OPPROTO glue(op_lods, SUFFIX)(void)
ESI += inc;
ECX--;
}
+ FORCE_RET();
}
void OPPROTO glue(op_scas, SUFFIX)(void)
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
+ FORCE_RET();
}
void OPPROTO glue(op_repnz_scas, SUFFIX)(void)
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
+ FORCE_RET();
}
void OPPROTO glue(op_cmps, SUFFIX)(void)
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
+ FORCE_RET();
}
void OPPROTO glue(op_repnz_cmps, SUFFIX)(void)
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
+ FORCE_RET();
}
/* port I/O */
ESI += inc;
ECX--;
}
+ FORCE_RET();
}
void OPPROTO glue(op_ins, SUFFIX)(void)
EDI += (DF << SHIFT);
ECX--;
}
+ FORCE_RET();
}
void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void)
LDFLAGS=
ifeq ($(ARCH),i386)
-TESTS=hello test2 sha1 test-i386
+TESTS=test2 sha1-i386 test-i386
endif
+TESTS+=sha1
GEMU=../gemu
hello: hello.c
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
+ strip hello
test2: test2.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
-# i386 emulation test (dump various opcodes) */
+# i386 emulation test (test various opcodes) */
test-i386: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< -lm
test: test-i386
+ifeq ($(ARCH),i386)
./test-i386 > test-i386.ref
+endif
$(GEMU) test-i386 > test-i386.out
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
# speed test
-sha1: sha1.c
+sha1-i386: sha1.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
-speed: sha1
+sha1: sha1.c
+ $(HOST_CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+speed: sha1 sha1-i386
time ./sha1
- time $(GEMU) sha1
+ time $(GEMU) ./sha1-i386
clean:
rm -f *~ *.o $(TESTS)
{
struct modify_ldt_ldt_s ldt;
long long ldt_table[3];
- int i, res, res2;
+ int res, res2;
char tmp;
ldt.entry_number = 1;
modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */
- for(i=0;i<3;i++)
- printf("%d: %016Lx\n", i, ldt_table[i]);
-
+#if 0
+ {
+ int i;
+ for(i=0;i<3;i++)
+ printf("%d: %016Lx\n", i, ldt_table[i]);
+ }
+#endif
/* do some tests with fs or gs */
asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2)));
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
+/* XXX: move that elsewhere */
static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
int __op_param1, __op_param2, __op_param3;
+#ifdef __i386__
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+}
+#endif
+
+#ifdef __powerpc__
+
+#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
+
+static void inline flush_icache_range(unsigned long start, unsigned long stop)
+{
+ unsigned long p;
+
+ p = start & ~(MIN_CACHE_LINE_SIZE - 1);
+ stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
+
+ for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
+ asm ("dcbst 0,%0;" : : "r"(p) : "memory");
+ }
+ asm ("sync");
+ for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
+ asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
+ }
+ asm ("sync");
+ asm ("isync");
+}
+#endif
+
extern FILE *logfile;
extern int loglevel;
DisasContext dc1, *dc = &dc1;
uint8_t *pc_ptr;
uint16_t *gen_opc_end;
+ int gen_code_size;
long ret;
#ifdef DEBUG_DISAS
struct disassemble_info disasm_info;
#endif
/* generate machine code */
- *gen_code_size_ptr = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf);
+ gen_code_size = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf);
+ flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size));
+ *gen_code_size_ptr = gen_code_size;
#ifdef DEBUG_DISAS
if (loglevel) {