1 #include "kvm/kvm.h"
2 #include "kvm/kvm-cpu.h"
3
4 static int debug_fd;
5
kvm_cpu__set_debug_fd(int fd)6 void kvm_cpu__set_debug_fd(int fd)
7 {
8 debug_fd = fd;
9 }
10
kvm_cpu__get_debug_fd(void)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
kvm_cpu__set_kvm_arm_generic_target(struct kvm_arm_target * target)19 void kvm_cpu__set_kvm_arm_generic_target(struct kvm_arm_target *target)
20 {
21 kvm_arm_generic_target = target;
22 }
23
kvm_cpu__register_kvm_arm_target(struct kvm_arm_target * target)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
kvm_cpu__arch_init(struct kvm * kvm,unsigned long cpu_id)38 struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id)
39 {
40 struct kvm_arm_target *target = NULL;
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 = {},
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 /* VCPU 0 is the boot CPU, the others start in a poweroff state. */
67 if (cpu_id > 0)
68 vcpu_init.features[0] |= (1UL << KVM_ARM_VCPU_POWER_OFF);
69
70 /* Set KVM_ARM_VCPU_PSCI_0_2 if available */
71 if (kvm__supports_extension(kvm, KVM_CAP_ARM_PSCI_0_2)) {
72 vcpu_init.features[0] |= (1UL << KVM_ARM_VCPU_PSCI_0_2);
73 }
74
75 kvm_cpu__select_features(kvm, &vcpu_init);
76
77 /*
78 * If the preferred target ioctl is successful then
79 * use preferred target else try each and every target type
80 */
81 err = ioctl(kvm->vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init);
82 if (!err) {
83 /* Match preferred target CPU type. */
84 for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
85 if (!kvm_arm_targets[i])
86 continue;
87 if (kvm_arm_targets[i]->id == preferred_init.target) {
88 target = kvm_arm_targets[i];
89 break;
90 }
91 }
92 if (!target) {
93 target = kvm_arm_generic_target;
94 vcpu_init.target = preferred_init.target;
95 } else {
96 vcpu_init.target = target->id;
97 }
98 err = ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_INIT, &vcpu_init);
99 } else {
100 /* Find an appropriate target CPU type. */
101 for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
102 if (!kvm_arm_targets[i])
103 continue;
104 target = kvm_arm_targets[i];
105 vcpu_init.target = target->id;
106 err = ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_INIT, &vcpu_init);
107 if (!err)
108 break;
109 }
110 if (err)
111 die("Unable to find matching target");
112 }
113
114 /* Populate the vcpu structure. */
115 vcpu->kvm = kvm;
116 vcpu->cpu_id = cpu_id;
117 vcpu->cpu_type = vcpu_init.target;
118 vcpu->cpu_compatible = target->compatible;
119 vcpu->is_running = true;
120
121 if (err || target->init(vcpu))
122 die("Unable to initialise vcpu");
123
124 coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION,
125 KVM_CAP_COALESCED_MMIO);
126 if (coalesced_offset)
127 vcpu->ring = (void *)vcpu->kvm_run +
128 (coalesced_offset * PAGE_SIZE);
129
130 if (kvm_cpu__configure_features(vcpu))
131 die("Unable to configure requested vcpu features");
132
133 return vcpu;
134 }
135
kvm_cpu__arch_nmi(struct kvm_cpu * cpu)136 void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
137 {
138 }
139
kvm_cpu__delete(struct kvm_cpu * vcpu)140 void kvm_cpu__delete(struct kvm_cpu *vcpu)
141 {
142 kvm_cpu__teardown_pvtime(vcpu->kvm);
143 free(vcpu);
144 }
145
kvm_cpu__handle_exit(struct kvm_cpu * vcpu)146 bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
147 {
148 return false;
149 }
150
kvm_cpu__show_page_tables(struct kvm_cpu * vcpu)151 void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
152 {
153 }
154