Message ID | BLU437-SMTP1086ADDBFC233B4DD108B9BB9C80@phx.gbl |
---|---|
State | New |
Headers | show |
On 30 May 2015 at 22:10, Chen Gang <xili_gchen_5257@hotmail.com> wrote: > 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 <gang.chen.5i5j@gmail.com> > --- > 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(); You don't appear to be guaranteeing that the register value is < TILEGX_R_COUNT anywhere: get_SrcA_X1() and friends mask with 0x3f, but that only means you're guaranteed the value is between 0 and 63, wherease TILEGX_R_COUNT is 56. What does real hardware do if the encoded register value is 56..63 ? Also, if (something) { g_assert_not_reached(); } is an awkward way to write g_assert(!something); > + } > + 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 stray "- ". > + * 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. Not sure what this sentence means? > + */ > +static void do_exch(CPUTLGState *env, int8_t quad, int8_t cmp) quad and cmp are just booleans, right? Why int8_t not bool? > +{ > + 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; Consider extract32(). > + > + 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 */ Why do this, when we could just use a different variable rather than trashing val below? > + > + if (cmp) { > + if (quad) { > + sprval = (target_long)env->spregs[TILEGX_SPR_CMPEXCH]; Pointless cast. > + } else { > + sprval = (int32_t)(env->spregs[TILEGX_SPR_CMPEXCH] & 0xffffffff); Clearer as sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32); > + } > + } > + > + if (!cmp || val == sprval) { > + val = get_regval(env, rsrcb); If you say "target_long srcbval = ..." you don't trash val. > + 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 */ Again, unnecessary copy when you could just use a different variable for the value in rsrcb. > + 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; > + } > + } Just give these their own case blocks rather than writing an if() that's conditioned on the same variable we're switching on. The only duplication you're saving is a single line addition. > + 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); these should be true, false assuming you change the arg type to bool. > + 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); Again. > + 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; > -- > 1.9.3 thanks -- PMM
On 06/03/2015 01:40 AM, Peter Maydell wrote: > On 30 May 2015 at 22:10, Chen Gang <xili_gchen_5257@hotmail.com> wrote: >> >> +#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(); > > You don't appear to be guaranteeing that the register value > is < TILEGX_R_COUNT anywhere: get_SrcA_X1() and friends > mask with 0x3f, but that only means you're guaranteed the > value is between 0 and 63, wherease TILEGX_R_COUNT is 56. > What does real hardware do if the encoded register value > is 56..63 ? > At present, it will g_assert_not_reached() too. 56..62 are hidden to outside. So I did not implement them, either. Need we still implement them? For 63, it is zero register, we need do nothing for it. > Also, if (something) { > g_assert_not_reached(); > } > > is an awkward way to write > g_assert(!something); > OK, thanks. The code above is fine to me. >> + >> +/* >> + * 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 > > stray "- ". > OK, thanks. >> + * 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. > > Not sure what this sentence means? > This function also process exch and exch4 which need not process SPR. I guess, the comments needs to be improved (provide more details). >> + */ >> +static void do_exch(CPUTLGState *env, int8_t quad, int8_t cmp) > > quad and cmp are just booleans, right? Why int8_t not bool? > OK, thanks. I will change to bool in qemu. I often use char or int instead of bool. For the latest C, bool is better. >> +{ >> + 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; > > Consider extract32(). > OK, thanks. It sounds good. >> + >> + 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 */ > > Why do this, when we could just use a different variable > rather than trashing val below? > OK, thanks, the code need rewrite a little, just like you said below. >> + >> + if (cmp) { >> + if (quad) { >> + sprval = (target_long)env->spregs[TILEGX_SPR_CMPEXCH]; > > Pointless cast. > OK, thanks. >> + } else { >> + sprval = (int32_t)(env->spregs[TILEGX_SPR_CMPEXCH] & 0xffffffff); > > Clearer as > sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32); > OK, thanks. >> + } >> + } >> + >> + if (!cmp || val == sprval) { >> + val = get_regval(env, rsrcb); > > If you say "target_long srcbval = ..." you don't trash val. > OK, thanks. >> + 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 */ > > Again, unnecessary copy when you could just use a different > variable for the value in rsrcb. > OK, thanks. >> + 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; >> + } >> + } > > Just give these their own case blocks rather than > writing an if() that's conditioned on the same variable > we're switching on. The only duplication you're saving > is a single line addition. > OK, thanks. >> + 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); > > these should be true, false assuming you change the arg type to bool. > OK, thanks. >> + 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); > > ??? > OK, thanks. >> + 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); > > Again. > OK, thanks.
On 3 June 2015 at 13:30, Chen Gang <xili_gchen_5257@hotmail.com> wrote: > On 06/03/2015 01:40 AM, Peter Maydell wrote: >> On 30 May 2015 at 22:10, Chen Gang <xili_gchen_5257@hotmail.com> wrote: >>> >>> +#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(); >> >> You don't appear to be guaranteeing that the register value >> is < TILEGX_R_COUNT anywhere: get_SrcA_X1() and friends >> mask with 0x3f, but that only means you're guaranteed the >> value is between 0 and 63, wherease TILEGX_R_COUNT is 56. >> What does real hardware do if the encoded register value >> is 56..63 ? >> > > At present, it will g_assert_not_reached() too. No, it is not possible for hardware to assert! > 56..62 are hidden to > outside. So I did not implement them, either. Need we still implement > them? You must do something. You can't allow guest code (even broken guest code) to make QEMU assert. You need to find out what the hardware does here, and do that. thanks -- PMM
On 06/03/2015 08:34 PM, Peter Maydell wrote: > On 3 June 2015 at 13:30, Chen Gang <xili_gchen_5257@hotmail.com> wrote: >> On 06/03/2015 01:40 AM, Peter Maydell wrote: >>> On 30 May 2015 at 22:10, Chen Gang <xili_gchen_5257@hotmail.com> wrote: >>>> >>>> +#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(); >>> >>> You don't appear to be guaranteeing that the register value >>> is < TILEGX_R_COUNT anywhere: get_SrcA_X1() and friends >>> mask with 0x3f, but that only means you're guaranteed the >>> value is between 0 and 63, wherease TILEGX_R_COUNT is 56. >>> What does real hardware do if the encoded register value >>> is 56..63 ? >>> >> >> At present, it will g_assert_not_reached() too. > > No, it is not possible for hardware to assert! > >> 56..62 are hidden to >> outside. So I did not implement them, either. Need we still implement >> them? > > You must do something. You can't allow guest code (even > broken guest code) to make QEMU assert. You need to find > out what the hardware does here, and do that. > OK, what you said sounds reasonable to me. I will check what to do next for the 56..62 registers (at present, I guess, we need generate a hardware exception, and its default handler will do nothing). Thanks.
On 06/03/2015 08:47 AM, Chen Gang wrote: > On 06/03/2015 08:34 PM, Peter Maydell wrote: >> On 3 June 2015 at 13:30, Chen Gang <xili_gchen_5257@hotmail.com> wrote: >>> On 06/03/2015 01:40 AM, Peter Maydell wrote: >>>> On 30 May 2015 at 22:10, Chen Gang <xili_gchen_5257@hotmail.com> wrote: >>>>> +#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(); >>>> You don't appear to be guaranteeing that the register value >>>> is < TILEGX_R_COUNT anywhere: get_SrcA_X1() and friends >>>> mask with 0x3f, but that only means you're guaranteed the >>>> value is between 0 and 63, wherease TILEGX_R_COUNT is 56. >>>> What does real hardware do if the encoded register value >>>> is 56..63 ? >>>> >>> At present, it will g_assert_not_reached() too. >> No, it is not possible for hardware to assert! >> >>> 56..62 are hidden to >>> outside. So I did not implement them, either. Need we still implement >>> them? >> You must do something. You can't allow guest code (even >> broken guest code) to make QEMU assert. You need to find >> out what the hardware does here, and do that. >> > OK, what you said sounds reasonable to me. I will check what to do next > for the 56..62 registers (at present, I guess, we need generate a > hardware exception, and its default handler will do nothing). The registers in question are mapped directly to the on-chip networks. 56 - sn (static network) 57 - idn0 (internal dynamic network, demux 0) 58 - idn1 (internal dynamic network, demux 1) 59 - udn0 (user dynamic network, demux 0) 60 - udn1 (user dynamic network, demux 1) 61 - udn2 (user dynamic network, demux 2) 62 - udn3 (user dynamic network, demux 3) The "sn" is obsoleted in tilegx so acts just like "zero". Accessing idn0 or idn1 will generate an IDN_ACCESS exception, and accessing udn0..udn3 will generate a UDN_ACCESS exception; either of those becomes a SIGILL to a userspace application with code ILL_PRVREG. The tilegx hypervisor uses idn0/idn1 internally, and userspace applications can use udn0..udn3 after setting up a suitable hardwall with the kernel (see arch/tile/kernel/hardwall.c), but you almost certainly don't want to care about any of that.
On 3 June 2015 at 16:10, Chris Metcalf <cmetcalf@ezchip.com> wrote: > On 06/03/2015 08:47 AM, Chen Gang wrote: >> >> On 06/03/2015 08:34 PM, Peter Maydell wrote: >>> You must do something. You can't allow guest code (even >>> broken guest code) to make QEMU assert. You need to find >>> out what the hardware does here, and do that. >>> >> OK, what you said sounds reasonable to me. I will check what to do next >> for the 56..62 registers (at present, I guess, we need generate a >> hardware exception, and its default handler will do nothing). > > > The registers in question are mapped directly to the on-chip > networks. > > 56 - sn (static network) > 57 - idn0 (internal dynamic network, demux 0) > 58 - idn1 (internal dynamic network, demux 1) > 59 - udn0 (user dynamic network, demux 0) > 60 - udn1 (user dynamic network, demux 1) > 61 - udn2 (user dynamic network, demux 2) > 62 - udn3 (user dynamic network, demux 3) > > The "sn" is obsoleted in tilegx so acts just like "zero". > > Accessing idn0 or idn1 will generate an IDN_ACCESS exception, > and accessing udn0..udn3 will generate a UDN_ACCESS exception; > either of those becomes a SIGILL to a userspace application > with code ILL_PRVREG. Presumably this applies for all register accesses, not just atomic instructions? thanks -- PMM
On 06/03/2015 11:19 AM, Peter Maydell wrote: > On 3 June 2015 at 16:10, Chris Metcalf <cmetcalf@ezchip.com> wrote: >> On 06/03/2015 08:47 AM, Chen Gang wrote: >>> On 06/03/2015 08:34 PM, Peter Maydell wrote: >>>> You must do something. You can't allow guest code (even >>>> broken guest code) to make QEMU assert. You need to find >>>> out what the hardware does here, and do that. >>>> >>> OK, what you said sounds reasonable to me. I will check what to do next >>> for the 56..62 registers (at present, I guess, we need generate a >>> hardware exception, and its default handler will do nothing). >> >> The registers in question are mapped directly to the on-chip >> networks. >> >> 56 - sn (static network) >> 57 - idn0 (internal dynamic network, demux 0) >> 58 - idn1 (internal dynamic network, demux 1) >> 59 - udn0 (user dynamic network, demux 0) >> 60 - udn1 (user dynamic network, demux 1) >> 61 - udn2 (user dynamic network, demux 2) >> 62 - udn3 (user dynamic network, demux 3) >> >> The "sn" is obsoleted in tilegx so acts just like "zero". >> >> Accessing idn0 or idn1 will generate an IDN_ACCESS exception, >> and accessing udn0..udn3 will generate a UDN_ACCESS exception; >> either of those becomes a SIGILL to a userspace application >> with code ILL_PRVREG. > Presumably this applies for all register accesses, not > just atomic instructions? Correct.
On 06/03/2015 05:34 AM, Peter Maydell wrote: > You must do something. You can't allow guest code (even > broken guest code) to make QEMU assert. You need to find > out what the hardware does here, and do that. These are I/O registers for IPC. I believe that the best thing to do is assume protection is enabled at the "kernel" level, and thus raise the appropriate exception: SN_ACCESS, IDN_ACCESS, UDN_ACCESS. That said, I don't have the system architecture manual handy to check the full details. r~
On 06/03/2015 11:20 PM, Chris Metcalf wrote: > On 06/03/2015 11:19 AM, Peter Maydell wrote: >> On 3 June 2015 at 16:10, Chris Metcalf <cmetcalf@ezchip.com> wrote: >>> On 06/03/2015 08:47 AM, Chen Gang wrote: >>>> On 06/03/2015 08:34 PM, Peter Maydell wrote: >>>>> You must do something. You can't allow guest code (even >>>>> broken guest code) to make QEMU assert. You need to find >>>>> out what the hardware does here, and do that. >>>>> >>>> OK, what you said sounds reasonable to me. I will check what to do next >>>> for the 56..62 registers (at present, I guess, we need generate a >>>> hardware exception, and its default handler will do nothing). >>> >>> The registers in question are mapped directly to the on-chip >>> networks. >>> >>> 56 - sn (static network) >>> 57 - idn0 (internal dynamic network, demux 0) >>> 58 - idn1 (internal dynamic network, demux 1) >>> 59 - udn0 (user dynamic network, demux 0) >>> 60 - udn1 (user dynamic network, demux 1) >>> 61 - udn2 (user dynamic network, demux 2) >>> 62 - udn3 (user dynamic network, demux 3) >>> >>> The "sn" is obsoleted in tilegx so acts just like "zero". >>> >>> Accessing idn0 or idn1 will generate an IDN_ACCESS exception, >>> and accessing udn0..udn3 will generate a UDN_ACCESS exception; >>> either of those becomes a SIGILL to a userspace application >>> with code ILL_PRVREG. OK, thank you very much for your details. I will implement it according to the details above. >> Presumably this applies for all register accesses, not >> just atomic instructions? Excuse me, I do not quite understand what it is meaning, welcome any more details for it. > > Correct. >
On 4 June 2015 at 13:25, Chen Gang <xili_gchen_5257@hotmail.com> wrote: > On 06/03/2015 11:20 PM, Chris Metcalf wrote: >> On 06/03/2015 11:19 AM, Peter Maydell wrote: >>> On 3 June 2015 at 16:10, Chris Metcalf <cmetcalf@ezchip.com> wrote: >>>> On 06/03/2015 08:47 AM, Chen Gang wrote: >>>>> On 06/03/2015 08:34 PM, Peter Maydell wrote: >>>>>> You must do something. You can't allow guest code (even >>>>>> broken guest code) to make QEMU assert. You need to find >>>>>> out what the hardware does here, and do that. >>>>>> >>>>> OK, what you said sounds reasonable to me. I will check what to do next >>>>> for the 56..62 registers (at present, I guess, we need generate a >>>>> hardware exception, and its default handler will do nothing). >>>> >>>> The registers in question are mapped directly to the on-chip >>>> networks. >>>> >>>> 56 - sn (static network) >>>> 57 - idn0 (internal dynamic network, demux 0) >>>> 58 - idn1 (internal dynamic network, demux 1) >>>> 59 - udn0 (user dynamic network, demux 0) >>>> 60 - udn1 (user dynamic network, demux 1) >>>> 61 - udn2 (user dynamic network, demux 2) >>>> 62 - udn3 (user dynamic network, demux 3) >>>> >>>> The "sn" is obsoleted in tilegx so acts just like "zero". >>>> >>>> Accessing idn0 or idn1 will generate an IDN_ACCESS exception, >>>> and accessing udn0..udn3 will generate a UDN_ACCESS exception; >>>> either of those becomes a SIGILL to a userspace application >>>> with code ILL_PRVREG. > > OK, thank you very much for your details. I will implement it according > to the details above. > >>> Presumably this applies for all register accesses, not >>> just atomic instructions? > > Excuse me, I do not quite understand what it is meaning, welcome any > more details for it. Chris says that all instructions that use these registers generate an exception. Atomic instructions are not "special". This means you should handle these registers in translate.c (in the same place you handle their use in all other kinds of instruction). If you do that then it's OK to assert in main.c, because you know that translate.c has already made sure those cases are handled and won't generate the "do an atomic operation" exception for them. thanks -- PMM
On 06/03/2015 11:47 PM, Richard Henderson wrote: > On 06/03/2015 05:34 AM, Peter Maydell wrote: >> You must do something. You can't allow guest code (even >> broken guest code) to make QEMU assert. You need to find >> out what the hardware does here, and do that. > > These are I/O registers for IPC. > > I believe that the best thing to do is assume protection > is enabled at the "kernel" level, and thus raise the > appropriate exception: SN_ACCESS, IDN_ACCESS, UDN_ACCESS. > OK, thanks > That said, I don't have the system architecture manual > handy to check the full details. Fortunately, Chris knows more about it, and provide more valuable details for it. And welcome any members to provide related pdf documents, if possible. Thanks.
On 06/04/2015 08:29 PM, Peter Maydell wrote: > On 4 June 2015 at 13:25, Chen Gang <xili_gchen_5257@hotmail.com> wrote: >> On 06/03/2015 11:20 PM, Chris Metcalf wrote: >>> On 06/03/2015 11:19 AM, Peter Maydell wrote: >>>> On 3 June 2015 at 16:10, Chris Metcalf <cmetcalf@ezchip.com> wrote: >>>>> On 06/03/2015 08:47 AM, Chen Gang wrote: >>>>>> On 06/03/2015 08:34 PM, Peter Maydell wrote: >>>>>>> You must do something. You can't allow guest code (even >>>>>>> broken guest code) to make QEMU assert. You need to find >>>>>>> out what the hardware does here, and do that. >>>>>>> >>>>>> OK, what you said sounds reasonable to me. I will check what to do next >>>>>> for the 56..62 registers (at present, I guess, we need generate a >>>>>> hardware exception, and its default handler will do nothing). >>>>> >>>>> The registers in question are mapped directly to the on-chip >>>>> networks. >>>>> >>>>> 56 - sn (static network) >>>>> 57 - idn0 (internal dynamic network, demux 0) >>>>> 58 - idn1 (internal dynamic network, demux 1) >>>>> 59 - udn0 (user dynamic network, demux 0) >>>>> 60 - udn1 (user dynamic network, demux 1) >>>>> 61 - udn2 (user dynamic network, demux 2) >>>>> 62 - udn3 (user dynamic network, demux 3) >>>>> >>>>> The "sn" is obsoleted in tilegx so acts just like "zero". >>>>> >>>>> Accessing idn0 or idn1 will generate an IDN_ACCESS exception, >>>>> and accessing udn0..udn3 will generate a UDN_ACCESS exception; >>>>> either of those becomes a SIGILL to a userspace application >>>>> with code ILL_PRVREG. >> >> OK, thank you very much for your details. I will implement it according >> to the details above. >> >>>> Presumably this applies for all register accesses, not >>>> just atomic instructions? >> >> Excuse me, I do not quite understand what it is meaning, welcome any >> more details for it. > > Chris says that all instructions that use these registers > generate an exception. Atomic instructions are not "special". > This means you should handle these registers in translate.c > (in the same place you handle their use in all other kinds > of instruction). > > If you do that then it's OK to assert in main.c, because > you know that translate.c has already made sure those cases > are handled and won't generate the "do an atomic operation" > exception for them. > OK, Thanks. And I shall try to send patch v12 within next week (2015-06-14).
I will be posting more hardware documents on Wednesday when I'm back in the office. > On Jun 4, 2015, at 5:33 AM, Chen Gang <xili_gchen_5257@hotmail.com> wrote: > >> On 06/03/2015 11:47 PM, Richard Henderson wrote: >>> On 06/03/2015 05:34 AM, Peter Maydell wrote: >>> You must do something. You can't allow guest code (even >>> broken guest code) to make QEMU assert. You need to find >>> out what the hardware does here, and do that. >> >> These are I/O registers for IPC. >> >> I believe that the best thing to do is assume protection >> is enabled at the "kernel" level, and thus raise the >> appropriate exception: SN_ACCESS, IDN_ACCESS, UDN_ACCESS. >> > > OK, thanks > >> That said, I don't have the system architecture manual >> handy to check the full details. > > Fortunately, Chris knows more about it, and provide more valuable > details for it. > > And welcome any members to provide related pdf documents, if possible. > > > Thanks. > -- > Chen Gang > > Open, share, and attitude like air, water, and life which God blessed
On 07/07/2015 08:19 AM, Chris Metcalf wrote: > I will be posting more hardware documents on Wednesday when I'm back in the office. > That is good news! Thanks. And at present, I am just analyzing the issue about the vi of busybox with the static glibc (displaying and modifying contents through vi under tilegx qemu have bugs). Hope I can finish within this month (I also have to do some kernel and gcc related things in my free time during this month). Thanks. >> On Jun 4, 2015, at 5:33 AM, Chen Gang <xili_gchen_5257@hotmail.com> wrote: >> >>> On 06/03/2015 11:47 PM, Richard Henderson wrote: >>>> On 06/03/2015 05:34 AM, Peter Maydell wrote: >>>> You must do something. You can't allow guest code (even >>>> broken guest code) to make QEMU assert. You need to find >>>> out what the hardware does here, and do that. >>> >>> These are I/O registers for IPC. >>> >>> I believe that the best thing to do is assume protection >>> is enabled at the "kernel" level, and thus raise the >>> appropriate exception: SN_ACCESS, IDN_ACCESS, UDN_ACCESS. >>> >> >> OK, thanks >> >>> That said, I don't have the system architecture manual >>> handy to check the full details. >> >> Fortunately, Chris knows more about it, and provide more valuable >> details for it. >> >> And welcome any members to provide related pdf documents, if possible. >> >> >> Thanks. >> -- >> Chen Gang >> >> Open, share, and attitude like air, water, and life which God blessed
On 07/07/2015 08:19 AM, Chris Metcalf wrote: > I will be posting more hardware documents on Wednesday when I'm back in the office. > That is good news! Thanks. And at present, I am just analyzing the issue about the vi of busybox with the static glibc (displaying and modifying contents through vi under tilegx qemu have bugs). Hope I can finish within this month (I also have to do some kernel and gcc related things in my free time during this month). Thanks. >> On Jun 4, 2015, at 5:33 AM, Chen Gang <xili_gchen_5257@hotmail.com> wrote: >> >>> On 06/03/2015 11:47 PM, Richard Henderson wrote: >>>> On 06/03/2015 05:34 AM, Peter Maydell wrote: >>>> You must do something. You can't allow guest code (even >>>> broken guest code) to make QEMU assert. You need to find >>>> out what the hardware does here, and do that. >>> >>> These are I/O registers for IPC. >>> >>> I believe that the best thing to do is assume protection >>> is enabled at the "kernel" level, and thus raise the >>> appropriate exception: SN_ACCESS, IDN_ACCESS, UDN_ACCESS. >>> >> >> OK, thanks >> >>> That said, I don't have the system architecture manual >>> handy to check the full details. >> >> Fortunately, Chris knows more about it, and provide more valuable >> details for it. >> >> And welcome any members to provide related pdf documents, if possible. >> >> >> Thanks. >> -- >> Chen Gang >> >> Open, share, and attitude like air, water, and life which God blessed
On 06/04/2015 08:32 AM, Chen Gang wrote: > On 06/03/2015 11:47 PM, Richard Henderson wrote: >> That said, I don't have the system architecture manual >> handy to check the full details. > Fortunately, Chris knows more about it, and provide more valuable > details for it. > > And welcome any members to provide related pdf documents, if possible. I worked with our internal folks to get a few more tilegx hardware docs on the web site: http://www.ezchip.com/scm/docs/
On 07/09/2015 03:24 AM, Chris Metcalf wrote: > On 06/04/2015 08:32 AM, Chen Gang wrote: >> On 06/03/2015 11:47 PM, Richard Henderson wrote: >>> That said, I don't have the system architecture manual >>> handy to check the full details. >> Fortunately, Chris knows more about it, and provide more valuable >> details for it. >> >> And welcome any members to provide related pdf documents, if possible. > > I worked with our internal folks to get a few more tilegx hardware docs > on the web site: > > http://www.ezchip.com/scm/docs/ > Thank you very much. I have implemented iret insn (which is related with EX_CONTEXT_?_?) according to the longjmp assembly code and the ISA docs. This document (spr registers) can let me check whether my implementation is really correct or not. I guess, for the next system mode qemu tilegx, this document is very necessary. Thanks. -- Chen Gang Open, share, and attitude like air, water, and life which God blessed
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;
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 <gang.chen.5i5j@gmail.com> --- 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(-)