KVM
Macros | Functions | Variables
vmid.c File Reference
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
Include dependency graph for vmid.c:

Go to the source code of this file.

Macros

#define VMID_MASK   (~GENMASK(kvm_arm_vmid_bits - 1, 0))
 
#define VMID_FIRST_VERSION   (1UL << kvm_arm_vmid_bits)
 
#define NUM_USER_VMIDS   VMID_FIRST_VERSION
 
#define vmid2idx(vmid)   ((vmid) & ~VMID_MASK)
 
#define idx2vmid(idx)   vmid2idx(idx)
 
#define VMID_ACTIVE_INVALID   VMID_FIRST_VERSION
 
#define vmid_gen_match(vmid)    (!(((vmid) ^ atomic64_read(&vmid_generation)) >> kvm_arm_vmid_bits))
 

Functions

static DEFINE_RAW_SPINLOCK (cpu_vmid_lock)
 
static DEFINE_PER_CPU (atomic64_t, active_vmids)
 
static DEFINE_PER_CPU (u64, reserved_vmids)
 
static void flush_context (void)
 
static bool check_update_reserved_vmid (u64 vmid, u64 newvmid)
 
static u64 new_vmid (struct kvm_vmid *kvm_vmid)
 
void kvm_arm_vmid_clear_active (void)
 
bool kvm_arm_vmid_update (struct kvm_vmid *kvm_vmid)
 
int __init kvm_arm_vmid_alloc_init (void)
 
void __init kvm_arm_vmid_alloc_free (void)
 

Variables

unsigned int __ro_after_init kvm_arm_vmid_bits
 
static atomic64_t vmid_generation
 
static unsigned long * vmid_map
 

Macro Definition Documentation

◆ idx2vmid

#define idx2vmid (   idx)    vmid2idx(idx)

Definition at line 33 of file vmid.c.

◆ NUM_USER_VMIDS

#define NUM_USER_VMIDS   VMID_FIRST_VERSION

Definition at line 31 of file vmid.c.

◆ vmid2idx

#define vmid2idx (   vmid)    ((vmid) & ~VMID_MASK)

Definition at line 32 of file vmid.c.

◆ VMID_ACTIVE_INVALID

#define VMID_ACTIVE_INVALID   VMID_FIRST_VERSION

Definition at line 40 of file vmid.c.

◆ VMID_FIRST_VERSION

#define VMID_FIRST_VERSION   (1UL << kvm_arm_vmid_bits)

Definition at line 29 of file vmid.c.

◆ vmid_gen_match

#define vmid_gen_match (   vmid)     (!(((vmid) ^ atomic64_read(&vmid_generation)) >> kvm_arm_vmid_bits))

Definition at line 42 of file vmid.c.

◆ VMID_MASK

#define VMID_MASK   (~GENMASK(kvm_arm_vmid_bits - 1, 0))

Definition at line 28 of file vmid.c.

Function Documentation

◆ check_update_reserved_vmid()

static bool check_update_reserved_vmid ( u64  vmid,
u64  newvmid 
)
static

Definition at line 72 of file vmid.c.

73 {
74  int cpu;
75  bool hit = false;
76 
77  /*
78  * Iterate over the set of reserved VMIDs looking for a match
79  * and update to use newvmid (i.e. the same VMID in the current
80  * generation).
81  */
82  for_each_possible_cpu(cpu) {
83  if (per_cpu(reserved_vmids, cpu) == vmid) {
84  hit = true;
85  per_cpu(reserved_vmids, cpu) = newvmid;
86  }
87  }
88 
89  return hit;
90 }
Here is the caller graph for this function:

◆ DEFINE_PER_CPU() [1/2]

static DEFINE_PER_CPU ( atomic64_t  ,
active_vmids   
)
static

◆ DEFINE_PER_CPU() [2/2]

static DEFINE_PER_CPU ( u64  ,
reserved_vmids   
)
static

◆ DEFINE_RAW_SPINLOCK()

static DEFINE_RAW_SPINLOCK ( cpu_vmid_lock  )
static

◆ flush_context()

static void flush_context ( void  )
static

Definition at line 45 of file vmid.c.

46 {
47  int cpu;
48  u64 vmid;
49 
50  bitmap_zero(vmid_map, NUM_USER_VMIDS);
51 
52  for_each_possible_cpu(cpu) {
53  vmid = atomic64_xchg_relaxed(&per_cpu(active_vmids, cpu), 0);
54 
55  /* Preserve reserved VMID */
56  if (vmid == 0)
57  vmid = per_cpu(reserved_vmids, cpu);
58  __set_bit(vmid2idx(vmid), vmid_map);
59  per_cpu(reserved_vmids, cpu) = vmid;
60  }
61 
62  /*
63  * Unlike ASID allocator, we expect less frequent rollover in
64  * case of VMIDs. Hence, instead of marking the CPU as
65  * flush_pending and issuing a local context invalidation on
66  * the next context-switch, we broadcast TLB flush + I-cache
67  * invalidation over the inner shareable domain on rollover.
68  */
69  kvm_call_hyp(__kvm_flush_vm_context);
70 }
void __kvm_flush_vm_context(void)
Definition: tlb.c:197
#define NUM_USER_VMIDS
Definition: vmid.c:31
static unsigned long * vmid_map
Definition: vmid.c:23
#define vmid2idx(vmid)
Definition: vmid.c:32
Here is the call graph for this function:
Here is the caller graph for this function:

◆ kvm_arm_vmid_alloc_free()

void __init kvm_arm_vmid_alloc_free ( void  )

Definition at line 197 of file vmid.c.

198 {
199  bitmap_free(vmid_map);
200 }
Here is the caller graph for this function:

