| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
- */
- #include <linux/kvm_host.h>
- #include <asm/kvm_mmu.h>
- #include <asm/kvm_vcpu.h>
- const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
- KVM_GENERIC_VM_STATS(),
- STATS_DESC_ICOUNTER(VM, pages),
- STATS_DESC_ICOUNTER(VM, hugepages),
- };
- const struct kvm_stats_header kvm_vm_stats_header = {
- .name_size = KVM_STATS_NAME_SIZE,
- .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
- .id_offset = sizeof(struct kvm_stats_header),
- .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
- .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
- sizeof(kvm_vm_stats_desc),
- };
- int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
- {
- int i;
- /* Allocate page table to map GPA -> RPA */
- kvm->arch.pgd = kvm_pgd_alloc();
- if (!kvm->arch.pgd)
- return -ENOMEM;
- kvm->arch.phyid_map = kvzalloc(sizeof(struct kvm_phyid_map), GFP_KERNEL_ACCOUNT);
- if (!kvm->arch.phyid_map) {
- free_page((unsigned long)kvm->arch.pgd);
- kvm->arch.pgd = NULL;
- return -ENOMEM;
- }
- spin_lock_init(&kvm->arch.phyid_map_lock);
- kvm_init_vmcs(kvm);
- /* Enable all PV features by default */
- kvm->arch.pv_features = BIT(KVM_FEATURE_IPI);
- if (kvm_pvtime_supported())
- kvm->arch.pv_features |= BIT(KVM_FEATURE_STEAL_TIME);
- kvm->arch.gpa_size = BIT(cpu_vabits - 1);
- kvm->arch.root_level = CONFIG_PGTABLE_LEVELS - 1;
- kvm->arch.invalid_ptes[0] = 0;
- kvm->arch.invalid_ptes[1] = (unsigned long)invalid_pte_table;
- #if CONFIG_PGTABLE_LEVELS > 2
- kvm->arch.invalid_ptes[2] = (unsigned long)invalid_pmd_table;
- #endif
- #if CONFIG_PGTABLE_LEVELS > 3
- kvm->arch.invalid_ptes[3] = (unsigned long)invalid_pud_table;
- #endif
- for (i = 0; i <= kvm->arch.root_level; i++)
- kvm->arch.pte_shifts[i] = PAGE_SHIFT + i * (PAGE_SHIFT - 3);
- return 0;
- }
- void kvm_arch_destroy_vm(struct kvm *kvm)
- {
- kvm_destroy_vcpus(kvm);
- free_page((unsigned long)kvm->arch.pgd);
- kvm->arch.pgd = NULL;
- kvfree(kvm->arch.phyid_map);
- kvm->arch.phyid_map = NULL;
- }
- int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
- {
- int r;
- switch (ext) {
- case KVM_CAP_ONE_REG:
- case KVM_CAP_ENABLE_CAP:
- case KVM_CAP_READONLY_MEM:
- case KVM_CAP_SYNC_MMU:
- case KVM_CAP_IMMEDIATE_EXIT:
- case KVM_CAP_IOEVENTFD:
- case KVM_CAP_MP_STATE:
- case KVM_CAP_SET_GUEST_DEBUG:
- r = 1;
- break;
- case KVM_CAP_NR_VCPUS:
- r = num_online_cpus();
- break;
- case KVM_CAP_MAX_VCPUS:
- r = KVM_MAX_VCPUS;
- break;
- case KVM_CAP_MAX_VCPU_ID:
- r = KVM_MAX_VCPU_IDS;
- break;
- case KVM_CAP_NR_MEMSLOTS:
- r = KVM_USER_MEM_SLOTS;
- break;
- default:
- r = 0;
- break;
- }
- return r;
- }
- static int kvm_vm_feature_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
- {
- switch (attr->attr) {
- case KVM_LOONGARCH_VM_FEAT_LSX:
- if (cpu_has_lsx)
- return 0;
- return -ENXIO;
- case KVM_LOONGARCH_VM_FEAT_LASX:
- if (cpu_has_lasx)
- return 0;
- return -ENXIO;
- case KVM_LOONGARCH_VM_FEAT_X86BT:
- if (cpu_has_lbt_x86)
- return 0;
- return -ENXIO;
- case KVM_LOONGARCH_VM_FEAT_ARMBT:
- if (cpu_has_lbt_arm)
- return 0;
- return -ENXIO;
- case KVM_LOONGARCH_VM_FEAT_MIPSBT:
- if (cpu_has_lbt_mips)
- return 0;
- return -ENXIO;
- case KVM_LOONGARCH_VM_FEAT_PMU:
- if (cpu_has_pmp)
- return 0;
- return -ENXIO;
- case KVM_LOONGARCH_VM_FEAT_PV_IPI:
- return 0;
- case KVM_LOONGARCH_VM_FEAT_PV_STEALTIME:
- if (kvm_pvtime_supported())
- return 0;
- return -ENXIO;
- default:
- return -ENXIO;
- }
- }
- static int kvm_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
- {
- switch (attr->group) {
- case KVM_LOONGARCH_VM_FEAT_CTRL:
- return kvm_vm_feature_has_attr(kvm, attr);
- default:
- return -ENXIO;
- }
- }
- int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
- {
- void __user *argp = (void __user *)arg;
- struct kvm *kvm = filp->private_data;
- struct kvm_device_attr attr;
- switch (ioctl) {
- case KVM_HAS_DEVICE_ATTR:
- if (copy_from_user(&attr, argp, sizeof(attr)))
- return -EFAULT;
- return kvm_vm_has_attr(kvm, &attr);
- default:
- return -ENOIOCTLCMD;
- }
- }
|