arch/x86/hyperv/mmu.c

Source file repositories/reference/linux-study-clean/arch/x86/hyperv/mmu.c

File Facts

System
Linux kernel
Corpus path
arch/x86/hyperv/mmu.c
Extension
.c
Size
6556 bytes
Lines
247
Domain
Architecture Layer
Bucket
arch/x86
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 (diff >= HV_TLB_FLUSH_UNIT) {
			gva_list[gva_n] |= ~PAGE_MASK;
			cur += HV_TLB_FLUSH_UNIT;
		}  else if (diff) {
			gva_list[gva_n] |= (diff - 1) >> PAGE_SHIFT;
			cur = end;
		}

		gva_n++;

	} while (cur < end);

	return gva_n - offset;
}

static bool cpu_is_lazy(int cpu)
{
	return per_cpu(cpu_tlbstate_shared.is_lazy, cpu);
}

static void hyperv_flush_tlb_multi(const struct cpumask *cpus,
				   const struct flush_tlb_info *info)
{
	int cpu, vcpu, gva_n, max_gvas;
	struct hv_tlb_flush *flush;
	u64 status;
	unsigned long flags;
	bool do_lazy = !info->freed_tables;

	trace_hyperv_mmu_flush_tlb_multi(cpus, info);

	if (!hv_hypercall_pg)
		goto do_native;

	local_irq_save(flags);

	flush = *this_cpu_ptr(hyperv_pcpu_input_arg);

	if (unlikely(!flush)) {
		local_irq_restore(flags);
		goto do_native;
	}

	if (info->mm) {
		/*
		 * AddressSpace argument must match the CR3 with PCID bits
		 * stripped out.
		 */
		flush->address_space = virt_to_phys(info->mm->pgd);
		flush->address_space &= CR3_ADDR_MASK;
		flush->flags = 0;
	} else {
		flush->address_space = 0;
		flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
	}

	flush->processor_mask = 0;
	if (cpumask_equal(cpus, cpu_present_mask)) {
		flush->flags |= HV_FLUSH_ALL_PROCESSORS;
	} else {
		/*
		 * From the supplied CPU set we need to figure out if we can get
		 * away with cheaper HVCALL_FLUSH_VIRTUAL_ADDRESS_{LIST,SPACE}
		 * hypercalls. This is possible when the highest VP number in
		 * the set is < 64. As VP numbers are usually in ascending order
		 * and match Linux CPU ids, here is an optimization: we check
		 * the VP number for the highest bit in the supplied set first
		 * so we can quickly find out if using *_EX hypercalls is a
		 * must. We will also check all VP numbers when walking the
		 * supplied CPU set to remain correct in all cases.
		 */
		cpu = cpumask_last(cpus);

		if (cpu < nr_cpumask_bits && hv_cpu_number_to_vp_number(cpu) >= 64)
			goto do_ex_hypercall;

		for_each_cpu(cpu, cpus) {
			if (do_lazy && cpu_is_lazy(cpu))
				continue;
			vcpu = hv_cpu_number_to_vp_number(cpu);
			if (vcpu == VP_INVAL) {
				local_irq_restore(flags);
				goto do_native;
			}

			if (vcpu >= 64)
				goto do_ex_hypercall;

			__set_bit(vcpu, (unsigned long *)
				  &flush->processor_mask);

Annotation

Implementation Notes