qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] ppc64 host support
@ 2006-02-25  9:56 Heikki Lindholm
  0 siblings, 0 replies; 2+ messages in thread
From: Heikki Lindholm @ 2006-02-25  9:56 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 479 bytes --]

In case someone else has interest in this, a preliminary patch for 
64-bit powerpc host _with_ 64-bit userland, eg. gentoo/ppc64. A bit 
unclean, because some functions needed one argument to be appended. 
Compiles at least i386-user+softmmu and powerpc-softmmu. i386-softmmu 
boots sarge i386 netinst, but has some trouble after keyboard selection, 
i386-user runs 'ls'. The configure changes rudely destroy building on 
ppc 64-bit kernel + 32-bit userland.

-- Heikki Lindholm

[-- Attachment #2: qemu-cvs-060225-ppc64host.patch --]
[-- Type: text/plain, Size: 51007 bytes --]

diff -Nru qemu-cvs/configure qemu-devel-ppc64/configure
--- qemu-cvs/configure	2006-02-09 19:58:47.000000000 +0200
+++ qemu-devel-ppc64/configure	2006-02-24 19:26:18.000000000 +0200
@@ -41,9 +41,12 @@
   alpha)
     cpu="alpha"
   ;;
-  "Power Macintosh"|ppc|ppc64)
+  "Power Macintosh"|ppc)
     cpu="powerpc"
   ;;
+  ppc64)
+    cpu="powerpc64"
+  ;;
   mips)
     cpu="mips"
   ;;
@@ -262,7 +265,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
 
@@ -270,7 +273,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
 
@@ -501,6 +504,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-cvs/cpu-exec.c qemu-devel-ppc64/cpu-exec.c
--- qemu-cvs/cpu-exec.c	2006-02-20 02:33:36.000000000 +0200
+++ qemu-devel-ppc64/cpu-exec.c	2006-02-25 10:37:03.000000000 +0200
@@ -83,6 +83,9 @@
     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);
 
@@ -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;
@@ -253,6 +263,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;
@@ -649,6 +662,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;
@@ -739,6 +755,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-cvs/dyngen.c qemu-devel-ppc64/dyngen.c
--- qemu-cvs/dyngen.c	2006-02-04 22:47:57.000000000 +0200
+++ qemu-devel-ppc64/dyngen.c	2006-02-25 10:37:59.000000000 +0200
@@ -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,9 @@
     ElfW(Sym) *sym;
     char *shstr;
     ELF_RELOC *rel;
+    struct elf_shdr *toc_sec;
+    int toc_shndx;
+    uint8_t *toc;
     
     fd = open(filename, O_RDONLY);
     if (fd < 0) 
@@ -552,6 +608,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 +1279,7 @@
     }
 }
 
-#ifdef HOST_IA64
+#if defined(HOST_IA64) || defined(HOST_PPC64)
 
 #define PLT_ENTRY_SIZE	16	/* 1 bundle containing "brl" */
 
@@ -1393,11 +1467,15 @@
         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);
-        if (p == p_start)
+#endif
+	if (p == p_start)
             error("empty code for %s", name);
         if (get32((uint32_t *)p) != 0x4e800020)
             error("blr expected at the end of %s", name);
@@ -1610,6 +1688,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
@@ -1617,8 +1702,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 */
         {
@@ -1798,7 +1888,7 @@
                 }
                 }
             }
-#elif defined(HOST_PPC)
+#elif defined(HOST_PPC) || defined(HOST_PPC64)
             {
 #ifdef CONFIG_FORMAT_ELF
                 char name[256];
@@ -1808,7 +1898,8 @@
                 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;
+                        EXE_RELOC *toc_entry;
+                        sym_name = get_rel_sym_name(rel);
                         reloc_offset = rel->r_offset - start_offset;
                         if (strstart(sym_name, "__op_jmp", &p)) {
                             int n;
@@ -1823,7 +1914,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:
@@ -1843,10 +1938,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);
                         }
