Commit b345e140 authored by Max Filippov's avatar Max Filippov
Browse files

target/xtensa: implement exclusive access option



The Exclusive Instructions provide a general-purpose mechanism for
atomic updates of memory-based synchronization variables that can be
used for exclusion algorithms.

Use cmpxchg-based implementation that is sufficient for the typical use
of exclusive access in atomic operations.

Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
parent 98736654
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ static void xtensa_cpu_reset(CPUState *s)
            XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15;
    env->sregs[CONFIGID0] = env->config->configid[0];
    env->sregs[CONFIGID1] = env->config->configid[1];
    env->exclusive_addr = -1;

#ifndef CONFIG_USER_ONLY
    reset_mmu(env);
+2 −0
Original line number Diff line number Diff line
@@ -527,6 +527,8 @@ typedef struct CPUXtensaState {
    } fregs[16];
    float_status fp_status;
    uint32_t windowbase_next;
    uint32_t exclusive_addr;
    uint32_t exclusive_val;

#ifndef CONFIG_USER_ONLY
    xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE];
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ DEF_HELPER_1(check_interrupts, void, env)
DEF_HELPER_2(intset, void, env, i32)
DEF_HELPER_2(intclear, void, env, i32)
DEF_HELPER_3(check_atomctl, void, env, i32, i32)
DEF_HELPER_4(check_exclusive, void, env, i32, i32, i32)
DEF_HELPER_2(wsr_memctl, void, env, i32)

DEF_HELPER_2(itlb_hit_test, void, env, i32)
+42 −0
Original line number Diff line number Diff line
@@ -130,6 +130,48 @@ void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
    }
}

void HELPER(check_exclusive)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr,
                             uint32_t is_write)
{
    uint32_t paddr, page_size, access;
    uint32_t atomctl = env->sregs[ATOMCTL];
    int rc = xtensa_get_physical_addr(env, true, vaddr, is_write,
                                      xtensa_get_cring(env), &paddr,
                                      &page_size, &access);

    if (rc) {
        HELPER(exception_cause_vaddr)(env, pc, rc, vaddr);
    }

    /* When data cache is not configured use ATOMCTL bypass field. */
    if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
        access = PAGE_CACHE_BYPASS;
    }

    switch (access & PAGE_CACHE_MASK) {
    case PAGE_CACHE_WB:
        atomctl >>= 2;
        /* fall through */
    case PAGE_CACHE_WT:
        atomctl >>= 2;
        /* fall through */
    case PAGE_CACHE_BYPASS:
        if ((atomctl & 0x3) == 0) {
            HELPER(exception_cause_vaddr)(env, pc,
                                          EXCLUSIVE_ERROR_CAUSE, vaddr);
        }
        break;

    case PAGE_CACHE_ISOLATE:
        HELPER(exception_cause_vaddr)(env, pc,
                LOAD_STORE_ERROR_CAUSE, vaddr);
        break;

    default:
        break;
    }
}

void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v)
{
    if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) {
+6 −2
Original line number Diff line number Diff line
@@ -76,6 +76,10 @@
#define XCHAL_HAVE_MPU 0
#endif

#ifndef XCHAL_HAVE_EXCLUSIVE
#define XCHAL_HAVE_EXCLUSIVE 0
#endif

#define XCHAL_OPTION(xchal, qemu) ((xchal) ? XTENSA_OPTION_BIT(qemu) : 0)

#define XTENSA_OPTIONS ( \
@@ -96,8 +100,8 @@
    XCHAL_OPTION(XCHAL_HAVE_FP, XTENSA_OPTION_FP_COPROCESSOR) | \
    XCHAL_OPTION(XCHAL_HAVE_RELEASE_SYNC, XTENSA_OPTION_MP_SYNCHRO) | \
    XCHAL_OPTION(XCHAL_HAVE_S32C1I, XTENSA_OPTION_CONDITIONAL_STORE) | \
    XCHAL_OPTION(XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION >= 230000, \
        XTENSA_OPTION_ATOMCTL) | \
    XCHAL_OPTION(((XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION >= 230000) || \
                  XCHAL_HAVE_EXCLUSIVE), XTENSA_OPTION_ATOMCTL) | \
    XCHAL_OPTION(XCHAL_HAVE_DEPBITS, XTENSA_OPTION_DEPBITS) | \
    /* Interrupts and exceptions */ \
    XCHAL_OPTION(XCHAL_HAVE_EXCEPTIONS, XTENSA_OPTION_EXCEPTION) | \
Loading