Revision a96c0514 target-arm/kvm.c

b/target-arm/kvm.c
27 27
    KVM_CAP_LAST_INFO
28 28
};
29 29

  
30
bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
31
                                      int *fdarray,
32
                                      struct kvm_vcpu_init *init)
33
{
34
    int ret, kvmfd = -1, vmfd = -1, cpufd = -1;
35

  
36
    kvmfd = qemu_open("/dev/kvm", O_RDWR);
37
    if (kvmfd < 0) {
38
        goto err;
39
    }
40
    vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
41
    if (vmfd < 0) {
42
        goto err;
43
    }
44
    cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
45
    if (cpufd < 0) {
46
        goto err;
47
    }
48

  
49
    ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, init);
50
    if (ret >= 0) {
51
        ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
52
        if (ret < 0) {
53
            goto err;
54
        }
55
    } else {
56
        /* Old kernel which doesn't know about the
57
         * PREFERRED_TARGET ioctl: we know it will only support
58
         * creating one kind of guest CPU which is its preferred
59
         * CPU type.
60
         */
61
        while (*cpus_to_try != QEMU_KVM_ARM_TARGET_NONE) {
62
            init->target = *cpus_to_try++;
63
            memset(init->features, 0, sizeof(init->features));
64
            ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
65
            if (ret >= 0) {
66
                break;
67
            }
68
        }
69
        if (ret < 0) {
70
            goto err;
71
        }
72
    }
73

  
74
    fdarray[0] = kvmfd;
75
    fdarray[1] = vmfd;
76
    fdarray[2] = cpufd;
77

  
78
    return true;
79

  
80
err:
81
    if (cpufd >= 0) {
82
        close(cpufd);
83
    }
84
    if (vmfd >= 0) {
85
        close(vmfd);
86
    }
87
    if (kvmfd >= 0) {
88
        close(kvmfd);
89
    }
90

  
91
    return false;
92
}
93

  
94
void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
95
{
96
    int i;
97

  
98
    for (i = 2; i >= 0; i--) {
99
        close(fdarray[i]);
100
    }
101
}
102

  
103
static inline void set_feature(uint64_t *features, int feature)
104
{
105
    *features |= 1ULL << feature;
106
}
107

  
108
bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
109
{
110
    /* Identify the feature bits corresponding to the host CPU, and
111
     * fill out the ARMHostCPUClass fields accordingly. To do this
112
     * we have to create a scratch VM, create a single CPU inside it,
113
     * and then query that CPU for the relevant ID registers.
114
     */
115
    int i, ret, fdarray[3];
116
    uint32_t midr, id_pfr0, id_isar0, mvfr1;
117
    uint64_t features = 0;
118
    /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
119
     * we know these will only support creating one kind of guest CPU,
120
     * which is its preferred CPU type.
121
     */
122
    static const uint32_t cpus_to_try[] = {
123
        QEMU_KVM_ARM_TARGET_CORTEX_A15,
124
        QEMU_KVM_ARM_TARGET_NONE
125
    };
126
    struct kvm_vcpu_init init;
127
    struct kvm_one_reg idregs[] = {
128
        {
129
            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
130
            | ENCODE_CP_REG(15, 0, 0, 0, 0, 0),
131
            .addr = (uintptr_t)&midr,
132
        },
133
        {
134
            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
135
            | ENCODE_CP_REG(15, 0, 0, 1, 0, 0),
136
            .addr = (uintptr_t)&id_pfr0,
137
        },
138
        {
139
            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
140
            | ENCODE_CP_REG(15, 0, 0, 2, 0, 0),
141
            .addr = (uintptr_t)&id_isar0,
142
        },
143
        {
144
            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
145
            | KVM_REG_ARM_VFP | KVM_REG_ARM_VFP_MVFR1,
146
            .addr = (uintptr_t)&mvfr1,
147
        },
148
    };
149

  
150
    if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
151
        return false;
152
    }
153

  
154
    ahcc->target = init.target;
155

  
156
    /* This is not strictly blessed by the device tree binding docs yet,
157
     * but in practice the kernel does not care about this string so
158
     * there is no point maintaining an KVM_ARM_TARGET_* -> string table.
159
     */
