* [PATCH v6 7/7] KVM: PPC: Ultravisor: Add PPC_UV config option
From: Bharata B Rao @ 2019-08-09 8:41 UTC (permalink / raw)
To: linuxppc-dev
Cc: linuxram, cclaudio, kvm-ppc, Bharata B Rao, linux-mm, jglisse,
aneesh.kumar, paulus, sukadev, hch, Anshuman Khandual
In-Reply-To: <20190809084108.30343-1-bharata@linux.ibm.com>
From: Anshuman Khandual <khandual@linux.vnet.ibm.com>
CONFIG_PPC_UV adds support for ultravisor.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Signed-off-by: Bharata B Rao <bharata@linux.ibm.com>
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
[ Update config help and commit message ]
Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com>
---
arch/powerpc/Kconfig | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d8dcd8820369..8b36ca5ed3b0 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -448,6 +448,24 @@ config PPC_TRANSACTIONAL_MEM
help
Support user-mode Transactional Memory on POWERPC.
+config PPC_UV
+ bool "Ultravisor support"
+ depends on KVM_BOOK3S_HV_POSSIBLE
+ select ZONE_DEVICE
+ select MIGRATE_VMA_HELPER
+ select DEV_PAGEMAP_OPS
+ select DEVICE_PRIVATE
+ select MEMORY_HOTPLUG
+ select MEMORY_HOTREMOVE
+ default n
+ help
+ This option paravirtualizes the kernel to run in POWER platforms that
+ supports the Protected Execution Facility (PEF). In such platforms,
+ the ultravisor firmware runs at a privilege level above the
+ hypervisor.
+
+ If unsure, say "N".
+
config LD_HEAD_STUB_CATCH
bool "Reserve 256 bytes to cope with linker stubs in HEAD text" if EXPERT
depends on PPC64
--
2.21.0
^ permalink raw reply related
* [PATCH v6 6/7] kvmppc: Support reset of secure guest
From: Bharata B Rao @ 2019-08-09 8:41 UTC (permalink / raw)
To: linuxppc-dev
Cc: linuxram, cclaudio, kvm-ppc, Bharata B Rao, linux-mm, jglisse,
aneesh.kumar, paulus, sukadev, hch
In-Reply-To: <20190809084108.30343-1-bharata@linux.ibm.com>
Add support for reset of secure guest via a new ioctl KVM_PPC_SVM_OFF.
This ioctl will be issued by QEMU during reset and includes the
the following steps:
- Ask UV to terminate the guest via UV_SVM_TERMINATE ucall
- Unpin the VPA pages so that they can be migrated back to secure
side when guest becomes secure again. This is required because
pinned pages can't be migrated.
- Reinitialize guest's partitioned scoped page tables. These are
freed when guest become secure (H_SVM_INIT_DONE)
- Release all device pages of the secure guest.
After these steps, guest is ready to issue UV_ESM call once again
to switch to secure mode.
Signed-off-by: Bharata B Rao <bharata@linux.ibm.com>
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
[Implementation of uv_svm_terminate() and its call from
guest shutdown path]
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
[Unpinning of VPA pages]
---
Documentation/virtual/kvm/api.txt | 18 ++++++
arch/powerpc/include/asm/kvm_book3s_devm.h | 7 +++
arch/powerpc/include/asm/kvm_ppc.h | 2 +
arch/powerpc/include/asm/ultravisor-api.h | 1 +
arch/powerpc/include/asm/ultravisor.h | 5 ++
arch/powerpc/kvm/book3s_hv.c | 70 ++++++++++++++++++++++
arch/powerpc/kvm/book3s_hv_devm.c | 61 +++++++++++++++++++
arch/powerpc/kvm/powerpc.c | 12 ++++
include/uapi/linux/kvm.h | 1 +
9 files changed, 177 insertions(+)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index e54a3f51ddc5..6fdd140dd9af 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -4111,6 +4111,24 @@ Valid values for 'action':
#define KVM_PMU_EVENT_ALLOW 0
#define KVM_PMU_EVENT_DENY 1
+4.121 KVM_PPC_SVM_OFF
+
+Capability: basic
+Architectures: powerpc
+Type: vm ioctl
+Parameters: none
+Returns: 0 on successful completion,
+Errors:
+ EINVAL: if ultravisor failed to terminate the secure guest
+ ENOMEM: if hypervisor failed to allocate new radix page tables for guest
+
+This ioctl is used to turn off the secure mode of the guest or transition
+the guest from secure mode to normal mode. This is invoked when the guest
+is reset. This has no effect if called for a normal guest.
+
+This ioctl issues an ultravisor call to terminate the secure guest,
+unpin the VPA pages, reinitialize guest's partition scoped page
+tables and releases all the HMM pages that is associated with this guest.
5. The kvm_run structure
------------------------
diff --git a/arch/powerpc/include/asm/kvm_book3s_devm.h b/arch/powerpc/include/asm/kvm_book3s_devm.h
index 8c7aacabb2e0..6d97da320400 100644
--- a/arch/powerpc/include/asm/kvm_book3s_devm.h
+++ b/arch/powerpc/include/asm/kvm_book3s_devm.h
@@ -13,6 +13,8 @@ extern unsigned long kvmppc_h_svm_page_out(struct kvm *kvm,
unsigned long page_shift);
extern unsigned long kvmppc_h_svm_init_start(struct kvm *kvm);
extern unsigned long kvmppc_h_svm_init_done(struct kvm *kvm);
+extern void kvmppc_devm_free_memslot_pfns(struct kvm *kvm,
+ struct kvm_memslots *slots);
#else
static inline unsigned long
kvmppc_h_svm_page_in(struct kvm *kvm, unsigned long gra,
@@ -37,5 +39,10 @@ static inline unsigned long kvmppc_h_svm_init_done(struct kvm *kvm)
{
return H_UNSUPPORTED;
}
+
+static inline void kvmppc_devm_free_memslot_pfns(struct kvm *kvm,
+ struct kvm_memslots *slots)
+{
+}
#endif /* CONFIG_PPC_UV */
#endif /* __POWERPC_KVM_PPC_HMM_H__ */
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 2484e6a8f5ca..e4093d067354 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -177,6 +177,7 @@ extern void kvm_spapr_tce_release_iommu_group(struct kvm *kvm,
extern int kvmppc_switch_mmu_to_hpt(struct kvm *kvm);
extern int kvmppc_switch_mmu_to_radix(struct kvm *kvm);
extern void kvmppc_setup_partition_table(struct kvm *kvm);
+extern int kvmppc_reinit_partition_table(struct kvm *kvm);
extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
struct kvm_create_spapr_tce_64 *args);
@@ -321,6 +322,7 @@ struct kvmppc_ops {
int size);
int (*store_to_eaddr)(struct kvm_vcpu *vcpu, ulong *eaddr, void *ptr,
int size);
+ int (*svm_off)(struct kvm *kvm);
};
extern struct kvmppc_ops *kvmppc_hv_ops;
diff --git a/arch/powerpc/include/asm/ultravisor-api.h b/arch/powerpc/include/asm/ultravisor-api.h
index cf200d4ce703..3a27a0c0be05 100644
--- a/arch/powerpc/include/asm/ultravisor-api.h
+++ b/arch/powerpc/include/asm/ultravisor-api.h
@@ -30,5 +30,6 @@
#define UV_PAGE_IN 0xF128
#define UV_PAGE_OUT 0xF12C
#define UV_PAGE_INVAL 0xF138
+#define UV_SVM_TERMINATE 0xF13C
#endif /* _ASM_POWERPC_ULTRAVISOR_API_H */
diff --git a/arch/powerpc/include/asm/ultravisor.h b/arch/powerpc/include/asm/ultravisor.h
index 640db659c8c8..03d4fd49fa0d 100644
--- a/arch/powerpc/include/asm/ultravisor.h
+++ b/arch/powerpc/include/asm/ultravisor.h
@@ -50,4 +50,9 @@ static inline int uv_page_inval(u64 lpid, u64 gpa, u64 page_shift)
return ucall_norets(UV_PAGE_INVAL, lpid, gpa, page_shift);
}
+static inline int uv_svm_terminate(u64 lpid)
+{
+ return ucall_norets(UV_SVM_TERMINATE, lpid);
+}
+
#endif /* _ASM_POWERPC_ULTRAVISOR_H */
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 13e31ef3583e..b348452b2a93 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -2433,6 +2433,15 @@ static void unpin_vpa(struct kvm *kvm, struct kvmppc_vpa *vpa)
vpa->dirty);
}
+static void unpin_vpa_reset(struct kvm *kvm, struct kvmppc_vpa *vpa)
+{
+ unpin_vpa(kvm, vpa);
+ vpa->gpa = 0;
+ vpa->pinned_addr = NULL;
+ vpa->dirty = false;
+ vpa->update_pending = 0;
+}
+
static void kvmppc_core_vcpu_free_hv(struct kvm_vcpu *vcpu)
{
spin_lock(&vcpu->arch.vpa_update_lock);
@@ -4578,6 +4587,22 @@ void kvmppc_setup_partition_table(struct kvm *kvm)
kvmhv_set_ptbl_entry(kvm->arch.lpid, dw0, dw1);
}
+/*
+ * Called from KVM_PPC_SVM_OFF ioctl at guest reset time when secure
+ * guest is converted back to normal guest.
+ */
+int kvmppc_reinit_partition_table(struct kvm *kvm)
+{
+ int ret;
+
+ ret = kvmppc_init_vm_radix(kvm);
+ if (ret)
+ return ret;
+
+ kvmppc_setup_partition_table(kvm);
+ return 0;
+}
+
/*
* Set up HPT (hashed page table) and RMA (real-mode area).
* Must be called with kvm->arch.mmu_setup_lock held.
@@ -4965,6 +4990,7 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
if (nesting_enabled(kvm))
kvmhv_release_all_nested(kvm);
kvm->arch.process_table = 0;
+ uv_svm_terminate(kvm->arch.lpid);
kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0);
}
kvmppc_free_lpid(kvm->arch.lpid);
@@ -5406,6 +5432,49 @@ static int kvmhv_store_to_eaddr(struct kvm_vcpu *vcpu, ulong *eaddr, void *ptr,
return rc;
}
+/*
+ * IOCTL handler to turn off secure mode of guest
+ *
+ * - Issue ucall to terminate the guest on the UV side
+ * - Unpin the VPA pages (Enables these pages to be migrated back
+ * when VM becomes secure again)
+ * - Recreate partition table as the guest is transitioning back to
+ * normal mode
+ * - Release all HMM pages
+ */
+static int kvmhv_svm_off(struct kvm *kvm)
+{
+ struct kvm_vcpu *vcpu;
+ int ret = 0;
+ int i;
+
+ if (kvmppc_is_guest_secure(kvm)) {
+ ret = uv_svm_terminate(kvm->arch.lpid);
+ if (ret != U_SUCCESS) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ spin_lock(&vcpu->arch.vpa_update_lock);
+ unpin_vpa_reset(kvm, &vcpu->arch.dtl);
+ unpin_vpa_reset(kvm, &vcpu->arch.slb_shadow);
+ unpin_vpa_reset(kvm, &vcpu->arch.vpa);
+ spin_unlock(&vcpu->arch.vpa_update_lock);
+ }
+
+ ret = kvmppc_reinit_partition_table(kvm);
+ if (ret)
+ goto out;
+ kvm->arch.secure_guest = 0;
+ for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++)
+ kvmppc_devm_free_memslot_pfns(kvm,
+ __kvm_memslots(kvm, i));
+ }
+out:
+ return ret;
+}
+
static struct kvmppc_ops kvm_ops_hv = {
.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,
.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,
@@ -5448,6 +5517,7 @@ static struct kvmppc_ops kvm_ops_hv = {
.enable_nested = kvmhv_enable_nested,
.load_from_eaddr = kvmhv_load_from_eaddr,
.store_to_eaddr = kvmhv_store_to_eaddr,
+ .svm_off = kvmhv_svm_off,
};
static int kvm_init_subcore_bitmap(void)
diff --git a/arch/powerpc/kvm/book3s_hv_devm.c b/arch/powerpc/kvm/book3s_hv_devm.c
index 9c4b05cd5b0a..1a33283192c2 100644
--- a/arch/powerpc/kvm/book3s_hv_devm.c
+++ b/arch/powerpc/kvm/book3s_hv_devm.c
@@ -38,6 +38,8 @@
#include <linux/kvm_host.h>
#include <linux/sched/mm.h>
#include <asm/ultravisor.h>
+#include <asm/kvm_ppc.h>
+#include <asm/kvm_book3s.h>
struct kvmppc_devm_device {
struct device dev;
@@ -101,6 +103,12 @@ unsigned long kvmppc_h_svm_init_done(struct kvm *kvm)
return H_UNSUPPORTED;
kvm->arch.secure_guest |= KVMPPC_SECURE_INIT_DONE;
+ if (kvm_is_radix(kvm)) {
+ pr_info("LPID %d went secure, freeing HV side radix pgtables\n",
+ kvm->arch.lpid);
+ kvmppc_free_radix(kvm);
+ }
+
return H_SUCCESS;
}
@@ -116,6 +124,59 @@ static inline bool kvmppc_is_devm_pfn(unsigned long pfn)
return !!(pfn & KVMPPC_PFN_DEVM);
}
+/*
+ * Drop device pages that we maintain for the secure guest
+ *
+ * We first mark the pages to be skipped from UV_PAGE_OUT when there
+ * is HV side fault on these pages. Next we *get* these pages, forcing
+ * fault on them, do fault time migration to replace the device PTEs in
+ * QEMU page table with normal PTEs from newly allocated pages.
+ */
+static void kvmppc_devm_drop_pages(struct kvm_memory_slot *free,
+ struct kvm *kvm)
+{
+ int i;
+ struct kvmppc_devm_page_pvt *pvt;
+ unsigned long pfn;
+
+ for (i = 0; i < free->npages; i++) {
+ unsigned long *rmap = &free->arch.rmap[i];
+ struct page *devm_page;
+
+ if (kvmppc_is_devm_pfn(*rmap)) {
+ devm_page = pfn_to_page(*rmap & ~KVMPPC_PFN_DEVM);
+ pvt = (struct kvmppc_devm_page_pvt *)
+ devm_page->zone_device_data;
+ pvt->skip_page_out = true;
+
+ pfn = gfn_to_pfn(kvm, pvt->gpa >> PAGE_SHIFT);
+ if (is_error_noslot_pfn(pfn))
+ continue;
+ kvm_release_pfn_clean(pfn);
+ }
+ }
+}
+
+/*
+ * Called from KVM_PPC_SVM_OFF ioctl when secure guest is reset
+ *
+ * UV has already cleaned up the guest, we release any device pages
+ * that we maintain
+ */
+void kvmppc_devm_free_memslot_pfns(struct kvm *kvm, struct kvm_memslots *slots)
+{
+ struct kvm_memory_slot *memslot;
+ int srcu_idx;
+
+ if (!slots)
+ return;
+
+ srcu_idx = srcu_read_lock(&kvm->srcu);
+ kvm_for_each_memslot(memslot, slots)
+ kvmppc_devm_drop_pages(memslot, kvm);
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
+}
+
/*
* Get a free device PFN from the pool
*
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 0dba7eb24f92..77dceaa8fb55 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -31,6 +31,8 @@
#include <asm/hvcall.h>
#include <asm/plpar_wrappers.h>
#endif
+#include <asm/ultravisor.h>
+#include <asm/kvm_host.h>
#include "timing.h"
#include "irq.h"
@@ -2415,6 +2417,16 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = -EFAULT;
break;
}
+ case KVM_PPC_SVM_OFF: {
+ struct kvm *kvm = filp->private_data;
+
+ r = 0;
+ if (!kvm->arch.kvm_ops->svm_off)
+ goto out;
+
+ r = kvm->arch.kvm_ops->svm_off(kvm);
+ break;
+ }
default: {
struct kvm *kvm = filp->private_data;
r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index a7c19540ce21..07041a64e21f 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1332,6 +1332,7 @@ struct kvm_s390_ucas_mapping {
#define KVM_PPC_GET_CPU_CHAR _IOR(KVMIO, 0xb1, struct kvm_ppc_cpu_char)
/* Available with KVM_CAP_PMU_EVENT_FILTER */
#define KVM_SET_PMU_EVENT_FILTER _IOW(KVMIO, 0xb2, struct kvm_pmu_event_filter)
+#define KVM_PPC_SVM_OFF _IO(KVMIO, 0xb3)
/* ioctl for vm fd */
#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device)
--
2.21.0
^ permalink raw reply related
* [PATCH v6 5/7] kvmppc: Radix changes for secure guest
From: Bharata B Rao @ 2019-08-09 8:41 UTC (permalink / raw)
To: linuxppc-dev
Cc: linuxram, cclaudio, kvm-ppc, Bharata B Rao, linux-mm, jglisse,
aneesh.kumar, paulus, sukadev, hch
In-Reply-To: <20190809084108.30343-1-bharata@linux.ibm.com>
- After the guest becomes secure, when we handle a page fault of a page
belonging to SVM in HV, send that page to UV via UV_PAGE_IN.
- Whenever a page is unmapped on the HV side, inform UV via UV_PAGE_INVAL.
- Ensure all those routines that walk the secondary page tables of
the guest don't do so in case of secure VM. For secure guest, the
active secondary page tables are in secure memory and the secondary
page tables in HV are freed when guest becomes secure.
Signed-off-by: Bharata B Rao <bharata@linux.ibm.com>
---
arch/powerpc/include/asm/kvm_host.h | 12 ++++++++++++
arch/powerpc/include/asm/ultravisor-api.h | 1 +
arch/powerpc/include/asm/ultravisor.h | 5 +++++
arch/powerpc/kvm/book3s_64_mmu_radix.c | 22 ++++++++++++++++++++++
arch/powerpc/kvm/book3s_hv_devm.c | 20 ++++++++++++++++++++
5 files changed, 60 insertions(+)
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 1827c22909cd..db680d7f5779 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -856,6 +856,8 @@ static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
#ifdef CONFIG_PPC_UV
extern int kvmppc_devm_init(void);
extern void kvmppc_devm_free(void);
+extern bool kvmppc_is_guest_secure(struct kvm *kvm);
+extern int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gpa);
#else
static inline int kvmppc_devm_init(void)
{
@@ -863,6 +865,16 @@ static inline int kvmppc_devm_init(void)
}
static inline void kvmppc_devm_free(void) {}
+
+static inline bool kvmppc_is_guest_secure(struct kvm *kvm)
+{
+ return false;
+}
+
+static inline int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gpa)
+{
+ return -EFAULT;
+}
#endif /* CONFIG_PPC_UV */
#endif /* __POWERPC_KVM_HOST_H__ */
diff --git a/arch/powerpc/include/asm/ultravisor-api.h b/arch/powerpc/include/asm/ultravisor-api.h
index 46b1ee381695..cf200d4ce703 100644
--- a/arch/powerpc/include/asm/ultravisor-api.h
+++ b/arch/powerpc/include/asm/ultravisor-api.h
@@ -29,5 +29,6 @@
#define UV_UNREGISTER_MEM_SLOT 0xF124
#define UV_PAGE_IN 0xF128
#define UV_PAGE_OUT 0xF12C
+#define UV_PAGE_INVAL 0xF138
#endif /* _ASM_POWERPC_ULTRAVISOR_API_H */
diff --git a/arch/powerpc/include/asm/ultravisor.h b/arch/powerpc/include/asm/ultravisor.h
index 79c415bf5ee8..640db659c8c8 100644
--- a/arch/powerpc/include/asm/ultravisor.h
+++ b/arch/powerpc/include/asm/ultravisor.h
@@ -45,4 +45,9 @@ static inline int uv_unregister_mem_slot(u64 lpid, u64 slotid)
return ucall_norets(UV_UNREGISTER_MEM_SLOT, lpid, slotid);
}
+static inline int uv_page_inval(u64 lpid, u64 gpa, u64 page_shift)
+{
+ return ucall_norets(UV_PAGE_INVAL, lpid, gpa, page_shift);
+}
+
#endif /* _ASM_POWERPC_ULTRAVISOR_H */
diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c
index 2d415c36a61d..93ad34e63045 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c
@@ -19,6 +19,8 @@
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/pte-walk.h>
+#include <asm/ultravisor.h>
+#include <asm/kvm_host.h>
/*
* Supported radix tree geometry.
@@ -915,6 +917,9 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
if (!(dsisr & DSISR_PRTABLE_FAULT))
gpa |= ea & 0xfff;
+ if (kvmppc_is_guest_secure(kvm))
+ return kvmppc_send_page_to_uv(kvm, gpa & PAGE_MASK);
+
/* Get the corresponding memslot */
memslot = gfn_to_memslot(kvm, gfn);
@@ -972,6 +977,11 @@ int kvm_unmap_radix(struct kvm *kvm, struct kvm_memory_slot *memslot,
unsigned long gpa = gfn << PAGE_SHIFT;
unsigned int shift;
+ if (kvmppc_is_guest_secure(kvm)) {
+ uv_page_inval(kvm->arch.lpid, gpa, PAGE_SIZE);
+ return 0;
+ }
+
ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift);
if (ptep && pte_present(*ptep))
kvmppc_unmap_pte(kvm, ptep, gpa, shift, memslot,
@@ -989,6 +999,9 @@ int kvm_age_radix(struct kvm *kvm, struct kvm_memory_slot *memslot,
int ref = 0;
unsigned long old, *rmapp;
+ if (kvmppc_is_guest_secure(kvm))
+ return ref;
+
ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift);
if (ptep && pte_present(*ptep) && pte_young(*ptep)) {
old = kvmppc_radix_update_pte(kvm, ptep, _PAGE_ACCESSED, 0,
@@ -1013,6 +1026,9 @@ int kvm_test_age_radix(struct kvm *kvm, struct kvm_memory_slot *memslot,
unsigned int shift;
int ref = 0;
+ if (kvmppc_is_guest_secure(kvm))
+ return ref;
+
ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift);
if (ptep && pte_present(*ptep) && pte_young(*ptep))
ref = 1;
@@ -1030,6 +1046,9 @@ static int kvm_radix_test_clear_dirty(struct kvm *kvm,
int ret = 0;
unsigned long old, *rmapp;
+ if (kvmppc_is_guest_secure(kvm))
+ return ret;
+
ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift);
if (ptep && pte_present(*ptep) && pte_dirty(*ptep)) {
ret = 1;
@@ -1082,6 +1101,9 @@ void kvmppc_radix_flush_memslot(struct kvm *kvm,
unsigned long gpa;
unsigned int shift;
+ if (kvmppc_is_guest_secure(kvm))
+ return;
+
gpa = memslot->base_gfn << PAGE_SHIFT;
spin_lock(&kvm->mmu_lock);
for (n = memslot->npages; n; --n) {
diff --git a/arch/powerpc/kvm/book3s_hv_devm.c b/arch/powerpc/kvm/book3s_hv_devm.c
index c55bb5f57928..9c4b05cd5b0a 100644
--- a/arch/powerpc/kvm/book3s_hv_devm.c
+++ b/arch/powerpc/kvm/book3s_hv_devm.c
@@ -65,6 +65,11 @@ struct kvmppc_devm_copy_args {
unsigned long page_shift;
};
+bool kvmppc_is_guest_secure(struct kvm *kvm)
+{
+ return !!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_DONE);
+}
+
unsigned long kvmppc_h_svm_init_start(struct kvm *kvm)
{
struct kvm_memslots *slots;
@@ -483,6 +488,21 @@ kvmppc_h_svm_page_out(struct kvm *kvm, unsigned long gpa,
return ret;
}
+int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gpa)
+{
+ unsigned long pfn;
+ int ret;
+
+ pfn = gfn_to_pfn(kvm, gpa >> PAGE_SHIFT);
+ if (is_error_noslot_pfn(pfn))
+ return -EFAULT;
+
+ ret = uv_page_in(kvm->arch.lpid, pfn << PAGE_SHIFT, gpa, 0, PAGE_SHIFT);
+ kvm_release_pfn_clean(pfn);
+
+ return (ret == U_SUCCESS) ? RESUME_GUEST : -EFAULT;
+}
+
static u64 kvmppc_get_secmem_size(void)
{
struct device_node *np;
--
2.21.0
^ permalink raw reply related
* [PATCH v6 4/7] kvmppc: Handle memory plug/unplug to secure VM
From: Bharata B Rao @ 2019-08-09 8:41 UTC (permalink / raw)
To: linuxppc-dev
Cc: linuxram, cclaudio, kvm-ppc, Bharata B Rao, linux-mm, jglisse,
aneesh.kumar, paulus, sukadev, hch
In-Reply-To: <20190809084108.30343-1-bharata@linux.ibm.com>
Register the new memslot with UV during plug and unregister
the memslot during unplug.
Signed-off-by: Bharata B Rao <bharata@linux.ibm.com>
Acked-by: Paul Mackerras <paulus@ozlabs.org>
---
arch/powerpc/include/asm/ultravisor-api.h | 1 +
arch/powerpc/include/asm/ultravisor.h | 5 +++++
arch/powerpc/kvm/book3s_hv.c | 19 +++++++++++++++++++
3 files changed, 25 insertions(+)
diff --git a/arch/powerpc/include/asm/ultravisor-api.h b/arch/powerpc/include/asm/ultravisor-api.h
index c578d9b13a56..46b1ee381695 100644
--- a/arch/powerpc/include/asm/ultravisor-api.h
+++ b/arch/powerpc/include/asm/ultravisor-api.h
@@ -26,6 +26,7 @@
#define UV_WRITE_PATE 0xF104
#define UV_RETURN 0xF11C
#define UV_REGISTER_MEM_SLOT 0xF120
+#define UV_UNREGISTER_MEM_SLOT 0xF124
#define UV_PAGE_IN 0xF128
#define UV_PAGE_OUT 0xF12C
diff --git a/arch/powerpc/include/asm/ultravisor.h b/arch/powerpc/include/asm/ultravisor.h
index 8a722c575c56..79c415bf5ee8 100644
--- a/arch/powerpc/include/asm/ultravisor.h
+++ b/arch/powerpc/include/asm/ultravisor.h
@@ -40,4 +40,9 @@ static inline int uv_register_mem_slot(u64 lpid, u64 start_gpa, u64 size,
size, flags, slotid);
}
+static inline int uv_unregister_mem_slot(u64 lpid, u64 slotid)
+{
+ return ucall_norets(UV_UNREGISTER_MEM_SLOT, lpid, slotid);
+}
+
#endif /* _ASM_POWERPC_ULTRAVISOR_H */
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 33b8ebffbef0..13e31ef3583e 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -74,6 +74,7 @@
#include <asm/hw_breakpoint.h>
#include <asm/kvm_host.h>
#include <asm/kvm_book3s_devm.h>
+#include <asm/ultravisor.h>
#include "book3s.h"
@@ -4504,6 +4505,24 @@ static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
if (change == KVM_MR_FLAGS_ONLY && kvm_is_radix(kvm) &&
((new->flags ^ old->flags) & KVM_MEM_LOG_DIRTY_PAGES))
kvmppc_radix_flush_memslot(kvm, old);
+ /*
+ * If UV hasn't yet called H_SVM_INIT_START, don't register memslots.
+ */
+ if (!kvm->arch.secure_guest)
+ return;
+
+ /*
+ * TODO: Handle KVM_MR_MOVE
+ */
+ if (change == KVM_MR_CREATE) {
+ uv_register_mem_slot(kvm->arch.lpid,
+ new->base_gfn << PAGE_SHIFT,
+ new->npages * PAGE_SIZE,
+ 0,
+ new->id);
+ } else if (change == KVM_MR_DELETE) {
+ uv_unregister_mem_slot(kvm->arch.lpid, old->id);
+ }
}
/*
--
2.21.0
^ permalink raw reply related
* [PATCH v6 3/7] kvmppc: H_SVM_INIT_START and H_SVM_INIT_DONE hcalls
From: Bharata B Rao @ 2019-08-09 8:41 UTC (permalink / raw)
To: linuxppc-dev
Cc: linuxram, cclaudio, kvm-ppc, Bharata B Rao, linux-mm, jglisse,
aneesh.kumar, paulus, sukadev, hch
In-Reply-To: <20190809084108.30343-1-bharata@linux.ibm.com>
H_SVM_INIT_START: Initiate securing a VM
H_SVM_INIT_DONE: Conclude securing a VM
As part of H_SVM_INIT_START, register all existing memslots with
the UV. H_SVM_INIT_DONE call by UV informs HV that transition of
the guest to secure mode is complete.
These two states (transition to secure mode STARTED and transition
to secure mode COMPLETED) are recorded in kvm->arch.secure_guest.
Setting these states will cause the assembly code that enters the
guest to call the UV_RETURN ucall instead of trying to enter the
guest directly.
Signed-off-by: Bharata B Rao <bharata@linux.ibm.com>
Acked-by: Paul Mackerras <paulus@ozlabs.org>
---
arch/powerpc/include/asm/hvcall.h | 2 ++
arch/powerpc/include/asm/kvm_book3s_devm.h | 12 ++++++++
arch/powerpc/include/asm/kvm_host.h | 4 +++
arch/powerpc/include/asm/ultravisor-api.h | 1 +
arch/powerpc/include/asm/ultravisor.h | 7 +++++
arch/powerpc/kvm/book3s_hv.c | 7 +++++
arch/powerpc/kvm/book3s_hv_devm.c | 34 ++++++++++++++++++++++
7 files changed, 67 insertions(+)
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 05b8536f6653..fa7695928e30 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -343,6 +343,8 @@
/* Platform-specific hcalls used by the Ultravisor */
#define H_SVM_PAGE_IN 0xEF00
#define H_SVM_PAGE_OUT 0xEF04
+#define H_SVM_INIT_START 0xEF08
+#define H_SVM_INIT_DONE 0xEF0C
/* Values for 2nd argument to H_SET_MODE */
#define H_SET_MODE_RESOURCE_SET_CIABR 1
diff --git a/arch/powerpc/include/asm/kvm_book3s_devm.h b/arch/powerpc/include/asm/kvm_book3s_devm.h
index 21f3de5f2acb..8c7aacabb2e0 100644
--- a/arch/powerpc/include/asm/kvm_book3s_devm.h
+++ b/arch/powerpc/include/asm/kvm_book3s_devm.h
@@ -11,6 +11,8 @@ extern unsigned long kvmppc_h_svm_page_out(struct kvm *kvm,
unsigned long gra,
unsigned long flags,
unsigned long page_shift);
+extern unsigned long kvmppc_h_svm_init_start(struct kvm *kvm);
+extern unsigned long kvmppc_h_svm_init_done(struct kvm *kvm);
#else
static inline unsigned long
kvmppc_h_svm_page_in(struct kvm *kvm, unsigned long gra,
@@ -25,5 +27,15 @@ kvmppc_h_svm_page_out(struct kvm *kvm, unsigned long gra,
{
return H_UNSUPPORTED;
}
+
+static inline unsigned long kvmppc_h_svm_init_start(struct kvm *kvm)
+{
+ return H_UNSUPPORTED;
+}
+
+static inline unsigned long kvmppc_h_svm_init_done(struct kvm *kvm)
+{
+ return H_UNSUPPORTED;
+}
#endif /* CONFIG_PPC_UV */
#endif /* __POWERPC_KVM_PPC_HMM_H__ */
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 86bbe607ad7e..1827c22909cd 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -261,6 +261,10 @@ struct kvm_hpt_info {
struct kvm_resize_hpt;
+/* Flag values for kvm_arch.secure_guest */
+#define KVMPPC_SECURE_INIT_START 0x1 /* H_SVM_INIT_START has been called */
+#define KVMPPC_SECURE_INIT_DONE 0x2 /* H_SVM_INIT_DONE completed */
+
struct kvm_arch {
unsigned int lpid;
unsigned int smt_mode; /* # vcpus per virtual core */
diff --git a/arch/powerpc/include/asm/ultravisor-api.h b/arch/powerpc/include/asm/ultravisor-api.h
index 1cd1f595fd81..c578d9b13a56 100644
--- a/arch/powerpc/include/asm/ultravisor-api.h
+++ b/arch/powerpc/include/asm/ultravisor-api.h
@@ -25,6 +25,7 @@
/* opcodes */
#define UV_WRITE_PATE 0xF104
#define UV_RETURN 0xF11C
+#define UV_REGISTER_MEM_SLOT 0xF120
#define UV_PAGE_IN 0xF128
#define UV_PAGE_OUT 0xF12C
diff --git a/arch/powerpc/include/asm/ultravisor.h b/arch/powerpc/include/asm/ultravisor.h
index d668a59e099b..8a722c575c56 100644
--- a/arch/powerpc/include/asm/ultravisor.h
+++ b/arch/powerpc/include/asm/ultravisor.h
@@ -33,4 +33,11 @@ static inline int uv_page_out(u64 lpid, u64 dst_ra, u64 src_gpa, u64 flags,
page_shift);
}
+static inline int uv_register_mem_slot(u64 lpid, u64 start_gpa, u64 size,
+ u64 flags, u64 slotid)
+{
+ return ucall_norets(UV_REGISTER_MEM_SLOT, lpid, start_gpa,
+ size, flags, slotid);
+}
+
#endif /* _ASM_POWERPC_ULTRAVISOR_H */
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 00b43ee8b693..33b8ebffbef0 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1089,6 +1089,13 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6));
break;
+ case H_SVM_INIT_START:
+ ret = kvmppc_h_svm_init_start(vcpu->kvm);
+ break;
+ case H_SVM_INIT_DONE:
+ ret = kvmppc_h_svm_init_done(vcpu->kvm);
+ break;
+
default:
return RESUME_HOST;
}
diff --git a/arch/powerpc/kvm/book3s_hv_devm.c b/arch/powerpc/kvm/book3s_hv_devm.c
index c9189e58401d..c55bb5f57928 100644
--- a/arch/powerpc/kvm/book3s_hv_devm.c
+++ b/arch/powerpc/kvm/book3s_hv_devm.c
@@ -65,6 +65,40 @@ struct kvmppc_devm_copy_args {
unsigned long page_shift;
};
+unsigned long kvmppc_h_svm_init_start(struct kvm *kvm)
+{
+ struct kvm_memslots *slots;
+ struct kvm_memory_slot *memslot;
+ int ret = H_SUCCESS;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&kvm->srcu);
+ slots = kvm_memslots(kvm);
+ kvm_for_each_memslot(memslot, slots) {
+ ret = uv_register_mem_slot(kvm->arch.lpid,
+ memslot->base_gfn << PAGE_SHIFT,
+ memslot->npages * PAGE_SIZE,
+ 0, memslot->id);
+ if (ret < 0) {
+ ret = H_PARAMETER;
+ goto out;
+ }
+ }
+ kvm->arch.secure_guest |= KVMPPC_SECURE_INIT_START;
+out:
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
+ return ret;
+}
+
+unsigned long kvmppc_h_svm_init_done(struct kvm *kvm)
+{
+ if (!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START))
+ return H_UNSUPPORTED;
+
+ kvm->arch.secure_guest |= KVMPPC_SECURE_INIT_DONE;
+ return H_SUCCESS;
+}
+
/*
* Bits 60:56 in the rmap entry will be used to identify the
* different uses/functions of rmap. This definition with move
--
2.21.0
^ permalink raw reply related
* [PATCH v6 2/7] kvmppc: Shared pages support for secure guests
From: Bharata B Rao @ 2019-08-09 8:41 UTC (permalink / raw)
To: linuxppc-dev
Cc: linuxram, cclaudio, kvm-ppc, Bharata B Rao, linux-mm, jglisse,
aneesh.kumar, paulus, sukadev, hch
In-Reply-To: <20190809084108.30343-1-bharata@linux.ibm.com>
A secure guest will share some of its pages with hypervisor (Eg. virtio
bounce buffers etc). Support sharing of pages between hypervisor and
ultravisor.
Once a secure page is converted to shared page, stop tracking that page
as a device page.
Signed-off-by: Bharata B Rao <bharata@linux.ibm.com>
---
arch/powerpc/include/asm/hvcall.h | 3 ++
arch/powerpc/kvm/book3s_hv_devm.c | 67 +++++++++++++++++++++++++++++--
2 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 2f6b952deb0f..05b8536f6653 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -337,6 +337,9 @@
#define H_TLB_INVALIDATE 0xF808
#define H_COPY_TOFROM_GUEST 0xF80C
+/* Flags for H_SVM_PAGE_IN */
+#define H_PAGE_IN_SHARED 0x1
+
/* Platform-specific hcalls used by the Ultravisor */
#define H_SVM_PAGE_IN 0xEF00
#define H_SVM_PAGE_OUT 0xEF04
diff --git a/arch/powerpc/kvm/book3s_hv_devm.c b/arch/powerpc/kvm/book3s_hv_devm.c
index 2e6c077bd22e..c9189e58401d 100644
--- a/arch/powerpc/kvm/book3s_hv_devm.c
+++ b/arch/powerpc/kvm/book3s_hv_devm.c
@@ -55,6 +55,7 @@ struct kvmppc_devm_page_pvt {
unsigned long *rmap;
unsigned int lpid;
unsigned long gpa;
+ bool skip_page_out;
};
struct kvmppc_devm_copy_args {
@@ -188,6 +189,54 @@ kvmppc_devm_migrate_alloc_and_copy(struct migrate_vma *mig,
return 0;
}
+/*
+ * Shares the page with HV, thus making it a normal page.
+ *
+ * - If the page is already secure, then provision a new page and share
+ * - If the page is a normal page, share the existing page
+ *
+ * In the former case, uses the dev_pagemap_ops migrate_to_ram handler to
+ * release the device page.
+ */
+static unsigned long
+kvmppc_share_page(struct kvm *kvm, unsigned long gpa, unsigned long page_shift)
+{
+
+ int ret = H_PARAMETER;
+ struct page *devm_page;
+ struct kvmppc_devm_page_pvt *pvt;
+ unsigned long pfn;
+ unsigned long *rmap;
+ struct kvm_memory_slot *slot;
+ unsigned long gfn = gpa >> page_shift;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&kvm->srcu);
+ slot = gfn_to_memslot(kvm, gfn);
+ if (!slot)
+ goto out;
+
+ rmap = &slot->arch.rmap[gfn - slot->base_gfn];
+ if (kvmppc_is_devm_pfn(*rmap)) {
+ devm_page = pfn_to_page(*rmap & ~KVMPPC_PFN_DEVM);
+ pvt = (struct kvmppc_devm_page_pvt *)
+ devm_page->zone_device_data;
+ pvt->skip_page_out = true;
+ }
+
+ pfn = gfn_to_pfn(kvm, gpa >> page_shift);
+ if (is_error_noslot_pfn(pfn))
+ goto out;
+
+ ret = uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0, page_shift);
+ if (ret == U_SUCCESS)
+ ret = H_SUCCESS;
+ kvm_release_pfn_clean(pfn);
+out:
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
+ return ret;
+}
+
/*
* Move page from normal memory to secure memory.
*/
@@ -209,9 +258,12 @@ kvmppc_h_svm_page_in(struct kvm *kvm, unsigned long gpa,
if (page_shift != PAGE_SHIFT)
return H_P3;
- if (flags)
+ if (flags & ~H_PAGE_IN_SHARED)
return H_P2;
+ if (flags & H_PAGE_IN_SHARED)
+ return kvmppc_share_page(kvm, gpa, page_shift);
+
ret = H_PARAMETER;
down_read(&kvm->mm->mmap_sem);
srcu_idx = srcu_read_lock(&kvm->srcu);
@@ -279,8 +331,17 @@ kvmppc_devm_fault_migrate_alloc_and_copy(struct migrate_vma *mig)
pvt = (struct kvmppc_devm_page_pvt *)spage->zone_device_data;
pfn = page_to_pfn(dpage);
- ret = uv_page_out(pvt->lpid, pfn << PAGE_SHIFT,
- pvt->gpa, 0, PAGE_SHIFT);
+
+ /*
+ * This same function is used in two cases:
+ * - When HV touches a secure page, for which we do page-out
+ * - When a secure page is converted to shared page, we touch
+ * the page to essentially discard the device page. In this
+ * case we skip page-out.
+ */
+ if (!pvt->skip_page_out)
+ ret = uv_page_out(pvt->lpid, pfn << PAGE_SHIFT,
+ pvt->gpa, 0, PAGE_SHIFT);
if (ret == U_SUCCESS)
*mig->dst = migrate_pfn(pfn) | MIGRATE_PFN_LOCKED;
return 0;
--
2.21.0
^ permalink raw reply related
* [PATCH v6 1/7] kvmppc: Driver to manage pages of secure guest
From: Bharata B Rao @ 2019-08-09 8:41 UTC (permalink / raw)
To: linuxppc-dev
Cc: linuxram, cclaudio, kvm-ppc, Bharata B Rao, linux-mm, jglisse,
aneesh.kumar, paulus, sukadev, hch
In-Reply-To: <20190809084108.30343-1-bharata@linux.ibm.com>
KVMPPC driver to manage page transitions of secure guest
via H_SVM_PAGE_IN and H_SVM_PAGE_OUT hcalls.
H_SVM_PAGE_IN: Move the content of a normal page to secure page
H_SVM_PAGE_OUT: Move the content of a secure page to normal page
Private ZONE_DEVICE memory equal to the amount of secure memory
available in the platform for running secure guests is created
via a char device. Whenever a page belonging to the guest becomes
secure, a page from this private device memory is used to
represent and track that secure page on the HV side. The movement
of pages between normal and secure memory is done via
migrate_vma_pages() using UV_PAGE_IN and UV_PAGE_OUT ucalls.
Signed-off-by: Bharata B Rao <bharata@linux.ibm.com>
---
arch/powerpc/include/asm/hvcall.h | 4 +
arch/powerpc/include/asm/kvm_book3s_devm.h | 29 ++
arch/powerpc/include/asm/kvm_host.h | 12 +
arch/powerpc/include/asm/ultravisor-api.h | 2 +
arch/powerpc/include/asm/ultravisor.h | 14 +
arch/powerpc/kvm/Makefile | 3 +
arch/powerpc/kvm/book3s_hv.c | 19 +
arch/powerpc/kvm/book3s_hv_devm.c | 492 +++++++++++++++++++++
8 files changed, 575 insertions(+)
create mode 100644 arch/powerpc/include/asm/kvm_book3s_devm.h
create mode 100644 arch/powerpc/kvm/book3s_hv_devm.c
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 463c63a9fcf1..2f6b952deb0f 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -337,6 +337,10 @@
#define H_TLB_INVALIDATE 0xF808
#define H_COPY_TOFROM_GUEST 0xF80C
+/* Platform-specific hcalls used by the Ultravisor */
+#define H_SVM_PAGE_IN 0xEF00
+#define H_SVM_PAGE_OUT 0xEF04
+
/* Values for 2nd argument to H_SET_MODE */
#define H_SET_MODE_RESOURCE_SET_CIABR 1
#define H_SET_MODE_RESOURCE_SET_DAWR 2
diff --git a/arch/powerpc/include/asm/kvm_book3s_devm.h b/arch/powerpc/include/asm/kvm_book3s_devm.h
new file mode 100644
index 000000000000..21f3de5f2acb
--- /dev/null
+++ b/arch/powerpc/include/asm/kvm_book3s_devm.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __POWERPC_KVM_PPC_HMM_H__
+#define __POWERPC_KVM_PPC_HMM_H__
+
+#ifdef CONFIG_PPC_UV
+extern unsigned long kvmppc_h_svm_page_in(struct kvm *kvm,
+ unsigned long gra,
+ unsigned long flags,
+ unsigned long page_shift);
+extern unsigned long kvmppc_h_svm_page_out(struct kvm *kvm,
+ unsigned long gra,
+ unsigned long flags,
+ unsigned long page_shift);
+#else
+static inline unsigned long
+kvmppc_h_svm_page_in(struct kvm *kvm, unsigned long gra,
+ unsigned long flags, unsigned long page_shift)
+{
+ return H_UNSUPPORTED;
+}
+
+static inline unsigned long
+kvmppc_h_svm_page_out(struct kvm *kvm, unsigned long gra,
+ unsigned long flags, unsigned long page_shift)
+{
+ return H_UNSUPPORTED;
+}
+#endif /* CONFIG_PPC_UV */
+#endif /* __POWERPC_KVM_PPC_HMM_H__ */
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 4bb552d639b8..86bbe607ad7e 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -849,4 +849,16 @@ static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
+#ifdef CONFIG_PPC_UV
+extern int kvmppc_devm_init(void);
+extern void kvmppc_devm_free(void);
+#else
+static inline int kvmppc_devm_init(void)
+{
+ return 0;
+}
+
+static inline void kvmppc_devm_free(void) {}
+#endif /* CONFIG_PPC_UV */
+
#endif /* __POWERPC_KVM_HOST_H__ */
diff --git a/arch/powerpc/include/asm/ultravisor-api.h b/arch/powerpc/include/asm/ultravisor-api.h
index 6a0f9c74f959..1cd1f595fd81 100644
--- a/arch/powerpc/include/asm/ultravisor-api.h
+++ b/arch/powerpc/include/asm/ultravisor-api.h
@@ -25,5 +25,7 @@
/* opcodes */
#define UV_WRITE_PATE 0xF104
#define UV_RETURN 0xF11C
+#define UV_PAGE_IN 0xF128
+#define UV_PAGE_OUT 0xF12C
#endif /* _ASM_POWERPC_ULTRAVISOR_API_H */
diff --git a/arch/powerpc/include/asm/ultravisor.h b/arch/powerpc/include/asm/ultravisor.h
index 6fe1f365dec8..d668a59e099b 100644
--- a/arch/powerpc/include/asm/ultravisor.h
+++ b/arch/powerpc/include/asm/ultravisor.h
@@ -19,4 +19,18 @@ static inline int uv_register_pate(u64 lpid, u64 dw0, u64 dw1)
return ucall_norets(UV_WRITE_PATE, lpid, dw0, dw1);
}
+static inline int uv_page_in(u64 lpid, u64 src_ra, u64 dst_gpa, u64 flags,
+ u64 page_shift)
+{
+ return ucall_norets(UV_PAGE_IN, lpid, src_ra, dst_gpa, flags,
+ page_shift);
+}
+
+static inline int uv_page_out(u64 lpid, u64 dst_ra, u64 src_gpa, u64 flags,
+ u64 page_shift)
+{
+ return ucall_norets(UV_PAGE_OUT, lpid, dst_ra, src_gpa, flags,
+ page_shift);
+}
+
#endif /* _ASM_POWERPC_ULTRAVISOR_H */
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 4c67cc79de7c..16b40590e67c 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -71,6 +71,9 @@ kvm-hv-y += \
book3s_64_mmu_radix.o \
book3s_hv_nested.o
+kvm-hv-$(CONFIG_PPC_UV) += \
+ book3s_hv_devm.o
+
kvm-hv-$(CONFIG_PPC_TRANSACTIONAL_MEM) += \
book3s_hv_tm.o
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index ec1804f822af..00b43ee8b693 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -72,6 +72,8 @@
#include <asm/xics.h>
#include <asm/xive.h>
#include <asm/hw_breakpoint.h>
+#include <asm/kvm_host.h>
+#include <asm/kvm_book3s_devm.h>
#include "book3s.h"
@@ -1075,6 +1077,18 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
kvmppc_get_gpr(vcpu, 5),
kvmppc_get_gpr(vcpu, 6));
break;
+ case H_SVM_PAGE_IN:
+ ret = kvmppc_h_svm_page_in(vcpu->kvm,
+ kvmppc_get_gpr(vcpu, 4),
+ kvmppc_get_gpr(vcpu, 5),
+ kvmppc_get_gpr(vcpu, 6));
+ break;
+ case H_SVM_PAGE_OUT:
+ ret = kvmppc_h_svm_page_out(vcpu->kvm,
+ kvmppc_get_gpr(vcpu, 4),
+ kvmppc_get_gpr(vcpu, 5),
+ kvmppc_get_gpr(vcpu, 6));
+ break;
default:
return RESUME_HOST;
}
@@ -5510,11 +5524,16 @@ static int kvmppc_book3s_init_hv(void)
no_mixing_hpt_and_radix = true;
}
+ r = kvmppc_devm_init();
+ if (r < 0)
+ pr_err("KVM-HV: kvmppc_devm_init failed %d\n", r);
+
return r;
}
static void kvmppc_book3s_exit_hv(void)
{
+ kvmppc_devm_free();
kvmppc_free_host_rm_ops();
if (kvmppc_radix_possible())
kvmppc_radix_exit();
diff --git a/arch/powerpc/kvm/book3s_hv_devm.c b/arch/powerpc/kvm/book3s_hv_devm.c
new file mode 100644
index 000000000000..2e6c077bd22e
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_hv_devm.c
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver to manage page migration between normal and secure
+ * memory.
+ *
+ * Copyright 2018 Bharata B Rao, IBM Corp. <bharata@linux.ibm.com>
+ */
+
+/*
+ * A pseries guest can be run as a secure guest on Ultravisor-enabled
+ * POWER platforms. On such platforms, this driver will be used to manage
+ * the movement of guest pages between the normal memory managed by
+ * hypervisor (HV) and secure memory managed by Ultravisor (UV).
+ *
+ * The page-in or page-out requests from UV will come to HV as hcalls and
+ * HV will call back into UV via uvcalls to satisfy these page requests.
+ *
+ * Private ZONE_DEVICE memory equal to the amount of secure memory
+ * available in the platform for running secure guests is created
+ * via a char device. Whenever a page belonging to the guest becomes
+ * secure, a page from this private device memory is used to
+ * represent and track that secure page on the HV side.
+ *
+ * For each page that gets moved into secure memory, a device PFN is used
+ * on the HV side and migration PTE corresponding to that PFN would be
+ * populated in the QEMU page tables. Device PFNs are stored in the rmap
+ * array. Whenever a guest page becomes secure, device PFN allocated for
+ * the same will be populated in the corresponding slot in the rmap
+ * array. The overloading of rmap array's usage which otherwise is
+ * used primarily by HPT guests means that this feature (secure
+ * guest on PEF platforms) is available only for Radix MMU guests.
+ * Also the same rmap array is used differently by nested HPT guests.
+ * Hence a secure guest can't have nested guests.
+ */
+
+#include <linux/pagemap.h>
+#include <linux/migrate.h>
+#include <linux/kvm_host.h>
+#include <linux/sched/mm.h>
+#include <asm/ultravisor.h>
+
+struct kvmppc_devm_device {
+ struct device dev;
+ dev_t devt;
+ struct dev_pagemap pagemap;
+ unsigned long pfn_first, pfn_last;
+ unsigned long *pfn_bitmap;
+};
+
+
+static struct kvmppc_devm_device kvmppc_devm;
+spinlock_t kvmppc_devm_lock;
+
+struct kvmppc_devm_page_pvt {
+ unsigned long *rmap;
+ unsigned int lpid;
+ unsigned long gpa;
+};
+
+struct kvmppc_devm_copy_args {
+ unsigned long *rmap;
+ unsigned int lpid;
+ unsigned long gpa;
+ unsigned long page_shift;
+};
+
+/*
+ * Bits 60:56 in the rmap entry will be used to identify the
+ * different uses/functions of rmap. This definition with move
+ * to a proper header when all other functions are defined.
+ */
+#define KVMPPC_PFN_DEVM (0x2ULL << 56)
+
+static inline bool kvmppc_is_devm_pfn(unsigned long pfn)
+{
+ return !!(pfn & KVMPPC_PFN_DEVM);
+}
+
+/*
+ * Get a free device PFN from the pool
+ *
+ * Called when a normal page is moved to secure memory (UV_PAGE_IN). Device
+ * PFN will be used to keep track of the secure page on HV side.
+ *
+ * @rmap here is the slot in the rmap array that corresponds to @gpa.
+ * Thus a non-zero rmap entry indicates that the corresonding guest
+ * page has become secure, and is not mapped on the HV side.
+ *
+ * NOTE: In this and subsequent functions, we pass around and access
+ * individual elements of kvm_memory_slot->arch.rmap[] without any
+ * protection. Should we use lock_rmap() here?
+ */
+static struct page *kvmppc_devm_get_page(unsigned long *rmap,
+ unsigned long gpa, unsigned int lpid)
+{
+ struct page *dpage = NULL;
+ unsigned long bit, devm_pfn;
+ unsigned long nr_pfns = kvmppc_devm.pfn_last -
+ kvmppc_devm.pfn_first;
+ unsigned long flags;
+ struct kvmppc_devm_page_pvt *pvt;
+
+ if (kvmppc_is_devm_pfn(*rmap))
+ return NULL;
+
+ spin_lock_irqsave(&kvmppc_devm_lock, flags);
+ bit = find_first_zero_bit(kvmppc_devm.pfn_bitmap, nr_pfns);
+ if (bit >= nr_pfns)
+ goto out;
+
+ bitmap_set(kvmppc_devm.pfn_bitmap, bit, 1);
+ devm_pfn = bit + kvmppc_devm.pfn_first;
+ dpage = pfn_to_page(devm_pfn);
+
+ if (!trylock_page(dpage))
+ goto out_clear;
+
+ *rmap = devm_pfn | KVMPPC_PFN_DEVM;
+ pvt = kzalloc(sizeof(*pvt), GFP_ATOMIC);
+ if (!pvt)
+ goto out_unlock;
+ pvt->rmap = rmap;
+ pvt->gpa = gpa;
+ pvt->lpid = lpid;
+ dpage->zone_device_data = pvt;
+ spin_unlock_irqrestore(&kvmppc_devm_lock, flags);
+
+ get_page(dpage);
+ return dpage;
+
+out_unlock:
+ unlock_page(dpage);
+out_clear:
+ bitmap_clear(kvmppc_devm.pfn_bitmap,
+ devm_pfn - kvmppc_devm.pfn_first, 1);
+out:
+ spin_unlock_irqrestore(&kvmppc_devm_lock, flags);
+ return NULL;
+}
+
+/*
+ * Release the device PFN back to the pool
+ *
+ * Gets called when secure page becomes a normal page during UV_PAGE_OUT.
+ */
+static void kvmppc_devm_put_page(struct page *page)
+{
+ unsigned long pfn = page_to_pfn(page);
+ unsigned long flags;
+ struct kvmppc_devm_page_pvt *pvt;
+
+ spin_lock_irqsave(&kvmppc_devm_lock, flags);
+ pvt = (struct kvmppc_devm_page_pvt *)page->zone_device_data;
+ page->zone_device_data = 0;
+
+ bitmap_clear(kvmppc_devm.pfn_bitmap,
+ pfn - kvmppc_devm.pfn_first, 1);
+ *(pvt->rmap) = 0;
+ spin_unlock_irqrestore(&kvmppc_devm_lock, flags);
+ kfree(pvt);
+}
+
+/*
+ * Alloc a PFN from private device memory pool and copy page from normal
+ * memory to secure memory.
+ */
+static int
+kvmppc_devm_migrate_alloc_and_copy(struct migrate_vma *mig,
+ struct kvmppc_devm_copy_args *args)
+{
+ struct page *spage = migrate_pfn_to_page(*mig->src);
+ unsigned long pfn = *mig->src >> MIGRATE_PFN_SHIFT;
+ struct page *dpage;
+
+ *mig->dst = 0;
+ if (!spage || !(*mig->src & MIGRATE_PFN_MIGRATE))
+ return 0;
+
+ dpage = kvmppc_devm_get_page(args->rmap, args->gpa, args->lpid);
+ if (!dpage)
+ return -EINVAL;
+
+ if (spage)
+ uv_page_in(args->lpid, pfn << args->page_shift,
+ args->gpa, 0, args->page_shift);
+
+ *mig->dst = migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED;
+ return 0;
+}
+
+/*
+ * Move page from normal memory to secure memory.
+ */
+unsigned long
+kvmppc_h_svm_page_in(struct kvm *kvm, unsigned long gpa,
+ unsigned long flags, unsigned long page_shift)
+{
+ unsigned long addr, end;
+ unsigned long src_pfn, dst_pfn;
+ struct kvmppc_devm_copy_args args;
+ struct migrate_vma mig;
+ struct vm_area_struct *vma;
+ int srcu_idx;
+ unsigned long gfn = gpa >> page_shift;
+ struct kvm_memory_slot *slot;
+ unsigned long *rmap;
+ int ret;
+
+ if (page_shift != PAGE_SHIFT)
+ return H_P3;
+
+ if (flags)
+ return H_P2;
+
+ ret = H_PARAMETER;
+ down_read(&kvm->mm->mmap_sem);
+ srcu_idx = srcu_read_lock(&kvm->srcu);
+ slot = gfn_to_memslot(kvm, gfn);
+ rmap = &slot->arch.rmap[gfn - slot->base_gfn];
+ addr = gfn_to_hva(kvm, gpa >> page_shift);
+ if (kvm_is_error_hva(addr))
+ goto out;
+
+ end = addr + (1UL << page_shift);
+ vma = find_vma_intersection(kvm->mm, addr, end);
+ if (!vma || vma->vm_start > addr || vma->vm_end < end)
+ goto out;
+
+ args.rmap = rmap;
+ args.lpid = kvm->arch.lpid;
+ args.gpa = gpa;
+ args.page_shift = page_shift;
+
+ memset(&mig, 0, sizeof(mig));
+ mig.vma = vma;
+ mig.start = addr;
+ mig.end = end;
+ mig.src = &src_pfn;
+ mig.dst = &dst_pfn;
+
+ if (migrate_vma_setup(&mig))
+ goto out;
+
+ if (kvmppc_devm_migrate_alloc_and_copy(&mig, &args))
+ goto out_finalize;
+
+ migrate_vma_pages(&mig);
+ ret = H_SUCCESS;
+out_finalize:
+ migrate_vma_finalize(&mig);
+out:
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
+ up_read(&kvm->mm->mmap_sem);
+ return ret;
+}
+
+/*
+ * Provision a new page on HV side and copy over the contents
+ * from secure memory.
+ */
+static int
+kvmppc_devm_fault_migrate_alloc_and_copy(struct migrate_vma *mig)
+{
+ struct page *dpage, *spage;
+ struct kvmppc_devm_page_pvt *pvt;
+ unsigned long pfn;
+ int ret = U_SUCCESS;
+
+ spage = migrate_pfn_to_page(*mig->src);
+ if (!spage || !(*mig->src & MIGRATE_PFN_MIGRATE))
+ return 0;
+ if (!is_zone_device_page(spage))
+ return 0;
+
+ dpage = alloc_page_vma(GFP_HIGHUSER, mig->vma, mig->start);
+ if (!dpage)
+ return -EINVAL;
+ lock_page(dpage);
+ pvt = (struct kvmppc_devm_page_pvt *)spage->zone_device_data;
+
+ pfn = page_to_pfn(dpage);
+ ret = uv_page_out(pvt->lpid, pfn << PAGE_SHIFT,
+ pvt->gpa, 0, PAGE_SHIFT);
+ if (ret == U_SUCCESS)
+ *mig->dst = migrate_pfn(pfn) | MIGRATE_PFN_LOCKED;
+ return 0;
+}
+
+/*
+ * Fault handler callback when HV touches any page that has been
+ * moved to secure memory, we ask UV to give back the page by
+ * issuing a UV_PAGE_OUT uvcall.
+ *
+ * This eventually results in dropping of device PFN and the newly
+ * provisioned page/PFN gets populated in QEMU page tables.
+ */
+static vm_fault_t kvmppc_devm_migrate_to_ram(struct vm_fault *vmf)
+{
+ unsigned long src_pfn, dst_pfn = 0;
+ struct migrate_vma mig;
+ int ret = 0;
+
+ memset(&mig, 0, sizeof(mig));
+ mig.vma = vmf->vma;
+ mig.start = vmf->address;
+ mig.end = vmf->address + PAGE_SIZE;
+ mig.src = &src_pfn;
+ mig.dst = &dst_pfn;
+
+ if (migrate_vma_setup(&mig)) {
+ ret = VM_FAULT_SIGBUS;
+ goto out;
+ }
+
+ if (kvmppc_devm_fault_migrate_alloc_and_copy(&mig)) {
+ ret = VM_FAULT_SIGBUS;
+ goto out_finalize;
+ }
+
+ migrate_vma_pages(&mig);
+out_finalize:
+ migrate_vma_finalize(&mig);
+out:
+ return ret;
+}
+
+static void kvmppc_devm_page_free(struct page *page)
+{
+ kvmppc_devm_put_page(page);
+}
+
+static const struct dev_pagemap_ops kvmppc_devm_ops = {
+ .page_free = kvmppc_devm_page_free,
+ .migrate_to_ram = kvmppc_devm_migrate_to_ram,
+};
+
+/*
+ * Move page from secure memory to normal memory.
+ */
+unsigned long
+kvmppc_h_svm_page_out(struct kvm *kvm, unsigned long gpa,
+ unsigned long flags, unsigned long page_shift)
+{
+ struct migrate_vma mig;
+ unsigned long addr, end;
+ struct vm_area_struct *vma;
+ unsigned long src_pfn, dst_pfn = 0;
+ int srcu_idx;
+ int ret;
+
+ if (page_shift != PAGE_SHIFT)
+ return H_P3;
+
+ if (flags)
+ return H_P2;
+
+ ret = H_PARAMETER;
+ down_read(&kvm->mm->mmap_sem);
+ srcu_idx = srcu_read_lock(&kvm->srcu);
+ addr = gfn_to_hva(kvm, gpa >> page_shift);
+ if (kvm_is_error_hva(addr))
+ goto out;
+
+ end = addr + (1UL << page_shift);
+ vma = find_vma_intersection(kvm->mm, addr, end);
+ if (!vma || vma->vm_start > addr || vma->vm_end < end)
+ goto out;
+
+ memset(&mig, 0, sizeof(mig));
+ mig.vma = vma;
+ mig.start = addr;
+ mig.end = end;
+ mig.src = &src_pfn;
+ mig.dst = &dst_pfn;
+ if (migrate_vma_setup(&mig))
+ goto out;
+
+ if (kvmppc_devm_fault_migrate_alloc_and_copy(&mig))
+ goto out_finalize;
+
+ migrate_vma_pages(&mig);
+ ret = H_SUCCESS;
+out_finalize:
+ migrate_vma_finalize(&mig);
+out:
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
+ up_read(&kvm->mm->mmap_sem);
+ return ret;
+}
+
+static u64 kvmppc_get_secmem_size(void)
+{
+ struct device_node *np;
+ int i, len;
+ const __be32 *prop;
+ u64 size = 0;
+
+ np = of_find_node_by_path("/ibm,ultravisor/ibm,uv-firmware");
+ if (!np)
+ goto out;
+
+ prop = of_get_property(np, "secure-memory-ranges", &len);
+ if (!prop)
+ goto out_put;
+
+ for (i = 0; i < len / (sizeof(*prop) * 4); i++)
+ size += of_read_number(prop + (i * 4) + 2, 2);
+
+out_put:
+ of_node_put(np);
+out:
+ return size;
+}
+
+static int kvmppc_devm_pages_init(void)
+{
+ unsigned long nr_pfns = kvmppc_devm.pfn_last -
+ kvmppc_devm.pfn_first;
+
+ kvmppc_devm.pfn_bitmap = kcalloc(BITS_TO_LONGS(nr_pfns),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!kvmppc_devm.pfn_bitmap)
+ return -ENOMEM;
+
+ spin_lock_init(&kvmppc_devm_lock);
+
+ return 0;
+}
+
+static void kvmppc_devm_release(struct device *dev)
+{
+ unregister_chrdev_region(kvmppc_devm.devt, 1);
+}
+
+int kvmppc_devm_init(void)
+{
+ int ret = 0;
+ unsigned long size;
+ struct resource *res;
+ void *addr;
+
+ size = kvmppc_get_secmem_size();
+ if (!size) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = alloc_chrdev_region(&kvmppc_devm.devt, 0, 1,
+ "kvmppc-devm");
+ if (ret)
+ goto out;
+
+ dev_set_name(&kvmppc_devm.dev, "kvmppc_devm_device%d", 0);
+ kvmppc_devm.dev.release = kvmppc_devm_release;
+ device_initialize(&kvmppc_devm.dev);
+ res = devm_request_free_mem_region(&kvmppc_devm.dev,
+ &iomem_resource, size);
+ if (IS_ERR(res)) {
+ ret = PTR_ERR(res);
+ goto out_unregister;
+ }
+
+ kvmppc_devm.pagemap.type = MEMORY_DEVICE_PRIVATE;
+ kvmppc_devm.pagemap.res = *res;
+ kvmppc_devm.pagemap.ops = &kvmppc_devm_ops;
+ addr = devm_memremap_pages(&kvmppc_devm.dev, &kvmppc_devm.pagemap);
+ if (IS_ERR(addr)) {
+ ret = PTR_ERR(addr);
+ goto out_unregister;
+ }
+
+ kvmppc_devm.pfn_first = res->start >> PAGE_SHIFT;
+ kvmppc_devm.pfn_last = kvmppc_devm.pfn_first +
+ (resource_size(res) >> PAGE_SHIFT);
+ ret = kvmppc_devm_pages_init();
+ if (ret < 0)
+ goto out_unregister;
+
+ pr_info("KVMPPC-DEVM: Secure Memory size 0x%lx\n", size);
+ return ret;
+
+out_unregister:
+ put_device(&kvmppc_devm.dev);
+out:
+ return ret;
+}
+
+void kvmppc_devm_free(void)
+{
+ kfree(kvmppc_devm.pfn_bitmap);
+ put_device(&kvmppc_devm.dev);
+}
--
2.21.0
^ permalink raw reply related
* [PATCH v6 0/7] KVMPPC driver to manage secure guest pages
From: Bharata B Rao @ 2019-08-09 8:41 UTC (permalink / raw)
To: linuxppc-dev
Cc: linuxram, cclaudio, kvm-ppc, Bharata B Rao, linux-mm, jglisse,
aneesh.kumar, paulus, sukadev, hch
Hi,
A pseries guest can be run as a secure guest on Ultravisor-enabled
POWER platforms. On such platforms, this driver will be used to manage
the movement of guest pages between the normal memory managed by
hypervisor(HV) and secure memory managed by Ultravisor(UV).
Private ZONE_DEVICE memory equal to the amount of secure memory
available in the platform for running secure guests is created
via a char device. Whenever a page belonging to the guest becomes
secure, a page from this private device memory is used to
represent and track that secure page on the HV side. The movement
of pages between normal and secure memory is done via
migrate_vma_pages().
The page-in or page-out requests from UV will come to HV as hcalls and
HV will call back into UV via uvcalls to satisfy these page requests.
These patches are against Christoph Hellwig's migrate_vma-cleanup.2
branch
(http://git.infradead.org/users/hch/misc.git/shortlog/refs/heads/migrate_vma-cleanup.2)
plus
Claudio Carvalho's base ultravisor enablement patchset
(https://lore.kernel.org/linuxppc-dev/20190808040555.2371-1-cclaudio@linux.ibm.com/T/#t)
These patches along with Claudio's above patches are required to
run a secure pseries guest on KVM.
Changes in v6
=============
Updated the driver to account for the changes in HMM and migrate_vma()
by Christoph Hellwig.
- Not using any HMM routines any more.
- Switched to using migrate_vma_pages()
v5: https://www.mail-archive.com/linuxppc-dev@lists.ozlabs.org/msg153294.html
Anshuman Khandual (1):
KVM: PPC: Ultravisor: Add PPC_UV config option
Bharata B Rao (6):
kvmppc: Driver to manage pages of secure guest
kvmppc: Shared pages support for secure guests
kvmppc: H_SVM_INIT_START and H_SVM_INIT_DONE hcalls
kvmppc: Handle memory plug/unplug to secure VM
kvmppc: Radix changes for secure guest
kvmppc: Support reset of secure guest
Documentation/virtual/kvm/api.txt | 18 +
arch/powerpc/Kconfig | 18 +
arch/powerpc/include/asm/hvcall.h | 9 +
arch/powerpc/include/asm/kvm_book3s_devm.h | 48 ++
arch/powerpc/include/asm/kvm_host.h | 28 +
arch/powerpc/include/asm/kvm_ppc.h | 2 +
arch/powerpc/include/asm/ultravisor-api.h | 6 +
arch/powerpc/include/asm/ultravisor.h | 36 ++
arch/powerpc/kvm/Makefile | 3 +
arch/powerpc/kvm/book3s_64_mmu_radix.c | 22 +
arch/powerpc/kvm/book3s_hv.c | 115 ++++
arch/powerpc/kvm/book3s_hv_devm.c | 668 +++++++++++++++++++++
arch/powerpc/kvm/powerpc.c | 12 +
include/uapi/linux/kvm.h | 1 +
14 files changed, 986 insertions(+)
create mode 100644 arch/powerpc/include/asm/kvm_book3s_devm.h
create mode 100644 arch/powerpc/kvm/book3s_hv_devm.c
--
2.21.0
^ permalink raw reply
* [PATCH v5 4/4] mm/nvdimm: Pick the right alignment default when creating dax devices
From: Aneesh Kumar K.V @ 2019-08-09 7:45 UTC (permalink / raw)
To: dan.j.williams; +Cc: linux-mm, linuxppc-dev, Aneesh Kumar K.V, linux-nvdimm
In-Reply-To: <20190809074520.27115-1-aneesh.kumar@linux.ibm.com>
Allow arch to provide the supported alignments and use hugepage alignment only
if we support hugepage. Right now we depend on compile time configs whereas this
patch switch this to runtime discovery.
Architectures like ppc64 can have THP enabled in code, but then can have
hugepage size disabled by the hypervisor. This allows us to create dax devices
with PAGE_SIZE alignment in this case.
Existing dax namespace with alignment larger than PAGE_SIZE will fail to
initialize in this specific case. We still allow fsdax namespace initialization.
With respect to identifying whether to enable hugepage fault for a dax device,
if THP is enabled during compile, we default to taking hugepage fault and in dax
fault handler if we find the fault size > alignment we retry with PAGE_SIZE
fault size.
This also addresses the below failure scenario on ppc64
ndctl create-namespace --mode=devdax | grep align
"align":16777216,
"align":16777216
cat /sys/devices/ndbus0/region0/dax0.0/supported_alignments
65536 16777216
daxio.static-debug -z -o /dev/dax0.0
Bus error (core dumped)
$ dmesg | tail
lpar: Failed hash pte insert with error -4
hash-mmu: mm: Hashing failure ! EA=0x7fff17000000 access=0x8000000000000006 current=daxio
hash-mmu: trap=0x300 vsid=0x22cb7a3 ssize=1 base psize=2 psize 10 pte=0xc000000501002b86
daxio[3860]: bus error (7) at 7fff17000000 nip 7fff973c007c lr 7fff973bff34 code 2 in libpmem.so.1.0.0[7fff973b0000+20000]
daxio[3860]: code: 792945e4 7d494b78 e95f0098 7d494b78 f93f00a0 4800012c e93f0088 f93f0120
daxio[3860]: code: e93f00a0 f93f0128 e93f0120 e95f0128 <f9490000> e93f0088 39290008 f93f0110
The failure was due to guest kernel using wrong page size.
The namespaces created with 16M alignment will appear as below on a config with
16M page size disabled.
$ ndctl list -Ni
[
{
"dev":"namespace0.1",
"mode":"fsdax",
"map":"dev",
"size":5351931904,
"uuid":"fc6e9667-461a-4718-82b4-69b24570bddb",
"align":16777216,
"blockdev":"pmem0.1",
"supported_alignments":[
65536
]
},
{
"dev":"namespace0.0",
"mode":"fsdax", <==== devdax 16M alignment marked disabled.
"map":"mem",
"size":5368709120,
"uuid":"a4bdf81a-f2ee-4bc6-91db-7b87eddd0484",
"state":"disabled"
}
]
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/libnvdimm.h | 9 ++++++++
arch/powerpc/mm/Makefile | 1 +
arch/powerpc/mm/nvdimm.c | 34 ++++++++++++++++++++++++++++
arch/x86/include/asm/libnvdimm.h | 19 ++++++++++++++++
drivers/nvdimm/nd.h | 6 -----
drivers/nvdimm/pfn_devs.c | 32 +++++++++++++++++++++++++-
include/linux/huge_mm.h | 7 +++++-
7 files changed, 100 insertions(+), 8 deletions(-)
create mode 100644 arch/powerpc/include/asm/libnvdimm.h
create mode 100644 arch/powerpc/mm/nvdimm.c
create mode 100644 arch/x86/include/asm/libnvdimm.h
diff --git a/arch/powerpc/include/asm/libnvdimm.h b/arch/powerpc/include/asm/libnvdimm.h
new file mode 100644
index 000000000000..d35fd7f48603
--- /dev/null
+++ b/arch/powerpc/include/asm/libnvdimm.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_LIBNVDIMM_H
+#define _ASM_POWERPC_LIBNVDIMM_H
+
+#define nd_pfn_supported_alignments nd_pfn_supported_alignments
+extern unsigned long *nd_pfn_supported_alignments(void);
+extern unsigned long nd_pfn_default_alignment(void);
+
+#endif
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 0f499db315d6..42e4a399ba5d 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o
obj-$(CONFIG_PPC_PTDUMP) += ptdump/
obj-$(CONFIG_KASAN) += kasan/
+obj-$(CONFIG_NVDIMM_PFN) += nvdimm.o
diff --git a/arch/powerpc/mm/nvdimm.c b/arch/powerpc/mm/nvdimm.c
new file mode 100644
index 000000000000..a29a4510715e
--- /dev/null
+++ b/arch/powerpc/mm/nvdimm.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <linux/mm.h>
+/*
+ * We support only pte and pmd mappings for now.
+ */
+const unsigned long *nd_pfn_supported_alignments(void)
+{
+ static unsigned long supported_alignments[3];
+
+ supported_alignments[0] = PAGE_SIZE;
+
+ if (has_transparent_hugepage())
+ supported_alignments[1] = HPAGE_PMD_SIZE;
+ else
+ supported_alignments[1] = 0;
+
+ supported_alignments[2] = 0;
+ return supported_alignments;
+}
+
+/*
+ * Use pmd mapping if supported as default alignment
+ */
+unsigned long nd_pfn_default_alignment(void)
+{
+
+ if (has_transparent_hugepage())
+ return HPAGE_PMD_SIZE;
+ return PAGE_SIZE;
+}
diff --git a/arch/x86/include/asm/libnvdimm.h b/arch/x86/include/asm/libnvdimm.h
new file mode 100644
index 000000000000..3d5361db9164
--- /dev/null
+++ b/arch/x86/include/asm/libnvdimm.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_LIBNVDIMM_H
+#define _ASM_X86_LIBNVDIMM_H
+
+static inline unsigned long nd_pfn_default_alignment(void)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ return HPAGE_PMD_SIZE;
+#else
+ return PAGE_SIZE;
+#endif
+}
+
+static inline unsigned long nd_altmap_align_size(unsigned long nd_align)
+{
+ return PMD_SIZE;
+}
+
+#endif
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 1b9955651379..5d095a19ff2c 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -289,12 +289,6 @@ static inline struct device *nd_btt_create(struct nd_region *nd_region)
struct nd_pfn *to_nd_pfn(struct device *dev);
#if IS_ENABLED(CONFIG_NVDIMM_PFN)
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-#define PFN_DEFAULT_ALIGNMENT HPAGE_PMD_SIZE
-#else
-#define PFN_DEFAULT_ALIGNMENT PAGE_SIZE
-#endif
-
int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns);
bool is_nd_pfn(struct device *dev);
struct device *nd_pfn_create(struct nd_region *nd_region);
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index c1d9be609322..f43d1baa6f33 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -10,6 +10,7 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/mm.h>
+#include <asm/libnvdimm.h>
#include "nd-core.h"
#include "pfn.h"
#include "nd.h"
@@ -103,6 +104,8 @@ static ssize_t align_show(struct device *dev,
return sprintf(buf, "%ld\n", nd_pfn->align);
}
+#ifndef nd_pfn_supported_alignments
+#define nd_pfn_supported_alignments nd_pfn_supported_alignments
static const unsigned long *nd_pfn_supported_alignments(void)
{
/*
@@ -125,6 +128,7 @@ static const unsigned long *nd_pfn_supported_alignments(void)
return data;
}
+#endif
static ssize_t align_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
@@ -302,7 +306,7 @@ struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn,
return NULL;
nd_pfn->mode = PFN_MODE_NONE;
- nd_pfn->align = PFN_DEFAULT_ALIGNMENT;
+ nd_pfn->align = nd_pfn_default_alignment();
dev = &nd_pfn->dev;
device_initialize(&nd_pfn->dev);
if (ndns && !__nd_attach_ndns(&nd_pfn->dev, ndns, &nd_pfn->ndns)) {
@@ -412,6 +416,20 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
return 0;
}
+static bool nd_supported_alignment(unsigned long align)
+{
+ int i;
+ const unsigned long *supported = nd_pfn_supported_alignments();
+
+ if (align == 0)
+ return false;
+
+ for (i = 0; supported[i]; i++)
+ if (align == supported[i])
+ return true;
+ return false;
+}
+
/**
* nd_pfn_validate - read and validate info-block
* @nd_pfn: fsdax namespace runtime state / properties
@@ -498,6 +516,18 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
return -EOPNOTSUPP;
}
+ /*
+ * Check whether the we support the alignment. For Dax if the
+ * superblock alignment is not matching, we won't initialize
+ * the device.
+ */
+ if (!nd_supported_alignment(align) &&
+ !memcmp(pfn_sb->signature, DAX_SIG, PFN_SIG_LEN)) {
+ dev_err(&nd_pfn->dev, "init failed, alignment mismatch: "
+ "%ld:%ld\n", nd_pfn->align, align);
+ return -EOPNOTSUPP;
+ }
+
if (!nd_pfn->uuid) {
/*
* When probing a namepace via nd_pfn_probe() the uuid
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index 45ede62aa85b..4fa91f9bd0da 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -108,7 +108,12 @@ static inline bool __transparent_hugepage_enabled(struct vm_area_struct *vma)
if (transparent_hugepage_flags & (1 << TRANSPARENT_HUGEPAGE_FLAG))
return true;
-
+ /*
+ * For dax let's try to do hugepage fault always. If we don't support
+ * hugepages we will not have enabled namespaces with hugepage alignment.
+ * This also means we try to handle hugepage fault on device with
+ * smaller alignment. But for then we will return with VM_FAULT_FALLBACK
+ */
if (vma_is_dax(vma))
return true;
--
2.21.0
^ permalink raw reply related
* [PATCH v5 3/4] mm/nvdimm: Use correct #defines instead of open coding
From: Aneesh Kumar K.V @ 2019-08-09 7:45 UTC (permalink / raw)
To: dan.j.williams; +Cc: linux-mm, linuxppc-dev, Aneesh Kumar K.V, linux-nvdimm
In-Reply-To: <20190809074520.27115-1-aneesh.kumar@linux.ibm.com>
Use PAGE_SIZE instead of SZ_4K and sizeof(struct page) instead of 64.
If we have a kernel built with different struct page size the previous
patch should handle marking the namespace disabled.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
drivers/nvdimm/label.c | 2 +-
drivers/nvdimm/namespace_devs.c | 6 +++---
drivers/nvdimm/pfn_devs.c | 3 ++-
drivers/nvdimm/region_devs.c | 8 ++++----
4 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 73e197babc2f..7ee037063be7 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -355,7 +355,7 @@ static bool slot_valid(struct nvdimm_drvdata *ndd,
/* check that DPA allocations are page aligned */
if ((__le64_to_cpu(nd_label->dpa)
- | __le64_to_cpu(nd_label->rawsize)) % SZ_4K)
+ | __le64_to_cpu(nd_label->rawsize)) % PAGE_SIZE)
return false;
/* check checksum */
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index a16e52251a30..a9c76df12cb9 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1006,10 +1006,10 @@ static ssize_t __size_store(struct device *dev, unsigned long long val)
return -ENXIO;
}
- div_u64_rem(val, SZ_4K * nd_region->ndr_mappings, &remainder);
+ div_u64_rem(val, PAGE_SIZE * nd_region->ndr_mappings, &remainder);
if (remainder) {
- dev_dbg(dev, "%llu is not %dK aligned\n", val,
- (SZ_4K * nd_region->ndr_mappings) / SZ_1K);
+ dev_dbg(dev, "%llu is not %ldK aligned\n", val,
+ (PAGE_SIZE * nd_region->ndr_mappings) / SZ_1K);
return -EINVAL;
}
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 37e96811c2fc..c1d9be609322 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -725,7 +725,8 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
* when populating the vmemmap. This *should* be equal to
* PMD_SIZE for most architectures.
*/
- offset = ALIGN(start + SZ_8K + 64 * npfns, align) - start;
+ offset = ALIGN(start + SZ_8K + sizeof(struct page) * npfns,
+ align) - start;
} else if (nd_pfn->mode == PFN_MODE_RAM)
offset = ALIGN(start + SZ_8K, align) - start;
else
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index af30cbe7a8ea..20e265a534f8 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -992,10 +992,10 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
struct nvdimm *nvdimm = mapping->nvdimm;
- if ((mapping->start | mapping->size) % SZ_4K) {
- dev_err(&nvdimm_bus->dev, "%s: %s mapping%d is not 4K aligned\n",
- caller, dev_name(&nvdimm->dev), i);
-
+ if ((mapping->start | mapping->size) % PAGE_SIZE) {
+ dev_err(&nvdimm_bus->dev,
+ "%s: %s mapping%d is not %ld aligned\n",
+ caller, dev_name(&nvdimm->dev), i, PAGE_SIZE);
return NULL;
}
--
2.21.0
^ permalink raw reply related
* [PATCH v5 2/4] mm/nvdimm: Add page size and struct page size to pfn superblock
From: Aneesh Kumar K.V @ 2019-08-09 7:45 UTC (permalink / raw)
To: dan.j.williams; +Cc: linux-mm, linuxppc-dev, Aneesh Kumar K.V, linux-nvdimm
In-Reply-To: <20190809074520.27115-1-aneesh.kumar@linux.ibm.com>
This is needed so that we don't wrongly initialize a namespace
which doesn't have enough space reserved for holding struct pages
with the current kernel.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
drivers/nvdimm/pfn.h | 5 ++++-
drivers/nvdimm/pfn_devs.c | 27 ++++++++++++++++++++++++++-
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/drivers/nvdimm/pfn.h b/drivers/nvdimm/pfn.h
index 7381673b7b70..acb19517f678 100644
--- a/drivers/nvdimm/pfn.h
+++ b/drivers/nvdimm/pfn.h
@@ -29,7 +29,10 @@ struct nd_pfn_sb {
/* minor-version-2 record the base alignment of the mapping */
__le32 align;
/* minor-version-3 guarantee the padding and flags are zero */
- u8 padding[4000];
+ /* minor-version-4 record the page size and struct page size */
+ __le32 page_size;
+ __le16 page_struct_size;
+ u8 padding[3994];
__le64 checksum;
};
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 3e7b11cf1aae..37e96811c2fc 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -460,6 +460,15 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
if (__le16_to_cpu(pfn_sb->version_minor) < 2)
pfn_sb->align = 0;
+ if (__le16_to_cpu(pfn_sb->version_minor) < 4) {
+ /*
+ * For a large part we use PAGE_SIZE. But we
+ * do have some accounting code using SZ_4K.
+ */
+ pfn_sb->page_struct_size = cpu_to_le16(64);
+ pfn_sb->page_size = cpu_to_le32(PAGE_SIZE);
+ }
+
switch (le32_to_cpu(pfn_sb->mode)) {
case PFN_MODE_RAM:
case PFN_MODE_PMEM:
@@ -475,6 +484,20 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
align = 1UL << ilog2(offset);
mode = le32_to_cpu(pfn_sb->mode);
+ if (le32_to_cpu(pfn_sb->page_size) != PAGE_SIZE) {
+ dev_err(&nd_pfn->dev,
+ "init failed, page size mismatch %d\n",
+ le32_to_cpu(pfn_sb->page_size));
+ return -EOPNOTSUPP;
+ }
+
+ if (le16_to_cpu(pfn_sb->page_struct_size) < sizeof(struct page)) {
+ dev_err(&nd_pfn->dev,
+ "init failed, struct page size mismatch %d\n",
+ le16_to_cpu(pfn_sb->page_struct_size));
+ return -EOPNOTSUPP;
+ }
+
if (!nd_pfn->uuid) {
/*
* When probing a namepace via nd_pfn_probe() the uuid
@@ -722,8 +745,10 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
pfn_sb->version_major = cpu_to_le16(1);
- pfn_sb->version_minor = cpu_to_le16(3);
+ pfn_sb->version_minor = cpu_to_le16(4);
pfn_sb->align = cpu_to_le32(nd_pfn->align);
+ pfn_sb->page_struct_size = cpu_to_le16(sizeof(struct page));
+ pfn_sb->page_size = cpu_to_le32(PAGE_SIZE);
checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
pfn_sb->checksum = cpu_to_le64(checksum);
--
2.21.0
^ permalink raw reply related
* [PATCH v5 1/4] nvdimm: Consider probe return -EOPNOTSUPP as success
From: Aneesh Kumar K.V @ 2019-08-09 7:45 UTC (permalink / raw)
To: dan.j.williams; +Cc: linux-mm, linuxppc-dev, Aneesh Kumar K.V, linux-nvdimm
In-Reply-To: <20190809074520.27115-1-aneesh.kumar@linux.ibm.com>
This patch add -EOPNOTSUPP as return from probe callback to
indicate we were not able to initialize a namespace due to pfn superblock
feature/version mismatch. We want to consider this a probe success so that
we can create new namesapce seed and there by avoid marking the failed
namespace as the seed namespace.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
drivers/nvdimm/bus.c | 2 +-
drivers/nvdimm/pmem.c | 26 ++++++++++++++++++++++----
2 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 798c5c4aea9c..16c35e6446a7 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -95,7 +95,7 @@ static int nvdimm_bus_probe(struct device *dev)
rc = nd_drv->probe(dev);
debug_nvdimm_unlock(dev);
- if (rc == 0)
+ if (rc == 0 || rc == -EOPNOTSUPP)
nd_region_probe_success(nvdimm_bus, dev);
else
nd_region_disable(nvdimm_bus, dev);
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 4c121dd03dd9..3f498881dd28 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -490,6 +490,7 @@ static int pmem_attach_disk(struct device *dev,
static int nd_pmem_probe(struct device *dev)
{
+ int ret;
struct nd_namespace_common *ndns;
ndns = nvdimm_namespace_common_probe(dev);
@@ -505,12 +506,29 @@ static int nd_pmem_probe(struct device *dev)
if (is_nd_pfn(dev))
return pmem_attach_disk(dev, ndns);
- /* if we find a valid info-block we'll come back as that personality */
- if (nd_btt_probe(dev, ndns) == 0 || nd_pfn_probe(dev, ndns) == 0
- || nd_dax_probe(dev, ndns) == 0)
+ ret = nd_btt_probe(dev, ndns);
+ if (ret == 0)
return -ENXIO;
+ else if (ret == -EOPNOTSUPP)
+ return ret;
- /* ...otherwise we're just a raw pmem device */
+ ret = nd_pfn_probe(dev, ndns);
+ if (ret == 0)
+ return -ENXIO;
+ else if (ret == -EOPNOTSUPP)
+ return ret;
+
+ ret = nd_dax_probe(dev, ndns);
+ if (ret == 0)
+ return -ENXIO;
+ else if (ret == -EOPNOTSUPP)
+ return ret;
+ /*
+ * We have two failure conditions here, there is no
+ * info reserver block or we found a valid info reserve block
+ * but failed to initialize the pfn superblock.
+ * Don't create a raw pmem disk for the second case.
+ */
return pmem_attach_disk(dev, ndns);
}
--
2.21.0
^ permalink raw reply related
* [PATCH v5 0/4] Mark the namespace disabled on pfn superblock mismatch
From: Aneesh Kumar K.V @ 2019-08-09 7:45 UTC (permalink / raw)
To: dan.j.williams; +Cc: linux-mm, linuxppc-dev, Aneesh Kumar K.V, linux-nvdimm
We add new members to pfn superblock (PAGE_SIZE and struct page size) in this series.
This is now checked while initializing the namespace. If we find a mismatch we mark
the namespace disabled.
This series also handle configs where hugepage support is not enabled by default.
This can result in different align restrictions for dax namespace. We mark the
dax namespace disabled if we find the alignment not supported.
Aneesh Kumar K.V (4):
nvdimm: Consider probe return -EOPNOTSUPP as success
mm/nvdimm: Add page size and struct page size to pfn superblock
mm/nvdimm: Use correct #defines instead of open coding
mm/nvdimm: Pick the right alignment default when creating dax devices
arch/powerpc/include/asm/libnvdimm.h | 9 ++++
arch/powerpc/mm/Makefile | 1 +
arch/powerpc/mm/nvdimm.c | 34 +++++++++++++++
arch/x86/include/asm/libnvdimm.h | 19 +++++++++
drivers/nvdimm/bus.c | 2 +-
drivers/nvdimm/label.c | 2 +-
drivers/nvdimm/namespace_devs.c | 6 +--
drivers/nvdimm/nd.h | 6 ---
drivers/nvdimm/pfn.h | 5 ++-
drivers/nvdimm/pfn_devs.c | 62 ++++++++++++++++++++++++++--
drivers/nvdimm/pmem.c | 26 ++++++++++--
drivers/nvdimm/region_devs.c | 8 ++--
include/linux/huge_mm.h | 7 +++-
13 files changed, 163 insertions(+), 24 deletions(-)
create mode 100644 arch/powerpc/include/asm/libnvdimm.h
create mode 100644 arch/powerpc/mm/nvdimm.c
create mode 100644 arch/x86/include/asm/libnvdimm.h
--
2.21.0
^ permalink raw reply
* [RFC V2 1/1] mm/pgtable/debug: Add test validating architecture page table helpers
From: Anshuman Khandual @ 2019-08-09 7:33 UTC (permalink / raw)
To: linux-mm
Cc: Mark Rutland, linux-ia64, linux-sh, Peter Zijlstra, James Hogan,
Tetsuo Handa, Heiko Carstens, Michal Hocko, Dave Hansen,
Paul Mackerras, sparclinux, Thomas Gleixner, linux-s390, x86,
Russell King - ARM Linux, Matthew Wilcox, Steven Price,
Jason Gunthorpe, linux-arm-kernel, linux-snps-arc, Kees Cook,
Anshuman Khandual, Masahiro Yamada, Mark Brown, Dan Williams,
Vlastimil Babka, Sri Krishna chowdary, Ard Biesheuvel,
Greg Kroah-Hartman, linux-mips, Ralf Baechle, linux-kernel,
Paul Burton, Mike Rapoport, Vineet Gupta, Martin Schwidefsky,
Andrew Morton, linuxppc-dev, David S. Miller
In-Reply-To: <1565335998-22553-1-git-send-email-anshuman.khandual@arm.com>
This adds a test module which will validate architecture page table helpers
and accessors regarding compliance with generic MM semantics expectations.
This will help various architectures in validating changes to the existing
page table helpers or addition of new ones.
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Mike Rapoport <rppt@linux.vnet.ibm.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: Steven Price <Steven.Price@arm.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Sri Krishna chowdary <schowdary@nvidia.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Russell King - ARM Linux <linux@armlinux.org.uk>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Vineet Gupta <vgupta@synopsys.com>
Cc: James Hogan <jhogan@kernel.org>
Cc: Paul Burton <paul.burton@mips.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-snps-arc@lists.infradead.org
Cc: linux-mips@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-ia64@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-s390@vger.kernel.org
Cc: linux-sh@vger.kernel.org
Cc: sparclinux@vger.kernel.org
Cc: x86@kernel.org
Cc: linux-kernel@vger.kernel.org
Suggested-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
---
mm/Kconfig.debug | 14 ++
mm/Makefile | 1 +
mm/arch_pgtable_test.c | 400 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 415 insertions(+)
create mode 100644 mm/arch_pgtable_test.c
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
index 82b6a20898bd..d3dfbe984d41 100644
--- a/mm/Kconfig.debug
+++ b/mm/Kconfig.debug
@@ -115,3 +115,17 @@ config DEBUG_RODATA_TEST
depends on STRICT_KERNEL_RWX
---help---
This option enables a testcase for the setting rodata read-only.
+
+config DEBUG_ARCH_PGTABLE_TEST
+ bool "Test arch page table helpers for semantics compliance"
+ depends on MMU
+ depends on DEBUG_KERNEL
+ help
+ This options provides a kernel module which can be used to test
+ architecture page table helper functions on various platform in
+ verifying if they comply with expected generic MM semantics. This
+ will help architectures code in making sure that any changes or
+ new additions of these helpers will still conform to generic MM
+ expected semantics.
+
+ If unsure, say N.
diff --git a/mm/Makefile b/mm/Makefile
index 338e528ad436..0e6ac3789ca8 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o
obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o
obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o
obj-$(CONFIG_DEBUG_RODATA_TEST) += rodata_test.o
+obj-$(CONFIG_DEBUG_ARCH_PGTABLE_TEST) += arch_pgtable_test.o
obj-$(CONFIG_PAGE_OWNER) += page_owner.o
obj-$(CONFIG_CLEANCACHE) += cleancache.o
obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
diff --git a/mm/arch_pgtable_test.c b/mm/arch_pgtable_test.c
new file mode 100644
index 000000000000..41d6fa78a620
--- /dev/null
+++ b/mm/arch_pgtable_test.c
@@ -0,0 +1,400 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * This kernel module validates architecture page table helpers &
+ * accessors and helps in verifying their continued compliance with
+ * generic MM semantics.
+ *
+ * Copyright (C) 2019 ARM Ltd.
+ *
+ * Author: Anshuman Khandual <anshuman.khandual@arm.com>
+ */
+#define pr_fmt(fmt) "arch_pgtable_test: %s " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/hugetlb.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/mm_types.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
+#include <linux/pfn_t.h>
+#include <linux/gfp.h>
+#include <linux/spinlock.h>
+#include <linux/sched/mm.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+/*
+ * Basic operations
+ *
+ * mkold(entry) = An old and not a young entry
+ * mkyoung(entry) = A young and not an old entry
+ * mkdirty(entry) = A dirty and not a clean entry
+ * mkclean(entry) = A clean and not a dirty entry
+ * mkwrite(entry) = A write and not a write protected entry
+ * wrprotect(entry) = A write protected and not a write entry
+ * pxx_bad(entry) = A mapped and non-table entry
+ * pxx_same(entry1, entry2) = Both entries hold the exact same value
+ */
+#define VADDR_TEST (PGDIR_SIZE + PUD_SIZE + PMD_SIZE + PAGE_SIZE)
+#define VMA_TEST_FLAGS (VM_READ|VM_WRITE|VM_EXEC)
+#define RANDOM_NZVALUE (0xbe)
+
+static bool pud_aligned;
+
+extern struct mm_struct *mm_alloc(void);
+
+static void pte_basic_tests(struct page *page, pgprot_t prot)
+{
+ pte_t pte = mk_pte(page, prot);
+
+ WARN_ON(!pte_same(pte, pte));
+ WARN_ON(!pte_young(pte_mkyoung(pte)));
+ WARN_ON(!pte_dirty(pte_mkdirty(pte)));
+ WARN_ON(!pte_write(pte_mkwrite(pte)));
+ WARN_ON(pte_young(pte_mkold(pte)));
+ WARN_ON(pte_dirty(pte_mkclean(pte)));
+ WARN_ON(pte_write(pte_wrprotect(pte)));
+}
+
+#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE
+static void pmd_basic_tests(struct page *page, pgprot_t prot)
+{
+ pmd_t pmd = mk_pmd(page, prot);
+
+ WARN_ON(!pmd_same(pmd, pmd));
+ WARN_ON(!pmd_young(pmd_mkyoung(pmd)));
+ WARN_ON(!pmd_dirty(pmd_mkdirty(pmd)));
+ WARN_ON(!pmd_write(pmd_mkwrite(pmd)));
+ WARN_ON(pmd_young(pmd_mkold(pmd)));
+ WARN_ON(pmd_dirty(pmd_mkclean(pmd)));
+ WARN_ON(pmd_write(pmd_wrprotect(pmd)));
+ /*
+ * A huge page does not point to next level page table
+ * entry. Hence this must qualify as pmd_bad().
+ */
+ WARN_ON(!pmd_bad(pmd_mkhuge(pmd)));
+}
+#else
+static void pmd_basic_tests(struct page *page, pgprot_t prot) { }
+#endif
+
+#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
+static void pud_basic_tests(struct page *page, pgprot_t prot)
+{
+ pud_t pud;
+
+ /*
+ * Memory block here must be PUD_SIZE aligned. Abort this
+ * test in case we could not allocate such a memory block.
+ */
+ if (!pud_aligned) {
+ pr_warn("Could not proceed with PUD tests\n");
+ return;
+ }
+ pud = pfn_pud(page_to_pfn(page), prot);
+
+ WARN_ON(!pud_same(pud, pud));
+ WARN_ON(!pud_young(pud_mkyoung(pud)));
+ WARN_ON(!pud_write(pud_mkwrite(pud)));
+ WARN_ON(pud_write(pud_wrprotect(pud)));
+ WARN_ON(pud_young(pud_mkold(pud)));
+
+#if !defined(__PAGETABLE_PMD_FOLDED) && !defined(__ARCH_HAS_4LEVEL_HACK)
+ /*
+ * A huge page does not point to next level page table
+ * entry. Hence this must qualify as pud_bad().
+ */
+ WARN_ON(!pud_bad(pud_mkhuge(pud)));
+#endif
+}
+#else
+static void pud_basic_tests(struct page *page, pgprot_t prot) { }
+#endif
+
+static void p4d_basic_tests(struct page *page, pgprot_t prot)
+{
+ p4d_t p4d;
+
+ memset(&p4d, RANDOM_NZVALUE, sizeof(p4d_t));
+ WARN_ON(!p4d_same(p4d, p4d));
+}
+
+static void pgd_basic_tests(struct page *page, pgprot_t prot)
+{
+ pgd_t pgd;
+
+ memset(&pgd, RANDOM_NZVALUE, sizeof(pgd_t));
+ WARN_ON(!pgd_same(pgd, pgd));
+}
+
+#if !defined(__PAGETABLE_PMD_FOLDED) && !defined(__ARCH_HAS_4LEVEL_HACK)
+static void pud_clear_tests(pud_t *pudp)
+{
+ memset(pudp, RANDOM_NZVALUE, sizeof(pud_t));
+ pud_clear(pudp);
+ WARN_ON(!pud_none(READ_ONCE(*pudp)));
+}
+
+static void pud_populate_tests(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp)
+{
+ /*
+ * This entry points to next level page table page.
+ * Hence this must not qualify as pud_bad().
+ */
+ pmd_clear(pmdp);
+ pud_clear(pudp);
+ pud_populate(mm, pudp, pmdp);
+ WARN_ON(pud_bad(READ_ONCE(*pudp)));
+}
+#else
+static void pud_clear_tests(pud_t *pudp) { }
+static void pud_populate_tests(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp)
+{
+}
+#endif
+
+#if !defined(__PAGETABLE_PUD_FOLDED) && !defined(__ARCH_HAS_5LEVEL_HACK)
+static void p4d_clear_tests(p4d_t *p4dp)
+{
+ memset(p4dp, RANDOM_NZVALUE, sizeof(p4d_t));
+ p4d_clear(p4dp);
+ WARN_ON(!p4d_none(READ_ONCE(*p4dp)));
+}
+
+static void p4d_populate_tests(struct mm_struct *mm, p4d_t *p4dp, pud_t *pudp)
+{
+ /*
+ * This entry points to next level page table page.
+ * Hence this must not qualify as p4d_bad().
+ */
+ pud_clear(pudp);
+ p4d_clear(p4dp);
+ p4d_populate(mm, p4dp, pudp);
+ WARN_ON(p4d_bad(READ_ONCE(*p4dp)));
+}
+#else
+static void p4d_clear_tests(p4d_t *p4dp) { }
+static void p4d_populate_tests(struct mm_struct *mm, p4d_t *p4dp, pud_t *pudp)
+{
+}
+#endif
+
+#ifndef __PAGETABLE_P4D_FOLDED
+static void pgd_clear_tests(pgd_t *pgdp)
+{
+ memset(pgdp, RANDOM_NZVALUE, sizeof(pgd_t));
+ pgd_clear(pgdp);
+ WARN_ON(!pgd_none(READ_ONCE(*pgdp)));
+}
+
+static void pgd_populate_tests(struct mm_struct *mm, pgd_t *pgdp, p4d_t *p4dp)
+{
+ /*
+ * This entry points to next level page table page.
+ * Hence this must not qualify as pgd_bad().
+ */
+ p4d_clear(p4dp);
+ pgd_clear(pgdp);
+ pgd_populate(mm, pgdp, p4dp);
+ WARN_ON(pgd_bad(READ_ONCE(*pgdp)));
+}
+#else
+static void pgd_clear_tests(pgd_t *pgdp) { }
+static void pgd_populate_tests(struct mm_struct *mm, pgd_t *pgdp, p4d_t *p4dp)
+{
+}
+#endif
+
+static void pte_clear_tests(pte_t *ptep)
+{
+ memset(ptep, RANDOM_NZVALUE, sizeof(pte_t));
+ pte_clear(NULL, 0, ptep);
+ WARN_ON(!pte_none(READ_ONCE(*ptep)));
+}
+
+static void pmd_clear_tests(pmd_t *pmdp)
+{
+ memset(pmdp, RANDOM_NZVALUE, sizeof(pmd_t));
+ pmd_clear(pmdp);
+ WARN_ON(!pmd_none(READ_ONCE(*pmdp)));
+}
+
+static void pmd_populate_tests(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pgtable)
+{
+ /*
+ * This entry points to next level page table page.
+ * Hence this must not qualify as pmd_bad().
+ */
+ pmd_clear(pmdp);
+ pmd_populate(mm, pmdp, pgtable);
+ WARN_ON(pmd_bad(READ_ONCE(*pmdp)));
+}
+
+static bool pfn_range_valid(struct zone *z, unsigned long start_pfn,
+ unsigned long nr_pages)
+{
+ unsigned long i, end_pfn = start_pfn + nr_pages;
+ struct page *page;
+
+ for (i = start_pfn; i < end_pfn; i++) {
+ if (!pfn_valid(i))
+ return false;
+
+ page = pfn_to_page(i);
+
+ if (page_zone(page) != z)
+ return false;
+
+ if (PageReserved(page))
+ return false;
+
+ if (page_count(page) > 0)
+ return false;
+
+ if (PageHuge(page))
+ return false;
+ }
+ return true;
+}
+
+static struct page *alloc_gigantic_page(nodemask_t *nodemask,
+ int nid, gfp_t gfp_mask, int order)
+{
+ struct zonelist *zonelist;
+ struct zone *zone;
+ struct zoneref *z;
+ enum zone_type zonesel;
+ unsigned long ret, pfn, flags, nr_pages;
+
+ nr_pages = 1UL << order;
+ zonesel = gfp_zone(gfp_mask);
+ zonelist = node_zonelist(nid, gfp_mask);
+ for_each_zone_zonelist_nodemask(zone, z, zonelist, zonesel, nodemask) {
+ spin_lock_irqsave(&zone->lock, flags);
+ pfn = ALIGN(zone->zone_start_pfn, nr_pages);
+ while (zone_spans_pfn(zone, pfn + nr_pages - 1)) {
+ if (pfn_range_valid(zone, pfn, nr_pages)) {
+ spin_unlock_irqrestore(&zone->lock, flags);
+ ret = alloc_contig_range(pfn, pfn + nr_pages,
+ MIGRATE_MOVABLE,
+ gfp_mask);
+ if (!ret)
+ return pfn_to_page(pfn);
+ spin_lock_irqsave(&zone->lock, flags);
+ }
+ pfn += nr_pages;
+ }
+ spin_unlock_irqrestore(&zone->lock, flags);
+ }
+ return NULL;
+}
+
+static struct page *alloc_mapped_page(void)
+{
+ gfp_t gfp_mask = GFP_KERNEL | __GFP_ZERO;
+ struct page *page = NULL;
+
+ page = alloc_gigantic_page(&node_states[N_MEMORY], first_memory_node,
+ gfp_mask, get_order(PUD_SIZE));
+ if (page) {
+ pud_aligned = true;
+ return page;
+ }
+ return alloc_pages(gfp_mask, get_order(PMD_SIZE));
+}
+
+static void free_mapped_page(struct page *page)
+{
+ if (pud_aligned) {
+ unsigned long pfn = page_to_pfn(page);
+
+ free_contig_range(pfn, 1ULL << get_order(PUD_SIZE));
+ return;
+ }
+ free_pages((unsigned long)page_address(page), get_order(PMD_SIZE));
+}
+
+static int __init arch_pgtable_tests_init(void)
+{
+ struct mm_struct *mm;
+ struct page *page;
+ pgd_t *pgdp;
+ p4d_t *p4dp, *saved_p4dp;
+ pud_t *pudp, *saved_pudp;
+ pmd_t *pmdp, *saved_pmdp;
+ pte_t *ptep, *saved_ptep;
+ pgprot_t prot = vm_get_page_prot(VMA_TEST_FLAGS);
+ unsigned long vaddr = VADDR_TEST;
+
+ mm = mm_alloc();
+ if (!mm) {
+ pr_err("mm_struct allocation failed\n");
+ return 1;
+ }
+
+ page = alloc_mapped_page();
+ if (!page) {
+ pr_err("memory allocation failed\n");
+ return 1;
+ }
+
+ pgdp = pgd_offset(mm, vaddr);
+ p4dp = p4d_alloc(mm, pgdp, vaddr);
+ pudp = pud_alloc(mm, p4dp, vaddr);
+ pmdp = pmd_alloc(mm, pudp, vaddr);
+ ptep = pte_alloc_map(mm, pmdp, vaddr);
+
+ /*
+ * Save all the page table page addresses as the page table
+ * entries will be used for testing with random or garbage
+ * values. These saved addresses will be used for freeing
+ * page table pages.
+ */
+ saved_p4dp = p4d_offset(pgdp, 0UL);
+ saved_pudp = pud_offset(p4dp, 0UL);
+ saved_pmdp = pmd_offset(pudp, 0UL);
+ saved_ptep = pte_offset_map(pmdp, 0UL);
+
+ pte_basic_tests(page, prot);
+ pmd_basic_tests(page, prot);
+ pud_basic_tests(page, prot);
+ p4d_basic_tests(page, prot);
+ pgd_basic_tests(page, prot);
+
+ pte_clear_tests(ptep);
+ pmd_clear_tests(pmdp);
+ pud_clear_tests(pudp);
+ p4d_clear_tests(p4dp);
+ pgd_clear_tests(pgdp);
+
+ pmd_populate_tests(mm, pmdp, (pgtable_t) page);
+ pud_populate_tests(mm, pudp, pmdp);
+ p4d_populate_tests(mm, p4dp, pudp);
+ pgd_populate_tests(mm, pgdp, p4dp);
+
+ p4d_free(mm, saved_p4dp);
+ pud_free(mm, saved_pudp);
+ pmd_free(mm, saved_pmdp);
+ pte_free(mm, (pgtable_t) virt_to_page(saved_ptep));
+
+ mm_dec_nr_puds(mm);
+ mm_dec_nr_pmds(mm);
+ mm_dec_nr_ptes(mm);
+ __mmdrop(mm);
+
+ free_mapped_page(page);
+ return 0;
+}
+
+static void __exit arch_pgtable_tests_exit(void) { }
+
+module_init(arch_pgtable_tests_init);
+module_exit(arch_pgtable_tests_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Anshuman Khandual <anshuman.khandual@arm.com>");
+MODULE_DESCRIPTION("Test archicture page table helpers");
--
2.20.1
^ permalink raw reply related
* [RFC V2 0/1] mm/debug: Add tests for architecture exported page table helpers
From: Anshuman Khandual @ 2019-08-09 7:33 UTC (permalink / raw)
To: linux-mm
Cc: Mark Rutland, linux-ia64, linux-sh, Peter Zijlstra, James Hogan,
Tetsuo Handa, Heiko Carstens, Michal Hocko, Dave Hansen,
Paul Mackerras, sparclinux, Thomas Gleixner, linux-s390, x86,
Russell King - ARM Linux, Matthew Wilcox, Steven Price,
Jason Gunthorpe, linux-arm-kernel, linux-snps-arc, Kees Cook,
Anshuman Khandual, Masahiro Yamada, Mark Brown, Dan Williams,
Vlastimil Babka, Sri Krishna chowdary, Ard Biesheuvel,
Greg Kroah-Hartman, linux-mips, Ralf Baechle, linux-kernel,
Paul Burton, Mike Rapoport, Vineet Gupta, Martin Schwidefsky,
Andrew Morton, linuxppc-dev, David S. Miller
This series adds a test validation for architecture exported page table
helpers. Patch in the series adds basic transformation tests at various
levels of the page table.
This test was originally suggested by Catalin during arm64 THP migration
RFC discussion earlier. Going forward it can include more specific tests
with respect to various generic MM functions like THP, HugeTLB etc and
platform specific tests.
https://lore.kernel.org/linux-mm/20190628102003.GA56463@arrakis.emea.arm.com/
Questions:
Should alloc_gigantic_page() be made available as an interface for general
use in the kernel. The test module here uses very similar implementation from
HugeTLB to allocate a PUD aligned memory block. Similar for mm_alloc() which
needs to be exported through a header.
Testing:
Build and boot tested on arm64 and x86 platforms. While arm64 clears all
these tests, following errors were reported on x86.
1. WARN_ON(pud_bad(pud)) in pud_populate_tests()
2. WARN_ON(p4d_bad(p4d)) in p4d_populate_tests()
I would really appreciate if folks can help validate this test on other
platforms and report back problems if any. Suggestions, comments and
inputs welcome. Thank you.
Changes in V2:
- Moved test module and it's config from lib/ to mm/
- Renamed config TEST_ARCH_PGTABLE as DEBUG_ARCH_PGTABLE_TEST
- Renamed file from test_arch_pgtable.c to arch_pgtable_test.c
- Added relevant MODULE_DESCRIPTION() and MODULE_AUTHOR() details
- Dropped loadable module config option
- Basic tests now use memory blocks with required size and alignment
- PUD aligned memory block gets allocated with alloc_contig_range()
- If PUD aligned memory could not be allocated it falls back on PMD aligned
memory block from page allocator and pud_* tests are skipped
- Clear and populate tests now operate on real in memory page table entries
- Dummy mm_struct gets allocated with mm_alloc()
- Dummy page table entries get allocated with [pud|pmd|pte]_alloc_[map]()
- Simplified [p4d|pgd]_basic_tests(), now has random values in the entries
RFC V1:
https://lore.kernel.org/linux-mm/1564037723-26676-1-git-send-email-anshuman.khandual@arm.com/
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Mike Rapoport <rppt@linux.vnet.ibm.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: Steven Price <Steven.Price@arm.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Sri Krishna chowdary <schowdary@nvidia.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Russell King - ARM Linux <linux@armlinux.org.uk>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Vineet Gupta <vgupta@synopsys.com>
Cc: James Hogan <jhogan@kernel.org>
Cc: Paul Burton <paul.burton@mips.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-snps-arc@lists.infradead.org
Cc: linux-mips@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-ia64@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-s390@vger.kernel.org
Cc: linux-sh@vger.kernel.org
Cc: sparclinux@vger.kernel.org
Cc: x86@kernel.org
Cc: linux-kernel@vger.kernel.org
Anshuman Khandual (1):
mm/pgtable/debug: Add test validating architecture page table helpers
mm/Kconfig.debug | 14 ++
mm/Makefile | 1 +
mm/arch_pgtable_test.c | 400 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 415 insertions(+)
create mode 100644 mm/arch_pgtable_test.c
--
2.20.1
^ permalink raw reply
* Re: [PATCH 8/8] dma-mapping: remove CONFIG_ARCH_NO_COHERENT_DMA_MMAP
From: Geert Uytterhoeven @ 2019-08-09 7:21 UTC (permalink / raw)
To: Christoph Hellwig
Cc: linux-xtensa, Michal Simek, Vladimir Murzin, Parisc List,
Linux-sh list, Takashi Iwai, linuxppc-dev, Helge Deller,
the arch/x86 maintainers, linux-m68k, Linux Kernel Mailing List,
Linux IOMMU, Robin Murphy, Linux ARM, Marek Szyprowski
In-Reply-To: <20190808160005.10325-9-hch@lst.de>
Hi Christoph,
On Thu, Aug 8, 2019 at 6:01 PM Christoph Hellwig <hch@lst.de> wrote:
> CONFIG_ARCH_NO_COHERENT_DMA_MMAP is now functionally identical to
> !CONFIG_MMU, so remove the separate symbol. The only difference is that
> arm did not set it for !CONFIG_MMU, but arm uses a separate dma mapping
> implementation including its own mmap method, which is handled by moving
> the CONFIG_MMU check in dma_can_mmap so that is only applies to the
> dma-direct case, just as the other ifdefs for it.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> arch/m68k/Kconfig | 1 -
For m68k:
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [Bug 204479] KASAN hit at modprobe zram
From: bugzilla-daemon @ 2019-08-09 5:38 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <bug-204479-206035@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=204479
--- Comment #9 from Christophe Leroy (christophe.leroy@c-s.fr) ---
The module loads seems to be nested. It might then be an SMP issue,
kasan_init_region() is most likely not SMP safe.
Could you test without CONFIG_SMP or with only one CPU ?
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply
* [Bug 204479] KASAN hit at modprobe zram
From: bugzilla-daemon @ 2019-08-09 5:34 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <bug-204479-206035@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=204479
--- Comment #8 from Christophe Leroy (christophe.leroy@c-s.fr) ---
List of allocated areas with associated kasan shadow area in [ ], together with
the addresses when shadow initialisation fails:
Aug 08 23:39:58 T600 kernel: ###### module_alloc(c78c) = f1470000
[fe28e000-fe28f8f1]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(36f8) = f147e000
[fe28fc00-fe2902df]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(c78c) = f1483000
[fe290600-fe291ef1]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(c78c) = f1491000
[fe292200-fe293af1]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(36f8) = f1502000
[fe2a0400-fe2a0adf]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(1521) = f1013000
[fe202600-fe2028a4]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(13bc5) = f103d000
[fe207a00-fe20a178]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(1357) = f1027000
[fe204e00-fe20506a]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(36f8) = f102a000
[fe205400-fe205adf]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(4301) = f102f000
[fe205e00-fe206660]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(4718) = f1065000
[fe20ca00-fe20d2e3]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(19ac) = f1076000
[fe20ec00-fe20ef35]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(4718) = f129d000
[fe253a00-fe2542e3]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(16ca) = f102a000
[fe205400-fe2056d9]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(1f81) = f1079000
[fe20f200-fe20f5f0]
Aug 08 23:39:58 T600 kernel: ###### module_alloc(1f81) = f1027000
[fe204e00-fe2051f0]
Aug 08 23:39:59 T600 kernel: BUG: Unable to handle kernel data access at
0xfe20d040
Aug 08 23:39:59 T600 kernel: ###### module_alloc(185ef) = f12d0000
[fe25a000-fe25d0bd]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(4035) = f106b000
[fe20d600-fe20de06]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(6196) = f12b3000
[fe256600-fe257232]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(1d27) = f1071000
[fe20e200-fe20e5a4]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(4035) = f102d000
[fe205a00-fe206206]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(a11b) = f13ad000
[fe275a00-fe276e23]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(4035) = f12b3000
[fe256600-fe256e06]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(4035) = f12ea000
[fe25d400-fe25dc06]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(1d27) = f1033000
[fe206600-fe2069a4]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(4035) = f1397000
[fe272e00-fe273606]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(307a) = f12f0000
[fe25e000-fe25e60f]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(1d27) = f1062000
[fe20c400-fe20c7a4]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(1d27) = f12f7000
[fe25ee00-fe25f1a4]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(1d27) = f12fd000
[fe25fa00-fe25fda4]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(d102) = f1429000
[fe285200-fe286c20]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(2a37) = f1033000
[fe206600-fe206b46]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(4718) = f106b000
[fe20d600-fe20dee3]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(9a3f2) = f1db8000
[fe3b7000-fe3ca47e]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(18571) = f13cd000
[fe279a00-fe27caae]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(1f81) = f1071000
[fe20e200-fe20e5f0]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(1fdb9) = f1438000
[fe287000-fe28afb7]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(56a49) = f1e54000
[fe3ca800-fe3d5549]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(56a49) = f1eac000
[fe3d5800-fe3e0549]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(56a49) = f1f04000
[fe3e0800-fe3eb549]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(7c61) = f12ea000
[fe25d400-fe25e38c]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(e011) = f140c000
[fe281800-fe283402]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(56a49) = f1f5c000
[fe3eb800-fe3f6549]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(56a49) = f1fb4000
[fe3f6800-fe401549]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(e011) = f1459000
[fe28b200-fe28ce02]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(e011) = f147e000
[fe28fc00-fe291802]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(2561) = f1033000
[fe206600-fe206aac]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(6ae1) = f12b3000
[fe256600-fe25735c]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(e011) = f148e000
[fe291c00-fe293802]
Aug 08 23:39:59 T600 kernel: ###### module_alloc(e011) = f200c000
[fe401800-fe403402]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(3355) = f1397000
[fe272e00-fe27346a]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(1c8f) = f12f7000
[fe25ee00-fe25f191]
Aug 08 23:40:00 T600 kernel: BUG: Unable to handle kernel data access at
0xfe2731a0
Aug 08 23:40:00 T600 kernel: ###### module_alloc(1c078) = f13cd000
[fe279a00-fe27d20f]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(12f27) = f13eb000
[fe27d600-fe27fbe4]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(12f27) = f13ff000
[fe27fe00-fe2823e4]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(12f27) = f1413000
[fe282600-fe284be4]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(12f27) = f1459000
[fe28b200-fe28d7e4]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(601c) = f12b3000
[fe256600-fe257203]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(3716) = f147e000
[fe28fc00-fe2902e2]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(3716) = f1483000
[fe290600-fe290ce2]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(3716) = f1488000
[fe291000-fe2916e2]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(3716) = f148d000
[fe291a00-fe2920e2]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(12f27) = f1647000
[fe2c8e00-fe2cb3e4]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(1b7a) = f1033000
[fe206600-fe20696f]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(3716) = f165b000
[fe2cb600-fe2cbce2]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(15f7) = f12fd000
[fe25fa00-fe25fcbe]
Aug 08 23:40:00 T600 kernel: ###### module_alloc(fe69) = f13ff000
[fe27fe00-fe281dcd]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(fe69) = f1410000
[fe282000-fe283fcd]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(fe69) = f1459000
[fe28b200-fe28d1cd]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(fe69) = f147e000
[fe28fc00-fe291bcd]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(3087) = f12b3000
[fe256600-fe256c10]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(3087) = f1421000
[fe284200-fe284810]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(3087) = f146a000
[fe28d400-fe28da10]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(2d72) = f1592000
[fe2b2400-fe2b29ae]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(1c09) = f12b8000
[fe257000-fe257381]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(1e4d) = f12fd000
[fe25fa00-fe25fdc9]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(3087) = f1596000
[fe2b2c00-fe2b3210]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(1562) = f1426000
[fe284c00-fe284eac]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(2d72) = f15ab000
[fe2b5600-fe2b5bae]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(24c2) = f15bc000
[fe2b7800-fe2b7c98]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(2d72) = f12b3000
[fe256600-fe256bae]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(2d72) = f1420000
[fe284000-fe2845ae]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(1c09) = f1424000
[fe284800-fe284b81]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(15b9) = f1469000
[fe28d200-fe28d4b7]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(1c09) = f146c000
[fe28d800-fe28db81]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(1c09) = f147e000
[fe28fc00-fe28ff81]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(2d72) = f1491000
[fe292200-fe2927ae]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(1c09) = f1495000
[fe292a00-fe292d81]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(2068) = f1498000
[fe293000-fe29340d]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(13c0) = f1469000
[fe28d200-fe28d478]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(3f159) = f149c000
[fe293800-fe29b62b]
Aug 08 23:40:01 T600 kernel: ###### module_alloc(d8e5) = f14dd000
[fe29ba00-fe29d51c]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(4ed5) = f1500000
[fe2a0000-fe2a09da]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(2843) = f12b3000
[fe256600-fe256b08]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(2843) = f12b7000
[fe256e00-fe257308]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(2843) = f141e000
[fe283c00-fe284108]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(2584) = f1422000
[fe284400-fe2848b0]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(1be5) = f1426000
[fe284c00-fe284f7c]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(1be5) = f1467000
[fe28ce00-fe28d17c]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(2843) = f146a000
[fe28d400-fe28d908]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(1be5) = f147e000
[fe28fc00-fe28ff7c]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(1be5) = f1491000
[fe292200-fe29257c]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(3921) = f1523000
[fe2a4600-fe2a4d24]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(199d) = f1410000
[fe282000-fe282333]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(9d3b) = f1412000
[fe282400-fe2837a7]
Aug 08 23:40:02 T600 kernel: ###### module_alloc(2bfc) = f1422000
[fe284400-fe28497f]
Aug 08 23:40:03 T600 kernel: ###### module_alloc(19a6) = f1422000
[fe284400-fe284734]
Aug 08 23:40:03 T600 kernel: ###### module_alloc(5215) = f1514000
[fe2a2800-fe2a3242]
Aug 08 23:40:03 T600 kernel: ###### module_alloc(1524) = f148b000
[fe291600-fe2918a4]
Aug 08 23:40:03 T600 kernel: ###### module_alloc(1d62) = f148e000
[fe291c00-fe291fac]
Aug 08 23:40:03 T600 kernel: ###### module_alloc(bf4f) = f1596000
[fe2b2c00-fe2b43e9]
Aug 08 23:40:03 T600 kernel: ###### module_alloc(19bf4) = f15f7000
[fe2bee00-fe2c217e]
Aug 08 23:40:03 T600 kernel: ###### module_alloc(2851) = f1481000
[fe290200-fe29070a]
Aug 08 23:40:03 T600 kernel: ###### module_alloc(52fd) = f1485000
[fe290a00-fe29145f]
Aug 08 23:40:04 T600 kernel: BUG: Unable to handle kernel data access at
0xfe2b40dc
Aug 08 23:40:04 T600 kernel: ###### module_alloc(f30b) = f14eb000
[fe29d600-fe29f461]
Aug 08 23:40:04 T600 kernel: ###### module_alloc(2d9d) = f1485000
[fe290a00-fe290fb3]
Aug 08 23:40:04 T600 kernel: BUG: Unable to handle kernel data access at
0xfe29f0b0
Aug 08 23:40:05 T600 kernel: ###### module_alloc(3f9d) = f1489000
[fe291200-fe2919f3]
Aug 08 23:40:05 T600 kernel: ###### module_alloc(1e82) = f148e000
[fe291c00-fe291fd0]
Aug 08 23:40:05 T600 kernel: ###### module_alloc(666f) = f151b000
[fe2a3600-fe2a42cd]
Aug 08 23:40:05 T600 kernel: ###### module_alloc(264d) = f14fc000
[fe29f800-fe29fcc9]
Aug 08 23:40:06 T600 kernel: ###### module_alloc(180d) = f12b3000
[fe256600-fe256901]
Aug 08 23:40:06 T600 kernel: ###### module_alloc(13fa) = f141d000
[fe283a00-fe283c7f]
Aug 08 23:40:06 T600 kernel: ###### module_alloc(74a8) = f1459000
[fe28b200-fe28c095]
Aug 08 23:40:06 T600 kernel: ###### module_alloc(2cc6) = f141d000
[fe283a00-fe283f98]
Aug 08 23:40:07 T600 kernel: ###### module_alloc(eeb18) = f19ee000
[fe33dc00-fe35b963]
Aug 08 23:40:07 T600 kernel: ###### module_alloc(2f546) = f1528000
[fe2a5000-fe2aaea8]
Aug 08 23:40:07 T600 kernel: ###### module_alloc(37fed) = f1559000
[fe2ab200-fe2b21fd]
Aug 08 23:40:07 T600 kernel: ###### module_alloc(37fed) = f1c94000
[fe392800-fe3997fd]
Aug 08 23:40:07 T600 kernel: ###### module_alloc(37fed) = f1ccd000
[fe399a00-fe3a09fd]
Aug 08 23:40:07 T600 kernel: ###### module_alloc(4fa5) = f1462000
[fe28c400-fe28cdf4]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(4fa5) = f1468000
[fe28d000-fe28d9f4]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(4fa5) = f148e000
[fe291c00-fe2925f4]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(37fed) = f1e54000
[fe3ca800-fe3d17fd]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(4fa5) = f14dd000
[fe29ba00-fe29c3f4]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(114e6) = f15a3000
[fe2b4600-fe2b689c]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(114e6) = f15c0000
[fe2b8000-fe2ba29c]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(114e6) = f15d3000
[fe2ba600-fe2bc89c]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(3afc) = f141d000
[fe283a00-fe28415f]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(3afc) = f1462000
[fe28c400-fe28cb5f]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(114e6) = f16de000
[fe2dbc00-fe2dde9c]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(3afc) = f1467000
[fe28ce00-fe28d55f]
Aug 08 23:40:08 T600 kernel: ###### module_alloc(3afc) = f148e000
[fe291c00-fe29235f]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(1bde) = f141d000
[fe283a00-fe283d7b]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(16f8) = f146d000
[fe28da00-fe28dcdf]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(1bde) = f147e000
[fe28fc00-fe28ff7b]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(1bde) = f148e000
[fe291c00-fe291f7b]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(1bde) = f1491000
[fe292200-fe29257b]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(16f8) = f14e8000
[fe29d000-fe29d2df]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(16f8) = f14fc000
[fe29f800-fe29fadf]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(16f8) = f1511000
[fe2a2200-fe2a24df]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(105dd6) = f1612000
[fe2c2400-fe2e2fba]
Aug 08 23:40:09 T600 kernel: ###### module_alloc(2b1fa) = f1719000
[fe2e3200-fe2e883f]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(35b8) = f1466000
[fe28cc00-fe28d2b7]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(2006) = f1554000
[fe2aa800-fe2aac00]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(2c633) = f1528000
[fe2a5000-fe2aa8c6]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(5c9d) = f14dd000
[fe29ba00-fe29c593]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(571d) = f14e4000
[fe29c800-fe29d2e3]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(571d) = f1506000
[fe2a0c00-fe2a16e3]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(571d) = f150d000
[fe2a1a00-fe2a24e3]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(22af) = f1462000
[fe28c400-fe28c855]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(22af) = f146b000
[fe28d600-fe28da55]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(2946) = f148e000
[fe291c00-fe292128]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(22af) = f14fc000
[fe29f800-fe29fc55]
Aug 08 23:40:10 T600 kernel: ###### module_alloc(18bc) = f147e000
[fe28fc00-fe28ff17]
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply
* Re: [PATCH v3 38/41] powerpc: convert put_page() to put_user_page*()
From: John Hubbard @ 2019-08-09 1:26 UTC (permalink / raw)
To: Michael Ellerman, Andrew Morton
Cc: linux-fbdev, Jan Kara, kvm, Dave Hansen, Dave Chinner, dri-devel,
linux-mm, sparclinux, Ira Weiny, ceph-devel, devel, rds-devel,
linux-rdma, x86, amd-gfx, Christoph Hellwig, Christoph Hellwig,
Jason Gunthorpe, xen-devel, devel, linux-media, intel-gfx,
linux-block, Jérôme Glisse, linux-rpi-kernel,
Dan Williams, linux-arm-kernel, linux-nfs, netdev, LKML,
linux-xfs, linux-crypto, linux-fsdevel, linuxppc-dev
In-Reply-To: <87k1botdpx.fsf@concordia.ellerman.id.au>
On 8/7/19 10:42 PM, Michael Ellerman wrote:
> Hi John,
>
> john.hubbard@gmail.com writes:
>> diff --git a/arch/powerpc/mm/book3s64/iommu_api.c b/arch/powerpc/mm/book3s64/iommu_api.c
>> index b056cae3388b..e126193ba295 100644
>> --- a/arch/powerpc/mm/book3s64/iommu_api.c
>> +++ b/arch/powerpc/mm/book3s64/iommu_api.c
>> @@ -203,6 +202,7 @@ static void mm_iommu_unpin(struct mm_iommu_table_group_mem_t *mem)
>> {
>> long i;
>> struct page *page = NULL;
>> + bool dirty = false;
>
> I don't think you need that initialisation do you?
>
Nope, it can go. Fixed locally, thanks.
Did you get a chance to look at enough of the other bits to feel comfortable
with the patch, overall?
thanks,
--
John Hubbard
NVIDIA
^ permalink raw reply
* [PATCH 2/2] powerpc: Convert flush_icache_range to C
From: Alastair D'Silva @ 2019-08-09 0:46 UTC (permalink / raw)
To: alastair
Cc: linux-kernel, Paul Mackerras, Greg Kroah-Hartman, Qian Cai,
Thomas Gleixner, linuxppc-dev, Allison Randal
From: Alastair D'Silva <alastair@d-silva.org>
Similar to commit 22e9c88d486a
("powerpc/64: reuse PPC32 static inline flush_dcache_range()")
this patch converts flush_icache_range to C.
This was done as we discovered a long-standing bug where the
length of the range was truncated due to using a 32 bit shift
instead of a 64 bit one.
By converting this function to C, it becomes easier to maintain.
Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
---
arch/powerpc/include/asm/cache.h | 35 +++++++++++++--
arch/powerpc/include/asm/cacheflush.h | 63 +++++++++++++++++++++++----
arch/powerpc/kernel/misc_64.S | 55 -----------------------
3 files changed, 85 insertions(+), 68 deletions(-)
diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
index b3388d95f451..d3d7077b75e2 100644
--- a/arch/powerpc/include/asm/cache.h
+++ b/arch/powerpc/include/asm/cache.h
@@ -55,25 +55,46 @@ struct ppc64_caches {
extern struct ppc64_caches ppc64_caches;
-static inline u32 l1_cache_shift(void)
+static inline u32 l1_dcache_shift(void)
{
return ppc64_caches.l1d.log_block_size;
}
-static inline u32 l1_cache_bytes(void)
+static inline u32 l1_dcache_bytes(void)
{
return ppc64_caches.l1d.block_size;
}
+
+static inline u32 l1_icache_shift(void)
+{
+ return ppc64_caches.l1i.log_block_size;
+}
+
+static inline u32 l1_icache_bytes(void)
+{
+ return ppc64_caches.l1i.block_size;
+}
#else
-static inline u32 l1_cache_shift(void)
+static inline u32 l1_dcache_shift(void)
{
return L1_CACHE_SHIFT;
}
-static inline u32 l1_cache_bytes(void)
+static inline u32 l1_dcache_bytes(void)
{
return L1_CACHE_BYTES;
}
+
+static inline u32 l1_icache_shift(void)
+{
+ return L1_CACHE_SHIFT;
+}
+
+static inline u32 l1_icache_bytes(void)
+{
+ return L1_CACHE_BYTES;
+}
+
#endif
#endif /* ! __ASSEMBLY__ */
@@ -124,6 +145,12 @@ static inline void dcbst(void *addr)
{
__asm__ __volatile__ ("dcbst %y0" : : "Z"(*(u8 *)addr) : "memory");
}
+
+static inline void icbi(void *addr)
+{
+ __asm__ __volatile__ ("icbi %y0" : : "Z"(*(u8 *)addr) : "memory");
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_CACHE_H */
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index eef388f2659f..f68e75a6dc4b 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -42,7 +42,6 @@ extern void flush_dcache_page(struct page *page);
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
-extern void flush_icache_range(unsigned long, unsigned long);
extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long addr,
int len);
@@ -57,14 +56,17 @@ static inline void __flush_dcache_icache_phys(unsigned long physaddr)
}
#endif
-/*
- * Write any modified data cache blocks out to memory and invalidate them.
+/**
+ * flush_dcache_range: Write any modified data cache blocks out to memory and invalidate them.
* Does not invalidate the corresponding instruction cache blocks.
+ *
+ * @start: the start address
+ * @stop: the stop address (exclusive)
*/
static inline void flush_dcache_range(unsigned long start, unsigned long stop)
{
- unsigned long shift = l1_cache_shift();
- unsigned long bytes = l1_cache_bytes();
+ unsigned long shift = l1_dcache_shift();
+ unsigned long bytes = l1_dcache_bytes();
void *addr = (void *)(start & ~(bytes - 1));
unsigned long size = stop - (unsigned long)addr + (bytes - 1);
unsigned long i;
@@ -82,6 +84,49 @@ static inline void flush_dcache_range(unsigned long start, unsigned long stop)
isync();
}
+/**
+ * flush_icache_range: Write any modified data cache blocks out to memory
+ * and invalidate the corresponding blocks in the instruction cache
+ *
+ * Generic code will call this after writing memory, before executing from it.
+ *
+ * @start: the start address
+ * @stop: the stop address (exclusive)
+ */
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+ unsigned long shift = l1_dcache_shift();
+ unsigned long bytes = l1_dcache_bytes();
+ void *addr = (void *)(start & ~(bytes - 1));
+ unsigned long size = stop - (unsigned long)addr + (bytes - 1);
+ unsigned long i;
+
+ if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
+ mb(); /* sync */
+ icbi((void *)start);
+ mb(); /* sync */
+ isync();
+ return;
+ }
+
+ /* Flush the data cache to memory */
+ for (i = 0; i < size >> shift; i++, addr += bytes)
+ dcbst(addr);
+
+ mb(); /* sync */
+
+ shift = l1_icache_shift();
+ bytes = l1_icache_bytes();
+ addr = (void *)(start & ~(bytes - 1));
+ size = stop - (unsigned long)addr + (bytes - 1);
+
+ /* Now invalidate the instruction cache */
+ for (i = 0; i < size >> shift; i++, addr += bytes)
+ icbi(addr);
+
+ isync();
+}
+
/*
* Write any modified data cache blocks out to memory.
* Does not invalidate the corresponding cache lines (especially for
@@ -89,8 +134,8 @@ static inline void flush_dcache_range(unsigned long start, unsigned long stop)
*/
static inline void clean_dcache_range(unsigned long start, unsigned long stop)
{
- unsigned long shift = l1_cache_shift();
- unsigned long bytes = l1_cache_bytes();
+ unsigned long shift = l1_dcache_shift();
+ unsigned long bytes = l1_dcache_bytes();
void *addr = (void *)(start & ~(bytes - 1));
unsigned long size = stop - (unsigned long)addr + (bytes - 1);
unsigned long i;
@@ -108,8 +153,8 @@ static inline void clean_dcache_range(unsigned long start, unsigned long stop)
static inline void invalidate_dcache_range(unsigned long start,
unsigned long stop)
{
- unsigned long shift = l1_cache_shift();
- unsigned long bytes = l1_cache_bytes();
+ unsigned long shift = l1_dcache_shift();
+ unsigned long bytes = l1_dcache_bytes();
void *addr = (void *)(start & ~(bytes - 1));
unsigned long size = stop - (unsigned long)addr + (bytes - 1);
unsigned long i;
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 9bc0aa9aeb65..999828e86bba 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -54,61 +54,6 @@ PPC64_CACHES:
.tc ppc64_caches[TC],ppc64_caches
.section ".text"
-/*
- * Write any modified data cache blocks out to memory
- * and invalidate the corresponding instruction cache blocks.
- *
- * flush_icache_range(unsigned long start, unsigned long stop)
- *
- * flush all bytes from start through stop-1 inclusive
- */
-
-_GLOBAL_TOC(flush_icache_range)
-BEGIN_FTR_SECTION
- PURGE_PREFETCHED_INS
- blr
-END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-/*
- * Flush the data cache to memory
- *
- * Different systems have different cache line sizes
- * and in some cases i-cache and d-cache line sizes differ from
- * each other.
- */
- ld r10,PPC64_CACHES@toc(r2)
- lwz r7,DCACHEL1BLOCKSIZE(r10)/* Get cache block size */
- addi r5,r7,-1
- andc r6,r3,r5 /* round low to line bdy */
- subf r8,r6,r4 /* compute length */
- add r8,r8,r5 /* ensure we get enough */
- lwz r9,DCACHEL1LOGBLOCKSIZE(r10) /* Get log-2 of cache block size */
- srd. r8,r8,r9 /* compute line count */
- beqlr /* nothing to do? */
- mtctr r8
-1: dcbst 0,r6
- add r6,r6,r7
- bdnz 1b
- sync
-
-/* Now invalidate the instruction cache */
-
- lwz r7,ICACHEL1BLOCKSIZE(r10) /* Get Icache block size */
- addi r5,r7,-1
- andc r6,r3,r5 /* round low to line bdy */
- subf r8,r6,r4 /* compute length */
- add r8,r8,r5
- lwz r9,ICACHEL1LOGBLOCKSIZE(r10) /* Get log-2 of Icache block size */
- srd. r8,r8,r9 /* compute line count */
- beqlr /* nothing to do? */
- mtctr r8
-2: icbi 0,r6
- add r6,r6,r7
- bdnz 2b
- isync
- blr
-_ASM_NOKPROBE_SYMBOL(flush_icache_range)
-EXPORT_SYMBOL(flush_icache_range)
-
/*
* Flush a particular page from the data cache to RAM.
* Note: this is necessary because the instruction cache does *not*
--
2.21.0
^ permalink raw reply related
* [PATCH 1/2] powerpc: Allow flush_icache_range to work across ranges >4GB
From: Alastair D'Silva @ 2019-08-09 0:45 UTC (permalink / raw)
To: alastair
Cc: linux-kernel, stable, Paul Mackerras, Greg Kroah-Hartman,
Thomas Gleixner, linuxppc-dev
From: Alastair D'Silva <alastair@d-silva.org>
When calling flush_icache_range with a size >4GB, we were masking
off the upper 32 bits, so we would incorrectly flush a range smaller
than intended.
This patch replaces the 32 bit shifts with 64 bit ones, so that
the full size is accounted for.
Heads-up for backporters: the old version of flush_dcache_range is
subject to a similar bug (this has since been replaced with a C
implementation).
Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
---
arch/powerpc/kernel/misc_64.S | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index b55a7b4cb543..9bc0aa9aeb65 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -82,7 +82,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
subf r8,r6,r4 /* compute length */
add r8,r8,r5 /* ensure we get enough */
lwz r9,DCACHEL1LOGBLOCKSIZE(r10) /* Get log-2 of cache block size */
- srw. r8,r8,r9 /* compute line count */
+ srd. r8,r8,r9 /* compute line count */
beqlr /* nothing to do? */
mtctr r8
1: dcbst 0,r6
@@ -98,7 +98,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
subf r8,r6,r4 /* compute length */
add r8,r8,r5
lwz r9,ICACHEL1LOGBLOCKSIZE(r10) /* Get log-2 of Icache block size */
- srw. r8,r8,r9 /* compute line count */
+ srd. r8,r8,r9 /* compute line count */
beqlr /* nothing to do? */
mtctr r8
2: icbi 0,r6
--
2.21.0
^ permalink raw reply related
* [Bug 204375] kernel 5.2.4 w. KASAN enabled fails to boot on a PowerMac G4 3,6 at very early stage
From: bugzilla-daemon @ 2019-08-08 22:04 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <bug-204375-206035@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=204375
Erhard F. (erhard_f@mailbox.org) changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|NEW |RESOLVED
Resolution|--- |CODE_FIX
--- Comment #15 from Erhard F. (erhard_f@mailbox.org) ---
The fix landed succesfully in 5.2.7 and I can confirm it works on my G4 now.
Thanks!
--
You are receiving this mail because:
You are watching the assignee of the bug.
^ permalink raw reply
* [Bug 204479] KASAN hit at modprobe zram
From: bugzilla-daemon @ 2019-08-08 21:58 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <bug-204479-206035@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=204479
Erhard F. (erhard_f@mailbox.org) changed:
What |Removed |Added
----------------------------------------------------------------------------
Attachment #284175|0 |1
is obsolete| |
--- Comment #7 from Erhard F. (erhard_f@mailbox.org) ---
Created attachment 284273
--> https://bugzilla.kernel.org/attachment.cgi?id=284273&action=edit
dmesg (kernel 5.3-rc3 + patch, PowerMac G4 DP)
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply
* [Bug 204479] KASAN hit at modprobe zram
From: bugzilla-daemon @ 2019-08-08 21:57 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <bug-204479-206035@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=204479
--- Comment #6 from Erhard F. (erhard_f@mailbox.org) ---
(In reply to Christophe Leroy from comment #4)
> We need to identify if the allocation of KASAN shadow area at module
> allocation fails, or if kasan accesses outside of the allocated area.
>
> Could you please run again with the below trace:
The patch did not apply to the mainstream kernnel with 'patch -p1 < ...' but I
inserted the code manually. Please find the new results attached.
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply
* [Bug 204479] KASAN hit at modprobe zram
From: bugzilla-daemon @ 2019-08-08 21:55 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <bug-204479-206035@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=204479
Erhard F. (erhard_f@mailbox.org) changed:
What |Removed |Added
----------------------------------------------------------------------------
Attachment #284177|0 |1
is obsolete| |
--- Comment #5 from Erhard F. (erhard_f@mailbox.org) ---
Created attachment 284271
--> https://bugzilla.kernel.org/attachment.cgi?id=284271&action=edit
kernel .config (5.3-rc3, PowerMac G4 DP)
--
You are receiving this mail because:
You are on the CC list for the bug.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox