diff mbox

[02/10,v11] linux-user: Support tilegx architecture in linux-user

Message ID BLU437-SMTP1086ADDBFC233B4DD108B9BB9C80@phx.gbl
State New
Headers show

Commit Message

Chen Gang May 30, 2015, 9:10 p.m. UTC
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(-)

Comments

Peter Maydell June 2, 2015, 5:40 p.m. UTC | #1
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
Chen Gang June 3, 2015, 12:30 p.m. UTC | #2
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.
Peter Maydell June 3, 2015, 12:34 p.m. UTC | #3
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
Chen Gang June 3, 2015, 12:47 p.m. UTC | #4
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.
Chris Metcalf June 3, 2015, 3:10 p.m. UTC | #5
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.
Peter Maydell June 3, 2015, 3:19 p.m. UTC | #6
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
Chris Metcalf June 3, 2015, 3:20 p.m. UTC | #7
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.
Richard Henderson June 3, 2015, 3:47 p.m. UTC | #8
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~
Chen Gang June 4, 2015, 12:25 p.m. UTC | #9
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.
>
Peter Maydell June 4, 2015, 12:29 p.m. UTC | #10
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
Chen Gang June 4, 2015, 12:32 p.m. UTC | #11
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 June 4, 2015, 12:39 p.m. UTC | #12
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).
Chris Metcalf July 7, 2015, 12:19 a.m. UTC | #13
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
Chen Gang July 7, 2015, 8:47 p.m. UTC | #14
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
Chen Gang July 7, 2015, 8:50 p.m. UTC | #15
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
Chris Metcalf July 8, 2015, 7:24 p.m. UTC | #16
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/
Chen Gang July 9, 2015, 1:09 a.m. UTC | #17
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 mbox

Patch

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;