arch/x86/hyperv/ivm.c

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

File Facts

System
Linux kernel
Corpus path
arch/x86/hyperv/ivm.c
Extension
.c
Size
24180 bytes
Lines
947
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration 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

struct hv_enc_pfn_region {
	struct list_head list;
	u64 pfn;
	int count;
};

static LIST_HEAD(hv_list_enc);
static DEFINE_RAW_SPINLOCK(hv_list_enc_lock);

static int hv_list_enc_add(const u64 *pfn_list, int count)
{
	struct hv_enc_pfn_region *ent;
	unsigned long flags;
	u64 pfn;
	int i;

	for (i = 0; i < count; i++) {
		pfn = pfn_list[i];

		raw_spin_lock_irqsave(&hv_list_enc_lock, flags);
		/* Check if the PFN already exists in some region first */
		list_for_each_entry(ent, &hv_list_enc, list) {
			if ((ent->pfn <= pfn) && (ent->pfn + ent->count - 1 >= pfn))
				/* Nothing to do - pfn is already in the list */
				goto unlock_done;
		}

		/*
		 * Check if the PFN is adjacent to an existing region. Growing
		 * a region can make it adjacent to another one but merging is
		 * not (yet) implemented for simplicity. A PFN cannot be added
		 * to two regions to keep the logic in hv_list_enc_remove()
		 * correct.
		 */
		list_for_each_entry(ent, &hv_list_enc, list) {
			if (ent->pfn + ent->count == pfn) {
				/* Grow existing region up */
				ent->count++;
				goto unlock_done;
			} else if (pfn + 1 == ent->pfn) {
				/* Grow existing region down */
				ent->pfn--;
				ent->count++;
				goto unlock_done;
			}
		}
		raw_spin_unlock_irqrestore(&hv_list_enc_lock, flags);

		/* No adjacent region found -- create a new one */
		ent = kzalloc_obj(struct hv_enc_pfn_region);
		if (!ent)
			return -ENOMEM;

		ent->pfn = pfn;
		ent->count = 1;

		raw_spin_lock_irqsave(&hv_list_enc_lock, flags);
		list_add(&ent->list, &hv_list_enc);

unlock_done:
		raw_spin_unlock_irqrestore(&hv_list_enc_lock, flags);
	}

	return 0;
}

static int hv_list_enc_remove(const u64 *pfn_list, int count)
{
	struct hv_enc_pfn_region *ent, *t;
	struct hv_enc_pfn_region new_region;
	unsigned long flags;
	u64 pfn;
	int i;

	for (i = 0; i < count; i++) {
		pfn = pfn_list[i];

		raw_spin_lock_irqsave(&hv_list_enc_lock, flags);
		list_for_each_entry_safe(ent, t, &hv_list_enc, list) {
			if (pfn == ent->pfn + ent->count - 1) {
				/* Removing tail pfn */
				ent->count--;
				if (!ent->count) {
					list_del(&ent->list);
					kfree(ent);
				}
				goto unlock_done;
			} else if (pfn == ent->pfn) {
				/* Removing head pfn */
				ent->count--;

Annotation

Implementation Notes