Commit 48a539df authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180814' into staging



target-arm queue:
 * Implement more of ARMv6-M support
 * Support direct execution from non-RAM regions;
   use this to implmeent execution from small (<1K) MPU regions
 * GICv2: implement the virtualization extensions
 * support a virtualization-capable GICv2 in the virt and
   xlnx-zynqmp boards
 * arm: Fix return code of arm_load_elf() so we can detect
   failure to load the file correctly
 * Implement HCR_EL2.TGE ("trap general exceptions") bit
 * Implement tailchaining for M profile cores
 * Fix bugs in SVE compare, saturating add/sub, WHILE, MOVZ

# gpg: Signature made Tue 14 Aug 2018 17:23:38 BST
# gpg:                using RSA key 3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20180814: (45 commits)
  target/arm: Fix typo in helper_sve_movz_d
  target/arm: Reorganize SVE WHILE
  target/arm: Fix typo in do_sat_addsub_64
  target/arm: Fix sign of sve_cmpeq_ppzw/sve_cmpne_ppzw
  target/arm: Implement tailchaining for M profile cores
  target/arm: Restore M-profile CONTROL.SPSEL before any tailchaining
  target/arm: Initialize exc_secure correctly in do_v7m_exception_exit()
  target/arm: Improve exception-taken logging
  target/arm: Treat SCTLR_EL1.M as if it were zero when HCR_EL2.TGE is set
  target/arm: Provide accessor functions for HCR_EL2.{IMO, FMO, AMO}
  target/arm: Honour HCR_EL2.TGE when raising synchronous exceptions
  target/arm: Honour HCR_EL2.TGE and MDCR_EL2.TDE in debug register access checks
  target/arm: Mask virtual interrupts if HCR_EL2.TGE is set
  arm: Fix return code of arm_load_elf
  arm/virt: Add support for GICv2 virtualization extensions
  xlnx-zynqmp: Improve GIC wiring and MMIO mapping
  intc/arm_gic: Improve traces
  intc/arm_gic: Implement maintenance interrupt generation
  intc/arm_gic: Implement gic_update_virt() function
  intc/arm_gic: Implement the virtual interface registers
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents c7fb81a5 054e7adf
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -332,6 +332,9 @@ TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
    desc.trace_vcpu_dstate = *cpu->trace_dstate;
    desc.pc = pc;
    phys_pc = get_page_addr_code(desc.env, pc);
    if (phys_pc == -1) {
        return NULL;
    }
    desc.phys_page1 = phys_pc & TARGET_PAGE_MASK;
    h = tb_hash_func(phys_pc, pc, flags, cf_mask, *cpu->trace_dstate);
    return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
+12 −99
Original line number Diff line number Diff line
@@ -741,39 +741,6 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr,
                            prot, mmu_idx, size);
}

