mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-06-15 18:05:49 +00:00
ce6ae1228a
Currently we separate any incoming MMIO request into one of the ARM memory map regions and take care to spare the GIC. It turns out that this is unnecessary, as we only have one special region (the IO port area in the first 64 KByte). The MMIO rbtree takes care about unhandled MMIO ranges, so we can simply drop all the special range checking (except that for the IO range) in kvm_cpu__emulate_mmio(). As the GIC is handled in the kernel, a GIC MMIO access should never reach userland (and we don't know what to do with it anyway). This lets us delete some more code and simplifies future extensions (like expanding the GIC regions). To be in line with the other architectures, move the now simpler code into a header file. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
145 lines
3.3 KiB
C
145 lines
3.3 KiB
C
#include "kvm/kvm.h"
|
|
#include "kvm/kvm-cpu.h"
|
|
|
|
static int debug_fd;
|
|
|
|
void kvm_cpu__set_debug_fd(int fd)
|
|
{
|
|
debug_fd = fd;
|
|
}
|
|
|
|
int kvm_cpu__get_debug_fd(void)
|
|
{
|
|
return debug_fd;
|
|
}
|
|
|
|
static struct kvm_arm_target *kvm_arm_generic_target;
|
|
static struct kvm_arm_target *kvm_arm_targets[KVM_ARM_NUM_TARGETS];
|
|
|
|
void kvm_cpu__set_kvm_arm_generic_target(struct kvm_arm_target *target)
|
|
{
|
|
kvm_arm_generic_target = target;
|
|
}
|
|
|
|
int kvm_cpu__register_kvm_arm_target(struct kvm_arm_target *target)
|
|
{
|
|
unsigned int i = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
|
|
if (!kvm_arm_targets[i]) {
|
|
kvm_arm_targets[i] = target;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -ENOSPC;
|
|
}
|
|
|
|
struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id)
|
|
{
|
|
struct kvm_arm_target *target;
|
|
struct kvm_cpu *vcpu;
|
|
int coalesced_offset, mmap_size, err = -1;
|
|
unsigned int i;
|
|
struct kvm_vcpu_init preferred_init;
|
|
struct kvm_vcpu_init vcpu_init = {
|
|
.features = ARM_VCPU_FEATURE_FLAGS(kvm, cpu_id)
|
|
};
|
|
|
|
vcpu = calloc(1, sizeof(struct kvm_cpu));
|
|
if (!vcpu)
|
|
return NULL;
|
|
|
|
vcpu->vcpu_fd = ioctl(kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
|
|
if (vcpu->vcpu_fd < 0)
|
|
die_perror("KVM_CREATE_VCPU ioctl");
|
|
|
|
mmap_size = ioctl(kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
|
|
if (mmap_size < 0)
|
|
die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
|
|
|
|
vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED,
|
|
vcpu->vcpu_fd, 0);
|
|
if (vcpu->kvm_run == MAP_FAILED)
|
|
die("unable to mmap vcpu fd");
|
|
|
|
/* Set KVM_ARM_VCPU_PSCI_0_2 if available */
|
|
if (kvm__supports_extension(kvm, KVM_CAP_ARM_PSCI_0_2)) {
|
|
vcpu_init.features[0] |= (1UL << KVM_ARM_VCPU_PSCI_0_2);
|
|
}
|
|
|
|
/*
|
|
* If the preferred target ioctl is successful then
|
|
* use preferred target else try each and every target type
|
|
*/
|
|
err = ioctl(kvm->vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init);
|
|
if (!err) {
|
|
/* Match preferred target CPU type. */
|
|
target = NULL;
|
|
for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
|
|
if (!kvm_arm_targets[i])
|
|
continue;
|
|
if (kvm_arm_targets[i]->id == preferred_init.target) {
|
|
target = kvm_arm_targets[i];
|
|
break;
|
|
}
|
|
}
|
|
if (!target) {
|
|
target = kvm_arm_generic_target;
|
|
vcpu_init.target = preferred_init.target;
|
|
} else {
|
|
vcpu_init.target = target->id;
|
|
}
|
|
err = ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_INIT, &vcpu_init);
|
|
} else {
|
|
/* Find an appropriate target CPU type. */
|
|
for (i = 0; i < ARRAY_SIZE(kvm_arm_targets); ++i) {
|
|
if (!kvm_arm_targets[i])
|
|
continue;
|
|
target = kvm_arm_targets[i];
|
|
vcpu_init.target = target->id;
|
|
err = ioctl(vcpu->vcpu_fd, KVM_ARM_VCPU_INIT, &vcpu_init);
|
|
if (!err)
|
|
break;
|
|
}
|
|
if (err)
|
|
die("Unable to find matching target");
|
|
}
|
|
|
|
if (err || target->init(vcpu))
|
|
die("Unable to initialise vcpu");
|
|
|
|
coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION,
|
|
KVM_CAP_COALESCED_MMIO);
|
|
if (coalesced_offset)
|
|
vcpu->ring = (void *)vcpu->kvm_run +
|
|
(coalesced_offset * PAGE_SIZE);
|
|
|
|
/* Populate the vcpu structure. */
|
|
vcpu->kvm = kvm;
|
|
vcpu->cpu_id = cpu_id;
|
|
vcpu->cpu_type = vcpu_init.target;
|
|
vcpu->cpu_compatible = target->compatible;
|
|
vcpu->is_running = true;
|
|
|
|
return vcpu;
|
|
}
|
|
|
|
void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
|
|
{
|
|
}
|
|
|
|
void kvm_cpu__delete(struct kvm_cpu *vcpu)
|
|
{
|
|
free(vcpu);
|
|
}
|
|
|
|
bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
|
|
{
|
|
}
|