Commit f988c7e1 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/shorne/tags/pull-or-20180703' into staging



OpenRISC cleanups and Fixes for QEMU 3.0

Mostly patches from Richard Henderson fixing multiple things:
 * Fix singlestepping in GDB.
 * Use more TB linking.
 * Fixes to exit TB after updating SPRs to enable registering of state
   changes.
 * Significant optimizations and refactors to the TLB
 * Split out disassembly from translation.
 * Add qemu-or1k to qemu-binfmt-conf.sh.
 * Implement signal handling for linux-user.

Then there are a few fixups from me:
 * Fix delay slot detections to match hardware, this was masking a bug
   in the linus kernel.
 * Fix stores to the PIC mask register

# gpg: Signature made Tue 03 Jul 2018 14:44:10 BST
# gpg:                using RSA key C3B31C2D5E6627E4
# gpg: Good signature from "Stafford Horne <shorne@gmail.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: D9C4 7354 AEF8 6C10 3A25  EFF1 C3B3 1C2D 5E66 27E4

* remotes/shorne/tags/pull-or-20180703: (25 commits)
  target/openrisc: Fix writes to interrupt mask register
  target/openrisc: Fix delay slot exception flag to match spec
  linux-user: Fix struct sigaltstack for openrisc
  linux-user: Implement signals for openrisc
  target/openrisc: Add support in scripts/qemu-binfmt-conf.sh
  target/openrisc: Reorg tlb lookup
  target/openrisc: Increase the TLB size
  target/openrisc: Stub out handle_mmu_fault for softmmu
  target/openrisc: Use identical sizes for ITLB and DTLB
  target/openrisc: Fix cpu_mmu_index
  target/openrisc: Fix tlb flushing in mtspr
  target/openrisc: Reduce tlb to a single dimension
  target/openrisc: Merge mmu_helper.c into mmu.c
  target/openrisc: Remove indirect function calls for mmu
  target/openrisc: Merge tlb allocation into CPUOpenRISCState
  target/openrisc: Form the spr index from tcg
  target/openrisc: Exit the TB after l.mtspr
  target/openrisc: Split out is_user
  target/openrisc: Link more translation blocks
  target/openrisc: Fix singlestep_enabled
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents b07cd3e7 dfc84745
Loading
Loading
Loading
Loading
+84 −133
Original line number Diff line number Diff line
@@ -21,124 +21,69 @@
#include "signal-common.h"
#include "linux-user/trace.h"

struct target_sigcontext {
typedef struct target_sigcontext {
    struct target_pt_regs regs;
    abi_ulong oldmask;
    abi_ulong usp;
};
} target_sigcontext;

struct target_ucontext {
typedef struct target_ucontext {
    abi_ulong tuc_flags;
    abi_ulong tuc_link;
    target_stack_t tuc_stack;
    struct target_sigcontext tuc_mcontext;
    target_sigcontext tuc_mcontext;
    target_sigset_t tuc_sigmask;   /* mask last for extensibility */
};
} target_ucontext;

struct target_rt_sigframe {
    abi_ulong pinfo;
    uint64_t puc;
typedef struct target_rt_sigframe {
    struct target_siginfo info;
    struct target_sigcontext sc;
    struct target_ucontext uc;
    unsigned char retcode[16];  /* trampoline code */
};

/* This is the asm-generic/ucontext.h version */
#if 0
static int restore_sigcontext(CPUOpenRISCState *regs,
                              struct target_sigcontext *sc)
{
    unsigned int err = 0;
    unsigned long old_usp;

    /* Alwys make any pending restarted system call return -EINTR */
    current_thread_info()->restart_block.fn = do_no_restart_syscall;
    target_ucontext uc;
    uint32_t retcode[4];  /* trampoline code */
} target_rt_sigframe;

