From patchwork Mon Aug 24 16:17:28 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 510170 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 275881401C7 for ; Tue, 25 Aug 2015 02:38:06 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=MsUqMBi+; dkim-atps=neutral Received: from localhost ([::1]:55304 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZTul2-0001im-AD for incoming@patchwork.ozlabs.org; Mon, 24 Aug 2015 12:38:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37294) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZTuSG-0002Ag-Nt for qemu-devel@nongnu.org; Mon, 24 Aug 2015 12:18:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZTuSF-0002qw-0t for qemu-devel@nongnu.org; Mon, 24 Aug 2015 12:18:40 -0400 Received: from mail-qk0-x22a.google.com ([2607:f8b0:400d:c09::22a]:35162) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZTuSE-0002qo-Pi for qemu-devel@nongnu.org; Mon, 24 Aug 2015 12:18:38 -0400 Received: by qkbm65 with SMTP id m65so74161760qkb.2 for ; Mon, 24 Aug 2015 09:18:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=Im8R8I99yGoX347jdOiva0SNtHOpSouZpGzuYye1CZA=; b=MsUqMBi+NFSOrz+5azJ+IHWK4yySk4GnWflYP6/EB1nxBnP+Wv7TyziVTe9CnPx33N RlCl4YNLL44dT7RuKrX+d0/X+mHY5kwiwAEtPr1vRlS96Pz4yPbzwJxiqy/uTjMGTkhx uP3Xeh0zJr58cYtnKPmuwL3RnDefqakf0UVBnPTKIddhOoGBkGTKayf1IkpUzS9yXrUT 3qcWY27of8kcDz/AwD4CFglEbJ2Jdv9lrrNQLSMDhJKQ04UKuBVdSLtkItJHJ0IeB6pA vpTUlaDfHmorN8Lz7ic2Gx2/xYURWzyV97aHavMb8jDC3HmZhhs4KF1dAgHDUkvupzcd zOZg== X-Received: by 10.55.195.80 with SMTP id a77mr19859535qkj.2.1440433118444; Mon, 24 Aug 2015 09:18:38 -0700 (PDT) Received: from bigtime.com ([75.147.178.105]) by smtp.gmail.com with ESMTPSA id g76sm11445818qhc.33.2015.08.24.09.18.36 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2015 09:18:37 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Mon, 24 Aug 2015 09:17:28 -0700 Message-Id: <1440433079-14458-3-git-send-email-rth@twiddle.net> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1440433079-14458-1-git-send-email-rth@twiddle.net> References: <1440433079-14458-1-git-send-email-rth@twiddle.net> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400d:c09::22a Cc: walt@tilera.com, cmetcalf@ezchip.com, Chen Gang , xili_gchen_5257@hotmail.com, peter.maydell@linaro.org Subject: [Qemu-devel] [PATCH v14 02/33] 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 From: Chen Gang 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 Reviewed-by: Peter Maydell Message-Id: Signed-off-by: Richard Henderson --- include/elf.h | 2 + linux-user/elfload.c | 23 ++++ linux-user/main.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 14 ++- 4 files changed, 329 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 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..2d4b0b4 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(cs); + 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;