xref: /kvmtool/arm/kvm-cpu.c (revision 85bd726a06b6e6208e24f51cea464427bb9cfe42)
1 #include "kvm/kvm.h"
2 #include "kvm/kvm-cpu.h"
3 
4 static int debug_fd;
5 
6 void kvm_cpu__set_debug_fd(int fd)
7 {
8 	debug_fd = fd;
9 }
10 
11 int kvm_cpu__get_debug_fd(void)
12 {
13 	return debug_fd;
14 }
15 
16 static struct kvm_arm_target *kvm_arm_generic_target;
17 static struct kvm_arm_target *kvm_arm_targets[KVM_ARM_NUM_TARGETS];
18 
19 void kvm_cpu__set_kvm_arm_generic_target(struct kvm_arm_target *target)
20 {
21 	kvm_arm_generic_target = target;
22 }
23 
24 int kvm_cpu__register_kvm_arm_target(struct kvm_arm_target *target)
25 {
26 	unsigned int i = 0;
27 
28 	for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
29 		if (!kvm_arm_targets[i]) {
30 			kvm_arm_targets[i] = target;
31 			return 0;
32 		}
33 	}
34 
35 	return -ENOSPC;
36 }
37 
38 struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id)
39 {
40 	struct kvm_arm_target *target;
41 	struct kvm_cpu *vcpu;
42 	int coalesced_offset, mmap_size, err = -1;
43 	unsigned int i;
44 	struct kvm_vcpu_init preferred_init;
45 	struct kvm_vcpu_init vcpu_init = {
46 		.features = ARM_VCPU_FEATURE_FLAGS(kvm, cpu_id)
47 	};
48 
49 	vcpu = calloc(1, sizeof(struct kvm_cpu));
50 	if (!vcpu)
51 		return NULL;
52 
53 	vcpu->vcpu_fd = ioctl(kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
54 	if (vcpu->vcpu_fd < 0)
55 		die_perror("KVM_CREATE_VCPU ioctl");
56 
57 	mmap_size = ioctl(kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
58 	if (mmap_size < 0)
59 		die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
60 
61 	vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED,
62 			     vcpu->vcpu_fd, 0);
63 	if (vcpu->kvm_run == MAP_FAILED)
64 		die("unable to mmap vcpu fd");
65 
66 	/*
67 	 * If the preferred target ioctl is successful then
68 	 * use preferred target else try each and every target type
69 	 */
70 	err = ioctl(kvm->vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init);
71 	if (!err) {
72 		/* Match preferred target CPU type. */
73 		target = NULL;
74 		for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
75 			if (!kvm_arm_targets[i])
76 				continue;
77 			if (kvm_arm_targets[i]->id == preferred_init.target) {
78 				target = kvm_arm_targets[i];
79 				break;
80 			}
81 		}
82 		if (!target) {
83 			target = kvm_arm_generic_target;
84 			vcpu_init.target = preferred_init.target;
85 		} else {
86 			vcpu_init.target = target->id;
87 		}
88 		err = ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_INIT, &vcpu_init);
89 	} else {
90 		/* Find an appropriate target CPU type. */
91 		for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
92 			if (!kvm_arm_targets[i])
93 				continue;
94 			target = kvm_arm_targets[i];
95 			vcpu_init.target = target->id;
96 			err = ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_INIT, &vcpu_init);
97 			if (!err)
98 				break;
99 		}
100 		if (err)
101 			die("Unable to find matching target");
102 	}
103 
104 	if (err || target->init(vcpu))
105 		die("Unable to initialise vcpu");
106 
107 	coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION,
108 				 KVM_CAP_COALESCED_MMIO);
109 	if (coalesced_offset)
110 		vcpu->ring = (void *)vcpu->kvm_run +
111 			     (coalesced_offset * PAGE_SIZE);
112 
113 	/* Populate the vcpu structure. */
114 	vcpu->kvm		= kvm;
115 	vcpu->cpu_id		= cpu_id;
116 	vcpu->cpu_type		= vcpu_init.target;
117 	vcpu->cpu_compatible	= target->compatible;
118 	vcpu->is_running	= true;
119 
120 	return vcpu;
121 }
122 
123 void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
124 {
125 }
126 
127 void kvm_cpu__delete(struct kvm_cpu *vcpu)
128 {
129 	free(vcpu);
130 }
131 
132 bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
133 {
134 	return false;
135 }
136 
137 bool kvm_cpu__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data,
138 			   u32 len, u8 is_write)
139 {
140 	if (arm_addr_in_virtio_mmio_region(phys_addr)) {
141 		return kvm__emulate_mmio(vcpu, phys_addr, data, len, is_write);
142 	} else if (arm_addr_in_ioport_region(phys_addr)) {
143 		int direction = is_write ? KVM_EXIT_IO_OUT : KVM_EXIT_IO_IN;
144 		u16 port = (phys_addr - KVM_IOPORT_AREA) & USHRT_MAX;
145 		return kvm__emulate_io(vcpu, port, data, direction, len, 1);
146 	} else if (arm_addr_in_pci_region(phys_addr)) {
147 		return kvm__emulate_mmio(vcpu, phys_addr, data, len, is_write);
148 	}
149 
150 	return false;
151 }
152 
153 void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
154 {
155 }
156