Commit 269bd5d8 authored by Richard Henderson's avatar Richard Henderson
Browse files

cpu: Move the softmmu tlb to CPUNegativeOffsetState



We have for some time had code within the tcg backends to
handle large positive offsets from env.  This move makes
sure that need not happen.  Indeed, we are able to assert
at build time that simple offsets suffice for all hosts.

Reviewed-by: default avatarAlistair Francis <alistair.francis@wdc.com>
Reviewed-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Signed-off-by: default avatarRichard Henderson <richard.henderson@linaro.org>
parent 5e140196
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -429,4 +429,15 @@ static inline CPUNegativeOffsetState *cpu_neg(CPUState *cpu)
    return &arch_cpu->neg;
}

/**
 * env_tlb(env)
 * @env: The architecture environment
 *
 * Return the CPUTLB state associated with the environment.
 */
static inline CPUTLB *env_tlb(CPUArchState *env)
{
    return &env_neg(env)->tlb;
}

#endif /* CPU_ALL_H */
+13 −7
Original line number Diff line number Diff line
@@ -178,13 +178,14 @@ typedef struct CPUTLBDesc {

/*
 * Data elements that are per MMU mode, accessed by the fast path.
 * The structure is aligned to aid loading the pair with one insn.
 */
typedef struct CPUTLBDescFast {
    /* Contains (n_entries - 1) << CPU_TLB_ENTRY_BITS */
    uintptr_t mask;
    /* The array of tlb entries itself. */
    CPUTLBEntry *table;
} CPUTLBDescFast;
} CPUTLBDescFast QEMU_ALIGNED(2 * sizeof(void *));

/*
 * Data elements that are shared between all MMU modes.
@@ -211,28 +212,33 @@ typedef struct CPUTLBCommon {
/*
 * The entire softmmu tlb, for all MMU modes.
 * The meaning of each of the MMU modes is defined in the target code.
 * Since this is placed within CPUNegativeOffsetState, the smallest
 * negative offsets are at the end of the struct.
 */
typedef struct CPUTLB {
    CPUTLBDescFast f[NB_MMU_MODES];
    CPUTLBDesc d[NB_MMU_MODES];
    CPUTLBCommon c;
    CPUTLBDesc d[NB_MMU_MODES];
    CPUTLBDescFast f[NB_MMU_MODES];
} CPUTLB;

/* There are target-specific members named "tlb".  This is temporary.  */
#define CPU_COMMON    CPUTLB tlb_;
#define env_tlb(ENV)  (&(ENV)->tlb_)
/* This will be used by TCG backends to compute offsets.  */
#define TLB_MASK_TABLE_OFS(IDX) \
    ((int)offsetof(ArchCPU, neg.tlb.f[IDX]) - (int)offsetof(ArchCPU, env))

#else

#define CPU_COMMON  /* Nothing */
typedef struct CPUTLB { } CPUTLB;

#endif  /* !CONFIG_USER_ONLY && CONFIG_TCG */

#define CPU_COMMON  /* Nothing */

/*
 * This structure must be placed in ArchCPU immedately
 * before CPUArchState, as a field named "neg".
 */
typedef struct CPUNegativeOffsetState {
    CPUTLB tlb;
    IcountDecr icount_decr;
} CPUNegativeOffsetState;

+6 −23
Original line number Diff line number Diff line
@@ -1637,9 +1637,9 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
    label->label_ptr[0] = label_ptr;
}

/* We expect to use a 24-bit unsigned offset from ENV.  */
QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_.f[NB_MMU_MODES - 1].table)
                  > 0xffffff);
/* We expect to use a 7-bit scaled negative offset from ENV.  */
QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0);
QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -512);

/* Load and compare a TLB entry, emitting the conditional jump to the
   slow path for the failure case, which will be patched later when finalizing
@@ -1649,8 +1649,9 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp opc,
                             tcg_insn_unit **label_ptr, int mem_index,
                             bool is_read)
{
    int mask_ofs = offsetof(CPUArchState, tlb_.f[mem_index].mask);
    int table_ofs = offsetof(CPUArchState, tlb_.f[mem_index].table);
    int fast_ofs = TLB_MASK_TABLE_OFS(mem_index);
    int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask);
    int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table);
    unsigned a_bits = get_alignment_bits(opc);
    unsigned s_bits = opc & MO_SIZE;
    unsigned a_mask = (1u << a_bits) - 1;
@@ -1659,24 +1660,6 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp opc,
    TCGType mask_type;
    uint64_t compare_mask;

    if (table_ofs > 0xfff) {
        int table_hi = table_ofs & ~0xfff;
        int mask_hi = mask_ofs & ~0xfff;

        table_base = TCG_REG_X1;
        if (mask_hi == table_hi) {
            mask_base = table_base;
        } else if (mask_hi) {
            mask_base = TCG_REG_X0;
            tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64,
                         mask_base, TCG_AREG0, mask_hi);
        }
        tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64,
                     table_base, TCG_AREG0, table_hi);
        mask_ofs -= mask_hi;
        table_ofs -= table_hi;
    }

    mask_type = (TARGET_PAGE_BITS + CPU_TLB_DYN_MAX_BITS > 32
                 ? TCG_TYPE_I64 : TCG_TYPE_I32);

+8 −32
Original line number Diff line number Diff line
@@ -1220,9 +1220,9 @@ static TCGReg tcg_out_arg_reg64(TCGContext *s, TCGReg argreg,

#define TLB_SHIFT	(CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)

/* We expect to use a 20-bit unsigned offset from ENV.  */
QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_.f[NB_MMU_MODES - 1].table)
                  > 0xfffff);
/* We expect to use an 9-bit sign-magnitude negative offset from ENV.  */
QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0);
QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -256);

/* Load and compare a TLB entry, leaving the flags set.  Returns the register
   containing the addend of the tlb entry.  Clobbers R0, R1, R2, TMP.  */
@@ -1232,39 +1232,15 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
{
    int cmp_off = (is_load ? offsetof(CPUTLBEntry, addr_read)
                   : offsetof(CPUTLBEntry, addr_write));
    int mask_off = offsetof(CPUArchState, tlb_.f[mem_index].mask);
    int table_off = offsetof(CPUArchState, tlb_.f[mem_index].table);
    TCGReg mask_base = TCG_AREG0, table_base = TCG_AREG0;
    int fast_off = TLB_MASK_TABLE_OFS(mem_index);
    int mask_off = fast_off + offsetof(CPUTLBDescFast, mask);
    int table_off = fast_off + offsetof(CPUTLBDescFast, table);
    unsigned s_bits = opc & MO_SIZE;
    unsigned a_bits = get_alignment_bits(opc);

    if (table_off > 0xfff) {
        int mask_hi = mask_off & ~0xfff;
        int table_hi = table_off & ~0xfff;
        int rot;

        table_base = TCG_REG_R2;
        if (mask_hi == table_hi) {
            mask_base = table_base;
        } else if (mask_hi) {
            mask_base = TCG_REG_TMP;
            rot = encode_imm(mask_hi);
            assert(rot >= 0);
            tcg_out_dat_imm(s, COND_AL, ARITH_ADD, mask_base, TCG_AREG0,
                            rotl(mask_hi, rot) | (rot << 7));
        }
        rot = encode_imm(table_hi);
        assert(rot >= 0);
        tcg_out_dat_imm(s, COND_AL, ARITH_ADD, table_base, TCG_AREG0,
                        rotl(table_hi, rot) | (rot << 7));

        mask_off -= mask_hi;
        table_off -= table_hi;
    }

    /* Load tlb_mask[mmu_idx] and tlb_table[mmu_idx].  */
    tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP, mask_base, mask_off);
    tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_R2, table_base, table_off);
    tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP, TCG_AREG0, mask_off);
    tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_R2, TCG_AREG0, table_off);

    /* Extract the tlb index from the address into TMP.  */
    tcg_out_dat_reg(s, COND_AL, ARITH_AND, TCG_REG_TMP, TCG_REG_TMP, addrlo,
+4 −2
Original line number Diff line number Diff line
@@ -1730,10 +1730,12 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
                   TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);

    tcg_out_modrm_offset(s, OPC_AND_GvEv + trexw, r0, TCG_AREG0,
                         offsetof(CPUArchState, tlb_.f[mem_index].mask));
                         TLB_MASK_TABLE_OFS(mem_index) +
                         offsetof(CPUTLBDescFast, mask));

    tcg_out_modrm_offset(s, OPC_ADD_GvEv + hrexw, r0, TCG_AREG0,
                         offsetof(CPUArchState, tlb_.f[mem_index].table));
                         TLB_MASK_TABLE_OFS(mem_index) +
                         offsetof(CPUTLBDescFast, table));

    /* If the required alignment is at least as large as the access, simply
       copy the address and mask.  For lesser alignments, check that we don't
Loading