qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] ppc64 host support


From: Heikki Lindholm
Subject: [Qemu-devel] [PATCH] ppc64 host support
Date: Thu, 03 Aug 2006 22:01:09 +0300
User-agent: Mozilla Thunderbird 1.0.7 (Macintosh/20050923)

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)@address@hidden */
+#define R_PPC64_TPREL16_HI     71 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HA     72 /* half16    (sym+add)@address@hidden */
+#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)@address@hidden */
+#define R_PPC64_DTPREL16_HI    76 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HA    77 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_DTPREL64       78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16    79 /* half16*   (sym+add)@address@hidden */
+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16    (sym+add)@address@hidden@l */
+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16    (sym+add)@address@hidden@h */
+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16    (sym+add)@address@hidden@ha */
+#define R_PPC64_GOT_TLSLD16    83 /* half16*   (sym+add)@address@hidden */
+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16    (sym+add)@address@hidden@l */
+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16    (sym+add)@address@hidden@h */
+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16    (sym+add)@address@hidden@ha */
+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@address@hidden */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@address@hidden@l */
+#define R_PPC64_GOT_TPREL16_HI 89 /* half16    (sym+add)@address@hidden@h */
+#define R_PPC64_GOT_TPREL16_HA 90 /* half16    (sym+add)@address@hidden@ha */
+#define R_PPC64_GOT_DTPREL16_DS        91 /* half16ds* 
(sym+add)@address@hidden */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@address@hidden@l */
+#define R_PPC64_GOT_DTPREL16_HI        93 /* half16    
(sym+add)@address@hidden@h */
+#define R_PPC64_GOT_DTPREL16_HA        94 /* half16    
(sym+add)@address@hidden@ha */
+#define R_PPC64_TPREL16_DS     95 /* half16ds* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS  96 /* half16ds  (sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HIGHER 97 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HIGHERA        98 /* half16    
(sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HIGHEST        99 /* half16    
(sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_DS    101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HIGHER        103 /* half16   
(sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16        
(sym+add)@address@hidden */
+
+/* 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

reply via email to

[Prev in Thread] Current Thread [Next in Thread]