arch/arm64/kvm/vmid.c

Source file repositories/reference/linux-study-clean/arch/arm64/kvm/vmid.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/vmid.c
Extension
.c
Size
5114 bytes
Lines
196
Domain
Architecture Layer
Bucket
arch/arm64
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (per_cpu(reserved_vmids, cpu) == vmid) {
			hit = true;
			per_cpu(reserved_vmids, cpu) = newvmid;
		}
	}

	return hit;
}

static u64 new_vmid(struct kvm_vmid *kvm_vmid)
{
	static u32 cur_idx = 1;
	u64 vmid = atomic64_read(&kvm_vmid->id);
	u64 generation = atomic64_read(&vmid_generation);

	if (vmid != 0) {
		u64 newvmid = generation | (vmid & ~VMID_MASK);

		if (check_update_reserved_vmid(vmid, newvmid)) {
			atomic64_set(&kvm_vmid->id, newvmid);
			return newvmid;
		}

		if (!__test_and_set_bit(vmid2idx(vmid), vmid_map)) {
			atomic64_set(&kvm_vmid->id, newvmid);
			return newvmid;
		}
	}

	vmid = find_next_zero_bit(vmid_map, NUM_USER_VMIDS, cur_idx);
	if (vmid != NUM_USER_VMIDS)
		goto set_vmid;

	/* We're out of VMIDs, so increment the global generation count */
	generation = atomic64_add_return_relaxed(VMID_FIRST_VERSION,
						 &vmid_generation);
	flush_context();

	/* We have more VMIDs than CPUs, so this will always succeed */
	vmid = find_next_zero_bit(vmid_map, NUM_USER_VMIDS, 1);

set_vmid:
	__set_bit(vmid, vmid_map);
	cur_idx = vmid;
	vmid = idx2vmid(vmid) | generation;
	atomic64_set(&kvm_vmid->id, vmid);
	return vmid;
}

/* Called from vCPU sched out with preemption disabled */
void kvm_arm_vmid_clear_active(void)
{
	atomic64_set(this_cpu_ptr(&active_vmids), VMID_ACTIVE_INVALID);
}

void kvm_arm_vmid_update(struct kvm_vmid *kvm_vmid)
{
	unsigned long flags;
	u64 vmid, old_active_vmid;

	vmid = atomic64_read(&kvm_vmid->id);

	/*
	 * Please refer comments in check_and_switch_context() in
	 * arch/arm64/mm/context.c.
	 *
	 * Unlike ASID allocator, we set the active_vmids to
	 * VMID_ACTIVE_INVALID on vCPU schedule out to avoid
	 * reserving the VMID space needlessly on rollover.
	 * Hence explicitly check here for a "!= 0" to
	 * handle the sync with a concurrent rollover.
	 */
	old_active_vmid = atomic64_read(this_cpu_ptr(&active_vmids));
	if (old_active_vmid != 0 && vmid_gen_match(vmid) &&
	    0 != atomic64_cmpxchg_relaxed(this_cpu_ptr(&active_vmids),
					  old_active_vmid, vmid))
		return;

	raw_spin_lock_irqsave(&cpu_vmid_lock, flags);

	/* Check that our VMID belongs to the current generation. */
	vmid = atomic64_read(&kvm_vmid->id);
	if (!vmid_gen_match(vmid))
		vmid = new_vmid(kvm_vmid);

	atomic64_set(this_cpu_ptr(&active_vmids), vmid);
	raw_spin_unlock_irqrestore(&cpu_vmid_lock, flags);
}

/*

Annotation

Implementation Notes