arm64: mm: Allocate ASIDs in pairs

In preparation for separate kernel/user ASIDs, allocate them in pairs
for each mm_struct. The bottom bit distinguishes the two: if it is set,
then the ASID will map only userspace.

Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Laura Abbott <labbott@redhat.com>
Tested-by: Shanker Donthineni <shankerd@codeaurora.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
Will Deacon 2017-08-10 14:10:28 +01:00
parent 27a921e757
commit 0c8ea531b7
2 changed files with 18 additions and 8 deletions

View File

@ -17,6 +17,7 @@
#define __ASM_MMU_H #define __ASM_MMU_H
#define MMCF_AARCH32 0x1 /* mm context flag for AArch32 executables */ #define MMCF_AARCH32 0x1 /* mm context flag for AArch32 executables */
#define USER_ASID_FLAG (UL(1) << 48)
typedef struct { typedef struct {
atomic64_t id; atomic64_t id;

View File

@ -39,7 +39,16 @@ static cpumask_t tlb_flush_pending;
#define ASID_MASK (~GENMASK(asid_bits - 1, 0)) #define ASID_MASK (~GENMASK(asid_bits - 1, 0))
#define ASID_FIRST_VERSION (1UL << asid_bits) #define ASID_FIRST_VERSION (1UL << asid_bits)
#define NUM_USER_ASIDS ASID_FIRST_VERSION
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
#define NUM_USER_ASIDS (ASID_FIRST_VERSION >> 1)
#define asid2idx(asid) (((asid) & ~ASID_MASK) >> 1)
#define idx2asid(idx) (((idx) << 1) & ~ASID_MASK)
#else
#define NUM_USER_ASIDS (ASID_FIRST_VERSION)
#define asid2idx(asid) ((asid) & ~ASID_MASK)
#define idx2asid(idx) asid2idx(idx)
#endif
/* Get the ASIDBits supported by the current CPU */ /* Get the ASIDBits supported by the current CPU */
static u32 get_cpu_asid_bits(void) static u32 get_cpu_asid_bits(void)
@ -98,7 +107,7 @@ static void flush_context(unsigned int cpu)
*/ */
if (asid == 0) if (asid == 0)
asid = per_cpu(reserved_asids, i); asid = per_cpu(reserved_asids, i);
__set_bit(asid & ~ASID_MASK, asid_map); __set_bit(asid2idx(asid), asid_map);
per_cpu(reserved_asids, i) = asid; per_cpu(reserved_asids, i) = asid;
} }
@ -153,16 +162,16 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
* We had a valid ASID in a previous life, so try to re-use * We had a valid ASID in a previous life, so try to re-use
* it if possible. * it if possible.
*/ */
asid &= ~ASID_MASK; if (!__test_and_set_bit(asid2idx(asid), asid_map))
if (!__test_and_set_bit(asid, asid_map))
return newasid; return newasid;
} }
/* /*
* Allocate a free ASID. If we can't find one, take a note of the * Allocate a free ASID. If we can't find one, take a note of the
* currently active ASIDs and mark the TLBs as requiring flushes. * currently active ASIDs and mark the TLBs as requiring flushes. We
* We always count from ASID #1, as we use ASID #0 when setting a * always count from ASID #2 (index 1), as we use ASID #0 when setting
* reserved TTBR0 for the init_mm. * a reserved TTBR0 for the init_mm and we allocate ASIDs in even/odd
* pairs.
*/ */
asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx); asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx);
if (asid != NUM_USER_ASIDS) if (asid != NUM_USER_ASIDS)
@ -179,7 +188,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
set_asid: set_asid:
__set_bit(asid, asid_map); __set_bit(asid, asid_map);
cur_idx = asid; cur_idx = asid;
return asid | generation; return idx2asid(asid) | generation;
} }
void check_and_switch_context(struct mm_struct *mm, unsigned int cpu) void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)