* [PATCH] powerpc: Add ppc_inst_as_u64()
From: Michael Ellerman @ 2020-05-25 5:50 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jniethe5
The code patching code wants to get the value of a struct ppc_inst as
a u64 when the instruction is prefixed, so we can pass the u64 down to
__put_user_asm() and write it with a single store.
This is a bit awkward because the value differs based on the CPU
endianness, so add a helper to do the conversion.
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/include/asm/inst.h | 9 +++++++++
arch/powerpc/kernel/optprobes.c | 3 +--
arch/powerpc/lib/code-patching.c | 8 +-------
3 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/include/asm/inst.h b/arch/powerpc/include/asm/inst.h
index d82e0c99cfa1..d61e07fb2937 100644
--- a/arch/powerpc/include/asm/inst.h
+++ b/arch/powerpc/include/asm/inst.h
@@ -100,6 +100,15 @@ static inline int ppc_inst_len(struct ppc_inst x)
return ppc_inst_prefixed(x) ? 8 : 4;
}
+static inline u64 ppc_inst_as_u64(struct ppc_inst x)
+{
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+ return (u64)ppc_inst_suffix(x) << 32 | ppc_inst_val(x);
+#else
+ return (u64)ppc_inst_val(x) << 32 | ppc_inst_suffix(x);
+#endif
+}
+
int probe_user_read_inst(struct ppc_inst *inst,
struct ppc_inst __user *nip);
diff --git a/arch/powerpc/kernel/optprobes.c b/arch/powerpc/kernel/optprobes.c
index 3ac105e7faae..69bfe96884e2 100644
--- a/arch/powerpc/kernel/optprobes.c
+++ b/arch/powerpc/kernel/optprobes.c
@@ -283,8 +283,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
* 3. load instruction to be emulated into relevant register, and
*/
temp = ppc_inst_read((struct ppc_inst *)p->ainsn.insn);
- patch_imm64_load_insns(ppc_inst_val(temp) | ((u64)ppc_inst_suffix(temp) << 32),
- 4, buff + TMPL_INSN_IDX);
+ patch_imm64_load_insns(ppc_inst_as_u64(temp), 4, buff + TMPL_INSN_IDX);
/*
* 4. branch back from trampoline
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
index 64cf621e5b00..5ecf0d635a8d 100644
--- a/arch/powerpc/lib/code-patching.c
+++ b/arch/powerpc/lib/code-patching.c
@@ -27,13 +27,7 @@ static int __patch_instruction(struct ppc_inst *exec_addr, struct ppc_inst instr
if (!ppc_inst_prefixed(instr)) {
__put_user_asm(ppc_inst_val(instr), patch_addr, err, "stw");
} else {
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
- __put_user_asm((u64)ppc_inst_suffix(instr) << 32 |
- ppc_inst_val(instr), patch_addr, err, "std");
-#else
- __put_user_asm((u64)ppc_inst_val(instr) << 32 |
- ppc_inst_suffix(instr), patch_addr, err, "std");
-#endif
+ __put_user_asm(ppc_inst_as_u64(instr), patch_addr, err, "std");
}
if (err)
--
2.25.1
^ permalink raw reply related
* [powerpc:merge] BUILD SUCCESS 1ef93962cf4293ec9e1bb3163cc4b7dcfc3de84f
From: kbuild test robot @ 2020-05-25 5:45 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git merge
branch HEAD: 1ef93962cf4293ec9e1bb3163cc4b7dcfc3de84f Automatic merge of 'master', 'next' and 'fixes' (2020-05-22 23:44)
elapsed time: 3835m
configs tested: 92
configs skipped: 1
The following configs have been built successfully.
More configs may be tested in the coming days.
arm64 allyesconfig
arm64 defconfig
arm64 allmodconfig
arm64 allnoconfig
arm defconfig
arm allyesconfig
arm allmodconfig
arm allnoconfig
m68k allyesconfig
sparc allyesconfig
mips allyesconfig
i386 allnoconfig
i386 allyesconfig
i386 defconfig
i386 debian-10.3
ia64 allmodconfig
ia64 defconfig
ia64 allnoconfig
ia64 allyesconfig
m68k allmodconfig
m68k allnoconfig
m68k sun3_defconfig
m68k defconfig
nios2 defconfig
nios2 allyesconfig
openrisc defconfig
c6x allyesconfig
c6x allnoconfig
openrisc allyesconfig
nds32 defconfig
nds32 allnoconfig
csky allyesconfig
csky defconfig
alpha defconfig
alpha allyesconfig
xtensa allyesconfig
h8300 allyesconfig
h8300 allmodconfig
xtensa defconfig
arc defconfig
sh allnoconfig
microblaze allnoconfig
arc allyesconfig
sh allmodconfig
mips allnoconfig
mips allmodconfig
parisc allnoconfig
parisc defconfig
parisc allyesconfig
parisc allmodconfig
powerpc defconfig
powerpc allyesconfig
powerpc rhel-kconfig
powerpc allmodconfig
powerpc allnoconfig
i386 randconfig-a001-20200524
i386 randconfig-a004-20200524
i386 randconfig-a006-20200524
i386 randconfig-a003-20200524
i386 randconfig-a002-20200524
i386 randconfig-a005-20200524
i386 randconfig-a013-20200524
i386 randconfig-a015-20200524
i386 randconfig-a012-20200524
i386 randconfig-a011-20200524
i386 randconfig-a016-20200524
i386 randconfig-a014-20200524
riscv allyesconfig
riscv allnoconfig
riscv defconfig
riscv allmodconfig
s390 allyesconfig
s390 allnoconfig
s390 allmodconfig
s390 defconfig
x86_64 defconfig
sparc defconfig
sparc64 defconfig
sparc64 allnoconfig
sparc64 allyesconfig
sparc64 allmodconfig
um allmodconfig
um allnoconfig
um defconfig
um allyesconfig
x86_64 rhel
x86_64 rhel-7.6
x86_64 rhel-7.6-kselftests
x86_64 rhel-7.2-clear
x86_64 lkp
x86_64 fedora-25
x86_64 kexec
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply
* Re: [PATCH v4 14/45] powerpc/32s: Don't warn when mapping RO data ROX.
From: Michael Ellerman @ 2020-05-25 5:40 UTC (permalink / raw)
To: Christophe Leroy, Benjamin Herrenschmidt, Paul Mackerras
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <6499f8eeb2a36330e5c9fc1cee9a79374875bd54.1589866984.git.christophe.leroy@csgroup.eu>
Christophe Leroy <christophe.leroy@csgroup.eu> writes:
> Mapping RO data as ROX is not an issue since that data
> cannot be modified to introduce an exploit.
Being pedantic: it is still an issue, in that it means there's more
targets for a code-reuse attack.
But given the entire kernel text is also available for code-reuse
attacks, the RO data is unlikely to contain any useful sequences that
aren't also in the kernel text.
> PPC64 accepts to have RO data mapped ROX, as a trade off
> between kernel size and strictness of protection.
>
> On PPC32, kernel size is even more critical as amount of
> memory is usually small.
Yep, I think it's a reasonable trade off to make.
cheers
> Depending on the number of available IBATs, the last IBATs
> might overflow the end of text. Only warn if it crosses
> the end of RO data.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> ---
> arch/powerpc/mm/book3s32/mmu.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c
> index 39ba53ca5bb5..a9b2cbc74797 100644
> --- a/arch/powerpc/mm/book3s32/mmu.c
> +++ b/arch/powerpc/mm/book3s32/mmu.c
> @@ -187,6 +187,7 @@ void mmu_mark_initmem_nx(void)
> int i;
> unsigned long base = (unsigned long)_stext - PAGE_OFFSET;
> unsigned long top = (unsigned long)_etext - PAGE_OFFSET;
> + unsigned long border = (unsigned long)__init_begin - PAGE_OFFSET;
> unsigned long size;
>
> if (IS_ENABLED(CONFIG_PPC_BOOK3S_601))
> @@ -201,9 +202,10 @@ void mmu_mark_initmem_nx(void)
> size = block_size(base, top);
> size = max(size, 128UL << 10);
> if ((top - base) > size) {
> - if (strict_kernel_rwx_enabled())
> - pr_warn("Kernel _etext not properly aligned\n");
> size <<= 1;
> + if (strict_kernel_rwx_enabled() && base + size > border)
> + pr_warn("Some RW data is getting mapped X. "
> + "Adjust CONFIG_DATA_SHIFT to avoid that.\n");
> }
> setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
> base += size;
> --
> 2.25.0
^ permalink raw reply
* Re: [PATCH v4 07/45] powerpc/ptdump: Limit size of flags text to 1/2 chars on PPC32
From: Michael Ellerman @ 2020-05-25 5:15 UTC (permalink / raw)
To: Christophe Leroy, Benjamin Herrenschmidt, Paul Mackerras
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <83a7a0cfca6198e63caf7a16839bd18454961f52.1589866984.git.christophe.leroy@csgroup.eu>
Christophe Leroy <christophe.leroy@csgroup.eu> writes:
> In order to have all flags fit on a 80 chars wide screen,
> reduce the flags to 1 char (2 where ambiguous).
I don't love this, the output is less readable. Is fitting on an 80 char
screen a real issue for you? I just make my terminal window bigger.
cheers
> No cache is 'i'
> User is 'ur' (Supervisor would be sr)
> Shared (for 8xx) becomes 'sh' (it was 'user' when not shared but
> that was ambiguous because that's not entirely right)
>
> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> ---
> arch/powerpc/mm/ptdump/8xx.c | 33 ++++++++++++++++---------------
> arch/powerpc/mm/ptdump/shared.c | 35 +++++++++++++++++----------------
> 2 files changed, 35 insertions(+), 33 deletions(-)
^ permalink raw reply
* Re: [PATCH] ASoC: fsl_asrc: Merge suspend/resume function to runtime_suspend/resume
From: Nicolin Chen @ 2020-05-25 5:09 UTC (permalink / raw)
To: Shengjiu Wang
Cc: alsa-devel, timur, Xiubo.Lee, linuxppc-dev, tiwai, lgirdwood,
perex, broonie, festevam, linux-kernel
In-Reply-To: <1590141444-28668-1-git-send-email-shengjiu.wang@nxp.com>
On Fri, May 22, 2020 at 05:57:24PM +0800, Shengjiu Wang wrote:
> With dedicated power domain for asrc, power can be disabled after
> probe and pm runtime suspend, then the value of all registers need to
> be restored in pm runtime resume. So we can merge suspend/resume function
> to runtime_suspend/resume function and enable regcache only in end of
> probe.
>
> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> ---
> sound/soc/fsl/fsl_asrc.c | 70 ++++++++++++++++------------------------
> 1 file changed, 27 insertions(+), 43 deletions(-)
>
> diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
> index 432936039de4..3ebbe15ac378 100644
> --- a/sound/soc/fsl/fsl_asrc.c
> +++ b/sound/soc/fsl/fsl_asrc.c
> @@ -1100,6 +1100,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
> platform_set_drvdata(pdev, asrc);
> pm_runtime_enable(&pdev->dev);
> spin_lock_init(&asrc->lock);
> + regcache_cache_only(asrc->regmap, true);
>
> ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component,
> &fsl_asrc_dai, 1);
> @@ -1117,6 +1118,7 @@ static int fsl_asrc_runtime_resume(struct device *dev)
> struct fsl_asrc *asrc = dev_get_drvdata(dev);
> struct fsl_asrc_priv *asrc_priv = asrc->private;
> int i, ret;
> + u32 asrctr;
>
> ret = clk_prepare_enable(asrc->mem_clk);
> if (ret)
> @@ -1135,6 +1137,24 @@ static int fsl_asrc_runtime_resume(struct device *dev)
> goto disable_asrck_clk;
> }
>
> + /* Stop all pairs provisionally */
> + regmap_read(asrc->regmap, REG_ASRCTR, &asrctr);
> + regmap_update_bits(asrc->regmap, REG_ASRCTR,
> + ASRCTR_ASRCEi_ALL_MASK, 0);
> +
> + /* Restore all registers */
> + regcache_cache_only(asrc->regmap, false);
> + regcache_mark_dirty(asrc->regmap);
I see you doing regcache_mark_dirty() in the resume() now,
being different from previously doing in suspend()?
Thanks
Nic
> + regcache_sync(asrc->regmap);
> +
> + regmap_update_bits(asrc->regmap, REG_ASRCFG,
> + ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK |
> + ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
> +
> + /* Restart enabled pairs */
> + regmap_update_bits(asrc->regmap, REG_ASRCTR,
> + ASRCTR_ASRCEi_ALL_MASK, asrctr);
> +
> return 0;
>
> disable_asrck_clk:
> @@ -1155,6 +1175,11 @@ static int fsl_asrc_runtime_suspend(struct device *dev)
> struct fsl_asrc_priv *asrc_priv = asrc->private;
> int i;
>
> + regmap_read(asrc->regmap, REG_ASRCFG,
> + &asrc_priv->regcache_cfg);
> +
> + regcache_cache_only(asrc->regmap, true);
> +
> for (i = 0; i < ASRC_CLK_MAX_NUM; i++)
> clk_disable_unprepare(asrc_priv->asrck_clk[i]);
> if (!IS_ERR(asrc->spba_clk))
> @@ -1166,51 +1191,10 @@ static int fsl_asrc_runtime_suspend(struct device *dev)
> }
> #endif /* CONFIG_PM */
>
> -#ifdef CONFIG_PM_SLEEP
> -static int fsl_asrc_suspend(struct device *dev)
> -{
> - struct fsl_asrc *asrc = dev_get_drvdata(dev);
> - struct fsl_asrc_priv *asrc_priv = asrc->private;
> -
> - regmap_read(asrc->regmap, REG_ASRCFG,
> - &asrc_priv->regcache_cfg);
> -
> - regcache_cache_only(asrc->regmap, true);
> - regcache_mark_dirty(asrc->regmap);
> -
> - return 0;
> -}
> -
> -static int fsl_asrc_resume(struct device *dev)
> -{
> - struct fsl_asrc *asrc = dev_get_drvdata(dev);
> - struct fsl_asrc_priv *asrc_priv = asrc->private;
> - u32 asrctr;
> -
> - /* Stop all pairs provisionally */
> - regmap_read(asrc->regmap, REG_ASRCTR, &asrctr);
> - regmap_update_bits(asrc->regmap, REG_ASRCTR,
> - ASRCTR_ASRCEi_ALL_MASK, 0);
> -
> - /* Restore all registers */
> - regcache_cache_only(asrc->regmap, false);
> - regcache_sync(asrc->regmap);
> -
> - regmap_update_bits(asrc->regmap, REG_ASRCFG,
> - ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK |
> - ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
> -
> - /* Restart enabled pairs */
> - regmap_update_bits(asrc->regmap, REG_ASRCTR,
> - ASRCTR_ASRCEi_ALL_MASK, asrctr);
> -
> - return 0;
> -}
> -#endif /* CONFIG_PM_SLEEP */
> -
> static const struct dev_pm_ops fsl_asrc_pm = {
> SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL)
> - SET_SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume)
> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> + pm_runtime_force_resume)
> };
>
> static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = {
> --
> 2.21.0
>
^ permalink raw reply
* Re: [PATCH v2] powerpc: Add ppc_inst_next()
From: Jordan Niethe @ 2020-05-25 3:28 UTC (permalink / raw)
To: Michael Ellerman; +Cc: Christophe Leroy, linuxppc-dev
In-Reply-To: <20200522133318.1681406-1-mpe@ellerman.id.au>
On Fri, May 22, 2020 at 11:33 PM Michael Ellerman <mpe@ellerman.id.au> wrote:
>
> In a few places we want to calculate the address of the next
> instruction. Previously that was simple, we just added 4 bytes, or if
> using a u32 * we incremented that pointer by 1.
>
> But prefixed instructions make it more complicated, we need to advance
> by either 4 or 8 bytes depending on the actual instruction. We also
> can't do pointer arithmetic using struct ppc_inst, because it is
> always 8 bytes in size on 64-bit, even though we might only need to
> advance by 4 bytes.
>
> So add a ppc_inst_next() helper which calculates the location of the
> next instruction, if the given instruction was located at the given
> address. Note the instruction doesn't need to actually be at the
> address in memory.
>
> Although it would seem natural for the value to be passed by value,
> that makes it too easy to write a loop that will read off the end of a
> page, eg:
>
> for (; src < end; src = ppc_inst_next(src, *src),
> dest = ppc_inst_next(dest, *dest))
>
> As noticed by Christophe and Jordan, if end is the exact end of a
> page, and the next page is not mapped, this will fault, because *dest
> will read 8 bytes, 4 bytes into the next page.
>
> So value is passed by reference, so the helper can be careful to use
> ppc_inst_read() on it.
>
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
> ---
> arch/powerpc/include/asm/inst.h | 13 +++++++++++++
> arch/powerpc/kernel/uprobes.c | 2 +-
> arch/powerpc/lib/feature-fixups.c | 15 ++++++++-------
> arch/powerpc/xmon/xmon.c | 2 +-
> 4 files changed, 23 insertions(+), 9 deletions(-)
>
> v2: Pass the value as a pointer and use ppc_inst_read() on it.
>
> diff --git a/arch/powerpc/include/asm/inst.h b/arch/powerpc/include/asm/inst.h
> index d82e0c99cfa1..5b756ba77ed2 100644
> --- a/arch/powerpc/include/asm/inst.h
> +++ b/arch/powerpc/include/asm/inst.h
> @@ -100,6 +100,19 @@ static inline int ppc_inst_len(struct ppc_inst x)
> return ppc_inst_prefixed(x) ? 8 : 4;
> }
>
> +/*
> + * Return the address of the next instruction, if the instruction @value was
> + * located at @location.
> + */
> +static inline struct ppc_inst *ppc_inst_next(void *location, struct ppc_inst *value)
> +{
> + struct ppc_inst tmp;
> +
> + tmp = ppc_inst_read(value);
> +
> + return location + ppc_inst_len(tmp);
> +}
> +
> int probe_user_read_inst(struct ppc_inst *inst,
> struct ppc_inst __user *nip);
>
> diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c
> index 83e883e1a42d..d200e7df7167 100644
> --- a/arch/powerpc/kernel/uprobes.c
> +++ b/arch/powerpc/kernel/uprobes.c
> @@ -112,7 +112,7 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
> * support doesn't exist and have to fix-up the next instruction
> * to be executed.
> */
> - regs->nip = utask->vaddr + ppc_inst_len(ppc_inst_read(&auprobe->insn));
> + regs->nip = (unsigned long)ppc_inst_next((void *)utask->vaddr, &auprobe->insn);
>
> user_disable_single_step(current);
> return 0;
> diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
> index 80f320c2e189..4c0a7ee9fa00 100644
> --- a/arch/powerpc/lib/feature-fixups.c
> +++ b/arch/powerpc/lib/feature-fixups.c
> @@ -68,7 +68,7 @@ static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest,
>
> static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
> {
> - struct ppc_inst *start, *end, *alt_start, *alt_end, *src, *dest;
> + struct ppc_inst *start, *end, *alt_start, *alt_end, *src, *dest, nop;
>
> start = calc_addr(fcur, fcur->start_off);
> end = calc_addr(fcur, fcur->end_off);
> @@ -84,14 +84,15 @@ static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
> src = alt_start;
> dest = start;
>
> - for (; src < alt_end; src = (void *)src + ppc_inst_len(ppc_inst_read(src)),
> - (dest = (void *)dest + ppc_inst_len(ppc_inst_read(dest)))) {
> + for (; src < alt_end; src = ppc_inst_next(src, src),
> + dest = ppc_inst_next(dest, dest)) {
> if (patch_alt_instruction(src, dest, alt_start, alt_end))
> return 1;
> }
>
> - for (; dest < end; dest = (void *)dest + ppc_inst_len(ppc_inst(PPC_INST_NOP)))
> - raw_patch_instruction(dest, ppc_inst(PPC_INST_NOP));
> + nop = ppc_inst(PPC_INST_NOP);
> + for (; dest < end; dest = ppc_inst_next(dest, &nop))
> + raw_patch_instruction(dest, nop);
>
> return 0;
> }
> @@ -405,8 +406,8 @@ static void do_final_fixups(void)
> while (src < end) {
> inst = ppc_inst_read(src);
> raw_patch_instruction(dest, inst);
> - src = (void *)src + ppc_inst_len(inst);
> - dest = (void *)dest + ppc_inst_len(inst);
> + src = ppc_inst_next(src, src);
> + dest = ppc_inst_next(dest, dest);
> }
> #endif
> }
> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
> index fb135f2cd6b0..65cf853a4d26 100644
> --- a/arch/powerpc/xmon/xmon.c
> +++ b/arch/powerpc/xmon/xmon.c
> @@ -939,7 +939,7 @@ static void insert_bpts(void)
> }
>
> patch_instruction(bp->instr, instr);
> - patch_instruction((void *)bp->instr + ppc_inst_len(instr),
> + patch_instruction(ppc_inst_next(bp->instr, &instr),
> ppc_inst(bpinstr));
> if (bp->enabled & BP_CIABR)
> continue;
> --
> 2.25.1
>
Reviewed-by: Jordan Niethe <jniethe5@gmail.com>
^ permalink raw reply
* [PATCH 5/5] powerpc sstep: Add tests for Prefixed Add Immediate
From: Jordan Niethe @ 2020-05-25 2:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alistair, Jordan Niethe, bala24
In-Reply-To: <20200525025923.19843-1-jniethe5@gmail.com>
Use the existing support for testing compute type instructions to test
Prefixed Add Immediate (paddi). The R bit of the paddi instruction
controls whether current instruction address is used. Add test cases for
when R=1 and for R=0. paddi has a 34 bit immediate field formed by
concatenating si0 and si1. Add tests for the extreme values of this
field.
Skip the paddi tests if ISA v3.1 is unsupported.
Some of these test cases were added by Balamuruhan S.
Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
---
arch/powerpc/lib/test_emulate_step.c | 127 ++++++++++++++++++
.../lib/test_emulate_step_exec_instr.S | 1 +
2 files changed, 128 insertions(+)
diff --git a/arch/powerpc/lib/test_emulate_step.c b/arch/powerpc/lib/test_emulate_step.c
index 579b5db80674..33a72b7d2764 100644
--- a/arch/powerpc/lib/test_emulate_step.c
+++ b/arch/powerpc/lib/test_emulate_step.c
@@ -105,6 +105,13 @@
___PPC_RA(a) | ___PPC_RB(b))
#define TEST_ADDC_DOT(t, a, b) ppc_inst(PPC_INST_ADDC | ___PPC_RT(t) | \
___PPC_RA(a) | ___PPC_RB(b) | 0x1)
+#define TEST_PADDI(t, a, i, pr) ppc_inst_prefix(PPC_PREFIX_MLS | __PPC_PRFX_R(pr) | \
+ IMM_H(i), \
+ PPC_INST_ADDI | \
+ ___PPC_RT(t) | ___PPC_RA(a) | \
+ IMM_L(i))
+
+
#define MAX_SUBTESTS 16
@@ -699,6 +706,11 @@ struct compute_test {
} subtests[MAX_SUBTESTS + 1];
};
+/* Extreme values for si0||si1 (the MLS:D-form 34 bit immediate field) */
+#define SI_MIN BIT(33)
+#define SI_MAX (BIT(33) - 1)
+#define SI_UMAX (BIT(34) - 1)
+
static struct compute_test compute_tests[] = {
{
.mnemonic = "nop",
@@ -1071,6 +1083,121 @@ static struct compute_test compute_tests[] = {
}
}
}
+ },
+ {
+ .mnemonic = "paddi",
+ .cpu_feature = CPU_FTR_ARCH_31,
+ .subtests = {
+ {
+ .descr = "RA = LONG_MIN, SI = SI_MIN, R = 0",
+ .instr = TEST_PADDI(21, 22, SI_MIN, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = LONG_MIN,
+ }
+ },
+ {
+ .descr = "RA = LONG_MIN, SI = SI_MAX, R = 0",
+ .instr = TEST_PADDI(21, 22, SI_MAX, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = LONG_MIN,
+ }
+ },
+ {
+ .descr = "RA = LONG_MAX, SI = SI_MAX, R = 0",
+ .instr = TEST_PADDI(21, 22, SI_MAX, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = LONG_MAX,
+ }
+ },
+ {
+ .descr = "RA = ULONG_MAX, SI = SI_UMAX, R = 0",
+ .instr = TEST_PADDI(21, 22, SI_UMAX, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = ULONG_MAX,
+ }
+ },
+ {
+ .descr = "RA = ULONG_MAX, SI = 0x1, R = 0",
+ .instr = TEST_PADDI(21, 22, 0x1, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = ULONG_MAX,
+ }
+ },
+ {
+ .descr = "RA = INT_MIN, SI = SI_MIN, R = 0",
+ .instr = TEST_PADDI(21, 22, SI_MIN, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = INT_MIN,
+ }
+ },
+ {
+ .descr = "RA = INT_MIN, SI = SI_MAX, R = 0",
+ .instr = TEST_PADDI(21, 22, SI_MAX, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = INT_MIN,
+ }
+ },
+ {
+ .descr = "RA = INT_MAX, SI = SI_MAX, R = 0",
+ .instr = TEST_PADDI(21, 22, SI_MAX, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = INT_MAX,
+ }
+ },
+ {
+ .descr = "RA = UINT_MAX, SI = 0x1, R = 0",
+ .instr = TEST_PADDI(21, 22, 0x1, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = UINT_MAX,
+ }
+ },
+ {
+ .descr = "RA = UINT_MAX, SI = SI_MAX, R = 0",
+ .instr = TEST_PADDI(21, 22, SI_MAX, 0),
+ .regs = {
+ .gpr[21] = 0,
+ .gpr[22] = UINT_MAX,
+ }
+ },
+ {
+ .descr = "RA is r0, SI = SI_MIN, R = 0",
+ .instr = TEST_PADDI(21, 0, SI_MIN, 0),
+ .regs = {
+ .gpr[21] = 0x0,
+ }
+ },
+ {
+ .descr = "RA = 0, SI = SI_MIN, R = 0",
+ .instr = TEST_PADDI(21, 22, SI_MIN, 0),
+ .regs = {
+ .gpr[21] = 0x0,
+ .gpr[22] = 0x0,
+ }
+ },
+ {
+ .descr = "RA is r0, SI = 0, R = 1",
+ .instr = TEST_PADDI(21, 0, 0, 1),
+ .regs = {
+ .gpr[21] = 0,
+ }
+ },
+ {
+ .descr = "RA is r0, SI = SI_MIN, R = 1",
+ .instr = TEST_PADDI(21, 0, SI_MIN, 1),
+ .regs = {
+ .gpr[21] = 0,
+ }
+ }
+ }
}
};
diff --git a/arch/powerpc/lib/test_emulate_step_exec_instr.S b/arch/powerpc/lib/test_emulate_step_exec_instr.S
index 1580f34f4f4f..aef53ee77a43 100644
--- a/arch/powerpc/lib/test_emulate_step_exec_instr.S
+++ b/arch/powerpc/lib/test_emulate_step_exec_instr.S
@@ -81,6 +81,7 @@ _GLOBAL(exec_instr)
/* Placeholder for the test instruction */
1: nop
+ nop
patch_site 1b patch__exec_instr
/*
--
2.17.1
^ permalink raw reply related
* [PATCH 4/5] powerpc sstep: Let compute tests specify a required cpu feature
From: Jordan Niethe @ 2020-05-25 2:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alistair, Jordan Niethe, bala24
In-Reply-To: <20200525025923.19843-1-jniethe5@gmail.com>
An a array of struct compute_test's are used to declare tests for
compute instructions. Add a cpu_feature field to struct compute_test as
an optional way to specify a cpu feature that must be present. If not
present then skip the test.
Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
---
arch/powerpc/lib/test_emulate_step.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/powerpc/lib/test_emulate_step.c b/arch/powerpc/lib/test_emulate_step.c
index 427c2ca8191e..579b5db80674 100644
--- a/arch/powerpc/lib/test_emulate_step.c
+++ b/arch/powerpc/lib/test_emulate_step.c
@@ -690,6 +690,7 @@ static void __init run_tests_load_store(void)
struct compute_test {
char *mnemonic;
+ unsigned long cpu_feature;
struct {
char *descr;
unsigned long flags;
@@ -1133,6 +1134,11 @@ static void __init run_tests_compute(void)
for (i = 0; i < ARRAY_SIZE(compute_tests); i++) {
test = &compute_tests[i];
+ if (test->cpu_feature && !early_cpu_has_feature(test->cpu_feature)) {
+ show_result(test->mnemonic, "SKIP (!CPU_FTR)");
+ continue;
+ }
+
for (j = 0; j < MAX_SUBTESTS && test->subtests[j].descr; j++) {
instr = test->subtests[j].instr;
flags = test->subtests[j].flags;
--
2.17.1
^ permalink raw reply related
* [PATCH 3/5] powerpc sstep: Set NIP in instruction emulation tests
From: Jordan Niethe @ 2020-05-25 2:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alistair, Jordan Niethe, bala24
In-Reply-To: <20200525025923.19843-1-jniethe5@gmail.com>
The tests for emulation of compute instructions execute and
emulate an instruction and then compare the results to verify the
emulation. In ISA v3.1 there are instructions that operate relative to
the NIP. Therefore set the NIP in the regs used for the emulated
instruction to the location of the executed instruction so they will
give the same result.
This is a rework of a patch by Balamuruhan S.
Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
---
arch/powerpc/lib/test_emulate_step.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/powerpc/lib/test_emulate_step.c b/arch/powerpc/lib/test_emulate_step.c
index 9599f3a03ca1..427c2ca8191e 100644
--- a/arch/powerpc/lib/test_emulate_step.c
+++ b/arch/powerpc/lib/test_emulate_step.c
@@ -1076,11 +1076,14 @@ static struct compute_test compute_tests[] = {
static int __init emulate_compute_instr(struct pt_regs *regs,
struct ppc_inst instr)
{
+ extern s32 patch__exec_instr;
struct instruction_op op;
if (!regs || !ppc_inst_val(instr))
return -EINVAL;
+ regs->nip = patch_site_addr(&patch__exec_instr);
+
if (analyse_instr(&op, regs, instr) != 1 ||
GETTYPE(op.type) != COMPUTE) {
pr_info("emulation failed, instruction = 0x%08x\n", ppc_inst_val(instr));
--
2.17.1
^ permalink raw reply related
* [PATCH 2/5] powerpc sstep: Add tests for prefixed floating-point load/stores
From: Jordan Niethe @ 2020-05-25 2:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alistair, Jordan Niethe, bala24
In-Reply-To: <20200525025923.19843-1-jniethe5@gmail.com>
Add tests for the prefixed versions of the floating-point load/stores
that are currently tested. This includes the following instructions:
* Prefixed Load Floating-Point Single (plfs)
* Prefixed Load Floating-Point Double (plfd)
* Prefixed Store Floating-Point Single (pstfs)
* Prefixed Store Floating-Point Double (pstfd)
Skip the new tests if ISA v3.10 is unsupported.
Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
---
arch/powerpc/include/asm/ppc-opcode.h | 4 +
arch/powerpc/lib/test_emulate_step.c | 136 ++++++++++++++++++++++++++
2 files changed, 140 insertions(+)
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 9e3ecb42597e..6b5edec0e347 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -371,9 +371,13 @@
#define PPC_INST_LBZCIX 0x7c0006aa
#define PPC_INST_STBCIX 0x7c0007aa
#define PPC_INST_LWZX 0x7c00002e
+#define PPC_INST_LFS 0xc0000000
#define PPC_INST_LFSX 0x7c00042e
+#define PPC_INST_STFS 0xd0000000
#define PPC_INST_STFSX 0x7c00052e
+#define PPC_INST_LFD 0xc8000000
#define PPC_INST_LFDX 0x7c0004ae
+#define PPC_INST_STFD 0xd8000000
#define PPC_INST_STFDX 0x7c0005ae
#define PPC_INST_LVX 0x7c0000ce
#define PPC_INST_STVX 0x7c0001ce
diff --git a/arch/powerpc/lib/test_emulate_step.c b/arch/powerpc/lib/test_emulate_step.c
index 8d8953b5fe90..9599f3a03ca1 100644
--- a/arch/powerpc/lib/test_emulate_step.c
+++ b/arch/powerpc/lib/test_emulate_step.c
@@ -57,12 +57,40 @@
___PPC_RA(a) | ___PPC_RB(b))
#define TEST_LFSX(t, a, b) ppc_inst(PPC_INST_LFSX | ___PPC_RT(t) | \
___PPC_RA(a) | ___PPC_RB(b))
+#define TEST_PLFS(r, base, i, pr) ppc_inst_prefix(PPC_PREFIX_MLS | \
+ __PPC_PRFX_R(pr) | \
+ IMM_H(i), \
+ PPC_INST_LFS | \
+ ___PPC_RT(r) | \
+ ___PPC_RA(base) | \
+ IMM_L(i))
#define TEST_STFSX(s, a, b) ppc_inst(PPC_INST_STFSX | ___PPC_RS(s) | \
___PPC_RA(a) | ___PPC_RB(b))
+#define TEST_PSTFS(r, base, i, pr) ppc_inst_prefix(PPC_PREFIX_MLS | \
+ __PPC_PRFX_R(pr) | \
+ IMM_H(i), \
+ PPC_INST_STFS | \
+ ___PPC_RT(r) | \
+ ___PPC_RA(base) | \
+ IMM_L(i))
#define TEST_LFDX(t, a, b) ppc_inst(PPC_INST_LFDX | ___PPC_RT(t) | \
___PPC_RA(a) | ___PPC_RB(b))
+#define TEST_PLFD(r, base, i, pr) ppc_inst_prefix(PPC_PREFIX_MLS | \
+ __PPC_PRFX_R(pr) | \
+ IMM_H(i), \
+ PPC_INST_LFD | \
+ ___PPC_RT(r) | \
+ ___PPC_RA(base) | \
+ IMM_L(i))
#define TEST_STFDX(s, a, b) ppc_inst(PPC_INST_STFDX | ___PPC_RS(s) | \
___PPC_RA(a) | ___PPC_RB(b))
+#define TEST_PSTFD(r, base, i, pr) ppc_inst_prefix(PPC_PREFIX_MLS | \
+ __PPC_PRFX_R(pr) | \
+ IMM_H(i), \
+ PPC_INST_STFD | \
+ ___PPC_RT(r) | \
+ ___PPC_RA(base) | \
+ IMM_L(i))
#define TEST_LVX(t, a, b) ppc_inst(PPC_INST_LVX | ___PPC_RT(t) | \
___PPC_RA(a) | ___PPC_RB(b))
#define TEST_STVX(s, a, b) ppc_inst(PPC_INST_STVX | ___PPC_RS(s) | \
@@ -357,6 +385,53 @@ static void __init test_lfsx_stfsx(void)
show_result("stfsx", "FAIL");
}
+static void __init test_plfs_pstfs(void)
+{
+ struct pt_regs regs;
+ union {
+ float a;
+ int b;
+ } c;
+ int cached_b;
+ int stepped = -1;
+
+ if (!cpu_has_feature(CPU_FTR_ARCH_31)) {
+ show_result("pld", "SKIP (!CPU_FTR_ARCH_31)");
+ return;
+ }
+
+ init_pt_regs(®s);
+
+
+ /*** plfs ***/
+
+ c.a = 123.45;
+ cached_b = c.b;
+
+ regs.gpr[3] = (unsigned long)&c.a;
+
+ /* plfs frt10, 0(r3), 0 */
+ stepped = emulate_step(®s, TEST_PLFS(10, 3, 0, 0));
+
+ if (stepped == 1)
+ show_result("plfs", "PASS");
+ else
+ show_result("plfs", "FAIL");
+
+
+ /*** pstfs ***/
+
+ c.a = 678.91;
+
+ /* pstfs frs10, 0(r3), 0 */
+ stepped = emulate_step(®s, TEST_PSTFS(10, 3, 0, 0));
+
+ if (stepped == 1 && c.b == cached_b)
+ show_result("pstfs", "PASS");
+ else
+ show_result("pstfs", "FAIL");
+}
+
static void __init test_lfdx_stfdx(void)
{
struct pt_regs regs;
@@ -399,6 +474,53 @@ static void __init test_lfdx_stfdx(void)
else
show_result("stfdx", "FAIL");
}
+
+static void __init test_plfd_pstfd(void)
+{
+ struct pt_regs regs;
+ union {
+ double a;
+ long b;
+ } c;
+ long cached_b;
+ int stepped = -1;
+
+ if (!cpu_has_feature(CPU_FTR_ARCH_31)) {
+ show_result("pld", "SKIP (!CPU_FTR_ARCH_31)");
+ return;
+ }
+
+ init_pt_regs(®s);
+
+
+ /*** plfd ***/
+
+ c.a = 123456.78;
+ cached_b = c.b;
+
+ regs.gpr[3] = (unsigned long)&c.a;
+
+ /* plfd frt10, 0(r3), 0 */
+ stepped = emulate_step(®s, TEST_PLFD(10, 3, 0, 0));
+
+ if (stepped == 1)
+ show_result("plfd", "PASS");
+ else
+ show_result("plfd", "FAIL");
+
+
+ /*** pstfd ***/
+
+ c.a = 987654.32;
+
+ /* pstfd frs10, 0(r3), 0 */
+ stepped = emulate_step(®s, TEST_PSTFD(10, 3, 0, 0));
+
+ if (stepped == 1 && c.b == cached_b)
+ show_result("pstfd", "PASS");
+ else
+ show_result("pstfd", "FAIL");
+}
#else
static void __init test_lfsx_stfsx(void)
{
@@ -406,11 +528,23 @@ static void __init test_lfsx_stfsx(void)
show_result("stfsx", "SKIP (CONFIG_PPC_FPU is not set)");
}
+static void __init test_plfs_pstfs(void)
+{
+ show_result("plfs", "SKIP (CONFIG_PPC_FPU is not set)");
+ show_result("pstfs", "SKIP (CONFIG_PPC_FPU is not set)");
+}
+
static void __init test_lfdx_stfdx(void)
{
show_result("lfdx", "SKIP (CONFIG_PPC_FPU is not set)");
show_result("stfdx", "SKIP (CONFIG_PPC_FPU is not set)");
}
+
+static void __init test_plfd_pstfd(void)
+{
+ show_result("plfd", "SKIP (CONFIG_PPC_FPU is not set)");
+ show_result("pstfd", "SKIP (CONFIG_PPC_FPU is not set)");
+}
#endif /* CONFIG_PPC_FPU */
#ifdef CONFIG_ALTIVEC
@@ -547,7 +681,9 @@ static void __init run_tests_load_store(void)
test_pstd();
test_ldarx_stdcx();
test_lfsx_stfsx();
+ test_plfs_pstfs();
test_lfdx_stfdx();
+ test_plfd_pstfd();
test_lvx_stvx();
test_lxvd2x_stxvd2x();
}
--
2.17.1
^ permalink raw reply related
* [PATCH 1/5] powerpc sstep: Add tests for prefixed integer load/stores
From: Jordan Niethe @ 2020-05-25 2:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alistair, Jordan Niethe, bala24
Add tests for the prefixed versions of the integer load/stores that are
currently tested. This includes the following instructions:
* Prefixed Load Doubleword (pld)
* Prefixed Load Word and Zero (plwz)
* Prefixed Store Doubleword (pstd)
Skip the new tests if ISA v3.1 is unsupported.
Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
---
arch/powerpc/include/asm/ppc-opcode.h | 9 +++
arch/powerpc/lib/test_emulate_step.c | 95 +++++++++++++++++++++++++++
2 files changed, 104 insertions(+)
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 2a39c716c343..9e3ecb42597e 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -380,6 +380,14 @@
#define PPC_INST_VCMPEQUD 0x100000c7
#define PPC_INST_VCMPEQUB 0x10000006
+/* Prefixes */
+#define PPC_PREFIX_MLS 0x06000000
+#define PPC_PREFIX_8LS 0x04000000
+
+/* Prefixed instructions */
+#define PPC_INST_PLD 0xe4000000
+#define PPC_INST_PSTD 0xf4000000
+
/* macros to insert fields into opcodes */
#define ___PPC_RA(a) (((a) & 0x1f) << 16)
#define ___PPC_RB(b) (((b) & 0x1f) << 11)
@@ -411,6 +419,7 @@
#define __PPC_CT(t) (((t) & 0x0f) << 21)
#define __PPC_SPR(r) ((((r) & 0x1f) << 16) | ((((r) >> 5) & 0x1f) << 11))
#define __PPC_RC21 (0x1 << 10)
+#define __PPC_PRFX_R(r) (((r) & 0x1) << 20)
/*
* Both low and high 16 bits are added as SIGNED additions, so if low 16 bits
diff --git a/arch/powerpc/lib/test_emulate_step.c b/arch/powerpc/lib/test_emulate_step.c
index 46af80279ebc..8d8953b5fe90 100644
--- a/arch/powerpc/lib/test_emulate_step.c
+++ b/arch/powerpc/lib/test_emulate_step.c
@@ -15,6 +15,7 @@
#define IMM_L(i) ((uintptr_t)(i) & 0xffff)
#define IMM_DS(i) ((uintptr_t)(i) & 0xfffc)
+#define IMM_H(i) (((uintptr_t)(i) >> 16) & 0x3ffff)
/*
* Defined with TEST_ prefix so it does not conflict with other
@@ -22,12 +23,33 @@
*/
#define TEST_LD(r, base, i) ppc_inst(PPC_INST_LD | ___PPC_RT(r) | \
___PPC_RA(base) | IMM_DS(i))
+#define TEST_PLD(r, base, i, pr) ppc_inst_prefix(PPC_PREFIX_8LS | \
+ __PPC_PRFX_R(pr) | \
+ IMM_H(i), \
+ PPC_INST_PLD | \
+ ___PPC_RT(r) | \
+ ___PPC_RA(base) | \
+ IMM_L(i))
#define TEST_LWZ(r, base, i) ppc_inst(PPC_INST_LWZ | ___PPC_RT(r) | \
___PPC_RA(base) | IMM_L(i))
+#define TEST_PLWZ(r, base, i, pr) ppc_inst_prefix(PPC_PREFIX_MLS | \
+ __PPC_PRFX_R(pr) | \
+ IMM_H(i), \
+ PPC_INST_LWZ | \
+ ___PPC_RT(r) | \
+ ___PPC_RA(base) | \
+ IMM_L(i))
#define TEST_LWZX(t, a, b) ppc_inst(PPC_INST_LWZX | ___PPC_RT(t) | \
___PPC_RA(a) | ___PPC_RB(b))
#define TEST_STD(r, base, i) ppc_inst(PPC_INST_STD | ___PPC_RS(r) | \
___PPC_RA(base) | IMM_DS(i))
+#define TEST_PSTD(r, base, i, pr) ppc_inst_prefix(PPC_PREFIX_8LS | \
+ __PPC_PRFX_R(pr) | \
+ IMM_H(i), \
+ PPC_INST_PSTD | \
+ ___PPC_RT(r) | \
+ ___PPC_RA(base) | \
+ IMM_L(i))
#define TEST_LDARX(t, a, b, eh) ppc_inst(PPC_INST_LDARX | ___PPC_RT(t) | \
___PPC_RA(a) | ___PPC_RB(b) | \
__PPC_EH(eh))
@@ -113,6 +135,29 @@ static void __init test_ld(void)
show_result("ld", "FAIL");
}
+static void __init test_pld(void)
+{
+ struct pt_regs regs;
+ unsigned long a = 0x23;
+ int stepped = -1;
+
+ if (!cpu_has_feature(CPU_FTR_ARCH_31)) {
+ show_result("pld", "SKIP (!CPU_FTR_ARCH_31)");
+ return;
+ }
+
+ init_pt_regs(®s);
+ regs.gpr[3] = (unsigned long)&a;
+
+ /* pld r5, 0(r3), 0 */
+ stepped = emulate_step(®s, TEST_PLD(5, 3, 0, 0));
+
+ if (stepped == 1 && regs.gpr[5] == a)
+ show_result("pld", "PASS");
+ else
+ show_result("pld", "FAIL");
+}
+
static void __init test_lwz(void)
{
struct pt_regs regs;
@@ -131,6 +176,30 @@ static void __init test_lwz(void)
show_result("lwz", "FAIL");
}
+static void __init test_plwz(void)
+{
+ struct pt_regs regs;
+ unsigned int a = 0x4545;
+ int stepped = -1;
+
+ if (!cpu_has_feature(CPU_FTR_ARCH_31)) {
+ show_result("plwz", "SKIP (!CPU_FTR_ARCH_31)");
+ return;
+ }
+
+ init_pt_regs(®s);
+ regs.gpr[3] = (unsigned long)&a;
+
+ /* plwz r5, 0(r3), 0 */
+
+ stepped = emulate_step(®s, TEST_PLWZ(5, 3, 0, 0));
+
+ if (stepped == 1 && regs.gpr[5] == a)
+ show_result("plwz", "PASS");
+ else
+ show_result("plwz", "FAIL");
+}
+
static void __init test_lwzx(void)
{
struct pt_regs regs;
@@ -168,6 +237,29 @@ static void __init test_std(void)
show_result("std", "FAIL");
}
+static void __init test_pstd(void)
+{
+ struct pt_regs regs;
+ unsigned long a = 0x1234;
+ int stepped = -1;
+
+ if (!cpu_has_feature(CPU_FTR_ARCH_31)) {
+ show_result("pstd", "SKIP (!CPU_FTR_ARCH_31)");
+ return;
+ }
+
+ init_pt_regs(®s);
+ regs.gpr[3] = (unsigned long)&a;
+ regs.gpr[5] = 0x5678;
+
+ /* pstd r5, 0(r3), 0 */
+ stepped = emulate_step(®s, TEST_PSTD(5, 3, 0, 0));
+ if (stepped == 1 || regs.gpr[5] == a)
+ show_result("pstd", "PASS");
+ else
+ show_result("pstd", "FAIL");
+}
+
static void __init test_ldarx_stdcx(void)
{
struct pt_regs regs;
@@ -447,9 +539,12 @@ static void __init test_lxvd2x_stxvd2x(void)
static void __init run_tests_load_store(void)
{
test_ld();
+ test_pld();
test_lwz();
+ test_plwz();
test_lwzx();
test_std();
+ test_pstd();
test_ldarx_stdcx();
test_lfsx_stfsx();
test_lfdx_stfdx();
--
2.17.1
^ permalink raw reply related
* RE: [PATCH] soc: fsl: qe: Replace one-element array and use struct_size() helper
From: Qiang Zhao @ 2020-05-25 2:47 UTC (permalink / raw)
To: Leo Li, Leo Li, Kees Cook
Cc: Gustavo A. R. Silva, linuxppc-dev, Gustavo A. R. Silva,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE, lkml
In-Reply-To: <CADRPPNTuUUVOHs76JVzELcsyRH_LSi2PGML1t2wob+45LJCXvA@mail.gmail.com>
On Wed, May 23, 2020 at 5:22 PM Li Yang <leoyang.li@nxp.com>
> -----Original Message-----
> From: Li Yang <leoyang.li@nxp.com>
> Sent: 2020年5月23日 5:22
> To: Kees Cook <keescook@chromium.org>
> Cc: Gustavo A. R. Silva <gustavoars@kernel.org>; Qiang Zhao
> <qiang.zhao@nxp.com>; linuxppc-dev <linuxppc-dev@lists.ozlabs.org>;
> moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
> <linux-arm-kernel@lists.infradead.org>; lkml <linux-kernel@vger.kernel.org>;
> Gustavo A. R. Silva <gustavo@embeddedor.com>
> Subject: Re: [PATCH] soc: fsl: qe: Replace one-element array and use
> struct_size() helper
>
> On Wed, May 20, 2020 at 10:24 PM Kees Cook <keescook@chromium.org>
> wrote:
> >
> > On Wed, May 20, 2020 at 06:52:21PM -0500, Li Yang wrote:
> > > On Mon, May 18, 2020 at 5:57 PM Kees Cook <keescook@chromium.org>
> wrote:
> > > > Hm, looking at this code, I see a few other things that need to be
> > > > fixed:
> > > >
> > > > 1) drivers/tty/serial/ucc_uart.c does not do a be32_to_cpu() conversion
> > > > on the length test (understandably, a little-endian system has never
> run
> > > > this code since it's ppc specific), but it's still wrong:
> > > >
> > > > if (firmware->header.length != fw->size) {
> > > >
> > > > compare to the firmware loader:
> > > >
> > > > length = be32_to_cpu(hdr->length);
> > > >
> > > > 2) drivers/soc/fsl/qe/qe.c does not perform bounds checking on the
> > > > per-microcode offsets, so the uploader might send data outside the
> > > > firmware buffer. Perhaps:
> > >
> > > We do validate the CRC for each microcode, it is unlikely the CRC
> > > check can pass if the offset or length is not correct. But you are
> > > probably right that it will be safer to check the boundary and fail
> >
> > Right, but a malicious firmware file could still match CRC but trick
> > the kernel code.
> >
> > > quicker before we actually start the CRC check. Will you come up
> > > with a formal patch or you want us to deal with it?
> >
> > It sounds like Gustavo will be sending one, though I don't think
> > either of us have the hardware to test it with, so if you could do
> > that part, that would be great! :)
>
> That will be great. I think Zhao Qiang can help with the testing part.
>
Now the firmware are loaded in uboot, and kernel will do nothing for it.
So testing on it maybe need some extra codes both in driver and dts.
In the meanwhile, I am so busy on some high priority work that maybe test work
could not be done in time.
Once I am free, I will do it.
Best Regards
Qiang Zhao
^ permalink raw reply
* Re: [PATCH v2] powerpc: Add ppc_inst_next()
From: Michael Ellerman @ 2020-05-25 2:41 UTC (permalink / raw)
To: Nicholas Piggin, linuxppc-dev; +Cc: christophe.leroy, jniethe5
In-Reply-To: <1590278278.q0bfj10pkn.astroid@bobo.none>
Nicholas Piggin <npiggin@gmail.com> writes:
> Excerpts from Nicholas Piggin's message of May 24, 2020 9:56 am:
>> Excerpts from Michael Ellerman's message of May 22, 2020 11:33 pm:
>>> In a few places we want to calculate the address of the next
>>> instruction. Previously that was simple, we just added 4 bytes, or if
>>> using a u32 * we incremented that pointer by 1.
>>>
>>> But prefixed instructions make it more complicated, we need to advance
>>> by either 4 or 8 bytes depending on the actual instruction. We also
>>> can't do pointer arithmetic using struct ppc_inst, because it is
>>> always 8 bytes in size on 64-bit, even though we might only need to
>>> advance by 4 bytes.
>>>
>>> So add a ppc_inst_next() helper which calculates the location of the
>>> next instruction, if the given instruction was located at the given
>>> address. Note the instruction doesn't need to actually be at the
>>> address in memory.
>>>
>>> Although it would seem natural for the value to be passed by value,
>>> that makes it too easy to write a loop that will read off the end of a
>>> page, eg:
>>>
>>> for (; src < end; src = ppc_inst_next(src, *src),
>>> dest = ppc_inst_next(dest, *dest))
>>>
>>> As noticed by Christophe and Jordan, if end is the exact end of a
>>> page, and the next page is not mapped, this will fault, because *dest
>>> will read 8 bytes, 4 bytes into the next page.
>>>
>>> So value is passed by reference, so the helper can be careful to use
>>> ppc_inst_read() on it.
>>>
>>> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
>>> ---
>>> arch/powerpc/include/asm/inst.h | 13 +++++++++++++
>>> arch/powerpc/kernel/uprobes.c | 2 +-
>>> arch/powerpc/lib/feature-fixups.c | 15 ++++++++-------
>>> arch/powerpc/xmon/xmon.c | 2 +-
>>> 4 files changed, 23 insertions(+), 9 deletions(-)
>>>
>>> v2: Pass the value as a pointer and use ppc_inst_read() on it.
>>>
>>> diff --git a/arch/powerpc/include/asm/inst.h b/arch/powerpc/include/asm/inst.h
>>> index d82e0c99cfa1..5b756ba77ed2 100644
>>> --- a/arch/powerpc/include/asm/inst.h
>>> +++ b/arch/powerpc/include/asm/inst.h
>>> @@ -100,6 +100,19 @@ static inline int ppc_inst_len(struct ppc_inst x)
>>> return ppc_inst_prefixed(x) ? 8 : 4;
>>> }
>>>
>>> +/*
>>> + * Return the address of the next instruction, if the instruction @value was
>>> + * located at @location.
>>> + */
>>> +static inline struct ppc_inst *ppc_inst_next(void *location, struct ppc_inst *value)
>>> +{
>>> + struct ppc_inst tmp;
>>> +
>>> + tmp = ppc_inst_read(value);
>>> +
>>> + return location + ppc_inst_len(tmp);
>>> +}
>>> +
>>> int probe_user_read_inst(struct ppc_inst *inst,
>>> struct ppc_inst __user *nip);
>>>
>>> diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c
>>> index 83e883e1a42d..d200e7df7167 100644
>>> --- a/arch/powerpc/kernel/uprobes.c
>>> +++ b/arch/powerpc/kernel/uprobes.c
>>> @@ -112,7 +112,7 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
>>> * support doesn't exist and have to fix-up the next instruction
>>> * to be executed.
>>> */
>>> - regs->nip = utask->vaddr + ppc_inst_len(ppc_inst_read(&auprobe->insn));
>>> + regs->nip = (unsigned long)ppc_inst_next((void *)utask->vaddr, &auprobe->insn);
>>>
>>> user_disable_single_step(current);
>>> return 0;
>>
>> AFAIKS except for here, there is no need for the void *location arg.
>>
>> I would prefer to drop that and keep this unchanged (it's a slightly
>> special case anyway).
>
> Ooops, I didn't read the last thread. I don't think insert_bpts needs it
> though, only this case. Anyway it's a minor nitpick so if it's already
> been considered, fine.
There's a few places that don't need it, eg:
+ nop = ppc_inst(PPC_INST_NOP);
+ for (; dest < end; dest = ppc_inst_next(dest, &nop))
+ raw_patch_instruction(dest, nop);
But I prefer the way that reads, it's clear we're incrementing by the
length of a nop, even though we could read the nop from dest because we
just patched it.
If we ever did execute-only kernel text, it would help to have the
location and value separate too, because then reading from the text
would require a helper, but reading from data/stack would not.
So I'll go with this version.
cheers
^ permalink raw reply
* Re: [linux-next RFC v2] mm/gup.c: Convert to use get_user_{page|pages}_fast_only()
From: John Hubbard @ 2020-05-25 1:06 UTC (permalink / raw)
To: Souptick Joarder, paulus, mpe, benh, akpm, peterz, mingo, acme,
mark.rutland, alexander.shishkin, jolsa, namhyung, pbonzini, sfr,
rppt, aneesh.kumar, msuchanek
Cc: kvm, linux-kernel, Matthew Wilcox, linux-mm, kvm-ppc,
linuxppc-dev
In-Reply-To: <1590294434-19125-1-git-send-email-jrdr.linux@gmail.com>
On 2020-05-23 21:27, Souptick Joarder wrote:
> API __get_user_pages_fast() renamed to get_user_pages_fast_only()
> to align with pin_user_pages_fast_only().
>
> As part of this we will get rid of write parameter. Instead caller
> will pass FOLL_WRITE to get_user_pages_fast_only(). This will not
> change any existing functionality of the API.
>
> All the callers are changed to pass FOLL_WRITE.
This looks good. A few nits below, but with those fixed, feel free to
add:
Reviewed-by: John Hubbard <jhubbard@nvidia.com>
>
> There are few places where 1 is passed to 2nd parameter of
> __get_user_pages_fast() and return value is checked for 1
> like [1]. Those are replaced with new inline
> get_user_page_fast_only().
>
> [1] if (__get_user_pages_fast(hva, 1, 1, &page) == 1)
>
We try to avoid talking *too* much about the previous version of
the code. Just enough. So, instead of the above two paragraphs,
I'd compress it down to:
Also: introduce get_user_page_fast_only(), and use it in a few
places that hard-code nr_pages to 1.
...
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 93d93bd..8d4597f 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1817,10 +1817,16 @@ extern int mprotect_fixup(struct vm_area_struct *vma,
> /*
> * doesn't attempt to fault and will return short.
> */
> -int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> - struct page **pages);
> +int get_user_pages_fast_only(unsigned long start, int nr_pages,
> + unsigned int gup_flags, struct page **pages);
Silly nit:
Can you please leave the original indentation in place? I don't normally
comment about this, but I like the original indentation better, and it matches
the pin_user_pages_fast() below, too.
...
> @@ -2786,8 +2792,8 @@ static int internal_get_user_pages_fast(unsigned long start, int nr_pages,
> * If the architecture does not support this function, simply return with no
> * pages pinned.
> */
> -int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> - struct page **pages)
> +int get_user_pages_fast_only(unsigned long start, int nr_pages,
> + unsigned int gup_flags, struct page **pages)
Same thing here: you've changed the original indentation, which was (arguably, but
to my mind anyway) more readable, and for no reason. It still would have fit within
80 cols.
I'm sure it's a perfect 50/50 mix of people who prefer either indentation style, and
so for brand new code, I'll remain silent, as long as it is consistent with either
itself and/or the surrounding code. But changing it back and forth is a bit
aggravating, and best avoided. :)
thanks,
--
John Hubbard
NVIDIA
^ permalink raw reply
* [Bug 207873] BUG at swapops + rcu stall + soft lockup at running btrfs test suite (TEST=013\* ./misc-tests.sh)
From: bugzilla-daemon @ 2020-05-24 17:04 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <bug-207873-206035@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=207873
Erhard F. (erhard_f@mailbox.org) changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|NEW |RESOLVED
Resolution|--- |PATCH_ALREADY_AVAILABLE
--- Comment #6 from Erhard F. (erhard_f@mailbox.org) ---
(In reply to Christophe Leroy from comment #5)
> Try
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/
> ?id=40bb0e904212cf7d6f041a98c58c8341b2016670
Thanks for the hint! That patch did the trick. The btrfs test suite completes
fine now and building larger projects works unremarkably.
Will close here as the fix seems to be going into -rc7.
--
You are receiving this mail because:
You are watching the assignee of the bug.
^ permalink raw reply
* [PATCH v2 3/4] powerpc: Fix instruction dumping to use address value correctly
From: Aneesh Kumar K.V @ 2020-05-24 9:38 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V
In-Reply-To: <20200524093822.423487-1-aneesh.kumar@linux.ibm.com>
Use ___va() to convert the real address that will skip the input
validation. We can get interrupts with IR=0 and with NIP value > PAGE_OFFSET.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/processor.h | 9 +++++++++
arch/powerpc/kernel/process.c | 7 ++-----
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 4e53df163b92..8bf7921dceca 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -441,6 +441,15 @@ extern void cvt_fd(float *from, double *to);
extern void cvt_df(double *from, float *to);
extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
+static inline unsigned long fixup_real_addr(struct pt_regs *regs,
+ unsigned long addr)
+{
+ if (!(regs->msr & MSR_IR))
+ return (unsigned long)___va(addr);
+
+ return addr;
+}
+
#ifdef CONFIG_PPC64
/*
* We handle most unaligned accesses in hardware. On the other hand
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 93bf4a766707..de07b796222d 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1262,12 +1262,9 @@ static void show_instructions(struct pt_regs *regs)
/* If executing with the IMMU off, adjust pc rather
* than print XXXXXXXX.
*/
- if (!(regs->msr & MSR_IR)) {
- pc = (unsigned long)phys_to_virt(pc);
- nip = (unsigned long)phys_to_virt(regs->nip);
- }
+ pc = fixup_real_addr(regs, pc);
+ nip = fixup_real_addr(regs, nip);
#endif
-
for (i = 0; i < NR_INSN_TO_PRINT; i++) {
int instr;
--
2.26.2
^ permalink raw reply related
* [PATCH v2 4/4] powerpc: Avoid opencoding fixup_real_addr
From: Aneesh Kumar K.V @ 2020-05-24 9:38 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V
In-Reply-To: <20200524093822.423487-1-aneesh.kumar@linux.ibm.com>
Use the newly added helper.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/kernel/traps.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 051d7028e71f..1d58d88a7be1 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1508,12 +1508,10 @@ void program_check_exception(struct pt_regs *regs)
== NOTIFY_STOP)
goto bail;
- bugaddr = regs->nip;
/*
* Fixup bugaddr for BUG_ON() in real mode
*/
- if (!is_kernel_addr(bugaddr) && !(regs->msr & MSR_IR))
- bugaddr += PAGE_OFFSET;
+ bugaddr = fixup_real_addr(regs, regs->nip);
if (!(regs->msr & MSR_PR) && /* not user-mode */
report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) {
--
2.26.2
^ permalink raw reply related
* [PATCH v2 2/4] powerpc/va: Add a __va() variant that doesn't do input validation
From: Aneesh Kumar K.V @ 2020-05-24 9:38 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V
In-Reply-To: <20200524093822.423487-1-aneesh.kumar@linux.ibm.com>
On ppc64, __va(x) do check for input argument to be less than PAGE_OFFSET.
In certain code paths, we want to skip that check. Add a variant ___va(x)
to be used in such cases.
Switch the #define to static inline. __pa() still doesn't benefit from this. But
a static inline done in this patch is better than multi-line #define.
For __va() we get the type checking benefit. We still have to keep the
macro __pa(x) to avoid a large number of compilation errors with the change.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/page.h | 38 ++++++++++++++--------
arch/powerpc/mm/nohash/book3e_pgtable.c | 2 +-
arch/powerpc/platforms/powernv/opal-core.c | 4 +--
3 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index a63fe6f3a0ff..8e8ffde0aef8 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -9,6 +9,7 @@
#ifndef __ASSEMBLY__
#include <linux/types.h>
#include <linux/kernel.h>
+#include <linux/mmdebug.h>
#else
#include <asm/types.h>
#endif
@@ -208,30 +209,41 @@ static inline bool pfn_valid(unsigned long pfn)
* the other definitions for __va & __pa.
*/
#if defined(CONFIG_PPC32) && defined(CONFIG_BOOKE)
-#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + VIRT_PHYS_OFFSET))
+#define ___va(x) ((void *)(unsigned long)((phys_addr_t)(x) + VIRT_PHYS_OFFSET))
#define __pa(x) ((phys_addr_t)(unsigned long)(x) - VIRT_PHYS_OFFSET)
+#define __va(x) ___va(x)
#else
#ifdef CONFIG_PPC64
+
+#ifndef __ASSEMBLY__
/*
* gcc miscompiles (unsigned long)(&static_var) - PAGE_OFFSET
* with -mcmodel=medium, so we use & and | instead of - and + on 64-bit.
* This also results in better code generation.
*/
-#define __va(x) \
-({ \
- VIRTUAL_BUG_ON((unsigned long)(x) >= PAGE_OFFSET); \
- (void *)(unsigned long)((phys_addr_t)(x) | PAGE_OFFSET); \
-})
-
-#define __pa(x) \
-({ \
- VIRTUAL_BUG_ON((unsigned long)(x) < PAGE_OFFSET); \
- (unsigned long)(x) & 0x0fffffffffffffffUL; \
-})
+static inline void *___va(phys_addr_t addr)
+{
+ return (void *)(addr | PAGE_OFFSET);
+}
+
+static inline void *__va(phys_addr_t addr)
+{
+ VIRTUAL_BUG_ON((unsigned long)(addr) >= PAGE_OFFSET);
+ return ___va(addr);
+}
+
+static inline phys_addr_t ___pa(void *addr)
+{
+ VIRTUAL_BUG_ON((unsigned long)(addr) < PAGE_OFFSET);
+ return (phys_addr_t)((unsigned long)addr & 0x0fffffffffffffffUL);
+}
+#define __pa(x) ___pa((void *)(x))
+#endif /* __ASSEMBLY__ */
#else /* 32-bit, non book E */
-#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + PAGE_OFFSET - MEMORY_START))
+#define ___va(x) ((void *)(unsigned long)((phys_addr_t)(x) + PAGE_OFFSET - MEMORY_START))
#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + MEMORY_START)
+#define __va(x) ___va(x)
#endif
#endif
diff --git a/arch/powerpc/mm/nohash/book3e_pgtable.c b/arch/powerpc/mm/nohash/book3e_pgtable.c
index 4637fdd469cf..a8ce309ce740 100644
--- a/arch/powerpc/mm/nohash/book3e_pgtable.c
+++ b/arch/powerpc/mm/nohash/book3e_pgtable.c
@@ -60,7 +60,7 @@ static void __init *early_alloc_pgtable(unsigned long size)
if (!ptr)
panic("%s: Failed to allocate %lu bytes align=0x%lx max_addr=%lx\n",
- __func__, size, size, __pa(MAX_DMA_ADDRESS));
+ __func__, size, size, (unsigned long)__pa(MAX_DMA_ADDRESS));
return ptr;
}
diff --git a/arch/powerpc/platforms/powernv/opal-core.c b/arch/powerpc/platforms/powernv/opal-core.c
index 6dba3b62269f..9a993db88212 100644
--- a/arch/powerpc/platforms/powernv/opal-core.c
+++ b/arch/powerpc/platforms/powernv/opal-core.c
@@ -192,10 +192,10 @@ static ssize_t read_opalcore(struct file *file, struct kobject *kobj,
break;
if (tpos < m->offset + m->size) {
- void *addr;
+ phys_addr_t addr;
tsz = min_t(size_t, m->offset + m->size - tpos, count);
- addr = (void *)(m->paddr + tpos - m->offset);
+ addr = m->paddr + tpos - m->offset;
memcpy(to, __va(addr), tsz);
to += tsz;
tpos += tsz;
--
2.26.2
^ permalink raw reply related
* [PATCH v2 1/4] powerpc/instruction_dump: Fix kernel crash with show_instructions
From: Aneesh Kumar K.V @ 2020-05-24 9:38 UTC (permalink / raw)
To: linuxppc-dev, mpe; +Cc: Aneesh Kumar K.V
With Hard Lockup watchdog, we can hit a BUG() if we take a watchdog
interrupt when in OPAL mode. This happens in show_instructions()
where the kernel takes the watchdog NMI IPI with MSR_IR == 0.
With that show_instructions() updates the variable pc in the loop
and the second iterations will result in BUG().
We hit the BUG_ON due the below check in __va()
#define __va(x) \
({ \
VIRTUAL_BUG_ON((unsigned long)(x) >= PAGE_OFFSET); \
(void *)(unsigned long)((phys_addr_t)(x) | PAGE_OFFSET); \
})
Fixes: 4dd7554a6456 ("powerpc/64: Add VIRTUAL_BUG_ON checks for __va and __pa addresses")
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/kernel/process.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 048d64c4e115..93bf4a766707 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1253,29 +1253,32 @@ struct task_struct *__switch_to(struct task_struct *prev,
static void show_instructions(struct pt_regs *regs)
{
int i;
+ unsigned long nip = regs->nip;
unsigned long pc = regs->nip - (NR_INSN_TO_PRINT * 3 / 4 * sizeof(int));
printk("Instruction dump:");
+#if !defined(CONFIG_BOOKE)
+ /* If executing with the IMMU off, adjust pc rather
+ * than print XXXXXXXX.
+ */
+ if (!(regs->msr & MSR_IR)) {
+ pc = (unsigned long)phys_to_virt(pc);
+ nip = (unsigned long)phys_to_virt(regs->nip);
+ }
+#endif
+
for (i = 0; i < NR_INSN_TO_PRINT; i++) {
int instr;
if (!(i % 8))
pr_cont("\n");
-#if !defined(CONFIG_BOOKE)
- /* If executing with the IMMU off, adjust pc rather
- * than print XXXXXXXX.
- */
- if (!(regs->msr & MSR_IR))
- pc = (unsigned long)phys_to_virt(pc);
-#endif
-
if (!__kernel_text_address(pc) ||
probe_kernel_address((const void *)pc, instr)) {
pr_cont("XXXXXXXX ");
} else {
- if (regs->nip == pc)
+ if (nip == pc)
pr_cont("<%08x> ", instr);
else
pr_cont("%08x ", instr);
--
2.26.2
^ permalink raw reply related
* [PATCH v3 0/3] vmalloc kernel mapping and relocatable kernel
From: Alexandre Ghiti @ 2020-05-24 8:52 UTC (permalink / raw)
To: Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Anup Patel, Atish Patra,
Zong Li, linux-kernel, linuxppc-dev, linux-riscv
Cc: Alexandre Ghiti
This patchset originally implemented relocatable kernel support but now
also moves the kernel mapping into the vmalloc zone.
The first patch explains why we need to move the kernel into vmalloc
zone (instead of memcpying it around). That patch should ease KASLR
implementation a lot.
The second patch allows to build relocatable kernels but is not selected
by default.
The third patch takes advantage of an already existing powerpc script
that checks relocations at compile-time, and uses it for riscv.
Alexandre Ghiti (3):
riscv: Move kernel mapping to vmalloc zone
riscv: Introduce CONFIG_RELOCATABLE
arch, scripts: Add script to check relocations at compile time
arch/powerpc/tools/relocs_check.sh | 18 +----
arch/riscv/Kconfig | 12 +++
arch/riscv/Makefile | 5 +-
arch/riscv/Makefile.postlink | 36 +++++++++
arch/riscv/boot/loader.lds.S | 3 +-
arch/riscv/include/asm/page.h | 10 ++-
arch/riscv/include/asm/pgtable.h | 37 ++++++---
arch/riscv/kernel/head.S | 3 +-
arch/riscv/kernel/module.c | 4 +-
arch/riscv/kernel/vmlinux.lds.S | 9 ++-
arch/riscv/mm/Makefile | 4 +
arch/riscv/mm/init.c | 121 +++++++++++++++++++++++++----
arch/riscv/mm/physaddr.c | 2 +-
arch/riscv/tools/relocs_check.sh | 26 +++++++
scripts/relocs_check.sh | 20 +++++
15 files changed, 258 insertions(+), 52 deletions(-)
create mode 100644 arch/riscv/Makefile.postlink
create mode 100755 arch/riscv/tools/relocs_check.sh
create mode 100755 scripts/relocs_check.sh
--
2.20.1
^ permalink raw reply
* [PATCH v3 3/3] arch, scripts: Add script to check relocations at compile time
From: Alexandre Ghiti @ 2020-05-24 8:52 UTC (permalink / raw)
To: Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Anup Patel, Atish Patra,
Zong Li, linux-kernel, linuxppc-dev, linux-riscv
Cc: Alexandre Ghiti
In-Reply-To: <20200524085259.24784-1-alex@ghiti.fr>
Relocating kernel at runtime is done very early in the boot process, so
it is not convenient to check for relocations there and react in case a
relocation was not expected.
Powerpc architecture has a script that allows to check at compile time
for such unexpected relocations: extract the common logic to scripts/
and add arch specific scripts triggered at postlink.
At the moment, powerpc and riscv architectures take advantage of this
compile-time check.
Signed-off-by: Alexandre Ghiti <alex@ghiti.fr>
---
arch/powerpc/tools/relocs_check.sh | 18 ++-------------
arch/riscv/Makefile.postlink | 36 ++++++++++++++++++++++++++++++
arch/riscv/tools/relocs_check.sh | 26 +++++++++++++++++++++
scripts/relocs_check.sh | 20 +++++++++++++++++
4 files changed, 84 insertions(+), 16 deletions(-)
create mode 100644 arch/riscv/Makefile.postlink
create mode 100755 arch/riscv/tools/relocs_check.sh
create mode 100755 scripts/relocs_check.sh
diff --git a/arch/powerpc/tools/relocs_check.sh b/arch/powerpc/tools/relocs_check.sh
index 014e00e74d2b..e367895941ae 100755
--- a/arch/powerpc/tools/relocs_check.sh
+++ b/arch/powerpc/tools/relocs_check.sh
@@ -15,21 +15,8 @@ if [ $# -lt 3 ]; then
exit 1
fi
-# Have Kbuild supply the path to objdump and nm so we handle cross compilation.
-objdump="$1"
-nm="$2"
-vmlinux="$3"
-
-# Remove from the bad relocations those that match an undefined weak symbol
-# which will result in an absolute relocation to 0.
-# Weak unresolved symbols are of that form in nm output:
-# " w _binary__btf_vmlinux_bin_end"
-undef_weak_symbols=$($nm "$vmlinux" | awk '$1 ~ /w/ { print $2 }')
-
bad_relocs=$(
-$objdump -R "$vmlinux" |
- # Only look at relocation lines.
- grep -E '\<R_' |
+${srctree}/scripts/relocs_check.sh "$@" |
# These relocations are okay
# On PPC64:
# R_PPC64_RELATIVE, R_PPC64_NONE
@@ -43,8 +30,7 @@ R_PPC_ADDR16_LO
R_PPC_ADDR16_HI
R_PPC_ADDR16_HA
R_PPC_RELATIVE
-R_PPC_NONE' |
- ([ "$undef_weak_symbols" ] && grep -F -w -v "$undef_weak_symbols" || cat)
+R_PPC_NONE'
)
if [ -z "$bad_relocs" ]; then
diff --git a/arch/riscv/Makefile.postlink b/arch/riscv/Makefile.postlink
new file mode 100644
index 000000000000..bf2b2bca1845
--- /dev/null
+++ b/arch/riscv/Makefile.postlink
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: GPL-2.0
+# ===========================================================================
+# Post-link riscv pass
+# ===========================================================================
+#
+# Check that vmlinux relocations look sane
+
+PHONY := __archpost
+__archpost:
+
+-include include/config/auto.conf
+include scripts/Kbuild.include
+
+quiet_cmd_relocs_check = CHKREL $@
+cmd_relocs_check = \
+ $(CONFIG_SHELL) $(srctree)/arch/riscv/tools/relocs_check.sh "$(OBJDUMP)" "$(NM)" "$@"
+
+# `@true` prevents complaint when there is nothing to be done
+
+vmlinux: FORCE
+ @true
+ifdef CONFIG_RELOCATABLE
+ $(call if_changed,relocs_check)
+endif
+
+%.ko: FORCE
+ @true
+
+clean:
+ @true
+
+PHONY += FORCE clean
+
+FORCE:
+
+.PHONY: $(PHONY)
diff --git a/arch/riscv/tools/relocs_check.sh b/arch/riscv/tools/relocs_check.sh
new file mode 100755
index 000000000000..baeb2e7b2290
--- /dev/null
+++ b/arch/riscv/tools/relocs_check.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Based on powerpc relocs_check.sh
+
+# This script checks the relocations of a vmlinux for "suspicious"
+# relocations.
+
+if [ $# -lt 3 ]; then
+ echo "$0 [path to objdump] [path to nm] [path to vmlinux]" 1>&2
+ exit 1
+fi
+
+bad_relocs=$(
+${srctree}/scripts/relocs_check.sh "$@" |
+ # These relocations are okay
+ # R_RISCV_RELATIVE
+ grep -F -w -v 'R_RISCV_RELATIVE'
+)
+
+if [ -z "$bad_relocs" ]; then
+ exit 0
+fi
+
+num_bad=$(echo "$bad_relocs" | wc -l)
+echo "WARNING: $num_bad bad relocations"
+echo "$bad_relocs"
diff --git a/scripts/relocs_check.sh b/scripts/relocs_check.sh
new file mode 100755
index 000000000000..137c660499f3
--- /dev/null
+++ b/scripts/relocs_check.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Get a list of all the relocations, remove from it the relocations
+# that are known to be legitimate and return this list to arch specific
+# script that will look for suspicious relocations.
+
+objdump="$1"
+nm="$2"
+vmlinux="$3"
+
+# Remove from the possible bad relocations those that match an undefined
+# weak symbol which will result in an absolute relocation to 0.
+# Weak unresolved symbols are of that form in nm output:
+# " w _binary__btf_vmlinux_bin_end"
+undef_weak_symbols=$($nm "$vmlinux" | awk '$1 ~ /w/ { print $2 }')
+
+$objdump -R "$vmlinux" |
+ grep -E '\<R_' |
+ ([ "$undef_weak_symbols" ] && grep -F -w -v "$undef_weak_symbols" || cat)
--
2.20.1
^ permalink raw reply related
* [PATCH v3 2/3] riscv: Introduce CONFIG_RELOCATABLE
From: Alexandre Ghiti @ 2020-05-24 8:52 UTC (permalink / raw)
To: Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Anup Patel, Atish Patra,
Zong Li, linux-kernel, linuxppc-dev, linux-riscv
Cc: Alexandre Ghiti
In-Reply-To: <20200524085259.24784-1-alex@ghiti.fr>
This config allows to compile the kernel as PIE and to relocate it at
any virtual address at runtime: this paves the way to KASLR and to 4-level
page table folding at runtime. Runtime relocation is possible since
relocation metadata are embedded into the kernel.
Note that relocating at runtime introduces an overhead even if the
kernel is loaded at the same address it was linked at and that the compiler
options are those used in arm64 which uses the same RELA relocation
format.
Signed-off-by: Alexandre Ghiti <alex@ghiti.fr>
---
arch/riscv/Kconfig | 12 +++++++
arch/riscv/Makefile | 5 ++-
arch/riscv/kernel/vmlinux.lds.S | 6 ++--
arch/riscv/mm/Makefile | 4 +++
arch/riscv/mm/init.c | 63 +++++++++++++++++++++++++++++++++
5 files changed, 87 insertions(+), 3 deletions(-)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index a31e1a41913a..93127d5913fe 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -170,6 +170,18 @@ config PGTABLE_LEVELS
default 3 if 64BIT
default 2
+config RELOCATABLE
+ bool
+ depends on MMU
+ help
+ This builds a kernel as a Position Independent Executable (PIE),
+ which retains all relocation metadata required to relocate the
+ kernel binary at runtime to a different virtual address than the
+ address it was linked at.
+ Since RISCV uses the RELA relocation format, this requires a
+ relocation pass at runtime even if the kernel is loaded at the
+ same address it was linked at.
+
source "arch/riscv/Kconfig.socs"
menu "Platform type"
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index fb6e37db836d..1406416ea743 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -9,7 +9,10 @@
#
OBJCOPYFLAGS := -O binary
-LDFLAGS_vmlinux :=
+ifeq ($(CONFIG_RELOCATABLE),y)
+LDFLAGS_vmlinux := -shared -Bsymbolic -z notext -z norelro
+KBUILD_CFLAGS += -fPIE
+endif
ifeq ($(CONFIG_DYNAMIC_FTRACE),y)
LDFLAGS_vmlinux := --no-relax
endif
diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
index a9abde62909f..e8ffba8c2044 100644
--- a/arch/riscv/kernel/vmlinux.lds.S
+++ b/arch/riscv/kernel/vmlinux.lds.S
@@ -85,8 +85,10 @@ SECTIONS
BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0)
- .rel.dyn : {
- *(.rel.dyn*)
+ .rela.dyn : ALIGN(8) {
+ __rela_dyn_start = .;
+ *(.rela .rela*)
+ __rela_dyn_end = .;
}
_end = .;
diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile
index 363ef01c30b1..dc5cdaa80bc1 100644
--- a/arch/riscv/mm/Makefile
+++ b/arch/riscv/mm/Makefile
@@ -1,6 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
CFLAGS_init.o := -mcmodel=medany
+ifdef CONFIG_RELOCATABLE
+CFLAGS_init.o += -fno-pie
+endif
+
ifdef CONFIG_FTRACE
CFLAGS_REMOVE_init.o = -pg
endif
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 17f108baec4f..7074522d40c6 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -13,6 +13,9 @@
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <linux/set_memory.h>
+#ifdef CONFIG_RELOCATABLE
+#include <linux/elf.h>
+#endif
#include <asm/fixmap.h>
#include <asm/tlbflush.h>
@@ -379,6 +382,53 @@ static uintptr_t __init best_map_size(phys_addr_t base, phys_addr_t size)
#error "setup_vm() is called from head.S before relocate so it should not use absolute addressing."
#endif
+#ifdef CONFIG_RELOCATABLE
+extern unsigned long __rela_dyn_start, __rela_dyn_end;
+
+#ifdef CONFIG_64BIT
+#define Elf_Rela Elf64_Rela
+#define Elf_Addr Elf64_Addr
+#else
+#define Elf_Rela Elf32_Rela
+#define Elf_Addr Elf32_Addr
+#endif
+
+void __init relocate_kernel(uintptr_t load_pa)
+{
+ Elf_Rela *rela = (Elf_Rela *)&__rela_dyn_start;
+ /*
+ * This holds the offset between the linked virtual address and the
+ * relocated virtual address.
+ */
+ uintptr_t reloc_offset = kernel_virt_addr - KERNEL_LINK_ADDR;
+ /*
+ * This holds the offset between kernel linked virtual address and
+ * physical address.
+ */
+ uintptr_t va_kernel_link_pa_offset = KERNEL_LINK_ADDR - load_pa;
+
+ for ( ; rela < (Elf_Rela *)&__rela_dyn_end; rela++) {
+ Elf_Addr addr = (rela->r_offset - va_kernel_link_pa_offset);
+ Elf_Addr relocated_addr = rela->r_addend;
+
+ if (rela->r_info != R_RISCV_RELATIVE)
+ continue;
+
+ /*
+ * Make sure to not relocate vdso symbols like rt_sigreturn
+ * which are linked from the address 0 in vmlinux since
+ * vdso symbol addresses are actually used as an offset from
+ * mm->context.vdso in VDSO_OFFSET macro.
+ */
+ if (relocated_addr >= KERNEL_LINK_ADDR)
+ relocated_addr += reloc_offset;
+
+ *(Elf_Addr *)addr = relocated_addr;
+ }
+}
+
+#endif
+
static uintptr_t load_pa, load_sz;
void create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size)
@@ -405,6 +455,19 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
pfn_base = PFN_DOWN(load_pa);
+#ifdef CONFIG_RELOCATABLE
+#ifdef CONFIG_64BIT
+ /*
+ * Early page table uses only one PGDIR, which makes it possible
+ * to map PGDIR_SIZE aligned on PGDIR_SIZE: if the relocation offset
+ * makes the kernel cross over a PGDIR_SIZE boundary, raise a bug
+ * since a part of the kernel would not get mapped.
+ * This cannot happen on rv32 as we use the entire page directory level.
+ */
+ BUG_ON(PGDIR_SIZE - (kernel_virt_addr & (PGDIR_SIZE - 1)) < load_sz);
+#endif
+ relocate_kernel(load_pa);
+#endif
/*
* Enforce boot alignment requirements of RV32 and
* RV64 by only allowing PMD or PGD mappings.
--
2.20.1
^ permalink raw reply related
* [PATCH v3 1/3] riscv: Move kernel mapping to vmalloc zone
From: Alexandre Ghiti @ 2020-05-24 8:52 UTC (permalink / raw)
To: Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Anup Patel, Atish Patra,
Zong Li, linux-kernel, linuxppc-dev, linux-riscv
Cc: Alexandre Ghiti
In-Reply-To: <20200524085259.24784-1-alex@ghiti.fr>
This is a preparatory patch for relocatable kernel.
The kernel used to be linked at PAGE_OFFSET address and used to be loaded
physically at the beginning of the main memory. Therefore, we could use
the linear mapping for the kernel mapping.
But the relocated kernel base address will be different from PAGE_OFFSET
and since in the linear mapping, two different virtual addresses cannot
point to the same physical address, the kernel mapping needs to lie outside
the linear mapping.
In addition, because modules and BPF must be close to the kernel (inside
+-2GB window), the kernel is placed at the end of the vmalloc zone minus
2GB, which leaves room for modules and BPF. The kernel could not be
placed at the beginning of the vmalloc zone since other vmalloc
allocations from the kernel could get all the +-2GB window around the
kernel which would prevent new modules and BPF programs to be loaded.
Signed-off-by: Alexandre Ghiti <alex@ghiti.fr>
---
arch/riscv/boot/loader.lds.S | 3 +-
arch/riscv/include/asm/page.h | 10 +++++-
arch/riscv/include/asm/pgtable.h | 37 +++++++++++++-------
arch/riscv/kernel/head.S | 3 +-
arch/riscv/kernel/module.c | 4 +--
arch/riscv/kernel/vmlinux.lds.S | 3 +-
arch/riscv/mm/init.c | 58 +++++++++++++++++++++++++-------
arch/riscv/mm/physaddr.c | 2 +-
8 files changed, 87 insertions(+), 33 deletions(-)
diff --git a/arch/riscv/boot/loader.lds.S b/arch/riscv/boot/loader.lds.S
index 47a5003c2e28..62d94696a19c 100644
--- a/arch/riscv/boot/loader.lds.S
+++ b/arch/riscv/boot/loader.lds.S
@@ -1,13 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <asm/page.h>
+#include <asm/pgtable.h>
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS
{
- . = PAGE_OFFSET;
+ . = KERNEL_LINK_ADDR;
.payload : {
*(.payload)
diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h
index 2d50f76efe48..48bb09b6a9b7 100644
--- a/arch/riscv/include/asm/page.h
+++ b/arch/riscv/include/asm/page.h
@@ -90,18 +90,26 @@ typedef struct page *pgtable_t;
#ifdef CONFIG_MMU
extern unsigned long va_pa_offset;
+extern unsigned long va_kernel_pa_offset;
extern unsigned long pfn_base;
#define ARCH_PFN_OFFSET (pfn_base)
#else
#define va_pa_offset 0
+#define va_kernel_pa_offset 0
#define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT)
#endif /* CONFIG_MMU */
extern unsigned long max_low_pfn;
extern unsigned long min_low_pfn;
+extern unsigned long kernel_virt_addr;
#define __pa_to_va_nodebug(x) ((void *)((unsigned long) (x) + va_pa_offset))
-#define __va_to_pa_nodebug(x) ((unsigned long)(x) - va_pa_offset)
+#define linear_mapping_va_to_pa(x) ((unsigned long)(x) - va_pa_offset)
+#define kernel_mapping_va_to_pa(x) \
+ ((unsigned long)(x) - va_kernel_pa_offset)
+#define __va_to_pa_nodebug(x) \
+ (((x) >= PAGE_OFFSET) ? \
+ linear_mapping_va_to_pa(x) : kernel_mapping_va_to_pa(x))
#ifdef CONFIG_DEBUG_VIRTUAL
extern phys_addr_t __virt_to_phys(unsigned long x);
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 35b60035b6b0..25213cfaf680 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -11,23 +11,29 @@
#include <asm/pgtable-bits.h>
-#ifndef __ASSEMBLY__
-
-/* Page Upper Directory not used in RISC-V */
-#include <asm-generic/pgtable-nopud.h>
-#include <asm/page.h>
-#include <asm/tlbflush.h>
-#include <linux/mm_types.h>
-
-#ifdef CONFIG_MMU
+#ifndef CONFIG_MMU
+#define KERNEL_VIRT_ADDR PAGE_OFFSET
+#define KERNEL_LINK_ADDR PAGE_OFFSET
+#else
+/*
+ * Leave 2GB for modules and BPF that must lie within a 2GB range around
+ * the kernel.
+ */
+#define KERNEL_VIRT_ADDR (VMALLOC_END - SZ_2G + 1)
+#define KERNEL_LINK_ADDR KERNEL_VIRT_ADDR
#define VMALLOC_SIZE (KERN_VIRT_SIZE >> 1)
#define VMALLOC_END (PAGE_OFFSET - 1)
#define VMALLOC_START (PAGE_OFFSET - VMALLOC_SIZE)
#define BPF_JIT_REGION_SIZE (SZ_128M)
-#define BPF_JIT_REGION_START (PAGE_OFFSET - BPF_JIT_REGION_SIZE)
-#define BPF_JIT_REGION_END (VMALLOC_END)
+#define BPF_JIT_REGION_START (kernel_virt_addr)
+#define BPF_JIT_REGION_END (kernel_virt_addr + BPF_JIT_REGION_SIZE)
+
+#ifdef CONFIG_64BIT
+#define VMALLOC_MODULE_START BPF_JIT_REGION_END
+#define VMALLOC_MODULE_END VMALLOC_END
+#endif
/*
* Roughly size the vmemmap space to be large enough to fit enough
@@ -57,9 +63,16 @@
#define FIXADDR_SIZE PGDIR_SIZE
#endif
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
-
#endif
+#ifndef __ASSEMBLY__
+
+/* Page Upper Directory not used in RISC-V */
+#include <asm-generic/pgtable-nopud.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+#include <linux/mm_types.h>
+
#ifdef CONFIG_64BIT
#include <asm/pgtable-64.h>
#else
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index 98a406474e7d..8f5bb7731327 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -49,7 +49,8 @@ ENTRY(_start)
#ifdef CONFIG_MMU
relocate:
/* Relocate return address */
- li a1, PAGE_OFFSET
+ la a1, kernel_virt_addr
+ REG_L a1, 0(a1)
la a2, _start
sub a1, a1, a2
add ra, ra, a1
diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c
index 8bbe5dbe1341..1a8fbe05accf 100644
--- a/arch/riscv/kernel/module.c
+++ b/arch/riscv/kernel/module.c
@@ -392,12 +392,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
}
#if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
-#define VMALLOC_MODULE_START \
- max(PFN_ALIGN((unsigned long)&_end - SZ_2G), VMALLOC_START)
void *module_alloc(unsigned long size)
{
return __vmalloc_node_range(size, 1, VMALLOC_MODULE_START,
- VMALLOC_END, GFP_KERNEL,
+ VMALLOC_MODULE_END, GFP_KERNEL,
PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
__builtin_return_address(0));
}
diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
index 0339b6bbe11a..a9abde62909f 100644
--- a/arch/riscv/kernel/vmlinux.lds.S
+++ b/arch/riscv/kernel/vmlinux.lds.S
@@ -4,7 +4,8 @@
* Copyright (C) 2017 SiFive
*/
-#define LOAD_OFFSET PAGE_OFFSET
+#include <asm/pgtable.h>
+#define LOAD_OFFSET KERNEL_LINK_ADDR
#include <asm/vmlinux.lds.h>
#include <asm/page.h>
#include <asm/cache.h>
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 27a334106708..17f108baec4f 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -22,6 +22,9 @@
#include "../kernel/head.h"
+unsigned long kernel_virt_addr = KERNEL_VIRT_ADDR;
+EXPORT_SYMBOL(kernel_virt_addr);
+
unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]
__page_aligned_bss;
EXPORT_SYMBOL(empty_zero_page);
@@ -178,8 +181,12 @@ void __init setup_bootmem(void)
}
#ifdef CONFIG_MMU
+/* Offset between linear mapping virtual address and kernel load address */
unsigned long va_pa_offset;
EXPORT_SYMBOL(va_pa_offset);
+/* Offset between kernel mapping virtual address and kernel load address */
+unsigned long va_kernel_pa_offset;
+EXPORT_SYMBOL(va_kernel_pa_offset);
unsigned long pfn_base;
EXPORT_SYMBOL(pfn_base);
@@ -271,7 +278,7 @@ static phys_addr_t __init alloc_pmd(uintptr_t va)
if (mmu_enabled)
return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
- pmd_num = (va - PAGE_OFFSET) >> PGDIR_SHIFT;
+ pmd_num = (va - kernel_virt_addr) >> PGDIR_SHIFT;
BUG_ON(pmd_num >= NUM_EARLY_PMDS);
return (uintptr_t)&early_pmd[pmd_num * PTRS_PER_PMD];
}
@@ -372,14 +379,30 @@ static uintptr_t __init best_map_size(phys_addr_t base, phys_addr_t size)
#error "setup_vm() is called from head.S before relocate so it should not use absolute addressing."
#endif
+static uintptr_t load_pa, load_sz;
+
+void create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size)
+{
+ uintptr_t va, end_va;
+
+ end_va = kernel_virt_addr + load_sz;
+ for (va = kernel_virt_addr; va < end_va; va += map_size)
+ create_pgd_mapping(pgdir, va,
+ load_pa + (va - kernel_virt_addr),
+ map_size, PAGE_KERNEL_EXEC);
+}
+
asmlinkage void __init setup_vm(uintptr_t dtb_pa)
{
uintptr_t va, end_va;
- uintptr_t load_pa = (uintptr_t)(&_start);
- uintptr_t load_sz = (uintptr_t)(&_end) - load_pa;
uintptr_t map_size = best_map_size(load_pa, MAX_EARLY_MAPPING_SIZE);
+ load_pa = (uintptr_t)(&_start);
+ load_sz = (uintptr_t)(&_end) - load_pa;
+
va_pa_offset = PAGE_OFFSET - load_pa;
+ va_kernel_pa_offset = kernel_virt_addr - load_pa;
+
pfn_base = PFN_DOWN(load_pa);
/*
@@ -402,26 +425,22 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
create_pmd_mapping(fixmap_pmd, FIXADDR_START,
(uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE);
/* Setup trampoline PGD and PMD */
- create_pgd_mapping(trampoline_pg_dir, PAGE_OFFSET,
+ create_pgd_mapping(trampoline_pg_dir, kernel_virt_addr,
(uintptr_t)trampoline_pmd, PGDIR_SIZE, PAGE_TABLE);
- create_pmd_mapping(trampoline_pmd, PAGE_OFFSET,
+ create_pmd_mapping(trampoline_pmd, kernel_virt_addr,
load_pa, PMD_SIZE, PAGE_KERNEL_EXEC);
#else
/* Setup trampoline PGD */
- create_pgd_mapping(trampoline_pg_dir, PAGE_OFFSET,
+ create_pgd_mapping(trampoline_pg_dir, kernel_virt_addr,
load_pa, PGDIR_SIZE, PAGE_KERNEL_EXEC);
#endif
/*
- * Setup early PGD covering entire kernel which will allows
+ * Setup early PGD covering entire kernel which will allow
* us to reach paging_init(). We map all memory banks later
* in setup_vm_final() below.
*/
- end_va = PAGE_OFFSET + load_sz;
- for (va = PAGE_OFFSET; va < end_va; va += map_size)
- create_pgd_mapping(early_pg_dir, va,
- load_pa + (va - PAGE_OFFSET),
- map_size, PAGE_KERNEL_EXEC);
+ create_kernel_page_table(early_pg_dir, map_size);
/* Create fixed mapping for early FDT parsing */
end_va = __fix_to_virt(FIX_FDT) + FIX_FDT_SIZE;
@@ -441,6 +460,7 @@ static void __init setup_vm_final(void)
uintptr_t va, map_size;
phys_addr_t pa, start, end;
struct memblock_region *reg;
+ static struct vm_struct vm_kernel = { 0 };
/* Set mmu_enabled flag */
mmu_enabled = true;
@@ -467,10 +487,22 @@ static void __init setup_vm_final(void)
for (pa = start; pa < end; pa += map_size) {
va = (uintptr_t)__va(pa);
create_pgd_mapping(swapper_pg_dir, va, pa,
- map_size, PAGE_KERNEL_EXEC);
+ map_size, PAGE_KERNEL);
}
}
+ /* Map the kernel */
+ create_kernel_page_table(swapper_pg_dir, PMD_SIZE);
+
+ /* Reserve the vmalloc area occupied by the kernel */
+ vm_kernel.addr = (void *)kernel_virt_addr;
+ vm_kernel.phys_addr = load_pa;
+ vm_kernel.size = (load_sz + PMD_SIZE) & ~(PMD_SIZE - 1);
+ vm_kernel.flags = VM_MAP | VM_NO_GUARD;
+ vm_kernel.caller = __builtin_return_address(0);
+
+ vm_area_add_early(&vm_kernel);
+
/* Clear fixmap PTE and PMD mappings */
clear_fixmap(FIX_PTE);
clear_fixmap(FIX_PMD);
diff --git a/arch/riscv/mm/physaddr.c b/arch/riscv/mm/physaddr.c
index e8e4dcd39fed..35703d5ef5fd 100644
--- a/arch/riscv/mm/physaddr.c
+++ b/arch/riscv/mm/physaddr.c
@@ -23,7 +23,7 @@ EXPORT_SYMBOL(__virt_to_phys);
phys_addr_t __phys_addr_symbol(unsigned long x)
{
- unsigned long kernel_start = (unsigned long)PAGE_OFFSET;
+ unsigned long kernel_start = (unsigned long)kernel_virt_addr;
unsigned long kernel_end = (unsigned long)_end;
/*
--
2.20.1
^ permalink raw reply related
* [Bug 207873] BUG at swapops + rcu stall + soft lockup at running btrfs test suite (TEST=013\* ./misc-tests.sh)
From: bugzilla-daemon @ 2020-05-24 6:57 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <bug-207873-206035@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=207873
Christophe Leroy (christophe.leroy@c-s.fr) changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |christophe.leroy@c-s.fr
--- Comment #5 from Christophe Leroy (christophe.leroy@c-s.fr) ---
Try
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=40bb0e904212cf7d6f041a98c58c8341b2016670
--
You are receiving this mail because:
You are watching the assignee of the bug.
^ permalink raw reply
* [linux-next RFC v2] mm/gup.c: Convert to use get_user_{page|pages}_fast_only()
From: Souptick Joarder @ 2020-05-24 4:27 UTC (permalink / raw)
To: paulus, mpe, benh, akpm, peterz, mingo, acme, mark.rutland,
alexander.shishkin, jolsa, namhyung, pbonzini, sfr, rppt,
aneesh.kumar, msuchanek
Cc: Matthew Wilcox, kvm, John Hubbard, linux-kernel, kvm-ppc,
linux-mm, Souptick Joarder, linuxppc-dev
API __get_user_pages_fast() renamed to get_user_pages_fast_only()
to align with pin_user_pages_fast_only().
As part of this we will get rid of write parameter. Instead caller
will pass FOLL_WRITE to get_user_pages_fast_only(). This will not
change any existing functionality of the API.
All the callers are changed to pass FOLL_WRITE.
There are few places where 1 is passed to 2nd parameter of
__get_user_pages_fast() and return value is checked for 1
like [1]. Those are replaced with new inline
get_user_page_fast_only().
[1] if (__get_user_pages_fast(hva, 1, 1, &page) == 1)
Updated the documentation of the API.
Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Matthew Wilcox <willy@infradead.org>
---
v2:
Updated the subject line and change log.
Address Matthew's comment to fix a bug and added
new inline get_user_page_fast_only().
arch/powerpc/kvm/book3s_64_mmu_hv.c | 2 +-
arch/powerpc/kvm/book3s_64_mmu_radix.c | 2 +-
arch/powerpc/perf/callchain_64.c | 4 +---
include/linux/mm.h | 10 ++++++++--
kernel/events/core.c | 4 ++--
mm/gup.c | 29 ++++++++++++++++-------------
virt/kvm/kvm_main.c | 8 +++-----
7 files changed, 32 insertions(+), 27 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 18aed97..ddfc4c9 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -581,7 +581,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
* We always ask for write permission since the common case
* is that the page is writable.
*/
- if (__get_user_pages_fast(hva, 1, 1, &page) == 1) {
+ if (get_user_page_fast_only(hva, FOLL_WRITE, &page)) {
write_ok = true;
} else {
/* Call KVM generic code to do the slow-path check */
diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c
index 3248f78..5d4c087 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c
@@ -795,7 +795,7 @@ int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu,
* is that the page is writable.
*/
hva = gfn_to_hva_memslot(memslot, gfn);
- if (!kvm_ro && __get_user_pages_fast(hva, 1, 1, &page) == 1) {
+ if (!kvm_ro && get_user_page_fast_only(hva, FOLL_WRITE, &page)) {
upgrade_write = true;
} else {
unsigned long pfn;
diff --git a/arch/powerpc/perf/callchain_64.c b/arch/powerpc/perf/callchain_64.c
index 1bff896d..814d1c2 100644
--- a/arch/powerpc/perf/callchain_64.c
+++ b/arch/powerpc/perf/callchain_64.c
@@ -29,11 +29,9 @@ int read_user_stack_slow(void __user *ptr, void *buf, int nb)
unsigned long addr = (unsigned long) ptr;
unsigned long offset;
struct page *page;
- int nrpages;
void *kaddr;
- nrpages = __get_user_pages_fast(addr, 1, 1, &page);
- if (nrpages == 1) {
+ if (get_user_page_fast_only(addr, FOLL_WRITE, &page)) {
kaddr = page_address(page);
/* align address to page boundary */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 93d93bd..8d4597f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1817,10 +1817,16 @@ extern int mprotect_fixup(struct vm_area_struct *vma,
/*
* doesn't attempt to fault and will return short.
*/
-int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
- struct page **pages);
+int get_user_pages_fast_only(unsigned long start, int nr_pages,
+ unsigned int gup_flags, struct page **pages);
int pin_user_pages_fast_only(unsigned long start, int nr_pages,
unsigned int gup_flags, struct page **pages);
+
+static inline bool get_user_page_fast_only(unsigned long addr,
+ unsigned int gup_flags, struct page **pagep)
+{
+ return get_user_pages_fast_only(addr, 1, gup_flags, pagep) == 1;
+}
/*
* per-process(per-mm_struct) statistics.
*/
diff --git a/kernel/events/core.c b/kernel/events/core.c
index c94eb27..856d98c 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6934,12 +6934,12 @@ static u64 perf_virt_to_phys(u64 virt)
* Walking the pages tables for user address.
* Interrupts are disabled, so it prevents any tear down
* of the page tables.
- * Try IRQ-safe __get_user_pages_fast first.
+ * Try IRQ-safe get_user_page_fast_only first.
* If failed, leave phys_addr as 0.
*/
if (current->mm != NULL) {
pagefault_disable();
- if (__get_user_pages_fast(virt, 1, 0, &p) == 1)
+ if (get_user_page_fast_only(virt, 0, &p))
phys_addr = page_to_phys(p) + virt % PAGE_SIZE;
pagefault_enable();
}
diff --git a/mm/gup.c b/mm/gup.c
index 80f51a36..bb59f5c 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -2278,7 +2278,7 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
* to be special.
*
* For a futex to be placed on a THP tail page, get_futex_key requires a
- * __get_user_pages_fast implementation that can pin pages. Thus it's still
+ * get_user_pages_fast_only implementation that can pin pages. Thus it's still
* useful to have gup_huge_pmd even if we can't operate on ptes.
*/
static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
@@ -2683,7 +2683,7 @@ static inline void gup_pgd_range(unsigned long addr, unsigned long end,
#ifndef gup_fast_permitted
/*
- * Check if it's allowed to use __get_user_pages_fast() for the range, or
+ * Check if it's allowed to use get_user_pages_fast_only() for the range, or
* we need to fall back to the slow version:
*/
static bool gup_fast_permitted(unsigned long start, unsigned long end)
@@ -2776,8 +2776,14 @@ static int internal_get_user_pages_fast(unsigned long start, int nr_pages,
return ret;
}
-
-/*
+/**
+ * get_user_pages_fast_only() - pin user pages in memory
+ * @start: starting user address
+ * @nr_pages: number of pages from start to pin
+ * @gup_flags: flags modifying pin behaviour
+ * @pages: array that receives pointers to the pages pinned.
+ * Should be at least nr_pages long.
+ *
* Like get_user_pages_fast() except it's IRQ-safe in that it won't fall back to
* the regular GUP.
* Note a difference with get_user_pages_fast: this always returns the
@@ -2786,8 +2792,8 @@ static int internal_get_user_pages_fast(unsigned long start, int nr_pages,
* If the architecture does not support this function, simply return with no
* pages pinned.
*/
-int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
- struct page **pages)
+int get_user_pages_fast_only(unsigned long start, int nr_pages,
+ unsigned int gup_flags, struct page **pages)
{
int nr_pinned;
/*
@@ -2797,10 +2803,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
* FOLL_FAST_ONLY is required in order to match the API description of
* this routine: no fall back to regular ("slow") GUP.
*/
- unsigned int gup_flags = FOLL_GET | FOLL_FAST_ONLY;
-
- if (write)
- gup_flags |= FOLL_WRITE;
+ gup_flags |= FOLL_GET | FOLL_FAST_ONLY;
nr_pinned = internal_get_user_pages_fast(start, nr_pages, gup_flags,
pages);
@@ -2815,7 +2818,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
return nr_pinned;
}
-EXPORT_SYMBOL_GPL(__get_user_pages_fast);
+EXPORT_SYMBOL_GPL(get_user_pages_fast_only);
/**
* get_user_pages_fast() - pin user pages in memory
@@ -2886,8 +2889,8 @@ int pin_user_pages_fast(unsigned long start, int nr_pages,
EXPORT_SYMBOL_GPL(pin_user_pages_fast);
/*
- * This is the FOLL_PIN equivalent of __get_user_pages_fast(). Behavior is the
- * same, except that this one sets FOLL_PIN instead of FOLL_GET.
+ * This is the FOLL_PIN equivalent of get_user_pages_fast_only(). Behavior
+ * is the same, except that this one sets FOLL_PIN instead of FOLL_GET.
*
* The API rules are the same, too: no negative values may be returned.
*/
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index fc38d63..b62ea62 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1740,7 +1740,6 @@ static bool hva_to_pfn_fast(unsigned long addr, bool write_fault,
bool *writable, kvm_pfn_t *pfn)
{
struct page *page[1];
- int npages;
/*
* Fast pin a writable pfn only if it is a write fault request
@@ -1750,8 +1749,7 @@ static bool hva_to_pfn_fast(unsigned long addr, bool write_fault,
if (!(write_fault || writable))
return false;
- npages = __get_user_pages_fast(addr, 1, 1, page);
- if (npages == 1) {
+ if (get_user_page_fast_only(addr, FOLL_WRITE, page)) {
*pfn = page_to_pfn(page[0]);
if (writable)
@@ -1791,7 +1789,7 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault,
if (unlikely(!write_fault) && writable) {
struct page *wpage;
- if (__get_user_pages_fast(addr, 1, 1, &wpage) == 1) {
+ if (get_user_page_fast_only(addr, FOLL_WRITE, &wpage)) {
*writable = true;
put_page(page);
page = wpage;
@@ -1998,7 +1996,7 @@ int gfn_to_page_many_atomic(struct kvm_memory_slot *slot, gfn_t gfn,
if (entry < nr_pages)
return 0;
- return __get_user_pages_fast(addr, nr_pages, 1, pages);
+ return get_user_pages_fast_only(addr, nr_pages, FOLL_WRITE, pages);
}
EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic);
--
1.9.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