From patchwork Sat May 30 21:10:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chen Gang X-Patchwork-Id: 478496 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 585EA140F9B for ; Sun, 31 May 2015 07:11:09 +1000 (AEST) Received: from localhost ([::1]:40517 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yyo27-0006T6-CI for incoming@patchwork.ozlabs.org; Sat, 30 May 2015 17:11:07 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47659) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yyo1V-0005SO-N4 for qemu-devel@nongnu.org; Sat, 30 May 2015 17:10:31 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Yyo1O-0005AU-4s for qemu-devel@nongnu.org; Sat, 30 May 2015 17:10:29 -0400 Received: from blu004-omc1s36.hotmail.com ([65.55.116.47]:52895) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yyo1O-0005AI-1M for qemu-devel@nongnu.org; Sat, 30 May 2015 17:10:22 -0400 Received: from BLU437-SMTP108 ([65.55.116.9]) by BLU004-OMC1S36.hotmail.com over TLS secured channel with Microsoft SMTPSVC(7.5.7601.22751); Sat, 30 May 2015 14:10:22 -0700 X-TMN: [SjgwrebZCydO22/MLv1kNWq4i0Kvsby7] X-Originating-Email: [xili_gchen_5257@hotmail.com] Message-ID: Date: Sun, 31 May 2015 05:10:58 +0800 From: Chen Gang User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 MIME-Version: 1.0 To: "rth@twiddle.net" , Peter Maydell , =?UTF-8?B?QW5kcmVhcyBGw6RyYmVy?= , Chris Metcalf References: In-Reply-To: X-OriginalArrivalTime: 30 May 2015 21:10:19.0658 (UTC) FILETIME=[08BB16A0:01D09B1D] X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 65.55.116.47 Cc: "walt@tilera.com" , Riku Voipio , qemu-devel Subject: [Qemu-devel] [PATCH 02/10 v11] linux-user: Support tilegx architecture in linux-user X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add main working flow feature, system call processing feature, and elf64 tilegx binary loading feature, based on Linux kernel tilegx 64-bit implementation. Signed-off-by: Chen Gang --- include/elf.h | 2 + linux-user/elfload.c | 23 +++++ linux-user/main.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 14 ++- 4 files changed, 270 insertions(+), 5 deletions(-) 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 0ba9706..fbf9212 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1189,6 +1189,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 3f32db0..8e7fe86 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3416,6 +3416,231 @@ void cpu_loop(CPUS390XState *env) #endif /* TARGET_S390X */ +#ifdef TARGET_TILEGX + +static uint64_t get_regval(CPUTLGState *env, uint8_t reg) +{ + if (likely(reg < TILEGX_R_COUNT)) { + return env->regs[reg]; + } else if (reg != TILEGX_R_ZERO) { + fprintf(stderr, "invalid register r%d for reading.\n", reg); + g_assert_not_reached(); + } + return 0; +} + +static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val) +{ + if (likely(reg < TILEGX_R_COUNT)) { + env->regs[reg] = val; + } else if (reg != TILEGX_R_ZERO) { + fprintf(stderr, "invalid register r%d for writing.\n", reg); + g_assert_not_reached(); + } +} + +/* + * 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 instruc- tion 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]); + * + * + * For exch(4), will no cmp spr. + */ +static void do_exch(CPUTLGState *env, int8_t quad, int8_t cmp) +{ + uint8_t rdst, rsrc, rsrcb; + target_ulong addr, tmp; + target_long val, sprval; + target_siginfo_t info; + + start_exclusive(); + + rdst = (env->excparam >> 16) & 0xff; + rsrc = (env->excparam >> 8) & 0xff; + rsrcb = env->excparam & 0xff; + + addr = get_regval(env, rsrc); + if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) { + goto do_sigsegv; + } + tmp = (target_ulong)val; /* rdst may be the same to rsrcb, so buffer it */ + + if (cmp) { + if (quad) { + sprval = (target_long)env->spregs[TILEGX_SPR_CMPEXCH]; + } else { + sprval = (int32_t)(env->spregs[TILEGX_SPR_CMPEXCH] & 0xffffffff); + } + } + + if (!cmp || val == sprval) { + val = get_regval(env, rsrcb); + if (quad ? put_user_u64(val, addr) : put_user_u32(val, addr)) { + goto do_sigsegv; + } + } + + set_regval(env, rdst, tmp); + + end_exclusive(); + return; + +do_sigsegv: + end_exclusive(); + + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = addr; + queue_signal(env, TARGET_SIGSEGV, &info); +} + +static void do_fetch(CPUTLGState *env, int trapnr, int8_t quad) +{ + uint8_t rdst, rsrc, rsrcb; + int8_t write = 1; + target_ulong addr; + target_long val, tmp; + target_siginfo_t info; + + start_exclusive(); + + rdst = (env->excparam >> 16) & 0xff; + rsrc = (env->excparam >> 8) & 0xff; + rsrcb = env->excparam & 0xff; + + addr = get_regval(env, rsrc); + if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) { + goto do_sigsegv; + } + tmp = val; /* rdst may be the same to rsrcb, so buffer it */ + + val = get_regval(env, rsrcb); + switch (trapnr) { + case TILEGX_EXCP_OPCODE_FETCHADD: + case TILEGX_EXCP_OPCODE_FETCHADD4: + case TILEGX_EXCP_OPCODE_FETCHADDGEZ: + case TILEGX_EXCP_OPCODE_FETCHADDGEZ4: + val += tmp; + if (trapnr == TILEGX_EXCP_OPCODE_FETCHADDGEZ) { + if (val < 0) { + write = 0; + } + } else if (trapnr == TILEGX_EXCP_OPCODE_FETCHADDGEZ4) { + if ((int32_t)val < 0) { + write = 0; + } + } + break; + case TILEGX_EXCP_OPCODE_FETCHAND: + case TILEGX_EXCP_OPCODE_FETCHAND4: + val &= tmp; + break; + case TILEGX_EXCP_OPCODE_FETCHOR: + case TILEGX_EXCP_OPCODE_FETCHOR4: + val |= tmp; + break; + default: + g_assert_not_reached(); + } + + if (write) { + if (quad ? put_user_u64(val, addr) : put_user_u32(val, addr)) { + goto do_sigsegv; + } + } + + set_regval(env, rdst, tmp); + + end_exclusive(); + return; + +do_sigsegv: + end_exclusive(); + + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = addr; + queue_signal(env, TARGET_SIGSEGV, &info); +} + +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, 1, 0); + break; + case TILEGX_EXCP_OPCODE_EXCH4: + do_exch(env, 0, 0); + break; + case TILEGX_EXCP_OPCODE_CMPEXCH: + do_exch(env, 1, 1); + break; + case TILEGX_EXCP_OPCODE_CMPEXCH4: + do_exch(env, 0, 1); + break; + case TILEGX_EXCP_OPCODE_FETCHADD: + do_fetch(env, trapnr, 1); + break; + case TILEGX_EXCP_OPCODE_FETCHADDGEZ: + case TILEGX_EXCP_OPCODE_FETCHAND: + case TILEGX_EXCP_OPCODE_FETCHOR: + do_fetch(env, trapnr, 1); + exit(1); + 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, 0); + exit(1); + 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) @@ -4389,6 +4614,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;