    /* restore the regs from &sc->regs (same as sc, since regs is first)
     * (sc is already checked for VERIFY_READ since the sigframe was
     *  checked in sys_sigreturn previously)
     */
static void restore_sigcontext(CPUOpenRISCState *env, target_sigcontext *sc)
{
    int i;
    abi_ulong v;

    if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
        goto badframe;
    for (i = 0; i < 32; ++i) {
        __get_user(v, &sc->regs.gpr[i]);
        cpu_set_gpr(env, i, v);
    }
    __get_user(env->pc, &sc->regs.pc);

    /* make sure the U-flag is set so user-mode cannot fool us */

    regs->sr &= ~SR_SM;

    /* restore the old USP as it was before we stacked the sc etc.
     * (we cannot just pop the sigcontext since we aligned the sp and
     *  stuff after pushing it)
     */

    __get_user(old_usp, &sc->usp);
    phx_signal("old_usp 0x%lx", old_usp);

    __PHX__ REALLY           /* ??? */
    wrusp(old_usp);
    regs->gpr[1] = old_usp;

    /* TODO: the other ports use regs->orig_XX to disable syscall checks
     * after this completes, but we don't use that mechanism. maybe we can
     * use it now ?
     */

    return err;

badframe:
    return 1;
    /* Make sure the supervisor flag is clear.  */
    __get_user(v, &sc->regs.sr);
    cpu_set_sr(env, v & ~SR_SM);
}
#endif

/* Set up a signal frame.  */

static void setup_sigcontext(struct target_sigcontext *sc,
                             CPUOpenRISCState *regs,
                             unsigned long mask)
static void setup_sigcontext(target_sigcontext *sc, CPUOpenRISCState *env)
{
    unsigned long usp = cpu_get_gpr(regs, 1);

    /* copy the regs. they are first in sc so we can use sc directly */

    /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/

    /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
       the signal handler. The frametype will be restored to its previous
       value in restore_sigcontext. */
    /*regs->frametype = CRIS_FRAME_NORMAL;*/
    int i;

    /* then some other stuff */
    __put_user(mask, &sc->oldmask);
    __put_user(usp, &sc->usp);
    for (i = 0; i < 32; ++i) {
        __put_user(cpu_get_gpr(env, i), &sc->regs.gpr[i]);
    }

static inline unsigned long align_sigframe(unsigned long sp)
{
    return sp & ~3UL;
    __put_user(env->pc, &sc->regs.pc);
    __put_user(cpu_get_sr(env), &sc->regs.sr);
}

static inline abi_ulong get_sigframe(struct target_sigaction *ka,
                                     CPUOpenRISCState *regs,
                                     CPUOpenRISCState *env,
                                     size_t frame_size)
{
    unsigned long sp = get_sp_from_cpustate(regs);
    int onsigstack = on_sig_stack(sp);

    /* redzone */
    sp = target_sigsp(sp, ka);
    target_ulong sp = get_sp_from_cpustate(env);

    sp = align_sigframe(sp - frame_size);

    /*
     * If we are on the alternate signal stack and would overflow it, don't.
     * Return an always-bogus address instead so we will die with SIGSEGV.
    /* Honor redzone now.  If we swap to signal stack, no need to waste
     * the 128 bytes by subtracting afterward.
     */
    sp -= 128;

    if (onsigstack && !likely(on_sig_stack(sp))) {
        return -1L;
    }
    sp = target_sigsp(sp, ka);
    sp -= frame_size;
    sp = QEMU_ALIGN_DOWN(sp, 4);

    return sp;
}
@@ -147,11 +92,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
                    target_siginfo_t *info,
                    target_sigset_t *set, CPUOpenRISCState *env)
{
    int err = 0;
    abi_ulong frame_addr;
    unsigned long return_ip;
    struct target_rt_sigframe *frame;
    abi_ulong info_addr, uc_addr;
    target_rt_sigframe *frame;
    int i;

    frame_addr = get_sigframe(ka, env, sizeof(*frame));
    trace_user_setup_rt_frame(env, frame_addr);
@@ -159,47 +102,37 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
        goto give_sigsegv;
    }

    info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
    __put_user(info_addr, &frame->pinfo);
    uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
    __put_user(uc_addr, &frame->puc);

    if (ka->sa_flags & SA_SIGINFO) {
        tswap_siginfo(&frame->info, info);
    }

    /*err |= __clear_user(&frame->uc, offsetof(ucontext_t, uc_mcontext));*/
    __put_user(0, &frame->uc.tuc_flags);
    __put_user(0, &frame->uc.tuc_link);
    target_save_altstack(&frame->uc.tuc_stack, env);
    setup_sigcontext(&frame->sc, env, set->sig[0]);

    /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/

    /* trampoline - the desired return ip is the retcode itself */
    return_ip = (unsigned long)&frame->retcode;
    /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
    __put_user(0xa960, (short *)(frame->retcode + 0));
    __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
    __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
    __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));

    if (err) {
        goto give_sigsegv;
    target_save_altstack(&frame->uc.tuc_stack, env);
    setup_sigcontext(&frame->uc.tuc_mcontext, env);
    for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
        __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
    }

    /* TODO what is the current->exec_domain stuff and invmap ? */
    /* This is l.ori r11,r0,__NR_sigreturn; l.sys 1; l.nop; l.nop */
    __put_user(0xa9600000 | TARGET_NR_rt_sigreturn, frame->retcode + 0);
    __put_user(0x20000001, frame->retcode + 1);
    __put_user(0x15000000, frame->retcode + 2);
    __put_user(0x15000000, frame->retcode + 3);

    /* Set up registers for signal handler */
    env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
    cpu_set_gpr(env, 9, (unsigned long)return_ip);     /* what we enter LATER */
    cpu_set_gpr(env, 3, (unsigned long)sig);           /* arg 1: signo */
    cpu_set_gpr(env, 4, (unsigned long)&frame->info);  /* arg 2: (siginfo_t*) */
    cpu_set_gpr(env, 5, (unsigned long)&frame->uc);    /* arg 3: ucontext */

    /* actually move the usp to reflect the stacked frame */
    cpu_set_gpr(env, 1, (unsigned long)frame);

    cpu_set_gpr(env, 9, frame_addr + offsetof(target_rt_sigframe, retcode));
    cpu_set_gpr(env, 3, sig);
    cpu_set_gpr(env, 4, frame_addr + offsetof(target_rt_sigframe, info));
    cpu_set_gpr(env, 5, frame_addr + offsetof(target_rt_sigframe, uc));
    cpu_set_gpr(env, 1, frame_addr);

    /* For debugging convenience, set ppc to the insn that faulted.  */
    env->ppc = env->pc;
    /* When setting the PC for the signal handler, exit delay slot.  */
    env->pc = ka->_sa_handler;
    env->dflag = 0;
    return;

