qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH] ppc64 host support


From: Heikki Lindholm
Subject: [Qemu-devel] [PATCH] ppc64 host support
Date: Sat, 25 Feb 2006 11:56:23 +0200
User-agent: Mozilla Thunderbird 1.0.7 (Macintosh/20050923)

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
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)@address@hidden */
+#define R_PPC64_TPREL16_HI     71 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HA     72 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_TPREL64                73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16       74 /* half16*   (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO    75 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HI    76 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HA    77 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_DTPREL64       78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16    79 /* half16*   (sym+add)@address@hidden */
+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16    (sym+add)@address@hidden@l */
+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16    (sym+add)@address@hidden@h */
+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16    (sym+add)@address@hidden@ha */
+#define R_PPC64_GOT_TLSLD16    83 /* half16*   (sym+add)@address@hidden */
+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16    (sym+add)@address@hidden@l */
+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16    (sym+add)@address@hidden@h */
+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16    (sym+add)@address@hidden@ha */
+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@address@hidden */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@address@hidden@l */
+#define R_PPC64_GOT_TPREL16_HI 89 /* half16    (sym+add)@address@hidden@h */
+#define R_PPC64_GOT_TPREL16_HA 90 /* half16    (sym+add)@address@hidden@ha */
+#define R_PPC64_GOT_DTPREL16_DS        91 /* half16ds* 
(sym+add)@address@hidden */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@address@hidden@l */
+#define R_PPC64_GOT_DTPREL16_HI        93 /* half16    
(sym+add)@address@hidden@h */
+#define R_PPC64_GOT_DTPREL16_HA        94 /* half16    
(sym+add)@address@hidden@ha */
+#define R_PPC64_TPREL16_DS     95 /* half16ds* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS  96 /* half16ds  (sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HIGHER 97 /* half16    (sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HIGHERA        98 /* half16    
(sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HIGHEST        99 /* half16    
(sym+add)@address@hidden */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_DS    101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HIGHER        103 /* half16   
(sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@address@hidden */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16        
(sym+add)@address@hidden */
+
+/* Keep this the last entry.  */
+#define R_PPC64_NUM            107
+
+/* PowerPC64 specific values for the Dyn d_tag field.  */
+#define DT_PPC64_GLINK  (DT_LOPROC + 0)
+#define DT_PPC64_OPD   (DT_LOPROC + 1)
+#define DT_PPC64_OPDSZ (DT_LOPROC + 2)
+#define DT_PPC64_NUM    3
+
 /* ARM specific declarations */
 
 /* Processor specific flags for the ELF header e_flags field.  */
diff -Nru qemu-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) 
 {

reply via email to

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