@@ -2319,6 +2437,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);
             }
         }
@@ -2333,14 +2454,22 @@
                 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);
             }
         }
         
     } else {
         /* generate big code generation switch */
+#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"
@@ -2354,7 +2483,8 @@
 "    LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
 "    uint32_t *arm_data_ptr = arm_data_table;\n");
 #endif
-#ifdef HOST_IA64
+
+#if defined(HOST_IA64) || defined(HOST_PPC64)
     {
 	long addend, not_first = 0;
 	unsigned long sym_idx;
@@ -2367,9 +2497,17 @@
 	    sym_idx = ELF64_R_SYM(rel->r_info);
 	    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);
@@ -2379,19 +2517,34 @@
 	    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++) {
 	    sym_idx = ELF64_R_SYM(rel->r_info);
 	    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);
@@ -2437,6 +2590,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);
             }
         }
@@ -2473,6 +2629,13 @@
 "    }\n"
 " the_end:\n"
 );
+#ifdef HOST_PPC64
+    fprintf(outfile,
+            "    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,
 	    "    ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
diff -Nru qemu-cvs/dyngen-exec.h qemu-devel-ppc64/dyngen-exec.h
--- qemu-cvs/dyngen-exec.h	2005-07-24 18:11:38.000000000 +0300
+++ qemu-devel-ppc64/dyngen-exec.h	2006-02-23 10:06:09.000000000 +0200
@@ -29,7 +29,7 @@
 typedef unsigned short uint16_t;
 typedef unsigned int uint32_t;
 /* 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;
@@ -38,7 +38,7 @@
 typedef signed char int8_t;
 typedef signed short int16_t;
 typedef signed int int32_t;
-#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-cvs/dyngen.h qemu-devel-ppc64/dyngen.h
--- qemu-cvs/dyngen.h	2005-04-08 01:20:28.000000000 +0300
+++ qemu-devel-ppc64/dyngen.h	2006-02-25 10:58:47.000000000 +0200
@@ -53,25 +53,8 @@
 
 #ifdef __powerpc__
 
-#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
+#include "ppc_icache.h"
 
-static void inline flush_icache_range(unsigned long start, unsigned long stop)
-{
-    unsigned long p;
-
-    p = start & ~(MIN_CACHE_LINE_SIZE - 1);
-    stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
-    
-    for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
-        asm 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");
-}
 #endif
 
 #ifdef __alpha__
@@ -210,6 +193,143 @@
 
 #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-cvs/elf.h qemu-devel-ppc64/elf.h
--- qemu-cvs/elf.h	2005-07-02 17:56:31.000000000 +0300
+++ qemu-devel-ppc64/elf.h	2006-02-23 10:01:03.000000000 +0200
@@ -449,6 +449,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)@tprel@l */
+#define R_PPC64_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
+#define R_PPC64_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
+#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)@dtprel@l */
+#define R_PPC64_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
+#define R_PPC64_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
+#define R_PPC64_DTPREL64	78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
+#define R_PPC64_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
+#define R_PPC64_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
+#define R_PPC64_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
+#define R_PPC64_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
+#define R_PPC64_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
+#define R_PPC64_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
+#define R_PPC64_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
+#define R_PPC64_GOT_TPREL16_DS	87 /* half16ds*	(sym+add)@got@tprel */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
+#define R_PPC64_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
+#define R_PPC64_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
+#define R_PPC64_GOT_DTPREL16_DS	91 /* half16ds*	(sym+add)@got@dtprel */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
+#define R_PPC64_GOT_DTPREL16_HI	93 /* half16	(sym+add)@got@dtprel@h */
+#define R_PPC64_GOT_DTPREL16_HA	94 /* half16	(sym+add)@got@dtprel@ha */
+#define R_PPC64_TPREL16_DS	95 /* half16ds*	(sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS	96 /* half16ds	(sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HIGHER	97 /* half16	(sym+add)@tprel@higher */
+#define R_PPC64_TPREL16_HIGHERA	98 /* half16	(sym+add)@tprel@highera */
+#define R_PPC64_TPREL16_HIGHEST	99 /* half16	(sym+add)@tprel@highest */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16	(sym+add)@tprel@highesta */
+#define R_PPC64_DTPREL16_DS	101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS	102 /* half16ds	(sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HIGHER	103 /* half16	(sym+add)@dtprel@higher */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16	(sym+add)@dtprel@highera */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16	(sym+add)@dtprel@highest */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16	(sym+add)@dtprel@highesta */
+
+/* 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-cvs/exec-all.h qemu-devel-ppc64/exec-all.h
--- qemu-cvs/exec-all.h	2006-02-09 00:43:39.000000000 +0200
+++ qemu-devel-ppc64/exec-all.h	2006-02-23 12:02:05.000000000 +0200
@@ -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 immeadite 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-cvs/exec.c qemu-devel-ppc64/exec.c
--- qemu-cvs/exec.c	2006-02-09 00:43:39.000000000 +0200
+++ qemu-devel-ppc64/exec.c	2006-02-24 20:50:59.000000000 +0200
@@ -439,7 +439,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)
@@ -580,7 +584,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-cvs/linux-user/elfload.c qemu-devel-ppc64/linux-user/elfload.c
--- qemu-cvs/linux-user/elfload.c	2006-02-04 22:46:24.000000000 +0200
+++ qemu-devel-ppc64/linux-user/elfload.c	2006-02-25 10:58:53.000000000 +0200
@@ -13,6 +13,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-cvs/linux-user/mmap.c qemu-devel-ppc64/linux-user/mmap.c
--- qemu-cvs/linux-user/mmap.c	2006-02-04 22:46:24.000000000 +0200
+++ qemu-devel-ppc64/linux-user/mmap.c	2006-02-24 19:27:48.000000000 +0200
@@ -153,7 +153,7 @@
 {
     unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
 #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \
-    defined(__ia64)
+    defined(__ia64) || defined(__powerpc64__)
     static unsigned long last_start = 0x40000000;
 #endif
 
@@ -195,7 +195,7 @@
 
     if (!(flags & MAP_FIXED)) {
 #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \
-    defined(__ia64)
+    defined(__ia64) || defined(__powerpc64__)
         /* tell the kenel to search at the same place as i386 */
         if (host_start == 0) {
             host_start = last_start;
diff -Nru qemu-cvs/linux-user/syscall.c qemu-devel-ppc64/linux-user/syscall.c
--- qemu-cvs/linux-user/syscall.c	2006-02-09 18:49:55.000000000 +0200
+++ qemu-devel-ppc64/linux-user/syscall.c	2006-02-23 14:40:20.000000000 +0200
@@ -87,18 +87,21 @@
 #undef __sc_loadargs_3
 #undef __sc_loadargs_4
 #undef __sc_loadargs_5
+#undef __sc_loadargs_6
 #undef __sc_asm_input_0
 #undef __sc_asm_input_1
 #undef __sc_asm_input_2
 #undef __sc_asm_input_3
 #undef __sc_asm_input_4
 #undef __sc_asm_input_5
+#undef __sc_asm_input_6
 #undef _syscall0
 #undef _syscall1
 #undef _syscall2
 #undef _syscall3
 #undef _syscall4
 #undef _syscall5
+#undef _syscall6
 
 /* need to redefine syscalls as Linux kernel defines are incorrect for
    the clobber list */
@@ -117,6 +120,7 @@
 		register unsigned long __sc_5  __asm__ ("r5");		\
 		register unsigned long __sc_6  __asm__ ("r6");		\
 		register unsigned long __sc_7  __asm__ ("r7");		\
+		register unsigned long __sc_8  __asm__ ("r8");		\
 									\
 		__sc_loadargs_##nr(name, args);				\
 		__asm__ __volatile__					\
@@ -125,10 +129,10 @@
 			: "=&r" (__sc_0),				\
 			  "=&r" (__sc_3),  "=&r" (__sc_4),		\
 			  "=&r" (__sc_5),  "=&r" (__sc_6),		\
-			  "=&r" (__sc_7)				\
+			  "=&r" (__sc_7),  "=&r" (__sc_8)		\
 			: __sc_asm_input_##nr				\
 			: "cr0", "ctr", "memory",			\
-			  "r8", "r9", "r10","r11", "r12");		\
+			  "r9", "r10","r11", "r12");			\
 		__sc_ret = __sc_3;					\
 		__sc_err = __sc_0;					\
 	}								\
