xref: /kvmtool/arm/kvm-cpu.c (revision c2dad40280028f9e89a3451f29dd3aaa0bd2614f)
17c0e8b0cSWill Deacon #include "kvm/kvm.h"
27c0e8b0cSWill Deacon #include "kvm/kvm-cpu.h"
37c0e8b0cSWill Deacon 
47c0e8b0cSWill Deacon static int debug_fd;
57c0e8b0cSWill Deacon 
67c0e8b0cSWill Deacon void kvm_cpu__set_debug_fd(int fd)
77c0e8b0cSWill Deacon {
87c0e8b0cSWill Deacon 	debug_fd = fd;
97c0e8b0cSWill Deacon }
107c0e8b0cSWill Deacon 
117c0e8b0cSWill Deacon int kvm_cpu__get_debug_fd(void)
127c0e8b0cSWill Deacon {
137c0e8b0cSWill Deacon 	return debug_fd;
147c0e8b0cSWill Deacon }
157c0e8b0cSWill Deacon 
1685bd726aSAnup Patel static struct kvm_arm_target *kvm_arm_generic_target;
177c0e8b0cSWill Deacon static struct kvm_arm_target *kvm_arm_targets[KVM_ARM_NUM_TARGETS];
1885bd726aSAnup Patel 
1985bd726aSAnup Patel void kvm_cpu__set_kvm_arm_generic_target(struct kvm_arm_target *target)
2085bd726aSAnup Patel {
2185bd726aSAnup Patel 	kvm_arm_generic_target = target;
2285bd726aSAnup Patel }
2385bd726aSAnup Patel 
247c0e8b0cSWill Deacon int kvm_cpu__register_kvm_arm_target(struct kvm_arm_target *target)
257c0e8b0cSWill Deacon {
267c0e8b0cSWill Deacon 	unsigned int i = 0;
277c0e8b0cSWill Deacon 
287c0e8b0cSWill Deacon 	for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
297c0e8b0cSWill Deacon 		if (!kvm_arm_targets[i]) {
307c0e8b0cSWill Deacon 			kvm_arm_targets[i] = target;
317c0e8b0cSWill Deacon 			return 0;
327c0e8b0cSWill Deacon 		}
337c0e8b0cSWill Deacon 	}
347c0e8b0cSWill Deacon 
357c0e8b0cSWill Deacon 	return -ENOSPC;
367c0e8b0cSWill Deacon }
377c0e8b0cSWill Deacon 
387c0e8b0cSWill Deacon struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id)
397c0e8b0cSWill Deacon {
409b47146bSMarc Zyngier 	struct kvm_arm_target *target;
417c0e8b0cSWill Deacon 	struct kvm_cpu *vcpu;
427c0e8b0cSWill Deacon 	int coalesced_offset, mmap_size, err = -1;
437c0e8b0cSWill Deacon 	unsigned int i;
4485bd726aSAnup Patel 	struct kvm_vcpu_init preferred_init;
4561076240SWill Deacon 	struct kvm_vcpu_init vcpu_init = {
4661076240SWill Deacon 		.features = ARM_VCPU_FEATURE_FLAGS(kvm, cpu_id)
4761076240SWill Deacon 	};
487c0e8b0cSWill Deacon 
497c0e8b0cSWill Deacon 	vcpu = calloc(1, sizeof(struct kvm_cpu));
507c0e8b0cSWill Deacon 	if (!vcpu)
517c0e8b0cSWill Deacon 		return NULL;
527c0e8b0cSWill Deacon 
537c0e8b0cSWill Deacon 	vcpu->vcpu_fd = ioctl(kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
547c0e8b0cSWill Deacon 	if (vcpu->vcpu_fd < 0)
557c0e8b0cSWill Deacon 		die_perror("KVM_CREATE_VCPU ioctl");
567c0e8b0cSWill Deacon 
577c0e8b0cSWill Deacon 	mmap_size = ioctl(kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
587c0e8b0cSWill Deacon 	if (mmap_size < 0)
597c0e8b0cSWill Deacon 		die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
607c0e8b0cSWill Deacon 
617c0e8b0cSWill Deacon 	vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED,
627c0e8b0cSWill Deacon 			     vcpu->vcpu_fd, 0);
637c0e8b0cSWill Deacon 	if (vcpu->kvm_run == MAP_FAILED)
647c0e8b0cSWill Deacon 		die("unable to mmap vcpu fd");
657c0e8b0cSWill Deacon 
66*c2dad402SAnup Patel 	/* Set KVM_ARM_VCPU_PSCI_0_2 if available */
67*c2dad402SAnup Patel 	if (kvm__supports_extension(kvm, KVM_CAP_ARM_PSCI_0_2)) {
68*c2dad402SAnup Patel 		vcpu_init.features[0] |= (1UL << KVM_ARM_VCPU_PSCI_0_2);
69*c2dad402SAnup Patel 	}
70*c2dad402SAnup Patel 
7185bd726aSAnup Patel 	/*
7285bd726aSAnup Patel 	 * If the preferred target ioctl is successful then
7385bd726aSAnup Patel 	 * use preferred target else try each and every target type
7485bd726aSAnup Patel 	 */
7585bd726aSAnup Patel 	err = ioctl(kvm->vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init);
7685bd726aSAnup Patel 	if (!err) {
7785bd726aSAnup Patel 		/* Match preferred target CPU type. */
7885bd726aSAnup Patel 		target = NULL;
7985bd726aSAnup Patel 		for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
8085bd726aSAnup Patel 			if (!kvm_arm_targets[i])
8185bd726aSAnup Patel 				continue;
8285bd726aSAnup Patel 			if (kvm_arm_targets[i]->id == preferred_init.target) {
8385bd726aSAnup Patel 				target = kvm_arm_targets[i];
8485bd726aSAnup Patel 				break;
8585bd726aSAnup Patel 			}
8685bd726aSAnup Patel 		}
8785bd726aSAnup Patel 		if (!target) {
8885bd726aSAnup Patel 			target = kvm_arm_generic_target;
8985bd726aSAnup Patel 			vcpu_init.target = preferred_init.target;
9085bd726aSAnup Patel 		} else {
9185bd726aSAnup Patel 			vcpu_init.target = target->id;
9285bd726aSAnup Patel 		}
9385bd726aSAnup Patel 		err = ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_INIT, &vcpu_init);
9485bd726aSAnup Patel 	} else {
957c0e8b0cSWill Deacon 		/* Find an appropriate target CPU type. */
967c0e8b0cSWill Deacon 		for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
978d0413d2SMarc Zyngier 			if (!kvm_arm_targets[i])
988d0413d2SMarc Zyngier 				continue;
999b47146bSMarc Zyngier 			target = kvm_arm_targets[i];
1009b47146bSMarc Zyngier 			vcpu_init.target = target->id;
1017c0e8b0cSWill Deacon 			err = ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_INIT, &vcpu_init);
1027c0e8b0cSWill Deacon 			if (!err)
1037c0e8b0cSWill Deacon 				break;
1047c0e8b0cSWill Deacon 		}
10585bd726aSAnup Patel 		if (err)
10685bd726aSAnup Patel 			die("Unable to find matching target");
10785bd726aSAnup Patel 	}
1087c0e8b0cSWill Deacon 
1099b47146bSMarc Zyngier 	if (err || target->init(vcpu))
11085bd726aSAnup Patel 		die("Unable to initialise vcpu");
1117c0e8b0cSWill Deacon 
1127c0e8b0cSWill Deacon 	coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION,
1137c0e8b0cSWill Deacon 				 KVM_CAP_COALESCED_MMIO);
1147c0e8b0cSWill Deacon 	if (coalesced_offset)
1157c0e8b0cSWill Deacon 		vcpu->ring = (void *)vcpu->kvm_run +
1167c0e8b0cSWill Deacon 			     (coalesced_offset * PAGE_SIZE);
1177c0e8b0cSWill Deacon 
1187c0e8b0cSWill Deacon 	/* Populate the vcpu structure. */
1197c0e8b0cSWill Deacon 	vcpu->kvm		= kvm;
1207c0e8b0cSWill Deacon 	vcpu->cpu_id		= cpu_id;
12185bd726aSAnup Patel 	vcpu->cpu_type		= vcpu_init.target;
1229b47146bSMarc Zyngier 	vcpu->cpu_compatible	= target->compatible;
1237c0e8b0cSWill Deacon 	vcpu->is_running	= true;
12485bd726aSAnup Patel 
1257c0e8b0cSWill Deacon 	return vcpu;
1267c0e8b0cSWill Deacon }
1277c0e8b0cSWill Deacon 
1287c0e8b0cSWill Deacon void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
1297c0e8b0cSWill Deacon {
1307c0e8b0cSWill Deacon }
1317c0e8b0cSWill Deacon 
1327c0e8b0cSWill Deacon void kvm_cpu__delete(struct kvm_cpu *vcpu)
1337c0e8b0cSWill Deacon {
1347c0e8b0cSWill Deacon 	free(vcpu);
1357c0e8b0cSWill Deacon }
1367c0e8b0cSWill Deacon 
1377c0e8b0cSWill Deacon bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
1387c0e8b0cSWill Deacon {
1397c0e8b0cSWill Deacon 	return false;
1407c0e8b0cSWill Deacon }
1417c0e8b0cSWill Deacon 
1429b735910SMarc Zyngier bool kvm_cpu__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data,
1439b735910SMarc Zyngier 			   u32 len, u8 is_write)
1447c0e8b0cSWill Deacon {
145d8bd1e1fSWill Deacon 	if (arm_addr_in_virtio_mmio_region(phys_addr)) {
1469b735910SMarc Zyngier 		return kvm__emulate_mmio(vcpu, phys_addr, data, len, is_write);
147d8bd1e1fSWill Deacon 	} else if (arm_addr_in_ioport_region(phys_addr)) {
148d8bd1e1fSWill Deacon 		int direction = is_write ? KVM_EXIT_IO_OUT : KVM_EXIT_IO_IN;
149c3e5e101SWill Deacon 		u16 port = (phys_addr - KVM_IOPORT_AREA) & USHRT_MAX;
1504123ca55SMarc Zyngier 		return kvm__emulate_io(vcpu, port, data, direction, len, 1);
151fcc922bfSWill Deacon 	} else if (arm_addr_in_pci_region(phys_addr)) {
1529b735910SMarc Zyngier 		return kvm__emulate_mmio(vcpu, phys_addr, data, len, is_write);
153d8bd1e1fSWill Deacon 	}
1547c0e8b0cSWill Deacon 
1557c0e8b0cSWill Deacon 	return false;
1567c0e8b0cSWill Deacon }
1577c0e8b0cSWill Deacon 
1587c0e8b0cSWill Deacon void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
1597c0e8b0cSWill Deacon {
1607c0e8b0cSWill Deacon }
161