◆ kvm_arm_vmid_alloc_init()

int __init kvm_arm_vmid_alloc_init ( void  )

Definition at line 180 of file vmid.c.

181 {
182  kvm_arm_vmid_bits = kvm_get_vmid_bits();
183 
184  /*
185  * Expect allocation after rollover to fail if we don't have
186  * at least one more VMID than CPUs. VMID #0 is always reserved.
187  */
188  WARN_ON(NUM_USER_VMIDS - 1 <= num_possible_cpus());
189  atomic64_set(&vmid_generation, VMID_FIRST_VERSION);
190  vmid_map = bitmap_zalloc(NUM_USER_VMIDS, GFP_KERNEL);
191  if (!vmid_map)
192  return -ENOMEM;
193 
194  return 0;
195 }
unsigned int __ro_after_init kvm_arm_vmid_bits
Definition: vmid.c:19
static atomic64_t vmid_generation
Definition: vmid.c:22
#define VMID_FIRST_VERSION
Definition: vmid.c:29
Here is the caller graph for this function:

◆ kvm_arm_vmid_clear_active()

void kvm_arm_vmid_clear_active ( void  )

Definition at line 133 of file vmid.c.

134 {
135  atomic64_set(this_cpu_ptr(&active_vmids), VMID_ACTIVE_INVALID);
136 }
#define VMID_ACTIVE_INVALID
Definition: vmid.c:40
Here is the caller graph for this function:

◆ kvm_arm_vmid_update()

bool kvm_arm_vmid_update ( struct kvm_vmid *  kvm_vmid)

Definition at line 138 of file vmid.c.

139 {
140  unsigned long flags;
141  u64 vmid, old_active_vmid;
142  bool updated = false;
143 
144  vmid = atomic64_read(&kvm_vmid->id);
145 
146  /*
147  * Please refer comments in check_and_switch_context() in
148  * arch/arm64/mm/context.c.
149  *
150  * Unlike ASID allocator, we set the active_vmids to
151  * VMID_ACTIVE_INVALID on vCPU schedule out to avoid
152  * reserving the VMID space needlessly on rollover.
153  * Hence explicitly check here for a "!= 0" to
154  * handle the sync with a concurrent rollover.
155  */
156  old_active_vmid = atomic64_read(this_cpu_ptr(&active_vmids));
157  if (old_active_vmid != 0 && vmid_gen_match(vmid) &&
158  0 != atomic64_cmpxchg_relaxed(this_cpu_ptr(&active_vmids),
159  old_active_vmid, vmid))
160  return false;
161 
162  raw_spin_lock_irqsave(&cpu_vmid_lock, flags);
163 
164  /* Check that our VMID belongs to the current generation. */
165  vmid = atomic64_read(&kvm_vmid->id);
166  if (!vmid_gen_match(vmid)) {
167  vmid = new_vmid(kvm_vmid);
168  updated = true;
169  }
170 
171  atomic64_set(this_cpu_ptr(&active_vmids), vmid);
172  raw_spin_unlock_irqrestore(&cpu_vmid_lock, flags);
173 
174  return updated;
175 }
static u64 new_vmid(struct kvm_vmid *kvm_vmid)
Definition: vmid.c:92
#define vmid_gen_match(vmid)
Definition: vmid.c:42
Here is the call graph for this function:
Here is the caller graph for this function:

◆ new_vmid()

static u64 new_vmid ( struct kvm_vmid *  kvm_vmid)
static

Definition at line 92 of file vmid.c.

93 {
94  static u32 cur_idx = 1;
95  u64 vmid = atomic64_read(&kvm_vmid->id);
96  u64 generation = atomic64_read(&vmid_generation);
97 
98  if (vmid != 0) {
99  u64 newvmid = generation | (vmid & ~VMID_MASK);
100 
101  if (check_update_reserved_vmid(vmid, newvmid)) {
102  atomic64_set(&kvm_vmid->id, newvmid);
103  return newvmid;
104  }
105 
106  if (!__test_and_set_bit(vmid2idx(vmid), vmid_map)) {
107  atomic64_set(&kvm_vmid->id, newvmid);
108  return newvmid;
109  }
110  }
111 
112  vmid = find_next_zero_bit(vmid_map, NUM_USER_VMIDS, cur_idx);
113  if (vmid != NUM_USER_VMIDS)
114  goto set_vmid;
115 
116  /* We're out of VMIDs, so increment the global generation count */
117  generation = atomic64_add_return_relaxed(VMID_FIRST_VERSION,
118  &vmid_generation);
119  flush_context();
120 
121  /* We have more VMIDs than CPUs, so this will always succeed */
122  vmid = find_next_zero_bit(vmid_map, NUM_USER_VMIDS, 1);
123 
124 set_vmid:
125  __set_bit(vmid, vmid_map);
126  cur_idx = vmid;
127  vmid = idx2vmid(vmid) | generation;
128  atomic64_set(&kvm_vmid->id, vmid);
129  return vmid;
130 }
static bool check_update_reserved_vmid(u64 vmid, u64 newvmid)
Definition: vmid.c:72
#define VMID_MASK
Definition: vmid.c:28
static void flush_context(void)
Definition: vmid.c:45
#define idx2vmid(idx)
Definition: vmid.c:33
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ kvm_arm_vmid_bits

unsigned int __ro_after_init kvm_arm_vmid_bits

Definition at line 19 of file vmid.c.

◆ vmid_generation

atomic64_t vmid_generation
static

Definition at line 22 of file vmid.c.

◆ vmid_map

unsigned long* vmid_map
static

Definition at line 23 of file vmid.c.