drivers/virt/acrn/mm.c

Source file repositories/reference/linux-study-clean/drivers/virt/acrn/mm.c

File Facts

System
Linux kernel
Corpus path
drivers/virt/acrn/mm.c
Extension
.c
Size
9269 bytes
Lines
368
Domain
Driver Families
Bucket
drivers/virt
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if ((memmap->vma_base + memmap->len) > vma->vm_end) {
			mmap_read_unlock(current->mm);
			return -EINVAL;
		}

		for (i = 0; i < nr_pages; i++) {
			struct follow_pfnmap_args args = {
				.vma = vma,
				.address = memmap->vma_base + i * PAGE_SIZE,
			};

			ret = follow_pfnmap_start(&args);
			if (ret)
				break;

			cur_pfn = args.pfn;
			if (i == 0)
				start_pfn = cur_pfn;
			writable = args.writable;
			follow_pfnmap_end(&args);

			/* Disallow write access if the PTE is not writable. */
			if (!writable &&
			    (memmap->attr & ACRN_MEM_ACCESS_WRITE)) {
				ret = -EFAULT;
				break;
			}

			/* Disallow refcounted pages. */
			if (pfn_valid(cur_pfn) &&
			    !PageReserved(pfn_to_page(cur_pfn))) {
				ret = -EFAULT;
				break;
			}

			/* Disallow non-contiguous ranges. */
			if (cur_pfn != start_pfn + i) {
				ret = -EINVAL;
				break;
			}
		}
		mmap_read_unlock(current->mm);

		if (ret) {
			dev_dbg(acrn_dev.this_device,
				"Failed to lookup PFN at VMA:%p.\n", (void *)memmap->vma_base);
			return ret;
		}

		return acrn_mm_region_add(vm, memmap->user_vm_pa,
			 PFN_PHYS(start_pfn), memmap->len,
			 ACRN_MEM_TYPE_WB, memmap->attr);
	}
	mmap_read_unlock(current->mm);

	pages = vzalloc(array_size(nr_pages, sizeof(*pages)));
	if (!pages)
		return -ENOMEM;

	/* Lock the pages of user memory map region */
	pinned = pin_user_pages_fast(memmap->vma_base,
				     nr_pages, FOLL_WRITE | FOLL_LONGTERM,
				     pages);
	if (pinned < 0) {
		ret = pinned;
		goto free_pages;
	} else if (pinned != nr_pages) {
		ret = -EFAULT;
		goto put_pages;
	}

	/* Create a kernel map for the map region */
	remap_vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
	if (!remap_vaddr) {
		ret = -ENOMEM;
		goto put_pages;
	}

	/* Record Service VM va <-> User VM pa mapping */
	mutex_lock(&vm->regions_mapping_lock);
	region_mapping = &vm->regions_mapping[vm->regions_mapping_count];
	if (vm->regions_mapping_count < ACRN_MEM_MAPPING_MAX) {
		region_mapping->pages = pages;
		region_mapping->npages = nr_pages;
		region_mapping->size = memmap->len;
		region_mapping->service_vm_va = remap_vaddr;
		region_mapping->user_vm_pa = memmap->user_vm_pa;
		vm->regions_mapping_count++;
	} else {
		dev_warn(acrn_dev.this_device,

Annotation

Implementation Notes