| /* | |
| * Constants for memory operations | |
| * | |
| * Authors: | |
| * Richard Henderson <rth@twiddle.net> | |
| * | |
| * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
| * See the COPYING file in the top-level directory. | |
| * | |
| */ | |
| #ifndef MEMOP_H | |
| #define MEMOP_H | |
| #include "qemu/host-utils.h" | |
| typedef enum MemOp { | |
| MO_8 = 0, | |
| MO_16 = 1, | |
| MO_32 = 2, | |
| MO_64 = 3, | |
| MO_128 = 4, | |
| MO_256 = 5, | |
| MO_512 = 6, | |
| MO_1024 = 7, | |
| MO_SIZE = 0x07, /* Mask for the above. */ | |
| MO_SIGN = 0x08, /* Sign-extended, otherwise zero-extended. */ | |
| MO_BSWAP = 0x10, /* Host reverse endian. */ | |
| #if HOST_BIG_ENDIAN | |
| MO_LE = MO_BSWAP, | |
| MO_BE = 0, | |
| #else | |
| MO_LE = 0, | |
| MO_BE = MO_BSWAP, | |
| #endif | |
| #ifdef COMPILING_PER_TARGET | |
| #if TARGET_BIG_ENDIAN | |
| MO_TE = MO_BE, | |
| #else | |
| MO_TE = MO_LE, | |
| #endif | |
| #endif | |
| /* | |
| * MO_UNALN accesses are never checked for alignment. | |
| * MO_ALIGN accesses will result in a call to the CPU's | |
| * do_unaligned_access hook if the guest address is not aligned. | |
| * | |
| * Some architectures (e.g. ARMv8) need the address which is aligned | |
| * to a size more than the size of the memory access. | |
| * Some architectures (e.g. SPARCv9) need an address which is aligned, | |
| * but less strictly than the natural alignment. | |
| * | |
| * MO_ALIGN supposes the alignment size is the size of a memory access. | |
| * | |
| * There are three options: | |
| * - unaligned access permitted (MO_UNALN). | |
| * - an alignment to the size of an access (MO_ALIGN); | |
| * - an alignment to a specified size, which may be more or less than | |
| * the access size (MO_ALIGN_x where 'x' is a size in bytes); | |
| */ | |
| MO_ASHIFT = 5, | |
| MO_AMASK = 0x7 << MO_ASHIFT, | |
| MO_UNALN = 0, | |
| MO_ALIGN_2 = 1 << MO_ASHIFT, | |
| MO_ALIGN_4 = 2 << MO_ASHIFT, | |
| MO_ALIGN_8 = 3 << MO_ASHIFT, | |
| MO_ALIGN_16 = 4 << MO_ASHIFT, | |
| MO_ALIGN_32 = 5 << MO_ASHIFT, | |
| MO_ALIGN_64 = 6 << MO_ASHIFT, | |
| MO_ALIGN = MO_AMASK, | |
| /* | |
| * MO_ATOM_* describes the atomicity requirements of the operation: | |
| * MO_ATOM_IFALIGN: the operation must be single-copy atomic if it | |
| * is aligned; if unaligned there is no atomicity. | |
| * MO_ATOM_IFALIGN_PAIR: the entire operation may be considered to | |
| * be a pair of half-sized operations which are packed together | |
| * for convenience, with single-copy atomicity on each half if | |
| * the half is aligned. | |
| * This is the atomicity e.g. of Arm pre-FEAT_LSE2 LDP. | |
| * MO_ATOM_WITHIN16: the operation is single-copy atomic, even if it | |
| * is unaligned, so long as it does not cross a 16-byte boundary; | |
| * if it crosses a 16-byte boundary there is no atomicity. | |
| * This is the atomicity e.g. of Arm FEAT_LSE2 LDR. | |
| * MO_ATOM_WITHIN16_PAIR: the entire operation is single-copy atomic, | |
| * if it happens to be within a 16-byte boundary, otherwise it | |
| * devolves to a pair of half-sized MO_ATOM_WITHIN16 operations. | |
| * Depending on alignment, one or both will be single-copy atomic. | |
| * This is the atomicity e.g. of Arm FEAT_LSE2 LDP. | |
| * MO_ATOM_SUBALIGN: the operation is single-copy atomic by parts | |
| * by the alignment. E.g. if an 8-byte value is accessed at an | |
| * address which is 0 mod 8, then the whole 8-byte access is | |
| * single-copy atomic; otherwise, if it is accessed at 0 mod 4 | |
| * then each 4-byte subobject is single-copy atomic; otherwise | |
| * if it is accessed at 0 mod 2 then the four 2-byte subobjects | |
| * are single-copy atomic. | |
| * This is the atomicity e.g. of IBM Power. | |
| * MO_ATOM_NONE: the operation has no atomicity requirements. | |
| * | |
| * Note the default (i.e. 0) value is single-copy atomic to the | |
| * size of the operation, if aligned. This retains the behaviour | |
| * from before this field was introduced. | |
| */ | |
| MO_ATOM_SHIFT = 8, | |
| MO_ATOM_IFALIGN = 0 << MO_ATOM_SHIFT, | |
| MO_ATOM_IFALIGN_PAIR = 1 << MO_ATOM_SHIFT, | |
| MO_ATOM_WITHIN16 = 2 << MO_ATOM_SHIFT, | |
| MO_ATOM_WITHIN16_PAIR = 3 << MO_ATOM_SHIFT, | |
| MO_ATOM_SUBALIGN = 4 << MO_ATOM_SHIFT, | |
| MO_ATOM_NONE = 5 << MO_ATOM_SHIFT, | |
| MO_ATOM_MASK = 7 << MO_ATOM_SHIFT, | |
| /* Combinations of the above, for ease of use. */ | |
| MO_UB = MO_8, | |
| MO_UW = MO_16, | |
| MO_UL = MO_32, | |
| MO_UQ = MO_64, | |
| MO_UO = MO_128, | |
| MO_SB = MO_SIGN | MO_8, | |
| MO_SW = MO_SIGN | MO_16, | |
| MO_SL = MO_SIGN | MO_32, | |
| MO_SQ = MO_SIGN | MO_64, | |
| MO_SO = MO_SIGN | MO_128, | |
| MO_LEUW = MO_LE | MO_UW, | |
| MO_LEUL = MO_LE | MO_UL, | |
| MO_LEUQ = MO_LE | MO_UQ, | |
| MO_LESW = MO_LE | MO_SW, | |
| MO_LESL = MO_LE | MO_SL, | |
| MO_LESQ = MO_LE | MO_SQ, | |
| MO_BEUW = MO_BE | MO_UW, | |
| MO_BEUL = MO_BE | MO_UL, | |
| MO_BEUQ = MO_BE | MO_UQ, | |
| MO_BESW = MO_BE | MO_SW, | |
| MO_BESL = MO_BE | MO_SL, | |
| MO_BESQ = MO_BE | MO_SQ, | |
| #ifdef COMPILING_PER_TARGET | |
| MO_TEUW = MO_TE | MO_UW, | |
| MO_TEUL = MO_TE | MO_UL, | |
| MO_TEUQ = MO_TE | MO_UQ, | |
| MO_TEUO = MO_TE | MO_UO, | |
| MO_TESW = MO_TE | MO_SW, | |
| MO_TESL = MO_TE | MO_SL, | |
| MO_TESQ = MO_TE | MO_SQ, | |
| #endif | |
| MO_SSIZE = MO_SIZE | MO_SIGN, | |
| } MemOp; | |
| /* MemOp to size in bytes. */ | |
| static inline unsigned memop_size(MemOp op) | |
| { | |
| return 1 << (op & MO_SIZE); | |
| } | |
| /* Size in bytes to MemOp. */ | |
| static inline MemOp size_memop(unsigned size) | |
| { | |
| #ifdef CONFIG_DEBUG_TCG | |
| /* Power of 2 up to 1024 */ | |
| assert(is_power_of_2(size) && size >= 1 && size <= (1 << MO_SIZE)); | |
| #endif | |
| return (MemOp)ctz32(size); | |
| } | |
| /** | |
| * memop_alignment_bits: | |
| * @memop: MemOp value | |
| * | |
| * Extract the alignment size from the memop. | |
| */ | |
| static inline unsigned memop_alignment_bits(MemOp memop) | |
| { | |
| unsigned a = memop & MO_AMASK; | |
| if (a == MO_UNALN) { | |
| /* No alignment required. */ | |
| a = 0; | |
| } else if (a == MO_ALIGN) { | |
| /* A natural alignment requirement. */ | |
| a = memop & MO_SIZE; | |
| } else { | |
| /* A specific alignment requirement. */ | |
| a = a >> MO_ASHIFT; | |
| } | |
| return a; | |
| } | |
| /* | |
| * memop_atomicity_bits: | |
| * @memop: MemOp value | |
| * | |
| * Extract the atomicity size from the memop. | |
| */ | |
| static inline unsigned memop_atomicity_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; | |
| } | |
| #endif |