static void report_bad_exec(CPUState *cpu, target_ulong addr)
{
    /* Accidentally executing outside RAM or ROM is quite common for
     * several user-error situations, so report it in a way that
     * makes it clear that this isn't a QEMU bug and provide suggestions
     * about what a user could do to fix things.
     */
    error_report("Trying to execute code outside RAM or ROM at 0x"
                 TARGET_FMT_lx, addr);
    error_printf("This usually means one of the following happened:\n\n"
                 "(1) You told QEMU to execute a kernel for the wrong machine "
                 "type, and it crashed on startup (eg trying to run a "
                 "raspberry pi kernel on a versatilepb QEMU machine)\n"
                 "(2) You didn't give QEMU a kernel or BIOS filename at all, "
                 "and QEMU executed a ROM full of no-op instructions until "
                 "it fell off the end\n"
                 "(3) Your guest kernel has a bug and crashed by jumping "
                 "off into nowhere\n\n"
                 "This is almost always one of the first two, so check your "
                 "command line and that you are using the right type of kernel "
                 "for this machine.\n"
                 "If you think option (3) is likely then you can try debugging "
                 "your guest with the -d debug options; in particular "
                 "-d guest_errors will cause the log to include a dump of the "
                 "guest register state at this point.\n\n"
                 "Execution cannot continue; stopping here.\n\n");

    /* Report also to the logs, with more detail including register dump */
    qemu_log_mask(LOG_GUEST_ERROR, "qemu: fatal: Trying to execute code "
                  "outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
    log_cpu_state_mask(LOG_GUEST_ERROR, cpu, CPU_DUMP_FPU | CPU_DUMP_CCOP);
}

static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
{
    ram_addr_t ram_addr;
@@ -789,7 +756,7 @@ static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
                         int mmu_idx,
                         target_ulong addr, uintptr_t retaddr,
                         bool recheck, int size)
                         bool recheck, MMUAccessType access_type, int size)
{
    CPUState *cpu = ENV_GET_CPU(env);
    hwaddr mr_offset;
@@ -831,6 +798,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
    }

    cpu->mem_io_vaddr = addr;
    cpu->mem_io_access_type = access_type;

    if (mr->global_locking && !qemu_mutex_iothread_locked()) {
        qemu_mutex_lock_iothread();
@@ -843,7 +811,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
            section->offset_within_address_space -
            section->offset_within_region;

        cpu_transaction_failed(cpu, physaddr, addr, size, MMU_DATA_LOAD,
        cpu_transaction_failed(cpu, physaddr, addr, size, access_type,
                               mmu_idx, iotlbentry->attrs, r, retaddr);
    }
    if (locked) {
@@ -958,11 +926,6 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
{
    int mmu_idx, index;
    void *p;
    MemoryRegion *mr;
    MemoryRegionSection *section;
    CPUState *cpu = ENV_GET_CPU(env);
    CPUIOTLBEntry *iotlbentry;
    hwaddr physaddr, mr_offset;

    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
    mmu_idx = cpu_mmu_index(env, true);
@@ -973,69 +936,19 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
        assert(tlb_hit(env->tlb_table[mmu_idx][index].addr_code, addr));
    }

    if (unlikely(env->tlb_table[mmu_idx][index].addr_code & TLB_RECHECK)) {
    if (unlikely(env->tlb_table[mmu_idx][index].addr_code &
                 (TLB_RECHECK | TLB_MMIO))) {
        /*
         * This is a TLB_RECHECK access, where the MMU protection
         * covers a smaller range than a target page, and we must
         * repeat the MMU check here. This tlb_fill() call might
         * longjump out if this access should cause a guest exception.
         */
        int index;
        target_ulong tlb_addr;

        tlb_fill(cpu, addr, 0, MMU_INST_FETCH, mmu_idx, 0);

        index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
        tlb_addr = env->tlb_table[mmu_idx][index].addr_code;
        if (!(tlb_addr & ~(TARGET_PAGE_MASK | TLB_RECHECK))) {
            /* RAM access. We can't handle this, so for now just stop */
            cpu_abort(cpu, "Unable to handle guest executing from RAM within "
                      "a small MPU region at 0x" TARGET_FMT_lx, addr);
        }
        /*
         * Fall through to handle IO accesses (which will almost certainly
         * also result in failure)
         * Return -1 if we can't translate and execute from an entire
         * page of RAM here, which will cause us to execute by loading
         * and translating one insn at a time, without caching:
         *  - TLB_RECHECK: means the MMU protection covers a smaller range
         *    than a target page, so we must redo the MMU check every insn
         *  - TLB_MMIO: region is not backed by RAM
         */
        return -1;
    }

    iotlbentry = &env->iotlb[mmu_idx][index];
    section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs);
    mr = section->mr;
    if (memory_region_is_unassigned(mr)) {
        qemu_mutex_lock_iothread();
        if (memory_region_request_mmio_ptr(mr, addr)) {
            qemu_mutex_unlock_iothread();
            /* A MemoryRegion is potentially added so re-run the
             * get_page_addr_code.
             */
            return get_page_addr_code(env, addr);
        }
        qemu_mutex_unlock_iothread();

        /* Give the new-style cpu_transaction_failed() hook first chance
         * to handle this.
         * This is not the ideal place to detect and generate CPU
         * exceptions for instruction fetch failure (for instance
         * we don't know the length of the access that the CPU would
         * use, and it would be better to go ahead and try the access
         * and use the MemTXResult it produced). However it is the
         * simplest place we have currently available for the check.
         */
        mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr;
        physaddr = mr_offset +
            section->offset_within_address_space -
            section->offset_within_region;
        cpu_transaction_failed(cpu, physaddr, addr, 0, MMU_INST_FETCH, mmu_idx,
                               iotlbentry->attrs, MEMTX_DECODE_ERROR, 0);

        cpu_unassigned_access(cpu, addr, false, true, 0, 4);
        /* The CPU's unassigned access hook might have longjumped out
         * with an exception. If it didn't (or there was no hook) then
         * we can't proceed further.
         */
        report_bad_exec(cpu, addr);
        exit(1);
    }
    p = (void *)((uintptr_t)addr + env->tlb_table[mmu_idx][index].addend);
    return qemu_ram_addr_from_host_nofail(p);
}
+7 −4
Original line number Diff line number Diff line
@@ -99,11 +99,12 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env,
                                              size_t mmu_idx, size_t index,
                                              target_ulong addr,
                                              uintptr_t retaddr,
                                              bool recheck)
                                              bool recheck,
                                              MMUAccessType access_type)
{
    CPUIOTLBEntry *iotlbentry = &env->iotlb[mmu_idx][index];
    return io_readx(env, iotlbentry, mmu_idx, addr, retaddr, recheck,
                    DATA_SIZE);
                    access_type, DATA_SIZE);
}
#endif

