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