160
    ahcc->dtb_compatible = "arm,arm-v7";
161

  
162
    for (i = 0; i < ARRAY_SIZE(idregs); i++) {
163
        ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &idregs[i]);
164
        if (ret) {
165
            break;
166
        }
167
    }
168

  
169
    kvm_arm_destroy_scratch_host_vcpu(fdarray);
170

  
171
    if (ret) {
172
        return false;
173
    }
174

  
175
    /* Now we've retrieved all the register information we can
176
     * set the feature bits based on the ID register fields.
177
     * We can assume any KVM supporting CPU is at least a v7
178
     * with VFPv3, LPAE and the generic timers; this in turn implies
179
     * most of the other feature bits, but a few must be tested.
180
     */
181
    set_feature(&features, ARM_FEATURE_V7);
182
    set_feature(&features, ARM_FEATURE_VFP3);
183
    set_feature(&features, ARM_FEATURE_LPAE);
184
    set_feature(&features, ARM_FEATURE_GENERIC_TIMER);
185

  
186
    switch (extract32(id_isar0, 24, 4)) {
187
    case 1:
188
        set_feature(&features, ARM_FEATURE_THUMB_DIV);
189
        break;
190
    case 2:
191
        set_feature(&features, ARM_FEATURE_ARM_DIV);
192
        set_feature(&features, ARM_FEATURE_THUMB_DIV);
193
        break;
194
    default:
195
        break;
196
    }
197

  
198
    if (extract32(id_pfr0, 12, 4) == 1) {
199
        set_feature(&features, ARM_FEATURE_THUMB2EE);
200
    }
201
    if (extract32(mvfr1, 20, 4) == 1) {
202
        set_feature(&features, ARM_FEATURE_VFP_FP16);
203
    }
204
    if (extract32(mvfr1, 12, 4) == 1) {
205
        set_feature(&features, ARM_FEATURE_NEON);
206
    }
207
    if (extract32(mvfr1, 28, 4) == 1) {
208
        /* FMAC support implies VFPv4 */
209
        set_feature(&features, ARM_FEATURE_VFP4);
210
    }
211

  
212
    ahcc->features = features;
213

  
214
    return true;
215
}
216

  
217
static void kvm_arm_host_cpu_class_init(ObjectClass *oc, void *data)
218
{
219
    ARMHostCPUClass *ahcc = ARM_HOST_CPU_CLASS(oc);
220

  
221
    /* All we really need to set up for the 'host' CPU
222
     * is the feature bits -- we rely on the fact that the
223
     * various ID register values in ARMCPU are only used for
224
     * TCG CPUs.
225
     */
226
    if (!kvm_arm_get_host_cpu_features(ahcc)) {
227
        fprintf(stderr, "Failed to retrieve host CPU features!\n");
228
        abort();
229
    }
230
}
231

  
232
static void kvm_arm_host_cpu_initfn(Object *obj)
233
{
234
    ARMHostCPUClass *ahcc = ARM_HOST_CPU_GET_CLASS(obj);
235
    ARMCPU *cpu = ARM_CPU(obj);
236
    CPUARMState *env = &cpu->env;
237

  
238
    cpu->kvm_target = ahcc->target;
239
    cpu->dtb_compatible = ahcc->dtb_compatible;
240
    env->features = ahcc->features;
241
}
242

  
243
static const TypeInfo host_arm_cpu_type_info = {
244
    .name = TYPE_ARM_HOST_CPU,
245
    .parent = TYPE_ARM_CPU,
246
    .instance_init = kvm_arm_host_cpu_initfn,
247
    .class_init = kvm_arm_host_cpu_class_init,
248
    .class_size = sizeof(ARMHostCPUClass),
249
};
250

  
30 251
int kvm_arch_init(KVMState *s)
31 252
{
32 253
    /* For ARM interrupt delivery is always asynchronous,
33 254
     * whether we are using an in-kernel VGIC or not.
34 255
     */
35 256
    kvm_async_interrupts_allowed = true;
257

  
258
    type_register_static(&host_arm_cpu_type_info);
259

  
36 260
    return 0;
37 261
}
38 262

  

Also available in: Unified diff