* [PATCH v3 02/16] powerpc/mm/32: add base address to mmu_mapin_ram()
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
At the time being, mmu_mapin_ram() always maps RAM from the beginning.
But some platforms like the WII have to map a second block of RAM.
This patch adds to mmu_mapin_ram() the base address of the block.
At the moment, only base address 0 is supported.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/mm/40x_mmu.c | 2 +-
arch/powerpc/mm/44x_mmu.c | 2 +-
arch/powerpc/mm/8xx_mmu.c | 2 +-
arch/powerpc/mm/fsl_booke_mmu.c | 2 +-
arch/powerpc/mm/mmu_decl.h | 2 +-
arch/powerpc/mm/pgtable_32.c | 6 +++---
arch/powerpc/mm/ppc_mmu_32.c | 2 +-
7 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/mm/40x_mmu.c b/arch/powerpc/mm/40x_mmu.c
index 61ac468c87c6..b9cf6f8764b0 100644
--- a/arch/powerpc/mm/40x_mmu.c
+++ b/arch/powerpc/mm/40x_mmu.c
@@ -93,7 +93,7 @@ void __init MMU_init_hw(void)
#define LARGE_PAGE_SIZE_16M (1<<24)
#define LARGE_PAGE_SIZE_4M (1<<22)
-unsigned long __init mmu_mapin_ram(unsigned long top)
+unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
{
unsigned long v, s, mapped;
phys_addr_t p;
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
index ea2b9af08a48..aad127acdbaa 100644
--- a/arch/powerpc/mm/44x_mmu.c
+++ b/arch/powerpc/mm/44x_mmu.c
@@ -170,7 +170,7 @@ void __init MMU_init_hw(void)
flush_instruction_cache();
}
-unsigned long __init mmu_mapin_ram(unsigned long top)
+unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
{
unsigned long addr;
unsigned long memstart = memstart_addr & ~(PPC_PIN_SIZE - 1);
diff --git a/arch/powerpc/mm/8xx_mmu.c b/arch/powerpc/mm/8xx_mmu.c
index e2c32bdb6023..46bc26ef71e9 100644
--- a/arch/powerpc/mm/8xx_mmu.c
+++ b/arch/powerpc/mm/8xx_mmu.c
@@ -99,7 +99,7 @@ static void __init mmu_patch_cmp_limit(s32 *site, unsigned long mapped)
modify_instruction_site(site, 0xffff, (unsigned long)__va(mapped) >> 16);
}
-unsigned long __init mmu_mapin_ram(unsigned long top)
+unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
{
unsigned long mapped;
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index 080d49b26c3a..210cbc1faf63 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -221,7 +221,7 @@ unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx, bool dryrun)
#error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS"
#endif
-unsigned long __init mmu_mapin_ram(unsigned long top)
+unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
{
return tlbcam_addrs[tlbcam_index - 1].limit - PAGE_OFFSET + 1;
}
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index c4a717da65eb..61730023dde3 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -130,7 +130,7 @@ extern void wii_memory_fixups(void);
*/
#ifdef CONFIG_PPC32
extern void MMU_init_hw(void);
-extern unsigned long mmu_mapin_ram(unsigned long top);
+unsigned long mmu_mapin_ram(unsigned long base, unsigned long top);
#endif
#ifdef CONFIG_PPC_FSL_BOOK3E
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index ded71126ce4c..b4858818523f 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -258,15 +258,15 @@ void __init mapin_ram(void)
#ifndef CONFIG_WII
top = total_lowmem;
- s = mmu_mapin_ram(top);
+ s = mmu_mapin_ram(0, top);
__mapin_ram_chunk(s, top);
#else
if (!wii_hole_size) {
- s = mmu_mapin_ram(total_lowmem);
+ s = mmu_mapin_ram(0, total_lowmem);
__mapin_ram_chunk(s, total_lowmem);
} else {
top = wii_hole_start;
- s = mmu_mapin_ram(top);
+ s = mmu_mapin_ram(0, top);
__mapin_ram_chunk(s, top);
top = memblock_end_of_DRAM();
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 3f4193201ee7..b260ced065b4 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -73,7 +73,7 @@ unsigned long p_block_mapped(phys_addr_t pa)
return 0;
}
-unsigned long __init mmu_mapin_ram(unsigned long top)
+unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
{
unsigned long tot, bl, done;
unsigned long max_size = (256<<20);
--
2.13.3
^ permalink raw reply related
* [PATCH v3 08/16] powerpc/32: add helper to write into segment registers
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
This patch add an helper which wraps 'mtsrin' instruction
to write into segment registers.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/reg.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 1c98ef1f2d5b..a70cbaf5c26f 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -1425,6 +1425,11 @@ static inline void msr_check_and_clear(unsigned long bits)
#define mfsrin(v) ({unsigned int rval; \
asm volatile("mfsrin %0,%1" : "=r" (rval) : "r" (v)); \
rval;})
+
+static inline void mtsrin(u32 val, u32 idx)
+{
+ asm volatile("mtsrin %0, %1" : : "r" (val), "r" (idx));
+}
#endif
#define proc_trap() asm volatile("trap")
--
2.13.3
^ permalink raw reply related
* [PATCH v3 07/16] powerpc/mm/32s: use _PAGE_EXEC in setbat()
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
Do not set IBAT when setbat() is called without _PAGE_EXEC
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/mm/ppc_mmu_32.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 5fc59b195fef..ff8580c6ab11 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -131,6 +131,7 @@ unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
* Set up one of the I/D BAT (block address translation) register pairs.
* The parameters are not checked; in particular size must be a power
* of 2 between 128k and 256M.
+ * On 603+, only set IBAT when _PAGE_EXEC is set
*/
void __init setbat(int index, unsigned long virt, phys_addr_t phys,
unsigned int size, pgprot_t prot)
@@ -157,11 +158,12 @@ void __init setbat(int index, unsigned long virt, phys_addr_t phys,
bat[1].batu |= 1; /* Vp = 1 */
if (flags & _PAGE_GUARDED) {
/* G bit must be zero in IBATs */
- bat[0].batu = bat[0].batl = 0;
- } else {
- /* make IBAT same as DBAT */
- bat[0] = bat[1];
+ flags &= ~_PAGE_EXEC;
}
+ if (flags & _PAGE_EXEC)
+ bat[0] = bat[1];
+ else
+ bat[0].batu = bat[0].batl = 0;
} else {
/* 601 cpu */
if (bl > BL_8M)
--
2.13.3
^ permalink raw reply related
* [PATCH v3 05/16] powerpc/32: always populate page tables for Abatron BDI.
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
When CONFIG_BDI_SWITCH is set, the page tables have to be populated
allthough large TLBs are used, because the BDI switch knows nothing
about those large TLBs which are handled directly in TLB miss logic.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/mm/pgtable_32.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index fd665c32a1f7..94bd7d013557 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -261,7 +261,10 @@ void __init mapin_ram(void)
unsigned long top = base + reg->size;
base = mmu_mapin_ram(base, top);
- __mapin_ram_chunk(base, top);
+ if (IS_ENABLED(CONFIG_BDI_SWITCH))
+ __mapin_ram_chunk(reg->base, top);
+ else
+ __mapin_ram_chunk(base, top);
}
}
--
2.13.3
^ permalink raw reply related
* [PATCH v3 06/16] powerpc/wii: remove wii_mmu_mapin_mem2()
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
wii_mmu_mapin_mem2() is not used anymore, remove it.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/platforms/embedded6xx/wii.c | 28 ----------------------------
1 file changed, 28 deletions(-)
diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c
index ac4ee88efc80..235fe81aa2b1 100644
--- a/arch/powerpc/platforms/embedded6xx/wii.c
+++ b/arch/powerpc/platforms/embedded6xx/wii.c
@@ -54,10 +54,6 @@
static void __iomem *hw_ctrl;
static void __iomem *hw_gpio;
-unsigned long wii_hole_start;
-unsigned long wii_hole_size;
-
-
static int __init page_aligned(unsigned long x)
{
return !(x & (PAGE_SIZE-1));
@@ -69,30 +65,6 @@ void __init wii_memory_fixups(void)
BUG_ON(memblock.memory.cnt != 2);
BUG_ON(!page_aligned(p[0].base) || !page_aligned(p[1].base));
-
- /* determine hole */
- wii_hole_start = ALIGN(p[0].base + p[0].size, PAGE_SIZE);
- wii_hole_size = p[1].base - wii_hole_start;
-}
-
-unsigned long __init wii_mmu_mapin_mem2(unsigned long top)
-{
- unsigned long delta, size, bl;
- unsigned long max_size = (256<<20);
-
- /* MEM2 64MB@0x10000000 */
- delta = wii_hole_start + wii_hole_size;
- size = top - delta;
-
- if (__map_without_bats)
- return delta;
-
- for (bl = 128<<10; bl < max_size; bl <<= 1) {
- if (bl * 2 > size)
- break;
- }
- setbat(4, PAGE_OFFSET+delta, delta, bl, PAGE_KERNEL_X);
- return delta + bl;
}
static void __noreturn wii_spin(void)
--
2.13.3
^ permalink raw reply related
* [PATCH v3 09/16] powerpc/mmu: add is_strict_kernel_rwx() helper
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
Add a helper to know whether STRICT_KERNEL_RWX is enabled.
This is based on rodata_enabled flag which is defined only
when CONFIG_STRICT_KERNEL_RWX is selected.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/mmu.h | 11 +++++++++++
arch/powerpc/mm/init_32.c | 4 +---
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index 6d22a8e78fe2..d34ad1657d7b 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -289,6 +289,17 @@ static inline u16 get_mm_addr_key(struct mm_struct *mm, unsigned long address)
}
#endif /* CONFIG_PPC_MEM_KEYS */
+#ifdef CONFIG_STRICT_KERNEL_RWX
+static inline bool strict_kernel_rwx_enabled(void)
+{
+ return rodata_enabled;
+}
+#else
+static inline bool strict_kernel_rwx_enabled(void)
+{
+ return false;
+}
+#endif
#endif /* !__ASSEMBLY__ */
/* The kernel use the constants below to index in the page sizes array.
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 3e59e5d64b01..ee5a430b9a18 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -108,12 +108,10 @@ static void __init MMU_setup(void)
__map_without_bats = 1;
__map_without_ltlbs = 1;
}
-#ifdef CONFIG_STRICT_KERNEL_RWX
- if (rodata_enabled) {
+ if (strict_kernel_rwx_enabled()) {
__map_without_bats = 1;
__map_without_ltlbs = 1;
}
-#endif
}
/*
--
2.13.3
^ permalink raw reply related
* [PATCH v3 11/16] powerpc/kconfig: define CONFIG_DATA_SHIFT and CONFIG_ETEXT_SHIFT
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
CONFIG_STRICT_KERNEL_RWX requires a special alignment
for DATA for some subarches. Today it is just defined
as an #ifdef in vmlinux.lds.S
In order to get more flexibility, this patch moves the
definition of this alignment in Kconfig
On some subarches, CONFIG_STRICT_KERNEL_RWX will
require a special alignment of _etext.
This patch also adds a configuration item for it in Kconfig
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 9 +++++++++
arch/powerpc/kernel/vmlinux.lds.S | 9 +++------
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 417e52a27f63..edef40a2b446 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -725,6 +725,15 @@ config THREAD_SHIFT
Used to define the stack size. The default is almost always what you
want. Only change this if you know what you are doing.
+config ETEXT_SHIFT
+ int
+ default PPC_PAGE_SHIFT
+
+config DATA_SHIFT
+ int
+ default 24 if STRICT_KERNEL_RWX && PPC64
+ default PPC_PAGE_SHIFT
+
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
range 8 9 if PPC64 && PPC_64K_PAGES
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index c3efb972c8c1..060a1acd7c6d 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -12,11 +12,8 @@
#include <asm/cache.h>
#include <asm/thread_info.h>
-#if defined(CONFIG_STRICT_KERNEL_RWX) && !defined(CONFIG_PPC32)
-#define STRICT_ALIGN_SIZE (1 << 24)
-#else
-#define STRICT_ALIGN_SIZE PAGE_SIZE
-#endif
+#define STRICT_ALIGN_SIZE (1 << CONFIG_DATA_SHIFT)
+#define ETEXT_ALIGN_SIZE (1 << CONFIG_ETEXT_SHIFT)
ENTRY(_stext)
@@ -131,7 +128,7 @@ SECTIONS
} :kernel
- . = ALIGN(PAGE_SIZE);
+ . = ALIGN(ETEXT_ALIGN_SIZE);
_etext = .;
PROVIDE32 (etext = .);
--
2.13.3
^ permalink raw reply related
* [PATCH v3 10/16] powerpc/kconfig: define PAGE_SHIFT inside Kconfig
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
This patch defined CONFIG_PPC_PAGE_SHIFT in order
to be able to use PAGE_SHIFT value inside Kconfig.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 7 +++++++
arch/powerpc/include/asm/page.h | 13 ++-----------
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 849b0d5ac3d1..417e52a27f63 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -708,6 +708,13 @@ config PPC_256K_PAGES
endchoice
+config PPC_PAGE_SHIFT
+ int
+ default 18 if PPC_256K_PAGES
+ default 16 if PPC_64K_PAGES
+ default 14 if PPC_16K_PAGES
+ default 12
+
config THREAD_SHIFT
int "Thread shift" if EXPERT
range 13 15
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index aa4497175bd3..ed870468ef6f 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -20,20 +20,11 @@
/*
* On regular PPC32 page size is 4K (but we support 4K/16K/64K/256K pages
- * on PPC44x). For PPC64 we support either 4K or 64K software
+ * on PPC44x and 4K/16K on 8xx). For PPC64 we support either 4K or 64K software
* page size. When using 64K pages however, whether we are really supporting
* 64K pages in HW or not is irrelevant to those definitions.
*/
-#if defined(CONFIG_PPC_256K_PAGES)
-#define PAGE_SHIFT 18
-#elif defined(CONFIG_PPC_64K_PAGES)
-#define PAGE_SHIFT 16
-#elif defined(CONFIG_PPC_16K_PAGES)
-#define PAGE_SHIFT 14
-#else
-#define PAGE_SHIFT 12
-#endif
-
+#define PAGE_SHIFT CONFIG_PPC_PAGE_SHIFT
#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT)
#ifndef __ASSEMBLY__
--
2.13.3
^ permalink raw reply related
* [PATCH v3 13/16] powerpc/mm/32s: Use BATs for STRICT_KERNEL_RWX
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
Today, STRICT_KERNEL_RWX is based on the use of regular pages
to map kernel pages.
On Book3s 32, it has three consequences:
- Using pages instead of BAT for mapping kernel linear memory severely
impacts performance.
- Exec protection is not effective because no-execute cannot be set at
page level (except on 603 which doesn't have hash tables)
- Write protection is not effective because PP bits do not provide RO
mode for kernel-only pages (except on 603 which handles it in software
via PAGE_DIRTY)
On the 603+, we have:
- Independent IBAT and DBAT allowing limitation of exec parts.
- NX bit can be set in segment registers to forbit execution on memory
mapped by pages.
- RO mode on DBATs even for kernel-only blocks.
On the 601, there is nothing much we can do other than warn the user
about it, because:
- BATs are common to instructions and data.
- BAT do not provide RO mode for kernel-only blocks.
- segment registers don't have the NX bit.
In order to use IBAT for exec protection, this patch:
- Aligns _etext to BAT block sizes (128kb)
- Set NX bit in kernel segment register (Except on vmalloc area when
CONFIG_MODULES is selected)
- Maps kernel text with IBATs.
In order to use DBAT for exec protection, this patch:
- Aligns RW DATA to BAT block sizes (4M)
- Maps kernel RO area with write prohibited DBATs
- Maps remaining memory with remaining DBATs
Here is what we get with this patch on a 832x when activating
STRICT_KERNEL_RWX:
Symbols:
c0000000 T _stext
c0680000 R __start_rodata
c0680000 R _etext
c0800000 T __init_begin
c0800000 T _sinittext
~# cat /sys/kernel/debug/block_address_translation
---[ Instruction Block Address Translation ]---
0: 0xc0000000-0xc03fffff 0x00000000 Kernel EXEC coherent
1: 0xc0400000-0xc05fffff 0x00400000 Kernel EXEC coherent
2: 0xc0600000-0xc067ffff 0x00600000 Kernel EXEC coherent
3: -
4: -
5: -
6: -
7: -
---[ Data Block Address Translation ]---
0: 0xc0000000-0xc07fffff 0x00000000 Kernel RO coherent
1: 0xc0800000-0xc0ffffff 0x00800000 Kernel RW coherent
2: 0xc1000000-0xc1ffffff 0x01000000 Kernel RW coherent
3: 0xc2000000-0xc3ffffff 0x02000000 Kernel RW coherent
4: 0xc4000000-0xc7ffffff 0x04000000 Kernel RW coherent
5: 0xc8000000-0xcfffffff 0x08000000 Kernel RW coherent
6: 0xd0000000-0xdfffffff 0x10000000 Kernel RW coherent
7: -
~# cat /sys/kernel/debug/segment_registers
---[ User Segments ]---
0x00000000-0x0fffffff Kern key 1 User key 1 VSID 0xa085d0
0x10000000-0x1fffffff Kern key 1 User key 1 VSID 0xa086e1
0x20000000-0x2fffffff Kern key 1 User key 1 VSID 0xa087f2
0x30000000-0x3fffffff Kern key 1 User key 1 VSID 0xa08903
0x40000000-0x4fffffff Kern key 1 User key 1 VSID 0xa08a14
0x50000000-0x5fffffff Kern key 1 User key 1 VSID 0xa08b25
0x60000000-0x6fffffff Kern key 1 User key 1 VSID 0xa08c36
0x70000000-0x7fffffff Kern key 1 User key 1 VSID 0xa08d47
0x80000000-0x8fffffff Kern key 1 User key 1 VSID 0xa08e58
0x90000000-0x9fffffff Kern key 1 User key 1 VSID 0xa08f69
0xa0000000-0xafffffff Kern key 1 User key 1 VSID 0xa0907a
0xb0000000-0xbfffffff Kern key 1 User key 1 VSID 0xa0918b
---[ Kernel Segments ]---
0xc0000000-0xcfffffff Kern key 0 User key 1 No Exec VSID 0x000ccc
0xd0000000-0xdfffffff Kern key 0 User key 1 No Exec VSID 0x000ddd
0xe0000000-0xefffffff Kern key 0 User key 1 No Exec VSID 0x000eee
0xf0000000-0xffffffff Kern key 0 User key 1 No Exec VSID 0x000fff
Aligning _etext to 128kb allows to map up to 32Mb text with 8 IBATs:
16Mb + 8Mb + 4Mb + 2Mb + 1Mb + 512kb + 256kb + 128kb (+ 128kb) = 32Mb
(A 9th IBAT is unneeded as 32Mb would need only a single 32Mb block)
Aligning data to 4M allows to map up to 512Mb data with 8 DBATs:
16Mb + 8Mb + 4Mb + 4Mb + 32Mb + 64Mb + 128Mb + 256Mb = 512Mb
Because some processors only have 4 BATs and because some targets need
DBATs for mapping other areas, the following patch will allow to
modify _etext and data alignment.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 2 +
arch/powerpc/include/asm/book3s/32/pgtable.h | 11 ++++
arch/powerpc/mm/init_32.c | 4 +-
arch/powerpc/mm/mmu_decl.h | 8 +++
arch/powerpc/mm/pgtable_32.c | 10 +++-
arch/powerpc/mm/ppc_mmu_32.c | 87 ++++++++++++++++++++++++++--
6 files changed, 112 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index edef40a2b446..640a7cfba9d0 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -727,11 +727,13 @@ config THREAD_SHIFT
config ETEXT_SHIFT
int
+ default 17 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
default PPC_PAGE_SHIFT
config DATA_SHIFT
int
default 24 if STRICT_KERNEL_RWX && PPC64
+ default 22 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
default PPC_PAGE_SHIFT
config FORCE_MAX_ZONEORDER
diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 49d76adb9bc5..aa8406b8f7ba 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -174,7 +174,18 @@ static inline bool pte_user(pte_t pte)
* of RAM. -- Cort
*/
#define VMALLOC_OFFSET (0x1000000) /* 16M */
+
+/*
+ * With CONFIG_STRICT_KERNEL_RWX, kernel segments are set NX. But when modules
+ * are used, NX cannot be set on VMALLOC space. So vmalloc VM space and linear
+ * memory shall not share segments.
+ */
+#if defined(CONFIG_STRICT_KERNEL_RWX) && defined(CONFIG_MODULES)
+#define VMALLOC_START ((_ALIGN((long)high_memory, 256L << 20) + VMALLOC_OFFSET) & \
+ ~(VMALLOC_OFFSET - 1))
+#else
#define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#endif
#define VMALLOC_END ioremap_bot
#ifndef __ASSEMBLY__
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index ee5a430b9a18..bc28995a37ea 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -108,10 +108,8 @@ static void __init MMU_setup(void)
__map_without_bats = 1;
__map_without_ltlbs = 1;
}
- if (strict_kernel_rwx_enabled()) {
- __map_without_bats = 1;
+ if (strict_kernel_rwx_enabled())
__map_without_ltlbs = 1;
- }
}
/*
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index 61730023dde3..98fc94affc29 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -165,3 +165,11 @@ unsigned long p_block_mapped(phys_addr_t pa);
static inline phys_addr_t v_block_mapped(unsigned long va) { return 0; }
static inline unsigned long p_block_mapped(phys_addr_t pa) { return 0; }
#endif
+
+#if defined(CONFIG_PPC_BOOK3S_32)
+void mmu_mark_initmem_nx(void);
+void mmu_mark_rodata_ro(void);
+#else
+static inline void mmu_mark_initmem_nx(void) { }
+static inline void mmu_mark_rodata_ro(void) { }
+#endif
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 94bd7d013557..a3ad09c6e277 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -351,7 +351,10 @@ void mark_initmem_nx(void)
unsigned long numpages = PFN_UP((unsigned long)_einittext) -
PFN_DOWN((unsigned long)_sinittext);
- change_page_attr(page, numpages, PAGE_KERNEL);
+ if (v_block_mapped((unsigned long)_stext) + 1)
+ mmu_mark_initmem_nx();
+ else
+ change_page_attr(page, numpages, PAGE_KERNEL);
}
#ifdef CONFIG_STRICT_KERNEL_RWX
@@ -360,6 +363,11 @@ void mark_rodata_ro(void)
struct page *page;
unsigned long numpages;
+ if (v_block_mapped((unsigned long)_sinittext)) {
+ mmu_mark_rodata_ro();
+ return;
+ }
+
page = virt_to_page(_stext);
numpages = PFN_UP((unsigned long)_etext) -
PFN_DOWN((unsigned long)_stext);
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 66f1319e8e20..53d9ed576ab5 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -32,6 +32,7 @@
#include <asm/mmu.h>
#include <asm/machdep.h>
#include <asm/code-patching.h>
+#include <asm/sections.h>
#include "mmu_decl.h"
@@ -138,15 +139,10 @@ static void clearibat(int index)
bat[0].batl = 0;
}
-unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
+unsigned long __init __mmu_mapin_ram(unsigned long base, unsigned long top)
{
int idx;
- if (__map_without_bats) {
- printk(KERN_DEBUG "RAM mapped without BATs\n");
- return base;
- }
-
while ((idx = find_free_bat()) != -1 && base != top) {
unsigned int size = block_size(base, top);
@@ -159,6 +155,85 @@ unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
return base;
}
+unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
+{
+ int done;
+ unsigned long border = (unsigned long)__init_begin - PAGE_OFFSET;
+
+ if (__map_without_bats) {
+ pr_debug("RAM mapped without BATs\n");
+ return base;
+ }
+
+ if (!strict_kernel_rwx_enabled() || base >= border || top <= border)
+ return __mmu_mapin_ram(base, top);
+
+ done = __mmu_mapin_ram(base, border);
+ if (done != border - base)
+ return done;
+
+ return done + __mmu_mapin_ram(border, top);
+}
+
+void mmu_mark_initmem_nx(void)
+{
+ int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
+ int i;
+ unsigned long base = (unsigned long)_stext - PAGE_OFFSET;
+ unsigned long top = (unsigned long)_etext - PAGE_OFFSET;
+ unsigned long size;
+
+ if (cpu_has_feature(CPU_FTR_601))
+ return;
+
+ for (i = 0; i < nb - 1 && base < top && top - base > (128 << 10);) {
+ size = block_size(base, top);
+ setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
+ base += size;
+ }
+ if (base < top) {
+ 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;
+ }
+ setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
+ base += size;
+ }
+ for (; i < nb; i++)
+ clearibat(i);
+
+ update_bats();
+
+ for (i = TASK_SIZE >> 28; i < 16; i++) {
+ /* Do not set NX on VM space for modules */
+ if (IS_ENABLED(CONFIG_MODULES) &&
+ (VMALLOC_START & 0xf0000000) == i << 28)
+ break;
+ mtsrin(mfsrin(i << 28) | 0x10000000, i << 28);
+ }
+}
+
+void mmu_mark_rodata_ro(void)
+{
+ int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
+ int i;
+
+ if (cpu_has_feature(CPU_FTR_601))
+ return;
+
+ for (i = 0; i < nb; i++) {
+ struct ppc_bat *bat = BATS[i];
+
+ if (bat_addrs[i].start < (unsigned long)__init_begin)
+ bat[1].batl = (bat[1].batl & ~BPP_RW) | BPP_RX;
+ }
+
+ update_bats();
+}
+
/*
* Set up one of the I/D BAT (block address translation) register pairs.
* The parameters are not checked; in particular size must be a power
--
2.13.3
^ permalink raw reply related
* [PATCH v3 12/16] powerpc/mm/32s: add setibat() clearibat() and update_bats()
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
setibat() and clearibat() allows to manipulate IBATs independently
of DBATs.
update_bats() allows to update bats after init. This is done
with MMU off.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/book3s/32/mmu-hash.h | 2 ++
arch/powerpc/kernel/head_32.S | 35 +++++++++++++++++++++++++++
arch/powerpc/mm/ppc_mmu_32.c | 32 ++++++++++++++++++++++++
3 files changed, 69 insertions(+)
diff --git a/arch/powerpc/include/asm/book3s/32/mmu-hash.h b/arch/powerpc/include/asm/book3s/32/mmu-hash.h
index 0c261ba2c826..5cb588395fdc 100644
--- a/arch/powerpc/include/asm/book3s/32/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/32/mmu-hash.h
@@ -92,6 +92,8 @@ typedef struct {
unsigned long vdso_base;
} mm_context_t;
+void update_bats(void);
+
/* patch sites */
extern s32 patch__hash_page_A0, patch__hash_page_A1, patch__hash_page_A2;
extern s32 patch__hash_page_B, patch__hash_page_C;
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index c2f564690778..91b302b0797f 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -1104,6 +1104,41 @@ BEGIN_MMU_FTR_SECTION
END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
blr
+_ENTRY(update_bats)
+ lis r4, 1f@h
+ ori r4, r4, 1f@l
+ tophys(r4, r4)
+ mfmsr r6
+ mflr r7
+ li r3, MSR_KERNEL & ~(MSR_IR | MSR_DR)
+ rlwinm r0, r6, 0, ~MSR_RI
+ rlwinm r0, r0, 0, ~MSR_EE
+ mtmsr r0
+ mtspr SPRN_SRR0, r4
+ mtspr SPRN_SRR1, r3
+ SYNC
+ RFI
+1: bl clear_bats
+ lis r3, BATS@ha
+ addi r3, r3, BATS@l
+ tophys(r3, r3)
+ LOAD_BAT(0, r3, r4, r5)
+ LOAD_BAT(1, r3, r4, r5)
+ LOAD_BAT(2, r3, r4, r5)
+ LOAD_BAT(3, r3, r4, r5)
+BEGIN_MMU_FTR_SECTION
+ LOAD_BAT(4, r3, r4, r5)
+ LOAD_BAT(5, r3, r4, r5)
+ LOAD_BAT(6, r3, r4, r5)
+ LOAD_BAT(7, r3, r4, r5)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+ li r3, MSR_KERNEL & ~(MSR_IR | MSR_DR | MSR_RI)
+ mtmsr r3
+ mtspr SPRN_SRR0, r7
+ mtspr SPRN_SRR1, r6
+ SYNC
+ RFI
+
flush_tlbs:
lis r10, 0x40
1: addic. r10, r10, -0x1000
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index ff8580c6ab11..66f1319e8e20 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -106,6 +106,38 @@ static unsigned int block_size(unsigned long base, unsigned long top)
return min3(max_size, 1U << base_shift, 1U << block_shift);
}
+/*
+ * Set up one of the IBAT (block address translation) register pairs.
+ * The parameters are not checked; in particular size must be a power
+ * of 2 between 128k and 256M.
+ * Only for 603+ ...
+ */
+static void setibat(int index, unsigned long virt, phys_addr_t phys,
+ unsigned int size, pgprot_t prot)
+{
+ unsigned int bl = (size >> 17) - 1;
+ int wimgxpp;
+ struct ppc_bat *bat = BATS[index];
+ unsigned long flags = pgprot_val(prot);
+
+ if (!cpu_has_feature(CPU_FTR_NEED_COHERENT))
+ flags &= ~_PAGE_COHERENT;
+
+ wimgxpp = (flags & _PAGE_COHERENT) | (_PAGE_EXEC ? BPP_RX : BPP_XX);
+ bat[0].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
+ bat[0].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
+ if (flags & _PAGE_USER)
+ bat[0].batu |= 1; /* Vp = 1 */
+}
+
+static void clearibat(int index)
+{
+ struct ppc_bat *bat = BATS[index];
+
+ bat[0].batu = 0;
+ bat[0].batl = 0;
+}
+
unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
{
int idx;
--
2.13.3
^ permalink raw reply related
* [PATCH v3 14/16] powerpc/kconfig: make _etext and data areas alignment configurable on Book3s 32
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
Depending on the number of available BATs for mapping the different
kernel areas, it might be needed to increase the alignment of _etext
and/or of data areas.
This patchs allows the user to do it via Kconfig.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 640a7cfba9d0..20c4e3a62b90 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -725,16 +725,44 @@ config THREAD_SHIFT
Used to define the stack size. The default is almost always what you
want. Only change this if you know what you are doing.
+config ETEXT_SHIFT_BOOL
+ bool "Set custom etext alignment" if STRICT_KERNEL_RWX && PPC_BOOK3S_32
+ depends on ADVANCED_OPTIONS
+ help
+ This option allows you to set the kernel end of text alignment. When
+ RAM is mapped by blocks, the alignment needs to fit the size and
+ number of possible blocks. The default should be OK for most configs.
+
+ Say N here unless you know what you are doing.
+
config ETEXT_SHIFT
- int
+ int "_etext shift" if ETEXT_SHIFT_BOOL
+ range 17 28 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
default 17 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
default PPC_PAGE_SHIFT
+ help
+ On Book3S 32 (603+), IBATs are used to map kernel text.
+ Smaller is the alignment, greater is the number of necessary IBATs.
+
+config DATA_SHIFT_BOOL
+ bool "Set custom data alignment" if STRICT_KERNEL_RWX && PPC_BOOK3S_32
+ depends on ADVANCED_OPTIONS
+ help
+ This option allows you to set the kernel data alignment. When
+ RAM is mapped by blocks, the alignment needs to fit the size and
+ number of possible blocks. The default should be OK for most configs.
+
+ Say N here unless you know what you are doing.
config DATA_SHIFT
- int
+ int "Data shift" if DATA_SHIFT_BOOL
default 24 if STRICT_KERNEL_RWX && PPC64
+ range 17 28 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
default 22 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
default PPC_PAGE_SHIFT
+ help
+ On Book3S 32 (603+), DBATs are used to map kernel text and rodata RO.
+ Smaller is the alignment, greater is the number of necessary DBATs.
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
--
2.13.3
^ permalink raw reply related
* [PATCH v3 15/16] powerpc/8xx: don't disable large TLBs with CONFIG_STRICT_KERNEL_RWX
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
This patch implements handling of STRICT_KERNEL_RWX with
large TLBs directly in the TLB miss handlers.
To do so, etext and sinittext are aligned on 512kB boundaries
and the miss handlers use 512kB pages instead of 8Mb pages for
addresses close to the boundaries.
It sets RO PP flags for addresses under sinittext.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 2 ++
arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 3 +-
arch/powerpc/kernel/head_8xx.S | 54 +++++++++++++++++++++-------
arch/powerpc/mm/8xx_mmu.c | 31 +++++++++++++++-
arch/powerpc/mm/init_32.c | 2 +-
arch/powerpc/mm/mmu_decl.h | 2 +-
6 files changed, 78 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 20c4e3a62b90..c4d6c97d7699 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -739,6 +739,7 @@ config ETEXT_SHIFT
int "_etext shift" if ETEXT_SHIFT_BOOL
range 17 28 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
default 17 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
+ default 19 if STRICT_KERNEL_RWX && PPC_8xx
default PPC_PAGE_SHIFT
help
On Book3S 32 (603+), IBATs are used to map kernel text.
@@ -759,6 +760,7 @@ config DATA_SHIFT
default 24 if STRICT_KERNEL_RWX && PPC64
range 17 28 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
default 22 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
+ default 19 if STRICT_KERNEL_RWX && PPC_8xx
default PPC_PAGE_SHIFT
help
On Book3S 32 (603+), DBATs are used to map kernel text and rodata RO.
diff --git a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
index b0f764c827c0..0a1a3fc54e54 100644
--- a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
@@ -231,9 +231,10 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize)
}
/* patch sites */
-extern s32 patch__itlbmiss_linmem_top;
+extern s32 patch__itlbmiss_linmem_top, patch__itlbmiss_linmem_top8;
extern s32 patch__dtlbmiss_linmem_top, patch__dtlbmiss_immr_jmp;
extern s32 patch__fixupdar_linmem_top;
+extern s32 patch__dtlbmiss_romem_top, patch__dtlbmiss_romem_top8;
extern s32 patch__itlbmiss_exit_1, patch__itlbmiss_exit_2;
extern s32 patch__dtlbmiss_exit_1, patch__dtlbmiss_exit_2, patch__dtlbmiss_exit_3;
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 4a2e3ffdb5bb..01ed8f3c95c8 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -292,6 +292,17 @@ SystemCall:
*/
EXCEPTION(0x1000, SoftEmu, program_check_exception, EXC_XFER_STD)
+/* Called from DataStoreTLBMiss when perf TLB misses events are activated */
+#ifdef CONFIG_PERF_EVENTS
+ patch_site 0f, patch__dtlbmiss_perf
+0: lwz r10, (dtlb_miss_counter - PAGE_OFFSET)@l(0)
+ addi r10, r10, 1
+ stw r10, (dtlb_miss_counter - PAGE_OFFSET)@l(0)
+ mfspr r10, SPRN_SPRG_SCRATCH0
+ mfspr r11, SPRN_SPRG_SCRATCH1
+ rfi
+#endif
+
. = 0x1100
/*
* For the MPC8xx, this is a software tablewalk to load the instruction
@@ -405,10 +416,20 @@ InstructionTLBMiss:
#ifndef CONFIG_PIN_TLB_TEXT
ITLBMissLinear:
mtcr r11
+#ifdef CONFIG_STRICT_KERNEL_RWX
+ patch_site 0f, patch__itlbmiss_linmem_top8
+
+ mfspr r10, SPRN_SRR0
+0: subis r11, r10, (PAGE_OFFSET - 0x80000000)@ha
+ rlwinm r11, r11, 4, MI_PS8MEG ^ MI_PS512K
+ ori r11, r11, MI_PS512K | MI_SVALID
+ rlwinm r10, r10, 0, 0x0ff80000 /* 8xx supports max 256Mb RAM */
+#else
/* Set 8M byte page and mark it valid */
li r11, MI_PS8MEG | MI_SVALID
- mtspr SPRN_MI_TWC, r11
rlwinm r10, r10, 20, 0x0f800000 /* 8xx supports max 256Mb RAM */
+#endif
+ mtspr SPRN_MI_TWC, r11
ori r10, r10, 0xf0 | MI_SPS16K | _PAGE_SH | _PAGE_DIRTY | \
_PAGE_PRESENT
mtspr SPRN_MI_RPN, r10 /* Update TLB entry */
@@ -494,16 +515,6 @@ DataStoreTLBMiss:
rfi
patch_site 0b, patch__dtlbmiss_exit_1
-#ifdef CONFIG_PERF_EVENTS
- patch_site 0f, patch__dtlbmiss_perf
-0: lwz r10, (dtlb_miss_counter - PAGE_OFFSET)@l(0)
- addi r10, r10, 1
- stw r10, (dtlb_miss_counter - PAGE_OFFSET)@l(0)
- mfspr r10, SPRN_SPRG_SCRATCH0
- mfspr r11, SPRN_SPRG_SCRATCH1
- rfi
-#endif
-
DTLBMissIMMR:
mtcr r11
/* Set 512k byte guarded page and mark it valid */
@@ -525,10 +536,29 @@ DTLBMissIMMR:
DTLBMissLinear:
mtcr r11
+ rlwinm r10, r10, 20, 0x0f800000 /* 8xx supports max 256Mb RAM */
+#ifdef CONFIG_STRICT_KERNEL_RWX
+ patch_site 0f, patch__dtlbmiss_romem_top8
+
+0: subis r11, r10, (PAGE_OFFSET - 0x80000000)@ha
+ rlwinm r11, r11, 0, 0xff800000
+ neg r10, r11
+ or r11, r11, r10
+ rlwinm r11, r11, 4, MI_PS8MEG ^ MI_PS512K
+ ori r11, r11, MI_PS512K | MI_SVALID
+ mfspr r10, SPRN_MD_EPN
+ rlwinm r10, r10, 0, 0x0ff80000 /* 8xx supports max 256Mb RAM */
+#else
/* Set 8M byte page and mark it valid */
li r11, MD_PS8MEG | MD_SVALID
+#endif
mtspr SPRN_MD_TWC, r11
- rlwinm r10, r10, 20, 0x0f800000 /* 8xx supports max 256Mb RAM */
+#ifdef CONFIG_STRICT_KERNEL_RWX
+ patch_site 0f, patch__dtlbmiss_romem_top
+
+0: subis r11, r10, 0
+ rlwimi r10, r11, 11, _PAGE_RO
+#endif
ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_SH | _PAGE_DIRTY | \
_PAGE_PRESENT
mtspr SPRN_MD_RPN, r10 /* Update TLB entry */
diff --git a/arch/powerpc/mm/8xx_mmu.c b/arch/powerpc/mm/8xx_mmu.c
index 46bc26ef71e9..62d4e6d76cd7 100644
--- a/arch/powerpc/mm/8xx_mmu.c
+++ b/arch/powerpc/mm/8xx_mmu.c
@@ -94,11 +94,20 @@ static void __init mmu_mapin_immr(void)
map_kernel_page(v + offset, p + offset, PAGE_KERNEL_NCG);
}
-static void __init mmu_patch_cmp_limit(s32 *site, unsigned long mapped)
+static void mmu_patch_cmp_limit(s32 *site, unsigned long mapped)
{
modify_instruction_site(site, 0xffff, (unsigned long)__va(mapped) >> 16);
}
+static void mmu_patch_addis(s32 *site, long simm)
+{
+ unsigned int instr = *(unsigned int *)patch_site_addr(site);
+
+ instr &= 0xffff0000;
+ instr |= ((unsigned long)simm) >> 16;
+ patch_instruction_site(site, instr);
+}
+
unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
{
unsigned long mapped;
@@ -135,6 +144,26 @@ unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
return mapped;
}
+void mmu_mark_initmem_nx(void)
+{
+ if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX) && CONFIG_ETEXT_SHIFT < 23)
+ mmu_patch_addis(&patch__itlbmiss_linmem_top8,
+ -((long)_etext & ~(LARGE_PAGE_SIZE_8M - 1)));
+ if (!IS_ENABLED(CONFIG_PIN_TLB_TEXT))
+ mmu_patch_cmp_limit(&patch__itlbmiss_linmem_top, __pa(_etext));
+}
+
+#ifdef CONFIG_STRICT_KERNEL_RWX
+void mmu_mark_rodata_ro(void)
+{
+ if (CONFIG_DATA_SHIFT < 23)
+ mmu_patch_addis(&patch__dtlbmiss_romem_top8,
+ -__pa(((unsigned long)_sinittext) &
+ ~(LARGE_PAGE_SIZE_8M - 1)));
+ mmu_patch_addis(&patch__dtlbmiss_romem_top, -__pa(_sinittext));
+}
+#endif
+
void __init setup_initial_memory_limit(phys_addr_t first_memblock_base,
phys_addr_t first_memblock_size)
{
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index bc28995a37ea..41a3513cadc9 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -108,7 +108,7 @@ static void __init MMU_setup(void)
__map_without_bats = 1;
__map_without_ltlbs = 1;
}
- if (strict_kernel_rwx_enabled())
+ if (strict_kernel_rwx_enabled() && !IS_ENABLED(CONFIG_PPC_8xx))
__map_without_ltlbs = 1;
}
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index 98fc94affc29..74ff61dabcb1 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -166,7 +166,7 @@ static inline phys_addr_t v_block_mapped(unsigned long va) { return 0; }
static inline unsigned long p_block_mapped(phys_addr_t pa) { return 0; }
#endif
-#if defined(CONFIG_PPC_BOOK3S_32)
+#if defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_PPC_8xx)
void mmu_mark_initmem_nx(void);
void mmu_mark_rodata_ro(void);
#else
--
2.13.3
^ permalink raw reply related
* [PATCH v3 16/16] powerpc/kconfig: make _etext and data areas alignment configurable on 8xx
From: Christophe Leroy @ 2019-02-20 17:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
j.neuschaefer
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1550648295.git.christophe.leroy@c-s.fr>
On 8xx, large pages (512kb or 8M) are used to map kernel linear
memory. Aligning to 8M reduces TLB misses as only 8M pages are used
in that case. We make 8M the default for data.
This patchs allows the user to do it via Kconfig.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 18 +++++++++++++++---
arch/powerpc/kernel/head_8xx.S | 4 ++--
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index c4d6c97d7699..cf30a8f522b9 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -726,7 +726,8 @@ config THREAD_SHIFT
want. Only change this if you know what you are doing.
config ETEXT_SHIFT_BOOL
- bool "Set custom etext alignment" if STRICT_KERNEL_RWX && PPC_BOOK3S_32
+ bool "Set custom etext alignment" if STRICT_KERNEL_RWX && \
+ (PPC_BOOK3S_32 || PPC_8xx)
depends on ADVANCED_OPTIONS
help
This option allows you to set the kernel end of text alignment. When
@@ -738,6 +739,7 @@ config ETEXT_SHIFT_BOOL
config ETEXT_SHIFT
int "_etext shift" if ETEXT_SHIFT_BOOL
range 17 28 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
+ range 19 23 if STRICT_KERNEL_RWX && PPC_8xx
default 17 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
default 19 if STRICT_KERNEL_RWX && PPC_8xx
default PPC_PAGE_SHIFT
@@ -745,8 +747,13 @@ config ETEXT_SHIFT
On Book3S 32 (603+), IBATs are used to map kernel text.
Smaller is the alignment, greater is the number of necessary IBATs.
+ On 8xx, large pages (512kb or 8M) are used to map kernel linear
+ memory. Aligning to 8M reduces TLB misses as only 8M pages are used
+ in that case.
+
config DATA_SHIFT_BOOL
- bool "Set custom data alignment" if STRICT_KERNEL_RWX && PPC_BOOK3S_32
+ bool "Set custom data alignment" if STRICT_KERNEL_RWX && \
+ (PPC_BOOK3S_32 || PPC_8xx)
depends on ADVANCED_OPTIONS
help
This option allows you to set the kernel data alignment. When
@@ -759,13 +766,18 @@ config DATA_SHIFT
int "Data shift" if DATA_SHIFT_BOOL
default 24 if STRICT_KERNEL_RWX && PPC64
range 17 28 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
+ range 19 23 if STRICT_KERNEL_RWX && PPC_8xx
default 22 if STRICT_KERNEL_RWX && PPC_BOOK3S_32
- default 19 if STRICT_KERNEL_RWX && PPC_8xx
+ default 23 if STRICT_KERNEL_RWX && PPC_8xx
default PPC_PAGE_SHIFT
help
On Book3S 32 (603+), DBATs are used to map kernel text and rodata RO.
Smaller is the alignment, greater is the number of necessary DBATs.
+ On 8xx, large pages (512kb or 8M) are used to map kernel linear
+ memory. Aligning to 8M reduces TLB misses as only 8M pages are used
+ in that case.
+
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
range 8 9 if PPC64 && PPC_64K_PAGES
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 01ed8f3c95c8..63f1b7eec3f0 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -416,7 +416,7 @@ InstructionTLBMiss:
#ifndef CONFIG_PIN_TLB_TEXT
ITLBMissLinear:
mtcr r11
-#ifdef CONFIG_STRICT_KERNEL_RWX
+#if defined(CONFIG_STRICT_KERNEL_RWX) && CONFIG_ETEXT_SHIFT < 23
patch_site 0f, patch__itlbmiss_linmem_top8
mfspr r10, SPRN_SRR0
@@ -537,7 +537,7 @@ DTLBMissIMMR:
DTLBMissLinear:
mtcr r11
rlwinm r10, r10, 20, 0x0f800000 /* 8xx supports max 256Mb RAM */
-#ifdef CONFIG_STRICT_KERNEL_RWX
+#if defined(CONFIG_STRICT_KERNEL_RWX) && CONFIG_DATA_SHIFT < 23
patch_site 0f, patch__dtlbmiss_romem_top8
0: subis r11, r10, (PAGE_OFFSET - 0x80000000)@ha
--
2.13.3
^ permalink raw reply related
* [PATCH] powerpc/hugetlb: Don't do runtime allocation of 16G pages in LPAR configuration
From: Aneesh Kumar K.V @ 2019-02-20 17:33 UTC (permalink / raw)
To: npiggin, benh, paulus, mpe; +Cc: Aneesh Kumar K.V, linuxppc-dev
We added runtime allocation of 16G pages in
commit 4ae279c2c96a ("powerpc/mm/hugetlb: Allow runtime allocation of 16G.")
That was done to enable 16G allocation on PowerNV and KVM config. In case of KVM
config, we mostly would have the entire guest RAM backed by 16G hugetlb pages for
this to work. PAPR do support partial backing of guest RAM with hugepages via
ibm,expected#pages node of memory node in the device tree. This means rest of the
guest RAM won't be backed by 16G contiguous pages in the host and hence a hash page
table insertion can fail in such case.
An example error message will look like
hash-mmu: mm: Hashing failure ! EA=0x7efc00000000 access=0x8000000000000006 current=readback
hash-mmu: trap=0x300 vsid=0x67af789 ssize=1 base psize=14 psize 14 pte=0xc000000400000386
readback[12260]: unhandled signal 7 at 00007efc00000000 nip 00000000100012d0 lr 000000001000127c code 2
This patch address that by preventing runtime allocation of 16G hugepages in
LPAR config. To allocate 16G hugetlb one need to kernel command line
hugepagesz=16G hugepages=<number of 16G pages>
With radix translation mode we don't run into this issue.
Fixes: 4ae279c2c96a ("powerpc/mm/hugetlb: Allow runtime allocation of 16G.")
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/hugetlb.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/powerpc/include/asm/book3s/64/hugetlb.h b/arch/powerpc/include/asm/book3s/64/hugetlb.h
index 5b0177733994..cd3f2ae0e1e4 100644
--- a/arch/powerpc/include/asm/book3s/64/hugetlb.h
+++ b/arch/powerpc/include/asm/book3s/64/hugetlb.h
@@ -35,6 +35,13 @@ static inline int hstate_get_psize(struct hstate *hstate)
#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
static inline bool gigantic_page_supported(void)
{
+ /*
+ * We used gigantic page reservation with hypervisor assist in some case.
+ * We cannot use runtime allocation of gigantic pages in those platforms
+ * This is hash translation mode LPARs.
+ */
+ if (firmware_has_feature(FW_FEATURE_LPAR) && !radix_enabled())
+ return false;
return true;
}
#endif
--
2.20.1
^ permalink raw reply related
* Re: [PATCH 02/10] powerpc/603: Store PGDIR physical address in a SPRG
From: Christophe Leroy @ 2019-02-20 17:39 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
joakim.tjernlund
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <a805b78bc4c7c24ee061d1578e7ff7bb2746e54a.1548419273.git.christophe.leroy@c-s.fr>
Le 25/01/2019 à 13:34, Christophe Leroy a écrit :
> Use SPRN_SPRG5 to store the current thread PGDIR and
> avoid reading thread_struct->pgdir at every TLB miss.
I'll send out v2 with an additional patch getting rid of SPRN_SPRG_RTAS
hence freeing SPRN_SPRG2 which I will use here instead of SPRN_SPRG5 so
that all 6xx will benefit.
Christophe
>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
> ---
> arch/powerpc/include/asm/reg.h | 1 +
> arch/powerpc/kernel/cpu_setup_6xx.S | 4 ++++
> arch/powerpc/kernel/head_32.S | 28 ++++++++++++++++------------
> 3 files changed, 21 insertions(+), 12 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
> index 1c98ef1f2d5b..ba0ab1a1431b 100644
> --- a/arch/powerpc/include/asm/reg.h
> +++ b/arch/powerpc/include/asm/reg.h
> @@ -1169,6 +1169,7 @@
> #define SPRN_SPRG_SCRATCH1 SPRN_SPRG1
> #define SPRN_SPRG_RTAS SPRN_SPRG2
> #define SPRN_SPRG_603_LRU SPRN_SPRG4
> +#define SPRN_SPRG_603_PGDIR SPRN_SPRG5
> #endif
>
> #ifdef CONFIG_40x
> diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S
> index 8c069e96c478..4c91d1f640fe 100644
> --- a/arch/powerpc/kernel/cpu_setup_6xx.S
> +++ b/arch/powerpc/kernel/cpu_setup_6xx.S
> @@ -24,6 +24,10 @@ BEGIN_MMU_FTR_SECTION
> li r10,0
> mtspr SPRN_SPRG_603_LRU,r10 /* init SW LRU tracking */
> END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
> + lis r10, (swapper_pg_dir - PAGE_OFFSET)@h
> + ori r10, r10, (swapper_pg_dir - PAGE_OFFSET)@l
> + mtspr SPRN_SPRG_603_PGDIR, r10
> +
> BEGIN_FTR_SECTION
> bl __init_fpu_registers
> END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE)
> diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
> index c2f564690778..dbd15e03952a 100644
> --- a/arch/powerpc/kernel/head_32.S
> +++ b/arch/powerpc/kernel/head_32.S
> @@ -502,16 +502,15 @@ InstructionTLBMiss:
> mfspr r3,SPRN_IMISS
> lis r1,PAGE_OFFSET@h /* check if kernel address */
> cmplw 0,r1,r3
> - mfspr r2,SPRN_SPRG_THREAD
> + mfspr r2, SPRN_SPRG_603_PGDIR
> li r1,_PAGE_USER|_PAGE_PRESENT|_PAGE_EXEC /* low addresses tested as user */
> - lwz r2,PGDIR(r2)
> bge- 112f
> mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */
> rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */
> lis r2,swapper_pg_dir@ha /* if kernel address, use */
> addi r2,r2,swapper_pg_dir@l /* kernel page table */
> -112: tophys(r2,r2)
> - rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */
> + tophys(r2,r2)
> +112: rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */
> lwz r2,0(r2) /* get pmd entry */
> rlwinm. r2,r2,0,0,19 /* extract address of pte page */
> beq- InstructionAddressInvalid /* return if no mapping */
> @@ -576,16 +575,15 @@ DataLoadTLBMiss:
> mfspr r3,SPRN_DMISS
> lis r1,PAGE_OFFSET@h /* check if kernel address */
> cmplw 0,r1,r3
> - mfspr r2,SPRN_SPRG_THREAD
> + mfspr r2, SPRN_SPRG_603_PGDIR
> li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
> - lwz r2,PGDIR(r2)
> bge- 112f
> mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */
> rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */
> lis r2,swapper_pg_dir@ha /* if kernel address, use */
> addi r2,r2,swapper_pg_dir@l /* kernel page table */
> -112: tophys(r2,r2)
> - rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */
> + tophys(r2,r2)
> +112: rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */
> lwz r2,0(r2) /* get pmd entry */
> rlwinm. r2,r2,0,0,19 /* extract address of pte page */
> beq- DataAddressInvalid /* return if no mapping */
> @@ -660,16 +658,15 @@ DataStoreTLBMiss:
> mfspr r3,SPRN_DMISS
> lis r1,PAGE_OFFSET@h /* check if kernel address */
> cmplw 0,r1,r3
> - mfspr r2,SPRN_SPRG_THREAD
> + mfspr r2, SPRN_SPRG_603_PGDIR
> li r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */
> - lwz r2,PGDIR(r2)
> bge- 112f
> mfspr r2,SPRN_SRR1 /* and MSR_PR bit from SRR1 */
> rlwimi r1,r2,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */
> lis r2,swapper_pg_dir@ha /* if kernel address, use */
> addi r2,r2,swapper_pg_dir@l /* kernel page table */
> -112: tophys(r2,r2)
> - rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */
> + tophys(r2,r2)
> +112: rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */
> lwz r2,0(r2) /* get pmd entry */
> rlwinm. r2,r2,0,0,19 /* extract address of pte page */
> beq- DataAddressInvalid /* return if no mapping */
> @@ -1030,6 +1027,13 @@ _ENTRY(switch_mmu_context)
> lis r5, abatron_pteptrs@ha
> stw r4, abatron_pteptrs@l + 0x4(r5)
> #endif
> +BEGIN_MMU_FTR_SECTION
> +#ifndef CONFIG_BDI_SWITCH
> + lwz r4, MM_PGD(r4)
> +#endif
> + tophys(r4, r4)
> + mtspr SPRN_SPRG_603_PGDIR, r4
> +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_HPTE_TABLE)
> li r4,0
> isync
> 3:
>
^ permalink raw reply
* [powerpc:next-test 77/77] arch/powerpc/kernel/exceptions-64s.S:625: Error: Fixed entry overflow
From: kbuild test robot @ 2019-02-20 17:40 UTC (permalink / raw)
To: Nicholas Piggin; +Cc: linuxppc-dev, kbuild-all
[-- Attachment #1: Type: text/plain, Size: 2294 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next-test
head: 9a065d2e3633d2f443ec01427265098ebe3a0e1f
commit: 9a065d2e3633d2f443ec01427265098ebe3a0e1f [77/77] powerpc/64s: Fix data interrupts vs d-side MCE reentrancy
config: powerpc-defconfig (attached as .config)
compiler: powerpc64-linux-gnu-gcc (Debian 8.2.0-11) 8.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout 9a065d2e3633d2f443ec01427265098ebe3a0e1f
# save the attached .config to linux build tree
GCC_VERSION=8.2.0 make.cross ARCH=powerpc
All errors (new ones prefixed by >>):
arch/powerpc/kernel/exceptions-64s.S: Assembler messages:
>> arch/powerpc/kernel/exceptions-64s.S:625: Error: Fixed entry overflow
arch/powerpc/kernel/exceptions-64s.S:625: Fatal error: .abort detected. Abandoning ship.
vim +625 arch/powerpc/kernel/exceptions-64s.S
80795e6cb Nicholas Piggin 2016-09-21 616
0ebc4cdaa Benjamin Herrenschmidt 2009-06-02 617
1a6822d19 Nicholas Piggin 2016-12-06 618 EXC_REAL_BEGIN(data_access_slb, 0x380, 0x80)
9fcdbda07 Nicholas Piggin 2019-01-22 619 SET_SCRATCH0(r13) /* save r13 */
9fcdbda07 Nicholas Piggin 2019-01-22 620 EXCEPTION_PROLOG_0(PACA_EXSLB)
9fcdbda07 Nicholas Piggin 2019-01-22 621 EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380)
9a065d2e3 Nicholas Piggin 2019-01-22 622 mfspr r10,SPRN_DAR
9a065d2e3 Nicholas Piggin 2019-01-22 623 std r10,PACA_EXGEN+EX_DAR(r13)
9fcdbda07 Nicholas Piggin 2019-01-22 624 EXCEPTION_PROLOG_2(data_access_slb_common, EXC_STD)
1a6822d19 Nicholas Piggin 2016-12-06 @625 EXC_REAL_END(data_access_slb, 0x380, 0x80)
0ebc4cdaa Benjamin Herrenschmidt 2009-06-02 626
:::::: The code at line 625 was first introduced by commit
:::::: 1a6822d194c3f627eeb6aaca6688a5d0a444663e powerpc/64s: Use (start, size) rather than (start, end) for exception handlers
:::::: TO: Nicholas Piggin <npiggin@gmail.com>
:::::: CC: Michael Ellerman <mpe@ellerman.id.au>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 24045 bytes --]
^ permalink raw reply
* Re: [PATCH v6 4/6] powerpc/32: Add KASAN support
From: Christophe Leroy @ 2019-02-20 17:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Nicholas Piggin, Aneesh Kumar K.V, Andrey Ryabinin,
Alexander Potapenko, Dmitry Vyukov, Daniel Axtens
Cc: linux-mm, linuxppc-dev, linux-kernel, kasan-dev
In-Reply-To: <e51647fdac60d523892cd3eab3217c3a4d8d356b.1550596242.git.christophe.leroy@c-s.fr>
Le 19/02/2019 à 18:23, Christophe Leroy a écrit :
> This patch adds KASAN support for PPC32.
>
> The KASAN shadow area is located between the vmalloc area and the
> fixmap area.
>
> KASAN_SHADOW_OFFSET is calculated in asm/kasan.h and extracted
> by Makefile prepare rule via asm-offsets.h
>
> For modules, the shadow area is allocated at module_alloc().
>
> Note that on book3s it will only work on the 603 because the other
> ones use hash table and can therefore not share a single PTE table
> covering the entire early KASAN shadow area.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
> ---
> arch/powerpc/Kconfig | 1 +
> arch/powerpc/Makefile | 7 ++
> arch/powerpc/include/asm/book3s/32/pgtable.h | 2 +
> arch/powerpc/include/asm/highmem.h | 10 +-
> arch/powerpc/include/asm/kasan.h | 23 ++++
> arch/powerpc/include/asm/nohash/32/pgtable.h | 2 +
> arch/powerpc/include/asm/setup.h | 5 +
> arch/powerpc/kernel/Makefile | 9 +-
> arch/powerpc/kernel/asm-offsets.c | 4 +
> arch/powerpc/kernel/head_32.S | 3 +
> arch/powerpc/kernel/head_40x.S | 3 +
> arch/powerpc/kernel/head_44x.S | 3 +
> arch/powerpc/kernel/head_8xx.S | 3 +
> arch/powerpc/kernel/head_fsl_booke.S | 3 +
> arch/powerpc/kernel/setup-common.c | 2 +
> arch/powerpc/lib/Makefile | 8 ++
> arch/powerpc/mm/Makefile | 1 +
> arch/powerpc/mm/kasan/Makefile | 5 +
> arch/powerpc/mm/kasan/kasan_init_32.c | 147 ++++++++++++++++++++++++++
> arch/powerpc/mm/mem.c | 4 +
> arch/powerpc/mm/ptdump/dump_linuxpagetables.c | 8 ++
@Daniel (and others), note that to apply properly, this requires my
other patch which moves the dumping files in a arch/powerpc/mm/ptdump/
subdir.
Christophe
> arch/powerpc/purgatory/Makefile | 3 +
> arch/powerpc/xmon/Makefile | 1 +
> 23 files changed, 253 insertions(+), 4 deletions(-)
> create mode 100644 arch/powerpc/mm/kasan/Makefile
> create mode 100644 arch/powerpc/mm/kasan/kasan_init_32.c
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 08908219fba9..850b06def84f 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -175,6 +175,7 @@ config PPC
> select GENERIC_TIME_VSYSCALL
> select HAVE_ARCH_AUDITSYSCALL
> select HAVE_ARCH_JUMP_LABEL
> + select HAVE_ARCH_KASAN if PPC32
> select HAVE_ARCH_KGDB
> select HAVE_ARCH_MMAP_RND_BITS
> select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
> diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
> index ac033341ed55..f0738099e31e 100644
> --- a/arch/powerpc/Makefile
> +++ b/arch/powerpc/Makefile
> @@ -427,6 +427,13 @@ else
> endif
> endif
>
> +ifdef CONFIG_KASAN
> +prepare: kasan_prepare
> +
> +kasan_prepare: prepare0
> + $(eval KASAN_SHADOW_OFFSET = $(shell awk '{if ($$2 == "KASAN_SHADOW_OFFSET") print $$3;}' include/generated/asm-offsets.h))
> +endif
> +
> # Check toolchain versions:
> # - gcc-4.6 is the minimum kernel-wide version so nothing required.
> checkbin:
> diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
> index 49d76adb9bc5..4543016f80ca 100644
> --- a/arch/powerpc/include/asm/book3s/32/pgtable.h
> +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
> @@ -141,6 +141,8 @@ static inline bool pte_user(pte_t pte)
> */
> #ifdef CONFIG_HIGHMEM
> #define KVIRT_TOP PKMAP_BASE
> +#elif defined(CONFIG_KASAN)
> +#define KVIRT_TOP KASAN_SHADOW_START
> #else
> #define KVIRT_TOP (0xfe000000UL) /* for now, could be FIXMAP_BASE ? */
> #endif
> diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h
> index a4b65b186ec6..483b90025bef 100644
> --- a/arch/powerpc/include/asm/highmem.h
> +++ b/arch/powerpc/include/asm/highmem.h
> @@ -28,6 +28,7 @@
> #include <asm/cacheflush.h>
> #include <asm/page.h>
> #include <asm/fixmap.h>
> +#include <asm/kasan.h>
>
> extern pte_t *kmap_pte;
> extern pgprot_t kmap_prot;
> @@ -50,10 +51,15 @@ extern pte_t *pkmap_page_table;
> #define PKMAP_ORDER 9
> #endif
> #define LAST_PKMAP (1 << PKMAP_ORDER)
> +#ifdef CONFIG_KASAN
> +#define PKMAP_TOP KASAN_SHADOW_START
> +#else
> +#define PKMAP_TOP FIXADDR_START
> +#endif
> #ifndef CONFIG_PPC_4K_PAGES
> -#define PKMAP_BASE (FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1))
> +#define PKMAP_BASE (PKMAP_TOP - PAGE_SIZE*(LAST_PKMAP + 1))
> #else
> -#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK)
> +#define PKMAP_BASE ((PKMAP_TOP - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK)
> #endif
> #define LAST_PKMAP_MASK (LAST_PKMAP-1)
> #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
> diff --git a/arch/powerpc/include/asm/kasan.h b/arch/powerpc/include/asm/kasan.h
> index 2efd0e42cfc9..0bc9148f5d87 100644
> --- a/arch/powerpc/include/asm/kasan.h
> +++ b/arch/powerpc/include/asm/kasan.h
> @@ -12,4 +12,27 @@
> #define EXPORT_SYMBOL_KASAN(fn) EXPORT_SYMBOL(fn)
> #endif
>
> +#ifndef __ASSEMBLY__
> +
> +#include <asm/page.h>
> +#include <asm/pgtable-types.h>
> +
> +#define KASAN_SHADOW_SCALE_SHIFT 3
> +
> +#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_START - \
> + (PAGE_OFFSET >> KASAN_SHADOW_SCALE_SHIFT))
> +
> +#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)
> +
> +#include <asm/fixmap.h>
> +
> +#define KASAN_SHADOW_START (ALIGN_DOWN(FIXADDR_START - KASAN_SHADOW_SIZE, \
> + PGDIR_SIZE))
> +
> +#define KASAN_SHADOW_SIZE ((~0UL - PAGE_OFFSET + 1) >> KASAN_SHADOW_SCALE_SHIFT)
> +
> +void kasan_early_init(void);
> +void kasan_init(void);
> +
> +#endif /* __ASSEMBLY */
> #endif
> diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
> index bed433358260..b3b52f02be1a 100644
> --- a/arch/powerpc/include/asm/nohash/32/pgtable.h
> +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
> @@ -71,6 +71,8 @@ extern int icache_44x_need_flush;
> */
> #ifdef CONFIG_HIGHMEM
> #define KVIRT_TOP PKMAP_BASE
> +#elif defined(CONFIG_KASAN)
> +#define KVIRT_TOP KASAN_SHADOW_START
> #else
> #define KVIRT_TOP (0xfe000000UL) /* for now, could be FIXMAP_BASE ? */
> #endif
> diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h
> index 65676e2325b8..da7768aa996a 100644
> --- a/arch/powerpc/include/asm/setup.h
> +++ b/arch/powerpc/include/asm/setup.h
> @@ -74,6 +74,11 @@ static inline void setup_spectre_v2(void) {};
> #endif
> void do_btb_flush_fixups(void);
>
> +#ifndef CONFIG_KASAN
> +static inline void kasan_early_init(void) { }
> +static inline void kasan_init(void) { }
> +#endif
> +
> #endif /* !__ASSEMBLY__ */
>
> #endif /* _ASM_POWERPC_SETUP_H */
> diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
> index 879b36602748..fc4c42262694 100644
> --- a/arch/powerpc/kernel/Makefile
> +++ b/arch/powerpc/kernel/Makefile
> @@ -16,8 +16,9 @@ CFLAGS_prom_init.o += -fPIC
> CFLAGS_btext.o += -fPIC
> endif
>
> -CFLAGS_cputable.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
> -CFLAGS_prom_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
> +CFLAGS_early_32.o += -DDISABLE_BRANCH_PROFILING
> +CFLAGS_cputable.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) -DDISABLE_BRANCH_PROFILING
> +CFLAGS_prom_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) -DDISABLE_BRANCH_PROFILING
> CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
> CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
>
> @@ -31,6 +32,10 @@ CFLAGS_REMOVE_btext.o = $(CC_FLAGS_FTRACE)
> CFLAGS_REMOVE_prom.o = $(CC_FLAGS_FTRACE)
> endif
>
> +KASAN_SANITIZE_early_32.o := n
> +KASAN_SANITIZE_cputable.o := n
> +KASAN_SANITIZE_prom_init.o := n
> +
> obj-y := cputable.o ptrace.o syscalls.o \
> irq.o align.o signal_32.o pmc.o vdso.o \
> process.o systbl.o idle.o \
> diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
> index 9ffc72ded73a..846fb30b1190 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -783,5 +783,9 @@ int main(void)
> DEFINE(VIRT_IMMR_BASE, (u64)__fix_to_virt(FIX_IMMR_BASE));
> #endif
>
> +#ifdef CONFIG_KASAN
> + DEFINE(KASAN_SHADOW_OFFSET, KASAN_SHADOW_OFFSET);
> +#endif
> +
> return 0;
> }
> diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
> index 05b08db3901d..0ec9dec06bc2 100644
> --- a/arch/powerpc/kernel/head_32.S
> +++ b/arch/powerpc/kernel/head_32.S
> @@ -962,6 +962,9 @@ start_here:
> * Do early platform-specific initialization,
> * and set up the MMU.
> */
> +#ifdef CONFIG_KASAN
> + bl kasan_early_init
> +#endif
> li r3,0
> mr r4,r31
> bl machine_init
> diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
> index b19d78410511..5d6ff8fa7e2b 100644
> --- a/arch/powerpc/kernel/head_40x.S
> +++ b/arch/powerpc/kernel/head_40x.S
> @@ -848,6 +848,9 @@ start_here:
> /*
> * Decide what sort of machine this is and initialize the MMU.
> */
> +#ifdef CONFIG_KASAN
> + bl kasan_early_init
> +#endif
> li r3,0
> mr r4,r31
> bl machine_init
> diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
> index bf23c19c92d6..7ca14dff6192 100644
> --- a/arch/powerpc/kernel/head_44x.S
> +++ b/arch/powerpc/kernel/head_44x.S
> @@ -203,6 +203,9 @@ _ENTRY(_start);
> /*
> * Decide what sort of machine this is and initialize the MMU.
> */
> +#ifdef CONFIG_KASAN
> + bl kasan_early_init
> +#endif
> li r3,0
> mr r4,r31
> bl machine_init
> diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
> index fe2857ef0309..88f0cb34cef4 100644
> --- a/arch/powerpc/kernel/head_8xx.S
> +++ b/arch/powerpc/kernel/head_8xx.S
> @@ -823,6 +823,9 @@ start_here:
> /*
> * Decide what sort of machine this is and initialize the MMU.
> */
> +#ifdef CONFIG_KASAN
> + bl kasan_early_init
> +#endif
> li r3,0
> mr r4,r31
> bl machine_init
> diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
> index 2386ce2a9c6e..4f4585a68850 100644
> --- a/arch/powerpc/kernel/head_fsl_booke.S
> +++ b/arch/powerpc/kernel/head_fsl_booke.S
> @@ -274,6 +274,9 @@ set_ivor:
> /*
> * Decide what sort of machine this is and initialize the MMU.
> */
> +#ifdef CONFIG_KASAN
> + bl kasan_early_init
> +#endif
> mr r3,r30
> mr r4,r31
> bl machine_init
> diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
> index ca00fbb97cf8..16ff1ea66805 100644
> --- a/arch/powerpc/kernel/setup-common.c
> +++ b/arch/powerpc/kernel/setup-common.c
> @@ -978,6 +978,8 @@ void __init setup_arch(char **cmdline_p)
>
> paging_init();
>
> + kasan_init();
> +
> /* Initialize the MMU context management stuff. */
> mmu_context_init();
>
> diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
> index ee08a7e1bcdf..7efbd5122c74 100644
> --- a/arch/powerpc/lib/Makefile
> +++ b/arch/powerpc/lib/Makefile
> @@ -8,6 +8,14 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
> CFLAGS_REMOVE_code-patching.o = $(CC_FLAGS_FTRACE)
> CFLAGS_REMOVE_feature-fixups.o = $(CC_FLAGS_FTRACE)
>
> +KASAN_SANITIZE_code-patching.o := n
> +KASAN_SANITIZE_feature-fixups.o := n
> +
> +ifdef CONFIG_KASAN
> +CFLAGS_code-patching.o += -DDISABLE_BRANCH_PROFILING
> +CFLAGS_feature-fixups.o += -DDISABLE_BRANCH_PROFILING
> +endif
> +
> obj-y += alloc.o code-patching.o feature-fixups.o
>
> ifndef CONFIG_KASAN
> diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
> index ee1efa3b3382..292b96ce1efc 100644
> --- a/arch/powerpc/mm/Makefile
> +++ b/arch/powerpc/mm/Makefile
> @@ -47,3 +47,4 @@ obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o
> obj-$(CONFIG_SPAPR_TCE_IOMMU) += mmu_context_iommu.o
> obj-$(CONFIG_PPC_PTDUMP) += ptdump/
> obj-$(CONFIG_PPC_MEM_KEYS) += pkeys.o
> +obj-$(CONFIG_KASAN) += kasan/
> diff --git a/arch/powerpc/mm/kasan/Makefile b/arch/powerpc/mm/kasan/Makefile
> new file mode 100644
> index 000000000000..6577897673dd
> --- /dev/null
> +++ b/arch/powerpc/mm/kasan/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +KASAN_SANITIZE := n
> +
> +obj-$(CONFIG_PPC32) += kasan_init_32.o
> diff --git a/arch/powerpc/mm/kasan/kasan_init_32.c b/arch/powerpc/mm/kasan/kasan_init_32.c
> new file mode 100644
> index 000000000000..495c908d6ee6
> --- /dev/null
> +++ b/arch/powerpc/mm/kasan/kasan_init_32.c
> @@ -0,0 +1,147 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#define DISABLE_BRANCH_PROFILING
> +
> +#include <linux/kasan.h>
> +#include <linux/printk.h>
> +#include <linux/memblock.h>
> +#include <linux/sched/task.h>
> +#include <linux/vmalloc.h>
> +#include <asm/pgalloc.h>
> +
> +void __init kasan_early_init(void)
> +{
> + unsigned long addr = KASAN_SHADOW_START;
> + unsigned long end = KASAN_SHADOW_END;
> + unsigned long next;
> + pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(addr), addr), addr);
> + int i;
> + phys_addr_t pa = __pa(kasan_early_shadow_page);
> +
> + BUILD_BUG_ON(KASAN_SHADOW_START & ~PGDIR_MASK);
> +
> + if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE))
> + panic("KASAN not supported with Hash MMU\n");
> +
> + for (i = 0; i < PTRS_PER_PTE; i++)
> + __set_pte_at(&init_mm, (unsigned long)kasan_early_shadow_page,
> + kasan_early_shadow_pte + i,
> + pfn_pte(PHYS_PFN(pa), PAGE_KERNEL), 0);
> +
> + do {
> + next = pgd_addr_end(addr, end);
> + pmd_populate_kernel(&init_mm, pmd, kasan_early_shadow_pte);
> + } while (pmd++, addr = next, addr != end);
> +}
> +
> +static void __ref *kasan_get_one_page(void)
> +{
> + if (slab_is_available())
> + return (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
> +
> + return memblock_alloc(PAGE_SIZE, PAGE_SIZE);
> +}
> +
> +static int __ref kasan_init_region(void *start, size_t size)
> +{
> + void *end = start + size;
> + unsigned long k_start, k_end, k_cur, k_next;
> + pmd_t *pmd;
> + void *block = NULL;
> +
> + if (start >= end)
> + return 0;
> +
> + k_start = (unsigned long)kasan_mem_to_shadow(start);
> + k_end = (unsigned long)kasan_mem_to_shadow(end);
> + pmd = pmd_offset(pud_offset(pgd_offset_k(k_start), k_start), k_start);
> +
> + for (k_cur = k_start; k_cur != k_end; k_cur = k_next, pmd++) {
> + k_next = pgd_addr_end(k_cur, k_end);
> + if ((void *)pmd_page_vaddr(*pmd) == kasan_early_shadow_pte) {
> + pte_t *new = pte_alloc_one_kernel(&init_mm);
> +
> + if (!new)
> + return -ENOMEM;
> + memcpy(new, kasan_early_shadow_pte, PTE_TABLE_SIZE);
> + pmd_populate_kernel(&init_mm, pmd, new);
> + }
> + };
> +
> + if (!slab_is_available())
> + block = memblock_alloc(k_end - k_start, PAGE_SIZE);
> +
> + for (k_cur = k_start; k_cur < k_end; k_cur += PAGE_SIZE) {
> + void *va = block ? block + k_cur - k_start :
> + kasan_get_one_page();
> + pte_t pte = pfn_pte(PHYS_PFN(__pa(va)), PAGE_KERNEL);
> +
> + if (!va)
> + return -ENOMEM;
> +
> + pmd = pmd_offset(pud_offset(pgd_offset_k(k_cur), k_cur), k_cur);
> + pte_update(pte_offset_kernel(pmd, k_cur), ~0, pte_val(pte));
> + }
> + flush_tlb_kernel_range(k_start, k_end);
> + return 0;
> +}
> +
> +static void __init kasan_remap_early_shadow_ro(void)
> +{
> + unsigned long k_cur;
> + phys_addr_t pa = __pa(kasan_early_shadow_page);
> + int i;
> +
> + for (i = 0; i < PTRS_PER_PTE; i++)
> + ptep_set_wrprotect(&init_mm, 0, kasan_early_shadow_pte + i);
> +
> + for (k_cur = PAGE_OFFSET & PAGE_MASK; k_cur; k_cur += PAGE_SIZE) {
> + pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(k_cur), k_cur), k_cur);
> + pte_t *ptep = pte_offset_kernel(pmd, k_cur);
> +
> + if ((void *)pmd_page_vaddr(*pmd) == kasan_early_shadow_pte)
> + continue;
> + if ((pte_val(*ptep) & PAGE_MASK) != pa)
> + continue;
> +
> + ptep_set_wrprotect(&init_mm, k_cur, ptep);
> + }
> + flush_tlb_mm(&init_mm);
> +}
> +
> +void __init kasan_init(void)
> +{
> + struct memblock_region *reg;
> +
> + for_each_memblock(memory, reg) {
> + int ret = kasan_init_region(__va(reg->base), reg->size);
> +
> + if (ret)
> + panic("kasan: kasan_init_region() failed");
> + }
> +
> + kasan_remap_early_shadow_ro();
> +
> + clear_page(kasan_early_shadow_page);
> +
> + /* At this point kasan is fully initialized. Enable error messages */
> + init_task.kasan_depth = 0;
> + pr_info("KASAN init done\n");
> +}
> +
> +#ifdef CONFIG_MODULES
> +void *module_alloc(unsigned long size)
> +{
> + void *base = vmalloc_exec(size);
> +
> + if (!base)
> + return NULL;
> +
> + if (!kasan_init_region(base, size))
> + return base;
> +
> + vfree(base);
> +
> + return NULL;
> +}
> +#endif
> diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
> index 81f251fc4169..1bb055775e60 100644
> --- a/arch/powerpc/mm/mem.c
> +++ b/arch/powerpc/mm/mem.c
> @@ -336,6 +336,10 @@ void __init mem_init(void)
> pr_info(" * 0x%08lx..0x%08lx : highmem PTEs\n",
> PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP));
> #endif /* CONFIG_HIGHMEM */
> +#ifdef CONFIG_KASAN
> + pr_info(" * 0x%08lx..0x%08lx : kasan shadow mem\n",
> + KASAN_SHADOW_START, KASAN_SHADOW_END);
> +#endif
> #ifdef CONFIG_NOT_COHERENT_CACHE
> pr_info(" * 0x%08lx..0x%08lx : consistent mem\n",
> IOREMAP_TOP, IOREMAP_TOP + CONFIG_CONSISTENT_SIZE);
> diff --git a/arch/powerpc/mm/ptdump/dump_linuxpagetables.c b/arch/powerpc/mm/ptdump/dump_linuxpagetables.c
> index b0da447197d4..4a03910974e2 100644
> --- a/arch/powerpc/mm/ptdump/dump_linuxpagetables.c
> +++ b/arch/powerpc/mm/ptdump/dump_linuxpagetables.c
> @@ -94,6 +94,10 @@ static struct addr_marker address_markers[] = {
> { 0, "Consistent mem start" },
> { 0, "Consistent mem end" },
> #endif
> +#ifdef CONFIG_KASAN
> + { 0, "kasan shadow mem start" },
> + { 0, "kasan shadow mem end" },
> +#endif
> #ifdef CONFIG_HIGHMEM
> { 0, "Highmem PTEs start" },
> { 0, "Highmem PTEs end" },
> @@ -316,6 +320,10 @@ static void populate_markers(void)
> address_markers[i++].start_address = IOREMAP_TOP +
> CONFIG_CONSISTENT_SIZE;
> #endif
> +#ifdef CONFIG_KASAN
> + address_markers[i++].start_address = KASAN_SHADOW_START;
> + address_markers[i++].start_address = KASAN_SHADOW_END;
> +#endif
> #ifdef CONFIG_HIGHMEM
> address_markers[i++].start_address = PKMAP_BASE;
> address_markers[i++].start_address = PKMAP_ADDR(LAST_PKMAP);
> diff --git a/arch/powerpc/purgatory/Makefile b/arch/powerpc/purgatory/Makefile
> index 4314ba5baf43..7c6d8b14f440 100644
> --- a/arch/powerpc/purgatory/Makefile
> +++ b/arch/powerpc/purgatory/Makefile
> @@ -1,4 +1,7 @@
> # SPDX-License-Identifier: GPL-2.0
> +
> +KASAN_SANITIZE := n
> +
> targets += trampoline.o purgatory.ro kexec-purgatory.c
>
> LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined
> diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile
> index 878f9c1d3615..064f7062c0a3 100644
> --- a/arch/powerpc/xmon/Makefile
> +++ b/arch/powerpc/xmon/Makefile
> @@ -6,6 +6,7 @@ subdir-ccflags-y := $(call cc-disable-warning, builtin-requires-header)
>
> GCOV_PROFILE := n
> UBSAN_SANITIZE := n
> +KASAN_SANITIZE := n
>
> # Disable ftrace for the entire directory
> ORIG_CFLAGS := $(KBUILD_CFLAGS)
>
^ permalink raw reply
* Re: [PATCH v2] sched/topology: fix kernel crash when a CPU is hotplugged in a memoryless node
From: Laurent Vivier @ 2019-02-20 17:57 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Srikar Dronamraju, linux-kernel, Michael Bringmann, Ingo Molnar,
Suravee Suthikulpanit, Nathan Fontenot, Borislav Petkov,
linuxppc-dev, David Gibson
In-Reply-To: <20190220170841.GM32494@hirez.programming.kicks-ass.net>
On 20/02/2019 18:08, Peter Zijlstra wrote:
> On Wed, Feb 20, 2019 at 05:55:20PM +0100, Laurent Vivier wrote:
>> index 3f35ba1d8fde..372278605f0d 100644
>> --- a/kernel/sched/topology.c
>> +++ b/kernel/sched/topology.c
>> @@ -1651,6 +1651,7 @@ void sched_init_numa(void)
>> */
>> tl[i++] = (struct sched_domain_topology_level){
>> .mask = sd_numa_mask,
>> + .flags = SDTL_OVERLAP,
>
> This makes no sense what so ever. The numa identify node should not have
> overlap with other domains.
>
> Are you sure this is not because of the utterly broken powerpc nonsense
> where they move CPUs between nodes?
No, I'm not sure. This why I've Cc: powerpc folks. My conclusion is only
based on the before/after changes.
I've tested some patches from powerpc ML, but they don't fix this problem:
powerpc/numa: Perform full re-add of CPU for PRRN/VPHN topology update
powerpc/pseries: Perform full re-add of CPU for topology update
post-migration
So the only reason I can see to have a corrupted sched_group list is the
sched_domain_span() fonction doesn't return a correct cpumask for the
domain once a new CPU is added.
Thanks,
Laurent
^ permalink raw reply
* Re: [RESEND PATCH 0/7] Add FOLL_LONGTERM to GUP fast and use it
From: Ira Weiny @ 2019-02-20 18:02 UTC (permalink / raw)
To: Christoph Hellwig
Cc: linux-fbdev, Michal Hocko, kvm, linux-sh, Peter Zijlstra,
James Hogan, linux-fpga, Heiko Carstens, dri-devel, linux-mips,
linux-mm, Rich Felker, Paul Mackerras, sparclinux, ceph-devel,
devel, linux-s390, rds-devel, Yoshinori Sato, linux-rdma,
Jason Gunthorpe, Ingo Molnar, xen-devel, devel, linux-media,
John Hubbard, kvm-ppc, Borislav Petkov, Thomas Gleixner,
virtualization, linux-scsi, netdev, linux-kernel, Ralf Baechle,
Paul Burton, Martin Schwidefsky, Andrew Morton, linuxppc-dev,
David S. Miller, Kirill A. Shutemov
In-Reply-To: <20190220151930.GB11695@infradead.org>
On Wed, Feb 20, 2019 at 07:19:30AM -0800, Christoph Hellwig wrote:
> On Tue, Feb 19, 2019 at 09:30:33PM -0800, ira.weiny@intel.com wrote:
> > From: Ira Weiny <ira.weiny@intel.com>
> >
> > Resending these as I had only 1 minor comment which I believe we have covered
> > in this series. I was anticipating these going through the mm tree as they
> > depend on a cleanup patch there and the IB changes are very minor. But they
> > could just as well go through the IB tree.
> >
> > NOTE: This series depends on my clean up patch to remove the write parameter
> > from gup_fast_permitted()[1]
> >
> > HFI1, qib, and mthca, use get_user_pages_fast() due to it performance
> > advantages. These pages can be held for a significant time. But
> > get_user_pages_fast() does not protect against mapping of FS DAX pages.
>
> This I don't get - if you do lock down long term mappings performance
> of the actual get_user_pages call shouldn't matter to start with.
>
> What do I miss?
A couple of points.
First "longterm" is a relative thing and at this point is probably a misnomer.
This is really flagging a pin which is going to be given to hardware and can't
move. I've thought of a couple of alternative names but I think we have to
settle on if we are going to use FL_LAYOUT or something else to solve the
"longterm" problem. Then I think we can change the flag to a better name.
Second, It depends on how often you are registering memory. I have spoken with
some RDMA users who consider MR in the performance path... For the overall
application performance. I don't have the numbers as the tests for HFI1 were
done a long time ago. But there was a significant advantage. Some of which is
probably due to the fact that you don't have to hold mmap_sem.
Finally, architecturally I think it would be good for everyone to use *_fast.
There are patches submitted to the RDMA list which would allow the use of
*_fast (they reworking the use of mmap_sem) and as soon as they are accepted
I'll submit a patch to convert the RDMA core as well. Also to this point
others are looking to use *_fast.[2]
As an asside, Jasons pointed out in my previous submission that *_fast and
*_unlocked look very much the same. I agree and I think further cleanup will
be coming. But I'm focused on getting the final solution for DAX at the
moment.
Ira
^ permalink raw reply
* Re: [PATCH] powerpc/pseries: Fix dn reference error in dlpar_cpu_remove_by_index
From: Michael Bringmann @ 2019-02-20 20:18 UTC (permalink / raw)
To: Tyrel Datwyler, linuxppc-dev, linux-kernel
Cc: Rob Herring, Thomas Falcon, Nicholas Piggin, Paul Mackerras,
Nathan Lynch, Juliet M. Kim
In-Reply-To: <a7986146-f09d-6d40-63f9-8e7307fc2609@linux.vnet.ibm.com>
On 2/19/19 2:03 PM, Tyrel Datwyler wrote:
> On 02/19/2019 07:46 AM, Michael Bringmann wrote:
>> powerpc/pseries: Fix dn reference error in dlpar_cpu_remove_by_index()
>>
>> A reference to the device node of the CPU to be removed is released
>> upon successful removal of the associated CPU device. If the call
>> to remove the CPU device fails, dlpar_cpu_remove_by_index() still
>> frees the reference and this leads to miscomparisons and/or
>> addressing errors later on.
>>
>> This problem may be observed when trying to DLPAR 'hot-remove' a CPU
>> from a system that has only a single CPU. The operation will fail
>> because there is no other CPU to which the kernel operations may be
>> migrated, but the refcount will still be decremented.
>>
>> Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
>>
>>
>> diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
>> index 97feb6e..9537bb9 100644
>> --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
>> +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
>> @@ -635,7 +635,8 @@ static int dlpar_cpu_remove_by_index(u32 drc_index)
>> }
>>
>> rc = dlpar_cpu_remove(dn, drc_index);
>> - of_node_put(dn);
>> + if (!rc)
>> + of_node_put(dn);
>> return rc;
>> }
>>
>
> NACK!
>
> The logic here is wrong. Here is the full function.
>
> static int dlpar_cpu_remove_by_index(u32 drc_index)
> {
> struct device_node *dn;
> int rc;
>
> dn = cpu_drc_index_to_dn(drc_index);
> if (!dn) {
> pr_warn("Cannot find CPU (drc index %x) to remove\n",
> drc_index);
> return -ENODEV;
> }
>
> rc = dlpar_cpu_remove(dn, drc_index);
> of_node_put(dn);
> return rc;
> }
>
> The call to cpu_drc_index_to_dn() returns a device_node with the reference count
> incremented. So, regardless of the success or failure of the call to
> dlpar_cpu_remove() you need to release that reference.
>
> If there is a reference counting issue it is somewhere else.
Okay. Withdrawn while we look some more.
> -Tyrel
--
Michael W. Bringmann
Linux Technology Center
IBM Corporation
Tie-Line 363-5196
External: (512) 286-5196
Cell: (512) 466-0650
mwb@linux.vnet.ibm.com
^ permalink raw reply
* Re: [RESEND PATCH 3/7] mm/gup: Change GUP fast to use flags rather than a write 'bool'
From: Mike Marshall @ 2019-02-20 19:29 UTC (permalink / raw)
To: ira.weiny
Cc: linux-fbdev, Michal Hocko, kvm, linux-sh, Peter Zijlstra,
James Hogan, linux-fpga, Heiko Carstens, dri-devel,
virtualization, linux-mm, Rich Felker, Paul Mackerras, sparclinux,
ceph-devel, devel, linux-s390, rds-devel, Yoshinori Sato,
linux-rdma, Jason Gunthorpe, Ingo Molnar, xen-devel, devel,
linux-media, John Hubbard, kvm-ppc, Borislav Petkov,
Thomas Gleixner, linux-scsi, netdev, linux-mips, Ralf Baechle,
LKML, Paul Burton, Martin Schwidefsky, Andrew Morton,
linuxppc-dev, David S. Miller, Kirill A. Shutemov
In-Reply-To: <20190220053040.10831-4-ira.weiny@intel.com>
Hi Ira
Martin and I looked at your patch and agree that it doesn't change
functionality for Orangefs.
Reviewed-by: Mike Marshall <hubcap@omnibond.com>
On Wed, Feb 20, 2019 at 12:32 AM <ira.weiny@intel.com> wrote:
>
> From: Ira Weiny <ira.weiny@intel.com>
>
> To facilitate additional options to get_user_pages_fast() change the
> singular write parameter to be gup_flags.
>
> This patch does not change any functionality. New functionality will
> follow in subsequent patches.
>
> Some of the get_user_pages_fast() call sites were unchanged because they
> already passed FOLL_WRITE or 0 for the write parameter.
>
> Signed-off-by: Ira Weiny <ira.weiny@intel.com>
> ---
> arch/mips/mm/gup.c | 11 ++++++-----
> arch/powerpc/kvm/book3s_64_mmu_hv.c | 4 ++--
> arch/powerpc/kvm/e500_mmu.c | 2 +-
> arch/powerpc/mm/mmu_context_iommu.c | 4 ++--
> arch/s390/kvm/interrupt.c | 2 +-
> arch/s390/mm/gup.c | 12 ++++++------
> arch/sh/mm/gup.c | 11 ++++++-----
> arch/sparc/mm/gup.c | 9 +++++----
> arch/x86/kvm/paging_tmpl.h | 2 +-
> arch/x86/kvm/svm.c | 2 +-
> drivers/fpga/dfl-afu-dma-region.c | 2 +-
> drivers/gpu/drm/via/via_dmablit.c | 3 ++-
> drivers/infiniband/hw/hfi1/user_pages.c | 3 ++-
> drivers/misc/genwqe/card_utils.c | 2 +-
> drivers/misc/vmw_vmci/vmci_host.c | 2 +-
> drivers/misc/vmw_vmci/vmci_queue_pair.c | 6 ++++--
> drivers/platform/goldfish/goldfish_pipe.c | 3 ++-
> drivers/rapidio/devices/rio_mport_cdev.c | 4 +++-
> drivers/sbus/char/oradax.c | 2 +-
> drivers/scsi/st.c | 3 ++-
> drivers/staging/gasket/gasket_page_table.c | 4 ++--
> drivers/tee/tee_shm.c | 2 +-
> drivers/vfio/vfio_iommu_spapr_tce.c | 3 ++-
> drivers/vhost/vhost.c | 2 +-
> drivers/video/fbdev/pvr2fb.c | 2 +-
> drivers/virt/fsl_hypervisor.c | 2 +-
> drivers/xen/gntdev.c | 2 +-
> fs/orangefs/orangefs-bufmap.c | 2 +-
> include/linux/mm.h | 4 ++--
> kernel/futex.c | 2 +-
> lib/iov_iter.c | 7 +++++--
> mm/gup.c | 10 +++++-----
> mm/util.c | 8 ++++----
> net/ceph/pagevec.c | 2 +-
> net/rds/info.c | 2 +-
> net/rds/rdma.c | 3 ++-
> 36 files changed, 81 insertions(+), 65 deletions(-)
>
> diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c
> index 0d14e0d8eacf..4c2b4483683c 100644
> --- a/arch/mips/mm/gup.c
> +++ b/arch/mips/mm/gup.c
> @@ -235,7 +235,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> * get_user_pages_fast() - pin user pages in memory
> * @start: starting user address
> * @nr_pages: number of pages from start to pin
> - * @write: whether pages will be written to
> + * @gup_flags: flags modifying pin behaviour
> * @pages: array that receives pointers to the pages pinned.
> * Should be at least nr_pages long.
> *
> @@ -247,8 +247,8 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> * requested. If nr_pages is 0 or negative, returns 0. If no pages
> * were pinned, returns -errno.
> */
> -int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> - struct page **pages)
> +int get_user_pages_fast(unsigned long start, int nr_pages,
> + unsigned int gup_flags, struct page **pages)
> {
> struct mm_struct *mm = current->mm;
> unsigned long addr, len, end;
> @@ -273,7 +273,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> next = pgd_addr_end(addr, end);
> if (pgd_none(pgd))
> goto slow;
> - if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
> + if (!gup_pud_range(pgd, addr, next, gup_flags & FOLL_WRITE,
> + pages, &nr))
> goto slow;
> } while (pgdp++, addr = next, addr != end);
> local_irq_enable();
> @@ -289,7 +290,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> pages += nr;
>
> ret = get_user_pages_unlocked(start, (end - start) >> PAGE_SHIFT,
> - pages, write ? FOLL_WRITE : 0);
> + pages, gup_flags);
>
> /* Have to be a bit careful with return values */
> if (nr > 0) {
> diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
> index bd2dcfbf00cd..8fcb0a921e46 100644
> --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
> +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
> @@ -582,7 +582,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
> /* If writing != 0, then the HPTE must allow writing, if we get here */
> write_ok = writing;
> hva = gfn_to_hva_memslot(memslot, gfn);
> - npages = get_user_pages_fast(hva, 1, writing, pages);
> + npages = get_user_pages_fast(hva, 1, writing ? FOLL_WRITE : 0, pages);
> if (npages < 1) {
> /* Check if it's an I/O mapping */
> down_read(¤t->mm->mmap_sem);
> @@ -1175,7 +1175,7 @@ void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long gpa,
> if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
> goto err;
> hva = gfn_to_hva_memslot(memslot, gfn);
> - npages = get_user_pages_fast(hva, 1, 1, pages);
> + npages = get_user_pages_fast(hva, 1, FOLL_WRITE, pages);
> if (npages < 1)
> goto err;
> page = pages[0];
> diff --git a/arch/powerpc/kvm/e500_mmu.c b/arch/powerpc/kvm/e500_mmu.c
> index 24296f4cadc6..e0af53fd78c5 100644
> --- a/arch/powerpc/kvm/e500_mmu.c
> +++ b/arch/powerpc/kvm/e500_mmu.c
> @@ -783,7 +783,7 @@ int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
> if (!pages)
> return -ENOMEM;
>
> - ret = get_user_pages_fast(cfg->array, num_pages, 1, pages);
> + ret = get_user_pages_fast(cfg->array, num_pages, FOLL_WRITE, pages);
> if (ret < 0)
> goto free_pages;
>
> diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c
> index a712a650a8b6..acb0990c8364 100644
> --- a/arch/powerpc/mm/mmu_context_iommu.c
> +++ b/arch/powerpc/mm/mmu_context_iommu.c
> @@ -190,7 +190,7 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
> for (i = 0; i < entries; ++i) {
> cur_ua = ua + (i << PAGE_SHIFT);
> if (1 != get_user_pages_fast(cur_ua,
> - 1/* pages */, 1/* iswrite */, &page)) {
> + 1/* pages */, FOLL_WRITE, &page)) {
> ret = -EFAULT;
> for (j = 0; j < i; ++j)
> put_page(pfn_to_page(mem->hpas[j] >>
> @@ -209,7 +209,7 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
> if (mm_iommu_move_page_from_cma(page))
> goto populate;
> if (1 != get_user_pages_fast(cur_ua,
> - 1/* pages */, 1/* iswrite */,
> + 1/* pages */, FOLL_WRITE,
> &page)) {
> ret = -EFAULT;
> for (j = 0; j < i; ++j)
> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
> index fcb55b02990e..69d9366b966c 100644
> --- a/arch/s390/kvm/interrupt.c
> +++ b/arch/s390/kvm/interrupt.c
> @@ -2278,7 +2278,7 @@ static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
> ret = -EFAULT;
> goto out;
> }
> - ret = get_user_pages_fast(map->addr, 1, 1, &map->page);
> + ret = get_user_pages_fast(map->addr, 1, FOLL_WRITE, &map->page);
> if (ret < 0)
> goto out;
> BUG_ON(ret != 1);
> diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
> index 2809d11c7a28..0a6faf3d9960 100644
> --- a/arch/s390/mm/gup.c
> +++ b/arch/s390/mm/gup.c
> @@ -265,7 +265,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> * get_user_pages_fast() - pin user pages in memory
> * @start: starting user address
> * @nr_pages: number of pages from start to pin
> - * @write: whether pages will be written to
> + * @gup_flags: flags modifying pin behaviour
> * @pages: array that receives pointers to the pages pinned.
> * Should be at least nr_pages long.
> *
> @@ -277,22 +277,22 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> * requested. If nr_pages is 0 or negative, returns 0. If no pages
> * were pinned, returns -errno.
> */
> -int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> - struct page **pages)
> +int get_user_pages_fast(unsigned long start, int nr_pages,
> + unsigned int gup_flags, struct page **pages)
> {
> int nr, ret;
>
> might_sleep();
> start &= PAGE_MASK;
> - nr = __get_user_pages_fast(start, nr_pages, write, pages);
> + nr = __get_user_pages_fast(start, nr_pages, gup_flags & FOLL_WRITE,
> + pages);
> if (nr == nr_pages)
> return nr;
>
> /* Try to get the remaining pages with get_user_pages */
> start += nr << PAGE_SHIFT;
> pages += nr;
> - ret = get_user_pages_unlocked(start, nr_pages - nr, pages,
> - write ? FOLL_WRITE : 0);
> + ret = get_user_pages_unlocked(start, nr_pages - nr, pages, gup_flags);
> /* Have to be a bit careful with return values */
> if (nr > 0)
> ret = (ret < 0) ? nr : ret + nr;
> diff --git a/arch/sh/mm/gup.c b/arch/sh/mm/gup.c
> index 3e27f6d1f1ec..277c882f7489 100644
> --- a/arch/sh/mm/gup.c
> +++ b/arch/sh/mm/gup.c
> @@ -204,7 +204,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> * get_user_pages_fast() - pin user pages in memory
> * @start: starting user address
> * @nr_pages: number of pages from start to pin
> - * @write: whether pages will be written to
> + * @gup_flags: flags modifying pin behaviour
> * @pages: array that receives pointers to the pages pinned.
> * Should be at least nr_pages long.
> *
> @@ -216,8 +216,8 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> * requested. If nr_pages is 0 or negative, returns 0. If no pages
> * were pinned, returns -errno.
> */
> -int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> - struct page **pages)
> +int get_user_pages_fast(unsigned long start, int nr_pages,
> + unsigned int gup_flags, struct page **pages)
> {
> struct mm_struct *mm = current->mm;
> unsigned long addr, len, end;
> @@ -241,7 +241,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> next = pgd_addr_end(addr, end);
> if (pgd_none(pgd))
> goto slow;
> - if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
> + if (!gup_pud_range(pgd, addr, next, gup_flags & FOLL_WRITE,
> + pages, &nr))
> goto slow;
> } while (pgdp++, addr = next, addr != end);
> local_irq_enable();
> @@ -261,7 +262,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
>
> ret = get_user_pages_unlocked(start,
> (end - start) >> PAGE_SHIFT, pages,
> - write ? FOLL_WRITE : 0);
> + gup_flags);
>
> /* Have to be a bit careful with return values */
> if (nr > 0) {
> diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c
> index aee6dba83d0e..1e770a517d4a 100644
> --- a/arch/sparc/mm/gup.c
> +++ b/arch/sparc/mm/gup.c
> @@ -245,8 +245,8 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> return nr;
> }
>
> -int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> - struct page **pages)
> +int get_user_pages_fast(unsigned long start, int nr_pages,
> + unsigned int gup_flags, struct page **pages)
> {
> struct mm_struct *mm = current->mm;
> unsigned long addr, len, end;
> @@ -303,7 +303,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> next = pgd_addr_end(addr, end);
> if (pgd_none(pgd))
> goto slow;
> - if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
> + if (!gup_pud_range(pgd, addr, next, gup_flags & FOLL_WRITE,
> + pages, &nr))
> goto slow;
> } while (pgdp++, addr = next, addr != end);
>
> @@ -324,7 +325,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
>
> ret = get_user_pages_unlocked(start,
> (end - start) >> PAGE_SHIFT, pages,
> - write ? FOLL_WRITE : 0);
> + gup_flags);
>
> /* Have to be a bit careful with return values */
> if (nr > 0) {
> diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
> index 6bdca39829bc..08715034e315 100644
> --- a/arch/x86/kvm/paging_tmpl.h
> +++ b/arch/x86/kvm/paging_tmpl.h
> @@ -140,7 +140,7 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
> pt_element_t *table;
> struct page *page;
>
> - npages = get_user_pages_fast((unsigned long)ptep_user, 1, 1, &page);
> + npages = get_user_pages_fast((unsigned long)ptep_user, 1, FOLL_WRITE, &page);
> /* Check if the user is doing something meaningless. */
> if (unlikely(npages != 1))
> return -EFAULT;
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index f13a3a24d360..173596a020cb 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -1803,7 +1803,7 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
> return NULL;
>
> /* Pin the user virtual address. */
> - npinned = get_user_pages_fast(uaddr, npages, write ? FOLL_WRITE : 0, pages);
> + npinned = get_user_pages_fast(uaddr, npages, FOLL_WRITE, pages);
> if (npinned != npages) {
> pr_err("SEV: Failure locking %lu pages.\n", npages);
> goto err;
> diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c
> index e18a786fc943..c438722bf4e1 100644
> --- a/drivers/fpga/dfl-afu-dma-region.c
> +++ b/drivers/fpga/dfl-afu-dma-region.c
> @@ -102,7 +102,7 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata,
> goto unlock_vm;
> }
>
> - pinned = get_user_pages_fast(region->user_addr, npages, 1,
> + pinned = get_user_pages_fast(region->user_addr, npages, FOLL_WRITE,
> region->pages);
> if (pinned < 0) {
> ret = pinned;
> diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c
> index 345bda4494e1..0c8b09602910 100644
> --- a/drivers/gpu/drm/via/via_dmablit.c
> +++ b/drivers/gpu/drm/via/via_dmablit.c
> @@ -239,7 +239,8 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
> if (NULL == vsg->pages)
> return -ENOMEM;
> ret = get_user_pages_fast((unsigned long)xfer->mem_addr,
> - vsg->num_pages, vsg->direction == DMA_FROM_DEVICE,
> + vsg->num_pages,
> + vsg->direction == DMA_FROM_DEVICE ? FOLL_WRITE : 0,
> vsg->pages);
> if (ret != vsg->num_pages) {
> if (ret < 0)
> diff --git a/drivers/infiniband/hw/hfi1/user_pages.c b/drivers/infiniband/hw/hfi1/user_pages.c
> index 24b592c6522e..78ccacaf97d0 100644
> --- a/drivers/infiniband/hw/hfi1/user_pages.c
> +++ b/drivers/infiniband/hw/hfi1/user_pages.c
> @@ -105,7 +105,8 @@ int hfi1_acquire_user_pages(struct mm_struct *mm, unsigned long vaddr, size_t np
> {
> int ret;
>
> - ret = get_user_pages_fast(vaddr, npages, writable, pages);
> + ret = get_user_pages_fast(vaddr, npages, writable ? FOLL_WRITE : 0,
> + pages);
> if (ret < 0)
> return ret;
>
> diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c
> index 25265fd0fd6e..89cff9d1012b 100644
> --- a/drivers/misc/genwqe/card_utils.c
> +++ b/drivers/misc/genwqe/card_utils.c
> @@ -603,7 +603,7 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr,
> /* pin user pages in memory */
> rc = get_user_pages_fast(data & PAGE_MASK, /* page aligned addr */
> m->nr_pages,
> - m->write, /* readable/writable */
> + m->write ? FOLL_WRITE : 0, /* readable/writable */
> m->page_list); /* ptrs to pages */
> if (rc < 0)
> goto fail_get_user_pages;
> diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c
> index 997f92543dd4..422d08da3244 100644
> --- a/drivers/misc/vmw_vmci/vmci_host.c
> +++ b/drivers/misc/vmw_vmci/vmci_host.c
> @@ -242,7 +242,7 @@ static int vmci_host_setup_notify(struct vmci_ctx *context,
> /*
> * Lock physical page backing a given user VA.
> */
> - retval = get_user_pages_fast(uva, 1, 1, &context->notify_page);
> + retval = get_user_pages_fast(uva, 1, FOLL_WRITE, &context->notify_page);
> if (retval != 1) {
> context->notify_page = NULL;
> return VMCI_ERROR_GENERIC;
> diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
> index 264f4ed8eef2..c5396ee32e51 100644
> --- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
> +++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
> @@ -666,7 +666,8 @@ static int qp_host_get_user_memory(u64 produce_uva,
> int err = VMCI_SUCCESS;
>
> retval = get_user_pages_fast((uintptr_t) produce_uva,
> - produce_q->kernel_if->num_pages, 1,
> + produce_q->kernel_if->num_pages,
> + FOLL_WRITE,
> produce_q->kernel_if->u.h.header_page);
> if (retval < (int)produce_q->kernel_if->num_pages) {
> pr_debug("get_user_pages_fast(produce) failed (retval=%d)",
> @@ -678,7 +679,8 @@ static int qp_host_get_user_memory(u64 produce_uva,
> }
>
> retval = get_user_pages_fast((uintptr_t) consume_uva,
> - consume_q->kernel_if->num_pages, 1,
> + consume_q->kernel_if->num_pages,
> + FOLL_WRITE,
> consume_q->kernel_if->u.h.header_page);
> if (retval < (int)consume_q->kernel_if->num_pages) {
> pr_debug("get_user_pages_fast(consume) failed (retval=%d)",
> diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
> index 321bc673c417..cef0133aa47a 100644
> --- a/drivers/platform/goldfish/goldfish_pipe.c
> +++ b/drivers/platform/goldfish/goldfish_pipe.c
> @@ -274,7 +274,8 @@ static int pin_user_pages(unsigned long first_page,
> *iter_last_page_size = last_page_size;
> }
>
> - ret = get_user_pages_fast(first_page, requested_pages, !is_write,
> + ret = get_user_pages_fast(first_page, requested_pages,
> + !is_write ? FOLL_WRITE : 0,
> pages);
> if (ret <= 0)
> return -EFAULT;
> diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c
> index cbe467ff1aba..f681b3e9e970 100644
> --- a/drivers/rapidio/devices/rio_mport_cdev.c
> +++ b/drivers/rapidio/devices/rio_mport_cdev.c
> @@ -868,7 +868,9 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
>
> pinned = get_user_pages_fast(
> (unsigned long)xfer->loc_addr & PAGE_MASK,
> - nr_pages, dir == DMA_FROM_DEVICE, page_list);
> + nr_pages,
> + dir == DMA_FROM_DEVICE ? FOLL_WRITE : 0,
> + page_list);
>
> if (pinned != nr_pages) {
> if (pinned < 0) {
> diff --git a/drivers/sbus/char/oradax.c b/drivers/sbus/char/oradax.c
> index 6516bc3cb58b..790aa148670d 100644
> --- a/drivers/sbus/char/oradax.c
> +++ b/drivers/sbus/char/oradax.c
> @@ -437,7 +437,7 @@ static int dax_lock_page(void *va, struct page **p)
>
> dax_dbg("uva %p", va);
>
> - ret = get_user_pages_fast((unsigned long)va, 1, 1, p);
> + ret = get_user_pages_fast((unsigned long)va, 1, FOLL_WRITE, p);
> if (ret == 1) {
> dax_dbg("locked page %p, for VA %p", *p, va);
> return 0;
> diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
> index 7ff22d3f03e3..871b25914c07 100644
> --- a/drivers/scsi/st.c
> +++ b/drivers/scsi/st.c
> @@ -4918,7 +4918,8 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
>
> /* Try to fault in all of the necessary pages */
> /* rw==READ means read from drive, write into memory area */
> - res = get_user_pages_fast(uaddr, nr_pages, rw == READ, pages);
> + res = get_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0,
> + pages);
>
> /* Errors and no page mapped should return here */
> if (res < nr_pages)
> diff --git a/drivers/staging/gasket/gasket_page_table.c b/drivers/staging/gasket/gasket_page_table.c
> index 26755d9ca41d..f67fdf1d3817 100644
> --- a/drivers/staging/gasket/gasket_page_table.c
> +++ b/drivers/staging/gasket/gasket_page_table.c
> @@ -486,8 +486,8 @@ static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
> ptes[i].dma_addr = pg_tbl->coherent_pages[0].paddr +
> off + i * PAGE_SIZE;
> } else {
> - ret = get_user_pages_fast(page_addr - offset, 1, 1,
> - &page);
> + ret = get_user_pages_fast(page_addr - offset, 1,
> + FOLL_WRITE, &page);
>
> if (ret <= 0) {
> dev_err(pg_tbl->device,
> diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
> index 0b9ab1d0dd45..49fd7312e2aa 100644
> --- a/drivers/tee/tee_shm.c
> +++ b/drivers/tee/tee_shm.c
> @@ -273,7 +273,7 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
> goto err;
> }
>
> - rc = get_user_pages_fast(start, num_pages, 1, shm->pages);
> + rc = get_user_pages_fast(start, num_pages, FOLL_WRITE, shm->pages);
> if (rc > 0)
> shm->num_pages = rc;
> if (rc != num_pages) {
> diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
> index c424913324e3..a4b10bb4086b 100644
> --- a/drivers/vfio/vfio_iommu_spapr_tce.c
> +++ b/drivers/vfio/vfio_iommu_spapr_tce.c
> @@ -532,7 +532,8 @@ static int tce_iommu_use_page(unsigned long tce, unsigned long *hpa)
> enum dma_data_direction direction = iommu_tce_direction(tce);
>
> if (get_user_pages_fast(tce & PAGE_MASK, 1,
> - direction != DMA_TO_DEVICE, &page) != 1)
> + direction != DMA_TO_DEVICE ? FOLL_WRITE : 0,
> + &page) != 1)
> return -EFAULT;
>
> *hpa = __pa((unsigned long) page_address(page));
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index 24a129fcdd61..72685b1659ff 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -1700,7 +1700,7 @@ static int set_bit_to_user(int nr, void __user *addr)
> int bit = nr + (log % PAGE_SIZE) * 8;
> int r;
>
> - r = get_user_pages_fast(log, 1, 1, &page);
> + r = get_user_pages_fast(log, 1, FOLL_WRITE, &page);
> if (r < 0)
> return r;
> BUG_ON(r != 1);
> diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c
> index 8a53d1de611d..41390c8e0f67 100644
> --- a/drivers/video/fbdev/pvr2fb.c
> +++ b/drivers/video/fbdev/pvr2fb.c
> @@ -686,7 +686,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
> if (!pages)
> return -ENOMEM;
>
> - ret = get_user_pages_fast((unsigned long)buf, nr_pages, true, pages);
> + ret = get_user_pages_fast((unsigned long)buf, nr_pages, FOLL_WRITE, pages);
> if (ret < nr_pages) {
> nr_pages = ret;
> ret = -EINVAL;
> diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c
> index 8ba726e600e9..6446bcab4185 100644
> --- a/drivers/virt/fsl_hypervisor.c
> +++ b/drivers/virt/fsl_hypervisor.c
> @@ -244,7 +244,7 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
>
> /* Get the physical addresses of the source buffer */
> num_pinned = get_user_pages_fast(param.local_vaddr - lb_offset,
> - num_pages, param.source != -1, pages);
> + num_pages, param.source != -1 ? FOLL_WRITE : 0, pages);
>
> if (num_pinned != num_pages) {
> /* get_user_pages() failed */
> diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
> index 5efc5eee9544..7b47f1e6aab4 100644
> --- a/drivers/xen/gntdev.c
> +++ b/drivers/xen/gntdev.c
> @@ -852,7 +852,7 @@ static int gntdev_get_page(struct gntdev_copy_batch *batch, void __user *virt,
> unsigned long xen_pfn;
> int ret;
>
> - ret = get_user_pages_fast(addr, 1, writeable, &page);
> + ret = get_user_pages_fast(addr, 1, writeable ? FOLL_WRITE : 0, &page);
> if (ret < 0)
> return ret;
>
> diff --git a/fs/orangefs/orangefs-bufmap.c b/fs/orangefs/orangefs-bufmap.c
> index 443bcd8c3c19..5a7c4fda682f 100644
> --- a/fs/orangefs/orangefs-bufmap.c
> +++ b/fs/orangefs/orangefs-bufmap.c
> @@ -269,7 +269,7 @@ orangefs_bufmap_map(struct orangefs_bufmap *bufmap,
>
> /* map the pages */
> ret = get_user_pages_fast((unsigned long)user_desc->ptr,
> - bufmap->page_count, 1, bufmap->page_array);
> + bufmap->page_count, FOLL_WRITE, bufmap->page_array);
>
> if (ret < 0)
> return ret;
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 05a105d9d4c3..8e1f3cd7482a 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1537,8 +1537,8 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
> long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
> struct page **pages, unsigned int gup_flags);
>
> -int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> - struct page **pages);
> +int get_user_pages_fast(unsigned long start, int nr_pages,
> + unsigned int gup_flags, struct page **pages);
>
> /* Container for pinned pfns / pages */
> struct frame_vector {
> diff --git a/kernel/futex.c b/kernel/futex.c
> index fdd312da0992..e10209946f8b 100644
> --- a/kernel/futex.c
> +++ b/kernel/futex.c
> @@ -546,7 +546,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, enum futex_a
> if (unlikely(should_fail_futex(fshared)))
> return -EFAULT;
>
> - err = get_user_pages_fast(address, 1, 1, &page);
> + err = get_user_pages_fast(address, 1, FOLL_WRITE, &page);
> /*
> * If write access is not required (eg. FUTEX_WAIT), try
> * and get read-only access.
> diff --git a/lib/iov_iter.c b/lib/iov_iter.c
> index be4bd627caf0..6dbae0692719 100644
> --- a/lib/iov_iter.c
> +++ b/lib/iov_iter.c
> @@ -1280,7 +1280,9 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
> len = maxpages * PAGE_SIZE;
> addr &= ~(PAGE_SIZE - 1);
> n = DIV_ROUND_UP(len, PAGE_SIZE);
> - res = get_user_pages_fast(addr, n, iov_iter_rw(i) != WRITE, pages);
> + res = get_user_pages_fast(addr, n,
> + iov_iter_rw(i) != WRITE ? FOLL_WRITE : 0,
> + pages);
> if (unlikely(res < 0))
> return res;
> return (res == n ? len : res * PAGE_SIZE) - *start;
> @@ -1361,7 +1363,8 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
> p = get_pages_array(n);
> if (!p)
> return -ENOMEM;
> - res = get_user_pages_fast(addr, n, iov_iter_rw(i) != WRITE, p);
> + res = get_user_pages_fast(addr, n,
> + iov_iter_rw(i) != WRITE ? FOLL_WRITE : 0, p);
> if (unlikely(res < 0)) {
> kvfree(p);
> return res;
> diff --git a/mm/gup.c b/mm/gup.c
> index 681388236106..6f32d36b3c5b 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -1863,7 +1863,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> * get_user_pages_fast() - pin user pages in memory
> * @start: starting user address
> * @nr_pages: number of pages from start to pin
> - * @write: whether pages will be written to
> + * @gup_flags: flags modifying pin behaviour
> * @pages: array that receives pointers to the pages pinned.
> * Should be at least nr_pages long.
> *
> @@ -1875,8 +1875,8 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
> * requested. If nr_pages is 0 or negative, returns 0. If no pages
> * were pinned, returns -errno.
> */
> -int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> - struct page **pages)
> +int get_user_pages_fast(unsigned long start, int nr_pages,
> + unsigned int gup_flags, struct page **pages)
> {
> unsigned long addr, len, end;
> int nr = 0, ret = 0;
> @@ -1894,7 +1894,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
>
> if (gup_fast_permitted(start, nr_pages)) {
> local_irq_disable();
> - gup_pgd_range(addr, end, write ? FOLL_WRITE : 0, pages, &nr);
> + gup_pgd_range(addr, end, gup_flags, pages, &nr);
> local_irq_enable();
> ret = nr;
> }
> @@ -1905,7 +1905,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
> pages += nr;
>
> ret = get_user_pages_unlocked(start, nr_pages - nr, pages,
> - write ? FOLL_WRITE : 0);
> + gup_flags);
>
> /* Have to be a bit careful with return values */
> if (nr > 0) {
> diff --git a/mm/util.c b/mm/util.c
> index 1ea055138043..01ffe145c62b 100644
> --- a/mm/util.c
> +++ b/mm/util.c
> @@ -306,7 +306,7 @@ EXPORT_SYMBOL_GPL(__get_user_pages_fast);
> * get_user_pages_fast() - pin user pages in memory
> * @start: starting user address
> * @nr_pages: number of pages from start to pin
> - * @write: whether pages will be written to
> + * @gup_flags: flags modifying pin behaviour
> * @pages: array that receives pointers to the pages pinned.
> * Should be at least nr_pages long.
> *
> @@ -327,10 +327,10 @@ EXPORT_SYMBOL_GPL(__get_user_pages_fast);
> * get_user_pages_fast simply falls back to get_user_pages.
> */
> int __weak get_user_pages_fast(unsigned long start,
> - int nr_pages, int write, struct page **pages)
> + int nr_pages, unsigned int gup_flags,
> + struct page **pages)
> {
> - return get_user_pages_unlocked(start, nr_pages, pages,
> - write ? FOLL_WRITE : 0);
> + return get_user_pages_unlocked(start, nr_pages, pages, gup_flags);
> }
> EXPORT_SYMBOL_GPL(get_user_pages_fast);
>
> diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c
> index d3736f5bffec..74cafc0142ea 100644
> --- a/net/ceph/pagevec.c
> +++ b/net/ceph/pagevec.c
> @@ -27,7 +27,7 @@ struct page **ceph_get_direct_page_vector(const void __user *data,
> while (got < num_pages) {
> rc = get_user_pages_fast(
> (unsigned long)data + ((unsigned long)got * PAGE_SIZE),
> - num_pages - got, write_page, pages + got);
> + num_pages - got, write_page ? FOLL_WRITE : 0, pages + got);
> if (rc < 0)
> break;
> BUG_ON(rc == 0);
> diff --git a/net/rds/info.c b/net/rds/info.c
> index e367a97a18c8..03f6fd56d237 100644
> --- a/net/rds/info.c
> +++ b/net/rds/info.c
> @@ -193,7 +193,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
> ret = -ENOMEM;
> goto out;
> }
> - ret = get_user_pages_fast(start, nr_pages, 1, pages);
> + ret = get_user_pages_fast(start, nr_pages, FOLL_WRITE, pages);
> if (ret != nr_pages) {
> if (ret > 0)
> nr_pages = ret;
> diff --git a/net/rds/rdma.c b/net/rds/rdma.c
> index 182ab8430594..b340ed4fc43a 100644
> --- a/net/rds/rdma.c
> +++ b/net/rds/rdma.c
> @@ -158,7 +158,8 @@ static int rds_pin_pages(unsigned long user_addr, unsigned int nr_pages,
> {
> int ret;
>
> - ret = get_user_pages_fast(user_addr, nr_pages, write, pages);
> + ret = get_user_pages_fast(user_addr, nr_pages, write ? FOLL_WRITE : 0,
> + pages);
>
> if (ret >= 0 && ret < nr_pages) {
> while (ret--)
> --
> 2.20.1
>
>
^ permalink raw reply
* make modules_prepare doesn't build arch/powerpc/lib/crtsavres.o
From: Luis Ressel @ 2019-02-20 21:33 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 645 bytes --]
Hello,
as documented in the top-level Makefile, "make modules_prepare" is
supposed to get a pristine kernel tree into a state that's suitable to
build out-of-tree modules. However, this is not the case for the
powerpc arch, since all modules are linked against
arch/powerpc/lib/crtsavres.o on ppc32 (and ppc64 if binutils is too
old).
A similar problem applies to "make clean" -- it is supposed to retain
all files which are neccessary for module building, but the global
"find . -name '*.o' -delete" it performs drops crtsavres.o.
--
Regards,
Luis Ressel
Please CC me when replying; I'm not subscribed to the kernel MLs.
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] powerpc/kvm: Save and restore AMR instead of zeroing
From: Paul Mackerras @ 2019-02-20 23:55 UTC (permalink / raw)
To: Russell Currey; +Cc: linuxppc-dev, stable, kvm-ppc
In-Reply-To: <20190220045958.14966-1-ruscur@russell.cc>
On Wed, Feb 20, 2019 at 03:59:58PM +1100, Russell Currey wrote:
> Using the hash MMU on P7+, the AMR is used for pkeys. It's important
This needs a bit of rewording. The "Using" ... "used" construct is a
bit confusing on the first read. Also, there was a processor called
P7+, but I think you're trying to say P7 and subsequent processors.
> that the host and guest never end up with each other's AMR value, since
> this could disrupt operations and break things.
What sort of breakage? Guest kernel crash? Host kernel crash?
> The AMR gets correctly restored on context switch, however before this
> happens (i.e. in a program like qemu) having the host value of the AMR
> be zero would interfere with that program using pkeys.
>
> In addition, the AMR on Radix can control kernel access to userspace
> data, which you wouldn't want to be zeroed.
>
> So, just save and restore it like the other registers that get saved and
> restored.
>
> Fixes: cf43d3b26452 ("powerpc: Enable pkey subsystem")
> Cc: <stable@vger.kernel.org> # v4.16+
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> ---
> I'm not entirely sure the stack frame numbers are correct, I've tested it
> and it works but it'd be good if someone could double check this.
>
> arch/powerpc/kvm/book3s_hv_rmhandlers.S | 13 +++++++++----
> 1 file changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> index 9b8d50a7cbaf..6291751c4ad9 100644
> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> @@ -47,7 +47,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
> #define NAPPING_NOVCPU 2
>
> /* Stack frame offsets for kvmppc_hv_entry */
> -#define SFS 208
> +#define SFS 224 /* must be divisible by 16 */
I don't think this needs to be increased. What's happening here is
that we have a "short path" where most SPRs are saved/loaded/restored
etc. in C code in book3s_hv.c, and that path uses 144 bytes on the
stack to save/restore 18 GPR values (r14 - r31). Your patch needs to
add code to context-switch AMR in kvmhv_p9_guest_entry() to fix that
path.
Alternatively there is the slow path where we go to real mode and do
most of the SPR loading in assembler code. That path uses the stack
to store host SPR values in STACK_SLOT_TID, PSSCR, PID, etc.
> #define STACK_SLOT_TRAP (SFS-4)
> #define STACK_SLOT_SHORT_PATH (SFS-8)
> #define STACK_SLOT_TID (SFS-16)
> @@ -58,8 +58,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
> #define STACK_SLOT_DAWR (SFS-56)
> #define STACK_SLOT_DAWRX (SFS-64)
> #define STACK_SLOT_HFSCR (SFS-72)
> +#define STACK_SLOT_AMR (SFS-80)
> /* the following is used by the P9 short path */
> -#define STACK_SLOT_NVGPRS (SFS-152) /* 18 gprs */
> +#define STACK_SLOT_NVGPRS (SFS-160) /* 18 gprs */
I don't see why you need to change this either.
>
> /*
> * Call kvmppc_hv_entry in real mode.
> @@ -743,6 +744,9 @@ BEGIN_FTR_SECTION
> std r7, STACK_SLOT_DAWRX(r1)
> END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
>
> + mfspr r5, SPRN_AMR
> + std r5, STACK_SLOT_AMR(r1)
> +
> BEGIN_FTR_SECTION
> /* Set partition DABR */
> /* Do this before re-enabling PMU to avoid P7 DABR corruption bug */
> @@ -1640,13 +1644,14 @@ BEGIN_FTR_SECTION
> END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
> 8:
>
> - /* Save and reset AMR and UAMOR before turning on the MMU */
> + /* Save and restore/reset AMR and UAMOR before turning on the MMU */
> mfspr r5,SPRN_AMR
> mfspr r6,SPRN_UAMOR
> std r5,VCPU_AMR(r9)
> std r6,VCPU_UAMOR(r9)
> + ld r5,STACK_SLOT_AMR(r1)
> li r6,0
> - mtspr SPRN_AMR,r6
> + mtspr SPRN_AMR, r5
> mtspr SPRN_UAMOR, r6
>
> /* Switch DSCR back to host value */
> --
> 2.20.1
Rest looks fine, but as I said, the patch needs to hit
kvmhv_p9_guest_entry() also.
Paul.
^ permalink raw reply
* Re: [PATCH v2] powerpc/prom_init: add __init markers to all functions
From: Daniel Axtens @ 2019-02-21 0:26 UTC (permalink / raw)
To: Masahiro Yamada, linux-kbuild, linuxppc-dev, Michael Ellerman
Cc: Mathieu Malaterre, Aneesh Kumar K.V, linux-kernel,
Masahiro Yamada, Paul Mackerras
In-Reply-To: <1550641996-21937-1-git-send-email-yamada.masahiro@socionext.com>
Hi Masahiro,
> It is fragile to rely on the compiler's optimization to avoid the
> section mismatch. Some functions may not be necessarily inlined
> when the compiler's inlining heuristic changes.
>
> Add __init markers consistently.
>
Are you doing this with some sort of static analysis, or manually?
Regards,
Daniel
> As for prom_getprop() and prom_getproplen(), they are marked as
> 'inline', so inlining is guaranteed because PowerPC never enables
> CONFIG_OPTIMIZE_INLINING. However, it would be better to leave the
> inlining decision to the compiler. I replaced 'inline' with __init.
> I added __maybe_unused to prom_getproplen() because it is currently
> relying on the side-effect of 'inline'; GCC does not report
> -Wunused-function warnings for functions with 'inline' marker.
>
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
> ---
>
> Changes in v2:
> - Add __maybe_unsed to prom_getproplen()
> - Add __init to enter_prom() as well
>
> arch/powerpc/kernel/prom_init.c | 29 +++++++++++++++--------------
> 1 file changed, 15 insertions(+), 14 deletions(-)
>
> diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
> index f33ff41..1bad0ac 100644
> --- a/arch/powerpc/kernel/prom_init.c
> +++ b/arch/powerpc/kernel/prom_init.c
> @@ -138,9 +138,9 @@ extern void __start(unsigned long r3, unsigned long r4, unsigned long r5,
> unsigned long r9);
>
> #ifdef CONFIG_PPC64
> -extern int enter_prom(struct prom_args *args, unsigned long entry);
> +extern int __init enter_prom(struct prom_args *args, unsigned long entry);
> #else
> -static inline int enter_prom(struct prom_args *args, unsigned long entry)
> +static int __init enter_prom(struct prom_args *args, unsigned long entry)
> {
> return ((int (*)(struct prom_args *))entry)(args);
> }
> @@ -501,19 +501,20 @@ static int __init prom_next_node(phandle *nodep)
> }
> }
>
> -static inline int prom_getprop(phandle node, const char *pname,
> +static int __init prom_getprop(phandle node, const char *pname,
> void *value, size_t valuelen)
> {
> return call_prom("getprop", 4, 1, node, ADDR(pname),
> (u32)(unsigned long) value, (u32) valuelen);
> }
>
> -static inline int prom_getproplen(phandle node, const char *pname)
> +static int __init __maybe_unused prom_getproplen(phandle node,
> + const char *pname)
> {
> return call_prom("getproplen", 2, 1, node, ADDR(pname));
> }
>
> -static void add_string(char **str, const char *q)
> +static void __init add_string(char **str, const char *q)
> {
> char *p = *str;
>
> @@ -523,7 +524,7 @@ static void add_string(char **str, const char *q)
> *str = p;
> }
>
> -static char *tohex(unsigned int x)
> +static char __init *tohex(unsigned int x)
> {
> static const char digits[] __initconst = "0123456789abcdef";
> static char result[9] __prombss;
> @@ -570,7 +571,7 @@ static int __init prom_setprop(phandle node, const char *nodename,
> #define islower(c) ('a' <= (c) && (c) <= 'z')
> #define toupper(c) (islower(c) ? ((c) - 'a' + 'A') : (c))
>
> -static unsigned long prom_strtoul(const char *cp, const char **endp)
> +static unsigned long __init prom_strtoul(const char *cp, const char **endp)
> {
> unsigned long result = 0, base = 10, value;
>
> @@ -595,7 +596,7 @@ static unsigned long prom_strtoul(const char *cp, const char **endp)
> return result;
> }
>
> -static unsigned long prom_memparse(const char *ptr, const char **retptr)
> +static unsigned long __init prom_memparse(const char *ptr, const char **retptr)
> {
> unsigned long ret = prom_strtoul(ptr, retptr);
> int shift = 0;
> @@ -2924,7 +2925,7 @@ static void __init fixup_device_tree_pasemi(void)
> prom_setprop(iob, name, "device_type", "isa", sizeof("isa"));
> }
> #else /* !CONFIG_PPC_PASEMI_NEMO */
> -static inline void fixup_device_tree_pasemi(void) { }
> +static void __init fixup_device_tree_pasemi(void) { }
> #endif
>
> static void __init fixup_device_tree(void)
> @@ -2986,15 +2987,15 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
>
> #ifdef CONFIG_PPC64
> #ifdef CONFIG_RELOCATABLE
> -static void reloc_toc(void)
> +static void __init reloc_toc(void)
> {
> }
>
> -static void unreloc_toc(void)
> +static void __init unreloc_toc(void)
> {
> }
> #else
> -static void __reloc_toc(unsigned long offset, unsigned long nr_entries)
> +static void __init __reloc_toc(unsigned long offset, unsigned long nr_entries)
> {
> unsigned long i;
> unsigned long *toc_entry;
> @@ -3008,7 +3009,7 @@ static void __reloc_toc(unsigned long offset, unsigned long nr_entries)
> }
> }
>
> -static void reloc_toc(void)
> +static void __init reloc_toc(void)
> {
> unsigned long offset = reloc_offset();
> unsigned long nr_entries =
> @@ -3019,7 +3020,7 @@ static void reloc_toc(void)
> mb();
> }
>
> -static void unreloc_toc(void)
> +static void __init unreloc_toc(void)
> {
> unsigned long offset = reloc_offset();
> unsigned long nr_entries =
> --
> 2.7.4
^ permalink raw reply
* Re: [PATCH 5/8] iio/counter: add FlexTimer Module Quadrature decoder counter driver
From: William Breathitt Gray @ 2019-02-21 1:09 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Mark Rutland, devicetree, Lars-Peter Clausen, linux-pwm,
linux-iio, Patrick Havelange, Linus Walleij, Daniel Lezcano,
linux-kernel, Li Yang, linuxppc-dev, Rob Herring, Thierry Reding,
linux-arm-kernel, Peter Meerwald-Stadler, Hartmut Knaack,
Thomas Gleixner, Shawn Guo, Esben Haabendal
In-Reply-To: <20190220164154.00547a77@archlinux>
On Wed, Feb 20, 2019 at 04:41:54PM +0000, Jonathan Cameron wrote:
> On Mon, 18 Feb 2019 15:03:18 +0100
> Patrick Havelange <patrick.havelange@essensium.com> wrote:
>
> > This driver exposes the counter for the quadrature decoder of the
> > FlexTimer Module, present in the LS1021A soc.
> >
> > Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
> > Reviewed-by: Esben Haabendal <esben@haabendal.dk>
> Given you cc'd William, I'm guessing you know about the counter
> subsystem effort. I would really rather not take any drivers
> into IIO if we have any hope of getting that upstreamed soon
> (which I personally think we do and should!). The reason is
> we end up having to maintain old ABI just because someone might be using
> it and it makes the drivers very messy.
>
> I'll review as is though as may be there are some elements that will
> cross over.
>
> Comments inline. William: Looks like a straight forward conversion if
> it makes sense to get this lined up as part of your initial submission?
> You have quite a few drivers so I wouldn't have said it needs to be there
> at the start, but good to have it soon after.
>
> Jonathan
I agree, we should try to merge this as part of Counter subsystem
introduction rather than as another IIO Counter driver. As we determined
when adding support for the STM32 timers, the existing IIO Counter API
is fundamentally unsuitable for representing counter devices. So
regardless of how a new Counter API is merged, the existing IIO Counter
API must be deprecated.
Patrick, I apologize for the confusion this has caused. Would you be
able to convert this driver to use the proposed Counter subsystem API
from this patchset that I believe you encountered before:
https://marc.info/?l=linux-arm-kernel&m=153229982404051
Although it was last updated in October, I believe you should be able to
rebase that Counter subsystem introduction patchset cleanly on top of
the IIO tree (if there are any merge conflicts send me an email). Take a
look at the generic-counter.rst file under the Documentation/driver-api/
directory for an overview of the API; the counter drivers under the
drivers/counter/ directory also make good references.
If you have any difficulties understanding the API, or any other
troubles, don't hesitate to ask. Hopefully, I've made the documentation
clear enough to make the conversion of this driver quick and easy -- and
if not, then it's something I need to fix, so let me know. :-)
William Breathitt Gray
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox