diff --git a/include/elf.h b/include/elf.h
index 4afd474..79859f0 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -133,6 +133,8 @@ typedef int64_t Elf64_Sxword;

#define EM_AARCH64 183

+#define EM_TILEGX 191 /* TILE-Gx */
+
/* This is the info that is needed to parse the dynamic section of the file */
#define DT_NULL 0
#define DT_NEEDED 1
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 1788368..bfb8d1f 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1218,6 +1218,29 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i

#endif /* TARGET_S390X */

+#ifdef TARGET_TILEGX
+
+/* 42 bits real used address, a half for user mode */
+#define ELF_START_MMAP (0x00000020000000000ULL)
+
+#define elf_check_arch(x) ((x) == EM_TILEGX)
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_TILEGX
+
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
+{
+ regs->pc = infop->entry;
+ regs->sp = infop->start_stack;
+
+}
+
+#define ELF_EXEC_PAGESIZE 65536 /* TILE-Gx page size is 64KB */
+
+#endif /* TARGET_TILEGX */
+
#ifndef ELF_PLATFORM
#define ELF_PLATFORM (NULL)
#endif
diff --git a/linux-user/main.c b/linux-user/main.c
index fdee981..253aade 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3411,6 +3411,290 @@ void cpu_loop(CPUS390XState *env)

#endif /* TARGET_S390X */

+#ifdef TARGET_TILEGX
+
+static void gen_sigsegv_mapper(CPUTLGState *env, target_ulong addr)
+{
+ target_siginfo_t info;
+
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = addr;
+ queue_signal(env, info.si_signo, &info);
+}
+
+static void gen_sigill_reg(CPUTLGState *env)
+{
+ target_siginfo_t info;
+
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_PRVREG;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, &info);
+}
+
+static int get_regval(CPUTLGState *env, uint8_t reg, target_ulong *val)
+{
+ if (likely(reg < TILEGX_R_COUNT)) {
+ *val = env->regs[reg];
+ return 0;
+ }
+
+ switch (reg) {
+ case TILEGX_R_SN:
+ case TILEGX_R_ZERO:
+ *val = 0;
+ return 0;
+ case TILEGX_R_IDN0:
+ case TILEGX_R_IDN1:
+ case TILEGX_R_UDN0:
+ case TILEGX_R_UDN1:
+ case TILEGX_R_UDN2:
+ case TILEGX_R_UDN3:
+ return -1;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static int set_regval(CPUTLGState *env, uint8_t reg, uint64_t val)
+{
+ if (unlikely(reg>= TILEGX_R_COUNT)) {
+ switch (reg) {
+ case TILEGX_R_SN:
+ case TILEGX_R_ZERO:
+ return 0;
+ case TILEGX_R_IDN0:
+ case TILEGX_R_IDN1:
+ case TILEGX_R_UDN0:
+ case TILEGX_R_UDN1:
+ case TILEGX_R_UDN2:
+ case TILEGX_R_UDN3:
+ return -1;
+ default:
+ g_assert_not_reached();
+ }
+ }
+
+ env->regs[reg] = val;
+ return 0;
+}
+
+/*
+ * Compare the 8-byte contents of the CmpValue SPR with the 8-byte value in
+ * memory at the address held in the first source register. If the values are
+ * not equal, then no memory operation is performed. If the values are equal,
+ * the 8-byte quantity from the second source register is written into memory
+ * at the address held in the first source register. In either case, the result
+ * of the instruction is the value read from memory. The compare and write to
+ * memory are atomic and thus can be used for synchronization purposes. This
+ * instruction only operates for addresses aligned to a 8-byte boundary.
+ * Unaligned memory access causes an Unaligned Data Reference interrupt.
+ *
+ * Functional Description (64-bit)
+ * uint64_t memVal = memoryReadDoubleWord (rf[SrcA]);
+ * rf[Dest] = memVal;
+ * if (memVal == SPR[CmpValueSPR])
+ * memoryWriteDoubleWord (rf[SrcA], rf[SrcB]);
+ *
+ * Functional Description (32-bit)
+ * uint64_t memVal = signExtend32 (memoryReadWord (rf[SrcA]));
+ * rf[Dest] = memVal;
+ * if (memVal == signExtend32 (SPR[CmpValueSPR]))
+ * memoryWriteWord (rf[SrcA], rf[SrcB]);
+ *
+ *
+ * This function also processes exch and exch4 which need not process SPR.
+ */
+static void do_exch(CPUTLGState *env, bool quad, bool cmp)
+{
+ uint8_t rdst, rsrc, rsrcb;
+ target_ulong addr;
+ target_long val, sprval;
+
+ start_exclusive();
+
+ rdst = extract32(env->excparam, 16, 8);
+ rsrc = extract32(env->excparam, 8, 8);
+ rsrcb = extract32(env->excparam, 0, 8);
+
+ if (get_regval(env, rsrc, &addr)) {
+ goto sigill_reg;
+ }
+ if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
+ goto sigsegv_mapper;
+ }
+
+ if (cmp) {
+ if (quad) {
+ sprval = env->spregs[TILEGX_SPR_CMPEXCH];
+ } else {
+ sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32);
+ }
+ }
+
+ if (!cmp || val == sprval) {
+ target_long valb;
+
+ if (get_regval(env, rsrcb, (target_ulong *)&valb)) {
+ goto sigill_reg;
+ }
+ if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
+ goto sigsegv_mapper;
+ }
+ }
+
+ if (set_regval(env, rdst, val)) {
+ goto sigill_reg;
+ }
+ end_exclusive();
+ return;
+
+sigill_reg:
+ end_exclusive();
+ gen_sigill_reg(env);
+ return;
+
+sigsegv_mapper:
+ end_exclusive();
+ gen_sigsegv_mapper(env, addr);
+}
+
+static void do_fetch(CPUTLGState *env, int trapnr, bool quad)
+{
+ uint8_t rdst, rsrc, rsrcb;
+ int8_t write = 1;
+ target_ulong addr;
+ target_long val, valb;
+
+ start_exclusive();
+
+ rdst = extract32(env->excparam, 16, 8);
+ rsrc = extract32(env->excparam, 8, 8);
+ rsrcb = extract32(env->excparam, 0, 8);
+
+
+ if (get_regval(env, rsrc, &addr)) {
+ goto sigill_reg;
+ }
+ if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
+ goto sigsegv_mapper;
+ }
+
+ if (get_regval(env, rsrcb, (target_ulong *)&valb)) {
+ goto sigill_reg;
+ }
+ switch (trapnr) {
+ case TILEGX_EXCP_OPCODE_FETCHADD:
+ case TILEGX_EXCP_OPCODE_FETCHADD4:
+ valb += val;
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
+ valb += val;
+ if (valb < 0) {
+ write = 0;
+ }
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
+ valb += val;
+ if ((int32_t)valb < 0) {
+ write = 0;
+ }
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHAND:
+ case TILEGX_EXCP_OPCODE_FETCHAND4:
+ valb &= val;
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHOR:
+ case TILEGX_EXCP_OPCODE_FETCHOR4:
+ valb |= val;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (write) {
+ if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
+ goto sigsegv_mapper;
+ }
+ }
+
+ if (set_regval(env, rdst, val)) {
+ goto sigill_reg;
+ }
+ end_exclusive();
+ return;
+
+sigill_reg:
+ end_exclusive();
+ gen_sigill_reg(env);
+ return;
+
+sigsegv_mapper:
+ end_exclusive();
+ gen_sigsegv_mapper(env, addr);
+}
+
+void cpu_loop(CPUTLGState *env)
+{
+ CPUState *cs = CPU(tilegx_env_get_cpu(env));
+ int trapnr;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_tilegx_exec(env);
+ cpu_exec_end(cs);
+ switch (trapnr) {
+ case TILEGX_EXCP_SYSCALL:
+ env->regs[TILEGX_R_RE] = do_syscall(env, env->regs[TILEGX_R_NR],
+ env->regs[0], env->regs[1],
+ env->regs[2], env->regs[3],
+ env->regs[4], env->regs[5],
+ env->regs[6], env->regs[7]);
+ env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(env->regs[TILEGX_R_RE])
+ ? env->regs[TILEGX_R_RE]
+ : 0;
+ break;
+ case TILEGX_EXCP_OPCODE_EXCH:
+ do_exch(env, true, false);
+ break;
+ case TILEGX_EXCP_OPCODE_EXCH4:
+ do_exch(env, false, false);
+ break;
+ case TILEGX_EXCP_OPCODE_CMPEXCH:
+ do_exch(env, true, true);
+ break;
+ case TILEGX_EXCP_OPCODE_CMPEXCH4:
+ do_exch(env, false, true);
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADD:
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
+ case TILEGX_EXCP_OPCODE_FETCHAND:
+ case TILEGX_EXCP_OPCODE_FETCHOR:
+ do_fetch(env, trapnr, true);
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADD4:
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
+ case TILEGX_EXCP_OPCODE_FETCHAND4:
+ case TILEGX_EXCP_OPCODE_FETCHOR4:
+ do_fetch(env, trapnr, false);
+ break;
+ case TILEGX_EXCP_REG_IDN_ACCESS:
+ case TILEGX_EXCP_REG_UDN_ACCESS:
+ gen_sigill_reg(env);
+ break;
+ default:
+ fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);
+ g_assert_not_reached();
+ }
+ process_pending_signals(env);
+ }
+}
+
+#endif
+
THREAD CPUState *thread_cpu;

void task_settid(TaskState *ts)
@@ -4386,6 +4670,17 @@ int main(int argc, char **argv, char **envp)
env->psw.mask = regs->psw.mask;
env->psw.addr = regs->psw.addr;
}
+#elif defined(TARGET_TILEGX)
+ {
+ int i;
+ for (i = 0; i < TILEGX_R_COUNT; i++) {
+ env->regs[i] = regs->regs[i];
+ }
+ for (i = 0; i < TILEGX_SPR_COUNT; i++) {
+ env->spregs[i] = 0;
+ }
+ env->pc = regs->pc;
+ }
#else
#error unsupported target CPU
#endif
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index edd5f3c..e6af073 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -64,8 +64,9 @@
#endif

#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \
- || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) \
- || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
+ || defined(TARGET_M68K) || defined(TARGET_CRIS) \
+ || defined(TARGET_UNICORE32) || defined(TARGET_S390X) \
+ || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)

#define TARGET_IOC_SIZEBITS 14
#define TARGET_IOC_DIRBITS 2
@@ -365,7 +366,8 @@ int do_sigaction(int sig, const struct target_sigaction *act,
|| defined(TARGET_PPC) || defined(TARGET_MIPS) || defined(TARGET_SH4) \
|| defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) \
|| defined(TARGET_MICROBLAZE) || defined(TARGET_UNICORE32) \
- || defined(TARGET_S390X) || defined(TARGET_OPENRISC)
+ || defined(TARGET_S390X) || defined(TARGET_OPENRISC) \
+ || defined(TARGET_TILEGX)

#if defined(TARGET_SPARC)
#define TARGET_SA_NOCLDSTOP 8u
@@ -1871,7 +1873,7 @@ struct target_stat {
abi_ulong target_st_ctime_nsec;
unsigned int __unused[2];
};
-#elif defined(TARGET_OPENRISC)
+#elif defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)

/* These are the asm-generic versions of the stat and stat64 structures */

@@ -2264,7 +2266,9 @@ struct target_flock {
struct target_flock64 {
short l_type;
short l_whence;
-#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) || defined(TARGET_SPARC) || defined(TARGET_HPPA) || defined (TARGET_MICROBLAZE)
+#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) \
+ || defined(TARGET_SPARC) || defined(TARGET_HPPA) \
+ || defined(TARGET_MICROBLAZE) || defined(TARGET_TILEGX)
int __pad;
#endif
unsigned long long l_start;
