* Re: [V4 0/2] tools/perf: Add instruction and data address registers to extended regs in powerpc
From: Arnaldo Carvalho de Melo @ 2021-10-19 16:30 UTC (permalink / raw)
To: Athira Rajeev
Cc: maddy, rnsastry, linux-perf-users, jolsa, kjain, linuxppc-dev
In-Reply-To: <20211018114948.16830-1-atrajeev@linux.vnet.ibm.com>
Em Mon, Oct 18, 2021 at 05:19:46PM +0530, Athira Rajeev escreveu:
> Patch set adds PMU registers namely Sampled Instruction Address Register
> (SIAR) and Sampled Data Address Register (SDAR) as part of extended regs
> in PowerPC. These registers provides the instruction/data address and
> adding these to extended regs helps in debug purposes.
>
> Patch 1/2 refactors the existing macro definition of
> PERF_REG_PMU_MASK_300 and PERF_REG_PMU_MASK_31 to make it more
> readable.
> Patch 2/2 includes perf tools side changes to add the SPRs to
> sample_reg_mask to use with -I? option.
Thanks, applied.
- Arnaldo
> Changelog:
> Change from v3 -> v4:
> - Spilt tools side patches separately since kernel side
> changes are in powerpc/next. There is no code wise changes
> from v3.
> Link to previous version:
> https://patchwork.ozlabs.org/project/linuxppc-dev/list/?series=265811&state=*
>
> Kernel patches are taken to powerpc/next:
> [1/4] powerpc/perf: Refactor the code definition of perf reg extended mask
> https://git.kernel.org/powerpc/c/02b182e67482d9167a13a0ff19b55037b70b21ad
> [3/4] powerpc/perf: Expose instruction and data address registers as part of extended regs
> https://git.kernel.org/powerpc/c/29908bbf7b8960d261dfdd428bbaa656275e80f3
>
> Change from v2 -> v3:
> Addressed review comments from Michael Ellerman
> - Fixed the macro definition to use "unsigned long long"
> which otherwise will cause build error with perf on
> 32-bit.
> - Added Reviewed-by from Daniel Axtens for patch3.
>
> Change from v1 -> v2:
> Addressed review comments from Michael Ellerman
> - Refactored the perf reg extended mask value macros for
> PERF_REG_PMU_MASK_300 and PERF_REG_PMU_MASK_31 to
> make it more readable. Also moved PERF_REG_EXTENDED_MAX
> along with enum definition similar to PERF_REG_POWERPC_MAX.
>
> Athira Rajeev (2):
> tools/perf: Refactor the code definition of perf reg extended mask in
> tools side header file
> tools/perf: Add perf tools support to expose instruction and data
> address registers as part of extended regs
>
> .../arch/powerpc/include/uapi/asm/perf_regs.h | 28 ++++++++++++-------
> tools/perf/arch/powerpc/include/perf_regs.h | 2 ++
> tools/perf/arch/powerpc/util/perf_regs.c | 2 ++
> 3 files changed, 22 insertions(+), 10 deletions(-)
>
> --
> 2.33.0
--
- Arnaldo
^ permalink raw reply
* Re: [PATCH 06/13] nvdimm/blk: avoid calling del_gendisk() on early failures
From: Luis Chamberlain @ 2021-10-19 16:06 UTC (permalink / raw)
To: Dan Williams
Cc: Linux NVDIMM, vigneshr, linux-nvme, Paul Mackerras, miquel.raynal,
Weiny, Ira, Christoph Hellwig, Dave Jiang, Sagi Grimberg,
Minchan Kim, Vishal L Verma, Nitin Gupta, linux-block,
Keith Busch, Jens Axboe, Geoff Levand, Linux Kernel Mailing List,
Jim Paris, senozhatsky, Richard Weinberger, linux-mtd,
linuxppc-dev
In-Reply-To: <CAPcyv4j+xLT=5RUodHWgnPjNq6t5OcmX1oM2zK2ML0U+OS_16Q@mail.gmail.com>
On Fri, Oct 15, 2021 at 05:13:48PM -0700, Dan Williams wrote:
> On Fri, Oct 15, 2021 at 4:53 PM Luis Chamberlain <mcgrof@kernel.org> wrote:
> >
> > If nd_integrity_init() fails we'd get del_gendisk() called,
> > but that's not correct as we should only call that if we're
> > done with device_add_disk(). Fix this by providing unwinding
> > prior to the devm call being registered and moving the devm
> > registration to the very end.
> >
> > This should fix calling del_gendisk() if nd_integrity_init()
> > fails. I only spotted this issue through code inspection. It
> > does not fix any real world bug.
> >
>
> Just fyi, I'm preparing patches to delete this driver completely as it
> is unused by any shipping platform. I hope to get that removal into
> v5.16.
I'll remove this from my queue, any chance you can review the changes
for nvdimm/btt?
Luis
^ permalink raw reply
* Re: [PATCH] tracing: Have all levels of checks prevent recursion
From: Steven Rostedt @ 2021-10-19 13:00 UTC (permalink / raw)
To: Petr Mladek
Cc: 王贇, Peter Zijlstra (Intel), Paul Walmsley,
James E.J. Bottomley, Paul Mackerras, Jisheng Zhang,
H. Peter Anvin, live-patching, linux-riscv, Miroslav Benes,
Joe Lawrence, Helge Deller, x86, linux-csky, Ingo Molnar,
Albert Ou, Jiri Kosina, Nicholas Piggin, Borislav Petkov,
Josh Poimboeuf, Thomas Gleixner, linux-parisc, LKML,
Palmer Dabbelt, Masami Hiramatsu, Guo Ren, Colin Ian King,
linuxppc-dev
In-Reply-To: <YW5ok3CfNoRMfVQ5@alley>
On Tue, 19 Oct 2021 08:41:23 +0200
Petr Mladek <pmladek@suse.com> wrote:
> Feel free to postpone this change. I do not want to complicate
> upstreaming the fix for stable. I am sorry if I already
> complicated it.
>
No problem. It's not that complicated of a merge fix. I'm sure Linus can
handle it ;-)
-- Steve
^ permalink raw reply
* Re: [PATCH v3 05/18] powerpc/85xx: Load all early TLB entries at once
From: Christophe Leroy @ 2021-10-19 12:42 UTC (permalink / raw)
To: Scott Wood; +Cc: Laurentiu Tudor, linuxppc-dev, kexec
In-Reply-To: <1445572476-17192-1-git-send-email-scottwood@freescale.com>
Hi Scott,
Le 23/10/2015 à 05:54, Scott Wood a écrit :
> Use an AS=1 trampoline TLB entry to allow all normal TLB1 entries to
> be loaded at once. This avoids the need to keep the translation that
> code is executing from in the same TLB entry in the final TLB
> configuration as during early boot, which in turn is helpful for
> relocatable kernels (e.g. kdump) where the kernel is not running from
> what would be the first TLB entry.
>
> On e6500, we limit map_mem_in_cams() to the primary hwthread of a
> core (the boot cpu is always considered primary, as a kdump kernel
> can be entered on any cpu). Each TLB only needs to be set up once,
> and when we do, we don't want another thread to be running when we
> create a temporary trampoline TLB1 entry.
Isn't that redundant with commit 78a235efdc42 ("powerpc/fsl_booke: set
the tlb entry for the kernel address in AS1") ?
Should we revert commit 78a235efdc42 ?
Christophe
>
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
> v3: Drop rename of settlbcam to preptlbcam, as the settlbcam wrapper
> was unused.
>
> arch/powerpc/kernel/setup_64.c | 8 +++++
> arch/powerpc/mm/fsl_booke_mmu.c | 4 +--
> arch/powerpc/mm/mmu_decl.h | 1 +
> arch/powerpc/mm/tlb_nohash.c | 19 +++++++++++-
> arch/powerpc/mm/tlb_nohash_low.S | 63 ++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 92 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
> index bdcbb71..505ec2c 100644
> --- a/arch/powerpc/kernel/setup_64.c
> +++ b/arch/powerpc/kernel/setup_64.c
> @@ -108,6 +108,14 @@ static void setup_tlb_core_data(void)
> for_each_possible_cpu(cpu) {
> int first = cpu_first_thread_sibling(cpu);
>
> + /*
> + * If we boot via kdump on a non-primary thread,
> + * make sure we point at the thread that actually
> + * set up this TLB.
> + */
> + if (cpu_first_thread_sibling(boot_cpuid) == first)
> + first = boot_cpuid;
> +
> paca[cpu].tcd_ptr = &paca[first].tcd;
>
> /*
> diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
> index 354ba3c..bb1f88c 100644
> --- a/arch/powerpc/mm/fsl_booke_mmu.c
> +++ b/arch/powerpc/mm/fsl_booke_mmu.c
> @@ -141,8 +141,6 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys,
> tlbcam_addrs[index].start = virt;
> tlbcam_addrs[index].limit = virt + size - 1;
> tlbcam_addrs[index].phys = phys;
> -
> - loadcam_entry(index);
> }
>
> unsigned long calc_cam_sz(unsigned long ram, unsigned long virt,
> @@ -188,6 +186,8 @@ static unsigned long map_mem_in_cams_addr(phys_addr_t phys, unsigned long virt,
> virt += cam_sz;
> phys += cam_sz;
> }
> +
> + loadcam_multi(0, i, max_cam_idx);
> tlbcam_index = i;
>
> #ifdef CONFIG_PPC64
> diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
> index 085b66b..27c3a2d 100644
> --- a/arch/powerpc/mm/mmu_decl.h
> +++ b/arch/powerpc/mm/mmu_decl.h
> @@ -152,6 +152,7 @@ extern int switch_to_as1(void);
> extern void restore_to_as0(int esel, int offset, void *dt_ptr, int bootcpu);
> #endif
> extern void loadcam_entry(unsigned int index);
> +extern void loadcam_multi(int first_idx, int num, int tmp_idx);
>
> struct tlbcam {
> u32 MAS0;
> diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
> index 723a099..a7381fb 100644
> --- a/arch/powerpc/mm/tlb_nohash.c
> +++ b/arch/powerpc/mm/tlb_nohash.c
> @@ -42,6 +42,7 @@
> #include <asm/tlbflush.h>
> #include <asm/tlb.h>
> #include <asm/code-patching.h>
> +#include <asm/cputhreads.h>
> #include <asm/hugetlb.h>
> #include <asm/paca.h>
>
> @@ -628,10 +629,26 @@ static void early_init_this_mmu(void)
> #ifdef CONFIG_PPC_FSL_BOOK3E
> if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
> unsigned int num_cams;
> + int __maybe_unused cpu = smp_processor_id();
> + bool map = true;
>
> /* use a quarter of the TLBCAM for bolted linear map */
> num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
> - linear_map_top = map_mem_in_cams(linear_map_top, num_cams);
> +
> + /*
> + * Only do the mapping once per core, or else the
> + * transient mapping would cause problems.
> + */
> +#ifdef CONFIG_SMP
> + if (cpu != boot_cpuid &&
> + (cpu != cpu_first_thread_sibling(cpu) ||
> + cpu == cpu_first_thread_sibling(boot_cpuid)))
> + map = false;
> +#endif
> +
> + if (map)
> + linear_map_top = map_mem_in_cams(linear_map_top,
> + num_cams);
> }
> #endif
>
> diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S
> index 43ff3c7..68c4775 100644
> --- a/arch/powerpc/mm/tlb_nohash_low.S
> +++ b/arch/powerpc/mm/tlb_nohash_low.S
> @@ -400,6 +400,7 @@ _GLOBAL(set_context)
> * extern void loadcam_entry(unsigned int index)
> *
> * Load TLBCAM[index] entry in to the L2 CAM MMU
> + * Must preserve r7, r8, r9, and r10
> */
> _GLOBAL(loadcam_entry)
> mflr r5
> @@ -423,4 +424,66 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS)
> tlbwe
> isync
> blr
> +
> +/*
> + * Load multiple TLB entries at once, using an alternate-space
> + * trampoline so that we don't have to care about whether the same
> + * TLB entry maps us before and after.
> + *
> + * r3 = first entry to write
> + * r4 = number of entries to write
> + * r5 = temporary tlb entry
> + */
> +_GLOBAL(loadcam_multi)
> + mflr r8
> +
> + /*
> + * Set up temporary TLB entry that is the same as what we're
> + * running from, but in AS=1.
> + */
> + bl 1f
> +1: mflr r6
> + tlbsx 0,r8
> + mfspr r6,SPRN_MAS1
> + ori r6,r6,MAS1_TS
> + mtspr SPRN_MAS1,r6
> + mfspr r6,SPRN_MAS0
> + rlwimi r6,r5,MAS0_ESEL_SHIFT,MAS0_ESEL_MASK
> + mr r7,r5
> + mtspr SPRN_MAS0,r6
> + isync
> + tlbwe
> + isync
> +
> + /* Switch to AS=1 */
> + mfmsr r6
> + ori r6,r6,MSR_IS|MSR_DS
> + mtmsr r6
> + isync
> +
> + mr r9,r3
> + add r10,r3,r4
> +2: bl loadcam_entry
> + addi r9,r9,1
> + cmpw r9,r10
> + mr r3,r9
> + blt 2b
> +
> + /* Return to AS=0 and clear the temporary entry */
> + mfmsr r6
> + rlwinm. r6,r6,0,~(MSR_IS|MSR_DS)
> + mtmsr r6
> + isync
> +
> + li r6,0
> + mtspr SPRN_MAS1,r6
> + rlwinm r6,r7,MAS0_ESEL_SHIFT,MAS0_ESEL_MASK
> + oris r6,r6,MAS0_TLBSEL(1)@h
> + mtspr SPRN_MAS0,r6
> + isync
> + tlbwe
> + isync
> +
> + mtlr r8
> + blr
> #endif
>
^ permalink raw reply
* [PATCH v2][net-next] soc: fsl: dpio: Unsigned compared against 0 in qbman_swp_set_irq_coalescing()
From: Tim Gardner @ 2021-10-19 12:19 UTC (permalink / raw)
To: netdev
Cc: Roy Pledge, linux-kernel, Li Yang, Ioana Ciornei, Tim Gardner,
linuxppc-dev, linux-arm-kernel
Coverity complains of unsigned compare against 0. There are 2 cases in
this function:
1821 itp = (irq_holdoff * 1000) / p->desc->qman_256_cycles_per_ns;
CID 121131 (#1 of 1): Unsigned compared against 0 (NO_EFFECT)
unsigned_compare: This less-than-zero comparison of an unsigned value is never true. itp < 0U.
1822 if (itp < 0 || itp > 4096) {
1823 max_holdoff = (p->desc->qman_256_cycles_per_ns * 4096) / 1000;
1824 pr_err("irq_holdoff must be between 0..%dus\n", max_holdoff);
1825 return -EINVAL;
1826 }
1827
unsigned_compare: This less-than-zero comparison of an unsigned value is never true. irq_threshold < 0U.
1828 if (irq_threshold >= p->dqrr.dqrr_size || irq_threshold < 0) {
1829 pr_err("irq_threshold must be between 0..%d\n",
1830 p->dqrr.dqrr_size - 1);
1831 return -EINVAL;
1832 }
Fix this by removing the comparisons altogether as they are incorrect. Zero is
a possible value in either case. Also fix a minor comment typo and update the
2 pr_err() calls to use %u formatting as well as be more precise regarding
the exact error.
Fixes: ed1d2143fee5 ("soc: fsl: dpio: add support for irq coalescing per software portal")
Cc: Ioana Ciornei <ioana.ciornei@nxp.com>
Cc: Roy Pledge <Roy.Pledge@nxp.com>
Cc: Li Yang <leoyang.li@nxp.com>
Cc: linux-kernel@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: netdev@vger.kernel.org
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
---
v1 - check itp and irq_threshold for 0.
v2 - drop the checks for comparison to 0. Update pr_err() calls with precise language
about the error.
---
drivers/soc/fsl/dpio/qbman-portal.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/soc/fsl/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c
index d3c58df6240d..3474bf5f88d5 100644
--- a/drivers/soc/fsl/dpio/qbman-portal.c
+++ b/drivers/soc/fsl/dpio/qbman-portal.c
@@ -1816,18 +1816,17 @@ int qbman_swp_set_irq_coalescing(struct qbman_swp *p, u32 irq_threshold,
u32 itp, max_holdoff;
/* Convert irq_holdoff value from usecs to 256 QBMAN clock cycles
- * increments. This depends to the QBMAN internal frequency.
+ * increments. This depends on the QBMAN internal frequency.
*/
itp = (irq_holdoff * 1000) / p->desc->qman_256_cycles_per_ns;
- if (itp < 0 || itp > 4096) {
+ if (itp > 4096) {
max_holdoff = (p->desc->qman_256_cycles_per_ns * 4096) / 1000;
- pr_err("irq_holdoff must be between 0..%dus\n", max_holdoff);
+ pr_err("irq_holdoff must be <= %uus\n", max_holdoff);
return -EINVAL;
}
- if (irq_threshold >= p->dqrr.dqrr_size || irq_threshold < 0) {
- pr_err("irq_threshold must be between 0..%d\n",
- p->dqrr.dqrr_size - 1);
+ if (irq_threshold >= p->dqrr.dqrr_size) {
+ pr_err("irq_threshold must be < %u\n", p->dqrr.dqrr_size - 1);
return -EINVAL;
}
--
2.33.1
^ permalink raw reply related
* Re: [PATCH] powerpc/boot: Set LANG=C in wrapper script
From: Segher Boessenkool @ 2021-10-19 10:44 UTC (permalink / raw)
To: Christophe Leroy; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <6a103cc4bb5ada724f893711e35ae6c459f95f3e.1634638790.git.christophe.leroy@csgroup.eu>
On Tue, Oct 19, 2021 at 12:20:01PM +0200, Christophe Leroy wrote:
> Add LANG=C at the beginning of the wrapper script in order to get the
> output expected by the script:
This doesn't use if any LC_* are set. Use LC_ALL=C to override all user
choices.
Segher
^ permalink raw reply
* [PATCH] powerpc/boot: Set LANG=C in wrapper script
From: Christophe Leroy @ 2021-10-19 10:20 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
While trying to build a simple Image for ACADIA platform, I got the
following error:
WRAP arch/powerpc/boot/simpleImage.acadia
INFO: Uncompressed kernel (size 0x6ae7d0) overlaps the address of the wrapper(0x400000)
INFO: Fixing the link_address of wrapper to (0x700000)
powerpc64-linux-gnu-ld : mode d'émulation non reconnu : -T
Émulations prises en charge : elf64ppc elf32ppc elf32ppclinux elf32ppcsim elf64lppc elf32lppc elf32lppclinux elf32lppcsim
make[1]: *** [arch/powerpc/boot/Makefile:424 : arch/powerpc/boot/simpleImage.acadia] Erreur 1
make: *** [arch/powerpc/Makefile:285 : simpleImage.acadia] Erreur 2
Trying again with V=1 shows the following command
powerpc64-linux-gnu-ld -m -T arch/powerpc/boot/zImage.lds -Ttext 0x700000 --no-dynamic-linker -o arch/powerpc/boot/simpleImage.acadia -Map wrapper.map arch/powerpc/boot/fixed-head.o arch/powerpc/boot/simpleboot.o ./zImage.3278022.o arch/powerpc/boot/wrapper.a
The argument of '-m' is missing.
This is due to the wrapper script calling 'objdump -p vmlinux' and
looking for 'file format', whereas the output of objdump is:
vmlinux: format de fichier elf32-powerpc
En-tête de programme:
LOAD off 0x00010000 vaddr 0xc0000000 paddr 0x00000000 align 2**16
filesz 0x0069e1d4 memsz 0x006c128c flags rwx
NOTE off 0x0064591c vaddr 0xc063591c paddr 0x0063591c align 2**2
filesz 0x00000054 memsz 0x00000054 flags ---
Add LANG=C at the beginning of the wrapper script in order to get the
output expected by the script:
vmlinux: file format elf32-powerpc
Program Header:
LOAD off 0x00010000 vaddr 0xc0000000 paddr 0x00000000 align 2**16
filesz 0x0069e1d4 memsz 0x006c128c flags rwx
NOTE off 0x0064591c vaddr 0xc063591c paddr 0x0063591c align 2**2
filesz 0x00000054 memsz 0x00000054 flags ---
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/boot/wrapper | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 1cd82564c996..59fafa1cf897 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -26,6 +26,8 @@
# Stop execution if any command fails
set -e
+export LANG=C
+
# Allow for verbose output
if [ "$V" = 1 ]; then
set -x
--
2.31.1
^ permalink raw reply related
* Re: [PATCH][linux-next] soc: fsl: dpio: Unsigned compared against 0 in
From: Ioana Ciornei @ 2021-10-19 9:08 UTC (permalink / raw)
To: tim.gardner; +Cc: linuxppc-dev, linux-kernel, linux-arm-kernel, leoyang.li
In-Reply-To: <20211018160541.13512-1-tim.gardner@canonical.com>
>
> Subject: [PATCH][linux-next] soc: fsl: dpio: Unsigned compared against 0 in
>
> Coverity complains of unsigned compare against 0. There are 2 cases in
> this function:
>
> 1821 itp = (irq_holdoff * 1000) / p->desc->qman_256_cycles_per_ns;
>
> CID 121131 (#1 of 1): Unsigned compared against 0 (NO_EFFECT)
> unsigned_compare: This less-than-zero comparison of an unsigned value is never true. itp < 0U.
> 1822 if (itp < 0 || itp > 4096) {
> 1823 max_holdoff = (p->desc->qman_256_cycles_per_ns * 4096) / 1000;
> 1824 pr_err("irq_holdoff must be between 0..%dus\n", max_holdoff);
> 1825 return -EINVAL;
> 1826 }
> 1827
> unsigned_compare: This less-than-zero comparison of an unsigned value is never true. irq_threshold < 0U.
> 1828 if (irq_threshold >= p->dqrr.dqrr_size || irq_threshold < 0) {
> 1829 pr_err("irq_threshold must be between 0..%d\n",
> 1830 p->dqrr.dqrr_size - 1);
> 1831 return -EINVAL;
> 1832 }
>
> Fix this by checking for 0. Also fix a minor comment typo.
>
> Fixes ed1d2143fee53755ec601eb4d48a337a93933f71 ("soc: fsl: dpio: add support for
> irq coalescing per software portal")
I think this should be formatted as following:
Fixes: ed1d2143fee5 ("soc: fsl: dpio: add support for irq coalescing per software portal")
>
> Cc: Roy Pledge <Roy.Pledge@nxp.com>
> Cc: Li Yang <leoyang.li@nxp.com>
> Cc: linux-kernel@vger.kernel.org
> Cc: linuxppc-dev@lists.ozlabs.org
> Cc: linux-arm-kernel@lists.infradead.org
> Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
> ---
>
> I'm not 100% sure this is the right way to fix the warning, but according to the
> pr_err() comments these values should never be 0.
These threshold values can be 0, the pr_err comment tries to say that those are
the ranges, 0 and the maximum included.
>
> ---
> drivers/soc/fsl/dpio/qbman-portal.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/soc/fsl/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c
> index d3c58df6240d..b768a14bb271 100644
> --- a/drivers/soc/fsl/dpio/qbman-portal.c
> +++ b/drivers/soc/fsl/dpio/qbman-portal.c
> @@ -1816,16 +1816,16 @@ int qbman_swp_set_irq_coalescing(struct qbman_swp *p, u32 irq_threshold,
> u32 itp, max_holdoff;
>
> /* Convert irq_holdoff value from usecs to 256 QBMAN clock cycles
> - * increments. This depends to the QBMAN internal frequency.
> + * increments. This depends on the QBMAN internal frequency.
> */
> itp = (irq_holdoff * 1000) / p->desc->qman_256_cycles_per_ns;
> - if (itp < 0 || itp > 4096) {
> + if (!itp || itp > 4096) {
> max_holdoff = (p->desc->qman_256_cycles_per_ns * 4096) / 1000;
> pr_err("irq_holdoff must be between 0..%dus\n", max_holdoff);
> return -EINVAL;
> }
>
> - if (irq_threshold >= p->dqrr.dqrr_size || irq_threshold < 0) {
> + if (irq_threshold >= p->dqrr.dqrr_size || !irq_threshold) {
> pr_err("irq_threshold must be between 0..%d\n",
> p->dqrr.dqrr_size - 1);
> return -EINVAL;
>
These 'value < 0' checks should be removed all together. Somehow I missed that
those are unsigned values.
Anyhow, thanks a lot that you spotted this.
Could you please sent the v2 towards the net-next tree since that's the tree
that adds the fixed patch?
Thanks.
-Ioana
^ permalink raw reply
* Re: [PATCH] powerpc/pseries/mobility: ignore ibm, platform-facilities updates
From: Laurent Dufour @ 2021-10-19 9:05 UTC (permalink / raw)
To: Tyrel Datwyler, Nathan Lynch, linuxppc-dev; +Cc: cheloha
In-Reply-To: <6de8b295-112f-651e-a18e-3ab3e499ad69@linux.ibm.com>
Le 19/10/2021 à 00:37, Tyrel Datwyler a écrit :
> On 10/18/21 9:34 AM, Nathan Lynch wrote:
>> On VMs with NX encryption, compression, and/or RNG offload, these
>> capabilities are described by nodes in the ibm,platform-facilities device
>> tree hierarchy:
>>
>> $ tree -d /sys/firmware/devicetree/base/ibm,platform-facilities/
>> /sys/firmware/devicetree/base/ibm,platform-facilities/
>> ├── ibm,compression-v1
>> ├── ibm,random-v1
>> └── ibm,sym-encryption-v1
>>
>> 3 directories
>>
>> The acceleration functions that these nodes describe are not disrupted by
>> live migration, not even temporarily.
>>
>> But the post-migration ibm,update-nodes sequence firmware always sends
>> "delete" messages for this hierarchy, followed by an "add" directive to
>> reconstruct it via ibm,configure-connector (log with debugging statements
>> enabled in mobility.c):
>>
>> mobility: removing node /ibm,platform-facilities/ibm,random-v1:4294967285
>> mobility: removing node /ibm,platform-facilities/ibm,compression-v1:4294967284
>> mobility: removing node /ibm,platform-facilities/ibm,sym-encryption-v1:4294967283
>> mobility: removing node /ibm,platform-facilities:4294967286
>> ...
>> mobility: added node /ibm,platform-facilities:4294967286
>
> It always bothered me that the update from firmware here was an delete/add at
> the entire '/ibm,platform-facilities' node level instead of update properties
> calls. When I asked about it years ago the claim was it was just easier to pass
> an entire sub-tree as a single node add.
>
>>
>> Note we receive a single "add" message for the entire hierarchy, and what
>> we receive from the ibm,configure-connector sequence is the top-level
>> platform-facilities node along with its three children. The debug message
>> simply reports the parent node and not the whole subtree.
>>
>> Also, significantly, the nodes added are almost completely equivalent to
>> the ones removed; even phandles are unchanged. ibm,shared-interrupt-pool in
>> the leaf nodes is the only property I've observed to differ, and Linux does
>> not use that. So in practice, the sum of update messages Linux receives for
>> this hierarchy is equivalent to minor property updates.
>
> The two props I would think maybe we would need to be most be concerned about
> ensuring don't change are "ibm,resource-id" which gets used in the vio bus code
> when configuring platform facilities nodes, and 'ibm,max-sync-cop' used by the
> pseries-nx driver.
>
>>
>> We succeed in removing the original hierarchy from the device tree. But the
>> drivers bound to the leaf nodes are ignorant of this, and do not relinquish
>> their references. The leaf nodes, still reachable through sysfs, of course
>> still refer to the now-freed ibm,platform-facilities parent node, which
>> makes use-after-free possible:
>
> It is actually more subtle then the drivers themselves being ignorant. They
> could register node update notifiers, but the real problem here is that the vio
> bus device itself takes a reference to each child node registered to the bus.
> I'm not sure we really want to unbind/rebind drivers as a result of LPM, but it
> would be generic to the vio bus instead of updating each driver to ensure its
> handling it device node references properly.
>
>>
>> refcount_t: addition on 0; use-after-free.
>> WARNING: CPU: 3 PID: 1706 at lib/refcount.c:25 refcount_warn_saturate+0x164/0x1f0
>> refcount_warn_saturate+0x160/0x1f0 (unreliable)
>> kobject_get+0xf0/0x100
>> of_node_get+0x30/0x50
>> of_get_parent+0x50/0xb0
>> of_fwnode_get_parent+0x54/0x90
>> fwnode_count_parents+0x50/0x150
>> fwnode_full_name_string+0x30/0x110
>> device_node_string+0x49c/0x790
>> vsnprintf+0x1c0/0x4c0
>> sprintf+0x44/0x60
>> devspec_show+0x34/0x50
>> dev_attr_show+0x40/0xa0
>> sysfs_kf_seq_show+0xbc/0x200
>> kernfs_seq_show+0x44/0x60
>> seq_read_iter+0x2a4/0x740
>> kernfs_fop_read_iter+0x254/0x2e0
>> new_sync_read+0x120/0x190
>> vfs_read+0x1d0/0x240
>>
>> Moreover, the "new" replacement subtree is not correctly added to the
>> device tree, resulting in ibm,platform-facilities parent node without the
>> appropriate leaf nodes, and broken symlinks in the sysfs device hierarchy:
>>
>> $ tree -d /sys/firmware/devicetree/base/ibm,platform-facilities/
>> /sys/firmware/devicetree/base/ibm,platform-facilities/
>>
>> 0 directories
>>
>> $ cd /sys/devices/vio ; find . -xtype l -exec file {} +
>> ./ibm,sym-encryption-v1/of_node: broken symbolic link to
>> ../../../firmware/devicetree/base/ibm,platform-facilities/ibm,sym-encryption-v1
>> ./ibm,random-v1/of_node: broken symbolic link to
>> ../../../firmware/devicetree/base/ibm,platform-facilities/ibm,random-v1
>> ./ibm,compression-v1/of_node: broken symbolic link to
>> ../../../firmware/devicetree/base/ibm,platform-facilities/ibm,compression-v1
>>
>> This is because add_dt_node() -> dlpar_attach_node() attaches only the
>> parent node returned from configure-connector, ignoring any children. This
>> should be corrected for the general case, but fixing that won't help with
>> the stale OF node references, which is the more urgent problem.
>
> I don't follow. If the code path you mention is truly broken in the way you say
> then DLPAR operations involving nodes with child nodes should also be broken.
> Last I had seen was that sysfs adds of the new nodes got renamed because the old
> nodes still existed as a result of there reference count not going to zero. Has
> this behavior changed, or am I misremembering the observed behavior?
>
>>
>> One way to address that would be to make the drivers respond to node
>> removal notifications, so that node references can be dropped
>> appropriately. But this would likely force the drivers to disrupt active
>> clients for no useful purpose: equivalent nodes are immediately re-added.
>> And recall that the acceleration capabilities described by the nodes remain
>> available throughout the whole process.
>
> See my comments above about its the vio bus more at fault here then the drivers
> themselves. I'm inclined to agree though that disrupting active operations with
> a driver unbind/rebind is a little extreme.
>
> This also brings me back to firmware removing and re-adding the whole
> '/ibm,platform-facilities' node instead of simply updating changed properties
> could avoid this whole fiasco.
>
>>
>> The solution I believe to be robust for this situation is to convert
>> remove+add of a node with an unchanged phandle to an update of the node's
>> properties in the Linux device tree structure. That would involve changing
>> and adding a fair amount of code, and may take several iterations to land.
>>
>> Until that can be realized we have a confirmed use-after-free and the
>> possibility of memory corruption. So add a limited workaround that
>> discriminates on the node type, ignoring adds and removes. This should be
>> amenable to backporting in the meantime.
>
> The reality is that '/ibm,platform-facilities' and 'cache' nodes are the only
> LPM scoped device tree nodes that allow node delete/add. So, as a one-off
> workaround to deal with what I consider a bad firmware approach I think this is
> probably the best approach barring getting firmware to move to an update
> properties approach.
I do agree, this is probably the best option until the firmware is moving to an
update notification.
>
> An audit of the drivers is probably still a valid exercise to ensure any device
> tree props they care about they pick up a new value should it change.
>
> -Tyrel
>
>>
>> Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
>> Fixes: 410bccf97881 ("powerpc/pseries: Partition migration in the kernel")
>> Cc: stable@vger.kernel.org
>> ---
>> arch/powerpc/platforms/pseries/mobility.c | 34 +++++++++++++++++++++++
>> 1 file changed, 34 insertions(+)
>>
>> diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
>> index e83e0891272d..210a37a065fb 100644
>> --- a/arch/powerpc/platforms/pseries/mobility.c
>> +++ b/arch/powerpc/platforms/pseries/mobility.c
>> @@ -63,6 +63,27 @@ static int mobility_rtas_call(int token, char *buf, s32 scope)
>>
>> static int delete_dt_node(struct device_node *dn)
>> {
>> + struct device_node *pdn;
>> + bool is_platfac;
>> +
>> + pdn = of_get_parent(dn);
>> + is_platfac = of_node_is_type(dn, "ibm,platform-facilities") ||
>> + of_node_is_type(pdn, "ibm,platform-facilities");
>> + of_node_put(pdn);
>> +
>> + /*
>> + * The drivers that bind to nodes in the platform-facilities
>> + * hierarchy don't support node removal, and the removal directive
>> + * from firmware is always followed by an add of an equivalent
>> + * node. The capability (e.g. RNG, encryption, compression)
>> + * represented by the node is never interrupted by the migration.
>> + * So ignore changes to this part of the tree.
>> + */
>> + if (is_platfac) {
>> + pr_notice("ignoring remove operation for %pOFfp\n", dn);
>> + return 0;
>> + }
>> +
>> pr_debug("removing node %pOFfp\n", dn);
>> dlpar_detach_node(dn);
>> return 0;
>> @@ -222,6 +243,19 @@ static int add_dt_node(struct device_node *parent_dn, __be32 drc_index)
>> if (!dn)
>> return -ENOENT;
>>
>> + /*
>> + * Since delete_dt_node() ignores this node type, this is the
>> + * necessary counterpart. We also know that a platform-facilities
>> + * node returned from dlpar_configure_connector() has children
>> + * attached, and dlpar_attach_node() only adds the parent, leaking
>> + * the children. So ignore these on the add side for now.
>> + */
>> + if (of_node_is_type(dn, "ibm,platform-facilities")) {
>> + pr_notice("ignoring add operation for %pOF\n", dn);
>> + dlpar_free_cc_nodes(dn);
>> + return 0;
>> + }
>> +
>> rc = dlpar_attach_node(dn, parent_dn);
>> if (rc)
>> dlpar_free_cc_nodes(dn);
>>
>
^ permalink raw reply
* Re: [PATCH v1 09/11] powerpc/64s: Make hash MMU code build configurable
From: Christophe Leroy @ 2021-10-19 8:05 UTC (permalink / raw)
To: Nicholas Piggin, linuxppc-dev
In-Reply-To: <20211015154624.922960-10-npiggin@gmail.com>
Le 15/10/2021 à 17:46, Nicholas Piggin a écrit :
> Introduce a new option CONFIG_PPC_64S_HASH_MMU which allows the 64s hash
> MMU code to be compiled out if radix is selected and the minimum
> supported CPU type is POWER9 or higher, and KVM is not selected.
>
> This saves 128kB kernel image size (90kB text) on powernv_defconfig
> minus KVM, 350kB on pseries_defconfig minus KVM, 40kB on a tiny config.
This patch is huge, it could be split in several smaller patches ?
I'm sure at least the Kconfig stuff can be do as a second step. In first
step just make CONFIG_PPC_64S_HASH_MMU always y.
I'm wondering if we could also reduce the amount of #ifdefs in C files,
by using IS_ENABLED() and/or stubs defined in H files.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
> arch/powerpc/Kconfig | 1 +
> arch/powerpc/include/asm/book3s/64/mmu.h | 22 ++++++++++++++++++-
> .../include/asm/book3s/64/tlbflush-hash.h | 7 ++++++
> arch/powerpc/include/asm/book3s/pgtable.h | 4 ++++
> arch/powerpc/include/asm/mmu.h | 14 +++++++++---
> arch/powerpc/include/asm/mmu_context.h | 2 ++
> arch/powerpc/include/asm/paca.h | 8 +++++++
> arch/powerpc/kernel/asm-offsets.c | 2 ++
> arch/powerpc/kernel/dt_cpu_ftrs.c | 8 ++++++-
> arch/powerpc/kernel/entry_64.S | 4 ++--
> arch/powerpc/kernel/exceptions-64s.S | 16 ++++++++++++++
> arch/powerpc/kernel/mce.c | 2 +-
> arch/powerpc/kernel/mce_power.c | 10 ++++++---
> arch/powerpc/kernel/paca.c | 18 ++++++---------
> arch/powerpc/kernel/process.c | 13 ++++++-----
> arch/powerpc/kernel/prom.c | 2 ++
> arch/powerpc/kernel/setup_64.c | 4 ++++
> arch/powerpc/kexec/core_64.c | 4 ++--
> arch/powerpc/kexec/ranges.c | 4 ++++
> arch/powerpc/kvm/Kconfig | 1 +
> arch/powerpc/mm/book3s64/Makefile | 17 ++++++++------
> arch/powerpc/mm/book3s64/hash_utils.c | 10 ---------
> .../{hash_hugetlbpage.c => hugetlbpage.c} | 6 +++++
> arch/powerpc/mm/book3s64/mmu_context.c | 16 ++++++++++++++
> arch/powerpc/mm/book3s64/pgtable.c | 12 ++++++++++
> arch/powerpc/mm/book3s64/radix_pgtable.c | 4 ++++
> arch/powerpc/mm/copro_fault.c | 2 ++
> arch/powerpc/mm/pgtable.c | 10 ++++++---
> arch/powerpc/platforms/Kconfig.cputype | 21 +++++++++++++++++-
> arch/powerpc/platforms/cell/Kconfig | 1 +
> arch/powerpc/platforms/maple/Kconfig | 1 +
> arch/powerpc/platforms/microwatt/Kconfig | 2 +-
> arch/powerpc/platforms/pasemi/Kconfig | 1 +
> arch/powerpc/platforms/powermac/Kconfig | 1 +
> arch/powerpc/platforms/powernv/Kconfig | 2 +-
> arch/powerpc/platforms/powernv/idle.c | 2 ++
> arch/powerpc/platforms/powernv/setup.c | 2 ++
> arch/powerpc/platforms/pseries/lpar.c | 11 ++++++++--
> arch/powerpc/platforms/pseries/lparcfg.c | 2 +-
> arch/powerpc/platforms/pseries/mobility.c | 6 +++++
> arch/powerpc/platforms/pseries/ras.c | 2 ++
> arch/powerpc/platforms/pseries/reconfig.c | 2 ++
> arch/powerpc/platforms/pseries/setup.c | 6 +++--
> arch/powerpc/xmon/xmon.c | 8 +++++--
> 44 files changed, 233 insertions(+), 60 deletions(-)
> rename arch/powerpc/mm/book3s64/{hash_hugetlbpage.c => hugetlbpage.c} (95%)
>
> diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
> index 8abe8e42e045..0f89fcab834d 100644
> --- a/arch/powerpc/include/asm/mmu.h
> +++ b/arch/powerpc/include/asm/mmu.h
> @@ -157,7 +157,7 @@ DECLARE_PER_CPU(int, next_tlbcam_idx);
>
> enum {
> MMU_FTRS_POSSIBLE =
> -#if defined(CONFIG_PPC_BOOK3S_64) || defined(CONFIG_PPC_BOOK3S_604)
> +#if defined(CONFIG_PPC_BOOK3S_604)
> MMU_FTR_HPTE_TABLE |
> #endif
> #ifdef CONFIG_PPC_8xx
> @@ -184,15 +184,18 @@ enum {
> MMU_FTR_USE_TLBRSRV | MMU_FTR_USE_PAIRED_MAS |
> #endif
> #ifdef CONFIG_PPC_BOOK3S_64
> + MMU_FTR_KERNEL_RO |
> +#ifdef CONFIG_PPC_64S_HASH_MMU
> MMU_FTR_NO_SLBIE_B | MMU_FTR_16M_PAGE | MMU_FTR_TLBIEL |
> MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_CI_LARGE_PAGE |
> MMU_FTR_1T_SEGMENT | MMU_FTR_TLBIE_CROP_VA |
> - MMU_FTR_KERNEL_RO | MMU_FTR_68_BIT_VA |
> + MMU_FTR_68_BIT_VA | MMU_FTR_HPTE_TABLE |
> #endif
> #ifdef CONFIG_PPC_RADIX_MMU
> MMU_FTR_TYPE_RADIX |
> MMU_FTR_GTSE |
> #endif /* CONFIG_PPC_RADIX_MMU */
> +#endif
> #ifdef CONFIG_PPC_KUAP
> MMU_FTR_BOOK3S_KUAP |
> #endif /* CONFIG_PPC_KUAP */
> @@ -223,6 +226,11 @@ enum {
> #ifdef CONFIG_E500
> #define MMU_FTRS_ALWAYS MMU_FTR_TYPE_FSL_E
> #endif
> +#ifdef CONFIG_PPC_BOOK3S_64
> +#if defined(CONFIG_PPC_RADIX_MMU) && !defined(CONFIG_PPC_64S_HASH_MMU)
> +#define MMU_FTRS_ALWAYS MMU_FTR_TYPE_RADIX
> +#endif
> +#endif
Should you also set MMU_FTR_HPTE_TABLE in MMU_FTRS_ALWAYS when HAS_MMU
&& !RADIX ?
>
> #ifndef MMU_FTRS_ALWAYS
> #define MMU_FTRS_ALWAYS 0
> @@ -329,7 +337,7 @@ static __always_inline bool radix_enabled(void)
> return mmu_has_feature(MMU_FTR_TYPE_RADIX);
> }
>
> -static inline bool early_radix_enabled(void)
> +static __always_inline bool early_radix_enabled(void)
> {
> return early_mmu_has_feature(MMU_FTR_TYPE_RADIX);
> }
> diff --git a/arch/powerpc/mm/book3s64/mmu_context.c b/arch/powerpc/mm/book3s64/mmu_context.c
> index c10fc8a72fb3..642cabc25e99 100644
> --- a/arch/powerpc/mm/book3s64/mmu_context.c
> +++ b/arch/powerpc/mm/book3s64/mmu_context.c
> @@ -31,6 +31,7 @@ static int alloc_context_id(int min_id, int max_id)
> return ida_alloc_range(&mmu_context_ida, min_id, max_id, GFP_KERNEL);
> }
>
> +#ifdef CONFIG_PPC_64S_HASH_MMU
> void hash__reserve_context_id(int id)
> {
> int result = ida_alloc_range(&mmu_context_ida, id, id, GFP_KERNEL);
> @@ -50,7 +51,9 @@ int hash__alloc_context_id(void)
> return alloc_context_id(MIN_USER_CONTEXT, max);
> }
> EXPORT_SYMBOL_GPL(hash__alloc_context_id);
> +#endif
>
> +#ifdef CONFIG_PPC_64S_HASH_MMU
> static int realloc_context_ids(mm_context_t *ctx)
> {
> int i, id;
> @@ -144,12 +147,15 @@ static int hash__init_new_context(struct mm_struct *mm)
> return index;
> }
>
> +void slb_setup_new_exec(void);
> +
> void hash__setup_new_exec(void)
> {
> slice_setup_new_exec();
>
> slb_setup_new_exec();
> }
> +#endif
>
> static int radix__init_new_context(struct mm_struct *mm)
> {
> @@ -175,7 +181,9 @@ static int radix__init_new_context(struct mm_struct *mm)
> */
> asm volatile("ptesync;isync" : : : "memory");
>
> +#ifdef CONFIG_PPC_64S_HASH_MMU
> mm->context.hash_context = NULL;
> +#endif
>
> return index;
> }
> @@ -186,8 +194,10 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
>
> if (radix_enabled())
> index = radix__init_new_context(mm);
> +#ifdef CONFIG_PPC_64S_HASH_MMU
> else
> index = hash__init_new_context(mm);
> +#endif
I really dislike #ifdef nested in if/else.
Can you do something like
if (radix_enabled()
index = radix__init_new_context(mm);
else if (mmu_has_feature(MMU_FTR_HPTE_TABLE))
index = hash__init_new_context(mm);
>
> if (index < 0)
> return index;
> @@ -211,6 +221,7 @@ void __destroy_context(int context_id)
> }
> EXPORT_SYMBOL_GPL(__destroy_context);
>
> +#ifdef CONFIG_PPC_64S_HASH_MMU
> static void destroy_contexts(mm_context_t *ctx)
> {
> int index, context_id;
> @@ -222,6 +233,7 @@ static void destroy_contexts(mm_context_t *ctx)
> }
> kfree(ctx->hash_context);
> }
> +#endif
>
> static void pmd_frag_destroy(void *pmd_frag)
> {
> @@ -274,7 +286,11 @@ void destroy_context(struct mm_struct *mm)
> process_tb[mm->context.id].prtb0 = 0;
> else
> subpage_prot_free(mm);
> +#ifdef CONFIG_PPC_64S_HASH_MMU
> destroy_contexts(&mm->context);
> +#else
> + ida_free(&mmu_context_ida, mm->context.id);
Is that correct ? Was it done somewhere else before ?
> +#endif
> mm->context.id = MMU_NO_CONTEXT;
> }
>
^ permalink raw reply
* [PATCH v3 17/22] powerpc: Add KUAP support for BOOKE and 40x
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
On booke/40x we don't have segments like book3s/32.
On booke/40x we don't have access protection groups like 8xx.
Use the PID register to provide user access protection.
Kernel address space can be accessed with any PID.
User address space has to be accessed with the PID of the user.
User PID is always not null.
Everytime the kernel is entered, set PID register to 0 and
restore PID register when returning to user.
Everytime kernel needs to access user data, PID is restored
for the access.
In TLB miss handlers, check the PID and bail out to data storage
exception when PID is 0 and accessed address is in user space.
Note that also forbids execution of user text by kernel except
when user access is unlocked. But this shouldn't be a problem
as the kernel is not supposed to ever run user text.
This patch prepares the infrastructure but the real activation of KUAP
is done by following patches for each processor type one by one.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/include/asm/kup.h | 4 +
arch/powerpc/include/asm/nohash/kup-booke.h | 110 ++++++++++++++++++++
arch/powerpc/include/asm/processor.h | 3 +
arch/powerpc/kernel/process.c | 3 +
arch/powerpc/mm/mmu_context.c | 6 ++
arch/powerpc/mm/nohash/mmu_context.c | 6 +-
6 files changed, 131 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/nohash/kup-booke.h
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 656e6f1d6b6f..fb2237809d63 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -14,6 +14,10 @@
#include <asm/nohash/32/kup-8xx.h>
#endif
+#ifdef CONFIG_BOOKE_OR_40x
+#include <asm/nohash/kup-booke.h>
+#endif
+
#ifdef CONFIG_PPC_BOOK3S_32
#include <asm/book3s/32/kup.h>
#endif
diff --git a/arch/powerpc/include/asm/nohash/kup-booke.h b/arch/powerpc/include/asm/nohash/kup-booke.h
new file mode 100644
index 000000000000..49bb41ed0816
--- /dev/null
+++ b/arch/powerpc/include/asm/nohash/kup-booke.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_KUP_BOOKE_H_
+#define _ASM_POWERPC_KUP_BOOKE_H_
+
+#include <asm/bug.h>
+
+#ifdef CONFIG_PPC_KUAP
+
+#ifdef __ASSEMBLY__
+
+.macro kuap_check_amr gpr1, gpr2
+.endm
+
+#else
+
+#include <linux/jump_label.h>
+#include <linux/sched.h>
+
+#include <asm/reg.h>
+
+extern struct static_key_false disable_kuap_key;
+
+static __always_inline bool kuap_is_disabled(void)
+{
+ return static_branch_unlikely(&disable_kuap_key);
+}
+
+static inline void __kuap_lock(void)
+{
+ mtspr(SPRN_PID, 0);
+ isync();
+}
+
+static inline void __kuap_save_and_lock(struct pt_regs *regs)
+{
+ regs->kuap = mfspr(SPRN_PID);
+ mtspr(SPRN_PID, 0);
+ isync();
+}
+
+static inline void kuap_user_restore(struct pt_regs *regs)
+{
+ if (kuap_is_disabled())
+ return;
+
+ mtspr(SPRN_PID, current->thread.pid);
+
+ /* Context synchronisation is performed by rfi */
+}
+
+static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
+{
+ if (regs->kuap)
+ mtspr(SPRN_PID, current->thread.pid);
+
+ /* Context synchronisation is performed by rfi */
+}
+
+static inline unsigned long __kuap_get_and_assert_locked(void)
+{
+ unsigned long kuap = mfspr(SPRN_PID);
+
+ if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
+ WARN_ON_ONCE(kuap);
+
+ return kuap;
+}
+
+static inline void __allow_user_access(void __user *to, const void __user *from,
+ unsigned long size, unsigned long dir)
+{
+ mtspr(SPRN_PID, current->thread.pid);
+ isync();
+}
+
+static inline void __prevent_user_access(unsigned long dir)
+{
+ mtspr(SPRN_PID, 0);
+ isync();
+}
+
+static inline unsigned long __prevent_user_access_return(void)
+{
+ unsigned long flags = mfspr(SPRN_PID);
+
+ mtspr(SPRN_PID, 0);
+ isync();
+
+ return flags;
+}
+
+static inline void __restore_user_access(unsigned long flags)
+{
+ if (flags) {
+ mtspr(SPRN_PID, current->thread.pid);
+ isync();
+ }
+}
+
+static inline bool
+__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
+{
+ return !regs->kuap;
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* CONFIG_PPC_KUAP */
+
+#endif /* _ASM_POWERPC_KUP_BOOKE_H_ */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index e64ec54398c6..8d2a7e3a5891 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -160,6 +160,9 @@ struct thread_struct {
unsigned long sr0;
#endif
#endif /* CONFIG_PPC32 */
+#if defined(CONFIG_BOOKE_OR_40x) && defined(CONFIG_PPC_KUAP)
+ unsigned long pid; /* value written in PID reg. at interrupt exit */
+#endif
/* Debug Registers */
struct debug_reg debug;
#ifdef CONFIG_PPC_FPU_REGS
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 2c637740c0c2..b22d70681a21 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1767,6 +1767,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
#if defined(CONFIG_PPC_BOOK3S_32) && defined(CONFIG_PPC_KUAP)
p->thread.kuap = KUAP_NONE;
#endif
+#if defined(CONFIG_BOOKE_OR_40x) && defined(CONFIG_PPC_KUAP)
+ p->thread.pid = MMU_NO_CONTEXT;
+#endif
setup_ksp_vsid(p, sp);
diff --git a/arch/powerpc/mm/mmu_context.c b/arch/powerpc/mm/mmu_context.c
index e618d5442a28..735c36f26388 100644
--- a/arch/powerpc/mm/mmu_context.c
+++ b/arch/powerpc/mm/mmu_context.c
@@ -21,6 +21,9 @@ static inline void switch_mm_pgdir(struct task_struct *tsk,
#ifdef CONFIG_PPC_BOOK3S_32
tsk->thread.sr0 = mm->context.sr0;
#endif
+#if defined(CONFIG_BOOKE_OR_40x) && defined(CONFIG_PPC_KUAP)
+ tsk->thread.pid = mm->context.id;
+#endif
}
#elif defined(CONFIG_PPC_BOOK3E_64)
static inline void switch_mm_pgdir(struct task_struct *tsk,
@@ -28,6 +31,9 @@ static inline void switch_mm_pgdir(struct task_struct *tsk,
{
/* 64-bit Book3E keeps track of current PGD in the PACA */
get_paca()->pgd = mm->pgd;
+#ifdef CONFIG_PPC_KUAP
+ tsk->thread.pid = mm->context.id;
+#endif
}
#else
static inline void switch_mm_pgdir(struct task_struct *tsk,
diff --git a/arch/powerpc/mm/nohash/mmu_context.c b/arch/powerpc/mm/nohash/mmu_context.c
index 44b2b5e7cabe..85b048f04c56 100644
--- a/arch/powerpc/mm/nohash/mmu_context.c
+++ b/arch/powerpc/mm/nohash/mmu_context.c
@@ -33,6 +33,7 @@
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
#include <asm/smp.h>
+#include <asm/kup.h>
#include <mm/mmu_decl.h>
@@ -217,7 +218,7 @@ static void set_context(unsigned long id, pgd_t *pgd)
/* sync */
mb();
- } else {
+ } else if (kuap_is_disabled()) {
if (IS_ENABLED(CONFIG_40x))
mb(); /* sync */
@@ -305,6 +306,9 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next,
if (IS_ENABLED(CONFIG_BDI_SWITCH))
abatron_pteptrs[1] = next->pgd;
set_context(id, next->pgd);
+#if defined(CONFIG_BOOKE_OR_40x) && defined(CONFIG_PPC_KUAP)
+ tsk->thread.pid = id;
+#endif
raw_spin_unlock(&context_lock);
}
--
2.31.1
^ permalink raw reply related
* [PATCH v3 20/22] powerpc/kuap: Wire-up KUAP on 85xx in 32 bits mode.
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
This adds KUAP support to 85xx in 32 bits mode.
This is done by reading the content of SPRN_MAS1 and checking
the TID at the time user pgtable is loaded.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/kernel/head_fsl_booke.S | 12 ++++++++++++
arch/powerpc/platforms/Kconfig.cputype | 1 +
2 files changed, 13 insertions(+)
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 4622b50a5208..ac2b4dcf5fd3 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -462,6 +462,12 @@ END_BTB_FLUSH_SECTION
mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
+#ifdef CONFIG_PPC_KUAP
+ mfspr r12, SPRN_MAS1
+ rlwinm. r12,r12,0,0x3fff0000
+ beq 2f /* KUAP fault */
+#endif
+
4:
/* Mask of required permission bits. Note that while we
* do copy ESR:ST to _PAGE_RW position as trying to write
@@ -571,6 +577,12 @@ END_BTB_FLUSH_SECTION
mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
+#ifdef CONFIG_PPC_KUAP
+ mfspr r12, SPRN_MAS1
+ rlwinm. r12,r12,0,0x3fff0000
+ beq 2f /* KUAP fault */
+#endif
+
/* Make up the required permissions for user code */
#ifdef CONFIG_PTE_64BIT
li r13,_PAGE_PRESENT | _PAGE_BAP_UX
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 3ea415bcf9b8..611d6efc047b 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -37,6 +37,7 @@ config PPC_BOOK3S_32
config PPC_85xx
bool "Freescale 85xx"
select E500
+ select PPC_HAVE_KUAP
config PPC_8xx
bool "Freescale 8xx"
--
2.31.1
^ permalink raw reply related
* [PATCH v3 14/22] powerpc/config: Add CONFIG_BOOKE_OR_40x
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
We have many functionnalities common to 40x and BOOKE, it leads to
many places with #if defined(CONFIG_BOOKE) || defined(CONFIG_40x).
We are going to add a few more with KUAP for booke/40x, so create
a new symbol which is defined when either BOOKE or 40x is defined.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/include/asm/hw_irq.h | 8 ++++----
arch/powerpc/include/asm/irq.h | 2 +-
arch/powerpc/include/asm/ptrace.h | 2 +-
arch/powerpc/include/asm/reg.h | 4 ++--
arch/powerpc/kernel/asm-offsets.c | 2 +-
arch/powerpc/kernel/entry_32.S | 2 +-
arch/powerpc/kernel/irq.c | 2 +-
arch/powerpc/kernel/kgdb.c | 4 ++--
arch/powerpc/kernel/setup.h | 2 +-
arch/powerpc/kernel/setup_32.c | 2 +-
arch/powerpc/kernel/time.c | 2 +-
arch/powerpc/platforms/Kconfig.cputype | 5 +++++
12 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index 21cc571ea9c2..276e9dd7348b 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -61,7 +61,7 @@
static inline void __hard_irq_enable(void)
{
- if (IS_ENABLED(CONFIG_BOOKE) || IS_ENABLED(CONFIG_40x))
+ if (IS_ENABLED(CONFIG_BOOKE_OR_40x))
wrtee(MSR_EE);
else if (IS_ENABLED(CONFIG_PPC_8xx))
wrtspr(SPRN_EIE);
@@ -73,7 +73,7 @@ static inline void __hard_irq_enable(void)
static inline void __hard_irq_disable(void)
{
- if (IS_ENABLED(CONFIG_BOOKE) || IS_ENABLED(CONFIG_40x))
+ if (IS_ENABLED(CONFIG_BOOKE_OR_40x))
wrtee(0);
else if (IS_ENABLED(CONFIG_PPC_8xx))
wrtspr(SPRN_EID);
@@ -85,7 +85,7 @@ static inline void __hard_irq_disable(void)
static inline void __hard_EE_RI_disable(void)
{
- if (IS_ENABLED(CONFIG_BOOKE) || IS_ENABLED(CONFIG_40x))
+ if (IS_ENABLED(CONFIG_BOOKE_OR_40x))
wrtee(0);
else if (IS_ENABLED(CONFIG_PPC_8xx))
wrtspr(SPRN_NRI);
@@ -97,7 +97,7 @@ static inline void __hard_EE_RI_disable(void)
static inline void __hard_RI_enable(void)
{
- if (IS_ENABLED(CONFIG_BOOKE) || IS_ENABLED(CONFIG_40x))
+ if (IS_ENABLED(CONFIG_BOOKE_OR_40x))
return;
if (IS_ENABLED(CONFIG_PPC_8xx))
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index 2b3278534bc1..13f0409dd617 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -36,7 +36,7 @@ extern int distribute_irqs;
struct pt_regs;
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+#ifdef CONFIG_BOOKE_OR_40x
/*
* Per-cpu stacks for handling critical, debug and machine check
* level interrupts.
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index 6e560f035614..42f89e2d8f04 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -291,7 +291,7 @@ static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
static inline bool cpu_has_msr_ri(void)
{
- return !IS_ENABLED(CONFIG_BOOKE) && !IS_ENABLED(CONFIG_40x);
+ return !IS_ENABLED(CONFIG_BOOKE_OR_40x);
}
static inline bool regs_is_unrecoverable(struct pt_regs *regs)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index e9d27265253b..50478738c8f1 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -18,9 +18,9 @@
#include <asm/feature-fixups.h>
/* Pickup Book E specific registers. */
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+#ifdef CONFIG_BOOKE_OR_40x
#include <asm/reg_booke.h>
-#endif /* CONFIG_BOOKE || CONFIG_40x */
+#endif
#ifdef CONFIG_FSL_EMB_PERFMON
#include <asm/reg_fsl_emb.h>
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 256aa669cf80..40a631ae5ba5 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -56,7 +56,7 @@
#endif
#ifdef CONFIG_PPC32
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+#ifdef CONFIG_BOOKE_OR_40x
#include "head_booke.h"
#endif
#endif
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index cf3cc0e52d07..62c244ffa489 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -105,7 +105,7 @@ transfer_to_syscall:
stw r11, 0(r1)
mflr r12
stw r12, _LINK(r1)
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+#ifdef CONFIG_BOOKE_OR_40x
rlwinm r9,r9,0,14,12 /* clear MSR_WE (necessary?) */
#endif
lis r12,STACK_FRAME_REGS_MARKER@ha /* exception frame marker */
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index c4f1d6b7d992..8207f97d51e8 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -811,7 +811,7 @@ void __init init_IRQ(void)
ppc_md.init_IRQ();
}
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+#ifdef CONFIG_BOOKE_OR_40x
void *critirq_ctx[NR_CPUS] __read_mostly;
void *dbgirq_ctx[NR_CPUS] __read_mostly;
void *mcheckirq_ctx[NR_CPUS] __read_mostly;
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index bdee7262c080..9f8d0fa7b718 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -48,7 +48,7 @@ static struct hard_trap_info
{ 0x0800, 0x08 /* SIGFPE */ }, /* fp unavailable */
{ 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */
{ 0x0c00, 0x14 /* SIGCHLD */ }, /* system call */
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_BOOKE_OR_40x
{ 0x2002, 0x05 /* SIGTRAP */ }, /* debug */
#if defined(CONFIG_FSL_BOOKE)
{ 0x2010, 0x08 /* SIGFPE */ }, /* spe unavailable */
@@ -67,7 +67,7 @@ static struct hard_trap_info
{ 0x2010, 0x08 /* SIGFPE */ }, /* fp unavailable */
{ 0x2020, 0x08 /* SIGFPE */ }, /* ap unavailable */
#endif
-#else /* ! (defined(CONFIG_40x) || defined(CONFIG_BOOKE)) */
+#else /* !CONFIG_BOOKE_OR_40x */
{ 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step */
#if defined(CONFIG_PPC_8xx)
{ 0x1000, 0x04 /* SIGILL */ }, /* software emulation */
diff --git a/arch/powerpc/kernel/setup.h b/arch/powerpc/kernel/setup.h
index 84058bbc8fe9..93f22da12abe 100644
--- a/arch/powerpc/kernel/setup.h
+++ b/arch/powerpc/kernel/setup.h
@@ -29,7 +29,7 @@ void setup_tlb_core_data(void);
static inline void setup_tlb_core_data(void) { }
#endif
-#if defined(CONFIG_PPC_BOOK3E) || defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+#ifdef CONFIG_BOOKE_OR_40x
void exc_lvl_early_init(void);
#else
static inline void exc_lvl_early_init(void) { }
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 7ec5c47fce0e..15e7386584f9 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -175,7 +175,7 @@ void __init emergency_stack_init(void)
}
#endif
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+#ifdef CONFIG_BOOKE_OR_40x
void __init exc_lvl_early_init(void)
{
unsigned int i, hw_cpu;
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 934d8ae66cc6..f7bb2866a1c4 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -738,7 +738,7 @@ static int __init get_freq(char *name, int cells, unsigned long *val)
static void start_cpu_decrementer(void)
{
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+#ifdef CONFIG_BOOKE_OR_40x
unsigned int tcr;
/* Clear any pending timer interrupts */
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 68361ab7078d..f58f9edf9b28 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -280,6 +280,11 @@ config BOOKE
depends on E500 || 44x || PPC_BOOK3E
default y
+config BOOKE_OR_40x
+ bool
+ depends on BOOKE || 40x
+ default y
+
config FSL_BOOKE
bool
depends on E500 && PPC32
--
2.31.1
^ permalink raw reply related
* [PATCH v3 09/22] powerpc/kuap: Add a generic intermediate layer
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
Make the following functions generic to all platforms.
- bad_kuap_fault()
- kuap_assert_locked()
- kuap_save_and_lock() (PPC32 only)
- kuap_kernel_restore()
- kuap_get_and_assert_locked()
And for all platforms except book3s/64
- allow_user_access()
- prevent_user_access()
- prevent_user_access_return()
- restore_user_access()
Prepend __ in front of the name of platform specific ones.
For now the generic just calls the platform specific, but
next patch will move redundant parts of specific functions
into the generic one.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/include/asm/book3s/32/kup.h | 22 +++---
arch/powerpc/include/asm/book3s/64/kup.h | 10 ++-
arch/powerpc/include/asm/kup.h | 71 +++++++++++++++++---
arch/powerpc/include/asm/nohash/32/kup-8xx.h | 20 +++---
4 files changed, 86 insertions(+), 37 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/32/kup.h b/arch/powerpc/include/asm/book3s/32/kup.h
index e3db5ed4b255..9e9b2692070c 100644
--- a/arch/powerpc/include/asm/book3s/32/kup.h
+++ b/arch/powerpc/include/asm/book3s/32/kup.h
@@ -77,7 +77,7 @@ static inline void kuap_unlock(unsigned long addr, bool ool)
kuap_unlock_all_ool();
}
-static inline void kuap_save_and_lock(struct pt_regs *regs)
+static inline void __kuap_save_and_lock(struct pt_regs *regs)
{
unsigned long kuap = current->thread.kuap;
@@ -96,7 +96,7 @@ static inline void kuap_user_restore(struct pt_regs *regs)
{
}
-static inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
+static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
{
if (kuap_is_disabled())
return;
@@ -114,7 +114,7 @@ static inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
kuap_unlock(regs->kuap, false);
}
-static inline unsigned long kuap_get_and_assert_locked(void)
+static inline unsigned long __kuap_get_and_assert_locked(void)
{
unsigned long kuap = current->thread.kuap;
@@ -126,13 +126,13 @@ static inline unsigned long kuap_get_and_assert_locked(void)
return kuap;
}
-static inline void kuap_assert_locked(void)
+static inline void __kuap_assert_locked(void)
{
- kuap_get_and_assert_locked();
+ __kuap_get_and_assert_locked();
}
-static __always_inline void allow_user_access(void __user *to, const void __user *from,
- u32 size, unsigned long dir)
+static __always_inline void __allow_user_access(void __user *to, const void __user *from,
+ u32 size, unsigned long dir)
{
if (kuap_is_disabled())
return;
@@ -146,7 +146,7 @@ static __always_inline void allow_user_access(void __user *to, const void __user
kuap_unlock_one((__force u32)to);
}
-static __always_inline void prevent_user_access(unsigned long dir)
+static __always_inline void __prevent_user_access(unsigned long dir)
{
u32 kuap = current->thread.kuap;
@@ -162,7 +162,7 @@ static __always_inline void prevent_user_access(unsigned long dir)
kuap_lock(kuap, true);
}
-static inline unsigned long prevent_user_access_return(void)
+static inline unsigned long __prevent_user_access_return(void)
{
unsigned long flags = current->thread.kuap;
@@ -177,7 +177,7 @@ static inline unsigned long prevent_user_access_return(void)
return flags;
}
-static inline void restore_user_access(unsigned long flags)
+static inline void __restore_user_access(unsigned long flags)
{
if (kuap_is_disabled())
return;
@@ -189,7 +189,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)
+__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
unsigned long kuap = regs->kuap;
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h
index 170339969b7c..03d61c5205a4 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -268,8 +268,7 @@ static inline void kuap_user_restore(struct pt_regs *regs)
*/
}
-static inline void kuap_kernel_restore(struct pt_regs *regs,
- unsigned long amr)
+static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr)
{
if (mmu_has_feature(MMU_FTR_BOOK3S_KUAP)) {
if (unlikely(regs->amr != amr)) {
@@ -287,7 +286,7 @@ static inline void kuap_kernel_restore(struct pt_regs *regs,
*/
}
-static inline unsigned long kuap_get_and_assert_locked(void)
+static inline unsigned long __kuap_get_and_assert_locked(void)
{
if (mmu_has_feature(MMU_FTR_BOOK3S_KUAP)) {
unsigned long amr = mfspr(SPRN_AMR);
@@ -298,7 +297,7 @@ static inline unsigned long kuap_get_and_assert_locked(void)
return 0;
}
-static inline void kuap_assert_locked(void)
+static inline void __kuap_assert_locked(void)
{
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && mmu_has_feature(MMU_FTR_BOOK3S_KUAP))
WARN_ON_ONCE(mfspr(SPRN_AMR) != AMR_KUAP_BLOCKED);
@@ -339,8 +338,7 @@ static inline void set_kuap(unsigned long value)
isync();
}
-static inline bool bad_kuap_fault(struct pt_regs *regs, unsigned long address,
- bool is_write)
+static inline bool __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
if (!mmu_has_feature(MMU_FTR_BOOK3S_KUAP))
return false;
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index fa8513b7acca..f2a6fdb45d33 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -41,17 +41,17 @@ void setup_kuap(bool disabled);
static inline void setup_kuap(bool disabled) { }
static inline bool
-bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
+__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
return false;
}
-static inline void kuap_assert_locked(void) { }
-static inline void kuap_save_and_lock(struct pt_regs *regs) { }
+static inline void __kuap_assert_locked(void) { }
+static inline void __kuap_save_and_lock(struct pt_regs *regs) { }
static inline void kuap_user_restore(struct pt_regs *regs) { }
-static inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) { }
+static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) { }
-static inline unsigned long kuap_get_and_assert_locked(void)
+static inline unsigned long __kuap_get_and_assert_locked(void)
{
return 0;
}
@@ -62,14 +62,65 @@ static inline unsigned long kuap_get_and_assert_locked(void)
* platforms.
*/
#ifndef CONFIG_PPC_BOOK3S_64
-static inline void allow_user_access(void __user *to, const void __user *from,
- unsigned long size, unsigned long dir) { }
-static inline void prevent_user_access(unsigned long dir) { }
-static inline unsigned long prevent_user_access_return(void) { return 0UL; }
-static inline void restore_user_access(unsigned long flags) { }
+static inline void __allow_user_access(void __user *to, const void __user *from,
+ unsigned long size, unsigned long dir) { }
+static inline void __prevent_user_access(unsigned long dir) { }
+static inline unsigned long __prevent_user_access_return(void) { return 0UL; }
+static inline void __restore_user_access(unsigned long flags) { }
#endif /* CONFIG_PPC_BOOK3S_64 */
#endif /* CONFIG_PPC_KUAP */
+static __always_inline bool
+bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
+{
+ return __bad_kuap_fault(regs, address, is_write);
+}
+
+static __always_inline void kuap_assert_locked(void)
+{
+ __kuap_assert_locked();
+}
+
+#ifdef CONFIG_PPC32
+static __always_inline void kuap_save_and_lock(struct pt_regs *regs)
+{
+ __kuap_save_and_lock(regs);
+}
+#endif
+
+static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr)
+{
+ __kuap_kernel_restore(regs, amr);
+}
+
+static __always_inline unsigned long kuap_get_and_assert_locked(void)
+{
+ return __kuap_get_and_assert_locked();
+}
+
+#ifndef CONFIG_PPC_BOOK3S_64
+static __always_inline void allow_user_access(void __user *to, const void __user *from,
+ unsigned long size, unsigned long dir)
+{
+ __allow_user_access(to, from, size, dir);
+}
+
+static __always_inline void prevent_user_access(unsigned long dir)
+{
+ __prevent_user_access(dir);
+}
+
+static __always_inline unsigned long prevent_user_access_return(void)
+{
+ return __prevent_user_access_return();
+}
+
+static __always_inline void restore_user_access(unsigned long flags)
+{
+ __restore_user_access(flags);
+}
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
static __always_inline void allow_read_from_user(const void __user *from, unsigned long size)
{
barrier_nospec();
diff --git a/arch/powerpc/include/asm/nohash/32/kup-8xx.h b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
index 882a0bc7887a..a5db84164afd 100644
--- a/arch/powerpc/include/asm/nohash/32/kup-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
@@ -20,7 +20,7 @@ static __always_inline bool kuap_is_disabled(void)
return static_branch_unlikely(&disable_kuap_key);
}
-static inline void kuap_save_and_lock(struct pt_regs *regs)
+static inline void __kuap_save_and_lock(struct pt_regs *regs)
{
if (kuap_is_disabled())
return;
@@ -33,7 +33,7 @@ static inline void kuap_user_restore(struct pt_regs *regs)
{
}
-static inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
+static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
{
if (kuap_is_disabled())
return;
@@ -41,7 +41,7 @@ static inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
mtspr(SPRN_MD_AP, regs->kuap);
}
-static inline unsigned long kuap_get_and_assert_locked(void)
+static inline unsigned long __kuap_get_and_assert_locked(void)
{
unsigned long kuap;
@@ -56,14 +56,14 @@ static inline unsigned long kuap_get_and_assert_locked(void)
return kuap;
}
-static inline void kuap_assert_locked(void)
+static inline void __kuap_assert_locked(void)
{
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && !kuap_is_disabled())
kuap_get_and_assert_locked();
}
-static inline void allow_user_access(void __user *to, const void __user *from,
- unsigned long size, unsigned long dir)
+static inline void __allow_user_access(void __user *to, const void __user *from,
+ unsigned long size, unsigned long dir)
{
if (kuap_is_disabled())
return;
@@ -71,7 +71,7 @@ static inline void allow_user_access(void __user *to, const void __user *from,
mtspr(SPRN_MD_AP, MD_APG_INIT);
}
-static inline void prevent_user_access(unsigned long dir)
+static inline void __prevent_user_access(unsigned long dir)
{
if (kuap_is_disabled())
return;
@@ -79,7 +79,7 @@ static inline void prevent_user_access(unsigned long dir)
mtspr(SPRN_MD_AP, MD_APG_KUAP);
}
-static inline unsigned long prevent_user_access_return(void)
+static inline unsigned long __prevent_user_access_return(void)
{
unsigned long flags;
@@ -93,7 +93,7 @@ static inline unsigned long prevent_user_access_return(void)
return flags;
}
-static inline void restore_user_access(unsigned long flags)
+static inline void __restore_user_access(unsigned long flags)
{
if (kuap_is_disabled())
return;
@@ -102,7 +102,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)
+__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
if (kuap_is_disabled())
return false;
--
2.31.1
^ permalink raw reply related
* [PATCH v3 21/22] powerpc/kuap: Wire-up KUAP on book3e/64
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
This adds KUAP support to book3e/64.
This is done by reading the content of SPRN_MAS1 and checking
the TID at the time user pgtable is loaded.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/mm/nohash/tlb_low_64e.S | 40 ++++++++++++++++++++++----
arch/powerpc/platforms/Kconfig.cputype | 1 +
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/mm/nohash/tlb_low_64e.S b/arch/powerpc/mm/nohash/tlb_low_64e.S
index bf24451f3e71..b43524ca2b95 100644
--- a/arch/powerpc/mm/nohash/tlb_low_64e.S
+++ b/arch/powerpc/mm/nohash/tlb_low_64e.S
@@ -128,6 +128,13 @@ END_BTB_FLUSH_SECTION
bne tlb_miss_kernel_bolted
+tlb_miss_user_bolted:
+#ifdef CONFIG_PPC_KUAP
+ mfspr r10,SPRN_MAS1
+ rlwinm. r10,r10,0,0x3fff0000
+ beq- tlb_miss_fault_bolted /* KUAP fault */
+#endif
+
tlb_miss_common_bolted:
/*
* This is the guts of the TLB miss handler for bolted-linear.
@@ -246,7 +253,7 @@ itlb_miss_fault_bolted:
cmpldi cr0,r15,0 /* Check for user region */
oris r11,r11,_PAGE_ACCESSED@h
- beq tlb_miss_common_bolted
+ beq tlb_miss_user_bolted
b itlb_miss_kernel_bolted
#ifdef CONFIG_PPC_FSL_BOOK3E
@@ -676,6 +683,11 @@ finish_normal_tlb_miss:
/* Check if required permissions are met */
andc. r15,r11,r14
bne- normal_tlb_miss_access_fault
+#ifdef CONFIG_PPC_KUAP
+ mfspr r11,SPRN_MAS1
+ rlwinm. r10,r11,0,0x3fff0000
+ beq- normal_tlb_miss_access_fault /* KUAP fault */
+#endif
/* Now we build the MAS:
*
@@ -689,15 +701,17 @@ finish_normal_tlb_miss:
*
* TODO: mix up code below for better scheduling
*/
- clrrdi r11,r16,12 /* Clear low crap in EA */
- rlwimi r11,r14,32-19,27,31 /* Insert WIMGE */
- mtspr SPRN_MAS2,r11
+ clrrdi r10,r16,12 /* Clear low crap in EA */
+ rlwimi r10,r14,32-19,27,31 /* Insert WIMGE */
+ mtspr SPRN_MAS2,r10
/* Check page size, if not standard, update MAS1 */
- rldicl r11,r14,64-8,64-8
- cmpldi cr0,r11,BOOK3E_PAGESZ_4K
+ rldicl r10,r14,64-8,64-8
+ cmpldi cr0,r10,BOOK3E_PAGESZ_4K
beq- 1f
+#ifndef CONFIG_PPC_KUAP
mfspr r11,SPRN_MAS1
+#endif
rlwimi r11,r14,31,21,24
rlwinm r11,r11,0,21,19
mtspr SPRN_MAS1,r11
@@ -786,7 +800,16 @@ virt_page_table_tlb_miss:
mfspr r10,SPRN_MAS1
rlwinm r10,r10,0,16,1 /* Clear TID */
mtspr SPRN_MAS1,r10
+#ifdef CONFIG_PPC_KUAP
+ b 2f
+1:
+ mfspr r10,SPRN_MAS1
+ rlwinm. r10,r10,0,0x3fff0000
+ beq- virt_page_table_tlb_miss_fault /* KUAP fault */
+2:
+#else
1:
+#endif
BEGIN_MMU_FTR_SECTION
/* Search if we already have a TLB entry for that virtual address, and
* if we do, bail out.
@@ -1027,6 +1050,11 @@ virt_page_table_tlb_miss_whacko_fault:
* avoid too much complication, it will save/restore things for us
*/
htw_tlb_miss:
+#ifdef CONFIG_PPC_KUAP
+ mfspr r10,SPRN_MAS1
+ rlwinm. r10,r10,0,0x3fff0000
+ beq- htw_tlb_miss_fault /* KUAP fault */
+#endif
/* Search if we already have a TLB entry for that virtual address, and
* if we do, bail out.
*
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 611d6efc047b..f3614bfd47ad 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -122,6 +122,7 @@ config PPC_BOOK3E_64
select PPC_SMP_MUXED_IPI
select PPC_DOORBELL
select ZONE_DMA
+ select PPC_HAVE_KUAP
endchoice
--
2.31.1
^ permalink raw reply related
* [PATCH v3 18/22] powerpc/kuap: Wire-up KUAP on 44x
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
This adds KUAP support to 44x. This is done by checking
the content of SPRN_PID at the time it is read and written
into SPRN_MMUCR.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/kernel/head_44x.S | 16 ++++++++++++++++
arch/powerpc/platforms/Kconfig.cputype | 1 +
2 files changed, 17 insertions(+)
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 916f7e91c6de..b73a56466903 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -334,6 +334,10 @@ interrupt_base:
mfspr r12,SPRN_MMUCR
mfspr r13,SPRN_PID /* Get PID */
rlwimi r12,r13,0,24,31 /* Set TID */
+#ifdef CONFIG_PPC_KUAP
+ cmpwi r13,0
+ beq 2f /* KUAP Fault */
+#endif
4:
mtspr SPRN_MMUCR,r12
@@ -444,6 +448,10 @@ interrupt_base:
mfspr r12,SPRN_MMUCR
mfspr r13,SPRN_PID /* Get PID */
rlwimi r12,r13,0,24,31 /* Set TID */
+#ifdef CONFIG_PPC_KUAP
+ cmpwi r13,0
+ beq 2f /* KUAP Fault */
+#endif
4:
mtspr SPRN_MMUCR,r12
@@ -572,6 +580,10 @@ finish_tlb_load_44x:
3: mfspr r11,SPRN_SPRG3
lwz r11,PGDIR(r11)
mfspr r12,SPRN_PID /* Get PID */
+#ifdef CONFIG_PPC_KUAP
+ cmpwi r12,0
+ beq 2f /* KUAP Fault */
+#endif
4: mtspr SPRN_MMUCR,r12 /* Set MMUCR */
/* Mask of required permission bits. Note that while we
@@ -669,6 +681,10 @@ finish_tlb_load_44x:
3: mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
mfspr r12,SPRN_PID /* Get PID */
+#ifdef CONFIG_PPC_KUAP
+ cmpwi r12,0
+ beq 2f /* KUAP Fault */
+#endif
4: mtspr SPRN_MMUCR,r12 /* Set MMUCR */
/* Make up the required permissions */
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index fad34f28bd3a..e989eeca4c7e 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -64,6 +64,7 @@ config 44x
select PHYS_64BIT
select PPC_HAVE_KUEP
select PPC_KUEP
+ select PPC_HAVE_KUAP
endchoice
--
2.31.1
^ permalink raw reply related
* [PATCH v3 13/22] powerpc/nohash: Move setup_kuap out of 8xx.c
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
In order to reuse it on booke/4xx, move KUAP
setup routine out of 8xx.c
Make them usable on SMP by removing the __init tag
as it is called for each CPU.
And use __prevent_user_access() instead of hard
coding initial lock.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/mm/nohash/8xx.c | 21 ---------------------
arch/powerpc/mm/nohash/Makefile | 2 +-
arch/powerpc/mm/nohash/kup.c | 31 +++++++++++++++++++++++++++++++
3 files changed, 32 insertions(+), 22 deletions(-)
create mode 100644 arch/powerpc/mm/nohash/kup.c
diff --git a/arch/powerpc/mm/nohash/8xx.c b/arch/powerpc/mm/nohash/8xx.c
index 36010d1c0bc4..27f9186ae374 100644
--- a/arch/powerpc/mm/nohash/8xx.c
+++ b/arch/powerpc/mm/nohash/8xx.c
@@ -8,11 +8,7 @@
*/
#include <linux/memblock.h>
-#include <linux/mmu_context.h>
#include <linux/hugetlb.h>
-#include <asm/fixmap.h>
-#include <asm/code-patching.h>
-#include <asm/inst.h>
#include <mm/mmu_decl.h>
@@ -212,23 +208,6 @@ void __init setup_initial_memory_limit(phys_addr_t first_memblock_base,
memblock_set_current_limit(min_t(u64, first_memblock_size, SZ_32M));
}
-#ifdef CONFIG_PPC_KUAP
-struct static_key_false disable_kuap_key;
-EXPORT_SYMBOL(disable_kuap_key);
-
-void setup_kuap(bool disabled)
-{
- if (disabled) {
- static_branch_enable(&disable_kuap_key);
- return;
- }
-
- pr_info("Activating Kernel Userspace Access Protection\n");
-
- mtspr(SPRN_MD_AP, MD_APG_KUAP);
-}
-#endif
-
int pud_clear_huge(pud_t *pud)
{
return 0;
diff --git a/arch/powerpc/mm/nohash/Makefile b/arch/powerpc/mm/nohash/Makefile
index 0424f6ce5bd8..2ffca5f8a169 100644
--- a/arch/powerpc/mm/nohash/Makefile
+++ b/arch/powerpc/mm/nohash/Makefile
@@ -2,7 +2,7 @@
ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
-obj-y += mmu_context.o tlb.o tlb_low.o
+obj-y += mmu_context.o tlb.o tlb_low.o kup.o
obj-$(CONFIG_PPC_BOOK3E_64) += tlb_low_64e.o book3e_pgtable.o
obj-$(CONFIG_40x) += 40x.o
obj-$(CONFIG_44x) += 44x.o
diff --git a/arch/powerpc/mm/nohash/kup.c b/arch/powerpc/mm/nohash/kup.c
new file mode 100644
index 000000000000..eaea52231dd6
--- /dev/null
+++ b/arch/powerpc/mm/nohash/kup.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * This file contains the routines for initializing kernel userspace protection
+ */
+
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/jump_label.h>
+#include <linux/printk.h>
+#include <linux/smp.h>
+
+#include <asm/kup.h>
+#include <asm/smp.h>
+
+#ifdef CONFIG_PPC_KUAP
+struct static_key_false disable_kuap_key;
+EXPORT_SYMBOL(disable_kuap_key);
+
+void setup_kuap(bool disabled)
+{
+ if (disabled) {
+ if (smp_processor_id() == boot_cpuid)
+ static_branch_enable(&disable_kuap_key);
+ return;
+ }
+
+ pr_info("Activating Kernel Userspace Access Protection\n");
+
+ __prevent_user_access(KUAP_READ_WRITE);
+}
+#endif
--
2.31.1
^ permalink raw reply related
* [PATCH v3 00/22] powerpc: Add KUAP support for BOOKE and 40x
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
On booke/40x we don't have segments like book3s/32.
On booke/40x we don't have access protection groups like 8xx.
Use the PID register to provide user access protection.
Kernel address space can be accessed with any PID.
User address space has to be accessed with the PID of the user.
User PID is always not null.
Everytime the kernel is entered, set PID register to 0 and
restore PID register when returning to user.
Everytime kernel needs to access user data, PID is restored
for the access.
In TLB miss handlers, check the PID and bail out to data storage
exception when PID is 0 and accessed address is in user space.
Note that also forbids execution of user text by kernel except
when user access is unlocked. But this shouldn't be a problem
as the kernel is not supposed to ever run user text.
This series has:
- First five patches remove the complexity due to too much configurability of KUEP (ref https://github.com/linuxppc/issues/issues/379)
- Two following patches have already been submitted and are not directly related to KUAP but would conflict otherwise
- Patch 8 removes 'nosmep' kernel parameter.
- Following patches aim at refactoring the KUAP interface to reduce redundant platform specific code.
- Then comes patches 14 and 15 that add generic support frame for booke type processors
- Followed by the assembly modification for each of the 4 booke family types
- Last patch removes CONFIG_PPC_HAVE_KUAP and CONFIG_PPC_HAVE_KUEP now that all powerpc platforms have KUAP and KUEP.
Changes in v3:
- Added the first five patches plus patch 8 to reduce the configurability of KUEP
- Patch 4 also adds missing KUEP support to book3e in 32 bits PTE mode.
- Modified 6 and 7 to also remove configurability of KUEP
- Patch 19 links KUEP to KUAP
- Last patch now removes both CONFIG_PPC_HAVE_KUAP and CONFIG_PPC_HAVE_KUEP
Changes in v2:
- Rebased on top of today's merge (trivial conflict with d93f9e23744b ("powerpc/32s: Fix kuap_kernel_restore()"))
- Fix missing check in bad_kuap_fault() which led to KUAP fault on platforms where KUAP was disabled (CI g5_defconfig)
- New patch to fix PPC_KUAP_DEBUG dependency
Christophe Leroy (22):
Revert "powerpc: Inline setup_kup()"
powerpc/8xx: Activate KUEP at all time
powerpc/44x: Activate KUEP at all time
powerpc/book3e: Activate KUEP at all time
powerpc/32s: Remove capability to disable KUEP at boottime
powerpc/32s: Do kuep_lock() and kuep_unlock() in assembly
powerpc/32s: Save content of sr0 to avoid 'mfsr'
powerpc/kuep: Remove 'nosmep' boot time parameter except for book3s/64
powerpc/kuap: Add a generic intermediate layer
powerpc/kuap: Check KUAP activation in generic functions
powerpc/kuap: Remove __kuap_assert_locked()
powerpc/kuap: Add kuap_lock()
powerpc/nohash: Move setup_kuap out of 8xx.c
powerpc/config: Add CONFIG_BOOKE_OR_40x
powerpc/kuap: Prepare for supporting KUAP on BOOK3E/64
powerpc/kuap: Make PPC_KUAP_DEBUG depend on PPC_KUAP only
powerpc: Add KUAP support for BOOKE and 40x
powerpc/kuap: Wire-up KUAP on 44x
powerpc/kuap: Wire-up KUAP on 40x
powerpc/kuap: Wire-up KUAP on 85xx in 32 bits mode.
powerpc/kuap: Wire-up KUAP on book3e/64
powerpc: Remove CONFIG_PPC_HAVE_KUAP and CONFIG_PPC_HAVE_KUEP
.../admin-guide/kernel-parameters.txt | 2 +-
arch/powerpc/include/asm/book3s/32/kup.h | 108 ++++------------
arch/powerpc/include/asm/book3s/32/mmu-hash.h | 82 +++++++++++-
arch/powerpc/include/asm/book3s/64/kup.h | 56 ++++----
arch/powerpc/include/asm/hw_irq.h | 8 +-
arch/powerpc/include/asm/interrupt.h | 13 +-
arch/powerpc/include/asm/irq.h | 2 +-
arch/powerpc/include/asm/kup.h | 122 ++++++++++++++----
arch/powerpc/include/asm/nohash/32/kup-8xx.h | 50 ++-----
arch/powerpc/include/asm/nohash/32/mmu-44x.h | 1 -
arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 6 +-
arch/powerpc/include/asm/nohash/kup-booke.h | 110 ++++++++++++++++
arch/powerpc/include/asm/processor.h | 12 ++
arch/powerpc/include/asm/ptrace.h | 2 +-
arch/powerpc/include/asm/reg.h | 4 +-
arch/powerpc/kernel/asm-offsets.c | 3 +-
arch/powerpc/kernel/entry_32.S | 31 ++++-
arch/powerpc/kernel/head_32.h | 6 +
arch/powerpc/kernel/head_40x.S | 8 ++
arch/powerpc/kernel/head_44x.S | 26 ++--
arch/powerpc/kernel/head_book3s_32.S | 4 +
arch/powerpc/kernel/head_fsl_booke.S | 13 ++
arch/powerpc/kernel/interrupt.c | 3 +-
arch/powerpc/kernel/irq.c | 2 +-
arch/powerpc/kernel/kgdb.c | 4 +-
arch/powerpc/kernel/process.c | 9 +-
arch/powerpc/kernel/setup.h | 2 +-
arch/powerpc/kernel/setup_32.c | 2 +-
arch/powerpc/kernel/time.c | 2 +-
arch/powerpc/mm/book3s32/Makefile | 1 -
arch/powerpc/mm/book3s32/kuap.c | 5 +-
arch/powerpc/mm/book3s32/kuep.c | 20 ---
arch/powerpc/mm/book3s32/mmu_context.c | 15 +--
arch/powerpc/mm/init-common.c | 21 +++
arch/powerpc/mm/mmu_context.c | 9 ++
arch/powerpc/mm/nohash/44x.c | 16 ---
arch/powerpc/mm/nohash/8xx.c | 33 -----
arch/powerpc/mm/nohash/Makefile | 2 +-
arch/powerpc/mm/nohash/kup.c | 33 +++++
arch/powerpc/mm/nohash/mmu_context.c | 6 +-
arch/powerpc/mm/nohash/tlb_low_64e.S | 40 +++++-
arch/powerpc/platforms/Kconfig.cputype | 30 ++---
42 files changed, 606 insertions(+), 318 deletions(-)
create mode 100644 arch/powerpc/include/asm/nohash/kup-booke.h
delete mode 100644 arch/powerpc/mm/book3s32/kuep.c
create mode 100644 arch/powerpc/mm/nohash/kup.c
--
2.31.1
^ permalink raw reply
* [PATCH v3 03/22] powerpc/44x: Activate KUEP at all time
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
On 44x, KUEP is implemented by clearing SX bit during TLB miss
for user pages. The impact is minimal and not worth neither
boot time nor build time selection.
Activate it at all time.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/include/asm/nohash/32/mmu-44x.h | 1 -
arch/powerpc/kernel/head_44x.S | 10 ++--------
arch/powerpc/mm/nohash/44x.c | 8 +-------
arch/powerpc/platforms/Kconfig.cputype | 1 +
4 files changed, 4 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/include/asm/nohash/32/mmu-44x.h b/arch/powerpc/include/asm/nohash/32/mmu-44x.h
index 43ceca128531..2d92a39d8f2e 100644
--- a/arch/powerpc/include/asm/nohash/32/mmu-44x.h
+++ b/arch/powerpc/include/asm/nohash/32/mmu-44x.h
@@ -113,7 +113,6 @@ typedef struct {
/* patch sites */
extern s32 patch__tlb_44x_hwater_D, patch__tlb_44x_hwater_I;
-extern s32 patch__tlb_44x_kuep, patch__tlb_47x_kuep;
#endif /* !__ASSEMBLY__ */
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 02d2928d1e01..916f7e91c6de 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -532,10 +532,7 @@ finish_tlb_load_44x:
andi. r10,r12,_PAGE_USER /* User page ? */
beq 1f /* nope, leave U bits empty */
rlwimi r11,r11,3,26,28 /* yes, copy S bits to U */
-#ifdef CONFIG_PPC_KUEP
-0: rlwinm r11,r11,0,~PPC44x_TLB_SX /* Clear SX if User page */
- patch_site 0b, patch__tlb_44x_kuep
-#endif
+ rlwinm r11,r11,0,~PPC44x_TLB_SX /* Clear SX if User page */
1: tlbwe r11,r13,PPC44x_TLB_ATTRIB /* Write ATTRIB */
/* Done...restore registers and get out of here.
@@ -747,10 +744,7 @@ finish_tlb_load_47x:
andi. r10,r12,_PAGE_USER /* User page ? */
beq 1f /* nope, leave U bits empty */
rlwimi r11,r11,3,26,28 /* yes, copy S bits to U */
-#ifdef CONFIG_PPC_KUEP
-0: rlwinm r11,r11,0,~PPC47x_TLB2_SX /* Clear SX if User page */
- patch_site 0b, patch__tlb_47x_kuep
-#endif
+ rlwinm r11,r11,0,~PPC47x_TLB2_SX /* Clear SX if User page */
1: tlbwe r11,r13,2
/* Done...restore registers and get out of here.
diff --git a/arch/powerpc/mm/nohash/44x.c b/arch/powerpc/mm/nohash/44x.c
index e079f26b267e..ceb290df1fb5 100644
--- a/arch/powerpc/mm/nohash/44x.c
+++ b/arch/powerpc/mm/nohash/44x.c
@@ -247,12 +247,6 @@ void setup_kuep(bool disabled)
if (smp_processor_id() != boot_cpuid)
return;
- if (disabled)
- patch_instruction_site(&patch__tlb_44x_kuep, ppc_inst(PPC_RAW_NOP()));
- else
- pr_info("Activating Kernel Userspace Execution Prevention\n");
-
- if (IS_ENABLED(CONFIG_PPC_47x) && disabled)
- patch_instruction_site(&patch__tlb_47x_kuep, ppc_inst(PPC_RAW_NOP()));
+ pr_info("Activating Kernel Userspace Execution Prevention\n");
}
#endif
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 66650ec1c7e6..6f2e8a4026ff 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -63,6 +63,7 @@ config 44x
select HAVE_PCI
select PHYS_64BIT
select PPC_HAVE_KUEP
+ select PPC_KUEP
endchoice
--
2.31.1
^ permalink raw reply related
* [PATCH v3 19/22] powerpc/kuap: Wire-up KUAP on 40x
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
This adds KUAP support to 40x. This is done by checking
the content of SPRN_PID at the time user pgtable is loaded.
40x doesn't have KUEP, but KUAP implies KUEP because when the
PID doesn't match the page's PID, the page cannot be read nor
executed.
So KUEP is now automatically selected when KUAP is selected and
disabled when KUAP is disabled.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/kernel/head_40x.S | 8 ++++++++
arch/powerpc/mm/nohash/kup.c | 2 ++
arch/powerpc/platforms/Kconfig.cputype | 7 +++++--
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index 7d72ee5ab387..87d322dbed94 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -297,6 +297,10 @@ _ASM_NOKPROBE_SYMBOL(\name\()_virt)
3:
mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
+#ifdef CONFIG_PPC_KUAP
+ rlwinm. r9, r9, 0, 0xff
+ beq 5f /* Kuap fault */
+#endif
4:
tophys(r11, r11)
rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */
@@ -377,6 +381,10 @@ _ASM_NOKPROBE_SYMBOL(\name\()_virt)
3:
mfspr r11,SPRN_SPRG_THREAD
lwz r11,PGDIR(r11)
+#ifdef CONFIG_PPC_KUAP
+ rlwinm. r9, r9, 0, 0xff
+ beq 5f /* Kuap fault */
+#endif
4:
tophys(r11, r11)
rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */
diff --git a/arch/powerpc/mm/nohash/kup.c b/arch/powerpc/mm/nohash/kup.c
index eaea52231dd6..552becf90e97 100644
--- a/arch/powerpc/mm/nohash/kup.c
+++ b/arch/powerpc/mm/nohash/kup.c
@@ -19,6 +19,8 @@ EXPORT_SYMBOL(disable_kuap_key);
void setup_kuap(bool disabled)
{
if (disabled) {
+ if (IS_ENABLED(CONFIG_40x))
+ disable_kuep = true;
if (smp_processor_id() == boot_cpuid)
static_branch_enable(&disable_kuap_key);
return;
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index e989eeca4c7e..3ea415bcf9b8 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -54,6 +54,9 @@ config 40x
select PPC_UDBG_16550
select 4xx_SOC
select HAVE_PCI
+ select PPC_HAVE_KUAP
+ select PPC_HAVE_KUEP
+ select PPC_KUEP if PPC_KUAP
config 44x
bool "AMCC 44x, 46x or 47x"
@@ -401,9 +404,9 @@ config PPC_HAVE_KUEP
bool
config PPC_KUEP
- bool "Kernel Userspace Execution Prevention"
+ bool "Kernel Userspace Execution Prevention" if !40x
depends on PPC_HAVE_KUEP
- default y
+ default y if !40x
help
Enable support for Kernel Userspace Execution Prevention (KUEP)
--
2.31.1
^ permalink raw reply related
* [PATCH v3 15/22] powerpc/kuap: Prepare for supporting KUAP on BOOK3E/64
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
Also call kuap_lock() and kuap_save_and_lock() from
interrupt functions with CONFIG_PPC64.
For book3s/64 we keep them empty as it is done in assembly.
Also do the locked assert when switching task unless it is
book3s/64.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/include/asm/book3s/64/kup.h | 9 +++++++++
arch/powerpc/include/asm/interrupt.h | 2 ++
arch/powerpc/include/asm/kup.h | 2 --
arch/powerpc/kernel/process.c | 6 +++---
4 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h
index 503828709d55..69fcf63eec94 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -298,6 +298,15 @@ static inline unsigned long __kuap_get_and_assert_locked(void)
return amr;
}
+/* Do nothing, book3s/64 does that in ASM */
+static inline void __kuap_lock(void)
+{
+}
+
+static inline void __kuap_save_and_lock(struct pt_regs *regs)
+{
+}
+
/*
* We support individually allowing read or write, but we don't support nesting
* because that would require an expensive read/modify write of the AMR.
diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h
index ae719e200c80..cd78dbca49e5 100644
--- a/arch/powerpc/include/asm/interrupt.h
+++ b/arch/powerpc/include/asm/interrupt.h
@@ -154,12 +154,14 @@ static inline void interrupt_enter_prepare(struct pt_regs *regs, struct interrup
local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
if (user_mode(regs)) {
+ kuap_lock();
CT_WARN_ON(ct_state() != CONTEXT_USER);
user_exit_irqoff();
account_cpu_user_entry();
account_stolen_time();
} else {
+ kuap_save_and_lock(regs);
/*
* CT_WARN_ON comes here via program_check_exception,
* so avoid recursion.
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 34574a7455ce..656e6f1d6b6f 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -91,7 +91,6 @@ static __always_inline void kuap_assert_locked(void)
__kuap_get_and_assert_locked();
}
-#ifdef CONFIG_PPC32
static __always_inline void kuap_lock(void)
{
if (kuap_is_disabled())
@@ -107,7 +106,6 @@ static __always_inline void kuap_save_and_lock(struct pt_regs *regs)
__kuap_save_and_lock(regs);
}
-#endif
static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr)
{
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 50436b52c213..2c637740c0c2 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1281,9 +1281,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
set_return_regs_changed(); /* _switch changes stack (and regs) */
-#ifdef CONFIG_PPC32
- kuap_assert_locked();
-#endif
+ if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64))
+ kuap_assert_locked();
+
last = _switch(old_thread, new_thread);
/*
--
2.31.1
^ permalink raw reply related
* [PATCH v3 22/22] powerpc: Remove CONFIG_PPC_HAVE_KUAP and CONFIG_PPC_HAVE_KUEP
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
All platforms now have KUAP and KUEP so remove CONFIG_PPC_HAVE_KUAP
and CONFIG_PPC_HAVE_KUEP.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/platforms/Kconfig.cputype | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index f3614bfd47ad..744cb201ae4d 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -30,22 +30,17 @@ config PPC_BOOK3S_32
bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
imply PPC_FPU
select PPC_HAVE_PMU_SUPPORT
- select PPC_HAVE_KUEP
- select PPC_HAVE_KUAP
select HAVE_ARCH_VMAP_STACK
config PPC_85xx
bool "Freescale 85xx"
select E500
- select PPC_HAVE_KUAP
config PPC_8xx
bool "Freescale 8xx"
select ARCH_SUPPORTS_HUGETLBFS
select FSL_SOC
- select PPC_HAVE_KUEP
select PPC_KUEP
- select PPC_HAVE_KUAP
select HAVE_ARCH_VMAP_STACK
select HUGETLBFS
@@ -55,8 +50,6 @@ config 40x
select PPC_UDBG_16550
select 4xx_SOC
select HAVE_PCI
- select PPC_HAVE_KUAP
- select PPC_HAVE_KUEP
select PPC_KUEP if PPC_KUAP
config 44x
@@ -66,9 +59,7 @@ config 44x
select 4xx_SOC
select HAVE_PCI
select PHYS_64BIT
- select PPC_HAVE_KUEP
select PPC_KUEP
- select PPC_HAVE_KUAP
endchoice
@@ -113,8 +104,6 @@ config PPC_BOOK3S_64
select HAVE_MOVE_PUD
select IRQ_WORK
select PPC_MM_SLICES
- select PPC_HAVE_KUEP
- select PPC_HAVE_KUAP
config PPC_BOOK3E_64
bool "Embedded processors"
@@ -122,7 +111,6 @@ config PPC_BOOK3E_64
select PPC_SMP_MUXED_IPI
select PPC_DOORBELL
select ZONE_DMA
- select PPC_HAVE_KUAP
endchoice
@@ -303,7 +291,6 @@ config PPC_FSL_BOOK3E
select FSL_EMB_PERFMON
select PPC_SMP_MUXED_IPI
select PPC_DOORBELL
- select PPC_HAVE_KUEP
select PPC_KUEP
default y if FSL_BOOKE
@@ -402,24 +389,16 @@ config PPC_RADIX_MMU_DEFAULT
If you're unsure, say Y.
-config PPC_HAVE_KUEP
- bool
-
config PPC_KUEP
bool "Kernel Userspace Execution Prevention" if !40x
- depends on PPC_HAVE_KUEP
default y if !40x
help
Enable support for Kernel Userspace Execution Prevention (KUEP)
If you're unsure, say Y.
-config PPC_HAVE_KUAP
- bool
-
config PPC_KUAP
bool "Kernel Userspace Access Protection"
- depends on PPC_HAVE_KUAP
default y
help
Enable support for Kernel Userspace Access Protection (KUAP)
--
2.31.1
^ permalink raw reply related
* [PATCH v3 16/22] powerpc/kuap: Make PPC_KUAP_DEBUG depend on PPC_KUAP only
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
PPC_KUAP_DEBUG is supported by all platforms doing PPC_KUAP,
it doesn't depend on Radix on book3s/64.
This will avoid adding one more dependency when implementing
KUAP on book3e/64.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v2: New
---
arch/powerpc/platforms/Kconfig.cputype | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index f58f9edf9b28..fad34f28bd3a 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -422,7 +422,7 @@ config PPC_KUAP
config PPC_KUAP_DEBUG
bool "Extra debugging for Kernel Userspace Access Protection"
- depends on PPC_KUAP && (PPC_RADIX_MMU || PPC32)
+ depends on PPC_KUAP
help
Add extra debugging for Kernel Userspace Access Protection (KUAP)
If you're unsure, say N.
--
2.31.1
^ permalink raw reply related
* [PATCH v3 10/22] powerpc/kuap: Check KUAP activation in generic functions
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
Today, every platform checks that KUAP is not de-activated
before doing the real job.
Move the verification out of platform specific functions.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v2: Added missing check in bad_kuap_fault()
---
arch/powerpc/include/asm/book3s/32/kup.h | 34 +++-------------
arch/powerpc/include/asm/book3s/64/kup.h | 41 ++++++++++----------
arch/powerpc/include/asm/kup.h | 29 ++++++++++++++
arch/powerpc/include/asm/nohash/32/kup-8xx.h | 28 +------------
4 files changed, 56 insertions(+), 76 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/32/kup.h b/arch/powerpc/include/asm/book3s/32/kup.h
index 9e9b2692070c..35ca48f7c293 100644
--- a/arch/powerpc/include/asm/book3s/32/kup.h
+++ b/arch/powerpc/include/asm/book3s/32/kup.h
@@ -13,11 +13,6 @@
extern struct static_key_false disable_kuap_key;
-static __always_inline bool kuap_is_disabled(void)
-{
- return !IS_ENABLED(CONFIG_PPC_KUAP) || static_branch_unlikely(&disable_kuap_key);
-}
-
static __always_inline bool kuep_is_disabled(void)
{
return !IS_ENABLED(CONFIG_PPC_KUEP);
@@ -30,6 +25,11 @@ static __always_inline bool kuep_is_disabled(void)
#define KUAP_NONE (~0UL)
#define KUAP_ALL (~1UL)
+static __always_inline bool kuap_is_disabled(void)
+{
+ return static_branch_unlikely(&disable_kuap_key);
+}
+
static inline void kuap_lock_one(unsigned long addr)
{
mtsr(mfsr(addr) | SR_KS, addr);
@@ -81,9 +81,6 @@ static inline void __kuap_save_and_lock(struct pt_regs *regs)
{
unsigned long kuap = current->thread.kuap;
- if (kuap_is_disabled())
- return;
-
regs->kuap = kuap;
if (unlikely(kuap == KUAP_NONE))
return;
@@ -98,9 +95,6 @@ static inline void kuap_user_restore(struct pt_regs *regs)
static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
{
- if (kuap_is_disabled())
- return;
-
if (unlikely(kuap != KUAP_NONE)) {
current->thread.kuap = KUAP_NONE;
kuap_lock(kuap, false);
@@ -118,9 +112,6 @@ static inline unsigned long __kuap_get_and_assert_locked(void)
{
unsigned long kuap = current->thread.kuap;
- if (kuap_is_disabled())
- return KUAP_NONE;
-
WARN_ON_ONCE(IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && kuap != KUAP_NONE);
return kuap;
@@ -134,9 +125,6 @@ static inline void __kuap_assert_locked(void)
static __always_inline void __allow_user_access(void __user *to, const void __user *from,
u32 size, unsigned long dir)
{
- if (kuap_is_disabled())
- return;
-
BUILD_BUG_ON(!__builtin_constant_p(dir));
if (!(dir & KUAP_WRITE))
@@ -150,9 +138,6 @@ static __always_inline void __prevent_user_access(unsigned long dir)
{
u32 kuap = current->thread.kuap;
- if (kuap_is_disabled())
- return;
-
BUILD_BUG_ON(!__builtin_constant_p(dir));
if (!(dir & KUAP_WRITE))
@@ -166,9 +151,6 @@ static inline unsigned long __prevent_user_access_return(void)
{
unsigned long flags = current->thread.kuap;
- if (kuap_is_disabled())
- return KUAP_NONE;
-
if (flags != KUAP_NONE) {
current->thread.kuap = KUAP_NONE;
kuap_lock(flags, true);
@@ -179,9 +161,6 @@ static inline unsigned long __prevent_user_access_return(void)
static inline void __restore_user_access(unsigned long flags)
{
- if (kuap_is_disabled())
- return;
-
if (flags != KUAP_NONE) {
current->thread.kuap = flags;
kuap_unlock(flags, true);
@@ -193,9 +172,6 @@ __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
unsigned long kuap = regs->kuap;
- if (kuap_is_disabled())
- return false;
-
if (!is_write || kuap == KUAP_ALL)
return false;
if (kuap == KUAP_NONE)
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h
index 03d61c5205a4..9f2099790658 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -229,6 +229,11 @@ static inline u64 current_thread_iamr(void)
#ifdef CONFIG_PPC_KUAP
+static __always_inline bool kuap_is_disabled(void)
+{
+ return !mmu_has_feature(MMU_FTR_BOOK3S_KUAP);
+}
+
static inline void kuap_user_restore(struct pt_regs *regs)
{
bool restore_amr = false, restore_iamr = false;
@@ -270,36 +275,32 @@ static inline void kuap_user_restore(struct pt_regs *regs)
static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr)
{
- if (mmu_has_feature(MMU_FTR_BOOK3S_KUAP)) {
- if (unlikely(regs->amr != amr)) {
- isync();
- mtspr(SPRN_AMR, regs->amr);
- /*
- * 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.
- */
- }
- }
+ if (likely(regs->amr == amr))
+ return;
+
+ isync();
+ mtspr(SPRN_AMR, regs->amr);
/*
+ * 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.
+ *
* No need to restore IAMR when returning to kernel space.
*/
}
static inline unsigned long __kuap_get_and_assert_locked(void)
{
- if (mmu_has_feature(MMU_FTR_BOOK3S_KUAP)) {
- unsigned long amr = mfspr(SPRN_AMR);
- if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) /* kuap_check_amr() */
- WARN_ON_ONCE(amr != AMR_KUAP_BLOCKED);
- return amr;
- }
- return 0;
+ unsigned long amr = mfspr(SPRN_AMR);
+
+ if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) /* kuap_check_amr() */
+ WARN_ON_ONCE(amr != AMR_KUAP_BLOCKED);
+ return amr;
}
static inline void __kuap_assert_locked(void)
{
- if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && mmu_has_feature(MMU_FTR_BOOK3S_KUAP))
+ if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
WARN_ON_ONCE(mfspr(SPRN_AMR) != AMR_KUAP_BLOCKED);
}
@@ -340,8 +341,6 @@ static inline void set_kuap(unsigned long value)
static inline bool __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
- if (!mmu_has_feature(MMU_FTR_BOOK3S_KUAP))
- return false;
/*
* For radix this will be a storage protection fault (DSISR_PROTFAULT).
* For hash this will be a key fault (DSISR_KEYFAULT)
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index f2a6fdb45d33..33e93a6c5d19 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -40,6 +40,8 @@ void setup_kuap(bool disabled);
#else
static inline void setup_kuap(bool disabled) { }
+static __always_inline bool kuap_is_disabled(void) { return true; }
+
static inline bool
__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
@@ -73,28 +75,43 @@ static inline void __restore_user_access(unsigned long flags) { }
static __always_inline bool
bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
+ if (kuap_is_disabled())
+ return false;
+
return __bad_kuap_fault(regs, address, is_write);
}
static __always_inline void kuap_assert_locked(void)
{
+ if (kuap_is_disabled())
+ return;
+
__kuap_assert_locked();
}
#ifdef CONFIG_PPC32
static __always_inline void kuap_save_and_lock(struct pt_regs *regs)
{
+ if (kuap_is_disabled())
+ return;
+
__kuap_save_and_lock(regs);
}
#endif
static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr)
{
+ if (kuap_is_disabled())
+ return;
+
__kuap_kernel_restore(regs, amr);
}
static __always_inline unsigned long kuap_get_and_assert_locked(void)
{
+ if (kuap_is_disabled())
+ return 0;
+
return __kuap_get_and_assert_locked();
}
@@ -102,21 +119,33 @@ static __always_inline unsigned long kuap_get_and_assert_locked(void)
static __always_inline void allow_user_access(void __user *to, const void __user *from,
unsigned long size, unsigned long dir)
{
+ if (kuap_is_disabled())
+ return;
+
__allow_user_access(to, from, size, dir);
}
static __always_inline void prevent_user_access(unsigned long dir)
{
+ if (kuap_is_disabled())
+ return;
+
__prevent_user_access(dir);
}
static __always_inline unsigned long prevent_user_access_return(void)
{
+ if (kuap_is_disabled())
+ return 0;
+
return __prevent_user_access_return();
}
static __always_inline void restore_user_access(unsigned long flags)
{
+ if (kuap_is_disabled())
+ return;
+
__restore_user_access(flags);
}
#endif /* CONFIG_PPC_BOOK3S_64 */
diff --git a/arch/powerpc/include/asm/nohash/32/kup-8xx.h b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
index a5db84164afd..74f15c386476 100644
--- a/arch/powerpc/include/asm/nohash/32/kup-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
@@ -22,9 +22,6 @@ static __always_inline bool kuap_is_disabled(void)
static inline void __kuap_save_and_lock(struct pt_regs *regs)
{
- if (kuap_is_disabled())
- return;
-
regs->kuap = mfspr(SPRN_MD_AP);
mtspr(SPRN_MD_AP, MD_APG_KUAP);
}
@@ -35,9 +32,6 @@ static inline void kuap_user_restore(struct pt_regs *regs)
static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
{
- if (kuap_is_disabled())
- return;
-
mtspr(SPRN_MD_AP, regs->kuap);
}
@@ -45,9 +39,6 @@ static inline unsigned long __kuap_get_and_assert_locked(void)
{
unsigned long kuap;
- if (kuap_is_disabled())
- return MD_APG_INIT;
-
kuap = mfspr(SPRN_MD_AP);
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
@@ -58,24 +49,18 @@ static inline unsigned long __kuap_get_and_assert_locked(void)
static inline void __kuap_assert_locked(void)
{
- if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && !kuap_is_disabled())
- kuap_get_and_assert_locked();
+ if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
+ __kuap_get_and_assert_locked();
}
static inline void __allow_user_access(void __user *to, const void __user *from,
unsigned long size, unsigned long dir)
{
- if (kuap_is_disabled())
- return;
-
mtspr(SPRN_MD_AP, MD_APG_INIT);
}
static inline void __prevent_user_access(unsigned long dir)
{
- if (kuap_is_disabled())
- return;
-
mtspr(SPRN_MD_AP, MD_APG_KUAP);
}
@@ -83,9 +68,6 @@ static inline unsigned long __prevent_user_access_return(void)
{
unsigned long flags;
- if (kuap_is_disabled())
- return MD_APG_INIT;
-
flags = mfspr(SPRN_MD_AP);
mtspr(SPRN_MD_AP, MD_APG_KUAP);
@@ -95,18 +77,12 @@ static inline unsigned long __prevent_user_access_return(void)
static inline void __restore_user_access(unsigned long flags)
{
- if (kuap_is_disabled())
- return;
-
mtspr(SPRN_MD_AP, flags);
}
static inline bool
__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
{
- if (kuap_is_disabled())
- return false;
-
return !((regs->kuap ^ MD_APG_KUAP) & 0xff000000);
}
--
2.31.1
^ permalink raw reply related
* [PATCH v3 01/22] Revert "powerpc: Inline setup_kup()"
From: Christophe Leroy @ 2021-10-19 7:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1634627931.git.christophe.leroy@csgroup.eu>
This reverts commit 1791ebd131c46539b024c0f2ebf12b6c88a265b9.
setup_kup() was inlined to manage conflict between PPC32 marking
setup_{kuap/kuep}() __init and PPC64 not marking them __init.
But in fact PPC32 has removed the __init mark for all but 8xx
in order to properly handle SMP.
In order to make setup_kup() grow a bit, revert the commit
mentioned above but remove __init for 8xx as well so that
we don't have to mark setup_kup() as __ref.
Also switch the order so that KUAP is initialised before KUEP
because on the 40x, KUEP will depend on the activation of KUAP.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/include/asm/kup.h | 8 ++------
arch/powerpc/mm/init-common.c | 6 ++++++
arch/powerpc/mm/nohash/8xx.c | 4 ++--
3 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 1df763002726..8699ca5884b9 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -32,6 +32,8 @@ extern bool disable_kuap;
#include <linux/pgtable.h>
+void setup_kup(void);
+
#ifdef CONFIG_PPC_KUEP
void setup_kuep(bool disabled);
#else
@@ -78,12 +80,6 @@ static inline void restore_user_access(unsigned long flags) { }
#endif /* CONFIG_PPC_BOOK3S_64 */
#endif /* CONFIG_PPC_KUAP */
-static __always_inline void setup_kup(void)
-{
- setup_kuep(disable_kuep);
- setup_kuap(disable_kuap);
-}
-
static __always_inline void allow_read_from_user(const void __user *from, unsigned long size)
{
barrier_nospec();
diff --git a/arch/powerpc/mm/init-common.c b/arch/powerpc/mm/init-common.c
index 3a82f89827a5..b4f3437aee38 100644
--- a/arch/powerpc/mm/init-common.c
+++ b/arch/powerpc/mm/init-common.c
@@ -47,6 +47,12 @@ static int __init parse_nosmap(char *p)
}
early_param("nosmap", parse_nosmap);
+void setup_kup(void)
+{
+ setup_kuap(disable_kuap);
+ setup_kuep(disable_kuep);
+}
+
#define CTOR(shift) static void ctor_##shift(void *addr) \
{ \
memset(addr, 0, sizeof(void *) << (shift)); \
diff --git a/arch/powerpc/mm/nohash/8xx.c b/arch/powerpc/mm/nohash/8xx.c
index 0df9fe29dd56..baa1f8a40af8 100644
--- a/arch/powerpc/mm/nohash/8xx.c
+++ b/arch/powerpc/mm/nohash/8xx.c
@@ -213,7 +213,7 @@ void __init setup_initial_memory_limit(phys_addr_t first_memblock_base,
}
#ifdef CONFIG_PPC_KUEP
-void __init setup_kuep(bool disabled)
+void setup_kuep(bool disabled)
{
if (disabled)
return;
@@ -228,7 +228,7 @@ void __init setup_kuep(bool disabled)
struct static_key_false disable_kuap_key;
EXPORT_SYMBOL(disable_kuap_key);
-void __init setup_kuap(bool disabled)
+void setup_kuap(bool disabled)
{
if (disabled) {
static_branch_enable(&disable_kuap_key);
--
2.31.1
^ permalink raw reply related
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