From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1FCwAF-0003lY-OU for qemu-devel@nongnu.org; Sat, 25 Feb 2006 04:56:35 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1FCwAB-0003e0-W9 for qemu-devel@nongnu.org; Sat, 25 Feb 2006 04:56:34 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1FCwAA-0003bN-AW for qemu-devel@nongnu.org; Sat, 25 Feb 2006 04:56:31 -0500 Received: from [193.229.0.44] (helo=fep02-app.kolumbus.fi) by monty-python.gnu.org with esmtp (Exim 4.52) id 1FCwAR-0005yN-E4 for qemu-devel@nongnu.org; Sat, 25 Feb 2006 04:56:48 -0500 Received: from [192.168.1.4] (really [80.186.59.4]) by fep02-app.kolumbus.fi with ESMTP id <20060225095623.MFGJ14691.fep02-app.kolumbus.fi@[192.168.1.4]> for ; Sat, 25 Feb 2006 11:56:23 +0200 Message-ID: <440029C7.8060207@cs.helsinki.fi> Date: Sat, 25 Feb 2006 11:56:23 +0200 From: Heikki Lindholm MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------000306090906090604090607" Subject: [Qemu-devel] [PATCH] ppc64 host support Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org This is a multi-part message in MIME format. --------------000306090906090604090607 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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 --------------000306090906090604090607 Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0"; name="qemu-cvs-060225-ppc64host.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="qemu-cvs-060225-ppc64host.patch" 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) { --------------000306090906090604090607--