@@ -156,6 +160,9 @@
 #define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5)		\
 	__sc_loadargs_4(name, arg1, arg2, arg3, arg4);			\
 	__sc_7 = (unsigned long) (arg5)
+#define __sc_loadargs_6(name, arg1, arg2, arg3, arg4, arg5, arg6)	\
+	__sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5);		\
+	__sc_8 = (unsigned long) (arg6)
 
 #define __sc_asm_input_0 "0" (__sc_0)
 #define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3)
@@ -163,6 +170,7 @@
 #define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5)
 #define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6)
 #define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7)
+#define __sc_asm_input_6 __sc_asm_input_5, "6" (__sc_8)
 
 #define _syscall0(type,name)						\
 type name(void)								\
@@ -199,6 +207,11 @@
 {									\
 	__syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5);	\
 }
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \
+{									\
+	__syscall_nr(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \
+}
 #endif
 
 #define __NR_sys_uname __NR_uname
diff -Nru qemu-cvs/Makefile.target qemu-devel-ppc64/Makefile.target
--- qemu-cvs/Makefile.target	2006-02-06 06:11:15.000000000 +0200
+++ qemu-devel-ppc64/Makefile.target	2006-02-24 19:14:18.000000000 +0200
@@ -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-cvs/ppc_icache.h qemu-devel-ppc64/ppc_icache.h
--- qemu-cvs/ppc_icache.h	1970-01-01 02:00:00.000000000 +0200
+++ qemu-devel-ppc64/ppc_icache.h	2006-02-23 11:54:21.000000000 +0200
@@ -0,0 +1,26 @@
+#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;
+
+    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-cvs/ppc64.ld qemu-devel-ppc64/ppc64.ld
--- qemu-cvs/ppc64.ld	1970-01-01 02:00:00.000000000 +0200
+++ qemu-devel-ppc64/ppc64.ld	2006-02-24 19:28:11.000000000 +0200
@@ -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-cvs/translate-all.c qemu-devel-ppc64/translate-all.c
--- qemu-cvs/translate-all.c	2005-12-05 21:56:07.000000000 +0200
+++ qemu-devel-ppc64/translate-all.c	2006-02-23 09:39:10.000000000 +0200
@@ -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
diff -Nru qemu-cvs/vl.c qemu-devel-ppc64/vl.c
--- qemu-cvs/vl.c	2006-02-20 02:33:36.000000000 +0200
+++ qemu-devel-ppc64/vl.c	2006-02-24 20:50:41.000000000 +0200
@@ -506,7 +506,16 @@
 /***********************************************************/
 /* timers */
 
-#if defined(__powerpc__)
+#if defined(__powerpc64__)
+
+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) 
 {

^ permalink raw reply	[flat|nested] 2+ messages in thread
* [Qemu-devel] [PATCH] ppc64 host support
@ 2006-08-03 19:01 Heikki Lindholm
  0 siblings, 0 replies; 2+ messages in thread
From: Heikki Lindholm @ 2006-08-03 19:01 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 222 bytes --]

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

[-- Attachment #2: qemu-060803-ppc64host.patch --]
[-- Type: text/plain, Size: 48455 bytes --]

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

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2006-08-03 19:01 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-02-25  9:56 [Qemu-devel] [PATCH] ppc64 host support Heikki Lindholm
  -- strict thread matches above, loose matches on Subject: below --
2006-08-03 19:01 Heikki Lindholm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).