accel/tcg: Introduce and use MO_ALIGN_TLB_ONLY

For Arm, we need 3 cases: (1) the alignment required when accessing
Normal memory, (2) the alignment required when accessing Device memory,
and (3) the atomicity of the access.

When we added TLB_CHECK_ALIGNED, we assumed that cases 2 and 3 were
identical, and thus used memop_atomicity_bits for TLB_CHECK_ALIGNED.

This is incorrect for multiple reasons, including that the atomicity
of the access is adjusted depending on whether or not we are executing
within a serial context.

For Arm, what is true is that there is an underlying alignment
requirement of the access, and for that access Normal memory
will support unalignement.

Introduce MO_ALIGN_TLB_ONLY to indicate that the alignment
specified in MO_AMASK only applies when the TLB entry has
TLB_CHECK_ALIGNED set; otherwise no alignment required.

Introduce memop_tlb_alignment_bits with an additional bool
argument that specifies whether TLB_CHECK_ALIGNED is set.
All other usage of memop_alignment_bits assumes it is not.

Remove memop_atomicity_bits as unused; it didn't properly
support MO_ATOM_SUBWORD anyway.

Update target/arm finalize_memop_atom to set MO_ALIGN_TLB_ONLY
when strict alignment isn't otherwise required.

Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3171
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
This commit is contained in:
Richard Henderson 2025-10-21 14:35:39 -05:00
parent 3728de3192
commit 4dea00368d
7 changed files with 35 additions and 49 deletions

View file

@ -72,6 +72,16 @@ typedef enum MemOp {
MO_ALIGN_64 = 6 << MO_ASHIFT,
MO_ALIGN = MO_AMASK,
/*
* MO_ALIGN_TLB_ONLY:
* Apply MO_AMASK only along the TCG slow path if TLB_CHECK_ALIGNED
* is set; otherwise unaligned access is permitted.
* This is used by target/arm, where unaligned accesses are
* permitted for pages marked Normal but aligned accesses are
* required for pages marked Device.
*/
MO_ALIGN_TLB_ONLY = 1 << 8,
/*
* MO_ATOM_* describes the atomicity requirements of the operation:
* MO_ATOM_IFALIGN: the operation must be single-copy atomic if it
@ -104,7 +114,7 @@ typedef enum MemOp {
* size of the operation, if aligned. This retains the behaviour
* from before this field was introduced.
*/
MO_ATOM_SHIFT = 8,
MO_ATOM_SHIFT = 9,
MO_ATOM_IFALIGN = 0 << MO_ATOM_SHIFT,
MO_ATOM_IFALIGN_PAIR = 1 << MO_ATOM_SHIFT,
MO_ATOM_WITHIN16 = 2 << MO_ATOM_SHIFT,
@ -169,16 +179,16 @@ static inline MemOp size_memop(unsigned size)
}
/**
* memop_alignment_bits:
* memop_tlb_alignment_bits:
* @memop: MemOp value
*
* Extract the alignment size from the memop.
* Extract the alignment size for use with TLB_CHECK_ALIGNED.
*/
static inline unsigned memop_alignment_bits(MemOp memop)
static inline unsigned memop_tlb_alignment_bits(MemOp memop, bool tlb_check)
{
unsigned a = memop & MO_AMASK;
if (a == MO_UNALN) {
if (a == MO_UNALN || (!tlb_check && (memop & MO_ALIGN_TLB_ONLY))) {
/* No alignment required. */
a = 0;
} else if (a == MO_ALIGN) {
@ -191,28 +201,15 @@ static inline unsigned memop_alignment_bits(MemOp memop)
return a;
}
/*
* memop_atomicity_bits:
/**
* memop_alignment_bits:
* @memop: MemOp value
*
* Extract the atomicity size from the memop.
* Extract the alignment size from the memop.
*/
static inline unsigned memop_atomicity_bits(MemOp memop)
static inline unsigned memop_alignment_bits(MemOp memop)
{
unsigned size = memop & MO_SIZE;
switch (memop & MO_ATOM_MASK) {
case MO_ATOM_NONE:
size = MO_8;
break;
case MO_ATOM_IFALIGN_PAIR:
case MO_ATOM_WITHIN16_PAIR:
size = size ? size - 1 : 0;
break;
default:
break;
}
return size;
return memop_tlb_alignment_bits(memop, false);
}
#endif