A sent a patch some months ago for adding ppc64 host support on Linux.
This one's pretty much the same, though updated to apply to the current
CVS qemu. Only i386 target tested and working partially.
-- Heikki Lindholm
diff -Nru qemu/configure qemu-devel-ppc64/configure
--- qemu/configure 2006-07-30 21:06:23.000000000 +0300
+++ qemu-devel-ppc64/configure 2006-08-02 19:41:02.000000000 +0300
@@ -42,9 +42,12 @@
alpha)
cpu="alpha"
;;
- "Power Macintosh"|ppc|ppc64)
+ "Power Macintosh"|ppc)
cpu="powerpc"
;;
+ ppc64)
+ cpu="powerpc64"
+ ;;
mips)
cpu="mips"
;;
@@ -401,7 +404,7 @@
else
# if cross compiling, cannot launch a program, so make a static guess
-if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" =
"sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then
+if test "$cpu" = "powerpc" -o "$cpu" = "powerpc64" -o "$cpu" = "mips" -o
"$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o
"$cpu" = "armv4b"; then
bigendian="yes"
fi
@@ -409,7 +412,7 @@
# host long bits test
hostlongbits="32"
-if test "$cpu" = "sparc64" -o "$cpu" = "ia64" -o "$cpu" = "x86_64" -o "$cpu" =
"alpha"; then
+if test "$cpu" = "sparc64" -o "$cpu" = "ia64" -o "$cpu" = "x86_64" -o "$cpu" =
"alpha" -o "$cpu" = "powerpc64"; then
hostlongbits="64"
fi
@@ -611,6 +614,9 @@
elif test "$cpu" = "powerpc" ; then
echo "ARCH=ppc" >> $config_mak
echo "#define HOST_PPC 1" >> $config_h
+elif test "$cpu" = "powerpc64" ; then
+ echo "ARCH=ppc64" >> $config_mak
+ echo "#define HOST_PPC64 1" >> $config_h
elif test "$cpu" = "mips" ; then
echo "ARCH=mips" >> $config_mak
echo "#define HOST_MIPS 1" >> $config_h
diff -Nru qemu/cpu-all.h qemu-devel-ppc64/cpu-all.h
--- qemu/cpu-all.h 2006-08-02 19:32:20.000000000 +0300
+++ qemu-devel-ppc64/cpu-all.h 2006-08-03 08:26:07.000000000 +0300
@@ -902,8 +902,16 @@
/*******************************************/
/* host CPU ticks (if available) */
+#if defined(__powerpc64__)
-#if defined(__powerpc__)
+static inline int64_t cpu_get_real_ticks(void)
+{
+ int64_t t;
+ asm volatile("mftb %0\n" : "=r" (t));
+ return t;
+}
+
+#elif defined(__powerpc__)
static inline uint32_t get_tbl(void)
{
diff -Nru qemu/cpu-exec.c qemu-devel-ppc64/cpu-exec.c
--- qemu/cpu-exec.c 2006-07-30 21:06:24.000000000 +0300
+++ qemu-devel-ppc64/cpu-exec.c 2006-08-02 19:47:05.000000000 +0300
@@ -83,7 +83,10 @@
unsigned int h;
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
uint8_t *tc_ptr;
-
+#ifdef __powerpc64__
+ long toc_addr;
+#endif
+
spin_lock(&tb_lock);
tb_invalidated_flag = 0;
@@ -132,9 +135,16 @@
tb->tc_ptr = tc_ptr;
tb->cs_base = cs_base;
tb->flags = flags;
- cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
+ cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE,
+#ifdef __powerpc64__
+ &toc_addr,
+#endif
+ &code_gen_size);
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size +
CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
-
+#ifdef __powerpc64__
+ tb->toc_addr = toc_addr;
+#endif
+
/* check next page if needed */
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
phys_page2 = -1;
@@ -261,6 +271,9 @@
int saved_i7, tmp_T0;
#endif
int ret, interrupt_request;
+#ifdef __powerpc64__
+ unsigned long toc_addr;
+#endif
void (*gen_func)(void);
TranslationBlock *tb;
uint8_t *tc_ptr;
@@ -667,6 +680,9 @@
}
}
tc_ptr = tb->tc_ptr;
+#ifdef __powerpc64__
+ toc_addr = tb->toc_addr;
+#endif
env->current_tb = tb;
/* execute the generated code */
gen_func = (void *)tc_ptr;
@@ -759,6 +775,16 @@
);
}
}
+#elif defined(__powerpc64__)
+ struct fdesc {
+ uint64_t entry;
+ uint64_t toc_base;
+ uint64_t env_ptr;
+ } fp;
+ fp.entry = (uint64_t)tc_ptr;
+ fp.toc_base = toc_addr;
+ fp.env_ptr = 0;
+ (*(void (*)(void))&fp)();
#elif defined(__ia64)
struct fptr {
void *ip;
diff -Nru qemu/dyngen.c qemu-devel-ppc64/dyngen.c
--- qemu/dyngen.c 2006-08-02 19:32:21.000000000 +0300
+++ qemu-devel-ppc64/dyngen.c 2006-08-02 23:29:54.000000000 +0300
@@ -68,6 +68,13 @@
#define elf_check_arch(x) ((x) == EM_PPC)
#define ELF_USES_RELOCA
+#elif defined(HOST_PPC64)
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_ARCH EM_PPC64
+#define elf_check_arch(x) ((x) == EM_PPC64)
+#define ELF_USES_RELOCA
+
#elif defined(HOST_S390)
#define ELF_CLASS ELFCLASS32
@@ -211,7 +218,11 @@
};
/* all dynamically generated functions begin with this code */
+#ifdef HOST_PPC64
+#define OP_PREFIX ".op_"
+#else
#define OP_PREFIX "op_"
+#endif
int do_swap;
@@ -336,6 +347,10 @@
uint8_t **sdata;
struct elfhdr ehdr;
char *strtab;
+#ifdef HOST_PPC64
+EXE_RELOC *toc_relocs;
+int nb_toc_relocs;
+#endif
int elf_must_swap(struct elfhdr *h)
{
@@ -437,8 +452,46 @@
return rel->r_offset;
}
+#ifdef HOST_PPC64
+EXE_RELOC *find_sym_in_toc(EXE_RELOC *tocrel) {
+ EXE_RELOC *rel;
+ int i;
+
+ if (!tocrel)
+ return NULL;
+ if (ELF64_R_TYPE(tocrel->r_info) != R_PPC64_TOC16 &&
+ ELF64_R_TYPE(tocrel->r_info) != R_PPC64_TOC16_DS)
+ return NULL;
+
+ for (i = 0, rel = toc_relocs; i < nb_toc_relocs; i++, rel++) {
+ int rsize;
+
+ rsize = 0;
+ if (ELF64_R_TYPE(rel->r_info) == R_PPC64_ADDR64)
+ rsize = 8;
+ else {
+ fprintf(stderr, "find_sym_in_toc: Unexpected address type in TOC");
+ return NULL;
+ }
+ if (rel->r_addend != 0) {
+ fprintf(stderr, "find_sym_in_toc: Unexpected addend in TOC\n");
+ return NULL;
+ }
+ if (tocrel->r_addend >= rel->r_offset &&
+ tocrel->r_addend < rel->r_offset + rsize)
+ return rel;
+ }
+ return NULL;
+}
+#endif
+
static char *get_rel_sym_name(EXE_RELOC *rel)
{
+#ifdef HOST_PPC64
+ EXE_RELOC *trel = find_sym_in_toc(rel);
+ if (trel)
+ rel = trel;
+#endif
return strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
}
@@ -456,6 +509,11 @@
ElfW(Sym) *sym;
char *shstr;
ELF_RELOC *rel;
+#ifdef HOST_PPC64
+ struct elf_shdr *toc_sec;
+ int toc_shndx;
+ uint8_t *toc;
+#endif
fd = open(filename, O_RDONLY);
if (fd < 0)
@@ -552,6 +610,24 @@
swab16s(&sym->st_shndx);
}
}
+
+#ifdef HOST_PPC64
+ toc_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".toc");
+ if (!toc_sec)
+ error("could not find .toc section");
+ toc_shndx = toc_sec - shdr;
+ toc = sdata[toc_shndx];
+
+ toc_relocs = NULL;
+ nb_toc_relocs = 0;
+ i = find_reloc(toc_shndx);
+ if (i != 0) {
+ toc_relocs = (ELF_RELOC *)sdata[i];
+ nb_toc_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
+ }
+ else
+ fprintf(stderr, "That's odd, found no TOC relocs.\n");
+#endif
close(fd);
return 0;
}
@@ -1205,7 +1281,7 @@
}
}
-#ifdef HOST_IA64
+#if defined(HOST_IA64) || defined(HOST_PPC64)
#define PLT_ENTRY_SIZE 16 /* 1 bundle containing "brl" */
@@ -1452,10 +1528,14 @@
copy_size = len;
}
#endif
-#elif defined(HOST_PPC)
+#elif defined(HOST_PPC) || defined(HOST_PPC64)
{
uint8_t *p;
+#ifdef HOST_PPC64
+ p = (void *)(p_end - 4 - 3*4);
+#else
p = (void *)(p_end - 4);
+#endif
if (p == p_start)
error("empty code for %s", name);
if (get32((uint32_t *)p) != 0x4e800020)
@@ -1714,6 +1794,13 @@
*/
fprintf(outfile, " extern char %s;\n",
sym_name);
+#elif defined(HOST_PPC64)
+ /* REL24s are generally functions, which are already
+ * imported at the beginning of the file (plt fixups)
+ */
+ if (ELF64_R_TYPE(rel->r_info) != R_PPC64_REL24)
+ fprintf(outfile, "extern char %s;\n", sym_name+
+ (sym_name[0]=='.' ? 1:0));
#else
fprintf(outfile, "extern char %s;\n", sym_name);
#endif
@@ -1721,8 +1808,13 @@
}
}
+#ifdef HOST_PPC64
+ fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char
*)(((uint64_t *)&%s)[0])+%d), %d);\n",
+ name, (int)(start_offset - offset),
copy_size);
+#else
fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d),
%d);\n",
name, (int)(start_offset - offset),
copy_size);
+#endif
/* emit code offset information */
{
@@ -1902,7 +1994,7 @@
}
}
}
-#elif defined(HOST_PPC)
+#elif defined(HOST_PPC) || defined(HOST_PPC64)
{
#ifdef CONFIG_FORMAT_ELF
char name[256];
@@ -1912,7 +2004,10 @@
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
- sym_name = strtab +
symtab[ELFW(R_SYM)(rel->r_info)].st_name;
+#ifdef HOST_PPC64
+ EXE_RELOC *toc_entry;
+#endif
+ sym_name = get_rel_sym_name(rel);
reloc_offset = rel->r_offset - start_offset;
if (strstart(sym_name, "__op_jmp", &p)) {
int n;
@@ -1927,7 +2022,11 @@
}
get_reloc_expr(name, sizeof(name), sym_name);
+#ifdef HOST_PPC64
+ type = ELF64_R_TYPE(rel->r_info);
+#else
type = ELF32_R_TYPE(rel->r_info);
+#endif
addend = rel->r_addend;
switch(type) {
case R_PPC_ADDR32:
@@ -1947,10 +2046,33 @@
reloc_offset, name, addend);
break;
case R_PPC_REL24:
+#ifdef HOST_PPC64
+ if (strstart(sym_name, "__op_gen_label", NULL))
+ fprintf(outfile, " *(uint32_t
*)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s
- (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
+ reloc_offset, reloc_offset, name,
reloc_offset, addend);
+ else
+ /* this has to be a function call */
+ fprintf(outfile,
+ " PPC64_PLT(gen_code_ptr + %ld, "
+ "%d);\t/* %s + %ld */\n",
+ reloc_offset,
+ get_plt_index(sym_name+1, addend),
+ sym_name, addend);
+#else
/* warning: must be at 32 MB distancy */
fprintf(outfile, " *(uint32_t *)(gen_code_ptr +
%d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s -
(long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
reloc_offset, reloc_offset, name,
reloc_offset, addend);
+#endif
break;
+#ifdef HOST_PPC64
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16:
+ toc_entry = find_sym_in_toc(rel);
+ fprintf(outfile, " PPC64_TOC16(gen_code_ptr +
%ld, %s, %d);\n",
+ reloc_offset,
+ name, addend-toc_entry->r_offset);
+ break;
+#endif
default:
error("unsupported powerpc relocation (%d)", type);
}
@@ -2486,6 +2608,9 @@
const char *name;
name = get_sym_name(sym);
if (strstart(name, OP_PREFIX, NULL)) {
+#ifdef HOST_PPC64
+ name = name + 1;
+#endif
gen_code(name, sym->st_value, sym->st_size, outfile, 2);
}
}
@@ -2500,6 +2625,9 @@
if (sym->st_shndx != text_shndx)
error("invalid section for opcode (0x%x)", sym->st_shndx);
#endif
+#ifdef HOST_PPC64
+ name = name + 1;
+#endif
gen_code(name, sym->st_value, sym->st_size, outfile, 0);
}
}
@@ -2528,8 +2656,13 @@
"};\n");
#endif
+#ifdef HOST_PPC64
+#define TOC_PTR_ARG " long *toc_addr_ptr,\n"
+#else
+#define TOC_PTR_ARG
+#endif
fprintf(outfile,
-"int dyngen_code(uint8_t *gen_code_buf,\n"
+"int dyngen_code(uint8_t *gen_code_buf,\n" TOC_PTR_ARG
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
" const uint16_t *opc_buf, const uint32_t *opparam_buf, const
long *gen_labels)\n"
"{\n"
@@ -2569,7 +2702,7 @@
/* Initialise the parmissible pool offset to an arbitary large value. */
" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
#endif
-#ifdef HOST_IA64
+#if defined(HOST_IA64) || defined(HOST_PPC64)
{
long addend, not_first = 0;
unsigned long sym_idx;
@@ -2583,8 +2716,16 @@
sym_name = (strtab + symtab[sym_idx].st_name);
if (strstart(sym_name, "__op_gen_label", NULL))
continue;
+#ifdef HOST_PPC64
+ if (strstart(sym_name, "__op_jmp", NULL))
+ continue;
+ if (ELF64_R_TYPE(rel->r_info) != R_PPC64_REL24)
+ continue;
+ sym_name = sym_name + 1; /* scrap the leading '.' */
+#else
if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
continue;
+#endif
addend = rel->r_addend;
index = get_plt_index(sym_name, addend);
@@ -2594,10 +2735,17 @@
fprintf(outfile, " extern void %s(void);\n", sym_name);
}
+#ifdef HOST_PPC64
+ fprintf(outfile,
+ " struct ppc64_fixup *plt_fixes = NULL, "
+ "*toc16_fixes = NULL;\n"
+ " static long plt_target[] = {\n\t");
+#else
fprintf(outfile,
" struct ia64_fixup *plt_fixes = NULL, "
"*ltoff_fixes = NULL;\n"
" static long plt_target[] = {\n\t");
+#endif
max_index = -1;
for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
@@ -2605,8 +2753,16 @@
sym_name = (strtab + symtab[sym_idx].st_name);
if (strstart(sym_name, "__op_gen_label", NULL))
continue;
+#ifdef HOST_PPC64
+ if (strstart(sym_name, "__op_jmp", NULL))
+ continue;
+ if (ELF64_R_TYPE(rel->r_info) != R_PPC64_REL24)
+ continue;
+ sym_name = sym_name + 1; /* scrap the leading '.' */
+#else
if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
continue;
+#endif
addend = rel->r_addend;
index = get_plt_index(sym_name, addend);
@@ -2666,6 +2822,9 @@
if (sym->st_shndx != text_shndx)
error("invalid section for opcode (0x%x)", sym->st_shndx);
#endif
+#ifdef HOST_PPC64
+ name = name + 1;
+#endif
gen_code(name, sym->st_value, sym->st_size, outfile, 1);
}
}
@@ -2691,6 +2850,14 @@
" }\n"
" the_end:\n"
);
+#ifdef HOST_PPC64
+ fprintf(outfile,
+ " {\n"
+ " ppc64_apply_fixes(&gen_code_ptr, toc16_fixes, "
+ "toc_addr_ptr, plt_fixes,\n\t\t\t"
+ "sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
+ "plt_target, plt_offset); }\n");
+#endif
#ifdef HOST_IA64
fprintf(outfile,
" {\n"
diff -Nru qemu/dyngen-exec.h qemu-devel-ppc64/dyngen-exec.h
--- qemu/dyngen-exec.h 2006-07-30 21:06:25.000000000 +0300
+++ qemu-devel-ppc64/dyngen-exec.h 2006-08-02 19:48:18.000000000 +0300
@@ -38,7 +38,7 @@
// Linux/Sparc64 defines uint64_t
#if !(defined (__sparc_v9__) && defined(__linux__))
/* XXX may be done for all 64 bits targets ? */
-#if defined (__x86_64__) || defined(__ia64)
+#if defined (__x86_64__) || defined(__ia64) || defined(__powerpc64__)
typedef unsigned long uint64_t;
#else
typedef unsigned long long uint64_t;
@@ -55,7 +55,7 @@
typedef signed int int32_t;
// Linux/Sparc64 defines int64_t
#if !(defined (__sparc_v9__) && defined(__linux__))
-#if defined (__x86_64__) || defined(__ia64)
+#if defined (__x86_64__) || defined(__ia64) || defined(__powerpc64__)
typedef signed long int64_t;
#else
typedef signed long long int64_t;
diff -Nru qemu/dyngen.h qemu-devel-ppc64/dyngen.h
--- qemu/dyngen.h 2006-08-02 19:32:21.000000000 +0300
+++ qemu-devel-ppc64/dyngen.h 2006-08-02 20:10:01.000000000 +0300
@@ -58,26 +58,7 @@
#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;
-
- 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 volatile ("dcbst 0,%0" : : "r"(p) : "memory");
- }
- asm volatile ("sync" : : : "memory");
- for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
- asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
- }
- asm volatile ("sync" : : : "memory");
- asm volatile ("isync" : : : "memory");
-}
+#include "ppc_icache.h"
#endif
#ifdef __alpha__
@@ -246,6 +227,141 @@
#endif /* __arm__ */
+#ifdef __powerpc64__
+struct ppc64_fixup {
+ struct ppc64_fixup *next;
+ void *addr;
+ long value;
+ int offset;
+};
+
+/* plt fixup consist of creating a linkage code at the end of the
+ * generated code and patching the calling instruction to call
+ * the linkage code instead
+ */
+#define PPC64_PLT(insn, plt_index) \
+do { \
+ struct ppc64_fixup *fixup = alloca(sizeof(*fixup)); \
+ fixup->next = plt_fixes; \
+ plt_fixes = fixup; \
+ fixup->addr = (insn); \
+ fixup->value = (plt_index); \
+ plt_offset[(plt_index)] = 1; \
+} while (0)
+
+/* for handling TOC16 and TOC16DS relocations
+ */
+#define PPC64_TOC16(insn, val, offs) \
+do { \
+ struct ppc64_fixup *fixup = alloca(sizeof(*fixup)); \
+ fixup->next = toc16_fixes; \
+ toc16_fixes = fixup; \
+ fixup->addr = (insn); \
+ fixup->value = (val); \
+ fixup->offset = (offs); \
+} while (0)
+
+static inline void ppc64_apply_fixes (uint8_t **gen_code_pp,
+ struct ppc64_fixup *toc16_fixes,
+ uint64_t *toc_addr_ptr,
+ struct ppc64_fixup *plt_fixes,
+ int num_plts,
+ unsigned long *plt_target,
+ unsigned int *plt_offset)
+{
+ /* note: TOC relative addressing here, too */
+ static const uint8_t linkage_code[] = {
+ 0x3d, 0x82, 0x00, 0x00, /* addis r12, r2, 0 */
+ 0xf8, 0x41, 0x00, 0x28, /* std r2, 40(r1) */
+ 0xe9, 0x6c, 0x00, 0x00, /* ld r11, xx(r12) function entry */
+ 0xe8, 0x4c, 0x00, 0x00, /* ld r2, xx(r12) function toc */
+ 0x7d, 0x69, 0x03, 0xa6, /* mtctr r11 */
+ 0x4e, 0x80, 0x04, 0x20 /* bctr */
+ };
+
+ /* this is patched in the "nop" following the function call "bl" */
+ static const uint8_t restore_toc[] = {
+ 0xe8, 0x41, 0x00, 0x28 /* ld r2,40(r1) this gets saved above */
+ };
+
+ uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *toc16_start,
*toc_start, *vp;
+ struct ppc64_fixup *fixup;
+ unsigned int offset = 0;
+ unsigned int toc_offset = -0x8000;
+ struct fdesc {
+ uint64_t entry;
+ uint64_t toc_base;
+ uint64_t env_ptr; /* we don't actually use this */
+ } *fdesc;
+ int i;
+
+ toc_start = gen_code_ptr;
+ if (plt_fixes) {
+ plt_start = gen_code_ptr;
+
+ /* generate linkage code */
+ for (i = 0; i < num_plts; ++i) {
+ if (plt_offset[i]) {
+ memcpy(gen_code_ptr, linkage_code, sizeof(linkage_code));
+
+ *(int16_t *)(gen_code_ptr + 10) = (int16_t)toc_offset;
+ toc_offset += 8;
+ *(int16_t *)(gen_code_ptr + 14) = (int16_t)toc_offset;
+ toc_offset += 8;
+ gen_code_ptr += sizeof(linkage_code);
+ }
+ }
+
+ /* generate opd entries (in the toc) for actual called functions */
+ toc_start = gen_code_ptr;
+ for (i = 0; i < num_plts; ++i) {
+ if (plt_offset[i]) {
+ /* count the linkage code positions */
+ plt_offset[i] = offset;
+ offset += sizeof(linkage_code);
+
+ fdesc = (struct fdesc *) plt_target[i];
+ *(uint64_t *)(gen_code_ptr) = fdesc->entry;
+ gen_code_ptr += 8;
+ *(uint64_t *)(gen_code_ptr) = fdesc->toc_base;
+ gen_code_ptr += 8;
+ }
+ }
+
+ /* fix original bl addresses to point at linkage code */
+ for (fixup = plt_fixes; fixup; fixup = fixup->next) {
+ *(uint32_t *)(fixup->addr) =
+ (*(uint32_t *)(fixup->addr) & ~0x03fffffc) |
+ ((((long)plt_start + plt_offset[fixup->value]) -
+ (long)(fixup->addr)) & 0x03fffffc);
+ /* fixup the nop, after the jump */
+ *(uint32_t *)(fixup->addr+4) = *(uint32_t *)restore_toc;
+ }
+ }
+
+ *toc_addr_ptr = ((long)toc_start)+0x8000;
+ toc16_start = gen_code_ptr;
+
+ /* create the toc parts for TOC16(DS) relocations */
+ for (fixup = toc16_fixes; fixup; fixup = fixup->next) {
+ /* first check if we already have this value in the toc */
+ for (vp = toc16_start; vp < gen_code_ptr; vp+=8)
+ if (*(uint64_t *)vp == fixup->value)
+ break;
+ if (vp == gen_code_ptr) {
+ /* nope, we need to put the value in the toc */
+ *(uint64_t *)vp = fixup->value;
+ gen_code_ptr += 8;
+ }
+ /* assuming that a TOC16DS relocation will work for TOC16, too */
+ *(int16_t *)(fixup->addr) = (int16_t)(((-0x8000+(vp-toc_start)+
+ fixup->offset) & 0xfffc) |
+ (*(int16_t *)(fixup->addr) & 0x3));
+ }
+ *gen_code_pp = gen_code_ptr;
+}
+#endif /* __powerpc64__ */
+
#ifdef __ia64
diff -Nru qemu/elf.h qemu-devel-ppc64/elf.h
--- qemu/elf.h 2006-08-02 19:32:21.000000000 +0300
+++ qemu-devel-ppc64/elf.h 2006-08-02 19:50:21.000000000 +0300
@@ -451,6 +451,127 @@
/* Keep this the last entry. */
#define R_PPC_NUM 37
+/* PowerPC64 relocations defined by the ABIs */
+#define R_PPC64_NONE R_PPC_NONE
+#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */
+#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */
+#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */
+#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */
+#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */
+#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */
+#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */
+#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN
+#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN
+#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
+#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */
+#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN
+#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN
+#define R_PPC64_GOT16 R_PPC_GOT16
+#define R_PPC64_GOT16_LO R_PPC_GOT16_LO
+#define R_PPC64_GOT16_HI R_PPC_GOT16_HI
+#define R_PPC64_GOT16_HA R_PPC_GOT16_HA
+
+#define R_PPC64_COPY R_PPC_COPY
+#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT
+#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
+#define R_PPC64_RELATIVE R_PPC_RELATIVE
+
+#define R_PPC64_UADDR32 R_PPC_UADDR32
+#define R_PPC64_UADDR16 R_PPC_UADDR16
+#define R_PPC64_REL32 R_PPC_REL32
+#define R_PPC64_PLT32 R_PPC_PLT32
+#define R_PPC64_PLTREL32 R_PPC_PLTREL32
+#define R_PPC64_PLT16_LO R_PPC_PLT16_LO
+#define R_PPC64_PLT16_HI R_PPC_PLT16_HI
+#define R_PPC64_PLT16_HA R_PPC_PLT16_HA
+
+#define R_PPC64_SECTOFF R_PPC_SECTOFF
+#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO
+#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI
+#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA
+#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */
+#define R_PPC64_ADDR64 38 /* doubleword64 S + A */
+#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */
+#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */
+#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */
+#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */
+#define R_PPC64_UADDR64 43 /* doubleword64 S + A */
+#define R_PPC64_REL64 44 /* doubleword64 S + A - P */
+#define R_PPC64_PLT64 45 /* doubleword64 L + A */
+#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */
+#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */
+#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */
+#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */
+#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */
+#define R_PPC64_TOC 51 /* doubleword64 .TOC */
+#define R_PPC64_PLTGOT16 52 /* half16* M + A */
+#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */
+#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */
+#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */
+
+#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */
+#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */
+#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */
+#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */
+#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */
+#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */
+#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */
+#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */
+#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */
+#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */
+#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */
+
+/* PowerPC64 relocations defined for the TLS access ABI. */
+#define R_PPC64_TLS 67 /* none (sym+add)@tls */
+#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */
+#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@[EMAIL PROTECTED]@l */
+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@[EMAIL PROTECTED]@h */
+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@[EMAIL PROTECTED]@ha
*/
+#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@[EMAIL PROTECTED]@l */
+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@[EMAIL PROTECTED]@h */
+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@[EMAIL PROTECTED]@ha
*/
+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@[EMAIL PROTECTED]@l
*/
+#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@[EMAIL PROTECTED]@h */
+#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@[EMAIL PROTECTED]@ha
*/
+#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@[EMAIL
PROTECTED] */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@[EMAIL
PROTECTED]@l */
+#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@[EMAIL
PROTECTED]@h */
+#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@[EMAIL
PROTECTED]@ha */
+#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@[EMAIL
PROTECTED] */
+#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@[EMAIL
PROTECTED] */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@[EMAIL
PROTECTED] */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@[EMAIL PROTECTED] */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@[EMAIL
PROTECTED] */
+
+/* Keep this the last entry. */
+#define R_PPC64_NUM 107
+
+/* PowerPC64 specific values for the Dyn d_tag field. */
+#define DT_PPC64_GLINK (DT_LOPROC + 0)
+#define DT_PPC64_OPD (DT_LOPROC + 1)
+#define DT_PPC64_OPDSZ (DT_LOPROC + 2)
+#define DT_PPC64_NUM 3
+
/* ARM specific declarations */
/* Processor specific flags for the ELF header e_flags field. */
diff -Nru qemu/exec-all.h qemu-devel-ppc64/exec-all.h
--- qemu/exec-all.h 2006-07-30 21:06:25.000000000 +0300
+++ qemu-devel-ppc64/exec-all.h 2006-08-03 21:39:59.000000000 +0300
@@ -82,7 +82,11 @@
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
- int max_code_size, int *gen_code_size_ptr);
+ int max_code_size,
+#ifdef __powerpc64__
+ uint64_t *toc_addr_ptr,
+#endif
+ int *gen_code_size_ptr);
int cpu_restore_state(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc);
@@ -173,6 +177,9 @@
#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */
uint8_t *tc_ptr; /* pointer to the translated code */
+#ifdef __powerpc64__
+ uint64_t toc_addr; /* address of the TOC for the translated code */
+#endif
/* next matching tb for physical address. */
struct TranslationBlock *phys_hash_next;
/* first and second physical page containing code. The lower bit
@@ -218,22 +225,55 @@
#if defined(USE_DIRECT_JUMP)
+#if defined(__powerpc64__)
+#include "ppc_icache.h"
+#endif
+
#if defined(__powerpc__)
-static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long
addr)
+static inline void tb_set_jmp_target1(unsigned long jmp_addr,
+#ifdef __powerpc64__
+ unsigned long toc_addr,
+#endif
+ unsigned long addr)
{
uint32_t val, *ptr;
+#ifdef __powerpc64__
+ extern void *memcpy(void *, const void *, size_t);
+
+ /* load 64-bit immediate address into r2 */
+ static const uint8_t loadtoc_code[] = {
+ 0x3c, 0x40, 0x00, 0x00, /* lis r2,0 */
+ 0x60, 0x42, 0x00, 0x00, /* ori r2,r2,0 */
+ 0x78, 0x42, 0x07, 0xc6, /* rldicr r2,r2,32,31 */
+ 0x64, 0x42, 0x00, 0x00, /* oris r2,r2,0 */
+ 0x60, 0x42, 0x00, 0x00, /* ori r2,r2,0 */
+ };
+
+ /* update TOC addr */
+ jmp_addr -= sizeof(loadtoc_code); /* there are nops in-place for this */
+ memcpy((void *)jmp_addr, (void *)loadtoc_code, sizeof(loadtoc_code));
+ *(uint16_t *)(jmp_addr+2) = (uint16_t)((toc_addr >> 48) & 0xffff);
+ *(uint16_t *)(jmp_addr+6) = (uint16_t)((toc_addr >> 32) & 0xffff);
+ *(uint16_t *)(jmp_addr+14) = (uint16_t)((toc_addr >> 16) & 0xffff);
+ *(uint16_t *)(jmp_addr+18) = (uint16_t)(toc_addr & 0xffff);
+ jmp_addr += sizeof(loadtoc_code);
+#endif
/* patch the branch destination */
ptr = (uint32_t *)jmp_addr;
val = *ptr;
val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
*ptr = val;
+#ifdef __powerpc64__
+ flush_icache_range(jmp_addr-sizeof(loadtoc_code), jmp_addr+4);
+#else
/* 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");
+#endif
}
#elif defined(__i386__)
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long
addr)
@@ -245,15 +285,27 @@
#endif
static inline void tb_set_jmp_target(TranslationBlock *tb,
- int n, unsigned long addr)
+ int n,
+#ifdef __powerpc64__
+ unsigned long toc_addr,
+#endif
+ unsigned long addr)
{
unsigned long offset;
offset = tb->tb_jmp_offset[n];
- tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
+ tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset),
+#ifdef __powerpc64__
+ toc_addr,
+#endif
+ addr);
offset = tb->tb_jmp_offset[n + 2];
if (offset != 0xffff)
- tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
+ tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset),
+#ifdef __powerpc64__
+ toc_addr,
+#endif
+ addr);
}
#else
@@ -273,7 +325,11 @@
/* 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);
+ tb_set_jmp_target(tb, n,
+#ifdef __powerpc64__
+ tb_next->toc_addr,
+#endif
+ (unsigned long)tb_next->tc_ptr);
/* add in TB jmp circular list */
tb->jmp_next[n] = tb_next->jmp_first;
@@ -301,7 +357,25 @@
#define ASM_OP_LABEL_NAME(n, opname) \
ASM_NAME(__op_label) #n "." ASM_NAME(opname)
-#if defined(__powerpc__)
+#if defined(__powerpc64__)
+
+/* we patch the jump instruction directly */
+#define GOTO_TB(opname, tbparam, n)\
+do {\
+ asm volatile (ASM_DATA_SECTION\
+ ASM_OP_LABEL_NAME(n, opname) ":\n"\
+ ".long 1f\n"\
+ ASM_PREVIOUS_SECTION \
+ "nop\n"\
+ "nop\n"\
+ "nop\n"\
+ "nop\n"\
+ "nop\n"\
+ "b " ASM_NAME(__op_jmp) #n "\n"\
+ "1:\n");\
+} while (0)
+
+#elif defined(__powerpc__)
/* we patch the jump instruction directly */
#define GOTO_TB(opname, tbparam, n)\
diff -Nru qemu/exec.c qemu-devel-ppc64/exec.c
--- qemu/exec.c 2006-07-30 21:06:25.000000000 +0300
+++ qemu-devel-ppc64/exec.c 2006-08-02 19:56:24.000000000 +0300
@@ -450,7 +450,11 @@
another TB */
static inline void tb_reset_jump(TranslationBlock *tb, int n)
{
- tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr +
tb->tb_next_offset[n]));
+ tb_set_jmp_target(tb, n,
+#ifdef __powerpc64__
+ tb->toc_addr,
+#endif
+ (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
}
static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int
page_addr)
@@ -591,7 +595,11 @@
tb->cs_base = cs_base;
tb->flags = flags;
tb->cflags = cflags;
- cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
+ cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE,
+#ifdef __powerpc64__
+ &tb->toc_addr,
+#endif
+ &code_gen_size);
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size +
CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
/* check next page if needed */
diff -Nru qemu/linux-user/elfload.c qemu-devel-ppc64/linux-user/elfload.c
--- qemu/linux-user/elfload.c 2006-07-30 21:06:54.000000000 +0300
+++ qemu-devel-ppc64/linux-user/elfload.c 2006-08-02 19:57:37.000000000
+0300
@@ -12,6 +12,18 @@
#include "qemu.h"
#include "disas.h"
+#ifdef __powerpc64__
+#undef elf_check_arch
+#undef ELF_CLASS
+#undef ELF_DATA
+#undef ELF_ARCH
+#undef ELF_PLAT_INIT
+#undef ELF_PLATFORM
+#undef ELF_HWCAP
+#undef R_PPC_NUM
+#undef ARCH_DLINFO
+#endif
+
/* this flag is uneffective under linux too, should be deleted */
#ifndef MAP_DENYWRITE
#define MAP_DENYWRITE 0
diff -Nru qemu/linux-user/mmap.c qemu-devel-ppc64/linux-user/mmap.c
--- qemu/linux-user/mmap.c 2006-04-22 09:30:29.000000000 +0300
+++ qemu-devel-ppc64/linux-user/mmap.c 2006-08-02 19:58:37.000000000 +0300
@@ -157,7 +157,7 @@
target_ulong ret, end, real_start, real_end, retaddr, host_offset,
host_len;
long host_start;
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \
- defined(__ia64)
+ defined(__ia64) || defined(__powerpc64__)
static target_ulong last_start = 0x40000000;
#elif defined(__CYGWIN__)
/* Cygwin doesn't have a whole lot of address space. */
@@ -202,7 +202,7 @@
if (!(flags & MAP_FIXED)) {
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \
- defined(__ia64) || defined(__CYGWIN__)
+ defined(__ia64) || defined(__powerpc64__) || defined(__CYGWIN__)
/* tell the kenel to search at the same place as i386 */
if (real_start == 0) {
real_start = last_start;
diff -Nru qemu/Makefile.target qemu-devel-ppc64/Makefile.target
--- qemu/Makefile.target 2006-08-02 19:32:18.000000000 +0300
+++ qemu-devel-ppc64/Makefile.target 2006-08-02 19:37:07.000000000 +0300
@@ -101,6 +101,12 @@
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
endif
+ifeq ($(ARCH),ppc64)
+CFLAGS+= -D__powerpc__ -D__powerpc64__
+OP_CFLAGS=$(CFLAGS)
+LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc64.ld
+endif
+
ifeq ($(ARCH),s390)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
diff -Nru qemu/ppc_icache.h qemu-devel-ppc64/ppc_icache.h
--- qemu/ppc_icache.h 1970-01-01 02:00:00.000000000 +0200
+++ qemu-devel-ppc64/ppc_icache.h 2006-08-02 20:07:27.000000000 +0300
@@ -0,0 +1,25 @@
+#ifdef __powerpc64__
+#define MIN_CACHE_LINE_SIZE 0x80
+#else
+#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
+#endif
+
+static void inline flush_icache_range(unsigned long start, unsigned long stop)
+{
+ unsigned long 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 volatile ("dcbst 0,%0" : : "r"(p) : "memory");
+ }
+ asm volatile ("sync" : : : "memory");
+ for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
+ asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
+ }
+#ifndef __powerpc64__
+ asm volatile ("sync" : : : "memory");
+#endif
+ asm volatile ("isync" : : : "memory");
+}
diff -Nru qemu/ppc64.ld qemu-devel-ppc64/ppc64.ld
--- qemu/ppc64.ld 1970-01-01 02:00:00.000000000 +0200
+++ qemu-devel-ppc64/ppc64.ld 2006-08-02 20:01:51.000000000 +0300
@@ -0,0 +1,222 @@
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc",
+ "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_start)
+SEARCH_DIR("/usr/powerpc64-unknown-linux-gnu/lib64");
SEARCH_DIR("/usr/lib/binutils/powerpc64-unknown-linux-gnu/2.16.164");
SEARCH_DIR("/usr/local/lib64"); SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/powerpc64-unknown-linux-gnu/lib");
SEARCH_DIR("/usr/lib/binutils/powerpc64-unknown-linux-gnu/2.16.1");
SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
+ *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
+ *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
+ *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.toc)
+ *(.rela.opd)
+ *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+ *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+ *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+ *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .rela.tocbss : { *(.rela.tocbss) }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x60000000
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ KEEP (*(.text.*personality*))
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.sfpr .glink)
+ } =0x60000000
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x60000000
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
+ .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table))
*(.gcc_except_table.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . =
DATA_SEGMENT_ALIGN (0x10000, 0x1000);
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table))
*(.gcc_except_table.*) }
+ /* Thread Local Storage sections */
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(64 / 8);
+ PROVIDE (__preinit_array_start = .);
+ .preinit_array : { KEEP (*(.preinit_array)) }
+ PROVIDE (__preinit_array_end = .);
+ PROVIDE (__init_array_start = .);
+ .init_array : { KEEP (*(.init_array)) }
+ PROVIDE (__init_array_end = .);
+ PROVIDE (__fini_array_start = .);
+ .fini_array : { KEEP (*(.fini_array)) }
+ PROVIDE (__fini_array_end = .);
+ .ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin*.o(.ctors))
+ /* We don't want to include the .ctor section from
+ from the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ .dtors :
+ {
+ KEEP (*crtbegin*.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }
+ .dynamic : { *(.dynamic) }
+ . = DATA_SEGMENT_RELRO_END (0, .);
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ KEEP (*(.gnu.linkonce.d.*personality*))
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ .toc1 ALIGN(8) : { *(.toc1) }
+ .opd ALIGN(8) : { KEEP (*(.opd)) }
+ .got ALIGN(8) : { *(.got .toc) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata :
+ {
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .tocbss ALIGN(8) : { *(.tocbss)}
+ .sbss :
+ {
+ PROVIDE (__sbss_start = .);
+ PROVIDE (___sbss_start = .);
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ PROVIDE (__sbss_end = .);
+ PROVIDE (___sbss_end = .);
+ }
+ .plt : { *(.plt) }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(64 / 8);
+ }
+ . = ALIGN(64 / 8);
+ _end = .;
+ PROVIDE (end = .);
+ . = DATA_SEGMENT_END (.);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff -Nru qemu/translate-all.c qemu-devel-ppc64/translate-all.c
--- qemu/translate-all.c 2005-12-05 21:56:07.000000000 +0200
+++ qemu-devel-ppc64/translate-all.c 2006-08-02 20:02:44.000000000 +0300
@@ -31,6 +31,9 @@
#include "disas.h"
extern int dyngen_code(uint8_t *gen_code_buf,
+#ifdef __powerpc64__
+ uint64_t *toc_addr_ptr,
+#endif
uint16_t *label_offsets, uint16_t *jmp_offsets,
const uint16_t *opc_buf, const uint32_t *opparam_buf,
const long *gen_labels);
@@ -139,7 +142,11 @@
code).
*/
int cpu_gen_code(CPUState *env, TranslationBlock *tb,
- int max_code_size, int *gen_code_size_ptr)
+ int max_code_size,
+#ifdef __powerpc64__
+ uint64_t *toc_addr_ptr,
+#endif
+ int *gen_code_size_ptr)
{
uint8_t *gen_code_buf;
int gen_code_size;
@@ -165,7 +172,11 @@
#endif
dyngen_labels(gen_labels, nb_gen_labels, gen_code_buf, gen_opc_buf);
- gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
+ gen_code_size = dyngen_code(gen_code_buf,
+#ifdef __powerpc64__
+ toc_addr_ptr,
+#endif
+ tb->tb_next_offset,
#ifdef USE_DIRECT_JUMP
tb->tb_jmp_offset,
#else
_______________________________________________
Qemu-devel mailing list
Qemu-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/qemu-devel