All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nicholas Piggin <npiggin@gmail.com>
To: linuxppc-dev@lists.ozlabs.org
Cc: Nicholas Piggin <npiggin@gmail.com>
Subject: [RFC PATCH 08/10] powerpc/powernv: Set up an mm context to call OPAL in
Date: Sat,  2 May 2020 21:19:12 +1000	[thread overview]
Message-ID: <20200502111914.166578-9-npiggin@gmail.com> (raw)
In-Reply-To: <20200502111914.166578-1-npiggin@gmail.com>

This creates an mm context to be used for OPAL V4 calls, which
is populated with ptes according to querying OPAL_FIND_VM_AREA.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/platforms/powernv/opal-call.c |  21 +++-
 arch/powerpc/platforms/powernv/opal.c      | 119 ++++++++++++++++++++-
 2 files changed, 137 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index e62a74dfb3d0..4bdad3d2fa18 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -104,6 +104,9 @@ typedef int64_t (*opal_v4_le_entry_fn)(uint64_t r3, uint64_t r4, uint64_t r5,
                                uint64_t r6, uint64_t r7, uint64_t r8,
                                uint64_t r9, uint64_t r10);
 
+extern struct mm_struct *opal_mm;
+extern bool opal_mm_enabled;
+
 static int64_t opal_call(int64_t a0, int64_t a1, int64_t a2, int64_t a3,
 	     int64_t a4, int64_t a5, int64_t a6, int64_t a7, int64_t opcode)
 {
@@ -117,6 +120,8 @@ static int64_t opal_call(int64_t a0, int64_t a1, int64_t a2, int64_t a3,
 		fn = (opal_v4_le_entry_fn)(opal.v4_le_entry);
 
 	if (fn) {
+		struct mm_struct *old_mm = current->active_mm;
+
 		if (!mmu) {
 			BUG_ON(msr & MSR_EE);
 			ret = fn(opcode, a0, a1, a2, a3, a4, a5, a6);
@@ -126,11 +131,23 @@ static int64_t opal_call(int64_t a0, int64_t a1, int64_t a2, int64_t a3,
 		local_irq_save(flags);
 		hard_irq_disable(); /* XXX r13 */
 		msr &= ~MSR_EE;
-		mtmsr(msr & ~(MSR_IR|MSR_DR));
+		if (!opal_mm_enabled)
+			mtmsr(msr & ~(MSR_IR|MSR_DR));
+
+		if (opal_mm_enabled && old_mm != opal_mm) {
+			current->active_mm = opal_mm;
+			switch_mm_irqs_off(NULL, opal_mm, current);
+		}
 
 		ret = fn(opcode, a0, a1, a2, a3, a4, a5, a6);
 
-		mtmsr(msr);
+		if (opal_mm_enabled && old_mm != opal_mm) {
+			current->active_mm = old_mm;
+			switch_mm_irqs_off(NULL, old_mm, current);
+		}
+
+		if (!opal_mm_enabled)
+			mtmsr(msr);
 		local_irq_restore(flags);
 
 		return ret;
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index d00772d40680..98d6d7fc5411 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -45,6 +45,10 @@ struct opal_msg_node {
 static DEFINE_SPINLOCK(msg_list_lock);
 static LIST_HEAD(msg_list);
 
+struct mm_struct *opal_mm __read_mostly;
+bool opal_v4_present __read_mostly;
+bool opal_mm_enabled __read_mostly;
+
 /* /sys/firmware/opal */
 struct kobject *opal_kobj __read_mostly;
 
@@ -172,7 +176,12 @@ int __init early_init_dt_scan_opal(unsigned long node,
 
 	if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
 		powerpc_firmware_features |= FW_FEATURE_OPAL;
-		pr_debug("OPAL detected !\n");
+		if (of_flat_dt_is_compatible(node, "ibm,opal-v4")) {
+			opal_v4_present = true;
+			pr_debug("OPAL v4 runtime firmware\n");
+		} else {
+			pr_debug("OPAL detected !\n");
+		}
 	} else {
 		panic("OPAL v3 compatible firmware not detected, can not continue.\n");
 	}
@@ -187,6 +196,9 @@ int __init early_init_dt_scan_opal(unsigned long node,
 
 		pr_debug("OPAL v4 Entry = 0x%llx (v4_le_entryp=%p v4_le_entrysz=%d)\n",
 			 opal.v4_le_entry, v4_le_entryp, v4_le_entrysz);
+	} else {
+		/* Can't use v4 entry */
+		opal_v4_present = false;
 	}
 
 	return 1;
@@ -1033,6 +1045,111 @@ static void opal_init_heartbeat(void)
 		kopald_tsk = kthread_run(kopald, NULL, "kopald");
 }
 
+static pgprot_t opal_vm_flags_to_prot(uint64_t flags)
+{
+	pgprot_t prot;
+
+	BUG_ON(!flags);
+	if (flags & OS_VM_FLAG_EXECUTE) {
+		if (flags & OS_VM_FLAG_CI)
+			BUG();
+		if (flags & OS_VM_FLAG_WRITE)
+			prot = PAGE_KERNEL_X;
+		else
+			prot = PAGE_KERNEL_X /* XXX!? PAGE_KERNEL_ROX */;
+	} else {
+		if (flags & OS_VM_FLAG_WRITE)
+			prot = PAGE_KERNEL;
+		else if (flags & OS_VM_FLAG_READ)
+			prot = PAGE_KERNEL_RO;
+		else
+			BUG();
+		if (flags & OS_VM_FLAG_CI)
+			prot = pgprot_noncached(prot);
+	}
+	return prot;
+}
+
+static int __init opal_init_mm(void)
+{
+	struct mm_struct *mm;
+	unsigned long addr;
+	struct opal_vm_area vm_area;
+
+	mm = copy_init_mm();
+	if (!mm)
+		return -ENOMEM;
+
+	/* Set up initial mappings for OPAL. */
+	addr = 0;
+	while (opal_find_vm_area(addr, &vm_area) == OPAL_SUCCESS) {
+		unsigned long length;
+		unsigned long pa;
+		unsigned long flags;
+		unsigned long end;
+		pgprot_t prot;
+
+		addr = be64_to_cpu(vm_area.address);
+		length = be64_to_cpu(vm_area.length);
+		pa = be64_to_cpu(vm_area.pa);
+		flags = be64_to_cpu(vm_area.vm_flags);
+
+		if (flags == 0) {
+			/* flags == 0 is a special case */
+			BUG_ON(pa != 0);
+		} else {
+			/* Don't support non-linear (yet?) */
+			BUG_ON(addr != pa);
+			prot = opal_vm_flags_to_prot(flags);
+		}
+
+		/* Align to PAGE_SIZE */
+		end = (addr + length + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+		addr &= ~(PAGE_SIZE - 1);
+
+		while (addr < end) {
+			spinlock_t *ptl;
+			pte_t pte, *ptep;
+
+			ptep = get_locked_pte(mm, addr, &ptl);
+			if (flags) {
+				pte = pfn_pte(addr >> PAGE_SHIFT, prot);
+				set_pte_at(mm, addr, ptep, pte);
+			} else {
+				pte_clear(mm, addr, ptep);
+			}
+			pte_unmap_unlock(ptep, ptl);
+
+			addr += PAGE_SIZE;
+		}
+	}
+
+	printk("OPAL Virtual Memory Runtime Enabled, using PID=0x%04x\n", (unsigned int)mm->context.id);
+
+	opal_mm = mm;
+	opal_mm_enabled = true;
+
+	return 0;
+}
+
+static int __init opal_init_early(void)
+{
+	int rc;
+
+	if (opal_v4_present) {
+		if (radix_enabled()) {
+			/* Hash can't resolve SLB faults to the switched mm */
+			rc = opal_init_mm();
+			if (rc) {
+				pr_warn("OPAL virtual memory init failed, firmware will run in real-mode.\n");
+			}
+		}
+	}
+
+	return 0;
+}
+machine_early_initcall(powernv, opal_init_early);
+
 static int __init opal_init(void)
 {
 	struct device_node *np, *consoles, *leds;
-- 
2.23.0


  parent reply	other threads:[~2020-05-02 11:54 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-02 11:19 [RFC PATCH 00/10] OPAL V4 Nicholas Piggin
2020-05-02 11:19 ` [RFC PATCH 01/10] kallsyms: architecture specific symbol lookups Nicholas Piggin
2020-05-02 11:19 ` [RFC PATCH 02/10] powerpc/powernv: Wire up OPAL address lookups Nicholas Piggin
2020-05-02 11:19 ` [RFC PATCH 03/10] powerpc/powernv: Use OPAL_REPORT_TRAP to cope with trap interrupts from OPAL Nicholas Piggin
2020-05-02 14:30   ` kbuild test robot
2020-05-02 11:19 ` [RFC PATCH 04/10] powerpc/powernv: avoid polling in opal_get_chars Nicholas Piggin
2020-05-02 11:19 ` [RFC PATCH 05/10] powerpc/powernv: Don't translate kernel addresses to real addresses for OPAL Nicholas Piggin
2020-05-02 11:19 ` [RFC PATCH 06/10] powerpc/powernv: opal use new opal call entry point if it exists Nicholas Piggin
2020-05-02 16:25   ` kbuild test robot
2020-05-06  7:02   ` Gautham R Shenoy
2020-05-02 11:19 ` [RFC PATCH 07/10] powerpc/powernv: Add OPAL_FIND_VM_AREA API Nicholas Piggin
2020-05-02 11:19 ` Nicholas Piggin [this message]
2020-05-02 11:19 ` [RFC PATCH 09/10] powerpc/powernv: OPAL V4 OS services Nicholas Piggin
2020-05-02 11:19 ` [RFC PATCH 10/10] powerpc/powernv: OPAL V4 Implement vm_map/unmap service Nicholas Piggin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200502111914.166578-9-npiggin@gmail.com \
    --to=npiggin@gmail.com \
    --cc=linuxppc-dev@lists.ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.