tools/testing/selftests/kvm/arm64/sea_to_user.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/kvm/arm64/sea_to_user.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/arm64/sea_to_user.c
Extension
.c
Size
9440 bytes
Lines
329
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

switch (get_ucall(vcpu, &uc)) {
		case UCALL_PRINTF:
			ksft_print_msg("From guest: %s", uc.buffer);
			break;
		case UCALL_DONE:
			ksft_print_msg("Guest done gracefully!\n");
			guest_done = 1;
			break;
		case UCALL_ABORT:
			ksft_print_msg("Guest aborted!\n");
			guest_done = 1;
			REPORT_GUEST_ASSERT(uc);
			break;
		default:
			TEST_FAIL("Unexpected ucall: %lu\n", uc.cmd);
		}
	} while (!guest_done);
}

static struct kvm_vm *vm_create_with_sea_handler(struct kvm_vcpu **vcpu)
{
	size_t backing_page_size;
	size_t guest_page_size;
	size_t alignment;
	u64 num_guest_pages;
	gpa_t start_gpa;
	enum vm_mem_backing_src_type src_type = VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB;
	struct kvm_vm *vm;

	backing_page_size = get_backing_src_pagesz(src_type);
	guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size;
	alignment = max(backing_page_size, guest_page_size);
	num_guest_pages = VM_MEM_SIZE / guest_page_size;

	vm = __vm_create_with_one_vcpu(vcpu, num_guest_pages, guest_code);
	vm_init_descriptor_tables(vm);
	vcpu_init_descriptor_tables(*vcpu);

	vm_install_sync_handler(vm,
		/*vector=*/VECTOR_SYNC_CURRENT,
		/*ec=*/ESR_ELx_EC_DABT_CUR,
		/*handler=*/expect_sea_handler);

	start_gpa = (vm->max_gfn - num_guest_pages) * guest_page_size;
	start_gpa = align_down(start_gpa, alignment);

	vm_userspace_mem_region_add(
		/*vm=*/vm,
		/*src_type=*/src_type,
		/*gpa=*/start_gpa,
		/*slot=*/1,
		/*npages=*/num_guest_pages,
		/*flags=*/0);

	virt_map(vm, START_GVA, start_gpa, num_guest_pages);

	ksft_print_msg("Mapped %#lx pages: gva=%#lx to gpa=%#lx\n",
		       num_guest_pages, START_GVA, start_gpa);
	return vm;
}

static void vm_inject_memory_uer(struct kvm_vm *vm)
{
	u64 guest_data;

	einj_gpa = addr_gva2gpa(vm, EINJ_GVA);
	einj_hva = addr_gva2hva(vm, EINJ_GVA);

	/* Populate certain data before injecting UER. */
	*(u64 *)einj_hva = 0xBAADCAFE;
	guest_data = *(u64 *)einj_hva;
	ksft_print_msg("Before EINJect: data=%#lx\n",
		guest_data);

	einj_hpa = translate_hva_to_hpa((unsigned long)einj_hva);

	ksft_print_msg("EINJ_GVA=%#lx, einj_gpa=%#lx, einj_hva=%p, einj_hpa=%#lx\n",
		       EINJ_GVA, einj_gpa, einj_hva, einj_hpa);

	inject_uer(einj_hpa);
	ksft_print_msg("Memory UER EINJected\n");
}

int main(int argc, char *argv[])
{
	struct kvm_vm *vm;
	struct kvm_vcpu *vcpu;

	TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SEA_TO_USER));

Annotation

Implementation Notes