give_sigsegv:
@@ -207,16 +140,34 @@ give_sigsegv:
    force_sigsegv(sig);
}

long do_sigreturn(CPUOpenRISCState *env)
{
    trace_user_do_sigreturn(env, 0);
    fprintf(stderr, "do_sigreturn: not implemented\n");
    return -TARGET_ENOSYS;
}

long do_rt_sigreturn(CPUOpenRISCState *env)
{
    abi_ulong frame_addr = get_sp_from_cpustate(env);
    target_rt_sigframe *frame;
    sigset_t set;

    trace_user_do_rt_sigreturn(env, 0);
    fprintf(stderr, "do_rt_sigreturn: not implemented\n");
    return -TARGET_ENOSYS;
    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
        goto badframe;
    }
    if (frame_addr & 3) {
        goto badframe;
    }

    target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
    set_sigmask(&set);

    restore_sigcontext(env, &frame->uc.tuc_mcontext);
    if (do_sigaltstack(frame_addr + offsetof(target_rt_sigframe, uc.tuc_stack),
                       0, frame_addr) == -EFAULT) {
        goto badframe;
    }

    unlock_user_struct(frame, frame_addr, 0);
    return cpu_get_gpr(env, 11);

 badframe:
    unlock_user_struct(frame, frame_addr, 0);
    force_sig(TARGET_SIGSEGV);
    return 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -5,8 +5,8 @@

typedef struct target_sigaltstack {
    abi_long ss_sp;
    abi_int ss_flags;
    abi_ulong ss_size;
    abi_long ss_flags;
} target_stack_t;

/* sigaltstack controls  */
+8 −20
Original line number Diff line number Diff line
#ifndef OPENRISC_TARGET_SYSCALL_H
#define OPENRISC_TARGET_SYSCALL_H

/* Note that in linux/arch/openrisc/include/uapi/asm/ptrace.h,
 * this is called user_regs_struct.  Given that this is what
 * is used within struct sigcontext we need this definition.
 * However, elfload.c wants this name.
 */
struct target_pt_regs {
    union {
        struct {
            /* Named registers */
            uint32_t sr;       /* Stored in place of r0 */
            target_ulong sp;   /* r1 */
        };
        struct {
            /* Old style */
            target_ulong offset[2];
            target_ulong gprs[30];
        };
        struct {
            /* New style */
            target_ulong gpr[32];
        };
    };
    target_ulong pc;
    target_ulong orig_gpr11;   /* For restarting system calls */
    uint32_t syscallno;        /* Syscall number (used by strace) */
    target_ulong dummy;     /* Cheap alignment fix */
    abi_ulong gpr[32];
    abi_ulong pc;
    abi_ulong sr;
};

#define UNAME_MACHINE "openrisc"
+1 −1
Original line number Diff line number Diff line
@@ -236,7 +236,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
    return 0;
}

#if !defined(TARGET_OPENRISC) && !defined(TARGET_NIOS2)
#if !defined(TARGET_NIOS2)
/* Just set the guest's signal mask to the specified value; the
 * caller is assumed to have called block_signals() already.
 */
+7 −3
Original line number Diff line number Diff line
#!/bin/sh
# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390/HPPA/Xtensa/microblaze
# program execution by the kernel
# Enable automatic program execution by the kernel.

qemu_target_list="i386 i486 alpha arm armeb sparc32plus ppc ppc64 ppc64le m68k \
mips mipsel mipsn32 mipsn32el mips64 mips64el \
sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb microblaze microblazeel"
sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb \
microblaze microblazeel or1k"

i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'
i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
@@ -124,6 +124,10 @@ microblazeel_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\
microblazeel_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
microblazeel_family=microblazeel

or1k_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5c'
or1k_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
or1k_family=or1k

qemu_get_family() {
    cpu=${HOST_ARCH:-$(uname -m)}
    case "$cpu" in
Loading