This is necessary for qemu to be able to pass the right information to the guest, as the supported sizes and encodings can vary depending on the machine, the type of KVM used (PR vs HV) and the version of KVM Signed-off-by: Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx> --- Please comment ASAP. I'm tired of the qemu side never working properly because of that and our out-of-tree nasty patches we've been carrying internally, so I'd like to get something like that in real quick :-) I have the qemu side patches that use this to generate the appropriate device-tree when available, and use heuristics for the fallback. I'll post them later, let's agree on the kernel interfaces first. The heuristics work as long as we have a reasonable guarantee that this kernel patch will get in -before- any patch that enables the PVINFO ioctl on "HV" KVM, that way I can rely on the later not working as a way to differenciate PR and HV KVM if this new ioctl is not supported. Note: We probably want an other ioctl for getting other type of MMU info, such as whether we support 1T segments etc... but I didn't want to try to kill to many birds at once and end up in bike shed painting on the mailing list for the next 6 month... Cheers, Ben. arch/powerpc/include/asm/kvm_ppc.h | 3 ++- arch/powerpc/kvm/book3s_hv.c | 35 +++++++++++++++++++++++++++++++++++ arch/powerpc/kvm/book3s_pr.c | 22 ++++++++++++++++++++++ arch/powerpc/kvm/powerpc.c | 18 +++++++++++++++++- include/linux/kvm.h | 29 +++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index c1069f6..bf530fd 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -140,7 +140,8 @@ extern int kvmppc_core_prepare_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem); extern void kvmppc_core_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem); - +extern int kvm_vm_ioctl_get_page_sizes(struct kvm *kvm, + struct kvm_ppc_page_sizes *ps); extern int kvmppc_bookehv_init(void); extern void kvmppc_bookehv_exit(void); diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 8ee46b9..c7f7f20 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1174,6 +1174,37 @@ long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *ret) return fd; } +static void kvmppc_add_seg_page_size(struct kvm_ppc_one_seg_page_size **sps, + int linux_psize) +{ + struct mmu_psize_def *def = &mmu_psize_defs[linux_psize]; + + if (!def->shift) + return; + *sps->page_shift = def->shift; + *sps->slb_enc = def->sllp; + *sps->enc[0].page_shift = def->shift; + *sps->enc[0].pte_enc = def->penc; + *sps++; +} + +int kvm_vm_ioctl_get_page_sizes(struct kvm *kvm, struct kvm_ppc_page_sizes *ps) +{ + struct kvm_ppc_one_seg_page_size *sps; + int i; + + /* Page sizes limited by backing store */ + ps->flags = KVM_PPC_PAGE_SIZES_REAL; + + /* We only support these sizes for now, and no muti-size segments */ + sps = &ps->sps[0]; + kvmppc_add_seg_page_size(&sps, MMU_PAGE_4K); + kvmppc_add_seg_page_size(&sps, MMU_PAGE_64K); + kvmppc_add_seg_page_size(&sps, MMU_PAGE_16M); + + return 0; +} + /* * Get (and clear) the dirty memory log for a memory slot. */ @@ -1211,6 +1242,10 @@ out: return r; } +int kvm_vm_ioctl_get_page_sizes(struct kvm *kvm, struct kvm_ppc_page_sizes *ps) +{ +} + static unsigned long slb_pgsize_encoding(unsigned long psize) { unsigned long senc = 0; diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 5f0ee48..3c823ed 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -1154,6 +1154,28 @@ out: return r; } +#ifdef CONFIG_PPC64 +int kvm_vm_ioctl_get_page_sizes(struct kvm *kvm, struct kvm_ppc_page_sizes *ps) +{ + /* No flags */ + ps->flags = 0; + + /* Standard 4k base page size segment */ + ps->sps[0].page_shift = 12; + ps->sps[0].slb_enc = 0; + ps->sps[0].enc[0].page_shift = 12; + ps->sps[0].enc[0].pte_enc = 0; + + /* Standard 16M large page size segment */ + ps->sps[1].page_shift = 24; + ps->sps[1].slb_enc = SLB_VSID_L; + ps->sps[1].enc[0].page_shift = 24; + ps->sps[1].enc[0].pte_enc = 0; + + return 0; +} +#endif /* CONFIG_PPC64 */ + int kvmppc_core_prepare_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem) { diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 6ac3115..6f0c066 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -279,6 +279,11 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_MAX_VCPUS: r = KVM_MAX_VCPUS; break; +#ifdef CONFIG_PPC_BOOK3S_64 + case KVM_CAP_PPC_GET_PAGE_SIZES: + r = 1; + break; +#endif default: r = 0; break; @@ -718,7 +723,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp, break; } #endif - default: r = -EINVAL; } @@ -800,6 +804,18 @@ long kvm_arch_vm_ioctl(struct file *filp, } #endif /* CONFIG_KVM_BOOK3S_64_HV */ +#ifdef CONFIG_PPC_BOOK3S_64 + case KVM_PPC_GET_PAGE_SIZES: { + struct kvm *kvm = filp->private_data; + struct kvm_ppc_page_sizes sizes; + + memset(&sizes, 0, sizeof(sizes)); + r = kvm_vm_ioctl_get_page_sizes(kvm, &sizes); + if (r >= 0 && copy_to_user(argp, &sizes, sizeof(sizes))) + r = -EFAULT; + break; + } +#endif /* CONFIG_PPC_BOOK3S_64 */ default: r = -ENOTTY; } diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 7a9dd4b..a8b026c 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -449,6 +449,32 @@ struct kvm_ppc_pvinfo { __u8 pad[108]; }; +/* for KVM_PPC_GET_PAGE_SIZES */ +#define KVM_PPC_PAGE_SIZES_MAX_SZ 8 + +struct kvm_ppc_one_page_size { + __u32 page_shift; /* Page shift (or 0) */ + __u32 pte_enc; /* Encoding in the HPTE (>>12) */ +}; + +struct kvm_ppc_one_seg_page_size { + __u32 page_shift; /* Base page shift of segment (or 0) */ + __u32 slb_enc; /* SLB encoding for BookS */ + struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ]; +}; + +/* When that flag is set, guest page sizes must "fit" + * the backing store page sizes. When not set, any + * page size in the list can be used regardless of + * how they are backed + */ +#define KVM_PPC_PAGE_SIZES_REAL 0x00000001 + +struct kvm_ppc_page_sizes { + __u32 flags; + struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ]; +}; + #define KVMIO 0xAE /* machine type bits, to be used as argument to KVM_CREATE_VM */ @@ -590,6 +616,7 @@ struct kvm_ppc_pvinfo { #define KVM_CAP_SYNC_REGS 74 #define KVM_CAP_PCI_2_3 75 #define KVM_CAP_KVMCLOCK_CTRL 76 +#define KVM_CAP_PPC_GET_PAGE_SIZES 77 #ifdef KVM_CAP_IRQ_ROUTING @@ -789,6 +816,8 @@ struct kvm_s390_ucas_mapping { /* Available with KVM_CAP_PCI_2_3 */ #define KVM_ASSIGN_SET_INTX_MASK _IOW(KVMIO, 0xa4, \ struct kvm_assigned_pci_dev) +/* Available with KVM_CAP_PPC_GET_PAGE_SIZES */ +#define KVM_PPC_GET_PAGE_SIZES _IOR(KVMIO, 0xa5, struct kvm_ppc_page_sizes) /* * ioctls for vcpu fds -- 1.7.9.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html