* [PATCH v2 14/28] powerpc/book3s64/pkeys: Inherit correctly on fork.
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
Child thread.kuap value is inherited from the parent in copy_thread_tls. We still
need to make sure when the child returns from a fork in the kernel we start with the kernel
default AMR value.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/kernel/process.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index abbe545ed88c..9ef95a1217ef 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1677,6 +1677,13 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
childregs->ppr = DEFAULT_PPR;
p->thread.tidr = 0;
+#endif
+ /*
+ * Run with the current AMR value of the kernel
+ */
+#if defined(CONFIG_PPC_MEM_KEYS)
+ kregs->kuap = AMR_KUAP_BLOCKED;
+ kregs->kuep = AMR_KUEP_BLOCKED;
#endif
kregs->nip = ppc_function_entry(f);
return 0;
--
2.26.2
^ permalink raw reply related
* [PATCH v2 13/28] powerpc/book3s64/kuep: Store/restore userspace IAMR correctly on entry and exit from kernel
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
This prepare kernel to operate with a different value than userspace IAMR.
For this, IAMR needs to be saved and restored on entry and return from the
kernel.
If MMU_FTR_KEY is enabled we always use the key mechanism to implement KUEP
feature. If MMU_FTR_KEY is not supported and if we support MMU_FTR_KUEP
(radix translation on POWER9), we can skip restoring IAMR on return
to userspace. Userspace won't be using IAMR in that specific config.
We don't need to save/restore IAMR on reentry into the kernel due to interrupt
because the kernel doesn't modify IAMR internally.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/kup.h | 46 ++++++++++++++++++++++--
arch/powerpc/include/asm/ptrace.h | 6 +++-
arch/powerpc/kernel/asm-offsets.c | 4 +++
arch/powerpc/kernel/syscall_64.c | 7 ++--
4 files changed, 58 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h
index 82bef3901672..67320a990f3f 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -17,15 +17,26 @@
#if defined(CONFIG_PPC_MEM_KEYS)
BEGIN_MMU_FTR_SECTION_NESTED(67)
/*
- * AMR is going to be different when
+ * AMR and IAMR are going to be different when
* returning to userspace.
*/
ld \gpr1, STACK_REGS_KUAP(r1)
isync
mtspr SPRN_AMR, \gpr1
+ /*
+ * Restore IAMR only when returning to userspace
+ */
+ ld \gpr1, STACK_REGS_KUEP(r1)
+ mtspr SPRN_IAMR, \gpr1
/* No isync required, see kuap_restore_user_amr() */
END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_PKEY , 67)
+
+ /*
+ * We don't check KUEP feature here, because if FTR_PKEY
+ * is not enabled we don't need to restore IAMR on
+ * return to usespace.
+ */
#endif
.endm
@@ -53,6 +64,9 @@
isync
mtspr SPRN_AMR, \gpr2
/* No isync required, see kuap_restore_amr() */
+ /*
+ * No need to restore IAMR when returning to kernel space.
+ */
100: // skip_restore_amr
#endif
.endm
@@ -90,6 +104,12 @@
b 100f // skip_save_amr
ALT_MMU_FTR_SECTION_END_NESTED_IFSET(MMU_FTR_KUAP, 68)
+ /*
+ * We don't check KUEP feature here, because if FTR_PKEY
+ * is not enabled we don't need to save IAMR on
+ * entry from usespace. That is handled by either
+ * handle_kuap_save_amr or skip_save_amr
+ */
99: // handle_kuap_save_amr
.ifnb \msr_pr_cr
@@ -120,6 +140,25 @@
102:
END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_KUAP, 69)
+ .ifnb \msr_pr_cr
+ beq \msr_pr_cr, 103f // from kernel space
+ mfspr \gpr1, SPRN_IAMR
+ std \gpr1, STACK_REGS_KUEP(r1)
+
+ /*
+ * update kernel IAMR with AMR_KUEP_BLOCKED only
+ * if KUAP feature is enabled
+ */
+ BEGIN_MMU_FTR_SECTION_NESTED(70)
+ LOAD_REG_IMMEDIATE(\gpr2, AMR_KUEP_BLOCKED)
+ cmpd \use_cr, \gpr1, \gpr2
+ beq \use_cr, 103f
+ mtspr SPRN_IAMR, \gpr2
+ isync
+103:
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_KUEP, 70)
+ .endif
+
100: // skip_save_amr
#endif
.endm
@@ -140,13 +179,13 @@ static inline void kuap_restore_user_amr(struct pt_regs *regs)
isync();
mtspr(SPRN_AMR, regs->kuap);
+ mtspr(SPRN_IAMR, regs->kuep);
/*
* No isync required here because we are about to rfi
* back to previous context before any user accesses
* would be made, which is a CSI.
*/
}
-
static inline void kuap_restore_kernel_amr(struct pt_regs *regs,
unsigned long amr)
{
@@ -162,6 +201,9 @@ static inline void kuap_restore_kernel_amr(struct pt_regs *regs,
*/
}
}
+ /*
+ * No need to restore IAMR when returning to kernel space.
+ */
}
static inline unsigned long kuap_get_and_check_amr(void)
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index e0195e6b892b..2bfd2b6a72ab 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -56,8 +56,12 @@ struct pt_regs
#ifdef CONFIG_PPC_KUAP
unsigned long kuap;
#endif
+#ifdef CONFIG_PPC_KUEP
+ unsigned long kuep;
+#endif
+
};
- unsigned long __pad[2]; /* Maintain 16 byte interrupt stack alignment */
+ unsigned long __pad[4]; /* Maintain 16 byte interrupt stack alignment */
};
};
#endif
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index fcf24a365fc0..6c7326fc73b9 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -353,6 +353,10 @@ int main(void)
#ifdef CONFIG_PPC_KUAP
STACK_PT_REGS_OFFSET(STACK_REGS_KUAP, kuap);
#endif
+#ifdef CONFIG_PPC_KUEP
+ STACK_PT_REGS_OFFSET(STACK_REGS_KUEP, kuep);
+#endif
+
#if defined(CONFIG_PPC32)
#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
diff --git a/arch/powerpc/kernel/syscall_64.c b/arch/powerpc/kernel/syscall_64.c
index 4d417fdadb2a..faac67d04a70 100644
--- a/arch/powerpc/kernel/syscall_64.c
+++ b/arch/powerpc/kernel/syscall_64.c
@@ -37,14 +37,17 @@ notrace long system_call_exception(long r3, long r4, long r5,
#ifdef CONFIG_PPC_MEM_KEYS
if (mmu_has_feature(MMU_FTR_PKEY)) {
- unsigned long amr;
+ unsigned long amr, iamr;
/*
- * When entering from userspace we mostly have the AMR
+ * When entering from userspace we mostly have the AMR/IAMR
* different from kernel default values. Hence don't compare.
*/
amr = mfspr(SPRN_AMR);
+ iamr = mfspr(SPRN_IAMR);
regs->kuap = amr;
+ regs->kuep = iamr;
mtspr(SPRN_AMR, AMR_KUAP_BLOCKED);
+ mtspr(SPRN_IAMR, AMR_KUEP_BLOCKED);
isync();
} else
#endif
--
2.26.2
^ permalink raw reply related
* [PATCH v2 12/28] powerpc/book3s64/pkeys: Store/restore userspace AMR correctly on entry and exit from kernel
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
This prepare kernel to operate with a different value than userspace AMR.
For this, AMR needs to be saved and restored on entry and return from the
kernel.
With KUAP we modify kernel AMR when accessing user address from the kernel
via copy_to/from_user interfaces.
If MMU_FTR_KEY is enabled we always use the key mechanism to implement KUAP
feature. If MMU_FTR_KEY is not supported and if we support MMU_FTR_KUAP
(radix translation on POWER9), we can skip restoring AMR on return
to userspace. Userspace won't be using AMR in that specific config.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/kup.h | 129 +++++++++++++++++++----
arch/powerpc/kernel/entry_64.S | 6 +-
arch/powerpc/kernel/exceptions-64s.S | 4 +-
arch/powerpc/kernel/syscall_64.c | 25 ++++-
4 files changed, 136 insertions(+), 28 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h
index 1b350bf781ec..82bef3901672 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -13,18 +13,47 @@
#ifdef __ASSEMBLY__
-.macro kuap_restore_amr gpr1, gpr2
-#ifdef CONFIG_PPC_KUAP
+.macro kuap_restore_user_amr gpr1
+#if defined(CONFIG_PPC_MEM_KEYS)
BEGIN_MMU_FTR_SECTION_NESTED(67)
- mfspr \gpr1, SPRN_AMR
+ /*
+ * AMR is going to be different when
+ * returning to userspace.
+ */
+ ld \gpr1, STACK_REGS_KUAP(r1)
+ isync
+ mtspr SPRN_AMR, \gpr1
+
+ /* No isync required, see kuap_restore_user_amr() */
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_PKEY , 67)
+#endif
+.endm
+
+.macro kuap_restore_kernel_amr gpr1, gpr2
+#if defined(CONFIG_PPC_MEM_KEYS)
+ BEGIN_MMU_FTR_SECTION_NESTED(67)
+ b 99f // handle_pkey_restore_amr
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_PKEY , 67)
+
+ BEGIN_MMU_FTR_SECTION_NESTED(68)
+ b 99f // handle_kuap_restore_amr
+ MMU_FTR_SECTION_ELSE_NESTED(68)
+ b 100f // skip_restore_amr
+ ALT_MMU_FTR_SECTION_END_NESTED_IFSET(MMU_FTR_KUAP, 68)
+
+99:
+ /*
+ * AMR is going to be mostly the same since we are
+ * returning to the kernel. Compare and do a mtspr.
+ */
ld \gpr2, STACK_REGS_KUAP(r1)
+ mfspr \gpr1, SPRN_AMR
cmpd \gpr1, \gpr2
- beq 998f
+ beq 100f
isync
mtspr SPRN_AMR, \gpr2
/* No isync required, see kuap_restore_amr() */
-998:
- END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_KUAP, 67)
+100: // skip_restore_amr
#endif
.endm
@@ -40,38 +69,89 @@
#endif
.endm
+/*
+ * MMU_FTR_PKEY and MMU_FTR_KUAP can both be enabled on a platform. We prefer
+ * PKEY over KUAP if both can be enabled on the platform.
+ *
+ * With KUAP only enabled on exception if we are coming from userspace we don't
+ * save the AMR at all, because the expectation is that userspace can't change
+ * the AMR if KUAP feature is enabled.
+ */
.macro kuap_save_amr_and_lock gpr1, gpr2, use_cr, msr_pr_cr
-#ifdef CONFIG_PPC_KUAP
+#if defined(CONFIG_PPC_MEM_KEYS)
+
BEGIN_MMU_FTR_SECTION_NESTED(67)
+ b 101f // handle_pkey_save_amr
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_PKEY , 67)
+
+ BEGIN_MMU_FTR_SECTION_NESTED(68)
+ b 99f // handle_kuap_save_amr
+ MMU_FTR_SECTION_ELSE_NESTED(68)
+ b 100f // skip_save_amr
+ ALT_MMU_FTR_SECTION_END_NESTED_IFSET(MMU_FTR_KUAP, 68)
+
+
+99: // handle_kuap_save_amr
.ifnb \msr_pr_cr
- bne \msr_pr_cr, 99f
+ /*
+ * We avoid changing AMR outside the kernel
+ * hence skip this completely.
+ */
+ bne \msr_pr_cr, 100f // from userspace
.endif
+
+101: // handle_pkey_save_amr
mfspr \gpr1, SPRN_AMR
std \gpr1, STACK_REGS_KUAP(r1)
- li \gpr2, (AMR_KUAP_BLOCKED >> AMR_KUAP_SHIFT)
- sldi \gpr2, \gpr2, AMR_KUAP_SHIFT
+
+ /*
+ * update kernel AMR with AMR_KUAP_BLOCKED only
+ * if KUAP feature is enabled
+ */
+ BEGIN_MMU_FTR_SECTION_NESTED(69)
+ LOAD_REG_IMMEDIATE(\gpr2, AMR_KUAP_BLOCKED)
cmpd \use_cr, \gpr1, \gpr2
- beq \use_cr, 99f
- // We don't isync here because we very recently entered via rfid
+ beq \use_cr, 102f
+ /*
+ * We don't isync here because we very recently entered via an interrupt
+ */
mtspr SPRN_AMR, \gpr2
isync
-99:
- END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_KUAP, 67)
+102:
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_KUAP, 69)
+
+100: // skip_save_amr
#endif
.endm
#else /* !__ASSEMBLY__ */
-#ifdef CONFIG_PPC_KUAP
+#ifdef CONFIG_PPC_MEM_KEYS
#include <asm/mmu.h>
#include <asm/ptrace.h>
extern u64 default_uamor;
-static inline void kuap_restore_amr(struct pt_regs *regs, unsigned long amr)
+static inline void kuap_restore_user_amr(struct pt_regs *regs)
{
- if (mmu_has_feature(MMU_FTR_KUAP)) {
+ if (!mmu_has_feature(MMU_FTR_PKEY))
+ return;
+
+ isync();
+ mtspr(SPRN_AMR, regs->kuap);
+ /*
+ * No isync required here because we are about to rfi
+ * back to previous context before any user accesses
+ * would be made, which is a CSI.
+ */
+}
+
+static inline void kuap_restore_kernel_amr(struct pt_regs *regs,
+ unsigned long amr)
+{
+ if (mmu_has_feature(MMU_FTR_KUAP) || mmu_has_feature(MMU_FTR_PKEY)) {
+
if (unlikely(regs->kuap != amr)) {
isync();
mtspr(SPRN_AMR, regs->kuap);
@@ -86,7 +166,7 @@ static inline void kuap_restore_amr(struct pt_regs *regs, unsigned long amr)
static inline unsigned long kuap_get_and_check_amr(void)
{
- if (mmu_has_feature(MMU_FTR_KUAP)) {
+ if (mmu_has_feature(MMU_FTR_KUAP) || mmu_has_feature(MMU_FTR_PKEY)) {
unsigned long amr = mfspr(SPRN_AMR);
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) /* kuap_check_amr() */
WARN_ON_ONCE(amr != AMR_KUAP_BLOCKED);
@@ -97,7 +177,8 @@ static inline unsigned long kuap_get_and_check_amr(void)
static inline void kuap_check_amr(void)
{
- if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && mmu_has_feature(MMU_FTR_KUAP))
+ if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) &&
+ (mmu_has_feature(MMU_FTR_KUAP) || mmu_has_feature(MMU_FTR_PKEY)))
WARN_ON_ONCE(mfspr(SPRN_AMR) != AMR_KUAP_BLOCKED);
}
@@ -170,8 +251,12 @@ bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
(regs->kuap & (is_write ? AMR_KUAP_BLOCK_WRITE : AMR_KUAP_BLOCK_READ)),
"Bug: %s fault blocked by AMR!", is_write ? "Write" : "Read");
}
-#else /* CONFIG_PPC_KUAP */
-static inline void kuap_restore_amr(struct pt_regs *regs, unsigned long amr)
+#else /* CONFIG_PPC_MEM_KEYS */
+static inline void kuap_restore_user_amr(struct pt_regs *regs)
+{
+}
+
+static inline void kuap_restore_kernel_amr(struct pt_regs *regs, unsigned long amr)
{
}
@@ -183,7 +268,7 @@ static inline unsigned long kuap_get_and_check_amr(void)
{
return 0;
}
-#endif /* CONFIG_PPC_KUAP */
+#endif /* CONFIG_PPC_MEM_KEYS */
#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 9d49338e0c85..a087cbe0b17d 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -481,8 +481,8 @@ _ASM_NOKPROBE_SYMBOL(fast_interrupt_return)
kuap_check_amr r3, r4
ld r5,_MSR(r1)
andi. r0,r5,MSR_PR
- bne .Lfast_user_interrupt_return
- kuap_restore_amr r3, r4
+ bne .Lfast_user_interrupt_return_amr
+ kuap_restore_kernel_amr r3, r4
andi. r0,r5,MSR_RI
li r3,0 /* 0 return value, no EMULATE_STACK_STORE */
bne+ .Lfast_kernel_interrupt_return
@@ -502,6 +502,8 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return)
cmpdi r3,0
bne- .Lrestore_nvgprs
+.Lfast_user_interrupt_return_amr:
+ kuap_restore_user_amr r3
.Lfast_user_interrupt_return:
ld r11,_NIP(r1)
ld r12,_MSR(r1)
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index ef4a90212664..11abe8fbf0ba 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -971,7 +971,7 @@ EXC_COMMON_BEGIN(system_reset_common)
ld r10,SOFTE(r1)
stb r10,PACAIRQSOFTMASK(r13)
- kuap_restore_amr r9, r10
+ kuap_restore_kernel_amr r9, r10
EXCEPTION_RESTORE_REGS
RFI_TO_USER_OR_KERNEL
@@ -2757,7 +2757,7 @@ EXC_COMMON_BEGIN(soft_nmi_common)
ld r10,SOFTE(r1)
stb r10,PACAIRQSOFTMASK(r13)
- kuap_restore_amr r9, r10
+ kuap_restore_kernel_amr r9, r10
EXCEPTION_RESTORE_REGS hsrr=0
RFI_TO_KERNEL
diff --git a/arch/powerpc/kernel/syscall_64.c b/arch/powerpc/kernel/syscall_64.c
index f704f657e1f7..4d417fdadb2a 100644
--- a/arch/powerpc/kernel/syscall_64.c
+++ b/arch/powerpc/kernel/syscall_64.c
@@ -35,7 +35,20 @@ notrace long system_call_exception(long r3, long r4, long r5,
BUG_ON(!FULL_REGS(regs));
BUG_ON(regs->softe != IRQS_ENABLED);
- kuap_check_amr();
+#ifdef CONFIG_PPC_MEM_KEYS
+ if (mmu_has_feature(MMU_FTR_PKEY)) {
+ unsigned long amr;
+ /*
+ * When entering from userspace we mostly have the AMR
+ * different from kernel default values. Hence don't compare.
+ */
+ amr = mfspr(SPRN_AMR);
+ regs->kuap = amr;
+ mtspr(SPRN_AMR, AMR_KUAP_BLOCKED);
+ isync();
+ } else
+#endif
+ kuap_check_amr();
account_cpu_user_entry();
@@ -208,6 +221,10 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
account_cpu_user_exit();
+ /*
+ * We do this at the end so that we do context switch with KERNEL AMR
+ */
+ kuap_restore_user_amr(regs);
return ret;
}
@@ -300,6 +317,10 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs, unsigned
account_cpu_user_exit();
+ /*
+ * We do this at the end so that we do context switch with KERNEL AMR
+ */
+ kuap_restore_user_amr(regs);
return ret;
}
@@ -378,7 +399,7 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs, unsign
* mtmsr, which would cause RAW stalls. Hence, we take the AMR value
* from the check above.
*/
- kuap_restore_amr(regs, amr);
+ kuap_restore_kernel_amr(regs, amr);
return ret;
}
--
2.26.2
^ permalink raw reply related
* [PATCH v2 11/28] powerpc/exec: Set thread.regs early during exec
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
In later patches during exec, we would like to access default regs.kuap to
control access to the user mapping. Having thread.regs set early makes the
code changes simpler.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/kernel/process.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 8479c762aef2..abbe545ed88c 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1462,9 +1462,18 @@ void flush_thread(void)
#ifdef CONFIG_PPC_BOOK3S_64
void arch_setup_new_exec(void)
{
- if (radix_enabled())
- return;
- hash__setup_new_exec();
+ if (!radix_enabled())
+ hash__setup_new_exec();
+
+ /*
+ * If we exec out of a kernel thread then thread.regs will not be
+ * set. Do it now.
+ */
+ if (!current->thread.regs) {
+ struct pt_regs *regs = task_stack_page(current) + THREAD_SIZE;
+ current->thread.regs = regs - 1;
+ }
+
}
#endif
@@ -1689,15 +1698,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
#endif
#endif
- /*
- * If we exec out of a kernel thread then thread.regs will not be
- * set. Do it now.
- */
- if (!current->thread.regs) {
- struct pt_regs *regs = task_stack_page(current) + THREAD_SIZE;
- current->thread.regs = regs - 1;
- }
-
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
/*
* Clear any transactional state, we're exec()ing. The cause is
--
2.26.2
^ permalink raw reply related
* [PATCH v2 10/28] powerpc/book3s64/kuap: Use Key 3 for kernel mapping with hash translation
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
This patch updates kernel hash page table entries to use storage key 3
for its mapping. This implies all kernel access will now use key 3 to
control READ/WRITE. The patch also prevents the allocation of key 3 from
userspace and UAMOR value is updated such that userspace cannot modify key 3.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
.../powerpc/include/asm/book3s/64/hash-pkey.h | 24 ++++++++++++++-----
arch/powerpc/include/asm/book3s/64/hash.h | 3 ++-
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 1 +
arch/powerpc/include/asm/mmu_context.h | 2 +-
arch/powerpc/mm/book3s64/hash_4k.c | 2 +-
arch/powerpc/mm/book3s64/hash_64k.c | 4 ++--
arch/powerpc/mm/book3s64/hash_hugepage.c | 2 +-
arch/powerpc/mm/book3s64/hash_hugetlbpage.c | 2 +-
arch/powerpc/mm/book3s64/hash_pgtable.c | 2 +-
arch/powerpc/mm/book3s64/hash_utils.c | 10 ++++----
arch/powerpc/mm/book3s64/pkeys.c | 4 ++++
11 files changed, 38 insertions(+), 18 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/hash-pkey.h b/arch/powerpc/include/asm/book3s/64/hash-pkey.h
index 795010897e5d..fc75b815c9ca 100644
--- a/arch/powerpc/include/asm/book3s/64/hash-pkey.h
+++ b/arch/powerpc/include/asm/book3s/64/hash-pkey.h
@@ -2,6 +2,9 @@
#ifndef _ASM_POWERPC_BOOK3S_64_HASH_PKEY_H
#define _ASM_POWERPC_BOOK3S_64_HASH_PKEY_H
+/* We use key 3 for KERNEL */
+#define HASH_DEFAULT_KERNEL_KEY (HPTE_R_KEY_BIT0 | HPTE_R_KEY_BIT1)
+
static inline u64 hash__vmflag_to_pte_pkey_bits(u64 vm_flags)
{
return (((vm_flags & VM_PKEY_BIT0) ? H_PTE_PKEY_BIT0 : 0x0UL) |
@@ -11,13 +14,22 @@ static inline u64 hash__vmflag_to_pte_pkey_bits(u64 vm_flags)
((vm_flags & VM_PKEY_BIT4) ? H_PTE_PKEY_BIT4 : 0x0UL));
}
-static inline u64 pte_to_hpte_pkey_bits(u64 pteflags)
+static inline u64 pte_to_hpte_pkey_bits(u64 pteflags, unsigned long flags)
{
- return (((pteflags & H_PTE_PKEY_BIT4) ? HPTE_R_KEY_BIT4 : 0x0UL) |
- ((pteflags & H_PTE_PKEY_BIT3) ? HPTE_R_KEY_BIT3 : 0x0UL) |
- ((pteflags & H_PTE_PKEY_BIT2) ? HPTE_R_KEY_BIT2 : 0x0UL) |
- ((pteflags & H_PTE_PKEY_BIT1) ? HPTE_R_KEY_BIT1 : 0x0UL) |
- ((pteflags & H_PTE_PKEY_BIT0) ? HPTE_R_KEY_BIT0 : 0x0UL));
+ unsigned long pte_pkey;
+
+ pte_pkey = (((pteflags & H_PTE_PKEY_BIT4) ? HPTE_R_KEY_BIT4 : 0x0UL) |
+ ((pteflags & H_PTE_PKEY_BIT3) ? HPTE_R_KEY_BIT3 : 0x0UL) |
+ ((pteflags & H_PTE_PKEY_BIT2) ? HPTE_R_KEY_BIT2 : 0x0UL) |
+ ((pteflags & H_PTE_PKEY_BIT1) ? HPTE_R_KEY_BIT1 : 0x0UL) |
+ ((pteflags & H_PTE_PKEY_BIT0) ? HPTE_R_KEY_BIT0 : 0x0UL));
+
+ if (mmu_has_feature(MMU_FTR_KUAP)) {
+ if ((pte_pkey == 0) && (flags & HPTE_USE_KERNEL_KEY))
+ return HASH_DEFAULT_KERNEL_KEY;
+ }
+
+ return pte_pkey;
}
static inline u16 hash__pte_to_pkey_bits(u64 pteflags)
diff --git a/arch/powerpc/include/asm/book3s/64/hash.h b/arch/powerpc/include/asm/book3s/64/hash.h
index 6fc4520092c7..12b65d3d79aa 100644
--- a/arch/powerpc/include/asm/book3s/64/hash.h
+++ b/arch/powerpc/include/asm/book3s/64/hash.h
@@ -145,7 +145,8 @@ extern void hash__mark_initmem_nx(void);
extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, unsigned long pte, int huge);
-extern unsigned long htab_convert_pte_flags(unsigned long pteflags);
+extern unsigned long htab_convert_pte_flags(unsigned long pteflags,
+ unsigned long flags);
/* Atomic PTE updates */
static inline unsigned long hash__pte_update(struct mm_struct *mm,
unsigned long addr,
diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
index 58fcc959f9d5..eb9950043b78 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
@@ -452,6 +452,7 @@ static inline unsigned long hpt_hash(unsigned long vpn,
#define HPTE_LOCAL_UPDATE 0x1
#define HPTE_NOHPTE_UPDATE 0x2
+#define HPTE_USE_KERNEL_KEY 0x4
extern int __hash_page_4K(unsigned long ea, unsigned long access,
unsigned long vsid, pte_t *ptep, unsigned long trap,
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 1a474f6b1992..2d85e0ea5f1c 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -286,7 +286,7 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
#define thread_pkey_regs_init(thread)
#define arch_dup_pkeys(oldmm, mm)
-static inline u64 pte_to_hpte_pkey_bits(u64 pteflags)
+static inline u64 pte_to_hpte_pkey_bits(u64 pteflags, unsigned long flags)
{
return 0x0UL;
}
diff --git a/arch/powerpc/mm/book3s64/hash_4k.c b/arch/powerpc/mm/book3s64/hash_4k.c
index 22e787123cdf..7de1a8a0c62a 100644
--- a/arch/powerpc/mm/book3s64/hash_4k.c
+++ b/arch/powerpc/mm/book3s64/hash_4k.c
@@ -54,7 +54,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
* PP bits. _PAGE_USER is already PP bit 0x2, so we only
* need to add in 0x1 if it's a read-only user page
*/
- rflags = htab_convert_pte_flags(new_pte);
+ rflags = htab_convert_pte_flags(new_pte, flags);
rpte = __real_pte(__pte(old_pte), ptep, PTRS_PER_PTE);
if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
diff --git a/arch/powerpc/mm/book3s64/hash_64k.c b/arch/powerpc/mm/book3s64/hash_64k.c
index 7084ce2951e6..998c6817ed47 100644
--- a/arch/powerpc/mm/book3s64/hash_64k.c
+++ b/arch/powerpc/mm/book3s64/hash_64k.c
@@ -72,7 +72,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
* Handle the subpage protection bits
*/
subpg_pte = new_pte & ~subpg_prot;
- rflags = htab_convert_pte_flags(subpg_pte);
+ rflags = htab_convert_pte_flags(subpg_pte, flags);
if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
@@ -260,7 +260,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
new_pte |= _PAGE_DIRTY;
} while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
- rflags = htab_convert_pte_flags(new_pte);
+ rflags = htab_convert_pte_flags(new_pte, flags);
rpte = __real_pte(__pte(old_pte), ptep, PTRS_PER_PTE);
if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
diff --git a/arch/powerpc/mm/book3s64/hash_hugepage.c b/arch/powerpc/mm/book3s64/hash_hugepage.c
index 440823797de7..c0fabe6c5a12 100644
--- a/arch/powerpc/mm/book3s64/hash_hugepage.c
+++ b/arch/powerpc/mm/book3s64/hash_hugepage.c
@@ -57,7 +57,7 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
if (!(old_pmd & (H_PAGE_THP_HUGE | _PAGE_DEVMAP)))
return 0;
- rflags = htab_convert_pte_flags(new_pmd);
+ rflags = htab_convert_pte_flags(new_pmd, flags);
#if 0
if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
diff --git a/arch/powerpc/mm/book3s64/hash_hugetlbpage.c b/arch/powerpc/mm/book3s64/hash_hugetlbpage.c
index eefa89c6117b..8ce8fc327af4 100644
--- a/arch/powerpc/mm/book3s64/hash_hugetlbpage.c
+++ b/arch/powerpc/mm/book3s64/hash_hugetlbpage.c
@@ -72,7 +72,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
if (old_pte & (H_PAGE_THP_HUGE | _PAGE_DEVMAP))
return 0;
- rflags = htab_convert_pte_flags(new_pte);
+ rflags = htab_convert_pte_flags(new_pte, flags);
if (unlikely(mmu_psize == MMU_PAGE_16G))
offset = PTRS_PER_PUD;
else
diff --git a/arch/powerpc/mm/book3s64/hash_pgtable.c b/arch/powerpc/mm/book3s64/hash_pgtable.c
index 64733b9cb20a..6c43aaf1c713 100644
--- a/arch/powerpc/mm/book3s64/hash_pgtable.c
+++ b/arch/powerpc/mm/book3s64/hash_pgtable.c
@@ -454,7 +454,7 @@ void hash__mark_initmem_nx(void)
start = (unsigned long)__init_begin;
end = (unsigned long)__init_end;
- pp = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL));
+ pp = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL), HPTE_USE_KERNEL_KEY);
WARN_ON(!hash__change_memory_range(start, end, pp));
}
diff --git a/arch/powerpc/mm/book3s64/hash_utils.c b/arch/powerpc/mm/book3s64/hash_utils.c
index 8ed2411c3f39..bdd4f1792c76 100644
--- a/arch/powerpc/mm/book3s64/hash_utils.c
+++ b/arch/powerpc/mm/book3s64/hash_utils.c
@@ -183,7 +183,7 @@ static struct mmu_psize_def mmu_psize_defaults_gp[] = {
* - We make sure R is always set and never lost
* - C is _PAGE_DIRTY, and *should* always be set for a writeable mapping
*/
-unsigned long htab_convert_pte_flags(unsigned long pteflags)
+unsigned long htab_convert_pte_flags(unsigned long pteflags, unsigned long flags)
{
unsigned long rflags = 0;
@@ -237,7 +237,7 @@ unsigned long htab_convert_pte_flags(unsigned long pteflags)
*/
rflags |= HPTE_R_M;
- rflags |= pte_to_hpte_pkey_bits(pteflags);
+ rflags |= pte_to_hpte_pkey_bits(pteflags, flags);
return rflags;
}
@@ -252,7 +252,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
shift = mmu_psize_defs[psize].shift;
step = 1 << shift;
- prot = htab_convert_pte_flags(prot);
+ prot = htab_convert_pte_flags(prot, HPTE_USE_KERNEL_KEY);
DBG("htab_bolt_mapping(%lx..%lx -> %lx (%lx,%d,%d)\n",
vstart, vend, pstart, prot, psize, ssize);
@@ -1295,12 +1295,14 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea,
vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
psize = mmu_vmalloc_psize;
ssize = mmu_kernel_ssize;
+ flags |= HPTE_USE_KERNEL_KEY;
break;
case IO_REGION_ID:
vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
psize = mmu_io_psize;
ssize = mmu_kernel_ssize;
+ flags |= HPTE_USE_KERNEL_KEY;
break;
default:
/*
@@ -1894,7 +1896,7 @@ static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi)
unsigned long hash;
unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize);
unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize);
- unsigned long mode = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL));
+ unsigned long mode = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL), HPTE_USE_KERNEL_KEY);
long ret;
hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize);
diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c
index 12a9ac169f5d..976f65f27324 100644
--- a/arch/powerpc/mm/book3s64/pkeys.c
+++ b/arch/powerpc/mm/book3s64/pkeys.c
@@ -189,6 +189,10 @@ void __init pkey_early_init_devtree(void)
reserved_allocation_mask |= (0x1 << 1);
default_uamor &= ~(0x3ul << pkeyshift(1));
+ /* handle key 3 which is used by kernel for KAUP */
+ reserved_allocation_mask |= (0x1 << 3);
+ default_uamor &= ~(0x3ul << pkeyshift(3));
+
/*
* Prevent the usage of OS reserved keys. Update UAMOR
* for those keys. Also mark the rest of the bits in the
--
2.26.2
^ permalink raw reply related
* [PATCH v2 09/28] powerpc/book3s64/kuap: Move UAMOR setup to key init function
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
With hash translation, the kernel will use key 3 for implementing
KUAP feature. Hence the default UAMOR value depends on what other
keys are marked reserved. Move the UAMOR initialization to pkeys init.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/kup.h | 2 ++
arch/powerpc/kernel/smp.c | 5 +++++
arch/powerpc/mm/book3s64/pkeys.c | 25 +++++++++++++++++++-----
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h
index f4fb651f5850..1b350bf781ec 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -67,6 +67,8 @@
#include <asm/mmu.h>
#include <asm/ptrace.h>
+extern u64 default_uamor;
+
static inline void kuap_restore_amr(struct pt_regs *regs, unsigned long amr)
{
if (mmu_has_feature(MMU_FTR_KUAP)) {
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 6d2a3a3666f0..4cd5b620c08c 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -59,6 +59,7 @@
#include <asm/asm-prototypes.h>
#include <asm/cpu_has_feature.h>
#include <asm/ftrace.h>
+#include <asm/kup.h>
#ifdef DEBUG
#include <asm/udbg.h>
@@ -1256,6 +1257,10 @@ void start_secondary(void *unused)
mmgrab(&init_mm);
current->active_mm = &init_mm;
+#ifdef CONFIG_PPC_MEM_KEYS
+ mtspr(SPRN_UAMOR, default_uamor);
+#endif
+
smp_store_cpu_info(cpu);
set_dec(tb_ticks_per_jiffy);
preempt_disable();
diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c
index 7498c9a8ef74..12a9ac169f5d 100644
--- a/arch/powerpc/mm/book3s64/pkeys.c
+++ b/arch/powerpc/mm/book3s64/pkeys.c
@@ -23,7 +23,7 @@ static u32 initial_allocation_mask; /* Bits set for the initially allocated k
static u64 default_amr;
static u64 default_iamr;
/* Allow all keys to be modified by default */
-static u64 default_uamor = ~0x0UL;
+u64 default_uamor = ~0x0UL;
/*
* Key used to implement PROT_EXEC mmap. Denies READ/WRITE
* We pick key 2 because 0 is special key and 1 is reserved as per ISA.
@@ -112,8 +112,16 @@ void __init pkey_early_init_devtree(void)
/* scan the device tree for pkey feature */
pkeys_total = scan_pkey_feature();
if (!pkeys_total) {
- /* No support for pkey. Mark it disabled */
- return;
+ /*
+ * No key support but on radix we can use key 0
+ * to implement kuap.
+ */
+ if (early_radix_enabled())
+ /*
+ * Make sure userspace can't change the AMR
+ */
+ default_uamor = 0;
+ goto err_out;
}
cur_cpu_spec->mmu_features |= MMU_FTR_PKEY;
@@ -195,6 +203,12 @@ void __init pkey_early_init_devtree(void)
*/
initial_allocation_mask |= reserved_allocation_mask;
+err_out:
+ /*
+ * Setup uamor on boot cpu
+ */
+ mtspr(SPRN_UAMOR, default_uamor);
+
return;
}
@@ -230,8 +244,9 @@ void __init setup_kuap(bool disabled)
cur_cpu_spec->mmu_features |= MMU_FTR_KUAP;
}
- /* Make sure userspace can't change the AMR */
- mtspr(SPRN_UAMOR, 0);
+ /*
+ * Set the default kernel AMR values on all cpus.
+ */
mtspr(SPRN_AMR, AMR_KUAP_BLOCKED);
isync();
}
--
2.26.2
^ permalink raw reply related
* [PATCH v2 08/28] powerpc/book3s64/kuap/kuep: Make KUAP and KUEP a subfeature of PPC_MEM_KEYS
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
The next set of patches adds support for kuap with hash translation.
Hence make KUAP a BOOK3S_64 feature. Also make it a subfeature of
PPC_MEM_KEYS. Hash translation is going to use pkeys to support
KUAP/KUEP. Adding this dependency reduces the code complexity and
enables us to move some of the initialization code to pkeys.c
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/platforms/Kconfig.cputype | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 27a81c291be8..eb36a6007a94 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -99,6 +99,8 @@ config PPC_BOOK3S_64
select ARCH_SUPPORTS_NUMA_BALANCING
select IRQ_WORK
select PPC_MM_SLICES
+ select PPC_HAVE_KUAP if PPC_MEM_KEYS
+ select PPC_HAVE_KUEP if PPC_MEM_KEYS
config PPC_BOOK3E_64
bool "Embedded processors"
@@ -350,8 +352,6 @@ config PPC_RADIX_MMU
bool "Radix MMU Support"
depends on PPC_BOOK3S_64
select ARCH_HAS_GIGANTIC_PAGE
- select PPC_HAVE_KUEP
- select PPC_HAVE_KUAP
default y
help
Enable support for the Power ISA 3.0 Radix style MMU. Currently this
--
2.26.2
^ permalink raw reply related
* [PATCH v2 07/28] powerpc/book3s64/kuap: Rename MMU_FTR_RADIX_KUAP to MMU_FTR_KUAP
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
The next set of patches adds support for kuap with hash translation.
In preparation for that rename/move kuap related functions to
non radix names.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/kup.h | 18 +++++++++---------
arch/powerpc/include/asm/mmu.h | 6 +++---
arch/powerpc/mm/book3s64/pkeys.c | 2 +-
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h
index 21008cc7af6f..f4fb651f5850 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -24,7 +24,7 @@
mtspr SPRN_AMR, \gpr2
/* No isync required, see kuap_restore_amr() */
998:
- END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_KUAP, 67)
#endif
.endm
@@ -36,7 +36,7 @@
sldi \gpr2, \gpr2, AMR_KUAP_SHIFT
999: tdne \gpr1, \gpr2
EMIT_BUG_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
- END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_KUAP, 67)
#endif
.endm
@@ -56,7 +56,7 @@
mtspr SPRN_AMR, \gpr2
isync
99:
- END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_KUAP, 67)
#endif
.endm
@@ -69,7 +69,7 @@
static inline void kuap_restore_amr(struct pt_regs *regs, unsigned long amr)
{
- if (mmu_has_feature(MMU_FTR_RADIX_KUAP)) {
+ if (mmu_has_feature(MMU_FTR_KUAP)) {
if (unlikely(regs->kuap != amr)) {
isync();
mtspr(SPRN_AMR, regs->kuap);
@@ -84,7 +84,7 @@ static inline void kuap_restore_amr(struct pt_regs *regs, unsigned long amr)
static inline unsigned long kuap_get_and_check_amr(void)
{
- if (mmu_has_feature(MMU_FTR_RADIX_KUAP)) {
+ if (mmu_has_feature(MMU_FTR_KUAP)) {
unsigned long amr = mfspr(SPRN_AMR);
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) /* kuap_check_amr() */
WARN_ON_ONCE(amr != AMR_KUAP_BLOCKED);
@@ -95,7 +95,7 @@ static inline unsigned long kuap_get_and_check_amr(void)
static inline void kuap_check_amr(void)
{
- if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && mmu_has_feature(MMU_FTR_RADIX_KUAP))
+ if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && mmu_has_feature(MMU_FTR_KUAP))
WARN_ON_ONCE(mfspr(SPRN_AMR) != AMR_KUAP_BLOCKED);
}
@@ -106,7 +106,7 @@ static inline void kuap_check_amr(void)
static inline unsigned long get_kuap(void)
{
- if (!early_mmu_has_feature(MMU_FTR_RADIX_KUAP))
+ if (!early_mmu_has_feature(MMU_FTR_KUAP))
return 0;
return mfspr(SPRN_AMR);
@@ -114,7 +114,7 @@ static inline unsigned long get_kuap(void)
static inline void set_kuap(unsigned long value)
{
- if (!early_mmu_has_feature(MMU_FTR_RADIX_KUAP))
+ if (!early_mmu_has_feature(MMU_FTR_KUAP))
return;
/*
@@ -164,7 +164,7 @@ static inline void restore_user_access(unsigned long flags)
static inline bool
bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
- return WARN(mmu_has_feature(MMU_FTR_RADIX_KUAP) &&
+ return WARN(mmu_has_feature(MMU_FTR_KUAP) &&
(regs->kuap & (is_write ? AMR_KUAP_BLOCK_WRITE : AMR_KUAP_BLOCK_READ)),
"Bug: %s fault blocked by AMR!", is_write ? "Write" : "Read");
}
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index b26af5aac5a6..a7cc2b83836f 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -112,7 +112,7 @@
/*
* Supports KUAP (key 0 controlling userspace addresses) on radix
*/
-#define MMU_FTR_RADIX_KUAP ASM_CONST(0x80000000)
+#define MMU_FTR_KUAP ASM_CONST(0x80000000)
/* MMU feature bit sets for various CPUs */
#define MMU_FTRS_DEFAULT_HPTE_ARCH_V2 \
@@ -174,10 +174,10 @@ enum {
#endif
#ifdef CONFIG_PPC_RADIX_MMU
MMU_FTR_TYPE_RADIX |
+#endif /* CONFIG_PPC_RADIX_MMU */
#ifdef CONFIG_PPC_KUAP
- MMU_FTR_RADIX_KUAP |
+ MMU_FTR_KUAP |
#endif /* CONFIG_PPC_KUAP */
-#endif /* CONFIG_PPC_RADIX_MMU */
#ifdef CONFIG_PPC_MEM_KEYS
MMU_FTR_PKEY |
#endif
diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c
index b6ea4fec787b..7498c9a8ef74 100644
--- a/arch/powerpc/mm/book3s64/pkeys.c
+++ b/arch/powerpc/mm/book3s64/pkeys.c
@@ -227,7 +227,7 @@ void __init setup_kuap(bool disabled)
if (smp_processor_id() == boot_cpuid) {
pr_info("Activating Kernel Userspace Access Prevention\n");
- cur_cpu_spec->mmu_features |= MMU_FTR_RADIX_KUAP;
+ cur_cpu_spec->mmu_features |= MMU_FTR_KUAP;
}
/* Make sure userspace can't change the AMR */
--
2.26.2
^ permalink raw reply related
* [PATCH v2 06/28] powerpc/book3s64/kuep: Move KUEP related function outside radix
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
The next set of patches adds support for kuep with hash translation.
In preparation for that rename/move kuap related functions to
non radix names.
Also set MMU_FTR_KUEP and add the missing isync().
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/kup.h | 1 +
arch/powerpc/mm/book3s64/pkeys.c | 21 +++++++++++++++++++++
arch/powerpc/mm/book3s64/radix_pgtable.c | 18 ------------------
3 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h
index 21de441762d5..21008cc7af6f 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -7,6 +7,7 @@
#define AMR_KUAP_BLOCK_READ UL(0x4000000000000000)
#define AMR_KUAP_BLOCK_WRITE UL(0x8000000000000000)
+#define AMR_KUEP_BLOCKED (1UL << 62)
#define AMR_KUAP_BLOCKED (AMR_KUAP_BLOCK_READ | AMR_KUAP_BLOCK_WRITE)
#define AMR_KUAP_SHIFT 62
diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c
index e923be3b52e7..b6ea4fec787b 100644
--- a/arch/powerpc/mm/book3s64/pkeys.c
+++ b/arch/powerpc/mm/book3s64/pkeys.c
@@ -198,6 +198,27 @@ void __init pkey_early_init_devtree(void)
return;
}
+#ifdef CONFIG_PPC_KUEP
+void __init setup_kuep(bool disabled)
+{
+ if (disabled || !early_radix_enabled())
+ return;
+
+ if (smp_processor_id() == boot_cpuid) {
+ pr_info("Activating Kernel Userspace Execution Prevention\n");
+ cur_cpu_spec->mmu_features |= MMU_FTR_KUEP;
+ }
+
+ /*
+ * Radix always uses key0 of the IAMR to determine if an access is
+ * allowed. We set bit 0 (IBM bit 1) of key0, to prevent instruction
+ * fetch.
+ */
+ mtspr(SPRN_IAMR, AMR_KUEP_BLOCKED);
+ isync();
+}
+#endif
+
#ifdef CONFIG_PPC_KUAP
void __init setup_kuap(bool disabled)
{
diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
index 74558ce6b5cb..3fb088eecece 100644
--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
+++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
@@ -508,24 +508,6 @@ static void radix_init_amor(void)
mtspr(SPRN_AMOR, (3ul << 62));
}
-#ifdef CONFIG_PPC_KUEP
-void setup_kuep(bool disabled)
-{
- if (disabled || !early_radix_enabled())
- return;
-
- if (smp_processor_id() == boot_cpuid)
- pr_info("Activating Kernel Userspace Execution Prevention\n");
-
- /*
- * Radix always uses key0 of the IAMR to determine if an access is
- * allowed. We set bit 0 (IBM bit 1) of key0, to prevent instruction
- * fetch.
- */
- mtspr(SPRN_IAMR, (1ul << 62));
-}
-#endif
-
void __init radix__early_init_mmu(void)
{
unsigned long lpcr;
--
2.26.2
^ permalink raw reply related
* [PATCH v2 05/28] powerpc/book3s64/kuap: Move KUAP related function outside radix
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
The next set of patches adds support for kuap with hash translation.
In preparation for that rename/move kuap related functions to
non radix names.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
.../asm/book3s/64/{kup-radix.h => kup.h} | 6 +++---
arch/powerpc/include/asm/kup.h | 2 +-
arch/powerpc/kernel/syscall_64.c | 2 +-
arch/powerpc/mm/book3s64/pkeys.c | 18 ++++++++++++++++++
arch/powerpc/mm/book3s64/radix_pgtable.c | 18 ------------------
5 files changed, 23 insertions(+), 23 deletions(-)
rename arch/powerpc/include/asm/book3s/64/{kup-radix.h => kup.h} (97%)
diff --git a/arch/powerpc/include/asm/book3s/64/kup-radix.h b/arch/powerpc/include/asm/book3s/64/kup.h
similarity index 97%
rename from arch/powerpc/include/asm/book3s/64/kup-radix.h
rename to arch/powerpc/include/asm/book3s/64/kup.h
index e82df54f5681..21de441762d5 100644
--- a/arch/powerpc/include/asm/book3s/64/kup-radix.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H
-#define _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H
+#ifndef _ASM_POWERPC_BOOK3S_64_KUP_H
+#define _ASM_POWERPC_BOOK3S_64_KUP_H
#include <linux/const.h>
#include <asm/reg.h>
@@ -184,4 +184,4 @@ static inline unsigned long kuap_get_and_check_amr(void)
#endif /* __ASSEMBLY__ */
-#endif /* _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H */
+#endif /* _ASM_POWERPC_BOOK3S_64_KUP_H */
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 92bcd1a26d73..248438dff74a 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -13,7 +13,7 @@
#define KUAP_CURRENT 4
#ifdef CONFIG_PPC64
-#include <asm/book3s/64/kup-radix.h>
+#include <asm/book3s/64/kup.h>
#endif
#ifdef CONFIG_PPC_8xx
#include <asm/nohash/32/kup-8xx.h>
diff --git a/arch/powerpc/kernel/syscall_64.c b/arch/powerpc/kernel/syscall_64.c
index bfb161a3a0ea..f704f657e1f7 100644
--- a/arch/powerpc/kernel/syscall_64.c
+++ b/arch/powerpc/kernel/syscall_64.c
@@ -2,7 +2,7 @@
#include <linux/err.h>
#include <asm/asm-prototypes.h>
-#include <asm/book3s/64/kup-radix.h>
+#include <asm/book3s/64/kup.h>
#include <asm/cputime.h>
#include <asm/hw_irq.h>
#include <asm/kprobes.h>
diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c
index 810118123e70..e923be3b52e7 100644
--- a/arch/powerpc/mm/book3s64/pkeys.c
+++ b/arch/powerpc/mm/book3s64/pkeys.c
@@ -198,6 +198,24 @@ void __init pkey_early_init_devtree(void)
return;
}
+#ifdef CONFIG_PPC_KUAP
+void __init setup_kuap(bool disabled)
+{
+ if (disabled || !early_radix_enabled())
+ return;
+
+ if (smp_processor_id() == boot_cpuid) {
+ pr_info("Activating Kernel Userspace Access Prevention\n");
+ cur_cpu_spec->mmu_features |= MMU_FTR_RADIX_KUAP;
+ }
+
+ /* Make sure userspace can't change the AMR */
+ mtspr(SPRN_UAMOR, 0);
+ mtspr(SPRN_AMR, AMR_KUAP_BLOCKED);
+ isync();
+}
+#endif
+
void pkey_mm_init(struct mm_struct *mm)
{
if (!mmu_has_feature(MMU_FTR_PKEY))
diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
index 8f9edf07063a..74558ce6b5cb 100644
--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
+++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
@@ -526,24 +526,6 @@ void setup_kuep(bool disabled)
}
#endif
-#ifdef CONFIG_PPC_KUAP
-void setup_kuap(bool disabled)
-{
- if (disabled || !early_radix_enabled())
- return;
-
- if (smp_processor_id() == boot_cpuid) {
- pr_info("Activating Kernel Userspace Access Prevention\n");
- cur_cpu_spec->mmu_features |= MMU_FTR_RADIX_KUAP;
- }
-
- /* Make sure userspace can't change the AMR */
- mtspr(SPRN_UAMOR, 0);
- mtspr(SPRN_AMR, AMR_KUAP_BLOCKED);
- isync();
-}
-#endif
-
void __init radix__early_init_mmu(void)
{
unsigned long lpcr;
--
2.26.2
^ permalink raw reply related
* [PATCH v2 04/28] powerpc/book3s64/pkeys: Use MMU_FTR_PKEY instead of pkey_disabled static key
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
Instead of pkey_disabled static key use mmu feature MMU_FTR_PKEY.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/pkeys.h | 2 +-
arch/powerpc/include/asm/pkeys.h | 14 ++++++--------
arch/powerpc/mm/book3s64/pkeys.c | 16 +++++++---------
3 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/pkeys.h b/arch/powerpc/include/asm/book3s/64/pkeys.h
index 8174662a9173..5b178139f3c0 100644
--- a/arch/powerpc/include/asm/book3s/64/pkeys.h
+++ b/arch/powerpc/include/asm/book3s/64/pkeys.h
@@ -7,7 +7,7 @@
static inline u64 vmflag_to_pte_pkey_bits(u64 vm_flags)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return 0x0UL;
if (radix_enabled())
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index 09fbaa409ac4..b1d448c53209 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -11,7 +11,6 @@
#include <linux/jump_label.h>
#include <asm/firmware.h>
-DECLARE_STATIC_KEY_FALSE(pkey_disabled);
extern int max_pkey;
extern u32 reserved_allocation_mask; /* bits set for reserved keys */
@@ -38,7 +37,7 @@ static inline u64 pkey_to_vmflag_bits(u16 pkey)
static inline int vma_pkey(struct vm_area_struct *vma)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return 0;
return (vma->vm_flags & ARCH_VM_PKEY_FLAGS) >> VM_PKEY_SHIFT;
}
@@ -93,9 +92,8 @@ static inline int mm_pkey_alloc(struct mm_struct *mm)
u32 all_pkeys_mask = (u32)(~(0x0));
int ret;
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return -1;
-
/*
* Are we out of pkeys? We must handle this specially because ffz()
* behavior is undefined if there are no zeros.
@@ -111,7 +109,7 @@ static inline int mm_pkey_alloc(struct mm_struct *mm)
static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return -1;
if (!mm_pkey_is_allocated(mm, pkey))
@@ -132,7 +130,7 @@ extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma,
static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
int prot, int pkey)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return 0;
/*
@@ -150,7 +148,7 @@ extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
unsigned long init_val)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return -EINVAL;
/*
@@ -167,7 +165,7 @@ static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
static inline bool arch_pkeys_enabled(void)
{
- return !static_branch_likely(&pkey_disabled);
+ return mmu_has_feature(MMU_FTR_PKEY);
}
extern void pkey_mm_init(struct mm_struct *mm);
diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c
index fed4f159011b..810118123e70 100644
--- a/arch/powerpc/mm/book3s64/pkeys.c
+++ b/arch/powerpc/mm/book3s64/pkeys.c
@@ -13,7 +13,6 @@
#include <linux/of_fdt.h>
-DEFINE_STATIC_KEY_FALSE(pkey_disabled);
DEFINE_STATIC_KEY_FALSE(execute_pkey_disabled);
int max_pkey; /* Maximum key value supported */
/*
@@ -114,7 +113,6 @@ void __init pkey_early_init_devtree(void)
pkeys_total = scan_pkey_feature();
if (!pkeys_total) {
/* No support for pkey. Mark it disabled */
- static_branch_enable(&pkey_disabled);
return;
}
@@ -202,7 +200,7 @@ void __init pkey_early_init_devtree(void)
void pkey_mm_init(struct mm_struct *mm)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return;
mm_pkey_allocation_map(mm) = initial_allocation_mask;
mm->context.execute_only_pkey = execute_only_key;
@@ -306,7 +304,7 @@ int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
void thread_pkey_regs_save(struct thread_struct *thread)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return;
/*
@@ -320,7 +318,7 @@ void thread_pkey_regs_save(struct thread_struct *thread)
void thread_pkey_regs_restore(struct thread_struct *new_thread,
struct thread_struct *old_thread)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return;
if (old_thread->amr != new_thread->amr)
@@ -333,7 +331,7 @@ void thread_pkey_regs_restore(struct thread_struct *new_thread,
void thread_pkey_regs_init(struct thread_struct *thread)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return;
thread->amr = default_amr;
@@ -408,7 +406,7 @@ static bool pkey_access_permitted(int pkey, bool write, bool execute)
bool arch_pte_access_permitted(u64 pte, bool write, bool execute)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return true;
return pkey_access_permitted(pte_to_pkey_bits(pte), write, execute);
@@ -425,7 +423,7 @@ bool arch_pte_access_permitted(u64 pte, bool write, bool execute)
bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write,
bool execute, bool foreign)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return true;
/*
* Do not enforce our key-permissions on a foreign vma.
@@ -438,7 +436,7 @@ bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write,
void arch_dup_pkeys(struct mm_struct *oldmm, struct mm_struct *mm)
{
- if (static_branch_likely(&pkey_disabled))
+ if (!mmu_has_feature(MMU_FTR_PKEY))
return;
/* Duplicate the oldmm pkey state in mm: */
--
2.26.2
^ permalink raw reply related
* [PATCH v2 03/28] powerpc/book3s64/pkeys: Use execute_pkey_disable static key
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
Use execute_pkey_disabled static key to check for execute key support instead
of pkey_disabled.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/pkeys.h | 10 +---------
arch/powerpc/mm/book3s64/pkeys.c | 5 ++++-
2 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h
index 47c81d41ea9a..09fbaa409ac4 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -126,15 +126,7 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
* Try to dedicate one of the protection keys to be used as an
* execute-only protection key.
*/
-extern int __execute_only_pkey(struct mm_struct *mm);
-static inline int execute_only_pkey(struct mm_struct *mm)
-{
- if (static_branch_likely(&pkey_disabled))
- return -1;
-
- return __execute_only_pkey(mm);
-}
-
+extern int execute_only_pkey(struct mm_struct *mm);
extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma,
int prot, int pkey);
static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c
index bbba9c601e14..fed4f159011b 100644
--- a/arch/powerpc/mm/book3s64/pkeys.c
+++ b/arch/powerpc/mm/book3s64/pkeys.c
@@ -345,8 +345,11 @@ void thread_pkey_regs_init(struct thread_struct *thread)
write_uamor(default_uamor);
}
-int __execute_only_pkey(struct mm_struct *mm)
+int execute_only_pkey(struct mm_struct *mm)
{
+ if (static_branch_likely(&execute_pkey_disabled))
+ return -1;
+
return mm->context.execute_only_pkey;
}
--
2.26.2
^ permalink raw reply related
* [PATCH v2 02/28] powerpc/book3s64/kuep: Add MMU_FTR_KUEP
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
This will be used to enable/disable Kernel Userspace Execution
Prevention (KUEP).
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/mmu.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index 0e5d7ed9fcd6..b26af5aac5a6 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -24,6 +24,7 @@
/* Radix page table supported and enabled */
#define MMU_FTR_TYPE_RADIX ASM_CONST(0x00000040)
#define MMU_FTR_PKEY ASM_CONST(0x00000080)
+#define MMU_FTR_KUEP ASM_CONST(0x00000100)
/*
* Individual features below.
@@ -180,6 +181,10 @@ enum {
#ifdef CONFIG_PPC_MEM_KEYS
MMU_FTR_PKEY |
#endif
+#ifdef CONFIG_PPC_KUEP
+ MMU_FTR_KUEP |
+#endif /* CONFIG_PPC_KUAP */
+
0,
};
--
2.26.2
^ permalink raw reply related
* [PATCH v2 01/28] powerpc/book3s64/pkeys: Enable MMU_FTR_PKEY
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
In-Reply-To: <20200502112229.545331-1-aneesh.kumar@linux.ibm.com>
Parse storage keys related device tree entry in early_init_devtree
and enable MMU feature MMU_FTR_PKEY if pkeys are supported.
MMU feature is used instead of CPU feature because this enables us
to group MMU_FTR_KUAP and MMU_FTR_PKEY in asm feature fixup code.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/mmu.h | 6 +++
arch/powerpc/include/asm/mmu.h | 6 +++
arch/powerpc/kernel/prom.c | 5 +++
arch/powerpc/mm/book3s64/pkeys.c | 54 ++++++++++++++----------
4 files changed, 48 insertions(+), 23 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
index f0a9ff690881..10f54288b3b7 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu.h
@@ -209,6 +209,12 @@ extern int mmu_io_psize;
void mmu_early_init_devtree(void);
void hash__early_init_devtree(void);
void radix__early_init_devtree(void);
+#ifdef CONFIG_PPC_MEM_KEYS
+void pkey_early_init_devtree(void);
+#else
+static inline void pkey_early_init_devtree(void) {}
+#endif
+
extern void hash__early_init_mmu(void);
extern void radix__early_init_mmu(void);
static inline void early_init_mmu(void)
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index 0699cfeeb8c9..0e5d7ed9fcd6 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -23,6 +23,7 @@
/* Radix page table supported and enabled */
#define MMU_FTR_TYPE_RADIX ASM_CONST(0x00000040)
+#define MMU_FTR_PKEY ASM_CONST(0x00000080)
/*
* Individual features below.
@@ -176,6 +177,9 @@ enum {
MMU_FTR_RADIX_KUAP |
#endif /* CONFIG_PPC_KUAP */
#endif /* CONFIG_PPC_RADIX_MMU */
+#ifdef CONFIG_PPC_MEM_KEYS
+ MMU_FTR_PKEY |
+#endif
0,
};
@@ -364,6 +368,8 @@ extern void setup_initial_memory_limit(phys_addr_t first_memblock_base,
phys_addr_t first_memblock_size);
static inline void mmu_early_init_devtree(void) { }
+static inline void pkey_early_init_devtree(void) {}
+
extern void *abatron_pteptrs[2];
#endif /* __ASSEMBLY__ */
#endif
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 6620f37abe73..6266bfb72aae 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -791,6 +791,11 @@ void __init early_init_devtree(void *params)
/* Now try to figure out if we are running on LPAR and so on */
pseries_probe_fw_features();
+ /*
+ * Initialize pkey features and default AMR/IAMR values
+ */
+ pkey_early_init_devtree();
+
#ifdef CONFIG_PPC_PS3
/* Identify PS3 firmware */
if (of_flat_dt_is_compatible(of_get_flat_dt_root(), "sony,ps3"))
diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c
index 0ff59acdbb84..bbba9c601e14 100644
--- a/arch/powerpc/mm/book3s64/pkeys.c
+++ b/arch/powerpc/mm/book3s64/pkeys.c
@@ -10,7 +10,8 @@
#include <asm/mmu.h>
#include <asm/setup.h>
#include <linux/pkeys.h>
-#include <linux/of_device.h>
+#include <linux/of_fdt.h>
+
DEFINE_STATIC_KEY_FALSE(pkey_disabled);
DEFINE_STATIC_KEY_FALSE(execute_pkey_disabled);
@@ -38,38 +39,45 @@ static int execute_only_key = 2;
#define PKEY_REG_BITS (sizeof(u64) * 8)
#define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey+1) * AMR_BITS_PER_PKEY))
+static int __init dt_scan_storage_keys(unsigned long node,
+ const char *uname, int depth,
+ void *data)
+{
+ const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+ const __be32 *prop;
+ int pkeys_total;
+
+ /* We are scanning "cpu" nodes only */
+ if (type == NULL || strcmp(type, "cpu") != 0)
+ return 0;
+
+ prop = of_get_flat_dt_prop(node, "ibm,processor-storage-keys", NULL);
+ if (!prop)
+ return 0;
+ pkeys_total = be32_to_cpu(prop[0]);
+ return pkeys_total;
+}
+
static int scan_pkey_feature(void)
{
- u32 vals[2];
- int pkeys_total = 0;
- struct device_node *cpu;
+ int pkeys_total;
/*
* Pkey is not supported with Radix translation.
*/
- if (radix_enabled())
+ if (early_radix_enabled())
return 0;
- cpu = of_find_node_by_type(NULL, "cpu");
- if (!cpu)
- return 0;
+ pkeys_total = of_scan_flat_dt(dt_scan_storage_keys, NULL);
+ if (pkeys_total == 0) {
- if (of_property_read_u32_array(cpu,
- "ibm,processor-storage-keys", vals, 2) == 0) {
- /*
- * Since any pkey can be used for data or execute, we will
- * just treat all keys as equal and track them as one entity.
- */
- pkeys_total = vals[0];
- /* Should we check for IAMR support FIXME!! */
- } else {
/*
* Let's assume 32 pkeys on P8 bare metal, if its not defined by device
* tree. We make this exception since skiboot forgot to expose this
* property on power8.
*/
if (!firmware_has_feature(FW_FEATURE_LPAR) &&
- cpu_has_feature(CPU_FTRS_POWER8))
+ early_cpu_has_feature(CPU_FTRS_POWER8))
pkeys_total = 32;
}
@@ -82,7 +90,7 @@ static int scan_pkey_feature(void)
return pkeys_total;
}
-static int pkey_initialize(void)
+void __init pkey_early_init_devtree(void)
{
int pkeys_total, i;
@@ -107,9 +115,11 @@ static int pkey_initialize(void)
if (!pkeys_total) {
/* No support for pkey. Mark it disabled */
static_branch_enable(&pkey_disabled);
- return 0;
+ return;
}
+ cur_cpu_spec->mmu_features |= MMU_FTR_PKEY;
+
/*
* The device tree cannot be relied to indicate support for
* execute_disable support. Instead we use a PVR check.
@@ -187,11 +197,9 @@ static int pkey_initialize(void)
*/
initial_allocation_mask |= reserved_allocation_mask;
- return 0;
+ return;
}
-arch_initcall(pkey_initialize);
-
void pkey_mm_init(struct mm_struct *mm)
{
if (static_branch_likely(&pkey_disabled))
--
2.26.2
^ permalink raw reply related
* [PATCH v2 00/28] Kernel userspace access/execution prevention with hash translation
From: Aneesh Kumar K.V @ 2020-05-02 11:22 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V, linuxram, bauerman, npiggin
This patch series implements KUAP and KUEP with hash translation mode using
memory keys. The kernel now uses memory protection key 3 to control access
to the kernel. Kernel page table entries are now configured with key 3.
Access to locations configured with any other key value is denied when in
kernel mode (MSR_PR=0). This includes userspace which is by default configured
with key 0.
Changes from V1:
* Rebased on latest kernel
* Depends on the below patch sets.
https://lore.kernel.org/linuxppc-dev/20200429065654.1677541-1-npiggin@gmail.com
https://lore.kernel.org/linuxppc-dev/20200428123130.73078-1-mpe@ellerman.id.au
https://lore.kernel.org/linuxppc-dev/20200502111347.541836-1-aneesh.kumar@linux.ibm.com
Aneesh Kumar K.V (28):
powerpc/book3s64/pkeys: Enable MMU_FTR_PKEY
powerpc/book3s64/kuep: Add MMU_FTR_KUEP
powerpc/book3s64/pkeys: Use execute_pkey_disable static key
powerpc/book3s64/pkeys: Use MMU_FTR_PKEY instead of pkey_disabled
static key
powerpc/book3s64/kuap: Move KUAP related function outside radix
powerpc/book3s64/kuep: Move KUEP related function outside radix
powerpc/book3s64/kuap: Rename MMU_FTR_RADIX_KUAP to MMU_FTR_KUAP
powerpc/book3s64/kuap/kuep: Make KUAP and KUEP a subfeature of
PPC_MEM_KEYS
powerpc/book3s64/kuap: Move UAMOR setup to key init function
powerpc/book3s64/kuap: Use Key 3 for kernel mapping with hash
translation
powerpc/exec: Set thread.regs early during exec
powerpc/book3s64/pkeys: Store/restore userspace AMR correctly on entry
and exit from kernel
powerpc/book3s64/kuep: Store/restore userspace IAMR correctly on entry
and exit from kernel
powerpc/book3s64/pkeys: Inherit correctly on fork.
powerpc/book3s64/pkeys: Reset userspace AMR correctly on exec
powerpc/ptrace-view: Use pt_regs values instead of thread_struct based
one.
powerpc/book3s64/pkeys: Don't update SPRN_AMR when in kernel mode.
powerpc/book3s64/kuap: Restrict access to userspace based on userspace
AMR
powerpc/book3s64/kuap: Improve error reporting with KUAP
powerpc/book3s64/kuap: Use Key 3 to implement KUAP with hash
translation.
powerpc/book3s64/kuep: Use Key 3 to implement KUEP with hash
translation.
powerpc/book3s64/hash/kuap: Enable kuap on hash
powerpc/book3s64/hash/kuep: Enable KUEP on hash
powerpc/book3s64/keys: Print information during boot.
powerpc/selftest/ptrave-pkey: Rename variables to make it easier to
follow code
powerpc/selftest/ptrace-pkey: Update the test to mark an invalid pkey
correctly
powerpc/selftest/ptrace-pkey: IAMR and uamor cannot be updated by
ptrace
powerpc/book3s64/keys/kuap: Reset AMR/IAMR values on kexec
arch/powerpc/include/asm/book3s/32/kup.h | 4 +-
.../powerpc/include/asm/book3s/64/hash-pkey.h | 24 +-
arch/powerpc/include/asm/book3s/64/hash.h | 3 +-
.../powerpc/include/asm/book3s/64/kup-radix.h | 187 ---------
arch/powerpc/include/asm/book3s/64/kup.h | 385 ++++++++++++++++++
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 1 +
arch/powerpc/include/asm/book3s/64/mmu.h | 6 +
arch/powerpc/include/asm/book3s/64/pkeys.h | 2 +-
arch/powerpc/include/asm/kup.h | 20 +-
arch/powerpc/include/asm/mmu.h | 17 +-
arch/powerpc/include/asm/mmu_context.h | 2 +-
arch/powerpc/include/asm/nohash/32/kup-8xx.h | 4 +-
arch/powerpc/include/asm/pkeys.h | 24 +-
arch/powerpc/include/asm/processor.h | 5 -
arch/powerpc/include/asm/ptrace.h | 6 +-
arch/powerpc/kernel/asm-offsets.c | 4 +
arch/powerpc/kernel/entry_64.S | 6 +-
arch/powerpc/kernel/exceptions-64s.S | 4 +-
arch/powerpc/kernel/misc_64.S | 14 -
arch/powerpc/kernel/process.c | 54 ++-
arch/powerpc/kernel/prom.c | 5 +
arch/powerpc/kernel/ptrace/ptrace-view.c | 23 +-
arch/powerpc/kernel/smp.c | 5 +
arch/powerpc/kernel/syscall_64.c | 30 +-
arch/powerpc/kernel/traps.c | 6 -
arch/powerpc/kexec/core_64.c | 3 +
arch/powerpc/mm/book3s64/hash_4k.c | 2 +-
arch/powerpc/mm/book3s64/hash_64k.c | 4 +-
arch/powerpc/mm/book3s64/hash_hugepage.c | 2 +-
arch/powerpc/mm/book3s64/hash_hugetlbpage.c | 2 +-
arch/powerpc/mm/book3s64/hash_pgtable.c | 2 +-
arch/powerpc/mm/book3s64/hash_utils.c | 10 +-
arch/powerpc/mm/book3s64/pgtable.c | 3 +
arch/powerpc/mm/book3s64/pkeys.c | 221 +++++-----
arch/powerpc/mm/book3s64/radix_pgtable.c | 36 --
arch/powerpc/mm/fault.c | 2 +-
arch/powerpc/platforms/Kconfig.cputype | 4 +-
.../selftests/powerpc/ptrace/ptrace-pkey.c | 53 +--
38 files changed, 723 insertions(+), 462 deletions(-)
delete mode 100644 arch/powerpc/include/asm/book3s/64/kup-radix.h
create mode 100644 arch/powerpc/include/asm/book3s/64/kup.h
--
2.26.2
^ permalink raw reply
* [RFC PATCH 10/10] powerpc/powernv: OPAL V4 Implement vm_map/unmap service
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20200502111914.166578-1-npiggin@gmail.com>
This implements os_vm_map, os_vm_unmap. OPAL uses EA regions that
is specifies in OPAL_FIND_VM_AREA for these mappings, so provided
the page tables are allocated at init-time and not freed, these
services can be provided without memory allocation / blocking.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/opal-api.h | 2 +
arch/powerpc/platforms/powernv/opal.c | 57 +++++++++++++++++++++++++++
2 files changed, 59 insertions(+)
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 1b2f176677fc..97c5e5423827 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -1205,6 +1205,8 @@ struct opal_vm_area {
struct opal_os_ops {
__be64 os_printf; /* void printf(int32_t level, const char *str) */
+ __be64 os_vm_map; /* int64_t os_vm_map(uint64_t ea, uint64_t pa, uint64_t flags) */
+ __be64 os_vm_unmap; /* void os_vm_unmap(uint64_t ea) */
};
#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 0fbfcd088c58..93b9afaf33b3 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -1095,6 +1095,61 @@ static pgprot_t opal_vm_flags_to_prot(uint64_t flags)
return prot;
}
+static int64_t os_vm_map(uint64_t ea, uint64_t pa, uint64_t flags)
+{
+ struct mm_struct *mm = opal_mm;
+ spinlock_t *ptl;
+ pte_t pte, *ptep;
+ pgprot_t prot;
+
+ if (WARN_ON_ONCE(!opal_mm_enabled))
+ return -EINVAL;
+
+ if (WARN_ON_ONCE(!(mfmsr() & (MSR_IR|MSR_DR))))
+ return -EINVAL;
+
+ /* mm should be active_mm if MMU is on here */
+
+// printk("os_vm_map 0x%llx->0x%llx flags=0x%llx\n", ea, pa, flags);
+
+ prot = opal_vm_flags_to_prot(flags);
+
+ pte = pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL_X);
+
+ ptep = get_locked_pte(mm, ea, &ptl);
+ set_pte_at(mm, ea, ptep, pte);
+ pte_unmap_unlock(ptep, ptl);
+
+ return 0;
+}
+
+static void os_vm_unmap(uint64_t ea)
+{
+ struct mm_struct *mm = opal_mm;
+ spinlock_t *ptl;
+ pte_t *ptep;
+
+ if (WARN_ON_ONCE(!opal_mm_enabled))
+ return;
+
+ if (WARN_ON_ONCE(!(mfmsr() & (MSR_IR|MSR_DR))))
+ return;
+
+// printk("os_vm_unmap 0x%llx\n", ea);
+
+ /* mm should be active_mm if MMU is on here */
+
+ ptep = get_locked_pte(mm, ea, &ptl);
+ pte_clear(mm, ea, ptep);
+ pte_unmap_unlock(ptep, ptl);
+
+ /*
+ * This leaves potential TLBs in other CPUs for this EA, but it is
+ * only used by this CPU. Can't do a broadcast flush here, no IPIs.
+ */
+ local_flush_tlb_mm(mm);
+}
+
static int __init opal_init_mm(void)
{
struct mm_struct *mm;
@@ -1174,6 +1229,8 @@ static int __init opal_init_early(void)
memset(&opal_os_ops, 0, sizeof(opal_os_ops));
opal_os_ops.os_printf = cpu_to_be64(&os_printf);
+ opal_os_ops.os_vm_map = cpu_to_be64(&os_vm_map);
+ opal_os_ops.os_vm_unmap = cpu_to_be64(&os_vm_unmap);
if (opal_register_os_ops(&opal_os_ops, sizeof(opal_os_ops))) {
pr_warn("OPAL register OS ops failed, firmware will run in v3 mode.\n");
} else {
--
2.23.0
^ permalink raw reply related
* [RFC PATCH 09/10] powerpc/powernv: OPAL V4 OS services
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20200502111914.166578-1-npiggin@gmail.com>
This implements OPAL_REGISTER_OS_OPS and implements the printf
service.
When this API is called, OPAL switches to V4 mode which requires
the OS to subsequently handle its program interrupts and printf
calls.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/opal-api.h | 7 ++++-
arch/powerpc/include/asm/opal.h | 1 +
arch/powerpc/platforms/powernv/opal-call.c | 1 +
arch/powerpc/platforms/powernv/opal.c | 36 ++++++++++++++++++++++
4 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 0be5ff4e51b5..1b2f176677fc 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -218,7 +218,8 @@
#define OPAL_SYM_TO_ADDR 182
#define OPAL_REPORT_TRAP 183
#define OPAL_FIND_VM_AREA 184
-#define OPAL_LAST 184
+#define OPAL_REGISTER_OS_OPS 185
+#define OPAL_LAST 185
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
@@ -1202,6 +1203,10 @@ struct opal_vm_area {
__be64 vm_flags;
};
+struct opal_os_ops {
+ __be64 os_printf; /* void printf(int32_t level, const char *str) */
+};
+
#endif /* __ASSEMBLY__ */
#endif /* __OPAL_API_H */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 199b5582b700..09985b7718b3 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -406,6 +406,7 @@ void opal_psr_init(void);
void opal_sensor_groups_init(void);
int64_t opal_find_vm_area(uint64_t addr, struct opal_vm_area *opal_vm_area);
+int64_t opal_register_os_ops(struct opal_os_ops *ops, uint64_t size);
#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 4bdad3d2fa18..11f419e76059 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -350,3 +350,4 @@ OPAL_CALL(opal_addr_to_sym, OPAL_ADDR_TO_SYM);
OPAL_CALL(opal_sym_to_addr, OPAL_SYM_TO_ADDR);
OPAL_CALL(opal_report_trap, OPAL_REPORT_TRAP);
OPAL_CALL(opal_find_vm_area, OPAL_FIND_VM_AREA);
+OPAL_CALL(opal_register_os_ops, OPAL_REGISTER_OS_OPS);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 98d6d7fc5411..0fbfcd088c58 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -47,6 +47,7 @@ static LIST_HEAD(msg_list);
struct mm_struct *opal_mm __read_mostly;
bool opal_v4_present __read_mostly;
+bool opal_v4_enabled __read_mostly;
bool opal_mm_enabled __read_mostly;
/* /sys/firmware/opal */
@@ -152,6 +153,8 @@ unsigned long arch_symbol_lookup_name(const char *name)
return be64_to_cpu(addr);
}
+static void os_printf(int32_t level, const char *str);
+
int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
{
@@ -1045,6 +1048,28 @@ static void opal_init_heartbeat(void)
kopald_tsk = kthread_run(kopald, NULL, "kopald");
}
+static void os_printf(int32_t level, const char *str)
+{
+ const char *l;
+
+ /* Assuming printk does not work in real mode */
+ if (WARN_ON_ONCE(!(mfmsr() & (MSR_IR|MSR_DR))))
+ return;
+
+ switch (level) {
+ case 0: l = KERN_EMERG; break;
+ case 1: l = KERN_ALERT; break;
+ case 2: l = KERN_CRIT; break;
+ case 3: l = KERN_ERR; break;
+ case 4: l = KERN_WARNING; break;
+ case 5: l = KERN_NOTICE; break;
+ case 6: l = KERN_INFO; break;
+ case 7: l = KERN_DEBUG; break;
+ default: l = KERN_ERR;
+ }
+ printk("%s[OPAL] %s", l, str);
+}
+
static pgprot_t opal_vm_flags_to_prot(uint64_t flags)
{
pgprot_t prot;
@@ -1137,6 +1162,8 @@ static int __init opal_init_early(void)
int rc;
if (opal_v4_present) {
+ struct opal_os_ops opal_os_ops;
+
if (radix_enabled()) {
/* Hash can't resolve SLB faults to the switched mm */
rc = opal_init_mm();
@@ -1144,6 +1171,15 @@ static int __init opal_init_early(void)
pr_warn("OPAL virtual memory init failed, firmware will run in real-mode.\n");
}
}
+
+ memset(&opal_os_ops, 0, sizeof(opal_os_ops));
+ opal_os_ops.os_printf = cpu_to_be64(&os_printf);
+ if (opal_register_os_ops(&opal_os_ops, sizeof(opal_os_ops))) {
+ pr_warn("OPAL register OS ops failed, firmware will run in v3 mode.\n");
+ } else {
+ opal_v4_enabled = true;
+ pr_warn("OPAL running in v4 mode!\n");
+ }
}
return 0;
--
2.23.0
^ permalink raw reply related
* [RFC PATCH 08/10] powerpc/powernv: Set up an mm context to call OPAL in
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
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
^ permalink raw reply related
* [RFC PATCH 07/10] powerpc/powernv: Add OPAL_FIND_VM_AREA API
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20200502111914.166578-1-npiggin@gmail.com>
This will be used in the next patch.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/opal-api.h | 15 ++++++++++++++-
arch/powerpc/include/asm/opal.h | 2 ++
arch/powerpc/platforms/powernv/opal-call.c | 1 +
3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 018d4734c323..0be5ff4e51b5 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -217,7 +217,8 @@
#define OPAL_ADDR_TO_SYM 181
#define OPAL_SYM_TO_ADDR 182
#define OPAL_REPORT_TRAP 183
-#define OPAL_LAST 183
+#define OPAL_FIND_VM_AREA 184
+#define OPAL_LAST 184
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
@@ -1189,6 +1190,18 @@ struct opal_mpipl_fadump {
#define OPAL_TRAP_WARN 2
#define OPAL_TRAP_PANIC 3
+#define OS_VM_FLAG_READ 0x1
+#define OS_VM_FLAG_WRITE 0x2
+#define OS_VM_FLAG_EXECUTE 0x4
+#define OS_VM_FLAG_CI 0x8
+
+struct opal_vm_area {
+ __be64 address;
+ __be64 length;
+ __be64 pa;
+ __be64 vm_flags;
+};
+
#endif /* __ASSEMBLY__ */
#endif /* __OPAL_API_H */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index dc77c2d5e036..199b5582b700 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -405,6 +405,8 @@ void opal_powercap_init(void);
void opal_psr_init(void);
void opal_sensor_groups_init(void);
+int64_t opal_find_vm_area(uint64_t addr, struct opal_vm_area *opal_vm_area);
+
#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_OPAL_H */
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 32857254d268..e62a74dfb3d0 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -332,3 +332,4 @@ OPAL_CALL(opal_secvar_enqueue_update, OPAL_SECVAR_ENQUEUE_UPDATE);
OPAL_CALL(opal_addr_to_sym, OPAL_ADDR_TO_SYM);
OPAL_CALL(opal_sym_to_addr, OPAL_SYM_TO_ADDR);
OPAL_CALL(opal_report_trap, OPAL_REPORT_TRAP);
+OPAL_CALL(opal_find_vm_area, OPAL_FIND_VM_AREA);
--
2.23.0
^ permalink raw reply related
* [RFC PATCH 06/10] powerpc/powernv: opal use new opal call entry point if it exists
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20200502111914.166578-1-npiggin@gmail.com>
OPAL may advertise new endian-specific entry point which has different
calling conventions including using the caller's stack, but otherwise
provides the standard OPAL call API without any changes required to
the OS.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/boot/opal.c | 5 +++
arch/powerpc/platforms/powernv/opal-call.c | 36 ++++++++++++++++++++++
arch/powerpc/platforms/powernv/opal.c | 30 +++++++++++-------
3 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/boot/opal.c b/arch/powerpc/boot/opal.c
index b69818ce592b..8b006a0282ac 100644
--- a/arch/powerpc/boot/opal.c
+++ b/arch/powerpc/boot/opal.c
@@ -13,6 +13,7 @@
struct opal {
u64 base;
u64 entry;
+ u64 v4_le_entry;
} opal;
static u32 opal_con_id;
@@ -75,6 +76,10 @@ static void opal_init(void)
if (getprop(opal_node, "opal-entry-address", &opal.entry, sizeof(u64)) < 0)
return;
opal.entry = be64_to_cpu(opal.entry);
+
+ if (getprop(opal_node, "opal-v4-le-entry-address", &opal.v4_le_entry, sizeof(u64)) < 0)
+ return;
+ opal.v4_le_entry = be64_to_cpu(opal.v4_le_entry);
}
int opal_console_init(void *devp, struct serial_console_data *scdp)
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 506b1798081a..32857254d268 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -92,6 +92,18 @@ static s64 __opal_call_trace(s64 a0, s64 a1, s64 a2, s64 a3,
#define DO_TRACE false
#endif /* CONFIG_TRACEPOINTS */
+struct opal {
+ u64 base;
+ u64 entry;
+ u64 size;
+ u64 v4_le_entry;
+};
+extern struct opal opal;
+
+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);
+
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)
{
@@ -99,6 +111,30 @@ static int64_t opal_call(int64_t a0, int64_t a1, int64_t a2, int64_t a3,
unsigned long msr = mfmsr();
bool mmu = (msr & (MSR_IR|MSR_DR));
int64_t ret;
+ opal_v4_le_entry_fn fn;
+
+ if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
+ fn = (opal_v4_le_entry_fn)(opal.v4_le_entry);
+
+ if (fn) {
+ if (!mmu) {
+ BUG_ON(msr & MSR_EE);
+ ret = fn(opcode, a0, a1, a2, a3, a4, a5, a6);
+ return ret;
+ }
+
+ local_irq_save(flags);
+ hard_irq_disable(); /* XXX r13 */
+ msr &= ~MSR_EE;
+ mtmsr(msr & ~(MSR_IR|MSR_DR));
+
+ ret = fn(opcode, a0, a1, a2, a3, a4, a5, a6);
+
+ mtmsr(msr);
+ local_irq_restore(flags);
+
+ return ret;
+ }
msr &= ~MSR_EE;
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index a0e9808237b2..d00772d40680 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -46,13 +46,14 @@ static DEFINE_SPINLOCK(msg_list_lock);
static LIST_HEAD(msg_list);
/* /sys/firmware/opal */
-struct kobject *opal_kobj;
+struct kobject *opal_kobj __read_mostly;
struct opal {
u64 base;
u64 entry;
u64 size;
-} opal;
+ u64 v4_le_entry;
+} opal __read_mostly;
struct mcheck_recoverable_range {
u64 start_addr;
@@ -150,14 +151,15 @@ unsigned long arch_symbol_lookup_name(const char *name)
int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
{
- const void *basep, *entryp, *sizep;
- int basesz, entrysz, runtimesz;
+ const void *basep, *entryp, *v4_le_entryp, *sizep;
+ int basesz, entrysz, v4_le_entrysz, runtimesz;
if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
return 0;
basep = of_get_flat_dt_prop(node, "opal-base-address", &basesz);
entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz);
+ v4_le_entryp = of_get_flat_dt_prop(node, "opal-v4-le-entry-address", &v4_le_entrysz);
sizep = of_get_flat_dt_prop(node, "opal-runtime-size", &runtimesz);
if (!basep || !entryp || !sizep)
@@ -166,19 +168,25 @@ int __init early_init_dt_scan_opal(unsigned long node,
opal.base = of_read_number(basep, basesz/4);
opal.entry = of_read_number(entryp, entrysz/4);
opal.size = of_read_number(sizep, runtimesz/4);
+ opal.v4_le_entry = of_read_number(v4_le_entryp, v4_le_entrysz/4);
+
+ if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
+ powerpc_firmware_features |= FW_FEATURE_OPAL;
+ pr_debug("OPAL detected !\n");
+ } else {
+ panic("OPAL v3 compatible firmware not detected, can not continue.\n");
+ }
pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%d)\n",
opal.base, basep, basesz);
- pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%d)\n",
+ pr_debug("OPAL Entry = 0x%llx (entryp=%p entrysz=%d)\n",
opal.entry, entryp, entrysz);
- pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%d)\n",
+ pr_debug("OPAL Size = 0x%llx (sizep=%p runtimesz=%d)\n",
opal.size, sizep, runtimesz);
+ if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN) && v4_le_entryp) {
- if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
- powerpc_firmware_features |= FW_FEATURE_OPAL;
- pr_debug("OPAL detected !\n");
- } else {
- panic("OPAL != V3 detected, no longer supported.\n");
+ 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);
}
return 1;
--
2.23.0
^ permalink raw reply related
* [RFC PATCH 05/10] powerpc/powernv: Don't translate kernel addresses to real addresses for OPAL
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20200502111914.166578-1-npiggin@gmail.com>
A random assortment of OPAL callers use __pa() on pointers (others don't).
This is not required because __pa() behaves the same as __va() when
translation is off. In order to run OPAL with translation on, the
effective addresses have to be used.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/perf/imc-pmu.c | 4 ++--
arch/powerpc/platforms/powernv/npu-dma.c | 2 +-
arch/powerpc/platforms/powernv/opal-dump.c | 2 +-
arch/powerpc/platforms/powernv/opal-elog.c | 4 ++--
arch/powerpc/platforms/powernv/opal-flash.c | 6 +++---
arch/powerpc/platforms/powernv/opal-hmi.c | 2 +-
arch/powerpc/platforms/powernv/opal-nvram.c | 4 ++--
arch/powerpc/platforms/powernv/opal-powercap.c | 2 +-
arch/powerpc/platforms/powernv/opal-psr.c | 2 +-
arch/powerpc/platforms/powernv/opal-xscom.c | 2 +-
arch/powerpc/platforms/powernv/opal.c | 6 +++---
arch/powerpc/platforms/powernv/pci-ioda.c | 2 +-
arch/powerpc/sysdev/xive/native.c | 2 +-
drivers/char/powernv-op-panel.c | 3 +--
drivers/i2c/busses/i2c-opal.c | 12 ++++++------
drivers/mtd/devices/powernv_flash.c | 4 ++--
16 files changed, 29 insertions(+), 30 deletions(-)
diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c
index eb82dda884e5..332c7a3398f3 100644
--- a/arch/powerpc/perf/imc-pmu.c
+++ b/arch/powerpc/perf/imc-pmu.c
@@ -610,7 +610,7 @@ static int core_imc_mem_init(int cpu, int size)
mutex_init(&core_imc_refc[core_id].lock);
rc = opal_imc_counters_init(OPAL_IMC_COUNTERS_CORE,
- __pa((void *)mem_info->vbase),
+ (u64)mem_info->vbase,
get_hard_smp_processor_id(cpu));
if (rc) {
free_pages((u64)mem_info->vbase, get_order(size));
@@ -1209,7 +1209,7 @@ static int trace_imc_mem_alloc(int cpu_id, int size)
per_cpu(trace_imc_mem, cpu_id) = local_mem;
/* Initialise the counters for trace mode */
- rc = opal_imc_counters_init(OPAL_IMC_COUNTERS_TRACE, __pa((void *)local_mem),
+ rc = opal_imc_counters_init(OPAL_IMC_COUNTERS_TRACE, (u64)local_mem,
get_hard_smp_processor_id(cpu_id));
if (rc) {
pr_info("IMC:opal init failed for trace imc\n");
diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c
index b95b9e3c4c98..9d38a30cc27e 100644
--- a/arch/powerpc/platforms/powernv/npu-dma.c
+++ b/arch/powerpc/platforms/powernv/npu-dma.c
@@ -149,7 +149,7 @@ static long pnv_npu_set_window(struct iommu_table_group *table_group, int num,
npe->pe_number,
npe->pe_number,
tbl->it_indirect_levels + 1,
- __pa(tbl->it_base),
+ __pa(tbl->it_base), /* XXX? */
size << 3,
IOMMU_PAGE_SIZE(tbl));
if (rc) {
diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
index 543c816fa99e..94d5fb716a32 100644
--- a/arch/powerpc/platforms/powernv/opal-dump.c
+++ b/arch/powerpc/platforms/powernv/opal-dump.c
@@ -256,7 +256,7 @@ static int64_t dump_read_data(struct dump_obj *dump)
}
/* First entry address */
- addr = __pa(list);
+ addr = (u64)list;
/* Fetch data */
rc = OPAL_BUSY_EVENT;
diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c
index 62ef7ad995da..6af5ff892195 100644
--- a/arch/powerpc/platforms/powernv/opal-elog.c
+++ b/arch/powerpc/platforms/powernv/opal-elog.c
@@ -163,7 +163,7 @@ static ssize_t raw_attr_read(struct file *filep, struct kobject *kobj,
if (!elog->buffer)
return -EIO;
- opal_rc = opal_read_elog(__pa(elog->buffer),
+ opal_rc = opal_read_elog((u64)elog->buffer,
elog->size, elog->id);
if (opal_rc != OPAL_SUCCESS) {
pr_err("ELOG: log read failed for log-id=%llx\n",
@@ -206,7 +206,7 @@ static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
elog->buffer = kzalloc(elog->size, GFP_KERNEL);
if (elog->buffer) {
- rc = opal_read_elog(__pa(elog->buffer),
+ rc = opal_read_elog((u64)elog->buffer,
elog->size, elog->id);
if (rc != OPAL_SUCCESS) {
pr_err("ELOG: log read failed for log-id=%llx\n",
diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c
index 7e7d38b17420..46f02279d36a 100644
--- a/arch/powerpc/platforms/powernv/opal-flash.c
+++ b/arch/powerpc/platforms/powernv/opal-flash.c
@@ -130,11 +130,11 @@ static DEFINE_MUTEX(image_data_mutex);
static inline void opal_flash_validate(void)
{
long ret;
- void *buf = validate_flash_data.buf;
+ u64 buf = (u64)validate_flash_data.buf;
__be32 size = cpu_to_be32(validate_flash_data.buf_size);
__be32 result;
- ret = opal_validate_flash(__pa(buf), &size, &result);
+ ret = opal_validate_flash(buf, &size, &result);
validate_flash_data.status = ret;
validate_flash_data.buf_size = be32_to_cpu(size);
@@ -290,7 +290,7 @@ static int opal_flash_update(int op)
goto invalid_img;
/* First entry address */
- addr = __pa(list);
+ addr = (u64)list;
flash:
rc = opal_update_flash(addr);
diff --git a/arch/powerpc/platforms/powernv/opal-hmi.c b/arch/powerpc/platforms/powernv/opal-hmi.c
index 3e1f064a18db..7c51baeb62ff 100644
--- a/arch/powerpc/platforms/powernv/opal-hmi.c
+++ b/arch/powerpc/platforms/powernv/opal-hmi.c
@@ -298,7 +298,7 @@ static void hmi_event_handler(struct work_struct *work)
if (unrecoverable) {
/* Pull all HMI events from OPAL before we panic. */
- while (opal_get_msg(__pa(&msg), sizeof(msg)) == OPAL_SUCCESS) {
+ while (opal_get_msg((u64)&msg, sizeof(msg)) == OPAL_SUCCESS) {
u32 type;
type = be32_to_cpu(msg.msg_type);
diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c
index 380bc2d7ebbf..a7924dffee2b 100644
--- a/arch/powerpc/platforms/powernv/opal-nvram.c
+++ b/arch/powerpc/platforms/powernv/opal-nvram.c
@@ -33,7 +33,7 @@ static ssize_t opal_nvram_read(char *buf, size_t count, loff_t *index)
off = *index;
if ((off + count) > nvram_size)
count = nvram_size - off;
- rc = opal_read_nvram(__pa(buf), count, off);
+ rc = opal_read_nvram((unsigned long)buf, count, off);
if (rc != OPAL_SUCCESS)
return -EIO;
*index += count;
@@ -56,7 +56,7 @@ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index)
count = nvram_size - off;
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
- rc = opal_write_nvram(__pa(buf), count, off);
+ rc = opal_write_nvram((unsigned long)buf, count, off);
if (rc == OPAL_BUSY_EVENT) {
if (in_interrupt() || irqs_disabled())
mdelay(OPAL_BUSY_DELAY_MS);
diff --git a/arch/powerpc/platforms/powernv/opal-powercap.c b/arch/powerpc/platforms/powernv/opal-powercap.c
index c16d44f6f1d1..a1167ecf9e43 100644
--- a/arch/powerpc/platforms/powernv/opal-powercap.c
+++ b/arch/powerpc/platforms/powernv/opal-powercap.c
@@ -46,7 +46,7 @@ static ssize_t powercap_show(struct kobject *kobj, struct kobj_attribute *attr,
if (ret)
goto out_token;
- ret = opal_get_powercap(pcap_attr->handle, token, (u32 *)__pa(&pcap));
+ ret = opal_get_powercap(pcap_attr->handle, token, &pcap);
switch (ret) {
case OPAL_ASYNC_COMPLETION:
ret = opal_async_wait_response(token, &msg);
diff --git a/arch/powerpc/platforms/powernv/opal-psr.c b/arch/powerpc/platforms/powernv/opal-psr.c
index 69d7e75950d1..a3a68f53b1f8 100644
--- a/arch/powerpc/platforms/powernv/opal-psr.c
+++ b/arch/powerpc/platforms/powernv/opal-psr.c
@@ -40,7 +40,7 @@ static ssize_t psr_show(struct kobject *kobj, struct kobj_attribute *attr,
goto out_token;
ret = opal_get_power_shift_ratio(psr_attr->handle, token,
- (u32 *)__pa(&psr));
+ (u32 *)&psr);
switch (ret) {
case OPAL_ASYNC_COMPLETION:
ret = opal_async_wait_response(token, &msg);
diff --git a/arch/powerpc/platforms/powernv/opal-xscom.c b/arch/powerpc/platforms/powernv/opal-xscom.c
index fd510d961b8c..aef596997ad4 100644
--- a/arch/powerpc/platforms/powernv/opal-xscom.c
+++ b/arch/powerpc/platforms/powernv/opal-xscom.c
@@ -58,7 +58,7 @@ static int opal_scom_read(uint32_t chip, uint64_t addr, u64 reg, u64 *value)
__be64 v;
reg = opal_scom_unmangle(addr + reg);
- rc = opal_xscom_read(chip, reg, (__be64 *)__pa(&v));
+ rc = opal_xscom_read(chip, reg, &v);
if (rc) {
*value = 0xfffffffffffffffful;
return -EIO;
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index e8eba210a92d..a0e9808237b2 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -397,7 +397,7 @@ static void opal_handle_message(void)
s64 ret;
u32 type;
- ret = opal_get_msg(__pa(opal_msg), opal_msg_size);
+ ret = opal_get_msg((u64)opal_msg, opal_msg_size);
/* No opal message pending. */
if (ret == OPAL_RESOURCE)
return;
@@ -961,7 +961,7 @@ static void __init opal_dump_region_init(void)
return;
rc = opal_register_dump_region(OPAL_DUMP_REGION_LOG_BUF,
- __pa(addr), size);
+ (u64)addr, size);
/* Don't warn if this is just an older OPAL that doesn't
* know about that call
*/
@@ -1197,7 +1197,7 @@ struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
sg->length = cpu_to_be64(
i * sizeof(struct opal_sg_entry) + 16);
i = 0;
- sg->next = cpu_to_be64(__pa(next));
+ sg->next = cpu_to_be64(next);
sg = next;
}
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 57d3a6af1d52..dc6caec7cb46 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1844,7 +1844,7 @@ static int pnv_pci_ioda_dma_64bit_bypass(struct pnv_ioda_pe *pe)
/* reconfigure window 0 */
(pe->pe_number << 1) + 0,
1,
- __pa(tces),
+ __pa(tces), /* XXX? */
table_size,
1 << tce_order);
if (rc == OPAL_SUCCESS) {
diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c
index 5218fdc4b29a..a80960829bf0 100644
--- a/arch/powerpc/sysdev/xive/native.c
+++ b/arch/powerpc/sysdev/xive/native.c
@@ -647,7 +647,7 @@ static bool xive_native_provision_pages(void)
pr_err("Failed to allocate provisioning page\n");
return false;
}
- opal_xive_donate_page(chip, __pa(p));
+ opal_xive_donate_page(chip, (u64)p);
}
return true;
}
diff --git a/drivers/char/powernv-op-panel.c b/drivers/char/powernv-op-panel.c
index 027484ecfb0d..e7569f5025ef 100644
--- a/drivers/char/powernv-op-panel.c
+++ b/drivers/char/powernv-op-panel.c
@@ -175,8 +175,7 @@ static int oppanel_probe(struct platform_device *pdev)
memset(oppanel_data, ' ', oppanel_size);
for (i = 0; i < num_lines; i++) {
oppanel_lines[i].line_len = cpu_to_be64(line_len);
- oppanel_lines[i].line = cpu_to_be64(__pa(&oppanel_data[i *
- line_len]));
+ oppanel_lines[i].line = cpu_to_be64(&oppanel_data[i * line_len]);
}
rc = misc_register(&oppanel_dev);
diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c
index 1c4c9bb06a0b..a2ea1e36d9aa 100644
--- a/drivers/i2c/busses/i2c-opal.c
+++ b/drivers/i2c/busses/i2c-opal.c
@@ -87,7 +87,7 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
req.addr = cpu_to_be16(msgs[0].addr);
req.size = cpu_to_be32(msgs[0].len);
- req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
+ req.buffer_ra = cpu_to_be64(msgs[0].buf);
break;
case 2:
req.type = (msgs[1].flags & I2C_M_RD) ?
@@ -98,7 +98,7 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
req.subaddr = (req.subaddr << 8) | msgs[0].buf[i];
req.subaddr = cpu_to_be32(req.subaddr);
req.size = cpu_to_be32(msgs[1].len);
- req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf));
+ req.buffer_ra = cpu_to_be64(msgs[1].buf);
break;
}
@@ -123,7 +123,7 @@ static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr,
req.addr = cpu_to_be16(addr);
switch (size) {
case I2C_SMBUS_BYTE:
- req.buffer_ra = cpu_to_be64(__pa(&data->byte));
+ req.buffer_ra = cpu_to_be64(&data->byte);
req.size = cpu_to_be32(1);
/* Fall through */
case I2C_SMBUS_QUICK:
@@ -131,7 +131,7 @@ static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr,
OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
break;
case I2C_SMBUS_BYTE_DATA:
- req.buffer_ra = cpu_to_be64(__pa(&data->byte));
+ req.buffer_ra = cpu_to_be64(&data->byte);
req.size = cpu_to_be32(1);
req.subaddr = cpu_to_be32(command);
req.subaddr_sz = 1;
@@ -143,7 +143,7 @@ static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr,
local[0] = data->word & 0xff;
local[1] = (data->word >> 8) & 0xff;
}
- req.buffer_ra = cpu_to_be64(__pa(local));
+ req.buffer_ra = cpu_to_be64(local);
req.size = cpu_to_be32(2);
req.subaddr = cpu_to_be32(command);
req.subaddr_sz = 1;
@@ -151,7 +151,7 @@ static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr,
OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
- req.buffer_ra = cpu_to_be64(__pa(&data->block[1]));
+ req.buffer_ra = cpu_to_be64(&data->block[1]);
req.size = cpu_to_be32(data->block[0]);
req.subaddr = cpu_to_be32(command);
req.subaddr_sz = 1;
diff --git a/drivers/mtd/devices/powernv_flash.c b/drivers/mtd/devices/powernv_flash.c
index 0b757d9ba2f6..86dbaae8808f 100644
--- a/drivers/mtd/devices/powernv_flash.c
+++ b/drivers/mtd/devices/powernv_flash.c
@@ -66,10 +66,10 @@ static int powernv_flash_async_op(struct mtd_info *mtd, enum flash_op op,
switch (op) {
case FLASH_OP_READ:
- rc = opal_flash_read(info->id, offset, __pa(buf), len, token);
+ rc = opal_flash_read(info->id, offset, (u64)buf, len, token);
break;
case FLASH_OP_WRITE:
- rc = opal_flash_write(info->id, offset, __pa(buf), len, token);
+ rc = opal_flash_write(info->id, offset, (u64)buf, len, token);
break;
case FLASH_OP_ERASE:
rc = opal_flash_erase(info->id, offset, len, token);
--
2.23.0
^ permalink raw reply related
* [RFC PATCH 04/10] powerpc/powernv: avoid polling in opal_get_chars
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20200502111914.166578-1-npiggin@gmail.com>
OPAL console IO should avoid locks and complexity where possible, to
maximise the chance of it working if there are crashes or bugs. This
poll is not necessary, opal_console_read can handle no input.
In a future patch, Linux will provide a console service to OPAL via the
OPAL console, so it must avoid using any other OPAL calls in this path.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/platforms/powernv/opal.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 1bf2e0b31ecf..e8eba210a92d 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -467,13 +467,10 @@ static int __init opal_message_init(struct device_node *opal_node)
int opal_get_chars(uint32_t vtermno, char *buf, int count)
{
s64 rc;
- __be64 evt, len;
+ __be64 len;
if (!opal.entry)
return -ENODEV;
- opal_poll_events(&evt);
- if ((be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_INPUT) == 0)
- return 0;
len = cpu_to_be64(count);
rc = opal_console_read(vtermno, &len, buf);
if (rc == OPAL_SUCCESS)
--
2.23.0
^ permalink raw reply related
* [RFC PATCH 03/10] powerpc/powernv: Use OPAL_REPORT_TRAP to cope with trap interrupts from OPAL
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20200502111914.166578-1-npiggin@gmail.com>
This isn't used yet, because OPAL is nice enough not to cause unexpected
program check interrupts to the OS. A future patch will allow OPAL to
start using traps. Like so.
[OPAL] < assert failed at core/opal.c:814 >
[OPAL] .
[OPAL] .
[OPAL] .
[OPAL] OO__)
[OPAL] <"__/
[OPAL] ^ ^
cpu 0x0: Vector: 700 (Program Check) at [c000000080287770]
pc: 000000003002f360: opal_poll_events+0x54/0x174 [OPAL]
lr: 000000003002f344: opal_poll_events+0x38/0x174 [OPAL]
sp: c000000080287a00
msr: 9000000000021033
current = 0xc0000000016fa100
paca = 0xc0000000012c0000^I irqmask: 0x03^I irq_happened: 0x01
pid = 19, comm = kopald
Linux version 5.7.0-rc3-00053-g2d9c3c965178-dirty
enter ? for help
[c000000080287a80] 000000003002e6b8 opal_v4_le_entry+0x224/0x29c [OPAL]
[c000000080287b50] c000000000096ce8 opal_call+0x1c8/0x580
[c000000080287c90] c000000000097448 opal_poll_events+0x28/0x40
[c000000080287d00] c0000000000a26e0 opal_handle_events+0x70/0x140
[c000000080287d50] c00000000009a198 kopald+0x98/0x140
[c000000080287db0] c00000000012139c kthread+0x18c/0x1a0
[c000000080287e20] c00000000000cc28 ret_from_kernel_thread+0x5c/0x74
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/opal-api.h | 7 +++-
arch/powerpc/include/asm/opal.h | 2 ++
arch/powerpc/kernel/traps.c | 39 ++++++++++++++++------
arch/powerpc/platforms/powernv/opal-call.c | 1 +
4 files changed, 37 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 8eb31b9aeb27..018d4734c323 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -216,7 +216,8 @@
#define OPAL_SECVAR_ENQUEUE_UPDATE 178
#define OPAL_ADDR_TO_SYM 181
#define OPAL_SYM_TO_ADDR 182
-#define OPAL_LAST 182
+#define OPAL_REPORT_TRAP 183
+#define OPAL_LAST 183
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
@@ -1184,6 +1185,10 @@ struct opal_mpipl_fadump {
struct opal_mpipl_region region[];
} __packed;
+#define OPAL_TRAP_FATAL 1
+#define OPAL_TRAP_WARN 2
+#define OPAL_TRAP_PANIC 3
+
#endif /* __ASSEMBLY__ */
#endif /* __OPAL_API_H */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 56b6994aefb7..dc77c2d5e036 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -314,6 +314,8 @@ s64 opal_quiesce(u64 shutdown_type, s32 cpu);
int64_t opal_addr_to_sym(uint64_t addr, __be64 *symaddr, __be64 *symsize, char *namebuf, uint64_t buflen);
int64_t opal_sym_to_addr(const char *name, __be64 *symaddr, __be64 *symsize);
+int64_t opal_report_trap(uint64_t nip);
+
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 3fca22276bb1..0274ae7b8a03 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -52,6 +52,7 @@
#endif
#ifdef CONFIG_PPC64
#include <asm/firmware.h>
+#include <asm/opal.h>
#include <asm/processor.h>
#include <asm/tm.h>
#endif
@@ -1471,7 +1472,6 @@ void program_check_exception(struct pt_regs *regs)
goto bail;
}
if (reason & REASON_TRAP) {
- unsigned long bugaddr;
/* Debugger is first in line to stop recursive faults in
* rcu_lock, notify_die, or atomic_notifier_call_chain */
if (debugger_bpt(regs))
@@ -1485,18 +1485,35 @@ void program_check_exception(struct pt_regs *regs)
== NOTIFY_STOP)
goto bail;
- bugaddr = regs->nip;
- /*
- * Fixup bugaddr for BUG_ON() in real mode
- */
- if (!is_kernel_addr(bugaddr) && !(regs->msr & MSR_IR))
- bugaddr += PAGE_OFFSET;
+ if (!(regs->msr & MSR_PR)) { /* not user-mode */
+ unsigned long bugaddr;
+ enum bug_trap_type t;
+
+ /*
+ * Fixup bugaddr for BUG_ON() in real mode
+ */
+ bugaddr = regs->nip;
+ if (!is_kernel_addr(bugaddr) && !(regs->msr & MSR_IR))
+ bugaddr += PAGE_OFFSET;
+ t = report_bug(bugaddr, regs);
+ if (t == BUG_TRAP_TYPE_WARN) {
+ regs->nip += 4;
+ goto bail;
+ }
+ if (t == BUG_TRAP_TYPE_BUG)
+ goto bug;
- if (!(regs->msr & MSR_PR) && /* not user-mode */
- report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) {
- regs->nip += 4;
- goto bail;
+ if (firmware_has_feature(FW_FEATURE_OPAL)) {
+ int64_t ret;
+
+ ret = opal_report_trap(regs->nip);
+ if (ret == OPAL_TRAP_WARN) {
+ regs->nip += 4;
+ goto bail;
+ }
+ }
}
+bug:
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
goto bail;
}
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 2233a58924cb..506b1798081a 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -295,3 +295,4 @@ OPAL_CALL(opal_secvar_get_next, OPAL_SECVAR_GET_NEXT);
OPAL_CALL(opal_secvar_enqueue_update, OPAL_SECVAR_ENQUEUE_UPDATE);
OPAL_CALL(opal_addr_to_sym, OPAL_ADDR_TO_SYM);
OPAL_CALL(opal_sym_to_addr, OPAL_SYM_TO_ADDR);
+OPAL_CALL(opal_report_trap, OPAL_REPORT_TRAP);
--
2.23.0
^ permalink raw reply related
* [RFC PATCH 02/10] powerpc/powernv: Wire up OPAL address lookups
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20200502111914.166578-1-npiggin@gmail.com>
Use ARCH_HAS_SYMBOL_LOOKUP to look up the opal symbol table. This
allows crashes and xmon debugging to print firmware symbols.
Oops: System Reset, sig: 6 [#1]
LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA PowerNV
Modules linked in:
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.6.0-rc2-dirty #903
NIP: 0000000030020434 LR: 000000003000378c CTR: 0000000030020414
REGS: c0000000fffc3d70 TRAP: 0100 Not tainted (5.6.0-rc2-dirty)
MSR: 9000000002101002 <SF,HV,VEC,ME,RI> CR: 28022284 XER: 20040000
CFAR: 0000000030003788 IRQMASK: 3
GPR00: 000000003000378c 0000000031c13c90 0000000030136200 c0000000012cfa10
GPR04: c0000000012cfa10 0000000000000010 0000000000000000 0000000031c10060
GPR08: c0000000012cfaaf 0000000030003640 0000000000000000 0000000000000001
GPR12: 00000000300e0000 c000000001490000 0000000000000000 c00000000139c588
GPR16: 0000000031c10000 c00000000125a900 0000000000000000 c0000000012076a8
GPR20: c0000000012a3950 0000000000000001 0000000031c10060 c0000000012cfaaf
GPR24: 0000000000000019 0000000030003640 0000000000000000 0000000000000000
GPR28: 0000000000000010 c0000000012cfa10 0000000000000000 0000000000000000
NIP [0000000030020434] .dummy_console_write_buffer_space+0x20/0x64 [OPAL]
LR [000000003000378c] opal_entry+0x14c/0x17c [OPAL]
This won't unwind the firmware stack (or its Linux caller) properly if
firmware and kernel endians don't match, but that problem could be solved
in powerpc's unwinder.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/opal-api.h | 4 ++-
arch/powerpc/include/asm/opal.h | 3 ++
arch/powerpc/platforms/powernv/opal-call.c | 2 ++
arch/powerpc/platforms/powernv/opal.c | 40 ++++++++++++++++++++++
5 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 924c541a9260..0be717291e38 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -115,6 +115,7 @@ config PPC
# Please keep this list sorted alphabetically.
#
select ARCH_32BIT_OFF_T if PPC32
+ select ARCH_HAS_SYMBOL_LOOKUP if PPC_POWERNV
select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 1dffa3cb16ba..8eb31b9aeb27 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -214,7 +214,9 @@
#define OPAL_SECVAR_GET 176
#define OPAL_SECVAR_GET_NEXT 177
#define OPAL_SECVAR_ENQUEUE_UPDATE 178
-#define OPAL_LAST 178
+#define OPAL_ADDR_TO_SYM 181
+#define OPAL_SYM_TO_ADDR 182
+#define OPAL_LAST 182
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 9986ac34b8e2..56b6994aefb7 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -312,6 +312,9 @@ s64 opal_mpipl_query_tag(enum opal_mpipl_tags tag, u64 *addr);
s64 opal_signal_system_reset(s32 cpu);
s64 opal_quiesce(u64 shutdown_type, s32 cpu);
+int64_t opal_addr_to_sym(uint64_t addr, __be64 *symaddr, __be64 *symsize, char *namebuf, uint64_t buflen);
+int64_t opal_sym_to_addr(const char *name, __be64 *symaddr, __be64 *symsize);
+
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
int depth, void *data);
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 5cd0f52d258f..2233a58924cb 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -293,3 +293,5 @@ OPAL_CALL(opal_mpipl_query_tag, OPAL_MPIPL_QUERY_TAG);
OPAL_CALL(opal_secvar_get, OPAL_SECVAR_GET);
OPAL_CALL(opal_secvar_get_next, OPAL_SECVAR_GET_NEXT);
OPAL_CALL(opal_secvar_enqueue_update, OPAL_SECVAR_ENQUEUE_UPDATE);
+OPAL_CALL(opal_addr_to_sym, OPAL_ADDR_TO_SYM);
+OPAL_CALL(opal_sym_to_addr, OPAL_SYM_TO_ADDR);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 2b3dfd0b6cdd..1bf2e0b31ecf 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -107,6 +107,46 @@ void opal_configure_cores(void)
cur_cpu_spec->cpu_restore();
}
+const char *arch_symbol_lookup_address(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset,
+ char **modname, char *namebuf)
+{
+ __be64 symaddr;
+ __be64 symsize;
+
+ if (!firmware_has_feature(FW_FEATURE_OPAL))
+ return NULL;
+
+ if (opal_addr_to_sym(addr, &symaddr, &symsize, namebuf,
+ cpu_to_be64(KSYM_NAME_LEN)) != OPAL_SUCCESS)
+ return NULL;
+
+ *symbolsize = be64_to_cpu(symsize);
+ *offset = addr - be64_to_cpu(symaddr);
+ *modname = "OPAL";
+
+ return namebuf;
+}
+
+unsigned long arch_symbol_lookup_name(const char *name)
+{
+ __be64 addr;
+ __be64 size;
+
+ if (!firmware_has_feature(FW_FEATURE_OPAL))
+ return 0;
+
+ /* opal: prefix allows lookup of symbols that clash with kernel */
+ if (!strncasecmp(name, "opal:", strlen("opal:")))
+ name += strlen("opal:");
+
+ if (opal_sym_to_addr(name, &addr, &size) != OPAL_SUCCESS)
+ return 0;
+
+ return be64_to_cpu(addr);
+}
+
int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
{
--
2.23.0
^ permalink raw reply related
* [RFC PATCH 00/10] OPAL V4
From: Nicholas Piggin @ 2020-05-02 11:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
"OPAL V4" is a proposed new approach to running and calling PowerNV
OPAL firmware.
OPAL calls use the caller's (kernel) stack, which vastly simplifies
re-entrancy concerns around doing things like idle and machine check
OPAL drivers.
The OS can get at symbol and assert metadata to help with debugging
firmware.
OPAL may be called (and will run in) virtual mode in its own address
space.
And the operating system provides some services to the firmware,
message logging, for example.
This fairly close to the point where we could run OPAL in user-mode
with a few services (scv could be used to call back to the OS) for
privileged instructions, we may yet do this, but one thing that's
stopped me is it would require a slower API. As it is now with LE
skiboot and LE Linux, the OPAL call is basically a shared-library
function call, which is fast enough that it's feasible to
implement a performant CPU idle driver, which is a significant
motivation.
Anyway this is up and running, coming together pretty well just needs
a bit of polishing and more documentation. I'll post the skiboot
patches on the skiboot list.
Nicholas Piggin (10):
kallsyms: architecture specific symbol lookups
powerpc/powernv: Wire up OPAL address lookups
powerpc/powernv: Use OPAL_REPORT_TRAP to cope with trap interrupts
from OPAL
powerpc/powernv: avoid polling in opal_get_chars
powerpc/powernv: Don't translate kernel addresses to real addresses
for OPAL
powerpc/powernv: opal use new opal call entry point if it exists
powerpc/powernv: Add OPAL_FIND_VM_AREA API
powerpc/powernv: Set up an mm context to call OPAL in
powerpc/powernv: OPAL V4 OS services
powerpc/powernv: OPAL V4 Implement vm_map/unmap service
arch/powerpc/Kconfig | 1 +
arch/powerpc/boot/opal.c | 5 +
arch/powerpc/include/asm/opal-api.h | 29 +-
arch/powerpc/include/asm/opal.h | 8 +
arch/powerpc/kernel/traps.c | 39 ++-
arch/powerpc/perf/imc-pmu.c | 4 +-
arch/powerpc/platforms/powernv/npu-dma.c | 2 +-
arch/powerpc/platforms/powernv/opal-call.c | 58 ++++
arch/powerpc/platforms/powernv/opal-dump.c | 2 +-
arch/powerpc/platforms/powernv/opal-elog.c | 4 +-
arch/powerpc/platforms/powernv/opal-flash.c | 6 +-
arch/powerpc/platforms/powernv/opal-hmi.c | 2 +-
arch/powerpc/platforms/powernv/opal-nvram.c | 4 +-
.../powerpc/platforms/powernv/opal-powercap.c | 2 +-
arch/powerpc/platforms/powernv/opal-psr.c | 2 +-
arch/powerpc/platforms/powernv/opal-xscom.c | 2 +-
arch/powerpc/platforms/powernv/opal.c | 289 ++++++++++++++++--
arch/powerpc/platforms/powernv/pci-ioda.c | 2 +-
arch/powerpc/sysdev/xive/native.c | 2 +-
drivers/char/powernv-op-panel.c | 3 +-
drivers/i2c/busses/i2c-opal.c | 12 +-
drivers/mtd/devices/powernv_flash.c | 4 +-
include/linux/kallsyms.h | 20 ++
kernel/kallsyms.c | 13 +-
lib/Kconfig | 3 +
25 files changed, 461 insertions(+), 57 deletions(-)
--
2.23.0
^ 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