diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2023-06-06 10:19:39 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2023-06-06 10:19:39 +0100 |
commit | 5096ec5b32f14906bbc16b0728066723f502fa71 (patch) | |
tree | 5451d2f17364778d777aa9f59441611dca642594 /target/arm | |
parent | c1a1f80518d360b694b32d7a00cd91b79683d026 (diff) |
target/arm: Move mte check for store-exclusive
Push the mte check behind the exclusive_addr check.
Document the several ways that we are still out of spec
with this implementation.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20230530191438.411344-18-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/arm')
-rw-r--r-- | target/arm/tcg/translate-a64.c | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index adedebd1c2..aa93f37e21 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -2512,17 +2512,47 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, */ TCGLabel *fail_label = gen_new_label(); TCGLabel *done_label = gen_new_label(); - TCGv_i64 tmp, dirty_addr, clean_addr; + TCGv_i64 tmp, clean_addr; MemOp memop; - memop = (size + is_pair) | MO_ALIGN; - memop = finalize_memop(s, memop); - - dirty_addr = cpu_reg_sp(s, rn); - clean_addr = gen_mte_check1(s, dirty_addr, true, rn != 31, memop); + /* + * FIXME: We are out of spec here. We have recorded only the address + * from load_exclusive, not the entire range, and we assume that the + * size of the access on both sides match. The architecture allows the + * store to be smaller than the load, so long as the stored bytes are + * within the range recorded by the load. + */ + /* See AArch64.ExclusiveMonitorsPass() and AArch64.IsExclusiveVA(). */ + clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); tcg_gen_brcond_i64(TCG_COND_NE, clean_addr, cpu_exclusive_addr, fail_label); + /* + * The write, and any associated faults, only happen if the virtual + * and physical addresses pass the exclusive monitor check. These + * faults are exceedingly unlikely, because normally the guest uses + * the exact same address register for the load_exclusive, and we + * would have recognized these faults there. + * + * It is possible to trigger an alignment fault pre-LSE2, e.g. with an + * unaligned 4-byte write within the range of an aligned 8-byte load. + * With LSE2, the store would need to cross a 16-byte boundary when the + * load did not, which would mean the store is outside the range + * recorded for the monitor, which would have failed a corrected monitor + * check above. For now, we assume no size change and retain the + * MO_ALIGN to let tcg know what we checked in the load_exclusive. + * + * It is possible to trigger an MTE fault, by performing the load with + * a virtual address with a valid tag and performing the store with the + * same virtual address and a different invalid tag. + */ + memop = size + is_pair; + if (memop == MO_128 || !dc_isar_feature(aa64_lse2, s)) { + memop |= MO_ALIGN; + } + memop = finalize_memop(s, memop); + gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, memop); + tmp = tcg_temp_new_i64(); if (is_pair) { if (size == 2) { |