@@ -140,7 +141,8 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr,
        /* ??? Note that the io helpers always read data in the target
           byte ordering.  We should push the LE/BE request down into io.  */
        res = glue(io_read, SUFFIX)(env, mmu_idx, index, addr, retaddr,
                                    tlb_addr & TLB_RECHECK);
                                    tlb_addr & TLB_RECHECK,
                                    READ_ACCESS_TYPE);
        res = TGT_LE(res);
        return res;
    }
@@ -207,7 +209,8 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr,
        /* ??? Note that the io helpers always read data in the target
           byte ordering.  We should push the LE/BE request down into io.  */
        res = glue(io_read, SUFFIX)(env, mmu_idx, index, addr, retaddr,
                                    tlb_addr & TLB_RECHECK);
                                    tlb_addr & TLB_RECHECK,
                                    READ_ACCESS_TYPE);
        res = TGT_BE(res);
        return res;
    }
+21 −2
Original line number Diff line number Diff line
@@ -1493,7 +1493,7 @@ static void tb_phys_invalidate__locked(TranslationBlock *tb)
 */
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
{
    if (page_addr == -1) {
    if (page_addr == -1 && tb->page_addr[0] != -1) {
        page_lock_tb(tb);
        do_tb_phys_invalidate(tb, true);
        page_unlock_tb(tb);
@@ -1608,6 +1608,17 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,

    assert_memory_lock();

    if (phys_pc == -1) {
        /*
         * If the TB is not associated with a physical RAM page then
         * it must be a temporary one-insn TB, and we have nothing to do
         * except fill in the page_addr[] fields.
         */
        assert(tb->cflags & CF_NOCACHE);
        tb->page_addr[0] = tb->page_addr[1] = -1;
        return tb;
    }

    /*
     * Add the TB to the page list, acquiring first the pages's locks.
     * We keep the locks held until after inserting the TB in the hash table,
@@ -1677,6 +1688,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu,

    phys_pc = get_page_addr_code(env, pc);

    if (phys_pc == -1) {
        /* Generate a temporary TB with 1 insn in it */
        cflags &= ~CF_COUNT_MASK;
        cflags |= CF_NOCACHE | 1;
    }

 buffer_overflow:
    tb = tb_alloc(pc);
    if (unlikely(!tb)) {
@@ -2121,9 +2138,11 @@ void tb_check_watchpoint(CPUState *cpu)

        cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
        addr = get_page_addr_code(env, pc);
        if (addr != -1) {
            tb_invalidate_phys_range(addr, addr + 1);
        }
    }
}

#ifndef CONFIG_USER_ONLY
/* in deterministic execution mode, instructions doing device I/Os
+0 −6
Original line number Diff line number Diff line
@@ -402,12 +402,6 @@ static MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, hwaddr addr)
    }
}

bool memory_region_is_unassigned(MemoryRegion *mr)
{
    return mr != &io_mem_rom && mr != &io_mem_notdirty && !mr->rom_device
        && mr != &io_mem_watch;
}

/* Called from RCU critical section */
static MemoryRegionSection *address_space_lookup_region(AddressSpaceDispatch *d,
                                                        hwaddr addr,
Loading